Skip to content

in-rolls/jaali

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

jaali

जाली — forged / fake. A jaali ration card is the colloquial term for a fraudulent ration card in India.

jaali is a forensic toolkit for Indian PDS (Public Distribution System / ration) data. It finds duplicate and suspicious ration-card images in a Google Cloud Storage bucket and joins them to the PDS relational tables to surface fraud signals — one photo used across many cards, the same person holding multiple cards, ghost beneficiaries — with reproducible, offline HTML review viewers. Report only — it never modifies the source data.

⚠️ Privacy / PII. The inputs and every output (manifests, duplicate clusters, applicant names, card numbers, face thumbnails, annotations) describe real people and are personal data. They are git-ignored by design — never commit, publish, or share data/, out*/, inspect/, or any *.csv / *.parquet / thumbnail produced here. This repo is code only.

Data it works with

Built for the Rajasthan PDS corpus:

  • Card imagesgs://ration/{rural,urban}/jpg/<cardnumber>.jpg (~15.85M rural images; each object is named after its 12-digit ration card number). Note: gs://ration is requester-pays, so a non-owner identity must pass a billing user_project.
  • Relational tables — Harvard Dataverse doi:10.7910/DVN/FIFZEX ("Transaction Level Ration Data from Rajasthan"): rationcard (Card_Type APL/BPL/AAY, Applicant_Name, FPS, geography), rationcarddata, rationcardfamily, rationcardtransaction (offtake), fps. Join key = Ration_Card_Number = the image filename, zero-padded to 12 digits. Access is token-gated (Dataverse API key; the access endpoint 303-redirects to S3).

Pipeline

Image stages (python -m jaali)

Stage Method Cost
0 manifest List objects + metadata (name, size, content-type, MD5, crc32c) → streamed parquet GCS list ops — ~free
1 exact Group by GCS-stored MD5 → byte-identical files (DuckDB; no downloads) ~free
2 near Download pixels, dHash + pHash (256-bit), cluster within a Hamming threshold via a BK-tree ~$4 / 10M in-region
issues Zero-byte / non-jpeg / unreadable, anomalous filenames, suspiciously large clusters free
viewer Static offline HTML to annotate a sample of flagged pairs free
report summary.md roll-up + cost free

Every flag is an edge: the file, the file it is similar to, a score, and a human-readable reason (exact_edges.csv / near_edges.csv).

How "near-duplicate" is decided: two images match if either perceptual hash is within a small Hamming distance — dHash (gradient; robust to re-compression / brightness) ≤ --dhash-max (default 6) or pHash (DCT structure; robust to crop/scale) ≤ --phash-max (default 8), i.e. ≤ ~2–3 % of bits differ. Matches are unioned into groups; a BK-tree avoids O(n²) comparison. Exact (MD5) dups are a strict subset, annotated also_exact.

Forensic detectors (python -m jaali.forensics)

Joins the duplicate-photo clusters to the PDS card metadata and grades suspicion:

  1. Photo impersonation — one byte-identical photo (MD5) registered under many distinct applicant names across multiple shops; strongest on subsidised (BPL/AAY) cards. (Real example in the Rajasthan data: one face on 1,078 cards under 943 different names across 42 fair-price shops.)
  2. Duplicate identity — same Applicant_Name + Father_Name in the same village on more than one card (duplicate-beneficiary enrolment).
  3. Cross signal — cards that trip both a photo cluster and a duplicate identity (highest confidence).

Outputs: fire1_photo_reuse.csv, fire2_duplicate_identity.csv, forensic_summary.csv. Heuristic note: near-blank template images (~600–1000 B) and the rare corrupt file are flagged separately so they are not mistaken for real impersonation; size + the viewer resolve them.

Review viewers (python -m jaali.cluster_review)

Static, offline HTML (open index.html — no server). Reproducible seeded weighted sampling (weight ∝ how often an image is duplicated; big clusters always included):

  • --mode clusters — all duplicate clusters, concern-first.
  • --mode impersonation — Fire-1 ranked by number of distinct names, showing the shared photo, the applicant names it is registered under (one per line), and badges (distinct names / shops / districts / subsidised / likely-blank).

Annotators label each item and Export annotations.json.

Install

python3 -m venv .venv
.venv/bin/python -m pip install -e .          # or: pip install -r requirements.txt
gcloud auth application-default login          # for the image stages

Run

# estimate cost first (no spend)
python -m jaali --dry-run

# cheapest signal: byte-identical re-uploads, no downloads
python -m jaali --stages 0,1 --project <gcp-project>

# full image pipeline
python -m jaali --stages all --project <gcp-project>

# scope/test on a sample
python -m jaali --stages all --max-images 5000 --project <gcp-project>

# forensic join (needs data/rural_rationcard.csv.gz from Dataverse)
python -m jaali.forensics --out out_full --data data

# build the impersonation review viewer (reproducible; seed 42)
python -m jaali.cluster_review --mode impersonation --out out_full --seed 42

At full scale, run the download/compute stages in-region (Cloud Shell or a VM in the bucket's region) to make egress $0. All stages cache to out/ (manifest.parquet, phashes.parquet, CSVs) so reruns never re-download.

Useful flags

  • --stages 0,1,2,issues,viewer,report (or all)
  • --max-images N — cap objects (testing/scoping)
  • --sample N — pairs/clusters in the HTML viewer · --seed N — reproducible sample
  • --dhash-max / --phash-max — near-dup thresholds
  • --budget $ — abort the download stage if estimated cost exceeds this
  • --workers N — parallel download workers (default 32)

Cost guardrail

The only way this gets expensive is paid per-image cloud APIs (Vision OCR / web-detection) across the full corpus — at Vision rates that is tens of thousands of dollars for ~10M images. jaali deliberately uses local / open-source methods for the full sweep; the image pipeline over the whole rural set costs single-digit dollars (and $0 egress in-region). --dry-run prints an estimate; --budget caps spend.

License

MIT — see LICENSE.

About

Forensic toolkit for Indian PDS (ration) data: image dedup + fraud detection (photo impersonation, duplicate identities)

Resources

Stars

Watchers

Forks

Releases

Packages

Used by

Contributors

Languages