Spaces:
Runtime error
Runtime error
| """ | |
| agent.py β Groq API version | |
| Uses Groq's free API with llama-3.3-70b-versatile model. | |
| Groq is extremely fast (200+ tokens/sec) and free to use. | |
| Setup: | |
| 1. Go to console.groq.com β sign up β API Keys β Create Key | |
| 2. Set: export GROQ_API_KEY=gsk_your_key_here (Mac/Linux) | |
| set GROQ_API_KEY=gsk_your_key_here (Windows) | |
| 3. pip install groq | |
| """ | |
| import os | |
| import json | |
| import re | |
| from groq import Groq | |
| client = Groq(api_key=os.environ.get("GROQ_API_KEY", "")) | |
| MODEL = "llama-3.3-70b-versatile" # Free, fast, high quality | |
| def _call(system: str, user: str, max_tokens: int = 800) -> str: | |
| """Call Groq API and return text response.""" | |
| response = client.chat.completions.create( | |
| model=MODEL, | |
| max_tokens=max_tokens, | |
| temperature=0.2, | |
| messages=[ | |
| {"role": "system", "content": system}, | |
| {"role": "user", "content": user}, | |
| ], | |
| ) | |
| return response.choices[0].message.content.strip() | |
| # ββ CLASSIFICATION ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| CLASSIFY_SYSTEM = """You are a support ticket classifier for a multi-domain helpdesk. | |
| Classify the ticket into exactly these fields and respond ONLY with valid JSON. | |
| Fields: | |
| - domain: one of ["hackerrank", "claude", "visa", "unknown"] | |
| * hackerrank β coding assessments, candidates, recruiters, HackerRank platform, proctoring, plagiarism | |
| * claude β Claude AI assistant, claude.ai, Anthropic API, AI conversations, Claude subscription | |
| * visa β Visa card, ATM, transactions, payments, card dispute, merchant | |
| * unknown β unclear or does not match any domain | |
| - request_type: one of ["faq", "billing", "bug_report", "account_access", | |
| "assessment", "feature_request", "fraud", "complaint", | |
| "how_to", "permissions", "other"] | |
| - product_area: short phrase (e.g. "password reset", "card dispute", "API usage", "candidate results") | |
| - confidence: "high" | "medium" | "low" | |
| Respond ONLY with a JSON object. No markdown fences. No explanation. No extra text.""" | |
| def classify_ticket(ticket_text: str) -> dict: | |
| """Classify a support ticket. Returns dict.""" | |
| raw = _call(CLASSIFY_SYSTEM, f"Classify this ticket:\n\n{ticket_text}", max_tokens=200) | |
| try: | |
| clean = raw.strip().strip("```json").strip("```").strip() | |
| return json.loads(clean) | |
| except json.JSONDecodeError: | |
| # Try to extract JSON object with regex | |
| match = re.search(r'\{.*?\}', clean, re.DOTALL) | |
| if match: | |
| try: | |
| return json.loads(match.group(0)) | |
| except Exception: | |
| pass | |
| return _rule_based_classify(ticket_text) | |
| def _rule_based_classify(text: str) -> dict: | |
| """Fast keyword fallback if LLM JSON parse fails.""" | |
| t = text.lower() | |
| if any(w in t for w in ["hackerrank", "assessment", "candidate", "recruiter", "plagiar", "proctoring"]): | |
| domain = "hackerrank" | |
| elif any(w in t for w in ["claude", "anthropic", "claude.ai", "ai assistant"]): | |
| domain = "claude" | |
| elif any(w in t for w in ["visa", "card", "atm", "transaction", "merchant", "chargeback"]): | |
| domain = "visa" | |
| else: | |
| domain = "unknown" | |
| if any(w in t for w in ["fraud", "unauthorized", "stolen", "scam"]): | |
| rtype = "fraud" | |
| elif any(w in t for w in ["charge", "refund", "billing", "invoice"]): | |
| rtype = "billing" | |
| elif any(w in t for w in ["password", "login", "locked", "hacked", "access"]): | |
| rtype = "account_access" | |
| elif any(w in t for w in ["bug", "error", "broken", "crash", "not working"]): | |
| rtype = "bug_report" | |
| else: | |
| rtype = "faq" | |
| return {"domain": domain, "request_type": rtype, | |
| "product_area": f"{domain} support", "confidence": "medium"} | |
| # ββ RESPONSE GENERATION βββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| RESPONSE_SYSTEM = """You are a professional, friendly support agent. | |
| STRICT RULE: Answer ONLY using the provided support documentation. | |
| Do NOT invent any policies, prices, steps, or features not in the docs. | |
| If docs don't cover something, say so honestly and suggest contacting support directly. | |
| Keep responses concise: 3-5 sentences for simple FAQs, up to 8 for complex issues.""" | |
| def generate_response(ticket_text: str, docs: list[dict]) -> str: | |
| """Generate a grounded support response using retrieved docs.""" | |
| if not docs: | |
| return ( | |
| "Thank you for reaching out. I wasn't able to find relevant documentation " | |
| "for your specific query in our support corpus. Please contact our support " | |
| "team directly for personalized assistance." | |
| ) | |
| context = "\n\n---\n\n".join( | |
| f"[Source {i}: {d['title']}]\n{d.get('snippet', d['text'][:800])}" | |
| for i, d in enumerate(docs[:4], 1) | |
| ) | |
| user_prompt = f"""Support Documentation: | |
| {context} | |
| --- | |
| Customer Issue: | |
| {ticket_text} | |
| Write a helpful, accurate response using only the documentation above.""" | |
| return _call(RESPONSE_SYSTEM, user_prompt, max_tokens=500) | |
| # ββ ESCALATION MESSAGE ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| ESCALATE_SYSTEM = """You are a support agent writing an escalation acknowledgment. | |
| Write 2-3 sentences: acknowledge the customer's concern, say a specialist will review it, | |
| and set a reasonable expectation. Be warm and professional. | |
| Do NOT attempt to resolve the issue. Do NOT reveal internal routing decisions.""" | |
| def generate_escalation_message(ticket_text: str, escalation_reason: str) -> str: | |
| """Generate a customer-facing escalation message.""" | |
| return _call( | |
| ESCALATE_SYSTEM, | |
| f"Customer issue: {ticket_text}\n\n(Internal note - do not reveal: {escalation_reason})", | |
| max_tokens=180, | |
| ) | |