Spaces:
Running
Running
Deploy demo to HF Space
Browse files- __pycache__/app.cpython-312.pyc +0 -0
- app.py +52 -9
- packages.txt +1 -0
__pycache__/app.cpython-312.pyc
CHANGED
|
Binary files a/__pycache__/app.cpython-312.pyc and b/__pycache__/app.cpython-312.pyc differ
|
|
|
app.py
CHANGED
|
@@ -32,9 +32,10 @@ os.environ["MPLCONFIGDIR"] = "/tmp/matplotlib"
|
|
| 32 |
# Disable tokenizer parallelism warning
|
| 33 |
os.environ["TOKENIZERS_PARALLELISM"] = "false"
|
| 34 |
|
| 35 |
-
import base64
|
| 36 |
import html
|
|
|
|
| 37 |
import sys
|
|
|
|
| 38 |
from collections.abc import Callable, Mapping, Sequence
|
| 39 |
from itertools import groupby
|
| 40 |
from operator import itemgetter
|
|
@@ -347,27 +348,69 @@ def local_runner(model_path: str) -> Callable[[str, dict[str, Any]], dict[str, A
|
|
| 347 |
WAKING_UP = "The model server is starting up or offline. Please try again in a few minutes."
|
| 348 |
|
| 349 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 350 |
def remote_runner(
|
| 351 |
endpoint_url: str, api_key: str | None
|
| 352 |
) -> Callable[[str, dict[str, Any]], dict[str, Any]]:
|
| 353 |
"""POST each request to a `ta serve` server (scripts/serve.py)."""
|
| 354 |
-
|
| 355 |
|
| 356 |
def run_pipeline(audio: str, kwargs: dict[str, Any]) -> dict[str, Any]:
|
| 357 |
-
#
|
| 358 |
-
#
|
| 359 |
-
|
| 360 |
-
"inputs": base64.b64encode(Path(audio).read_bytes()).decode(),
|
| 361 |
-
"parameters": kwargs,
|
| 362 |
-
}
|
| 363 |
try:
|
| 364 |
-
response = httpx.post(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 365 |
except httpx.TimeoutException as e:
|
| 366 |
msg = "The model server took too long to respond."
|
| 367 |
raise gr.Error(msg) from e
|
| 368 |
except httpx.HTTPError as e:
|
| 369 |
msg = f"Could not reach the model server: {e}"
|
| 370 |
raise gr.Error(msg) from e
|
|
|
|
|
|
|
| 371 |
if response.status_code in (502, 503, 504):
|
| 372 |
raise gr.Error(WAKING_UP)
|
| 373 |
if response.is_error:
|
|
|
|
| 32 |
# Disable tokenizer parallelism warning
|
| 33 |
os.environ["TOKENIZERS_PARALLELISM"] = "false"
|
| 34 |
|
|
|
|
| 35 |
import html
|
| 36 |
+
import subprocess
|
| 37 |
import sys
|
| 38 |
+
import tempfile
|
| 39 |
from collections.abc import Callable, Mapping, Sequence
|
| 40 |
from itertools import groupby
|
| 41 |
from operator import itemgetter
|
|
|
|
| 348 |
WAKING_UP = "The model server is starting up or offline. Please try again in a few minutes."
|
| 349 |
|
| 350 |
|
| 351 |
+
def compact_audio(audio: str) -> tuple[bytes, str]:
|
| 352 |
+
"""`(body, content type)` for an upload: 16 kHz mono FLAC, or the file as-is.
|
| 353 |
+
|
| 354 |
+
The server decodes everything to 16 kHz mono, so sending that -- losslessly
|
| 355 |
+
-- changes nothing but the size: a 44.1 kHz stereo WAV shrinks ~10x, from
|
| 356 |
+
~10.6 to ~1 MB a minute. RunPod's proxy refuses large bodies (413 Payload
|
| 357 |
+
Too Large), so this is what lets hour-long recordings through. Without
|
| 358 |
+
ffmpeg, or for a file it can't read, the original bytes go and the server
|
| 359 |
+
reports any decode error itself.
|
| 360 |
+
"""
|
| 361 |
+
# To a file, not a pipe: ffmpeg seeks back to write the stream's length
|
| 362 |
+
# into the FLAC header, which a piped stream leaves bogus (libsndfile then
|
| 363 |
+
# refuses it).
|
| 364 |
+
with tempfile.TemporaryDirectory() as tmp:
|
| 365 |
+
flac = Path(tmp) / "upload.flac"
|
| 366 |
+
command = [
|
| 367 |
+
"ffmpeg", "-nostdin", "-v", "error", "-i", audio,
|
| 368 |
+
"-ac", "1", "-ar", "16000", "-sample_fmt", "s16", str(flac),
|
| 369 |
+
] # fmt: skip
|
| 370 |
+
try:
|
| 371 |
+
subprocess.run(command, check=True, capture_output=True)
|
| 372 |
+
except (OSError, subprocess.CalledProcessError):
|
| 373 |
+
return Path(audio).read_bytes(), "application/octet-stream"
|
| 374 |
+
return flac.read_bytes(), "audio/flac"
|
| 375 |
+
|
| 376 |
+
|
| 377 |
+
def query_parameters(kwargs: Mapping[str, Any]) -> dict[str, str]:
|
| 378 |
+
"""Pipeline options as the query string `ta serve` parses ("true", "3")."""
|
| 379 |
+
return {k: str(v).lower() if isinstance(v, bool) else str(v) for k, v in kwargs.items()}
|
| 380 |
+
|
| 381 |
+
|
| 382 |
+
TOO_LARGE = (
|
| 383 |
+
"This file is too large for the model server, even compressed to 16 kHz mono. "
|
| 384 |
+
"Try a shorter recording."
|
| 385 |
+
)
|
| 386 |
+
|
| 387 |
+
|
| 388 |
def remote_runner(
|
| 389 |
endpoint_url: str, api_key: str | None
|
| 390 |
) -> Callable[[str, dict[str, Any]], dict[str, Any]]:
|
| 391 |
"""POST each request to a `ta serve` server (scripts/serve.py)."""
|
| 392 |
+
auth = {"Authorization": f"Bearer {api_key}"} if api_key else {}
|
| 393 |
|
| 394 |
def run_pipeline(audio: str, kwargs: dict[str, Any]) -> dict[str, Any]:
|
| 395 |
+
# Raw audio as the body, options in the query string: base64 in JSON
|
| 396 |
+
# would add a third to an upload the proxy already caps.
|
| 397 |
+
body, content_type = compact_audio(audio)
|
|
|
|
|
|
|
|
|
|
| 398 |
try:
|
| 399 |
+
response = httpx.post(
|
| 400 |
+
endpoint_url,
|
| 401 |
+
content=body,
|
| 402 |
+
params=query_parameters(kwargs),
|
| 403 |
+
headers={**auth, "Content-Type": content_type},
|
| 404 |
+
timeout=600,
|
| 405 |
+
)
|
| 406 |
except httpx.TimeoutException as e:
|
| 407 |
msg = "The model server took too long to respond."
|
| 408 |
raise gr.Error(msg) from e
|
| 409 |
except httpx.HTTPError as e:
|
| 410 |
msg = f"Could not reach the model server: {e}"
|
| 411 |
raise gr.Error(msg) from e
|
| 412 |
+
if response.status_code == 413:
|
| 413 |
+
raise gr.Error(TOO_LARGE)
|
| 414 |
if response.status_code in (502, 503, 504):
|
| 415 |
raise gr.Error(WAKING_UP)
|
| 416 |
if response.is_error:
|
packages.txt
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
ffmpeg
|