Files

1 line
112 KiB
JSON

{"repo": "ayushx309/litedbadmin", "files": {"src/LiteDBAdmin/ajax_handler.php": {"840b1629bdd98baae5094e022313954fb1d7c92d": {"t": 1785746172.6137433, "n": 54789, "h": "63b2859e691afa69", "c": "<?php\nrequire_once './config.php';\nsession_start();\n\n\nif(!isset($_SESSION['dev_authenticated'])){\n header('Location: ../');\n exit();\n}\n\n\nif (isset($_GET['action'])) {\n $action = $_GET['action'];\n \n switch ($action) {\n case 'get_table_structure':\n getTableStructure();\n break;\n \n case 'get_table_data':\n getTableData();\n break;\n \n case 'get_query_suggestions':\n getQuerySuggestions();\n break;\n \n case 'change_database':\n changeDatabase();\n break;\n \n case 'get_database_schema':\n getDatabaseSchema();\n break;\n \n case 'execute_query':\n executeQuery();\n break;\n \n case 'nl_to_sql':\n naturalLanguageToSQL();\n break;\n \n default:\n header('Content-Type: application/json');\n echo json_encode(['error' => 'Invalid action']);\n break;\n }\n}\n\n/**\n * Get the structure of a specific table\n */\nfunction getTableStructure() {\n global $conn;\n \n if (!isset($_GET['table'])) {\n header('Content-Type: application/json');\n echo json_encode(['error' => 'Table name is required']);\n return;\n }\n \n $table = mysqli_real_escape_string($conn, $_GET['table']);\n $db = isset($_GET['db']) ? mysqli_real_escape_string($conn, $_GET['db']) : '';\n \n\n if (!empty($db)) {\n mysqli_select_db($conn, $db);\n }\n \n try {\n \n $query = \"DESCRIBE `$table`\";\n $result = mysqli_query($conn, $query);\n \n if (!$result) {\n header('Content-Type: application/json');\n echo json_encode(['error' => 'Error fetching table structure: ' . mysqli_error($conn)]);\n return;\n }\n \n $columns = [];\n while ($row = mysqli_fetch_assoc($result)) {\n $columns[] = $row;\n }\n \n \n $indexQuery = \"SHOW INDEX FROM `$table`\";\n $indexResult = mysqli_query($conn, $indexQuery);\n \n $indexes = [];\n if ($indexResult) {\n while ($row = mysqli_fetch_assoc($indexResult)) {\n $indexes[] = $row;\n }\n }\n \n header('Content-Type: application/json');\n echo json_encode([\n 'table' => $table,\n 'columns' => $columns,\n 'indexes' => $indexes\n ]);\n } catch (Exception $e) {\n header('Content-Type: application/json');\n echo json_encode(['error' => 'Error: ' . $e->getMessage()]);\n }\n}\n\n/**\n * Get data from a specific table with pagination\n */\nfunction getTableData() {\n global $conn;\n \n if (!isset($_GET['table'])) {\n header('Content-Type: application/json');\n echo json_encode(['error' => 'Table name is required']);\n return;\n }\n \n $table = mysqli_real_escape_string($conn, $_GET['table']);\n $db = isset($_GET['db']) ? mysqli_real_escape_string($conn, $_GET['db']) : '';\n $page = isset($_GET['page']) ? (int)$_GET['page'] : 1;\n $perPage = isset($_GET['per_page']) ? (int)$_GET['per_page'] : 50;\n \n\n if ($page < 1) $page = 1;\n if ($perPage < 10) $perPage = 10;\n if ($perPage > 1000) $perPage = 1000;\n \n $offset = ($page - 1) * $perPage;\n \n\n if (!empty($db)) {\n mysqli_select_db($conn, $db);\n }\n \n try {\n\n $countQuery = \"SELECT COUNT(*) as total FROM `$table`\";\n $countResult = mysqli_query($conn, $countQuery);\n $totalRows = 0;\n \n if ($countResult && $row = mysqli_fetch_assoc($countResult)) {\n $totalRows = $row['total'];\n }\n \n\n $query = \"SELECT * FROM `$table` LIMIT $offset, $perPage\";\n $result = mysqli_query($conn, $query);\n \n if (!$result) {\n header('Content-Type: application/json');\n echo json_encode(['error' => 'Error fetching table data: ' . mysqli_error($conn)]);\n return;\n }\n \n $data = [];\n while ($row = mysqli_fetch_assoc($result)) {\n $data[] = $row;\n }\n \n header('Content-Type: application/json');\n echo json_encode([\n 'table' => $table,\n 'data' => $data,\n 'pagination' => [\n 'page' => $page,\n 'per_page' => $perPage,\n 'total_rows' => $totalRows,\n 'total_pages' => ceil($totalRows / $perPage)\n ]\n ]);\n } catch (Exception $e) {\n header('Content-Type: application/json');\n echo json_encode(['error' => 'Error: ' . $e->getMessage()]);\n }\n}\n\n/**\n * Get SQL query suggestions based on context\n */\nfunction getQuerySuggestions() {\n global $conn;\n \n $partial = isset($_GET['partial']) ? $_GET['partial'] : '';\n $context = isset($_GET['context']) ? $_GET['context'] : '';\n $db = isset($_GET['db']) ? mysqli_real_escape_string($conn, $_GET['db']) : '';\n \n\n if (!empty($db)) {\n mysqli_select_db($conn, $db);\n }\n \n $suggestions = [];\n \n\n $keywords = ['SELECT', 'FROM', 'WHERE', 'GROUP BY', 'ORDER BY', 'HAVING', 'LIMIT', \n 'JOIN', 'INNER JOIN', 'LEFT JOIN', 'RIGHT JOIN', 'OUTER JOIN', 'INSERT INTO', \n 'VALUES', 'UPDATE', 'SET', 'DELETE FROM', 'CREATE TABLE', 'ALTER TABLE', \n 'DROP TABLE', 'CREATE INDEX', 'DROP INDEX', 'UNION', 'UNION ALL'];\n \n\n if (!empty($partial)) {\n $partial = strtoupper($partial);\n $keywords = array_filter($keywords, function($keyword) use ($partial) {\n return strpos($keyword, $partial) === 0;\n });\n }\n \n\n foreach ($keywords as $keyword) {\n $suggestions[] = [\n 'text' => $keyword,\n 'type' => 'keyword'\n ];\n }\n \n try {\n $query = \"SHOW TABLES\";\n $result = mysqli_query($conn, $query);\n \n if ($result) {\n while ($row = mysqli_fetch_array($result)) {\n $tableName = $row[0];\n if (empty($partial) || stripos($tableName, $partial) === 0) {\n $suggestions[] = [\n 'text' => $tableName,\n 'type' => 'table'\n ];\n }\n }\n }\n } catch (Exception $e) {\n // Silent catch - just don't add tables to suggestions\n }\n \n header('Content-Type: application/json');\n echo json_encode(['suggestions' => $suggestions]);\n}\n\n/**\n * Change the current database\n */\nfunction changeDatabase() {\n global $conn;\n \n if (!isset($_GET['db'])) {\n header('Content-Type: application/json');\n echo json_encode(['error' => 'Database name is required']);\n return;\n }\n \n $db = mysqli_real_escape_string($conn, $_GET['db']);\n \n try {\n\n $result = mysqli_select_db($conn, $db);\n \n if (!$result) {\n header('Content-Type: application/json');\n echo json_encode(['error' => 'Error changing database: ' . mysqli_error($conn)]);\n return;\n }\n \n\n $tablesQuery = \"SHOW TABLES\";\n $tablesResult = mysqli_query($conn, $tablesQuery);\n \n $tables = [];\n if ($tablesResult) {\n while ($row = mysqli_fetch_array($tablesResult)) {\n $tables[] = $row[0];\n }\n }\n \n header('Content-Type: application/json');\n echo json_encode([\n 'success' => true,\n 'database' => $db,\n 'tables' => $tables\n ]);\n } catch (Exception $e) {\n header('Content-Type: application/json');\n echo json_encode(['error' => 'Error: ' . $e->getMessage()]);\n }\n}\n\n/**\n * Get database schema including tables and relationships for visualization\n */\nfunction getDatabaseSchema() {\n global $conn;\n \n $database = $_GET['db'] ?? '';\n \n if (empty($database)) {\n echo json_encode(['error' => 'Database not specified']);\n exit;\n }\n \n try {\n $conn->select_db($database);\n \n \n $tables = [];\n $tablesResult = $conn->query(\"SHOW TABLES\");\n \n if ($tablesResult) {\n while ($row = $tablesResult->fetch_row()) {\n $tables[] = ['name' => $row[0]];\n }\n $tablesResult->free();\n }\n \n \n foreach ($tables as &$table) {\n $columns = [];\n $columnsResult = $conn->query(\"DESCRIBE `{$table['name']}`\");\n \n if ($columnsResult) {\n while ($row = $columnsResult->fetch_assoc()) {\n $columns[] = $row;\n }\n $columnsResult->free();\n }\n \n $table['columns'] = $columns;\n }\n \n // Get relationships using INFORMATION_SCHEMA\n $relationships = [];\n $relationshipsQuery = \"\n SELECT \n TABLE_NAME AS table_name,\n COLUMN_NAME AS column_name,\n REFERENCED_TABLE_NAME AS referenced_table_name,\n REFERENCED_COLUMN_NAME AS referenced_column_name\n FROM\n INFORMATION_SCHEMA.KEY_COLUMN_USAGE\n WHERE\n REFERENCED_TABLE_SCHEMA = '$database'\n AND REFERENCED_TABLE_NAME IS NOT NULL\n AND REFERENCED_COLUMN_NAME IS NOT NULL\n \";\n \n $relationshipsResult = $conn->query($relationshipsQuery);\n \n if ($relationshipsResult) {\n while ($row = $relationshipsResult->fetch_assoc()) {\n $relationships[] = [\n 'table' => $row['table_name'],\n 'column' => $row['column_name'],\n 'referenced_table' => $row['referenced_table_name'],\n 'referenced_column' => $row['referenced_column_name']\n ];\n }\n $relationshipsResult->free();\n }\n \n \n if (empty($relationships)) {\n \n foreach ($tables as $table) {\n if (empty($table['columns'])) continue;\n \n foreach ($table['columns'] as $column) {\n \n $columnName = $column['Field'];\n \n \n if (preg_match('/(.*?)_id$/', $columnName, $matches)) {\n $potentialTableName = $matches[1];\n \n \n $tableExists = false;\n $referencedTable = '';\n $referencedColumn = '';\n \n\n foreach ($tables as $t) {\n if ($t['name'] === $potentialTableName) {\n $tableExists = true;\n $referencedTable = $t['name'];\n break;\n }\n }\n \n \n if (!$tableExists) {\n foreach ($tables as $t) {\n if ($t['name'] === $potentialTableName . 's') {\n $tableExists = true;\n $referencedTable = $t['name'];\n break;\n }\n }\n }\n \n\n if (!$tableExists && substr($potentialTableName, -1) === 's') {\n $singularName = substr($potentialTableName, 0, -1);\n foreach ($tables as $t) {\n if ($t['name'] === $singularName) {\n $tableExists = true;\n $referencedTable = $t['name'];\n break;\n }\n }\n }\n \n if ($tableExists) {\n \n foreach ($tables as $t) {\n if ($t['name'] === $referencedTable) {\n foreach ($t['columns'] as $col) {\n if (isset($col['Key']) && $col['Key'] === 'PRI') {\n $referencedColumn = $col['Field'];\n break;\n }\n }\n \n \n if (empty($referencedColumn)) {\n $referencedColumn = 'id';\n }\n \n break;\n }\n }\n \n if (!empty($referencedColumn)) {\n $relationships[] = [\n 'table' => $table['name'],\n 'column' => $columnName,\n 'referenced_table' => $referencedTable,\n 'referenced_column' => $referencedColumn,\n 'inferred' => true\n ];\n }\n }\n }\n }\n }\n }\n \n\n $debugInfo = [\n 'tableCount' => count($tables),\n 'relationshipCount' => count($relationships),\n 'relatedTableNames' => array_unique(array_merge(\n array_column($relationships, 'table'),\n array_column($relationships, 'referenced_table')\n ))\n ];\n \n echo json_encode([\n 'tables' => $tables,\n 'relationships' => $relationships,\n 'debug' => $debugInfo\n ]);\n } catch (Exception $e) {\n echo json_encode(['error' => $e->getMessage()]);\n }\n}\n\n/**\n * Execute a custom SQL query\n */\nfunction executeQuery() {\n global $conn;\n \n header('Content-Type: application/json');\n \n\n if (!isset($_POST['query']) || empty($_POST['query'])) {\n echo json_encode(['error' => 'No query provided']);\n return;\n }\n \n $query = $_POST['query'];\n $database = isset($_POST['database']) ? $_POST['database'] : '';\n \n\n if (!empty($database)) {\n if (!mysqli_select_db($conn, $database)) {\n echo json_encode(['error' => 'Error selecting database: ' . mysqli_error($conn)]);\n return;\n }\n }\n \n try {\n\n $startTime = microtime(true);\n \n\n $result = mysqli_query($conn, $query);\n \n \n $endTime = microtime(true);\n $executionTime = round(($endTime - $startTime) * 1000, 2); // in milliseconds\n \n if ($result === false) {\n echo json_encode([\n 'error' => 'Query error: ' . mysqli_error($conn),\n 'query' => $query\n ]);\n return;\n }\n \n\n if ($result instanceof mysqli_result) {\n \n $data = [];\n $fields = [];\n \n \n $fieldInfo = mysqli_fetch_fields($result);\n foreach ($fieldInfo as $field) {\n $fields[] = $field->name;\n }\n \n \n while ($row = mysqli_fetch_assoc($result)) {\n $data[] = $row;\n }\n \n mysqli_free_result($result);\n \n echo json_encode([\n 'success' => true,\n 'isSelect' => true,\n 'fields' => $fields,\n 'data' => $data,\n 'rowCount' => count($data),\n 'executionTime' => $executionTime\n ]);\n } else {\n \n echo json_encode([\n 'success' => true,\n 'isSelect' => false,\n 'affectedRows' => mysqli_affected_rows($conn),\n 'insertId' => mysqli_insert_id($conn),\n 'executionTime' => $executionTime\n ]);\n }\n } catch (Exception $e) {\n echo json_encode([\n 'error' => 'Error: ' . $e->getMessage(),\n 'query' => $query\n ]);\n }\n}\n\n/**\n * Convert natural language to SQL query\n * This function takes a natural language description and converts it to a SQL query\n */\nfunction naturalLanguageToSQL() {\n global $conn;\n \n header('Content-Type: application/json');\n \n\n if (!isset($_POST['nl_query']) || empty($_POST['nl_query'])) {\n echo json_encode(['error' => 'No natural language query provided']);\n return;\n }\n \n $nlQuery = $_POST['nl_query'];\n $database = isset($_POST['database']) ? $_POST['database'] : '';\n \n\n $useAI = isset($_POST['use_ai']) && $_POST['use_ai'] === 'true';\n $apiKey = isset($_POST['api_key']) ? $_POST['api_key'] : '';\n $apiModel = isset($_POST['api_model']) ? $_POST['api_model'] : 'gpt-3.5-turbo';\n $apiProvider = isset($_POST['api_provider']) ? $_POST['api_provider'] : 'openai';\n \n\n if ($useAI && empty($apiKey) && $apiProvider !== 'deepseek-free') {\n echo json_encode(['error' => 'API key is required when using AI']);\n return;\n }\n \n \n if (!empty($database)) {\n if (!mysqli_select_db($conn, $database)) {\n echo json_encode(['error' => 'Error selecting database: ' . mysqli_error($conn)]);\n return;\n }\n }\n \n try {\n\n $tables = [];\n $tableColumns = [];\n \n \n $tablesResult = mysqli_query($conn, \"SHOW TABLES\");\n if ($tablesResult) {\n while ($tableRow = mysqli_fetch_row($tablesResult)) {\n $tableName = $tableRow[0];\n $tables[] = $tableName;\n \n \n $columnsResult = mysqli_query($conn, \"SHOW COLUMNS FROM `$tableName`\");\n if ($columnsResult) {\n $tableColumns[$tableName] = [];\n while ($columnRow = mysqli_fetch_assoc($columnsResult)) {\n $tableColumns[$tableName][] = $columnRow;\n }\n }\n }\n }\n \n\n $schemaString = generateSchemaString($tables, $tableColumns);\n \n\n if ($useAI) {\n \n $result = generateSQLWithAI($nlQuery, $schemaString, $tables, $tableColumns, $apiKey, $apiModel, $apiProvider);\n $sqlQuery = $result['sql_query'];\n $explanation = $result['explanation'];\n } else {\n\n $sqlQuery = generateSQLFromNaturalLanguage($nlQuery, $tables, $tableColumns);\n $explanation = explainQueryGeneration($nlQuery, $sqlQuery);\n }\n \n echo json_encode([\n 'success' => true,\n 'natural_language_query' => $nlQuery,\n 'sql_query' => $sqlQuery,\n 'tables' => $tables,\n 'explanation' => $explanation,\n 'ai_used' => $useAI\n ]);\n } catch (Exception $e) {\n echo json_encode([\n 'error' => 'Error: ' . $e->getMessage(),\n 'natural_language_query' => $nlQuery\n ]);\n }\n}\n\n/**\n * Convert database schema to a string representation for AI context\n */\nfunction generateSchemaString($tables, $tableColumns) {\n $schemaString = \"Database Schema:\\n\\n\";\n \n foreach ($tables as $table) {\n $schemaString .= \"Table: {$table}\\n\";\n $schemaString .= \"Columns:\\n\";\n \n if (!empty($tableColumns[$table])) {\n foreach ($tableColumns[$table] as $column) {\n $isPrimary = isset($column['Key']) && $column['Key'] === 'PRI' ? ' (Primary Key)' : '';\n $isNull = $column['Null'] === 'YES' ? ' NULL' : ' NOT NULL';\n $default = isset($column['Default']) && $column['Default'] !== null ? \" Default: {$column['Default']}\" : '';\n \n $schemaString .= \"- {$column['Field']} ({$column['Type']}){$isPrimary}{$isNull}{$default}\\n\";\n }\n }\n \n $schemaString .= \"\\n\";\n }\n \n return $schemaString;\n}\n\n/**\n * Generate SQL using an AI API\n */\nfunction generateSQLWithAI($nlQuery, $schemaString, $tables, $tableColumns, $apiKey, $apiModel, $apiProvider) {\n\n \n // System message for the AI\n $systemMessage = \"You are an elite-level SQL architect and database optimization specialist with expertise in enterprise-scale database systems, query planning, and performance tuning. \";\n $systemMessage .= \"Your task is to convert natural language descriptions into sophisticated, highly optimized SQL queries that follow industry best practices. \";\n $systemMessage .= \"Below is the database schema you should use to generate the SQL query:\\n\\n\";\n $systemMessage .= $schemaString;\n \n $systemMessage .= \"\\n\\n## ADVANCED QUERY GENERATION DIRECTIVES ##\";\n \n $systemMessage .= \"\\n\\n### Schema Analysis & Optimization ###\";\n $systemMessage .= \"\\n- Analyze relationships between tables to determine optimal join strategies\";\n $systemMessage .= \"\\n- Consider available indexes to optimize query execution paths\";\n $systemMessage .= \"\\n- Identify and leverage primary and foreign key relationships\";\n $systemMessage .= \"\\n- Use table aliases to improve query readability and prevent ambiguity\";\n \n $systemMessage .= \"\\n\\n### Query Construction Excellence ###\";\n $systemMessage .= \"\\n- Choose between subqueries, CTEs (WITH clause), or JOINs based on performance characteristics\";\n $systemMessage .= \"\\n- Implement appropriate query hints when beneficial for performance\";\n $systemMessage .= \"\\n- Use EXISTS/NOT EXISTS, IN/NOT IN, or joins appropriately based on data distribution patterns\";\n $systemMessage .= \"\\n- Consider UNION vs. UNION ALL based on need for duplicate elimination\";\n $systemMessage .= \"\\n- Optimize aggregation with GROUP BY clauses using the minimal necessary columns\";\n $systemMessage .= \"\\n- Implement window functions (ROW_NUMBER, RANK, etc.) for sophisticated data analysis\";\n $systemMessage .= \"\\n- Apply advanced filtering techniques like dynamic pivoting or hierarchical queries when appropriate\";\n \n $systemMessage .= \"\\n\\n### Data Integrity & Security ###\";\n $systemMessage .= \"\\n- Prevent SQL injection by properly parametrizing user inputs\";\n $systemMessage .= \"\\n- Include appropriate transaction isolation levels for multi-statement operations\";\n $systemMessage .= \"\\n- Implement appropriate error handling and graceful fallbacks\";\n $systemMessage .= \"\\n- Consider ACID properties when designing transaction-based queries\";\n \n $systemMessage .= \"\\n\\n### Performance Tuning ###\";\n $systemMessage .= \"\\n- Minimize full table scans and optimize for index usage\";\n $systemMessage .= \"\\n- Avoid unnecessary columns in SELECT statements\";\n $systemMessage .= \"\\n- Consider data volume when choosing between aggregation methods\";\n $systemMessage .= \"\\n- Use appropriate LIMIT/OFFSET for pagination with optimized execution\";\n $systemMessage .= \"\\n- Anticipate and mitigate potential bottlenecks in complex joins or aggregations\";\n $systemMessage .= \"\\n- Consider query cache implications with appropriate cache hints if supported\";\n \n $systemMessage .= \"\\n\\n### Error Correction & Enhancement ###\";\n $systemMessage .= \"\\n- Identify and fix potential logical errors in the user's request\";\n $systemMessage .= \"\\n- Detect ambiguities in natural language and resolve with the most likely intent\";\n $systemMessage .= \"\\n- Provide alternative query approaches when multiple valid interpretations exist\";\n $systemMessage .= \"\\n- When encountering incomplete requests, make reasonable assumptions and document them\";\n $systemMessage .= \"\\n- Include thorough commenting of complex logic or assumptions made\";\n \n $systemMessage .= \"\\n\\n### Response Format ###\";\n $systemMessage .= \"\\nYou MUST format your response as a JSON object with EXACTLY these two properties:\";\n $systemMessage .= \"\\n1. 'sql_query': A string containing ONLY the complete SQL query with detailed inline comments\";\n $systemMessage .= \"\\n2. 'explanation': A string containing a comprehensive explanation\";\n \n $systemMessage .= \"\\n\\nIMPORTANT: Your response MUST be valid JSON. Do not include any text outside the JSON object.\";\n $systemMessage .= \"\\nFormat example:\";\n $systemMessage .= \"\\n```json\";\n $systemMessage .= \"\\n{\";\n $systemMessage .= \"\\n \\\"sql_query\\\": \\\"SELECT * FROM users WHERE status = 'active' LIMIT 10;\\\",\";\n $systemMessage .= \"\\n \\\"explanation\\\": \\\"This query retrieves active users with a limit of 10 records.\\\"\";\n $systemMessage .= \"\\n}\";\n $systemMessage .= \"\\n```\";\n \n $systemMessage .= \"\\n\\nPlease note that in the actual response, you should NOT include the ```json and ``` markers - your response should ONLY be the JSON object itself.\";\n $systemMessage .= \"\\n\\nEnsure the SQL follows MySQL best practices and optimization techniques. Your goal is to create production-ready, maintainable, and highly efficient queries.\";\n \n // Create the user message with additional context extraction\n $userMessage = \"Generate an optimal MySQL query for the following request. If my request contains any errors or ambiguities, please correct them: {$nlQuery}\";\n \n\n $apiResult = null;\n try {\n switch ($apiProvider) {\n case 'openai':\n $apiResult = callOpenAI($systemMessage, $userMessage, $apiKey, $apiModel, $tables);\n break;\n \n case 'claude':\n $apiResult = callClaude($systemMessage, $userMessage, $apiKey, $apiModel, $tables);\n break;\n \n case 'gemini':\n $apiResult = callGemini($systemMessage, $userMessage, $apiKey, $apiModel, $tables);\n break;\n \n case 'mistral':\n $apiResult = callMistral($systemMessage, $userMessage, $apiKey, $apiModel, $tables);\n break;\n \n case 'deepseek':\n $apiResult = callDeepSeek($systemMessage, $userMessage, $apiKey, $apiModel, $tables);\n break;\n \n case 'deepseek-free':\n $apiResult = callDeepSeekFree($systemMessage, $userMessage, $tables);\n break;\n \n case 'llama':\n $apiResult = callLlama($systemMessage, $userMessage, $apiKey, $apiModel, $tables);\n break;\n \n default:\n \n $apiResult = callOpenAI($systemMessage, $userMessage, $apiKey, $apiModel, $tables);\n break;\n }\n \n \n if (is_array($apiResult) && !isset($apiResult['provider'])) {\n $apiResult['provider'] = $apiProvider;\n }\n \n return $apiResult;\n \n } catch (Exception $e) {\n \n return [\n 'sql_query' => \"-- Error from {$apiProvider} API\\n-- \" . $e->getMessage() . \"\\nSELECT * FROM \" . ($tables[0] ?? 'unknown_table') . \" LIMIT 10;\",\n 'explanation' => \"Error while generating SQL with {$apiProvider}: \" . $e->getMessage() . \". Using a safe fallback query.\",\n 'provider' => $apiProvider,\n 'error' => true\n ];\n }\n}\n\n/**\n * Call OpenAI API to generate SQL\n */\nfunction callOpenAI($systemMessage, $userMessage, $apiKey, $apiModel, $tables) {\n\n $data = [\n 'model' => $apiModel,\n 'messages' => [\n ['role' => 'system', 'content' => $systemMessage],\n ['role' => 'user', 'content' => $userMessage]\n ],\n 'temperature' => 0.3,\n 'max_tokens' => 1500,\n 'response_format' => ['type' => 'json_object'] \n ];\n \n\n $ch = curl_init('https://api.openai.com/v1/chat/completions');\n \n\n curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n curl_setopt($ch, CURLOPT_POST, true);\n curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));\n curl_setopt($ch, CURLOPT_HTTPHEADER, [\n 'Content-Type: application/json',\n 'Authorization: Bearer ' . $apiKey\n ]);\n \n // SECURITY NOTE: SSL verification is disabled to handle environments with missing or outdated certificates.\n // In production, consider enabling proper SSL verification and installing required certificates.\n curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);\n curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);\n \n\n $response = curl_exec($ch);\n \n\n if (curl_errno($ch)) {\n $error = curl_error($ch);\n curl_close($ch);\n throw new Exception('cURL error: ' . $error);\n }\n \n\n $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);\n curl_close($ch);\n \n\n if ($httpCode >= 400) {\n throw new Exception('HTTP error ' . $httpCode . ': OpenAI API request failed. Response: ' . substr($response, 0, 200));\n }\n \n\n $responseData = json_decode($response, true);\n \n \n if (isset($responseData['error'])) {\n throw new Exception('OpenAI API error: ' . ($responseData['error']['message'] ?? json_encode($responseData['error'])));\n }\n\n if (isset($responseData['choices'][0]['message']['content'])) {\n $content = $responseData['choices'][0]['message']['content'];\n return parseAIResponse($content, $tables);\n } else {\n throw new Exception('Invalid response format from OpenAI API: ' . json_encode($responseData));\n }\n}\n\n/**\n * Call Claude API to generate SQL\n */\nfunction callClaude($systemMessage, $userMessage, $apiKey, $apiModel, $tables) {\n\n $data = [\n 'model' => $apiModel,\n 'system' => $systemMessage,\n 'messages' => [\n ['role' => 'user', 'content' => $userMessage]\n ],\n 'temperature' => 0.3,\n 'max_tokens' => 1500,\n 'anthropic_version' => '2023-06-01'\n ];\n \n \n $ch = curl_init('https://api.anthropic.com/v1/messages');\n \n // Set cURL options\n curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n curl_setopt($ch, CURLOPT_POST, true);\n curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));\n curl_setopt($ch, CURLOPT_HTTPHEADER, [\n 'Content-Type: application/json',\n 'x-api-key: ' . $apiKey,\n 'anthropic-version: 2023-06-01'\n ]);\n \n // SECURITY NOTE: SSL verification is disabled to handle environments with missing or outdated certificates.\n // In production, consider enabling proper SSL verification and installing required certificates.\n curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);\n curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);\n \n \n $response = curl_exec($ch);\n \n \n if (curl_errno($ch)) {\n $error = curl_error($ch);\n curl_close($ch);\n throw new Exception('cURL error: ' . $error);\n }\n \n \n $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);\n curl_close($ch);\n \n \n if ($httpCode >= 400) {\n throw new Exception('HTTP error ' . $httpCode . ': Claude API request failed. Response: ' . substr($response, 0, 200));\n }\n \n \n $responseData = json_decode($response, true);\n \n \n if (isset($responseData['error'])) {\n throw new Exception('Claude API error: ' . ($responseData['error']['message'] ?? json_encode($responseData['error'])));\n }\n \n \n $content = '';\n if (isset($responseData['content']) && is_array($responseData['content']) && !empty($responseData['content'])) {\n foreach ($responseData['content'] as $part) {\n if (isset($part['text'])) {\n $content .= $part['text'];\n }\n }\n \n \n if (preg_match('/\\{\\s*\"sql_query\"\\s*:.*\"explanation\"\\s*:.*\\}/s', $content, $matches)) {\n $content = $matches[0];\n }\n \n return parseAIResponse($content, $tables);\n } else {\n \n throw new Exception('Invalid response format from Claude API: ' . json_encode($responseData));\n }\n}\n\n/**\n * Call Google Gemini API to generate SQL\n */\nfunction callGemini($systemMessage, $userMessage, $apiKey, $apiModel, $tables) {\n \n $prompt = $systemMessage . \"\\n\\n\" . $userMessage;\n \n\n $isGemini2 = (strpos($apiModel, 'gemini-2') === 0);\n \n\n if ($isGemini2) {\n // Gemini 2.0 format with system instruction\n $data = [\n 'contents' => [\n [\n 'role' => 'user',\n 'parts' => [\n ['text' => $userMessage]\n ]\n ]\n ],\n 'systemInstruction' => [\n 'parts' => [\n ['text' => $systemMessage]\n ]\n ],\n 'generationConfig' => [\n 'temperature' => 0.3,\n 'maxOutputTokens' => 1000\n ]\n ];\n } else {\n // Original Gemini format (gemini-pro, gemini-ultra, etc.)\n $data = [\n 'contents' => [\n [\n 'parts' => [\n ['text' => $prompt]\n ]\n ]\n ],\n 'generationConfig' => [\n 'temperature' => 0.3,\n 'maxOutputTokens' => 1000\n ]\n ];\n }\n \n \n $ch = curl_init(\"https://generativelanguage.googleapis.com/v1beta/models/{$apiModel}:generateContent?key={$apiKey}\");\n \n \n curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n curl_setopt($ch, CURLOPT_POST, true);\n curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));\n curl_setopt($ch, CURLOPT_HTTPHEADER, [\n 'Content-Type: application/json'\n ]);\n \n // SECURITY NOTE: SSL verification is disabled to handle environments with missing or outdated certificates.\n // In production, consider enabling proper SSL verification and installing required certificates.\n curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);\n curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);\n \n \n $response = curl_exec($ch);\n \n \n if (curl_errno($ch)) {\n $error = curl_error($ch);\n curl_close($ch);\n throw new Exception('cURL error: ' . $error);\n }\n \n \n $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);\n curl_close($ch);\n \n \n if ($httpCode >= 400) {\n throw new Exception('HTTP error ' . $httpCode . ': Gemini API request failed. Response: ' . substr($response, 0, 200));\n }\n \n \n $responseData = json_decode($response, true);\n \n \n if (isset($responseData['error'])) {\n throw new Exception('Gemini API error: ' . ($responseData['error']['message'] ?? json_encode($responseData['error'])));\n }\n \n \n $content = '';\n \n\n if (isset($responseData['candidates'][0]['content']['parts'][0]['text'])) {\n $content = $responseData['candidates'][0]['content']['parts'][0]['text'];\n } else {\n\n $content = json_encode($responseData);\n }\n \n return parseAIResponse($content, $tables);\n}\n\n/**\n * Call DeepSeek API with API key to generate SQL\n */\nfunction callDeepSeek($systemMessage, $userMessage, $apiKey, $apiModel, $tables) {\n\n $data = [\n 'model' => $apiModel,\n 'messages' => [\n ['role' => 'system', 'content' => $systemMessage],\n ['role' => 'user', 'content' => $userMessage]\n ],\n 'temperature' => 0.3,\n 'max_tokens' => 1000\n ];\n \n\n $ch = curl_init('https://api.deepseek.com/v1/chat/completions');\n \n\n curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n curl_setopt($ch, CURLOPT_POST, true);\n curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));\n curl_setopt($ch, CURLOPT_HTTPHEADER, [\n 'Content-Type: application/json',\n 'Authorization: Bearer ' . $apiKey\n ]);\n \n\n curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);\n curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);\n \n\n $response = curl_exec($ch);\n \n\n if (curl_errno($ch)) {\n $error = curl_error($ch);\n curl_close($ch);\n throw new Exception('cURL error: ' . $error);\n }\n \n \n $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);\n curl_close($ch);\n \n \n if ($httpCode >= 400) {\n throw new Exception('HTTP error ' . $httpCode . ': DeepSeek API request failed. Response: ' . substr($response, 0, 200));\n }\n \n \n $responseData = json_decode($response, true);\n \n \n if (isset($responseData['error'])) {\n throw new Exception('DeepSeek API error: ' . ($responseData['error']['message'] ?? json_encode($responseData['error'])));\n }\n \n \n $content = '';\n \n if (isset($responseData['choices'][0]['message']['content'])) {\n $content = $responseData['choices'][0]['message']['content'];\n } else {\n\n $content = json_encode($responseData);\n }\n \n return parseAIResponse($content, $tables);\n}\n\n/**\n * Call Mistral API to generate SQL\n */\nfunction callMistral($systemMessage, $userMessage, $apiKey, $apiModel, $tables) {\n\n $data = [\n 'model' => $apiModel,\n 'messages' => [\n ['role' => 'system', 'content' => $systemMessage],\n ['role' => 'user', 'content' => $userMessage]\n ],\n 'temperature' => 0.3,\n 'max_tokens' => 1000\n ];\n \n\n $ch = curl_init('https://api.mistral.ai/v1/chat/completions');\n \n \n curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n curl_setopt($ch, CURLOPT_POST, true);\n curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));\n curl_setopt($ch, CURLOPT_HTTPHEADER, [\n 'Content-Type: application/json',\n 'Authorization: Bearer ' . $apiKey\n ]);\n \n // SECURITY NOTE: SSL verification is disabled to handle environments with missing or outdated certificates.\n // In production, consider enabling proper SSL verification and installing required certificates.\n curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);\n curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);\n \n\n $response = curl_exec($ch);\n \n \n if (curl_errno($ch)) {\n $error = curl_error($ch);\n curl_close($ch);\n throw new Exception('cURL error: ' . $error);\n }\n \n\n $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);\n curl_close($ch);\n \n\n if ($httpCode >= 400) {\n throw new Exception('HTTP error ' . $httpCode . ': Mistral API request failed. Response: ' . substr($response, 0, 200));\n }\n \n\n $responseData = json_decode($response, true);\n \n\n if (isset($responseData['error'])) {\n throw new Exception('Mistral API error: ' . ($responseData['error']['message'] ?? json_encode($responseData['error'])));\n }\n \n\n $content = '';\n \n if (isset($responseData['choices'][0]['message']['content'])) {\n $content = $responseData['choices'][0]['message']['content'];\n } else {\n\n $content = json_encode($responseData);\n }\n \n return parseAIResponse($content, $tables);\n}\n\n/**\n * Call Llama API to generate SQL\n */\nfunction callLlama($systemMessage, $userMessage, $apiKey, $apiModel, $tables) {\n\n $data = [\n 'model' => $apiModel,\n 'messages' => [\n ['role' => 'system', 'content' => $systemMessage],\n ['role' => 'user', 'content' => $userMessage]\n ],\n 'temperature' => 0.3,\n 'max_tokens' => 1000\n ];\n\n $ch = curl_init('https://api.llama-api.com/v1/chat/completions');\n \n\n curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n curl_setopt($ch, CURLOPT_POST, true);\n curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));\n curl_setopt($ch, CURLOPT_HTTPHEADER, [\n 'Content-Type: application/json',\n 'Authorization: Bearer ' . $apiKey\n ]);\n \n // SECURITY NOTE: SSL verification is disabled to handle environments with missing or outdated certificates.\n // In production, consider enabling proper SSL verification and installing required certificates.\n curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);\n curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);\n \n // Execute cURL request\n $response = curl_exec($ch);\n \n\n if (curl_errno($ch)) {\n $error = curl_error($ch);\n curl_close($ch);\n throw new Exception('cURL error: ' . $error);\n }\n \n\n $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);\n curl_close($ch);\n \n\n if ($httpCode >= 400) {\n throw new Exception('HTTP error ' . $httpCode . ': Llama API request failed. Response: ' . substr($response, 0, 200));\n }\n \n \n $responseData = json_decode($response, true);\n \n\n if (isset($responseData['error'])) {\n throw new Exception('Llama API error: ' . ($responseData['error']['message'] ?? json_encode($responseData['error'])));\n }\n \n\n $content = '';\n \n if (isset($responseData['choices'][0]['message']['content'])) {\n $content = $responseData['choices'][0]['message']['content'];\n } else {\n\n $content = json_encode($responseData);\n }\n \n return parseAIResponse($content, $tables);\n}\n\n/**\n * Parse AI response to extract SQL query and explanation\n */\nfunction parseAIResponse($content, $tables) {\n \n if (empty($content)) {\n return [\n 'sql_query' => \"SELECT * FROM \" . ($tables[0] ?? 'unknown_table') . \" LIMIT 10; -- AI response was empty\",\n 'explanation' => \"The AI didn't provide a valid response. Using a default query instead.\"\n ];\n }\n \n \n try {\n \n $content = trim($content);\n \n \n $content = preg_replace('/^```(?:json)?|```$/m', '', $content);\n \n \n $parsedResponse = json_decode($content, true);\n \n if (json_last_error() === JSON_ERROR_NONE && isset($parsedResponse['sql_query'])) {\n \n return [\n 'sql_query' => $parsedResponse['sql_query'],\n 'explanation' => $parsedResponse['explanation'] ?? \"The AI generated this SQL query based on your request.\"\n ];\n }\n \n \n if (preg_match('/\\{[\\s\\S]*?\\}/m', $content, $jsonMatches)) {\n $jsonContent = $jsonMatches[0];\n $parsedJson = json_decode($jsonContent, true);\n \n if (json_last_error() === JSON_ERROR_NONE && isset($parsedJson['sql_query'])) {\n return [\n 'sql_query' => $parsedJson['sql_query'],\n 'explanation' => $parsedJson['explanation'] ?? \"The AI generated this SQL query based on your request.\"\n ];\n }\n }\n \n \n if (preg_match('/```(?:sql)?\\s*([\\s\\S]*?)```/m', $content, $sqlMatches)) {\n $sql = trim($sqlMatches[1]);\n \n // Try to find explanation\n if (preg_match('/(?:explanation|here\\'s why|reasoning)(?:\\s*:|)\\s*([\\s\\S]*?)(?=```|$)/mi', $content, $explMatches)) {\n $explanation = trim($explMatches[1]);\n } else {\n $explanation = \"The AI generated a SQL query based on your request.\";\n }\n \n return [\n 'sql_query' => $sql,\n 'explanation' => $explanation\n ];\n }\n \n \n if (preg_match('/(SELECT|INSERT\\s+INTO|UPDATE|DELETE\\s+FROM|CREATE\\s+TABLE|ALTER\\s+TABLE|DROP\\s+TABLE|CREATE\\s+INDEX)\\s+[\\s\\S]*?;/mi', $content, $sqlMatches)) {\n $sql = trim($sqlMatches[0]);\n \n \n $contentParts = explode($sql, $content, 2);\n $explanation = !empty($contentParts[1]) ? trim($contentParts[1]) : \"Extracted SQL query from the AI response.\";\n \n return [\n 'sql_query' => $sql,\n 'explanation' => $explanation\n ];\n }\n \n \n if (preg_match('/[A-Za-z_][A-Za-z0-9_\\s\\.\\,\\(\\)\\=\\'\\\"\\`\\*\\+\\-\\/\\<\\>\\!\\%]*;/m', $content, $sqlMatches)) {\n $sql = trim($sqlMatches[0]);\n \n \n if (preg_match('/(select|from|where|order by|group by|having|limit|join|insert|update|delete|create|alter|drop)/i', $sql)) {\n return [\n 'sql_query' => $sql,\n 'explanation' => \"Extracted SQL query from the AI response text.\"\n ];\n }\n }\n \n \n return [\n 'sql_query' => \"SELECT * FROM \" . ($tables[0] ?? 'unknown_table') . \" LIMIT 10; -- Could not extract SQL from AI response\",\n 'explanation' => \"The AI response did not contain a valid SQL query. Using a default query instead.\\nOriginal response: \" . substr($content, 0, 100) . \"...\"\n ];\n } catch (Exception $e) {\n \n return [\n 'sql_query' => \"SELECT * FROM \" . ($tables[0] ?? 'unknown_table') . \" LIMIT 10; -- Error parsing AI response\",\n 'explanation' => \"Error parsing the AI response: \" . $e->getMessage() . \". Using a default query instead.\"\n ];\n }\n}\n\n/**\n * Generate SQL from natural language query\n * This is a pattern matching approach for common query patterns\n */\nfunction generateSQLFromNaturalLanguage($nlQuery, $tables, $tableColumns) {\n \n $nlQuery = trim(strtolower($nlQuery));\n \n\n $queryType = 'SELECT';\n $selectColumns = '*';\n $whereClause = '';\n $orderByClause = '';\n $limitClause = '';\n $joinClause = '';\n $groupByClause = '';\n $havingClause = '';\n \n \n $mainTable = findMainTable($nlQuery, $tables);\n $fromClause = \"`$mainTable`\";\n \n\n if (preg_match('/\\b(show|list|get|display|select|find|search|query|fetch|retrieve)\\b/', $nlQuery)) {\n $queryType = 'SELECT';\n \n \n if (preg_match('/\\b(count|how many)\\b/', $nlQuery)) {\n $selectColumns = \"COUNT(*)\";\n \n if (preg_match('/\\bdistinct\\b/', $nlQuery)) {\n \n foreach ($tableColumns[$mainTable] as $colInfo) {\n $colName = $colInfo['Field'];\n if (stripos($nlQuery, $colName) !== false) {\n $selectColumns = \"COUNT(DISTINCT `$colName`)\";\n break;\n }\n }\n }\n } else {\n \n $columnsToSelect = [];\n if (isset($tableColumns[$mainTable])) {\n foreach ($tableColumns[$mainTable] as $colInfo) {\n $colName = $colInfo['Field'];\n \n if (($colName === 'id' || preg_match('/_id$/', $colName)) && \n !preg_match('/\\bid\\b|\\bidentifier\\b/', $nlQuery)) {\n continue;\n }\n \n if (stripos($nlQuery, $colName) !== false) {\n $columnsToSelect[] = \"`$colName`\";\n }\n }\n }\n \n if (!empty($columnsToSelect)) {\n $selectColumns = implode(', ', $columnsToSelect);\n }\n }\n \n\n $whereConditions = [];\n \n \n $comparisonPatterns = [\n '/\\bwhere\\s+(\\w+)\\s+equals?\\s+([\"\\']?[\\w\\s]+[\"\\']?)/' => '`$1` = \\'$2\\'',\n '/\\bwhere\\s+(\\w+)\\s+is\\s+([\"\\']?[\\w\\s]+[\"\\']?)/' => '`$1` = \\'$2\\'',\n '/\\bwhere\\s+(\\w+)\\s+greater than\\s+([\"\\']?[\\w\\s]+[\"\\']?)/' => '`$1` > \\'$2\\'',\n '/\\bwhere\\s+(\\w+)\\s+less than\\s+([\"\\']?[\\w\\s]+[\"\\']?)/' => '`$1` < \\'$2\\'',\n '/\\bwhere\\s+(\\w+)\\s+contains\\s+([\"\\']?[\\w\\s]+[\"\\']?)/' => '`$1` LIKE \\'%$2%\\'',\n '/\\bwhere\\s+(\\w+)\\s+starts with\\s+([\"\\']?[\\w\\s]+[\"\\']?)/' => '`$1` LIKE \\'$2%\\'',\n '/\\bwhere\\s+(\\w+)\\s+ends with\\s+([\"\\']?[\\w\\s]+[\"\\']?)/' => '`$1` LIKE \\'%$2\\'',\n ];\n \n foreach ($comparisonPatterns as $pattern => $replacement) {\n if (preg_match($pattern, $nlQuery, $matches)) {\n $condition = preg_replace($pattern, $replacement, $matches[0]);\n $whereConditions[] = $condition;\n }\n }\n \n\n if (preg_match('/\\b(\\w+)\\s+(greater than|more than|higher than|>)\\s+(\\d+)/', $nlQuery, $matches)) {\n $whereConditions[] = \"`{$matches[1]}` > {$matches[3]}\";\n }\n \n if (preg_match('/\\b(\\w+)\\s+(less than|lower than|<)\\s+(\\d+)/', $nlQuery, $matches)) {\n $whereConditions[] = \"`{$matches[1]}` < {$matches[3]}\";\n }\n \n\n if (preg_match('/\\b(from|between)\\s+(\\d{4}-\\d{2}-\\d{2})\\s+(to|and)\\s+(\\d{4}-\\d{2}-\\d{2})/', $nlQuery, $matches)) {\n \n $dateColumn = null;\n foreach ($tableColumns[$mainTable] as $colInfo) {\n if (strpos(strtolower($colInfo['Type']), 'date') !== false) {\n $dateColumn = $colInfo['Field'];\n break;\n }\n }\n \n if ($dateColumn) {\n $whereConditions[] = \"`$dateColumn` BETWEEN '{$matches[2]}' AND '{$matches[4]}'\";\n }\n }\n \n\n if (!empty($whereConditions)) {\n $whereClause = \"WHERE \" . implode(' AND ', $whereConditions);\n }\n \n \n if (preg_match('/\\b(order|sort)\\s+by\\s+(\\w+)\\s+(asc|ascending|desc|descending)/', $nlQuery, $matches)) {\n $direction = (strpos($matches[3], 'desc') === 0) ? 'DESC' : 'ASC';\n $orderByClause = \"ORDER BY `{$matches[2]}` $direction\";\n }\n\n if (preg_match('/\\blimit\\s+(\\d+)/', $nlQuery, $matches)) {\n $limitClause = \"LIMIT {$matches[1]}\";\n } else if (preg_match('/\\b(top|first)\\s+(\\d+)/', $nlQuery, $matches)) {\n $limitClause = \"LIMIT {$matches[2]}\";\n }\n \n if (preg_match('/\\bgroup\\s+by\\s+(\\w+)/', $nlQuery, $matches)) {\n $groupByClause = \"GROUP BY `{$matches[1]}`\";\n }\n }\n \n else if (preg_match('/\\b(insert|add|create|new)\\b/', $nlQuery)) {\n $queryType = 'INSERT';\n \n return \"INSERT INTO `$mainTable` (...) VALUES (...)\";\n }\n \n else if (preg_match('/\\b(update|modify|change|edit)\\b/', $nlQuery)) {\n $queryType = 'UPDATE';\n \n return \"UPDATE `$mainTable` SET ... WHERE ...\";\n }\n\n else if (preg_match('/\\b(delete|remove|drop)\\b/', $nlQuery)) {\n $queryType = 'DELETE';\n \n return \"DELETE FROM `$mainTable` WHERE ...\";\n }\n \n\n $sqlQuery = \"$queryType $selectColumns FROM $fromClause\";\n \n if (!empty($joinClause)) {\n $sqlQuery .= \" $joinClause\";\n }\n \n if (!empty($whereClause)) {\n $sqlQuery .= \" $whereClause\";\n }\n \n if (!empty($groupByClause)) {\n $sqlQuery .= \" $groupByClause\";\n }\n \n if (!empty($havingClause)) {\n $sqlQuery .= \" $havingClause\";\n }\n \n if (!empty($orderByClause)) {\n $sqlQuery .= \" $orderByClause\";\n }\n \n if (!empty($limitClause)) {\n $sqlQuery .= \" $limitClause\";\n }\n \n $sqlQuery .= \";\";\n \n return $sqlQuery;\n}\n\n/**\n * Determine which table is most likely the main one from the natural language query\n */\nfunction findMainTable($nlQuery, $tables) {\n foreach ($tables as $table) {\n \n $singular = rtrim($table, 's');\n \n if (stripos($nlQuery, $table) !== false || \n (strlen($singular) > 3 && stripos($nlQuery, $singular) !== false)) {\n return $table;\n }\n }\n \n return $tables[0] ?? 'unknown_table';\n}\n\n/**\n * Generate an explanation of how the SQL query was derived from natural language\n */\nfunction explainQueryGeneration($nlQuery, $sqlQuery) {\n return \"Converted your question \\\"$nlQuery\\\" into a SQL query by identifying the main table, \n relevant columns, and conditions. The generated query retrieves the data you're looking for.\";\n}\n\n/**\n * Call DeepSeek free models without API key\n */\nfunction callDeepSeekFree($systemMessage, $userMessage, $tables) {\n\n $data = [\n 'model' => 'deepseek-coder-v2', \n 'messages' => [\n ['role' => 'system', 'content' => $systemMessage],\n ['role' => 'user', 'content' => $userMessage]\n ],\n 'temperature' => 0.3,\n 'max_tokens' => 1000\n ];\n \n \n $ch = curl_init('https://api.deepseek.com/v1/chat/completions');\n\n curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n curl_setopt($ch, CURLOPT_POST, true);\n curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));\n curl_setopt($ch, CURLOPT_HTTPHEADER, [\n 'Content-Type: application/json'\n ]);\n \n // SECURITY NOTE: SSL verification is disabled to handle environments with missing or outdated certificates.\n // In production, consider enabling proper SSL verification and installing required certificates.\n curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);\n curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);\n \n \n $response = curl_exec($ch);\n \n \n if (curl_errno($ch)) {\n $error = curl_error($ch);\n curl_close($ch);\n \n \n $fallbackResponse = [\n 'sql_query' => \"SELECT * FROM \" . ($tables[0] ?? 'unknown_table') . \" LIMIT 10; -- Connection error with DeepSeek API\",\n 'explanation' => \"Could not connect to DeepSeek free service: \" . $error . \"\\nUsing a default query instead.\"\n ];\n \n return $fallbackResponse;\n }\n \n \n $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);\n curl_close($ch);\n \n \n if ($httpCode >= 400) {\n $fallbackResponse = [\n 'sql_query' => \"SELECT * FROM \" . ($tables[0] ?? 'unknown_table') . \" LIMIT 10; -- HTTP error with DeepSeek API\",\n 'explanation' => \"HTTP error \" . $httpCode . \" when calling DeepSeek free service. Using a default query instead.\"\n ];\n \n return $fallbackResponse;\n }\n \n\n $responseData = json_decode($response, true);\n \n\n if (isset($responseData['choices'][0]['message']['content'])) {\n $content = $responseData['choices'][0]['message']['content'];\n return parseAIResponse($content, $tables);\n } else {\n // Return a more helpful fallback response\n $fallbackResponse = [\n 'sql_query' => \"SELECT * FROM \" . ($tables[0] ?? 'unknown_table') . \" LIMIT 10; -- Invalid response from DeepSeek API\",\n 'explanation' => \"Received an invalid response format from DeepSeek free service. Using a default query instead.\"\n ];\n \n return $fallbackResponse;\n }\n} "}, "09b06bade3d550a7a5a29ced17bc53d0ec4348e2": {"t": 1785760309.6196527, "n": 54789, "h": "63b2859e691afa69", "c": "<?php\nrequire_once './config.php';\nsession_start();\n\n\nif(!isset($_SESSION['dev_authenticated'])){\n header('Location: ../');\n exit();\n}\n\n\nif (isset($_GET['action'])) {\n $action = $_GET['action'];\n \n switch ($action) {\n case 'get_table_structure':\n getTableStructure();\n break;\n \n case 'get_table_data':\n getTableData();\n break;\n \n case 'get_query_suggestions':\n getQuerySuggestions();\n break;\n \n case 'change_database':\n changeDatabase();\n break;\n \n case 'get_database_schema':\n getDatabaseSchema();\n break;\n \n case 'execute_query':\n executeQuery();\n break;\n \n case 'nl_to_sql':\n naturalLanguageToSQL();\n break;\n \n default:\n header('Content-Type: application/json');\n echo json_encode(['error' => 'Invalid action']);\n break;\n }\n}\n\n/**\n * Get the structure of a specific table\n */\nfunction getTableStructure() {\n global $conn;\n \n if (!isset($_GET['table'])) {\n header('Content-Type: application/json');\n echo json_encode(['error' => 'Table name is required']);\n return;\n }\n \n $table = mysqli_real_escape_string($conn, $_GET['table']);\n $db = isset($_GET['db']) ? mysqli_real_escape_string($conn, $_GET['db']) : '';\n \n\n if (!empty($db)) {\n mysqli_select_db($conn, $db);\n }\n \n try {\n \n $query = \"DESCRIBE `$table`\";\n $result = mysqli_query($conn, $query);\n \n if (!$result) {\n header('Content-Type: application/json');\n echo json_encode(['error' => 'Error fetching table structure: ' . mysqli_error($conn)]);\n return;\n }\n \n $columns = [];\n while ($row = mysqli_fetch_assoc($result)) {\n $columns[] = $row;\n }\n \n \n $indexQuery = \"SHOW INDEX FROM `$table`\";\n $indexResult = mysqli_query($conn, $indexQuery);\n \n $indexes = [];\n if ($indexResult) {\n while ($row = mysqli_fetch_assoc($indexResult)) {\n $indexes[] = $row;\n }\n }\n \n header('Content-Type: application/json');\n echo json_encode([\n 'table' => $table,\n 'columns' => $columns,\n 'indexes' => $indexes\n ]);\n } catch (Exception $e) {\n header('Content-Type: application/json');\n echo json_encode(['error' => 'Error: ' . $e->getMessage()]);\n }\n}\n\n/**\n * Get data from a specific table with pagination\n */\nfunction getTableData() {\n global $conn;\n \n if (!isset($_GET['table'])) {\n header('Content-Type: application/json');\n echo json_encode(['error' => 'Table name is required']);\n return;\n }\n \n $table = mysqli_real_escape_string($conn, $_GET['table']);\n $db = isset($_GET['db']) ? mysqli_real_escape_string($conn, $_GET['db']) : '';\n $page = isset($_GET['page']) ? (int)$_GET['page'] : 1;\n $perPage = isset($_GET['per_page']) ? (int)$_GET['per_page'] : 50;\n \n\n if ($page < 1) $page = 1;\n if ($perPage < 10) $perPage = 10;\n if ($perPage > 1000) $perPage = 1000;\n \n $offset = ($page - 1) * $perPage;\n \n\n if (!empty($db)) {\n mysqli_select_db($conn, $db);\n }\n \n try {\n\n $countQuery = \"SELECT COUNT(*) as total FROM `$table`\";\n $countResult = mysqli_query($conn, $countQuery);\n $totalRows = 0;\n \n if ($countResult && $row = mysqli_fetch_assoc($countResult)) {\n $totalRows = $row['total'];\n }\n \n\n $query = \"SELECT * FROM `$table` LIMIT $offset, $perPage\";\n $result = mysqli_query($conn, $query);\n \n if (!$result) {\n header('Content-Type: application/json');\n echo json_encode(['error' => 'Error fetching table data: ' . mysqli_error($conn)]);\n return;\n }\n \n $data = [];\n while ($row = mysqli_fetch_assoc($result)) {\n $data[] = $row;\n }\n \n header('Content-Type: application/json');\n echo json_encode([\n 'table' => $table,\n 'data' => $data,\n 'pagination' => [\n 'page' => $page,\n 'per_page' => $perPage,\n 'total_rows' => $totalRows,\n 'total_pages' => ceil($totalRows / $perPage)\n ]\n ]);\n } catch (Exception $e) {\n header('Content-Type: application/json');\n echo json_encode(['error' => 'Error: ' . $e->getMessage()]);\n }\n}\n\n/**\n * Get SQL query suggestions based on context\n */\nfunction getQuerySuggestions() {\n global $conn;\n \n $partial = isset($_GET['partial']) ? $_GET['partial'] : '';\n $context = isset($_GET['context']) ? $_GET['context'] : '';\n $db = isset($_GET['db']) ? mysqli_real_escape_string($conn, $_GET['db']) : '';\n \n\n if (!empty($db)) {\n mysqli_select_db($conn, $db);\n }\n \n $suggestions = [];\n \n\n $keywords = ['SELECT', 'FROM', 'WHERE', 'GROUP BY', 'ORDER BY', 'HAVING', 'LIMIT', \n 'JOIN', 'INNER JOIN', 'LEFT JOIN', 'RIGHT JOIN', 'OUTER JOIN', 'INSERT INTO', \n 'VALUES', 'UPDATE', 'SET', 'DELETE FROM', 'CREATE TABLE', 'ALTER TABLE', \n 'DROP TABLE', 'CREATE INDEX', 'DROP INDEX', 'UNION', 'UNION ALL'];\n \n\n if (!empty($partial)) {\n $partial = strtoupper($partial);\n $keywords = array_filter($keywords, function($keyword) use ($partial) {\n return strpos($keyword, $partial) === 0;\n });\n }\n \n\n foreach ($keywords as $keyword) {\n $suggestions[] = [\n 'text' => $keyword,\n 'type' => 'keyword'\n ];\n }\n \n try {\n $query = \"SHOW TABLES\";\n $result = mysqli_query($conn, $query);\n \n if ($result) {\n while ($row = mysqli_fetch_array($result)) {\n $tableName = $row[0];\n if (empty($partial) || stripos($tableName, $partial) === 0) {\n $suggestions[] = [\n 'text' => $tableName,\n 'type' => 'table'\n ];\n }\n }\n }\n } catch (Exception $e) {\n // Silent catch - just don't add tables to suggestions\n }\n \n header('Content-Type: application/json');\n echo json_encode(['suggestions' => $suggestions]);\n}\n\n/**\n * Change the current database\n */\nfunction changeDatabase() {\n global $conn;\n \n if (!isset($_GET['db'])) {\n header('Content-Type: application/json');\n echo json_encode(['error' => 'Database name is required']);\n return;\n }\n \n $db = mysqli_real_escape_string($conn, $_GET['db']);\n \n try {\n\n $result = mysqli_select_db($conn, $db);\n \n if (!$result) {\n header('Content-Type: application/json');\n echo json_encode(['error' => 'Error changing database: ' . mysqli_error($conn)]);\n return;\n }\n \n\n $tablesQuery = \"SHOW TABLES\";\n $tablesResult = mysqli_query($conn, $tablesQuery);\n \n $tables = [];\n if ($tablesResult) {\n while ($row = mysqli_fetch_array($tablesResult)) {\n $tables[] = $row[0];\n }\n }\n \n header('Content-Type: application/json');\n echo json_encode([\n 'success' => true,\n 'database' => $db,\n 'tables' => $tables\n ]);\n } catch (Exception $e) {\n header('Content-Type: application/json');\n echo json_encode(['error' => 'Error: ' . $e->getMessage()]);\n }\n}\n\n/**\n * Get database schema including tables and relationships for visualization\n */\nfunction getDatabaseSchema() {\n global $conn;\n \n $database = $_GET['db'] ?? '';\n \n if (empty($database)) {\n echo json_encode(['error' => 'Database not specified']);\n exit;\n }\n \n try {\n $conn->select_db($database);\n \n \n $tables = [];\n $tablesResult = $conn->query(\"SHOW TABLES\");\n \n if ($tablesResult) {\n while ($row = $tablesResult->fetch_row()) {\n $tables[] = ['name' => $row[0]];\n }\n $tablesResult->free();\n }\n \n \n foreach ($tables as &$table) {\n $columns = [];\n $columnsResult = $conn->query(\"DESCRIBE `{$table['name']}`\");\n \n if ($columnsResult) {\n while ($row = $columnsResult->fetch_assoc()) {\n $columns[] = $row;\n }\n $columnsResult->free();\n }\n \n $table['columns'] = $columns;\n }\n \n // Get relationships using INFORMATION_SCHEMA\n $relationships = [];\n $relationshipsQuery = \"\n SELECT \n TABLE_NAME AS table_name,\n COLUMN_NAME AS column_name,\n REFERENCED_TABLE_NAME AS referenced_table_name,\n REFERENCED_COLUMN_NAME AS referenced_column_name\n FROM\n INFORMATION_SCHEMA.KEY_COLUMN_USAGE\n WHERE\n REFERENCED_TABLE_SCHEMA = '$database'\n AND REFERENCED_TABLE_NAME IS NOT NULL\n AND REFERENCED_COLUMN_NAME IS NOT NULL\n \";\n \n $relationshipsResult = $conn->query($relationshipsQuery);\n \n if ($relationshipsResult) {\n while ($row = $relationshipsResult->fetch_assoc()) {\n $relationships[] = [\n 'table' => $row['table_name'],\n 'column' => $row['column_name'],\n 'referenced_table' => $row['referenced_table_name'],\n 'referenced_column' => $row['referenced_column_name']\n ];\n }\n $relationshipsResult->free();\n }\n \n \n if (empty($relationships)) {\n \n foreach ($tables as $table) {\n if (empty($table['columns'])) continue;\n \n foreach ($table['columns'] as $column) {\n \n $columnName = $column['Field'];\n \n \n if (preg_match('/(.*?)_id$/', $columnName, $matches)) {\n $potentialTableName = $matches[1];\n \n \n $tableExists = false;\n $referencedTable = '';\n $referencedColumn = '';\n \n\n foreach ($tables as $t) {\n if ($t['name'] === $potentialTableName) {\n $tableExists = true;\n $referencedTable = $t['name'];\n break;\n }\n }\n \n \n if (!$tableExists) {\n foreach ($tables as $t) {\n if ($t['name'] === $potentialTableName . 's') {\n $tableExists = true;\n $referencedTable = $t['name'];\n break;\n }\n }\n }\n \n\n if (!$tableExists && substr($potentialTableName, -1) === 's') {\n $singularName = substr($potentialTableName, 0, -1);\n foreach ($tables as $t) {\n if ($t['name'] === $singularName) {\n $tableExists = true;\n $referencedTable = $t['name'];\n break;\n }\n }\n }\n \n if ($tableExists) {\n \n foreach ($tables as $t) {\n if ($t['name'] === $referencedTable) {\n foreach ($t['columns'] as $col) {\n if (isset($col['Key']) && $col['Key'] === 'PRI') {\n $referencedColumn = $col['Field'];\n break;\n }\n }\n \n \n if (empty($referencedColumn)) {\n $referencedColumn = 'id';\n }\n \n break;\n }\n }\n \n if (!empty($referencedColumn)) {\n $relationships[] = [\n 'table' => $table['name'],\n 'column' => $columnName,\n 'referenced_table' => $referencedTable,\n 'referenced_column' => $referencedColumn,\n 'inferred' => true\n ];\n }\n }\n }\n }\n }\n }\n \n\n $debugInfo = [\n 'tableCount' => count($tables),\n 'relationshipCount' => count($relationships),\n 'relatedTableNames' => array_unique(array_merge(\n array_column($relationships, 'table'),\n array_column($relationships, 'referenced_table')\n ))\n ];\n \n echo json_encode([\n 'tables' => $tables,\n 'relationships' => $relationships,\n 'debug' => $debugInfo\n ]);\n } catch (Exception $e) {\n echo json_encode(['error' => $e->getMessage()]);\n }\n}\n\n/**\n * Execute a custom SQL query\n */\nfunction executeQuery() {\n global $conn;\n \n header('Content-Type: application/json');\n \n\n if (!isset($_POST['query']) || empty($_POST['query'])) {\n echo json_encode(['error' => 'No query provided']);\n return;\n }\n \n $query = $_POST['query'];\n $database = isset($_POST['database']) ? $_POST['database'] : '';\n \n\n if (!empty($database)) {\n if (!mysqli_select_db($conn, $database)) {\n echo json_encode(['error' => 'Error selecting database: ' . mysqli_error($conn)]);\n return;\n }\n }\n \n try {\n\n $startTime = microtime(true);\n \n\n $result = mysqli_query($conn, $query);\n \n \n $endTime = microtime(true);\n $executionTime = round(($endTime - $startTime) * 1000, 2); // in milliseconds\n \n if ($result === false) {\n echo json_encode([\n 'error' => 'Query error: ' . mysqli_error($conn),\n 'query' => $query\n ]);\n return;\n }\n \n\n if ($result instanceof mysqli_result) {\n \n $data = [];\n $fields = [];\n \n \n $fieldInfo = mysqli_fetch_fields($result);\n foreach ($fieldInfo as $field) {\n $fields[] = $field->name;\n }\n \n \n while ($row = mysqli_fetch_assoc($result)) {\n $data[] = $row;\n }\n \n mysqli_free_result($result);\n \n echo json_encode([\n 'success' => true,\n 'isSelect' => true,\n 'fields' => $fields,\n 'data' => $data,\n 'rowCount' => count($data),\n 'executionTime' => $executionTime\n ]);\n } else {\n \n echo json_encode([\n 'success' => true,\n 'isSelect' => false,\n 'affectedRows' => mysqli_affected_rows($conn),\n 'insertId' => mysqli_insert_id($conn),\n 'executionTime' => $executionTime\n ]);\n }\n } catch (Exception $e) {\n echo json_encode([\n 'error' => 'Error: ' . $e->getMessage(),\n 'query' => $query\n ]);\n }\n}\n\n/**\n * Convert natural language to SQL query\n * This function takes a natural language description and converts it to a SQL query\n */\nfunction naturalLanguageToSQL() {\n global $conn;\n \n header('Content-Type: application/json');\n \n\n if (!isset($_POST['nl_query']) || empty($_POST['nl_query'])) {\n echo json_encode(['error' => 'No natural language query provided']);\n return;\n }\n \n $nlQuery = $_POST['nl_query'];\n $database = isset($_POST['database']) ? $_POST['database'] : '';\n \n\n $useAI = isset($_POST['use_ai']) && $_POST['use_ai'] === 'true';\n $apiKey = isset($_POST['api_key']) ? $_POST['api_key'] : '';\n $apiModel = isset($_POST['api_model']) ? $_POST['api_model'] : 'gpt-3.5-turbo';\n $apiProvider = isset($_POST['api_provider']) ? $_POST['api_provider'] : 'openai';\n \n\n if ($useAI && empty($apiKey) && $apiProvider !== 'deepseek-free') {\n echo json_encode(['error' => 'API key is required when using AI']);\n return;\n }\n \n \n if (!empty($database)) {\n if (!mysqli_select_db($conn, $database)) {\n echo json_encode(['error' => 'Error selecting database: ' . mysqli_error($conn)]);\n return;\n }\n }\n \n try {\n\n $tables = [];\n $tableColumns = [];\n \n \n $tablesResult = mysqli_query($conn, \"SHOW TABLES\");\n if ($tablesResult) {\n while ($tableRow = mysqli_fetch_row($tablesResult)) {\n $tableName = $tableRow[0];\n $tables[] = $tableName;\n \n \n $columnsResult = mysqli_query($conn, \"SHOW COLUMNS FROM `$tableName`\");\n if ($columnsResult) {\n $tableColumns[$tableName] = [];\n while ($columnRow = mysqli_fetch_assoc($columnsResult)) {\n $tableColumns[$tableName][] = $columnRow;\n }\n }\n }\n }\n \n\n $schemaString = generateSchemaString($tables, $tableColumns);\n \n\n if ($useAI) {\n \n $result = generateSQLWithAI($nlQuery, $schemaString, $tables, $tableColumns, $apiKey, $apiModel, $apiProvider);\n $sqlQuery = $result['sql_query'];\n $explanation = $result['explanation'];\n } else {\n\n $sqlQuery = generateSQLFromNaturalLanguage($nlQuery, $tables, $tableColumns);\n $explanation = explainQueryGeneration($nlQuery, $sqlQuery);\n }\n \n echo json_encode([\n 'success' => true,\n 'natural_language_query' => $nlQuery,\n 'sql_query' => $sqlQuery,\n 'tables' => $tables,\n 'explanation' => $explanation,\n 'ai_used' => $useAI\n ]);\n } catch (Exception $e) {\n echo json_encode([\n 'error' => 'Error: ' . $e->getMessage(),\n 'natural_language_query' => $nlQuery\n ]);\n }\n}\n\n/**\n * Convert database schema to a string representation for AI context\n */\nfunction generateSchemaString($tables, $tableColumns) {\n $schemaString = \"Database Schema:\\n\\n\";\n \n foreach ($tables as $table) {\n $schemaString .= \"Table: {$table}\\n\";\n $schemaString .= \"Columns:\\n\";\n \n if (!empty($tableColumns[$table])) {\n foreach ($tableColumns[$table] as $column) {\n $isPrimary = isset($column['Key']) && $column['Key'] === 'PRI' ? ' (Primary Key)' : '';\n $isNull = $column['Null'] === 'YES' ? ' NULL' : ' NOT NULL';\n $default = isset($column['Default']) && $column['Default'] !== null ? \" Default: {$column['Default']}\" : '';\n \n $schemaString .= \"- {$column['Field']} ({$column['Type']}){$isPrimary}{$isNull}{$default}\\n\";\n }\n }\n \n $schemaString .= \"\\n\";\n }\n \n return $schemaString;\n}\n\n/**\n * Generate SQL using an AI API\n */\nfunction generateSQLWithAI($nlQuery, $schemaString, $tables, $tableColumns, $apiKey, $apiModel, $apiProvider) {\n\n \n // System message for the AI\n $systemMessage = \"You are an elite-level SQL architect and database optimization specialist with expertise in enterprise-scale database systems, query planning, and performance tuning. \";\n $systemMessage .= \"Your task is to convert natural language descriptions into sophisticated, highly optimized SQL queries that follow industry best practices. \";\n $systemMessage .= \"Below is the database schema you should use to generate the SQL query:\\n\\n\";\n $systemMessage .= $schemaString;\n \n $systemMessage .= \"\\n\\n## ADVANCED QUERY GENERATION DIRECTIVES ##\";\n \n $systemMessage .= \"\\n\\n### Schema Analysis & Optimization ###\";\n $systemMessage .= \"\\n- Analyze relationships between tables to determine optimal join strategies\";\n $systemMessage .= \"\\n- Consider available indexes to optimize query execution paths\";\n $systemMessage .= \"\\n- Identify and leverage primary and foreign key relationships\";\n $systemMessage .= \"\\n- Use table aliases to improve query readability and prevent ambiguity\";\n \n $systemMessage .= \"\\n\\n### Query Construction Excellence ###\";\n $systemMessage .= \"\\n- Choose between subqueries, CTEs (WITH clause), or JOINs based on performance characteristics\";\n $systemMessage .= \"\\n- Implement appropriate query hints when beneficial for performance\";\n $systemMessage .= \"\\n- Use EXISTS/NOT EXISTS, IN/NOT IN, or joins appropriately based on data distribution patterns\";\n $systemMessage .= \"\\n- Consider UNION vs. UNION ALL based on need for duplicate elimination\";\n $systemMessage .= \"\\n- Optimize aggregation with GROUP BY clauses using the minimal necessary columns\";\n $systemMessage .= \"\\n- Implement window functions (ROW_NUMBER, RANK, etc.) for sophisticated data analysis\";\n $systemMessage .= \"\\n- Apply advanced filtering techniques like dynamic pivoting or hierarchical queries when appropriate\";\n \n $systemMessage .= \"\\n\\n### Data Integrity & Security ###\";\n $systemMessage .= \"\\n- Prevent SQL injection by properly parametrizing user inputs\";\n $systemMessage .= \"\\n- Include appropriate transaction isolation levels for multi-statement operations\";\n $systemMessage .= \"\\n- Implement appropriate error handling and graceful fallbacks\";\n $systemMessage .= \"\\n- Consider ACID properties when designing transaction-based queries\";\n \n $systemMessage .= \"\\n\\n### Performance Tuning ###\";\n $systemMessage .= \"\\n- Minimize full table scans and optimize for index usage\";\n $systemMessage .= \"\\n- Avoid unnecessary columns in SELECT statements\";\n $systemMessage .= \"\\n- Consider data volume when choosing between aggregation methods\";\n $systemMessage .= \"\\n- Use appropriate LIMIT/OFFSET for pagination with optimized execution\";\n $systemMessage .= \"\\n- Anticipate and mitigate potential bottlenecks in complex joins or aggregations\";\n $systemMessage .= \"\\n- Consider query cache implications with appropriate cache hints if supported\";\n \n $systemMessage .= \"\\n\\n### Error Correction & Enhancement ###\";\n $systemMessage .= \"\\n- Identify and fix potential logical errors in the user's request\";\n $systemMessage .= \"\\n- Detect ambiguities in natural language and resolve with the most likely intent\";\n $systemMessage .= \"\\n- Provide alternative query approaches when multiple valid interpretations exist\";\n $systemMessage .= \"\\n- When encountering incomplete requests, make reasonable assumptions and document them\";\n $systemMessage .= \"\\n- Include thorough commenting of complex logic or assumptions made\";\n \n $systemMessage .= \"\\n\\n### Response Format ###\";\n $systemMessage .= \"\\nYou MUST format your response as a JSON object with EXACTLY these two properties:\";\n $systemMessage .= \"\\n1. 'sql_query': A string containing ONLY the complete SQL query with detailed inline comments\";\n $systemMessage .= \"\\n2. 'explanation': A string containing a comprehensive explanation\";\n \n $systemMessage .= \"\\n\\nIMPORTANT: Your response MUST be valid JSON. Do not include any text outside the JSON object.\";\n $systemMessage .= \"\\nFormat example:\";\n $systemMessage .= \"\\n```json\";\n $systemMessage .= \"\\n{\";\n $systemMessage .= \"\\n \\\"sql_query\\\": \\\"SELECT * FROM users WHERE status = 'active' LIMIT 10;\\\",\";\n $systemMessage .= \"\\n \\\"explanation\\\": \\\"This query retrieves active users with a limit of 10 records.\\\"\";\n $systemMessage .= \"\\n}\";\n $systemMessage .= \"\\n```\";\n \n $systemMessage .= \"\\n\\nPlease note that in the actual response, you should NOT include the ```json and ``` markers - your response should ONLY be the JSON object itself.\";\n $systemMessage .= \"\\n\\nEnsure the SQL follows MySQL best practices and optimization techniques. Your goal is to create production-ready, maintainable, and highly efficient queries.\";\n \n // Create the user message with additional context extraction\n $userMessage = \"Generate an optimal MySQL query for the following request. If my request contains any errors or ambiguities, please correct them: {$nlQuery}\";\n \n\n $apiResult = null;\n try {\n switch ($apiProvider) {\n case 'openai':\n $apiResult = callOpenAI($systemMessage, $userMessage, $apiKey, $apiModel, $tables);\n break;\n \n case 'claude':\n $apiResult = callClaude($systemMessage, $userMessage, $apiKey, $apiModel, $tables);\n break;\n \n case 'gemini':\n $apiResult = callGemini($systemMessage, $userMessage, $apiKey, $apiModel, $tables);\n break;\n \n case 'mistral':\n $apiResult = callMistral($systemMessage, $userMessage, $apiKey, $apiModel, $tables);\n break;\n \n case 'deepseek':\n $apiResult = callDeepSeek($systemMessage, $userMessage, $apiKey, $apiModel, $tables);\n break;\n \n case 'deepseek-free':\n $apiResult = callDeepSeekFree($systemMessage, $userMessage, $tables);\n break;\n \n case 'llama':\n $apiResult = callLlama($systemMessage, $userMessage, $apiKey, $apiModel, $tables);\n break;\n \n default:\n \n $apiResult = callOpenAI($systemMessage, $userMessage, $apiKey, $apiModel, $tables);\n break;\n }\n \n \n if (is_array($apiResult) && !isset($apiResult['provider'])) {\n $apiResult['provider'] = $apiProvider;\n }\n \n return $apiResult;\n \n } catch (Exception $e) {\n \n return [\n 'sql_query' => \"-- Error from {$apiProvider} API\\n-- \" . $e->getMessage() . \"\\nSELECT * FROM \" . ($tables[0] ?? 'unknown_table') . \" LIMIT 10;\",\n 'explanation' => \"Error while generating SQL with {$apiProvider}: \" . $e->getMessage() . \". Using a safe fallback query.\",\n 'provider' => $apiProvider,\n 'error' => true\n ];\n }\n}\n\n/**\n * Call OpenAI API to generate SQL\n */\nfunction callOpenAI($systemMessage, $userMessage, $apiKey, $apiModel, $tables) {\n\n $data = [\n 'model' => $apiModel,\n 'messages' => [\n ['role' => 'system', 'content' => $systemMessage],\n ['role' => 'user', 'content' => $userMessage]\n ],\n 'temperature' => 0.3,\n 'max_tokens' => 1500,\n 'response_format' => ['type' => 'json_object'] \n ];\n \n\n $ch = curl_init('https://api.openai.com/v1/chat/completions');\n \n\n curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n curl_setopt($ch, CURLOPT_POST, true);\n curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));\n curl_setopt($ch, CURLOPT_HTTPHEADER, [\n 'Content-Type: application/json',\n 'Authorization: Bearer ' . $apiKey\n ]);\n \n // SECURITY NOTE: SSL verification is disabled to handle environments with missing or outdated certificates.\n // In production, consider enabling proper SSL verification and installing required certificates.\n curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);\n curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);\n \n\n $response = curl_exec($ch);\n \n\n if (curl_errno($ch)) {\n $error = curl_error($ch);\n curl_close($ch);\n throw new Exception('cURL error: ' . $error);\n }\n \n\n $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);\n curl_close($ch);\n \n\n if ($httpCode >= 400) {\n throw new Exception('HTTP error ' . $httpCode . ': OpenAI API request failed. Response: ' . substr($response, 0, 200));\n }\n \n\n $responseData = json_decode($response, true);\n \n \n if (isset($responseData['error'])) {\n throw new Exception('OpenAI API error: ' . ($responseData['error']['message'] ?? json_encode($responseData['error'])));\n }\n\n if (isset($responseData['choices'][0]['message']['content'])) {\n $content = $responseData['choices'][0]['message']['content'];\n return parseAIResponse($content, $tables);\n } else {\n throw new Exception('Invalid response format from OpenAI API: ' . json_encode($responseData));\n }\n}\n\n/**\n * Call Claude API to generate SQL\n */\nfunction callClaude($systemMessage, $userMessage, $apiKey, $apiModel, $tables) {\n\n $data = [\n 'model' => $apiModel,\n 'system' => $systemMessage,\n 'messages' => [\n ['role' => 'user', 'content' => $userMessage]\n ],\n 'temperature' => 0.3,\n 'max_tokens' => 1500,\n 'anthropic_version' => '2023-06-01'\n ];\n \n \n $ch = curl_init('https://api.anthropic.com/v1/messages');\n \n // Set cURL options\n curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n curl_setopt($ch, CURLOPT_POST, true);\n curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));\n curl_setopt($ch, CURLOPT_HTTPHEADER, [\n 'Content-Type: application/json',\n 'x-api-key: ' . $apiKey,\n 'anthropic-version: 2023-06-01'\n ]);\n \n // SECURITY NOTE: SSL verification is disabled to handle environments with missing or outdated certificates.\n // In production, consider enabling proper SSL verification and installing required certificates.\n curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);\n curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);\n \n \n $response = curl_exec($ch);\n \n \n if (curl_errno($ch)) {\n $error = curl_error($ch);\n curl_close($ch);\n throw new Exception('cURL error: ' . $error);\n }\n \n \n $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);\n curl_close($ch);\n \n \n if ($httpCode >= 400) {\n throw new Exception('HTTP error ' . $httpCode . ': Claude API request failed. Response: ' . substr($response, 0, 200));\n }\n \n \n $responseData = json_decode($response, true);\n \n \n if (isset($responseData['error'])) {\n throw new Exception('Claude API error: ' . ($responseData['error']['message'] ?? json_encode($responseData['error'])));\n }\n \n \n $content = '';\n if (isset($responseData['content']) && is_array($responseData['content']) && !empty($responseData['content'])) {\n foreach ($responseData['content'] as $part) {\n if (isset($part['text'])) {\n $content .= $part['text'];\n }\n }\n \n \n if (preg_match('/\\{\\s*\"sql_query\"\\s*:.*\"explanation\"\\s*:.*\\}/s', $content, $matches)) {\n $content = $matches[0];\n }\n \n return parseAIResponse($content, $tables);\n } else {\n \n throw new Exception('Invalid response format from Claude API: ' . json_encode($responseData));\n }\n}\n\n/**\n * Call Google Gemini API to generate SQL\n */\nfunction callGemini($systemMessage, $userMessage, $apiKey, $apiModel, $tables) {\n \n $prompt = $systemMessage . \"\\n\\n\" . $userMessage;\n \n\n $isGemini2 = (strpos($apiModel, 'gemini-2') === 0);\n \n\n if ($isGemini2) {\n // Gemini 2.0 format with system instruction\n $data = [\n 'contents' => [\n [\n 'role' => 'user',\n 'parts' => [\n ['text' => $userMessage]\n ]\n ]\n ],\n 'systemInstruction' => [\n 'parts' => [\n ['text' => $systemMessage]\n ]\n ],\n 'generationConfig' => [\n 'temperature' => 0.3,\n 'maxOutputTokens' => 1000\n ]\n ];\n } else {\n // Original Gemini format (gemini-pro, gemini-ultra, etc.)\n $data = [\n 'contents' => [\n [\n 'parts' => [\n ['text' => $prompt]\n ]\n ]\n ],\n 'generationConfig' => [\n 'temperature' => 0.3,\n 'maxOutputTokens' => 1000\n ]\n ];\n }\n \n \n $ch = curl_init(\"https://generativelanguage.googleapis.com/v1beta/models/{$apiModel}:generateContent?key={$apiKey}\");\n \n \n curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n curl_setopt($ch, CURLOPT_POST, true);\n curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));\n curl_setopt($ch, CURLOPT_HTTPHEADER, [\n 'Content-Type: application/json'\n ]);\n \n // SECURITY NOTE: SSL verification is disabled to handle environments with missing or outdated certificates.\n // In production, consider enabling proper SSL verification and installing required certificates.\n curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);\n curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);\n \n \n $response = curl_exec($ch);\n \n \n if (curl_errno($ch)) {\n $error = curl_error($ch);\n curl_close($ch);\n throw new Exception('cURL error: ' . $error);\n }\n \n \n $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);\n curl_close($ch);\n \n \n if ($httpCode >= 400) {\n throw new Exception('HTTP error ' . $httpCode . ': Gemini API request failed. Response: ' . substr($response, 0, 200));\n }\n \n \n $responseData = json_decode($response, true);\n \n \n if (isset($responseData['error'])) {\n throw new Exception('Gemini API error: ' . ($responseData['error']['message'] ?? json_encode($responseData['error'])));\n }\n \n \n $content = '';\n \n\n if (isset($responseData['candidates'][0]['content']['parts'][0]['text'])) {\n $content = $responseData['candidates'][0]['content']['parts'][0]['text'];\n } else {\n\n $content = json_encode($responseData);\n }\n \n return parseAIResponse($content, $tables);\n}\n\n/**\n * Call DeepSeek API with API key to generate SQL\n */\nfunction callDeepSeek($systemMessage, $userMessage, $apiKey, $apiModel, $tables) {\n\n $data = [\n 'model' => $apiModel,\n 'messages' => [\n ['role' => 'system', 'content' => $systemMessage],\n ['role' => 'user', 'content' => $userMessage]\n ],\n 'temperature' => 0.3,\n 'max_tokens' => 1000\n ];\n \n\n $ch = curl_init('https://api.deepseek.com/v1/chat/completions');\n \n\n curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n curl_setopt($ch, CURLOPT_POST, true);\n curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));\n curl_setopt($ch, CURLOPT_HTTPHEADER, [\n 'Content-Type: application/json',\n 'Authorization: Bearer ' . $apiKey\n ]);\n \n\n curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);\n curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);\n \n\n $response = curl_exec($ch);\n \n\n if (curl_errno($ch)) {\n $error = curl_error($ch);\n curl_close($ch);\n throw new Exception('cURL error: ' . $error);\n }\n \n \n $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);\n curl_close($ch);\n \n \n if ($httpCode >= 400) {\n throw new Exception('HTTP error ' . $httpCode . ': DeepSeek API request failed. Response: ' . substr($response, 0, 200));\n }\n \n \n $responseData = json_decode($response, true);\n \n \n if (isset($responseData['error'])) {\n throw new Exception('DeepSeek API error: ' . ($responseData['error']['message'] ?? json_encode($responseData['error'])));\n }\n \n \n $content = '';\n \n if (isset($responseData['choices'][0]['message']['content'])) {\n $content = $responseData['choices'][0]['message']['content'];\n } else {\n\n $content = json_encode($responseData);\n }\n \n return parseAIResponse($content, $tables);\n}\n\n/**\n * Call Mistral API to generate SQL\n */\nfunction callMistral($systemMessage, $userMessage, $apiKey, $apiModel, $tables) {\n\n $data = [\n 'model' => $apiModel,\n 'messages' => [\n ['role' => 'system', 'content' => $systemMessage],\n ['role' => 'user', 'content' => $userMessage]\n ],\n 'temperature' => 0.3,\n 'max_tokens' => 1000\n ];\n \n\n $ch = curl_init('https://api.mistral.ai/v1/chat/completions');\n \n \n curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n curl_setopt($ch, CURLOPT_POST, true);\n curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));\n curl_setopt($ch, CURLOPT_HTTPHEADER, [\n 'Content-Type: application/json',\n 'Authorization: Bearer ' . $apiKey\n ]);\n \n // SECURITY NOTE: SSL verification is disabled to handle environments with missing or outdated certificates.\n // In production, consider enabling proper SSL verification and installing required certificates.\n curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);\n curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);\n \n\n $response = curl_exec($ch);\n \n \n if (curl_errno($ch)) {\n $error = curl_error($ch);\n curl_close($ch);\n throw new Exception('cURL error: ' . $error);\n }\n \n\n $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);\n curl_close($ch);\n \n\n if ($httpCode >= 400) {\n throw new Exception('HTTP error ' . $httpCode . ': Mistral API request failed. Response: ' . substr($response, 0, 200));\n }\n \n\n $responseData = json_decode($response, true);\n \n\n if (isset($responseData['error'])) {\n throw new Exception('Mistral API error: ' . ($responseData['error']['message'] ?? json_encode($responseData['error'])));\n }\n \n\n $content = '';\n \n if (isset($responseData['choices'][0]['message']['content'])) {\n $content = $responseData['choices'][0]['message']['content'];\n } else {\n\n $content = json_encode($responseData);\n }\n \n return parseAIResponse($content, $tables);\n}\n\n/**\n * Call Llama API to generate SQL\n */\nfunction callLlama($systemMessage, $userMessage, $apiKey, $apiModel, $tables) {\n\n $data = [\n 'model' => $apiModel,\n 'messages' => [\n ['role' => 'system', 'content' => $systemMessage],\n ['role' => 'user', 'content' => $userMessage]\n ],\n 'temperature' => 0.3,\n 'max_tokens' => 1000\n ];\n\n $ch = curl_init('https://api.llama-api.com/v1/chat/completions');\n \n\n curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n curl_setopt($ch, CURLOPT_POST, true);\n curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));\n curl_setopt($ch, CURLOPT_HTTPHEADER, [\n 'Content-Type: application/json',\n 'Authorization: Bearer ' . $apiKey\n ]);\n \n // SECURITY NOTE: SSL verification is disabled to handle environments with missing or outdated certificates.\n // In production, consider enabling proper SSL verification and installing required certificates.\n curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);\n curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);\n \n // Execute cURL request\n $response = curl_exec($ch);\n \n\n if (curl_errno($ch)) {\n $error = curl_error($ch);\n curl_close($ch);\n throw new Exception('cURL error: ' . $error);\n }\n \n\n $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);\n curl_close($ch);\n \n\n if ($httpCode >= 400) {\n throw new Exception('HTTP error ' . $httpCode . ': Llama API request failed. Response: ' . substr($response, 0, 200));\n }\n \n \n $responseData = json_decode($response, true);\n \n\n if (isset($responseData['error'])) {\n throw new Exception('Llama API error: ' . ($responseData['error']['message'] ?? json_encode($responseData['error'])));\n }\n \n\n $content = '';\n \n if (isset($responseData['choices'][0]['message']['content'])) {\n $content = $responseData['choices'][0]['message']['content'];\n } else {\n\n $content = json_encode($responseData);\n }\n \n return parseAIResponse($content, $tables);\n}\n\n/**\n * Parse AI response to extract SQL query and explanation\n */\nfunction parseAIResponse($content, $tables) {\n \n if (empty($content)) {\n return [\n 'sql_query' => \"SELECT * FROM \" . ($tables[0] ?? 'unknown_table') . \" LIMIT 10; -- AI response was empty\",\n 'explanation' => \"The AI didn't provide a valid response. Using a default query instead.\"\n ];\n }\n \n \n try {\n \n $content = trim($content);\n \n \n $content = preg_replace('/^```(?:json)?|```$/m', '', $content);\n \n \n $parsedResponse = json_decode($content, true);\n \n if (json_last_error() === JSON_ERROR_NONE && isset($parsedResponse['sql_query'])) {\n \n return [\n 'sql_query' => $parsedResponse['sql_query'],\n 'explanation' => $parsedResponse['explanation'] ?? \"The AI generated this SQL query based on your request.\"\n ];\n }\n \n \n if (preg_match('/\\{[\\s\\S]*?\\}/m', $content, $jsonMatches)) {\n $jsonContent = $jsonMatches[0];\n $parsedJson = json_decode($jsonContent, true);\n \n if (json_last_error() === JSON_ERROR_NONE && isset($parsedJson['sql_query'])) {\n return [\n 'sql_query' => $parsedJson['sql_query'],\n 'explanation' => $parsedJson['explanation'] ?? \"The AI generated this SQL query based on your request.\"\n ];\n }\n }\n \n \n if (preg_match('/```(?:sql)?\\s*([\\s\\S]*?)```/m', $content, $sqlMatches)) {\n $sql = trim($sqlMatches[1]);\n \n // Try to find explanation\n if (preg_match('/(?:explanation|here\\'s why|reasoning)(?:\\s*:|)\\s*([\\s\\S]*?)(?=```|$)/mi', $content, $explMatches)) {\n $explanation = trim($explMatches[1]);\n } else {\n $explanation = \"The AI generated a SQL query based on your request.\";\n }\n \n return [\n 'sql_query' => $sql,\n 'explanation' => $explanation\n ];\n }\n \n \n if (preg_match('/(SELECT|INSERT\\s+INTO|UPDATE|DELETE\\s+FROM|CREATE\\s+TABLE|ALTER\\s+TABLE|DROP\\s+TABLE|CREATE\\s+INDEX)\\s+[\\s\\S]*?;/mi', $content, $sqlMatches)) {\n $sql = trim($sqlMatches[0]);\n \n \n $contentParts = explode($sql, $content, 2);\n $explanation = !empty($contentParts[1]) ? trim($contentParts[1]) : \"Extracted SQL query from the AI response.\";\n \n return [\n 'sql_query' => $sql,\n 'explanation' => $explanation\n ];\n }\n \n \n if (preg_match('/[A-Za-z_][A-Za-z0-9_\\s\\.\\,\\(\\)\\=\\'\\\"\\`\\*\\+\\-\\/\\<\\>\\!\\%]*;/m', $content, $sqlMatches)) {\n $sql = trim($sqlMatches[0]);\n \n \n if (preg_match('/(select|from|where|order by|group by|having|limit|join|insert|update|delete|create|alter|drop)/i', $sql)) {\n return [\n 'sql_query' => $sql,\n 'explanation' => \"Extracted SQL query from the AI response text.\"\n ];\n }\n }\n \n \n return [\n 'sql_query' => \"SELECT * FROM \" . ($tables[0] ?? 'unknown_table') . \" LIMIT 10; -- Could not extract SQL from AI response\",\n 'explanation' => \"The AI response did not contain a valid SQL query. Using a default query instead.\\nOriginal response: \" . substr($content, 0, 100) . \"...\"\n ];\n } catch (Exception $e) {\n \n return [\n 'sql_query' => \"SELECT * FROM \" . ($tables[0] ?? 'unknown_table') . \" LIMIT 10; -- Error parsing AI response\",\n 'explanation' => \"Error parsing the AI response: \" . $e->getMessage() . \". Using a default query instead.\"\n ];\n }\n}\n\n/**\n * Generate SQL from natural language query\n * This is a pattern matching approach for common query patterns\n */\nfunction generateSQLFromNaturalLanguage($nlQuery, $tables, $tableColumns) {\n \n $nlQuery = trim(strtolower($nlQuery));\n \n\n $queryType = 'SELECT';\n $selectColumns = '*';\n $whereClause = '';\n $orderByClause = '';\n $limitClause = '';\n $joinClause = '';\n $groupByClause = '';\n $havingClause = '';\n \n \n $mainTable = findMainTable($nlQuery, $tables);\n $fromClause = \"`$mainTable`\";\n \n\n if (preg_match('/\\b(show|list|get|display|select|find|search|query|fetch|retrieve)\\b/', $nlQuery)) {\n $queryType = 'SELECT';\n \n \n if (preg_match('/\\b(count|how many)\\b/', $nlQuery)) {\n $selectColumns = \"COUNT(*)\";\n \n if (preg_match('/\\bdistinct\\b/', $nlQuery)) {\n \n foreach ($tableColumns[$mainTable] as $colInfo) {\n $colName = $colInfo['Field'];\n if (stripos($nlQuery, $colName) !== false) {\n $selectColumns = \"COUNT(DISTINCT `$colName`)\";\n break;\n }\n }\n }\n } else {\n \n $columnsToSelect = [];\n if (isset($tableColumns[$mainTable])) {\n foreach ($tableColumns[$mainTable] as $colInfo) {\n $colName = $colInfo['Field'];\n \n if (($colName === 'id' || preg_match('/_id$/', $colName)) && \n !preg_match('/\\bid\\b|\\bidentifier\\b/', $nlQuery)) {\n continue;\n }\n \n if (stripos($nlQuery, $colName) !== false) {\n $columnsToSelect[] = \"`$colName`\";\n }\n }\n }\n \n if (!empty($columnsToSelect)) {\n $selectColumns = implode(', ', $columnsToSelect);\n }\n }\n \n\n $whereConditions = [];\n \n \n $comparisonPatterns = [\n '/\\bwhere\\s+(\\w+)\\s+equals?\\s+([\"\\']?[\\w\\s]+[\"\\']?)/' => '`$1` = \\'$2\\'',\n '/\\bwhere\\s+(\\w+)\\s+is\\s+([\"\\']?[\\w\\s]+[\"\\']?)/' => '`$1` = \\'$2\\'',\n '/\\bwhere\\s+(\\w+)\\s+greater than\\s+([\"\\']?[\\w\\s]+[\"\\']?)/' => '`$1` > \\'$2\\'',\n '/\\bwhere\\s+(\\w+)\\s+less than\\s+([\"\\']?[\\w\\s]+[\"\\']?)/' => '`$1` < \\'$2\\'',\n '/\\bwhere\\s+(\\w+)\\s+contains\\s+([\"\\']?[\\w\\s]+[\"\\']?)/' => '`$1` LIKE \\'%$2%\\'',\n '/\\bwhere\\s+(\\w+)\\s+starts with\\s+([\"\\']?[\\w\\s]+[\"\\']?)/' => '`$1` LIKE \\'$2%\\'',\n '/\\bwhere\\s+(\\w+)\\s+ends with\\s+([\"\\']?[\\w\\s]+[\"\\']?)/' => '`$1` LIKE \\'%$2\\'',\n ];\n \n foreach ($comparisonPatterns as $pattern => $replacement) {\n if (preg_match($pattern, $nlQuery, $matches)) {\n $condition = preg_replace($pattern, $replacement, $matches[0]);\n $whereConditions[] = $condition;\n }\n }\n \n\n if (preg_match('/\\b(\\w+)\\s+(greater than|more than|higher than|>)\\s+(\\d+)/', $nlQuery, $matches)) {\n $whereConditions[] = \"`{$matches[1]}` > {$matches[3]}\";\n }\n \n if (preg_match('/\\b(\\w+)\\s+(less than|lower than|<)\\s+(\\d+)/', $nlQuery, $matches)) {\n $whereConditions[] = \"`{$matches[1]}` < {$matches[3]}\";\n }\n \n\n if (preg_match('/\\b(from|between)\\s+(\\d{4}-\\d{2}-\\d{2})\\s+(to|and)\\s+(\\d{4}-\\d{2}-\\d{2})/', $nlQuery, $matches)) {\n \n $dateColumn = null;\n foreach ($tableColumns[$mainTable] as $colInfo) {\n if (strpos(strtolower($colInfo['Type']), 'date') !== false) {\n $dateColumn = $colInfo['Field'];\n break;\n }\n }\n \n if ($dateColumn) {\n $whereConditions[] = \"`$dateColumn` BETWEEN '{$matches[2]}' AND '{$matches[4]}'\";\n }\n }\n \n\n if (!empty($whereConditions)) {\n $whereClause = \"WHERE \" . implode(' AND ', $whereConditions);\n }\n \n \n if (preg_match('/\\b(order|sort)\\s+by\\s+(\\w+)\\s+(asc|ascending|desc|descending)/', $nlQuery, $matches)) {\n $direction = (strpos($matches[3], 'desc') === 0) ? 'DESC' : 'ASC';\n $orderByClause = \"ORDER BY `{$matches[2]}` $direction\";\n }\n\n if (preg_match('/\\blimit\\s+(\\d+)/', $nlQuery, $matches)) {\n $limitClause = \"LIMIT {$matches[1]}\";\n } else if (preg_match('/\\b(top|first)\\s+(\\d+)/', $nlQuery, $matches)) {\n $limitClause = \"LIMIT {$matches[2]}\";\n }\n \n if (preg_match('/\\bgroup\\s+by\\s+(\\w+)/', $nlQuery, $matches)) {\n $groupByClause = \"GROUP BY `{$matches[1]}`\";\n }\n }\n \n else if (preg_match('/\\b(insert|add|create|new)\\b/', $nlQuery)) {\n $queryType = 'INSERT';\n \n return \"INSERT INTO `$mainTable` (...) VALUES (...)\";\n }\n \n else if (preg_match('/\\b(update|modify|change|edit)\\b/', $nlQuery)) {\n $queryType = 'UPDATE';\n \n return \"UPDATE `$mainTable` SET ... WHERE ...\";\n }\n\n else if (preg_match('/\\b(delete|remove|drop)\\b/', $nlQuery)) {\n $queryType = 'DELETE';\n \n return \"DELETE FROM `$mainTable` WHERE ...\";\n }\n \n\n $sqlQuery = \"$queryType $selectColumns FROM $fromClause\";\n \n if (!empty($joinClause)) {\n $sqlQuery .= \" $joinClause\";\n }\n \n if (!empty($whereClause)) {\n $sqlQuery .= \" $whereClause\";\n }\n \n if (!empty($groupByClause)) {\n $sqlQuery .= \" $groupByClause\";\n }\n \n if (!empty($havingClause)) {\n $sqlQuery .= \" $havingClause\";\n }\n \n if (!empty($orderByClause)) {\n $sqlQuery .= \" $orderByClause\";\n }\n \n if (!empty($limitClause)) {\n $sqlQuery .= \" $limitClause\";\n }\n \n $sqlQuery .= \";\";\n \n return $sqlQuery;\n}\n\n/**\n * Determine which table is most likely the main one from the natural language query\n */\nfunction findMainTable($nlQuery, $tables) {\n foreach ($tables as $table) {\n \n $singular = rtrim($table, 's');\n \n if (stripos($nlQuery, $table) !== false || \n (strlen($singular) > 3 && stripos($nlQuery, $singular) !== false)) {\n return $table;\n }\n }\n \n return $tables[0] ?? 'unknown_table';\n}\n\n/**\n * Generate an explanation of how the SQL query was derived from natural language\n */\nfunction explainQueryGeneration($nlQuery, $sqlQuery) {\n return \"Converted your question \\\"$nlQuery\\\" into a SQL query by identifying the main table, \n relevant columns, and conditions. The generated query retrieves the data you're looking for.\";\n}\n\n/**\n * Call DeepSeek free models without API key\n */\nfunction callDeepSeekFree($systemMessage, $userMessage, $tables) {\n\n $data = [\n 'model' => 'deepseek-coder-v2', \n 'messages' => [\n ['role' => 'system', 'content' => $systemMessage],\n ['role' => 'user', 'content' => $userMessage]\n ],\n 'temperature' => 0.3,\n 'max_tokens' => 1000\n ];\n \n \n $ch = curl_init('https://api.deepseek.com/v1/chat/completions');\n\n curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\n curl_setopt($ch, CURLOPT_POST, true);\n curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));\n curl_setopt($ch, CURLOPT_HTTPHEADER, [\n 'Content-Type: application/json'\n ]);\n \n // SECURITY NOTE: SSL verification is disabled to handle environments with missing or outdated certificates.\n // In production, consider enabling proper SSL verification and installing required certificates.\n curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);\n curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);\n \n \n $response = curl_exec($ch);\n \n \n if (curl_errno($ch)) {\n $error = curl_error($ch);\n curl_close($ch);\n \n \n $fallbackResponse = [\n 'sql_query' => \"SELECT * FROM \" . ($tables[0] ?? 'unknown_table') . \" LIMIT 10; -- Connection error with DeepSeek API\",\n 'explanation' => \"Could not connect to DeepSeek free service: \" . $error . \"\\nUsing a default query instead.\"\n ];\n \n return $fallbackResponse;\n }\n \n \n $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);\n curl_close($ch);\n \n \n if ($httpCode >= 400) {\n $fallbackResponse = [\n 'sql_query' => \"SELECT * FROM \" . ($tables[0] ?? 'unknown_table') . \" LIMIT 10; -- HTTP error with DeepSeek API\",\n 'explanation' => \"HTTP error \" . $httpCode . \" when calling DeepSeek free service. Using a default query instead.\"\n ];\n \n return $fallbackResponse;\n }\n \n\n $responseData = json_decode($response, true);\n \n\n if (isset($responseData['choices'][0]['message']['content'])) {\n $content = $responseData['choices'][0]['message']['content'];\n return parseAIResponse($content, $tables);\n } else {\n // Return a more helpful fallback response\n $fallbackResponse = [\n 'sql_query' => \"SELECT * FROM \" . ($tables[0] ?? 'unknown_table') . \" LIMIT 10; -- Invalid response from DeepSeek API\",\n 'explanation' => \"Received an invalid response format from DeepSeek free service. Using a default query instead.\"\n ];\n \n return $fallbackResponse;\n }\n} "}}}}