diff --git a/src/genesis/qa/validator.py b/src/genesis/qa/validator.py new file mode 100644 index 0000000..c4fc545 --- /dev/null +++ b/src/genesis/qa/validator.py @@ -0,0 +1,31 @@ +"""QA 校验:章节级/文档级评估(Phase 5)。""" +from __future__ import annotations + +from genesis.eval.scorer import ChapterScorer, EvalReport, ChapterArtifact +from genesis.writer.models import ChapterContent + + +class QAValidator: + def __init__(self, scorer: ChapterScorer | None = None) -> None: + self.scorer = scorer or ChapterScorer() + + def _to_artifact(self, content: ChapterContent) -> ChapterArtifact: + """把 ChapterContent 转换为评分器所需的 ChapterArtifact(聚合正文与来源 URI)。""" + text = "".join(b.text or "" for b in content.blocks) + source_uris: list[str] = [] + for b in content.blocks: + source_uris.extend(b.source_uris) + return ChapterArtifact( + chapter_id=content.chapter_id, + text=text, + source_uris=source_uris, + template_sections_expected=[], + ) + + def validate_chapter(self, content: ChapterContent, structured_source) -> tuple[bool, EvalReport]: + report = self.scorer.score([self._to_artifact(content)], structured_source) + passed = content.chapter_id not in report.failed_chapters + return passed, report + + def validate_document(self, contents: list[ChapterContent], structured_source) -> list[tuple[bool, EvalReport]]: + return [self.validate_chapter(c, structured_source) for c in contents] diff --git a/tests/test_phase5_validator.py b/tests/test_phase5_validator.py new file mode 100644 index 0000000..73c7151 --- /dev/null +++ b/tests/test_phase5_validator.py @@ -0,0 +1,32 @@ +from genesis.qa.validator import QAValidator +from genesis.writer.models import ChapterContent, ContentBlock + + +def _chapter(cid, text): + return ChapterContent( + chapter_id=cid, version=1, title=cid, + blocks=[ContentBlock(block_id="1", type="paragraph", text=text)], + ) + + +def test_validate_chapter_passes_good(): + v = QAValidator() + passed, report = v.validate_chapter(_chapter("a", "充分且规范的说明内容,满足写入规则要求。"), None) + assert passed is True + assert "a" not in report.failed_chapters + + +def test_validate_chapter_fails_short(): + v = QAValidator() + passed, report = v.validate_chapter(_chapter("b", "x"), None) + assert passed is False + assert "b" in report.failed_chapters + + +def test_validate_document_aggregates(): + v = QAValidator() + results = v.validate_document( + [_chapter("a", "充分且规范的说明内容,满足写入规则要求。"), _chapter("b", "x")], None + ) + assert len(results) == 2 + assert results[0][0] is True and results[1][0] is False