# 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: 1 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 Turbo TTS description: > Resemble AI's low-latency English TTS (350M, ~75ms TTFB, 6× realtime). Zero-shot voice cloning from ~5s reference. 9 paralinguistic tags. category: tts version: 1 status: down host: irv-ml1 lifecycle: stack: chatterbox vram_gb: 4 gpu_device_id: 0 endpoint: http://10.100.79.3:8196/v1/audio/speech method: POST content_type: application/json model: id: ResembleAI/chatterbox-turbo revision: null image: devnen/Chatterbox-TTS-Server:latest fields: - name: input type: textarea label: Text (with optional [tags]) required: true max_length: 5000 description: > Inline tags: [laugh] [chuckle] [sigh] [gasp] [cough] [clear throat] [sniff] [groan] [shush]. Turbo loses base-Chatterbox's exaggeration knob. - name: model type: select options: [chatterbox-turbo] default: chatterbox-turbo - name: voice type: select label: Voice default: alloy description: > Built-in OpenAI-compat aliases (alloy, echo, fable, onyx, nova, shimmer). Cloned: 5–15s WAV files in /worktank/chatterbox/reference_audio/. - name: response_format type: select options: [wav, opus, aac, flac, pcm_s16] default: wav - name: stream type: bool default: false response: type: audio mime_from_field: response_format reproducibility: seedable: false deterministic: true notes: > No seed. Wrapper repo updates ~weekly; pin SHA in .env. PerTh watermark unconditionally applied (Resemble policy). estimated_latency: cold_start_s: 3 warm_per_unit: "~75ms TTFB, 6× realtime" license: MIT notes: | Python 3.10 only (wrapper hardcoding). Multilingual variant (23 languages) also available via .env. - id: index-tts name: IndexTTS-2 description: > Bilibili's emotion-controllable zero-shot TTS. Disentangled emotion control (timbre from one reference, emotion from another). 22050 Hz fixed output. category: tts version: 1 status: down host: irv-ml1 lifecycle: stack: index-tts vram_gb: 6 gpu_device_id: null endpoint: http://10.100.79.3:8192/v1/audio/speech method: POST content_type: application/json model: id: IndexTeam/IndexTTS-2 revision: null image: local/index-tts:v2 fields: - name: input type: textarea label: Text required: true max_length: 5000 - name: voice type: select label: Speaker Voice description: .wav in /worktank/index-tts/voices/. 5–30s clean clips. - name: response_format type: select options: [wav] default: wav description: 22050 Hz PCM_16 mono only; no negotiation. - name: stream type: bool default: false description: > Segment-level streaming (~120 tokens). Streaming WAV uses placeholder data-length (0xFFFFFFFF); browsers fine, strict parsers may complain. - name: emotion_voice type: select label: Emotion Reference Voice optional: true description: .wav in /worktank/index-tts/emotions/. - name: emotion_vector type: json label: Emotion Vector optional: true description: > 8 floats [happy, angry, sad, afraid, disgusted, melancholic, surprised, calm], each 0.0–1.0. - name: emotion_text type: textarea label: Emotion Description (free text) optional: true - name: emotion_alpha type: slider min: 0.0 max: 1.0 default: 1.0 label: Emotion Strength response: type: audio mime: audio/wav reproducibility: seedable: false deterministic: true notes: > No seed. 22050 Hz hardcoded — resample in caller if 24/48 kHz needed. Precedence if multiple emotion sources: emotion_voice > vector > text. estimated_latency: cold_start_s: 5 warm_per_unit: "segment-latency streaming" license: "Custom Bilibili (free at small scale; commercial tier 100M MAU)" notes: | Three-way mutual-exclusion among emotion_voice / emotion_vector / emotion_text; precedence as above. UI should expose this as a single picker. - id: qwen3-tts name: Qwen3-TTS 1.7B description: > Alibaba's open English-first TTS (Apache 2.0). 10 languages, 97ms TTFB, instruction-driven emotion, voice cloning. category: tts version: 1 status: down host: irv-ml1 lifecycle: stack: qwen3-tts vram_gb: 16 gpu_device_id: null endpoint: http://10.100.79.3:8191/v1/audio/speech method: POST content_type: application/json model: id: Qwen/Qwen3-TTS-12Hz-1.7B revision: null image: local/qwen3-tts:v2 fields: - name: model type: select options: [Qwen/Qwen3-TTS-12Hz-1.7B, Qwen/Qwen3-TTS-12Hz-0.6B-Base] default: Qwen/Qwen3-TTS-12Hz-1.7B - name: input type: textarea label: Text required: true max_length: 5000 - name: voice type: select label: Voice description: > Built-in or cloned. For cloning: clone: where is a profile dir under /worktank/qwen3-tts/voices/profiles/. Create via /voice-studio web UI or manually (meta.json + reference.wav). - name: instructions type: textarea label: Emotion/Style Instructions optional: true description: > Natural-language directive (e.g. "speak with cold contempt"). English instructions verified working ~2026-04. - name: response_format type: select options: [wav, mp3, pcm] default: wav response: type: audio mime_from_field: response_format reproducibility: seedable: false deterministic: true estimated_latency: cold_start_s: 5 warm_per_unit: "~97ms TTFB" license: Apache-2.0 notes: | Voice cloning shape differs from CosyVoice: profile-based, not voice-id-based. - id: cosyvoice name: CosyVoice 3 (Multilingual) description: > FunAudioLLM's multilingual expressive TTS. 18+ Chinese dialects + 8 other langs. English prosody not ElevenLabs-grade — use Qwen3-TTS for English. category: tts version: 1 status: down host: irv-ml1 lifecycle: stack: cosyvoice vram_gb: 4 gpu_device_id: null endpoint: http://10.100.79.3:8190/v1/audio/speech method: POST content_type: application/json model: id: FunAudioLLM/Fun-CosyVoice3-0.5B-2512 revision: null image: neosun/cosyvoice:v1.3.2 fields: - name: model type: select options: [cosyvoice-v3, cosyvoice-v2] default: cosyvoice-v3 - name: input type: textarea label: Text (with optional XML emotion tags) required: true max_length: 5000 description: > For English: use XML tags , , , , , etc. NOT the instruct field — English instruct values get vocalized literally (upstream bug). - name: voice type: select label: Voice (cloned only — no presets) description: > Create via POST /v1/voices/create (multipart with reference audio ≤30s). Reference must be 16kHz mono ≤30s; longer = AssertionError. - name: response_format type: select options: [wav] default: wav - name: speed type: slider min: 0.5 max: 2.0 default: 1.0 response: type: audio mime: audio/wav reproducibility: seedable: false deterministic: true notes: > Reference audio MUST be ≤30s (16kHz mono). instruct field broken for English. estimated_latency: cold_start_s: 5 warm_per_unit: "~150ms TTFB streaming" license: Apache-2.0 notes: | GOTCHA: instruct field is Chinese-context only — UI should hide it for English or surface a strong warning. - id: fish-s2 name: Fish Audio S2-Pro description: > Fishaudio's richest-paralinguistic English TTS (15,000+ inline tags). Trained 10M+ hours, dual-AR, ~150ms streaming TTFB. Released March 2026. category: tts version: 1 host: irv-ml1 lifecycle: stack: fish-s2 vram_gb: 4 gpu_device_id: 1 endpoint: http://10.100.79.3:8195/v1/tts method: POST content_type: application/json model: id: fishaudio/s2-pro revision: null image: local/fish-s2:v1 fields: - name: text type: textarea label: Text (with optional [tags]) required: true max_length: 5000 description: > Inline tags: [laugh] [whispers] [super happy] [sigh] [excited] [heavy breathing] [angry] [sleepy] [crying] [surprise] ... (15,000+). Upstream best-practice: physical tags like [whispers] feel flat without emotional context — pair with an emotion tag. Example: `[excited] Welcome back! [whisper] I have a secret. [laugh] Just kidding.` - name: references type: json label: Voice References optional: true description: > Array of {audio: "/app/references/.wav", text: "transcript"}. Files under /worktank/fish-s2/references/ on host. response: type: audio mime: audio/wav reproducibility: seedable: false deterministic: true estimated_latency: cold_start_s: 8 warm_per_unit: "~150ms TTFB" license: "Research-only (Fishaudio terms; non-commercial)" license_warning: | Research/internal only. Not clear for commercial use. Same flag as Voxtral and SAO — UI must surface when output destined for products. notes: | NOT OpenAI-compatible: only /v1/tts. No /v1/audio/voices, no /v1/models. Voice discovery is manual (host filesystem). - id: kyutai-tts name: Kyutai TTS 1.6B EN/FR description: > Kyutai's bilingual streaming TTS (1.6B, 2.5M hours). Heritage from Mimi codec + Moshi dialogue framework. OpenAI-compat HTTP wrapper over Rust streaming core. category: tts version: 1 status: down host: irv-ml1 lifecycle: stack: kyutai-tts vram_gb: 6 gpu_device_id: 0 endpoint: http://10.100.79.3:8198/v1/audio/speech method: POST content_type: application/json model: id: kyutai/tts-1.6b-en_fr revision: null image: local/kyutai-tts:v1 fields: - name: model type: select options: [tts-1.6b-en_fr] default: tts-1.6b-en_fr - name: input type: textarea label: Text required: true max_length: 5000 - name: voice type: select label: Voice source_url: http://10.100.79.3:8198/v1/audio/voices - name: response_format type: select options: [wav, mp3, pcm] default: wav - name: stream type: bool default: false response: type: audio mime_from_field: response_format reproducibility: seedable: false deterministic: true notes: > Wrapper adds Python overhead vs Kyutai's bare 220ms claim. estimated_latency: cold_start_s: 4 warm_per_unit: "~220–400ms TTFB (with wrapper)" license: "TBD (Kyutai — verify)" - id: vibevoice name: VibeVoice 1.5B (Long-form) description: > Microsoft's diffusion-based long-form multi-speaker TTS. Multi-minute scripts with speaker switching. Not for low-latency single-line use. category: tts version: 3 host: irv-ml1 lifecycle: stack: vibevoice vram_gb: 20 gpu_device_id: 1 endpoint: http://10.100.79.3:8194/v1/audio/speech method: POST content_type: application/json model: id: microsoft/VibeVoice-1.5B revision: null image: local/vibevoice:v1 fields: - name: model type: select options: [tts-1, tts-1-hd, vibevoice] default: tts-1 description: > OpenAI-compatibility aliases all map to VibeVoice internally. Wire default is tts-1 (verified against /openapi.json). - name: input type: textarea label: "Text (or Speaker N: ... script)" required: true description: > Single-speaker: plain text. Multi-speaker: "Speaker 0: ...\nSpeaker 1: ..." via /v1/vibevoice/generate (extended endpoint). - name: voice type: select label: Voice default: en-Alice_woman description: > Default `en-Alice_woman` matches the upstream model card's stated default voice. Foot-gun: Alice has been observed to insert intro-BGM for openers like "Welcome to ..." — flip to en-Maya_woman if BGM artifacts are unwanted. OpenAI presets (compat aliases): alloy, echo, fable, onyx, nova, shimmer. VibeVoice presets: en-Alice_woman, en-Carter_man, en-Frank_man, en-Mary_woman_bgm, en-Maya_woman, in-Samuel_man, zh-Anchen_man_bgm, zh-Bowen_man, zh-Xinran_woman. The `_bgm`-suffixed voices were trained with background music intentionally — avoid for clean speech. Custom: drop WAV/MP3/FLAC/M4A into /worktank/vibevoice/voices/, restart container. Voice cloning training NOT released by Microsoft. options: - alloy - echo - fable - onyx - nova - shimmer - en-Alice_woman - en-Carter_man - en-Frank_man - en-Mary_woman_bgm - en-Maya_woman - in-Samuel_man - zh-Anchen_man_bgm - zh-Bowen_man - zh-Xinran_woman - name: response_format type: select options: [wav, mp3, opus, flac, pcm] default: mp3 description: > Wire default is mp3 (verified /openapi.json). All five values confirmed by exercising the endpoint 2026-05-11; aac and m4a fail with 500 despite OpenAPI not enforcing an enum, so excluded. - name: stream type: bool default: false description: Single-shot endpoint doesn't stream; segment-level on multi-speaker. response: type: audio mime_from_field: response_format reproducibility: seedable: false deterministic: true estimated_latency: cold_start_s: 8 warm_per_unit: "30–60s first generation; segment-based after" license: MIT notes: | flash_attention_2 default; sdpa fallback. 7B variant (rsxdalv/VibeVoice-Large, ~18GB) needs int8 for <10GB VRAM. - id: voxtral name: Voxtral 4B TTS description: > Mistral AI's 4B multilingual streaming TTS (CC BY-NC — research/internal only). 8 languages, 70ms model latency, 9.7× realtime. Served via vLLM-Omni. category: tts version: 1 status: down host: irv-ml1 lifecycle: stack: voxtral vram_gb: 12 gpu_device_id: 1 endpoint: http://10.100.79.3:8197/v1/audio/speech method: POST content_type: application/json model: id: mistralai/Voxtral-4B-TTS-2603 revision: null image: vllm/vllm-omni:v0.18.0 fields: - name: model type: select options: [mistralai/Voxtral-4B-TTS-2603] default: mistralai/Voxtral-4B-TTS-2603 - name: input type: textarea label: Text required: true max_length: 5000 - name: voice type: select label: Voice source_url: http://10.100.79.3:8197/v1/audio/voices default: alloy - name: response_format type: select options: [wav, mp3, pcm] default: wav - name: stream type: bool default: false response: type: audio mime_from_field: response_format reproducibility: seedable: false deterministic: true notes: vLLM-Omni v0.18.0+ required (first Voxtral-aware release, 2026-03-29). estimated_latency: cold_start_s: 6 warm_per_unit: "~70ms model latency, 9.7× realtime" license: "CC BY-NC (Mistral) — non-commercial only" license_warning: | NOT clear for commercial use. UI must surface this when output destined for products. Use Kokoro/Chatterbox/Fish/IndexTTS/Qwen3/CosyVoice for commercial paths. - id: parakeet name: Parakeet TDT (ASR) description: > NVIDIA Parakeet-TDT 0.6B (int8 ONNX, ~400MB) via sherpa-onnx. Transcription only. category: asr version: 1 host: irv-ml1 lifecycle: stack: parakeet vram_gb: 2 gpu_device_id: null endpoint: http://10.100.79.3:8765/transcribe method: POST content_type: multipart/form-data model: id: nvidia/parakeet-tdt-v2-en-int8 revision: null image: local/parakeet:sherpa-onnx-v2 fields: - name: file type: file label: Audio File required: true accepted_types: [audio/wav, audio/mp3, audio/flac, audio/ogg] response: type: text output_field: text reproducibility: seedable: false deterministic: true estimated_latency: cold_start_s: 1 warm_per_unit: "~realtime" license: "Proprietary (NVIDIA model) + Apache-2.0 (sherpa-onnx)" notes: | Aliased at /v1/audio/transcriptions for OpenAI compat. v3 model (25 languages) available via env-only change. - id: stable-audio-open name: Stable Audio Open 1.0 (SFX) description: > Stability AI's text-to-audio diffusion. SFX/foley/ambience only — NOT music. Max 47s clips. Seeded, fully deterministic. category: sfx version: 2 host: irv-ml1 lifecycle: stack: stable-audio-open vram_gb: 6 gpu_device_id: 1 endpoint: http://10.100.79.3:8211/v1/audio/sfx method: POST content_type: application/json model: id: stabilityai/stable-audio-open-1.0 revision: null image: local/stable-audio-open:v1 fields: - name: prompt type: textarea label: Prompt required: true description: > Description of the audio to generate. Per diffusers Tips section, descriptive multi-element prompts produce better results than terse ones — `"melodic techno with a fast beat and synths, 128 BPM"` is stronger than `"techno"`. Other canonical examples from the model card: `"128 BPM tech house drum loop"`, `"the sound of a hammer hitting a wooden surface"`. - name: negative_prompt type: textarea label: Negative Prompt default: "low quality, average quality" description: > Official diffusers-docs recommendation. `"low quality, average quality"` (lowercase, comma-separated) per the Stable Audio pipeline's Tips section — was `"Low quality."` in v0, fixed in v1. - name: duration type: slider min: 0.5 max: 47.0 default: 10.0 label: Duration (seconds) - name: steps type: slider min: 10 max: 300 default: 100 label: Diffusion Steps - name: cfg_scale type: slider min: 0.0 max: 20.0 default: 7.0 label: CFG Scale - name: seed type: number label: Seed optional: true response: type: audio mime: audio/wav reproducibility: seedable: true seed_field: seed deterministic: true notes: > Identical seed+prompt+steps+cfg = bit-identical bytes. Wrapper serializes concurrent requests via asyncio.Lock (StableAudioPipeline not reentrant). estimated_latency: cold_start_s: 3 warm_per_unit: "~30–60s per 10s clip" license: "Stability AI Community (non-commercial)" license_warning: | Non-commercial only. Same flag as Voxtral for commercial paths. - id: ace-step name: ACE-Step 1.5 (Music) description: > Apache-2.0 hybrid diffusion+LLM music generation. Multi-minute lyric-aware songs with vocals + instrumentation. category: music version: 5 host: irv-ml1 lifecycle: stack: ace-step vram_gb: 16 gpu_device_id: 1 endpoint: http://10.100.79.3:8210/generate method: POST content_type: application/json model: id: ace-step/ACE-Step revision: main image: local/ace-step:v1 section_groups: - id: basic label: Basic hint: "Prompt + lyrics + duration. The 80% case." - id: generation label: Generation hint: "Sampler steps, guidance, scheduler, seed." - id: conditioning label: Conditioning hint: "ERG flags, OSS schedule, guidance shape." - id: a2a label: "Audio → Audio" hint: "Generate from a reference clip." - id: lora label: LoRA hint: "Adapter weights." - id: output label: Output hint: "Format and device." fields: - name: prompt type: textarea label: Musical Prompt required: true section: basic description: > Style/mood/instrumentation as a comma-separated tag string. The upstream Gradio UI ships pre-filled with: `"funk, pop, soul, rock, melodic, guitar, drums, bass, keyboard, percussion, 105 BPM, energetic, upbeat, groovy, vibrant, dynamic"` — same shape works well here. Shorter examples: `"uplifting pop with synth leads"`, `"lo-fi hip-hop beat with vinyl crackle"`. - name: lyrics type: textarea label: Lyrics required: true default: "" section: basic description: > Required by the upstream Pydantic model (`lyrics: str`) but empty string is a valid value (instrumental). Default '' so the inference client always sends a string. - name: audio_duration type: slider min: 5.0 max: 240.0 default: 30.0 label: Duration (seconds) section: basic description: > Upstream caps at 240s (the model's training horizon). Lower bound 5s is our choice — upstream uses -1 as a "random duration" sentinel which is hostile UX for a slider. Default 30s also kept (upstream uses -1; explicit 30 is the better first-time-user experience). - name: infer_step type: number default: 60 label: Inference Steps section: generation description: > Upstream Gradio default is 60 (matches benchmark numbers in the README). Lower values (20-30) are useful for "preview" passes; higher (80-100) marginal returns. - name: guidance_scale type: slider min: 0.0 max: 30.0 default: 15.0 section: generation - name: scheduler_type type: select options: [euler, heun, pingpong] default: euler section: generation description: > Flow-matching scheduler. `euler` is the canonical default; `heun` trades 2x compute for higher-order accuracy; `pingpong` is a specialized noise-bouncing variant. - name: cfg_type type: select options: [apg, cfg, cfg_star] default: apg section: generation description: > Classifier-free guidance variant. Upstream Gradio default is `apg` (adaptive projected guidance); `cfg` is the standard SD-style formulation; `cfg_star` is an advanced alternative. See the upstream pipeline source for trade-offs. - name: omega_scale type: slider min: -10.0 max: 30.0 default: 10.0 section: generation description: > Upstream technically allows [-100, 100] but values that wide are unusable as a slider. UI-bounded to [-10, 30] which covers the typical zone with headroom. Hit the API directly for extremes. - name: actual_seeds type: json label: Seeds (empty = random) default: [] section: generation description: > Empty list = wrapper sends empty string to pipeline = pipeline picks a random seed per batch element. Explicit seeds (e.g. [42] or [42, 137, 9999]) for reproducibility. REPRODUCIBILITY GAP (queued for follow-up): the pipeline returns the chosen seed in its result dict, but our wrapper currently throws it away. Assets generated with the default `[]` cannot currently be regenerated. Workaround: set actual_seeds explicitly when reproducibility matters. Wrapper enhancement to surface random-resolved seeds via X-Actual-Seeds header + a catalog schema field for header→accessory capture is the planned fix. - name: guidance_interval type: slider min: 0.0 max: 1.0 default: 0.5 section: conditioning - name: guidance_interval_decay type: slider min: 0.0 max: 1.0 default: 0.0 section: conditioning description: > Upstream Gradio default is 0.0 (no decay). Catalog v4 had this at 1.0 (full decay) — wrong; produced under-conditioned outputs. - name: min_guidance_scale type: slider min: 0.0 max: 20.0 default: 3.0 section: conditioning description: > Upstream technically allows up to 200; UI-bounded to 20 (covers the typical zone). Hit the API directly for extremes. - name: use_erg_tag type: bool default: true section: conditioning - name: use_erg_lyric type: bool default: false section: conditioning - name: use_erg_diffusion type: bool default: true section: conditioning - name: oss_steps type: json default: [] section: conditioning - name: guidance_scale_text type: slider min: 0.0 max: 10.0 default: 0.0 section: conditioning - name: guidance_scale_lyric type: slider min: 0.0 max: 10.0 default: 0.0 section: conditioning - name: audio2audio_enable type: bool default: false section: a2a - name: ref_audio_strength type: slider min: 0.0 max: 1.0 default: 0.5 section: a2a - name: ref_audio_input type: text label: Reference Audio Path optional: true section: a2a - name: lora_name_or_path type: text label: LoRA Repo/Path optional: true section: lora - name: lora_weight type: slider min: -3.0 max: 3.0 default: 1.0 section: lora description: > Negative weights are legitimate (apply the LoRA in inverse). Upstream Gradio range adopted verbatim. - name: audio_format type: select options: [wav, mp3, flac] default: wav section: output - name: bf16 type: bool default: true section: output - name: torch_compile type: bool default: false section: output - name: device_id type: number default: 0 label: GPU Device Index section: output - name: checkpoint_path type: text label: Checkpoint Path required: true default: /app/checkpoints section: output description: > Required by the upstream wrapper (`infer-api.py:29`, no default in the Pydantic model). The container always mounts checkpoints at /app/checkpoints, so the catalog default works out-of-the-box. Only override if you've mounted an alternate checkpoint path. Wrapper-side cleanup queued — once the upstream model defaults this, the catalog field will become optional or be dropped entirely. response: # As of wrapper version that ships with image local/ace-step:v1 # post 2026-05-11, /generate streams audio bytes inline with # Content-Type set from the audio_format request field. The # in-container output_path is exposed via X-Output-Path header # for log correlation but is no longer load-bearing. type: audio mime_from_field: audio_format reproducibility: seedable: true deterministic: true notes: > actual_seeds parameter exposed; identical seeds + params = identical audio. Local infer-api.py patches upstream's broken 24-arg pipeline signature (v2: was 18 in upstream — caused crashes with audio_duration in `format` slot) AND inline-streams the generated audio bytes (v4: was returning a JSON path reference to a file inside the container, which was unreachable from outside). REPRODUCIBILITY GAP (v5): default `actual_seeds: []` triggers random seed selection inside the pipeline. The chosen seed IS available in the pipeline's return dict (`actual_seeds` key) but our wrapper doesn't capture or surface it — so default-defaulted assets cannot be regenerated bit-exact. Set actual_seeds explicitly when reproducibility is required. Wrapper enhancement to surface chosen seeds via response header + a catalog schema for header→accessory capture is queued. estimated_latency: cold_start_s: 30 warm_per_unit: "~10–60s depending on audio_duration + infer_step" license: Apache-2.0 notes: | 27-field surface — UI must do progressive disclosure (basic/advanced). Gradio UI fallback: docker exec -it ace-step python3 acestep/gui.py. - id: comfyui name: ComfyUI (workflow engine — catalog-deferred) description: > Node-based diffusion workflow engine. Native API is workflow JSON DAG, not form fields. Catalog-deferred until per-asset-type workflow templates are defined and a wrapper maps form inputs to template node parameters. category: image status: catalog-deferred version: 1 host: irv-ml1 endpoint: http://10.100.79.3:8188 method: WebSocket + POST content_type: application/json model: id: "various (SD, SDXL, Flux, ControlNet, LoRA, upscalers)" revision: null image: mmartial/comfyui-nvidia-docker:ubuntu24_cuda12.8-20260312 response: type: image mime: image/png reproducibility: seedable: true deterministic: true notes: > Seed is a workflow node parameter. Reproducibility requires persisting full workflow JSON + seed alongside the asset. license: GPL-3.0 notes: | To bring into the catalog: define workflow templates per asset-type (portrait, landscape, sfx-thumbnail, ...), build a wrapper that does form-field-to-node-parameter substitution, submit via POST /prompt, poll /history. Until then, expose ComfyUI as an external link in the UI. User state at /worktank/comfyui/basedir/. # Reproducibility audit — answers per service: (a) seedable, (b) model # deterministic without seed, (c) image tag mutable (security/reproducibility risk). reproducibility_audit: - service: kokoro seedable: false model_deterministic: true image_tag_mutable: true notes: ":v0.2.4-master is mutable; pin to digest for v3." - service: kokoro-captioned seedable: false model_deterministic: true image_tag_mutable: true notes: "Same image as kokoro proper; same mutability story. Response carries timestamps." - service: chatterbox seedable: false model_deterministic: true image_tag_mutable: false notes: "PerTh watermark unconditional (Resemble policy)." - service: index-tts seedable: false model_deterministic: true image_tag_mutable: false notes: "22050 Hz hardcoded — caller must resample." - service: qwen3-tts seedable: false model_deterministic: true image_tag_mutable: false - service: cosyvoice seedable: false model_deterministic: true image_tag_mutable: false notes: "instruct field broken for English; XML tags only." - service: fish-s2 seedable: false model_deterministic: true image_tag_mutable: false notes: "Research-only license — non-commercial." - service: kyutai-tts seedable: false model_deterministic: true image_tag_mutable: false - service: vibevoice seedable: false model_deterministic: true image_tag_mutable: false notes: "Voice cloning training not released." - service: voxtral seedable: false model_deterministic: true image_tag_mutable: false notes: "CC BY-NC — non-commercial." - service: parakeet seedable: false model_deterministic: true image_tag_mutable: false - service: stable-audio-open seedable: true model_deterministic: true image_tag_mutable: false notes: "Wrapper serializes concurrent requests (StableAudioPipeline not reentrant)." - service: ace-step seedable: true model_deterministic: true image_tag_mutable: false notes: "Local infer-api.py patches upstream's broken pipeline signature." - service: comfyui seedable: true model_deterministic: true image_tag_mutable: false notes: "Reproducibility requires persisting full workflow JSON + seed."