suggestion_bot / simple_agent.py
Sanjay Ram A
Upload 52 files
75788a5 verified
Raw
History Blame Contribute Delete
10.9 kB
"""Simplified agent that works without LangChain - pure Python only."""
import logging
from typing import Dict, Any, List, Optional
import re
import json
from config import settings
from database import db, Platform
logger = logging.getLogger(__name__)
class SimpleAgent:
"""Simplified agent for direct product suggestions without complex orchestration."""
def __init__(self):
self.api_key = settings.gemini_api_key
self.serpapi_key = settings.serpapi_api_key
def process_simple(
self,
platform: str,
platform_user_id: str,
user_message: str
) -> Dict[str, Any]:
"""Process request with simple direct approach."""
try:
logger.info(f"Simple agent processing: {user_message}")
# Get or create user
user = db.get_user(Platform(platform), platform_user_id)
# Check if user is providing location (pincode or city name)
if self._looks_like_location(user_message):
db.upsert_user(Platform(platform), platform_user_id, location_str=user_message)
return {
"success": True,
"response_text": "Great! Location saved. Now, what's your name?",
"picks": []
}
# Check profile completion
if not user or not user.get("location_str"):
db.upsert_user(Platform(platform), platform_user_id)
return {
"success": True,
"response_text": "Welcome! To give you personalized product suggestions, I need a few details.\n\n📍 First, what's your location? (e.g., 'Mumbai' or '400001')",
"picks": []
}
if not user.get("name"):
# Check if this message is a name (simple heuristic)
if not any(char.isdigit() for char in user_message) and len(user_message.split()) <= 3 and not self._looks_like_location(user_message):
db.upsert_user(Platform(platform), platform_user_id, name=user_message.strip())
return {
"success": True,
"response_text": "Nice to meet you! What's your age?",
"picks": []
}
return {
"success": True,
"response_text": "Thanks! What's your name?",
"picks": []
}
if not user.get("age"):
# Check if this message is an age
try:
age = int(user_message.strip())
if 5 <= age <= 120:
db.upsert_user(Platform(platform), platform_user_id, age=age)
return {
"success": True,
"response_text": "Perfect! Now you can ask me for product suggestions.\n\n"
"Examples:\n"
"• 'I need a mobile under ₹6000'\n"
"• 'Show me cycles under ₹8000'\n"
"• 'Books under ₹300'",
"picks": []
}
except:
pass
return {
"success": True,
"response_text": "Great! And what's your age?",
"picks": []
}
# Extract category and budget
category, budget = self._extract_info(user_message)
if not category or not budget:
return {
"success": True,
"response_text": "Please specify what you're looking for and your budget.\n\n"
"Examples:\n"
"• 'I need a mobile under ₹6000'\n"
"• 'Show me cycles under ₹7000'\n"
"• 'Books under ₹300'",
"picks": []
}
# Check cache
location_key = db.make_location_key(user.get("location_str"))
cached = db.cache_get(category, budget, location_key)
if cached:
logger.info("Using cached results")
return {
"success": True,
"response_text": cached["response_text"],
"picks": cached.get("picks_json", [])
}
# Get product suggestions using search
picks = self._search_products(category, budget, user.get("location_str", "India"))
if not picks:
return {
"success": True,
"response_text": f"I couldn't find any {category} products under ₹{budget}. Try:\n"
f"• Increasing your budget\n"
f"• Checking the spelling\n"
f"• Being more specific",
"picks": []
}
# Format response
top_picks = picks[:3]
response = f"Top Picks: {', '.join([p['name'] for p in top_picks])}\n\n"
response += f"Here are 3 great {category} options under ₹{budget} for you:\n\n"
for i, pick in enumerate(top_picks, 1):
response += f"{i}. {pick['name']}\n"
response += f" Price: ₹{pick['price']}\n"
if pick.get('rating'):
response += f" Rating: {pick['rating']}⭐\n"
response += "\n"
# Cache the results
picks_json = [{"name": p["name"], "rank": i+1} for i, p in enumerate(top_picks)]
db.cache_put(
user_id=user["id"],
category=category,
budget_inr=budget,
location_key=location_key,
response_text=response,
picks_json=picks_json,
ttl_hours=24
)
return {
"success": True,
"response_text": response,
"picks": picks_json
}
except Exception as e:
logger.error(f"Simple agent error: {e}", exc_info=True)
return {
"success": False,
"error": str(e),
"response_text": "Sorry, something went wrong. Please try again.",
"picks": []
}
def _extract_info(self, message: str) -> tuple:
"""Extract category and budget from message."""
message_lower = message.lower()
# Extract category
category = None
if any(word in message_lower for word in ['mobile', 'phone', 'smartphone']):
category = 'mobile'
elif any(word in message_lower for word in ['cycle', 'bicycle', 'bike']):
category = 'cycle'
elif any(word in message_lower for word in ['book', 'books']):
category = 'books'
# Extract budget
budget = None
patterns = [
r'₹\s*(\d+k?)',
r'(?:under|below|max|maximum|budget)\s*[:\s]*₹?\s*(\d+k?)',
r'(\d+k?)\s*(?:rupees|inr|rs|₹)',
r'(\d+k?)', # Just a number
]
for pattern in patterns:
match = re.search(pattern, message_lower)
if match:
budget_str = match.group(1)
if 'k' in budget_str:
budget = int(budget_str.replace('k', '')) * 1000
else:
budget = int(budget_str)
break
logger.info(f"Extracted: category={category}, budget={budget}")
return category, budget
def _looks_like_location(self, message: str) -> bool:
"""Check if message looks like a location (pincode or city name)."""
message = message.strip()
# Check if it's a 6-digit pincode
if message.isdigit() and len(message) == 6:
return True
# Check if it's a city/location name (no numbers, reasonable length)
if not any(char.isdigit() for char in message) and 3 <= len(message) <= 50:
# Exclude common greetings
greetings = ['hi', 'hello', 'hey', 'thanks', 'ok', 'yes', 'no']
if message.lower() not in greetings:
return True
return False
def _search_products(self, category: str, budget: int, location: str) -> List[Dict]:
"""Search for products using SerpApi."""
try:
import serpapi
query = f"{category} under {budget} INR"
logger.info(f"Searching: {query}")
client = serpapi.Client(api_key=settings.serpapi_api_key)
results = client.search({
"engine": "google_shopping",
"q": query,
"gl": "in",
"hl": "en",
"num": 10
})
candidates = []
shopping_results = results.get("shopping_results", [])
for item in shopping_results:
try:
price_str = item.get("extracted_price", item.get("price", "0"))
if isinstance(price_str, str):
price = float(price_str.replace(",", "").replace("₹", "").strip())
else:
price = float(price_str)
if price > 0 and price <= budget:
candidates.append({
"name": item.get("title", "Unknown"),
"price": int(price),
"rating": item.get("rating", 0),
"source": item.get("source", ""),
"link": item.get("link", "")
})
except Exception as e:
logger.debug(f"Skipping item: {e}")
continue
# Sort by rating, then price
candidates.sort(key=lambda x: (x.get("rating", 0), -x["price"]), reverse=True)
logger.info(f"Found {len(candidates)} products")
return candidates
except Exception as e:
logger.error(f"Search error: {e}")
return []
simple_agent = SimpleAgent()