phantom-grid / llm /audio.py
unity4ar's picture
Ship Phantom Grid Docker Space
d2e6f94 verified
Raw
History Blame Contribute Delete
1.74 kB
from __future__ import annotations
import base64
import wave
from array import array
from pathlib import Path
def wav_to_float32_base64(path: Path, target_rate: int = 16000) -> tuple[str, float]:
"""Return mono float32 PCM expected by the MiniCPM-o Comni APIs.
``audioop`` was removed from the standard library in Python 3.13, so it is
imported lazily here: only the optional MiniCPM-o voice path needs it. The
default text backend never calls this function, keeping the app importable
on modern Python without the ``audioop-lts`` backport installed.
"""
try:
import audioop # stdlib <=3.12; provided by the audioop-lts backport on 3.13+
except ModuleNotFoundError as exc: # pragma: no cover - exercised only on 3.13+ without backport
raise RuntimeError(
"Audio/voice features require the 'audioop' module. On Python 3.13+ "
"install the backport with: pip install audioop-lts"
) from exc
with wave.open(str(path), "rb") as source:
channels = source.getnchannels()
sample_width = source.getsampwidth()
source_rate = source.getframerate()
pcm = source.readframes(source.getnframes())
if channels > 1:
pcm = audioop.tomono(pcm, sample_width, 0.5, 0.5)
if sample_width != 2:
pcm = audioop.lin2lin(pcm, sample_width, 2)
if source_rate != target_rate:
pcm, _ = audioop.ratecv(pcm, 2, 1, source_rate, target_rate, None)
int_samples = array("h")
int_samples.frombytes(pcm)
float_samples = array("f", (sample / 32768.0 for sample in int_samples))
duration = len(float_samples) / target_rate
return base64.b64encode(float_samples.tobytes()).decode("ascii"), duration