feat(ai-outfit): 左栏新增「标题生成」(看图→提示词→AI 文字标题→写回A列) (§19.18)

AI 穿搭页左栏新增独立的「生成标题」流程:用户写标题提示词,AI 看该行
衣服图(目录行取首图)生成电商标题,逐行立即写回 Excel A 列并刷新明细表;
完成后重载 Excel,紧接「开始生成」跑图即用新标题。移除原「最终生成要求预览」
腾出版面(docs/11 §17)。

- ai_text_service.py:AiTextClient 复用图像服务 HTTP 管道做文本输出;
  chat/gemini 带图视觉,images/images_edits 明确报错;extract_text 取首条标题
- ai_title.py + TitleResult:单行编排,never raises
- excel_service.write_title_result:只写 A 列、不动 D/E/F
- config_service:title_model 默认 + load/save_title_prompt + 默认标题话术
- 面板:标题生成组(提示词+标题模型下拉+保存+生成标题)置于话术组上方;
  _TitleWorker 顺序逐行+立即回填+刷新;与「开始生成」互斥;删预览相关组件
- 测试:文本解析/payload、generate_title(单文件/目录首图/失败)、
  write_title_result、面板标题组存在且无预览;全套 py37 通过

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-23 11:04:38 +08:00
co-authored by Claude Opus 4.8
parent 313e71b774
commit 2fa488bd21
12 changed files with 921 additions and 86 deletions
+16
View File
@@ -126,6 +126,22 @@ class TestOutfitExcelService(unittest.TestCase):
self.assertEqual(tasks[0].product_id, "")
self.assertEqual([r.row_index for r in read_all_rows(p)], [2])
def test_write_title_result_updates_a_only_and_saves(self):
"""标题生成回填只改 A 列,不动 D/E/F(docs/11 §17)。"""
from services.excel_service import write_title_result
# Row 3 starts as 完成 with D/E filled; writing a title must not touch them.
write_title_result(self.excel_path, 3, "AI 生成的电商标题")
wb = load_workbook(str(self.excel_path))
try:
ws = wb.active
self.assertEqual(ws.cell(3, 1).value, "AI 生成的电商标题") # A 改写
self.assertEqual(ws.cell(3, 4).value, r"D:\out\ty002.jpg") # D 不动
self.assertEqual(ws.cell(3, 5).value, "完成") # E 不动
finally:
wb.close()
def test_check_excel_writable_true_for_existing_workbook(self):
from services.excel_service import check_excel_writable