Files
esh-pfi-infrastructure/stacks/fish-s2/compose.yaml
T
vh e0d1c44137 chore(fleet): repoint stale irv-ml1 refs (10.100.79.3 -> irv-ml1.nh3.internal)
The 2026-09-06 headscale cutover retired irv-ml1's wg0 tunnel IP 10.100.79.3
(now 10.6.110.50). Repointed all LIVE canonical refs to the DNS NAME so the next
move can't re-break them: homepage.href/siteMonitor labels across 25 stack
composes, load-bearing env defaults (asset-engine INFERENCE_HOST, open-webui
AUDIO_TTS_OPENAI_API_BASE_URL, skaldsong SKALDSONG_TTS_BASE_URL, zonos-gateway
ZONOS_URL, dia), homepage services.yaml manual cards (Voice Design Studio,
IRV-ML1), and servers/irv-ml1/ssh-target. Updated the stale 'WG tunnel' comment
to the mesh reality.

Left as-is: README curl-examples and .env.example comments (docs), and historical
mentions in CLAUDE.md/persistent-memory. NOTE: applying the label repoints to the
RUNNING irv-ml1 containers needs a recreate per service (labels read at creation);
deployed .env values are separate from these canonical defaults.
2026-09-07 15:08:56 -07:00

106 lines
5.2 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.
# Fish Audio S2-Pro — the most expressive open-source TTS as of
# 2026-04. 4B params, dual-AR architecture (Slow AR for semantic
# codebook + Fast AR for 9 residual codebooks), trained on 10M+ hours
# across 80+ languages. ~150 ms streaming TTFB on warm GPU.
#
# Why this stack alongside the existing TTS:
# * Headline feature: 15,000+ paralinguistic / emotion tags via
# natural language, e.g. [laugh] [whispers] [super happy] [sigh].
# Chatterbox Turbo only has 9 fixed tags — Fish's vocabulary is
# dramatically richer for any emotive use case.
# * 91.61% paralinguistic win rate on EmergentTTS-Eval — currently
# the leader on that benchmark.
# * Voice cloning + native multi-speaker / multi-turn generation.
# * MIT-style license (weights, training code, inference engine all
# open).
#
# Image is built locally from upstream's repo via docker buildx
# git-context. Upstream ships a compose with `--profile server` for
# the API path; we adapt that to our `restart: unless-stopped`
# convention + bind-mount layout.
#
# All tunables live in .env — edit that, not this file.
services:
fish-s2:
image: local/fish-s2:${FISH_S2_TAG}
build:
context: https://github.com/fishaudio/fish-speech.git#${FISH_S2_SHA}
# The REAL production Dockerfile is at docker/Dockerfile (per
# upstream's compose.base.yml). The repo also ships a
# `dockerfile.dev` at root which is a thin
# `FROM ghcr.io/fishaudio/fish-speech:${VERSION}` wrapper meant
# for dev iteration on top of a private base image — that path
# 403s on anonymous pulls. Build from source via docker/Dockerfile
# instead.
dockerfile: docker/Dockerfile
# Multi-stage Dockerfile — `server` stage installs start_server.sh
# and exposes the API. The default last stage is `webui` (gradio
# only), which crashloops silently because start_server.sh isn't
# there. Target=server is what upstream's compose.yml does.
target: server
args:
# Build args mirror upstream compose.base.yml defaults.
# CUDA_VER 12.9 + UV_EXTRA cu129 = the CUDA 12.9 PyTorch wheels.
# irv-ml1's driver (595.58.03 / CUDA 13.2 capable) is
# backward-compatible with 12.9-built images.
BACKEND: cuda
CUDA_VER: "12.9.0"
UV_EXTRA: cu129
UV_VERSION: "0.8.15"
container_name: fish-s2
restart: unless-stopped
runtime: nvidia
ports:
- "${FISH_S2_BIND:-0.0.0.0}:${FISH_S2_PORT}:8080"
environment:
- NVIDIA_VISIBLE_DEVICES=${FISH_S2_GPU_DEVICES:-1}
- BACKEND=cuda
# COMPILE=1 enables torch.compile — upstream claims ~10× speedup
# on the autoregressive forward, at the cost of ~60 s warmup the
# first time each input shape is seen. Worth the speedup; turn
# off via .env if you hit a torch.compile bug on a future model
# checkpoint.
- COMPILE=${FISH_S2_COMPILE:-1}
- API_PORT=8080
# Model selection. Override Fish's Dockerfile defaults so we can
# swap variants via .env without rebuilding. Both checkpoints are
# pre-pulled by the deploy playbook into bind-mounted checkpoints/.
# s2-pro — 4B class, ~17 GB VRAM, slow but highest quality
# s1-mini — lighter, ~3-5× smaller model.pth, much faster
- LLAMA_CHECKPOINT_PATH=checkpoints/${FISH_S2_MODEL:-s2-pro}
- DECODER_CHECKPOINT_PATH=checkpoints/${FISH_S2_MODEL:-s2-pro}/codec.pth
# Hugging Face cache for model weights — first start pulls
# fishaudio/s2-pro (~9 GB BF16) into this dir.
- HF_HOME=/app/hf_cache
volumes:
# Model checkpoints (auto-downloaded on first run, then cached).
- ${FISH_S2_CHECKPOINT_DIR}:/app/checkpoints
# Reference audio for voice cloning — drop ~5–15 s WAV clips here.
- ${FISH_S2_REFERENCE_DIR}:/app/references
# Persistent HF cache so model re-pull only happens on first deploy.
- ${FISH_S2_CACHE_DIR}:/app/hf_cache
# Pass --half to start_server.sh → enables fp16 inference on the
# LLM half. Speeds up the autoregressive loop (the dominant cost
# in TTFB). Also enables the streaming path's faster total time.
# build_compile_args() echoes unknown args back to the exec line.
command: ["--half"]
healthcheck:
# Fish ships /v1/health on the API server. python urllib instead
# of curl because the upstream image is python-based and may not
# carry curl. 127.0.0.1 explicit to dodge the IPv6-first
# localhost trap we hit on chatterbox + news-digest.
test: ["CMD-SHELL", "python3 -c \"import urllib.request,sys; sys.exit(0 if urllib.request.urlopen('http://127.0.0.1:8080/v1/health', timeout=5).status==200 else 1)\""]
interval: 30s
timeout: 10s
retries: 3
# First boot: torch.compile warmup + first-pull HF download +
# checkpoint load. Generous deadline.
start_period: 900s
labels:
- homepage.group=AI - Dormant
- homepage.name=Fish Audio S2-Pro
- homepage.icon=mdi-fish
- homepage.description=Most expressive open-source TTS — 15k+ paralinguistic tags, voice cloning, 80+ languages (irv-ml1)
- homepage.href=http://irv-ml1.nh3.internal:${FISH_S2_PORT}