Bhumi14 commited on
Commit
6d83415
Β·
verified Β·
1 Parent(s): c84e21f

Update logic.py

Browse files
Files changed (1) hide show
  1. logic.py +209 -206
logic.py CHANGED
@@ -1,207 +1,210 @@
1
- from typing import Dict, List, Tuple
2
- import re
3
- import tempfile
4
- from pathlib import Path
5
- import pandas as pd
6
- import requests
7
- from agent import GaiaAgent
8
- from pandas import DataFrame
9
-
10
- # --- Constants ---
11
- DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
12
- QUESTIONS_URL = f"{DEFAULT_API_URL}/questions"
13
- SUBMIT_URL = f"{DEFAULT_API_URL}/submit"
14
- FILE_PATH = f"{DEFAULT_API_URL}/files/"
15
-
16
-
17
- # --- Helper Methods ---
18
- def fetch_all_questions() -> Dict:
19
- """Fetches all questions from the specified API endpoint.
20
-
21
- This function retrieves a list of questions from the API, handles potential errors
22
- such as network issues, invalid responses, or empty question lists, and returns
23
- the questions as a dictionary.
24
-
25
- Returns:
26
- Dict: A dictionary containing the questions data retrieved from the API.
27
-
28
- Raises:
29
- UserWarning: If there is an error fetching the questions, such as network issues,
30
- invalid JSON response, or an empty question list. The exception message
31
- provides details about the specific error encountered.
32
- """
33
- print(f"Fetching questions from: {QUESTIONS_URL}")
34
- response = requests.get(QUESTIONS_URL, timeout=15)
35
- try:
36
- response.raise_for_status()
37
- questions_data = response.json()
38
- if not questions_data:
39
- print("Fetched questions list is empty.")
40
- raise UserWarning("Fetched questions list is empty or invalid format.")
41
- print(f"Fetched {len(questions_data)} questions.")
42
- return questions_data
43
- except requests.exceptions.RequestException as e:
44
- print(f"Error fetching questions: {e}")
45
- raise UserWarning(f"Error fetching questions: {e}")
46
- except requests.exceptions.JSONDecodeError as e:
47
- print(f"Error decoding JSON response from questions endpoint: {e}")
48
- print(f"Response text: {response.text[:500]}")
49
- raise UserWarning(f"Error decoding server response for questions: {e}")
50
- except Exception as e:
51
- print(f"An unexpected error occurred fetching questions: {e}")
52
- raise UserWarning(f"An unexpected error occurred fetching questions: {e}")
53
-
54
-
55
- def submit_answers(submission_data: dict, results_log: list) -> Tuple[str, DataFrame]:
56
- """Submits answers to the scoring API and returns the submission status and results.
57
-
58
- This function sends the provided answers to the scoring API, handles potential errors
59
- such as network issues, server errors, or invalid responses, and returns a status
60
- message indicating the success or failure of the submission, along with a DataFrame
61
- containing the results log.
62
-
63
- Args:
64
- submission_data (dict): A dictionary containing the answers to be submitted.
65
- Expected to have a structure compatible with the scoring API.
66
- results_log (list): A list of dictionaries containing the results log.
67
- This log is converted to a Pandas DataFrame and returned.
68
-
69
- Returns:
70
- Tuple[str, DataFrame]: A tuple containing:
71
- - A status message (str) indicating the submission status and any relevant
72
- information or error messages.
73
- - A Pandas DataFrame containing the results log.
74
-
75
- """
76
- try:
77
- response = requests.post(SUBMIT_URL, json=submission_data, timeout=60)
78
- response.raise_for_status()
79
- result_data = response.json()
80
- final_status = (
81
- f"Submission Successful!\n"
82
- f"User: {result_data.get('username')}\n"
83
- f"Overall Score: {result_data.get('score', 'N/A')}% "
84
- f"({result_data.get('correct_count', '?')}/"
85
- f"{result_data.get('total_attempted', '?')} correct)\n"
86
- f"Message: {result_data.get('message', 'No message received.')}"
87
- )
88
- print("Submission successful.")
89
- results_df = pd.DataFrame(results_log)
90
- return final_status, results_df
91
- except requests.exceptions.HTTPError as e:
92
- error_detail = f"Server responded with status {e.response.status_code}."
93
- try:
94
- error_json = e.response.json()
95
- error_detail += f" Detail: {error_json.get('detail', e.response.text)}"
96
- except requests.exceptions.JSONDecodeError:
97
- error_detail += f" Response: {e.response.text[:500]}"
98
- status_message = f"Submission Failed: {error_detail}"
99
- print(status_message)
100
- results_df = pd.DataFrame(results_log)
101
- return status_message, results_df
102
- except requests.exceptions.Timeout:
103
- status_message = "Submission Failed: The request timed out."
104
- print(status_message)
105
- results_df = pd.DataFrame(results_log)
106
- return status_message, results_df
107
- except requests.exceptions.RequestException as e:
108
- status_message = f"Submission Failed: Network error - {e}"
109
- print(status_message)
110
- results_df = pd.DataFrame(results_log)
111
- return status_message, results_df
112
- except Exception as e:
113
- status_message = f"An unexpected error occurred during submission: {e}"
114
- print(status_message)
115
- results_df = pd.DataFrame(results_log)
116
- return status_message, results_df
117
-
118
-
119
- def run_agent(
120
- gaia_agent: GaiaAgent, questions_data: List[Dict]
121
- ) -> Tuple[List[Dict], List[Dict]]:
122
- """Runs the agent on a list of questions and returns the results and answers.
123
-
124
- This function iterates through a list of questions, runs the provided agent on each
125
- question, and collects the results and answers. It handles potential errors during
126
- agent execution and returns the results log and the answers payload.
127
-
128
- Args:
129
- gaia_agent (GaiaAgent): An instance of the GaiaAgent class, which is responsible for
130
- generating answers to the questions.
131
- questions_data (List[Dict]): A list of dictionaries, where each dictionary
132
- represents a question and contains at least the 'task_id' and 'question' keys.
133
-
134
- Returns:
135
- Tuple[List[Dict], List[Dict]]: A tuple containing:
136
- - A list of dictionaries representing the results log, where each dictionary
137
- contains the 'Task ID', 'Question', and 'Submitted Answer'.
138
- - A list of dictionaries representing the answers payload, where each dictionary
139
- contains the 'task_id' and 'submitted_answer'.
140
- """
141
- results_log = []
142
- answers_payload = []
143
-
144
- print(f"πŸš€ Running agent on {len(questions_data)} questions...")
145
- for item in questions_data:
146
- task_id = item.get("task_id")
147
- question_text = item.get("question")
148
- question_text = process_file(task_id, question_text)
149
- if not task_id or question_text is None:
150
- print(f"⚠️ Skipping invalid item (missing task_id or question): {item}")
151
- continue
152
- try:
153
- submitted_answer = gaia_agent(task_id, question_text)
154
- answers_payload.append(
155
- {"task_id": task_id, "submitted_answer": submitted_answer}
156
- )
157
- except Exception as e:
158
- print(f"❌ Error running agent on task {task_id}: {e}")
159
- submitted_answer = f"AGENT ERROR: {e}"
160
-
161
- results_log.append(
162
- {
163
- "Task ID": task_id,
164
- "Question": question_text,
165
- "Submitted Answer": submitted_answer,
166
- }
167
- )
168
- return results_log, answers_payload
169
-
170
-
171
- def process_file(task_id: str, question_text: str) -> str:
172
- """
173
- Attempt to download a file associated with a task from the API.
174
-
175
- - If the file exists (HTTP 200), it is saved to a temp directory and the local file path is returned.
176
- - If no file is found (HTTP 404), returns None.
177
- - For all other HTTP errors, the exception is propagated to the caller.
178
- """
179
- file_url = f"{FILE_PATH}{task_id}"
180
-
181
- try:
182
- response = requests.get(file_url, timeout=30)
183
- response.raise_for_status()
184
- except requests.exceptions.RequestException as exc:
185
- print(f"Exception in download_file>> {str(exc)}")
186
- return question_text # Unable to get the file
187
-
188
- # Determine filename from 'Content-Disposition' header, fallback to task_id
189
- content_disposition = response.headers.get("content-disposition", "")
190
- filename = task_id
191
- match = re.search(r'filename="([^"]+)"', content_disposition)
192
- if match:
193
- filename = match.group(1)
194
-
195
- # Save file in a temp directory
196
- temp_storage_dir = Path(tempfile.gettempdir()) / "gaia_cached_files"
197
- temp_storage_dir.mkdir(parents=True, exist_ok=True)
198
-
199
- file_path = temp_storage_dir / filename
200
- file_path.write_bytes(response.content)
201
- return (
202
- f"{question_text}\n\n"
203
- f"---\n"
204
- f"A file was downloaded for this task and saved locally at:\n"
205
- f"{str(file_path)}\n"
206
- f"---\n\n"
 
 
 
207
  )
 
1
+ from typing import Dict, List, Tuple
2
+ import re
3
+ import tempfile
4
+ from pathlib import Path
5
+ import pandas as pd
6
+ import requests
7
+ from agent import GaiaAgent
8
+ from pandas import DataFrame
9
+
10
+ # --- Constants ---
11
+ DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
12
+ QUESTIONS_URL = f"{DEFAULT_API_URL}/questions"
13
+ SUBMIT_URL = f"{DEFAULT_API_URL}/submit"
14
+ FILE_PATH = f"{DEFAULT_API_URL}/files/"
15
+
16
+
17
+ # --- Helper Methods ---
18
+ def fetch_all_questions() -> Dict:
19
+ """Fetches all questions from the specified API endpoint.
20
+
21
+ This function retrieves a list of questions from the API, handles potential errors
22
+ such as network issues, invalid responses, or empty question lists, and returns
23
+ the questions as a dictionary.
24
+
25
+ Returns:
26
+ Dict: A dictionary containing the questions data retrieved from the API.
27
+
28
+ Raises:
29
+ UserWarning: If there is an error fetching the questions, such as network issues,
30
+ invalid JSON response, or an empty question list. The exception message
31
+ provides details about the specific error encountered.
32
+ """
33
+ print(f"Fetching questions from: {QUESTIONS_URL}")
34
+ response = requests.get(QUESTIONS_URL, timeout=15)
35
+ try:
36
+ response.raise_for_status()
37
+ questions_data = response.json()
38
+ if not questions_data:
39
+ print("Fetched questions list is empty.")
40
+ raise UserWarning("Fetched questions list is empty or invalid format.")
41
+ print(f"Fetched {len(questions_data)} questions.")
42
+ return questions_data
43
+ except requests.exceptions.RequestException as e:
44
+ print(f"Error fetching questions: {e}")
45
+ raise UserWarning(f"Error fetching questions: {e}")
46
+ except requests.exceptions.JSONDecodeError as e:
47
+ print(f"Error decoding JSON response from questions endpoint: {e}")
48
+ print(f"Response text: {response.text[:500]}")
49
+ raise UserWarning(f"Error decoding server response for questions: {e}")
50
+ except Exception as e:
51
+ print(f"An unexpected error occurred fetching questions: {e}")
52
+ raise UserWarning(f"An unexpected error occurred fetching questions: {e}")
53
+
54
+
55
+ def submit_answers(submission_data: dict, results_log: list) -> Tuple[str, DataFrame]:
56
+ """Submits answers to the scoring API and returns the submission status and results.
57
+
58
+ This function sends the provided answers to the scoring API, handles potential errors
59
+ such as network issues, server errors, or invalid responses, and returns a status
60
+ message indicating the success or failure of the submission, along with a DataFrame
61
+ containing the results log.
62
+
63
+ Args:
64
+ submission_data (dict): A dictionary containing the answers to be submitted.
65
+ Expected to have a structure compatible with the scoring API.
66
+ results_log (list): A list of dictionaries containing the results log.
67
+ This log is converted to a Pandas DataFrame and returned.
68
+
69
+ Returns:
70
+ Tuple[str, DataFrame]: A tuple containing:
71
+ - A status message (str) indicating the submission status and any relevant
72
+ information or error messages.
73
+ - A Pandas DataFrame containing the results log.
74
+
75
+ """
76
+ try:
77
+ response = requests.post(SUBMIT_URL, json=submission_data, timeout=60)
78
+ response.raise_for_status()
79
+ result_data = response.json()
80
+ final_status = (
81
+ f"Submission Successful!\n"
82
+ f"User: {result_data.get('username')}\n"
83
+ f"Overall Score: {result_data.get('score', 'N/A')}% "
84
+ f"({result_data.get('correct_count', '?')}/"
85
+ f"{result_data.get('total_attempted', '?')} correct)\n"
86
+ f"Message: {result_data.get('message', 'No message received.')}"
87
+ )
88
+ print("Submission successful.")
89
+ results_df = pd.DataFrame(results_log)
90
+ return final_status, results_df
91
+ except requests.exceptions.HTTPError as e:
92
+ error_detail = f"Server responded with status {e.response.status_code}."
93
+ try:
94
+ error_json = e.response.json()
95
+ error_detail += f" Detail: {error_json.get('detail', e.response.text)}"
96
+ except requests.exceptions.JSONDecodeError:
97
+ error_detail += f" Response: {e.response.text[:500]}"
98
+ status_message = f"Submission Failed: {error_detail}"
99
+ print(status_message)
100
+ results_df = pd.DataFrame(results_log)
101
+ return status_message, results_df
102
+ except requests.exceptions.Timeout:
103
+ status_message = "Submission Failed: The request timed out."
104
+ print(status_message)
105
+ results_df = pd.DataFrame(results_log)
106
+ return status_message, results_df
107
+ except requests.exceptions.RequestException as e:
108
+ status_message = f"Submission Failed: Network error - {e}"
109
+ print(status_message)
110
+ results_df = pd.DataFrame(results_log)
111
+ return status_message, results_df
112
+ except Exception as e:
113
+ status_message = f"An unexpected error occurred during submission: {e}"
114
+ print(status_message)
115
+ results_df = pd.DataFrame(results_log)
116
+ return status_message, results_df
117
+
118
+
119
+ def run_agent(
120
+ gaia_agent: GaiaAgent, questions_data: List[Dict]
121
+ ) -> Tuple[List[Dict], List[Dict]]:
122
+ """Runs the agent on a list of questions and returns the results and answers.
123
+
124
+ This function iterates through a list of questions, runs the provided agent on each
125
+ question, and collects the results and answers. It handles potential errors during
126
+ agent execution and returns the results log and the answers payload.
127
+
128
+ Args:
129
+ gaia_agent (GaiaAgent): An instance of the GaiaAgent class, which is responsible for
130
+ generating answers to the questions.
131
+ questions_data (List[Dict]): A list of dictionaries, where each dictionary
132
+ represents a question and contains at least the 'task_id' and 'question' keys.
133
+
134
+ Returns:
135
+ Tuple[List[Dict], List[Dict]]: A tuple containing:
136
+ - A list of dictionaries representing the results log, where each dictionary
137
+ contains the 'Task ID', 'Question', and 'Submitted Answer'.
138
+ - A list of dictionaries representing the answers payload, where each dictionary
139
+ contains the 'task_id' and 'submitted_answer'.
140
+ """
141
+ results_log = []
142
+ answers_payload = []
143
+
144
+ print(f"πŸš€ Running agent on {len(questions_data)} questions...")
145
+ for item in questions_data:
146
+ task_id = item.get("task_id")
147
+ question_text = item.get("question")
148
+ question_text = process_file(task_id, question_text)
149
+ if not task_id or question_text is None:
150
+ print(f"⚠️ Skipping invalid item (missing task_id or question): {item}")
151
+ continue
152
+ try:
153
+ submitted_answer = gaia_agent(task_id, question_text)
154
+ answers_payload.append(
155
+ {"task_id": task_id, "submitted_answer": submitted_answer}
156
+ )
157
+ except Exception as e:
158
+ print(f"❌ Error running agent on task {task_id}: {e}")
159
+ submitted_answer = f"AGENT ERROR: {e}"
160
+
161
+ results_log.append(
162
+ {
163
+ "Task ID": task_id,
164
+ "Question": question_text,
165
+ "Submitted Answer": submitted_answer,
166
+ }
167
+ )
168
+ # βœ… Add safe delay
169
+ if idx < len(questions_data):
170
+ time.sleep(3)
171
+ return results_log, answers_payload
172
+
173
+
174
+ def process_file(task_id: str, question_text: str) -> str:
175
+ """
176
+ Attempt to download a file associated with a task from the API.
177
+
178
+ - If the file exists (HTTP 200), it is saved to a temp directory and the local file path is returned.
179
+ - If no file is found (HTTP 404), returns None.
180
+ - For all other HTTP errors, the exception is propagated to the caller.
181
+ """
182
+ file_url = f"{FILE_PATH}{task_id}"
183
+
184
+ try:
185
+ response = requests.get(file_url, timeout=30)
186
+ response.raise_for_status()
187
+ except requests.exceptions.RequestException as exc:
188
+ print(f"Exception in download_file>> {str(exc)}")
189
+ return question_text # Unable to get the file
190
+
191
+ # Determine filename from 'Content-Disposition' header, fallback to task_id
192
+ content_disposition = response.headers.get("content-disposition", "")
193
+ filename = task_id
194
+ match = re.search(r'filename="([^"]+)"', content_disposition)
195
+ if match:
196
+ filename = match.group(1)
197
+
198
+ # Save file in a temp directory
199
+ temp_storage_dir = Path(tempfile.gettempdir()) / "gaia_cached_files"
200
+ temp_storage_dir.mkdir(parents=True, exist_ok=True)
201
+
202
+ file_path = temp_storage_dir / filename
203
+ file_path.write_bytes(response.content)
204
+ return (
205
+ f"{question_text}\n\n"
206
+ f"---\n"
207
+ f"A file was downloaded for this task and saved locally at:\n"
208
+ f"{str(file_path)}\n"
209
+ f"---\n\n"
210
  )