Spaces:
Runtime error
Runtime error
File size: 6,808 Bytes
e7a9f02 e7ffc83 e7a9f02 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 | """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
@spaces.GPU
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)
|