soyleyicicem commited on
Commit
48129e9
·
verified ·
1 Parent(s): d232287

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +143 -108
app.py CHANGED
@@ -13,8 +13,14 @@ from openai import AzureOpenAI
13
  import json
14
  from qdrant_client.http import models as rest
15
  import time
 
 
 
 
 
 
 
16
 
17
- embeddings = import_embedding()
18
  AZURE_OPENAI_KEY = os.getenv('azure_api')
19
  os.environ['AZURE_OPENAI_KEY'] = AZURE_OPENAI_KEY
20
  openai.api_version = "2024-08-01-preview" # change it with your own version
@@ -30,15 +36,47 @@ qclient = obj_qdrant.initialize_db()
30
  obj_loader = PDFLoader()
31
 
32
  # -----
33
- def retriever_db(db, CAR_ID):
34
 
35
- retriever = db.as_retriever(search_kwargs={'k': 4}, filter=rest.Filter(
36
- must=[
37
- models.FieldCondition(key="car_id", match=models.MatchValue(value=CAR_ID))
38
- ]
39
- ))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
40
 
41
- return retriever
42
 
43
  ## new version
44
  def chat_gpt(prompt=None, history=[], model=model, client=client, tools=[None]):
@@ -94,10 +132,12 @@ def get_section_content(section_title, sub_section_title, sub_sub_section_title,
94
  response = None
95
  try:
96
  response = doc_section_content["TableOfContents"][section_title][sub_section_title][sub_sub_section_title]["content"]
97
-
 
 
98
  except:
99
  pass
100
-
101
  return response
102
 
103
  def get_lead_result(question):
@@ -185,6 +225,32 @@ def format_chat_prompt(chat_history):
185
  prompt.append({"role": "assistant", "content": ai_message})
186
 
187
  return prompt
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
188
 
189
  liked_state = gr.State(None)
190
  last_interaction = gr.State(None)
@@ -199,9 +265,9 @@ def chat(question, manual, history, liked):
199
  "Renault_Clio_2024_TR":-5514489544983735006,
200
  "Fiat_Egea_2024_TR":-2026113796962100812}
201
 
202
- collection_list = {"Toyota_Corolla_2024_TR": "TOYOTA_MANUAL_COLLECTION_EMBED3",
203
- "Renault_Clio_2024_TR": "RENAULT_MANUAL_COLLECTION_EMBED3",
204
- "Fiat_Egea_2024_TR": "FIAT_MANUAL_COLLECTION_EMBED3"}
205
 
206
  collection_name = collection_list[manual]
207
 
@@ -212,28 +278,24 @@ def chat(question, manual, history, liked):
212
  content = json.loads(file.read())
213
  print("ToCs:--- %s seconds ---" % (time.time() - start_time))
214
 
215
- start_time = time.time()
216
- db = obj_loader.load_from_database(embeddings=embeddings, collection_name=collection_name)
217
- print("DB Load:--- %s seconds ---" % (time.time() - start_time))
218
-
219
- CAR_ID = manual_list[manual]
220
-
221
- retriever = retriever_db(db, CAR_ID)
222
 
223
  start_time = time.time()
224
 
225
  for i in range(3):
226
  first_hop = f"""Soruyu cevaplarken:
227
  1- Önce soruyu düşün.
228
- 2- Kullanıcının sorduğu sorunun konu başlıkları neler olabilir?
229
- 3- Bu konu başlıkları kullanım kılavuzu içindekiler tablosu başlıkları ile alakalı mı?
230
- 4- Alakalı olabilecek tüm başlıkları türet.
 
231
  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.
232
 
233
  Eğer herhangi bir içeriğe ulaşamazsan, bunu belir ve sorunun cevabı hakkında yorum yapma.
234
  Kullanım Kılavuzu İçindekiler Tablosu:
235
  {content}
236
-
237
  """
238
  # conv = [{"role": "system", "content": f"{first_hop}"}]
239
  # conv.append({"role": "system", "content": f"{first_hop}"})
@@ -260,107 +322,80 @@ def chat(question, manual, history, liked):
260
  print("First_hop:--- %s seconds ---" % (time.time() - start_time))
261
 
262
  path = "Contents/" + manual + ".json"
263
-
264
- # start_time = time.time()
265
- # i = 0
266
- # while(i < 2):
267
- # tool_calls = first_hop_response.choices[-1].message.tool_calls
268
- # if tool_calls:
269
- # for tool_call in tool_calls:
270
- # function_name = tool_call.function.name
271
- # args = json.loads(tool_call.function.arguments)
272
- # print(f"Will call {function_name} with arguments {args}")
273
-
274
- # if function_name == 'get_section_content':
275
- # addition = get_section_content(str(args['section_title']), str(args['sub_section_title']), str(args['sub_sub_section_title']), content_path=path)
276
- # if not addition:
277
- # addition = ' '
278
-
279
- # conv.append({
280
- # "tool_call_id": tool_call.id,
281
- # "role": "tool",
282
- # "name": function_name,
283
- # "content": addition
284
- # })
285
- # first_hop_response = chat_gpt(prompt=None, history=conv, tools=retrieval_functions)
286
- # else:
287
- # conv.append(first_hop_response.choices[-1].message)
288
- # break
289
- # i += 1
290
-
291
- # print("Second_hop:--- %s seconds ---" % (time.time() - start_time))
292
 
293
  start_time = time.time()
294
  documents = []
295
  for i in arg_list:
296
  documents.append(get_section_content(str(i['section_title']), str(i['sub_section_title']), str(i['sub_sub_section_title']), content_path=path))
297
-
298
- documents_db = retriever.invoke(question)
299
- documents.append(documents_db)
300
 
 
 
 
 
 
301
  print("Retriever:--- %s seconds ---" % (time.time() - start_time))
302
 
303
  start_time = time.time()
304
- if get_lead_result(question).lower() == 'yes':
 
 
 
 
 
 
 
 
 
 
 
305
  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.
306
  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."""
307
  print('Lead: yes')
308
  else:
309
- 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.'
310
  print('Lead: no')
311
- print("Lead Check:--- %s seconds ---" % (time.time() - start_time))
312
 
313
  start_time = time.time()
314
  prompt = f"""
315
- Sen, yalnızca araba sorunları ve araç bilgilerine odaklanan, ARVI adında uzman bir asistansın.
316
- 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.
 
317
 
318
- Ayrıca, temel nezaket etkileşimlerine uygun ve kibar bir şekilde yanıt vermek için tasarlandın. İşte yönergeler:
319
-
320
- 1. Araba Sorunları ve Araç Bilgileri:
321
-
322
- - Araba sorunları, teşhis, onarımlar, bakım ve araç teknik özellikleri ile ilgili soruları her zaman yanıtla.
323
- - Soruları yanıtlarken yorum yapma ve kişisel görüşlerini belirtme.
324
-
325
- 2. Referanslar:
326
-
327
- - Bir soruyu yanıtlarken, cevabın sonunda, faydalandığın dokümanın sayfa numarasını veya bölümünü mutlaka referans olarak ekle.
328
- - Aynı referansı tekrar etme.
329
- - Doküman kullandığın cevaplarda referans eklemek zorundasın.
330
- - Doküman kullanamadığında zaten cevap veremezsin.
331
-
332
- Lead: {lead} \n
333
-
334
- Dokümanlarda verilen tüm bilgilere dayanarak, aşağıdaki soruyu kısaca yanıtla: \n
335
- Sorulara cevap verirken sana sağlanan bilgilerdeki uyarılara, tehlikelere vurgu yap. \n
 
 
 
 
 
 
 
 
 
 
 
 
 
336
 
337
- Dokümanlar: {documents}
338
- Elde ettiğin bilgiler soru ile ilgili görünmüyorsa cevap veremeyeceğini belirt.
339
-
340
- Kullanıcıya doğrudan cevap ver. \n
341
- Soru çok genel ise, spesifik bilgi iste. \n
342
- Eğer sorunun cevabına ulaşamadıysan, bu soruya cevap veremeyeceğini belirt.
343
- Kesinlikle cevaplar üzerine yorum yapma ve bilgi dağarcığını kullanma.
344
- Referans verme örneği:
345
- Ref-1:
346
- Ref-2:
347
- ...
348
- """
349
- #final_response = chat_gpt_nofn(prompt=prompt, history=conv)
350
- #response = final_response.choices[-1].message.content
351
- #conv.append(final_response.choices[-1].message)
352
-
353
- #history.append((question, response))
354
- #print("Answer:--- %s seconds ---" % (time.time() - start_time))
355
- # Store the last interaction without saving to the database yet
356
- #last_interaction.value = {
357
- # "question": question,
358
- # "response": response,
359
- # "manual": manual,
360
- # "point_id": uuid.uuid4().hex
361
- #}
362
-
363
- #return '', history
364
  conv.append({"role": "system", "content": f"{prompt}"})
365
  final_response = chat_gpt_nofn(prompt=f"Soru: {question}", history=conv)
366
  # final_response = chat_gpt_nofn(prompt=prompt, history=conv)
@@ -399,10 +434,10 @@ def save_last_interaction(feedback):
399
  if last_interaction.value:
400
  DatabaseOperations.save_user_history_demo(
401
  qclient,
402
- "USER_COLLECTION_EMBED3_v2",
403
  last_interaction.value["question"],
404
  last_interaction.value["response"],
405
- embeddings,
406
  last_interaction.value["point_id"],
407
  last_interaction.value["manual"],
408
  feedback
 
13
  import json
14
  from qdrant_client.http import models as rest
15
  import time
16
+ from fastembed.sparse.bm25 import Bm25
17
+ from fastembed.late_interaction import LateInteractionTextEmbedding
18
+
19
+ dense_embedding_model = import_embedding()
20
+
21
+ late_interaction_embedding_model = LateInteractionTextEmbedding("colbert-ir/colbertv2.0")
22
+ bm25_embedding_model = Bm25("Qdrant/bm25", language="turkish")
23
 
 
24
  AZURE_OPENAI_KEY = os.getenv('azure_api')
25
  os.environ['AZURE_OPENAI_KEY'] = AZURE_OPENAI_KEY
26
  openai.api_version = "2024-08-01-preview" # change it with your own version
 
36
  obj_loader = PDFLoader()
37
 
38
  # -----
39
+ def retriever_db(client, query, collection_name, CAR_ID):
40
 
41
+ dense_query_vector = list(dense_embedding_model.embed_documents([query]))[0]
42
+ sparse_query_vector = list(bm25_embedding_model.query_embed(query))[0]
43
+ late_query_vector = list(late_interaction_embedding_model.query_embed(query))[0].tolist()
44
+
45
+ prefetch = [
46
+ models.Prefetch(
47
+ query=dense_query_vector,
48
+ using="sfr-mistral",
49
+ limit=30,
50
+ ),
51
+ models.Prefetch(
52
+ query=models.SparseVector(**sparse_query_vector.as_object()),
53
+ using="bm25",
54
+ limit=30,
55
+ ),
56
+ models.Prefetch(
57
+ query=late_query_vector,
58
+ using="colbertv2.0",
59
+ limit=30,
60
+ ),
61
+ ]
62
+
63
+ results = client.query_points(
64
+ collection_name,
65
+ prefetch=prefetch,
66
+ query=models.FusionQuery(
67
+ fusion=models.Fusion.RRF,
68
+ ),
69
+ with_payload=True,
70
+ filter=models.Filter(
71
+ must=[
72
+ models.FieldCondition(key="car_id", match=models.MatchValue(value=CAR_ID))
73
+ ])
74
+
75
+ limit=10,
76
+ )
77
+ retrieved_chunks = [doc.payload for doc in results.points]
78
 
79
+ return retrieved_chunks
80
 
81
  ## new version
82
  def chat_gpt(prompt=None, history=[], model=model, client=client, tools=[None]):
 
132
  response = None
133
  try:
134
  response = doc_section_content["TableOfContents"][section_title][sub_section_title][sub_sub_section_title]["content"]
135
+ pages = doc_section_content["TableOfContents"][section_title][sub_section_title][sub_sub_section_title]["pages"]
136
+
137
+ response = {"metadata":{"pages": pages}, "page_content": response}
138
  except:
139
  pass
140
+
141
  return response
142
 
143
  def get_lead_result(question):
 
225
  prompt.append({"role": "assistant", "content": ai_message})
226
 
227
  return prompt
228
+
229
+ class GradeDocuments(BaseModel):
230
+ """Binary score for relevance check on retrieved documents."""
231
+
232
+ binary_score: str = Field(description="Documents are relevant to the question, 'yes' or 'no'")
233
+
234
+ def grade_document_with_openai(document: str, question: str) -> GradeDocuments:
235
+ system_message = """
236
+ You are a grader assessing relevance of a retrieved document to a user question.
237
+ Consider the following when making your assessment:
238
+ - Does the document directly or indiretly address the user's question?
239
+ - Does it provide information or context that is pertinent to the question?
240
+ - Does it discuss relevant risks, benefits, recommendations, or considerations related to the question?
241
+ If the document contains keyword(s) or semantic meaning related or partially related to the question, grade it as relevant.
242
+ Give a binary score 'yes' or 'no' score to indicate whether the document is relevant to the question.
243
+ """
244
+ response = client.chat.completions.create(
245
+ model=model,
246
+ messages=[
247
+ {"role": "system", "content": system_message},
248
+ {"role": "user", "content": f'Retrieved document: \n\n {document} \n\n User question: {question}'}
249
+ ]
250
+ )
251
+
252
+ score = response.choices[0].message.content
253
+ return GradeDocuments(binary_score=score.strip())
254
 
255
  liked_state = gr.State(None)
256
  last_interaction = gr.State(None)
 
265
  "Renault_Clio_2024_TR":-5514489544983735006,
266
  "Fiat_Egea_2024_TR":-2026113796962100812}
267
 
268
+ collection_list = {"Toyota_Corolla_2024_TR": "HYBRID_TOYOTA_MANUAL_COLLECTION_EMBED3",
269
+ "Renault_Clio_2024_TR": "HYBRID_RENAULT_MANUAL_COLLECTION_EMBED3",
270
+ "Fiat_Egea_2024_TR": "HYBRID_FIAT_MANUAL_COLLECTION_EMBED3"}
271
 
272
  collection_name = collection_list[manual]
273
 
 
278
  content = json.loads(file.read())
279
  print("ToCs:--- %s seconds ---" % (time.time() - start_time))
280
 
281
+ # start_time = time.time()
282
+ # db = obj_loader.load_from_database(embeddings=embeddings, collection_name=collection_name)
283
+ # print("DB Load:--- %s seconds ---" % (time.time() - start_time))
 
 
 
 
284
 
285
  start_time = time.time()
286
 
287
  for i in range(3):
288
  first_hop = f"""Soruyu cevaplarken:
289
  1- Önce soruyu düşün.
290
+ 2- Kullanıcının sorduğu sorunun konu başlıkları neler olabilir?
291
+ 3- Sorulan soru bir arızaya işaret ediyo olabilir mi?
292
+ 4- Bu konu başlıkları kullanım kılavuzu içindekiler tablosu başlıkları ile alakalı mı?
293
+ 5- Alakalı olabilecek tüm başlıkları türet.
294
  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.
295
 
296
  Eğer herhangi bir içeriğe ulaşamazsan, bunu belir ve sorunun cevabı hakkında yorum yapma.
297
  Kullanım Kılavuzu İçindekiler Tablosu:
298
  {content}
 
299
  """
300
  # conv = [{"role": "system", "content": f"{first_hop}"}]
301
  # conv.append({"role": "system", "content": f"{first_hop}"})
 
322
  print("First_hop:--- %s seconds ---" % (time.time() - start_time))
323
 
324
  path = "Contents/" + manual + ".json"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
325
 
326
  start_time = time.time()
327
  documents = []
328
  for i in arg_list:
329
  documents.append(get_section_content(str(i['section_title']), str(i['sub_section_title']), str(i['sub_sub_section_title']), content_path=path))
330
+
331
+ CAR_ID = manual_list[manual]
 
332
 
333
+ documents_db = retriever_db(qclient, query, collection_name, CAR_ID)
334
+
335
+ for i in documents_db:
336
+ documents.append(i)
337
+
338
  print("Retriever:--- %s seconds ---" % (time.time() - start_time))
339
 
340
  start_time = time.time()
341
+ graded_doc = []
342
+ for r in documents:
343
+
344
+ grade = grade_document_with_openai(r, query)
345
+
346
+ if grade.binary_score == "yes":
347
+ graded_doc.append(r)
348
+ print("Grade Doc:--- %s seconds ---" % (time.time() - start_time))
349
+
350
+
351
+ start_time = time.time()
352
+ if get_lead_result(query).lower() == 'yes':
353
  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.
354
  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."""
355
  print('Lead: yes')
356
  else:
357
+ 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. Sorunun tipine göre OtoBakım servislerine yönlendirme yapmalısın.'
358
  print('Lead: no')
359
+ print("Lead Check:--- %s seconds ---" % (time.time() - start_time))
360
 
361
  start_time = time.time()
362
  prompt = f"""
363
+ Sen, yalnızca araba ile ilgili sorunlara ve araç bilgilerine odaklanan, ARVI adında uzman bir asistansın.
364
+ Amacın, araba sorunları, bakım, onarımlar, teknik özellikler ve diğer araçla ilgili konularla ilgili sorulara eğer dokümanlarda yeterli bilgi varsa doğru, yardımcı, net ve yorum yapmadan cevaplar vermektir.
365
+ Temel nezaket etkileşimlerine uygun ve kibar bir şekilde yanıt vermek için tasarlandın.
366
 
367
+ Soruları yanıtlarken aşağıdaki adımları izle: \n
368
+ - Dokümanlar soruyla ilgiliyse, soruyu yanıtlamak için dokümanlardan yararlan.
369
+ - Sorulara cevap verirken sana sağlanan bilgilerdeki uyarılara, tehlikelere vurgu yap ve öne çıkar.
370
+ - Soruları yanıtlarken yorum yapma, kişisel görüşlerini belirtme ve önceki bilgilerini kullanma.
371
+ - Dokümandakiler dışında terim ve bilgileri kullanma.
372
+ - Eğer dokümanlarda bir işlemin nasıl yapıldığı adım adım anlatılıyorsa, bu adımları direkt şekilde ekle.
373
+ - Dokümanlarda farklı motor modellerine göre bilgi veriliyorsa, aracın motor modelini belirt.
374
+ - Kullanıcıya doğrudan cevap ver.
375
+ - Cevaplar kısa ama anlamlı ve yeterli olsun.
376
+ - Her cevabında kullandığın tüm kaynakları göster.
377
+ - Cevap verirken aşağıdaki kaynak verme kurallarına uy:
378
+ * Sayfa numaralarını küçükten büyüğe sırala.
379
+ * Aynı cümle içinde tekrar eden sayfa numaralarını eleme.
380
+ * Aynı numarayı birden fazla kez yazma.
381
+ * Cevabın sonunda kullanılan tüm kaynakları listele:
382
+ Kaynaklar:
383
+ - Sayfa **: [Doküman adı veya kısa açıklama]
384
+ - Sayfa **: [Doküman adı veya kısa açıklama]
385
+
386
+ Ek yönerge: {lead} \n
387
+
388
+ Son Kontrol:
389
+ - Cevabın doğruluğunu ve tamlığını kontrol et.
390
+ - Gereksiz bilgi veya yorum olup olmadığını kontrol et.
391
+ - Referansların doğru eklendiğinden emin ol.
392
+
393
+ Eğer dokümanlar boş ise: "Üzgünüm, kılavuzda bu konuyla ilgili bilgi bulamadım. Bu soruyu yanıtlayamıyorum."
394
+ Soru çok genel ise, spesifik bilgi iste.
395
+
396
+ Dokümanlar: {graded_doc}
397
+ """
398
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
399
  conv.append({"role": "system", "content": f"{prompt}"})
400
  final_response = chat_gpt_nofn(prompt=f"Soru: {question}", history=conv)
401
  # final_response = chat_gpt_nofn(prompt=prompt, history=conv)
 
434
  if last_interaction.value:
435
  DatabaseOperations.save_user_history_demo(
436
  qclient,
437
+ "USER_COLLECTION_EMBED3_v3",
438
  last_interaction.value["question"],
439
  last_interaction.value["response"],
440
+ dense_embedding_model,
441
  last_interaction.value["point_id"],
442
  last_interaction.value["manual"],
443
  feedback