LamiaYT commited on
Commit
a42d6f7
ยท
1 Parent(s): ab91638

Initial commit with LlamaIndex-based agent

Browse files
Files changed (2) hide show
  1. app.py +148 -42
  2. requirements.txt +4 -2
app.py CHANGED
@@ -7,10 +7,22 @@ import os
7
  import gradio as gr
8
  import requests
9
  import pandas as pd
 
10
 
11
- from duckduckgo_search import DDGS
12
- from sympy import sympify
13
- from sympy.core.sympify import SympifyError
 
 
 
 
 
 
 
 
 
 
 
14
 
15
  # --- Constants ---
16
  DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
@@ -19,7 +31,7 @@ DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
19
  class SmartAgent:
20
  def __init__(self):
21
  print("Initializing Local LLM Agent...")
22
-
23
  # Initialize Zephyr-7B model
24
  self.llm = HuggingFaceLLM(
25
  model_name="HuggingFaceH4/zephyr-7b-beta",
@@ -29,21 +41,21 @@ class SmartAgent:
29
  generate_kwargs={"temperature": 0.7, "do_sample": True},
30
  device_map="auto"
31
  )
32
-
33
  # Define tools with real implementations
34
  self.tools = [
35
  FunctionTool.from_defaults(
36
  fn=self.web_search,
37
  name="web_search",
38
- description="Searches the web for current information using DuckDuckGo."
39
  ),
40
  FunctionTool.from_defaults(
41
  fn=self.math_calculator,
42
  name="math_calculator",
43
- description="Performs symbolic math using SymPy."
44
  )
45
  ]
46
-
47
  # Create ReAct agent with tools
48
  self.agent = ReActAgent.from_tools(
49
  tools=self.tools,
@@ -55,27 +67,51 @@ class SmartAgent:
55
  def web_search(self, query: str) -> str:
56
  """Real web search using DuckDuckGo"""
57
  print(f"Web search triggered for: {query[:50]}...")
 
 
 
 
58
  try:
59
  with DDGS() as ddgs:
60
- results = ddgs.text(query, max_results=3)
61
  if results:
62
- return "\n\n".join([f"{r['title']}: {r['href']}" for r in results])
 
 
 
 
 
 
63
  else:
64
- return "No results found."
65
  except Exception as e:
66
  print(f"Web search error: {e}")
67
- return f"Error during web search: {e}"
68
 
69
  def math_calculator(self, expression: str) -> str:
70
  """Safe math evaluation using SymPy"""
71
  print(f"Math calculation triggered for: {expression}")
 
 
 
 
 
 
 
 
 
 
 
 
 
72
  try:
 
73
  result = sympify(expression).evalf()
74
  return str(result)
75
  except SympifyError as e:
76
- return f"Error: Could not parse the expression ({e})"
77
  except Exception as e:
78
- return f"Error: Calculation failed ({e})"
79
 
80
  def __call__(self, question: str) -> str:
81
  print(f"Processing question (first 50 chars): {question[:50]}...")
@@ -84,10 +120,11 @@ class SmartAgent:
84
  return str(response)
85
  except Exception as e:
86
  print(f"Agent error: {str(e)}")
 
87
  return f"Error processing question: {str(e)}"
88
 
89
 
90
- # --- Original Submission Logic ---
91
  def run_and_submit_all(profile: gr.OAuthProfile | None):
92
  """
93
  Fetches all questions, runs the agent on them, submits all answers,
@@ -111,10 +148,11 @@ def run_and_submit_all(profile: gr.OAuthProfile | None):
111
  agent = SmartAgent()
112
  except Exception as e:
113
  print(f"Error instantiating agent: {e}")
 
114
  return f"Error initializing agent: {e}", None
115
 
116
  agent_code = f"https://huggingface.co/spaces/{space_id}/tree/main"
117
- print(agent_code)
118
 
119
  # Fetch Questions
120
  print(f"Fetching questions from: {questions_url}")
@@ -131,7 +169,6 @@ def run_and_submit_all(profile: gr.OAuthProfile | None):
131
  return f"Error fetching questions: {e}", None
132
  except requests.exceptions.JSONDecodeError as e:
133
  print(f"Error decoding JSON response from questions endpoint: {e}")
134
- print(f"Response text: {response.text[:500]}")
135
  return f"Error decoding server response for questions: {e}", None
136
  except Exception as e:
137
  print(f"An unexpected error occurred fetching questions: {e}")
@@ -141,45 +178,68 @@ def run_and_submit_all(profile: gr.OAuthProfile | None):
141
  results_log = []
142
  answers_payload = []
143
  print(f"Running agent on {len(questions_data)} questions...")
144
- for item in questions_data:
 
145
  task_id = item.get("task_id")
146
  question_text = item.get("question")
 
147
  if not task_id or question_text is None:
148
  print(f"Skipping item with missing task_id or question: {item}")
149
  continue
 
 
 
150
  try:
151
  submitted_answer = agent(question_text)
152
  answers_payload.append({"task_id": task_id, "submitted_answer": submitted_answer})
153
- results_log.append({"Task ID": task_id, "Question": question_text, "Submitted Answer": submitted_answer})
 
 
 
 
 
154
  except Exception as e:
155
- print(f"Error running agent on task {task_id}: {e}")
156
- results_log.append({"Task ID": task_id, "Question": question_text, "Submitted Answer": f"AGENT ERROR: {e}"})
 
 
 
 
 
 
157
 
158
  if not answers_payload:
159
  print("Agent did not produce any answers to submit.")
160
  return "Agent did not produce any answers to submit.", pd.DataFrame(results_log)
161
 
162
  # Prepare submission
163
- submission_data = {"username": username.strip(), "agent_code": agent_code, "answers": answers_payload}
164
- status_update = f"Agent finished. Submitting {len(answers_payload)} answers for user '{username}'..."
 
 
 
 
 
165
  print(status_update)
166
 
167
- # Submit
168
  print(f"Submitting {len(answers_payload)} answers to: {submit_url}")
169
  try:
170
  response = requests.post(submit_url, json=submission_data, timeout=60)
171
  response.raise_for_status()
172
  result_data = response.json()
 
173
  final_status = (
174
- f"Submission Successful!\n"
175
  f"User: {result_data.get('username')}\n"
176
  f"Overall Score: {result_data.get('score', 'N/A')}% "
177
  f"({result_data.get('correct_count', '?')}/{result_data.get('total_attempted', '?')} correct)\n"
178
  f"Message: {result_data.get('message', 'No message received.')}"
179
  )
180
- print("Submission successful.")
181
  results_df = pd.DataFrame(results_log)
182
  return final_status, results_df
 
183
  except requests.exceptions.HTTPError as e:
184
  error_detail = f"Server responded with status {e.response.status_code}."
185
  try:
@@ -187,44 +247,72 @@ def run_and_submit_all(profile: gr.OAuthProfile | None):
187
  error_detail += f" Detail: {error_json.get('detail', e.response.text)}"
188
  except requests.exceptions.JSONDecodeError:
189
  error_detail += f" Response: {e.response.text[:500]}"
190
- status_message = f"Submission Failed: {error_detail}"
191
  print(status_message)
192
  results_df = pd.DataFrame(results_log)
193
  return status_message, results_df
 
194
  except requests.exceptions.Timeout:
195
- status_message = "Submission Failed: The request timed out."
196
  print(status_message)
197
  results_df = pd.DataFrame(results_log)
198
  return status_message, results_df
 
199
  except requests.exceptions.RequestException as e:
200
- status_message = f"Submission Failed: Network error - {e}"
201
  print(status_message)
202
  results_df = pd.DataFrame(results_log)
203
  return status_message, results_df
 
204
  except Exception as e:
205
- status_message = f"An unexpected error occurred during submission: {e}"
206
  print(status_message)
207
  results_df = pd.DataFrame(results_log)
208
  return status_message, results_df
209
 
210
 
211
  # --- Gradio UI ---
212
- with gr.Blocks() as demo:
213
- gr.Markdown("# Local LLM Agent Evaluation Runner")
214
  gr.Markdown(
215
  """
216
  **Instructions:**
217
- 1. Log in to your Hugging Face account
218
- 2. Click 'Run Evaluation & Submit All Answers'
219
- 3. Wait for the local LLM to process all questions
 
 
 
 
 
 
220
  """
221
  )
222
 
223
- gr.LoginButton()
224
- run_button = gr.Button("Run Evaluation & Submit All Answers")
225
- status_output = gr.Textbox(label="Run Status / Submission Result", lines=5, interactive=False)
226
- results_table = gr.DataFrame(label="Questions and Agent Answers", wrap=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
227
 
 
228
  run_button.click(
229
  fn=run_and_submit_all,
230
  outputs=[status_output, results_table]
@@ -232,14 +320,32 @@ with gr.Blocks() as demo:
232
 
233
 
234
  if __name__ == "__main__":
235
- print("\n" + "-"*30 + " App Starting " + "-"*30)
 
 
 
236
  space_host_startup = os.getenv("SPACE_HOST")
237
  space_id_startup = os.getenv("SPACE_ID")
238
 
239
  if space_host_startup:
240
  print(f"โœ… SPACE_HOST found: {space_host_startup}")
 
 
 
 
 
241
  print(f"โœ… SPACE_ID found: {space_id_startup}")
 
 
242
  else:
243
- print("โŒ SPACE_HOST not found. Please set environment variables.")
244
 
245
- demo.launch()
 
 
 
 
 
 
 
 
 
7
  import gradio as gr
8
  import requests
9
  import pandas as pd
10
+ import traceback
11
 
12
+ # Import real tool dependencies
13
+ try:
14
+ from duckduckgo_search import DDGS
15
+ except ImportError:
16
+ print("Warning: duckduckgo_search not installed. Web search will be limited.")
17
+ DDGS = None
18
+
19
+ try:
20
+ from sympy import sympify
21
+ from sympy.core.sympify import SympifyError
22
+ except ImportError:
23
+ print("Warning: sympy not installed. Math calculator will be limited.")
24
+ sympify = None
25
+ SympifyError = Exception
26
 
27
  # --- Constants ---
28
  DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
 
31
  class SmartAgent:
32
  def __init__(self):
33
  print("Initializing Local LLM Agent...")
34
+
35
  # Initialize Zephyr-7B model
36
  self.llm = HuggingFaceLLM(
37
  model_name="HuggingFaceH4/zephyr-7b-beta",
 
41
  generate_kwargs={"temperature": 0.7, "do_sample": True},
42
  device_map="auto"
43
  )
44
+
45
  # Define tools with real implementations
46
  self.tools = [
47
  FunctionTool.from_defaults(
48
  fn=self.web_search,
49
  name="web_search",
50
+ description="Searches the web for current information using DuckDuckGo when questions require up-to-date knowledge"
51
  ),
52
  FunctionTool.from_defaults(
53
  fn=self.math_calculator,
54
  name="math_calculator",
55
+ description="Performs mathematical calculations and symbolic math using SymPy when questions involve numbers or equations"
56
  )
57
  ]
58
+
59
  # Create ReAct agent with tools
60
  self.agent = ReActAgent.from_tools(
61
  tools=self.tools,
 
67
  def web_search(self, query: str) -> str:
68
  """Real web search using DuckDuckGo"""
69
  print(f"Web search triggered for: {query[:50]}...")
70
+
71
+ if not DDGS:
72
+ return "Web search unavailable - duckduckgo_search not installed"
73
+
74
  try:
75
  with DDGS() as ddgs:
76
+ results = list(ddgs.text(query, max_results=3))
77
  if results:
78
+ formatted_results = []
79
+ for i, r in enumerate(results, 1):
80
+ title = r.get('title', 'No title')
81
+ body = r.get('body', 'No description')[:200]
82
+ url = r.get('href', '')
83
+ formatted_results.append(f"{i}. {title}\n{body}...\nSource: {url}")
84
+ return "\n\n".join(formatted_results)
85
  else:
86
+ return "No search results found for the query."
87
  except Exception as e:
88
  print(f"Web search error: {e}")
89
+ return f"Error during web search: {str(e)}"
90
 
91
  def math_calculator(self, expression: str) -> str:
92
  """Safe math evaluation using SymPy"""
93
  print(f"Math calculation triggered for: {expression}")
94
+
95
+ if not sympify:
96
+ # Fallback to basic eval with safety checks
97
+ try:
98
+ # Only allow basic math operations
99
+ allowed_chars = set('0123456789+-*/().^ ')
100
+ if not all(c in allowed_chars for c in expression.replace(' ', '')):
101
+ return "Error: Only basic math operations are allowed"
102
+ result = eval(expression.replace('^', '**'))
103
+ return str(result)
104
+ except Exception as e:
105
+ return f"Error: Could not evaluate the mathematical expression - {str(e)}"
106
+
107
  try:
108
+ # Use SymPy for safe evaluation
109
  result = sympify(expression).evalf()
110
  return str(result)
111
  except SympifyError as e:
112
+ return f"Error: Could not parse the mathematical expression - {str(e)}"
113
  except Exception as e:
114
+ return f"Error: Calculation failed - {str(e)}"
115
 
116
  def __call__(self, question: str) -> str:
117
  print(f"Processing question (first 50 chars): {question[:50]}...")
 
120
  return str(response)
121
  except Exception as e:
122
  print(f"Agent error: {str(e)}")
123
+ print(f"Full traceback: {traceback.format_exc()}")
124
  return f"Error processing question: {str(e)}"
125
 
126
 
127
+ # --- Submission Logic ---
128
  def run_and_submit_all(profile: gr.OAuthProfile | None):
129
  """
130
  Fetches all questions, runs the agent on them, submits all answers,
 
148
  agent = SmartAgent()
149
  except Exception as e:
150
  print(f"Error instantiating agent: {e}")
151
+ print(f"Full traceback: {traceback.format_exc()}")
152
  return f"Error initializing agent: {e}", None
153
 
154
  agent_code = f"https://huggingface.co/spaces/{space_id}/tree/main"
155
+ print(f"Agent code URL: {agent_code}")
156
 
157
  # Fetch Questions
158
  print(f"Fetching questions from: {questions_url}")
 
169
  return f"Error fetching questions: {e}", None
170
  except requests.exceptions.JSONDecodeError as e:
171
  print(f"Error decoding JSON response from questions endpoint: {e}")
 
172
  return f"Error decoding server response for questions: {e}", None
173
  except Exception as e:
174
  print(f"An unexpected error occurred fetching questions: {e}")
 
178
  results_log = []
179
  answers_payload = []
180
  print(f"Running agent on {len(questions_data)} questions...")
181
+
182
+ for i, item in enumerate(questions_data, 1):
183
  task_id = item.get("task_id")
184
  question_text = item.get("question")
185
+
186
  if not task_id or question_text is None:
187
  print(f"Skipping item with missing task_id or question: {item}")
188
  continue
189
+
190
+ print(f"Processing question {i}/{len(questions_data)}: {task_id}")
191
+
192
  try:
193
  submitted_answer = agent(question_text)
194
  answers_payload.append({"task_id": task_id, "submitted_answer": submitted_answer})
195
+ results_log.append({
196
+ "Task ID": task_id,
197
+ "Question": question_text[:100] + "..." if len(question_text) > 100 else question_text,
198
+ "Submitted Answer": submitted_answer[:200] + "..." if len(submitted_answer) > 200 else submitted_answer
199
+ })
200
+ print(f"โœ… Completed question {i}: {task_id}")
201
  except Exception as e:
202
+ print(f"โŒ Error running agent on task {task_id}: {e}")
203
+ error_answer = f"AGENT ERROR: {str(e)}"
204
+ answers_payload.append({"task_id": task_id, "submitted_answer": error_answer})
205
+ results_log.append({
206
+ "Task ID": task_id,
207
+ "Question": question_text[:100] + "..." if len(question_text) > 100 else question_text,
208
+ "Submitted Answer": error_answer
209
+ })
210
 
211
  if not answers_payload:
212
  print("Agent did not produce any answers to submit.")
213
  return "Agent did not produce any answers to submit.", pd.DataFrame(results_log)
214
 
215
  # Prepare submission
216
+ submission_data = {
217
+ "username": username.strip(),
218
+ "agent_code": agent_code,
219
+ "answers": answers_payload
220
+ }
221
+
222
+ status_update = f"Agent finished processing. Submitting {len(answers_payload)} answers for user '{username}'..."
223
  print(status_update)
224
 
225
+ # Submit answers
226
  print(f"Submitting {len(answers_payload)} answers to: {submit_url}")
227
  try:
228
  response = requests.post(submit_url, json=submission_data, timeout=60)
229
  response.raise_for_status()
230
  result_data = response.json()
231
+
232
  final_status = (
233
+ f"๐ŸŽ‰ Submission Successful!\n\n"
234
  f"User: {result_data.get('username')}\n"
235
  f"Overall Score: {result_data.get('score', 'N/A')}% "
236
  f"({result_data.get('correct_count', '?')}/{result_data.get('total_attempted', '?')} correct)\n"
237
  f"Message: {result_data.get('message', 'No message received.')}"
238
  )
239
+ print("โœ… Submission successful!")
240
  results_df = pd.DataFrame(results_log)
241
  return final_status, results_df
242
+
243
  except requests.exceptions.HTTPError as e:
244
  error_detail = f"Server responded with status {e.response.status_code}."
245
  try:
 
247
  error_detail += f" Detail: {error_json.get('detail', e.response.text)}"
248
  except requests.exceptions.JSONDecodeError:
249
  error_detail += f" Response: {e.response.text[:500]}"
250
+ status_message = f"โŒ Submission Failed: {error_detail}"
251
  print(status_message)
252
  results_df = pd.DataFrame(results_log)
253
  return status_message, results_df
254
+
255
  except requests.exceptions.Timeout:
256
+ status_message = "โŒ Submission Failed: The request timed out."
257
  print(status_message)
258
  results_df = pd.DataFrame(results_log)
259
  return status_message, results_df
260
+
261
  except requests.exceptions.RequestException as e:
262
+ status_message = f"โŒ Submission Failed: Network error - {e}"
263
  print(status_message)
264
  results_df = pd.DataFrame(results_log)
265
  return status_message, results_df
266
+
267
  except Exception as e:
268
+ status_message = f"โŒ An unexpected error occurred during submission: {e}"
269
  print(status_message)
270
  results_df = pd.DataFrame(results_log)
271
  return status_message, results_df
272
 
273
 
274
  # --- Gradio UI ---
275
+ with gr.Blocks(title="Local LLM Agent Evaluation") as demo:
276
+ gr.Markdown("# ๐Ÿค– Local LLM Agent Evaluation Runner")
277
  gr.Markdown(
278
  """
279
  **Instructions:**
280
+ 1. ๐Ÿ” Log in to your Hugging Face account using the button below
281
+ 2. ๐Ÿš€ Click 'Run Evaluation & Submit All Answers'
282
+ 3. โณ Wait for the local LLM (Zephyr-7B) to process all questions
283
+ 4. ๐Ÿ“Š View your results and submission status
284
+
285
+ **Features:**
286
+ - ๐Ÿ” Real web search using DuckDuckGo
287
+ - ๐Ÿงฎ Advanced math calculations with SymPy
288
+ - ๐Ÿง  Powered by HuggingFace Zephyr-7B model
289
  """
290
  )
291
 
292
+ with gr.Row():
293
+ gr.LoginButton()
294
+
295
+ with gr.Row():
296
+ run_button = gr.Button(
297
+ "๐Ÿš€ Run Evaluation & Submit All Answers",
298
+ variant="primary",
299
+ size="lg"
300
+ )
301
+
302
+ status_output = gr.Textbox(
303
+ label="๐Ÿ“‹ Run Status / Submission Result",
304
+ lines=8,
305
+ interactive=False,
306
+ placeholder="Click the button above to start the evaluation..."
307
+ )
308
+
309
+ results_table = gr.DataFrame(
310
+ label="๐Ÿ“Š Questions and Agent Answers",
311
+ wrap=True,
312
+ interactive=False
313
+ )
314
 
315
+ # Wire up the button
316
  run_button.click(
317
  fn=run_and_submit_all,
318
  outputs=[status_output, results_table]
 
320
 
321
 
322
  if __name__ == "__main__":
323
+ print("\n" + "="*60)
324
+ print("๐Ÿš€ Application Startup at", pd.Timestamp.now().strftime("%Y-%m-%d %H:%M:%S"))
325
+ print("="*60)
326
+
327
  space_host_startup = os.getenv("SPACE_HOST")
328
  space_id_startup = os.getenv("SPACE_ID")
329
 
330
  if space_host_startup:
331
  print(f"โœ… SPACE_HOST found: {space_host_startup}")
332
+ print(f" Runtime URL should be: https://{space_host_startup}")
333
+ else:
334
+ print("โ„น๏ธ SPACE_HOST environment variable not found (running locally?).")
335
+
336
+ if space_id_startup:
337
  print(f"โœ… SPACE_ID found: {space_id_startup}")
338
+ print(f" Repo URL: https://huggingface.co/spaces/{space_id_startup}")
339
+ print(f" Repo Tree URL: https://huggingface.co/spaces/{space_id_startup}/tree/main")
340
  else:
341
+ print("โ„น๏ธ SPACE_ID environment variable not found (running locally?).")
342
 
343
+ print("-" * 60)
344
+ print("๐ŸŽฏ Launching Gradio Interface for Local LLM Agent Evaluation...")
345
+
346
+ # Launch without share=True for Hugging Face Spaces
347
+ demo.launch(
348
+ server_name="0.0.0.0",
349
+ server_port=7860,
350
+ show_error=True
351
+ )
requirements.txt CHANGED
@@ -3,9 +3,11 @@ llama-index-llms-huggingface
3
  transformers>=4.30.0
4
  torch>=2.0.0
5
  accelerate
6
- gradio>=3.30
7
  requests
8
  pandas
9
  python-dotenv
10
- duckduckgo_search
11
  sympy
 
 
 
3
  transformers>=4.30.0
4
  torch>=2.0.0
5
  accelerate
6
+ gradio>=4.0.0
7
  requests
8
  pandas
9
  python-dotenv
10
+ duckduckgo-search
11
  sympy
12
+ sentencepiece
13
+ protobuf