Files
cmshoppe/docs/tasks/T-643.md
T

7.4 KiB
Raw Blame History

id, title, phase, deps, status, created
id title phase deps status created
T-643 商品套图持久化当前生成轮次 7
T-642
TODO 2026-07-16

问题 / 背景

⑥「商品套图」当前把 SuiteTaskState.current_job_ids 作为“本轮结果”的唯一依据。该字段只存在于 GUI 内存中:

  • 软件重启、关闭任务后重新输入商品 ID,无法恢复上次正在使用的一轮生成结果;
  • image_studio_jobs 只有单张生成 job,没有持久化的轮次和槽位字段;
  • 「历史生成」当前只能把当前项目全部 job 混在同一个结果网格中,无法可靠区分整轮生成、单张失败重试和更早历史;
  • 如果直接隐藏「历史生成」,已有项目重新打开后可能显示“还没有生成结果”,但数据库和本地图片实际仍然存在。

产品目标是:每个店铺商品项目在主界面默认只展示一轮“当前结果”,同时保留以前的 job、图片、错误和计费记录,供后续历史弹窗查看。不能通过创建时间间隔、文件夹名称或图片数量猜测轮次。

方案

1. 为生成 job 增加持久化轮次与槽位

修改 SQLite schema、迁移和 app/image_studio.py 数据模型:

  • image_studio_projects 增加可空 current_generation_round_key,表示主界面当前使用的生成轮次;
  • image_studio_jobs 增加 generation_round_key,同一次整轮生成创建的 job 使用同一个不可复用 UUID;
  • image_studio_jobs 增加 generation_slot_index,按本轮生成规格顺序从 0 开始稳定编号;
  • 为 (project_id, generation_round_key, generation_slot_index, id) 增加适合查询当前槽位和历史轮次的索引;
  • 数据类、建库和增量迁移同步兼容旧数据库。

不把 GUI run_token 直接作为长期业务主键。轮次 key 可以在本轮开始时由 GUI 创建并传给 worker,但持久化语义是“生成轮次”,不承担迟到信号隔离职责。

2. 整轮生成创建新轮次

修改 app/gui/tabs/product_suite.py、app/gui/workers.py 和生成服务调用:

  • 正常点击「生成套图」时创建新的 generation_round_key;
  • worker 创建每条 job 时同时写入该轮次 key 和稳定槽位;
  • 活动运行仍使用现有 generation_run_token 做线程/迟到信号隔离,不改变 T-639/T-640 的终态看门狗;
  • 当前会话内继续用 current_job_ids 实时展示本轮 job,避免等待整轮完成后才显示;
  • 本轮至少有一个成功结果时,把项目 current_generation_round_key 原子更新为新轮次;
  • 本轮全部失败、全部取消或未创建有效结果时,保留原来的当前轮,失败轮仍进入历史记录;
  • 部分成功时允许新轮成为当前轮,主界面保留成功和失败槽位,用户可继续按 T-640 单张重试。

切换当前轮不得删除、覆盖或改写旧轮次 job、计费、错误和输出资产。

3. 单张重试留在原轮次和原槽位

T-640 的单张失败重试继续新建 job,但必须:

  • 继承原 job 的 generation_round_key;
  • 继承原 job 的 generation_slot_index;
  • 当前轮每个槽位默认取该轮次、该槽位最新创建的 job;
  • 重试成功、再次失败或取消都只替换该槽位在主界面的当前版本,其他槽位和轮次不变;
  • 原失败 job 和每次重试 job 全部保留,供历史详情和问题审计使用。

成功图片的主动“重新生成”若后续开放,也必须明确是替换当前槽位还是新增变体;本任务不扩大该入口。

4. 已有项目和旧版 job 兼容

旧数据库中的 job 没有可靠的轮次边界,不得按时间差或图片数量猜测:

  • 迁移后旧 job 使用明确的 legacy 兼容轮次语义,或保持空值并由查询层统一映射为“旧版历史记录”;
  • 若项目只有旧版 job、没有新格式当前轮,主界面可以临时展示“旧版历史记录”,避免用户误以为图片丢失;
  • 用户完成下一次新格式整轮生成后,项目切换到新轮次,旧 job 只在历史记录中展示;
  • 文件缺失时保留 job/asset 记录并显示不可用状态,不自动删除历史。

5. 当前结果查询与恢复

在 app/image_studio.py 提供结构化 API:

  • 设置或读取项目当前轮次;
  • 按项目列出生成轮次摘要;
  • 按轮次和槽位读取当前有效 job;
  • 按轮次读取全部尝试记录,供 T-644 历史弹窗使用。

商品项目绑定、草稿恢复、任务切换和软件重启后:

  • 从项目持久化的当前轮次恢复 current_job_ids;
  • 按槽位顺序展示,不使用 updated_at 排序打乱图片位置;
  • 当前轮不存在、job 被软删除或图片文件缺失时给出稳定空态/缺失态,不抛出裸英文错误;
  • generation_job_ids 仍只表示当前活动请求,不从历史轮次恢复。

6. 数据一致性和诊断

  • 设置当前轮次、读取轮次槽位和单张重试替换必须校验 project/job 归属;
  • 不允许把其他账号、商品项目或草稿项目的轮次设为当前轮;
  • 当前轮 key、job 数量、成功/失败数量可写诊断日志,不记录提示词全文、图片 URL、密钥或 Cookie;
  • schema 变化同步更新 docs/04-architecture.md、docs/api.md 和 docs/routes.md。

验收要点

  • 商品完成一轮生成后,关闭软件并重新打开相同店铺和商品 ID,主结果区恢复同一轮、同一顺序的图片。
  • 再生成一整轮后,主界面只展示新当前轮,旧轮 job、图片、错误和计费记录仍保留。
  • 新轮全部失败或全部取消时,原当前轮继续显示;失败轮可以被历史查询读取。
  • 新轮部分成功时切换为当前轮,成功和失败槽位均可见,失败槽位可继续单张重试。
  • 单张失败重试沿用原轮次和槽位,其他当前图片不消失、不换序。
  • 程序重启后重试结果仍占据原槽位,原失败 job 仍存在。
  • 旧数据库可以自动迁移;旧 job 不被猜测性拆分、删除或覆盖。
  • 当前轮和历史轮查询不会跨店铺、跨商品或跨项目串数据。
  • 不影响生成停止、迟到信号隔离、恢复未完成 cmhub 任务和本地图片保存。

测试

  • tests/test_db.py:
    • 新建数据库字段与索引;
    • 旧数据库增量迁移;
    • 重复初始化幂等。
  • tests/test_image_studio.py:
    • 当前轮设置/读取和项目归属校验;
    • 轮次摘要、槽位当前 job、全部尝试查询;
    • 旧版 job 兼容。
  • tests/test_workers.py:
    • 整轮 job 写入相同轮次和稳定槽位;
    • 单张重试继承轮次和槽位。
  • tests/test_product_suite_gui.py:
    • 项目重新绑定和重启恢复当前轮;
    • 新轮成功、部分成功、全失败/取消时的当前轮切换;
    • 单张重试跨重启保持槽位。
  • 运行:
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

边界(不改什么)

  • 不删除旧轮次 job、生成图片、错误、扣点或余额记录。
  • 不通过扫描目录、文件名、时间差或图片数量猜测轮次。
  • 不在本任务实现历史弹窗、历史图片删除或“恢复历史轮为当前轮”。
  • 不修改 cmhub API、模型别名、提示词组装、并发、超时、轮询和下载协议。
  • 不修改 CDP、蝦皮主图拉取、①导入采集、②AI生成、③更新蝦皮、④账号管理或⑤设置。

执行记录

  • 待执行。