Nandi: complaint router for Indian languages and Hinglish (category, top 3, experimental urgency)

Nandi (nandi-grievance-indic) is an open-weights, Apache-2.0 model that reads a customer complaint in Hindi, Hinglish, 10 other Indian languages or English and returns one of 53 categories, the top 3 categories with probabilities, and an urgency level (P1/P2/P3). The categories follow the complaint lists of India's regulators and grievance systems: RBI (banking), IRDAI (insurance), CPGRAMS (central government services), TRAI/DoT (telecom) and the National Consumer Helpline, plus "not a complaint". It is a 560M-parameter XLM-RoBERTa-large encoder with two small heads.

On 443 real public posts it never saw, labelled blind Category accuracy Top-3 accuracy Macro-F1
Nandi 0.625 0.813 0.428
Qwen3.6-35B-A3B zero-shot (about 60ร— larger) 0.664 โ€“ 0.624
Yama zero-shot (same encoder size) 0.366 โ€“ 0.283

Read this before you use it.

  • Category: usable with a human in the loop. On real posts it picks the right category about 6 times in 10 and has it in the top 3 about 8 times in 10. A large zero-shot LLM is somewhat more accurate and much better on rare categories; this model's case is that it is small, local and fast.
  • Urgency: experimental on real text. It catches only about 1 in 4 real P1 (most urgent) complaints, and 1 in 10 if you leave out loan-app harassment. Do not use it to decide what gets handled first without a human check.
  • About 1 in 5 real posts that are not complaints get routed to a category anyway.
  • All training data is synthetic. Details in Evaluation and Limitations.

Key facts

  • What: a text classifier for complaint and grievance routing, with a Python route() API.
  • Languages: Hindi, Hinglish, Bengali, Tamil, Telugu, Marathi, Gujarati, Kannada, Malayalam, Punjabi, Urdu, Odia and Indian English, in native scripts and romanised. The real-text test is mostly English, Hindi and Hinglish.
  • Returns: category, domain, confidence, urgency with probabilities, and the top 3 categories.
  • Runs: locally on CPU or GPU, no API calls; Apache-2.0, free for commercial use.

The name. In Shiva temples, devotees whisper their wishes into the ear of Nandi, the bull who keeps Shiva's gate; Nandi does not grant the wish but makes sure it reaches the right place. This model does the same with complaints: it does not resolve them, it sends each one to the right desk. It is a companion to Yama, a zero-shot classifier, and Chitragupta, a PII detector, for the same languages.

Nandi is an independent personal release.

Parameters about 560M (XLM-RoBERTa-large, mean pooling, a 53-way category head and a 3-way urgency head)
Input up to 512 tokens (longer texts are cut)
Training 3 epochs over 109,776 synthetic complaints and non-complaints in 13 languages
Licence Apache-2.0

Quickstart

# pip install torch transformers safetensors huggingface_hub
import sys
from huggingface_hub import snapshot_download

path = snapshot_download("arunp0/nandi-grievance-indic")
sys.path.insert(0, path)
from router import ComplaintRouter

r = ComplaintRouter(path)                   # GPU if available
r.route("UPI se 2,000 rupaye kat gaye par receiver ko nahi mile, aaj subah ki baat hai. Bank helpline koi jawab nahi de raha.")
# {'category': 'bank.digital_banking', 'domain': 'bank', 'confidence': 0.9999, 'urgency': 'P1',
#  'urgency_probs': {'P1': 0.868, 'P2': 0.0012, 'P3': 0.1307},
#  'top3': [('bank.digital_banking', 0.9999), ('bank.fraud_unauthorised_txn', 0.0), ('con.ecommerce', 0.0)]}

r.route("Thank you SBI for the quick help at the Andheri branch today!")
# {'category': 'none.out_of_scope', 'domain': 'none', ..., 'urgency': 'P3', ...}

r.route_batch(list_of_texts)                # batched

router.py is the supported way to run the model; taxonomy.py holds the 53 categories, their descriptions and their mapping to the official lists. Confidence values are not calibrated: the model is often 0.99+ sure when it is wrong on real text, so do not use confidence alone to skip human review. Use the top 3 for routing suggestions. The evaluation numbers were computed on GPU in bfloat16 (the blind real set with a float16 copy of these weights); the published float32 weights on CPU can differ on a few borderline texts (29 of 30 identical in a spot check).

Categories

Six domains: banking and payments (RBI) 14 categories, insurance (IRDAI) 12, central government services (CPGRAMS) 17, telecom 4, consumer 5, and none.out_of_scope (praise, plain questions, suggestions, chit-chat, news, opinions and other posts with no service problem). The full list, with how each category is grounded, is at the end of this card.

Grounding tiers. form (23): a verbatim item on an official complaint form (RBI Integrated Ombudsman Scheme, IRDAI). cpgrams (17): a published CPGRAMS ministry category. nch (4): a sector named by the National Consumer Helpline. derived (4): an official bucket split because routing or urgency differs (for example fraud split out of digital banking). inferred (5): no published category name, defined here (railways, ration/PDS, telecom billing, telecom other, coaching). The category names belong to the regulators and are cited as facts; this schema is a derived mapping, not an official one.

Boundary choices (decided before the final test):

  • Fraud beats the payment method: a fraudulent UPI debit is bank.fraud_unauthorised_txn, not bank.digital_banking.
  • Insurance mis-sold by a bank is bank.misselling_parabanking; by an insurer or agent, ins.misselling_ufbp.
  • A government hospital or PM-JAY/CGHS problem is gov.health_hospitals; an insurer's health claim is ins.health_claim.
  • A review criticising an app or service the writer used is a complaint even if it asks for nothing.
  • Not complaints: news or information posts, live traffic or event updates, opinions about a policy, and reports of a crime by someone else or requests asking the police to act against someone. None of the grievance systems above handles crime, and there is no police category. Misconduct or bribery by officials is a complaint (gov.corruption_misconduct).
  • If a message has several problems, the most time-critical one wins.

Urgency

Level Meaning
P1 Money lost to fraud, an unauthorised debit or a failed transfer within the last ~3 days; health or safety at risk now (patient waiting on cashless approval, gas leak, unsafe on a train); threats or abuse by recovery agents or loan apps; a complete outage now; someone stranded now
P2 A short official turnaround (up to a few weeks) has been missed, or the provider ignored earlier complaints or missed its own promised date
P3 Routine; no short deadline. Every non-complaint is P3

The levels are loosely based on published turnaround times (RBI, IRDAI, TRAI, CPGRAMS) as of 2026. The model outputs a level, never a deadline. This is not legal advice. On real text the urgency head is experimental; see Evaluation.

Training data

All training text is synthetic. No real complaints, production data or customer data were used for training.

The training and test data are public: arunp0/nandi-grievance-synthetic (116,199 training and 2,985 test rows, Apache-2.0). In the released copy, real company names were replaced with placeholders such as Bank A or Telco B after training; on that test set this model scores 0.932 accuracy and 0.912 macro-F1 (0.931 and 0.911 on the original text, 2,963 of 2,985 predictions identical).

  • Writers: Gemma 4 26B-A4B-it (94,903 rows) and Gemma 4 31B-it (21,296 rows), both open weights under Apache-2.0. Channels: forum posts, emails, social posts, chat messages, app-store reviews, ombudsman forms, formal letters, tweets and helpline-call transcripts. Lengths from one line to about 150 words.
  • Languages: Hinglish 22,047, English 16,422, Hindi 14,997, and 5,029โ€“8,019 each for Marathi, Bengali, Tamil, Telugu, Urdu, Malayalam, Gujarati, Kannada, Odia and Punjabi.
  • Labels. In the first rounds, code chose the scenario (category, timing facts, history) and Gemma wrote the text; Qwen3.6-35B-A3B (Apache-2.0) then labelled each text blind, and rows where it disagreed were dropped. Later rounds wrote freer text, closer to real reviews and tweets, and labelled it with two open-weight teachers (Gemma 4 31B and Qwen3.6); only rows where both agreed on the category, and did not disagree about P1, were kept. So labels are "scenario-designed or teacher-labelled, LLM-written, cross-checked by a second model".
  • 15,902 rows are non-complaints; 24,638 are P1.
  • Every person, account, phone or policy number in training text is a dummy value.
  • No output of a proprietary model is in the training data. Claude (Anthropic) was used only to build and label evaluation sets, never for training data.

Evaluation

Real text (headline)

No openly licensed set of real Indian complaints with categories exists, so three private sets of real public posts were built. They are never trained on or released; only aggregate scores are reported.

Blind set (443 posts) from public Play Store and App Store India reviews and a public HR forum, collected read-only after the model was frozen. 38% are not English (mostly Hindi and Hinglish; other Indian languages are thin). Apps and companies used in the two earlier real sets were excluded. Three independent Claude agents labelled every post blind from the text alone, using the same written definitions the training teachers used; 2-of-3 votes decide. The labels are LLM-reviewed, not human-verified, and the three labellers are the same model, so their 91% agreement overstates how reliable the labels are. The evaluation plan and the decision rules were written down before any post was collected, and the set was scored once.

Nandi Qwen3.6 zero-shot Yama zero-shot
Category accuracy 0.625 0.664 0.366
Category macro-F1 0.428 0.624 0.283
Top-3 accuracy 0.813 โ€“ โ€“
Domain accuracy 0.749 0.797 0.497
Non-complaints routed to a category (62) 21.0% 22.6% 54.8%
P1 recall (75) 0.25 [0.17, 0.36] 0.20 0.69
P1 recall, loan-app harassment (35) 0.43 [0.28, 0.59] 0.31 0.66
P1 recall, all other P1 (40) 0.10 [0.04, 0.23] 0.10 0.73
P1 precision 0.70 0.65 0.32

Brackets are Wilson 95% intervals. 433 of the 443 posts have no product overlap with the earlier sets; scores on them are within 0.01 of the table.

  • The accuracy gap to Qwen (3.9 points) is not statistically clear on this set (McNemar p โ‰ˆ 0.15 before the correction below). The macro-F1 gap comes from rare categories, where Nandi is weaker.
  • Yama flags far more posts as P1, so its recall is high and its precision low.
  • Correction, disclosed. The labelling guide wrongly told labellers to put recovery-agent threats under bank.loan_advances instead of the taxonomy's bank.recovery_harassment. On those 35 posts either category is accepted. Before this correction Nandi scored 0.571 accuracy / 0.397 macro-F1 (Qwen 0.607 / 0.593, Yama 0.352 / 0.256). Urgency numbers are unaffected.

Urgency on real text

Real urgent posts rarely state their timing the way the training scenarios do, and both Nandi and Qwen miss most of them. Treat the urgency output as a hint, not a triage decision. The labellers also read "a failed transfer" to include recent merchant payments that were debited but not credited (recharges, tickets, tolls), which the model mostly calls P3.

Earlier real sets (used to choose between model versions, so not blind): on 240 public reviews and complaint-forum posts, category accuracy 0.696 (Qwen 0.738); on a second set of 154 Play Store reviews, 0.656.

Public tweets (development set). The Mendeley "Enhanced Dataset of Citizen Centric Complaints and Grievances on Twitter" (Agarwal, Mittal and Sureka, IIIT-Delhi; CC BY 4.0) has English tweets to Indian Railways, the Income Tax Department, Delhi Police and Delhi Traffic Police. 2,249 tweets were relabelled with this taxonomy by Claude agents, with the official @handles masked because they give the category away. Error examples were read while choosing between versions, so this is a development set, not a test. Category accuracy 0.668 and top-3 0.806 on 1,198 complaints; 40% of 1,051 non-complaints routed to a category; P1 recall 26/43.

Synthetic test

2,985 complaints in 13 languages written by a different model from the training writer (Qwen3.6), with held-out channels (call transcripts, portal forms) and personas, checked by Gemma.

Nandi Qwen3.6 zero-shot Yama zero-shot TF-IDF + logistic regression
Category macro-F1 0.909 0.888 0.536 0.604
Category accuracy 0.929 0.913 0.543 0.597
Top-3 accuracy 0.971 โ€“ โ€“ 0.788
P1 recall (rows whose P1 label a blind checker confirmed) 0.955 0.904 0.925 0.540
Non-complaints routed to a category 7.3% 5.2% 42.9% 0.0%

Per-language category accuracy: English 0.98, Hinglish 0.97, Marathi 0.97, Hindi 0.96, Gujarati 0.94, Telugu 0.91, Kannada 0.91, Punjabi 0.91, Malayalam 0.90, Bengali 0.90, Tamil 0.88, Odia 0.88, Urdu 0.87.

The synthetic test follows the same definitions as training, so it overstates real-world accuracy; the real-text numbers above are the ones to plan with. The 625 test rows that the checker disagreed with (the contested slice) were not scored for this version.

Pre-registered rules

Before any data was generated: ship only if, on the synthetic test, P1 recall (checked) โ‰ฅ 0.90, macro-F1 โ‰ฅ Yama + 0.10 and non-complaint false alarms โ‰ค 10%. Passed (0.955; 0.909 vs 0.636; 7.3%). Before the blind real set was collected: the category head ships only if its macro-F1 is โ‰ฅ Yama + 0.10 there; urgency is called reliable only if the lower end of its P1-recall interval is โ‰ฅ 0.50 overall, and (added while the set was being labelled, before scoring) also without loan-app posts. Category passed, but not by a wide margin: 0.428 vs 0.383 (0.397 vs 0.356 before the correction); the margin over Yama is 0.141 before the correction with a bootstrap 95% interval of [0.07, 0.24], and 89% of resamples clear the 0.10 bar. Urgency did not pass, so it is marked experimental.

Limitations

  • Synthetic training data. Real complaints are shorter, vaguer and messier. Accuracy drops from 0.93 on the synthetic test to about 0.63 on real posts.
  • Urgency is experimental on real text (above).
  • Non-complaints. About 1 in 5 real non-complaints (praise, questions, opinions) get a complaint category; on public tweets it was about 2 in 5. Attempts to tighten this cost recall on real traffic and transport complaints, so they were not shipped.
  • Rare categories are weak on real text (macro-F1 0.43).
  • Confidence is not calibrated: high confidence does not mean the answer is right.
  • Real-text evaluation is English, Hindi and Hinglish heavy. Other Indian languages are tested only on synthetic text.
  • Labels for every real-text number are LLM-reviewed, not human-verified.
  • Category names and turnaround times are as of 2026; regulators change their lists. Not legal advice.
  • It routes; it does not resolve complaints or decide whether one is valid.

Files

File What
model.safetensors, config.json XLM-RoBERTa-large encoder weights
heads.safetensors category and urgency heads
router_config.json category and urgency order, max length
tokenizer.json, tokenizer_config.json tokenizer
router.py ComplaintRouter with route() / route_batch()
taxonomy.py the 53 categories, descriptions, grounding tiers and official mappings
LICENSE, NOTICE Apache-2.0; XLM-RoBERTa MIT notice

Citation

@misc{prabhakaran2026nandi,
  author = {Arun Prabhakaran},
  title  = {Nandi: complaint routing for Indian languages and Hinglish},
  year   = {2026},
  url    = {https://huggingface.co/arunp0/nandi-grievance-indic}
}

The development tweets come from: Agarwal, Mittal and Sureka (IIIT-Delhi), Enhanced Dataset of Citizen Centric Complaints and Grievances on Twitter, Mendeley Data, https://data.mendeley.com/datasets/w2cp7h53s5 (CC BY 4.0).

Licence

Apache-2.0. Copyright 2026 Arun Prabhakaran. The encoder is fine-tuned from FacebookAI/xlm-roberta-large (MIT); see NOTICE.

All 53 categories

Category Covers Tier Official mapping
bank.atm_debit_card ATM cash not dispensed, debit card blocked, card charges or replacement form RB-IOS form i ATM/Debit Cards
bank.digital_banking UPI, IMPS, NEFT, net or mobile banking failure, pending or failed transfer, wallet problems form RB-IOS form v Internet/Mobile/Electronic Banking
bank.fraud_unauthorised_txn Unauthorised or fraudulent debit, phishing, SIM swap, card skimming, scam payment derived split of RB-IOS i/iii/v; CPGRAMS DFS-Banking 'Fraud'
bank.credit_card Credit card billing, charges, limits, closure, disputed card transactions form RB-IOS form iii Credit Cards
bank.loan_advances Loan sanction or disbursal, interest or EMI, foreclosure, return of property documents, NBFC or app loans form RB-IOS form vi Loans and advances
bank.recovery_harassment Recovery agents, coercive collection calls or visits, Fair Practices Code breaches derived split of RB-IOS vi (recovery agents, harassment, FPC)
bank.deposit_account Savings or current account opening, operation, closure, charges, minimum balance, interest, locker form RB-IOS form iv Deposit Account
bank.kyc_freeze KYC update problems, account frozen or debit-frozen form RB-IOS form xi KYC updation
bank.remittance_cheque Cheque, demand draft or bill collection, inward or outward remittance form RB-IOS form xiv Remittance and collection
bank.pension_senior Pension credited by a bank, arrears, facilities for senior citizens form RB-IOS form x Pensions and facilities for Senior Citizens
bank.misselling_parabanking Insurance, mutual fund or other third-party product sold by a bank, mis-selling form RB-IOS form viii Para-Banking, ix Mis-selling
bank.staff_behaviour Rude, discriminatory or corrupt behaviour by bank staff form RB-IOS form xiii Staff behaviour
bank.credit_report Credit score or credit bureau report errors derived RBI annual report CIC rows
bank.other Other banking: notes and coins, guarantees, premises, government business, access for differently abled form RB-IOS form ii, vii, xii, xv, xvi
ins.death_claim Life insurance death claim delayed or rejected form IRDAI life: Death Claims
ins.survival_maturity Survival benefit, maturity or annuity payout delayed or wrong form IRDAI life: Survival Claims
ins.health_claim Health insurance cashless denial or delay, reimbursement rejected or partly paid form IRDAI life: Health Claims; non-life: Claims x Health
ins.motor_claim Motor insurance own-damage or third-party claim, survey delay form IRDAI non-life: Claims x Motor
ins.property_crop_other_claim Fire, crop, travel or other non-life claims, surveyor or loss assessment form IRDAI non-life: Claims x Fire/Crop/Misc
ins.policy_servicing Surrender, policy loan, nominee or address change, revival, policy document not received form IRDAI life: Policy Servicing; non-life: Policy Related
ins.proposal_processing Proposal pending or rejected, cover note not issued form IRDAI: Proposal Processing; Cover Note
ins.misselling_ufbp Policy mis-sold by an insurer or agent, unfair business practice, fake bonus calls form IRDAI life: Unfair Business Practices; non-life: Product/Sales related
ins.ulip ULIP fund value, switch or NAV problems form IRDAI life: ULIP Related
ins.premium_refund Premium wrongly debited, refund or free-look cancellation not paid form IRDAI non-life: Premium; Refund
ins.coverage_policy_terms Dispute about what the policy covers or its terms form IRDAI non-life: Coverage
ins.other Other insurance complaints form IRDAI: Others
gov.pf_epfo PF withdrawal, settlement, transfer, member detail correction, employer not depositing PF cpgrams MoLBR PF categories
gov.pension EPS, civil or defence pension from a government body cpgrams MoLBR Pension (EPS); uniform 'Pension Related'
gov.employee_service Pay, allowances and service matters of government employees cpgrams uniform 'Employee Services Related'; Defence Finance 'Pay & Allowance'
gov.agri_pmkisan PM-KISAN instalments stopped or not received, land record approval cpgrams DOAAC PM-KISAN categories
gov.housing_pmay PMAY housing benefit or HUDCO cpgrams DOURD PMAY; MoHUA HUDCO
gov.income_tax_pan Income tax refund, wrong demand, PAN problems cpgrams CBDT Refund/Wrong Demand; PAN Issues
gov.aadhaar Aadhaar update or enrolment problems cpgrams UIDAI Non Updation of AADHAAR
gov.passport Passport application or police verification delay cpgrams MEA Passport Application Related
gov.postal Postal article delayed, not delivered or lost, post office savings cpgrams DPOST Delay/Non-Delivery/Abstraction
gov.railways Train ticket, refund, onboard service or station problems inferred Railways (category names not published)
gov.roads_transport Road condition, driving licence or vehicle registration, transport cpgrams MoRTH Roads; Transport Related
gov.health_hospitals Government hospital, CGHS or PM-JAY treatment denied or poor cpgrams DHLTH Hospitals
gov.lpg_fuel LPG booking, delivery, agency or short weight cpgrams MoPNG LPG/LPG Agency Related
gov.ration_pds Ration card or public distribution supply inferred Food & Public Distribution (names not published)
gov.cooperative Cooperative society or cooperative bank disputes cpgrams MoCOP Central Registrar and Cooperative Society
gov.corruption_misconduct Bribery, misbehaviour or harassment by government officials cpgrams uniform 'Misbehaviour/Corruption/Harassment'
gov.other_scheme Other government scheme benefits or citizen services cpgrams uniform 'Government Schemes Related' / 'Citizen Services Related'
tel.network_coverage No signal, call drops, network outage cpgrams DoT Issues Related to Network Coverage
tel.broadband_internet Mobile data or broadband speed or outage cpgrams DoT Broadband Related
tel.billing_recharge Wrong bill, recharge not credited, unwanted value-added service charges inferred TRAI billing complaints (no official category list)
tel.other SIM, porting, spam calls or other telecom problems inferred Telecom (no official category list)
con.ecommerce Online order not delivered, wrong or defective item, refund or return refused nch NCH sector E-commerce
con.durables_electronics Appliance or electronics defect, warranty, service centre nch NCH sectors Consumer Durables, Electronics Products
con.travel_airlines Flight, travel or hotel refund and cancellation nch NCH sector Travel & Tourism
con.education_coaching Coaching or edtech refund, service not delivered inferred PIB NCH coaching refund cases
con.other Other consumer complaints: food, retail, automobile, real estate, electricity nch NCH: Food, Retail Outlets, Direct Selling, Agency Services, Others
none.out_of_scope Not a routable grievance: a question, praise, spam, court matter, employer-employee dispute derived RB-IOS cl. 10(2) exclusions; CPGRAMS exclusions
Downloads last month
35
Safetensors
Model size
0.6B params
Tensor type
F32
ยท
Inference Providers NEW
This model isn't deployed by any Inference Provider. ๐Ÿ™‹ Ask for provider support

Model tree for arunp0/nandi-grievance-indic

Finetuned
(1082)
this model

Dataset used to train arunp0/nandi-grievance-indic

Evaluation results

  • Category accuracy on Real public posts, blind set (443 rows, private, LLM-reviewed labels)
    self-reported
    0.625
  • Top-3 accuracy on Real public posts, blind set (443 rows, private, LLM-reviewed labels)
    self-reported
    0.813
  • Category macro-F1 on Real public posts, blind set (443 rows, private, LLM-reviewed labels)
    self-reported
    0.428
  • Category macro-F1 on Synthetic test (2,985 rows, 13 languages, different writer model)
    self-reported
    0.909
  • Category accuracy on Synthetic test (2,985 rows, 13 languages, different writer model)
    self-reported
    0.929