Spaces:
Sleeping
Sleeping
| #!/usr/bin/env python3 | |
| """Pre-flight checks before a full-report demo (local or Hugging Face Space). | |
| Usage: | |
| python scripts/preflight_hf.py | |
| python scripts/preflight_hf.py --base https://StormShadow308-RICS.hf.space --tenant my-tenant | |
| """ | |
| from __future__ import annotations | |
| import argparse | |
| import json | |
| import sys | |
| import urllib.error | |
| import urllib.request | |
| def _get(url: str, tenant: str, timeout: float = 30.0) -> dict: | |
| req = urllib.request.Request( | |
| url, | |
| headers={"X-Tenant-ID": tenant, "Accept": "application/json"}, | |
| ) | |
| with urllib.request.urlopen(req, timeout=timeout) as resp: | |
| return json.loads(resp.read().decode()) | |
| def main() -> int: | |
| parser = argparse.ArgumentParser(description="RICS Report Genius HF/local pre-flight") | |
| parser.add_argument( | |
| "--base", | |
| default="http://localhost:8000", | |
| help="API base URL (no trailing slash)", | |
| ) | |
| parser.add_argument("--tenant", default="preflight-check", help="X-Tenant-ID header") | |
| args = parser.parse_args() | |
| base = args.base.rstrip("/") | |
| tenant = args.tenant | |
| failed = 0 | |
| def ok(msg: str) -> None: | |
| print(f" OK {msg}") | |
| def warn(msg: str) -> None: | |
| print(f" WARN {msg}") | |
| def fail(msg: str) -> None: | |
| nonlocal failed | |
| failed += 1 | |
| print(f" FAIL {msg}") | |
| print(f"\nPre-flight: {base} tenant={tenant}\n") | |
| try: | |
| health = _get(f"{base}/health", tenant) | |
| except urllib.error.HTTPError as exc: | |
| fail(f"/health returned {exc.code}") | |
| return 1 | |
| except Exception as exc: # noqa: BLE001 | |
| fail(f"Cannot reach API: {exc}") | |
| return 1 | |
| if health.get("status") not in ("ok", "degraded"): | |
| warn(f"health status={health.get('status')!r}") | |
| if not health.get("components", {}).get("openai", health.get("openai_api_key_configured")): | |
| key_ok = bool( | |
| (health.get("ai_features") or {}).get("openai_api_key_configured") | |
| ) | |
| if not key_ok: | |
| fail("OPENAI_API_KEY not configured on server") | |
| phases = health.get("ai_phases") or (health.get("ai_features") or {}).get("ai_phases") or {} | |
| p3 = phases.get("phase3") or {} | |
| caps = p3.get("capabilities") or {} | |
| if caps.get("parallel_multi_section"): | |
| ok("Parallel multi-section generation enabled (10m SLA path)") | |
| else: | |
| fail( | |
| "parallel_multi_section is false — full reports may exceed 10 minutes; " | |
| "redeploy with SPACE_ID / PRODUCTION_AI_PROFILE or ENABLE_ASYNC_PIPELINE=true" | |
| ) | |
| sla = p3.get("generation_sla_seconds") or 600 | |
| ok(f"Generation SLA target: {sla}s ({sla // 60} min)") | |
| for w in health.get("ai_phase_warnings") or health.get("ai_warnings") or []: | |
| warn(w) | |
| try: | |
| summary = _get(f"{base}/documents/tenant-chunk-summary", tenant) | |
| n = int(summary.get("indexed_chunk_count") or 0) | |
| if n > 0: | |
| ok(f"Tenant RAG index: {n} chunks") | |
| else: | |
| warn( | |
| "indexed_chunk_count=0 — upload and wait for ingest before expecting personalised RAG" | |
| ) | |
| except Exception as exc: # noqa: BLE001 | |
| warn(f"tenant-chunk-summary: {exc}") | |
| print() | |
| if failed: | |
| print(f"Pre-flight FAILED ({failed} blocking issue(s)).\n") | |
| return 1 | |
| print("Pre-flight passed — safe to run batch full-report generate.\n") | |
| return 0 | |
| if __name__ == "__main__": | |
| sys.exit(main()) | |