Arquitectura
speech-swift está organizado como un paquete Swift modular con protocolos compartidos, módulos de modelo independientes y una CLI unificada. Toda la inferencia se ejecuta en el dispositivo usando MLX (GPU Metal) o CoreML (Neural Engine).
Grafo de dependencias de módulos
┌──────────┐
│ AudioCLI │ (punto de entrada)
└────┬─────┘
│
┌──────┴──────┐
│ AudioCLILib │ (comandos)
└──────┬──────┘
│
┌─────────┬───────┼───────┬──────────┬──────────────┐
│ │ │ │ │ │
┌────┴───┐ ┌──┴──┐ ┌──┴──┐ ┌─┴────┐ ┌───┴────┐ ┌──────┴───────┐
│Qwen3ASR│ │Qwen3│ │Cosy │ │Perso-│ │Speech- │ │ Speech- │
│Parakeet│ │ TTS │ │Voice│ │naPlex│ │ VAD │ │Enhancement │
└────┬───┘ └──┬──┘ └──┬──┘ └──┬───┘ └───┬───┘ └──────┬───────┘
│ │ │ │ │ │
└────────┴───────┼───────┴─────────┘ │
│ │
┌──────┴──────┐ │
│ Qwen3Common │ (capas compartidas) │
└──────┬──────┘ │
│ │
┌──────┴──────┐ │
│ AudioCommon │ ◄──────────────────────┘
└─────────────┘ (protocolos, E/S de audio)Backends de inferencia
| Backend | Hardware | Modelos |
|---|---|---|
| MLX | GPU Metal | Qwen3-ASR, Qwen3-TTS, CosyVoice3, Qwen3.5-Chat, PersonaPlex, Omnilingual ASR (300M / 1B / 3B / 7B), Pyannote, Silero VAD, WeSpeaker |
| CoreML | Neural Engine | Encoder de Qwen3-ASR (híbrido), Parakeet TDT, Parakeet EOU streaming, Omnilingual ASR 300M, Kokoro-82M, Qwen3.5-Chat (opcional), diarización Sortformer, DeepFilterNet3, Silero VAD (opcional), WeSpeaker (opcional) |
| Accelerate | CPU (SIMD) | Preprocesamiento de audio (STFT, mel, FFT), procesamiento de señales |
Formato de pesos de los modelos
Los modelos MLX usan el formato safetensors con cuantización de 4 bits u 8 bits (tamaño de grupo 64). Los modelos CoreML usan el formato compilado .mlmodelc. Los scripts de conversión en scripts/ convierten desde checkpoints de PyTorch.
| Modelo | Parámetros | Cuantización | Tamaño en disco |
|---|---|---|---|
| Qwen3-ASR 0.6B (MLX) | ~600M | 4-bit / 8-bit | 680 MB / 1.0 GB |
| Qwen3-ASR 0.6B (CoreML) | ~186M (encoder) | INT8 | ~180 MB |
| Qwen3-ASR 1.7B (MLX) | ~1.7B | 4-bit / 8-bit | 2.1 GB / 3.2 GB |
| Parakeet-TDT 0.6B (CoreML) | ~600M | INT8 | 500 MB |
| Parakeet-EOU 120M (CoreML) | ~120M | INT8 | ~120 MB |
| Omnilingual-ASR-CTC 300M (CoreML) | 326M | INT8 | 312 MB |
| Omnilingual-ASR-CTC 300M (MLX) | 326M | 4-bit / 8-bit | 193 MB / 342 MB |
| Omnilingual-ASR-CTC 1B (MLX) | 1.01B | 4-bit / 8-bit | 549 MB / 1006 MB |
| Omnilingual-ASR-CTC 3B (MLX) | ~3B | 4-bit / 8-bit | 1.71 GB / 3.16 GB |
| Omnilingual-ASR-CTC 7B (MLX) | ~7B | 4-bit / 8-bit | 3.55 GB / 6.63 GB |
| Qwen3-ForcedAligner 0.6B (MLX) | ~600M | 4-bit / 8-bit | 979 MB / 1.4 GB |
| Qwen3-ForcedAligner 0.6B (CoreML) | ~600M | INT4 / INT8 | 630 MB / 1.0 GB |
| Qwen3-TTS 0.6B (MLX) | ~600M | 4-bit / 8-bit | 1.7 GB / 2.4 GB |
| Qwen3-TTS 1.7B (MLX) | ~1.7B | 4-bit / 8-bit | 3.2 GB / 4.8 GB |
| CosyVoice3 0.5B (MLX) | ~500M | LLM en 4-bit | ~1.2 GB |
| Kokoro-82M (CoreML) | 82M | INT8 (1 bucket) | ~89 MB |
| Qwen3.5-Chat 0.8B (MLX) | ~800M | INT4 | 418 MB |
| Qwen3.5-Chat 0.8B (CoreML) | ~800M | INT8 | 981 MB |
| PersonaPlex 7B (MLX) | ~7B | 4-bit / 8-bit | 4.9 GB / 9.1 GB |
| Pyannote VAD (MLX) | ~1.49M | float32 | ~5.7 MB |
| Silero VAD v5 | ~309K | float32 | ~1.2 MB (MLX y CoreML) |
| WeSpeaker ResNet34 | ~6.6M | float32 | ~25 MB (MLX y CoreML) |
| Sortformer (CoreML) | — | float16 | ~50 MB |
| DeepFilterNet3 (CoreML) | ~2.1M | FP16 | ~4.2 MB |
Optimizaciones de rendimiento
- MLX compile() — Fusión de kernels para bucles autoregresivos. Talker usa
compile(shapeless: true), el Code Predictor usacompile(shapeless: false)con tamaños de caché fijos. - Librería de shaders Metal — El metallib precompilado evita una sobrecarga de compilación JIT ~5x. Construido vía
scripts/build_mlx_metallib.sh. - Decodificación de códec por chunks — El decoder TTS procesa audio en chunks de 25 frames con un solape de contexto de 10 frames para evitar timeouts de GPU.
- CFG con batch duplicado — El DiT de CosyVoice3 reduce a la mitad los pases de flow matching agrupando condicional + incondicional en un batch.
- RoPE fusionado — Usa
MLXNN.RoPErespaldado por un kernel Metal en lugar de rotación manual. - Fusión de BN — La batch normalization de WeSpeaker se fusiona en los pesos de Conv2d en tiempo de conversión.
Procesamiento de audio
Toda la E/S de audio usa PCM Float32. El remuestreo interno gestiona la conversión de formato:
| Modelo | Tasa esperada | Formato |
|---|---|---|
| Qwen3-ASR | 16 kHz | Mono Float32 |
| Qwen3-TTS | 24 kHz de salida | Mono Float32 |
| CosyVoice3 | 24 kHz de salida | Mono Float32 |
| Kokoro-82M | 24 kHz de salida | Mono Float32 |
| PersonaPlex | 24 kHz E/S | Mono Float32 |
| Pyannote VAD | 16 kHz | Mono Float32 |
| Silero VAD | 16 kHz | Mono Float32 |
| WeSpeaker | 16 kHz | Mono Float32 |
| DeepFilterNet3 | 48 kHz | Mono Float32 |
Estructura del código fuente
Sources/
AudioCommon/ Protocolos compartidos, E/S de audio, descargador
de HuggingFace, SentencePieceModel (lector protobuf)
MLXCommon/ Utilidades MLX: carga de pesos, helpers QuantizedLinear,
helper de atención multi-head SDPA, presupuesto metal
Qwen3Common/ Componentes de modelo compartidos (caché KV, RoPE, cuantización)
Qwen3ASR/ Qwen3-ASR voz a texto
ParakeetASR/ Parakeet TDT voz a texto (CoreML)
ParakeetStreamingASR/ Dictado en streaming Parakeet EOU 120M (CoreML)
OmnilingualASR/ Meta wav2vec2 + CTC, 1.672 idiomas
(CoreML 300M + MLX 300M / 1B / 3B / 7B)
Qwen3TTS/ Qwen3-TTS texto a voz
CosyVoiceTTS/ CosyVoice3 texto a voz
KokoroTTS/ Kokoro-82M texto a voz (CoreML)
Qwen3Chat/ Chat LLM en el dispositivo Qwen3.5-0.8B (MLX + CoreML)
PersonaPlex/ PersonaPlex voz a voz
SpeechVAD/ VAD (Silero + Pyannote), diarización, embeddings de hablante
SpeechEnhancement/ Supresión de ruido DeepFilterNet3 (CoreML)
AudioCLILib/ Implementaciones de comandos de la CLI
AudioCLI/ Punto de entrada de la CLI
scripts/ Conversión de modelos (PyTorch → MLX/CoreML), benchmarking
Tests/ Pruebas unitarias y de integración
Examples/ Apps de demostración (PersonaPlexDemo, SpeechDemo)