Upload app.py with huggingface_hub
Browse files
app.py
CHANGED
|
@@ -11,6 +11,8 @@ from gradio import Server
|
|
| 11 |
from fastapi import Request
|
| 12 |
from fastapi.responses import HTMLResponse
|
| 13 |
from huggingface_hub import hf_hub_download
|
|
|
|
|
|
|
| 14 |
|
| 15 |
from magenta_rt import paths
|
| 16 |
|
|
@@ -145,9 +147,8 @@ async def banks(session_id: str = ""):
|
|
| 145 |
return {"bankStatus": [os.path.exists(os.path.join(SESSION_DIR, f"{sid}_bank{i}.pt")) for i in range(3)]}
|
| 146 |
|
| 147 |
|
| 148 |
-
@app.api(name="stream")
|
| 149 |
@spaces.GPU(duration=90)
|
| 150 |
-
def
|
| 151 |
"""Continuous gen; switches model live when the dropdown changes."""
|
| 152 |
from magenta_rt.torch.system import make_sampler, discretize_cfg, _float_to_int16, FRAME_SAMPLES
|
| 153 |
if style_model.device != "cuda":
|
|
@@ -284,8 +285,8 @@ def stream(session_id: str) -> str:
|
|
| 284 |
emitted_samples += audio.shape[1]
|
| 285 |
frame_ms = (time.time() - gen_t) * 1000.0 / CHUNK # real per-frame inference time
|
| 286 |
if audio.shape[1] > 0:
|
| 287 |
-
|
| 288 |
-
yield
|
| 289 |
buf = (0.15, 0.3, 0.5)[max(0, min(2, int(c.get("buffer", 0))))]
|
| 290 |
ahead = (emitted_samples / SR) - (time.time() - t0)
|
| 291 |
if ahead < -0.3: # fell behind (cold-start/hiccup) -> resync, no catch-up burst
|
|
@@ -304,6 +305,70 @@ def stream(session_id: str) -> str:
|
|
| 304 |
time.sleep(min(sleep_for, 0.5))
|
| 305 |
|
| 306 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 307 |
@app.get("/")
|
| 308 |
async def index():
|
| 309 |
with open(os.path.join(os.path.dirname(os.path.abspath(__file__)), "index.html")) as f:
|
|
|
|
| 11 |
from fastapi import Request
|
| 12 |
from fastapi.responses import HTMLResponse
|
| 13 |
from huggingface_hub import hf_hub_download
|
| 14 |
+
import asyncio, threading, queue as _q, contextvars, struct
|
| 15 |
+
from fastapi import WebSocket, WebSocketDisconnect
|
| 16 |
|
| 17 |
from magenta_rt import paths
|
| 18 |
|
|
|
|
| 147 |
return {"bankStatus": [os.path.exists(os.path.join(SESSION_DIR, f"{sid}_bank{i}.pt")) for i in range(3)]}
|
| 148 |
|
| 149 |
|
|
|
|
| 150 |
@spaces.GPU(duration=90)
|
| 151 |
+
def gpu_stream(session_id):
|
| 152 |
"""Continuous gen; switches model live when the dropdown changes."""
|
| 153 |
from magenta_rt.torch.system import make_sampler, discretize_cfg, _float_to_int16, FRAME_SAMPLES
|
| 154 |
if style_model.device != "cuda":
|
|
|
|
| 285 |
emitted_samples += audio.shape[1]
|
| 286 |
frame_ms = (time.time() - gen_t) * 1000.0 / CHUNK # real per-frame inference time
|
| 287 |
if audio.shape[1] > 0:
|
| 288 |
+
ab = _float_to_int16(audio[0].float().cpu().numpy()).astype("<i2").tobytes()
|
| 289 |
+
yield (ab, frame_ms)
|
| 290 |
buf = (0.15, 0.3, 0.5)[max(0, min(2, int(c.get("buffer", 0))))]
|
| 291 |
ahead = (emitted_samples / SR) - (time.time() - t0)
|
| 292 |
if ahead < -0.3: # fell behind (cold-start/hiccup) -> resync, no catch-up burst
|
|
|
|
| 305 |
time.sleep(min(sleep_for, 0.5))
|
| 306 |
|
| 307 |
|
| 308 |
+
_sessions = {}
|
| 309 |
+
_slock = threading.Lock()
|
| 310 |
+
|
| 311 |
+
|
| 312 |
+
def _worker(session_id, audio_q, stop_ev):
|
| 313 |
+
try:
|
| 314 |
+
while not stop_ev.is_set():
|
| 315 |
+
try:
|
| 316 |
+
for ab, fm in gpu_stream(session_id): # ~55s GPU grant; re-grants on loop
|
| 317 |
+
if stop_ev.is_set():
|
| 318 |
+
break
|
| 319 |
+
if audio_q.full():
|
| 320 |
+
try: audio_q.get_nowait()
|
| 321 |
+
except _q.Empty: pass
|
| 322 |
+
try: audio_q.put_nowait((ab, fm))
|
| 323 |
+
except _q.Full: pass
|
| 324 |
+
except Exception as e:
|
| 325 |
+
if "abort" in str(e).lower() or "duration" in str(e).lower():
|
| 326 |
+
continue # grant expired -> re-grant
|
| 327 |
+
print("[worker]", repr(e), flush=True); break
|
| 328 |
+
finally:
|
| 329 |
+
stop_ev.set()
|
| 330 |
+
|
| 331 |
+
|
| 332 |
+
@app.api(name="start")
|
| 333 |
+
def start(session_id: str = ""):
|
| 334 |
+
if not session_id:
|
| 335 |
+
return {"ok": False}
|
| 336 |
+
with _slock:
|
| 337 |
+
prev = _sessions.pop(session_id, None)
|
| 338 |
+
if prev:
|
| 339 |
+
prev["stop"].set()
|
| 340 |
+
audio_q = _q.Queue(maxsize=48); stop_ev = threading.Event()
|
| 341 |
+
ctx = contextvars.copy_context()
|
| 342 |
+
t = threading.Thread(target=ctx.run, args=(_worker, session_id, audio_q, stop_ev), daemon=True)
|
| 343 |
+
with _slock:
|
| 344 |
+
_sessions[session_id] = {"audio": audio_q, "stop": stop_ev}
|
| 345 |
+
t.start()
|
| 346 |
+
return {"ok": True}
|
| 347 |
+
|
| 348 |
+
|
| 349 |
+
@app.websocket("/ws")
|
| 350 |
+
async def audio_ws(websocket: WebSocket, session_id: str = ""):
|
| 351 |
+
await websocket.accept()
|
| 352 |
+
sess = _sessions.get(session_id)
|
| 353 |
+
if not sess:
|
| 354 |
+
await websocket.close(code=1008); return
|
| 355 |
+
audio_q, stop_ev = sess["audio"], sess["stop"]
|
| 356 |
+
loop = asyncio.get_event_loop()
|
| 357 |
+
try:
|
| 358 |
+
while not stop_ev.is_set():
|
| 359 |
+
try:
|
| 360 |
+
ab, fm = await loop.run_in_executor(None, lambda: audio_q.get(timeout=1.0))
|
| 361 |
+
except Exception:
|
| 362 |
+
continue
|
| 363 |
+
await websocket.send_bytes(struct.pack("<f", fm) + ab)
|
| 364 |
+
except WebSocketDisconnect:
|
| 365 |
+
pass
|
| 366 |
+
finally:
|
| 367 |
+
stop_ev.set()
|
| 368 |
+
with _slock:
|
| 369 |
+
_sessions.pop(session_id, None)
|
| 370 |
+
|
| 371 |
+
|
| 372 |
@app.get("/")
|
| 373 |
async def index():
|
| 374 |
with open(os.path.join(os.path.dirname(os.path.abspath(__file__)), "index.html")) as f:
|