PersonaPlex full-duplex online serving
Serve nvidia/personaplex-7b-v1
(a Moshi-based full-duplex speech-to-speech model) with the native vLLM-Omni engine.
The server hosts the official PersonaPlex web client at / (auto-downloaded from
the model repo) and implements its WebSocket protocol at /api/chat, so you talk to the
model live in the browser — mic in, agent speech + inner-monologue text out.
Experimental. Requires a GPU and Hugging Face access to the gated repo (
HF_TOKENwith access tonvidia/personaplex-7b-v1).
Start the server
HF_TOKEN=... CUDA_VISIBLE_DEVICES=0 bash run_server.sh
# or directly:
HF_TOKEN=... CUDA_VISIBLE_DEVICES=0 python -m \
vllm_omni.experimental.fullduplex.personaplex.serving.server --port 8124
Talk to it
-
Browser (recommended): open
http://localhost:8124/and allow the microphone. Use headphones so the agent does not hear itself. -
Headless: stream a 24 kHz mono WAV and save the reply:
python duplex_client.py --url ws://localhost:8124/api/chat --input user.wav --out reply.wav
Unified Realtime API
The default vllm_omni/deploy/personaplex.yaml also enables main's engine-owned
full-duplex control plane:
CUDA_VISIBLE_DEVICES=0 python -m vllm_omni.entrypoints.cli.main serve \
/path/to/personaplex-7b-v1 \
--omni \
--deploy-config vllm_omni/deploy/personaplex.yaml
Validate the actual /v1/realtime?duplex=1 scheduler path with paced 24 kHz
PCM, two concurrent sessions, overflow admission, per-session slot recycling,
and non-silent output:
python tests/e2e/online_serving/personaplex_realtime_duplex.py \
--model /path/to/personaplex-7b-v1 \
--input-wav /path/to/speech.wav \
--output-dir /tmp/personaplex-realtime-duplex
This is distinct from the standalone /api/chat compatibility server above.
The unified endpoint advertises supports_barge_in=false: overlapping speech
is native model behavior, but destructive output interruption and model-state
rewind have not been validated for PersonaPlex.
Protocol (/api/chat)
Binary WebSocket messages, first byte is a tag (identical to moshi.server):
| Direction | Tag | Payload |
|---|---|---|
| server → client | \x00 |
ready handshake (after the system-prompt prefill) |
| client → server | \x01 |
Opus-encoded mic audio (24 kHz) |
| server → client | \x01 |
Opus-encoded agent audio |
| server → client | \x02 |
UTF-8 inner-monologue text |
Connect with query params text_prompt (persona) and voice_prompt (voice file).
A raw-PCM endpoint (/v1/audio/duplex, JSON open + float32 frames) is also available
for clients that do not want an Opus dependency.
Notes
- Run the client near the server. Real-time 80 ms audio is sensitive to network latency/jitter; over a high-latency remote link playback can stutter regardless of engine speed. On localhost it is smooth.
- Greedy decoding by default. One conversation per server by default (a second
concurrent connection is rejected with WS close 1013 until the first ends);
pass
--batch-size Nto host N concurrent conversations on one engine (elastic batching; connections beyond N are rejected until a slot frees). - Full runbook:
recipes/NVIDIA/PersonaPlex.md.