File size: 5,120 Bytes
25c8c70
dffe895
25c8c70
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
428dafd
25c8c70
 
d29a4b6
25c8c70
 
dffe895
25c8c70
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
"""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