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

Assistant vocal multimodal

Leçon 16 sur 18 Mis à jour le 3 novembre 2026 Développeur
Sur cette page
  1. Assistant vocal multimodal
  2. Texte et audio en parallèle
  3. Montrer une image à l’agent vocal
  4. Interface web multimodale
  5. Scénarios d’utilisation multimodale
  6. Points clés à retenir

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.

Corrigé le 3 novembre 2026. Pour analyser une image, la leçon passait par un appel séparé à l’API Responses, puis injectait la description comme message de l’assistant avec un contenu input_text, type réservé aux messages d’utilisateur ou système. Or gpt-realtime-2.1 et gpt-realtime-2 acceptent les images en entrée : l’image se joint directement, en input_image, à un message de l’utilisateur. L’événement response.text.delta, de l’ancienne bêta, s’appelle désormais response.output_text.delta. Formes d’événements vérifiées contre les types du SDK openai 3.42.1. Sources : Realtime conversations, Image inputs · gpt-realtime-2.1.

Assistant vocal multimodal

Un assistant vocal multimodal combine la voix avec d’autres modalités : texte, images, vidéo, données structurées. L’utilisateur parle, mais l’agent peut aussi afficher des informations visuelles, analyser des images envoyées par l’utilisateur, ou combiner plusieurs sources de données. C’est l’avenir de l’interaction homme-machine.

Texte et audio en parallèle

La Realtime API supporte nativement les modalités texte et audio simultanément. Vous pouvez injecter du texte dans la conversation tout en maintenant l’échange vocal :

async def inject_text_context(ws, context: str):
    """Ajoute du contexte textuel à la conversation vocale."""
    await ws.send(json.dumps({
        "type": "conversation.item.create",
        "item": {
            "type": "message",
            "role": "user",
            "content": [
                {
                    "type": "input_text",
                    "text": context
                }
            ]
        }
    }))

    # Déclencher une réponse vocale basée sur ce contexte
    await ws.send(json.dumps({"type": "response.create"}))

# L'utilisateur demande vocalement "Lis-moi mon dernier email"
# Vous injectez le contenu de l'email en texte
await inject_text_context(ws, """
Voici le dernier email reçu :
De : [email protected]
Objet : Demande de devis
Contenu : Bonjour, je souhaiterais obtenir un devis pour
l'intégration d'un agent vocal dans notre centre d'appels.
""")

Montrer une image à l’agent vocal

gpt-realtime-2.1 et gpt-realtime-2 prennent en entrée du texte, de l’audio et des images. Une image se joint comme une partie input_image d’un message de l’utilisateur, avec une Data URI Base64, sur WebSocket comme sur le canal de données WebRTC. Le modèle en tient compte dans sa réponse vocale, sans appel à une autre API :

import base64
import json


async def montrer_image(ws, chemin_image: str, question: str) -> None:
    """Joint une image et une question à la conversation, puis demande une réponse vocale."""
    with open(chemin_image, "rb") as f:
        image_b64 = base64.b64encode(f.read()).decode()

    await ws.send(json.dumps({
        "type": "conversation.item.create",
        "item": {
            "type": "message",
            "role": "user",
            "content": [
                {"type": "input_image", "image_url": f"data:image/jpeg;base64,{image_b64}"},
                {"type": "input_text", "text": question},
            ],
        },
    }))
    await ws.send(json.dumps({"type": "response.create"}))


await montrer_image(ws, "facture.jpg", "Que dois-je payer, et avant quelle date ?")

Les images sont facturées en tokens d’image, à un tarif propre indiqué sur la fiche du modèle. Pour une analyse lourde ou un modèle de vision plus capable, vous pouvez toujours interroger l’API Responses à part, puis transmettre son résultat à la session : faites-le alors par un message system ou user (contenu input_text), jamais par un faux message de l’assistant, que le modèle prendrait pour ses propres paroles.

Interface web multimodale

Pour une application web, combinez le WebSocket Realtime avec une interface visuelle :

from fastapi import FastAPI, WebSocket
from fastapi.staticfiles import StaticFiles

app = FastAPI()

@app.websocket("/ws/agent")
async def multimodal_agent(client_ws: WebSocket):
    """Agent multimodal avec interface web."""
    await client_ws.accept()

    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

        await openai_ws.send(json.dumps({
            "type": "session.update",
            "session": {
                "type": "realtime",
                "output_modalities": ["audio"],
                "instructions": "Assistant multimodal. Répondez en français.",
                "audio": {"output": {"voice": "marin"}}
            }
        }))
        await openai_ws.recv()

        async def client_to_openai():
            async for message in client_ws.iter_text():
                data = json.loads(message)

                if data["type"] == "audio":
                    # Relayer l'audio
                    await openai_ws.send(json.dumps({
                        "type": "input_audio_buffer.append",
                        "audio": data["audio"]
                    }))

                elif data["type"] == "text":
                    # Message texte (chat)
                    await openai_ws.send(json.dumps({
                        "type": "conversation.item.create",
                        "item": {
                            "type": "message",
                            "role": "user",
                            "content": [{
                                "type": "input_text",
                                "text": data["text"]
                            }]
                        }
                    }))
                    await openai_ws.send(json.dumps({
                        "type": "response.create"
                    }))

        async def openai_to_client():
            async for message in openai_ws:
                event = json.loads(message)
                t = event["type"]

                if t == "response.output_audio.delta":
                    await client_ws.send_json({
                        "type": "audio",
                        "delta": event["delta"]
                    })

                elif t == "response.output_audio_transcript.delta":
                    await client_ws.send_json({
                        "type": "transcript",
                        "delta": event["delta"]
                    })

                elif t == "response.output_text.delta":
                    await client_ws.send_json({
                        "type": "text",
                        "delta": event["delta"]
                    })

        await asyncio.gather(client_to_openai(), openai_to_client())

Scénarios d’utilisation multimodale

Voici comment un agent multimodal gère différents scénarios dans un outil de function calling :

tools = [
    {
        "type": "function",
        "name": "show_chart",
        "description": "Affiche un graphique de données à l'utilisateur",
        "parameters": {
            "type": "object",
            "properties": {
                "chart_type": {"type": "string", "enum": ["bar", "line", "pie"]},
                "title": {"type": "string"},
                "data": {"type": "object"}
            },
            "required": ["chart_type", "title", "data"]
        }
    },
    {
        "type": "function",
        "name": "send_document",
        "description": "Envoie un document au client par email",
        "parameters": {
            "type": "object",
            "properties": {
                "document_type": {"type": "string"},
                "recipient": {"type": "string"}
            },
            "required": ["document_type", "recipient"]
        }
    }
]

L’utilisateur dit vocalement : « Montre-moi les ventes du dernier trimestre sous forme de graphique ». L’agent appelle show_chart, votre frontend affiche le graphique, et l’agent commente vocalement les résultats.

Points clés à retenir

  • La Realtime API supporte les modalités texte et audio simultanément dans une même session
  • L’injection de texte via conversation.item.create permet d’enrichir le contexte vocal
  • Les modèles Realtime acceptent les images : joignez-les en input_image à un message de l’utilisateur
  • Les outils (function calling) permettent d’afficher des éléments visuels tout en répondant vocalement
  • L’architecture WebSocket côté client permet de mixer audio, texte et données structurées