205 lines
6.1 KiB
Markdown
Executable File
205 lines
6.1 KiB
Markdown
Executable File
# Silero TTS API
|
||
|
||
REST-сервис синтеза русской речи. Silero v5.5 + автостресс + GPU/CPU.
|
||
Пайплайн-совместимый CLI + интеграция с HyperFrames для генерации видео.
|
||
|
||
## ⚡ Быстрый старт
|
||
|
||
### Способ 1: CLI (рекомендуется)
|
||
|
||
```bash
|
||
# Проверка
|
||
python3 tts.py health
|
||
|
||
# Голоса
|
||
python3 tts.py voices
|
||
|
||
# Синтез в файл
|
||
python3 tts.py speak "Привет, мир!" --voice xenia --output hello.wav
|
||
|
||
# Гиперфреймс: аудио для видео + HTML-сниппет
|
||
python3 tts.py hyperframes "Текст озвучки" --voice xenia -o narration.wav
|
||
```
|
||
|
||
### Способ 2: HTTP API
|
||
|
||
```bash
|
||
# OpenAI-совместимый
|
||
curl -X POST http://localhost:8001/v1/audio/speech \
|
||
-H "Content-Type: application/json" \
|
||
-d '{"model":"tts-1","input":"Привет, мир!","voice":"xenia","response_format":"wav"}' \
|
||
--output hello.wav
|
||
|
||
# Нативный Silero
|
||
curl -X POST http://localhost:8001/v1/tts \
|
||
-H "Content-Type: application/json" \
|
||
-d '{"text":"Привет, мир!","speaker":"xenia"}' \
|
||
--output hello.wav
|
||
```
|
||
|
||
### Способ 3: Запуск сервера
|
||
|
||
```bash
|
||
# Локально (порт 8001)
|
||
pip install -e .
|
||
cp .env.example .env
|
||
python3 run.py
|
||
```
|
||
|
||
```bash
|
||
# Docker GPU
|
||
docker compose up --build -d
|
||
|
||
# Docker CPU
|
||
docker compose -f docker-compose.yml -f docker-compose.cpu.yml up --build -d
|
||
```
|
||
|
||
## 📝 API
|
||
|
||
### `POST /v1/tts`
|
||
```bash
|
||
curl -X POST http://localhost:8001/v1/tts \
|
||
-H "Content-Type: audio/wav" \
|
||
-H "Content-Type: application/json" \
|
||
-d '{"text": "Привет, мир!", "speaker": "aidar"}' \
|
||
-o output.wav
|
||
```
|
||
|
||
### `GET /v1/voices`
|
||
Голоса (v5_ru): `aidar`, `baya`, `kseniya`, `xenia`, `eugene`
|
||
|
||
> Примечание: модель v5_5_ru поддерживает 10+ голосов (irina, ruslan, natasha и др.).
|
||
> Для переключения на v5_5_ru нужно скачать модель и обновить config.py.
|
||
|
||
### `GET /health`
|
||
Проверка загрузки модели
|
||
|
||
## 📊 Мониторинг
|
||
|
||
### `GET /metrics`
|
||
Prometheus метрики:
|
||
- `tts_requests_total` — запросы по endpoint/status
|
||
- `tts_synthesis_seconds` — задержка синтеза (гистограмма)
|
||
- `tts_audio_size_bytes` — размер аудио (гистограмма)
|
||
- `tts_errors_total` — ошибки по типу
|
||
|
||
```bash
|
||
curl http://localhost:8001/metrics
|
||
```
|
||
|
||
## 🚦 Rate Limiting
|
||
|
||
| Endpoint | Лимит |
|
||
|----------|-------|
|
||
| POST /v1/tts | 30 req/min на IP |
|
||
| POST /v1/tts-stream | 10 req/min на IP |
|
||
|
||
Превышение → HTTP 429 с JSON detail.
|
||
|
||
## 🎙️ Streaming
|
||
|
||
### `POST /v1/tts-stream`
|
||
Синтез в MP3 192kbps (chunked transfer).
|
||
- Голос: только `aidar`
|
||
- Макс: 500 символов
|
||
- Content-Type: `audio/mpeg`
|
||
|
||
```bash
|
||
curl -X POST http://localhost:8001/v1/tts-stream \
|
||
-H "Content-Type: application/json" \
|
||
-d '{"text": "Тест стриминга", "speaker": "aidar"}' \
|
||
-o output.mp3
|
||
```
|
||
|
||
## 🔧 Режимы
|
||
|
||
| Режим |DEVICE|Скорость/100 слов|Память|Голоса|
|
||
|-------|------|----------------|------|------|
|
||
| GPU | `cuda:0` | 0.5–1s | 2.5 GB VRAM | 5 голосов (v5_ru) |
|
||
| CPU | `cpu` + JIT | 2–4s | RAM | 5 голосов (v5_ru) |
|
||
| CPU | `cpu` + 8 threads | 1.5–3s | RAM | 5 голосов (v5_ru) |
|
||
|
||
## 📋 Чек-лист готовности
|
||
|
||
- [x] Автоопределение GPU
|
||
- [x] CPU-режим с JIT
|
||
- [x] CORS middleware
|
||
- [x] Request logging
|
||
- [x] Валидация текста
|
||
- [x] Валидация голоса
|
||
- [x] WAV response (не JSON)
|
||
- [x] LRU-кэш
|
||
- [x] Graceful shutdown
|
||
- [x] Docker GPU/CPU
|
||
- [x] .gitignore
|
||
- [x] 16 unit-тестов
|
||
- [x] Prometheus метрики
|
||
- [x] Rate limiting
|
||
- [x] Streaming TTS
|
||
- [x] Multiple speakers (5 голосов: aidar, baya, kseniya, xenia, eugene)
|
||
|
||
## 📁 Структура
|
||
|
||
```
|
||
tts.py ← CLI-инструмент (speak, pipe, hyperframes, health, voices)
|
||
app/
|
||
main.py — FastAPI + lifespan + CORS + metrics endpoint
|
||
api.py — Роуты /v1/tts, /tts-stream, /voices, /health, /v1/audio/speech
|
||
engine.py — Загрузка моделей (GPU/CPU)
|
||
pipeline.py — Синтез (async + executor)
|
||
validators.py — Валидация текста/голоса (изолирована)
|
||
metrics.py — Prometheus метрики + rate limiter
|
||
config.py — Настройки (.env)
|
||
tests/
|
||
test_validation.py — 16 тестов валидации
|
||
test_api.py — Тесты API (mock)
|
||
```
|
||
|
||
## 🎬 Интеграция с HyperFrames
|
||
|
||
```bash
|
||
# 1. Сгенерировать аудио и HTML-сниппет
|
||
python3 tts.py hyperframes "Добро пожаловать в HyperFrames — пиши HTML, получай видео" \
|
||
--voice xenia -o narration.wav
|
||
|
||
# Вывод:
|
||
# ✅ Аудио: narration.wav (84.2 KB, 5.12 сек)
|
||
#
|
||
# ─── HTML-сниппет для HyperFrames ───
|
||
# <audio id="narration"
|
||
# data-start="0"
|
||
# data-duration="5.1"
|
||
# data-track-index="0"
|
||
# data-volume="1.0"
|
||
# src="narration.wav">
|
||
# </audio>
|
||
```
|
||
|
||
Вставить сниппет в `index.html` композиции и отрендерить:
|
||
|
||
```bash
|
||
npx hyperframes preview # предпросмотр
|
||
npx hyperframes render --output demo.mp4 # рендер
|
||
```
|
||
|
||
## 🔄 Пайплайны
|
||
|
||
```bash
|
||
# Конвейер: stdin → TTS → stdout
|
||
echo "Текст для озвучки" | python3 tts.py pipe --voice aidar > output.wav
|
||
|
||
# JSON-вывод для API-интеграций
|
||
python3 tts.py speak "Текст" --json | jq '.audio_base64' | base64 -d > output.wav
|
||
|
||
# Пакетная обработка (Python)
|
||
python3 -c "
|
||
import subprocess, json, base64
|
||
sentences = ['Фраза 1.', 'Фраза 2.', 'Фраза 3.']
|
||
for i, s in enumerate(sentences):
|
||
r = subprocess.run(['python3', 'tts.py', 'speak', s, '--voice', 'xenia', '--json'], capture_output=True, text=True)
|
||
data = json.loads(r.stdout)
|
||
with open(f'chunk_{i:03d}.wav', 'wb') as f:
|
||
f.write(base64.b64decode(data['audio_base64']))
|
||
"
|
||
```
|