| @@ -382,9 +382,9 @@ | ||
| 382 | 382 | //error_log('[DEBUG] ---------- mxchat_handle_save_email_and_response START ----------'); |
| 383 | 383 | |
| 384 | 384 | // Validate nonce |
| 385 | 385 | if (!isset($_POST['nonce']) || !wp_verify_nonce($_POST['nonce'], 'mxchat_chat_nonce')) { |
| 386 | - error_log(esc_html__('[ERROR] Invalid nonce in mxchat_handle_save_email_and_response', 'mxchat')); | |
| 386 | + //error_log(esc_html__('[ERROR] Invalid nonce in mxchat_handle_save_email_and_response', 'mxchat')); | |
| 387 | 387 | wp_send_json_error(['message' => esc_html__('Invalid nonce.', 'mxchat')]); |
| 388 | 388 | wp_die(); |
| 389 | 389 | } |
| 390 | 390 | |
| @@ -703,8 +703,30 @@ | ||
| 703 | 703 | |
| 704 | 704 | // Preserve code blocks from markdown conversion |
| 705 | 705 | $message = preg_replace('/```(\w+)?\s*([\s\S]+?)```/s', '<pre><code class="$1">$2</code></pre>', $message); |
| 706 | 706 | |
| 707 | +// Check if any add-ons want to pre-process this message (for web search etc.) | |
| 708 | +$pre_processed_result = apply_filters('mxchat_pre_process_message', $message, $user_id, $session_id); | |
| 709 | + | |
| 710 | +// If the pre-processing returned a result (not the original message), use it directly | |
| 711 | +if (is_array($pre_processed_result) && isset($pre_processed_result['text'])) { | |
| 712 | + // Save the AI response | |
| 713 | + $this->mxchat_save_chat_message($session_id, 'bot', $pre_processed_result['text']); | |
| 714 | + | |
| 715 | + // Save HTML content if provided | |
| 716 | + if (!empty($pre_processed_result['html'])) { | |
| 717 | + $this->mxchat_save_chat_message($session_id, 'bot', $pre_processed_result['html']); | |
| 718 | + } | |
| 719 | + | |
| 720 | + // Return the response | |
| 721 | + wp_send_json([ | |
| 722 | + 'text' => $pre_processed_result['text'], | |
| 723 | + 'html' => $pre_processed_result['html'] ?? '', | |
| 724 | + 'session_id' => $session_id | |
| 725 | + ]); | |
| 726 | + wp_die(); | |
| 727 | +} | |
| 728 | + | |
| 707 | 729 | // Save the user's message |
| 708 | 730 | $this->mxchat_save_chat_message($session_id, 'user', $message); |
| 709 | 731 | |
| 710 | 732 | // Check if the message is an email address |
| @@ -928,8 +950,11 @@ | ||
| 928 | 950 | } |
| 929 | 951 | $context_content .= "\n"; |
| 930 | 952 | } |
| 931 | 953 | } |
| 954 | + | |
| 955 | + $context_content = apply_filters('mxchat_prepare_context', $context_content, $session_id); | |
| 956 | + | |
| 932 | 957 | // Generate the response using the full context |
| 933 | 958 | $response = $this->mxchat_generate_response( |
| 934 | 959 | $context_content, |
| 935 | 960 | $this->options['api_key'], |
| @@ -960,42 +985,30 @@ | ||
| 960 | 985 | wp_send_json($response_data); |
| 961 | 986 | wp_die(); |
| 962 | 987 | } |
| 963 | 988 | |
| 964 | - | |
| 965 | -// Helper function to clear PDF and Word document related transients | |
| 966 | -private function clear_pdf_transients($session_id) { | |
| 967 | - // PDF transients | |
| 968 | - delete_transient('mxchat_pdf_url_' . $session_id); | |
| 969 | - delete_transient('mxchat_pdf_embeddings_' . $session_id); | |
| 970 | - delete_transient('mxchat_include_pdf_in_context_' . $session_id); | |
| 971 | - delete_transient('mxchat_waiting_for_pdf_url_' . $session_id); | |
| 972 | - | |
| 973 | - // Word document transients | |
| 974 | - delete_transient('mxchat_word_url_' . $session_id); | |
| 975 | - delete_transient('mxchat_word_filename_' . $session_id); | |
| 976 | - delete_transient('mxchat_word_embeddings_' . $session_id); | |
| 977 | - delete_transient('mxchat_include_word_in_context_' . $session_id); | |
| 978 | - delete_transient('mxchat_waiting_for_word_' . $session_id); | |
| 979 | -} | |
| 980 | - | |
| 981 | 989 | // New function to check intents and invoke the callback function |
| 982 | 990 | private function mxchat_check_intent_and_invoke_callback($message, $user_id, $session_id) { |
| 983 | 991 | global $wpdb; |
| 984 | 992 | $chat_mode = get_option("mxchat_mode_{$session_id}", 'ai'); |
| 985 | 993 | |
| 986 | - //error_log("[MxChat] Checking intents for message: " . $message); | |
| 994 | + //error_log('🔍 MXCHAT DEBUG: Intent Check Started =================='); | |
| 995 | + //error_log("🔍 MXCHAT DEBUG: Message: '$message'"); | |
| 996 | + //error_log("🔍 MXCHAT DEBUG: Chat Mode: $chat_mode"); | |
| 987 | 997 | |
| 988 | 998 | // Generate the user embedding |
| 999 | + //error_log('🔄 MXCHAT DEBUG: Generating user embedding'); | |
| 989 | 1000 | $user_embedding = $this->mxchat_generate_embedding($message, $this->options['api_key']); |
| 990 | 1001 | if (!is_array($user_embedding)) { |
| 991 | - //error_log("[MxChat] Failed to generate user embedding"); | |
| 1002 | + //error_log('❌ MXCHAT DEBUG: Failed to generate user embedding'); | |
| 992 | 1003 | return false; |
| 993 | 1004 | } |
| 1005 | + //error_log('✅ MXCHAT DEBUG: User embedding generated successfully'); | |
| 994 | 1006 | |
| 995 | 1007 | // Fetch intents from the database |
| 996 | 1008 | $table_name = $wpdb->prefix . 'mxchat_intents'; |
| 997 | 1009 | if ($chat_mode === 'agent') { |
| 1010 | + //error_log('🔍 MXCHAT DEBUG: Agent mode - fetching only chatbot switch intent'); | |
| 998 | 1011 | $query = $wpdb->prepare( |
| 999 | 1012 | "SELECT * FROM $table_name WHERE callback_function = %s", |
| 1000 | 1013 | 'mxchat_handle_switch_to_chatbot_intent' |
| 1001 | 1014 | ); |
| @@ -1000,15 +1013,16 @@ | ||
| 1000 | 1013 | 'mxchat_handle_switch_to_chatbot_intent' |
| 1001 | 1014 | ); |
| 1002 | 1015 | $intents = $wpdb->get_results($query); |
| 1003 | 1016 | } else { |
| 1017 | + //error_log('🔍 MXCHAT DEBUG: AI mode - fetching all intents'); | |
| 1004 | 1018 | $intents = $wpdb->get_results("SELECT * FROM $table_name"); |
| 1005 | 1019 | } |
| 1006 | 1020 | |
| 1007 | - //error_log("[MxChat] Found " . count($intents) . " intents to check"); | |
| 1021 | + //error_log('🔍 MXCHAT DEBUG: Found ' . count($intents) . ' intents to check'); | |
| 1008 | 1022 | |
| 1009 | 1023 | if (empty($intents)) { |
| 1010 | - //error_log("[MxChat] No intents found in database"); | |
| 1024 | + //error_log('❌ MXCHAT DEBUG: No intents found in database'); | |
| 1011 | 1025 | return false; |
| 1012 | 1026 | } |
| 1013 | 1027 | |
| 1014 | 1028 | $highest_similarity = -INF; |
| @@ -1013,10 +1027,11 @@ | ||
| 1013 | 1027 | |
| 1014 | 1028 | $highest_similarity = -INF; |
| 1015 | 1029 | $matched_intent = null; |
| 1016 | 1030 | |
| 1031 | + //error_log('📊 MXCHAT DEBUG: Intent Similarity Scores =================='); | |
| 1017 | 1032 | foreach ($intents as $intent) { |
| 1018 | - //error_log("[MxChat] Checking intent: " . $intent->intent_label . " (callback: " . $intent->callback_function . ")"); | |
| 1033 | + //error_log("🔄 MXCHAT DEBUG: Checking intent: '{$intent->intent_label}' (callback: {$intent->callback_function})"); | |
| 1019 | 1034 | |
| 1020 | 1035 | $intent_embedding_serialized = $intent->embedding_vector; |
| 1021 | 1036 | $intent_embedding = $intent_embedding_serialized |
| 1022 | 1037 | ? unserialize($intent_embedding_serialized, ['allowed_classes' => false]) |
| @@ -1022,9 +1037,9 @@ | ||
| 1022 | 1037 | ? unserialize($intent_embedding_serialized, ['allowed_classes' => false]) |
| 1023 | 1038 | : null; |
| 1024 | 1039 | |
| 1025 | 1040 | if (!is_array($intent_embedding)) { |
| 1026 | - //error_log("[MxChat] Invalid embedding for intent: " . $intent->intent_label); | |
| 1041 | + //error_log("❌ MXCHAT DEBUG: Invalid embedding for intent: {$intent->intent_label}"); | |
| 1027 | 1042 | continue; |
| 1028 | 1043 | } |
| 1029 | 1044 | |
| 1030 | 1045 | $similarity = $this->mxchat_calculate_cosine_similarity($user_embedding, $intent_embedding); |
| @@ -1029,30 +1044,34 @@ | ||
| 1029 | 1044 | |
| 1030 | 1045 | $similarity = $this->mxchat_calculate_cosine_similarity($user_embedding, $intent_embedding); |
| 1031 | 1046 | $intent_threshold = isset($intent->similarity_threshold) ? $intent->similarity_threshold : 0.85; |
| 1032 | 1047 | |
| 1033 | - //error_log("[MxChat] Similarity for {$intent->intent_label}: {$similarity} (threshold: {$intent_threshold})"); | |
| 1034 | 1048 | |
| 1035 | 1049 | if ($similarity >= $intent_threshold && $similarity > $highest_similarity) { |
| 1036 | 1050 | $highest_similarity = $similarity; |
| 1037 | 1051 | $matched_intent = $intent; |
| 1038 | - //error_log("[MxChat] New best match: {$intent->intent_label} with similarity {$similarity}"); | |
| 1052 | + //error_log("✅ MXCHAT DEBUG: New best match: '{$intent->intent_label}' with similarity {$similarity}"); | |
| 1039 | 1053 | } |
| 1040 | 1054 | } |
| 1055 | + //error_log('📊 MXCHAT DEBUG: End Intent Scores =================='); | |
| 1041 | 1056 | |
| 1042 | 1057 | if ($matched_intent) { |
| 1043 | - //error_log("[MxChat] Invoking callback: " . $matched_intent->callback_function); | |
| 1058 | + //error_log("🎯 MXCHAT DEBUG: Final Intent Match: '{$matched_intent->intent_label}'"); | |
| 1059 | + //error_log("🔄 MXCHAT DEBUG: Invoking callback: {$matched_intent->callback_function}"); | |
| 1044 | 1060 | |
| 1045 | 1061 | // If the callback is a method on this instance (core callback), call it directly |
| 1046 | 1062 | if (method_exists($this, $matched_intent->callback_function)) { |
| 1063 | + //error_log('🔍 MXCHAT DEBUG: Using direct method call for core callback'); | |
| 1047 | 1064 | $callback_result = call_user_func( |
| 1048 | - [$this, $matched_intent->callback_function], | |
| 1049 | - $message, | |
| 1050 | - $user_id, | |
| 1051 | - $session_id, | |
| 1052 | - $matched_intent | |
| 1053 | - ); | |
| 1065 | + [$this, $matched_intent->callback_function], | |
| 1066 | + $message, | |
| 1067 | + $user_id, | |
| 1068 | + $session_id, | |
| 1069 | + $matched_intent, | |
| 1070 | + $user_context // Add user context | |
| 1071 | + ); | |
| 1054 | 1072 | } else { |
| 1073 | + //error_log('🔍 MXCHAT DEBUG: Using apply_filters for add-on callback'); | |
| 1055 | 1074 | // Otherwise, use apply_filters for add-on callbacks |
| 1056 | 1075 | $callback_result = apply_filters( |
| 1057 | 1076 | $matched_intent->callback_function, |
| 1058 | 1077 | false, // default return value |
| @@ -1062,159 +1081,42 @@ | ||
| 1062 | 1081 | $matched_intent |
| 1063 | 1082 | ); |
| 1064 | 1083 | } |
| 1065 | 1084 | |
| 1066 | - //error_log("[MxChat] Callback result: " . print_r($callback_result, true)); | |
| 1085 | + //error_log('🔍 MXCHAT DEBUG: Callback result type: ' . gettype($callback_result)); | |
| 1067 | 1086 | if ($callback_result !== false) { |
| 1087 | + //error_log('✅ MXCHAT DEBUG: Intent handled successfully'); | |
| 1068 | 1088 | $this->fallbackResponse = $callback_result; |
| 1069 | 1089 | return true; |
| 1070 | 1090 | } |
| 1091 | + //error_log('❌ MXCHAT DEBUG: Callback returned false'); | |
| 1092 | + } else { | |
| 1093 | + //error_log('❌ MXCHAT DEBUG: No matching intent found'); | |
| 1071 | 1094 | } |
| 1072 | 1095 | |
| 1073 | - //error_log("[MxChat] No matching intent found"); | |
| 1096 | + //error_log('🔍 MXCHAT DEBUG: Intent Check Completed =================='); | |
| 1074 | 1097 | return false; |
| 1075 | 1098 | } |
| 1076 | 1099 | |
| 1077 | 1100 | |
| 1078 | -//verified good | |
| 1079 | -public function mxchat_handle_order_history($message, $user_id, $session_id) { | |
| 1080 | - if (!class_exists('WooCommerce')) { | |
| 1081 | - $this->fallbackResponse['text'] = esc_html__("I can't access order information right now. The order system seems to be unavailable.", 'mxchat'); | |
| 1082 | - return true; | |
| 1083 | - } | |
| 1101 | +// Helper function to clear PDF and Word document related transients | |
| 1102 | +private function clear_pdf_transients($session_id) { | |
| 1103 | + // PDF transients | |
| 1104 | + delete_transient('mxchat_pdf_url_' . $session_id); | |
| 1105 | + delete_transient('mxchat_pdf_embeddings_' . $session_id); | |
| 1106 | + delete_transient('mxchat_include_pdf_in_context_' . $session_id); | |
| 1107 | + delete_transient('mxchat_waiting_for_pdf_url_' . $session_id); | |
| 1084 | 1108 | |
| 1085 | - $orderDetails = MxChat_WooCommerce::mxchat_fetch_user_orders_details('all'); | |
| 1086 | - | |
| 1087 | - if (empty($orderDetails)) { | |
| 1088 | - $this->fallbackResponse['text'] = esc_html__("I don't see any orders associated with your account. Are you logged in?", 'mxchat'); | |
| 1089 | - return true; | |
| 1090 | - } | |
| 1091 | - | |
| 1092 | - // Generate AI prompt with context | |
| 1093 | - $prompt = __("User asked about their orders:", 'mxchat') . " '{$message}'\n\n"; | |
| 1094 | - $prompt .= __("Order information:", 'mxchat') . "\n"; | |
| 1095 | - foreach ($orderDetails as $order) { | |
| 1096 | - $items_list = array_map(function($item) { | |
| 1097 | - return "{$item['name']} ({$item['quantity']})"; | |
| 1098 | - }, $order['items']); | |
| 1099 | - | |
| 1100 | - $prompt .= __("Order #", 'mxchat') . "{$order['order_id']}: {$order['formatted_total']} " . __("on", 'mxchat') . " {$order['date']}\n"; | |
| 1101 | - $prompt .= __("Items:", 'mxchat') . " " . implode(', ', $items_list) . "\n"; | |
| 1102 | - } | |
| 1103 | - | |
| 1104 | - $prompt .= __("\nProvide a natural, conversational response focusing on the specific information the user asked about. ", 'mxchat'); | |
| 1105 | - $prompt .= __("If they ask about a specific order or detail, provide just that information. ", 'mxchat'); | |
| 1106 | - $prompt .= __("If they ask about license keys or sensitive information, inform them to check their email or contact support.", 'mxchat'); | |
| 1107 | - | |
| 1108 | - // Get AI response | |
| 1109 | - $ai_response = $this->mxchat_call_ai_api($prompt); | |
| 1110 | - $this->fallbackResponse['text'] = $ai_response['text']; | |
| 1111 | - | |
| 1112 | - return true; | |
| 1109 | + // Word document transients | |
| 1110 | + delete_transient('mxchat_word_url_' . $session_id); | |
| 1111 | + delete_transient('mxchat_word_filename_' . $session_id); | |
| 1112 | + delete_transient('mxchat_word_embeddings_' . $session_id); | |
| 1113 | + delete_transient('mxchat_include_word_in_context_' . $session_id); | |
| 1114 | + delete_transient('mxchat_waiting_for_word_' . $session_id); | |
| 1113 | 1115 | } |
| 1114 | 1116 | |
| 1115 | 1117 | |
| 1116 | -public function mxchat_handle_product_inquiry($message, $user_id, $session_id) { | |
| 1117 | - //error_log("PRODUCT INQUIRY START - Message: $message, User ID: $user_id"); | |
| 1118 | 1118 | |
| 1119 | - // Sanitize user ID | |
| 1120 | - $sanitized_user_id = sanitize_key($user_id); | |
| 1121 | - //error_log("Sanitized User ID: $sanitized_user_id"); | |
| 1122 | - | |
| 1123 | - // Find product | |
| 1124 | - $product_id = $this->find_product_in_message($message); | |
| 1125 | - //error_log("Initial product ID from message: " . ($product_id ?? 'null')); | |
| 1126 | - | |
| 1127 | - // Check transient if no product found | |
| 1128 | - if (!$product_id) { | |
| 1129 | - $product_id = get_transient('mxchat_last_discussed_product_' . $sanitized_user_id); | |
| 1130 | - //error_log("Product ID from transient: " . ($product_id ?? 'null')); | |
| 1131 | - } | |
| 1132 | - | |
| 1133 | - // Handle product inquiries | |
| 1134 | - if ($product_id && class_exists('WooCommerce')) { | |
| 1135 | - $product = wc_get_product($product_id); | |
| 1136 | - if ($product) { | |
| 1137 | - //error_log("Found product: " . $product->get_name() . " (ID: $product_id)"); | |
| 1138 | - | |
| 1139 | - // Prepare product details | |
| 1140 | - $product_name = esc_html($product->get_name()); | |
| 1141 | - $product_price = $product->get_price_html(); | |
| 1142 | - $product_image_url = esc_url(wp_get_attachment_url($product->get_image_id())); | |
| 1143 | - $product_url = esc_url(get_permalink($product_id)); | |
| 1144 | - $product_id_attr = esc_attr($product_id); | |
| 1145 | - | |
| 1146 | - // Get product description | |
| 1147 | - $product_description = $product->get_description() ?: $product->get_short_description(); | |
| 1148 | - | |
| 1149 | - // Log embeddings process | |
| 1150 | - //error_log("Generating embedding for message: $message"); | |
| 1151 | - $user_message_embedding = $this->mxchat_generate_embedding($message, $this->options['api_key']); | |
| 1152 | - //error_log("Finding relevant content for product inquiry"); | |
| 1153 | - $relevant_content = $this->mxchat_find_relevant_content($user_message_embedding); | |
| 1154 | - | |
| 1155 | - // Build AI prompt | |
| 1156 | - $ai_prompt = esc_html__("You are a knowledgeable product assistant. ", 'mxchat'); | |
| 1157 | - $ai_prompt .= esc_html__("Respond to this user query: '{$message}'\n\n", 'mxchat'); | |
| 1158 | - | |
| 1159 | - if (!empty($relevant_content)) { | |
| 1160 | - $ai_prompt .= esc_html__("Relevant information from our knowledge base:\n{$relevant_content}\n\n", 'mxchat'); | |
| 1161 | - } | |
| 1162 | - | |
| 1163 | - $ai_prompt .= esc_html__("Product details:\n", 'mxchat'); | |
| 1164 | - $ai_prompt .= esc_html__("Name: {$product_name}\n", 'mxchat'); | |
| 1165 | - $ai_prompt .= esc_html__("Price: ", 'mxchat') . strip_tags($product_price) . "\n"; | |
| 1166 | - if ($product_description) { | |
| 1167 | - $ai_prompt .= esc_html__("Description: {$product_description}\n", 'mxchat'); | |
| 1168 | - } | |
| 1169 | - | |
| 1170 | - $ai_prompt .= esc_html__("\nInstructions:\n", 'mxchat'); | |
| 1171 | - $ai_prompt .= esc_html__("1. Address the user's specific question or concern about the product\n", 'mxchat'); | |
| 1172 | - $ai_prompt .= esc_html__("2. Incorporate relevant information from our knowledge base if provided\n", 'mxchat'); | |
| 1173 | - $ai_prompt .= esc_html__("3. Highlight key product features that relate to their query\n", 'mxchat'); | |
| 1174 | - $ai_prompt .= esc_html__("4. Include a natural suggestion to check out the product\n", 'mxchat'); | |
| 1175 | - $ai_prompt .= esc_html__("5. Keep the response conversational and helpful\n", 'mxchat'); | |
| 1176 | - | |
| 1177 | - //error_log("Sending AI prompt: " . $ai_prompt); | |
| 1178 | - | |
| 1179 | - // Build and log AI response | |
| 1180 | - $ai_response = $this->mxchat_call_ai_api($ai_prompt); | |
| 1181 | - //error_log("AI Response received for product inquiry: " . print_r($ai_response, true)); | |
| 1182 | - | |
| 1183 | - // Generate and log product card | |
| 1184 | - $product_card_html = <<<HTML | |
| 1185 | -<div class="mxchat-product-card"> | |
| 1186 | - <a href="{$product_url}" target="_blank"> | |
| 1187 | - <img src="{$product_image_url}" alt="{$product_name}" class="mxchat-product-image" /> | |
| 1188 | - <h3 class="mxchat-product-name">{$product_name}</h3> | |
| 1189 | - </a> | |
| 1190 | - <div class="mxchat-product-price">{$product_price}</div> | |
| 1191 | - <button class="mxchat-add-to-cart-button" data-product-id="{$product_id_attr}">Add to Cart</button> | |
| 1192 | -</div> | |
| 1193 | -HTML; | |
| 1194 | - | |
| 1195 | - // Save response and set transient | |
| 1196 | - $this->productCardHtml = $product_card_html; | |
| 1197 | - $this->fallbackResponse = [ | |
| 1198 | - 'text' => $ai_response['text'], | |
| 1199 | - 'html' => $this->productCardHtml, | |
| 1200 | - ]; | |
| 1201 | - | |
| 1202 | - //error_log("Setting transient for product: $product_id with key: mxchat_last_discussed_product_$sanitized_user_id"); | |
| 1203 | - set_transient('mxchat_last_discussed_product_' . $sanitized_user_id, $product_id, HOUR_IN_SECONDS); | |
| 1204 | - | |
| 1205 | - // Verify transient was set | |
| 1206 | - $verify_transient = get_transient('mxchat_last_discussed_product_' . $sanitized_user_id); | |
| 1207 | - //error_log("Verification - Retrieved transient value: " . ($verify_transient ?? 'null')); | |
| 1208 | - | |
| 1209 | - return true; | |
| 1210 | - } | |
| 1211 | - } | |
| 1212 | - | |
| 1213 | - //error_log("PRODUCT INQUIRY END - No product found or WooCommerce not available"); | |
| 1214 | - return false; | |
| 1215 | -} | |
| 1216 | - | |
| 1217 | 1119 | //verified good |
| 1218 | 1120 | public function mxchat_handle_email_capture($message, $user_id, $session_id) { |
| 1219 | 1121 | // Log the message safely |
| 1220 | 1122 | //error_log("Triggered email capture intent for message: " . sanitize_text_field($message)); |
| @@ -1254,18 +1156,20 @@ | ||
| 1254 | 1156 | $response_html = ''; |
| 1255 | 1157 | //error_log("DALL-E image generation error: " . esc_html($image_response['error'] ?? 'Unknown error.')); |
| 1256 | 1158 | } |
| 1257 | 1159 | |
| 1258 | - // Save both text and HTML responses | |
| 1259 | - $this->mxchat_save_chat_message($session_id, 'bot', $response_text . "\n" . $response_html); | |
| 1160 | + // Where you save the AI response | |
| 1161 | + if (!empty($response)) { | |
| 1162 | + $this->mxchat_save_chat_message($session_id, 'bot', $response); | |
| 1163 | + } | |
| 1164 | + | |
| 1165 | + // Similarly, when returning the response data | |
| 1166 | + $response_data = [ | |
| 1167 | + 'text' => empty($response) ? null : $response, // Use null instead of empty string | |
| 1168 | + 'html' => !empty($this->productCardHtml) ? $this->productCardHtml : ($this->fallbackResponse['html'] ?? ''), | |
| 1169 | + 'session_id' => $session_id | |
| 1170 | + ]; | |
| 1260 | 1171 | |
| 1261 | - // Prepare the response data | |
| 1262 | - $response_data = [ | |
| 1263 | - 'message' => $response_text, | |
| 1264 | - 'html' => $response_html, | |
| 1265 | - 'image_url' => $image_url ?? '', | |
| 1266 | - ]; | |
| 1267 | - | |
| 1268 | 1172 | // Send the JSON response |
| 1269 | 1173 | header('Content-Type: application/json; charset=' . get_option('blog_charset')); |
| 1270 | 1174 | echo json_encode($response_data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); |
| 1271 | 1175 | wp_die(); |
| @@ -1534,9 +1438,9 @@ | ||
| 1534 | 1438 | |
| 1535 | 1439 | if (empty($api_key)) { |
| 1536 | 1440 | /* |
| 1537 | 1441 | if (defined('WP_DEBUG') && WP_DEBUG) { |
| 1538 | - error_log("Brave API key is missing."); | |
| 1442 | + //error_log("Brave API key is missing."); | |
| 1539 | 1443 | } |
| 1540 | 1444 | */ |
| 1541 | 1445 | |
| 1542 | 1446 | $this->fallbackResponse = [ |
| @@ -1558,9 +1462,9 @@ | ||
| 1558 | 1462 | |
| 1559 | 1463 | /* |
| 1560 | 1464 | // Log the final API URL for the search |
| 1561 | 1465 | if (defined('WP_DEBUG') && WP_DEBUG) { |
| 1562 | - error_log("Final API URL for Brave Image Search: " . esc_url_raw($api_url)); | |
| 1466 | + //error_log("Final API URL for Brave Image Search: " . esc_url_raw($api_url)); | |
| 1563 | 1467 | } |
| 1564 | 1468 | */ |
| 1565 | 1469 | |
| 1566 | 1470 | |
| @@ -1582,9 +1486,9 @@ | ||
| 1582 | 1486 | |
| 1583 | 1487 | if (is_wp_error($response)) { |
| 1584 | 1488 | /* |
| 1585 | 1489 | if (defined('WP_DEBUG') && WP_DEBUG) { |
| 1586 | - error_log("Brave Image API request failed: " . $response->get_error_message()); | |
| 1490 | + //error_log("Brave Image API request failed: " . $response->get_error_message()); | |
| 1587 | 1491 | } |
| 1588 | 1492 | */ |
| 1589 | 1493 | |
| 1590 | 1494 | $this->fallbackResponse = [ |
| @@ -1628,9 +1532,9 @@ | ||
| 1628 | 1532 | |
| 1629 | 1533 | } else { |
| 1630 | 1534 | /* |
| 1631 | 1535 | if (defined('WP_DEBUG') && WP_DEBUG) { |
| 1632 | - error_log("Brave Image API response did not contain expected data structure or was empty: " . print_r($body, true)); | |
| 1536 | + //error_log("Brave Image API response did not contain expected data structure or was empty: " . print_r($body, true)); | |
| 1633 | 1537 | } |
| 1634 | 1538 | */ |
| 1635 | 1539 | |
| 1636 | 1540 | $this->fallbackResponse = [ |
| @@ -1647,9 +1551,9 @@ | ||
| 1647 | 1551 | |
| 1648 | 1552 | /* |
| 1649 | 1553 | // Log the API key check, without exposing the key |
| 1650 | 1554 | if (defined('WP_DEBUG') && WP_DEBUG) { |
| 1651 | - error_log("Retrieved OpenAI API Key: " . ($api_key ? "Present" : "Missing")); | |
| 1555 | + //error_log("Retrieved OpenAI API Key: " . ($api_key ? "Present" : "Missing")); | |
| 1652 | 1556 | } |
| 1653 | 1557 | */ |
| 1654 | 1558 | |
| 1655 | 1559 | if (empty($api_key)) { |
| @@ -1690,9 +1594,9 @@ | ||
| 1690 | 1594 | |
| 1691 | 1595 | /* |
| 1692 | 1596 | // Log the interpreted query for debugging |
| 1693 | 1597 | if (defined('WP_DEBUG') && WP_DEBUG) { |
| 1694 | - error_log("Interpreted search query: " . $interpreted_query); | |
| 1598 | + //error_log("Interpreted search query: " . $interpreted_query); | |
| 1695 | 1599 | } |
| 1696 | 1600 | */ |
| 1697 | 1601 | |
| 1698 | 1602 | return $interpreted_query; |
| @@ -1701,100 +1605,10 @@ | ||
| 1701 | 1605 | return sanitize_text_field($user_query); |
| 1702 | 1606 | } |
| 1703 | 1607 | } |
| 1704 | 1608 | |
| 1705 | -public function mxchat_handle_add_to_cart_intent($message, $user_id, $session_id) { | |
| 1706 | - //error_log("ADD TO CART START - Message: $message, User ID: $user_id"); | |
| 1707 | 1609 | |
| 1708 | - if (!class_exists('WooCommerce')) { | |
| 1709 | - //error_log("WooCommerce not available"); | |
| 1710 | - return $this->generate_intent_response([ | |
| 1711 | - 'intent' => 'add_to_cart', | |
| 1712 | - 'status' => 'error', | |
| 1713 | - 'reason' => esc_html__('woocommerce_not_available', 'mxchat') | |
| 1714 | - ], $session_id); | |
| 1715 | - } | |
| 1716 | 1610 | |
| 1717 | - $sanitized_user_id = sanitize_key($user_id); | |
| 1718 | - // error_log("Sanitized User ID: $sanitized_user_id"); | |
| 1719 | - $product_id = null; | |
| 1720 | - | |
| 1721 | - // If button click, use transient | |
| 1722 | - if ($message === '!addtocart') { | |
| 1723 | - //error_log("Button click detected - using transient"); | |
| 1724 | - $product_id = get_transient('mxchat_last_discussed_product_' . $sanitized_user_id); | |
| 1725 | - //error_log("Product ID from transient: " . ($product_id ?? 'null')); | |
| 1726 | - } else { | |
| 1727 | - // For text commands, search message first | |
| 1728 | - //error_log("Text command detected - searching message first"); | |
| 1729 | - $product_id = $this->find_product_in_message($message); | |
| 1730 | - //error_log("Product ID from message search: " . ($product_id ?? 'null')); | |
| 1731 | - | |
| 1732 | - // Only use transient as fallback if no product found in message | |
| 1733 | - if (!$product_id) { | |
| 1734 | - //error_log("No product found in message, checking transient as fallback"); | |
| 1735 | - $product_id = get_transient('mxchat_last_discussed_product_' . $sanitized_user_id); | |
| 1736 | - //error_log("Product ID from transient fallback: " . ($product_id ?? 'null')); | |
| 1737 | - } | |
| 1738 | - } | |
| 1739 | - | |
| 1740 | - // Handle no product found | |
| 1741 | - if (!$product_id) { | |
| 1742 | - //error_log("No product ID found through any method"); | |
| 1743 | - return $this->generate_intent_response([ | |
| 1744 | - 'intent' => 'add_to_cart', | |
| 1745 | - 'status' => 'error', | |
| 1746 | - 'reason' => esc_html__('no_product_context', 'mxchat'), | |
| 1747 | - 'action_needed' => esc_html__('request_product_name', 'mxchat'), | |
| 1748 | - 'searched_message' => $message | |
| 1749 | - ], $session_id); | |
| 1750 | - } | |
| 1751 | - | |
| 1752 | - // Get and verify product | |
| 1753 | - $product = wc_get_product($product_id); | |
| 1754 | - if (!$product) { | |
| 1755 | - //error_log("Product not found with ID: $product_id"); | |
| 1756 | - return $this->generate_intent_response([ | |
| 1757 | - 'intent' => 'add_to_cart', | |
| 1758 | - 'status' => 'error', | |
| 1759 | - 'reason' => esc_html__('product_not_found', 'mxchat'), | |
| 1760 | - 'product_id' => $product_id | |
| 1761 | - ], $session_id); | |
| 1762 | - } | |
| 1763 | - | |
| 1764 | - //error_log("Found product: " . $product->get_name() . " (ID: $product_id)"); | |
| 1765 | - | |
| 1766 | - // Add to cart | |
| 1767 | - $added = WC()->cart->add_to_cart($product_id); | |
| 1768 | - if ($added) { | |
| 1769 | - //error_log("Successfully added to cart: " . $product->get_name()); | |
| 1770 | - return $this->generate_intent_response([ | |
| 1771 | - 'intent' => 'add_to_cart', | |
| 1772 | - 'status' => 'success', | |
| 1773 | - 'product' => [ | |
| 1774 | - 'name' => $product->get_name(), | |
| 1775 | - 'id' => $product_id | |
| 1776 | - ], | |
| 1777 | - 'cart_url' => wc_get_cart_url(), | |
| 1778 | - 'available_actions' => [ | |
| 1779 | - esc_html__('view_cart', 'mxchat'), | |
| 1780 | - esc_html__('checkout', 'mxchat'), | |
| 1781 | - esc_html__('continue_shopping', 'mxchat') | |
| 1782 | - ] | |
| 1783 | - ], $session_id); | |
| 1784 | - } else { | |
| 1785 | - //error_log("Failed to add to cart: " . $product->get_name()); | |
| 1786 | - return $this->generate_intent_response([ | |
| 1787 | - 'intent' => 'add_to_cart', | |
| 1788 | - 'status' => 'error', | |
| 1789 | - 'reason' => esc_html__('add_to_cart_failed', 'mxchat'), | |
| 1790 | - 'product' => [ | |
| 1791 | - 'name' => $product->get_name(), | |
| 1792 | - 'id' => $product_id | |
| 1793 | - ] | |
| 1794 | - ], $session_id); | |
| 1795 | - } | |
| 1796 | -} | |
| 1797 | 1611 | private function find_product_in_message($message) { |
| 1798 | 1612 | global $wpdb; |
| 1799 | 1613 | |
| 1800 | 1614 | // Get embedding for the search query |
| @@ -1920,44 +1734,8 @@ | ||
| 1920 | 1734 | return $context_string; |
| 1921 | 1735 | } |
| 1922 | 1736 | |
| 1923 | 1737 | |
| 1924 | -public function mxchat_handle_checkout_intent($message, $user_id, $session_id) { | |
| 1925 | - if (!class_exists('WooCommerce')) { | |
| 1926 | - $this->fallbackResponse['text'] = esc_html__("I apologize, but the checkout feature isn't available at the moment.", 'mxchat'); | |
| 1927 | - return true; | |
| 1928 | - } | |
| 1929 | - | |
| 1930 | - // Check if cart has items | |
| 1931 | - if (WC()->cart->is_empty()) { | |
| 1932 | - $this->fallbackResponse['text'] = esc_html__("Your cart is empty at the moment. Would you like to see our products?", 'mxchat'); | |
| 1933 | - return true; | |
| 1934 | - } | |
| 1935 | - | |
| 1936 | - // Get cart summary | |
| 1937 | - $cart_count = WC()->cart->get_cart_contents_count(); | |
| 1938 | - $cart_total = WC()->cart->get_total(); | |
| 1939 | - | |
| 1940 | - // Get and validate checkout URL | |
| 1941 | - $checkout_url = wc_get_checkout_url(); | |
| 1942 | - if (!$checkout_url) { | |
| 1943 | - $this->fallbackResponse['text'] = esc_html__("I'm having trouble accessing the checkout page. Please try again in a moment.", 'mxchat'); | |
| 1944 | - return true; | |
| 1945 | - } | |
| 1946 | - | |
| 1947 | - wp_send_json([ | |
| 1948 | - 'text' => sprintf( | |
| 1949 | - esc_html__("You have %d item%s in your cart totaling %s. I'll redirect you to checkout now.", 'mxchat'), | |
| 1950 | - $cart_count, | |
| 1951 | - $cart_count > 1 ? esc_html__('s', 'mxchat') : '', | |
| 1952 | - strip_tags($cart_total) | |
| 1953 | - ), | |
| 1954 | - 'redirect_url' => esc_url_raw($checkout_url) | |
| 1955 | - ]); | |
| 1956 | - wp_die(); | |
| 1957 | -} | |
| 1958 | - | |
| 1959 | - | |
| 1960 | 1738 | //very good |
| 1961 | 1739 | private function add_email_to_loops($email) { |
| 1962 | 1740 | // Sanitize the email |
| 1963 | 1741 | $email = sanitize_email($email); |
| @@ -2118,9 +1896,9 @@ | ||
| 2118 | 1896 | |
| 2119 | 1897 | return $embeddings; |
| 2120 | 1898 | |
| 2121 | 1899 | } catch (\Exception $e) { |
| 2122 | - // error_log(esc_html__("Error parsing or processing PDF: ", 'mxchat') . $e->getMessage()); | |
| 1900 | + // //error_log(esc_html__("Error parsing or processing PDF: ", 'mxchat') . $e->getMessage()); | |
| 2123 | 1901 | |
| 2124 | 1902 | // Cleanup in case of exception |
| 2125 | 1903 | if (filter_var($pdf_source, FILTER_VALIDATE_URL) && $temp_file && file_exists($temp_file)) { |
| 2126 | 1904 | unlink($temp_file); |
| @@ -2250,408 +2028,10 @@ | ||
| 2250 | 2028 | wp_die(); |
| 2251 | 2029 | } |
| 2252 | 2030 | |
| 2253 | 2031 | |
| 2254 | -/** | |
| 2255 | - * Calls the AI API with the provided prompt. | |
| 2256 | - * | |
| 2257 | - * @param string $prompt The prompt to send to the AI. | |
| 2258 | - * @return array An array containing the AI's response text. | |
| 2259 | - */ | |
| 2260 | -private function mxchat_call_ai_api( $prompt ) { | |
| 2261 | - //error_log( esc_html__( 'Calling AI API with the provided prompt.', 'mxchat' ) ); | |
| 2262 | 2032 | |
| 2263 | - $api_key = $this->options['api_key']; | |
| 2264 | - if ( empty( $api_key ) ) { | |
| 2265 | - //error_log( esc_html__( 'API key is not set.', 'mxchat' ) ); | |
| 2266 | - return [ 'text' => esc_html__( 'API key is not set.', 'mxchat' ) ]; | |
| 2267 | - } | |
| 2268 | 2033 | |
| 2269 | - $url = 'https://api.openai.com/v1/chat/completions'; | |
| 2270 | - $messages = [ | |
| 2271 | - [ | |
| 2272 | - 'role' => 'system', | |
| 2273 | - 'content' => __( 'You are a helpful assistant that provides concise and personalized product recommendations. Someone has asked you for some recommendations please respond very concisely appropriate for an AI chatbot.', 'mxchat' ), | |
| 2274 | - ], | |
| 2275 | - [ | |
| 2276 | - 'role' => 'user', | |
| 2277 | - 'content' => $prompt, | |
| 2278 | - ], | |
| 2279 | - ]; | |
| 2280 | - | |
| 2281 | - $args = [ | |
| 2282 | - 'headers' => [ | |
| 2283 | - 'Authorization' => 'Bearer ' . $api_key, | |
| 2284 | - 'Content-Type' => 'application/json', | |
| 2285 | - ], | |
| 2286 | - 'body' => wp_json_encode( | |
| 2287 | - [ | |
| 2288 | - 'model' => 'gpt-4o', | |
| 2289 | - 'messages' => $messages, | |
| 2290 | - 'temperature' => 0.7, | |
| 2291 | - ] | |
| 2292 | - ), | |
| 2293 | - 'timeout' => 10, | |
| 2294 | - 'method' => 'POST', | |
| 2295 | - ]; | |
| 2296 | - | |
| 2297 | - $response = wp_remote_post( $url, $args ); | |
| 2298 | - | |
| 2299 | - if ( is_wp_error( $response ) ) { | |
| 2300 | - //error_log( esc_html__( 'Error communicating with AI API: ', 'mxchat' ) . $response->get_error_message() ); | |
| 2301 | - return [ 'text' => esc_html__( 'Error communicating with AI API.', 'mxchat' ) ]; | |
| 2302 | - } | |
| 2303 | - | |
| 2304 | - $body = wp_remote_retrieve_body( $response ); | |
| 2305 | - //error_log( esc_html__( 'API response body: ', 'mxchat' ) . $body ); | |
| 2306 | - | |
| 2307 | - $decoded_body = json_decode( $body, true ); | |
| 2308 | - if ( isset( $decoded_body['choices'][0]['message']['content'] ) ) { | |
| 2309 | - return [ 'text' => $decoded_body['choices'][0]['message']['content'] ]; | |
| 2310 | - } else { | |
| 2311 | - //error_log( esc_html__( 'Unexpected API response format: ', 'mxchat' ) . wp_json_encode( $decoded_body ) ); | |
| 2312 | - return [ 'text' => esc_html__( 'No response received from AI.', 'mxchat' ) ]; | |
| 2313 | - } | |
| 2314 | -} | |
| 2315 | - | |
| 2316 | -/** | |
| 2317 | - * Fetches the AI response for the given prompt. | |
| 2318 | - * | |
| 2319 | - * @param string $prompt The prompt to send to the AI. | |
| 2320 | - * @return string|null The AI's response text or null if not available. | |
| 2321 | - */ | |
| 2322 | -private function mxchat_fetch_ai_response( $prompt ) { | |
| 2323 | - $response = $this->mxchat_call_ai_api( $prompt ); | |
| 2324 | - return isset( $response['text'] ) ? $response['text'] : null; | |
| 2325 | -} | |
| 2326 | -/** | |
| 2327 | - * Generates the AI prompt for product recommendations. | |
| 2328 | - * | |
| 2329 | - * @param array $recommendations An array of product recommendations. | |
| 2330 | - * @return string The generated AI prompt. | |
| 2331 | - */ | |
| 2332 | -private function mxchat_generate_ai_recommendation_prompt($recommendations) { | |
| 2333 | - $recommendation_list = ''; | |
| 2334 | - foreach ($recommendations as $index => $rec) { | |
| 2335 | - $number = $index + 1; | |
| 2336 | - $name = $rec['name']; | |
| 2337 | - $price = $rec['price']; | |
| 2338 | - $url = $rec['url']; | |
| 2339 | - $image = $rec['image']; | |
| 2340 | - $recommendation_list .= "{$number}. " . esc_html__('Product:', 'mxchat') . " {$name} (" . esc_html__('Price:', 'mxchat') . " \\${$price})\n"; | |
| 2341 | - $recommendation_list .= " [Link]({$url})\n"; | |
| 2342 | - $recommendation_list .= " \n\n"; | |
| 2343 | - } | |
| 2344 | - | |
| 2345 | - $prompt = esc_html__('Based on the following list of products, generate a unique, friendly, and personalized response to a user. ', 'mxchat'); | |
| 2346 | - $prompt .= esc_html__('If some products aren\'t exactly what the user asked for but share similar styles or patterns, acknowledge this and explain why you\'re suggesting them. ', 'mxchat'); | |
| 2347 | - $prompt .= esc_html__('For each product, provide a brief justification that clearly explains why it\'s relevant, especially if it\'s a different type of product than requested. ', 'mxchat'); | |
| 2348 | - $prompt .= esc_html__('Please number your responses to match the product numbers.', 'mxchat') . "\n\n"; | |
| 2349 | - $prompt .= esc_html__('Products:', 'mxchat') . "\n\n{$recommendation_list}"; | |
| 2350 | - $prompt .= esc_html__('Please ensure that the number of each product matches the order in which the products are listed.', 'mxchat'); | |
| 2351 | - | |
| 2352 | - return $prompt; | |
| 2353 | -} | |
| 2354 | -private function mxchat_generate_recommendations($user_id, $message) { | |
| 2355 | - // 1. Gather user context | |
| 2356 | - $user_context = $this->mxchat_get_user_context($user_id); | |
| 2357 | - | |
| 2358 | - // Get cart item IDs for filtering | |
| 2359 | - $cart_item_ids = []; | |
| 2360 | - if (!empty($user_context['cart_items'])) { | |
| 2361 | - $cart_item_ids = array_map(function($item) { | |
| 2362 | - return $item['product_id']; | |
| 2363 | - }, $user_context['cart_items']); | |
| 2364 | - } | |
| 2365 | - | |
| 2366 | - // 2. Get AI recommendation based on context | |
| 2367 | - $ai_suggestion = $this->mxchat_get_ai_shopping_suggestion($message, $user_context); | |
| 2368 | - //error_log("AI Shopping Suggestion: " . $ai_suggestion); | |
| 2369 | - | |
| 2370 | - // 3. Generate embedding for the AI suggestion | |
| 2371 | - $suggestion_embedding = $this->mxchat_generate_embedding($ai_suggestion, $this->options['api_key']); | |
| 2372 | - if (!$suggestion_embedding) { | |
| 2373 | - //error_log("Could not generate embedding for AI suggestion"); | |
| 2374 | - return ['recommendations' => [], 'sources' => []]; | |
| 2375 | - } | |
| 2376 | - | |
| 2377 | - // 4. Use existing relevant content function to find matches | |
| 2378 | - $relevant_content = $this->mxchat_find_relevant_content($suggestion_embedding); | |
| 2379 | - | |
| 2380 | - // 5. Extract product URLs from the relevant content | |
| 2381 | - preg_match_all('/https?:\/\/[^\s<>"\']+?\/product\/[^\s<>"\']+/', $relevant_content, $matches); | |
| 2382 | - | |
| 2383 | - $found_products = []; | |
| 2384 | - if (!empty($matches[0])) { | |
| 2385 | - foreach ($matches[0] as $url) { | |
| 2386 | - // Clean the URL | |
| 2387 | - $url = rtrim($url, '/."\']'); | |
| 2388 | - | |
| 2389 | - // Get the product slug | |
| 2390 | - $path = parse_url($url, PHP_URL_PATH); | |
| 2391 | - $slug = basename(rtrim($path, '/')); | |
| 2392 | - | |
| 2393 | - // Find product by slug | |
| 2394 | - $args = array( | |
| 2395 | - 'post_type' => 'product', | |
| 2396 | - 'post_status' => 'publish', | |
| 2397 | - 'name' => $slug, | |
| 2398 | - 'posts_per_page' => 1 | |
| 2399 | - ); | |
| 2400 | - | |
| 2401 | - $products = get_posts($args); | |
| 2402 | - | |
| 2403 | - if (!empty($products)) { | |
| 2404 | - $product_id = $products[0]->ID; | |
| 2405 | - | |
| 2406 | - // Skip if product is in cart | |
| 2407 | - if (in_array($product_id, $cart_item_ids)) { | |
| 2408 | - //error_log("Skipping product ID $product_id - already in cart"); | |
| 2409 | - continue; | |
| 2410 | - } | |
| 2411 | - | |
| 2412 | - $product = wc_get_product($product_id); | |
| 2413 | - | |
| 2414 | - if ($product && $product->is_purchasable() && !in_array($product_id, array_map(function($p) { | |
| 2415 | - return $p->get_id(); | |
| 2416 | - }, $found_products))) { | |
| 2417 | - $found_products[] = $product; | |
| 2418 | - } | |
| 2419 | - } | |
| 2420 | - } | |
| 2421 | - } | |
| 2422 | - | |
| 2423 | - // If no products found by URLs, look for product names in the content | |
| 2424 | - if (empty($found_products)) { | |
| 2425 | - $products = wc_get_products([ | |
| 2426 | - 'status' => 'publish', | |
| 2427 | - 'limit' => -1, | |
| 2428 | - 'return' => 'objects' | |
| 2429 | - ]); | |
| 2430 | - | |
| 2431 | - foreach ($products as $product) { | |
| 2432 | - // Skip if product is in cart | |
| 2433 | - if (in_array($product->get_id(), $cart_item_ids)) { | |
| 2434 | - continue; | |
| 2435 | - } | |
| 2436 | - | |
| 2437 | - $name = $product->get_name(); | |
| 2438 | - if (stripos($relevant_content, $name) !== false) { | |
| 2439 | - if ($product->is_purchasable() && !in_array($product->get_id(), array_map(function($p) { | |
| 2440 | - return $p->get_id(); | |
| 2441 | - }, $found_products))) { | |
| 2442 | - $found_products[] = $product; | |
| 2443 | - } | |
| 2444 | - } | |
| 2445 | - } | |
| 2446 | - } | |
| 2447 | - | |
| 2448 | - // Keep searching until we have 4 products or run out of options | |
| 2449 | - $formatted_recommendations = []; | |
| 2450 | - foreach ($found_products as $product) { | |
| 2451 | - if (count($formatted_recommendations) >= 4) break; | |
| 2452 | - | |
| 2453 | - $formatted_recommendations[] = [ | |
| 2454 | - 'name' => $product->get_name(), | |
| 2455 | - 'price' => $product->get_price(), | |
| 2456 | - 'url' => get_permalink($product->get_id()), | |
| 2457 | - 'image' => wp_get_attachment_url($product->get_image_id()) | |
| 2458 | - ]; | |
| 2459 | - } | |
| 2460 | - | |
| 2461 | - return [ | |
| 2462 | - 'recommendations' => $formatted_recommendations, | |
| 2463 | - 'sources' => [__('AI-powered personalized recommendations', 'mxchat')] | |
| 2464 | - ]; | |
| 2465 | -} | |
| 2466 | -private function mxchat_get_ai_shopping_suggestion($message, $user_context) { | |
| 2467 | - $prompt = esc_html__("As a shopping assistant, analyze this user's context and generate a specific product search suggestion. ", 'mxchat'); | |
| 2468 | - $prompt .= esc_html__("User's Question: \"{$message}\"\n\n", 'mxchat'); | |
| 2469 | - | |
| 2470 | - if (!empty($user_context['order_history'])) { | |
| 2471 | - $prompt .= esc_html__("Their recent orders include:\n", 'mxchat'); | |
| 2472 | - foreach ($user_context['order_history'] as $order) { | |
| 2473 | - $prompt .= esc_html__("- {$order['name']} ({$order['date']})\n", 'mxchat'); | |
| 2474 | - } | |
| 2475 | - } | |
| 2476 | - | |
| 2477 | - if (!empty($user_context['cart_items'])) { | |
| 2478 | - $prompt .= esc_html__("\nThey currently have in their cart:\n", 'mxchat'); | |
| 2479 | - foreach ($user_context['cart_items'] as $item) { | |
| 2480 | - $prompt .= esc_html__("- {$item['name']}\n", 'mxchat'); | |
| 2481 | - } | |
| 2482 | - } | |
| 2483 | - | |
| 2484 | - $prompt .= esc_html__("\nBased on their question and history, suggest a specific search query that would help find the most relevant products. ", 'mxchat'); | |
| 2485 | - $prompt .= esc_html__("Respond with ONLY the search query, nothing else.", 'mxchat'); | |
| 2486 | - | |
| 2487 | - $response = $this->mxchat_call_ai_api($prompt); | |
| 2488 | - return isset($response['text']) ? trim($response['text']) : $message; | |
| 2489 | -} | |
| 2490 | -public function mxchat_handle_product_recommendations($message, $user_id, $session_id) { | |
| 2491 | - try { | |
| 2492 | - //error_log("Starting product recommendations for user: $user_id, session: $session_id"); | |
| 2493 | - | |
| 2494 | - // Pass the message to get context-aware recommendations | |
| 2495 | - $recommendation_data = $this->mxchat_generate_recommendations($user_id, $message); | |
| 2496 | - //error_log('Generated recommendation data: ' . wp_json_encode($recommendation_data)); | |
| 2497 | - | |
| 2498 | - if (empty($recommendation_data['recommendations'])) { | |
| 2499 | - //error_log("No recommendations found for user: $user_id"); | |
| 2500 | - $this->fallbackResponse = [ | |
| 2501 | - 'text' => __("I couldn't find any product recommendations for you right now. Please try again later!", 'mxchat'), | |
| 2502 | - ]; | |
| 2503 | - return; | |
| 2504 | - } | |
| 2505 | - | |
| 2506 | - // Remove duplicates and limit to top 4 recommendations | |
| 2507 | - $unique_recommendations = []; | |
| 2508 | - foreach ($recommendation_data['recommendations'] as $rec) { | |
| 2509 | - $unique_recommendations[$rec['url']] = $rec; | |
| 2510 | - } | |
| 2511 | - | |
| 2512 | - $unique_recommendations = array_slice($unique_recommendations, 0, 4); | |
| 2513 | - //error_log('Top 4 recommendations: ' . wp_json_encode($unique_recommendations)); | |
| 2514 | - | |
| 2515 | - $recommendations_summary = []; | |
| 2516 | - foreach ($unique_recommendations as $rec) { | |
| 2517 | - $recommendations_summary[] = [ | |
| 2518 | - 'name' => $rec['name'], | |
| 2519 | - 'price' => strip_tags($rec['price']), | |
| 2520 | - 'url' => $rec['url'], | |
| 2521 | - 'image' => $rec['image'], | |
| 2522 | - ]; | |
| 2523 | - } | |
| 2524 | - | |
| 2525 | - // Generate AI prompt and fetch response | |
| 2526 | - $ai_prompt = $this->mxchat_generate_ai_recommendation_prompt($recommendations_summary); | |
| 2527 | - $ai_response = $this->mxchat_fetch_ai_response($ai_prompt); | |
| 2528 | - | |
| 2529 | - if (empty($ai_response)) { | |
| 2530 | - $this->fallbackResponse = [ | |
| 2531 | - 'text' => __('An unexpected error occurred while generating recommendations. Please try again later.', 'mxchat'), | |
| 2532 | - ]; | |
| 2533 | - return; | |
| 2534 | - } | |
| 2535 | - | |
| 2536 | - // Split the AI's response into lines | |
| 2537 | - $ai_lines = preg_split('/\r\n|\r|\n/', $ai_response); | |
| 2538 | - | |
| 2539 | - // Initialize variables | |
| 2540 | - $formatted_response = ''; | |
| 2541 | - $justifications = []; | |
| 2542 | - $current_number = 0; | |
| 2543 | - $in_introduction = true; | |
| 2544 | - $introduction = ''; | |
| 2545 | - | |
| 2546 | - // Parse the AI response to separate the introduction and the justifications | |
| 2547 | - foreach ($ai_lines as $line) { | |
| 2548 | - if (preg_match('/^\s*(\d+)\.\s*(.*)$/', $line, $matches)) { | |
| 2549 | - // This line is a numbered justification | |
| 2550 | - $current_number = intval($matches[1]) - 1; | |
| 2551 | - $justifications[$current_number] = $matches[2]; | |
| 2552 | - $in_introduction = false; | |
| 2553 | - } elseif ($in_introduction) { | |
| 2554 | - // This line is part of the introduction | |
| 2555 | - $introduction .= $line . ' '; | |
| 2556 | - } else { | |
| 2557 | - // This line is a continuation of the current justification | |
| 2558 | - if (isset($justifications[$current_number])) { | |
| 2559 | - $justifications[$current_number] .= ' ' . $line; | |
| 2560 | - } | |
| 2561 | - } | |
| 2562 | - } | |
| 2563 | - | |
| 2564 | - // Build the formatted response | |
| 2565 | - if (!empty($introduction)) { | |
| 2566 | - $formatted_response .= esc_html(trim($introduction)) . "<br><br>"; | |
| 2567 | - } | |
| 2568 | - | |
| 2569 | - foreach ($recommendations_summary as $index => $rec) { | |
| 2570 | - $name = esc_html($rec['name']); | |
| 2571 | - $price = number_format((float)$rec['price'], 2, '.', ''); | |
| 2572 | - $url = esc_url($rec['url']); | |
| 2573 | - $image = esc_url($rec['image']); | |
| 2574 | - | |
| 2575 | - $formatted_response .= ($index + 1) . ". <strong>" . $name . "</strong> - <strong>$" . $price . "</strong><br>"; | |
| 2576 | - $formatted_response .= "<img src=\"{$image}\" alt=\"{$name}\" style=\"max-width: 200px; height: auto; display: block; margin: 10px 0;\" /><br>"; | |
| 2577 | - | |
| 2578 | - if (isset($justifications[$index])) { | |
| 2579 | - $formatted_response .= "<em>" . esc_html(trim($justifications[$index])) . "</em><br><br>"; | |
| 2580 | - } | |
| 2581 | - } | |
| 2582 | - | |
| 2583 | - $this->fallbackResponse = [ | |
| 2584 | - 'text' => $formatted_response, | |
| 2585 | - ]; | |
| 2586 | - //error_log('Final formatted response set.'); | |
| 2587 | - } catch (Exception $e) { | |
| 2588 | - //error_log('Error in mxchat_handle_product_recommendations: ' . $e->getMessage()); | |
| 2589 | - $this->fallbackResponse = [ | |
| 2590 | - 'text' => __('An unexpected error occurred while generating recommendations. Please try again later.', 'mxchat'), | |
| 2591 | - ]; | |
| 2592 | - } | |
| 2593 | -} | |
| 2594 | -private function mxchat_get_user_context($user_id) { | |
| 2595 | - $context = [ | |
| 2596 | - 'order_history' => [], | |
| 2597 | - 'cart_items' => [], | |
| 2598 | - 'recently_viewed' => [], | |
| 2599 | - ]; | |
| 2600 | - | |
| 2601 | - // Get order history | |
| 2602 | - if (is_user_logged_in() && $user_id) { | |
| 2603 | - $orders = wc_get_orders([ | |
| 2604 | - 'customer_id' => $user_id, | |
| 2605 | - 'limit' => 5, // Last 5 orders | |
| 2606 | - 'orderby' => 'date', | |
| 2607 | - 'order' => 'DESC', | |
| 2608 | - ]); | |
| 2609 | - | |
| 2610 | - foreach ($orders as $order) { | |
| 2611 | - foreach ($order->get_items() as $item) { | |
| 2612 | - $context['order_history'][] = [ | |
| 2613 | - 'name' => $item->get_name(), | |
| 2614 | - 'product_id' => $item->get_product_id(), | |
| 2615 | - 'date' => $order->get_date_created()->format('Y-m-d') | |
| 2616 | - ]; | |
| 2617 | - } | |
| 2618 | - } | |
| 2619 | - } | |
| 2620 | - | |
| 2621 | - // Get cart items | |
| 2622 | - if (WC()->cart && WC()->cart->get_cart_contents_count() > 0) { | |
| 2623 | - foreach (WC()->cart->get_cart() as $cart_item) { | |
| 2624 | - $product = wc_get_product($cart_item['product_id']); | |
| 2625 | - if ($product) { | |
| 2626 | - $context['cart_items'][] = [ | |
| 2627 | - 'name' => $product->get_name(), | |
| 2628 | - 'product_id' => $product->get_id() | |
| 2629 | - ]; | |
| 2630 | - } | |
| 2631 | - } | |
| 2632 | - } | |
| 2633 | - | |
| 2634 | - // Get recently viewed items from session | |
| 2635 | - $viewed_products = WC()->session->get('recently_viewed_products', []); | |
| 2636 | - foreach ($viewed_products as $product_id) { | |
| 2637 | - $product = wc_get_product($product_id); | |
| 2638 | - if ($product) { | |
| 2639 | - $context['recently_viewed'][] = [ | |
| 2640 | - 'name' => $product->get_name(), | |
| 2641 | - 'product_id' => $product->get_id() | |
| 2642 | - ]; | |
| 2643 | - } | |
| 2644 | - } | |
| 2645 | - | |
| 2646 | - return $context; | |
| 2647 | -} | |
| 2648 | - | |
| 2649 | - | |
| 2650 | - | |
| 2651 | - | |
| 2652 | - | |
| 2653 | - | |
| 2654 | 2034 | function mxchat_fetch_new_messages() { |
| 2655 | 2035 | $session_id = sanitize_text_field($_POST['session_id']); |
| 2656 | 2036 | $last_seen_id = sanitize_text_field($_POST['last_seen_id']); |
| 2657 | 2037 | $persistence_enabled = $_POST['persistence_enabled'] === 'true'; |
| @@ -2988,13 +2368,13 @@ | ||
| 2988 | 2368 | |
| 2989 | 2369 | public function mxchat_handle_agent_response(WP_REST_Request $request) { |
| 2990 | 2370 | //error_log('Received agent response request'); |
| 2991 | 2371 | //error_log('Request data: ' . print_r($request->get_params(), true)); |
| 2992 | - // error_log('Raw body: ' . file_get_contents('php://input')); | |
| 2372 | + // //error_log('Raw body: ' . file_get_contents('php://input')); | |
| 2993 | 2373 | |
| 2994 | 2374 | // Get the data from Slack's slash command format |
| 2995 | 2375 | $command_text = $request->get_param('text'); |
| 2996 | - // error_log('Command text: ' . $command_text); | |
| 2376 | + // //error_log('Command text: ' . $command_text); | |
| 2997 | 2377 | |
| 2998 | 2378 | if (empty($command_text)) { |
| 2999 | 2379 | //error_log(esc_html__('Agent response error: No command text received', 'mxchat')); |
| 3000 | 2380 | return new WP_REST_Response([ |
| @@ -3019,9 +2399,9 @@ | ||
| 3019 | 2399 | // Save the message |
| 3020 | 2400 | $message_id = $this->mxchat_save_chat_message($session_id, 'agent', $message); |
| 3021 | 2401 | |
| 3022 | 2402 | if (!$message_id) { |
| 3023 | - // error_log('Failed to save agent message'); | |
| 2403 | + // //error_log('Failed to save agent message'); | |
| 3024 | 2404 | return new WP_REST_Response([ |
| 3025 | 2405 | 'error' => esc_html__('Failed to save message', 'mxchat') |
| 3026 | 2406 | ], 500); |
| 3027 | 2407 | } |
| @@ -3076,42 +2456,64 @@ | ||
| 3076 | 2456 | return MxChat_User::mxchat_get_user_identifier(); |
| 3077 | 2457 | } |
| 3078 | 2458 | |
| 3079 | 2459 | private function mxchat_generate_embedding($text, $api_key) { |
| 2460 | + // Get options and selected model | |
| 2461 | + $options = get_option('mxchat_options'); | |
| 2462 | + $selected_model = $options['embedding_model'] ?? 'text-embedding-ada-002'; | |
| 2463 | + | |
| 2464 | + // Determine endpoint and API key based on model | |
| 2465 | + if (strpos($selected_model, 'voyage') === 0) { | |
| 2466 | + $endpoint = 'https://api.voyageai.com/v1/embeddings'; | |
| 2467 | + $api_key = $options['voyage_api_key'] ?? ''; | |
| 2468 | + } else { | |
| 3080 | 2469 | $endpoint = 'https://api.openai.com/v1/embeddings'; |
| 3081 | - | |
| 3082 | - $body = wp_json_encode([ | |
| 3083 | - 'input' => $text, | |
| 3084 | - 'model' => 'text-embedding-ada-002' | |
| 3085 | - ]); | |
| 3086 | - | |
| 3087 | - $args = [ | |
| 3088 | - 'body' => $body, | |
| 3089 | - 'headers' => [ | |
| 3090 | - 'Content-Type' => 'application/json', | |
| 3091 | - 'Authorization' => 'Bearer ' . $api_key, | |
| 3092 | - ], | |
| 3093 | - 'timeout' => 60, | |
| 3094 | - 'redirection' => 5, | |
| 3095 | - 'blocking' => true, | |
| 3096 | - 'httpversion' => '1.0', | |
| 3097 | - 'sslverify' => true, | |
| 3098 | - ]; | |
| 3099 | - | |
| 3100 | - $response = wp_remote_post($endpoint, $args); | |
| 3101 | - | |
| 3102 | - if (is_wp_error($response)) { | |
| 3103 | - return null; | |
| 3104 | - } | |
| 3105 | - | |
| 3106 | - $response_body = json_decode(wp_remote_retrieve_body($response), true); | |
| 3107 | - | |
| 3108 | - if (isset($response_body['data'][0]['embedding']) && is_array($response_body['data'][0]['embedding'])) { | |
| 3109 | - return $response_body['data'][0]['embedding']; | |
| 3110 | - } else { | |
| 3111 | - return null; | |
| 3112 | - } | |
| 2470 | + // Use the passed API key for OpenAI | |
| 3113 | 2471 | } |
| 2472 | + | |
| 2473 | + // Prepare request body with conditional output_dimension | |
| 2474 | + $request_body = [ | |
| 2475 | + 'input' => $text, | |
| 2476 | + 'model' => $selected_model | |
| 2477 | + ]; | |
| 2478 | + | |
| 2479 | + // Add output_dimension for voyage-3-large | |
| 2480 | + if ($selected_model === 'voyage-3-large') { | |
| 2481 | + $request_body['output_dimension'] = 2048; | |
| 2482 | + } | |
| 2483 | + | |
| 2484 | + // Prepare request arguments | |
| 2485 | + $args = [ | |
| 2486 | + 'body' => wp_json_encode($request_body), | |
| 2487 | + 'headers' => [ | |
| 2488 | + 'Content-Type' => 'application/json', | |
| 2489 | + 'Authorization' => 'Bearer ' . $api_key, | |
| 2490 | + ], | |
| 2491 | + 'timeout' => 60, | |
| 2492 | + 'redirection' => 5, | |
| 2493 | + 'blocking' => true, | |
| 2494 | + 'httpversion' => '1.0', | |
| 2495 | + 'sslverify' => true, | |
| 2496 | + ]; | |
| 2497 | + | |
| 2498 | + // Make the request | |
| 2499 | + $response = wp_remote_post($endpoint, $args); | |
| 2500 | + | |
| 2501 | + // Rest of your existing code... | |
| 2502 | + if (is_wp_error($response)) { | |
| 2503 | + //error_log('Embedding Generation Error: ' . $response->get_error_message()); | |
| 2504 | + return null; | |
| 2505 | + } | |
| 2506 | + | |
| 2507 | + $response_body = json_decode(wp_remote_retrieve_body($response), true); | |
| 2508 | + | |
| 2509 | + if (isset($response_body['data'][0]['embedding']) && is_array($response_body['data'][0]['embedding'])) { | |
| 2510 | + return $response_body['data'][0]['embedding']; | |
| 2511 | + } else { | |
| 2512 | + //error_log('Invalid embedding response: ' . wp_json_encode($response_body)); | |
| 2513 | + return null; | |
| 2514 | + } | |
| 2515 | +} | |
| 3114 | 2516 | |
| 3115 | 2517 | |
| 3116 | 2518 | private function mxchat_find_relevant_content($user_embedding) { |
| 3117 | 2519 | //error_log('MXChat Vector Search: Starting content search...'); |
| @@ -3133,8 +2535,9 @@ | ||
| 3133 | 2535 | return $this->find_relevant_content_wordpress($user_embedding); |
| 3134 | 2536 | } |
| 3135 | 2537 | } |
| 3136 | 2538 | |
| 2539 | + | |
| 3137 | 2540 | private function find_relevant_content_wordpress($user_embedding) { |
| 3138 | 2541 | global $wpdb; |
| 3139 | 2542 | $system_prompt_table = $wpdb->prefix . 'mxchat_system_prompt_content'; |
| 3140 | 2543 | $cache_key = 'mxchat_system_prompt_embeddings'; |
| @@ -3139,11 +2542,15 @@ | ||
| 3139 | 2542 | $system_prompt_table = $wpdb->prefix . 'mxchat_system_prompt_content'; |
| 3140 | 2543 | $cache_key = 'mxchat_system_prompt_embeddings'; |
| 3141 | 2544 | $batch_size = 500; |
| 3142 | 2545 | |
| 2546 | + // Log start of matching process | |
| 2547 | + //error_log('[MXCHAT] Starting similarity matching process'); | |
| 2548 | + | |
| 3143 | 2549 | // Retrieve embeddings from cache or database |
| 3144 | 2550 | $embeddings = wp_cache_get($cache_key, 'mxchat_system_prompts'); |
| 3145 | 2551 | if ($embeddings === false) { |
| 2552 | + //error_log('[MXCHAT] Cache miss - loading embeddings from database'); | |
| 3146 | 2553 | $embeddings = []; |
| 3147 | 2554 | $offset = 0; |
| 3148 | 2555 | |
| 3149 | 2556 | // Load in batches and build cache |
| @@ -3169,15 +2576,28 @@ | ||
| 3169 | 2576 | |
| 3170 | 2577 | } while (true); |
| 3171 | 2578 | |
| 3172 | 2579 | if (empty($embeddings)) { |
| 2580 | + //error_log('[MXCHAT] No embeddings found in database'); | |
| 3173 | 2581 | return ''; // Return an empty string if no embeddings found |
| 3174 | 2582 | } |
| 3175 | 2583 | wp_cache_set($cache_key, $embeddings, 'mxchat_system_prompts', 3600); |
| 2584 | + //error_log('[MXCHAT] Cached ' . count($embeddings) . ' embeddings'); | |
| 2585 | + } else { | |
| 2586 | + //error_log('[MXCHAT] Using ' . count($embeddings) . ' cached embeddings'); | |
| 3176 | 2587 | } |
| 3177 | 2588 | |
| 3178 | 2589 | // Initialize array to store relevant results with similarity scores |
| 3179 | 2590 | $relevant_results = []; |
| 2591 | + | |
| 2592 | + // Get the similarity threshold from the main options array only | |
| 2593 | + $main_options = get_option('mxchat_options', []); | |
| 2594 | + $similarity_threshold = isset($main_options['similarity_threshold']) | |
| 2595 | + ? ((int) $main_options['similarity_threshold']) / 100 | |
| 2596 | + : 0.8; // Default to 80% | |
| 2597 | + | |
| 2598 | + //error_log('[MXCHAT] Using similarity threshold: ' . ($similarity_threshold * 100) . '%'); | |
| 2599 | + | |
| 3180 | 2600 | // Iterate through embeddings to calculate similarity |
| 3181 | 2601 | foreach ($embeddings as $embedding) { |
| 3182 | 2602 | $database_embedding = $embedding->embedding_vector |
| 3183 | 2603 | ? unserialize($embedding->embedding_vector, ['allowed_classes' => false]) |
| @@ -3183,8 +2603,14 @@ | ||
| 3183 | 2603 | ? unserialize($embedding->embedding_vector, ['allowed_classes' => false]) |
| 3184 | 2604 | : null; |
| 3185 | 2605 | if (is_array($database_embedding) && is_array($user_embedding)) { |
| 3186 | 2606 | $similarity = $this->mxchat_calculate_cosine_similarity($user_embedding, $database_embedding); |
| 2607 | + | |
| 2608 | + // Log each similarity score over 0.5 to reduce log spam | |
| 2609 | + if ($similarity > 0.1) { | |
| 2610 | + //error_log(sprintf('[MXCHAT] ID: %d | Similarity Score: %.4f', $embedding->id, $similarity)); | |
| 2611 | + } | |
| 2612 | + | |
| 3187 | 2613 | $relevant_results[] = [ |
| 3188 | 2614 | 'id' => $embedding->id, |
| 3189 | 2615 | 'similarity' => $similarity |
| 3190 | 2616 | ]; |
| @@ -3192,11 +2618,8 @@ | ||
| 3192 | 2618 | // Free memory |
| 3193 | 2619 | unset($database_embedding); |
| 3194 | 2620 | } |
| 3195 | 2621 | |
| 3196 | - // Retrieve the similarity threshold | |
| 3197 | - $similarity_threshold = ((int) get_option('mxchat_similarity_threshold', 80)) / 100; | |
| 3198 | - | |
| 3199 | 2622 | // Filter and sort relevant results by similarity |
| 3200 | 2623 | $relevant_results = array_filter($relevant_results, function ($result) use ($similarity_threshold) { |
| 3201 | 2624 | return $result['similarity'] >= $similarity_threshold; |
| 3202 | 2625 | }); |
| @@ -3203,11 +2626,20 @@ | ||
| 3203 | 2626 | usort($relevant_results, function ($a, $b) { |
| 3204 | 2627 | return $b['similarity'] <=> $a['similarity']; |
| 3205 | 2628 | }); |
| 3206 | 2629 | |
| 2630 | + // Log number of results that met threshold | |
| 2631 | + //error_log('[MXCHAT] ' . count($relevant_results) . ' results met the similarity threshold'); | |
| 2632 | + | |
| 3207 | 2633 | // Limit to the top 5 results |
| 3208 | 2634 | $top_results = array_slice($relevant_results, 0, 5); |
| 3209 | 2635 | |
| 2636 | + // Log the top matches | |
| 2637 | + //error_log('[MXCHAT] Top matching results:'); | |
| 2638 | + foreach ($top_results as $index => $result) { | |
| 2639 | + | |
| 2640 | + } | |
| 2641 | + | |
| 3210 | 2642 | // Initialize the final content |
| 3211 | 2643 | $content = ''; |
| 3212 | 2644 | |
| 3213 | 2645 | // Fetch and combine content for the top results |
| @@ -3214,10 +2646,11 @@ | ||
| 3214 | 2646 | foreach ($top_results as $result) { |
| 3215 | 2647 | $chunk_content = $this->fetch_content_with_product_links($result['id']); |
| 3216 | 2648 | // Check if the content is PDF-related and add surrounding pages |
| 3217 | 2649 | if (strpos($chunk_content, '{"document_type":"pdf"') !== false) { |
| 2650 | + //error_log('[MXCHAT] ID ' . $result['id'] . ' is PDF content, adding surrounding pages'); | |
| 3218 | 2651 | $surrounding_content = $wpdb->get_results($wpdb->prepare( |
| 3219 | - "SELECT article_content FROM {$system_prompt_table} | |
| 2652 | + "SELECT id, article_content FROM {$system_prompt_table} | |
| 3220 | 2653 | WHERE id IN ( |
| 3221 | 2654 | (SELECT id FROM {$system_prompt_table} WHERE id < %d ORDER BY id DESC LIMIT 1), |
| 3222 | 2655 | (SELECT id FROM {$system_prompt_table} WHERE id > %d ORDER BY id ASC LIMIT 1) |
| 3223 | 2656 | )", |
| @@ -3239,29 +2672,38 @@ | ||
| 3239 | 2672 | $content .= $chunk_content . "\n\n"; |
| 3240 | 2673 | } |
| 3241 | 2674 | } |
| 3242 | 2675 | |
| 2676 | + // Log content length | |
| 2677 | + //error_log('[MXCHAT] Retrieved content length: ' . strlen(trim($content)) . ' characters'); | |
| 2678 | + | |
| 3243 | 2679 | return trim($content); |
| 3244 | 2680 | } |
| 3245 | -/** | |
| 3246 | - * Find relevant content in Pinecone vector database | |
| 3247 | - */ | |
| 2681 | + | |
| 2682 | + | |
| 3248 | 2683 | private function find_relevant_content_pinecone($user_embedding) { |
| 3249 | 2684 | $options = get_option('mxchat_pinecone_addon_options', array()); |
| 3250 | 2685 | $api_key = $options['mxchat_pinecone_api_key'] ?? ''; |
| 3251 | 2686 | $host = $options['mxchat_pinecone_host'] ?? ''; |
| 3252 | - | |
| 2687 | + | |
| 3253 | 2688 | if (empty($host) || empty($api_key)) { |
| 3254 | - //error_log('Pinecone credentials not properly configured'); | |
| 2689 | + //error_log('[MXCHAT Debug] Pinecone credentials not properly configured'); | |
| 3255 | 2690 | return ''; |
| 3256 | 2691 | } |
| 3257 | - | |
| 3258 | - // Get similarity threshold from WordPress settings | |
| 3259 | - $similarity_threshold = ((int) get_option('mxchat_similarity_threshold', 80)) / 100; | |
| 3260 | - | |
| 2692 | + | |
| 2693 | + // Get the similarity threshold from the main options array only | |
| 2694 | + $main_options = get_option('mxchat_options', []); | |
| 2695 | + $similarity_threshold = isset($main_options['similarity_threshold']) | |
| 2696 | + ? ((int) $main_options['similarity_threshold']) / 100 | |
| 2697 | + : 0.8; // Default to 80% | |
| 2698 | + | |
| 2699 | + //error_log('[MXCHAT Debug] Using similarity threshold: ' . ($similarity_threshold * 100) . '%'); | |
| 2700 | + | |
| 3261 | 2701 | // Prepare the query request for Pinecone |
| 3262 | 2702 | $api_endpoint = "https://{$host}/query"; |
| 3263 | - | |
| 2703 | + | |
| 2704 | + //error_log('[MXCHAT Debug] Querying Pinecone at: ' . $api_endpoint); | |
| 2705 | + | |
| 3264 | 2706 | $request_body = array( |
| 3265 | 2707 | 'vector' => $user_embedding, |
| 3266 | 2708 | 'topK' => 5, |
| 3267 | 2709 | 'includeMetadata' => true, |
| @@ -3266,9 +2708,9 @@ | ||
| 3266 | 2708 | 'topK' => 5, |
| 3267 | 2709 | 'includeMetadata' => true, |
| 3268 | 2710 | 'includeValues' => true |
| 3269 | 2711 | ); |
| 3270 | - | |
| 2712 | + | |
| 3271 | 2713 | $response = wp_remote_post($api_endpoint, array( |
| 3272 | 2714 | 'headers' => array( |
| 3273 | 2715 | 'Api-Key' => $api_key, |
| 3274 | 2716 | 'accept' => 'application/json', |
| @@ -3276,35 +2718,43 @@ | ||
| 3276 | 2718 | ), |
| 3277 | 2719 | 'body' => wp_json_encode($request_body), |
| 3278 | 2720 | 'timeout' => 30 |
| 3279 | 2721 | )); |
| 3280 | - | |
| 2722 | + | |
| 3281 | 2723 | if (is_wp_error($response)) { |
| 3282 | - //error_log('Pinecone query error: ' . $response->get_error_message()); | |
| 2724 | + //error_log('[MXCHAT Debug] Pinecone query error: ' . $response->get_error_message()); | |
| 3283 | 2725 | return ''; |
| 3284 | 2726 | } |
| 3285 | - | |
| 2727 | + | |
| 3286 | 2728 | $response_code = wp_remote_retrieve_response_code($response); |
| 3287 | 2729 | if ($response_code !== 200) { |
| 3288 | - //error_log('Pinecone API error: ' . wp_remote_retrieve_body($response)); | |
| 2730 | + //error_log('[MXCHAT Debug] Pinecone API error: ' . wp_remote_retrieve_body($response)); | |
| 3289 | 2731 | return ''; |
| 3290 | 2732 | } |
| 3291 | - | |
| 2733 | + | |
| 3292 | 2734 | $results = json_decode(wp_remote_retrieve_body($response), true); |
| 3293 | 2735 | if (empty($results['matches'])) { |
| 2736 | + //error_log('[MXCHAT Debug] No matches found in Pinecone response'); | |
| 3294 | 2737 | return ''; |
| 3295 | 2738 | } |
| 3296 | - | |
| 2739 | + | |
| 2740 | + //error_log('[MXCHAT Debug] Found ' . count($results['matches']) . ' matches in Pinecone'); | |
| 2741 | + | |
| 3297 | 2742 | // Initialize the final content |
| 3298 | 2743 | $content = ''; |
| 2744 | + $matches_above_threshold = 0; | |
| 2745 | + | |
| 2746 | + // Process each match | |
| 2747 | + foreach ($results['matches'] as $index => $match) { | |
| 2748 | + // Log score for each match | |
| 3299 | 2749 | |
| 3300 | - // Process each match | |
| 3301 | - foreach ($results['matches'] as $match) { | |
| 3302 | 2750 | // Skip if similarity is below threshold |
| 3303 | 2751 | if ($match['score'] < $similarity_threshold) { |
| 3304 | 2752 | continue; |
| 3305 | 2753 | } |
| 3306 | - | |
| 2754 | + | |
| 2755 | + $matches_above_threshold++; | |
| 2756 | + | |
| 3307 | 2757 | if (!empty($match['metadata']['text']) && !empty($match['metadata']['source_url'])) { |
| 3308 | 2758 | // Add content with citation |
| 3309 | 2759 | $content .= $match['metadata']['text'] . "\n"; |
| 3310 | 2760 | $content .= "Source: " . $match['metadata']['source_url'] . "\n\n"; |
| @@ -3309,13 +2759,15 @@ | ||
| 3309 | 2759 | $content .= $match['metadata']['text'] . "\n"; |
| 3310 | 2760 | $content .= "Source: " . $match['metadata']['source_url'] . "\n\n"; |
| 3311 | 2761 | } |
| 3312 | 2762 | } |
| 3313 | - | |
| 2763 | + | |
| 2764 | + //error_log('[MXCHAT Debug] Total matches used (above threshold): ' . $matches_above_threshold); | |
| 2765 | + //error_log('[MXCHAT Debug] Content length returned: ' . strlen(trim($content)) . ' characters'); | |
| 2766 | + | |
| 3314 | 2767 | return trim($content); |
| 3315 | 2768 | } |
| 3316 | 2769 | |
| 3317 | - | |
| 3318 | 2770 | private function mxchat_find_relevant_products($user_embedding) { |
| 3319 | 2771 | //error_log('MXChat Vector Search: Starting product search...'); |
| 3320 | 2772 | |
| 3321 | 2773 | // Retrieve the add-on settings from the database |
| @@ -3671,9 +3123,8 @@ | ||
| 3671 | 3123 | //error_log('DeepSeek API Response Format Error: ' . print_r($decoded_response, true)); |
| 3672 | 3124 | return "Sorry, I couldn't process that request."; |
| 3673 | 3125 | } |
| 3674 | 3126 | } |
| 3675 | - | |
| 3676 | 3127 | private function mxchat_generate_response_openai($selected_model, $api_key, $conversation_history, $relevant_content) { |
| 3677 | 3128 | // Ensure conversation_history is an array |
| 3678 | 3129 | if (!is_array($conversation_history)) { |
| 3679 | 3130 | $conversation_history = array(); |
| @@ -3817,9 +3268,8 @@ | ||
| 3817 | 3268 | } else { |
| 3818 | 3269 | return "Sorry, I couldn't process that request."; |
| 3819 | 3270 | } |
| 3820 | 3271 | } |
| 3821 | - | |
| 3822 | 3272 | private function mxchat_generate_response_claude($selected_model, $claude_api_key, $conversation_history, $relevant_content) { |
| 3823 | 3273 | // Get system prompt instructions from options |
| 3824 | 3274 | $system_prompt_instructions = isset($this->options['system_prompt_instructions']) ? $this->options['system_prompt_instructions'] : ''; |
| 3825 | 3275 | |
| @@ -3918,8 +3368,11 @@ | ||
| 3918 | 3368 | // Log unexpected response format |
| 3919 | 3369 | //error_log("Claude API unexpected response format: " . print_r($response_body, true)); |
| 3920 | 3370 | return "Sorry, I received an unexpected response format from the API."; |
| 3921 | 3371 | } |
| 3372 | + | |
| 3373 | + | |
| 3374 | + | |
| 3922 | 3375 | public function mxchat_dismiss_pre_chat_message() { |
| 3923 | 3376 | // Get and sanitize the user identifier |
| 3924 | 3377 | $user_id = $this->mxchat_get_user_identifier(); |
| 3925 | 3378 | $user_id = sanitize_key($user_id); |
| @@ -3975,10 +3428,10 @@ | ||
| 3975 | 3428 | } |
| 3976 | 3429 | |
| 3977 | 3430 | public function mxchat_enqueue_scripts_styles() { |
| 3978 | 3431 | // Define version numbers for the styles and scripts |
| 3979 | - $chat_style_version = '2.0.3'; // Replace with your actual version | |
| 3980 | - $chat_script_version = '2.0.3'; // Replace with your actual version | |
| 3432 | + $chat_style_version = '2.1.1'; // Replace with your actual version | |
| 3433 | + $chat_script_version = '2.1.1'; // Replace with your actual version | |
| 3981 | 3434 | |
| 3982 | 3435 | // Enqueue the script |
| 3983 | 3436 | wp_enqueue_script( |
| 3984 | 3437 | 'mxchat-chat-js', |