Spaces:
Sleeping
Sleeping
| """Safe execution of LLM-generated Plotly visualization code.""" | |
| import traceback | |
| import numpy as np | |
| import pandas as pd | |
| import plotly.express as px | |
| import plotly.graph_objects as go | |
| def _strip_imports(code: str) -> str: | |
| """Remove import statements — px, go, pd, np are already in the namespace.""" | |
| lines = [ | |
| line for line in code.splitlines() | |
| if not line.strip().startswith(("import ", "from ")) | |
| ] | |
| return "\n".join(lines) | |
| def execute_viz_code(code: str, result_df: pd.DataFrame): | |
| """ | |
| Execute plotly visualization code in a restricted namespace. | |
| Returns (fig, error_message). | |
| """ | |
| if not code or code.strip().lower() in ("null", "none", ""): | |
| return None, None | |
| code = _strip_imports(code) | |
| namespace = { | |
| "result_df": result_df.copy(), | |
| "pd": pd, | |
| "np": np, | |
| "px": px, | |
| "go": go, | |
| "__builtins__": { | |
| "len": len, | |
| "range": range, | |
| "list": list, | |
| "dict": dict, | |
| "str": str, | |
| "int": int, | |
| "float": float, | |
| "bool": bool, | |
| "print": print, | |
| "sorted": sorted, | |
| "zip": zip, | |
| "enumerate": enumerate, | |
| "min": min, | |
| "max": max, | |
| "sum": sum, | |
| "abs": abs, | |
| "round": round, | |
| "isinstance": isinstance, | |
| }, | |
| } | |
| try: | |
| exec(code, namespace) # noqa: S102 | |
| fig = namespace.get("fig") | |
| if fig is None: | |
| return None, "Visualization code did not create 'fig'. Make sure your code assigns a Plotly figure to 'fig'." | |
| return fig, None | |
| except Exception: | |
| return None, f"Visualization error:\n{traceback.format_exc()}" | |
| def make_fallback_chart(result_df: pd.DataFrame, title: str = "Data Overview"): | |
| """Generate a simple bar chart when LLM viz code fails.""" | |
| numeric_cols = result_df.select_dtypes(include=[np.number]).columns.tolist() | |
| text_cols = result_df.select_dtypes(include=["object", "category"]).columns.tolist() | |
| if numeric_cols and text_cols: | |
| fig = px.bar( | |
| result_df, | |
| x=text_cols[0], | |
| y=numeric_cols[0], | |
| title=title, | |
| height=500, | |
| ) | |
| return fig | |
| return None | |