Traduzione automatica · Originale inglese

Modelli di Speech-to-Speech

Soniqo supporta due famiglie di modelli MLX native per la conversazione-speech: PersonaPlex 7 e VoiceChat 11. Entrambi consumano il discorso e generano l'audio del modello direttamente, ma utilizzano diverse architetture duplex e contratti di runtime.

Scegli un modello

ModelloModello di conversazioneVestibilità migliore
PersonaPlex 7Duplex completo simultaneo con Moshi, Depformer e MimiOverlapping comportamento di ascolto/speak e 18 voci selezionabili
VoiceChat 11Duplex continuo, frame-synchronous con FastConformer, Nemotron-H, EAR-TTS e un codec neurale80 ms frame di streaming, eventi di testo / funzione, e discorso di checkpoint-native

Hibiki mappa anche il discorso direttamente al discorso, ma il suo compito è lo streaming della traduzione vocale, quindi è documentato separatamente.

PersonaPlex 7

Modello di dialogo vocale-speech completo basato sul Moshi architettura (Kyutai). PersonaPlex 7B genera risposte parlate direttamente da input parlati — non è necessario alcun processo di testo intermedio. 18 preset vocali ed è disponibile in 8-bit (consigliato) e 4- Quantizzazione a bit. 8-bit è il default — è 30% più veloce e produce risposte coerenti, mentre 4-bit degrada la qualità dell'output.

VoiceChat 11

Riferimento duplex-speech: SALM-Duplex: Modellazione duplex efficiente e diretta per il modello di linguaggio vocale (Interspeech) 2025), citata da NVIDIA'a monte VoiceChat scheda modello.

M5 Pro, 48 GB, Rilasciare, 80 ms cadenza live, testa protetta INT5: tre circuiti controllati misurati intera pipelina RTF 0.94, 0.92e 0.92con circa 8.70 GB picco RSS. Primo testo parlato arrivato in 44.3–46.7 ms e primo audio riproducibile in 74.0–76.4 ms. Quelle sono figure di calcolo caldo, non imparato latenza di turni; ottimizzato INT8 le prestazioni non sono ancora state rassicurate.

VoiceChat è l'altro nativo MLX tempo di esecuzione del discorso-a-speech in speech-swift. Combina la percezione causale di FastConformer, i canali di testo/funzione duplex Nemotron-H, il testo autonomo EAR-TTS, e un 22.05 kHz codice neurale. Una sessione accetta 16 kHz mono audio continuamente e restituisce eventi di testo più uno 1,764- cornice di uscita del campione ogni 80 Signora.

Uso VoiceChatModel.load(from:)# Avvicinati # VoiceChatSession, e l'audio di alimentazione pushAudio. Un pacchetto completo deve contenere encoder/, llm/e tts/; i fasci di comprensione più vecchi sono respinti.

Prestazioni attuali

INT5 sostiene il throughput aggregato qui sotto RTF 1 sul testato M5 Pro. Tutte e tre le piste hanno anche tenuto totale/frame p95 Di seguito 80 ms, a 76.2–78.6 ms; la camera di testa di scadenza rimane quindi stretta. modello di treat accendere il set e la latenza di calcolo hardware come misurazioni separate.

Live VoiceChat CLI

Parla con Soniqo utilizzando la testata completa protetta INT5 fascio, alimentato da NVIDIA Nemotron VoiceChat 11B. Il comando mantiene la cattura e la riproduzione su un AVAudioEngine per Apple AEC, trasmette le didascalie dell'utente RNN-T del bundle e gioca 22.05 kHz modello audio mentre continua ad ascoltare.

Il prompt predefinito Soniqo è basato sulla capacità: questo CLI può conversare e rispondere a domande, ma non può accedere a calendari, promemoria, app, account, dispositivi o servizi esterni. Per tali richieste Soniqo dice chiaramente che non può eseguire l'azione, non chiede una conferma che non può soddisfare, e suggerisce brevemente ciò che l'utente può fare invece.

speech voice-chat

speech voice-chat --input question.wav --output response.wav

Strumenti di configurazione MCP

MCP è disabilitato a meno che --mcp-config Il file provider-neutral JSON può lanciare qualsiasi server stdio MCP e sceglie esplicitamente quali strumenti scoperti raggiungono VoiceChat. L'esempio deliberatamente stretto di Apple Reminders espone l'elenco, crea e aggiorna i flussi di lavoro; configurazioni personalizzate possono abilitare altri strumenti del server:

speech voice-chat \
  --mcp-config Examples/VoiceChatMCP/apple-reminders.json

L'esempio in bundle indica un fornitore di EventKit-backed dietro un apple-reminders-eventkit adattatore. VoiceChat espone solo la canonica list_reminders, create_remindere update_reminder operazioni, non cancellate dal fornitore, la modifica dell'elenco, il calendario o le azioni di subtask. La scoperta dell'elenco rimane privata dell'adattatore. Un promemoria e la sua data dovuta sono commessi in un unico salvataggio di EventKit, evitando l'ex guasto di scrittura parziale che potrebbe lasciare un promemorie non datato dietro. Il fornitore può compilare il suo piccolo Swift helper al primo utilizzo, quindi l'avvio ha un separato 60- indennità secondaria; le normali chiamate degli strumenti tengono 15- Secondo di default.

Solo enabledTools sono mostrati al modello, con un massimo di cinque per sessione. Gli strumenti sono scritti a meno che la configurazione non li elenca esplicitamente in readOnlyTools. Scrive di default a --mcp-write-policy allow, quindi una chiamata nativa completa esegue immediatamente e il suo vero e proprio risultato del provider guida la risposta; la demo dei promemoria non aggiunge una seconda svolta di conferma. confirm per esplicita conferma del modello o deny per disabilitare le scritture.

Non c'è un router di trascrizione, un matcher di espressione regolare, un estrattore di slot, un promemoria di stato, una riparazione di argomenti, un risolutore di nome parlato o un discorso di assistente scritto. Il checkpoint da solo seleziona lo strumento e gli argomenti. Il coordinatore convalida l'appartenenza di strumento abilitato-tool e i tipi JSON, applica la politica, chiama MCP, e restituisce il successo strutturato o il fallimento attraverso il canale di risposta di funzione addestrato. name per la creazione e lusinga tutti gli elenchi EventKit in uno list_reminders leggi. Presenta gli UUID del fornitore lungo come riferimenti stabili e incerti come r1, quindi risolve un riferimento ritorto modello esatto prima update_reminder esecuzione. Questa è compressione ID senza perdita, non trascrizione o corrispondente intento. I valori mancanti o non validi tornano al modello per una chiarificazione naturale; non sono mai deferiti silenziosamente dalla trascrizione visualizzata.

Una volta aperta una chiamata, il canale di testo forzato-PAD salta il suo inutilizzato 131,072Dopo EOTC, il percorso bifase blocca la lingua condivisa e la timeline EAR-TTS mentre il risultato esterno è in sospeso, abbinando NVIDIAL'involucro di riferimento; le cornici del microfono continuano attraverso la percezione e RNN-T ma non sono inserite come posizioni sintetiche del PAD. 16-token chunks causale-prefill. La sessione produce tra gettoni di chiamata e lotti di risultato, esterno MCP I / O funziona in un compito separato, e la percezione del microfono dal vivo più le didascalie RNN-T rimangono ammissibili in tutto. Retenta la timeline condivisa non più di un vecchio frame semantico per live callback; il frame corrente rimane in coda, l'audio di rigioco trascorso viene disattivato, e le posizioni EAR-TTS si sincronizzano più tardi in funzioni di otto-frame chunks. MCP stato istantanee ogni 160 ms invece di fare diverse chiamate attore dopo ogni fotogramma del microfono. Il cruscotto interattivo segnala la fase attive dello strumento; il benchmark strutturato registra decodifica nativo, MCP viaggio rotondo, sincronizzazione dei risultati, calcolo modello/cache, e live interleave residuo separatamente. conversazione ordinaria e barge-in mantenere NVIDIA 40-frame fallback di sicurezza; un candidato di strumento nativo già proposto può commettere dopo otto frame vuoti.

Su un'idiota M5 Pro con 48 GB, tre frasi promemoria-list nativo hanno raggiunto il discorso post-tool autorizzato dal modello 3.56–4.00 secondi dopo la fine dell'ingresso con un fisso 200 Il nativo JSON ha preso 1.15–1.28 secondi per 27–31 passi; il 67-risultato di token 0.58–0.72 secondi in cinque prefill. Una regressione di aggiornamento focalizzata richiesto 67 passi nativi / 5.25 secondi quando il modello ha ripetuto un realistico EventKit UUID, contro 37 passi / su 2.29 secondi con la soluzione senza perdita r1 riferimento—45% meno passi token e circa 56% meno tempo di decodifica. Un due secondi di stress separato tenuto il microfono di attesa del fornitore lavoro a 19.6 ms p95 e 19.8 ms massimo, così I/O esterno aggiunge ritardo di risposta senza tenere cattura. 118 ms microfono-servizio p95 e 139 ms p95 la latenza al di là del 80 scadenze di ingresso ms; quest'ultimo espone brevi interruzioni di coda di coda di risultato-sync nascoste da primo piano RTF. Il locale EventKit si legge misurato 358 ms dopo una volta MCP avvio. Una frase di creazione testata è stata trascritta correttamente, ma il discorso ordinario selezionato piuttosto che una chiamata nativo; questo rimane la qualità dello strumento-selezione, non un router runtime nascosto.

Il confine concorrenziale è la cache condivisa di Nemotron-H KV: il discorso comune con il risultato condizionato non può formare un secondo futuro causale indipendente mentre i token della funzione sono generati o riprodotti. Soniqo riprende un discorso coerente e auto-modello dopo <SPECIAL_22> chiude la risposta dello strumento.

I server di Child MCP ereditano solo PATH, HOME, temporaneamente-direttivo e variabili locali. Le credenziali devono essere trasmesse esplicitamente nel server. env mappa; non vengono inoltrati segreti relativi al processo genitore. Il comando configurato viene eseguito localmente con il filesystem e le autorizzazioni applicative dell'utente corrente, quindi utilizzare solo i file di configurazione e i pacchetti server di fiducia MCP.

Il 8- la proiezione della funzione del bit è circa 518 MB. Durante il discorso ordinario, VoiceChat valuta solo una cache 36 KB PAD/tool-start sonda. Se l'iniziatore vince prima del limite di turno, solo la sua 4,096-valore candidato allo stato nascosto viene mantenuto; la verifica a pieno carico viene eseguita quando viene appreso BOS o l'ultimo punto di sicurezza RNN-T scade. Per una chiamata generica nativo, chiamata verificata JSON poi corre a piena velocità del modello di lingua su una percezione che incorpora cache da un secondo di silenzio invece di una volta per volta per 80 cornice microfono ms. Una volta MCP il risultato è noto, VoiceChat rigiocarlo in rilegato 16-token blocchi causali-preriempire, mantenendo il feedback funzione addestrato e lo stato cache lingua/spaech senza uno 11B decodifica per risultato token. La sessione produce tra gettoni di chiamata generati e pezzi di risposta-prefill in modo da la percezione del microfono dal vivo, capzioni RNN-T e rilevamento di interruzione di corrente continua; i limiti di chiamata e risposta separati convertono il lavoro di sola PAD malformato in una riprovazione esplicita piuttosto che uno stallo permanente.

Riproduzione precompone tre 80 cornici ms (240 ms) per impostazione predefinita. Dopo un gap di altoparlanti, attende un cuscino di recupero di otto fotogrammi prima del riavvio. 88 ms callback o quando tre frame code; una 120 ms callback, sei cornici in coda o risincronizzazione degli input vanno direttamente ad un passo di emergenza. Solo i cambiamenti di raffinatezza acustica – percezione, RNN-T e stato del linguaggio rimangono intatti.640 Il limite di ms, solo il minimo più antico microfono audio necessario per ammettere l'ingresso fresco è scartato. Il sovraccarico prolungato è trattato come un episodio di recupero, e un'utente gira già confermato da RNN-T rimane armato invece di essere cancellato da reimpostazioni ripetute.

Il cruscotto utilizza metriche di aspetto umano: behind è in coda microfono audio, RTF 0.93× è il mezzo di rotolamento sopra le ultime chiamate microfono 120 del tempo di parete diviso da 80 ms di audio (sotto 1 si mantiene in alto; sopra 1 cade dietro), e last 74 ms for 80 ms audio significa che l'ultimo callback ha preso 74 ms. Gli eventi di riproduzione non sono considerati come denominatori audio extra. Poiché RTF è una finestra, può rimanere alto brevemente dopo un'operazione costosa anche quando last ha recuperato. Sotto la conversazione, speaker gaps, old-audio skipse microphone audio skipped rendere il recupero esplicito. PLEASE REPEAT appare solo quando l'audio del microfono è stato effettivamente saltato.

La modalità Microfono utilizza la presa di turno RNN-T in stile NVIDIA per impostazione predefinita. La testa trascrizione tratta la sua prima previsione su ogni 80 Due cornici di discorso iniziali e tre giri successivi rimangono fallimenti di attività sostenute, mentre un token lexico riconosciuto immediatamente arma un'idle giro così un completo "sì" o "chi sei?" non può comparire nella didascalia e poi aspettare più discorso. VoiceChatLe previsioni BOS/EOS apprese rimangono le normali decisioni a bassa latenza.3.2 secondi) forza BOS solo se la testa imparata non apre mai una risposta, e quaranta cornici non-blank freschi forniscono il ritorno di sicurezza RNN-T EOS corrispondente. Soniqo inizia, quindi l'attività dal turno utente completato non può tagliare immediatamente la risposta. Ogni cornice audio raggiunge ancora il modello duplex; l'uso --no-rnnt-turn-taking per lasciare le decisioni BOS/EOS interamente alla testa di lingua imparata. Il cruscotto segnala i barge-ins RNN-T separatamente dai sottogruppi di riproduzione.

Il frontend RNN-T corrisponde all'imbottitura di riflessione di NeMo ad ogni bordo a ventola a microfono rotante. Questo rimuove un errore di rivestimento zero che potrebbe alterare le decisioni di token avidi marginali; non sostituisce la testa di trascrizione compatta 1,024-token del punto di controllo con una testa di transcript generale di grande-vocabolario ASR.

In modalità normale, il modello-nativo BOS viene soppresso fino a quando il discorso dell'utente non viene confermato, quindi Soniqo non parla prima. --greet Dopo il contenuto di risposta udibile, il PAD vuoto rimane all'interno del giro aperto per almeno i frame 16 e per tre frame per token di contenuto quando questo è più lungo. Il primo PAD vuoto in eccesso chiude il giro logico. Questa coda in aumento dei contenuti conserva parole ritardate che un taglio fisso 1.28-secondo può mutere.

La modalità interattiva utilizza un cruscotto fisso nella schermata alternativa del terminale, quindi gli aggiornamenti di stato si ridisegnano al posto di riempire lo scorrimento. --plain per l'uscita di sola accettazione.

Per la diagnosi locale, --debug-timeline timestamps ogni utente e Soniqo frase e inserisce gli argomenti di chiamata nativo parsed, MCP start/completion, e la sincronizzazione dei risultati nella stessa cronologia. pronunciation ended alla finestra finale audibile generato-PCM; questo è il tempo di modella-output, non il completamento di altoparlanti-dispositivo. La demo intenzionalmente omette blocchi storici di phase-timing; dettagliati nativo-decode, provider, cache e metriche di pressione del microfono rimangono in voicechat-bench JSON. La timeline può esporre argomenti di strumento, quindi non usarlo nei registri condivisi.

Misurato con didascalie live

Tre M5 Pro 48 GB esegue il rilascio misurato RTF 0.92, total-frame p95 74.8–75.8 ms, primo audio riproducibile 74.2–74.9 ms, e circa 8.74 GB picco RSS. Trascrizione e risposta sono stati identici tra le piste.

Le sessioni live mantengono l'immutabile 37-frame altoparlante più 20 i secondi della storia recente di EAR-TTS, mentre Nemotron-H mantiene lo stato di conversazione semantica separatamente. PAD all'interno della coda acustica aumentata dei contenuti viene reso normalmente; solo in seguito il PAD silenzioso avanza causalmente in lotti di otto. TTS l'attenzione e il lavoro inattivo da crescita senza limiti senza tagliare la risposta parlata; --live-speech-context-seconds 0 ripristina la storia completa TTS, e la modalità file rimane esatta full-history per impostazione predefinita.

In un 63.6-secondo M5 Profilo Pro con coda sicura dei contenuti, il percorso live misurato aggregato RTF 0.87, ultima finestra RTF 0.71, 4.1 ms/frame sintesi della finestra finale, 8.72 GB picco RSS, e 23.67 GB picco impronta fisica. Speech-attivo otto fasi finestre raggiunto RTF 1.05 e 1.12, quindi il CLI interattivo utilizza un ritorno a due passi reversibile e una modalità di emergenza a un passo. 31 I codebook RVQ in un unico passaggio; protegge la cattura dal vivo ma non è parità acustica con il programma di otto fasi. 0.9999999.

Per la diagnosi audio, il benchmark confronta il rendering live codec-window limitato con un render continuo full-context. Una lunga pausa presente in entrambi è stata generata da EAR-TTS o dal codec, non dalla coda dell'altoparlante; una discontinuità trovata solo nei punti di render live verso la cucitura codec-finestra. 50 ms di discorso sostenuto e campioni di bandiere salta sopra entrambi 0.05 ampiezza e sei volte il costante p99 baseline. Scenarios può impostare maximum_suspect_onset_transients a zero, mentre l'ascolto percettivo rimane il controllo di qualità finale.

PersonaPlex architettura e uso

PersonaPlex è un modello autoregressivo multi-stream con tre componenti principali:

ComponentiDettagli
Trasformatore temporaneo32 strati, dim=4096, 32 teste, SwiGLU (hidden_scale=4.125), RoPE, 8 bit quantizzati (default)
Depformer6 strati, dim=1024, 16 teste, MultiLinear (pesi_per_step=true), dep_q=16
Codice Mimi16 codebooks, 12,5 Hz frame rate, 24 kHz uscita audio

Il modello elabora i flussi 17 contemporaneamente: 1 flusso di testo + 8 flussi audio utente + 8 stream audio agente. Questa architettura consente la conversazione full-duplex dove il modello può ascoltare e parlare allo stesso tempo.

Preimpostazioni vocali

PersonaPlex include 18 preset vocali integrati in stili naturali e vari:

CategoriaPreimpostazioni
Femmina naturaleNATF0, NATF1, NATF2, NATF3
Maschio naturaleNATM0, NATM1, NATM2, NATM3
Femmina VariataVARF0, VARF1, VARF2, VARF3, VARF4
Variato maschioVARM0, VARM1, VARM2, VARM3, VARM4

Monologo interno

PersonaPlex genera due flussi paralleli ad ogni passo: 8 token audio codebook per il codice Mimi e un testo per il monologo interno del modello. Il flusso di testo è quello che il modello è “pensare” come si dice: può divergere leggermente dall’audio finale, ma in pratica rispecchia come risposta dal vivo.

Decodificale con il SentencePieceDecoder che PersonaPlex navi:

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

In modalità streaming, respondStream emittenti textTokens chunks come sono prodotti — li decodifica in modo incrementale per guidare una vista didascalia live mentre l'audio è ancora generante. --transcript La bandiera CLI fa esattamente questo dietro le quinte.

Perché è importante: SentencePieceDecoder è costruito sulla condivisa AudioCommon.SentencePieceModel lettore protobuf, così PersonaPlex, OmnilingualASR e qualsiasi modello SentencePiece-based decodifica attraverso la stessa implementazione tokenizer. SentencePieceModel riferimento.

Prompts di sistema

Passare qualsiasi richiesta di sistema personalizzato come una stringa normale — nessuna tokenizzazione esterna necessaria:

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

Oppure utilizzare una preimpostazione integrata:

Uso CLI

Generare una risposta parlata da un input 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

Opzioni

OpzioneDesignazione
--inputFile audio di input ( WAV, richiesto)
--voiceNome di preset vocale (ad esempio, NATM0, VARF2)
--system-promptPreimpostazione del prompt del sistema: assistente, focalizzato, servizio clienti, insegnante
--system-prompt-textTesto del prompt del sistema personalizzato (override --system-prompt)
--max-stepsFase di generazione massima
--streamEmettere pezzi audio durante la generazione
--compileUtilizzare MLX inferenza compilata per una generazione più rapida
--transcriptEsprimere la trascrizione del testo insieme all'audio
--jsonUscita JSON con metadati

I parametri di campionamento possono anche essere sovrascritti:

OpzionePredefinitoDesignazione
--audio-temp0.8Temperatura di campionamento Audio token
--audio-top-k250Audio token campionamento top-k
--text-temp0.7Temperatura di campionamento
--text-top-k25Campionamento in token di testo

Streaming

La bandiera --stream consente l'uscita audio in tempo reale. I pezzi audio vengono emessi come vengono generati, quindi la riproduzione può iniziare prima che la risposta completa sia completa. Ciò è particolarmente utile per applicazioni interattive dove la latenza bassa è importante.

Prestazioni

MetricoValore
Fattore in tempo reale ( RTF)~1.4 (8-bit, vicino in tempo reale)
Latenza del passo~ 112 ms/step su M2 Max (8-bit)
Dimensione del modello (8-bit)9,1 GB
Picco RAM (8-bit)~ 11 GB
Dimensione del modello (4-bit)~ 4,9 GB
Massimo RAM (4-bit)~ 7 GB
Importante

PersonaPlex 7B (8-bit) richiede almeno 24 GB di RAM. 4-bit variante si adatta su 16 Dispositivi GB ma produce output degradato. Su 8 Dispositivi GB, nessuna variante si adatta. --compile per le migliori prestazioni su hardware supportato.

Varianti di modello

ModelloDimensioneHuggingFace
PersonaPlex-7B (8-bit) Consigliato9,1 GBaufklarer/PersonaPlex-7B-MLX-8bit
PersonaPlex-7B (4 bit)4.9 GBaufklarer/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"))