fix: 修复 Liblib provider 认证和多个图片生成关键缺陷
- 重写 LiblibImageProvider:Bearer token 改为 HMAC-SHA1 签名认证, 适配 Liblib 真实 API(Star-3 Alpha 文生图端点) - 修复 chapter.images JSON 列原地修改不持久化(深拷贝+整列重赋值) - 修复 generate_chapter_images 在事务提交前派发(改为 commit 后统一 delay) - 修复 initialize_chapter_images 覆盖已完成图片(新增 merge 去重逻辑) - 修复 Android failed 图片渲染为错误卡片(改为隐藏,保持正文连续) - 模型模板 UUID 改为环境变量配置(LIBLIB_TEMPLATE_UUID) - 更新 .env 凭证格式为 ACCESS_KEY/SECRET_KEY - 补充 test_memoir_image_bootstrap 缺失的 unittest.mock 导入 Made-with: Cursor
This commit is contained in:
74
api/tests/test_process_memoir_segments_image_enqueue.py
Normal file
74
api/tests/test_process_memoir_segments_image_enqueue.py
Normal file
@@ -0,0 +1,74 @@
|
||||
import unittest
|
||||
from types import SimpleNamespace
|
||||
from unittest.mock import Mock, patch
|
||||
|
||||
from api.tasks.memoir_tasks import MemoirImageSettings, process_memoir_segments
|
||||
|
||||
|
||||
class ProcessMemoirSegmentsImageEnqueueTest(unittest.TestCase):
|
||||
@patch("api.tasks.memoir_tasks._update_task_status_sync")
|
||||
@patch("api.tasks.memoir_tasks._release_chapter_lock")
|
||||
@patch("api.tasks.memoir_tasks._acquire_chapter_lock", return_value=True)
|
||||
@patch("api.tasks.memoir_tasks._classify_chapter_category", return_value="childhood")
|
||||
@patch("api.tasks.memoir_tasks._get_or_create_state_sync")
|
||||
@patch("api.tasks.memoir_tasks.llm_service.get_llm", return_value=None)
|
||||
@patch("api.tasks.memoir_tasks.generate_chapter_images.delay")
|
||||
@patch("api.tasks.memoir_tasks.SessionLocal")
|
||||
@patch("api.tasks.memoir_tasks.MemoirImageSettings.from_env")
|
||||
def test_process_memoir_segments_enqueues_image_jobs_after_commit(
|
||||
self,
|
||||
settings_from_env,
|
||||
session_local_cls,
|
||||
delay_mock,
|
||||
_get_llm,
|
||||
get_state_mock,
|
||||
_classify_mock,
|
||||
_acquire_lock_mock,
|
||||
_release_lock_mock,
|
||||
_update_status_mock,
|
||||
):
|
||||
settings_from_env.return_value = MemoirImageSettings(
|
||||
enabled=True,
|
||||
max_per_chapter=2,
|
||||
provider="liblib",
|
||||
default_style="watercolor",
|
||||
default_size="1024x1024",
|
||||
poll_interval_seconds=3,
|
||||
max_attempts=20,
|
||||
)
|
||||
get_state_mock.return_value = SimpleNamespace(current_stage="childhood", slots={})
|
||||
|
||||
segment = SimpleNamespace(
|
||||
id="segment-1",
|
||||
transcript_text="那条路我一直记得。\n\n{{{{IMAGE:南方小镇的青石板路}}}}",
|
||||
processed=False,
|
||||
)
|
||||
|
||||
segments_result = Mock()
|
||||
segments_result.scalars.return_value.all.return_value = [segment]
|
||||
|
||||
chapter_result = Mock()
|
||||
chapter_result.scalar_one_or_none.return_value = None
|
||||
|
||||
book_result = Mock()
|
||||
book_result.scalar_one_or_none.return_value = None
|
||||
|
||||
db = Mock()
|
||||
db.execute.side_effect = [segments_result, chapter_result, book_result]
|
||||
db.get.return_value = None
|
||||
session_local_cls.return_value = db
|
||||
|
||||
events: list[str] = []
|
||||
db.commit.side_effect = lambda: events.append("commit")
|
||||
delay_mock.side_effect = lambda chapter_id: events.append(f"delay:{chapter_id}")
|
||||
|
||||
task_self = SimpleNamespace(
|
||||
request=SimpleNamespace(id="task-1"),
|
||||
retry=Mock(side_effect=AssertionError("retry should not be called")),
|
||||
)
|
||||
process_memoir_segments.run.__func__(task_self, "user-1", ["segment-1"])
|
||||
|
||||
self.assertIn("commit", events)
|
||||
delay_events = [event for event in events if event.startswith("delay:")]
|
||||
self.assertEqual(len(delay_events), 1)
|
||||
self.assertGreater(events.index(delay_events[0]), events.index("commit"))
|
||||
Reference in New Issue
Block a user