Choisissez votre API pour afficher les étapes de connexion et les événements de session correspondants.
Connexion d’un serveur à GPT-Live
Nous recommandons WebRTC pour les connexions audio à GPT-Live, y compris pour les intégrations de serveur à serveur.
GPT-Live prend également en charge les connexions WebSocket. La connexion WebSocket principale transporte l’audio et les événements JSON dans les deux sens. Conservez la clé API du projet sur votre serveur de confiance.
Ce guide explique comment transmettre un flux audio à GPT-Live. Pour surveiller ou piloter une session existante, consultez Contrôles côté serveur. Pour connecter un backend chargé du raisonnement et de l’exécution des outils à l’API Responses, consultez Mode WebSocket de l’API Responses.
Authentification et démarrage de la session
- Connectez-vous à
wss://api.openai.com/v1/live/sessionssans paramètre de requête. Authentifiez-vous avecAuthorization: Bearer $OPENAI_API_KEYet incluez les en-têtes de connexion indiqués dans l’exemple. - Envoyez
session.startcomme premier message. Dans l’objetsession, indiquez le modèle, les instructions de conversation, le format audio, la voix et la configuration de la délégation. - Attendez l’événement
session.startedavant d’envoyer des données audio ou des commandes de l’application. Cet événement contient la configuration effective de la session et son identifiant.
L’exemple ci-dessous utilise la voix Marin, de l’audio PCM16 à 24 kHz et un backend Responses avec recherche web. Formulez des instructions de conversation courtes. Pour configurer les instructions du backend, ses outils et leurs autorisations, consultez Délégation et outils.
Transmission d’un flux audio avec un SDK
Pour Node.js, installez openai et ws avec npm install openai ws, puis enregistrez l’exemple JavaScript sous le nom client.mjs. Pour Python sur macOS ou Linux, installez openai[realtime], puis enregistrez l’exemple Python sous le nom client.py. Définissez OPENAI_API_KEY dans l’environnement du serveur. Ces exemples nécessitent une version du SDK compatible avec Live. L’exemple lit un flux audio brut PCM16 mono à 24 kHz sur l’entrée standard et écrit l’audio reçu dans le même format sur la sortie standard. Reliez ces flux aux fonctions de capture et de lecture audio de votre application. Les journaux et les événements de transcription sont écrits sur la sortie d’erreur standard pour préserver l’intégrité du flux audio.
Pour Go, utilisez Go 1.26 ou une version ultérieure, enregistrez l’exemple sous le nom main.go, initialisez un module avec go mod init live-demo, puis installez github.com/openai/openai-go/v3@v3.85.1 avec go get. Pour Java, utilisez Java 17 ou une version ultérieure, ajoutez la dépendance Maven com.openai:openai-java:4.95.0 et utilisez la classe LiveConnectionWebsocketExample. Pour Ruby 3.3 ou une version ultérieure, installez le SDK avec gem install openai -v 0.110.0, installez sa dépendance WebSocket avec gem install async-websocket, puis enregistrez l’exemple sous le nom client.rb.
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;
}
});Exécutez node client.mjs, python client.py, go run ., ruby client.rb ou votre application Java après avoir connecté votre source audio et votre lecteur. Une fois le message Session ready affiché, transmettez en continu l’audio du microphone au rythme de l’enregistrement, en respectant sa fréquence d’échantillonnage. Envoyer tout un fichier d’un seul coup via un tube ne simule pas un microphone en direct. La fin du flux (EOF) de la source audio ne met pas fin à la conversation. Envoyez SIGINT au processus pour demander une fermeture propre.
L’exemple relie les flux audio. Votre application assure la capture, la mise en mémoire tampon, la lecture et, si nécessaire, le rééchantillonnage. Testez ces fonctions avec vos appareils et votre réseau avant d’évaluer le comportement du modèle.
Choix du format audio
Définissez session.audio.format au démarrage. Le même format s’applique à l’entrée et à la sortie et reste fixe pendant toute la session.
{"type":"audio/pcm","rate":24000}: PCM mono signé sur 16 bits à 24 kHz, octet de poids faible en premier (format par défaut).{"type":"audio/pcm","rate":16000}: PCM mono signé sur 16 bits à 16 kHz, octet de poids faible en premier.{"type":"audio/pcmu","rate":8000}: G.711 loi μ à 8 kHz, un octet par échantillon.{"type":"audio/pcma","rate":8000}: G.711 loi A à 8 kHz, un octet par échantillon.
Encodez les octets bruts en base64, sans en-tête WAV ni en-tête d’un autre conteneur. Chaque bloc PCM doit contenir des échantillons complets de 16 bits et donc un nombre pair d’octets. S’il reste un octet en fin de bloc, l’exemple le reporte au début du bloc d’entrée suivant. Pour le reste, vous pouvez découper le flux librement, à condition de préserver sa continuité et l’ordre des données.
Rééchantillonnez l’audio si sa fréquence d’échantillonnage diffère de la fréquence configurée. Modifier le format dans la configuration ne convertit pas les octets d’entrée. Pour adapter l’exemple à G.711, transmettez les octets encodés de chaque bloc sans appliquer l’alignement sur deux octets propre au PCM, puis configurez le lecteur de sortie pour qu’il utilise le même codec. Un flux G.711 conforme à la configuration peut être transmis sans conversion en PCM. Pour connecter un appel téléphonique, consultez Intégrations téléphoniques.
Envoi et réception d’événements
Envoyez chaque événement dans un message texte au format JSON. Ces messages transportent l’audio encodé en base64.
- Envoi de l’audio : envoyez
session.input_audio.appenden plaçant les octets bruts encodés en base64 dansaudio. Les ajouts de données audio ne donnent lieu à aucun accusé de réception. - Réception de l’audio : décodez
deltadans chaque événementsession.output_audio.delta, puis placez les blocs audio dans la file de lecture dans l’ordre de réception, en utilisant le format configuré. - Réception des transcriptions : ajoutez le texte du champ
deltades événementssession.input_transcript.deltaetsession.output_transcript.deltaà la transcription correspondante. - Réception des événements du backend : si vous utilisez la délégation à Responses, traitez l’objet
eventimbriqué dans chaque envelopperesponse.event. - Gestion des erreurs : traitez les rejets de commandes et les erreurs de session signalés par les événements
error. Utilisezerror.client_event_id, s’il est présent, pour identifier la commande.
Suivez la lecture à l’aide de la file d’attente audio de votre application. La connexion WebSocket principale de GPT-Live transmet l’audio de sortie sans champs temporels ni événement signalant la fin de l’audio de sortie. Utilisez les horodatages des transcriptions pour organiser les sous-titres et les événements du backend pour suivre les tâches déléguées.
Pendant la transmission continue de l’audio, GPT-Live détermine quand écouter et quand prendre la parole. Utilisez response.create pour lancer ou poursuivre une tâche déléguée au backend. Pour en savoir plus sur cette procédure, consultez Délégation et outils.
Configuration d’une session en cours
Le modèle Live, les instructions de conversation initiales, le format audio, la voix et le mode de délégation sont fixés au démarrage. Utilisez session.update pour modifier les paramètres pris en charge dans le mode de délégation actuel. Les paramètres omis conservent leur valeur. Si la mise à jour réussit, vous recevez session.updated avec la configuration effective de la session.
Utilisez session.instructions.append pour ajouter des instructions de conversation et session.input_audio.mute ou session.input_audio.unmute pour couper ou réactiver l’entrée audio. Couper l’entrée audio n’annule pas les tâches du backend et n’interrompt pas la parole générée. Pour en savoir plus sur les mises à jour du contexte, les transcriptions, les commandes d’entrée et les données d’utilisation, consultez Gestion des sessions.
Fermeture de la session
Envoyez session.close à la fin de la conversation. Enregistrez au préalable un gestionnaire pour session.closed, continuez à recevoir les événements jusqu’à la réception de cet événement final, puis libérez la connexion. L’exemple attend jusqu’à 15 secondes et signale que la fermeture n’a pas abouti si l’événement final n’arrive pas.
Conservez les données finales d’utilisation de la voix fournies par session.closed ainsi que les événements d’utilisation du backend déjà reçus. Chaque mise à jour de la durée d’utilisation de la voix indique un total cumulé. Ne les additionnez pas. En cas d’erreur de transport ou d’expiration du délai avant la réception de session.closed, les données finales d’utilisation restent à confirmer. Pour consulter l’ensemble du cycle de vie, reportez-vous à Gestion des sessions.
L’API WebSockets, largement prise en charge, permet de transférer des données en temps réel. Elle convient particulièrement bien aux applications qui se connectent à la Realtime API d’OpenAI de serveur à serveur. Pour les navigateurs et les clients mobiles, nous recommandons une connexion via WebRTC.
Dans une intégration de serveur à serveur avec Realtime, votre backend se connecte directement à la Realtime API via WebSocket. Vous pouvez authentifier cette connexion avec une clé API standard, puisque le jeton d’authentification reste accessible uniquement sur votre serveur backend sécurisé.
Connexion via WebSocket
Les exemples ci-dessous montrent comment se connecter à la Realtime API via WebSocket. Utilisez l’URL WebSocket indiquée et transmettez un en-tête d’authentification contenant votre clé API OpenAI. Si votre application attribue des identifiants de sécurité, transmettez dans l’en-tête OpenAI-Safety-Identifier l’identifiant stable qui préserve la confidentialité de l’utilisateur final.
Dans un navigateur, vous pouvez utiliser WebSocket avec un jeton API éphémère, comme expliqué dans le guide de connexion WebRTC. Toutefois, pour une connexion depuis un client tel qu’un navigateur ou une application mobile, WebRTC offre une solution plus robuste dans la plupart des cas.
Module ws (Node.js)
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",
},
});
let connected = false;
ws.on("message", function incoming(message) {
const event = JSON.parse(message.toString());
if (event.type === "error") throw new Error(event.error.message);
if (event.type === "session.created") {
connected = true;
console.log(`Connected to the Realtime API: ${event.session.id}`);
ws.close(1000);
}
});
ws.on("close", () => {
if (!connected)
throw new Error("Connection closed before the session was created");
});# 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",
]
session_created = False
def on_message(ws, message):
global session_created
data = json.loads(message)
if data["type"] == "session.created":
session_created = True
print("Connected to the Realtime API:", data["session"]["id"])
ws.close()
elif data["type"] == "error":
ws.close()
ws = websocket.WebSocketApp(
url,
header=headers,
on_message=on_message,
)
ws.run_forever()
if not session_created:
raise RuntimeError("Connection closed before the Realtime session was created.")Installez les gems nécessaires avec
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|
created = connection.find do |event|
raise event.error.message if event.is_a?(OpenAI::Realtime::RealtimeErrorEvent)
next unless event.is_a?(OpenAI::Realtime::SessionCreatedEvent)
puts("Connected to the Realtime API: #{event.session[:id]}")
true
end
raise "Connection closed before the session was created" unless created
endUtilisez Java 17 ou une version ultérieure avec com.openai:openai-java:4.75.1.
import com.openai.client.okhttp.OkHttpClient;
import com.openai.core.ClientOptions;
import com.openai.helpers.RealtimeConnection;
import com.openai.helpers.RealtimeWebSocketOptions;
import com.openai.models.realtime.*;
var http = OkHttpClient.builder().build();
var options =
ClientOptions.builder()
.fromEnv()
.httpClient(http)
.putHeader("OpenAI-Safety-Identifier", "hashed-user-id")
.build();
try (http;
var connection =
RealtimeConnection.connect(
options,
RealtimeWebSocketOptions.builder().model("gpt-realtime-2.1").build())) {
while (true) {
var event = connection.receive();
if (event.error().isPresent())
throw new IllegalStateException(event.error().orElseThrow().toString());
if (event.sessionCreated().isPresent()) {
System.out.println("Connected to server.");
System.out.println(event);
break;
}
}
}Utilisez Go 1.26 ou une version ultérieure et installez le SDK avec
go get github.com/openai/openai-go/v3@v3.85.1. Le SDK gère
le transport des données via la connexion WebSocket. Votre application traite les événements,
capture et lit l’audio, puis restaure l’état de la session après une reconnexion.
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
defer cancel()
client := openai.NewClient()
conn, err := client.Realtime.Connect(ctx, realtime.RealtimeConnectionOptions{}, option.WithQuery("model", "gpt-realtime-2.1"), option.WithHeader("OpenAI-Safety-Identifier", "hashed-user-id"))
if err != nil {
return err
}
defer conn.Close()Installez le SDK avec
dotnet add package OpenAI –version 2.14.0. La Realtime API
utilise des types expérimentaux du SDK. L’exemple inclut la directive
requise pour gérer l’avertissement correspondant.
using OpenAI.Realtime;
#pragma warning disable OPENAI002
string key = Environment.GetEnvironmentVariable("OPENAI_API_KEY")!;
RealtimeClient client = new(key);
RealtimeSessionClientOptions options = new();
options.Headers["OpenAI-Safety-Identifier"] = "hashed-user-id";
using CancellationTokenSource timeout = new(TimeSpan.FromSeconds(30));
using RealtimeSessionClient session = await client.StartConversationSessionAsync("gpt-realtime-2.1", options, cancellationToken: timeout.Token);
await foreach (RealtimeServerUpdate update in session.ReceiveUpdatesAsync(timeout.Token))
{
if (update is RealtimeServerUpdateError error)
throw new InvalidOperationException(error.Error.Message);
if (update is RealtimeServerUpdateSessionCreated)
{
Console.WriteLine("Connected to server.");
Console.WriteLine(System.ClientModel.Primitives.ModelReaderWriter.Write(update));
return;
}
}
throw new InvalidOperationException("Connection closed before session creation.");/*
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,
]
);
ws.addEventListener("open", function open() {
console.log("Connected to server.");
});
ws.addEventListener("message", function incoming(event) {
console.log(event.data);
});Envoi et réception d’événements
La gestion des sessions de la Realtime API repose sur deux types d’événements : les événements envoyés par le client, que vous émettez depuis votre application, et les événements envoyés par le serveur, que la Realtime API génère pour signaler les étapes du cycle de vie de la session.
Sur une connexion WebSocket, vous envoyez et recevez les événements sérialisés en JSON sous forme de chaînes de caractères. L’exemple Node.js ci-dessous illustre ce fonctionnement. Les mêmes principes s’appliquent aux autres bibliothèques 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()));
});L’interface WebSocket est peut-être l’interface de plus bas niveau disponible pour interagir avec un modèle Realtime. Votre application doit à la fois envoyer les blocs audio encodés en base64 sur la connexion et traiter ceux qu’elle reçoit.
Pour savoir comment envoyer et recevoir de l’audio via WebSocket, consultez le guide des conversations Realtime.