207 lines
8.3 KiB
Python
207 lines
8.3 KiB
Python
#!/usr/bin/env python3
|
|
"""Collect bounded, secret-free VedAstro HTTP raw for divisional parity."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import hashlib
|
|
import json
|
|
import os
|
|
from pathlib import Path
|
|
from typing import Any
|
|
|
|
try:
|
|
from scripts import vedastro_service_adapter as adapter
|
|
except ModuleNotFoundError: # pragma: no cover - direct script execution
|
|
import vedastro_service_adapter as adapter
|
|
|
|
|
|
ROOT = Path(__file__).resolve().parents[1]
|
|
DEFAULT_PLANETS = ["Sun", "Moon", "Mars", "Mercury", "Jupiter", "Venus", "Saturn"]
|
|
VARGA_FIELDS = {
|
|
"D2": "PlanetHoraD2Signs",
|
|
"D4": "PlanetChaturthamshaD4Sign",
|
|
"D9": "PlanetNavamshaD9Sign",
|
|
"D10": "PlanetDashamamshaD10Sign",
|
|
}
|
|
SHADBALA_COMPONENT_FIELDS = [
|
|
"PlanetSthanaBala",
|
|
"PlanetDigBala",
|
|
"PlanetKalaBala",
|
|
"PlanetChestaBala",
|
|
"PlanetNaisargikaBala",
|
|
"PlanetDrikBala",
|
|
]
|
|
|
|
|
|
def _hash(payload: Any) -> str:
|
|
raw = json.dumps(payload, ensure_ascii=False, sort_keys=True, separators=(",", ":")).encode("utf-8")
|
|
return hashlib.sha256(raw).hexdigest()
|
|
|
|
|
|
def collect_chart_core(
|
|
case: dict[str, Any],
|
|
*,
|
|
case_id: str,
|
|
planets: list[str],
|
|
output_path: Path,
|
|
) -> dict[str, Any]:
|
|
endpoint = os.environ.get("VEDASTRO_API_ENDPOINT", "").strip()
|
|
if not endpoint:
|
|
raise RuntimeError("VEDASTRO_API_ENDPOINT is not configured")
|
|
|
|
manifest = adapter._official_full_snapshot_manifest(case, case_id)
|
|
chart_request = next(item for item in manifest["requests"] if item["section"] == "chart_core")
|
|
raw_responses: dict[str, Any] = {}
|
|
statuses: dict[str, str] = {}
|
|
scalar_responses: dict[str, Any] = {}
|
|
scalar_statuses: dict[str, str] = {}
|
|
component_responses: dict[str, Any] = {}
|
|
component_statuses: dict[str, str] = {}
|
|
retry_error_codes: list[int] = []
|
|
attempt_count = 0
|
|
|
|
for planet in planets:
|
|
request_item = {**chart_request, "fanout_value": planet}
|
|
try:
|
|
payload, attempts, retries = adapter._post_official_snapshot_section(endpoint, request_item)
|
|
raw_responses[planet] = payload
|
|
statuses[planet] = adapter._payload_status(payload)
|
|
attempt_count += attempts
|
|
retry_error_codes.extend(retries)
|
|
except Exception as exc: # Preserve partial raw instead of discarding the batch.
|
|
statuses[planet] = f"{type(exc).__name__}:{str(exc)[:200]}"
|
|
|
|
common_body = adapter._official_common_body(case)
|
|
scalar_requests = {
|
|
"shadbala": {
|
|
"section": "shadbala",
|
|
"endpoint_path": "/Calculate/AllPlanetStrength",
|
|
"method": "POST",
|
|
"headers": {"Content-Type": "application/json"},
|
|
"body": common_body,
|
|
"calculator_name": "AllPlanetStrength",
|
|
},
|
|
"ashtakavarga_sav": {
|
|
"section": "ashtakavarga_sav",
|
|
"endpoint_path": "/Calculate/AshtakvargaLifeMap",
|
|
"method": "POST",
|
|
"headers": {"Content-Type": "application/json"},
|
|
"body": {"birthTime": common_body["time"], "Ayanamsa": common_body["Ayanamsa"]},
|
|
"calculator_name": "AshtakvargaLifeMap",
|
|
},
|
|
"ashtakavarga_bav": {
|
|
"section": "ashtakavarga_bav",
|
|
"endpoint_path": "/Calculate/BhinnashtakavargaChart",
|
|
"method": "POST",
|
|
"headers": {"Content-Type": "application/json"},
|
|
"body": {"birthTime": common_body["time"], "Ayanamsa": common_body["Ayanamsa"]},
|
|
"calculator_name": "BhinnashtakavargaChart",
|
|
},
|
|
"ashtakavarga_sav_chart": {
|
|
"section": "ashtakavarga_sav_chart",
|
|
"endpoint_path": "/Calculate/SarvashtakavargaChart",
|
|
"method": "POST",
|
|
"headers": {"Content-Type": "application/json"},
|
|
"body": {"birthTime": common_body["time"], "Ayanamsa": common_body["Ayanamsa"]},
|
|
"calculator_name": "SarvashtakavargaChart",
|
|
},
|
|
}
|
|
for section, request_item in scalar_requests.items():
|
|
try:
|
|
payload, attempts, retries = adapter._post_official_snapshot_section(endpoint, request_item)
|
|
scalar_responses[section] = payload
|
|
scalar_statuses[section] = adapter._payload_status(payload)
|
|
attempt_count += attempts
|
|
retry_error_codes.extend(retries)
|
|
except Exception as exc:
|
|
scalar_statuses[section] = f"{type(exc).__name__}:{str(exc)[:200]}"
|
|
|
|
for planet in planets:
|
|
key = f"{planet}.chesta"
|
|
request_item = {
|
|
"section": "shadbala_chesta",
|
|
"endpoint_path": "/Calculate/PlanetChestaBala",
|
|
"method": "POST",
|
|
"headers": {"Content-Type": "application/json"},
|
|
"body": {
|
|
"planetName": {"Name": planet},
|
|
"time": common_body["time"],
|
|
"useSpecialSunMoon": False,
|
|
"Ayanamsa": common_body["Ayanamsa"],
|
|
},
|
|
"calculator_name": "PlanetChestaBala",
|
|
}
|
|
try:
|
|
payload, attempts, retries = adapter._post_official_snapshot_section(endpoint, request_item)
|
|
component_responses[key] = payload
|
|
component_statuses[key] = adapter._payload_status(payload)
|
|
attempt_count += attempts
|
|
retry_error_codes.extend(retries)
|
|
except Exception as exc:
|
|
component_statuses[key] = f"{type(exc).__name__}:{str(exc)[:200]}"
|
|
|
|
settings = {
|
|
"case_id": case_id,
|
|
"birth": {key: case.get(key) for key in ("year", "month", "day", "hour", "minute", "second", "lat", "lon", "tz")},
|
|
"ayanamsa_policy": case.get("ayanamsa_policy") or case.get("ayanamsa") or "lahiri",
|
|
"node_policy": case.get("node_policy") or case.get("node_mode") or "mean",
|
|
"endpoint_host": adapter._endpoint_host(endpoint),
|
|
"calculator": "AllPlanetData",
|
|
"planets": planets,
|
|
}
|
|
packet = {
|
|
"scope": "vedastro_official_http_divisional_parity_raw",
|
|
"status": "ok"
|
|
if statuses and scalar_statuses and component_statuses and all(value == "ok" for value in [*statuses.values(), *scalar_statuses.values(), *component_statuses.values()])
|
|
else "partial",
|
|
"source": "vedastro_official_http",
|
|
"settings": settings,
|
|
"coverage": {
|
|
"sections": [
|
|
*VARGA_FIELDS,
|
|
"shadbala_total",
|
|
"shadbala_components",
|
|
"ashtakavarga_bav",
|
|
"ashtakavarga_sav",
|
|
],
|
|
"field_map": VARGA_FIELDS,
|
|
"shadbala_component_fields": SHADBALA_COMPONENT_FIELDS,
|
|
"blocked_sections": [],
|
|
},
|
|
"fanout_statuses": dict(sorted(statuses.items())),
|
|
"scalar_statuses": dict(sorted(scalar_statuses.items())),
|
|
"component_statuses": dict(sorted(component_statuses.items())),
|
|
"attempt_count": attempt_count,
|
|
"retry_error_codes": retry_error_codes,
|
|
"raw_responses": raw_responses,
|
|
"scalar_responses": scalar_responses,
|
|
"component_responses": component_responses,
|
|
}
|
|
packet["response_hash"] = _hash({"chart_core": raw_responses, "scalar": scalar_responses, "components": component_responses})
|
|
output_path.parent.mkdir(parents=True, exist_ok=True)
|
|
output_path.write_text(json.dumps(packet, ensure_ascii=False, indent=2, sort_keys=True), encoding="utf-8")
|
|
return packet
|
|
|
|
|
|
def main() -> int:
|
|
parser = argparse.ArgumentParser(description=__doc__)
|
|
parser.add_argument("--case", choices=sorted(adapter.PARITY_CASES), default="beijing_first_use_demo")
|
|
parser.add_argument("--planets", default=",".join(DEFAULT_PLANETS))
|
|
parser.add_argument("--output", type=Path)
|
|
args = parser.parse_args()
|
|
planets = [item.strip() for item in args.planets.split(",") if item.strip()]
|
|
output = args.output or ROOT / "references" / "oracle" / "artifacts" / f"vedastro_{args.case}_divisional_raw.json"
|
|
report = collect_chart_core(
|
|
dict(adapter.PARITY_CASES[args.case]),
|
|
case_id=args.case,
|
|
planets=planets,
|
|
output_path=output,
|
|
)
|
|
print(json.dumps({"status": report["status"], "output": str(output), "response_hash": report["response_hash"], "fanout_statuses": report["fanout_statuses"]}, ensure_ascii=False, indent=2, sort_keys=True))
|
|
return 0 if report["status"] == "ok" else 1
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|