import os import re import warnings from typing import Dict, Tuple # Suppress deprecation warning for google.generativeai warnings.filterwarnings("ignore", category=FutureWarning, module="google.generativeai") import google.generativeai as genai class IntentDetector: """Detects user intent using Gemini API with fallback patterns.""" def __init__(self, api_key: str = None): """Initialize intent detector.""" self.api_key = api_key or os.getenv("GEMINI_API_KEY") if self.api_key: genai.configure(api_key=self.api_key) self.model = genai.GenerativeModel("gemini-2.5-flash") if self.api_key else None # Fallback patterns for intent detection self.lead_keywords = ["interested", "pricing", "cost", "plan", "business", "solution", "need help", "help me", "problem", "solve", "budget"] self.support_keywords = ["issue", "problem", "broken", "error", "not working", "help", "support", "ticket", "complaint", "fix", "order"] self.general_keywords = ["hello", "hi", "what do you do", "services", "about", "company", "info", "tell me"] def detect_intent(self, user_message: str) -> Tuple[str, float]: """ Detect user intent using Gemini API. Args: user_message: User's message Returns: Tuple of (intent, confidence) Intent: "lead", "support", "general", or "unknown" """ if self.model: return self._detect_with_gemini(user_message) else: return self._detect_with_patterns(user_message) def _detect_with_gemini(self, user_message: str) -> Tuple[str, float]: """Detect intent using Gemini API.""" try: prompt = f"""Analyze the user's message and classify their intent into ONE of these categories: - "lead": They want to know about services, pricing, features, or have a problem to solve (sales/business inquiry) - "support": They have a technical issue or need customer support help - "general": They're asking general questions about the company or making small talk - "unknown": The message doesn't fit any category User message: "{user_message}" Respond ONLY with the intent category name and a confidence score (0-1) in this format: INTENT: [category] CONFIDENCE: [score]""" response = self.model.generate_content(prompt, safety_settings=[ { "category": "HARM_CATEGORY_HARASSMENT", "threshold": "BLOCK_NONE", }, { "category": "HARM_CATEGORY_HATE_SPEECH", "threshold": "BLOCK_NONE", }, { "category": "HARM_CATEGORY_SEXUALLY_EXPLICIT", "threshold": "BLOCK_NONE", }, { "category": "HARM_CATEGORY_DANGEROUS_CONTENT", "threshold": "BLOCK_NONE", }, ]) text = response.text.strip() # Parse response intent = "unknown" confidence = 0.5 for line in text.split('\n'): if "INTENT:" in line: intent = line.split("INTENT:")[-1].strip().lower() intent = intent.strip('"\'') elif "CONFIDENCE:" in line: try: confidence = float(line.split("CONFIDENCE:")[-1].strip()) except: confidence = 0.5 # Validate intent valid_intents = ["lead", "support", "general", "unknown"] if intent not in valid_intents: intent = "unknown" return intent, confidence except Exception as e: print(f"Error in Gemini detection: {e}") return self._detect_with_patterns(user_message) def _detect_with_patterns(self, user_message: str) -> Tuple[str, float]: """Fallback pattern-based detection.""" message_lower = user_message.lower() lead_score = sum(1 for kw in self.lead_keywords if kw in message_lower) support_score = sum(1 for kw in self.support_keywords if kw in message_lower) general_score = sum(1 for kw in self.general_keywords if kw in message_lower) scores = { "lead": lead_score, "support": support_score, "general": general_score } max_score = max(scores.values()) if max_score == 0: return "unknown", 0.3 intent = max(scores, key=scores.get) confidence = min(max_score / 3, 1.0) return intent, confidence def extract_email(self, text: str) -> str: """Extract email from text.""" pattern = r'([a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,})' match = re.search(pattern, text) return match.group(1) if match else None def extract_name(self, text: str) -> str: """Extract user name from text (simple heuristic).""" patterns = [ r"my name is (\w+)", r"i'm (\w+)", r"i am (\w+)", r"call me (\w+)" ] text_lower = text.lower() for pattern in patterns: match = re.search(pattern, text_lower) if match: return match.group(1).capitalize() return None