DevEmmy commited on
Commit
74d52f2
·
1 Parent(s): 7cb4735

Do not bind a port; let the Space runner serve the ASGI app

Browse files

The runner already serves the module-level app, so our own uvicorn.run was a
second server competing for 7860 — the container died on 'address already in
use' right after startup completed. Mount the Blocks UI onto the same app at
import time instead, keeping /asr and /translate at the root.

Files changed (1) hide show
  1. app.py +25 -19
app.py CHANGED
@@ -225,34 +225,40 @@ def translate(body: TranslateIn, x_service_token: str = Header(default=None)):
225
 
226
 
227
  # ------------------------------------------------------------------- LAUNCH ---
228
- # A Gradio-SDK Space runs `python app.py` and expects something listening on
229
- # 7860. Mounting the Blocks onto our own FastAPI (rather than calling
230
- # demo.launch()) keeps /asr and /translate at the root, where the backend
231
- # already expects them, and puts the UI at /ui.
232
- def _ui_check(_):
 
 
 
 
233
  import json as _json
234
  return _json.dumps(health(), indent=2)
235
 
236
 
 
 
 
 
 
 
 
 
 
 
237
  def _build_ui():
238
  import gradio as gr
239
  with gr.Blocks(title="ScriptFlow Hausa inference") as demo:
240
- gr.Markdown(
241
- "## ScriptFlow inference service\n"
242
- "Hausa ASR + Hausa→English MT. The REST API is the real interface:\n"
243
- "`POST /asr` (raw audio body) and `POST /translate` "
244
- "(`{\"texts\": [...]}`), both with an `X-Service-Token` header.\n\n"
245
- "Press the button to see whether the models have loaded — the first "
246
- "call after a cold start downloads ~1GB and takes several minutes."
247
- )
248
  out = gr.Code(label="GET /", language="json")
249
- gr.Button("Check status").click(_ui_check, inputs=[gr.State(None)], outputs=out)
250
  return demo
251
 
252
 
253
- if __name__ == "__main__":
254
- import uvicorn
255
  import gradio as gr
256
-
257
- application = gr.mount_gradio_app(app, _build_ui(), path="/ui")
258
- uvicorn.run(application, host="0.0.0.0", port=int(os.environ.get("PORT", 7860)))
 
225
 
226
 
227
  # ------------------------------------------------------------------- LAUNCH ---
228
+ # The Space runner serves the module-level `app` itself. Binding a port here as
229
+ # well is what produced "address already in use" and killed the container: two
230
+ # servers competing for 7860. So this module defines the ASGI app and never
231
+ # listens.
232
+ #
233
+ # The Blocks UI is grafted onto that same app at import time, which keeps /asr
234
+ # and /translate at the root where the backend expects them, with a status page
235
+ # at /ui.
236
+ def _ui_check():
237
  import json as _json
238
  return _json.dumps(health(), indent=2)
239
 
240
 
241
+ _UI_TEXT = (
242
+ "## ScriptFlow inference service\n\n"
243
+ "Hausa ASR + Hausa->English MT. The REST API is the real interface:\n\n"
244
+ "- `POST /asr` — raw audio bytes as the body\n"
245
+ "- `POST /translate` — `{\"texts\": [...]}`\n\n"
246
+ "Both take an `X-Service-Token` header. The first call after a cold start "
247
+ "downloads ~1GB of weights and takes several minutes."
248
+ )
249
+
250
+
251
  def _build_ui():
252
  import gradio as gr
253
  with gr.Blocks(title="ScriptFlow Hausa inference") as demo:
254
+ gr.Markdown(_UI_TEXT)
 
 
 
 
 
 
 
255
  out = gr.Code(label="GET /", language="json")
256
+ gr.Button("Check status").click(_ui_check, inputs=None, outputs=out)
257
  return demo
258
 
259
 
260
+ try:
 
261
  import gradio as gr
262
+ app = gr.mount_gradio_app(app, _build_ui(), path="/ui")
263
+ except Exception as _e: # never let the UI break the API
264
+ print(f"gradio UI unavailable ({type(_e).__name__}: {_e}) — REST only", flush=True)