Integra Google Gemini con Twilio Voice mediante ConversationRelay y Python

April 20, 2026
Redactado por
Revisado por

Resumen generado por IA
  • Configura el servidor FastAPI y conecta Google Gemini con Twilio Voice a través de ConversationRelay.
  • Configura las variables y dependencias de entorno necesarias para una comunicación segura.
  • Prueba tu integración enfocándote en Twilio y disfrutando de conversaciones telefónicas en tiempo real con tecnología de IA.

Este resumen fue generado por IA.

Imagina tener conversaciones que se sienten humanas en tiempo real con un modelo de IA por teléfono. Con Twilio Conversation Relay, puedes hacerlo realidad. Conecta tu llamada de voz con cualquier modelo de lenguaje grande (LLM) a través de un WebSocket rápido e impulsado por eventos, lo que permite una comunicación fluida.

En esta publicación, te mostraré cómo configurar Google Gemini con Twilio Voice mediante ConversationRelay. Al final, tendrás un servidor Python sencillo en ejecución, listo para permitirte marcar un número de Twilio y hablar con Gemini. Es un punto de partida perfecto para crear aplicaciones de voz más interactivas y repletas de funciones.

Requisitos previos

Para seguir los pasos de este tutorial, necesitarás lo siguiente:

Configura el proyecto

Comencemos creando un nuevo directorio para tu proyecto:

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

A continuación, crea un entorno virtual y actívalo:

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

Ahora, instala las dependencias necesarias mediante pip:

pip install google-genai python-dotenv uvicorn fastapi websockets

Utilizarás FastAPI como tu estructura para crear rápidamente un servidor tanto para WebSocket como para la ruta de Twilio.

Todo el código para este inicio rápido está disponible en GitHub.

Configura las variables de entorno

Deberás almacenar de forma segura tu clave de API de Google Gemini. Crea un archivo .env en la carpeta de tu proyecto y agrega lo siguiente:

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

Asegúrate de reemplazar los marcadores de posición con tu clave de API real y tu URL de reenvío de Ngrok (configurarás esto más adelante en la publicación).

Crea el servidor

Ahora, crea un nuevo archivo Python llamado main.py. Aquí es donde escribirás la lógica principal de la aplicación.

1. Importa las bibliotecas necesarias y configura el entorno

El primer paso para configurar el servidor es importar las bibliotecas necesarias. Estas bibliotecas te ayudarán a crear el servidor, manejar las conexiones de WebSocket, interactuar con Google Gemini y cargar variables de entorno.

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: esta es la estructura web principal que se utiliza para crear el servidor. Te permite definir rutas fácilmente y manejar solicitudes HTTP. También permite la comunicación de WebSocket entre el servidor y ConversationRelay de Twilio.
  • uvicorn: un servidor ASGI rápido que ejecuta la aplicación FastAPI.
  • genai: el SDK de Google Gen AI te permite interactuar con los modelos Gemini de Google para generar respuestas.
  • dotenv: este módulo ayuda a cargar variables de entorno (como tu clave de API de Google y la URL de Ngrok) desde un archivo .env.

Después de importar las bibliotecas, agrega la siguiente línea para cargar las variables de entorno desde el archivo .env:

load_dotenv()

Esto garantiza que la información confidencial (como las claves de API) no esté codificada en el código.

2. Constantes y configuración

Define algunas constantes para utilizar en todo el código a fin de personalizar el comportamiento de la aplicación.

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: el puerto para que el servidor escuche (ya sea desde una variable de entorno o el valor predeterminado de 8080).
  • DOMAIN: la URL de Ngrok que se utilizará para establecer una conexión de WebSocket con Twilio. El código lo valida de inmediato y genera un error si no está configurado.
  • WS_URL: la URL completa de WebSocket para el punto final donde se conectará Twilio.
  • WELCOME_GREETING: el saludo que se pronunciará cuando se conecte la llamada.
  • SYSTEM_PROMPT: este es un mensaje especial que se envía al modelo Gemini para indicarle cómo comportarse. Es importante porque ayuda a dar forma al tono y formato de las respuestas de la IA (p. ej., deletrear números, evitar emojis). Dado que esta es una conversación de voz, las reglas ayudan a garantizar un resultado limpio y agradable.
  • sessions: diccionario para almacenar objetos de sesión de chat activos para cada llamada (usando callSid como clave). Nota: Esta implementación solo se limpia al desconectarse correctamente; en producción, considera agregar el manejo del tiempo de espera de sesión.

3. Inicialización de FastAPI y el cliente Gemini

Inicializa la aplicación FastAPI y configura el cliente Gemini mediante la clave de API almacenada en el archivo .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: el código carga la clave API de las variables del entorno y valida que esté presente antes de continuar.
  • client: Inicializa el cliente de Google Gen AI con genai.Client(). Este es el nuevo patrón de SDK: si ya utilizaste el paquete anterior de Google-Generativeai, ten en cuenta que este es el SDK más reciente de Google-genai.
  • App FastAPI: esta crea el servidor web que manejará las solicitudes HTTP y las conexiones de WebSocket.

4. Función de respuesta de IA

Ahora crea una función que interactuará con la API de Gemini y obtendrá la respuesta de la IA.

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(): esta función toma un objeto de sesión de chat de Gemini y la indicación del usuario, envía el mensaje y devuelve la respuesta de texto. El objeto de sesión de chat mantiene automáticamente el historial de conversaciones, por lo que Gemini tiene un contexto completo de la conversación con cada mensaje nuevo.

5. Respuesta de TwiML para Twilio

El punto final /twiml está diseñado para proporcionar a Twilio instrucciones sobre cómo conectar una llamada de voz a tu aplicación WebSocket. Twilio utiliza TwiML (lenguaje de marcado de Twilio) para determinar cómo manejar las interacciones de voz.

@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 respuesta de TwiML indica a Twilio que se conecte al servidor de WebSocket (a través de WS_URL) y que salude a la persona que llama con el mensaje WELCOME_GREETING.
  • En este ejemplo, el código utiliza ElevenLabs como proveedor de texto a voz con un ID de voz específico (FGY2WhTYpPnrIDTdsKH5: este es un ID de voz de ejemplo; reemplácelo por uno propio si utiliza ElevenLabs). Esta es una personalización opcional: puedes eliminar los atributos ttsProvider y voice por completo para utilizar el TTS predeterminado de Twilio o intercambiar "ElevenLabs" por "Amazon" o "Google" si prefieres un proveedor diferente.
  • Consulta los documentos de ConversationRelay para obtener más información sobre todos los atributos compatibles, como language, ttsProvider y voice.
  • Nota: Este punto final no valida las firmas de solicitud de Twilio. Para el uso en producción, consulta la documentación de validación de solicitudes de Twilio.

6. Manejo de conexiones de WebSocket

El punto final de WebSocket de /ws maneja la comunicación en tiempo real entre Twilio y el servidor. Recibe mensajes de Twilio, los procesa y envía respuestas.

@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}")
  • El bucle while escucha los mensajes entrantes de Twilio. El servidor procesa diferentes tipos de mensajes:
  • setup: inicia una nueva sesión de chat de Gemini para esta llamada. El código utiliza client.chats.create() con el modelo gemini-2.5-flash y pasa la indicación del sistema a través del parámetro config. Esto crea un objeto de chat con estado que mantiene el historial de conversaciones automáticamente.
  • prompt: procesa la entrada de voz del usuario (transcrita al texto por Twilio) y la envía a Gemini a través de la función gemini_response(). El texto de respuesta se envía de vuelta a Twilio, que lo convierte en voz.
  • interrupt: maneja cualquier interrupción durante la conversación (p. ej., cuando la persona que llama habla mientras la IA sigue hablando).
  • Unknown message: registra cualquier tipo de mensaje no reconocido.
  • sessions: las sesiones de chat activas de Gemini se almacenan en el diccionario sessions, indexadas por call_sid. Cuando el WebSocket se desconecta, la sesión se limpia.

7. Ejecuta el servidor FastAPI

Por último, ejecuta el servidor FastAPI con Uvicorn:

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

uvicorn.run(): esto inicia el servidor, que escucha en el puerto especificado (el valor predeterminado es 8080). El servidor ahora está listo para manejar tanto las solicitudes HTTP (para TwiML) como las conexiones WebSocket (para la conversación en tiempo real).

Ejecuta el servidor

Para ejecutar el servidor, primero, abre una terminal e inicia un túnel Ngrok:

ngrok http 8080

Abre primero el socket de conexión de ngrok, porque necesitarás la URL de ngrok en dos lugares: en Twilio Console y en tu archivo .env.

Toma nota de tu URL de Ngrok (p. ej., https://1234abcd.ngrok.app) y agrega la parte del dominio a tu archivo .env:

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

Ahora puedes iniciar el servidor con:

python main.py

Configura Twilio

Ve a Twilio Console y selecciona tu número de teléfono de Twilio. En la pestaña Configurar, en los ajustes de Configuración de voz, establece la URL del webhook en tu URL de Ngrok (incluyendo /twiml), de la siguiente manera:

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

Prueba la integración

Con todo configurado, marca tu número de teléfono de Twilio desde tu teléfono móvil. Deberás escuchar el mensaje de saludo y puedes comenzar a hacer preguntas a la IA.

¿Qué sigue?

Esta app de Python configura un servidor FastAPI que conecta las capacidades de voz de Twilio con ConversationRelay, lo que permite comunicarse en tiempo real con un asistente de IA con tecnología de Google Gemini. El servidor se encarga de las solicitudes HTTP (para dar a Twilio sus instrucciones) y las conexiones de WebSocket (para la comunicación en directo con la IA). A medida que llamas, ConversationRelay organiza el manejo de la transcripción, las comunicaciones con el LLM y el texto a voz con base en la respuesta del LLM, para impulsar una conversación fluida entre tú y un asistente de IA con tecnología Gemini.

Ahora que tienes un asistente de voz en tiempo real en funcionamiento, puedes explorar otras personalizaciones, como intercambiar proveedores de TTS, agregar llamadas de funciones para permitir que Gemini revise el clima o reserve citas durante la llamada, o experimentar con diferentes modelos de Gemini.

Si buscas más ejemplos y demostraciones con ConversationRelay, consulta estas publicaciones de blog de otros Twilions:

¿Prefieres verlo? Esta es mi explicación paso a paso de la integración de Twilio y Gemini Flash:




Rishab Kumar es un evangelista de desarrolladores en Twilio y un entusiasta de la nube. Ponte en contacto con Rishab en Twitter @rishabincloud y sigue su blog personal sobre aventuras en la nube, DevOps y DevRel en youtube.com/@rishabincloud.