01 · RegRAG 02 · Negotiation Gate 03 · Voice Agent Audit 04 · Sanwaad 05 · LMA Clause Tool 06 · AutoTransFlow 07 · RAG Chatbot 08 · Medical Bill OCR 09 · Multilingual ASR 10 · Market Analysis 11 · OpsAgent 12 · Audit Insight 13 · Career Copilot 14 · AirFare-ML 15 · Hastkala Setu 16 · Road Safety NLP 17 · HydRERA Analytics 18 · KG-RAG Legal AI 19 · StemCells DBMS
Project 1 · Personal Project · Nov 2026
RegRAG:
RBI Banking-Regulation RAG Benchmark
A question-answering tool and benchmark for RBI banking rules. It answers with page citations, says "not found" when the documents do not support an answer, and compares six RAG designs on the same questions.
RAG Evals Regulatory AI
The Problem
Banking regulation is a hard test for RAG: long documents, clauses that cross-reference each other, tables, amendments, and answers where a wrong reply is costly. Most RAG demos show one pipeline working, and none says where it fails.
The Approach
Six designs (classic, hybrid, graph, agentic, STAIR-inspired and OKF-style) on the same questions, with six techniques added one at a time and scored before and after. An evidence gate refuses to answer when the sources do not support it, and everything runs on a CPU-only laptop through Ollama.
The Impact
Early result: on 26 KYC questions over a 373-chunk corpus, hybrid retrieval put the right page in the top 5 for 92% of questions (96% on a looser page match), ahead of BM25 at 85% and dense search at 88%. The end-to-end benchmark has not been run yet, so its result tables are empty on purpose.
6
Pipelines compared
0.92
Hybrid recall@5 (26 questions)
57
Seed golden questions
49
Unit tests
System Architecture — Guardrails, retrieval, and an evidence gate
Question → guardrails → rewrite → pipeline → rerank → evidence gate → cited answer or "not found"
A question is checked for scope and personal data, rewritten, and sent to one of six retrieval designs. The top chunks are reranked, and an evidence gate decides whether the sources really support an answer. If they do not, the system abstains instead of guessing.
Question About RBI Master Directions "Is an Aadhaar number mandatory for KYC?" Input guardrails Refuse off-topic questions Mask Aadhaar, PAN, phone No legal or financial advice Query rewriting Clearer standalone query added as one measured technique, not assumed Six pipelines Classic · Hybrid · Graph Agentic · STAIR-inspired OKF-style same questions for all Top chunks + metadata BM25 + bge-m3 embeddings fused by RRF document, chapter, date hybrid recall@5 0.92 Reranker bge-reranker-v2-m3 reorders the top 20 low score can stop early threshold not tuned yet Evidence gate NLI check on each claim LLM-judge fallback number-grounding check abstain over guess Answer or "not found" Document and page citation "Updated as on" date shown stale-source warning no unsupported claims Early development: the gate and guardrails are unit-tested with fake models and not yet measured end to end.
Step-by-step workflow
01
Corpus and chunking
14 RBI Master Directions registered with source URL, date, page count and SHA-256 (RBI blocks scripted downloads, so files are saved by hand). Four are indexed so far, split by chapter and clause with document, chapter, date and amended-flag metadata.
Python · ChromaDB · MANIFEST.json
02
Retrieval and reranking
BM25 keyword search and bge-m3 dense search fused by reciprocal rank fusion, then reordered by a cross-encoder reranker. Classic and hybrid pipelines are written; graph, agentic, STAIR-inspired and OKF-style follow.
rank-bm25 · bge-m3 · bge-reranker-v2-m3
03
Evidence gate and guardrails
Answers need a document and page citation or the system abstains. Retrieved text is treated as data, never as instructions. Personal numbers are masked in inputs and logs, and a 20-item safety set covers advice, off-topic, injection and stale-source cases.
NLI · LLM judge · config.yaml
04
Evaluation
A tagged golden set (lookup, table, multi-hop, amendment, unanswerable) with a seeded train/test split, so thresholds are tuned on one half and reported on the other. RAGAS and DeepEval are planned in GitHub Actions with thresholds.
RAGAS · DeepEval · GitHub Actions
Technical decisions
  • Measure, don't claim: six techniques (chunking, metadata, hybrid search, query rewriting, reranking, strict prompt) are added one at a time with a before and after score, and the results tables stay empty until a number is measured.
  • Abstain over guess: an evidence gate refuses to answer when the retrieved sources do not support it, and every claim needs a document and page citation.
  • Local first: query time runs on a CPU-only laptop with Ollama (qwen3:4b). Cloud models are optional, used only for one-time indexing or judging, and flagged wherever used.
  • Honest evaluation: every golden question is checked against the source PDF page by an LLM, not a human, and the README says so.
Key results (early)
  • Retrieval check, 26 questions, 373 chunks, recall@5 (strict / loose): BM25 0.85 / 0.96, dense 0.88 / 0.92, hybrid 0.92 / 0.96, hybrid with reranker 0.92 / 0.96
  • At rank 1: hybrid 0.69 / 0.88 against 0.58 / 0.69 for BM25 alone
  • Reranker limit: it only reorders the same 20 candidates, so it cannot raise recall at 20
  • Smoke test, not a measurement: with a small qwen3:1.7b model, 1 lookup was answered with a page citation, 3 unanswerable questions were correctly refused, and 1 multi-hop question was wrongly refused
  • Stack: Python, Ollama, bge-m3, ChromaDB, rank-bm25, FastAPI, GitHub Actions; planned: LightRAG, RAGAS, DeepEval
Key Insight
Treat the differences between retrieval rows as noise. Only 26 questions were used (one question is about 4 points), the corpus is small, the questions follow the document's own wording, and the gold pages were checked by an LLM rather than a person. The full benchmark across all six pipelines has not been run, and the project is in early development.
⊕ View on GitHub → github.com/Harshaaalll/regrag
Project 2 · OTO Capital · Aug – Nov 2026
Collections Voice Agent:
Deterministic Negotiation Gate
A production Gemini Live voice agent for loan-collection calls in 10 Indian languages, where negotiation policy lives in a Python state machine that approves or refuses every tool call before the model speaks. Delivered for Jana Small Finance Bank, Swarnodhayam MFI, Fusion MFI, Seed Fincap and Satin.
Voice AI LLM Agents Evals
The Problem
A collections call is regulated and irreversible, and a policy written in a prompt is only a suggestion. The model conceded early, hung up mid-negotiation, invented figures, read internal refusals aloud and disclosed loan details to strangers.
The Approach
Move negotiation policy out of prose into a deterministic Python gate (4 gated tools, 6 severity bands, 3 concession steps) that approves or refuses each tool call in microseconds, before the model speaks. All situational content moved into tool responses, so the prompt carries only what is true on every turn.
The Impact
Prompt tokens per turn fell 78% (16,558 to 3,596). 49 defects found in live-call reviews are each pinned by a committed regression check (201 at the first milestone), with the control arm byte-identical on every change. A simulated-borrower harness runs 500+ calls per change in seconds.
78%
Fewer prompt tokens
201
Regression checks
49
Live-call defects fixed
10
Languages, 5 clients
System Architecture — A gate between the model and the call
Borrower call → Gemini Live → deterministic gate → tool response → telemetry, analytics and regression
The model proposes a tool call, and the Python gate approves or refuses it with a reason before anything is said. Every call writes telemetry that is joined to payments. A simulator and a committed regression suite keep each change honest.
Borrower call Exotel telephony 10 languages, barge-in sub-200ms latency budget Gemini Live Native-audio speech to speech Pipecat + FastAPI proposes a tool call Negotiation gate Python state machine 4 gated tools, 6 severity bands approves or refuses first Tool response Reason, floor, consequence scenes and opener lines paid once, only when relevant prompt stays small Telemetry + A/B arms 33 fields persisted per call joined to payments arm by SHA-256 of account id control arm always represented Post-call analytics Dispositions, commitments Persona and PTP verification text steps on OpenAI Gemini fallback per call Simulated borrowers 5 archetypes, seeded 500+ calls per change no audio, model or database tests policy, not wording Regression suite One check per live defect prompt and gate pinned to agree on shared rules control arm byte-identical The gate verifies before the model speaks: speech is irreversible, and an LLM verifier would add 500ms+ per turn.
Step-by-step workflow
01
Onboard clients
Mirrored the full contextual call stack for Jana Small Finance Bank, then Swarnodhayam MFI, Fusion MFI, Seed Fincap and Satin. Hindi, Tamil and eight more languages, with identity confirmed before any account detail is spoken.
Gemini Live · Pipecat · Exotel
02
Gate the policy
20 consequences that never repeat in a call, a concession ladder from 1500 to 1200, 1000 and 750 rupees, a date ladder (today, 2 days, 7 days, then escalate) that never crosses the month, a figure ratchet and a post-link hold.
Python · 2,732-line gate
03
Mine and measure
36,091 call rows narrowed to 8,600 connected calls, 42 with a verified same-day payment, 26 analysed and 12 curated scenes. Same-day promises converted at 14.1% against 7.3% for next day. Outcomes are joined to payments by arm.
PostgreSQL · SQL · A/B arms
04
Review live calls
Each live transcript was traced to a line of code across 16 review cycles, 49 defects in all, and pinned by a regression check. The simulator found two real bugs on its first run, lifting one case from 580 to 880 rupees per simulated call.
pytest · simulator · QA signals
Technical decisions
  • Deterministic gate over an LLM verifier: a verifier adds 500ms+ per turn against a sub-200ms voice budget, and speech cannot be unsaid, so the gate decides before the model speaks.
  • Situational content in tool responses, not the prompt: a system prompt is paid on every turn of every call, a tool response only once and only when relevant. Over six review rounds the prompt moved by 69 characters while the gate absorbed every new behaviour.
  • Identity as a confidence, not a coin flip: strong signals latch, weak ones ask "Kya main X ji se baat kar raha hoon?" and disclose nothing, and the check runs ahead of every other branch.
  • Pin the prompt and the gate together: three contradictions between the two shipped, so checks pin every shared rule, each verified by reintroducing the old contradiction and watching it fail.
Key results
  • Prompt cost: 16,558 to 3,596 tokens per turn; a real 22-turn call used about 101K tokens against roughly 370K on the old prompt
  • Compliance: 26 human-collector calls audited against RBI norms, 17 practices flagged and 9 locked as prohibited; three breach classes closed (disclosure, impersonation, prohibited advice)
  • Prompt-cache bug: 117 of 140 cache creations were redundant, about 824,500 tokens; lookup-before-create took 10 restarts to 1 creation
  • Post-call analytics on OpenAI: queue, prompt-builder and narrative steps moved from Gemini to gpt-6-luna with a per-call Gemini fallback. Queue matched Gemini on 99.1% of 3,110 past calls; live for Satin at about 0.22 rupees per call against 0.58, across 8,402 calls with 15 fallbacks
  • Language fix: a sweep of 24,493 Hindi replies found 0 Tamil-script runs, down from 60 distinct runs before
  • Stack: Gemini Live, Vertex AI, Pipecat, FastAPI, OpenAI Responses API, PostgreSQL with asyncpg, AWS RDS, GCP, Exotel
Key Insight
Broad patterns match the person they protect. Three separate times a detector wide enough to catch a stranger also caught the borrower, for example "main bol raha hoon", which is how anyone answers a phone in Hindi. The identity latch is one-way, so a false positive costs the whole call while a false negative costs one turn. Each was found only by replaying a transcript, so every identity-detector change is now tested in both directions.
Repository
Private company repository at OTO Capital. Open items: the latest gate version has not yet run on a real call, and Hinglish transcription accuracy has not been measured against the roughly 400 romanised patterns the gate relies on.
Project 3 · Personal Project · Oct 2026
Voice Agent Audit:
Evaluating a Hinglish Voice Agent
Evaluation and audit kit for a Hinglish payment-reminder voice agent: rule checks, an LLM judge checked against human labels, hybrid retrieval evals, and a FastAPI service on PostgreSQL with pgvector.
Evals RAG Voice AI
The Problem
A voice agent that calls borrowers must follow strict rules: no threats, no invented fees, and never reveal loan details to a wrong number. You cannot test it on real calls, and an LLM judge cannot be trusted until it has been checked against people.
The Approach
Synthetic Hinglish borrowers with speech-recognition noise, seven rule checks, a judge model scored against human labels with Cohen's kappa, BLEU and chrF with a fact check, harmless-edit tests, and hybrid retrieval over a policy corpus in pgvector, all behind a FastAPI service with Redis and Langfuse tracing.
The Impact
On 120 real-model scenarios per prompt variant, retrieving only the matching rules cut prompt tokens by 43.5% (806 to 455) and the right action was chosen 119/120 times. Hybrid retrieval reached recall@3 0.53, against 0.45 for BM25 alone. 175 tests run without an API key.
43.5%
Fewer prompt tokens
119/120
Correct actions (pruned)
0.53
Retrieval recall@3
175
Tests
System Architecture — Layered evaluation and a retrieval service
Synthetic call → agent → rule checks → judge checked against humans → retrieval and service
Practice calls with known answers go to the agent. Rules catch the clear mistakes, and a second model judges the rest. Its agreement with human labels is measured before it is trusted. The same agent is also served with retrieved policy, traced and queued.
Synthetic calls 6 intents, 3 language styles ASR noise added on purpose right answer known in advance Agent under test Gemini, Ollama or mock static vs pruned prompt reply plus tool call Rule checks 7 deterministic checks: format, action, amounts, threats, disclosure, length Judge vs humans Judge must be a different model from the agent Cohen's kappa vs human labels bias probes Hybrid retrieval Policy chunks in pgvector BM25 + multilingual embeddings, fused by RRF recall@3 0.53 on 49 queries FastAPI service /respond /evaluate /retrieve PostgreSQL store Docker Compose 175 tests, run offline Redis Judge-call cache Job queue and worker runs resume after a stop Langfuse · Dashboard Traces, tokens, latency Static HTML dashboard unmeasured is shown as such Every number is either measured on the pipeline above or labeled as unmeasured.
Step-by-step workflow
01
Synthetic calls
Generated borrowers across six intents (pay, need time, hardship, dispute, wrong number, abusive) and three language styles, with noise that mimics speech recognition. The correct action is known in advance.
Python · seeded generator
02
Layered checks
Seven deterministic rules, a judge model that must differ from the agent, kappa against human labels, bias probes for position and length, BLEU and chrF with a fact check, and metamorphic tests.
pytest · promptfoo · CI
03
Hybrid retrieval
34 policy chunks in pgvector, searched with BM25 plus multilingual embeddings fused by reciprocal rank fusion, then scored with recall, hit rate and MRR.
pgvector · BM25 · RRF
04
Service and tracing
FastAPI endpoints store runs in PostgreSQL. Redis caches judge calls and queues evaluation jobs for a worker. Langfuse traces each call, and real-model runs resume after a quota stop.
FastAPI · Redis · Langfuse
Technical decisions
  • Judge must differ from the agent: enforced in code, and the report prints "unmeasured" for any criterion with no human labels yet.
  • Hybrid over dense-only retrieval: a multilingual embedding model alone scored recall@3 0.54 on English queries but only 0.11 on Hinglish; adding BM25 recovered it.
  • Built for free-tier limits: retries, a fail-fast on daily quota, and an on-disk response cache so a stopped run costs nothing to resume.
Key results
  • Prompt pruning: 806 to 455 tokens; decision 120/120 (static) vs 119/120 (pruned); account-disclosure check 118/120 vs 115/120, within noise
  • RAG costs accuracy here: on 40 scenarios the decision was right 40/40 with the full static prompt, 39/40 pruned, and 31/40 with retrieved policy; context recall was only 0.39 (95% CI 0.26 to 0.53)
  • Metric blind spot: BLEU scored a wrong-amount translation about 0.90; a fact check catches it
  • Process: an independent test agent found 29 issues across four slices (24 defects, 5 minor) before they were merged
  • Stack: Python, FastAPI, PostgreSQL with pgvector, Redis, Docker Compose, Langfuse, GitHub Actions, promptfoo
Key Insight
The data is synthetic and the retrieval gold set is small, so these numbers show that the pipeline works and where retrieval breaks, not how a production agent performs. Judge-versus-human agreement is reported only once human labels exist, and until then it is shown as unmeasured.
⊕ View on GitHub → github.com/Harshaaalll/Voice_Agent_Audit
Project 4 · Personal Project · Sep 2026
Sanwaad:
Multi-Agent Complaint Resolution
Multi-agent complaint resolution with human-approved actions and trace-level evals. LangGraph · Gemini · hybrid RAG.
AI Agents RAG Evals
The Problem
Public complaints about a company often never reach support. Someone has to find them, work out whether the author is a real customer, a troll or a bot, reply in line with written policy, and fix the problem — without a model ever moving money on its own.
The Approach
A LangGraph case pipeline with Listener, Pattern, Judge and Ghostwriter agents, each with a declared contract. Replies are grounded in policy through local hybrid RAG. Refunds are only suggested by the model; code checks them against the ledger and a person approves the exact amount.
The Impact
15/15 offline trajectory scenarios passed with 0 safety violations. Hybrid retrieval reached recall@5 1.00. Loop evals rose from 3/13 to 13/13 passing scenarios. 472 tests run without an API key.
472
Tests
15/15
Trajectory scenarios
1.00
Recall@5
0
Safety violations
System Architecture — Multi-agent case pipeline
Complaint → triage → grounded reply → validated fix → human approval
A complaint enters on the left. Agents classify the author, rank the case and retrieve policy; a reply is drafted and checked against that policy. Any money action is validated by code and paused for a person to approve the exact amount before it executes.
Public complaint Reviews and posts that are not tagged at the company Listener · Triage Finds the complaint Author: customer, audience, troll or bot Pattern · Judge Each agent declares the state it writes and the tools it may call Prioritise Priority score and author score, explained in the console Retrieve Local hybrid RAG BM25 + ONNX embeddings merged by RRF Hindi · English · Hinglish Ghostwriter Reply grounded in written policy Ground check verifies bounded rewrite loop Plan · Lookup Model only suggests a fix; code checks it against the ledger 9 validation checks Human review gate A person approves the exact amount, bound to a digest of the arguments executor re-checks Publish · Act · Close Posting is disabled unless explicitly enabled Audit records redacted The model suggests, code verifies, a person approves — no model moves money on its own.
Step-by-step workflow
01
Case pipeline
Listener → triage → pattern → judge → prioritise → retrieve → ghostwriter → ground check (bounded rewrite loop) → plan → lookup → review gate → publish → act → close.
LangGraph
02
Hybrid retrieval
ONNX multilingual embeddings plus BM25, merged with reciprocal rank fusion. Handles Hindi, English and Hinglish policy text.
BM25 · RRF · ONNX
03
Human approval gate
Each money action pauses for a person. The approval is bound to a digest of the exact arguments, and the executor re-checks before anything runs.
Interrupt · digest check
04
Reliability and evals
Per-step timeouts, token caps, fallback models, dead-letter queue, circuit breakers, and trace-level evals including a 13-scenario loop ladder.
pytest · eval harness
Technical decisions
  • Model suggests, code decides: nine named validation checks run on every proposed fix before it reaches a reviewer.
  • Hybrid over dense-only retrieval: reciprocal rank fusion scored strict@5 1.00 against 0.89 for dense-only on 19 golden cases.
  • Earned autonomy: a reply type posts without review only after reviewers have agreed with it repeatedly; policy thresholds are editable only within hard bounds, with a revertible log.
Key results
  • Trajectory eval: 15/15 scenarios, tool-call success 0.973 with injected outages, median case latency about 1.3 s
  • Loop eval (MINT ladder): 3/13 to 13/13 passing; unsafe answers 1 to 0 from the second rung
  • Console: review UI with cases, model comparison, policy and explanation tabs, plus role-based accounts
  • Stack: Python, LangGraph, FastAPI, SQLite, Gemini, Docker, GitHub Actions
Key Insight
Offline evals test the system around the models, not model quality. The payments ledger and ticket desk are mocks and the sample feed is 15 seeded comments, so the numbers show that the safety and control layers work, not how well a live model performs.
⊕ View on GitHub → github.com/Harshaaalll/sanwaad
Project 5 · Standard Chartered GBS · Jul–Dec 2025
LMA Clause
Identification Tool
A production NLP pipeline on Dataiku DSS that reads 100+ page Loan Market Association agreements and automatically flags every legally-significant clause — sanctions, indemnities, governing law — that compliance auditors must review. Ships with confidence calibration, semantic search, and an auditor-friendly threshold tuning UI.
NLP Fine-Tuning Production
The Problem
Auditors at a global bank were manually reading 100+ page loan agreements to find ~30 specific compliance-critical clauses. One missed sanctions clause = regulatory failure. The work was slow, error-prone, and didn't scale.
The Approach
Train a small, fast language model (DistilBERT) to recognise each clause type, then add a second-stage semantic search layer that confirms the match against gold-standard reference clauses. Filter low-confidence predictions before showing to humans.
The Impact
90% reduction in audit time. 98.6% recall on rare clauses (the ones that matter most). 95%+ of false positives filtered before reaching auditors. Legal team can review 10× more agreements in the same window.
90%
Audit time reduced
98.6%
Recall on rare clauses
95%+
False positives filtered
0.93
Weighted F1 score
250
Token window size
System Architecture — How the pipeline thinks
End-to-end clause identification pipeline
A 100+ page PDF enters on the left. By the time it exits on the right, every legally-significant clause has been classified, scored for confidence, and matched against a gold-standard reference — ready for auditor review.
INPUT PREP ML CORE VERIFY OUTPUT 📄 LMA Agreement 100+ page PDF ✂️ ETL Chunking 250-token window · 50 overlap 🧠 DistilBERT Classifier Fine-tuned on labelled clauses WeightedTrainer · 20× class boost handles 90%+ irrelevant text 🎯 Confidence Filter Min-correct-confidence threshold Drops uncertain predictions filters 95%+ false positives 🔍 SBERT Semantic Search Fine-tuned w/ MultipleNegatives Cosine vs gold-standard library catches synonym phrasings ✅ Auditor Dashboard Clause · type · confidence · page ref Threshold-tunable per auditor Threshold calibration feedback loop (auditor recalibrates per loan type)
Step-by-step workflow
01
Ingest the agreement
A 100+ page LMA PDF lands in the Dataiku dataset. Text is extracted page-by-page, preserving section markers so we can later cite exact clause locations.
Dataiku DSS · PyMuPDF
02
Slice into context windows
The full text is sliced into 250-token windows with 50-token overlap. The overlap ensures clauses that span window boundaries aren't cut in half. An earlier 75-token version produced 1.0 F1 — a red flag for data leakage.
HuggingFace tokenizer · sliding window
03
Classify with DistilBERT
A fine-tuned DistilBERT classifies each window into one of N clause types (or "irrelevant"). DistilBERT was chosen for being 40% smaller than BERT while retaining 97% of accuracy — critical for batch-processing 100+ page documents at speed.
DistilBERT · WeightedTrainer (20× boost)
04
Calibrate confidence
For each prediction, we check the model's softmax confidence. The "minimum correct confidence" threshold is calibrated per clause type using validation data. Anything below the threshold is dropped before reaching humans.
Custom thresholding · KDE rejected
05
Verify with SBERT
Surviving predictions are embedded with a fine-tuned SBERT and cosine-matched against a curated library of gold-standard reference clauses. This catches synonym rephrasings the classifier alone might rank low.
SBERT · MultipleNegativesRankingLoss
06
Surface to auditors
Output is rendered in a Dataiku web app: each detected clause shown with its type, confidence, page reference, and the matching gold-standard text. A separate UI lets non-technical auditors recalibrate thresholds without touching code.
Dataiku Web App · threshold UI
Technical decisions
  • Why DistilBERT: Encoder-only, optimised for classification. 40% smaller than BERT, 97% of its accuracy — letting us batch-process documents fast.
  • Why 250-token windows: 75-token windows produced a suspicious 1.0 F1, indicating data leakage. 250 tokens preserved context without bleeding.
  • WeightedTrainer: 90%+ of document text is irrelevant. A 20× class weight boost prevents the model from defaulting to "irrelevant".
  • Minimum-correct-confidence: KDE thresholding rejected (no clean incorrect-probability curve). Empirical, data-driven cut-off used instead.
  • SBERT fine-tuning: MultipleNegativesRankingLoss on legal anchor-positive pairs — model learns synonym clauses semantically, not lexically.
Key results
  • Train accuracy: 0.96 · Val accuracy: 0.93 · Weighted F1: 0.93
  • Recall on rare clauses: 98.6% — critical because a missed sanctions clause is a compliance failure
  • False positive reduction: 95%+ filtered — auditors only review high-confidence, relevant predictions
  • Deployment: Dataiku DSS pipeline + threshold-calibration web app for non-technical auditors
  • Business impact: Legal team reviews 10× more agreements in the same time window
Key Learning
The single most important lesson: a perfect F1 score is a red flag, not a success. When 75-token windows produced 1.0 F1, I suspected data leakage — clause text was appearing in both training and validation chunks. Reducing to 250-token windows with careful document-level splits fixed the leakage and produced honest, deployable metrics. Trusting suspicious results would have shipped a broken model into a regulated environment.
⊕ View on GitHub → github.com/Harshaaalll/lma-clause-identifier
Project 6 · Standard Chartered GBS · Aug–Nov 2025
AutoTransFlow:
Multilingual Document AI
A layout-preserving multilingual PDF translation system. Translates financial and legal documents into 200 languages while keeping the exact spatial structure — headings, tables, columns, signatures — intact. Runs entirely on local models with zero external API calls.
Computer Vision Translation Document AI
The Problem
Legal documents must be readable across 200+ jurisdictions. Google Translate destroys layout (turns tables into paragraphs) — and bank policy forbids sending sensitive PDFs to external APIs. We needed a translator that runs internally and preserves every visual structure.
The Approach
Treat each PDF page as an image first, text second. A YOLO-based layout model finds every text block's bounding box; then NLLB-200 translates the text inside each box; finally each translation is re-rendered at its original coordinates.
The Impact
200 languages supported · 0 external API calls · 100% layout fidelity. The translated PDF looks identical to the original — same tables, same columns, same signatures — just in the target language.
200
Languages supported
0
External API calls
100%
Layout preserved
0.25
Detection threshold
System Architecture — Vision-first translation
Layout-aware PDF translation pipeline
The trick: solve a translation problem with a computer vision model first. By detecting the geometry of every text block before translating, we know where each translated word must go on the page.
📑 Source PDF Financial / legal English origin 🖼️ Render Page PDF → image Normalised [0,1] 📐 doc-layout-yolo Detects every text block Outputs (x,y,w,h, type) Confidence > 0.25 heading / para / table 🌍 NLLB-200 600M params · local forced_bos_token_id 200 target languages translates each block 🎯 Re-render BabelDoc font embed Original coordinates "What it says" "What it looks like" "Where text lives" "What it means" "Reassemble doc" The vision-first insight: Traditional PDF tools extract text linearly — losing structure. We treat each page as an image, solve the geometry first with computer vision, then translate inside known boxes. 📋 Final PDF: original document with translated text in identical layout — appended after source page
Step-by-step workflow
01
Duplicate & embed fonts
BabelDoc creates a copy of the source PDF and embeds fonts compatible with the target language (Devanagari, CJK, Arabic, etc.) so translated glyphs render correctly.
BabelDoc · font embedding
02
Render to pixmap
Each page is rasterised to an image and normalised to [0,1] pixel intensity — the input format expected by the layout model.
PyMuPDF · NumPy
03
Detect layout with YOLO
doc-layout-yolo predicts a bounding box and class (heading, paragraph, table, caption) for every text block. Confidence threshold of 0.25 keeps recall high — false detections are cheaper to filter than missing text.
doc-layout-yolo · 0.25 threshold
04
Translate per block
For each box, the text is extracted and fed to NLLB-200 with forced_bos_token_id set to the target language code (e.g. hin_Deva). The model runs entirely on internal hardware.
NLLB-200 · 600M · local inference
05
Re-render at original coords
Translated text is drawn back into each bounding box at its original (x, y, w, h) — preserving the visual structure exactly. Auto font-size adjustment handles language length variance.
PyMuPDF · text-fit logic
06
Stitch & deliver
The original page and its translated counterpart are appended in the final PDF, giving auditors a side-by-side reference. Modular backend lets translation engine be swapped (e.g. Argos Translate).
Final PDF assembly
Why not pdfplumber or PyMuPDF text extraction?
  • Traditional PDF libraries extract text as a linear stream — no understanding of visual structure
  • Cannot differentiate headings from paragraphs, tables from captions
  • Spatial relationships between text blocks are completely lost
  • Output would be a long unformatted text block — legally unusable for financial documents
  • Solution: Treat the page as an image, use computer vision to understand layout first
Why NLLB-200 over Google Translate?
  • Data privacy: Standard Chartered policy prohibits sending documents to external cloud APIs
  • NLLB-200 runs entirely on internal servers — zero data leaves the network
  • forced_bos_token_id: Steers decoder to target language (e.g. eng_Latn, hin_Deva)
  • Covers 200 languages including low-resource languages that Google handles poorly
  • Modular design — translation backend can be swapped (Argos Translate as alternative)
Key Insight
The critical innovation is treating document translation as a computer vision problem first, not a text problem. By using doc-layout-yolo to map the visual structure before extracting text, the system knows exactly where every word lives on the page — not just what it says. This makes it possible to put translated text back in exactly the right position, preserving the legal and structural integrity of the document.
⊕ View on GitHub → github.com/Harshaaalll/autotransflow
Project 7 · DG Liger Consulting · Jun–Jul 2024
RAG Chatbot with
Conversational Memory
Production retrieval-augmented generation chatbot built over proprietary PDF documents. Multi-turn conversation support via LangChain's ConversationalRetrievalChain, with local StableLM Zephyr 3B inference — no external API calls, no data leakage.
RAG LangChain LLM
The Problem
A consulting firm had hundreds of proprietary client PDFs. Analysts wasted hours searching through them for specific facts. They couldn't use ChatGPT — client confidentiality forbids cloud APIs.
The Approach
Build a chatbot that retrieves before it generates. Embed all PDFs into a local vector database, retrieve the most relevant chunks for each question, and let a small local LLM produce a grounded answer — with full conversation memory.
The Impact
Analysts query proprietary docs in seconds. Zero data leaves the network. Multi-turn dialogue means follow-up questions like "and what about the fees?" work naturally. Runs on standard hardware via 4-bit quantisation.
500
Chunk size (chars)
3B
StableLM params
Q4_K_M
Quantisation level
384
Embedding dimensions
System Architecture — Two-phase RAG pipeline
Indexing phase (one-time) + Query phase (per question)
A RAG system has two distinct workflows. The top row runs once when documents are ingested. The bottom row runs every time a user asks a question.
PHASE 1 · INDEXING (RUN ONCE PER DOCUMENT) 📁 PDF Documents Proprietary client docs + web pages ✂️ Recursive Splitter 500 chars · 50 overlap Sentence-boundary aware 🔢 Embeddings all-MiniLM-L6-v2 384-dim vectors 🗄️ FAISS Index In-memory ANN search Persisted to disk retrieved at query time ↓ PHASE 2 · QUERY (RUN PER USER QUESTION) 💬 User Question "What about the fees?" often ambiguous! 🔄 Question Rewriter + ConvBufferMemory → standalone query 🔍 FAISS Retrieve Top-k similar chunks Cosine similarity 🤖 StableLM Zephyr 3B GGUF Q4_K_M · local Grounded generation 💡 Grounded Answer + Source citations Stored to memory Conversation memory loop — every Q&A pair informs the next question's rewriting
Step-by-step workflow
01
Load & chunk documents
LangChain document loaders pull in PDFs and web pages. RecursiveCharacterTextSplitter slices them into 500-character chunks with 50-character overlap, respecting sentence boundaries.
LangChain · RecursiveCharacterTextSplitter
02
Embed every chunk
all-MiniLM-L6-v2 turns each chunk into a 384-dim vector. Small, fast, and surprisingly accurate — chosen so embedding hundreds of documents takes minutes not hours on CPU.
sentence-transformers · 384-dim
03
Build FAISS index
Vectors are stored in an in-memory FAISS index for sub-millisecond similarity search. The index is persisted to disk so the system can boot instantly on subsequent runs.
FAISS · IndexFlatL2
04
Rewrite follow-ups
When a user asks "and what about the fees?", that question alone has no context. ConversationalRetrievalChain combines the question with chat history and rewrites it into a standalone query the retriever can act on.
ConversationalRetrievalChain · BufferMemory
05
Retrieve top-k chunks
The rewritten question is embedded with the same model, and FAISS returns the top-k most similar chunks from the index. These become the LLM's grounding context.
FAISS similarity_search · top-k
06
Generate grounded answer
StableLM Zephyr 3B (4-bit quantised, GGUF) receives the question + retrieved chunks and produces an answer grounded in those chunks. Source chunks are surfaced as citations.
StableLM Zephyr 3B · llama.cpp
Why ConversationalRetrievalChain matters
  • Standard RetrievalQA treats each question in isolation
  • Follow-up questions like "What about the fees?" have no context without history
  • ConversationalRetrievalChain rephrases follow-up questions into standalone queries before searching
  • ConversationBufferMemory stores the full conversation history
  • Result: the chatbot maintains coherent multi-turn dialogue across a session
Why StableLM Zephyr 3B?
  • Local inference: No API costs, no latency from external calls, no data privacy risk
  • Q4_K_M quantisation: 4-bit weights reduce model from ~6GB to ~2GB — fits on standard hardware
  • GGUF format: Optimised for CPU inference via llama.cpp
  • Instruction-tuned: Zephyr variant fine-tuned to follow instructions and stay grounded
  • Trade-off acknowledged: smaller than GPT-4, but sufficient for grounded Q&A over retrieved context
Key Insight
The most important design decision was local inference over API calls. By running StableLM Zephyr locally in GGUF format, the system has no ongoing API costs, no latency from network calls, and no risk of sending proprietary client documents to external servers. For a consulting firm handling sensitive client PDFs, this isn't optional — it's the only architecturally correct choice.
⊕ View on GitHub → github.com/Harshaaalll/rag-chatbot
Project 8 · Datathon · November 2025
Medical Bill OCR &
Fraud Detection
An end-to-end pipeline for extracting structured data from scanned hospital bills and automatically detecting fraudulent claims using four independent anomaly-detection algorithms running in parallel.
OCR Fraud Detection Computer Vision
The Problem
Insurance companies process millions of scanned hospital bills. Manual review is slow; fraudsters exploit this with inflated totals, duplicated submissions, and impossible service combinations. We needed an automated triage system.
The Approach
Two-stage pipeline. Stage 1: aggressive image cleanup → OCR → LLM extraction turns noisy scans into clean JSON. Stage 2: four independent fraud checks vote on a risk score that routes the claim to ACCEPT / REVIEW / REJECT.
The Impact
90%+ extraction accuracy on degraded scans. Four fraud signals catch issues a single check would miss. Risk-scored output means humans only spend time on the actually suspicious 10% — not all 100%.
90%+
Extraction accuracy
4
Fraud checks
0.8
Rejection threshold
30
Day SHA-256 window
300
DPI target resolution
System Architecture — Extraction + parallel fraud detection
Two-stage pipeline: image → structured data → risk score
The four fraud checks run in parallel, not sequence — each catches a different attack pattern. Their outputs are weighted into a single risk score that drives an automated routing decision.
STAGE 1 · DATA EXTRACTION 🖼️ Scanned Bill PNG / PDF Often blurry, skewed 🔧 OpenCV Cleanup Deskew · CLAHE · bilateral 4× DPI upscale → 300 DPI 👁️ PaddleOCR Angle classifier first Text detection + recognition 🤖 Qwen 7B (Ollama) Raw text → structured JSON Patient · items · totals 📋 Structured Bill JSON: patient, items[], amounts, total, date STAGE 2 · PARALLEL FRAUD CHECKS (4 INDEPENDENT SIGNALS) ① IQR Anomaly Flag charges > 95th percentile × 1.5 Bill-level context, not global Catches: inflated single line items ② Reconciliation Σ(line items) vs declared total >1% mismatch = flagged Catches: inflated grand totals ③ SHA-256 Dedup Hash content, check 30-day cache Reject exact duplicates Catches: same bill, multiple insurers ④ Pattern Analysis Same service billed 2× · impossible combos · spike qtys Catches: structural fraud patterns 📊 Weighted Risk Score (0–1) Each check contributes a sub-score; weighted sum produces final risk ✓ ACCEPT risk < 0.4 ⚠ MANUAL REVIEW 0.4 ≤ risk < 0.8 ✗ REJECT risk ≥ 0.8
Step-by-step workflow
01
Aggressive image cleanup
Real bills are blurry, skewed, and shadowed. We deskew via Hough transform, denoise with bilateral filter (preserves letter edges), apply CLAHE for local contrast, and upscale 4× to hit 300 DPI — the resolution OCR engines expect.
OpenCV · Hough · CLAHE · bilateral
02
OCR with PaddleOCR
PaddleOCR runs an angle classifier first (handles rotated docs), then text detection and recognition. Outputs raw text strings with bounding boxes — no structure yet, just words.
PaddleOCR · DB detector · CRNN
03
LLM-based extraction
Qwen 7B (via Ollama, local) receives raw OCR text and returns a strict JSON schema: patient name, line items, amounts, total, date. The LLM handles formatting variance across different hospital templates.
Qwen 7B · Ollama · JSON schema
04
Run all 4 fraud checks in parallel
IQR (per-bill outliers), reconciliation (sum vs declared total), SHA-256 (duplicate submission across 30-day window), and pattern analysis (impossible combos) each run independently and produce a sub-score.
NumPy · hashlib · rule engine
05
Aggregate to risk score
The four sub-scores are combined into a single weighted risk score in [0, 1]. Each check has a tunable weight, calibrated against historical fraud cases.
Weighted ensemble
06
Route the claim
< 0.4 → auto-accept, 0.4–0.8 → human review, ≥ 0.8 → auto-reject. Humans only see the 10–15% of bills the system is uncertain about — saving the bulk of review time.
Threshold routing
The 4 fraud detection checks
  • IQR Amount Anomaly: Flags charges exceeding 95th percentile × 1.5 on that bill. Adapts to bill-level context, not global averages.
  • Reconciliation Check: Sums all line items and compares to declared total. Any >1% discrepancy is flagged — inflated totals are a classic fraud signal.
  • SHA-256 Duplicate Detection: Hashes bill content, checks against 30-day cache. Prevents the same bill from being resubmitted to multiple insurers.
  • Pattern Analysis: Detects same service billed twice, unusually high quantities, and suspicious service combinations in one visit.
Image preprocessing pipeline
  • Deskewing: Hough Line Transform detects text angle and rotates image to straighten it
  • Bilateral filter: Removes noise while preserving letter edge sharpness (unlike regular blur)
  • CLAHE: Local contrast enhancement — brightens dark corners without overexposing the rest
  • Adaptive thresholding: Region-specific black/white conversion — handles shadows correctly
  • 4× DPI scaling: Upscales toward 300 DPI for OCR accuracy
Key Learning
No single fraud signal is reliable on its own — but four independent signals combined are nearly impossible to fool. A clever fraudster might bypass IQR by spreading inflated amounts across many small line items, but that breaks reconciliation. They might avoid reconciliation issues but get caught by SHA-256 duplication. Defence-in-depth, applied to model design.
⊕ View on GitHub → github.com/Harshaaalll/medical-bill-ocr-fraud
Project 9 · BITS Hyderabad · Aug–Nov 2024
Multilingual ASR
in Low-Resource Languages
Automatic speech recognition for Urdu — a low-resource language. Zero-shot Whisper transcription with a two-stage post-processing pipeline including IndicBERT-based MLM error correction.
Speech AI NLP Audio Processing
The Problem
Speech recognition for English is excellent. For low-resource languages like Urdu, it's poor — and there's not enough labelled data to train a new model from scratch. We needed a working Urdu transcriber without millions of labelled hours.
The Approach
Use Whisper zero-shot for the acoustic part, then fix its mistakes using a second model that understands Urdu language. IndicBERT acts as a linguistic spell-checker over the transcript, replacing phonetically-similar words that don't fit the context.
The Impact
14% reduction in Word Error Rate over baseline Whisper alone. Pipeline works on noisy real-world recordings thanks to the audio cleanup stage. Generalisable architecture — swap IndicBERT for any MLM and it works for other languages.
14%
WER reduction
-10dB
Noise reduction
16kHz
Resampled rate
0.4
MLM threshold
System Architecture — Acoustic + linguistic two-pass
Specialist-models architecture: Whisper hears, IndicBERT reads
Instead of one giant model trying to do everything, we let two specialists each do what they're best at — Whisper handles audio, IndicBERT handles language. Their combination beats either alone.
PHASE 1 · AUDIO CONDITIONING 🎵 Raw Audio Variable format / quality 🔊 pydub Pipeline Mono · -20dBFS norm silence trim · 16kHz 📉 Denoise Spectral subtraction ~ -10dB noise floor PHASE 2 · ACOUSTIC MODEL (HEAR) 🎤 Whisper (small) Zero-shot Urdu Language biasing token 📝 Raw Transcript Has phonetic substitutions e.g. similar-sounding wrong word PHASE 3 · LINGUISTIC CORRECTION (READ) For each token... Mask the word Show context to IndicBERT Get probability of word "Is this word likely here?" 🔤 IndicBERT MLM Pre-trained on Indian langs Predicts P(word | context) Threshold: 0.4 below → suggest replacement P < 0.4 ? replace token ✓ Final Transcription WER tracked vs reference ↓ 14% over Whisper alone Iterate over every token in the transcript
Step-by-step workflow
01
Standardise the audio
Convert to mono (Whisper expects mono), normalise to -20dBFS so loudness is consistent across recordings, trim leading/trailing silence, and resample to 16kHz — Whisper's training rate.
pydub · ffmpeg backend
02
Subtract background noise
noisereduce estimates the noise floor from silent regions and subtracts it spectrally from the speech signal — about -10dB reduction without distorting voice.
librosa · noisereduce
03
Transcribe with Whisper
Whisper (small) is run zero-shot with a language token forcing Urdu output. The result is a transcript with the right number of words but plausible-sounding errors — phonetically close, semantically wrong.
openai/whisper-small
04
Mask each token
For every word in the transcript, we hide it (replace with [MASK]) and ask IndicBERT to score how likely the original word is given the surrounding context.
HuggingFace fill-mask
05
Threshold & replace
If IndicBERT's probability for the original word is below 0.4, that word probably doesn't fit — we replace it with the highest-probability alternative IndicBERT suggests.
argmax over vocab
06
Measure WER
Word Error Rate is computed against gold-standard transcripts. The two-stage pipeline produces ~14% lower WER than baseline Whisper alone — significant for a low-resource language.
jiwer · WER metric
Audio preprocessing rationale
  • Mono conversion: Whisper expects mono. Stereo creates phase issues that confuse the model.
  • -20dBFS normalisation: Standardises loudness across mics and environments.
  • Silence trimming: Removes leading/trailing silence that adds nothing but inflates WER.
  • 16kHz resampling: Whisper was trained on 16kHz. Mismatched sample rates degrade quality.
  • Spectral subtraction: Estimates noise floor in silence, subtracts from speech. ~ -10dB reduction.
Why IndicBERT as the corrector?
  • Whisper makes phonetically plausible errors — e.g. transcribing a similar-sounding word
  • MLM (Masked Language Model): IndicBERT is pre-trained to predict masked tokens from context
  • For each transcribed word, check: given the surrounding context, is this the most likely word?
  • If confidence for the transcribed word is below 0.4, replace with the highest-probability alternative
  • IndicBERT is specifically trained on Indian languages — understands Urdu context better than generic models
Key Learning
The two-stage design — ASR first, then MLM correction — is more powerful than trying to build a perfect ASR model. Whisper handles the acoustic modelling, IndicBERT handles linguistic correction. This separation of concerns lets each model do what it's best at: Whisper is excellent at converting audio to text, IndicBERT is excellent at deciding whether a word makes sense in context. Combining specialist models often beats one general model trying to do everything.
⊕ View on GitHub → github.com/Harshaaalll/multilingual-asr
Project 10 · Independent · Jun–Jul 2024
Market Analysis
Using LLMs
An automated financial news sentiment pipeline. Scrapes, summarises, and analyses 500+ articles using BART and RoBERTa, producing real-time sentiment scores served via a Flask API with a Streamlit dashboard.
LLM Sentiment FinTech
The Problem
Markets move on news, but no human can read 500+ articles a day. Existing sentiment APIs are either too generic (consumer Twitter sentiment) or too expensive at scale. We needed a financial-domain pipeline running locally.
The Approach
Three-stage pipeline. Scrape with BeautifulSoup. Summarise with two-pass BART (handles articles longer than the model's 1024-token limit). Score with RoBERTa trained on financial text — using a continuous compound score, not a discrete class.
The Impact
500+ articles/day processed. 70% length reduction via summarisation while keeping financial signals. Real-time API + Streamlit dashboard surfaces sentiment trends live. SMOTE applied correctly — only on training data, no leakage.
500+
Articles processed
70%
Text length reduction
67%
Sentiment accuracy
4
BART beam size
55:46
Class split (pre-SMOTE)
System Architecture — Scrape → summarise → score → serve
Two-pass summarisation pipeline with continuous sentiment scoring
The interesting part is the two-pass BART in the middle. Many financial articles exceed BART's 1024-token context window, so we summarise chunks first, then summarise the chunk-summaries.
🕸️ BeautifulSoup 500+ articles scraped Financial sources ✂️ LangChain Split Article → chunks ≤ 1024 tokens each 📰 Two-Pass BART facebook/bart-large-cnn · 4-beam Pass 1: summarise each chunk → N chunk-summaries Pass 2: summarise the summaries → 70% length reduction 📑 Final Summary Earnings · guidance · risk ~ 30% of original 💭 RoBERTa Sentiment cardiffnlp/twitter-roberta-base softmax → compound score continuous, not discrete ⚖️ SMOTE Balancing Pre-SMOTE class split: 55:46 Applied AFTER train/test split no synthetic data leakage 🚀 Serving Layer Flask REST API · /sentiment Streamlit live dashboard Real-time market signals ⚠ CRITICAL: SMOTE applied to training set ONLY — applying it before split would leak synthetic samples into the test set Output sample: {"ticker": "AAPL", "compound": +0.62, "headline": "...", "trend_24h": "↑"}
Step-by-step workflow
01
Scrape financial news
BeautifulSoup pulls 500+ articles from financial sources daily — headlines, body text, publish date, ticker mentions.
BeautifulSoup · requests
02
Chunk long articles
Articles exceeding BART's 1024-token limit are split via LangChain's unstructured text workflow into manageable chunks.
LangChain · token-aware splitter
03
Two-pass BART summarisation
Pass 1 summarises each chunk independently. Pass 2 summarises the combined chunk-summaries into a final article summary. 4-beam search produces higher quality than greedy decoding by considering 4 alternatives at each step.
facebook/bart-large-cnn · 4-beam
04
Score sentiment with RoBERTa
cardiffnlp/twitter-roberta-base-sentiment scores the summary. Instead of argmax (one class), we compute a softmax-weighted compound score across positive/neutral/negative — a continuous signal more useful for tracking trends.
RoBERTa · softmax compound
05
Balance training data — correctly
For the supervised classifier, classes were 55:46. SMOTE was applied only after train/test split, on the training portion. Applying it earlier would leak synthetic samples into validation and inflate accuracy.
imblearn · SMOTE (post-split)
06
Serve via API + dashboard
A Flask endpoint returns sentiment-per-ticker for downstream consumers. A Streamlit dashboard shows live sentiment trends — green when positive sentiment dominates, red when negative.
Flask · Streamlit · WebSocket
Why two-pass BART summarisation?
  • Financial news articles often exceed BART's 1024-token context limit
  • Pass 1: Split article into chunks, summarise each independently
  • Pass 2: Summarise the combined chunk-summaries into a final summary
  • 4-beam search produces better quality than greedy decoding — considers 4 possible next tokens at each step
  • Result: 70% length reduction while preserving key financial signals (earnings, guidance, risk factors)
Why RoBERTa over BERT for sentiment?
  • cardiffnlp/twitter-roberta-base-sentiment is trained on financial Twitter data — closer domain than generic models
  • Compound score: Instead of argmax (pick one class), compute softmax-weighted sum across positive/neutral/negative
  • This gives a continuous sentiment score rather than a discrete class — more useful for tracking sentiment trends over time
  • SMOTE only on training data — a common mistake is applying SMOTE before splitting, which leaks synthetic samples into validation. Applied correctly here.
Key Learning
The most important data-science lesson from this project: SMOTE must only be applied to training data, never before the train-test split. Applying SMOTE on the full dataset before splitting creates data leakage — synthetic samples generated from real training examples end up in the test set, inflating accuracy metrics. The correct workflow: split first, then apply SMOTE only on the training portion.
⊕ View on GitHub → github.com/Harshaaalll/market-analysis-llm
Project 11 · Personal Project · 2026
OpsAgent:
Autonomous Browser Operator
Autonomous AI operator: plan-act-verify loop over a real browser, with approval gates and independent verification.
AI Agents Automation Verification
The Problem
Back-office work such as finding a vendor invoice and entering it into an ERP is repetitive, but an agent that clicks around can save the wrong amount, get fooled by a page, or report success it never achieved.
The Approach
A plan-act-verify loop over a real browser (Playwright) driven by Gemini. Policy is enforced in code: every action is blocked, auto-approved or sent to a human, and the approved action’s digest is re-checked at execution. A verifier with no LLM re-reads the ERP afterwards.
The Impact
11/12 eval scenarios passed in a full run (the twelfth passed on rerun after a network error). A typical run takes 20–30 steps and costs about $0.03.
11/12
Eval scenarios
20–30
Steps per run
~$0.03
Cost per run
0
LLMs in verifier
System Architecture — Plan-act-verify loop
Request → plan → act in a real browser → verify against the system of record
The agent plans from retrieved policy, then acts in a real browser one step at a time. Risky actions pass an approval gate enforced in code. When it finishes, a verifier with no LLM re-reads the ERP before anything is reported as done.
User request e.g. find a vendor invoice and enter it in the ERP Retrieve policy BM25 retrieval with aliases; lessons from earlier verified runs Plan Gemini plans the task before the first click gemini-flash-latest Act Real browser via Playwright Risk judged per click from the live page Observe Text snapshot with numbered elements, not CSS selectors Decide Next step, or stop Budgets and stall detection Approval gate Block · auto-approve · ask a human, enforced in code; digest re-checked Independent verifier No LLM. Re-reads the ERP and checks values appear in source documents next step, until done or budget limit Report report.md · steps.jsonl redacted audit · screenshots An agent should not grade its own work: success is checked against the system of record.
Step-by-step workflow
01
Retrieve policy and plan
The request is matched against policy with BM25 retrieval, then planned before the first click.
BM25 · Gemini
02
Act and observe
The page is read as a text snapshot with numbered elements instead of CSS selectors. Each click is risk-judged from the live page.
Playwright
03
Approval gate
Block, auto-approve or ask a human. The human sees the same values that will execute, bound to a digest.
Policy in code
04
Independent verifier
Re-reads the ERP and requires typed values to appear in the source documents before the run is reported as done.
No LLM
Technical decisions
  • Policy in code, not prompt: a prompt cannot reliably stop a financial write; a gate that checks the action itself can.
  • Verifier without an LLM: success is checked against the system of record, so the agent cannot grade itself.
  • Text snapshots over selectors: numbered elements survive UI drift better than hard-coded selectors.
Key results
  • 12 scenarios: UI drift, session expiry, save-then-error, duplicate invoices, amount mismatches and prompt-injected email
  • Repeat runs: three of four tested scenarios passed 3/3; the fourth went from 2/3 to 3/3 after detail pages were pinned in context
  • Audit trail: every run writes a report, step log, redacted audit log and screenshots
  • Security: credentials are vault placeholders resolved in the tool layer; navigation is allow-listed; page text is treated as data
Key Insight
An agent should not grade its own work. Separating the doer from an independent check against the real system made failures visible instead of being reported as success. Limits: it is validated on two mock web apps and one workflow family, with one model family and scenarios tuned during development.
⊕ View on GitHub → github.com/Harshaaalll/opsagent
Project 12 · Personal Project · 2025
Audit Insight:
NLP Analytics for Audits
An end-to-end NLP pipeline that ingests raw audit observations, findings, and recommendations — then automatically classifies sentiment, discovers latent topics, and clusters similar documents for rapid triage. Built for teams that need to surface risk patterns from thousands of audit texts in minutes, not weeks.
NLP Sentiment Analytics
The Problem
Audit teams manually read thousands of unstructured audit observations to identify risk patterns. Inconsistent categorization, missed connections between similar findings, and no systematic way to quantify sentiment across audit reports.
The Approach
End-to-end pipeline: spaCy preprocessing → RoBERTa transformer for sentiment classification → Gensim LDA for latent topic discovery → TF-IDF + SVD + t-SNE for dimensionality reduction → KMeans clustering for grouping similar findings.
The Impact
Automatic sentiment scoring with confidence levels. Latent topics surfaced across audit documents. Similar findings clustered for batch review. Interactive Streamlit dashboard with CSV export for downstream analysis.
RoBERTa
Sentiment Model
6
LDA Topics
5
KMeans Clusters
CLI+UI
Dual Interface
System Architecture — Multi-path NLP analysis
Parallel analysis pipeline: sentiment + topics + clustering
Raw audit observations flow through spaCy preprocessing, then split into three parallel analysis paths — RoBERTa sentiment, LDA topic modeling, and TF-IDF clustering — before converging in an interactive dashboard.
📄 Audit CSV Raw observations 🔤 spaCy Preprocess Tokenize · Lemmatize Stop-word removal 🧠 RoBERTa Sentiment 3-class + confidence cardiffnlp model 📊 Gensim LDA 6 latent topics Topic-word distributions 🔬 TF-IDF → KMeans SVD → t-SNE → cluster 5 document groups 📋 Results CSV Merged analysis Export-ready 🖥️ Streamlit Interactive dashboard Upload + explore
Step-by-step workflow
01
Ingest audit CSV
Load raw audit observations from CSV. Validate text column, handle missing values, basic data quality checks.
pandas
02
Preprocess text
spaCy-powered tokenization, lemmatization, and stop-word removal. Clean text for downstream models.
spaCy · en_core_web_sm
03
Classify sentiment
RoBERTa transformer classifies each observation as positive/neutral/negative with confidence scores.
cardiffnlp/twitter-roberta-base-sentiment
04
Discover topics
Gensim LDA uncovers recurring themes across audit documents. Configurable number of topics with coherence scoring.
Gensim LDA · TF-IDF
05
Reduce & cluster
TF-IDF vectorization → SVD dimensionality reduction → t-SNE 2D projection → KMeans groups similar findings.
scikit-learn · KMeans
06
Dashboard & export
Streamlit web UI with upload, real-time analysis, and CSV export. CLI also available for batch processing.
Streamlit · CLI
Technical decisions
  • Why RoBERTa: Pre-trained on 58M tweets, excels at short informal text — similar register to audit observations.
  • Why LDA over BERTopic: LDA provides interpretable topic-word distributions; BERTopic requires GPU and adds complexity without clear benefit for this text size.
  • KMeans over DBSCAN: Known number of audit categories makes KMeans appropriate. DBSCAN better for unknown cluster count.
  • t-SNE over UMAP: t-SNE produces better local structure preservation for visualization at this scale.
Key results
  • Sentiment: 3-class classification with per-observation confidence scores
  • Topics: Configurable LDA with coherence-based topic count selection
  • Clustering: KMeans grouping with silhouette scoring
  • Deployment: Streamlit dashboard + CLI, full pytest suite with GitHub Actions CI
Key Insight
The most impactful design decision was building a dual interface (CLI + Streamlit). The CLI enables batch processing in automated pipelines, while the Streamlit dashboard gives non-technical auditors a point-and-click interface. This separation of concerns made the tool adoptable across both technical and business teams.
⊕ View on GitHub → github.com/Harshaaalll/audit-insight
Project 13 · Personal Project · 2025
Career Copilot 2.0:
AI Job Search OS
Not just another job tracker — a complete Career Operating System that transforms job search from scattered applications into a data-driven, AI-optimized conversion funnel. 11 intelligent modules powered by LangChain + FAISS + Groq LLaMA 3.
LLM/RAG NLP AI
The Problem
Job seekers follow a broken workflow: apply everywhere, pray for responses, get ghosted, repeat. No data-driven approach to prioritize applications, predict response likelihood, or optimize resumes for ATS systems.
The Approach
Build an 11-module AI operating system: Command Center with daily briefings, FAISS-powered resume-JD matching, response probability prediction, ghost job detection, hidden market radar, ATS keyword optimization, interview battle plans, salary intelligence, and RAG-powered cover letter generation.
The Impact
Complete career funnel from Lead → Qualified → Outreach → Interview → Offer with conversion analytics. AI-scored application priority. ATS optimization with keyword gap analysis.
11
AI Modules
RAG
Matching Engine
FAISS
Vector Search
LLaMA 3
LLM Backend
System Architecture — RAG matching + career funnel
Dual-path pipeline: resume RAG index + job board scraping
The resume is chunked and embedded into a FAISS index for RAG matching. Job descriptions flow through a separate scraping pipeline. Both paths converge at the Command Center dashboard.
PATH 1 · RESUME RAG INDEX 📄 Resume PDF Upload + extract ✂️ Recursive Chunk 500 chars · 50 overlap MiniLM-L6-v2 embed 🗄️ FAISS Index Vector similarity Resume ↔ JD matching Match Analysis Opportunity scoring Cover Letter Gen RAG-powered PATH 2 · JOB DISCOVERY 🕸️ Selenium Scraper LinkedIn · Indeed 📝 JD Processing Keyword extraction 📊 Pipeline Tracker Lead → Offer funnel 🎯 Command Center Daily AI briefings Conversion analytics 11 modules unified
Step-by-step workflow
01
Upload resume
PDF upload with text extraction, recursive chunking, and MiniLM-L6-v2 embedding. Creates a FAISS vector index for RAG-powered matching.
LangChain · FAISS · sentence-transformers
02
Discover jobs
Dual-mode job ingestion — Selenium scraper for LinkedIn/Indeed with anti-detection, or manual JD paste.
Selenium · BeautifulSoup
03
AI match scoring
FAISS vector similarity between resume chunks and JD. Response probability prediction based on match strength, company signals, and historical patterns.
FAISS · Groq LLaMA 3
04
ATS optimization
Keyword gap analysis against each JD. Identifies missing keywords, section-by-section optimization suggestions.
NLP keyword extraction
05
Generate content
RAG-powered cover letter generation, interview question prediction with STAR framework scaffolding, salary intelligence with location adjustment.
LangChain RAG · Groq
06
Track funnel
Pipeline stages (Lead → Qualified → Outreach → Interview → Offer) with conversion rates, warm vs cold tracking, weekly trend snapshots.
Streamlit · analytics
Technical decisions
  • Why Groq over OpenAI: Free tier with 30 req/min, LLaMA 3 quality comparable to GPT-3.5 for structured tasks, zero cost for personal project.
  • Why FAISS over Pinecone: Local vector store, no API costs, fast enough for resume-scale (hundreds of chunks, not millions).
  • Why Selenium over APIs: LinkedIn/Indeed don't offer free job search APIs. Stealth scraping with randomized delays and user-agent rotation.
  • 11 modules: Each module is independent — users can use just the ATS optimizer without the full pipeline.
Key results
  • Command Center with AI-generated daily strategic briefings
  • RAG matching with per-job opportunity scores
  • Ghost job detection and hidden market radar
  • Conversion funnel analytics with stage-to-stage rates
Key Insight
The biggest lesson was that building 11 modules in Streamlit requires aggressive session state management. Each module shares data (resume index, job pipeline, API keys) through st.session_state, but circular dependencies between modules can cause infinite reruns. The solution was a centralized state registry that initializes all shared state once at startup.
⊕ View on GitHub → github.com/Harshaaalll/career-copilot
Project 14 · Personal Project · 2025
AirFare-ML:
Airline Price Prediction
A production-grade machine learning system that predicts domestic airline ticket prices in India. 6 regression algorithms, advanced feature engineering, and Bayesian hyperparameter optimization. LightGBM achieves 93.91% R² with ₹689 MAE.
ML Regression Data Science
The Problem
Airlines use dynamic pricing that makes ticket prices volatile. Consumers need predictive models to understand what drives price changes and when to book for the best deals.
The Approach
Modular ML pipeline: data ingestion → cyclical sin/cos encoding, target-guided ordinal encoding, IQR outlier removal → 6 regression algorithms benchmarked with 5-fold CV → Bayesian optimization for hyperparameter tuning.
The Impact
LightGBM 93.91% R², ₹689 MAE, 9.62% MAPE. Top 4 ensemble models within 0.002 R² of each other — feature engineering matters more than algorithm choice.
93.9%
R² Score
₹689
Mean Abs Error
9.6%
MAPE
6
Models Benchmarked
System Architecture — Regression pipeline
End-to-end airline price prediction pipeline
Raw flight data enters on the left. Feature engineering transforms temporal and categorical variables. Six regression models are benchmarked with cross-validation. LightGBM emerges as the best performer.
📊 Raw Data Flights · prices Routes · airlines 🔧 Feature Engineering Sin/cos cyclical encoding Target-guided ordinal IQR outlier removal temporal + categorical Ridge · 89.73% R² Decision Tree · 91.94% R² ⭐ LightGBM · 93.91% R² Random Forest · 93.79% R² XGBoost · 93.6% R² Gradient Boost · 93.5% R² 📏 5-Fold CV R² · MAE · MAPE Bayesian optimization hyperparameter tuning ✅ LightGBM 93.91% R² · ₹689 MAE Best performer Top 4 models within 0.002 R² — feature engineering dominates algorithm choice
Step-by-step workflow
01
Load data
Ingest domestic flight dataset with airline, route, stops, departure/arrival times, and price. Handle missing values and validate data types.
pandas · data validation
02
Feature engineering
Cyclical sin/cos encoding for temporal features (departure hour, day of week). Target-guided ordinal encoding for categorical variables. IQR-based outlier removal for price stability.
sin/cos · target-guided ordinal · IQR
03
Exploratory data analysis
Price distributions by airline, route, and time. Correlation analysis between features. Outlier visualization and handling strategy determination.
matplotlib · seaborn · statistical tests
04
Train 6 models
Benchmark Ridge, Decision Tree, Random Forest, Gradient Boosting, XGBoost, and LightGBM. Each trained with 5-fold stratified cross-validation.
scikit-learn · XGBoost · LightGBM
05
Evaluate
Compare R², MAE, RMSE, and MAPE across all models. Bayesian hyperparameter optimization on top performers. Residual analysis for model diagnostics.
Optuna · Bayesian optimization
06
Select best
LightGBM selected: 93.91% R², ₹689 MAE, 9.62% MAPE. Leaf-wise tree growth strategy outperforms level-wise. Feature importance analysis confirms engineering choices.
LightGBM · leaf-wise growth
Technical decisions
  • Why cyclical encoding: Time features (hour, day) are circular — 23:00 is close to 00:00. Sin/cos encoding preserves this circular relationship that one-hot encoding destroys.
  • Why target-guided ordinal: Encodes categorical variables by their mean target value, capturing ordinal relationships that label encoding misses and avoiding high cardinality of one-hot.
  • Why IQR over z-score: IQR is robust to non-normal distributions. Flight prices are right-skewed, making z-score thresholds unreliable.
  • LightGBM wins: Leaf-wise growth finds deeper interactions than level-wise (XGBoost). Histogram-based splitting is faster on large datasets.
Key results
  • LightGBM: 93.91% R² — best overall performer with ₹689 MAE
  • Random Forest: 93.79% R² — within 0.12% of LightGBM
  • Ensemble top 4: All >93% R², within 0.002 of each other
  • Decision Tree: 91.94% R² — strong baseline, interpretable
  • Ridge: 89.73% R² — linear baseline, confirms non-linearity in data
Key Insight
Feature engineering matters more than algorithm choice. The top 4 ensemble models were within 0.002 R² of each other — proving that once features are well-engineered, most modern ensemble algorithms converge to similar performance. The real gains came from cyclical time encoding and target-guided ordinal encoding, not from hyperparameter tuning.
⊕ View on GitHub → github.com/Harshaaalll/airfare-ml
Project 15 · BITS Pilani Design Project · 2025–2026
Hastkala Setu:
Tradition × Technology
Dual-component academic project: ML pipeline for cross-cultural conflict resolution analysis (MANOVA, XGBoost, SHAP) + Flutter mobile app for Indian handicraft artisans with Hindi voice input.
Research ML Mobile App
The Problem
Two intertwined challenges: understanding cultural and psychological factors in conflict resolution across demographics, and Indian handicraft artisans lacking digital tools to manage their business.
The Approach
6-step ML pipeline on 776 adults: Cronbach's α validation → MANOVA → XGBoost classification → SHAP explainability. Parallel Flutter app with Hindi voice input, Firebase backend, FL Chart visualizations.
The Impact
0.938 AUC with XGBoost. Instrumental Attitude identified as #1 predictor via SHAP. Flutter app tested with 8 artisans, achieving 80% Hindi voice input accuracy.
0.938
Best AUC
776
Subjects
12
Models
8
Artisans Tested
System Architecture — Dual-track pipeline
Parallel tracks: ML conflict analysis + Flutter artisan app
Two independent pipelines share a common research foundation. Track 1 analyzes conflict resolution patterns via ML. Track 2 empowers artisans with a Hindi-first mobile app.
TRACK 1 · ML CONFLICT RESOLUTION ANALYSIS 📋 Survey Data 776 adults Cross-cultural 📊 Cronbach's α Scale reliability MANOVA analysis Wilks' Λ = 0.933 🧠 ML Classification 12 models benchmarked XGBoost best: 0.938 AUC tertile encoding · SMOTE 🔍 SHAP Analysis Feature importance Instrumental Attitude #1 explainable predictions TRACK 2 · FLUTTER ARTISAN APP 🎨 Artisan Input Product details Sales records 🗣️ Hindi Voice 80% accuracy Compositional numbers 🔥 Firebase Cloud Firestore Real-time sync 📈 FL Chart Sales visualizations Business insights Two independent systems sharing a common research foundation — tradition meets technology
Step-by-step workflow
01
Load survey data
Ingest survey responses from 776 adults across demographic groups. Validate response quality, handle missing data, and prepare for psychometric analysis.
pandas · survey design
02
Cronbach's α analysis
Validate internal consistency of psychological scales. Compute Cronbach's alpha for each construct. MANOVA for multivariate group differences (Wilks' Λ = 0.933).
pingouin · scipy · MANOVA
03
ML classification
Benchmark 12 classification models. Tertile encoding for conflict resolution styles. SMOTE applied selectively (only for Compromising style where class imbalance exists).
scikit-learn · XGBoost · SMOTE
04
SHAP explainability
SHAP TreeExplainer on best XGBoost model. Instrumental Attitude emerges as #1 predictor. Psychological variables dominate over demographics.
SHAP · TreeExplainer
05
Recoded analysis
Re-run pipeline with alternative variable coding to validate findings. Stability check ensures SHAP rankings are robust across encoding choices.
robustness testing
06
Flutter app
Cross-platform mobile app for artisans. Hindi voice input with compositional number parsing. Firebase backend for data persistence. FL Chart for sales analytics.
Flutter · Firebase · FL Chart
Technical decisions
  • XGBoost over deep learning: 776 samples is too small for neural networks. Tree-based methods handle tabular data with small N better.
  • Tertile encoding: Conflict resolution scores divided into low/medium/high tertiles — preserves ordinal structure while enabling classification.
  • SMOTE only for Compromising: Not all styles had class imbalance. Applying SMOTE globally would distort balanced classes.
  • Hindi voice parser: Custom compositional number parser handles Hindi numerals (e.g., "ek hazaar paanch sau" → 1500).
Key results
  • XGBoost: 0.938 AUC — best performer across all conflict styles
  • Random Forest: 0.897 AUC — strong second performer
  • SHAP #1: Instrumental Attitude — most predictive variable
  • MANOVA: Wilks' Λ = 0.933 — significant multivariate differences
  • Flutter app: 80% Hindi voice accuracy, tested with 8 artisans
Key Insight
Psychological variables are more predictive than demographic variables for conflict resolution. SHAP analysis consistently ranked Instrumental Attitude, Subjective Norms, and Perceived Behavioral Control above age, gender, and education. This finding held across recoded analyses, confirming that how people think about conflict matters more than who they are.
⊕ View on GitHub → github.com/Harshaaalll/hasthkala-setu
Project 16 · BITS Pilani Design Project · 2024–2025
Road Safety NLP:
Accident Severity Analysis
NLP-based classification of road accident severity from news articles. 4 data collection phases, 8 Hyderabad news outlets, spaCy NER for location extraction.
NLP NER Scraping
The Problem
Fragmented road safety data in India. No centralized system for tracking accident severity across cities. Official data is delayed, incomplete, and lacks the granularity needed for targeted interventions.
The Approach
Iterative 4-phase data collection (Twitter → Nitter → YouTube → News articles). 8 Hyderabad outlets scraped. spaCy NER for location extraction + Nominatim geocoding. Severity classification into Fatal/Severe/Moderate/Minor.
The Impact
Automated pipeline from raw news → severity-classified, geocoded accidents. Reusable framework adaptable to any Indian city. 3 failed data sources documented — teaching the value of iteration.
8
News Sources
4
Iteration Phases
NER
Location Extraction
4
Severity Levels
System Architecture — Iterative data pipeline
Multi-source scraping pipeline with NER extraction
Three data sources were tried and rejected before news articles proved viable. The pipeline scrapes 8 outlets, extracts text, runs spaCy NER for locations, classifies severity, and geocodes results.
Twitter API ✘ Rate limits Nitter ✘ Shutdown YouTube ✘ Unstructured 3 sources rejected → pivoted to news articles 📰 8 News Sources Hyderabad outlets Verified · structured freely accessible 🕷️ Scraper Multi-keyword filter Article extraction 📝 Text Extraction Clean article body Remove boilerplate 🔍 spaCy NER Location extraction Entity recognition GPE + LOC entities ⚠️ Severity Class Fatal · Severe Moderate · Minor 📍 Geocoded Output Nominatim geocoding Mapped analysis Failures documented: 3 data sources abandoned before news articles proved viable
Step-by-step workflow
01
Source selection
Evaluated Twitter API (rate-limited), Nitter (shut down), YouTube (unstructured). Pivoted to 8 Hyderabad news outlets: verified, structured, freely accessible.
iterative evaluation · 4 phases
02
Article scraping
Custom scrapers for each outlet with multi-keyword filtering (accident, crash, collision, etc.). Rate-limited requests to respect robots.txt.
BeautifulSoup · requests
03
NER extraction
spaCy NER extracts GPE (geo-political entity) and LOC (location) entities from article text. Custom rules for Indian place name patterns.
spaCy · en_core_web_sm
04
Severity classification
Rule-based severity classification: Fatal (death keywords), Severe (hospitalization), Moderate (injuries), Minor (property damage only).
keyword matching · rule engine
05
Geocoding
Nominatim geocoding converts extracted location names to latitude/longitude coordinates for spatial analysis and mapping.
Nominatim · geopy
06
Analysis output
Structured dataset with severity-classified, geocoded accidents. Reusable framework adaptable to any Indian city by swapping news sources.
pandas · output pipeline
Technical decisions
  • News over social media: News articles are verified, structured, and freely accessible. Social media is noisy, rate-limited, and often unreliable.
  • spaCy over BERT NER: spaCy is fast and sufficient for Indian place name extraction. BERT NER adds latency without significant accuracy gains for this task.
  • Multi-keyword filtering: Boolean OR across accident-related keywords ensures high recall across different reporting styles.
  • 8 sources for diversity: Multiple outlets reduce bias from any single publication's reporting patterns.
Key results
  • 4 phases documented: Twitter → Nitter → YouTube → News articles (final)
  • 8 news sources: Diverse Hyderabad outlets for comprehensive coverage
  • spaCy NER + Nominatim: Automated location extraction and geocoding
  • Severity classification: 4-level system (Fatal/Severe/Moderate/Minor)
  • Reusable framework: Adaptable to any Indian city by swapping source configs
Key Insight
Failures taught the most. Three data sources were abandoned before news articles proved viable. Twitter's API rate limits, Nitter's shutdown, and YouTube's unstructured content each taught a lesson about data source evaluation. News articles won because they're verified, structured, and freely accessible — the trifecta of reliable data sources.
⊕ View on GitHub → github.com/Harshaaalll/social_media_scrapper
Project 17 · Personal Project · 2025
HydRERA Analytics:
Real Estate Intelligence
End-to-end data analytics platform for Hyderabad real estate. ELT pipeline (Python → PostgreSQL → dbt) powering four analytical modules with Power BI dashboards and ML-driven delay prediction.
Data Engineering ML Analytics
The Problem
Homebuyers lack data-driven tools for builder evaluation. RERA data is public but raw — no scoring, no delay prediction, no systematic way to compare builders across projects.
The Approach
ELT pipeline with dbt transforms producing 4 analytical marts: Builder Scorecard, Supply/Demand analysis, Price Fairness detection, and ML-driven Delay Prediction with SHAP explainability.
The Impact
Builder risk tiers from composite scoring. Oversupply flags by micro-market. Price fairness detection across comparable projects. XGBoost delay prediction with SHAP-driven feature importance.
4
Analytical Modules
ELT
Pipeline
SHAP
Explainability
dbt
Transform Layer
System Architecture — ELT analytics pipeline
End-to-end ELT pipeline with 4 analytical modules
Raw RERA data flows through Python ingestion into PostgreSQL. dbt transforms raw data into staging models and analytical marts. Power BI and Jupyter consume the marts for dashboards and ML analysis.
📊 Data Sources RERA public data Hyderabad projects 🐍 Python Ingestion Extract + load Raw tables 🐘 PostgreSQL Raw storage Schema-on-read ELT paradigm 🔄 dbt Transform Staging → marts Single DAG all 4 modules 📊 Power BI Interactive dashboards 📓 Jupyter ML delay prediction 4 Analytical Modules 🏗️ Builder Scorecard NTILE scoring · risk tiers Composite builder rating 📈 Supply / Demand Micro-market analysis Oversupply flags 💰 Price Fairness Comparable analysis Outlier detection ⏰ Delay Prediction XGBoost + SHAP ML-driven forecasting All 4 modules share same data foundation — one dbt DAG produces all 4 marts
Step-by-step workflow
01
Data ingestion
Python scripts extract RERA public data. Raw records loaded into PostgreSQL without transformation — ELT paradigm preserves source fidelity.
Python · psycopg2 · ELT
02
Raw storage
PostgreSQL stores raw tables with schema-on-read. No premature transforms — dbt handles all business logic downstream.
PostgreSQL · raw schema
03
dbt transformation
Single dbt DAG transforms raw data into staging models, then into 4 analytical marts. NTILE scoring for builder rankings, window functions for time-series analysis.
dbt · SQL · Jinja macros
04
Builder scorecard
Composite builder scoring using NTILE percentiles across on-time delivery, project count, and complaint ratio. Risk tiers for buyer guidance.
NTILE · Power BI
05
Delay prediction
XGBoost classifier predicts project delay probability. SHAP explainability shows which builder and project features drive delay risk.
XGBoost · SHAP · Jupyter
06
Visualization
Power BI dashboards for interactive exploration. Supply/demand heatmaps, price fairness comparisons, and builder risk scorecards.
Power BI · interactive filters
Technical decisions
  • dbt over pandas: SQL-based transforms are reproducible, version-controlled, and testable. Pandas transforms live in notebooks — fragile and hard to audit.
  • ELT over ETL: Load raw data first, transform in-database. Preserves source fidelity and lets dbt handle all business logic declaratively.
  • NTILE for scoring: Percentile-based scoring (NTILE) is distribution-agnostic — works regardless of skewness in builder metrics.
  • XGBoost for delay prediction: Handles mixed feature types (categorical + numeric) natively. SHAP integration provides explainable predictions.
Key results
  • 4 modules: Builder Scorecard, Supply/Demand, Price Fairness, Delay Prediction
  • Builder scoring: Composite NTILE-based risk tiers for buyer guidance
  • Oversupply detection: Micro-market flags for areas with excess inventory
  • Price fairness: Outlier detection across comparable projects
  • Delay prediction: XGBoost + SHAP for explainable delay risk forecasting
Key Insight
All 4 modules share the same data foundation. One dbt DAG produces all 4 analytical marts from the same raw PostgreSQL tables. This means a single data quality fix propagates to every module simultaneously. The power of ELT is that business logic lives in version-controlled SQL, not scattered across notebooks.
⊕ View on GitHub → github.com/Harshaaalll/hydera-analytics
Project 18 · BITS Pilani Study Project · 2026
Knowledge Graph RAG:
Legal AI for Indian Courts
Hybrid pipeline: Neo4j legal knowledge graph, Vespa hybrid search (BM25 + InLegalBERT), IRAC-constrained Mistral 7B. Benchmarked against GraphMERT on 1,000-case corpus.
Knowledge Graph LLM Research
The Problem
50M backlogged cases in Indian courts. Generic RAG systems miss legal structure — they can't distinguish between citing a statute and applying a precedent. Legal reasoning requires typed relationships, not just similarity search.
The Approach
Neo4j typed property graph (7 node types, 8 relationships). Hybrid retrieval: NER-Cypher queries against KG + Vespa BM25+InLegalBERT semantic search. IRAC-constrained Mistral 7B generates structured legal analysis.
The Impact
211 statutes, 1,285 precedents indexed. Balanced verdict predictions vs GraphMERT's class collapse (92.4% in one class). Parser recovers 55% of UNKNOWN predictions. Always report MCC and Cohen's κ.
1,000
Cases
211
Statutes
1,285
Precedents
768-d
InLegalBERT
System Architecture — Hybrid KG-RAG pipeline
Knowledge Graph + Vespa hybrid retrieval → IRAC-constrained generation
A new case enters on the left. Entity extraction identifies statutes, parties, and legal concepts. Two parallel retrieval paths — Neo4j KG (structural) and Vespa (semantic) — converge to assemble context for IRAC-constrained Mistral 7B generation.
📄 New Case Case description Legal query 🔍 Entity Extraction NER for statutes Parties · legal concepts typed entity recognition 🕸️ Neo4j KG 7 node types · 8 relationships Cypher graph traversal MERGE for density · 11.1 mean degree 🔎 Vespa Search BM25 + InLegalBERT 768-dim embeddings hybrid semantic + lexical 📋 Context Assembly Merge KG + Vespa Deduplicate · rank ⚖️ IRAC Mistral 7B Issue · Rule Application · Conclusion Structured verdict prevents hallucination GraphMERT's 92.4% accuracy was illusory — predictions collapsed to one class. KG-RAG produces balanced recall.
Step-by-step workflow
01
Entity extraction
NER identifies statutes, parties, judges, legal concepts, and case metadata from raw case text. Typed entities enable structured KG queries.
NER · typed entity recognition
02
Knowledge graph
Neo4j typed property graph with 7 node types and 8 relationship types. MERGE operations ensure graph density (11.1 mean degree). 211 statutes, 1,285 precedents indexed.
Neo4j · Cypher · MERGE
03
Vespa indexing
Case texts embedded with InLegalBERT (768-d, domain-specific legal embeddings). Indexed in Vespa for hybrid BM25 + semantic search.
InLegalBERT · Vespa · 768-d
04
Hybrid retrieval
Parallel retrieval: NER-Cypher queries traverse KG for structural matches. Vespa combines BM25 lexical + InLegalBERT semantic scores. Results merged and deduplicated.
Cypher + Vespa hybrid
05
IRAC generation
Mistral 7B constrained to IRAC format (Issue, Rule, Application, Conclusion). Sliding window attention handles long legal contexts. Prevents hallucination through structured output.
Mistral 7B · IRAC constraint
06
Evaluation
Benchmarked against GraphMERT. Report MCC and Cohen's κ alongside accuracy. Parser recovers 55% of UNKNOWN predictions through rule-based post-processing.
MCC · Cohen's κ · parser recovery
Technical decisions
  • KG over pure vector: Legal reasoning requires typed relationships (cites, overrules, interprets). Vector similarity alone can't distinguish between citing and overruling a case.
  • InLegalBERT over MiniLM: Domain-specific legal embeddings capture legal terminology nuances that general-purpose models miss.
  • IRAC constraint: Forces structured legal reasoning (Issue → Rule → Application → Conclusion). Prevents the LLM from generating ungrounded legal opinions.
  • MERGE for graph density: Neo4j MERGE operations ensure nodes are reused, not duplicated — creating a denser, more connected knowledge graph (11.1 mean degree).
  • Mistral over LLaMA: Sliding window attention handles the long context lengths typical of legal documents more efficiently.
Key results
  • 211 statutes: Indexed in Neo4j with typed relationships
  • 1,285 precedents: Linked via CITES, OVERRULES, INTERPRETS edges
  • 11.1 mean degree: Dense graph connectivity from MERGE operations
  • Balanced predictions: KG-RAG avoids GraphMERT's class collapse
  • Parser recovers 55%: Rule-based post-processing salvages UNKNOWN verdicts
Key Insight
GraphMERT's accuracy was illusory — 92.4% of predictions fell into one class. High accuracy masked complete failure on minority classes. KG-RAG produced balanced recall across all verdict types. The lesson: always report MCC and Cohen's κ alongside accuracy. A model that predicts "allowed" every time gets 92.4% accuracy but is legally useless.
Repository
Private repository — BITS Pilani Study Project under Prof. Hrishikesh Rajesh Terdalkar. CS F266: Study Project, Hyderabad Campus.
Project 19 · Course Project · 2024
StemCells DBMS:
Donor Management System
Full-stack donor, patient, hospital, and staff management system. Flask + MySQL with dynamic dashboard and real-time entity counting.
DBMS Full-Stack Web App
The Problem
Stem cell registries need centralized tracking of donors, patients, hospitals, and staff. Manual spreadsheets don't scale, can't enforce data integrity, and provide no real-time visibility.
The Approach
Flask + MySQL full-stack application. Dynamic dashboard with real-time entity counts. Registration forms for all 4 entity types. Normalized relational schema with foreign key constraints.
The Impact
Real-time dashboard with dynamic counts. Full CRUD operations for donors, patients, hospitals, and staff. Responsive UI that makes the system feel alive — not just a database wrapper.
4
Entity Types
Flask
Backend
MySQL
Database
CRUD
Operations
System Architecture — Full-stack CRUD application
Flask + MySQL donor management pipeline
User interactions flow through a Flask server to MySQL. Four entity tables (Donors, Patients, Hospitals, Staff) feed a dynamic dashboard with real-time counts.
🌐 User Browser Registration forms Dashboard view 🐍 Flask Server REST routes Jinja2 templates Form validation CRUD operations 🗄️ MySQL Normalized schema Foreign key constraints Data integrity multi-user support 🩸 Donors 🏥 Patients 🏢 Hospitals 👤 Staff 📊 Dashboard Real-time counts Dynamic from base 25 live system Dynamic dashboard with real-time entity counting makes the system feel alive
Step-by-step workflow
01
Database schema
Normalized MySQL schema with 4 entity tables: Donors, Patients, Hospitals, Staff. Foreign key constraints enforce referential integrity across all relationships.
MySQL · normalized design
02
Flask backend
RESTful Flask routes for all CRUD operations. Jinja2 templates for server-side rendering. Form validation and error handling for data integrity.
Flask · Jinja2 · REST
03
Registration forms
Responsive HTML forms for donor, patient, hospital, and staff registration. Client-side validation for immediate feedback. Server-side validation for security.
HTML forms · validation
04
Dynamic dashboard
Real-time entity counts starting from a base of 25. Dashboard updates dynamically as new records are added. Visual indicators for system health.
Jinja2 · dynamic counts
Technical decisions
  • Flask over Django: Simpler for CRUD-focused applications. Django's ORM and admin panel add complexity unnecessary for a 4-entity system.
  • MySQL over SQLite: Proper multi-user support with concurrent connections. SQLite's file-based locking would bottleneck in multi-user scenarios.
  • Dynamic counts from base 25: Dashboard starts with a base count and increments with real registrations — making the system feel populated and active from day one.
Key results
  • CRUD operations: Full Create, Read, Update, Delete for all 4 entity types
  • Dynamic dashboard: Real-time counts with visual entity cards
  • Responsive forms: Client + server validation for data integrity
  • Normalized schema: Foreign key constraints across all relationships
Key Insight
The gap between knowing SQL and building a working app is enormous. Writing SELECT queries in a textbook is nothing like building a full CRUD system with form validation, error handling, and responsive UI. The dynamic dashboard — showing real-time counts that update with every new registration — was the feature that made the system feel alive, not just a database wrapper.
⊕ View on GitHub → github.com/Harshaaalll/StemCells_DBMS