Files
life-echo/api/app/features/memoir/chapter_markdown_compose.py
Kevin 8af37e5e8e 修复:CI 部署环境与 ref 错配、迁移碎片化、图片意图 source_span、章节物化脏版式、会话历史与本地语音不一致
新增:TTS 上传 COS 与分片、章节 reading_segments 物化与快照、markdown 清洗、会话消息 repository、语音 store 重构与相关测试
2026-03-20 16:43:02 +08:00

68 lines
2.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
按 chapter_story_links 顺序将各 story 正文物化为单一 markdown无 LLM
保留 story 内 asset:// 引用不变。
章节级 canonical仅正文拼接故事间用 ---;故事标题仅存 stories.title。
PDF 导出可单独物化「## 标题 + 正文」版本。
"""
from typing import Any
from app.features.memoir.markdown_sanitize import sanitize_story_for_chapter_compose
def _gather_title_body_pairs(chapter: Any) -> list[tuple[str, str]]:
links = sorted(
list(getattr(chapter, "story_links", None) or []),
key=lambda x: getattr(x, "order_index", 0),
)
pairs: list[tuple[str, str]] = []
for link in links:
st = getattr(link, "story", None)
if st is None:
continue
title = (getattr(st, "title", None) or "").strip()
body = (getattr(st, "canonical_markdown", None) or "").strip()
pairs.append((title, body))
return pairs
def compose_ordered_stories_to_markdown(ordered: list[tuple[str, str]]) -> str:
"""
:param ordered: (story_title, canonical_markdown) 已按阅读顺序排好title 仅用于清洗去重)
:return: 章节级 markdown仅各故事正文非空块之间用 \\n\\n---\\n\\n 分隔
"""
bodies: list[str] = []
for title, md in ordered:
raw = (md or "").strip()
if not raw:
continue
cleaned = sanitize_story_for_chapter_compose(raw, title)
if cleaned:
bodies.append(cleaned)
return "\n\n---\n\n".join(bodies)
def compose_ordered_stories_to_pdf_markdown(ordered: list[tuple[str, str]]) -> str:
"""PDF每故事 ## 标题 + 正文,块间 ---(标题来自元数据,不写回章节 canonical"""
parts: list[str] = []
for title, md in ordered:
t = (title or "").strip() or "故事"
raw = (md or "").strip()
if not raw:
continue
body = sanitize_story_for_chapter_compose(raw, title)
if not body:
continue
parts.append(f"## {t}\n\n{body}")
return "\n\n---\n\n".join(parts)
def materialize_chapter_markdown_from_loaded_chapter(chapter: Any) -> str:
"""要求 chapter.story_links 已 eager-load且各 link.story 可用。"""
return compose_ordered_stories_to_markdown(_gather_title_body_pairs(chapter))
def materialize_chapter_pdf_markdown_from_loaded_chapter(chapter: Any) -> str:
"""PDF 专用:含每段 ## 故事名。"""
return compose_ordered_stories_to_pdf_markdown(_gather_title_body_pairs(chapter))