From 49879f39a71a4d134cf4a1be38a17a7433693c04 Mon Sep 17 00:00:00 2001 From: Linghong Date: Wed, 15 Jul 2026 08:10:03 +0000 Subject: [PATCH] =?UTF-8?q?=E7=BB=9F=E4=B8=80BgFilter=E4=B8=8E=E5=A4=96?= =?UTF-8?q?=E9=83=A8=E7=94=9F=E6=88=90=E6=96=87=E6=A1=A3=E5=8F=A3=E5=BE=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 收敛手动去背景到BgFilter complex并补齐单次重试边界 明确外部生成summary读取事实源、phase字段与正式procedure 补充nohup.out刷新循环的运维说明和共享踩坑记录 整理SpacetimeDB mapper导出列表格式 --- docs/project-memory/shared-memory/pitfalls.md | 8 +++++++ ...架构】图片画布编辑器MVP接入方案-2026-06-11.md | 11 +++++----- ...端架构】外部生成Worker化方案-2026-06-03.md | 22 ++++++++++++------- ...】server-rs与SpacetimeDB数据契约-2026-05-15.md | 5 ++--- ...发运维】本地开发验证与生产运维-2026-05-15.md | 6 ++--- ...辑器】画板角色形象生成入口设计-2026-06-15.md | 2 +- server-rs/crates/spacetime-client/src/lib.rs | 21 +++++++++--------- 7 files changed, 43 insertions(+), 32 deletions(-) diff --git a/docs/project-memory/shared-memory/pitfalls.md b/docs/project-memory/shared-memory/pitfalls.md index 3f2050978..6fdd9ab55 100644 --- a/docs/project-memory/shared-memory/pitfalls.md +++ b/docs/project-memory/shared-memory/pitfalls.md @@ -1602,6 +1602,14 @@ - 验证:`npm run dev -- --watch` 下修改 `apps/admin-web/src/**` 应由 Vite HMR 处理,不应出现连续 `[dev] 重启 admin-web`;`scripts/dev.test.ts` 覆盖 web/admin-web 不注册外层 watch。 - 关联:`scripts/dev.mjs`、`docs/technical/RUST_LOCAL_AND_REMOTE_DEPLOYMENT_SCRIPTS_2026-04-22.md`。 +## 根目录 `nohup.out` 持续写入会触发主站 Vite 刷新循环 + +- 现象:在仓库根目录用 `nohup npm run dev ... &` 启动完整 dev 栈后,即使没有修改前端源码,主站页面也会反复整页刷新;`nohup.out` 同时持续增长。 +- 原因:未显式重定向 stdout / stderr 时,`nohup.out` 会收集 SpacetimeDB、api-server 和两套 Vite 的整套 dev 栈输出。主站 Vite 的 root 是仓库根目录,若 watcher 未忽略这个持续写入的文件,每次追加日志都会被当成文件变化;后台 Vite root 是 `apps/admin-web`,仓库根日志不在其监听根内。 +- 处理:主站 `vite.config.ts` 的 `server.watch.ignored` 保持忽略 `**/nohup.out`,Git 同时忽略 `nohup.out`。修改配置后重启主站 Vite。若显式重定向到其它仓库内日志文件,该文件不会自动受保护,应写到 Vite root 之外或补充精确忽略规则。 +- 验证:在仓库根目录追加 `nohup.out` 时主站不再刷新,真实源码修改仍正常触发 HMR;`git check-ignore nohup.out` 能命中忽略规则,`git status` 不出现该日志。 +- 关联:`vite.config.ts`、`.gitignore`、`docs/【开发运维】本地开发验证与生产运维-2026-05-15.md`。 + ## 本地 SpacetimeDB publish 401 可清本地库重发 - 现象:本地 `spacetime publish` 显示 `401` 无权限,或重新发布仍像是在更新旧库。 diff --git a/docs/technical/【前端架构】图片画布编辑器MVP接入方案-2026-06-11.md b/docs/technical/【前端架构】图片画布编辑器MVP接入方案-2026-06-11.md index f9ff1ca55..af3cec512 100644 --- a/docs/technical/【前端架构】图片画布编辑器MVP接入方案-2026-06-11.md +++ b/docs/technical/【前端架构】图片画布编辑器MVP接入方案-2026-06-11.md @@ -21,13 +21,13 @@ - 生成资源右上角显示元数据按钮,点击打开独立元数据窗口。图片信息页不展示后端组装后的生图 Prompt,也不提供复制 Prompt;只展示该图片生成时用户在面板里提交的输入快照,包括普通生成提示词、规范表单字段、角色设定、图标素材描述、快速编辑提示词、重绘提示词,以及角色规范 / 常规参考图 / 图标规范 / 编辑参考图等参考图卡片,并提供“复制信息”复制当前可见字段。参考图输入快照只保存 `refType/refId` 行引用,其中 `refType="project-resource"` 指向 `editor_project_resource.resourceId`,`refType="asset"` 指向 `editor_asset.assetId`;不得把图片 Data URL、普通 URL 或 `objectKey` 写入 `generationInputs.references`。旧数据或上传图片没有输入快照时显示 `-`,禁止回退展示内部 Prompt。 - 对生成资源执行重绘时,在右侧创建新的生成结果图层,并自动调整视图显示原图和新图;重绘面板不因提交成功自动关闭,便于连续改提示词。重绘 / 改造输入框只允许从 `generationInputs.fields` 中恢复用户可见输入快照,例如普通生成提示词、视频描述、音效 `prompt`、背景音乐 `gpt_description_prompt`、角色设定、UI 用户输入、图标素材描述、规范表单和宣发素材字段;禁止回退展示资源 `prompt` / `actualPrompt` 中的后端拼接 Prompt、固定生成模板或模型默认提示词。没有用户输入快照的旧图层打开改造时保持空输入,等待用户重新填写。 - 图片生成 / 修改统一经 api-server BFF 接入 VectorEngine。普通生成、生成规范和重绘保留既有 `gpt-image-2` 路径;图片快速编辑统一打开框选区域 + 单提示词 + 模型选择面板,默认沿用原图模型,不展示参考图或比例 / 尺寸控件;其中生成规范类图片固定 `16:9`、`2K`、`gpt-image-2`,面板底部用与可编辑面板一致的比例 / 尺寸 / 模型胶囊按钮展示固定参数,但按钮为禁用态,不允许在该面板改比例、尺寸或模型。`生成角色形象` 与 `生成图标素材` 支持 `nanobanana2`(`gemini-3.1-flash-image-preview`)和 `gpt-image-2`,默认 `nanobanana2`,并在两类面板之间沿用用户上次选择的模型;两类面板不展示抠图背景色或抠图模型选择;前端用户路径固定提交 `screenColor=auto` 和 `segModel=birefnet`,由后端自动决策具体抠图背景色,`anime-seg` 作为内部保留能力不在用户界面暴露。`nanobanana2` 走 `/v1beta/models/{model}:generateContent`,请求体写入 `generationConfig.imageConfig.aspectRatio/imageSize`;`gpt-image-2` 走 `/v1/images/generations` 或 `/v1/images/edits`,请求体按 VectorEngine 文档映射 `size`。宣发素材三个工作流(游戏首图、详情五图、运营海报)固定使用 `gpt-image-2`,面板模型胶囊为禁用态,不提供 `nanobanana2` 入口;前端按 workflow 同时提交 `outputSize`、`aspectRatio` 和 `imageSize`,其中游戏首图为 `720x540 / 4:3`、详情单图为 `720x1280 / 9:16`、运营海报为 `1280x720 / 16:9`;后端收到 `kind: "publication-material"` 时也强制归一为 `gpt-image-2` 生成和计费,生成回填图层优先使用生成占位的 `originalWidth/originalHeight`,即使上游回包尺寸漂移也不得把宣发素材卡片变成随机 `1:1` 或 `4:3`。纯文本生成走 `/api/editor/images/generations`,重绘在前端读入当前图层图片 Data URL 后走同一图片生成 BFF,并在原图右侧生成一张新图;普通图层重绘作为 `quick-edit` 参考图提交,角色图层重绘必须按 `kind: "character"` 提交,继续套用角色生成器提示词限定、透明 PNG 后处理和角色资产持久化。`生成视频` 走 `/api/editor/videos/generations`,前端模型入口仅展示 Seedance 2.0 Fast / Seedance 2.0 / Kling 3.0 / Kling 3.0 Omni,不展示 Veo 入口,默认 Seedance 2.0 Fast;视频参数按当前正式面板支持的比例、时长、清晰度和声音开关提交,且 Seedance Fast 与 Seedance 标准版必须按各自真实模型 ID 独立映射,不得混用。生成结果以视频图层加入画布。纯文本生成入口采用 Lovart 式画布内占位图 + 锚定生成输入框:点击生成图片后以当前视口世界中心为目标,经统一 placement 避让后创建选中的灰色占位框,输入框跟随占位框显示;待生成、生成中和失败后保留的占位图都必须继续支持拖动,生成完成时真实生成图或视频落在最新占位框位置,输入框继续跟随新生成图层;占位图失焦时隐藏高亮边框、左上角生成器名称和右上角原始尺寸,重新聚焦时再显示,且名称 / 尺寸在画布缩小时按 viewport 反向缩放保持屏幕尺寸稳定;点击所有图片 / 视频生成入口并确认请求开始后,必须隐藏对应设置面板,只保留画布内占位图或原图预览,并在预览上显示 Lovart 式生成中遮罩,避免“面板仍占屏”或“预览一起消失”。图片快速编辑和重绘在调用图片 BFF 前必须把当前图层图片源读取为图片 Data URL;视频素材快速编辑走视频生成 BFF,不允许走图片模型;角色动作的 `生成动画` 仍固定使用 `seedance2.0-fast` 动作 / 视频模型,角色动作素材的 `快速编辑` 按当前帧图片走图片编辑。前端不持有 provider 密钥;上游失败或配置缺失时恢复当前生成设置面板展示失败,不创建 mock 成功图。 -- 图片画布抠图分两类:手动去除背景面向用户任意图片,走登录态同源 BFF `POST /api/editor/images/background-removals` 并转发远端 BiRefNet;编辑器自己生成的标准纯色背景抠图资产在保存源图后统一调用独立 BgFilter 服务 `GENARRATIVE_EDITOR_BGFILTER_BASE_URL/remove-background`,默认 `http://58.87.105.82/bgfilter/remove-background`,默认请求超时 `180000ms`(BgFilter CPU 推理)。角色形象生成、图标 spritesheet 生成、UI 设计图素材提取和角色动作的前端用户路径都固定把 `screenColor=auto` 注入请求体,但用户可见 `generationInputs.fields` 不再记录 `抠图背景色` 或 `抠图模型`;api-server 在组装 prompt 前调用背景决策模块,从 12 个候选色中选择具体 hex,最多重试 3 次,失败后兜底 `#CFEFFF`。后端仍保留手动 hex 解析能力供内部兼容。最终生图 prompt、动作视频实色背景和 BgFilter `screen_color` multipart 字段只接收解析后的具体 hex,不透传 `auto`。四条 BgFilter 路径都固定传 `background_mode=flat`,明确使用现有单一纯色背景抠图模式;同时把默认 `segModel=birefnet` 传为 `seg_model`,并显式传 `cross_check`:角色形象生成和角色动作逐帧去背传 `on`,图标 spritesheet 和 UI 设计图素材提取传 `off`,不依赖 BgFilter 服务端默认值;后端仍保留识别 `anime-seg` 的内部兼容能力,但前端用户入口不展示也不提交 `seg_model`、`background_mode` 或 `cross_check`。这里的 `birefnet` 只是 BgFilter 管线内部后端,不等同于手动去背景的独立 BiRefNet 服务。后端在调用 BgFilter 前必须先把带纯色背景 / 绿幕源图写入 OSS;BgFilter 请求失败、返回非成功状态、空图片或非法图片时,以及连续失败达到 `GENARRATIVE_EDITOR_BGFILTER_CIRCUIT_FAILURE_THRESHOLD=3` 后的 `GENARRATIVE_EDITOR_BGFILTER_CIRCUIT_COOLDOWN_SECONDS=300` 秒熔断期,api-server 都先调用阿里云通用抠图,只有阿里云失败才用本地 `editor_green_screen` 按同一 `screenColor` 兜底去背。角色动作生成的序列帧背景色已与生图统一:后端把源角色图合成到视觉决策出的具体 hex 后再图生视频;抽帧后逐帧进入同一条 `BgFilter(background_mode=flat,cross_check=on)→ 阿里云 → 本地键色` 链路。BiRefNet 手动去背景服务地址为 `GENARRATIVE_EDITOR_BACKGROUND_REMOVAL_BASE_URL/remove-background`,默认 `http://58.87.105.82/remove-background`;BgFilter 可选访问令牌来自 `GENARRATIVE_EDITOR_BGFILTER_TOKEN`,未配置时复用 `GENARRATIVE_EDITOR_BACKGROUND_REMOVAL_TOKEN`,所有令牌都只在服务端注入,前端不持有令牌。api-server 对上游结果做响应字节和图片尺寸上限保护,并先落 OSS / asset object,再返回 `imageSrc/objectKey/assetObjectId/taskId`;queue 模式下手动去背景进入 SpacetimeDB 外部生成队列,画布任务侧栏只展示服务器任务阶段,生成中才显示耗时,不显示百分比;有项目上下文时前端同时创建去背景生成占位并把 `canvasCompletion` 交给后端,完成后由后端写入结果图层和最新项目快照。 -- 2026-07-14 更新:上句关于手动去背景代理独立 BiRefNet 和使用独立 base URL 的口径已废止。手动去背景仍走同一 BFF/队列,但 worker 改用 BgFilter `background_mode=complex`、`seg_model=birefnet`、`cross_check=off`,不发送 `screen_color`;标准纯色背景四条链路继续使用 `background_mode=flat`。两类模式统一使用 `GENARRATIVE_EDITOR_BGFILTER_BASE_URL`、`GENARRATIVE_EDITOR_BGFILTER_TOKEN`、`GENARRATIVE_EDITOR_BGFILTER_REQUEST_TIMEOUT_MS` 和共享 HTTP client。 +- 图片画布抠图统一使用 BgFilter 服务 `GENARRATIVE_EDITOR_BGFILTER_BASE_URL/remove-background`,默认 `http://58.87.105.82/bgfilter/remove-background`,默认请求超时 `180000ms`(BgFilter CPU 推理)。手动去除背景面向用户任意图片,仍走登录态同源 BFF `POST /api/editor/images/background-removals` 和外部生成队列;worker 固定提交 `background_mode=complex`、`seg_model=birefnet`、`cross_check=off`,不提交 `screen_color`。首次请求失败后立即重试 `1` 次,两次都失败则返回最终错误;manual complex 不接入依赖纯色键值的阿里云 / 本地键色降级链,也不改变 flat 链路的熔断状态。手动与标准纯色背景两类模式共用 `GENARRATIVE_EDITOR_BGFILTER_BASE_URL`、`GENARRATIVE_EDITOR_BGFILTER_TOKEN`、`GENARRATIVE_EDITOR_BGFILTER_REQUEST_TIMEOUT_MS` 和共享 HTTP client;BgFilter token 未配置时只兼容回退读取旧 `GENARRATIVE_EDITOR_BACKGROUND_REMOVAL_TOKEN`。所有令牌都只在服务端注入,前端不持有令牌。api-server 对上游结果做响应字节和图片尺寸上限保护,并先落 OSS / asset object,再返回 `imageSrc/objectKey/assetObjectId/taskId`;有项目上下文时前端同时创建去背景生成占位并把 `canvasCompletion` 交给后端,完成后由后端写入结果图层和最新项目快照。 +- 编辑器自己生成的标准纯色背景抠图资产在保存源图后统一调用 BgFilter `background_mode=flat`。角色形象生成、图标 spritesheet 生成、UI 设计图素材提取和角色动作的前端用户路径都固定把 `screenColor=auto` 注入请求体,但用户可见 `generationInputs.fields` 不再记录 `抠图背景色` 或 `抠图模型`;api-server 在组装 prompt 前调用背景决策模块,从 12 个候选色中选择具体 hex,最多重试 3 次,失败后兜底 `#CFEFFF`。后端仍保留手动 hex 解析能力供内部兼容。最终生图 prompt、动作视频实色背景和 BgFilter `screen_color` multipart 字段只接收解析后的具体 hex,不透传 `auto`。四条 flat 路径同时把默认 `segModel=birefnet` 传为 `seg_model`,并显式传 `cross_check`:角色形象生成和角色动作逐帧去背传 `on`,图标 spritesheet 和 UI 设计图素材提取传 `off`,不依赖 BgFilter 服务端默认值;后端仍保留识别 `anime-seg` 的内部兼容能力,但前端用户入口不展示也不提交 `seg_model`、`background_mode` 或 `cross_check`。flat 请求首次失败后立即重试 `1` 次;第二次仍失败、返回非成功状态、空图片或非法图片时,以及连续失败达到 `GENARRATIVE_EDITOR_BGFILTER_CIRCUIT_FAILURE_THRESHOLD=3` 后的 `GENARRATIVE_EDITOR_BGFILTER_CIRCUIT_COOLDOWN_SECONDS=300` 秒熔断期,api-server 都先调用阿里云通用抠图,只有阿里云失败才用本地 `editor_green_screen` 按同一 `screenColor` 兜底去背。角色动作生成的序列帧背景色已与生图统一:后端把源角色图合成到视觉决策出的具体 hex 后再图生视频;抽帧后逐帧进入同一条 `BgFilter(background_mode=flat,cross_check=on)→ 阿里云 → 本地键色` 链路。 - 角色动作逐帧抠图在 api-server 内复用共享 BgFilter HTTP Client;单帧首次失败立即重试 `1` 次,第二次仍失败才进入阿里云/本地降级链。全部 `32 / 40 / 48` 帧按“对应绿幕源图落 OSS → BgFilter/降级 → 透明帧落 OSS”连续加入无序在途流水线,允许响应乱序完成并在最终返回前按 `frameIndex` 恢复顺序;任一帧最终失败时仍排空全部已启动请求,整个动作任务失败退款,不发布缺帧动画。 - 多产物生成以后端项目快照为唯一画布真相:同一任务的原始产物、抠图 / 透明化结果和拆分结果都要先登记为 `editor_project_resource`,再通过一次 `canvasCompletion` 原子写入画布。角色形象、图标 spritesheet 和 UI 素材提取的纯色背景原图不能只留在 OSS;透明后处理结果保持主图层和 `generatedLayerId` 锚点,原图及其它附属产物从主结果右侧开始错开放置。无项目上下文时不创建项目资源或画布图层。 - 图片快速编辑面板只保留一个提示词输入框和模型选择,不展示额外参考图或比例 / 尺寸控件;原图 / 原素材作为 `/api/editor/images/edits` 的 `sourceImageSrc` 直接提交,不作为 `referenceImageSrcs`。打开快速编辑时画布必须自动平移缩放,让原素材完整落在可视区上半部分,底部面板固定出现在素材下方且不遮挡内容,竖屏 UI 素材也必须完整展示。快速编辑右侧显示矩形、椭圆、画笔框选工具,但进入时不默认启用;点击工具后显示选中态,再点同一工具取消启用。完成框选后,画布红色细框显示连续序号,提示词可按这些编号填写每个区域怎么改。点击 `修改` 后仍停留在当前快速编辑面板显示修改中,不创建独立 `Quick Edit Generator` 画布占位;生成成功后直接用结果覆盖原图图层,失败时保留当前面板并显示错误。 - 底部生成类按钮每次点击都必须创建独立的画布生成对象;新建规范、角色形象或图标素材时,只切换当前编辑面板,不得销毁此前尚未生成或已生成后的其它生成对象状态。归档为非当前编辑对象的生成占位仍可拖动、删除和等待异步完成,完成 / 失败回写必须按生成对象 ID 读取最新占位状态,不能使用提交瞬间的旧快照。 -- 画布右上角提供自动隐藏任务侧栏。列表为空且侧栏关闭时只保留图标开关;生成或去背景任务进入时默认打开;用户可手动切换开关状态。进行中阶段只使用外部生成 BFF 返回的 `phaseDetail`:调用或等待图片 / 视频生成服务时显示“正在生成”,进入 BgFilter、逐帧抠图或独立去背景时显示“正在处理”;前端不得按耗时或任务类型猜测阶段。 +- 画布右上角提供自动隐藏任务侧栏。列表为空且侧栏关闭时只保留图标开关;生成或去背景任务进入时默认打开;用户可手动切换开关状态。进行中阶段只使用外部生成 BFF 返回的 `phaseDetail`:调用或等待图片 / 视频生成服务时显示“正在生成”,进入 BgFilter、逐帧抠图或手动去背景时显示“正在处理”;前端不得按耗时或任务类型猜测阶段。 - 画布底部工具栏 / 面板 Dock 提供“画布 Agent”入口。点击后打开右侧独立 Agent 对话面板;桌面端为右侧窄面板,移动端占满可用宽度。该面板与素材侧栏、图层侧栏、右上角任务侧栏互斥,打开 Agent 时必须收起其它侧栏,打开其它侧栏或任务侧栏时也必须收起 Agent。Agent 面板不得在当前画布内容下方追加内联内容,也不默认展示大段功能说明文案。 - 所有会新建画布生成占位的入口必须先创建 draft,再统一经过 `ImageCanvasGenerationPlacementModel` 计算落点,禁止各入口自行使用当前视口中心裸坐标或原图右侧固定偏移。当前覆盖入口包括 `生成图片`、`生成规范`、`生成角色形象`、`生成图标素材`、`生成视频`、`生成UI设计图` 和 `生成角色动作`。placement 模型的避让对象为所有未隐藏画布图层,以及当前 active / inactive generation dialogs 中仍存在的 placeholder;每个避让矩形按 32px 画布世界坐标间距外扩。候选落点以当前视口世界中心为距离目标,优先选择离视口中心最近且不重叠的占位位置;若中心被占用,会按上下左右和环形候选继续寻找。打开生成面板时必须把避让后的 placeholder 写入 `openCanvasGenerationDialog(...)`,并立即调用 `centerViewportOnPlacement(...)` 居中到新占位中心,保持原 viewport scale 不变;图片快速编辑不属于新建占位入口,提交后覆盖源图。 @@ -88,8 +88,7 @@ - `PATCH /api/editor/assets/{assetId}`:重命名素材或移动素材到文件夹。 - `DELETE /api/editor/assets/{assetId}`:删除素材。已放入画布的 project resource 不被级联删除,避免旧画布丢图。 - `POST /api/editor/images/generations`:按提示词调用 VectorEngine 生成图片;普通图片的 provider 回图先留在内存,尺寸变换成功后只上传变换结果,变换失败则只上传 provider 原图,主结果只写一次 OSS 且不额外创建“原始输出”。角色生成可携带 `model`、`screenColor`、`segModel`、`aspectRatio`、`imageSize` 和 `referenceImageSrcs`,生成成功后 api-server 先保存带纯色背景源图,再调用 BgFilter 并传入 `screen_color=`、`seg_model=` 生成透明 PNG。宣发素材携带 `kind: "publication-material"` 时固定归一为 `gpt-image-2`,不支持 `nanobanana2`。`nanobanana2` 参考图作为 `inline_data` 进入 `generateContent`,`gpt-image-2` 参考图进入 edits;`nanobanana2` 的 `512 / 1024 / 2K` 是标量清晰度档位,后端保留 provider 输出几何尺寸,不按 `宽x高` 解析。普通重绘继续走该接口并把当前图层图片作为参考图;图片快速编辑不走该接口。请求可携带 `projectId`、`assetFolderId`、`assetKind`、`generationInputs` 和 `sourceResourceId`,后端生成成功后创建 project resource / 账号素材并在响应中返回 resource / asset 快照。 -- `POST /api/editor/images/background-removals`:接收当前图片源,校验登录态后由 api-server 解析为图片文件并转发到 BiRefNet 去背景服务;请求可携带 `projectId`、`targetLayerId`、`assetFolderId`、`assetLabel`、`sourceResourceId` 和 `canvasCompletion`,有 `canvasCompletion` 时完成后按生成占位写入结果图层,否则沿用旧的目标图层替换路径;响应返回 `imageSrc`、`objectKey`、`assetObjectId`、`width`、`height`、`taskId`、`elapsedMs`、`provider` 和可选 `project` 快照。服务地址由 `GENARRATIVE_EDITOR_BACKGROUND_REMOVAL_BASE_URL` 配置,令牌只在服务端通过 `GENARRATIVE_EDITOR_BACKGROUND_REMOVAL_TOKEN` 注入。 -- 2026-07-14 更新:该接口的上游已替换为 BgFilter complex;请求字段和回包结构保持不变,服务端 multipart 固定为 `file + background_mode=complex + seg_model=birefnet + cross_check=off`,provider 返回 `BgFilter`。 +- `POST /api/editor/images/background-removals`:接收当前图片源,校验登录态后由 api-server 解析为图片文件,并通过共享 BgFilter HTTP client 调用 `GENARRATIVE_EDITOR_BGFILTER_BASE_URL/remove-background`;multipart 固定为 `file + background_mode=complex + seg_model=birefnet + cross_check=off`,不包含 `screen_color`,首次失败立即重试 `1` 次,两次都失败返回最终错误。请求可携带 `projectId`、`targetLayerId`、`assetFolderId`、`assetLabel`、`sourceResourceId` 和 `canvasCompletion`,有 `canvasCompletion` 时完成后按生成占位写入结果图层,否则沿用旧的目标图层替换路径;响应返回 `imageSrc`、`objectKey`、`assetObjectId`、`width`、`height`、`taskId`、`elapsedMs`、`provider: "BgFilter"` 和可选 `project` 快照。令牌只在服务端通过 `GENARRATIVE_EDITOR_BGFILTER_TOKEN` 注入,未配置时兼容回退旧 `GENARRATIVE_EDITOR_BACKGROUND_REMOVAL_TOKEN`。 - `POST /api/editor/icon-spritesheets/generations`:按图标规范图和素材描述数组生成 spritesheet,生成成功后 api-server 先保存带纯色背景 spritesheet 源图,再调用 BgFilter 生成透明 spritesheet。请求支持 `model`、`screenColor`、`segModel`、`aspectRatio`、`imageSize`、`priceMudPoints`、`projectId`、`assetFolderId` 和 `generationInputs`;`priceMudPoints` 必须来自编辑器生成计费配置中对应生图模型的尺寸档位(如 `nanobanana2` 的 `0.5K / 1K / 2K` 或 `gpt-image-2` 的 `1K / 2K`),后端用 `editor_generation_config` 校验后才调用上游;`nanobanana2` 走原生 `generateContent` 并写入 `generationConfig.imageConfig.aspectRatio/imageSize`,`0.5K` 传 `"512"`;`gpt-image-2` 走 `/v1/images/edits`。后端保存透明 spritesheet project resource / 账号素材,并随响应返回对应快照。 - `POST /api/editor/ui-designs/assets/extractions`:前端把红色框选轮廓绘入本地临时图后,先将该图上传 OSS 并确认 asset object,再以返回的 `objectKey` 作为参考图入队;Data URL / Blob URL 只允许停留在上传前的浏览器临时态。接口固定 `gpt-image-2` 和自动决策纯色背景素材提取提示词生成素材 spritesheet,生成成功后 api-server 先保存带纯色背景 spritesheet 源图,再调用 BgFilter 生成透明 spritesheet,并按连通域自动拆分为 `素材 1..N`,返回结构复用图标 spritesheet 响应。请求必须携带 `screenColor`、`segModel`、`aspectRatio: "1:1"`、`imageSize: "1K" | "2K"` 和 `priceMudPoints`;框选数量不超过 6 个时前端按 `1:1·1K` 与 gpt-image-2 1K 价格提交,超过 6 个时按 `1:1·2K` 与 2K 价格提交。后端必须在调用上游前校验比例、尺寸和泥点价格,只允许 `1:1 / 1K / 2K`。请求可携带 `projectId`、`assetFolderId`、`generationInputs` 和 `spritesheetLabel`,后端保存 spritesheet / 拆分素材并返回对应 resource / asset 快照;前端必须把 spritesheet 原图与拆分素材都加入画布。 - `POST /api/editor/images/edits`:按提示词和当前图片的已登记 `objectKey` / `resourceId` 调用 VectorEngine edits,返回新的生成图片元数据;图片快速编辑当前只提交 `sourceImageSrc`,不提交隐藏的 `referenceImageSrcs`。画布快速编辑必须把源图精确 `originalWidth x originalHeight` 作为业务目标 `size` 提交,不能重新映射为近似比例或 1K / 2K 预设;api-server 在 VectorEngine provider 边界把目标尺寸和所有 multipart 参考图临时补齐到 16 的倍数,回图后在内存恢复业务目标尺寸,成功时只上传恢复结果,失败时只上传 provider 原图。无论是否发生尺寸恢复都只创建一个 project resource / 账号素材,不显示重复“原始输出”。16 对齐尺寸不得泄漏到正常完成的最终响应、资源或图层 Resolution;变换失败降级时以实际 provider 原图尺寸为准。本地红框标记图必须先上传再提交 objectKey;请求携带 project / asset 上下文时由后端创建新 resource / asset,前端只消费响应快照。 @@ -131,7 +130,7 @@ - 发送消息后,面板展示用户消息、Agent 阶段状态和 SSE 增量回复;`stage/message_delta/tool_started/tool_completed/generation_result/error/done` 都能被正确渲染。流式响应中点击“停止”会中断当前请求,并把仍在 streaming / generating 的消息标记为停止态。 - Agent 返回生成结果缩略图后,点击缩略图应优先聚焦当前画布中已有 `resourceId` 对应图层;如果当前内存布局尚未包含该资源,则重新读取工程快照,应用后再聚焦新图层。对话入口触发生成时不创建“即将生成”画布占位;生成中状态只显示在消息流,生成完成后通过后端 `canvasCompletion` 落新图层。工具失败时消息内必须保留失败 generation record 和错误气泡,不能只弹一次性 toast。 - 画布 Agent 会话刷新后能从后端恢复会话标题、消息、附件和生成记录;前端不得根据本地临时状态伪造会话持久化结果。 -- 图片选中后的浮动工具栏按钮顺序固定为:快速编辑、分割线、裁扩按钮、去除背景按钮、UI设计图专属提取素材、角色图专属生成动画、分割线、重绘、下载按钮。裁扩通过画布边界拖拉完成,不再展示四边数值输入;默认自由比例,选择固定比例后拖拉边界保持对应比例,完成后在原素材旁边新增裁扩结果图层,扩展区域透明填充。去除背景调用同源 BFF `POST /api/editor/images/background-removals`,由 api-server 代理远端 BiRefNet 服务并持久化结果;有项目上下文时先在画布创建关闭面板的去背景生成占位,完成后由后端通过 `canvasCompletion` 把新 project resource 写入该占位并返回快照,无占位上下文时才用新的 project resource 引用替换当前图层。画布任务侧栏按“排队/生成中”和“已完成”分页,生成中排在排队前,生成中耗时从任务开始时间戳实时计算,排队中不计时;进行中任务只显示阶段文本和已用时,不显示百分比;完成态生成任务副标题显示用户提示词并单行截断;点击任务只聚焦对应画布内容,不激活生成面板或改变任务顺序,聚焦时必须预留图片上方工具栏、底部工具栏和可见生成对话框空间。UI设计图的提取素材必须先进入红框素材框选状态,默认启用矩形框选,右侧框选工具与快速编辑统一且可再次点击取消启用态,当前启用工具按钮必须保持高亮。素材提取面板必须在素材下方,使用与生成新素材一致的面板宽度和底部模型 / 按钮样式,提示语显示 `使用框选工具框选你希望从画面中提取的素材`,并展示按原图坐标准确裁剪的框选区域截图预览、固定模型 `gpt-image-2`、左下角计划规格 `1:1·1K/2K` 和 `提取 · N泥点` 按钮,不显示额外取消按钮;点击素材和面板以外的画布区域即退出 UI 素材提取。至少框选一个区域后才可提交,前端把红色轮廓绘入原图后固定走 `gpt-image-2` 和自动决策纯色背景素材提取提示词;生成的透明 spritesheet 原图和拆分后的独立素材都作为画布图层保留。 +- 图片选中后的浮动工具栏按钮顺序固定为:快速编辑、分割线、裁扩按钮、去除背景按钮、UI设计图专属提取素材、角色图专属生成动画、分割线、重绘、下载按钮。裁扩通过画布边界拖拉完成,不再展示四边数值输入;默认自由比例,选择固定比例后拖拉边界保持对应比例,完成后在原素材旁边新增裁扩结果图层,扩展区域透明填充。去除背景调用同源 BFF `POST /api/editor/images/background-removals`,由 api-server 通过共享 BgFilter `background_mode=complex` 链路去背景并持久化结果;有项目上下文时先在画布创建关闭面板的去背景生成占位,完成后由后端通过 `canvasCompletion` 把新 project resource 写入该占位并返回快照,无占位上下文时才用新的 project resource 引用替换当前图层。画布任务侧栏按“排队/生成中”和“已完成”分页,生成中排在排队前,生成中耗时从任务开始时间戳实时计算,排队中不计时;进行中任务只显示阶段文本和已用时,不显示百分比;完成态生成任务副标题显示用户提示词并单行截断;点击任务只聚焦对应画布内容,不激活生成面板或改变任务顺序,聚焦时必须预留图片上方工具栏、底部工具栏和可见生成对话框空间。UI设计图的提取素材必须先进入红框素材框选状态,默认启用矩形框选,右侧框选工具与快速编辑统一且可再次点击取消启用态,当前启用工具按钮必须保持高亮。素材提取面板必须在素材下方,使用与生成新素材一致的面板宽度和底部模型 / 按钮样式,提示语显示 `使用框选工具框选你希望从画面中提取的素材`,并展示按原图坐标准确裁剪的框选区域截图预览、固定模型 `gpt-image-2`、左下角计划规格 `1:1·1K/2K` 和 `提取 · N泥点` 按钮,不显示额外取消按钮;点击素材和面板以外的画布区域即退出 UI 素材提取。至少框选一个区域后才可提交,前端把红色轮廓绘入原图后固定走 `gpt-image-2` 和自动决策纯色背景素材提取提示词;生成的透明 spritesheet 原图和拆分后的独立素材都作为画布图层保留。 - 重绘生成资源后,右侧出现新生成结果图层,并自动 fit 原图 + 新图,且重绘面板保持打开。 - 快速编辑 / 重绘站内 public 示例图、历史 generated 图或 OSS generated 图时,优先复用当前图层已有 `objectKey` / `resourceId` / `sourceAssetId`;只有尚未登记的浏览器本地图片才先上传并取得 objectKey。前端不得再把正式对象下载成 `data:image/*;base64,...` 后提交,也不得把 Data URL / Blob URL 写入外部生成持久任务 JSON;后端收到引用后统一做 owner 归属校验并签名读取。 - 快速编辑不保留额外参考图入口;点击修改时只把原图或红框序号标注图作为 `/api/editor/images/edits` 的 `sourceImageSrc` 提交给后端。 diff --git a/docs/technical/【后端架构】外部生成Worker化方案-2026-06-03.md b/docs/technical/【后端架构】外部生成Worker化方案-2026-06-03.md index cefdcf63c..62a24f544 100644 --- a/docs/technical/【后端架构】外部生成Worker化方案-2026-06-03.md +++ b/docs/technical/【后端架构】外部生成Worker化方案-2026-06-03.md @@ -1,6 +1,6 @@ # 外部生成 Worker 化方案 -更新时间:`2026-06-24` +更新时间:`2026-07-15` ## 背景 @@ -13,7 +13,7 @@ - 多个 worker 进程通过 SpacetimeDB 任务表抢占任务,依赖 lease 超时恢复,支持按进程数和单进程并发动态缩扩容。 - 本地或小流量同步排查可显式启用 `inline` 模式,由 HTTP handler 复用同一 worker executor 同步执行并返回 `completed`;该模式不创建队列任务,也不具备 worker 横向扩容能力。 - SpacetimeDB reducer / procedure 只做任务状态流转,不做网络、文件系统或外部 provider I/O。 -- 已接入拼图 `compile_puzzle_draft`、结果页 `generate_puzzle_images` 与结果页 `generate_puzzle_ui_background`,跳一跳、拼消消和敲木鱼的外部图片生成动作,以及图片画布编辑器的图片、改图、图标 spritesheet、UI 素材提取、角色动作、视频、音效和背景音乐生成。后续玩法和编辑器生成入口继续复用同一队列 Module,不再为每个入口发明独立队列。 +- 已接入拼图 `compile_puzzle_draft`、结果页 `generate_puzzle_images` 与结果页 `generate_puzzle_ui_background`,跳一跳、拼消消和敲木鱼的外部图片生成动作,以及图片画布编辑器的图片、改图、手动去背景、图标 spritesheet、UI 素材提取、角色动作、视频、音效和背景音乐生成。后续玩法和编辑器生成入口继续复用同一队列 Module,不再为每个入口发明独立队列。 - 第一版外部生成队列粒度固定为“单个用户动作对应单个 job”。例如草稿编译、结果页单槽重生、图集重生都各自入一个 job;job 内部可以串行或并行调用 provider、OSS、SpacetimeDB 写回,但不再拆成“提示词 / 生图 / 切图 / 去背景 / 持久化 / 回写”等阶段 job。用户可见执行阶段通过现有任务行及摘要投影的轻量 `phase` 保存,不作为队列调度单位,也不写回大 payload。 - 不调用外部图片 / 音频 / LLM provider 的动作继续 inline 执行,不为了统一排队而进入 `external_generation_job`。 @@ -27,10 +27,12 @@ - `update_external_generation_job_phase_and_return`:worker 按 `job_id + worker_id + lease_token` 把当前执行阶段更新为 `generating` 或 `processing`,并同步现有摘要投影;不新增阶段任务或阶段表。 - `complete_external_generation_job_and_return`:worker 成功后按 `worker_id + lease_token` 写入 `result_payload_json`,任务进入 `completed`。 - `fail_external_generation_job_and_return`:worker 失败后按 `worker_id + lease_token` 回写错误,并按 `max_attempts` 决定回到 `pending` 重试或进入 `failed`。 -- `list_external_generation_jobs_and_return`:按当前账号读取正式生成任务列表,返回 pending / running / 未确认终态数量、任务价格和完成提示确认状态。 -- `acknowledge_external_generation_jobs_and_return`:按当前账号确认已终态任务的完成 / 失败提示,写入 `notification_acknowledged_at` 并追加审计事件。 +- `list_external_generation_job_summaries_and_return`:按当前账号从轻量摘要投影读取正式生成任务列表,返回 pending / running / 未确认终态数量、任务价格、执行阶段和完成提示确认状态。 +- `acknowledge_external_generation_job_summaries_and_return`:按当前账号确认已终态任务的完成 / 失败提示,写入摘要投影的 `notification_acknowledged_at` 并追加审计事件。 - `get_external_generation_queue_stats_and_return`:controller 读取队列积压、运行中任务和过期 lease 数量,用于计算 worker 目标实例数;该 procedure 只读 `external_generation_job`,不直接操作 systemd。 -- `get_external_generation_job_and_return`:按 `job_id` 读取单个任务状态,给 BFF 和生成页展示使用;必须只返回调用者有权读取的任务,不能暴露其它用户的 payload、错误详情或 worker 内部字段。 +- `get_external_generation_job_summary_and_return`:按 `job_id` 从轻量摘要投影读取单个任务状态,给 BFF 和生成页展示使用;必须只返回调用者有权读取的任务,不能暴露其它用户的 payload、错误详情或 worker 内部字段。 + +不带 `summary / summaries` 的旧 `get / list / acknowledge_external_generation_job*` procedure 只保留给受控内部兼容,不是 BFF 正式读取入口。 这个 Module 的 **Seam** 在 SpacetimeDB procedure + `spacetime-client` facade;`api-server` HTTP role 和 worker role 都只依赖这个 Interface。外部 provider、OSS、计费补偿、玩法草稿回写仍留在 `api-server` worker implementation 内,不进入 SpacetimeDB reducer。 @@ -40,11 +42,11 @@ - `GET /api/runtime/external-generation/queue-overview`:当前账号队列概览,用于兼容旧展示和轻量状态读取。返回 pending、running、未确认终态数量和更新时间。 - `GET /api/runtime/external-generation/jobs?limit=20&includeAcknowledgedTerminal=false`:当前账号正式生成任务列表,用于 `我的` 页签任务列表和完成 / 失败提示。返回每个任务的 job id、kind、source、可展示 label、状态、进度、错误、`priceMudPoints`、`refundLedgerId`、`notificationAcknowledgedAt` 和时间戳。默认不返回已确认的终态任务;需要拆分活跃和完成列表时可追加 `statuses=running,queued` 或 `statuses=completed,failed`,BFF 仍只返回当前账号任务。 -- 任务被 claim 后默认处于 `generating`,BFF 显示“正在生成”;真实进入 BgFilter、逐帧抠图或独立去背景时切换为 `processing`,BFF 显示“正在处理”。旧任务 `phase=None` 按 `generating` 兼容,前端不得按耗时或 job kind 推断阶段。 +- 任务被 claim 后默认处于 `generating`,BFF 显示“正在生成”;真实进入 BgFilter、逐帧抠图或手动去背景时切换为 `processing`,BFF 显示“正在处理”。旧任务 `phase=None` 按 `generating` 兼容,前端不得按耗时或 job kind 推断阶段。 - `POST /api/runtime/external-generation/jobs/acknowledge`:生成完成 / 失败提示展示后由前端后台调用,BFF 只传当前账号 job ids,后端只确认属于当前账号且已终态的任务。 - `GET /api/runtime/external-generation/jobs/{jobId}`:单 job 状态,用于生成页轮询某次动作。返回 `jobId`、`jobKind`、`sourceModule`、`sourceEntityId`、`status`、`attempt`、`maxAttempts`、`createdAt`、`startedAt`、`completedAt`、`updatedAt`、可展示的 `requestLabel`、可展示的 `lastErrorMessage`、以及业务侧下一次轮询所需的 source 标识。 -BFF 只做鉴权、授权裁剪、字段脱敏和契约映射;队列事实仍以 `external_generation_job` 为准,业务结果仍以玩法 session / work profile 为准。生成页 / 进度页只展示当前玩法业务进度;用户可见任务列表放在 `我的` 页签,必要时再用单 job 状态补充排障信息,并继续按原玩法 session/detail 接口收敛到 ready 或 failed。队列接口不替代玩法恢复接口,也不把 private `request_payload_json` 原样传给前端。终态提示的弹出与否以后端 `notification_acknowledged_at` 为准;前端在提示展示后后台调用 acknowledge 接口,关闭按钮只负责收起本地弹窗,不能只靠本地 dismiss 永久吞掉任务。 +BFF 只做鉴权、授权裁剪、字段脱敏和契约映射;worker 调度、lease、执行和计费事实仍以 `external_generation_job` 为准,用户可见任务列表、单任务状态、执行阶段和通知确认的正式读取事实源为 `external_generation_job_summary`,业务结果仍以玩法 session / work profile 为准。生成页 / 进度页只展示当前玩法业务进度;用户可见任务列表放在 `我的` 页签,必要时再用单 job 状态补充排障信息,并继续按原玩法 session/detail 接口收敛到 ready 或 failed。队列接口不替代玩法恢复接口,也不把 private `request_payload_json` 原样传给前端。终态提示的弹出与否以后端 `notification_acknowledged_at` 为准;前端在提示展示后后台调用 acknowledge 接口,关闭按钮只负责收起本地弹窗,不能只靠本地 dismiss 永久吞掉任务。 ## 任务表 @@ -54,7 +56,7 @@ BFF 只做鉴权、授权裁剪、字段脱敏和契约映射;队列事实仍 | --- | --- | | `job_id` | 主键,`extgen-` 前缀 UUID | | `dedupe_key` | 唯一键,建议为 `play/action/session/scope` | -| `job_kind` | 执行类型,当前覆盖 `puzzle_compile_draft`、`puzzle_generate_images`、`puzzle_generate_ui_background`、跳一跳 / 拼消消 / 敲木鱼生成动作,以及 `editor_image_generation`、`editor_image_edit`、`editor_icon_spritesheet_generation`、`editor_ui_design_asset_extraction`、`editor_character_animation_generation`、`editor_video_generation`、`editor_sound_effect_generation`、`editor_background_music_generation` | +| `job_kind` | 执行类型,当前覆盖 `puzzle_compile_draft`、`puzzle_generate_images`、`puzzle_generate_ui_background`、跳一跳 / 拼消消 / 敲木鱼生成动作,以及 `editor_image_generation`、`editor_image_edit`、`editor_background_removal`、`editor_icon_spritesheet_generation`、`editor_ui_design_asset_extraction`、`editor_character_animation_generation`、`editor_video_generation`、`editor_sound_effect_generation`、`editor_background_music_generation` | | `owner_user_id` | 触发用户 | | `source_module` | 玩法或能力名,例如 `puzzle` | | `source_entity_id` | session/profile/work 等作用域 | @@ -72,6 +74,9 @@ BFF 只做鉴权、授权裁剪、字段脱敏和契约映射;队列事实仍 | `price_mud_points` | 后端计算的本任务价格,用于任务列表展示和排障 | | `refund_ledger_id` | 失败退款产生的钱包退款流水 ID,便于从任务追到退款记录 | | `notification_acknowledged_at` | 用户已确认完成 / 失败提示的时间,未确认终态任务下次登录继续集中弹出 | +| `phase` | 尾部可选字段;`null / generating / processing`,claim 时写 `generating`,进入正式后处理时写 `processing` | + +用户正式读取使用私有轻量投影 `external_generation_job_summary`。该表同步保存 owner、来源、状态、`phase`、价格、有限错误/告警摘要、通知确认和时间字段,不复制 request/result payload、worker lease 或 dedupe 内部字段;enqueue、claim、renew、phase update、complete、fail 与 acknowledge 都必须维护对应投影语义。 新增私有审计表 `external_generation_job_event`,记录 `enqueued/claimed/lease_renewed/completed/failed/acknowledged` 等事件。事件表只追加状态转换事实,不作为当前状态源;排障时先看 `external_generation_job` 当前状态,再按 `job_id` 追 `external_generation_job_event` 时间线。 @@ -180,6 +185,7 @@ controller 配置: - `editor_image_generation`:普通图片、生成规范、角色形象、UI 设计图、宣发素材和图片快速编辑。 - `editor_image_edit`:图片编辑 / 修改结果。 +- `editor_background_removal`:手动去除任意图片背景,worker 使用 BgFilter complex 模式、首次失败后重试 `1` 次,并把执行阶段标记为 `processing`。 - `editor_icon_spritesheet_generation`:图标素材 spritesheet 生成和拆分。 - `editor_ui_design_asset_extraction`:UI 设计图红框素材提取。 - `editor_character_animation_generation`:角色动作视频和帧素材生成。 diff --git a/docs/【后端架构】server-rs与SpacetimeDB数据契约-2026-05-15.md b/docs/【后端架构】server-rs与SpacetimeDB数据契约-2026-05-15.md index 92ea3298d..fa43f12ae 100644 --- a/docs/【后端架构】server-rs与SpacetimeDB数据契约-2026-05-15.md +++ b/docs/【后端架构】server-rs与SpacetimeDB数据契约-2026-05-15.md @@ -240,9 +240,8 @@ npm run check:server-rs-ddd - LLM:通用 LLM 门面继续使用 `GENARRATIVE_LLM_*`;创意 Agent `gpt-5.4-mini` Chat Completions 文本链路已于 2026-06 从 APIMart 迁移到 VectorEngine,使用 `VECTOR_ENGINE_BASE_URL` / `VECTOR_ENGINE_API_KEY` 构造 OpenAI-compatible client,`api-server` 会把未带 `/v1` 的 VectorEngine base URL 规范化到 `/v1` 后请求 `/chat/completions`。通用 `/api/llm/chat/completions` 代理使用 `GENARRATIVE_LLM_PROVIDER=openai-compatible`、`GENARRATIVE_LLM_BASE_URL=https://api.vectorengine.cn/v1`、`GENARRATIVE_LLM_MODEL=gpt-5.4-mini`;未单独配置 `GENARRATIVE_LLM_API_KEY` 时可复用 `VECTOR_ENGINE_API_KEY`。`APIMART_BASE_URL` / `APIMART_API_KEY` 只作为历史残留,不再作为创意 Agent gpt-5.4-mini 客户端来源;后续排障时优先确认 VectorEngine `/v1/models`、`/v1/chat/completions` 和 `/v1/responses` 可用性。 - 图片生成:VectorEngine `gpt-image-2` 图片 provider 归属 `platform-image`,密钥只在后端环境变量中;`api-server` 内的 `openai_image_generation.rs` 只是兼容调用面和外部失败审计桥接,不再承载 provider 协议实现。实际外部生成运行记录统一落 `tracking_event`,`event_key = external_generation_run`,metadata 记录开始 / 结束时间、耗时、状态、成功标记、失败原因、provider task id 和结果摘要,不再写回过时的 `ai_task`。DashScope 只按仍在使用的历史能力单独处理,不作为 GPT-image-2 兜底。VectorEngine `/v1/images/generations` 和 `/v1/images/edits` 上游 POST 使用 `libcurl` 发送;`reqwest` 只保留给参考图 URL 下载和响应中图片 URL 下载。`/v1/images/edits` 的 multipart 参考图必须作为 libcurl 文件上传 part 发送,字段名为 `image`,实现上使用 `Form::buffer(file_name, bytes)` 并设置 `Content-Type`;不能只用 `contents(...).filename(...)`,否则上游会把请求转码为缺少图片并返回 `image is required`。`request_send` 阶段的 curl timeout / connect error 按可重试传输错误处理,最多尝试 5 次,并使用指数退避加短抖动;排障时优先看 `attempt`、`max_attempts`、`retry_delay_ms`、`reference_image_bytes_total` 和 `request_params`,不要把 `SendRequest` 当成上游业务错误。 -- 编辑器抠图服务:手动 `POST /api/editor/images/background-removals` 继续代理独立 BiRefNet 服务,配置为 `GENARRATIVE_EDITOR_BACKGROUND_REMOVAL_BASE_URL`、`GENARRATIVE_EDITOR_BACKGROUND_REMOVAL_TOKEN` 和 `GENARRATIVE_EDITOR_BACKGROUND_REMOVAL_REQUEST_TIMEOUT_MS`。角色形象生成、图标 spritesheet 生成、UI 设计图素材提取和角色动作抽帧后的纯色背景透明化统一走独立 BgFilter 服务,配置为 `GENARRATIVE_EDITOR_BGFILTER_BASE_URL`、`GENARRATIVE_EDITOR_BGFILTER_TOKEN` 和 `GENARRATIVE_EDITOR_BGFILTER_REQUEST_TIMEOUT_MS`,默认 base URL 为 `http://58.87.105.82/bgfilter`,默认请求超时为 `180000ms`(BgFilter 当前为 CPU 推理,单次抠图较慢,必须留足超时),token 未配置时复用 BiRefNet token。BgFilter 请求必须显式传 `screen_color=`、`seg_model=` 和 `cross_check=`;角色形象生成和角色动作逐帧去背固定传 `cross_check=on`,图标 spritesheet 生成和 UI 设计图素材提取固定传 `cross_check=off`,不依赖服务端默认值。前端用户路径不展示抠图模型选择并固定提交默认 `birefnet`,后端仍识别内部保留的 `anime-seg`,其中 `birefnet` 只表示 BgFilter 管线内部后端,不等同于手动去背景的独立 BiRefNet 服务;`cross_check` 同样只属于后端内部供应商策略,不进入前端或外部 OpenAPI。BgFilter 调用失败,或连续失败达到 `GENARRATIVE_EDITOR_BGFILTER_CIRCUIT_FAILURE_THRESHOLD`(默认 `3`)并在 `GENARRATIVE_EDITOR_BGFILTER_CIRCUIT_COOLDOWN_SECONDS`(默认 `300`)内打开熔断时,四条路线均跳过或结束 BgFilter 调用后复用同一兜底链:先调用阿里云通用抠图,阿里云失败才使用本地 `editor_green_screen` 键色扣除;熔断期不得直接退化到本地兜底。角色动作视频生成的背景色已与生图链路统一:`screenColor=auto` 时由视觉 LLM(`gpt-5-mini`,Responses 协议、low 推理档)读源角色图自动决策,并经硬过滤器剔除与前景 / 皮肤撞色的候选,手动 hex 则尊重用户选择;透明源角色图在提交 Ark 图生视频前先合成到选定背景色实色,使视频背景等于抠图键色;抽帧后逐帧固定使用 `seg_model=birefnet`、`cross_check=on` 进入上述三段式链路。阿里云通用抠图配置为 `GENARRATIVE_ALIYUN_MATTING_ENABLED`、`GENARRATIVE_ALIYUN_MATTING_ENDPOINT`、`GENARRATIVE_ALIYUN_MATTING_ACCESS_KEY_ID`、`GENARRATIVE_ALIYUN_MATTING_ACCESS_KEY_SECRET` 和 `GENARRATIVE_ALIYUN_MATTING_REQUEST_TIMEOUT_MS`;未配置专用 AK/SK 时可复用 `ALIBABA_CLOUD_ACCESS_KEY_ID` / `ALIBABA_CLOUD_ACCESS_KEY_SECRET`,默认 endpoint 为 `imageseg.cn-shanghai.aliyuncs.com`。BgFilter 与阿里云抠图失败都写入 `external_api_call_failure` 审计。 -- 2026-07-14 更新:上句关于“手动去背景继续代理独立 BiRefNet”的口径已废止。手动 `POST /api/editor/images/background-removals` 现与标准纯色背景链路共用 BgFilter 配置和 HTTP client,固定传 `background_mode=complex`、`seg_model=birefnet`、`cross_check=off`,不传 `screen_color`;标准纯色背景四条链路固定传 `background_mode=flat` 并继续沿用各自的 `screen_color`、`seg_model`、`cross_check` 策略。独立 `GENARRATIVE_EDITOR_BACKGROUND_REMOVAL_BASE_URL` 与 `GENARRATIVE_EDITOR_BACKGROUND_REMOVAL_REQUEST_TIMEOUT_MS` 已删除,旧 `GENARRATIVE_EDITOR_BACKGROUND_REMOVAL_TOKEN` 只作为 BgFilter token 的兼容回退别名。 -- BgFilter 连接复用、重试与动作帧流水线:api-server 必须在 `AppState` 复用同一个 BgFilter HTTP Client 及 keep-alive 连接池。单次 BgFilter 调用失败后立即重试 `1` 次,第二次仍失败才进入既有“阿里云通用抠图 → 本地键色”降级链,每次已发出的失败调用都单独写审计。角色动作全部 `32 / 40 / 48` 帧按“单帧绿幕源图先落 OSS → BgFilter/降级 → 透明帧落 OSS”独立流水化,使用覆盖本次全部帧的无序在途集合连续发射,不在 api-server 增加供应商进程锁或固定小并发窗口;返回结果携带原始帧序并在收口时排序。任一帧最终失败时必须先排空全部已启动 Future,再让整个动作任务失败退款,不能发布缺帧动画。 +- 编辑器抠图服务:手动 `POST /api/editor/images/background-removals` 与角色形象生成、图标 spritesheet 生成、UI 设计图素材提取、角色动作抽帧后的透明化统一走 BgFilter,配置为 `GENARRATIVE_EDITOR_BGFILTER_BASE_URL`、`GENARRATIVE_EDITOR_BGFILTER_TOKEN` 和 `GENARRATIVE_EDITOR_BGFILTER_REQUEST_TIMEOUT_MS`,默认 base URL 为 `http://58.87.105.82/bgfilter`,默认请求超时为 `180000ms`(BgFilter 当前为 CPU 推理,单次抠图较慢,必须留足超时);旧 `GENARRATIVE_EDITOR_BACKGROUND_REMOVAL_TOKEN` 只作为 BgFilter token 的兼容回退别名,原手动去背景专用 base URL / timeout 配置已经删除。手动去背景固定传 `background_mode=complex`、`seg_model=birefnet`、`cross_check=off`,不传 `screen_color`;标准纯色背景四条链路固定传 `background_mode=flat`,并显式传 `screen_color=`、`seg_model=` 和 `cross_check=`,其中角色形象生成和角色动作逐帧去背传 `cross_check=on`,图标 spritesheet 生成和 UI 设计图素材提取传 `cross_check=off`。前端用户路径不展示抠图模型、模式或 cross-check,固定提交默认 `birefnet`,后端仍识别内部保留的 `anime-seg`;这些参数只属于后端内部供应商策略,不进入前端或外部 OpenAPI。标准纯色背景 BgFilter 调用失败,或连续失败达到 `GENARRATIVE_EDITOR_BGFILTER_CIRCUIT_FAILURE_THRESHOLD`(默认 `3`)并在 `GENARRATIVE_EDITOR_BGFILTER_CIRCUIT_COOLDOWN_SECONDS`(默认 `300`)内打开熔断时,继续复用“阿里云通用抠图 → 本地 `editor_green_screen` 键色扣除”兜底链,熔断期不得直接退化到本地兜底。角色动作视频生成的背景色已与生图链路统一:`screenColor=auto` 时由视觉 LLM(`gpt-5-mini`,Responses 协议、low 推理档)读源角色图自动决策,并经硬过滤器剔除与前景 / 皮肤撞色的候选,手动 hex 则尊重用户选择;透明源角色图在提交 Ark 图生视频前先合成到选定背景色实色,使视频背景等于抠图键色;抽帧后逐帧固定使用 `seg_model=birefnet`、`cross_check=on` 进入上述三段式链路。阿里云通用抠图配置为 `GENARRATIVE_ALIYUN_MATTING_ENABLED`、`GENARRATIVE_ALIYUN_MATTING_ENDPOINT`、`GENARRATIVE_ALIYUN_MATTING_ACCESS_KEY_ID`、`GENARRATIVE_ALIYUN_MATTING_ACCESS_KEY_SECRET` 和 `GENARRATIVE_ALIYUN_MATTING_REQUEST_TIMEOUT_MS`;未配置专用 AK/SK 时可复用 `ALIBABA_CLOUD_ACCESS_KEY_ID` / `ALIBABA_CLOUD_ACCESS_KEY_SECRET`,默认 endpoint 为 `imageseg.cn-shanghai.aliyuncs.com`。标准纯色背景链路的 BgFilter 与阿里云抠图失败都写入 `external_api_call_failure` 审计。 +- BgFilter 连接复用、重试与动作帧流水线:api-server 必须在 `AppState` 复用同一个 BgFilter HTTP Client 及 keep-alive 连接池。flat 与 complex 请求首次失败后都立即重试 `1` 次;标准纯色背景 flat 请求第二次仍失败才进入“阿里云通用抠图 → 本地键色”降级链,手动 complex 请求第二次仍失败则返回最终错误,不接入依赖纯色键值的降级链,也不改变 flat 路径的熔断状态。角色动作全部 `32 / 40 / 48` 帧按“单帧绿幕源图先落 OSS → BgFilter/降级 → 透明帧落 OSS”独立流水化,使用覆盖本次全部帧的无序在途集合连续发射,不在 api-server 增加供应商进程锁或固定小并发窗口;返回结果携带原始帧序并在收口时排序。任一帧最终失败时必须先排空全部已启动 Future,再让整个动作任务失败退款,不能发布缺帧动画。 - Match3D 物品 sheet:关卡整图完成后走 VectorEngine `/v1/images/edits` multipart `image`,模型为 `gpt-image-2`,`2K 1:1` 输出 `10*10` spritesheet;物品 sheet prompt 固定要求单一纯绿色 `#00FF00 / RGB(0,255,0)` 绿幕背景,后端上传 OSS 前必须把绿幕扣成透明 PNG,并把透明整图写入 `itemSpritesheetImageSrc/itemSpritesheetImageObjectKey`。后端优先按透明 alpha 连通域从该 sheet 识别真实素材矩形并持久化 20 个物品、每个 5 个形态;识别数量不足时才回退 `10*10` 固定网格。通用系列素材图集的行列索引按每行 2 个物品计算,必须落在 `1..=10`,难度只决定运行态加载 3 / 9 / 15 / 20 种。 - Match3D UI spritesheet 和背景派生图:关卡整图作为参考图并发生成 `1K 1:1` UI spritesheet 与 `1K 9:16` 背景图,模型均为 `gpt-image-2`。UI spritesheet prompt 固定要求单一纯绿色 `#00FF00 / RGB(0,255,0)` 绿幕背景,后端上传 OSS 前必须把绿幕扣成透明 PNG;背景图必须合成为全画幅不透明 PNG。 - Match3D 1:1 容器 UI:VectorEngine `/v1/images/edits` multipart 参考图。该容器参考图是后端生图协议输入,必须通过 `include_bytes!` 随 `api-server` 编译进二进制,避免 API 单独发布或运行目录缺少 `public/` 时生成失败。 diff --git a/docs/【开发运维】本地开发验证与生产运维-2026-05-15.md b/docs/【开发运维】本地开发验证与生产运维-2026-05-15.md index 4846203ff..6cd9886b5 100644 --- a/docs/【开发运维】本地开发验证与生产运维-2026-05-15.md +++ b/docs/【开发运维】本地开发验证与生产运维-2026-05-15.md @@ -1,6 +1,6 @@ # 本地开发验证与生产运维 -更新时间:`2026-06-12` +更新时间:`2026-07-15` ## 标准开发流程 @@ -33,7 +33,7 @@ npm run dev `npm run dev` 和单模块 `npm run dev:web`、`npm run dev:api-server`、`npm run dev:spacetime`、`npm run dev:admin-web` 启动后都会更新根目录 `.app/dev-stack.json`。该文件记录本次命令、数据库、更新时间,以及 `spacetime`、`api-server`、`web`、`admin-web` 的 `pid`、监听 host / port、可访问 URL、启动状态和当前命令。`.app/` 是本地运行态目录,不提交 Git;端口漂移、服务重启或子进程退出后以该文件里的实际状态为准。 -通过 `nohup` 在仓库根目录启动 dev 栈时,`nohup.out` 已被 Vite 和 Git 忽略,避免 API 日志持续追加后触发页面刷新循环;重启 Vite 后生效。 +通过 `nohup` 在仓库根目录启动 dev 栈且未显式重定向 stdout / stderr 时,默认 `nohup.out` 会持续收集 SpacetimeDB、api-server、主站 Vite 和后台 Vite 的整套 dev 栈输出;该文件已被主站 Vite watcher 和 Git 忽略,避免日志追加触发页面刷新循环,重启主站 Vite 后生效。若把输出显式重定向到其它仓库内文件(例如 `> dev.out`),该自定义文件不会自动获得同样的 watcher 保护,应改为写到 Vite root 之外,或同步配置精确的忽略规则。 单独启动主站前端: @@ -66,7 +66,7 @@ Windows 本地如果已在 `%LOCALAPPDATA%\Genarrative\ffmpeg\bin` 安装 FFmpeg lease 过期后不代表任务一定再次执行:claim transaction 只有在 `attempt < max_attempts` 时才会递增 attempt 并返回 worker;如果过期的是最终 attempt,则直接把 job 收口为 `failed`、清理 lease,并按入队冻结价格为当前 attempt 原子退款或写 cancellation intent。该终态任务不会再次进入 provider executor,迟到 consume 会被 settlement intent 拒绝。 图片画布角色图、图标素材、UI 素材提取和角色动作逐帧去背景时优先调用 BgFilter;当前全部调用都显式传 `background_mode=flat`,保持单一纯色背景抠图语义。默认 `GENARRATIVE_EDITOR_BGFILTER_REQUEST_TIMEOUT_MS=180000`,连续失败达到 `GENARRATIVE_EDITOR_BGFILTER_CIRCUIT_FAILURE_THRESHOLD=3` 后熔断 `GENARRATIVE_EDITOR_BGFILTER_CIRCUIT_COOLDOWN_SECONDS=300` 秒。BgFilter 调用失败和熔断期均先走阿里云通用抠图,只有阿里云失败才走本地幕布色去背景兜底。阿里云这层默认 `GENARRATIVE_ALIYUN_MATTING_ENABLED=true`,但必须在 `api-server.env` 填入 `GENARRATIVE_ALIYUN_MATTING_ACCESS_KEY_ID` / `GENARRATIVE_ALIYUN_MATTING_ACCESS_KEY_SECRET`(或标准 SDK 命名 `ALIBABA_CLOUD_ACCESS_KEY_ID` / `ALIBABA_CLOUD_ACCESS_KEY_SECRET`)才会真正启用;AccessKey 缺失时启动日志会打印「阿里云抠图 AccessKey 未配置,跳过抠图客户端初始化」,抠图直接塌成 BgFilter→本地两级,`npm run check:api-server-env` 也会给出对应告警。修改这些变量后需要重启对应 `api-server` / worker 进程;排查时先从 worker 启动日志确认 lease 和 job timeout,再看带 `background_mode=flat` 的 `editor_bgfilter_request_start`、`editor_bgfilter_fallback_to_aliyun_matting`、`editor_bgfilter_circuit_open_fallback_to_aliyun_matting`,以及阿里云失败后的 `editor_aliyun_matting_fallback_to_local_screen_background_removal` 日志。 -手动 `POST /api/editor/images/background-removals` 同样调用 BgFilter,但固定传 `background_mode=complex`、`seg_model=birefnet`、`cross_check=off`,不传背景色;它不进入只适用于已知纯色背景的阿里云 / 本地键色兜底链。标准纯色背景四条链路仍固定传 `background_mode=flat`。两种模式统一使用 `GENARRATIVE_EDITOR_BGFILTER_BASE_URL`、`GENARRATIVE_EDITOR_BGFILTER_TOKEN` 和 `GENARRATIVE_EDITOR_BGFILTER_REQUEST_TIMEOUT_MS`;旧 `GENARRATIVE_EDITOR_BACKGROUND_REMOVAL_TOKEN` 只保留为 token 兼容别名。 +手动 `POST /api/editor/images/background-removals` 同样调用 BgFilter,但固定传 `background_mode=complex`、`seg_model=birefnet`、`cross_check=off`,不传背景色;首次失败后立即重试 `1` 次,两次都失败则返回最终错误。它不进入只适用于已知纯色背景的阿里云 / 本地键色兜底链,也不改变 flat 路径的熔断状态。标准纯色背景四条链路仍固定传 `background_mode=flat`。两种模式统一使用 `GENARRATIVE_EDITOR_BGFILTER_BASE_URL`、`GENARRATIVE_EDITOR_BGFILTER_TOKEN`、`GENARRATIVE_EDITOR_BGFILTER_REQUEST_TIMEOUT_MS` 和共享 HTTP client;旧 `GENARRATIVE_EDITOR_BACKGROUND_REMOVAL_TOKEN` 只保留为 token 兼容别名。 `我的` 页签或排障面板展示队列等待时,只读取 BFF 队列接口:`GET /api/runtime/external-generation/queue-overview` 查看当前用户可见队列概览,`GET /api/runtime/external-generation/jobs/{jobId}` 查看单 job 状态。生成页 / 进度页不承接队列概览,只展示当前玩法业务进度;队列接口只提供等待 / 运行 / 失败 / 完成状态补充,最终草稿、作品和结果页仍要轮询对应玩法 session/detail 接口收敛到 ready 或 failed;不要直接查询 `external_generation_job` private table,也不要把 worker 内部 payload 暴露到前端。 diff --git a/docs/【编辑器】画板角色形象生成入口设计-2026-06-15.md b/docs/【编辑器】画板角色形象生成入口设计-2026-06-15.md index 24bced80c..134c71d39 100644 --- a/docs/【编辑器】画板角色形象生成入口设计-2026-06-15.md +++ b/docs/【编辑器】画板角色形象生成入口设计-2026-06-15.md @@ -65,7 +65,7 @@ 角色设定:<用户输入的角色设定> ``` -- 角色图生成完成后,编辑器后端必须先把带自动决策纯色背景的源图写入 OSS,再调用独立 BgFilter 服务透明化:multipart 字段包含 `file`、`screen_color=`、`seg_model=` 和 `background_mode=flat`,用户路径默认并只提交 `seg_model=birefnet`;`flat` 明确表示沿用单一纯色背景抠图模式。这里的 `seg_model=birefnet` 是 BgFilter 管线内部后端,不等同于手动去背景使用的独立 BiRefNet 服务。角色图 prompt 按 `screenColor` 写入颜色名称、hex 和 RGB。该流程不再调用 RPG / 资产工坊的角色主图专用 `character_visual_assets` 后处理,也不调用手动去背景的独立 BiRefNet;输出仍统一为透明背景 PNG,随后写入 OSS 私有对象并确认 `asset_object`。接口回包仍返回透明 PNG Data URL 供画板立即显示,同时返回 `objectKey` / `assetObjectId`,前端创建图层和画板资源记录时必须保存这些字段。 +- 角色图生成完成后,编辑器后端必须先把带自动决策纯色背景的源图写入 OSS,再调用共享 BgFilter 服务透明化:multipart 字段包含 `file`、`screen_color=`、`seg_model=`、`background_mode=flat` 和 `cross_check=on`,用户路径默认并只提交 `seg_model=birefnet`;`flat` 明确表示单一纯色背景抠图模式,`birefnet` 是 BgFilter 管线内部后端。首次请求失败后立即重试 `1` 次,第二次仍失败进入“阿里云通用抠图 → 本地键色”降级链。角色图 prompt 按 `screenColor` 写入颜色名称、hex 和 RGB。该流程不再调用 RPG / 资产工坊的角色主图专用 `character_visual_assets` 后处理,也不复用手动去背景的 `background_mode=complex` 路径;输出仍统一为透明背景 PNG,随后写入 OSS 私有对象并确认 `asset_object`。接口回包仍返回透明 PNG Data URL 供画板立即显示,同时返回 `objectKey` / `assetObjectId`,前端创建图层和画板资源记录时必须保存这些字段。 - 对 `assetKind: "character"` 的角色图层执行 `重绘` 时,前端仍使用原图作为参考图,但请求 `kind` 必须传 `character`,让后端继续套用上述角色提示词限定、角色图后处理和角色资产持久化;普通图片图层重绘仍保持 `kind: "quick-edit"`。 ## 生成规范参考图 diff --git a/server-rs/crates/spacetime-client/src/lib.rs b/server-rs/crates/spacetime-client/src/lib.rs index ddb11ef96..1c661eae2 100644 --- a/server-rs/crates/spacetime-client/src/lib.rs +++ b/server-rs/crates/spacetime-client/src/lib.rs @@ -62,17 +62,16 @@ pub use mapper::{ ExternalGenerationJobListRecordInput, ExternalGenerationJobPhaseUpdateRecordInput, ExternalGenerationJobRecord, ExternalGenerationJobRenewLeaseRecordInput, ExternalGenerationJobSummaryListRecord, ExternalGenerationJobSummaryRecord, - ExternalGenerationQueueStatsRecord, - FeatureGateConfigRecord, JumpHopActionRequest, JumpHopActionResponse, JumpHopActionType, - JumpHopCharacterAsset, JumpHopDifficulty, JumpHopDraftResponse, JumpHopGalleryCardResponse, - JumpHopGalleryDetailResponse, JumpHopGalleryResponse, JumpHopGenerationStatus, - JumpHopJumpRequest, JumpHopJumpResponse, JumpHopJumpResult, JumpHopLastJump, JumpHopPath, - JumpHopPlatform, JumpHopRestartRunRequest, JumpHopRunResponse, JumpHopRunStatus, - JumpHopRuntimeRunSnapshotResponse, JumpHopScoring, JumpHopSessionResponse, - JumpHopSessionSnapshotResponse, JumpHopStartRunRequest, JumpHopStylePreset, JumpHopTileAsset, - JumpHopTileType, JumpHopWorkDetailResponse, JumpHopWorkMutationResponse, - JumpHopWorkProfileResponse, JumpHopWorkSummaryResponse, JumpHopWorksResponse, - JumpHopWorkspaceCreateRequest, Match3DAgentMessageFinalizeRecordInput, + ExternalGenerationQueueStatsRecord, FeatureGateConfigRecord, JumpHopActionRequest, + JumpHopActionResponse, JumpHopActionType, JumpHopCharacterAsset, JumpHopDifficulty, + JumpHopDraftResponse, JumpHopGalleryCardResponse, JumpHopGalleryDetailResponse, + JumpHopGalleryResponse, JumpHopGenerationStatus, JumpHopJumpRequest, JumpHopJumpResponse, + JumpHopJumpResult, JumpHopLastJump, JumpHopPath, JumpHopPlatform, JumpHopRestartRunRequest, + JumpHopRunResponse, JumpHopRunStatus, JumpHopRuntimeRunSnapshotResponse, JumpHopScoring, + JumpHopSessionResponse, JumpHopSessionSnapshotResponse, JumpHopStartRunRequest, + JumpHopStylePreset, JumpHopTileAsset, JumpHopTileType, JumpHopWorkDetailResponse, + JumpHopWorkMutationResponse, JumpHopWorkProfileResponse, JumpHopWorkSummaryResponse, + JumpHopWorksResponse, JumpHopWorkspaceCreateRequest, Match3DAgentMessageFinalizeRecordInput, Match3DAgentMessageRecord, Match3DAgentMessageSubmitRecordInput, Match3DAgentSessionCreateRecordInput, Match3DAgentSessionRecord, Match3DAnchorItemRecord, Match3DAnchorPackRecord, Match3DClickConfirmationRecord, Match3DCompileDraftRecordInput,