ЦАРЬ РОУТЕР

Потоковое распознавание речи

Транскрипция в реальном времени через WebSocket /v1/realtime/transcriptions: формат событий OpenAI Realtime, подключение, аудио-формат, биллинг, пример кода

Потоковое распознавание превращает речь в текст по мере произнесения: вы шлёте аудио-чанки в WebSocket, сервер отвечает промежуточными результатами (delta) и финальной транскрипцией. Подходит для живых субтитров, диктовки и транскрипции звонков. Модели с этим режимом отмечены в каталоге бейджем «Потоковая».

Формат событий совместим с OpenAI Realtime API (transcription-режим) — при переносе клиентского кода достаточно сменить URL.

Подключение

wss://api.tsarrouter.ru/v1/realtime/transcriptions?model=<id модели>

Два способа авторизации:

СпособКакДля кого
ЗаголовокAuthorization: Bearer <ключ>серверные клиенты
Subprotocol["realtime", "openai-insecure-api-key.<ключ>"]браузер (заголовки в WebSocket недоступны)

Оба держат ключ вне URL. Передавать ключ query-параметром нельзя — секрет попал бы в журналы сервера.

Модель задаётся query-параметром ?model= или событием session.update (поле session.audio.input.transcription.model).

События

Клиент → сервер:

СобытиеНазначение
session.updateНастроить формат аудио и/или модель (до первого аудио)
input_audio_buffer.appendЧанк аудио: {"audio": "<base64 PCM16LE>"}, рекомендуем ~200 мс
input_audio_buffer.commitКонец фразы — запросить финальную транскрипцию

Сервер → клиент:

СобытиеНазначение
session.created / session.updatedПодтверждение сессии и настроек
conversation.item.input_audio_transcription.deltaПрирост текста по мере речи
input_audio_buffer.committedФраза принята в финализацию
conversation.item.input_audio_transcription.completedФинальный текст + usage.seconds
errorОшибка; фатальные дополнительно закрывают соединение (коды)

Серверного VAD нет: конец фразы задаёт клиент событием commit (turn_detection: null).

Формат аудио

Сырой PCM16LE mono (audio/pcm), частота дискретизации 8000–48000 Гц (по умолчанию 16000). Частота задаётся в session.update:

{"type": "session.update", "session": {"audio": {"input": {"format": {"type": "audio/pcm", "rate": 16000}}}}}

Биллинг и лимиты

Тарификация посекундная — по длительности принятого аудио (не времени соединения: паузы между чанками бесплатны). Списанные секунды каждой фразы приходят в usage.seconds события completed. На старте сессии на балансе резервируется стоимость аудио-бюджета сессии, по завершении списывается только фактическое — остаток возвращается сразу.

Лимиты сессий (аудио-бюджет, одновременные сессии, таймаут бездействия) зависят от уровня аккаунта — см. Лимиты.

Пример (Python)

# pip install websockets
import asyncio, base64, json, websockets

URL = "wss://api.tsarrouter.ru/v1/realtime/transcriptions?model=palatine/palatine_stream"

async def main():
    async with websockets.connect(
        URL, additional_headers={"Authorization": "Bearer sk-tsar-ваш-ключ"},
    ) as ws:
        await ws.send(json.dumps({"type": "session.update", "session": {
            "audio": {"input": {"format": {"type": "audio/pcm", "rate": 16000}}},
        }}))
        pcm = open("audio.pcm", "rb").read()  # PCM16LE mono 16 кГц
        for i in range(0, len(pcm), 6400):    # чанки ~200 мс
            await ws.send(json.dumps({
                "type": "input_audio_buffer.append",
                "audio": base64.b64encode(pcm[i:i + 6400]).decode(),
            }))
        await ws.send(json.dumps({"type": "input_audio_buffer.commit"}))
        async for raw in ws:
            ev = json.loads(raw)
            if ev["type"] == "conversation.item.input_audio_transcription.delta":
                print(ev["delta"], end="", flush=True)
            elif ev["type"] == "conversation.item.input_audio_transcription.completed":
                print("\n---", ev["transcript"], ev["usage"])
                break

asyncio.run(main())

Попробовать без кода можно в песочнице личного кабинета — с записью с микрофона.

На этой странице

Редактировать на GitVerse