38471-vm/api/chat.php
2026-05-02 17:17:21 +00:00

123 lines
3.8 KiB
PHP

<?php
header('Content-Type: application/json');
require_once __DIR__ . '/../db/config.php';
require_once __DIR__ . '/../ai/LocalAIApi.php';
function chatTableExists(string $table): bool
{
static $cache = [];
$table = strtolower($table);
if (array_key_exists($table, $cache)) {
return $cache[$table];
}
try {
$stmt = db()->prepare("SELECT 1 FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = ? LIMIT 1");
$stmt->execute([$table]);
$cache[$table] = (bool)$stmt->fetchColumn();
} catch (Throwable $e) {
$cache[$table] = false;
}
return $cache[$table];
}
function chatColumnExists(string $table, string $column): bool
{
static $cache = [];
$cacheKey = strtolower($table . '.' . $column);
if (array_key_exists($cacheKey, $cache)) {
return $cache[$cacheKey];
}
try {
$stmt = db()->prepare("SELECT 1 FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = ? AND COLUMN_NAME = ? LIMIT 1");
$stmt->execute([$table, $column]);
$cache[$cacheKey] = (bool)$stmt->fetchColumn();
} catch (Throwable $e) {
$cache[$cacheKey] = false;
}
return $cache[$cacheKey];
}
function chatFetchFaqs(): array
{
if (!chatTableExists('faqs') || !chatColumnExists('faqs', 'keywords') || !chatColumnExists('faqs', 'answer')) {
return [];
}
$stmt = db()->query("SELECT keywords, answer FROM faqs");
return $stmt ? $stmt->fetchAll(PDO::FETCH_ASSOC) : [];
}
function chatStoreMessage(string $userMessage, string $aiResponse): void
{
if (!chatTableExists('messages') || !chatColumnExists('messages', 'user_message') || !chatColumnExists('messages', 'ai_response')) {
return;
}
try {
$stmt = db()->prepare("INSERT INTO messages (user_message, ai_response) VALUES (?, ?)");
$stmt->execute([$userMessage, $aiResponse]);
} catch (Throwable $e) {
error_log('DB Save Error: ' . $e->getMessage());
}
}
$input = json_decode(file_get_contents('php://input'), true);
$message = $input['message'] ?? '';
if (empty($message)) {
echo json_encode(['reply' => "I didn't catch that. Could you repeat?"]);
exit;
}
try {
$faqs = chatFetchFaqs();
$knowledgeBase = '';
if ($faqs !== []) {
$knowledgeBase = "Here is the knowledge base for this website:
";
foreach ($faqs as $faq) {
$knowledgeBase .= "Q: " . ($faq['keywords'] ?? '') . "
A: " . ($faq['answer'] ?? '') . "
---
";
}
}
$systemPrompt = "You are a helpful, friendly AI assistant for this website. " .
"Use the provided Knowledge Base to answer user questions accurately. " .
"If the answer is found in the Knowledge Base, rephrase it naturally. " .
"If the answer is NOT in the Knowledge Base, use your general knowledge to help, " .
"but politely mention that you don't have specific information about that if it seems like a site-specific question. " .
"Keep answers concise and professional.
" .
$knowledgeBase;
$response = LocalAIApi::createResponse([
'input' => [
['role' => 'system', 'content' => $systemPrompt],
['role' => 'user', 'content' => $message],
],
]);
if (!empty($response['success'])) {
$aiReply = LocalAIApi::extractText($response);
chatStoreMessage($message, $aiReply);
echo json_encode(['reply' => $aiReply]);
} else {
error_log('AI Error: ' . ($response['error'] ?? 'Unknown'));
echo json_encode(['reply' => "I'm having trouble connecting to my brain right now. Please try again later."]);
}
} catch (Throwable $e) {
error_log('Chat Error: ' . $e->getMessage());
echo json_encode(['reply' => 'An internal error occurred.']);
}