dressgen-admin-tool.md
6.74 KB
人衣图生成 admin 工具 — 现状与待办
独立于主线换装跳舞直播间任务序列(T1-T39,见 dev-plan*.md)之外的一个
standalone 工具:admin-dressgen.html(新建任务)+
admin-dressgenlist.html(任务列表)+ admin-dressgendetail.html(任务
详情)。输入人物定妆照(全身/脸部 × 正/侧/背,传几张算几张,至少 1
张)+ 1 张新衣服图,依次生成这位人物穿新衣服的全身正/侧/背 3 张图。
2026-09-03 当天从头做到这里,记录一下现状,避免下次接着做时重新踩一遍
已经踩过的坑。
1. 已完成
- 异步任务队列(不是同步阻塞接口——最早的同步版本真的把前端代理
拖到 502 超时过一次):
POST /api/admin/dressgen立即返回status:"queued"的任务行,runDressGenViews()(server.js)在响应 发出后 fire-and-forget 依次(不并发)跑 3 个视角,每一步都写回dressGenRecords(dress-gen.json),前端轮询GET /api/admin/dressgen/:id看进度。 - 重试:
POST /api/admin/dressgen/:id/retry(整体重试,只重跑没成 功的视角)、POST /api/admin/dressgen/:id/retry/:view(单张重试, 可选带{prompt}覆盖那一张的 prompt)——都复用任务自己存的图片/ prompt,不用重新上传、不用重新填 prompt。两个重试接口都额外接受可选{provider}覆盖,手动把某个任务/某一张换供应商重跑。 - 两个供应商都已接入并验证成功:
- GPT Image 2(万界方舟):
https://maas-openapi.wanjiedata.com /api/v1/images/edits,model:"GPT Image 2"(带空格,写错会被 WAF 拦 410 或报 unauthorized),rejectUnauthorized:false(万界这个 host 的证书链在这台机器上验证不过,-k),300s 超时,60-180秒/张。 - Seedream v4(wavespeed.ai 的
bytedance/seedream-v4/edit):上传POST /api/v3/media/upload/binary→ 提交POST /api/v3/{model}→ 轮询GET /api/v3/predictions/{id}/result,约 30 秒/张,$0.027/次, 无 TLS 证书问题、无内容审核。.env已配置WAVESPEED_API_KEY。 - 默认行为(2026-09-03 当天二次确认的产品决策,覆盖了更早的"不做
自动切换"那版):新任务默认用 image2;某一视角 image2 失败(不
区分技术故障还是审核拒绝)→ 自动改用 wavespeed 重试一次,成功的话
该视角
viewProvider[view]记为"wavespeed",前端详情页会显示 "实际使用: Seedream v4"。手动重试接口仍可传{provider}强制指定。 这条决策的取舍写在server.js里WAVESPEED_API_KEY声明上方的 注释里,包含为什么会改主意——下次改这块之前先看那段注释。
- GPT Image 2(万界方舟):
- 17 个自动化测试全过(
dressgen-generate.test.js:任务创建即时 返回、轮询到终态、per-view 自定义 prompt、单视角失败不拖累其它两个、 整体/单视角重试(含 provider 覆盖)、非法路径防护、wavespeed 供应商 路径、image2→wavespeed 自动降级等)。 - 前端拆成三个页面(原来是"新建+列表"揉在一张页面里,"详情"按钮在
宽表格右侧、窄窗口下需要横向滚动才能看到,容易被当成"消失了"):
admin-dressgen.html:新建任务表单,提交后跳到该任务的详情页。admin-dressgenlist.html:任务列表,操作列(详情/重试/删除)用position: sticky; right: 0钉住,横向滚动时始终可见;所有缩略图 (人物参考图/衣服图/生成结果)点击可放大预览(一个简单的 lightbox,点哪张放大哪张,点遮罩关闭)。admin-dressgendetail.html:单任务详情(原admin-dressgen-task. html改名),生成结果图也支持点击放大,每张视角显示"实际使用"的 供应商。- 其它 admin 页面导航栏的"人衣图生成"链接都改指向
admin-dressgenlist.html(列表作为默认落地页,列表页右上角 "+新建任务" 去创建页)。
2. 待办
- [ ] 生成结果目前是完全独立的列表(
dress-gen.json),不会进characters.json/garments.json(人物库/衣服库)。现状确认 (2026-09-03):人物库现在每个人物只有单张imageUrl,不是"一个 人物对应多张可复用资产图"的模型——characters.json唯一一条 种子记录也只有一个imageUrl字段,没有相册/资产列表这回事。 "存为新人物"要做成什么形态(人物库本身要不要先改成多资产模型、 用 dressgen 的哪张视角图当定妆照等)还没定,做之前需要先对齐。
3. 已完成(第二批,2026-09-03 当天晚些时候)
- 任务僵死检测:
server.js的resumeDressgenTasks(),进程启动时 (resumeGenerations()/resumeDressupGenerations()旁边)扫一遍dressGenRecords,把仍停在queued/generating的视角标记为failed(错误信息"进程重启,任务丢失,请点重试",前端详情页会照常 显示),并按 T8generationJobs同款逻辑重算整条任务的status。 没有可恢复的 in-flight 请求 id(image2/wavespeed 调用是runDressGenViews里直接 await 的 HTTP 往返,进程一退什么都不剩), 所以是标失败而不是真的续跑——用户点"重试"即可,跟真实生成失败的 体验一致。测试:dressgen-generate.test.js里专门起了一个独立 cwd/mock(mock 故意不响应,制造一个真实卡在 generating 的视角),SIGKILL模拟崩溃,重新起一个指向同一份dress-gen.json的进程, 断言恢复后的状态。 - 列表分页:
GET /api/admin/dressgen现在接受?page=&pageSize=(默认pageSize=20,上限 100),按createdAt倒序(最新的在前) 切片,返回{items, total, page, pageSize}(之前是裸数组,前端自己.reverse()——这是个破坏性的响应格式变更,前端和测试已同步改掉)。admin-dressgenlist.html加了"上一页/下一页",操作列还是 sticky, 互不冲突。
3. 相关文件
server.js:IMAGE2_*/WAVESPEED_*常量、generateDressImage/generateDressImageViaImage2/generateDressImageViaWavespeed/runDressGenViews(含自动降级分支)/dressGenImageAbsPaths、/api/admin/dressgen*路由dressup-store.js:dressGenRecordsdress-gen.json:数据文件admin-dressgen.html(新建)/admin-dressgenlist.html(列表)/admin-dressgendetail.html(详情):前端dressgen-generate.test.js:测试.env:IMAGE2_API_KEY/IMAGE2_API_BASE/WAVESPEED_API_KEY/WAVESPEED_API_BASE