feat(writer): add Phase5 data models (ContentBlock/ChapterContent/GenerationContext/ChapterSpec)
This commit is contained in:
@@ -0,0 +1,51 @@
|
|||||||
|
"""Writer 子系统数据模型(Phase 5)。"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from dataclasses import dataclass, field
|
||||||
|
from typing import Literal
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class ContentBlock:
|
||||||
|
"""LLM 生成的内容块。注意:table.headers/caption、list.items/style 在渲染至
|
||||||
|
DocxInjector.Block 时显式丢弃(renderer 中声明并测试)。"""
|
||||||
|
|
||||||
|
block_id: str
|
||||||
|
type: Literal["paragraph", "heading", "table", "list", "note"]
|
||||||
|
level: int | None = None
|
||||||
|
text: str | None = None
|
||||||
|
caption: str | None = None
|
||||||
|
headers: list[str] | None = None
|
||||||
|
rows: list[list[str]] | None = None
|
||||||
|
items: list[str] | None = None
|
||||||
|
style: str | None = None
|
||||||
|
source_uris: list[str] = field(default_factory=list)
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class ChapterContent:
|
||||||
|
chapter_id: str
|
||||||
|
version: int
|
||||||
|
title: str
|
||||||
|
blocks: list[ContentBlock]
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class ChapterSpec:
|
||||||
|
"""template_mapper 产出:驱动 WriterAgent 串行顺序。"""
|
||||||
|
|
||||||
|
chapter_id: str
|
||||||
|
title: str
|
||||||
|
section_placeholder: str | None = None # 如 "{{section:db_design}}",无则 None
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class GenerationContext:
|
||||||
|
chapter_id: str
|
||||||
|
title: str
|
||||||
|
template_marker: ChapterSpec
|
||||||
|
structured_source: object | None
|
||||||
|
write_rules: list[str]
|
||||||
|
design_rules: list[str]
|
||||||
|
template_styles: set[str]
|
||||||
|
prior_state: object | None = None # WriterState,避免循环 import 用 object
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
from dataclasses import FrozenInstanceError
|
||||||
|
from genesis.writer.models import ContentBlock, ChapterContent, GenerationContext, ChapterSpec
|
||||||
|
|
||||||
|
|
||||||
|
def test_content_block_defaults():
|
||||||
|
b = ContentBlock(block_id="b1", type="paragraph", text="你好")
|
||||||
|
assert b.level is None
|
||||||
|
assert b.source_uris == []
|
||||||
|
|
||||||
|
|
||||||
|
def test_chapter_content_holds_blocks():
|
||||||
|
b = ContentBlock(block_id="b1", type="heading", level=2, text="标题")
|
||||||
|
c = ChapterContent(chapter_id="db_design", version=1, title="DB 设计", blocks=[b])
|
||||||
|
assert c.blocks[0].type == "heading"
|
||||||
|
assert c.version == 1
|
||||||
|
|
||||||
|
|
||||||
|
def test_generation_context_no_impact_field():
|
||||||
|
ctx = GenerationContext(
|
||||||
|
chapter_id="db_design", title="DB 设计",
|
||||||
|
template_marker=ChapterSpec(chapter_id="db_design", title="DB 设计", section_placeholder="{{section:db_design}}"),
|
||||||
|
structured_source=None, write_rules=["规则1"], design_rules=["规则2"],
|
||||||
|
template_styles={"Heading 1"},
|
||||||
|
)
|
||||||
|
assert not hasattr(ctx, "impact")
|
||||||
|
|
||||||
|
|
||||||
|
def test_chapter_spec_placeholder_optional():
|
||||||
|
s = ChapterSpec(chapter_id="x", title="X", section_placeholder=None)
|
||||||
|
assert s.section_placeholder is None
|
||||||
Reference in New Issue
Block a user