BF-WAB / whatsapp_improved_chatbot.py
SamiKoen's picture
Upload 3 files
cba1186 verified
raw
history blame
12.4 kB
"""
WhatsApp Improved Chatbot with Professional Product Search
Optimized for mobile WhatsApp formatting
"""
from product_search import ProductSearchEngine
import re
from typing import List, Dict, Optional, Tuple
class WhatsAppImprovedChatbot:
"""Enhanced chatbot with intelligent product handling for WhatsApp"""
def __init__(self, products: List[Tuple]):
"""Initialize with product list"""
self.search_engine = ProductSearchEngine(products)
self.products = products
def detect_product_query(self, message: str) -> bool:
"""Detect if message is asking about products"""
product_keywords = [
'bisiklet', 'bike', 'model', 'fiyat', 'price', 'stok', 'stock',
'özellikleri', 'features', 'hangi', 'which', 'var mı', 'mevcut',
'kaç', 'how much', 'ne kadar', 'kampanya', 'indirim', 'discount',
'karşılaştır', 'compare', 'benzer', 'similar', 'alternatif',
'öneri', 'recommend', 'tavsiye', 'suggest'
]
message_lower = message.lower()
# Check for product keywords
if any(keyword in message_lower for keyword in product_keywords):
return True
# Check for model numbers
if re.search(r'\b\d+\.?\d*\b', message):
return True
# Check for known product categories
categories = ['trek', 'marlin', 'fuel', 'slash', 'remedy', 'checkpoint',
'domane', 'madone', 'emonda', 'fx', 'dual', 'wahoo', 'powerfly']
if any(cat in message_lower for cat in categories):
return True
return False
def extract_query_intent(self, message: str) -> Dict:
"""Extract the intent from user query"""
intent = {
'type': 'general',
'action': None,
'filters': {}
}
message_lower = message.lower()
# Price query
if any(word in message_lower for word in ['fiyat', 'price', 'kaç', 'ne kadar', 'how much']):
intent['type'] = 'price'
intent['action'] = 'get_price'
# Stock query
elif any(word in message_lower for word in ['stok', 'stock', 'var mı', 'mevcut', 'available']):
intent['type'] = 'stock'
intent['action'] = 'check_stock'
# Comparison query
elif any(word in message_lower for word in ['karşılaştır', 'compare', 'fark', 'difference']):
intent['type'] = 'comparison'
intent['action'] = 'compare_products'
# Recommendation query
elif any(word in message_lower for word in ['öneri', 'recommend', 'tavsiye', 'suggest', 'hangi']):
intent['type'] = 'recommendation'
intent['action'] = 'recommend'
# Feature query
elif any(word in message_lower for word in ['özellik', 'feature', 'spec', 'detay', 'detail']):
intent['type'] = 'features'
intent['action'] = 'get_features'
# Extract context (size, color, type, etc.)
context = self.search_engine.extract_product_context(message)
intent['filters'] = context
return intent
def format_product_info_whatsapp(self, product: Tuple, intent: Dict) -> str:
"""Format product information for WhatsApp"""
name = product[2] # Full name
info = product[1] # Product info array
# Basic info
stock_status = info[0] if len(info) > 0 else "bilinmiyor"
# Build response for WhatsApp (more compact format)
response_parts = []
# Product name with status emoji
if stock_status == "stokta":
response_parts.append(f"🚴‍♂️ *{name}*")
response_parts.append("✅ *Stokta mevcut*")
else:
response_parts.append(f"🚴‍♂️ *{name}*")
response_parts.append("❌ *Stokta yok*")
# Price information (only if in stock)
if intent['type'] in ['price', 'general'] and stock_status == "stokta" and len(info) > 1:
price = info[1]
response_parts.append(f"💰 *Fiyat:* {price} TL")
# Campaign price if available
if len(info) > 4 and info[4]:
response_parts.append(f"🎯 *Kampanya:* {info[4]} TL")
# Calculate discount
try:
normal_price = float(info[1])
campaign_price = float(info[4])
discount = normal_price - campaign_price
if discount > 0:
response_parts.append(f"💸 *İndirim:* {discount:.0f} TL")
except:
pass
# Wire transfer price if no campaign
elif len(info) > 3 and info[3]:
response_parts.append(f"🏦 *Havale:* {info[3]} TL")
# Product link (shortened for WhatsApp)
if len(info) > 2 and info[2]:
response_parts.append(f"🔗 Ürün sayfası: {info[2]}")
return "\n".join(response_parts)
def generate_product_response(self, message: str) -> str:
"""Generate response for product queries optimized for WhatsApp"""
intent = self.extract_query_intent(message)
# Search for products
search_results = self.search_engine.search(message)
if not search_results:
# No products found - provide helpful response
response = self._handle_no_results_whatsapp(message)
elif len(search_results) == 1:
# Single product found
product = search_results[0][1]
response = self.format_product_info_whatsapp(product, intent)
elif search_results[0][0] > 0.9:
# Very high confidence match
product = search_results[0][1]
response = self.format_product_info_whatsapp(product, intent)
else:
# Multiple products found
response = self._handle_multiple_results_whatsapp(search_results[:3], intent) # Only 3 for WhatsApp
return response
def _handle_no_results_whatsapp(self, query: str) -> str:
"""Handle case when no products are found - WhatsApp format"""
response_parts = ["🤔 *Aradığınız ürünü bulamadım.*"]
# Get suggestions
suggestions = self.search_engine.generate_suggestions(query)
if suggestions:
response_parts.append("\n💡 *Belki şunları arıyor olabilirsiniz:*")
for i, suggestion in enumerate(suggestions[:2], 1): # Only 2 suggestions for WhatsApp
response_parts.append(f"{i}. {suggestion}")
else:
response_parts.append("\n📝 *Örnek aramalar:*")
response_parts.append("• Marlin 5")
response_parts.append("• FX 3 Disc")
response_parts.append("• Checkpoint ALR 5")
return "\n".join(response_parts)
def _handle_multiple_results_whatsapp(self, results: List[Tuple[float, Tuple]], intent: Dict) -> str:
"""Handle multiple product results - WhatsApp format"""
response_parts = ["📋 *Birden fazla ürün buldum:*\n"]
for i, (score, product) in enumerate(results, 1):
name = product[2]
stock = product[1][0] if len(product[1]) > 0 else "bilinmiyor"
# Compact info line for WhatsApp
if stock == "stokta":
status_emoji = "✅"
response_parts.append(f"*{i}. {name}* {status_emoji}")
# Add price if intent is price-related
if intent['type'] in ['price', 'general'] and len(product[1]) > 1:
price = product[1][1]
response_parts.append(f" 💰 {price} TL")
# Show campaign price if available
if len(product[1]) > 4 and product[1][4]:
response_parts.append(f" 🎯 Kampanya: {product[1][4]} TL")
# Add product link if available
if len(product[1]) > 2 and product[1][2]:
response_parts.append(f" 🔗 {product[1][2]}")
else:
status_emoji = "❌"
response_parts.append(f"*{i}. {name}* {status_emoji}")
response_parts.append("") # Empty line between products
response_parts.append("💡 _Daha detaylı bilgi için ürün adını yazın_")
return "\n".join(response_parts)
def handle_comparison_whatsapp(self, message: str) -> Optional[str]:
"""Handle product comparison requests - WhatsApp format"""
# Extract product names for comparison
comparison_words = ['ile', 've', 'vs', 'versus', 'karşılaştır', 'arasında']
products_to_compare = []
# Try to extract two product names
for word in comparison_words:
if word in message.lower():
parts = message.lower().split(word)
if len(parts) >= 2:
# Search for each part
for part in parts[:2]:
result = self.search_engine.find_best_match(part.strip())
if result:
products_to_compare.append(result)
if len(products_to_compare) < 2:
# Try to find products mentioned in the message
search_results = self.search_engine.search(message)
products_to_compare = [r[1] for r in search_results[:2] if r[0] > 0.6]
if len(products_to_compare) >= 2:
return self._format_comparison_whatsapp(products_to_compare[:2])
return None
def _format_comparison_whatsapp(self, products: List[Tuple]) -> str:
"""Format product comparison for WhatsApp"""
response_parts = ["📊 *Ürün Karşılaştırması*\n"]
for i, product in enumerate(products, 1):
name = product[2]
info = product[1]
response_parts.append(f"*{i}. {name}*")
# Stock status
stock = info[0] if len(info) > 0 else "bilinmiyor"
if stock == "stokta":
response_parts.append("✅ Stokta mevcut")
else:
response_parts.append("❌ Stokta yok")
# Price (compact for WhatsApp)
if stock == "stokta" and len(info) > 1:
price = info[1]
response_parts.append(f"💰 {price} TL")
if len(info) > 4 and info[4]:
response_parts.append(f"🎯 Kampanya: {info[4]} TL")
response_parts.append("") # Empty line
return "\n".join(response_parts)
def process_message(self, message: str) -> Dict:
"""Process user message and return structured response optimized for WhatsApp"""
result = {
'is_product_query': False,
'response': None,
'products_found': [],
'intent': None
}
# Check if it's a product query
if self.detect_product_query(message):
result['is_product_query'] = True
result['intent'] = self.extract_query_intent(message)
# Check for comparison request
if result['intent']['type'] == 'comparison':
comparison_result = self.handle_comparison_whatsapp(message)
if comparison_result:
result['response'] = comparison_result
return result
# Generate product response
result['response'] = self.generate_product_response(message)
# Get found products
search_results = self.search_engine.search(message)
result['products_found'] = [r[1] for r in search_results[:2] if r[0] > 0.6] # Limit to 2 for WhatsApp
return result