Spaces:
Running on Zero
Running on Zero
| """ | |
| 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 | |
| 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) | |