Spaces:
Sleeping
Sleeping
import uuid | |
from embedding_loader import * | |
from initialize_db import QdrantClientInitializer | |
from pdf_loader import PDFLoader | |
from IPython.display import display, Markdown | |
import gradio as gr | |
from langchain_core.messages import HumanMessage, AIMessage | |
from langchain.memory import ConversationBufferMemory | |
from langchain_core.chat_history import InMemoryChatMessageHistory | |
from qdrant_client import QdrantClient, models | |
from db_operations import DatabaseOperations | |
from openai import AzureOpenAI | |
import json | |
from qdrant_client.http import models as rest | |
import time | |
embeddings = import_embedding() | |
AZURE_OPENAI_KEY = os.getenv('azure_api') | |
os.environ['AZURE_OPENAI_KEY'] = AZURE_OPENAI_KEY | |
openai.api_version = "2024-02-15-preview" # change it with your own version | |
openai.azure_endpoint = os.getenv('azure_endpoint') | |
model = "gpt4o" # deployment name on Azure OPENAI Studio | |
client = AzureOpenAI(azure_endpoint = openai.azure_endpoint, | |
api_key=AZURE_OPENAI_KEY, | |
api_version=openai.api_version) | |
obj_qdrant = QdrantClientInitializer() | |
qclient = obj_qdrant.initialize_db() | |
obj_loader = PDFLoader() | |
# ----- | |
def retriever_db(db, CAR_ID): | |
retriever = db.as_retriever(search_kwargs={'k': 4}, filter=rest.Filter( | |
must=[ | |
models.FieldCondition(key="car_id", match=models.MatchValue(value=CAR_ID)) | |
] | |
)) | |
return retriever | |
## new version | |
def chat_gpt(prompt=None, history=[], model=model, client=client, tools=[None]): | |
if prompt is None: | |
messages = history | |
else: | |
history.append({"role": "user", "content": f"{prompt}"}) | |
messages = history | |
completion = client.chat.completions.create( | |
model=model, | |
messages=messages, | |
tools=tools | |
) | |
return completion | |
retrieval_functions = [ | |
{ | |
"type": "function", | |
"function":{ | |
"name": "get_section_content", | |
"description": """Use this function to get the contents of a particular section of a user manual.""", | |
"parameters": { | |
"type": "object", | |
"properties": { | |
"section_title": { | |
"type": "string", | |
"description": "Title of the section in the user manual", | |
}, | |
"sub_section_title": { | |
"type": "string", | |
"description": "Title of the subsection in the user manual", | |
}, | |
"sub_sub_section_title": { | |
"type": "string", | |
"description": "Title of the subsubsection in the user manual", | |
} | |
}, | |
"required": ["section_title", "sub_section_title", "sub_sub_section_title"], | |
} | |
} | |
} | |
] | |
def get_section_content(section_title, sub_section_title, sub_sub_section_title, content_path): | |
with open(content_path, "r") as file: | |
doc_section_content = json.loads(file.read()) | |
response = None | |
try: | |
response = doc_section_content["TableOfContents"][section_title][sub_section_title][sub_sub_section_title]["content"] | |
except: | |
pass | |
return response | |
def get_lead_result(question): | |
hizmet_listesi = {"Bakım": """Check-Up, Periyodik Bakım, Aks Değişimi, Amortisör Değişimi, Amortisör Takozu Değişimi, Baskı Balata Değişimi, Benzin Filtresi Değişimi, | |
Debriyaj Balatası Değişimi, Direksiyon Kutusu Değişimi, Dizel Araç Bakımı, Egzoz Muayenesi, Fren Kaliperi Değişimi, El Freni Teli Değişimi, | |
Fren Balatası Değişimi, Fren Disk Değişimi, Hava Filtresi Değişimi, Helezon Yay Değişimi, Kampana Fren Balatası Değişimi, | |
Kızdırma Bujisi Değişimi, Rot Başı Değişimi, Rot Kolu Değişimi, Rotil Değişimi, Silecek Değişimi, Süspansiyon, Triger Kayışı Değişimi, | |
Triger Zinciri Değişimi, V Kayışı Değişimi, Yağ Filtresi Değişimi, Yakıt Filtresi Değişimi, Havayastığı Değişimi""", | |
"Yağ ve Sıvılar": """Şanzıman Yağı Değişimi, Dizel Araçlarda Yağ Değişimi, Yağ Değişimi, Fren Hidrolik Değişimi, Antifriz Değişimi,""", | |
"Akü": """Akü Şarj Etme, Akü Değişimi""", | |
"Klima": """Oto Klima Kompresörü Tamiri, Oto Klima Tamiri, Araç Klima Temizliği, Araç Klima Bakteri Temizliği, Klima Gazı Dolumu, Klima Dezenfeksiyonu, Polen Filtresi Değişimi""", | |
"Elektrik": """Servis Uyarı Lambası Sıfırlama,Buji Kablosu Değişimi, Arıza Tespit, Göstergelerin Kontrolü, Far Ayarı ve Ampul Değişimi, Buji Değişimi, Sigorta Değişimi""", | |
"Lastik/ Jant": """Lastik Jant Satış, Lastik Değişimi, Balans Ayarı, Rot Ayarı, Rotasyon, Lastik Tamiri, Hava Kontrolü, Nitrojen Dolumu, Supap Değişimi, Lastik Saklama (Lastik Oteli), Jant Sökme Takma,""", | |
"Diğer": """Cam Tamiri""", | |
"Hibrit Araçlar": "Hibrit Araç Aküsü"} | |
lead_functions = [ | |
{ | |
"type": "function", | |
"function": { | |
"name": "grade_service_relevance", | |
"description": "Grade the relevance of services to a user question", | |
"parameters": { | |
"type": "object", | |
"properties": { | |
"binary_score": { | |
"type": "string", | |
"description": "Services are relevant to the question, 'yes' or 'no'", | |
"enum": ["yes", "no"] | |
} | |
}, | |
"required": ["binary_score"] | |
} | |
} | |
} | |
] | |
# System message | |
system_message = """Soruyu cevaplarken: | |
1- Önce soruyu düşün. | |
2- Kullanıcının sorduğu soru, hizmet listesinde sunulan hizmetlerle alakalı mı? | |
Alakalı ise "yes", değilse "no" olarak cevap ver.""" | |
def service_grader_relevance(hizmet_listesi: str, question: str) -> dict: | |
completion = client.chat.completions.create( | |
model=model, | |
messages=[ | |
{"role": "system", "content": system_message}, | |
{"role": "user", "content": f"Provided services: \n\n {hizmet_listesi} \n\n User question: {question}"} | |
], | |
tools=lead_functions, | |
tool_choice={"type": "function", "function": {"name": "grade_service_relevance"}} | |
) | |
tool_call = completion.choices[0].message.tool_calls[0] | |
return json.loads(tool_call.function.arguments) | |
result = service_grader_relevance(hizmet_listesi, question) | |
return result['binary_score'] | |
def chat_gpt_nofn(prompt=None, history=[], model=model, client=client): | |
if prompt is None: | |
messages = history | |
else: | |
history.append({"role": "user", "content": f"{prompt}"}) | |
messages = history | |
completion = client.chat.completions.create( | |
model=model, | |
messages=messages, | |
stream=True) | |
return completion | |
def format_chat_prompt(chat_history): | |
prompt = [] | |
print(chat_history) | |
for turn in chat_history: | |
user_message, ai_message = turn | |
prompt.append({"role": "user", "content": user_message}) | |
prompt.append({"role": "assistant", "content": ai_message}) | |
return prompt | |
liked_state = gr.State(None) | |
last_interaction = gr.State(None) | |
def chat(question, manual, history, liked): | |
history = history or [] | |
conv = format_chat_prompt(history) | |
manual_list = {"Toyota_Corolla_2024_TR": -8580416610875007536, | |
"Renault_Clio_2024_TR":-5514489544983735006, | |
"Fiat_Egea_2024_TR":-2026113796962100812} | |
collection_list = {"Toyota_Corolla_2024_TR": "TOYOTA_MANUAL_COLLECTION_EMBED3", | |
"Renault_Clio_2024_TR": "RENAULT_MANUAL_COLLECTION_EMBED3", | |
"Fiat_Egea_2024_TR": "FIAT_MANUAL_COLLECTION_EMBED3"} | |
collection_name = collection_list[manual] | |
toc_name = "ToC_" + manual + ".txt" | |
start_time = time.time() | |
with open("ToCs/" + toc_name, "r") as file: | |
content = json.loads(file.read()) | |
print("ToCs:--- %s seconds ---" % (time.time() - start_time)) | |
start_time = time.time() | |
db = obj_loader.load_from_database(embeddings=embeddings, collection_name=collection_name) | |
print("DB Load:--- %s seconds ---" % (time.time() - start_time)) | |
CAR_ID = manual_list[manual] | |
retriever = retriever_db(db, CAR_ID) | |
start_time = time.time() | |
first_hop = f"""Soruyu cevaplarken: | |
1- Önce soruyu düşün. | |
2- Kullanıcının sorduğu sorunun konu başlıkları neler olabilir? | |
3- Bu konu başlıkları kullanım kılavuzu içindekiler tablosu başlıkları ile alakalı mı? | |
4- Alakalı olabilecek tüm başlıkları türet. | |
Buna göre, aşağıda vereceğim kullanım kılavuzu içindekiler tablosu (başlıklar) bilgisini kullanarak bu içeriğe erişmek için uygun fonksiyonları üret. | |
Eğer herhangi bir içeriğe ulaşamazsan, bunu belir ve sorunun cevabı hakkında yorum yapma. | |
Kullanım Kılavuzu İçindekiler Tablosu: | |
{content} | |
""" | |
# conv = [{"role": "system", "content": f"{first_hop}"}] | |
conv.append({"role": "system", "content": f"{first_hop}"}) | |
first_hop_response = chat_gpt(prompt=f"Soru: {question}", history=conv, tools=retrieval_functions) | |
conv.append(first_hop_response.choices[-1].message) | |
print("First_hop:--- %s seconds ---" % (time.time() - start_time)) | |
path = "Contents/" + manual + ".json" | |
start_time = time.time() | |
i = 0 | |
while(i < 2): | |
tool_calls = first_hop_response.choices[-1].message.tool_calls | |
if tool_calls: | |
for tool_call in tool_calls: | |
function_name = tool_call.function.name | |
args = json.loads(tool_call.function.arguments) | |
print(f"Will call {function_name} with arguments {args}") | |
if function_name == 'get_section_content': | |
addition = get_section_content(str(args['section_title']), str(args['sub_section_title']), str(args['sub_sub_section_title']), content_path=path) | |
if not addition: | |
addition = ' ' | |
conv.append({ | |
"tool_call_id": tool_call.id, | |
"role": "tool", | |
"name": function_name, | |
"content": addition | |
}) | |
first_hop_response = chat_gpt(prompt=None, history=conv, tools=retrieval_functions) | |
else: | |
conv.append(first_hop_response.choices[-1].message) | |
break | |
i += 1 | |
print("Second_hop:--- %s seconds ---" % (time.time() - start_time)) | |
start_time = time.time() | |
documents = retriever.invoke(question) | |
print("Retriever:--- %s seconds ---" % (time.time() - start_time)) | |
start_time = time.time() | |
if get_lead_result(question).lower() == 'yes': | |
lead = """ Cevabın sonunda, "Nasıl devam edeceğinizden emin değilseniz." ifadesiyle başlayarak, kullanıcılara hızlı ve uygun fiyatlı çözümler için OtoBakım mağazalarını ziyaret etmelerini teklif etmelisin.""" | |
print('Lead: yes') | |
else: | |
lead = 'Her zaman tamirci yerine geçen "Servis", "Yetkili Servis", ""... servisi", ""... yetkili servisi", "bakım" gibi ifadeler yerine yalnızca "OtoBakım Servisi" yazmalısın.' | |
print('Lead: no') | |
print("Lead Check:--- %s seconds ---" % (time.time() - start_time)) | |
start_time = time.time() | |
prompt = f""" | |
Sen, yalnızca araba sorunları ve araç bilgilerine odaklanan, ARVI adında uzman bir asistansın. | |
Amacın, araba sorunları, bakım, onarımlar, teknik özellikler ve diğer araçla ilgili konularla ilgili sorulara doğru, yardımcı ve net cevaplar vermektir. | |
Ayrıca, temel nezaket etkileşimlerine uygun ve kibar bir şekilde yanıt vermek için tasarlandın. İşte yönergeler: | |
1. Araba Sorunları ve Araç Bilgileri: | |
- Araba sorunları, teşhis, onarımlar, bakım ve araç teknik özellikleri ile ilgili soruları her zaman yanıtla. | |
- Soruları yanıtlarken yorum yapma ve kişisel görüşlerini belirtme. | |
2. Referanslar: | |
- Bir soruyu yanıtlarken, eğer aşağıdaki ya da sorunun içindeki içerikten faydalandıysan, cevabın sonunda içeriğin sayfa numarasını ve bölümünü referans olarak ekle. | |
- Aynı referansı tekrar etme. | |
Lead: {lead} \n | |
Dokümanlarda ve sorunun içinde verilen tüm bilgilere dayanarak, aşağıdaki soruyu kısaca yanıtla: \n | |
Sorulara cevap verirken sana sağlanan bilgilerdeki uyarılara, tehlikelere vurgu yap. \n | |
Soru: {question} \n | |
Dokümanlar: {documents} | |
Elde ettiğin bilgiler soru ile ilgili görünmüyorsa cevap veremeyeceğini belirt. | |
Kullanıcıya doğrudan cevap ver. \n | |
Yeni fonksiyon çağırma. \n | |
Soru çok genel ise, spesifik bilgi iste. \n | |
Eğer sorunun cevabına ulaşamadıysan, bu soruya cevap veremeyeceğini belirt. | |
Kesinlikle cevaplar üzerine yorum yapma ve bilgi dağarcığını kullanma | |
Referans verme örneği: | |
Ref-1: | |
Ref-2: | |
... | |
""" | |
#final_response = chat_gpt_nofn(prompt=prompt, history=conv) | |
#response = final_response.choices[-1].message.content | |
#conv.append(final_response.choices[-1].message) | |
#history.append((question, response)) | |
#print("Answer:--- %s seconds ---" % (time.time() - start_time)) | |
# Store the last interaction without saving to the database yet | |
#last_interaction.value = { | |
# "question": question, | |
# "response": response, | |
# "manual": manual, | |
# "point_id": uuid.uuid4().hex | |
#} | |
#return '', history | |
final_response = chat_gpt_nofn(prompt=prompt, history=conv) | |
partial_response = "" | |
for chunk in final_response: | |
try: | |
if chunk.choices[0].delta.content is not None: | |
partial_response += chunk.choices[0].delta.content | |
print("Answer:--- %s seconds ---" % (time.time() - start_time)) | |
yield partial_response, history + [(question, partial_response)] | |
except: | |
pass | |
response = partial_response | |
conv.append({"role": "user", "content": prompt}) | |
conv.append({"role": "assistant", "content": response}) | |
history.append((question, response)) | |
print("Answer:--- %s seconds ---" % (time.time() - start_time)) | |
# Store the last interaction without saving to the database yet | |
last_interaction.value = { | |
"question": question, | |
"response": response, | |
"manual": manual, | |
"point_id": uuid.uuid4().hex | |
} | |
yield response, history | |
def save_last_interaction(feedback): | |
if last_interaction.value: | |
DatabaseOperations.save_user_history_demo( | |
qclient, | |
"USER_COLLECTION_EMBED3_v2", | |
last_interaction.value["question"], | |
last_interaction.value["response"], | |
embeddings, | |
last_interaction.value["point_id"], | |
last_interaction.value["manual"], | |
feedback | |
) | |
last_interaction.value = None | |
manual_list = ["Toyota_Corolla_2024_TR", "Renault_Clio_2024_TR", "Fiat_Egea_2024_TR"] | |
with gr.Blocks() as demo: | |
chatbot = gr.Chatbot(height=600) | |
manual = gr.Dropdown(label="Kullanım Kılavuzları", value="Toyota_Corolla_2024_TR", choices=manual_list) | |
textbox = gr.Textbox() | |
clear = gr.ClearButton(components=[textbox, chatbot], value='Clear console') | |
def handle_like(data: gr.LikeData): | |
liked_state.value = data.liked | |
if liked_state.value is not None: | |
feedback = "LIKE" if liked_state.value else "DISLIKE" | |
save_last_interaction(feedback) | |
#def gradio_chat(question, manual, history): | |
# save_last_interaction("N/A") # Save previous interaction before starting a new one | |
# return chat(question, manual, history, liked_state.value) | |
def gradio_chat(question, manual, history): | |
save_last_interaction("N/A") # Save previous interaction before starting a new one | |
history.append((question, "")) | |
yield "", history | |
chat_generator = chat(question, manual, history, liked_state.value) | |
final_response = "" | |
final_history = history | |
for partial_response, updated_history in chat_generator: | |
final_response += partial_response | |
final_history = updated_history | |
yield "", final_history | |
return "", final_history | |
textbox.submit(gradio_chat, [textbox, manual, chatbot], [textbox, chatbot]) | |
chatbot.like(handle_like, None, None) | |
demo.queue() | |
demo.launch() | |