# Rule-based triage classifier for support inquiries. # # Deterministic keyword scorer: every category carries a list of case-insensitive # substrings (single words and multi-word phrases). classify() returns the # category with the most matching keywords; ties are resolved by a fixed priority # order. Texts with zero keyword hits fall back to "other". # # This is a dictionary-exact router (triage lane). Real-world accuracy is # measured, not assumed: the gold set in gold.json and the assertion in # test_triage.py pin the expected behaviour, and run_audit.py reports precision / # recall / f1 per category. CATEGORY_ORDER = [ "account", "billing", "technical_support", "feature_request", "other", ] CATEGORY_META = { "account": "Account access & identity", "billing": "Billing & payments", "technical_support": "Technical support", "feature_request": "Feature request", "other": "Other / general", } # Multi-word keywords are matched as substrings too, so "log in" matches # "cannot log in" (which is purely account-side speech). KEYWORDS = { "account": [ "log in", "password", "2fa", "sign up", "signup", "cannot log in", "verification code", "not received my code", ], "billing": [ "invoice", "charged", "refund", "subscription", "credit card", "payment method", "amount due", "billing statement", ], "technical_support": [ "crash", "500", "slow", "deploy", "cannot connect", "connection refused", "database unreachable", "page not found", "timeout", "install", "uptime check", "api error", "experienced an error", ], "feature_request": [ "feature", "suggest", "enhancement", "request", "would like", "new feature", "add ability", ], } def classify(text): """Return (category, scores_dict) for a single inquiry string.""" low = text.lower() scores = {"other": 0} scores.update({cat: sum(1 for k in kws if k in low) for cat, kws in KEYWORDS.items()}) best = max(scores.values()) if best == 0: return "other", scores winners = [c for c in CATEGORY_ORDER if scores[c] == best] return winners[0], scores def batch_classify(texts): """Classify a list of texts; result mirrors (text, category).""" return [classify(t) for t in texts]