File size: 15,881 Bytes
c85b2c2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
# -*- 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)