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

## Почему 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.
