vocal_helper.eot_bench module
vocal_helper.eot_bench
End-of-turn detection benchmark utilities — reusable evaluation
functions inspired by LiveKit’s eot-bench methodology
[@livekitturndetector] (April 2026 whitepaper).
Motivation
Every EOT / turn-taking study we run needs the same primitives :
A ground-truth turn boundary (the moment speaker A actually stops holding the floor).
A detector’s commit boundary (the moment the detector emits “turn ended, hand over”).
A latency band under which we score the detector (e.g. 300 ms, 600 ms, 1200 ms).
A pair of failure modes to count : * false-cutoff — the detector fired before the true turn
end (interrupts the speaker prematurely).
hang — the detector waited too long after the true turn end (perceived as agent hesitation).
This module implements both metrics as pure functions of aligned
lists of (true_turn_end_s, detector_commit_s) pairs. Every
call is deterministic ; no models are loaded here. The consumer
brings the ground truth (from RTTM / manual annotation) and the
detector output ; this module scores them.
Origin — the LiveKit paper reports :
9.9 % false-cutoff at 300 ms median semantic latency
4.5 % false-cutoff at 600 ms
3.0 % false-cutoff at 1200 ms
on their proprietary conversational corpus. We adopt the same three latency bands as the default reporting protocol.
Public surface
EOTPair— one (true_turn_end, detector_commit) datum.false_cutoff_rate()— fraction of pairs wherecommit < true_end - tolerance.hang_rate()— fraction of pairs wherecommit > true_end + tolerance.score()— full breakdown at the standard {300, 600, 1200} ms latency bands.
- class vocal_helper.eot_bench.EOTPair(true_turn_end_s, detector_commit_s)[source]
Bases:
objectOne aligned ground-truth / detector datum.
- true_turn_end_s
Absolute (mix-time) second at which the speaker actually released the floor. In practice pulled from a hand-labelled turn boundary or a bridged word-level RTTM.
- Type:
- detector_commit_s
Absolute second at which the detector emitted its end-of-turn decision. For a semantic-EOT model this is typically
true_turn_end + inference_latencyon hits.- Type:
- vocal_helper.eot_bench.false_cutoff_rate(pairs, *, tolerance_s)[source]
Share of pairs where the detector fired
tolerance_searly.A “false cutoff” is a decision to end the turn while the speaker is still speaking — the perceptual failure LiveKit’s metric targets. Setting
tolerance_s = 0treats any early commit as a false cutoff ; realistic tolerances are 50-150 ms (below human turn-taking noise floor).
- vocal_helper.eot_bench.hang_rate(pairs, *, latency_budget_s)[source]
Share of pairs where the detector waited >
latency_budget_s.The other-side failure : the speaker finished but the agent kept waiting, producing perceived agent hesitation.
latency_budget_sis the acceptable upper bound (LiveKit uses 300 / 600 / 1200 ms bands).
- vocal_helper.eot_bench.score(pairs, *, latency_bands_ms=(300, 600, 1200), tolerance_ms=50)[source]
Full LiveKit-style report on a set of paired detections.
- Parameters:
pairs (Iterable[EOTPair]) – Iterable of aligned (true_end, detector_commit) pairs.
latency_bands_ms (Sequence[int]) – Latency budgets to score the hang rate against. Default is LiveKit’s canonical (300, 600, 1200) ms bands.
tolerance_ms (int) – Acceptable early-commit slack before we count a false-cutoff. Default 50 ms sits below human turn-taking noise floor (Heldner & Edlund 2010 median gap 200 ms).
- Returns:
{"n": int, "median_latency_ms": float, "false_cutoff_rate": float, "hang_rate_at_ms": {band: rate, ...}}.- Return type: