← Todas las recetasReceta · 15 de septiembre de 2025

Dale voz (y oídos) a tu IA: pipeline de voz completo en local

Habla con tu IA por voz: Whisper para escuchar, un LLM local para responder y Kokoro para sintetizar. Un prototipo controlable, sin API obligatoria.

Portada de la receta: Dale voz (y oídos) a tu IA: pipeline de voz completo en local
Dificultadavanzada
Tiempo1-2 horas
IngredientesWhisper · Ollama · Kokoro TTS · Python

Un proyecto estupendo para entender un sistema multimodal pequeño: Whisper escucha, un LLM local responde y Kokoro sintetiza. Si todos los componentes y temporales están en tu máquina, puedes mantener el audio dentro de tu perímetro.

La arquitectura (simple de verdad)

🎙️ Micrófono → [Whisper STT] → texto
                                    ↓
                              [Tu LLM local] → respuesta texto
                                                      ↓
                                    🔊 [TTS] → voz sintética

Son 3 piezas independientes unidas por texto. Cada una la puedes mejorar por separado.

Ingredientes

  • Ollama + un modelo local
  • pip install faster-whisper sounddevice soundfile "kokoro>=0.9.4"
  • En Linux, el backend de idiomas de Kokoro puede necesitar espeak-ng.
  • Micrófono y altavoces :)

Pasos

  1. Captura de audio en tiempo real:

    import sounddevice as sd
    import soundfile as sf
    import numpy as np
    
    SAMPLE_RATE = 16000
    grabacion = []
    
    def callback(indata, frames, time, status):
        grabacion.append(indata.copy())
    
    # grabar mientras se mantenga pulsada una tecla o detecte voz (VAD)
    with sd.InputStream(samplerate=SAMPLE_RATE, channels=1, callback=callback):
        input("Pulsa ENTER para dejar de grabar...")
    audio = np.concatenate(grabacion)
    sf.write("consulta.wav", audio, SAMPLE_RATE)
  2. Whisper transcribe (con language="es"):

    from faster_whisper import WhisperModel
    stt = WhisperModel("small", device="cpu", compute_type="int8")
    segments, _ = stt.transcribe("consulta.wav", language="es")
    pregunta = " ".join(s.text for s in segments)
  3. Tu LLM responde:

    import ollama
    respuesta = ollama.chat(model="qwen2.5:7b", messages=[
        {"role": "system", "content": "Eres un asistente de voz. Responde en 2-3 frases, natural."},
        {"role": "user", "content": pregunta},
    ])["message"]["content"]

    (El system prompt de “responde corto” suele ser importante en voz: nadie quiere escuchar un ensayo.)

  4. Kokoro habla. La API actual devuelve fragmentos; en español usa el código e y una voz cuyo prefijo también sea e:

    from kokoro import KPipeline
    import numpy as np
    
    tts = KPipeline(lang_code="e")  # español
    for _, _, audio in tts(respuesta, voice="ef_dora"):
        sd.play(audio.cpu().numpy() if hasattr(audio, "cpu") else np.asarray(audio),
                samplerate=24000)
        sd.wait()

Resultado esperado

La latencia total no está garantizada: depende de la captura, el modelo de Whisper, el LLM, la síntesis y si hay streaming. Mide por separado cada tramo antes de prometer una conversación natural.

Trucos de la experiencia

  • Latencia es todo: usa modelos SLM (3-7B) para voz. Nadie espera respuestas de genio hablando; espera fluidez.
  • VAD (Voice Activity Detection): usa webrtcvad o silero-vad para que empiece a escuchar solo cuando hablas. Es la diferencia entre “cutre” y “casi Alexa”.
  • Streaming: haz que el TTS empiece a hablar en cuanto llegue la primera frase del LLM, no al final. La latencia percibida cae a la mitad.
  • Palabra de activación: en modo kiosko, openwakeword te da un “Oye, En Local” casero.

A dónde llevarlo

La evolución natural es conectar acciones con permisos mínimos. Empieza con respuestas informativas y logs; solo después añade cosas como anotar una lista. Nunca des a un modelo de voz acceso directo a acciones irreversibles.