Escolha a API que seu aplicativo usa. Cada API tem seus próprios mecanismos de autenticação e criação de sessões, além de seu próprio contrato de eventos.
Conecte um servidor ao GPT-Live
Use um WebSocket principal quando seu servidor capturar áudio ou retransmitir um fluxo de áudio para um cliente. Ele transporta áudio e eventos JSON nas duas direções. Mantenha a chave de API do projeto nesse servidor confiável. Para aplicativos de navegador e dispositivos móveis, comece com WebRTC.
Este guia aborda a conexão principal de áudio. Uma conexão de banda lateral permite que um servidor observe e controle uma sessão Live existente. Um WebSocket da Responses conecta seu backend à API Responses para raciocínio e ferramentas. Nenhuma dessas conexões substitui a conexão principal de áudio.
Autentique-se e inicie a sessão
- Conecte-se a
wss://api.openai.com/v1/live/sessionssem parâmetros de consulta. Autentique-se comAuthorization: Bearer $OPENAI_API_KEYe inclua os cabeçalhos de conexão mostrados no exemplo. - Envie
session.startcomo a primeira mensagem. Coloque o modelo, as instruções da conversa, o formato de áudio, a voz e a configuração de delegação dentro do objetosession. - Aguarde
session.startedantes de enviar áudio ou comandos do aplicativo. Esse evento contém a configuração efetiva da sessão e o ID da sessão.
O exemplo abaixo usa Marin, áudio PCM16 a 24 kHz e um backend da Responses com pesquisa na Web. Mantenha as instruções da conversa curtas. Configure as instruções do backend, as ferramentas e as permissões das ferramentas conforme descrito em Delegação e ferramentas.
Transmita áudio com um SDK
Para Node.js, instale openai e ws com npm install openai ws e salve o exemplo JavaScript como client.mjs. Para Python no macOS ou Linux, instale openai[realtime] e salve o exemplo Python como client.py. Defina OPENAI_API_KEY no ambiente do servidor. Esses exemplos exigem uma versão do SDK com suporte ao Live. O exemplo lê áudio PCM16 bruto, mono, a 24 kHz da entrada padrão e grava o áudio retornado no mesmo formato na saída padrão. Conecte esses fluxos à captura e à reprodução de áudio do seu aplicativo. Os logs e os eventos de transcrição são enviados para a saída de erro padrão para não corromper o fluxo de áudio.
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;
}
});Execute node client.mjs ou python client.py com sua fonte de áudio e seu reprodutor conectados. Depois que Session ready aparecer, forneça um fluxo contínuo do microfone no ritmo da taxa de amostragem usada na gravação. Enviar um arquivo inteiro de uma só vez por um pipe não simula um microfone ao vivo. O EOF na fonte de áudio não encerra a conversa. Envie SIGINT ao processo para solicitar um encerramento normal.
O exemplo conecta os fluxos de áudio; seu aplicativo cuida da captura, do armazenamento em buffer, da reprodução e da reamostragem, quando necessária. Teste essas partes com seus dispositivos e sua rede antes de avaliar o comportamento do modelo.
Escolha o formato de áudio
Defina session.audio.format na inicialização. Um único formato se aplica tanto à entrada quanto à saída e não pode mudar durante a sessão.
{"type":"audio/pcm","rate":24000}: PCM mono de 16 bits com sinal, little-endian, a 24 kHz; o padrão.{"type":"audio/pcm","rate":16000}: PCM mono de 16 bits com sinal, little-endian, a 16 kHz.{"type":"audio/pcmu","rate":8000}: G.711 μ-law a 8 kHz, um byte por amostra.{"type":"audio/pcma","rate":8000}: G.711 A-law a 8 kHz, um byte por amostra.
Codifique os bytes brutos em base64, sem cabeçalho WAV ou de outro contêiner. Os blocos PCM devem conter amostras completas de 16 bits, portanto seu tamanho em bytes deve ser par. O exemplo transfere um byte restante no final para o próximo bloco de entrada. Fora isso, os limites dos blocos são arbitrários: preserve um fluxo contínuo e ordenado.
Reamostre o áudio quando sua taxa de amostragem for diferente da taxa configurada. Alterar a configuração de formato não converte os bytes de entrada. Para adaptar o exemplo ao G.711, encaminhe os bytes do codec de cada bloco sem a lógica de alinhamento de dois bytes específica do PCM e configure o reprodutor de saída para o mesmo codec. Um fluxo G.711 compatível pode passar sem conversão para PCM. Consulte Integrações de telefonia para conectar uma chamada telefônica.
Envie e receba eventos
Envie cada evento como uma mensagem de texto JSON. O áudio é transportado em base64 dentro dessas mensagens.
- Envie áudio: envie
session.input_audio.appendcom bytes brutos codificados em base64 emaudio. As operações de acréscimo de áudio não recebem confirmação. - Receba áudio: decodifique
deltade cada eventosession.output_audio.deltae coloque o áudio na fila para reprodução em ordem, usando o formato configurado. - Receba transcrições: acrescente o texto de
deltados eventossession.input_transcript.deltaesession.output_transcript.deltaà transcrição correspondente. - Receba eventos do backend: ao usar a delegação para a Responses, processe o
eventaninhado em cada enveloperesponse.event. - Trate erros: trate comandos rejeitados e erros de sessão informados nos eventos
error. Useerror.client_event_id, quando presente, para identificar o comando.
Os eventos de áudio de saída não têm campos de tempo, e o GPT-Live não emite um evento output-audio-done. Acompanhe sua fila de reprodução para saber qual áudio recebido já foi reproduzido. Os carimbos de data/hora das transcrições descrevem intervalos na linha do tempo da sessão; eles não indicam a conclusão da reprodução do áudio. A conclusão de uma resposta do backend também não significa que o assistente terminou de falar.
O GPT-Live gerencia quando ouvir e falar durante a transmissão de áudio. Ele não usa o ciclo de turnos de voz do Realtime, baseado na confirmação do buffer de entrada e em response.create. No Live, response.create inicia ou continua o trabalho delegado ao backend. Consulte Delegação e ferramentas para conhecer esse fluxo de trabalho.
Configure uma sessão em andamento
O modelo Live, as instruções iniciais da conversa, o formato de áudio, a voz e o modo de delegação são fixados na inicialização. Use session.update para alterar as configurações compatíveis com o modo de delegação existente; as configurações omitidas mantêm seus valores atuais. Uma atualização bem-sucedida retorna session.updated com a configuração efetiva da sessão.
Use session.instructions.append para adicionar instruções à conversa e session.input_audio.mute ou session.input_audio.unmute para controlar o áudio de entrada. Silenciar a entrada não cancela o trabalho do backend nem interrompe a fala gerada. Consulte Gerenciamento de sessões para saber mais sobre atualizações de contexto, transcrições, controles de entrada e uso.
Encerre a sessão
Envie session.close quando a conversa terminar. Primeiro, registre o ouvinte de session.closed, continue recebendo até esse evento chegar e, então, libere a conexão. O exemplo aguarda até 15 segundos e informa que a finalização ficou incompleta se o evento de encerramento não chegar.
Preserve os dados finais de uso de voz de session.closed e os eventos de uso do backend já recebidos. As atualizações de duração de voz são registros cumulativos; não some seus valores. Uma falha de transporte ou um tempo limite excedido antes de session.closed deixa o uso final sem confirmação. Consulte Gerenciamento de sessões para conhecer o ciclo de vida completo.
WebSockets são uma API amplamente compatível para transferência de dados em tempo real e uma ótima opção para conectar-se à Realtime API da OpenAI em aplicativos com comunicação entre servidores. Para clientes de navegador e dispositivos móveis, recomendamos a conexão via WebRTC.
Em uma integração entre servidores com o Realtime, seu sistema de backend se conectará via WebSocket diretamente à Realtime API. Você pode usar uma chave de API padrão para autenticar essa conexão, pois o token estará disponível apenas no seu servidor de backend seguro.
Conecte-se via WebSocket
Abaixo estão vários exemplos de conexão via WebSocket com a Realtime API. Além de usar a URL do WebSocket abaixo, você também precisará passar um cabeçalho de autenticação com sua chave de API da OpenAI. Se seu aplicativo atribuir identificadores de segurança, passe o identificador estável do usuário final que preserva sua privacidade no cabeçalho OpenAI-Safety-Identifier.
É possível usar WebSocket em navegadores com um token de API efêmero, conforme mostrado no guia de conexão WebRTC, mas, se você estiver se conectando a partir de um cliente como um navegador ou aplicativo móvel, o WebRTC será uma solução mais robusta na maioria dos 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()Instale as gems necessárias com
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);
});Envio e recebimento de eventos
As sessões da Realtime API são gerenciadas por uma combinação de eventos enviados pelo cliente, emitidos por você como desenvolvedor, e eventos enviados pelo servidor, criados pela Realtime API para indicar eventos do ciclo de vida da sessão.
Por uma conexão WebSocket, você envia e recebe eventos serializados em JSON como strings de texto, conforme o exemplo em Node.js abaixo (os mesmos princípios se aplicam a outras bibliotecas 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()));
});A interface WebSocket talvez seja a interface de mais baixo nível disponível para interagir com um modelo Realtime. Nela, você é responsável tanto por enviar quanto por processar blocos de áudio codificados em Base64 pela conexão de socket.
Para aprender a enviar e receber áudio por WebSockets, consulte o guia de conversas com a Realtime API.