Files
esh-pfi-infrastructure/stacks/mOrpheus/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

95 lines
3.8 KiB
YAML

# mOrpheus — uncensored Orpheus TTS, permanent stack on irv-ml1.
#
# Two services:
# vllm-morpheus (GPU, 3090, FP8) — serves the mOrpheus 3B LLM; emits Orpheus audio
# tokens. Real-time: ~165 tok/s single-stream => RTF ~0.50 (2x real-time), measured.
# morpheus-tts (CPU) — SNAC-decodes those tokens to 24kHz WAV; the public /tts endpoint
# (baddy voice + optional zero-shot cloning). Kept off the GPU to avoid contention.
#
# PLACEMENT / GOTCHAS (irv-ml1, INTERNAL RESEARCH — CC-BY-NC, do NOT expose externally):
# - GPU = the 3090 (audio-zoo GPU, stabler); the A6000 is comfy's and spikes to ~41GB
# without warning (it OOM'd two launch attempts). Pin by UUID via MORPHEUS_GPU_UUID.
# - Image PINNED to vllm/vllm-openai:v0.23.0 — `latest` ships Blackwell-only kernels
# (oink/aiter) that crash on Ampere import. Do NOT bump to latest on this Ampere box.
# - bf16 REQUIRED, NOT FP8. FP8 (--quantization fp8) destroys audio-token generation on
# this model — 0 valid SNAC frames even at greedy (quant-breaks-TTS). bf16 weights are
# ~6.6GB; with --enforce-eager (no CUDA-graph capture) it fits the shared 3090 (~8GB
# free after nothing else vLLM). util 0.32 (~7.7GB of the 24GB 3090).
# All tunables in .env — edit that, not this file.
name: morpheus
services:
vllm-morpheus:
image: vllm/vllm-openai:v0.23.0
container_name: vllm-morpheus
restart: unless-stopped
runtime: nvidia
ipc: host
environment:
- NVIDIA_VISIBLE_DEVICES=${MORPHEUS_GPU_UUID:-GPU-12c15b3c-0827-0bab-b0cd-31aaa37a8e72}
- CUDA_DEVICE_ORDER=PCI_BUS_ID
volumes:
- ${MORPHEUS_MODEL_DIR:-/home/lkraven/morpheus/models/mOrpheus}:/model:ro
command:
- /model
- --served-model-name
- morpheus
- --dtype
- bfloat16
# NO --quantization: FP8 breaks audio-token generation on this model (see header).
- --enforce-eager
- --max-model-len
- "${MORPHEUS_MAX_LEN:-4096}"
- --gpu-memory-utilization
- "${MORPHEUS_GPU_UTIL:-0.32}"
- --max-num-seqs
- "${MORPHEUS_MAX_SEQS:-8}"
healthcheck:
test: ["CMD", "python3", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:8000/health')"]
interval: 30s
timeout: 10s
retries: 3
start_period: 300s
networks: [morpheus-net]
morpheus-tts:
build: ./tts
image: morpheus-tts:local
container_name: morpheus-tts
restart: unless-stopped
depends_on:
vllm-morpheus:
condition: service_healthy
environment:
- VLLM_URL=http://vllm-morpheus:8000/v1/completions
- VLLM_MODEL=morpheus
- SNAC_DEVICE=cpu
- MORPHEUS_DEFAULT_VOICE=${MORPHEUS_DEFAULT_VOICE:-baddy}
- MORPHEUS_VOICES=${MORPHEUS_VOICES:-baddy}
- MORPHEUS_VOICES_DIR=/voices # <name>.wav + <name>.txt => voice="<name>" clones it
- MORPHEUS_MAX_LEN=${MORPHEUS_MAX_LEN:-4096} # must match engine --max-model-len (max_tokens clamp)
volumes:
- ${MORPHEUS_MODEL_DIR:-/home/lkraven/morpheus/models/mOrpheus}:/model:ro
- ${SNAC_DIR:-/home/lkraven/morpheus/models/snac_24khz}:/snac:ro
- ${MORPHEUS_VOICES_DIR:-/home/lkraven/morpheus/voices}:/voices:ro
ports:
- "${MORPHEUS_TTS_PORT:-8299}:8000"
healthcheck:
test: ["CMD", "python3", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:8000/health')"]
interval: 30s
timeout: 10s
retries: 3
start_period: 60s
labels:
- homepage.group=AI - Speech (TTS)
- homepage.name=mOrpheus TTS
- homepage.icon=mdi-account-voice
- homepage.description=Uncensored Orpheus TTS (baddy + zero-shot clone), real-time, irv-ml1
- homepage.href=http://irv-ml1.nh3.internal:${MORPHEUS_TTS_PORT:-8299}/docs
networks: [morpheus-net]
networks:
morpheus-net:
name: morpheus-net