Architecture
speech-swift est organisé comme un package Swift modulaire avec des protocoles partagés, des modules de modèles indépendants et une CLI unifiée. Toute l'inférence s'exécute sur l'appareil en utilisant MLX (GPU Metal) ou CoreML (Neural Engine).
Graphe de dépendances des modules
┌──────────┐
│ AudioCLI │ (point d'entrée)
└────┬─────┘
│
┌──────┴──────┐
│ AudioCLILib │ (commandes)
└──────┬──────┘
│
┌─────────┬───────┼───────┬──────────┬──────────────┐
│ │ │ │ │ │
┌────┴───┐ ┌──┴──┐ ┌──┴──┐ ┌─┴────┐ ┌───┴────┐ ┌──────┴───────┐
│Qwen3ASR│ │Qwen3│ │Cosy │ │Perso-│ │Speech- │ │ Speech- │
│Parakeet│ │ TTS │ │Voice│ │naPlex│ │ VAD │ │Enhancement │
└────┬───┘ └──┬──┘ └──┬──┘ └──┬───┘ └───┬───┘ └──────┬───────┘
│ │ │ │ │ │
└────────┴───────┼───────┴─────────┘ │
│ │
┌──────┴──────┐ │
│ Qwen3Common │ (couches partagées) │
└──────┬──────┘ │
│ │
┌──────┴──────┐ │
│ AudioCommon │ ◄──────────────────────┘
└─────────────┘ (protocoles, E/S audio)Backends d'inférence
| Backend | Matériel | Modèles |
|---|---|---|
| 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 | Encodeur Qwen3-ASR (hybride), Parakeet TDT, Parakeet EOU streaming, Omnilingual ASR 300M, Kokoro-82M, Qwen3.5-Chat (optionnel), diarisation Sortformer, DeepFilterNet3, Silero VAD (optionnel), WeSpeaker (optionnel) |
| Accelerate | CPU (SIMD) | Prétraitement audio (STFT, mel, FFT), traitement du signal |
Format des poids de modèles
Les modèles MLX utilisent le format safetensors avec une quantification 4 bits ou 8 bits (taille de groupe 64). Les modèles CoreML utilisent le format compilé .mlmodelc. Les scripts de conversion dans scripts/ convertissent depuis des checkpoints PyTorch.
| Modèle | Paramètres | Quantification | Taille sur disque |
|---|---|---|---|
| Qwen3-ASR 0.6B (MLX) | ~600M | 4 bits / 8 bits | 680 Mo / 1,0 Go |
| Qwen3-ASR 0.6B (CoreML) | ~186M (encodeur) | INT8 | ~180 Mo |
| Qwen3-ASR 1.7B (MLX) | ~1,7B | 4 bits / 8 bits | 2,1 Go / 3,2 Go |
| Parakeet-TDT 0.6B (CoreML) | ~600M | INT8 | 500 Mo |
| Parakeet-EOU 120M (CoreML) | ~120M | INT8 | ~120 Mo |
| Omnilingual-ASR-CTC 300M (CoreML) | 326M | INT8 | 312 Mo |
| Omnilingual-ASR-CTC 300M (MLX) | 326M | 4 bits / 8 bits | 193 Mo / 342 Mo |
| Omnilingual-ASR-CTC 1B (MLX) | 1,01B | 4 bits / 8 bits | 549 Mo / 1006 Mo |
| Omnilingual-ASR-CTC 3B (MLX) | ~3B | 4 bits / 8 bits | 1,71 Go / 3,16 Go |
| Omnilingual-ASR-CTC 7B (MLX) | ~7B | 4 bits / 8 bits | 3,55 Go / 6,63 Go |
| Qwen3-ForcedAligner 0.6B (MLX) | ~600M | 4 bits / 8 bits | 979 Mo / 1,4 Go |
| Qwen3-ForcedAligner 0.6B (CoreML) | ~600M | INT4 / INT8 | 630 Mo / 1,0 Go |
| Qwen3-TTS 0.6B (MLX) | ~600M | 4 bits / 8 bits | 1,7 Go / 2,4 Go |
| Qwen3-TTS 1.7B (MLX) | ~1,7B | 4 bits / 8 bits | 3,2 Go / 4,8 Go |
| CosyVoice3 0.5B (MLX) | ~500M | LLM 4 bits | ~1,2 Go |
| Kokoro-82M (CoreML) | 82M | INT8 (1 bucket) | ~89 Mo |
| Qwen3.5-Chat 0.8B (MLX) | ~800M | INT4 | 418 Mo |
| Qwen3.5-Chat 0.8B (CoreML) | ~800M | INT8 | 981 Mo |
| PersonaPlex 7B (MLX) | ~7B | 4 bits / 8 bits | 4,9 Go / 9,1 Go |
| Pyannote VAD (MLX) | ~1,49M | float32 | ~5,7 Mo |
| Silero VAD v5 | ~309K | float32 | ~1,2 Mo (MLX et CoreML) |
| WeSpeaker ResNet34 | ~6,6M | float32 | ~25 Mo (MLX et CoreML) |
| Sortformer (CoreML) | — | float16 | ~50 Mo |
| DeepFilterNet3 (CoreML) | ~2,1M | FP16 | ~4,2 Mo |
Optimisations de performance
- MLX compile() — Fusion de noyaux pour les boucles autorégressives. Talker utilise
compile(shapeless: true), Code Predictor utilisecompile(shapeless: false)avec des tailles de cache fixes. - Bibliothèque de shaders Metal — Le metallib pré-compilé évite environ 5× de surcoût de compilation JIT. Compilé via
scripts/build_mlx_metallib.sh. - Décodage de codec par chunks — Le décodeur TTS traite l'audio par chunks de 25 trames avec chevauchement de contexte de 10 trames pour éviter les timeouts GPU.
- CFG à batch doublé — Le DiT de CosyVoice3 divise par deux les passes de flow matching en groupant conditionnel + inconditionnel ensemble.
- RoPE fusionné — Utilise
MLXNN.RoPEadossé à un noyau Metal plutôt qu'une rotation manuelle. - Fusion BN — La normalisation par batch de WeSpeaker est fusionnée dans les poids Conv2d au moment de la conversion.
Traitement audio
Toutes les E/S audio utilisent du PCM Float32. Le rééchantillonnage interne gère la conversion de format :
| Modèle | Taux attendu | Format |
|---|---|---|
| Qwen3-ASR | 16 kHz | Mono Float32 |
| Qwen3-TTS | 24 kHz en sortie | Mono Float32 |
| CosyVoice3 | 24 kHz en sortie | Mono Float32 |
| Kokoro-82M | 24 kHz en sortie | 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 |
Structure des sources
Sources/
AudioCommon/ Protocoles partagés, E/S audio, téléchargeur HuggingFace,
SentencePieceModel (lecteur protobuf)
MLXCommon/ Utilitaires MLX : chargement des poids, aides QuantizedLinear,
aide d'attention multi-tête SDPA, budget Metal
Qwen3Common/ Composants de modèle partagés (cache KV, RoPE, quantification)
Qwen3ASR/ Qwen3-ASR parole vers texte
ParakeetASR/ Parakeet TDT parole vers texte (CoreML)
ParakeetStreamingASR/ Dictée streaming Parakeet EOU 120M (CoreML)
OmnilingualASR/ Meta wav2vec2 + CTC, 1 672 langues
(CoreML 300M + MLX 300M / 1B / 3B / 7B)
Qwen3TTS/ Qwen3-TTS texte vers parole
CosyVoiceTTS/ CosyVoice3 texte vers parole
KokoroTTS/ Kokoro-82M texte vers parole (CoreML)
Qwen3Chat/ Chat LLM embarqué Qwen3.5-0.8B (MLX + CoreML)
PersonaPlex/ PersonaPlex parole-à-parole
SpeechVAD/ VAD (Silero + Pyannote), diarisation, empreintes de locuteur
SpeechEnhancement/ Suppression de bruit DeepFilterNet3 (CoreML)
AudioCLILib/ Implémentations des commandes CLI
AudioCLI/ Point d'entrée CLI
scripts/ Conversion de modèles (PyTorch → MLX/CoreML), benchmarking
Tests/ Tests unitaires et d'intégration
Examples/ Applications de démonstration (PersonaPlexDemo, SpeechDemo)