Centro de ayuda
ayuda@netelip.com

Integración Gemini Live

Integración Gemini Live

Integración Gemini Live con SIP Trunk de netelip

Conecta la API de voz en tiempo real de Google a cualquier número virtual de netelip usando LiveKit, Modal.com y Supabase como infraestructura.

Integración Gemini Live con los números virtuales de netelip

Conecta la API de voz en tiempo real de Google a cualquier número virtual de netelip usando LiveKit, Modal.com y Supabase como infraestructura.

Esta guía explica cómo configurar la integración paso a paso: qué debes preparar en netelip, qué debes configurar en cada plataforma, y cómo verificar que el agente responde antes de ponerlo en producción.

A quién va dirigida: desarrolladores que integran IA conversacional con telefonía VoIP, equipos técnicos de empresas que ya operan con netelip, e integradores que construyen agentes de voz para clientes.

Cómo funciona la integración

Esta integración conecta Gemini Live API a un número de teléfono real. El audio de cada llamada viaja a través de cuatro componentes que trabajan juntos:

Llamada entrante → teléfono del llamante marca el número de netelip
netelip SIP Trunk Recibe la llamada y la enruta vía SIP a LiveKit
LiveKit Cloud Convierte SIP → WebRTC y entrega el audio al worker
Worker en Modal Carga la config del agente desde Supabase y abre sesión
Gemini Live API Procesa el audio y genera respuesta de voz en tiempo real
La respuesta vuelve por el mismo camino hasta el teléfono del llamante.
Componente Función en la arquitectura
netelipOperador SIP. Proporciona el número virtual y el SIP Trunk que recibe la llamada y la enruta a LiveKit.
LiveKit CloudPuente SIP ↔ WebRTC. Sin LiveKit, Gemini no puede recibir audio de una llamada telefónica.
Modal.comInfraestructura serverless donde corre el worker Python con la lógica del agente. Debe estar activo 24 horas.
Gemini Live APIMotor de IA conversacional. Procesa el audio y genera respuestas de voz en tiempo real vía WebSocket.
SupabaseBase de datos donde se almacena la configuración por agente y los transcritos de cada llamada.
Qué necesitas antes de empezar
Plataforma Qué necesitas
netelipNúmero virtual activo (geográfico, nacional o internacional). SIP Trunk disponible en tu cuenta.
LiveKit CloudCuenta creada en cloud.livekit.io
Modal.comCuenta creada en modal.com
SupabaseCuenta creada con permisos para crear tablas.
Google AI StudioAPI key en aistudio.google.com/apikey. Facturación activa en el proyecto de Google Cloud asociado.
Paso 1. Crear el proyecto en LiveKit Cloud

Accede a cloud.livekit.io y crea un proyecto nuevo. Obtendrás tres credenciales que necesitarás en los pasos siguientes:

LIVEKIT_URL        →  wss://tu-proyecto.livekit.cloud
LIVEKIT_API_KEY    →  tu clave API
LIVEKIT_API_SECRET →  tu secreto API

Guarda estas credenciales. Las necesitarás al configurar los secrets en Modal.com (Paso 5) y al registrar el SIP Inbound Trunk en LiveKit (Paso 2).

Paso 2. Crear el SIP Inbound Trunk en LiveKit

El SIP Inbound Trunk le indica a LiveKit de dónde esperar llamadas entrantes. Apunta al número virtual de netelip que usarás con este agente.

En el panel de LiveKit, ve a SIP → Inbound Trunks → New Trunk e introduce estos datos:

  • Name: el nombre que quieras (por ejemplo: Mi trunk netelip).
  • Numbers: tu número virtual de netelip en formato E.164.
  • Allowed IPs: dejar vacío para aceptar todas las IPs entrantes.

Una vez guardado, LiveKit genera una SIP URI de entrada:

xxxxxxxxxxxxxxx.sip.livekit.cloud

Guarda esta SIP URI. Es el destino que introducirás en la configuración de netelip en el Paso 3.

Formato correcto del número virtual (E.164)

El número debe incluir el prefijo internacional, sin espacios ni guiones:

+34910000000  →  número geográfico de Madrid
+34930000000  →  número geográfico de Barcelona
+34900000000  →  número de red inteligente (900)
+52550000000  →  número virtual de México
+56220000000  →  número virtual de Chile
Paso 3. Configurar netelip para enviar las llamadas a LiveKit

Accede a tu panel de cliente de netelip. Localiza la configuración del número virtual o del SIP Trunk y establece como destino la SIP URI de LiveKit con este formato:

+34XXXXXXXXX@xxxxxxxxxxxxxxx.sip.livekit.cloud
  • +34XXXXXXXXX → tu número virtual en netelip en formato E.164.
  • xxxxxxxxxxxxxxx.sip.livekit.cloud → la SIP URI de tu proyecto en LiveKit (Paso 2).

Desde este momento, cualquier llamada que llegue a ese número viajará automáticamente vía SIP hasta LiveKit. Cuando el worker de Modal esté activo (Paso 5), el agente responderá.

¿Qué tipo de número usar?
Tipo de número Cuándo usarlo
Geográfico (91, 93, 96…)Agente con presencia local. El llamante ve un número fijo de su ciudad.
Nacional 900 (gratuito)Línea de atención centralizada. El 900 elimina la barrera del coste para el llamante.
Nacional 901 / 902Servicios con coste compartido o total. Uso en declive; valora alternativas.
Internacional (México, Chile…)Agentes que atienden mercados latinoamericanos desde infraestructura en España.
Paso 4. Crear la Dispatch Rule en LiveKit

La Dispatch Rule le indica a LiveKit qué hacer cuando llega una llamada: a qué sala asignarla y qué agente debe gestionarla.

En el panel de LiveKit, ve a SIP → Dispatch Rules → New Rule e introduce esta configuración en JSON:

{
  "agent_name": "gemini-sip-agent",
  "metadata": "{\"agent_id\": \"TU_UUID_DEL_AGENTE\"}"
}
Campo Explicación
agent_nameDebe coincidir exactamente con el nombre del worker Python en Modal. Sensible a mayúsculas, espacios y guiones.
metadataJSON en formato string. Transporta el agent_id al worker para cargar la configuración desde Supabase.

Punto crítico: el valor de agent_name en la Dispatch Rule y el nombre del worker en Modal deben ser idénticos carácter a carácter. Cualquier diferencia —mayúsculas, espacios, guiones— rompe el enrutamiento y la llamada queda sin respuesta.

Paso 5. Desplegar el worker Python en Modal.com

Modal.com ejecuta el worker Python con la lógica del agente. Es imprescindible mantener siempre una instancia activa para que las llamadas no queden sin respuesta.

Por qué min_containers=1 es imprescindible: sin esta configuración, Modal apaga el worker cuando no hay actividad. El arranque en frío tarda 10-15 segundos: tiempo suficiente para que la llamada ya haya colgado. Con min_containers=1 siempre hay una instancia esperando. Para llamadas simultáneas, aumenta este valor según el volumen esperado. Coste: Modal cobra por tiempo de ejecución continuo — consulta su página de precios antes de desplegar.

1. Imagen y dependencias
image = (
    modal.Image.debian_slim(python_version='3.11')
    .pip_install(
        'livekit-agents[google]>=1.0',
        'livekit-plugins-google>=1.0',
        'supabase>=2.0',
        'google-generativeai>=0.8',
    )
)
2. Entrypoint: lógica de cada llamada

Carga la configuración del agente desde Supabase, abre la sesión con Gemini y guarda el transcrito al colgar.

async def entrypoint(ctx):
    await ctx.connect()
    agent_id = json.loads(ctx.job.metadata).get('agent_id')
    config = get_agent_config(agent_id)  # carga desde Supabase
    session = AgentSession(
        llm=google.beta.realtime.RealtimeModel(
            model='gemini-2.0-flash-live-preview',
            api_key=config['gemini_api_key'],
            voice=config['voice_name'],
        )
    )
    await session.start(room=ctx.room, agent=VoiceAgent())
    await session.wait_for_disconnect()
    save_session(...)  # guarda transcript en Supabase
3. Worker persistente (activo 24 horas)
@app.function(
    secrets=['supabase-credentials', 'livekit-credentials', 'google-api-key'],
    timeout=86400,
    min_containers=1,  # CRÍTICO: siempre hay 1 instancia activa
)
def run_worker():
    sys.argv = ['agent', 'start',
        '--url', os.environ['LIVEKIT_URL'],
        '--api-key', os.environ['LIVEKIT_API_KEY'],
        '--api-secret', os.environ['LIVEKIT_API_SECRET'],
    ]
    cli.run_app(WorkerOptions(
        entrypoint_fnc=entrypoint,
        agent_name='gemini-sip-agent',  # idéntico al de la Dispatch Rule
    ))

Nota — agent_id en ctx.job.metadata: el agent_id se pasa en el metadata de la Dispatch Rule y el worker lo lee desde ctx.job.metadata, no desde ctx.room.metadata. El código debería comprobar ambas ubicaciones por seguridad.

Nota — sys.argv injection: cli.run_app espera argumentos de línea de comandos. Modal no tiene CLI en ejecución, así que los argumentos se inyectan manualmente en sys.argv. Es la forma correcta de inicializar el worker en este entorno.

Secrets que debes crear en Modal
Nombre del secret Variables que debe contener
supabase-credentialsSUPABASE_URL, SUPABASE_SERVICE_KEY
livekit-credentialsLIVEKIT_URL, LIVEKIT_API_KEY, LIVEKIT_API_SECRET
google-api-keyGOOGLE_API_KEY — fallback si el agente no tiene su propia API key de Google
Despliegue
pip install modal
modal setup            # autentica con tu cuenta de Modal
modal deploy agent.py  # despliega el worker; queda corriendo permanentemente
Paso 6. Configurar la tabla de agentes en Supabase

Supabase almacena la configuración individual de cada agente y los transcritos. El worker carga esta configuración al inicio de cada llamada usando el agent_id recibido en el metadata de la Dispatch Rule.

Crea la tabla agents con estos campos:

Campo Descripción
gemini_api_keyAPI key de Google AI Studio del propietario del agente. Puede ser por cliente o global.
voice_nameVoz de Gemini. Opciones: Puck, Charon, Kore, Fenrir, Aoede, Leda, Orus, Zephyr.
system_promptInstrucciones del agente: rol, tono, límites, información del negocio, respuestas tipo.
greetingTexto que el agente pronuncia automáticamente al conectar la llamada.
user_idIdentificador del propietario del agente en la plataforma.

Asegúrate de tener al menos un registro con el agent_id que usas en la Dispatch Rule antes de hacer la primera prueba.

API key por agente: cada agente puede tener su propia API key de Google, que el worker carga desde Supabase al inicio de la llamada. Si no existe, usa la key global configurada como secret en Modal. Esto permite que múltiples clientes compartan la plataforma con sus propias credenciales.

Límite de duración de sesión: Gemini Live tiene un límite por conexión WebSocket (actualmente en torno a 15 minutos). Para llamadas largas, implementa lógica de reconexión automática o avisa al llamante antes de que se agote el tiempo.

Flujo completo de una llamada

Lo que ocurre internamente cada vez que alguien llama al número virtual:

1 El llamante marca el número virtual de netelip.
2 netelip envía un SIP INVITE a la SIP URI de LiveKit (configurada en el Paso 3).
3 LiveKit crea una sala y busca el worker con agent_name='gemini-sip-agent'.
4 Modal.com recibe el job con el metadata que incluye el agent_id.
5 El worker ejecuta ctx.connect() y entra en la sala de LiveKit.
6 Carga la configuración del agente (system_prompt, voz, API key) desde Supabase.
7 Abre la conexión WebSocket con la API de Gemini Live.
8 El audio fluye en tiempo real: SIP → LiveKit → WebSocket → Gemini.
9 Gemini procesa y devuelve voz: Gemini → WebSocket → LiveKit → SIP → teléfono del llamante.
10 Al colgar: el worker guarda transcript, duración, número y resumen en Supabase.
Casos de uso con infraestructura netelip
Agente de cualificación de leads fuera de horario

El agente atiende llamadas fuera de horario que antes iban a buzón de voz o se perdían. Recoge nombre, empresa, motivo de contacto y disponibilidad horaria, y guarda el lead cualificado en el CRM. Número recomendado: geográfico (91, 93…) vinculado al número habitual. Sin cambios visibles para el llamante.

Línea 900 con filtrado automático de consultas

Un número 900 (gratuito para el llamante) conectado al agente. Resuelve consultas frecuentes de forma autónoma y escala las complejas a un agente humano mediante transferencia. El equipo humano solo recibe las que superan la capacidad del agente.

Expansión a Latinoamérica sin oficina local

Una empresa española activa un número virtual de México, Chile o Colombia en netelip. El agente atiende en el idioma y tono adecuado para ese mercado con un system_prompt específico por país. Todo corre desde la misma infraestructura. El llamante ve un número local.

Agente de soporte técnico de primer nivel

Agente configurado con la documentación técnica del producto como system_prompt. Resuelve incidencias comunes, guía al usuario paso a paso y escala solo las que superan su capacidad. Cada llamada queda transcrita en Supabase para análisis posterior.

Integración con Centralita Virtual de netelip

Los clientes que ya tienen Centralita Virtual en netelip pueden integrar el agente Gemini en un punto concreto del IVR. El agente atiende fuera de horario mientras que en horario laboral las llamadas van al equipo humano con el flujo habitual. No hay que reemplazar nada de lo que ya funciona.

Widget de llamada web como canal adicional

El mismo agente puede atender llamadas desde un widget web, compartiendo la misma configuración en Supabase: system_prompt, voz y API key.

  • Vía teléfono: el llamante marca el número de netelip y la llamada entra por SIP.
  • Vía web: el visitante pulsa el botón del widget y habla directamente desde el navegador.
Resolución de problemas frecuentes
Síntoma Causa probable y solución
La llamada llega pero nadie respondeEl worker no está activo. Verifica que min_containers=1 está configurado y el deploy está running en Modal.
El agente responde con retraso de 10-15 sEl worker arrancó en frío. Confirma que min_containers=1 está activo en run_worker.
La llamada no llega a LiveKitRevisa la configuración SIP en netelip. El destino debe ser: número E.164 @ SIP URI de LiveKit.
LiveKit no asigna agente a la llamadaEl agent_name en la Dispatch Rule no coincide con el del worker en Modal. Deben ser idénticos.
El agente no carga su configuraciónEl agent_id en el metadata de la Dispatch Rule no existe en la tabla agents de Supabase.
La llamada se corta a los 15 minutosLímite de sesión de Gemini Live. Implementa reconexión automática o avisa al llamante.
Dos llamadas simultáneas, una sin atenderSolo hay una instancia activa. Aumenta min_containers según el volumen esperado.
Las llamadas salientes no funcionanEsta arquitectura es para llamadas entrantes. Las salientes requieren un SIP Outbound Trunk en LiveKit.
¿Tienes dudas sobre la configuración de netelip?

Para preguntas sobre el SIP Trunk o los números virtuales, abre un ticket desde tu panel privado de cliente.

Para la configuración de LiveKit, Modal y Gemini, consulta la documentación oficial de cada plataforma.

Integración Gemini Live con los números virtuales de netelip

¿Te ha sido útil esta información?

Aprende desde nuestro canal

Te ayudaremos a conocer todo lo que necesitas sobre la telefonía IP y Cloud Computing. Te harás un experto con multitud de videos demostrativos de todas y cada una de nuestras soluciones.

¡Comienza a trabajar con nuestros video tutoriales!