""" 按 chapter_story_links 顺序将各 story 正文物化为单一 markdown(无 LLM)。 保留 story 内 asset:// 引用不变。 """ from typing import Any def compose_ordered_stories_to_markdown( ordered: list[tuple[str, str]], ) -> str: """ :param ordered: (story_title, canonical_markdown) 已按阅读顺序排好 :return: 章节级 markdown;每个故事为 ## 标题 + 正文,故事之间用 markdown 水平线 --- 分隔 (配图在 story 正文中,自然落在该故事块内、--- 之前) """ parts: list[str] = [] for title, md in ordered: title = (title or "").strip() or "故事" body = (md or "").strip() parts.append(f"## {title}\n\n{body}" if body else f"## {title}") return "\n\n---\n\n".join(parts) def materialize_chapter_markdown_from_loaded_chapter(chapter: Any) -> str: """要求 chapter.story_links 已 eager-load,且各 link.story 可用。""" 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 compose_ordered_stories_to_markdown(pairs)