Restore backup and fix Turkish normalization
Browse files- Restored all Python files from backup (20250904)
- Fixed Turkish character normalization in smart_warehouse_with_price.py
- Removed CRM hardcoded keyword dependencies from app.py
- Improved product search with proper İ/I handling for Turkish XML data
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <[email protected]>
- __pycache__/prompts.cpython-312.pyc +0 -0
- __pycache__/smart_warehouse_with_price.cpython-312.pyc +0 -0
- app.py +39 -316
- smart_warehouse_with_price.py +13 -16
__pycache__/prompts.cpython-312.pyc
CHANGED
Binary files a/__pycache__/prompts.cpython-312.pyc and b/__pycache__/prompts.cpython-312.pyc differ
|
|
__pycache__/smart_warehouse_with_price.cpython-312.pyc
CHANGED
Binary files a/__pycache__/smart_warehouse_with_price.cpython-312.pyc and b/__pycache__/smart_warehouse_with_price.cpython-312.pyc differ
|
|
app.py
CHANGED
@@ -41,16 +41,6 @@ except ImportError:
|
|
41 |
USE_GPT5_SEARCH = False
|
42 |
logger.info("❌ GPT-5 search not available")
|
43 |
|
44 |
-
# Import CRM system
|
45 |
-
try:
|
46 |
-
from customer_manager import CustomerManager
|
47 |
-
customer_manager = CustomerManager()
|
48 |
-
USE_CRM = True
|
49 |
-
logger.info("✅ CRM System loaded - Customer tracking enabled")
|
50 |
-
except ImportError:
|
51 |
-
USE_CRM = False
|
52 |
-
logger.info("❌ CRM System not available")
|
53 |
-
|
54 |
warnings.simplefilter('ignore')
|
55 |
|
56 |
# Import Media Queue V2
|
@@ -758,10 +748,7 @@ def get_conversation_context(phone_number):
|
|
758 |
conversation_memory[phone_number] = {
|
759 |
"messages": [],
|
760 |
"current_category": None,
|
761 |
-
"last_activity": None
|
762 |
-
"last_product_info": None, # Son bulunan ürün bilgisi
|
763 |
-
"last_search_term": None, # Son arama terimi
|
764 |
-
"last_search_time": None # Son arama zamanı
|
765 |
}
|
766 |
return conversation_memory[phone_number]
|
767 |
|
@@ -784,81 +771,6 @@ def add_to_conversation(phone_number, user_message, ai_response):
|
|
784 |
|
785 |
detect_category(phone_number, user_message, ai_response)
|
786 |
|
787 |
-
def cache_product_info(phone_number, search_term, product_info):
|
788 |
-
"""Ürün bilgisini conversation memory'e cache'le"""
|
789 |
-
import datetime
|
790 |
-
|
791 |
-
context = get_conversation_context(phone_number)
|
792 |
-
context["last_product_info"] = product_info
|
793 |
-
context["last_search_term"] = search_term.lower().strip()
|
794 |
-
context["last_search_time"] = datetime.datetime.now()
|
795 |
-
|
796 |
-
logger.info(f"📦 Cached product info for {phone_number}: {search_term}")
|
797 |
-
|
798 |
-
def get_cached_product_info(phone_number, search_term):
|
799 |
-
"""Cache'den ürün bilgisini getir"""
|
800 |
-
import datetime
|
801 |
-
|
802 |
-
context = get_conversation_context(phone_number)
|
803 |
-
|
804 |
-
if not context.get("last_product_info") or not context.get("last_search_term"):
|
805 |
-
return None
|
806 |
-
|
807 |
-
# Son aramadan 30 dakika geçmişse cache'i temizle
|
808 |
-
if context.get("last_search_time"):
|
809 |
-
time_diff = datetime.datetime.now() - context["last_search_time"]
|
810 |
-
if time_diff.total_seconds() > 1800: # 30 dakika
|
811 |
-
context["last_product_info"] = None
|
812 |
-
return None
|
813 |
-
|
814 |
-
# Arama terimi benzer mi kontrol et
|
815 |
-
cached_term = context["last_search_term"]
|
816 |
-
current_term = search_term.lower().strip()
|
817 |
-
|
818 |
-
# Daha esnek ürün eşleştirmesi
|
819 |
-
|
820 |
-
# 1. Aynı ürün ailesi tespit edici kelimeler
|
821 |
-
product_families = ["fx", "marlin", "domane", "madone", "emonda", "fuel", "supercaliber", "procaliber"]
|
822 |
-
|
823 |
-
# Cache'deki ürün ailesini bul
|
824 |
-
cached_family = None
|
825 |
-
for family in product_families:
|
826 |
-
if family in cached_term:
|
827 |
-
cached_family = family
|
828 |
-
break
|
829 |
-
|
830 |
-
# Current term'deki ürün ailesini bul
|
831 |
-
current_family = None
|
832 |
-
for family in product_families:
|
833 |
-
if family in current_term:
|
834 |
-
current_family = family
|
835 |
-
break
|
836 |
-
|
837 |
-
# Aynı ürün ailesi varsa cache kullan
|
838 |
-
if cached_family and current_family and cached_family == current_family:
|
839 |
-
logger.info(f"📦 Using cached product info - Same family: {cached_family}")
|
840 |
-
return context["last_product_info"]
|
841 |
-
|
842 |
-
# 2. Context-aware keywords - sadece farklı ürün ismi içermiyorsa
|
843 |
-
contextual_keywords = ["boyum", "boy", "beden", "size", "l ", "xl", "cm", "ayırt", "rezerv",
|
844 |
-
"fiyat", "price", "stok", "nasıl", "nerede", "hangi mağaza",
|
845 |
-
"teslimat", "ödeme", "taksit", "kaç", "almak", "satın"]
|
846 |
-
|
847 |
-
# Farklı bir ürün ailesi ismi var mı kontrol et
|
848 |
-
has_different_product = current_family and current_family != cached_family
|
849 |
-
|
850 |
-
# Cache'de ürün var, farklı ürün yok ve contextual ise
|
851 |
-
if cached_family and not has_different_product and any(keyword in current_term for keyword in contextual_keywords):
|
852 |
-
logger.info(f"📦 Using cached product info - Contextual query about {cached_family}")
|
853 |
-
return context["last_product_info"]
|
854 |
-
|
855 |
-
# 3. Tam metin benzerliği (eski mantık)
|
856 |
-
if cached_term in current_term or current_term in cached_term:
|
857 |
-
logger.info(f"📦 Using cached product info - Text similarity: {search_term}")
|
858 |
-
return context["last_product_info"]
|
859 |
-
|
860 |
-
return None
|
861 |
-
|
862 |
def detect_category(phone_number, user_message, ai_response):
|
863 |
"""Konuşulan kategoriyi tespit et"""
|
864 |
context = get_conversation_context(phone_number)
|
@@ -1033,18 +945,6 @@ def process_whatsapp_message_with_media(user_message, phone_number, media_urls,
|
|
1033 |
def process_whatsapp_message_with_memory(user_message, phone_number):
|
1034 |
"""Hafızalı WhatsApp mesaj işleme"""
|
1035 |
try:
|
1036 |
-
# CRM - Kişiselleştirilmiş yanıt hazırlığı
|
1037 |
-
personalized_greeting = ""
|
1038 |
-
product_searched = None
|
1039 |
-
|
1040 |
-
if USE_CRM:
|
1041 |
-
clean_phone = phone_number.replace('whatsapp:', '')
|
1042 |
-
customer_context = customer_manager.get_customer_context(clean_phone)
|
1043 |
-
|
1044 |
-
# Eğer ilk mesaj ise veya selamlama içeriyorsa
|
1045 |
-
user_msg_lower = user_message.lower()
|
1046 |
-
if any(word in user_msg_lower for word in ["merhaba", "selam", "günaydın", "iyi günler", "iyi akşamlar", "hey", "hi", "hello"]):
|
1047 |
-
personalized_greeting = customer_context.get("greeting", "") + "\n\n"
|
1048 |
# 🔔 Yeni Mağaza Bildirim Sistemi - Mehmet Bey'e otomatik bildirim
|
1049 |
if USE_STORE_NOTIFICATION:
|
1050 |
# Önce basit keyword kontrolü yap
|
@@ -1195,56 +1095,61 @@ def process_whatsapp_message_with_memory(user_message, phone_number):
|
|
1195 |
|
1196 |
if warehouse_info_parts:
|
1197 |
warehouse_response = "\n".join(warehouse_info_parts)
|
1198 |
-
|
1199 |
-
# Cache'e kaydet - tutarlılık için
|
1200 |
-
cache_product_info(phone_number, user_message, warehouse_response)
|
1201 |
-
|
1202 |
messages.append({
|
1203 |
"role": "system",
|
1204 |
"content": f"MAĞAZA STOK BİLGİSİ (BF Space):\n{warehouse_response}\n\nSADECE bu bilgileri kullanarak kullanıcıya yardımcı ol."
|
1205 |
})
|
1206 |
product_found_improved = True
|
1207 |
-
logger.info("✅ BF Space: Warehouse stock info used
|
1208 |
|
1209 |
if not product_found_improved:
|
1210 |
-
# Use improved search response directly
|
1211 |
-
response_content = product_result['response']
|
1212 |
-
|
1213 |
-
# Cache'e kaydet - tutarlılık için
|
1214 |
-
cache_product_info(phone_number, user_message, response_content)
|
1215 |
-
|
1216 |
messages.append({
|
1217 |
"role": "system",
|
1218 |
-
"content": f"ÜRÜN BİLGİSİ (BF Space):\n{
|
1219 |
})
|
1220 |
product_found_improved = True
|
1221 |
-
logger.info("✅ BF Space: Improved product search used
|
1222 |
except Exception as e:
|
1223 |
logger.error(f"❌ BF Space: Improved search error: {e}")
|
1224 |
|
1225 |
-
#
|
1226 |
if not product_found_improved:
|
1227 |
-
#
|
1228 |
-
|
|
|
1229 |
|
1230 |
-
|
1231 |
-
|
1232 |
-
|
1233 |
-
|
1234 |
-
|
1235 |
-
|
1236 |
-
|
1237 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1238 |
else:
|
1239 |
-
|
1240 |
-
# System prompt'taki "MESAJ TİPİ TANIMA REHBERİ"ni kullansın
|
1241 |
-
|
1242 |
-
# GPT-5'e özel talimat: Eğer ürün bilgisi gerekiyorsa belirtsin
|
1243 |
-
messages.append({
|
1244 |
-
"role": "system",
|
1245 |
-
"content": "NOT: Eğer bu mesaj bir ürün/stok/fiyat sorgusu ise ve elimde o bilgi yoksa, kullanıcıya 'Bu ürün için güncel bilgi kontrol edebilirim, ister misiniz?' diye sor. Basit selamlamalarda stok araması gereksiz."
|
1246 |
-
})
|
1247 |
-
logger.info("🧠 GPT-5'e mesaj klasifikasyonu bırakıldı - hardcoded logic yok")
|
1248 |
|
1249 |
if not OPENAI_API_KEY:
|
1250 |
return "OpenAI API anahtarı eksik. Lütfen environment variables'ları kontrol edin."
|
@@ -1281,54 +1186,6 @@ def process_whatsapp_message_with_memory(user_message, phone_number):
|
|
1281 |
# WhatsApp için resim URL'lerini formatla
|
1282 |
formatted_response = extract_product_info_whatsapp(ai_response)
|
1283 |
|
1284 |
-
# CRM - Kişiselleştirilmiş selamlama ekle (sadece GPT-5 selamlamadıysa)
|
1285 |
-
if personalized_greeting:
|
1286 |
-
# GPT-5 zaten selamladıysa ekleme
|
1287 |
-
ai_lower = ai_response.lower()
|
1288 |
-
if not any(word in ai_lower for word in ["hoş geldin", "selam", "merhaba", "iyi akşam", "günaydın", "iyi günler"]):
|
1289 |
-
formatted_response = personalized_greeting + formatted_response
|
1290 |
-
|
1291 |
-
# CRM - İsim sorma kontrolü
|
1292 |
-
name_request = ""
|
1293 |
-
if USE_CRM:
|
1294 |
-
clean_phone = phone_number.replace('whatsapp:', '')
|
1295 |
-
|
1296 |
-
# Önce mevcut müşteriyi kontrol et (son mesajı isim yanıtı olabilir)
|
1297 |
-
customer = customer_manager.get_or_create_customer(clean_phone)
|
1298 |
-
|
1299 |
-
# Eğer önceki mesajda isim sorulmuşsa ve şimdi yanıt geliyorsa
|
1300 |
-
if customer.get("awaiting_name_response", False):
|
1301 |
-
# İsim çıkarmayı dene
|
1302 |
-
extracted_name = customer_manager.extract_name_from_response(user_message)
|
1303 |
-
if extracted_name:
|
1304 |
-
customer["name"] = extracted_name
|
1305 |
-
customer["awaiting_name_response"] = False
|
1306 |
-
customer_manager._save_database()
|
1307 |
-
formatted_response = f"Memnun oldum {extracted_name}!\n\n" + formatted_response
|
1308 |
-
logger.info(f"✅ İsim kaydedildi: {extracted_name}")
|
1309 |
-
|
1310 |
-
# İsim sorulmalı mı kontrol et
|
1311 |
-
should_ask, name_question = customer_manager.should_ask_for_name(clean_phone, user_message)
|
1312 |
-
if should_ask:
|
1313 |
-
name_request = f"\n\n{name_question}"
|
1314 |
-
# İsim yanıtı bekleniyor işaretle
|
1315 |
-
customer["awaiting_name_response"] = True
|
1316 |
-
customer_manager._save_database()
|
1317 |
-
|
1318 |
-
# Ürün araması yapılmışsa, ürün adını çıkar
|
1319 |
-
if "📦" in formatted_response or "stok" in formatted_response.lower():
|
1320 |
-
# İlk satırdan ürün adını çıkarmaya çalış
|
1321 |
-
lines = formatted_response.split('\n')
|
1322 |
-
for line in lines:
|
1323 |
-
if '📦' in line or 'Trek' in line or 'Marlin' in line or 'FX' in line:
|
1324 |
-
product_searched = line.replace('📦', '').strip()
|
1325 |
-
break
|
1326 |
-
customer_manager.update_interaction(clean_phone, user_message, product_searched)
|
1327 |
-
|
1328 |
-
# İsim sorusunu yanıta ekle
|
1329 |
-
if name_request:
|
1330 |
-
formatted_response = formatted_response + name_request
|
1331 |
-
|
1332 |
# Sohbet geçmişine ekle
|
1333 |
add_to_conversation(phone_number, user_message, formatted_response)
|
1334 |
|
@@ -1645,21 +1502,6 @@ async def whatsapp_webhook(request: Request):
|
|
1645 |
|
1646 |
print(f"✅ MESAJ ALINDI: {from_number} -> {message_body}")
|
1647 |
|
1648 |
-
# CRM - Müşteri tanıma ve güncelleme
|
1649 |
-
if USE_CRM:
|
1650 |
-
# Telefon numarasından whatsapp: prefix'ini kaldır
|
1651 |
-
clean_phone = from_number.replace('whatsapp:', '')
|
1652 |
-
|
1653 |
-
# Müşteri bilgilerini al veya oluştur
|
1654 |
-
customer = customer_manager.get_or_create_customer(clean_phone)
|
1655 |
-
customer_context = customer_manager.get_customer_context(clean_phone)
|
1656 |
-
|
1657 |
-
# Müşteri segmenti ve kişisel bilgi log
|
1658 |
-
if customer_context.get("name"):
|
1659 |
-
logger.info(f"👤 Müşteri: {customer_context['name']} ({customer_context['segment']} segment)")
|
1660 |
-
else:
|
1661 |
-
logger.info(f"👤 Müşteri: {clean_phone} ({customer_context['segment']} segment)")
|
1662 |
-
|
1663 |
if not twilio_client:
|
1664 |
return {"status": "error", "message": "Twilio yapılandırması eksik"}
|
1665 |
|
@@ -1731,125 +1573,6 @@ async def clear_memory(phone_number: str):
|
|
1731 |
return {"status": "info", "message": "Hafıza bulunamadı"}
|
1732 |
|
1733 |
# Mehmet Bey bildirimlerini görüntüleme endpoint'i
|
1734 |
-
@app.get("/crm-analytics")
|
1735 |
-
async def view_crm_analytics():
|
1736 |
-
"""CRM analytics ve müşteri listesi görüntüle"""
|
1737 |
-
if not USE_CRM:
|
1738 |
-
return {"error": "CRM system not available"}
|
1739 |
-
|
1740 |
-
analytics = customer_manager.get_analytics()
|
1741 |
-
customers = customer_manager.get_customer_list()
|
1742 |
-
|
1743 |
-
# HTML formatında döndür
|
1744 |
-
html_content = f"""
|
1745 |
-
<!DOCTYPE html>
|
1746 |
-
<html>
|
1747 |
-
<head>
|
1748 |
-
<title>CRM Analytics - Trek Bisiklet</title>
|
1749 |
-
<meta charset="utf-8">
|
1750 |
-
<style>
|
1751 |
-
body {{ font-family: Arial, sans-serif; padding: 20px; background: #f5f5f5; }}
|
1752 |
-
h1 {{ color: #333; border-bottom: 2px solid #007bff; padding-bottom: 10px; }}
|
1753 |
-
.stats-grid {{ display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 20px; margin: 20px 0; }}
|
1754 |
-
.stat-card {{ background: white; padding: 20px; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }}
|
1755 |
-
.stat-number {{ font-size: 2em; font-weight: bold; color: #007bff; }}
|
1756 |
-
.stat-label {{ color: #666; margin-top: 5px; }}
|
1757 |
-
.segment-chart {{ background: white; padding: 20px; border-radius: 8px; margin: 20px 0; }}
|
1758 |
-
table {{ width: 100%; background: white; border-radius: 8px; overflow: hidden; margin: 20px 0; }}
|
1759 |
-
th {{ background: #007bff; color: white; padding: 12px; text-align: left; }}
|
1760 |
-
td {{ padding: 12px; border-bottom: 1px solid #eee; }}
|
1761 |
-
tr:hover {{ background: #f9f9f9; }}
|
1762 |
-
.segment-badge {{ padding: 4px 8px; border-radius: 4px; font-size: 12px; font-weight: bold; }}
|
1763 |
-
.segment-vip {{ background: #ffd700; color: #333; }}
|
1764 |
-
.segment-potansiyel {{ background: #17a2b8; color: white; }}
|
1765 |
-
.segment-yeni {{ background: #28a745; color: white; }}
|
1766 |
-
.segment-kayip {{ background: #dc3545; color: white; }}
|
1767 |
-
.segment-aktif {{ background: #007bff; color: white; }}
|
1768 |
-
.segment-standart {{ background: #6c757d; color: white; }}
|
1769 |
-
</style>
|
1770 |
-
</head>
|
1771 |
-
<body>
|
1772 |
-
<h1>🎯 CRM Analytics Dashboard</h1>
|
1773 |
-
|
1774 |
-
<div class="stats-grid">
|
1775 |
-
<div class="stat-card">
|
1776 |
-
<div class="stat-number">{analytics['total_customers']}</div>
|
1777 |
-
<div class="stat-label">Toplam Müşteri</div>
|
1778 |
-
</div>
|
1779 |
-
<div class="stat-card">
|
1780 |
-
<div class="stat-number">{analytics['active_today']}</div>
|
1781 |
-
<div class="stat-label">Bugün Aktif</div>
|
1782 |
-
</div>
|
1783 |
-
<div class="stat-card">
|
1784 |
-
<div class="stat-number">{analytics['total_purchases']}</div>
|
1785 |
-
<div class="stat-label">Toplam Satış</div>
|
1786 |
-
</div>
|
1787 |
-
<div class="stat-card">
|
1788 |
-
<div class="stat-number">₺{analytics['total_revenue']:,.0f}</div>
|
1789 |
-
<div class="stat-label">Toplam Gelir</div>
|
1790 |
-
</div>
|
1791 |
-
</div>
|
1792 |
-
|
1793 |
-
<div class="segment-chart">
|
1794 |
-
<h2>📊 Müşteri Segmentleri</h2>
|
1795 |
-
<div class="stats-grid">
|
1796 |
-
"""
|
1797 |
-
|
1798 |
-
for segment, count in analytics['segments'].items():
|
1799 |
-
html_content += f"""
|
1800 |
-
<div class="stat-card">
|
1801 |
-
<div class="stat-number">{count}</div>
|
1802 |
-
<div class="stat-label segment-badge segment-{segment.lower().replace(' ', '-')}">{segment}</div>
|
1803 |
-
</div>
|
1804 |
-
"""
|
1805 |
-
|
1806 |
-
html_content += """
|
1807 |
-
</div>
|
1808 |
-
</div>
|
1809 |
-
|
1810 |
-
<h2>👥 Müşteri Listesi</h2>
|
1811 |
-
<table>
|
1812 |
-
<thead>
|
1813 |
-
<tr>
|
1814 |
-
<th>Telefon</th>
|
1815 |
-
<th>İsim</th>
|
1816 |
-
<th>Segment</th>
|
1817 |
-
<th>Sorgular</th>
|
1818 |
-
<th>Satınalmalar</th>
|
1819 |
-
<th>Son Etkileşim</th>
|
1820 |
-
<th>İlgi Alanları</th>
|
1821 |
-
</tr>
|
1822 |
-
</thead>
|
1823 |
-
<tbody>
|
1824 |
-
"""
|
1825 |
-
|
1826 |
-
for customer in customers[:50]: # İlk 50 müşteri
|
1827 |
-
segment_class = f"segment-{customer['segment'].lower().replace(' ', '-')}"
|
1828 |
-
interests = ', '.join(customer['interests'][:3]) if customer['interests'] else '-'
|
1829 |
-
last_interaction = customer['last_interaction'].split('T')[0] if customer['last_interaction'] else '-'
|
1830 |
-
|
1831 |
-
html_content += f"""
|
1832 |
-
<tr>
|
1833 |
-
<td>{customer['phone']}</td>
|
1834 |
-
<td>{customer['name']}</td>
|
1835 |
-
<td><span class="segment-badge {segment_class}">{customer['segment']}</span></td>
|
1836 |
-
<td>{customer['total_queries']}</td>
|
1837 |
-
<td>{customer['total_purchases']}</td>
|
1838 |
-
<td>{last_interaction}</td>
|
1839 |
-
<td>{interests}</td>
|
1840 |
-
</tr>
|
1841 |
-
"""
|
1842 |
-
|
1843 |
-
html_content += """
|
1844 |
-
</tbody>
|
1845 |
-
</table>
|
1846 |
-
</body>
|
1847 |
-
</html>
|
1848 |
-
"""
|
1849 |
-
|
1850 |
-
from fastapi.responses import HTMLResponse
|
1851 |
-
return HTMLResponse(content=html_content)
|
1852 |
-
|
1853 |
@app.get("/mehmet-bey-notifications")
|
1854 |
async def view_mehmet_bey_notifications():
|
1855 |
"""Mehmet Bey için kaydedilen bildirimleri görüntüle"""
|
|
|
41 |
USE_GPT5_SEARCH = False
|
42 |
logger.info("❌ GPT-5 search not available")
|
43 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
44 |
warnings.simplefilter('ignore')
|
45 |
|
46 |
# Import Media Queue V2
|
|
|
748 |
conversation_memory[phone_number] = {
|
749 |
"messages": [],
|
750 |
"current_category": None,
|
751 |
+
"last_activity": None
|
|
|
|
|
|
|
752 |
}
|
753 |
return conversation_memory[phone_number]
|
754 |
|
|
|
771 |
|
772 |
detect_category(phone_number, user_message, ai_response)
|
773 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
774 |
def detect_category(phone_number, user_message, ai_response):
|
775 |
"""Konuşulan kategoriyi tespit et"""
|
776 |
context = get_conversation_context(phone_number)
|
|
|
945 |
def process_whatsapp_message_with_memory(user_message, phone_number):
|
946 |
"""Hafızalı WhatsApp mesaj işleme"""
|
947 |
try:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
948 |
# 🔔 Yeni Mağaza Bildirim Sistemi - Mehmet Bey'e otomatik bildirim
|
949 |
if USE_STORE_NOTIFICATION:
|
950 |
# Önce basit keyword kontrolü yap
|
|
|
1095 |
|
1096 |
if warehouse_info_parts:
|
1097 |
warehouse_response = "\n".join(warehouse_info_parts)
|
|
|
|
|
|
|
|
|
1098 |
messages.append({
|
1099 |
"role": "system",
|
1100 |
"content": f"MAĞAZA STOK BİLGİSİ (BF Space):\n{warehouse_response}\n\nSADECE bu bilgileri kullanarak kullanıcıya yardımcı ol."
|
1101 |
})
|
1102 |
product_found_improved = True
|
1103 |
+
logger.info("✅ BF Space: Warehouse stock info used")
|
1104 |
|
1105 |
if not product_found_improved:
|
1106 |
+
# Use improved search response directly
|
|
|
|
|
|
|
|
|
|
|
1107 |
messages.append({
|
1108 |
"role": "system",
|
1109 |
+
"content": f"ÜRÜN BİLGİSİ (BF Space):\n{product_result['response']}\n\nSADECE bu bilgileri kullanarak kullanıcıya yardımcı ol. Bu bilgiler dışında ek bilgi ekleme."
|
1110 |
})
|
1111 |
product_found_improved = True
|
1112 |
+
logger.info("✅ BF Space: Improved product search used")
|
1113 |
except Exception as e:
|
1114 |
logger.error(f"❌ BF Space: Improved search error: {e}")
|
1115 |
|
1116 |
+
# Fallback to warehouse search if improved search didn't work
|
1117 |
if not product_found_improved:
|
1118 |
+
# Check if message seems to be asking about products
|
1119 |
+
product_keywords = ['fiyat', 'kaç', 'stok', 'var mı', 'mevcut', 'bisiklet', 'bike',
|
1120 |
+
'trek', 'model', 'beden', 'renk', 'mağaza', 'nerede', 'hangi']
|
1121 |
|
1122 |
+
# Common non-product responses
|
1123 |
+
non_product_responses = ['süper', 'harika', 'güzel', 'teşekkür', 'tamam', 'olur',
|
1124 |
+
'evet', 'hayır', 'peki', 'anladım', 'tamamdır']
|
1125 |
+
|
1126 |
+
is_product_query = False
|
1127 |
+
lower_message = user_message.lower()
|
1128 |
+
|
1129 |
+
# Check if it's likely a product query
|
1130 |
+
if any(keyword in lower_message for keyword in product_keywords):
|
1131 |
+
is_product_query = True
|
1132 |
+
# Check if it's NOT a simple response
|
1133 |
+
elif lower_message not in non_product_responses and len(lower_message.split()) > 1:
|
1134 |
+
# Multi-word queries might be product searches
|
1135 |
+
is_product_query = True
|
1136 |
+
# Single short words are usually not products
|
1137 |
+
elif len(lower_message.split()) == 1 and len(lower_message) < 6:
|
1138 |
+
is_product_query = False
|
1139 |
+
|
1140 |
+
if is_product_query:
|
1141 |
+
# Use GPT-5 warehouse search for product queries
|
1142 |
+
logger.info("📦 Using GPT-5 warehouse search")
|
1143 |
+
warehouse_result = get_warehouse_stock(user_message)
|
1144 |
+
if warehouse_result and warehouse_result != ['Ürün bulunamadı']:
|
1145 |
+
warehouse_response = "\n".join(warehouse_result)
|
1146 |
+
messages.append({
|
1147 |
+
"role": "system",
|
1148 |
+
"content": f"MAĞAZA STOK BİLGİSİ:\n{warehouse_response}\n\nBu bilgileri kullanarak kullanıcıya yardımcı ol. Fiyat ve stok bilgilerini AYNEN kullan."
|
1149 |
+
})
|
1150 |
+
logger.info(f"✅ Warehouse stock info added: {warehouse_response[:200]}...")
|
1151 |
else:
|
1152 |
+
logger.info(f"🚫 Skipping product search for: '{user_message}'")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1153 |
|
1154 |
if not OPENAI_API_KEY:
|
1155 |
return "OpenAI API anahtarı eksik. Lütfen environment variables'ları kontrol edin."
|
|
|
1186 |
# WhatsApp için resim URL'lerini formatla
|
1187 |
formatted_response = extract_product_info_whatsapp(ai_response)
|
1188 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1189 |
# Sohbet geçmişine ekle
|
1190 |
add_to_conversation(phone_number, user_message, formatted_response)
|
1191 |
|
|
|
1502 |
|
1503 |
print(f"✅ MESAJ ALINDI: {from_number} -> {message_body}")
|
1504 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1505 |
if not twilio_client:
|
1506 |
return {"status": "error", "message": "Twilio yapılandırması eksik"}
|
1507 |
|
|
|
1573 |
return {"status": "info", "message": "Hafıza bulunamadı"}
|
1574 |
|
1575 |
# Mehmet Bey bildirimlerini görüntüleme endpoint'i
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1576 |
@app.get("/mehmet-bey-notifications")
|
1577 |
async def view_mehmet_bey_notifications():
|
1578 |
"""Mehmet Bey için kaydedilen bildirimleri görüntüle"""
|
smart_warehouse_with_price.py
CHANGED
@@ -293,26 +293,23 @@ def get_warehouse_stock_smart_with_price(user_message, previous_result=None):
|
|
293 |
# Check if the target product exists
|
294 |
# Normalize Turkish characters for comparison
|
295 |
def normalize_turkish(text):
|
296 |
-
|
297 |
-
|
298 |
-
#
|
299 |
-
|
300 |
-
|
301 |
-
'Ğ': 'G', 'ğ': 'g', 'Ü': 'U', 'ü': 'u',
|
302 |
-
'Ö': 'O', 'ö': 'o', 'Ç': 'C', 'ç': 'c'
|
303 |
-
}
|
304 |
-
normalized = text
|
305 |
-
for tr_char, en_char in replacements.items():
|
306 |
-
normalized = normalized.replace(tr_char, en_char)
|
307 |
-
return normalized.lower()
|
308 |
|
309 |
-
search_term =
|
|
|
310 |
|
311 |
matching_products = []
|
312 |
for p in products_summary:
|
313 |
-
p_name =
|
314 |
-
# Check
|
315 |
-
if search_term in p_name
|
|
|
|
|
|
|
316 |
matching_products.append(p)
|
317 |
|
318 |
if matching_products:
|
|
|
293 |
# Check if the target product exists
|
294 |
# Normalize Turkish characters for comparison
|
295 |
def normalize_turkish(text):
|
296 |
+
text = text.upper()
|
297 |
+
replacements = {'I': 'İ', 'Ç': 'C', 'Ş': 'S', 'Ğ': 'G', 'Ü': 'U', 'Ö': 'O'}
|
298 |
+
# Also try with İ -> I conversion
|
299 |
+
text2 = text.replace('İ', 'I')
|
300 |
+
return text, text2
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
301 |
|
302 |
+
search_term = user_message.upper()
|
303 |
+
search_norm1, search_norm2 = normalize_turkish(search_term)
|
304 |
|
305 |
matching_products = []
|
306 |
for p in products_summary:
|
307 |
+
p_name = p['name'].upper()
|
308 |
+
# Check both original and normalized versions
|
309 |
+
if (search_term in p_name or
|
310 |
+
search_norm1 in p_name or
|
311 |
+
search_norm2 in p_name or
|
312 |
+
search_term.replace('I', 'İ') in p_name):
|
313 |
matching_products.append(p)
|
314 |
|
315 |
if matching_products:
|