run_existing_execution_local.py 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. """Local JSON entrypoint for an existing PG Pattern V2 execution.
  2. This entrypoint intentionally requires an existing PG pattern_mining_execution.id.
  3. It redirects result/.trace/output into one local run directory and never calls
  4. prepare/run_mining.
  5. """
  6. import argparse
  7. import asyncio
  8. import json
  9. import os
  10. import sys
  11. from datetime import datetime
  12. from pathlib import Path
  13. from zoneinfo import ZoneInfo
  14. sys.path.insert(0, str(Path(__file__).parent.parent.parent))
  15. def _load_project_env() -> None:
  16. try:
  17. from dotenv import load_dotenv
  18. except ImportError:
  19. return
  20. load_dotenv(Path(__file__).parent.parent.parent / ".env")
  21. def _default_output_root(execution_id: int) -> Path:
  22. ts = datetime.now(ZoneInfo("Asia/Shanghai")).strftime("%Y%m%d_%H%M%S")
  23. return Path(__file__).parent / "test_output_data" / f"execution_{execution_id}_{ts}"
  24. def _test_output_base_dir() -> Path:
  25. return Path(__file__).parent / "test_output_data"
  26. def _resolve_output_root(execution_id: int, run_id: str | None, output_root: Path | None) -> Path:
  27. base_dir = _test_output_base_dir().resolve()
  28. if run_id:
  29. return base_dir / run_id
  30. if output_root is None:
  31. return _default_output_root(execution_id)
  32. resolved = output_root.expanduser().resolve()
  33. if resolved != base_dir and base_dir not in resolved.parents:
  34. raise ValueError(
  35. f"local MVP 输出必须位于 {base_dir} 下;请改用 --run-id 或传入该目录下的 --output-root"
  36. )
  37. return resolved
  38. def _configure_local_env(execution_id: int, output_root: Path) -> None:
  39. os.environ["DEMAND_OUTPUT_MODE"] = "local_json"
  40. os.environ["DEMAND_LOCAL_ENTRYPOINT"] = "run_existing_execution_local"
  41. os.environ["DEMAND_LOCAL_OUTPUT_ROOT"] = str(output_root)
  42. os.environ["DEMAND_RESULT_BASE_DIR"] = str(output_root / "intermediate" / "result")
  43. os.environ["DEMAND_WEIGHT_DATA_DIR"] = str(output_root / "intermediate" / "data")
  44. os.environ["DEMAND_TRACE_STORE_PATH"] = str(output_root / ".trace")
  45. os.environ["DEMAND_OUTPUT_BASE_DIR"] = str(output_root / "output")
  46. os.environ.setdefault("DEMAND_LOCAL_TASK_ID", "1")
  47. def _validate_execution_success(execution_id: int) -> None:
  48. from examples.demand.db_manager import query_execution_for_evidence
  49. execution = query_execution_for_evidence(execution_id)
  50. if not execution:
  51. raise ValueError(f"execution_id={execution_id} 不存在,local MVP 只允许跑已有 execution")
  52. if str(execution.get("status") or "").strip().lower() != "success":
  53. raise ValueError(
  54. f"execution_id={execution_id} status={execution.get('status')},不是 success,拒绝生成本地输出"
  55. )
  56. def parse_args() -> argparse.Namespace:
  57. parser = argparse.ArgumentParser(
  58. description="Run DemandAgent against an existing PG Pattern V2 execution_id and write local JSON outputs."
  59. )
  60. parser.add_argument("--execution-id", type=int, required=True, help="Existing PG pattern_mining_execution.id")
  61. parser.add_argument("--merge-level2", required=True, help="Current merge_leve2 / cluster name")
  62. parser.add_argument("--platform-type", default="piaoquan", help="Platform label for manifest only")
  63. parser.add_argument("--count", type=int, default=5, help="Approximate demand count requested from the prompt")
  64. parser.add_argument("--run-id", default=None, help="Run directory name under examples/demand/test_output_data")
  65. parser.add_argument(
  66. "--output-root",
  67. type=Path,
  68. default=None,
  69. help="Optional full run directory; must be under examples/demand/test_output_data",
  70. )
  71. return parser.parse_args()
  72. async def async_main() -> dict:
  73. _load_project_env()
  74. args = parse_args()
  75. output_root = _resolve_output_root(args.execution_id, args.run_id, args.output_root)
  76. _configure_local_env(args.execution_id, output_root)
  77. _validate_execution_success(args.execution_id)
  78. from examples.demand.run import main
  79. return await main(
  80. cluster_name=args.merge_level2,
  81. platform_type=args.platform_type,
  82. count=args.count,
  83. execution_id=args.execution_id,
  84. task_id=int(os.environ.get("DEMAND_LOCAL_TASK_ID", "1")),
  85. )
  86. def main() -> None:
  87. result = asyncio.run(async_main())
  88. print(json.dumps(result, ensure_ascii=False, indent=2))
  89. if __name__ == "__main__":
  90. main()