HomeRealty / src /rag /chatbot.py
jaydeb2023
Moved project files to root for Hugging Face Space
4ab8820
Raw
History Blame Contribute Delete
5.53 kB
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,
}