Assistant vocal multimodal
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.
""")
Combiner Realtime API et Vision
Pour analyser des images pendant une conversation vocale, combinez la Realtime API avec la Responses API :
import base64
class MultimodalAgent:
"""Agent vocal capable d'analyser des images."""
def __init__(self, ws, client):
self.ws = ws
self.client = client # Client OpenAI standard
async def analyze_image(self, image_path: str, question: str):
"""Analyse une image et répond vocalement."""
# Lire et encoder l'image
with open(image_path, "rb") as f:
image_b64 = base64.b64encode(f.read()).decode()
# Appel à la Responses API avec vision
response = self.client.responses.create(
model="gpt-4o-mini",
input=[{
"role": "user",
"content": [
{"type": "input_text", "text": question},
{
"type": "input_image",
"image_url": f"data:image/jpeg;base64,{image_b64}"
}
]
}]
)
description = response.output_text
# Injecter la description dans la session Realtime
await self.ws.send(json.dumps({
"type": "conversation.item.create",
"item": {
"type": "message",
"role": "assistant",
"content": [{
"type": "input_text",
"text": f"[Analyse d'image] {description}"
}]
}
}))
# Répondre vocalement
await self.ws.send(json.dumps({
"type": "response.create",
"response": {
"instructions": f"Décrivez à l'utilisateur ce que montre l'image : {description}"
}
}))
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}",
"OpenAI-Beta": "realtime=v1"
}
async with websockets.connect(REALTIME_URL, extra_headers=headers) as openai_ws:
await openai_ws.recv() # session.created
await openai_ws.send(json.dumps({
"type": "session.update",
"session": {
"modalities": ["text", "audio"],
"instructions": "Assistant multimodal. Répondez en français.",
"voice": "nova"
}
}))
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.audio.delta":
await client_ws.send_json({
"type": "audio",
"delta": event["delta"]
})
elif t == "response.audio_transcript.delta":
await client_ws.send_json({
"type": "transcript",
"delta": event["delta"]
})
elif t == "response.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.createpermet d’enrichir le contexte vocal - L’analyse d’images combine la Responses API (vision) avec la Realtime API (voix)
- 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