Elige la API que usa tu aplicación. Cada API tiene sus propios mecanismos de autenticación y creación de sesiones, y su propio contrato de eventos.
Conecta un servidor a GPT-Live
Usa un WebSocket principal cuando tu servidor capture audio o retransmita un flujo de audio para un cliente. Transporta audio y eventos JSON en ambas direcciones. Mantén la clave de API del proyecto en ese servidor de confianza. Para aplicaciones móviles y de navegador, comienza con WebRTC.
Esta guía aborda la conexión principal de audio. Una conexión de banda lateral permite que un servidor observe y controle una sesión de Live existente. Un WebSocket de Responses conecta tu backend a la API Responses para usar razonamiento y herramientas. Ninguna de estas conexiones reemplaza la conexión principal de audio.
Autentícate e inicia la sesión
- Conéctate a
wss://api.openai.com/v1/live/sessionssin parámetros de consulta. Autentícate conAuthorization: Bearer $OPENAI_API_KEYe incluye los encabezados de conexión que se muestran en el ejemplo. - Envía
session.startcomo primer mensaje. Incluye el modelo, las instrucciones de conversación, el formato de audio, la voz y la configuración de delegación dentro del objetosession. - Espera a recibir
session.startedantes de enviar audio o comandos de la aplicación. Contiene la configuración resuelta de la sesión y su ID.
El siguiente ejemplo usa Marin, audio PCM16 a 24 kHz y un backend de Responses con búsqueda web. Mantén breves las instrucciones de conversación. Configura las instrucciones del backend, las herramientas y sus permisos siguiendo Delegación y herramientas.
Transmite audio con un SDK
Para Node.js, instala openai y ws con npm install openai ws y guarda el ejemplo de JavaScript como client.mjs. Para Python en macOS o Linux, instala openai[realtime] y guarda el ejemplo de Python como client.py. Define OPENAI_API_KEY en el entorno del servidor. Estos ejemplos requieren una versión del SDK compatible con Live. El ejemplo lee audio PCM16 mono sin procesar a 24 kHz desde la entrada estándar y escribe el audio recibido en el mismo formato en la salida estándar. Conecta estos flujos a la captura y reproducción de audio de tu aplicación. Los registros y los eventos de transcripción se envían a la salida de error estándar para que no corrompan el flujo de audio.
import OpenAI from "openai";
import { LiveWS } from "openai/resources/live/ws";
// stdin and stdout carry raw mono PCM16 audio at 24 kHz, not WAV files.
// Supply microphone bytes continuously and play stdout in the same format.
process.stdin.pause();
const ws = new LiveWS(new OpenAI());
let started = false;
let closing = false;
let finalized = false;
let pendingByte = Buffer.alloc(0);
let closeTimeout;
ws.socket.on("open", () => {
ws.send({
type: "session.start",
event_id: "event_start",
session: {
model: "gpt-live-1",
instructions:
"Be concise. Delegate requests needing current information to the backend, which can search the web.",
audio: {
format: { type: "audio/pcm", rate: 24000 },
output: { voice: "marin" },
},
delegation: {
type: "responses",
responses: {
model: "gpt-5.6-luna",
tools: [{ type: "web_search" }],
tool_choice: "auto",
},
},
},
});
});
process.stdin.on("data", (chunk) => {
if (!started || closing || ws.socket.readyState !== 1) return;
const bytes = Buffer.concat([pendingByte, chunk]);
const completeLength = bytes.length - (bytes.length % 2);
pendingByte = bytes.subarray(completeLength);
if (completeLength) {
ws.send({
type: "session.input_audio.append",
audio: bytes.subarray(0, completeLength).toString("base64"),
});
}
});
// Register the final-event handler before any close command can be sent.
ws.on("event", (event) => {
if (event.type === "session.started") {
started = true;
console.error("Session ready", event.session.id);
process.stdin.resume();
} else if (event.type === "session.output_audio.delta") {
process.stdout.write(Buffer.from(event.delta, "base64"));
} else if (event.type === "session.closed") {
finalized = true;
clearTimeout(closeTimeout);
process.stdin.pause();
console.error("Final session usage", event.usage);
ws.close();
} else {
// Includes transcript deltas and nested response.event usage.
console.error(JSON.stringify(event));
}
});
process.on("SIGINT", () => {
if (closing) return;
if (!started || ws.socket.readyState !== 1) {
ws.socket.platformSocket.terminate();
return;
}
closing = true;
process.stdin.pause();
ws.send({ type: "session.close" });
closeTimeout = setTimeout(() => {
console.error("Incomplete finalization: session.closed was not received");
process.exitCode = 1;
ws.socket.platformSocket.terminate();
}, 15_000);
});
ws.on("error", (error) => {
console.error(error.message);
process.exitCode = 1;
});
ws.socket.on("close", () => {
clearTimeout(closeTimeout);
process.stdin.pause();
if (!finalized) {
console.error("Connection closed without final session usage");
process.exitCode = 1;
}
});Ejecuta node client.mjs o python client.py con la fuente de audio y el reproductor conectados. Después de que aparezca Session ready, proporciona un flujo continuo de micrófono al ritmo de la frecuencia de muestreo con la que se grabó. Enviar un archivo completo de una sola vez por una tubería no simula un micrófono en vivo. Un EOF en la fuente de audio no finaliza la conversación. Envía SIGINT al proceso para solicitar un cierre ordenado.
El ejemplo conecta los flujos de audio; tu aplicación se encarga de la captura, el almacenamiento en búfer, la reproducción y el remuestreo cuando sea necesario. Prueba estos componentes con tus dispositivos y tu red antes de evaluar el comportamiento del modelo.
Elige el formato de audio
Define session.audio.format al iniciar. Se aplica un mismo formato tanto a la entrada como a la salida y no se puede cambiar durante la sesión.
{"type":"audio/pcm","rate":24000}: PCM mono de 16 bits con signo en orden little-endian a 24 kHz; es el formato predeterminado.{"type":"audio/pcm","rate":16000}: PCM mono de 16 bits con signo en orden little-endian a 16 kHz.{"type":"audio/pcmu","rate":8000}: G.711 μ-law a 8 kHz, un byte por muestra.{"type":"audio/pcma","rate":8000}: G.711 A-law a 8 kHz, un byte por muestra.
Codifica en base64 los bytes sin procesar, sin encabezado WAV ni de otro contenedor. Los fragmentos PCM deben contener muestras completas de 16 bits, por lo que su longitud en bytes debe ser par. El ejemplo traslada el byte sobrante al siguiente fragmento de entrada. Fuera de ese requisito, los límites de los fragmentos son arbitrarios: mantén un flujo continuo y ordenado.
Remuestrea el audio cuando su frecuencia de muestreo difiera de la frecuencia configurada. Cambiar la configuración del formato no convierte los bytes de entrada. Para adaptar el ejemplo a G.711, reenvía los bytes del códec de cada fragmento sin la lógica de alineación de dos bytes específica de PCM y configura el reproductor de salida para el mismo códec. Un flujo G.711 que coincida con la configuración puede pasar sin convertirse a PCM. Consulta Integraciones de telefonía para conectar una llamada telefónica.
Envía y recibe eventos
Envía cada evento como un mensaje de texto JSON. El audio se transmite en base64 dentro de esos mensajes.
- Envía audio: envía
session.input_audio.appendcon bytes sin procesar codificados en base64 enaudio. Las operaciones de adición de audio no reciben confirmación. - Recibe audio: decodifica
deltade cada eventosession.output_audio.deltay coloca el audio en una cola para reproducirlo en orden con el formato configurado. - Recibe transcripciones: agrega el texto de
deltade los eventossession.input_transcript.deltaysession.output_transcript.deltaa la transcripción correspondiente. - Recibe eventos del backend: cuando uses la delegación a Responses, procesa el
eventanidado en cada mensaje contenedorresponse.event. - Maneja los errores: maneja los comandos rechazados y los errores de sesión a partir de los eventos
error. Usaerror.client_event_id, cuando esté presente, para identificar el comando.
Los eventos de audio de salida no tienen campos de tiempo y GPT-Live no emite un evento output-audio-done. Lleva un control de la cola de reproducción para saber qué audio recibido ya se reprodujo. Las marcas de tiempo de las transcripciones describen intervalos en la línea de tiempo de la sesión; no indican que la reproducción del audio haya terminado. Que se complete una respuesta del backend tampoco significa que el asistente haya terminado de hablar.
GPT-Live administra cuándo escuchar y hablar mientras se transmite el audio. No usa el ciclo de turnos de voz de Realtime basado en la confirmación del búfer de entrada y response.create. En Live, response.create inicia o continúa el trabajo delegado al backend. Consulta Delegación y herramientas para conocer ese flujo de trabajo.
Configura una sesión en curso
El modelo de Live, las instrucciones iniciales de conversación, el formato de audio, la voz y el modo de delegación quedan fijos al iniciar. Usa session.update para los ajustes admitidos dentro del modo de delegación existente; los ajustes omitidos conservan sus valores actuales. Una actualización exitosa devuelve session.updated con la configuración resuelta de la sesión.
Usa session.instructions.append para agregar instrucciones de conversación y session.input_audio.mute o session.input_audio.unmute para controlar el audio entrante. Silenciar la entrada no cancela el trabajo del backend ni detiene la voz generada. Consulta Administración de sesiones para obtener información sobre las actualizaciones de contexto, las transcripciones, los controles de entrada y el uso.
Cierra la sesión
Envía session.close cuando termine la conversación. Primero registra el listener de session.closed, sigue recibiendo hasta que llegue ese evento y luego libera la conexión. El ejemplo espera hasta 15 segundos e informa que la finalización quedó incompleta si el evento final nunca llega.
Conserva los datos finales de uso de voz de session.closed y los eventos de uso del backend que ya recibiste. Las actualizaciones de duración de voz son instantáneas acumulativas; no las sumes. Si se produce una falla de transporte o se agota el tiempo de espera antes de recibir session.closed, el uso final queda sin confirmar. Consulta Administración de sesiones para conocer el ciclo de vida completo.
WebSockets es una API ampliamente compatible para transferir datos en tiempo real y una excelente opción para conectarse a la Realtime API de OpenAI en aplicaciones con comunicación entre servidores. Para clientes móviles y de navegador, recomendamos conectarse a través de WebRTC.
En una integración entre servidores con Realtime, tu sistema backend se conectará por WebSocket directamente a la Realtime API. Puedes usar una clave de API estándar para autenticar esta conexión, ya que el token solo estará disponible en tu servidor backend seguro.
Conéctate por WebSocket
A continuación se muestran varios ejemplos de conexión por WebSocket a la Realtime API. Además de usar la URL de WebSocket que se muestra a continuación, también deberás enviar un encabezado de autenticación con tu clave de API de OpenAI. Si tu aplicación asigna identificadores de seguridad, envía el identificador estable que preserva la privacidad del usuario final en el encabezado OpenAI-Safety-Identifier.
Es posible usar WebSocket en navegadores con un token de API efímero, como se muestra en la guía de conexión con WebRTC, pero si te conectas desde un cliente como un navegador o una aplicación móvil, WebRTC será una solución más robusta en la mayoría de los casos.
import WebSocket from "ws";
const url = "wss://api.openai.com/v1/realtime?model=gpt-realtime-2.1";
const ws = new WebSocket(url, {
headers: {
Authorization: "Bearer " + process.env.OPENAI_API_KEY,
"OpenAI-Safety-Identifier": "hashed-user-id",
},
});
ws.on("open", function open() {
console.log("Connected to server.");
});
ws.on("message", function incoming(message) {
console.log(JSON.parse(message.toString()));
});# example requires websocket-client library:
# pip install websocket-client
import os
import json
import websocket
OPENAI_API_KEY = os.environ["OPENAI_API_KEY"]
url = "wss://api.openai.com/v1/realtime?model=gpt-realtime-2.1"
headers = [
"Authorization: Bearer " + OPENAI_API_KEY,
"OpenAI-Safety-Identifier: hashed-user-id",
]
def on_open(ws):
print("Connected to server.")
def on_message(ws, message):
data = json.loads(message)
print("Received event:", json.dumps(data, indent=2))
ws = websocket.WebSocketApp(
url,
header=headers,
on_open=on_open,
on_message=on_message,
)
ws.run_forever()Instala las gemas necesarias con
gem install openai async-websocket.
require "openai"
client = OpenAI::Client.new(
default_headers: { "OpenAI-Safety-Identifier" => "hashed-user-id" }
)
client.realtime.connect(model: "gpt-realtime-2.1") do |connection|
puts("Connected to the Realtime API: #{connection.url.host}")
connection.each { |event| puts("Received event: #{event.type}") }
end/*
Note that in client-side environments like web browsers, we recommend
using WebRTC instead. It is possible, however, to use the standard
WebSocket interface in browser-like environments like Deno and
Cloudflare Workers.
*/
const ws = new WebSocket(
"wss://api.openai.com/v1/realtime?model=gpt-realtime-2.1",
[
"realtime",
// Use a short-lived token fetched from your application server.
"openai-insecure-api-key." + OPENAI_REALTIME_EPHEMERAL_KEY,
// Optional
"openai-organization." + OPENAI_ORG_ID,
"openai-project." + OPENAI_PROJECT_ID,
]
);
ws.addEventListener("open", function open() {
console.log("Connected to server.");
});
ws.addEventListener("message", function incoming(event) {
console.log(event.data);
});Envío y recepción de eventos
Las sesiones de Realtime API se administran mediante una combinación de eventos enviados por el cliente, que tú emites como desarrollador, y eventos enviados por el servidor, que Realtime API crea para indicar eventos del ciclo de vida de la sesión.
A través de un WebSocket, enviarás y recibirás eventos serializados en JSON como cadenas de texto, tal como se muestra en el siguiente ejemplo de Node.js (los mismos principios se aplican a otras bibliotecas de WebSocket):
import WebSocket from "ws";
const url = "wss://api.openai.com/v1/realtime?model=gpt-realtime-2.1";
const ws = new WebSocket(url, {
headers: {
Authorization: "Bearer " + process.env.OPENAI_API_KEY,
"OpenAI-Safety-Identifier": "hashed-user-id",
},
});
ws.on("open", function open() {
console.log("Connected to server.");
// Send client events over the WebSocket once connected
ws.send(
JSON.stringify({
type: "session.update",
session: {
type: "realtime",
instructions: "Be extra nice today!",
},
})
);
});
// Listen for and parse server events
ws.on("message", function incoming(message) {
console.log(JSON.parse(message.toString()));
});La interfaz de WebSocket es quizás la interfaz de más bajo nivel disponible para interactuar con un modelo Realtime. Al usarla, serás responsable tanto de enviar como de procesar fragmentos de audio codificados en Base64 a través de la conexión de socket.
Para aprender a enviar y recibir audio a través de WebSockets, consulta la guía de conversaciones de Realtime.