Konuşmadan konuşmaya modeller
Soniqo, konuşmadan konuşmaya diyalog için iki native MLX model ailesini destekler: PersonaPlex 7B ve VoiceChat 11B. İkisi de konuşmayı alıp model sesini doğrudan üretir, ancak duplex mimarileri ve runtime sözleşmeleri farklıdır.
Model seçin
| Model | Diyalog modeli | En uygun kullanım |
|---|---|---|
| PersonaPlex 7B | Moshi, Depformer ve Mimi ile eşzamanlı full duplex | Dinleme ve konuşmanın örtüşmesi, seçilebilir 18 ses |
| VoiceChat 11B | FastConformer, Nemotron-H, EAR-TTS ve neural codec ile sürekli frame-synchronous duplex | 80 ms streaming frame'leri, metin/işlev event'leri ve checkpoint-native konuşma |
Bunlar konuşmadan konuşmaya diyalog modelleridir. Hibiki de konuşmayı doğrudan konuşmaya dönüştürür; ancak görevi streaming konuşma çevirisidir ve ayrı belgelenir.
PersonaPlex 7B
Moshi mimarisine (Kyutai) dayanan çift yönlü speech-to-speech diyalog modeli. PersonaPlex 7B, konuşulan girdiden doğrudan konuşulan yanıtlar üretir — ara metin pipeline'ı gerekmez. Model 18 ses preset'i ile birlikte gelir ve 8-bit (önerilen) ile 4-bit niceleme olarak sunulur. Varsayılan 8-bit'tir — %30 daha hızlıdır ve tutarlı yanıtlar üretir; 4-bit ise çıktı kalitesini düşürür.
VoiceChat 11B
Duplex speech-to-speech referansı: SALM-Duplex: Efficient and Direct Duplex Modeling for Speech-to-Speech Language Model (Interspeech 2025); NVIDIA'nın upstream VoiceChat model kartında atıf yapılır.
M5 Pro, 48 GB, Release, 80 ms canlı ritim, korumalı head INT5: üç kontrollü çalıştırma tüm pipeline RTF'sini 0.94, 0.92 ve 0.92; tepe RSS'yi yaklaşık 8.70 GB ölçtü. İlk konuşulan metin 44.3–46.7 ms, ilk oynatılabilir ses 74.0–76.4 ms içinde geldi. Bunlar ısınmış hesaplama değerleridir, öğrenilmiş sıra alma gecikmesi değildir; optimize INT8 performansı henüz yeniden ölçülmedi.
VoiceChat, speech-swift'teki diğer native MLX konuşmadan-konuşmaya runtime'ıdır. Nedensel FastConformer algı, Nemotron-H duplex metin/işlev kanalları, bağımsız metin koşullu EAR-TTS ve 22,05 kHz nöral codec'i birleştirir. Session sürekli 16 kHz mono ses alır ve her 80 ms'de metin olaylarıyla 1.764 örneklik bir çıkış frame'i döndürür.
VoiceChatModel.load(from:) ile yükleyin, bir VoiceChatSession başlatın ve sesi pushAudio ile verin. Eksiksiz bundle encoder/, llm/ ve tts/ içermelidir; eski yalnızca-anlama bundle'ları reddedilir.
INT5, test edilen M5 Pro'da RTF 1'in altında toplam throughput sürdürür. Üç çalıştırmanın tamamında toplam/frame p95 76.2–78.6 ms ile 80 ms'nin altında kaldı; yine de deadline payı dardır. Modelin konuşma başlangıcı ile donanım hesaplama gecikmesini ayrı ölçün.
PersonaPlex mimarisi ve kullanımı
PersonaPlex, üç temel bileşene sahip çok akışlı otoregresif bir modeldir:
| Bileşen | Detaylar |
|---|---|
| Temporal Transformer | 32 katman, dim=4096, 32 head, SwiGLU (hidden_scale=4.125), RoPE, 8-bit nicelenmiş (varsayılan) |
| Depformer | 6 katman, dim=1024, 16 head, MultiLinear (weights_per_step=true), dep_q=16 |
| Mimi Codec | 16 codebook, 12,5 Hz frame oranı, 24 kHz ses çıktısı |
Model aynı anda 17 akış işler: 1 metin akışı + 8 kullanıcı ses akışı + 8 ajan ses akışı. Bu mimari, modelin aynı anda dinleyip konuşabildiği çift yönlü konuşmayı mümkün kılar.
Ses preset'leri
PersonaPlex, doğal ve çeşitli stillerde 18 yerleşik ses preset'i içerir:
| Kategori | Preset'ler |
|---|---|
| Doğal Kadın | NATF0, NATF1, NATF2, NATF3 |
| Doğal Erkek | NATM0, NATM1, NATM2, NATM3 |
| Çeşitli Kadın | VARF0, VARF1, VARF2, VARF3, VARF4 |
| Çeşitli Erkek | VARM0, VARM1, VARM2, VARM3, VARM4 |
İç monolog
PersonaPlex her adımda iki paralel akış üretir: Mimi codec için 8 audio codebook token'ı ve modelin iç monoloğu için bir metin token'ı. Metin akışı, modelin konuşurken “düşündüğü” şeydir — nihai sesten hafifçe sapabilir ama pratikte konuşulan yanıtı, canlı bir transkript olarak kullanmaya yetecek kadar yakından yansıtır.
Metin token'ları ham SentencePiece piece ID'leri olarak geri döner. Onları PersonaPlex'in sunduğu SentencePieceDecoder ile çözün:
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
Streaming modunda respondStream, textTokens chunk'larını üretildikçe yayar — ses hâlâ üretilmekteyken bir canlı altyazı görünümünü sürmek için bunları artımlı olarak çözün. --transcript CLI bayrağı tam olarak bunu perde arkasında yapar.
Neden önemli: SentencePieceDecoder, paylaşılan AudioCommon.SentencePieceModel protobuf okuyucusu üzerine inşa edilmiştir; bu nedenle PersonaPlex, OmnilingualASR ve gelecekteki tüm SentencePiece tabanlı modeller aynı tokenizer uygulaması üzerinden çözer. SentencePieceModel referansına bakın.
System prompt'ları
Herhangi bir özel system prompt'u düz bir string olarak iletin — harici tokenize gerekmez:
let response = model.respond(
userAudio: audio,
voice: .NATM0,
systemPrompt: "You enjoy having a good conversation."
)
Veya yerleşik bir preset kullanın:
assistant— Genel amaçlı yardımcı asistan (varsayılan)focused— Kısa ve net yanıtlarcustomer-service— Nazik, çözüm odaklı destek ajanıteacher— Sabırlı, açıklayıcı öğretim tarzı
CLI kullanımı
Bir ses girdisinden konuşulan yanıt üretin:
# 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
Seçenekler
| Seçenek | Açıklama |
|---|---|
--input | Giriş ses dosyası (WAV, gerekli) |
--voice | Ses preset adı (örn. NATM0, VARF2) |
--system-prompt | System prompt preset'i: assistant, focused, customer-service, teacher |
--system-prompt-text | Özel system prompt metni (--system-prompt'u geçersiz kılar) |
--max-steps | Maksimum üretim adımı |
--stream | Üretim sırasında ses chunk'larını yay |
--compile | Daha hızlı üretim için MLX derlenmiş çıkarımı kullan |
--transcript | Sesle birlikte metin transkriptini çıkar |
--json | Metadata ile JSON çıktısı |
Örnekleme parametreleri de geçersiz kılınabilir:
| Seçenek | Varsayılan | Açıklama |
|---|---|---|
--audio-temp | 0.8 | Ses token örnekleme sıcaklığı |
--audio-top-k | 250 | Ses token top-k örnekleme |
--text-temp | 0.7 | Metin token örnekleme sıcaklığı |
--text-top-k | 25 | Metin token top-k örnekleme |
Streaming
--stream bayrağı gerçek zamanlı ses çıktısını etkinleştirir. Ses chunk'ları üretildikçe yayılır; böylece tam yanıt tamamlanmadan önce çalma başlayabilir. Bu, düşük gecikmenin önemli olduğu etkileşimli uygulamalar için özellikle yararlıdır.
Performans
| Metrik | Değer |
|---|---|
| Gerçek zaman katsayısı (RTF) | ~1,4 (8-bit, gerçek zamana yakın) |
| Adım gecikmesi | M2 Max'ta ~112 ms/adım (8-bit) |
| Model boyutu (8-bit) | ~9,1 GB |
| Tepe RAM (8-bit) | ~11 GB |
| Model boyutu (4-bit) | ~4,9 GB |
| Tepe RAM (4-bit) | ~7 GB |
PersonaPlex 7B (8-bit) en az 24 GB RAM gerektirir. 4-bit varyant 16 GB cihazlara sığar ancak düşük kaliteli çıktı üretir. 8 GB cihazlarda hiçbir varyant sığmaz. Desteklenen donanımda en iyi performans için --compile kullanın.
Model varyantları
| Model | Boyut | HuggingFace |
|---|---|---|
| PersonaPlex-7B (8-bit) önerilen | 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"))