Quazim0t0 commited on
Commit
91561ce
ยท
verified ยท
1 Parent(s): 9ab0aad

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +194 -121
app.py CHANGED
@@ -1,154 +1,227 @@
1
  import os
2
  import gradio as gr
3
- from sqlalchemy import text, inspect
4
  from smolagents import tool, CodeAgent, HfApiModel
 
5
  import pandas as pd
6
- import tempfile
7
- from database import engine, initialize_database
8
-
9
- # Ensure the database initializes with placeholder data
10
- initialize_database()
11
-
12
- # SQL Execution Tool (FIXED - Defined BEFORE Use)
13
- @tool
14
- def sql_engine(query: str) -> str:
15
  """
16
- Executes an SQL SELECT query and returns the results.
17
-
18
- Parameters:
19
- query (str): The SQL query string that should be executed.
20
-
21
- Returns:
22
- str: The result of the SQL query formatted as a string.
23
 
24
- Example:
25
- >>> sql_engine("SELECT * FROM users")
26
- '1, Alice, 30, 100.50\\n2, Bob, 24, 250.75\\n3, Charlie, 35, 80.00'
27
- """
28
- try:
29
- with engine.connect() as con:
30
- rows = con.execute(text(query)).fetchall()
31
- if not rows:
32
- return "No results found."
33
- return "\n".join([", ".join(map(str, row)) for row in rows])
34
- except Exception as e:
35
- return f"Error: {str(e)}"
36
-
37
-
38
- # Function to execute an uploaded SQL script
39
- def execute_sql_script(file_path):
40
- """
41
- Executes an uploaded SQL file to initialize the database.
42
-
43
  Args:
44
- file_path (str): Path to the SQL file.
45
-
46
  Returns:
47
- str: Success message or error description.
48
  """
49
  try:
50
- with engine.connect() as con:
51
- with open(file_path, "r") as f:
52
- sql_script = f.read()
53
- con.execute(text(sql_script))
54
- return "SQL file executed successfully. Database updated."
 
 
 
 
 
 
 
 
 
 
 
 
 
 
55
  except Exception as e:
56
- return f"Error: {str(e)}"
57
-
58
- # Function to get table names dynamically
59
- def get_table_names():
60
- """
61
- Returns a list of tables available in the database.
62
 
63
- Returns:
64
- list: List of table names.
65
  """
66
- inspector = inspect(engine)
67
- return inspector.get_table_names()
68
-
69
- # Function to get table schema dynamically
70
- def get_table_schema(table_name):
71
  """
72
- Returns a list of column names for a given table.
73
-
74
- Args:
75
- table_name (str): Name of the table.
 
 
 
 
 
 
 
 
76
 
77
- Returns:
78
- list: List of column names.
79
- """
80
- inspector = inspect(engine)
81
- columns = inspector.get_columns(table_name)
82
- return [col["name"] for col in columns]
83
 
84
- # Function to fetch data dynamically from any table
85
- def get_table_data(table_name):
86
  """
87
- Retrieves all rows from a specified table as a Pandas DataFrame.
88
-
89
- Args:
90
- table_name (str): Name of the table.
91
-
92
- Returns:
93
- pd.DataFrame: Table data or an error message.
94
  """
95
  try:
96
  with engine.connect() as con:
97
- result = con.execute(text(f"SELECT * FROM {table_name}"))
98
- rows = result.fetchall()
99
-
100
- columns = get_table_schema(table_name)
101
 
102
  if not rows:
103
- return pd.DataFrame(columns=columns)
104
 
105
- return pd.DataFrame(rows, columns=columns)
106
- except Exception as e:
107
- return pd.DataFrame({"Error": [str(e)]})
108
 
109
- # Function to handle SQL file uploads and execute them
110
- def handle_file_upload(file):
111
- """
112
- Handles SQL file upload, executes SQL, and updates database schema.
113
 
114
- Args:
115
- file (File): Uploaded SQL file.
116
 
117
- Returns:
118
- tuple: Execution result message and updated table data.
 
 
119
  """
120
- temp_file_path = tempfile.mkstemp(suffix=".sql")[1]
121
- with open(temp_file_path, "wb") as temp_file:
122
- temp_file.write(file.read())
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
123
 
124
- result = execute_sql_script(temp_file_path)
125
- tables = get_table_names()
126
-
127
- if tables:
128
- table_data = {table: get_table_data(table) for table in tables}
129
- else:
130
- table_data = {"Error": ["No tables found after execution. Ensure your SQL file creates tables."]}
131
-
132
- return result, table_data
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
133
 
134
- # Gradio UI
135
  with gr.Blocks() as demo:
136
- gr.Markdown("## SQL Query Interface")
137
-
138
- with gr.Row():
139
- user_input = gr.Textbox(label="Ask a question about the data")
140
- query_output = gr.Textbox(label="Result")
141
-
142
- user_input.change(fn=query_sql, inputs=user_input, outputs=query_output)
143
-
144
- gr.Markdown("## Upload SQL File to Execute")
145
- file_upload = gr.File(label="Upload SQL File")
146
- upload_output = gr.Textbox(label="Execution Result")
147
-
148
- # Dynamic table display
149
- table_output = gr.Dataframe(label="Database Tables (Dynamic)")
150
-
151
- file_upload.change(fn=handle_file_upload, inputs=file_upload, outputs=[upload_output, table_output])
152
 
153
  if __name__ == "__main__":
154
  demo.launch(server_name="0.0.0.0", server_port=7860, share=True)
 
1
  import os
2
  import gradio as gr
3
+ from sqlalchemy import text
4
  from smolagents import tool, CodeAgent, HfApiModel
5
+ import spaces
6
  import pandas as pd
7
+ from database import (
8
+ engine,
9
+ create_dynamic_table,
10
+ clear_database,
11
+ insert_rows_into_table,
12
+ get_table_schema
13
+ )
14
+
15
+ def process_uploaded_file(file):
16
  """
17
+ Process the uploaded CSV file and load it into the database.
 
 
 
 
 
 
18
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
  Args:
20
+ file: Path to the uploaded file
21
+
22
  Returns:
23
+ tuple: (success_flag, message)
24
  """
25
  try:
26
+ if file is None:
27
+ return False, "Please upload a file."
28
+
29
+ # Read the CSV file
30
+ df = pd.read_csv(file.name)
31
+
32
+ if len(df.columns) == 0:
33
+ return False, "Error: File contains no columns"
34
+
35
+ # Clear existing database and create new table
36
+ clear_database()
37
+ table = create_dynamic_table(df)
38
+
39
+ # Convert DataFrame to list of dictionaries and insert
40
+ records = df.to_dict('records')
41
+ insert_rows_into_table(records, table)
42
+
43
+ return True, "File successfully loaded! Proceeding to query interface..."
44
+
45
  except Exception as e:
46
+ return False, f"Error processing file: {str(e)}"
 
 
 
 
 
47
 
48
+ def get_data_table():
 
49
  """
50
+ Fetches all data from the current table and returns it as a Pandas DataFrame.
 
 
 
 
51
  """
52
+ try:
53
+ with engine.connect() as con:
54
+ result = con.execute(text("SELECT * FROM data_table"))
55
+ rows = result.fetchall()
56
+
57
+ if not rows:
58
+ return pd.DataFrame()
59
+
60
+ # Get column names from the result
61
+ columns = result.keys()
62
+ df = pd.DataFrame(rows, columns=columns)
63
+ return df
64
 
65
+ except Exception as e:
66
+ return pd.DataFrame({"Error": [str(e)]})
 
 
 
 
67
 
68
+ @tool
69
+ def sql_engine(query: str) -> str:
70
  """
71
+ Executes an SQL query and returns formatted results.
 
 
 
 
 
 
72
  """
73
  try:
74
  with engine.connect() as con:
75
+ rows = con.execute(text(query)).fetchall()
 
 
 
76
 
77
  if not rows:
78
+ return "No results found."
79
 
80
+ if len(rows) == 1 and len(rows[0]) == 1:
81
+ return str(rows[0][0])
 
82
 
83
+ return "\n".join([", ".join(map(str, row)) for row in rows])
 
 
 
84
 
85
+ except Exception as e:
86
+ return f"Error: {str(e)}"
87
 
88
+ def query_sql(user_query: str) -> str:
89
+ """
90
+ Converts natural language input to an SQL query using CodeAgent
91
+ and returns the execution results.
92
  """
93
+ schema = get_table_schema()
94
+ if not schema:
95
+ return "Error: No data table exists. Please upload a file first."
96
+
97
+ schema_info = (
98
+ "The database has a table named 'data_table' with the following schema:\n"
99
+ f"{schema}\n"
100
+ "Generate a valid SQL SELECT query using ONLY these column names.\n"
101
+ "DO NOT explain your reasoning, and DO NOT return anything other than the SQL query itself."
102
+ )
103
+
104
+ generated_sql = agent.run(f"{schema_info} Convert this request into SQL: {user_query}")
105
+
106
+ if not isinstance(generated_sql, str):
107
+ return f"{generated_sql}"
108
+
109
+ if not generated_sql.strip().lower().startswith(("select", "show", "pragma")):
110
+ return "Error: Only SELECT queries are allowed."
111
+
112
+ result = sql_engine(generated_sql)
113
 
114
+ try:
115
+ float_result = float(result)
116
+ return f"{float_result:.2f}"
117
+ except ValueError:
118
+ return result
119
+
120
+ agent = CodeAgent(
121
+ tools=[sql_engine],
122
+ model=HfApiModel(model_id="Qwen/Qwen2.5-Coder-32B-Instruct"),
123
+ )
124
+
125
+ # Create the upload interface
126
+ def create_upload_interface():
127
+ with gr.Blocks() as upload_interface:
128
+ gr.Markdown("""
129
+ # Data Query Interface
130
+
131
+ Upload your CSV file to begin.
132
+
133
+ ### Requirements:
134
+ - File must be in CSV format
135
+ - First column will be used as the primary key
136
+ - All columns will be automatically typed based on their content
137
+ """)
138
+
139
+ file_input = gr.File(
140
+ label="Upload CSV File",
141
+ file_types=[".csv"],
142
+ type="file"
143
+ )
144
+ status = gr.Textbox(label="Status", interactive=False)
145
+
146
+ def handle_upload(file):
147
+ success, message = process_uploaded_file(file)
148
+ if success:
149
+ return message, gr.Blocks.update(visible=False), gr.Blocks.update(visible=True)
150
+ return message, gr.Blocks.update(visible=True), gr.Blocks.update(visible=False)
151
+
152
+ file_input.upload(
153
+ fn=handle_upload,
154
+ inputs=[file_input],
155
+ outputs=[status, upload_interface, query_interface]
156
+ )
157
+
158
+ return upload_interface
159
+
160
+ # Create the query interface
161
+ def create_query_interface():
162
+ with gr.Blocks(visible=False) as query_interface:
163
+ gr.Markdown("""
164
+ ## Data Query Interface
165
+
166
+ Enter your questions about the data in natural language.
167
+ The AI will convert your questions into SQL queries.
168
+ """)
169
+
170
+ with gr.Row():
171
+ with gr.Column(scale=1):
172
+ user_input = gr.Textbox(label="Ask a question about the data")
173
+ query_output = gr.Textbox(label="Result")
174
+
175
+ with gr.Column(scale=2):
176
+ gr.Markdown("### Current Data")
177
+ data_table = gr.Dataframe(
178
+ value=get_data_table(),
179
+ label="Data Table",
180
+ interactive=False
181
+ )
182
+
183
+ # Show current schema
184
+ schema_display = gr.Markdown(value="Loading schema...")
185
+
186
+ def update_schema():
187
+ schema = get_table_schema()
188
+ if schema:
189
+ return f"### Current Schema:\n```\n{schema}\n```"
190
+ return "No data loaded"
191
+
192
+ user_input.change(
193
+ fn=query_sql,
194
+ inputs=[user_input],
195
+ outputs=[query_output]
196
+ )
197
+
198
+ # Add refresh buttons
199
+ with gr.Row():
200
+ refresh_table_btn = gr.Button("Refresh Table")
201
+ refresh_schema_btn = gr.Button("Refresh Schema")
202
+
203
+ refresh_table_btn.click(
204
+ fn=get_data_table,
205
+ outputs=[data_table]
206
+ )
207
+
208
+ refresh_schema_btn.click(
209
+ fn=update_schema,
210
+ outputs=[schema_display]
211
+ )
212
+
213
+ # Update schema on load
214
+ query_interface.load(
215
+ fn=update_schema,
216
+ outputs=[schema_display]
217
+ )
218
+
219
+ return query_interface
220
 
221
+ # Create the main interface
222
  with gr.Blocks() as demo:
223
+ upload_interface = create_upload_interface()
224
+ query_interface = create_query_interface()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
225
 
226
  if __name__ == "__main__":
227
  demo.launch(server_name="0.0.0.0", server_port=7860, share=True)