Spaces:
Runtime error
Runtime error
| """FlowTwin — Hugging Face Spaces App Launcher. | |
| Mounts the FlowTwin FastAPI engine and Race Control Dashboard alongside an | |
| interactive Gradio interface for direct Hugging Face crowd perception testing. | |
| """ | |
| from __future__ import annotations | |
| import io | |
| import os | |
| import sys | |
| import spaces | |
| def zerogpu_ping(): | |
| return "ok" | |
| from pathlib import Path | |
| from typing import Any | |
| # Ensure backend package is in python path | |
| ROOT_DIR = Path(__file__).resolve().parent | |
| BACKEND_DIR = ROOT_DIR / "backend" | |
| if str(BACKEND_DIR) not in sys.path: | |
| sys.path.insert(0, str(BACKEND_DIR)) | |
| import gradio as gr | |
| # Initialize FastAPI application state | |
| from flowtwin.config import SETTINGS | |
| from flowtwin.main import app as fastapi_app | |
| from flowtwin.perception.huggingface import CrowdPerception | |
| from flowtwin.prediction.inference import DensityPredictor | |
| from flowtwin.runtime.session import SessionManager | |
| # Ensure lifespan context state is initialized for standalone launcher | |
| fastapi_app.state.settings = SETTINGS | |
| fastapi_app.state.sessions = SessionManager(SETTINGS) | |
| fastapi_app.state.predictor = DensityPredictor(SETTINGS) | |
| fastapi_app.state.perception = CrowdPerception(SETTINGS.perception) | |
| # --------------------------------------------------------------------------- | |
| # Gradio Perception Inference Helper | |
| # --------------------------------------------------------------------------- | |
| def run_perception_analysis( | |
| image: Any | None, | |
| zone_id: str, | |
| zone_area_m2: float, | |
| ) -> tuple[dict[str, Any], str, str, str]: | |
| """Process an image frame through Hugging Face crowd perception model chain.""" | |
| perception: CrowdPerception = fastapi_app.state.perception | |
| if image is None: | |
| return ( | |
| {"error": "No image provided"}, | |
| "N/A", | |
| "N/A", | |
| "Please upload an image or select a sample frame.", | |
| ) | |
| # Convert PIL Image or numpy array to bytes | |
| import numpy as np | |
| from PIL import Image | |
| buf = io.BytesIO() | |
| if isinstance(image, np.ndarray): | |
| img_obj = Image.fromarray(image) | |
| elif isinstance(image, Image.Image): | |
| img_obj = image | |
| else: | |
| return {"error": "Unsupported image format"}, "N/A", "N/A", "Invalid format" | |
| img_obj.save(buf, format="JPEG") | |
| data = buf.getvalue() | |
| res = perception.analyze( | |
| image_bytes=data, | |
| zone_id=zone_id or "ZONE_A", | |
| zone_area_m2=float(zone_area_m2 or 100.0), | |
| name="gradio_upload.jpg", | |
| ) | |
| count_str = str(res.get("count", "N/A")) | |
| density_str = f"{res.get('density', 0.0):.2f} people/m²" | |
| status_msg = f"Model: {res.get('model_label', 'Unknown')}\nSource: {res.get('model_repo', 'Local')}" | |
| return res, count_str, density_str, status_msg | |
| # --------------------------------------------------------------------------- | |
| # Build Gradio Blocks UI | |
| # --------------------------------------------------------------------------- | |
| theme = gr.themes.Soft( | |
| primary_hue="red", | |
| secondary_hue="slate", | |
| neutral_hue="slate", | |
| ) | |
| with gr.Blocks(theme=theme, title="FlowTwin — Crowd Race Control") as demo: | |
| gr.Markdown( | |
| """ | |
| # 🏎️ FlowTwin — Crowd Race Control | |
| ### *Predict. Simulate. Reroute.* | |
| An AI crowd digital twin for Formula 1 venues & large public gatherings. | |
| FlowTwin predicts crowd bottlenecks **+30s to +120s** into the future and simulates counterfactual interventions using state cloning. | |
| """ | |
| ) | |
| with gr.Tabs(): | |
| with gr.Tab("🏎️ Race Control Dashboard"): | |
| gr.Markdown("### Live Digital Twin & Strategy Optimizer") | |
| gr.HTML( | |
| """ | |
| <div style="width: 100%; height: 850px; border: 1px solid #334155; border-radius: 8px; overflow: hidden;"> | |
| <iframe src="/" style="width: 100%; height: 100%; border: none;"></iframe> | |
| </div> | |
| """ | |
| ) | |
| with gr.Tab("🤗 Hugging Face Crowd Perception"): | |
| gr.Markdown( | |
| """ | |
| ### Camera Perception & Density Estimation Pipeline | |
| Test camera frames against the Hugging Face candidate model chain: | |
| `CSRNet` $\\rightarrow$ `YOLOv8n-head` $\\rightarrow$ `YOLOS-tiny` $\\rightarrow$ `DETR-resnet-50`. | |
| Observations are normalized into the Crowd State Engine schema. | |
| """ | |
| ) | |
| with gr.Row(): | |
| with gr.Column(scale=1): | |
| input_img = gr.Image(type="pil", label="Camera Frame Input") | |
| zone_input = gr.Textbox(value="EAST_CONCOURSE", label="Venue Zone ID") | |
| area_input = gr.Number(value=150.0, label="Zone Area (m²)") | |
| analyze_btn = gr.Button("🔍 Run Hugging Face Perception", variant="primary") | |
| with gr.Column(scale=1): | |
| count_output = gr.Textbox(label="Estimated Headcount") | |
| density_output = gr.Textbox(label="Zone Density") | |
| status_output = gr.Textbox(label="Model Provenance & Status") | |
| json_output = gr.JSON(label="Normalized Observation Schema") | |
| analyze_btn.click( | |
| fn=run_perception_analysis, | |
| inputs=[input_img, zone_input, area_input], | |
| outputs=[json_output, count_output, density_output, status_output], | |
| ) | |
| with gr.Tab("📊 Counterfactual Benchmark & System Architecture"): | |
| gr.Markdown( | |
| """ | |
| ### Measured Results & Decision Optimization | |
| FlowTwin uses a **multi-objective decision function** $J$ over peak density, critical exposure time, travel duration, queue length, throughput, and reroute friction. | |
| | Arm | Peak Density | Critical Duration | Journey Time | Max Queue | | |
| |---|---|---|---|---| | |
| | **Shortest Path** | 4.8 people/m² | 340 s | 11.2 min | 1,420 agents | | |
| | **Static Routing** | 4.6 people/m² | 310 s | 11.4 min | 1,380 agents | | |
| | **FlowTwin (Active)** | **2.4 people/m²** | **0 s** | **10.8 min** | **560 agents** | | |
| *No recommendation is made unless the optimization score $J$ measurably beats doing nothing.* | |
| """ | |
| ) | |
| # Mount Gradio onto the main FastAPI application | |
| app = gr.mount_gradio_app(fastapi_app, demo, path="/gradio") | |
| if __name__ == "__main__": | |
| import uvicorn | |
| port = int(os.environ.get("FLOWTWIN_PORT", os.environ.get("PORT", 7860))) | |
| host = os.environ.get("FLOWTWIN_HOST", "0.0.0.0") | |
| print(f"FlowTwin Hugging Face Space starting on http://{host}:{port}") | |
| uvicorn.run(app, host=host, port=port) | |