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

Rename code_interpreter.py to logic.py

Browse files
Files changed (2) hide show
  1. code_interpreter.py +0 -281
  2. logic.py +196 -0
code_interpreter.py DELETED
@@ -1,281 +0,0 @@
1
- import os
2
- import io
3
- import sys
4
- import uuid
5
- import base64
6
- import traceback
7
- import contextlib
8
- import tempfile
9
- import subprocess
10
- import sqlite3
11
- from typing import Dict, List, Any, Optional, Union
12
- import numpy as np
13
- import pandas as pd
14
- import matplotlib.pyplot as plt
15
- from PIL import Image
16
-
17
- class CodeInterpreter:
18
- def __init__(self, allowed_modules=None, max_execution_time=30, working_directory=None):
19
- """Initialize the code interpreter with safety measures."""
20
- self.allowed_modules = allowed_modules or [
21
- "numpy", "pandas", "matplotlib", "scipy", "sklearn",
22
- "math", "random", "statistics", "datetime", "collections",
23
- "itertools", "functools", "operator", "re", "json",
24
- "sympy", "networkx", "nltk", "PIL", "pytesseract",
25
- "cmath", "uuid", "tempfile", "requests", "urllib"
26
- ]
27
- self.max_execution_time = max_execution_time
28
- self.working_directory = working_directory or os.path.join(os.getcwd())
29
- if not os.path.exists(self.working_directory):
30
- os.makedirs(self.working_directory)
31
-
32
- self.globals = {
33
- "__builtins__": __builtins__,
34
- "np": np,
35
- "pd": pd,
36
- "plt": plt,
37
- "Image": Image,
38
- }
39
- self.temp_sqlite_db = os.path.join(tempfile.gettempdir(), "code_exec.db")
40
-
41
- def execute_code(self, code: str, language: str = "python") -> Dict[str, Any]:
42
- """Execute the provided code in the selected programming language."""
43
- language = language.lower()
44
- execution_id = str(uuid.uuid4())
45
-
46
- result = {
47
- "execution_id": execution_id,
48
- "status": "error",
49
- "stdout": "",
50
- "stderr": "",
51
- "result": None,
52
- "plots": [],
53
- "dataframes": []
54
- }
55
-
56
- try:
57
- if language == "python":
58
- return self._execute_python(code, execution_id)
59
- elif language == "bash":
60
- return self._execute_bash(code, execution_id)
61
- elif language == "sql":
62
- return self._execute_sql(code, execution_id)
63
- elif language == "c":
64
- return self._execute_c(code, execution_id)
65
- elif language == "java":
66
- return self._execute_java(code, execution_id)
67
- else:
68
- result["stderr"] = f"Unsupported language: {language}"
69
- except Exception as e:
70
- result["stderr"] = str(e)
71
-
72
- return result
73
-
74
- def _execute_python(self, code: str, execution_id: str) -> dict:
75
- output_buffer = io.StringIO()
76
- error_buffer = io.StringIO()
77
- result = {
78
- "execution_id": execution_id,
79
- "status": "error",
80
- "stdout": "",
81
- "stderr": "",
82
- "result": None,
83
- "plots": [],
84
- "dataframes": []
85
- }
86
-
87
- try:
88
- exec_dir = os.path.join(self.working_directory, execution_id)
89
- os.makedirs(exec_dir, exist_ok=True)
90
- plt.switch_backend('Agg')
91
-
92
- with contextlib.redirect_stdout(output_buffer), contextlib.redirect_stderr(error_buffer):
93
- exec_result = exec(code, self.globals)
94
-
95
- if plt.get_fignums():
96
- for i, fig_num in enumerate(plt.get_fignums()):
97
- fig = plt.figure(fig_num)
98
- img_path = os.path.join(exec_dir, f"plot_{i}.png")
99
- fig.savefig(img_path)
100
- with open(img_path, "rb") as img_file:
101
- img_data = base64.b64encode(img_file.read()).decode('utf-8')
102
- result["plots"].append({
103
- "figure_number": fig_num,
104
- "data": img_data
105
- })
106
-
107
- for var_name, var_value in self.globals.items():
108
- if isinstance(var_value, pd.DataFrame) and len(var_value) > 0:
109
- result["dataframes"].append({
110
- "name": var_name,
111
- "head": var_value.head().to_dict(),
112
- "shape": var_value.shape,
113
- "dtypes": str(var_value.dtypes)
114
- })
115
-
116
- result["status"] = "success"
117
- result["stdout"] = output_buffer.getvalue()
118
- result["result"] = exec_result
119
-
120
- except Exception as e:
121
- result["status"] = "error"
122
- result["stderr"] = f"{error_buffer.getvalue()}\n{traceback.format_exc()}"
123
-
124
- return result
125
-
126
- def _execute_bash(self, code: str, execution_id: str) -> dict:
127
- try:
128
- completed = subprocess.run(
129
- code, shell=True, capture_output=True, text=True, timeout=self.max_execution_time
130
- )
131
- return {
132
- "execution_id": execution_id,
133
- "status": "success" if completed.returncode == 0 else "error",
134
- "stdout": completed.stdout,
135
- "stderr": completed.stderr,
136
- "result": None,
137
- "plots": [],
138
- "dataframes": []
139
- }
140
- except subprocess.TimeoutExpired:
141
- return {
142
- "execution_id": execution_id,
143
- "status": "error",
144
- "stdout": "",
145
- "stderr": "Execution timed out.",
146
- "result": None,
147
- "plots": [],
148
- "dataframes": []
149
- }
150
-
151
- def _execute_sql(self, code: str, execution_id: str) -> dict:
152
- result = {
153
- "execution_id": execution_id,
154
- "status": "error",
155
- "stdout": "",
156
- "stderr": "",
157
- "result": None,
158
- "plots": [],
159
- "dataframes": []
160
- }
161
- try:
162
- conn = sqlite3.connect(self.temp_sqlite_db)
163
- cur = conn.cursor()
164
- cur.execute(code)
165
- if code.strip().lower().startswith("select"):
166
- columns = [description[0] for description in cur.description]
167
- rows = cur.fetchall()
168
- df = pd.DataFrame(rows, columns=columns)
169
- result["dataframes"].append({
170
- "name": "query_result",
171
- "head": df.head().to_dict(),
172
- "shape": df.shape,
173
- "dtypes": str(df.dtypes)
174
- })
175
- else:
176
- conn.commit()
177
-
178
- result["status"] = "success"
179
- result["stdout"] = "Query executed successfully."
180
-
181
- except Exception as e:
182
- result["stderr"] = str(e)
183
- finally:
184
- conn.close()
185
-
186
- return result
187
-
188
- def _execute_c(self, code: str, execution_id: str) -> dict:
189
- temp_dir = tempfile.mkdtemp()
190
- source_path = os.path.join(temp_dir, "program.c")
191
- binary_path = os.path.join(temp_dir, "program")
192
-
193
- try:
194
- with open(source_path, "w") as f:
195
- f.write(code)
196
-
197
- compile_proc = subprocess.run(
198
- ["gcc", source_path, "-o", binary_path],
199
- capture_output=True, text=True, timeout=self.max_execution_time
200
- )
201
- if compile_proc.returncode != 0:
202
- return {
203
- "execution_id": execution_id,
204
- "status": "error",
205
- "stdout": compile_proc.stdout,
206
- "stderr": compile_proc.stderr,
207
- "result": None,
208
- "plots": [],
209
- "dataframes": []
210
- }
211
-
212
- run_proc = subprocess.run(
213
- [binary_path],
214
- capture_output=True, text=True, timeout=self.max_execution_time
215
- )
216
- return {
217
- "execution_id": execution_id,
218
- "status": "success" if run_proc.returncode == 0 else "error",
219
- "stdout": run_proc.stdout,
220
- "stderr": run_proc.stderr,
221
- "result": None,
222
- "plots": [],
223
- "dataframes": []
224
- }
225
- except Exception as e:
226
- return {
227
- "execution_id": execution_id,
228
- "status": "error",
229
- "stdout": "",
230
- "stderr": str(e),
231
- "result": None,
232
- "plots": [],
233
- "dataframes": []
234
- }
235
-
236
- def _execute_java(self, code: str, execution_id: str) -> dict:
237
- temp_dir = tempfile.mkdtemp()
238
- source_path = os.path.join(temp_dir, "Main.java")
239
-
240
- try:
241
- with open(source_path, "w") as f:
242
- f.write(code)
243
-
244
- compile_proc = subprocess.run(
245
- ["javac", source_path],
246
- capture_output=True, text=True, timeout=self.max_execution_time
247
- )
248
- if compile_proc.returncode != 0:
249
- return {
250
- "execution_id": execution_id,
251
- "status": "error",
252
- "stdout": compile_proc.stdout,
253
- "stderr": compile_proc.stderr,
254
- "result": None,
255
- "plots": [],
256
- "dataframes": []
257
- }
258
-
259
- run_proc = subprocess.run(
260
- ["java", "-cp", temp_dir, "Main"],
261
- capture_output=True, text=True, timeout=self.max_execution_time
262
- )
263
- return {
264
- "execution_id": execution_id,
265
- "status": "success" if run_proc.returncode == 0 else "error",
266
- "stdout": run_proc.stdout,
267
- "stderr": run_proc.stderr,
268
- "result": None,
269
- "plots": [],
270
- "dataframes": []
271
- }
272
- except Exception as e:
273
- return {
274
- "execution_id": execution_id,
275
- "status": "error",
276
- "stdout": "",
277
- "stderr": str(e),
278
- "result": None,
279
- "plots": [],
280
- "dataframes": []
281
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
logic.py ADDED
@@ -0,0 +1,196 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ This function retrieves a list of questions from the API, handles potential errors
21
+ such as network issues, invalid responses, or empty question lists, and returns
22
+ the questions as a dictionary.
23
+ Returns:
24
+ Dict: A dictionary containing the questions data retrieved from the API.
25
+ Raises:
26
+ UserWarning: If there is an error fetching the questions, such as network issues,
27
+ invalid JSON response, or an empty question list. The exception message
28
+ provides details about the specific error encountered.
29
+ """
30
+ print(f"Fetching questions from: {QUESTIONS_URL}")
31
+ response = requests.get(QUESTIONS_URL, timeout=15)
32
+ try:
33
+ response.raise_for_status()
34
+ questions_data = response.json()
35
+ if not questions_data:
36
+ print("Fetched questions list is empty.")
37
+ raise UserWarning("Fetched questions list is empty or invalid format.")
38
+ print(f"Fetched {len(questions_data)} questions.")
39
+ return questions_data
40
+ except requests.exceptions.RequestException as e:
41
+ print(f"Error fetching questions: {e}")
42
+ raise UserWarning(f"Error fetching questions: {e}")
43
+ except requests.exceptions.JSONDecodeError as e:
44
+ print(f"Error decoding JSON response from questions endpoint: {e}")
45
+ print(f"Response text: {response.text[:500]}")
46
+ raise UserWarning(f"Error decoding server response for questions: {e}")
47
+ except Exception as e:
48
+ print(f"An unexpected error occurred fetching questions: {e}")
49
+ raise UserWarning(f"An unexpected error occurred fetching questions: {e}")
50
+
51
+
52
+ def submit_answers(submission_data: dict, results_log: list) -> Tuple[str, DataFrame]:
53
+ """Submits answers to the scoring API and returns the submission status and results.
54
+ This function sends the provided answers to the scoring API, handles potential errors
55
+ such as network issues, server errors, or invalid responses, and returns a status
56
+ message indicating the success or failure of the submission, along with a DataFrame
57
+ containing the results log.
58
+ Args:
59
+ submission_data (dict): A dictionary containing the answers to be submitted.
60
+ Expected to have a structure compatible with the scoring API.
61
+ results_log (list): A list of dictionaries containing the results log.
62
+ This log is converted to a Pandas DataFrame and returned.
63
+ Returns:
64
+ Tuple[str, DataFrame]: A tuple containing:
65
+ - A status message (str) indicating the submission status and any relevant
66
+ information or error messages.
67
+ - A Pandas DataFrame containing the results log.
68
+ """
69
+ try:
70
+ response = requests.post(SUBMIT_URL, json=submission_data, timeout=60)
71
+ response.raise_for_status()
72
+ result_data = response.json()
73
+ final_status = (
74
+ f"Submission Successful!\n"
75
+ f"User: {result_data.get('username')}\n"
76
+ f"Overall Score: {result_data.get('score', 'N/A')}% "
77
+ f"({result_data.get('correct_count', '?')}/"
78
+ f"{result_data.get('total_attempted', '?')} correct)\n"
79
+ f"Message: {result_data.get('message', 'No message received.')}"
80
+ )
81
+ print("Submission successful.")
82
+ results_df = pd.DataFrame(results_log)
83
+ return final_status, results_df
84
+ except requests.exceptions.HTTPError as e:
85
+ error_detail = f"Server responded with status {e.response.status_code}."
86
+ try:
87
+ error_json = e.response.json()
88
+ error_detail += f" Detail: {error_json.get('detail', e.response.text)}"
89
+ except requests.exceptions.JSONDecodeError:
90
+ error_detail += f" Response: {e.response.text[:500]}"
91
+ status_message = f"Submission Failed: {error_detail}"
92
+ print(status_message)
93
+ results_df = pd.DataFrame(results_log)
94
+ return status_message, results_df
95
+ except requests.exceptions.Timeout:
96
+ status_message = "Submission Failed: The request timed out."
97
+ print(status_message)
98
+ results_df = pd.DataFrame(results_log)
99
+ return status_message, results_df
100
+ except requests.exceptions.RequestException as e:
101
+ status_message = f"Submission Failed: Network error - {e}"
102
+ print(status_message)
103
+ results_df = pd.DataFrame(results_log)
104
+ return status_message, results_df
105
+ except Exception as e:
106
+ status_message = f"An unexpected error occurred during submission: {e}"
107
+ print(status_message)
108
+ results_df = pd.DataFrame(results_log)
109
+ return status_message, results_df
110
+
111
+
112
+ def run_agent(
113
+ gaia_agent: GaiaAgent, questions_data: List[Dict]
114
+ ) -> Tuple[List[Dict], List[Dict]]:
115
+ """Runs the agent on a list of questions and returns the results and answers.
116
+ This function iterates through a list of questions, runs the provided agent on each
117
+ question, and collects the results and answers. It handles potential errors during
118
+ agent execution and returns the results log and the answers payload.
119
+ Args:
120
+ gaia_agent (GaiaAgent): An instance of the GaiaAgent class, which is responsible for
121
+ generating answers to the questions.
122
+ questions_data (List[Dict]): A list of dictionaries, where each dictionary
123
+ represents a question and contains at least the 'task_id' and 'question' keys.
124
+ Returns:
125
+ Tuple[List[Dict], List[Dict]]: A tuple containing:
126
+ - A list of dictionaries representing the results log, where each dictionary
127
+ contains the 'Task ID', 'Question', and 'Submitted Answer'.
128
+ - A list of dictionaries representing the answers payload, where each dictionary
129
+ contains the 'task_id' and 'submitted_answer'.
130
+ """
131
+ results_log = []
132
+ answers_payload = []
133
+
134
+ print(f"πŸš€ Running agent on {len(questions_data)} questions...")
135
+ for item in questions_data:
136
+ task_id = item.get("task_id")
137
+ question_text = item.get("question")
138
+ question_text = process_file(task_id, question_text)
139
+ if not task_id or question_text is None:
140
+ print(f"⚠️ Skipping invalid item (missing task_id or question): {item}")
141
+ continue
142
+ try:
143
+ submitted_answer = gaia_agent(task_id, question_text)
144
+ answers_payload.append(
145
+ {"task_id": task_id, "submitted_answer": submitted_answer}
146
+ )
147
+ except Exception as e:
148
+ print(f"❌ Error running agent on task {task_id}: {e}")
149
+ submitted_answer = f"AGENT ERROR: {e}"
150
+
151
+ results_log.append(
152
+ {
153
+ "Task ID": task_id,
154
+ "Question": question_text,
155
+ "Submitted Answer": submitted_answer,
156
+ }
157
+ )
158
+ return results_log, answers_payload
159
+
160
+
161
+ def process_file(task_id: str, question_text: str) -> str:
162
+ """
163
+ Attempt to download a file associated with a task from the API.
164
+ - If the file exists (HTTP 200), it is saved to a temp directory and the local file path is returned.
165
+ - If no file is found (HTTP 404), returns None.
166
+ - For all other HTTP errors, the exception is propagated to the caller.
167
+ """
168
+ file_url = f"{FILE_PATH}{task_id}"
169
+
170
+ try:
171
+ response = requests.get(file_url, timeout=30)
172
+ response.raise_for_status()
173
+ except requests.exceptions.RequestException as exc:
174
+ print(f"Exception in download_file>> {str(exc)}")
175
+ return question_text # Unable to get the file
176
+
177
+ # Determine filename from 'Content-Disposition' header, fallback to task_id
178
+ content_disposition = response.headers.get("content-disposition", "")
179
+ filename = task_id
180
+ match = re.search(r'filename="([^"]+)"', content_disposition)
181
+ if match:
182
+ filename = match.group(1)
183
+
184
+ # Save file in a temp directory
185
+ temp_storage_dir = Path(tempfile.gettempdir()) / "gaia_cached_files"
186
+ temp_storage_dir.mkdir(parents=True, exist_ok=True)
187
+
188
+ file_path = temp_storage_dir / filename
189
+ file_path.write_bytes(response.content)
190
+ return (
191
+ f"{question_text}\n\n"
192
+ f"---\n"
193
+ f"A file was downloaded for this task and saved locally at:\n"
194
+ f"{str(file_path)}\n"
195
+ f"---\n\n"
196
+ )