Skip to content

hackfest-dev/HF26-13

Repository files navigation

VidyutMitra

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


The Problem

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%+

The Solution

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.

Core Innovation: Three-Module Analysis on Primary-Source Rules

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).

The Four Zeros

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

Architecture

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
Loading

Deliberate Architectural Decisions

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.

Cost Analysis

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

Services

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

Quick Start

Prerequisites

  • Python 3.11+
  • Node.js 18+ (admin dashboard only)
  • Accounts + API keys for: Google AI Studio (Gemini), Twilio (WhatsApp Sandbox), Supabase, Sarvam AI

Deploy Backend

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 keys

Initialise Supabase Schema

python scripts/init_supabase.py
# Prints the schema + paste instructions. Copy into Supabase SQL Editor,
# run it, then verify:
python scripts/init_supabase.py --verify

Deploy Dashboard

cd 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:3000

Seed Demo Data

python scripts/seed_demo_data.py   # 35 users, ~70 realistic bills
python scripts/clean_demo_data.py  # wipes DEMO-prefixed rows after rehearsal

Local Development

# 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.

Demo Mode for Judges

The project runs in demo mode by default:

  • Pre-seeded data: 35 synthetic users, ~70 bills with realistic KERC math
  • Demo fallbacks: demo_fallbacks.json caches 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:

  1. Open the admin dashboard (http://localhost:3000) and enter ADMIN_PASSWORD
  2. Summary panel: consented users, bills analysed, GJ cliff counts
  3. Sustainability panel: aggregate CO2 footprint, potential solar impact at scale
  4. Recent Activity: anonymised log of the last 10 analyses

Project Structure

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

Security & Privacy

  • DPDPA 2023 compliant by design: explicit Kannada + English consent notice, bill image NEVER persisted (bills table 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/* requires Authorization: Bearer <ADMIN_PASSWORD>, rejected otherwise
  • TLS: Twilio and Supabase both enforce TLS 1.2+ on all transit
  • DPDPA-forbidden-field guard: write_bill in db/supabase_client.py raises ValueError if ANY kwarg matches bill_image / bill_url / image_bytes / photo / etc., or if the analysis blob contains any such key
  • No committed secrets: .env gitignored, .env.example is the template, every tracked file scanned for leaked API keys pre-commit

Primary Sources (Defensibility)

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

Impact

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

Team Cube - Anjuman Institute of Technology and Management (AITM), Karnataka. Built in 36 hours at Hackfest'26, NMAMIT Nitte, April 17-19, 2026.

License

MIT

About

Hackfest26 repository for T13

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors