Integrieren Sie Google Gemini mit Twilio Voice mithilfe von ConversationRelay und Python

April 20, 2026
Autor:in:
Prüfer:in:

KI-generierte Zusammenfassung
  • Richten Sie einen FastAPI-Server ein und verbinden Sie Google Gemini über ConversationRelay mit Twilio Voice.
  • Konfigurieren Sie die erforderlichen Umgebungsvariablen und Abhängigkeiten für eine sichere Kommunikation.
  • Testen Sie die Integration, indem Sie Ihre Twilio-Nummer anrufen und KI-gestützte Telefongespräche in Echtzeit führen.

Diese Zusammenfassung wurde mithilfe von KI erstellt.

Stellen Sie sich vor, Sie könnten am Telefon in Echtzeit mit einem KI-Modell sprechen und das Gespräch würde sich fast wie mit einem Menschen anfühlen. Mit Twilio Conversation Relay wird das möglich. ConversationRelay verbindet Ihren Sprachanruf über einen schnellen, ereignisgesteuerten WebSocket mit einem beliebigen Large Language Model (LLM) und ermöglicht so eine nahtlose Kommunikation.

In diesem Beitrag zeige ich Ihnen, wie Sie Google Gemini über ConversationRelay mit Twilio Voice verbinden. Am Ende läuft ein einfacher Python-Server, über den Sie eine Twilio-Nummer anrufen und mit Gemini sprechen können. Damit haben Sie eine ideale Grundlage für interaktivere Sprachanwendungen mit umfangreicheren Funktionen.

Voraussetzungen

Für dieses Tutorial benötigen Sie:

Projekt einrichten

Erstellen Sie zunächst ein neues Verzeichnis für Ihr Projekt:

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

Erstellen und aktivieren Sie anschließend eine virtuelle Umgebung:

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

Installieren Sie nun die erforderlichen Abhängigkeiten mit pip:

pip install google-genai python-dotenv uvicorn fastapi websockets

Als Framework verwenden Sie FastAPI. Damit richten Sie schnell einen Server für den WebSocket und die Twilio-Route ein.

Den vollständigen Code für diesen Quickstart finden Sie auf GitHub.

Umgebungsvariablen konfigurieren

Sie müssen Ihren API-Schlüssel für Google Gemini sicher speichern. Erstellen Sie im Projektordner eine .env-Datei und fügen Sie Folgendes hinzu:

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

Ersetzen Sie die Platzhalter durch Ihren tatsächlichen API-Schlüssel und die Weiterleitungs-URL von Ngrok. Diese richten Sie später im Beitrag ein.

Server erstellen

Erstellen Sie nun eine neue Python-Datei namens main.py. In dieser Datei schreiben Sie die Hauptlogik der Anwendung.

1. Erforderliche Bibliotheken importieren und Umgebung einrichten

Importieren Sie beim Einrichten des Servers zunächst die erforderlichen Bibliotheken. Mit diesen Bibliotheken erstellen Sie den Server, verarbeiten WebSocket-Verbindungen, kommunizieren mit Google Gemini und laden Umgebungsvariablen.

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: FastAPI ist das zentrale Webframework für den Server. Damit können Sie auf einfache Weise Routen definieren und HTTP-Anfragen verarbeiten. Außerdem ermöglicht FastAPI die WebSocket-Kommunikation zwischen dem Server und Twilio ConversationRelay.
  • uvicorn: Ein schneller ASGI-Server, der die FastAPI-Anwendung ausführt.
  • genai: Mit dem Google Gen AI SDK können Sie mit den Gemini-Modellen von Google interagieren und Antworten generieren.
  • dotenv: Dieses Modul lädt Umgebungsvariablen wie Ihren Google API-Schlüssel und die Ngrok-URL aus einer .env-Datei.

Nachdem Sie die Bibliotheken importiert haben, fügen Sie die folgende Zeile hinzu, um die Umgebungsvariablen aus der .env-Datei zu laden:

load_dotenv()

So verhindern Sie, dass sensible Daten wie API-Schlüssel direkt im Code hinterlegt werden.

2. Konstanten und Konfiguration

Definieren Sie einige Konstanten, mit denen Sie das Verhalten der Anwendung im gesamten Code steuern.

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: Der Port, an dem der Server auf Verbindungen wartet. Er wird entweder aus einer Umgebungsvariablen gelesen oder standardmäßig auf 8080 gesetzt.
  • DOMAIN: Die Ngrok-URL, über die eine WebSocket-Verbindung mit Twilio hergestellt wird. Der Code prüft sofort, ob die URL gesetzt ist, und löst andernfalls einen Fehler aus.
  • WS_URL: Die vollständige WebSocket-URL des Endpunkts, mit dem Twilio eine Verbindung herstellt.
  • WELCOME_GREETING: Die Begrüßung, die zu Beginn des Anrufs gesprochen wird.
  • SYSTEM_PROMPT: Eine spezielle Nachricht an das Gemini-Modell, die vorgibt, wie es sich verhalten soll. Damit lassen sich Ton und Format der KI-Antworten steuern, etwa indem Zahlen ausgeschrieben und Emojis vermieden werden. Da es sich um ein Sprachgespräch handelt, sorgen diese Regeln für eine klare Ausgabe, die sich gut vorlesen lässt.
  • sessions: Ein Wörterbuch, in dem die aktiven Chat-Sitzungsobjekte für die einzelnen Anrufe gespeichert werden. Als Schlüssel dient jeweils die callSid. Hinweis: Diese Implementierung bereinigt Sitzungen nur bei einem ordnungsgemäßen Verbindungsabbau. Für den Produktionseinsatz sollten Sie zusätzlich Session-Timeouts berücksichtigen.

3. FastAPI und den Gemini-Client initialisieren

Initialisieren Sie die FastAPI-Anwendung und richten Sie den Gemini-Client mit dem API-Schlüssel aus der Datei .env ein.

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: Der Code lädt den API-Schlüssel aus den Umgebungsvariablen und prüft, ob er vorhanden ist, bevor die Ausführung fortgesetzt wird.
  • client: Initialisieren Sie den Google Gen AI-Client mit genai.Client(). Dabei handelt es sich um das neue SDK-Muster. Falls Sie bisher das ältere Paket google-generativeai verwendet haben, beachten Sie, dass google-genai das neuere SDK ist.
  • FastAPI-App: Damit wird der Webserver erstellt, der HTTP-Anfragen und WebSocket-Verbindungen verarbeitet.

4. Funktion für KI-Antworten

Erstellen Sie nun eine Funktion, die mit der Gemini API kommuniziert und die Antwort der KI abruft.

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(): Diese Funktion übernimmt ein Gemini-Chat-Sitzungsobjekt und den Prompt des Nutzers, sendet die Nachricht und gibt die Textantwort zurück. Das Chat-Sitzungsobjekt verwaltet den Gesprächsverlauf automatisch. Dadurch steht Gemini bei jeder neuen Nachricht der vollständige Gesprächskontext zur Verfügung.

5. TwiML-Antwort für Twilio

Der Endpunkt /twiml übermittelt Twilio die Anweisungen, mit denen ein Sprachanruf mit Ihrer WebSocket-Anwendung verbunden wird. Twilio verwendet TwiML (Twilio Markup Language), um festzulegen, wie Sprachinteraktionen verarbeitet werden.

@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")
  • Die TwiML-Antwort weist Twilio an, über WS_URL eine Verbindung zum WebSocket-Server herzustellen und den Anrufer mit der Nachricht WELCOME_GREETING zu begrüßen.
  • In diesem Beispiel verwendet der Code ElevenLabs als Text-to-Speech-Anbieter mit der Voice-ID FGY2WhTYpPnrIDTdsKH5. Dabei handelt es sich um eine Beispiel-ID, die Sie durch Ihre eigene ersetzen sollten, wenn Sie ElevenLabs verwenden. Diese Anpassung ist optional. Wenn Sie die Standard-TTS von Twilio verwenden möchten, können Sie die Attribute ttsProvider und voice vollständig entfernen. Alternativ können Sie "ElevenLabs" durch "Amazon" oder "Google" ersetzen.
  • Weitere Informationen zu unterstützten Attributen wie language, ttsProvider und voice finden Sie in der ConversationRelay-Dokumentation.
  • Hinweis: Dieser Endpunkt validiert keine Signaturen von Twilio-Anfragen. Für den produktiven Einsatz finden Sie weitere Informationen in der Twilio-Dokumentation zur Anfragevalidierung.

6. WebSocket-Verbindungen verarbeiten

Der WebSocket-Endpunkt /ws übernimmt die Echtzeitkommunikation zwischen Twilio und dem Server. Er empfängt Nachrichten von Twilio, verarbeitet sie und sendet Antworten zurück.

@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}")
  • Die while-Schleife wartet auf eingehende Nachrichten von Twilio. Der Server verarbeitet verschiedene Nachrichtentypen:
  • setup: Initialisiert für den jeweiligen Anruf eine neue Gemini-Chat-Sitzung. Der Code verwendet client.chats.create() mit dem gemini-2.5-flash-Modell und übergibt den System-Prompt über den Parameter config. Dadurch wird ein zustandsbehaftetes Chat-Objekt erstellt, das den Gesprächsverlauf automatisch speichert.
  • prompt: Verarbeitet die Spracheingabe des Nutzers, die Twilio zuvor in Text transkribiert hat, und sendet sie über die Funktion gemini_response() an Gemini. Der Antworttext wird an Twilio zurückgesendet und dort in Sprache umgewandelt.
  • interrupt: Verarbeitet Unterbrechungen während des Gesprächs, beispielsweise wenn der Anrufer der KI ins Wort fällt.
  • Unbekannte Nachricht: Protokolliert alle nicht erkannten Nachrichtentypen.
  • sessions: Aktive Gemini-Chat-Sitzungen werden im Wörterbuch sessions gespeichert und über die jeweilige call_sid zugeordnet. Wenn die WebSocket-Verbindung getrennt wird, wird die zugehörige Sitzung bereinigt.

7. FastAPI-Server starten

Führen Sie den FastAPI-Server abschließend mit Uvicorn aus:

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

uvicorn.run(): Damit wird der Server gestartet und wartet am angegebenen Port auf eingehende Verbindungen. Standardmäßig ist dies Port 8080. Der Server kann nun sowohl HTTP-Anfragen für TwiML als auch WebSocket-Verbindungen für Echtzeitgespräche verarbeiten.

Server starten

Öffnen Sie zunächst ein Terminal und starten Sie einen Ngrok-Tunnel:

ngrok http 8080

Öffnen Sie zuerst die Ngrok-Verbindung, da Sie die Ngrok-URL an zwei Stellen benötigen: in der Twilio Console und in der Datei .env.

Notieren Sie sich die Ngrok-URL, zum Beispiel https://1234abcd.ngrok.app, und tragen Sie den Domainteil in die Datei .env ein:

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

Nun können Sie den Server mit folgendem Befehl starten:

python main.py

Twilio konfigurieren

Öffnen Sie die Twilio Console und wählen Sie Ihre Twilio-Telefonnummer aus. Tragen Sie auf der Registerkarte Configure unter Voice Configuration die Ngrok-URL einschließlich /twiml als Webhook-URL ein, beispielsweise:

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

Integration testen

Wenn alles eingerichtet ist, rufen Sie Ihre Twilio-Telefonnummer mit Ihrem Mobiltelefon an. Sie sollten nun die Begrüßung hören. Anschließend können Sie der KI Fragen stellen.

Wie geht es weiter?

Diese Python-App richtet einen FastAPI-Server ein, der Twilio Voice über ConversationRelay mit einem KI-Assistenten auf Basis von Google Gemini verbindet. Damit ist Echtzeitkommunikation mit dem KI-Assistenten möglich. Der Server verarbeitet sowohl HTTP-Anfragen, über die Twilio seine Anweisungen erhält, als auch WebSocket-Verbindungen für die Live-Kommunikation mit der KI. Während des Anrufs orchestriert ConversationRelay die Verarbeitung der Transkription, die Kommunikation mit dem LLM und die Text-to-Speech-Ausgabe auf Grundlage der LLM-Antwort. So entsteht ein flüssiges Gespräch zwischen Ihnen und dem KI-Assistenten auf Basis von Gemini.

Jetzt haben Sie einen funktionierenden Echtzeit-Sprachassistenten und können weitere Anpassungen ausprobieren. Wechseln Sie beispielsweise den TTS-Anbieter, ergänzen Sie Function Calling, damit Gemini während des Anrufs das Wetter abrufen oder Termine buchen kann, oder testen Sie verschiedene Gemini-Modelle.

Weitere Beispiele und Demos zu ConversationRelay finden Sie in diesen Blogbeiträgen anderer Twilions:

Möchten Sie lieber ein Video dazu sehen? Hier finden Sie meine Anleitung zur Integration von Twilio und Gemini Flash:




Rishab Kumar ist Developer Evangelist bei Twilio und begeistert sich für Cloud-Technologien. Sie erreichen Rishab auf Twitter unter @rishabincloud. Seinen persönlichen Blog über Cloud, DevOps und DevRel finden Sie unter youtube.com/@rishabincloud.