| |
| from typing import Optional, Tuple |
| import uuid |
| import pandas as pd |
| import numpy as np |
| import matplotlib |
| import matplotlib.pyplot as plt |
| import seaborn as sns |
| import datetime as dt |
| import io |
| import contextlib |
| import os |
| import traceback |
| from dotenv import load_dotenv |
|
|
| load_dotenv() |
|
|
| |
| matplotlib.use('Agg') |
|
|
| def execute_python_code(code: str, csv_url: Optional[str] = None) -> Tuple[Optional[bytes], Optional[str], str]: |
| """ |
| Executes Python code and captures the Matplotlib plot into memory bytes. |
| """ |
| |
| local_scope = { |
| "pd": pd, "np": np, "plt": plt, "sns": sns, "dt": dt, |
| "uuid": uuid, "os": os, "csv_url": csv_url |
| } |
|
|
| |
| if csv_url: |
| try: |
| |
| df = pd.read_csv(csv_url) |
| |
| local_scope["df"] = df |
| except Exception as e: |
| |
| return None, f"System Error: Failed to load CSV data. {str(e)}", "" |
|
|
| stdout_capture = io.StringIO() |
| |
| try: |
| plt.clf() |
| plt.close('all') |
| |
| with contextlib.redirect_stdout(stdout_capture): |
| |
| exec(code, {}, local_scope) |
| |
| |
| buf = io.BytesIO() |
| fig = plt.gcf() |
| |
| |
| if not fig.get_axes(): |
| return None, "No plot was generated by the code.", stdout_capture.getvalue() |
| |
| fig.savefig(buf, format='png', bbox_inches='tight') |
| buf.seek(0) |
| image_bytes = buf.getvalue() |
| buf.close() |
|
|
| return image_bytes, None, stdout_capture.getvalue() |
| |
| except Exception: |
| return None, traceback.format_exc(), stdout_capture.getvalue() |