Autosave: 20260502-171721

This commit is contained in:
Flatlogic Bot 2026-05-02 17:17:21 +00:00
parent 9e51645c2f
commit 7781b48bf8
7 changed files with 1154 additions and 266 deletions

View File

@ -4,7 +4,7 @@ require_once __DIR__ . '/db/config.php';
// Sessions setup (Must match index.php) // Sessions setup (Must match index.php)
$sessions_dir = __DIR__ . '/sessions'; $sessions_dir = __DIR__ . '/sessions';
if (is_dir($sessions_dir) && is_writable($sessions_dir)) { if (is_dir($sessions_dir) && is_writable($sessions_dir)) {
session_save_path($sessions_dir); session_save_path("0;0660;" . $sessions_dir);
} }
// Enhanced session security and iframe compatibility (Must match index.php) // Enhanced session security and iframe compatibility (Must match index.php)

View File

@ -3,6 +3,70 @@ header('Content-Type: application/json');
require_once __DIR__ . '/../db/config.php'; require_once __DIR__ . '/../db/config.php';
require_once __DIR__ . '/../ai/LocalAIApi.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); $input = json_decode(file_get_contents('php://input'), true);
$message = $input['message'] ?? ''; $message = $input['message'] ?? '';
@ -12,53 +76,47 @@ if (empty($message)) {
} }
try { try {
// 1. Fetch Knowledge Base (FAQs) $faqs = chatFetchFaqs();
$stmt = db()->query("SELECT keywords, answer FROM faqs");
$faqs = $stmt->fetchAll(PDO::FETCH_ASSOC);
$knowledgeBase = "Here is the knowledge base for this website:\n\n"; $knowledgeBase = '';
foreach ($faqs as $faq) { if ($faqs !== []) {
$knowledgeBase .= "Q: " . $faq['keywords'] . "\nA: " . $faq['answer'] . "\n---\n"; $knowledgeBase = "Here is the knowledge base for this website:
";
foreach ($faqs as $faq) {
$knowledgeBase .= "Q: " . ($faq['keywords'] ?? '') . "
A: " . ($faq['answer'] ?? '') . "
---
";
}
} }
// 2. Construct Prompt for AI
$systemPrompt = "You are a helpful, friendly AI assistant for this website. " . $systemPrompt = "You are a helpful, friendly AI assistant for this website. " .
"Use the provided Knowledge Base to answer user questions accurately. " . "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 found in the Knowledge Base, rephrase it naturally. " .
"If the answer is NOT in the Knowledge Base, use your general knowledge to help, " . "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. " . "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.\n\n" . "Keep answers concise and professional.
" .
$knowledgeBase; $knowledgeBase;
// 3. Call AI API
$response = LocalAIApi::createResponse([ $response = LocalAIApi::createResponse([
'model' => 'gpt-4o-mini',
'input' => [ 'input' => [
['role' => 'system', 'content' => $systemPrompt], ['role' => 'system', 'content' => $systemPrompt],
['role' => 'user', 'content' => $message], ['role' => 'user', 'content' => $message],
] ],
]); ]);
if (!empty($response['success'])) { if (!empty($response['success'])) {
$aiReply = LocalAIApi::extractText($response); $aiReply = LocalAIApi::extractText($response);
chatStoreMessage($message, $aiReply);
// 4. Save to Database
try {
$stmt = db()->prepare("INSERT INTO messages (user_message, ai_response) VALUES (?, ?)");
$stmt->execute([$message, $aiReply]);
} catch (Exception $e) {
error_log("DB Save Error: " . $e->getMessage());
// Continue even if save fails, so the user still gets a reply
}
echo json_encode(['reply' => $aiReply]); echo json_encode(['reply' => $aiReply]);
} else { } else {
// Fallback if AI fails error_log('AI Error: ' . ($response['error'] ?? 'Unknown'));
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."]); echo json_encode(['reply' => "I'm having trouble connecting to my brain right now. Please try again later."]);
} }
} catch (Throwable $e) {
} catch (Exception $e) { error_log('Chat Error: ' . $e->getMessage());
error_log("Chat Error: " . $e->getMessage()); echo json_encode(['reply' => 'An internal error occurred.']);
echo json_encode(['reply' => "An internal error occurred."]);
} }

View File

@ -2,8 +2,115 @@
require_once __DIR__ . '/../db/config.php'; require_once __DIR__ . '/../db/config.php';
require_once __DIR__ . '/../ai/LocalAIApi.php'; require_once __DIR__ . '/../ai/LocalAIApi.php';
// Get Telegram Update function telegramTableExists(string $table): bool
$content = file_get_contents("php://input"); {
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 telegramColumnExists(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 telegramSettingValue(string $key): ?string
{
try {
if (telegramColumnExists('settings', 'key') && telegramColumnExists('settings', 'value')) {
$stmt = db()->prepare("SELECT `value` FROM settings WHERE `key` = ? LIMIT 1");
$stmt->execute([$key]);
$value = $stmt->fetchColumn();
return $value === false ? null : (string)$value;
}
if (telegramColumnExists('settings', 'setting_key') && telegramColumnExists('settings', 'setting_value')) {
$stmt = db()->prepare("SELECT setting_value FROM settings WHERE setting_key = ? LIMIT 1");
$stmt->execute([$key]);
$value = $stmt->fetchColumn();
return $value === false ? null : (string)$value;
}
} catch (Throwable $e) {
error_log('Telegram settings error: ' . $e->getMessage());
}
return null;
}
function telegramFetchFaqs(): array
{
if (!telegramTableExists('faqs') || !telegramColumnExists('faqs', 'keywords') || !telegramColumnExists('faqs', 'answer')) {
return [];
}
$stmt = db()->query("SELECT keywords, answer FROM faqs");
return $stmt ? $stmt->fetchAll(PDO::FETCH_ASSOC) : [];
}
function telegramStoreMessage(string $userMessage, string $aiResponse): void
{
if (!telegramTableExists('messages') || !telegramColumnExists('messages', 'user_message') || !telegramColumnExists('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('Telegram DB Save Error: ' . $e->getMessage());
}
}
function sendTelegramMessage($chatId, $text, $token)
{
$url = "https://api.telegram.org/bot$token/sendMessage";
$data = [
'chat_id' => $chatId,
'text' => $text,
'parse_mode' => 'Markdown',
];
$options = [
'http' => [
'header' => "Content-type: application/x-www-form-urlencoded
",
'method' => 'POST',
'content' => http_build_query($data),
],
];
$context = stream_context_create($options);
return file_get_contents($url, false, $context);
}
$content = file_get_contents('php://input');
$update = json_decode($content, true); $update = json_decode($content, true);
if (!$update || !isset($update['message'])) { if (!$update || !isset($update['message'])) {
@ -11,81 +118,56 @@ if (!$update || !isset($update['message'])) {
} }
$message = $update['message']; $message = $update['message'];
$chatId = $message['chat']['id']; $chatId = $message['chat']['id'] ?? null;
$text = $message['text'] ?? ''; $text = $message['text'] ?? '';
if (empty($text)) { if ($chatId === null || $text === '') {
exit; exit;
} }
// Get Telegram Token from DB $token = telegramSettingValue('telegram_token');
$stmt = db()->query("SELECT setting_value FROM settings WHERE setting_key = 'telegram_token'");
$token = $stmt->fetchColumn();
if (!$token) { if (!$token) {
error_log("Telegram Error: No bot token found in settings."); error_log('Telegram Error: No bot token found in settings.');
exit; exit;
} }
function sendTelegramMessage($chatId, $text, $token) {
$url = "https://api.telegram.org/bot$token/sendMessage";
$data = [
'chat_id' => $chatId,
'text' => $text,
'parse_mode' => 'Markdown'
];
$options = [
'http' => [
'header' => "Content-type: application/x-www-form-urlencoded\r\n",
'method' => 'POST',
'content' => http_build_query($data),
],
];
$context = stream_context_create($options);
return file_get_contents($url, false, $context);
}
// Process with AI (Similar logic to api/chat.php)
try { try {
// 1. Fetch Knowledge Base $faqs = telegramFetchFaqs();
$stmt = db()->query("SELECT keywords, answer FROM faqs");
$faqs = $stmt->fetchAll(PDO::FETCH_ASSOC);
$knowledgeBase = "Here is the knowledge base for this website:\n\n"; $knowledgeBase = '';
foreach ($faqs as $faq) { if ($faqs !== []) {
$knowledgeBase .= "Q: " . $faq['keywords'] . "\nA: " . $faq['answer'] . "\n---\n"; $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 AI assistant integrated with Telegram. " . $systemPrompt = "You are a helpful AI assistant integrated with Telegram. " .
"Use the provided Knowledge Base to answer user questions. " . "Use the provided Knowledge Base to answer user questions. " .
"Keep answers concise for mobile reading. Use Markdown for formatting.\n\n" . "Keep answers concise for mobile reading. Use Markdown for formatting.
" .
$knowledgeBase; $knowledgeBase;
// 2. Call AI
$response = LocalAIApi::createResponse([ $response = LocalAIApi::createResponse([
'model' => 'gpt-4o-mini',
'input' => [ 'input' => [
['role' => 'system', 'content' => $systemPrompt], ['role' => 'system', 'content' => $systemPrompt],
['role' => 'user', 'content' => $text], ['role' => 'user', 'content' => $text],
] ],
]); ]);
if (!empty($response['success'])) { if (!empty($response['success'])) {
$aiReply = LocalAIApi::extractText($response); $aiReply = LocalAIApi::extractText($response);
telegramStoreMessage('[Telegram] ' . $text, $aiReply);
// 3. Save History
try {
$stmt = db()->prepare("INSERT INTO messages (user_message, ai_response) VALUES (?, ?)");
$stmt->execute(["[Telegram] " . $text, $aiReply]);
} catch (Exception $e) {}
// 4. Send back to Telegram
sendTelegramMessage($chatId, $aiReply, $token); sendTelegramMessage($chatId, $aiReply, $token);
} else { } else {
sendTelegramMessage($chatId, "I'm sorry, I encountered an error processing your request.", $token); sendTelegramMessage($chatId, "I'm sorry, I encountered an error processing your request.", $token);
} }
} catch (Throwable $e) {
} catch (Exception $e) { error_log('Telegram Webhook Error: ' . $e->getMessage());
error_log("Telegram Webhook Error: " . $e->getMessage());
} }

1118
index.php

File diff suppressed because it is too large Load Diff

View File

@ -27,7 +27,7 @@ function configureMigrationSession(): void
} }
if (is_writable($sessionsDir)) { if (is_writable($sessionsDir)) {
session_save_path($sessionsDir); session_save_path("0;0660;" . $sessionsDir);
} }
if ( if (

View File

@ -27,7 +27,7 @@ function configureSnapshotSession(): void
} }
if (is_writable($sessionsDir)) { if (is_writable($sessionsDir)) {
session_save_path($sessionsDir); session_save_path("0;0660;" . $sessionsDir);
} }
if ( if (

View File

@ -27,7 +27,7 @@ function configureSchemaDebugSession(): void
} }
if (is_writable($sessionsDir)) { if (is_writable($sessionsDir)) {
session_save_path($sessionsDir); session_save_path("0;0660;" . $sessionsDir);
} }
if ( if (