Sindbad~EG File Manager

Current Path : /home/copmadinaarea/thecopmadinaarea.org/portal/classes/
Upload File :
Current File : /home/copmadinaarea/thecopmadinaarea.org/portal/classes/ChatbotService.php

<?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