SamiKoen commited on
Commit
c85b2c2
·
verified ·
1 Parent(s): 8ad7963

Upload 3 files

Browse files
Files changed (3) hide show
  1. app.py +121 -1
  2. user_profiles.json +76 -0
  3. whatsapp_passive_profiler.py +368 -0
app.py CHANGED
@@ -14,6 +14,9 @@ from whatsapp_features import (
14
  handle_whatsapp_budget_request, handle_whatsapp_category_request
15
  )
16
  from whatsapp_renderer import extract_product_info_whatsapp
 
 
 
17
 
18
  # LOGGING EN BAŞA EKLENDİ
19
  import logging
@@ -329,6 +332,19 @@ def build_context_messages(phone_number, current_message):
329
  def process_whatsapp_message_with_memory(user_message, phone_number):
330
  """Hafızalı WhatsApp mesaj işleme"""
331
  try:
 
 
 
 
 
 
 
 
 
 
 
 
 
332
  # Enhanced features kontrolü - önce bunları kontrol et
333
  comparison_result = handle_whatsapp_comparison_request(user_message)
334
  if comparison_result:
@@ -345,6 +361,12 @@ def process_whatsapp_message_with_memory(user_message, phone_number):
345
  # Sohbet geçmişi ile sistem mesajlarını oluştur
346
  messages = build_context_messages(phone_number, user_message)
347
 
 
 
 
 
 
 
348
  # Ürün bilgilerini kontrol et ve ekle
349
  input_words = user_message.lower().split()
350
  for product_info in products:
@@ -366,7 +388,7 @@ def process_whatsapp_message_with_memory(user_message, phone_number):
366
  return "OpenAI API anahtarı eksik. Lütfen environment variables'ları kontrol edin."
367
 
368
  payload = {
369
- "model": "gpt-4.1",
370
  "messages": messages,
371
  "temperature": 0.3,
372
  "max_tokens": 800,
@@ -398,6 +420,87 @@ def process_whatsapp_message_with_memory(user_message, phone_number):
398
  print(f"❌ WhatsApp mesaj işleme hatası: {e}")
399
  return "Teknik bir sorun oluştu. Lütfen daha sonra tekrar deneyin."
400
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
401
  def split_long_message(message, max_length=1600):
402
  """Uzun mesajları WhatsApp için uygun parçalara böler"""
403
  if len(message) <= max_length:
@@ -588,6 +691,23 @@ async def debug_memory():
588
  }
589
  return {"conversation_memory": memory_info}
590
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
591
  @app.get("/health")
592
  async def health():
593
  return {
 
14
  handle_whatsapp_budget_request, handle_whatsapp_category_request
15
  )
16
  from whatsapp_renderer import extract_product_info_whatsapp
17
+ from whatsapp_passive_profiler import (
18
+ analyze_user_message, get_user_profile_summary, get_personalized_recommendations
19
+ )
20
 
21
  # LOGGING EN BAŞA EKLENDİ
22
  import logging
 
332
  def process_whatsapp_message_with_memory(user_message, phone_number):
333
  """Hafızalı WhatsApp mesaj işleme"""
334
  try:
335
+ # 🧠 Pasif profil analizi - kullanıcı mesajını analiz et
336
+ profile_analysis = analyze_user_message(phone_number, user_message)
337
+ logger.info(f"📊 Profil analizi: {phone_number} -> {profile_analysis}")
338
+
339
+ # 🎯 Kişiselleştirilmiş öneriler kontrolü
340
+ if any(keyword in user_message.lower() for keyword in ["öneri", "öner", "tavsiye", "ne önerirsin"]):
341
+ personalized = get_personalized_recommendations(phone_number, products)
342
+ if personalized.get("personalized") and personalized.get("recommendations"):
343
+ # Kullanıcı profiline göre özelleştirilmiş cevap hazırla
344
+ profile_summary = get_user_profile_summary(phone_number)
345
+ custom_response = create_personalized_response(personalized, profile_summary)
346
+ return extract_product_info_whatsapp(custom_response)
347
+
348
  # Enhanced features kontrolü - önce bunları kontrol et
349
  comparison_result = handle_whatsapp_comparison_request(user_message)
350
  if comparison_result:
 
361
  # Sohbet geçmişi ile sistem mesajlarını oluştur
362
  messages = build_context_messages(phone_number, user_message)
363
 
364
+ # 🎯 Profil bilgilerini sistem mesajlarına ekle
365
+ profile_summary = get_user_profile_summary(phone_number)
366
+ if profile_summary.get("exists") and profile_summary.get("confidence", 0) > 0.3:
367
+ profile_context = create_profile_context_message(profile_summary)
368
+ messages.append({"role": "system", "content": profile_context})
369
+
370
  # Ürün bilgilerini kontrol et ve ekle
371
  input_words = user_message.lower().split()
372
  for product_info in products:
 
388
  return "OpenAI API anahtarı eksik. Lütfen environment variables'ları kontrol edin."
389
 
390
  payload = {
391
+ "model": "gpt-4.5-preview",
392
  "messages": messages,
393
  "temperature": 0.3,
394
  "max_tokens": 800,
 
420
  print(f"❌ WhatsApp mesaj işleme hatası: {e}")
421
  return "Teknik bir sorun oluştu. Lütfen daha sonra tekrar deneyin."
422
 
423
+ def create_profile_context_message(profile_summary):
424
+ """Profil bilgilerini sistem mesajına çevir"""
425
+ context_parts = []
426
+
427
+ preferences = profile_summary.get("preferences", {})
428
+ behavior = profile_summary.get("behavior", {})
429
+
430
+ # Bütçe bilgisi
431
+ if preferences.get("budget_min") and preferences.get("budget_max"):
432
+ budget_min = preferences["budget_min"]
433
+ budget_max = preferences["budget_max"]
434
+ context_parts.append(f"Kullanıcının bütçesi: {budget_min:,}-{budget_max:,} TL")
435
+
436
+ # Kategori tercihleri
437
+ if preferences.get("categories"):
438
+ categories = ", ".join(preferences["categories"])
439
+ context_parts.append(f"İlgilendiği kategoriler: {categories}")
440
+
441
+ # Kullanım amacı
442
+ if preferences.get("usage_purpose"):
443
+ purposes = ", ".join(preferences["usage_purpose"])
444
+ context_parts.append(f"Kullanım amacı: {purposes}")
445
+
446
+ # Davranış kalıpları
447
+ if behavior.get("price_sensitive"):
448
+ context_parts.append("Fiyata duyarlı bir kullanıcı")
449
+ if behavior.get("tech_interested"):
450
+ context_parts.append("Teknik detaylarla ilgilenen bir kullanıcı")
451
+ if behavior.get("comparison_lover"):
452
+ context_parts.append("Karşılaştırma yapmayı seven bir kullanıcı")
453
+
454
+ # Etkileşim stili
455
+ interaction_style = profile_summary.get("interaction_style", "balanced")
456
+ style_descriptions = {
457
+ "analytical": "Detaylı ve analitik bilgi bekleyen",
458
+ "budget_conscious": "Bütçe odaklı ve ekonomik seçenekleri arayan",
459
+ "technical": "Teknik özellikler ve spesifikasyonlarla ilgilenen",
460
+ "decisive": "Hızlı karar veren ve özet bilgi isteyen",
461
+ "balanced": "Dengeli yaklaşım sergileyen"
462
+ }
463
+ context_parts.append(f"{style_descriptions.get(interaction_style, 'balanced')} bir kullanıcı")
464
+
465
+ if context_parts:
466
+ return f"Kullanıcı profili: {'. '.join(context_parts)}. Bu bilgileri göz önünde bulundurarak cevap ver."
467
+ return ""
468
+
469
+ def create_personalized_response(personalized_data, profile_summary):
470
+ """Kişiselleştirilmiş öneri cevabı oluştur"""
471
+ response_parts = []
472
+
473
+ # Kullanıcı stiline göre selamlama
474
+ interaction_style = profile_summary.get("interaction_style", "balanced")
475
+ if interaction_style == "analytical":
476
+ response_parts.append("🔍 Profilinizi analiz ederek sizin için en uygun seçenekleri belirledim:")
477
+ elif interaction_style == "budget_conscious":
478
+ response_parts.append("💰 Bütçenize uygun en iyi seçenekleri hazırladım:")
479
+ elif interaction_style == "technical":
480
+ response_parts.append("⚙️ Teknik tercihlerinize göre önerilerim:")
481
+ else:
482
+ response_parts.append("🎯 Size özel seçtiklerim:")
483
+
484
+ # Önerileri listele
485
+ recommendations = personalized_data.get("recommendations", [])[:3] # İlk 3 öneri
486
+
487
+ if recommendations:
488
+ response_parts.append("\n")
489
+ for i, product in enumerate(recommendations, 1):
490
+ name, item_info, full_name = product
491
+ price = item_info[1] if len(item_info) > 1 else "Fiyat yok"
492
+ response_parts.append(f"**{i}. {full_name}**")
493
+ response_parts.append(f"💰 Fiyat: {price} TL")
494
+ response_parts.append("")
495
+
496
+ # Profil bazlı açıklama
497
+ preferences = profile_summary.get("preferences", {})
498
+ if preferences.get("categories"):
499
+ category = preferences["categories"][0]
500
+ response_parts.append(f"Bu öneriler {category} kategorisindeki ilginizi ve tercihlerinizi dikkate alarak hazırlandı.")
501
+
502
+ return "\n".join(response_parts)
503
+
504
  def split_long_message(message, max_length=1600):
505
  """Uzun mesajları WhatsApp için uygun parçalara böler"""
506
  if len(message) <= max_length:
 
691
  }
692
  return {"conversation_memory": memory_info}
693
 
694
+ # Profil bilgilerini görme endpoint'i
695
+ @app.get("/debug-profile/{phone_number}")
696
+ async def debug_profile(phone_number: str):
697
+ """Belirli kullanıcının profil bilgilerini görüntüle"""
698
+ profile_summary = get_user_profile_summary(phone_number)
699
+ return {"phone_number": phone_number, "profile": profile_summary}
700
+
701
+ # Tüm profilleri görme endpoint'i
702
+ @app.get("/debug-profiles")
703
+ async def debug_profiles():
704
+ """Tüm kullanıcı profillerini görüntüle"""
705
+ from whatsapp_passive_profiler import passive_profiler
706
+ all_profiles = {}
707
+ for phone_number in passive_profiler.profiles.keys():
708
+ all_profiles[phone_number] = get_user_profile_summary(phone_number)
709
+ return {"profiles": all_profiles}
710
+
711
  @app.get("/health")
712
  async def health():
713
  return {
user_profiles.json ADDED
@@ -0,0 +1,76 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "+905551234567": {
3
+ "created_at": "2025-07-15 19:19:13.653674",
4
+ "last_updated": "2025-07-15 19:19:13.656036",
5
+ "total_messages": 8,
6
+ "preferences": {
7
+ "budget_min": 50000,
8
+ "budget_max": 80000,
9
+ "categories": [
10
+ "dağ_bisikleti"
11
+ ],
12
+ "usage_purpose": [],
13
+ "size_info": {
14
+ "height": 175
15
+ },
16
+ "brand_preferences": [],
17
+ "color_preferences": []
18
+ },
19
+ "behavior": {
20
+ "price_sensitive": true,
21
+ "tech_interested": false,
22
+ "comparison_lover": true,
23
+ "quick_decider": false,
24
+ "research_oriented": false
25
+ },
26
+ "interests": {
27
+ "viewed_products": [],
28
+ "compared_products": [],
29
+ "favorite_features": [],
30
+ "mentioned_brands": []
31
+ },
32
+ "statistics": {
33
+ "comparison_requests": 1,
34
+ "budget_queries": 1,
35
+ "technical_questions": 0,
36
+ "price_questions": 2,
37
+ "availability_questions": 0
38
+ }
39
+ },
40
+ "+905551234569": {
41
+ "created_at": "2025-07-15 19:20:10.867248",
42
+ "last_updated": "2025-07-15 19:20:10.868919",
43
+ "total_messages": 4,
44
+ "preferences": {
45
+ "budget_min": 150000,
46
+ "budget_max": 200000,
47
+ "categories": [
48
+ "yol_bisikleti"
49
+ ],
50
+ "usage_purpose": [],
51
+ "size_info": {},
52
+ "brand_preferences": [],
53
+ "color_preferences": []
54
+ },
55
+ "behavior": {
56
+ "price_sensitive": true,
57
+ "tech_interested": true,
58
+ "comparison_lover": true,
59
+ "quick_decider": false,
60
+ "research_oriented": true
61
+ },
62
+ "interests": {
63
+ "viewed_products": [],
64
+ "compared_products": [],
65
+ "favorite_features": [],
66
+ "mentioned_brands": []
67
+ },
68
+ "statistics": {
69
+ "comparison_requests": 0,
70
+ "budget_queries": 1,
71
+ "technical_questions": 1,
72
+ "price_questions": 0,
73
+ "availability_questions": 0
74
+ }
75
+ }
76
+ }
whatsapp_passive_profiler.py ADDED
@@ -0,0 +1,368 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ WhatsApp Pasif Profil Sistemi
4
+ Kullanıcıya soru sormadan sohbet analizi ile profil oluşturur
5
+ """
6
+
7
+ import re
8
+ import json
9
+ import os
10
+ from datetime import datetime, timedelta
11
+ from typing import Dict, List, Optional, Any
12
+
13
+ class WhatsAppPassiveProfiler:
14
+ """Sohbet analizi ile kullanıcı profili çıkarır"""
15
+
16
+ def __init__(self):
17
+ self.profiles_file = "user_profiles.json"
18
+ self.profiles = self.load_profiles()
19
+
20
+ # Bütçe ifadeleri
21
+ self.budget_patterns = [
22
+ r'bütçem?\s*(\d+)[\s-]*(\d+)?\s*k?\s*(bin|bin tl|tl)?',
23
+ r'(\d+)[\s-]*(\d+)?\s*k?\s*(bin|bin tl|tl)?\s*bütçe',
24
+ r'(\d+)[\s-]*(\d+)?\s*k?\s*(bin|bin tl|tl)?\s*arasında',
25
+ r'maksimum\s*(\d+)\s*k?\s*(bin|bin tl|tl)?',
26
+ r'en fazla\s*(\d+)\s*k?\s*(bin|bin tl|tl)?'
27
+ ]
28
+
29
+ # Kategori tercihleri
30
+ self.category_keywords = {
31
+ "dağ_bisikleti": ["dağ", "dag", "offroad", "patika", "doğa", "orman", "marlin", "fuel", "procaliber"],
32
+ "yol_bisikleti": ["yol", "asfalt", "hız", "yarış", "triathlon", "émonda", "madone", "domane"],
33
+ "şehir_bisikleti": ["şehir", "kent", "günlük", "işe gidip gelme", "fx", "ds", "verve"],
34
+ "elektrikli": ["elektrikli", "electric", "e-bike", "ebike", "batarya", "powerfly", "rail"],
35
+ "gravel": ["gravel", "çakıl", "macera", "touring", "checkpoint"]
36
+ }
37
+
38
+ # Kullanım amaçları
39
+ self.usage_patterns = {
40
+ "spor": ["spor", "antrenman", "kondisyon", "fitness", "egzersiz", "yarış"],
41
+ "günlük": ["işe gitmek", "günlük", "şehir içi", "ulaşım", "market", "alışveriş"],
42
+ "hobi": ["hobi", "eğlence", "gezinti", "keyif", "hafta sonu", "macera"],
43
+ "profesyonel": ["profesyonel", "yarış", "müsabaka", "antrenör", "ciddi"]
44
+ }
45
+
46
+ # Boy/beden işaretçileri
47
+ self.size_patterns = {
48
+ "boy": r'boyum\s*(\d+)\s*cm?|(\d+)\s*cm?\s*boy',
49
+ "kilo": r'kilom\s*(\d+)\s*kg?|(\d+)\s*kg?\s*kilo',
50
+ "beden": r'beden[im]?\s*([xsl]+)|([xsl]+)\s*beden'
51
+ }
52
+
53
+ def load_profiles(self) -> Dict:
54
+ """Mevcut profilleri yükle"""
55
+ if os.path.exists(self.profiles_file):
56
+ try:
57
+ with open(self.profiles_file, 'r', encoding='utf-8') as f:
58
+ return json.load(f)
59
+ except Exception as e:
60
+ print(f"Profil yükleme hatası: {e}")
61
+ return {}
62
+
63
+ def save_profiles(self):
64
+ """Profilleri kaydet"""
65
+ try:
66
+ with open(self.profiles_file, 'w', encoding='utf-8') as f:
67
+ json.dump(self.profiles, f, ensure_ascii=False, indent=2, default=str)
68
+ except Exception as e:
69
+ print(f"Profil kaydetme hatası: {e}")
70
+
71
+ def get_or_create_profile(self, phone_number: str) -> Dict:
72
+ """Profil getir veya oluştur"""
73
+ if phone_number not in self.profiles:
74
+ self.profiles[phone_number] = {
75
+ "created_at": datetime.now(),
76
+ "last_updated": datetime.now(),
77
+ "total_messages": 0,
78
+ "preferences": {
79
+ "budget_min": None,
80
+ "budget_max": None,
81
+ "categories": [], # İlgilendiği kategoriler
82
+ "usage_purpose": [], # Kullanım amaçları
83
+ "size_info": {}, # Boy, kilo, beden bilgileri
84
+ "brand_preferences": [], # Marka tercihleri
85
+ "color_preferences": [] # Renk tercihleri
86
+ },
87
+ "behavior": {
88
+ "price_sensitive": False, # Fiyata duyarlı mı
89
+ "tech_interested": False, # Teknik detaylarla ilgilenir mi
90
+ "comparison_lover": False, # Karşılaştırma sever mi
91
+ "quick_decider": False, # Hızlı karar verir mi
92
+ "research_oriented": False # Araştırmacı mı
93
+ },
94
+ "interests": {
95
+ "viewed_products": [], # Baktığı ürünler
96
+ "compared_products": [], # Karşılaştırdığı ürünler
97
+ "favorite_features": [], # İlgilendiği özellikler
98
+ "mentioned_brands": [] # Bahsettiği markalar
99
+ },
100
+ "statistics": {
101
+ "comparison_requests": 0,
102
+ "budget_queries": 0,
103
+ "technical_questions": 0,
104
+ "price_questions": 0,
105
+ "availability_questions": 0
106
+ }
107
+ }
108
+ return self.profiles[phone_number]
109
+
110
+ def analyze_message(self, phone_number: str, message: str) -> Dict:
111
+ """Mesajı analiz et ve profili güncelle"""
112
+ profile = self.get_or_create_profile(phone_number)
113
+ message_lower = message.lower()
114
+
115
+ # Mesaj sayısını artır
116
+ profile["total_messages"] += 1
117
+ profile["last_updated"] = datetime.now()
118
+
119
+ analysis_results = {
120
+ "budget_detected": False,
121
+ "category_detected": False,
122
+ "usage_detected": False,
123
+ "size_detected": False,
124
+ "behavior_indicators": []
125
+ }
126
+
127
+ # Bütçe analizi
128
+ budget_info = self.extract_budget(message_lower)
129
+ if budget_info:
130
+ profile["preferences"]["budget_min"] = budget_info["min"]
131
+ profile["preferences"]["budget_max"] = budget_info["max"]
132
+ profile["statistics"]["budget_queries"] += 1
133
+ analysis_results["budget_detected"] = True
134
+
135
+ # Kategori tercihi analizi
136
+ detected_categories = self.detect_categories(message_lower)
137
+ if detected_categories:
138
+ for category in detected_categories:
139
+ if category not in profile["preferences"]["categories"]:
140
+ profile["preferences"]["categories"].append(category)
141
+ analysis_results["category_detected"] = True
142
+
143
+ # Kullanım amacı analizi
144
+ usage_purposes = self.detect_usage_purpose(message_lower)
145
+ if usage_purposes:
146
+ for purpose in usage_purposes:
147
+ if purpose not in profile["preferences"]["usage_purpose"]:
148
+ profile["preferences"]["usage_purpose"].append(purpose)
149
+ analysis_results["usage_detected"] = True
150
+
151
+ # Boy/beden bilgisi analizi
152
+ size_info = self.extract_size_info(message_lower)
153
+ if size_info:
154
+ profile["preferences"]["size_info"].update(size_info)
155
+ analysis_results["size_detected"] = True
156
+
157
+ # Davranış analizi
158
+ behavior_indicators = self.analyze_behavior(message_lower)
159
+ for behavior, detected in behavior_indicators.items():
160
+ if detected:
161
+ profile["behavior"][behavior] = True
162
+ analysis_results["behavior_indicators"].append(behavior)
163
+
164
+ # İstatistik güncelleme
165
+ self.update_statistics(profile, message_lower)
166
+
167
+ # Profili kaydet
168
+ self.save_profiles()
169
+
170
+ return analysis_results
171
+
172
+ def extract_budget(self, message: str) -> Optional[Dict]:
173
+ """Bütçe bilgisini çıkar"""
174
+ for pattern in self.budget_patterns:
175
+ match = re.search(pattern, message)
176
+ if match:
177
+ numbers = [g for g in match.groups() if g and g.isdigit()]
178
+ if numbers:
179
+ if len(numbers) == 1:
180
+ # Tek sayı - maksimum bütçe
181
+ budget = int(numbers[0])
182
+ if budget < 1000: # K formatında (50k = 50000)
183
+ budget *= 1000
184
+ return {"min": int(budget * 0.7), "max": budget}
185
+ elif len(numbers) >= 2:
186
+ # Aralık - min ve max
187
+ min_budget = int(numbers[0])
188
+ max_budget = int(numbers[1])
189
+ if min_budget < 1000:
190
+ min_budget *= 1000
191
+ if max_budget < 1000:
192
+ max_budget *= 1000
193
+ return {"min": min_budget, "max": max_budget}
194
+ return None
195
+
196
+ def detect_categories(self, message: str) -> List[str]:
197
+ """Kategori tercihlerini tespit et"""
198
+ detected = []
199
+ for category, keywords in self.category_keywords.items():
200
+ if any(keyword in message for keyword in keywords):
201
+ detected.append(category)
202
+ return detected
203
+
204
+ def detect_usage_purpose(self, message: str) -> List[str]:
205
+ """Kullanım amacını tespit et"""
206
+ detected = []
207
+ for purpose, keywords in self.usage_patterns.items():
208
+ if any(keyword in message for keyword in keywords):
209
+ detected.append(purpose)
210
+ return detected
211
+
212
+ def extract_size_info(self, message: str) -> Dict:
213
+ """Boy/beden bilgisini çıkar"""
214
+ size_info = {}
215
+
216
+ # Boy bilgisi
217
+ boy_match = re.search(self.size_patterns["boy"], message)
218
+ if boy_match:
219
+ boy = boy_match.group(1) or boy_match.group(2)
220
+ if boy:
221
+ size_info["height"] = int(boy)
222
+
223
+ # Kilo bilgisi
224
+ kilo_match = re.search(self.size_patterns["kilo"], message)
225
+ if kilo_match:
226
+ kilo = kilo_match.group(1) or kilo_match.group(2)
227
+ if kilo:
228
+ size_info["weight"] = int(kilo)
229
+
230
+ # Beden bilgisi
231
+ beden_match = re.search(self.size_patterns["beden"], message)
232
+ if beden_match:
233
+ beden = beden_match.group(1) or beden_match.group(2)
234
+ if beden:
235
+ size_info["size"] = beden.upper()
236
+
237
+ return size_info
238
+
239
+ def analyze_behavior(self, message: str) -> Dict[str, bool]:
240
+ """Davranış kalıplarını analiz et"""
241
+ behavior = {}
242
+
243
+ # Fiyata duyarlılık
244
+ price_keywords = ["ucuz", "fiyat", "indirim", "kampanya", "ekonomik", "bütçe"]
245
+ behavior["price_sensitive"] = any(keyword in message for keyword in price_keywords)
246
+
247
+ # Teknik ilgi
248
+ tech_keywords = ["teknik", "özellik", "ağırlık", "malzeme", "karbon", "alüminyum", "vites"]
249
+ behavior["tech_interested"] = any(keyword in message for keyword in tech_keywords)
250
+
251
+ # Karşılaştırma sevgisi
252
+ comparison_keywords = ["karşılaştır", "fark", "hangisi", "arası", "seçim"]
253
+ behavior["comparison_lover"] = any(keyword in message for keyword in comparison_keywords)
254
+
255
+ # Araştırmacı yapı
256
+ research_keywords = ["detay", "bilgi", "araştır", "inceleme", "test", "deneyim"]
257
+ behavior["research_oriented"] = any(keyword in message for keyword in research_keywords)
258
+
259
+ return behavior
260
+
261
+ def update_statistics(self, profile: Dict, message: str):
262
+ """İstatistikleri güncelle"""
263
+ if "karşılaştır" in message:
264
+ profile["statistics"]["comparison_requests"] += 1
265
+
266
+ if any(word in message for word in ["fiyat", "kaç para", "ne kadar"]):
267
+ profile["statistics"]["price_questions"] += 1
268
+
269
+ if any(word in message for word in ["stok", "var mı", "mevcut"]):
270
+ profile["statistics"]["availability_questions"] += 1
271
+
272
+ if any(word in message for word in ["teknik", "özellik", "detay"]):
273
+ profile["statistics"]["technical_questions"] += 1
274
+
275
+ def get_profile_summary(self, phone_number: str) -> Dict:
276
+ """Profil özetini döndür"""
277
+ if phone_number not in self.profiles:
278
+ return {"exists": False}
279
+
280
+ profile = self.profiles[phone_number]
281
+
282
+ # Profil güvenilirlik skoru (mesaj sayısına göre)
283
+ confidence = min(profile["total_messages"] / 10.0, 1.0) # 10 mesajda %100
284
+
285
+ summary = {
286
+ "exists": True,
287
+ "confidence": confidence,
288
+ "total_messages": profile["total_messages"],
289
+ "preferences": profile["preferences"],
290
+ "behavior": profile["behavior"],
291
+ "top_categories": profile["preferences"]["categories"][:3],
292
+ "is_budget_defined": profile["preferences"]["budget_min"] is not None,
293
+ "is_tech_savvy": profile["behavior"]["tech_interested"],
294
+ "is_price_conscious": profile["behavior"]["price_sensitive"],
295
+ "interaction_style": self.get_interaction_style(profile)
296
+ }
297
+
298
+ return summary
299
+
300
+ def get_interaction_style(self, profile: Dict) -> str:
301
+ """Etkileşim stilini belirle"""
302
+ stats = profile["statistics"]
303
+ behavior = profile["behavior"]
304
+
305
+ if stats["comparison_requests"] > 2 and behavior["research_oriented"]:
306
+ return "analytical" # Analitik - detaylı bilgi sever
307
+ elif behavior["price_sensitive"] and stats["budget_queries"] > 0:
308
+ return "budget_conscious" # Bütçe odaklı
309
+ elif behavior["tech_interested"] and stats["technical_questions"] > 1:
310
+ return "technical" # Teknik odaklı
311
+ elif stats["comparison_requests"] == 0 and profile["total_messages"] < 5:
312
+ return "decisive" # Hızlı karar verici
313
+ else:
314
+ return "balanced" # Dengeli
315
+
316
+ def get_personalized_suggestions(self, phone_number: str, products_data: List) -> Dict:
317
+ """Kişiselleştirilmiş öneriler"""
318
+ profile_summary = self.get_profile_summary(phone_number)
319
+
320
+ if not profile_summary["exists"] or profile_summary["confidence"] < 0.3:
321
+ return {"personalized": False, "reason": "insufficient_data"}
322
+
323
+ suggestions = {
324
+ "personalized": True,
325
+ "user_style": profile_summary["interaction_style"],
326
+ "budget_aware": profile_summary["is_budget_defined"],
327
+ "recommendations": []
328
+ }
329
+
330
+ # Bütçe filtresi
331
+ filtered_products = products_data
332
+ if profile_summary["preferences"]["budget_min"]:
333
+ budget_min = profile_summary["preferences"]["budget_min"]
334
+ budget_max = profile_summary["preferences"]["budget_max"]
335
+ filtered_products = [
336
+ p for p in products_data
337
+ if p[1][0] == "stokta" and p[1][1] and
338
+ budget_min <= float(p[1][1]) <= budget_max
339
+ ]
340
+
341
+ # Kategori filtresi
342
+ if profile_summary["top_categories"]:
343
+ category_products = []
344
+ for category in profile_summary["top_categories"]:
345
+ category_products.extend([
346
+ p for p in filtered_products
347
+ if any(keyword in p[2].lower() for keyword in self.category_keywords.get(category, []))
348
+ ])
349
+ if category_products:
350
+ filtered_products = category_products
351
+
352
+ suggestions["recommendations"] = filtered_products[:5]
353
+ return suggestions
354
+
355
+ # Global instance
356
+ passive_profiler = WhatsAppPassiveProfiler()
357
+
358
+ def analyze_user_message(phone_number: str, message: str) -> Dict:
359
+ """Kullanıcı mesajını analiz et ve profili güncelle"""
360
+ return passive_profiler.analyze_message(phone_number, message)
361
+
362
+ def get_user_profile_summary(phone_number: str) -> Dict:
363
+ """Kullanıcı profil özetini getir"""
364
+ return passive_profiler.get_profile_summary(phone_number)
365
+
366
+ def get_personalized_recommendations(phone_number: str, products_data: List) -> Dict:
367
+ """Kişiselleştirilmiş öneriler getir"""
368
+ return passive_profiler.get_personalized_suggestions(phone_number, products_data)