File size: 5,532 Bytes
04c71fb
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
import os
import requests
from src.rag.router import classify_query, extract_filters
from src.rag.retriever import retrieve_faq, load_vector_store
from src.rag.searcher import (
    search_properties, get_leases_expiring,
    get_leases_vacant_or_pending
)

GROQ_MODEL = "llama-3.3-70b-versatile"

SYSTEM_PROMPT = """You are a helpful AI assistant for a resale real estate business in Mumbai, India.

RULES:
- Answer ONLY from the data provided to you in this prompt.
- Never invent prices, features, lease status, or property details.
- If you cannot find the info, say: "I can't find this in our system right now. Please check with our sales team."
- Be friendly, short, and clear.
- Use Indian number formatting: ₹1,20,00,000 (1.2 crore) or ₹85 lakh (₹85,00,000).
- After property listings, always add: "For a site visit or more details, WhatsApp us or contact our sales team."
- After FAQ answers, optionally add: "If you need more info, feel free to ask."
- For manager queries, be factual and structured with tables.
"""


def _fmt_price(price_inr: float) -> str:
    """Format price in Indian notation."""
    if price_inr >= 10000000:
        return f"₹{price_inr/10000000:.2f} Cr"
    else:
        return f"₹{price_inr/100000:.1f} L"


def format_properties(props: list[dict]) -> str:
    if not props:
        return "We don't have any properties matching your filters in current listings."
    lines = []
    for i, p in enumerate(props, 1):
        lines.append(
            f"{i}. **{p['title']}**\n"
            f"   • {p['bhk']} BHK | {p['property_type']} | {p['area_sqft']} sq ft\n"
            f"   • Price: {_fmt_price(p['price_inr'])} | Floor: {p['floor']}/{p['total_floors']}\n"
            f"   • Location: {p['location']}, {p['society']}\n"
            f"   • Furnishing: {p['furnishing']} | Parking: {p['parking']} | Grade: {p['condition_grade']}\n"
            f"   • Amenities: {p['amenities']}"
        )
    return "\n\n".join(lines)


def format_lease_table(records: list[dict]) -> str:
    if not records:
        return "No records found for this query."
    lines = [
        "| Prop ID | Property | Location | Rent/mo | Status | Lease End | Follow-up |",
        "|---------|----------|----------|---------|--------|-----------|-----------|"
    ]
    for r in records:
        rent = f"₹{r['monthly_rent']:,}" if r.get('monthly_rent') else "—"
        lease_end = r.get('lease_end') or "—"
        lines.append(
            f"| {r['property_id']} | {r['title']} ({r['bhk']}BHK) "
            f"| {r['location']} | {rent} "
            f"| {r['lease_status']} | {lease_end} | {r['followup_person']} |"
        )
    return "\n".join(lines)


def call_groq(api_key: str, messages: list) -> str:
    url = "https://api.groq.com/openai/v1/chat/completions"
    headers = {
        "Authorization": f"Bearer {api_key}",
        "Content-Type": "application/json"
    }
    payload = {
        "model": GROQ_MODEL,
        "messages": messages,
        "max_tokens": 1024,
        "temperature": 0.3
    }
    resp = requests.post(url, json=payload, headers=headers, timeout=30)
    if resp.status_code != 200:
        raise ValueError(f"Groq API error {resp.status_code}: {resp.text[:200]}")
    return resp.json()["choices"][0]["message"]["content"]


def chat(query: str, role: str = "customer", history: list = None) -> dict:
    query_type = classify_query(query, role)
    context = ""
    properties = []
    lease_records = []

    if query_type == "property_filter":
        filters = extract_filters(query)
        properties = search_properties(**filters)
        prop_text = format_properties(properties)
        context = f"PROPERTY INVENTORY RESULTS:\n{prop_text}"

    elif query_type == "lease" and role == "manager":
        q_lower = query.lower()
        if "vacant" in q_lower or "expired" in q_lower or "pending" in q_lower:
            lease_records = get_leases_vacant_or_pending()
        else:
            days = 30
            if "15 days" in q_lower:
                days = 15
            elif "week" in q_lower:
                days = 7
            elif "month" in q_lower or "30 days" in q_lower:
                days = 30
            elif "60 days" in q_lower or "2 months" in q_lower:
                days = 60
            lease_records = get_leases_expiring(days)
        table = format_lease_table(lease_records)
        context = f"LEASE DATA:\n{table}"

    elif query_type == "faq":
        faq_context = retrieve_faq(query)
        context = f"FAQ KNOWLEDGE BASE:\n{faq_context}"

    # Build messages for Groq (OpenAI-compatible)
    messages = [{"role": "system", "content": SYSTEM_PROMPT}]
    if history:
        for h in history[-6:]:
            msg_role = "user" if h["role"] == "user" else "assistant"
            messages.append({"role": msg_role, "content": h["content"]})

    user_content = f"CONTEXT:\n{context}\n\nUSER QUERY: {query}"
    messages.append({"role": "user", "content": user_content})

    try:
        api_key = os.environ.get("GROQ_API_KEY", "").strip()
        if not api_key:
            raise ValueError(
                "GROQ_API_KEY is not set. Go to Space Settings → Repository Secrets and add GROQ_API_KEY."
            )
        reply = call_groq(api_key, messages)
    except Exception as e:
        reply = f"⚠️ AI unavailable: {str(e)[:200]}"

    return {
        "reply": reply,
        "query_type": query_type,
        "properties": properties,
        "lease_records": lease_records,
    }