# Использование и развёртывание

## Установка

> Рекомендуется Python 3.11. Python 3.14+ пока не имеет совместимых wheel для
> `torch` / `f5-tts`, поэтому используйте 3.10–3.12.

```bash
# Клонировать / перейти в директорию проекта
cd voice

# Создать виртуальное окружение
python3.11 -m venv .venv
source .venv/bin/activate  # Windows: .venv\Scripts\activate

# Установить PyTorch с CUDA 12.6 (обязательно первым)
pip install torch torchaudio --index-url https://download.pytorch.org/whl/cu126

# Установить остальные зависимости
pip install -r requirements.txt

# (Опционально) скопировать настройки
cp .env.example .env
```

## Запуск сервера

```bash
# Основной режим: F5-TTS на GPU
python -m voice_tts.main

# С настроенным референсом и warm-up (рекомендуется)
TTS_BACKEND=f5_tts \
DEFAULT_VOICE_REF=voices/rick_ref_clean.wav \
DEFAULT_REF_TEXT="Ва-ба-ла-ба-дап-дап! Рикки-тики-тави, сученька! И вот такие у нас новости! Иди." \
WARMUP=true \
python -m voice_tts.main

# Тестовый режим без модели
TTS_BACKEND=dummy python -m voice_tts.main
```

Сервер поднимется на `ws://localhost:8765/ws`.

## Проверка работоспособности

```bash
curl http://localhost:8765/health
# {"status":"ok","backend":"f5_tts"}
```

## Пример Python-клиента

```python
import asyncio
import base64
import json
import websockets


async def main():
    uri = "ws://localhost:8765/ws"
    async with websockets.connect(uri) as ws:
        await ws.send(json.dumps({
            "type": "init",
            "session_id": "demo",
            "voice_ref": "voices/default_neutral.wav",
            "language": "ru",
            "speed": 1.0,
            "emotion": "neutral",
            "seq": 1,
        }))

        for chunk in ["Привет, ", "как ", "дела?"]:
            await ws.send(json.dumps({
                "type": "text",
                "payload": chunk,
                "seq": 2,
            }))
            await asyncio.sleep(0.2)

        await ws.send(json.dumps({"type": "flush", "seq": 3}))

        while True:
            msg = json.loads(await ws.recv())
            print(msg)
            if msg["type"] == "audio":
                pcm = base64.b64decode(msg["data"])
                # отправить pcm на воспроизведение
            if msg["type"] == "status" and msg["event"] == "stopped":
                break


if __name__ == "__main__":
    asyncio.run(main())
```

## Настройка через переменные окружения (.env)

| Переменная | Описание | По умолчанию |
|------------|----------|--------------|
| `HOST` | Хост сервера | `0.0.0.0` |
| `PORT` | Порт сервера | `8765` |
| `LOG_LEVEL` | Уровень логирования | `INFO` |
| `TTS_BACKEND` | Бэкенд (`dummy` / `f5_tts`) | `f5_tts` |
| `TTS_SAMPLE_RATE` | Частота дискретизации | `24000` |
| `VOICES_DIR` | Директория с референсами | `voices` |
| `MIN_SEGMENT_LENGTH` | Мин. длина сегмента | `30` |
| `MAX_SEGMENT_LENGTH` | Макс. длина сегмента | `200` |
| `MAX_BUFFER_WAIT_MS` | Макс. ожидание перед flush | `500` |
| `DEVICE` | `cuda` или `cpu` | `cuda` |
| `DTYPE` | `bfloat16` / `float16` | `bfloat16` |
| `DEFAULT_VOICE_REF` | Путь к референсу по умолчанию | — |
| `DEFAULT_REF_TEXT` | Точный текст референса (skip Whisper) | — |
| `WARMUP` | Прогреть CUDA и кэшировать референс | `false` |
| `WARMUP_TEXT` | Текст для warm-up | `Привет. Это тестовая фраза.` |

## Загрузка модели

Если `TTS_BACKEND=f5_tts` (по умолчанию), при первом старте сервер автоматически
скачает нужный checkpoint из Hugging Face в кэш. Чтобы скачать модель
заранее:

```bash
python scripts/download_f5_tts.py --model F5TTS_v1_Base
```

Поддерживаемые варианты: `F5TTS_v1_Base`, `F5TTS_Base`, `E2TTS_Base`.
Модель сохраняется в `models/F5TTS_v1_Base/`.

## Тесты

```bash
# Быстрые тесты без загрузки F5-TTS
TTS_BACKEND=dummy python -m pytest tests/ -v
```

## Референсные аудио

Поместите файлы в директорию `voices/`:

```
voices/
├── default_neutral.wav
├── default_happy.wav
├── default_sad.wav
└── ...
```

Требования к референсу:
- WAV или другой формат, читаемый `torchaudio`.
- Моно, 16+ кГц.
- Длина 3–10 секунд (для F5-TTS).
- Чистая речь одного спикера без фонового шума.
- Для мгновенного старта задайте точный `DEFAULT_REF_TEXT` — иначе сервер
  будет транскрибировать референс через Whisper при первом запуске (5–6 с).
