18 agosto 2026 · Euskolabs
En euskolabs tenemos Charly, un asistente de voz híbrido que opera 24/7 en Telegram, web y API. Esta es la guía técnica de cómo lo construimos usando Faster-Whisper para reconocimiento de voz y Kokoro TTS para síntesis, con fallback offline local.
Audio entrada → Whisper (STT) → LLM (razonamiento) → Kokoro (TTS) → Audio salida
↓
Ollama (fallback local)
↓
Gemini (cloud)
El flujo es simple: el usuario habla, Whisper transcribe, el LLM genera la respuesta, Kokoro la sintetiza a voz. La latencia total de ida y vuelta es de 2-4 segundos en hardware estándar.
Faster-Whisper es una reimplementación optimizada de Whisper usando CTranslate2. Es 4x más rápida que el Whisper original con la misma precisión.
from faster_whisper import WhisperModel
model = WhisperModel("base", device="cpu", compute_type="int8")
def transcribe(audio_path):
segments, info = model.transcribe(audio_path, language="es")
text = " ".join([s.text for s in segments])
return text.strip()
Usamos el modelo base en CPU porque ofrece el mejor balance velocidad/precisión. Para entornos con GPU, large-v3 da precisión casi perfecta.
Kokoro es un motor TTS de código abierto con calidad natural impresionante. Soporta múltiples voces e idiomas.
import kokoro
# Inicializar con voz por defecto
tts = kokoro.KokoroTTS(model_path="kokoro.pt", voice="em_alex")
def speak(text, output_path="/tmp/response.wav"):
tts.generate(text, output_path)
return output_path
La voz em_alex es la que usa Charly en producción — natural, clara, con buen ritmo. La generación de 10 segundos de audio toma menos de 2 segundos en CPU.
El cerebro del agente usa doble modo: Gemini en la nube para máxima capacidad y Ollama con LLaMA local para privacidad y funcionamiento offline.
import google.generativeai as genai
import ollama
def generate_response(prompt, context=""):
try:
# Cloud first — máxima capacidad
model = genai.GenerativeModel("gemini-pro")
response = model.generate_content(f"{context}\n\nUser: {prompt}")
return response.text
except Exception:
# Fallback local — privacidad y offline
response = ollama.chat(
model="llama3",
messages=[{"role": "user", "content": f"{context}\n\n{prompt}"}]
)
return response["message"]["content"]
El fallback es automático: si la API de Gemini falla (rate limit, red caída, etc.), el sistema usa Ollama local sin interrupción perceptible para el usuario.
El agente se conecta a procesos de negocio via n8n webhooks:
import httpx
async def execute_workflow(action, params):
webhook_url = f"http://n8n:5678/webhook/{action}"
async with httpx.AsyncClient() as client:
response = await client.post(webhook_url, json=params)
return response.json()
Esto permite al agente ejecutar acciones reales: crear facturas, enviar emails, actualizar CRM, etc.
Charly corre en un VPS con Docker. Los modelos de Whisper y Kokoro se cargan en memoria al arrancar. Ollama corre como servicio separado. La latencia total:
| Fase | Tiempo |
|---|---|
| Whisper (transcripción) | ~0.5s |
| LLM (generación respuesta) | ~1-2s |
| Kokoro (síntesis voz) | ~1-2s |
| Total ida y vuelta | ~2-4s |
¿Quieres tu propio AI Agent con voz? Solicita un diagnóstico en euskolabs.com.