initial: silero-tts-service + README
This commit is contained in:
1 parent
8c60c25ad2
commit
984b1fec6d
18 files changed
+2080
No files matched your search
Executable
+204
@@ -0,0 +1,204 @@
|
||||
# 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']))
|
||||
"
|
||||
```
|
||||
Reference in new issue
Block a user