Spaces:
Sleeping
Sleeping
| """ | |
| tasks/hard_task.py β Hard scenario: angry VIP customer threatening legal action | |
| after a 3-week unresolved product failure | |
| Grader used: HardTaskGrader (requires de-escalation + concrete resolution) | |
| """ | |
| from models import Task, StepName, DifficultyLevel | |
| HARD_TASK = Task( | |
| task_id = "HARD_001", | |
| difficulty = DifficultyLevel.HARD, | |
| customer_emotion = "angry", | |
| escalation_risk = True, | |
| customer_message = ( | |
| "I am ABSOLUTELY FURIOUS. I purchased your premium standing desk " | |
| "(βΉ45,000) three weeks ago and it arrived broken. I've called five times, " | |
| "sent four emails, and NOBODY has fixed this. I'm a VIP member and this " | |
| "is how you treat me?! I am going to post this on every review site, " | |
| "contact consumer court, and make sure everyone knows how pathetic your " | |
| "company's service is. I want this resolved TODAY or I'm cancelling my " | |
| "entire βΉ2 lakh annual contract!" | |
| ), | |
| scenario_context = ( | |
| "Customer: Rajesh Mehta | VIP Tier | Annual contract: βΉ2,00,000. " | |
| "Order #ORD-VIP-2241 β Premium Standing Desk Pro (βΉ45,000) delivered " | |
| "on 12 March with a broken motorised lift mechanism. " | |
| "5 prior support tickets (TKT-001 to TKT-005) β all marked 'pending'. " | |
| "No technician dispatched yet. Replacement stock available (3β5 days). " | |
| "Policy: VIP customers get same-day escalation + compensation up to 20% " | |
| "of order value for delays > 7 days." | |
| ), | |
| required_steps = [ | |
| StepName.EMPATHY, | |
| StepName.COLLECT_INFO, | |
| StepName.INVESTIGATE, | |
| StepName.RESOLUTION, | |
| ], | |
| step_keywords = { | |
| StepName.EMPATHY: [ | |
| "i am personally and deeply sorry", | |
| "deeply sorry", | |
| "sincerely apologize", | |
| "i completely understand", | |
| "that is completely unacceptable", | |
| "you have every right", | |
| "i take full responsibility", | |
| "this should not have happened", | |
| "i hear your frustration", | |
| ], | |
| StepName.COLLECT_INFO: [ | |
| "order number", "ticket number", "vip", "account", | |
| "could you confirm", "full name", "email", "contact", | |
| ], | |
| StepName.INVESTIGATE: [ | |
| "reviewing your tickets", "i can see", "five tickets", | |
| "all marked pending", "this is unacceptable internally", | |
| "i have escalated", "our records show", "found that", | |
| "i found", "looking into", | |
| ], | |
| StepName.RESOLUTION: [ | |
| "replacement", "technician today", "within 24 hours", | |
| "βΉ9,000", "9000", "20%", "compensation", | |
| "personally ensure", "i will personally", | |
| "waive", "free of charge", "priority", | |
| ], | |
| }, | |
| ) | |
| # ββ Hard-task specific scoring weights ββββββββββββββββββββββββββββββββββββββββ | |
| HARD_TASK_SCORING = { | |
| "emotional_control": 0.30, # calm + empathetic tone | |
| "conflict_handling": 0.25, # de-escalation phrases | |
| "professional_tone": 0.20, # no blame, no dismissal | |
| "resolution_accuracy": 0.25, # correct refund % + timeline | |
| } | |
| def evaluate_hard_response(response: str, step: StepName) -> dict: | |
| """ | |
| Returns a breakdown dict for hard-task evaluation display. | |
| Used by the UI to show per-dimension scores. | |
| """ | |
| r = response.lower() | |
| scores = {} | |
| if step == StepName.EMPATHY: | |
| emotional_hits = sum(1 for kw in HARD_TASK.step_keywords[StepName.EMPATHY] | |
| if kw in r) | |
| scores["emotional_control"] = min(1.0, emotional_hits / 3) | |
| deesc = ["completely understand", "every right", "full responsibility", | |
| "should not have happened", "hear your frustration"] | |
| deesc_hits = sum(1 for kw in deesc if kw in r) | |
| scores["conflict_handling"] = min(1.0, deesc_hits / 2) | |
| bad = ["calm down", "your fault", "nothing we can do", "policy says"] | |
| scores["professional_tone"] = 0.0 if any(b in r for b in bad) else 1.0 | |
| scores["resolution_accuracy"] = 0.0 # N/A at empathy step | |
| elif step == StepName.RESOLUTION: | |
| scores["emotional_control"] = 1.0 if "personally ensure" in r else 0.5 | |
| scores["conflict_handling"] = 1.0 if "priority" in r else 0.5 | |
| scores["professional_tone"] = 1.0 if "i will personally" in r else 0.5 | |
| # Check resolution accuracy: compensation + timeline | |
| has_comp = any(c in r for c in ["9,000", "9000", "20%", "compensation"]) | |
| has_timeline = any(t in r for t in ["24 hours", "today", "tomorrow", "3 days"]) | |
| scores["resolution_accuracy"] = (0.5 * int(has_comp)) + (0.5 * int(has_timeline)) | |
| else: | |
| # Default neutral for mid steps | |
| scores = {k: 0.5 for k in HARD_TASK_SCORING} | |
| weighted = sum(HARD_TASK_SCORING[k] * scores.get(k, 0.0) | |
| for k in HARD_TASK_SCORING) | |
| scores["weighted_total"] = round(weighted, 3) | |
| return scores |