Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -1,9 +1,14 @@
|
|
| 1 |
-
|
| 2 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3 |
|
| 4 |
# ================================
|
| 5 |
-
#
|
| 6 |
-
# ================================
|
| 7 |
DEFAULT_PRIORITY_SCORE = {
|
| 8 |
"water": 0.9,
|
| 9 |
"electricity": 0.9,
|
|
@@ -12,7 +17,8 @@ DEFAULT_PRIORITY_SCORE = {
|
|
| 12 |
"garbage": 0.2
|
| 13 |
}
|
| 14 |
|
| 15 |
-
|
|
|
|
| 16 |
if score >= 0.75:
|
| 17 |
return "Critical"
|
| 18 |
elif score >= 0.55:
|
|
@@ -22,41 +28,85 @@ def get_priority_label(score):
|
|
| 22 |
else:
|
| 23 |
return "Low"
|
| 24 |
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
|
|
|
|
|
|
|
| 28 |
weighted = (alpha * complaint_score) + (beta * upvote_score)
|
| 29 |
return weighted
|
| 30 |
|
| 31 |
-
|
|
|
|
| 32 |
default_score = DEFAULT_PRIORITY_SCORE.get(category.lower(), 0.3)
|
| 33 |
weighted_score = calculate_weighted_score(upvotes, complaints)
|
| 34 |
final_score = 0.5 * default_score + 0.5 * weighted_score
|
|
|
|
| 35 |
return {
|
| 36 |
"text": text,
|
| 37 |
"category": category,
|
| 38 |
-
"default_score": default_score,
|
| 39 |
"weighted_score": round(weighted_score, 2),
|
| 40 |
"final_score": round(final_score, 2),
|
| 41 |
"final_label": get_priority_label(final_score)
|
| 42 |
}
|
| 43 |
|
| 44 |
-
#
|
| 45 |
-
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
|
| 51 |
-
category
|
| 52 |
-
|
| 53 |
-
|
| 54 |
-
|
| 55 |
-
|
| 56 |
-
|
| 57 |
-
|
| 58 |
-
|
| 59 |
-
|
| 60 |
-
|
| 61 |
-
|
| 62 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# app.py
|
| 2 |
+
"""
|
| 3 |
+
Complaint Prioritization API (Gradio-based)
|
| 4 |
+
Drop this file into a Hugging Face Space (SDK: Gradio) or run locally.
|
| 5 |
+
"""
|
| 6 |
+
|
| 7 |
+
from typing import List, Dict, Any
|
| 8 |
+
import gradio as gr
|
| 9 |
|
| 10 |
# ================================
|
| 11 |
+
# Default priority values mapped 0–1
|
|
|
|
| 12 |
DEFAULT_PRIORITY_SCORE = {
|
| 13 |
"water": 0.9,
|
| 14 |
"electricity": 0.9,
|
|
|
|
| 17 |
"garbage": 0.2
|
| 18 |
}
|
| 19 |
|
| 20 |
+
# Helper to convert 0–1 score into labels
|
| 21 |
+
def get_priority_label(score: float) -> str:
|
| 22 |
if score >= 0.75:
|
| 23 |
return "Critical"
|
| 24 |
elif score >= 0.55:
|
|
|
|
| 28 |
else:
|
| 29 |
return "Low"
|
| 30 |
|
| 31 |
+
# Calculate weighted score (0–1)
|
| 32 |
+
def calculate_weighted_score(upvotes: int, complaints: int, alpha: float = 0.6, beta: float = 0.4) -> float:
|
| 33 |
+
# Normalize to 0–1 scale (cap at 1)
|
| 34 |
+
upvote_score = min(upvotes / 50.0, 1.0) # assume 50 upvotes = max
|
| 35 |
+
complaint_score = min(complaints / 20.0, 1.0) # assume 20 complaints = max
|
| 36 |
weighted = (alpha * complaint_score) + (beta * upvote_score)
|
| 37 |
return weighted
|
| 38 |
|
| 39 |
+
# Handle a single complaint
|
| 40 |
+
def handle_complaint(text: str, category: str, complaints: int, upvotes: int) -> Dict[str, Any]:
|
| 41 |
default_score = DEFAULT_PRIORITY_SCORE.get(category.lower(), 0.3)
|
| 42 |
weighted_score = calculate_weighted_score(upvotes, complaints)
|
| 43 |
final_score = 0.5 * default_score + 0.5 * weighted_score
|
| 44 |
+
|
| 45 |
return {
|
| 46 |
"text": text,
|
| 47 |
"category": category,
|
| 48 |
+
"default_score": round(default_score, 2),
|
| 49 |
"weighted_score": round(weighted_score, 2),
|
| 50 |
"final_score": round(final_score, 2),
|
| 51 |
"final_label": get_priority_label(final_score)
|
| 52 |
}
|
| 53 |
|
| 54 |
+
# API entrypoint for a single complaint (for UI)
|
| 55 |
+
def predict_single(text: str, category: str, complaints: int, upvotes: int):
|
| 56 |
+
try:
|
| 57 |
+
complaints = int(complaints)
|
| 58 |
+
upvotes = int(upvotes)
|
| 59 |
+
except Exception:
|
| 60 |
+
return {"error": "complaints and upvotes must be integers"}
|
| 61 |
+
return handle_complaint(text, category, complaints, upvotes)
|
| 62 |
+
|
| 63 |
+
# API entrypoint for batch complaints (JSON text input)
|
| 64 |
+
def predict_batch(json_string: str):
|
| 65 |
+
"""
|
| 66 |
+
Accepts a JSON array string (list of dicts with keys: text, category, complaints, upvotes)
|
| 67 |
+
Example:
|
| 68 |
+
[
|
| 69 |
+
{"text":"Pothole","category":"road","complaints":2,"upvotes":5},
|
| 70 |
+
{"text":"Leak","category":"water","complaints":15,"upvotes":8}
|
| 71 |
+
]
|
| 72 |
+
"""
|
| 73 |
+
import json
|
| 74 |
+
try:
|
| 75 |
+
items = json.loads(json_string)
|
| 76 |
+
if not isinstance(items, list):
|
| 77 |
+
return {"error": "Expected a JSON array/list of complaints"}
|
| 78 |
+
except Exception as e:
|
| 79 |
+
return {"error": f"Invalid JSON: {str(e)}"}
|
| 80 |
+
|
| 81 |
+
results = []
|
| 82 |
+
for it in items:
|
| 83 |
+
t = it.get("text", "")
|
| 84 |
+
cat = it.get("category", "")
|
| 85 |
+
complaints = int(it.get("complaints", 0))
|
| 86 |
+
upvotes = int(it.get("upvotes", 0))
|
| 87 |
+
results.append(handle_complaint(t, cat, complaints, upvotes))
|
| 88 |
+
return {"results": results}
|
| 89 |
+
|
| 90 |
+
# Small UI using Gradio; Spaces will host this and expose a programmatic endpoint automatically
|
| 91 |
+
with gr.Blocks() as demo:
|
| 92 |
+
gr.Markdown("## Complaint Prioritization API\nProvide a single complaint or a JSON list for batch processing.")
|
| 93 |
+
with gr.Tab("Single complaint"):
|
| 94 |
+
txt = gr.Textbox(label="Complaint text", value="Huge pothole on main road, damaging cars daily.")
|
| 95 |
+
cat = gr.Dropdown(label="Category", choices=["water","electricity","gas","road","garbage","other"], value="road")
|
| 96 |
+
comp = gr.Number(label="Number of complaints", value=2, precision=0)
|
| 97 |
+
upv = gr.Number(label="Number of upvotes", value=5, precision=0)
|
| 98 |
+
out = gr.JSON(label="Result")
|
| 99 |
+
btn = gr.Button("Predict")
|
| 100 |
+
btn.click(fn=predict_single, inputs=[txt, cat, comp, upv], outputs=out)
|
| 101 |
+
|
| 102 |
+
with gr.Tab("Batch (JSON array)"):
|
| 103 |
+
batch_in = gr.Textbox(label="JSON array of complaints", lines=10, value='[{"text":"Leak near market","category":"water","complaints":15,"upvotes":8}]')
|
| 104 |
+
batch_out = gr.JSON(label="Batch results")
|
| 105 |
+
batch_btn = gr.Button("Predict batch")
|
| 106 |
+
batch_btn.click(fn=predict_batch, inputs=batch_in, outputs=batch_out)
|
| 107 |
+
|
| 108 |
+
gr.Markdown("### Programmatic usage\nUse the Spaces' `gradio` API endpoint `/api/predict/` (or use the `predict_batch` JSON route). See README for examples.")
|
| 109 |
+
|
| 110 |
+
# When running locally in debug mode, this will start a Gradio server.
|
| 111 |
+
if __name__ == "__main__":
|
| 112 |
+
demo.launch()
|