Aller au contenu principal
Leçon 15 sur 18 · API Temps Réel et Agents Vocaux

Intégration téléphonique (Twilio, etc.)

Leçon 15 sur 18 Mis à jour le 3 novembre 2026 Développeur
Sur cette page
  1. Intégration téléphonique (Twilio, etc.)
  2. Architecture téléphonique
  3. Implémentation avec Twilio
  4. Alternatives à Twilio
  5. Points clés à retenir

Corrigé le 3 novembre 2026 d’après la documentation de la Realtime API : le format G.711 μ-law s’appelle audio/pcmu (le texte citait g711_ulaw, nom de la version bêta). Source : Realtime API.

Mise à jour du 2 novembre 2026 — modèles audio. Plusieurs modèles de ce cours sont dépréciés : tts-1, tts-1-hd et gpt-4o-mini-tts s’arrêtent le 6 janvier 2027 (remplaçant indiqué : gpt-realtime-2.1-mini, que le guide TTS d’OpenAI déclare non pris en charge par /v1/audio/speech : la migration de la synthèse vocale passe par l’API Realtime) ; gpt-realtime, gpt-4o-realtime et les anciens modèles audio le 20 janvier 2027 (gpt-realtime-2.1, gpt-realtime-2.1-mini, gpt-audio-1.5) ; whisper-1, gpt-4o-transcribe et /v1/audio/translations le 26 février 2027 (gpt-transcribe, gpt-live-transcribe, v1/realtime/translations). Pour la voix full-duplex, GPT-Live 1 est disponible dans l’API depuis le 10 septembre 2026.

Intégration téléphonique (Twilio, etc.)

Un agent vocal devient vraiment utile quand il est accessible par téléphone. Les plateformes de téléphonie cloud comme Twilio, LiveKit et Daily permettent de connecter la Realtime API au réseau téléphonique mondial. Un utilisateur appelle un numéro, et votre agent répond en temps réel.

Architecture téléphonique

L’intégration téléphonique ajoute une couche entre le réseau téléphonique et la Realtime API :

1

Appel entrant → Twilio

L'utilisateur appelle un numéro de téléphone. Twilio reçoit l'appel et envoie un webhook à votre serveur.

2

Votre serveur → Media Stream

Votre serveur répond avec des instructions TwiML qui ouvrent un Media Stream WebSocket bidirectionnel.

3

Media Stream ↔ Realtime API

Votre serveur relaie l'audio entre le Media Stream Twilio et la Realtime API OpenAI.

4

Réponse vocale → Utilisateur

L'audio de réponse de la Realtime API est renvoyé via Twilio au téléphone de l'utilisateur.

Implémentation avec Twilio

Webhook d’appel entrant

Quand un appel arrive, Twilio envoie une requête HTTP à votre serveur. Vous répondez avec du TwiML qui ouvre un Media Stream :

from fastapi import FastAPI, Request
from fastapi.responses import Response

app = FastAPI()

@app.post("/incoming-call")
async def incoming_call(request: Request):
    """Webhook Twilio pour les appels entrants."""
    twiml = """<?xml version="1.0" encoding="UTF-8"?>
    <Response>
        <Say language="fr-FR">
            Bienvenue chez Corsen AI. Connexion à votre assistant vocal.
        </Say>
        <Connect>
            <Stream url="wss://votre-serveur.com/media-stream">
                <Parameter name="caller" value="{caller_number}" />
            </Stream>
        </Connect>
    </Response>"""

    form_data = await request.form()
    caller = form_data.get("From", "inconnu")
    twiml = twiml.replace("{caller_number}", caller)

    return Response(content=twiml, media_type="application/xml")

Le pont Media Stream ↔ Realtime API

Le serveur WebSocket reçoit l’audio de Twilio et le relaie à la Realtime API :

from fastapi import WebSocket
import websockets
import json
import base64
import audioop

OPENAI_API_KEY = "sk-..."
REALTIME_URL = "wss://api.openai.com/v1/realtime?model=gpt-realtime-2.1"

@app.websocket("/media-stream")
async def media_stream(twilio_ws: WebSocket):
    """Pont entre Twilio Media Stream et la Realtime API."""
    await twilio_ws.accept()

    # Connexion à la Realtime API
    headers = {
        "Authorization": f"Bearer {OPENAI_API_KEY}"
    }

    async with websockets.connect(REALTIME_URL, additional_headers=headers) as openai_ws:
        await openai_ws.recv()  # session.created

        # Configurer la session
        await openai_ws.send(json.dumps({
            "type": "session.update",
            "session": {
                "type": "realtime",
                "output_modalities": ["audio"],
                "instructions": "Vous êtes un assistant téléphonique. "
                                "Répondez en français, de manière concise.",
                "audio": {
                    "input": {
                        "format": {"type": "audio/pcmu"},
                        "turn_detection": {
                            "type": "server_vad",
                            "threshold": 0.5,
                            "silence_duration_ms": 600
                        }
                    },
                    "output": {
                        "format": {"type": "audio/pcmu"},
                        "voice": "marin"
                    }
                }
            }
        }))
        await openai_ws.recv()

        stream_sid = None

        async def twilio_to_openai():
            nonlocal stream_sid
            async for message in twilio_ws.iter_text():
                data = json.loads(message)

                if data["event"] == "media":
                    audio_b64 = data["media"]["payload"]
                    await openai_ws.send(json.dumps({
                        "type": "input_audio_buffer.append",
                        "audio": audio_b64
                    }))

                elif data["event"] == "start":
                    stream_sid = data["start"]["streamSid"]

        async def openai_to_twilio():
            async for message in openai_ws:
                event = json.loads(message)

                if event["type"] == "response.output_audio.delta":
                    await twilio_ws.send_json({
                        "event": "media",
                        "streamSid": stream_sid,
                        "media": {
                            "payload": event["delta"]
                        }
                    })

        await asyncio.gather(twilio_to_openai(), openai_to_twilio())

Format audio G.711

La téléphonie utilise le format G.711 μ-law (8 kHz, un octet par échantillon). La Realtime API le prend en charge nativement sous le nom audio/pcmu, à déclarer en entrée comme en sortie (audio.input.format et audio.output.format, comme dans le code ci-dessus), ce qui évite toute conversion côté serveur. Le nom g711_ulaw appartenait à la version bêta de l’API ; l’équivalent A-law s’appelle audio/pcma.

Alternatives à Twilio

Plateforme Force Intégration Realtime API
Twilio Écosystème complet, numéros dans 100+ pays Media Streams WebSocket natif
LiveKit Open source, faible latence, WebRTC Plugin OpenAI officiel
Daily Simple, hébergé, bon pour prototypage SDK Pipecat avec connecteur Realtime

Points clés à retenir

  • Twilio Media Streams permet de connecter un appel téléphonique à un WebSocket bidirectionnel
  • Le serveur fait office de pont entre le Media Stream Twilio et la Realtime API OpenAI
  • Le format G.711 μ-law est natif en téléphonie et supporté directement par la Realtime API
  • LiveKit (open source, WebRTC) et Daily (hébergé) sont des alternatives viables à Twilio
  • L’architecture est toujours la même : téléphonie → votre serveur → Realtime API