""" CRM (Customer Relationship Management) System Müşteri tanıma, segmentasyon ve kişiselleştirilmiş yanıtlar """ import json import os from datetime import datetime, timedelta from typing import Dict, List, Optional, Tuple import re class CustomerManager: def __init__(self, db_path: str = "customers.json"): self.db_path = db_path self.customers = self._load_database() def _load_database(self) -> Dict: """Müşteri veritabanını yükle""" if os.path.exists(self.db_path): try: with open(self.db_path, 'r', encoding='utf-8') as f: return json.load(f) except: return {} return {} def _save_database(self): """Veritabanını kaydet""" with open(self.db_path, 'w', encoding='utf-8') as f: json.dump(self.customers, f, ensure_ascii=False, indent=2) def _extract_name_from_message(self, message: str) -> Optional[str]: """Mesajdan isim çıkarmaya çalış""" # "Ben Ahmet", "Benim adım Mehmet", "Merhaba ben Ali" gibi kalıplar patterns = [ r"ben[im]?\s+ad[ıi]m?\s+(\w+)", r"ben\s+(\w+)", r"ad[ıi]m\s+(\w+)", r"(\w+)\s+diye", ] message_lower = message.lower() for pattern in patterns: match = re.search(pattern, message_lower) if match: name = match.group(1) # İlk harfi büyük yap return name.capitalize() return None def _detect_interests(self, message: str) -> List[str]: """Mesajdan ilgi alanlarını çıkar""" interests = [] message_lower = message.lower() # Bisiklet kategorileri if any(word in message_lower for word in ["dağ", "mountain", "mtb"]): interests.append("mountain_bike") if any(word in message_lower for word in ["yol", "road", "yarış"]): interests.append("road_bike") if any(word in message_lower for word in ["şehir", "city", "urban"]): interests.append("city_bike") # Marka ve modeller if "trek" in message_lower: interests.append("trek") if "marlin" in message_lower: interests.append("marlin_series") if "fx" in message_lower: interests.append("fx_series") if "domane" in message_lower: interests.append("domane_series") if "madone" in message_lower: interests.append("madone_series") # Özellikler if any(word in message_lower for word in ["elektrik", "e-bike", "ebike"]): interests.append("e_bike") if any(word in message_lower for word in ["karbon", "carbon"]): interests.append("carbon") if any(word in message_lower for word in ["kadın", "women", "wsd"]): interests.append("women_specific") # Bütçe if any(word in message_lower for word in ["ucuz", "uygun fiyat", "ekonomik"]): interests.append("budget_friendly") if any(word in message_lower for word in ["premium", "high-end", "üst segment"]): interests.append("premium") return interests def _calculate_segment(self, customer: Dict) -> str: """Müşteri segmentini hesapla""" total_purchases = len(customer.get("purchases", [])) total_spent = sum(p.get("price", 0) for p in customer.get("purchases", [])) total_queries = customer.get("total_queries", 0) # Son aktivite kontrolü last_interaction = datetime.fromisoformat(customer.get("last_interaction", datetime.now().isoformat())) days_since_last = (datetime.now() - last_interaction).days # VIP kriterler if total_purchases >= 3 or total_spent >= 50000: return "VIP" # Potansiyel müşteri if total_queries >= 5 and total_purchases == 0: return "Potansiyel" # Kayıp riski if days_since_last > 30 and total_purchases > 0: return "Kayıp Riski" # Yeni müşteri (ilk 7 gün) first_seen = datetime.fromisoformat(customer.get("first_seen", datetime.now().isoformat())) if (datetime.now() - first_seen).days <= 7: return "Yeni" # Aktif müşteri if days_since_last <= 7: return "Aktif" # Standart return "Standart" def get_or_create_customer(self, phone: str, name: Optional[str] = None) -> Dict: """Müşteriyi getir veya yeni oluştur""" if phone in self.customers: # Var olan müşteri customer = self.customers[phone] customer["last_interaction"] = datetime.now().isoformat() # İsim güncellemesi if name and not customer.get("name"): customer["name"] = name # Segment güncelle customer["segment"] = self._calculate_segment(customer) else: # Yeni müşteri customer = { "phone": phone, "name": name, "first_seen": datetime.now().isoformat(), "last_interaction": datetime.now().isoformat(), "total_queries": 0, "purchases": [], "interests": [], "searched_products": [], "segment": "Yeni", "notes": [], "preferred_contact_time": None # "morning", "afternoon", "evening" } self.customers[phone] = customer self._save_database() return customer def update_interaction(self, phone: str, message: str, product_searched: Optional[str] = None) -> Dict: """Müşteri etkileşimini güncelle""" customer = self.get_or_create_customer(phone) # Sorgu sayısını artır customer["total_queries"] = customer.get("total_queries", 0) + 1 # İsim çıkarma denemesi if not customer.get("name"): extracted_name = self._extract_name_from_message(message) if extracted_name: customer["name"] = extracted_name # İlgi alanlarını güncelle new_interests = self._detect_interests(message) existing_interests = set(customer.get("interests", [])) customer["interests"] = list(existing_interests.union(set(new_interests))) # Aranan ürünü kaydet if product_searched: searched_products = customer.get("searched_products", []) # Son 10 aramayı tut searched_products.append({ "product": product_searched, "date": datetime.now().isoformat() }) customer["searched_products"] = searched_products[-10:] # İletişim zamanı tercihi hour = datetime.now().hour if 6 <= hour < 12: time_pref = "morning" elif 12 <= hour < 18: time_pref = "afternoon" else: time_pref = "evening" # En çok hangi zaman diliminde yazıyor if not customer.get("preferred_contact_time"): customer["preferred_contact_time"] = time_pref # Segment güncelle customer["segment"] = self._calculate_segment(customer) # Son etkileşim zamanı customer["last_interaction"] = datetime.now().isoformat() self._save_database() return customer def add_purchase(self, phone: str, product: str, price: float) -> Dict: """Satın alma kaydı ekle""" customer = self.get_or_create_customer(phone) purchase = { "product": product, "price": price, "date": datetime.now().isoformat() } customer.setdefault("purchases", []).append(purchase) customer["segment"] = self._calculate_segment(customer) self._save_database() return customer def get_customer_context(self, phone: str) -> Dict: """Müşteri bağlamını getir""" customer = self.customers.get(phone, {}) if not customer: return { "is_new": True, "greeting": "Merhaba! Trek bisikletleri hakkında size nasıl yardımcı olabilirim?" } context = { "is_new": False, "name": customer.get("name"), "segment": customer.get("segment", "Standart"), "total_queries": customer.get("total_queries", 0), "interests": customer.get("interests", []), "last_product": None, "days_since_last": 0, "greeting": "" } # Son aranan ürün searched_products = customer.get("searched_products", []) if searched_products: context["last_product"] = searched_products[-1]["product"] last_search_date = datetime.fromisoformat(searched_products[-1]["date"]) context["days_since_last"] = (datetime.now() - last_search_date).days # Kişiselleştirilmiş selamlama oluştur context["greeting"] = self._generate_greeting(customer, context) return context def _generate_greeting(self, customer: Dict, context: Dict) -> str: """Kişiselleştirilmiş selamlama oluştur""" segment = customer.get("segment", "Standart") name = customer.get("name", "") # Saat bazlı selamlama hour = datetime.now().hour if 6 <= hour < 12: time_greeting = "Günaydın" elif 12 <= hour < 18: time_greeting = "İyi günler" else: time_greeting = "İyi akşamlar" # Segment bazlı selamlama if segment == "VIP": if name: greeting = f"{time_greeting} {name} Bey/Hanım! Değerli müşterimiz olarak size özel VIP avantajlarımız mevcut." else: greeting = f"{time_greeting}! Değerli müşterimize özel VIP avantajlarımız mevcut." elif segment == "Yeni": greeting = f"{time_greeting}! Trek bisikletleri dünyasına hoş geldiniz! Size nasıl yardımcı olabilirim?" elif segment == "Potansiyel": if context.get("last_product"): greeting = f"{time_greeting}! Daha önce sorduğunuz {context['last_product']} veya başka bir konuda size yardımcı olabilir miyim?" else: greeting = f"{time_greeting}! Bisiklet arayışınızda size nasıl yardımcı olabilirim?" elif segment == "Kayıp Riski": if name: greeting = f"{time_greeting} {name} Bey/Hanım! Sizi özledik! Size özel geri dönüş kampanyamız var." else: greeting = f"{time_greeting}! Sizi tekrar aramızda görmek güzel! Size özel fırsatlarımız var." elif segment == "Aktif": if name: greeting = f"{time_greeting} {name} Bey/Hanım! Tekrar hoş geldiniz!" else: greeting = f"{time_greeting}! Tekrar hoş geldiniz!" # Son aranan ürün varsa ekle if context.get("last_product") and context.get("days_since_last", 99) <= 3: greeting += f" {context['last_product']} hakkında bilgi almak ister misiniz?" else: # Standart if name: greeting = f"{time_greeting} {name} Bey/Hanım! Size nasıl yardımcı olabilirim?" else: greeting = f"{time_greeting}! Size nasıl yardımcı olabilirim?" return greeting def get_analytics(self) -> Dict: """Analitik özet döndür""" total_customers = len(self.customers) segments = {} total_purchases = 0 total_revenue = 0 active_today = 0 today = datetime.now().date() for customer in self.customers.values(): # Segment dağılımı segment = customer.get("segment", "Standart") segments[segment] = segments.get(segment, 0) + 1 # Satış istatistikleri purchases = customer.get("purchases", []) total_purchases += len(purchases) total_revenue += sum(p.get("price", 0) for p in purchases) # Bugün aktif olanlar last_interaction = datetime.fromisoformat(customer.get("last_interaction", "2020-01-01")) if last_interaction.date() == today: active_today += 1 return { "total_customers": total_customers, "segments": segments, "total_purchases": total_purchases, "total_revenue": total_revenue, "active_today": active_today, "average_purchase_value": total_revenue / total_purchases if total_purchases > 0 else 0 } def get_customer_list(self, segment: Optional[str] = None) -> List[Dict]: """Müşteri listesini getir""" customers = [] for phone, customer in self.customers.items(): if segment and customer.get("segment") != segment: continue customers.append({ "phone": phone, "name": customer.get("name", "Bilinmiyor"), "segment": customer.get("segment", "Standart"), "total_queries": customer.get("total_queries", 0), "total_purchases": len(customer.get("purchases", [])), "last_interaction": customer.get("last_interaction"), "interests": customer.get("interests", []) }) # Son etkileşime göre sırala customers.sort(key=lambda x: x["last_interaction"], reverse=True) return customers def should_ask_for_name(self, phone: str, message: str) -> Tuple[bool, Optional[str]]: """İsim sorulmalı mı kontrol et""" customer = self.customers.get(phone, {}) # Zaten isim varsa sorma if customer.get("name"): return False, None queries = customer.get("total_queries", 0) message_lower = message.lower() # 1. Rezervasyon/satın alma anında (EN DOĞAL) reservation_keywords = ["rezerv", "ayırt", "satın al", "alabilir miyim", "almak istiyorum", "sipariş", "kargola", "gönder", "paket", "teslimat"] if any(keyword in message_lower for keyword in reservation_keywords): return True, "📝 Rezervasyon için adınızı alabilir miyim?" # 2. Mağaza ziyareti planı store_visit_keywords = ["mağazaya gel", "mağazaya uğra", "görmeye gel", "bakmaya gel", "test sürüşü", "denemek istiyorum"] if any(keyword in message_lower for keyword in store_visit_keywords): return True, "🏪 Mağazada size daha iyi yardımcı olabilmemiz için adınızı öğrenebilir miyim?" # 3. Telefon görüşmesi talebi phone_keywords = ["ara", "telefon", "görüş", "konuş", "iletişim"] if any(keyword in message_lower for keyword in phone_keywords): return True, "📞 Sizi arayabilmemiz için adınızı paylaşır mısınız?" # 4. Fiyat/ödeme görüşmesi (ciddi alıcı) payment_keywords = ["taksit", "ödeme", "kredi kartı", "havale", "eft", "nakit", "peşin"] if any(keyword in message_lower for keyword in payment_keywords): return True, "💳 Size özel ödeme seçenekleri sunabilmem için adınızı öğrenebilir miyim?" # 5. 3. mesajda nazikçe sor (sadece ürün sorguluyorsa) if queries == 2: # 3. mesaj (0'dan başlıyor) # Sadece basit selamlaşma değilse greeting_only = ["merhaba", "selam", "günaydın", "iyi günler", "hey", "sa"] if not any(message_lower.strip() == greeting for greeting in greeting_only): return True, "Bu arada, size daha iyi hizmet verebilmem için adınızı öğrenebilir miyim? 😊" # 6. 5+ sorgudan sonra hala isim yoksa (potansiyel müşteri) if queries >= 5: return True, "✨ Sizin için özel tekliflerimiz olabilir. Adınızı paylaşır mısınız?" return False, None def extract_name_from_response(self, message: str) -> Optional[str]: """İsim sorulduktan sonra gelen yanıttan isim çıkar""" message_lower = message.lower().strip() # Direkt isim yanıtları if len(message_lower.split()) == 1: # Yaygın olmayan tek kelime yanıtları filtrele common_words = ["evet", "hayır", "tamam", "olur", "peki", "teşekkür", "teşekkürler", "merhaba", "selam", "günaydın", "güle", "hoşçakal", "görüşürüz", "sa", "as", "slm", "mrb", "ok", "okay", "yes", "no", "hi", "hello", "bye"] if message_lower not in common_words: # Tek kelime, muhtemelen isim name = message.capitalize() # Türkçe isim kontrolü (en az 2 karakter) if len(name) >= 2 and name.isalpha(): return name # "Benim adım X", "Ben X", "Adım X" kalıpları patterns = [ r"(?:benim\s+)?ad[ıi]m?\s+(\w+)", r"ben\s+(\w+)", r"(\w+)\s+diye\s+hitap", r"bana\s+(\w+)\s+diyebilirsiniz", r"ismim\s+(\w+)", r"(\w+),?\s*teşekkür", # "Ahmet, teşekkürler" ] for pattern in patterns: import re match = re.search(pattern, message_lower) if match: name = match.group(1).capitalize() if len(name) >= 2: return name # İsim + Soyisim durumu (sadece ismi al) two_words = message.strip().split() if len(two_words) == 2: # Her ikisi de büyük harfle başlıyorsa if two_words[0][0].isupper() and two_words[1][0].isupper(): return two_words[0] return None