--- id: T-651 title: 商品套图生成前的数量与预计扣点确认 phase: 7 deps: [T-650] status: DONE created: 2026-07-17 --- ## 问题 / 背景 ⑥「商品套图」正常点击「生成套图」后,当前已有「确认生成商品套图」弹窗。它会显示店铺、商品 ID、可用原图数量、各分类实际生成张数、比例、总张数和“本次生成会消耗 cmhub 点数”。但用户看不到当前配置下的预计单张/总扣点,也无法清晰区分“每张上传图分别作为主图生成”对各分类数量的实际影响。 实际生成数量不是简单的原图数量:`product_suite.build_job_specs()` 先按分类数量规划 job;开启逐图主图时,场景图、卖点图等非白底分类按每张可用原图展开,白底图仍只使用第一张原图。当前确认文字只有“是/否”,可能让用户误以为白底图也会按每张原图重复生成。 T-650 将提供图片理解价格确认所需的短期 cmhub 模型目录缓存和安全价格读取边界;套图正式生图应复用同一份模型目录缓存,不能重复设计另一套价格来源。 ## 方案 ### 1. 基于实际 job 规划计算可确认的预估价格 - 继续先完成现有模板、项目、原图、卖点和数量校验,并构建最终 `specs`;确认框中的分类数量和总数必须来自 `specs`,不是从界面文字或原图数量猜测; - 复用 T-650 的进程内 cmhub 模型目录缓存和后台刷新机制,按当前 `image_alias` 查找可用的正式生图模型价格;缓存键、脱敏、失效和线程管理遵守 T-650,不另存 API Key、价格或模型目录; - 只有模型目录能明确给出每个正式生图 job 的唯一、无条件歧义 `points_cost` 时,才计算「预计单张扣点」与「预计总扣点」。总点数等于该确认框中 `len(specs)` 个 planned job 的单价合计;不得按上传原图数量、勾选数量或“前8张”规则自行倍乘; - 若价格与分辨率、质量档或其他服务器条件相关而无法唯一确定,或目录不可用/未定价/字段缺失,则不显示数字总价,只显示「本次会消耗 cmhub 点数,暂时无法取得预计扣点,实际以网关返回为准」;不得取最低价、最高价、平均价或沿用过期未知价格; - 预估价格仅供确认,不预扣余额、不写 SQLite/Excel/运行日志、不影响 job 成功失败。每个 job 完成后仍以 cmhub 返回的 `points_cost`/`points_balance` 作为实际计费事实。 ### 2. 优化正式生成确认弹窗内容 在既有「确认生成商品套图」弹窗中保留并整理为清晰的中文分组: ```text 店铺:... 商品ID:... 可用商品原图:N 张 逐图主图:已开启 说明:白底图只使用第一张原图;场景图、卖点图和自定义分类会按每张原图分别生成。 白底图:1 张 场景图:6 张 卖点图:6 张 图片比例:1:1 本次生成总数:13 张 预计单张扣点:2 点 预计总扣点:26 点 实际扣点以 cmhub 返回为准。 ``` - 逐图主图关闭时,明确说明所有分类均只使用第一张可用原图; - 分类行只显示本次实际存在的类别,保持 `product_suite.category_order()` 顺序,自定义分类追加在后; - 不显示模型别名、API URL、图片路径、Key、原始上游错误或内部 task ID; - 按钮继续使用「确认生成」和「返回修改」,默认/关闭/Esc 均不提交生成;价格读取阶段需要后台处理,不得卡住 GUI 或提前创建 `ProductSuiteGenerateWorker`。 ### 3. 与历史确认、取消和并发的顺序 - 已有成功套图时,先保留 T-648 的“查看历史 / 继续生成新一轮 / 取消”确认;只有用户选择继续后,才进入包含数量和预计扣点的正式生成确认; - 价格读取、确认框和最终提交之间必须防重复点击。用户取消、关闭、切换任务或关闭任务时,不创建正式生成 worker、不写 job、不调用 cmhub 生图; - 最终确认前重新核对当前任务、原图和 `specs` 仍有效。若配置或原图在等待价格期间已变化,取消旧确认并重新计算,不可用旧数量或旧价格提交; - 单张失败图片的“重新生成”和恢复未完成任务沿用现有语义,不强行套用整轮批量确认;如后续需要显示单图预估扣点,另行设计,不在本任务扩展。 ### 4. 测试与文档 - `tests/test_product_suite_gui.py`:覆盖逐图主图开/关时确认文案、白底图例外、分类实际数量、确定价格的单价/总价、未知价格降级、取消不创建 worker、确认只创建一次 worker、已有历史的两段确认顺序; - `tests/test_product_suite.py` / `tests/test_ai.py`:覆盖 `specs` 数量与预估总价只按 planned job 计算,多个条件价格或无价格时不产生数字估算; - 同步更新 `docs/04-architecture.md`、`docs/api.md`、`docs/routes.md`,说明正式套图生成的确认、逐图主图例外和预估/实际扣点边界; - 运行: ```bash py -3.10 -m unittest tests.test_ai tests.test_product_suite tests.test_product_suite_gui tests.test_workers 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 ``` ## 验收要点 - [ ] 正常点击「生成套图」在真正提交前显示基于最终 `specs` 的分类数量、总张数和逐图主图说明。 - [ ] 开启逐图主图时明确白底图只使用第一张原图,其余分类按每张原图展开;关闭时明确所有分类只使用第一张原图。 - [ ] 已知唯一 per-job 价格时显示预计单张扣点和预计总扣点,且总价只按 planned job 数量计算。 - [ ] 价格未知或有歧义时不显示伪造数字,用户仍可明确选择确认或返回修改。 - [ ] 历史确认、价格读取、正式确认和 worker 启动顺序正确,取消不会创建 job 或产生生图请求。 - [ ] 实际扣点仍由 cmhub 响应决定,不预扣、不改变余额或计费协议。 - [ ] 不影响 AI帮写、②AI生成、历史、单图重试、导出、Shopee CDP、采集、更新蝦皮、账号管理或设置模块。 ## 边界(不改什么) - 不修改 cmhub 生图接口、模型别名、超时、轮询、下载、重试、并发或点数协议。 - 不新增余额硬阻断、自动充值、批量预算、价格持久化或“不再确认”开关。 - 不修改 `build_job_specs()` 的实际生成规则、分类数量、提示词、原图排序或白底图使用第一张原图的既有语义。 - 不改变单张失败重试、恢复未完成任务或历史导出的确认路径。 ## 执行记录 - 2026-07-17:根据商品套图生成前的数量、逐图主图和预计扣点确认需求创建任务。待实现。 - 2026-07-17:开始复用 T-650 模型目录缓存实现常规套图生成的明细扣点确认。 - 2026-07-17:已实现常规套图生成的后台价格读取和二次确认:历史确认后按最终 `specs` 展示逐图主图说明、分类实际数量、总张数、比例及可确定的单张/总预估点数。计划变化、取消读取、切换或关闭任务均不会创建生图 job;单图重试和恢复保持原路径。验证:`py -3.10 -m unittest discover -s tests`(577 项通过)、`py -3.10 -m ruff check app tests main.py`、`py -3.10 -m compileall app main.py`、`git diff --check` 通过。