nika:tts_generate is the image pipeline’s sibling for audio: one file
lands under a permit-gated output_dir:, sha256-named, manifest beside it,
and audio bytes never ride workflow outputs — tasks pass a path and a
hash, not megabytes of base64.
The four providers
| provider | default model | default voice | what to know |
|---|---|---|---|
local | tts-1 | alloy | The sovereign path: any OpenAI-speech-compatible server — LocalAI (:8080, also ElevenLabs-compatible upstream), Kokoro-FastAPI, Speaches, openedai-speech. One wire: POST {base}/v1/audio/speech → raw bytes. Never inferred from model:. |
openai | gpt-4o-mini-tts | alloy | Sync, seconds-class. speed: 0.25–4.0 native. |
elevenlabs | eleven_multilingual_v2 | Rachel’s id | voice: is a voice id (find them in your voice library) — ids ride the URL path, so the engine restricts them to the id alphabet. speed: is warned-dropped. |
mock | mock-tts-1 | sine | A real, playable, deterministic 16 kHz WAV — zero network, zero keys. CI runs the pipeline offline. |
OPENAI_API_KEY / ELEVENLABS_API_KEY (or NIKA_-prefixed),
NIKA_TTS_LOCAL_URL (+ optional NIKA_TTS_LOCAL_API_KEY). nika doctor
prints a tts line naming what’s wired.
Quickstart
nika: v1
Honesty rules
- The extension follows the bytes. WAV
RIFF…WAVEand MP3 headers are sniffed; a mislabel is aformat_mismatch:warning, a non-audio payload is a hard error — never a corrupt file on disk. - Duration is exact or absent. WAV
duration_msis pure header math; MP3 duration is honestlynullrather than a frame-walking guess. text:caps at 4096 chars (the strictest wire’s limit, held portably) — fan longer scripts out withfor_eachover paragraphs.- Content credentials are detected, not verified: audio C2PA carriage
(RIFF
C2PA· MP3 GEOB) is surfaced ascontent_credentialsin output and manifest, the same contract as images. - Watermarking is declared, never byte-verified. The manifest’s
watermark_declaredis a catalog fact:elevenlabs→"synthid (provider-declared · not byte-verified)", every other provider →null— no such declaration, honestly absent.
Cookbook (proven against live APIs)
An LLM writes the script, another model speaks it — one run:nika: v1
Local CPU synthesis gets a 300s default timeout (
timeout_ms: up to
600000); clouds default to 120s. Sub-second values are refused — under 1s
is a typo’d unit.