"""Agent 1 — Intent Agent Uses Gemini 2.5 Flash Lite if GEMINI_API_KEY is valid. Falls back to rule-based parser if key is missing/invalid (demo mode). """ import os, json, re import google.generativeai as genai # ── Rule-based fallback (no API key needed) ────────────────────── SERVICE_KEYWORDS = { "AC Technician": ["ac", "air condition", "cooling", "hvac", "thanda"], "Plumber": ["plumber", "plumbing", "pipe", "leakage", "tap", "nal"], "Electrician": ["electric", "bijli", "wiring", "light", "switch", "fuse"], "Tutor": ["tutor", "teacher", "teacher", "teacher", "padhai", "math", "science", "english"], "Beautician": ["beauty", "parlour", "makeup", "salon", "facial", "wax"], "Carpenter": ["carpenter", "wood", "furniture", "darwaza", "door", "shelf"], "Painter": ["paint", "rang", "wall", "colour", "color"], "Driver": ["driver", "car", "ride", "airport", "drop", "pick"], "Maid": ["maid", "cleaning", "sweep", "jharo", "safai", "cook"], "Delivery Worker": ["delivery", "parcel", "courier", "deliver", "send"], } AREA_KEYWORDS = [ "G-13","G-11","G-10","G-9","G-6","G-7","G-8", "F-10","F-7","F-6","F-8","F-11", "E-11","E-7","I-8","I-10","I-9", ] TIME_KEYWORDS = { "morning": ["subah", "morning", "صبح", "savere"], "afternoon": ["dopahar", "afternoon", "دوپہر"], "evening": ["sham", "evening", "شام", "shaam"], "asap": ["aaj", "today", "abhi", "now", "jaldi", "asap", "فوری"], "tomorrow": ["kal", "tomorrow", "کل"], } def rule_based_parse(message: str) -> dict: msg = message.lower() service = None for svc, keywords in SERVICE_KEYWORDS.items(): if any(k in msg for k in keywords): service = svc break location = None for area in AREA_KEYWORDS: if area.lower() in msg: location = area break time_str = "tomorrow morning" for label, keywords in TIME_KEYWORDS.items(): if any(k in msg for k in keywords): time_str = label break lang = "roman_urdu" urdu_chars = set("ابتثجحخدذرزسشصضطظعغفقکگلمنوہیآ") if any(c in urdu_chars for c in message): lang = "urdu" elif all(ord(c) < 128 for c in message): lang = "english" if re.search(r'\b(i|need|want|please|the|a|an)\b', msg) else "roman_urdu" return { "service_type": service, "location": location or "G-13", "time": time_str, "language": lang, "confidence": 0.75, "mode": "rule_based_fallback", } def run(message: str) -> dict: api_key = os.environ.get("GEMINI_API_KEY", "GEMINI_API_KEY").strip() # ── Try Gemini first ───────────────────────────────────────── if api_key and api_key != "YOUR_GEMINI_API_KEY_HERE": try: genai.configure(api_key=api_key) model = genai.GenerativeModel("gemini-2.5-flash-lite") prompt = f"""You are a service request parser for Pakistan's informal economy. Extract structured info from the user message. Respond ONLY with valid JSON, no markdown, no explanation. User message: "{message}" Return exactly this JSON: {{ "service_type": "", "location": "", "time": "", "language": "", "confidence": <0.0 to 1.0>, "mode": "gemini" }} If a field cannot be determined use null.""" response = model.generate_content(prompt) raw = response.text.strip() raw = re.sub(r"```json|```", "", raw).strip() result = json.loads(raw) result["mode"] = "gemini" return result except Exception as e: err = str(e) # Key invalid → fall through to rule-based, don't crash if "API_KEY_INVALID" in err or "API key not valid" in err: result = rule_based_parse(message) result["_warning"] = "Gemini API key invalid — using rule-based parser. Check HF Secrets." return result # Quota exceeded → same fallback if "quota" in err.lower() or "429" in err: result = rule_based_parse(message) result["_warning"] = "Gemini quota exceeded — using rule-based parser." return result raise # re-raise unexpected errors # ── No key set → rule-based ─────────────────────────────────── result = rule_based_parse(message) result["_warning"] = "GEMINI_API_KEY not set — using rule-based parser (demo mode)." return result