MOHAN799S commited on
Commit
0c4bd2e
·
1 Parent(s): 3d3f5e1

fix: register BERT model folders as proper git submodules

Browse files
.gitmodules ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [submodule "civicconnect-bert-en"]
2
+ path = civicconnect-bert-en
3
+ url = https://huggingface.co/mohanbot799s/civicconnect-bert-en
4
+ [submodule "civicconnect-bert-indic"]
5
+ path = civicconnect-bert-indic
6
+ url = https://huggingface.co/mohanbot799s/civicconnect-bert-indic
7
+ [submodule "civicconnect-urgency-en"]
8
+ path = civicconnect-urgency-en
9
+ url = https://huggingface.co/mohanbot799s/civicconnect-urgency-en
10
+ [submodule "civicconnect-urgency-indic"]
11
+ path = civicconnect-urgency-indic
12
+ url = https://huggingface.co/mohanbot799s/civicconnect-urgency-indic
README.md CHANGED
@@ -1,11 +1,942 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  ---
2
- title: Civicconnect Ai Engine
3
- emoji: 😻
4
- colorFrom: yellow
5
- colorTo: green
6
- sdk: docker
7
- pinned: false
8
- license: mit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9
  ---
10
 
11
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
1
+ # CivicConnect AI Engine
2
+
3
+ > Multilingual Civic Grievance Classification API
4
+ > Deployed on Hugging Face Spaces · Built for Kakinada Municipal Corporation
5
+
6
+ ---
7
+
8
+ ## Table of Contents
9
+
10
+ 1. [Project Overview](#1-project-overview)
11
+ 2. [System Architecture](#2-system-architecture)
12
+ 3. [Folder Structure](#3-folder-structure)
13
+ 4. [API Endpoints](#4-api-endpoints)
14
+ 5. [Input Modes](#5-input-modes)
15
+ 6. [Grievance Categories](#6-grievance-categories)
16
+ 7. [Grievance Validation Logic](#7-grievance-validation-logic)
17
+ 8. [Image Pipeline](#8-image-pipeline)
18
+ 9. [Audio Pipeline](#9-audio-pipeline)
19
+ 10. [Language Support](#10-language-support)
20
+ 11. [Priority Engine (XPE)](#11-priority-engine-xpe)
21
+ 12. [Explainability (Integrated Gradients)](#12-explainability-integrated-gradients)
22
+ 13. [Fairness Audit (GFAS)](#13-fairness-audit-gfas)
23
+ 14. [Hotspot Forecasting](#14-hotspot-forecasting)
24
+ 15. [Location Validation](#15-location-validation)
25
+ 16. [Ward Bounding Boxes](#16-ward-bounding-boxes)
26
+ 17. [Models Used](#17-models-used)
27
+ 18. [Requirements](#18-requirements)
28
+ 19. [Environment Variables](#19-environment-variables)
29
+ 20. [Running Locally](#20-running-locally)
30
+ 21. [Deploying to Hugging Face Spaces](#21-deploying-to-hugging-face-spaces)
31
+ 22. [API Request & Response Examples](#22-api-request--response-examples)
32
+ 23. [Error Codes Reference](#23-error-codes-reference)
33
+ 24. [Testing Grievance Inputs](#24-testing-grievance-inputs)
34
+ 25. [Known Limitations](#25-known-limitations)
35
+
36
+ ---
37
+
38
+ ## 1. Project Overview
39
+
40
+ CivicConnect AI Engine is the machine learning backend for the CivicConnect platform — a civic grievance management system built for Kakinada Municipal Corporation, Andhra Pradesh, India.
41
+
42
+ Citizens submit complaints about public infrastructure issues via text, voice, or photo. This engine:
43
+
44
+ - Classifies the grievance into one of 8 civic categories
45
+ - Detects urgency level
46
+ - Computes a priority score for routing
47
+ - Validates the image location against Kakinada ward boundaries
48
+ - Generates explainability tokens showing why the classification was made
49
+ - Detects and rejects non-grievance inputs (greetings, observations, off-topic messages)
50
+ - Supports English, Hindi, and Telugu
51
+
52
+ The API is consumed by the CivicConnect Node.js/Express backend. MongoDB storage and Cloudinary media handling are managed by the Express layer — this engine handles only ML inference.
53
+
54
+ ---
55
+
56
+ ## 2. System Architecture
57
+
58
+ ```
59
+ Citizen App (React Native / Web)
60
+
61
+
62
+ Express / Node.js Backend
63
+ (MongoDB · Cloudinary · Auth)
64
+
65
+ ▼ HTTP POST
66
+ ┌─────────────────────────────────────────┐
67
+ │ CivicConnect AI Engine │
68
+ │ (Flask API) │
69
+ │ │
70
+ │ ┌─────────────────────────────────┐ │
71
+ │ │ /predict (main endpoint) │ │
72
+ │ │ │ │
73
+ │ │ Input Mode Detection │ │
74
+ │ │ A: Image only │ │
75
+ │ │ B: Audio only │ │
76
+ │ │ C: Text only │ │
77
+ │ │ D: Text + Image (evidence) │ │
78
+ │ │ E: Audio + Image (evidence) │ │
79
+ │ │ │ │
80
+ │ │ Grievance Validation Gate │ │
81
+ │ │ ├─ Reject greetings/fillers │ │
82
+ │ │ ├─ Detect civic topic │ │
83
+ │ │ └─ Detect animal harm │ │
84
+ │ │ │ │
85
+ │ │ OpenCV + GIT-large (image) │ │
86
+ │ │ Whisper (audio) │ │
87
+ │ │ │ │
88
+ │ │ BERT / IndicBERT │ │
89
+ │ │ ├─ Category classification │ │
90
+ │ │ └─ Urgency classification │ │
91
+ │ │ │ │
92
+ │ │ XPE Priority Engine │ │
93
+ │ │ IG Explainability │ │
94
+ │ └─────────────────────────────────┘ │
95
+ │ │
96
+ │ /fairness-audit (GFAS) │
97
+ │ /hotspot-forecast (Prophet) │
98
+ └─────────────────────────────────────────┘
99
+ ```
100
+
101
+ ---
102
+
103
+ ## 3. Folder Structure
104
+
105
+ ```
106
+ civicconnect-ai-engine/
107
+
108
+ ├── app.py # Main Flask API — all endpoints
109
+
110
+ ├── classification/
111
+ │ ├── bert_classify.py # English BERT category classifier
112
+ │ └── indic_bert_classify.py # Hindi/Telugu IndicBERT classifier
113
+
114
+ ├── sentiment_analysis/
115
+ │ ├── bert_predict.py # English BERT urgency classifier
116
+ │ └── indic_bert_predict.py # Hindi/Telugu urgency classifier
117
+
118
+ ├── multi_modal/
119
+ │ ├── image_to_text.py # OpenCV preprocessing + GIT-large captioning + EasyOCR
120
+ │ └── audio_to_text.py # Whisper audio transcription
121
+
122
+ ├── xpe/
123
+ │ ├── priority_engine.py # Computes priority score + band
124
+ │ ├── integrated_gradients_explainer.py # IG token attribution
125
+ │ └── hybrid_explainer.py # Generates human-readable explanation
126
+
127
+ ├── gfas/
128
+ │ └── __init__.py # Grievance Fairness Audit System
129
+ ├── requirements.txt # Python dependencies
130
+ └── README.md # This file
131
+ ```
132
+
133
+ ---
134
+
135
+ ## 4. API Endpoints
136
+
137
+ ### `GET /`
138
+ Health check. Returns API version, status, and available endpoints.
139
+
140
+ ### `GET /health`
141
+ Lightweight liveness probe. Returns `{"status": "ok"}`.
142
+
143
+ ### `POST /predict`
144
+ Main inference endpoint. Accepts text, audio, image, or combinations.
145
+ Content-Type: `multipart/form-data` or `application/json`.
146
+
147
+ ### `POST /fairness-audit`
148
+ Runs GFAS fairness audit on a batch of grievances.
149
+ Content-Type: `application/json`.
150
+
151
+ ### `POST /hotspot-forecast`
152
+ Runs Prophet time-series forecasting to predict civic issue hotspots.
153
+ Content-Type: `application/json`.
154
+
155
+ ---
156
+
157
+ ## 5. Input Modes
158
+
159
+ The `/predict` endpoint auto-detects which mode to use based on what fields are present in the request.
160
+
161
+ | Mode | Fields Sent | Description |
162
+ |------|-------------|-------------|
163
+ | A | `image` only | Image with GPS — location validated, GIT caption extracted |
164
+ | B | `audio` only | Audio file — transcribed via Whisper, then classified |
165
+ | C | `text` only | Plain text complaint — validated and classified |
166
+ | D | `text` + `image` | Text is the grievance, image is location evidence |
167
+ | E | `audio` + `image` | Audio is the grievance, image is location evidence |
168
+
169
+ **Mode A** — GPS location is validated against Kakinada Municipal Corporation boundaries. Hard reject if outside jurisdiction or no GPS data.
170
+
171
+ **Modes D & E** — Text/audio is the primary grievance. Image is evidence only — soft-flagged if non-civic, never a hard reject.
172
+
173
+ ---
174
+
175
+ ## 6. Grievance Categories
176
+
177
+ The classifier outputs one of these 8 categories:
178
+
179
+ | Category | Examples |
180
+ |----------|---------|
181
+ | `electricity` | Broken streetlight, fallen pole, dangling wire, power cut |
182
+ | `garbage` | Uncollected waste, overflowing bin, garbage dumped on road |
183
+ | `pollution` | Factory smoke, burning garbage, chemical spill |
184
+ | `public transport` | Broken bus stop, auto stand encroachment, accident scene |
185
+ | `roads` | Pothole, road crack, footpath broken, road excavation |
186
+ | `sanitation` | Open manhole, blocked drain, sewage overflow, open defecation |
187
+ | `stray animals` | Dogs biting residents, cattle blocking road, animal carcass |
188
+ | `water` | No water supply, pipe burst, waterlogging, flooded road |
189
+
190
+ ---
191
+
192
+ ## 7. Grievance Validation Logic
193
+
194
+ User-typed text (Mode C and Mode D) goes through a three-stage validation gate before classification. Machine-generated text (GIT captions, Whisper transcripts) skips the intent check.
195
+
196
+ ### Stage 1 — Conversational rejection
197
+ Full-string anchored pattern. Fires only when the **entire** input is a greeting, filler, or non-content phrase.
198
+
199
+ ```
200
+ "Good morning" → REJECTED (full match)
201
+ "Hi" → REJECTED (full match)
202
+ "Namaste" → REJECTED (full match)
203
+ "Good morning, pothole on road" → PASSES (has content after greeting)
204
+ ```
205
+
206
+ ### Stage 2a — Animal harm pattern
207
+ Self-contained check. Fires when animal + harm verb + victim are all present within 50 characters of each other. No separate civic noun required.
208
+
209
+ ```
210
+ "dogs biting people" → GRIEVANCE ✅
211
+ "stray dogs attacked my child" → GRIEVANCE ✅
212
+ "there are lots of dogs in the area biting people" → GRIEVANCE ✅
213
+ "dogs are barking at night" → NOT (no harm + victim)
214
+ "there are dogs in the area" → NOT (no harm signal)
215
+ ```
216
+
217
+ ### Stage 2b — Civic topic presence
218
+ A civic infrastructure term alone is sufficient. The user observing a civic issue IS reporting it — formal complaint language is not required.
219
+
220
+ ```
221
+ "Hello, I can see garbage on the road" → GRIEVANCE ✅
222
+ "Hi, the road has a pothole" → GRIEVANCE ✅
223
+ "there is water on the street" → GRIEVANCE ✅ (waterlogging)
224
+ "I see a broken pipe nearby" → GRIEVANCE ✅
225
+ "I notice the streetlight is off" → GRIEVANCE ✅
226
+ "dogs are barking at night" → NOT ❌ (not a civic topic)
227
+ "there are people on the road" → NOT ❌ (no civic topic)
228
+ ```
229
+
230
+ ### Civic topic terms (selected)
231
+
232
+ Roads: `pothole`, `road damage`, `footpath broken`, `pavement crack`
233
+ Water: `waterlogging`, `pipe burst`, `drain overflow`, `sewage overflow`, `water on the road/street`
234
+ Electricity: `streetlight`, `fallen electric pole`, `live wire`, `dangling wire`
235
+ Garbage: `garbage`, `waste`, `overflowing bin`, `garbage dump`
236
+ Sanitation: `manhole`, `drain blocked`, `sewage`, `open sewer`
237
+ Animals: `stray dogs`, `cattle blocking`, `stray animal`
238
+ Pollution: `smoke`, `pollution`, `burning garbage`, `chemical spill`
239
+
240
+ ### What gets rejected
241
+
242
+ | Input | Reason |
243
+ |-------|--------|
244
+ | `Good morning` | Pure greeting (Stage 1) |
245
+ | `hi` | Pure greeting (Stage 1) |
246
+ | `test` | Test input (Stage 1) |
247
+ | `thank you` | Filler (Stage 1) |
248
+ | `dogs are barking at night` | No civic topic (Stage 2b) |
249
+ | `there are people on the road` | No civic topic (Stage 2b) |
250
+ | `I see a car on the street` | No civic topic (Stage 2b) |
251
+ | `nice day today` | No civic topic (Stage 2b) |
252
+
253
+ ---
254
+
255
+ ## 8. Image Pipeline
256
+
257
+ **File:** `multi_modal/image_to_text.py`
258
+
259
+ Images are processed through a 5-step pipeline. The output is a natural language description sent to BERT for classification.
260
+
261
+ ### Step 1 — OpenCV Preprocessing (9 techniques)
262
+
263
+ OpenCV is used for all image processing before model inference.
264
+
265
+ | # | Technique | Purpose |
266
+ |---|-----------|---------|
267
+ | 1 | EXIF auto-orientation | Fixes sideways/upside-down phone photos |
268
+ | 2 | Resize LANCZOS4 (≤1024px) | Optimal input size for GIT model |
269
+ | 3 | NL-means denoising | Removes phone camera sensor noise |
270
+ | 4 | Gray-world white balance | Corrects colour casts (tungsten, fluorescent, overcast) |
271
+ | 5 | CLAHE on LAB L-channel | Adaptive contrast for dark/overexposed shots |
272
+ | 6 | Adaptive gamma correction | Brightens night shots, dampens overexposed ones |
273
+ | 7 | Bilateral filter | Edge-preserving smooth (keeps structural edges sharp) |
274
+ | 8 | Unsharp mask sharpening | Recovers blurry edges from phone camera motion |
275
+ | 9 | Percentile contrast stretch | Eliminates washed-out highlights |
276
+
277
+ ### Step 2 — EasyOCR (EN + HI + TE)
278
+
279
+ Extracts any printed or handwritten text visible in the image. Useful when the photo contains a complaint notice, signboard, or label. Returns empty string if nothing meaningful is found (minimum 6 characters).
280
+
281
+ ### Step 3 — Microsoft GIT-large-coco Captioning
282
+
283
+ Model: `microsoft/git-large-coco` (~700 MB)
284
+
285
+ GIT (Generative Image-to-text Transformer) generates an unconditional visual description of what the image contains. No text prompt is used — the model describes freely based on what it sees.
286
+
287
+ **Why GIT over BLIP-base:**
288
+
289
+ | Model | Caption for pothole image | Problem |
290
+ |-------|--------------------------|---------|
291
+ | BLIP-base | "a road with cars on it" | Too generic |
292
+ | GIT-large-coco | "a large hole in the middle of a cracked road surface" | Specific and accurate |
293
+
294
+ BLIP-base was trained on web images and produces one-line generic captions. GIT-large is more accurate for real-world outdoor civic scenes including roads, drains, garbage piles, and broken infrastructure.
295
+
296
+ ### Step 4 — Civic Grievance Scorer
297
+
298
+ Scores the GIT caption against a weighted civic keyword lexicon:
299
+ - Primary terms (specific problem language): **score +2**
300
+ - Secondary terms (supporting context): **score +1**
301
+ - Minimum threshold: **score ≥ 2** to flag as civic
302
+
303
+ Non-civic captions (selfies, food, nature, indoor scenes) are detected by override patterns and flagged. This score populates the `civic_score` and `evidence_relevant` fields in the response. It never modifies the text sent to BERT.
304
+
305
+ ### Step 5 — Clean Fusion (OCR + Caption)
306
+
307
+ ```
308
+ OCR > 20 chars → OCR is primary (actual text from image)
309
+ Caption appended only if it adds new information
310
+ OCR short/none → GIT caption is the full output
311
+ Both empty → return "" (image unreadable)
312
+ ```
313
+
314
+ ### HF API fallback
315
+
316
+ When `IMAGE_BACKEND=hf_api`, the preprocessed image is sent to HuggingFace Inference API (`blip-image-captioning-large`). GIT is not available on the HF Inference API. OpenCV preprocessing still runs before the API call.
317
+
318
+ ---
319
+
320
+ ## 9. Audio Pipeline
321
+
322
+ **File:** `multi_modal/audio_to_text.py`
323
+
324
+ Audio files are transcribed using OpenAI Whisper. The transcript is treated as machine-generated text — the grievance intent check is skipped, only length and junk validation applies.
325
+
326
+ Supported formats: WAV, MP3, M4A, OGG, FLAC (via `pydub` conversion).
327
+
328
+ ---
329
+
330
+ ## 10. Language Support
331
+
332
+ | Language | Script detection | Models used |
333
+ |----------|-----------------|-------------|
334
+ | English | Default (no script match) | `civicconnect-bert-en`, `civicconnect-urgency-en` |
335
+ | Hindi | Unicode range U+0900–U+097F | `civicconnect-bert-indic`, `civicconnect-urgency-indic` |
336
+ | Telugu | Unicode range U+0C00–U+0C7F | `civicconnect-bert-indic`, `civicconnect-urgency-indic` |
337
+
338
+ Language is auto-detected from the grievance text. The correct model pair is selected automatically — no language parameter needed in the request.
339
+
340
+ **Hindi grievance validation keywords (sample):**
341
+ `समस्या`, `शिकायत`, `बिजली`, `पानी`, `सड़क`, `कचरा`, `नाली`
342
+
343
+ **Telugu grievance validation keywords (sample):**
344
+ `సమస్య`, `ఫిర్యాదు`, `విద్యుత్`, `నీరు`, `రోడ్డు`, `చెత్త`, `మురుగు`
345
+
346
+ ---
347
+
348
+ ## 11. Priority Engine (XPE)
349
+
350
+ **File:** `xpe/priority_engine.py`
351
+
352
+ Computes a numeric priority score (0–100) and a priority band for routing the grievance to the right department queue.
353
+
354
+ Inputs: `category`, `urgency`, `urgency_confidence`
355
+
356
+ | Priority Band | Score Range | Meaning |
357
+ |---------------|-------------|---------|
358
+ | `Critical` | 75–100 | Immediate action required |
359
+ | `High` | 50–74 | Resolve within 24 hours |
360
+ | `Medium` | 25–49 | Resolve within 3 days |
361
+ | `Low` | 0–24 | Routine queue |
362
+
363
+ Certain category + urgency combinations automatically elevate priority — for example, `stray animals` + `high urgency` (biting incident) or `electricity` + `high urgency` (live wire on road).
364
+
365
+ ---
366
+
367
+ ## 12. Explainability (Integrated Gradients)
368
+
369
+ **Files:** `xpe/integrated_gradients_explainer.py`, `xpe/hybrid_explainer.py`
370
+
371
+ When `explain=true` is sent in the request, Integrated Gradients attribution is computed for both the category and urgency predictions.
372
+
373
+ **What it returns:**
374
+
375
+ ```json
376
+ "explanation": {
377
+ "category_tokens": [
378
+ {"token": "pothole", "score": 0.87},
379
+ {"token": "road", "score": 0.64}
380
+ ],
381
+ "urgency_tokens": [
382
+ {"token": "since", "score": 0.71},
383
+ {"token": "3", "score": 0.68},
384
+ {"token": "days", "score": 0.65}
385
+ ],
386
+ "category_decision": "Classified as 'roads' because of strong signals: pothole, road damage",
387
+ "urgency_decision": "Urgency is 'high' because complaint has been pending for a duration",
388
+ "priority_summary": "High priority — road infrastructure issue with time-based urgency",
389
+ "final_reason": "Grievance about road damage (pothole) pending since 3 days. Routed as High priority."
390
+ }
391
+ ```
392
+
393
+ Integrated Gradients computes the contribution of each input token to the final prediction by interpolating between a baseline (zero embedding) and the actual input. It is the only explainability method used — SHAP was evaluated and removed due to BERT incompatibility.
394
+
395
  ---
396
+
397
+ ## 13. Fairness Audit (GFAS)
398
+
399
+ **File:** `gfas/__init__.py`
400
+
401
+ **Endpoint:** `POST /fairness-audit`
402
+
403
+ GFAS (Grievance Fairness Audit System) audits a batch of grievance records for demographic or geographic bias in classification and priority assignment.
404
+
405
+ **Request body:**
406
+ ```json
407
+ {
408
+ "grievances": [
409
+ {
410
+ "id": "abc123",
411
+ "text": "Pothole on main road",
412
+ "category": "roads",
413
+ "urgency": "high",
414
+ "priority_score": 72,
415
+ "area": "Gandhi Nagar",
416
+ "language": "english"
417
+ }
418
+ ]
419
+ }
420
+ ```
421
+
422
+ **Returns:** Fairness metrics, disparity scores by area/language, and flagged anomalies.
423
+
424
+ ---
425
+
426
+ ## 14. Hotspot Forecasting
427
+
428
+ **Endpoint:** `POST /hotspot-forecast`
429
+
430
+ Uses Facebook Prophet time-series forecasting to predict which area+category combinations are likely to see increased grievance volumes.
431
+
432
+ **Request body:**
433
+ ```json
434
+ {
435
+ "grievances": [...],
436
+ "horizon_days": 7,
437
+ "top_n": 10,
438
+ "source_window_days": 45
439
+ }
440
+ ```
441
+
442
+ **How the risk score is computed:**
443
+
444
+ ```
445
+ raw_risk = 0.5 × (growth%) + 0.3 × (avg_priority) + 0.2 × (recent_avg / 5)
446
+ risk_100 = 100 / (1 + e^(-raw_risk)) ← sigmoid normalisation to 0–100
447
+ ```
448
+
449
+ | Risk Level | Score |
450
+ |------------|-------|
451
+ | Critical | ≥ 75 |
452
+ | High | ≥ 50 |
453
+ | Medium | ≥ 25 |
454
+ | Low | < 25 |
455
+
456
+ Prophet requires a minimum of 2 unique dates per area+category group. Groups with fewer data points are skipped. Forecasting runs in parallel via `ThreadPoolExecutor` (default 4 workers, configurable via `PROPHET_MAX_WORKERS`).
457
+
458
+ ---
459
+
460
+ ## 15. Location Validation
461
+
462
+ **File:** `app.py` — `resolve_location_status()`
463
+
464
+ All images are validated for GPS location before processing.
465
+
466
+ ### Validation flow
467
+
468
+ ```
469
+ 1. Extract GPS from EXIF metadata (piexif)
470
+ ↓ if no EXIF
471
+ 2. Read lat/lng from form fields (latitude, longitude)
472
+ ↓ if none supplied
473
+ 3. Return status="no_gps" → request rejected (Mode A)
474
+
475
+ 4. Kakinada boundary check:
476
+ 16.85°N–17.10°N, 82.00°E–82.35°E
477
+ ↓ if outside
478
+ 5. Return status="invalid" → request rejected
479
+
480
+ 6. Ward bounding box check (if area field supplied)
481
+ Tolerance: ±0.015° (~1.5 km)
482
+ ↓ if GPS doesn't match declared ward
483
+ 7. Return status="invalid" with specific ward mismatch message
484
+ ```
485
+
486
+ ### Location behaviour by mode
487
+
488
+ | Mode | Location failure | Action |
489
+ |------|-----------------|--------|
490
+ | A (image only) | Invalid or no GPS | **Hard reject** — 403 response |
491
+ | D (text + image) | Invalid GPS | **Soft flag** — `location: "invalid"` in response, grievance still processed |
492
+ | E (audio + image) | Invalid GPS | **Soft flag** — same as Mode D |
493
+
494
+ ---
495
+
496
+ ## 16. Ward Bounding Boxes
497
+
498
+ 49 Kakinada Municipal Corporation wards are defined with bounding box coordinates (lat_min, lat_max, lon_min, lon_max). A ±0.015° tolerance (~1.5 km) is applied to account for GPS drift.
499
+
500
+ Sample wards defined:
501
+
502
+ | Ward | Lat Range | Lon Range |
503
+ |------|-----------|-----------|
504
+ | Suryaraopeta | 16.980–17.010 | 82.230–82.260 |
505
+ | Gandhi Nagar | 16.975–17.005 | 82.240–82.270 |
506
+ | Old Town | 16.990–17.020 | 82.220–82.250 |
507
+ | Kakinada Port Area | 16.940–16.970 | 82.260–82.300 |
508
+ | Surampalem | 17.075–17.105 | 82.050–82.085 |
509
+ | JNTU Kakinada Area | 16.950–16.980 | 82.260–82.300 |
510
+ | ... | ... | ... |
511
+
512
+ Full list of all 49 wards is defined in `WARD_BOUNDS` in `app.py`.
513
+
514
+ ---
515
+
516
+ ## 17. Models Used
517
+
518
+ | Model | Purpose | Size | Source |
519
+ |-------|---------|------|--------|
520
+ | `civicconnect-bert-en` | English category classification | ~440 MB | Fine-tuned BERT (HF submodule) |
521
+ | `civicconnect-bert-indic` | Hindi/Telugu category classification | ~580 MB | Fine-tuned IndicBERT (HF submodule) |
522
+ | `civicconnect-urgency-en` | English urgency classification | ~440 MB | Fine-tuned BERT (HF submodule) |
523
+ | `civicconnect-urgency-indic` | Hindi/Telugu urgency classification | ~580 MB | Fine-tuned IndicBERT (HF submodule) |
524
+ | `microsoft/git-large-coco` | Image captioning | ~700 MB | HuggingFace Hub |
525
+ | EasyOCR (en+hi+te) | OCR from images | ~400 MB | PyPI |
526
+ | Whisper | Audio transcription | varies | OpenAI via HF |
527
+ | Prophet | Hotspot time-series forecast | lightweight | Meta / PyPI |
528
+
529
+ ---
530
+
531
+ ## 18. Requirements
532
+
533
+ ```
534
+ # Core ML
535
+ torch
536
+ transformers>=4.47.0,<4.50.0 # Pin — 4.50+ breaks GIT trust_remote_code
537
+ tokenizers>=0.20.3,<0.22
538
+ accelerate>=1.1.0
539
+ safetensors>=0.4.3
540
+ huggingface-hub>=0.26.0
541
+
542
+ # Image
543
+ opencv-python-headless # 9-technique preprocessing pipeline
544
+ Pillow
545
+ piexif # EXIF GPS extraction
546
+ easyocr # OCR (EN + HI + TE)
547
+
548
+ # Audio
549
+ pydub
550
+ soundfile
551
+ scipy
552
+
553
+ # NLP
554
+ sentencepiece
555
+ tiktoken
556
+ protobuf>=5.28.0
557
+ regex
558
+ nltk
559
+ indic-nlp-library
560
+ stopwordsiso
561
+
562
+ # Explainability
563
+ captum # Integrated Gradients
564
+ shap>=0.44
565
+
566
+ # Forecasting
567
+ prophet
568
+
569
+ # Data
570
+ pandas
571
+ numpy
572
+ scikit-learn==1.5.2
573
+ matplotlib
574
+ seaborn
575
+
576
+ # Backend
577
+ flask
578
+ flask-cors
579
+ gunicorn
580
+ werkzeug
581
+ python-dotenv
582
+ requests
583
+ ```
584
+
585
+ > **Note:** `transformers` is pinned to `<4.50.0`. Versions 4.50 and above changed `GenerationMixin` inheritance in a way that breaks GIT's remote code loading, causing `AttributeError: _supports_sdpa`.
586
+
587
+ ---
588
+
589
+ ## 19. Environment Variables
590
+
591
+ | Variable | Default | Description |
592
+ |----------|---------|-------------|
593
+ | `PORT` | `7860` | Flask server port (HF Spaces uses 7860) |
594
+ | `FLASK_DEBUG` | `false` | Enable Flask debug mode |
595
+ | `MAX_UPLOAD_MB` | `32` | Maximum image/audio upload size in MB |
596
+ | `IMAGE_BACKEND` | `local` | `local` = GIT runs on server, `hf_api` = HF Inference API |
597
+ | `HF_TOKEN` | `""` | HuggingFace token (required when `IMAGE_BACKEND=hf_api`) |
598
+ | `GIT_MODEL` | `microsoft/git-large-coco` | GIT model repo ID |
599
+ | `PROPHET_MAX_WORKERS` | `4` | Thread pool size for hotspot forecasting |
600
+ | `APP_VERSION` | `1.0.0` | Shown in health check response |
601
+
602
+ ---
603
+
604
+ ## 20. Running Locally
605
+
606
+ ### Prerequisites
607
+ - Python 3.10+
608
+ - pip
609
+
610
+ ### Setup
611
+
612
+ ```bash
613
+ # Clone the repo
614
+ git clone https://huggingface.co/spaces/YOUR_USERNAME/YOUR_SPACE_NAME
615
+ cd civicconnect-ai-engine
616
+
617
+ # Install dependencies
618
+ pip install -r requirements.txt
619
+
620
+ # Pull submodules (BERT model weights)
621
+ git submodule update --init --recursive
622
+ ```
623
+
624
+ ### Run
625
+
626
+ ```bash
627
+ python app.py
628
+ ```
629
+
630
+ API will be available at `http://localhost:7860`
631
+
632
+ ### Test
633
+
634
+ ```bash
635
+ # Health check
636
+ curl http://localhost:7860/health
637
+
638
+ # Text grievance
639
+ curl -X POST http://localhost:7860/predict \
640
+ -H "Content-Type: application/json" \
641
+ -d '{"text": "There is a pothole on main road not fixed since 3 weeks"}'
642
+
643
+ # Image + text
644
+ curl -X POST http://localhost:7860/predict \
645
+ -F "text=Garbage not collected since 5 days" \
646
+ -F "image=@/path/to/photo.jpg" \
647
+ -F "area=gandhi nagar"
648
+ ```
649
+
650
+ ---
651
+
652
+ ## 21. Deploying to Hugging Face Spaces
653
+
654
+ ### One-time setup
655
+
656
+ ```bash
657
+ # Install HF CLI
658
+ pip install huggingface_hub
659
+
660
+ # Login (get token from https://huggingface.co/settings/tokens)
661
+ huggingface-cli login
662
+
663
+ # Add HF remote (if not already set)
664
+ git remote add origin https://huggingface.co/spaces/YOUR_USERNAME/YOUR_SPACE_NAME
665
+ ```
666
+
667
+ ### Push changes
668
+
669
+ ```bash
670
+ # Stage changed files
671
+ git add app.py
672
+ git add multi_modal/image_to_text.py
673
+ git add requirements.txt
674
+
675
+ # Commit
676
+ git commit -m "your commit message"
677
+
678
+ # Push
679
+ git push origin main
680
+ ```
681
+
682
+ ### Push to specific commit
683
+
684
+ ```bash
685
+ # Reset to a specific commit and force push
686
+ git reset --hard COMMIT_HASH
687
+ git push origin main --force
688
+ ```
689
+
690
+ ### Troubleshooting
691
+
692
+ | Problem | Fix |
693
+ |---------|-----|
694
+ | `Authentication failed` | Run `huggingface-cli login` again with a Write token |
695
+ | `rejected — non-fast-forward` | Run `git pull origin main --rebase` first |
696
+ | Space stuck on Building | Go to Space → Settings → Factory Reboot |
697
+ | `_supports_sdpa` error | Ensure `transformers<4.50.0` in requirements.txt |
698
+
699
+ ---
700
+
701
+ ## 22. API Request & Response Examples
702
+
703
+ ### Mode C — Text only
704
+
705
+ **Request:**
706
+ ```json
707
+ POST /predict
708
+ Content-Type: application/json
709
+
710
+ {
711
+ "text": "There is a pothole on main road in Gandhi Nagar not repaired since 3 weeks",
712
+ "explain": true
713
+ }
714
+ ```
715
+
716
+ **Response:**
717
+ ```json
718
+ {
719
+ "status": "success",
720
+ "input_mode": "text",
721
+ "text": "There is a pothole on main road in Gandhi Nagar not repaired since 3 weeks",
722
+ "language": "english",
723
+ "category": "roads",
724
+ "category_confidence": 0.9423,
725
+ "urgency": "high",
726
+ "urgency_confidence": 0.8761,
727
+ "priority_score": 74.2,
728
+ "priority_band": "High",
729
+ "explanation": {
730
+ "category_tokens": [
731
+ {"token": "pothole", "score": 0.91},
732
+ {"token": "road", "score": 0.67},
733
+ {"token": "repaired", "score": 0.54}
734
+ ],
735
+ "urgency_tokens": [
736
+ {"token": "since", "score": 0.78},
737
+ {"token": "3", "score": 0.71},
738
+ {"token": "weeks", "score": 0.69}
739
+ ],
740
+ "category_decision": "Classified as roads due to: pothole, road, repaired",
741
+ "urgency_decision": "High urgency due to duration signal: since 3 weeks",
742
+ "priority_summary": "Road damage with high urgency — pending for weeks",
743
+ "final_reason": "Pothole on main road in Gandhi Nagar unresolved for 3 weeks. Routed as High priority."
744
+ }
745
+ }
746
+ ```
747
+
748
+ ---
749
+
750
+ ### Mode D — Text + Image
751
+
752
+ **Request:**
753
+ ```
754
+ POST /predict
755
+ Content-Type: multipart/form-data
756
+
757
+ text=Garbage not collected since 5 days
758
+ image=<photo.jpg>
759
+ area=ashok nagar
760
+ explain=false
761
+ ```
762
+
763
+ **Response:**
764
+ ```json
765
+ {
766
+ "status": "success",
767
+ "input_mode": "text+image",
768
+ "text": "Garbage not collected since 5 days",
769
+ "language": "english",
770
+ "category": "garbage",
771
+ "category_confidence": 0.9812,
772
+ "urgency": "high",
773
+ "urgency_confidence": 0.8934,
774
+ "priority_score": 78.5,
775
+ "priority_band": "High",
776
+ "location": "valid",
777
+ "evidence_relevant": true,
778
+ "evidence_note": "Image contains civic content related to garbage (visual relevance score: 6). GIT scores the image visually; BERT classifies the complaint text.",
779
+ "civic_score": 6,
780
+ "image_caption": "a large pile of garbage on the side of a road near residential buildings",
781
+ "explanation": { ... }
782
+ }
783
+ ```
784
+
785
+ ---
786
+
787
+ ### Rejected — not a grievance
788
+
789
+ **Request:**
790
+ ```json
791
+ {"text": "Good morning"}
792
+ ```
793
+
794
+ **Response (422):**
795
+ ```json
796
+ {
797
+ "status": "failed",
798
+ "code": "not_a_grievance",
799
+ "message": "Your message does not appear to be a grievance or civic complaint. Please describe the issue you are facing — for example: pothole on the road, water supply disruption, electricity outage, garbage not collected, stray dogs biting residents, or any other civic problem."
800
+ }
801
+ ```
802
+
803
+ ---
804
+
805
+ ### Rejected — outside Kakinada
806
+
807
+ **Response (403):**
808
+ ```json
809
+ {
810
+ "status": "failed",
811
+ "code": "location_invalid",
812
+ "message": "Image location is outside Kakinada Municipal Corporation limits. Only grievances within Kakinada jurisdiction are accepted.",
813
+ "location": "invalid"
814
+ }
815
+ ```
816
+
817
+ ---
818
+
819
+ ## 23. Error Codes Reference
820
+
821
+ | Code | HTTP | Meaning |
822
+ |------|------|---------|
823
+ | `missing_input` | 400 | No text, audio, or image provided |
824
+ | `too_short` | 422 | Text is fewer than 5 characters |
825
+ | `junk_input` | 422 | Input contains only numbers or symbols |
826
+ | `not_a_grievance` | 422 | Text does not contain a civic grievance signal |
827
+ | `image_unreadable` | 422 | GIT/OCR could not extract content from image |
828
+ | `audio_unreadable` | 422 | Whisper could not transcribe audio |
829
+ | `location_invalid` | 403 | Image GPS outside Kakinada limits |
830
+ | `payload_too_large` | 413 | Upload exceeds size limit (default 32 MB) |
831
+ | `not_found` | 404 | Endpoint does not exist |
832
+ | `method_not_allowed` | 405 | Wrong HTTP method |
833
+ | `internal_error` | 500 | Unhandled server exception (trace included) |
834
+
835
+ ---
836
+
837
+ ## 24. Testing Grievance Inputs
838
+
839
+ ### Should be accepted ✅
840
+
841
+ **English — civic observation (no complaint language needed):**
842
+ ```
843
+ Hello, I can see garbage on the road
844
+ Hi, the road has a pothole
845
+ Good morning, there are stray dogs near my house
846
+ there is water on the street
847
+ I see a broken pipe nearby
848
+ I notice the streetlight is off
849
+ there is sewage on the road
850
+ I can see a manhole without cover
851
+ ```
852
+
853
+ **English — with complaint intent:**
854
+ ```
855
+ There is a big pothole on the main road near Gandhi Nagar
856
+ Road is completely broken in Suryaraopeta ward
857
+ No water supply since 3 days in our area
858
+ Garbage not collected in our area since 5 days
859
+ Power cut since 2 days no response from electricity board
860
+ Streetlight not working since last month
861
+ Stray dogs biting residents in our colony
862
+ Dogs attacking my child near school
863
+ Drain is blocked and sewage is overflowing
864
+ Manhole is open on the main road
865
+ ```
866
+
867
+ **Hindi:**
868
+ ```
869
+ हमारे इलाके में पानी नहीं आ रहा है
870
+ सड़क बहुत खराब है कृपया ठीक करें
871
+ कचरा नहीं उठाया जा रहा है
872
+ बिजली कल से नहीं है
873
+ नाली बंद है और पानी भर गया है
874
+ ```
875
+
876
+ **Telugu:**
877
+ ```
878
+ మా కాలనీలో నీళ్ళు రావడం లేదు
879
+ రోడ్డు పాడైంది దయచేసి సరిచేయండి
880
+ చెత్త తీయడం లేదు చాలా రోజులు అయింది
881
+ విద్యుత్ సమస్య ఉంది
882
+ మురుగు పొంగి రోడ్డు మీద పడుతోంది
883
+ ```
884
+
885
+ ### Should be rejected ❌
886
+
887
+ ```
888
+ Good morning
889
+ Hi
890
+ Hello
891
+ Namaste
892
+ How are you
893
+ test
894
+ ok
895
+ thank you
896
+ Dogs are barking at night
897
+ There are people on the road
898
+ I see a car on the street
899
+ Nice day today
900
+ Happy Diwali
901
+ ```
902
+
903
+ ### Tricky edge cases
904
+
905
+ | Input | Expected | Reason |
906
+ |-------|----------|--------|
907
+ | `There are lots of dogs in the area` | ❌ NOT | No civic topic, no harm signal |
908
+ | `There are lots of dogs in the area biting people` | ✅ GRIEVANCE | Animal harm pattern |
909
+ | `Good morning, garbage on the road` | ✅ GRIEVANCE | Greeting + civic topic |
910
+ | `The road looks bad today` | ❌ NOT | Vague — no specific civic term |
911
+ | `Road is damaged` | ✅ GRIEVANCE | Civic topic match |
912
+ | `Pothole` | ❌ NOT | Too short (< 8 characters) |
913
+ | `Big pothole` | ✅ GRIEVANCE | ≥ 8 chars + civic topic |
914
+ | `Dogs are roaming in the colony` | ❌ NOT | Roaming ≠ civic harm |
915
+ | `Stray cattle on the highway` | ✅ GRIEVANCE | `stray cattle` = civic topic |
916
+
917
+ ---
918
+
919
+ ## 25. Known Limitations
920
+
921
+ **Image captioning accuracy**
922
+ GIT-large-coco was trained on general web images (COCO dataset), not specifically on civic infrastructure damage. It performs significantly better than BLIP-base for outdoor scenes but may occasionally produce vague captions for very dark, blurry, or low-contrast photos. OpenCV preprocessing mitigates most of these cases.
923
+
924
+ **Grievance validation false negatives**
925
+ Unusual phrasing not covered by `_CIVIC_TOPIC` patterns may be rejected. Users can always rephrase using standard civic terminology. The pattern set is designed to be expanded over time.
926
+
927
+ **Hotspot forecasting minimum data**
928
+ Prophet requires at least 2 unique dates per area+category group. New wards or newly emerging issue categories with insufficient history will be skipped in forecasting output.
929
+
930
+ **Language detection**
931
+ Language is detected by Unicode script range. Mixed-script inputs (e.g., Romanised Hindi/Telugu + English) default to English models. Code-switching ("Kachra nahi utha hai") may reduce classification accuracy.
932
+
933
+ **GPS tolerance**
934
+ Ward boundary validation uses ±0.015° tolerance (~1.5 km). GPS drift from indoor locations, tunnels, or weak signal may cause valid grievances to be flagged as outside the ward boundary.
935
+
936
+ **Transformer version pinning**
937
+ `transformers<4.50.0` is required for GIT model loading. Upgrading to 4.50+ will break the image pipeline with `AttributeError: _supports_sdpa`. This limitation will be resolved when GIT is migrated to the native `Florence2ForConditionalGeneration` class available in transformers 5.x.
938
+
939
  ---
940
 
941
+ *CivicConnect AI Engine Built for Kakinada Municipal Corporation*
942
+ *Multilingual · Multimodal · Explainable · Fair*
civicconnect-bert-en ADDED
@@ -0,0 +1 @@
 
 
1
+ Subproject commit 55fee65aab4f41d4a584b1177facdd54c6f1dbcd
civicconnect-bert-indic ADDED
@@ -0,0 +1 @@
 
 
1
+ Subproject commit f852884dceff475ee499adf5994f765af5658455
civicconnect-urgency-en ADDED
@@ -0,0 +1 @@
 
 
1
+ Subproject commit ed301fe2c3c864cd431c50363d068f1b4dfefce0
civicconnect-urgency-indic ADDED
@@ -0,0 +1 @@
 
 
1
+ Subproject commit 63d31c859a86fe027522b20cfa147c9cbde15c09