Skip to content

Repository files navigation

Message Notification Router

An explainable, multimodal routing system that decides whether an incoming WhatsApp message should interrupt a user now (notify), wait for a digest (digest), or be suppressed (mute). It combines message content, user and sender history, group or business context, media extraction, safety checks, and confidence calibration to reduce notification overload without hiding urgent messages.

Built for the solo HackerRank Orchestrate 24-hour hackathon challenge, August 1–2, 2026. The submission ranked 38th out of 1,983 participants.

What it solves

A single inbox can mix family requests, school and society notices, order updates, promotions, forwards, voice notes, image posters, and scams. Static keyword rules miss the recipient's context; forwarding everything creates alert fatigue. This router produces one auditable action, type, reason, confidence, and historical-evidence reference for every incoming message.

Key features

  • Routes text, images, and voice notes into notify, digest, or mute.
  • Personalizes decisions using prior opens, replies, dismissals, opt-outs, group settings, quiet hours, and sender relationships.
  • Retrieves only same-recipient historical messages that predate the target.
  • Treats message text and extracted media as untrusted input and gives scam and prompt-injection signals a deterministic safety veto.
  • Uses schema-constrained Gemini extraction for images and audio, with ffmpeg normalization, content-hash caching, bounded retries, and a second-pass critic for uncertain or conflicting results.
  • Validates output shape, coverage, evidence ownership, chronology, and allowed taxonomy values before writing the submission.
  • Includes 251 automated tests plus evaluation, evidence-quality, robustness, leakage, paraphrase, and counterfactual audit commands.

Architecture and workflow

This is a single orchestration pipeline with three specialist assessments. It does not use independent autonomous agents or majority voting.

CSV dataset + media
        |
        v
Dataset validation --> Gemini media extraction --> SHA-256 cache
        |                       |
        +-----------------------+
        v
Context builder --> historical retrieval
        |
        +--> safety assessment
        +--> personalization assessment
        +--> content assessment
        |
        v
Deterministic arbiter --> confidence calibration --> reason/evidence selection
        |
        v
Output validation --> dataset/output.csv

The cloud model extracts typed media facts; it does not choose the final route. The deterministic arbiter applies safety, opt-out, urgency, quiet-hour, and engagement precedence. There is no conversational memory service: the provided CSV history is the retrieval store, and the local media cache only avoids repeated extraction calls. See SOLUTION.md for the detailed contracts, rules, guardrails, and tradeoffs.

Technology

  • Python 3.10+ and the standard library for routing, retrieval, validation, and evaluation
  • Google Gemini via google-genai for structured image/audio extraction
  • Pillow for image decoding and normalization
  • ffmpeg/ffprobe for audio normalization and duration checks
  • pytest for automated tests

Repository structure

.
├── code/
│   ├── main.py                 # routing CLI
│   ├── extract_media.py        # extraction/cache CLI
│   ├── audit.py                # adversarial audits
│   ├── reports.py              # media and evidence reports
│   ├── evaluation/             # visible-sample metrics
│   ├── prompts/                # extraction prompts
│   ├── router/                 # pipeline implementation
│   └── tests/                  # automated tests
├── dataset/                    # challenge inputs, media, and canonical output
├── .env.example                # safe configuration template
├── requirements.txt            # direct dependencies
├── requirements-lock.txt       # fully resolved CPython 3.13 environment
├── problem_statement.md        # organizer-provided task statement
└── SOLUTION.md                 # detailed technical report

Prerequisites

  • Python 3.10 or newer
  • ffmpeg and ffprobe on PATH for voice-note preprocessing
  • A Gemini API key only when extracting media that is not already cached

Installation

# From the repository root:
python3 -m venv .venv
source .venv/bin/activate                # Windows: .venv\Scripts\activate
python -m pip install -r requirements.txt
cp .env.example .env

Install ffmpeg separately when media extraction is needed:

sudo apt-get install ffmpeg              # Debian/Ubuntu
# brew install ffmpeg                    # macOS

Set GEMINI_API_KEY in .env before the first uncached extraction. Never commit .env. If no key or cache is available, the router still completes using captions and structured context, reports missing extraction explicitly, and lowers confidence for affected rows.

Environment variables

Variable Required Default Purpose
GEMINI_API_KEY For uncached media Gemini credential
GEMINI_MODEL No gemini-3.6-flash Structured multimodal extraction model
ROUTER_REPO_ROOT No repository root Base path for other defaults
ROUTER_DATASET_DIR No dataset Challenge dataset directory
ROUTER_OUTPUT_PATH No dataset/output.csv Canonical prediction output
ROUTER_CACHE_DIR No .router_cache Local extraction cache
ROUTER_MEDIA_ENABLED No 1 Set to 0 to disable media
ROUTER_MEDIA_WORKERS No 2 Maximum parallel extraction calls
ROUTER_MEDIA_TIMEOUT_SECONDS No 600 Per-request/preprocessing timeout
ROUTER_ASR_CHUNK_SECONDS No 60 Long-audio window length
ROUTER_ASR_CHUNK_OVERLAP_SECONDS No 5 Long-audio overlap

Run

# Extract and cache referenced media. This may call Gemini.
python code/extract_media.py --verbose

# Route all 110 target messages. Normal runs are cache-only by default.
python code/main.py

# Validate an existing output without changing it.
python code/main.py --validate-only

# Inspect one decision trace.
python code/main.py --explain msg_023

Useful fallback and diagnostics:

python code/main.py --no-media
python code/extract_media.py --report-only
python code/evaluation/main.py --errors --ablations
python code/reports.py all
python code/audit.py all
python -m pytest code/tests -q

The canonical output has exactly these columns:

message_id,action,message_type,reason,confidence,evidence_message_ids

Validation results

Validated locally on Python 3.13:

  • 251 tests passed.
  • All 110 target messages produced schema-valid decisions.
  • All emitted evidence belongs to the recipient and predates the target.
  • Shuffle, message-ID rename, and repeated-run audits were deterministic.
  • The 30 visible solved examples reached 1.000 action and type accuracy.

The last result is training-set fit, not a held-out benchmark: rules and thresholds were iterated with those examples visible. It must not be interpreted as expected hidden-set performance. Run the commands above to reproduce the current local reports.

Design decisions and tradeoffs

  • Rules over a second routing model: deterministic precedence makes safety and notification decisions inspectable, but hand-built multilingual concepts do not generalize like a large trained classifier.
  • Model extraction, not model routing: Gemini handles multimodal perception; trusted dataset fields and local checks retain control of the route.
  • Grounded evidence or abstention: unrelated history is emitted as none instead of being cited for appearance's sake.
  • Cache by content hash: repeated runs avoid API calls, while a fresh model or prompt version can change extraction results.

Demo and screenshots

There is no hosted demo or application UI. The --explain command is the project's inspectable CLI demo. No decorative screenshots were added; the repository's images are challenge inputs, not product screenshots.

Known limitations

  • The visible sample is not a held-out evaluation set.
  • Cross-lingual matching uses an auditable, hand-written concept map rather than general multilingual embeddings.
  • Media quality and reproducibility depend on the selected Gemini model unless the matching local cache is present.

Future improvements

  • Evaluate on a genuinely held-out, licensed dataset.
  • Replace the small cross-lingual map with a measured multilingual retriever.
  • Add privacy-preserving user feedback and longitudinal calibration.
  • Package a synthetic fixture dataset so the public code can run without redistributing challenge assets.

License and acknowledgements

The original solution code is released under the MIT License. HackerRank's challenge statement, starter files, dataset, and media remain HackerRank competition materials and are included with redistribution permission; see THIRD_PARTY_NOTICES.md.

Built by abhinavgulisetty for HackerRank Orchestrate. HackerRank and WhatsApp are acknowledged solely for competition and problem context; no affiliation or endorsement is implied.

About

Explainable multimodal notification router with personalized retrieval, Gemini media extraction, deterministic safety guardrails, and calibrated decisions.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages