khidmatAI / agents /intent.py
CoderHassan's picture
Update agents/intent.py
428dafd verified
"""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": "<one of: AC Technician, Plumber, Electrician, Tutor, Beautician, Carpenter, Painter, Driver, Maid, Delivery Worker>",
"location": "<area name like G-13, F-10, etc. Extract from message>",
"time": "<e.g. tomorrow morning, today evening, asap>",
"language": "<urdu | roman_urdu | english | mixed>",
"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