BF / app.py
SamiKoen's picture
Update app.py
04b6f7b verified
raw
history blame
11.1 kB
import gradio as gr
import os
import json
import uuid
import requests
import xml.etree.ElementTree as ET
# API URL ve API KEY ayarları
API_URL = "https://api.openai.com/v1/chat/completions"
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
# Ürün verilerini çekme işlemi
url = 'https://www.trekbisiklet.com.tr/output/8582384479'
response = requests.get(url)
root = ET.fromstring(response.content)
products = []
for item in root.findall('item'):
if item.find('isOptionOfAProduct').text == '1':
if item.find('stockAmount').text > '0':
name_words = item.find('rootlabel').text.lower().split()
name = name_words[0]
full_name = ' '.join(name_words)
stockAmount = "stokta"
price = item.find('priceWithTax').text
item_info = (stockAmount, price)
# name: ilk kelime (marka), item_info: (stok durumu, fiyat)
products.append((name, item_info, full_name))
# ------------------ Session Yönetimi ------------------ #
SESSION_DIR = "chat_sessions"
if not os.path.exists(SESSION_DIR):
os.makedirs(SESSION_DIR)
def get_session_id():
return str(uuid.uuid4())
def load_session(session_id):
filename = os.path.join(SESSION_DIR, f"session_{session_id}.json")
if os.path.exists(filename):
with open(filename, "r", encoding="utf-8") as f:
return json.load(f)
return []
def save_session(session_id, history):
filename = os.path.join(SESSION_DIR, f"session_{session_id}.json")
with open(filename, "w", encoding="utf-8") as f:
json.dump(history, f)
# ------------------ Predict Fonksiyonu ------------------ #
def predict(system_msg, inputs, top_p, temperature, chat_counter, chatbot=[], history=[], session_id=""):
headers = {
"Content-Type": "application/json",
"Authorization": f"Bearer {OPENAI_API_KEY}"
}
print(f"system message is ^^ {system_msg}")
initial_message = [{"role": "user", "content": f"{inputs}"}]
multi_turn_message = [
{"role": "system", "content": "Sen 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."},
{"role": "system", "content": "Merhaba, ben Trek Stok Danısmanı Asistanıyım! Size en uygun Trek bisiklet modelini belirleyebilmem için birkaç sorum olacak. 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+."},
{"role": "system", "content": "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."},
{"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."}
]
messages = multi_turn_message
input_words = [str(word).lower() for word in inputs.split()]
for product_info in products:
if product_info[0] in input_words:
new_msg = f"{product_info[2]} {product_info[1][0]} ve fiyatı EURO {product_info[1][1]}"
print(new_msg)
product_msg = {"role": "system", "content": new_msg}
messages.append(product_msg)
for data in chatbot:
user = {"role": "user", "content": data[0]}
assistant = {"role": "assistant", "content": data[1]}
messages.append(user)
messages.append(assistant)
messages.append({"role": "user", "content": inputs})
# o3-mini modeli için payload'i güncelledik.
# Eğer o3-mini modeli streaming desteklemiyorsa "stream": False yapıyoruz.
payload = {
"model": "o3-mini",
"messages": messages,
"temperature": 0.7,
"top_p": 0.9,
"n": 1,
"stream": False,
"presence_penalty": 0,
"frequency_penalty": 0,
}
chat_counter += 1
history.append(inputs)
print(f"Logging : payload is - {payload}")
response = requests.post(API_URL, headers=headers, json=payload, stream=payload["stream"])
print(f"Logging : response code - {response}")
token_counter = 0
partial_words = ""
counter = 0
for chunk in response.iter_lines():
if counter == 0:
counter += 1
continue
if chunk.decode():
chunk = chunk.decode()
if len(chunk) > 12 and "content" in json.loads(chunk[6:])['choices'][0]['delta']:
partial_words += json.loads(chunk[6:])['choices'][0]["delta"]["content"]
if token_counter == 0:
history.append(" " + partial_words)
else:
history[-1] = partial_words
chat = [(history[i], history[i + 1]) for i in range(0, len(history) - 1, 2)]
token_counter += 1
save_session(session_id, history)
yield chat, history, chat_counter, response
def reset_textbox():
return gr.update(value='')
def set_visible_false():
return gr.update(visible=False)
def set_visible_true():
return gr.update(visible=False)
# Yeni jenerasyon, okunaklı ve modern tasarım için özel CSS
css = """
/* Chat Başlığı: Temiz ve modern görünüm */
.chat-header {
background-color: #ffffff;
color: #333;
padding: 15px;
text-align: center;
font-size: 22px;
font-weight: 600;
border-bottom: 1px solid #e0e0e0;
}
/* Chat penceresi: Açık ve ferah arka plan */
#chatbot {
background-color: #fafafa;
border: none;
padding: 15px;
}
/* Kullanıcı mesajı: Açık mavi ton, modern görünüm */
.chat-bubble.user {
background-color: #e1f5fe;
align-self: flex-end;
border-radius: 16px;
padding: 12px 18px;
margin: 8px 0;
max-width: 70%;
box-shadow: 0px 1px 3px rgba(0,0,0,0.1);
font-size: 16px;
color: #333;
}
/* Bot mesajı: Beyaz, hafif gri kenarlık, modern görünüm */
.chat-bubble.bot {
background-color: #ffffff;
align-self: flex-start;
border: 1px solid #e0e0e0;
border-radius: 16px;
padding: 12px 18px;
margin: 8px 0;
max-width: 70%;
box-shadow: 0px 1px 3px rgba(0,0,0,0.1);
font-size: 16px;
color: #333;
}
/* Mesaj gönderme alanı: Temiz ve modern */
.chat-input-container {
display: flex;
padding: 15px;
border-top: 1px solid #e0e0e0;
background-color: #ffffff;
}
/* Chat input alanı */
.chat-input {
flex: 1;
padding: 10px 15px;
border: 1px solid #ddd;
border-radius: 20px;
font-size: 16px;
outline: none;
}
/* Gönder butonu: Modern mavi ton */
.send-button {
background-color: #1976d2;
border: none;
color: #fff;
padding: 10px 20px;
margin-left: 10px;
border-radius: 20px;
font-size: 16px;
cursor: pointer;
}
"""
# Tema ayarını güncelliyoruz: modern ve temiz görünüm için neutral_hue "blue"
theme = gr.themes.Base(
neutral_hue="blue",
text_size="sm",
spacing_size="sm",
)
# Yeni oturum için benzersiz session ID oluşturuyoruz
session_id_value = get_session_id()
with gr.Blocks(theme=theme, css=css) as demo:
gr.Markdown("<div class='chat-header'>Trek Bike Finder Chatbot</div>")
with gr.Column(elem_id="col_container"):
with gr.Accordion("", open=False, visible=False):
system_msg = gr.Textbox(value="")
new_msg = gr.Textbox(value="")
accordion_msg = gr.HTML(value="", visible=False)
chatbot = gr.Chatbot(label='Trek Bike Finder', elem_id="chatbot")
inputs = gr.Textbox(
placeholder="Buraya yazın, istediğiniz modeli beraber bulalım.", show_label=False)
# Oturum geçmişini session_id üzerinden yüklüyoruz.
state = gr.State(load_session(session_id_value))
# Gizli session ID
session_id = gr.Textbox(value=session_id_value, visible=False, label="Session ID")
with gr.Accordion("", open=False, visible=False):
top_p = gr.Slider(minimum=0, maximum=1.0, value=0.5, step=0.05, interactive=False, visible=False)
temperature = gr.Slider(minimum=0, maximum=5.0, value=0.1, step=0.1, interactive=False, visible=False)
chat_counter = gr.Number(value=0, visible=False, precision=0)
inputs.submit(
predict,
[system_msg, inputs, top_p, temperature, chat_counter, chatbot, state, session_id],
[chatbot, state, chat_counter]
)
inputs.submit(reset_textbox, [], [inputs])
demo.queue(max_size=10).launch(debug=True)