"""FloodGate v1 on a Hugging Face Space: the OpenEnv server (reset, step, state, the MCP tools, the Task API and the web UI at /web, whose Explore tab holds the 3D replay and every committed run's results) and the replay at /twin/. The Space serves live mode (FLOOD_MODE=live): the agent commits the dams' releases block by block on forecast scenarios that carry real 2025 NWS forecast errors. It runs on ZeroGPU hardware but never asks for a GPU; ZeroGPU wants one decorated function, so `_noop` exists and is never called. python app.py # http://127.0.0.1:7860/web/ (the Space's page), /twin/ """ from __future__ import annotations import os import sys from pathlib import Path ROOT = Path(__file__).resolve().parent sys.path[:0] = [str(ROOT / "core"), str(ROOT / "openenv")] os.environ.setdefault("FLOOD_TASKS_DIR", str(ROOT / "tasks" / "flood-v1-sample")) os.environ.setdefault("FLOOD_RUNS_DIR", str(ROOT / "runs")) os.environ.setdefault("FLOOD_DATA_DIR", str(ROOT / "data" / "cumberland")) os.environ.setdefault("FLOOD_MODE", "live") os.environ.setdefault("ENABLE_WEB_INTERFACE", "true") # Spaces turn on Gradio's server-side rendering, whose Node server takes port 7860 before uvicorn can. os.environ["GRADIO_SSR_MODE"] = "false" card = (ROOT / "README.md").read_text(encoding="utf-8") if card.startswith("---"): card = card.split("---", 2)[2].lstrip() readme = Path(os.environ.get("TMPDIR", "/tmp")) / "floodgate_readme.md" readme.write_text(card, encoding="utf-8") os.environ.setdefault("ENV_README_PATH", str(readme)) try: import spaces except ImportError: # running elsewhere spaces = None if spaces is not None: @spaces.GPU(duration=1) def _noop(): # ZeroGPU requires one decorated function; nothing calls it pass import uvicorn # noqa: E402 from flood_openenv.server import build_app # noqa: E402 app = build_app() if __name__ == "__main__": if spaces is not None: from spaces import zero zero.startup() uvicorn.run(app, host="0.0.0.0", port=int(os.environ.get("PORT", "7860")), ws_ping_interval=60, ws_ping_timeout=600)