Skip to main content

Introdução

A conversa em tempo real estabelece uma conexão persistente via WebSocket (um protocolo que mantém uma conexão duradoura e bidirecional entre o cliente e o servidor), envia seu áudio ou texto ao modelo de conversa em tempo real e o modelo devolve texto e voz de forma incremental. É adequada para assistentes de voz, perguntas e respostas em tempo real, prática de fala e outros cenários que exigem interação de ida e volta. Assim como a transcrição em tempo real, ela funciona sobre WebSocket, mas os usos são diferentes: Modelo disponível:
  • gpt-realtime-2.1: modelo de conversa por voz, suporta entrada de áudio e texto e produz respostas de texto e voz em tempo real.
Esta API é destinada à integração no lado do servidor; navegadores não podem se conectar diretamente. Por motivos de segurança, o gateway valida e rejeita conexões que carregam um cabeçalho Origin, rejeita o subprotocolo openai-insecure-api-key e aceita a chave apenas pelo cabeçalho padrão Authorization. Um WebSocket iniciado pelo navegador anexa automaticamente um cabeçalho Origin e, portanto, é rejeitado. Se você precisar de conversa em tempo real no frontend, estabeleça a conexão com o gateway a partir do seu próprio servidor e encaminhe o áudio e os resultados entre o frontend e o servidor.

Início rápido

Endpoint de conexão

  • model=gpt-realtime-2.1: obrigatório, o modelo é fixado no momento da conexão pelo parâmetro da URL e não pode mais ser alterado durante a sessão (veja as restrições abaixo).
  • Atenção à diferença em relação à transcrição: o endpoint de conversa não leva intent=transcription.

Autenticação

Envie a chave em um cabeçalho HTTP padrão durante o handshake:

Requisitos de formato de áudio

O áudio de entrada e de saída suporta atualmente apenas um formato. Converta seu áudio antes de enviar:
  • Codificação: PCM16 (inteiro com sinal de 16 bits, little-endian)
  • Taxa de amostragem: 24000 Hz
  • Canais: mono
Ou seja, audio/pcm@24000. Declarar outro formato (como G.711/µ-law) na entrada ou na saída é rejeitado e encerra a sessão.
Diferente da transcrição, as sessões de conversa suportam detecção de atividade de voz (turn_detection / VAD). Quando ativada, o modelo determina automaticamente o fim de uma fala e dispara uma resposta; quando desativada (valor null), você controla quando confirmar o áudio e quando solicitar uma resposta. Escolha conforme a necessidade.

Configuração da sessão (session.update)

Após a conexão ser estabelecida, o cliente pode enviar um quadro session.update para configurar parâmetros da conversa (voz, instruções do sistema, se o VAD está ativo). O modelo da sessão de conversa já está ancorado pela URL de conexão, portanto você pode conversar sem enviar session.update; envie quando precisar de uma voz ou instruções personalizadas.

Parâmetros de configuração

string
obrigatório
Tipo de sessão, realtime para o cenário de conversa.
string
Instruções do sistema que definem o papel, o tom e as restrições de resposta do modelo.
string[]
Modalidades de saída, ["audio"] ou ["text"]: com ["audio"] (padrão) o modelo gera voz e o texto da resposta chega pelo evento response.output_audio_transcript.delta; com ["text"] ele gera apenas texto, entregue por response.output_text.delta. Qualquer outra combinação (por exemplo ["audio", "text"]) é rejeitada e retorna um evento error.
object
obrigatório
Formato do áudio de entrada, fixado em { "type": "audio/pcm", "rate": 24000 }.
object | null
Detecção de atividade de voz. Envie { "type": "server_vad" } para ativar a detecção automática de turnos; envie null para desativá-la e confirmar o áudio e solicitar respostas manualmente pelo cliente.
object
obrigatório
Formato do áudio de saída, fixado em { "type": "audio/pcm", "rate": 24000 }.
string
Voz da resposta de áudio. Ela não pode ser alterada depois do início da primeira resposta: quando a sessão entra em estado de geração, um voice enviado novamente é ignorado (os demais ajustes continuam valendo). Portanto, se precisar de uma voz específica, defina-a antes de solicitar a primeira resposta.
As capacidades a seguir não são suportadas nesta versão e fecham a sessão quando configuradas (código de fechamento 1008): ativar a transcrição embutida dentro de uma sessão de conversa (audio.input.transcription, motivo input_transcription_not_supported), injetar áudio (motivo item_audio_not_supported) ou imagens (motivo image_input_not_supported) pelos itens de conversa, e qualquer tipo de item de conteúdo diferente de texto (motivo unsupported_content_part). Envie todo o áudio pelo canal input_audio_buffer.append.

Envio de entrada

Envio de áudio

Divida o áudio PCM16 em pequenos fragmentos (por exemplo, um a cada 100 ms), codifique-os em base64 e envie-os continuamente com o evento input_audio_buffer.append:
Com o VAD ativado, o modelo detecta o fim de uma fala e dispara uma resposta automaticamente. Com o VAD desativado, após enviar um trecho de áudio você deve confirmar e solicitar uma resposta manualmente:

Envio de texto

Você também pode injetar diretamente uma mensagem de texto e então solicitar uma resposta:

Recebimento de respostas

O servidor continua enviando eventos. Tipos de evento principais:
event
Confirmação de que a sessão foi criada ou de que sua configuração foi atualizada. Você pode começar a enviar áudio e texto ao receber session.created.
event
Um item de conversa foi gravado: cada entrada do usuário e cada resposta do modelo adicionam um item.
event
Com a VAD ativada, o servidor detectou que o usuário começou ou parou de falar. Um evento speech_started geralmente significa que o usuário está interrompendo o modelo; consulte Interrupção e truncamento.
event
Uma resposta começou a ser gerada.
event
O item de saída da resposta começou e terminou. O campo item.id do evento added é o ID do item de conversa que você referencia ao truncar o áudio depois.
event
Um trecho incremental do áudio da resposta (PCM16 codificado em base64) e sua marca de fim, que você pode reproduzir conforme chega.
event
A transcrição incremental correspondente ao áudio da resposta, frase por frase, e sua marca de fim; o campo delta contém o texto adicionado. Quando a saída inclui áudio, obtenha o texto da resposta neste evento, por exemplo para exibir legendas enquanto o áudio é reproduzido.
event
Um trecho incremental de uma resposta somente texto e sua marca de fim, emitidos apenas quando a modalidade de saída é somente texto (output_modalities: ["text"]).
event
Uma resposta terminou. Este evento carrega o uso de tokens do turno (usage), que é a base da cobrança.
event
Confirmação de que a solicitação de truncamento teve efeito; consulte Interrupção e truncamento.
event
Evento de erro, com código e descrição. Um problema da própria solicitação (por exemplo um valor output_modalities inválido) retorna um único evento error e a sessão continua utilizável; questões de política (troca de modelo, saldo esgotado) fecham a sessão.
Escolha o evento certo para o texto da resposta. Por padrão (saída com áudio) o modelo envia apenas response.output_audio_transcript.delta e não envia response.output_text.delta; defina a modalidade de saída como somente texto e o texto passa para response.output_text.delta. Escute os dois em qualquer um dos modos para não perder texto (veja a saída medida abaixo).

Interrupção e truncamento

Quando o usuário começa a falar enquanto o modelo fala, o conteúdo já gerado mas ainda não reproduzido entra em conflito com a próxima frase do usuário. Em uma conexão WebSocket a reprodução é responsabilidade do cliente, então o cliente também conclui a limpeza após uma interrupção. Com a VAD ativada, o servidor envia input_audio_buffer.speech_started assim que detecta que o usuário começou a falar. Ao receber esse evento, o cliente deve:
  1. Parar imediatamente a reprodução local e registrar até onde a resposta já havia sido reproduzida (em milissegundos).
  2. Enviar conversation.item.truncate para remover da conversa o áudio não reproduzido, para que o modelo não o trate como dito no turno seguinte.
  • item_id: o ID do item de conversa desta resposta, obtido de item.id no evento response.output_item.added.
  • content_index: o índice da parte de conteúdo de áudio, sempre 0.
  • audio_end_ms: o comprimento de áudio a manter, em milissegundos, conforme a posição realmente reproduzida pelo cliente.
O servidor responde com conversation.item.truncated quando a solicitação é processada. O truncamento afeta apenas o áudio desta resposta e a transcrição correspondente; a sessão não é afetada e você pode seguir para o próximo turno. Com o SDK da OpenAI, chame conn.conversation.item.truncate(item_id=..., content_index=0, audio_end_ms=...). Com a VAD desativada (por exemplo, apertar para falar), o toque no botão é a interrupção: envie response.cancel para cancelar a resposta em andamento e trunque conforme descrito acima; ao soltar, envie input_audio_buffer.append, input_audio_buffer.commit e response.create nessa ordem.

Exemplos completos

Abaixo são mostradas três abordagens; escolha uma:
  • SDK oficial da OpenAI (recomendado): sem precisar escrever os quadros WebSocket à mão; aponte websocket_base_url (o parâmetro de URL base de WebSocket do SDK) para o gateway e reutilize a biblioteca oficial.
  • SDK oficial da OpenAI Agents: a forma de voz em tempo real do framework de agentes oficial; troque a url de model_config pelo endereço do gateway.
  • websockets puro: sem SDK, troque quadros diretamente conforme o protocolo. Menos dependências e mais fácil de depurar.
Por que passar o nome do modelo na conexão? O gateway da AiHubMix precisa do model no momento do handshake WebSocket para selecionar o provedor de modelos, autenticar e reservar cota, enquanto o session.update chega apenas depois que o handshake termina. Por isso, com um SDK você deve passar model explicitamente para connect() (o SDK o insere na consulta da URL); sem ele, o gateway rejeita durante o handshake e nenhuma conexão é estabelecida. Diferente da transcrição, o endpoint de conversa não precisa de intent=transcription.
Para converter qualquer áudio no formato PCM bruto exigido por esta API, use o ffmpeg:

Reutilizar exemplos oficiais

A maioria dos exemplos de conversa em tempo real publicados pela OpenAI depende apenas do parâmetro de URL base do SDK, então você pode reutilizá-los apontando o endereço para o endpoint da AiHubMix:

Saída medida (em produção)

A seguir está o resultado real do exemplo do SDK da OpenAI no ambiente de produção aihubmix.com com o modelo gpt-realtime-2.1. A sessão ativa server_vad, e tanto os prompts quanto o áudio estão em inglês. Entrada de texto
Entrada de áudio
Diferença medida entre duas configurações
Confirmação medida: por padrão (saída com áudio) o texto da resposta chega caractere por caractere apenas por response.output_audio_transcript.delta, e response.output_text.delta nunca aparece; o response.done carrega o usage do turno; o handshake leva de 2 a 4 segundos, o custo da reserva de cota ao estabelecer a sessão.

Cobrança

  • Cobrança por token: uma sessão de conversa devolve o uso de tokens de cada turno (usage) com o evento response.done, e a cobrança se baseia nele. O uso é medido separadamente por componente, incluindo entrada de áudio, saída de áudio, entrada de texto e saída de texto. O preço unitário de cada componente segue o preço exibido em tempo real na página de detalhes do modelo.
  • Liquidação conforme o uso: esta é uma conexão de longa duração, e os valores são descontados em tempo real a cada turno durante a sessão, sem uma liquidação única no final. Ao estabelecer a sessão é feita primeiro uma reserva de cota de aproximadamente um minuto de uso (apenas uma verificação de admissão, não uma cobrança real), e a reserva restante é liberada ao final da sessão. Portanto, o saldo disponível da sua conta precisa cobrir pelo menos cerca de um minuto de uso para que a sessão seja estabelecida.
  • Cada registro de cobrança de conversa em tempo real pode ser consultado item por item em Uso e faturamento.

Limites e restrições

  1. Duração da sessão: uma conexão WebSocket dura no máximo 62 minutos, após o que o servidor a encerra (código de fechamento 1000, motivo session_duration_limit); divida em segmentos se precisar de mais tempo.
  2. Desconexão por inatividade: quando nem o cliente nem o modelo têm atividade por 5 minutos, o servidor fecha a sessão (código de fechamento 1008, motivo idle_timeout). A atividade de qualquer um dos lados reinicia o cronômetro, então uma resposta longa que continua sendo transmitida não é interrompida.
  3. Saldo insuficiente: ao estabelecer a sessão, se o saldo disponível não cobrir a reserva de aproximadamente um minuto, o handshake é rejeitado de imediato (HTTP 403) e nenhuma sessão é estabelecida; durante a sessão, se o saldo se esgotar, a conexão estabelecida é encerrada imediatamente.
  4. Somente no lado do servidor: conexões diretas do navegador não são suportadas (o cabeçalho Origin é validado); integre a partir do seu servidor.
  5. Modelo fixado: o modelo é fixado na URL de conexão, e alterá-lo com session.update durante a sessão é rejeitado e encerra a sessão.
  6. Formato fixado: o áudio de entrada e de saída suporta apenas audio/pcm@24000 mono; outros formatos são rejeitados.
  7. Voz fixada: o voice não pode ser alterado depois do início da primeira resposta; defina-o antes de solicitar a primeira resposta.
  8. Não suportado: a transcrição embutida dentro de uma sessão de conversa, a injeção de conteúdo de áudio ou imagem pelos itens de conversa e qualquer tipo de item de conteúdo diferente de texto.
  9. Uma resposta por vez: uma sessão permite apenas uma resposta em andamento; enviar outro response.create antes de o turno atual terminar é rejeitado e fecha a sessão (código de fechamento 1008, motivo response_already_active).

Erros comuns


Última atualização: 2026-09-21