from __future__ import annotations import hashlib import importlib.util import json import sys from pathlib import Path ROOT = Path(__file__).resolve().parents[2] sys.path.insert(0, str(ROOT / "dev" / "ana-dev")) sys.path.insert(0, str(ROOT / "dev" / "project-dev")) GENERATOR = ROOT / "ai-valuation-analyst" / "tools" / "generate_image_targets_batch_20260805.py" SPEC = importlib.util.spec_from_file_location("image_targets_generator_for_repair", GENERATOR) if SPEC is None or SPEC.loader is None: raise RuntimeError(f"cannot load {GENERATOR}") module = importlib.util.module_from_spec(SPEC) sys.modules[SPEC.name] = module SPEC.loader.exec_module(module) RESULT_ROOT = ROOT / "ana-data" / "result" / "股票估值" BATCH_JSON = RESULT_ROOT / "20260805_batch_six_images_valuation" / "batch_results.json" def write_json(path: Path, value) -> None: path.write_text(json.dumps(value, ensure_ascii=False, indent=2) + "\n", encoding="utf-8") def sha256(path: Path) -> str: return hashlib.sha256(path.read_bytes()).hexdigest() def main() -> None: batch = json.loads(BATCH_JSON.read_text(encoding="utf-8")) repaired = 0 for row in batch["rows"]: out_dir = RESULT_ROOT / Path(row["formal_path"]).parent snapshot_path = next(out_dir.glob("*估值快照_20260804.json")) snapshot = json.loads(snapshot_path.read_text(encoding="utf-8")) old_cap = snapshot["market"].get("platform_market_cap") snapshot["market"]["platform_market_cap"] = None snapshot.setdefault("analysis", {})["platform_market_cap_excluded"] = old_cap snapshot["analysis"]["platform_market_cap_exclusion_reason"] = ( "行情接口平台市值是取数时点实时值,与2026-08-04历史收盘价不在同一时点;正式市值只按历史收盘价×同口径股本复算。" ) write_json(snapshot_path, snapshot) calc_dir = out_dir / "calculation" module.base.run_pipeline(snapshot_path, calc_dir, module.REGISTRY) results_path = calc_dir / "valuation_results.json" results = json.loads(results_path.read_text(encoding="utf-8")) report = (calc_dir / "valuation_report.md").read_text(encoding="utf-8") report = report.replace("价格合理性评估(流水线生成底稿)", "价格合理性评估", 1).replace( "本文是研究计算底稿,不构成交易指令或收益承诺。", "本文为按《股票价格合理性评估操作手册》形成的条件化研究结论,不构成交易指令或收益承诺。", 1, ) formal_path = RESULT_ROOT / row["formal_path"] formal_path.write_text(report, encoding="utf-8") row["qa"] = results["qa"]["status"] row["qa_errors"] = results["qa"]["error_count"] row["qa_warnings"] = results["qa"]["warning_count"] row["market_cap"] = float(results["metrics"]["market_cap"]) evidence_path = out_dir / "source_evidence_manifest.json" evidence = json.loads(evidence_path.read_text(encoding="utf-8")) note = ( "行情平台市值与历史收盘价不在同一时点,已从V1平台市值交叉校验输入中剔除;" "原始行情哈希和平台值保留,正式市值仅按股价×股本复算。" ) gaps = evidence.setdefault("bounded_gaps", []) if note not in gaps: gaps.append(note) evidence["market_cap_timing_repair"] = { "excluded_platform_market_cap": old_cap, "formal_recomputed_market_cap": float(results["metrics"]["market_cap"]), "snapshot_sha256": sha256(snapshot_path), "calculation_sha256": sha256(results_path), "formal_report_sha256": sha256(formal_path), } write_json(evidence_path, evidence) repaired += 1 write_json(BATCH_JSON, batch) print(json.dumps({ "repaired": repaired, "qa_errors": sum(row["qa_errors"] for row in batch["rows"]), "qa_warnings": sum(row["qa_warnings"] for row in batch["rows"]), }, ensure_ascii=False), flush=True) if __name__ == "__main__": main()