jzou19950715's picture
Update app.py
fc29f53 verified
raw
history blame
7.43 kB
import os
import pandas as pd
import requests
import json
import subprocess
import gradio as gr
import tempfile
import sys
from io import StringIO
import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np
from typing import Dict, Any, Tuple, Optional
import ast
# Safe imports list - mirrors smolagents approach
SAFE_IMPORTS = [
"pandas", "numpy", "matplotlib", "seaborn", "sklearn",
"scipy", "statsmodels", "plotly", "math", "datetime",
"collections", "itertools", "functools", "operator"
]
class SafeExecutor:
"""Safely executes Python code with restricted imports and environment"""
def __init__(self, allowed_imports=None):
self.allowed_imports = allowed_imports or SAFE_IMPORTS
def validate_imports(self, code: str) -> bool:
"""Validate that all imports in the code are allowed"""
try:
tree = ast.parse(code)
for node in ast.walk(tree):
if isinstance(node, (ast.Import, ast.ImportFrom)):
for name in node.names:
module = name.name.split('.')[0]
if module not in self.allowed_imports:
raise ValueError(f"Import of '{module}' is not allowed. Allowed imports: {self.allowed_imports}")
return True
except Exception as e:
raise ValueError(f"Code validation error: {str(e)}")
def execute_code(self, code: str, globals_dict: Dict[str, Any] = None) -> Tuple[Any, str]:
"""Execute code safely and return the output"""
if globals_dict is None:
globals_dict = {}
# Add safe imports to globals
for module in self.allowed_imports:
try:
globals_dict[module] = __import__(module)
except ImportError:
pass
# Redirect stdout to capture print outputs
old_stdout = sys.stdout
redirected_output = StringIO()
sys.stdout = redirected_output
try:
# Validate imports first
self.validate_imports(code)
# Execute the code
exec(code, globals_dict)
output = redirected_output.getvalue()
# Handle matplotlib figures
if plt.get_figs():
with tempfile.NamedTemporaryFile(suffix='.png', delete=False) as tmp:
plt.savefig(tmp.name)
plt.close('all')
return tmp.name, output
return None, output
except Exception as e:
return None, f"Error executing code:\n{str(e)}"
finally:
sys.stdout = old_stdout
def query_api(prompt: str, api_url: str, api_key: str, system_prompt: str) -> str:
"""Send a prompt to the specified API and return the response"""
headers = {
"Content-Type": "application/json",
"Authorization": f"Bearer {api_key}"
}
payload = {
"messages": [
{"role": "system", "content": system_prompt},
{"role": "user", "content": prompt}
]
}
try:
response = requests.post(api_url, headers=headers, json=payload)
response.raise_for_status()
return response.json()["choices"][0]["message"]["content"]
except requests.exceptions.RequestException as e:
return f"API Error: {str(e)}"
def analyze_data(
csv_file: str,
api_url: str,
api_key: str,
system_prompt: str
) -> Tuple[str, str, str, Optional[str]]:
"""Analyze uploaded CSV data using the API and execute the generated code"""
if not csv_file:
return "No file uploaded.", None, None, None
try:
# Create safe executor
executor = SafeExecutor()
# Read the CSV file
df = pd.read_csv(csv_file.name)
columns = df.columns.tolist()
sample_data = df.head(3).to_dict()
# Build the prompt
prompt = f"""Analyze this CSV file with columns: {columns}.
Sample data: {sample_data}
Generate Python code that:
1. Creates insightful visualizations using matplotlib or seaborn
2. Performs relevant statistical analysis
3. Identifies key patterns or insights
4. Properly handles potential data issues
Important: Use only these libraries: {', '.join(SAFE_IMPORTS)}"""
# Get code from API
generated_code = query_api(prompt, api_url, api_key, system_prompt)
# Create execution environment
globals_dict = {'df': df, 'pd': pd, 'np': np, 'plt': plt, 'sns': sns}
# Execute the code
vis_path, execution_output = executor.execute_code(generated_code, globals_dict)
status = "Analysis completed successfully."
return status, generated_code, execution_output, vis_path
except Exception as e:
return f"Error during analysis: {str(e)}", None, None, None
def create_interface():
"""Create the Gradio interface"""
with gr.Blocks() as interface:
gr.Markdown("# AI-Powered Data Analysis Tool")
with gr.Row():
with gr.Column():
api_url = gr.Textbox(
label="API URL",
placeholder="Enter API endpoint URL",
type="text"
)
api_key = gr.Textbox(
label="API Key",
placeholder="Enter API key",
type="password"
)
system_prompt = gr.Textbox(
label="System Prompt",
placeholder="Enter system prompt for the AI",
value="You are an AI assistant specialized in data analysis and visualization.",
lines=3
)
csv_file = gr.File(
label="Upload CSV File",
file_types=[".csv"]
)
analyze_button = gr.Button("Analyze Data")
with gr.Column():
status_output = gr.Textbox(label="Status")
code_output = gr.Code(
label="Generated Code",
language="python"
)
execution_output = gr.Textbox(
label="Execution Output",
lines=10
)
visualization_output = gr.Image(
label="Visualization",
type="filepath"
)
analyze_button.click(
fn=analyze_data,
inputs=[csv_file, api_url, api_key, system_prompt],
outputs=[status_output, code_output, execution_output, visualization_output]
)
gr.Markdown("""
## How to Use
1. Enter your API URL and key (supports various API providers)
2. Customize the system prompt if desired
3. Upload a CSV file for analysis
4. Click 'Analyze Data' to generate and execute analysis code
The tool will:
- Generate Python code to analyze your data
- Execute the code safely in a controlled environment
- Display both textual results and visualizations
- Support common data science libraries
""")
return interface
if __name__ == "__main__":
interface = create_interface()
interface.launch()