El Proyecto

Este proyecto captura y transcribe en tiempo real un flujo de audio de una emisora de radio (RAC1) y muestra los fragmentos más relevantes en una interfaz web minimalista. Todo está automatizado con Docker.

También me sirvió para validar un pipeline simple de captura, transcripción y filtrado, y para ver qué partes conviene separar si el sistema necesita escalar.

Accede a la Demo

👉 Pruébalo: https://eurekatop.com/radioalert
👉 Endpoint SSE: https://eurekatop.com/radioalert/events

Descripción de la imagen

Backend: Transcripción Automática con Whisper

La base del proyecto es un script en Python que escucha el stream como si fuera un navegador. Al principio probé usar ffmpeg para capturar el stream, pero falló porque la emisora tiene protecciones antibot y no aceptó la conexión.

Como alternativa, descubrí que usando httpx.stream() se puede leer el flujo de audio sin problemas—siempre que la petición parezca provenir de un navegador real. Por eso hay que añadir algunos headers...

El script está dividido en dos partes: una para la captura del stream y otra para la transcripción y filtrado de palabras clave. Esta transcripción se realiza en paralelo con la captura, por lo que no es necesario esperar a que finalice para seguir capturando.

El audio se procesa en bloques de 4 segundos y se transcribe usando el modelo optimizado Whisper (int8).

model = WhisperModel("/models/whisper-small", compute_type="int8")
segments, _ = model.transcribe(BytesIO(audio_data), language="ca")

Una vez transcrito, se busca si aparecen palabras clave como “barça”, “avui” o “lamine yamal”. Si se detectan, se genera una alerta y se escribe todo en un archivo .log. Por ejemplo:

🕒 [2025-06-09 14:10:23] 🗣️ [12] avui a catalunya hem vist que...
🚨 🕒 [2025-06-09 14:10:23] ALERTA: Palabra clave detectada: avui

El sistema añade una pequeña cola de audio anterior para evitar cortes entre frases, ya que el modelo necesita contexto para entender bien las primeras palabras del stream.

Todo está automatizado con Docker.

Frontend: Visualización en Directo

Un pequeño servidor en Node.js muestra las líneas transcritas en directo desde un archivo .log, enviándolas vía Server-Sent Events a la interfaz web de estilo “terminal”.

fs.readFile(FILE_PATH, 'utf8', (err, data) => {
  const lines = data.trim().split('\n').slice(-30)
  lines.forEach(line => res.write(`data: ${line}\n\n`))
})

En el cliente, la conexión permanece abierta con EventSource() del navegador, que recibe automáticamente las actualizaciones en tiempo real:

const eventSource = new EventSource('/events')
eventSource.onmessage = function(event) {
  console.log(event.data)
}

💡 Aprendizajes

  • Whisper es bastante fiable, incluso en catalán.
  • Añadir una cola de audio anterior mejora la precisión en frases cortadas.
  • Con httpx.stream e hilos ligeros se puede capturar audio de forma estable sin saturar el proceso principal. ffmpeg fue descartado para evitar las protecciones antibot, simulando una conexión de navegador real.
  • Server-Sent Events es una herramienta muy simple pero efectiva para enviar datos en vivo a una web.

Stack y Técnicas

  • 🐍 Python + faster-whisper
  • 📡 httpx para capturar streams de audio
  • 🎛️ Transcripción en catalán con el modelo Whisper-small optimizado
  • 🐳 Docker para encapsular el servicio
  • 🟩 Node.js + Express para exponer el archivo como feed SSE
  • 🎨 HTML + CSS en modo consola de terminal

Un experimento en vibe coding por Francesc López Marió, 2025