"""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()