Sindbad~EG File Manager
<?php
class ChatbotService {
private $db;
private $settings;
public function __construct() {
$this->db = Database::getInstance()->getConnection();
$this->loadSettings();
}
private function loadSettings() {
$stmt = $this->db->query("SELECT setting_key, setting_value FROM chatbot_settings");
$this->settings = [];
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
$this->settings[$row['setting_key']] = $row['setting_value'];
}
}
public function isEnabled() {
return !empty($this->settings['enabled']);
}
public function getSetting($key, $default = null) {
return $this->settings[$key] ?? $default;
}
public function getAllSettings() {
return $this->settings;
}
public function updateSetting($key, $value, $userId = null) {
$stmt = $this->db->prepare("
INSERT INTO chatbot_settings (setting_key, setting_value, updated_by)
VALUES (:key, :value, :user_id)
ON DUPLICATE KEY UPDATE setting_value = :value2, updated_by = :user_id2
");
return $stmt->execute([
'key' => $key,
'value' => $value,
'value2' => $value,
'user_id' => $userId,
'user_id2' => $userId
]);
}
public function getOrCreateConversation($sessionId, $userId = null, $userName = null, $userEmail = null) {
// Check for existing active conversation
$stmt = $this->db->prepare("
SELECT id FROM chatbot_conversations
WHERE session_id = :session_id AND is_active = 1
ORDER BY started_at DESC LIMIT 1
");
$stmt->execute(['session_id' => $sessionId]);
$conversation = $stmt->fetch(PDO::FETCH_ASSOC);
if ($conversation) {
return $conversation['id'];
}
// Create new conversation
$stmt = $this->db->prepare("
INSERT INTO chatbot_conversations
(session_id, user_id, user_name, user_email, ip_address, user_agent)
VALUES (:session_id, :user_id, :user_name, :user_email, :ip_address, :user_agent)
");
$stmt->execute([
'session_id' => $sessionId,
'user_id' => $userId,
'user_name' => $userName,
'user_email' => $userEmail,
'ip_address' => $_SERVER['REMOTE_ADDR'] ?? null,
'user_agent' => $_SERVER['HTTP_USER_AGENT'] ?? null
]);
return $this->db->lastInsertId();
}
public function saveMessage($conversationId, $messageType, $message, $contextUsed = null, $sources = null, $responseTime = null) {
$stmt = $this->db->prepare("
INSERT INTO chatbot_messages
(conversation_id, message_type, message, context_used, sources, response_time_ms)
VALUES (:conversation_id, :message_type, :message, :context_used, :sources, :response_time)
");
$stmt->execute([
'conversation_id' => $conversationId,
'message_type' => $messageType,
'message' => $message,
'context_used' => $contextUsed ? json_encode($contextUsed) : null,
'sources' => $sources ? json_encode($sources) : null,
'response_time' => $responseTime
]);
return $this->db->lastInsertId();
}
public function getConversationHistory($conversationId, $limit = 10) {
$stmt = $this->db->prepare("
SELECT message_type, message, created_at, sources
FROM chatbot_messages
WHERE conversation_id = :conversation_id
ORDER BY created_at DESC
LIMIT :limit
");
$stmt->bindValue(':conversation_id', $conversationId, PDO::PARAM_INT);
$stmt->bindValue(':limit', $limit, PDO::PARAM_INT);
$stmt->execute();
return array_reverse($stmt->fetchAll(PDO::FETCH_ASSOC));
}
public function searchFAQs($query, $limit = 5) {
$stmt = $this->db->prepare("
SELECT id, question, answer, category, priority
FROM chatbot_faqs
WHERE is_active = 1
AND (MATCH(question, answer, keywords) AGAINST(:query IN NATURAL LANGUAGE MODE)
OR question LIKE :like_query
OR answer LIKE :like_query)
ORDER BY
priority DESC,
MATCH(question, answer, keywords) AGAINST(:query IN NATURAL LANGUAGE MODE) DESC
LIMIT :limit
");
$likeQuery = '%' . $query . '%';
$stmt->bindValue(':query', $query, PDO::PARAM_STR);
$stmt->bindValue(':like_query', $likeQuery, PDO::PARAM_STR);
$stmt->bindValue(':limit', $limit, PDO::PARAM_INT);
$stmt->execute();
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
public function searchDocuments($query, $limit = 3) {
$stmt = $this->db->prepare("
SELECT id, title, description, filename, file_path
FROM chatbot_documents
WHERE is_active = 1
AND MATCH(title, description, content_text) AGAINST(:query IN NATURAL LANGUAGE MODE)
ORDER BY MATCH(title, description, content_text) AGAINST(:query IN NATURAL LANGUAGE MODE) DESC
LIMIT :limit
");
$stmt->bindValue(':query', $query, PDO::PARAM_STR);
$stmt->bindValue(':limit', $limit, PDO::PARAM_INT);
$stmt->execute();
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
public function searchContext($query, $limit = 3) {
$stmt = $this->db->prepare("
SELECT id, context_type, context_key, context_title, context_content
FROM chatbot_context
WHERE MATCH(context_title, context_content) AGAINST(:query IN NATURAL LANGUAGE MODE)
ORDER BY
usage_count DESC,
MATCH(context_title, context_content) AGAINST(:query IN NATURAL LANGUAGE MODE) DESC
LIMIT :limit
");
$stmt->bindValue(':query', $query, PDO::PARAM_STR);
$stmt->bindValue(':limit', $limit, PDO::PARAM_INT);
$stmt->execute();
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
public function generateResponse($userMessage, $conversationId) {
$startTime = microtime(true);
$sources = [];
$contextUsed = [];
$response = '';
// 1. Search FAQs first
$faqs = $this->searchFAQs($userMessage, 3);
if (!empty($faqs)) {
$bestMatch = $faqs[0];
$sources[] = ['type' => 'faq', 'id' => $bestMatch['id'], 'title' => $bestMatch['question']];
$response = $bestMatch['answer'];
$contextUsed[] = 'faq';
// Update FAQ stats
$this->db->prepare("UPDATE chatbot_faqs SET view_count = view_count + 1 WHERE id = ?")
->execute([$bestMatch['id']]);
}
// 2. If no good FAQ match, search documents
if (empty($response)) {
$docs = $this->searchDocuments($userMessage, 2);
if (!empty($docs)) {
$response = "I found some relevant documents that might help:\n\n";
foreach ($docs as $doc) {
$sources[] = ['type' => 'document', 'id' => $doc['id'], 'title' => $doc['title']];
$response .= "📄 **{$doc['title']}**\n";
if (!empty($doc['description'])) {
$response .= "{$doc['description']}\n";
}
$response .= "\n";
}
$contextUsed[] = 'documents';
}
}
// 3. If still no match, search system context
if (empty($response)) {
$contexts = $this->searchContext($userMessage, 2);
if (!empty($contexts)) {
$bestContext = $contexts[0];
$sources[] = ['type' => 'context', 'key' => $bestContext['context_key'], 'title' => $bestContext['context_title']];
$response = $bestContext['context_content'];
$contextUsed[] = 'system_context';
// Update context usage
$this->db->prepare("UPDATE chatbot_context SET usage_count = usage_count + 1, last_used_at = NOW() WHERE id = ?")
->execute([$bestContext['id']]);
}
}
// 4. Default fallback response
if (empty($response)) {
$response = "I'm sorry, I couldn't find a specific answer to your question. However, I can help you with:\n\n";
$response .= "• **Membership** - Registration and membership cards\n";
$response .= "• **Events** - Check-ins and attendance\n";
$response .= "• **Directory** - Finding and searching members\n";
$response .= "• **Profile** - Updating your information\n\n";
$response .= "Could you rephrase your question or ask about one of these topics?";
$contextUsed[] = 'fallback';
}
$responseTime = round((microtime(true) - $startTime) * 1000);
// Save the response
$this->saveMessage($conversationId, 'bot', $response, $contextUsed, $sources, $responseTime);
return [
'response' => $response,
'sources' => $sources,
'response_time' => $responseTime
];
}
public function markMessageHelpful($messageId, $isHelpful) {
$stmt = $this->db->prepare("UPDATE chatbot_messages SET is_helpful = ? WHERE id = ?");
return $stmt->execute([$isHelpful ? 1 : 0, $messageId]);
}
public function rateConversation($conversationId, $rating, $feedback = null) {
$stmt = $this->db->prepare("UPDATE chatbot_conversations SET rating = ?, feedback = ? WHERE id = ?");
return $stmt->execute([$rating, $feedback, $conversationId]);
}
public function getStatistics() {
$stats = [];
// Total conversations
$stmt = $this->db->query("SELECT COUNT(*) as total FROM chatbot_conversations");
$stats['total_conversations'] = $stmt->fetch(PDO::FETCH_ASSOC)['total'];
// Total messages
$stmt = $this->db->query("SELECT COUNT(*) as total FROM chatbot_messages");
$stats['total_messages'] = $stmt->fetch(PDO::FETCH_ASSOC)['total'];
// Active FAQs
$stmt = $this->db->query("SELECT COUNT(*) as total FROM chatbot_faqs WHERE is_active = 1");
$stats['active_faqs'] = $stmt->fetch(PDO::FETCH_ASSOC)['total'];
// Active documents
$stmt = $this->db->query("SELECT COUNT(*) as total FROM chatbot_documents WHERE is_active = 1");
$stats['active_documents'] = $stmt->fetch(PDO::FETCH_ASSOC)['total'];
// Average rating
$stmt = $this->db->query("SELECT AVG(rating) as avg_rating FROM chatbot_conversations WHERE rating IS NOT NULL");
$stats['avg_rating'] = round($stmt->fetch(PDO::FETCH_ASSOC)['avg_rating'] ?? 0, 1);
return $stats;
}
}
Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists