Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 14 additions & 23 deletions uc-0a/agents.md
Original file line number Diff line number Diff line change
@@ -1,27 +1,18 @@
# agents.md — UC-0A Complaint Classifier
# INSTRUCTIONS:
# 1. Open your AI tool
# 2. Paste the full contents of uc-0a/README.md
# 3. Use this prompt:
# "Read this UC README. Using the R.I.C.E framework, generate an
# agents.md YAML with four fields: role, intent, context, enforcement.
# Enforcement must include every rule listed under
# 'Enforcement Rules Your agents.md Must Include'.
# Output only valid YAML."
# 4. Paste the output below

role: >
[FILL IN]

City Operations AI Complaint Classifier responsible for accurately categorizing municipal reports.
The agent's operational boundary is restricted to translating complaint descriptions into the
approved city taxonomy for the Director's dashboard.
intent: >
[FILL IN]

Produce a verifiable classification output consisting of a category, priority, reason, and flag.
Success is defined by zero taxonomy drift, correct severity triggering for safety-critical issues,
and verbatim justification for every assigned category.
context: >
[FILL IN]

The agent processes dictionaries containing 'description' and 'location' fields.
Exclusions: The agent must not use external demographic data, historical trends,
or sub-categories not defined in the schema (e.g., "Pedestrian Safety Incident").
enforcement:
- "[FILL IN: category enum rule]"
- "[FILL IN: severity keyword rule — list the keywords]"
- "[FILL IN: reason field rule]"
- "[FILL IN: ambiguity refusal rule]"
- "[FILL IN: no invented categories rule]"
- Category must be exactly one value from the allowed list (Pothole, Flooding, Streetlight, Waste, Noise, Road Damage, Heritage Damage, Heat Hazard, Drain Blockage, Other). No variations.
- Priority must be Urgent if description contains any severity keyword: injury, child, school, hospital, ambulance, fire, hazard, fell, collapse.
- Every output row must include a reason field citing specific words from the description.
- If category cannot be determined confidently — output category: Other and flag: NEEDS_REVIEW.
- Never invent category names outside the allowed list.
177 changes: 161 additions & 16 deletions uc-0a/classifier.py
Original file line number Diff line number Diff line change
@@ -1,31 +1,176 @@
"""
UC-0A — Complaint Classifier
classifier.py — Starter file

Build this using your AI coding tool:
1. Share agents.md, skills.md, and uc-0a/README.md
2. Ask the AI to implement this file
3. Run: python3 classifier.py --input ../data/city-test-files/test_pune.csv \
--output results_pune.csv
Implementation follows R.I.C.E (Role, Intent, Context, Enforcement)
and CRAFT principles as defined in agents.md and skills.md.
"""
import argparse
import csv
import os
import sys

# --- SYSTEM PROMPT (From agents.md) ---
SYSTEM_PROMPT = """
Role: City Operations AI Complaint Classifier.
Boundary: Categorize municipal reports into the approved city taxonomy.

Allowed Categories:
Pothole, Flooding, Streetlight, Waste, Noise, Road Damage, Heritage Damage, Heat Hazard, Drain Blockage, Other.

Enforcement Rules:
1. Category must be exactly one value from the allowed list. No variations.
2. Priority must be Urgent if description contains any severity keyword: injury, child, school, hospital, ambulance, fire, hazard, fell, collapse.
3. Every output row must include a reason field citing specific words from the description.
4. If category cannot be determined confidently — output category: Other and flag: NEEDS_REVIEW.
5. If description is vague or too short — output category: Other and flag: NEEDS_REVIEW.
6. Never invent category names outside the allowed list.

Output JSON Format for each row:
{
"category": "Allowed Category Name",
"priority": "Urgent/Standard/Low",
"reason": "One sentence justification citing specific words",
"flag": "NEEDS_REVIEW or (blank)"
}
"""

def classify_complaint(row: dict) -> dict:
"""
Classify a single complaint row.
Returns dict with: complaint_id, category, priority, reason, flag
Skill: classify_complaint
Input: one complaint row (dict with description, location fields)
Output: dict with category, priority, reason, flag
Error handling: vague/short descriptions → Other + NEEDS_REVIEW
"""
raise NotImplementedError("Build this using your AI tool + agents.md")
description = row.get("description", "").strip()
location = row.get("location", "Unknown")

# Heuristic Logic for Severity (Rule 2)
severity_keywords = ["injury", "child", "school", "hospital", "ambulance", "fire", "hazard", "fell", "collapse"]
priority = "Standard"
desc_lower = description.lower()
for kw in severity_keywords:
if kw in desc_lower:
priority = "Urgent"
break

# Error handling for vague/short descriptions (Rule 5)
if len(description) < 15:
return {
"category": "Other",
"priority": priority,
"reason": f"Input too short ('{description}') to classify confidently.",
"flag": "NEEDS_REVIEW"
}

# Taxonomy Mapping Logic (Ensuring Rules 1, 4, 6)
category = "Other"
reason = "No taxonomy keyword match."
flag = "NEEDS_REVIEW"

taxonomy_map = {
"pothole": "Pothole",
"flooding": "Flooding",
"flood": "Flooding",
"light": "Streetlight",
"waste": "Waste",
"garbage": "Waste",
"noise": "Noise",
"sound": "Noise",
"road": "Road Damage",
"heritage": "Heritage Damage",
"statue": "Heritage Damage",
"heat": "Heat Hazard",
"drain": "Drain Blockage"
}

matches = [cat for kw, cat in taxonomy_map.items() if kw in desc_lower]
unique_matches = sorted(list(set(matches)))

# Ambiguity Check (Rule 4)
if len(unique_matches) == 1:
category = unique_matches[0]
keyword = next(kw for kw in taxonomy_map.keys() if kw in desc_lower)
# Reason citing words (Rule 3)
reason = f"Detected '{keyword}' in description, mapping to {category}."
flag = ""
elif len(unique_matches) > 1:
category = "Other"
reason = f"Ambiguous input matching multiple categories: {list(unique_matches)}."
flag = "NEEDS_REVIEW"
else:
category = "Other"
reason = "No specific keywords found mapping to the current list of categories."
flag = "NEEDS_REVIEW"

# Final Enforcement of Allowed List
allowed = ["Pothole", "Flooding", "Streetlight", "Waste", "Noise", "Road Damage", "Heritage Damage", "Heat Hazard", "Drain Blockage", "Other"]
if category not in allowed:
category = "Other"
flag = "NEEDS_REVIEW"

return {
"category": category,
"priority": priority,
"reason": reason,
"flag": flag
}

def batch_classify(input_path: str, output_path: str):
"""Read input CSV, classify each row, write results CSV."""
raise NotImplementedError("Build this using your AI tool + agents.md")
"""
Skill: batch_classify
Input: path to test CSV file
Output: path to results CSV file
Error handling: malformed rows logged and skipped, processing continues
"""
if not os.path.exists(input_path):
print(f"Error: Input file '{input_path}' not found.")
sys.exit(1)

processed_data = []

try:
with open(input_path, mode='r', encoding='utf-8') as f:
reader = csv.DictReader(f)

for row_id, row in enumerate(reader, 1):
try:
# Handle malformed/incomplete rows (Skill Error Handling)
if not row.get("description") or not row.get("location"):
print(f"Row {row_id}: Malformed/Empty description or location. Skipping...")
continue

classification = classify_complaint(row)

# Combine original fields with classification results
final_row = {**row, **classification}
processed_data.append(final_row)

except Exception as e:
print(f"Row {row_id}: Unexpected error processing. Logging and continuing... ({e})")
continue

except Exception as e:
print(f"Fatal error reading CSV: {e}")
sys.exit(1)

if not processed_data:
print("No valid complaint rows to process.")
return

# Write Results to CSV
try:
fieldnames = list(processed_data[0].keys())
with open(output_path, mode='w', encoding='utf-8', newline='') as f:
writer = csv.DictWriter(f, fieldnames=fieldnames)
writer.writeheader()
writer.writerows(processed_data)
print(f"Done. {len(processed_data)} complaints classified. Results saved to: {output_path}")
except Exception as e:
print(f"Error saving output file: {e}")

if __name__ == "__main__":
parser = argparse.ArgumentParser(description="UC-0A Complaint Classifier")
parser.add_argument("--input", required=True)
parser.add_argument("--output", required=True)
parser = argparse.ArgumentParser(description="UC-0A Complaint Classifier Script")
parser.add_argument("--input", required=True, help="Input CSV path (data/city-test-files/test_pune.csv)")
parser.add_argument("--output", required=True, help="Output CSV path (uc-0a/results_pune.csv)")

args = parser.parse_args()
batch_classify(args.input, args.output)
print(f"Done. Results written to {args.output}")
16 changes: 16 additions & 0 deletions uc-0a/results_ahmedabad.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
complaint_id,date_raised,city,ward,location,description,reported_by,days_open,category,priority,reason,flag
AM-202401,2024-04-24,Ahmedabad,Ward 13 – Sabarmati,Kankaria Lake promenade,Tarmac surface melting at 44°C. Footwear sticking. Park users unsafe.,Email,1,Other,Standard,No specific keywords found mapping to the current list of categories.,NEEDS_REVIEW
AM-202402,2024-04-23,Ahmedabad,Ward 12 – Maninagar,"Naroda Industrial Area, main gate",Metal bus shelter reaching dangerous temperatures. Commuters refusing to use.,Citizen Portal,4,Other,Standard,No specific keywords found mapping to the current list of categories.,NEEDS_REVIEW
AM-202405,2024-05-08,Ahmedabad,Ward 11 – Vastrapur,"Sabarmati Riverfront, North section",Dead trees with split branches. Fall risk to walkers. 3 trees affected.,WhatsApp Helpline,19,Other,Standard,No specific keywords found mapping to the current list of categories.,NEEDS_REVIEW
AM-202406,2024-04-21,Ahmedabad,Ward 15 – Chandkheda,"Chandkheda, Sector 22 park",Irrigation system broken. Grass dying in heatwave conditions.,Phone Helpline,18,Heat Hazard,Standard,"Detected 'heat' in description, mapping to Heat Hazard.",
AM-202407,2024-04-25,Ahmedabad,Ward 15 – Chandkheda,"Thaltej, residential park",Broken bench and upturned paving. Child injured last week.,Email,20,Other,Urgent,No specific keywords found mapping to the current list of categories.,NEEDS_REVIEW
AM-202410,2024-05-02,Ahmedabad,Ward 12 – Maninagar,SG Highway near Prahladnagar,Pothole on main highway causing morning rush lane closure.,Ward Office Walk-in,4,Pothole,Standard,"Detected 'pothole' in description, mapping to Pothole.",
AM-202414,2024-04-20,Ahmedabad,Ward 14 – Odhav,"Jodhpur Village, off SG Highway",Residential colony unlit after 9pm. Wiring theft reported.,Citizen Portal,10,Other,Standard,No specific keywords found mapping to the current list of categories.,NEEDS_REVIEW
AM-202417,2024-05-08,Ahmedabad,Ward 13 – Sabarmati,"Manek Chowk, Old City",Night market waste not cleared before morning. Heritage area affected.,Councillor Referral,21,Other,Standard,"Ambiguous input matching multiple categories: ['Heritage Damage', 'Waste'].",NEEDS_REVIEW
AM-202421,2024-05-03,Ahmedabad,Ward 14 – Odhav,"CG Road, commercial zone",Club music audible at residential buildings at 2am.,Citizen Portal,18,Other,Standard,No specific keywords found mapping to the current list of categories.,NEEDS_REVIEW
AM-202424,2024-05-04,Ahmedabad,Ward 11 – Vastrapur,"Shahibaug, near zoo",Zoo approach road surface bubbling at 45°C. Visitor complaints.,Councillor Referral,19,Road Damage,Standard,"Detected 'road' in description, mapping to Road Damage.",
AM-202429,2024-04-24,Ahmedabad,Ward 11 – Vastrapur,Ellis Bridge walking track,River walk surface temperature unbearable. Installed temperature reads 52°C.,Councillor Referral,3,Other,Standard,No specific keywords found mapping to the current list of categories.,NEEDS_REVIEW
AM-202431,2024-04-26,Ahmedabad,Ward 14 – Odhav,"Paldi, Ratanpol area",Old city road subsidence near ancient step well. Heritage concern.,Citizen Portal,18,Other,Standard,"Ambiguous input matching multiple categories: ['Heritage Damage', 'Road Damage'].",NEEDS_REVIEW
AM-202435,2024-05-07,Ahmedabad,Ward 11 – Vastrapur,"New CG Road, Chandkheda",Black metal road dividers storing heat. Motorists reporting burns on contact.,WhatsApp Helpline,16,Other,Standard,"Ambiguous input matching multiple categories: ['Heat Hazard', 'Road Damage'].",NEEDS_REVIEW
AM-202444,2024-05-15,Ahmedabad,Ward 12 – Maninagar,"Jivraj Park, commercial area",Restaurant waste bins overflowing on Sunday night. Health risk.,Councillor Referral,20,Waste,Standard,"Detected 'waste' in description, mapping to Waste.",
AM-202445,2024-04-19,Ahmedabad,Ward 13 – Sabarmati,Ranip Bus Rapid Transit stop,BRT shelter roof glass broken. Users exposed to full sun.,Councillor Referral,9,Other,Standard,No specific keywords found mapping to the current list of categories.,NEEDS_REVIEW
16 changes: 16 additions & 0 deletions uc-0a/results_hyderabad.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
complaint_id,date_raised,city,ward,location,description,reported_by,days_open,category,priority,reason,flag
GH-202401,2024-07-01,Hyderabad,Ward 55 – Secunderabad,Tank Bund Road underpass,Underpass flooded after 1hr rain. Ambulance diverted. Lives at risk.,WhatsApp Helpline,13,Flooding,Urgent,"Detected 'flood' in description, mapping to Flooding.",
GH-202402,2024-07-13,Hyderabad,Ward 55 – Secunderabad,Dilsukhnagar Monda Market area,Market area flooded. Traders suffering losses. Drain completely blocked.,Citizen Portal,20,Other,Standard,"Ambiguous input matching multiple categories: ['Drain Blockage', 'Flooding'].",NEEDS_REVIEW
GH-202406,2024-07-26,Hyderabad,Ward 54 – Kukatpally,"Mehdipatnam, Rethibowli Road",Main stormwater drain 100% blocked with construction debris.,Phone Helpline,3,Drain Blockage,Standard,"Detected 'drain' in description, mapping to Drain Blockage.",
GH-202407,2024-07-15,Hyderabad,Ward 55 – Secunderabad,"Santoshnagar, Saidabad",Drain blocked and mosquito breeding. Dengue concern.,WhatsApp Helpline,4,Drain Blockage,Standard,"Detected 'drain' in description, mapping to Drain Blockage.",
GH-202410,2024-07-23,Hyderabad,Ward 55 – Secunderabad,"Outer Ring Road service lane, Narsingi",Potholes causing vehicles to slow to 20kmph on fast road.,Councillor Referral,18,Other,Standard,"Ambiguous input matching multiple categories: ['Pothole', 'Road Damage'].",NEEDS_REVIEW
GH-202411,2024-07-31,Hyderabad,Ward 55 – Secunderabad,"Tolichowki, Mount Pleasant Road",Pothole swallowed entire motorcycle wheel. Rider hospitalised.,Ward Office Walk-in,17,Pothole,Urgent,"Detected 'pothole' in description, mapping to Pothole.",
GH-202412,2024-07-24,Hyderabad,Ward 53 – LB Nagar,"Nagole, Ramanthapur Road",School bus struggling to navigate 6 potholes in 200m stretch.,Citizen Portal,4,Pothole,Urgent,"Detected 'pothole' in description, mapping to Pothole.",
GH-202417,2024-07-16,Hyderabad,Ward 53 – LB Nagar,"Charminar area, old city",Heritage zone garbage overflow. Tourist photographs showing piles of waste.,WhatsApp Helpline,11,Other,Standard,"Ambiguous input matching multiple categories: ['Heritage Damage', 'Waste'].",NEEDS_REVIEW
GH-202420,2024-07-10,Hyderabad,Ward 55 – Secunderabad,Hitech City co-working zone,Construction drilling from 5am daily near residential towers.,WhatsApp Helpline,12,Other,Standard,No specific keywords found mapping to the current list of categories.,NEEDS_REVIEW
GH-202422,2024-07-31,Hyderabad,Ward 52 – Madhapur,"Attapur, Shaikpet Road",Road collapsed partially. Crater 1m deep near residential gate.,Social Media,1,Road Damage,Urgent,"Detected 'road' in description, mapping to Road Damage.",
GH-202424,2024-07-19,Hyderabad,Ward 52 – Madhapur,Malkajgiri railway underpass,Underpass floods in light rain. Cars regularly abandoned.,Councillor Referral,5,Other,Standard,"Ambiguous input matching multiple categories: ['Flooding', 'Streetlight'].",NEEDS_REVIEW
GH-202428,2024-07-24,Hyderabad,Ward 54 – Kukatpally,Tolichowki Friday Market area,Post-market waste not cleared. Area unusable by Sunday morning.,Ward Office Walk-in,8,Waste,Standard,"Detected 'waste' in description, mapping to Waste.",
GH-202432,2024-07-19,Hyderabad,Ward 51 – Jubilee Hills,"Kukatpally, KPHB Phase 7",24hr supermarket delivery trucks idling with engines on.,Citizen Portal,2,Other,Standard,No specific keywords found mapping to the current list of categories.,NEEDS_REVIEW
GH-202448,2024-07-22,Hyderabad,Ward 52 – Madhapur,Kondapur main drain,Main drain blocked — entire locality at flooding risk this week.,Councillor Referral,8,Other,Standard,"Ambiguous input matching multiple categories: ['Drain Blockage', 'Flooding'].",NEEDS_REVIEW
GH-202438,2024-07-06,Hyderabad,Ward 53 – LB Nagar,Hayathnagar residential colony,Colony surrounded by fields that channel rainwater through main road.,Social Media,11,Road Damage,Standard,"Detected 'road' in description, mapping to Road Damage.",
Loading