Shreyas094 commited on
Commit
149b538
·
verified ·
1 Parent(s): dc56661

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +130 -30
app.py CHANGED
@@ -33,7 +33,8 @@ print(f"CLOUDFLARE_AUTH_TOKEN: {API_TOKEN[:5]}..." if API_TOKEN else "Not set")
33
  MODELS = [
34
  "mistralai/Mistral-7B-Instruct-v0.3",
35
  "mistralai/Mixtral-8x7B-Instruct-v0.1",
36
- "@cf/meta/llama-3.1-8b-instruct"
 
37
  ]
38
 
39
  # Initialize LlamaParse
@@ -63,32 +64,60 @@ def load_document(file: NamedTemporaryFile, parser: str = "llamaparse") -> List[
63
  raise ValueError("Invalid parser specified. Use 'pypdf' or 'llamaparse'.")
64
 
65
  def get_embeddings():
66
- return HuggingFaceEmbeddings(model_name="sentence-transformers/all-mpnet-base-v2")
67
 
68
  def update_vectors(files, parser):
 
 
 
69
  if not files:
70
- return "Please upload at least one PDF file."
 
 
 
 
 
71
 
72
  embed = get_embeddings()
73
  total_chunks = 0
74
 
75
  all_data = []
76
  for file in files:
77
- data = load_document(file, parser)
78
- all_data.extend(data)
79
- total_chunks += len(data)
 
 
 
 
 
 
 
 
 
 
 
 
 
80
 
81
  if os.path.exists("faiss_database"):
 
82
  database = FAISS.load_local("faiss_database", embed, allow_dangerous_deserialization=True)
83
  database.add_documents(all_data)
84
  else:
 
85
  database = FAISS.from_documents(all_data, embed)
86
 
87
  database.save_local("faiss_database")
 
88
 
89
- return f"Vector store updated successfully. Processed {total_chunks} chunks from {len(files)} files using {parser}."
 
 
 
 
90
 
91
- def generate_chunked_response(prompt, model, max_tokens=1000, num_calls=3, temperature=0.2, should_stop=False):
92
  print(f"Starting generate_chunked_response with {num_calls} calls")
93
  full_response = ""
94
  messages = [{"role": "user", "content": prompt}]
@@ -214,27 +243,39 @@ def retry_last_response(history, use_web_search, model, temperature, num_calls):
214
 
215
  return chatbot_interface(last_user_msg, history, use_web_search, model, temperature, num_calls)
216
 
217
- def respond(message, history, model, temperature, num_calls, use_web_search):
218
  logging.info(f"User Query: {message}")
219
  logging.info(f"Model Used: {model}")
220
  logging.info(f"Search Type: {'Web Search' if use_web_search else 'PDF Search'}")
221
 
 
 
222
  try:
223
  if use_web_search:
224
  for main_content, sources in get_response_with_search(message, model, num_calls=num_calls, temperature=temperature):
225
  response = f"{main_content}\n\n{sources}"
226
  first_line = response.split('\n')[0] if response else ''
227
- logging.info(f"Generated Response (first line): {first_line}")
228
  yield response
229
  else:
230
  embed = get_embeddings()
231
  if os.path.exists("faiss_database"):
232
  database = FAISS.load_local("faiss_database", embed, allow_dangerous_deserialization=True)
233
  retriever = database.as_retriever()
234
- relevant_docs = retriever.get_relevant_documents(message)
 
 
 
 
 
 
 
 
235
  context_str = "\n".join([doc.page_content for doc in relevant_docs])
236
  else:
237
  context_str = "No documents available."
 
 
238
 
239
  if model == "@cf/meta/llama-3.1-8b-instruct":
240
  # Use Cloudflare API
@@ -244,7 +285,7 @@ def respond(message, history, model, temperature, num_calls, use_web_search):
244
  yield partial_response
245
  else:
246
  # Use Hugging Face API
247
- for partial_response in get_response_from_pdf(message, model, num_calls=num_calls, temperature=temperature):
248
  first_line = partial_response.split('\n')[0] if partial_response else ''
249
  logging.info(f"Generated Response (first line): {first_line}")
250
  yield partial_response
@@ -253,7 +294,7 @@ def respond(message, history, model, temperature, num_calls, use_web_search):
253
  if "microsoft/Phi-3-mini-4k-instruct" in model:
254
  logging.info("Falling back to Mistral model due to Phi-3 error")
255
  fallback_model = "mistralai/Mistral-7B-Instruct-v0.3"
256
- yield from respond(message, history, fallback_model, temperature, num_calls, use_web_search)
257
  else:
258
  yield f"An error occurred with the {model} model: {str(e)}. Please try again or select a different model."
259
 
@@ -284,7 +325,8 @@ After writing the document, please provide a list of sources used in your respon
284
  payload = {
285
  "messages": inputs,
286
  "stream": True,
287
- "temperature": temperature
 
288
  }
289
 
290
  full_response = ""
@@ -335,7 +377,7 @@ After writing the document, please provide a list of sources used in your respon
335
  for i in range(num_calls):
336
  for message in client.chat_completion(
337
  messages=[{"role": "user", "content": prompt}],
338
- max_tokens=1000,
339
  temperature=temperature,
340
  stream=True,
341
  ):
@@ -344,23 +386,46 @@ After writing the document, please provide a list of sources used in your respon
344
  main_content += chunk
345
  yield main_content, "" # Yield partial main content without sources
346
 
347
- def get_response_from_pdf(query, model, num_calls=3, temperature=0.2):
 
 
348
  embed = get_embeddings()
349
  if os.path.exists("faiss_database"):
 
350
  database = FAISS.load_local("faiss_database", embed, allow_dangerous_deserialization=True)
351
  else:
 
352
  yield "No documents available. Please upload PDF documents to answer questions."
353
  return
354
 
355
  retriever = database.as_retriever()
 
356
  relevant_docs = retriever.get_relevant_documents(query)
357
- context_str = "\n".join([doc.page_content for doc in relevant_docs])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
358
 
359
  if model == "@cf/meta/llama-3.1-8b-instruct":
 
360
  # Use Cloudflare API with the retrieved context
361
  for response in get_response_from_cloudflare(prompt="", context=context_str, query=query, num_calls=num_calls, temperature=temperature, search_type="pdf"):
362
  yield response
363
  else:
 
364
  # Use Hugging Face API
365
  prompt = f"""Using the following context from the PDF documents:
366
  {context_str}
@@ -370,9 +435,10 @@ Write a detailed and complete response that answers the following user question:
370
 
371
  response = ""
372
  for i in range(num_calls):
 
373
  for message in client.chat_completion(
374
  messages=[{"role": "user", "content": prompt}],
375
- max_tokens=1000,
376
  temperature=temperature,
377
  stream=True,
378
  ):
@@ -380,6 +446,8 @@ Write a detailed and complete response that answers the following user question:
380
  chunk = message.choices[0].delta.content
381
  response += chunk
382
  yield response # Yield partial response
 
 
383
 
384
  def vote(data: gr.LikeData):
385
  if data.liked:
@@ -388,22 +456,44 @@ def vote(data: gr.LikeData):
388
  print(f"You downvoted this response: {data.value}")
389
 
390
  css = """
391
- /* Add your custom CSS here */
 
 
 
 
 
 
 
 
392
  """
393
 
 
 
 
 
 
 
 
 
 
394
  # Define the checkbox outside the demo block
395
- use_web_search = gr.Checkbox(label="Use Web Search", value=False)
 
 
 
 
396
 
397
  demo = gr.ChatInterface(
398
  respond,
399
  additional_inputs=[
400
- gr.Dropdown(choices=MODELS, label="Select Model", value=MODELS[0]),
401
  gr.Slider(minimum=0.1, maximum=1.0, value=0.2, step=0.1, label="Temperature"),
402
  gr.Slider(minimum=1, maximum=5, value=1, step=1, label="Number of API Calls"),
403
- use_web_search # Add this line to include the checkbox
 
404
  ],
405
  title="AI-powered Web Search and PDF Chat Assistant",
406
- description="Chat with your PDFs or use web search to answer questions.",
407
  theme=gr.themes.Soft(
408
  primary_hue="orange",
409
  secondary_hue="amber",
@@ -422,7 +512,6 @@ demo = gr.ChatInterface(
422
  color_accent_soft_dark="transparent",
423
  code_background_fill_dark="#140b0b"
424
  ),
425
-
426
  css=css,
427
  examples=[
428
  ["Tell me about the contents of the uploaded PDFs."],
@@ -431,6 +520,13 @@ demo = gr.ChatInterface(
431
  ],
432
  cache_examples=False,
433
  analytics_enabled=False,
 
 
 
 
 
 
 
434
  )
435
 
436
  # Add file upload functionality
@@ -443,18 +539,22 @@ with demo:
443
  update_button = gr.Button("Upload Document")
444
 
445
  update_output = gr.Textbox(label="Update Status")
446
- update_button.click(update_vectors, inputs=[file_input, parser_dropdown], outputs=update_output)
447
-
448
 
 
 
 
 
 
449
  gr.Markdown(
450
  """
451
  ## How to use
452
  1. Upload PDF documents using the file input at the top.
453
  2. Select the PDF parser (pypdf or llamaparse) and click "Upload Document" to update the vector store.
454
- 3. Ask questions in the chat interface.
455
- 4. Toggle "Use Web Search" to switch between PDF chat and web search.
456
- 5. Adjust Temperature and Number of API Calls to fine-tune the response generation.
457
- 6. Use the provided examples or ask your own questions.
 
458
  """
459
  )
460
 
 
33
  MODELS = [
34
  "mistralai/Mistral-7B-Instruct-v0.3",
35
  "mistralai/Mixtral-8x7B-Instruct-v0.1",
36
+ "@cf/meta/llama-3.1-8b-instruct",
37
+ "mistralai/Mistral-Nemo-Instruct-2407"
38
  ]
39
 
40
  # Initialize LlamaParse
 
64
  raise ValueError("Invalid parser specified. Use 'pypdf' or 'llamaparse'.")
65
 
66
  def get_embeddings():
67
+ return HuggingFaceEmbeddings(model_name="sentence-transformers/stsb-roberta-large")
68
 
69
  def update_vectors(files, parser):
70
+ global uploaded_documents
71
+ logging.info(f"Entering update_vectors with {len(files)} files and parser: {parser}")
72
+
73
  if not files:
74
+ logging.warning("No files provided for update_vectors")
75
+ return "Please upload at least one PDF file.", gr.CheckboxGroup(
76
+ choices=[doc["name"] for doc in uploaded_documents],
77
+ value=[doc["name"] for doc in uploaded_documents if doc["selected"]],
78
+ label="Select documents to query"
79
+ )
80
 
81
  embed = get_embeddings()
82
  total_chunks = 0
83
 
84
  all_data = []
85
  for file in files:
86
+ logging.info(f"Processing file: {file.name}")
87
+ try:
88
+ data = load_document(file, parser)
89
+ logging.info(f"Loaded {len(data)} chunks from {file.name}")
90
+ all_data.extend(data)
91
+ total_chunks += len(data)
92
+ # Append new documents instead of replacing
93
+ if not any(doc["name"] == file.name for doc in uploaded_documents):
94
+ uploaded_documents.append({"name": file.name, "selected": True})
95
+ logging.info(f"Added new document to uploaded_documents: {file.name}")
96
+ else:
97
+ logging.info(f"Document already exists in uploaded_documents: {file.name}")
98
+ except Exception as e:
99
+ logging.error(f"Error processing file {file.name}: {str(e)}")
100
+
101
+ logging.info(f"Total chunks processed: {total_chunks}")
102
 
103
  if os.path.exists("faiss_database"):
104
+ logging.info("Updating existing FAISS database")
105
  database = FAISS.load_local("faiss_database", embed, allow_dangerous_deserialization=True)
106
  database.add_documents(all_data)
107
  else:
108
+ logging.info("Creating new FAISS database")
109
  database = FAISS.from_documents(all_data, embed)
110
 
111
  database.save_local("faiss_database")
112
+ logging.info("FAISS database saved")
113
 
114
+ return f"Vector store updated successfully. Processed {total_chunks} chunks from {len(files)} files using {parser}.", gr.CheckboxGroup(
115
+ choices=[doc["name"] for doc in uploaded_documents],
116
+ value=[doc["name"] for doc in uploaded_documents if doc["selected"]],
117
+ label="Select documents to query"
118
+ )
119
 
120
+ def generate_chunked_response(prompt, model, max_tokens=10000, num_calls=3, temperature=0.2, should_stop=False):
121
  print(f"Starting generate_chunked_response with {num_calls} calls")
122
  full_response = ""
123
  messages = [{"role": "user", "content": prompt}]
 
243
 
244
  return chatbot_interface(last_user_msg, history, use_web_search, model, temperature, num_calls)
245
 
246
+ def respond(message, history, model, temperature, num_calls, use_web_search, selected_docs):
247
  logging.info(f"User Query: {message}")
248
  logging.info(f"Model Used: {model}")
249
  logging.info(f"Search Type: {'Web Search' if use_web_search else 'PDF Search'}")
250
 
251
+ logging.info(f"Selected Documents: {selected_docs}")
252
+
253
  try:
254
  if use_web_search:
255
  for main_content, sources in get_response_with_search(message, model, num_calls=num_calls, temperature=temperature):
256
  response = f"{main_content}\n\n{sources}"
257
  first_line = response.split('\n')[0] if response else ''
258
+ # logging.info(f"Generated Response (first line): {first_line}")
259
  yield response
260
  else:
261
  embed = get_embeddings()
262
  if os.path.exists("faiss_database"):
263
  database = FAISS.load_local("faiss_database", embed, allow_dangerous_deserialization=True)
264
  retriever = database.as_retriever()
265
+
266
+ # Filter relevant documents based on user selection
267
+ all_relevant_docs = retriever.get_relevant_documents(message)
268
+ relevant_docs = [doc for doc in all_relevant_docs if doc.metadata["source"] in selected_docs]
269
+
270
+ if not relevant_docs:
271
+ yield "No relevant information found in the selected documents. Please try selecting different documents or rephrasing your query."
272
+ return
273
+
274
  context_str = "\n".join([doc.page_content for doc in relevant_docs])
275
  else:
276
  context_str = "No documents available."
277
+ yield "No documents available. Please upload PDF documents to answer questions."
278
+ return
279
 
280
  if model == "@cf/meta/llama-3.1-8b-instruct":
281
  # Use Cloudflare API
 
285
  yield partial_response
286
  else:
287
  # Use Hugging Face API
288
+ for partial_response in get_response_from_pdf(message, model, selected_docs, num_calls=num_calls, temperature=temperature):
289
  first_line = partial_response.split('\n')[0] if partial_response else ''
290
  logging.info(f"Generated Response (first line): {first_line}")
291
  yield partial_response
 
294
  if "microsoft/Phi-3-mini-4k-instruct" in model:
295
  logging.info("Falling back to Mistral model due to Phi-3 error")
296
  fallback_model = "mistralai/Mistral-7B-Instruct-v0.3"
297
+ yield from respond(message, history, fallback_model, temperature, num_calls, use_web_search, selected_docs)
298
  else:
299
  yield f"An error occurred with the {model} model: {str(e)}. Please try again or select a different model."
300
 
 
325
  payload = {
326
  "messages": inputs,
327
  "stream": True,
328
+ "temperature": temperature,
329
+ "max_tokens": 32000
330
  }
331
 
332
  full_response = ""
 
377
  for i in range(num_calls):
378
  for message in client.chat_completion(
379
  messages=[{"role": "user", "content": prompt}],
380
+ max_tokens=10000,
381
  temperature=temperature,
382
  stream=True,
383
  ):
 
386
  main_content += chunk
387
  yield main_content, "" # Yield partial main content without sources
388
 
389
+ def get_response_from_pdf(query, model, selected_docs, num_calls=3, temperature=0.2):
390
+ logging.info(f"Entering get_response_from_pdf with query: {query}, model: {model}, selected_docs: {selected_docs}")
391
+
392
  embed = get_embeddings()
393
  if os.path.exists("faiss_database"):
394
+ logging.info("Loading FAISS database")
395
  database = FAISS.load_local("faiss_database", embed, allow_dangerous_deserialization=True)
396
  else:
397
+ logging.warning("No FAISS database found")
398
  yield "No documents available. Please upload PDF documents to answer questions."
399
  return
400
 
401
  retriever = database.as_retriever()
402
+ logging.info(f"Retrieving relevant documents for query: {query}")
403
  relevant_docs = retriever.get_relevant_documents(query)
404
+ logging.info(f"Number of relevant documents retrieved: {len(relevant_docs)}")
405
+
406
+ # Filter relevant_docs based on selected documents
407
+ filtered_docs = [doc for doc in relevant_docs if doc.metadata["source"] in selected_docs]
408
+ logging.info(f"Number of filtered documents: {len(filtered_docs)}")
409
+
410
+ if not filtered_docs:
411
+ logging.warning(f"No relevant information found in the selected documents: {selected_docs}")
412
+ yield "No relevant information found in the selected documents. Please try selecting different documents or rephrasing your query."
413
+ return
414
+
415
+ for doc in filtered_docs:
416
+ logging.info(f"Document source: {doc.metadata['source']}")
417
+ logging.info(f"Document content preview: {doc.page_content[:100]}...") # Log first 100 characters of each document
418
+
419
+ context_str = "\n".join([doc.page_content for doc in filtered_docs])
420
+ logging.info(f"Total context length: {len(context_str)}")
421
 
422
  if model == "@cf/meta/llama-3.1-8b-instruct":
423
+ logging.info("Using Cloudflare API")
424
  # Use Cloudflare API with the retrieved context
425
  for response in get_response_from_cloudflare(prompt="", context=context_str, query=query, num_calls=num_calls, temperature=temperature, search_type="pdf"):
426
  yield response
427
  else:
428
+ logging.info("Using Hugging Face API")
429
  # Use Hugging Face API
430
  prompt = f"""Using the following context from the PDF documents:
431
  {context_str}
 
435
 
436
  response = ""
437
  for i in range(num_calls):
438
+ logging.info(f"API call {i+1}/{num_calls}")
439
  for message in client.chat_completion(
440
  messages=[{"role": "user", "content": prompt}],
441
+ max_tokens=10000,
442
  temperature=temperature,
443
  stream=True,
444
  ):
 
446
  chunk = message.choices[0].delta.content
447
  response += chunk
448
  yield response # Yield partial response
449
+
450
+ logging.info("Finished generating response")
451
 
452
  def vote(data: gr.LikeData):
453
  if data.liked:
 
456
  print(f"You downvoted this response: {data.value}")
457
 
458
  css = """
459
+ /* Fine-tune chatbox size */
460
+ .chatbot-container {
461
+ height: 600px !important;
462
+ width: 100% !important;
463
+ }
464
+ .chatbot-container > div {
465
+ height: 100%;
466
+ width: 100%;
467
+ }
468
  """
469
 
470
+ uploaded_documents = []
471
+
472
+ def display_documents():
473
+ return gr.CheckboxGroup(
474
+ choices=[doc["name"] for doc in uploaded_documents],
475
+ value=[doc["name"] for doc in uploaded_documents if doc["selected"]],
476
+ label="Select documents to query"
477
+ )
478
+
479
  # Define the checkbox outside the demo block
480
+ document_selector = gr.CheckboxGroup(label="Select documents to query")
481
+
482
+ use_web_search = gr.Checkbox(label="Use Web Search", value=True)
483
+
484
+ custom_placeholder = "Ask a question (Note: You can toggle between Web Search and PDF Chat in Additional Inputs below)"
485
 
486
  demo = gr.ChatInterface(
487
  respond,
488
  additional_inputs=[
489
+ gr.Dropdown(choices=MODELS, label="Select Model", value=MODELS[3]),
490
  gr.Slider(minimum=0.1, maximum=1.0, value=0.2, step=0.1, label="Temperature"),
491
  gr.Slider(minimum=1, maximum=5, value=1, step=1, label="Number of API Calls"),
492
+ use_web_search,
493
+ document_selector
494
  ],
495
  title="AI-powered Web Search and PDF Chat Assistant",
496
+ description="Chat with your PDFs or use web search to answer questions. Toggle between Web Search and PDF Chat in Additional Inputs below.",
497
  theme=gr.themes.Soft(
498
  primary_hue="orange",
499
  secondary_hue="amber",
 
512
  color_accent_soft_dark="transparent",
513
  code_background_fill_dark="#140b0b"
514
  ),
 
515
  css=css,
516
  examples=[
517
  ["Tell me about the contents of the uploaded PDFs."],
 
520
  ],
521
  cache_examples=False,
522
  analytics_enabled=False,
523
+ textbox=gr.Textbox(placeholder=custom_placeholder, container=False, scale=7),
524
+ chatbot = gr.Chatbot(
525
+ show_copy_button=True,
526
+ likeable=True,
527
+ layout="bubble",
528
+ height=400,
529
+ )
530
  )
531
 
532
  # Add file upload functionality
 
539
  update_button = gr.Button("Upload Document")
540
 
541
  update_output = gr.Textbox(label="Update Status")
 
 
542
 
543
+ # Update both the output text and the document selector
544
+ update_button.click(update_vectors,
545
+ inputs=[file_input, parser_dropdown],
546
+ outputs=[update_output, document_selector])
547
+
548
  gr.Markdown(
549
  """
550
  ## How to use
551
  1. Upload PDF documents using the file input at the top.
552
  2. Select the PDF parser (pypdf or llamaparse) and click "Upload Document" to update the vector store.
553
+ 3. Select the documents you want to query using the checkboxes.
554
+ 4. Ask questions in the chat interface.
555
+ 5. Toggle "Use Web Search" to switch between PDF chat and web search.
556
+ 6. Adjust Temperature and Number of API Calls to fine-tune the response generation.
557
+ 7. Use the provided examples or ask your own questions.
558
  """
559
  )
560