01 · LMA Clause Tool 02 · AutoTransFlow 03 · RAG Chatbot 04 · Medical Bill OCR 05 · Multilingual ASR 06 · Market Analysis 07 · Audit Insight 08 · Career Copilot 09 · AirFare-ML 10 · Hastkala Setu 11 · Road Safety NLP 12 · HydRERA Analytics 13 · KG-RAG Legal AI 14 · StemCells DBMS
Project 01 · 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 02 · 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 03 · 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 04 · 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 05 · 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 06 · 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 07 · 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 08 · 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 09 · 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 10 · 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 11 · 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 12 · 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 13 · 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 14 · 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