修复一些已知问题

This commit is contained in:
Kevin
2026-03-20 17:25:42 +08:00
parent 8af37e5e8e
commit 70070216c4
16 changed files with 350 additions and 74 deletions

View File

@@ -8,6 +8,7 @@ from app.features.memoir.asset_resolver import (
collect_asset_ids_from_markdown,
resolve_asset_refs_in_markdown,
split_markdown_by_asset_refs,
strip_asset_image_refs_from_markdown,
strip_legacy_image_placeholders,
)
from app.features.memoir.models import Chapter
@@ -53,6 +54,22 @@ class AssetResolverTest(unittest.TestCase):
ids = collect_asset_ids_for_chapter(ch)
self.assertEqual(ids, {"a1", "cov1"})
def test_strip_asset_image_refs_removes_all_and_collapses_blank_lines(self):
md = (
"第一段\n\n![a](asset://old-id-1)\n\n第二段\n\n\n"
"![b](asset://old-id-2)\n\n第三段"
)
out = strip_asset_image_refs_from_markdown(md)
self.assertNotIn("asset://", out)
self.assertIn("第一段", out)
self.assertIn("第二段", out)
self.assertIn("第三段", out)
self.assertNotIn("\n\n\n", out)
def test_strip_asset_image_refs_empty(self):
self.assertEqual(strip_asset_image_refs_from_markdown(""), "")
self.assertEqual(strip_asset_image_refs_from_markdown(" "), "")
def test_collect_asset_ids_includes_linked_story_markdown(self):
ch = SimpleNamespace(
canonical_markdown="",

View File

@@ -134,6 +134,103 @@ class GenerateStoryImageTaskTest(unittest.TestCase):
acquire_lock_mock.assert_called_once()
release_lock_mock.assert_called_once()
@patch("app.tasks.story_image_tasks.release_redis_lock")
@patch(
"app.tasks.story_image_tasks.acquire_redis_lock",
return_value=SimpleNamespace(key="lock:story-image:story-1"),
)
@patch("app.tasks.story_image_tasks._claim_story_image_intent_sync")
@patch("app.tasks.story_image_tasks.get_sync_db")
@patch("app.tasks.story_image_tasks.TencentCosStorageService")
@patch("app.tasks.story_image_tasks.get_image_generator")
@patch("app.features.memoir.memoir_images.settings.MemoirImageSettings.from_env")
@patch("app.tasks.story_image_tasks.uuid.uuid4")
def test_generate_story_image_strips_existing_asset_refs_before_backfill(
self,
uuid4_mock,
settings_from_env,
get_image_generator_mock,
storage_cls,
get_sync_db_mock,
claim_intent_mock,
acquire_lock_mock,
release_lock_mock,
):
uuid4_mock.side_effect = [
_FakeUUID("claim-token"),
_FakeUUID("new-asset-uuid"),
_FakeUUID("version-uuid"),
]
settings_from_env.return_value = SimpleNamespace(
provider="liblib",
default_style="watercolor",
default_size="1024x1024",
)
intent = SimpleNamespace(
id="intent-1",
prompt_brief="院子里的藤椅",
style_profile="watercolor",
story_version_id="ver-1",
caption="主插图",
status="processing",
)
story = SimpleNamespace(
id="story-1",
user_id="user-1",
title="童年的院子",
stage="childhood",
)
db_claim = Mock()
claim_intent_mock.return_value = (intent, story)
intent_db = SimpleNamespace(
id="intent-1",
story_version_id="ver-1",
caption="主插图",
prompt_brief="院子里的藤椅",
status="processing",
style_profile="watercolor",
claim_token="claim-token",
asset_id=None,
error=None,
updated_at=None,
)
story_db = SimpleNamespace(
id="story-1",
current_version_id="ver-1",
canonical_markdown="第一段\n\n第二段",
)
version_db = SimpleNamespace(
id="ver-1",
markdown_snapshot=("第一段\n\n![旧图](asset://old-stale-id)\n\n第二段"),
)
version_max_result = Mock()
version_max_result.scalar.return_value = 1
db_persist = Mock()
db_persist.get.side_effect = [intent_db, story_db, version_db]
db_persist.execute.return_value = version_max_result
get_sync_db_mock.side_effect = [_mock_db_cm(db_claim), _mock_db_cm(db_persist)]
generator = get_image_generator_mock.return_value
generator.generate.return_value = ImageResult(
status=TaskStatus.COMPLETED,
task_id="task-1",
image_url="https://provider.example.com/story.png",
)
generator.download_image.return_value = _png_bytes()
storage_cls.from_env.return_value.upload_bytes.return_value = (
"https://cos.example.com/stories/u1/s1.png"
)
result = generate_story_image.run("story-1")
self.assertEqual(result["status"], "success")
self.assertEqual(story_db.canonical_markdown.count("asset://"), 1)
self.assertIn("asset://new-asset-uuid", story_db.canonical_markdown)
self.assertNotIn("old-stale-id", story_db.canonical_markdown)
@patch("app.tasks.story_image_tasks.acquire_redis_lock", return_value=None)
@patch("app.tasks.story_image_tasks.get_sync_db")
@patch("app.tasks.story_image_tasks.get_image_generator")