arabic-audio-reader-worker / scripts /deployment_status.py
Syncre's picture
Deploy Arabic Audio Reader worker
088795a verified
from __future__ import annotations
import argparse
import json
import sys
from dataclasses import asdict, dataclass
from pathlib import Path
from typing import Any
ROOT_DIR = Path(__file__).resolve().parent.parent
if str(ROOT_DIR) not in sys.path:
sys.path.insert(0, str(ROOT_DIR))
from scripts.next_deployment_step import (
LIVE_PROOF,
LOCAL_REPORT,
SITE_REPORT,
WORKER_REPORT,
choose_next_step,
deployment_urls_look_real,
load_json,
local_ready,
)
@dataclass
class ReportStatus:
path: str
exists: bool
valid_json: bool
summary: str
@dataclass
class DeploymentStatus:
ready_for_live_urls: bool
live_urls_look_real: bool
live_complete: bool
reports_are_real_live_evidence: bool
local_report: ReportStatus
site_report: ReportStatus
worker_report: ReportStatus
live_proof: ReportStatus
missing_site_checks: list[str]
missing_worker_checks: list[str]
next_status: str
next_title: str
next_detail: str
next_command: str
def _report_status(path: Path) -> ReportStatus:
payload = load_json(path)
if payload is None:
return ReportStatus(str(path), path.exists(), False, "missing or invalid JSON")
return ReportStatus(str(path), True, True, summarize_payload(path, payload))
def _list_checks_ok(payload: Any, names: set[str]) -> bool:
if not isinstance(payload, list):
return False
checks = {str(item.get("name", "")): bool(item.get("ok")) for item in payload if isinstance(item, dict)}
return all(checks.get(name) is True for name in names)
def _missing_checks(payload: Any, names: set[str]) -> list[str]:
if not isinstance(payload, list):
return sorted(names)
checks = {str(item.get("name", "")): bool(item.get("ok")) for item in payload if isinstance(item, dict)}
return sorted(name for name in names if checks.get(name) is not True)
def _looks_like_test_artifact(payload: Any) -> bool:
if not isinstance(payload, dict):
return False
text = json.dumps(payload, ensure_ascii=False).lower()
return "pytest-" in text or "your-space.hf.space" in text or "your-vercel-app.vercel.app" in text
def _url_evidence_matches(live_payload: Any, worker_url: str | None, vercel_origin: str | None) -> bool:
if not isinstance(live_payload, dict):
return False
proof_worker = str(live_payload.get("workerUrl") or "").rstrip("/")
proof_origin = str(live_payload.get("origin") or "").rstrip("/")
expected_worker = (worker_url or proof_worker).rstrip("/")
expected_origin = (vercel_origin or proof_origin).rstrip("/")
if not deployment_urls_look_real(expected_worker, expected_origin):
return False
return proof_worker == expected_worker and proof_origin == expected_origin
def summarize_payload(path: Path, payload: Any) -> str:
if isinstance(payload, dict):
if "ready" in payload or "complete" in payload:
return f"ready={payload.get('ready')} complete={payload.get('complete')}"
if "counts" in payload:
return f"counts={payload.get('counts')}"
return f"object keys={','.join(sorted(str(key) for key in payload.keys())[:6])}"
if isinstance(payload, list):
passed = sum(1 for item in payload if isinstance(item, dict) and item.get("ok") is True)
failed = sum(1 for item in payload if isinstance(item, dict) and item.get("ok") is False)
return f"checks={len(payload)} pass={passed} fail={failed}"
return type(payload).__name__
def build_status(
worker_url: str | None = None,
vercel_origin: str | None = None,
code: str = "1234",
local_report: Path = LOCAL_REPORT,
site_report: Path = SITE_REPORT,
worker_report: Path = WORKER_REPORT,
live_proof: Path = LIVE_PROOF,
) -> DeploymentStatus:
site_required = {
"site login",
"site platform vercel",
"site worker configured",
"site large PDF ready",
"site production worker ready",
"site hosted limits documented",
"site recommended stack documented",
"site direct cloud fallback disabled",
"site worker diagnostics endpoint",
"site worker reachable from vercel",
"site worker CORS ready",
}
worker_required = {
"recommended stack documented",
"smoke upload accepted",
"smoke job complete",
"smoke usable text",
"smoke audio url",
"smoke download url",
"smoke audio bytes",
"smoke audio file signature",
"smoke download bytes",
"smoke download file signature",
"scanned smoke upload accepted",
"scanned smoke job complete",
"scanned smoke usable text",
"scanned smoke OCR extraction",
"scanned smoke audio url",
"scanned smoke download url",
"scanned smoke audio bytes",
"scanned smoke audio file signature",
"scanned smoke download bytes",
"scanned smoke download file signature",
}
live_payload = load_json(live_proof)
site_payload = load_json(site_report)
worker_payload = load_json(worker_report)
missing_site_checks = _missing_checks(site_payload, site_required)
missing_worker_checks = _missing_checks(worker_payload, worker_required)
live_complete = isinstance(live_payload, dict) and bool(live_payload.get("complete"))
live_urls_look_real = deployment_urls_look_real(worker_url, vercel_origin)
reports_are_real_live_evidence = bool(
live_complete
and not missing_site_checks
and not missing_worker_checks
and not _looks_like_test_artifact(live_payload)
and _url_evidence_matches(live_payload, worker_url, vercel_origin)
)
next_step = choose_next_step(
worker_url=worker_url,
vercel_origin=vercel_origin,
code=code,
local_report=local_report,
site_report=site_report,
worker_report=worker_report,
live_proof=live_proof,
)
if live_complete and not reports_are_real_live_evidence:
next_status = "live-proof"
next_title = "Re-run live proof against real deployed URLs"
next_detail = (
"A complete live proof file exists, but it does not look like trustworthy live evidence. "
"Re-run the proof after replacing placeholder/test URLs with the real Hugging Face worker and Vercel site."
)
next_command = (
f"python scripts\\prove_live_deployment.py {worker_url or 'https://your-space.hf.space'} "
f"--origin {vercel_origin or 'https://your-vercel-app.vercel.app'} --code {code} "
"--smoke-ocr-engine arabic "
"--check-hf-metadata --hf-metadata-report outputs\\hf-model-metadata.md "
"--proof-out outputs\\live-deployment-proof.json"
)
else:
next_status = next_step.status
next_title = next_step.title
next_detail = next_step.detail
next_command = next_step.command
return DeploymentStatus(
ready_for_live_urls=local_ready(local_report) and live_urls_look_real,
live_urls_look_real=live_urls_look_real,
live_complete=live_complete,
reports_are_real_live_evidence=reports_are_real_live_evidence,
local_report=_report_status(local_report),
site_report=_report_status(site_report),
worker_report=_report_status(worker_report),
live_proof=_report_status(live_proof),
missing_site_checks=missing_site_checks,
missing_worker_checks=missing_worker_checks,
next_status=next_status,
next_title=next_title,
next_detail=next_detail,
next_command=next_command,
)
def print_status(status: DeploymentStatus) -> None:
print(f"Ready for live URLs: {status.ready_for_live_urls}")
print(f"Live URLs look real: {status.live_urls_look_real}")
print(f"Live proof complete: {status.live_complete}")
print(f"Reports are real live evidence: {status.reports_are_real_live_evidence}")
print()
for label, report in [
("Local", status.local_report),
("Site", status.site_report),
("Worker", status.worker_report),
("Live proof", status.live_proof),
]:
print(f"{label}: {report.summary} ({report.path})")
if status.missing_site_checks:
print()
print("Missing site proof checks:")
for name in status.missing_site_checks:
print(f"- {name}")
if status.missing_worker_checks:
print()
print("Missing worker proof checks:")
for name in status.missing_worker_checks:
print(f"- {name}")
print()
print(status.next_title)
print(status.next_detail)
print()
print(status.next_command)
def main() -> None:
parser = argparse.ArgumentParser(description="Show the current deployment proof status and next command.")
parser.add_argument("--worker-url", help="Live worker URL, for example https://your-space.hf.space")
parser.add_argument("--origin", help="Live Vercel origin, for example https://your-app.vercel.app")
parser.add_argument("--code", default="1234", help="Access code for live verification.")
parser.add_argument("--json", action="store_true", help="Print JSON.")
args = parser.parse_args()
status = build_status(worker_url=args.worker_url, vercel_origin=args.origin, code=args.code)
if args.json:
print(json.dumps(asdict(status), ensure_ascii=False, indent=2))
else:
print_status(status)
if __name__ == "__main__":
main()