Realtime
Голосовое общение в реальном времени на основе WebSocket (протокол OpenAI Realtime) — создано для голосовых ассистентов, синхронного перевода и других сценариев с низкой задержкой.
Подключение
Название модели передаётся в строке запроса; аутентификация такая же, как у HTTP-эндпоинтов:
wss://test.kailin.com.cn/v1/realtime?model=gpt-4o-realtime-preview
const ws = new WebSocket(
'wss://test.kailin.com.cn/v1/realtime?model=gpt-4o-realtime-preview',
{
headers: {
Authorization: 'Bearer sk-your-token',
'OpenAI-Beta': 'realtime=v1',
},
}
);
Браузерный new WebSocket не позволяет задавать пользовательские заголовки. Либо передайте токен через параметры субпротокола, либо проксируйте WebSocket через собственный бэкенд (рекомендуется — токен не попадает на фронтенд).
Формат сообщений
Все сообщения — текстовые кадры JSON с полем type.
Настройка сессии
После подключения сервер отправляет session.created. Клиенты обычно сначала отправляют session.update, чтобы настроить голос и детекцию реплик:
{
"type": "session.update",
"session": {
"instructions": "You are a voice assistant. Keep answers short.",
"voice": "alloy",
"input_audio_format": "pcm16",
"output_audio_format": "pcm16",
"input_audio_transcription": { "model": "whisper-1" },
"turn_detection": { "type": "server_vad" }
}
}
Отправка пользовательского аудио
Аудио отправляется фрагментами в виде Base64-кодированного PCM16 (24 кГц, моно):
{ "type": "input_audio_buffer.append", "audio": "<base64 pcm16>" }
{ "type": "input_audio_buffer.commit" }
При включённом server_vad сервер сам определяет конец речи и выполняет фиксацию автоматически — вручную вызывать commit не нужно.
Запуск ответа
{
"type": "response.create",
"response": { "modalities": ["text", "audio"], "instructions": "Be enthusiastic." }
}
События сервера
| Событие | Описание |
|---|---|
session.created / session.updated | Сессия создана / конфигурация применена |
input_audio_buffer.speech_started / _stopped | VAD обнаружил начало / конец речи |
input_audio_buffer.committed | Аудиобуфер зафиксирован |
conversation.item.created | Создан элемент диалога |
response.audio_transcript.delta / _done | Дельта / завершение транскрипта ответа |
response.audio.delta / _done | Дельта аудио ответа (Base64 PCM16) |
response.text.delta / _done | Дельта текстового ответа (только текст) |
response.done | Текущий ответ завершён |
error | Событие ошибки |
Полный пример последовательности
const ws = new WebSocket(url);
ws.onopen = () => {
ws.send(JSON.stringify({
type: 'session.update',
session: { voice: 'alloy', turn_detection: { type: 'server_vad' } },
}));
// send an audio chunk…
ws.send(JSON.stringify({
type: 'input_audio_buffer.append',
audio: btoa(String.fromCharCode(...pcmChunk)),
}));
};
ws.onmessage = (event) => {
const msg = JSON.parse(event.data);
switch (msg.type) {
case 'response.audio.delta':
playPcmChunk(atob(msg.delta));
break;
case 'response.audio_transcript.delta':
appendSubtitle(msg.delta);
break;
case 'response.done':
console.log('turn finished', msg.response.usage);
break;
}
};
Realtime-эндпоинты тарифицируются по длительности аудио и обходятся заметно дороже текста. Во время тестирования следите за длительностью сессии. Доступность зависит от моделей, настроенных в вашем канале.