Files
rocm-chatterbox-whisper/main.py
scott 169e003a34
All checks were successful
Build ROCm Image / build (push) Successful in 3m35s
Fix warmup text length and ve attribute for torch.compile
- Warmup now uses a ~170-char representative sentence so torch.compile
  JIT-compiles for typical token sequence lengths. Previously "Warmup."
  compiled for very short shapes, causing a full re-compile (17s) on the
  first real HA request and pushing total synthesis past 30s.
- Compile model.ve (voice encoder) in addition to s3gen — both are
  convolutional and hit the MIOpen workspace=0 bug.
- Fix _patch_timing: attribute is model.ve not model.voice_encoder,
  so the timing wrap was silently skipping the speaker embedding.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-05 14:51:08 -04:00

66 lines
2.1 KiB
Python

import asyncio
import logging
import sys
from functools import partial
from wyoming.server import AsyncServer
import engine
from config import get_wyoming_host, get_wyoming_port, load_config
from wyoming_handler import ChatterboxWyomingHandler
from wyoming_voices import create_wyoming_info, load_voices
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s %(levelname)s %(name)s: %(message)s",
stream=sys.stdout,
)
logger = logging.getLogger(__name__)
def _warmup(voices: dict) -> None:
from wyoming_voices import resolve_voice
audio_prompt = resolve_voice(None, voices) if voices else None
logger.info("Running warmup synthesis to populate MIOpen kernel cache...")
try:
engine.synthesize(
text=(
"This is a warmup synthesis request used to pre-compile neural network kernels "
"for typical text lengths, so that the first real request runs at full speed."
),
audio_prompt_path=audio_prompt,
)
logger.info("Warmup complete — MIOpen cache populated")
except Exception:
logger.warning("Warmup synthesis failed (non-fatal)", exc_info=True)
async def main() -> None:
load_config()
logger.info("Loading TTS model...")
if not engine.load_model():
logger.error("Failed to load model, exiting")
sys.exit(1)
voices = load_voices()
wyoming_info = create_wyoming_info(engine.get_sample_rate(), voices)
# Run a warmup synthesis before accepting connections so MIOpen benchmarks
# and caches the best convolution algorithms for all layer shapes. Without
# this, the first real HA request triggers benchmarking (hundreds of runs)
# and times out before any audio is returned.
_warmup(voices)
host = get_wyoming_host()
port = get_wyoming_port()
uri = f"tcp://{host}:{port}"
logger.info(f"Starting Wyoming server on {uri}")
server = AsyncServer.from_uri(uri)
await server.run(partial(ChatterboxWyomingHandler, wyoming_info, voices))
if __name__ == "__main__":
asyncio.run(main())