Nyayagraph
Independent project · 2026
A legal research assistant over 2,037 Indian Supreme Court criminal-appeal judgments that answers in plain language and cites the exact paragraph behind every claim, built on a knowledge graph extracted from the judgment PDFs.
Lawyers need case law they can check paragraph by paragraph, and since July 2024 they need it across two sets of codes: a question about BNSS s.528 has to find the decade of judgments decided under CrPC s.482.
- Fine-tuned Qwen2.5-7B with QLoRA on two Kaggle T4s for legal entity extraction: 0.879 strict F1 on InLegalNER, ahead of a fine-tuned InLegalBERT (0.856; +0.023, 95% CI [+0.015, +0.030]) and up from 0.334 zero-shot. Every predicted string is aligned back to the source text, so nothing the model invents reaches the graph.
- Built a Neo4j graph of 8,219 cases, 57,314 paragraphs and 832 old-to-new section mappings (IPC to BNS, CrPC to BNSS, Evidence Act to BSA), linking "(supra)" precedent mentions at 0.980 precision with fuzzy matching plus a Claude Haiku tie-break. Lawyers and lower courts from the NER pass let a question like "appeals from the Bombay High Court" search only those judgments: relevant paragraphs in the top 10 rose from 20% to 93% on a 10-question benchmark.
- Benchmarked retrieval on 279 held-out questions derived from law-report headnotes: BM25 with graph re-ranking (MRR 0.640) beat dense embeddings by 0.255 MRR, and a cross-encoder reranker that gained 5 points on dev did not replicate on test, so neither ships. Answers stream from Claude with native citations; 120 of 131 cited passages are word-for-word text of the paragraph they cite.
NER strict F10.879
retrieval MRR0.640
cited passages verbatim120 / 131
Qwen2.5-7B QLoRAvLLMInLegalBERTNeo4jBM25Claude APIFastAPIReact
ClearSight
A multi-agent AI analyst that lets non-technical clients query campaign data in plain English, with a verification gate that keeps unverified numbers from ever reaching them.
Clients want plain-English answers about campaign performance, but a chatbot that occasionally hallucinates a number is worse than no chatbot at all.
- Orchestrated router, text-to-SQL, RAG, diagnostic, report, and translator agents as a single LangGraph StateGraph with conditional routing and multi-turn context.
- Built a QA verification gate: every numeric claim is extracted, re-executed against the underlying data, and repaired or escalated to a human analyst rather than shipped as a guess.
- Validated with a 150-question benchmark against single-agent and ablated (no-QA, no-translator) baselines, tracking accuracy, hallucination rate, and escalation precision/recall with full audit logging and deterministic replays.
unverified numeric claims shipped0
LangGraphStateGraph orchestrationText-to-SQLRAGAWS Bedrock
Heterogeneous Uplift Modeling for Campaign Incrementality
A PySpark pipeline estimating per-household incremental sales lift for CPG campaigns across a 2M-person matched panel, so targeting spend goes toward customers the campaign actually moves.
Average treatment effects tell you whether a campaign worked overall, not which customers it worked for.
- Implemented an R-learner (Double Machine Learning) with cross-fitted gradient-boosted nuisance models in PySpark on Databricks to estimate per-household CATE across a matched 2M-person panel.
- Engineered 230+ leakage-controlled pre-period features across transactions, ACR/CTV viewership, and demographics, with strict pre-campaign cutoffs and cross-fitting.
- Achieved 0.87 decile rank correlation between predicted and realised lift out-of-sample, and distilled the resulting 2M lift scores into deployable segments via a decision-tree surrogate.
decile rank correlation0.87
PySparkDatabricksR-learner (Double-ML)Gradient-boosted treesDecision tree segmentation
Multi-Level Segmentation Using a 2-Stage Model
A two-stage consumer segmentation framework, calibrated to census distributions, that regenerates itself daily as underlying data changes.
Single-pass segmentation models tend to blur boundary cases between similar segments.
- Built a two-stage framework: a multiclass model handles preliminary segment assignment, and binary classifiers refine the boundary cases into a final allocation.
- Calibrated survey-seeded sample weights to census distributions so segments stay representative and scalable rather than reflecting survey-response bias.
- Automated the pipeline as a daily scheduled job that regenerates segments as transactional and census data change, eliminating a manual refresh process.
PySparkMulticlass classificationBinary classifiersSample weight calibrationDatabricks Workflows
Propensity-Based Synthetic Control Modeling
A matched-twin methodology for measuring campaign sales lift at scale when a clean randomized control group isn't available.
Without a true randomized control, you need a synthetic control group that's a statistically valid stand-in for what would have happened without the campaign.
- Developed a propensity-to-buy model and a complementary sales-prediction model over engineered RFM and time-windowed transactional features, fused into a composite score for selecting statistically comparable controls.
- Built a scalable matching algorithm pairing 5M test IDs with their nearest composite-score controls, avoiding infeasible full cross-joins, at a 96% match rate.
- Productionized independent per-brand models so synthetic control generation for any new campaign runs on-demand through a standardized scoring-and-matching pipeline.
match rate96%
IDs matched5M
PythonPySparkPropensity modelingSynthetic controlScalable matching