docs(frank-tts): the contract table gains its Default voice row
#18 shipped DEFAULT_VOICE and #17 explained why the harness cannot name a voice from a setting, but the endpoint page still described voice resolution as if every request carried a name. One contract row, one paragraph in Naming a voice (a call that names nothing is the harness default shape, not a client bug), the env-file row now lists the default voice among its knobs, and the worklog records the rollout: both merges, the one-dispatch deploy with the 33/33 gate, the card flipping to up on the next checker tick, and the previously failing call returning 430124 bytes with the journal reading "speech voice=narrator1 (default)".
This commit is contained in:
@@ -35,6 +35,7 @@ render needs the app installed, not this endpoint.
|
||||
| Networks | `dankclaw_default` first (it owns the default route and the consumers), then `frank-tts-engine.network` (10.89.5.0/24, the bridge to the engine) |
|
||||
| Voice packs | `/home/dank/voices` mounted read-only at `/voices` — host state, never repo state |
|
||||
| Upstream | `http://frank-tts-engine:8880` (`scripts/frank-tts.env`, `TTS_UPSTREAM`) |
|
||||
| Default voice | `DEFAULT_VOICE` (`scripts/frank-tts.env`) answers a request that names none; the journal marks that line `(default)`, and an **unknown** name is still a 400 |
|
||||
| Rollback | `TTS_BACKEND=llama-tts-cli` runs a CLI binary per request and needs no upstream at all |
|
||||
|
||||
## Naming a voice
|
||||
@@ -42,7 +43,9 @@ render needs the app installed, not this endpoint.
|
||||
A voice **is** a directory name. `voice=narrator1` resolves to
|
||||
`/voices/narrator1/reference.wav`, and that file — not a manifest, not a config
|
||||
entry — is what makes the name real. omp's TTS device may send `voice_id`; the
|
||||
shim accepts either.
|
||||
shim accepts either. A call that sends **neither** — the harness's normal shape,
|
||||
because no harness setting carries a voice for this transport — speaks
|
||||
`$DEFAULT_VOICE`; empty default makes it a 400 again.
|
||||
|
||||
The usable shape is `^[a-z0-9][a-z0-9._-]*$`: lowercase, starting with a letter
|
||||
or digit, then letters, digits, `.`, `_`, `-`, at most 64 characters. No slash,
|
||||
@@ -114,7 +117,7 @@ shows up as a failed synthesis, never as a down probe.
|
||||
| `dankclaw/voiceservice/Containerfile` | python 3.12-alpine pinned by digest + ffmpeg, uid 10000 |
|
||||
| `dankclaw/voiceservice/quadlet/frank-tts.container` | the unit: two networks, `Restart=always`, `HealthCmd`, `[Install]` |
|
||||
| `dankclaw/voiceservice/quadlet/frank-tts-engine.network` | the shared bridge, named after the engine unit and attached by both |
|
||||
| `scripts/frank-tts.env` | backend, upstream, port, limits — paths and numbers, no credentials |
|
||||
| `scripts/frank-tts.env` | backend, upstream, port, limits, and the default voice — paths and numbers, no credentials |
|
||||
| `tests/frank_tts_unit.bats` | the shim against stub engines over real sockets |
|
||||
| `tests/frank_tts_engine.bats` | the pair's wiring: generator output, planner, homepage, deployer |
|
||||
|
||||
|
||||
@@ -2734,3 +2734,23 @@ every restart since the cutover.
|
||||
to Kokoro is one key, not two, and `speech.voice: narrator1` — briefly recorded
|
||||
above as wiring — went back to `am_fenrir`: that key is the vocalizer's Kokoro
|
||||
enum, so a pack name there breaks speak-aloud and does nothing for synthesis.
|
||||
|
||||
## 2026-10-18 — the default voice shipped: a harness voiceover needs no voice
|
||||
|
||||
- Merged **#17** (`b590695`) and **#18** (`7889a68`), then deployed both affected
|
||||
services in one dispatch — `--service frank-tts --service homepage`, 159 s,
|
||||
Playwright gate 33/33. The shim image rebuilt with the new handler; the
|
||||
homepage checker took the card on its next timer tick: `frank-tts → up`,
|
||||
probed for real rather than gated.
|
||||
- The call that had failed is the one that proves the fix. Same device, same
|
||||
restarted session, **no** `voice_id`: `Saved 430124 bytes (model=frank-tts
|
||||
(dankclaw)/frank-tts, voice=default, codec=wav)`. The façade journal says what
|
||||
actually spoke — `speech voice=narrator1 (default) format=wav chars=148 ->
|
||||
430124 bytes` — with the engine's ledger behind it (`audio 8.96 s, RTF 0.551`).
|
||||
The harness prints `voice=default` because it never had a name to print; the
|
||||
voice that answered is the operator's line in `scripts/frank-tts.env`, and the
|
||||
journal keeps them distinguishable forever after.
|
||||
- The page gained a **Default voice** row in its contract table and
|
||||
[[#Naming a voice]] now states that a call naming nothing is the harness's
|
||||
normal shape, not a client bug — the misconception that produced the 400 in
|
||||
the first place.
|
||||
|
||||
Reference in New Issue
Block a user