| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131 |
- """
- Step 3 测试:投书目录生成
- 读取 Step2 保存的 step2_info.pkl,再调用 generate_outline_safe 生成目录,
- 并把最终目录保存为 step3_outline.pkl 供 test_step4.py 复用。
- 用法: uv run python scripts/test_step3.py
- """
- import logging
- import os
- import pickle
- import sys
- from _bootstrap import PROJECT_ROOT
- # ---------- 测试数据(环境变量可覆盖) ----------
- TEMPLATE_PATH = os.environ.get(
- "PROPOSA_TEMPLATE_PATH",
- "src/templates/申勤投标模板.docx",
- )
- REFERENCE_BID = os.environ.get(
- "PROPOSA_REFERENCE_BID",
- "test_data/171-上海群众艺术馆/参考投标文件/物业管理费项目投标文件.docx",
- )
- OUTPUT_DIR = os.environ.get(
- "PROPOSA_STEP3_OUTPUT_DIR",
- os.environ.get("PROPOSA_WORK_DIR", "output/171-上海群众艺术馆"),
- )
- STEP2_INFO_FILE = os.environ.get(
- "PROPOSA_STEP2_INFO_FILE",
- os.path.join(OUTPUT_DIR, "step2_info.pkl"),
- )
- STEP3_OUTLINE_FILE = os.environ.get(
- "PROPOSA_STEP3_OUTLINE_FILE",
- os.path.join(OUTPUT_DIR, "step3_outline.pkl"),
- )
- os.environ["BID_OUTLINE_CACHE_DIR"] = os.path.join(OUTPUT_DIR, ".outline_cache")
- os.environ["BID_LLM_CACHE_DIR"] = os.path.join(OUTPUT_DIR, ".llm_cache")
- # ---------- 日志 ----------
- logging.basicConfig(
- level=logging.INFO,
- format="%(asctime)s [%(levelname)s] %(message)s",
- datefmt="%H:%M:%S",
- stream=sys.stderr,
- )
- # ---------- Step 2: 复用已落盘的分析结果 ----------
- print("=" * 60)
- print("Step 2: 复用已落盘的分析结果(Step 3 的前置)")
- print("=" * 60)
- if not os.path.isfile(STEP2_INFO_FILE):
- raise FileNotFoundError(
- f"Step2 分析结果不存在: {STEP2_INFO_FILE}\n"
- "请先运行 uv run python scripts/test_step2.py。"
- )
- with open(STEP2_INFO_FILE, "rb") as file:
- step2_payload = pickle.load(file)
- analysis = step2_payload["analysis"]
- pd = step2_payload["project_data"]
- print(
- f"复用 Step2 分析: {len(analysis.scoring_criteria)} 评分项, "
- f"{len(analysis.rejection_items)} 废标项"
- )
- # ---------- Step 3: 生成目录 ----------
- print()
- print("=" * 60)
- print("Step 3: 生成投书目录")
- print("=" * 60)
- from step3_outlining import generate_outline_safe
- from models import ChapterType
- outline = generate_outline_safe(
- analysis,
- pd,
- template_path=TEMPLATE_PATH,
- reference_bid_path=REFERENCE_BID,
- )
- # generate_outline_safe 已在返回前写出报告并执行硬门禁;失败时不会进入这里。
- os.makedirs(OUTPUT_DIR, exist_ok=True)
- with open(STEP3_OUTLINE_FILE, "wb") as file:
- pickle.dump(outline, file)
- report_md = os.path.join(OUTPUT_DIR, "step3_outline_report.md")
- report_json = os.path.join(OUTPUT_DIR, "step3_outline_report.json")
- print(f"大纲对照报告: {report_md}")
- print(f"机器可读映射: {report_json}")
- print(f"Step3 最终目录: {STEP3_OUTLINE_FILE}")
- # ---------- 打印结果 ----------
- print()
- print("=== 目录结构 ===")
- print(f"项目: {outline.project_name}")
- print(f"总目标字数: {outline.total_word_count_target:,}")
- print()
- biz_chs = [c for c in outline.chapters if c.chapter_type == ChapterType.BUSINESS]
- tech_chs = [c for c in outline.chapters if c.chapter_type == ChapterType.TECHNICAL]
- appendix_chs = [c for c in outline.chapters if c.chapter_type == ChapterType.APPENDIX]
- if biz_chs:
- print("【商务部分】")
- for ch in biz_chs:
- children_info = f" ({len(ch.children)} 节)" if ch.children else ""
- print(f" 第{ch.id}章 {ch.title} — 目标 {ch.word_count_target:,} 字{children_info}")
- for child in ch.children:
- print(f" {child.id} {child.title} — {child.word_count_target:,} 字")
- if tech_chs:
- print()
- print(f"【技术部分】")
- for ch in tech_chs:
- children_info = f" ({len(ch.children)} 节)" if ch.children else ""
- print(f" 第{ch.id}章 {ch.title} — 目标 {ch.word_count_target:,} 字{children_info}")
- for child in ch.children:
- print(f" {child.id} {child.title} — {child.word_count_target:,} 字")
- if appendix_chs:
- print()
- print("【附件】")
- for ch in appendix_chs:
- print(f" {ch.id} {ch.title}")
- total = sum(ch.word_count_target for ch in outline.chapters)
- print(f"\n章节总字数目标: {total:,} (配置最低: 170,000)")
- print()
- print("Step 3 测试完成 [OK]")
|