File size: 3,206 Bytes
34a66f3
6c546fd
 
 
 
 
 
 
34a66f3
 
6c546fd
34a66f3
 
 
 
d0a71c1
 
f8179a8
d0a71c1
 
 
f8179a8
 
 
 
 
 
 
d0a71c1
 
 
c896909
ab4a075
c381a99
 
 
 
 
ab4a075
 
c896909
4286fba
 
f8179a8
6c546fd
 
1a41112
34a66f3
 
a53a2ed
34a66f3
a53a2ed
34a66f3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
d0a71c1
 
34a66f3
6c546fd
34a66f3
 
6c546fd
 
 
 
 
 
 
b1e4e62
 
 
 
 
6c546fd
 
 
 
3bc066c
 
 
 
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
"""
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)