Spaces:
Running
Running
| from fastapi import FastAPI | |
| import os, time, requests | |
| app = FastAPI() | |
| # === CONFIG === | |
| BASE = os.getenv("DB3_BASE_URL", "https://alesamodio-db3-update.hf.space") # receiver base URL | |
| CRON_SECRET = os.getenv("CRON_SECRET", "") # receiver's /run secret (set in receiver Space) | |
| HF_TOKEN = os.getenv("HF_TOKEN", "") # READ token if receiver is PRIVATE (set in this trigger Space) | |
| # Timings (tune if needed; can also override via query params) | |
| DEFAULT_WARMUP_WAIT_S = int(os.getenv("WARMUP_WAIT_S", "180")) # quiet wait after first wake | |
| READY_INTERVAL_S = int(os.getenv("READY_INTERVAL_S", "20")) # poll cadence | |
| READY_MAX_ATTEMPTS = int(os.getenv("READY_MAX_ATTEMPTS", "15")) # ~5 min total | |
| def _headers(): | |
| return {"Authorization": f"Bearer {HF_TOKEN}"} if HF_TOKEN else {} | |
| def home(): | |
| return {"status": "running", "message": "HF trigger alive"} | |
| def run(): | |
| """ | |
| Wake receiver once -> quiet wait -> poll /ready -> fire /run?secret=... | |
| Optional query overrides: | |
| warmup_wait (int seconds), max_attempts, interval | |
| """ | |
| log = [] | |
| warmup_wait = int(os.getenv("WARMUP_WAIT_S", str(DEFAULT_WARMUP_WAIT_S))) | |
| # allow query overrides without importing FastAPI Request | |
| try: | |
| import starlette.requests | |
| # no-op; just to avoid extra dependency notes | |
| except Exception: | |
| pass | |
| # simple query parsing without typing Request | |
| from fastapi import Request | |
| def get_query(): | |
| # tiny helper because we didn't annotate Request in signature | |
| import inspect | |
| frame = inspect.currentframe().f_back | |
| req = frame.f_locals.get('request') # not available in this simple handler | |
| return {} | |
| # actual overrides via os env only to keep it minimal | |
| max_attempts = READY_MAX_ATTEMPTS | |
| interval = READY_INTERVAL_S | |
| # --- 1) Wake once (GET /) --- | |
| try: | |
| r = requests.get(f"{BASE}/", headers=_headers(), timeout=10) | |
| log.append(f"wake: {r.status_code}") | |
| except Exception as e: | |
| log.append(f"wake_err: {e}") | |
| # --- 2) Quiet wait to let models load --- | |
| time.sleep(warmup_wait) | |
| log.append(f"quiet_wait_done: {warmup_wait}s") | |
| # --- 3) Poll /ready --- | |
| ready = False | |
| last_text = "" | |
| for i in range(1, max_attempts + 1): | |
| try: | |
| rr = requests.get(f"{BASE}/ready", headers=_headers(), timeout=10) | |
| last_text = rr.text | |
| if rr.ok and '"ready"' in rr.text: | |
| log.append(f"ready_yes_at_attempt:{i}") | |
| ready = True | |
| break | |
| else: | |
| log.append(f"ready_no_{i}: {rr.status_code} {rr.text[:80]}") | |
| except Exception as e: | |
| log.append(f"ready_err_{i}: {e}") | |
| time.sleep(interval) | |
| if not ready: | |
| return { | |
| "status": "not_ready", | |
| "last_ready_response": last_text[:200], | |
| "log": log | |
| } | |
| # --- 4) Fire /run with secret --- | |
| try: | |
| run_url = f"{BASE}/run?secret={CRON_SECRET}" | |
| final = requests.get(run_url, headers=_headers(), timeout=600) | |
| return { | |
| "status": "ok", | |
| "code": final.status_code, | |
| "body": (final.text[:2000] if final.text else ""), | |
| "log": log | |
| } | |
| except Exception as e: | |
| return {"status": "run_error", "error": str(e), "log": log} | |