AdnaPlays commited on
Commit
33a9d4f
Β·
verified Β·
1 Parent(s): b989503

Create hf_launch.py

Browse files
Files changed (1) hide show
  1. hf_launch.py +119 -0
hf_launch.py ADDED
@@ -0,0 +1,119 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ hf_launch.py β€” starts any of the three apps on Hugging Face behind the admin.gamify.pt gate,
3
+ WITHOUT changing the app's own code.
4
+
5
+ Video Processor β†’ APP_MODULE=app (app.py builds a FastAPI "app")
6
+ Thumbnail Editor β†’ APP_MODULE=server (server.py builds a FastAPI "app")
7
+ Upload Center β†’ APP_MODULE=app (app.py builds Gradio Blocks and calls .launch())
8
+
9
+ How:
10
+ β€’ If the module calls Blocks.launch(), that call is caught (Gradio's own server is NOT started)
11
+ and the Blocks are served here instead, with the same theme / css the app passed to launch().
12
+ β€’ If the module already builds a FastAPI/Starlette app, that app is used as it is.
13
+ β€’ The GamifyGate (gamify_gate.py) is put in front β€” unless the app already added it itself.
14
+ β€’ GAMIFY_GATE=off opens the app to everyone; if gamify_gate.py can't be loaded, everything is
15
+ blocked (the app is never opened by accident).
16
+
17
+ Dockerfile: CMD ["python", "hf_launch.py"]
18
+ """
19
+ import importlib
20
+ import inspect
21
+ import logging
22
+ import os
23
+
24
+ import gradio as gr
25
+
26
+ logging.basicConfig(level=logging.INFO)
27
+ PORT = int(os.environ.get("PORT", 7860))
28
+ MODULE = os.environ.get("APP_MODULE", "app")
29
+
30
+
31
+ def _params(fn):
32
+ try:
33
+ return inspect.signature(fn).parameters
34
+ except (TypeError, ValueError):
35
+ return {}
36
+
37
+
38
+ # ---- 1) load the app; catch Blocks.launch() so it doesn't start its own (ungated) server ----
39
+ _captured = {}
40
+ _original_launch = gr.Blocks.launch
41
+
42
+
43
+ def _capture_launch(self, *args, **kwargs):
44
+ _captured["blocks"], _captured["kwargs"] = self, kwargs
45
+ logging.info("hf_launch: the app called launch() β€” it will be served behind the gate instead")
46
+ return None
47
+
48
+
49
+ gr.Blocks.launch = _capture_launch
50
+ try:
51
+ module = importlib.import_module(MODULE)
52
+ finally:
53
+ gr.Blocks.launch = _original_launch
54
+
55
+
56
+ def _is_asgi_app(obj):
57
+ """A FastAPI / Starlette application (has add_middleware and is callable)."""
58
+ return obj is not None and not isinstance(obj, gr.Blocks) and callable(obj) and hasattr(obj, "add_middleware")
59
+
60
+
61
+ # ---- 2) the web app to serve ----
62
+ asgi = next((getattr(module, n) for n in ("app", "server", "application") if _is_asgi_app(getattr(module, n, None))),
63
+ None)
64
+ if asgi is None:
65
+ from fastapi import FastAPI
66
+ blocks = _captured.get("blocks") or next(
67
+ (getattr(module, n) for n in ("app", "demo", "interface") if isinstance(getattr(module, n, None), gr.Blocks)),
68
+ None)
69
+ if blocks is None:
70
+ raise RuntimeError(f"hf_launch: no Gradio Blocks or FastAPI app found in {MODULE}.py")
71
+ launch_kwargs = _captured.get("kwargs", {})
72
+ mount_params = _params(gr.mount_gradio_app)
73
+ extra = {k: v for k, v in launch_kwargs.items() if k in mount_params and k not in ("app", "blocks", "path")}
74
+ if "css" in launch_kwargs and "css" not in mount_params and hasattr(blocks, "css"):
75
+ blocks.css = launch_kwargs["css"] # older Gradio: css lives on the Blocks
76
+ asgi = gr.mount_gradio_app(FastAPI(), blocks, path="/", **extra)
77
+
78
+
79
+ # ---- 3) the access gate ----
80
+ def _has_gate(app_):
81
+ for m in getattr(app_, "user_middleware", []) or []:
82
+ cls = getattr(m, "cls", None)
83
+ if getattr(cls, "__name__", "") == "GamifyGate":
84
+ return True
85
+ return False
86
+
87
+
88
+ class _BlockEverything:
89
+ """Gate wanted but gamify_gate.py missing: nobody gets in."""
90
+ def __init__(self, app_):
91
+ self.app = app_
92
+
93
+ async def __call__(self, scope, receive, send):
94
+ if scope.get("type") != "http" or scope.get("path") == "/healthz":
95
+ return await self.app(scope, receive, send)
96
+ await send({"type": "http.response.start", "status": 503,
97
+ "headers": [(b"content-type", b"text/plain; charset=utf-8")]})
98
+ await send({"type": "http.response.body",
99
+ "body": b"Access blocked: gamify_gate.py is missing from this Space."})
100
+
101
+
102
+ if os.environ.get("GAMIFY_GATE", "on").strip().lower() == "off":
103
+ logging.warning("hf_launch: GAMIFY_GATE=off β€” the app is OPEN to everyone")
104
+ elif _has_gate(asgi):
105
+ logging.info("hf_launch: the app already has the access gate")
106
+ else:
107
+ try:
108
+ from gamify_gate import GamifyGate
109
+ asgi.add_middleware(GamifyGate)
110
+ logging.info("hf_launch: access gate ON β€” only through admin.gamify.pt")
111
+ except Exception as e:
112
+ asgi.add_middleware(_BlockEverything)
113
+ logging.error(f"hf_launch: gamify_gate could not be loaded ({e}) β€” blocking all access")
114
+
115
+ app = asgi
116
+
117
+ if __name__ == "__main__":
118
+ import uvicorn
119
+ uvicorn.run(app, host="0.0.0.0", port=PORT)