Autosave: 20260502-171721
This commit is contained in:
parent
9e51645c2f
commit
7781b48bf8
@ -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)
|
||||||
|
|||||||
112
api/chat.php
112
api/chat.php
@ -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."]);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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());
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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 (
|
||||||
|
|||||||
@ -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 (
|
||||||
|
|||||||
@ -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 (
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user