# services.yaml — canonical catalog of inference services on irv-ml1 # # THIS IS A FIRST-CLASS CONTRACT. External consumers depend on the # shape and contents of this file. See CATALOG-CONTRACT.md alongside # for: schema reference, change-management policy, sync workflow for # downstream consumers, and known consumers list. # # Drives form generators that auto-render UIs against the inference # services. Each entry produces one form (from `fields:`) and one # response renderer (dispatched on `response.type`). The field-type # vocabulary and response-type vocabulary are closed sets — see the # JSON Schema at services.schema.json or the contract doc. # # `catalog_version`: bump when the SCHEMA changes (a field type added, # a required field removed, etc). Per-service `version:` bumps when a # specific service's parameter shape changes. Both let downstream # consumers detect drift. catalog_version: 2 services: - id: kokoro name: Kokoro 82M TTS description: > Lowest-latency English TTS (82M params, fp16). ~300ms TTFA, 35–100x realtime, 60+ built-in voices in 8 languages. Voice mixing via inline weights. OpenAI-compatible /v1/audio/speech. category: tts version: 3 host: irv-ml1 lifecycle: stack: kokoro vram_gb: 2 gpu_device_id: null endpoint: http://10.100.79.3:8193/v1/audio/speech method: POST content_type: application/json model: id: hexgrad/Kokoro-82M revision: null image: ghcr.io/remsky/kokoro-fastapi-gpu:v0.2.4-master fields: - name: input type: textarea label: Text required: true max_length: 5000 - name: voice type: select label: Voice source_url: http://10.100.79.3:8193/v1/audio/voices source_jsonpath: $.voices[*] default: af_heart description: > 60+ built-in voices. Default `af_heart` is the only A-rated voice per upstream VOICES.md (also the kokoro-fastapi container's own default). Custom blends: af_bella(2)+af_aoede(1) syntax for weighted mixing. Persistent custom voices via playbooks/blend-kokoro-voice.yaml. - name: response_format type: select options: [wav, mp3, opus, flac, pcm] default: wav - name: speed type: slider label: Speed required: false min: 0.25 max: 4.0 step: 0.05 default: 1.0 description: Playback speed multiplier. 1.0 is natural. - name: volume_multiplier type: slider label: Volume required: false min: 0.5 max: 2.0 step: 0.05 default: 1.0 description: > Output gain. Useful for level-matching against music beds. Upstream is unbounded; UI bounds (0.5–2.0) are a sensible default — override the slider client-side if you need extremes. - name: lang_code type: text label: Language code required: false description: > Optional language hint (e.g. "a" for American English). When unset, kokoro infers from the first letter of the voice name. Set when text contains code-switching kokoro guesses wrong on. - name: stream type: bool default: false description: Phrase-by-phrase streaming via chunked HTTP. response: type: audio mime_from_field: response_format reproducibility: seedable: false deterministic: true notes: > No seed parameter. Model fully deterministic (no sampling); identical params always produce identical bytes. Image tag is mutable; pin to digest for v3 reproducibility audit. estimated_latency: cold_start_s: 2 warm_per_unit: "~300ms TTFA, 35–100x realtime" license: Apache-2.0 notes: | Voice mixing: voice="name1(w1)+name2(w2)+..." normalizes weights. Custom voices persist at /worktank/kokoro/user_voices (bind-mounted). v2 (2026-05-11): added speed, volume_multiplier, lang_code per kokoro's OpenAPI surface. - id: kokoro-captioned name: Kokoro Captioned Speech description: > Kokoro TTS with word-level timestamps returned alongside the audio. For subtitle generation and video sync. Same model as `kokoro`; separate catalog entry because the wire shape is a JSON envelope carrying base64-encoded audio plus a structured timestamps array. category: tts version: 2 status: ready host: irv-ml1 endpoint: http://10.100.79.3:8193/dev/captioned_speech method: POST content_type: application/json model: id: hexgrad/Kokoro-82M revision: null image: ghcr.io/remsky/kokoro-fastapi-gpu:v0.2.4-master fields: - name: input type: textarea label: Text required: true max_length: 5000 - name: voice type: select label: Voice source_url: http://10.100.79.3:8193/v1/audio/voices source_jsonpath: $.voices[*] default: af_heart - name: response_format type: select options: [wav, mp3, opus, flac, pcm] default: wav - name: speed type: slider label: Speed required: false min: 0.25 max: 4.0 step: 0.05 default: 1.0 - name: lang_code type: text label: Language code required: false response: # Stays in the closed type vocabulary: from a renderer-dispatch # standpoint this IS audio. The audio_field/audio_format_field/ # timestamps_field decomposition tells consumers how to extract # those parts from the JSON envelope wire shape — added to the # catalog schema in 2026-05 specifically to support response # shapes like this one without extending the type vocab. type: audio audio_field: audio audio_format_field: audio_format timestamps_field: timestamps reproducibility: seedable: false deterministic: true notes: > Same determinism story as kokoro proper. Verified wire shape (2026-05-11 against live API): { "audio": "", "audio_format": "audio/wav" (or matching response_format), "timestamps": [{"word": str, "start_time": float, "end_time": float}, ...] } Consumer base64-decodes `audio` to play; `timestamps` drives subtitle/karaoke UI. The response decomposition fields above encode this so the renderer doesn't need per-service-id branches. estimated_latency: cold_start_s: 2 warm_per_unit: "~same as kokoro proper, plus minor overhead for timestamp emission" license: Apache-2.0 notes: | `return_timestamps` and `stream` upstream params deliberately omitted from the catalog: timestamps must be on for this endpoint to be meaningful, and streaming + JSON-with-base64 don't compose. `download_format` / `return_download_link` skipped — same as kokoro proper. status: experimental until the consumer's audio-with-timestamps renderer ships. Once present, flip to status: ready. - id: chatterbox name: Chatterbox TTS description: > Resemble AI's low-latency English TTS (Chatterbox-Turbo, 350M, ~75ms TTFB, 6× realtime). 28 built-in predefined voices + zero-shot cloning from a 5–30s reference. Inline paralinguistic tags. (Resemble's exaggeration / cfg_weight emotion knobs are no-ops on the Turbo checkpoint — omitted.) category: tts version: 2 status: ready host: irv-ml1 lifecycle: stack: chatterbox vram_gb: 4 gpu_device_id: 0 endpoint: http://10.100.79.3:8196/tts method: POST content_type: application/json model: id: ResembleAI/chatterbox-turbo revision: null image: devnen/Chatterbox-TTS-Server:latest section_groups: - id: basic label: Text & voice - id: sampling label: Expression & sampling hint: Turbo honors temperature / seed / speed_factor. (exaggeration / cfg_weight are Turbo no-ops — removed.) - id: advanced label: Advanced fields: - name: text type: textarea label: Text (with optional [tags]) section: basic required: true max_length: 5000 description: > Inline paralinguistic tags honored by Turbo: [laugh] [chuckle] [sigh] [gasp] [cough] [clear throat] [sniff] [groan] [shush]. Best results when a physical tag is paired with surrounding emotional context. - name: voice_mode type: select label: Voice mode section: basic options: [predefined, clone] default: predefined description: > `predefined` -> a built-in voice (predefined_voice_id below). `clone` -> a reference clip (reference_audio_filename). predefined is the out-of-box default; the empty/"undefined" case is avoided by defaulting the voice below. - name: predefined_voice_id type: select label: Voice (built-in) section: basic optional: true default: "Emily.wav" source_url: http://10.100.79.3:8196/get_predefined_voices source_jsonpath: $[*].filename description: > Required when voice_mode=predefined. 28 built-in voices staged in the devnen image (Abigail, Adrian, Alexander, Alice, Austin, Axel, Connor, Cora, Elena, Eli, Emily, Everett, Gabriel, Gianna, Henry, Ian, Jade, Jeremiah, Jordan, Julian, Layla, Leonardo, Michael, Miles, Olivia, Ryan, Taylor, Thomas — each .wav). Default Emily.wav is the server's own default_voice_id. Verified live via /get_predefined_voices. - name: reference_audio_filename type: select label: Voice (clone reference) section: basic optional: true source_url: http://10.100.79.3:8196/get_reference_files source_jsonpath: $[*] description: > Required when voice_mode=clone. 5–30s clean WAV (16 kHz+ mono) under /worktank/chatterbox/reference_audio/; upload via the server's /upload_reference. Match the clip's language to `language` to avoid accent transfer. # exaggeration / cfg_weight intentionally removed: Chatterbox-Turbo IGNORES # both. Proven 2026-06-04 — same text/voice/seed across cfg 0.0/0.5/0.9 gave # byte-identical audio, and the model logs "CFG, min_p and exaggeration are # not supported by Turbo version and will be ignored." They were dead UI # sliders. They'd only do something on a non-turbo Chatterbox checkpoint. - name: temperature type: slider section: sampling min: 0.05 max: 2.0 step: 0.05 default: 0.8 description: Sampling temperature; lower = steadier. Server + Resemble default 0.8. - name: speed_factor type: slider section: sampling min: 0.5 max: 2.0 step: 0.05 default: 1.0 description: Post-hoc playback speed. Server default 1.0. - name: seed type: number section: sampling required: false default: 0 description: 0 = random; a fixed integer repeats the same take. - name: output_format type: select section: basic options: [wav, opus, mp3] default: wav description: 24 kHz. Live-verified enum (wav/opus/mp3). - name: language type: text section: advanced required: false default: en description: > Language override. Base Turbo is English; the multilingual variant (23 languages, via the stack .env) honors other codes. Leave `en`. - name: split_text type: bool section: advanced default: true description: Auto-split long text into chunks. - name: chunk_size type: slider section: advanced min: 100 max: 1000 step: 10 default: 120 description: Target chunk length in chars when splitting (server default 120). response: type: audio mime_from_field: output_format reproducibility: seedable: true deterministic: false seed_field: seed notes: > /tts exposes `seed` (0=random); a fixed seed + identical params repeats a take. Temperature-sampled → not guaranteed byte-exact, and Resemble's PerTh watermark is applied unconditionally. (Prior catalog claimed no seed support — corrected against the live OpenAPI 2026-06-01.) estimated_latency: cold_start_s: 3 warm_per_unit: "~75ms TTFB, 6× realtime" license: MIT notes: | Routes to the devnen wrapper's /tts (control surface: temperature / speed_factor / seed / voice_mode) rather than the thin OpenAI /v1/audio/speech. exaggeration / cfg_weight were DROPPED 2026-06-04 — the Turbo checkpoint ignores them (proven byte-identical across cfg values; the model warns they're "not supported by Turbo version and will be ignored"), so they were dead UI sliders. Same wrapper author as the `dia` stack; identical predefined/clone voice model. Defaults from the server's generation_defaults (temperature 0.8, speed 1.0, seed 0), read live 2026-06-01. Python 3.10 only (wrapper hardcoding); multilingual (23-language) variant available via the stack .env. - id: chatterbox-fast name: Chatterbox Fast (streaming) description: > Custom streaming front-end for Chatterbox-Turbo: an adaptive buffer-ratchet chunker emits the first sentence immediately (~0.5s time-to-first-audio vs ~5s one-shot), then ratchets chunk size up on the model's realtime headroom. Single-stream interactive. Same Turbo voice + inline paralinguistic tags as `chatterbox`; the win is sub-second start for streaming consumers. category: tts version: 1 status: ready host: irv-ml1 lifecycle: stack: chatterbox-fast vram_gb: 6 gpu_device_id: 1 endpoint: http://10.100.79.3:8197/tts method: POST content_type: application/json streamable: true model: id: ResembleAI/chatterbox-turbo revision: null image: local/chatterbox-fast:v1 section_groups: - id: basic label: Text & voice - id: sampling label: Sampling fields: - name: text type: textarea label: Text (with optional [tags]) section: basic required: true max_length: 5000 description: > Inline paralinguistic tags honored by Turbo ([laugh] [whispers] [sigh] etc.). Adaptive-chunking splits on sentence boundaries; a very long comma-less sentence may show a faint join seam. - name: voice type: select label: Voice section: basic default: glados_25s source_url: http://10.100.79.3:8197/voices source_jsonpath: $.voices[*] description: > Predefined voice (a *.wav stem under /worktank/chatterbox/reference_audio, shared with the chatterbox stack). Live-enumerated via /voices. Clone references are passable as an absolute path via the API (not listed here). - name: temperature type: slider section: sampling min: 0.05 max: 2.0 step: 0.05 default: 0.8 description: Sampling temperature; lower = steadier. Turbo default 0.8. - name: top_p type: slider section: sampling min: 0.0 max: 1.0 step: 0.05 default: 0.95 description: Nucleus sampling cutoff. Spike-validated default 0.95. - name: top_k type: number section: sampling required: false default: 1000 description: Top-k sampling cutoff. Spike-validated default 1000. - name: repetition_penalty type: slider section: sampling min: 1.0 max: 2.0 step: 0.05 default: 1.2 description: Penalize token repetition. Spike-validated default 1.2. - name: seed type: number section: sampling required: false default: 0 description: > 0 = random. A fixed seed repeats a one-shot take (verified byte-exact). Streaming output is NOT reproducible — adaptive-chunk boundaries depend on the live-measured realtime factor. - name: format type: select section: basic options: [pcm, wav] default: pcm description: > pcm = raw s16le @ 24 kHz (lowest latency, for API consumers); wav adds a header. The streaming-audition UI forces wav for the browser