feat(writer): add WriteOrchestrator.generate (vertical slice, real DocxInjector.inject)
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
"""Writer 编排:上下文装配 → 逐章生成 → 渲染 → docx 注入(Phase 5 垂直切片)。"""
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
from docx import Document
|
||||
|
||||
from genesis.data_models import StructuredSource
|
||||
from genesis.inference.engine import InferenceEngine
|
||||
from genesis.inference.prompt_registry import PromptRegistry
|
||||
from genesis.writer.context_builder import build_contexts
|
||||
from genesis.writer.docx_injector import Block, DocxInjector
|
||||
from genesis.writer.models import ChapterContent
|
||||
from genesis.writer.renderer import render_chapter_blocks
|
||||
from genesis.writer.writer_agent import WriterAgent
|
||||
from genesis.writer.writer_state import WriterState
|
||||
|
||||
|
||||
def _section_id_of(placeholder: str | None) -> str | None:
|
||||
if not placeholder or not placeholder.startswith("section:"):
|
||||
return None
|
||||
return placeholder[len("section:"):]
|
||||
|
||||
|
||||
class WriteOrchestrator:
|
||||
def generate(
|
||||
self,
|
||||
structured_source: StructuredSource,
|
||||
output_path: str,
|
||||
session_id: str = "writer",
|
||||
samples_dir: str = "samples",
|
||||
engine=None,
|
||||
prompt_registry=None,
|
||||
template_path: str | None = None,
|
||||
) -> list[ChapterContent]:
|
||||
engine = engine or InferenceEngine()
|
||||
prompt_registry = prompt_registry or PromptRegistry()
|
||||
ctxs = build_contexts(structured_source, samples_dir)
|
||||
state = WriterState([c.chapter_id for c in ctxs])
|
||||
agent = WriterAgent(session_id=session_id, engine=engine, prompt_registry=prompt_registry, state=state)
|
||||
|
||||
contents: list[ChapterContent] = []
|
||||
sections: dict[str, list[Block]] = {}
|
||||
for ctx in ctxs:
|
||||
content = agent.generate_chapter(ctx)
|
||||
contents.append(content)
|
||||
blocks = render_chapter_blocks(content)
|
||||
sec_id = _section_id_of(ctx.template_marker.section_placeholder)
|
||||
if sec_id:
|
||||
sections[sec_id] = blocks
|
||||
|
||||
tpl = template_path or getattr(structured_source.template, "file_name", None)
|
||||
if not tpl:
|
||||
raise ValueError("template_path 必须提供(structured_source.template.file_name 为空)")
|
||||
doc = DocxInjector(tpl).inject(sections, meta={})
|
||||
Path(output_path).parent.mkdir(parents=True, exist_ok=True)
|
||||
doc.save(output_path)
|
||||
return contents
|
||||
Reference in New Issue
Block a user