feat(writer): 输出语言一致性保障 + 用户可选输出语言
- 步骤0: 新增中文镜像模板 scripts/make_zh_template.py 与 samples/概要设计书模板_中文.docx(7章锚点原样保留) - 步骤1: config.WriterConfig.output_language→Settings.writer;GenerationContext.output_language + to_vars.language_instruction(zh/ja/auto);writer_agent【语言约束】改引变量;context_builder/orchestrator/run_trial 透传 --output-language - 步骤A: 新建 src/genesis/writer/language.py(detect_script/resolve_expected_language/find_language_violations);WriterAgent.generate_chapter 按期望语言强制、违规重试、耗尽硬失败;max_retries 默认 1→2 - 步骤B: _format_impact 影响调查标签按 output_language 本地化(zh 新建/变更/删除/警告) - 步骤C: eval scorer 第 11 维度 language_consistency(不可验证=满分,不拉低总分);ChapterArtifact.expected_language;QAValidator.validate_doc 透传;QALoop.run 透传 output_language - 测试: test_zh_template/test_language_plumbing/test_writer_language/test_scorer_language/test_language_coverage,并更新 test_phase5_e2e - 全量 pytest 424 passed / 99.15%(覆盖率门槛 99% 达标)
This commit is contained in:
@@ -0,0 +1,82 @@
|
||||
"""生成中文镜像模板(步骤 0)。
|
||||
|
||||
镜像既有日文概要设计书模板的结构与锚点 id(section:xxx 原样保留),
|
||||
仅将 H1/H2 标题与封面字段翻译为中文,产物 samples/概要设计书模板_中文.docx 入库。
|
||||
|
||||
锚点段落文本保持不变是硬约束:Writer 子系统(template_mapper / docx_injector)
|
||||
依赖这些占位符定位章节,任何改动都会破坏映射与注入。
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import shutil
|
||||
from pathlib import Path
|
||||
|
||||
from docx import Document
|
||||
|
||||
# H1/H2 标题日文 → 中文(保持编号前缀一一对应)
|
||||
HEADING_TRANSLATIONS: dict[str, str] = {
|
||||
"1. はじめに": "1. 前言",
|
||||
"2. 機能一覧": "2. 功能一览",
|
||||
"2.1 機能一覧表": "2.1 功能一览表",
|
||||
"2.2 機能詳細": "2.2 功能详细",
|
||||
"3. 画面一覧": "3. 画面一览",
|
||||
"3.1 画面遷移図": "3.1 画面迁移图",
|
||||
"3.2 画面一覧表": "3.2 画面一览表",
|
||||
"4. 帳票一覧": "4. 报表一览",
|
||||
"5. DB設計": "5. DB设计",
|
||||
"5.1 テーブル一覧": "5.1 表一览",
|
||||
"5.2 ER図": "5.2 ER图",
|
||||
"6. IF定義": "6. 接口定义",
|
||||
"7. バッチ一覧": "7. 批处理一览",
|
||||
}
|
||||
|
||||
# 封面字段(Normal 段落)日文 → 中文
|
||||
COVER_TRANSLATIONS: dict[str, str] = {
|
||||
"概要設計書": "概要设计书",
|
||||
"ドキュメント名: {{doc_title}}": "文档名: {{doc_title}}",
|
||||
"バージョン: {{version}}": "版本: {{version}}",
|
||||
"作成日: {{created_at}}": "创建日期: {{created_at}}",
|
||||
"テンプレート開始": "模板开始",
|
||||
}
|
||||
|
||||
|
||||
def _translate(text: str) -> str:
|
||||
"""锚点段落({{section:...}})原样保留;其余按字典翻译,未命中则原样。"""
|
||||
if text.startswith("{{section:"):
|
||||
return text
|
||||
return HEADING_TRANSLATIONS.get(text, COVER_TRANSLATIONS.get(text, text))
|
||||
|
||||
|
||||
def build_zh_template(src: str, dst: str) -> str:
|
||||
"""镜像 src(日文模板)为 dst(中文模板),返回 dst 路径。"""
|
||||
src_path = Path(src)
|
||||
dst_path = Path(dst)
|
||||
if not src_path.exists():
|
||||
raise FileNotFoundError(f"源模板不存在: {src_path}")
|
||||
dst_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
# 先物理复制(保留样式/编号定义等所有非文本属性),再逐段改写文本
|
||||
shutil.copyfile(str(src_path), str(dst_path))
|
||||
doc = Document(str(dst_path))
|
||||
for para in doc.paragraphs:
|
||||
new_text = _translate(para.text)
|
||||
if new_text != para.text:
|
||||
para.text = new_text
|
||||
doc.save(str(dst_path))
|
||||
return str(dst_path)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
import argparse
|
||||
|
||||
parser = argparse.ArgumentParser(description="生成中文镜像模板")
|
||||
default_src = str(Path(__file__).resolve().parents[1] / "samples" / "概要設計書テンプレート.docx")
|
||||
default_dst = str(Path(__file__).resolve().parents[1] / "samples" / "概要设计书模板_中文.docx")
|
||||
parser.add_argument("--src", default=default_src, help="源日文模板")
|
||||
parser.add_argument("--dst", default=default_dst, help="输出中文模板")
|
||||
args = parser.parse_args()
|
||||
out = build_zh_template(args.src, args.dst)
|
||||
print(f"中文模板已生成: {out}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -53,6 +53,8 @@ def _parse_args(argv: list[str] | None) -> argparse.Namespace:
|
||||
p.add_argument("--existing-system", default=str(ROOT / "samples" / "existing-system"),
|
||||
help="既有系统源码目录(追加/改修场景)")
|
||||
p.add_argument("--language", default="java", help="既有系统开发语言(默认 java,None=自动探测)")
|
||||
p.add_argument("--output-language", default="auto",
|
||||
choices=["auto", "zh", "ja"], help="输出语言:auto=与标题一致,zh=简体中文,ja=日文")
|
||||
p.add_argument("--samples-dir", default=str(ROOT / "samples"), help="样本资产根目录")
|
||||
p.add_argument("--output", default=str(ROOT / "output" / "output.docx"), help="概要设计书输出路径")
|
||||
p.add_argument("--impact-report", default=str(ROOT / "output" / "impact-report.json"),
|
||||
@@ -86,6 +88,7 @@ def main(argv: list[str] | None = None) -> dict:
|
||||
samples_dir=args.samples_dir,
|
||||
engine=engine,
|
||||
template_path=str(Path(args.template)),
|
||||
output_language=args.output_language,
|
||||
)
|
||||
|
||||
report = ss.impact_report
|
||||
|
||||
Reference in New Issue
Block a user