ru-stt-tts-api
Одноконтейнерный сервис STT (GigaAM) + TTS (Silero v5_5_ru) для русского языка. OpenAI-совместимый API: распознавание речи и синтез голоса в одном процессе, без внешних зависимостей — модели запекаются в Docker-образ при сборке.
POST /v1/audio/transcriptions # STT: аудио -> текст (GigaAM ONNX)
POST /v1/audio/speech # TTS: текст -> аудио (Silero v5_5_ru, 5 голосов)
GET /healthz # статус
GET /v1/audio/voices # список голосов
Готовые Docker-образы
Образы опубликованы на Docker Hub под bampodev/ru-sst-tts-docker. Модели (GigaAM ONNX ~886 МБ, Silero v5_5_ru) уже внутри — интернет при запуске не нужен.
| Тег | Платформа | Размер (на диске) |
|---|---|---|
bampodev/ru-sst-tts-docker:linux-amd64 |
x86-64 (серверы, Docker Desktop) | ~2.7 GB |
bampodev/ru-sst-tts-docker:linux-arm64 |
aarch64 (Raspberry Pi 4/5, postmarketOS, ARM-серверы) | ~3.9 GB |
Запуск (любая платформа)
docker run -d --name ru-stt-tts \
--restart unless-stopped \
-p 8000:8000 \
bampodev/ru-sst-tts-docker:linux-amd64 # или :linux-arm64 на aarch64-хосте
Опционально:
-v /path/to/output:/data— каталог для legacy-режима TTS (полеoutput_pathвPOST /ttsи/generate, сервер сам пишет файл). Для стандартного OpenAI-API (/v1/audio/speech) не нужен — аудио возвращается в ответе.
Проверка (прогрев моделей ~30–90 с):
curl -s http://localhost:8000/healthz
# {"ok": true, "stt": "gigaam", "tts": "v5_5_ru"}
Быстрый тест обоих сервисов:
# TTS
curl -s http://localhost:8000/v1/audio/speech \
-H "Content-Type: application/json" \
-d '{"voice":"aidar","input":"Созвон в 14:30"}' --output out.wav
# STT
curl -s http://localhost:8000/v1/audio/transcriptions -F "file=@out.wav"
# {"text": "Созвон в 14:30."}
- Порт 8000 (изменить
-p ХХХХ:8000). - Прогрев моделей ~30–90 с; healthcheck:
GET /healthz.
Возможности
- STT — GigaAM
v3_e2e_ctcв ONNX (onnxruntime), длинное аудио режется на фрагменты по тишине (ffmpeg, строго по паузам, без перекрытий), итог склеивается. Проверено на записях ~2 мин: дублирования фраз нет. - TTS — Silero v5_5_ru, голоса:
aidar,baya,kseniya,eugene,xenia. Форматы вывода:wav(по умолчанию),mp3,opus,flac,pcm. Скорость 0.5–2.0, высота тона ±%. -
Кастомный препроцессинг текста (
silero_norm/) — Silero v5_5_ru имеет алфавит только из 47 кириллических символов и молча вырезает цифры и латиницу перед синтезом. Пакетsilero_normнормализует текст в чистую кириллицу ДО синтеза:Вход Что слышно Созвон в 14:30«четырнадцать тридцать» +7 921 555-35-35«семь девять два один пять пять пять…» (по цифрам) Цена 100 рублей«сто рублей» Скидка 50%«пятьдесят процентов» 05.09.2026«пять сентября две тысячи двадцать шесть» v1.2.3«один два три» (без дубля слова «версия») 192.168.1.100«сто девяносто два точка сто шестьдесят восемь…» GitHub, Docker, API«гитхаб, докер, эйпиай» (словарь ~300 слов) Postman, Nginx(нет в словаре)транслитерация: «постман», «нджинкс» ivan@gmail.com«е-мэйл» https://example.com«ссылка» коды с цифрами A3F0,GPT-4по буквам: «эй три эф ноль», «джи пи ти четыре» Структура пакета — каждый тип логики в своём файле (легко расширять):
silero_norm/ ├── __init__.py # normalize_for_silero() — пайплайн ├── digits_latin.py # цифры: телефоны, время, даты, IP, %, версии ├── english_words.py # словарь EN_WORDS (~300 англ. слов -> рус. произношение) └── num2t4ru.py # числа словами (vendored, без зависимостей)Тесты:
python -m silero_norm.test_norm.
Голоса — примеры
В каталоге voices/ — по 4 аудио на каждый голос (WAV 48 kHz). Слушать прямо в README (GitHub):
aidar
baya
kseniya
eugene
xenia
Итого 20 файлов. Формат: <голос>_<тип>.wav.
Сборка Docker-образа из исходников
Модели не хранятся в git (ONNX ~886 МБ, Silero ~139 МБ) — их нужно подготовить в staging-каталоге рядом с Dockerfile:
staging/
├── Dockerfile # из этого репо
├── server_combined.py # из этого репо
├── silero_norm/ # из этого репо
├── .dockerignore # из этого репо
├── models/gigaam_onnx/ # v3_e2e_ctc.onnx + v3_e2e_ctc.yaml (~886 МБ)
├── gigaam_cache/ # v3_e2e_ctc_tokenizer.model (~236 КБ)
└── silero_hub/snakers4_silero-models_master/ # torch.hub кэш с v5_5_ru.pt
Откуда взять модели:
-
ONNX + tokenizer — конвертация GigaAM
v3_e2e_ctcв ONNX скриптомtools/convert_onnx.py(обрабатывает формат checkpoint{'state_dict', 'cfg'}, сам патчит путь токенайзера):pip install torch torchaudio onnx onnxruntime gigaam python tools/convert_onnx.py v3_e2e_ctc.ckpt out_dir/ # -> out_dir/v3_e2e_ctc.onnx + out_dir/v3_e2e_ctc.yamlлибо копирование из готового образа/сервера:
/models/gigaam_onnx/{v3_e2e_ctc.onnx,v3_e2e_ctc.yaml}и~/.cache/gigaam/v3_e2e_ctc_tokenizer.model. - Silero hub кэш — каталог
snakers4_silero-models_masterиз~/.cache/torch/hub/(скачивается автоматически при первомtorch.hub.load("snakers4/silero-models", "silero_tts", trust_repo=True)). Оставить только весаsrc/silero/model/v5_5_ru.pt, остальные модели можно удалить (~207 МБ экономии).
amd64 (x86-64 серверы, Docker Desktop)
docker build -f Dockerfile -t ru-stt-tts-api staging/
arm64 (aarch64 — Raspberry Pi 4/5, телефоны на postmarketOS и т.п.)
Dockerfile.arm64 собирает нативный образ на самом aarch64-хосте (локальные wheels torch/torchaudio в staging/wheels/) и включает strip лишних директорий (torch/include, onnx, networkx, sympy — ~200 МБ):
# на aarch64-хосте:
pip download --python-version 311 --platform manylinux_2_28_aarch64 \
--implementation cp --abi cp311 --only-binary=:all: \
torch==2.8.0+cpu torchaudio==2.8.0 \
--extra-index-url https://download.pytorch.org/whl/cpu -d staging/wheels/
docker build -f Dockerfile.arm64 -t ru-stt-tts-api staging/
Важно: torchaudio ≥ 2.9 требует torchcodec, чьи aarch64-wheels тянут CUDA-библиотеки — STT падает с
ImportError: TorchCodec is required. Поэтому в arm64-Dockerfile зашиты wheels torch==2.8.0+cpu + torchaudio==2.8.0.
API
STT — POST /v1/audio/transcriptions
Multipart: поле file (аудио), опционально model, language.
curl -s http://localhost:8000/v1/audio/transcriptions \
-F "file=@speech.wav" -F "model=whisper-1"
# {"text": "распознанный текст"}
Поддерживаются форматы, которые умеет ffmpeg (wav, mp3, ogg, webm/opus — голосовые мессенджеров, m4a и др.). WebM/Opus декодируются в mono 16 kHz float32 прямо в сервере.
TTS — POST /v1/audio/speech (OpenAI-совместимый)
curl -s http://localhost:8000/v1/audio/speech \
-H "Content-Type: application/json" \
-d '{"model":"tts-1","voice":"aidar","input":"Созвон в 14:30, позвони на +7 921 555-35-35","response_format":"mp3"}' \
--output out.mp3
| Поле | Значение |
|---|---|
voice |
aidar (по умолчанию), baya, kseniya, eugene, xenia |
input / text |
текст, до 4000 символов; цифры/латиница нормализуются автоматически |
speed |
0.5–2.0 (по умолчанию из env SILERO_SPEED, 1.2) |
pitch |
множитель высоты тона (legacy, 1.0 = без изменений) |
response_format |
wav (default), mp3, opus, flac, pcm |
Legacy-эндпоинты: POST/GET /tts, /generate (параметры в query/body, поддержка output_path для записи в /data).
Прочее
curl -s http://localhost:8000/healthz
# {"ok": true, "stt": "gigaam", "tts": "v5_5_ru"}
curl -s http://localhost:8000/v1/audio/voices
# {"voices": ["aidar","baya","kseniya","eugene","xenia"], "model": "v5_5_ru"}
Переменные окружения
| Env | По умолчанию | Назначение |
|---|---|---|
SILERO_MODEL |
v5_5_ru |
модель TTS |
SILERO_SPEED |
1.2 |
скорость по умолчанию |
OMP_NUM_THREADS |
4 |
потоки torch/onnxruntime |
OUT_DIR |
/data |
каталог для legacy-файлов TTS |
Структура репозитория
├── Dockerfile # amd64
├── Dockerfile.arm64 # aarch64 (нативная сборка на целевом хосте, со strip)
├── server_combined.py # HTTP-сервер: STT + TTS в одном процессе
├── silero_norm/ # кастомный препроцессинг текста для Silero
│ ├── __init__.py # normalize_for_silero() — пайплайн
│ ├── digits_latin.py # цифры: телефоны, время, даты, IP, %, версии
│ ├── english_words.py # словарь англ. слов (~300)
│ ├── num2t4ru.py # числа -> русские слова (vendored)
│ └── test_norm.py # тесты: python -m silero_norm.test_norm
├── tools/ # утилиты для работы с моделями
│ ├── convert_onnx.py # конвертация v3_e2e_ctc.ckpt -> ONNX float32
│ └── verify_onnx.py # проверка ONNX-модели внутри контейнера
├── voices/ # аудио-примеры: 5 голосов × 4 текста (WAV)
└── docs/ # расширенная документация
Лицензия
Сервер и silero_norm — MIT. Модели: GigaAM — лицензия Salute Developers, Silero — MIT.