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

119 lines
9.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
id: T-621
title: ②只生成封面支持无新标题任务并保持图文结果独立
phase: 7
deps: [T-533, T-554, T-576]
status: DONE
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`,不自动切换用户选择的生成模式。
- 不放宽未采集任务;没有旧标题且没有新标题时不提交生图。
- 不改变③真实更新确认和高风险边界。
## 执行记录
- 2026-07-13:`app/ai.py` 新增统一的封面标题上下文,`cover` 模式按 `new_title` 优先、`old_title` 回退判断资格并渲染prompt;`title_cover` 仍须先生成新标题,不用旧标题绕过生文失败。
- 2026-07-13:`app/db.py` 新增组件级 `set_generated_cover()`,封面成功只更新 `new_cover_path`,保留 `new_title`(包括NULL),并按AI成功口径更新阶段、状态、尝试次数和时间。
- 2026-07-13:②表格改为持有精确 `generate_mode`;只生成封面时,无新标题但有旧标题的任务可进入待生成筛选,封面成功后保持“标题待生成 / 图片已生成”。封面prompt预览复用同一回退规则,运行日志明确提示使用旧标题作为封面参考。
- 2026-07-13:补充AI、DB、GUI和③更新模式测试,覆盖无新标题独立生图、旧标题不回写、后补标题保留封面、状态/筛选/预览/进度,以及只有“只更新封面”放行该组件结果;同步需求、架构、API和界面流程文档。
- 2026-07-13:主工作区GUI全量测试仅有2项既有默认提示词重命名断言失败,与本任务无关;在只包含T-621差异的干净worktree运行 `python -m ruff check app tests main.py`、`py -3.10 -m compileall app main.py`、`py -3.10 -m unittest discover -s tests`(429项通过)、`git diff --check`,结果全部通过。