feat(tts): map ratatoskr:sindra -> miranda voice
Sindra now voices with the dots "miranda" voice (operator-directed); donut stays on "donut", other agents fall to the "glados" default. One entry in _TTS_VOICE_MAP + a test; contract DEC-8 updated. Live-verified on :8765 (/api/tts with agent_id=ratatoskr:sindra -> 200 audio/wav @ 48kHz).
This commit is contained in:
@@ -174,7 +174,8 @@ each independently shippable. Slice order is chosen for fastest visible result.
|
||||
dots clones a voice server-side from a reference clip + transcript; the client just
|
||||
passes a voice NAME (GET /v1/voices lists them: donut/glados/emmie/miranda). The
|
||||
`donut` voice carries over from chatterbox, so `_TTS_VOICE_MAP` maps
|
||||
`ratatoskr:donut → "donut"` unchanged. NOTE the case: lowercase `"donut"` (Zonos used
|
||||
`ratatoskr:donut → "donut"`; `ratatoskr:sindra → "miranda"` (operator-directed
|
||||
2026-08-10). NOTE the case: lowercase `"donut"` (Zonos used
|
||||
`"Donut"`). Non-interview agents fall to the dots default `"glados"` (was chatterbox
|
||||
`"glados_25s"` / Zonos `"Cora"`, neither of which exists on dots). New voices are a
|
||||
one-line request to infra-ops (derived from the canonical voice corpus).
|
||||
|
||||
@@ -545,7 +545,7 @@ async def _memory_chunks_endpoint(request: Request) -> JSONResponse:
|
||||
# Per-character voice map (DEC-8): interview characters resolve to their registered
|
||||
# dots voice name (GET /v1/voices lists them); everything else falls to the gateway default.
|
||||
# NOTE the case: dots wants lowercase "donut" (Zonos used "Donut").
|
||||
_TTS_VOICE_MAP = {"ratatoskr:donut": "donut"}
|
||||
_TTS_VOICE_MAP = {"ratatoskr:donut": "donut", "ratatoskr:sindra": "miranda"}
|
||||
_TTS_DEFAULT_VOICE = "glados" # a dots voice (chatterbox "glados_25s" / Zonos "Cora" do not exist here)
|
||||
# The text rides the POST body (DEC-10a), so URL length is not the bound — this is a safety
|
||||
# ceiling on the shared-GPU hold. dots streams a whole turn from one call (no client concat),
|
||||
|
||||
@@ -1505,6 +1505,21 @@ class TestTtsEndpoint:
|
||||
body = json.loads(route.calls.last.request.content)
|
||||
assert body["voice"] == "glados" # dots default voice (DEC-8)
|
||||
|
||||
@respx.mock
|
||||
def test_sindra_resolves_miranda_voice(self) -> None:
|
||||
from ratatoskr.web.server import create_app
|
||||
|
||||
route = respx.post(self._TTS).mock(
|
||||
return_value=httpx.Response(200, content=self._WAV)
|
||||
)
|
||||
app = create_app(_mock_client_factory(), tts_url=self._TTS)
|
||||
resp = TestClient(app).post(
|
||||
"/api/tts", json={"text": "Hello there.", "agent_id": "ratatoskr:sindra"}
|
||||
)
|
||||
assert resp.status_code == 200
|
||||
body = json.loads(route.calls.last.request.content)
|
||||
assert body["voice"] == "miranda" # per-character map (DEC-8)
|
||||
|
||||
def test_missing_text_returns_400(self) -> None:
|
||||
from ratatoskr.web.server import create_app
|
||||
|
||||
|
||||
Reference in New Issue
Block a user