Free / locally-runnable implementation of the WhatsApp Message Notification Router for the HackerRank Orchestrate challenge.
Stack (all local except Gemini):
- PaddleOCR (PP-OCRv4) for image text
- faster-whisper (large-v3) for voice notes
- Qwen2.5-VL-7B-Instruct-AWQ for image understanding (Florence-2 CPU fallback)
- BGE-M3 for multilingual dense embeddings
- NumPy / FAISS cosine retrieval over
message_history - Gemini 2.5 Flash (free tier) as the single external reasoning model
Full architecture is in the chat transcript. This README covers only setup.
# 1. Python 3.11 virtual env
py -3.11 -m venv .venv
.\.venv\Scripts\Activate.ps1
# 2. Install dependencies (see "Install notes" below if this fails)
.\run.ps1 install
# 3. Configure API key
cp .env.example .env
# Then edit .env and paste your Gemini API key.
# 4. Preprocess media (OCR + ASR + VLM + embeddings) — cached, safe to rerun
.\run.ps1 preprocess
# 5. Route messages -> output.csv
.\run.ps1 route
# 6. Evaluate on solved sample rows
.\run.ps1 evalLinux / macOS users can substitute make install, make preprocess, etc.
Only one is required:
| Var | Required | How to get |
|---|---|---|
GEMINI_API_KEY |
yes | https://aistudio.google.com/apikey (free tier, no credit card, ~250 requests/day) |
DEVICE |
no | auto (default), cuda, or cpu |
HF_HOME |
no | HuggingFace model cache dir (defaults to ~/.cache/huggingface) |
The Gemini API key is the only external secret. Everything else is local.
- Disk: ~15 GB for downloaded model weights (Qwen2.5-VL 7B AWQ ~5 GB, faster-whisper large-v3 ~3 GB, BGE-M3 ~2 GB, PaddleOCR ~200 MB).
- GPU (recommended): any NVIDIA card with ≥12 GB VRAM for Qwen2.5-VL. Everything else runs on CPU. If you have no GPU, the VLM automatically falls back to Florence-2.
- RAM: 16 GB minimum, 32 GB recommended.
If pip install paddlepaddle paddleocr fails on Windows:
- Use Python 3.11 (not 3.12+).
- Install
paddlepaddlefrom https://www.paddlepaddle.org.cn/en (pick your CUDA or CPU wheel), thenpip install paddleocrseparately. - If Visual C++ redistributable is missing, install the latest MSVC redistributable.
If pip install autoawq fails and you have no NVIDIA GPU, just remove that line —
the VLM will use Florence-2 which does not require AWQ.
If pip install torch picks the CPU wheel by mistake, install the CUDA wheel first:
pip install torch --index-url https://download.pytorch.org/whl/cu121code/
main.py thin wrapper around src.router.main
config.yaml all thresholds + weights
requirements.txt
.env.example
Makefile Linux/macOS entry points
run.ps1 Windows entry points
prompts/
router.jinja2 LLM prompt template (arrives in T9)
src/
data/ loaders + join layer
features/ receiver / sender / group / content / priority
pipelines/ ocr, asr, vlm preprocessors (cached)
retrieval/ bge-m3 embeddings + two-stage retrieval
llm/ gemini client
router/ rules gate, main loop, postprocess, fallback
eval/ metrics + sample-row harness
cache/ created at runtime (OCR/ASR/VLM/embeddings/LLM)
outputs/ output.csv lands here
View routing statistics, action distribution, and message type analytics.
Browse all processed messages with confidence scores, routing decisions, filters, and explanations.
Inspect why a particular message was classified as Notify, Digest, or Mute, along with confidence and retrieved evidence.
Enter a WhatsApp message and route it in real time.
The router returns the predicted action, confidence score, and routing reason.
Expand the explanation panel to understand the reasoning behind every routing decision.
Visualize the decision pipeline, retrieved context, detected content signals, and feature contributions.
## DeterminismAll local models are pinned by hash via requirements.txt. Gemini uses
temperature=0, top_p=1, seed=42. Every OCR / ASR / VLM / embedding / LLM call
is cached by content-hash. Two consecutive run.ps1 route invocations produce
bit-identical output.csv.






