fix(ai-outfit): 标题生成对「标题(A)空」的印花表不再误报无行 (§19.27)

catch-22:「生成标题」用 read_all_rows 取行,而它要求 标题(A)+原始图片路径(C)
都非空;但标题生成的目的就是填 A。印花导出表若 A 空(被清空/早期导出),
所有行被跳过 → 误报「该表没有可处理的行」。实测 output/20260623_094529.xlsx:
A 全空、C 是印花子目录。

- excel_service.read_all_rows 增 require_title=True 开关:False 时只在
  原始图片路径(C) 空时跳过、允许 标题(A) 空;默认 True 行为不变(预览/
  无待处理统计/图片生成 load_outfit_tasks 仍要求 A)
- ai_outfit_panel._TitleWorker.run 改调 read_all_rows(..., require_title=False)

测试:A 空+C 有的行 require_title=False 收录、默认跳过;C 空两种都跳过。
全套 py37 通过(test_config_service 的 packaging 模板失败属并行 §19.13,无关)。
离屏冒烟:真表 20260623_094529.xlsx 默认 0 行→require_title=False 加载 6 行;
worker 把 6 条标题按序回填 A、C(印花目录)不动。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-23 17:35:13 +08:00
co-authored by Claude Opus 4.8
parent be1eb9ee36
commit a9360f9421
5 changed files with 59 additions and 8 deletions
+3 -1
View File
@@ -429,7 +429,9 @@ Excel 行 → `OutfitTask` 列表的转换由 `excel_service` 完成;核心只
> **§17.7 改版**:早期为「逐行看图、各生成 1 条」(每行一次请求、带图)。现改为
> **一次请求、纯提示词(不传图)、生成多条、按序回填**(用户在提示词里自写数量)。
- **行来源**:复用 `excel_service.read_all_rows(excel)`(状态无关)——拿到全部有效行(仅为「填到哪些行 + 行号」),**覆盖式**写 A,不看 E 列状态、不引入新列。
- **行来源(§19.27)**:用 `excel_service.read_all_rows(excel, require_title=False)`(状态无关)——拿到全部数据行(仅为「填到哪些行 + 行号」),**覆盖式**写 A,不看 E 列状态、不引入新列。
- **关键:标题生成的行来源只要求 原始图片路径(C) 非空,标题(A) 可空**。因为 A 正是要生成/覆盖的列;若沿用「A 必须非空」(图片生成/预览的规则),则 A 空的印花表(恰恰最需要生成标题)会被全部跳过 → 误报「该表没有可处理的行」(§19.27 修复的 catch-22)。
- `read_all_rows(excel, require_title=True)`(默认)行为不变:要求 标题(A)+原始图片路径(C) 都非空——预览弹窗、`_show_no_pending_message` 统计仍用默认;图片生成的 `load_outfit_tasks` 也仍要求 A(`{title}` 是输入)。
- **一次请求、纯提示词**:把用户标题提示词**原样**(不带图、不替换 `{title}`)发一次给文本模型;提示词里由用户自写数量并**约定标题之间用逗号隔开**(如「生成 6 条…标题之间用逗号分隔,不要表格/换行/序号」)。
- **按逗号拆分多条**:把响应文本按**逗号**(半角 `,` / 全角 `,`,并兼容换行作兜底分隔)拆成多条,每条清洗(去首尾空白、去行首序号/符号 `1. / - / ①`、去首尾引号、丢空)→ 得到标题列表。**不再按行/不解析 Markdown 表格**——靠提示词约定逗号分隔(§19.23)。
- **按序回填**:第 i 条 → 第 i 行 A(`write_title_result(excel, row_index, title)`),逐条写、刷新中栏「处理明细」表该行「标题」列。