VoiceChat टूल कॉल और प्रदर्शन की नवीनतम जानकारी के लिए अंग्रेज़ी संस्करण देखें।
स्पीच-टू-स्पीच मॉडल
Soniqo conversational speech-to-speech के लिए दो native MLX model families support करता है: PersonaPlex 7B और VoiceChat 11B। दोनों speech लेते हैं और model audio सीधे generate करते हैं, लेकिन उनकी duplex architecture और runtime contracts अलग हैं।
मॉडल चुनें
| मॉडल | Conversation model | सबसे उपयुक्त |
|---|---|---|
| PersonaPlex 7B | Moshi, Depformer और Mimi के साथ simultaneous full duplex | एक साथ सुनना/बोलना और 18 selectable voices |
| VoiceChat 11B | FastConformer, Nemotron-H, EAR-TTS और neural codec के साथ continuous frame-synchronous duplex | 80 ms streaming frames, text/function events और checkpoint-native speech |
ये conversational speech-to-speech models हैं। Hibiki भी speech को सीधे speech में बदलता है, लेकिन उसका काम streaming speech translation है, इसलिए उसका documentation अलग है।
PersonaPlex 7B
Moshi आर्किटेक्चर (Kyutai) पर आधारित Full-duplex speech-to-speech dialogue मॉडल। PersonaPlex 7B सीधे बोले गए input से बोले गए responses उत्पन्न करता है — कोई intermediate text pipeline आवश्यक नहीं। मॉडल 18 voice presets के साथ आता है और 8-bit (अनुशंसित) और 4-bit क्वांटिज़ेशन में उपलब्ध है। 8-bit डिफ़ॉल्ट है — यह 30% तेज़ है और coherent responses उत्पन्न करता है, जबकि 4-bit output गुणवत्ता को degrade करता है।
VoiceChat 11B
Duplex speech-to-speech reference: SALM-Duplex: Efficient and Direct Duplex Modeling for Speech-to-Speech Language Model (Interspeech 2025), जिसे NVIDIA के upstream VoiceChat model card में cite किया गया है।
M5 Pro, 48 GB, Release, 80 ms live cadence, protected-head INT5: तीन controlled runs में whole-pipeline RTF 0.94, 0.92 और 0.92 था, और peak RSS लगभग 8.70 GB था। पहला spoken text 44.3–46.7 ms में और पहला playable audio 74.0–76.4 ms में मिला। ये warm compute आंकड़े हैं, सीखी हुई turn-taking latency नहीं; optimized INT8 performance को अभी दोबारा नहीं मापा गया है।
VoiceChat speech-swift का दूसरा native MLX speech-to-speech runtime है। यह causal FastConformer perception, Nemotron-H duplex text/function channels, स्वतंत्र text-conditioned EAR-TTS और 22.05 kHz neural codec को जोड़ता है। session लगातार 16 kHz mono audio लेता है और हर 80 ms में text events तथा 1,764-sample output frame देता है।
VoiceChatModel.load(from:) से load करें, VoiceChatSession शुरू करें और pushAudio से audio दें। पूरे bundle में encoder/, llm/ और tts/ होना चाहिए; पुराने understanding-only bundles अस्वीकार होते हैं।
INT5 परीक्षित M5 Pro पर RTF 1 से कम aggregate throughput बनाए रखता है। तीनों runs में total/frame p95 भी 76.2–78.6 ms के बीच और 80 ms से कम रहा; इसलिए deadline headroom अभी कम है। model turn onset और hardware compute latency को अलग मापें।
लाइव VoiceChat CLI
NVIDIA Nemotron VoiceChat 11B पर आधारित पूरे protected-head INT5 bundle से Soniqo के साथ लाइव बातचीत करें। Apple AEC के लिए कमांड capture और playback को एक AVAudioEngine में रखता है, bundle के RNN-T user captions को stream करता है और सुनते हुए 22.05 kHz model audio चलाता है।
डिफ़ॉल्ट Soniqo prompt क्षमता की सीमा स्पष्ट करता है: यह CLI बातचीत और सवालों के जवाब दे सकता है, लेकिन calendar, reminder, app, account, device या external service तक पहुँच नहीं रखता। ऐसे अनुरोध पर Soniqo साफ बताता है कि वह action नहीं कर सकता, ऐसी confirmation नहीं माँगता जिसे पूरा न कर सके, और संक्षेप में बताता है कि user स्वयं क्या कर सकता है।
speech voice-chat
speech voice-chat --input question.wav --output response.wav
speech voice-chat \\
--mcp-config Examples/VoiceChatMCP/apple-reminders.json
कॉन्फ़िगर किए जा सकने वाले MCP टूल
बंडल किया गया apple-reminders-eventkit अडैप्टर अब मॉडल को केवल list_reminders, create_reminder और update_reminder दिखाता है। सूची खोज अडैप्टर के भीतर निजी रहती है। अपडेट के लिए उपयोगकर्ता रिमाइंडर का नाम बोलता है और रनटाइम उसे विश्वसनीय निजी EventKit ID में बदलता है; यह ID मॉडल को दिखने वाले परिणाम में कभी नहीं जाती। रिमाइंडर और उसकी नियत तारीख एक ही EventKit save में लिखे जाते हैं। पहले server startup को कम-से-कम 60 सेकंड और सामान्य tool call को डिफ़ॉल्ट 15 सेकंड मिलते हैं।
MCP केवल --mcp-config देने पर सक्रिय होता है। provider-neutral JSON किसी भी stdio MCP server को शुरू कर सकता है और enabledTools से अधिकतम पाँच टूल स्पष्ट रूप से चुनता है। readOnlyTools में न दिए गए हर टूल को write माना जाता है। डिफ़ॉल्ट नीति confirm है: पहली call रोकी जाती है; Soniqo की deterministic पुष्टि समझे गए arguments दोहराती है और साफ़ बताती है कि अभी कुछ नहीं बदला। उपयोगकर्ता की नई सकारात्मक पुष्टि पर ही वह केवल एक बार चलती है। नई user speech के बिना वही call दोबारा नहीं चल सकती, allow में भी नहीं। deny तथा स्पष्ट session अनुमति allow भी उपलब्ध हैं। वास्तविक परिणाम model के function channel से लौटता है और सफलता के लिए ok response आवश्यक है।
पुष्टि से पहले write arguments को user transcript से जाँचा जाता है। Relative dates वर्तमान local date से निकाली जाती हैं; गढ़े हुए list names, पुराने dates, priorities या दूसरे अपुष्ट values कभी execute नहीं होते। नया RNN-T speech और उसके बाद end-of-utterance transcript reset के बाद भी पुष्टि को resolve करता है। Soniqo सफलता तभी बोलता है जब MCP server वास्तव में ok: true लौटाए; अन्यथा वह बताता है कि execution की पुष्टि नहीं हुई।
“मेरे कौन से रिमाइंडर हैं?” अब सभी EventKit सूचियों पर एक ही समतल list_reminders कॉल करता है। सूची, नियत समय, पूर्ण स्थिति और केवल रनटाइम के लिए स्थिर ID cache होते हैं, इसलिए विवरण और सुरक्षित अपडेट के लिए हर सूची दोबारा नहीं पढ़नी पड़ती। डैशबोर्ड function decoding का समय, token steps और token/s ऑडियो RTF से अलग दिखाता है; RTF केवल सामने चल रहे 80 ms ऑडियो फ्रेम मापता है।
बोली गई पुष्टि पूछती है कि उपयोगकर्ता “आगे बढ़ना” चाहता है या नहीं और जानबूझकर सभी affirmative allow-list phrases से बचती है, ताकि playback echo pending action को authorize न कर सके।
Child MCP server केवल PATH, HOME, temporary-directory और locale variables inherit करते हैं। Credentials को server के env map में स्पष्ट रूप से देना होगा; parent process के अन्य secrets आगे नहीं भेजे जाते।
8-bit function projection लगभग 518 MB है। सामान्य speech के दौरान VoiceChat केवल cache किया हुआ 36 KB PAD/tool-start probe चलाता है। पूरी 131,072-row head तभी चलती है जब tool-start पहले PAD से आगे हो, फिर global argmax सत्यापित करती है और खुले JSON call के बनते समय सक्रिय रहती है। MCP result ज्ञात होने पर VoiceChat उसे सीमित 16-token causal-prefill chunks में replay करता है। इससे trained function feedback और language/speech cache state सुरक्षित रहती है और हर result token के लिए अलग 11B decode नहीं करना पड़ता। इससे tool-start निर्णयों को कमजोर किए बिना MCP conversation realtime रहती है।
Playback से पहले डिफ़ॉल्ट रूप से तीन 80 ms frames (240 ms) buffer होते हैं। Gap के बाद playback आठ-frame recovery buffer की प्रतीक्षा करता है। Inference तीन frames पीछे होने पर voice refinement अस्थायी रूप से आठ से चार steps हो जाता है। Queue फिर भी आठ frames (640 ms) तक पहुँचे तो नए input के लिए केवल न्यूनतम आवश्यक पुराना audio हटता है। लगातार overload को एक recovery episode माना जाता है और RNN-T द्वारा पहले से confirmed user turn बार-बार reset होकर मिटता नहीं है। छूटे शब्द चिह्नित रहते हैं और उन्हें दोहराना पड़ सकता है।
Metrics सीधे user experience बताते हैं: behind 0.3 s प्रतीक्षा करता microphone audio है, RTF 0.93× compute time ÷ audio time है (1 से कम साथ चलता है, 1 से अधिक पीछे रहता है), और last 74 ms for 80 ms audio आखिरी compute समय की तुलना हर model frame के 80 ms audio से करता है। Rolling average पिछले 120 microphone callbacks पर आधारित है; replay events अतिरिक्त audio time नहीं गिने जाते।
Microphone mode डिफ़ॉल्ट रूप से NVIDIA-style RNN-T turn-taking उपयोग करता है। Model के learned BOS/EOS निर्णय सामान्य low-latency path बने रहते हैं। हर 80 ms frame की पहली prediction को blank या non-blank माना जाता है; user speech confirm होने के बाद 40 लगातार blank frames (3.2 s) केवल response शुरू करने का safety fallback हैं, और 40 नए non-blank frames matching barge-in fallback देते हैं। Soniqo के बोलना शुरू करते ही speech counter reset होता है, इसलिए पूरा हो चुका user turn response को तुरंत नहीं काट सकता। सभी audio frames duplex model तक लगातार पहुँचते हैं; इन fallbacks को बंद करके BOS/EOS केवल learned language head पर छोड़ने के लिए --no-rnnt-turn-taking उपयोग करें। Dashboard RNN-T barge-ins और speaker gaps को अलग दिखाता है।
सामान्य mode में user speech confirm होने तक model-native BOS दबा रहता है, इसलिए Soniqo पहले नहीं बोलती। --greet शुरुआती greeting को स्पष्ट रूप से अनुमति देता है। सुनाई देने वाले उत्तर के बाद blank PAD कम-से-कम 16 frame या हर content token पर तीन frame, जो भी अधिक हो, खुले turn में रहता है। इस budget के बाद पहला blank PAD logical turn बंद करता है। Content के अनुसार बढ़ने वाली यह tail उन देर से बने शब्दों को बचाती है जिन्हें 1.28-second की fixed cutoff mute कर सकती है।
Interactive mode terminal की alternate screen पर एक स्थिर dashboard उपयोग करता है, इसलिए status updates scrollback भरने के बजाय वहीं redraw होते हैं। Append-only output के लिए --plain उपयोग करें।
स्थानीय निदान के लिए --debug-timeline हर user और Soniqo वाक्य को timestamp देता है और parsed native call arguments, MCP start/completion तथा result-cache synchronization को उसी timeline में जोड़ता है। यह अंतिम सुनाई देने वाली generated-PCM window पर pronunciation ended भी दिखाता है; यह model-output समय है, speaker-device completion नहीं। Demo पुराने phase-timing blocks नहीं दिखाता; native decode, provider, cache और microphone pressure की विस्तृत metrics voicechat-bench JSON में रहती हैं। इससे tool arguments दिख सकते हैं, इसलिए shared logs में इसका उपयोग न करें। Native decode और provider wait के बीच phase timer reset होता है।
Live session स्थिर 37-frame speaker prompt और हाल का 20 सेकंड EAR-TTS इतिहास रखता है; semantic conversation state Nemotron-H अलग से रखता है। Content-scaled acoustic tail के भीतर PAD सामान्य रूप से render होता है; केवल उसके बाद का silent PAD आठ-आठ के batch में causal रूप से आगे बढ़ता है। इससे बोला गया उत्तर कटता नहीं है और TTS attention तथा idle काम भी बिना सीमा नहीं बढ़ते। --live-speech-context-seconds 0 पूरा TTS इतिहास वापस देता है और file mode डिफ़ॉल्ट रूप से exact full-history रहता है।
M5 Pro पर सुरक्षित acoustic tail वाले 63.6-second profile में live path ने aggregate RTF 0.87, final-window RTF 0.71, final-window synthesis 4.1 ms/frame, peak RSS 8.72 GB और peak physical footprint 23.67 GB मापे। आठ-step speech-active windows RTF 1.05 और 1.12 तक पहुँचीं, इसलिए input queue होने पर interactive CLI अभी भी reversible two-step fallback और one-step emergency mode इस्तेमाल करता है। Sequential और batched idle-cache state की minimum cosine similarity 0.9999999 थी।
voicechat-bench onset-pop detector generated lead-in और sustained speech के पहले 50 ms को जाँचता है। यह केवल 0.05 amplitude और steady-speech p99 baseline के छह गुने से बड़े sample jump को flag करता है; scenario maximum_suspect_onset_transients को zero रखकर regression रोक सकता है।
M5 Pro 48 GB पर तीन Release runs में RTF 0.92, total-frame p95 74.8–75.8 ms, पहला playable audio 74.2–74.9 ms और लगभग 8.74 GB peak RSS मापा गया। Transcript और reply तीनों runs में समान थे।
PersonaPlex आर्किटेक्चर और उपयोग
PersonaPlex तीन core कॉम्पोनेंट वाला multi-stream autoregressive मॉडल है:
| कॉम्पोनेंट | विवरण |
|---|---|
| Temporal Transformer | 32 layers, dim=4096, 32 heads, SwiGLU (hidden_scale=4.125), RoPE, 8-bit क्वांटाइज़्ड (डिफ़ॉल्ट) |
| Depformer | 6 layers, dim=1024, 16 heads, MultiLinear (weights_per_step=true), dep_q=16 |
| Mimi Codec | 16 codebooks, 12.5 Hz frame rate, 24 kHz ऑडियो आउटपुट |
मॉडल एक साथ 17 streams प्रोसेस करता है: 1 text stream + 8 user audio streams + 8 agent audio streams। यह आर्किटेक्चर full-duplex conversation सक्षम करती है जहाँ मॉडल एक साथ सुन और बोल सकता है।
Voice Presets
PersonaPlex में natural और varied styles में 18 बिल्ट-इन voice presets शामिल हैं:
| श्रेणी | Presets |
|---|---|
| Natural Female | NATF0, NATF1, NATF2, NATF3 |
| Natural Male | NATM0, NATM1, NATM2, NATM3 |
| Varied Female | VARF0, VARF1, VARF2, VARF3, VARF4 |
| Varied Male | VARM0, VARM1, VARM2, VARM3, VARM4 |
Inner Monologue
PersonaPlex प्रत्येक चरण पर दो parallel streams उत्पन्न करता है: Mimi codec के लिए 8 audio codebook tokens और मॉडल के आंतरिक monologue के लिए एक text token। Text stream वह है जो मॉडल बोलते समय "सोच रहा है" — यह अंतिम ऑडियो से थोड़ा diverge हो सकता है, लेकिन व्यवहार में यह spoken response को live transcript के रूप में उपयोग करने के लिए पर्याप्त रूप से closely mirror करता है।
Text tokens raw SentencePiece piece IDs के रूप में वापस आते हैं। उन्हें SentencePieceDecoder के साथ decode करें जो PersonaPlex ship करता है:
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 mode में, respondStream textTokens chunks उत्पन्न होने के साथ उत्सर्जित करता है — ऑडियो अभी भी generate हो रहा होता है तब एक live caption view को drive करने के लिए उन्हें incrementally decode करें। --transcript CLI flag ठीक यही व्यवहार पर्दे के पीछे करता है।
यह क्यों मायने रखता है: SentencePieceDecoder shared AudioCommon.SentencePieceModel protobuf reader पर बना है, इसलिए PersonaPlex, OmnilingualASR और कोई भी भविष्य का SentencePiece-आधारित मॉडल उसी tokenizer कार्यान्वयन के माध्यम से decode करता है। SentencePieceModel reference देखें।
System Prompts
किसी भी custom system prompt को एक plain string के रूप में pass करें — कोई external tokenization आवश्यक नहीं:
let response = model.respond(
userAudio: audio,
voice: .NATM0,
systemPrompt: "You enjoy having a good conversation."
)
या एक बिल्ट-इन preset का उपयोग करें:
assistant— सामान्य-उद्देश्य helpful assistant (डिफ़ॉल्ट)focused— Concise, direct responsescustomer-service— विनम्र, समाधान-उन्मुख support एजेंटteacher— धैर्यवान, explanatory teaching style
CLI उपयोग
एक ऑडियो input से एक spoken response उत्पन्न करें:
# 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
विकल्प
| विकल्प | विवरण |
|---|---|
--input | Input ऑडियो फ़ाइल (WAV, आवश्यक) |
--voice | Voice preset नाम (जैसे, NATM0, VARF2) |
--system-prompt | System prompt preset: assistant, focused, customer-service, teacher |
--system-prompt-text | Custom system prompt text (--system-prompt को override करता है) |
--max-steps | अधिकतम generation steps |
--stream | Generation के दौरान ऑडियो chunks उत्सर्जित करें |
--compile | तेज़ generation के लिए MLX compiled inference का उपयोग करें |
--transcript | ऑडियो के साथ text transcript output करें |
--json | मेटाडेटा के साथ JSON आउटपुट |
Sampling पैरामीटर भी override किए जा सकते हैं:
| विकल्प | डिफ़ॉल्ट | विवरण |
|---|---|---|
--audio-temp | 0.8 | Audio token sampling temperature |
--audio-top-k | 250 | Audio token top-k sampling |
--text-temp | 0.7 | Text token sampling temperature |
--text-top-k | 25 | Text token top-k sampling |
Streaming
--stream flag रियल-टाइम ऑडियो आउटपुट सक्षम करता है। ऑडियो chunks उत्पन्न होने के साथ उत्सर्जित होते हैं, इसलिए playback पूर्ण response पूरा होने से पहले शुरू हो सकता है। यह विशेष रूप से interactive applications के लिए उपयोगी है जहाँ low latency मायने रखता है।
परफ़ॉर्मेंस
| मेट्रिक | मान |
|---|---|
| Real-time factor (RTF) | ~1.4 (8-bit, near real-time) |
| Step latency | M2 Max पर ~112 ms/step (8-bit) |
| मॉडल आकार (8-bit) | ~9.1 GB |
| Peak RAM (8-bit) | ~11 GB |
| मॉडल आकार (4-bit) | ~4.9 GB |
| Peak RAM (4-bit) | ~7 GB |
PersonaPlex 7B (8-bit) को कम से कम 24 GB RAM की आवश्यकता है। 4-bit वेरिएंट 16 GB डिवाइस पर फिट होता है लेकिन degraded output उत्पन्न करता है। 8 GB डिवाइस पर, कोई भी वेरिएंट फिट नहीं होगा। समर्थित हार्डवेयर पर सर्वश्रेष्ठ परफ़ॉर्मेंस के लिए --compile का उपयोग करें।
मॉडल वेरिएंट
| मॉडल | आकार | HuggingFace |
|---|---|---|
| PersonaPlex-7B (8-bit) अनुशंसित | 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"))