""" HuggingFace Space entry point (Gradio SDK) Mounts Gradio onto the existing FastAPI backend. HF Gradio SDK pre-starts a server on port 7860 before executing app.py. So instead of starting our own uvicorn (port conflict), we monkey-patch blocks.launch to pass app=combined — injecting all FastAPI routes into the server that HF already started. """ import os import types import gradio as gr from app.main import app as fastapi_app try: import spaces import torch @spaces.GPU def gpu_warmup(): try: if torch.cuda.is_available(): _ = torch.zeros(1, device="cuda") return "ZeroGPU CUDA Tensor Allocated" return "CUDA unavailable" except Exception as e: return f"ZeroGPU CUDA Warmup Error: {e}" except Exception: def gpu_warmup(): return "CPU Active" # Run warmup immediately during container startup to satisfy the ZeroGPU supervisor check try: gpu_warmup() except Exception as e: print(f"Startup GPU Warmup failed (possibly transient HF hardware error): {e}") # ── Blocks UI ───────────────────────────────────────────────────────── # Gradio 6: title & theme moved from Blocks() constructor to launch() with gr.Blocks(title="Othaim ALPR API", theme=gr.themes.Soft()) as blocks: gr.Markdown(""" # 🅿️ Othaim Parking ALPR System Backend is running. All API endpoints are available at their normal paths. **Endpoints:** - [`/docs`](/docs) → Swagger Interactive API Docs - [`/health`](/health) → Health Check - [`/predict`](/predict) → Plate Recognition - [`/auth/login`](/auth/login) → Authentication """) with gr.Tab("System Status"): status_btn = gr.Button("Check API Status") status_out = gr.JSON() def check_health(): import requests port = os.getenv("PORT", "7860") try: r = requests.get(f"http://localhost:{port}/health", timeout=10) return r.json() except Exception as e: return {"status": "error", "detail": str(e)} status_btn.click(check_health, outputs=status_out) blocks.load(gpu_warmup) # ── Combine FastAPI + Gradio so the server serves both ──────────────── combined = gr.mount_gradio_app(fastapi_app, blocks, path="/gradio") # ── Monkey-patch: inject combined app when HF calls demo.launch() ───── # HF's Gradio wrapper calls demo.launch(server_name=..., server_port=...). # We intercept to pass app=combined so the FastAPI routes are included. _blocks_launch_original = blocks.launch def _launch_with_app(self, **kwargs): import uvicorn server_name = kwargs.get("server_name", "0.0.0.0") server_port = int(kwargs.get("server_port", os.getenv("PORT", "7860"))) uvicorn.run(combined, host=server_name, port=server_port) blocks.launch = types.MethodType(_launch_with_app, blocks) demo = blocks if __name__ == "__main__": demo.launch(server_name="0.0.0.0", server_port=7860)