Luong Huu Thanh commited on
Commit
501df39
ยท
1 Parent(s): d8c261b

some updates

Browse files
Files changed (3) hide show
  1. agent.py +3 -3
  2. qna_ui.py +364 -0
  3. requirements.txt +2 -1
agent.py CHANGED
@@ -64,10 +64,10 @@ def web_search(query: str) -> str:
64
 
65
  Args:
66
  query: The search query."""
67
- search_docs = TavilySearchResults(max_results=3).invoke(query=query)
68
  formatted_search_docs = "\n\n---\n\n".join(
69
  [
70
- f'<Document source="{doc.metadata["source"]}" page="{doc.metadata.get("page", "")}"/>\n{doc.page_content}\n</Document>'
71
  for doc in search_docs
72
  ]
73
  )
@@ -738,7 +738,7 @@ def build_graph(provider: str = "groq"):
738
  # Load environment variables from .env file
739
  if provider == "groq":
740
  # Groq https://console.groq.com/docs/models
741
- llm = ChatGroq(model="qwen-qwq-32b", temperature=0)
742
  elif provider == "huggingface":
743
  # TODO: Add huggingface endpoint
744
  llm = ChatHuggingFace(
 
64
 
65
  Args:
66
  query: The search query."""
67
+ search_docs = TavilySearchResults(max_results=3).invoke(query)
68
  formatted_search_docs = "\n\n---\n\n".join(
69
  [
70
+ f'<Document source="{doc.get("url", "")}" title="{doc.get("title", "")}"/>\n{doc.get("content", "")}\n</Document>'
71
  for doc in search_docs
72
  ]
73
  )
 
738
  # Load environment variables from .env file
739
  if provider == "groq":
740
  # Groq https://console.groq.com/docs/models
741
+ llm = ChatGroq(model="qwen/qwen3-32b", temperature=0)
742
  elif provider == "huggingface":
743
  # TODO: Add huggingface endpoint
744
  llm = ChatHuggingFace(
qna_ui.py ADDED
@@ -0,0 +1,364 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import time
3
+ import os
4
+ import base64
5
+ from typing import List, Tuple, Optional
6
+ from langchain_core.messages import HumanMessage
7
+ from agent import build_graph
8
+
9
+ class QnAChatbot:
10
+ """A Q&A chatbot interface for the agent."""
11
+
12
+ def __init__(self):
13
+ print("๐Ÿค– QnAChatbot initializing...")
14
+ print("๐Ÿ”ง Building agent graph...")
15
+ self.graph = build_graph()
16
+ self.conversation_history = []
17
+ print("โœ… QnAChatbot initialized successfully")
18
+
19
+ def process_question(self, question: str, history: List[Tuple[str, str]], uploaded_files: Optional[List] = None) -> Tuple[str, List[Tuple[str, str]]]:
20
+ """Process a question and return the response with updated history."""
21
+ if not question.strip() and not uploaded_files:
22
+ print("โš ๏ธ No question or files provided")
23
+ return "", history
24
+
25
+ try:
26
+ print(f"\n{'='*60}")
27
+ print(f"๐Ÿค– Processing new question...")
28
+ print(f"๐Ÿ“ Question: {question[:100]}{'...' if len(question) > 100 else ''}")
29
+ print(f"๐Ÿ“ Files uploaded: {len(uploaded_files) if uploaded_files else 0}")
30
+
31
+ # Handle uploaded files
32
+ file_context = ""
33
+ if uploaded_files:
34
+ print(f"๐Ÿ“‚ Processing {len(uploaded_files)} uploaded file(s)...")
35
+ file_context = self._process_uploaded_files(uploaded_files)
36
+ if file_context:
37
+ original_question = question
38
+ question = f"{question}\n\n{file_context}" if question.strip() else file_context
39
+ print(f"๐Ÿ“‹ File context added to question (length: {len(file_context)} chars)")
40
+
41
+ # Wrap the question in a HumanMessage
42
+ messages = [HumanMessage(content=question)]
43
+ print(f"๐Ÿ”„ Invoking agent graph...")
44
+
45
+ # Get response from the agent
46
+ result = self.graph.invoke({"messages": messages})
47
+ print(f"๐Ÿ“จ Received {len(result['messages'])} message(s) from agent")
48
+
49
+ # Print all messages for debugging
50
+ for i, msg in enumerate(result['messages']):
51
+ print(f"๐Ÿ“ง Message {i+1}: {type(msg).__name__}")
52
+ if hasattr(msg, 'content'):
53
+ content_preview = msg.content[:200] + "..." if len(msg.content) > 200 else msg.content
54
+ print(f" Content preview: {content_preview}")
55
+
56
+ answer = result['messages'][-1].content
57
+
58
+ # Clean up the answer if it starts with "Assistant: "
59
+ if answer.startswith("Assistant: "):
60
+ answer = answer[11:]
61
+ print("๐Ÿงน Cleaned 'Assistant: ' prefix from response")
62
+
63
+ # Update conversation history
64
+ history.append((question, answer))
65
+ print(f"โœ… Question processed successfully")
66
+ print(f"๐Ÿ“Š Response length: {len(answer)} characters")
67
+ print(f"๐Ÿ’ฌ Total conversation history: {len(history)} exchanges")
68
+ print(f"{'='*60}\n")
69
+
70
+ return "", history
71
+
72
+ except Exception as e:
73
+ error_msg = f"Error processing question: {str(e)}"
74
+ print(f"โŒ {error_msg}")
75
+ print(f"๐Ÿ” Exception details: {type(e).__name__}: {str(e)}")
76
+ import traceback
77
+ print(f"๐Ÿ“‹ Traceback:\n{traceback.format_exc()}")
78
+ history.append((question, error_msg))
79
+ print(f"{'='*60}\n")
80
+ return "", history
81
+
82
+ def _process_uploaded_files(self, uploaded_files: List) -> str:
83
+ """Process uploaded files and return context for the question."""
84
+ file_contexts = []
85
+
86
+ for file_path in uploaded_files:
87
+ if not file_path or not os.path.exists(file_path):
88
+ print(f"โš ๏ธ Skipping invalid file path: {file_path}")
89
+ continue
90
+
91
+ try:
92
+ file_name = os.path.basename(file_path)
93
+ file_ext = os.path.splitext(file_name)[1].lower()
94
+ file_size = os.path.getsize(file_path)
95
+
96
+ print(f"๐Ÿ“„ Processing file: {file_name} ({file_size} bytes, {file_ext})")
97
+
98
+ # Handle different file types
99
+ if file_ext in ['.jpg', '.jpeg', '.png', '.gif', '.bmp', '.webp']:
100
+ # Image file - convert to base64
101
+ with open(file_path, 'rb') as f:
102
+ image_data = base64.b64encode(f.read()).decode('utf-8')
103
+ file_contexts.append(f"[UPLOADED IMAGE: {file_name}] - Base64 data: {image_data}")
104
+ print(f"๐Ÿ–ผ๏ธ Image converted to base64 ({len(image_data)} chars)")
105
+
106
+ elif file_ext in ['.txt', '.md', '.py', '.js', '.html', '.css', '.json', '.xml']:
107
+ # Text file - read content
108
+ with open(file_path, 'r', encoding='utf-8') as f:
109
+ content = f.read()
110
+ file_contexts.append(f"[UPLOADED TEXT FILE: {file_name}]\nContent:\n{content}")
111
+ print(f"๐Ÿ“ Text file content read ({len(content)} chars)")
112
+
113
+ elif file_ext in ['.csv']:
114
+ # CSV file - provide file path for analysis
115
+ file_contexts.append(f"[UPLOADED CSV FILE: {file_name}] - File path: {file_path}")
116
+ print(f"๐Ÿ“Š CSV file prepared for analysis")
117
+
118
+ elif file_ext in ['.xlsx', '.xls']:
119
+ # Excel file - provide file path for analysis
120
+ file_contexts.append(f"[UPLOADED EXCEL FILE: {file_name}] - File path: {file_path}")
121
+ print(f"๐Ÿ“ˆ Excel file prepared for analysis")
122
+
123
+ elif file_ext in ['.pdf']:
124
+ # PDF file - mention it's available
125
+ file_contexts.append(f"[UPLOADED PDF FILE: {file_name}] - File path: {file_path}")
126
+ print(f"๐Ÿ“„ PDF file prepared for processing")
127
+
128
+ else:
129
+ # Other file types - just mention the file
130
+ file_contexts.append(f"[UPLOADED FILE: {file_name}] - File path: {file_path}")
131
+ print(f"๐Ÿ“ Generic file prepared for processing")
132
+
133
+ except Exception as e:
134
+ error_msg = f"Error processing file {file_path}: {e}"
135
+ print(f"โŒ {error_msg}")
136
+ print(f"๐Ÿ” File processing error details: {type(e).__name__}: {str(e)}")
137
+ file_contexts.append(f"[ERROR PROCESSING FILE: {os.path.basename(file_path)}] - {str(e)}")
138
+
139
+ total_context = "\n\n".join(file_contexts) if file_contexts else ""
140
+ if total_context:
141
+ print(f"๐Ÿ“‹ Total file context generated: {len(total_context)} characters")
142
+
143
+ return total_context
144
+
145
+ def clear_history(self):
146
+ """Clear the conversation history."""
147
+ print("๐Ÿงน Clearing conversation history...")
148
+ self.conversation_history = []
149
+ print("โœ… Conversation history cleared")
150
+ return []
151
+
152
+ def create_qna_interface():
153
+ """Create the Q&A chatbot interface."""
154
+
155
+ print("๐Ÿš€ Creating Q&A interface...")
156
+ # Initialize the chatbot
157
+ chatbot = QnAChatbot()
158
+ print("๐ŸŽจ Setting up UI components...")
159
+
160
+ # Custom CSS for better styling
161
+ custom_css = """
162
+ .gradio-container {
163
+ max-width: 1200px !important;
164
+ margin: auto !important;
165
+ }
166
+ .chat-message {
167
+ padding: 10px !important;
168
+ margin: 5px 0 !important;
169
+ border-radius: 10px !important;
170
+ }
171
+ .user-message {
172
+ background-color: #e3f2fd !important;
173
+ margin-left: 20% !important;
174
+ }
175
+ .bot-message {
176
+ background-color: #f5f5f5 !important;
177
+ margin-right: 20% !important;
178
+ }
179
+ """
180
+
181
+ with gr.Blocks(css=custom_css, title="GAIA Agent - Q&A Chatbot") as demo:
182
+ gr.Markdown(
183
+ """
184
+ # ๐Ÿค– GAIA Agent - Q&A Chatbot
185
+
186
+ 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.
187
+
188
+ **What I can do:**
189
+ - ๐Ÿ” Search the web, Wikipedia, and academic papers
190
+ - ๐Ÿงฎ Perform mathematical calculations
191
+ - ๐Ÿ’ป Execute code in multiple languages (Python, Bash, SQL, C, Java)
192
+ - ๐Ÿ“Š Analyze CSV and Excel files
193
+ - ๐Ÿ–ผ๏ธ Process and analyze images (JPG, PNG, GIF, etc.)
194
+ - ๐Ÿ“„ Extract text from images (OCR)
195
+ - ๐Ÿ“ Handle file uploads and processing (PDF, DOC, TXT, etc.)
196
+ - ๐Ÿ“ˆ Create visualizations and charts
197
+ - ๐Ÿ”ง Multi-file analysis and comparison
198
+ - And much more!
199
+
200
+ ---
201
+ """
202
+ )
203
+
204
+ # Chat interface
205
+ with gr.Row():
206
+ with gr.Column(scale=1):
207
+ chatbot_interface = gr.Chatbot(
208
+ label="Conversation",
209
+ height=500,
210
+ show_label=True,
211
+ container=True,
212
+ bubble_full_width=False
213
+ )
214
+
215
+ # File upload section
216
+ with gr.Row():
217
+ with gr.Column():
218
+ file_upload = gr.File(
219
+ label="๐Ÿ“ Upload Files (Images, Documents, CSV, Excel, etc.)",
220
+ file_count="multiple",
221
+ file_types=[
222
+ ".jpg", ".jpeg", ".png", ".gif", ".bmp", ".webp", # Images
223
+ ".txt", ".md", ".py", ".js", ".html", ".css", ".json", ".xml", # Text files
224
+ ".csv", ".xlsx", ".xls", # Data files
225
+ ".pdf", ".doc", ".docx" # Documents
226
+ ],
227
+ height=100
228
+ )
229
+
230
+ with gr.Row():
231
+ with gr.Column(scale=8):
232
+ question_input = gr.Textbox(
233
+ label="Ask a question",
234
+ placeholder="Type your question here or upload files above... (e.g., 'What is the capital of France?', 'Analyze this image', 'Summarize this document')",
235
+ lines=2,
236
+ max_lines=5
237
+ )
238
+ with gr.Column(scale=1, min_width=100):
239
+ submit_btn = gr.Button("Send", variant="primary", size="lg")
240
+
241
+ with gr.Row():
242
+ clear_btn = gr.Button("Clear History", variant="secondary")
243
+ clear_files_btn = gr.Button("Clear Files", variant="secondary")
244
+
245
+ # Example questions
246
+ with gr.Row():
247
+ gr.Markdown("### ๐Ÿ’ก Example Questions:")
248
+
249
+ with gr.Row():
250
+ with gr.Column():
251
+ gr.Examples(
252
+ examples=[
253
+ "What is the current population of Tokyo?",
254
+ "Calculate the square root of 144",
255
+ "Write a Python function to sort a list",
256
+ "What are the latest developments in AI?",
257
+ "Explain quantum computing in simple terms",
258
+ ],
259
+ inputs=question_input,
260
+ label="General Questions"
261
+ )
262
+ with gr.Column():
263
+ gr.Examples(
264
+ examples=[
265
+ "Search for recent papers on machine learning",
266
+ "What is the weather like today?",
267
+ "Create a simple bar chart using Python",
268
+ "Convert 100 USD to EUR",
269
+ "What are the benefits of renewable energy?",
270
+ ],
271
+ inputs=question_input,
272
+ label="Research & Analysis"
273
+ )
274
+ with gr.Column():
275
+ gr.Examples(
276
+ examples=[
277
+ "Analyze this image and describe what you see",
278
+ "Extract text from this image using OCR",
279
+ "Summarize the content of this document",
280
+ "Analyze the data in this CSV file",
281
+ "What insights can you find in this Excel file?",
282
+ ],
283
+ inputs=question_input,
284
+ label="File Analysis"
285
+ )
286
+
287
+ # Event handlers
288
+ def submit_question(question, history, files):
289
+ print(f"๐ŸŽฏ UI: Submit button clicked")
290
+ print(f"๐Ÿ“ UI: Question length: {len(question) if question else 0}")
291
+ print(f"๐Ÿ“ UI: Files count: {len(files) if files else 0}")
292
+ result_question, result_history = chatbot.process_question(question, history, files)
293
+ print(f"๐Ÿ”„ UI: Returning results and clearing files")
294
+ return result_question, result_history, None # Clear files after processing
295
+
296
+ def clear_conversation():
297
+ print("๐Ÿงน UI: Clear conversation button clicked")
298
+ return chatbot.clear_history()
299
+
300
+ def clear_files():
301
+ print("๐Ÿ—‘๏ธ UI: Clear files button clicked")
302
+ return None
303
+
304
+ # Connect the events
305
+ submit_btn.click(
306
+ fn=submit_question,
307
+ inputs=[question_input, chatbot_interface, file_upload],
308
+ outputs=[question_input, chatbot_interface, file_upload],
309
+ show_progress=True
310
+ )
311
+
312
+ question_input.submit(
313
+ fn=submit_question,
314
+ inputs=[question_input, chatbot_interface, file_upload],
315
+ outputs=[question_input, chatbot_interface, file_upload],
316
+ show_progress=True
317
+ )
318
+
319
+ clear_btn.click(
320
+ fn=clear_conversation,
321
+ outputs=[chatbot_interface],
322
+ show_progress=False
323
+ )
324
+
325
+ clear_files_btn.click(
326
+ fn=clear_files,
327
+ outputs=[file_upload],
328
+ show_progress=False
329
+ )
330
+
331
+ # Footer
332
+ gr.Markdown(
333
+ """
334
+ ---
335
+
336
+ **Note:** This agent uses various tools and APIs to provide comprehensive answers.
337
+ Processing complex questions and file analysis may take some time. Please be patient!
338
+
339
+ **Supported file types:**
340
+ - **Images:** JPG, PNG, GIF, BMP, WebP
341
+ - **Documents:** PDF, DOC, DOCX, TXT, MD
342
+ - **Data files:** CSV, Excel (XLS, XLSX)
343
+ - **Code files:** Python, JavaScript, HTML, CSS, JSON, XML
344
+
345
+ **Powered by:** LangGraph, Groq, and various specialized tools
346
+ """
347
+ )
348
+
349
+ return demo
350
+
351
+ if __name__ == "__main__":
352
+ print("\n" + "-"*50)
353
+ print("๐Ÿš€ Starting GAIA Agent Q&A Chatbot...")
354
+ print("-"*50 + "\n")
355
+
356
+ # Create and launch the interface
357
+ demo = create_qna_interface()
358
+ demo.launch(
359
+ debug=True,
360
+ share=False,
361
+ server_name="0.0.0.0",
362
+ server_port=7860,
363
+ show_error=True
364
+ )
requirements.txt CHANGED
@@ -17,4 +17,5 @@ wikipedia
17
  pgvector
18
  python-dotenv
19
  pytesseract
20
- matplotlib
 
 
17
  pgvector
18
  python-dotenv
19
  pytesseract
20
+ matplotlib
21
+ sentence_transformers