Newer
Older
voice / docs / 06_technical_notes.md

Технические заметки

Почему base64 PCM вместо WAV/Opus

  • Низкая задержка: не нужно ждать формирования заголовка WAV или энкодинга Opus.
  • Простота клиента: Python-агент может напрямую скормить PCM в pyaudio / sounddevice / alsaaudio.
  • Компромисс: трафик больше, чем с Opus, но в локальной сети это некритично.
  • Opus можно добавить позже как опциональный формат.

Почему один TTS worker

  • CUDA context не любит параллельные вызовы из разных потоков.
  • Один worker с asyncio.Queue гарантирует последовательный доступ к GPU и предсказуемое потребление VRAM.
  • Если в будущем понадобится масштабирование — можно запустить несколько независимых инстансов.

Управление остановкой

stop_event — центральный механизм:

  • SessionState.stop() устанавливает флаг.
  • Все длительные операции (TTS, отправка аудио) могут его проверять.
  • После stop новое сообщение text автоматически сбрасывает флаг и начинает новую фразу.

Сегментация

Цель — найти баланс между:

  • задержкой (короткие сегменты синтезируются быстрее),
  • качеством (TTS лучше звучит на целых предложениях),
  • реалтаймом (не ждём слишком долго).

Параметры по умолчанию:

  • min_segment_length = 30
  • max_segment_length = 200
  • max_buffer_wait_ms = 500

Для русского языка предложения обычно короче, чем на английском, поэтому max_length выбран консервативно.

Fish Speech 1.5

Особенности интеграции

  • Локальный checkpoint в models/fishaudio_fish-speech-1.5/: model.pth, firefly-gan-vq-fsq-8x1024-21hz-generator.pth, tokenizer.tiktoken, config.json, special_tokens.json.
  • Исходный код models/fish-speech-v1.5.1/ добавляется в sys.path для импорта модулей.
  • Выходная частота дискретизации — 44,1 кГц.
  • Точный транскрипт референса важен: используется .lab рядом с референсом, затем DEFAULT_REF_TEXT, затем Whisper-транскрипция, затем placeholder.
  • Скорость регулируется resampling'ом после синтеза (TTS_SPEED).
  • Параллельные CUDA-вызовы сериализуются через asyncio.Lock и asyncio.to_thread.

Тюнинг

  • FISH_USE_MEMORY_CACHE=on — кэшировать VQ-представление референса (включено).
  • FISH_CHUNK_LENGTH — длина LLM-чанка (100–300, по умолчанию 200). Больше = длиннее связные куски, но выше задержка.
  • FISH_COMPILE=true — пытается включить torch.compile. Не включать по умолчанию: при повторном инференсе возникает ошибка accessing tensor output of CUDAGraphs that has been overwritten. Исследуется отдельно.

Замеры задержки (RTX 3090, Python 3.11, CUDA 12.6)

  • Первый запуск без DEFAULT_REF_TEXT: ~5–6 с, большая часть уходит на Whisper-транскрипцию.
  • С DEFAULT_REF_TEXT и WARMUP=true: загрузка модели + один инференс.
  • RTF (real-time factor) Fish Speech ~1.4 на коротких сегментах: медленнее реального времени.
  • RTF XTTS-v2 ~0.34: быстрее реального времени.
  • Fish Speech даёт более естественную русскую интонацию, поэтому выбран по умолчанию.
  • XTTS-v2 — резервный быстрый бэкенд для сценариев, где задержка важнее качества.

Сравнение с XTTS-v2

Показатель Fish Speech 1.5 XTTS-v2
RTF ~1.4 ~0.34
Русская интонация естественнее приемлемо, акцент чаще
Английская речь хорошо хорошо
Размер weights ~2 ГБ LLM + VQGAN ~3 ГБ
Sample rate 44,1 кГц 24 кГц
Требует ref transcript да, точный да, но терпимее
torch.compile нестабилен не применяется

XTTS-v2

  • Coqui-модель tts_models/multilingual/multi-dataset/xtts_v2.
  • Автоматически скачивается при первом TTS_BACKEND=xtts_v2.
  • Можно указать локальный checkpoint через TTS_MODEL_PATH.
  • Sample rate 24 кГц; клиенты examples/client_*.py/examples/client_browser.html настроены на динамический sample rate из сообщений audio.

Мультиязычность

Базовая модель F5TTS_v1_Base поддерживает несколько языков из коробки. Инференс на коротких тестовых фразах работает для:

  • русского,
  • английского,
  • украинского,
  • испанского,
  • немецкого,
  • французского.

При этом важные нюансы:

  • Акцент: когда референс — русский спикер, английская и европейская речь может иметь сильный русский акцент.
  • Произношение: для незнакомых фонем модель может «додумывать» звуки или пропускать сложные буквосочетания.
  • Скорость: английские/романские фразы короче по токенам, поэтому инференс занимает ~1.0–1.2 с, в то время как русский/украинский — ~1.2–2.2 с на сегмент из 1–2 предложений.
  • Точность языка: модель не использует явный language токен; язык определяется по тексту. Для смешанных текстов (ru + en) возможны переключения произношения.

Что делать, если качество европейских языков недостаточно

  1. Отдельный референс на английском/европейском языке — в протоколе уже поддерживаются voice_refs по эмоциям; можно добавить language в профиль голоса и выбирать референс в зависимости от языка.
  2. Fallback backend — для «чужеродных» языков переключаться на MeloTTS или другой TTS, который лучше произносит конкретный язык.
  3. Fine-tuning F5-TTS — самый трудоёмкий, но даёт лучший контроль над акцентом и языком.

Сейчас оставляем Fish Speech 1.5 как бэкенд по умолчанию для en/ru, XTTS-v2 — как быстрый резерв. Архитектура (TTSEngine + _BACKEND_MAP) позволяет добавить fallback позже.

  • F5-TTS может не идеально произносить украинский / европейские языки из коробки — возможно потребуется fine-tuning или fallback. Сейчас протокол и сегментатор не ограничивают язык; качество зависит от самой модели.
  • RTX 3060 (12 GB) подойдёт для базовой модели, но batch-size и длина референса придётся ограничивать.
  • Быстрый stop во время CUDA kernel не прервёт уже запущенный kernel, но предотвратит отправку результата.
  • main.py создаёт engine до старта uvicorn; при TTS_BACKEND=fish_speech первый запуск занимает десяток секунд из-за загрузки LLM и VQ-GAN.