Modèles parole-à-parole

Soniqo prend en charge deux familles de modèles MLX natifs pour la conversation parole-à-parole : PersonaPlex 7B et VoiceChat 11B. Tous deux reçoivent de la parole et génèrent directement l'audio du modèle, mais leurs architectures duplex et leurs contrats d'exécution diffèrent.

Choisir un modèle

ModèleModèle de conversationIdéal pour
PersonaPlex 7BFull-duplex simultané avec Moshi, Depformer et MimiÉcoute et parole simultanées, avec 18 voix sélectionnables
VoiceChat 11BDuplex continu et synchronisé par trame avec FastConformer, Nemotron-H, EAR-TTS et un codec neuronalTrames de streaming de 80 ms, événements texte/fonction et voix native du checkpoint

Il s'agit de modèles conversationnels parole-à-parole. Hibiki transforme aussi directement la parole en parole, mais sa tâche est la traduction vocale en streaming et sa documentation est séparée.

PersonaPlex 7B

Modèle de dialogue parole-à-parole full-duplex basé sur l'architecture Moshi (Kyutai). PersonaPlex 7B génère des réponses parlées directement à partir d'une entrée parlée — sans pipeline texte intermédiaire. Le modèle est livré avec 18 préréglages de voix et est disponible en quantification 8 bits (recommandée) et 4 bits. Le 8 bits est la valeur par défaut — il est 30 % plus rapide et produit des réponses cohérentes, tandis que le 4 bits dégrade la qualité de sortie.

VoiceChat 11B

Référence speech-to-speech duplex : SALM-Duplex: Efficient and Direct Duplex Modeling for Speech-to-Speech Language Model (Interspeech 2025), citée par la fiche VoiceChat amont de NVIDIA.

M5 Pro, 48 Go, Release, cadence live de 80 ms, INT5 avec têtes protégées : trois exécutions contrôlées ont mesuré un RTF du pipeline complet de 0.94, 0.92 et 0.92, avec environ 8.70 Go de RSS maximal. Le premier texte parlé est arrivé en 44.3–46.7 ms et le premier audio lisible en 74.0–76.4 ms. Ce sont des mesures de calcul à chaud, pas une latence de prise de tour apprise ; les performances INT8 optimisées n'ont pas encore été remesurées.

VoiceChat est l'autre runtime parole-à-parole MLX natif de speech-swift. Il combine perception FastConformer causale, canaux duplex texte/fonction Nemotron-H, EAR-TTS autonome conditionné par le texte et codec neuronal à 22,05 kHz. Une session reçoit en continu de l'audio mono 16 kHz et renvoie toutes les 80 ms des événements texte ainsi qu'une trame de sortie de 1 764 échantillons.

Chargez avec VoiceChatModel.load(from:), démarrez une VoiceChatSession et envoyez l'audio via pushAudio. Un bundle complet doit contenir encoder/, llm/ et tts/ ; les anciens bundles limités à la compréhension sont refusés.

Performances actuelles

INT5 maintient un débit global sous RTF 1 sur le M5 Pro testé. Les trois exécutions ont aussi gardé le p95 total par trame sous 80 ms, entre 76.2 et 78.6 ms ; la marge d'échéance reste donc faible. Mesurez séparément le début de tour du modèle et la latence de calcul matériel.

Architecture et utilisation de PersonaPlex

PersonaPlex est un modèle autorégressif multi-flux avec trois composants principaux :

ComposantDétails
Temporal Transformer32 couches, dim=4096, 32 têtes, SwiGLU (hidden_scale=4.125), RoPE, quantifié 8 bits (par défaut)
Depformer6 couches, dim=1024, 16 têtes, MultiLinear (weights_per_step=true), dep_q=16
Mimi Codec16 codebooks, taux de trame 12,5 Hz, sortie audio 24 kHz

Le modèle traite 17 flux simultanément : 1 flux texte + 8 flux audio utilisateur + 8 flux audio agent. Cette architecture permet une conversation full-duplex où le modèle peut écouter et parler en même temps.

Préréglages de voix

PersonaPlex inclut 18 préréglages de voix intégrés dans des styles naturels et variés :

CatégoriePréréglages
Femme naturelleNATF0, NATF1, NATF2, NATF3
Homme naturelNATM0, NATM1, NATM2, NATM3
Femme variéeVARF0, VARF1, VARF2, VARF3, VARF4
Homme variéVARM0, VARM1, VARM2, VARM3, VARM4

Monologue intérieur

PersonaPlex génère deux flux parallèles à chaque étape : 8 tokens de codebook audio pour le codec Mimi et un token de texte pour le monologue intérieur du modèle. Le flux de texte est ce que le modèle « pense » pendant qu'il parle — il peut diverger légèrement de l'audio final, mais en pratique il reflète suffisamment la réponse parlée pour être utilisé comme transcription en direct.

Les tokens de texte reviennent sous forme d'IDs de pièces SentencePiece bruts. Décodez-les avec le SentencePieceDecoder fourni par PersonaPlex :

import PersonaPlex
import AudioCommon

let model = try await PersonaPlexModel.fromPretrained()
let decoder = model.tokenizer  // SentencePieceDecoder?

let result = model.respond(userAudio: userSamples, voice: .NATM0)
let transcript = decoder?.decode(result.textTokens) ?? ""
print(transcript)        // "Sure, I can help with that..."
playAudio(result.audio)  // 24 kHz mono Float32

En mode streaming, respondStream émet des chunks textTokens à mesure qu'ils sont produits — décodez-les de façon incrémentale pour piloter une vue de sous-titres en direct pendant que l'audio est encore en génération. L'option CLI --transcript fait exactement cela en coulisses.

Pourquoi c'est important : SentencePieceDecoder est construit sur le lecteur protobuf partagé AudioCommon.SentencePieceModel, donc PersonaPlex, OmnilingualASR et tout futur modèle basé sur SentencePiece décodent via la même implémentation de tokenizer. Voir la référence SentencePieceModel.

Prompts système

Passez n'importe quel prompt système personnalisé sous forme de chaîne simple — aucune tokenisation externe n'est nécessaire :

let response = model.respond(
    userAudio: audio,
    voice: .NATM0,
    systemPrompt: "You enjoy having a good conversation."
)

Ou utilisez un préréglage intégré :

Utilisation en CLI

Générer une réponse parlée à partir d'une entrée audio :

# Basic speech-to-speech
.build/release/speech respond --input question.wav

# Choose a voice preset
.build/release/speech respond --input question.wav --voice NATM0

# Stream audio output during generation
.build/release/speech respond --input question.wav --stream

# Custom system prompt text
.build/release/speech respond --input question.wav --system-prompt-text "You enjoy having a good conversation."

# Use a preset system prompt
.build/release/speech respond --input question.wav --system-prompt customer-service

# Get transcript alongside audio
.build/release/speech respond --input question.wav --transcript

# JSON output with metadata
.build/release/speech respond --input question.wav --json

Options

OptionDescription
--inputFichier audio d'entrée (WAV, requis)
--voiceNom de préréglage de voix (ex. NATM0, VARF2)
--system-promptPréréglage de prompt système : assistant, focused, customer-service, teacher
--system-prompt-textTexte de prompt système personnalisé (prime sur --system-prompt)
--max-stepsÉtapes de génération maximum
--streamÉmettre des chunks audio pendant la génération
--compileUtiliser l'inférence compilée MLX pour une génération plus rapide
--transcriptAfficher la transcription textuelle avec l'audio
--jsonSortie JSON avec métadonnées

Les paramètres d'échantillonnage peuvent également être surchargés :

OptionPar défautDescription
--audio-temp0,8Température d'échantillonnage des tokens audio
--audio-top-k250Échantillonnage top-k des tokens audio
--text-temp0,7Température d'échantillonnage des tokens texte
--text-top-k25Échantillonnage top-k des tokens texte

Streaming

L'option --stream active la sortie audio en temps réel. Les chunks audio sont émis à mesure qu'ils sont générés, donc la lecture peut commencer avant que la réponse complète ne soit terminée. C'est particulièrement utile pour les applications interactives où une faible latence compte.

Performance

MétriqueValeur
Facteur temps réel (RTF)~1,4 (8 bits, proche du temps réel)
Latence par étape~112 ms/étape sur M2 Max (8 bits)
Taille du modèle (8 bits)~9,1 Go
RAM en pic (8 bits)~11 Go
Taille du modèle (4 bits)~4,9 Go
RAM en pic (4 bits)~7 Go
Important

PersonaPlex 7B (8 bits) requiert au moins 24 Go de RAM. La variante 4 bits tient sur des appareils 16 Go mais produit une sortie dégradée. Sur des appareils 8 Go, aucune variante ne tiendra. Utilisez --compile pour de meilleures performances sur le matériel pris en charge.

Variantes du modèle

ModèleTailleHuggingFace
PersonaPlex-7B (8 bits) recommandé9,1 Goaufklarer/PersonaPlex-7B-MLX-8bit
PersonaPlex-7B (4 bits)4,9 Goaufklarer/PersonaPlex-7B-MLX-4bit

API Swift

import PersonaPlex
import AudioCommon

let model = try await PersonaPlexModel.fromPretrained()
let response = model.respond(
    userAudio: userSamples,
    voice: .NATM0,
    systemPrompt: "You are a helpful assistant."
)
try WAVWriter.write(samples: response.audio, sampleRate: 24000, to: URL(filePath: "answer.wav"))