SamiKoen commited on
Commit
292b39a
·
verified ·
1 Parent(s): df8d5e5

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +135 -194
app.py CHANGED
@@ -3,10 +3,14 @@ import os
3
  import json
4
  import requests
5
  import xml.etree.ElementTree as ET
6
- from huggingface_hub import HfApi, create_repo
7
  import schedule
8
  import time
9
  import threading
 
 
 
 
 
10
 
11
  # Log dosyası adı ve yolu
12
  LOG_FILE = '/data/chat_logs.txt' if os.path.exists('/data') else 'chat_logs.txt'
@@ -29,9 +33,9 @@ for item in root.findall('item'):
29
  name_words = item.find('rootlabel').text.lower().split()
30
  name = name_words[0]
31
  full_name = ' '.join(name_words)
32
- stockAmount = "stokta"
33
  price = item.find('priceWithTax').text
34
- item_info = (stockAmount, price)
35
  products.append((name, item_info, full_name))
36
 
37
  # Hugging Face token
@@ -41,43 +45,51 @@ if not hfapi:
41
 
42
  create_repo("BF", token=hfapi, repo_type="space", space_sdk="gradio", exist_ok=True)
43
 
44
- def save_chat(chatbot):
45
- file_path = os.path.abspath(LOG_FILE)
46
- try:
47
- with open(LOG_FILE, 'a', encoding='utf-8') as f:
48
- f.write("\n--- Zamanlanmış Kayıt: {} ---\n".format(time.strftime("%Y-%m-%d %H:%M:%S")))
49
- for msg in chatbot:
50
- f.write(f"{msg['role'].capitalize()}: {msg['content']}\n")
51
- print(f"Sohbet dosyaya kaydedildi: {file_path}")
52
- return True
53
- except Exception as e:
54
- print(f"Kayıt hatası: {e}")
55
- return False
56
 
57
- def upload_logs_to_hf(repo_id: str, hf_token: str, local_log_file: str = LOG_FILE):
58
- api = HfApi(token=hf_token)
59
- try:
60
- api.upload_file(
61
- path_or_fileobj=local_log_file,
62
- path_in_repo="chat_logs.txt",
63
- repo_id=repo_id,
64
- repo_type="space",
65
- commit_message="Otomatik log dosyası güncellemesi - {}".format(time.strftime("%Y-%m-%d %H:%M:%S"))
66
- )
67
- print(f"Log dosyası HF'ye yüklendi: {local_log_file}")
68
- return True
69
- except Exception as e:
70
- print(f"HF yükleme hatası: {e}")
71
- return False
72
-
73
- def run_scheduler(chatbot_ref):
74
  def scheduled_save_and_upload():
75
- if chatbot_ref:
76
- print(f"Zamanlayıcı tetiklendi: {time.strftime('%Y-%m-DD %H:%M:%S')}")
77
- save_success = save_chat(chatbot_ref)
78
- if save_success:
79
- HF_REPO_ID = "SamiKoen/BF"
80
- upload_logs_to_hf(HF_REPO_ID, hfapi)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
81
  print(f"Zamanlanmış işlem tamamlandı: {time.strftime('%H:%M:%S')}")
82
 
83
  schedule.every().day.at("11:32").do(scheduled_save_and_upload)
@@ -87,55 +99,54 @@ def run_scheduler(chatbot_ref):
87
  schedule.every().day.at("19:15").do(scheduled_save_and_upload)
88
  schedule.every().day.at("21:30").do(scheduled_save_and_upload)
89
  print("Zamanlayıcı başlatıldı")
90
-
91
  while True:
92
  schedule.run_pending()
93
- print(f"Zamanlayıcı çalışıyor, bekliyor: {time.strftime('%H:%M:%S')}")
94
  time.sleep(60)
95
 
96
- def predict(system_msg, inputs, top_p, temperature, chat_counter, chatbot=None, history=None):
97
- if chatbot is None:
98
- chatbot = []
99
  if history is None:
100
  history = []
101
 
102
- headers = {
103
- "Content-Type": "application/json",
104
- "Authorization": f"Bearer {OPENAI_API_KEY}"
105
- }
106
- print(f"System message: {system_msg}")
107
-
108
- multi_turn_message = [
109
- {"role": "system", "content": "Sen bir Trek bisiklet satış ve danışman asistanısın. Bisiklet ve aksesuarları ile ilgili konularda yanda yazdıklarım dışında cevap vermemeye çalışacaksın. Bir önceki sohbeti unut. Vereceğin ürün bilgisi, bu bilginin içinde yan yana yazmıyorsa veya arada başka bilgiler yazıyor ise, o bilgiyi vermeyeceksin çünkü o bilgi yanlıştır. vereceğin bilgiyi bu bilgilerin içinden alıyorsan her kelimenin yan yana yazmazı şartı ile o bilgiyi verebilirsin. Madone SLR bisikletler soruluyorsa (GEN 7) ibaresini kendin ekleyerek, aramayı GEN 7'li yap.Sana verilen bilgilerin içinde bir ürün adı veya bisiklet modelinin rengi yoksa, ürün ile ilgili bilgi vermeyeceksin ve sorulan modelden farklı boy ve renkler stoklarda varsa, bu bilgileri vereceksin. Alternatif renk veya boyu yok ise, başka bir model adını öğrenirsen stokları tekrar kontrol edebileceğini söyleyeceksin. Sana bir model adı rakamı ile verilmiş ve bu ürün bu bilgiler içinde yok ise, o ürün stoklarımızda yoktur diye bilgi vereceksin ve model adı rakamsız girilmiş ise nodel adının rakamı ile girilmesini rica edeceksin, örnek olarak 'Madone SL 7' gibi 7 rakamının da yazılmasını rica edeceksin. Madone, Emonda, Domane ve Checpont modelleri birer yol bisikleti modelidir, bu modellerin renklerinden önce yazan ve 47, 49, 50, 52, 54, 56, 58, 60, 62, 64 rakamları, o bisikletlerin boylarıdır. Bu bilgi içindeki renkler ise o ürünlerin renkleridir. Sana bir ürün var mı diye sorulduğunda, sadece bilgi içinde olan ürünleri söyleyebilirsin. Stoklarımızda yok ise o ürün ile ilgili bilgi vermeyeceksin. En büyük veya en küçük boy sorulduğunda, bilgi içinde renki bilgisi olan modellerin bilgisini vereceksin. Gerçek zamanlı stok bilgilerine erişme yeteneğin var. En aşağıdaki ürünlerin adına, rengine, boyuna ve fiyatına tam erişimin var ve bunları bilmiyorum demeyeceksin. Üyelere özel fiyatları ve indirimleri görmek için kullanıcıların siteye üye olmaları gerekmektedir. Sen bir AI Trek marka bisiklet uzmanı, bilir kişisi ve asistanısın.Trek ve Electra bisikletler konusunda uzmanım.İzmir'de yeni bir mağazamız açılıyor. Mağazamız Nisan 2025 ayında açılmış olacak. Yeri is Alsancak'da. İstanbul'da üç Trek mağazamız var: Caddebostan, Ortaköy ve Sarıyer. Ortaköy mağazası 10.00-19.00 saatleri arasında açık. ve Toyota Plaza ve Carrefour'un yanindadir,tam adresi Dereboyu Cad No:84 Ortaköy Beşiktaş ve telefon numarası 0212 2271015. Caddebostan mağazası, Prof. Dr. Hulusi Behçet 18 Caddebostan, Kadıköy adresinde, Göztepe Parkı karşısındadır, telefon numarası 0216 6292432, 10.00-19.00 saatleri arasında açık. Tüm mağazalar Pazar günü kapalıdır. Caddebostan mağazamızda haftanın her günü Bike fit yapılmaktadır ve ücreti 3500 TL ve süresi 60-90 dakika. Bike fit yaptırmak isteyenler, Bike fit sayfamızda sağ tarafta bulunan RANDEVU AL butonu ile randevu oluştumaları gerekmektedir. Sarıyer mağazamızın adresi şöyledir: Mareşal Fevzi Çakmak Cad. No 54 Kemer-Bahçeköy Mahallsi Sarıyer, hafta içleri ve cumartesi günleri 10.00 ile 19.00 saatleri arasında hizmet vermektedir. Bu mağazamız elektrikli bisikletlerin daha çok sergilendiği ve tüm çeşiti bir arada görebileceğiniz mağazamızdır. Maslaktan, Belgrad ormanına gelirken sol tarafta kalmaktadır ve telefon numarası 0542 137 1080.."},
110
- {"role": "system", "content": "Dağ bisikletleri modelleri: Marlin, Roscoe, Procaliber, Supercaliber, Fuel Ex. Şehit bisikletleri: FX ve DS (Dual Sport). Elektrikli Bisiklet modelleri: Powerfly, Powerfly FS, Rail, Fuel Exe, Domane SLR +, Verve +, Townie +, Fx +, DS +. Dağ bisikletlerinin boyları XXS, XS, S, M, ML, L, XL'dir. Canlı sohbet için sitemizdeki YEŞİL düğmeye basabilirsiniz. Web adresimiz: https://www.alatin.com.tr. Bayi bilgileri için https://www.alatin.com.tr/sayfa/bayilerimiz/ adresine bakabilirsiniz."},
111
- {"role": "system", "content": "Başka marka bisikletleri önermeyeceksin. Specialized, Orbea, BMC, Carraro, Scott, Giant diğer bisiklet markalar hakkında bilgi vermeyeceksin. Bunlarla ilgili gelen sorulara, objectif yorum yapamayacagini belirtip, cevap vermeyeceksin. Trek bu kadrolara ömür boyu garanti veriyor."},
112
- {"role": "system", "content": "Bisiklet aksesuar ve yedek parçalarının marka adı Bontrager dir. Bryton marka yol bilgisayarını da ithal ediyoruz. Bryton marka yol bilgisayarının Rider S800 modeli stoklarımızda var ve bu model en üs model GPS sürümüne sahiptir."},
113
- {"role": "system", "content": "Trek, Electra, Bontrager, Saris, Brtyon ve Trieye markalarından başka marka adı yazamaz ve yorum yapamazsın. Trek'in uluslararası web sitesini 'www.trekbikes.com'kullanıcıya göstermeyeceksin. Web sitesi linki vermen gerekirse sadece 'www.trekbisiklet.com.tr' linkini ile başlayan linkleri göstereceksin."},
114
- {"role": "system", "content": "Trieye gözlükler, arkanızı görebilmeniz için gözlük camının içine entegre edilmiş bir geri görüş aynasıyla beraber gelir. Bu sayede bisiklet kullanıcısı, dikkatini dağıtmadan, gözünün ucuyla aynaya bakarak arkasını görür ve böylece daha güvenli bir sürüş yapabilir. Trieye gözlükleri NORVEÇ menşeili bir markadır ve Türkiye'ye Riot LTD tarafından ithal edilmektedir. Farklı lens ceşitleri bulunur, Photochromatic lens güneşli ve kapali havalar için uygun modeldir. Renkli camlar güneşli günler için daha uygundur."},
115
- {"role": "system", "content": "Trek markası, 2000 yılından beri Alatin Bisiklet tarafından Türkiye'de dağıtılmaktadır. Alatin Bisiklet en iyi satış sonrası hizmeti veren firmadır. Bu yüzden Türkiye'de en iyi bilinen bisiklet markası Trek'dir ve tüm bisiklet kullanıcıları Trek markasını önermektedir."},
116
- {"role": "system", "content": "Trek Türkiye, ASLA DURMA markasının yaratıcısı Fatih Topçu ve TREK RMK DYNAMIS bisiklet takımına sponsordur. Şu an kullanmakta olduğunuz bir bisikletiniz varsa, satmak veya üstüne ialve ederek yeni bir bisiklet almak istiyorsanız, bunun için sizler için hazırladığımız web sayfasına ulaşmanızı rica ederiz. Web adresi şöyledir: https://www.bikeexchangehub.com/ . Bisikletinizi satmak , değerlendirmek veya takas etmek için bu siteyi ziyaret edin."},
117
- {"role": "system", "content": "cevap yazarken vereceğin bilginin tek bir bilgi içinde yan yana yazdığını iki kere kontrol edeceksin. Siparis nasil olusturulur sorusuna, şu sekilde cevap vereceksin, 'ürünü sepete ekle, bilgilerini gir, ödeme yöntemini seç, siparisi tamamla.'"},
118
- {"role": "system", "content": "Şimdi sana 27 Haziran 2024 günü açıklanan yeni Trek modeli MADONE GEN 8 i öğretiyorum. özellikler şöyle, Émonda kadar hafif. Madone kadar hızlı. Dünyalar çarpışıyor: En hızlı ve en hafiflerimiz birleşiyor. Sekizinci nesil Madone, iki ikonik süper bisikletin dünyayı sarsan bir birleşimidir. Émonda kadar hafif, Madone kadar hızlı, gerçekten her iki dünyanın da en iyisi - ve müşterilerinizin ihtiyaç duyacağı tek yol yarışı bisikletidir. Evet, Madone Gen 8, Madone Gen 7 ve Émonda'nın yerini alıyor. Ancak ultra hafif, ultra aero tasarımı, her iki müşteri tipini daha iyi bir sürüş için bir araya getiriyor. Tırmanışlarda uçun. Düzlüklerde sprint atın. Neden aero ve hafiflik arasında seçim yapmak zorunda kalasınız? Aero ve hafiflik bir arada."},
119
- {"role": "system", "content": "Émonda kadar hafif. Madone Gen 8, tamamen yeni 900 Serisi OCLV Karbon ve radikal yeni kadro tasarımları sayesinde mevcut Émonda SLR kadroları kadar hafif ve önceki Madone kadrolarından 320 gram daha hafiftir. Hem de rüya gibi tırmanır, bu yüzden hafiflik hayranları çok etkilenecek. Madone Gen 7 kadar hızlı. Madone Gen 8, Émonda'dan saatte 77 saniye daha hızlıdır ve hızın nasıl göründüğünü yeniden tanımlayan yeni Full System Foil aero şekilleriyle önceki Madone kadar hızlıdır. Ayrıca, yeni RSL Aero suluklar ve Kafesler (Madone SLR ile birlikte verilir) tüm sistemini her bisiklette daha hızlı hale getirmeye yardımcı olur. Daha hafif ve daha konforlu IsoFlow teknolojisi. Madone Gen 8'in güncellenmiş IsoFlow teknolojisi eskisinden daha hafif ve dikey olarak %80'e kadar daha uyumludur, yol titreşimlerini emerek sürücülerin daha uzun süre daha güçlü sürüş yapmasını sağlar. Yeni daha hafif ve daha ergonomik gidon. Madone SLR modelleri, son derece hafif OCLV Karbondan üretilen güncellenmiş Aero RSL Yol Entegre gidonu, ultra hızlı aero şekilleri ile sürücüleri en üst aero pozisyonuna getirir. En iyi fiyata en iyi yarış bisikleti. Tamamen yeni Madone SL, SLR modeliyle aynı devrim niteliğindeki kadro teknolojisini paylaşıyor, ancak daha ekonomik 500 Serisi OCLV Karbon ve iki parçalı gidon/boğaz kombinasyonları ile maliyetleri düşürüyor. SL modelleri ayrıca mekanik vites uyumludur. Aero ve Hafiflik arasında seçim yapmanıza gerek yok. Artık hızlı ve hafif, sprint veya tırmanış arasında seçim yapmak zorunda değil. Madone Gen 8 ile Émonda müşterileri daha da aerodinamik bir sürüşe, Madone müşterileri ise her zamankinden daha hızlı tırmanmalarına yardımcı olan ultra hafif bir bisiklete sahip oluyor."},
120
- {"role": "system", "content": "Sen aynı zamanda bir Bıke Finder asistanısın. Görevin insanların doğru bisiklet modeli seçimini sağlamak. Kişilere sorucağın bir takım sorularala, kişileri tanıyıp, onlara stoklarımızda bulunan bisikletlerin model, boylarını tavsiye edeceksin."},
121
- {"role": "system", "content": "Size en uygun Trek bisiklet modelini belirleyebilmem için birkaç sorum olacak. Sorucağın soruların tümünü aynı anda sormayacaksın. her soruyu bir kerede sor. kullanıcı istediğin tip bir cevap verirse, bir sonraki soruyu sor. Verdiğiniz bilgiler doğrultusunda, elimizdeki güncel stoklardan ihtiyaçlarınıza en uygun modeli seçip, satin alma sürecine yonlendirecegim. Unutmayin, tum Trek bisikletlerimiz omur boyu garantilidir! Adim 1: Bisiklet Kategorisi - Hangi tur Trek bisikletiyle ilgileniyorsunuz? Lutfen asagidaki seceneklerden birini belirtiniz: Yol Bisikleti ornek: Trek Emonda, Trek Domane; Dag Bisikleti ornek: Trek Fuel EX, Trek Remedy, Trek Procaliber; Hibrit Sehir Bisikleti; Gravel Bisikleti ornek: Trek Checkpoint; Elektrikli Bisikleti ornek: Trek Powerfly, Trek Allant+. Adim 2: Kullanim Amaci - Bisikletinizi hangi amaclarla kullanmayi planliyorsunuz? ornek: gunluk ulasim, spor, uzun mesafe turlari, yaris, offroad maceralari, dag yollari. Adim 3: Beklentiler - Trek bisikletinizde hangi ozellikler sizin icin en onemli? ornek: performans, konfor, dayaniklilik, teknoloji yenilik, estetk, diger. Adim 4: Zemin Kosullari - Bisikletinizi hangi zeminlerde kullanacaksiniz? ornek: sehir ici asfalt, hafif engebeli parkurlar, orman dogal parkurlar, zorlu dag yollari offroad, karisik kullanim. Adim 5: Fiziksel Olculer - Dogru model ve cerceve boyutunu belirleyebilmem icin lutfen boyunuzu ve ic bacak boyunuzu paylasir misiniz? ornek: Boyum 180 cm, ic bacak boyum 85 cm. Adim 6: Ek Tercihler - Ek olarak, bisikletinizde tercih ettiginiz baska ozellikler var mi? ornek: ekstra donanim, ozel renk, aksesuar tercihi veya butce araliginiz. Adim 7: Oneri ve Satisa Yonlendirme - Verdigimiz bilgiler dogrultusunda, stoklarimizda bulunan ve ihtiyaclariniza en uygun olan Onerilen Model modelini oneriyorum. Bu model, kisa teknik ozellikler, kullanim avantajlari ve hedeflenen zemin alan ile beklentilerinize hitap ediyor. Ustelik, tum Trek bisikletlerimiz omur boyu garantilidir! Su an stok durumumuz: Stokta mevcut, Sinirli stok. Urun detaylari ve satin alma islemi icin lutfen su linke tiklayin: Trek Onerilen Model Urun Sayfasi https:orneksite.comtrek-ornek-model. Kargo ve Teslimat - Siparisiniz odeme onayindan sonra en gec 24 saat icinde paketlenip kargoya verilir; Yuritici Kargo, MNG veya Aras Kargo ile gonderim yapilir. Kargo takip numarasi SMS ve eposta ile iletilecek; gonderim sureci 3-5 is gunu surer. Belirli tutar uzerindeki siparislerde ucretsiz kargo kampanyasi uygulanir. Lutfen yukaridaki linke tiklayarak satin alma isleminizi tamamlayin. Herhangi bir sorunuz veya ek isteginiz olursa, ben buradayim. Hadi, siparisinizi tamamlayalim ve maceraya baslayalim!" },
122
- {"role": "system", "content": "Stokları ve fiyatları https://www.trekbisiklet.com.tr den bakacaksın, diğer markalarla ilgigi soru gelirse kibarca cevaplayamayacağını ve trek in neden farklı olduğunu anlat. Yol bisikletlerinde Türkiye stoklarımızda, Madone, Domane, Emonda, CheckMate, CheckPoint ve SpeedConcept modelleri bulunuyor. Dağ bisikletlerinde ise Marlin, Procaliber, Supercaliber modeller, full amortisörlülerde ise Fuel Ex modeli bulunmakta. Şehir kullanımı için FX ve DS modelini stoklarda bulunduruyoruz."},
123
- {"role": "system", "content": "Tüm modellerimizin ağırlıkları: Madone SL 5 Gen 8 8.70 kg, Madone SL 6 Gen 8 8.16 kg, Madone SL 7 Gen 8 7.88 kg, Madone SLR 7 Gen 8 7.30 kg, Madone SLR 7 AXS Gen 8 7.44 kg, Madone SLR 8 AXS Gen 8 7.18 kg, Madone SLR 9 Gen 8 7.00 kg, Madone SLR 9 AXS Gen 8 7.00 kg, Madone SLR 9 Etap Gen 7 7.36 kg, Madone SLR 9 Gen 7 7.10 kg, Madone SLR 7 Etap Gen 7 7.76 kg, Madone SLR 7 Gen 7 7.48 kg, Émonda SLR 9 6.72 kg, Émonda SLR 7 Etap 7.37 kg, Émonda SL 9 7.44 kg, Émonda SLR 7 7.10 kg, Émonda SLR 6 7.35 kg, Émonda SL 7 Etap 7.95 kg, Émonda SL 7 7.95 kg, Émonda SL 6 Pro Di2 8.25 kg, Émonda SL 5 9.15 kg, Émonda ALR 5 9.15 kg, Émonda ALR 4 9.50 kg, Domane SLR 7 Gen 4 7.25 kg, Domane SLR 7 AXS Gen 4 8.48 kg, Domane SL 6 Gen 4 8.90 kg, Domane SL 6 9.30 kg, Domane SL 5 Gen 4 8.93 kg, Domane AL 2 Gen 4 10.55 kg, Domane AL 2 Rim 9.57 kg, Checkmate SLR 7 AXS 9.00 kg, Checkpoint SL 7 AXS Gen 3 9.05 kg, Checkpoint SL 5 AXS Gen 3 9.30 kg, Domane+ SLR 7 AXS 12.40 kg, Speed Concept SLR 9 Etap 8.60 kg, Speed Concept SLR 9 8.70 kg, Speed Concept SLR 7 Etap 9.35 kg, Speed Concept SLR 7 8.97 kg, Fuel EXe 9.8 GX AXS T-Type 18.1 kg, Fuel EXe 9.7 SLX/XT 19.00 kg, Fuel EXe 5 20.8 kg, Rail 9.8 GX AXS T-Type 22.9 kg, Rail 5 21.53 kg, Rail 5 Gen 3 23.53 kg, Powerfly Gen 4 23.37 kg, Marlin+ 8 21.30 kg, Marlin+ 6 22.45 kg, Domane+ SLR 7 AXS 12.40 kg, Dual Sport+ 2 17.41 kg, FX+ 2 18.20 kg, Verve+ 3 24.70 kg, Townie Go 7D EQ Step Thru 20.41 kg, Marlin 8 13.2 kg, Marlin 7 13.77 kg, Marlin 5 13.90 kg, Marlin 4 14.60 kg, Procaliber 9.7 AXS Gen 3 10.58 kg, Procaliber 9.5 Gen 3 11.74 kg, Procaliber 9.5 11.74 kg, Supercaliber SL 9.7 Gen 2 11.98 kg, Fuel EX 8 GX AXS 13.77 kg, FX Sport 6 9.30 kg, FX 3 11.50 kg, FX 2 12.30 kg, DS 3 Gen 5 12.05 kg, DS 3 Gen 4 13.00 kg, DS 2 Gen 5 12.79 kg, Verve 3 Low Step 14.20 kg, Verve 3 14.30 kg"}
 
 
 
 
 
 
 
 
124
  ]
125
-
126
- messages = multi_turn_message.copy()
127
- input_words = [str(word).lower() for word in inputs.split()]
128
  for product_info in products:
129
  if product_info[0] in input_words:
130
  new_msg = f"{product_info[2]} {product_info[1][0]} ve fiyatı EURO {product_info[1][1]}"
131
- print(new_msg)
132
- messages.append({"role": "system", "content": new_msg})
133
-
134
- for data in chatbot:
135
- messages.append({"role": data["role"], "content": data["content"]})
136
-
137
- messages.append({"role": "user", "content": inputs})
138
-
139
  payload = {
140
  "model": "gpt-4o",
141
  "messages": messages,
@@ -146,29 +157,19 @@ def predict(system_msg, inputs, top_p, temperature, chat_counter, chatbot=None,
146
  "presence_penalty": 0,
147
  "frequency_penalty": 0,
148
  }
149
-
150
- chat_counter += 1
151
- history.append(inputs)
152
-
153
- try:
154
- with open(LOG_FILE, 'a', encoding='utf-8') as f:
155
- f.write(f"User: {inputs}\n")
156
- print(f"Kullanıcı mesajı dosyaya yazıldı: {inputs}")
157
- except Exception as e:
158
- print(f"Dosya yazma hatası (Kullanıcı): {e}")
159
-
160
- # Kullanıcı mesajını ekledikten sonra, ayrı bir assistant mesajı için yer açıyoruz
161
- chatbot.append({"role": "user", "content": inputs})
162
- chatbot.append({"role": "assistant", "content": ""}) # Boş bir assistant mesajı ekliyoruz
163
 
164
  response = requests.post(API_URL, headers=headers, json=payload, stream=True)
165
-
166
  if response.status_code != 200:
167
- print(f"API hatası: {response.text}")
168
- chatbot.pop() # Hata olursa boş assistant mesajını kaldır
169
- yield chatbot, history, chat_counter
170
 
171
  partial_response = ""
 
 
172
  for chunk in response.iter_lines():
173
  if not chunk:
174
  continue
@@ -177,114 +178,54 @@ def predict(system_msg, inputs, top_p, temperature, chat_counter, chatbot=None,
177
  try:
178
  chunk_data = json.loads(chunk_str[6:])
179
  delta = chunk_data['choices'][0]['delta']
180
- if 'content' in delta and delta['content']:
181
  partial_response += delta['content']
182
- # Son assistant mesajını güncelle, önceki mesajları koru
183
- chatbot[-1] = {"role": "assistant", "content": partial_response}
184
- yield chatbot, history, chat_counter
185
  except json.JSONDecodeError as e:
186
  print(f"JSON parse hatası: {e} - Chunk: {chunk_str}")
187
  elif chunk_str == "data: [DONE]":
188
- # Akış bittiğinde son haliyle assistant mesajını güncelle
189
- chatbot[-1] = {"role": "assistant", "content": partial_response}
190
- try:
191
- with open(LOG_FILE, 'a', encoding='utf-8') as f:
192
- f.write(f"Bot: {partial_response}\n")
193
- print(f"Bot yanıtı dosyaya yazıldı: {partial_response}")
194
- except Exception as e:
195
- print(f"Dosya yazma hatası (Bot): {e}")
196
  break
197
-
198
- yield chatbot, history, chat_counter
199
 
200
- def reset_textbox():
201
- return gr.update(value='')
 
 
 
 
 
202
 
203
- demo_css = """
204
- #send_button {
205
- background-color: #0b93f6;
206
- border: none;
207
- color: white;
208
- font-size: 16px;
209
- border-radius: 10%;
210
- width: 100px !important;
211
- height: 37px !important;
212
- display: inline-flex;
213
- align-items: center;
214
- justify-content: center;
215
- cursor: pointer;
216
- transition: background-color 0.3s;
217
- margin: 5px;
218
- }
219
- #send_button:hover {
220
- background-color: #0077c0;
221
- }
222
- .fixed_button_container {
223
- margin-top: -6px; /* Butonu 6 piksel yukarı kaydırır */
224
- padding: 0px;
225
- margin-left: 0px;
226
- margin-right: 0px;
227
- margin-bottom: 0px;
228
- }
229
- #custom_row {
230
- width: 150% !important;
231
- flex-wrap: nowrap !important;
232
- }
233
- @media only screen and (max-width: 1000px) {
234
- .custom_row {
235
- flex-wrap: nowrap !important;
236
- }
237
- }
238
- #chatbot {
239
- height: 100vh;
240
- overflow-y: auto;
241
- }
242
- """
243
 
244
- theme = gr.themes.Base(
245
- neutral_hue="blue",
246
- text_size="sm",
247
- spacing_size="sm",
248
- )
249
 
250
- with gr.Blocks(css=demo_css, theme=theme) as demo:
251
- if not os.path.exists(LOG_FILE):
252
- with open(LOG_FILE, 'w', encoding='utf-8') as f:
253
- f.write("--- Yeni Sohbet ---\n")
254
-
255
- with gr.Column(elem_id="col_container"):
256
- with gr.Accordion("", open=False, visible=False):
257
- system_msg = gr.Textbox(value="")
258
- new_msg = gr.Textbox(value="")
259
- accordion_msg = gr.HTML(value="", visible=False)
260
-
261
- chatbot = gr.Chatbot(label='Trek Asistanı', elem_id="chatbot", type="messages")
262
-
263
- with gr.Row(elem_id="custom_row"):
264
- inputs = gr.Textbox(
265
- placeholder="Buraya yazın",
266
- show_label=False,
267
- container=False,
268
- )
269
- with gr.Column(elem_classes="fixed_button_container"):
270
- send_button = gr.Button(value="✈", elem_id="send_button")
271
-
272
- state = gr.State([])
273
-
274
- with gr.Accordion("", open=False, visible=False):
275
- top_p = gr.Slider(minimum=0, maximum=1.0, value=0.5, step=0.05, interactive=False, visible=False)
276
- temperature = gr.Slider(minimum=0, maximum=5.0, value=0.1, step=0.1, interactive=False, visible=False)
277
- chat_counter = gr.Number(value=0, visible=False, precision=0)
278
-
279
- chatbot_ref = []
280
- def update_chatbot_ref(chat):
281
- chatbot_ref[:] = chat
282
- return chat
283
-
284
- inputs.submit(predict, [system_msg, inputs, top_p, temperature, chat_counter, chatbot, state], [chatbot, state, chat_counter]).then(update_chatbot_ref, chatbot, chatbot).then(reset_textbox, [], [inputs])
285
- send_button.click(predict, [system_msg, inputs, top_p, temperature, chat_counter, chatbot, state], [chatbot, state, chat_counter]).then(update_chatbot_ref, chatbot, chatbot).then(reset_textbox, [], [inputs])
286
-
287
- scheduler_thread = threading.Thread(target=run_scheduler, args=(chatbot_ref,), daemon=True)
288
  scheduler_thread.start()
289
 
290
- demo.launch(debug=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
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
10
+ import warnings
11
+
12
+ # Gradio uyarılarını bastır
13
+ warnings.filterwarnings("ignore", category=UserWarning, module="gradio.components.chatbot")
14
 
15
  # Log dosyası adı ve yolu
16
  LOG_FILE = '/data/chat_logs.txt' if os.path.exists('/data') else 'chat_logs.txt'
 
33
  name_words = item.find('rootlabel').text.lower().split()
34
  name = name_words[0]
35
  full_name = ' '.join(name_words)
36
+ stock_amount = "stokta"
37
  price = item.find('priceWithTax').text
38
+ item_info = (stock_amount, price)
39
  products.append((name, item_info, full_name))
40
 
41
  # Hugging Face token
 
45
 
46
  create_repo("BF", token=hfapi, repo_type="space", space_sdk="gradio", exist_ok=True)
47
 
48
+ global_chat_history = [] # Tüm sohbet geçmişi
49
+ history_lock = threading.Lock() # Global geçmiş için kilit
50
+ file_lock = threading.Lock() # Dosya yazma için kilit
51
+ last_logged_index = 0 # Son kaydedilen mesaj indeksi
 
 
 
 
 
 
 
 
52
 
53
+ def run_scheduler(chat_history_ref):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
54
  def scheduled_save_and_upload():
55
+ global last_logged_index
56
+ if chat_history_ref:
57
+ print(f"Zamanlayıcı tetiklendi: {time.strftime('%Y-%m-%d %H:%M:%S')}")
58
+ try:
59
+ with file_lock: # Dosya yazma kilidi
60
+ with open(LOG_FILE, 'a', encoding='utf-8') as f:
61
+ f.write("\n--- Zamanlanmış Kayıt: {} ---\n".format(time.strftime("%Y-%m-%d %H:%M:%S")))
62
+ with history_lock: # Geçmiş kilidi
63
+ new_messages = chat_history_ref[last_logged_index:]
64
+ for msg in new_messages:
65
+ if msg["role"] in ["user", "assistant"]:
66
+ f.write(f"{msg['role'].capitalize()}: {msg['content']}\n")
67
+ last_logged_index = len(chat_history_ref) # Son indeksi güncelle
68
+ print(f"Sohbet dosyaya kaydedildi: {os.path.abspath(LOG_FILE)}")
69
+ except Exception as e:
70
+ print(f"Kayıt hatası: {e}")
71
+ time.sleep(5) # Hata sonrası tekrar denemeden önce bekle
72
+ return # Tekrar deneme için erken çıkış
73
+
74
+ HF_REPO_ID = "SamiKoen/BF"
75
+ api = HfApi(token=hfapi)
76
+ for attempt in range(3): # 3 kez tekrar deneme
77
+ try:
78
+ with file_lock:
79
+ api.upload_file(
80
+ path_or_fileobj=LOG_FILE,
81
+ path_in_repo="chat_logs.txt",
82
+ repo_id=HF_REPO_ID,
83
+ repo_type="space",
84
+ commit_message="Otomatik log güncellemesi - {}".format(time.strftime("%Y-%m-%d %H:%M:%S"))
85
+ )
86
+ print(f"Log dosyası HF'ye yüklendi: {LOG_FILE}")
87
+ break
88
+ except Exception as e:
89
+ print(f"HF yükleme hatası (deneme {attempt+1}/3): {e}")
90
+ time.sleep(5)
91
+ else:
92
+ print("HF yükleme başarısız, tüm denemeler tamamlandı.")
93
  print(f"Zamanlanmış işlem tamamlandı: {time.strftime('%H:%M:%S')}")
94
 
95
  schedule.every().day.at("11:32").do(scheduled_save_and_upload)
 
99
  schedule.every().day.at("19:15").do(scheduled_save_and_upload)
100
  schedule.every().day.at("21:30").do(scheduled_save_and_upload)
101
  print("Zamanlayıcı başlatıldı")
 
102
  while True:
103
  schedule.run_pending()
 
104
  time.sleep(60)
105
 
106
+ def chatbot_fn(user_message, history):
 
 
107
  if history is None:
108
  history = []
109
 
110
+ # Log: Kullanıcı mesajını ekle
111
+ try:
112
+ with file_lock:
113
+ with open(LOG_FILE, 'a', encoding='utf-8') as f:
114
+ f.write(f"User: {user_message}\n")
115
+ except Exception as e:
116
+ print(f"Dosya yazma hatası (Kullanıcı): {e}")
117
+
118
+ # Sistem mesajları
119
+ system_messages = [
120
+ {"role": "system", "content": "Sen bir Trek bisiklet satış ve danışman asistanısın; Trek, Electra bisikletler, Bontrager aksesuarlar, Bryton yol bilgisayarları ve Trieye gözlükler konusunda uzmanım."},
121
+ {"role": "system", "content": "Başka markalar (ör. Specialized, Giant) hakkında bilgi vermem ve yorum yapmam."},
122
+ {"role": "system", "content": "Bir önceki sohbeti unuturum ve yalnızca aşağıda yan yana yazılan bilgilerden cevap veririm."},
123
+ {"role": "system", "content": "Stok kontrolüm gerçek zamanlıdır; stokta yoksa 'yok' derim."},
124
+ {"role": "system", "content": "Model adı rakamsız gelirse (ör. Madone SL), rakam eklenmesini rica ederim (ör. Madone SL 7)."},
125
+ {"role": "system", "content": "Madone SLR sorulursa Gen 7 kabul ederim."},
126
+ {"role": "system", "content": "Yol bisikletleri (Madone, Émonda, Domane, Checkpoint, Speed Concept) boyları 47-64 cm'dir."},
127
+ {"role": "system", "content": "Dağ bisikletleri (Marlin, Roscoe, Procaliber, Supercaliber, Fuel EX) boyları XXS-XL'dir."},
128
+ {"role": "system", "content": "Şehir bisikletleri FX ve DS’dir; elektrikli modeller Powerfly, Rail, Fuel EXe, Domane+ SLR, Verve+’dır; gravel için Checkpoint vardır."},
129
+ {"role": "system", "content": "Yeni Madone Gen 8 (27 Haziran 2024): Émonda kadar hafif (900 Serisi OCLV Karbon, 320g hafif) ve Madone Gen 7 kadar hızlıdır."},
130
+ {"role": "system", "content": "IsoFlow ile %80 konforludur; SL ekonomik, SLR üst seviyedir."},
131
+ {"role": "system", "content": "Stok ve fiyatlar için www.trekbisiklet.com.tr’ye bakarım; farklı boy/renk varsa söylerim, yoksa başka model öneririm."},
132
+ {"role": "system", "content": "En büyük/küçük boy sorusuna stoktan cevap veririm; üyelere özel fiyatlar için siteye üye olun derim."},
133
+ {"role": "system", "content": "İstanbul’da Caddebostan mağazamız (0216 6292432, 10:00-19:00, Bike Fit 3500 TL) ve Ortaköy mağazamız (0212 2271015, 10:00-19:00) bulunmaktadır."},
134
+ {"role": "system", "content": "Sarıyer mağazamız (0542 1371080, 10:00-19:00) elektrikli bisiklet odaklıdır."},
135
+ {"role": "system", "content": "İzmir Alsancak mağazası Nisan 2025’te açılacak ve Pazar günleri kapalı olacak."},
136
+ {"role": "system", "content": "Bontrager aksesuarlar, Bryton Rider S800 stokta ve Trieye gözlükler Norveç menşeli geri görüş aynalıdır."},
137
+ {"role": "system", "content": "Bike Finder olarak adım adım sorarım: 1) kategori (yol, dağ, hibrit, gravel, elektrikli), 2) amaç (ulaşım, spor, yarış), 3) özellik (performans, konfor)."},
138
+ {"role": "system", "content": "4) zemin (asfalt, off-road), 5) boy ve iç bacak ölçüsü, 6) ek tercih (renk, bütçe) sorularını sorarım; sonra stoktan öneri yapar www.trekbisiklet.com.tr’ye yönlendiririm."},
139
+ {"role": "system", "content": "Sipariş süreci: sepete ekle, bilgi gir, ödeme yap, tamamla; Trek kadroları ömür boyu garantilidir; 2000’den beri Alatin Bisiklet dağıtıyor; ASLA DURMA ve TREK RMK DYNAMIS’e sponsoruz; takas için www.bikeexchangehub.com, canlı sohbet için sitedeki yeşil düğme, bayiler için www.alatin.com.tr/sayfa/bayilerimiz/ kullanılır."}
140
  ]
141
+ # Kullanıcı mesajında ürün ismi geçiyorsa ekle
142
+ input_words = user_message.lower().split()
 
143
  for product_info in products:
144
  if product_info[0] in input_words:
145
  new_msg = f"{product_info[2]} {product_info[1][0]} ve fiyatı EURO {product_info[1][1]}"
146
+ system_messages.append({"role": "system", "content": new_msg})
147
+
148
+ messages = system_messages + history + [{"role": "user", "content": user_message}]
149
+
 
 
 
 
150
  payload = {
151
  "model": "gpt-4o",
152
  "messages": messages,
 
157
  "presence_penalty": 0,
158
  "frequency_penalty": 0,
159
  }
160
+ headers = {
161
+ "Content-Type": "application/json",
162
+ "Authorization": f"Bearer {OPENAI_API_KEY}"
163
+ }
 
 
 
 
 
 
 
 
 
 
164
 
165
  response = requests.post(API_URL, headers=headers, json=payload, stream=True)
 
166
  if response.status_code != 200:
167
+ yield [{"role": "user", "content": user_message}, {"role": "assistant", "content": "Bir hata oluştu."}]
168
+ return
 
169
 
170
  partial_response = ""
171
+ current_pair = [{"role": "user", "content": user_message}, {"role": "assistant", "content": ""}]
172
+
173
  for chunk in response.iter_lines():
174
  if not chunk:
175
  continue
 
178
  try:
179
  chunk_data = json.loads(chunk_str[6:])
180
  delta = chunk_data['choices'][0]['delta']
181
+ if 'content' in delta:
182
  partial_response += delta['content']
183
+ current_pair[1]["content"] = partial_response
184
+ yield current_pair
 
185
  except json.JSONDecodeError as e:
186
  print(f"JSON parse hatası: {e} - Chunk: {chunk_str}")
187
  elif chunk_str == "data: [DONE]":
 
 
 
 
 
 
 
 
188
  break
 
 
189
 
190
+ # Log: Asistan cevabını ekle
191
+ try:
192
+ with file_lock:
193
+ with open(LOG_FILE, 'a', encoding='utf-8') as f:
194
+ f.write(f"Bot: {partial_response}\n")
195
+ except Exception as e:
196
+ print(f"Dosya yazma hatası (Bot): {e}")
197
 
198
+ # Global geçmişi güncelle
199
+ with history_lock:
200
+ global_chat_history.append({"role": "user", "content": user_message})
201
+ global_chat_history.append({"role": "assistant", "content": partial_response})
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
202
 
203
+ yield current_pair
 
 
 
 
204
 
205
+ # Slow echo (test için)
206
+ def slow_echo(message, history):
207
+ for i in range(len(message)):
208
+ time.sleep(0.05)
209
+ yield [{"role": "user", "content": message}, {"role": "assistant", "content": "You typed: " + message[: i + 1]}]
210
+
211
+ # Kullanım modu
212
+ USE_SLOW_ECHO = False
213
+ chat_fn = slow_echo if USE_SLOW_ECHO else chatbot_fn
214
+
215
+ if not USE_SLOW_ECHO:
216
+ scheduler_thread = threading.Thread(target=run_scheduler, args=(global_chat_history,), daemon=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
217
  scheduler_thread.start()
218
 
219
+ demo = gr.ChatInterface(
220
+ fn=chat_fn,
221
+ title="Trek Asistanı",
222
+ description="Hoş geldiniz! Trek ile ilgili sorularınızı yanıtlıyorum.",
223
+ theme="default",
224
+ type="messages",
225
+ flagging_mode="manual",
226
+ flagging_options=["Doğru", "Yanlış", "Emin değilim", "Diğer"],
227
+ save_history=True
228
+ )
229
+
230
+ if __name__ == "__main__":
231
+ demo.launch(debug=True, share=True)