Spaces:
Running
Running
deploy: audiobook subsystem + encode int16 fix + R2 page fast-path + costs breakdown + query-run flow
1e55b98 verified | """Audio encoding helper: float/int PCM waveform β compact streamable bytes. | |
| A provider that renders raw audio (MMS β 16 kHz float waveform) calls | |
| :func:`encode_waveform` to get ``(audio_bytes, mime)`` ready to store + serve. | |
| The pipeline never special-cases a codec β it just stores the bytes + mime. | |
| Preferred output is **Opus in an Ogg container** (``audio/ogg``) β ~24-32 kbps | |
| mono speech β 3-4 KB/s, matching the contract's "keep clips small" note and the | |
| FE's ``Accept: audio/ogg`` preference. If the libsndfile build lacks the Opus | |
| subtype we fall back to Ogg/Vorbis (still ``audio/ogg``). A plain-WAV fallback | |
| exists only as a last resort so a render is never lost to an encoder gap. | |
| Opus mandates a 48 kHz sample rate; libsndfile resamples on write, but we also | |
| pre-handle the rate so duration math stays exact regardless of subtype. | |
| """ | |
| from __future__ import annotations | |
| import io | |
| from functools import lru_cache | |
| # Opus only accepts these container sample rates; 48000 is the canonical one. | |
| _OPUS_RATE = 48000 | |
| def _ogg_subtype() -> str | None: | |
| """Best Ogg subtype this libsndfile supports: 'OPUS' > 'VORBIS' > None.""" | |
| try: | |
| import soundfile as sf | |
| subs = sf.available_subtypes("OGG") | |
| if "OPUS" in subs: | |
| return "OPUS" | |
| if "VORBIS" in subs: | |
| return "VORBIS" | |
| except Exception: # noqa: BLE001 | |
| return None | |
| return None | |
| def duration_ms_for(num_frames: int, sample_rate: int) -> int: | |
| """Clip length in ms from frame count + sample rate (pre-encode, exact).""" | |
| if sample_rate <= 0: | |
| return 0 | |
| return int(round(num_frames * 1000.0 / sample_rate)) | |
| def encode_waveform(samples, sample_rate: int) -> tuple[bytes, str, int]: | |
| """Encode a 1-D PCM waveform to compact bytes. | |
| ``samples`` is a 1-D numpy float array (mono, typically in [-1, 1]) or any | |
| array soundfile accepts. Returns ``(audio_bytes, mime, duration_ms)``. | |
| Tries Opus/Ogg, then Vorbis/Ogg (both ``audio/ogg``), then WAV | |
| (``audio/wav`` β last resort so a clip is never lost). | |
| """ | |
| import numpy as np | |
| import soundfile as sf | |
| # Accept either a float waveform already in [-1, 1] (MMS) OR integer PCM | |
| # (Gemini / Google-Cloud TTS return 16-bit PCM). Integer input MUST be | |
| # normalized to float: casting int16 straight to float leaves values at | |
| # Β±32768, which soundfile then clips to full-scale garbage β the "random | |
| # noise instead of speech" failure. Float input passes through untouched. | |
| arr = np.asarray(samples) | |
| if np.issubdtype(arr.dtype, np.integer): | |
| info = np.iinfo(arr.dtype) | |
| max_mag = float(max(abs(int(info.min)), int(info.max))) | |
| arr = (arr.astype("float32") / max_mag).reshape(-1) | |
| else: | |
| arr = arr.astype("float32").reshape(-1) | |
| duration_ms = duration_ms_for(arr.shape[0], sample_rate) | |
| subtype = _ogg_subtype() | |
| if subtype is not None: | |
| buf = io.BytesIO() | |
| try: | |
| # libsndfile writes Opus at 48 kHz; passing the true input rate lets | |
| # it resample correctly. Vorbis accepts the native rate directly. | |
| sf.write(buf, arr, sample_rate, format="OGG", subtype=subtype) | |
| return buf.getvalue(), "audio/ogg", duration_ms | |
| except Exception: # noqa: BLE001 β fall through to WAV | |
| pass | |
| # Last-resort uncompressed fallback (still playable by the FE <audio>). | |
| buf = io.BytesIO() | |
| sf.write(buf, arr, sample_rate, format="WAV", subtype="PCM_16") | |
| return buf.getvalue(), "audio/wav", duration_ms | |
| def ext_for_mime(mime: str) -> str: | |
| """File extension for a clip mime β used to build the storage key.""" | |
| return { | |
| "audio/ogg": "ogg", | |
| "audio/mpeg": "mp3", | |
| "audio/wav": "wav", | |
| }.get(mime, "bin") | |