From 0490892e313879efcbe1207fb8a4788af1c4c9ab Mon Sep 17 00:00:00 2001 From: Flatlogic Bot Date: Thu, 11 Sep 2025 22:08:13 +0000 Subject: [PATCH] ai chat bot! --- .env | 3 +- .env.example | 1 + api/chat.php | 122 +++++++++++++++++++++++++++--------------- api/error.log | 7 +++ assets/js/main.js | 2 +- db/config.php | 4 +- lib/OpenAIService.php | 38 ++++++++----- 7 files changed, 117 insertions(+), 60 deletions(-) create mode 100644 api/error.log diff --git a/.env b/.env index f7ae637..189e151 100644 --- a/.env +++ b/.env @@ -1 +1,2 @@ -OPENAI_API_KEY=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 \ No newline at end of file +OPENAI_API_KEY=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 +OPENAI_MODEL=gpt-4o diff --git a/.env.example b/.env.example index e570b8b..da275fa 100644 --- a/.env.example +++ b/.env.example @@ -1 +1,2 @@ OPENAI_API_KEY= +OPENAI_MODEL=gpt-4o-mini \ No newline at end of file diff --git a/api/chat.php b/api/chat.php index 87f0a45..e17d8dc 100644 --- a/api/chat.php +++ b/api/chat.php @@ -1,58 +1,92 @@ 'An unexpected error occurred.', + 'message' => $exception->getMessage(), + 'file' => $exception->getFile(), + 'line' => $exception->getLine(), + ]; + file_put_contents($logFile, json_encode($error, JSON_PRETTY_PRINT)); + // We must output valid JSON, otherwise the frontend will get a syntax error. + echo json_encode($error); +}); require_once __DIR__ . '/../lib/config.php'; require_once __DIR__ . '/../lib/OpenAIService.php'; require_once __DIR__ . '/../db/config.php'; -header('Content-Type: application/json'); - -session_start(); -if (empty($_SESSION['session_id'])) { - $_SESSION['session_id'] = bin2hex(random_bytes(16)); -} -$session_id = $_SESSION['session_id']; - -if ($_SERVER['REQUEST_METHOD'] !== 'POST') { - echo json_encode(['error' => 'Invalid request method.']); - exit; -} - -$input = json_decode(file_get_contents('php://input'), true); - -if (!isset($input['message']) || trim($input['message']) === '') { - echo json_encode(['error' => 'Message is required.']); - exit; -} - -$user_message = trim($input['message']); - +// The main try-catch block for the application logic. try { - $pdo = db(); - // Save user message - $stmt = $pdo->prepare("INSERT INTO chat_log (session_id, sender, message) VALUES (?, ?, ?)"); - $stmt->execute([$session_id, 'user', $user_message]); - - // Get AI response - $response = OpenAIService::getCompletion($user_message); - - if (!empty($response['error'])) { - http_response_code(500); - echo json_encode($response); - exit; + // Check if it's a POST request + if ($_SERVER['REQUEST_METHOD'] !== 'POST') { + http_response_code(405); // Method Not Allowed + throw new Exception('Only POST requests are allowed.'); } - $ai_message = $response['reply']; + // Get the user's message from the request body + $json_data = file_get_contents('php://input'); + $data = json_decode($json_data); + $user_message = $data->message ?? ''; - // Save AI message + if (empty($user_message)) { + http_response_code(400); // Bad Request + throw new Exception('Message is required.'); + } + + // --- Database Interaction --- + $pdo = db(); + if (empty($_SESSION['chat_session_id'])) { + $_SESSION['chat_session_id'] = bin2hex(random_bytes(16)); + } + $chat_session_id = $_SESSION['chat_session_id']; + + // Log the user's message $stmt = $pdo->prepare("INSERT INTO chat_log (session_id, sender, message) VALUES (?, ?, ?)"); - $stmt->execute([$session_id, 'ai', $ai_message]); + $stmt->execute([$chat_session_id, 'user', $user_message]); - echo json_encode(['reply' => $ai_message]); + // --- OpenAI API Call --- + $bot_response_data = OpenAIService::getCompletion($user_message); + + if (isset($bot_response_data['error'])) { + throw new Exception('OpenAI API Error: ' . $bot_response_data['error']); + } + $bot_response = $bot_response_data['reply']; + + // Log the bot's response + $stmt = $pdo->prepare("INSERT INTO chat_log (session_id, sender, message) VALUES (?, ?, ?)"); + $stmt->execute([$chat_session_id, 'bot', $bot_response]); -} catch (PDOException $e) { - // Log error and return a generic error message - error_log("Database error: " . $e->getMessage()); - echo json_encode(['error' => 'An internal server error occurred.']); - exit; -} \ No newline at end of file + // --- Send Response --- + header('Content-Type: application/json'); + echo json_encode(['reply' => $bot_response]); + +} catch (Throwable $e) { + // This will catch both Exceptions and Errors + http_response_code(500); + $errorDetails = [ + 'error' => 'Caught in main try-catch', + 'message' => $e->getMessage(), + 'file' => $e->getFile(), + 'line' => $e->getLine(), + 'trace' => $e->getTraceAsString() + ]; + file_put_contents($logFile, date('Y-m-d H:i:s') . " - " . json_encode($errorDetails, JSON_PRETTY_PRINT) . " +", FILE_APPEND); + // Ensure a JSON response is sent on error + header('Content-Type: application/json'); + echo json_encode($errorDetails); +} diff --git a/api/error.log b/api/error.log new file mode 100644 index 0000000..2396d6e --- /dev/null +++ b/api/error.log @@ -0,0 +1,7 @@ +2025-09-11 22:08:09 - { + "error": "Caught in main try-catch", + "message": "Only POST requests are allowed.", + "file": "\/home\/ubuntu\/executor\/workspace\/api\/chat.php", + "line": 37, + "trace": "#0 {main}" +} diff --git a/assets/js/main.js b/assets/js/main.js index 86e0ead..8bca9c4 100644 --- a/assets/js/main.js +++ b/assets/js/main.js @@ -42,7 +42,7 @@ document.addEventListener('DOMContentLoaded', () => { if(data.error) { appendMessage(data.error, 'ai'); } else { - appendMessage(data.message, 'ai'); // Bug fix: data.reply -> data.message + appendMessage(data.reply, 'ai'); } } catch (error) { diff --git a/db/config.php b/db/config.php index 499d974..d7a7fc3 100644 --- a/db/config.php +++ b/db/config.php @@ -29,10 +29,10 @@ function db() { // Now, connect to the newly created database $pdo = new PDO($dsn . ';dbname=' . DB_NAME, DB_USER, DB_PASS, $options); } catch (PDOException $ce) { - die("Failed to create database and connect: " . $ce->getMessage()); + throw new PDOException("Failed to create database and connect: " . $ce->getMessage()); } } else { - die("Database connection failed: " . $e->getMessage()); + throw new PDOException("Database connection failed: " . $e->getMessage()); } } diff --git a/lib/OpenAIService.php b/lib/OpenAIService.php index 7d7db5a..d8b354d 100644 --- a/lib/OpenAIService.php +++ b/lib/OpenAIService.php @@ -3,10 +3,12 @@ class OpenAIService { private static $apiKey; + private static $model; public static function init() { self::$apiKey = getenv('OPENAI_API_KEY'); + self::$model = getenv('OPENAI_MODEL') ?: 'gpt-4o-mini'; } public static function getCompletion($message) @@ -18,7 +20,7 @@ class OpenAIService $url = 'https://api.openai.com/v1/chat/completions'; $data = [ - 'model' => 'gpt-3.5-turbo', + 'model' => self::$model, 'messages' => [ ['role' => 'system', 'content' => 'You are a helpful assistant.'], ['role' => 'user', 'content' => $message] @@ -31,19 +33,31 @@ class OpenAIService 'Authorization: Bearer ' . self::$apiKey ]; - $ch = curl_init($url); - curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); - curl_setopt($ch, CURLOPT_POST, true); - curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data)); - curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); + $options = [ + 'http' => [ + 'header' => implode("\r\n", $headers), + 'method' => 'POST', + 'content' => json_encode($data), + 'ignore_errors' => true, + 'timeout' => 30, + ], + ]; - $response = curl_exec($ch); - $httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE); - $error = curl_error($ch); - curl_close($ch); + $context = stream_context_create($options); + $response = @file_get_contents($url, false, $context); - if ($error) { - return ['error' => 'API call failed: ' . $error]; + // Get HTTP status code from the response headers + $httpcode = 0; + if (isset($http_response_header[0])) { + preg_match('{HTTP/1\.\d (\d{3})}', $http_response_header[0], $matches); + if (isset($matches[1])) { + $httpcode = (int)$matches[1]; + } + } + + if ($response === false) { + $error = error_get_last(); + return ['error' => 'API call failed: ' . ($error['message'] ?? 'Unknown error')]; } if ($httpcode !== 200) {