AI Energy Advisor for MESCOM Households on WhatsApp
WhatsApp-First | Kannada Voice | Zero App Downloads | DPDPA Compliant by Design
Hackfest'26 - NMAMIT Nitte | Team Cube | Sustainable Development Track
Karnataka's 22.6 lakh MESCOM households lose money every month to energy tariffs, subsidies, and solar payback math they cannot read. Climate action stalls at the first mile.
| Metric | Reality |
|---|---|
| MESCOM consumers across DK / Udupi / Chikmagalur / Shivamogga | 22.6 lakh (2.26 million) |
| Households over-provisioned on sanctioned load (10% est.) | ~Rs. 39 crore / yr in unnecessary fixed charges |
| Karnataka-wide PM Surya Ghar conversion (6,519 installs / 6.15 lakh apps) | 1.1% |
| Coastal DK + Udupi households that have even expressed interest | 0.2% (1 in 500) |
| Gruha Jyothi beneficiaries who know about the 200-unit cliff | Almost none |
| WhatsApp penetration in rural Karnataka | 95%+ |
VidyutMitra is a WhatsApp-first AI concierge. A household sends a photo of their MESCOM bill. Within 10-15 seconds they receive: a full bill analysis, subsidy eligibility verdict, solar payback math, a Kannada voice summary, and a personalised infographic. No app. No typing. No English required.
Every inbound bill passes through three deterministic analysis modules, each backed by a named primary source. This is the defensive moat: no judge can challenge a number without also challenging KERC, MNRE, or the Karnataka Cabinet.
| Module | Rule Source | What It Catches |
|---|---|---|
| Tariff Engine | KERC Tariff Order 2025 Annexure 2 | The Fixed Charge Trap (Rs. 1,740 / yr / household) |
| Subsidy Navigator | Karnataka Cabinet 18-Jan-2024 + MNRE PMSG | Gruha Jyothi 3-level cliff, PM Surya Ghar eligibility |
| Solar ROI Calculator | KERC Solar Order + CEA v21.0 + MNRE | 3.8 yr payback, 2.98 t CO2 / yr, Rs. 4.3 L lifetime savings |
AI handles the two steps where AI is defensibly better than rules: Gemini 2.5 Flash for bill extraction (vision + mixed Kannada-English OCR), Sarvam Bulbul v3 for Kannada voice (native Indian prosody).
| Principle | How |
|---|---|
| Zero App Installation | Inbound + outbound via WhatsApp Business Sandbox only |
| Zero English Required | Kannada voice note + Kannada snippets in every response |
| Zero PII Persistence | Bill images NEVER touch disk. bills schema has no bill_image column by design |
| Zero Fabricated Numbers | Every constant cites a primary source. Tests assert each value |
graph TB
subgraph "User Channels"
WA[WhatsApp Business Sandbox]
AD[Admin Dashboard<br/>Next.js 14 + Tailwind]
end
subgraph "Webhook Layer"
TW[Twilio Webhook<br/>POST /whatsapp]
MED[Flask /media<br/>serves TTS + PNG to Twilio CDN]
API[Flask /admin<br/>aggregate JSON API]
end
subgraph "Consent Gate DPDPA"
CG[consent_manager<br/>START / STOP / never-contacted]
end
subgraph "Extraction"
TM[twilio_media.py<br/>bytes only, no disk]
GC[gemini_client.py<br/>Gemini 2.5 Flash]
SV[schema_validator.py<br/>R1-R8 structural rules]
EP[pipeline.py<br/>single retry + fallback ladder]
end
subgraph "Analysis Rule-Based"
TE[tariff_engine.py<br/>KERC 2025 math]
SN[subsidy_navigator.py<br/>PMSG + GJ cliff + SWH]
SR[solar_roi.py<br/>size + payback + lifetime]
LI[load_inference.py<br/>seasonal dominant load]
CC[climate_context.py<br/>carbon footprint]
OR[orchestrator.py<br/>analyze_bill]
end
subgraph "Output"
RC[response_composer.py<br/>PRD §2.1 + §2.2 templates]
TTS[kannada_tts.py<br/>Sarvam Bulbul v3]
IG[infographic.py<br/>Pillow PNG card]
TD[twilio_dispatcher.py<br/>text + voice + image, 1-sec rate limit]
end
subgraph "Data Layer"
SB[(Supabase Postgres<br/>users + bills, no bill_image)]
LBC[(last_bill_cache<br/>30-min TTL in-memory)]
DF[(demo_fallbacks.json<br/>path-2 ladder)]
end
WA --> TW
AD --> API
TW --> CG
CG --> TM
TM --> GC
GC --> SV
SV --> EP
EP --> DF
EP --> OR
OR --> TE
OR --> SN
OR --> SR
OR --> LI
OR --> CC
OR --> RC
RC --> TTS
RC --> IG
RC --> TD
TD --> MED
OR --> SB
OR --> LBC
API --> SB
| Decision | Choice | Why Not Alternative |
|---|---|---|
| Bill OCR | Gemini 2.5 Flash (vision) | Tesseract needs preprocessing; Gemini handles rotation, low light, mixed Kannada-English text natively. ~85-92% field accuracy in-house. |
| Analysis layer | Rule-based, not ML | 15 sample bills overfits any ML model; KERC rules are deterministic and pitch-defensible against hostile judges. |
| Kannada TTS | Sarvam Bulbul v3 | Google Cloud TTS WaveNet has less native Indian prosody. Free tier covers hackathon usage. |
| Webhook framework | Flask 3 | FastAPI adds async complexity not needed at 10-req-per-demo load. Daemon thread handles the ~10-sec processing. |
| Database | Supabase (managed Postgres) | Self-hosted Postgres adds ops burden. Free tier covers hackathon. CASCADE delete for STOP is FK-level, not app-level. |
| Dashboard | Next.js 14 + Tailwind | Streamlit is Python-easy but a React SPA over a JSON API looks like real product. Aggregate-only, no PII. |
| DB schema | No bill_image column |
Deliberate DPDPA feature, not oversight. write_bill raises ValueError on any forbidden image-related kwarg. |
| Follow-up state | In-memory dict, 30-min TTL | Supabase table for this is premature; every follow-up is a pure function call on cached analysis. |
| Extraction retry | Exactly one retry, tighter prompt | More retries burn latency budget (hard cap 17s incl. retry). Two Gemini calls in 10s beats three in 25s. |
For a full production run serving every MESCOM consumer once per month:
| Component | Cost per bill | Notes |
|---|---|---|
| Gemini 2.5 Flash | ~Rs. 9 | Vision + structured JSON out, ~3 sec median |
| Sarvam Bulbul v3 | Free tier | Up to 2000 requests / month on hackathon tier |
| Twilio WhatsApp | ~Rs. 2 | Text + voice + infographic = ~4 outbound messages |
| Supabase Postgres | Free tier | 500 MB fits consent + bills table at demo scale |
| Flask on Railway | ~Rs. 400 / month flat | Webhook + admin API, single worker sufficient |
| Total per bill analysed | ~Rs. 11 | vs. Rs. 1,740 / yr saved per Fixed Charge Trap flag |
| Service | Role |
|---|---|
| Google Gemini 2.5 Flash | Bill extraction: vision + structured JSON output |
| Sarvam Bulbul v3 | Kannada TTS, OGG Opus at 16 kHz for WhatsApp native voice-note UI |
| Twilio WhatsApp Business Sandbox | Inbound webhook + outbound text / voice / image dispatch |
| Supabase (managed Postgres) | Consented-user + analyzed-bill persistence, CASCADE-delete on STOP |
| Flask 3 | Webhook server, /media route for Twilio CDN fetch, /admin JSON API |
| Next.js 14 + Tailwind | Admin dashboard, aggregate-only, bearer-token gated |
| Pillow | Pillow-drawn PNG infographic per bill (no template, draw from scratch) |
| Pytest | 305+ tests, smoke suite under 1 second |
| python-dotenv | Env var loading for local dev |
| ngrok | Webhook tunneling during local development and demo |
- Python 3.11+
- Node.js 18+ (admin dashboard only)
- Accounts + API keys for: Google AI Studio (Gemini), Twilio (WhatsApp Sandbox), Supabase, Sarvam AI
git clone https://github.com/hackfest-dev/HF26-13 vidyutmitra
cd vidyutmitra
python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -r requirements.txt
cp .env.example .env
# Fill in .env with your API keyspython scripts/init_supabase.py
# Prints the schema + paste instructions. Copy into Supabase SQL Editor,
# run it, then verify:
python scripts/init_supabase.py --verifycd vidyut-dashboard
cp .env.local.example .env.local
# Set NEXT_PUBLIC_ADMIN_PASSWORD to match ADMIN_PASSWORD in ../.env
npm install
npm run dev # http://localhost:3000python scripts/seed_demo_data.py # 35 users, ~70 realistic bills
python scripts/clean_demo_data.py # wipes DEMO-prefixed rows after rehearsal# Terminal 1: Flask webhook
python app.py
# Terminal 2: expose via ngrok
ngrok http 5001
# Update PUBLIC_BASE_URL in .env to the ngrok URL, then restart Flask.
# Configure Twilio WhatsApp Sandbox webhook to <ngrok-url>/whatsapp.
# Join the Twilio sandbox from your phone and send START.The project runs in demo mode by default:
- Pre-seeded data: 35 synthetic users, ~70 bills with realistic KERC math
- Demo fallbacks:
demo_fallbacks.jsoncaches real extractions for known demo phones; if Gemini is rate-limited or down, the pipeline falls back automatically - Dashboard charts display real aggregate data from Supabase
- Activity table is anonymised: no phone numbers or consumer names, ever
To explore:
- Open the admin dashboard (http://localhost:3000) and enter
ADMIN_PASSWORD - Summary panel: consented users, bills analysed, GJ cliff counts
- Sustainability panel: aggregate CO2 footprint, potential solar impact at scale
- Recent Activity: anonymised log of the last 10 analyses
vidyutmitra/
app.py # Flask webhook + /media + admin blueprint registration
admin_api.py # Aggregate-only JSON API for the admin dashboard
config/
tariff_constants.py # All verified KERC / CEA / GJ constants with citations
personas.py # Frozen demo persona fixtures
extraction/
gemini_client.py # Gemini 2.5 Flash integration
prompts.py # Bill extraction prompt
schema_validator.py # 8 structural validation rules (R1-R8)
pipeline.py # Extraction orchestrator with retry + fallback
twilio_media.py # Twilio CDN media fetch (no disk writes)
analysis/
tariff_engine.py # Bill recalc + Fixed Charge Trap detection
subsidy_navigator.py # PM Surya Ghar + GJ visibility + SWH rebate
solar_roi.py # System sizing + ROI + climate impact
load_inference.py # Seasonal dominant-load inference
climate_context.py # Carbon footprint + conservation tips
orchestrator.py # analyze_bill, single analysis entry point
consent/
consent_manager.py # START / STOP flow (DPDPA consent gate)
output/
response_composer.py # WhatsApp text + Kannada voice templates
twilio_dispatcher.py # Outbound messages + rate limiting
kannada_tts.py # Sarvam Bulbul v3 client
infographic.py # Pillow-drawn PNG summary card
last_bill_cache.py # In-memory follow-up state (30-min TTL)
db/
supabase_client.py # Persistence wrapper (DPDPA-guarded)
schema.sql # DDL, deliberately no bill_image column
vidyut-dashboard/ # Next.js 14 admin dashboard (aggregate-only)
tests/ # 305+ pytest tests
scripts/
init_supabase.py # One-time schema initialiser
seed_demo_data.py # Deterministic synthetic data for dashboard
clean_demo_data.py # Wipe DEMO-prefixed rows post-rehearsal
docs/
briefing_v4.md # Canonical product context
prd_v3.md # Product requirements
tech_spec_v1_1.md # Technical specification
reconciliation_research.md # Why numbers are what they are
- DPDPA 2023 compliant by design: explicit Kannada + English consent notice, bill image NEVER persisted (
billstable has no image column), one-word STOP hard-deletes with CASCADE, no soft-delete column, not a checkbox - Aggregate-only admin dashboard: every query is COUNT / AVG / SUM or anonymised projection. No route surfaces phone number, consumer name, or RR number
- Bearer-token gated admin API:
/admin/*requiresAuthorization: Bearer <ADMIN_PASSWORD>, rejected otherwise - TLS: Twilio and Supabase both enforce TLS 1.2+ on all transit
- DPDPA-forbidden-field guard:
write_billindb/supabase_client.pyraisesValueErrorif ANY kwarg matchesbill_image/bill_url/image_bytes/photo/ etc., or if the analysis blob contains any such key - No committed secrets:
.envgitignored,.env.exampleis the template, every tracked file scanned for leaked API keys pre-commit
Every numeric constant in config/tariff_constants.py carries an inline
citation. Defending a number is a one-line grep:
- KERC Tariff Order 2025, Order Dated 27 March 2025, Annexure 2 - flat Rs. 5.80/unit, Rs. 145/kW/month fixed, LT-1 domestic code
- KERC Solar Tariff Order, effective 1 July 2025 - Rs. 2.48/unit export for 2-3 kW systems under PM Surya Ghar
- CEA CO2 Baseline Database Version 21.0, December 2025 - 0.710 kg CO2 / kWh weighted average for FY 2024-25
- Karnataka Cabinet Order, 18 January 2024 - Gruha Jyothi entitlement formula
min(historical_avg + 10, 200) - MNRE PM Surya Ghar Muft Bijli Yojana - Rs. 30,000/kW first 2 kW, Rs. 18,000 third kW, Rs. 78,000 cap
| SDG | Contribution |
|---|---|
| SDG 7 - Affordable Clean Energy | Removes first-mile friction to rooftop solar adoption across 22.6 lakh MESCOM households |
| SDG 13 - Climate Action | Every bill response surfaces household carbon footprint and scale-equivalent CO2 savings |
| SDG 1 - No Poverty | Makes Rs. 12,960 / yr Gruha Jyothi subsidy visible to each beneficiary; prevents the 200-unit cliff loss |
| SDG 10 - Reduced Inequalities | Kannada voice note + Kannada text snippets include non-English-literate households; WhatsApp-only removes app-download barrier |
Team Cube - Anjuman Institute of Technology and Management (AITM), Karnataka. Built in 36 hours at Hackfest'26, NMAMIT Nitte, April 17-19, 2026.
MIT