feat(omnivoice): wire to asset-engine via FastAPI wrapper + reuse chatterbox voices

- app.py: thin FastAPI wrapper exposing OpenAI /v1/audio/speech (+ /v1/audio/voices,
  /healthz) around OmniVoice's Python API; precomputes a voice-clone prompt per voice
  at startup (loaded Whisper auto-transcribes each reference). Replaces the Gradio demo.
- Dockerfile/compose: run the uvicorn wrapper, /healthz healthcheck, project name pinned
  to "omnivoice" so the asset-engine liveness probe matches.
- deploy-omnivoice.yaml: stage chatterbox /refs/*.wav as clone voices (skip _* artifacts)
  + verify the API surface.
- services.yaml: catalog entry (id omnivoice, :8199/v1/audio/speech, voice list sourced
  live from /v1/audio/voices) + reproducibility_audit row.

Verified live on irv-ml1: /healthz ok, 33 voices loaded, test synth -> 24kHz PCM_16 WAV.
This commit is contained in:
vh
2026-06-18 23:03:20 -07:00
parent 984b72757f
commit 06eb487a26
6 changed files with 255 additions and 37 deletions
+65
View File
@@ -565,6 +565,66 @@ services:
Three-way mutual-exclusion among emotion_voice / emotion_vector / emotion_text;
precedence as above. UI should expose this as a single picker.
- id: omnivoice
name: OmniVoice
description: >
k2-fsa zero-shot, massively-multilingual (600+ language) voice-cloning TTS
(diffusion-LM, RTF ~0.025). Apache-2.0. Behind our own FastAPI wrapper
(stacks/omnivoice/app.py); voices are the reused chatterbox reference clips.
category: tts
version: 1
status: ready
host: irv-ml1
lifecycle:
stack: omnivoice
vram_gb: 6
gpu_device_id: 0
endpoint: http://10.100.79.3:8199/v1/audio/speech
method: POST
content_type: application/json
model:
id: k2-fsa/OmniVoice
revision: null
image: local/omnivoice:latest
fields:
- name: input
type: textarea
label: Text
required: true
max_length: 5000
- name: voice
type: select
label: Speaker Voice
source_url: http://10.100.79.3:8199/v1/audio/voices
source_jsonpath: $.voices[*]
description: >
Zero-shot clone target — a reference clip staged in
/worktank/omnivoice/voices/ (reused chatterbox voices; 33 at deploy).
Live list at /v1/audio/voices.
- name: response_format
type: select
options: [wav]
default: wav
description: 24000 Hz PCM_16 mono only; no negotiation.
response:
type: audio
mime: audio/wav
reproducibility:
seedable: false
deterministic: false
notes: >
Diffusion-LM, temperature/denoise sampled — not byte-exact, no seed exposed.
Output 24000 Hz PCM_16 mono. Voice = a cloned reference clip (clone prompt
precomputed per voice at startup; Whisper auto-transcribes the reference).
estimated_latency:
cold_start_s: 600
warm_per_unit: "full-utterance (no streaming)"
license: "Apache-2.0"
notes: |
v1 is clone-only (voice = a staged reference clip); OmniVoice's voice-DESIGN
and language/instruct controls are not yet exposed in the wrapper. No streaming.
Voices reused from chatterbox /refs (staged into /worktank/omnivoice/voices/).
- id: qwen3-tts
name: Qwen3-TTS 1.7B
description: >
@@ -2207,6 +2267,11 @@ reproducibility_audit:
model_deterministic: true
image_tag_mutable: false
notes: "22050 Hz hardcoded — caller must resample."
- service: omnivoice
seedable: false
model_deterministic: false
image_tag_mutable: true
notes: "Diffusion-LM, temperature/denoise sampled — not byte-exact, no seed exposed. 24000 Hz PCM_16 mono. image local/omnivoice:latest is mutable — pin a digest for true repro. Voices = reused chatterbox /refs clones (clone prompt precomputed per voice at startup)."
- service: qwen3-tts
seedable: false
model_deterministic: true