Потоковое распознавание — WebSocket¶
WebSocket STT предназначен для живого звука из браузера или приложения. Клиент отправляет бинарные PCM-фреймы, а сервер возвращает JSON с промежуточным и финальным текстом.
В отличие от файловых методов, поток не сохраняет запись или транскрипт и не создаёт операцию. Коррекция LLM, NER, диаризация и суммаризация здесь не выполняются.
Аутентификация¶
Используйте один из способов:
Authorization: Api-Key <ключ>илиAuthorization: Bearer <ключ>;- cookie активной portal-сессии;
- legacy query-параметр
?api_key=<ключ>.
Для новых клиентов предпочтителен заголовок: query string может попасть в
access-логи. Без аутентификации сервер закрывает соединение с кодом 1008, если
не включён PUBLIC_API_ALLOW_ANONYMOUS.
Перед распознаванием сервер проверяет, что на балансе достаточно кредитов хотя
бы на одну секунду STT. При отказе он отправляет
{"error":"...","code":"insufficient_credits"} и закрывает соединение с
кодом 1008. Фактический объём принятого аудио учитывается после потока.
Входной поток¶
Аудио имеет фиксированный формат:
| Параметр | Значение |
|---|---|
| Кодирование | signed PCM16 little-endian |
| Частота | 16 кГц |
| Каналы | mono |
Первое сообщение может быть JSON-конфигурацией:
| Поле | По умолчанию | Описание |
|---|---|---|
language |
ru-RU |
Языковая подсказка backend |
model |
RIVA_ONLINE_MODEL сервера, обычно SpeechExpert-STT |
Маршрут распознавания |
Конфигурация необязательна: первым сообщением можно сразу отправить бинарный PCM-фрейм. Сервер ждёт первое сообщение до 30 секунд, после чего продолжает с настройками по умолчанию. Последующие бинарные сообщения помещаются в очередь до 256 фреймов; если обработка отстаёт, чтение WebSocket приостанавливается и создаёт обратное давление клиенту.
Поддерживаемые потоковые маршруты:
T-one— прямые partial и пофразовые final T-One;SpeechExpert-STT— T-One для накопительных preview и один авторитетный offline-final SpeechExpert-STT;GigaAM-Multilingual-Large-CTCи устаревшие алиасыGigaAM-v3-CTC/SpeechExpert-STT-Enhanced— T-One preview и один offline-final multilingual GigaAM, только для русского. Дляkk-KZ,ky-KGиuz-UZиспользуйте асинхронное распознавание файла: русская T-One не может формировать корректные partial на этих языках.
После всех PCM-фреймов отправьте один из вариантов EOF и продолжайте читать ответы до закрытия потока:
Ответы и таймстемпы¶
Каждое серверное сообщение — самостоятельный JSON-объект. В каждом событии
распознавания присутствуют text и is_final; тайминги добавляются, только если
backend их вернул. Сообщения об ошибках имеют отдельную форму без этих полей.
{
"text": "добрый день",
"is_final": false,
"start_ms": 340,
"end_ms": 1080,
"timing_source": "t-one",
"words": [
{"text": "добрый", "start_ms": 340, "end_ms": 720},
{"text": "день", "start_ms": 760, "end_ms": 1080}
]
}
start_ms и end_ms отсчитываются от начала входного потока; нулевое начало
валидно. Сейчас WebSocket возвращает нативные тайминги для T-One с
timing_source: "t-one". Потоковые ветки Riva пока не передают тайминги в это
событие; для backend без нативного тайминга start_ms, end_ms,
timing_source и words опускаются.
Для hybrid-маршрута финальные границы берутся из T-One preview. Если offline-
текст отличается от preview, у финального сообщения words будет пустым:
слово-в-слово выравнивание неизвестно. На финальный text также накладывается
восстановление пунктуации, поэтому слова описывают исходные токены backend.
Ошибка распознавания возвращается как {"error":"..."}. Отдельного события
done нет: после EOF клиент дочитывает все final-сообщения до закрытия
соединения.
Пример Python¶
import asyncio
import json
import os
import websockets
async def main():
uri = "wss://api.speech.example.com/api/stt/v1/ws"
headers = {"Authorization": f"Api-Key {os.environ['API_KEY']}"}
async with websockets.connect(uri, additional_headers=headers) as ws:
await ws.send(json.dumps({"language": "ru-RU", "model": "T-one"}))
with open("audio.pcm", "rb") as source:
while chunk := source.read(3200): # около 100 мс
await ws.send(chunk)
await ws.send(json.dumps({"event": "eof"}))
async for message in ws:
event = json.loads(message)
print(event)
asyncio.run(main())
Выбор потокового API¶
| Интерфейс | Когда использовать |
|---|---|
| WebSocket | Браузер, простой JSON-протокол, mono PCM16 16 кГц |
| gRPC | Protobuf, несколько каналов, произвольная частота PCM, silence_chunk и нормализация |
| OpenAI SSE | Псевдострим готового загруженного файла; не для живого входящего аудио |