Spaces:
Sleeping
Sleeping
File size: 3,001 Bytes
021c59c | 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 | """HF Spaces entrypoint for NIGHTWAVE (shipped via the Docker SDK).
================================================================================
HOW THIS IS SERVED (Docker SDK -> `uvicorn app:app`)
--------------------------------------------------------------------------------
The Space runs `uvicorn app:app --host 0.0.0.0 --port 7860` (see ../space/Dockerfile
and the README front-matter: `sdk: docker`, `app_port: 7860`). That makes the
combined FastAPI ASGI `app` the single, deterministic server -- no guessing about
which object an HF gradio-launcher would pick up.
The module-level `app` is built FastAPI-FIRST and is ALWAYS functional:
* GET / -> the raw skeuomorphic radio document (top-level, so mic
+ autoplay permissions work without extra iframe nesting)
* POST /api/broadcast, /api/call, /api/seek -> same-origin proxy to Modal
(browser never sees Modal creds; graceful canned
fallback so the radio never goes silent)
A minimal Gradio Blocks (the iframe-wrapped radio) is then mounted at /gradio so
the Space is a bona-fide Gradio app (Off-Brand: a custom frontend past the default
Gradio look). The mount is OPPORTUNISTIC: if gradio import/mount fails for any
reason, the radio + /api/* still serve -- a gradio hiccup can never take the
product down. This is the deliberate <24h ship-safety choice.
================================================================================
"""
import logging
import os
from fastapi.responses import HTMLResponse
from server import create_api, radio_iframe_html, read_radio_html
_log = logging.getLogger("nightwave")
# 1) FastAPI app with the same-origin proxy routes. This ALWAYS works (no gradio).
app = create_api()
# Serve the radio at the root as the RAW document (top-level mic/autoplay).
@app.get("/", response_class=HTMLResponse)
def root_radio() -> HTMLResponse:
return HTMLResponse(read_radio_html())
# 2) Opportunistically mount a minimal Gradio Blocks at /gradio so the Space is a
# genuine Gradio app. Never let a gradio problem break the product.
demo = None
try:
import gradio as gr
with gr.Blocks(
title="NIGHTWAVE",
theme=gr.themes.Base(primary_hue="indigo", neutral_hue="slate"),
css="footer{display:none !important} .gradio-container{max-width:100% !important}",
) as demo:
gr.HTML(radio_iframe_html())
app = gr.mount_gradio_app(app, demo, path="/gradio")
_log.info("Gradio mounted at /gradio")
except Exception as exc: # pragma: no cover - defensive: never break serving
_log.warning("Gradio mount skipped (%r); serving radio + /api/* without it", exc)
if __name__ == "__main__":
# Runs locally too: with gradio absent (local Py3.9) the try/except above just
# skips the mount and we still serve the radio + /api/* exactly as on HF.
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=int(os.environ.get("PORT", "7860")))
|