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
6 changes: 6 additions & 0 deletions .idea/inspectionProfiles/profiles_settings.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions .idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions .idea/modules.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 12 additions & 0 deletions .idea/prompt-to-production.iml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions .idea/vcs.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

49 changes: 49 additions & 0 deletions .idea/workspace.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 16 additions & 0 deletions data/city-test-files/test_bangalore.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
BLR-202401,2024-06-21,Bangalore,Ward 1 – Malleshwaram,Sampige Road near Malleshwaram Circle,Large pothole 50cm wide causing vehicle damage during peak hours.,Citizen Portal,4
BLR-202402,2024-06-04,Bangalore,Ward 2 – Rajajinagar,Dr Rajkumar Road near Metro Station,Deep pothole near metro exit posing risk to pedestrians.,Councillor Referral,12
BLR-202406,2024-06-08,Bangalore,Ward 3 – Shivajinagar,Queens Road underpass,Underpass flooded after continuous rain. Traffic diverted.,Councillor Referral,8
BLR-202408,2024-06-05,Bangalore,Ward 4 – Indiranagar,100 Feet Road bus stop,Bus stop flooded. Commuters waiting on road.,Ward Office Walk-in,12
BLR-202410,2024-06-04,Bangalore,Ward 5 – Jayanagar,4th Block Market Road,Multiple streetlights not working for over a week.,Email,18
BLR-202411,2024-06-22,Bangalore,Ward 6 – Whitefield,ITPL Main Road,Streetlight flickering and sparking near tech park.,Social Media,9
BLR-202413,2024-06-29,Bangalore,Ward 7 – Yeshwanthpur,Yeshwanthpur Market Area,Overflowing garbage bins near vegetable market.,WhatsApp Helpline,13
BLR-202418,2024-06-02,Bangalore,Ward 8 – BTM Layout,2nd Stage Residential Area,Loud music from venue past midnight disturbing residents.,Citizen Portal,5
BLR-202419,2024-06-01,Bangalore,Ward 9 – Koramangala,Sony World Junction,Road surface sinking near recent utility work.,Social Media,2
BLR-202420,2024-06-03,Bangalore,Ward 10 – Banashankari,Outer Ring Road near PES University,Open manhole without cover creating accident risk.,Email,14
BLR-202427,2024-06-07,Bangalore,Ward 11 – Hebbal,Hebbal Flyover Service Road,Waterlogging makes approach road inaccessible after rain.,Councillor Referral,12
BLR-202428,2024-06-23,Bangalore,Ward 12 – Sadashivanagar,Bellary Road,Dead animal not removed for over a day. Health concern.,Email,1
BLR-202430,2024-06-23,Bangalore,Ward 13 – Chickpet,Chickpet Market Area,Streetlights not working in heritage market area.,Social Media,19
BLR-202433,2024-06-08,Bangalore,Ward 14 – Marathahalli,Outer Ring Road,Construction debris dumped on public road.,Phone Helpline,20
BLR-202446,2024-06-09,Bangalore,Ward 15 – Basavanagudi,Bull Temple Road,Broken footpath tiles causing trips and falls.,Email,18
8 changes: 4 additions & 4 deletions uc-0a/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,20 @@

## Your Input File
```
../data/city-test-files/test_[your-city].csv
../data/city-test-files/test_bangalore.csv
```
15 rows per city. `category` and `priority_flag` columns are stripped — you must classify them.

## Your Output File
```
uc-0a/results_[your-city].csv
uc-0a/results_bangalore.csv
```

## Run Command
```bash
python classifier.py \
--input ../data/city-test-files/test_pune.csv \
--output results_pune.csv
--input ../data/city-test-files/test_bangalore.csv \
--output results_bangalore.csv
```

---
Expand Down
42 changes: 28 additions & 14 deletions uc-0a/agents.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,32 @@
# agents.md — UC-0A Complaint Classifier
# INSTRUCTIONS: Generate a draft using your RICE prompt, then manually refine this file.
# Delete these comments before committing.
# UC-0A Agents

role: >
[FILL IN: Who is this agent? What is its operational boundary?]
This document defines the agents responsible for executing UC-0A — Complaint Classifier.

intent: >
[FILL IN: What does a correct output look like — make it verifiable]
---

context: >
[FILL IN: What information is the agent allowed to use? State exclusions explicitly.]
## Complaint Classifier Agent

enforcement:
- "[FILL IN: Specific testable rule 1 — e.g. Category must be exactly one of: Pothole, Flooding, ...]"
- "[FILL IN: Specific testable rule 2 — e.g. Priority must be Urgent if description contains: injury, child, school, ...]"
- "[FILL IN: Specific testable rule 3 — e.g. Every output row must include a reason field citing specific words from the description]"
- "[FILL IN: Refusal condition — e.g. If category cannot be determined from description alone, output category: Other and flag: NEEDS_REVIEW]"
Responsible for category assignment, priority detection, reason generation, and ambiguity handling.

**Key Constraints**
- Never invent categories
- Never downgrade priority when severity keywords exist
- Always provide a one-sentence reason
- Flag ambiguous cases conservatively

---

## Batch Processing Agent

Handles CSV ingestion and output generation.

Responsibilities:
- Read input CSV
- Invoke Complaint Classifier Agent per row
- Write validated output CSV

---

## Reviewer Agent

Validates rule compliance without reclassifying content.
185 changes: 173 additions & 12 deletions uc-0a/classifier.py
Original file line number Diff line number Diff line change
@@ -1,35 +1,196 @@

"""
UC-0A — Complaint Classifier
Starter file. Build this using the RICE → agents.md → skills.md → CRAFT workflow.

Built using README.md constraints + agents.md + skills.md
Deterministic, rule-based implementation (no hallucination).
"""

import argparse
import csv
import sys

# --------------------------------------------------
# UC-0A Constants (MUST match README exactly)
# --------------------------------------------------

ALLOWED_CATEGORIES = [
"Pothole",
"Flooding",
"Streetlight",
"Waste",
"Noise",
"Road Damage",
"Heritage Damage",
"Heat Hazard",
"Drain Blockage",
"Other",
]

SEVERITY_KEYWORDS = [
"injury",
"child",
"school",
"hospital",
"ambulance",
"fire",
"hazard",
"fell",
"collapse",
]


# --------------------------------------------------
# Helper functions
# --------------------------------------------------

def contains_severity_keyword(text: str) -> bool:
text_lower = text.lower()
return any(word in text_lower for word in SEVERITY_KEYWORDS)


def assign_category(text: str) -> tuple[str, str]:
"""
Returns (category, flag)
Flag is NEEDS_REVIEW only when genuinely ambiguous.
"""
t = text.lower()

matched = []

if "pothole" in t:
matched.append("Pothole")

if "flood" in t or "waterlogging" in t:
matched.append("Flooding")

if "streetlight" in t or "lamp" in t or "light not working" in t:
matched.append("Streetlight")

if "garbage" in t or "waste" in t or "trash" in t:
matched.append("Waste")

if "noise" in t or "loud" in t:
matched.append("Noise")

if "road" in t and "damage" in t:
matched.append("Road Damage")

if "heritage" in t or "monument" in t:
matched.append("Heritage Damage")

if "heat" in t or "heatwave" in t:
matched.append("Heat Hazard")

if "drain" in t or "sewage" in t or "blocked" in t:
matched.append("Drain Blockage")

if len(matched) == 1:
return matched[0], ""

if len(matched) > 1:
return matched[0], "NEEDS_REVIEW"

return "Other", ""


# --------------------------------------------------
# Core Skill: classify_complaint
# --------------------------------------------------

def classify_complaint(row: dict) -> dict:
"""
Classify a single complaint row.
Returns: dict with keys: complaint_id, category, priority, reason, flag

TODO: Build this using your AI tool guided by your agents.md and skills.md.
Your RICE enforcement rules must be reflected in this function's behaviour.

Returns dict with keys:
complaint_id, category, priority, reason, flag
"""
raise NotImplementedError("Build this using your AI tool + RICE prompt")

try:
complaint_id = row.get("complaint_id", "").strip()
description = row.get("description", "").strip()

if not description:
return {
"complaint_id": complaint_id,
"category": "Other",
"priority": "Low",
"reason": "Description is missing or empty.",
"flag": "NEEDS_REVIEW",
}

category, flag = assign_category(description)

if contains_severity_keyword(description):
priority = "Urgent"
reason = (
"Marked Urgent due to severity keyword present in description such as "
f"'{next(w for w in SEVERITY_KEYWORDS if w in description.lower())}'."
)
else:
priority = "Standard"
reason = "Classified based on complaint description text."

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

except Exception as e:
return {
"complaint_id": row.get("complaint_id", ""),
"category": "Other",
"priority": "Low",
"reason": f"Classification failed due to error: {str(e)}",
"flag": "NEEDS_REVIEW",
}


# --------------------------------------------------
# Core Skill: batch_classify
# --------------------------------------------------

def batch_classify(input_path: str, output_path: str):
"""
Read input CSV, classify each row, write results CSV.

TODO: Build this using your AI tool.
Must: flag nulls, not crash on bad rows, produce output even if some rows fail.
Must not crash on bad rows.
"""
raise NotImplementedError("Build this using your AI tool + RICE prompt")

with open(input_path, newline="", encoding="utf-8") as infile, \
open(output_path, "w", newline="", encoding="utf-8") as outfile:

reader = csv.DictReader(infile)
fieldnames = ["complaint_id", "category", "priority", "reason", "flag"]
writer = csv.DictWriter(outfile, fieldnames=fieldnames)

writer.writeheader()

for row in reader:
result = classify_complaint(row)
writer.writerow(result)


# --------------------------------------------------
# CLI entrypoint
# --------------------------------------------------

if __name__ == "__main__":
parser = argparse.ArgumentParser(description="UC-0A Complaint Classifier")
parser.add_argument("--input", required=True, help="Path to test_[city].csv")
parser.add_argument("--output", required=True, help="Path to write results CSV")
parser.add_argument(
"--input",
required=True,
help="./data/city-test-files/test_bangalore.csv",
)
parser.add_argument(
"--output",
required=True,
help="./results_bangalore.csv",
)

args = parser.parse_args()

batch_classify(args.input, args.output)
print(f"Done. Results written to {args.output}")
Loading
Loading