carolinacon commited on
Commit
86368de
·
1 Parent(s): 901b248

cached answers

Browse files
Files changed (3) hide show
  1. app.py +46 -31
  2. tools/python_executor.py +1 -1
  3. utils/cache_answers.py +74 -0
app.py CHANGED
@@ -1,34 +1,39 @@
1
  import os
2
- import gradio as gr
3
- import requests
4
- import pandas as pd
5
  from pathlib import Path
 
6
 
 
 
 
7
 
8
  from core.agent import GaiaAgent, Attachment
 
9
  from utils.dependencies_checker import check_dependencies
10
 
11
  # (Keep Constants as is)
12
  # --- Constants ---
13
  DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
14
 
 
15
  # --- Basic Agent Definition ---
16
- # ----- THIS IS WERE YOU CAN BUILD WHAT YOU WANT ------
17
  class BasicAgent:
18
  agent: GaiaAgent
 
19
  def __init__(self):
20
  self.agent = GaiaAgent()
21
- def __call__(self, question: str, attached_content: bytes|None, attached_file_name: str|None ) -> str:
 
22
  print(f"Agent received question (first 50 chars): {question[:50]}...")
23
- attachment = None
24
- if attached_content:
25
- attachment =Attachment(attached_content, attached_file_name)
26
  answer = self.agent.__call__(question, attachment)
27
  print(f"Agent returning fixed answer: {answer}")
28
  return answer
29
 
30
 
31
- def get_question_attached_file(task_id, file_name) -> bytes:
32
  api_url = DEFAULT_API_URL
33
  attachment_url = f"{api_url}/files/{task_id}"
34
 
@@ -41,7 +46,7 @@ def get_question_attached_file(task_id, file_name) -> bytes:
41
  print(f"Retrieved {file_name} attachment from: {attachment_url}")
42
 
43
  # Save to disk
44
- file_path = Path(f"attachments\{task_id}\{file_name}")
45
  content = response.content
46
 
47
  # Create parent directories if they don't exist
@@ -50,24 +55,22 @@ def get_question_attached_file(task_id, file_name) -> bytes:
50
  # Write the file
51
  file_path.write_bytes(content)
52
 
53
- return content
54
 
55
  except Exception as e:
56
  print(f"An unexpected error occurred fetching attachment for taskid{task_id}: {e}")
57
 
58
 
59
-
60
-
61
- def run_and_submit_all( profile: gr.OAuthProfile | None):
62
  """
63
  Fetches all questions, runs the BasicAgent on them, submits all answers,
64
  and displays the results.
65
  """
66
  # --- Determine HF Space Runtime URL and Repo URL ---
67
- space_id = os.getenv("SPACE_ID") # Get the SPACE_ID for sending link to the code
68
 
69
  if profile:
70
- username= f"{profile.username}"
71
  print(f"User logged in: {username}")
72
  else:
73
  print("User not logged in.")
@@ -94,16 +97,16 @@ def run_and_submit_all( profile: gr.OAuthProfile | None):
94
  response.raise_for_status()
95
  questions_data = response.json()
96
  if not questions_data:
97
- print("Fetched questions list is empty.")
98
- return "Fetched questions list is empty or invalid format.", None
99
  print(f"Fetched {len(questions_data)} questions.")
100
  except requests.exceptions.RequestException as e:
101
  print(f"Error fetching questions: {e}")
102
  return f"Error fetching questions: {e}", None
103
  except requests.exceptions.JSONDecodeError as e:
104
- print(f"Error decoding JSON response from questions endpoint: {e}")
105
- print(f"Response text: {response.text[:500]}")
106
- return f"Error decoding server response for questions: {e}", None
107
  except Exception as e:
108
  print(f"An unexpected error occurred fetching questions: {e}")
109
  return f"An unexpected error occurred fetching questions: {e}", None
@@ -112,22 +115,34 @@ def run_and_submit_all( profile: gr.OAuthProfile | None):
112
  results_log = []
113
  answers_payload = []
114
  print(f"Running agent on {len(questions_data)} questions...")
 
115
  for item in questions_data:
116
  task_id = item.get("task_id")
117
  question_text = item.get("question")
118
  attached_file_name = item.get("file_name")
 
119
  if attached_file_name:
120
- file_content = get_question_attached_file(task_id, attached_file_name)
121
  if not task_id or question_text is None:
122
  print(f"Skipping item with missing task_id or question: {item}")
123
  continue
 
 
 
 
 
124
  try:
125
- submitted_answer = agent(question_text, file_content)
 
 
 
 
 
126
  answers_payload.append({"task_id": task_id, "submitted_answer": submitted_answer})
127
  results_log.append({"Task ID": task_id, "Question": question_text, "Submitted Answer": submitted_answer})
128
  except Exception as e:
129
- print(f"Error running agent on task {task_id}: {e}")
130
- results_log.append({"Task ID": task_id, "Question": question_text, "Submitted Answer": f"AGENT ERROR: {e}"})
131
 
132
  if not answers_payload:
133
  print("Agent did not produce any answers to submit.")
@@ -214,10 +229,10 @@ with gr.Blocks() as demo:
214
  )
215
 
216
  if __name__ == "__main__":
217
- print("\n" + "-"*30 + " App Starting " + "-"*30)
218
  # Check for SPACE_HOST and SPACE_ID at startup for information
219
  space_host_startup = os.getenv("SPACE_HOST")
220
- space_id_startup = os.getenv("SPACE_ID") # Get SPACE_ID at startup
221
 
222
  if space_host_startup:
223
  print(f"✅ SPACE_HOST found: {space_host_startup}")
@@ -225,16 +240,16 @@ if __name__ == "__main__":
225
  else:
226
  print("ℹ️ SPACE_HOST environment variable not found (running locally?).")
227
 
228
- if space_id_startup: # Print repo URLs if SPACE_ID is found
229
  print(f"✅ SPACE_ID found: {space_id_startup}")
230
  print(f" Repo URL: https://huggingface.co/spaces/{space_id_startup}")
231
  print(f" Repo Tree URL: https://huggingface.co/spaces/{space_id_startup}/tree/main")
232
  else:
233
  print("ℹ️ SPACE_ID environment variable not found (running locally?). Repo URL cannot be determined.")
234
 
235
- print("-"*(60 + len(" App Starting ")) + "\n")
236
- print("-"*(60 + len(" Check dependencies ")) + "\n")
237
  check_dependencies()
238
 
239
  print("Launching Gradio Interface for Basic Agent Evaluation...")
240
- demo.launch(debug=True, share=False)
 
1
  import os
2
+ import time
 
 
3
  from pathlib import Path
4
+ from typing import Optional
5
 
6
+ import gradio as gr
7
+ import pandas as pd
8
+ import requests
9
 
10
  from core.agent import GaiaAgent, Attachment
11
+ from utils.cache_answers import AnswersCache
12
  from utils.dependencies_checker import check_dependencies
13
 
14
  # (Keep Constants as is)
15
  # --- Constants ---
16
  DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
17
 
18
+
19
  # --- Basic Agent Definition ---
 
20
  class BasicAgent:
21
  agent: GaiaAgent
22
+
23
  def __init__(self):
24
  self.agent = GaiaAgent()
25
+
26
+ def __call__(self, question: str, attachment: Optional[Attachment] = None) -> str:
27
  print(f"Agent received question (first 50 chars): {question[:50]}...")
28
+ if attachment:
29
+ print(f"Agent received an attachment : {attachment.file_path}...")
30
+
31
  answer = self.agent.__call__(question, attachment)
32
  print(f"Agent returning fixed answer: {answer}")
33
  return answer
34
 
35
 
36
+ def get_question_attached_file(task_id, file_name) -> Attachment:
37
  api_url = DEFAULT_API_URL
38
  attachment_url = f"{api_url}/files/{task_id}"
39
 
 
46
  print(f"Retrieved {file_name} attachment from: {attachment_url}")
47
 
48
  # Save to disk
49
+ file_path = Path("attachments") / f"{task_id}" / f"{file_name}"
50
  content = response.content
51
 
52
  # Create parent directories if they don't exist
 
55
  # Write the file
56
  file_path.write_bytes(content)
57
 
58
+ return Attachment(content, file_path.as_posix())
59
 
60
  except Exception as e:
61
  print(f"An unexpected error occurred fetching attachment for taskid{task_id}: {e}")
62
 
63
 
64
+ def run_and_submit_all(profile: gr.OAuthProfile | None):
 
 
65
  """
66
  Fetches all questions, runs the BasicAgent on them, submits all answers,
67
  and displays the results.
68
  """
69
  # --- Determine HF Space Runtime URL and Repo URL ---
70
+ space_id = os.getenv("SPACE_ID") # Get the SPACE_ID for sending link to the code
71
 
72
  if profile:
73
+ username = f"{profile.username}"
74
  print(f"User logged in: {username}")
75
  else:
76
  print("User not logged in.")
 
97
  response.raise_for_status()
98
  questions_data = response.json()
99
  if not questions_data:
100
+ print("Fetched questions list is empty.")
101
+ return "Fetched questions list is empty or invalid format.", None
102
  print(f"Fetched {len(questions_data)} questions.")
103
  except requests.exceptions.RequestException as e:
104
  print(f"Error fetching questions: {e}")
105
  return f"Error fetching questions: {e}", None
106
  except requests.exceptions.JSONDecodeError as e:
107
+ print(f"Error decoding JSON response from questions endpoint: {e}")
108
+ print(f"Response text: {response.text[:500]}")
109
+ return f"Error decoding server response for questions: {e}", None
110
  except Exception as e:
111
  print(f"An unexpected error occurred fetching questions: {e}")
112
  return f"An unexpected error occurred fetching questions: {e}", None
 
115
  results_log = []
116
  answers_payload = []
117
  print(f"Running agent on {len(questions_data)} questions...")
118
+ cache = AnswersCache()
119
  for item in questions_data:
120
  task_id = item.get("task_id")
121
  question_text = item.get("question")
122
  attached_file_name = item.get("file_name")
123
+ attachment = None
124
  if attached_file_name:
125
+ attachment = get_question_attached_file(task_id, attached_file_name)
126
  if not task_id or question_text is None:
127
  print(f"Skipping item with missing task_id or question: {item}")
128
  continue
129
+
130
+ if task_id in ["a1e91b78-d3d8-4675-bb8d-62741b4b68a6"]:
131
+ print(f"Skipping question. Not handled for the moment: {item}")
132
+ cache.set(task_id, "NAN")
133
+ continue
134
  try:
135
+ # check if the answer is cached, if not invoke the agent
136
+ submitted_answer = cache.get(task_id)
137
+ if submitted_answer is None:
138
+ submitted_answer = agent(question_text, attachment)
139
+ time.sleep(20)
140
+ cache.set(task_id, submitted_answer)
141
  answers_payload.append({"task_id": task_id, "submitted_answer": submitted_answer})
142
  results_log.append({"Task ID": task_id, "Question": question_text, "Submitted Answer": submitted_answer})
143
  except Exception as e:
144
+ print(f"Error running agent on task {task_id}: {e}")
145
+ results_log.append({"Task ID": task_id, "Question": question_text, "Submitted Answer": f"AGENT ERROR: {e}"})
146
 
147
  if not answers_payload:
148
  print("Agent did not produce any answers to submit.")
 
229
  )
230
 
231
  if __name__ == "__main__":
232
+ print("\n" + "-" * 30 + " App Starting " + "-" * 30)
233
  # Check for SPACE_HOST and SPACE_ID at startup for information
234
  space_host_startup = os.getenv("SPACE_HOST")
235
+ space_id_startup = os.getenv("SPACE_ID") # Get SPACE_ID at startup
236
 
237
  if space_host_startup:
238
  print(f"✅ SPACE_HOST found: {space_host_startup}")
 
240
  else:
241
  print("ℹ️ SPACE_HOST environment variable not found (running locally?).")
242
 
243
+ if space_id_startup: # Print repo URLs if SPACE_ID is found
244
  print(f"✅ SPACE_ID found: {space_id_startup}")
245
  print(f" Repo URL: https://huggingface.co/spaces/{space_id_startup}")
246
  print(f" Repo Tree URL: https://huggingface.co/spaces/{space_id_startup}/tree/main")
247
  else:
248
  print("ℹ️ SPACE_ID environment variable not found (running locally?). Repo URL cannot be determined.")
249
 
250
+ print("-" * (60 + len(" App Starting ")) + "\n")
251
+ print("-" * (60 + len(" Check dependencies ")) + "\n")
252
  check_dependencies()
253
 
254
  print("Launching Gradio Interface for Basic Agent Evaluation...")
255
+ demo.launch(debug=True, share=False)
tools/python_executor.py CHANGED
@@ -39,7 +39,7 @@ def subprocess_python_exec(file_reference: str) -> str:
39
  [sys.executable, file_reference],
40
  capture_output=True,
41
  text=True,
42
- timeout=60
43
  )
44
 
45
  if result.returncode == 0:
 
39
  [sys.executable, file_reference],
40
  capture_output=True,
41
  text=True,
42
+ timeout=90
43
  )
44
 
45
  if result.returncode == 0:
utils/cache_answers.py ADDED
@@ -0,0 +1,74 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json
2
+ import os
3
+ import time
4
+ from typing import Optional, Dict, Any
5
+
6
+
7
+ class AnswersCache:
8
+ def __init__(self, filename: str = "cache.json", max_size: int = 1000):
9
+ self.filename = filename
10
+ self.max_size = max_size
11
+ self.cache: Dict[str, Dict[str, Any]] = {}
12
+ self._load_cache()
13
+
14
+ def _load_cache(self):
15
+ """Load cache from file if it exists"""
16
+ if os.path.exists(self.filename):
17
+ try:
18
+ with open(self.filename, 'r') as f:
19
+ self.cache = json.load(f)
20
+ except (json.JSONDecodeError, FileNotFoundError):
21
+ self.cache = {}
22
+
23
+ def _save_cache(self):
24
+ """Save cache to file"""
25
+ with open(self.filename, 'w') as f:
26
+ json.dump(self.cache, f, indent=2)
27
+
28
+ def set(self, key: str, value: str, ttl: Optional[int] = None):
29
+ """Set a key-value pair with optional TTL (time to live in seconds)"""
30
+ if len(self.cache) >= self.max_size:
31
+ self._evict_oldest()
32
+
33
+ cache_entry = {
34
+ 'value': value,
35
+ 'created_at': time.time(),
36
+ 'ttl': ttl
37
+ }
38
+ self.cache[key] = cache_entry
39
+ self._save_cache()
40
+
41
+ def get(self, key: str) -> Optional[str]:
42
+ """Get value for key, returns None if not found or expired"""
43
+ if key not in self.cache:
44
+ return None
45
+
46
+ entry = self.cache[key]
47
+
48
+ # Check if entry has expired
49
+ if entry['ttl'] is not None:
50
+ if time.time() - entry['created_at'] > entry['ttl']:
51
+ self.delete(key)
52
+ return None
53
+
54
+ return entry['value']
55
+
56
+ def delete(self, key: str):
57
+ """Delete a key from cache"""
58
+ if key in self.cache:
59
+ del self.cache[key]
60
+ self._save_cache()
61
+
62
+ def clear(self):
63
+ """Clear all cache entries"""
64
+ self.cache = {}
65
+ self._save_cache()
66
+
67
+ def _evict_oldest(self):
68
+ """Remove the oldest entry when cache is full"""
69
+ if not self.cache:
70
+ return
71
+
72
+ oldest_key = min(self.cache.keys(),
73
+ key=lambda k: self.cache[k]['created_at'])
74
+ del self.cache[oldest_key]