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

9.4 KiB
Raw Blame History

id, title, phase, deps, status, created
id title phase deps status created
T-621 ②只生成封面支持无新标题任务并保持图文结果独立 7
T-533
T-554
T-576
DONE 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,结果全部通过。