- 新增 inference/factory.build_inference_engine:读 GENESIS_INFERENCE__* / 裸 DEEPSEEK_API_KEY·LLM_BASE_URL 环境变量与 .env,构造 HttpLLMClient + InferenceEngine - orchestrator/qa_loop 的 engine=None 分支改用工厂,真正接通真实 LLM 路径 - 脚本注入校验改为通用(非空段落数 + 残留占位符),适配真实模式 - 补工厂测试(缺密钥/前缀变量/裸变量/默认值/.env 解析),覆盖率 99.04%
80 lines
2.9 KiB
Python
80 lines
2.9 KiB
Python
"""Phase 5 垂直切片运行脚本(CLI)。
|
||
|
||
用法:
|
||
python scripts/run_phase5_slice.py --template <PATH> --output <PATH> [--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)
|
||
non_empty = [p.text for p in loaded.paragraphs if p.text.strip()]
|
||
remaining = sum(1 for p in loaded.paragraphs if "{{" in p.text)
|
||
print(f"[slice] 生成章节数: {len(contents)}")
|
||
print(f"[slice] 输出路径: {args.output}")
|
||
print(f"[slice] 注入校验: {'OK' if non_empty and remaining == 0 else 'CHECK'}")
|
||
print(f"[slice] 非空段落数: {len(non_empty)}; 残留占位符: {remaining}")
|
||
preview = "\n".join(non_empty[:5])
|
||
print(f"[slice] 文本内容预览:\n{preview[:400]}")
|
||
|
||
|
||
if __name__ == "__main__":
|
||
_main()
|