"""Slipstream: interactive presentation of the project-controls forecasting benchmark. A Gradio Server (FastAPI + Gradio's API engine) that serves a buildless Preact frontend and exposes the benchmark data through typed `@app.api` endpoints the frontend calls via the @gradio/client JS library. Runs locally (`python app.py`) and on Hugging Face Spaces (sdk: gradio, app_file: app.py). """ import json import os import urllib.request from pathlib import Path import gradio as gr from fastapi import Request from fastapi.responses import HTMLResponse, JSONResponse from fastapi.staticfiles import StaticFiles ROOT = Path(__file__).parent FRONTEND = ROOT / "frontend" BENCH = json.loads((ROOT / "data" / "bench.json").read_text()) # Live-demo backend (deployed Modal app: pipeline/agent/demo_modal.py). The frontend calls the # same-origin /demo/* routes below; we proxy to Modal server-side so the URL stays out of the client # and the long-running, possibly-cold forecast (Modal 303-redirects + long-polls past ~150s) is # resolved into a single clean response. Override the URL with SLIPSTREAM_DEMO_URL. MODAL_DEMO = os.environ.get("SLIPSTREAM_DEMO_URL", "https://ashaibani--slipstream-demo-web.modal.run") app = gr.Server(title="Slipstream") # --------------------------------------------------------------------------- backend API @app.api(name="summary") def summary() -> dict: """High-level benchmark facts for the intro section, derived from the live results.""" methods = BENCH["methods"] families = sorted({m["family"] for m in methods.values()}) return { "n_projects": BENCH.get("n_eval"), # scored (>= 4 reporting periods) "n_sourced": BENCH.get("n_test"), # real projects with recorded outcomes "n_methods": len(methods), "stages": BENCH.get("stages", []), "primary": BENCH.get("primary"), "families": families, } @app.api(name="benchmark") def benchmark() -> dict: """The full benchmark results (every method's per-stage + per-strata metrics).""" return BENCH # --------------------------------------------------------------------------- live-demo proxy def _modal_get(path: str, timeout: int = 60): with urllib.request.urlopen(f"{MODAL_DEMO}{path}", timeout=timeout) as r: return json.loads(r.read()) @app.get("/demo/projects") def demo_projects(): try: return JSONResponse(_modal_get("/api/projects")) except Exception as e: # noqa: BLE001 return JSONResponse({"error": f"demo backend unreachable: {type(e).__name__}"}, status_code=502) @app.post("/demo/forecast") async def demo_forecast(request: Request): body = await request.body() rq = urllib.request.Request(f"{MODAL_DEMO}/api/forecast", data=body, method="POST", headers={"Content-Type": "application/json"}) try: with urllib.request.urlopen(rq, timeout=120) as r: return JSONResponse(json.loads(r.read())) except Exception as e: # noqa: BLE001 return JSONResponse({"error": f"demo backend error: {type(e).__name__}"}, status_code=502) @app.get("/demo/result") def demo_result(agent: str = "", tabpfn: str = ""): from urllib.parse import urlencode try: return JSONResponse(_modal_get("/api/result?" + urlencode({"agent": agent, "tabpfn": tabpfn}))) except Exception as e: # noqa: BLE001 return JSONResponse({"error": f"demo backend error: {type(e).__name__}"}, status_code=502) # --------------------------------------------------------------------------- serve frontend @app.get("/") def index(): return HTMLResponse((FRONTEND / "index.html").read_text()) app.mount("/static", StaticFiles(directory=str(FRONTEND)), name="static") if __name__ == "__main__": app.launch(server_name="0.0.0.0", server_port=7860)