Integre o Google Gemini ao Twilio Voice usando ConversationRelay e Python

April 20, 2026
Escrito por
Revisado por

Resumo gerado por IA
  • Configure o servidor FastAPI e conecte o Google Gemini ao Twilio Voice por meio do ConversationRelay.
  • Configure as variáveis de ambiente e as dependências necessárias para uma comunicação segura.
  • Teste sua integração discando para a Twilio e desfrutando de conversas telefônicas em tempo real com IA.

Este resumo foi gerado por IA.

Imagine ter conversas em tempo real com um modelo de IA pelo telefone, de forma natural e semelhante a uma conversa entre humanos. Com o Twilio Conversation Relay, você pode tornar isso uma realidade. Ele conecta sua chamada de voz a qualquer LLM (grande modelo de linguagem) por meio de um WebSocket rápido e orientado por eventos, permitindo uma comunicação confiável.

Nesta publicação, mostrarei como configurar o Google Gemini com o Twilio Voice usando o ConversationRelay. Ao final, você terá um servidor Python simples em funcionamento, pronto para permitir que você ligue para um número da Twilio e converse com o Gemini. É um ponto de partida perfeito para criar aplicativos de voz mais interativos e ricos em recursos.

Pré-requisitos

Para acompanhar este tutorial, você precisará de:

Configurar o projeto

Vamos começar criando um novo diretório para seu projeto:

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

Em seguida, crie um ambiente virtual e ative-o:

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

Agora, instale as dependências necessárias usando pip:

pip install google-genai python-dotenv uvicorn fastapi websockets

Você usará o FastAPI como sua estrutura para configurar rapidamente um servidor que gerencie tanto a conexão WebSocket quanto a rota da Twilio.

Todo o código para este início rápido está disponível no GitHub.

Como configurar as variáveis de ambiente

Você precisará armazenar sua chave de API do Google Gemini com segurança. Crie um arquivo .env na pasta do projeto e adicione o seguinte:

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

Certifique-se de substituir os espaços reservados pela chave de API real e pelo URL de encaminhamento do Ngrok (você configurará isso mais tarde na publicação).

Criar o servidor

Agora, crie um novo arquivo Python chamado main.py. É aqui que você escreverá a lógica principal do aplicativo.

1. Importe bibliotecas necessárias e configure o ambiente

A primeira etapa na configuração do servidor é importar as bibliotecas necessárias. Essas bibliotecas ajudarão você a criar o servidor, lidar com conexões WebSocket, interagir com o Google Gemini e carregar variáveis de ambiente.

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 é a principal estrutura web usada para criar o servidor. FastAPI permite definir rotas e processar requisições HTTP com facilidade. Também possibilita a comunicação via WebSocket entre o servidor e o ConversationRelay da Twilio.
  • uvicorn: Um servidor ASGI rápido que executa o aplicativo FastAPI.
  • genai: O SDK Google Gen AI permite interagir com os modelos Gemini do Google para gerar respostas.
  • dotenv: Este módulo ajuda a carregar variáveis de ambiente (como sua chave de API do Google e URL do Ngrok) de um arquivo .env.

Depois de importar as bibliotecas, adicione a seguinte linha para carregar variáveis de ambiente do arquivo .env:

load_dotenv()

Isso garante que informações confidenciais (como chaves de API) não sejam inseridas diretamente no código.

2. Constantes e configuração

Defina algumas constantes a serem usadas em todo o código para personalizar o comportamento do aplicativo.

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: A porta na qual o servidor ficará disponível (obtida de uma variável de ambiente ou definida como 8080 por padrão).
  • DOMAIN: O URL do Ngrok que será usado para estabelecer uma conexão WebSocket com a Twilio. O código valida esse valor imediatamente e gera um erro caso ele não esteja definido.
  • WS_URL: O URL completo do WebSocket para o endpoint ao qual a Twilio se conectará.
  • WELCOME_GREETING: A mensagem de saudação que será reproduzida quando a chamada for conectada.
  • SYSTEM_PROMPT: Esta é uma mensagem especial enviada ao modelo Gemini para instruí-lo sobre como se comportar. Ela é importante porque ajuda a definir o tom e o formato das respostas da IA (por exemplo, escrever os números por extenso e evitar emojis). Como se trata de uma conversa por voz, essas regras ajudam a garantir respostas claras e fáceis de falar em voz alta.
  • sessions: Um dicionário para armazenar os objetos das sessões de chat ativas de cada chamada, usando o callSid como a chave). Observação: esta implementação realiza a limpeza apenas quando a desconexão ocorre corretamente. Em um ambiente de produção, considere adicionar um mecanismo para gerenciar o tempo limite das sessões.

3. Inicialização do FastAPI e do cliente Gemini

Inicialize o aplicativo FastAPI e configure o cliente Gemini usando a chave de API armazenada no arquivo .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: O código carrega a chave de API das variáveis de ambiente e verifica se ela está definida antes de continuar.
  • client: Inicializa o cliente Google Gen AI usando genai.Client(). Este é o novo padrão do SDK. Se você já utilizou o pacote antigo google-generativeai, observe que este é o SDK google-genai mais recente.
  • FastAPI app: Cria o servidor web que será responsável por processar as requisições HTTP e as conexões WebSocket.

4. Função de resposta da IA

Agora, crie uma função que interaja com a API do Gemini e obtenha a resposta da 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 função recebe um objeto de sessão de chat do Gemini e o prompt do usuário, envia a mensagem e retorna a resposta em texto. O objeto da sessão de chat mantém automaticamente o histórico da conversa, permitindo que o Gemini tenha todo o contexto das interações anteriores a cada nova mensagem.

5. Resposta TwiML para Twilio

O endpoint /twiml foi projetado para fornecer à Twilio instruções sobre como conectar uma chamada de voz ao seu aplicativo WebSocket. A Twilio usa TwiML (Twilio Markup Language) para determinar como lidar com interações 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")
  • A resposta TwiML instrui a Twilio a se conectar ao servidor WebSocket (por meio do WS_URL) e a cumprimentar o autor da chamada com a mensagem WELCOME_GREETING.
  • Neste exemplo, o código usa ElevenLabs como provedor de conversão de texto em fala com um ID de voz específico (FGY2WhTYpPnrIDTdsKH5: este é um exemplo; se você estiver usando o ElevenLabs, substitua-o pelo seu próprio ID de voz). Esta é uma personalização opcional. Você pode remover os atributos ttsProvider e voice inteiramente para usar o TTS padrão da Twilio ou trocar "ElevenLabs" por "Amazon" ou "Google", se preferir um provedor diferente.
  • Consulte a documentação do ConversationRelay para obter mais informações sobre todos os atributos compatíveis, como language (idioma), ttsProvider (provedor de conversão de texto em fala) e voice (voz).
  • Observação: este endpoint não valida as assinaturas das solicitações da Twilio. Para uso em produção, consulte a documentação de validação de solicitações da Twilio.

6. Gerenciamento de conexões WebSocket

O endpoint WebSocket /ws lida com a comunicação em tempo real entre a Twilio e o servidor. Ele recebe mensagens da Twilio, as processa e envia respostas de volta.

@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}")
  • O loop while escuta mensagens recebidas da Twilio. O servidor processa diferentes tipos de mensagem:
  • setup: Inicializa uma nova sessão de chat do Gemini para esta chamada. O código usa client.chats.create() com o modelo gemini-2.5-flash e passa o prompt do sistema pelo parâmetro config. Isso cria um objeto de chat dinâmico que mantém o histórico de conversas automaticamente.
  • prompt: Processa a entrada de voz do usuário (transcrita em texto pela Twilio) e a envia para a Gemini por meio da função gemini_response(). O texto de resposta é enviado de volta para a Twilio, que o converte em fala.
  • interrupt: Lida com quaisquer interrupções durante a conversa (por exemplo, quando o autor da chamada fala ao mesmo tempo que a IA).
  • Unknown message: Registra todos os tipos de mensagem não reconhecidos.
  • sessions: As sessões de chat ativas do Gemini são armazenadas no dicionário sessions, indexadas pelo call_sid. Quando o WebSocket se desconecta, a sessão é removida.

7. Execute o servidor FastAPI

Por fim, execute o servidor FastAPI usando Uvicorn:

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

uvicorn.run(): Isso inicia o servidor, ouvindo na porta especificada (o padrão é 8080). O servidor agora está pronto para lidar tanto com requisições HTTP (para TwiML) quanto com conexões WebSocket (para conversas em tempo real).

Execute o servidor

Para executar o servidor, primeiro, abra um terminal e inicie um túnel Ngrok:

ngrok http 8080

Abra primeiro a conexão do Ngrok, pois você precisará do URL do Ngrok em dois lugares: no Twilio Console e no seu arquivo .env.

Anote seu URL do Ngrok (por exemplo, https://1234abcd.ngrok.app) e adicione a parte do domínio ao arquivo .env:

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

Agora você pode iniciar o servidor com:

python main.py

Configure a Twilio

Acesse o Twilio Console e selecione o seu número de telefone Twilio. Na guia Configure, em Voice Configuration (Configurações de voz), defina o URL do webhook como o URL do seu Ngrok (incluindo /twiml), assim:

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

Teste a integração

Com tudo configurado, disque seu número de telefone Twilio no celular. Você deve ouvir a mensagem de saudação e pode começar a fazer perguntas à IA.

O que vem a seguir?

Este app Python configura um servidor FastAPI que conecta os recursos de voz da Twilio ao ConversationRelay, permitindo comunicação em tempo real com um assistente de IA com tecnologia Google Gemini. O servidor gerencia tanto as requisições HTTP (para fornecer instruções à Twilio) quanto as conexões WebSocket (para a comunicação em tempo real com a IA). Ao realizar a ligação, o ConversationRelay coordena o processamento da transcrição, a comunicação com o LLM e a conversão de texto em fala com base na resposta do LLM, proporcionando uma conversa fluida entre você e um assistente de IA baseado no Gemini.

Agora que você tem um assistente de voz em tempo real, pode explorar outras personalizações, como trocar provedores de TTS, adicionar Function Calling para permitir que o Gemini verifique o clima ou faça agendamentos durante a chamada, ou experimentar diferentes modelos do Gemini.

Se você estiver procurando mais exemplos e demonstrações com o ConversationRelay, confira estas publicações de blog de outros Twilions:

Prefere assistir? Aqui está meu passo a passo da integração Twilio e Gemini Flash:




Rishab Kumar é desenvolvedor evangelista da Twilio e entusiasta da nuvem. Entre em contato com Rishab no Twitter @rishabincloud e siga seu blog pessoal sobre aventuras em nuvem, DevOps e DevRel em youtube.com/@rishabincloud