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, }