Skip to main content

livekit-plugins-duplexjev

Audio end-of-turn detection for LiveKit Agents, powered by DuplexJev. It listens to how the user speaks, not only what they say, and tells your agent whether the user is finished, still talking, just backchanneling ("mm-hmm") or asking you to wait. The same request can also return emotion, laughter / breathing / coughs / sighs and barge-in.

  • Reads the audio, not the transcript. Every answer is one constrained token of a speech LLM: nothing is decoded, so the decision does not wait for STT.
  • Fast. Ten decisions about one utterance take 92 ms on one GPU, against 1,978 ms for ASR → LLM with the same LLM.
  • Accurate. On the CoDeTT turn-taking benchmark (English, zero-shot), DuplexJev-32B-Turn scores 70.0, against 51.4 for Smart Turn v3. See the paper.
  • More than turns, same request. Ask for emotion, non-verbal sounds or your own multiple-choice questions.
  • Chinese and English. CPU only on the agent side: the plugin calls an HTTP API.

Tested with livekit-agents 1.8.6. Maintained by Adventists.ai (AI降临派).

Install

pip install livekit-plugins-duplexjev

Use

from livekit.agents import AgentSession
from livekit.plugins import duplexjev, silero

session = AgentSession(
    stt=..., llm=..., tts=...,
    vad=silero.VAD.load(),
    turn_handling={"turn_detection": duplexjev.TurnDetector(
        api_url="http://localhost:8420",       # your own gateway; omit for the free hosted trial API
        extra_questions=["emotion", "sound"],
        on_answers=lambda a: print({k: v["answer"] for k, v in a.items()}),
    )},
)

Give it the agent's last message (new in 0.2.0). Turn-taking is clearly better when the model knows what the agent had just said. Keep a reference to the detector and attach it to the session once:

detector = duplexjev.TurnDetector(api_url="http://localhost:8420")
session = AgentSession(..., turn_handling={"turn_detection": detector})
detector.attach(session)        # follows conversation_item_added; or detector.set_assistant_said(text)

It needs a gateway from duplexjev>=0.6. On LiveKit eot-bench (English, DuplexJev-32B-Para v1.2) this cuts false cut-offs at a 300 ms budget from 23.5% to 19.7%.

AgentSession(turn_detection=duplexjev.TurnDetector(), ...) works too (LiveKit marks that argument as deprecated). A complete agent is in examples/agent.py.

A VAD is required. LiveKit ignores a streaming turn detector when the session has no VAD. The plugin buffers the user's audio, and after about 200 ms of VAD silence LiveKit asks it for a prediction: the last 8 s of the current user turn go to DuplexJev, and P(finished) becomes LiveKit's end_of_turn_probability. Below unlikely_threshold the session waits max_delay instead of min_delay before replying. The VAD's min_silence_duration must be at least 0.25 s (Silero's default is 0.55 s).

STT is optional for the decision. If the session has an STT, LiveKit still waits for its transcript before it commits the turn, as with any turn detector, because the LLM needs the text.

The default URL is our free trial API (rate limited to 30 requests per minute; the round trip from outside mainland China adds network latency). For a live agent, serve the model next to it (DuplexJev-4B-Para needs about 10 GB of GPU memory; for the best turn-taking use DuplexJev-32B-Para v1.2 on one 80 GB GPU):

pip install "vllm[audio]>=0.29" duplexjev-vllm "duplexjev[server]>=0.6"
vllm serve adventists-ai/DuplexJev-4B-Para --max-model-len 4096 --port 8000 &
duplexjev gateway --vllm http://localhost:8000/v1 --port 8420

Then pass api_url="http://localhost:8420" (or set DUPLEXJEV_API_URL).

Options

argument default
api_url hosted trial API base URL of a duplexjev gateway (or DUPLEXJEV_API_URL)
api_key None bearer key, if your gateway requires one (or DUPLEXJEV_API_KEY)
lang "en" "en" or "zh": wording of the questions (the model hears both languages either way)
unlikely_threshold 0.5 below this P(finished), wait max_delay instead of min_delay
backchannel_threshold None if set, also asks "What should the assistant do now?" and reports P(short acknowledgement) as LiveKit's backchannel probability
extra_questions [] "emotion", "sound", "barge_in", or dicts {"id", "text", "options"}
on_answers None callback with every answer dict; the latest is also on detector.last_answers
window_s 8.0 seconds of the current user turn sent with each request
trim_silence True drop the silence before the user started talking (keeps 0.3 s)
prediction_timeout 4.0 hosted, 1.0 own gateway how long LiveKit waits for a prediction
fallback_probability 1.0 P(finished) reported if the gateway fails, so the conversation never blocks

License

The plugin code is BSD-2-Clause. DuplexJev model weights are CC BY-NC 4.0 (non-commercial); see the model cards. For commercial use, contact jiejin@adventists.ai.

Metadata

Release files for livekit-plugins-duplexjev 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for livekit-plugins-duplexjev 0.2.0
File Size Uploaded
livekit_plugins_duplexjev-0.2.0.tar.gz 16.0 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for livekit-plugins-duplexjev 0.2.0
File Interpreter ABI Platform
livekit_plugins_duplexjev-0.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 29.3 kB

Release files / livekit_plugins_duplexjev-0.2.0.tar.gz

Download URL livekit_plugins_duplexjev-0.2.0.tar.gz
Size 16.0 kB
Tags Source
SHA-256 checksum
How to use checksums
0405f780386ac0472ae8a5a57fbea1959e8a82474a9c1ac6e9ed3fab06f19c7d
BLAKE2b-256 checksum
How to use checksums
bf3a095b4844d8f00b52a55335cbf4e41ef03bc0170e78b0143b3ec5559d550c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.10.12

Release files / livekit_plugins_duplexjev-0.2.0-py3-none-any.whl

Download URL livekit_plugins_duplexjev-0.2.0-py3-none-any.whl
Size 13.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
827b03ccf075ca15acc5debfcc427f9bc76214d11c9d8cfb577ba1a24f63ed9a
BLAKE2b-256 checksum
How to use checksums
516d05981d9332b12a5a9e39fb7c66e38a069f97a950146304a1855973821416
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.10.12

Release history Release notifications | RSS feed

0.3.3

2 release files

0.3.2

2 release files

0.3.1

2 release files

0.3.0

2 release files

This release

0.2.0 This release

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page