alihmaoubis/duckdbautoexplorer
0
1import gradio as gr2import json3from PIL import Image4import numpy as np5 6# --- User Defined Logic ---7 8import duckdb9import json10from urllib.parse import urlparse11import time12 13def execute_sql_query(file_url, sql_query):14 """15 Exécute une requête SQL sur un fichier de données depuis une URL.16 17 Args:18 file_url (str): URL du fichier (Parquet, CSV ou JSON)19 sql_query (str): Requête SQL à exécuter20 21 Returns:22 dict: Résultats de la requête23 """24 try:25 # Créer une connexion DuckDB26 con = duckdb.connect(':memory:')27 28 # Installer et charger l'extension httpfs29 con.execute("INSTALL httpfs;")30 con.execute("LOAD httpfs;")31 32 # Déterminer le type de fichier33 parsed_url = urlparse(file_url)34 path = parsed_url.path.lower()35 36 if path.endswith('.parquet'):37 file_type = 'parquet'38 load_query = f"SELECT * FROM read_parquet('{file_url}')"39 elif path.endswith('.csv'):40 file_type = 'csv'41 load_query = f"SELECT * FROM read_csv('{file_url}', AUTO_DETECT=TRUE)"42 elif path.endswith('.json') or path.endswith('.jsonl'):43 file_type = 'json'44 load_query = f"SELECT * FROM read_json('{file_url}', AUTO_DETECT=TRUE)"45 else:46 # Auto-détection47 file_type = 'unknown'48 try:49 load_query = f"SELECT * FROM read_csv('{file_url}', AUTO_DETECT=TRUE)"50 con.execute(f"{load_query} LIMIT 1")51 file_type = 'csv'52 except:53 try:54 load_query = f"SELECT * FROM read_parquet('{file_url}')"55 con.execute(f"{load_query} LIMIT 1")56 file_type = 'parquet'57 except:58 try:59 load_query = f"SELECT * FROM read_json('{file_url}', AUTO_DETECT=TRUE)"60 con.execute(f"{load_query} LIMIT 1")61 file_type = 'json'62 except:63 return {64 'error': 'Unable to detect file type. Supported: .parquet, .csv, .json',65 'file_url': file_url66 }67 68 # Créer une vue pour les données69 con.execute(f"CREATE OR REPLACE VIEW data_view AS {load_query}")70 71 # Préparer la requête SQL72 # Si la requête utilise déjà une table/vue spécifique, l'utiliser telle quelle73 # Sinon, remplacer les références communes par data_view74 query_to_execute = sql_query.strip()75 76 # Si la requête ne contient pas de FROM, on suppose qu'elle doit s'appliquer à data_view77 if 'FROM' not in query_to_execute.upper() and 'from' not in query_to_execute:78 # C'est probablement une erreur, mais on peut essayer de l'ajouter79 if query_to_execute.upper().startswith('SELECT'):80 query_to_execute = f"{query_to_execute} FROM data_view"81 82 # Exécuter la requête et mesurer le temps83 start_time = time.time()84 result = con.execute(query_to_execute)85 execution_time = time.time() - start_time86 87 # Récupérer les résultats88 rows = result.fetchall()89 columns = [desc[0] for desc in result.description]90 91 # Convertir les résultats en format JSON sérialisable92 json_rows = []93 for row in rows:94 json_row = []95 for val in row:96 # Convertir les types non-sérialisables97 if val is None:98 json_row.append(None)99 elif isinstance(val, (int, float, str, bool)):100 json_row.append(val)101 else:102 json_row.append(str(val))103 json_rows.append(json_row)104 105 result_data = {106 'status': 'success',107 'file_url': file_url,108 'file_type': file_type,109 'query': query_to_execute,110 'columns': columns,111 'rows': json_rows,112 'row_count': len(json_rows),113 'execution_time_seconds': round(execution_time, 4),114 'note': 'Use table name "data_view" in your SQL queries'115 }116 117 con.close()118 return result_data119 120 except Exception as e:121 return {122 'error': f'SQL execution failed: {str(e)}',123 'file_url': file_url,124 'query': sql_query,125 'hint': 'Make sure to use "data_view" as the table name in your SQL query'126 }127 128 129# --- Interface Factory ---130def create_interface():131 return gr.Interface(132 fn=execute_sql_query,133 inputs=[gr.Textbox(label=k) for k in ['file_url', 'sql_query']],134 outputs=gr.JSON(label="JSON object containing query results with columns and rows"),135 title="execute_sql_query",136 description="Auto-generated tool: execute_sql_query"137 )