|
"""Cached warehouse search to reduce API calls and token usage""" |
|
|
|
import time |
|
import re |
|
import json |
|
import requests |
|
from typing import Dict, List, Optional, Tuple |
|
|
|
|
|
CACHE_DURATION = 43200 |
|
cache = { |
|
'warehouse_xml': {'data': None, 'time': 0}, |
|
'trek_xml': {'data': None, 'time': 0}, |
|
'products_summary': {'data': None, 'time': 0}, |
|
'simple_searches': {} |
|
} |
|
|
|
def get_cached_warehouse_xml() -> str: |
|
"""Get warehouse XML with caching""" |
|
current_time = time.time() |
|
|
|
if cache['warehouse_xml']['data'] and (current_time - cache['warehouse_xml']['time'] < CACHE_DURATION): |
|
print("📦 Using cached warehouse XML") |
|
return cache['warehouse_xml']['data'] |
|
|
|
print("📡 Fetching fresh warehouse XML...") |
|
url = 'https://video.trek-turkey.com/bizimhesap-warehouse-xml-b2b-api-v2.php' |
|
response = requests.get(url, verify=False, timeout=15) |
|
|
|
cache['warehouse_xml']['data'] = response.text |
|
cache['warehouse_xml']['time'] = current_time |
|
|
|
return response.text |
|
|
|
def get_cached_trek_xml() -> str: |
|
"""Get Trek XML with caching""" |
|
current_time = time.time() |
|
|
|
if cache['trek_xml']['data'] and (current_time - cache['trek_xml']['time'] < CACHE_DURATION): |
|
print("🚴 Using cached Trek XML") |
|
return cache['trek_xml']['data'] |
|
|
|
print("📡 Fetching fresh Trek XML...") |
|
url = 'https://www.trekbisiklet.com.tr/output/8582384479' |
|
response = requests.get(url, verify=False, timeout=15) |
|
|
|
cache['trek_xml']['data'] = response.content |
|
cache['trek_xml']['time'] = current_time |
|
|
|
return response.content |
|
|
|
def simple_product_search(query: str) -> Optional[List[Dict]]: |
|
""" |
|
Simple local search without GPT-5 |
|
Returns product info if exact/close match found |
|
""" |
|
query_upper = query.upper() |
|
query_parts = query_upper.split() |
|
|
|
|
|
if not cache['products_summary']['data'] or \ |
|
(time.time() - cache['products_summary']['time'] > CACHE_DURATION): |
|
|
|
build_products_summary() |
|
|
|
products_summary = cache['products_summary']['data'] |
|
|
|
|
|
exact_patterns = { |
|
'MADONE SL 6': lambda p: 'MADONE SL 6' in p['name'], |
|
'MADONE SL 7': lambda p: 'MADONE SL 7' in p['name'], |
|
'MARLIN 5': lambda p: 'MARLIN 5' in p['name'], |
|
'MARLIN 6': lambda p: 'MARLIN 6' in p['name'], |
|
'MARLIN 7': lambda p: 'MARLIN 7' in p['name'], |
|
'DOMANE SL 5': lambda p: 'DOMANE SL 5' in p['name'], |
|
'CHECKPOINT': lambda p: 'CHECKPOINT' in p['name'], |
|
'FX': lambda p: p['name'].startswith('FX'), |
|
'DUAL SPORT': lambda p: 'DUAL SPORT' in p['name'], |
|
'RAIL': lambda p: 'RAIL' in p['name'], |
|
'POWERFLY': lambda p: 'POWERFLY' in p['name'], |
|
} |
|
|
|
|
|
for pattern, matcher in exact_patterns.items(): |
|
if pattern in query_upper: |
|
matching = [p for p in products_summary if matcher(p)] |
|
if matching: |
|
print(f"✅ Found {len(matching)} products via simple search (no GPT-5 needed)") |
|
return matching |
|
|
|
|
|
if len(query_parts) == 1: |
|
matching = [p for p in products_summary if query_parts[0] in p['name']] |
|
if matching and len(matching) < 20: |
|
print(f"✅ Found {len(matching)} products via simple search (no GPT-5 needed)") |
|
return matching |
|
|
|
return None |
|
|
|
def build_products_summary(): |
|
"""Build products summary from cached XMLs""" |
|
xml_text = get_cached_warehouse_xml() |
|
|
|
|
|
product_pattern = r'<Product>(.*?)</Product>' |
|
all_products = re.findall(product_pattern, xml_text, re.DOTALL) |
|
|
|
products_summary = [] |
|
for i, product_block in enumerate(all_products): |
|
name_match = re.search(r'<ProductName><!\[CDATA\[(.*?)\]\]></ProductName>', product_block) |
|
variant_match = re.search(r'<ProductVariant><!\[CDATA\[(.*?)\]\]></ProductVariant>', product_block) |
|
|
|
if name_match: |
|
warehouses_with_stock = [] |
|
warehouse_regex = r'<Warehouse>.*?<Name><!\[CDATA\[(.*?)\]\]></Name>.*?<Stock>(.*?)</Stock>.*?</Warehouse>' |
|
warehouses = re.findall(warehouse_regex, product_block, re.DOTALL) |
|
|
|
for wh_name, wh_stock in warehouses: |
|
try: |
|
if int(wh_stock.strip()) > 0: |
|
warehouses_with_stock.append(wh_name) |
|
except: |
|
pass |
|
|
|
product_info = { |
|
"index": i, |
|
"name": name_match.group(1), |
|
"variant": variant_match.group(1) if variant_match else "", |
|
"warehouses": warehouses_with_stock |
|
} |
|
products_summary.append(product_info) |
|
|
|
cache['products_summary']['data'] = products_summary |
|
cache['products_summary']['time'] = time.time() |
|
|
|
print(f"📊 Built products summary: {len(products_summary)} products") |
|
|
|
def should_use_gpt5(query: str) -> bool: |
|
"""Determine if query needs GPT-5""" |
|
query_lower = query.lower() |
|
|
|
|
|
gpt5_triggers = [ |
|
'öneri', 'tavsiye', 'bütçe', 'karşılaştır', |
|
'hangisi', 'ne önerirsin', 'yardım', |
|
'en iyi', 'en ucuz', 'en pahalı', |
|
'kaç tane', 'toplam', 'fark' |
|
] |
|
|
|
for trigger in gpt5_triggers: |
|
if trigger in query_lower: |
|
return True |
|
|
|
|
|
if simple_product_search(query): |
|
return False |
|
|
|
return True |
|
|
|
|
|
def smart_warehouse_search(query: str) -> List[str]: |
|
""" |
|
Smart search with caching and minimal GPT-5 usage |
|
""" |
|
|
|
cache_key = query.lower() |
|
if cache_key in cache['simple_searches']: |
|
cached_result = cache['simple_searches'][cache_key] |
|
if time.time() - cached_result['time'] < CACHE_DURATION: |
|
print(f"✅ Using cached result for '{query}'") |
|
return cached_result['data'] |
|
|
|
|
|
simple_results = simple_product_search(query) |
|
if simple_results: |
|
|
|
formatted_results = format_simple_results(simple_results) |
|
cache['simple_searches'][cache_key] = { |
|
'data': formatted_results, |
|
'time': time.time() |
|
} |
|
return formatted_results |
|
|
|
|
|
print(f"🤖 Using GPT-5 for complex query: '{query}'") |
|
|
|
return None |
|
|
|
def format_simple_results(products: List[Dict]) -> List[str]: |
|
"""Format simple search results""" |
|
if not products: |
|
return ["Ürün bulunamadı"] |
|
|
|
result = ["Bulunan ürünler:"] |
|
|
|
|
|
product_groups = {} |
|
for p in products: |
|
if p['name'] not in product_groups: |
|
product_groups[p['name']] = [] |
|
product_groups[p['name']].append(p) |
|
|
|
for product_name, variants in product_groups.items(): |
|
result.append(f"\n{product_name}:") |
|
for v in variants: |
|
if v['variant']: |
|
warehouses_str = ", ".join([w.replace('MAGAZA DEPO', '').strip() for w in v['warehouses']]) |
|
result.append(f"• {v['variant']}: {warehouses_str if warehouses_str else 'Stokta yok'}") |
|
|
|
return result |