customer-support-chatbot / backend /intent_detector.py
Hamza4100's picture
Update backend/intent_detector.py
7522cc8 verified
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