feat(memoir+conversation): 章节/故事最小可读字数;会话 hasUserMessage 与 UI 优化

- 后端:300 字门槛统一物化、hydrate、列表/PDF/详情;过短章节对读者隐藏
- 对话:首包前打字动画、大字模式排版、朗读/TTS 交互与布局稳定
- 首页:复用无用户消息会话;空列表「继续对话」与文案 i18n
- 章节阅读:标题进正文、封面与去重标题;阅读 Markdown 字号上调
This commit is contained in:
Kevin
2026-03-26 16:28:33 +08:00
parent d990399112
commit 1374f6e8f5
15 changed files with 708 additions and 198 deletions

View File

@@ -28,6 +28,9 @@ from app.features.memoir.helpers import (
)
from app.features.memoir.memoir_images.settings import MemoirImageSettings
from app.features.memoir.models import Book, Chapter, ChapterStoryLink
from app.features.memoir.reading_segment_materialize import (
chapter_meets_minimum_display,
)
from app.features.memory.service import MemoryService
from app.ports.storage import ObjectStorage
@@ -144,7 +147,12 @@ class MemoirService:
.order_by(Chapter.order_index)
)
result = await self._db.execute(stmt)
chapters = list(result.unique().scalars().all())
chapters_raw = list(result.unique().scalars().all())
chapters: List[Chapter] = []
for ch in chapters_raw:
ch2 = await self._ensure_chapter_materialized(ch)
if chapter_meets_minimum_display(ch2):
chapters.append(ch2)
asset_ids = collect_asset_ids_for_chapters(chapters)
asset_map = await signed_urls_for_asset_ids(self._db, asset_ids)
pdf_bytes = await pdf_service.generate_pdf(
@@ -170,6 +178,9 @@ class MemoirService:
asset_map = await signed_urls_for_asset_ids(self._db, asset_ids)
all_chapters: List[dict] = []
for ch in chapters:
ch = await self._ensure_chapter_materialized(ch)
if not chapter_meets_minimum_display(ch):
continue
await self._cleanup_unavailable_images(ch)
all_chapters.append(chapter_to_list_dict(ch, asset_url_map=asset_map))
return all_chapters
@@ -184,6 +195,8 @@ class MemoirService:
raise HTTPException(status_code=404, detail="Chapter not found")
chapter = await self._ensure_chapter_materialized(chapter)
await self._cleanup_unavailable_images(chapter)
if not chapter_meets_minimum_display(chapter):
raise HTTPException(status_code=404, detail="Chapter not found")
asset_map = await signed_urls_for_asset_ids(
self._db, collect_asset_ids_for_chapter(chapter)
)