Dialt Barge-In Detector
Detect user interruptions during AI voice-agent playback and distinguish them from backchannels that let the agent continue speaking.
Includes Silero VAD, playback arming, the one-second early-reply reflex and the learned classifier. The loader automatically downloads the pinned Moonshine Tiny base (MIT). Moonshine and Silero notices.
Install and run
Accept access on this page, then use Python 3.12 and uv. This CPU setup is tested on Linux:
uvx --from huggingface-hub==0.36.2 hf auth login
uvx --from huggingface-hub==0.36.2 hf download \
Dialt/barge-in-detector --local-dir dialt-barge
cd dialt-barge
uv venv --python 3.12
uv pip install --index-url https://download.pytorch.org/whl/cpu \
torch==2.11.0 torchaudio==2.11.0
uv pip install -r requirements.txt
uv run --no-project python example.py microphone.wav \
--playback 0 3
Supply a 16 kHz mono microphone WAV and the actual audible assistant-playback intervals in seconds; repeat --playback START STOP for additional replies. The example prints JSON events with recording timestamps and continues replaying each interval to show episode endings. It does not control audio playback. To run the included contract tests: uv run --no-project python -m unittest -v test_barge_detector.
Streaming integration
from barge_detector import BargeDetector
# One per microphone stream; load once before playback.
detector = BargeDetector()
# Arm at the first audible sample of each committed reply.
detector.playback_started()
def on_microphone_pcm(pcm16):
# PCM16 little-endian, mono, 16 kHz; whole-sample chunks.
for event in detector.feed(pcm16):
if event.kind == "barge":
# Your app stops output and discards queued audio.
stop_assistant_playback()
detector.playback_stopped()
break
# Also disarm when playback finishes or is cancelled.
# detector.playback_stopped()
Serialize calls on a worker thread, away from your realtime audio callback or async event loop. Arm only while committed assistant audio is audible, not while TTS is generating or a speculative reply is pending. playback_stopped() disarms and clears audio/VAD state; playback_started(new_reply=False) starts a fresh context without reopening the early-reply reflex for an already-started reply.
The guard requires five consecutive 32 ms Silero frames at probability โฅ 0.8. During the first 1,000 ms of a new reply, a confirmation triggers barge with reason early_vad, bypassing the classifier. Later confirmations score up to two seconds of microphone context; scores โฅ 0.5 trigger reason classifier. There is no duration-only fallback. Set reflex_window_ms=0 to disable the reflex.
Events are speech_onset, barge and speech_over, timed in milliseconds since playback_started(). A barge fires once per speech episode; if you continue feeding while armed, 550 ms below the smoothed VAD offset threshold closes the episode. score is the classifier's interruption score only for reason="classifier"; reflex events have score 0.
Benchmark
| Configuration | Interruption recall | Negative-span FPR |
|---|---|---|
| Trelis/barge-in-detector | 92.22% | 10.77% |
| Silero VAD | 98.27% | 34.24% |
| VAP OTO (threshold 0.5) | 94.81% | 36.35% |
TurnBench: all 38 development conversations, 347 positives and 3,733 negative spans; fixed pipelines at different operating points, not standalone-weight performance, held-out test results or live-latency results.
Dialt code, examples and weights are licensed under CC BY-NC 4.0 for non-commercial use. Third-party dependencies retain their own licences. For commercial licensing or training assistance, contact hello@dialt.com.