Shreyas094 commited on
Commit
91d3e69
·
verified ·
1 Parent(s): d037811

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +169 -142
app.py CHANGED
@@ -17,10 +17,9 @@ from huggingface_hub import InferenceClient
17
  import inspect
18
  import logging
19
  import shutil
20
- import asyncio
21
- from concurrent.futures import ThreadPoolExecutor
22
 
23
- executor = ThreadPoolExecutor()
24
 
25
  # Set up basic configuration for logging
26
  logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
@@ -31,7 +30,6 @@ llama_cloud_api_key = os.environ.get("LLAMA_CLOUD_API_KEY")
31
  ACCOUNT_ID = os.environ.get("CLOUDFARE_ACCOUNT_ID")
32
  API_TOKEN = os.environ.get("CLOUDFLARE_AUTH_TOKEN")
33
  API_BASE_URL = "https://api.cloudflare.com/client/v4/accounts/a17f03e0f049ccae0c15cdcf3b9737ce/ai/run/"
34
- whisper_api = InferenceClient("openai/whisper-large-v2", token=huggingface_token)
35
 
36
  print(f"ACCOUNT_ID: {ACCOUNT_ID}")
37
  print(f"CLOUDFLARE_AUTH_TOKEN: {API_TOKEN[:5]}..." if API_TOKEN else "Not set")
@@ -401,82 +399,84 @@ def summarize_web_results(query: str, search_results: List[Dict[str, str]], conv
401
  return f"An error occurred during summarization: {str(e)}"
402
 
403
  # Modify the existing respond function to handle both PDF and web search
404
- # Modify your existing respond function to handle both PDF and web search
405
- async def respond(message, history, model, temperature, num_calls, use_web_search, selected_docs, progress=gr.Progress()):
406
- logger.info(f"User Query: {message}")
407
- logger.info(f"Model Used: {model}")
408
- logger.info(f"Selected Documents: {selected_docs}")
409
- logger.info(f"Use Web Search: {use_web_search}")
410
-
411
- response = ""
412
-
413
- try:
414
- if use_web_search:
415
- progress(0, desc="Starting web search")
416
- original_query = message
417
- rephrased_query = rephrase_query(message, conversation_manager)
418
- logger.info(f"Original query: {original_query}")
419
- logger.info(f"Rephrased query: {rephrased_query}")
420
-
421
- final_summary = ""
422
- for i in range(num_calls):
423
- progress((i + 1) * 33, desc=f"Performing web search {i+1}/{num_calls}")
424
- search_results = get_web_search_results(rephrased_query)
425
- if not search_results:
426
- final_summary += f"No search results found for the query: {rephrased_query}\n\n"
427
- elif "error" in search_results[0]:
428
- final_summary += search_results[0]["error"] + "\n\n"
429
- else:
430
- summary = summarize_web_results(rephrased_query, search_results, conversation_manager)
431
- final_summary += summary + "\n\n"
432
-
433
- if final_summary:
434
- conversation_manager.add_interaction(original_query, final_summary)
435
- response = final_summary
436
  else:
437
- response = "Unable to generate a response. Please try a different query."
 
438
 
 
 
 
439
  else:
440
- # Existing PDF search logic
441
- progress(0, desc="Starting PDF search")
 
 
442
  embed = get_embeddings()
443
  if os.path.exists("faiss_database"):
444
  database = FAISS.load_local("faiss_database", embed, allow_dangerous_deserialization=True)
445
  retriever = database.as_retriever(search_kwargs={"k": 20})
446
 
447
- progress(33, desc="Retrieving relevant documents")
448
  all_relevant_docs = retriever.get_relevant_documents(message)
449
  relevant_docs = [doc for doc in all_relevant_docs if doc.metadata["source"] in selected_docs]
450
 
451
  if not relevant_docs:
452
- response = "No relevant information found in the selected documents. Please try selecting different documents or rephrasing your query."
453
- else:
454
- context_str = "\n".join([doc.page_content for doc in relevant_docs])
455
- logger.info(f"Context length: {len(context_str)}")
456
-
457
- progress(66, desc="Generating response")
458
- if model.startswith("duckduckgo/"):
459
- # Use DuckDuckGo chat with context
460
- for partial_response in get_response_from_duckduckgo(message, model, context_str, num_calls, temperature):
461
- response += partial_response
462
- elif model == "@cf/meta/llama-3.1-8b-instruct":
463
- # Use Cloudflare API
464
- for partial_response in get_response_from_cloudflare(prompt="", context=context_str, query=message, num_calls=num_calls, temperature=temperature, search_type="pdf"):
465
- response += partial_response
466
- else:
467
- # Use Hugging Face API
468
- for partial_response in get_response_from_pdf(message, model, selected_docs, num_calls=num_calls, temperature=temperature):
469
- response += partial_response
470
  else:
471
- response = "No documents available. Please upload PDF documents to answer questions."
472
-
473
- except Exception as e:
474
- logger.error(f"Error in respond function: {str(e)}")
475
- response = f"An error occurred: {str(e)}. Please try again or select a different model."
476
-
477
- progress(100, desc="Response generation complete")
478
- return response
479
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
480
  logging.basicConfig(level=logging.DEBUG)
481
 
482
  def get_response_from_cloudflare(prompt, context, query, num_calls=3, temperature=0.2, search_type="pdf"):
@@ -615,33 +615,23 @@ Write a detailed and complete response that answers the following user question:
615
 
616
  logging.info("Finished generating response")
617
 
618
- # Modified transcribe function
619
- async def transcribe_with_timeout(audio_file, progress=gr.Progress()):
620
- if audio_file is None:
621
- logger.warning("No audio file provided")
622
- return "No audio file provided"
623
 
624
- try:
625
- logger.info(f"Starting transcription for file: {audio_file}")
626
- progress(0, desc="Starting transcription")
627
-
628
- with open(audio_file, "rb") as f:
629
- audio_data = f.read()
630
-
631
- logger.info("Audio file read successfully")
632
- progress(50, desc="Audio loaded, sending to API")
633
-
634
- response = await asyncio.wait_for(asyncio.to_thread(whisper_api, audio_data), timeout=30)
635
-
636
- logger.info("Transcription complete")
637
- progress(100, desc="Transcription complete")
638
- return response["text"]
639
- except asyncio.TimeoutError:
640
- logger.error("Transcription timed out")
641
- return "Transcription timed out. Please try again with a shorter audio clip."
642
- except Exception as e:
643
- logger.exception(f"Error during transcription: {str(e)}")
644
- return f"Error during transcription: {str(e)}"
645
 
646
  def vote(data: gr.LikeData):
647
  if data.liked:
@@ -692,39 +682,73 @@ use_web_search = gr.Checkbox(label="Use Web Search", value=False)
692
 
693
  custom_placeholder = "Ask a question (Note: You can toggle between Web Search and PDF Chat in Additional Inputs below)"
694
 
695
- def update_textbox(transcription):
696
- return gr.Textbox.update(value=transcription)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
697
 
698
- # Gradio interface
699
- with gr.Blocks() as demo:
700
- gr.Markdown("# AI-powered PDF Chat and Web Search Assistant with Speech Input")
701
-
702
  with gr.Row():
703
- with gr.Column(scale=1):
704
- audio_input = gr.Audio(sources=["microphone"], type="filepath", label="Speak your query")
705
- transcribe_button = gr.Button("Transcribe")
706
-
707
- with gr.Column(scale=2):
708
- chatbot = gr.Chatbot(
709
- show_copy_button=True,
710
- bubble=True,
711
- height=400,
712
- value=initial_conversation()
713
- )
714
- query_textbox = gr.Textbox(
715
- placeholder="Ask a question about the uploaded PDFs or any topic",
716
- container=False,
717
- scale=7
718
- )
719
- submit_button = gr.Button("Submit")
720
-
721
- with gr.Accordion("⚙️ Parameters", open=False):
722
- model = gr.Dropdown(choices=MODELS, label="Select Model", value=MODELS[3])
723
- temperature = gr.Slider(minimum=0.1, maximum=1.0, value=0.2, step=0.1, label="Temperature")
724
- num_calls = gr.Slider(minimum=1, maximum=5, value=1, step=1, label="Number of API Calls")
725
- use_web_search = gr.Checkbox(label="Use Web Search", value=True)
726
- document_selector = gr.CheckboxGroup(label="Select documents to query")
727
-
728
  gr.Markdown("## Upload and Manage PDF Documents")
729
  with gr.Row():
730
  file_input = gr.Files(label="Upload your PDF documents", file_types=[".pdf"])
@@ -735,36 +759,39 @@ with gr.Blocks() as demo:
735
  update_output = gr.Textbox(label="Update Status")
736
  delete_button = gr.Button("Delete Selected Documents")
737
 
738
- # Connect components
739
- transcribe_button.click(
740
- transcribe_with_timeout,
741
- inputs=[audio_input],
742
- outputs=[query_textbox]
743
- )
744
-
745
- submit_button.click(
746
- respond,
747
- inputs=[query_textbox, chatbot, model, temperature, num_calls, use_web_search, document_selector],
748
- outputs=[chatbot]
749
- )
750
-
751
  update_button.click(
752
  update_vectors,
753
  inputs=[file_input, parser_dropdown],
754
- outputs=[update_output, document_selector]
755
  )
756
 
 
757
  refresh_button.click(
758
  refresh_documents,
759
  inputs=[],
760
- outputs=[document_selector]
761
  )
762
 
 
763
  delete_button.click(
764
  delete_documents,
765
- inputs=[document_selector],
766
- outputs=[update_output, document_selector]
 
 
 
 
 
 
 
 
 
 
 
 
 
767
  )
768
 
769
  if __name__ == "__main__":
770
- demo.launch(debug=True, show_error=True)
 
17
  import inspect
18
  import logging
19
  import shutil
20
+ import numpy as np
21
+ import soundfile as sf
22
 
 
23
 
24
  # Set up basic configuration for logging
25
  logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
 
30
  ACCOUNT_ID = os.environ.get("CLOUDFARE_ACCOUNT_ID")
31
  API_TOKEN = os.environ.get("CLOUDFLARE_AUTH_TOKEN")
32
  API_BASE_URL = "https://api.cloudflare.com/client/v4/accounts/a17f03e0f049ccae0c15cdcf3b9737ce/ai/run/"
 
33
 
34
  print(f"ACCOUNT_ID: {ACCOUNT_ID}")
35
  print(f"CLOUDFLARE_AUTH_TOKEN: {API_TOKEN[:5]}..." if API_TOKEN else "Not set")
 
399
  return f"An error occurred during summarization: {str(e)}"
400
 
401
  # Modify the existing respond function to handle both PDF and web search
402
+ def respond(message, history, model, temperature, num_calls, use_web_search, selected_docs, audio_input):
403
+ if audio_input:
404
+ message = transcribe_audio(audio_input)
405
+ logging.info(f"Transcribed audio: {message}")
406
+
407
+ if not message.strip():
408
+ return "Please provide a text or audio query.", history
409
+
410
+ logging.info(f"User Query: {message}")
411
+ logging.info(f"Model Used: {model}")
412
+ logging.info(f"Selected Documents: {selected_docs}")
413
+ logging.info(f"Use Web Search: {use_web_search}")
414
+
415
+ if use_web_search:
416
+ original_query = message
417
+ rephrased_query = rephrase_query(message, conversation_manager)
418
+ logging.info(f"Original query: {original_query}")
419
+ logging.info(f"Rephrased query: {rephrased_query}")
420
+
421
+ final_summary = ""
422
+ for _ in range(num_calls):
423
+ search_results = get_web_search_results(rephrased_query)
424
+ if not search_results:
425
+ final_summary += f"No search results found for the query: {rephrased_query}\n\n"
426
+ elif "error" in search_results[0]:
427
+ final_summary += search_results[0]["error"] + "\n\n"
 
 
 
 
 
 
428
  else:
429
+ summary = summarize_web_results(rephrased_query, search_results, conversation_manager)
430
+ final_summary += summary + "\n\n"
431
 
432
+ if final_summary:
433
+ conversation_manager.add_interaction(original_query, final_summary)
434
+ yield final_summary
435
  else:
436
+ yield "Unable to generate a response. Please try a different query."
437
+ else:
438
+ # Existing PDF search logic
439
+ try:
440
  embed = get_embeddings()
441
  if os.path.exists("faiss_database"):
442
  database = FAISS.load_local("faiss_database", embed, allow_dangerous_deserialization=True)
443
  retriever = database.as_retriever(search_kwargs={"k": 20})
444
 
 
445
  all_relevant_docs = retriever.get_relevant_documents(message)
446
  relevant_docs = [doc for doc in all_relevant_docs if doc.metadata["source"] in selected_docs]
447
 
448
  if not relevant_docs:
449
+ yield "No relevant information found in the selected documents. Please try selecting different documents or rephrasing your query."
450
+ return
451
+
452
+ context_str = "\n".join([doc.page_content for doc in relevant_docs])
453
+ logging.info(f"Context length: {len(context_str)}")
 
 
 
 
 
 
 
 
 
 
 
 
 
454
  else:
455
+ context_str = "No documents available."
456
+ yield "No documents available. Please upload PDF documents to answer questions."
457
+ return
458
+
459
+ if model.startswith("duckduckgo/"):
460
+ # Use DuckDuckGo chat with context
461
+ for partial_response in get_response_from_duckduckgo(message, model, context_str, num_calls, temperature):
462
+ yield partial_response
463
+ elif model == "@cf/meta/llama-3.1-8b-instruct":
464
+ # Use Cloudflare API
465
+ for partial_response in get_response_from_cloudflare(prompt="", context=context_str, query=message, num_calls=num_calls, temperature=temperature, search_type="pdf"):
466
+ yield partial_response
467
+ else:
468
+ # Use Hugging Face API
469
+ for partial_response in get_response_from_pdf(message, model, selected_docs, num_calls=num_calls, temperature=temperature):
470
+ yield partial_response
471
+ except Exception as e:
472
+ logging.error(f"Error with {model}: {str(e)}")
473
+ if "microsoft/Phi-3-mini-4k-instruct" in model:
474
+ logging.info("Falling back to Mistral model due to Phi-3 error")
475
+ fallback_model = "mistralai/Mistral-7B-Instruct-v0.3"
476
+ yield from respond(message, history, fallback_model, temperature, num_calls, selected_docs)
477
+ else:
478
+ yield f"An error occurred with the {model} model: {str(e)}. Please try again or select a different model."
479
+
480
  logging.basicConfig(level=logging.DEBUG)
481
 
482
  def get_response_from_cloudflare(prompt, context, query, num_calls=3, temperature=0.2, search_type="pdf"):
 
615
 
616
  logging.info("Finished generating response")
617
 
618
+ def transcribe_audio(audio_file):
619
+ client = InferenceClient("openai/whisper-large-v3", token=huggingface_token)
 
 
 
620
 
621
+ # Load the audio file
622
+ audio, sample_rate = sf.read(audio_file)
623
+
624
+ # Ensure audio is mono
625
+ if len(audio.shape) > 1:
626
+ audio = audio.mean(axis=1)
627
+
628
+ # Normalize audio
629
+ audio = (audio / np.max(np.abs(audio))) * 32767
630
+ audio = audio.astype(np.int16)
631
+
632
+ # Transcribe
633
+ result = client.automatic_speech_recognition(audio, sampling_rate=sample_rate)
634
+ return result["text"]
 
 
 
 
 
 
 
635
 
636
  def vote(data: gr.LikeData):
637
  if data.liked:
 
682
 
683
  custom_placeholder = "Ask a question (Note: You can toggle between Web Search and PDF Chat in Additional Inputs below)"
684
 
685
+ # Update the demo interface
686
+ # Update the Gradio interface
687
+ demo = gr.Interface(
688
+ fn=respond,
689
+ inputs=[
690
+ gr.Textbox(placeholder=custom_placeholder, container=False, scale=7),
691
+ gr.State([]), # for history
692
+ gr.Dropdown(choices=MODELS, label="Select Model", value=MODELS[3]),
693
+ gr.Slider(minimum=0.1, maximum=1.0, value=0.2, step=0.1, label="Temperature"),
694
+ gr.Slider(minimum=1, maximum=5, value=1, step=1, label="Number of API Calls"),
695
+ gr.Checkbox(label="Use Web Search", value=True),
696
+ gr.CheckboxGroup(label="Select documents to query"),
697
+ gr.Audio(source="microphone", type="filepath")
698
+ ],
699
+ outputs=[gr.Chatbot()],
700
+ title="AI-powered PDF Chat and Web Search Assistant",
701
+ description="Chat with your PDFs or use web search to answer questions. You can type or speak your query.",
702
+ theme=gr.themes.Soft(
703
+ primary_hue="orange",
704
+ secondary_hue="amber",
705
+ neutral_hue="gray",
706
+ font=[gr.themes.GoogleFont("Exo"), "ui-sans-serif", "system-ui", "sans-serif"]
707
+ ).set(
708
+ body_background_fill_dark="#0c0505",
709
+ block_background_fill_dark="#0c0505",
710
+ block_border_width="1px",
711
+ block_title_background_fill_dark="#1b0f0f",
712
+ input_background_fill_dark="#140b0b",
713
+ button_secondary_background_fill_dark="#140b0b",
714
+ border_color_accent_dark="#1b0f0f",
715
+ border_color_primary_dark="#1b0f0f",
716
+ background_fill_secondary_dark="#0c0505",
717
+ color_accent_soft_dark="transparent",
718
+ code_background_fill_dark="#140b0b"
719
+ ),
720
+ css=css,
721
+ examples=[
722
+ ["Tell me about the contents of the uploaded PDFs."],
723
+ ["What are the main topics discussed in the documents?"],
724
+ ["Can you summarize the key points from the PDFs?"],
725
+ ["What's the latest news about artificial intelligence?"]
726
+ ],
727
+ cache_examples=False,
728
+ analytics_enabled=False,
729
+ )
730
 
731
+ # Add file upload functionality
732
+ # Add file upload functionality
733
+ with demo:
734
+ gr.Markdown("## Chat Interface")
735
  with gr.Row():
736
+ text_input = gr.Textbox(
737
+ placeholder=custom_placeholder,
738
+ container=False,
739
+ scale=7
740
+ )
741
+ audio_input = gr.Audio(source="microphone", type="filepath")
742
+ submit_button = gr.Button("Submit")
743
+
744
+ chat_output = gr.Chatbot(
745
+ show_copy_button=True,
746
+ likeable=True,
747
+ layout="bubble",
748
+ height=400,
749
+ value=initial_conversation()
750
+ )
751
+ with demo:
 
 
 
 
 
 
 
 
 
752
  gr.Markdown("## Upload and Manage PDF Documents")
753
  with gr.Row():
754
  file_input = gr.Files(label="Upload your PDF documents", file_types=[".pdf"])
 
759
  update_output = gr.Textbox(label="Update Status")
760
  delete_button = gr.Button("Delete Selected Documents")
761
 
762
+ # Update both the output text and the document selector
 
 
 
 
 
 
 
 
 
 
 
 
763
  update_button.click(
764
  update_vectors,
765
  inputs=[file_input, parser_dropdown],
766
+ outputs=[update_output, demo.additional_inputs[-1]] # Use the CheckboxGroup from additional_inputs
767
  )
768
 
769
+ # Add the refresh button functionality
770
  refresh_button.click(
771
  refresh_documents,
772
  inputs=[],
773
+ outputs=[demo.additional_inputs[-1]] # Use the CheckboxGroup from additional_inputs
774
  )
775
 
776
+ # Add the delete button functionality
777
  delete_button.click(
778
  delete_documents,
779
+ inputs=[demo.additional_inputs[-1]], # Use the CheckboxGroup from additional_inputs
780
+ outputs=[update_output, demo.additional_inputs[-1]]
781
+ )
782
+
783
+ gr.Markdown(
784
+ """
785
+ ## How to use
786
+ 1. Upload PDF documents using the file input at the top.
787
+ 2. Select the PDF parser (pypdf or llamaparse) and click "Upload Document" to update the vector store.
788
+ 3. Select the documents you want to query using the checkboxes.
789
+ 4. Ask questions in the chat interface.
790
+ 5. Toggle "Use Web Search" to switch between PDF chat and web search.
791
+ 6. Adjust Temperature and Number of API Calls to fine-tune the response generation.
792
+ 7. Use the provided examples or ask your own questions.
793
+ """
794
  )
795
 
796
  if __name__ == "__main__":
797
+ demo.launch(share=True)