# Alpha + Handy — Integración de Transcripción Offline > **Inspiración**: Handy (github.com/cjpais/Handy) — 22.4k ⭐, Tauri v2, MIT. > Alpha toma de Handy su arquitectura de transcripción local con modelos Whisper/Parakeet. **Versión**: 1.0 | **Fecha**: 2026-05-26 | **Autor**: Ricardo Gonzalez (Teloprax) --- ## 1. ¿Qué es Handy? Handy es una app Tauri v2 que captura audio del micrófono, lo transcribe con modelos locales (Whisper o Parakeet) y pega el texto donde esté el cursor. Todo offline. Es la referencia perfecta para integrar transcripción en RUMBO/Alpha. | Aspecto | Handy | Alpha (a integrar) | |---------|-------|---------------------| | Shell | Tauri v2 | Tauri v2 ✅ | | Frontend | React + TS + Tailwind | Vue 3 + TS + Tailwind 🔄 | | Transcripción | transcribe-rs (Whisper + Parakeet) | transcribe-rs | | Captura audio | cpal (micrófono) | cpal (micrófono + archivos) | | VAD (silencio) | vad-rs (Silero) | vad-rs | | Atajos globales | rdev + tauri-plugin-global-shortcut | rdev + tauri-plugin-global-shortcut | | Permisos macOS | tauri-plugin-macos-permissions | Ídem | | Permisos Windows | Win32 APIs (Windows crate) | Ídem | --- ## 2. Arquitectura de transcripción (basada en Handy) ``` ┌──────────────────────────────────────────────────┐ │ Alpha (Tauri) │ │ │ │ ┌─────────────┐ ┌─────────────────────────┐ │ │ │ Vue 3 UI │ │ Rust Backend │ │ │ │ (activar │◄──►│ │ │ │ │ mic, │ │ ┌───────────────────┐ │ │ │ │ modelos, │ │ │ Audio Capture │ │ │ │ │ transc.) │ │ │ (cpal) │ │ │ │ └─────────────┘ │ │ → micrófono │ │ │ │ │ │ → archivo .wav │ │ │ │ │ │ → archivo .mp3 │ │ │ │ │ │ → video (ffmpeg │ │ │ │ │ │ extrae audio) │ │ │ │ │ └───────┬───────────┘ │ │ │ │ │ audio raw │ │ │ │ ┌───────▼───────────┐ │ │ │ │ │ VAD (vad-rs) │ │ │ │ │ │ → silencio OUT │ │ │ │ │ │ → voz → buffer │ │ │ │ │ └───────┬───────────┘ │ │ │ │ │ segmentos │ │ │ │ ┌───────▼───────────┐ │ │ │ │ │ transcribe-rs │ │ │ │ │ │ → Parakeet V3 │ │ │ │ │ │ → Whisper Small │ │ │ │ │ │ → Whisper Turbo │ │ │ │ │ └───────┬───────────┘ │ │ │ │ │ texto │ │ │ │ ┌───────▼───────────┐ │ │ │ │ │ Post-procesado │ │ │ │ │ │ → pegar en app │ │ │ │ │ │ → guardar en DB │ │ │ │ │ │ → pipeline IA │ │ │ │ │ └───────────────────┘ │ │ │ └─────────────────────────┘ │ └──────────────────────────────────────────────────┘ ``` --- ## 3. Dependencias Rust necesarias Inspiradas en el `Cargo.toml` de Handy (v0.8.3): ```toml [dependencies] # Transcripción (core) transcribe-rs = { version = "0.3", features = ["whisper-cpp", "onnx"] } # Audio cpal = "0.16" # Captura de micrófono hound = "3.5" # Lectura/escritura de archivos .wav # VAD (Voice Activity Detection) vad-rs = { git = "https://github.com/cjpais/vad-rs", default-features = false } # Atajos globales rdev = { git = "https://github.com/rustdesk-org/rdev" } tauri-plugin-global-shortcut = "2.3" # Permisos tauri-plugin-macos-permissions = "2.3" # Resampling (si se necesita cambiar sample rate) rubato = "0.16" # Audio playback (feedback sonoro) rodio = "0.16" # Utilidades anyhow = "1.0" tokio = { version = "1", features = ["full"] } serde = { version = "1", features = ["derive"] } serde_json = "1" # ─── Plataforma-específicas ─── [target.'cfg(target_os = "macos")'.dependencies] transcribe-rs = { version = "0.3", features = ["whisper-metal"] } [target.'cfg(target_os = "windows")'.dependencies] transcribe-rs = { version = "0.3", features = ["whisper-vulkan", "ort-directml"] } [target.'cfg(target_os = "linux")'.dependencies] transcribe-rs = { version = "0.3", features = ["whisper-vulkan"] } ``` --- ## 4. Modelos de transcripción ### 4.1 Parakeet V3 (RECOMENDADO) | Característica | Detalle | |---------------|---------| | Tamaño | ~478 MB (comprimido) | | Velocidad | ~5x tiempo real en CPU (i5) | | GPU | No requiere — CPU-optimizado | | Idioma | Detección automática (sin selección manual) | | Precisión | Excelente en español e inglés | | Descarga | `https://blob.handy.computer/parakeet-v3-int8.tar.gz` | | Backend | ONNX Runtime (vía transcribe-rs feature `onnx`) | **Por qué Parakeet V3**: No requiere GPU, funciona en cualquier CPU moderna (Skylake+), velocidad adecuada para transcripción interactiva, y detección automática de idioma (esencial para equipos bilingües español/inglés). ### 4.2 Whisper (alternativa) | Modelo | Tamaño | Velocidad | GPU | |--------|--------|-----------|-----| | Small | 487 MB | Rápido | Opcional | | Medium | 492 MB | Medio | Recomendada | | Turbo | 1.6 GB | Rápido | Recomendada | | Large | 1.1 GB | Lento | Necesaria | Whisper es más preciso pero más pesado y requiere GPU para velocidad aceptable. Parakeet V3 es mejor opción para Alpha por su eficiencia CPU. --- ## 5. ¿Parakeet V3 para video/audio pregrabado? **Sí**, pero con un paso intermedio: extraer el audio del video. ### Flujo para video ``` video.mp4 → ffmpeg (extraer pista de audio) → audio.wav → transcribe-rs → texto ``` ### Flujo para audio pregrabado ``` grabacion.mp3/.ogg/.flac/.m4a → decodificar a PCM/WAV → transcribe-rs → texto ``` ### Implementación en Rust ```rust // Opción A: Usar ffmpeg CLI (sidecar) use std::process::Command; Command::new("ffmpeg") .args(["-i", "video.mp4", "-vn", "-ar", "16000", "-ac", "1", "-f", "wav", "audio.wav"]) .output()?; // Opción B: Usar crate ffmpeg-sidecar (más portátil) // Opción C: Usar crate symphonia para decodificar audio sin ffmpeg ``` ### Formatos soportados | Fuente | Método | Librería Rust | |--------|--------|---------------| | Micrófono (vivo) | cpal → buffer → transcribe-rs | cpal | | .wav | hound → samples → transcribe-rs | hound | | .mp3, .ogg, .flac, .m4a | symphonia → decode → transcribe-rs | symphonia | | Video (.mp4, .mov, .mkv) | ffmpeg → extract audio → transcribe-rs | ffmpeg-sidecar | --- ## 6. Permisos del sistema ### 6.1 macOS | Permiso | Propósito | Cómo solicitarlo | |---------|-----------|-----------------| | **Microphone** | Capturar audio del micrófono | Info.plist: `NSMicrophoneUsageDescription` | | **Accessibility** | Pegar texto en cualquier app | System Preferences → Privacy → Accessibility | | **Screen Recording** | (futuro) Capturar audio del sistema | Info.plist: `NSScreenCaptureUsageDescription` | **Código Info.plist**: ```xml NSMicrophoneUsageDescription Alpha necesita acceso al micrófono para transcribir tus reuniones. ``` **Detección de permiso (Rust)**: ```rust use tauri_plugin_macos_permissions; // Verificar si el permiso está concedido let authorized = tauri_plugin_macos_permissions::check_accessibility(); // Solicitar permiso tauri_plugin_macos_permissions::request_accessibility(); ``` ### 6.2 Windows | Permiso | Propósito | Cómo solicitarlo | |---------|-----------|-----------------| | **Microphone** | Capturar audio | Windows Settings → Privacy → Microphone | | **Global shortcuts** | Atajos de teclado | Automático con rdev | Windows solicita el permiso automáticamente la primera vez que se usa el micrófono. ### 6.3 Linux | Requisito | Propósito | |-----------|-----------| | PulseAudio / ALSA | Captura de audio | | Grupo `input` | Atajos globales (algunos WMs) | --- ## 7. Flujo de transcripción paso a paso ### 7.1 Micrófono (tiempo real) ```rust use cpal::traits::{DeviceTrait, HostTrait, StreamTrait}; use transcribe_rs::Transcriber; // 1. Obtener dispositivo de audio por defecto let host = cpal::default_host(); let device = host.default_input_device().unwrap(); let config = device.default_input_config().unwrap(); // 2. Configurar stream de audio let (tx, rx) = std::sync::mpsc::channel(); let stream = device.build_input_stream(&config, move |data, _| { tx.send(data.to_vec()).unwrap(); }, |err| eprintln!("{}", err), None).unwrap(); stream.play().unwrap(); // 3. Buffer de audio + VAD let mut buffer: Vec = Vec::new(); let mut vad = vad_rs::Vad::new(config.sample_rate().0); // 4. Acumular voz, ignorar silencio while let Ok(samples) = rx.recv_timeout(Duration::from_millis(100)) { for &sample in &samples { if vad.is_voice(sample) { buffer.push(sample); } } if buffer.len() > config.sample_rate().0 as usize * 3 { break; // 3 segundos de voz → transcribir } } // 5. Transcribir con Parakeet V3 let transcriber = Transcriber::new("parakeet-tdt-0.6b-v3-int8")?; let text = transcriber.transcribe(&buffer, config.sample_rate().0)?; println!("{}", text); ``` ### 7.2 Archivo de audio/video ```rust // 1. Si es video, extraer audio con ffmpeg // 2. Leer archivo .wav use hound::WavReader; let mut reader = WavReader::open("audio.wav")?; let samples: Vec = reader.samples::() .map(|s| s.unwrap() as f32 / i16::MAX as f32) .collect(); // 3. Transcribir let transcriber = Transcriber::new("parakeet-tdt-0.6b-v3-int8")?; let text = transcriber.transcribe(&samples, reader.spec().sample_rate)?; ``` --- ## 8. Descarga y gestión de modelos Inspirado en Handy, los modelos se almacenan en: | SO | Ruta | |----|------| | macOS | `~/Library/Application Support/com.teloprax.alpha/models/` | | Windows | `%APPDATA%\com.teloprax.alpha\models\` | | Linux | `~/.config/com.teloprax.alpha/models/` | ### Estructura esperada ``` models/ ├── parakeet-tdt-0.6b-v3-int8/ ← Parakeet V3 (recomendado) │ ├── model.onnx │ ├── config.json │ └── tokenizer.json ├── ggml-small.bin ← Whisper Small (alternativo) └── ggml-large-v3-turbo.bin ← Whisper Turbo (alternativo) ``` ### Descarga programática ```rust use reqwest; use flate2::read::GzDecoder; use tar::Archive; async fn download_model(url: &str, dest: &Path) -> Result<()> { let response = reqwest::get(url).await?; let bytes = response.bytes().await?; // Extraer si es .tar.gz (Parakeet), copiar si es .bin (Whisper) if url.ends_with(".tar.gz") { let gz = GzDecoder::new(&bytes[..]); let mut archive = Archive::new(gz); archive.unpack(dest)?; } else { std::fs::write(dest.join(url.split('/').last().unwrap()), &bytes)?; } Ok(()) } ``` --- ## 9. Diferencia clave Alpha vs Handy Handy es una app de propósito general (transcribir y pegar). Alpha lo integra en el flujo de gestión de proyectos: | Capacidad | Handy | Alpha | |-----------|-------|-------| | Transcribir micrófono | ✅ | ✅ (para reuniones) | | Pegar texto en cualquier app | ✅ | ⬜ (no necesario) | | Transcribir archivos de audio | ⬜ | ✅ (.mp3, .wav, .ogg) | | Extraer audio de video | ⬜ | ✅ (vía ffmpeg) | | Pipeline IA post-transcripción | ⬜ | ✅ (→ análisis → HUs → KAPPA) | | Guardar transcripción en proyecto | ⬜ | ✅ (Turso + contexto de proyecto) | | Memoria de proyecto | ⬜ | ✅ (contexto_transcripciones.md) | | Integración con KAPPA | ⬜ | ✅ (crear HUs automáticamente) | --- ## 10. Roadmap de integración | Fase | Alcance | Prioridad | |------|---------|-----------| | **T1** | Agregar dependencias Rust (transcribe-rs, cpal, vad-rs) | 🔴 Alta | | **T2** | Captura de micrófono + transcripción Parakeet V3 | 🔴 Alta | | **T3** | Descarga de modelos desde UI | 🟡 Media | | **T4** | Transcripción de archivos (.wav, .mp3) | 🟡 Media | | **T5** | Transcripción de video (extracción audio) | 🟢 Baja | | **T6** | Pipeline completo: audio → transcripción → IA → HUs | 🔴 Alta | | **T7** | Permisos macOS/Windows UI | 🟡 Media | --- ## 11. Referencias - [Handy GitHub](https://github.com/cjpais/Handy) - [transcribe-rs crate](https://crates.io/crates/transcribe-rs) - [cpal crate](https://crates.io/crates/cpal) - [vad-rs (fork de Handy)](https://github.com/cjpais/vad-rs) - [Parakeet models (HuggingFace)](https://huggingface.co/nvidia/parakeet-tdt-0.6b-v3) - [Tauri Plugin macOS Permissions](https://github.com/ahkohd/tauri-plugin-macos-permissions)