End-of-turn detection for voice agents. Given the last 8 seconds of the user's speech, the model returns the probability that the user has finished their turn, so an agent can reply promptly after a real endpoint and keep listening through a mid-sentence pause. It looks at the raw audio (prosody, pace, intonation), not a transcript, and covers 23 languages.
This is an audio-in export: the Whisper log-mel front-end is inside the graph, including the zero-mean / unit-variance waveform normalisation the upstream model was trained with. Feed 16 kHz PCM and read one probability.
| Property | Value |
|---|---|
| Parameters | 8.0 M (Whisper-Tiny encoder + attention pooling + MLP head) |
| Input | audio float32 [1, 128000] — 16 kHz mono, most recent audio last, zeros at the front |
| Output | probability float32 [1, 1] — turn complete if > 0.5 |
| Window | 8 s (longer turns: keep the last 8 s) |
| Formats | float32 (33.0 MB), int8 (11.1 MB) |
| Opset | 18 |
| Languages | Arabic, Bengali, Chinese, Danish, Dutch, English, Finnish, French, German, Hindi, Indonesian, Italian, Japanese, Korean, Marathi, Norwegian, Polish, Portuguese, Russian, Spanish, Turkish, Ukrainian, Vietnamese |
| File | Size | Description |
|---|---|---|
smart-turn-v3.2.onnx | 33.0 MB | float32 graph with the audio front-end embedded |
smart-turn-v3.2-int8.onnx | 11.1 MB | int8 weights (dynamic quantization) for encoder and head, float32 front-end |
config.json | — | I/O contract, window size, upstream revision |
LICENSE | — | BSD-2-Clause notice for the upstream weights |
Accuracy on 1,000 clips from the upstream pipecat-ai/smart-turn-data-v3.2-test set (shard train-00000-of-00010.parquet, threshold 0.5). Latency is one 8-second window on Apple M5 Pro (macOS 26.5.2) (ONNX Runtime CPU with 2 intra-op threads, CoreML on CPU + Neural Engine). Higher accuracy / F1 is better; FPR is the share of unfinished turns wrongly cut off, FNR the share of finished turns the model kept waiting on.
| Model | Accuracy | Precision | Recall | F1 | FPR | FNR | Latency (mean) | Latency (p95) |
|---|---|---|---|---|---|---|---|---|
Upstream smart-turn-v3.2-gpu.onnx (mel input) | 92.90% | 0.912 | 0.944 | 0.927 | 8.48% | 5.61% | — | — |
Upstream smart-turn-v3.2-cpu.onnx (mel input) | 91.70% | 0.889 | 0.946 | 0.916 | 10.98% | 5.41% | — | — |
smart-turn-v3.2.onnx | 92.90% | 0.912 | 0.944 | 0.927 | 8.48% | 5.61% | 36.3 ms | 51.4 ms |
smart-turn-v3.2-int8.onnx | 93.00% | 0.910 | 0.948 | 0.929 | 8.67% | 5.20% | 37.3 ms | 50.6 ms |
The re-export reproduces the upstream fp32 graph to within 1e-5 on the same mel input; the only difference is where the front-end runs. The int8 file quantizes the encoder and head weights (dynamic quantization of MatMul/Gemm); on the test clips its probabilities differ from fp32 by 0.007 on average and it flips the 0.5 decision on fewer than 1 % of clips. On Apple Silicon the int8 graph is not faster than fp32 under ONNX Runtime; it mainly saves download size. The encoder dominates the cost (the embedded front-end is about 4 ms single-threaded), and more threads help: about 20 ms with four.
Run it after a lightweight VAD reports silence. Pass the whole current turn (up to 8 s), not just the last chunk. If the user resumes speaking before the agent answers, run it again on the full turn.
import numpy as np
import onnxruntime as ort
session = ort.InferenceSession("smart-turn-v3.2-int8.onnx", providers=["CPUExecutionProvider"])
def turn_complete_probability(turn_audio_16k: np.ndarray) -> float:
window = np.zeros(128000, dtype=np.float32)
tail = turn_audio_16k[-128000:].astype(np.float32)
window[128000 - len(tail):] = tail
return float(session.run(None, {"audio": window[None]})[0][0, 0])
# speech-core CLI (after scripts/download_models.sh)
speech turn --audio utterance.wav
Re-exported from pipecat-ai/smart-turn-v3 (revision
f766f81d3cfd, smart-turn-v3.2-gpu.onnx), the open Smart Turn model from the
Pipecat project, BSD-2-Clause. Training data and
evaluation sets are published by Pipecat as pipecat-ai/smart-turn-data-v3.2-*.