181 lines
5.4 KiB
PHP
181 lines
5.4 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
|
|
require_once __DIR__ . '/../db/schema.php';
|
|
require_once __DIR__ . '/../ai/LocalAIApi.php';
|
|
|
|
function sendTelegramMessage(int|string $chatId, string $text, string $token): bool
|
|
{
|
|
$url = "https://api.telegram.org/bot{$token}/sendMessage";
|
|
$data = [
|
|
'chat_id' => $chatId,
|
|
'text' => $text,
|
|
];
|
|
|
|
$options = [
|
|
'http' => [
|
|
'header' => "Content-type: application/x-www-form-urlencoded
|
|
",
|
|
'method' => 'POST',
|
|
'content' => http_build_query($data),
|
|
'timeout' => 20,
|
|
],
|
|
];
|
|
|
|
$context = stream_context_create($options);
|
|
$result = @file_get_contents($url, false, $context);
|
|
|
|
return $result !== false;
|
|
}
|
|
|
|
function findFaqReply(array $faqs, string $message): string
|
|
{
|
|
$normalizedMessage = function_exists('mb_strtolower')
|
|
? mb_strtolower($message, 'UTF-8')
|
|
: strtolower($message);
|
|
|
|
foreach ($faqs as $faq) {
|
|
$keywords = isset($faq['keywords']) && is_string($faq['keywords'])
|
|
? preg_split('/\s*,\s*/', $faq['keywords'])
|
|
: [];
|
|
|
|
foreach ($keywords as $keyword) {
|
|
if (!is_string($keyword) || $keyword === '') {
|
|
continue;
|
|
}
|
|
|
|
$needle = function_exists('mb_strtolower')
|
|
? mb_strtolower($keyword, 'UTF-8')
|
|
: strtolower($keyword);
|
|
|
|
$found = function_exists('mb_strpos')
|
|
? mb_strpos($normalizedMessage, $needle, 0, 'UTF-8') !== false
|
|
: strpos($normalizedMessage, $needle) !== false;
|
|
|
|
if ($needle !== '' && $found) {
|
|
return (string) ($faq['answer'] ?? '');
|
|
}
|
|
}
|
|
}
|
|
|
|
return '';
|
|
}
|
|
|
|
$content = file_get_contents('php://input');
|
|
$update = json_decode($content ?: '', true);
|
|
|
|
if (!is_array($update) || !isset($update['message']) || !is_array($update['message'])) {
|
|
exit;
|
|
}
|
|
|
|
$message = $update['message'];
|
|
$chatId = $message['chat']['id'] ?? null;
|
|
$text = isset($message['text']) && is_string($message['text']) ? trim($message['text']) : '';
|
|
|
|
if ($chatId === null || $text === '') {
|
|
exit;
|
|
}
|
|
|
|
try {
|
|
ensureSupportSchema();
|
|
|
|
$stmt = db()->prepare('SELECT setting_value FROM settings WHERE setting_key = :setting_key LIMIT 1');
|
|
$stmt->bindValue(':setting_key', 'telegram_token');
|
|
$stmt->execute();
|
|
$token = (string) ($stmt->fetchColumn() ?: '');
|
|
|
|
if ($token === '') {
|
|
error_log('Telegram Error: No bot token found in settings.');
|
|
exit;
|
|
}
|
|
|
|
$faqs = [];
|
|
try {
|
|
$stmt = db()->query('SELECT keywords, answer FROM faqs ORDER BY id ASC');
|
|
$faqs = $stmt->fetchAll(PDO::FETCH_ASSOC) ?: [];
|
|
} catch (Throwable $faqError) {
|
|
error_log('Telegram FAQ Load Error: ' . $faqError->getMessage());
|
|
}
|
|
|
|
$faqReply = findFaqReply($faqs, $text);
|
|
if ($faqReply !== '') {
|
|
try {
|
|
$stmt = db()->prepare('INSERT INTO messages (user_message, ai_response) VALUES (:user_message, :ai_response)');
|
|
$stmt->bindValue(':user_message', '[Telegram] ' . $text);
|
|
$stmt->bindValue(':ai_response', $faqReply);
|
|
$stmt->execute();
|
|
} catch (Throwable $saveError) {
|
|
error_log('Telegram Save Error: ' . $saveError->getMessage());
|
|
}
|
|
|
|
sendTelegramMessage($chatId, $faqReply, $token);
|
|
exit;
|
|
}
|
|
|
|
$knowledgeBase = "Berikut knowledge base website ini:
|
|
|
|
";
|
|
if ($faqs === []) {
|
|
$knowledgeBase .= "- Belum ada FAQ khusus yang dikonfigurasi.
|
|
";
|
|
} else {
|
|
foreach ($faqs as $faq) {
|
|
$knowledgeBase .= 'Q: ' . ($faq['keywords'] ?? '') . "
|
|
";
|
|
$knowledgeBase .= 'A: ' . ($faq['answer'] ?? '') . "
|
|
---
|
|
";
|
|
}
|
|
}
|
|
|
|
$systemPrompt = "Anda adalah asisten AI Telegram untuk website ini. "
|
|
. "Gunakan knowledge base bila relevan. "
|
|
. "Jawab ringkas, jelas, dan profesional dalam Bahasa Indonesia.
|
|
|
|
"
|
|
. $knowledgeBase;
|
|
|
|
$response = LocalAIApi::createResponse(
|
|
[
|
|
'input' => [
|
|
['role' => 'system', 'content' => $systemPrompt],
|
|
['role' => 'user', 'content' => $text],
|
|
],
|
|
],
|
|
[
|
|
'poll_interval' => 2,
|
|
'poll_timeout' => 45,
|
|
]
|
|
);
|
|
|
|
if (!empty($response['success'])) {
|
|
$aiReply = LocalAIApi::extractText($response);
|
|
if ($aiReply === '') {
|
|
$decoded = LocalAIApi::decodeJsonFromResponse($response);
|
|
if ($decoded) {
|
|
$aiReply = json_encode($decoded, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
|
|
}
|
|
}
|
|
if ($aiReply === '') {
|
|
$aiReply = 'Pesan Anda sudah diterima, tetapi balasan otomatis belum tersedia saat ini.';
|
|
}
|
|
|
|
try {
|
|
$stmt = db()->prepare('INSERT INTO messages (user_message, ai_response) VALUES (:user_message, :ai_response)');
|
|
$stmt->bindValue(':user_message', '[Telegram] ' . $text);
|
|
$stmt->bindValue(':ai_response', $aiReply);
|
|
$stmt->execute();
|
|
} catch (Throwable $saveError) {
|
|
error_log('Telegram Save Error: ' . $saveError->getMessage());
|
|
}
|
|
|
|
sendTelegramMessage($chatId, $aiReply, $token);
|
|
exit;
|
|
}
|
|
|
|
error_log('Telegram AI Error: ' . ($response['error'] ?? 'Unknown'));
|
|
sendTelegramMessage($chatId, 'Maaf, saya belum bisa memproses permintaan Anda saat ini.', $token);
|
|
} catch (Throwable $error) {
|
|
error_log('Telegram Webhook Error: ' . $error->getMessage());
|
|
}
|