The problem
Voice activity detection can detect silence, but silence alone does not reveal
whether someone has finished speaking. In Egyptian Arabic, a speaker may pause
while they are still dictating a number, revising a phrase, or about to complete
a request. An EOT detector adds the semantic decision:
- EOT — the turn is complete; the agent may answer.
- ONGOING — the user is still speaking; the agent should wait.
This checkpoint is intended as a text-based semantic signal alongside an audio
VAD, not as a replacement for VAD.
Training data
Fine-tuned on Waqf-AI/egyptian-arabic-turn-detection:
Table with columns: Split, Rows, Use| Split | Rows | Use |
|---|
| train | 21,280 | fine-tuning |
| validation | 1,200 | reserved |
| test | 2,516 | held-out evaluation |
The dataset is Egyptian Arabic (arz), context-aware, and split by
dialogue_id so truncated variants of the same utterance do not leak between
training and test. It is synthetic and author-labeled; results therefore measure
performance on this task distribution, not a guarantee of real-call performance.
Method
Base model: Qwen/Qwen3.5-0.8B.
Two decision tokens were added and learned with causal-LM supervision:
<|turn_done|> — EOT
<|turn_continue|> — ONGOING
At inference, the score is the normalized probability of <|turn_done|> versus
those two decision tokens. Training used full fine-tuning for 3 epochs, learning
rate 2e-5, batch size 4, gradient accumulation 8, and a maximum sequence
length of 512.
Held-out results
Evaluated once on the dataset's grouped test split (2,516 rows; 1,267 EOT,
1,249 ONGOING):
Table with columns: Model, ROC-AUC, Best balanced accuracy, EOT recall, ONGOING specificity| Model | ROC-AUC | Best balanced accuracy | EOT recall | ONGOING specificity |
|---|
| Qwen3.5-0.8B base | 0.500 | 50.0% | 100.0% | 0.0% |
| This fine-tuned checkpoint | 0.955 | 90.6% | 92.3% | 88.9% |
The selected equal-cost operating threshold is 0.51. In a voice agent,
false EOT causes an interruption and is usually more costly than a late response;
tune the threshold on your own validation calls accordingly.
Examples
With preceding agent context في اي خدمه (“How can I help?”):
Table with columns: Transcript so far, Expected decision, Why| Transcript so far | Expected decision | Why |
|---|
تعالي امم انا | ONGOING | incomplete predicate |
تعالي امم انا كنت عايز | ONGOING | more information is required |
تعالي امم انا كنت عايز اسال عن الفاتوره | EOT | complete request |
رقمي صفر واحد صفر | ONGOING | likely mid-number dictation |
Minimal inference
import torch
from transformers import AutoModelForMultimodalLM, AutoTokenizer
MODEL_ID = "Waqf-AI/egyptian-arabic-eot-qwen35-0.8b"
DONE, CONTINUE = "<|turn_done|>", "<|turn_continue|>"
tokenizer = AutoTokenizer.from_pretrained(MODEL_ID, padding_side="left")
model = AutoModelForMultimodalLM.from_pretrained(
MODEL_ID, dtype=torch.bfloat16, device_map="cuda"
).eval()
context = "agent: في اي خدمه"
text = "تعالي امم انا كنت عايز اسال عن الفاتوره"
prompt = (
"حدد هل المتحدث أنهى دوره أم سيكمل الكلام. أجب برمز واحد فقط: "
f"{DONE} أو {CONTINUE}.\n\nسياق المحادثة:\n{context}"
f"\n\nكلام المستخدم حتى الآن:\n{text}\nالقرار:"
)
inputs = tokenizer(prompt, return_tensors="pt").to(model.device)
with torch.inference_mode():
logits = model(**inputs).logits[:, -1, :]
ids = tokenizer.convert_tokens_to_ids([CONTINUE, DONE])
p_eot = torch.softmax(logits[:, ids].float(), dim=-1)[0, 1].item()
print(f"p(EOT) = {p_eot:.3f}")
Limitations and responsible use
- This is a text-only model. It does not hear prosody, interruptions, or
non-speech audio.
- It was trained on synthetic, author-labeled Egyptian Arabic examples. Validate
on consented, representative production transcripts before deployment.
- Use a conservative threshold and monitor false EOT decisions: an interruption
is typically more harmful than a small response delay.
- It is not intended for high-stakes decisions or as the sole control for a
safety-critical system.