14 KiB
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):
[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
// 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:
<key>NSMicrophoneUsageDescription</key>
<string>Alpha necesita acceso al micrófono para transcribir tus reuniones.</string>
Detección de permiso (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)
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<f32> = 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
// 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<f32> = reader.samples::<i16>()
.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
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 |