Skip to content

Протокол сообщений

Все сообщения передаются в формате JSON с обязательным полем event, определяющим тип сообщения.

Client → Server

session.begin

Аутентификация и инициализация сессии. Должно быть отправлено в течение 10 секунд после подключения.

ПолеТипОбязательноеПо умолчаниюОписание
eventstringда"session.begin"
api_keystringдаAPI-ключ (формат sk_live_...)
voice_idstringдаUUID голоса для синтеза
speedfloatнет1.0Скорость речи (0.5–1.5)
output_formatstringнет"pcm_24000"Формат выходного аудио
normalizeboolнетtrueНормализация текста перед синтезом. При true — полная нормализация: раскрытие времени (9:00 → «девять часов»), озвучивание символов (² → «в квадрате», → «рублей»), обработка ссылок, скобок и пунктуации. При false — только базовая очистка (удаление HTML/эмодзи, нормализация пробелов), косметические преобразования отключены
inactivity_timeoutintнет30Тайм-аут бездействия в секундах (5–180)
buffer_configobjectнетНастройки буферизации текста

buffer_config:

ПолеТипПо умолчаниюОписание
first_chunk_thresholdint120Порог для первого сброса буфера (50–200 символов)
subsequent_chunk_thresholdint160Порог для последующих сбросов (80–200 символов)
json
{
  "event": "session.begin",
  "api_key": "sk_live_YOUR_API_KEY",
  "voice_id": "9efc2a63-911e-4e19-9d5e-01b0640fc4e6",
  "speed": 1.0,
  "output_format": "pcm_24000",
  "normalize": true,
  "inactivity_timeout": 60,
  "buffer_config": {
    "first_chunk_threshold": 120,
    "subsequent_chunk_threshold": 160
  }
}

text.chunk

Отправка фрагмента текста для синтеза.

ПолеТипОбязательноеПо умолчаниюОписание
eventstringда"text.chunk"
textstringдаФрагмент текста (слово, токен, предложение)
flushboolнетfalseНемедленно отправить буфер на синтез
json
{
  "event": "text.chunk",
  "text": "Привет, как дела?",
  "flush": true
}

Когда использовать flush: true

Если вы отправляете короткую фразу (менее 120 символов) и хотите, чтобы синтез начался немедленно — передавайте flush: true. Без этого текст будет ждать в буфере до достижения порога или до text.end.


text.end

Сигнал окончания текста. Сервер сбрасывает остаток буфера и дожидается завершения синтеза. При успехе он отправляет generation.complete, при ошибке — только error.

ПолеТипОбязательноеОписание
eventstringда"text.end"
json
{"event": "text.end"}

interrupt

Немедленное прерывание текущей генерации. Сервер отменяет синтез, очищает буфер и очередь, затем отправляет generation.interrupted.

ПолеТипОбязательноеОписание
eventstringда"interrupt"
json
{"event": "interrupt"}

Важно: drain после interrupt

После отправки interrupt в WebSocket-канале могут находиться сообщения audio.chunk, которые сервер уже отправил до обработки вашего interrupt. Клиент обязан продолжать читать сообщения до получения generation.interrupted. Все audio.chunk, полученные после отправки interrupt, следует вычитать из канала, но не воспроизводить.


session.end

Завершение сессии. Сервер дожидается окончания текущей генерации (если есть), затем закрывает WebSocket с кодом 1000.

ПолеТипОбязательноеОписание
eventstringда"session.end"
json
{"event": "session.end"}

ping

Keepalive-сообщение. Сервер ответит pong. Можно отправлять до аутентификации.

ПолеТипОбязательноеОписание
eventstringда"ping"
json
{"event": "ping"}

Server → Client

session.ready

Подтверждение успешной аутентификации. Сессия готова к приёму текста.

ПолеТипОписание
eventstring"session.ready"
session_idstringUUID сессии (для логирования/отладки)
json
{
  "event": "session.ready",
  "session_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}

audio.chunk

Фрагмент аудио (~200 мс). Данные закодированы в base64.

ПолеТипОписание
eventstring"audio.chunk"
audiostringBase64-кодированные raw audio bytes
sequenceintПорядковый номер чанка (начинается с 1, монотонно возрастает)
json
{
  "event": "audio.chunk",
  "audio": "AQID...base64data...==",
  "sequence": 1
}

Размер чанка

Каждый чанк содержит ~200 мс аудио. Для pcm_24000 это 9 600 байт (24 000 × 2 × 0.2). После base64-кодирования — ~12 800 символов.


generation.complete

Синтез успешно завершён. Все аудио-чанки отправлены. Сессия возвращается в состояние READY. После события error для той же генерации generation.complete не отправляется.

ПолеТипОписание
eventstring"generation.complete"
total_chunksintОбщее количество отправленных audio.chunk
json
{
  "event": "generation.complete",
  "total_chunks": 42
}

generation.interrupted

Генерация прервана по запросу клиента (interrupt). Сессия возвращается в состояние READY.

ПолеТипОписание
eventstring"generation.interrupted"
chunks_sentintКоличество audio.chunk, отправленных до прерывания
json
{
  "event": "generation.interrupted",
  "chunks_sent": 15
}

WARNING

Значение chunks_sent отражает количество чанков, которые сервер успел отправить. Из-за сетевой задержки клиент может получить generation.interrupted после нескольких дополнительных audio.chunk — см. обработка interrupt.


error

Сообщение об ошибке. В зависимости от типа ошибки соединение может быть закрыто.

ПолеТипОписание
eventstring"error"
codestringКод ошибки
messagestringЧеловекочитаемое описание
json
{
  "event": "error",
  "code": "auth_failed",
  "message": "Invalid or revoked API key"
}

Коды ошибок

КодmessageПоведение
invalid_messageInvalid WebSocket messageСоединение открыто; исправьте сообщение
invalid_textText contains no synthesizable contentОшибка текущей генерации
request_too_largeText is too longОшибка текущей генерации
auth_failedInvalid or revoked API keyЗакрытие 4001
permission_deniedAccess deniedЗакрытие 4007
insufficient_balanceInsufficient balanceЗакрытие 4004
voice_not_foundVoice not foundЗакрытие 4006
voice_not_readyVoice is not ready yetЗакрытие 4009
rate_limitedRealtime connection limit exceededПревышен лимит параллельных Realtime-соединений; закрытие 4003
service_unavailableSpeech synthesis service is temporarily unavailableДо session.ready: закрытие 4005; во время генерации: соединение открыто
synthesis_timeoutSpeech synthesis timed outОшибка текущей генерации
synthesis_failedSpeech synthesis failedОшибка текущей генерации
internal_errorInternal server errorЗакрытие 4500
auth_timeoutsession.begin was not received in timeЗакрытие 4002
inactivity_timeoutSession closed due to inactivityЗакрытие 4008

Ошибки текущей генерации (invalid_text, request_too_large, service_unavailable, synthesis_timeout, synthesis_failed) не закрывают уже готовую сессию. Для ошибочной генерации сервер не отправляет generation.complete. Если text.end уже был отправлен, можно начинать следующую генерацию; иначе сначала завершите границу текущей генерации через text.end или interrupt.

Рекомендуемая реакция клиента

КодДействие
invalid_messageИсправить формат или порядок WS-сообщений
invalid_textИсправить или отфильтровать текст
request_too_largeУменьшить объём текста, отправляемого за одну генерацию
auth_failedОбновить API-ключ и переподключиться
permission_deniedПроверить права доступа
insufficient_balanceПополнить баланс/лимит и переподключиться
voice_not_foundВыбрать существующий голос
voice_not_readyПодождать готовности голоса и создать новую сессию
rate_limitedЗакрыть лишнее Realtime-соединение и подключиться снова
service_unavailableПовторить запрос
synthesis_timeoutПовторить запрос
synthesis_failedИспользовать fallback текста или голоса по бизнес-логике
internal_errorНе повторять автоматически; обратиться в поддержку
auth_timeoutПереподключиться и сразу отправить session.begin
inactivity_timeoutПереподключиться, если работу нужно продолжить

pong

Ответ на ping.

ПолеТипОписание
eventstring"pong"
json
{"event": "pong"}

Следующие шаги