|
|
|
|
|
|
|
""" |
|
Otomatik Takip ve Hatırlatma Sistemi |
|
Müşteri taahhütlerini takip eder ve Mehmet Bey'e hatırlatır |
|
""" |
|
|
|
import os |
|
import json |
|
import logging |
|
from datetime import datetime, timedelta |
|
from typing import Optional, List, Dict |
|
from dataclasses import dataclass, asdict |
|
from enum import Enum |
|
|
|
logger = logging.getLogger(__name__) |
|
|
|
|
|
class FollowUpType(Enum): |
|
RESERVATION = "reservation" |
|
VISIT_PROMISE = "visit" |
|
PRICE_INQUIRY = "price" |
|
DECISION_PENDING = "decision" |
|
TEST_RIDE = "test_ride" |
|
|
|
|
|
class FollowUpStatus(Enum): |
|
PENDING = "pending" |
|
REMINDED = "reminded" |
|
COMPLETED = "completed" |
|
CANCELLED = "cancelled" |
|
|
|
@dataclass |
|
class FollowUp: |
|
"""Takip kaydı""" |
|
id: str |
|
customer_phone: str |
|
customer_name: Optional[str] |
|
product_name: str |
|
follow_up_type: str |
|
status: str |
|
created_at: str |
|
follow_up_at: str |
|
original_message: str |
|
notes: Optional[str] |
|
store_name: Optional[str] |
|
reminded_count: int = 0 |
|
|
|
class FollowUpManager: |
|
"""Takip yöneticisi""" |
|
|
|
def __init__(self, db_file: str = "follow_ups.json"): |
|
self.db_file = db_file |
|
self.follow_ups = self._load_database() |
|
|
|
def _load_database(self) -> List[FollowUp]: |
|
"""Database'i yükle""" |
|
if os.path.exists(self.db_file): |
|
try: |
|
with open(self.db_file, "r") as f: |
|
data = json.load(f) |
|
return [FollowUp(**item) for item in data] |
|
except Exception as e: |
|
logger.error(f"Database yükleme hatası: {e}") |
|
return [] |
|
return [] |
|
|
|
def _save_database(self): |
|
"""Database'i kaydet""" |
|
try: |
|
data = [asdict(f) for f in self.follow_ups] |
|
with open(self.db_file, "w") as f: |
|
json.dump(data, f, indent=2, ensure_ascii=False) |
|
except Exception as e: |
|
logger.error(f"Database kayıt hatası: {e}") |
|
|
|
def create_follow_up( |
|
self, |
|
customer_phone: str, |
|
product_name: str, |
|
follow_up_type: FollowUpType, |
|
original_message: str, |
|
follow_up_hours: int = 24, |
|
customer_name: Optional[str] = None, |
|
notes: Optional[str] = None, |
|
store_name: Optional[str] = None |
|
) -> FollowUp: |
|
"""Yeni takip oluştur""" |
|
|
|
now = datetime.now() |
|
follow_up_time = now + timedelta(hours=follow_up_hours) |
|
|
|
|
|
follow_up_id = f"{customer_phone}_{now.strftime('%Y%m%d_%H%M%S')}" |
|
|
|
follow_up = FollowUp( |
|
id=follow_up_id, |
|
customer_phone=customer_phone, |
|
customer_name=customer_name, |
|
product_name=product_name, |
|
follow_up_type=follow_up_type.value, |
|
status=FollowUpStatus.PENDING.value, |
|
created_at=now.isoformat(), |
|
follow_up_at=follow_up_time.isoformat(), |
|
original_message=original_message, |
|
notes=notes, |
|
store_name=store_name, |
|
reminded_count=0 |
|
) |
|
|
|
self.follow_ups.append(follow_up) |
|
self._save_database() |
|
|
|
logger.info(f"✅ Takip oluşturuldu: {follow_up_id}") |
|
logger.info(f" Hatırlatma zamanı: {follow_up_time.strftime('%d.%m.%Y %H:%M')}") |
|
|
|
return follow_up |
|
|
|
def get_pending_reminders(self) -> List[FollowUp]: |
|
"""Bekleyen hatırlatmaları getir""" |
|
now = datetime.now() |
|
pending = [] |
|
|
|
for follow_up in self.follow_ups: |
|
if follow_up.status == FollowUpStatus.PENDING.value: |
|
follow_up_time = datetime.fromisoformat(follow_up.follow_up_at) |
|
if follow_up_time <= now: |
|
pending.append(follow_up) |
|
|
|
return pending |
|
|
|
def mark_as_reminded(self, follow_up_id: str): |
|
"""Hatırlatma yapıldı olarak işaretle""" |
|
for follow_up in self.follow_ups: |
|
if follow_up.id == follow_up_id: |
|
follow_up.status = FollowUpStatus.REMINDED.value |
|
follow_up.reminded_count += 1 |
|
self._save_database() |
|
logger.info(f"✅ Hatırlatma yapıldı: {follow_up_id}") |
|
break |
|
|
|
def mark_as_completed(self, follow_up_id: str): |
|
"""Tamamlandı olarak işaretle""" |
|
for follow_up in self.follow_ups: |
|
if follow_up.id == follow_up_id: |
|
follow_up.status = FollowUpStatus.COMPLETED.value |
|
self._save_database() |
|
logger.info(f"✅ Takip tamamlandı: {follow_up_id}") |
|
break |
|
|
|
def get_customer_history(self, customer_phone: str) -> List[FollowUp]: |
|
"""Müşteri geçmişini getir""" |
|
return [f for f in self.follow_ups if f.customer_phone == customer_phone] |
|
|
|
def get_todays_follow_ups(self) -> List[FollowUp]: |
|
"""Bugünün takiplerini getir""" |
|
today = datetime.now().date() |
|
todays = [] |
|
|
|
for follow_up in self.follow_ups: |
|
follow_up_date = datetime.fromisoformat(follow_up.follow_up_at).date() |
|
if follow_up_date == today: |
|
todays.append(follow_up) |
|
|
|
return todays |
|
|
|
def analyze_message_for_follow_up(message: str) -> Optional[Dict]: |
|
""" |
|
Mesajı analiz et ve takip gerekip gerekmediğini belirle |
|
|
|
Returns: |
|
{ |
|
"needs_follow_up": True/False, |
|
"follow_up_type": FollowUpType, |
|
"follow_up_hours": int, |
|
"reason": str |
|
} |
|
""" |
|
|
|
message_lower = message.lower() |
|
|
|
|
|
tomorrow_keywords = [ |
|
'yarın', 'yarin', |
|
'yarın gel', 'yarın al', 'yarın uğra', |
|
'yarına', 'yarina', |
|
'ertesi gün' |
|
] |
|
|
|
|
|
today_keywords = [ |
|
'bugün', 'bugun', |
|
'bugün gel', 'bugün al', 'bugün uğra', |
|
'akşam gel', 'aksam gel', |
|
'öğleden sonra', 'ogleden sonra', |
|
'birazdan', 'biraz sonra', |
|
'1 saat', 'bir saat', |
|
'2 saat', 'iki saat', |
|
'30 dakika', 'yarım saat' |
|
] |
|
|
|
|
|
weekend_keywords = [ |
|
'hafta sonu', 'haftasonu', |
|
'cumartesi', 'pazar', |
|
'hafta içi', 'haftaiçi' |
|
] |
|
|
|
|
|
decision_keywords = [ |
|
'düşüneyim', 'düşüncem', 'düşünelim', |
|
'danışayım', 'danısayım', 'danışıcam', |
|
'eşime sor', 'eşimle konuş', 'esime sor', |
|
'karar ver', 'haber ver', |
|
'araştırayım', 'araştırıcam', |
|
'bakarım', 'bakarız', 'bakıcam' |
|
] |
|
|
|
|
|
test_keywords = [ |
|
'test sürüş', 'test et', 'dene', |
|
'binebilir', 'binmek ist', |
|
'test ride', 'deneme sürüş' |
|
] |
|
|
|
|
|
for keyword in tomorrow_keywords: |
|
if keyword in message_lower: |
|
return { |
|
"needs_follow_up": True, |
|
"follow_up_type": FollowUpType.VISIT_PROMISE, |
|
"follow_up_hours": 24, |
|
"reason": f"Müşteri yarın geleceğini söyledi: '{keyword}'" |
|
} |
|
|
|
|
|
for keyword in today_keywords: |
|
if keyword in message_lower: |
|
return { |
|
"needs_follow_up": True, |
|
"follow_up_type": FollowUpType.VISIT_PROMISE, |
|
"follow_up_hours": 6, |
|
"reason": f"Müşteri bugün geleceğini söyledi: '{keyword}'" |
|
} |
|
|
|
|
|
for keyword in weekend_keywords: |
|
if keyword in message_lower: |
|
|
|
today = datetime.now().weekday() |
|
if today < 5: |
|
days_to_saturday = 5 - today |
|
hours = days_to_saturday * 24 |
|
else: |
|
hours = 24 |
|
|
|
return { |
|
"needs_follow_up": True, |
|
"follow_up_type": FollowUpType.VISIT_PROMISE, |
|
"follow_up_hours": hours, |
|
"reason": f"Müşteri hafta sonu geleceğini söyledi: '{keyword}'" |
|
} |
|
|
|
|
|
for keyword in decision_keywords: |
|
if keyword in message_lower: |
|
return { |
|
"needs_follow_up": True, |
|
"follow_up_type": FollowUpType.DECISION_PENDING, |
|
"follow_up_hours": 48, |
|
"reason": f"Müşteri düşüneceğini söyledi: '{keyword}'" |
|
} |
|
|
|
|
|
for keyword in test_keywords: |
|
if keyword in message_lower: |
|
return { |
|
"needs_follow_up": True, |
|
"follow_up_type": FollowUpType.TEST_RIDE, |
|
"follow_up_hours": 4, |
|
"reason": f"Müşteri test sürüşü istiyor: '{keyword}'" |
|
} |
|
|
|
|
|
reservation_keywords = ['ayırt', 'rezerve', 'tutun', 'sakla'] |
|
for keyword in reservation_keywords: |
|
if keyword in message_lower: |
|
return { |
|
"needs_follow_up": True, |
|
"follow_up_type": FollowUpType.RESERVATION, |
|
"follow_up_hours": 24, |
|
"reason": f"Ayırtma talebi var: '{keyword}'" |
|
} |
|
|
|
return None |
|
|
|
def format_reminder_message(follow_up: FollowUp) -> str: |
|
"""Hatırlatma mesajını formatla""" |
|
|
|
|
|
type_emojis = { |
|
"reservation": "📦", |
|
"visit": "🚶", |
|
"price": "💰", |
|
"decision": "🤔", |
|
"test_ride": "🚴" |
|
} |
|
|
|
emoji = type_emojis.get(follow_up.follow_up_type, "📌") |
|
|
|
|
|
created_time = datetime.fromisoformat(follow_up.created_at) |
|
time_diff = datetime.now() - created_time |
|
|
|
if time_diff.days > 0: |
|
time_str = f"{time_diff.days} gün önce" |
|
elif time_diff.seconds > 3600: |
|
hours = time_diff.seconds // 3600 |
|
time_str = f"{hours} saat önce" |
|
else: |
|
time_str = "Az önce" |
|
|
|
|
|
message = f""" |
|
{emoji} **TAKİP HATIRLATMASI** |
|
|
|
👤 Müşteri: {follow_up.customer_name or "İsimsiz"} |
|
📱 Tel: {follow_up.customer_phone.replace('whatsapp:', '')} |
|
|
|
🚲 Ürün: {follow_up.product_name} |
|
⏰ İlk mesaj: {time_str} |
|
|
|
📝 Müşteri mesajı: |
|
"{follow_up.original_message}" |
|
""" |
|
|
|
|
|
if follow_up.follow_up_type == "reservation": |
|
message += "\n⚠️ AYIRTMA TAKİBİ: Müşteri geldi mi?" |
|
elif follow_up.follow_up_type == "visit": |
|
message += "\n⚠️ ZİYARET TAKİBİ: Müşteri geleceğini söylemişti" |
|
elif follow_up.follow_up_type == "decision": |
|
message += "\n⚠️ KARAR TAKİBİ: Müşteri düşüneceğini söylemişti" |
|
elif follow_up.follow_up_type == "test_ride": |
|
message += "\n⚠️ TEST SÜRÜŞÜ TAKİBİ: Test için gelecekti" |
|
|
|
message += "\n\n📞 Müşteriyi arayıp durumu öğrenin!" |
|
|
|
return message |
|
|
|
|
|
def test_follow_up_system(): |
|
"""Test senaryoları""" |
|
|
|
print("\n" + "="*60) |
|
print("TAKİP SİSTEMİ TESTİ") |
|
print("="*60) |
|
|
|
manager = FollowUpManager("test_follow_ups.json") |
|
|
|
|
|
test_messages = [ |
|
("Yarın gelip FX 2'yi alacağım", "FX 2"), |
|
("Eşime danışayım, size dönerim", "Marlin 5"), |
|
("Bugün akşam uğrarım", "Checkpoint"), |
|
("Hafta sonu test sürüşü yapabilir miyim?", "Domane"), |
|
("30 dakikaya oradayım, ayırtın", "FX Sport") |
|
] |
|
|
|
for message, product in test_messages: |
|
print(f"\n📝 Mesaj: '{message}'") |
|
|
|
analysis = analyze_message_for_follow_up(message) |
|
if analysis and analysis["needs_follow_up"]: |
|
print(f"✅ Takip gerekli!") |
|
print(f" Tip: {analysis['follow_up_type'].value}") |
|
print(f" {analysis['follow_up_hours']} saat sonra hatırlat") |
|
print(f" Sebep: {analysis['reason']}") |
|
|
|
|
|
follow_up = manager.create_follow_up( |
|
customer_phone="whatsapp:+905551234567", |
|
product_name=product, |
|
follow_up_type=analysis["follow_up_type"], |
|
original_message=message, |
|
follow_up_hours=analysis["follow_up_hours"] |
|
) |
|
else: |
|
print("❌ Takip gerekmiyor") |
|
|
|
|
|
print("\n" + "="*60) |
|
print("BEKLEYEN HATIRLATMALAR") |
|
print("="*60) |
|
|
|
pending = manager.get_pending_reminders() |
|
if pending: |
|
for f in pending: |
|
print(f"\n{format_reminder_message(f)}") |
|
else: |
|
print("Bekleyen hatırlatma yok") |
|
|
|
print("\n" + "="*60) |
|
|
|
if __name__ == "__main__": |
|
test_follow_up_system() |