Spaces:
Running
Running
import logging | |
import gradio as gr | |
from utils.document_utils import initialize_logging | |
from globals import app_config | |
# Configure logging | |
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') | |
initialize_logging() | |
def load_sample_question(question): | |
return question | |
def clear_selection(): | |
return gr.update(value=[]), "", "", gr.update(value=[]) # Reset doc_selector to empty list | |
def process_uploaded_file(file, current_selection): | |
"""Process uploaded file using DocumentManager and update UI.""" | |
try: | |
if file is None: | |
# When file input is cleared, preserve current selection and choices | |
uploaded_docs = app_config.doc_manager.get_uploaded_documents() | |
return ( | |
"", | |
gr.update(choices=uploaded_docs, value=current_selection or []), | |
False, | |
"" | |
) | |
status, filename, doc_id = app_config.doc_manager.process_document(file.name if file else None) | |
updated_selection = current_selection if current_selection else [] | |
if filename and filename not in updated_selection: | |
updated_selection.append(filename) | |
trigger_summary = bool(filename) | |
logging.info(f"Processed file: {filename}, Trigger summary: {trigger_summary}") | |
return ( | |
status, | |
gr.update(choices=app_config.doc_manager.get_uploaded_documents(), value=updated_selection), | |
trigger_summary, | |
filename | |
) | |
except Exception as e: | |
logging.error(f"Error in process_uploaded_file: {e}") | |
return "Error processing file", gr.update(choices=[]), False, '' | |
def update_doc_selector(selected_docs): | |
"""Keep selected documents in sync.""" | |
return selected_docs | |
# UI Configuration | |
models = [ "gemma2-9b-it", "llama3-70b-8192"] | |
example_questions = [ | |
"What is the architecture of the Communication Server?", | |
"Show me an example of a configuration file.", | |
"How to create Protected File Directories ?", | |
"What functionalities are available in the Communication Server setups?", | |
"What is Mediator help?", | |
"Why AzureBlobStorage port is used?" | |
] | |
with gr.Blocks(css=""" | |
.chatbot .user { | |
position: relative; | |
background-color: #cfdcfd; | |
padding: 12px 16px; | |
border-radius: 20px; | |
border-bottom-right-radius: 6px; | |
display: inline-block; | |
max-width: 80%; | |
margin: 8px 0; | |
} | |
/* Tail effect */ | |
.chatbot .user::after { | |
content: ""; | |
position: absolute; | |
right: -10px; | |
bottom: 10px; | |
width: 0; | |
height: 0; | |
border: 10px solid transparent; | |
border-left-color: #cfdcfd; | |
border-right: 0; | |
border-top: 0; | |
margin-top: -5px; | |
} | |
.chatbot .bot { background-color: #f1f8e9; padding: 8px; border-radius: 10px; } /* Light green for bot responses */ | |
""") as interface: | |
interface.title = "π€ IntelliDoc: AI Document Explorer" | |
gr.Markdown(""" | |
# π€ IntelliDoc: AI Document Explorer | |
**AI Document Explorer** allows you to upload PDF documents and interact with them using AI-powered analysis and summarization. Ask questions, extract key insights, and gain a deeper understanding of your documents effortlessly. | |
""") | |
summary_query_state = gr.State() # State to hold the summary query | |
trigger_summary_state = gr.State() # State to hold trigger flag | |
filename_state = gr.State() # State to hold file name | |
chunks_state = gr.State() | |
summary_text_state = gr.State() | |
sample_questions_state = gr.State() | |
with gr.Row(): | |
# Left Sidebar | |
with gr.Column(scale=2): | |
gr.Markdown("## Upload and Select Document") | |
upload_btn = gr.File(label="Upload PDF Document", file_types=[".pdf"]) | |
doc_selector = gr.Dropdown( | |
choices=app_config.doc_manager.get_uploaded_documents(), | |
label="Documents", | |
multiselect=True, | |
value=[] # Initial value as empty list | |
) | |
model_selector = gr.Dropdown(choices=models, label="Models", interactive=True) | |
clear_btn = gr.Button("Clear Selection") | |
upload_status = gr.Textbox(label="Upload Status", interactive=False) | |
# Process uploaded file and update UI | |
upload_event = upload_btn.change( | |
process_uploaded_file, | |
inputs=[upload_btn, doc_selector], | |
outputs=[ | |
upload_status, | |
doc_selector, | |
trigger_summary_state, # Store trigger_summary | |
filename_state | |
] | |
) | |
# Middle Section (Chat & LLM Response) | |
with gr.Column(scale=6): | |
gr.Markdown("## Chat with document(s)") | |
chat_history = gr.Chatbot(label="Chat History", height= 650, bubble_full_width= False, type="messages") | |
with gr.Row(): | |
chat_input = gr.Textbox(label="Ask additional questions about the document...", show_label=False, placeholder="Ask additional questions about the document...", elem_id="chat-input", lines=3) | |
chat_btn = gr.Button("π Send", variant="primary", elem_id="send-button", scale=0) | |
chat_btn.click(app_config.chat_manager.generate_chat_response, inputs=[chat_input, doc_selector, chat_history], outputs=chat_history).then( | |
lambda: "", # Return an empty string to clear the chat_input | |
outputs=chat_input | |
) | |
# Right Sidebar (Sample Questions & History) | |
with gr.Column(scale=2): | |
gr.Markdown("## Sample questions for this document:") | |
with gr.Column(): | |
sample_questions = gr.Dropdown( | |
label="Select a sample question", | |
choices=[], | |
interactive=True, | |
allow_custom_value=True # Allows users to type custom questions if needed | |
) | |
clear_btn.click( | |
clear_selection, | |
outputs=[doc_selector, upload_status, filename_state, sample_questions] | |
) | |
# Reinitialize LLM when the model changes | |
model_selector.change( | |
app_config.gen_llm.reinitialize_llm, | |
inputs=[model_selector], | |
outputs=[upload_status] | |
) | |
# After upload, generate "Auto Summary" message only if trigger_summary is True | |
upload_event.then( | |
fn=lambda trigger, filename: "Can you provide summary of the document" if trigger and filename else None, | |
inputs=[trigger_summary_state, filename_state], | |
outputs=[summary_query_state] | |
).then( | |
fn=lambda query, history: history + [{"role": "user", "content": ""}, {"role": "assistant", "content": "Generating summary of the document, please wait..."}] if query else history, | |
inputs=[summary_query_state, chat_history], | |
outputs=[chat_history] | |
).then( | |
fn=lambda trigger, filename: app_config.doc_manager.get_chunks(filename) if trigger and filename else None, | |
inputs=[trigger_summary_state, filename_state], | |
outputs=[chunks_state] | |
).then( | |
fn=lambda chunks: app_config.chat_manager.generate_summary(chunks) if chunks else None, | |
inputs=[chunks_state], | |
outputs=[summary_text_state] | |
).then( | |
fn=lambda summary, history: history + [{"role": "assistant", "content": summary}] if summary else history, | |
inputs=[summary_text_state, chat_history], | |
outputs=[chat_history] | |
).then( | |
fn=lambda chunks: app_config.chat_manager.generate_sample_questions(chunks) if chunks else [], | |
inputs=[chunks_state], | |
outputs=[sample_questions_state] | |
).then( | |
fn=lambda questions: gr.update( | |
choices=questions if questions else ["No questions available"], | |
value=questions[0] if questions else None # Set the first question as default | |
), | |
inputs=[sample_questions_state], | |
outputs=[sample_questions] | |
) | |
# Populate chat_input when a question is selected | |
sample_questions.change( | |
fn=lambda question: question, | |
inputs=[sample_questions], | |
outputs=[chat_input] | |
) | |
#gr.Markdown("## Logs") | |
#history = gr.Textbox(label="Previous Queries", interactive=False) | |
if __name__ == "__main__": | |
interface.launch() |