PluginProbe
MxChat – AI Chatbot & Content Generation for WordPress / 2.0.7
MxChat – AI Chatbot & Content Generation for WordPress v2.0.7
3.2.21 3.2.20 3.2.19 3.2.18 3.2.17 3.2.16 3.2.15 3.2.14 3.2.12 3.2.13 3.2.11 3.2.10 3.2.9 3.2.8 3.2.7 3.2.6 3.2.5 3.2.4 3.2.3 3.2.2 3.2.1 2.0.3 2.0.4 2.0.5 2.0.6 All 152 releases
← All changes | includes/class-mxchat-integrator.php +135 -49 2.0.42.0.7 View file →
@@ -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'],
@@ -1131,18 +1156,20 @@
1131 1156 $response_html = '';
1132 1157 //error_log("DALL-E image generation error: " . esc_html($image_response['error'] ?? 'Unknown error.'));
1133 1158 }
1134 1159
1135 - // Save both text and HTML responses
1136 - $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 + ];
1137 1171
1138 - // Prepare the response data
1139 - $response_data = [
1140 - 'message' => $response_text,
1141 - 'html' => $response_html,
1142 - 'image_url' => $image_url ?? '',
1143 - ];
1144 -
1145 1172 // Send the JSON response
1146 1173 header('Content-Type: application/json; charset=' . get_option('blog_charset'));
1147 1174 echo json_encode($response_data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
1148 1175 wp_die();
@@ -2429,42 +2456,64 @@
2429 2456 return MxChat_User::mxchat_get_user_identifier();
2430 2457 }
2431 2458
2432 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 {
2433 2469 $endpoint = 'https://api.openai.com/v1/embeddings';
2434 -
2435 - $body = wp_json_encode([
2436 - 'input' => $text,
2437 - 'model' => 'text-embedding-ada-002'
2438 - ]);
2439 -
2440 - $args = [
2441 - 'body' => $body,
2442 - 'headers' => [
2443 - 'Content-Type' => 'application/json',
2444 - 'Authorization' => 'Bearer ' . $api_key,
2445 - ],
2446 - 'timeout' => 60,
2447 - 'redirection' => 5,
2448 - 'blocking' => true,
2449 - 'httpversion' => '1.0',
2450 - 'sslverify' => true,
2451 - ];
2452 -
2453 - $response = wp_remote_post($endpoint, $args);
2454 -
2455 - if (is_wp_error($response)) {
2456 - return null;
2457 - }
2458 -
2459 - $response_body = json_decode(wp_remote_retrieve_body($response), true);
2460 -
2461 - if (isset($response_body['data'][0]['embedding']) && is_array($response_body['data'][0]['embedding'])) {
2462 - return $response_body['data'][0]['embedding'];
2463 - } else {
2464 - return null;
2465 - }
2470 + // Use the passed API key for OpenAI
2466 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 +}
2467 2516
2468 2517
2469 2518 private function mxchat_find_relevant_content($user_embedding) {
2470 2519 //error_log('MXChat Vector Search: Starting content search...');
@@ -2486,8 +2535,9 @@
2486 2535 return $this->find_relevant_content_wordpress($user_embedding);
2487 2536 }
2488 2537 }
2489 2538
2539 +
2490 2540 private function find_relevant_content_wordpress($user_embedding) {
2491 2541 global $wpdb;
2492 2542 $system_prompt_table = $wpdb->prefix . 'mxchat_system_prompt_content';
2493 2543 $cache_key = 'mxchat_system_prompt_embeddings';
@@ -2492,11 +2542,15 @@
2492 2542 $system_prompt_table = $wpdb->prefix . 'mxchat_system_prompt_content';
2493 2543 $cache_key = 'mxchat_system_prompt_embeddings';
2494 2544 $batch_size = 500;
2495 2545
2546 + // Log start of matching process
2547 + error_log('[MXCHAT] Starting similarity matching process');
2548 +
2496 2549 // Retrieve embeddings from cache or database
2497 2550 $embeddings = wp_cache_get($cache_key, 'mxchat_system_prompts');
2498 2551 if ($embeddings === false) {
2552 + error_log('[MXCHAT] Cache miss - loading embeddings from database');
2499 2553 $embeddings = [];
2500 2554 $offset = 0;
2501 2555
2502 2556 // Load in batches and build cache
@@ -2522,15 +2576,24 @@
2522 2576
2523 2577 } while (true);
2524 2578
2525 2579 if (empty($embeddings)) {
2580 + error_log('[MXCHAT] No embeddings found in database');
2526 2581 return ''; // Return an empty string if no embeddings found
2527 2582 }
2528 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');
2529 2587 }
2530 2588
2531 2589 // Initialize array to store relevant results with similarity scores
2532 2590 $relevant_results = [];
2591 +
2592 + // Retrieve the similarity threshold
2593 + $similarity_threshold = ((int) get_option('mxchat_similarity_threshold', 80)) / 100;
2594 + error_log('[MXCHAT] Using similarity threshold: ' . ($similarity_threshold * 100) . '%');
2595 +
2533 2596 // Iterate through embeddings to calculate similarity
2534 2597 foreach ($embeddings as $embedding) {
2535 2598 $database_embedding = $embedding->embedding_vector
2536 2599 ? unserialize($embedding->embedding_vector, ['allowed_classes' => false])
@@ -2536,8 +2599,14 @@
2536 2599 ? unserialize($embedding->embedding_vector, ['allowed_classes' => false])
2537 2600 : null;
2538 2601 if (is_array($database_embedding) && is_array($user_embedding)) {
2539 2602 $similarity = $this->mxchat_calculate_cosine_similarity($user_embedding, $database_embedding);
2603 +
2604 + // Log each similarity score over 0.5 to reduce log spam
2605 + if ($similarity > 0.1) {
2606 + error_log(sprintf('[MXCHAT] ID: %d | Similarity Score: %.4f', $embedding->id, $similarity));
2607 + }
2608 +
2540 2609 $relevant_results[] = [
2541 2610 'id' => $embedding->id,
2542 2611 'similarity' => $similarity
2543 2612 ];
@@ -2545,11 +2614,8 @@
2545 2614 // Free memory
2546 2615 unset($database_embedding);
2547 2616 }
2548 2617
2549 - // Retrieve the similarity threshold
2550 - $similarity_threshold = ((int) get_option('mxchat_similarity_threshold', 80)) / 100;
2551 -
2552 2618 // Filter and sort relevant results by similarity
2553 2619 $relevant_results = array_filter($relevant_results, function ($result) use ($similarity_threshold) {
2554 2620 return $result['similarity'] >= $similarity_threshold;
2555 2621 });
@@ -2556,11 +2622,24 @@
2556 2622 usort($relevant_results, function ($a, $b) {
2557 2623 return $b['similarity'] <=> $a['similarity'];
2558 2624 });
2559 2625
2626 + // Log number of results that met threshold
2627 + error_log('[MXCHAT] ' . count($relevant_results) . ' results met the similarity threshold');
2628 +
2560 2629 // Limit to the top 5 results
2561 2630 $top_results = array_slice($relevant_results, 0, 5);
2562 2631
2632 + // Log the top matches
2633 + error_log('[MXCHAT] Top matching results:');
2634 + foreach ($top_results as $index => $result) {
2635 + error_log(sprintf('[MXCHAT] %d. ID: %d | Score: %.4f',
2636 + $index + 1,
2637 + $result['id'],
2638 + $result['similarity']
2639 + ));
2640 + }
2641 +
2563 2642 // Initialize the final content
2564 2643 $content = '';
2565 2644
2566 2645 // Fetch and combine content for the top results
@@ -2567,10 +2646,11 @@
2567 2646 foreach ($top_results as $result) {
2568 2647 $chunk_content = $this->fetch_content_with_product_links($result['id']);
2569 2648 // Check if the content is PDF-related and add surrounding pages
2570 2649 if (strpos($chunk_content, '{"document_type":"pdf"') !== false) {
2650 + error_log('[MXCHAT] ID ' . $result['id'] . ' is PDF content, adding surrounding pages');
2571 2651 $surrounding_content = $wpdb->get_results($wpdb->prepare(
2572 - "SELECT article_content FROM {$system_prompt_table}
2652 + "SELECT id, article_content FROM {$system_prompt_table}
2573 2653 WHERE id IN (
2574 2654 (SELECT id FROM {$system_prompt_table} WHERE id < %d ORDER BY id DESC LIMIT 1),
2575 2655 (SELECT id FROM {$system_prompt_table} WHERE id > %d ORDER BY id ASC LIMIT 1)
2576 2656 )",
@@ -2592,10 +2672,15 @@
2592 2672 $content .= $chunk_content . "\n\n";
2593 2673 }
2594 2674 }
2595 2675
2676 + // Log content length
2677 + error_log('[MXCHAT] Retrieved content length: ' . strlen(trim($content)) . ' characters');
2678 +
2596 2679 return trim($content);
2597 2680 }
2681 +
2682 +
2598 2683 /**
2599 2684 * Find relevant content in Pinecone vector database
2600 2685 */
2601 2686 private function find_relevant_content_pinecone($user_embedding) {
@@ -3024,9 +3109,8 @@
3024 3109 //error_log('DeepSeek API Response Format Error: ' . print_r($decoded_response, true));
3025 3110 return "Sorry, I couldn't process that request.";
3026 3111 }
3027 3112 }
3028 -
3029 3113 private function mxchat_generate_response_openai($selected_model, $api_key, $conversation_history, $relevant_content) {
3030 3114 // Ensure conversation_history is an array
3031 3115 if (!is_array($conversation_history)) {
3032 3116 $conversation_history = array();
@@ -3170,9 +3254,8 @@
3170 3254 } else {
3171 3255 return "Sorry, I couldn't process that request.";
3172 3256 }
3173 3257 }
3174 -
3175 3258 private function mxchat_generate_response_claude($selected_model, $claude_api_key, $conversation_history, $relevant_content) {
3176 3259 // Get system prompt instructions from options
3177 3260 $system_prompt_instructions = isset($this->options['system_prompt_instructions']) ? $this->options['system_prompt_instructions'] : '';
3178 3261
@@ -3271,8 +3354,11 @@
3271 3354 // Log unexpected response format
3272 3355 //error_log("Claude API unexpected response format: " . print_r($response_body, true));
3273 3356 return "Sorry, I received an unexpected response format from the API.";
3274 3357 }
3358 +
3359 +
3360 +
3275 3361 public function mxchat_dismiss_pre_chat_message() {
3276 3362 // Get and sanitize the user identifier
3277 3363 $user_id = $this->mxchat_get_user_identifier();
3278 3364 $user_id = sanitize_key($user_id);
@@ -3328,10 +3414,10 @@
3328 3414 }
3329 3415
3330 3416 public function mxchat_enqueue_scripts_styles() {
3331 3417 // Define version numbers for the styles and scripts
3332 - $chat_style_version = '2.0.4'; // Replace with your actual version
3333 - $chat_script_version = '2.0.4'; // Replace with your actual version
3418 + $chat_style_version = '2.0.7'; // Replace with your actual version
3419 + $chat_script_version = '2.0.7'; // Replace with your actual version
3334 3420
3335 3421 // Enqueue the script
3336 3422 wp_enqueue_script(
3337 3423 'mxchat-chat-js',