Skip to main content

Qasd (قصد)

Understanding what Arabic shoppers mean, in any dialect.

Type "iPhone" into an Arabic store and people write it six ways: آيفون, أيفون, ايفون, ايفونه, iphone, ayfon. Add a model number and you get ١٥ next to 15. Ask for shoes and an Egyptian types جزمة, someone from the Gulf types جوتي, someone from the Levant types صرماية, and the catalog says حذاء.

A search engine has to understand all of them. Qasd is a small, honest benchmark and toolkit for that problem: Arabic query understanding (normalization, dialects, Arabizi, code-switching) and retrieval (BM25, multilingual embeddings, hybrid search), measured per dialect and per error type.

What's here

Piece What it does
qasd.normalize Configurable Arabic normalizer: alef variants, ة/ه, ى/ي, hamza carriers, diacritics, tatweel, Arabic-Indic digits. Every rule is a switch, so its value can be measured.
qasd.arabizi Baseline Arabizi detector and transliterator (sha7en → شاحن).
qasd.retrieval BM25 (pure Python), dense retrieval with EmbeddingGemma 2 via sentence-transformers, and reciprocal-rank fusion.
qasd.eval Recall@k, MRR, nDCG@k, reported overall, by dialect and by phenomenon.
scripts/generate_queries.py LLM-generated dialect queries from product titles, flagged for human review.
notebooks/finetune_colab.ipynb Fine-tunes EmbeddingGemma 2 on Arabic query → product pairs on a Colab GPU.

Experiments

  1. Baselines: BM25 with and without normalization, then EmbeddingGemma 2 out of the box.
  2. Fine-tuning: EmbeddingGemma 2 trained on Arabic dialect query → product pairs, before vs after.
  3. Matryoshka sizes: how much accuracy 768 → 256 → 128 dimensions costs, against the speed and memory saved.
  4. Spoken queries: typed vs speech-to-text vs EmbeddingGemma 2's direct audio embeddings. Does the voice path return the same products as the typed one?

Results are reported per dialect and per error type, because an average hides exactly the cases this project is about.

Results

Nothing yet beyond the pipeline check on data/sample (18 synthetic queries). The real eval set is 100–200 hand-checked pairs; see data/README.md.

Quickstart

uv run --extra dev pytest -q                        # tests, no heavy installs
uv run scripts/run_eval.py --retriever bm25 --show-misses
uv run scripts/run_eval.py --retriever bm25 --no-normalize
uv run --extra dense scripts/run_eval.py --retriever dense   # needs torch + the model

Notes

  • EmbeddingGemma 2 must run in bfloat16 or float32, never float16. qasd.retrieval.dense.pick_dtype() handles this.
  • All data is synthetic or public; no real customer queries. Every query records whether it was hand-written, LLM-generated or human-checked.

See docs/ARCHITECTURE.md, docs/EXPERIMENTS.md and docs/ROADMAP.md.

License: Apache-2.0.

Metadata

Release files for qasd 0.0.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for qasd 0.0.1
File Size Uploaded Provenance
qasd-0.0.1.tar.gz 18.9 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for qasd 0.0.1
File Interpreter ABI Platform
qasd-0.0.1-py3-none-any.whl Python 3 none any Details

Total release size: 29.9 kB

Release files / qasd-0.0.1.tar.gz

Download URL qasd-0.0.1.tar.gz
Size 18.9 kB
Tags Source
SHA-256 checksum
How to use checksums
ff4cbd8fbcb81ee5c7d7b7077057fec1bcc739c6e0880bc29f80dcda38dce1e6
BLAKE2b-256 checksum
How to use checksums
a2c4eebe1e6e4b5595857f39faf0c8bf1d6ddbad4616b6f4be4873e624b721b6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.11.2 {"installer":{"name":"uv","version":"0.11.2","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release files / qasd-0.0.1-py3-none-any.whl

Download URL qasd-0.0.1-py3-none-any.whl
Size 11.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
a0a2b43ce5df92c8f7437d3674ad5c61f8bf6136270208efc74b2e2682aa018c
BLAKE2b-256 checksum
How to use checksums
0cb3bcaed1b5f123a0ae28c1e926bce356f475e4740e34a0655b06a00c10b62e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.11.2 {"installer":{"name":"uv","version":"0.11.2","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Security for qasd 0.0.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.

Release history Release notifications | RSS feed

This release

0.0.1 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page