| from typing import Any, Dict, Optional |
| import pandas as pd |
| import numpy as np |
| from pandas.api.types import is_numeric_dtype, is_string_dtype |
| from pydantic import BaseModel |
|
|
| class CsvInfoRequest(BaseModel): |
| csv_url: str |
|
|
| class CsvInfoResponse(BaseModel): |
| success: bool |
| data: Optional[Dict[str, Any]] = None |
| error: Optional[str] = None |
| request_id: str |
| duration: float |
| |
| class CsvDataRequest(BaseModel): |
| csv_url: str |
| |
| class PythonExecutionRequest(BaseModel): |
| code: str |
| context: Optional[Dict[str, Any]] = None |
|
|
| class PythonExecutionResponse(BaseModel): |
| success: bool |
| output: str |
| result: Optional[Any] = None |
| isStructured: bool |
| error: Optional[str] = None |
| request_id: str |
|
|
| def clean_data(input_data, drop_constants=True): |
| """ |
| The 'Ultimate' generic data cleaner. |
| MODIFIED: Keeps column names raw and original (no stripping, no lowercasing). |
| """ |
| try: |
| |
| if isinstance(input_data, str): |
| try: |
| |
| df = pd.read_csv(input_data, sep=None, engine='python') |
| except UnicodeDecodeError: |
| |
| df = pd.read_csv(input_data, sep=None, engine='python', encoding='latin1') |
| except Exception: |
| |
| df = pd.read_csv(input_data) |
| elif isinstance(input_data, pd.DataFrame): |
| df = input_data.copy() |
| else: |
| raise ValueError("Input must be a CSV URL string or a pandas DataFrame.") |
|
|
| |
| |
| |
| |
| |
| df = df.drop_duplicates() |
|
|
| |
| for col in df.columns: |
| |
| if is_numeric_dtype(df[col]): |
| continue |
|
|
| |
| if is_string_dtype(df[col]): |
| clean_col = df[col].astype(str).str.replace(r'[$,%]', '', regex=True) |
| converted = pd.to_numeric(clean_col, errors='coerce') |
| |
| if converted.notna().mean() > 0.8: |
| df[col] = converted |
| continue |
|
|
| |
| if is_string_dtype(df[col]): |
| try: |
| sample = str(df[col].dropna().iloc[0]) if not df[col].dropna().empty else "" |
| |
| is_date_like = any(x in sample for x in ['-', '/', ':']) |
| if is_date_like: |
| converted = pd.to_datetime(df[col], errors='coerce') |
| if converted.notna().mean() > 0.8: |
| df[col] = converted |
| except Exception: |
| pass |
|
|
| |
| df.replace([np.inf, -np.inf], np.nan, inplace=True) |
|
|
| |
| |
| num_cols = df.select_dtypes(include=[np.number]).columns |
| df[num_cols] = df[num_cols].fillna(0) |
|
|
| |
| cat_cols = df.select_dtypes(include=['object', 'category']).columns |
| for col in cat_cols: |
| if df[col].dtype.name == 'category': |
| if 'Unknown' not in df[col].cat.categories: |
| df[col] = df[col].cat.add_categories(['Unknown']) |
| df[col] = df[col].fillna('Unknown') |
| else: |
| df[col] = df[col].fillna('Unknown') |
|
|
| |
| bool_cols = df.select_dtypes(include=['bool']).columns |
| df[bool_cols] = df[bool_cols].fillna(False) |
|
|
| |
| if drop_constants: |
| cols_to_drop = [col for col in df.columns if df[col].nunique() <= 1] |
| if cols_to_drop: |
| df = df.drop(columns=cols_to_drop) |
|
|
| return df |
|
|
| except Exception as e: |
| raise Exception(f"Data Cleaning Failed: {str(e)}") |
|
|
| def get_csv_basic_info(csv_path): |
| """ |
| Get basic information about a CSV file. |
| Includes JSON serialization fix for dates and numpy types. |
| """ |
| try: |
| |
| df = clean_data(csv_path) |
| |
| |
| def json_serializable(val): |
| if pd.isna(val): |
| return None |
| if isinstance(val, (pd.Timestamp, np.datetime64)): |
| return str(val) |
| if isinstance(val, (np.integer, np.int64)): |
| return int(val) |
| if isinstance(val, (np.floating, np.float64)): |
| return float(val) |
| return val |
|
|
| |
| raw_sample = df.head(1).to_dict('records') |
| clean_sample = [] |
| |
| if raw_sample: |
| clean_sample = [{k: json_serializable(v) for k, v in raw_sample[0].items()}] |
|
|
| print(f"CSV file read successfully: {csv_path}") |
| |
| info = { |
| 'num_rows': int(len(df)), |
| 'num_cols': int(len(df.columns)), |
| 'example_rows': clean_sample, |
| 'dtypes': {col: str(df[col].dtype) for col in df.columns}, |
| 'columns': list(df.columns), |
| 'numeric_columns': [col for col in df.columns if pd.api.types.is_numeric_dtype(df[col])], |
| 'categorical_columns': [col for col in df.columns if pd.api.types.is_string_dtype(df[col])] |
| } |
| return info |
| except Exception as e: |
| error_info = { |
| 'error': f"Error reading CSV file: {str(e)}", |
| } |
| return error_info |
|
|
|
|
| def get_robust_csv_rows(csv_url: str): |
| """ |
| Reads a CSV securely and robustly for frontend table rendering. |
| - Auto-detects delimiters (semicolon vs comma). |
| - Handles encoding issues. |
| - Replaces NaNs with empty strings for JSON safety. |
| """ |
| try: |
| |
| try: |
| df = pd.read_csv(csv_url, sep=None, engine='python') |
| except UnicodeDecodeError: |
| df = pd.read_csv(csv_url, sep=None, engine='python', encoding='latin1') |
| except Exception: |
| |
| df = pd.read_csv(csv_url) |
|
|
| |
| |
| df.replace([np.inf, -np.inf], np.nan, inplace=True) |
| |
| |
| df = df.fillna("") |
|
|
| |
| data_list = df.to_dict(orient='records') |
| |
| return data_list |
|
|
| except Exception as e: |
| return {"error": f"Failed to read CSV: {str(e)}"} |
| |
| |
| import io |
| from contextlib import redirect_stdout, redirect_stderr |
| from typing import Any, Dict |
| import requests |
|
|
|
|
| def check_structured_data(data: Any) -> bool: |
| if isinstance(data, list) and data and all(isinstance(item, dict) for item in data): |
| return all( |
| all(isinstance(v, (str, int, float, bool)) or v is None for v in item.values()) |
| for item in data |
| ) |
| elif isinstance(data, dict): |
| return all(isinstance(v, (str, int, float, bool)) or v is None for v in data.values()) |
| return False |
|
|
|
|
| def clean_output(stdout: str, stderr: str) -> str: |
| output = [] |
| if stdout.strip(): |
| output.append(stdout.strip()) |
| if stderr.strip(): |
| output.append(stderr.strip()) |
| return '\n'.join(output) if output else '' |
|
|
|
|
| def execute_python_logic(code: str, custom_context: dict = None) -> Dict[str, Any]: |
| stdout = io.StringIO() |
| stderr = io.StringIO() |
| result = None |
| is_structured = False |
| error = None |
|
|
| try: |
| with redirect_stdout(stdout), redirect_stderr(stderr): |
| exec_globals = { |
| '__builtins__': __builtins__, |
| 'requests': requests, |
| 'print': print, |
| } |
|
|
| try: |
| compiled = compile(code, '<string>', 'eval') |
| result = eval(compiled, exec_globals) |
| except SyntaxError: |
| compiled = compile(code, '<string>', 'exec') |
| exec(compiled, exec_globals) |
| result = exec_globals.get('result') or exec_globals.get('_') |
|
|
| if result is not None: |
| is_structured = check_structured_data(result) |
|
|
| except Exception as e: |
| error = f"Execution error: {str(e)}" |
| stderr.write(error) |
|
|
| output = clean_output(stdout.getvalue(), stderr.getvalue()) |
|
|
| return { |
| 'output': output, |
| 'result': result, |
| 'isStructured': is_structured, |
| 'error': error |
| } |