| 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() |
|
|