Download app.py from Amii2410/api: direct link, hf CLI and curl.
- Browser
- Download file 10.6 kB
-
https://huggingface.co/Amii2410/api/resolve/main/app.py
- Command line
-
hf download hf://Amii2410/api/app.py
-
curl -L -o app.py https://huggingface.co/Amii2410/api/resolve/main/app.py
10.6 kB
| # -*- coding: utf-8 -*- | |
| """app.ipynb | |
| Automatically generated by Colab. | |
| Original file is located at | |
| https://colab.research.google.com/drive/1Bli_bGuux1CJr22uJYxsoLSQkr5LjXvD | |
| """ | |
| import random | |
| import pandas as pd | |
| # Complaint categories with 10–12 synonym-rich templates each (no {} placeholders now) | |
| categories = { | |
| "Garbage": [ | |
| "Garbage not collected", | |
| "Trash piled up", | |
| "Waste scattered everywhere", | |
| "Debris dumped carelessly", | |
| "Rubbish overflowing", | |
| "Litter causing bad smell", | |
| "Uncollected scrap lying around", | |
| "Filth spread all over", | |
| "Junk thrown carelessly", | |
| "Refuse dumped openly", | |
| "Garbage heap blocking the way", | |
| "Dumping ground overflowing" | |
| ], | |
| "Water": [ | |
| "Water pipeline leaking", | |
| "No water supply", | |
| "Contaminated tap water", | |
| "Low water pressure", | |
| "Water tanker not arrived", | |
| "Sewage water overflow", | |
| "Drainage issue", | |
| "Sewer blockage reported", | |
| "Flooding due to heavy rain", | |
| "Water logging problem", | |
| "Dirty water flowing", | |
| "Burst pipeline issue" | |
| ], | |
| "Roads": [ | |
| "Big pothole on the road", | |
| "Damaged road surface", | |
| "Cracks on the road", | |
| "Uneven surface making driving difficult", | |
| "Broken speed breaker", | |
| "Debris blocking the road", | |
| "Manhole cover missing", | |
| "Broken pavement", | |
| "Damaged footpath", | |
| "Road erosion reported", | |
| "Construction waste dumped on road", | |
| "Street blocked due to cave-in" | |
| ], | |
| "Electricity": [ | |
| # General electricity | |
| "Frequent power cuts", | |
| "Load shedding problem", | |
| "Voltage fluctuation issue", | |
| "Transformer not working", | |
| "Wire hanging dangerously", | |
| "No electricity supply", | |
| "Complete blackout", | |
| "Short circuit issue reported", | |
| "Electrical failure in houses", | |
| "Electric spark observed", | |
| # Streetlight related | |
| "Streetlight not working", | |
| "Streetlight bulb fused", | |
| "Dark area due to broken streetlight", | |
| "Streetlight flickering", | |
| "Streetlight pole damaged", | |
| "Entire lane dark without lights" | |
| ] | |
| } | |
| # Number of complaints per category (balanced dataset) | |
| num_samples = 300 # per category | |
| data = [] | |
| for category, templates in categories.items(): | |
| for _ in range(num_samples): | |
| template = random.choice(templates) | |
| data.append({ | |
| "Complaint Text": template, | |
| "Category": category | |
| }) | |
| # Convert to DataFrame | |
| df = pd.DataFrame(data) | |
| # Shuffle | |
| df = df.sample(frac=1).reset_index(drop=True) | |
| # Save CSV | |
| df.to_csv("synthetic_civic_complaints_no_location.csv", index=False, encoding="utf-8") | |
| print("✅ Final synonym-rich dataset created: synthetic_civic_complaints_no_location.csv") | |
| display(df.head()) | |
| import pandas as pd | |
| from sklearn.model_selection import train_test_split, cross_val_score, learning_curve | |
| from sklearn.feature_extraction.text import TfidfVectorizer | |
| from sklearn.linear_model import LogisticRegression | |
| from sklearn.metrics import classification_report, accuracy_score, confusion_matrix, ConfusionMatrixDisplay | |
| import matplotlib.pyplot as plt | |
| import numpy as np | |
| # 1. Load dataset | |
| df = pd.read_csv("synthetic_civic_complaints_rich.csv") | |
| # 🔹 Make all complaint text lowercase (case-insensitive) | |
| df["Complaint Text"] = df["Complaint Text"].str.lower() | |
| # 2. Train-test split | |
| X = df["Complaint Text"] | |
| y = df["Category"] | |
| X_train, X_test, y_train, y_test = train_test_split( | |
| X, y, test_size=0.2, random_state=42, stratify=y | |
| ) | |
| # 3. Vectorizer + classifier | |
| vectorizer = TfidfVectorizer(stop_words="english", max_features=5000) | |
| X_train_vec = vectorizer.fit_transform(X_train) | |
| X_test_vec = vectorizer.transform(X_test) | |
| clf = LogisticRegression(max_iter=500) | |
| clf.fit(X_train_vec, y_train) | |
| # 4. Evaluate | |
| y_pred = clf.predict(X_test_vec) | |
| print("Accuracy:", accuracy_score(y_test, y_pred)) | |
| print("\nClassification Report:\n", classification_report(y_test, y_pred)) | |
| # 5. Confusion Matrix | |
| labels = clf.classes_ | |
| cm = confusion_matrix(y_test, y_pred, labels=labels) | |
| disp = ConfusionMatrixDisplay(confusion_matrix=cm, display_labels=labels) | |
| fig, ax = plt.subplots(figsize=(6, 5)) | |
| disp.plot(ax=ax, cmap="Blues", values_format="d") | |
| plt.show() | |
| # 6. Cross-validation | |
| from sklearn.pipeline import Pipeline | |
| pipe = Pipeline([ | |
| ("tfidf", TfidfVectorizer(stop_words="english", max_features=5000)), | |
| ("clf", LogisticRegression(max_iter=500)) | |
| ]) | |
| scores = cross_val_score(pipe, X, y, cv=5, scoring="accuracy") | |
| print("Cross-validation scores:", scores) | |
| print("Mean CV Accuracy:", scores.mean()) | |
| # 7. Learning Curve | |
| train_sizes, train_scores, val_scores = learning_curve( | |
| pipe, X, y, cv=5, scoring="accuracy", | |
| train_sizes=np.linspace(0.1, 1.0, 5) | |
| ) | |
| train_mean = train_scores.mean(axis=1) | |
| val_mean = val_scores.mean(axis=1) | |
| plt.plot(train_sizes, train_mean, label="Training score") | |
| plt.plot(train_sizes, val_mean, label="Validation score") | |
| plt.xlabel("Training Set Size") | |
| plt.ylabel("Accuracy") | |
| plt.title("Learning Curve") | |
| plt.legend() | |
| plt.grid(True) | |
| plt.show() | |
| import spacy | |
| from spacy.training.example import Example | |
| # Create blank English pipeline | |
| nlp = spacy.blank("en") | |
| # Add text categorizer instead of NER | |
| textcat = nlp.add_pipe("textcat") | |
| textcat.add_label("Garbage") | |
| textcat.add_label("Water") | |
| textcat.add_label("Roads") | |
| textcat.add_label("Electricity") | |
| # Prepare training data | |
| TRAIN_DATA = [] | |
| for _, row in df.iterrows(): | |
| text = row["Complaint Text"] | |
| label = row["Category"] | |
| cats = {cat: 0.0 for cat in textcat.labels} | |
| cats[label] = 1.0 | |
| TRAIN_DATA.append((text, {"cats": cats})) | |
| # Train the text classifier | |
| optimizer = nlp.begin_training() | |
| for i in range(20): # epochs | |
| losses = {} | |
| for text, annotations in TRAIN_DATA: | |
| doc = nlp.make_doc(text) | |
| example = Example.from_dict(doc, annotations) | |
| nlp.update([example], sgd=optimizer, losses=losses) | |
| print(f"Epoch {i+1}, Losses: {losses}") | |
| # Save model | |
| nlp.to_disk("complaint_textcat_model") | |
| print("✅ Text classification model saved: complaint_textcat_model") | |
| import spacy | |
| from spacy.training.example import Example | |
| import random | |
| # 🔹 Build text classification training data | |
| TRAIN_DATA = [] | |
| for _, row in df.iterrows(): | |
| text = row["Complaint Text"] | |
| label = row["Category"] | |
| cats = { | |
| "Garbage": 0.0, | |
| "Water": 0.0, | |
| "Roads": 0.0, | |
| "Electricity": 0.0 | |
| } | |
| cats[label] = 1.0 | |
| TRAIN_DATA.append((text, {"cats": cats})) | |
| # 🔹 Create blank pipeline with text categorizer | |
| nlp = spacy.blank("en") | |
| textcat = nlp.add_pipe("textcat") | |
| for label in ["Garbage", "Water", "Roads", "Electricity"]: | |
| textcat.add_label(label) | |
| nlp.initialize() | |
| # 🔹 Train model | |
| for itn in range(10): # epochs | |
| random.shuffle(TRAIN_DATA) | |
| losses = {} | |
| for text, ann in TRAIN_DATA: | |
| doc = nlp.make_doc(text) | |
| example = Example.from_dict(doc, ann) | |
| nlp.update([example], losses=losses) | |
| print(f"Epoch {itn+1}, Losses: {losses}") | |
| # 🔹 Complaint prediction function | |
| def predict_complaint(text): | |
| doc = nlp(text) | |
| # Step 1 → Category prediction | |
| cats = doc.cats | |
| category = max(cats, key=cats.get) # pick category with highest score | |
| # Step 2 → Priority detection | |
| text_lower = text.lower() | |
| urgent_words = ["urgent", "dangerous", "immediately", "accident", "severe"] | |
| medium_words = ["not working", "overflow", "leak", "delay", "low pressure"] | |
| priority = "Low" | |
| if any(word in text_lower for word in urgent_words): | |
| priority = "High" | |
| elif any(word in text_lower for word in medium_words): | |
| priority = "Medium" | |
| return { | |
| "Complaint": text, | |
| "Predicted Category": category, | |
| "Priority": priority | |
| } | |
| # 🔹 Test it | |
| print(predict_complaint("Debris dumped behind chandni chowk")) | |
| print(predict_complaint("Streetlight not working near ChANdni chowk, its very dangerous")) | |
| import pickle | |
| # Wrapper so spaCy model can be pickled | |
| class ComplaintClassifier: | |
| def __init__(self, nlp_model): | |
| self.nlp = nlp_model | |
| def predict(self, text): | |
| doc = self.nlp(text) | |
| cats = doc.cats | |
| category = max(cats, key=cats.get) | |
| # Priority detection | |
| text_lower = text.lower() | |
| urgent_words = ["urgent", "dangerous", "immediately", "accident", "severe"] | |
| medium_words = ["not working", "overflow", "leak", "delay", "low pressure"] | |
| priority = "Low" | |
| if any(word in text_lower for word in urgent_words): | |
| priority = "High" | |
| elif any(word in text_lower for word in medium_words): | |
| priority = "Medium" | |
| return { | |
| "Complaint": text, | |
| "Predicted Category": category, | |
| "Priority": priority | |
| } | |
| # Wrap trained spaCy model | |
| classifier = ComplaintClassifier(nlp) | |
| # Save with pickle | |
| with open("complaint_model.pkl", "wb") as f: | |
| pickle.dump(classifier, f) | |
| print("✅ complaint_model.pkl saved successfully") | |
| from fastapi import FastAPI | |
| from pydantic import BaseModel | |
| import uvicorn | |
| import nest_asyncio | |
| import pickle | |
| import spacy | |
| # ========== Load trained model ========== | |
| # Make sure you have already trained & saved it as complaint_model.pkl | |
| with open("complaint_model.pkl", "rb") as f: | |
| nlp = pickle.load(f) | |
| # ========== Priority detection ========== | |
| def detect_priority(text: str) -> str: | |
| text_lower = text.lower() | |
| urgent_words = ["urgent", "dangerous", "immediately", "accident", "severe"] | |
| medium_words = ["not working", "overflow", "leak", "delay", "low pressure"] | |
| if any(word in text_lower for word in urgent_words): | |
| return "High" | |
| elif any(word in text_lower for word in medium_words): | |
| return "Medium" | |
| return "Low" | |
| # ========== FastAPI ========== | |
| app = FastAPI() | |
| class ComplaintInput(BaseModel): | |
| text: str | |
| async def predict_complaint(input_data: ComplaintInput): | |
| doc = nlp(input_data.text) | |
| cats = doc.cats | |
| category = max(cats, key=cats.get) | |
| priority = detect_priority(input_data.text) | |
| return { | |
| "Complaint": input_data.text, | |
| "Predicted Category": category, | |
| "Priority": priority, | |
| "Raw Scores": cats | |
| } | |
| # ========== Run in Colab only ========== | |
| if __name__ == "__main__": | |
| try: | |
| nest_asyncio.apply() | |
| uvicorn.run(app, host="0.0.0.0", port=7860) | |
| except RuntimeError: | |
| # In Hugging Face or when uvicorn is auto-run, we skip this | |
| pass | |