From 3c68dd1ef235026075471b131786d35c8a7fde68 Mon Sep 17 00:00:00 2001 From: chengma Date: Fri, 17 Jul 2026 16:34:00 +0800 Subject: [PATCH] docs(tasks): add T-658 multi-image reference submission rules Co-Authored-By: Claude Fable 5 --- docs/tasks/T-658.md | 136 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 136 insertions(+) create mode 100644 docs/tasks/T-658.md diff --git a/docs/tasks/T-658.md b/docs/tasks/T-658.md new file mode 100644 index 0000000..8028e52 --- /dev/null +++ b/docs/tasks/T-658.md @@ -0,0 +1,136 @@ +--- +id: T-658 +title: 商品套图多图参考提交与主图生成规则 +status: TODO +phase: 7 +deps: [T-622, T-637] +created: 2026-07-17 +--- + +# T-658 商品套图多图参考提交与主图生成规则 + +## 问题 / 背景 + +⑥「商品套图」当前每个生成请求只向 cmhub 提交**单张**源图(`app/image_studio_generation.py::_submit_or_resume_job()` 的顶层 `image_base64` 字段)。不勾选「每张上传图分别作为主图生成」时,除第一张外其余上传图**完全不参与生成**——用户上传多角度图没有任何价值。调研笔记《虾皮圈电商图生成器提示词组装分析》第 6.1 节指出源项目「提示词声称有参考图、实际未提交」的缺陷,cmshopee 目前靠 `{参考图规则}` 的「唯一主参考图」表述回避了这个不一致,但多图能力本身缺失。 + +cmhub 图生图接口已更新(cmhub T-620,契约见 obsidian《cmhub-接口对接文档-桌面端生文生图》2026-07-17 版): + +- 新增 `images` 有序数组,1–8 张,每项 `image_base64` 或 `image_url` 二选一;与顶层旧单图字段**互斥**; +- **第 1 张固定为主商品图**,cmhub 服务端固定要求上游优先保留其主体、外观和关键细节; +- **第 2 张及之后为参考图**,仅用于风格、构图、场景或排版,不得替换主商品——该规则由服务端固定追加,客户端 prompt 不能关闭或覆盖; +- 混用/空数组/空图片项/超过 8 张返回 `400 bad_request`; +- 单次请求**无论传几张图只扣一次点**,不按图片数量重复扣费; +- 同步 `/generate/image` 与异步 `/generate/image/tasks` 请求字段一致,桌面端继续走异步 + `Idempotency-Key`(T-564)。 + +用户已定稿生成规则(2026-07-17 讨论):不勾选时所有分类「第 1 张主图 + 其余全部作为参考图」一起提交;勾选时维持现行为(逐图主图、单图提交);白底图按配置数量生成、默认 1 张(现状即如此,不改)。 + +## 目标 + +1. **不勾选**「每张上传图分别作为主图生成」时:所有分类的每个请求提交「第 1 张上传图为主图 + 其余上传图按序作为参考图」,受 cmhub 上限约束最多 1+7 张,超出部分忽略并如实告知。 +2. **勾选**时:维持现行为——白底图只用第 1 张、按配置数量生成;其他分类每张上传图分别作为主图、各生成配置数量;每个请求仍**单图提交**(多 SKU 场景防止参考图混款)。 +3. `{参考图规则}` 渲染文本与实际提交严格一致:单图与多图两种文本,参考图数量取实际提交数。 +4. 提交层统一迁移到 `images` 数组结构(单图也用单元素数组),不再使用顶层旧字段,消除两套代码路径。 +5. 参考图列表在 `build_job_specs()` 时冻结进 job 快照,重试/恢复使用快照,不受生成后增删图片影响。 +6. 勾选项旁增加 helper 文案,说明勾选依据(多 SKU 勾选 / 同商品多角度不勾选)。 + +## 实现方案 + +### 1. 生成规则矩阵(定稿) + +| 场景 | 白底图 | 场景图 / 卖点图 / 自定义分类 | 每请求提交内容 | +| --- | --- | --- | --- | +| 不勾选 | 第 1 张为主图,按配置数量生成 | 同左 | 主图 + 其余上传图为参考图(最多 7 张参考) | +| 勾选 | 第 1 张为主图,按配置数量生成 | 每张上传图分别为主图,各生成配置数量 | 仅当前主图单图提交,无参考图 | + +- 张数计算与点数估算不变:`suite_total_count()` 逻辑不动;白底图默认数量保持 1(`DEFAULT_CATEGORY_COUNTS` 现状)。 +- 多图参考不增加点数消耗(cmhub 单次请求扣一次点),确认弹窗的总点数估算无需调整。 + +### 2. 提交层 payload(`app/image_studio_generation.py`) + +- `_submit_or_resume_job()` 的 payload 从顶层 `image_base64` 迁移为 `images` 数组: + - 勾选模式 / 无参考图:`images=[{"image_base64": 主图}]`; + - 不勾选且有参考图:`images=[{"image_base64": 主图}, {"image_base64": 参考1}, ...]`,参考图按上传顺序排列; +- 本地文件一律读成 base64(复用 `ai._image_data_url`),不使用 `image_url`(SSRF 校验只放行公网地址,本地路径不可用)。 +- 客户端在提交前裁剪到 cmhub 上限:主图 1 张 + 参考图最多 7 张;不得同时携带顶层旧字段与 `images`(互斥,违者 `bad_request`)。 +- 同步/异步接口字段一致;异步提交、`Idempotency-Key`、轮询、退点、重试语义全部不变。 + +### 3. job spec 与冻结快照 + +- `build_job_specs()` 为每个 spec 增加 `reference_asset_ids`(有序整数列表,不含 `source_asset_id` 自身);勾选模式为固定空列表。 +- `image_studio_jobs` 表新增可空列 `reference_asset_ids TEXT`(JSON 数组),走既有 additive 迁移方式;历史行为 `NULL`,语义等同「无参考图」,历史任务查看/恢复/重试不受影响。 +- 「生成套图」点击时冻结:参考图列表与 prompt 同时进入 job 快照;生成过程中增删上传图只影响下一轮。 +- 重试/恢复读取快照 `reference_asset_ids`:若某参考资产文件已缺失(被删除),跳过该参考图、仅以剩余图片提交,并写一条中文日志说明;主图缺失仍按现状让该 job 失败。 + +### 4. `{参考图规则}` 渲染(衔接 T-637 契约) + +- renderer context 增加实际参考图数量;`{参考图规则}` 按提交事实渲染两种文本: + - 单图(勾选模式,或不勾选但只上传 1 张):沿用现文本「当前图片为本任务唯一主参考图;保持商品主体、款式、颜色和关键细节准确;不编造用户与参考图均未提供的信息。」 + - 多图(不勾选且参考图 ≥1):「第 1 张为主商品图,请保持其主体、款式、颜色和关键细节准确;第 2–N 张仅作为风格、构图、场景参考,不得替换主商品;不编造用户与参考图均未提供的信息。」N 为实际提交总张数。 +- 该表述与 cmhub 服务端固定追加的多图规则同向,不冲突、不试图覆盖。 +- 提示词设置弹窗预览:预览 context 按当前套图任务的勾选状态与上传图数量计算参考图数;上传 0/1 张或勾选时显示单图文本。占位符契约(14 个变量、必需 9 个)不变。 + +### 5. GUI 调整(`app/gui/tabs/product_suite.py`) + +- 勾选项「每张上传图分别作为主图生成」旁增加 helper 文案(次要灰色小字,参考现有 helper 样式): + `多款式/多SKU图请勾选;同一商品多角度图不勾选,其余图将作为参考图一同提交。` +- 生成确认弹窗的「逐图主图」说明行更新为新规则表述;不勾选且上传图超过 8 张时,追加一行「参考图仅取前 7 张,其余不参与本轮生成」。 +- `1180x760` 及最小窗口尺寸下 helper 与弹窗文案不截断、不重叠。 + +### 6. 边界与超限 + +- 上传图 > 8:参考图取上传顺序前 7 张;确认弹窗与日志如实说明;`{参考图规则}` 的 N 用实际提交数,不用上传总数。 +- 单张参考图读取/编码失败:跳过该参考图并写中文日志,不使整个 job 失败;主图读取失败维持现状(job 失败)。 +- 上传仅 1 张时勾选与否行为一致(单图提交),不出现空参考数组。 + +## 验收标准 + +- [ ] 不勾选时,任一分类的生成请求 payload 为 `images` 数组:首元素为第 1 张上传图,后续为其余上传图按序(≤7 张);不含顶层旧单图字段。 +- [ ] 勾选时,每个请求 `images` 为单元素数组(当前主图);白底图仍只用第 1 张、按配置数量生成;其他分类每张上传图各生成配置数量。 +- [ ] 白底图默认数量为 1,允许用户调整,生成张数与配置一致;`suite_total_count()` 合计与实际 job 数一致。 +- [ ] 多图与单图请求均只扣一次点;确认弹窗总点数估算与实际扣点一致。 +- [ ] `{参考图规则}` 单图/多图两种渲染与实际提交张数严格一致;弹窗预览与新建 job 的最终 prompt 在同一 context 下完全相同。 +- [ ] `reference_asset_ids` 随 job 冻结落库;生成开始后增删上传图不影响本轮已创建 job;重试使用快照参考图列表。 +- [ ] 历史 job(`reference_asset_ids` 为 NULL)查看、恢复、重试行为不变,按单图提交。 +- [ ] 重试时参考资产文件缺失:跳过缺失项、剩余图片正常提交、写中文日志;主图缺失该 job 失败。 +- [ ] 上传图 > 8 时仅前 7 张作为参考提交,确认弹窗有明确中文说明。 +- [ ] 勾选项旁 helper 文案按定稿文案显示,`1180x760` 与最小窗口尺寸不截断。 +- [ ] 异步提交 `Idempotency-Key`、轮询、自动重试、失败退点语义与 T-564 一致,未被多图改动破坏。 +- [ ] cmhub 返回 `bad_request`(含多图字段混用)按不可重试错误处理并展示中文信息。 +- [ ] ②AI生成封面、AI 帮写、③「更新蝦皮」、CDP、计费展示不受影响。 + +## 测试要求 + +- 纯逻辑测试:`build_job_specs()` 勾选/不勾选 × 白底图/其他分类 × 上传 1/3/9 张的 `reference_asset_ids` 与 spec 数量矩阵;参考图排序、去除主图自身、>8 张裁剪。 +- `{参考图规则}` 渲染:单图文本、多图文本(N 取实际提交数)、上传 1 张勾选与不勾选文本一致;预览与 `build_job_specs()` prompt 相等。 +- 提交层:payload 使用 `images` 数组且不含顶层旧字段;单元素与多元素结构;参考图读取失败跳过并日志;主图失败 job 失败。 +- 迁移:新列 additive 迁移幂等;历史 NULL 行为单图提交;快照重试路径。 +- GUI:helper 文案存在与不截断断言;确认弹窗新规则说明与 >8 张提示(进 `tests/test_product_suite_gui.py`)。 + +## 文档同步 + +- 实现时更新 `docs/04-architecture.md`:商品套图多图提交规则、`reference_asset_ids` 快照语义、`{参考图规则}` 双态渲染。 +- 不修改冻结的 `docs/06-tasks.md`。 + +## 验证 + +```bash +py -3.10 -m unittest tests.test_product_suite +py -3.10 -m unittest tests.test_product_suite_gui +py -3.10 -m unittest tests.test_image_studio_generation +py -3.10 -m unittest discover -s tests +py -3.10 -m ruff check app tests main.py +py -3.10 -m compileall app main.py +git diff --check +``` + +## 非目标 + +- 不做多 SKU 自动识别或图片语义分组;多图关系由用户通过勾选项声明。 +- 不实现「多图联合生成一张多 SKU 拼图/色卡图」(源项目 `multi_sku` 详情图模式不迁移)。 +- 不修改点数计费规则、并发计划、轮询间隔或 cmhub 协议本身。 +- 不修改 T-637 占位符契约(变量清单与必需集不变,仅 `{参考图规则}` 渲染内容按事实扩展)。 +- 不修改 ③「更新蝦皮」、CDP、蝦皮主图拉取。 + +## 执行记录 + +- 待实现。