Files
esh-pfi-infrastructure/docs/asset-engine/services.yaml
T
vh 079c7b15e3 asset-engine + irv-ml1: scaffold orchestrator wiring
Three changes prepping infra for asset_engine's orchestration feature
(SSH-driven bring-up / bring-down of irv-ml1 inference services with
per-device VRAM gating, contract in vh/asset-engine commit 5a36f8c):

1. asset-engine compose + .env.example + playbook gain a read-only
   bind-mount for /app/runtime/ssh — the dedicated ed25519 keypair
   (generated on ana-docker, not in the repo) plus a pinned known_hosts
   for irv-ml1's host fingerprint. Env vars SSH_KEY_PATH and
   SSH_KNOWN_HOSTS are exposed for the app to consume.

2. docs/asset-engine/services.yaml gains a `lifecycle: { stack, vram_gb,
   gpu_device_id }` block on each of 12 orchestratable irv-ml1 services
   (kokoro, chatterbox, index-tts, qwen3-tts, cosyvoice, fish-s2,
   kyutai-tts, vibevoice, voxtral, parakeet, stable-audio-open, ace-step).
   VRAM numbers are estimates from model footprint at fp16 — tune from
   real nvidia-smi measurements once the gate is live. comfyui and
   kokoro-captioned are deliberately excluded (variable-VRAM and
   shared-container respectively).

3. servers/irv-ml1/README.md docker-stacks table now lists all 13
   inference stacks (was only dockge + agents + comfyui) with port +
   GPU pinning columns.

Pubkey deployed to ~lkraven/.ssh/authorized_keys on irv-ml1;
end-to-end SSH from ana-docker → irv-ml1 verified with strict
host-key checking.
2026-05-12 13:24:07 -07:00

1204 lines
39 KiB
YAML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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, 35100x realtime,
60+ built-in voices in 8 languages. Voice mixing via inline weights.
OpenAI-compatible /v1/audio/speech.
category: tts
version: 2
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_bella
description: >
60+ built-in voices. 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.52.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, 35100x 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: 1
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_bella
- 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": "<base64-encoded bytes in response_format>",
"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: 515s 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: <name>.wav in /worktank/index-tts/voices/. 530s 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: <name>.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.01.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:<name> where <name> 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 <angry>, <sad>, <surprised>, <fast>, <whisper>, 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+).
- name: references
type: json
label: Voice References
optional: true
description: >
Array of {audio: "/app/references/<file>.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: "~220400ms 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: 2
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-Carter_man
description: >
OpenAI presets: 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.
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: "3060s 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: 1
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
- name: negative_prompt
type: textarea
label: Negative Prompt
default: "Low quality."
- 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: "~3060s 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, e.g. "uplifting pop with synth leads".
- 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: "~1060s 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."