SamiKoen commited on
Commit
f22680d
·
verified ·
1 Parent(s): 97bb587

Upload app (7).py

Browse files
Files changed (1) hide show
  1. app (7).py +723 -0
app (7).py ADDED
@@ -0,0 +1,723 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import os
3
+ import json
4
+ import requests
5
+ import xml.etree.ElementTree as ET
6
+ import schedule
7
+ import time
8
+ import threading
9
+ from huggingface_hub import HfApi, create_repo, hf_hub_download
10
+ import warnings
11
+ import pandas as pd
12
+ from docx import Document
13
+ import spaces
14
+ from google.oauth2.service_account import Credentials
15
+ from googleapiclient.discovery import build
16
+ from googleapiclient.http import MediaIoBaseDownload
17
+ import io
18
+ import warnings
19
+ from requests.packages.urllib3.exceptions import InsecureRequestWarning
20
+ warnings.simplefilter('ignore', InsecureRequestWarning)
21
+
22
+ # Prompt dosyasını import et
23
+ from prompts import get_prompt_content_only
24
+
25
+ # Enhanced features import et (sadece temel özellikler)
26
+ from enhanced_features import (
27
+ initialize_enhanced_features, process_image_message,
28
+ handle_comparison_request
29
+ )
30
+ from image_renderer import extract_product_info_for_gallery, format_message_with_images
31
+
32
+ # Gradio uyarılarını bastır
33
+ warnings.filterwarnings("ignore", category=UserWarning, module="gradio.components.chatbot")
34
+
35
+ # Log dosyası adı ve yolu
36
+ LOG_FILE = '/data/chat_logs.txt' if os.path.exists('/data') else 'chat_logs.txt'
37
+ print(f"Dosya yolu: {os.path.abspath(LOG_FILE)}")
38
+
39
+ # API ayarları
40
+ API_URL = "https://api.openai.com/v1/chat/completions"
41
+ OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
42
+ if not OPENAI_API_KEY:
43
+ print("Hata: OPENAI_API_KEY çevre değişkeni ayarlanmamış!")
44
+
45
+ # Trek bisiklet ürünlerini çekme
46
+ url = 'https://www.trekbisiklet.com.tr/output/8582384479'
47
+ response = requests.get(url, verify=False, timeout=60)
48
+ if response.status_code == 200 and response.content:
49
+ root = ET.fromstring(response.content)
50
+ else:
51
+ print(f"HTTP hatası: {response.status_code}")
52
+ root = None
53
+
54
+ products = []
55
+ if root is not None:
56
+ for item in root.findall('item'):
57
+ # Tüm ürünleri al, sonra stokta olma durumunu kontrol et - None kontrolü
58
+ rootlabel_elem = item.find('rootlabel')
59
+ stock_elem = item.find('stockAmount')
60
+
61
+ if rootlabel_elem is None or stock_elem is None:
62
+ continue # Eksik veri varsa bu ürünü atla
63
+
64
+ name_words = rootlabel_elem.text.lower().split()
65
+ name = name_words[0]
66
+ full_name = ' '.join(name_words)
67
+
68
+ stock_amount = "stokta" if stock_elem.text and stock_elem.text > '0' else "stokta değil"
69
+
70
+ # Stokta olmayan ürünler için fiyat/link bilgisi eklemiyoruz
71
+ if stock_amount == "stokta":
72
+ # Normal fiyat bilgisini al - Güvenli versiyon
73
+ price_elem = item.find('priceTaxWithCur')
74
+ price_str = price_elem.text if price_elem is not None and price_elem.text else "Fiyat bilgisi yok"
75
+
76
+ # EFT fiyatını al (havale indirimli orijinal fiyat) - Güvenli versiyon
77
+ price_eft_elem = item.find('priceEft')
78
+ price_eft_str = price_eft_elem.text if price_eft_elem is not None and price_eft_elem.text else ""
79
+
80
+ # İndirimli fiyatı al (kampanyalı fiyat) - Güvenli versiyon
81
+ price_rebate_elem = item.find('priceRebateWithTax')
82
+ price_rebate_str = price_rebate_elem.text if price_rebate_elem is not None and price_rebate_elem.text else ""
83
+
84
+ # Havale indirimi fiyatını al (havale indirimli kampanyalı fiyat) - Güvenli versiyon
85
+ price_rebate_money_order_elem = item.find('priceRebateWithMoneyOrderWithTax')
86
+ price_rebate_money_order_str = price_rebate_money_order_elem.text if price_rebate_money_order_elem is not None and price_rebate_money_order_elem.text else ""
87
+
88
+ # Normal fiyatı yuvarla
89
+ try:
90
+ price_float = float(price_str)
91
+ # Fiyat 200000 üzerindeyse en yakın 5000'lik basamağa yuvarla
92
+ if price_float > 200000:
93
+ price = str(round(price_float / 5000) * 5000) # En yakın 5000'e yuvarla
94
+ # Fiyat 30000 üzerindeyse en yakın 1000'lik basamağa yuvarla
95
+ elif price_float > 30000:
96
+ price = str(round(price_float / 1000) * 1000) # En yakın 1000'e yuvarla
97
+ # Fiyat 10000 üzerindeyse en yakın 100'lük basamağa yuvarla
98
+ elif price_float > 10000:
99
+ price = str(round(price_float / 100) * 100) # En yakın 100'e yuvarla
100
+ # Diğer durumlarda en yakın 10'luk basamağa yuvarla
101
+ else:
102
+ price = str(round(price_float / 10) * 10) # En yakın 10'a yuvarla
103
+ except (ValueError, TypeError):
104
+ price = price_str # Sayıya dönüştürülemezse olduğu gibi bırak
105
+
106
+ # Havale indirimli orijinal fiyatı yuvarla (varsa)
107
+ if price_eft_str:
108
+ try:
109
+ price_eft_float = float(price_eft_str)
110
+ # Fiyat 200000 üzerindeyse en yakın 5000'lik basamağa yuvarla
111
+ if price_eft_float > 200000:
112
+ price_eft = str(round(price_eft_float / 5000) * 5000)
113
+ # Fiyat 30000 üzerindeyse en yakın 1000'lik basamağa yuvarla
114
+ elif price_eft_float > 30000:
115
+ price_eft = str(round(price_eft_float / 1000) * 1000)
116
+ # Fiyat 10000 üzerindeyse en yakın 100'lük basamağa yuvarla
117
+ elif price_eft_float > 10000:
118
+ price_eft = str(round(price_eft_float / 100) * 100)
119
+ # Diğer durumlarda en yakın 10'luk basamağa yuvarla
120
+ else:
121
+ price_eft = str(round(price_eft_float / 10) * 10)
122
+ except (ValueError, TypeError):
123
+ price_eft = price_eft_str
124
+ else:
125
+ price_eft = ""
126
+
127
+ # İndirimli fiyatı yuvarla (varsa)
128
+ if price_rebate_str:
129
+ try:
130
+ price_rebate_float = float(price_rebate_str)
131
+ # Fiyat 200000 üzerindeyse en yakın 5000'lik basamağa yuvarla
132
+ if price_rebate_float > 200000:
133
+ price_rebate = str(round(price_rebate_float / 5000) * 5000)
134
+ # Fiyat 30000 üzerindeyse en yakın 1000'lik basamağa yuvarla
135
+ elif price_rebate_float > 30000:
136
+ price_rebate = str(round(price_rebate_float / 1000) * 1000)
137
+ # Fiyat 10000 üzerindeyse en yakın 100'lük basamağa yuvarla
138
+ elif price_rebate_float > 10000:
139
+ price_rebate = str(round(price_rebate_float / 100) * 100)
140
+ # Diğer durumlarda en yakın 10'luk basamağa yuvarla
141
+ else:
142
+ price_rebate = str(round(price_rebate_float / 10) * 10)
143
+ except (ValueError, TypeError):
144
+ price_rebate = price_rebate_str
145
+ else:
146
+ price_rebate = ""
147
+
148
+ # Havale indirimli kampanyalı fiyatı yuvarla (varsa)
149
+ if price_rebate_money_order_str:
150
+ try:
151
+ price_rebate_money_order_float = float(price_rebate_money_order_str)
152
+ # Fiyat 200000 üzerindeyse en yakın 5000'lik basamağa yuvarla
153
+ if price_rebate_money_order_float > 200000:
154
+ price_rebate_money_order = str(round(price_rebate_money_order_float / 5000) * 5000)
155
+ # Fiyat 30000 üzerindeyse en yakın 1000'lik basamağa yuvarla
156
+ elif price_rebate_money_order_float > 30000:
157
+ price_rebate_money_order = str(round(price_rebate_money_order_float / 1000) * 1000)
158
+ # Fiyat 10000 üzerindeyse en yakın 100'lük basamağa yuvarla
159
+ elif price_rebate_money_order_float > 10000:
160
+ price_rebate_money_order = str(round(price_rebate_money_order_float / 100) * 100)
161
+ # Diğer durumlarda en yakın 10'luk basamağa yuvarla
162
+ else:
163
+ price_rebate_money_order = str(round(price_rebate_money_order_float / 10) * 10)
164
+ except (ValueError, TypeError):
165
+ price_rebate_money_order = price_rebate_money_order_str
166
+ else:
167
+ price_rebate_money_order = ""
168
+
169
+ # Ürün bilgilerini al - None kontrolü ekle
170
+ product_url_elem = item.find('productLink')
171
+ product_url = product_url_elem.text if product_url_elem is not None and product_url_elem.text else ""
172
+ product_info = [stock_amount, price, product_url, price_eft, price_rebate, price_rebate_money_order]
173
+
174
+ # Resim URL'si ekle (varsa) - Güvenli versiyon
175
+ image_elem = item.find('picture1Path')
176
+ if image_elem is not None and image_elem.text:
177
+ product_info.append(image_elem.text)
178
+ else:
179
+ product_info.append("") # Boş resim URL'si
180
+
181
+ else:
182
+ # Stokta olmayan ürün için sadece stok durumu
183
+ product_info = [stock_amount]
184
+
185
+ products.append((name, product_info, full_name))
186
+
187
+ print(f"Toplam {len(products)} ürün yüklendi.")
188
+
189
+ # Initialize enhanced features
190
+ initialize_enhanced_features(OPENAI_API_KEY, products)
191
+
192
+ # Google Drive API ayarları
193
+ GOOGLE_CREDENTIALS_PATH = os.getenv("GOOGLE_CREDENTIALS_PATH")
194
+ GOOGLE_FOLDER_ID = "1bE8aMj8-eFGftjMPOF8bKQJAhfHa0BN8"
195
+
196
+ # Global değişkenler
197
+ file_lock = threading.Lock()
198
+ history_lock = threading.Lock()
199
+ global_chat_history = []
200
+ document_content = ""
201
+
202
+ # Google Drive'dan döküman indirme fonksiyonu
203
+ def download_documents_from_drive():
204
+ global document_content
205
+
206
+ if not GOOGLE_CREDENTIALS_PATH:
207
+ print("Google credentials dosyası bulunamadı.")
208
+ return
209
+
210
+ try:
211
+ credentials = Credentials.from_service_account_file(GOOGLE_CREDENTIALS_PATH)
212
+ service = build('drive', 'v3', credentials=credentials)
213
+
214
+ # Klasördeki dosyaları listele
215
+ results = service.files().list(
216
+ q=f"'{GOOGLE_FOLDER_ID}' in parents",
217
+ fields="files(id, name, mimeType)"
218
+ ).execute()
219
+
220
+ files = results.get('files', [])
221
+ all_content = []
222
+
223
+ for file in files:
224
+ print(f"İndiriliyor: {file['name']}")
225
+
226
+ # DOCX dosyaları için
227
+ if file['mimeType'] == 'application/vnd.openxmlformats-officedocument.wordprocessingml.document':
228
+ request = service.files().get_media(fileId=file['id'])
229
+ file_io = io.BytesIO()
230
+ downloader = MediaIoBaseDownload(file_io, request)
231
+
232
+ done = False
233
+ while done is False:
234
+ status, done = downloader.next_chunk()
235
+
236
+ file_io.seek(0)
237
+ doc = Document(file_io)
238
+
239
+ content = f"\\n=== {file['name']} ===\\n"
240
+ for paragraph in doc.paragraphs:
241
+ if paragraph.text.strip():
242
+ content += paragraph.text + "\\n"
243
+
244
+ all_content.append(content)
245
+
246
+ document_content = "\\n".join(all_content)
247
+ print(f"Toplam {len(files)} döküman yüklendi.")
248
+
249
+ except Exception as e:
250
+ print(f"Google Drive'dan döküman indirme hatası: {e}")
251
+
252
+ # Döküman indirme işlemini arka planda çalıştır
253
+ document_thread = threading.Thread(target=download_documents_from_drive, daemon=True)
254
+ document_thread.start()
255
+
256
+ # Log dosyasını zamanla temizleme fonksiyonu
257
+ def clear_log_file():
258
+ try:
259
+ if os.path.exists(LOG_FILE):
260
+ with file_lock:
261
+ with open(LOG_FILE, 'w', encoding='utf-8') as f:
262
+ f.write("Log dosyası temizlendi.\\n")
263
+ print("Log dosyası temizlendi.")
264
+ except Exception as e:
265
+ print(f"Log dosyası temizleme hatası: {e}")
266
+
267
+ # Zamanlanmış görevleri çalıştırma fonksiyonu
268
+ def run_scheduler(chat_history):
269
+ schedule.every().day.at("03:00").do(clear_log_file)
270
+
271
+ while True:
272
+ schedule.run_pending()
273
+ time.sleep(60)
274
+
275
+ # Chatbot fonksiyonu
276
+ def chatbot_fn(user_message, history, image=None):
277
+ if history is None:
278
+ history = []
279
+
280
+ try:
281
+ # Enhanced features - Görsel işleme
282
+ if image is not None:
283
+ user_message = process_image_message(image, user_message)
284
+
285
+ # Enhanced features - Karşılaştırma kontrolü
286
+ comparison_result = handle_comparison_request(user_message)
287
+ if comparison_result:
288
+ yield comparison_result
289
+ return
290
+
291
+ # Enhanced features - Basit karşılaştırma ve görsel işleme
292
+ # Profil sistemi kaldırıldı - daha hızlı çalışma için
293
+
294
+ except Exception as e:
295
+ print(f"Enhanced features error: {e}")
296
+ # Enhanced features hata verirse normal chatbot'a devam et
297
+
298
+ # Log: Kullanıcı mesajını ekle
299
+ try:
300
+ with file_lock:
301
+ with open(LOG_FILE, 'a', encoding='utf-8') as f:
302
+ f.write(f"User: {user_message}\\n")
303
+ except Exception as e:
304
+ print(f"Dosya yazma hatası (Kullanıcı): {e}")
305
+
306
+ # Sistem mesajlarını external dosyadan yükle
307
+ system_messages = get_prompt_content_only()
308
+
309
+ # Döküman verilerini sistem mesajlarına ekle
310
+ if document_content:
311
+ system_messages.append({"role": "system", "content": f"Dökümanlardan gelen bilgiler: {document_content}"})
312
+
313
+ # Profil sistemi kaldırıldı - daha hızlı çalışma için
314
+
315
+ # Kullanıcı mesajında ürün ismi geçiyorsa ekle
316
+ input_words = user_message.lower().split()
317
+ for word in input_words:
318
+ for product_info in products:
319
+ if word in product_info[0] or word in product_info[2].lower():
320
+ # Stokta olup olmadığını kontrol et
321
+ if product_info[1][0] == "stokta":
322
+ # Normal fiyat
323
+ normal_price = f"\\nFiyat: {product_info[1][1]} TL"
324
+
325
+ # Kampanyalı fiyat kontrolü
326
+ rebate_price = ""
327
+ discount_info = ""
328
+ eft_price = ""
329
+ rebate_money_order_price = ""
330
+
331
+ # Kampanyalı fiyat var mı kontrol et
332
+ if len(product_info[1]) > 4 and product_info[1][4] and product_info[1][4] != "":
333
+ rebate_price = f"\\nKampanyalı fiyat: {product_info[1][4]} TL"
334
+
335
+ # İndirim miktarını hesapla
336
+ try:
337
+ normal_price_float = float(product_info[1][1])
338
+ rebate_price_float = float(product_info[1][4])
339
+ discount_amount = normal_price_float - rebate_price_float
340
+
341
+ # İndirim miktarı 0'dan büyükse göster
342
+ if discount_amount > 0:
343
+ # İndirim miktarı için yuvarlama kurallarını uygula
344
+ if discount_amount > 200000:
345
+ discount_amount_rounded = round(discount_amount / 5000) * 5000
346
+ elif discount_amount > 30000:
347
+ discount_amount_rounded = round(discount_amount / 1000) * 1000
348
+ elif discount_amount > 10000:
349
+ discount_amount_rounded = round(discount_amount / 100) * 100
350
+ else:
351
+ discount_amount_rounded = round(discount_amount / 10) * 10
352
+
353
+ # İndirim bilgisi
354
+ discount_info = f"\\nYapılan indirim: {discount_amount_rounded:.0f} TL"
355
+ except (ValueError, TypeError):
356
+ discount_info = ""
357
+
358
+ # Havale indirimli kampanyalı fiyat bilgisini gösterme
359
+ rebate_money_order_price = ""
360
+ else:
361
+ # Kampanyalı değilse, havale indirimli normal fiyatı göster
362
+ if product_info[1][3] and product_info[1][3] != "":
363
+ eft_price = f"\\nHavale indirimli fiyat: {product_info[1][3]} TL"
364
+
365
+ # Ürün linki ve resim
366
+ product_link = f"\\nÜrün linki: {product_info[1][2]}"
367
+ product_image = ""
368
+ if len(product_info[1]) > 6 and product_info[1][6]: # Resim URL'si varsa
369
+ product_image = f"\\nÜrün resmi: {product_info[1][6]}"
370
+
371
+ # Tüm bilgileri birleştir
372
+ new_msg = f"{product_info[2]} {product_info[1][0]}\\n{normal_price}{rebate_price}{discount_info}{eft_price}{rebate_money_order_price}{product_link}{product_image}"
373
+ else:
374
+ # Ürün stokta yoksa sadece stok durumunu bildir
375
+ new_msg = f"{product_info[2]} {product_info[1][0]}"
376
+ system_messages.append({"role": "system", "content": new_msg})
377
+
378
+ messages = system_messages + history + [{"role": "user", "content": user_message}]
379
+
380
+ payload = {
381
+ "model": "gpt-5",
382
+ "messages": messages,
383
+ "temperature": 0.1,
384
+ "top_p": 0.9,
385
+ "n": 1,
386
+ "stream": True,
387
+ "presence_penalty": 0.1,
388
+ "frequency_penalty": 0,
389
+ }
390
+ headers = {
391
+ "Content-Type": "application/json",
392
+ "Authorization": f"Bearer {OPENAI_API_KEY}"
393
+ }
394
+
395
+ response = requests.post(API_URL, headers=headers, json=payload, stream=True, timeout=120)
396
+ if response.status_code != 200:
397
+ yield "Bir hata oluştu."
398
+ return
399
+
400
+ partial_response = ""
401
+
402
+ for chunk in response.iter_lines():
403
+ if not chunk:
404
+ continue
405
+ chunk_str = chunk.decode('utf-8')
406
+ if chunk_str.startswith("data: ") and chunk_str != "data: [DONE]":
407
+ try:
408
+ chunk_data = json.loads(chunk_str[6:])
409
+ delta = chunk_data['choices'][0]['delta']
410
+ if 'content' in delta:
411
+ partial_response += delta['content']
412
+ # Resim formatlaması uygula
413
+ formatted_response = extract_product_info_for_gallery(partial_response)
414
+ yield formatted_response
415
+ except json.JSONDecodeError as e:
416
+ print(f"JSON parse hatası: {e} - Chunk: {chunk_str}")
417
+ elif chunk_str == "data: [DONE]":
418
+ break
419
+
420
+ # Son resim formatlaması
421
+ final_response = extract_product_info_for_gallery(partial_response)
422
+ yield final_response
423
+
424
+ # Profil kaydetme kaldırıldı - daha hızlı çalışma için
425
+
426
+ # Log: Asistan cevabını ekle
427
+ try:
428
+ with file_lock:
429
+ with open(LOG_FILE, 'a', encoding='utf-8') as f:
430
+ f.write(f"Bot: {partial_response}\\n")
431
+ except Exception as e:
432
+ print(f"Dosya yazma hatası (Bot): {e}")
433
+
434
+ # Global geçmişi güncelle
435
+ with history_lock:
436
+ global_chat_history.append({"role": "user", "content": user_message})
437
+ global_chat_history.append({"role": "assistant", "content": partial_response})
438
+
439
+ # Slow echo (test için)
440
+ def slow_echo(message, history):
441
+ for i in range(len(message)):
442
+ time.sleep(0.05)
443
+ yield "You typed: " + message[: i + 1]
444
+
445
+ # Kullanım modu
446
+ USE_SLOW_ECHO = False
447
+ chat_fn = slow_echo if USE_SLOW_ECHO else chatbot_fn
448
+
449
+ if not USE_SLOW_ECHO:
450
+ scheduler_thread = threading.Thread(target=run_scheduler, args=(global_chat_history,), daemon=True)
451
+ scheduler_thread.start()
452
+
453
+ # Trek markasına özel tema oluştur (düzeltilmiş sürüm)
454
+ trek_theme = gr.themes.Base(
455
+ primary_hue="red", # Trek kırmızısı için
456
+ secondary_hue="slate", # Gri tonları için
457
+ neutral_hue="slate",
458
+ radius_size=gr.themes.sizes.radius_sm, # Köşe yuvarlatma değerleri
459
+ spacing_size=gr.themes.sizes.spacing_md, # Aralık değerleri
460
+ text_size=gr.themes.sizes.text_sm # Yazı boyutları (small)
461
+ )
462
+ # Chatbot kartları için arka plan renkleri değiştiren CSS
463
+ custom_css = """
464
+ /* Genel font ayarları */
465
+ .gradio-container, .gradio-container *, .message-wrap, .message-wrap p, .message-wrap div,
466
+ button, input, select, textarea {
467
+ font-family: 'Segoe UI', 'SF Pro Text', 'Roboto', -apple-system, BlinkMacSystemFont,
468
+ 'Helvetica Neue', Arial, sans-serif !important;
469
+ font-size: 0.6rem !important;
470
+ }
471
+
472
+ /* Mobil responsive başlangıç */
473
+ @media (max-width: 768px) {
474
+ .gradio-container, .gradio-container *, .message-wrap, .message-wrap p, .message-wrap div {
475
+ font-size: 0.8rem !important;
476
+ }
477
+
478
+ h1 {
479
+ font-size: 1.8rem !important;
480
+ text-align: center;
481
+ margin: 10px 0;
482
+ }
483
+
484
+ h2 {
485
+ font-size: 1.4rem !important;
486
+ }
487
+ }
488
+
489
+ /* Input alanı için de aynı boyut */
490
+ .message-textbox textarea {
491
+ font-size: 0.6rem !important;
492
+ }
493
+
494
+ /* Başlıklar için özel boyutlar */
495
+ h1 {
496
+ font-size: 1.4rem !important;
497
+ font-weight: 800 !important;
498
+ }
499
+
500
+ h2 {
501
+ font-size: 1.2rem !important;
502
+ font-weight: 600 !important;
503
+ }
504
+
505
+ h3 {
506
+ font-size: 1rem !important;
507
+ font-weight: 600 !important;
508
+ }
509
+
510
+ /* Kart arka plan renkleri - görseldeki gibi */
511
+ /* Kullanıcı mesajları için mavi tonda arka plan */
512
+ .user-message, .user-message-highlighted {
513
+ background-color: #e9f5fe !important;
514
+ border-bottom-right-radius: 0 !important;
515
+ box-shadow: 0 1px 2px rgba(0,0,0,0.1) !important;
516
+ }
517
+
518
+ /* Bot mesajları için beyaz arka plan ve hafif kenarlık */
519
+ .bot-message, .bot-message-highlighted {
520
+ background-color: white !important;
521
+ border: 1px solid #e0e0e0 !important;
522
+ border-bottom-left-radius: 0 !important;
523
+ box-shadow: 0 1px 2px rgba(0,0,0,0.05) !important;
524
+ }
525
+
526
+ /* Mesaj baloncuklarının köşe yuvarlatma değerleri */
527
+ .message-wrap {
528
+ border-radius: 12px !important;
529
+ margin: 0.5rem 0 !important;
530
+ max-width: 90% !important;
531
+ }
532
+
533
+ /* Sohbet alanının genel arka planı */
534
+ .chat-container, .gradio-container {
535
+ background-color: #f7f7f7 !important;
536
+ }
537
+
538
+ /* Daha net yazılar için text rendering */
539
+ * {
540
+ -webkit-font-smoothing: antialiased;
541
+ -moz-osx-font-smoothing: grayscale;
542
+ text-rendering: optimizeLegibility;
543
+ }
544
+
545
+ /* Restore butonu stilleri kaldırıldı */
546
+
547
+ /* Responsive mobil tasarım - iOS benzeri */
548
+ @media (max-width: 768px) {
549
+ /* Daha büyük ve dokunmatik dostu boyutlar */
550
+ .gradio-container {
551
+ padding: 0 !important;
552
+ margin: 0 !important;
553
+ }
554
+
555
+ /* Mesaj baloncukları iOS tarzı */
556
+ .message-wrap {
557
+ margin: 0.3rem 0.5rem !important;
558
+ max-width: 85% !important;
559
+ border-radius: 18px !important;
560
+ padding: 10px 15px !important;
561
+ font-size: 0.9rem !important;
562
+ }
563
+
564
+ /* Kullanıcı mesajları */
565
+ .user-message, .user-message-highlighted {
566
+ background-color: #007AFF !important;
567
+ color: white !important;
568
+ margin-left: auto !important;
569
+ margin-right: 8px !important;
570
+ }
571
+
572
+ /* Bot mesajları */
573
+ .bot-message, .bot-message-highlighted {
574
+ background-color: #f1f1f1 !important;
575
+ color: #333 !important;
576
+ margin-left: 8px !important;
577
+ margin-right: auto !important;
578
+ }
579
+ }
580
+
581
+ /* Input alanına uçan kağıt ikonu ekle */
582
+ #msg-input {
583
+ position: relative;
584
+ }
585
+
586
+ #msg-input textarea {
587
+ padding-right: 40px !important;
588
+ }
589
+
590
+ .input-icon {
591
+ position: absolute;
592
+ right: 12px;
593
+ top: 50%;
594
+ transform: translateY(-50%);
595
+ font-size: 16px;
596
+ pointer-events: none;
597
+ z-index: 10;
598
+ color: #666;
599
+ }
600
+
601
+ /* Mobil responsive - Input alanı */
602
+ @media (max-width: 768px) {
603
+ #msg-input {
604
+ margin: 10px 0;
605
+ }
606
+
607
+ #msg-input textarea {
608
+ padding: 12px 45px 12px 15px !important;
609
+ font-size: 1rem !important;
610
+ border-radius: 20px !important;
611
+ border: 1px solid #ddd !important;
612
+ box-shadow: 0 1px 3px rgba(0,0,0,0.1) !important;
613
+ }
614
+
615
+ .input-icon {
616
+ right: 15px;
617
+ font-size: 18px;
618
+ }
619
+ }
620
+
621
+ /* Genel mobil iyileştirmeler */
622
+ @media (max-width: 768px) {
623
+ /* Chatbot alanı tam ekran */
624
+ .gradio-container .main {
625
+ padding: 0 !important;
626
+ }
627
+
628
+ /* Başlık alanı küçült */
629
+ .gradio-container header {
630
+ padding: 8px !important;
631
+ }
632
+
633
+ /* Tab alanlarını küçült */
634
+ .tab-nav {
635
+ padding: 5px !important;
636
+ }
637
+
638
+ /* Scroll bar'ı gizle */
639
+ .scroll-hide {
640
+ scrollbar-width: none;
641
+ -ms-overflow-style: none;
642
+ }
643
+
644
+ .scroll-hide::-webkit-scrollbar {
645
+ display: none;
646
+ }
647
+ }
648
+
649
+ /* CSS Bitişi */
650
+ """
651
+
652
+ # Chat persistence sistemi tamamen kaldırıldı
653
+ storage_js = ""
654
+
655
+ # Enhanced chatbot fonksiyonu image destekli
656
+ def enhanced_chatbot_fn(message, history, image):
657
+ return chatbot_fn(message, history, image)
658
+
659
+ # Demo arayüzü - Mobil responsive
660
+ with gr.Blocks(css=custom_css, theme="soft", title="Trek Asistanı", head=storage_js) as demo:
661
+ gr.Markdown("# 🚲 Trek Asistanı AI")
662
+ gr.Markdown("**Akıllı özellikler:** Ürün karşılaştırması ve detaylı ürün bilgileri sunuyorum.")
663
+
664
+ # LocalStorage fonksiyonu kaldırıldı
665
+
666
+ chatbot = gr.Chatbot(height=600, elem_id="chatbot", show_label=False)
667
+
668
+ msg = gr.Textbox(
669
+ placeholder="Trek bisikletleri hakkında soru sorun...",
670
+ show_label=False,
671
+ elem_id="msg-input"
672
+ )
673
+
674
+ # Restore button tamamen kaldırıldı
675
+
676
+ # Session ve profil sistemi tamamen kaldırıldı
677
+
678
+ def respond(message, chat_history):
679
+ if not message.strip():
680
+ return "", chat_history
681
+
682
+ # Kullanıcı mesajını hemen göster
683
+ if chat_history is None:
684
+ chat_history = []
685
+
686
+ # Kullanıcı mesajını ekle ve hemen yield et
687
+ chat_history.append((message, None))
688
+ yield "", chat_history
689
+
690
+ # Chat history'yi chatbot_fn için uygun formata çevir (son mesaj hariç)
691
+ formatted_history = []
692
+ if len(chat_history) > 1: # Son mesajı hariç tut
693
+ for user_msg, bot_msg in chat_history[:-1]:
694
+ if bot_msg: # Sadece tamamlanmış mesajlar
695
+ formatted_history.append({"role": "user", "content": user_msg})
696
+ formatted_history.append({"role": "assistant", "content": bot_msg})
697
+
698
+ try:
699
+ # Enhanced chatbot fonksiyonunu çağır (image=None)
700
+ response_generator = chatbot_fn(message, formatted_history, None)
701
+
702
+ # Generator'dan streaming cevap al
703
+ response = ""
704
+ for partial in response_generator:
705
+ response = partial
706
+ # Son mesajı güncelle ve yield et
707
+ chat_history[-1] = (message, response)
708
+ yield "", chat_history
709
+
710
+ # Chat kaydetme sistemi kaldırıldı
711
+
712
+ except Exception as e:
713
+ error_msg = f"Üzgünüm, bir hata oluştu: {str(e)}"
714
+ print(f"Chat error: {e}")
715
+ # Hata mesajıyla güncelle
716
+ chat_history[-1] = (message, error_msg)
717
+ yield "", chat_history
718
+
719
+ msg.submit(respond, [msg, chatbot], [msg, chatbot], show_progress=True)
720
+
721
+ if __name__ == "__main__":
722
+ demo.launch(debug=True)
723
+ demo.queue(max_size=20, default_concurrency_limit=5)