Dictado por voz en tu Mac

¿Lo estás viendo en el celular? El prompt se pega en el Mac: abre sencomar.cl/dictado allá. Si tu iPhone y tu Mac usan la misma cuenta de Apple, también puedes copiarlo aquí y pegarlo directo en el Mac.

Qué necesitas

Cómo armarla

  1. Copia el prompt con el botón.
  2. Pégalo en Claude Code y deja que trabaje. Te va a explicar cada paso.
  3. Al final, activa los tres permisos que te pide (Micrófono, Monitorización de entrada y Accesibilidad) y vuelve a abrir la app.

El prompt

Cópialo entero
Quiero que me construyas una app de dictado por voz para mi Mac con chip Apple (M1 o superior). Aprieto Option+Espacio, hablo, aprieto Option+Espacio otra vez y el texto aparece donde esté el cursor, en cualquier app. Todo local: el audio nunca sale del Mac, sin cuentas ni suscripción. Explícame cada paso en simple y avísame cuando tenga que dar un permiso.

MOTOR
- Python 3.12 en un entorno virtual dentro de ~/dictado (si no tengo Python, instálalo con uv).
- Whisper large-v3-turbo a 4 bits con mlx-whisper (mlx-community/whisper-large-v3-turbo-q4), en español y con condition_on_previous_text=False. Pásale el audio como arreglo de numpy, así no hace falta ffmpeg.
- Al abrir, carga el modelo transcribiendo medio segundo de silencio para que el primer dictado sea rápido.
- Graba con sounddevice a 16 kHz mono. Descarta audios de menos de 0,4 s o sin voz (RMS bajo 0,004).

ATAJO
- Option+Espacio global con un event tap de Quartz (pynput). Trágate la combinación para que no escriba un espacio duro.
- Esc cancela mientras grabo.
- Sonidos del sistema: Tink al empezar, Pop al terminar, Basso si no hubo nada.

PEGAR EL TEXTO
- Copia el texto al portapapeles, simula Cmd+V y restaura el portapapeles anterior 0,6 s después.

BARRITA FLOTANTE
- Una pastilla oscura abajo al centro con la onda del micrófono en vivo, una onda animada mientras transcribe y una X para cancelar.
- Tiene que ser un NSPanel no activable (orderFrontRegardless), visible en todos los escritorios y en pantalla completa: si roba el foco, el Cmd+V cae en ella y no donde escribía. Se oculta justo antes de pegar.

BARRA DE MENÚ
- Ícono arriba en la barra (sin ícono en el Dock) con: estado, Dictar/detener, Editar palabras y Salir.

PALABRAS QUE ESCUCHA MAL
- Archivo palabras.txt con líneas tipo "Claude Code = clod code | cloud code". Las palabras correctas se le pasan a Whisper como initial_prompt y las equivocadas se reemplazan después (sin importar mayúsculas, comas ni espacios de más; las más largas primero). Se relee solo cuando lo guardo.
- Correos dictados: "juan arroba gmail punto com" queda [email protected], siempre en minúsculas.

ARREGLOS QUE YA SABEMOS QUE HACEN FALTA
1. Antes de cada grabación reinicia PortAudio (sd._terminate() y sd._initialize()): guarda la lista de micrófonos del arranque y falla al cambiar de audífonos o de lugar. Si el micrófono no abre, avisa y la app sigue viva.
2. macOS apaga el event tap al bloquear la pantalla y pynput no lo vuelve a encender: reactívalo al recibir kCGEventTapDisabledByTimeout o kCGEventTapDisabledByUserInput, y con un vigía que lo revise cada 3 s.
3. Ningún error en un dictado puede matar la app. Todo queda en ~/Library/Logs/Dictado.log, con lo que escribió Whisper y lo que quedó después de corregir.
4. Al abrir, pide Accesibilidad con AXIsProcessTrustedWithOptions para que macOS muestre el aviso.

EMPAQUETADO
- Arma Dictado.app en ~/Applications con LSUIElement y NSMicrophoneUsageDescription.
- El ejecutable tiene que ser un binario chico en C que lance el Python como proceso hijo: así los permisos quedan a nombre de la app y no de Python ni de Terminal.
- Firma ad-hoc con un identificador fijo. El script de empaquetado solo recompila y refirma si cambió el lanzador, el ícono o el Info.plist, porque cada firma nueva invalida el permiso de Accesibilidad.
- Agrégala a los ítems de inicio para que arranque sola.

AL TERMINAR
- Dime qué activar en Ajustes del Sistema > Privacidad y seguridad (Micrófono, Monitorización de entrada y Accesibilidad) y que después reabra la app.
- Avísame que si el atajo deja de responder tras refirmar, hay que quitar la app de Accesibilidad con el botón menos y volver a agregarla: apagar y encender el interruptor no basta.
- Pruébala conmigo antes de darla por terminada.

¿Quieres armar más cosas así?

En la comunidad de Sencomar aprendes a construir con IA paso a paso: webs, sistemas, asistentes y herramientas como esta.

Conocer la comunidad