first commit
This commit is contained in:
@@ -0,0 +1,104 @@
|
||||
# Модуль 3: TTS (текст → звук)
|
||||
|
||||
Два провайдера за общим интерфейсом `TtsProvider`: переключение = выбор в конфиге.
|
||||
|
||||
| Провайдер | Сеть | Латентность (110 симв.) | Голоса | Роль |
|
||||
|---|---|---|---|---|
|
||||
| **edge** (`provider_edge.py`) | онлайн, бесплатный сервис MS, без ключа | 3.0 c (4 предл.), 1.7 c (короткая) | Svetlana/Dmitry, отличное качество | основной |
|
||||
| **piper** (`provider_piper.py`) | офлайн, локально на CPU | 0.47 c | dmitri/irina/ruslan, проще | фолбэк без сети |
|
||||
|
||||
## Режимы edge-провайдера
|
||||
|
||||
- **Один запрос** (по умолчанию): весь текст → один round-trip (~1.7–3 c). Паузы между
|
||||
предложениями удлиняются многоточиями («точка» → «…» — edge-tts читает как длинную паузу).
|
||||
- **per_sentence=True**: каждое предложение отдельным запросом + точная тишина
|
||||
`sentence_pause_sec` между ними. Медленнее (N запросов), нужен для тонкой подгонки пауз.
|
||||
|
||||
Замер 2026-09-11 (свежие соединения в каждом процессе): один запрос 110 симв = 3.0 c,
|
||||
короткая фраза 36 симв = 1.7 c, Piper 110 симв = 0.47 c. В живой программе соединение
|
||||
переиспользуется — будет быстрее. Цепочка целиком: STT ~1.2 c + LLM ~1–2 c + TTS ~1.7 c ≈ 4–5 c
|
||||
от отпускания клавиши до голоса (маскируется earcon «думаю»).
|
||||
|
||||
## Использование из кода
|
||||
|
||||
```python
|
||||
from modules.tts import get_provider
|
||||
|
||||
tts = get_provider("edge") # voice="ru-RU-DmitryNeural" — мужской
|
||||
result = tts.synthesize("Привет! Как дела?")
|
||||
# result.audio (float32), result.samplerate, result.generation_sec, result.duration_sec
|
||||
```
|
||||
|
||||
Фолбэк при обрыве сети (switch = одна строка):
|
||||
|
||||
```python
|
||||
tts = get_provider("piper", model_path="models/piper/ru_RU-dmitri-medium.onnx")
|
||||
```
|
||||
|
||||
## Потоковая озвучка (стриминг, 2026-09-11)
|
||||
|
||||
`tts.stream(text)` — генератор: отдаёт чанки-предложения **по мере готовности**
|
||||
(параллельные запросы, отдача в порядке следования). `Assistant` играёт чанк
|
||||
сразу, не дожидаясь синтеза всего текста:
|
||||
|
||||
- первое предложение звучит через ~0.5 c после готовности LLM (один round-trip);
|
||||
- длинные ответы больше не пропорционально тормозят (2-е/3-е предложение
|
||||
синтезируются, пока играет 1-е);
|
||||
- между чанками вставляется пауза sentence_pause_sec;
|
||||
- перебивание отцом гасит поток и синтез (счётчик поколений).
|
||||
|
||||
Плюс в `Player.play()` добавлен префикс тишины 0.1 c (`lead_silence_sec`) —
|
||||
защита от «съедания» первого слова при открытии аудио-потока (недозаполненный
|
||||
буфер ALSA/Pulse).
|
||||
|
||||
## Настройка из .env (2026-09-11)
|
||||
|
||||
```
|
||||
TTS_PROVIDER=edge # edge | piper
|
||||
TTS_VOICE=ru-RU-SvetlanaNeural # мужской: ru-RU-DmitryNeural
|
||||
TTS_RATE=+15 # темп речи, % (+ = быстрее; ≈+30% к исходному −15)
|
||||
PIPER_MODEL=models/piper/ru_RU-dmitri-medium.onnx
|
||||
```
|
||||
|
||||
Выбранный конфиг юзером: **edge + Svetlana, rate +15** («женский голос лучше и темп
|
||||
нормальный»). Piper остаётся офлайн-фолбэком (0.22 c синтез против 0.49 c у edge),
|
||||
при желании ускориться — одна строка в .env.
|
||||
|
||||
Фабрика: `make_tts()` из `modules/tts` — тесты ассистента читают эти параметры
|
||||
автоматически, смену голоса/скорости/провайдера можно делать без правки кода.
|
||||
|
||||
## Файлы
|
||||
|
||||
| Файл | Назначение |
|
||||
|---|---|
|
||||
| `base.py` | Интерфейс `TtsProvider`, результат `SynthResult` |
|
||||
| `provider_edge.py` | edge-tts: один запрос / сшивание предложений |
|
||||
| `provider_piper.py` | Piper офлайн (`length_scale` из rate автоматом в config) |
|
||||
| `config.py` | `make_tts()` — фабрика из .env (провайдер, голос, скорость) |
|
||||
| `text_split.py` | Разбивка на предложения; защита сокращений («т.д.», «т.к.») |
|
||||
| `test_tts.py` | Тест-скрипт (синтез / воспроизведение / интерактив / провайдеры) |
|
||||
|
||||
## Тест-скрипт
|
||||
|
||||
```bash
|
||||
.venv/bin/python modules/tts/test_tts.py --play # фраза по умолчанию + звук
|
||||
.venv/bin/python modules/tts/test_tts.py --text "Своё предложение"
|
||||
.venv/bin/python modules/tts/test_tts.py --voice ru-RU-DmitryNeural --play # мужской
|
||||
.venv/bin/python modules/tts/test_tts.py --listen # вводишь текст — слышишь
|
||||
.venv/bin/python modules/tts/test_tts.py --per-sentence # медленный режим (сравнение)
|
||||
.venv/bin/python modules/tts/test_tts.py --provider piper --model models/piper/ru_RU-dmitri-medium.onnx --play
|
||||
```
|
||||
|
||||
## Критерии приёмки Модуля 3
|
||||
|
||||
1. ✅ Русский голос звучит естественно, скорость −15% — принято юзером на слух (Svetlana).
|
||||
2. ✅ Паузы между предложениями слышны (многоточия / точная тишина).
|
||||
3. ✅ Синтез короткой фразы ≤ 3 c: 1.7 c (edge), 0.47 c (piper).
|
||||
|
||||
## Известные ограничения
|
||||
|
||||
- edge-tts — неофициальный API Microsoft: исторически ломался (403). План Б — Piper, он уже в проекте.
|
||||
- Piper: голос скачивается один раз в `models/piper/` (команда в docstring провайдера);
|
||||
качество проще edge, зато 0.5 c и полностью офлайн.
|
||||
- В `provider_edge._run_async` учтён будущий asyncio-контекст (aiogram в Модуле 6):
|
||||
синтез не сломает чужой event loop.
|
||||
Reference in New Issue
Block a user