import numpy as np from fastapi.testclient import TestClient from app.main import app from app.services.engine_registry import EngineRegistry, get_engine_registry from app.services.supertonic_engine import SynthesisResult class FakeEngine: def supports_voice(self, _: str) -> bool: return True def list_voice_bindings(self) -> list[dict[str, str]]: return [] def synthesize(self, **_: object) -> SynthesisResult: wav = np.zeros((1, 2400), dtype=np.float32) return SynthesisResult(waveform=wav, sample_rate=24000, duration_seconds=0.1) def fake_registry() -> EngineRegistry: engine = FakeEngine() return EngineRegistry( model_to_engine={ "supertonic-2": engine, "tts-1": engine, "tts-1-hd": engine, "gpt-4o-mini-tts": engine, "kitten-tts-micro-0.8": engine, "kitten-tts-micro": engine, "kitten-tts": engine, "kitten": engine, "melo-en": engine, "kokoro": engine, "kokoro-onnx": engine, "kokoro-82m": engine, } ) def test_speech_returns_wav(monkeypatch) -> None: app.dependency_overrides[get_engine_registry] = fake_registry try: with TestClient(app) as client: response = client.post( "/v1/audio/speech", headers={"Authorization": "Bearer changeme"}, json={ "model": "supertonic-2", "input": "hello", "voice": "alloy", "response_format": "wav", }, ) assert response.status_code == 200 assert response.headers["content-type"].startswith("audio/wav") assert len(response.content) > 44 finally: app.dependency_overrides.clear() def test_speech_returns_mp3(monkeypatch) -> None: app.dependency_overrides[get_engine_registry] = fake_registry try: with TestClient(app) as client: response = client.post( "/v1/audio/speech", headers={"Authorization": "Bearer changeme"}, json={ "model": "supertonic-2", "input": "hello", "voice": "alloy", "response_format": "mp3", }, ) assert response.status_code == 200 assert response.headers["content-type"].startswith("audio/mpeg") assert response.content[:3] == b"ID3" or response.content[:2] == b"\xff\xfb" finally: app.dependency_overrides.clear() def test_speech_accepts_quality_and_friendly_voice(monkeypatch) -> None: app.dependency_overrides[get_engine_registry] = fake_registry try: with TestClient(app) as client: response = client.post( "/v1/audio/speech", headers={"Authorization": "Bearer changeme"}, json={ "model": "supertonic-2", "input": "hello", "voice": "atlas", "quality": "high", "response_format": "wav", }, ) assert response.status_code == 200 assert response.headers["content-type"].startswith("audio/wav") finally: app.dependency_overrides.clear() def test_kokoro_model_route(monkeypatch) -> None: app.dependency_overrides[get_engine_registry] = fake_registry try: with TestClient(app) as client: response = client.post( "/v1/audio/speech", headers={"Authorization": "Bearer changeme"}, json={ "model": "kokoro", "input": "hello", "voice": "af_bella", "response_format": "wav", }, ) assert response.status_code == 200 assert response.headers["content-type"].startswith("audio/wav") finally: app.dependency_overrides.clear() def test_kitten_model_route(monkeypatch) -> None: app.dependency_overrides[get_engine_registry] = fake_registry try: with TestClient(app) as client: response = client.post( "/v1/audio/speech", headers={"Authorization": "Bearer changeme"}, json={ "model": "kitten-tts-micro-0.8", "input": "hello", "voice": "bella", "response_format": "wav", }, ) assert response.status_code == 200 assert response.headers["content-type"].startswith("audio/wav") finally: app.dependency_overrides.clear() def test_melo_model_route(monkeypatch) -> None: app.dependency_overrides[get_engine_registry] = fake_registry try: with TestClient(app) as client: response = client.post( "/v1/audio/speech", headers={"Authorization": "Bearer changeme"}, json={ "model": "melo-en", "input": "hello", "voice": "us", "response_format": "wav", }, ) assert response.status_code == 200 assert response.headers["content-type"].startswith("audio/wav") finally: app.dependency_overrides.clear()