修复:CI 部署环境与 ref 错配、迁移碎片化、图片意图 source_span、章节物化脏版式、会话历史与本地语音不一致
新增:TTS 上传 COS 与分片、章节 reading_segments 物化与快照、markdown 清洗、会话消息 repository、语音 store 重构与相关测试
This commit is contained in:
@@ -14,7 +14,11 @@ from app.core.config import settings
|
||||
from app.core.db import get_sync_db
|
||||
from app.core.logging import get_logger
|
||||
from app.features.memoir.asset_resolver import strip_legacy_image_placeholders
|
||||
from app.features.memoir.cover_eligibility import primary_chapter_memoir_image
|
||||
from app.features.memoir.cover_eligibility import (
|
||||
chapter_eligible_for_cover_by_inline_body_image_count,
|
||||
chapter_needs_cover_enqueue,
|
||||
primary_chapter_memoir_image,
|
||||
)
|
||||
from app.features.memoir.models import Chapter
|
||||
|
||||
logger = get_logger(__name__)
|
||||
@@ -42,6 +46,8 @@ def _chapter_eligible_for_http_enqueue(chapter: Chapter | None) -> bool:
|
||||
body = strip_legacy_image_placeholders(body).strip()
|
||||
if not body:
|
||||
return False
|
||||
if not chapter_eligible_for_cover_by_inline_body_image_count(chapter):
|
||||
return False
|
||||
cover_rec = primary_chapter_memoir_image(chapter)
|
||||
if cover_rec and (cover_rec.status or "").strip() == "completed":
|
||||
return False
|
||||
@@ -49,12 +55,8 @@ def _chapter_eligible_for_http_enqueue(chapter: Chapter | None) -> bool:
|
||||
|
||||
|
||||
def _chapter_eligible_for_pipeline_enqueue(chapter: Chapter | None) -> bool:
|
||||
"""与 memoir.cover_eligibility.chapter_needs_cover_enqueue 一致。"""
|
||||
if not chapter:
|
||||
return False
|
||||
if getattr(chapter, "cover_asset_id", None):
|
||||
return False
|
||||
return bool((getattr(chapter, "canonical_markdown", None) or "").strip())
|
||||
"""尚无 cover_asset、正文插图数 > 3(与 HTTP 闸门共用 chapter_needs_cover_enqueue 核心)。"""
|
||||
return bool(chapter_needs_cover_enqueue(chapter))
|
||||
|
||||
|
||||
def _load_chapter_for_enqueue_sync(chapter_id: str) -> Chapter | None:
|
||||
|
||||
@@ -22,6 +22,9 @@ from app.features.memoir.chapter_cover import (
|
||||
aggregate_cover_prompt_from_chapter,
|
||||
aggregate_cover_prompt_from_stories,
|
||||
)
|
||||
from app.features.memoir.cover_eligibility import (
|
||||
chapter_eligible_for_cover_by_inline_body_image_count,
|
||||
)
|
||||
from app.features.memoir.memoir_images.storage import TencentCosStorageService
|
||||
from app.features.memoir.models import Chapter, ChapterCoverIntent, ChapterStoryLink
|
||||
from app.ports.image_gen import TaskStatus
|
||||
@@ -197,6 +200,13 @@ def generate_chapter_cover(self, chapter_id: str):
|
||||
)
|
||||
return {"status": "no_chapter"}
|
||||
|
||||
if not chapter_eligible_for_cover_by_inline_body_image_count(chapter):
|
||||
logger.info(
|
||||
"generate_chapter_cover: chapter=%s, reason=insufficient_inline_body_images",
|
||||
chapter_id,
|
||||
)
|
||||
return {"status": "insufficient_inline_body_images"}
|
||||
|
||||
if getattr(chapter, "cover_asset_id", None):
|
||||
logger.info(
|
||||
"generate_chapter_cover: chapter=%s, reason=has_cover_asset",
|
||||
|
||||
@@ -263,11 +263,13 @@ def generate_story_image(self, story_id: str):
|
||||
return {"status": "success_no_snapshot", "asset_id": asset_id}
|
||||
|
||||
base_md = ver.markdown_snapshot or ""
|
||||
alt_text = (getattr(intent_db, "prompt_brief", None) or "").strip()
|
||||
if not alt_text:
|
||||
alt_text = (getattr(intent_db, "caption", None) or "").strip()
|
||||
backfilled_md = backfill_image_into_markdown(
|
||||
base_md,
|
||||
asset_id=asset_id,
|
||||
caption=intent_db.caption or "主插图",
|
||||
source_span=intent_db.source_span,
|
||||
image_alt=alt_text or "主插图",
|
||||
)
|
||||
max_stmt = select(func.max(StoryVersion.version_no)).where(
|
||||
StoryVersion.story_id == story_id
|
||||
|
||||
Reference in New Issue
Block a user