Speech-to-Speech-Modelle
Soniqo unterstützt zwei native MLX-Modellfamilien für Sprachdialoge: PersonaPlex 7B und VoiceChat 11B. Beide nehmen Sprache auf und erzeugen Modell-Audio direkt, verwenden aber unterschiedliche Duplex-Architekturen und Laufzeitverträge.
Modell auswählen
| Modell | Dialogmodell | Am besten für |
|---|---|---|
| PersonaPlex 7B | Gleichzeitiges Vollduplex mit Moshi, Depformer und Mimi | Überlappendes Hören/Sprechen und 18 wählbare Stimmen |
| VoiceChat 11B | Kontinuierliches, frame-synchrones Duplex mit FastConformer, Nemotron-H, EAR-TTS und neuronalem Codec | 80-ms-Streamingframes, Text-/Funktionsereignisse und checkpoint-native Sprache |
Dies sind dialogorientierte Speech-to-Speech-Modelle. Hibiki bildet Sprache ebenfalls direkt auf Sprache ab, ist aber für Streaming-Sprachübersetzung bestimmt und daher separat dokumentiert.
PersonaPlex 7B
Vollduplex-Sprache-zu-Sprache-Dialogmodell basierend auf der Moshi-Architektur (Kyutai). PersonaPlex 7B erzeugt gesprochene Antworten direkt aus gesprochener Eingabe — keine zwischengeschaltete Text-Pipeline nötig. Das Modell wird mit 18 Stimmvoreinstellungen ausgeliefert und ist in 8-Bit (empfohlen) und 4-Bit-Quantisierung verfügbar. 8-Bit ist der Standard — es ist 30 % schneller und erzeugt kohärente Antworten, während 4-Bit die Ausgabequalität verschlechtert.
VoiceChat 11B
Duplex-Speech-to-Speech-Referenz: SALM-Duplex: Efficient and Direct Duplex Modeling for Speech-to-Speech Language Model (Interspeech 2025), zitiert in NVIDIAs Upstream-VoiceChat-Modellkarte.
M5 Pro, 48 GB, Release, 80-ms-Live-Takt, INT5 mit geschützten Heads: Drei kontrollierte Läufe maßen für den Gesamtpfad RTF 0.94, 0.92 und 0.92 bei etwa 8.70 GB Peak-RSS. Der erste gesprochene Text erschien nach 44.3–46.7 ms, das erste abspielbare Audio nach 74.0–76.4 ms. Das sind Rechenwerte im Warmzustand, keine erlernte Turn-Taking-Latenz; die optimierte INT8-Leistung wurde noch nicht neu gemessen.
VoiceChat ist die zweite native MLX-Sprache-zu-Sprache-Laufzeit in speech-swift. Sie kombiniert kausale FastConformer-Wahrnehmung, Nemotron-H-Duplex-Text-/Funktionskanäle, eigenständiges textkonditioniertes EAR-TTS und einen neuronalen 22,05-kHz-Codec. Eine Sitzung nimmt fortlaufend 16-kHz-Mono-Audio an und liefert alle 80 ms Textereignisse sowie einen Ausgabeframe mit 1.764 Samples.
Lade mit VoiceChatModel.load(from:), starte eine VoiceChatSession und übergib Audio mit pushAudio. Ein vollständiges Bundle muss encoder/, llm/ und tts/ enthalten; ältere reine Verständnis-Bundles werden abgelehnt.
INT5 hält auf dem getesteten M5 Pro den Gesamtdurchsatz unter RTF 1. In allen drei Läufen blieb auch das Gesamt-p95 pro Frame mit 76.2–78.6 ms unter 80 ms; der Deadline-Spielraum bleibt daher knapp. Modell-Turnbeginn und Hardware-Rechenlatenz sind getrennt zu messen.
PersonaPlex: Architektur und Verwendung
PersonaPlex ist ein autoregressives Multi-Stream-Modell mit drei Kernkomponenten:
| Komponente | Details |
|---|---|
| Temporal-Transformer | 32 Schichten, dim=4096, 32 Heads, SwiGLU (hidden_scale=4.125), RoPE, 8-Bit-quantisiert (Standard) |
| Depformer | 6 Schichten, dim=1024, 16 Heads, MultiLinear (weights_per_step=true), dep_q=16 |
| Mimi-Codec | 16 Codebooks, 12,5 Hz Frame-Rate, 24 kHz Audio-Ausgabe |
Das Modell verarbeitet 17 Streams gleichzeitig: 1 Text-Stream + 8 Benutzer-Audio-Streams + 8 Agent-Audio-Streams. Diese Architektur ermöglicht Vollduplex-Gespräche, bei denen das Modell gleichzeitig zuhören und sprechen kann.
Stimmvoreinstellungen
PersonaPlex enthält 18 eingebaute Stimmvoreinstellungen in natürlichen und abwechslungsreichen Stilen:
| Kategorie | Voreinstellungen |
|---|---|
| Natürlich weiblich | NATF0, NATF1, NATF2, NATF3 |
| Natürlich männlich | NATM0, NATM1, NATM2, NATM3 |
| Abwechslungsreich weiblich | VARF0, VARF1, VARF2, VARF3, VARF4 |
| Abwechslungsreich männlich | VARM0, VARM1, VARM2, VARM3, VARM4 |
Inner Monologue
PersonaPlex erzeugt bei jedem Schritt zwei parallele Streams: 8 Audio-Codebook-Tokens für den Mimi-Codec und ein Text-Token für den inneren Monolog des Modells. Der Text-Stream ist das, was das Modell „denkt“, während es spricht — er kann leicht vom finalen Audio abweichen, spiegelt in der Praxis jedoch die gesprochene Antwort eng genug wider, um als Live-Transkript verwendet zu werden.
Die Text-Tokens kommen als rohe SentencePiece-Piece-IDs zurück. Dekodiere sie mit dem SentencePieceDecoder, den PersonaPlex mitliefert:
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
Im Streaming-Modus emittiert respondStream textTokens-Chunks, sobald sie erzeugt werden — dekodiere sie inkrementell, um eine Live-Untertitelansicht zu treiben, während das Audio noch generiert wird. Das CLI-Flag --transcript macht hinter den Kulissen genau das.
Warum das wichtig ist: SentencePieceDecoder baut auf dem gemeinsamen Protobuf-Reader AudioCommon.SentencePieceModel auf, sodass PersonaPlex, OmnilingualASR und jedes künftige SentencePiece-basierte Modell über dieselbe Tokenizer-Implementierung dekodieren. Siehe die SentencePieceModel-Referenz.
System-Prompts
Gib einen beliebigen benutzerdefinierten System-Prompt als reinen String weiter — keine externe Tokenisierung nötig:
let response = model.respond(
userAudio: audio,
voice: .NATM0,
systemPrompt: "You enjoy having a good conversation."
)
Oder verwende eine eingebaute Voreinstellung:
assistant— Allzweck-Assistent (Standard)focused— Prägnante, direkte Antwortencustomer-service— Höflicher, lösungsorientierter Support-Agentteacher— Geduldiger, erklärender Lehrstil
CLI-Verwendung
Erzeuge eine gesprochene Antwort aus einer Audioeingabe:
# 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
Optionen
| Option | Beschreibung |
|---|---|
--input | Eingabe-Audiodatei (WAV, erforderlich) |
--voice | Name der Stimmvoreinstellung (z. B. NATM0, VARF2) |
--system-prompt | System-Prompt-Voreinstellung: assistant, focused, customer-service, teacher |
--system-prompt-text | Benutzerdefinierter System-Prompt-Text (überschreibt --system-prompt) |
--max-steps | Maximale Generierungsschritte |
--stream | Gibt Audio-Chunks während der Generierung aus |
--compile | Verwendet MLX-kompilierte Inferenz für schnellere Generierung |
--transcript | Gibt das Text-Transkript neben dem Audio aus |
--json | JSON-Ausgabe mit Metadaten |
Sampling-Parameter können ebenfalls überschrieben werden:
| Option | Standard | Beschreibung |
|---|---|---|
--audio-temp | 0,8 | Sampling-Temperatur für Audio-Tokens |
--audio-top-k | 250 | Top-K-Sampling für Audio-Tokens |
--text-temp | 0,7 | Sampling-Temperatur für Text-Tokens |
--text-top-k | 25 | Top-K-Sampling für Text-Tokens |
Streaming
Das Flag --stream aktiviert Echtzeit-Audio-Ausgabe. Audio-Chunks werden ausgegeben, sobald sie generiert werden, sodass die Wiedergabe beginnen kann, bevor die vollständige Antwort fertig ist. Das ist besonders nützlich für interaktive Anwendungen, bei denen niedrige Latenz zählt.
Leistung
| Metrik | Wert |
|---|---|
| Echtzeitfaktor (RTF) | ~1,4 (8-Bit, nahe Echtzeit) |
| Schritt-Latenz | ~112 ms/Schritt auf M2 Max (8-Bit) |
| Modellgröße (8-Bit) | ~9,1 GB |
| Spitzen-RAM (8-Bit) | ~11 GB |
| Modellgröße (4-Bit) | ~4,9 GB |
| Spitzen-RAM (4-Bit) | ~7 GB |
PersonaPlex 7B (8-Bit) benötigt mindestens 24 GB RAM. Die 4-Bit-Variante passt auf 16-GB-Geräte, erzeugt jedoch verschlechterte Ausgabe. Auf 8-GB-Geräten passt keine der beiden Varianten. Verwende --compile für die beste Leistung auf unterstützter Hardware.
Modellvarianten
| Modell | Größe | HuggingFace |
|---|---|---|
| PersonaPlex-7B (8-Bit) empfohlen | 9,1 GB | aufklarer/PersonaPlex-7B-MLX-8bit |
| PersonaPlex-7B (4-Bit) | 4,9 GB | aufklarer/PersonaPlex-7B-MLX-4bit |
Swift-API
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"))