Spaces:
Sleeping
Sleeping
urwebsiteaz-ux commited on
Commit Β·
4c9ee07
1
Parent(s): d3752b1
chnaged app for the audio
Browse files
app.py
CHANGED
|
@@ -1,6 +1,11 @@
|
|
| 1 |
"""AUTOLYRICS β side-by-side baseline vs fine-tuned Gradio demo."""
|
| 2 |
import os
|
| 3 |
import time
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4 |
import torch
|
| 5 |
import torchaudio
|
| 6 |
import gradio as gr
|
|
@@ -36,12 +41,93 @@ print("Models ready.")
|
|
| 36 |
|
| 37 |
|
| 38 |
def load_audio(path: str) -> torch.Tensor:
|
| 39 |
-
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 45 |
|
| 46 |
|
| 47 |
@torch.inference_mode()
|
|
@@ -64,7 +150,20 @@ def transcribe_with(model, audio_tensor, num_beams: int):
|
|
| 64 |
def run(audio_path: str, num_beams: int, model_choice: str):
|
| 65 |
if audio_path is None:
|
| 66 |
return "β", "β", "β", "β", "Please upload audio."
|
| 67 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 68 |
duration = audio.shape[-1] / 16000
|
| 69 |
|
| 70 |
if model_choice == "Baseline only":
|
|
|
|
| 1 |
"""AUTOLYRICS β side-by-side baseline vs fine-tuned Gradio demo."""
|
| 2 |
import os
|
| 3 |
import time
|
| 4 |
+
import subprocess
|
| 5 |
+
import tempfile
|
| 6 |
+
import wave
|
| 7 |
+
from pathlib import Path
|
| 8 |
+
import numpy as np
|
| 9 |
import torch
|
| 10 |
import torchaudio
|
| 11 |
import gradio as gr
|
|
|
|
| 41 |
|
| 42 |
|
| 43 |
def load_audio(path: str) -> torch.Tensor:
|
| 44 |
+
"""Load any browser-uploaded audio format β 16 kHz mono float32 tensor.
|
| 45 |
+
|
| 46 |
+
Strategy (two-stage, zero libsndfile dependency):
|
| 47 |
+
1. ffmpeg transcodes ANY browser format (webm/opus, ogg, mp3, m4a, wav)
|
| 48 |
+
into a clean 16-bit PCM WAV at 16 kHz mono. ffmpeg handles every
|
| 49 |
+
container/codec that browsers produce, including Gradio mic recordings.
|
| 50 |
+
2. Python's built-in `wave` module reads the raw PCM bytes directly.
|
| 51 |
+
This **completely bypasses soundfile / libsndfile**, which cannot decode
|
| 52 |
+
webm, ogg/opus, or partially-encoded containers and raises
|
| 53 |
+
``soundfile.LibsndfileError: Format not recognised`` on HF Spaces.
|
| 54 |
+
|
| 55 |
+
ffmpeg is pre-installed on HF Spaces via packages.txt β no extra Python
|
| 56 |
+
package is needed. `wave` and `numpy` are always available.
|
| 57 |
+
|
| 58 |
+
Returns
|
| 59 |
+
-------
|
| 60 |
+
torch.Tensor
|
| 61 |
+
1-D float32 waveform on CPU, normalised to [-1, 1], at 16 000 Hz.
|
| 62 |
+
"""
|
| 63 |
+
src = Path(path)
|
| 64 |
+
if not src.exists() or src.stat().st_size == 0:
|
| 65 |
+
raise ValueError(f"Audio file missing or empty: {path}")
|
| 66 |
+
|
| 67 |
+
with tempfile.NamedTemporaryFile(suffix=".wav", delete=False) as tmp:
|
| 68 |
+
tmp_path = tmp.name
|
| 69 |
+
|
| 70 |
+
try:
|
| 71 |
+
# ββ Step 1: transcode to clean PCM WAV via ffmpeg ββββββββββββββββββ
|
| 72 |
+
result = subprocess.run(
|
| 73 |
+
[
|
| 74 |
+
"ffmpeg", "-y", # overwrite without prompting
|
| 75 |
+
"-i", str(src), # any browser-upload format
|
| 76 |
+
"-ac", "1", # force mono
|
| 77 |
+
"-ar", "16000", # resample to 16 kHz
|
| 78 |
+
"-sample_fmt", "s16", # 16-bit signed PCM
|
| 79 |
+
"-f", "wav", # output container: wav
|
| 80 |
+
tmp_path,
|
| 81 |
+
],
|
| 82 |
+
stdout=subprocess.DEVNULL,
|
| 83 |
+
stderr=subprocess.PIPE,
|
| 84 |
+
timeout=60,
|
| 85 |
+
)
|
| 86 |
+
if result.returncode != 0:
|
| 87 |
+
err = result.stderr.decode(errors="replace").strip().splitlines()
|
| 88 |
+
raise RuntimeError(
|
| 89 |
+
f"ffmpeg failed (code {result.returncode}): "
|
| 90 |
+
f"{err[-1] if err else 'unknown error'}"
|
| 91 |
+
)
|
| 92 |
+
|
| 93 |
+
# ββ Step 2: read PCM bytes with stdlib `wave` β no soundfile βββββββ
|
| 94 |
+
with wave.open(tmp_path, "rb") as wf:
|
| 95 |
+
n_channels = wf.getnchannels()
|
| 96 |
+
sampwidth = wf.getsampwidth() # bytes per sample: 2 for s16
|
| 97 |
+
framerate = wf.getframerate()
|
| 98 |
+
n_frames = wf.getnframes()
|
| 99 |
+
if n_frames == 0:
|
| 100 |
+
raise ValueError("ffmpeg produced an empty audio file.")
|
| 101 |
+
raw = wf.readframes(n_frames)
|
| 102 |
+
|
| 103 |
+
# Parse raw bytes β float32 in [-1, 1]
|
| 104 |
+
# ffmpeg guarantees s16, but use sampwidth defensively.
|
| 105 |
+
if sampwidth == 2:
|
| 106 |
+
arr = np.frombuffer(raw, dtype=np.int16).astype(np.float32) / 32768.0
|
| 107 |
+
elif sampwidth == 4:
|
| 108 |
+
arr = np.frombuffer(raw, dtype=np.int32).astype(np.float32) / 2147483648.0
|
| 109 |
+
else:
|
| 110 |
+
arr = np.frombuffer(raw, dtype=np.uint8).astype(np.float32) / 128.0 - 1.0
|
| 111 |
+
|
| 112 |
+
# Mix down multi-channel (guard: -ac 1 already handles this)
|
| 113 |
+
if n_channels > 1:
|
| 114 |
+
arr = arr.reshape(-1, n_channels).mean(axis=1)
|
| 115 |
+
|
| 116 |
+
wav = torch.from_numpy(arr.copy()) # copy() avoids non-writable buffer warning
|
| 117 |
+
|
| 118 |
+
# Resample if framerate drifted (guard: -ar 16000 already handles this)
|
| 119 |
+
if framerate != 16000:
|
| 120 |
+
wav = torchaudio.functional.resample(
|
| 121 |
+
wav.unsqueeze(0), framerate, 16000
|
| 122 |
+
).squeeze(0)
|
| 123 |
+
|
| 124 |
+
return wav # 1-D float32 CPU tensor
|
| 125 |
+
|
| 126 |
+
finally:
|
| 127 |
+
try:
|
| 128 |
+
os.unlink(tmp_path)
|
| 129 |
+
except OSError:
|
| 130 |
+
pass
|
| 131 |
|
| 132 |
|
| 133 |
@torch.inference_mode()
|
|
|
|
| 150 |
def run(audio_path: str, num_beams: int, model_choice: str):
|
| 151 |
if audio_path is None:
|
| 152 |
return "β", "β", "β", "β", "Please upload audio."
|
| 153 |
+
|
| 154 |
+
# Load and decode audio β raises ValueError/RuntimeError on bad input.
|
| 155 |
+
try:
|
| 156 |
+
audio = load_audio(audio_path)
|
| 157 |
+
except (ValueError, RuntimeError, subprocess.TimeoutExpired) as exc:
|
| 158 |
+
err_msg = f"β οΈ Audio error: {exc}"
|
| 159 |
+
return err_msg, err_msg, "β", "β", "Audio could not be decoded β try a different file."
|
| 160 |
+
except Exception as exc: # noqa: BLE001
|
| 161 |
+
err_msg = f"β οΈ Unexpected error loading audio: {exc}"
|
| 162 |
+
return err_msg, err_msg, "β", "β", "Audio could not be decoded β try a different file."
|
| 163 |
+
|
| 164 |
+
if audio.numel() == 0:
|
| 165 |
+
return "β", "β", "β", "β", "β οΈ Audio file appears to be empty or silent."
|
| 166 |
+
|
| 167 |
duration = audio.shape[-1] / 16000
|
| 168 |
|
| 169 |
if model_choice == "Baseline only":
|