changed prompt
Browse files- python_code_executor_service.py +39 -38
python_code_executor_service.py
CHANGED
|
@@ -61,7 +61,6 @@ class PythonExecutor:
|
|
| 61 |
self.df = df
|
| 62 |
self.charts_folder = Path(charts_folder)
|
| 63 |
self.charts_folder.mkdir(exist_ok=True)
|
| 64 |
-
self.exec_globals = None
|
| 65 |
|
| 66 |
def execute_code(self, code: str) -> Dict[str, Any]:
|
| 67 |
"""
|
|
@@ -76,7 +75,6 @@ class PythonExecutor:
|
|
| 76 |
output = ""
|
| 77 |
error = None
|
| 78 |
plots = []
|
| 79 |
-
locals_dict = {}
|
| 80 |
|
| 81 |
# Capture stdout
|
| 82 |
stdout = io.StringIO()
|
|
@@ -97,7 +95,7 @@ class PythonExecutor:
|
|
| 97 |
|
| 98 |
try:
|
| 99 |
# Create comprehensive execution context with data analysis libraries
|
| 100 |
-
|
| 101 |
# Core data analysis
|
| 102 |
'pd': pd,
|
| 103 |
'np': np,
|
|
@@ -125,13 +123,10 @@ class PythonExecutor:
|
|
| 125 |
|
| 126 |
# Execute code and capture output
|
| 127 |
with contextlib.redirect_stdout(stdout):
|
| 128 |
-
exec(code,
|
| 129 |
|
| 130 |
output = stdout.getvalue()
|
| 131 |
|
| 132 |
-
# Merge any local variables into globals
|
| 133 |
-
self.exec_globals.update(locals_dict)
|
| 134 |
-
|
| 135 |
except Exception as e:
|
| 136 |
error = {
|
| 137 |
"message": str(e),
|
|
@@ -144,8 +139,7 @@ class PythonExecutor:
|
|
| 144 |
return {
|
| 145 |
'output': output,
|
| 146 |
'error': error,
|
| 147 |
-
'plots': plots
|
| 148 |
-
'locals': self.exec_globals
|
| 149 |
}
|
| 150 |
|
| 151 |
async def save_plot_to_supabase(self, plot_data: bytes, description: str, chat_id: str) -> str:
|
|
@@ -195,37 +189,40 @@ class PythonExecutor:
|
|
| 195 |
'\n' in output and '=' in output # Python console output
|
| 196 |
)
|
| 197 |
|
| 198 |
-
def _format_result(self, result: Any) -> str:
|
| 199 |
-
"""Format the result for display"""
|
| 200 |
-
if isinstance(result, (pd.DataFrame, pd.Series)):
|
| 201 |
-
return str(result)
|
| 202 |
-
elif isinstance(result, (dict, list)):
|
| 203 |
-
return json.dumps(result, indent=2)
|
| 204 |
-
return str(result)
|
| 205 |
-
|
| 206 |
async def process_response(self, response: CsvChatResult, chat_id: str) -> str:
|
| 207 |
-
|
| 208 |
-
|
| 209 |
-
|
| 210 |
-
for operation in response.analysis_operations:
|
| 211 |
-
execution_result = self.execute_code(operation.code.code)
|
| 212 |
|
| 213 |
-
|
| 214 |
-
|
| 215 |
-
|
| 216 |
-
|
| 217 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 218 |
|
| 219 |
-
|
| 220 |
-
|
| 221 |
-
|
| 222 |
-
|
| 223 |
-
|
| 224 |
-
|
| 225 |
-
|
| 226 |
-
|
| 227 |
-
|
| 228 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 229 |
|
| 230 |
# Process charts
|
| 231 |
if response.charts:
|
|
@@ -248,4 +245,8 @@ class PythonExecutor:
|
|
| 248 |
elif result['error']:
|
| 249 |
output_parts.append("```python\n" + f"Error generating {chart.image_description}: {result['error']['message']}" + "\n```")
|
| 250 |
|
| 251 |
-
return "\n".join(output_parts)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 61 |
self.df = df
|
| 62 |
self.charts_folder = Path(charts_folder)
|
| 63 |
self.charts_folder.mkdir(exist_ok=True)
|
|
|
|
| 64 |
|
| 65 |
def execute_code(self, code: str) -> Dict[str, Any]:
|
| 66 |
"""
|
|
|
|
| 75 |
output = ""
|
| 76 |
error = None
|
| 77 |
plots = []
|
|
|
|
| 78 |
|
| 79 |
# Capture stdout
|
| 80 |
stdout = io.StringIO()
|
|
|
|
| 95 |
|
| 96 |
try:
|
| 97 |
# Create comprehensive execution context with data analysis libraries
|
| 98 |
+
exec_globals = {
|
| 99 |
# Core data analysis
|
| 100 |
'pd': pd,
|
| 101 |
'np': np,
|
|
|
|
| 123 |
|
| 124 |
# Execute code and capture output
|
| 125 |
with contextlib.redirect_stdout(stdout):
|
| 126 |
+
exec(code, exec_globals)
|
| 127 |
|
| 128 |
output = stdout.getvalue()
|
| 129 |
|
|
|
|
|
|
|
|
|
|
| 130 |
except Exception as e:
|
| 131 |
error = {
|
| 132 |
"message": str(e),
|
|
|
|
| 139 |
return {
|
| 140 |
'output': output,
|
| 141 |
'error': error,
|
| 142 |
+
'plots': plots
|
|
|
|
| 143 |
}
|
| 144 |
|
| 145 |
async def save_plot_to_supabase(self, plot_data: bytes, description: str, chat_id: str) -> str:
|
|
|
|
| 189 |
'\n' in output and '=' in output # Python console output
|
| 190 |
)
|
| 191 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 192 |
async def process_response(self, response: CsvChatResult, chat_id: str) -> str:
|
| 193 |
+
"""
|
| 194 |
+
Process the CsvChatResult response and generate formatted output
|
| 195 |
+
with markdown code blocks for structured data.
|
|
|
|
|
|
|
| 196 |
|
| 197 |
+
Args:
|
| 198 |
+
response (CsvChatResult): Response from CSV analysis
|
| 199 |
+
chat_id (str): ID of the chat session
|
| 200 |
+
|
| 201 |
+
Returns:
|
| 202 |
+
str: Formatted output with results and image URLs
|
| 203 |
+
"""
|
| 204 |
+
output_parts = []
|
| 205 |
+
|
| 206 |
+
# Add casual response
|
| 207 |
+
output_parts.append(response.casual_response)
|
| 208 |
|
| 209 |
+
# Process analysis operations
|
| 210 |
+
for operation in response.analysis_operations:
|
| 211 |
+
# Execute the code
|
| 212 |
+
result = self.execute_code(operation.code.code)
|
| 213 |
+
|
| 214 |
+
# Add operation description
|
| 215 |
+
output_parts.append(f"\n{operation.description}:")
|
| 216 |
+
|
| 217 |
+
# Add output or error with markdown wrapping
|
| 218 |
+
if result['error']:
|
| 219 |
+
output_parts.append("```python\n" + f"Error: {result['error']['message']}" + "\n```")
|
| 220 |
+
else:
|
| 221 |
+
output = result['output'].strip()
|
| 222 |
+
if self._looks_like_structured_data(output):
|
| 223 |
+
output_parts.append("```python\n" + output + "\n```")
|
| 224 |
+
else:
|
| 225 |
+
output_parts.append(output)
|
| 226 |
|
| 227 |
# Process charts
|
| 228 |
if response.charts:
|
|
|
|
| 245 |
elif result['error']:
|
| 246 |
output_parts.append("```python\n" + f"Error generating {chart.image_description}: {result['error']['message']}" + "\n```")
|
| 247 |
|
| 248 |
+
return "\n".join(output_parts)
|
| 249 |
+
|
| 250 |
+
|
| 251 |
+
|
| 252 |
+
|