🎙️ QwenCleo-ASR
The best open-source model for Egyptian Arabic & code-switching speech recognition
Built on Qwen3-ASR-1.7B, fine-tuned for Egyptian dialect and Arabic ↔ English code-switching.
QwenCleo — the name carries three meanings: Qwen, the powerful base model it is built on; Queen, signalling a model that reigns over its domain; and Cleo, for Cleopatra, the queen of Egypt — because this model is tailored for Egyptian Arabic. 👑🏺
QwenCleo-ASR is, to our knowledge, the best open-source ASR model for Egyptian Arabic and Arabic/English code-switching. It cuts the error rate of the strong Qwen3-ASR base roughly in half, and correctly keeps embedded English tech/loan words in Latin script (engineering, download, React, at least) instead of mangling them into broken Arabic.
- 🎯 Egyptian dialect — tuned on hundreds of hours of Egyptian podcast speech.
- 🔀 Code-switching — keeps English terms in
code-script, Arabic in Arabic. - 🥇 State-of-the-art (open) — beats Qwen3-ASR base, NVIDIA Nemotron, Cohere, and every Whisper variant on our Egyptian + CS test set.
- 📦
pip install qwencleo-asr— inference & chunked long-audio transcription in three lines. - ⚡ Real streaming — token-by-token via vLLM (
asr.stream(...)), plus a mic web demo. - 🚀 Serving — FastAPI server, Gradio demo, OpenAI-compatible vLLM endpoint.
📊 Results
WER / CER (%) on an Egyptian-Arabic + code-switching test set (3,699 utterances). Lower is better. All models scored with the same Egyptian-aware normalization.
| Rank | Model | Params | WER all | CER all | WER · AR | CER · AR | WER · CS | CER · CS |
|---|---|---|---|---|---|---|---|---|
| 🥇 | QwenCleo-ASR | 1.7B | 19.85 | 10.52 | 19.08 | 10.30 | 20.75 | 10.81 |
| 🥈 | Arabic-Whisper-CodeSwitching | 1.55B | 37.98 | 17.86 | 38.48 | 18.71 | 36.92 | 16.22 |
| 🥉 | NVIDIA Nemotron-3.5 | 0.6B | 38.04 | 19.72 | 36.23 | 16.43 | 41.44 | 25.66 |
| 4 | Qwen3-ASR-1.7B (base) | 1.7B | 41.51 | 20.86 | 40.59 | 18.52 | 43.20 | 25.04 |
| 5 | Whisper Large-v3 Turbo (FT) | 0.81B | 50.83 | 22.86 | 48.37 | 18.42 | 55.08 | 37.84 |
| 6 | Cohere Transcribe 03-2026 | 2.0B | 53.20 | 39.12 | 47.95 | 33.45 | 63.76 | 49.66 |
| 7 | MasriSwitch-Gemma3n | 8B | 57.30 | 30.19 | 60.38 | 32.91 | 51.32 | 25.13 |
| 8 | Whisper Large-v3 | 1.54B | 63.94 | 39.76 | 49.25 | 22.76 | 59.32 | 31.52 |
| 9 | Whisper Large-v2 | 1.54B | 72.34 | 48.73 | 60.75 | 33.21 | 66.85 | 40.75 |
| 10 | Whisper Large-v3 Turbo | 0.81B | 73.83 | 46.86 | 59.37 | 29.42 | 66.08 | 37.84 |
| 11 | Whisper Medium | 0.76B | 80.46 | 53.19 | 74.77 | 41.76 | 74.15 | 44.90 |
| 12 | Whisper Small | 0.24B | 89.99 | 60.34 | 77.42 | 42.53 | 87.09 | 55.22 |
| 13 | Whisper Tiny | 0.04B | 124.68 | 89.42 | 116.02 | 77.74 | 110.67 | 74.57 |
🗣️ Sample outputs
Real transcriptions from the test set, scored after Egyptian-aware normalization. Examples span short, medium, and long clips in both Egyptian Arabic and code-switching. These are picked to be honest — on some clips other models also do well; QwenCleo's edge is consistency, dialect fidelity, and keeping English terms in Latin script.
✅ = matches ground truth · ⚠️ = minor slips · ❌ = clear errors. Bold marks the wrong spans.
🔀 Code-switching
Short
✅ Ground truth ااه بحس ستايله حلو وشكله حلو كاريزما وهو بيلعب
| Model | Output |
|---|---|
| 🥇 QwenCleo | بحس style ه حلو وشكله حلو كاريزما وهو بيلعب ⚠️ |
| Qwen3-ASR (base) | أه بحس طايله حلو وشكله حلو وكرزمه وهو يلعب ❌ |
| Cohere | اااااااا بحس ستايله حلو وشكله حلو وكاريزما وهو بيلعب ✅ |
| Nemotron | آه بحس ستايله حلو وشكله حلو كاريزما هو بيلعب ✅ |
| Arabic-Whisper-CS | بحس style و حلو وشكل وحلو و charisma وهو بيلعب ⚠️ |
| MasriSwitch | بحس ستايله حلو و شكله حلو و كاريزما وهو بيعلق ❌ |
Medium
✅ Ground truth — ده حصل ازاي قرار اصلا انك تعمل قناة
YouTube
| Model | Output |
|---|---|
| 🥇 QwenCleo | ده حصل ازاي قرار اصلا انك تعمل قناة YouTube ✅ |
| Qwen3-ASR (base) | ده حصل إزاي قرار أصلا إنك تعمل قناة يوتيوب ⚠️ |
| Cohere | ده حصل ازاي قرار اصلا انك تعمل قناه يوتيوب ⚠️ |
| Nemotron | ده حصل إزاي قرار أصلاً إنك تعمل قناة يوتيوب ⚠️ |
| Arabic-Whisper-CS | دا حصل ازاي قرار اصلا انك تعمل قناة يوتيوب ⚠️ |
| MasriSwitch | ده حصل ازاي قرار أصلا إنك تعمل قناة YouTube ✅ |
✅ Ground truth — خليني اوضح بس هدفها ان الطالب يجي هو
already
| Model | Output |
|---|---|
| 🥇 QwenCleo | خليني اوضح بس هدفها ان الطالب يجي هو already ✅ |
| Qwen3-ASR (base) | خلينا أوضح بس هدفه إن الطالب يجي هو أرريدي ❌ |
| Cohere | خليني اوضح بس هدفها ان الطالب يجي هو اوردي ❌ |
| Nemotron | خلينا وضح بس هدفها إن الطالب يجي هو أوردي ❌ |
| Arabic-Whisper-CS | خليني اوضح بس هدفها ان الطالب ييجي هو already ✅ |
| MasriSwitch | خليني أوضح بس الأهداف إن الطالب بيجي هو already ⚠️ |
Long
✅ Ground truth — ما هو الفكرة جاية فين النهارده
averageالعربية اللي ممكن تجيبها من أوروبا ما بين 23 ل 28000dollarsتقريبا
| Model | Output |
|---|---|
| 🥇 QwenCleo | ما هو الفكره جايه فين النهارده average العربيه اللي ممكن تجيبها من اوروبا ما بين 23 ل 28000 dollars ⚠️ |
| Qwen3-ASR (base) | ما هو الفكرة جاية فين النهاردة أفرج العربية اللي ممكن تجابها من أوروبا ما بين 23 ل 28000 دولار ⚠️ |
| Cohere | ما هو الفكره جايه فين النهارده افريقيا العربيه اللي ممكن تجيبها من اوروبا ما بين 23 ل 28000 دولار ❌ |
| Nemotron | ما هو الفكرة جاية فين النهار ده أفريد العربية اللي ممكن تجيبها من أوروبا ما بين 23 ل 28000 دولار ثلاثة ❌ |
| Arabic-Whisper-CS | ما هو الفكرة جاية فين النهار دا average العربية اللي ممكن تجيبها من أوروبا ما بين 23 ل 28 ألف دولار تقريبا ⚠️ |
| MasriSwitch | ما هو الفكرة جاية فين النهاردة average العربية اللي ممكن تجيبها من أوروبا ما بين 23 لـ28 ألف دولار تقريبًا ⚠️ |
✅ Ground truth — فبتديك كل ال
soft skillsبشكلindirectحرفيا بتديهالك بالمعلقه ليه بتتعلم تشتغل على كل الحاجات بتاعهMicrosoft Excel PowerPoint Word whateverبعدين كمان بتتعلم ان انت تتكلم مع الناسpublic speaking
| Model | Output |
|---|---|
| 🥇 QwenCleo | فبتديك كل الsoft skills بشكل indirect حرفيا بتديهالك بالمعلقه ليه بتتعلم تشتغل على كل الحاجات بتاعه Microsoft Excel, PowerPoint, Word و whatever بعدين كمان بتتعلم ان انت تتكلم مع الناس public speaking ✅ |
| Arabic-Whisper-CS | فبتديك كل ال soft skills بشكل indirect حرفيا بتديهالك بالمعلقة ليه بتتعلم تشتغل على كل الحاجات بتاعة Microsoft, Excel, PowerPoint, Word whatever بعدين كمان بتتعلم أن أنت ⚠️ |
| MasriSwitch | فبتديك كل ال soft skills بشكل indirect حرفيا بتديهالك بالمعلاة ليه بتتعلم تشتغل على كل الحاجات بتاعة Microsoft Excel, PowerPoint, Word whatever بعدين كمان بتتعلم أن أنت ⚠️ |
🇪🇬 Egyptian Arabic
Pure-Arabic clips (no English). After normalization these reflect genuine word-level accuracy, not spelling/number-format differences.
Short
✅ Ground truth — الشهرة مرت بمرحلتين معاك
| Model | Output |
|---|---|
| 🥇 QwenCleo | الشهرة مرت بمرحلتين معاك ✅ |
| Qwen3-ASR (base) | الشهرة مرت بمرحلتين معك ⚠️ |
| Cohere | الشهره مرت بمرحلتين معاك ✅ |
| Nemotron | الشهرة مرت بمرحلتين معك ⚠️ |
| Arabic-Whisper-CS | الشهرة مرت بمرحلتين معاك ✅ |
| MasriSwitch | الشهرة مرت بمرحلتين معاك ✅ |
Medium
✅ Ground truth — لا ركز عشان انت دلوقتي هتتحاسب على الكلام ده
| Model | Output |
|---|---|
| 🥇 QwenCleo | لا ركز عشان انت دلوقتي هتتحاسب على الكلام ده ✅ |
| Qwen3-ASR (base) | لا ركز عشان أنت دلوقتي هتحسب على كلام ده ⚠️ |
| Cohere | لا ركز عشان انت دلوقتي هتتحاسب عالكلام ده ✅ |
| Nemotron | لأ ركز على شان أنت دي الوقت هتتحسب على الكلام ده ❌ |
| Arabic-Whisper-CS | لأ ركز عشان انت دلوقت هتتحسب على الكلام ده ⚠️ |
| MasriSwitch | لأ ركز عشان انت دلوقتي هتتحاسب على الكلام ده ✅ |
✅ Ground truth — بصراحة كانت من أسعد أيام حياتي لما شفت اللي هما فرحانين
| Model | Output |
|---|---|
| 🥇 QwenCleo | بصراحة كانت من أسعد أيام حياتي لما شفت اللي هما فرحانين ✅ |
| Qwen3-ASR (base) | بصراحة كنت من أسعد أيام حياتي لما شوفت اللي هم فرحاني ❌ |
| Cohere | بصراحه كانت قبل اسعد قيم حياتي لما شوفت اللي هم فرحانين ❌ |
| Nemotron | بصراحة كانت من أسعد قام حاتي لما شفت اللي هم فرحين ❌ |
| Arabic-Whisper-CS | بصراحة كانت أبنة أسعد أقام حياتي لما شوفت اللي هم فرحانين ❌ |
| MasriSwitch | بصراحة كانت من أسعد أيام حياتي لما شفت اللي هم فرحانين ✅ |
Long
✅ Ground truth — انا النهاردة مثلا ساكن في مدينة نصر وشغلي في المعادي فانا من البيت للشغل بقطع 20 كيلو في اليوم
| Model | Output |
|---|---|
| 🥇 QwenCleo | انا النهارده مثلا ساكن في مدينة نصر وشغلي في المعادي فانا من البيت للشغل بقطع 20 كيلو في اليوم ✅ |
| Qwen3-ASR (base) | أنا النهاردة مثلاً ساكن في مدينة نصر وشغلي في المعادي فأنا من البيت للشغل لبقيت 20 كيلو في اليوم ⚠️ |
| Cohere | انا النهارده مثلا ساكن في مدينه مصر وشغلي في المعادي فانا من البيت للشغل بقطع 20 كيلو في اليوم ⚠️ |
| Nemotron | أنا النهار ده مثلاً ساكن في مدينة نصر وشغلي في المعادي فأنا من البيت للشغل بقطع 20 كيلو في اليوم ✅ |
| Arabic-Whisper-CS | أنا النهاردة مثلا ساكن في مدينة نصر و شغلي في المعادي فانا من البيت للشغل بقطع 20 كيلو في اليوم ✅ |
| MasriSwitch | أنا النهاردة مثلا ساكن في مدينة نصر وشغلي في المعادي فأنا من البيت للشغل بقطع 20 كيلو في اليوم ✅ |
✅ Ground truth — اشتغلت كان فيه معاناة في تحضير المنهج
| Model | Output |
|---|---|
| 🥇 QwenCleo | اشتغلت كان فيه معاناة في تحضير المنهج ✅ |
| Qwen3-ASR (base) | اشتغلت كان في معاناة في تحضير المناك ❌ |
| Cohere | اشتغلت كان في معاناه في تحضير المنعكس ❌ |
| Nemotron | آه استقالت كان في معناه في تحضير المناك ❌ |
| Arabic-Whisper-CS | اشتغلت كان في معناه في تحضير المنهج ✅ |
| MasriSwitch | إشتغلت كان في معنية في تحضير المنهج ❌ |
📦 Installation
Install the right torch first. A plain
pip installpulls the newest torch (built for the latest CUDA), which fails on older drivers with "NVIDIA driver too old". Install a torch build matching your driver before the package, then add QwenCleo with--no-depsso torch is never reinstalled.Pick the wheel index for your CUDA driver —
cu121(driver ≥ 12.1, e.g. CUDA 12.2),cu118(driver ≥ 11.8), orcpu. Check yours withnvidia-smi.
For inference & chunked transcription (PyPI)
conda create -n qwencleo-asr python=3.12 -y
conda activate qwencleo-asr
# 1) torch matching your driver (cu121 shown — change the index for yours)
pip install torch==2.5.1 torchaudio==2.5.1 \
--index-url https://download.pytorch.org/whl/cu121
# 2) QwenCleo without touching torch, then its remaining deps
pip install qwencleo-asr --no-deps
pip install "qwen-asr>=0.0.6" numpy soundfile huggingface_hub
That's all you need for the Python API and the qwencleo CLI.
For serving / Gradio / vLLM (clone the repo)
conda create -n qwencleo-asr python=3.12 -y
conda activate qwencleo-asr
# 1) torch matching your driver, first
pip install torch==2.5.1 torchaudio==2.5.1 \
--index-url https://download.pytorch.org/whl/cu121
# 2) the repo (without re-resolving torch) + serving deps
git clone https://github.com/MohammedAly22/qwencleo-asr.git
cd qwencleo-asr
pip install -e . --no-deps
pip install "qwen-asr>=0.0.6" numpy soundfile huggingface_hub
pip install -r requirements-serving.txt
Verify torch sees the GPU before running:
python -c "import torch; print(torch.__version__, torch.cuda.is_available())"
# -> 2.5.1+cu121 True
🚀 Usage
Python — basic transcription
from qwencleo_asr import QwenCleoASR
asr = QwenCleoASR() # loads mohammedaly22/QwenCleo-ASR
result = asr.transcribe("clip.wav") # language defaults to "Arabic"
print(result.text)
Batch, auto-detect language, and Egyptian normalization:
results = asr.transcribe(["a.wav", "b.wav"], language=None) # auto-detect
clean = asr.transcribe("clip.wav", normalize=True) # normalized text
Python — chunked transcription of long audio / mic
from qwencleo_asr import QwenCleoASR, stream_file
asr = QwenCleoASR()
for chunk in stream_file(asr, "long_podcast.wav", chunk_s=20, overlap_s=2):
print(f"[{chunk.start:.0f}-{chunk.end:.0f}s] {chunk.text}")
ℹ️ This is chunked transcription, not true streaming. It splits long/live audio into overlapping windows and transcribes each — convenient for captioning without a server, but latency is per-window. For genuine token-by-token streaming, use the vLLM path below.
Python — true streaming (vLLM)
QwenCleo inherits Qwen3-ASR's real token-by-token streaming via vLLM. Two one-time setup commands, then stream from Python.
qwencleo install-vllm # installs the vLLM nightly (cu129) — the only build
# with Qwen3-ASR support (not on PyPI; uses uv)
qwencleo serve # launches the server (sets the right flags for you:
# VLLM_USE_FLASHINFER_SAMPLER=0, --gpu-memory-utilization 0.8)
Needs an Ampere-or-newer GPU (L4 / A100 / H100). See
server/vllm_serve.mdfor details and manual flags.
Then stream straight off the model object — deltas arrive as they're generated
(the language X<asr_text> prefix is stripped for you):
from qwencleo_asr import QwenCleoASR
asr = QwenCleoASR()
for delta in asr.stream("clip.wav", port=8000): # talks to the vLLM server
print(delta, end="", flush=True)
Or use the helpers directly:
from qwencleo_asr import stream_vllm, transcribe_vllm, VLLMOffline
for delta in stream_vllm("clip.wav", port=8000, language="Arabic"):
print(delta, end="", flush=True)
print(transcribe_vllm("clip.wav", port=8000)) # one-shot via the server
print(VLLMOffline().transcribe("clip.wav")) # in-process, no server
From the shell:
qwencleo stream-vllm clip.wav --port 8000 # token-by-token to stdout
CLI
qwencleo transcribe clip.wav
qwencleo transcribe a.wav b.wav --language None --normalize
qwencleo stream long_podcast.wav --chunk-s 20 --overlap-s 2
🌐 Serving
FastAPI server
QWENCLEO_MODEL=mohammedaly22/QwenCleo-ASR \
uvicorn server.app:app --host 0.0.0.0 --port 8000
curl -X POST http://localhost:8000/v1/transcribe -F file=@clip.wav -F language=Arabic
Gradio demo
python app/gradio_app.py # http://localhost:7860 (mic + file upload)
vLLM — serving, streaming & OpenAI-compatible API
Full guide in server/vllm_serve.md. In short:
qwencleo install-vllm # vLLM nightly (cu129) — the only build with Qwen3-ASR support
qwencleo serve # OpenAI-compatible server on :8000
OpenAI-compatible transcription:
from openai import OpenAI
client = OpenAI(base_url="http://localhost:8000/v1", api_key="EMPTY")
print(client.audio.transcriptions.create(
model="mohammedaly22/QwenCleo-ASR", file=open("clip.wav","rb").read()).text)
Streaming mic web demo
Live browser-mic transcription via the upstream Flask demo:
qwen-asr-demo-streaming \
--asr-model-path mohammedaly22/QwenCleo-ASR \
--host 0.0.0.0 --port 8000 --gpu-memory-utilization 0.9
# open http://<your-ip>:8000
📓 Examples (Colab)
Runnable notebooks in examples/ — open one, set the runtime to
GPU (Runtime → Change runtime type → GPU), and run the cells top to bottom.
🔗 Links
- 🤗 Model card:
mohammedaly22/QwenCleo-ASR - 📦 PyPI:
qwencleo-asr - 🧱 Base model:
Qwen/Qwen3-ASR-1.7B· Qwen3-ASR repo - Languages: Egyptian Arabic, Modern Standard Arabic, Arabic↔English code-switching
- Recommended
languagehint:"Arabic"(orNoneto auto-detect)
📜 License & citation
Apache-2.0, inheriting the Qwen3-ASR license terms.
@misc{qwencleo_asr_2026,
title = {QwenCleo-ASR: The Best Open-Source Egyptian Arabic and Code-Switching Speech Recognition Model},
author = {Mohammed Aly},
year = {2026},
howpublished = {\url{https://huggingface.co/mohammedaly22/QwenCleo-ASR}},
note = {Fine-tuned from Qwen3-ASR-1.7B}
}
Metadata
Release files for qwencleo-asr 0.2.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| qwencleo_asr-0.2.1.tar.gz | 27.8 kB | Without provenance | Details for qwencleo_asr-0.2.1.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| qwencleo_asr-0.2.1-py3-none-any.whl | Python 3 | none | any | Details for qwencleo_asr-0.2.1-py3-none-any.whl |
Total release size: 51.0 kB
Release files / qwencleo_asr-0.2.1.tar.gz
| Download URL | qwencleo_asr-0.2.1.tar.gz |
|---|---|
| Size | 27.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
8a04d16fcb148a8494d6916777a9cd63313e9f8aa4652c5ab0e41857a8269e4f
|
|
BLAKE2b-256 checksum How to use checksums |
fc3571b39154c6a7b96f2af489b90356a238662fc6a1ab7493e3523e06666013
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.13
|
Release files / qwencleo_asr-0.2.1-py3-none-any.whl
| Download URL | qwencleo_asr-0.2.1-py3-none-any.whl |
|---|---|
| Size | 23.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
b2ba72a23a01abad81974c125857e65800062225e94ddb5b29e2b1f0c314d979
|
|
BLAKE2b-256 checksum How to use checksums |
0c1db2be522c7aeaa45bd909e14b0c60d12fb28c0b015c84b42a480cd700aafb
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.13
|
Security for qwencleo-asr 0.2.1
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.