bbqddt2/Antigravity
0
1# -*- coding: utf-8 -*-2"""3Antigravity 统一编排入口4 5用法:6 python orchestrate.py # 运行全部引擎 + 因果验证 + 保存统一输出7 python orchestrate.py --engine luckcast # 只运行 Luckcast8 python orchestrate.py --engine enhanced # 只运行 Enhanced9 python orchestrate.py --causal-only # 只运行因果验证报告10"""11 12import json13import sys14import time15import logging16from pathlib import Path17from datetime import datetime18from typing import List, Dict, Optional19 20# Fix Windows GBK21if sys.stdout.encoding and sys.stdout.encoding.lower() != "utf-8":22 sys.stdout.reconfigure(encoding="utf-8")23 24_PROJECT_ROOT = Path(__file__).resolve().parent25sys.path.insert(0, str(_PROJECT_ROOT))26 27from data_layer import load_history, Draw28 29logger = logging.getLogger("Orchestrator")30logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s")31 32 33# ─── 引擎调用器 ─────────────────────────────────────────────34 35def run_luckcast(draws: List[Draw], top_k: int = 5) -> Optional[List[Dict]]:36 """运行 Luckcast V15 预测引擎"""37 try:38 from luckcast_antigravity_v1 import rank_candidates39 results = rank_candidates(draws, n_candidates=1000, top_k=top_k)40 return [41 {42 "engine": "Luckcast V15",43 "reds": list(r[0]),44 "blue": int(r[1]),45 "scores": {k: float(v) for k, v in r[2].items()},46 }47 for r in results48 ]49 except Exception as e:50 logger.error(f"Luckcast V15 失败: {e}")51 return None52 53 54def run_enhanced(draws: List[Draw], top_k: int = 5) -> Optional[List[Dict]]:55 """运行 Enhanced Predictor V2.0"""56 try:57 # 临时加载 DataFrame58 import pandas as pd59 csv_file = _PROJECT_ROOT / "data" / "lottery_history.csv"60 df = pd.read_csv(csv_file)61 62 from enhanced_predictor import WeightedEnsemble, parse_reds63 ensemble = WeightedEnsemble(df)64 preds = ensemble.generate(num_groups=top_k)65 return [66 {67 "engine": "Enhanced V2.0",68 "strategy": p.get("strategy", ""),69 "reds": list(p["reds"]),70 "blue": int(p["blue"]),71 "scores": {72 "causal_valid": p.get("causal_valid", True),73 "causal_multiplier": p.get("causal_multiplier", 1.0),74 },75 }76 for p in preds77 ]78 except Exception as e:79 logger.error(f"Enhanced Predictor 失败: {e}")80 return None81 82 83def run_evolution_life(draws: List[Draw], top_k: int = 1) -> Optional[List[Dict]]:84 """运行 Evolution Life (RF+Spectral)"""85 try:86 import importlib.util87 spec = importlib.util.spec_from_file_location("evolution_life", _PROJECT_ROOT / "evolution_life.py")88 mod = importlib.util.module_from_spec(spec)89 spec.loader.exec_module(mod)90 result = mod.run_prediction()91 if result and "predictions" in result:92 return result["predictions"]93 return [{"engine": "Evolution Life", "reds": [], "blue": 0, "scores": {}}]94 except Exception as e:95 logger.error(f"Evolution Life 失败: {e}")96 return None97 98 99# ─── 因果验证器 ─────────────────────────────────────────────100 101def causal_verify_all(predictions: List[Dict]) -> List[Dict]:102 """对一组预测做完整的因果验证报告"""103 try:104 from core.causal_reasoning import CausalAnalyzer105 analyzer = CausalAnalyzer()106 except ImportError:107 return predictions108 109 verified = []110 for p in predictions:111 reds = p.get("reds", [])112 blue = p.get("blue", 0)113 reds_str = ", ".join(str(r) for r in reds)114 result = analyzer.evaluate_causality(reds_str, str(blue))115 116 p["causal_status"] = result.get("status", "unknown")117 p["causal_multiplier"] = result.get("confidence_multiplier", 1.0)118 p["causal_warnings"] = result.get("warnings", [])119 p["causal_metrics"] = result.get("metrics", {})120 verified.append(p)121 122 return verified123 124 125# ─── 融合引擎 ───────────────────────────────────────────────126 127def fuse_predictions(all_results: Dict[str, List[Dict]]) -> List[Dict]:128 """129 多引擎结果融合。130 策略: 对所有引擎预测的号码做跨引擎共振计数 + 因果加权。131 """132 from collections import Counter133 134 # 收集所有预测135 all_preds = []136 for engine_name, preds in all_results.items():137 if preds:138 for p in preds:139 p["_engine"] = engine_name140 all_preds.append(p)141 142 if not all_preds:143 return []144 145 # 按红球组合分组(忽略蓝球)146 combo_counter: Counter = Counter()147 combo_map: Dict[tuple, List[Dict]] = {}148 for p in all_preds:149 key = tuple(p["reds"])150 combo_counter[key] += 1151 if key not in combo_map:152 combo_map[key] = []153 combo_map[key].append(p)154 155 # 跨引擎共振的组合得分更高156 fused = []157 for combo, count in combo_counter.most_common(20):158 if count < 2:159 continue # 只保留至少2个引擎都推荐的组合160 candidates = combo_map[combo]161 # 取蓝球得票最多的162 blue_counter = Counter()163 best_score = 0164 for c in candidates:165 b = c.get("blue", 0)166 s = c.get("scores", {})167 total = s.get("total_score", s.get("causal_multiplier", 0))168 blue_counter[b] += total169 best_score += total170 171 best_blue = blue_counter.most_common(1)[0][0] if blue_counter else 0172 173 fused.append({174 "engine": f"Fusion({count} engines)",175 "reds": list(combo),176 "blue": int(best_blue),177 "cross_engine_support": count,178 "fused_score": round(best_score, 4),179 "contributing_engines": [c.get("_engine", "") for c in candidates],180 })181 182 return fused183 184 185# ─── 主流程 ─────────────────────────────────────────────────186 187def run_full_pipeline(top_k: int = 5) -> Dict:188 """完整流水线: 数据加载 → 多引擎预测 → 因果验证 → 融合 → 保存"""189 start = time.time()190 logger.info("=" * 60)191 logger.info(" Antigravity 统一编排系统 V1.0")192 logger.info("=" * 60)193 194 # 1. 加载数据195 draws = load_history()196 latest = draws[-1]197 target = latest.period + 1198 logger.info(f"数据: {len(draws)} 期 | 最新: #{latest.period} | 目标: #{target}")199 200 # 2. 运行引擎201 all_results: Dict[str, List[Dict]] = {}202 203 engines = {204 "Luckcast V15": run_luckcast,205 "Enhanced V2.0": run_enhanced,206 }207 208 for name, runner in engines.items():209 logger.info(f"🚀 启动 {name}...")210 t0 = time.time()211 results = runner(draws, top_k=top_k)212 elapsed = time.time() - t0213 if results:214 all_results[name] = results215 logger.info(f"✅ {name}: {len(results)} 组预测 ({elapsed:.1f}s)")216 else:217 logger.warning(f"❌ {name}: 失败")218 219 # 3. 因果验证220 logger.info("\n🔬 因果验证...")221 verified_results = {}222 for name, preds in all_results.items():223 verified_results[name] = causal_verify_all(preds)224 225 # 4. 融合226 logger.info("\n🔗 多引擎融合...")227 fused = fuse_predictions(verified_results)228 if fused:229 logger.info(f"✅ 融合结果: {len(fused)} 组跨引擎共振号码")230 else:231 logger.info("⚠️ 无跨引擎共振组合")232 233 # 5. 保存统一输出234 output = {235 "target_period": target,236 "timestamp": datetime.now().isoformat(),237 "data_periods": len(draws),238 "latest_period": latest.period,239 "latest_actual": {240 "reds": list(latest.reds),241 "blue": latest.blue,242 },243 "engines": {244 name: {245 "status": "ok" if preds else "fail",246 "count": len(preds) if preds else 0,247 "predictions": preds,248 }249 for name, preds in verified_results.items()250 },251 "fusion": fused,252 "elapsed_seconds": round(time.time() - start, 2),253 }254 255 # 保存标准格式256 output_path = _PROJECT_ROOT / "latest_prediction.json"257 with open(output_path, "w", encoding="utf-8") as f:258 json.dump(output, f, ensure_ascii=False, indent=2)259 260 # 同时保存兼容旧格式的 latest_decision.json261 if fused:262 best = fused[0]263 legacy = {264 "period": str(target),265 "red": best["reds"],266 "blue": best["blue"],267 "engine": "Fusion",268 "scores": {"fused_score": best.get("fused_score", 0)},269 }270 elif verified_results:271 # 取第一个引擎的第一组272 first_engine = list(verified_results.keys())[0]273 first_pred = verified_results[first_engine][0]274 legacy = {275 "period": str(target),276 "red": first_pred["reds"],277 "blue": first_pred["blue"],278 "engine": first_engine,279 "scores": first_pred.get("scores", {}),280 }281 else:282 legacy = {"period": str(target), "red": [], "blue": 0, "engine": "none"}283 284 legacy_path = _PROJECT_ROOT / "latest_decision.json"285 with open(legacy_path, "w", encoding="utf-8") as f:286 json.dump(legacy, f, ensure_ascii=False, indent=2)287 288 # 6. 打印报告289 logger.info(f"\n{'='*60}")290 logger.info(f" 预测结果 - 第 {target} 期")291 logger.info(f"{'='*60}")292 293 for name, preds in verified_results.items():294 logger.info(f"\n [{name}]")295 for p in preds[:3]: # 只显示前3组296 reds = ", ".join(f"{r:02d}" for r in p.get("reds", []))297 blue = f"{p.get('blue', 0):02d}"298 causal = p.get("causal_status", "?")299 mult = p.get("causal_multiplier", 1.0)300 logger.info(f" 🔴[{reds}] 🔵{blue} | 因果:{causal} (x{mult:.2f})")301 302 if fused:303 logger.info(f"\n [融合结果]")304 for p in fused[:3]:305 reds = ", ".join(f"{r:02d}" for r in p.get("reds", []))306 blue = f"{p.get('blue', 0):02d}"307 support = p.get("cross_engine_support", 0)308 logger.info(f" 🔴[{reds}] 🔵{blue} | 跨引擎支持:{support} 引擎:{p.get('contributing_engines', [])}")309 310 logger.info(f"\n✅ 总耗时: {output['elapsed_seconds']}s")311 logger.info(f"📄 输出: {output_path}")312 313 return output314 315 316# ─── CLI ────────────────────────────────────────────────────317 318if __name__ == "__main__":319 import argparse320 parser = argparse.ArgumentParser(description="Antigravity 统一编排系统")321 parser.add_argument("--engine", choices=["luckcast", "enhanced", "all"], default="all")322 parser.add_argument("--top-k", type=int, default=5, help="每组预测几组号码")323 parser.add_argument("--causal-only", action="store_true", help="只运行因果验证")324 args = parser.parse_args()325 326 draws = load_history()327 328 if args.causal_only:329 logger.info("因果验证器独立运行模式")330 from core.causal_reasoning import CausalAnalyzer331 analyzer = CausalAnalyzer()332 # 测试最近10期333 for d in draws[-10:]:334 reds_str = ", ".join(str(r) for r in d.reds)335 result = analyzer.evaluate_causality(reds_str, str(d.blue))336 logger.info(f"#{d.period}: {d.reds} + {d.blue} → {result['status']} (x{result['confidence_multiplier']:.2f})")337 else:338 run_full_pipeline(top_k=args.top_k)339 