Aller au contenu principal

Sessions, événements et lifecycle

Sessions, événements et lifecycle

Chaque connexion WebSocket à la Realtime API crée une session. Cette session est l’unité fondamentale de gestion : elle encapsule la configuration du modèle, l’historique de conversation, les outils disponibles et l’état courant de l’interaction. Comprendre son cycle de vie est essentiel pour construire des agents vocaux robustes.

Le cycle de vie d’une session

Dès que la connexion WebSocket est établie, le serveur émet un événement session.created. La session passe par plusieurs phases :

1

Connexion → session.created

Le serveur confirme la session avec un ID unique et la configuration par défaut.

2

Configuration → session.update

Vous envoyez session.update pour définir les instructions, la voix, les outils et les modalités.

3

Conversation active

Échange d'événements audio et texte entre client et serveur.

4

Fermeture → déconnexion WebSocket

La session est détruite à la fermeture de la connexion. Aucun état n'est conservé côté serveur.

Configurer une session

Immédiatement après session.created, vous devez envoyer un événement session.update pour configurer le comportement du modèle :

import asyncio
import websockets
import json

async def configure_session():
    headers = {
        "Authorization": f"Bearer {OPENAI_API_KEY}",
        "OpenAI-Beta": "realtime=v1"
    }

    async with websockets.connect(URL, extra_headers=headers) as ws:
        # Attendre session.created
        event = json.loads(await ws.recv())
        session_id = event["session"]["id"]
        print(f"Session créée : {session_id}")

        # Configurer la session
        await ws.send(json.dumps({
            "type": "session.update",
            "session": {
                "modalities": ["text", "audio"],
                "instructions": "Vous êtes un assistant vocal francophone. "
                                "Répondez de manière concise et naturelle.",
                "voice": "alloy",
                "input_audio_format": "pcm16",
                "output_audio_format": "pcm16",
                "input_audio_transcription": {
                    "model": "whisper-1"
                },
                "turn_detection": {
                    "type": "server_vad",
                    "threshold": 0.5,
                    "prefix_padding_ms": 300,
                    "silence_duration_ms": 500
                },
                "tools": [],
                "temperature": 0.8,
                "max_response_output_tokens": 4096
            }
        }))

        # Confirmation
        event = json.loads(await ws.recv())
        print(f"Session mise à jour : {event['type']}")

Paramètres clés de la session

Paramètre Description Valeur recommandée
modalities Canaux d'entrée/sortie ["text", "audio"]
voice Voix de synthèse alloy, echo, shimmer, etc.
turn_detection Détection de fin de parole server_vad avec seuil 0.5
input_audio_format Format audio entrant pcm16 (16-bit PCM, 24kHz)

Le système d’événements

La Realtime API est entièrement événementielle. Chaque message échangé est un objet JSON avec un champ type qui détermine sa nature. Les événements se répartissent en deux catégories :

Événements client (vous → serveur)

# Les principaux événements que vous envoyez
client_events = {
    "session.update":              "Modifier la configuration",
    "input_audio_buffer.append":   "Envoyer un chunk audio",
    "input_audio_buffer.commit":   "Valider le buffer audio",
    "input_audio_buffer.clear":    "Vider le buffer audio",
    "conversation.item.create":    "Ajouter un message manuellement",
    "conversation.item.truncate":  "Tronquer une réponse",
    "conversation.item.delete":    "Supprimer un message",
    "response.create":             "Déclencher une réponse",
    "response.cancel":             "Annuler la réponse en cours",
}

Événements serveur (serveur → vous)

# Les principaux événements que vous recevez
server_events = {
    "session.created":             "Session initialisée",
    "session.updated":             "Configuration appliquée",
    "input_audio_buffer.speech_started":  "Parole détectée",
    "input_audio_buffer.speech_stopped":  "Silence détecté",
    "conversation.item.created":   "Nouveau message dans l'historique",
    "response.created":            "Début de génération",
    "response.audio.delta":        "Chunk audio de réponse",
    "response.audio_transcript.delta": "Chunk de transcription",
    "response.done":               "Réponse terminée",
    "error":                       "Erreur",
}

Gestion des erreurs

Les erreurs sont émises via un événement de type error. Vous devez toujours les intercepter :

async def handle_events(ws):
    async for raw_message in ws:
        event = json.loads(raw_message)
        event_type = event["type"]

        if event_type == "error":
            error = event["error"]
            print(f"Erreur [{error['type']}]: {error['message']}")

            if error["type"] == "invalid_request_error":
                # Erreur de configuration, corriger et réessayer
                pass
            elif error["type"] == "server_error":
                # Problème côté OpenAI, reconnecter
                pass

        elif event_type == "session.updated":
            print("Configuration appliquée avec succès")

        elif event_type == "response.done":
            usage = event["response"].get("usage", {})
            print(f"Tokens utilisés : {usage}")

Points clés à retenir

  • Une session est créée automatiquement à la connexion WebSocket et détruite à la déconnexion
  • session.update doit être envoyé immédiatement après session.created pour configurer le modèle
  • Le protocole est purement événementiel : chaque message a un type qui détermine son traitement
  • Les événements client pilotent l’interaction, les événements serveur rapportent les résultats
  • La gestion d’erreurs est critique : toujours écouter les événements error