PluginProbe
MxChat – AI Chatbot & Content Generation for WordPress / 2.1.1
MxChat – AI Chatbot & Content Generation for WordPress v2.1.1
3.2.22 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 All 153 releases
← All changes | includes/class-mxchat-integrator.php +125 -48 2.0.62.1.1 View file →
@@ -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'],
@@ -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();
@@ -1411,9 +1438,9 @@
1411 1438
1412 1439 if (empty($api_key)) {
1413 1440 /*
1414 1441 if (defined('WP_DEBUG') && WP_DEBUG) {
1415 - error_log("Brave API key is missing.");
1442 + //error_log("Brave API key is missing.");
1416 1443 }
1417 1444 */
1418 1445
1419 1446 $this->fallbackResponse = [
@@ -1435,9 +1462,9 @@
1435 1462
1436 1463 /*
1437 1464 // Log the final API URL for the search
1438 1465 if (defined('WP_DEBUG') && WP_DEBUG) {
1439 - 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));
1440 1467 }
1441 1468 */
1442 1469
1443 1470
@@ -1459,9 +1486,9 @@
1459 1486
1460 1487 if (is_wp_error($response)) {
1461 1488 /*
1462 1489 if (defined('WP_DEBUG') && WP_DEBUG) {
1463 - error_log("Brave Image API request failed: " . $response->get_error_message());
1490 + //error_log("Brave Image API request failed: " . $response->get_error_message());
1464 1491 }
1465 1492 */
1466 1493
1467 1494 $this->fallbackResponse = [
@@ -1505,9 +1532,9 @@
1505 1532
1506 1533 } else {
1507 1534 /*
1508 1535 if (defined('WP_DEBUG') && WP_DEBUG) {
1509 - 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));
1510 1537 }
1511 1538 */
1512 1539
1513 1540 $this->fallbackResponse = [
@@ -1524,9 +1551,9 @@
1524 1551
1525 1552 /*
1526 1553 // Log the API key check, without exposing the key
1527 1554 if (defined('WP_DEBUG') && WP_DEBUG) {
1528 - error_log("Retrieved OpenAI API Key: " . ($api_key ? "Present" : "Missing"));
1555 + //error_log("Retrieved OpenAI API Key: " . ($api_key ? "Present" : "Missing"));
1529 1556 }
1530 1557 */
1531 1558
1532 1559 if (empty($api_key)) {
@@ -1567,9 +1594,9 @@
1567 1594
1568 1595 /*
1569 1596 // Log the interpreted query for debugging
1570 1597 if (defined('WP_DEBUG') && WP_DEBUG) {
1571 - error_log("Interpreted search query: " . $interpreted_query);
1598 + //error_log("Interpreted search query: " . $interpreted_query);
1572 1599 }
1573 1600 */
1574 1601
1575 1602 return $interpreted_query;
@@ -1869,9 +1896,9 @@
1869 1896
1870 1897 return $embeddings;
1871 1898
1872 1899 } catch (\Exception $e) {
1873 - // 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());
1874 1901
1875 1902 // Cleanup in case of exception
1876 1903 if (filter_var($pdf_source, FILTER_VALIDATE_URL) && $temp_file && file_exists($temp_file)) {
1877 1904 unlink($temp_file);
@@ -2341,13 +2368,13 @@
2341 2368
2342 2369 public function mxchat_handle_agent_response(WP_REST_Request $request) {
2343 2370 //error_log('Received agent response request');
2344 2371 //error_log('Request data: ' . print_r($request->get_params(), true));
2345 - // error_log('Raw body: ' . file_get_contents('php://input'));
2372 + // //error_log('Raw body: ' . file_get_contents('php://input'));
2346 2373
2347 2374 // Get the data from Slack's slash command format
2348 2375 $command_text = $request->get_param('text');
2349 - // error_log('Command text: ' . $command_text);
2376 + // //error_log('Command text: ' . $command_text);
2350 2377
2351 2378 if (empty($command_text)) {
2352 2379 //error_log(esc_html__('Agent response error: No command text received', 'mxchat'));
2353 2380 return new WP_REST_Response([
@@ -2372,9 +2399,9 @@
2372 2399 // Save the message
2373 2400 $message_id = $this->mxchat_save_chat_message($session_id, 'agent', $message);
2374 2401
2375 2402 if (!$message_id) {
2376 - // error_log('Failed to save agent message');
2403 + // //error_log('Failed to save agent message');
2377 2404 return new WP_REST_Response([
2378 2405 'error' => esc_html__('Failed to save message', 'mxchat')
2379 2406 ], 500);
2380 2407 }
@@ -2508,8 +2535,9 @@
2508 2535 return $this->find_relevant_content_wordpress($user_embedding);
2509 2536 }
2510 2537 }
2511 2538
2539 +
2512 2540 private function find_relevant_content_wordpress($user_embedding) {
2513 2541 global $wpdb;
2514 2542 $system_prompt_table = $wpdb->prefix . 'mxchat_system_prompt_content';
2515 2543 $cache_key = 'mxchat_system_prompt_embeddings';
@@ -2514,11 +2542,15 @@
2514 2542 $system_prompt_table = $wpdb->prefix . 'mxchat_system_prompt_content';
2515 2543 $cache_key = 'mxchat_system_prompt_embeddings';
2516 2544 $batch_size = 500;
2517 2545
2546 + // Log start of matching process
2547 + //error_log('[MXCHAT] Starting similarity matching process');
2548 +
2518 2549 // Retrieve embeddings from cache or database
2519 2550 $embeddings = wp_cache_get($cache_key, 'mxchat_system_prompts');
2520 2551 if ($embeddings === false) {
2552 + //error_log('[MXCHAT] Cache miss - loading embeddings from database');
2521 2553 $embeddings = [];
2522 2554 $offset = 0;
2523 2555
2524 2556 // Load in batches and build cache
@@ -2544,15 +2576,28 @@
2544 2576
2545 2577 } while (true);
2546 2578
2547 2579 if (empty($embeddings)) {
2580 + //error_log('[MXCHAT] No embeddings found in database');
2548 2581 return ''; // Return an empty string if no embeddings found
2549 2582 }
2550 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');
2551 2587 }
2552 2588
2553 2589 // Initialize array to store relevant results with similarity scores
2554 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 +
2555 2600 // Iterate through embeddings to calculate similarity
2556 2601 foreach ($embeddings as $embedding) {
2557 2602 $database_embedding = $embedding->embedding_vector
2558 2603 ? unserialize($embedding->embedding_vector, ['allowed_classes' => false])
@@ -2558,8 +2603,14 @@
2558 2603 ? unserialize($embedding->embedding_vector, ['allowed_classes' => false])
2559 2604 : null;
2560 2605 if (is_array($database_embedding) && is_array($user_embedding)) {
2561 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 +
2562 2613 $relevant_results[] = [
2563 2614 'id' => $embedding->id,
2564 2615 'similarity' => $similarity
2565 2616 ];
@@ -2567,11 +2618,8 @@
2567 2618 // Free memory
2568 2619 unset($database_embedding);
2569 2620 }
2570 2621
2571 - // Retrieve the similarity threshold
2572 - $similarity_threshold = ((int) get_option('mxchat_similarity_threshold', 80)) / 100;
2573 -
2574 2622 // Filter and sort relevant results by similarity
2575 2623 $relevant_results = array_filter($relevant_results, function ($result) use ($similarity_threshold) {
2576 2624 return $result['similarity'] >= $similarity_threshold;
2577 2625 });
@@ -2578,11 +2626,20 @@
2578 2626 usort($relevant_results, function ($a, $b) {
2579 2627 return $b['similarity'] <=> $a['similarity'];
2580 2628 });
2581 2629
2630 + // Log number of results that met threshold
2631 + //error_log('[MXCHAT] ' . count($relevant_results) . ' results met the similarity threshold');
2632 +
2582 2633 // Limit to the top 5 results
2583 2634 $top_results = array_slice($relevant_results, 0, 5);
2584 2635
2636 + // Log the top matches
2637 + //error_log('[MXCHAT] Top matching results:');
2638 + foreach ($top_results as $index => $result) {
2639 +
2640 + }
2641 +
2585 2642 // Initialize the final content
2586 2643 $content = '';
2587 2644
2588 2645 // Fetch and combine content for the top results
@@ -2589,10 +2646,11 @@
2589 2646 foreach ($top_results as $result) {
2590 2647 $chunk_content = $this->fetch_content_with_product_links($result['id']);
2591 2648 // Check if the content is PDF-related and add surrounding pages
2592 2649 if (strpos($chunk_content, '{"document_type":"pdf"') !== false) {
2650 + //error_log('[MXCHAT] ID ' . $result['id'] . ' is PDF content, adding surrounding pages');
2593 2651 $surrounding_content = $wpdb->get_results($wpdb->prepare(
2594 - "SELECT article_content FROM {$system_prompt_table}
2652 + "SELECT id, article_content FROM {$system_prompt_table}
2595 2653 WHERE id IN (
2596 2654 (SELECT id FROM {$system_prompt_table} WHERE id < %d ORDER BY id DESC LIMIT 1),
2597 2655 (SELECT id FROM {$system_prompt_table} WHERE id > %d ORDER BY id ASC LIMIT 1)
2598 2656 )",
@@ -2614,29 +2672,38 @@
2614 2672 $content .= $chunk_content . "\n\n";
2615 2673 }
2616 2674 }
2617 2675
2676 + // Log content length
2677 + //error_log('[MXCHAT] Retrieved content length: ' . strlen(trim($content)) . ' characters');
2678 +
2618 2679 return trim($content);
2619 2680 }
2620 -/**
2621 - * Find relevant content in Pinecone vector database
2622 - */
2681 +
2682 +
2623 2683 private function find_relevant_content_pinecone($user_embedding) {
2624 2684 $options = get_option('mxchat_pinecone_addon_options', array());
2625 2685 $api_key = $options['mxchat_pinecone_api_key'] ?? '';
2626 2686 $host = $options['mxchat_pinecone_host'] ?? '';
2627 -
2687 +
2628 2688 if (empty($host) || empty($api_key)) {
2629 - //error_log('Pinecone credentials not properly configured');
2689 + //error_log('[MXCHAT Debug] Pinecone credentials not properly configured');
2630 2690 return '';
2631 2691 }
2632 -
2633 - // Get similarity threshold from WordPress settings
2634 - $similarity_threshold = ((int) get_option('mxchat_similarity_threshold', 80)) / 100;
2635 -
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 +
2636 2701 // Prepare the query request for Pinecone
2637 2702 $api_endpoint = "https://{$host}/query";
2638 -
2703 +
2704 + //error_log('[MXCHAT Debug] Querying Pinecone at: ' . $api_endpoint);
2705 +
2639 2706 $request_body = array(
2640 2707 'vector' => $user_embedding,
2641 2708 'topK' => 5,
2642 2709 'includeMetadata' => true,
@@ -2641,9 +2708,9 @@
2641 2708 'topK' => 5,
2642 2709 'includeMetadata' => true,
2643 2710 'includeValues' => true
2644 2711 );
2645 -
2712 +
2646 2713 $response = wp_remote_post($api_endpoint, array(
2647 2714 'headers' => array(
2648 2715 'Api-Key' => $api_key,
2649 2716 'accept' => 'application/json',
@@ -2651,35 +2718,43 @@
2651 2718 ),
2652 2719 'body' => wp_json_encode($request_body),
2653 2720 'timeout' => 30
2654 2721 ));
2655 -
2722 +
2656 2723 if (is_wp_error($response)) {
2657 - //error_log('Pinecone query error: ' . $response->get_error_message());
2724 + //error_log('[MXCHAT Debug] Pinecone query error: ' . $response->get_error_message());
2658 2725 return '';
2659 2726 }
2660 -
2727 +
2661 2728 $response_code = wp_remote_retrieve_response_code($response);
2662 2729 if ($response_code !== 200) {
2663 - //error_log('Pinecone API error: ' . wp_remote_retrieve_body($response));
2730 + //error_log('[MXCHAT Debug] Pinecone API error: ' . wp_remote_retrieve_body($response));
2664 2731 return '';
2665 2732 }
2666 -
2733 +
2667 2734 $results = json_decode(wp_remote_retrieve_body($response), true);
2668 2735 if (empty($results['matches'])) {
2736 + //error_log('[MXCHAT Debug] No matches found in Pinecone response');
2669 2737 return '';
2670 2738 }
2671 -
2739 +
2740 + //error_log('[MXCHAT Debug] Found ' . count($results['matches']) . ' matches in Pinecone');
2741 +
2672 2742 // Initialize the final content
2673 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
2674 2749
2675 - // Process each match
2676 - foreach ($results['matches'] as $match) {
2677 2750 // Skip if similarity is below threshold
2678 2751 if ($match['score'] < $similarity_threshold) {
2679 2752 continue;
2680 2753 }
2681 -
2754 +
2755 + $matches_above_threshold++;
2756 +
2682 2757 if (!empty($match['metadata']['text']) && !empty($match['metadata']['source_url'])) {
2683 2758 // Add content with citation
2684 2759 $content .= $match['metadata']['text'] . "\n";
2685 2760 $content .= "Source: " . $match['metadata']['source_url'] . "\n\n";
@@ -2684,13 +2759,15 @@
2684 2759 $content .= $match['metadata']['text'] . "\n";
2685 2760 $content .= "Source: " . $match['metadata']['source_url'] . "\n\n";
2686 2761 }
2687 2762 }
2688 -
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 +
2689 2767 return trim($content);
2690 2768 }
2691 2769
2692 -
2693 2770 private function mxchat_find_relevant_products($user_embedding) {
2694 2771 //error_log('MXChat Vector Search: Starting product search...');
2695 2772
2696 2773 // Retrieve the add-on settings from the database
@@ -3351,10 +3428,10 @@
3351 3428 }
3352 3429
3353 3430 public function mxchat_enqueue_scripts_styles() {
3354 3431 // Define version numbers for the styles and scripts
3355 - $chat_style_version = '2.0.6'; // Replace with your actual version
3356 - $chat_script_version = '2.0.6'; // 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
3357 3434
3358 3435 // Enqueue the script
3359 3436 wp_enqueue_script(
3360 3437 'mxchat-chat-js',