Murali-rade commited on
Commit
bcdf7ac
Β·
verified Β·
1 Parent(s): b63263b

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +130 -938
app.py CHANGED
@@ -1,945 +1,137 @@
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
- # Enhanced Custom CSS for modern, professional styling
161
- custom_css = """
162
- /* Import Google Fonts */
163
- @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&family=JetBrains+Mono:wght@400;500&display=swap');
164
-
165
- /* CSS Variables for Theme Support */
166
- :root {
167
- --primary-gradient: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
168
- --secondary-gradient: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
169
- --success-gradient: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
170
- --warning-gradient: linear-gradient(135deg, #43e97b 0%, #38f9d7 100%);
171
- --glass-bg: rgba(255, 255, 255, 0.95);
172
- --glass-border: rgba(255, 255, 255, 0.2);
173
- --text-primary: #2d3748;
174
- --text-secondary: #4a5568;
175
- --text-light: #718096;
176
- --bg-light: #f7fafc;
177
- --bg-card: #ffffff;
178
- --shadow-sm: 0 2px 10px rgba(0, 0, 0, 0.05);
179
- --shadow-md: 0 10px 30px rgba(0, 0, 0, 0.1);
180
- --shadow-lg: 0 20px 40px rgba(0, 0, 0, 0.15);
181
- --border-radius: 12px;
182
- --border-radius-lg: 20px;
183
- --transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
184
- }
185
-
186
- /* Global Styles */
187
- * {
188
- font-family: 'Inter', sans-serif !important;
189
- box-sizing: border-box !important;
190
- }
191
-
192
- /* Main Container with Enhanced Background */
193
- .gradio-container {
194
- max-width: 1400px !important;
195
- margin: 0 auto !important;
196
- background:
197
- radial-gradient(circle at 20% 50%, rgba(120, 119, 198, 0.3), transparent 50%),
198
- radial-gradient(circle at 80% 20%, rgba(255, 119, 198, 0.3), transparent 50%),
199
- radial-gradient(circle at 40% 80%, rgba(120, 219, 255, 0.3), transparent 50%),
200
- var(--primary-gradient) !important;
201
- min-height: 100vh !important;
202
- padding: 20px !important;
203
- position: relative !important;
204
- overflow-x: hidden !important;
205
- }
206
-
207
- /* Animated Background Particles */
208
- .gradio-container::before {
209
- content: '' !important;
210
- position: fixed !important;
211
- top: 0 !important;
212
- left: 0 !important;
213
- width: 100% !important;
214
- height: 100% !important;
215
- background: url("data:image/svg+xml,%3Csvg width='60' height='60' viewBox='0 0 60 60' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='none' fill-rule='evenodd'%3E%3Cg fill='%23ffffff' fill-opacity='0.05'%3E%3Ccircle cx='7' cy='7' r='1'/%3E%3Ccircle cx='53' cy='7' r='1'/%3E%3Ccircle cx='7' cy='53' r='1'/%3E%3Ccircle cx='53' cy='53' r='1'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E") !important;
216
- animation: float 20s ease-in-out infinite !important;
217
- pointer-events: none !important;
218
- z-index: 0 !important;
219
- }
220
-
221
- /* Main Content Area with Glass Effect */
222
- .main-content {
223
- background: var(--glass-bg) !important;
224
- backdrop-filter: blur(20px) !important;
225
- -webkit-backdrop-filter: blur(20px) !important;
226
- border-radius: var(--border-radius-lg) !important;
227
- box-shadow:
228
- var(--shadow-lg),
229
- inset 0 1px 0 var(--glass-border) !important;
230
- padding: 40px !important;
231
- margin: 20px 0 !important;
232
- position: relative !important;
233
- z-index: 1 !important;
234
- border: 1px solid var(--glass-border) !important;
235
- transition: var(--transition) !important;
236
- }
237
-
238
- .main-content:hover {
239
- transform: translateY(-2px) !important;
240
- box-shadow:
241
- 0 25px 50px rgba(0, 0, 0, 0.15),
242
- inset 0 1px 0 var(--glass-border) !important;
243
- }
244
-
245
- /* Enhanced Header with Animations */
246
- .markdown h1 {
247
- background: var(--primary-gradient) !important;
248
- -webkit-background-clip: text !important;
249
- -webkit-text-fill-color: transparent !important;
250
- background-clip: text !important;
251
- font-size: 3rem !important;
252
- font-weight: 800 !important;
253
- text-align: center !important;
254
- margin-bottom: 1.5rem !important;
255
- position: relative !important;
256
- animation: titleGlow 3s ease-in-out infinite alternate !important;
257
- }
258
-
259
- .markdown h1::after {
260
- content: '' !important;
261
- position: absolute !important;
262
- bottom: -10px !important;
263
- left: 50% !important;
264
- transform: translateX(-50%) !important;
265
- width: 100px !important;
266
- height: 4px !important;
267
- background: var(--primary-gradient) !important;
268
- border-radius: 2px !important;
269
- animation: pulse 2s ease-in-out infinite !important;
270
- }
271
-
272
- /* Enhanced Chat Interface */
273
- .chatbot {
274
- border: none !important;
275
- border-radius: var(--border-radius) !important;
276
- box-shadow: var(--shadow-md) !important;
277
- background: var(--bg-card) !important;
278
- overflow: hidden !important;
279
- position: relative !important;
280
- }
281
-
282
- /* Chat Messages with Better Styling */
283
- .chatbot .message-wrap {
284
- padding: 20px !important;
285
- margin: 15px !important;
286
- border-radius: 18px !important;
287
- max-width: 85% !important;
288
- animation: messageSlideIn 0.5s cubic-bezier(0.4, 0, 0.2, 1) !important;
289
- position: relative !important;
290
- word-wrap: break-word !important;
291
- }
292
-
293
- .chatbot .message.user {
294
- background: var(--primary-gradient) !important;
295
- color: white !important;
296
- margin-left: auto !important;
297
- margin-right: 15px !important;
298
- box-shadow: 0 8px 25px rgba(102, 126, 234, 0.4) !important;
299
- border-bottom-right-radius: 5px !important;
300
- }
301
-
302
- .chatbot .message.user::before {
303
- content: 'πŸ§‘β€πŸ’»' !important;
304
- position: absolute !important;
305
- top: -25px !important;
306
- right: 10px !important;
307
- font-size: 16px !important;
308
- background: var(--bg-card) !important;
309
- padding: 5px 8px !important;
310
- border-radius: 20px !important;
311
- box-shadow: var(--shadow-sm) !important;
312
- }
313
-
314
- .chatbot .message.bot {
315
- background: linear-gradient(135deg, #f8f9ff 0%, #e8eeff 100%) !important;
316
- color: var(--text-primary) !important;
317
- margin-right: auto !important;
318
- margin-left: 15px !important;
319
- border: 1px solid #e2e8f0 !important;
320
- box-shadow: var(--shadow-sm) !important;
321
- border-bottom-left-radius: 5px !important;
322
- }
323
-
324
- .chatbot .message.bot::before {
325
- content: 'πŸ€–' !important;
326
- position: absolute !important;
327
- top: -25px !important;
328
- left: 10px !important;
329
- font-size: 16px !important;
330
- background: var(--bg-card) !important;
331
- padding: 5px 8px !important;
332
- border-radius: 20px !important;
333
- box-shadow: var(--shadow-sm) !important;
334
- }
335
-
336
- /* Typing Indicator */
337
- .typing-indicator {
338
- display: flex !important;
339
- align-items: center !important;
340
- padding: 15px 20px !important;
341
- margin: 15px !important;
342
- background: linear-gradient(135deg, #f8f9ff 0%, #e8eeff 100%) !important;
343
- border-radius: 18px !important;
344
- max-width: 85% !important;
345
- margin-right: auto !important;
346
- margin-left: 15px !important;
347
- border: 1px solid #e2e8f0 !important;
348
- animation: messageSlideIn 0.5s cubic-bezier(0.4, 0, 0.2, 1) !important;
349
- }
350
-
351
- .typing-dots {
352
- display: flex !important;
353
- align-items: center !important;
354
- gap: 4px !important;
355
- }
356
-
357
- .typing-dots span {
358
- width: 8px !important;
359
- height: 8px !important;
360
- border-radius: 50% !important;
361
- background: var(--text-light) !important;
362
- animation: typingDots 1.4s ease-in-out infinite both !important;
363
- }
364
-
365
- .typing-dots span:nth-child(1) { animation-delay: -0.32s !important; }
366
- .typing-dots span:nth-child(2) { animation-delay: -0.16s !important; }
367
- .typing-dots span:nth-child(3) { animation-delay: 0s !important; }
368
-
369
- /* Enhanced Input Areas */
370
- .textbox input, .textbox textarea {
371
- border: 2px solid #e2e8f0 !important;
372
- border-radius: var(--border-radius) !important;
373
- padding: 18px 24px !important;
374
- font-size: 16px !important;
375
- line-height: 1.5 !important;
376
- transition: var(--transition) !important;
377
- background: var(--bg-card) !important;
378
- box-shadow: var(--shadow-sm) !important;
379
- font-family: 'Inter', sans-serif !important;
380
- }
381
-
382
- .textbox input:focus, .textbox textarea:focus {
383
- border-color: #667eea !important;
384
- box-shadow:
385
- 0 0 0 4px rgba(102, 126, 234, 0.1),
386
- var(--shadow-md) !important;
387
- outline: none !important;
388
- transform: translateY(-1px) !important;
389
- background: #ffffff !important;
390
- }
391
-
392
- /* Enhanced Buttons with Micro-interactions */
393
- .btn {
394
- border-radius: var(--border-radius) !important;
395
- font-weight: 600 !important;
396
- text-transform: none !important;
397
- letter-spacing: 0.3px !important;
398
- transition: var(--transition) !important;
399
- border: none !important;
400
- box-shadow: var(--shadow-sm) !important;
401
- padding: 14px 28px !important;
402
- font-size: 16px !important;
403
- position: relative !important;
404
- overflow: hidden !important;
405
- cursor: pointer !important;
406
- }
407
-
408
- .btn::before {
409
- content: '' !important;
410
- position: absolute !important;
411
- top: 0 !important;
412
- left: -100% !important;
413
- width: 100% !important;
414
- height: 100% !important;
415
- background: linear-gradient(90deg, transparent, rgba(255,255,255,0.3), transparent) !important;
416
- transition: left 0.5s !important;
417
- }
418
-
419
- .btn:hover::before {
420
- left: 100% !important;
421
- }
422
-
423
- .btn-primary {
424
- background: var(--primary-gradient) !important;
425
- color: white !important;
426
- box-shadow: 0 8px 25px rgba(102, 126, 234, 0.3) !important;
427
- }
428
-
429
- .btn-primary:hover {
430
- transform: translateY(-3px) scale(1.02) !important;
431
- box-shadow: 0 12px 35px rgba(102, 126, 234, 0.4) !important;
432
- }
433
-
434
- .btn-primary:active {
435
- transform: translateY(-1px) scale(0.98) !important;
436
- }
437
-
438
- .btn-secondary {
439
- background: linear-gradient(135deg, #f7fafc 0%, #edf2f7 100%) !important;
440
- color: var(--text-secondary) !important;
441
- border: 1px solid #e2e8f0 !important;
442
- }
443
-
444
- .btn-secondary:hover {
445
- transform: translateY(-2px) !important;
446
- background: linear-gradient(135deg, #edf2f7 0%, #e2e8f0 100%) !important;
447
- box-shadow: var(--shadow-md) !important;
448
- }
449
-
450
- /* Enhanced File Upload with Drag & Drop Animation */
451
- .file-upload {
452
- border: 3px dashed #cbd5e0 !important;
453
- border-radius: var(--border-radius) !important;
454
- background: linear-gradient(135deg, #f7fafc 0%, #edf2f7 100%) !important;
455
- padding: 40px !important;
456
- text-align: center !important;
457
- transition: var(--transition) !important;
458
- position: relative !important;
459
- overflow: hidden !important;
460
- cursor: pointer !important;
461
- }
462
-
463
- .file-upload:hover {
464
- border-color: #667eea !important;
465
- background: linear-gradient(135deg, #edf2f7 0%, #e2e8f0 100%) !important;
466
- transform: translateY(-2px) scale(1.01) !important;
467
- box-shadow: var(--shadow-md) !important;
468
- }
469
-
470
- .file-upload::before {
471
- content: 'πŸ“' !important;
472
- font-size: 4rem !important;
473
- display: block !important;
474
- margin-bottom: 15px !important;
475
- animation: fileFloat 3s ease-in-out infinite !important;
476
- }
477
-
478
- .file-upload::after {
479
- content: 'Drag files here or click to browse' !important;
480
- position: absolute !important;
481
- bottom: 15px !important;
482
- left: 50% !important;
483
- transform: translateX(-50%) !important;
484
- font-size: 14px !important;
485
- color: var(--text-light) !important;
486
- font-weight: 500 !important;
487
- }
488
-
489
- /* Enhanced Examples Section */
490
- .examples {
491
- background: linear-gradient(135deg, #f8f9ff 0%, #e8eeff 100%) !important;
492
- border-radius: var(--border-radius) !important;
493
- padding: 30px !important;
494
- margin: 25px 0 !important;
495
- border: 1px solid #e2e8f0 !important;
496
- box-shadow: var(--shadow-sm) !important;
497
- position: relative !important;
498
- }
499
-
500
- .examples::before {
501
- content: 'πŸ’‘' !important;
502
- position: absolute !important;
503
- top: -15px !important;
504
- left: 30px !important;
505
- background: var(--bg-card) !important;
506
- padding: 10px !important;
507
- border-radius: 50% !important;
508
- font-size: 20px !important;
509
- box-shadow: var(--shadow-sm) !important;
510
- }
511
-
512
- .examples h3 {
513
- color: #667eea !important;
514
- font-weight: 700 !important;
515
- margin-bottom: 20px !important;
516
- font-size: 1.3rem !important;
517
- margin-left: 20px !important;
518
- }
519
-
520
- /* Feature Cards with Hover Effects */
521
- .feature-card {
522
- background: var(--bg-card) !important;
523
- border-radius: var(--border-radius) !important;
524
- padding: 25px !important;
525
- margin: 15px 0 !important;
526
- box-shadow: var(--shadow-sm) !important;
527
- border-left: 4px solid transparent !important;
528
- transition: var(--transition) !important;
529
- cursor: pointer !important;
530
- }
531
-
532
- .feature-card:hover {
533
- transform: translateY(-5px) translateX(5px) !important;
534
- box-shadow: var(--shadow-md) !important;
535
- }
536
-
537
- .feature-card.research {
538
- border-left-color: #667eea !important;
539
- }
540
-
541
- .feature-card.code {
542
- border-left-color: #48bb78 !important;
543
- }
544
-
545
- .feature-card.data {
546
- border-left-color: #ed8936 !important;
547
- }
548
-
549
- .feature-card.image {
550
- border-left-color: #dd6b20 !important;
551
- }
552
-
553
- /* Status Indicator with Pulse Animation */
554
- .status-indicator {
555
- display: inline-block !important;
556
- width: 12px !important;
557
- height: 12px !important;
558
- border-radius: 50% !important;
559
- background: radial-gradient(circle, #48bb78, #38a169) !important;
560
- margin-right: 12px !important;
561
- animation: statusPulse 2s ease-in-out infinite !important;
562
- box-shadow: 0 0 0 0 rgba(72, 187, 120, 0.7) !important;
563
- }
564
-
565
- /* Enhanced Footer */
566
- .footer {
567
- background: var(--glass-bg) !important;
568
- backdrop-filter: blur(10px) !important;
569
- border-radius: var(--border-radius) !important;
570
- padding: 30px !important;
571
- margin-top: 40px !important;
572
- text-align: center !important;
573
- border: 1px solid var(--glass-border) !important;
574
- box-shadow: var(--shadow-sm) !important;
575
- }
576
-
577
- /* Advanced Animations */
578
- @keyframes titleGlow {
579
- 0%, 100% { text-shadow: 0 0 20px rgba(102, 126, 234, 0.5); }
580
- 50% { text-shadow: 0 0 30px rgba(102, 126, 234, 0.8), 0 0 40px rgba(118, 75, 162, 0.6); }
581
- }
582
-
583
- @keyframes messageSlideIn {
584
- from {
585
- opacity: 0;
586
- transform: translateY(30px) scale(0.95);
587
- }
588
- to {
589
- opacity: 1;
590
- transform: translateY(0) scale(1);
591
- }
592
- }
593
-
594
- @keyframes typingDots {
595
- 0%, 80%, 100% { transform: scale(0.8); opacity: 0.5; }
596
- 40% { transform: scale(1.2); opacity: 1; }
597
- }
598
-
599
- @keyframes fileFloat {
600
- 0%, 100% { transform: translateY(0px); }
601
- 50% { transform: translateY(-10px); }
602
- }
603
-
604
- @keyframes statusPulse {
605
- 0% {
606
- transform: scale(0.95);
607
- box-shadow: 0 0 0 0 rgba(72, 187, 120, 0.7);
608
- }
609
- 70% {
610
- transform: scale(1);
611
- box-shadow: 0 0 0 10px rgba(72, 187, 120, 0);
612
- }
613
- 100% {
614
- transform: scale(0.95);
615
- box-shadow: 0 0 0 0 rgba(72, 187, 120, 0);
616
- }
617
- }
618
-
619
- @keyframes float {
620
- 0%, 100% { transform: translateY(0px) rotate(0deg); }
621
- 33% { transform: translateY(-10px) rotate(1deg); }
622
- 66% { transform: translateY(-5px) rotate(-1deg); }
623
- }
624
-
625
- @keyframes pulse {
626
- 0%, 100% { transform: scale(1) scaleX(1); }
627
- 50% { transform: scale(1.05) scaleX(1.1); }
628
- }
629
-
630
- /* Responsive Design Enhancements */
631
- @media (max-width: 1024px) {
632
- .gradio-container { padding: 15px !important; }
633
- .main-content { padding: 25px !important; margin: 15px 0 !important; }
634
- .markdown h1 { font-size: 2.5rem !important; }
635
- }
636
-
637
- @media (max-width: 768px) {
638
- .gradio-container { padding: 10px !important; }
639
- .main-content { padding: 20px !important; margin: 10px 0 !important; }
640
- .chatbot .message-wrap { max-width: 90% !important; margin: 10px !important; padding: 15px !important; }
641
- .markdown h1 { font-size: 2rem !important; }
642
- .btn { padding: 12px 20px !important; font-size: 14px !important; }
643
- .file-upload { padding: 30px 20px !important; }
644
- }
645
-
646
- @media (max-width: 480px) {
647
- .markdown h1 { font-size: 1.8rem !important; }
648
- .chatbot .message-wrap { margin: 8px !important; padding: 12px !important; }
649
- .main-content { padding: 15px !important; }
650
- }
651
-
652
- /* Custom Scrollbar Enhancement */
653
- ::-webkit-scrollbar { width: 12px; }
654
- ::-webkit-scrollbar-track {
655
- background: rgba(241, 241, 241, 0.5);
656
- border-radius: 6px;
657
- }
658
- ::-webkit-scrollbar-thumb {
659
- background: var(--primary-gradient);
660
- border-radius: 6px;
661
- border: 2px solid rgba(255, 255, 255, 0.2);
662
- }
663
- ::-webkit-scrollbar-thumb:hover {
664
- background: linear-gradient(135deg, #5a6fd8 0%, #6a4190 100%);
665
- }
666
-
667
- /* Loading States */
668
- .loading { animation: pulse 2s infinite !important; }
669
- .processing {
670
- position: relative !important;
671
- overflow: hidden !important;
672
- }
673
- .processing::after {
674
- content: '' !important;
675
- position: absolute !important;
676
- top: 0 !important;
677
- left: -100% !important;
678
- width: 100% !important;
679
- height: 100% !important;
680
- background: linear-gradient(90deg, transparent, rgba(255,255,255,0.4), transparent) !important;
681
- animation: shimmer 2s infinite !important;
682
- }
683
-
684
- @keyframes shimmer {
685
- 0% { left: -100%; }
686
- 100% { left: 100%; }
687
- }
688
-
689
- /* Dark mode support (future enhancement) */
690
- @media (prefers-color-scheme: dark) {
691
- :root {
692
- --glass-bg: rgba(26, 32, 44, 0.95);
693
- --text-primary: #e2e8f0;
694
- --text-secondary: #cbd5e0;
695
- --text-light: #a0aec0;
696
- --bg-card: #2d3748;
697
- --bg-light: #1a202c;
698
- }
699
- }
700
  """
701
-
702
- with gr.Blocks(css=custom_css, title="GAIA Agent - Q&A Chatbot", theme=gr.themes.Soft()) as demo:
703
- # Header with enhanced styling
704
- with gr.Row(elem_classes="main-content"):
705
- gr.Markdown(
706
- """
707
- <h1 align="center">πŸ€– GAIA Agent - Advanced Q&A Chatbot</h1>
708
-
709
- 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.
710
-
711
- ### 🌟 **What I can do:**
712
-
713
- <div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 20px; margin: 20px 0;">
714
- <div class="feature-card research" style="background: linear-gradient(135deg, #f8f9ff 0%, #e8eeff 100%); padding: 25px; border-radius: 12px; border-left: 4px solid #667eea; cursor: pointer; transition: all 0.3s ease;">
715
- <div style="display: flex; align-items: center; margin-bottom: 10px;">
716
- <span style="font-size: 2rem; margin-right: 15px;">πŸ”</span>
717
- <strong style="font-size: 1.1rem; color: #667eea;">Research & Search</strong>
718
- </div>
719
- <p style="margin: 0; color: #718096; font-size: 14px; line-height: 1.5;">Web search, Wikipedia, academic papers, arXiv research</p>
720
- </div>
721
- <div class="feature-card code" style="background: linear-gradient(135deg, #f0fff4 0%, #c6f6d5 100%); padding: 25px; border-radius: 12px; border-left: 4px solid #48bb78; cursor: pointer; transition: all 0.3s ease;">
722
- <div style="display: flex; align-items: center; margin-bottom: 10px;">
723
- <span style="font-size: 2rem; margin-right: 15px;">πŸ’»</span>
724
- <strong style="font-size: 1.1rem; color: #48bb78;">Code Execution</strong>
725
- </div>
726
- <p style="margin: 0; color: #718096; font-size: 14px; line-height: 1.5;">Python, Bash, SQL, C, Java with real-time results</p>
727
- </div>
728
- <div class="feature-card data" style="background: linear-gradient(135deg, #fffaf0 0%, #fbd38d 100%); padding: 25px; border-radius: 12px; border-left: 4px solid #ed8936; cursor: pointer; transition: all 0.3s ease;">
729
- <div style="display: flex; align-items: center; margin-bottom: 10px;">
730
- <span style="font-size: 2rem; margin-right: 15px;">πŸ“Š</span>
731
- <strong style="font-size: 1.1rem; color: #ed8936;">Data Analysis</strong>
732
- </div>
733
- <p style="margin: 0; color: #718096; font-size: 14px; line-height: 1.5;">CSV, Excel, visualizations, statistical analysis</p>
734
- </div>
735
- <div class="feature-card image" style="background: linear-gradient(135deg, #fef5e7 0%, #f6ad55 100%); padding: 25px; border-radius: 12px; border-left: 4px solid #dd6b20; cursor: pointer; transition: all 0.3s ease;">
736
- <div style="display: flex; align-items: center; margin-bottom: 10px;">
737
- <span style="font-size: 2rem; margin-right: 15px;">πŸ–ΌοΈ</span>
738
- <strong style="font-size: 1.1rem; color: #dd6b20;">Image Processing</strong>
739
- </div>
740
- <p style="margin: 0; color: #718096; font-size: 14px; line-height: 1.5;">Analysis, OCR, transformations, generation</p>
741
- </div>
742
- </div>
743
-
744
- ---
745
- """
746
- )
747
-
748
- # Chat interface with enhanced styling
749
- with gr.Row(elem_classes="main-content"):
750
- with gr.Column(scale=1):
751
- chatbot_interface = gr.Chatbot(
752
- label="πŸ’¬ Conversation",
753
- height=600,
754
- show_label=True,
755
- container=True,
756
- bubble_full_width=False,
757
- elem_classes="chatbot"
758
- )
759
-
760
- # File upload section with enhanced styling
761
- with gr.Row(elem_classes="main-content"):
762
- with gr.Column():
763
- file_upload = gr.File(
764
- label="πŸ“ Upload Files - Drag & drop or click to upload images, documents, CSV, Excel files, etc.",
765
- file_count="multiple",
766
- file_types=[
767
- ".jpg", ".jpeg", ".png", ".gif", ".bmp", ".webp", # Images
768
- ".txt", ".md", ".py", ".js", ".html", ".css", ".json", ".xml", # Text files
769
- ".csv", ".xlsx", ".xls", # Data files
770
- ".pdf", ".doc", ".docx" # Documents
771
- ],
772
- height=120,
773
- elem_classes="file-upload"
774
- )
775
-
776
- # Input and buttons with enhanced styling
777
- with gr.Row(elem_classes="main-content"):
778
- with gr.Column(scale=8):
779
- question_input = gr.Textbox(
780
- label="πŸ’­ Ask a question",
781
- placeholder="Type your question here or upload files above... (e.g., 'What is the capital of France?', 'Analyze this image', 'Summarize this document')",
782
- lines=3,
783
- max_lines=5,
784
- elem_classes="textbox"
785
- )
786
- with gr.Column(scale=2, min_width=120):
787
- submit_btn = gr.Button("πŸš€ Send", variant="primary", size="lg", elem_classes="btn btn-primary")
788
-
789
- with gr.Row(elem_classes="main-content"):
790
- with gr.Column(scale=1):
791
- clear_btn = gr.Button("🧹 Clear History", variant="secondary", elem_classes="btn btn-secondary")
792
- with gr.Column(scale=1):
793
- clear_files_btn = gr.Button("πŸ—‘οΈ Clear Files", variant="secondary", elem_classes="btn btn-secondary")
794
- with gr.Column(scale=1):
795
- export_btn = gr.Button("πŸ’Ύ Export Chat", variant="secondary", elem_classes="btn btn-secondary")
796
-
797
- # Hidden download component for chat export
798
- download_file = gr.File(visible=False)
799
-
800
- with gr.Row(elem_classes="main-content"):
801
- with gr.Column():
802
- gr.Examples(
803
- examples=[
804
- "What is the current population of Tokyo?",
805
- "Calculate the square root of 144",
806
- "Write a Python function to sort a list",
807
- "What are the latest developments in AI?",
808
- "Explain quantum computing in simple terms",
809
- ],
810
- inputs=question_input,
811
- label="🌐 General Questions"
812
- )
813
- with gr.Column():
814
- gr.Examples(
815
- examples=[
816
- "Search for recent papers on machine learning",
817
- "What is the weather like today?",
818
- "Create a simple bar chart using Python",
819
- "Convert 100 USD to EUR",
820
- "What are the benefits of renewable energy?",
821
- ],
822
- inputs=question_input,
823
- label="πŸ”¬ Research & Analysis"
824
- )
825
- with gr.Column():
826
- gr.Examples(
827
- examples=[
828
- "Analyze this image and describe what you see",
829
- "Extract text from this image using OCR",
830
- "Summarize the content of this document",
831
- "Analyze the data in this CSV file",
832
- "What insights can you find in this Excel file?",
833
- ],
834
- inputs=question_input,
835
- label="πŸ“ File Analysis"
836
- )
837
-
838
- # Event handlers
839
- def submit_question(question, history, files):
840
- print(f"🎯 UI: Submit button clicked")
841
- print(f"πŸ“ UI: Question length: {len(question) if question else 0}")
842
- print(f"πŸ“ UI: Files count: {len(files) if files else 0}")
843
- result_question, result_history = chatbot.process_question(question, history, files)
844
- print(f"πŸ”„ UI: Returning results and clearing files")
845
- return result_question, result_history, None # Clear files after processing
846
-
847
- def clear_conversation():
848
- print("🧹 UI: Clear conversation button clicked")
849
- return chatbot.clear_history()
850
-
851
- def clear_files():
852
- print("πŸ—‘οΈ UI: Clear files button clicked")
853
- return None
854
-
855
- def export_conversation(history):
856
- """Export conversation history to a text file"""
857
- print("πŸ’Ύ UI: Export conversation button clicked")
858
- if not history:
859
- print("⚠️ No conversation to export")
860
- return None
861
-
862
- try:
863
- import tempfile
864
- import datetime
865
-
866
- # Create export content
867
- timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
868
- export_content = f"# GAIA Agent Conversation Export\n"
869
- export_content += f"Export Date: {datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n"
870
- export_content += f"Total Messages: {len(history)}\n\n"
871
- export_content += "=" * 50 + "\n\n"
872
-
873
- for i, (user_msg, bot_msg) in enumerate(history, 1):
874
- export_content += f"## Message {i}\n\n"
875
- export_content += f"**User:** {user_msg}\n\n"
876
- export_content += f"**Assistant:** {bot_msg}\n\n"
877
- export_content += "-" * 30 + "\n\n"
878
-
879
- # Save to temporary file
880
- temp_file = tempfile.NamedTemporaryFile(
881
- mode='w',
882
- suffix=f'_gaia_chat_export_{timestamp}.md',
883
- delete=False,
884
- encoding='utf-8'
885
- )
886
- temp_file.write(export_content)
887
- temp_file.close()
888
-
889
- print(f"πŸ“„ Conversation exported to: {temp_file.name}")
890
- return temp_file.name
891
-
892
- except Exception as e:
893
- print(f"❌ Error exporting conversation: {e}")
894
- return None
895
-
896
- # Connect the events
897
- submit_btn.click(
898
- fn=submit_question,
899
- inputs=[question_input, chatbot_interface, file_upload],
900
- outputs=[question_input, chatbot_interface, file_upload],
901
- show_progress=True
902
- )
903
-
904
- question_input.submit(
905
- fn=submit_question,
906
- inputs=[question_input, chatbot_interface, file_upload],
907
- outputs=[question_input, chatbot_interface, file_upload],
908
- show_progress=True
909
- )
910
-
911
- clear_btn.click(
912
- fn=clear_conversation,
913
- outputs=[chatbot_interface],
914
- show_progress=False
915
- )
916
-
917
- clear_files_btn.click(
918
- fn=clear_files,
919
- outputs=[file_upload],
920
- show_progress=False
921
  )
922
-
923
- export_btn.click(
924
- fn=export_conversation,
925
- inputs=[chatbot_interface],
926
- outputs=[download_file],
927
- show_progress=True
928
  )
929
-
930
- return demo
931
 
932
- if __name__ == "__main__":
933
- print("\n" + "-"*50)
934
- print("πŸš€ Starting GAIA Agent Q&A Chatbot...")
935
- print("-"*50 + "\n")
936
-
937
- # Create and launch the interface
938
- demo = create_qna_interface()
939
- demo.launch(
940
- debug=True,
941
- share=False,
942
- server_name="0.0.0.0",
943
- server_port=7860,
944
- show_error=True
945
- )
 
 
 
1
  import os
 
 
 
 
2
 
3
+ import agent
4
+ import gradio as gr
5
+ import logic
6
+ import pandas as pd
7
+ from dotenv import load_dotenv
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8
 
9
+ load_dotenv()
10
+
11
+
12
+ def run_and_submit_all(
13
+ profile: gr.OAuthProfile | None,
14
+ ) -> tuple[str, pd.DataFrame | None]:
15
+ """Fetches all questions, runs the BasicAgent on them, submits all answers,
16
+ and displays the results.
17
+ Args:
18
+ profile: An optional gr.OAuthProfile object containing user information
19
+ if the user is logged in. If None, the user is not logged in.
20
+ Returns:
21
+ tuple[str, pd.DataFrame | None]: A tuple containing:
22
+ - A string representing the status of the run and submission process.
23
+ This could be a success message, an error message, or a message
24
+ indicating that no answers were produced.
25
+ - A pandas DataFrame containing the results log. This DataFrame will
26
+ be displayed in the Gradio interface. It can be None if an error
27
+ occurred before the agent was run.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
28
  """
29
+ # 0. Get user details
30
+ space_id = os.getenv("SPACE_ID")
31
+ agent_code = f"https://huggingface.co/spaces/{space_id}/tree/main"
32
+ print(agent_code)
33
+ if profile:
34
+ username = f"{profile.username}"
35
+ print(f"User logged in: {username}")
36
+ else:
37
+ print("User not logged in.")
38
+ return "Please Login to Hugging Face with the button.", None
39
+
40
+ # 1. Instantiate Agent
41
+ try:
42
+ gaia_agent = agent.GaiaAgent()
43
+ except Exception as e:
44
+ print(f"Error instantiating agent: {e}")
45
+ return f"Error initializing agent: {e}", None
46
+
47
+ # 2. Fetch Questions
48
+ try:
49
+ questions_data = logic.fetch_all_questions()
50
+ except Exception as e:
51
+ return str(e), None
52
+
53
+ # 3. Run the Agent
54
+ results_log, answers_payload = logic.run_agent(gaia_agent, questions_data)
55
+ if not answers_payload:
56
+ print("Agent did not produce any answers to submit.")
57
+ return "Agent did not produce any answers to submit.", pd.DataFrame(results_log)
58
+
59
+ # 4. Prepare & Submit Answers
60
+ submission_data = {
61
+ "username": username.strip(),
62
+ "agent_code": agent_code,
63
+ "answers": answers_payload,
64
+ }
65
+ print(
66
+ f"Agent finished. Submitting {len(answers_payload)} answers for user '"
67
+ f"{username}'..."
68
+ )
69
+ return logic.submit_answers(submission_data, results_log)
70
+
71
+
72
+ # --- Build Gradio Interface using Blocks ---
73
+ with gr.Blocks() as gaia_ui:
74
+ gr.Markdown("# Basic Agent Evaluation Runner")
75
+ gr.Markdown(
76
+ """
77
+ **Instructions:**
78
+ 1. Please clone this space, then modify the code to define your agent's
79
+ logic, the tools, the necessary packages, etc ...
80
+ 2. Log in to your Hugging Face account using the button below. This uses
81
+ your HF username for submission.
82
+ 3. Click 'Run Evaluation & Submit All Answers' to fetch questions, run your
83
+ agent, submit answers, and see the score.
84
+ ---
85
+ **Disclaimers:**
86
+ Once clicking on the "submit button, it can take quite some time ( this is
87
+ the time for the agent to go through all the questions).
88
+ This space provides a basic setup and is intentionally sub-optimal to
89
+ encourage you to develop your own, more robust solution. For instance for the
90
+ delay process of the submit button, a solution could be to cache the answers
91
+ and submit in a separate action or even to answer the questions in async.
92
+ """
93
+ )
94
+
95
+ gr.LoginButton()
96
+
97
+ run_button = gr.Button("Run Evaluation & Submit All Answers")
98
+
99
+ status_output = gr.Textbox(
100
+ label="Run Status / Submission Result", lines=5, interactive=False
101
+ )
102
+ # Removed max_rows=10 from DataFrame constructor
103
+ results_table = gr.DataFrame(label="Questions and Agent Answers", wrap=True)
104
+
105
+ run_button.click(
106
+ fn=run_and_submit_all, inputs=None, outputs=[status_output, results_table]
107
+ )
108
+
109
+ if __name__ == "__main__":
110
+ print("\n" + "-" * 30 + " App Starting " + "-" * 30)
111
+ # Check for SPACE_HOST and SPACE_ID at startup for information
112
+ space_host_startup = os.getenv("SPACE_HOST")
113
+ space_id_startup = os.getenv("SPACE_ID") # Get SPACE_ID at startup
114
+
115
+ if space_host_startup:
116
+ print(f"βœ… SPACE_HOST found: {space_host_startup}")
117
+ print(f" Runtime URL should be: https://{space_host_startup}.hf.space")
118
+ else:
119
+ print("ℹ️ SPACE_HOST environment variable not found (running locally?).")
120
+
121
+ if space_id_startup: # Print repo URLs if SPACE_ID is found
122
+ print(f"βœ… SPACE_ID found: {space_id_startup}")
123
+ print(f" Repo URL: https://huggingface.co/spaces/{space_id_startup}")
124
+ print(
125
+ f" Repo Tree URL: https://huggingface.co/spaces/"
126
+ f"{space_id_startup}/tree/main"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
127
  )
128
+ else:
129
+ print(
130
+ "ℹ️ SPACE_ID environment variable not found (running locally?). Repo URL "
131
+ "cannot be determined."
 
 
132
  )
 
 
133
 
134
+ print("-" * (60 + len(" App Starting ")) + "\n")
135
+
136
+ print("Launching Gradio Interface for Basic Agent Evaluation...")
137
+ gaia_ui.launch(debug=True, share=True)