Files
2026Technology-Competition/scripts/run_trial.py
T
lhl becd3e1f57 chore(assets): 参赛提交规范红线修复(ASCII 化 + 相对路径)
按《参赛成果物提交规范·赛道一》§6 红线:
- samples/ 目录改名 sample/(git mv,保留历史)
- 10 个中日文样本文件 + docs 参赛手册 PDF 重命名为 ASCII
  (requirements_*/template_*/rules_*/contestant-handbook.pdf)
- tests/test_zh_template.py 硬编码绝对路径 D:\00_project\Genesis 改为相对路径
- 全局更新 21 个活动文件引用;历史日志/审查文档不改(追加说明记录)
全量 pytest 431 passed / 99.15%
2026-08-26 14:15:52 +08:00

119 lines
4.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""库级端到端试运行驱动(真实 LLM / 离线 Fake)。
用法:
python scripts/run_trial.py [--fake] [--output out.docx] ...
默认输入为 sample/ 下既有样本(追加改修·股票场景 + sunOnly 既有系统 + 真实概要设计书模板)。
真实模式需先在 .env 配置 GENESIS_INFERENCE__API_KEY(见 README「运行说明」),
缺失时抛 LLMNotConfiguredError 并给出配置提示;--fake 为离线确定性引擎,无需 key。
输出:
概要设计书 docx + 影响调查书 impact-report.json(默认写至 output/,不入库)。
"""
from __future__ import annotations
import argparse
import json
import sys
from pathlib import Path
from types import SimpleNamespace
ROOT = Path(__file__).resolve().parents[1]
if str(ROOT / "src") not in sys.path:
sys.path.insert(0, str(ROOT / "src"))
from genesis.impact.impact_agent import impact_report_to_dict # noqa: E402
from genesis.parsers.source_aggregator import SourceParser # noqa: E402
from genesis.writer.orchestrator import WriteOrchestrator # noqa: E402
class FakeEngine:
"""离线确定性引擎:章节正文固定为占位文本(用于无 key 验证整条管线)。"""
def chat_structured(self, *, session_id, prompt, variables, schema, retry_count=2):
return SimpleNamespace(
data={
"title": variables["title"],
"blocks": [{"type": "paragraph", "text": "自动生成内容"}],
},
status="ok",
)
def _parse_args(argv: list[str] | None) -> argparse.Namespace:
p = argparse.ArgumentParser(description="概要设计书自动生成试运行")
p.add_argument("--requirement", default=str(ROOT / "sample" / "requirements_enhancement_stock.xlsx"),
help="要件定义 Excel(可多个,逗号分隔)")
p.add_argument("--template", default=str(ROOT / "sample" / "template_design_ja.docx"),
help="概要设计书 Word 模板")
p.add_argument("--rules", nargs="*", default=[
str(ROOT / "sample" / "rules_design_ja.docx"),
str(ROOT / "sample" / "rules_entry_ja.docx"),
], help="写入规则/记入规则 docx(可多个)")
p.add_argument("--existing-system", default=str(ROOT / "sample" / "existing-system"),
help="既有系统源码目录(追加/改修场景)")
p.add_argument("--language", default="java", help="既有系统开发语言(默认 javaNone=自动探测)")
p.add_argument("--output-language", default="auto",
choices=["auto", "zh", "ja"], help="输出语言:auto=与标题一致,zh=简体中文,ja=日文")
p.add_argument("--samples-dir", default=str(ROOT / "sample"), help="样本资产根目录")
p.add_argument("--output", default=str(ROOT / "output" / "output.docx"), help="概要设计书输出路径")
p.add_argument("--impact-report", default=str(ROOT / "output" / "impact-report.json"),
help="影响调查书 JSON 输出路径")
p.add_argument("--fake", action="store_true", help="离线 Fake 引擎(无需 API key")
return p.parse_args(argv)
def main(argv: list[str] | None = None) -> dict:
args = _parse_args(argv if argv is not None else sys.argv[1:])
if args.fake:
engine = FakeEngine()
else:
from genesis.inference.factory import build_inference_engine # noqa: E402
engine = build_inference_engine()
ss = SourceParser().parse(
requirement_paths=[args.requirement],
template_path=args.template,
rule_paths=list(args.rules),
existing_system_path=args.existing_system,
existing_system_language=args.language,
)
out_path = Path(args.output)
out_path.parent.mkdir(parents=True, exist_ok=True)
orch = WriteOrchestrator()
contents = orch.generate(
ss, str(out_path),
samples_dir=args.samples_dir,
engine=engine,
template_path=str(Path(args.template)),
output_language=args.output_language,
)
report = ss.impact_report
if report is None:
raise RuntimeError("影响调查未执行(未提供既有系统或门控未触发)")
report_path = Path(args.impact_report)
report_path.parent.mkdir(parents=True, exist_ok=True)
report_path.write_text(
json.dumps(impact_report_to_dict(report), ensure_ascii=False, indent=2),
encoding="utf-8",
)
summary = dict(report.summary)
print(f"章节数: {len(contents)}")
print(f"影响调查: {json.dumps(summary, ensure_ascii=False)}")
print(f"概要设计书: {out_path}")
print(f"影响调查书: {report_path}")
return {
"chapters": len(contents),
"summary": summary,
"output": str(out_path),
"impact_report": str(report_path),
}
if __name__ == "__main__":
main()