Técnico

Voz a texto en streaming en tu CPU: integrar NVIDIA Nemotron en una aplicación de escritorio

Cómo muestra OpenWhispr texto en directo mientras hablas —un modelo en streaming con caché mediante un WebSocket local, sin GPU ni nube— y la ingeniería necesaria para hacerlo fiable.

OpenWhispr

OpenWhispr

Ingeniería

18 de julio de 2026
Tabla de contenidos

La voz a texto en streaming transcribe el audio mientras sigues hablando, sin esperar a que termine la grabación. Desde la versión 1.7.6, OpenWhispr lo hace íntegramente en el dispositivo: los modelos en streaming Nemotron de NVIDIA (600M parámetros, cuantizados a INT8) se ejecutan en tu CPU mediante un servidor WebSocket local de sherpa-onnx; la vista previa del dictado se actualiza al llegar resultados parciales y, en cuanto te detienes, el texto del flujo se guarda como transcripción. Sin GPU, sin entorno Python y sin que el audio salga de tu equipo.

Este artículo explica la ingeniería: por qué la antigua vista previa se percibía lenta, qué significa realmente el streaming con caché, cómo encaja la canalización en una aplicación Electron, el error de fijación de versión que decodificaba todo mal y cómo pasamos de volver a decodificar cada grabación a guardar el propio flujo. Si buscas la comparación entre modelos, está en Parakeet vs Whisper vs Nemotron.

Última actualización: 18 de julio de 2026. Los detalles de implementación corresponden a la función de transcripción en streaming publicada en OpenWhispr 1.7.6; todo lo descrito puede revisarse en el repositorio de código abierto.

Resumen de verificación (fuentes primarias)

El problema: una vista previa en directo construida sobre un modelo por lotes

OpenWhispr siempre ha ofrecido una vista previa de la transcripción: una pequeña ventana que muestra lo que el modelo oye mientras dictas. Antes de 1.7.6 funcionaba de la única manera posible para hacer que un modelo por lotes pareciera inmediato: acumular unos 1.5 segundos de audio del micrófono, transcribir por completo ese fragmento, añadir el texto y repetir.

El enfoque tiene tres problemas estructurales. Primero, la latencia: las palabras no pueden aparecer antes de llenarse el búfer, así que la vista previa lleva un retraso de segundo y medio más el tiempo de inferencia. Segundo, los límites: una palabra repartida entre dos fragmentos queda cortada y ninguno puede repararla porque se transcriben por separado. Tercero, el contexto: el quinto fragmento no sabe qué dijiste en el cuarto, por lo que el modelo vuelve a resolver la misma ambigüedad cada 1.5 segundos.

Puedes acortar los fragmentos para ganar velocidad, pero la precisión cae: hay menos contexto y más límites. Puedes solaparlos para corregir los cortes, pero entonces transcribes dos veces el mismo audio. Lo necesario es un modelo entrenado para transcribir un flujo. Eso es Nemotron.

Qué significa realmente el streaming con caché

Un modelo en streaming con caché conserva su estado interno entre fragmentos. Cuando llega la siguiente porción de audio, el codificador no vuelve a leer todo lo anterior: procesa solo los fotogramas nuevos y consulta una caché del contexto ya calculado. Es el mismo recurso que acelera los chatbots (caché KV), aplicado a un codificador de voz.

El diseño tiene dos consecuencias. El cómputo deja de crecer con la duración de la grabación: cada fragmento cuesta lo mismo a los diez segundos que a los diez minutos, lo que permite streaming solo con CPU. Además, el contexto se conserva: el modelo usa todo lo dicho para resolver ambigüedades y revisa palabras anteriores cuando el audio posterior aporta más información. Por eso el texto se «asienta» un instante después de hablar; no es un fallo, sino una corrección basada en mejores pruebas.

El margen de latencia se puede ajustar: Nemotron ofrece fragmentos desde 80ms (más rápido, menos contexto por paso) hasta 1.12s (máxima precisión: 6.93% WER medio en los conjuntos del leaderboard, aproximadamente a un punto de los mejores modelos por lotes). El entrenamiento usa el FastConformer con caché de NVIDIA y un decodificador transductor; su artículo técnico explica la teoría en profundidad.

La arquitectura dentro de OpenWhispr

La ruta de transmisión en directo en OpenWhispr

Microphone16kHz PCM via AudioWorklet
Local WebSocket127.0.0.1, float32 frames
Nemotron 0.6Bsherpa-onnx, INT8, CPU
Partial resultsJSON per chunk
Live previewText replaced in place
  • One persistent stream for the whole recording — the encoder cache carries context across chunks.
  • Everything is on-device: the WebSocket server is a local sherpa-onnx binary, not a cloud endpoint.
  • A clean flush at stop commits the streamed text as the final transcript; anything less falls back to a full re-decode.

La canalización es deliberadamente sencilla. Un AudioWorklet captura el PCM del micrófono a 16kHz. Los fotogramas se convierten al formato float32 y viajan por WebSocket hasta un servidor online de sherpa-onnx: un binario nativo que OpenWhispr inicia localmente y contacta en 127.0.0.1, con una conexión persistente por grabación. El servidor ejecuta Nemotron con pesos INT8 y devuelve resultados parciales JSON; la vista previa sustituye su texto en vez de añadirlo.

¿Por qué un servidor aparte y no inferencia dentro del proceso? Por aislamiento. Los runtimes nativos pueden fallar; una asignación errónea en un kernel ONNX no debería cerrar toda la aplicación. Con un proceso auxiliar, un fallo exige reconectar, no perder el dictado. Además, el código nativo queda fuera del proceso principal de Electron: la aplicación habla el protocolo y el auxiliar hace los cálculos.

El mismo patrón ejecuta nuestra diarización local de hablantes — una cadena de herramientas sherpa-onnx, varias tareas y todo en el dispositivo.

Lo que falló por el camino

La versión del runtime importó más de lo previsto. Los modelos Nemotron necesitan sherpa-onnx 1.13.4 o posterior para decodificar con precisión. Con el runtime antiguo incluido para Parakeet no daban un error claro: transcribían mal. La solución fue rutinaria —actualizar y volver a fijar los binarios de cada plataforma—, pero la lección sirve siempre: en runtimes de modelos, «se ejecuta» y «es correcto» son pruebas distintas, y solo cuenta la segunda.

Los flujos fallan, así que mantuvimos la ruta anterior. Un puerto puede estar ocupado, puede faltar el archivo del modelo o el servidor puede caer durante una grabación. Si el flujo persistente no arranca, la vista previa vuelve automáticamente a los fragmentos con búfer: más lenta, pero nunca vacía. Los modelos offline (Parakeet, Whisper) conservan esa vista previa por diseño; cada modelo del registro declara su runtime como online u offline y la aplicación elige la ruta adecuada.

Los resultados parciales exigían otra forma de renderizar. La ruta por fragmentos añade texto; una hipótesis en streaming se revisa, así que la interfaz sustituye toda la vista previa con cada parcial. Si añades una hipótesis que cambia, obtienes duplicados entrecortados: la versión en una línea de un fallo real de UX que corregimos pronto.

Guardar el flujo: de dos pasadas a una

La primera versión trataba el streaming como vista previa, no como resultado: al terminar el dictado, la aplicación volvía a decodificar desde cero toda la grabación y pegaba ese texto. Era seguro —la pasada final tenía todo el contexto—, pero cada dictado pagaba dos decodificaciones y, después de ver cómo el texto se asentaba en pantalla, había que esperar una segunda opinión que casi siempre coincidía.

En esa misma versión convertimos el flujo en la fuente de verdad. El dictado usa la conexión persistente aunque la ventana de vista previa esté cerrada y, al detenerse, la aplicación vacía la cola del modelo y guarda directamente el texto del flujo, sin segunda decodificación. La latencia final se reduce a un vaciado de cola y el uso de CPU por dictado queda aproximadamente a la mitad.

La red de seguridad no desapareció: pasó a ser el fallback. El vaciado final detecta truncamientos y amplía su plazo mientras sigan llegando resultados. Si algo falla —una conexión perdida o un resultado cortado—, la aplicación descarta el flujo y ejecuta el método clásico de grabar y después transcribir el audio completo. La ruta rápida solo se usa cuando también es correcta.

Rendimiento y recursos

  • Modelos: Nemotron Speech Streaming EN 0.6B (632MB) y Nemotron 3.5 ASR Streaming 0.6B (650MB, 15 idiomas listos para transcripción y detección automática): ONNX INT8, una sola descarga y caché local.
  • Runtime: sherpa-onnx 1.13.4, un binario nativo autónomo. No requiere Python, PyTorch ni CUDA.
  • Hardware: streaming en tiempo real en la CPU de un portátil moderno; tanto Apple Silicon como los x86 recientes siguen el ritmo del habla sin problemas.
  • Sensación: el texto parcial aparece con bastante menos de un segundo de retraso; al terminar, un único vaciado de cola guarda la transcripción, sin segunda decodificación.

Nada de esta ruta toca Internet. La aplicación habla con el servidor mediante 127.0.0.1 (en Windows, una regla de firewall limitada cierra además el puerto a la red), los modelos viven en la caché local y el audio nunca sale del equipo: la misma protección de privacidad que el resto de nuestra pila de transcripción local.

Limitaciones, sin rodeos

  • El streaming cambia algo de precisión por inmediatez. ~6.9% en streaming frente al 5.91% del mejor modelo inglés por lotes de NVIDIA en los mismos benchmarks. Como la transcripción guardada procede ahora del flujo, ese es el intercambio que aceptas. Si solo importa el resultado final, un modelo Parakeet offline sigue siendo la opción más precisa.
  • La cobertura de idiomas es menor que la de Whisper. 15 idiomas listos para transcripción en el modelo multilingüe frente a los 99 de Whisper. Aún no hay streaming en mandarín ni tailandés.
  • El texto parcial cambia. La hipótesis se revisa cuando llega contexto. Para nosotros, ver cómo se estabiliza es una ventaja; si distrae, puedes desactivar la vista previa y el dictado funciona exactamente como antes.
  • Son otros 650MB en disco si ya tienes un modelo offline: el coste de un segundo motor ajustado para otra tarea.

Elegir un modelo en OpenWhispr

Lo que necesitasElige
Vista previa en directo en inglés mientras dictasNemotron Speech Streaming EN 0.6B
Vista previa en español, japonés, árabe, hindi…Nemotron 3.5 ASR Streaming 0.6B
Máxima precisión en inglés; el texto en directo no importaParakeet Unified EN 0.6B
Un idioma fuera del conjunto de NVIDIAWhisper (turbo o large)

Todos aparecen en un menú de Ajustes; el catálogo completo, con tamaños y compromisos, está en la página de modelos. OpenWhispr es gratuito, de código abierto y está disponible para macOS, Windows y Linux.

Preguntas frecuentes

¿Qué es la voz a texto en streaming?

La voz a texto en streaming (u «online») transcribe el audio mientras aún se está hablando y emite resultados parciales dentro de un margen de latencia fijo, normalmente entre 80 milisegundos y alrededor de un segundo. Los modelos por lotes («offline»), como Whisper, esperan a que termine la grabación y la procesan entera. El streaming hace posibles los subtítulos en directo, los agentes de voz y las vistas previas de dictado que muestran el texto mientras hablas.

¿Puedo ejecutar voz a texto en streaming de forma local y sin GPU?

Sí. Los modelos en streaming Nemotron de NVIDIA tienen 600M parámetros, se distribuyen como archivos ONNX cuantizados a INT8 de unos 650MB y funcionan en tiempo real en una CPU moderna mediante sherpa-onnx, un binario nativo sin Python ni PyTorch. OpenWhispr incluye esta configuración en macOS, Windows y Linux.

¿Qué es el ASR en streaming con caché?

Es una arquitectura —el FastConformer con caché de NVIDIA— en la que el modelo conserva el estado interno del codificador entre fragmentos de audio. Cada fragmento nuevo se procesa una sola vez usando el contexto ya almacenado, en vez de volver a codificar ventanas de audio solapadas. Así, el streaming de baja latencia resulta lo bastante ligero para una CPU de portátil.

¿Por qué cambia el texto de la vista previa después de aparecer?

Los modelos en streaming revisan su hipótesis a medida que llega más audio: el contexto posterior puede resolver el límite de una palabra o un homófono, por lo que los resultados parciales se sustituyen en el mismo sitio. Es intencionado. Al detenerte, OpenWhispr vacía la cola del modelo y guarda como transcripción el texto ya estabilizado; si ese vaciado se interrumpe o queda truncado, vuelve a decodificar automáticamente la grabación completa. Un flujo inestable nunca acaba siendo el texto que pegas.

¿La transcripción en streaming es menos precisa que la transcripción por lotes?

Un poco, por una razón clara: un modelo en streaming no puede oír el audio futuro. El modelo inglés en streaming de Nemotron obtiene de media un 6.93% de tasa de error por palabra con fragmentos de 1.12 segundos en los conjuntos del Open ASR Leaderboard. Está muy cerca de los modelos por lotes, pero por detrás del 5.91% del mejor modelo inglés por lotes de NVIDIA. Elegir streaming implica aceptar esa pequeña diferencia a cambio de texto en directo y una transcripción instantánea al terminar; si prima la máxima precisión, elige un modelo Parakeet offline.

¿Qué idiomas admite el streaming en OpenWhispr?

Hay dos modelos Nemotron: uno solo para inglés y Nemotron 3.5 con 15 idiomas listos para transcripción (inglés, español, francés, italiano, portugués, neerlandés, alemán, turco, ruso, árabe, hindi, japonés, coreano, vietnamita y ucraniano) y detección automática del idioma. Los modelos offline como Parakeet y Whisper cubren más idiomas, pero su vista previa usa fragmentos almacenados en búfer en lugar de un flujo en directo.