Intégrez Google Gemini à Twilio Voice à l'aide de ConversationRelay et Python

April 20, 2026
Rédigé par
Révisé par

Résumé généré par l’IA
  • Configurez un serveur FastAPI et connectez Google Gemini à Twilio Voice grâce à ConversationRelay.
  • Définissez les variables d’environnement et installez les dépendances nécessaires pour sécuriser les communications.
  • Testez ensuite votre intégration en appelant votre numéro Twilio pour découvrir comment dialoguer en temps réel avec une intelligence artificielle, directement par téléphone.

Ce résumé a été généré par l’IA.

Imaginez une solution permettant d’établir, par téléphone, des conversations en temps réel avec un modèle d’intelligence artificielle, tout en bénéficiant d’interactions proches d’un échange humain naturel. C’est précisément ce que permet Twilio Conversation Relay. Grâce à une connexion WebSocket rapide, reposant sur une architecture événementielle, ConversationRelay fait le lien entre vos appels vocaux et n’importe quel grand modèle de langage (LLM), pour permettre des échanges fluides et sans interruption.

Dans cet article, je vais vous montrer comment associer Google Gemini à Twilio Voice à l’aide de ConversationRelay. À l’issue de ce tutoriel, vous disposerez d’un serveur Python simple et opérationnel, qui vous permettra d’appeler un numéro Twilio et de dialoguer directement avec Gemini. Vous aurez ainsi toutes les bases nécessaires pour aller plus loin et développer des applications vocales plus interactives et dotées de fonctionnalités enrichies.

Prérequis

Pour mettre en œuvre les différentes étapes décrites dans ce tutoriel, assurez-vous de disposer des éléments suivants :

Configurer le projet

Commençons par créer un nouveau dossier pour votre projet :

mkdir twilio-cr-gemini-python
cd twilio-cr-gemini-python

Procédez ensuite à la création et à l’activation d’un environnement virtuel Python :

python -m venv .venv
source .venv/bin/activate  # On Windows: .venv\Scripts\activate

Installez les dépendances requises à l’aide du gestionnaire de packages pip :

pip install google-genai python-dotenv uvicorn fastapi websockets

Le framework FastAPI sera utilisé pour déployer rapidement un serveur prenant en charge les connexions WebSocket ainsi que le point de terminaison HTTP destiné à Twilio.

Tout le code de ce guide de démarrage rapide est disponible sur GitHub.

Configurez les variables d'environnement

Vous devrez stocker en toute sécurité votre clé API Google Gemini. Créez un fichier .env dans le dossier de votre projet et ajoutez ce qui suit :

GOOGLE_API_KEY="YOUR_GEMINI_API_KEY"
NGROK_URL="your-ngrok-subdomain.ngrok-free.app"

Assurez-vous de remplacer les valeurs de substitution par votre clé API et par l’URL publique de redirection générée par Ngrok. La procédure de configuration de cette URL sera présentée dans une section ultérieure du tutoriel.

Mise en place du serveur

Créez un nouveau fichier Python intitulé main.py. Ce fichier contiendra la logique applicative principale.

1. Importation des bibliothèques requises et configuration de l’environnement

La configuration du serveur commence par l’importation des bibliothèques nécessaires à son fonctionnement. Ces bibliothèques fourniront les fonctionnalités permettant de développer le serveur, de gérer les connexions WebSocket, d’interagir avec Google Gemini et de charger les variables d’environnement.

import os
import json
import uvicorn
from google import genai
from fastapi import FastAPI, WebSocket, WebSocketDisconnect
from fastapi.responses import Response
from dotenv import load_dotenv
  • FastAPI : Ce framework web constitue la principale infrastructure de développement du serveur. Il facilite la définition des routes et le traitement des requêtes HTTP, tout en prenant en charge les communications WebSocket entre le serveur et le service ConversationRelay de Twilio.
  • uvicorn : Il s’agit d’un serveur ASGI haute performance chargé de l’exécution de l’application FastAPI.
  • genai : Le kit de développement logiciel (SDK) Google Gen AI fournit les fonctionnalités nécessaires pour interagir avec les modèles Gemini de Google et générer des réponses à partir de ces derniers.
  • dotenv : Ce module assure le chargement des variables d’environnement, notamment la clé API Google et l’URL Ngrok, depuis un fichier de configuration .env.

Une fois les bibliothèques importées, insérez la ligne de code suivante afin de charger les variables d’environnement contenues dans le fichier .env :

load_dotenv()

Cette approche permet d’éviter d’intégrer directement au code source des informations sensibles, telles que les clés API.

2. Définition des constantes et des paramètres de configuration

Déclarez les différentes constantes qui seront utilisées dans le programme afin de configurer et de personnaliser le comportement de l’application.

PORT = int(os.getenv("PORT", "8080"))
DOMAIN = os.getenv("NGROK_URL")
if not DOMAIN:
    raise ValueError("NGROK_URL environment variable not set.")
WS_URL = f"wss://{DOMAIN}/ws"
WELCOME_GREETING = "Hi! I am a voice assistant powered by Twilio and Google Gemini. Ask me anything!"
SYSTEM_PROMPT = """You are a helpful and friendly voice assistant. This conversation is happening over a phone call, so your responses will be spoken aloud. 
Please adhere to the following rules:
1. Provide clear, concise, and direct answers.
2. Spell out all numbers (e.g., say 'one thousand two hundred' instead of 1200).
3. Do not use any special characters like asterisks, bullet points, or emojis.
4. Keep the conversation natural and engaging."""
sessions = {}
  • PORT : définit le port d’écoute du serveur. (Sa valeur est obtenue à partir de la variable d’environnement correspondante ou, à défaut, initialisée à 8080).
  • DOMAINE : définit l’adresse utilisée pour établir la connexion WebSocket avec Twilio. Le programme procède immédiatement à la validation de ce paramètre et génère une erreur si aucune valeur n’a été fournie.
  • WS_URL : URL du point de terminaison WebSocket correspond à l’adresse complète du point de terminaison auquel Twilio établira sa connexion.
  • WELCOME_GREETING : Message d’accueil, définit le message vocal qui sera diffusé lors de l’établissement de l’appel.
  • SYSTEM_PROMPT : message d’instructions destiné à Gemini, correspond à un message spécifique transmis au modèle Gemini afin de définir les consignes régissant son comportement. Ces instructions sont essentielles, car elles permettent d'encadrer la tonalité et le format des réponses produites par le modèle d’intelligence artificielle. Elles peuvent notamment imposer l’écriture des nombres en toutes lettres ou exclure l’utilisation d’émojis. Dans le contexte d’une application conversationnelle vocale, ces règles contribuent à générer des contenus clairs et adaptés à la synthèse vocale.
  • sessions : Un dictionnaire destiné à stocker les objets correspondant aux sessions de conversation actives pour chaque appel, en utilisant l’identifiant callSid comme clé d’association. Remarques : Cette implémentation prévoit uniquement la suppression des sessions lors d’une déconnexion normale. Dans un environnement de production, il est recommandé de mettre en place un mécanisme supplémentaire de gestion des expirations de session afin de prendre en charge les situations dans lesquelles la connexion ne se termine pas normalement.

3. Initialisation de l’application FastAPI et du client Gemini

Procédez à l’initialisation de l’application FastAPI et à la configuration du client Gemini à partir de la clé API stockée dans le fichier .env.

GOOGLE_API_KEY = os.getenv("GOOGLE_API_KEY")
if not GOOGLE_API_KEY:
    raise ValueError("GOOGLE_API_KEY environment variable not set.")
client = genai.Client(api_key=GOOGLE_API_KEY)
app = FastAPI()
  • GOOGLE_API_KEY : Le programme charge la clé API depuis les variables d’environnement, puis vérifie sa présence avant de poursuivre son exécution.
  • client : Instanciez ensuite le client Google Gen AI à l’aide de la méthode genai.Client(). Cette syntaxe correspond à la nouvelle méthode d’initialisation du SDK Google Gen AI. Si vous avez précédemment utilisé le package google-generativeai, notez que l’implémentation présentée ici repose sur le SDK plus récent google-genai.
  • Application FastAPI : cette instruction initialise l’application web chargée de traiter les requêtes HTTP et de gérer les connexions WebSocket.

4. Définition de la fonction de génération des réponses de l’IA

Définissez une fonction chargée d'interagir avec l’API Gemini afin de soumettre les requêtes et de récupérer les réponses générées par le modèle.

def gemini_response(chat_session, user_prompt):
    """Get a response from the Gemini API."""
    response = chat_session.send_message(user_prompt)
    return response.text
  • gemini_response() : cette fonction accepte en paramètres un objet de session de conversation Gemini et le prompt fourni par l’utilisateur. Elle transmet ce dernier au modèle, puis renvoie la réponse générée au format texte. L’objet de session assure automatiquement la conservation de l’historique conversationnel. Gemini peut ainsi exploiter le contexte complet des échanges précédents lors du traitement de chaque nouveau message.

5. Génération de la réponse TwiML destinée à Twilio

Le point de terminaison /twiml a pour fonction de fournir à Twilio les instructions nécessaires à l’établissement d’une connexion entre un appel vocal et l’application WebSocket. wilio s’appuie sur TwiML (Twilio Markup Language), un langage de balisage permettant de définir les instructions de traitement des appels et de gestion des interactions vocales.

@app.post("/twiml")
async def twiml_endpoint():
    """Endpoint that returns TwiML for Twilio to connect to the WebSocket"""
    xml_response = f"""<?xml version="1.0" encoding="UTF-8"?>
    <Response>
    <Connect>
    <ConversationRelay url="{WS_URL}" welcomeGreeting="{WELCOME_GREETING}" ttsProvider="ElevenLabs" voice="FGY2WhTYpPnrIDTdsKH5" />
    </Connect>
    </Response>"""
    return Response(content=xml_response, media_type="text/xml")
  • La réponse TwiML fournit à Twilio les instructions nécessaires pour établir une connexion avec le serveur WebSocket à l’adresse indiquée par WS_URL et diffuser le message d’accueil défini dans WELCOME_GREETING à l’attention de l’appelant.
  • Dans cette implémentation, ElevenLabs est configuré comme fournisseur de synthèse vocale (TTS), avec l’identifiant de voix (FGY2WhTYpPnrIDTdsKH5). Cet identifiant est fourni uniquement à titre d’exemple et doit être remplacé par celui de la voix que vous souhaitez utiliser si vous retenez ElevenLabs comme fournisseur. Cette configuration est facultative. Les attributs ttsProvider et voice peuvent être entièrement supprimés afin d’utiliser le moteur de synthèse vocale par défaut de Twilio. Il est également possible de sélectionner un autre fournisseur en remplaçant ElevenLabs par Amazon ou Google.
  • Pour obtenir des informations détaillées sur les attributs pris en charge, notamment language, ttsProvider et voice, reportez-vous à la documentation de ConversationRelay.
  • Remarques : Ce point de terminaison ne procède pas à la validation des signatures associées aux requêtes provenant de Twilio. Dans le cadre d’un déploiement en production, il convient de se référer à la documentation de Twilio relative à la validation des requêtes afin de mettre en œuvre les contrôles de sécurité appropriés..

6. Gestion des connexions WebSocket

Le point de terminaison WebSocket /ws est chargé d’assurer la communication en temps réel entre Twilio et le serveur. Il réceptionne les messages entrants, effectue les traitements nécessaires et transmet les réponses à Twilio.

@app.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket):
    """WebSocket endpoint for real-time communication"""
    await websocket.accept()
    call_sid = None
    try:
        while True:
            data = await websocket.receive_text()
            message = json.loads(data)
            if message["type"] == "setup":
                call_sid = message["callSid"]
                print(f"Setup for call: {call_sid}")
                sessions[call_sid] = client.chats.create(
                    model="gemini-2.5-flash",
                    config={"system_instruction": SYSTEM_PROMPT}
                )
            elif message["type"] == "prompt":
                if not call_sid or call_sid not in sessions:
                    print(f"Error: Received prompt for unknown call_sid {call_sid}")
                    continue
                user_prompt = message["voicePrompt"]
                print(f"Processing prompt: {user_prompt}")
                chat_session = sessions[call_sid]
                response_text = gemini_response(chat_session, user_prompt)
                await websocket.send_text(
                    json.dumps({
                        "type": "text",
                        "token": response_text,
                        "last": True
                    })
                )
                print(f"Sent response: {response_text}")
            elif message["type"] == "interrupt":
                print(f"Handling interruption for call {call_sid}.")
            else:
                print(f"Unknown message type received: {message['type']}")
    except WebSocketDisconnect:
        print(f"WebSocket connection closed for call {call_sid}")
        if call_sid in sessions:
            sessions.pop(call_sid)
            print(f"Cleared session for call {call_sid}")
  • La boucle while assure l’écoute continue des messages entrants transmis par Twilio. Le serveur prend en charge plusieurs types de messages :
  • setup : procède à l’initialisation d’une nouvelle session de conversation Gemini associée à l’appel en cours. Le programme invoque la méthode client.chats.create() en spécifiant le modèle gemini-2.5-flash et en transmettant les instructions système au moyen du paramètre config. Cette opération permet de créer un objet de conversation avec conservation de l’état, qui assure automatiquement la gestion de l’historique des échanges.
  • prompt : prend en charge les entrées vocales de l’utilisateur, converties préalablement en texte par Twilio, puis les transmet au modèle Gemini par l’intermédiaire de la fonction gemini_response(). La réponse générée est ensuite renvoyée sous forme de texte à Twilio, qui se charge de la convertir en parole grâce à la synthèse vocale.
  • interrupt : permet de gérer les interruptions pendant la conversation, notamment lorsque la personne qui appelle commence à parler alors que l’IA est encore en train de répondre.
  • Message inconnu : consigne dans les journaux les messages dont le type n’est pas reconnu.
  • sessions : Pour assurer le suivi des conversations en cours, notre application conserve les sessions Gemini actives dans le dictionnaire sessions. Chacune est identifiée par le call_sid correspondant à l’appel auquel elle est associée. Lorsque la connexion WebSocket prend fin, la session correspondante est supprimée afin de libérer les ressources qu’elle utilisait.

7. Initialisation et démarrage du serveur FastAPI

Enfin, procédez au lancement du serveur FastAPI à l’aide de Uvicorn :

if __name__ == "__main__":
    uvicorn.run(app, host="0.0.0.0", port=PORT)

uvicorn.run() : Cette instruction permet de démarrer le serveur sur le port défini précédemment dans notre configuration. Si aucun port particulier n’a été indiqué, le port 8080 sera utilisé par défaut. Notre serveur dispose désormais de tout le nécessaire pour prendre en charge les deux types de communications de l’application : les requêtes HTTP utilisées pour fournir les instructions TwiML à Twilio et les connexions WebSocket qui permettront d’échanger avec Gemini en temps réel.

Mise en service du serveur

Pour exécuter l’application, ouvrez tout d’abord un terminal et démarrez un tunnel Ngrok :

ngrok http 8080

Le tunnel Ngrok doit être établi en premier, car son URL sera nécessaire à la fois pour la configuration du webhook dans la console Twilio et pour le renseignement des variables d’environnement dans le fichier .env.

Relevez l’URL publique générée par Ngrok, par exemple https://1234abcd.ngrok.app, puis reportez la partie correspondant au nom de domaine dans votre fichier .env :

NGROK_URL="1234abcd.ngrok-free.app"

Vous pouvez ensuite lancer le serveur en exécutant la commande suivante :

python main.py

Configuration du numéro Twilio

Dans la console Twilio, accédez aux paramètres de votre numéro de téléphone Twilio. Dans l’onglet Configurer, puis, dans la section Voice Configuration, configurez l’URL du webhook en indiquant l’adresse publique de votre tunnel Ngrok, suivie du chemin /twiml, conformément à l’exemple ci-dessous :

https://1234abcd.ngrok-free.app/twiml

Vérification du fonctionnement de l’intégration

Une fois la configuration terminée, composez votre numéro Twilio depuis un téléphone mobile. Le message d’accueil devrait être diffusé, après quoi vous pourrez commencer à interagir avec l’assistant d’intelligence artificielle en lui posant vos questions.

Et maintenant, quelles sont les prochaines étapes ?

Vous venez de créer une application Python reposant sur un serveur FastAPI, capable de faire communiquer les fonctionnalités vocales de Twilio et ConversationRelay avec un assistant IA exploitant Google Gemini. Le résultat : une application qui permet de mener de véritables conversations vocales avec une intelligence artificielle, en temps réel. Pour assurer le bon fonctionnement de l’ensemble, le serveur gère deux types de communications complémentaires. D’un côté, les requêtes HTTP permettent de transmettre à Twilio les instructions nécessaires au traitement des appels. De l’autre, les connexions WebSocket assurent la continuité des échanges avec le modèle d’intelligence artificielle. Lorsque vous composez votre numéro Twilio, ConversationRelay prend en charge la coordination des différentes opérations qui rendent cette expérience possible. Vos paroles sont d’abord transcrites en texte, puis transmises au grand modèle de langage (LLM), dont les réponses sont à leur tour converties en parole grâce à la synthèse vocale. Toutes ces étapes s’enchaînent pour vous permettre de dialoguer avec votre assistant Gemini de manière fluide et naturelle, comme au cours d’une conversation téléphonique classique.

Et maintenant que votre assistant vocal fonctionne en temps réel, pourquoi ne pas aller encore plus loin ? Vous pouvez, par exemple, personnaliser davantage l’expérience en choisissant un autre fournisseur de synthèse vocale, ou enrichir les capacités de votre assistant grâce à l’appel de fonctions (Function Calling). Gemini pourrait ainsi consulter la météo ou prendre des rendez-vous directement pendant la conversation. Vous pouvez également essayer différents modèles Gemini afin d’explorer leurs possibilités et d’adapter votre application à vos besoins.

Pour découvrir d’autres exemples et démonstrations exploitant ConversationRelay, nous vous invitons à consulter les articles suivants, rédigés par d’autres membres de l’équipe Twilio :

Vous préférez découvrir tout cela en images ? Retrouvez ma démonstration vidéo, dans laquelle je vous accompagne pas à pas pour intégrer Twilio à Gemini Flash :




Rishab Kumar est expert en relations avec les développeurs chez Twilio et passionné par le cloud. Vous pouvez le contacter sur Twitter @rishabincloud et retrouver ses publications consacrées au cloud, au DevOps et aux relations avec les développeurs (DevRel) à l’adresse youtube.com/@rishabincloud