README.md

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.

Описание
Образ Docker с сервером STT+TTS для русского языка
Конвейеры
0 успешных
0 с ошибкой
Разработчики