TBao-THUer commited on
Commit
175aca3
ยท
verified ยท
1 Parent(s): 8f85efb

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +933 -195
app.py CHANGED
@@ -1,207 +1,945 @@
1
- """ Basic Agent Evaluation Runner"""
2
- import os
3
- import inspect
4
  import gradio as gr
5
- import requests
6
- import pandas as pd
 
 
7
  from langchain_core.messages import HumanMessage
8
  from agent import build_graph
9
 
10
-
11
-
12
- # (Keep Constants as is)
13
- # --- Constants ---
14
- DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
15
-
16
- # --- Basic Agent Definition ---
17
- # ----- THIS IS WERE YOU CAN BUILD WHAT YOU WANT ------
18
-
19
-
20
- class BasicAgent:
21
- """A langgraph agent."""
22
  def __init__(self):
23
- print("BasicAgent initialized.")
 
24
  self.graph = build_graph()
25
-
26
- def __call__(self, question: str) -> str:
27
- print(f"Agent received question (first 50 chars): {question[:50]}...")
28
- messages = [HumanMessage(content=question)]
29
- result = self.graph.invoke({"messages": messages})
30
- answer = result['messages'][-1].content
31
- return answer # kein [14:] mehr nรถtig!
32
-
33
-
34
-
35
- def run_and_submit_all( profile: gr.OAuthProfile | None):
36
- """
37
- Fetches all questions, runs the BasicAgent on them, submits all answers,
38
- and displays the results.
39
- """
40
- # --- Determine HF Space Runtime URL and Repo URL ---
41
- space_id = os.getenv("SPACE_ID") # Get the SPACE_ID for sending link to the code
42
-
43
- if profile:
44
- username= f"{profile.username}"
45
- print(f"User logged in: {username}")
46
- else:
47
- print("User not logged in.")
48
- return "Please Login to Hugging Face with the button.", None
49
-
50
- api_url = DEFAULT_API_URL
51
- questions_url = f"{api_url}/questions"
52
- submit_url = f"{api_url}/submit"
53
-
54
- # 1. Instantiate Agent ( modify this part to create your agent)
55
- try:
56
- agent = BasicAgent()
57
- except Exception as e:
58
- print(f"Error instantiating agent: {e}")
59
- return f"Error initializing agent: {e}", None
60
- # In the case of an app running as a hugging Face space, this link points toward your codebase ( usefull for others so please keep it public)
61
- agent_code = f"https://huggingface.co/spaces/{space_id}/tree/main"
62
- print(agent_code)
63
-
64
- # 2. Fetch Questions
65
- print(f"Fetching questions from: {questions_url}")
66
- try:
67
- response = requests.get(questions_url, timeout=15)
68
- response.raise_for_status()
69
- questions_data = response.json()
70
- if not questions_data:
71
- print("Fetched questions list is empty.")
72
- return "Fetched questions list is empty or invalid format.", None
73
- print(f"Fetched {len(questions_data)} questions.")
74
- except requests.exceptions.RequestException as e:
75
- print(f"Error fetching questions: {e}")
76
- return f"Error fetching questions: {e}", None
77
- except requests.exceptions.JSONDecodeError as e:
78
- print(f"Error decoding JSON response from questions endpoint: {e}")
79
- print(f"Response text: {response.text[:500]}")
80
- return f"Error decoding server response for questions: {e}", None
81
- except Exception as e:
82
- print(f"An unexpected error occurred fetching questions: {e}")
83
- return f"An unexpected error occurred fetching questions: {e}", None
84
-
85
- # 3. Run your Agent
86
- results_log = []
87
- answers_payload = []
88
- print(f"Running agent on {len(questions_data)} questions...")
89
- for item in questions_data:
90
- task_id = item.get("task_id")
91
- question_text = item.get("question")
92
- if not task_id or question_text is None:
93
- print(f"Skipping item with missing task_id or question: {item}")
94
- continue
95
  try:
96
- submitted_answer = agent(question_text)
97
- answers_payload.append({"task_id": task_id, "submitted_answer": submitted_answer})
98
- results_log.append({"Task ID": task_id, "Question": question_text, "Submitted Answer": submitted_answer})
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
99
  except Exception as e:
100
- print(f"Error running agent on task {task_id}: {e}")
101
- results_log.append({"Task ID": task_id, "Question": question_text, "Submitted Answer": f"AGENT ERROR: {e}"})
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
102
 
103
- if not answers_payload:
104
- print("Agent did not produce any answers to submit.")
105
- return "Agent did not produce any answers to submit.", pd.DataFrame(results_log)
106
-
107
- # 4. Prepare Submission
108
- submission_data = {"username": username.strip(), "agent_code": agent_code, "answers": answers_payload}
109
- status_update = f"Agent finished. Submitting {len(answers_payload)} answers for user '{username}'..."
110
- print(status_update)
111
-
112
- # 5. Submit
113
- print(f"Submitting {len(answers_payload)} answers to: {submit_url}")
114
- try:
115
- response = requests.post(submit_url, json=submission_data, timeout=60)
116
- response.raise_for_status()
117
- result_data = response.json()
118
- final_status = (
119
- f"Submission Successful!\n"
120
- f"User: {result_data.get('username')}\n"
121
- f"Overall Score: {result_data.get('score', 'N/A')}% "
122
- f"({result_data.get('correct_count', '?')}/{result_data.get('total_attempted', '?')} correct)\n"
123
- f"Message: {result_data.get('message', 'No message received.')}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
124
  )
125
- print("Submission successful.")
126
- results_df = pd.DataFrame(results_log)
127
- return final_status, results_df
128
- except requests.exceptions.HTTPError as e:
129
- error_detail = f"Server responded with status {e.response.status_code}."
130
- try:
131
- error_json = e.response.json()
132
- error_detail += f" Detail: {error_json.get('detail', e.response.text)}"
133
- except requests.exceptions.JSONDecodeError:
134
- error_detail += f" Response: {e.response.text[:500]}"
135
- status_message = f"Submission Failed: {error_detail}"
136
- print(status_message)
137
- results_df = pd.DataFrame(results_log)
138
- return status_message, results_df
139
- except requests.exceptions.Timeout:
140
- status_message = "Submission Failed: The request timed out."
141
- print(status_message)
142
- results_df = pd.DataFrame(results_log)
143
- return status_message, results_df
144
- except requests.exceptions.RequestException as e:
145
- status_message = f"Submission Failed: Network error - {e}"
146
- print(status_message)
147
- results_df = pd.DataFrame(results_log)
148
- return status_message, results_df
149
- except Exception as e:
150
- status_message = f"An unexpected error occurred during submission: {e}"
151
- print(status_message)
152
- results_df = pd.DataFrame(results_log)
153
- return status_message, results_df
154
-
155
-
156
- # --- Build Gradio Interface using Blocks ---
157
- with gr.Blocks() as demo:
158
- gr.Markdown("# Basic Agent Evaluation Runner")
159
- gr.Markdown(
160
- """
161
- **Instructions:**
162
- 1. Please clone this space, then modify the code to define your agent's logic, the tools, the necessary packages, etc ...
163
- 2. Log in to your Hugging Face account using the button below. This uses your HF username for submission.
164
- 3. Click 'Run Evaluation & Submit All Answers' to fetch questions, run your agent, submit answers, and see the score.
165
- ---
166
- **Disclaimers:**
167
- Once clicking on the "submit button, it can take quite some time ( this is the time for the agent to go through all the questions).
168
- This space provides a basic setup and is intentionally sub-optimal to encourage you to develop your own, more robust solution. For instance for the delay process of the submit button, a solution could be to cache the answers and submit in a seperate action or even to answer the questions in async.
169
- """
170
- )
171
-
172
- gr.LoginButton()
173
-
174
- run_button = gr.Button("Run Evaluation & Submit All Answers")
175
-
176
- status_output = gr.Textbox(label="Run Status / Submission Result", lines=5, interactive=False)
177
- # Removed max_rows=10 from DataFrame constructor
178
- results_table = gr.DataFrame(label="Questions and Agent Answers", wrap=True)
179
-
180
- run_button.click(
181
- fn=run_and_submit_all,
182
- outputs=[status_output, results_table]
183
- )
184
 
185
  if __name__ == "__main__":
186
- print("\n" + "-"*30 + " App Starting " + "-"*30)
187
- # Check for SPACE_HOST and SPACE_ID at startup for information
188
- space_host_startup = os.getenv("SPACE_HOST")
189
- space_id_startup = os.getenv("SPACE_ID") # Get SPACE_ID at startup
190
-
191
- if space_host_startup:
192
- print(f"โœ… SPACE_HOST found: {space_host_startup}")
193
- print(f" Runtime URL should be: https://{space_host_startup}.hf.space")
194
- else:
195
- print("โ„น๏ธ SPACE_HOST environment variable not found (running locally?).")
196
-
197
- if space_id_startup: # Print repo URLs if SPACE_ID is found
198
- print(f"โœ… SPACE_ID found: {space_id_startup}")
199
- print(f" Repo URL: https://huggingface.co/spaces/{space_id_startup}")
200
- print(f" Repo Tree URL: https://huggingface.co/spaces/{space_id_startup}/tree/main")
201
- else:
202
- print("โ„น๏ธ SPACE_ID environment variable not found (running locally?). Repo URL cannot be determined.")
203
-
204
- print("-"*(60 + len(" App Starting ")) + "\n")
205
-
206
- print("Launching Gradio Interface for Basic Agent Evaluation...")
207
- demo.launch(debug=True, share=False)
 
 
 
 
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
+ )