feat(ai): generate covers without new titles

This commit is contained in:
chengma
2026-07-13 15:22:15 +08:00
parent e2fbae2ee1
commit d42a9c8084
13 changed files with 334 additions and 36 deletions
+88
View File
@@ -129,6 +129,32 @@ class AITests(TempDirMixin, unittest.TestCase):
)
return batch_id, db.list_tasks(batch_id=batch_id, path=cfg["db_path"])
def test_cover_title_context_and_cover_only_generation_needs(self):
task = SimpleNamespace(
stage="collected",
status="success",
old_title="旧标题",
new_title=None,
new_cover_path=None,
apply_attempts=0,
)
self.assertEqual("旧标题", ai.cover_title_context(task))
self.assertEqual(
{"title": False, "cover": True},
ai.generation_needs(task, generate_mode="cover"),
)
task.new_title = "新标题"
self.assertEqual("新标题", ai.cover_title_context(task))
task.new_title = None
task.old_title = ""
self.assertEqual("", ai.cover_title_context(task))
self.assertFalse(ai.is_generatable_task(task, generate_mode="cover"))
self.assertEqual(
{"title": True, "cover": True},
ai.generation_needs(task, generate_mode="title_cover"),
)
def _write_old_cover_files(self, tasks):
from PIL import Image
@@ -1644,6 +1670,68 @@ class AITests(TempDirMixin, unittest.TestCase):
self.assert_removed(temp_dir)
def test_generate_batch_cover_only_uses_old_title_and_keeps_new_title_empty(self):
with self.make_temp_dir() as temp_dir:
cfg = self._config()
cfg["db_path"] = os.path.join(temp_dir, "cmshopee.db")
cfg["image_dir"] = os.path.join(temp_dir, "images")
cfg["ai"]["generate_mode"] = "cover"
cfg["ai"]["generate_cover"] = True
batch_id, tasks = self._collected_tasks(temp_dir, cfg, ["旧标题"])
cover_prompts = []
events = []
def fake_cover(cover_prompt, old_cover_path, out_path, **kwargs):
cover_prompts.append(cover_prompt)
os.makedirs(os.path.dirname(out_path), exist_ok=True)
with open(out_path, "wb") as fh:
fh.write(b"jpeg")
return out_path
with mock.patch("app.ai.gen_title") as gen_title, \
mock.patch("app.ai.gen_cover", side_effect=fake_cover) as gen_cover:
summary = ai.generate_batch(
tasks,
{"title": "标题提示", "cover": "封面 {新标题} / {旧标题}"},
ai_cfg={
"config": cfg,
"db_path": cfg["db_path"],
"on_event": events.append,
},
)
self.assertTrue(summary["ok"])
self.assertEqual(0, summary["title_total"])
self.assertEqual(1, summary["cover_total"])
gen_title.assert_not_called()
gen_cover.assert_called_once()
self.assertEqual(["封面 旧标题 / 旧标题"], cover_prompts)
updated = db.get_task(tasks[0].id, path=cfg["db_path"])
self.assertIsNone(updated.new_title)
self.assertTrue(os.path.exists(updated.new_cover_path))
self.assertTrue(
any("使用旧标题作为封面参考" in str(event.get("detail") or "") for event in events)
)
cfg["ai"]["generate_mode"] = "title"
cfg["ai"]["generate_cover"] = False
with mock.patch("app.ai.gen_title", return_value="后补新标题") as gen_title, \
mock.patch("app.ai.gen_cover") as gen_cover:
title_summary = ai.generate_batch(
[updated],
{"title": "标题提示", "cover": "封面"},
ai_cfg={"config": cfg, "db_path": cfg["db_path"]},
)
self.assertTrue(title_summary["ok"])
gen_title.assert_called_once()
gen_cover.assert_not_called()
completed = db.get_task(tasks[0].id, path=cfg["db_path"])
self.assertEqual("后补新标题", completed.new_title)
self.assertEqual(updated.new_cover_path, completed.new_cover_path)
self.assert_removed(temp_dir)
def test_generate_batch_fills_reset_cover_after_committed_history(self):
with self.make_temp_dir() as temp_dir:
cfg = self._config()