Merge remote-tracking branch 'origin/feat/moss-tts-nano-isolated' into feat/cosyvoice3-isolated

This commit is contained in:
Palash Debnath
2026-09-10 09:46:02 -07:00
7 changed files with 65 additions and 7 deletions
+16 -2
View File
@@ -142,6 +142,20 @@ def _sample_rate(model) -> int:
return VOXCPM2_SAMPLE_RATE
def _at_engine_rate(wav, sample_rate: int):
"""The waveform at VOXCPM2_SAMPLE_RATE. The parent reads the PCM at that
fixed rate (it trims the tail and labels the audio with it), so a model
reporting another rate is resampled here rather than mislabelled."""
if sample_rate == VOXCPM2_SAMPLE_RATE:
return wav
import torch # noqa: PLC0415
import torchaudio # noqa: PLC0415
tensor = torch.as_tensor(wav.detach().cpu() if hasattr(wav, "detach") else wav,
dtype=torch.float32).reshape(-1)
return torchaudio.functional.resample(tensor, sample_rate, VOXCPM2_SAMPLE_RATE)
def _to_pcm_b64(wav) -> tuple[str, int]:
"""A float waveform in [-1, 1] (numpy or torch) as base64 int16 PCM."""
import numpy as np # noqa: PLC0415
@@ -189,11 +203,11 @@ def _handle_synthesize(msg: dict, stdout) -> None:
prompt_wav_path=ref_audio if ref_text else None,
prompt_text=ref_text,
)
pcm_b64, n_samples = _to_pcm_b64(wav)
pcm_b64, n_samples = _to_pcm_b64(_at_engine_rate(wav, _sample_rate(model)))
_send(stdout, {
"op": "audio",
"audio_pcm_b64": pcm_b64,
"sample_rate": _sample_rate(model),
"sample_rate": VOXCPM2_SAMPLE_RATE,
"n_samples": n_samples,
})
+8 -1
View File
@@ -648,7 +648,14 @@ def engine_venv_python(env_var: str) -> Optional[Path]:
if not env_dir:
return None
py = _venv_python(Path(env_dir) / ".venv")
return py if py.is_file() else None
# The interpreter alone proves nothing: a reinstall that failed partway
# leaves it behind. The completion marker is written only after the
# engine's import probe passed in this venv, and removed when a new
# dependency step starts, so it is the probe's verdict without running a
# multi-second import on every engine-list refresh.
if not py.is_file() or not (Path(env_dir) / _INSTALL_COMPLETE_MARKER).is_file():
return None
return py
def _legacy_managed_checkouts(spec: SidecarSpec) -> tuple[Path, ...]:
+2 -1
View File
@@ -120,7 +120,7 @@ def test_the_sidecar_imports_nothing_from_the_app():
def test_the_class_switches_to_the_sidecar_once_its_venv_exists(monkeypatch, tmp_path):
from engines.moss_tts_nano_subprocess import MossTTSNanoSubprocessBackend
from services import tts_backend
from services.sidecar_install import _venv_python
from services.sidecar_install import _INSTALL_COMPLETE_MARKER, _venv_python
monkeypatch.setenv("OMNIVOICE_MOSS_TTS_NANO_DIR", "")
monkeypatch.delenv("OMNIVOICE_MOSS_TTS_NANO_DIR")
@@ -129,6 +129,7 @@ def test_the_class_switches_to_the_sidecar_once_its_venv_exists(monkeypatch, tmp
py = _venv_python(tmp_path / ".venv")
py.parent.mkdir(parents=True)
py.write_text("#!fake\n")
(tmp_path / _INSTALL_COMPLETE_MARKER).write_text("x\n", encoding="utf-8")
monkeypatch.setenv("OMNIVOICE_MOSS_TTS_NANO_DIR", str(tmp_path))
cls = tts_backend.get_backend_class("moss-tts-nano")
+2 -1
View File
@@ -289,7 +289,7 @@ def test_prefers_the_venv_its_one_click_install_made(monkeypatch, tmp_path, mock
interpreter, where `uv sync --extra pockettts` installs it."""
from pathlib import Path
from services.sidecar_install import _venv_python
from services.sidecar_install import _INSTALL_COMPLETE_MARKER, _venv_python
mock_settings_store["pockettts"] = True
monkeypatch.delenv("OMNIVOICE_POCKETTTS_DIR", raising=False)
@@ -298,6 +298,7 @@ def test_prefers_the_venv_its_one_click_install_made(monkeypatch, tmp_path, mock
py = _venv_python(tmp_path / ".venv")
py.parent.mkdir(parents=True)
py.write_text("#!fake\n")
(tmp_path / _INSTALL_COMPLETE_MARKER).write_text("x\n", encoding="utf-8")
monkeypatch.setenv("OMNIVOICE_POCKETTTS_DIR", str(tmp_path))
assert _backend_cls().venv_python() == py
# Available without pocket_tts importable in the app's own environment.
+3
View File
@@ -1221,6 +1221,9 @@ def test_engine_venv_python_needs_a_real_interpreter(monkeypatch, tmp_path):
py = si._venv_python(tmp_path / ".venv")
py.parent.mkdir(parents=True)
py.write_text("#!fake\n")
# An interpreter without the marker is a failed or unfinished install.
assert si.engine_venv_python("OMNIVOICE_FAKE_SIDE_DIR") is None
(tmp_path / si._INSTALL_COMPLETE_MARKER).write_text("x\n", encoding="utf-8")
assert si.engine_venv_python("OMNIVOICE_FAKE_SIDE_DIR") == py
+2 -1
View File
@@ -389,7 +389,7 @@ def test_prefers_the_venv_its_one_click_install_made(monkeypatch, tmp_path, mock
from pathlib import Path
from engines.supertonic3.backend import Supertonic3Backend
from services.sidecar_install import _venv_python
from services.sidecar_install import _INSTALL_COMPLETE_MARKER, _venv_python
mock_settings_store["supertonic3"] = True
monkeypatch.delenv("OMNIVOICE_SUPERTONIC3_DIR", raising=False)
@@ -398,6 +398,7 @@ def test_prefers_the_venv_its_one_click_install_made(monkeypatch, tmp_path, mock
py = _venv_python(tmp_path / ".venv")
py.parent.mkdir(parents=True)
py.write_text("#!fake\n")
(tmp_path / _INSTALL_COMPLETE_MARKER).write_text("x\n", encoding="utf-8")
monkeypatch.setenv("OMNIVOICE_SUPERTONIC3_DIR", str(tmp_path))
assert Supertonic3Backend.venv_python() == py
# Available without supertonic importable in the app's own environment.
+32 -1
View File
@@ -129,11 +129,15 @@ def test_retries_a_transient_download_failure_only(monkeypatch):
assert sidecar._with_retries(flaky) == "model"
assert len(attempts) == 3
broken_calls = []
def broken():
broken_calls.append(1)
raise ValueError("bad config")
with pytest.raises(ValueError):
sidecar._with_retries(broken)
assert len(broken_calls) == 1 # a permanent error is not retried
def test_the_sidecar_imports_nothing_from_the_app():
@@ -145,7 +149,7 @@ def test_the_sidecar_imports_nothing_from_the_app():
def test_the_class_switches_to_the_sidecar_once_its_venv_exists(monkeypatch, tmp_path):
from engines.voxcpm2_subprocess import VoxCPM2SubprocessBackend
from services import tts_backend
from services.sidecar_install import _venv_python
from services.sidecar_install import _INSTALL_COMPLETE_MARKER, _venv_python
monkeypatch.setenv("OMNIVOICE_VOXCPM2_DIR", "")
monkeypatch.delenv("OMNIVOICE_VOXCPM2_DIR")
@@ -154,6 +158,7 @@ def test_the_class_switches_to_the_sidecar_once_its_venv_exists(monkeypatch, tmp
py = _venv_python(tmp_path / ".venv")
py.parent.mkdir(parents=True)
py.write_text("#!fake\n")
(tmp_path / _INSTALL_COMPLETE_MARKER).write_text("x\n", encoding="utf-8")
monkeypatch.setenv("OMNIVOICE_VOXCPM2_DIR", str(tmp_path))
cls = tts_backend.get_backend_class("voxcpm2")
@@ -197,3 +202,29 @@ def test_the_sidecar_class_prepares_the_reference_and_trims_the_tail(monkeypatch
assert sent["ref_audio"] == "/clip.wav.prepared.wav"
assert trimmed["sr"] == 48000
assert tuple(out.shape) == (1, 10)
def test_output_is_resampled_to_the_48_khz_the_parent_assumes(monkeypatch):
"""The parent trims and labels the PCM at a fixed 48 kHz, so a model that
reports another rate must be resampled, not passed through."""
sidecar = _load_sidecar(monkeypatch, [])
sidecar._handle_synthesize({"text": "warm up"}, io.BytesIO())
type(sidecar._MODEL).sample_rate = 24000
out = io.BytesIO()
sidecar._handle_synthesize({"text": "hi"}, out)
audio = _frames(out)[-1]
assert audio["sample_rate"] == 48000
assert audio["n_samples"] == 960 # 480 samples at 24 kHz
def test_a_failed_install_leaves_voxcpm2_in_process(monkeypatch, tmp_path):
"""A venv interpreter without the completion marker (a reinstall that
failed partway) must not hide the working in-process engine."""
from services import tts_backend
from services.sidecar_install import _venv_python
py = _venv_python(tmp_path / ".venv")
py.parent.mkdir(parents=True)
py.write_text("#!fake\n")
monkeypatch.setenv("OMNIVOICE_VOXCPM2_DIR", str(tmp_path))
assert tts_backend.get_backend_class("voxcpm2") is tts_backend.VoxCPM2Backend