Spaces:
Runtime error
Runtime error
Update app.py
Browse files
app.py
CHANGED
|
@@ -1,238 +1,321 @@
|
|
| 1 |
-
from flask import Flask, request, render_template, jsonify
|
| 2 |
-
import mysql.connector
|
| 3 |
-
from mysql.connector import Error
|
| 4 |
-
import os
|
| 5 |
-
from groq import Groq
|
| 6 |
-
from dotenv import load_dotenv
|
| 7 |
-
import re
|
| 8 |
-
import uuid
|
| 9 |
-
|
| 10 |
-
app = Flask(__name__)
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
'
|
| 17 |
-
'
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
|
| 31 |
-
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
|
| 37 |
-
return
|
| 38 |
-
|
| 39 |
-
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
|
| 51 |
-
|
| 52 |
-
|
| 53 |
-
|
| 54 |
-
|
| 55 |
-
if line.startswith('
|
| 56 |
-
|
| 57 |
-
|
| 58 |
-
|
| 59 |
-
|
| 60 |
-
|
| 61 |
-
|
| 62 |
-
|
| 63 |
-
|
| 64 |
-
|
| 65 |
-
|
| 66 |
-
|
| 67 |
-
|
| 68 |
-
|
| 69 |
-
|
| 70 |
-
|
| 71 |
-
|
| 72 |
-
summary
|
| 73 |
-
|
| 74 |
-
'
|
| 75 |
-
'
|
| 76 |
-
'
|
| 77 |
-
|
| 78 |
-
'
|
| 79 |
-
'
|
| 80 |
-
|
| 81 |
-
|
| 82 |
-
|
| 83 |
-
|
| 84 |
-
|
| 85 |
-
|
| 86 |
-
|
| 87 |
-
|
| 88 |
-
|
| 89 |
-
|
| 90 |
-
|
| 91 |
-
|
| 92 |
-
|
| 93 |
-
|
| 94 |
-
|
| 95 |
-
|
| 96 |
-
|
| 97 |
-
|
| 98 |
-
'
|
| 99 |
-
'
|
| 100 |
-
|
| 101 |
-
|
| 102 |
-
|
| 103 |
-
|
| 104 |
-
|
| 105 |
-
|
| 106 |
-
|
| 107 |
-
|
| 108 |
-
|
| 109 |
-
|
| 110 |
-
|
| 111 |
-
|
| 112 |
-
|
| 113 |
-
|
| 114 |
-
|
| 115 |
-
|
| 116 |
-
|
| 117 |
-
|
| 118 |
-
|
| 119 |
-
|
| 120 |
-
|
| 121 |
-
|
| 122 |
-
|
| 123 |
-
|
| 124 |
-
|
| 125 |
-
|
| 126 |
-
|
| 127 |
-
|
| 128 |
-
|
| 129 |
-
|
| 130 |
-
|
| 131 |
-
|
| 132 |
-
|
| 133 |
-
|
| 134 |
-
|
| 135 |
-
|
| 136 |
-
|
| 137 |
-
|
| 138 |
-
|
| 139 |
-
|
| 140 |
-
|
| 141 |
-
|
| 142 |
-
|
| 143 |
-
|
| 144 |
-
|
| 145 |
-
|
| 146 |
-
|
| 147 |
-
|
| 148 |
-
|
| 149 |
-
|
| 150 |
-
|
| 151 |
-
|
| 152 |
-
|
| 153 |
-
|
| 154 |
-
|
| 155 |
-
|
| 156 |
-
|
| 157 |
-
|
| 158 |
-
|
| 159 |
-
|
| 160 |
-
|
| 161 |
-
|
| 162 |
-
|
| 163 |
-
|
| 164 |
-
|
| 165 |
-
|
| 166 |
-
|
| 167 |
-
|
| 168 |
-
|
| 169 |
-
|
| 170 |
-
|
| 171 |
-
|
| 172 |
-
|
| 173 |
-
|
| 174 |
-
|
| 175 |
-
|
| 176 |
-
|
| 177 |
-
|
| 178 |
-
|
| 179 |
-
|
| 180 |
-
|
| 181 |
-
|
| 182 |
-
|
| 183 |
-
|
| 184 |
-
|
| 185 |
-
|
| 186 |
-
|
| 187 |
-
|
| 188 |
-
|
| 189 |
-
|
| 190 |
-
|
| 191 |
-
|
| 192 |
-
|
| 193 |
-
|
| 194 |
-
|
| 195 |
-
cursor.
|
| 196 |
-
|
| 197 |
-
|
| 198 |
-
|
| 199 |
-
|
| 200 |
-
|
| 201 |
-
|
| 202 |
-
|
| 203 |
-
|
| 204 |
-
|
| 205 |
-
|
| 206 |
-
|
| 207 |
-
|
| 208 |
-
|
| 209 |
-
|
| 210 |
-
|
| 211 |
-
|
| 212 |
-
|
| 213 |
-
|
| 214 |
-
|
| 215 |
-
|
| 216 |
-
|
| 217 |
-
|
| 218 |
-
|
| 219 |
-
|
| 220 |
-
|
| 221 |
-
|
| 222 |
-
|
| 223 |
-
|
| 224 |
-
|
| 225 |
-
|
| 226 |
-
|
| 227 |
-
|
| 228 |
-
|
| 229 |
-
|
| 230 |
-
|
| 231 |
-
|
| 232 |
-
|
| 233 |
-
|
| 234 |
-
|
| 235 |
-
|
| 236 |
-
|
| 237 |
-
|
| 238 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from flask import Flask, request, render_template, jsonify, session
|
| 2 |
+
import mysql.connector
|
| 3 |
+
from mysql.connector import Error
|
| 4 |
+
import os
|
| 5 |
+
from groq import Groq
|
| 6 |
+
from dotenv import load_dotenv
|
| 7 |
+
import re
|
| 8 |
+
import uuid
|
| 9 |
+
|
| 10 |
+
app = Flask(__name__)
|
| 11 |
+
app.secret_key = os.urandom(24) # Required for session management
|
| 12 |
+
load_dotenv()
|
| 13 |
+
|
| 14 |
+
# Default database configuration from .env
|
| 15 |
+
default_db_config = {
|
| 16 |
+
'host': os.getenv('DB_HOST', 'localhost'),
|
| 17 |
+
'user': os.getenv('DB_USER', 'root'),
|
| 18 |
+
'password': os.getenv('DB_PASSWORD', ''),
|
| 19 |
+
'port': int(os.getenv('DB_PORT', 3306))
|
| 20 |
+
}
|
| 21 |
+
|
| 22 |
+
# Groq API configuration
|
| 23 |
+
groq_client = Groq(api_key=os.getenv('GROQ_API_KEY'))
|
| 24 |
+
|
| 25 |
+
# Temporary storage for current database name and schema
|
| 26 |
+
current_db_name = None
|
| 27 |
+
current_schema = {}
|
| 28 |
+
current_summary = {}
|
| 29 |
+
|
| 30 |
+
def get_db_connection(db_name=None):
|
| 31 |
+
"""Establish a database connection using session or default config."""
|
| 32 |
+
config = session.get('db_config', default_db_config).copy()
|
| 33 |
+
if db_name:
|
| 34 |
+
config['database'] = db_name
|
| 35 |
+
try:
|
| 36 |
+
conn = mysql.connector.connect(**config)
|
| 37 |
+
return conn, None
|
| 38 |
+
except Error as e:
|
| 39 |
+
return None, f"Database connection failed: {str(e)}"
|
| 40 |
+
|
| 41 |
+
def parse_sql_file(file_content):
|
| 42 |
+
"""Parse SQL file to extract database name and clean statements."""
|
| 43 |
+
file_content = file_content.decode('utf-8') if isinstance(file_content, bytes) else file_content
|
| 44 |
+
statements = []
|
| 45 |
+
current_statement = ""
|
| 46 |
+
in_comment = False
|
| 47 |
+
|
| 48 |
+
# Extract database name
|
| 49 |
+
db_name_match = re.search(r"CREATE\s+DATABASE\s+[`']?(\w+)[`']?", file_content, re.IGNORECASE)
|
| 50 |
+
db_name = db_name_match.group(1) if db_name_match else f"temp_db_{uuid.uuid4().hex[:8]}"
|
| 51 |
+
|
| 52 |
+
# Split SQL into statements
|
| 53 |
+
for line in file_content.splitlines():
|
| 54 |
+
line = line.strip()
|
| 55 |
+
if not line or line.startswith('--'):
|
| 56 |
+
continue
|
| 57 |
+
if line.startswith('/*'):
|
| 58 |
+
in_comment = True
|
| 59 |
+
continue
|
| 60 |
+
if line.endswith('*/'):
|
| 61 |
+
in_comment = False
|
| 62 |
+
continue
|
| 63 |
+
if not in_comment:
|
| 64 |
+
current_statement += line + ' '
|
| 65 |
+
if line.endswith(';'):
|
| 66 |
+
statements.append(current_statement.strip())
|
| 67 |
+
current_statement = ""
|
| 68 |
+
|
| 69 |
+
return db_name, statements
|
| 70 |
+
|
| 71 |
+
def generate_schema_summary(schema, db_name):
|
| 72 |
+
"""Generate a dynamic summary of any MySQL database schema."""
|
| 73 |
+
summary = {
|
| 74 |
+
'description': '',
|
| 75 |
+
'main_tables': {},
|
| 76 |
+
'relationships': [],
|
| 77 |
+
'suggestions': {
|
| 78 |
+
'evaluation': 'Good',
|
| 79 |
+
'note': '',
|
| 80 |
+
'recommendations': []
|
| 81 |
+
}
|
| 82 |
+
}
|
| 83 |
+
|
| 84 |
+
# Infer description based on table names
|
| 85 |
+
table_names = list(schema.keys())
|
| 86 |
+
if any(table in table_names for table in ['patient', 'doctor', 'admission', 'appointment']):
|
| 87 |
+
summary['description'] = f"{db_name} appears to be a Hospital Management Database for tracking entities like patients, staff, and appointments."
|
| 88 |
+
elif any(table in table_names for table in ['customer', 'order', 'product', 'employee']):
|
| 89 |
+
summary['description'] = f"{db_name} appears to be a Retail or E-commerce Database for managing customers, orders, and products."
|
| 90 |
+
elif any(table in table_names for table in ['book', 'author', 'loan', 'member']):
|
| 91 |
+
summary['description'] = f"{db_name} appears to be a Library Management Database for tracking books, authors, and loans."
|
| 92 |
+
else:
|
| 93 |
+
summary['description'] = f"{db_name} is a database with {len(table_names)} tables for managing various entities."
|
| 94 |
+
|
| 95 |
+
# Select main tables (up to 5, prioritized by column count or presence of 'id')
|
| 96 |
+
sorted_tables = sorted(schema.items(), key=lambda x: len(x[1]), reverse=True)[:5]
|
| 97 |
+
for table, columns in sorted_tables:
|
| 98 |
+
key_columns = [col for col in columns if 'id' in col.lower() or col in ['name', 'first_name', 'last_name', 'title', 'amount', 'status', 'price']]
|
| 99 |
+
summary['main_tables'][table] = key_columns[:3] # Limit to 3 key columns
|
| 100 |
+
|
| 101 |
+
# Connect to database to detect relationships and suggestions
|
| 102 |
+
conn, error = get_db_connection(db_name)
|
| 103 |
+
if conn:
|
| 104 |
+
cursor = conn.cursor()
|
| 105 |
+
try:
|
| 106 |
+
# Detect foreign keys using INFORMATION_SCHEMA
|
| 107 |
+
cursor.execute("""
|
| 108 |
+
SELECT TABLE_NAME, COLUMN_NAME, REFERENCED_TABLE_NAME, REFERENCED_COLUMN_NAME
|
| 109 |
+
FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE
|
| 110 |
+
WHERE TABLE_SCHEMA = %s AND REFERENCED_TABLE_NAME IS NOT NULL
|
| 111 |
+
""", (db_name,))
|
| 112 |
+
relationships = cursor.fetchall()
|
| 113 |
+
for rel in relationships[:5]: # Limit to 5 relationships
|
| 114 |
+
summary['relationships'].append(f"{rel[0]} links to {rel[2]} via {rel[1]}")
|
| 115 |
+
|
| 116 |
+
# Fallback: Infer relationships from common column names
|
| 117 |
+
if not relationships:
|
| 118 |
+
for table1, columns1 in schema.items():
|
| 119 |
+
for col1 in columns1:
|
| 120 |
+
if '_id' in col1 and col1 != f"{table1}_id":
|
| 121 |
+
target_table = col1.replace('_id', '')
|
| 122 |
+
if target_table in schema:
|
| 123 |
+
summary['relationships'].append(f"{table1} likely links to {target_table} via {col1}")
|
| 124 |
+
|
| 125 |
+
# Check for indexes and constraints
|
| 126 |
+
cursor.execute("""
|
| 127 |
+
SELECT TABLE_NAME, NON_UNIQUE, INDEX_NAME
|
| 128 |
+
FROM INFORMATION_SCHEMA.STATISTICS
|
| 129 |
+
WHERE TABLE_SCHEMA = %s AND INDEX_NAME != 'PRIMARY'
|
| 130 |
+
""", (db_name,))
|
| 131 |
+
indexes = cursor.fetchall()
|
| 132 |
+
indexed_columns = set(row[0] + '.' + row[2] for row in indexes if row[1] == 0)
|
| 133 |
+
|
| 134 |
+
# Evaluate schema
|
| 135 |
+
has_foreign_keys = bool(relationships)
|
| 136 |
+
has_indexes = bool(indexes)
|
| 137 |
+
if has_foreign_keys and has_indexes:
|
| 138 |
+
summary['suggestions']['evaluation'] = 'Excellent'
|
| 139 |
+
summary['suggestions']['note'] = 'The schema is well-structured with defined foreign keys and indexes, supporting efficient queries.'
|
| 140 |
+
elif has_foreign_keys:
|
| 141 |
+
summary['suggestions']['evaluation'] = 'Good'
|
| 142 |
+
summary['suggestions']['note'] = 'The schema has clear foreign key relationships but may lack sufficient indexes.'
|
| 143 |
+
else:
|
| 144 |
+
summary['suggestions']['evaluation'] = 'Needs Improvement'
|
| 145 |
+
summary['suggestions']['note'] = 'The schema lacks explicit foreign key constraints, which may affect query reliability.'
|
| 146 |
+
|
| 147 |
+
# Recommendations
|
| 148 |
+
if not has_foreign_keys:
|
| 149 |
+
summary['suggestions']['recommendations'].append('Add explicit foreign key constraints to ensure data integrity.')
|
| 150 |
+
if not has_indexes:
|
| 151 |
+
summary['suggestions']['recommendations'].append('Add indexes on frequently queried columns (e.g., foreign keys, date fields) to improve performance.')
|
| 152 |
+
summary['suggestions']['recommendations'].append('Verify that date and numeric fields use appropriate data types for efficient querying.')
|
| 153 |
+
|
| 154 |
+
cursor.close()
|
| 155 |
+
conn.close()
|
| 156 |
+
except Error as e:
|
| 157 |
+
summary['suggestions']['note'] = f'Analysis limited due to: {str(e)}'
|
| 158 |
+
if not summary['relationships']:
|
| 159 |
+
summary['relationships'] = ['Unable to detect relationships due to limited metadata access.']
|
| 160 |
+
|
| 161 |
+
return summary
|
| 162 |
+
|
| 163 |
+
def load_sql_file(file):
|
| 164 |
+
"""Load SQL file into MySQL database and generate schema summary."""
|
| 165 |
+
global current_db_name, current_schema, current_summary
|
| 166 |
+
try:
|
| 167 |
+
file_content = file.read()
|
| 168 |
+
db_name, statements = parse_sql_file(file_content)
|
| 169 |
+
|
| 170 |
+
# Connect without specifying a database
|
| 171 |
+
conn, error = get_db_connection()
|
| 172 |
+
if error:
|
| 173 |
+
return False, error, None
|
| 174 |
+
cursor = conn.cursor()
|
| 175 |
+
|
| 176 |
+
# Drop existing database if it exists
|
| 177 |
+
cursor.execute(f"DROP DATABASE IF EXISTS `{db_name}`")
|
| 178 |
+
cursor.execute(f"CREATE DATABASE `{db_name}`")
|
| 179 |
+
conn.commit()
|
| 180 |
+
cursor.close()
|
| 181 |
+
conn.close()
|
| 182 |
+
|
| 183 |
+
# Connect to the new database
|
| 184 |
+
conn, error = get_db_connection(db_name)
|
| 185 |
+
if error:
|
| 186 |
+
return False, error, None
|
| 187 |
+
cursor = conn.cursor()
|
| 188 |
+
|
| 189 |
+
# Execute SQL statements
|
| 190 |
+
for statement in statements:
|
| 191 |
+
cursor.execute(statement)
|
| 192 |
+
conn.commit()
|
| 193 |
+
|
| 194 |
+
# Extract schema
|
| 195 |
+
cursor.execute("SHOW TABLES")
|
| 196 |
+
tables = [row[0] for row in cursor.fetchall()]
|
| 197 |
+
schema = {}
|
| 198 |
+
for table in tables:
|
| 199 |
+
cursor.execute(f"SHOW COLUMNS FROM `{table}`")
|
| 200 |
+
columns = [row[0] for row in cursor.fetchall()]
|
| 201 |
+
schema[table] = columns
|
| 202 |
+
|
| 203 |
+
# Generate summary
|
| 204 |
+
summary = generate_schema_summary(schema, db_name)
|
| 205 |
+
|
| 206 |
+
current_db_name = db_name
|
| 207 |
+
current_schema = schema
|
| 208 |
+
current_summary = summary
|
| 209 |
+
|
| 210 |
+
cursor.close()
|
| 211 |
+
conn.close()
|
| 212 |
+
return True, schema, summary
|
| 213 |
+
except Error as e:
|
| 214 |
+
return False, f"Failed to load SQL file: {str(e)}", None
|
| 215 |
+
|
| 216 |
+
def generate_sql_query(question, schema):
|
| 217 |
+
"""Generate SQL query using Groq API with user-friendly aliases."""
|
| 218 |
+
schema_text = "\n".join([f"Table: {table}\nColumns: {', '.join(columns)}" for table, columns in schema.items()])
|
| 219 |
+
prompt = f"""
|
| 220 |
+
You are a SQL expert. Based on the following database schema, generate a valid MySQL query for the user's question. Only use tables and columns that exist in the schema. Use user-friendly aliases for column names (e.g., 'cust_id' becomes 'Customer ID', 'admission_date' becomes 'Admission Date'). Return ONLY the SQL query, without explanations, markdown, or code block formatting (e.g., no ```). If the question references non-existent tables or columns, return an error message starting with 'ERROR:'. Do not use GROUP BY or aggregation functions (e.g., SUM, COUNT, AVG) unless the question explicitly requests aggregation (e.g., 'sum of all bills', 'average cost', 'count of patients'). Treat 'total bill amount' as the individual bill amount (e.g., bill.amount) unless aggregation is clearly specified. For names, concatenate first_name and last_name if applicable (e.g., CONCAT(first_name, ' ', last_name) AS 'Full Name'). Use direct JOINs with correct foreign key relationships. Avoid subqueries unless absolutely necessary. Place filtering conditions (e.g., department name, status) in the WHERE clause, not JOIN clauses. Handle case sensitivity in string comparisons by using LOWER() for status fields (e.g., LOWER(status) = 'unpaid'). Verify table relationships before joining.
|
| 221 |
+
|
| 222 |
+
Schema:
|
| 223 |
+
{schema_text}
|
| 224 |
+
|
| 225 |
+
User Question: {question}
|
| 226 |
+
"""
|
| 227 |
+
try:
|
| 228 |
+
response = groq_client.chat.completions.create(
|
| 229 |
+
messages=[{"role": "user", "content": prompt}],
|
| 230 |
+
model="llama3-70b-8192"
|
| 231 |
+
)
|
| 232 |
+
query = response.choices[0].message.content.strip()
|
| 233 |
+
query = re.sub(r'```(?:sql)?\n?', '', query) # Remove any markdown
|
| 234 |
+
query = query.strip()
|
| 235 |
+
return query
|
| 236 |
+
except Exception as e:
|
| 237 |
+
return f"ERROR: Failed to generate SQL query: {str(e)}"
|
| 238 |
+
|
| 239 |
+
def execute_sql_query(query):
|
| 240 |
+
"""Execute SQL query on the current database."""
|
| 241 |
+
if not current_db_name:
|
| 242 |
+
return False, "No database loaded. Please upload an SQL file.", None
|
| 243 |
+
conn, error = get_db_connection(current_db_name)
|
| 244 |
+
if error:
|
| 245 |
+
return False, error, None
|
| 246 |
+
try:
|
| 247 |
+
cursor = conn.cursor(dictionary=True)
|
| 248 |
+
cursor.execute(query)
|
| 249 |
+
results = cursor.fetchall()
|
| 250 |
+
conn.commit()
|
| 251 |
+
cursor.close()
|
| 252 |
+
conn.close()
|
| 253 |
+
return True, results, None
|
| 254 |
+
except Error as e:
|
| 255 |
+
return False, f"SQL execution failed: {str(e)}", None
|
| 256 |
+
|
| 257 |
+
@app.route('/', methods=['GET', 'POST'])
|
| 258 |
+
def index():
|
| 259 |
+
error = None
|
| 260 |
+
schema = current_schema
|
| 261 |
+
summary = current_summary
|
| 262 |
+
results = None
|
| 263 |
+
generated_query = None
|
| 264 |
+
|
| 265 |
+
if request.method == 'POST':
|
| 266 |
+
if 'sql_file' in request.files:
|
| 267 |
+
file = request.files['sql_file']
|
| 268 |
+
if file and file.filename.endswith('.sql'):
|
| 269 |
+
success, result, summary = load_sql_file(file)
|
| 270 |
+
if success:
|
| 271 |
+
schema = result
|
| 272 |
+
else:
|
| 273 |
+
error = result
|
| 274 |
+
else:
|
| 275 |
+
error = "Please upload a valid .sql file."
|
| 276 |
+
elif 'question' in request.form:
|
| 277 |
+
question = request.form['question']
|
| 278 |
+
if not current_db_name or not current_schema:
|
| 279 |
+
error = "No database loaded. Please upload an SQL file first."
|
| 280 |
+
else:
|
| 281 |
+
generated_query = generate_sql_query(question, current_schema)
|
| 282 |
+
if not generated_query.startswith('ERROR:'):
|
| 283 |
+
success, result, _ = execute_sql_query(generated_query)
|
| 284 |
+
if success:
|
| 285 |
+
results = result
|
| 286 |
+
else:
|
| 287 |
+
error = result
|
| 288 |
+
else:
|
| 289 |
+
error = generated_query
|
| 290 |
+
|
| 291 |
+
return render_template('index.html', error=error, schema=schema, summary=summary, results=results, query=generated_query)
|
| 292 |
+
|
| 293 |
+
@app.route('/configure_db', methods=['POST'])
|
| 294 |
+
def configure_db():
|
| 295 |
+
"""Handle MySQL connection configuration."""
|
| 296 |
+
host = request.form.get('host', '').strip()
|
| 297 |
+
user = request.form.get('user', '').strip()
|
| 298 |
+
password = request.form.get('password', '')
|
| 299 |
+
port = request.form.get('port', '3306').strip()
|
| 300 |
+
|
| 301 |
+
if not host or not user:
|
| 302 |
+
return render_template('index.html', error="Host and user are required.", schema=current_schema, summary=current_summary)
|
| 303 |
+
|
| 304 |
+
try:
|
| 305 |
+
port = int(port)
|
| 306 |
+
except ValueError:
|
| 307 |
+
return render_template('index.html', error="Port must be a valid number.", schema=current_schema, summary=current_summary)
|
| 308 |
+
|
| 309 |
+
# Test connection
|
| 310 |
+
test_config = {'host': host, 'user': user, 'password': password, 'port': port}
|
| 311 |
+
conn, error = get_db_connection()
|
| 312 |
+
if error:
|
| 313 |
+
return render_template('index.html', error=error, schema=current_schema, summary=current_summary)
|
| 314 |
+
|
| 315 |
+
# Store in session
|
| 316 |
+
session['db_config'] = test_config
|
| 317 |
+
conn.close()
|
| 318 |
+
return render_template('index.html', error=None, schema=current_schema, summary=current_summary, success="MySQL connection configured successfully.")
|
| 319 |
+
|
| 320 |
+
if __name__ == '__main__':
|
| 321 |
+
app.run(host='0.0.0.0', port=int(os.getenv('PORT', 5000)), debug=True)
|