Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
@@ -17,10 +17,9 @@ from huggingface_hub import InferenceClient
|
|
17 |
import inspect
|
18 |
import logging
|
19 |
import shutil
|
20 |
-
import
|
21 |
-
|
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 |
-
|
405 |
-
|
406 |
-
|
407 |
-
|
408 |
-
|
409 |
-
|
410 |
-
|
411 |
-
|
412 |
-
|
413 |
-
|
414 |
-
|
415 |
-
|
416 |
-
|
417 |
-
|
418 |
-
|
419 |
-
|
420 |
-
|
421 |
-
|
422 |
-
|
423 |
-
|
424 |
-
|
425 |
-
|
426 |
-
|
427 |
-
|
428 |
-
|
429 |
-
|
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 |
-
|
|
|
438 |
|
|
|
|
|
|
|
439 |
else:
|
440 |
-
|
441 |
-
|
|
|
|
|
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 |
-
|
453 |
-
|
454 |
-
|
455 |
-
|
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 |
-
|
472 |
-
|
473 |
-
|
474 |
-
|
475 |
-
|
476 |
-
|
477 |
-
|
478 |
-
|
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 |
-
|
619 |
-
|
620 |
-
if audio_file is None:
|
621 |
-
logger.warning("No audio file provided")
|
622 |
-
return "No audio file provided"
|
623 |
|
624 |
-
|
625 |
-
|
626 |
-
|
627 |
-
|
628 |
-
|
629 |
-
|
630 |
-
|
631 |
-
|
632 |
-
|
633 |
-
|
634 |
-
|
635 |
-
|
636 |
-
|
637 |
-
|
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 |
-
|
696 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
697 |
|
698 |
-
#
|
699 |
-
|
700 |
-
|
701 |
-
|
702 |
with gr.Row():
|
703 |
-
|
704 |
-
|
705 |
-
|
706 |
-
|
707 |
-
|
708 |
-
|
709 |
-
|
710 |
-
|
711 |
-
|
712 |
-
|
713 |
-
|
714 |
-
|
715 |
-
|
716 |
-
|
717 |
-
|
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 |
-
#
|
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,
|
755 |
)
|
756 |
|
|
|
757 |
refresh_button.click(
|
758 |
refresh_documents,
|
759 |
inputs=[],
|
760 |
-
outputs=[
|
761 |
)
|
762 |
|
|
|
763 |
delete_button.click(
|
764 |
delete_documents,
|
765 |
-
inputs=[
|
766 |
-
outputs=[update_output,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
767 |
)
|
768 |
|
769 |
if __name__ == "__main__":
|
770 |
-
demo.launch(
|
|
|
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)
|