Files
cmbot/tests/test_ai_outfit_panel.py
T
adminandClaude Opus 4.8 2fa488bd21 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>
2026-06-23 11:04:38 +08:00

104 lines
3.3 KiB
Python

"""Smoke tests for AI outfit panel defaults (offscreen Qt)."""
import os
import shutil
import sys
import tempfile
import unittest
from pathlib import Path
os.environ.setdefault("QT_QPA_PLATFORM", "offscreen")
sys.path.insert(0, str(Path(__file__).parent.parent / "src"))
import services.file_service as fs
from services.config_service import DEFAULT_CONFIG
class TestAiOutfitPanelDefaults(unittest.TestCase):
def setUp(self):
self.tmp = Path(tempfile.mkdtemp())
self._env = os.environ.get("CMBOT_DATA_DIR")
os.environ["CMBOT_DATA_DIR"] = str(self.tmp / "data")
self.app_dir = self.tmp / "app"
self.app_dir.mkdir(parents=True)
self._orig_get_app_dir = fs.get_app_dir
fs.get_app_dir = lambda: self.app_dir
self.app = self._app()
def tearDown(self):
fs.get_app_dir = self._orig_get_app_dir
if self._env is None:
os.environ.pop("CMBOT_DATA_DIR", None)
else:
os.environ["CMBOT_DATA_DIR"] = self._env
shutil.rmtree(str(self.tmp), ignore_errors=True)
def _app(self):
from PySide6.QtWidgets import QApplication
app = QApplication.instance()
if app is None:
app = QApplication([])
return app
def _panel(self):
from app.widgets.ai_outfit_panel import AiOutfitPanel
return AiOutfitPanel()
def test_empty_config_defaults_to_outfit_output_dir(self):
panel = self._panel()
cfg = dict(DEFAULT_CONFIG)
cfg["outfit_output_dir"] = ""
panel.apply_config(cfg)
self.assertEqual(Path(panel._output_edit.text()), self.app_dir / "穿搭图片")
def test_saved_outfit_output_dir_takes_precedence(self):
panel = self._panel()
saved = self.tmp / "custom-output"
cfg = dict(DEFAULT_CONFIG)
cfg["outfit_output_dir"] = str(saved)
panel.apply_config(cfg)
self.assertEqual(Path(panel._output_edit.text()), saved)
def test_generation_setting_label_is_image_concurrency(self):
from PySide6.QtWidgets import QLabel
panel = self._panel()
labels = [label.text() for label in panel.findChildren(QLabel)]
self.assertIn("图片并发数", labels)
def test_title_group_present_and_preview_removed(self):
"""标题生成组存在,预览块已移除(docs/11 §17)。"""
from PySide6.QtWidgets import QLabel
panel = self._panel()
panel.apply_config(dict(DEFAULT_CONFIG))
labels = [label.text() for label in panel.findChildren(QLabel)]
self.assertIn("标题生成提示词", labels)
self.assertIn("标题模型", labels)
self.assertNotIn("最终生成要求预览", labels)
# The preview widgets and methods are gone.
self.assertFalse(hasattr(panel, "_preview_view"))
self.assertFalse(hasattr(panel, "_sample_combo"))
self.assertTrue(hasattr(panel, "_title_btn"))
self.assertTrue(hasattr(panel, "_title_model_combo"))
def test_title_prompt_defaults_loaded(self):
from services.config_service import DEFAULT_TITLE_PROMPT
panel = self._panel()
panel.apply_config(dict(DEFAULT_CONFIG))
self.assertEqual(panel._title_prompt_edit.toPlainText(), DEFAULT_TITLE_PROMPT)
if __name__ == "__main__":
unittest.main()