Aplicación nativa para la barra de menú de macOS que convierte tu voz en texto al instante y lo pega automáticamente donde estés escribiendo. Incluye corrección inteligente de puntuación, detección de preguntas, y workflows LLM opcionales. Todo ocurre en tu máquina — sin servidores, sin internet, sin costos.
Mantenés presionada la tecla Opción derecha (⌥), hablás, la soltás — y el texto aparece donde tengas el cursor. En cualquier app: Notion, Slack, VS Code, un formulario web, lo que sea.
Imaginá que hay un asistente dentro de tu computadora que:
- Escucha tu voz mientras sostenés la tecla — como un walkie-talkie
- Convierte lo que dijiste en texto usando inteligencia artificial que corre localmente
- Copia ese texto al portapapeles automáticamente
- Lo pega en la app que tenías abierta, como si lo hubieras escrito a mano
Todo esto pasa en menos de un segundo, y jamás sale de tu computadora. No hay grabaciones enviadas a ningún lado.
┌─────────────────────────────────────────────────────────────────────┐
│ TU COMPUTADORA │
│ │
│ [Micrófono] │
│ │ │
│ ▼ audio crudo (16.000 muestras/segundo) │
│ ┌───────────────┐ │
│ │ Audio Engine │ captura y convierte señal analógica → digital │
│ └───────┬───────┘ │
│ │ PCM float32 │
│ ├──────────────────────────────────────────────────────┐ │
│ │ │ │
│ ▼ ▼ │
│ ┌───────────────┐ ┌─────────────┐ │
│ │ Reconocedor │ (Swift) SFSpeechRecognizer │ Visualizador│ │
│ │ de voz │ (Python) faster-whisper base (default)│ de ondas │ │
│ └───────┬───────┘ └─────────────┘ │
│ │ texto transcripto │
│ ▼ │
│ ┌───────────────┐ │
│ │ Portapapeles │ NSPasteboard / pyperclip │
│ └───────┬───────┘ │
│ │ Cmd+V simulado │
│ ▼ │
│ ┌───────────────┐ │
│ │ Tu app │ Notion, Slack, VS Code, browser… │
│ └───────────────┘ │
└─────────────────────────────────────────────────────────────────────┘
El audio nunca sale de este diagrama. No hay paso 5 que diga "enviar a la nube".
Decí el signo en voz alta y WisperBar lo convierte al símbolo. Funciona mezclando ES / EN / DE en el mismo dictado.
| Lo que decís | Lo que aparece |
|---|---|
| "coma" / "Komma" / "comma" | , |
| "punto" / "Punkt" / "period" / "full stop" | . |
| "signo de interrogación" / "Fragezeichen" / "question mark" | ? |
| "signo de exclamación" / "Ausrufezeichen" / "exclamation mark" | ! |
| "abrir paréntesis" / "Klammer auf" / "open parenthesis" | ( |
| "cerrar paréntesis" / "Klammer zu" / "close parenthesis" | ) |
| "párrafo" / "Absatz" / "new paragraph" | salto de párrafo |
El módulo NLP analiza cada oración transcripta y aplica puntuación de pregunta automáticamente, sin que lo pidás:
- Palabras interrogativas — "qué", "cómo", "por qué", "how", "what", "warum", etc. → agrega
? - Inversión verbo-sujeto — "¿Tenés tiempo?" detectado aunque no se haya dicho el signo
- Apertura española — agrega
¿al inicio automáticamente en español - Mayúsculas — capitaliza el inicio de cada oración nueva y cada párrafo
Seleccionable desde el menú o el panel de configuración. Cada workflow transforma el texto transcripto con un prompt especializado:
| Workflow | Descripción |
|---|---|
| 🎙 Transcribir | Transcripción directa con puntuación corregida |
| ✏️ Mejorar | Mejora redacción manteniendo el sentido |
| 👔 Profesional | Reformula en tono formal |
| 🧘 Desahogo | Transcribe sin filtros, ideal para notas privadas |
| 😊 Emoji | Agrega emojis contextuales al texto |
Los workflows requieren un LLM configurado (ver sección de proveedores).
WisperBar puede opcionalmente enviar el texto transcripto a un LLM para procesarlo. Las API keys se guardan en el Keychain de macOS, nunca en archivos de configuración.
| Proveedor | Descripción |
|---|---|
| Ollama | LLM 100% local. Cero datos salen de tu máquina. Recomendado. |
| Anthropic | Claude (Opus, Sonnet, Haiku) vía API |
| OpenAI | GPT-4o, o1, o3, o4-mini y otros vía API |
| Generic | Cualquier endpoint compatible con la API de OpenAI |
Sin LLM configurado, WisperBar transcribe directamente sin procesar el texto.
El modelo Whisper recibe un vocabulario de términos técnicos como guía de contexto (APIs, frameworks, términos de negocio) para mejorar la precisión en dictados técnicos en ES, EN y DE.
| Tecnología | Qué hace en este proyecto |
|---|---|
| Swift 5.9 | Lenguaje nativo de Apple. La versión principal de la app está escrita aquí |
| SwiftUI + AppKit | Construye la interfaz: ícono en la barra, overlay animado, menú |
| SFSpeechRecognizer | API de Apple para reconocimiento de voz on-device (sin internet) |
| AVAudioEngine | Captura audio del micrófono en tiempo real |
| CGEvent | Simula la pulsación Cmd+V para pegar en cualquier app |
| SMAppService | Registra la app para que inicie automáticamente con el sistema |
| Tecnología | Qué hace en este proyecto |
|---|---|
| Python 3.10+ | Lenguaje de scripting; orquesta el flujo completo |
| faster-whisper | Motor por defecto (CTranslate2). El modelo base en int8 transcribe en ~0.2s sobre Apple Silicon — dictado casi instantáneo, multiidioma |
| MLX Whisper | Motor alternativo. Modelos Whisper de OpenAI (tiny → large-v3) corriendo en Apple Silicon con el framework MLX; más precisos en audio difícil, algo más lentos |
| MLX | Framework de Apple para Machine Learning en chips M1/M2/M3/M4. Usa la GPU/Neural Engine del chip sin necesidad de CUDA ni GPU externa |
| sounddevice | Captura audio del micrófono vía PortAudio |
| NumPy | Procesa las muestras de audio (arrays float32, cálculo de RMS) |
| rumps | Crea la app de barra de menú en Python (wraps NSStatusItem) |
| pynput | Escucha teclas globales (la Opción derecha) aunque otra app esté en foco |
| pyperclip | Copia texto al portapapeles (wraps NSPasteboard) |
| PyObjC | Puente Python ↔ Objective-C; necesario para crear el overlay NSPanel sin Xcode |
| macOS Keychain | Almacena API keys de LLMs de forma segura vía security CLI |
| Módulo | Qué hace |
|---|---|
punctuation.py |
Reemplaza comandos hablados por símbolos de puntuación (ES/EN/DE) |
sentence_parser.py |
Detecta preguntas y corrige apertura/cierre en ES/EN/DE |
workflows.py |
Define los prompts de cada workflow LLM multiidioma |
llm_service.py |
Cliente unificado para Ollama, Anthropic, OpenAI y endpoints genéricos |
vocab.py |
Vocabulario técnico para guiar el reconocimiento de Whisper |
config_panel.py |
Panel de configuración nativo (PyObjC): proveedor LLM, modelo, idioma, hotkey mode |
i18n.py |
Internacionalización de la UI en ES / EN / DE |
autostart.py |
Registra y gestiona el LaunchAgent de macOS |
Python 3.13 eliminó el acceso a variables de bloque except ... as exc desde closures internos. WisperBar captura el mensaje de error como string antes de que Python borre la variable, garantizando que el estado de la app se resetee correctamente ante cualquier falla de audio. Además, el motor de grabación reintenta abrir el stream de micrófono con un breve delay cuando PortAudio devuelve el error -10851 (kAudioUnitErr_InvalidPropertyValue), que ocurre cuando otra app acaba de liberar el micrófono.
Whisper es un modelo de inteligencia artificial creado por OpenAI que escucha audio y lo convierte en texto. Normalmente requiere una computadora muy potente o conexión a internet. WisperBar lo corre entero en tu Mac, sin internet ni hardware especial.
WisperBar soporta dos motores, intercambiables desde el panel de configuración:
- faster-whisper
base(por defecto) — motor CTranslate2 optimizado. Transcribe en ~0.2s sobre Apple Silicon: el texto aparece casi instantáneo al soltar la tecla. Ideal para dictado ágil del día a día. - MLX Whisper (
tiny→large-v3) — corre sobre el Neural Engine del chip vía el framework MLX de Apple. Más preciso en audio ruidoso o términos raros, a cambio de algo más de latencia.
En ambos casos, al iniciar la app ejecuta un warmup silencioso — transcribe un segundo de silencio — para que el modelo quede cargado y el primer dictado real no tenga delay.
Este repositorio contiene dos implementaciones independientes:
| Swift nativa | Python + Whisper | |
|---|---|---|
| Ubicación | WisperBar/ |
wisperbar_py/ |
| Motor de voz | SFSpeechRecognizer (Apple) | faster-whisper base (default) o MLX Whisper |
| Idiomas | Español (es-ES) |
Auto-detect + ES / EN / DE |
| Primer arranque | Instantáneo | Descarga el modelo (~75 MB base, solo la primera vez) |
| Precisión | Alta para español | Muy alta, multiidioma |
| NLP / puntuación | No | Sí — comandos hablados + detección de preguntas |
| Workflows LLM | No | Sí — Ollama / Anthropic / OpenAI / genérico |
| Cómo correr | Xcode o make run |
./deploy.sh |
- macOS 13.0+ (Ventura o posterior)
- Apple Silicon (M1 / M2 / M3 / M4)
- Para la versión Swift: Xcode 15+
- Para la versión Python: Python 3.10+ (
brew install python)
| Acción | Tecla / Control |
|---|---|
| Iniciar dictado | Mantener Opción derecha (⌥) |
| Detener y pegar | Soltar Opción derecha (⌥) |
| Menú de opciones | Click en el ícono de la barra de menú |
| Configuración | Primer ítem del menú desplegable |
Al soltar la tecla, el texto transcripto se procesa (NLP + workflow LLM si está configurado), se copia al portapapeles y se pega automáticamente en el campo activo.
Durante el dictado, el overlay de ondas muestra un badge de idioma a la izquierda: la bandera y el código del idioma configurado (🇪🇸 ES, 🇺🇸 EN, 🇩🇪 DE). En modo auto-detect muestra 🌐 mientras grabás, y al terminar el flash verde de confirmación revela la bandera del idioma que Whisper detectó.
Accesible desde el menú. Permite configurar:
- Proveedor LLM — Ollama (local), Anthropic, OpenAI, o endpoint genérico
- Modelo — selección dinámica según el proveedor
- API Key — guardada en Keychain, nunca en disco
- Workflow activo — el que se aplica a cada transcripción
- Idioma de la UI — Español / English / Deutsch
- Modo hotkey — hold (mantener) o toggle (presionar una vez)
# 1. Clonar el repositorio
git clone https://github.com/albecabrera/WisperBar.git
cd WisperBar
# 2. Generar el proyecto Xcode y compilar
make runO abrí WisperBar.xcodeproj en Xcode y presioná ⌘R.
La app se firma ad-hoc en modo Debug. Los permisos del sistema (micrófono, voz, accesibilidad) se piden en el primer arranque.
El script deploy.sh crea un entorno virtual Python aislado, instala las dependencias y lanza la app:
./deploy.shEl script hace:
- Verifica que Python 3.10+ y Homebrew estén disponibles
- Crea un entorno virtual en
wisperbar_py/.venv - Instala todas las dependencias del
requirements.txt - Lanza WisperBar desde el entorno aislado
La primera vez descarga el modelo por defecto faster-whisper base (~75 MB). Las siguientes veces arranca directamente.
La versión Python se registra como LaunchAgent de macOS la primera vez que arranca. Esto significa que se inicia automáticamente con cada encendido o reinicio sin ninguna acción adicional.
Cómo funciona:
El módulo autostart.py genera y carga un plist en ~/Library/LaunchAgents/com.wisperbar.app.plist con estas propiedades:
| Propiedad | Valor | Efecto |
|---|---|---|
RunAtLoad |
true |
Arranca al hacer login |
KeepAlive.SuccessfulExit |
false |
Se reinicia ante cualquier salida no exitosa (crash, excepción Python, kill) |
ProcessType |
Interactive |
Acceso a micrófono y pantalla |
| Logs | /tmp/wisperbar.log / /tmp/wisperbar.err |
stdout y stderr persistidos |
Comandos de gestión manual:
# Ver si está corriendo (primera columna = PID, - = detenido)
launchctl list | grep wisperbar
# Iniciar ahora (sin reiniciar)
launchctl kickstart gui/$(id -u)/com.wisperbar.app
# Detener
launchctl kill TERM gui/$(id -u)/com.wisperbar.app
# Deshabilitar inicio automático
launchctl bootout gui/$(id -u) ~/Library/LaunchAgents/com.wisperbar.app.plist
# Ver logs en tiempo real
tail -f /tmp/wisperbar.log /tmp/wisperbar.errNota: Si
brew upgradeactualiza Python, el plist queda apuntando al ejecutable viejo. En ese caso, borrá~/Library/LaunchAgents/com.wisperbar.app.plisty reiniciá la app manualmente — se auto-registra con la nueva ruta.
En el primer arranque macOS pide:
| Permiso | Para qué |
|---|---|
| Micrófono | Capturar el audio mientras hablás |
| Reconocimiento de voz | Transcribir con SFSpeechRecognizer (solo versión Swift) |
| Accesibilidad | Monitor global de teclado (Opción derecha) y Cmd+V automático |
Concedelos en Configuración del Sistema → Privacidad y seguridad.
WisperBar/
├── App/
│ ├── WisperBarApp.swift — punto de entrada SwiftUI
│ └── AppDelegate.swift — barra de menú, overlay, hotkey, menú contextual
├── Managers/
│ ├── HotKeyManager.swift — monitor global NSEvent para Opción derecha
│ └── WaveformOverlayManager.swift — gestiona el panel flotante de ondas
├── Models/
│ └── SpeechRecognizer.swift — SFSpeechRecognizer (es-ES), auto-paste, guard idempotente
├── Views/
│ ├── FloatingWaveformView.swift — overlay "liquid glass" con animación de barras
│ ├── PopoverView.swift — UI del popover (transcripción, controles)
│ └── WaveformView.swift — componente de visualización de audio
├── Extensions/
│ └── Notification+Names.swift — nombres de notificaciones internas
└── Resources/
├── Info.plist
└── WisperBar.entitlements
Todo el procesamiento de audio y voz ocurre en el dispositivo. No se envía audio, texto ni metadatos a ningún servidor externo.