VoiceChat 11B
Causal FastConformer perception feeds Nemotron-H text and function channels. Speech is rendered by a separate text-conditioned EAR-TTS decoder — not a head on the language model — and a 22.05 kHz neural codec.
Three shapes of voice-first interfaces — native full-duplex speech-to-speech models, a compositional wake → VAD → ASR → LLM → TTS pipeline you fully control, and wake-word activation for hands-free entry. All on-device, no cloud APIs, no audio leaving the device.
Drop-in dialogue model, compositional pipeline with per-stage control, or a thin wake-word trigger. Each runs entirely on-device.
Native models stream microphone audio to spoken output without a classical ASR → LLM → TTS turn boundary. Choose VoiceChat’s asymmetric stack or PersonaPlex’s Moshi-family streams.
AEC → enhance → VAD → STT → LLM → TTS → audio, with a five-state turn detector, deferred interruption handling, and tool-call loop. The canonical orchestrator lives in speech-core.
Hands-free trigger for any voice flow. Custom keywords with per-phrase thresholds, plug into the same VAD pipeline as compositional agents.
Both accept continuous speech and generate speech without a classical ASR → LLM → TTS turn boundary. Text can still exist inside the model as an aligned reasoning and control stream.
Causal FastConformer perception feeds Nemotron-H text and function channels. Speech is rendered by a separate text-conditioned EAR-TTS decoder — not a head on the language model — and a 22.05 kHz neural codec.
PersonaPlex starts from Moshi weights and jointly models user audio, agent text, and agent audio through Mimi and Depformer streams. It supports simultaneous listening and speaking, text role prompts, and audio voice prompts.
BESTOW captures NVIDIA’s preceding streamable SpeechLLM lineage, but it maps speech to text; it is not a duplex S2S model. Moshi and PersonaPlex describe the multi-stream family, while SALM-Duplex describes efficient asymmetric duplex modeling. Full-Duplex-Bench evaluates pauses, backchannels, turn-taking, and interruptions — interaction behavior that RTF does not capture.
For PersonaPlex, speech-server exposes /v1/realtime — the same session.update / input_audio_buffer.append / response.audio.delta event shape as the OpenAI Realtime API. Existing clients keep working when pointed at the local URL. VoiceChat uses the native Swift session API documented in the guide.
brew install speech
# Start the local Realtime-compatible server (PersonaPlex backend)
speech serve --model personaplex --port 8080
# In your existing OpenAI Realtime client, swap the base URL:
# wss://api.openai.com/v1/realtime → ws://localhost:8080/v1/realtime
# session.update / input_audio_buffer.append / response.audio.delta — identical event schemaThe Apple-side VoicePipeline (in speech-swift) wraps the same orchestrator. Feed it any conforming STT / LLM / TTS / VAD implementation; it runs the five-state turn detector, fires events for each transition, and handles deferred interruption when the user speaks over the agent.
import SpeechCore
import SilereoVAD
import ParakeetSTT
import Qwen3Chat
import KokoroTTS
let pipeline = VoicePipeline(
vad: SileroVAD.streaming(),
stt: try await ParakeetSTT.fromPretrained(),
llm: try await Qwen35Chat.fromPretrained(systemPrompt: "..."),
tts: try await KokoroTTSModel.fromPretrained(voice: "af_alloy"),
config: .init(
maxUtteranceDuration: 15,
minInterruptionDuration: 0.4
)
)
for await event in pipeline.events {
switch event {
case .userSpeechStarted: print("listening")
case .transcriptionCompleted(let text): print("user:", text)
case .responseAudioDelta(let chunk): player.enqueue(chunk)
case .interruption: player.cancel()
default: break
}
}Read the full state machine, AEC integration, and tool-call loop in speech-core/docs/pipeline.md ↗.
VoiceChat and PersonaPlex were measured on different Macs, so these figures are capacity checks rather than a cross-model ranking. RTF below 1 is the threshold for sustained real-time output.