diff --git a/docs/tasks/T-621.md b/docs/tasks/T-621.md new file mode 100644 index 0000000..4d981f7 --- /dev/null +++ b/docs/tasks/T-621.md @@ -0,0 +1,114 @@ +--- +id: T-621 +title: ②只生成封面支持无新标题任务并保持图文结果独立 +phase: 7 +deps: [T-533, T-554, T-576] +status: TODO +created: 2026-07-13 +--- + +## 问题 / 背景 + +②「AI生成」选择“只生成封面”时,当前实现仍要求任务已有 `new_title`。当用户选中一个已经完成采集、但全部没有新标题的批次后点击“开始生成”,GUI提示:`当前筛选结果没有可生成封面的任务,请先生成标题。` + +这不是批次筛选或cmhub异常,而是T-576旧口径的主动限制: + +- `ai.generation_needs(..., generate_mode="cover")` 只有在 `new_title` 非空时才把缺封面的任务判为可生成; +- `GenerateTab.start_generate()` 过滤后得到空任务列表,直接显示“请先生成标题”; +- 封面prompt上下文目前把 `new_title` 作为 `{新标题}` 的值; +- 封面成功统一调用 `db.set_generated(task_id, new_title, new_cover_path)`,同时写标题和封面,尚未提供“只写封面、保持标题为空”的AI成功写库语义; +- ②表格图片状态在没有 `new_title` 时显示“未开始”,与真正独立生成封面的目标不一致。 + +用户已经在“生成内容”下拉中明确选择“只生成封面”,本轮不应再强制产生标题模型费用。新产品口径调整为:**只生成封面可以处理没有新标题、但已经采集到旧标题的任务;旧标题只作为封面生成的语义参考,不得写入或伪装成新标题。** + +## 方案 + +### 1. 调整封面生成资格 + +- `app/ai.py` 的 `generation_needs()` / `is_generatable_task()`: + - `generate_mode=cover` 时,只要任务处于可生成阶段、尚无 `new_cover_path`,并且存在可用标题上下文,即可进入本轮; + - 标题上下文优先级:非空 `new_title` → 非空 `old_title`; + - `new_title` 与 `old_title` 都为空时仍不可生图,避免向模型提交缺少商品语义的空prompt; + - `title`、`title_cover` 两种模式保持现有增量逻辑,`title_cover` 仍先补新标题再生成封面。 +- 可提取纯helper(例如 `cover_title_context(task)`),让资格判断、prompt预览、批量生成使用同一套优先级,避免GUI预览与实际请求不一致。 + +### 2. 封面prompt使用有效标题,但不伪造新标题 + +- `generate_mode=cover` 且无 `new_title` 时,渲染封面prompt的 `{新标题}` 使用 `old_title` 作为兼容回退;`{旧标题}` 仍保持原旧标题。 +- 该回退只存在于本轮封面prompt上下文。不得把 `old_title` 回写到 `tasks.new_title`,不得让标题状态显示“已生成”。 +- GUI“封面提示词预览”必须复用同一helper:在“只生成封面”模式且没有新标题时,预览结果应与实际cmhub请求一致。 +- 用户日志增加简短中文说明,例如:`商品 xxx 没有新标题,本轮使用旧标题作为封面参考`;不输出完整prompt、接口路径或敏感字段。 + +### 3. 增加只写封面的AI成功写库语义 + +- 在 `app/db.py` 增加职责明确的成功写库helper(名称可按现有风格确定,例如 `set_generated_cover()`): + - 只更新 `new_cover_path`; + - 保留原 `new_title`,包括继续保持 `NULL`; + - 设置 `stage=generated`、`status=success`,清除本轮生成错误; + - 按现有AI成功口径更新 `generate_attempts`、`generated_at`、`updated_at`; + - 不修改 `committed`、更新尝试次数或重置计数。 +- `generate_batch()` 的封面成功路径改用该helper或等价的组件级写库方式;有无新标题都不得因保存封面而覆盖标题字段。 +- 现有 `db.set_generated()` 继续服务标题成功及图文完整结果,不做破坏性语义变更。 +- 不修改SQLite schema。 + +### 4. 修正②列表、筛选和提示 + +- ②选择“只生成封面”时: + - 已采集、有旧标题、无新标题、无新封面的记录应进入“待生成”筛选; + - 图片状态显示“待生成”,标题状态继续显示“待生成”; + - 生成成功后图片状态显示“已生成”,标题状态仍为“待生成”。 +- `GenerateTaskTableModel` 需要知道当前精确 `generate_mode`,不能只依赖“是否包含封面”的布尔值来判断无新标题时的图片状态;保持兼容接口时也要确保模式切换会刷新状态列。 +- 当前筛选确实没有封面缺口时,提示改为不强制先生成标题的准确文案,例如:`当前筛选结果没有可生成的封面;请确认商品已完成采集且尚未生成新封面。` +- `title_total=0`、`cover_total=N`,标题进度明确显示本轮不生成标题;不得因无新标题把任务从封面进度总数中排除。 + +### 5. 保持后续图文流程独立 + +- 只生成封面成功后,用户可在③选择“只更新封面”,③只按 `new_cover_path` 校验并更新线上封面。 +- 此时若③选择“只更新标题”或“更新标题和封面”,仍应因缺 `new_title` 在打开Chrome前阻断。 +- 用户后续回到②选择“只生成标题”或“生成标题和封面”时: + - 只补缺失的新标题; + - 保留已经生成的新封面,不重复生图、不重复扣图片点; + - 新标题成功后标题状态变为“已生成”。 +- Excel回写、封面画廊、封面重置与候选图归档继续允许“有新封面、无新标题”的组件独立状态。 + +## 验收要点 + +- 已采集且有旧标题、没有新标题和新封面的整批任务,在②选择“只生成封面”后可以直接开始生图。 +- 本轮不调用标题生成接口,标题点数不增加;封面请求使用 `new_title or old_title` 作为标题语义上下文。 +- 封面生成成功后,SQLite中 `new_cover_path` 有值、`new_title` 仍为 `NULL`/空;不得把旧标题写成新标题。 +- ②标题状态仍为“待生成”,图片状态为“已生成”;程序重启和刷新后状态保持一致。 +- 无新标题但有旧标题的任务能进入“待生成”筛选;新旧标题都为空的任务不进入,并显示准确中文提示。 +- 封面prompt预览与实际请求使用相同回退规则。 +- 之后选择“只生成标题”只补标题并保留现有封面,不重复提交生图任务。 +- ③“只更新封面”可使用该结果;③“只更新标题/更新标题和封面”继续阻断缺标题任务。 +- 已有新标题的“只生成封面”和“生成标题和封面”现有增量流程不回归。 + +## 测试要求 + +- `tests/test_ai.py`:覆盖无新标题但有旧标题时 `cover` 资格为真、无任何标题时为假、标题上下文优先级,以及图文模式原逻辑不变。 +- `tests/test_db.py`:覆盖组件级封面成功只更新封面、保留空/已有新标题,并正确更新成功状态和时间/尝试字段。 +- `tests/test_gui.py`:覆盖整批无新标题时可以启动只生成封面、prompt预览回退、标题/图片状态、待生成筛选、进度总数、用户日志及后续只补标题保留封面。 +- 覆盖③三种更新模式对“有封面、无标题”任务的前置校验回归。 +- 运行: + - `python -m ruff check app tests main.py` + - `py -3.10 -m compileall app main.py` + - `py -3.10 -m unittest discover -s tests` + - `git diff --check` + +## 文档同步 + +- 更新 `docs/02-requirements.md`:移除“只生成封面要求任务已有新标题”的旧口径。 +- 更新 `docs/04-architecture.md`、`docs/api.md`、`docs/routes.md`:记录封面标题上下文回退、组件级写库与“有封面、无新标题”的合法状态。 +- T-576保持DONE作为历史决策;本任务在其上明确覆盖旧限制,不回写历史任务结论。 + +## 边界(不改什么) + +- 不修改cmhub/direct HTTP协议、生图submit/poll/download、并发、重试、超时、计费和图片保存格式。 +- 不修改SQLite schema、Excel列结构、Shopee/CDP选择器、账号登录或Chrome前台策略。 +- 不自动生成标题,不把旧标题复制到 `new_title`,不自动切换用户选择的生成模式。 +- 不放宽未采集任务;没有旧标题且没有新标题时不提交生图。 +- 不改变③真实更新确认和高风险边界。 + +## 执行记录 + +(完成后记录实现、验证命令与结果。)