import gradio as gr import time import os import base64 from typing import List, Tuple, Optional from langchain_core.messages import HumanMessage from agent import build_graph class QnAChatbot: """A Q&A chatbot interface for the agent.""" def __init__(self): print("๐Ÿค– QnAChatbot initializing...") print("๐Ÿ”ง Building agent graph...") self.graph = build_graph() self.conversation_history = [] print("โœ… QnAChatbot initialized successfully") def process_question(self, question: str, history: List[Tuple[str, str]], uploaded_files: Optional[List] = None) -> Tuple[str, List[Tuple[str, str]]]: """Process a question and return the response with updated history.""" if not question.strip() and not uploaded_files: print("โš ๏ธ No question or files provided") return "", history try: print(f"\n{'='*60}") print(f"๐Ÿค– Processing new question...") print(f"๐Ÿ“ Question: {question[:100]}{'...' if len(question) > 100 else ''}") print(f"๐Ÿ“ Files uploaded: {len(uploaded_files) if uploaded_files else 0}") # Handle uploaded files file_context = "" if uploaded_files: print(f"๐Ÿ“‚ Processing {len(uploaded_files)} uploaded file(s)...") file_context = self._process_uploaded_files(uploaded_files) if file_context: original_question = question question = f"{question}\n\n{file_context}" if question.strip() else file_context print(f"๐Ÿ“‹ File context added to question (length: {len(file_context)} chars)") # Wrap the question in a HumanMessage messages = [HumanMessage(content=question)] print(f"๐Ÿ”„ Invoking agent graph...") # Get response from the agent result = self.graph.invoke({"messages": messages}) print(f"๐Ÿ“จ Received {len(result['messages'])} message(s) from agent") # Print all messages for debugging for i, msg in enumerate(result['messages']): print(f"๐Ÿ“ง Message {i+1}: {type(msg).__name__}") if hasattr(msg, 'content'): content_preview = msg.content[:200] + "..." if len(msg.content) > 200 else msg.content print(f" Content preview: {content_preview}") answer = result['messages'][-1].content # Clean up the answer if it starts with "Assistant: " if answer.startswith("Assistant: "): answer = answer[11:] print("๐Ÿงน Cleaned 'Assistant: ' prefix from response") # Update conversation history history.append((question, answer)) print(f"โœ… Question processed successfully") print(f"๐Ÿ“Š Response length: {len(answer)} characters") print(f"๐Ÿ’ฌ Total conversation history: {len(history)} exchanges") print(f"{'='*60}\n") return "", history except Exception as e: error_msg = f"Error processing question: {str(e)}" print(f"โŒ {error_msg}") print(f"๐Ÿ” Exception details: {type(e).__name__}: {str(e)}") import traceback print(f"๐Ÿ“‹ Traceback:\n{traceback.format_exc()}") history.append((question, error_msg)) print(f"{'='*60}\n") return "", history def _process_uploaded_files(self, uploaded_files: List) -> str: """Process uploaded files and return context for the question.""" file_contexts = [] for file_path in uploaded_files: if not file_path or not os.path.exists(file_path): print(f"โš ๏ธ Skipping invalid file path: {file_path}") continue try: file_name = os.path.basename(file_path) file_ext = os.path.splitext(file_name)[1].lower() file_size = os.path.getsize(file_path) print(f"๐Ÿ“„ Processing file: {file_name} ({file_size} bytes, {file_ext})") # Handle different file types if file_ext in ['.jpg', '.jpeg', '.png', '.gif', '.bmp', '.webp']: # Image file - convert to base64 with open(file_path, 'rb') as f: image_data = base64.b64encode(f.read()).decode('utf-8') file_contexts.append(f"[UPLOADED IMAGE: {file_name}] - Base64 data: {image_data}") print(f"๐Ÿ–ผ๏ธ Image converted to base64 ({len(image_data)} chars)") elif file_ext in ['.txt', '.md', '.py', '.js', '.html', '.css', '.json', '.xml']: # Text file - read content with open(file_path, 'r', encoding='utf-8') as f: content = f.read() file_contexts.append(f"[UPLOADED TEXT FILE: {file_name}]\nContent:\n{content}") print(f"๐Ÿ“ Text file content read ({len(content)} chars)") elif file_ext in ['.csv']: # CSV file - provide file path for analysis file_contexts.append(f"[UPLOADED CSV FILE: {file_name}] - File path: {file_path}") print(f"๐Ÿ“Š CSV file prepared for analysis") elif file_ext in ['.xlsx', '.xls']: # Excel file - provide file path for analysis file_contexts.append(f"[UPLOADED EXCEL FILE: {file_name}] - File path: {file_path}") print(f"๐Ÿ“ˆ Excel file prepared for analysis") elif file_ext in ['.pdf']: # PDF file - mention it's available file_contexts.append(f"[UPLOADED PDF FILE: {file_name}] - File path: {file_path}") print(f"๐Ÿ“„ PDF file prepared for processing") else: # Other file types - just mention the file file_contexts.append(f"[UPLOADED FILE: {file_name}] - File path: {file_path}") print(f"๐Ÿ“ Generic file prepared for processing") except Exception as e: error_msg = f"Error processing file {file_path}: {e}" print(f"โŒ {error_msg}") print(f"๐Ÿ” File processing error details: {type(e).__name__}: {str(e)}") file_contexts.append(f"[ERROR PROCESSING FILE: {os.path.basename(file_path)}] - {str(e)}") total_context = "\n\n".join(file_contexts) if file_contexts else "" if total_context: print(f"๐Ÿ“‹ Total file context generated: {len(total_context)} characters") return total_context def clear_history(self): """Clear the conversation history.""" print("๐Ÿงน Clearing conversation history...") self.conversation_history = [] print("โœ… Conversation history cleared") return [] def create_qna_interface(): """Create the Q&A chatbot interface.""" print("๐Ÿš€ Creating Q&A interface...") # Initialize the chatbot chatbot = QnAChatbot() print("๐ŸŽจ Setting up UI components...") # Custom CSS for better styling custom_css = """ .gradio-container { max-width: 1200px !important; margin: auto !important; } .chat-message { padding: 10px !important; margin: 5px 0 !important; border-radius: 10px !important; } .user-message { background-color: #e3f2fd !important; margin-left: 20% !important; } .bot-message { background-color: #f5f5f5 !important; margin-right: 20% !important; } """ with gr.Blocks(css=custom_css, title="GAIA Agent - Q&A Chatbot") as demo: gr.Markdown( """ # ๐Ÿค– GAIA Agent - Q&A Chatbot Welcome to the GAIA Agent Q&A interface! Ask me anything and I'll help you find the answer using my various tools and capabilities. **What I can do:** - ๐Ÿ” Search the web, Wikipedia, and academic papers - ๐Ÿงฎ Perform mathematical calculations - ๐Ÿ’ป Execute code in multiple languages (Python, Bash, SQL, C, Java) - ๐Ÿ“Š Analyze CSV and Excel files - ๐Ÿ–ผ๏ธ Process and analyze images (JPG, PNG, GIF, etc.) - ๐Ÿ“„ Extract text from images (OCR) - ๐Ÿ“ Handle file uploads and processing (PDF, DOC, TXT, etc.) - ๐Ÿ“ˆ Create visualizations and charts - ๐Ÿ”ง Multi-file analysis and comparison - And much more! --- """ ) # Chat interface with gr.Row(): with gr.Column(scale=1): chatbot_interface = gr.Chatbot( label="Conversation", height=500, show_label=True, container=True, bubble_full_width=False ) # File upload section with gr.Row(): with gr.Column(): file_upload = gr.File( label="๐Ÿ“ Upload Files (Images, Documents, CSV, Excel, etc.)", file_count="multiple", file_types=[ ".jpg", ".jpeg", ".png", ".gif", ".bmp", ".webp", # Images ".txt", ".md", ".py", ".js", ".html", ".css", ".json", ".xml", # Text files ".csv", ".xlsx", ".xls", # Data files ".pdf", ".doc", ".docx" # Documents ], height=100 ) with gr.Row(): with gr.Column(scale=8): question_input = gr.Textbox( label="Ask a question", placeholder="Type your question here or upload files above... (e.g., 'What is the capital of France?', 'Analyze this image', 'Summarize this document')", lines=2, max_lines=5 ) with gr.Column(scale=1, min_width=100): submit_btn = gr.Button("Send", variant="primary", size="lg") with gr.Row(): clear_btn = gr.Button("Clear History", variant="secondary") clear_files_btn = gr.Button("Clear Files", variant="secondary") # Example questions with gr.Row(): gr.Markdown("### ๐Ÿ’ก Example Questions:") with gr.Row(): with gr.Column(): gr.Examples( examples=[ "What is the current population of Tokyo?", "Calculate the square root of 144", "Write a Python function to sort a list", "What are the latest developments in AI?", "Explain quantum computing in simple terms", ], inputs=question_input, label="General Questions" ) with gr.Column(): gr.Examples( examples=[ "Search for recent papers on machine learning", "What is the weather like today?", "Create a simple bar chart using Python", "Convert 100 USD to EUR", "What are the benefits of renewable energy?", ], inputs=question_input, label="Research & Analysis" ) with gr.Column(): gr.Examples( examples=[ "Analyze this image and describe what you see", "Extract text from this image using OCR", "Summarize the content of this document", "Analyze the data in this CSV file", "What insights can you find in this Excel file?", ], inputs=question_input, label="File Analysis" ) # Event handlers def submit_question(question, history, files): print(f"๐ŸŽฏ UI: Submit button clicked") print(f"๐Ÿ“ UI: Question length: {len(question) if question else 0}") print(f"๐Ÿ“ UI: Files count: {len(files) if files else 0}") result_question, result_history = chatbot.process_question(question, history, files) print(f"๐Ÿ”„ UI: Returning results and clearing files") return result_question, result_history, None # Clear files after processing def clear_conversation(): print("๐Ÿงน UI: Clear conversation button clicked") return chatbot.clear_history() def clear_files(): print("๐Ÿ—‘๏ธ UI: Clear files button clicked") return None # Connect the events submit_btn.click( fn=submit_question, inputs=[question_input, chatbot_interface, file_upload], outputs=[question_input, chatbot_interface, file_upload], show_progress=True ) question_input.submit( fn=submit_question, inputs=[question_input, chatbot_interface, file_upload], outputs=[question_input, chatbot_interface, file_upload], show_progress=True ) clear_btn.click( fn=clear_conversation, outputs=[chatbot_interface], show_progress=False ) clear_files_btn.click( fn=clear_files, outputs=[file_upload], show_progress=False ) # Footer gr.Markdown( """ --- **Note:** This agent uses various tools and APIs to provide comprehensive answers. Processing complex questions and file analysis may take some time. Please be patient! **Supported file types:** - **Images:** JPG, PNG, GIF, BMP, WebP - **Documents:** PDF, DOC, DOCX, TXT, MD - **Data files:** CSV, Excel (XLS, XLSX) - **Code files:** Python, JavaScript, HTML, CSS, JSON, XML **Powered by:** LangGraph, Groq, and various specialized tools """ ) return demo if __name__ == "__main__": print("\n" + "-"*50) print("๐Ÿš€ Starting GAIA Agent Q&A Chatbot...") print("-"*50 + "\n") # Create and launch the interface demo = create_qna_interface() demo.launch( debug=True, share=False, server_name="0.0.0.0", server_port=7860, show_error=True )