Pant0x's picture
fix(deploy): wrap hf_backend startup gpu_warmup in try-except block to handle transient HF GPU hardware ECC errors
c381a99
Raw
History Blame Contribute Delete
3.21 kB
"""
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)