Changeset 3367268
- Timestamp:
- 09/24/2025 02:47:37 PM (5 months ago)
- Location:
- mxchat-basic
- Files:
-
- 98 added
- 9 edited
-
tags/2.4.4 (added)
-
tags/2.4.4/admin (added)
-
tags/2.4.4/admin/class-ajax-handler.php (added)
-
tags/2.4.4/admin/class-knowledge-manager.php (added)
-
tags/2.4.4/admin/class-pinecone-manager.php (added)
-
tags/2.4.4/css (added)
-
tags/2.4.4/css/admin-add-ons.css (added)
-
tags/2.4.4/css/admin-style.css (added)
-
tags/2.4.4/css/chat-style.css (added)
-
tags/2.4.4/css/chat-transcripts.css (added)
-
tags/2.4.4/css/content-selector.css (added)
-
tags/2.4.4/css/intent-style.css (added)
-
tags/2.4.4/css/knowledge-style.css (added)
-
tags/2.4.4/css/test-panel.css (added)
-
tags/2.4.4/images (added)
-
tags/2.4.4/images/Icon-01.svg (added)
-
tags/2.4.4/images/Icon-02.svg (added)
-
tags/2.4.4/images/Icon-03.svg (added)
-
tags/2.4.4/images/Icon-04.svg (added)
-
tags/2.4.4/images/pro-only-dark.png (added)
-
tags/2.4.4/includes (added)
-
tags/2.4.4/includes/class-mxchat-addons.php (added)
-
tags/2.4.4/includes/class-mxchat-admin.php (added)
-
tags/2.4.4/includes/class-mxchat-integrator.php (added)
-
tags/2.4.4/includes/class-mxchat-meta-box.php (added)
-
tags/2.4.4/includes/class-mxchat-public.php (added)
-
tags/2.4.4/includes/class-mxchat-user.php (added)
-
tags/2.4.4/includes/class-mxchat-utils.php (added)
-
tags/2.4.4/includes/class-mxchat-word-handler.php (added)
-
tags/2.4.4/includes/pdf-parser (added)
-
tags/2.4.4/includes/pdf-parser/alt_autoload.php (added)
-
tags/2.4.4/includes/pdf-parser/src (added)
-
tags/2.4.4/includes/pdf-parser/src/Smalot (added)
-
tags/2.4.4/includes/pdf-parser/src/Smalot/PdfParser (added)
-
tags/2.4.4/includes/pdf-parser/src/Smalot/PdfParser/Config.php (added)
-
tags/2.4.4/includes/pdf-parser/src/Smalot/PdfParser/Document.php (added)
-
tags/2.4.4/includes/pdf-parser/src/Smalot/PdfParser/Element (added)
-
tags/2.4.4/includes/pdf-parser/src/Smalot/PdfParser/Element.php (added)
-
tags/2.4.4/includes/pdf-parser/src/Smalot/PdfParser/Element/ElementArray.php (added)
-
tags/2.4.4/includes/pdf-parser/src/Smalot/PdfParser/Element/ElementBoolean.php (added)
-
tags/2.4.4/includes/pdf-parser/src/Smalot/PdfParser/Element/ElementDate.php (added)
-
tags/2.4.4/includes/pdf-parser/src/Smalot/PdfParser/Element/ElementHexa.php (added)
-
tags/2.4.4/includes/pdf-parser/src/Smalot/PdfParser/Element/ElementMissing.php (added)
-
tags/2.4.4/includes/pdf-parser/src/Smalot/PdfParser/Element/ElementName.php (added)
-
tags/2.4.4/includes/pdf-parser/src/Smalot/PdfParser/Element/ElementNull.php (added)
-
tags/2.4.4/includes/pdf-parser/src/Smalot/PdfParser/Element/ElementNumeric.php (added)
-
tags/2.4.4/includes/pdf-parser/src/Smalot/PdfParser/Element/ElementString.php (added)
-
tags/2.4.4/includes/pdf-parser/src/Smalot/PdfParser/Element/ElementStruct.php (added)
-
tags/2.4.4/includes/pdf-parser/src/Smalot/PdfParser/Element/ElementXRef.php (added)
-
tags/2.4.4/includes/pdf-parser/src/Smalot/PdfParser/Encoding (added)
-
tags/2.4.4/includes/pdf-parser/src/Smalot/PdfParser/Encoding.php (added)
-
tags/2.4.4/includes/pdf-parser/src/Smalot/PdfParser/Encoding/AbstractEncoding.php (added)
-
tags/2.4.4/includes/pdf-parser/src/Smalot/PdfParser/Encoding/EncodingLocator.php (added)
-
tags/2.4.4/includes/pdf-parser/src/Smalot/PdfParser/Encoding/ISOLatin1Encoding.php (added)
-
tags/2.4.4/includes/pdf-parser/src/Smalot/PdfParser/Encoding/ISOLatin9Encoding.php (added)
-
tags/2.4.4/includes/pdf-parser/src/Smalot/PdfParser/Encoding/MacRomanEncoding.php (added)
-
tags/2.4.4/includes/pdf-parser/src/Smalot/PdfParser/Encoding/PDFDocEncoding.php (added)
-
tags/2.4.4/includes/pdf-parser/src/Smalot/PdfParser/Encoding/PostScriptGlyphs.php (added)
-
tags/2.4.4/includes/pdf-parser/src/Smalot/PdfParser/Encoding/StandardEncoding.php (added)
-
tags/2.4.4/includes/pdf-parser/src/Smalot/PdfParser/Encoding/WinAnsiEncoding.php (added)
-
tags/2.4.4/includes/pdf-parser/src/Smalot/PdfParser/Exception (added)
-
tags/2.4.4/includes/pdf-parser/src/Smalot/PdfParser/Exception/EmptyPdfException.php (added)
-
tags/2.4.4/includes/pdf-parser/src/Smalot/PdfParser/Exception/EncodingNotFoundException.php (added)
-
tags/2.4.4/includes/pdf-parser/src/Smalot/PdfParser/Exception/MissingPdfHeaderException.php (added)
-
tags/2.4.4/includes/pdf-parser/src/Smalot/PdfParser/Exception/NotImplementedException.php (added)
-
tags/2.4.4/includes/pdf-parser/src/Smalot/PdfParser/Font (added)
-
tags/2.4.4/includes/pdf-parser/src/Smalot/PdfParser/Font.php (added)
-
tags/2.4.4/includes/pdf-parser/src/Smalot/PdfParser/Font/FontCIDFontType0.php (added)
-
tags/2.4.4/includes/pdf-parser/src/Smalot/PdfParser/Font/FontCIDFontType2.php (added)
-
tags/2.4.4/includes/pdf-parser/src/Smalot/PdfParser/Font/FontTrueType.php (added)
-
tags/2.4.4/includes/pdf-parser/src/Smalot/PdfParser/Font/FontType0.php (added)
-
tags/2.4.4/includes/pdf-parser/src/Smalot/PdfParser/Font/FontType1.php (added)
-
tags/2.4.4/includes/pdf-parser/src/Smalot/PdfParser/Font/FontType3.php (added)
-
tags/2.4.4/includes/pdf-parser/src/Smalot/PdfParser/Header.php (added)
-
tags/2.4.4/includes/pdf-parser/src/Smalot/PdfParser/PDFObject.php (added)
-
tags/2.4.4/includes/pdf-parser/src/Smalot/PdfParser/Page.php (added)
-
tags/2.4.4/includes/pdf-parser/src/Smalot/PdfParser/Pages.php (added)
-
tags/2.4.4/includes/pdf-parser/src/Smalot/PdfParser/Parser.php (added)
-
tags/2.4.4/includes/pdf-parser/src/Smalot/PdfParser/RawData (added)
-
tags/2.4.4/includes/pdf-parser/src/Smalot/PdfParser/RawData/FilterHelper.php (added)
-
tags/2.4.4/includes/pdf-parser/src/Smalot/PdfParser/RawData/RawDataParser.php (added)
-
tags/2.4.4/includes/pdf-parser/src/Smalot/PdfParser/XObject (added)
-
tags/2.4.4/includes/pdf-parser/src/Smalot/PdfParser/XObject/Form.php (added)
-
tags/2.4.4/includes/pdf-parser/src/Smalot/PdfParser/XObject/Image.php (added)
-
tags/2.4.4/js (added)
-
tags/2.4.4/js/activation-script.js (added)
-
tags/2.4.4/js/chat-script.js (added)
-
tags/2.4.4/js/content-selector.js (added)
-
tags/2.4.4/js/knowledge-processing.js (added)
-
tags/2.4.4/js/meta-box.js (added)
-
tags/2.4.4/js/mxchat-admin.js (added)
-
tags/2.4.4/js/mxchat-test-streaming.js (added)
-
tags/2.4.4/js/mxchat_transcripts.js (added)
-
tags/2.4.4/js/test-panel.js (added)
-
tags/2.4.4/languages (added)
-
tags/2.4.4/languages/mxchat.pot (added)
-
tags/2.4.4/mxchat-basic.php (added)
-
tags/2.4.4/readme.txt (added)
-
trunk/admin/class-ajax-handler.php (modified) (4 diffs)
-
trunk/admin/class-knowledge-manager.php (modified) (78 diffs)
-
trunk/admin/class-pinecone-manager.php (modified) (36 diffs)
-
trunk/includes/class-mxchat-addons.php (modified) (1 diff)
-
trunk/includes/class-mxchat-admin.php (modified) (4 diffs)
-
trunk/includes/class-mxchat-integrator.php (modified) (30 diffs)
-
trunk/js/chat-script.js (modified) (3 diffs)
-
trunk/mxchat-basic.php (modified) (3 diffs)
-
trunk/readme.txt (modified) (5 diffs)
Legend:
- Unmodified
- Added
- Removed
-
mxchat-basic/trunk/admin/class-ajax-handler.php
r3364278 r3367268 31 31 add_action('wp_ajax_migrate_pinecone_settings', array($this, 'ajax_migrate_pinecone_settings')); 32 32 33 // License AJAX - FIXED TO MATCH JAVASCRIPT33 // License AJAX 34 34 add_action('wp_ajax_mxchat_handle_activate_license', array($this, 'mxchat_handle_activate_license')); 35 35 add_action('wp_ajax_mxchat_check_license_status', array($this, 'mxchat_check_license_status')); … … 249 249 update_option('mxchat_current_knowledge_bot', $bot_id); 250 250 251 // Clear caches when switching bots 252 $pinecone_manager = MxChat_Pinecone_Manager::get_instance(); 253 $pinecone_manager->mxchat_clear_all_bot_caches(); 251 // No cache clearing needed since we removed caching 254 252 255 253 wp_send_json_success(array( … … 499 497 500 498 /** 501 * Validates and activates chat license via AJAX - FIXED VERSION499 * Validates and activates chat license via AJAX 502 500 */ 503 501 public function mxchat_handle_activate_license() { … … 607 605 */ 608 606 public function mxchat_check_license_status() { 609 // Verify nonce - FIXED: Use the correct nonce string607 // Verify nonce 610 608 if (!check_ajax_referer('mxchat_activate_license_nonce', 'security', false)) { 611 609 wp_send_json_error('Security check failed'); -
mxchat-basic/trunk/admin/class-knowledge-manager.php
r3364278 r3367268 91 91 92 92 // Debug logging 93 error_log('MANUAL BATCH DEBUG: Process type: ' . $process_type);94 error_log('MANUAL BATCH DEBUG: URL: ' . $url);93 //error_log('MANUAL BATCH DEBUG: Process type: ' . $process_type); 94 //error_log('MANUAL BATCH DEBUG: URL: ' . $url); 95 95 96 96 // FIXED: Extract bot_id from stored status instead of POST data … … 100 100 $status_key = sanitize_key('mxchat_pdf_status_' . md5($url)); 101 101 $status = get_transient($status_key); 102 error_log('MANUAL BATCH DEBUG: Status key: ' . $status_key);103 error_log('MANUAL BATCH DEBUG: Status data: ' . print_r($status, true));102 //error_log('MANUAL BATCH DEBUG: Status key: ' . $status_key); 103 //error_log('MANUAL BATCH DEBUG: Status data: ' . print_r($status, true)); 104 104 105 105 if ($status && isset($status['bot_id'])) { 106 106 $bot_id = $status['bot_id']; 107 error_log('MANUAL BATCH DEBUG: Bot ID from status: ' . $bot_id);107 //error_log('MANUAL BATCH DEBUG: Bot ID from status: ' . $bot_id); 108 108 } else { 109 error_log('MANUAL BATCH DEBUG: No bot_id in status, using default');109 //error_log('MANUAL BATCH DEBUG: No bot_id in status, using default'); 110 110 } 111 111 } elseif ($process_type === 'sitemap') { … … 117 117 } 118 118 119 error_log('MANUAL BATCH DEBUG: Final bot_id: ' . $bot_id);119 //error_log('MANUAL BATCH DEBUG: Final bot_id: ' . $bot_id); 120 120 121 121 $processed = 0; … … 123 123 if ($process_type === 'pdf') { 124 124 $processed = $this->mxchat_manual_process_pdf_batch($url); 125 error_log('MANUAL BATCH DEBUG: PDF processing returned: ' . $processed);125 //error_log('MANUAL BATCH DEBUG: PDF processing returned: ' . $processed); 126 126 } elseif ($process_type === 'sitemap') { 127 127 $processed = $this->mxchat_manual_process_sitemap_batch($url); … … 149 149 150 150 } catch (Exception $e) { 151 error_log('MANUAL BATCH DEBUG: Exception: ' . $e->getMessage());151 //error_log('MANUAL BATCH DEBUG: Exception: ' . $e->getMessage()); 152 152 wp_send_json_error('Processing failed: ' . $e->getMessage()); 153 153 } … … 156 156 private function mxchat_manual_process_pdf_batch($pdf_url) { 157 157 try { 158 error_log('MANUAL PDF DEBUG: Starting batch processing for: ' . $pdf_url);158 //error_log('MANUAL PDF DEBUG: Starting batch processing for: ' . $pdf_url); 159 159 160 160 $status_key = sanitize_key('mxchat_pdf_status_' . md5($pdf_url)); 161 161 $status = get_transient($status_key); 162 162 163 error_log('MANUAL PDF DEBUG: Status key: ' . $status_key);164 error_log('MANUAL PDF DEBUG: Status data: ' . print_r($status, true));163 //error_log('MANUAL PDF DEBUG: Status key: ' . $status_key); 164 //error_log('MANUAL PDF DEBUG: Status data: ' . print_r($status, true)); 165 165 166 166 if (!$status || $status['status'] !== 'processing') { 167 error_log('MANUAL PDF DEBUG: No processing status found or status is not processing');168 error_log('MANUAL PDF DEBUG: Status: ' . ($status ? $status['status'] : 'NULL'));167 //error_log('MANUAL PDF DEBUG: No processing status found or status is not processing'); 168 //error_log('MANUAL PDF DEBUG: Status: ' . ($status ? $status['status'] : 'NULL')); 169 169 return 0; 170 170 } … … 172 172 // FIXED: Extract bot_id from status 173 173 $bot_id = $status['bot_id'] ?? 'default'; 174 error_log('MANUAL PDF DEBUG: Bot ID from status: ' . $bot_id);174 //error_log('MANUAL PDF DEBUG: Bot ID from status: ' . $bot_id); 175 175 176 176 // Get current progress … … 178 178 $total_pages = $status['total_pages'] ?? 0; 179 179 180 error_log('MANUAL PDF DEBUG: Current page: ' . $current_page . ', Total pages: ' . $total_pages);180 //error_log('MANUAL PDF DEBUG: Current page: ' . $current_page . ', Total pages: ' . $total_pages); 181 181 182 182 if ($current_page >= $total_pages) { 183 error_log('MANUAL PDF DEBUG: Already completed');183 //error_log('MANUAL PDF DEBUG: Already completed'); 184 184 return 0; 185 185 } 186 186 187 187 // Try to download the PDF again for processing 188 error_log('MANUAL PDF DEBUG: Attempting to download PDF');188 //error_log('MANUAL PDF DEBUG: Attempting to download PDF'); 189 189 $response = wp_remote_get($pdf_url, array('timeout' => 30)); 190 190 191 191 if (is_wp_error($response)) { 192 error_log('MANUAL PDF DEBUG: Failed to download PDF: ' . $response->get_error_message());192 //error_log('MANUAL PDF DEBUG: Failed to download PDF: ' . $response->get_error_message()); 193 193 return 0; 194 194 } … … 196 196 $pdf_content = wp_remote_retrieve_body($response); 197 197 if (empty($pdf_content)) { 198 error_log('MANUAL PDF DEBUG: Empty PDF content');198 //error_log('MANUAL PDF DEBUG: Empty PDF content'); 199 199 return 0; 200 200 } 201 201 202 error_log('MANUAL PDF DEBUG: PDF content size: ' . strlen($pdf_content) . ' bytes');202 //error_log('MANUAL PDF DEBUG: PDF content size: ' . strlen($pdf_content) . ' bytes'); 203 203 204 204 // Save PDF temporarily … … 207 207 file_put_contents($temp_pdf_path, $pdf_content); 208 208 209 error_log('MANUAL PDF DEBUG: Temp PDF saved to: ' . $temp_pdf_path);209 //error_log('MANUAL PDF DEBUG: Temp PDF saved to: ' . $temp_pdf_path); 210 210 211 211 // Process 5 pages directly with bot_id 212 212 $processed = $this->mxchat_process_pdf_pages_direct($temp_pdf_path, $pdf_url, $current_page, 5, $bot_id); 213 213 214 error_log('MANUAL PDF DEBUG: Direct processing returned: ' . $processed);214 //error_log('MANUAL PDF DEBUG: Direct processing returned: ' . $processed); 215 215 216 216 // Clean up temp file 217 217 if (file_exists($temp_pdf_path)) { 218 218 wp_delete_file($temp_pdf_path); 219 error_log('MANUAL PDF DEBUG: Cleaned up temp file');219 //error_log('MANUAL PDF DEBUG: Cleaned up temp file'); 220 220 } 221 221 … … 223 223 224 224 } catch (Exception $e) { 225 error_log('MANUAL PDF DEBUG: Exception in manual batch: ' . $e->getMessage());225 //error_log('MANUAL PDF DEBUG: Exception in manual batch: ' . $e->getMessage()); 226 226 return 0; 227 227 } … … 547 547 public function mxchat_handle_pdf_for_knowledge_base($pdf_url, $response, $bot_id = 'default') { 548 548 if (!current_user_can('manage_options')) { 549 error_log('[PDF DEBUG] Unauthorized PDF processing attempt');549 //error_log('[PDF DEBUG] Unauthorized PDF processing attempt'); 550 550 return false; 551 551 } 552 552 553 error_log('[PDF DEBUG] Starting PDF processing for bot: ' . $bot_id);554 error_log('[PDF DEBUG] PDF URL: ' . $pdf_url);553 //error_log('[PDF DEBUG] Starting PDF processing for bot: ' . $bot_id); 554 //error_log('[PDF DEBUG] PDF URL: ' . $pdf_url); 555 555 556 556 $pdf_url = esc_url_raw($pdf_url); … … 558 558 559 559 if (isset($upload_dir['error']) && $upload_dir['error'] !== false) { 560 error_log('[PDF DEBUG] Upload directory error: ' . $upload_dir['error']);560 //error_log('[PDF DEBUG] Upload directory error: ' . $upload_dir['error']); 561 561 return false; 562 562 } … … 567 567 $response_body = wp_remote_retrieve_body($response); 568 568 if (empty($response_body)) { 569 error_log('[PDF DEBUG] Empty PDF response body');569 //error_log('[PDF DEBUG] Empty PDF response body'); 570 570 return false; 571 571 } 572 572 573 573 if (!wp_mkdir_p(dirname($pdf_path))) { 574 error_log('[PDF DEBUG] Failed to create directory for PDF: ' . $pdf_path);574 //error_log('[PDF DEBUG] Failed to create directory for PDF: ' . $pdf_path); 575 575 return false; 576 576 } … … 589 589 } 590 590 591 error_log('[PDF DEBUG] PDF validated successfully with ' . $total_pages . ' pages');591 //error_log('[PDF DEBUG] PDF validated successfully with ' . $total_pages . ' pages'); 592 592 593 593 // UPDATED: Pass bot_id to PDF processing cron … … 601 601 )); 602 602 603 error_log('[PDF DEBUG] Cron job scheduled with bot_id: ' . $bot_id);603 //error_log('[PDF DEBUG] Cron job scheduled with bot_id: ' . $bot_id); 604 604 605 605 // UPDATED: Store bot_id in status data … … 615 615 set_transient($status_key, $status_data, DAY_IN_SECONDS); 616 616 617 error_log('[PDF DEBUG] Status stored with bot_id: ' . $bot_id . ' using key: ' . $status_key);617 //error_log('[PDF DEBUG] Status stored with bot_id: ' . $bot_id . ' using key: ' . $status_key); 618 618 619 619 return __('scheduled', 'mxchat'); 620 620 621 621 } catch (Exception $e) { 622 error_log('[PDF DEBUG] Error preparing PDF for processing: ' . $e->getMessage());622 //error_log('[PDF DEBUG] Error preparing PDF for processing: ' . $e->getMessage()); 623 623 if (file_exists($pdf_path)) { 624 624 wp_delete_file($pdf_path); … … 788 788 public function mxchat_process_pdf_pages_cron($pdf_path, $pdf_url, $total_pages, $batch_size, $batch_pause, $bot_id = 'default') { 789 789 // ADD THIS DEBUG SECTION AT THE VERY BEGINNING 790 error_log('[PDF CRON DEBUG] ===== PDF Cron Job Started =====');791 error_log('[PDF CRON DEBUG] Initial bot_id parameter: ' . $bot_id);792 error_log('[PDF CRON DEBUG] Received parameters:');793 error_log('[PDF CRON DEBUG] - pdf_path: ' . $pdf_path);794 error_log('[PDF CRON DEBUG] - pdf_url: ' . $pdf_url);795 error_log('[PDF CRON DEBUG] - total_pages: ' . $total_pages);796 error_log('[PDF CRON DEBUG] - batch_size: ' . $batch_size);797 error_log('[PDF CRON DEBUG] - batch_pause: ' . $batch_pause);798 error_log('[PDF CRON DEBUG] - Total args received: ' . func_num_args());799 error_log('[PDF CRON DEBUG] - All args: ' . print_r(func_get_args(), true));790 //error_log('[PDF CRON DEBUG] ===== PDF Cron Job Started ====='); 791 //error_log('[PDF CRON DEBUG] Initial bot_id parameter: ' . $bot_id); 792 //error_log('[PDF CRON DEBUG] Received parameters:'); 793 //error_log('[PDF CRON DEBUG] - pdf_path: ' . $pdf_path); 794 //error_log('[PDF CRON DEBUG] - pdf_url: ' . $pdf_url); 795 //error_log('[PDF CRON DEBUG] - total_pages: ' . $total_pages); 796 //error_log('[PDF CRON DEBUG] - batch_size: ' . $batch_size); 797 //error_log('[PDF CRON DEBUG] - batch_pause: ' . $batch_pause); 798 //error_log('[PDF CRON DEBUG] - Total args received: ' . func_num_args()); 799 //error_log('[PDF CRON DEBUG] - All args: ' . print_r(func_get_args(), true)); 800 800 801 801 // FIXED: Get the correct bot_id from stored status instead of relying on cron parameters … … 805 805 if ($status && isset($status['bot_id'])) { 806 806 $bot_id = $status['bot_id']; 807 error_log('[PDF CRON DEBUG] Using bot_id from status: ' . $bot_id);807 //error_log('[PDF CRON DEBUG] Using bot_id from status: ' . $bot_id); 808 808 } else { 809 error_log('[PDF CRON DEBUG] No bot_id in status, using default: ' . $bot_id);809 //error_log('[PDF CRON DEBUG] No bot_id in status, using default: ' . $bot_id); 810 810 } 811 811 … … 876 876 $options = !empty($bot_options) ? $bot_options : get_option('mxchat_options'); 877 877 878 error_log('[PDF CRON DEBUG] Using bot options for bot: ' . $bot_id);878 //error_log('[PDF CRON DEBUG] Using bot options for bot: ' . $bot_id); 879 879 880 880 if (empty($options['api_key'])) { … … 939 939 $page_processed = true; 940 940 $successful_pages++; 941 error_log('[PDF CRON DEBUG] Successfully processed page ' . $page_number . ' for bot: ' . $bot_id);941 //error_log('[PDF CRON DEBUG] Successfully processed page ' . $page_number . ' for bot: ' . $bot_id); 942 942 943 943 } catch (Exception $e) { … … 945 945 $last_error = $e->getMessage(); 946 946 947 error_log("PDF page {$page_number} failed (attempt {$retry_count}/{$max_retries}): " . $last_error);947 //error_log("PDF page {$page_number} failed (attempt {$retry_count}/{$max_retries}): " . $last_error); 948 948 949 949 if ($retry_count < $max_retries) { … … 967 967 } 968 968 969 error_log("PDF page {$page_number} permanently failed after {$max_retries} attempts: " . $last_error);969 //error_log("PDF page {$page_number} permanently failed after {$max_retries} attempts: " . $last_error); 970 970 } 971 971 … … 1007 1007 } 1008 1008 1009 error_log('[PDF CRON DEBUG] PDF processing completed for bot: ' . $bot_id);1009 //error_log('[PDF CRON DEBUG] PDF processing completed for bot: ' . $bot_id); 1010 1010 } 1011 1011 1012 1012 } catch (\Exception $e) { 1013 error_log(sprintf('[MXCHAT-PDF] Error processing PDF for bot %s: %s', $bot_id, $e->getMessage()));1013 //error_log(sprintf('[MXCHAT-PDF] Error processing PDF for bot %s: %s', $bot_id, $e->getMessage())); 1014 1014 1015 1015 $status_key = sanitize_key('mxchat_pdf_status_' . md5($pdf_url)); … … 1142 1142 public function mxchat_handle_sitemap_submission() { 1143 1143 // START DEBUG 1144 error_log('[SITEMAP DEBUG] ===== Starting URL submission process =====');1145 error_log('[SITEMAP DEBUG] POST data: ' . print_r($_POST, true));1144 //error_log('[SITEMAP DEBUG] ===== Starting URL submission process ====='); 1145 //error_log('[SITEMAP DEBUG] POST data: ' . print_r($_POST, true)); 1146 1146 1147 1147 // Get bot_id from form submission EARLY for debugging 1148 1148 $bot_id = isset($_POST['bot_id']) ? sanitize_key($_POST['bot_id']) : 'default'; 1149 error_log('[SITEMAP DEBUG] Extracted bot_id: ' . $bot_id);1150 error_log('[SITEMAP DEBUG] Class exists MxChat_Multi_Bot_Manager: ' . (class_exists('MxChat_Multi_Bot_Manager') ? 'YES' : 'NO'));1149 //error_log('[SITEMAP DEBUG] Extracted bot_id: ' . $bot_id); 1150 //error_log('[SITEMAP DEBUG] Class exists MxChat_Multi_Bot_Manager: ' . (class_exists('MxChat_Multi_Bot_Manager') ? 'YES' : 'NO')); 1151 1151 // END DEBUG 1152 1152 1153 1153 // Check if the form was submitted and verify permissions 1154 1154 if (!isset($_POST['submit_sitemap']) || !current_user_can('manage_options')) { 1155 error_log('[SITEMAP DEBUG] Error: Unauthorized access or form not submitted properly');1155 //error_log('[SITEMAP DEBUG] Error: Unauthorized access or form not submitted properly'); 1156 1156 wp_die(esc_html__('Unauthorized access', 'mxchat')); 1157 1157 } 1158 1158 1159 1159 // Verify nonce 1160 error_log('[SITEMAP DEBUG] Verifying nonce');1160 //error_log('[SITEMAP DEBUG] Verifying nonce'); 1161 1161 check_admin_referer('mxchat_submit_sitemap_action', 'mxchat_submit_sitemap_nonce'); 1162 1162 1163 1163 // Validate URL 1164 1164 if (!isset($_POST['sitemap_url']) || empty($_POST['sitemap_url'])) { 1165 error_log('[SITEMAP DEBUG] Error: Empty or missing URL');1165 //error_log('[SITEMAP DEBUG] Error: Empty or missing URL'); 1166 1166 set_transient('mxchat_admin_notice_error', 1167 1167 esc_html__('Please provide a valid URL.', 'mxchat'), … … 1175 1175 1176 1176 // Continue processing with already extracted bot_id 1177 error_log('[SITEMAP DEBUG] Processing URL: ' . $submitted_url . ' for bot: ' . $bot_id);1177 //error_log('[SITEMAP DEBUG] Processing URL: ' . $submitted_url . ' for bot: ' . $bot_id); 1178 1178 1179 1179 // UPDATED: Get bot-specific options and validate API key 1180 1180 $bot_options = $this->get_bot_options($bot_id); 1181 error_log('[SITEMAP DEBUG] Bot options retrieved: ' . print_r($bot_options, true));1181 //error_log('[SITEMAP DEBUG] Bot options retrieved: ' . print_r($bot_options, true)); 1182 1182 1183 1183 $options = !empty($bot_options) ? $bot_options : get_option('mxchat_options'); 1184 1184 $selected_model = $options['embedding_model'] ?? 'text-embedding-ada-002'; 1185 1185 1186 error_log('[SITEMAP DEBUG] Selected embedding model: ' . $selected_model);1186 //error_log('[SITEMAP DEBUG] Selected embedding model: ' . $selected_model); 1187 1187 1188 1188 if (strpos($selected_model, 'voyage') === 0) { … … 1197 1197 } 1198 1198 1199 error_log('[SITEMAP DEBUG] Provider: ' . $provider_name . ', Has API key: ' . (!empty($api_key) ? 'YES' : 'NO'));1199 //error_log('[SITEMAP DEBUG] Provider: ' . $provider_name . ', Has API key: ' . (!empty($api_key) ? 'YES' : 'NO')); 1200 1200 1201 1201 if (empty($api_key)) { … … 1204 1204 $provider_name 1205 1205 ); 1206 error_log('[SITEMAP DEBUG] Error: ' . $error_message);1206 //error_log('[SITEMAP DEBUG] Error: ' . $error_message); 1207 1207 set_transient('mxchat_admin_notice_error', $error_message, 30); 1208 1208 wp_safe_redirect(esc_url(admin_url('admin.php?page=mxchat-prompts'))); … … 1210 1210 } 1211 1211 1212 error_log('[SITEMAP DEBUG] Fetching URL content');1212 //error_log('[SITEMAP DEBUG] Fetching URL content'); 1213 1213 $response = wp_remote_get($submitted_url, array('timeout' => 30)); 1214 1214 1215 1215 if (is_wp_error($response) || wp_remote_retrieve_response_code($response) !== 200) { 1216 1216 $error_message = is_wp_error($response) ? $response->get_error_message() : 'HTTP Status: ' . wp_remote_retrieve_response_code($response); 1217 error_log('[SITEMAP DEBUG] Error fetching URL: ' . $error_message);1217 //error_log('[SITEMAP DEBUG] Error fetching URL: ' . $error_message); 1218 1218 set_transient('mxchat_admin_notice_error', 1219 1219 sprintf( … … 1228 1228 1229 1229 $content_type = wp_remote_retrieve_header($response, 'content-type'); 1230 error_log('[SITEMAP DEBUG] Content type: ' . $content_type);1230 //error_log('[SITEMAP DEBUG] Content type: ' . $content_type); 1231 1231 $body_content = wp_remote_retrieve_body($response); 1232 1232 1233 1233 if (empty($body_content)) { 1234 error_log('[SITEMAP DEBUG] Error: Empty response body');1234 //error_log('[SITEMAP DEBUG] Error: Empty response body'); 1235 1235 set_transient('mxchat_admin_notice_error', 1236 1236 esc_html__('Empty response received from URL.', 'mxchat'), … … 1240 1240 exit; 1241 1241 } 1242 error_log('[SITEMAP DEBUG] Retrieved body content length: ' . strlen($body_content) . ' bytes');1242 //error_log('[SITEMAP DEBUG] Retrieved body content length: ' . strlen($body_content) . ' bytes'); 1243 1243 1244 1244 // Handle PDF URL 1245 1245 if ($this->mxchat_is_pdf_url($submitted_url, $response)) { 1246 error_log('[SITEMAP DEBUG] Detected PDF URL, handling PDF for knowledge base');1247 error_log('[SITEMAP DEBUG] About to call PDF handler with bot_id: ' . $bot_id);1246 //error_log('[SITEMAP DEBUG] Detected PDF URL, handling PDF for knowledge base'); 1247 //error_log('[SITEMAP DEBUG] About to call PDF handler with bot_id: ' . $bot_id); 1248 1248 1249 1249 // UPDATED: Pass bot_id to PDF handler 1250 1250 $result = $this->mxchat_handle_pdf_for_knowledge_base($submitted_url, $response, $bot_id); 1251 error_log('[SITEMAP DEBUG] PDF handling result: ' . $result);1251 //error_log('[SITEMAP DEBUG] PDF handling result: ' . $result); 1252 1252 1253 1253 if ($result === 'scheduled') { … … 1263 1263 DAY_IN_SECONDS 1264 1264 ); 1265 error_log('[SITEMAP DEBUG] PDF processing scheduled successfully for bot: ' . $bot_id);1265 //error_log('[SITEMAP DEBUG] PDF processing scheduled successfully for bot: ' . $bot_id); 1266 1266 set_transient('mxchat_admin_notice_info', 1267 1267 esc_html__('PDF processing has started in the background. You can check the progress in the Knowledge Base section.', 'mxchat'), … … 1269 1269 ); 1270 1270 } else { 1271 error_log('[SITEMAP DEBUG] PDF processing failed: ' . $result);1271 //error_log('[SITEMAP DEBUG] PDF processing failed: ' . $result); 1272 1272 set_transient('mxchat_admin_notice_error', 1273 1273 esc_html__('Failed to start PDF processing: ', 'mxchat') . esc_html($result), … … 1282 1282 // Handle Sitemap XML 1283 1283 if (strpos($content_type, 'xml') !== false || strpos($body_content, '<urlset') !== false) { 1284 error_log('[SITEMAP DEBUG] Detected XML content, processing as sitemap');1284 //error_log('[SITEMAP DEBUG] Detected XML content, processing as sitemap'); 1285 1285 libxml_use_internal_errors(true); 1286 1286 $xml = simplexml_load_string($body_content); … … 1289 1289 1290 1290 if ($xml === false || !empty($xml_errors)) { 1291 error_log('[SITEMAP DEBUG] Error: Invalid XML format');1291 //error_log('[SITEMAP DEBUG] Error: Invalid XML format'); 1292 1292 if (!empty($xml_errors)) { 1293 1293 foreach ($xml_errors as $error) { 1294 error_log('[SITEMAP DEBUG] XML Error: ' . $error->message);1294 //error_log('[SITEMAP DEBUG] XML Error: ' . $error->message); 1295 1295 } 1296 1296 } … … 1304 1304 } 1305 1305 1306 error_log('[SITEMAP DEBUG] Valid XML found, handling sitemap for knowledge base');1306 //error_log('[SITEMAP DEBUG] Valid XML found, handling sitemap for knowledge base'); 1307 1307 // UPDATED: Pass bot_id to sitemap handler 1308 1308 $result = $this->mxchat_handle_sitemap_for_knowledge_base($xml, $submitted_url, $bot_id); 1309 error_log('[SITEMAP DEBUG] Sitemap handling result: ' . $result);1309 //error_log('[SITEMAP DEBUG] Sitemap handling result: ' . $result); 1310 1310 1311 1311 if ($result === 'scheduled') { … … 1337 1337 1338 1338 // Handle Regular URL 1339 error_log('[SITEMAP DEBUG] Processing as regular webpage');1339 //error_log('[SITEMAP DEBUG] Processing as regular webpage'); 1340 1340 $page_content = $this->mxchat_extract_main_content($body_content); 1341 error_log('[SITEMAP DEBUG] Extracted content length: ' . strlen($page_content) . ' bytes');1341 //error_log('[SITEMAP DEBUG] Extracted content length: ' . strlen($page_content) . ' bytes'); 1342 1342 1343 1343 $sanitized_content = $this->mxchat_sanitize_content_for_api($page_content); 1344 error_log('[SITEMAP DEBUG] Sanitized content length: ' . strlen($sanitized_content) . ' bytes');1344 //error_log('[SITEMAP DEBUG] Sanitized content length: ' . strlen($sanitized_content) . ' bytes'); 1345 1345 1346 1346 if (empty($sanitized_content)) { 1347 error_log('[SITEMAP DEBUG] Error: No valid content after sanitization');1347 //error_log('[SITEMAP DEBUG] Error: No valid content after sanitization'); 1348 1348 1349 1349 set_transient('mxchat_admin_notice_error', … … 1363 1363 } 1364 1364 1365 error_log('[SITEMAP DEBUG] Generating embedding for content');1365 //error_log('[SITEMAP DEBUG] Generating embedding for content'); 1366 1366 $embedding_vector = $this->mxchat_generate_embedding($sanitized_content, $bot_id); 1367 1367 1368 1368 if (is_string($embedding_vector)) { 1369 error_log('[SITEMAP DEBUG] Error generating embedding: ' . $embedding_vector);1369 //error_log('[SITEMAP DEBUG] Error generating embedding: ' . $embedding_vector); 1370 1370 $error_message = esc_html__('Failed to generate embedding: ', 'mxchat') . esc_html($embedding_vector); 1371 1371 … … 1384 1384 1385 1385 if (is_array($embedding_vector)) { 1386 error_log('[SITEMAP DEBUG] Successfully generated embedding with ' . count($embedding_vector) . ' dimensions');1386 //error_log('[SITEMAP DEBUG] Successfully generated embedding with ' . count($embedding_vector) . ' dimensions'); 1387 1387 1388 1388 // UPDATED: Pass bot_id to database submission … … 1396 1396 1397 1397 if (is_wp_error($db_result)) { 1398 error_log('[SITEMAP DEBUG] Error: Failed to store content in database: ' . $db_result->get_error_message());1398 //error_log('[SITEMAP DEBUG] Error: Failed to store content in database: ' . $db_result->get_error_message()); 1399 1399 $error_message = esc_html__('Failed to store content in database: ', 'mxchat') . esc_html($db_result->get_error_message()); 1400 1400 … … 1412 1412 } 1413 1413 1414 error_log('[SITEMAP DEBUG] Successfully stored content in database');1414 //error_log('[SITEMAP DEBUG] Successfully stored content in database'); 1415 1415 $success_message = esc_html__('URL content successfully submitted!', 'mxchat'); 1416 1416 … … 1426 1426 1427 1427 } else { 1428 error_log('[SITEMAP DEBUG] Error: Failed to generate embedding. Unexpected result type: ' . gettype($embedding_vector));1428 //error_log('[SITEMAP DEBUG] Error: Failed to generate embedding. Unexpected result type: ' . gettype($embedding_vector)); 1429 1429 $error_message = esc_html__('Failed to generate embedding: Unexpected result type. Please check your API key and try again.', 'mxchat'); 1430 1430 … … 1439 1439 } 1440 1440 1441 error_log('[SITEMAP DEBUG] ===== Completed URL submission process =====');1441 //error_log('[SITEMAP DEBUG] ===== Completed URL submission process ====='); 1442 1442 wp_safe_redirect(esc_url(admin_url('admin.php?page=mxchat-prompts'))); 1443 1443 exit; … … 2196 2196 2197 2197 2198 2199 2198 /** 2200 * checking if WooCommerce products were already processed in the WordPress database.2199 * Get content list for processing 2201 2200 */ 2202 2201 public function ajax_mxchat_get_content_list() { … … 2224 2223 ); 2225 2224 2226 // Handle post types 2225 // Handle post types - IMPROVED VERSION 2227 2226 if ($post_type !== 'all') { 2228 2227 $args['post_type'] = $post_type; 2229 2228 } else { 2230 // Default to post and page if we can't get post types 2231 $args['post_type'] = array('post', 'page'); 2232 2233 // Try to get public post types 2234 $public_types = $this->mxchat_get_public_post_types(); 2235 if (is_array($public_types) && !empty($public_types)) { 2236 $args['post_type'] = array_keys($public_types); 2237 } 2229 // Get all available post types that might contain content 2230 $all_post_types = array(); 2231 2232 // First get all public post types 2233 $public_types = get_post_types(array('public' => true), 'names'); 2234 $all_post_types = array_merge($all_post_types, $public_types); 2235 2236 // Add common forum/community post types 2237 $forum_types = array('topic', 'reply', 'forum', 'wpforo_topic', 'wpforo_post'); 2238 foreach ($forum_types as $forum_type) { 2239 if (post_type_exists($forum_type)) { 2240 $all_post_types[] = $forum_type; 2241 } 2242 } 2243 2244 // Add other commonly used post types 2245 $common_types = array('product', 'job_listing', 'event', 'portfolio'); 2246 foreach ($common_types as $common_type) { 2247 if (post_type_exists($common_type)) { 2248 $all_post_types[] = $common_type; 2249 } 2250 } 2251 2252 // Remove duplicates and ensure we have at least some post types 2253 $all_post_types = array_unique($all_post_types); 2254 2255 if (empty($all_post_types)) { 2256 // Fallback to basic post types 2257 $all_post_types = array('post', 'page'); 2258 } 2259 2260 $args['post_type'] = $all_post_types; 2261 2262 // Debug logging to see what post types are being queried 2263 //error_log('MxChat Debug: Querying post types: ' . implode(', ', $all_post_types)); 2238 2264 } 2239 2265 … … 2242 2268 } 2243 2269 2244 // ================================ 2245 // WordPress DB checking for WooCommerce products 2246 // ================================ 2247 2270 // Get processed data from storage 2248 2271 $processed_data = array(); 2249 2272 2250 $pinecone_manager = MxChat_Pinecone_Manager::get_instance();2251 2273 $pinecone_options = get_option('mxchat_pinecone_addon_options', array()); 2252 $pinecone_manager->mxchat_refresh_after_new_content($pinecone_options);2253 2274 $use_pinecone = ($pinecone_options['mxchat_use_pinecone'] ?? '0') === '1'; 2254 2275 2255 2276 if ($use_pinecone && !empty($pinecone_options['mxchat_pinecone_api_key'])) { 2256 // ONLY check Pinecone if it's enabled2277 // Get fresh data from Pinecone - no caching 2257 2278 $processed_data = $this->mxchat_get_pinecone_processed_content($pinecone_options); 2258 2279 } else { 2259 // IMPROVED: WordPress DB checking with better URL matching for WooCommerce2280 // WordPress DB checking with better URL matching for all post types 2260 2281 global $wpdb; 2261 2282 $table_name = $wpdb->prefix . 'mxchat_system_prompt_content'; … … 2264 2285 if (!empty($processed_items)) { 2265 2286 foreach ($processed_items as $item) { 2266 // FIXED: Use improved URL matching for WooCommerce products2287 // Use improved URL matching that works for all post types 2267 2288 $post_id = $this->mxchat_url_to_post_id_improved($item->source_url); 2268 2289 … … 2278 2299 } 2279 2300 } 2280 2281 // ================================2282 2301 2283 2302 // Get processed IDs as a simple array for in_array checks … … 2354 2373 } 2355 2374 2375 2356 2376 /** 2357 2377 * This function handles various WooCommerce URL formats and permalink structures … … 2365 2385 } 2366 2386 2367 // If that fails, try more aggressive URL matching for WooCommerce products2387 // If that fails, try more aggressive URL matching 2368 2388 // Remove trailing slashes and query parameters for better matching 2369 2389 $clean_url = rtrim($url, '/'); … … 2376 2396 } 2377 2397 2378 // For WooCommerce products, try extracting slug from URL 2398 // For bbPress forum topics, try extracting slug from URL 2399 if (strpos($url, '/topic/') !== false || strpos($url, '/forums/') !== false) { 2400 // Handle bbPress URLs: /forums/topic/topic-name/ 2401 if (preg_match('/\/forums\/topic\/([^\/\?]+)/', $url, $matches)) { 2402 $topic_slug = $matches[1]; 2403 2404 // Look up topic by slug 2405 $topic = get_page_by_path($topic_slug, OBJECT, 'topic'); 2406 if ($topic) { 2407 return $topic->ID; 2408 } 2409 2410 // Alternative method: query by post_name 2411 global $wpdb; 2412 $post_id = $wpdb->get_var($wpdb->prepare( 2413 "SELECT ID FROM {$wpdb->posts} WHERE post_name = %s AND post_type = 'topic' AND post_status IN ('publish', 'closed')", 2414 $topic_slug 2415 )); 2416 2417 if ($post_id) { 2418 return intval($post_id); 2419 } 2420 } 2421 2422 // Handle simpler topic URLs: /topic/topic-name/ 2423 if (preg_match('/\/topic\/([^\/\?]+)/', $url, $matches)) { 2424 $topic_slug = $matches[1]; 2425 2426 global $wpdb; 2427 $post_id = $wpdb->get_var($wpdb->prepare( 2428 "SELECT ID FROM {$wpdb->posts} WHERE post_name = %s AND post_type = 'topic' AND post_status IN ('publish', 'closed')", 2429 $topic_slug 2430 )); 2431 2432 if ($post_id) { 2433 return intval($post_id); 2434 } 2435 } 2436 } 2437 2438 // For WooCommerce products 2379 2439 if (strpos($url, '/product/') !== false || strpos($url, 'product=') !== false) { 2380 2440 // Extract product slug from various URL formats … … 2410 2470 } 2411 2471 2412 // ADDITIONAL FIX: Try direct database lookup by URL variations 2472 // Generic approach: try to extract slug and match against all post types 2473 $parsed_url = wp_parse_url($clean_url); 2474 $path = $parsed_url['path'] ?? ''; 2475 2476 if (!empty($path)) { 2477 // Get the last part of the path as potential slug 2478 $path_parts = array_filter(explode('/', trim($path, '/'))); 2479 $potential_slug = end($path_parts); 2480 2481 if (!empty($potential_slug)) { 2482 global $wpdb; 2483 2484 // Try to find any post with this slug 2485 $post_id = $wpdb->get_var($wpdb->prepare( 2486 "SELECT ID FROM {$wpdb->posts} 2487 WHERE post_name = %s 2488 AND post_status IN ('publish', 'closed', 'private') 2489 AND post_type NOT IN ('revision', 'attachment', 'nav_menu_item') 2490 ORDER BY CASE 2491 WHEN post_type = 'post' THEN 1 2492 WHEN post_type = 'page' THEN 2 2493 WHEN post_type = 'topic' THEN 3 2494 WHEN post_type = 'product' THEN 4 2495 ELSE 5 2496 END 2497 LIMIT 1", 2498 $potential_slug 2499 )); 2500 2501 if ($post_id) { 2502 return intval($post_id); 2503 } 2504 } 2505 } 2506 2507 // ADDITIONAL: Try direct database lookup by URL variations 2413 2508 global $wpdb; 2414 2509 $table_name = $wpdb->prefix . 'mxchat_system_prompt_content'; 2415 2510 2416 // Try exact match first2417 $existing_record = $wpdb->get_row($wpdb->prepare(2418 "SELECT id, source_url FROM $table_name WHERE source_url = %s",2419 $url2420 ));2421 2422 if ($existing_record) {2423 // Found exact match, now convert the URL to post ID2424 $post_id = url_to_postid($existing_record->source_url);2425 if ($post_id > 0) {2426 return $post_id;2427 }2428 }2429 2430 2511 // Try variations of the URL (with/without trailing slash, http/https) 2431 2512 $url_variations = array( 2513 $url, 2432 2514 rtrim($url, '/'), 2433 2515 $url . '/', … … 2438 2520 ); 2439 2521 2522 // Remove duplicates 2523 $url_variations = array_unique($url_variations); 2524 2440 2525 foreach ($url_variations as $variation) { 2441 2526 $existing_record = $wpdb->get_row($wpdb->prepare( … … 2445 2530 2446 2531 if ($existing_record) { 2447 $post_id = url_to_postid($existing_record->source_url); 2448 if ($post_id > 0) { 2449 return $post_id; 2450 } 2451 } 2452 } 2453 2454 // Last resort: try to match against all published products by URL if WooCommerce is active 2455 if (function_exists('wc_get_products')) { 2456 // Get all published products (limited to avoid memory issues) 2457 $products = wc_get_products(array( 2458 'status' => 'publish', 2459 'limit' => 1000, // Reasonable limit 2460 'return' => 'ids' 2461 )); 2462 2463 foreach ($products as $product_id) { 2464 $product_url = get_permalink($product_id); 2465 2466 // Compare cleaned URLs 2467 $clean_product_url = rtrim($product_url, '/'); 2468 $clean_product_url = strtok($clean_product_url, '?'); 2469 2470 if ($clean_url === $clean_product_url) { 2471 return $product_id; 2472 } 2473 2474 // Also check if any of our URL variations match 2475 foreach ($url_variations as $variation) { 2476 $clean_variation = rtrim($variation, '/'); 2477 $clean_variation = strtok($clean_variation, '?'); 2478 2479 if ($clean_variation === $clean_product_url) { 2480 return $product_id; 2481 } 2532 // Try to get post ID from this stored URL 2533 $stored_post_id = url_to_postid($existing_record->source_url); 2534 if ($stored_post_id > 0) { 2535 return $stored_post_id; 2482 2536 } 2483 2537 } … … 2486 2540 return 0; // No match found 2487 2541 } 2488 2542 /** 2543 * Process selected content via AJAX 2544 */ 2489 2545 public function ajax_mxchat_process_selected_content() { 2490 2546 // Basic request validation … … 2613 2669 } 2614 2670 2615 // Update caches if Pinecone is enabled for this bot2616 if ($use_pinecone && !empty($bot_pinecone_config['api_key'])) {2617 // Update vector ID cache for improved fetching2618 $this->mxchat_update_pinecone_vector_cache($vector_id);2619 2620 // Update local processed content cache for immediate UI feedback2621 $pinecone_cache = get_option('mxchat_pinecone_processed_cache', array());2622 $pinecone_cache[$post_id] = array(2623 'db_id' => $vector_id,2624 'processed_date' => 'Just now',2625 'url' => $source_url,2626 'source' => 'pinecone',2627 'timestamp' => current_time('timestamp')2628 );2629 update_option('mxchat_pinecone_processed_cache', $pinecone_cache);2630 2631 // Also update the general processed content cache2632 $processed_cache = get_option('mxchat_processed_content_cache', array());2633 $processed_cache[$post_id] = array(2634 'db_id' => $vector_id,2635 'timestamp' => current_time('timestamp'),2636 'url' => $source_url,2637 'source' => 'pinecone'2638 );2639 update_option('mxchat_processed_content_cache', $processed_cache);2640 }2641 2642 2671 $operation_type = $is_update ? 'update' : 'new'; 2643 2672 … … 2652 2681 'operation_type' => $operation_type, 2653 2682 'vector_id' => $vector_id, 2654 'cache_updated' => $use_pinecone,2655 2683 'acf_fields_found' => $acf_field_count, 2656 2684 'content_preview' => substr($content, 0, 100) . '...', … … 2660 2688 } 2661 2689 2662 2663 2664 2665 /**2666 * Updates cache with new vector ID if absent2667 */2668 public function mxchat_update_pinecone_vector_cache($vector_id) {2669 $cached_ids = get_option('mxchat_pinecone_vector_ids_cache', array());2670 if (!in_array($vector_id, $cached_ids)) {2671 $cached_ids[] = $vector_id;2672 update_option('mxchat_pinecone_vector_ids_cache', $cached_ids);2673 }2674 }2675 2690 public function mxchat_get_public_post_types() { 2691 // Get all public post types 2676 2692 $post_types = get_post_types(array('public' => true), 'objects'); 2677 2693 $post_type_options = array(); … … 2681 2697 } 2682 2698 2699 // Also include common forum/community post types that might not be marked as public 2700 $additional_types = array( 2701 'topic' => 'Forum Topics (bbPress)', 2702 'reply' => 'Forum Replies (bbPress)', 2703 'forum' => 'Forums (bbPress)', 2704 'wpforo_topic' => 'wpForo Topics', 2705 'wpforo_post' => 'wpForo Posts' 2706 ); 2707 2708 foreach ($additional_types as $type_name => $type_label) { 2709 if (post_type_exists($type_name) && !isset($post_type_options[$type_name])) { 2710 $post_type_options[$type_name] = $type_label; 2711 } 2712 } 2713 2683 2714 return $post_type_options; 2684 2715 } 2716 2717 /** 2718 * Retrieves processed content from Pinecone API 2719 */ 2685 2720 public function mxchat_get_pinecone_processed_content($pinecone_options) { 2686 //error_log('=== DEBUG: Starting mxchat_get_pinecone_processed_content ===');2687 2688 // First check local cache for immediate updates2689 $cached_data = get_option('mxchat_pinecone_processed_cache', array());2690 //error_log('DEBUG: Found ' . count($cached_data) . ' items in local cache');2691 2692 2721 $api_key = $pinecone_options['mxchat_pinecone_api_key'] ?? ''; 2693 2722 $host = $pinecone_options['mxchat_pinecone_host'] ?? ''; 2694 2695 //error_log('DEBUG: API key present: ' . (!empty($api_key) ? 'YES' : 'NO'));2696 //error_log('DEBUG: Host: ' . $host);2697 2723 2698 2724 if (empty($api_key) || empty($host)) { 2699 //error_log('DEBUG: Missing API credentials, returning cached data only'); 2700 return $cached_data; 2725 return array(); 2701 2726 } 2702 2727 … … 2704 2729 2705 2730 try { 2706 // Method 1: Try to get vectors using cached vector IDs first 2707 $cached_vector_ids = get_option('mxchat_pinecone_vector_ids_cache', array()); 2708 //error_log('DEBUG: Found ' . count($cached_vector_ids) . ' cached vector IDs'); 2709 2710 if (!empty($cached_vector_ids)) { 2711 //error_log('DEBUG: Trying to fetch by cached vector IDs...'); 2712 $pinecone_data = $this->mxchat_fetch_pinecone_vectors_by_ids($pinecone_options, $cached_vector_ids); 2713 //error_log('DEBUG: Fetch by IDs returned ' . count($pinecone_data) . ' items'); 2714 } 2715 2716 // Method 2: If no cached IDs or fetch failed, use scanning approach 2731 // Always get fresh data from Pinecone 2732 $pinecone_data = $this->mxchat_scan_pinecone_for_processed_content($pinecone_options); 2733 2734 // Method 2: Final fallback - try stats endpoint (if available) 2717 2735 if (empty($pinecone_data)) { 2718 //error_log('DEBUG: Trying scanning approach...');2719 $pinecone_data = $this->mxchat_scan_pinecone_for_processed_content($pinecone_options);2720 //error_log('DEBUG: Scanning returned ' . count($pinecone_data) . ' items');2721 }2722 2723 // Method 3: Final fallback - try stats endpoint2724 if (empty($pinecone_data)) {2725 //error_log('DEBUG: Trying stats endpoint...');2726 2736 $stats_url = "https://{$host}/describe_index_stats"; 2727 2737 … … 2738 2748 $body = wp_remote_retrieve_body($response); 2739 2749 $stats_data = json_decode($body, true); 2740 //error_log('DEBUG: Pinecone stats: ' . print_r($stats_data, true));2741 } else {2742 if (is_wp_error($response)) {2743 //error_log('DEBUG: Stats endpoint error: ' . $response->get_error_message());2744 } else {2745 //error_log('DEBUG: Stats endpoint failed with code: ' . wp_remote_retrieve_response_code($response));2746 }2747 2750 } 2748 2751 } 2749 2752 2750 2753 } catch (Exception $e) { 2751 //error_log('DEBUG: Exception in get_pinecone_processed_content: ' . $e->getMessage()); 2752 } 2753 2754 // Merge cached data with Pinecone data 2755 $merged_data = $pinecone_data; 2756 2757 foreach ($cached_data as $post_id => $cache_item) { 2758 $cache_timestamp = $cache_item['timestamp'] ?? 0; 2759 $time_diff = current_time('timestamp') - $cache_timestamp; 2760 2761 if ($time_diff < 300) { // 5 minutes = 300 seconds 2762 $merged_data[$post_id] = $cache_item; 2763 } else { 2764 if (!isset($merged_data[$post_id])) { 2765 $merged_data[$post_id] = $cache_item; 2766 } 2767 } 2768 } 2769 2770 //error_log('DEBUG: Final merged data count: ' . count($merged_data)); 2771 //error_log('=== DEBUG: End mxchat_get_pinecone_processed_content ==='); 2772 2773 return $merged_data; 2774 } 2775 2754 // Log error but return fresh data only 2755 } 2756 2757 return $pinecone_data; 2758 } 2776 2759 public function mxchat_fetch_pinecone_vectors_by_ids($pinecone_options, $vector_ids) { 2777 2760 //error_log('=== DEBUG: Starting mxchat_fetch_pinecone_vectors_by_ids ==='); … … 2867 2850 } 2868 2851 2852 /** 2853 * Scan Pinecone for processed content 2854 */ 2869 2855 public function mxchat_scan_pinecone_for_processed_content($pinecone_options) { 2870 //error_log('=== DEBUG: Starting mxchat_scan_pinecone_for_processed_content ===');2871 2872 2856 $api_key = $pinecone_options['mxchat_pinecone_api_key'] ?? ''; 2873 2857 $host = $pinecone_options['mxchat_pinecone_host'] ?? ''; 2874 2858 2875 2859 if (empty($api_key) || empty($host)) { 2876 //error_log('DEBUG: Missing API credentials for scanning');2877 2860 return array(); 2878 2861 } … … 2885 2868 // Try 3 different random vectors to get better coverage 2886 2869 for ($i = 0; $i < 3; $i++) { 2887 //error_log('DEBUG: Scanning attempt ' . ($i + 1) . '/3');2888 2889 2870 $query_url = "https://{$host}/query"; 2890 2871 … … 2918 2899 2919 2900 if (is_wp_error($response)) { 2920 //error_log('DEBUG: Query attempt ' . ($i + 1) . ' WP error: ' . $response->get_error_message());2921 2901 continue; 2922 2902 } 2923 2903 2924 2904 $response_code = wp_remote_retrieve_response_code($response); 2925 //error_log('DEBUG: Query attempt ' . ($i + 1) . ' response code: ' . $response_code);2926 2905 2927 2906 if ($response_code !== 200) { 2928 $error_body = wp_remote_retrieve_body($response);2929 //error_log('DEBUG: Query attempt ' . ($i + 1) . ' failed with body: ' . substr($error_body, 0, 500));2930 2907 continue; 2931 2908 } … … 2935 2912 2936 2913 if (isset($data['matches'])) { 2937 //error_log('DEBUG: Query attempt ' . ($i + 1) . ' returned ' . count($data['matches']) . ' matches');2938 2914 foreach ($data['matches'] as $match) { 2939 2915 $match_id = $match['id'] ?? ''; … … 2943 2919 } 2944 2920 } 2945 } else { 2946 //error_log('DEBUG: Query attempt ' . ($i + 1) . ' - no matches key in response'); 2947 } 2948 } 2949 2950 //error_log('DEBUG: Total unique matches found: ' . count($all_matches)); 2921 } 2922 } 2951 2923 2952 2924 // Convert matches to processed data format 2953 2925 $processed_data = array(); 2954 $vector_ids_for_cache = array();2955 2926 2956 2927 foreach ($all_matches as $match) { … … 2979 2950 'timestamp' => $timestamp ?? current_time('timestamp') 2980 2951 ); 2981 2982 $vector_ids_for_cache[] = $match_id;2983 2952 } 2984 2953 } 2985 2954 } 2986 2955 2987 // Update the vector IDs cache for future use2988 if (!empty($vector_ids_for_cache)) {2989 update_option('mxchat_pinecone_vector_ids_cache', $vector_ids_for_cache);2990 //error_log('DEBUG: Updated vector IDs cache with ' . count($vector_ids_for_cache) . ' IDs');2991 }2992 2993 //error_log('DEBUG: Returning ' . count($processed_data) . ' processed items from scanning');2994 2956 return $processed_data; 2995 2957 2996 2958 } catch (Exception $e) { 2997 //error_log('DEBUG: Exception in scan_pinecone_for_processed_content: ' . $e->getMessage());2998 2959 return array(); 2999 2960 } 3000 2961 } 3001 3002 2962 /** 3003 2963 * UPDATED: Generate embeddings from input text for MXChat with bot support … … 3216 3176 */ 3217 3177 private function get_bot_options($bot_id = 'default') { 3218 error_log("MXCHAT DEBUG: get_bot_options called for bot: " . $bot_id);3178 //error_log("MXCHAT DEBUG: get_bot_options called for bot: " . $bot_id); 3219 3179 3220 3180 if ($bot_id === 'default' || !class_exists('MxChat_Multi_Bot_Manager')) { 3221 error_log("MXCHAT DEBUG: Using default options (no multi-bot or bot is 'default')");3181 //error_log("MXCHAT DEBUG: Using default options (no multi-bot or bot is 'default')"); 3222 3182 return array(); 3223 3183 } … … 3226 3186 3227 3187 if (!empty($bot_options)) { 3228 error_log("MXCHAT DEBUG: Got bot-specific options from filter");3188 //error_log("MXCHAT DEBUG: Got bot-specific options from filter"); 3229 3189 if (isset($bot_options['similarity_threshold'])) { 3230 error_log(" - similarity_threshold: " . $bot_options['similarity_threshold']);3190 //error_log(" - similarity_threshold: " . $bot_options['similarity_threshold']); 3231 3191 } 3232 3192 } … … 3241 3201 // Also add debugging to your get_bot_pinecone_config function 3242 3202 private function get_bot_pinecone_config($bot_id = 'default') { 3243 error_log("MXCHAT DEBUG: get_bot_pinecone_config called for bot: " . $bot_id);3203 //error_log("MXCHAT DEBUG: get_bot_pinecone_config called for bot: " . $bot_id); 3244 3204 3245 3205 // If default bot or multi-bot add-on not active, use default Pinecone config 3246 3206 if ($bot_id === 'default' || !class_exists('MxChat_Multi_Bot_Manager')) { 3247 error_log("MXCHAT DEBUG: Using default Pinecone config (no multi-bot or bot is 'default')");3207 //error_log("MXCHAT DEBUG: Using default Pinecone config (no multi-bot or bot is 'default')"); 3248 3208 $addon_options = get_option('mxchat_pinecone_addon_options', array()); 3249 3209 $config = array( … … 3253 3213 'namespace' => $addon_options['mxchat_pinecone_namespace'] ?? '' 3254 3214 ); 3255 error_log("MXCHAT DEBUG: Default config - use_pinecone: " . ($config['use_pinecone'] ? 'true' : 'false'));3215 //error_log("MXCHAT DEBUG: Default config - use_pinecone: " . ($config['use_pinecone'] ? 'true' : 'false')); 3256 3216 return $config; 3257 3217 } 3258 3218 3259 error_log("MXCHAT DEBUG: Calling filter 'mxchat_get_bot_pinecone_config' for bot: " . $bot_id);3219 //error_log("MXCHAT DEBUG: Calling filter 'mxchat_get_bot_pinecone_config' for bot: " . $bot_id); 3260 3220 3261 3221 // Hook for multi-bot add-on to provide bot-specific Pinecone config … … 3263 3223 3264 3224 if (!empty($bot_pinecone_config)) { 3265 error_log("MXCHAT DEBUG: Got bot-specific config from filter");3266 error_log(" - use_pinecone: " . (isset($bot_pinecone_config['use_pinecone']) ? ($bot_pinecone_config['use_pinecone'] ? 'true' : 'false') : 'not set'));3267 error_log(" - host: " . ($bot_pinecone_config['host'] ?? 'not set'));3268 error_log(" - namespace: " . ($bot_pinecone_config['namespace'] ?? 'not set'));3225 //error_log("MXCHAT DEBUG: Got bot-specific config from filter"); 3226 //error_log(" - use_pinecone: " . (isset($bot_pinecone_config['use_pinecone']) ? ($bot_pinecone_config['use_pinecone'] ? 'true' : 'false') : 'not set')); 3227 //error_log(" - host: " . ($bot_pinecone_config['host'] ?? 'not set')); 3228 //error_log(" - namespace: " . ($bot_pinecone_config['namespace'] ?? 'not set')); 3269 3229 } else { 3270 error_log("MXCHAT DEBUG: Filter returned empty config!");3230 //error_log("MXCHAT DEBUG: Filter returned empty config!"); 3271 3231 } 3272 3232 … … 4265 4225 4266 4226 if ($result['success']) { 4267 // Remove from ALL caches 4268 $pinecone_manager->mxchat_remove_from_pinecone_vector_cache($vector_id); 4269 $pinecone_manager->mxchat_remove_from_processed_content_caches($vector_id); 4270 4271 // CLEAR ALL RELEVANT CACHES 4272 delete_transient('mxchat_pinecone_recent_1k_cache'); 4273 delete_option('mxchat_pinecone_vector_ids_cache'); 4274 delete_option('mxchat_pinecone_processed_cache'); 4275 delete_option('mxchat_processed_content_cache'); 4276 4277 // Also force refresh for next page load 4278 $pinecone_manager->mxchat_refresh_after_new_content($pinecone_options); 4279 4227 // No cache clearing needed since we removed caching 4280 4228 set_transient('mxchat_admin_notice_success', 4281 4229 esc_html__('Entry deleted successfully from Pinecone.', 'mxchat'), … … 4292 4240 exit; 4293 4241 } 4294 4242 /** 4243 * Handle individual Pinecone content deletion via AJAX 4244 */ 4295 4245 public function ajax_mxchat_delete_pinecone_prompt() { 4296 4246 // Verify nonce and permissions … … 4332 4282 4333 4283 if ($result['success']) { 4334 // Clear bot-specific caches 4335 $pinecone_manager->mxchat_clear_bot_caches($bot_id); 4336 4284 // No cache clearing needed since we removed caching 4337 4285 wp_send_json_success(array( 4338 4286 'message' => 'Entry deleted successfully from Pinecone', … … 4346 4294 exit; 4347 4295 } 4296 4348 4297 /** 4349 4298 * NEW: Get hierarchical roles for dropdown … … 4411 4360 4412 4361 /** 4413 * Handle role restriction updates via AJAX 4414 */ 4415 /** 4416 * UPDATED: Handle role restriction updates for both WordPress and Pinecone via AJAX 4362 * Handle role restriction updates via AJAX 4363 * UPDATED: Removed cache clearing call since we removed caching 4417 4364 */ 4418 4365 public function ajax_mxchat_update_role_restriction() { … … 4462 4409 ); 4463 4410 4464 // Clear Pinecone cache to reflect changes 4465 delete_transient('mxchat_pinecone_recent_1k_cache'); 4411 // No cache clearing needed since we removed caching 4466 4412 4467 4413 } else { -
mxchat-basic/trunk/admin/class-pinecone-manager.php
r3366492 r3367268 29 29 */ 30 30 public function mxchat_fetch_pinecone_records($pinecone_options, $search_query = '', $page = 1, $per_page = 20, $bot_id = 'default') { 31 error_log('=== DEBUG: mxchat_fetch_pinecone_records ===');32 error_log('Bot ID: ' . $bot_id);33 error_log('Pinecone Host: ' . ($pinecone_options['mxchat_pinecone_host'] ?? 'NOT SET'));34 error_log('Pinecone Namespace: ' . ($pinecone_options['mxchat_pinecone_namespace'] ?? 'NOT SET'));35 error_log('Use Pinecone: ' . ($pinecone_options['mxchat_use_pinecone'] ?? 'NOT SET'));31 //error_log('=== DEBUG: mxchat_fetch_pinecone_records ==='); 32 //error_log('Bot ID: ' . $bot_id); 33 //error_log('Pinecone Host: ' . ($pinecone_options['mxchat_pinecone_host'] ?? 'NOT SET')); 34 //error_log('Pinecone Namespace: ' . ($pinecone_options['mxchat_pinecone_namespace'] ?? 'NOT SET')); 35 //error_log('Use Pinecone: ' . ($pinecone_options['mxchat_use_pinecone'] ?? 'NOT SET')); 36 36 37 37 $api_key = $pinecone_options['mxchat_pinecone_api_key'] ?? ''; … … 40 40 41 41 if (empty($api_key) || empty($host)) { 42 //error_log('DEBUG: Missing required Pinecone parameters');43 42 return array('data' => array(), 'total' => 0, 'total_in_database' => 0, 'showing_recent_only' => false); 44 43 } … … 48 47 $total_in_database = $this->mxchat_get_pinecone_total_count($pinecone_options, $bot_id); 49 48 50 // Check cache first for consistency (bot-specific cache) 51 $cache_key = 'mxchat_pinecone_recent_1k_cache_' . $bot_id; 52 $all_records = get_transient($cache_key); 53 54 if ($all_records === false) { 55 // Cache miss - get fresh data (bot-specific) 56 $all_records = $this->mxchat_get_recent_1k_entries($pinecone_options, $bot_id); 57 } 49 // Always get fresh data - no caching 50 $all_records = $this->mxchat_get_recent_1k_entries($pinecone_options, $bot_id); 58 51 59 52 // Filter by search query if provided … … 70 63 $offset = ($page - 1) * $per_page; 71 64 $paged_records = array_slice($all_records, $offset, $per_page); 72 73 //error_log('DEBUG: Returning ' . count($paged_records) . ' records for bot ' . $bot_id);74 65 75 66 return array( … … 81 72 82 73 } catch (Exception $e) { 83 //error_log('DEBUG: Exception: ' . $e->getMessage());84 74 return array('data' => array(), 'total' => 0, 'total_in_database' => 0, 'showing_recent_only' => false); 85 75 } 86 76 } 87 88 77 /** 89 78 * Get embedding dimensions based on the selected model … … 143 132 144 133 134 /** 135 * Get recent 1K entries from Pinecone 136 */ 145 137 private function mxchat_get_recent_1k_entries($pinecone_options, $bot_id = 'default') { 146 138 global $wpdb; 147 error_log('=== DEBUG: mxchat_get_recent_1k_entries started ===');148 error_log('DEBUG: Bot ID: ' . $bot_id);139 //error_log('=== DEBUG: mxchat_get_recent_1k_entries started ==='); 140 //error_log('DEBUG: Bot ID: ' . $bot_id); 149 141 150 142 $api_key = $pinecone_options['mxchat_pinecone_api_key'] ?? ''; … … 164 156 165 157 foreach ($fixed_vectors as $vector_index => $query_vector) { 166 error_log('DEBUG: Using fixed query vector ' . ($vector_index + 1) . '/' . count($fixed_vectors));158 //error_log('DEBUG: Using fixed query vector ' . ($vector_index + 1) . '/' . count($fixed_vectors)); 167 159 168 160 $query_data = array( … … 177 169 $query_data['namespace'] = $namespace; 178 170 } 179 180 // REMOVE THE BOT_ID FILTER - Each bot has its own Pinecone index181 // No need to filter by bot_id within the index182 171 183 172 $response = wp_remote_post($query_url, array( … … 199 188 if (!empty($match_id) && !isset($seen_ids[$match_id])) { 200 189 $metadata = $match['metadata'] ?? array(); 201 202 // Remove the bot_id checking since each bot has its own index203 190 204 191 // Get created_at timestamp … … 217 204 'source_url' => $metadata['source_url'] ?? '', 218 205 'role_restriction' => $metadata['role_restriction'] ?? 'public', 219 'bot_id' => $bot_id, // Just set it to current bot for display206 'bot_id' => $bot_id, 220 207 'created_at' => $created_at, 221 208 'data_source' => 'pinecone' … … 254 241 } 255 242 256 error_log('DEBUG: Found ' . count($all_records) . ' total unique records, returning top ' . count($recent_1k)); 257 258 // Cache the results 259 $cache_key = 'mxchat_pinecone_recent_1k_cache_' . $bot_id; 260 set_transient($cache_key, $recent_1k, 60); 243 //error_log('DEBUG: Found ' . count($all_records) . ' total unique records, returning top ' . count($recent_1k)); 261 244 262 245 return $recent_1k; 263 246 264 247 } catch (Exception $e) { 265 error_log('DEBUG: Exception in get_recent_1k_entries: ' . $e->getMessage());248 //error_log('DEBUG: Exception in get_recent_1k_entries: ' . $e->getMessage()); 266 249 return array(); 267 250 } 268 251 } 269 270 252 /** 271 253 * Generate fixed query vectors for consistent results … … 323 305 324 306 /** 325 * Scan Pinecone for processed content (MISSING FUNCTION - ADD THIS) 326 */ 327 public function mxchat_scan_pinecone_for_processed_content($pinecone_options) { 328 //error_log('=== DEBUG: Starting mxchat_scan_pinecone_for_processed_content ==='); 329 330 $api_key = $pinecone_options['mxchat_pinecone_api_key'] ?? ''; 331 $host = $pinecone_options['mxchat_pinecone_host'] ?? ''; 332 333 if (empty($api_key) || empty($host)) { 334 //error_log('DEBUG: Missing API credentials for scanning'); 335 return array(); 336 } 337 338 try { 339 // Use multiple random vectors to get better coverage 340 $all_matches = array(); 341 $seen_ids = array(); 342 343 // Try 3 different random vectors to get better coverage 344 for ($i = 0; $i < 3; $i++) { 345 //error_log('DEBUG: Scanning attempt ' . ($i + 1) . '/3'); 346 347 $query_url = "https://{$host}/query"; 348 349 // Generate random vector with CORRECT dimensions 350 $random_vector = $this->mxchat_generate_random_vector(); 351 352 $query_data = array( 353 'includeMetadata' => true, 354 'includeValues' => false, 355 'topK' => 10000, 356 'vector' => $random_vector 357 ); 358 359 $response = wp_remote_post($query_url, array( 360 'headers' => array( 361 'Api-Key' => $api_key, 362 'Content-Type' => 'application/json' 363 ), 364 'body' => json_encode($query_data), 365 'timeout' => 30 366 )); 367 368 if (is_wp_error($response)) { 369 //error_log('DEBUG: Query attempt ' . ($i + 1) . ' WP error: ' . $response->get_error_message()); 370 continue; 307 * Scan Pinecone for processed content 308 */ 309 public function mxchat_scan_pinecone_for_processed_content($pinecone_options) { 310 $api_key = $pinecone_options['mxchat_pinecone_api_key'] ?? ''; 311 $host = $pinecone_options['mxchat_pinecone_host'] ?? ''; 312 313 if (empty($api_key) || empty($host)) { 314 return array(); 315 } 316 317 try { 318 // Use multiple random vectors to get better coverage 319 $all_matches = array(); 320 $seen_ids = array(); 321 322 // Try 3 different random vectors to get better coverage 323 for ($i = 0; $i < 3; $i++) { 324 $query_url = "https://{$host}/query"; 325 326 // Generate random vector with CORRECT dimensions 327 $random_vector = $this->mxchat_generate_random_vector(); 328 329 $query_data = array( 330 'includeMetadata' => true, 331 'includeValues' => false, 332 'topK' => 10000, 333 'vector' => $random_vector 334 ); 335 336 $response = wp_remote_post($query_url, array( 337 'headers' => array( 338 'Api-Key' => $api_key, 339 'Content-Type' => 'application/json' 340 ), 341 'body' => json_encode($query_data), 342 'timeout' => 30 343 )); 344 345 if (is_wp_error($response)) { 346 continue; 347 } 348 349 $response_code = wp_remote_retrieve_response_code($response); 350 351 if ($response_code !== 200) { 352 continue; 353 } 354 355 $body = wp_remote_retrieve_body($response); 356 $data = json_decode($body, true); 357 358 if (isset($data['matches'])) { 359 foreach ($data['matches'] as $match) { 360 $match_id = $match['id'] ?? ''; 361 if (!empty($match_id) && !isset($seen_ids[$match_id])) { 362 $all_matches[] = $match; 363 $seen_ids[$match_id] = true; 364 } 371 365 } 372 373 $response_code = wp_remote_retrieve_response_code($response); 374 //error_log('DEBUG: Query attempt ' . ($i + 1) . ' response code: ' . $response_code); 375 376 if ($response_code !== 200) { 377 $error_body = wp_remote_retrieve_body($response); 378 //error_log('DEBUG: Query attempt ' . ($i + 1) . ' failed with body: ' . substr($error_body, 0, 500)); 379 continue; 380 } 381 382 $body = wp_remote_retrieve_body($response); 383 $data = json_decode($body, true); 384 385 if (isset($data['matches'])) { 386 //error_log('DEBUG: Query attempt ' . ($i + 1) . ' returned ' . count($data['matches']) . ' matches'); 387 foreach ($data['matches'] as $match) { 388 $match_id = $match['id'] ?? ''; 389 if (!empty($match_id) && !isset($seen_ids[$match_id])) { 390 $all_matches[] = $match; 391 $seen_ids[$match_id] = true; 366 } 367 } 368 369 // Convert matches to processed data format 370 $processed_data = array(); 371 372 foreach ($all_matches as $match) { 373 $metadata = $match['metadata'] ?? array(); 374 $source_url = $metadata['source_url'] ?? ''; 375 $match_id = $match['id'] ?? ''; 376 377 if (!empty($source_url) && !empty($match_id)) { 378 $post_id = url_to_postid($source_url); 379 if ($post_id) { 380 $created_at = $metadata['created_at'] ?? ''; 381 $processed_date = 'Recently'; 382 383 if (!empty($created_at)) { 384 $timestamp = is_numeric($created_at) ? $created_at : strtotime($created_at); 385 if ($timestamp) { 386 $processed_date = human_time_diff($timestamp, current_time('timestamp')) . ' ago'; 392 387 } 393 388 } 394 } else { 395 //error_log('DEBUG: Query attempt ' . ($i + 1) . ' - no matches key in response'); 389 390 $processed_data[$post_id] = array( 391 'db_id' => $match_id, 392 'processed_date' => $processed_date, 393 'url' => $source_url, 394 'source' => 'pinecone', 395 'timestamp' => $timestamp ?? current_time('timestamp') 396 ); 396 397 } 397 398 } 398 399 //error_log('DEBUG: Total unique matches found: ' . count($all_matches)); 400 401 // Convert matches to processed data format 402 $processed_data = array(); 403 $vector_ids_for_cache = array(); 404 405 foreach ($all_matches as $match) { 406 $metadata = $match['metadata'] ?? array(); 407 $source_url = $metadata['source_url'] ?? ''; 408 $match_id = $match['id'] ?? ''; 409 410 if (!empty($source_url) && !empty($match_id)) { 411 $post_id = url_to_postid($source_url); 412 if ($post_id) { 413 $created_at = $metadata['created_at'] ?? ''; 414 $processed_date = 'Recently'; 415 416 if (!empty($created_at)) { 417 $timestamp = is_numeric($created_at) ? $created_at : strtotime($created_at); 418 if ($timestamp) { 419 $processed_date = human_time_diff($timestamp, current_time('timestamp')) . ' ago'; 420 } 421 } 422 423 $processed_data[$post_id] = array( 424 'db_id' => $match_id, 425 'processed_date' => $processed_date, 426 'url' => $source_url, 427 'source' => 'pinecone', 428 'timestamp' => $timestamp ?? current_time('timestamp') 429 ); 430 431 $vector_ids_for_cache[] = $match_id; 432 } 433 } 434 } 435 436 // Update the vector IDs cache for future use 437 if (!empty($vector_ids_for_cache)) { 438 update_option('mxchat_pinecone_vector_ids_cache', $vector_ids_for_cache); 439 //error_log('DEBUG: Updated vector IDs cache with ' . count($vector_ids_for_cache) . ' IDs'); 440 } 441 442 //error_log('DEBUG: Returning ' . count($processed_data) . ' processed items from scanning'); 443 return $processed_data; 444 445 } catch (Exception $e) { 446 //error_log('DEBUG: Exception in scan_pinecone_for_processed_content: ' . $e->getMessage()); 447 return array(); 448 } 449 } 450 399 } 400 401 return $processed_data; 402 403 } catch (Exception $e) { 404 return array(); 405 } 406 } 407 408 /** 409 * Get total count from Pinecone stats API 410 * UPDATED: Removed cache fallback reference 411 */ 451 412 private function mxchat_get_pinecone_total_count($pinecone_options, $bot_id = 'default') { 452 413 $api_key = $pinecone_options['mxchat_pinecone_api_key'] ?? ''; … … 467 428 $request_data['namespace'] = $namespace; 468 429 } 469 470 // REMOVE THE BOT_ID FILTER - Each bot has its own index471 430 472 431 $response = wp_remote_post($stats_url, array( … … 485 444 $total_count = $stats_data['totalVectorCount'] ?? 0; 486 445 if ($total_count > 0) { 487 error_log('DEBUG: Got total count from stats API: ' . $total_count);446 //error_log('DEBUG: Got total count from stats API: ' . $total_count); 488 447 return intval($total_count); 489 448 } 490 449 } 491 450 492 // Fallback: estimate from previous scans 493 $cached_vector_ids = get_option('mxchat_pinecone_vector_ids_cache_' . $bot_id, array()); 494 if (!empty($cached_vector_ids)) { 495 $estimated_count = count($cached_vector_ids); 496 return intval($estimated_count); 497 } 451 // If stats API fails, return 0 instead of using cache 452 return 0; 498 453 499 454 } catch (Exception $e) { 500 error_log('DEBUG: Exception getting total count: ' . $e->getMessage()); 501 } 502 503 return 0; 504 } 505 506 /** 507 * Clear all caches for a specific bot (and general caches) 508 */ 509 public function mxchat_clear_bot_caches($bot_id = 'default') { 510 //error_log('DEBUG: Clearing all caches for bot: ' . $bot_id); 511 512 // Clear bot-specific caches 513 delete_transient('mxchat_pinecone_recent_1k_cache_' . $bot_id); 514 delete_transient('mxchat_pinecone_recent_1k_' . $bot_id); 515 delete_transient('mxchat_pinecone_total_count_' . $bot_id); 516 delete_option('mxchat_pinecone_vector_ids_cache_' . $bot_id); 517 delete_option('mxchat_pinecone_processed_cache_' . $bot_id); 518 delete_option('mxchat_processed_content_cache_' . $bot_id); 519 520 // Also clear general caches for backward compatibility 521 delete_transient('mxchat_pinecone_recent_1k_cache'); 522 delete_transient('mxchat_pinecone_recent_1k'); 523 delete_transient('mxchat_pinecone_total_count'); 524 delete_option('mxchat_pinecone_vector_ids_cache'); 525 delete_option('mxchat_pinecone_processed_cache'); 526 delete_option('mxchat_processed_content_cache'); 527 528 //error_log('DEBUG: All caches cleared for bot: ' . $bot_id); 529 530 return true; 531 } 532 533 /** 534 * Clear caches for all bots 535 */ 536 public function mxchat_clear_all_bot_caches() { 537 // Clear default/general caches 538 $this->mxchat_clear_bot_caches('default'); 539 540 // If multi-bot addon is active, clear caches for all bots 541 if (class_exists('MxChat_Multi_Bot_Manager')) { 542 $multi_bot_manager = MxChat_Multi_Bot_Core_Manager::get_instance(); 543 $available_bots = $multi_bot_manager->get_available_bots(); 544 545 foreach ($available_bots as $bot_id => $bot_name) { 546 if ($bot_id !== 'default') { 547 $this->mxchat_clear_bot_caches($bot_id); 548 } 549 } 550 } 551 552 return true; 553 } 554 555 /** 556 * Call this after adding new content to refresh the view for specific bot 557 */ 558 public function mxchat_refresh_after_new_content($pinecone_options, $bot_id = 'default') { 559 //error_log('DEBUG: Refreshing after new content added for bot: ' . $bot_id); 560 561 // Use the new comprehensive cache clearing method 562 $this->mxchat_clear_bot_caches($bot_id); 563 564 // Force fresh fetch on next page load 565 return true; 455 //error_log('DEBUG: Exception getting total count: ' . $e->getMessage()); 456 return 0; 457 } 566 458 } 567 459 … … 570 462 */ 571 463 public function mxchat_get_bot_pinecone_options($bot_id = 'default') { 572 error_log('DEBUG: Getting Pinecone options for bot: ' . $bot_id);464 //error_log('DEBUG: Getting Pinecone options for bot: ' . $bot_id); 573 465 574 466 // If default bot or multi-bot add-on not active, use default Pinecone config 575 467 if ($bot_id === 'default' || !class_exists('MxChat_Multi_Bot_Manager')) { 576 468 $addon_options = get_option('mxchat_pinecone_addon_options', array()); 577 error_log('DEBUG: Using default Pinecone options');469 //error_log('DEBUG: Using default Pinecone options'); 578 470 return $addon_options; 579 471 } … … 582 474 $bot_config = apply_filters('mxchat_get_bot_pinecone_config', array(), $bot_id); 583 475 584 error_log('DEBUG: Bot config from filter: ' . print_r($bot_config, true));476 //error_log('DEBUG: Bot config from filter: ' . print_r($bot_config, true)); 585 477 586 478 // Check if we got valid bot-specific config … … 596 488 ); 597 489 598 error_log('DEBUG: Returning bot-specific Pinecone options for bot: ' . $bot_id);490 //error_log('DEBUG: Returning bot-specific Pinecone options for bot: ' . $bot_id); 599 491 return $pinecone_options; 600 492 } 601 493 602 494 // Fallback to default options if bot-specific config is invalid 603 error_log('DEBUG: Bot-specific config invalid, falling back to default');495 //error_log('DEBUG: Bot-specific config invalid, falling back to default'); 604 496 return get_option('mxchat_pinecone_addon_options', array()); 605 497 } … … 610 502 */ 611 503 private function get_bot_pinecone_config($bot_id = 'default') { 612 error_log("MXCHAT DEBUG: get_bot_pinecone_config called for bot: " . $bot_id);504 //error_log("MXCHAT DEBUG: get_bot_pinecone_config called for bot: " . $bot_id); 613 505 614 506 // If default bot or multi-bot add-on not active, use default Pinecone config 615 507 if ($bot_id === 'default' || !class_exists('MxChat_Multi_Bot_Manager')) { 616 error_log("MXCHAT DEBUG: Using default Pinecone config (no multi-bot or bot is 'default')");508 //error_log("MXCHAT DEBUG: Using default Pinecone config (no multi-bot or bot is 'default')"); 617 509 $addon_options = get_option('mxchat_pinecone_addon_options', array()); 618 510 $config = array( … … 622 514 'namespace' => $addon_options['mxchat_pinecone_namespace'] ?? '' 623 515 ); 624 error_log("MXCHAT DEBUG: Default config - use_pinecone: " . ($config['use_pinecone'] ? 'true' : 'false'));516 //error_log("MXCHAT DEBUG: Default config - use_pinecone: " . ($config['use_pinecone'] ? 'true' : 'false')); 625 517 return $config; 626 518 } 627 519 628 error_log("MXCHAT DEBUG: Calling filter 'mxchat_get_bot_pinecone_config' for bot: " . $bot_id);520 //error_log("MXCHAT DEBUG: Calling filter 'mxchat_get_bot_pinecone_config' for bot: " . $bot_id); 629 521 630 522 // Hook for multi-bot add-on to provide bot-specific Pinecone config … … 632 524 633 525 if (!empty($bot_pinecone_config)) { 634 error_log("MXCHAT DEBUG: Got bot-specific config from filter");635 error_log(" - use_pinecone: " . (isset($bot_pinecone_config['use_pinecone']) ? ($bot_pinecone_config['use_pinecone'] ? 'true' : 'false') : 'not set'));636 error_log(" - host: " . ($bot_pinecone_config['host'] ?? 'not set'));637 error_log(" - namespace: " . ($bot_pinecone_config['namespace'] ?? 'not set'));526 //error_log("MXCHAT DEBUG: Got bot-specific config from filter"); 527 //error_log(" - use_pinecone: " . (isset($bot_pinecone_config['use_pinecone']) ? ($bot_pinecone_config['use_pinecone'] ? 'true' : 'false') : 'not set')); 528 //error_log(" - host: " . ($bot_pinecone_config['host'] ?? 'not set')); 529 //error_log(" - namespace: " . ($bot_pinecone_config['namespace'] ?? 'not set')); 638 530 } else { 639 error_log("MXCHAT DEBUG: Filter returned empty config!");531 //error_log("MXCHAT DEBUG: Filter returned empty config!"); 640 532 } 641 533 642 534 return is_array($bot_pinecone_config) ? $bot_pinecone_config : array(); 643 535 } 536 537 644 538 /** 645 539 * Fetches vectors from Pinecone using provided IDs (for content selection feature) 646 540 */ 647 541 public function fetch_pinecone_vectors_by_ids($pinecone_options, $vector_ids) { 648 //error_log('=== DEBUG: fetch_pinecone_vectors_by_ids started (content selection method) ===');649 650 542 $api_key = $pinecone_options['mxchat_pinecone_api_key'] ?? ''; 651 543 $host = $pinecone_options['mxchat_pinecone_host'] ?? ''; 652 544 653 //error_log('DEBUG: API key present: ' . (!empty($api_key) ? 'YES' : 'NO'));654 //error_log('DEBUG: Host: ' . $host);655 //error_log('DEBUG: Vector IDs count: ' . count($vector_ids));656 657 545 if (empty($api_key) || empty($host) || empty($vector_ids)) { 658 //error_log('DEBUG: Missing parameters for fetch by IDs (content selection)');659 546 return array(); 660 547 } … … 662 549 try { 663 550 $fetch_url = "https://{$host}/vectors/fetch"; 664 //error_log('DEBUG: Fetch URL: ' . $fetch_url);665 551 666 552 // Pinecone fetch API allows fetching specific vectors by ID … … 679 565 680 566 if (is_wp_error($response)) { 681 //error_log('DEBUG: Fetch by IDs WP error (content selection): ' . $response->get_error_message());682 567 return array(); 683 568 } 684 569 685 570 $response_code = wp_remote_retrieve_response_code($response); 686 //error_log('DEBUG: Fetch response code (content selection): ' . $response_code);687 571 688 572 if ($response_code !== 200) { 689 $error_body = wp_remote_retrieve_body($response);690 //error_log('DEBUG: Fetch failed with body (content selection): ' . $error_body);691 573 return array(); 692 574 } … … 696 578 697 579 if (!isset($data['vectors'])) { 698 //error_log('DEBUG: No vectors key in response (content selection)');699 580 return array(); 700 581 } … … 730 611 } 731 612 732 //error_log('DEBUG: Processed ' . count($processed_data) . ' records (content selection method)');733 //error_log('=== DEBUG: fetch_pinecone_vectors_by_ids completed (content selection) ===');734 735 613 return $processed_data; 736 614 737 615 } catch (Exception $e) { 738 //error_log('DEBUG: Exception in fetch_pinecone_vectors_by_ids (content selection): ' . $e->getMessage());739 616 return array(); 740 617 } 741 618 } 742 743 744 619 // ======================================== 745 620 // PINECONE DELETE OPERATIONS 746 621 // ======================================== 747 622 623 /** 624 * Delete all vectors from Pinecone 625 */ 748 626 public function mxchat_delete_all_from_pinecone($pinecone_options) { 749 627 $api_key = $pinecone_options['mxchat_pinecone_api_key'] ?? ''; … … 758 636 759 637 try { 760 // First, get all vector IDs 638 // First, get all vector IDs by scanning Pinecone directly 761 639 $all_vector_ids = array(); 762 640 763 // Try to get from cache first 764 $cached_vector_ids = get_option('mxchat_pinecone_vector_ids_cache', array()); 765 if (!empty($cached_vector_ids)) { 766 $all_vector_ids = $cached_vector_ids; 767 } else { 768 // Use the correct method name that exists in your class 769 $records = $this->mxchat_get_recent_1k_entries($pinecone_options); 770 foreach ($records as $record) { 771 if (!empty($record->id)) { 772 $all_vector_ids[] = $record->id; 773 } 641 // Get fresh data from Pinecone 642 $records = $this->mxchat_get_recent_1k_entries($pinecone_options); 643 foreach ($records as $record) { 644 if (!empty($record->id)) { 645 $all_vector_ids[] = $record->id; 774 646 } 775 647 } … … 794 666 } else { 795 667 $failed_batches++; 796 //error_log('Failed to delete Pinecone batch: ' . $result['message']); 797 } 798 } 799 800 // CLEAR ALL RELEVANT CACHES - EXACTLY like your single delete 801 delete_transient('mxchat_pinecone_recent_1k_cache'); 802 delete_option('mxchat_pinecone_vector_ids_cache'); 803 delete_option('mxchat_pinecone_processed_cache'); 804 delete_option('mxchat_processed_content_cache'); 805 806 // Also force refresh for next page load - EXACTLY like your single delete 807 $this->mxchat_refresh_after_new_content($pinecone_options); 668 } 669 } 808 670 809 671 if ($failed_batches > 0) { … … 820 682 821 683 } catch (Exception $e) { 822 //error_log('Pinecone delete all exception: ' . $e->getMessage());823 684 return array( 824 685 'success' => false, … … 827 688 } 828 689 } 829 830 690 831 691 /** … … 889 749 */ 890 750 public function mxchat_delete_from_pinecone_by_vector_id($vector_id, $api_key, $host, $namespace = '') { 891 error_log('=== PINECONE DELETE OPERATION ===');892 error_log('Vector ID: ' . $vector_id);893 error_log('Host: ' . $host);894 error_log('API Key: ' . (empty($api_key) ? 'EMPTY' : 'SET'));751 //error_log('=== PINECONE DELETE OPERATION ==='); 752 //error_log('Vector ID: ' . $vector_id); 753 //error_log('Host: ' . $host); 754 //error_log('API Key: ' . (empty($api_key) ? 'EMPTY' : 'SET')); 895 755 896 756 // First, let's verify the vector exists before trying to delete … … 921 781 $fetch_data = json_decode($fetch_body, true); 922 782 923 error_log('DEBUG: Fetch response: ' . print_r($fetch_data, true));783 //error_log('DEBUG: Fetch response: ' . print_r($fetch_data, true)); 924 784 925 785 if (isset($fetch_data['vectors']) && isset($fetch_data['vectors'][$vector_id])) { 926 error_log('DEBUG: Vector EXISTS in this index before deletion');786 //error_log('DEBUG: Vector EXISTS in this index before deletion'); 927 787 } else { 928 error_log('WARNING: Vector NOT FOUND in this index! It may be in a different bot\'s index');788 //error_log('WARNING: Vector NOT FOUND in this index! It may be in a different bot\'s index'); 929 789 // You might want to return an error here 930 790 } 931 791 } else { 932 error_log('DEBUG: Could not fetch vector to verify existence');792 //error_log('DEBUG: Could not fetch vector to verify existence'); 933 793 } 934 794 … … 946 806 } 947 807 948 error_log('DEBUG: Delete request body: ' . json_encode($request_body));949 error_log('DEBUG: Delete endpoint: ' . $api_endpoint);808 //error_log('DEBUG: Delete request body: ' . json_encode($request_body)); 809 //error_log('DEBUG: Delete endpoint: ' . $api_endpoint); 950 810 951 811 // Make the deletion request … … 962 822 // Handle WordPress HTTP API errors 963 823 if (is_wp_error($response)) { 964 error_log('DEBUG: WP Error: ' . $response->get_error_message());824 //error_log('DEBUG: WP Error: ' . $response->get_error_message()); 965 825 return array( 966 826 'success' => false, … … 973 833 $response_body = wp_remote_retrieve_body($response); 974 834 975 error_log('DEBUG: Delete response code: ' . $response_code);976 error_log('DEBUG: Delete response body: ' . $response_body);835 //error_log('DEBUG: Delete response code: ' . $response_code); 836 //error_log('DEBUG: Delete response body: ' . $response_body); 977 837 978 838 // Pinecone returns 200 for successful deletion (even if vector didn't exist) 979 839 if ($response_code !== 200) { 980 error_log('DEBUG: Non-200 response from Pinecone');840 //error_log('DEBUG: Non-200 response from Pinecone'); 981 841 return array( 982 842 'success' => false, … … 1005 865 1006 866 if (isset($verify_data['vectors']) && isset($verify_data['vectors'][$vector_id])) { 1007 error_log('ERROR: Vector STILL EXISTS after deletion attempt!');867 //error_log('ERROR: Vector STILL EXISTS after deletion attempt!'); 1008 868 return array( 1009 869 'success' => false, … … 1011 871 ); 1012 872 } else { 1013 error_log('SUCCESS: Vector confirmed deleted (or never existed)');1014 } 1015 } 1016 1017 error_log('=== END PINECONE DELETE OPERATION ===');873 //error_log('SUCCESS: Vector confirmed deleted (or never existed)'); 874 } 875 } 876 877 //error_log('=== END PINECONE DELETE OPERATION ==='); 1018 878 1019 879 return array( … … 1151 1011 1152 1012 1153 // ======================================== 1154 // VECTOR CACHE MANAGEMENT 1155 // ======================================== 1156 1157 1158 /** 1159 * Removes vector ID from cache array option 1160 */ 1161 public function mxchat_remove_from_pinecone_vector_cache($vector_id) { 1162 $cached_ids = get_option('mxchat_pinecone_vector_ids_cache', array()); 1163 $key = array_search($vector_id, $cached_ids); 1164 if ($key !== false) { 1165 unset($cached_ids[$key]); 1166 update_option('mxchat_pinecone_vector_ids_cache', array_values($cached_ids)); 1167 } 1168 } 1169 1170 /** 1171 * Removes vector ID from processed content caches 1172 */ 1173 public function mxchat_remove_from_processed_content_caches($vector_id) { 1174 // Get all caches 1175 $pinecone_cache = get_option('mxchat_pinecone_processed_cache', array()); 1176 $processed_cache = get_option('mxchat_processed_content_cache', array()); 1177 1178 // We need to find the post ID that corresponds to this vector ID 1179 // Vector ID is typically md5 of the source URL 1180 $post_id_to_remove = null; 1181 1182 // Search through caches to find matching post 1183 foreach ($pinecone_cache as $post_id => $cache_data) { 1184 if (isset($cache_data['db_id']) && $cache_data['db_id'] === $vector_id) { 1185 $post_id_to_remove = $post_id; 1186 break; 1187 } 1188 } 1189 1190 // Also check the processed cache 1191 if (!$post_id_to_remove) { 1192 foreach ($processed_cache as $post_id => $cache_data) { 1193 if (isset($cache_data['db_id']) && $cache_data['db_id'] === $vector_id) { 1194 $post_id_to_remove = $post_id; 1195 break; 1196 } 1197 } 1198 } 1199 1200 // If we found the post ID, remove it from both caches 1201 if ($post_id_to_remove) { 1202 unset($pinecone_cache[$post_id_to_remove]); 1203 unset($processed_cache[$post_id_to_remove]); 1204 1205 update_option('mxchat_pinecone_processed_cache', $pinecone_cache); 1206 update_option('mxchat_processed_content_cache', $processed_cache); 1207 1208 //error_log('Removed post ID ' . $post_id_to_remove . ' from processed content caches'); 1209 } else { 1210 // If we can't find by vector ID, we might need to reconstruct the URL 1211 // and find the post ID that way 1212 //error_log('Could not find post ID for vector ID: ' . $vector_id); 1213 } 1214 } 1215 1216 1217 /** 1218 * Retrieves and caches Pinecone API processed content 1219 */ 1220 public function mxchat_get_pinecone_processed_content($pinecone_options) { 1221 // First check local cache for immediate updates 1222 $cached_data = get_option('mxchat_pinecone_processed_cache', array()); 1223 1224 $api_key = $pinecone_options['mxchat_pinecone_api_key'] ?? ''; 1225 $host = $pinecone_options['mxchat_pinecone_host'] ?? ''; 1226 1227 if (empty($api_key) || empty($host)) { 1228 // Return only cached data if API credentials are missing 1229 return $cached_data; 1230 } 1231 1232 $pinecone_data = array(); 1233 1234 try { 1235 // Method 1: Try to get vectors using cached vector IDs first 1236 $cached_vector_ids = get_option('mxchat_pinecone_vector_ids_cache', array()); 1237 1238 if (!empty($cached_vector_ids)) { 1239 $pinecone_data = $this->fetch_pinecone_vectors_by_ids($pinecone_options, $cached_vector_ids); 1240 } 1241 1242 // Method 2: If no cached IDs or fetch failed, use scanning approach 1243 if (empty($pinecone_data)) { 1244 $pinecone_data = $this->mxchat_scan_pinecone_for_processed_content($pinecone_options); 1245 } 1246 1247 // Method 3: Final fallback - try stats endpoint (if available) 1248 if (empty($pinecone_data)) { 1249 $stats_url = "https://{$host}/describe_index_stats"; 1250 1251 $response = wp_remote_post($stats_url, array( 1252 'headers' => array( 1253 'Api-Key' => $api_key, 1254 'Content-Type' => 'application/json' 1255 ), 1256 'body' => json_encode(array()), 1257 'timeout' => 30 1258 )); 1259 1260 if (!is_wp_error($response) && wp_remote_retrieve_response_code($response) === 200) { 1261 $body = wp_remote_retrieve_body($response); 1262 $stats_data = json_decode($body, true); 1263 1264 // Log stats for debugging but don't rely on them for vector listing 1265 //error_log('Pinecone index stats: ' . print_r($stats_data, true)); 1266 } 1267 } 1268 1269 } catch (Exception $e) { 1270 //error_log('Pinecone processed content exception: ' . $e->getMessage()); 1271 } 1272 1273 // Merge cached data with Pinecone data 1274 // Cache takes priority for recent updates (within last 5 minutes) 1275 $merged_data = $pinecone_data; 1276 1277 foreach ($cached_data as $post_id => $cache_item) { 1278 $cache_timestamp = $cache_item['timestamp'] ?? 0; 1279 $time_diff = current_time('timestamp') - $cache_timestamp; 1280 1281 // If cache item is recent (less than 5 minutes), prioritize it 1282 if ($time_diff < 300) { // 5 minutes = 300 seconds 1283 $merged_data[$post_id] = $cache_item; 1284 } else { 1285 // If not in Pinecone data and cache is old, keep cache but mark as potentially stale 1286 if (!isset($merged_data[$post_id])) { 1287 $merged_data[$post_id] = $cache_item; 1288 } 1289 } 1290 } 1291 1292 return $merged_data; 1293 } 1294 1295 1013 1014 /** 1015 * Retrieves processed content from Pinecone API 1016 */ 1017 public function mxchat_get_pinecone_processed_content($pinecone_options) { 1018 $api_key = $pinecone_options['mxchat_pinecone_api_key'] ?? ''; 1019 $host = $pinecone_options['mxchat_pinecone_host'] ?? ''; 1020 1021 if (empty($api_key) || empty($host)) { 1022 return array(); 1023 } 1024 1025 $pinecone_data = array(); 1026 1027 try { 1028 // Always get fresh data from Pinecone 1029 $pinecone_data = $this->mxchat_scan_pinecone_for_processed_content($pinecone_options); 1030 1031 // Method 2: Final fallback - try stats endpoint (if available) 1032 if (empty($pinecone_data)) { 1033 $stats_url = "https://{$host}/describe_index_stats"; 1034 1035 $response = wp_remote_post($stats_url, array( 1036 'headers' => array( 1037 'Api-Key' => $api_key, 1038 'Content-Type' => 'application/json' 1039 ), 1040 'body' => json_encode(array()), 1041 'timeout' => 30 1042 )); 1043 1044 if (!is_wp_error($response) && wp_remote_retrieve_response_code($response) === 200) { 1045 $body = wp_remote_retrieve_body($response); 1046 $stats_data = json_decode($body, true); 1047 } 1048 } 1049 1050 } catch (Exception $e) { 1051 // Log error but don't return cached data 1052 } 1053 1054 return $pinecone_data; 1055 } 1296 1056 // ======================================== 1297 1057 // HELPER METHODS -
mxchat-basic/trunk/includes/class-mxchat-addons.php
r3366492 r3367268 191 191 */ 192 192 public function enqueue_styles() { 193 $plugin_version = '2.4. 3';193 $plugin_version = '2.4.4'; 194 194 195 195 wp_enqueue_style( -
mxchat-basic/trunk/includes/class-mxchat-admin.php
r3366492 r3367268 592 592 <div class="mxchat-pro-notification"> 593 593 <div class="mxchat-pro-content"> 594 <h3>🚀 Limited Lifetime Offer: Save 30% on MxChat Pro, Agency, or Agency Plus!</h3>595 <p>Unlock <strong>unlimited access</strong> to our growing collection of powerful add-ons including Admin AI Assistant (ChatGPT-like experience), Forms Builder, AI Theme Generator, WooCommerce, Perplexity, and more – all included with your <strong>lifetime license!</strong></p> </div>594 <h3>🚀 Limited Lifetime Offer: Save 15% on MxChat Pro, Agency, or Agency Plus!</h3> 595 <p>Unlock <strong>unlimited access</strong> to our growing collection of powerful add-ons including Admin AI Assistant (ChatGPT-like experience), Forms Builder, AI Theme Generator, WooCommerce, multi-bot, and more – all included with your <strong>lifetime license!</strong></p> </div> 596 596 <div class="mxchat-pro-cta"> 597 597 <a href="https://mxchat.ai/" target="_blank" class="mxchat-button"><?php echo esc_html__('Upgrade Today', 'mxchat'); ?></a> … … 6531 6531 public function mxchat_enqueue_admin_assets() { 6532 6532 // Get plugin version (define this in your main plugin file) 6533 $version = defined('MXCHAT_VERSION') ? MXCHAT_VERSION : '2.4. 3';6533 $version = defined('MXCHAT_VERSION') ? MXCHAT_VERSION : '2.4.4'; 6534 6534 6535 6535 // Use file modification time for development (remove in production) … … 7253 7253 } 7254 7254 7255 // Clear bot-specific caches 7256 $pinecone_manager->mxchat_clear_bot_caches($bot_id); 7257 7258 // Clear bot-specific vector cache 7259 delete_option('mxchat_pinecone_vector_ids_cache_' . $bot_id); 7260 7261 // Clear bot-specific processed content caches 7262 delete_option('mxchat_pinecone_processed_cache_' . $bot_id); 7263 delete_option('mxchat_processed_content_cache_' . $bot_id); 7264 7265 // Clear bot-specific transient cache 7266 delete_transient('mxchat_pinecone_recent_1k_cache_' . $bot_id); 7255 // No cache clearing needed since we removed caching 7267 7256 7268 7257 } else { … … 7291 7280 } 7292 7281 7293 // Clear relevant cache 7294 wp_cache_delete('all_prompts', 'mxchat_prompts'); 7295 wp_cache_delete('all_prompts_' . $bot_id, 'mxchat_prompts'); 7282 // No cache clearing needed since we removed caching 7296 7283 7297 7284 error_log('=== DELETE ALL DEBUG END ==='); -
mxchat-basic/trunk/includes/class-mxchat-integrator.php
r3366492 r3367268 928 928 $similarity_threshold = isset($current_options['similarity_threshold']) 929 929 ? ((int) $current_options['similarity_threshold']) / 100 930 : 0. 75;930 : 0.35; 931 931 932 932 $testing_data['similarity_threshold'] = $similarity_threshold; … … 3622 3622 $similarity_threshold = isset($current_options['similarity_threshold']) 3623 3623 ? ((int) $current_options['similarity_threshold']) / 100 3624 : 0. 75;3624 : 0.35; 3625 3625 3626 3626 $this->last_similarity_analysis['threshold_used'] = $similarity_threshold; … … 3821 3821 $similarity_threshold = isset($current_options['similarity_threshold']) 3822 3822 ? ((int) $current_options['similarity_threshold']) / 100 3823 : 0. 75;3823 : 0.35; 3824 3824 3825 3825 $this->last_similarity_analysis['threshold_used'] = $similarity_threshold; … … 3998 3998 return trim($content); 3999 3999 } 4000 4001 4000 4002 /** 4001 4003 * Get role restriction for a single vector (with caching) … … 4505 4507 } 4506 4508 } 4509 4507 4510 private function mxchat_generate_response_openai_stream($selected_model, $api_key, $conversation_history, $relevant_content, $session_id, $testing_data = null) { 4508 4511 try { 4509 $bot_id = $this->get_current_bot_id($session_id);4512 $bot_id = $this->get_current_bot_id($session_id); 4510 4513 4511 4514 // Get system prompt instructions using centralized function … … 4544 4547 if (headers_sent() || !function_exists('curl_init')) { 4545 4548 // Fallback to regular response with testing data 4546 //error_log("MxChat: OpenAI streaming not possible, falling back to regular response");4547 4549 $regular_response = $this->mxchat_generate_response_openai( 4548 4550 $selected_model, … … 4560 4562 if ($testing_data !== null) { 4561 4563 $response_data['testing_data'] = $testing_data; 4562 //error_log("MxChat Testing: Added testing data to OpenAI fallback response");4563 4564 } 4564 4565 … … 4591 4592 $full_response = ''; // Accumulate full response for saving 4592 4593 $stream_started = false; 4594 $buffer = ''; // CRITICAL: Add persistent buffer for incomplete chunks 4593 4595 4594 4596 // Buffer control for real-time streaming 4595 curl_setopt($ch, CURLOPT_WRITEFUNCTION, function($ch, $data) use (&$full_response, &$stream_started, $testing_data) {4597 curl_setopt($ch, CURLOPT_WRITEFUNCTION, function($ch, $data) use (&$full_response, &$stream_started, &$buffer, $testing_data) { 4596 4598 // Send testing data as the first event if available 4597 4599 if (!$stream_started && $testing_data !== null) { … … 4599 4601 flush(); 4600 4602 $stream_started = true; 4601 //error_log("MxChat Testing: Sent testing data in OpenAI stream"); 4602 } 4603 4604 // Process each chunk of data 4605 $lines = explode("\n", $data); 4603 } 4604 4605 // CRITICAL FIX: Append new data to buffer 4606 $buffer .= $data; 4607 4608 // Process complete lines only 4609 $lines = explode("\n", $buffer); 4610 4611 // CRITICAL FIX: Keep the last incomplete line in the buffer 4612 // The last element might be incomplete, so keep it in buffer 4613 $buffer = array_pop($lines); 4606 4614 4607 4615 foreach ($lines as $line) { 4608 if (trim($line) === '' || strpos($line, 'data: ') !== 0) { 4616 // Skip empty lines 4617 if (trim($line) === '') { 4618 continue; 4619 } 4620 4621 // Only process lines that start with "data: " 4622 if (strpos($line, 'data: ') !== 0) { 4609 4623 continue; 4610 4624 } … … 4612 4626 $json_str = substr($line, 6); // Remove 'data: ' prefix 4613 4627 4614 if ( $json_str=== '[DONE]') {4628 if (trim($json_str) === '[DONE]') { 4615 4629 echo "data: [DONE]\n\n"; 4616 4630 flush(); … … 4618 4632 } 4619 4633 4620 $json = json_decode($json_str, true); 4621 if (isset($json['choices'][0]['delta']['content'])) { 4634 // Try to decode JSON 4635 $json = json_decode(trim($json_str), true); 4636 if ($json && isset($json['choices'][0]['delta']['content'])) { 4622 4637 $content = $json['choices'][0]['delta']['content']; 4623 $full_response .= $content; // Accumulate 4638 $full_response .= $content; // Accumulate the full response 4639 4624 4640 // Send as SSE format 4625 4641 echo "data: " . json_encode(['content' => $content]) . "\n\n"; … … 4638 4654 4639 4655 // Fallback to regular response 4640 //error_log("MxChat: OpenAI streaming failed, falling back");4641 4656 $regular_response = $this->mxchat_generate_response_openai( 4642 4657 $selected_model, … … 4654 4669 if ($testing_data !== null) { 4655 4670 $response_data['testing_data'] = $testing_data; 4656 //error_log("MxChat Testing: Added testing data to OpenAI error fallback");4657 4671 } 4658 4672 … … 4672 4686 4673 4687 } catch (Exception $e) { 4674 //error_log("MxChat OpenAI streaming exception: " . $e->getMessage());4675 4676 4688 // Fallback to regular response 4677 4689 $regular_response = $this->mxchat_generate_response_openai( … … 4690 4702 if ($testing_data !== null) { 4691 4703 $response_data['testing_data'] = $testing_data; 4692 //error_log("MxChat Testing: Added testing data to OpenAI exception fallback");4693 4704 } 4694 4705 … … 4794 4805 $full_response = ''; // Accumulate full response for saving 4795 4806 $stream_started = false; 4807 $buffer = ''; // CRITICAL: Add persistent buffer for incomplete chunks 4796 4808 4797 4809 // Buffer control for real-time streaming 4798 curl_setopt($ch, CURLOPT_WRITEFUNCTION, function($ch, $data) use (&$full_response, &$stream_started, $testing_data) {4810 curl_setopt($ch, CURLOPT_WRITEFUNCTION, function($ch, $data) use (&$full_response, &$stream_started, &$buffer, $testing_data) { 4799 4811 // Send testing data as the first event if available 4800 4812 if (!$stream_started && $testing_data !== null) { … … 4805 4817 } 4806 4818 4807 // Process each chunk of data 4808 $lines = explode("\n", $data); 4819 // CRITICAL FIX: Append new data to buffer 4820 $buffer .= $data; 4821 4822 // Process complete lines only 4823 $lines = explode("\n", $buffer); 4824 4825 // CRITICAL FIX: Keep the last incomplete line in the buffer 4826 // The last element might be incomplete, so keep it in buffer 4827 $buffer = array_pop($lines); 4809 4828 4810 4829 foreach ($lines as $line) { … … 4822 4841 $json_str = substr($line, 6); // Remove 'data: ' prefix 4823 4842 4824 $json = json_decode( $json_str, true);4843 $json = json_decode(trim($json_str), true); 4825 4844 if (json_last_error() !== JSON_ERROR_NONE) { 4826 4845 continue; … … 5014 5033 $full_response = ''; // Accumulate full response for saving 5015 5034 $stream_started = false; 5035 $buffer = ''; // CRITICAL: Add persistent buffer for incomplete chunks 5016 5036 5017 5037 // Buffer control for real-time streaming 5018 curl_setopt($ch, CURLOPT_WRITEFUNCTION, function($ch, $data) use (&$full_response, &$stream_started, $testing_data) {5038 curl_setopt($ch, CURLOPT_WRITEFUNCTION, function($ch, $data) use (&$full_response, &$stream_started, &$buffer, $testing_data) { 5019 5039 // Send testing data as the first event if available 5020 5040 if (!$stream_started && $testing_data !== null) { … … 5025 5045 } 5026 5046 5027 // Process each chunk of data 5028 $lines = explode("\n", $data); 5047 // CRITICAL FIX: Append new data to buffer 5048 $buffer .= $data; 5049 5050 // Process complete lines only 5051 $lines = explode("\n", $buffer); 5052 5053 // CRITICAL FIX: Keep the last incomplete line in the buffer 5054 // The last element might be incomplete, so keep it in buffer 5055 $buffer = array_pop($lines); 5029 5056 5030 5057 foreach ($lines as $line) { 5031 if (trim($line) === '' || strpos($line, 'data: ') !== 0) { 5058 // Skip empty lines 5059 if (trim($line) === '') { 5060 continue; 5061 } 5062 5063 // Only process lines that start with "data: " 5064 if (strpos($line, 'data: ') !== 0) { 5032 5065 continue; 5033 5066 } … … 5035 5068 $json_str = substr($line, 6); // Remove 'data: ' prefix 5036 5069 5037 if ( $json_str=== '[DONE]') {5070 if (trim($json_str) === '[DONE]') { 5038 5071 echo "data: [DONE]\n\n"; 5039 5072 flush(); … … 5041 5074 } 5042 5075 5043 $json = json_decode($json_str, true); 5044 if (isset($json['choices'][0]['delta']['content'])) { 5076 // Try to decode JSON 5077 $json = json_decode(trim($json_str), true); 5078 if ($json && isset($json['choices'][0]['delta']['content'])) { 5045 5079 $content = $json['choices'][0]['delta']['content']; 5046 5080 $full_response .= $content; // Accumulate … … 5208 5242 $full_response = ''; // Accumulate full response for saving 5209 5243 $stream_started = false; 5244 $buffer = ''; // CRITICAL: Add persistent buffer for incomplete chunks 5210 5245 5211 5246 // Buffer control for real-time streaming 5212 curl_setopt($ch, CURLOPT_WRITEFUNCTION, function($ch, $data) use (&$full_response, &$stream_started, $testing_data) {5247 curl_setopt($ch, CURLOPT_WRITEFUNCTION, function($ch, $data) use (&$full_response, &$stream_started, &$buffer, $testing_data) { 5213 5248 // Send testing data as the first event if available 5214 5249 if (!$stream_started && $testing_data !== null) { … … 5219 5254 } 5220 5255 5221 // Process each chunk of data 5222 $lines = explode("\n", $data); 5256 // CRITICAL FIX: Append new data to buffer 5257 $buffer .= $data; 5258 5259 // Process complete lines only 5260 $lines = explode("\n", $buffer); 5261 5262 // CRITICAL FIX: Keep the last incomplete line in the buffer 5263 // The last element might be incomplete, so keep it in buffer 5264 $buffer = array_pop($lines); 5223 5265 5224 5266 foreach ($lines as $line) { 5225 if (trim($line) === '' || strpos($line, 'data: ') !== 0) { 5267 // Skip empty lines 5268 if (trim($line) === '') { 5269 continue; 5270 } 5271 5272 // Only process lines that start with "data: " 5273 if (strpos($line, 'data: ') !== 0) { 5226 5274 continue; 5227 5275 } … … 5229 5277 $json_str = substr($line, 6); // Remove 'data: ' prefix 5230 5278 5231 if ( $json_str=== '[DONE]') {5279 if (trim($json_str) === '[DONE]') { 5232 5280 echo "data: [DONE]\n\n"; 5233 5281 flush(); … … 5235 5283 } 5236 5284 5237 $json = json_decode($json_str, true); 5238 if (isset($json['choices'][0]['delta']['content'])) { 5285 // Try to decode JSON 5286 $json = json_decode(trim($json_str), true); 5287 if ($json && isset($json['choices'][0]['delta']['content'])) { 5239 5288 $content = $json['choices'][0]['delta']['content']; 5240 $full_response .= $content; // Accumulate 5289 $full_response .= $content; // Accumulate the full response 5290 5241 5291 // Send as SSE format 5242 5292 echo "data: " . json_encode(['content' => $content]) . "\n\n"; … … 6289 6339 public function mxchat_enqueue_scripts_styles() { 6290 6340 // Define version numbers for the styles and scripts 6291 $chat_style_version = '2.4. 3';6292 $chat_script_version = '2.4. 3';6341 $chat_style_version = '2.4.4'; 6342 $chat_script_version = '2.4.4'; 6293 6343 // Enqueue the script 6294 6344 wp_enqueue_script( … … 6904 6954 : 'No system prompt configured'; 6905 6955 6906 // Get selected model 6907 $selected_model = isset($ current_options['model']) ? $current_options['model'] : 'gpt-4o';6956 // Get selected model - FIXED: Use $this->options instead of $current_options 6957 $selected_model = isset($this->options['model']) ? $this->options['model'] : 'gpt-4o'; 6908 6958 6909 6959 // Get API key status (just check if they exist, don't expose the keys) … … 6938 6988 } 6939 6989 6940 // Get similarity threshold from main options (default 75%)6990 // Get similarity threshold from main options (default 35%) 6941 6991 $similarity_threshold = isset($this->options['similarity_threshold']) 6942 6992 ? ((int) $this->options['similarity_threshold']) / 100 6943 : 0. 75;6993 : 0.35; 6944 6994 6945 6995 wp_send_json_success([ … … 7112 7162 $similarity_threshold = isset($this->options['similarity_threshold']) 7113 7163 ? ((int) $this->options['similarity_threshold']) / 100 7114 : 0. 75;7164 : 0.35; 7115 7165 7116 7166 $testing_data['similarity_threshold'] = $similarity_threshold; -
mxchat-basic/trunk/js/chat-script.js
r3366492 r3367268 480 480 // Log the error with code for debugging 481 481 //console.log("Response data:", response.data); 482 // //console.error("API Error:", errorMessage, "Code:", errorCode);482 //console.error("API Error:", errorMessage, "Code:", errorCode); 483 483 484 484 // Format user-friendly error message … … 1225 1225 1226 1226 function linkify(inputText) { 1227 console.log('=== LINKIFY DEBUG START ===');1228 console.log('Input to linkify:', inputText);1229 console.log('Input type:', typeof inputText);1230 console.log('Input length:', inputText ? inputText.length : 'null/undefined');1227 //console.log('=== LINKIFY DEBUG START ==='); 1228 //console.log('Input to linkify:', inputText); 1229 //console.log('Input type:', typeof inputText); 1230 //console.log('Input length:', inputText ? inputText.length : 'null/undefined'); 1231 1231 1232 1232 if (!inputText) { 1233 console.log('Empty input, returning empty string');1233 //console.log('Empty input, returning empty string'); 1234 1234 return ''; 1235 1235 } 1236 1236 1237 1237 // Process markdown headers FIRST (before paragraph wrapping) 1238 console.log('--- Processing Headers ---');1238 //console.log('--- Processing Headers ---'); 1239 1239 let processedText = formatMarkdownHeaders(inputText); 1240 console.log('After headers:', processedText);1241 console.log('Headers changed:', processedText !== inputText);1240 //console.log('After headers:', processedText); 1241 //console.log('Headers changed:', processedText !== inputText); 1242 1242 1243 1243 // Process text styling (bold, italic, strikethrough) 1244 console.log('--- Processing Text Styling ---');1245 const beforeStyling = processedText;1244 //console.log('--- Processing Text Styling ---'); 1245 //const beforeStyling = processedText; 1246 1246 processedText = formatTextStyling(processedText); 1247 console.log('After styling:', processedText);1248 console.log('Styling changed:', processedText !== beforeStyling);1247 //console.log('After styling:', processedText); 1248 //console.log('Styling changed:', processedText !== beforeStyling); 1249 1249 1250 1250 // Process code blocks BEFORE processing links to avoid conflicts 1251 console.log('--- Processing Code Blocks ---');1251 //console.log('--- Processing Code Blocks ---'); 1252 1252 const beforeCodeBlocks = processedText; 1253 1253 processedText = formatCodeBlocks(processedText); 1254 console.log('After code blocks:', processedText);1255 console.log('Code blocks changed:', processedText !== beforeCodeBlocks);1254 //console.log('After code blocks:', processedText); 1255 //console.log('Code blocks changed:', processedText !== beforeCodeBlocks); 1256 1256 1257 1257 // NOW convert to paragraphs (this should be AFTER markdown processing) 1258 console.log('--- Converting to Paragraphs ---');1258 //console.log('--- Converting to Paragraphs ---'); 1259 1259 const beforeParagraphs = processedText; 1260 1260 processedText = convertNewlinesToBreaks(processedText); 1261 console.log('After paragraph conversion:', processedText);1262 console.log('Paragraphs changed:', processedText !== beforeParagraphs);1261 //console.log('After paragraph conversion:', processedText); 1262 //console.log('Paragraphs changed:', processedText !== beforeParagraphs); 1263 1263 1264 1264 // Process markdown links 1265 console.log('--- Processing Markdown Links ---');1265 //console.log('--- Processing Markdown Links ---'); 1266 1266 const beforeMarkdownLinks = processedText; 1267 1267 const markdownLinkPattern = /\[([^\]]+)\]\((https?:\/\/[^\s)]+)\)/g; 1268 1268 processedText = processedText.replace(markdownLinkPattern, (match, text, url) => { 1269 console.log('Found markdown link:', match, 'text:', text, 'url:', url);1269 //console.log('Found markdown link:', match, 'text:', text, 'url:', url); 1270 1270 const safeUrl = encodeURI(url); 1271 1271 const safeText = sanitizeUserInput(text); 1272 1272 return `<a href="${safeUrl}" target="${linkTarget}">${safeText}</a>`; 1273 1273 }); 1274 console.log('After markdown links:', processedText);1275 console.log('Markdown links changed:', processedText !== beforeMarkdownLinks);1274 //console.log('After markdown links:', processedText); 1275 //console.log('Markdown links changed:', processedText !== beforeMarkdownLinks); 1276 1276 1277 1277 // Process phone numbers (tel:) 1278 console.log('--- Processing Phone Numbers ---');1278 //console.log('--- Processing Phone Numbers ---'); 1279 1279 const beforePhone = processedText; 1280 1280 const phonePattern = /\[([^\]]+)\]\((tel:[\d+\-\s()]+)\)/g; 1281 1281 processedText = processedText.replace(phonePattern, (match, text, phone) => { 1282 console.log('Found phone link:', match, 'text:', text, 'phone:', phone);1282 //console.log('Found phone link:', match, 'text:', text, 'phone:', phone); 1283 1283 const safePhone = encodeURI(phone); 1284 1284 const safeText = sanitizeUserInput(text); 1285 1285 return `<a href="${safePhone}">${safeText}</a>`; 1286 1286 }); 1287 console.log('After phone numbers:', processedText);1288 console.log('Phone numbers changed:', processedText !== beforePhone);1287 //console.log('After phone numbers:', processedText); 1288 //console.log('Phone numbers changed:', processedText !== beforePhone); 1289 1289 1290 1290 // Process mailto links 1291 console.log('--- Processing Mailto Links ---');1291 //console.log('--- Processing Mailto Links ---'); 1292 1292 const beforeMailto = processedText; 1293 1293 const mailtoPattern = /\[([^\]]+)\]\((mailto:[^\)]+)\)/g; … … 1298 1298 return `<a href="${safeMailto}">${safeText}</a>`; 1299 1299 }); 1300 console.log('After mailto links:', processedText);1301 console.log('Mailto links changed:', processedText !== beforeMailto);1300 //console.log('After mailto links:', processedText); 1301 //console.log('Mailto links changed:', processedText !== beforeMailto); 1302 1302 1303 1303 // Process standalone URLs (avoid already processed links) 1304 console.log('--- Processing Standalone URLs ---');1304 //console.log('--- Processing Standalone URLs ---'); 1305 1305 const beforeStandaloneUrls = processedText; 1306 1306 const urlPattern = /(^|[^">])(https?:\/\/[^\s<]+)(?![^<]*<\/a>)/gim; 1307 1307 processedText = processedText.replace(urlPattern, (match, prefix, url) => { 1308 console.log('Found standalone URL:', match, 'prefix:', prefix, 'url:', url);1308 //console.log('Found standalone URL:', match, 'prefix:', prefix, 'url:', url); 1309 1309 const safeUrl = encodeURI(url); 1310 1310 return `${prefix}<a href="${safeUrl}" target="${linkTarget}">${url}</a>`; 1311 1311 }); 1312 console.log('After standalone URLs:', processedText);1313 console.log('Standalone URLs changed:', processedText !== beforeStandaloneUrls);1312 //console.log('After standalone URLs:', processedText); 1313 //console.log('Standalone URLs changed:', processedText !== beforeStandaloneUrls); 1314 1314 1315 1315 // Process www. URLs (avoid already processed links) 1316 console.log('--- Processing WWW URLs ---');1316 //console.log('--- Processing WWW URLs ---'); 1317 1317 const beforeWwwUrls = processedText; 1318 1318 const wwwPattern = /(^|[^">])(www\.[\S]+(\b|$))(?![^<]*<\/a>)/gim; 1319 1319 processedText = processedText.replace(wwwPattern, (match, prefix, url) => { 1320 console.log('Found www URL:', match, 'prefix:', prefix, 'url:', url);1320 //console.log('Found www URL:', match, 'prefix:', prefix, 'url:', url); 1321 1321 const safeUrl = encodeURI(`http://${url}`); 1322 1322 return `${prefix}<a href="${safeUrl}" target="${linkTarget}">${url}</a>`; 1323 1323 }); 1324 console.log('After www URLs:', processedText);1325 console.log('WWW URLs changed:', processedText !== beforeWwwUrls);1326 1327 console.log('=== FINAL RESULT ===');1328 console.log('Final processed text:', processedText);1329 console.log('Total transformation:', inputText !== processedText);1330 console.log('=== LINKIFY DEBUG END ===');1324 //console.log('After www URLs:', processedText); 1325 //console.log('WWW URLs changed:', processedText !== beforeWwwUrls); 1326 1327 //console.log('=== FINAL RESULT ==='); 1328 //console.log('Final processed text:', processedText); 1329 //console.log('Total transformation:', inputText !== processedText); 1330 //console.log('=== LINKIFY DEBUG END ==='); 1331 1331 1332 1332 return processedText; -
mxchat-basic/trunk/mxchat-basic.php
r3366492 r3367268 3 3 * Plugin Name: MxChat 4 4 * Description: AI chatbot for WordPress with OpenAI, Claude, xAI, DeepSeek, live agent, PDF uploads, WooCommerce, and training on website data. 5 * Version: 2.4. 35 * Version: 2.4.4 6 6 * Author: MxChat 7 7 * Author URI: https://mxchat.ai … … 17 17 18 18 // Define plugin version constant for asset versioning 19 define('MXCHAT_VERSION', '2.4. 3');19 define('MXCHAT_VERSION', '2.4.4'); 20 20 21 21 function mxchat_load_textdomain() { … … 468 468 } 469 469 470 // NEW: Run enabled_bots column migration for 2.4. 3471 if (version_compare($current_version, '2.4. 3', '<')) {470 // NEW: Run enabled_bots column migration for 2.4.4 471 if (version_compare($current_version, '2.4.4', '<')) { 472 472 mxchat_add_enabled_bots_column(); 473 473 } -
mxchat-basic/trunk/readme.txt
r3366492 r3367268 6 6 Tested up to: 6.8 7 7 Requires PHP: 7.2 8 Stable tag: 2.4. 38 Stable tag: 2.4.4 9 9 License: GPLv2 or later 10 10 License URI: https://www.gnu.org/licenses/gpl-2.0.html … … 14 14 == Description == 15 15 16 [Documentation](https://mxchat.ai/documentation/) | [MxChat Pro](https://mxchat.ai/) 17 18 ### 🎥 Product Demo Videos: 19 - [AI Theme Generator Add-On](https://www.youtube.com/watch?v=rSQDW2qbtRU&t) - Transform your chatbot's appearance in seconds with AI-powered design 20 - [Admin Assistant Add-On](https://www.youtube.com/watch?v=AdEA1k-UCFM) - ChatGPT-like experience directly inside your WordPress dashboard 21 - [WooCommerce Add-On](https://www.youtube.com/watch?v=WsqAppHRGdA) - Display product cards, recommendations, and supercharge your store 22 - [MxChat Forms Add-On](https://www.youtube.com/watch?v=3MrWy5dRalA&t) - Convert conversations into data collection with smart forms that trigger during chats 23 - [Chat with PDF & Word](https://www.youtube.com/watch?v=j_c45WWCTG0) - Let users upload and interact with documents 24 25 [Explore all product videos on YouTube](https://www.youtube.com/@MxChat/videos) 16 [Documentation](https://mxchat.ai/documentation/) 17 18 ### 📦 Optional Premium Add-Ons 19 Extend the free plugin with these optional premium features: 20 21 - [Forms Action Add-On](https://mxchat.ai/forms-action/) – Capture leads and data with custom in-chat forms 22 - [WooCommerce Add-On](https://mxchat.ai/woocommerce/) – AI-powered shopping assistance and product recommendations 23 - [AI Theme Customizer Add-On](https://mxchat.ai/ai-theme-customizer/) – Instantly design chatbot themes with natural language 24 - [Multi-Bot Add-On](https://mxchat.ai/multi-bot/) – Run unlimited AI chatbots with custom knowledge and personalities 25 - [Image Analysis Add-On](https://mxchat.ai/image-analysis/) – Enable AI-powered image analysis and OCR inside chats 26 27 👉 [Visit our website to view all add-ons](https://mxchat.ai) 28 29 ### 🎥 Product Demo Videos 30 [Explore all product videos on YouTube](https://www.youtube.com/@MxChat/videos) 26 31 27 32 ## Why Choose MxChat AI Chatbot for Your WordPress Website? … … 34 39 ✅ **Extensive Add-On Ecosystem**: Forms, moderation, recommendations, theme customization, and more 35 40 36 ## 🔥 What's New in Version 2.4.2 37 🤖 **NEW: Multi-Bot Manager Add-on Support** – Create and manage multiple specialized chatbots with dedicated knowledge databases for different purposes (support, sales, technical, etc.). Each bot can have its own Pinecone configuration and settings. 41 ## 🔥 What's New in Version 2.4.4 42 43 🐞 **Bug Fixes** 44 - Default similarity is now accurate across all settings 45 - Improved streaming responses to prevent dropped characters or words 46 47 ⚡ **Enhancements** 48 - Removed unnecessary Pinecone caching in the knowledge database for more accurate results 38 49 39 50 ## Core Features That Set MxChat Apart … … 171 182 == Changelog == 172 183 184 = 2.4.4 - September 24, 2025 = 185 - Bug Fix: Default similarity is now accurate across all settings. 186 - Bug Fix: Improved streaming responses to prevent dropped characters or words. 187 - Enhanced: Removed unnecessary Pinecone caching in the knowledge database for more accurate results. 188 173 189 = 2.4.3 - September 23, 2025 = 174 190 - Added: Support for upcoming multi-bot update that allows for more customized settings such as individual chat models. … … 532 548 == Upgrade Notice == 533 549 534 = 2.4.3 = 535 - Added: Support for upcoming multi-bot update that allows for more customized settings such as individual chat models. 536 - Improved: CSS for chatbot UI & more robust markdown support. 550 = 2.4.4 = 551 This update fixes similarity accuracy issues, improves streaming responses, and enhances knowledge database accuracy. Recommended for all users. 537 552 538 553 == License & Warranty ==
Note: See TracChangeset
for help on using the changeset viewer.