| import os |
| import re |
| import warnings |
| from typing import Dict, Tuple |
|
|
| |
| 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 |
| |
| |
| 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() |
| |
| |
| 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 |
| |
| |
| 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 |
|
|