DB Chat for pro users only
Browse files- python_code_executor_service.py +52 -53
python_code_executor_service.py
CHANGED
@@ -32,7 +32,6 @@ class ChartSpecification(BaseModel):
|
|
32 |
"""Details about requested charts"""
|
33 |
image_description: str
|
34 |
code: Optional[str] = None
|
35 |
-
media_pointer: Optional[str] = None # Added media pointer field
|
36 |
|
37 |
|
38 |
class AnalysisOperation(BaseModel):
|
@@ -188,62 +187,62 @@ class PythonExecutor:
|
|
188 |
def _format_result(self, result: Any) -> str:
|
189 |
"""Format the result for display"""
|
190 |
if isinstance(result, (pd.DataFrame, pd.Series)):
|
191 |
-
|
|
|
|
|
192 |
elif isinstance(result, (dict, list)):
|
193 |
return json.dumps(result, indent=2)
|
194 |
return str(result)
|
195 |
|
196 |
async def process_response(self, response: CsvChatResult, chat_id: str) -> str:
|
197 |
-
|
198 |
-
|
199 |
-
|
200 |
-
|
201 |
-
|
202 |
-
|
203 |
-
result = self.exec_locals.get(operation.result_var)
|
204 |
-
|
205 |
-
if execution_result['error']:
|
206 |
-
output_parts.append(f"\nError in operation '{operation.result_var}':")
|
207 |
-
output_parts.append("```python\n" + execution_result['error']['message'] + "\n```")
|
208 |
-
elif result is not None:
|
209 |
-
if result is None or (hasattr(result, '__len__') and len(result) == 0):
|
210 |
-
output_parts.append(f"\nNo data - Operation '{operation.result_var}' returned empty results")
|
211 |
-
else:
|
212 |
-
output_parts.append(f"\nResult for '{operation.result_var}':")
|
213 |
-
output_parts.append("```python\n" + self._format_result(result) + "\n```")
|
214 |
-
else:
|
215 |
-
output_parts.append(f"\nOperation '{operation.result_var}' output:")
|
216 |
-
if execution_result['output'].strip():
|
217 |
-
output_parts.append("```\n" + execution_result['output'].strip() + "\n```")
|
218 |
-
else:
|
219 |
-
output_parts.append("No output - Operation didn't produce any results")
|
220 |
|
221 |
-
|
222 |
-
|
223 |
-
output_parts.append("\nVisualizations:")
|
224 |
-
for chart in response.charts:
|
225 |
-
# Skip processing if media pointer indicates blank chart
|
226 |
-
if chart.media_pointer and "blank" in chart.media_pointer.lower():
|
227 |
-
output_parts.append(f"\nSkipped blank chart: {chart.image_description}")
|
228 |
-
continue
|
229 |
-
|
230 |
-
if chart.code:
|
231 |
-
chart_result = self.execute_code(chart.code)
|
232 |
-
if chart_result['plots']:
|
233 |
-
for plot_data in chart_result['plots']:
|
234 |
-
try:
|
235 |
-
public_url = await self.save_plot_to_supabase(
|
236 |
-
plot_data=plot_data,
|
237 |
-
description=chart.image_description,
|
238 |
-
chat_id=chat_id
|
239 |
-
)
|
240 |
-
output_parts.append(f"\n{chart.image_description}")
|
241 |
-
output_parts.append(f"")
|
242 |
-
except Exception as e:
|
243 |
-
output_parts.append(f"\nChart error - Couldn't upload: {str(e)}")
|
244 |
-
elif chart_result['error']:
|
245 |
-
output_parts.append("```python\n" + f"Chart error: {chart_result['error']['message']}" + "\n```")
|
246 |
-
else:
|
247 |
-
output_parts.append(f"\nNo chart - '{chart.image_description}' couldn't be generated")
|
248 |
|
249 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
32 |
"""Details about requested charts"""
|
33 |
image_description: str
|
34 |
code: Optional[str] = None
|
|
|
35 |
|
36 |
|
37 |
class AnalysisOperation(BaseModel):
|
|
|
187 |
def _format_result(self, result: Any) -> str:
|
188 |
"""Format the result for display"""
|
189 |
if isinstance(result, (pd.DataFrame, pd.Series)):
|
190 |
+
# Convert DataFrame to a string, then to a list of dicts (handles NumPy types)
|
191 |
+
json_str = result.to_json(orient='records', date_format='iso')
|
192 |
+
json.dumps(json.loads(json_str), indent=2) # Re-parse for pretty formatting
|
193 |
elif isinstance(result, (dict, list)):
|
194 |
return json.dumps(result, indent=2)
|
195 |
return str(result)
|
196 |
|
197 |
async def process_response(self, response: CsvChatResult, chat_id: str) -> str:
|
198 |
+
"""Process the response with proper variable handling"""
|
199 |
+
output_parts = [response.casual_response]
|
200 |
+
|
201 |
+
# Process analysis operations first
|
202 |
+
for operation in response.analysis_operations:
|
203 |
+
execution_result = self.execute_code(operation.code.code)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
204 |
|
205 |
+
# Get the result from locals
|
206 |
+
result = self.exec_locals.get(operation.result_var)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
207 |
|
208 |
+
if execution_result['error']:
|
209 |
+
output_parts.append(f"\n❌ Error in operation '{operation.result_var}':")
|
210 |
+
output_parts.append("```python\n" + execution_result['error']['message'] + "\n```")
|
211 |
+
elif result is not None:
|
212 |
+
# Handle empty/None results
|
213 |
+
if result is None or (hasattr(result, '__len__') and len(result) == 0):
|
214 |
+
output_parts.append(f"\n⚠️ Values are missing - Operation '{operation.result_var}' returned no data")
|
215 |
+
else:
|
216 |
+
output_parts.append(f"\n🔹 Result for '{operation.result_var}':")
|
217 |
+
output_parts.append("```python\n" + self._format_result(result) + "\n```")
|
218 |
+
else:
|
219 |
+
output_str = execution_result['output'].strip()
|
220 |
+
if output_str:
|
221 |
+
output_parts.append(f"\nOutput for '{operation.result_var}':")
|
222 |
+
output_parts.append("```\n" + output_str + "\n```")
|
223 |
+
|
224 |
+
|
225 |
+
# Process charts after all operations
|
226 |
+
if response.charts:
|
227 |
+
output_parts.append("\n📊 Visualizations:")
|
228 |
+
for chart in response.charts:
|
229 |
+
if chart.code:
|
230 |
+
chart_result = self.execute_code(chart.code)
|
231 |
+
if chart_result['plots']:
|
232 |
+
for plot_data in chart_result['plots']:
|
233 |
+
try:
|
234 |
+
public_url = await self.save_plot_to_supabase(
|
235 |
+
plot_data=plot_data,
|
236 |
+
description=chart.image_description,
|
237 |
+
chat_id=chat_id
|
238 |
+
)
|
239 |
+
output_parts.append(f"\n🖼️ {chart.image_description}")
|
240 |
+
output_parts.append(f"")
|
241 |
+
except Exception as e:
|
242 |
+
output_parts.append(f"\n⚠️ Values are missing - Error uploading chart: {str(e)}")
|
243 |
+
elif chart_result['error']:
|
244 |
+
output_parts.append("```python\n" + f"Error generating {chart.image_description}: {chart_result['error']['message']}" + "\n```")
|
245 |
+
else:
|
246 |
+
output_parts.append(f"\n⚠️ Values are missing - No chart generated for '{chart.image_description}'")
|
247 |
+
|
248 |
+
return "\n".join(output_parts)
|