3.6 KiB
3.6 KiB
name, description
| name | description |
|---|---|
| tts-endpoint-parameter-capability-audit | Determine which request parameters a fleet TTS endpoint actually honors by probing façade and engine separately, with a nondeterminism control, instead of trusting docs or byte diffs. |
Use when asked whether a TTS (or other OpenAI-compatible shim) endpoint supports a parameter — mood, tone, instructions, speed, seed — or when a request "seems to" change the audio. Docs and single-request comparisons both lie; audit the layers.
Why the naive checks fail
- Byte-size diffs are meaningless. Synthesis is nondeterministic: three byte-identical requests to frank-tts came back 107564 / 134444 / 111404 bytes (~±15 % length). "The mood file differs from the baseline" proves nothing.
- HTTP 200 proves nothing. A shim that rebuilds its own payload answers 200 to
speed:"banana"because it never looks at the field. - A façade can drop fields the engine supports, so testing only the published port under-reports capability.
Procedure
- Read the shim's parse block (which request keys it reads) — not its docstring:
ssh -o BatchMode=yes dankclaw 'podman exec frank-tts grep -nE "body\.get|payload = |json\.loads" /app/app.py'Whatever keys appear there (plus what it forwards in its ownpayload = {...}dict) is the real published contract. - Enumerate the engine's key table from the binary (works with no
stringsin the image):podman exec <engine> sh -c 'grep -aoE ".{60}instructions.{60}" /app/tts-server | head -2'Adjacent tokens come out as a run — that run IS the accepted-key list (...instructions response_formatspeedseedmax_new_tokensrepetition_penalty subtalker_top_k subtalker_temperature ...). Alsopodman exec <engine> /app/tts-server --help, andpodman inspect <c> --format "{{json .Config.Entrypoint}}"to find the binary. - Reach the engine directly when its port is unpublished:
TTS_UPSTREAMinpodman inspect <shim>gives the real in-network address (http://frank-tts-engine:8880, nothost.containers.internal). No curl/python on the host? Pipe a script into the container that has one:podman exec -i frank-tts python3 - <<'PY' ... PY. - Control for nondeterminism before claiming an effect: repeat the identical request twice as the control; only compare conditions separated by far more than the jitter, and prefer an error response (a 400 naming the unsupported flag) as the decisive evidence.
Findings for the dank fleet (verify before trusting — they move)
- Published façade
:7772reads onlymodel,input,voice/voice_id,response_format; it rebuilds the payload, sospeedand every unknown field are dropped before the engine. - Engine (
frank-tts-engine, qwentts.cpp, qwen-talker-1.7b-base, Vulkan) acceptsinstructions,speed,seed,max_new_tokens,repetition_penalty,subtalker_top_k/_temperature/_top_p, but answers400 "--instruct is not supported for base models"forinstructionson the base checkpoint.seeddoes not make output reproducible. - Therefore tone/mood must be produced in the text layer (prompt directives), not the TTS request; and
speedneeds a two-line façade fix if tempo control is ever wanted.
Verification habits
- POST with a wrong type (
speed:"banana") to learn whether anything validates, and with a bogusvoiceto see the error shape (available_voicescame from the engine, not the shim). - Plain GET of
/v1/audio/voicesfor the roster. - Read-only probes of the fleet are always allowed; synthesis requests are transient GPU work, keep them to a handful.