From 08e311b0a1f3225d7eb0c7f642ce49d461613ae7 Mon Sep 17 00:00:00 2001 From: lhl Date: Thu, 13 Aug 2026 10:32:35 +0800 Subject: [PATCH] feat(writer): add WriteOrchestrator.generate (vertical slice, real DocxInjector.inject) --- samples/phase5-slice/output.docx | Bin 0 -> 35416 bytes samples/phase5-slice/template.docx | Bin 0 -> 35376 bytes scripts/run_phase5_slice.py | 76 +++++++++++++++++++++++ src/genesis/writer/orchestrator.py | 58 +++++++++++++++++ tests/test_phase5_writer_orchestrator.py | 49 +++++++++++++++ 5 files changed, 183 insertions(+) create mode 100644 samples/phase5-slice/output.docx create mode 100644 samples/phase5-slice/template.docx create mode 100644 scripts/run_phase5_slice.py create mode 100644 src/genesis/writer/orchestrator.py create mode 100644 tests/test_phase5_writer_orchestrator.py diff --git a/samples/phase5-slice/output.docx b/samples/phase5-slice/output.docx new file mode 100644 index 0000000000000000000000000000000000000000..fb293eca95f395c7b7121f378b769784f10bf9ec GIT binary patch literal 35416 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 literal 0 HcmV?d00001 diff --git a/scripts/run_phase5_slice.py b/scripts/run_phase5_slice.py new file mode 100644 index 0000000..ca63a0f --- /dev/null +++ b/scripts/run_phase5_slice.py @@ -0,0 +1,76 @@ +"""Phase 5 垂直切片运行脚本(CLI)。 + +用法: + python scripts/run_phase5_slice.py --template --output [--fake] + +- --fake: 使用内置 FakeEngine(无需 LLM 客户端/API Key),用于验证管线打通。 +- 不带 --fake: 使用真实 InferenceEngine(),需先配置 LLM 客户端(人工质量门禁)。 + +管线: WordTemplateParser → StructuredSource → WriteOrchestrator.generate → docx。 +""" +from __future__ import annotations + +import argparse +from types import SimpleNamespace + +from docx import Document + +from genesis.data_models import StructuredSource +from genesis.parsers.word_template_parser import WordTemplateParser +from genesis.writer.orchestrator import WriteOrchestrator + + +class FakeEngine: + """切片验证用假引擎:返回固定章节内容,避免真实 LLM 调用。""" + + def chat_structured(self, *, session_id, prompt, variables, schema, retry_count=2): + return SimpleNamespace( + data={ + "title": variables.get("title", "章"), + "blocks": [{"type": "paragraph", "text": f"【{variables.get('title','')}】自动生成的内容(fake 模式)"}], + }, + status="ok", + ) + + +def _build_source(template_path: str) -> StructuredSource: + parsed = WordTemplateParser().parse(template_path) + return StructuredSource( + tables=[], + template=parsed, + rule_docs=[], + image_analyses=[], + existing_system=None, + comments=[], + ) + + +def _main() -> None: + parser = argparse.ArgumentParser(description="Phase 5 垂直切片运行脚本") + parser.add_argument("--template", required=True, help="概要设计模板 docx 路径") + parser.add_argument("--output", required=True, help="输出 docx 路径") + parser.add_argument("--fake", action="store_true", help="使用 FakeEngine(无 LLM)") + parser.add_argument("--samples-dir", default="samples", help="RAG 样本目录") + args = parser.parse_args() + + source = _build_source(args.template) + engine = FakeEngine() if args.fake else None # None → 真实 InferenceEngine()(需客户端配置) + + orch = WriteOrchestrator() + contents = orch.generate( + source, + args.output, + samples_dir=args.samples_dir, + engine=engine, + template_path=args.template, + ) + loaded = Document(args.output) + joined = "\n".join(p.text for p in loaded.paragraphs) + print(f"[slice] 生成章节数: {len(contents)}") + print(f"[slice] 输出路径: {args.output}") + print(f"[slice] 注入校验: {'OK' if any('自动生成' in p.text for p in loaded.paragraphs) else 'EMPTY'}") + print(f"[slice] 文本内容预览:\n{joined[:200]}") + + +if __name__ == "__main__": + _main() diff --git a/src/genesis/writer/orchestrator.py b/src/genesis/writer/orchestrator.py new file mode 100644 index 0000000..0124cff --- /dev/null +++ b/src/genesis/writer/orchestrator.py @@ -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 diff --git a/tests/test_phase5_writer_orchestrator.py b/tests/test_phase5_writer_orchestrator.py new file mode 100644 index 0000000..b0a93d1 --- /dev/null +++ b/tests/test_phase5_writer_orchestrator.py @@ -0,0 +1,49 @@ +import pytest +from types import SimpleNamespace +from docx import Document + +from genesis.data_models import ParsedTemplate, ChapterMarker +from genesis.writer.orchestrator import WriteOrchestrator +from genesis.writer.models import ChapterContent + + +class FakeEngine: + def chat_structured(self, *, session_id, prompt, variables, schema, retry_count=2): + # 返回一个固定章节内容(title + 一个段落块) + return SimpleNamespace( + data={"title": variables["title"], "blocks": [{"type": "paragraph", "text": "自动生成的内容"}]}, + status="ok", + ) + + +def _make_template(path): + doc = Document() + doc.add_paragraph("はじめに", style="Heading 1") + doc.add_paragraph("{{section:introduction}}") + doc.save(path) + + +def _ss(template_path): + parsed = ParsedTemplate( + file_name=template_path, + sections=[ + ChapterMarker(type="heading", name="はじめに", level=1), + ChapterMarker(type="placeholder", name="section:introduction", level=0), + ], + placeholders={}, + styles={"defined": ["Heading 1"], "used": ["Heading 1"]}, + ) + return SimpleNamespace(template=parsed) + + +def test_generate_produces_filled_docx(tmp_path): + tpl = tmp_path / "tpl.docx" + out = tmp_path / "out.docx" + _make_template(str(tpl)) + orch = WriteOrchestrator() + contents = orch.generate(_ss(str(tpl)), str(out), samples_dir="nonexistent_dir_xyz", engine=FakeEngine()) + assert isinstance(contents, list) and len(contents) == 1 + # 输出 docx 含注入文本且无残留异常 + loaded = Document(str(out)) + joined = "\n".join(p.text for p in loaded.paragraphs) + assert "自动生成的内容" in joined