BF-WAB / whatsapp_passive_profiler.py
SamiKoen's picture
Upload 3 files
c85b2c2 verified
raw
history blame
15.9 kB
# -*- coding: utf-8 -*-
"""
WhatsApp Pasif Profil Sistemi
Kullanıcıya soru sormadan sohbet analizi ile profil oluşturur
"""
import re
import json
import os
from datetime import datetime, timedelta
from typing import Dict, List, Optional, Any
class WhatsAppPassiveProfiler:
"""Sohbet analizi ile kullanıcı profili çıkarır"""
def __init__(self):
self.profiles_file = "user_profiles.json"
self.profiles = self.load_profiles()
# Bütçe ifadeleri
self.budget_patterns = [
r'bütçem?\s*(\d+)[\s-]*(\d+)?\s*k?\s*(bin|bin tl|tl)?',
r'(\d+)[\s-]*(\d+)?\s*k?\s*(bin|bin tl|tl)?\s*bütçe',
r'(\d+)[\s-]*(\d+)?\s*k?\s*(bin|bin tl|tl)?\s*arasında',
r'maksimum\s*(\d+)\s*k?\s*(bin|bin tl|tl)?',
r'en fazla\s*(\d+)\s*k?\s*(bin|bin tl|tl)?'
]
# Kategori tercihleri
self.category_keywords = {
"dağ_bisikleti": ["dağ", "dag", "offroad", "patika", "doğa", "orman", "marlin", "fuel", "procaliber"],
"yol_bisikleti": ["yol", "asfalt", "hız", "yarış", "triathlon", "émonda", "madone", "domane"],
"şehir_bisikleti": ["şehir", "kent", "günlük", "işe gidip gelme", "fx", "ds", "verve"],
"elektrikli": ["elektrikli", "electric", "e-bike", "ebike", "batarya", "powerfly", "rail"],
"gravel": ["gravel", "çakıl", "macera", "touring", "checkpoint"]
}
# Kullanım amaçları
self.usage_patterns = {
"spor": ["spor", "antrenman", "kondisyon", "fitness", "egzersiz", "yarış"],
"günlük": ["işe gitmek", "günlük", "şehir içi", "ulaşım", "market", "alışveriş"],
"hobi": ["hobi", "eğlence", "gezinti", "keyif", "hafta sonu", "macera"],
"profesyonel": ["profesyonel", "yarış", "müsabaka", "antrenör", "ciddi"]
}
# Boy/beden işaretçileri
self.size_patterns = {
"boy": r'boyum\s*(\d+)\s*cm?|(\d+)\s*cm?\s*boy',
"kilo": r'kilom\s*(\d+)\s*kg?|(\d+)\s*kg?\s*kilo',
"beden": r'beden[im]?\s*([xsl]+)|([xsl]+)\s*beden'
}
def load_profiles(self) -> Dict:
"""Mevcut profilleri yükle"""
if os.path.exists(self.profiles_file):
try:
with open(self.profiles_file, 'r', encoding='utf-8') as f:
return json.load(f)
except Exception as e:
print(f"Profil yükleme hatası: {e}")
return {}
def save_profiles(self):
"""Profilleri kaydet"""
try:
with open(self.profiles_file, 'w', encoding='utf-8') as f:
json.dump(self.profiles, f, ensure_ascii=False, indent=2, default=str)
except Exception as e:
print(f"Profil kaydetme hatası: {e}")
def get_or_create_profile(self, phone_number: str) -> Dict:
"""Profil getir veya oluştur"""
if phone_number not in self.profiles:
self.profiles[phone_number] = {
"created_at": datetime.now(),
"last_updated": datetime.now(),
"total_messages": 0,
"preferences": {
"budget_min": None,
"budget_max": None,
"categories": [], # İlgilendiği kategoriler
"usage_purpose": [], # Kullanım amaçları
"size_info": {}, # Boy, kilo, beden bilgileri
"brand_preferences": [], # Marka tercihleri
"color_preferences": [] # Renk tercihleri
},
"behavior": {
"price_sensitive": False, # Fiyata duyarlı mı
"tech_interested": False, # Teknik detaylarla ilgilenir mi
"comparison_lover": False, # Karşılaştırma sever mi
"quick_decider": False, # Hızlı karar verir mi
"research_oriented": False # Araştırmacı mı
},
"interests": {
"viewed_products": [], # Baktığı ürünler
"compared_products": [], # Karşılaştırdığı ürünler
"favorite_features": [], # İlgilendiği özellikler
"mentioned_brands": [] # Bahsettiği markalar
},
"statistics": {
"comparison_requests": 0,
"budget_queries": 0,
"technical_questions": 0,
"price_questions": 0,
"availability_questions": 0
}
}
return self.profiles[phone_number]
def analyze_message(self, phone_number: str, message: str) -> Dict:
"""Mesajı analiz et ve profili güncelle"""
profile = self.get_or_create_profile(phone_number)
message_lower = message.lower()
# Mesaj sayısını artır
profile["total_messages"] += 1
profile["last_updated"] = datetime.now()
analysis_results = {
"budget_detected": False,
"category_detected": False,
"usage_detected": False,
"size_detected": False,
"behavior_indicators": []
}
# Bütçe analizi
budget_info = self.extract_budget(message_lower)
if budget_info:
profile["preferences"]["budget_min"] = budget_info["min"]
profile["preferences"]["budget_max"] = budget_info["max"]
profile["statistics"]["budget_queries"] += 1
analysis_results["budget_detected"] = True
# Kategori tercihi analizi
detected_categories = self.detect_categories(message_lower)
if detected_categories:
for category in detected_categories:
if category not in profile["preferences"]["categories"]:
profile["preferences"]["categories"].append(category)
analysis_results["category_detected"] = True
# Kullanım amacı analizi
usage_purposes = self.detect_usage_purpose(message_lower)
if usage_purposes:
for purpose in usage_purposes:
if purpose not in profile["preferences"]["usage_purpose"]:
profile["preferences"]["usage_purpose"].append(purpose)
analysis_results["usage_detected"] = True
# Boy/beden bilgisi analizi
size_info = self.extract_size_info(message_lower)
if size_info:
profile["preferences"]["size_info"].update(size_info)
analysis_results["size_detected"] = True
# Davranış analizi
behavior_indicators = self.analyze_behavior(message_lower)
for behavior, detected in behavior_indicators.items():
if detected:
profile["behavior"][behavior] = True
analysis_results["behavior_indicators"].append(behavior)
# İstatistik güncelleme
self.update_statistics(profile, message_lower)
# Profili kaydet
self.save_profiles()
return analysis_results
def extract_budget(self, message: str) -> Optional[Dict]:
"""Bütçe bilgisini çıkar"""
for pattern in self.budget_patterns:
match = re.search(pattern, message)
if match:
numbers = [g for g in match.groups() if g and g.isdigit()]
if numbers:
if len(numbers) == 1:
# Tek sayı - maksimum bütçe
budget = int(numbers[0])
if budget < 1000: # K formatında (50k = 50000)
budget *= 1000
return {"min": int(budget * 0.7), "max": budget}
elif len(numbers) >= 2:
# Aralık - min ve max
min_budget = int(numbers[0])
max_budget = int(numbers[1])
if min_budget < 1000:
min_budget *= 1000
if max_budget < 1000:
max_budget *= 1000
return {"min": min_budget, "max": max_budget}
return None
def detect_categories(self, message: str) -> List[str]:
"""Kategori tercihlerini tespit et"""
detected = []
for category, keywords in self.category_keywords.items():
if any(keyword in message for keyword in keywords):
detected.append(category)
return detected
def detect_usage_purpose(self, message: str) -> List[str]:
"""Kullanım amacını tespit et"""
detected = []
for purpose, keywords in self.usage_patterns.items():
if any(keyword in message for keyword in keywords):
detected.append(purpose)
return detected
def extract_size_info(self, message: str) -> Dict:
"""Boy/beden bilgisini çıkar"""
size_info = {}
# Boy bilgisi
boy_match = re.search(self.size_patterns["boy"], message)
if boy_match:
boy = boy_match.group(1) or boy_match.group(2)
if boy:
size_info["height"] = int(boy)
# Kilo bilgisi
kilo_match = re.search(self.size_patterns["kilo"], message)
if kilo_match:
kilo = kilo_match.group(1) or kilo_match.group(2)
if kilo:
size_info["weight"] = int(kilo)
# Beden bilgisi
beden_match = re.search(self.size_patterns["beden"], message)
if beden_match:
beden = beden_match.group(1) or beden_match.group(2)
if beden:
size_info["size"] = beden.upper()
return size_info
def analyze_behavior(self, message: str) -> Dict[str, bool]:
"""Davranış kalıplarını analiz et"""
behavior = {}
# Fiyata duyarlılık
price_keywords = ["ucuz", "fiyat", "indirim", "kampanya", "ekonomik", "bütçe"]
behavior["price_sensitive"] = any(keyword in message for keyword in price_keywords)
# Teknik ilgi
tech_keywords = ["teknik", "özellik", "ağırlık", "malzeme", "karbon", "alüminyum", "vites"]
behavior["tech_interested"] = any(keyword in message for keyword in tech_keywords)
# Karşılaştırma sevgisi
comparison_keywords = ["karşılaştır", "fark", "hangisi", "arası", "seçim"]
behavior["comparison_lover"] = any(keyword in message for keyword in comparison_keywords)
# Araştırmacı yapı
research_keywords = ["detay", "bilgi", "araştır", "inceleme", "test", "deneyim"]
behavior["research_oriented"] = any(keyword in message for keyword in research_keywords)
return behavior
def update_statistics(self, profile: Dict, message: str):
"""İstatistikleri güncelle"""
if "karşılaştır" in message:
profile["statistics"]["comparison_requests"] += 1
if any(word in message for word in ["fiyat", "kaç para", "ne kadar"]):
profile["statistics"]["price_questions"] += 1
if any(word in message for word in ["stok", "var mı", "mevcut"]):
profile["statistics"]["availability_questions"] += 1
if any(word in message for word in ["teknik", "özellik", "detay"]):
profile["statistics"]["technical_questions"] += 1
def get_profile_summary(self, phone_number: str) -> Dict:
"""Profil özetini döndür"""
if phone_number not in self.profiles:
return {"exists": False}
profile = self.profiles[phone_number]
# Profil güvenilirlik skoru (mesaj sayısına göre)
confidence = min(profile["total_messages"] / 10.0, 1.0) # 10 mesajda %100
summary = {
"exists": True,
"confidence": confidence,
"total_messages": profile["total_messages"],
"preferences": profile["preferences"],
"behavior": profile["behavior"],
"top_categories": profile["preferences"]["categories"][:3],
"is_budget_defined": profile["preferences"]["budget_min"] is not None,
"is_tech_savvy": profile["behavior"]["tech_interested"],
"is_price_conscious": profile["behavior"]["price_sensitive"],
"interaction_style": self.get_interaction_style(profile)
}
return summary
def get_interaction_style(self, profile: Dict) -> str:
"""Etkileşim stilini belirle"""
stats = profile["statistics"]
behavior = profile["behavior"]
if stats["comparison_requests"] > 2 and behavior["research_oriented"]:
return "analytical" # Analitik - detaylı bilgi sever
elif behavior["price_sensitive"] and stats["budget_queries"] > 0:
return "budget_conscious" # Bütçe odaklı
elif behavior["tech_interested"] and stats["technical_questions"] > 1:
return "technical" # Teknik odaklı
elif stats["comparison_requests"] == 0 and profile["total_messages"] < 5:
return "decisive" # Hızlı karar verici
else:
return "balanced" # Dengeli
def get_personalized_suggestions(self, phone_number: str, products_data: List) -> Dict:
"""Kişiselleştirilmiş öneriler"""
profile_summary = self.get_profile_summary(phone_number)
if not profile_summary["exists"] or profile_summary["confidence"] < 0.3:
return {"personalized": False, "reason": "insufficient_data"}
suggestions = {
"personalized": True,
"user_style": profile_summary["interaction_style"],
"budget_aware": profile_summary["is_budget_defined"],
"recommendations": []
}
# Bütçe filtresi
filtered_products = products_data
if profile_summary["preferences"]["budget_min"]:
budget_min = profile_summary["preferences"]["budget_min"]
budget_max = profile_summary["preferences"]["budget_max"]
filtered_products = [
p for p in products_data
if p[1][0] == "stokta" and p[1][1] and
budget_min <= float(p[1][1]) <= budget_max
]
# Kategori filtresi
if profile_summary["top_categories"]:
category_products = []
for category in profile_summary["top_categories"]:
category_products.extend([
p for p in filtered_products
if any(keyword in p[2].lower() for keyword in self.category_keywords.get(category, []))
])
if category_products:
filtered_products = category_products
suggestions["recommendations"] = filtered_products[:5]
return suggestions
# Global instance
passive_profiler = WhatsAppPassiveProfiler()
def analyze_user_message(phone_number: str, message: str) -> Dict:
"""Kullanıcı mesajını analiz et ve profili güncelle"""
return passive_profiler.analyze_message(phone_number, message)
def get_user_profile_summary(phone_number: str) -> Dict:
"""Kullanıcı profil özetini getir"""
return passive_profiler.get_profile_summary(phone_number)
def get_personalized_recommendations(phone_number: str, products_data: List) -> Dict:
"""Kişiselleştirilmiş öneriler getir"""
return passive_profiler.get_personalized_suggestions(phone_number, products_data)