| @@ -4,9 +4,8 @@ | ||
| 4 | 4 | } |
| 5 | 5 | |
| 6 | 6 | class MxChat_Integrator { |
| 7 | 7 | private $options; |
| 8 | - private $prompts_options; | |
| 9 | 8 | private $chat_count; |
| 10 | 9 | private $fallbackResponse; |
| 11 | 10 | private $productCardHtml; |
| 12 | 11 | private $word_handler; |
| @@ -12,13 +11,18 @@ | ||
| 12 | 11 | private $word_handler; |
| 13 | 12 | |
| 14 | 13 | public function __construct() { |
| 15 | 14 | $this->options = get_option('mxchat_options'); |
| 16 | - $this->prompts_options = get_option('mxchat_prompts_options', array()); | |
| 17 | - | |
| 18 | 15 | $this->chat_count = get_option('mxchat_chat_count', 0); |
| 19 | 16 | $this->word_handler = new MXChat_Word_Handler($this->options); |
| 20 | 17 | |
| 18 | + // Add WooCommerce hooks | |
| 19 | + add_action('wp_insert_post', array($this, 'mxchat_handle_product_change'), 10, 3); | |
| 20 | + | |
| 21 | + // Ensure embeddings are removed when a product is moved to trash or permanently deleted | |
| 22 | + add_action('wp_trash_post', array($this, 'mxchat_handle_product_delete')); | |
| 23 | + add_action('before_delete_post', array($this, 'mxchat_handle_product_delete')); | |
| 24 | + | |
| 21 | 25 | add_action('wp_enqueue_scripts', array($this, 'mxchat_enqueue_scripts_styles')); |
| 22 | 26 | add_action('wp_ajax_mxchat_handle_chat_request', array($this, 'mxchat_handle_chat_request')); |
| 23 | 27 | add_action('wp_ajax_nopriv_mxchat_handle_chat_request', array($this, 'mxchat_handle_chat_request')); |
| 24 | 28 | |
| @@ -43,8 +47,9 @@ | ||
| 43 | 47 | |
| 44 | 48 | add_action('wp_ajax_mxchat_fetch_new_messages', array($this, 'mxchat_fetch_new_messages')); |
| 45 | 49 | add_action('wp_ajax_nopriv_mxchat_fetch_new_messages', array($this, 'mxchat_fetch_new_messages')); |
| 46 | 50 | |
| 51 | + | |
| 47 | 52 | add_action('mxchat_reset_rate_limits', array($this, 'mxchat_reset_rate_limits')); |
| 48 | 53 | |
| 49 | 54 | add_action('wp_ajax_mxchat_upload_pdf', [$this, 'handle_pdf_upload']); |
| 50 | 55 | add_action('wp_ajax_nopriv_mxchat_upload_pdf', [$this, 'handle_pdf_upload']); |
| @@ -64,9 +69,70 @@ | ||
| 64 | 69 | add_action('wp_ajax_nopriv_mxchat_check_email_provided', [$this, 'mxchat_check_email_provided']); |
| 65 | 70 | add_action('wp_ajax_mxchat_check_email_provided', [$this, 'mxchat_check_email_provided']); |
| 66 | 71 | } |
| 67 | 72 | |
| 73 | +public function mxchat_handle_product_change($post_id, $post, $update) { | |
| 74 | + // Ensure this is a product post type | |
| 75 | + if ($post->post_type !== 'product') { | |
| 76 | + return; | |
| 77 | + } | |
| 68 | 78 | |
| 79 | + // Only generate embeddings if the product is published | |
| 80 | + if ($post->post_status === 'publish') { | |
| 81 | + // Delay the embedding slightly to ensure all product data is available | |
| 82 | + add_action('shutdown', function() use ($post_id) { | |
| 83 | + $product = wc_get_product($post_id); | |
| 84 | + if ($product && $product->get_price() !== '') { | |
| 85 | + $this->mxchat_store_product_embedding($product); | |
| 86 | + } else { | |
| 87 | + // Optionally, log or handle the case where product data is incomplete | |
| 88 | + // error_log("Product {$post_id} does not have complete data. Embedding not generated."); | |
| 89 | + } | |
| 90 | + }); | |
| 91 | + } | |
| 92 | +} | |
| 93 | + | |
| 94 | +public function mxchat_handle_product_delete($post_id) { | |
| 95 | + if (get_post_type($post_id) !== 'product') { | |
| 96 | + return; | |
| 97 | + } | |
| 98 | + | |
| 99 | + global $wpdb; | |
| 100 | + $table_name = $wpdb->prefix . 'mxchat_system_prompt_content'; | |
| 101 | + | |
| 102 | + // Delete the embedding associated with this product | |
| 103 | + $wpdb->delete($table_name, array('source_url' => get_permalink($post_id)), array('%s')); | |
| 104 | +} | |
| 105 | + | |
| 106 | +private function mxchat_store_product_embedding($product) { | |
| 107 | + if (isset($this->options['enable_woocommerce_integration']) && $this->options['enable_woocommerce_integration'] === '1') { | |
| 108 | + | |
| 109 | + $source_url = get_permalink($product->get_id()); | |
| 110 | + $regular_price = $product->get_regular_price(); | |
| 111 | + $sale_price = $product->get_sale_price(); | |
| 112 | + $price = $sale_price ?: $regular_price; | |
| 113 | + | |
| 114 | + $description = $product->get_description() . "\n\n" . | |
| 115 | + "Short Description: " . $product->get_short_description() . "\n" . | |
| 116 | + "Price: " . $regular_price . "\n" . | |
| 117 | + "Sale Price: " . ($sale_price ?: 'N/A') . "\n" . | |
| 118 | + "SKU: " . $product->get_sku(); | |
| 119 | + | |
| 120 | + global $wpdb; | |
| 121 | + $table_name = $wpdb->prefix . 'mxchat_system_prompt_content'; | |
| 122 | + | |
| 123 | + // Delete any existing embedding for this product | |
| 124 | + $wpdb->delete($table_name, array('source_url' => $source_url), array('%s')); | |
| 125 | + | |
| 126 | + // Submit the new content and embedding to the database | |
| 127 | + MxChat_Utils::submit_content_to_db($description, $source_url, $this->options['api_key']); | |
| 128 | + } | |
| 129 | +} | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 69 | 135 | private function mxchat_increment_chat_count() { |
| 70 | 136 | $chat_count = get_option('mxchat_chat_count', 0); |
| 71 | 137 | $chat_count++; |
| 72 | 138 | update_option('mxchat_chat_count', $chat_count); |
| @@ -73,9 +139,9 @@ | ||
| 73 | 139 | } |
| 74 | 140 | |
| 75 | 141 | function mxchat_fetch_conversation_history() { |
| 76 | 142 | if (empty($_POST['session_id'])) { |
| 77 | - wp_send_json_error(['message' => esc_html__('Session ID missing.', 'mxchat')]); | |
| 143 | + wp_send_json_error(['message' => 'Session ID missing.']); | |
| 78 | 144 | wp_die(); |
| 79 | 145 | } |
| 80 | 146 | |
| 81 | 147 | $session_id = sanitize_text_field($_POST['session_id']); |
| @@ -114,82 +180,41 @@ | ||
| 114 | 180 | |
| 115 | 181 | |
| 116 | 182 | private function mxchat_fetch_conversation_history_for_ai($session_id) { |
| 117 | 183 | $history = get_option("mxchat_history_{$session_id}", []); |
| 184 | + | |
| 118 | 185 | $formatted_history = []; |
| 119 | - | |
| 120 | - // Adjusted for code-heavy conversations | |
| 121 | - $max_tokens = 120000; // Context window size | |
| 122 | - $reserved_tokens = 5000; // Space for system prompts + current query | |
| 186 | + $max_tokens = 120000; // Adjust based on your model's context window | |
| 187 | + $reserved_tokens = 4000; // Reserve tokens for current query and system/context prompt | |
| 123 | 188 | $current_token_count = 0; |
| 124 | 189 | |
| 125 | - // Allowed HTML tags for content sanitization | |
| 126 | - $allowed_tags = [ | |
| 127 | - 'pre' => ['class' => true], | |
| 128 | - 'code' => ['class' => true], | |
| 129 | - 'span' => ['class' => true], | |
| 130 | - 'div' => ['class' => true], | |
| 131 | - 'strong' => [], | |
| 132 | - 'em' => [] | |
| 133 | - ]; | |
| 134 | - | |
| 135 | - foreach (array_reverse($history) as $entry) { | |
| 136 | - // Preserve code blocks while sanitizing other HTML | |
| 137 | - $clean_content = wp_kses($entry['content'], $allowed_tags); | |
| 138 | - | |
| 139 | - // Detect code blocks in content | |
| 140 | - $has_code = false; | |
| 141 | -// Replace the HTML check with: | |
| 142 | -// Allow messages that contain code blocks or are plain text | |
| 143 | -if (strpos($clean_content, '<pre') === false && | |
| 144 | - strpos($clean_content, '<code') === false && | |
| 145 | - $clean_content !== strip_tags($entry['content'])) { | |
| 146 | - continue; | |
| 147 | -} | |
| 148 | - | |
| 149 | - // Skip entries that lost significant content during sanitization | |
| 150 | - if (!$has_code && $clean_content !== strip_tags($entry['content'])) { | |
| 190 | + foreach ($history as $entry) { | |
| 191 | + // Skip messages containing HTML | |
| 192 | + if ($entry['content'] !== strip_tags($entry['content'])) { | |
| 151 | 193 | continue; |
| 152 | 194 | } |
| 153 | 195 | |
| 154 | - // More accurate token estimation (1 token ≈ 4 characters) | |
| 155 | - $token_estimate = ceil(mb_strlen($clean_content, 'UTF-8') / 4); | |
| 196 | + // Calculate tokens for this entry | |
| 197 | + $tokens_in_entry = str_word_count($entry['content']) * 1.5; // Rough estimate: ~1.5 tokens per word | |
| 198 | + $current_token_count += $tokens_in_entry; | |
| 156 | 199 | |
| 157 | - // Check token budget with the new estimate | |
| 158 | - if (($current_token_count + $token_estimate + $reserved_tokens) > $max_tokens) { | |
| 159 | - // Try to fit partial content if it's the first entry | |
| 160 | - if (empty($formatted_history)) { | |
| 161 | - $clean_content = mb_substr($clean_content, 0, ($max_tokens - $reserved_tokens) * 4); | |
| 162 | - $token_estimate = ceil(mb_strlen($clean_content, 'UTF-8') / 4); | |
| 163 | - } else { | |
| 164 | - break; | |
| 165 | - } | |
| 200 | + // If adding this entry exceeds the limit, stop | |
| 201 | + if ($current_token_count + $reserved_tokens > $max_tokens) { | |
| 202 | + break; | |
| 166 | 203 | } |
| 167 | 204 | |
| 168 | - // Add to formatted history | |
| 169 | 205 | $formatted_history[] = [ |
| 170 | 206 | 'role' => $entry['role'], |
| 171 | - 'content' => $clean_content | |
| 207 | + 'content' => $entry['content'] | |
| 172 | 208 | ]; |
| 173 | - | |
| 174 | - $current_token_count += $token_estimate; | |
| 175 | 209 | } |
| 176 | 210 | |
| 177 | - // Reverse back to maintain chronological order | |
| 178 | - $formatted_history = array_reverse($formatted_history); | |
| 179 | - | |
| 180 | - // Add system message about code context | |
| 181 | - array_unshift($formatted_history, [ | |
| 182 | - 'role' => 'system', | |
| 183 | - 'content' => 'Preserved code blocks are marked with [CODE BLOCK PRESERVED]. ' | |
| 184 | - . 'Maintain formatting and syntax highlighting when referencing code.' | |
| 185 | - ]); | |
| 186 | - | |
| 187 | 211 | return $formatted_history; |
| 188 | 212 | } |
| 189 | 213 | |
| 214 | + | |
| 190 | 215 | public function register_routes() { |
| 191 | - //error_log(esc_html__('Registering MxChat REST routes', 'mxchat')); | |
| 216 | + //error_log('Registering MxChat REST routes'); | |
| 192 | 217 | |
| 193 | 218 | register_rest_route('mxchat/v1', '/stream', [ |
| 194 | 219 | 'methods' => 'GET', |
| 195 | 220 | 'callback' => [$this, 'mxchat_stream_events'], |
| @@ -207,9 +232,9 @@ | ||
| 207 | 232 | 'callback' => [$this, 'handle_slack_interaction'], |
| 208 | 233 | 'permission_callback' => [$this, 'verify_slack_request'], |
| 209 | 234 | ]); |
| 210 | 235 | |
| 211 | - //error_log(esc_html__('MxChat REST routes registered', 'mxchat')); | |
| 236 | + //error_log('MxChat REST routes registered'); | |
| 212 | 237 | } |
| 213 | 238 | |
| 214 | 239 | /** |
| 215 | 240 | * Verify valid chat session |
| @@ -216,9 +241,9 @@ | ||
| 216 | 241 | */ |
| 217 | 242 | public function verify_chat_session($request) { |
| 218 | 243 | $session_id = $request->get_param('session_id'); |
| 219 | 244 | if (empty($session_id)) { |
| 220 | - //error_log(esc_html__('Empty session ID in chat request', 'mxchat')); | |
| 245 | + //error_log('Empty session ID in chat request'); | |
| 221 | 246 | return false; |
| 222 | 247 | } |
| 223 | 248 | |
| 224 | 249 | $chat_mode = get_option("mxchat_mode_{$session_id}", 'ai'); |
| @@ -235,9 +260,9 @@ | ||
| 235 | 260 | // Get the Slack signing secret from your plugin options |
| 236 | 261 | $valid_key = $this->options['live_agent_secret_key'] ?? ''; |
| 237 | 262 | |
| 238 | 263 | if (empty($valid_key)) { |
| 239 | - //error_log(esc_html__('Slack signing secret not configured', 'mxchat')); | |
| 264 | + //error_log('Slack signing secret not configured'); | |
| 240 | 265 | return false; |
| 241 | 266 | } |
| 242 | 267 | |
| 243 | 268 | $timestamp = $request->get_header('X-Slack-Request-Timestamp'); |
| @@ -244,9 +269,9 @@ | ||
| 244 | 269 | $slack_signature = $request->get_header('X-Slack-Signature'); |
| 245 | 270 | |
| 246 | 271 | // Verify timestamp to prevent replay attacks |
| 247 | 272 | if (abs(time() - intval($timestamp)) > 300) { |
| 248 | - //error_log(esc_html__('Slack request timestamp too old', 'mxchat')); | |
| 273 | + //error_log('Slack request timestamp too old'); | |
| 249 | 274 | return false; |
| 250 | 275 | } |
| 251 | 276 | |
| 252 | 277 | // Get raw request body |
| @@ -269,9 +294,9 @@ | ||
| 269 | 294 | $session_id = sanitize_text_field($request->get_param('session_id')); |
| 270 | 295 | $last_seen_id = sanitize_text_field($request->get_param('last_seen_id')) ?: ''; |
| 271 | 296 | |
| 272 | 297 | if (empty($session_id)) { |
| 273 | - echo esc_html__("event: error\ndata: ", 'mxchat') . esc_html__('Missing session_id', 'mxchat') . "\n\n"; | |
| 298 | + echo "event: error\ndata: Missing session_id\n\n"; | |
| 274 | 299 | flush(); |
| 275 | 300 | exit; |
| 276 | 301 | } |
| 277 | 302 | |
| @@ -283,12 +308,12 @@ | ||
| 283 | 308 | }); |
| 284 | 309 | |
| 285 | 310 | // Send new messages if available |
| 286 | 311 | if (!empty($new_messages)) { |
| 287 | - echo esc_html__("event: newMessages\ndata: ", 'mxchat') . json_encode(array_values($new_messages)) . "\n\n"; | |
| 312 | + echo "event: newMessages\ndata: " . json_encode(array_values($new_messages)) . "\n\n"; | |
| 288 | 313 | } else { |
| 289 | 314 | // Keep the connection alive |
| 290 | - echo esc_html__("event: keepAlive\ndata: ", 'mxchat') . "{}\n\n"; | |
| 315 | + echo "event: keepAlive\ndata: {}\n\n"; | |
| 291 | 316 | } |
| 292 | 317 | flush(); |
| 293 | 318 | exit; |
| 294 | 319 | } |
| @@ -382,10 +407,10 @@ | ||
| 382 | 407 | //error_log('[DEBUG] ---------- mxchat_handle_save_email_and_response START ----------'); |
| 383 | 408 | |
| 384 | 409 | // Validate nonce |
| 385 | 410 | if (!isset($_POST['nonce']) || !wp_verify_nonce($_POST['nonce'], 'mxchat_chat_nonce')) { |
| 386 | - error_log(esc_html__('[ERROR] Invalid nonce in mxchat_handle_save_email_and_response', 'mxchat')); | |
| 387 | - wp_send_json_error(['message' => esc_html__('Invalid nonce.', 'mxchat')]); | |
| 411 | + error_log('[ERROR] Invalid nonce in mxchat_handle_save_email_and_response'); | |
| 412 | + wp_send_json_error(['message' => 'Invalid nonce.']); | |
| 388 | 413 | wp_die(); |
| 389 | 414 | } |
| 390 | 415 | |
| 391 | 416 | $session_id = isset($_POST['session_id']) ? sanitize_text_field($_POST['session_id']) : ''; |
| @@ -394,9 +419,9 @@ | ||
| 394 | 419 | //error_log("[DEBUG] handle_save_email_and_response -> session_id: {$session_id}, email: {$email}"); |
| 395 | 420 | |
| 396 | 421 | if (empty($session_id) || empty($email)) { |
| 397 | 422 | //error_log("[ERROR] Missing session_id or email: session_id={$session_id}, email={$email}"); |
| 398 | - wp_send_json_error(['message' => esc_html__('Session ID or email is missing.', 'mxchat')]); | |
| 423 | + wp_send_json_error(['message' => 'Session ID or email is missing.']); | |
| 399 | 424 | wp_die(); |
| 400 | 425 | } |
| 401 | 426 | |
| 402 | 427 | // 1) Always store in wp_options |
| @@ -427,9 +452,9 @@ | ||
| 427 | 452 | //error_log("[INFO] handle_save_email_and_response -> No DB entry for {$session_id}, so email is only in wp_options."); |
| 428 | 453 | } |
| 429 | 454 | |
| 430 | 455 | // Provide success response |
| 431 | - $bot_message = __('Thanks for providing your email! You can continue chatting now.', 'mxchat'); | |
| 456 | + $bot_message = 'Thanks for providing your email! You can continue chatting now.'; | |
| 432 | 457 | //error_log("[DEBUG] handle_save_email_and_response -> success, returning bot_message: {$bot_message}"); |
| 433 | 458 | wp_send_json_success(['message' => $bot_message]); |
| 434 | 459 | wp_die(); |
| 435 | 460 | } |
| @@ -438,15 +463,15 @@ | ||
| 438 | 463 | //error_log('[DEBUG] ---------- mxchat_check_email_provided START ----------'); |
| 439 | 464 | |
| 440 | 465 | if (!isset($_POST['nonce']) || !wp_verify_nonce($_POST['nonce'], 'mxchat_chat_nonce')) { |
| 441 | 466 | //error_log('[ERROR] Invalid nonce in mxchat_check_email_provided'); |
| 442 | - wp_send_json_error(['message' => esc_html__('Invalid nonce', 'mxchat')]); | |
| 467 | + wp_send_json_error(['message' => 'Invalid nonce']); | |
| 443 | 468 | } |
| 444 | 469 | |
| 445 | 470 | $session_id = isset($_POST['session_id']) ? sanitize_text_field($_POST['session_id']) : ''; |
| 446 | 471 | if (empty($session_id)) { |
| 447 | 472 | //error_log('[ERROR] No session ID provided in mxchat_check_email_provided'); |
| 448 | - wp_send_json_error(['message' => esc_html__('No session ID provided', 'mxchat')]); | |
| 473 | + wp_send_json_error(['message' => 'No session ID provided']); | |
| 449 | 474 | } |
| 450 | 475 | |
| 451 | 476 | // Check if the user is logged in |
| 452 | 477 | if (is_user_logged_in()) { |
| @@ -464,182 +489,53 @@ | ||
| 464 | 489 | //error_log("[DEBUG] mxchat_check_email_provided -> Email found, returning success"); |
| 465 | 490 | wp_send_json_success(['email' => $stored_email]); |
| 466 | 491 | } else { |
| 467 | 492 | //error_log("[DEBUG] mxchat_check_email_provided -> No email found, returning error"); |
| 468 | - wp_send_json_error(['message' => esc_html__('No email found', 'mxchat')]); | |
| 493 | + wp_send_json_error(['message' => 'No email found']); | |
| 469 | 494 | } |
| 470 | 495 | } |
| 471 | 496 | |
| 472 | 497 | |
| 473 | -// First, add this helper function to get the highest rate limit for a user's roles | |
| 474 | -private function get_user_role_rate_limit($user_id) { | |
| 475 | - //error_log(esc_html__("Checking rate limit for user ID: ", 'mxchat') . $user_id); | |
| 476 | - | |
| 477 | - if (!$user_id) { | |
| 478 | - //error_log(esc_html__("No user ID provided, using logged-out limit: ", 'mxchat') . ($this->options['rate_limit_logged_out'] ?? '10')); | |
| 479 | - return $this->options['rate_limit_logged_out'] ?? '10'; | |
| 480 | - } | |
| 481 | - | |
| 482 | - $user = get_userdata($user_id); | |
| 483 | - if (!$user || !$user->roles) { | |
| 484 | - //error_log(esc_html__("No user data or roles found, using logged-out limit: ", 'mxchat') . ($this->options['rate_limit_logged_out'] ?? '10')); | |
| 485 | - return $this->options['rate_limit_logged_out'] ?? '10'; | |
| 486 | - } | |
| 487 | - | |
| 488 | - //error_log(esc_html__("User roles: ", 'mxchat') . print_r($user->roles, true)); | |
| 489 | - //error_log(esc_html__("Available role rate limits: ", 'mxchat') . print_r($this->options['role_rate_limits'] ?? [], true)); | |
| 490 | - | |
| 491 | - $max_limit = 0; | |
| 492 | - foreach ($user->roles as $role) { | |
| 493 | - //error_log(esc_html__("Checking limit for role: ", 'mxchat') . $role); | |
| 494 | - if (isset($this->options['role_rate_limits'][$role])) { | |
| 495 | - $role_limit = $this->options['role_rate_limits'][$role]; | |
| 496 | - //error_log(esc_html__("Found limit for role ", 'mxchat') . $role . esc_html__(": ", 'mxchat') . $role_limit); | |
| 497 | - | |
| 498 | - if ($role_limit === 'unlimited') { | |
| 499 | - //error_log(esc_html__("Returning unlimited for role: ", 'mxchat') . $role); | |
| 500 | - return 'unlimited'; | |
| 501 | - } | |
| 502 | - | |
| 503 | - $max_limit = max($max_limit, (int)$role_limit); | |
| 504 | - //error_log(esc_html__("Current max limit: ", 'mxchat') . $max_limit); | |
| 505 | - } else { | |
| 506 | - //error_log(esc_html__("No limit found for role: ", 'mxchat') . $role); | |
| 507 | - } | |
| 508 | - } | |
| 509 | - | |
| 510 | - $final_limit = $max_limit > 0 ? (string)$max_limit : '100'; | |
| 511 | - //error_log(esc_html__("Final rate limit: ", 'mxchat') . $final_limit); | |
| 512 | - return $final_limit; | |
| 513 | -} | |
| 514 | - | |
| 515 | - | |
| 516 | -// Add this to your plugin's main PHP file | |
| 517 | -public function mxchat_check_new_messages() { | |
| 518 | - if (!isset($_POST['session_id']) || !isset($_POST['last_seen_id'])) { | |
| 519 | - wp_send_json_error(['message' => 'Missing required parameters']); | |
| 520 | - wp_die(); | |
| 521 | - } | |
| 522 | - | |
| 523 | - $session_id = sanitize_text_field($_POST['session_id']); | |
| 524 | - $last_seen_id = sanitize_text_field($_POST['last_seen_id']); | |
| 525 | - | |
| 526 | - // Get chat history | |
| 527 | - $history = get_option("mxchat_history_{$session_id}", []); | |
| 528 | - | |
| 529 | - if (empty($history)) { | |
| 530 | - wp_send_json_success([ | |
| 531 | - 'hasNewMessages' => false, | |
| 532 | - 'new_messages' => [] | |
| 533 | - ]); | |
| 534 | - wp_die(); | |
| 535 | - } | |
| 536 | - | |
| 537 | - // Filter new messages | |
| 538 | - $new_messages = array_filter($history, function($message) use ($last_seen_id) { | |
| 539 | - return isset($message['id']) && $message['id'] > $last_seen_id; | |
| 540 | - }); | |
| 541 | - | |
| 542 | - // Sort by ID to ensure proper order | |
| 543 | - usort($new_messages, function($a, $b) { | |
| 544 | - return $a['id'] <=> $b['id']; | |
| 545 | - }); | |
| 546 | - | |
| 547 | - wp_send_json_success([ | |
| 548 | - 'hasNewMessages' => !empty($new_messages), | |
| 549 | - 'new_messages' => array_values($new_messages), | |
| 550 | - 'latestMessageId' => end($new_messages)['id'] ?? $last_seen_id | |
| 551 | - ]); | |
| 552 | - wp_die(); | |
| 553 | -} | |
| 554 | - | |
| 555 | 498 | public function mxchat_handle_chat_request() { |
| 556 | 499 | global $wpdb; |
| 557 | 500 | |
| 558 | - | |
| 559 | - // Check if MX Chat Moderation is active | |
| 560 | - if (class_exists('MX_Chat_Moderation')) { | |
| 561 | - // Get user email and IP | |
| 562 | - $user_email = ''; | |
| 563 | - $user_ip = $_SERVER['REMOTE_ADDR']; | |
| 564 | - | |
| 565 | - // If user is logged in, get their email | |
| 566 | - if (is_user_logged_in()) { | |
| 567 | - $current_user = wp_get_current_user(); | |
| 568 | - $user_email = $current_user->user_email; | |
| 569 | - } | |
| 570 | - | |
| 571 | - // Create ban handler instance | |
| 572 | - $ban_handler = new MX_Chat_Ban_Handler(); | |
| 573 | - | |
| 574 | - // Check if user is banned by IP | |
| 575 | - if ($ban_handler->check_ban($user_ip, 'ip')) { | |
| 576 | - wp_send_json([ | |
| 577 | - 'success' => false, | |
| 578 | - 'message' => esc_html__('Access denied. Your IP address has been banned.', 'mxchat'), | |
| 579 | - 'status' => 'banned' | |
| 580 | - ]); | |
| 581 | - wp_die(); | |
| 582 | - } | |
| 583 | - | |
| 584 | - // If user is logged in, also check email | |
| 585 | - if (!empty($user_email) && $ban_handler->check_ban($user_email, 'email')) { | |
| 586 | - wp_send_json([ | |
| 587 | - 'success' => false, | |
| 588 | - 'message' => esc_html__('Access denied. Your email address has been banned.', 'mxchat'), | |
| 589 | - 'status' => 'banned' | |
| 590 | - ]); | |
| 591 | - wp_die(); | |
| 592 | - } | |
| 593 | - } | |
| 594 | - | |
| 595 | - | |
| 596 | 501 | // Reset fallback response at the start of each request |
| 597 | 502 | $this->fallbackResponse = ['text' => '', 'html' => '', 'images' => []]; |
| 598 | 503 | $this->productCardHtml = ''; |
| 599 | 504 | |
| 600 | - // Get the actual WordPress user ID if logged in | |
| 601 | - $is_logged_in = is_user_logged_in(); | |
| 602 | - if ($is_logged_in) { | |
| 603 | - $user_id = get_current_user_id(); // This will get the actual WordPress user ID | |
| 604 | - } else { | |
| 605 | - // For logged-out users, use your existing identifier method | |
| 606 | - $user_id = $this->mxchat_get_user_identifier(); | |
| 607 | - } | |
| 608 | - | |
| 609 | 505 | // Get and sanitize the user identifier |
| 506 | + $user_id = $this->mxchat_get_user_identifier(); | |
| 610 | 507 | $user_id = sanitize_key($user_id); |
| 611 | 508 | |
| 612 | 509 | // Determine if user is logged in |
| 613 | 510 | $is_logged_in = is_user_logged_in(); |
| 614 | - //error_log("User logged in status: " . ($is_logged_in ? 'true' : 'false')); | |
| 615 | 511 | |
| 616 | 512 | // Get rate limit based on user status |
| 617 | - // Get rate limit based on user status | |
| 618 | 513 | $rate_limit = $is_logged_in |
| 619 | - ? $this->get_user_role_rate_limit($user_id) | |
| 620 | - : ($this->options['rate_limit_logged_out'] ?? '10'); | |
| 514 | + ? $this->options['rate_limit_logged_in'] ?? '100' | |
| 515 | + : $this->options['rate_limit_logged_out'] ?? '10'; | |
| 621 | 516 | |
| 622 | - //error_log("Selected rate limit: " . $rate_limit); | |
| 623 | - | |
| 624 | - // Rest of your code remains the same | |
| 625 | 517 | // If rate limit is 'unlimited', skip rate limiting checks |
| 626 | 518 | if ($rate_limit !== 'unlimited') { |
| 627 | 519 | // Convert rate limit to integer |
| 628 | 520 | $rate_limit = intval($rate_limit); |
| 521 | + | |
| 629 | 522 | // Setup rate limiting |
| 630 | 523 | $rate_limit_transient_key = 'mxchat_chat_limit_' . $user_id; |
| 631 | 524 | $chat_count = get_transient($rate_limit_transient_key); |
| 525 | + | |
| 632 | 526 | if ($chat_count === false) { |
| 633 | 527 | // Initialize new counter if none exists |
| 634 | 528 | $chat_count = 0; |
| 635 | 529 | } |
| 530 | + | |
| 636 | 531 | // Check if user has exceeded their rate limit |
| 637 | 532 | if ($chat_count >= $rate_limit) { |
| 638 | 533 | // Get custom rate limit message or use default |
| 639 | 534 | $rate_limit_message = isset($this->options['rate_limit_message']) |
| 640 | 535 | ? $this->options['rate_limit_message'] |
| 641 | - : esc_html__('Rate limit exceeded. Please try again later.', 'mxchat'); | |
| 536 | + : 'Rate limit exceeded. Please try again later.'; | |
| 537 | + | |
| 642 | 538 | // Replace placeholder if it exists in the message |
| 643 | 539 | $rate_limit_message = str_replace( |
| 644 | 540 | array('{limit}', '{count}', '{remaining}'), |
| 645 | 541 | array($rate_limit, $chat_count, max(0, $rate_limit - $chat_count)), |
| @@ -644,8 +540,9 @@ | ||
| 644 | 540 | array('{limit}', '{count}', '{remaining}'), |
| 645 | 541 | array($rate_limit, $chat_count, max(0, $rate_limit - $chat_count)), |
| 646 | 542 | $rate_limit_message |
| 647 | 543 | ); |
| 544 | + | |
| 648 | 545 | wp_send_json([ |
| 649 | 546 | 'success' => false, |
| 650 | 547 | 'message' => $rate_limit_message, |
| 651 | 548 | 'status' => 'rate_limit_exceeded', |
| @@ -653,10 +550,12 @@ | ||
| 653 | 550 | 'count' => $chat_count |
| 654 | 551 | ]); |
| 655 | 552 | wp_die(); |
| 656 | 553 | } |
| 554 | + | |
| 657 | 555 | // Increment the counter |
| 658 | 556 | $chat_count++; |
| 557 | + | |
| 659 | 558 | // Store the updated count with 24-hour expiration |
| 660 | 559 | set_transient($rate_limit_transient_key, $chat_count, DAY_IN_SECONDS); |
| 661 | 560 | } |
| 662 | 561 | |
| @@ -665,9 +564,9 @@ | ||
| 665 | 564 | //error_log("Session ID: $session_id"); |
| 666 | 565 | |
| 667 | 566 | if (empty($session_id)) { |
| 668 | 567 | //error_log("Error: Session ID is missing."); |
| 669 | - wp_send_json_error(esc_html__('Session ID is missing.', 'mxchat')); | |
| 568 | + wp_send_json_error('Session ID is missing.'); | |
| 670 | 569 | wp_die(); |
| 671 | 570 | } |
| 672 | 571 | |
| 673 | 572 | // Validate and sanitize the incoming message |
| @@ -672,39 +571,16 @@ | ||
| 672 | 571 | |
| 673 | 572 | // Validate and sanitize the incoming message |
| 674 | 573 | if (empty($_POST['message'])) { |
| 675 | 574 | //error_log("Error: No message received."); |
| 676 | - wp_send_json_error(esc_html__('No message received.', 'mxchat')); | |
| 575 | + wp_send_json_error('No message received.'); | |
| 677 | 576 | wp_die(); |
| 678 | 577 | } |
| 679 | 578 | |
| 680 | 579 | |
| 681 | -// Modify the message sanitization to preserve PHP tags in code blocks | |
| 682 | -$allowed_tags = [ | |
| 683 | - 'pre' => [], | |
| 684 | - 'code' => ['class' => true], | |
| 685 | - 'span' => ['class' => true], | |
| 686 | - 'div' => ['class' => true], | |
| 687 | -]; | |
| 580 | + $message = wp_strip_all_tags($_POST['message'], false); | |
| 581 | + $message = trim($message); | |
| 688 | 582 | |
| 689 | -// First preserve code blocks | |
| 690 | -$message = preg_replace_callback('/<pre><code.*?>.*?<\/code><\/pre>/s', function($matches) { | |
| 691 | - return htmlspecialchars_decode($matches[0]); | |
| 692 | -}, $_POST['message']); | |
| 693 | - | |
| 694 | -// Then apply sanitization | |
| 695 | -$message = wp_kses($message, $allowed_tags); | |
| 696 | - | |
| 697 | -// Decode code blocks | |
| 698 | -$message = preg_replace_callback('/(<pre><code.*?>.*?<\/code><\/pre>)/s', function($matches) { | |
| 699 | - return htmlspecialchars_decode($matches[1]); | |
| 700 | -}, $message); | |
| 701 | - | |
| 702 | -$message = trim($message); | |
| 703 | - | |
| 704 | -// Preserve code blocks from markdown conversion | |
| 705 | -$message = preg_replace('/```(\w+)?\s*([\s\S]+?)```/s', '<pre><code class="$1">$2</code></pre>', $message); | |
| 706 | - | |
| 707 | 583 | // Save the user's message |
| 708 | 584 | $this->mxchat_save_chat_message($session_id, 'user', $message); |
| 709 | 585 | |
| 710 | 586 | // Check if the message is an email address |
| @@ -713,9 +589,9 @@ | ||
| 713 | 589 | $this->add_email_to_loops($message); |
| 714 | 590 | |
| 715 | 591 | // Send success response |
| 716 | 592 | $response_message = $this->options['email_capture_response'] ?? |
| 717 | - esc_html__('Thank you! Your coupon is on the way!', 'mxchat'); | |
| 593 | + 'Thank you! Your coupon is on the way!'; | |
| 718 | 594 | |
| 719 | 595 | wp_send_json([ |
| 720 | 596 | 'success' => true, |
| 721 | 597 | 'status' => 'email_captured', |
| @@ -753,9 +629,9 @@ | ||
| 753 | 629 | 'chat_mode' => 'ai' |
| 754 | 630 | ]; |
| 755 | 631 | |
| 756 | 632 | // Save the mode switch message |
| 757 | - $this->mxchat_save_chat_message($session_id, 'system', esc_html__('Switched to AI chat mode', 'mxchat')); | |
| 633 | + $this->mxchat_save_chat_message($session_id, 'system', 'Switched to AI chat mode'); | |
| 758 | 634 | $this->mxchat_save_chat_message($session_id, 'bot', $this->fallbackResponse['text']); |
| 759 | 635 | |
| 760 | 636 | // Send response and exit |
| 761 | 637 | wp_send_json($response_data); |
| @@ -767,13 +643,13 @@ | ||
| 767 | 643 | //error_log("Message sent to agent."); |
| 768 | 644 | |
| 769 | 645 | wp_send_json_success([ |
| 770 | 646 | 'status' => 'waiting_for_agent', |
| 771 | - 'message' => esc_html__('Message sent to live agent.', 'mxchat') | |
| 647 | + 'message' => 'Message sent to live agent.' | |
| 772 | 648 | ]); |
| 773 | 649 | } catch (\Exception $e) { |
| 774 | 650 | //error_log("Error sending message to agent: " . $e->getMessage()); |
| 775 | - wp_send_json_error(esc_html__('Failed to send message to agent', 'mxchat')); | |
| 651 | + wp_send_json_error('Failed to send message to agent'); | |
| 776 | 652 | } |
| 777 | 653 | wp_die(); |
| 778 | 654 | } |
| 779 | 655 | } |
| @@ -809,9 +685,9 @@ | ||
| 809 | 685 | |
| 810 | 686 | if ($embeddings === 'too_many_pages') { |
| 811 | 687 | $error_text = sprintf( |
| 812 | 688 | $this->options['pdf_intent_error_text'] ?? |
| 813 | - esc_html__("The provided PDF exceeds the maximum allowed limit of %d pages. Please provide a smaller document.", 'mxchat'), | |
| 689 | + "The provided PDF exceeds the maximum allowed limit of %d pages. Please provide a smaller document.", | |
| 814 | 690 | $max_pages |
| 815 | 691 | ); |
| 816 | 692 | $this->fallbackResponse['text'] = $error_text; |
| 817 | 693 | } elseif ($embeddings) { |
| @@ -831,9 +707,9 @@ | ||
| 831 | 707 | set_transient('mxchat_pdf_embeddings_' . $session_id, $embeddings, HOUR_IN_SECONDS); |
| 832 | 708 | set_transient('mxchat_include_pdf_in_context_' . $session_id, true, HOUR_IN_SECONDS); |
| 833 | 709 | |
| 834 | 710 | $success_text = $this->options['pdf_intent_success_text'] ?? |
| 835 | - esc_html__("I've processed the new PDF '{$pdf_filename}'. What questions do you have about it?", 'mxchat'); | |
| 711 | + "I've processed the new PDF '{$pdf_filename}'. What questions do you have about it?"; | |
| 836 | 712 | |
| 837 | 713 | // Return success with filename for UI update |
| 838 | 714 | wp_send_json([ |
| 839 | 715 | 'success' => true, |
| @@ -844,9 +720,9 @@ | ||
| 844 | 720 | ]); |
| 845 | 721 | wp_die(); |
| 846 | 722 | } else { |
| 847 | 723 | $error_text = $this->options['pdf_intent_error_text'] ?? |
| 848 | - esc_html__("Sorry, I couldn't process the PDF. Please ensure it's a valid file.", 'mxchat'); | |
| 724 | + "Sorry, I couldn't process the PDF. Please ensure it's a valid file."; | |
| 849 | 725 | $this->fallbackResponse['text'] = $error_text; |
| 850 | 726 | } |
| 851 | 727 | |
| 852 | 728 | wp_send_json([ |
| @@ -885,9 +761,9 @@ | ||
| 885 | 761 | // Generate embedding for the user's query |
| 886 | 762 | $user_message_embedding = $this->mxchat_generate_embedding($message, $this->options['api_key']); |
| 887 | 763 | if (!is_array($user_message_embedding)) { |
| 888 | 764 | //error_log("Failed to generate message embedding for session $session_id"); |
| 889 | - wp_send_json_error(esc_html__('Error processing your message.', 'mxchat')); | |
| 765 | + wp_send_json_error('Error processing your message.'); | |
| 890 | 766 | wp_die(); |
| 891 | 767 | } |
| 892 | 768 | |
| 893 | 769 | // Build context with both knowledge base and PDF content if available |
| @@ -934,9 +810,8 @@ | ||
| 934 | 810 | $context_content, |
| 935 | 811 | $this->options['api_key'], |
| 936 | 812 | $this->options['xai_api_key'], |
| 937 | 813 | $this->options['claude_api_key'], |
| 938 | - $this->options['deepseek_api_key'], | |
| 939 | 814 | $conversation_history |
| 940 | 815 | ); |
| 941 | 816 | |
| 942 | 817 | $this->mxchat_save_chat_message($session_id, 'bot', $response); |
| @@ -980,106 +855,81 @@ | ||
| 980 | 855 | |
| 981 | 856 | // New function to check intents and invoke the callback function |
| 982 | 857 | private function mxchat_check_intent_and_invoke_callback($message, $user_id, $session_id) { |
| 983 | 858 | global $wpdb; |
| 859 | + | |
| 860 | + // Check chat mode | |
| 984 | 861 | $chat_mode = get_option("mxchat_mode_{$session_id}", 'ai'); |
| 985 | - | |
| 986 | - //error_log("[MxChat] Checking intents for message: " . $message); | |
| 987 | - | |
| 862 | + //error_log("Checking intents for mode: " . $chat_mode); | |
| 863 | + | |
| 988 | 864 | // Generate the user embedding |
| 989 | 865 | $user_embedding = $this->mxchat_generate_embedding($message, $this->options['api_key']); |
| 990 | 866 | if (!is_array($user_embedding)) { |
| 991 | - //error_log("[MxChat] Failed to generate user embedding"); | |
| 867 | + //error_log("Failed to generate user embedding"); | |
| 992 | 868 | return false; |
| 993 | 869 | } |
| 994 | - | |
| 870 | + | |
| 995 | 871 | // Fetch intents from the database |
| 996 | 872 | $table_name = $wpdb->prefix . 'mxchat_intents'; |
| 873 | + | |
| 997 | 874 | if ($chat_mode === 'agent') { |
| 875 | + // Only fetch the switch intent when in agent mode | |
| 998 | 876 | $query = $wpdb->prepare( |
| 999 | 877 | "SELECT * FROM $table_name WHERE callback_function = %s", |
| 1000 | 878 | 'mxchat_handle_switch_to_chatbot_intent' |
| 1001 | 879 | ); |
| 880 | + //error_log("Searching for switch intent with query: " . $query); | |
| 1002 | 881 | $intents = $wpdb->get_results($query); |
| 882 | + //error_log("Found " . count($intents) . " switch intents"); | |
| 1003 | 883 | } else { |
| 1004 | 884 | $intents = $wpdb->get_results("SELECT * FROM $table_name"); |
| 1005 | 885 | } |
| 1006 | - | |
| 1007 | - //error_log("[MxChat] Found " . count($intents) . " intents to check"); | |
| 1008 | - | |
| 886 | + | |
| 1009 | 887 | if (empty($intents)) { |
| 1010 | - //error_log("[MxChat] No intents found in database"); | |
| 888 | + //error_log("No intents found in database"); | |
| 1011 | 889 | return false; |
| 1012 | 890 | } |
| 1013 | - | |
| 891 | + | |
| 1014 | 892 | $highest_similarity = -INF; |
| 1015 | 893 | $matched_intent = null; |
| 1016 | - | |
| 894 | + | |
| 1017 | 895 | foreach ($intents as $intent) { |
| 1018 | - //error_log("[MxChat] Checking intent: " . $intent->intent_label . " (callback: " . $intent->callback_function . ")"); | |
| 1019 | - | |
| 896 | + //error_log("Checking intent: " . $intent->intent_label); | |
| 1020 | 897 | $intent_embedding_serialized = $intent->embedding_vector; |
| 1021 | 898 | $intent_embedding = $intent_embedding_serialized |
| 1022 | 899 | ? unserialize($intent_embedding_serialized, ['allowed_classes' => false]) |
| 1023 | 900 | : null; |
| 1024 | - | |
| 901 | + | |
| 1025 | 902 | if (!is_array($intent_embedding)) { |
| 1026 | - //error_log("[MxChat] Invalid embedding for intent: " . $intent->intent_label); | |
| 903 | + //error_log("Invalid embedding for intent: " . $intent->intent_label); | |
| 1027 | 904 | continue; |
| 1028 | 905 | } |
| 1029 | - | |
| 906 | + | |
| 1030 | 907 | $similarity = $this->mxchat_calculate_cosine_similarity($user_embedding, $intent_embedding); |
| 1031 | 908 | $intent_threshold = isset($intent->similarity_threshold) ? $intent->similarity_threshold : 0.85; |
| 1032 | - | |
| 1033 | - //error_log("[MxChat] Similarity for {$intent->intent_label}: {$similarity} (threshold: {$intent_threshold})"); | |
| 1034 | - | |
| 909 | + //error_log("Similarity for " . $intent->intent_label . ": " . $similarity . " (threshold: " . $intent_threshold . ")"); | |
| 910 | + | |
| 1035 | 911 | if ($similarity >= $intent_threshold && $similarity > $highest_similarity) { |
| 1036 | 912 | $highest_similarity = $similarity; |
| 1037 | 913 | $matched_intent = $intent; |
| 1038 | - //error_log("[MxChat] New best match: {$intent->intent_label} with similarity {$similarity}"); | |
| 914 | + //error_log("New best match: " . $intent->intent_label . " with similarity " . $similarity); | |
| 1039 | 915 | } |
| 1040 | 916 | } |
| 1041 | - | |
| 1042 | - if ($matched_intent) { | |
| 1043 | - //error_log("[MxChat] Invoking callback: " . $matched_intent->callback_function); | |
| 1044 | - | |
| 1045 | - // If the callback is a method on this instance (core callback), call it directly | |
| 1046 | - if (method_exists($this, $matched_intent->callback_function)) { | |
| 1047 | - $callback_result = call_user_func( | |
| 1048 | - [$this, $matched_intent->callback_function], | |
| 1049 | - $message, | |
| 1050 | - $user_id, | |
| 1051 | - $session_id, | |
| 1052 | - $matched_intent | |
| 1053 | - ); | |
| 1054 | - } else { | |
| 1055 | - // Otherwise, use apply_filters for add-on callbacks | |
| 1056 | - $callback_result = apply_filters( | |
| 1057 | - $matched_intent->callback_function, | |
| 1058 | - false, // default return value | |
| 1059 | - $message, | |
| 1060 | - $user_id, | |
| 1061 | - $session_id, | |
| 1062 | - $matched_intent | |
| 1063 | - ); | |
| 1064 | - } | |
| 1065 | - | |
| 1066 | - //error_log("[MxChat] Callback result: " . print_r($callback_result, true)); | |
| 1067 | - if ($callback_result !== false) { | |
| 1068 | - $this->fallbackResponse = $callback_result; | |
| 1069 | - return true; | |
| 1070 | - } | |
| 917 | + | |
| 918 | + if ($matched_intent && method_exists($this, $matched_intent->callback_function)) { | |
| 919 | + //error_log("Calling callback function: " . $matched_intent->callback_function); | |
| 920 | + call_user_func([$this, $matched_intent->callback_function], $message, $user_id, $session_id); | |
| 921 | + return true; | |
| 1071 | 922 | } |
| 1072 | - | |
| 1073 | - //error_log("[MxChat] No matching intent found"); | |
| 923 | + | |
| 924 | + //error_log("No matching intent found"); | |
| 1074 | 925 | return false; |
| 1075 | 926 | } |
| 1076 | 927 | |
| 1077 | - | |
| 1078 | 928 | //verified good |
| 1079 | 929 | public function mxchat_handle_order_history($message, $user_id, $session_id) { |
| 1080 | 930 | if (!class_exists('WooCommerce')) { |
| 1081 | - $this->fallbackResponse['text'] = esc_html__("I can't access order information right now. The order system seems to be unavailable.", 'mxchat'); | |
| 931 | + $this->fallbackResponse['text'] = "I can't access order information right now. The order system seems to be unavailable."; | |
| 1082 | 932 | return true; |
| 1083 | 933 | } |
| 1084 | 934 | |
| 1085 | 935 | $orderDetails = MxChat_WooCommerce::mxchat_fetch_user_orders_details('all'); |
| @@ -1084,27 +934,27 @@ | ||
| 1084 | 934 | |
| 1085 | 935 | $orderDetails = MxChat_WooCommerce::mxchat_fetch_user_orders_details('all'); |
| 1086 | 936 | |
| 1087 | 937 | if (empty($orderDetails)) { |
| 1088 | - $this->fallbackResponse['text'] = esc_html__("I don't see any orders associated with your account. Are you logged in?", 'mxchat'); | |
| 938 | + $this->fallbackResponse['text'] = "I don't see any orders associated with your account. Are you logged in?"; | |
| 1089 | 939 | return true; |
| 1090 | 940 | } |
| 1091 | 941 | |
| 1092 | 942 | // Generate AI prompt with context |
| 1093 | - $prompt = __("User asked about their orders:", 'mxchat') . " '{$message}'\n\n"; | |
| 1094 | - $prompt .= __("Order information:", 'mxchat') . "\n"; | |
| 943 | + $prompt = "User asked about their orders: '{$message}'\n\n"; | |
| 944 | + $prompt .= "Order information:\n"; | |
| 1095 | 945 | foreach ($orderDetails as $order) { |
| 1096 | 946 | $items_list = array_map(function($item) { |
| 1097 | 947 | return "{$item['name']} ({$item['quantity']})"; |
| 1098 | 948 | }, $order['items']); |
| 1099 | 949 | |
| 1100 | - $prompt .= __("Order #", 'mxchat') . "{$order['order_id']}: {$order['formatted_total']} " . __("on", 'mxchat') . " {$order['date']}\n"; | |
| 1101 | - $prompt .= __("Items:", 'mxchat') . " " . implode(', ', $items_list) . "\n"; | |
| 950 | + $prompt .= "Order #{$order['order_id']}: {$order['formatted_total']} on {$order['date']}\n"; | |
| 951 | + $prompt .= "Items: " . implode(', ', $items_list) . "\n"; | |
| 1102 | 952 | } |
| 1103 | 953 | |
| 1104 | - $prompt .= __("\nProvide a natural, conversational response focusing on the specific information the user asked about. ", 'mxchat'); | |
| 1105 | - $prompt .= __("If they ask about a specific order or detail, provide just that information. ", 'mxchat'); | |
| 1106 | - $prompt .= __("If they ask about license keys or sensitive information, inform them to check their email or contact support.", 'mxchat'); | |
| 954 | + $prompt .= "\nProvide a natural, conversational response focusing on the specific information the user asked about. "; | |
| 955 | + $prompt .= "If they ask about a specific order or detail, provide just that information. "; | |
| 956 | + $prompt .= "If they ask about license keys or sensitive information, inform them to check their email or contact support."; | |
| 1107 | 957 | |
| 1108 | 958 | // Get AI response |
| 1109 | 959 | $ai_response = $this->mxchat_call_ai_api($prompt); |
| 1110 | 960 | $this->fallbackResponse['text'] = $ai_response['text']; |
| @@ -1152,28 +1002,28 @@ | ||
| 1152 | 1002 | //error_log("Finding relevant content for product inquiry"); |
| 1153 | 1003 | $relevant_content = $this->mxchat_find_relevant_content($user_message_embedding); |
| 1154 | 1004 | |
| 1155 | 1005 | // Build AI prompt |
| 1156 | - $ai_prompt = esc_html__("You are a knowledgeable product assistant. ", 'mxchat'); | |
| 1157 | - $ai_prompt .= esc_html__("Respond to this user query: '{$message}'\n\n", 'mxchat'); | |
| 1006 | + $ai_prompt = "You are a knowledgeable product assistant. "; | |
| 1007 | + $ai_prompt .= "Respond to this user query: '{$message}'\n\n"; | |
| 1158 | 1008 | |
| 1159 | 1009 | if (!empty($relevant_content)) { |
| 1160 | - $ai_prompt .= esc_html__("Relevant information from our knowledge base:\n{$relevant_content}\n\n", 'mxchat'); | |
| 1010 | + $ai_prompt .= "Relevant information from our knowledge base:\n{$relevant_content}\n\n"; | |
| 1161 | 1011 | } |
| 1162 | 1012 | |
| 1163 | - $ai_prompt .= esc_html__("Product details:\n", 'mxchat'); | |
| 1164 | - $ai_prompt .= esc_html__("Name: {$product_name}\n", 'mxchat'); | |
| 1165 | - $ai_prompt .= esc_html__("Price: ", 'mxchat') . strip_tags($product_price) . "\n"; | |
| 1013 | + $ai_prompt .= "Product details:\n"; | |
| 1014 | + $ai_prompt .= "Name: {$product_name}\n"; | |
| 1015 | + $ai_prompt .= "Price: " . strip_tags($product_price) . "\n"; | |
| 1166 | 1016 | if ($product_description) { |
| 1167 | - $ai_prompt .= esc_html__("Description: {$product_description}\n", 'mxchat'); | |
| 1017 | + $ai_prompt .= "Description: {$product_description}\n"; | |
| 1168 | 1018 | } |
| 1169 | 1019 | |
| 1170 | - $ai_prompt .= esc_html__("\nInstructions:\n", 'mxchat'); | |
| 1171 | - $ai_prompt .= esc_html__("1. Address the user's specific question or concern about the product\n", 'mxchat'); | |
| 1172 | - $ai_prompt .= esc_html__("2. Incorporate relevant information from our knowledge base if provided\n", 'mxchat'); | |
| 1173 | - $ai_prompt .= esc_html__("3. Highlight key product features that relate to their query\n", 'mxchat'); | |
| 1174 | - $ai_prompt .= esc_html__("4. Include a natural suggestion to check out the product\n", 'mxchat'); | |
| 1175 | - $ai_prompt .= esc_html__("5. Keep the response conversational and helpful\n", 'mxchat'); | |
| 1020 | + $ai_prompt .= "\nInstructions:\n"; | |
| 1021 | + $ai_prompt .= "1. Address the user's specific question or concern about the product\n"; | |
| 1022 | + $ai_prompt .= "2. Incorporate relevant information from our knowledge base if provided\n"; | |
| 1023 | + $ai_prompt .= "3. Highlight key product features that relate to their query\n"; | |
| 1024 | + $ai_prompt .= "4. Include a natural suggestion to check out the product\n"; | |
| 1025 | + $ai_prompt .= "5. Keep the response conversational and helpful\n"; | |
| 1176 | 1026 | |
| 1177 | 1027 | //error_log("Sending AI prompt: " . $ai_prompt); |
| 1178 | 1028 | |
| 1179 | 1029 | // Build and log AI response |
| @@ -1219,9 +1069,9 @@ | ||
| 1219 | 1069 | // Log the message safely |
| 1220 | 1070 | //error_log("Triggered email capture intent for message: " . sanitize_text_field($message)); |
| 1221 | 1071 | |
| 1222 | 1072 | // Initiate email capture flow |
| 1223 | - $response = esc_html($this->options['triggered_phrase_response'] ?? esc_html__("Would you like to join our mailing list? Please provide your email below.", 'mxchat')); | |
| 1073 | + $response = esc_html($this->options['triggered_phrase_response'] ?? "Would you like to join our mailing list? Please provide your email below."); | |
| 1224 | 1074 | |
| 1225 | 1075 | set_transient('mxchat_email_capture_' . $user_id, true, 5 * MINUTE_IN_SECONDS); |
| 1226 | 1076 | $this->mxchat_save_chat_message($session_id, 'bot', $response); |
| 1227 | 1077 | |
| @@ -1232,9 +1082,9 @@ | ||
| 1232 | 1082 | |
| 1233 | 1083 | //very good |
| 1234 | 1084 | public function mxchat_generate_image($message, $user_id, $session_id) { |
| 1235 | 1085 | // Prepare a prompt for DALL-E |
| 1236 | - $prompt = esc_html__('Create an image of ', 'mxchat') . sanitize_text_field($message); | |
| 1086 | + $prompt = "Create an image of " . sanitize_text_field($message); | |
| 1237 | 1087 | |
| 1238 | 1088 | // Use the existing OpenAI API key |
| 1239 | 1089 | $openai_api_key = sanitize_text_field($this->options['api_key']); |
| 1240 | 1090 | |
| @@ -1245,13 +1095,13 @@ | ||
| 1245 | 1095 | if (isset($image_response['imageUrl'])) { |
| 1246 | 1096 | $image_url = esc_url_raw($image_response['imageUrl']); |
| 1247 | 1097 | |
| 1248 | 1098 | // Construct the HTML with a CSS class instead of inline styles |
| 1249 | - $response_html = '<img src="' . esc_url($image_url) . '" alt="' . esc_attr__('Generated Image', 'mxchat') . '" class="mxchat-generated-image" />'; | |
| 1099 | + $response_html = '<img src="' . esc_url($image_url) . '" alt="Generated Image" class="mxchat-generated-image" />'; | |
| 1250 | 1100 | |
| 1251 | - $response_text = esc_html__('Here is the image I generated:', 'mxchat'); | |
| 1101 | + $response_text = "Here is the image I generated:"; | |
| 1252 | 1102 | } else { |
| 1253 | - $response_text = esc_html__("I'm sorry, but I couldn't generate an image based on your request.", 'mxchat'); | |
| 1103 | + $response_text = "I'm sorry, but I couldn't generate an image based on your request."; | |
| 1254 | 1104 | $response_html = ''; |
| 1255 | 1105 | //error_log("DALL-E image generation error: " . esc_html($image_response['error'] ?? 'Unknown error.')); |
| 1256 | 1106 | } |
| 1257 | 1107 | |
| @@ -1292,9 +1142,9 @@ | ||
| 1292 | 1142 | $response = wp_remote_post($api_url, $args); |
| 1293 | 1143 | |
| 1294 | 1144 | if (is_wp_error($response)) { |
| 1295 | 1145 | //error_log("DALL-E request failed: " . $response->get_error_message()); |
| 1296 | - return ['error' => esc_html__('Error generating image: ', 'mxchat') . $response->get_error_message()]; | |
| 1146 | + return ['error' => "Error generating image: " . $response->get_error_message()]; | |
| 1297 | 1147 | } |
| 1298 | 1148 | |
| 1299 | 1149 | $response_body = json_decode(wp_remote_retrieve_body($response), true); |
| 1300 | 1150 | |
| @@ -1301,9 +1151,9 @@ | ||
| 1301 | 1151 | if (isset($response_body['data'][0]['url'])) { |
| 1302 | 1152 | return ['imageUrl' => esc_url_raw($response_body['data'][0]['url'])]; |
| 1303 | 1153 | } else { |
| 1304 | 1154 | //error_log("DALL-E response error: " . wp_remote_retrieve_body($response)); |
| 1305 | - return ['error' => esc_html__('Failed to generate image.', 'mxchat')]; | |
| 1155 | + return ['error' => "Failed to generate image."]; | |
| 1306 | 1156 | } |
| 1307 | 1157 | } |
| 1308 | 1158 | |
| 1309 | 1159 | /** |
| @@ -1604,9 +1454,9 @@ | ||
| 1604 | 1454 | |
| 1605 | 1455 | foreach ($body['results'] as $image) { |
| 1606 | 1456 | $image_url = isset($image['url']) ? esc_url($image['url']) : ''; |
| 1607 | 1457 | $thumbnail_url = isset($image['thumbnail']['src']) ? esc_url($image['thumbnail']['src']) : ''; |
| 1608 | - $title = isset($image['title']) ? esc_html($image['title']) : esc_html__('Image', 'mxchat'); | |
| 1458 | + $title = isset($image['title']) ? esc_html($image['title']) : __('Image', 'mxchat'); | |
| 1609 | 1459 | |
| 1610 | 1460 | if ($image_url && $thumbnail_url) { |
| 1611 | 1461 | $html_output .= '<div class="mxchat-image-item">'; |
| 1612 | 1462 | $html_output .= '<strong class="mxchat-image-title">' . $title . '</strong>'; |
| @@ -1639,20 +1489,21 @@ | ||
| 1639 | 1489 | ]; |
| 1640 | 1490 | } |
| 1641 | 1491 | } |
| 1642 | 1492 | public function mxchat_interpret_search_query($user_query) { |
| 1643 | - $system_prompt = esc_html__("Interpret the user's request to provide only the essential keywords or phrases for image searching. Remove conversational language, politeness, or extra context. Return a concise search query that doesn't lose any of the original meaning.", 'mxchat'); | |
| 1493 | + $system_prompt = "Interpret the user's request to provide only the essential keywords or phrases for image searching. Remove conversational language, politeness, or extra context. Return a concise search query that doesn't lose any of the original meaning."; | |
| 1644 | 1494 | |
| 1645 | 1495 | // Retrieve OpenAI API key using 'api_key' as the option key |
| 1646 | 1496 | $api_key = isset($this->options['api_key']) ? sanitize_text_field($this->options['api_key']) : sanitize_text_field(get_option('mxchat_options')['api_key']); |
| 1647 | 1497 | |
| 1648 | - /* | |
| 1498 | +/* | |
| 1649 | 1499 | // Log the API key check, without exposing the key |
| 1650 | 1500 | if (defined('WP_DEBUG') && WP_DEBUG) { |
| 1651 | 1501 | error_log("Retrieved OpenAI API Key: " . ($api_key ? "Present" : "Missing")); |
| 1652 | 1502 | } |
| 1653 | - */ | |
| 1503 | +*/ | |
| 1654 | 1504 | |
| 1505 | + | |
| 1655 | 1506 | if (empty($api_key)) { |
| 1656 | 1507 | //error_log("OpenAI API key is missing."); |
| 1657 | 1508 | return sanitize_text_field($user_query); // Default to the original query if API key is missing |
| 1658 | 1509 | } |
| @@ -1687,14 +1538,14 @@ | ||
| 1687 | 1538 | // Check for a valid response and sanitize output |
| 1688 | 1539 | if (isset($body['choices'][0]['message']['content'])) { |
| 1689 | 1540 | $interpreted_query = sanitize_text_field(trim($body['choices'][0]['message']['content'])); |
| 1690 | 1541 | |
| 1691 | - /* | |
| 1542 | +/* | |
| 1692 | 1543 | // Log the interpreted query for debugging |
| 1693 | 1544 | if (defined('WP_DEBUG') && WP_DEBUG) { |
| 1694 | 1545 | error_log("Interpreted search query: " . $interpreted_query); |
| 1695 | 1546 | } |
| 1696 | - */ | |
| 1547 | +*/ | |
| 1697 | 1548 | |
| 1698 | 1549 | return $interpreted_query; |
| 1699 | 1550 | } else { |
| 1700 | 1551 | //error_log("Unexpected API response format: " . print_r($body, true)); |
| @@ -1709,9 +1560,9 @@ | ||
| 1709 | 1560 | //error_log("WooCommerce not available"); |
| 1710 | 1561 | return $this->generate_intent_response([ |
| 1711 | 1562 | 'intent' => 'add_to_cart', |
| 1712 | 1563 | 'status' => 'error', |
| 1713 | - 'reason' => esc_html__('woocommerce_not_available', 'mxchat') | |
| 1564 | + 'reason' => 'woocommerce_not_available' | |
| 1714 | 1565 | ], $session_id); |
| 1715 | 1566 | } |
| 1716 | 1567 | |
| 1717 | 1568 | $sanitized_user_id = sanitize_key($user_id); |
| @@ -1742,10 +1593,10 @@ | ||
| 1742 | 1593 | //error_log("No product ID found through any method"); |
| 1743 | 1594 | return $this->generate_intent_response([ |
| 1744 | 1595 | 'intent' => 'add_to_cart', |
| 1745 | 1596 | 'status' => 'error', |
| 1746 | - 'reason' => esc_html__('no_product_context', 'mxchat'), | |
| 1747 | - 'action_needed' => esc_html__('request_product_name', 'mxchat'), | |
| 1597 | + 'reason' => 'no_product_context', | |
| 1598 | + 'action_needed' => 'request_product_name', | |
| 1748 | 1599 | 'searched_message' => $message |
| 1749 | 1600 | ], $session_id); |
| 1750 | 1601 | } |
| 1751 | 1602 | |
| @@ -1755,9 +1606,9 @@ | ||
| 1755 | 1606 | //error_log("Product not found with ID: $product_id"); |
| 1756 | 1607 | return $this->generate_intent_response([ |
| 1757 | 1608 | 'intent' => 'add_to_cart', |
| 1758 | 1609 | 'status' => 'error', |
| 1759 | - 'reason' => esc_html__('product_not_found', 'mxchat'), | |
| 1610 | + 'reason' => 'product_not_found', | |
| 1760 | 1611 | 'product_id' => $product_id |
| 1761 | 1612 | ], $session_id); |
| 1762 | 1613 | } |
| 1763 | 1614 | |
| @@ -1775,11 +1626,11 @@ | ||
| 1775 | 1626 | 'id' => $product_id |
| 1776 | 1627 | ], |
| 1777 | 1628 | 'cart_url' => wc_get_cart_url(), |
| 1778 | 1629 | 'available_actions' => [ |
| 1779 | - esc_html__('view_cart', 'mxchat'), | |
| 1780 | - esc_html__('checkout', 'mxchat'), | |
| 1781 | - esc_html__('continue_shopping', 'mxchat') | |
| 1630 | + 'view_cart', | |
| 1631 | + 'checkout', | |
| 1632 | + 'continue_shopping' | |
| 1782 | 1633 | ] |
| 1783 | 1634 | ], $session_id); |
| 1784 | 1635 | } else { |
| 1785 | 1636 | //error_log("Failed to add to cart: " . $product->get_name()); |
| @@ -1785,9 +1636,9 @@ | ||
| 1785 | 1636 | //error_log("Failed to add to cart: " . $product->get_name()); |
| 1786 | 1637 | return $this->generate_intent_response([ |
| 1787 | 1638 | 'intent' => 'add_to_cart', |
| 1788 | 1639 | 'status' => 'error', |
| 1789 | - 'reason' => esc_html__('add_to_cart_failed', 'mxchat'), | |
| 1640 | + 'reason' => 'add_to_cart_failed', | |
| 1790 | 1641 | 'product' => [ |
| 1791 | 1642 | 'name' => $product->get_name(), |
| 1792 | 1643 | 'id' => $product_id |
| 1793 | 1644 | ] |
| @@ -1806,9 +1657,9 @@ | ||
| 1806 | 1657 | // Get relevant content as string |
| 1807 | 1658 | $relevant_content = $this->mxchat_find_relevant_products($query_embedding); |
| 1808 | 1659 | if (empty($relevant_content)) { |
| 1809 | 1660 | // Return null to indicate no results and set fallback response |
| 1810 | - $this->fallbackResponse['text'] = esc_html__("I couldn't find any relevant products based on your query. Could you please be more specific about the product you're looking for?", 'mxchat'); | |
| 1661 | + $this->fallbackResponse['text'] = "I couldn't find any relevant products based on your query. Could you please be more specific about the product you're looking for?"; | |
| 1811 | 1662 | return null; |
| 1812 | 1663 | } |
| 1813 | 1664 | |
| 1814 | 1665 | // Extract product URLs from the content |
| @@ -1861,9 +1712,9 @@ | ||
| 1861 | 1712 | } |
| 1862 | 1713 | } |
| 1863 | 1714 | |
| 1864 | 1715 | // If no product is found after all checks, set the fallback response |
| 1865 | - $this->fallbackResponse['text'] = esc_html__("I couldn't find any relevant products based on your query. Try to be more specific", 'mxchat'); | |
| 1716 | + $this->fallbackResponse['text'] = "I couldn't find any relevant products based on your query. Try to be more specific"; | |
| 1866 | 1717 | return null; |
| 1867 | 1718 | } |
| 1868 | 1719 | |
| 1869 | 1720 | // New method to handle intent responses |
| @@ -1876,9 +1727,8 @@ | ||
| 1876 | 1727 | $context_string, |
| 1877 | 1728 | $this->options['api_key'], |
| 1878 | 1729 | $this->options['xai_api_key'], |
| 1879 | 1730 | $this->options['claude_api_key'], |
| 1880 | - $this->options['deepseek_api_key'], | |
| 1881 | 1731 | $this->mxchat_fetch_conversation_history_for_ai($session_id) |
| 1882 | 1732 | ); |
| 1883 | 1733 | |
| 1884 | 1734 | $this->fallbackResponse['text'] = $response; |
| @@ -1885,33 +1735,33 @@ | ||
| 1885 | 1735 | return true; |
| 1886 | 1736 | } |
| 1887 | 1737 | // Helper method to format intent context |
| 1888 | 1738 | private function format_intent_context($context) { |
| 1889 | - $context_string = esc_html__("INTENT CONTEXT:\n", 'mxchat'); | |
| 1739 | + $context_string = "INTENT CONTEXT:\n"; | |
| 1890 | 1740 | |
| 1891 | 1741 | switch ($context['intent']) { |
| 1892 | 1742 | case 'add_to_cart': |
| 1893 | 1743 | if ($context['status'] === 'success') { |
| 1894 | - $context_string .= esc_html__("Action: Successfully added product to cart\n", 'mxchat'); | |
| 1895 | - $context_string .= sprintf(esc_html__("Product: %s\n", 'mxchat'), $context['product']['name']); | |
| 1896 | - $context_string .= esc_html__("Available actions: ", 'mxchat') . implode(', ', $context['available_actions']) . "\n"; | |
| 1897 | - $context_string .= sprintf(esc_html__("Cart URL: %s\n", 'mxchat'), $context['cart_url']); | |
| 1898 | - $context_string .= esc_html__("\nPlease inform the user of the successful addition and their available options.", 'mxchat'); | |
| 1744 | + $context_string .= "Action: Successfully added product to cart\n"; | |
| 1745 | + $context_string .= "Product: {$context['product']['name']}\n"; | |
| 1746 | + $context_string .= "Available actions: " . implode(', ', $context['available_actions']) . "\n"; | |
| 1747 | + $context_string .= "Cart URL: {$context['cart_url']}\n"; | |
| 1748 | + $context_string .= "\nPlease inform the user of the successful addition and their available options."; | |
| 1899 | 1749 | } else { |
| 1900 | - $context_string .= esc_html__("Action: Failed to add product to cart\n", 'mxchat'); | |
| 1901 | - $context_string .= sprintf(esc_html__("Reason: %s\n", 'mxchat'), $context['reason']); | |
| 1750 | + $context_string .= "Action: Failed to add product to cart\n"; | |
| 1751 | + $context_string .= "Reason: {$context['reason']}\n"; | |
| 1902 | 1752 | switch ($context['reason']) { |
| 1903 | 1753 | case 'woocommerce_not_available': |
| 1904 | - $context_string .= esc_html__("\nPlease inform the user that shopping features are not available.", 'mxchat'); | |
| 1754 | + $context_string .= "\nPlease inform the user that shopping features are not available."; | |
| 1905 | 1755 | break; |
| 1906 | 1756 | case 'no_product_context': |
| 1907 | - $context_string .= esc_html__("\nPlease ask the user to specify which product they want to add.", 'mxchat'); | |
| 1757 | + $context_string .= "\nPlease ask the user to specify which product they want to add."; | |
| 1908 | 1758 | break; |
| 1909 | 1759 | case 'product_not_found': |
| 1910 | - $context_string .= esc_html__("\nPlease inform the user that the product couldn't be found and ask them to try again.", 'mxchat'); | |
| 1760 | + $context_string .= "\nPlease inform the user that the product couldn't be found and ask them to try again."; | |
| 1911 | 1761 | break; |
| 1912 | 1762 | case 'add_to_cart_failed': |
| 1913 | - $context_string .= esc_html__("\nPlease apologize to the user and suggest they try again or ask for assistance.", 'mxchat'); | |
| 1763 | + $context_string .= "\nPlease apologize to the user and suggest they try again or ask for assistance."; | |
| 1914 | 1764 | break; |
| 1915 | 1765 | } |
| 1916 | 1766 | } |
| 1917 | 1767 | break; |
| @@ -1922,15 +1772,15 @@ | ||
| 1922 | 1772 | |
| 1923 | 1773 | |
| 1924 | 1774 | public function mxchat_handle_checkout_intent($message, $user_id, $session_id) { |
| 1925 | 1775 | if (!class_exists('WooCommerce')) { |
| 1926 | - $this->fallbackResponse['text'] = esc_html__("I apologize, but the checkout feature isn't available at the moment.", 'mxchat'); | |
| 1776 | + $this->fallbackResponse['text'] = "I apologize, but the checkout feature isn't available at the moment."; | |
| 1927 | 1777 | return true; |
| 1928 | 1778 | } |
| 1929 | 1779 | |
| 1930 | 1780 | // Check if cart has items |
| 1931 | 1781 | if (WC()->cart->is_empty()) { |
| 1932 | - $this->fallbackResponse['text'] = esc_html__("Your cart is empty at the moment. Would you like to see our products?", 'mxchat'); | |
| 1782 | + $this->fallbackResponse['text'] = "Your cart is empty at the moment. Would you like to see our products?"; | |
| 1933 | 1783 | return true; |
| 1934 | 1784 | } |
| 1935 | 1785 | |
| 1936 | 1786 | // Get cart summary |
| @@ -1939,17 +1789,17 @@ | ||
| 1939 | 1789 | |
| 1940 | 1790 | // Get and validate checkout URL |
| 1941 | 1791 | $checkout_url = wc_get_checkout_url(); |
| 1942 | 1792 | if (!$checkout_url) { |
| 1943 | - $this->fallbackResponse['text'] = esc_html__("I'm having trouble accessing the checkout page. Please try again in a moment.", 'mxchat'); | |
| 1793 | + $this->fallbackResponse['text'] = "I'm having trouble accessing the checkout page. Please try again in a moment."; | |
| 1944 | 1794 | return true; |
| 1945 | 1795 | } |
| 1946 | 1796 | |
| 1947 | 1797 | wp_send_json([ |
| 1948 | 1798 | 'text' => sprintf( |
| 1949 | - esc_html__("You have %d item%s in your cart totaling %s. I'll redirect you to checkout now.", 'mxchat'), | |
| 1799 | + "You have %d item%s in your cart totaling %s. I'll redirect you to checkout now.", | |
| 1950 | 1800 | $cart_count, |
| 1951 | - $cart_count > 1 ? esc_html__('s', 'mxchat') : '', | |
| 1801 | + $cart_count > 1 ? 's' : '', | |
| 1952 | 1802 | strip_tags($cart_total) |
| 1953 | 1803 | ), |
| 1954 | 1804 | 'redirect_url' => esc_url_raw($checkout_url) |
| 1955 | 1805 | ]); |
| @@ -1967,9 +1817,9 @@ | ||
| 1967 | 1817 | $mailing_list_id = isset($this->options['loops_mailing_list']) ? sanitize_text_field($this->options['loops_mailing_list']) : ''; |
| 1968 | 1818 | |
| 1969 | 1819 | // Check for missing API key or mailing list ID |
| 1970 | 1820 | if (empty($api_key) || empty($mailing_list_id)) { |
| 1971 | - //error_log(esc_html__('Loops API key or mailing list ID is missing.', 'mxchat')); | |
| 1821 | + //error_log('Loops API key or mailing list ID is missing.'); | |
| 1972 | 1822 | return; |
| 1973 | 1823 | } |
| 1974 | 1824 | |
| 1975 | 1825 | $data = array( |
| @@ -1974,9 +1824,9 @@ | ||
| 1974 | 1824 | |
| 1975 | 1825 | $data = array( |
| 1976 | 1826 | 'email' => $email, |
| 1977 | 1827 | 'subscribed' => true, |
| 1978 | - 'source' => __('MxChat AI Chatbot', 'mxchat'), | |
| 1828 | + 'source' => 'MxChat AI Chatbot', | |
| 1979 | 1829 | 'mailingLists' => array($mailing_list_id => true), |
| 1980 | 1830 | ); |
| 1981 | 1831 | |
| 1982 | 1832 | $url = 'https://app.loops.so/api/v1/contacts/create'; |
| @@ -1993,9 +1843,9 @@ | ||
| 1993 | 1843 | $response = wp_remote_post($url, $args); |
| 1994 | 1844 | |
| 1995 | 1845 | // Handle errors in the API request |
| 1996 | 1846 | if (is_wp_error($response)) { |
| 1997 | - //error_log(esc_html__('Error adding email to Loops: ', 'mxchat') . $response->get_error_message()); | |
| 1847 | + //error_log('Error adding email to Loops: ' . $response->get_error_message()); | |
| 1998 | 1848 | return; |
| 1999 | 1849 | } |
| 2000 | 1850 | |
| 2001 | 1851 | // Check for non-200 HTTP responses |
| @@ -2001,9 +1851,9 @@ | ||
| 2001 | 1851 | // Check for non-200 HTTP responses |
| 2002 | 1852 | $response_code = wp_remote_retrieve_response_code($response); |
| 2003 | 1853 | if ($response_code != 200) { |
| 2004 | 1854 | $response_body = wp_remote_retrieve_body($response); |
| 2005 | - //error_log(esc_html__('Loops API responded with code ', 'mxchat') . $response_code . ': ' . $response_body); | |
| 1855 | + //error_log('Loops API responded with code ' . $response_code . ': ' . $response_body); | |
| 2006 | 1856 | } |
| 2007 | 1857 | } |
| 2008 | 1858 | |
| 2009 | 1859 | public function mxchat_handle_pdf_discussion($message, $user_id, $session_id) { |
| @@ -2010,11 +1860,11 @@ | ||
| 2010 | 1860 | // Get the maximum number of pages allowed from admin settings |
| 2011 | 1861 | $max_pages = isset($this->options['pdf_max_pages']) ? intval($this->options['pdf_max_pages']) : 69; |
| 2012 | 1862 | |
| 2013 | 1863 | // Retrieve options for dynamic texts |
| 2014 | - $trigger_text = $this->options['pdf_intent_trigger_text'] ?? __("Please provide the URL to the PDF you'd like to discuss.", 'mxchat'); | |
| 2015 | - $success_text = $this->options['pdf_intent_success_text'] ?? __("I've processed the PDF. What questions do you have about it?", 'mxchat'); | |
| 2016 | - $error_text = $this->options['pdf_intent_error_text'] ?? __("Sorry, I couldn't process the PDF. Please ensure it's a valid file.", 'mxchat'); | |
| 1864 | + $trigger_text = $this->options['pdf_intent_trigger_text'] ?? "Please provide the URL to the PDF you'd like to discuss."; | |
| 1865 | + $success_text = $this->options['pdf_intent_success_text'] ?? "I've processed the PDF. What questions do you have about it?"; | |
| 1866 | + $error_text = $this->options['pdf_intent_error_text'] ?? "Sorry, I couldn't process the PDF. Please ensure it's a valid file."; | |
| 2017 | 1867 | |
| 2018 | 1868 | // Check for explicit request for new PDF |
| 2019 | 1869 | $new_pdf_requested = stripos($message, 'new') !== false || |
| 2020 | 1870 | stripos($message, 'another') !== false || |
| @@ -2053,9 +1903,9 @@ | ||
| 2053 | 1903 | $temp_file = wp_tempnam($pdf_source); // Safe temporary file name |
| 2054 | 1904 | $response = wp_remote_get($pdf_source, ['timeout' => 60]); |
| 2055 | 1905 | |
| 2056 | 1906 | if (is_wp_error($response) || wp_remote_retrieve_response_code($response) !== 200) { |
| 2057 | - //error_log(esc_html__("Failed to download PDF. Error: ", 'mxchat') . print_r($response, true)); | |
| 1907 | + //error_log("Failed to download PDF. Error: " . print_r($response, true)); | |
| 2058 | 1908 | return false; |
| 2059 | 1909 | } |
| 2060 | 1910 | |
| 2061 | 1911 | file_put_contents($temp_file, wp_remote_retrieve_body($response)); |
| @@ -2062,9 +1912,9 @@ | ||
| 2062 | 1912 | |
| 2063 | 1913 | // Validate that the downloaded file is a PDF |
| 2064 | 1914 | $mime_type = mime_content_type($temp_file); |
| 2065 | 1915 | if ($mime_type !== 'application/pdf') { |
| 2066 | - //error_log(esc_html__("Invalid MIME type detected for PDF: ", 'mxchat') . $mime_type); | |
| 1916 | + //error_log("Invalid MIME type detected for PDF: $mime_type"); | |
| 2067 | 1917 | unlink($temp_file); |
| 2068 | 1918 | return false; |
| 2069 | 1919 | } |
| 2070 | 1920 | } else { |
| @@ -2077,13 +1927,13 @@ | ||
| 2077 | 1927 | $pdf = $parser->parseFile($temp_file); |
| 2078 | 1928 | $pages = $pdf->getPages(); |
| 2079 | 1929 | |
| 2080 | 1930 | if (count($pages) > $max_pages) { |
| 2081 | - //error_log(esc_html__("PDF exceeds the maximum allowed pages: ", 'mxchat') . count($pages)); | |
| 1931 | + //error_log("PDF exceeds the maximum allowed pages: " . count($pages)); | |
| 2082 | 1932 | if (filter_var($pdf_source, FILTER_VALIDATE_URL)) { |
| 2083 | 1933 | unlink($temp_file); |
| 2084 | 1934 | } |
| 2085 | - return esc_html__('too_many_pages', 'mxchat'); | |
| 1935 | + return 'too_many_pages'; | |
| 2086 | 1936 | } |
| 2087 | 1937 | |
| 2088 | 1938 | $embeddings = []; |
| 2089 | 1939 | foreach ($pages as $page_number => $page) { |
| @@ -2090,14 +1940,14 @@ | ||
| 2090 | 1940 | $text = $page->getText(); |
| 2091 | 1941 | |
| 2092 | 1942 | // Ensure text is non-empty before generating embeddings |
| 2093 | 1943 | if (empty(trim($text))) { |
| 2094 | - //error_log(esc_html__("Skipping empty page: ", 'mxchat') . ($page_number + 1)); | |
| 1944 | + //error_log("Skipping empty page: " . ($page_number + 1)); | |
| 2095 | 1945 | continue; |
| 2096 | 1946 | } |
| 2097 | 1947 | |
| 2098 | 1948 | $embedding = $this->mxchat_generate_embedding( |
| 2099 | - esc_html__("Page ", 'mxchat') . ($page_number + 1) . ": " . $text, | |
| 1949 | + "Page " . ($page_number + 1) . ": " . $text, | |
| 2100 | 1950 | $this->options['api_key'] |
| 2101 | 1951 | ); |
| 2102 | 1952 | |
| 2103 | 1953 | if ($embedding) { |
| @@ -2106,9 +1956,9 @@ | ||
| 2106 | 1956 | 'embedding' => $embedding, |
| 2107 | 1957 | 'text' => $text, |
| 2108 | 1958 | ]; |
| 2109 | 1959 | } else { |
| 2110 | - //error_log(esc_html__("Failed to generate embedding for page ", 'mxchat') . ($page_number + 1)); | |
| 1960 | + //error_log("Failed to generate embedding for page " . ($page_number + 1)); | |
| 2111 | 1961 | } |
| 2112 | 1962 | } |
| 2113 | 1963 | |
| 2114 | 1964 | // Clean up downloaded file if it was from URL |
| @@ -2118,9 +1968,9 @@ | ||
| 2118 | 1968 | |
| 2119 | 1969 | return $embeddings; |
| 2120 | 1970 | |
| 2121 | 1971 | } catch (\Exception $e) { |
| 2122 | - // error_log(esc_html__("Error parsing or processing PDF: ", 'mxchat') . $e->getMessage()); | |
| 1972 | + // error_log("Error parsing or processing PDF: " . $e->getMessage()); | |
| 2123 | 1973 | |
| 2124 | 1974 | // Cleanup in case of exception |
| 2125 | 1975 | if (filter_var($pdf_source, FILTER_VALIDATE_URL) && $temp_file && file_exists($temp_file)) { |
| 2126 | 1976 | unlink($temp_file); |
| @@ -2129,9 +1979,9 @@ | ||
| 2129 | 1979 | return false; |
| 2130 | 1980 | } |
| 2131 | 1981 | } |
| 2132 | 1982 | private function find_relevant_pdf_pages($query_embedding, $embeddings) { |
| 2133 | - //error_log(esc_html__("find_relevant_pdf_pages called.", 'mxchat')); | |
| 1983 | + //error_log("find_relevant_pdf_pages called."); | |
| 2134 | 1984 | |
| 2135 | 1985 | $most_relevant = null; |
| 2136 | 1986 | $highest_similarity = -INF; |
| 2137 | 1987 | |
| @@ -2157,9 +2007,9 @@ | ||
| 2157 | 2007 | public function handle_pdf_upload() { |
| 2158 | 2008 | check_ajax_referer('mxchat_chat_nonce', 'nonce'); |
| 2159 | 2009 | |
| 2160 | 2010 | if (!isset($_FILES['pdf_file']) || !isset($_POST['session_id'])) { |
| 2161 | - wp_send_json_error(esc_html__('Missing required parameters.', 'mxchat')); | |
| 2011 | + wp_send_json_error('Missing required parameters.'); | |
| 2162 | 2012 | return; |
| 2163 | 2013 | } |
| 2164 | 2014 | |
| 2165 | 2015 | $file = $_FILES['pdf_file']; |
| @@ -2167,9 +2017,9 @@ | ||
| 2167 | 2017 | $original_filename = sanitize_text_field($file['name']); |
| 2168 | 2018 | |
| 2169 | 2019 | $file_type = wp_check_filetype($file['name'], ['pdf' => 'application/pdf']); |
| 2170 | 2020 | if ($file_type['type'] !== 'application/pdf') { |
| 2171 | - wp_send_json_error(esc_html__('Invalid file type. Only PDF files are allowed.', 'mxchat')); | |
| 2021 | + wp_send_json_error('Invalid file type. Only PDF files are allowed.'); | |
| 2172 | 2022 | return; |
| 2173 | 2023 | } |
| 2174 | 2024 | |
| 2175 | 2025 | $upload_dir = wp_upload_dir(); |
| @@ -2176,9 +2026,9 @@ | ||
| 2176 | 2026 | $pdf_filename = 'mxchat_' . $session_id . '_' . time() . '.pdf'; |
| 2177 | 2027 | $pdf_path = $upload_dir['path'] . '/' . $pdf_filename; |
| 2178 | 2028 | |
| 2179 | 2029 | if (!move_uploaded_file($file['tmp_name'], $pdf_path)) { |
| 2180 | - wp_send_json_error(esc_html__('Failed to upload file.', 'mxchat')); | |
| 2030 | + wp_send_json_error('Failed to upload file.'); | |
| 2181 | 2031 | return; |
| 2182 | 2032 | } |
| 2183 | 2033 | |
| 2184 | 2034 | $this->clear_pdf_transients($session_id); |
| @@ -2189,9 +2039,9 @@ | ||
| 2189 | 2039 | if ($embeddings === 'too_many_pages') { |
| 2190 | 2040 | unlink($pdf_path); |
| 2191 | 2041 | $error_message = sprintf( |
| 2192 | 2042 | $this->options['pdf_intent_error_text'] ?? |
| 2193 | - esc_html__("The provided PDF exceeds the maximum allowed limit of %d pages. Please provide a smaller document.", 'mxchat'), | |
| 2043 | + "The provided PDF exceeds the maximum allowed limit of %d pages. Please provide a smaller document.", | |
| 2194 | 2044 | $max_pages |
| 2195 | 2045 | ); |
| 2196 | 2046 | wp_send_json_error($error_message); |
| 2197 | 2047 | return; |
| @@ -2199,9 +2049,9 @@ | ||
| 2199 | 2049 | |
| 2200 | 2050 | if ($embeddings === false || empty($embeddings)) { |
| 2201 | 2051 | unlink($pdf_path); |
| 2202 | 2052 | $error_message = $this->options['pdf_intent_error_text'] ?? |
| 2203 | - esc_html__('The uploaded PDF appears to be empty or contains unsupported content.', 'mxchat'); | |
| 2053 | + 'The uploaded PDF appears to be empty or contains unsupported content.'; | |
| 2204 | 2054 | wp_send_json_error($error_message); |
| 2205 | 2055 | return; |
| 2206 | 2056 | } |
| 2207 | 2057 | |
| @@ -2211,9 +2061,9 @@ | ||
| 2211 | 2061 | set_transient('mxchat_pdf_embeddings_' . $session_id, $embeddings, HOUR_IN_SECONDS); |
| 2212 | 2062 | set_transient('mxchat_include_pdf_in_context_' . $session_id, true, HOUR_IN_SECONDS); |
| 2213 | 2063 | |
| 2214 | 2064 | $success_message = $this->options['pdf_intent_success_text'] ?? |
| 2215 | - esc_html__("I've processed the PDF. What questions do you have about it?", 'mxchat'); | |
| 2065 | + "I've processed the PDF. What questions do you have about it?"; | |
| 2216 | 2066 | |
| 2217 | 2067 | wp_send_json_success([ |
| 2218 | 2068 | 'message' => $success_message, |
| 2219 | 2069 | 'filename' => $original_filename |
| @@ -2222,9 +2072,9 @@ | ||
| 2222 | 2072 | } |
| 2223 | 2073 | |
| 2224 | 2074 | unlink($pdf_path); |
| 2225 | 2075 | $error_message = $this->options['pdf_intent_error_text'] ?? |
| 2226 | - esc_html__('Sorry, I couldn\'t process the PDF. Please ensure it\'s a valid file.', 'mxchat'); | |
| 2076 | + 'Sorry, I couldn\'t process the PDF. Please ensure it\'s a valid file.'; | |
| 2227 | 2077 | wp_send_json_error($error_message); |
| 2228 | 2078 | return; |
| 2229 | 2079 | } |
| 2230 | 2080 | public function handle_pdf_remove() { |
| @@ -2230,9 +2080,9 @@ | ||
| 2230 | 2080 | public function handle_pdf_remove() { |
| 2231 | 2081 | check_ajax_referer('mxchat_chat_nonce', 'nonce'); |
| 2232 | 2082 | |
| 2233 | 2083 | if (empty($_POST['session_id'])) { |
| 2234 | - wp_send_json_error(esc_html__('Session ID missing.', 'mxchat')); | |
| 2084 | + wp_send_json_error('Session ID missing.'); | |
| 2235 | 2085 | wp_die(); |
| 2236 | 2086 | } |
| 2237 | 2087 | |
| 2238 | 2088 | $session_id = sanitize_text_field($_POST['session_id']); |
| @@ -2244,9 +2094,9 @@ | ||
| 2244 | 2094 | |
| 2245 | 2095 | $this->clear_pdf_transients($session_id); |
| 2246 | 2096 | |
| 2247 | 2097 | wp_send_json_success([ |
| 2248 | - 'message' => esc_html__('PDF removed successfully.', 'mxchat') | |
| 2098 | + 'message' => 'PDF removed successfully.' | |
| 2249 | 2099 | ]); |
| 2250 | 2100 | wp_die(); |
| 2251 | 2101 | } |
| 2252 | 2102 | |
| @@ -2257,14 +2107,14 @@ | ||
| 2257 | 2107 | * @param string $prompt The prompt to send to the AI. |
| 2258 | 2108 | * @return array An array containing the AI's response text. |
| 2259 | 2109 | */ |
| 2260 | 2110 | private function mxchat_call_ai_api( $prompt ) { |
| 2261 | - //error_log( esc_html__( 'Calling AI API with the provided prompt.', 'mxchat' ) ); | |
| 2111 | + //error_log( 'Calling AI API with the provided prompt.' ); | |
| 2262 | 2112 | |
| 2263 | 2113 | $api_key = $this->options['api_key']; |
| 2264 | 2114 | if ( empty( $api_key ) ) { |
| 2265 | - //error_log( esc_html__( 'API key is not set.', 'mxchat' ) ); | |
| 2266 | - return [ 'text' => esc_html__( 'API key is not set.', 'mxchat' ) ]; | |
| 2115 | + //error_log( 'API key is not set.' ); | |
| 2116 | + return [ 'text' => 'API key is not set.' ]; | |
| 2267 | 2117 | } |
| 2268 | 2118 | |
| 2269 | 2119 | $url = 'https://api.openai.com/v1/chat/completions'; |
| 2270 | 2120 | $messages = [ |
| @@ -2269,9 +2119,9 @@ | ||
| 2269 | 2119 | $url = 'https://api.openai.com/v1/chat/completions'; |
| 2270 | 2120 | $messages = [ |
| 2271 | 2121 | [ |
| 2272 | 2122 | 'role' => 'system', |
| 2273 | - 'content' => __( 'You are a helpful assistant that provides concise and personalized product recommendations. Someone has asked you for some recommendations please respond very concisely appropriate for an AI chatbot.', 'mxchat' ), | |
| 2123 | + 'content' => 'You are a helpful assistant that provides concise and personalized product recommendations. Someone has asked you for some recommendations please respond very concisely appropriate for an AI chatbot.', | |
| 2274 | 2124 | ], |
| 2275 | 2125 | [ |
| 2276 | 2126 | 'role' => 'user', |
| 2277 | 2127 | 'content' => $prompt, |
| @@ -2296,24 +2146,23 @@ | ||
| 2296 | 2146 | |
| 2297 | 2147 | $response = wp_remote_post( $url, $args ); |
| 2298 | 2148 | |
| 2299 | 2149 | if ( is_wp_error( $response ) ) { |
| 2300 | - //error_log( esc_html__( 'Error communicating with AI API: ', 'mxchat' ) . $response->get_error_message() ); | |
| 2301 | - return [ 'text' => esc_html__( 'Error communicating with AI API.', 'mxchat' ) ]; | |
| 2150 | + //error_log( 'Error communicating with AI API: ' . $response->get_error_message() ); | |
| 2151 | + return [ 'text' => 'Error communicating with AI API.' ]; | |
| 2302 | 2152 | } |
| 2303 | 2153 | |
| 2304 | 2154 | $body = wp_remote_retrieve_body( $response ); |
| 2305 | - //error_log( esc_html__( 'API response body: ', 'mxchat' ) . $body ); | |
| 2155 | + //error_log( 'API response body: ' . $body ); | |
| 2306 | 2156 | |
| 2307 | 2157 | $decoded_body = json_decode( $body, true ); |
| 2308 | 2158 | if ( isset( $decoded_body['choices'][0]['message']['content'] ) ) { |
| 2309 | 2159 | return [ 'text' => $decoded_body['choices'][0]['message']['content'] ]; |
| 2310 | 2160 | } else { |
| 2311 | - //error_log( esc_html__( 'Unexpected API response format: ', 'mxchat' ) . wp_json_encode( $decoded_body ) ); | |
| 2312 | - return [ 'text' => esc_html__( 'No response received from AI.', 'mxchat' ) ]; | |
| 2161 | + //error_log( 'Unexpected API response format: ' . wp_json_encode( $decoded_body ) ); | |
| 2162 | + return [ 'text' => 'No response received from AI.' ]; | |
| 2313 | 2163 | } |
| 2314 | 2164 | } |
| 2315 | - | |
| 2316 | 2165 | /** |
| 2317 | 2166 | * Fetches the AI response for the given prompt. |
| 2318 | 2167 | * |
| 2319 | 2168 | * @param string $prompt The prompt to send to the AI. |
| @@ -2336,19 +2185,19 @@ | ||
| 2336 | 2185 | $name = $rec['name']; |
| 2337 | 2186 | $price = $rec['price']; |
| 2338 | 2187 | $url = $rec['url']; |
| 2339 | 2188 | $image = $rec['image']; |
| 2340 | - $recommendation_list .= "{$number}. " . esc_html__('Product:', 'mxchat') . " {$name} (" . esc_html__('Price:', 'mxchat') . " \\${$price})\n"; | |
| 2189 | + $recommendation_list .= "{$number}. Product: {$name} (Price: \\${$price})\n"; | |
| 2341 | 2190 | $recommendation_list .= " [Link]({$url})\n"; |
| 2342 | 2191 | $recommendation_list .= " \n\n"; |
| 2343 | 2192 | } |
| 2344 | 2193 | |
| 2345 | - $prompt = esc_html__('Based on the following list of products, generate a unique, friendly, and personalized response to a user. ', 'mxchat'); | |
| 2346 | - $prompt .= esc_html__('If some products aren\'t exactly what the user asked for but share similar styles or patterns, acknowledge this and explain why you\'re suggesting them. ', 'mxchat'); | |
| 2347 | - $prompt .= esc_html__('For each product, provide a brief justification that clearly explains why it\'s relevant, especially if it\'s a different type of product than requested. ', 'mxchat'); | |
| 2348 | - $prompt .= esc_html__('Please number your responses to match the product numbers.', 'mxchat') . "\n\n"; | |
| 2349 | - $prompt .= esc_html__('Products:', 'mxchat') . "\n\n{$recommendation_list}"; | |
| 2350 | - $prompt .= esc_html__('Please ensure that the number of each product matches the order in which the products are listed.', 'mxchat'); | |
| 2194 | + $prompt = "Based on the following list of products, generate a unique, friendly, and personalized response to a user. "; | |
| 2195 | + $prompt .= "If some products aren't exactly what the user asked for but share similar styles or patterns, acknowledge this and explain why you're suggesting them. "; | |
| 2196 | + $prompt .= "For each product, provide a brief justification that clearly explains why it's relevant, especially if it's a different type of product than requested. "; | |
| 2197 | + $prompt .= "Please number your responses to match the product numbers.\n\n"; | |
| 2198 | + $prompt .= "Products:\n\n{$recommendation_list}"; | |
| 2199 | + $prompt .= "Please ensure that the number of each product matches the order in which the products are listed."; | |
| 2351 | 2200 | |
| 2352 | 2201 | return $prompt; |
| 2353 | 2202 | } |
| 2354 | 2203 | private function mxchat_generate_recommendations($user_id, $message) { |
| @@ -2459,31 +2308,31 @@ | ||
| 2459 | 2308 | } |
| 2460 | 2309 | |
| 2461 | 2310 | return [ |
| 2462 | 2311 | 'recommendations' => $formatted_recommendations, |
| 2463 | - 'sources' => [__('AI-powered personalized recommendations', 'mxchat')] | |
| 2312 | + 'sources' => ['AI-powered personalized recommendations'] | |
| 2464 | 2313 | ]; |
| 2465 | 2314 | } |
| 2466 | 2315 | private function mxchat_get_ai_shopping_suggestion($message, $user_context) { |
| 2467 | - $prompt = esc_html__("As a shopping assistant, analyze this user's context and generate a specific product search suggestion. ", 'mxchat'); | |
| 2468 | - $prompt .= esc_html__("User's Question: \"{$message}\"\n\n", 'mxchat'); | |
| 2316 | + $prompt = "As a shopping assistant, analyze this user's context and generate a specific product search suggestion. "; | |
| 2317 | + $prompt .= "User's Question: \"{$message}\"\n\n"; | |
| 2469 | 2318 | |
| 2470 | 2319 | if (!empty($user_context['order_history'])) { |
| 2471 | - $prompt .= esc_html__("Their recent orders include:\n", 'mxchat'); | |
| 2320 | + $prompt .= "Their recent orders include:\n"; | |
| 2472 | 2321 | foreach ($user_context['order_history'] as $order) { |
| 2473 | - $prompt .= esc_html__("- {$order['name']} ({$order['date']})\n", 'mxchat'); | |
| 2322 | + $prompt .= "- {$order['name']} ({$order['date']})\n"; | |
| 2474 | 2323 | } |
| 2475 | 2324 | } |
| 2476 | 2325 | |
| 2477 | 2326 | if (!empty($user_context['cart_items'])) { |
| 2478 | - $prompt .= esc_html__("\nThey currently have in their cart:\n", 'mxchat'); | |
| 2327 | + $prompt .= "\nThey currently have in their cart:\n"; | |
| 2479 | 2328 | foreach ($user_context['cart_items'] as $item) { |
| 2480 | - $prompt .= esc_html__("- {$item['name']}\n", 'mxchat'); | |
| 2329 | + $prompt .= "- {$item['name']}\n"; | |
| 2481 | 2330 | } |
| 2482 | 2331 | } |
| 2483 | 2332 | |
| 2484 | - $prompt .= esc_html__("\nBased on their question and history, suggest a specific search query that would help find the most relevant products. ", 'mxchat'); | |
| 2485 | - $prompt .= esc_html__("Respond with ONLY the search query, nothing else.", 'mxchat'); | |
| 2333 | + $prompt .= "\nBased on their question and history, suggest a specific search query that would help find the most relevant products. "; | |
| 2334 | + $prompt .= "Respond with ONLY the search query, nothing else."; | |
| 2486 | 2335 | |
| 2487 | 2336 | $response = $this->mxchat_call_ai_api($prompt); |
| 2488 | 2337 | return isset($response['text']) ? trim($response['text']) : $message; |
| 2489 | 2338 | } |
| @@ -2657,10 +2506,10 @@ | ||
| 2657 | 2506 | $persistence_enabled = $_POST['persistence_enabled'] === 'true'; |
| 2658 | 2507 | $initial_timestamp = isset($_POST['initial_timestamp']) ? intval($_POST['initial_timestamp']) : 0; |
| 2659 | 2508 | |
| 2660 | 2509 | if (empty($session_id)) { |
| 2661 | - //error_log(esc_html__('Fetch new messages error: Session ID missing.', 'mxchat')); | |
| 2662 | - wp_send_json_error(['message' => esc_html__('Session ID missing.', 'mxchat')]); | |
| 2510 | + //error_log('Fetch new messages error: Session ID missing.'); | |
| 2511 | + wp_send_json_error(['message' => 'Session ID missing.']); | |
| 2663 | 2512 | wp_die(); |
| 2664 | 2513 | } |
| 2665 | 2514 | |
| 2666 | 2515 | $history = get_option("mxchat_history_{$session_id}", []); |
| @@ -2678,9 +2527,9 @@ | ||
| 2678 | 2527 | $message['role'] === 'agent' && |
| 2679 | 2528 | $message['timestamp'] > $initial_timestamp; |
| 2680 | 2529 | }); |
| 2681 | 2530 | |
| 2682 | - //error_log(esc_html__("New agent messages fetched for session $session_id. Last seen ID: $last_seen_id", 'mxchat')); | |
| 2531 | + //error_log("New agent messages fetched for session $session_id. Last seen ID: $last_seen_id"); | |
| 2683 | 2532 | |
| 2684 | 2533 | wp_send_json_success([ |
| 2685 | 2534 | 'new_messages' => array_values($new_messages) |
| 2686 | 2535 | ]); |
| @@ -2689,11 +2538,13 @@ | ||
| 2689 | 2538 | |
| 2690 | 2539 | |
| 2691 | 2540 | public function mxchat_live_agent_handover($message, $user_id, $session_id) { |
| 2692 | 2541 | // First check if live agents are available |
| 2693 | - $live_agent_available = $this->options['live_agent_status'] ?? 'off'; | |
| 2694 | - if ($live_agent_available !== 'on') { | |
| 2542 | + $live_agent_available = $this->options['live_agent_status'] ?? 'offline'; | |
| 2543 | + | |
| 2544 | + if ($live_agent_available !== 'online') { | |
| 2695 | 2545 | $away_message = $this->options['live_agent_away_message'] ?? 'Sorry, live agents are currently unavailable. I can continue helping you as an AI assistant.'; |
| 2546 | + | |
| 2696 | 2547 | $this->fallbackResponse = [ |
| 2697 | 2548 | 'text' => $away_message, |
| 2698 | 2549 | 'html' => '', |
| 2699 | 2550 | 'images' => [], |
| @@ -2698,8 +2549,11 @@ | ||
| 2698 | 2549 | 'html' => '', |
| 2699 | 2550 | 'images' => [], |
| 2700 | 2551 | 'chat_mode' => 'ai' |
| 2701 | 2552 | ]; |
| 2553 | + | |
| 2554 | + //error_log('Live agent handover attempted but agents are offline'); | |
| 2555 | + | |
| 2702 | 2556 | wp_send_json([ |
| 2703 | 2557 | 'text' => $away_message, |
| 2704 | 2558 | 'html' => '', |
| 2705 | 2559 | 'chat_mode' => 'ai', |
| @@ -2708,27 +2562,15 @@ | ||
| 2708 | 2562 | wp_die(); |
| 2709 | 2563 | } |
| 2710 | 2564 | |
| 2711 | 2565 | $slack_webhook_url = $this->options['live_agent_webhook_url'] ?? ''; |
| 2566 | + //error_log('Slack Webhook URL retrieved: ' . $slack_webhook_url); | |
| 2567 | + | |
| 2712 | 2568 | if (empty($slack_webhook_url)) { |
| 2569 | + //error_log('Slack Webhook URL is not configured.'); | |
| 2713 | 2570 | return false; |
| 2714 | 2571 | } |
| 2715 | 2572 | |
| 2716 | - // Get recent chat history (last 5 messages) | |
| 2717 | - $history = get_option("mxchat_history_{$session_id}", []); | |
| 2718 | - $recent_history = array_slice($history, -5); // Get last 5 messages | |
| 2719 | - | |
| 2720 | - // Format conversation history | |
| 2721 | - $conversation_context = ""; | |
| 2722 | - if (!empty($recent_history)) { | |
| 2723 | - $conversation_context = "*Recent Conversation:*\n"; | |
| 2724 | - foreach ($recent_history as $hist_message) { | |
| 2725 | - $role_display = $hist_message['role'] === 'user' ? 'User' : 'AI'; | |
| 2726 | - $conversation_context .= ">{$role_display}: {$hist_message['content']}\n"; | |
| 2727 | - } | |
| 2728 | - $conversation_context .= "\n"; | |
| 2729 | - } | |
| 2730 | - | |
| 2731 | 2573 | update_option("mxchat_mode_{$session_id}", 'agent'); |
| 2732 | 2574 | |
| 2733 | 2575 | $webhook_data = [ |
| 2734 | 2576 | 'blocks' => [ |
| @@ -2744,53 +2586,38 @@ | ||
| 2744 | 2586 | 'type' => 'section', |
| 2745 | 2587 | 'fields' => [ |
| 2746 | 2588 | [ |
| 2747 | 2589 | 'type' => 'mrkdwn', |
| 2748 | - 'text' => sprintf('*User ID:*\n`%s`', $user_id) | |
| 2590 | + 'text' => "*User ID:*\n`$user_id`" | |
| 2749 | 2591 | ], |
| 2750 | 2592 | [ |
| 2751 | 2593 | 'type' => 'mrkdwn', |
| 2752 | - 'text' => sprintf('*Session ID:*\n`%s`', $session_id) | |
| 2594 | + 'text' => "*Session ID:*\n`$session_id`" | |
| 2753 | 2595 | ] |
| 2754 | 2596 | ] |
| 2755 | - ] | |
| 2756 | - ] | |
| 2757 | - ]; | |
| 2758 | - | |
| 2759 | - // Add conversation history if exists | |
| 2760 | - if (!empty($conversation_context)) { | |
| 2761 | - $webhook_data['blocks'][] = [ | |
| 2762 | - 'type' => 'section', | |
| 2763 | - 'text' => [ | |
| 2764 | - 'type' => 'mrkdwn', | |
| 2765 | - 'text' => $conversation_context | |
| 2766 | - ] | |
| 2767 | - ]; | |
| 2768 | - } | |
| 2769 | - | |
| 2770 | - // Add the current message | |
| 2771 | - $webhook_data['blocks'][] = [ | |
| 2772 | - 'type' => 'section', | |
| 2773 | - 'text' => [ | |
| 2774 | - 'type' => 'mrkdwn', | |
| 2775 | - 'text' => sprintf('*Current Message:*\n%s', $message) | |
| 2776 | - ] | |
| 2777 | - ]; | |
| 2778 | - | |
| 2779 | - // Add the reply button | |
| 2780 | - $webhook_data['blocks'][] = [ | |
| 2781 | - 'type' => 'actions', | |
| 2782 | - 'elements' => [ | |
| 2597 | + ], | |
| 2783 | 2598 | [ |
| 2784 | - 'type' => 'button', | |
| 2599 | + 'type' => 'section', | |
| 2785 | 2600 | 'text' => [ |
| 2786 | - 'type' => 'plain_text', | |
| 2787 | - 'text' => '✍️ Reply', | |
| 2788 | - 'emoji' => true | |
| 2789 | - ], | |
| 2790 | - 'value' => $session_id, | |
| 2791 | - 'action_id' => 'reply_to_user', | |
| 2792 | - 'style' => 'primary' | |
| 2601 | + 'type' => 'mrkdwn', | |
| 2602 | + 'text' => "*Initial Message:*\n$message" | |
| 2603 | + ] | |
| 2604 | + ], | |
| 2605 | + [ | |
| 2606 | + 'type' => 'actions', | |
| 2607 | + 'elements' => [ | |
| 2608 | + [ | |
| 2609 | + 'type' => 'button', | |
| 2610 | + 'text' => [ | |
| 2611 | + 'type' => 'plain_text', | |
| 2612 | + 'text' => '✍️ Reply', | |
| 2613 | + 'emoji' => true | |
| 2614 | + ], | |
| 2615 | + 'value' => $session_id, | |
| 2616 | + 'action_id' => 'reply_to_user', | |
| 2617 | + 'style' => 'primary' | |
| 2618 | + ] | |
| 2619 | + ] | |
| 2793 | 2620 | ] |
| 2794 | 2621 | ] |
| 2795 | 2622 | ]; |
| 2796 | 2623 | |
| @@ -2801,12 +2628,16 @@ | ||
| 2801 | 2628 | ], |
| 2802 | 2629 | ]); |
| 2803 | 2630 | |
| 2804 | 2631 | if (is_wp_error($response)) { |
| 2632 | + //error_log('Error sending live agent handover: ' . $response->get_error_message()); | |
| 2805 | 2633 | return false; |
| 2806 | 2634 | } |
| 2807 | 2635 | |
| 2636 | + //error_log('Live agent handover triggered successfully.'); | |
| 2637 | + | |
| 2808 | 2638 | $success_message = $this->options['live_agent_notification_message'] ?? 'Live agent has been notified.'; |
| 2639 | + | |
| 2809 | 2640 | $this->mxchat_save_chat_message($session_id, 'bot', $success_message); |
| 2810 | 2641 | |
| 2811 | 2642 | $this->fallbackResponse = [ |
| 2812 | 2643 | 'text' => $success_message, |
| @@ -2828,9 +2659,9 @@ | ||
| 2828 | 2659 | public function mxchat_send_user_message_to_agent($message, $user_id, $session_id) { |
| 2829 | 2660 | $slack_webhook_url = $this->options['live_agent_webhook_url'] ?? ''; |
| 2830 | 2661 | |
| 2831 | 2662 | if (empty($slack_webhook_url)) { |
| 2832 | - //error_log(esc_html__('Slack Webhook URL is not configured.', 'mxchat')); | |
| 2663 | + //error_log('Slack Webhook URL is not configured.'); | |
| 2833 | 2664 | return false; |
| 2834 | 2665 | } |
| 2835 | 2666 | |
| 2836 | 2667 | $webhook_data = [ |
| @@ -2838,9 +2669,9 @@ | ||
| 2838 | 2669 | [ |
| 2839 | 2670 | 'type' => 'header', |
| 2840 | 2671 | 'text' => [ |
| 2841 | 2672 | 'type' => 'plain_text', |
| 2842 | - 'text' => esc_html__('📩 New Chat Message', 'mxchat'), | |
| 2673 | + 'text' => '📩 New Chat Message', | |
| 2843 | 2674 | 'emoji' => true |
| 2844 | 2675 | ] |
| 2845 | 2676 | ], |
| 2846 | 2677 | [ |
| @@ -2847,13 +2678,13 @@ | ||
| 2847 | 2678 | 'type' => 'section', |
| 2848 | 2679 | 'fields' => [ |
| 2849 | 2680 | [ |
| 2850 | 2681 | 'type' => 'mrkdwn', |
| 2851 | - 'text' => sprintf(esc_html__('*User ID:*\n`%s`', 'mxchat'), $user_id) | |
| 2682 | + 'text' => "*User ID:*\n`$user_id`" | |
| 2852 | 2683 | ], |
| 2853 | 2684 | [ |
| 2854 | 2685 | 'type' => 'mrkdwn', |
| 2855 | - 'text' => sprintf(esc_html__('*Session ID:*\n`%s`', 'mxchat'), $session_id) | |
| 2686 | + 'text' => "*Session ID:*\n`$session_id`" | |
| 2856 | 2687 | ] |
| 2857 | 2688 | ] |
| 2858 | 2689 | ], |
| 2859 | 2690 | [ |
| @@ -2859,9 +2690,9 @@ | ||
| 2859 | 2690 | [ |
| 2860 | 2691 | 'type' => 'section', |
| 2861 | 2692 | 'text' => [ |
| 2862 | 2693 | 'type' => 'mrkdwn', |
| 2863 | - 'text' => sprintf(esc_html__('*Message:*\n%s', 'mxchat'), $message) | |
| 2694 | + 'text' => "*Message:*\n$message" | |
| 2864 | 2695 | ] |
| 2865 | 2696 | ], |
| 2866 | 2697 | [ |
| 2867 | 2698 | 'type' => 'actions', |
| @@ -2869,9 +2700,9 @@ | ||
| 2869 | 2700 | [ |
| 2870 | 2701 | 'type' => 'button', |
| 2871 | 2702 | 'text' => [ |
| 2872 | 2703 | 'type' => 'plain_text', |
| 2873 | - 'text' => esc_html__('✍️ Reply', 'mxchat'), | |
| 2704 | + 'text' => '✍️ Reply', | |
| 2874 | 2705 | 'emoji' => true |
| 2875 | 2706 | ], |
| 2876 | 2707 | 'value' => $session_id, |
| 2877 | 2708 | 'action_id' => 'reply_to_user', |
| @@ -2889,13 +2720,13 @@ | ||
| 2889 | 2720 | ], |
| 2890 | 2721 | ]); |
| 2891 | 2722 | |
| 2892 | 2723 | if (is_wp_error($response)) { |
| 2893 | - //error_log(esc_html__('Error sending message to Slack: ', 'mxchat') . $response->get_error_message()); | |
| 2724 | + //error_log('Error sending message to Slack: ' . $response->get_error_message()); | |
| 2894 | 2725 | return false; |
| 2895 | 2726 | } |
| 2896 | 2727 | |
| 2897 | - //error_log(esc_html__('Message sent to Slack successfully.', 'mxchat')); | |
| 2728 | + //error_log('Message sent to Slack successfully.'); | |
| 2898 | 2729 | return true; |
| 2899 | 2730 | } |
| 2900 | 2731 | public function handle_slack_interaction(WP_REST_Request $request) { |
| 2901 | 2732 | //error_log('Received Slack interaction'); |
| @@ -2912,9 +2743,9 @@ | ||
| 2912 | 2743 | $slack_token = $this->options['live_agent_bot_token'] ?? ''; |
| 2913 | 2744 | |
| 2914 | 2745 | if (empty($slack_token)) { |
| 2915 | 2746 | //error_log('Slack Bot Token not configured'); |
| 2916 | - return new WP_REST_Response(['error' => esc_html__('Bot token not configured', 'mxchat')], 400); | |
| 2747 | + return new WP_REST_Response(['error' => 'Bot token not configured'], 400); | |
| 2917 | 2748 | } |
| 2918 | 2749 | $response = wp_remote_post('https://slack.com/api/views.open', [ |
| 2919 | 2750 | 'headers' => [ |
| 2920 | 2751 | 'Content-Type' => 'application/json', |
| @@ -2926,17 +2757,17 @@ | ||
| 2926 | 2757 | 'type' => 'modal', |
| 2927 | 2758 | 'callback_id' => 'reply_modal', |
| 2928 | 2759 | 'title' => [ |
| 2929 | 2760 | 'type' => 'plain_text', |
| 2930 | - 'text' => __('Reply to User', 'mxchat') | |
| 2761 | + 'text' => 'Reply to User' | |
| 2931 | 2762 | ], |
| 2932 | 2763 | 'submit' => [ |
| 2933 | 2764 | 'type' => 'plain_text', |
| 2934 | - 'text' => __('Send', 'mxchat') | |
| 2765 | + 'text' => 'Send' | |
| 2935 | 2766 | ], |
| 2936 | 2767 | 'close' => [ |
| 2937 | 2768 | 'type' => 'plain_text', |
| 2938 | - 'text' => __('Cancel', 'mxchat') | |
| 2769 | + 'text' => 'Cancel' | |
| 2939 | 2770 | ], |
| 2940 | 2771 | 'blocks' => [ |
| 2941 | 2772 | [ |
| 2942 | 2773 | 'type' => 'input', |
| @@ -2942,9 +2773,9 @@ | ||
| 2942 | 2773 | 'type' => 'input', |
| 2943 | 2774 | 'block_id' => 'reply_block', |
| 2944 | 2775 | 'label' => [ |
| 2945 | 2776 | 'type' => 'plain_text', |
| 2946 | - 'text' => sprintf(__('Reply to session: %s', 'mxchat'), $session_id) | |
| 2777 | + 'text' => "Reply to session: $session_id" | |
| 2947 | 2778 | ], |
| 2948 | 2779 | 'element' => [ |
| 2949 | 2780 | 'type' => 'plain_text_input', |
| 2950 | 2781 | 'action_id' => 'message', |
| @@ -2950,9 +2781,9 @@ | ||
| 2950 | 2781 | 'action_id' => 'message', |
| 2951 | 2782 | 'multiline' => true, |
| 2952 | 2783 | 'placeholder' => [ |
| 2953 | 2784 | 'type' => 'plain_text', |
| 2954 | - 'text' => __('Type your message here...', 'mxchat') | |
| 2785 | + 'text' => 'Type your message here...' | |
| 2955 | 2786 | ] |
| 2956 | 2787 | ] |
| 2957 | 2788 | ] |
| 2958 | 2789 | ], |
| @@ -2967,21 +2798,19 @@ | ||
| 2967 | 2798 | return new WP_REST_Response(['ok' => true]); |
| 2968 | 2799 | } |
| 2969 | 2800 | |
| 2970 | 2801 | // Handle modal submission |
| 2971 | -// Handle modal submission | |
| 2972 | -if ($payload['type'] === 'view_submission') { | |
| 2973 | - $session_id = $payload['view']['private_metadata']; | |
| 2974 | - $message = $payload['view']['state']['values']['reply_block']['message']['value']; | |
| 2802 | + if ($payload['type'] === 'view_submission') { | |
| 2803 | + $session_id = $payload['view']['private_metadata']; | |
| 2804 | + $message = $payload['view']['state']['values']['reply_block']['message']['value']; | |
| 2975 | 2805 | |
| 2976 | - // Save the message (keep the message_id but don't include in response) | |
| 2977 | - $this->mxchat_save_chat_message($session_id, 'agent', $message); | |
| 2806 | + // Save the message | |
| 2807 | + $this->mxchat_save_chat_message($session_id, 'agent', $message); | |
| 2978 | 2808 | |
| 2979 | - // Keep the original response format for Slack | |
| 2980 | - return new WP_REST_Response([ | |
| 2981 | - 'response_action' => 'clear' | |
| 2982 | - ]); | |
| 2983 | -} | |
| 2809 | + return new WP_REST_Response([ | |
| 2810 | + 'response_action' => 'clear' | |
| 2811 | + ]); | |
| 2812 | + } | |
| 2984 | 2813 | |
| 2985 | 2814 | // Default acknowledgment |
| 2986 | 2815 | return new WP_REST_Response(['ok' => true]); |
| 2987 | 2816 | } |
| @@ -2995,11 +2824,11 @@ | ||
| 2995 | 2824 | $command_text = $request->get_param('text'); |
| 2996 | 2825 | // error_log('Command text: ' . $command_text); |
| 2997 | 2826 | |
| 2998 | 2827 | if (empty($command_text)) { |
| 2999 | - //error_log(esc_html__('Agent response error: No command text received', 'mxchat')); | |
| 2828 | + error_log('Agent response error: No command text received'); | |
| 3000 | 2829 | return new WP_REST_Response([ |
| 3001 | - 'error' => esc_html__('Command text is required. Format: /reply session_id message', 'mxchat') | |
| 2830 | + 'error' => 'Command text is required. Format: /reply session_id message' | |
| 3002 | 2831 | ], 400); |
| 3003 | 2832 | } |
| 3004 | 2833 | |
| 3005 | 2834 | // Split the command text into session_id and message |
| @@ -3006,9 +2835,9 @@ | ||
| 3006 | 2835 | $parts = explode(' ', $command_text, 2); |
| 3007 | 2836 | if (count($parts) !== 2) { |
| 3008 | 2837 | //error_log('Agent response error: Invalid command format'); |
| 3009 | 2838 | return new WP_REST_Response([ |
| 3010 | - 'error' => esc_html__('Invalid format. Use: /reply session_id message', 'mxchat') | |
| 2839 | + 'error' => 'Invalid format. Use: /reply session_id message' | |
| 3011 | 2840 | ], 400); |
| 3012 | 2841 | } |
| 3013 | 2842 | |
| 3014 | 2843 | $session_id = sanitize_text_field($parts[0]); |
| @@ -3021,9 +2850,9 @@ | ||
| 3021 | 2850 | |
| 3022 | 2851 | if (!$message_id) { |
| 3023 | 2852 | // error_log('Failed to save agent message'); |
| 3024 | 2853 | return new WP_REST_Response([ |
| 3025 | - 'error' => esc_html__('Failed to save message', 'mxchat') | |
| 2854 | + 'error' => 'Failed to save message' | |
| 3026 | 2855 | ], 500); |
| 3027 | 2856 | } |
| 3028 | 2857 | |
| 3029 | 2858 | // Return success response in Slack's expected format |
| @@ -3028,15 +2857,15 @@ | ||
| 3028 | 2857 | |
| 3029 | 2858 | // Return success response in Slack's expected format |
| 3030 | 2859 | return new WP_REST_Response([ |
| 3031 | 2860 | 'response_type' => 'in_channel', |
| 3032 | - 'text' => esc_html__("Message sent successfully to session $session_id", 'mxchat') | |
| 2861 | + 'text' => "Message sent successfully to session $session_id" | |
| 3033 | 2862 | ], 200); |
| 3034 | 2863 | } |
| 3035 | 2864 | |
| 3036 | 2865 | |
| 3037 | 2866 | public function mxchat_handle_switch_to_chatbot_intent($message, $user_id, $session_id) { |
| 3038 | - //error_log(esc_html__("Switching back to chatbot mode via intent.", 'mxchat')); | |
| 2867 | + //error_log("Switching back to chatbot mode via intent."); | |
| 3039 | 2868 | |
| 3040 | 2869 | // Just update mode to AI |
| 3041 | 2870 | update_option("mxchat_mode_{$session_id}", 'ai'); |
| 3042 | 2871 | |
| @@ -3044,9 +2873,9 @@ | ||
| 3044 | 2873 | $this->fallbackResponse = ['text' => '', 'html' => '', 'images' => []]; |
| 3045 | 2874 | $this->productCardHtml = ''; |
| 3046 | 2875 | |
| 3047 | 2876 | // Set the response message |
| 3048 | - $this->fallbackResponse['text'] = esc_html__('You are now chatting with the AI chatbot.', 'mxchat'); | |
| 2877 | + $this->fallbackResponse['text'] = 'You are now chatting with the AI chatbot.'; | |
| 3049 | 2878 | |
| 3050 | 2879 | return true; // Intent was handled |
| 3051 | 2880 | } |
| 3052 | 2881 | |
| @@ -3111,66 +2940,19 @@ | ||
| 3111 | 2940 | return null; |
| 3112 | 2941 | } |
| 3113 | 2942 | } |
| 3114 | 2943 | |
| 3115 | - | |
| 3116 | 2944 | private function mxchat_find_relevant_content($user_embedding) { |
| 3117 | - //error_log('MXChat Vector Search: Starting content search...'); | |
| 3118 | - | |
| 3119 | - // Retrieve the add-on settings from the database. | |
| 3120 | - $addon_options = get_option('mxchat_pinecone_addon_options', array()); | |
| 3121 | - | |
| 3122 | - // Determine whether Pinecone is enabled. | |
| 3123 | - // We expect the sanitized setting to be a string '1' if enabled, otherwise '0'. | |
| 3124 | - $use_pinecone = (isset($addon_options['mxchat_use_pinecone']) && $addon_options['mxchat_use_pinecone'] === '1') ? 1 : 0; | |
| 3125 | - | |
| 3126 | - //error_log('Pinecone enabled flag: ' . $use_pinecone); | |
| 3127 | - | |
| 3128 | - if ($use_pinecone === 1) { | |
| 3129 | - //error_log('MXChat Vector Search: Using Pinecone database'); | |
| 3130 | - return $this->find_relevant_content_pinecone($user_embedding); | |
| 3131 | - } else { | |
| 3132 | - //error_log('MXChat Vector Search: Using WordPress database'); | |
| 3133 | - return $this->find_relevant_content_wordpress($user_embedding); | |
| 3134 | - } | |
| 3135 | -} | |
| 3136 | - | |
| 3137 | -private function find_relevant_content_wordpress($user_embedding) { | |
| 3138 | 2945 | global $wpdb; |
| 3139 | 2946 | $system_prompt_table = $wpdb->prefix . 'mxchat_system_prompt_content'; |
| 3140 | 2947 | $cache_key = 'mxchat_system_prompt_embeddings'; |
| 3141 | - $batch_size = 500; | |
| 3142 | 2948 | |
| 3143 | 2949 | // Retrieve embeddings from cache or database |
| 3144 | 2950 | $embeddings = wp_cache_get($cache_key, 'mxchat_system_prompts'); |
| 3145 | 2951 | if ($embeddings === false) { |
| 3146 | - $embeddings = []; | |
| 3147 | - $offset = 0; | |
| 3148 | - | |
| 3149 | - // Load in batches and build cache | |
| 3150 | - do { | |
| 3151 | - $query = $wpdb->prepare( | |
| 3152 | - "SELECT id, embedding_vector | |
| 3153 | - FROM {$system_prompt_table} | |
| 3154 | - LIMIT %d OFFSET %d", | |
| 3155 | - $batch_size, | |
| 3156 | - $offset | |
| 3157 | - ); | |
| 3158 | - | |
| 3159 | - $batch = $wpdb->get_results($query); | |
| 3160 | - if (empty($batch)) { | |
| 3161 | - break; | |
| 3162 | - } | |
| 3163 | - | |
| 3164 | - $embeddings = array_merge($embeddings, $batch); | |
| 3165 | - $offset += $batch_size; | |
| 3166 | - | |
| 3167 | - // Free memory | |
| 3168 | - unset($batch); | |
| 3169 | - | |
| 3170 | - } while (true); | |
| 3171 | - | |
| 3172 | - if (empty($embeddings)) { | |
| 2952 | + $query = "SELECT id, embedding_vector FROM {$system_prompt_table}"; | |
| 2953 | + $embeddings = $wpdb->get_results($query); | |
| 2954 | + if ($embeddings === null || empty($embeddings)) { | |
| 3173 | 2955 | return ''; // Return an empty string if no embeddings found |
| 3174 | 2956 | } |
| 3175 | 2957 | wp_cache_set($cache_key, $embeddings, 'mxchat_system_prompts', 3600); |
| 3176 | 2958 | } |
| @@ -3176,13 +2958,15 @@ | ||
| 3176 | 2958 | } |
| 3177 | 2959 | |
| 3178 | 2960 | // Initialize array to store relevant results with similarity scores |
| 3179 | 2961 | $relevant_results = []; |
| 2962 | + | |
| 3180 | 2963 | // Iterate through embeddings to calculate similarity |
| 3181 | 2964 | foreach ($embeddings as $embedding) { |
| 3182 | 2965 | $database_embedding = $embedding->embedding_vector |
| 3183 | 2966 | ? unserialize($embedding->embedding_vector, ['allowed_classes' => false]) |
| 3184 | 2967 | : null; |
| 2968 | + | |
| 3185 | 2969 | if (is_array($database_embedding) && is_array($user_embedding)) { |
| 3186 | 2970 | $similarity = $this->mxchat_calculate_cosine_similarity($user_embedding, $database_embedding); |
| 3187 | 2971 | $relevant_results[] = [ |
| 3188 | 2972 | 'id' => $embedding->id, |
| @@ -3188,10 +2972,8 @@ | ||
| 3188 | 2972 | 'id' => $embedding->id, |
| 3189 | 2973 | 'similarity' => $similarity |
| 3190 | 2974 | ]; |
| 3191 | 2975 | } |
| 3192 | - // Free memory | |
| 3193 | - unset($database_embedding); | |
| 3194 | 2976 | } |
| 3195 | 2977 | |
| 3196 | 2978 | // Retrieve the similarity threshold |
| 3197 | 2979 | $similarity_threshold = ((int) get_option('mxchat_similarity_threshold', 80)) / 100; |
| @@ -3212,8 +2994,9 @@ | ||
| 3212 | 2994 | |
| 3213 | 2995 | // Fetch and combine content for the top results |
| 3214 | 2996 | foreach ($top_results as $result) { |
| 3215 | 2997 | $chunk_content = $this->fetch_content_with_product_links($result['id']); |
| 2998 | + | |
| 3216 | 2999 | // Check if the content is PDF-related and add surrounding pages |
| 3217 | 3000 | if (strpos($chunk_content, '{"document_type":"pdf"') !== false) { |
| 3218 | 3001 | $surrounding_content = $wpdb->get_results($wpdb->prepare( |
| 3219 | 3002 | "SELECT article_content FROM {$system_prompt_table} |
| @@ -3223,14 +3006,17 @@ | ||
| 3223 | 3006 | )", |
| 3224 | 3007 | $result['id'], |
| 3225 | 3008 | $result['id'] |
| 3226 | 3009 | )); |
| 3010 | + | |
| 3227 | 3011 | // Add previous content if it exists |
| 3228 | 3012 | if (!empty($surrounding_content[0])) { |
| 3229 | 3013 | $content .= $surrounding_content[0]->article_content . "\n\n"; |
| 3230 | 3014 | } |
| 3015 | + | |
| 3231 | 3016 | // Add the main chunk content |
| 3232 | 3017 | $content .= $chunk_content . "\n\n"; |
| 3018 | + | |
| 3233 | 3019 | // Add next content if it exists |
| 3234 | 3020 | if (!empty($surrounding_content[1])) { |
| 3235 | 3021 | $content .= $surrounding_content[1]->article_content . "\n\n"; |
| 3236 | 3022 | } |
| @@ -3239,148 +3025,36 @@ | ||
| 3239 | 3025 | $content .= $chunk_content . "\n\n"; |
| 3240 | 3026 | } |
| 3241 | 3027 | } |
| 3242 | 3028 | |
| 3243 | - return trim($content); | |
| 3029 | + return trim($content); // Return the combined content | |
| 3244 | 3030 | } |
| 3245 | -/** | |
| 3246 | - * Find relevant content in Pinecone vector database | |
| 3247 | - */ | |
| 3248 | -private function find_relevant_content_pinecone($user_embedding) { | |
| 3249 | - $options = get_option('mxchat_pinecone_addon_options', array()); | |
| 3250 | - $api_key = $options['mxchat_pinecone_api_key'] ?? ''; | |
| 3251 | - $host = $options['mxchat_pinecone_host'] ?? ''; | |
| 3252 | 3031 | |
| 3253 | - if (empty($host) || empty($api_key)) { | |
| 3254 | - //error_log('Pinecone credentials not properly configured'); | |
| 3255 | - return ''; | |
| 3256 | - } | |
| 3257 | - | |
| 3258 | - // Get similarity threshold from WordPress settings | |
| 3259 | - $similarity_threshold = ((int) get_option('mxchat_similarity_threshold', 80)) / 100; | |
| 3260 | - | |
| 3261 | - // Prepare the query request for Pinecone | |
| 3262 | - $api_endpoint = "https://{$host}/query"; | |
| 3263 | - | |
| 3264 | - $request_body = array( | |
| 3265 | - 'vector' => $user_embedding, | |
| 3266 | - 'topK' => 5, | |
| 3267 | - 'includeMetadata' => true, | |
| 3268 | - 'includeValues' => true | |
| 3269 | - ); | |
| 3270 | - | |
| 3271 | - $response = wp_remote_post($api_endpoint, array( | |
| 3272 | - 'headers' => array( | |
| 3273 | - 'Api-Key' => $api_key, | |
| 3274 | - 'accept' => 'application/json', | |
| 3275 | - 'content-type' => 'application/json' | |
| 3276 | - ), | |
| 3277 | - 'body' => wp_json_encode($request_body), | |
| 3278 | - 'timeout' => 30 | |
| 3279 | - )); | |
| 3280 | - | |
| 3281 | - if (is_wp_error($response)) { | |
| 3282 | - //error_log('Pinecone query error: ' . $response->get_error_message()); | |
| 3283 | - return ''; | |
| 3284 | - } | |
| 3285 | - | |
| 3286 | - $response_code = wp_remote_retrieve_response_code($response); | |
| 3287 | - if ($response_code !== 200) { | |
| 3288 | - //error_log('Pinecone API error: ' . wp_remote_retrieve_body($response)); | |
| 3289 | - return ''; | |
| 3290 | - } | |
| 3291 | - | |
| 3292 | - $results = json_decode(wp_remote_retrieve_body($response), true); | |
| 3293 | - if (empty($results['matches'])) { | |
| 3294 | - return ''; | |
| 3295 | - } | |
| 3296 | - | |
| 3297 | - // Initialize the final content | |
| 3298 | - $content = ''; | |
| 3299 | - | |
| 3300 | - // Process each match | |
| 3301 | - foreach ($results['matches'] as $match) { | |
| 3302 | - // Skip if similarity is below threshold | |
| 3303 | - if ($match['score'] < $similarity_threshold) { | |
| 3304 | - continue; | |
| 3305 | - } | |
| 3306 | - | |
| 3307 | - if (!empty($match['metadata']['text']) && !empty($match['metadata']['source_url'])) { | |
| 3308 | - // Add content with citation | |
| 3309 | - $content .= $match['metadata']['text'] . "\n"; | |
| 3310 | - $content .= "Source: " . $match['metadata']['source_url'] . "\n\n"; | |
| 3311 | - } | |
| 3312 | - } | |
| 3313 | - | |
| 3314 | - return trim($content); | |
| 3315 | -} | |
| 3316 | - | |
| 3317 | - | |
| 3318 | 3032 | private function mxchat_find_relevant_products($user_embedding) { |
| 3319 | - //error_log('MXChat Vector Search: Starting product search...'); | |
| 3320 | - | |
| 3321 | - // Retrieve the add-on settings from the database | |
| 3322 | - $addon_options = get_option('mxchat_pinecone_addon_options', array()); | |
| 3323 | - | |
| 3324 | - // Determine whether Pinecone is enabled | |
| 3325 | - $use_pinecone = (isset($addon_options['mxchat_use_pinecone']) && $addon_options['mxchat_use_pinecone'] === '1') ? 1 : 0; | |
| 3326 | - | |
| 3327 | - //error_log('Pinecone enabled flag: ' . $use_pinecone); | |
| 3328 | - | |
| 3329 | - if ($use_pinecone === 1) { | |
| 3330 | - //error_log('MXChat Vector Search: Using Pinecone database for products'); | |
| 3331 | - return $this->find_relevant_products_pinecone($user_embedding); | |
| 3332 | - } else { | |
| 3333 | - //error_log('MXChat Vector Search: Using WordPress database for products'); | |
| 3334 | - return $this->find_relevant_products_wordpress($user_embedding); | |
| 3335 | - } | |
| 3336 | -} | |
| 3337 | - | |
| 3338 | -private function find_relevant_products_wordpress($user_embedding) { | |
| 3339 | 3033 | global $wpdb; |
| 3340 | 3034 | $system_prompt_table = $wpdb->prefix . 'mxchat_system_prompt_content'; |
| 3341 | 3035 | $cache_key = 'mxchat_system_prompt_embeddings'; |
| 3342 | - $batch_size = 500; | |
| 3343 | 3036 | |
| 3344 | - // Original WordPress database search logic | |
| 3345 | - // [Previous implementation remains the same] | |
| 3037 | + // Retrieve embeddings from cache or database | |
| 3346 | 3038 | $embeddings = wp_cache_get($cache_key, 'mxchat_system_prompts'); |
| 3347 | 3039 | if ($embeddings === false) { |
| 3348 | - $embeddings = []; | |
| 3349 | - $offset = 0; | |
| 3350 | - | |
| 3351 | - do { | |
| 3352 | - $query = $wpdb->prepare( | |
| 3353 | - "SELECT id, embedding_vector | |
| 3354 | - FROM {$system_prompt_table} | |
| 3355 | - LIMIT %d OFFSET %d", | |
| 3356 | - $batch_size, | |
| 3357 | - $offset | |
| 3358 | - ); | |
| 3359 | - | |
| 3360 | - $batch = $wpdb->get_results($query); | |
| 3361 | - if (empty($batch)) { | |
| 3362 | - break; | |
| 3363 | - } | |
| 3364 | - | |
| 3365 | - $embeddings = array_merge($embeddings, $batch); | |
| 3366 | - $offset += $batch_size; | |
| 3367 | - | |
| 3368 | - unset($batch); | |
| 3369 | - | |
| 3370 | - } while (true); | |
| 3371 | - | |
| 3372 | - if (empty($embeddings)) { | |
| 3373 | - return ''; | |
| 3040 | + $query = "SELECT id, embedding_vector FROM {$system_prompt_table}"; | |
| 3041 | + $embeddings = $wpdb->get_results($query); | |
| 3042 | + if ($embeddings === null || empty($embeddings)) { | |
| 3043 | + return ''; // Return an empty string if no embeddings found | |
| 3374 | 3044 | } |
| 3375 | 3045 | wp_cache_set($cache_key, $embeddings, 'mxchat_system_prompts', 3600); |
| 3376 | 3046 | } |
| 3377 | 3047 | |
| 3048 | + // Initialize array to store relevant results with similarity scores | |
| 3378 | 3049 | $relevant_results = []; |
| 3050 | + | |
| 3051 | + // Iterate through embeddings to calculate similarity | |
| 3379 | 3052 | foreach ($embeddings as $embedding) { |
| 3380 | 3053 | $database_embedding = $embedding->embedding_vector |
| 3381 | 3054 | ? unserialize($embedding->embedding_vector, ['allowed_classes' => false]) |
| 3382 | 3055 | : null; |
| 3056 | + | |
| 3383 | 3057 | if (is_array($database_embedding) && is_array($user_embedding)) { |
| 3384 | 3058 | $similarity = $this->mxchat_calculate_cosine_similarity($user_embedding, $database_embedding); |
| 3385 | 3059 | $relevant_results[] = [ |
| 3386 | 3060 | 'id' => $embedding->id, |
| @@ -3386,14 +3060,14 @@ | ||
| 3386 | 3060 | 'id' => $embedding->id, |
| 3387 | 3061 | 'similarity' => $similarity |
| 3388 | 3062 | ]; |
| 3389 | 3063 | } |
| 3390 | - unset($database_embedding); | |
| 3391 | 3064 | } |
| 3392 | 3065 | |
| 3393 | - // Use fixed threshold for products | |
| 3066 | +// Use a fixed similarity threshold of 0.85 | |
| 3394 | 3067 | $similarity_threshold = 0.85; |
| 3395 | 3068 | |
| 3069 | + // Filter and sort relevant results by similarity | |
| 3396 | 3070 | $relevant_results = array_filter($relevant_results, function ($result) use ($similarity_threshold) { |
| 3397 | 3071 | return $result['similarity'] >= $similarity_threshold; |
| 3398 | 3072 | }); |
| 3399 | 3073 | usort($relevant_results, function ($a, $b) { |
| @@ -3399,98 +3073,51 @@ | ||
| 3399 | 3073 | usort($relevant_results, function ($a, $b) { |
| 3400 | 3074 | return $b['similarity'] <=> $a['similarity']; |
| 3401 | 3075 | }); |
| 3402 | 3076 | |
| 3077 | + // Limit to the top 5 results | |
| 3403 | 3078 | $top_results = array_slice($relevant_results, 0, 5); |
| 3079 | + | |
| 3080 | + // Initialize the final content | |
| 3404 | 3081 | $content = ''; |
| 3405 | 3082 | |
| 3083 | + // Fetch and combine content for the top results | |
| 3406 | 3084 | foreach ($top_results as $result) { |
| 3407 | 3085 | $chunk_content = $this->fetch_content_with_product_links($result['id']); |
| 3408 | - $content .= $chunk_content . "\n\n"; | |
| 3409 | - } | |
| 3410 | 3086 | |
| 3411 | - return trim($content); | |
| 3412 | -} | |
| 3087 | + // Check if the content is PDF-related and add surrounding pages | |
| 3088 | + if (strpos($chunk_content, '{"document_type":"pdf"') !== false) { | |
| 3089 | + $surrounding_content = $wpdb->get_results($wpdb->prepare( | |
| 3090 | + "SELECT article_content FROM {$system_prompt_table} | |
| 3091 | + WHERE id IN ( | |
| 3092 | + (SELECT id FROM {$system_prompt_table} WHERE id < %d ORDER BY id DESC LIMIT 1), | |
| 3093 | + (SELECT id FROM {$system_prompt_table} WHERE id > %d ORDER BY id ASC LIMIT 1) | |
| 3094 | + )", | |
| 3095 | + $result['id'], | |
| 3096 | + $result['id'] | |
| 3097 | + )); | |
| 3413 | 3098 | |
| 3414 | -// Modified search function with correct filter syntax | |
| 3415 | -private function find_relevant_products_pinecone($user_embedding) { | |
| 3416 | - //error_log('Starting Pinecone product search...'); | |
| 3099 | + // Add previous content if it exists | |
| 3100 | + if (!empty($surrounding_content[0])) { | |
| 3101 | + $content .= $surrounding_content[0]->article_content . "\n\n"; | |
| 3102 | + } | |
| 3417 | 3103 | |
| 3418 | - $options = get_option('mxchat_pinecone_addon_options', array()); | |
| 3419 | - $api_key = $options['mxchat_pinecone_api_key'] ?? ''; | |
| 3420 | - $host = $options['mxchat_pinecone_host'] ?? ''; | |
| 3104 | + // Add the main chunk content | |
| 3105 | + $content .= $chunk_content . "\n\n"; | |
| 3421 | 3106 | |
| 3422 | - if (empty($host) || empty($api_key)) { | |
| 3423 | - //error_log('Pinecone credentials not properly configured for product search'); | |
| 3424 | - return ''; | |
| 3425 | - } | |
| 3426 | - | |
| 3427 | - $similarity_threshold = 0.85; | |
| 3428 | - $api_endpoint = "https://{$host}/query"; | |
| 3429 | - | |
| 3430 | - $request_body = array( | |
| 3431 | - 'vector' => $user_embedding, | |
| 3432 | - 'topK' => 5, | |
| 3433 | - 'includeMetadata' => true, | |
| 3434 | - 'includeValues' => true, | |
| 3435 | - 'filter' => array( | |
| 3436 | - 'type' => 'product' | |
| 3437 | - ) | |
| 3438 | - ); | |
| 3439 | - | |
| 3440 | - //error_log('Sending request to Pinecone with body: ' . wp_json_encode($request_body)); | |
| 3441 | - | |
| 3442 | - $response = wp_remote_post($api_endpoint, array( | |
| 3443 | - 'headers' => array( | |
| 3444 | - 'Api-Key' => $api_key, | |
| 3445 | - 'accept' => 'application/json', | |
| 3446 | - 'content-type' => 'application/json' | |
| 3447 | - ), | |
| 3448 | - 'body' => wp_json_encode($request_body), | |
| 3449 | - 'timeout' => 30 | |
| 3450 | - )); | |
| 3451 | - | |
| 3452 | - if (is_wp_error($response)) { | |
| 3453 | - //error_log('Pinecone product query error: ' . $response->get_error_message()); | |
| 3454 | - return ''; | |
| 3455 | - } | |
| 3456 | - | |
| 3457 | - $response_code = wp_remote_retrieve_response_code($response); | |
| 3458 | - //error_log('Pinecone response code: ' . $response_code); | |
| 3459 | - | |
| 3460 | - if ($response_code !== 200) { | |
| 3461 | - //error_log('Pinecone API error during product search: ' . wp_remote_retrieve_body($response)); | |
| 3462 | - return ''; | |
| 3463 | - } | |
| 3464 | - | |
| 3465 | - $results = json_decode(wp_remote_retrieve_body($response), true); | |
| 3466 | - //error_log('Pinecone raw response: ' . wp_remote_retrieve_body($response)); | |
| 3467 | - | |
| 3468 | - if (empty($results['matches'])) { | |
| 3469 | - //error_log('No matches found in Pinecone response'); | |
| 3470 | - return ''; | |
| 3471 | - } | |
| 3472 | - | |
| 3473 | - $content = ''; | |
| 3474 | - foreach ($results['matches'] as $match) { | |
| 3475 | - if ($match['score'] < $similarity_threshold) { | |
| 3476 | - //error_log("Match below threshold: " . $match['score']); | |
| 3477 | - continue; | |
| 3478 | - } | |
| 3479 | - | |
| 3480 | - if (!empty($match['metadata']['text'])) { | |
| 3481 | - $content .= $match['metadata']['text']; | |
| 3482 | - if (!empty($match['metadata']['source_url'])) { | |
| 3483 | - $content .= "\n\nFor more details, check out this product: " . esc_url($match['metadata']['source_url']); | |
| 3107 | + // Add next content if it exists | |
| 3108 | + if (!empty($surrounding_content[1])) { | |
| 3109 | + $content .= $surrounding_content[1]->article_content . "\n\n"; | |
| 3484 | 3110 | } |
| 3485 | - $content .= "\n\n"; | |
| 3111 | + } else { | |
| 3112 | + // For non-PDF content, add directly | |
| 3113 | + $content .= $chunk_content . "\n\n"; | |
| 3486 | 3114 | } |
| 3487 | 3115 | } |
| 3488 | 3116 | |
| 3489 | - return trim($content); | |
| 3117 | + return trim($content); // Return the combined content | |
| 3490 | 3118 | } |
| 3491 | 3119 | |
| 3492 | - | |
| 3493 | 3120 | private function fetch_content_with_product_links($most_relevant_id) { |
| 3494 | 3121 | global $wpdb; |
| 3495 | 3122 | $system_prompt_table = $wpdb->prefix . 'mxchat_system_prompt_content'; |
| 3496 | 3123 | |
| @@ -3509,216 +3136,76 @@ | ||
| 3509 | 3136 | |
| 3510 | 3137 | return null; |
| 3511 | 3138 | } |
| 3512 | 3139 | |
| 3513 | -// Function definition | |
| 3514 | -private function mxchat_generate_response($relevant_content, $api_key, $xai_api_key, $claude_api_key, $deepseek_api_key, $conversation_history) { | |
| 3515 | - try { | |
| 3516 | - if (!$relevant_content) { | |
| 3517 | - return esc_html__("I'm sorry, I couldn't find relevant information on that topic.", 'mxchat'); | |
| 3518 | - } | |
| 3519 | - | |
| 3520 | - // Ensure conversation_history is an array | |
| 3521 | - if (!is_array($conversation_history)) { | |
| 3522 | - $conversation_history = array(); | |
| 3523 | - } | |
| 3524 | - | |
| 3525 | - // Get selected model with default fallback | |
| 3526 | - $selected_model = isset($this->options['model']) ? $this->options['model'] : 'gpt-4o'; | |
| 3527 | - | |
| 3528 | - // Extract model prefix to determine the provider | |
| 3529 | - $model_parts = explode('-', $selected_model); | |
| 3530 | - $provider = strtolower($model_parts[0]); | |
| 3531 | - | |
| 3532 | - // Handle model selection based on provider prefix | |
| 3533 | - switch ($provider) { | |
| 3534 | - case 'claude': | |
| 3535 | - if (empty($claude_api_key)) { | |
| 3536 | - throw new Exception(esc_html__('Claude API key is not configured', 'mxchat')); | |
| 3537 | - } | |
| 3538 | - return $this->mxchat_generate_response_claude( | |
| 3539 | - $selected_model, | |
| 3540 | - $claude_api_key, | |
| 3541 | - $conversation_history, | |
| 3542 | - $relevant_content | |
| 3543 | - ); | |
| 3544 | - | |
| 3545 | - case 'grok': | |
| 3546 | - if (empty($xai_api_key)) { | |
| 3547 | - throw new Exception(esc_html__('X.AI API key is not configured', 'mxchat')); | |
| 3548 | - } | |
| 3549 | - return $this->mxchat_generate_response_xai( | |
| 3550 | - $selected_model, | |
| 3551 | - $xai_api_key, | |
| 3552 | - $conversation_history, | |
| 3553 | - $relevant_content | |
| 3554 | - ); | |
| 3555 | - | |
| 3556 | - case 'deepseek': | |
| 3557 | - if (empty($deepseek_api_key)) { | |
| 3558 | - throw new Exception(esc_html__('DeepSeek API key is not configured', 'mxchat')); | |
| 3559 | - } | |
| 3560 | - return $this->mxchat_generate_response_deepseek( | |
| 3561 | - $selected_model, | |
| 3562 | - $deepseek_api_key, | |
| 3563 | - $conversation_history, | |
| 3564 | - $relevant_content | |
| 3565 | - ); | |
| 3566 | - | |
| 3567 | - case 'gpt': | |
| 3568 | - if (empty($api_key)) { | |
| 3569 | - throw new Exception(esc_html__('OpenAI API key is not configured', 'mxchat')); | |
| 3570 | - } | |
| 3571 | - return $this->mxchat_generate_response_openai( | |
| 3572 | - $selected_model, | |
| 3573 | - $api_key, | |
| 3574 | - $conversation_history, | |
| 3575 | - $relevant_content | |
| 3576 | - ); | |
| 3577 | - | |
| 3578 | - default: | |
| 3579 | - // Default to OpenAI for custom models or unrecognized prefixes | |
| 3580 | - if (empty($api_key)) { | |
| 3581 | - throw new Exception(esc_html__('OpenAI API key is not configured', 'mxchat')); | |
| 3582 | - } | |
| 3583 | - return $this->mxchat_generate_response_openai( | |
| 3584 | - $selected_model, | |
| 3585 | - $api_key, | |
| 3586 | - $conversation_history, | |
| 3587 | - $relevant_content | |
| 3588 | - ); | |
| 3589 | - } | |
| 3590 | - } catch (Exception $e) { | |
| 3591 | - //error_log('MXChat Error: ' . $e->getMessage()); | |
| 3592 | - return sprintf( | |
| 3593 | - esc_html__('An error occurred: %s', 'mxchat'), | |
| 3594 | - esc_html($e->getMessage()) | |
| 3595 | - ); | |
| 3140 | +private function mxchat_generate_response($relevant_content, $api_key, $xai_api_key, $claude_api_key, $conversation_history) { | |
| 3141 | + if (!$relevant_content) { | |
| 3142 | + return "I'm sorry, I couldn't find relevant information on that topic."; | |
| 3596 | 3143 | } |
| 3597 | -} | |
| 3598 | 3144 | |
| 3145 | + // Check the selected model | |
| 3146 | + $selected_model = isset($this->options['model']) ? $this->options['model'] : 'gpt-3.5-turbo'; | |
| 3599 | 3147 | |
| 3600 | -private function mxchat_generate_response_deepseek($selected_model, $deepseek_api_key, $conversation_history, $relevant_content) { | |
| 3601 | - // Ensure conversation_history is an array | |
| 3602 | - if (!is_array($conversation_history)) { | |
| 3603 | - $conversation_history = array(); | |
| 3604 | - } | |
| 3605 | - | |
| 3606 | - // Get system prompt instructions from options | |
| 3607 | - $system_prompt_instructions = isset($this->options['system_prompt_instructions']) ? $this->options['system_prompt_instructions'] : ''; | |
| 3608 | - | |
| 3609 | - // Create a new array for the formatted conversation | |
| 3610 | - $formatted_conversation = array(); | |
| 3611 | - | |
| 3612 | - // Add system message first | |
| 3613 | - $formatted_conversation[] = array( | |
| 3614 | - 'role' => 'system', | |
| 3615 | - 'content' => $system_prompt_instructions . " " . $relevant_content | |
| 3616 | - ); | |
| 3617 | - | |
| 3618 | - // Add the rest of the conversation history | |
| 3619 | - foreach ($conversation_history as $message) { | |
| 3620 | - if (is_array($message) && isset($message['role']) && isset($message['content'])) { | |
| 3621 | - $role = $message['role']; | |
| 3622 | - | |
| 3623 | - // Convert roles to supported format | |
| 3624 | - if ($role === 'bot' || $role === 'agent') { | |
| 3625 | - $role = 'assistant'; | |
| 3626 | - } | |
| 3627 | - if (!in_array($role, ['system', 'assistant', 'user', 'function', 'tool'])) { | |
| 3628 | - $role = 'user'; | |
| 3629 | - } | |
| 3630 | - | |
| 3631 | - $formatted_conversation[] = array( | |
| 3632 | - 'role' => $role, | |
| 3633 | - 'content' => $message['content'] | |
| 3634 | - ); | |
| 3635 | - } | |
| 3636 | - } | |
| 3637 | - | |
| 3638 | - $body = json_encode([ | |
| 3639 | - 'model' => $selected_model, | |
| 3640 | - 'messages' => $formatted_conversation, | |
| 3641 | - 'temperature' => 0.8, | |
| 3642 | - 'stream' => false | |
| 3643 | - ]); | |
| 3644 | - | |
| 3645 | - $args = [ | |
| 3646 | - 'body' => $body, | |
| 3647 | - 'headers' => [ | |
| 3648 | - 'Content-Type' => 'application/json', | |
| 3649 | - 'Authorization' => 'Bearer ' . $deepseek_api_key, | |
| 3650 | - ], | |
| 3651 | - 'timeout' => 60, | |
| 3652 | - 'redirection' => 5, | |
| 3653 | - 'blocking' => true, | |
| 3654 | - 'httpversion' => '1.0', | |
| 3655 | - 'sslverify' => true, | |
| 3656 | - ]; | |
| 3657 | - | |
| 3658 | - $response = wp_remote_post('https://api.deepseek.com/v1/chat/completions', $args); | |
| 3659 | - | |
| 3660 | - if (is_wp_error($response)) { | |
| 3661 | - //error_log('DeepSeek API Error: ' . $response->get_error_message()); | |
| 3662 | - return "Sorry, there was an error processing your request."; | |
| 3663 | - } | |
| 3664 | - | |
| 3665 | - $response_body = wp_remote_retrieve_body($response); | |
| 3666 | - $decoded_response = json_decode($response_body, true); | |
| 3667 | - | |
| 3668 | - if (isset($decoded_response['choices'][0]['message']['content'])) { | |
| 3669 | - return trim($decoded_response['choices'][0]['message']['content']); | |
| 3148 | + // Call the appropriate function based on the selected model | |
| 3149 | + if (strpos($selected_model, 'claude') !== false) { | |
| 3150 | + return $this->mxchat_generate_response_claude($selected_model, $claude_api_key, $conversation_history, $relevant_content); | |
| 3151 | + } elseif ($selected_model === 'grok-beta') { | |
| 3152 | + return $this->mxchat_generate_response_xai($selected_model, $xai_api_key, $conversation_history, $relevant_content); | |
| 3670 | 3153 | } else { |
| 3671 | - //error_log('DeepSeek API Response Format Error: ' . print_r($decoded_response, true)); | |
| 3672 | - return "Sorry, I couldn't process that request."; | |
| 3154 | + return $this->mxchat_generate_response_openai($selected_model, $api_key, $conversation_history, $relevant_content); | |
| 3673 | 3155 | } |
| 3674 | 3156 | } |
| 3675 | 3157 | |
| 3676 | 3158 | private function mxchat_generate_response_openai($selected_model, $api_key, $conversation_history, $relevant_content) { |
| 3677 | - // Ensure conversation_history is an array | |
| 3678 | - if (!is_array($conversation_history)) { | |
| 3679 | - $conversation_history = array(); | |
| 3680 | - } | |
| 3681 | - | |
| 3682 | 3159 | // Get system prompt instructions from options |
| 3683 | 3160 | $system_prompt_instructions = isset($this->options['system_prompt_instructions']) ? $this->options['system_prompt_instructions'] : ''; |
| 3684 | 3161 | |
| 3685 | - // Create a new array for the formatted conversation | |
| 3686 | - $formatted_conversation = array(); | |
| 3162 | + // Add system prompt to relevant content | |
| 3163 | + $content_with_instructions = $system_prompt_instructions . " " . $relevant_content; | |
| 3687 | 3164 | |
| 3688 | - // Add system message first | |
| 3689 | - $formatted_conversation[] = array( | |
| 3165 | + // Prepend system instructions to the conversation history | |
| 3166 | + array_unshift($conversation_history, [ | |
| 3690 | 3167 | 'role' => 'system', |
| 3691 | - 'content' => $system_prompt_instructions . " " . $relevant_content | |
| 3692 | - ); | |
| 3168 | + 'content' => "Here are your instructions: " . $content_with_instructions | |
| 3169 | + ]); | |
| 3693 | 3170 | |
| 3694 | - // Add the rest of the conversation history | |
| 3695 | - foreach ($conversation_history as $message) { | |
| 3696 | - if (is_array($message) && isset($message['role']) && isset($message['content'])) { | |
| 3697 | - $role = $message['role']; | |
| 3171 | + // Log the system prompt and relevant content | |
| 3172 | + //error_log("System Prompt Instructions: " . $system_prompt_instructions); | |
| 3173 | + //error_log("Relevant Content: " . substr($relevant_content, 0, 500)); // Log first 500 characters for brevity | |
| 3698 | 3174 | |
| 3699 | - // Convert roles to supported format | |
| 3700 | - if ($role === 'bot' || $role === 'agent') { | |
| 3701 | - $role = 'assistant'; | |
| 3175 | + // Ensure consistency: Replace 'bot' and 'agent' roles with supported values | |
| 3176 | + foreach ($conversation_history as &$message) { | |
| 3177 | + if ($message['role'] === 'bot') { | |
| 3178 | + $message['role'] = 'assistant'; | |
| 3179 | + } elseif ($message['role'] === 'agent') { | |
| 3180 | + // Tag the message as coming from a live agent | |
| 3181 | + $message['role'] = 'assistant'; | |
| 3182 | + if (!isset($message['metadata'])) { | |
| 3183 | + $message['metadata'] = ['source' => 'live_agent']; | |
| 3702 | 3184 | } |
| 3703 | - if (!in_array($role, ['system', 'assistant', 'user', 'function', 'tool'])) { | |
| 3704 | - $role = 'user'; | |
| 3705 | - } | |
| 3185 | + } | |
| 3706 | 3186 | |
| 3707 | - $formatted_conversation[] = array( | |
| 3708 | - 'role' => $role, | |
| 3709 | - 'content' => $message['content'] | |
| 3710 | - ); | |
| 3187 | + // Ensure all roles are valid | |
| 3188 | + if (!in_array($message['role'], ['system', 'assistant', 'user', 'function', 'tool'])) { | |
| 3189 | + $message['role'] = 'user'; // Default to 'user' | |
| 3711 | 3190 | } |
| 3712 | 3191 | } |
| 3713 | 3192 | |
| 3193 | + // Log the formatted conversation history | |
| 3194 | + //error_log("Conversation History: " . json_encode($conversation_history, JSON_PRETTY_PRINT)); | |
| 3195 | + | |
| 3196 | + // Build the request body | |
| 3714 | 3197 | $body = json_encode([ |
| 3715 | 3198 | 'model' => $selected_model, |
| 3716 | - 'messages' => $formatted_conversation, | |
| 3199 | + 'messages' => $conversation_history, | |
| 3717 | 3200 | 'temperature' => 0.8, |
| 3718 | 3201 | 'stream' => false |
| 3719 | 3202 | ]); |
| 3720 | 3203 | |
| 3204 | + // Log the full API request body | |
| 3205 | + //error_log("OpenAI API Request Body: " . $body); | |
| 3206 | + | |
| 3207 | + // Set up the API request | |
| 3721 | 3208 | $args = [ |
| 3722 | 3209 | 'body' => $body, |
| 3723 | 3210 | 'headers' => [ |
| 3724 | 3211 | 'Content-Type' => 'application/json', |
| @@ -3730,25 +3217,37 @@ | ||
| 3730 | 3217 | 'httpversion' => '1.0', |
| 3731 | 3218 | 'sslverify' => true, |
| 3732 | 3219 | ]; |
| 3733 | 3220 | |
| 3221 | + // Make the API request | |
| 3734 | 3222 | $response = wp_remote_post('https://api.openai.com/v1/chat/completions', $args); |
| 3735 | 3223 | |
| 3224 | + // Log the response or error | |
| 3736 | 3225 | if (is_wp_error($response)) { |
| 3737 | - //error_log('OpenAI API Error: ' . $response->get_error_message()); | |
| 3226 | + //error_log("OpenAI API Error: " . $response->get_error_message()); | |
| 3738 | 3227 | return "Sorry, there was an error processing your request."; |
| 3739 | 3228 | } |
| 3740 | 3229 | |
| 3230 | + // Log the raw API response | |
| 3231 | + //error_log("OpenAI API Raw Response: " . print_r($response, true)); | |
| 3232 | + | |
| 3741 | 3233 | $response_body = wp_remote_retrieve_body($response); |
| 3742 | 3234 | $decoded_response = json_decode($response_body, true); |
| 3743 | 3235 | |
| 3236 | + // Log the decoded API response | |
| 3237 | + error_log("OpenAI API Decoded Response: " . json_encode($decoded_response, JSON_PRETTY_PRINT)); | |
| 3238 | + | |
| 3744 | 3239 | if (isset($decoded_response['choices'][0]['message']['content'])) { |
| 3745 | - return trim($decoded_response['choices'][0]['message']['content']); | |
| 3240 | + $response_text = trim($decoded_response['choices'][0]['message']['content']); | |
| 3241 | + //error_log("OpenAI API Final Response: " . $response_text); | |
| 3242 | + return $response_text; | |
| 3746 | 3243 | } else { |
| 3747 | - //error_log('OpenAI API Response Format Error: ' . print_r($decoded_response, true)); | |
| 3244 | + // Log an error if the expected response format is missing | |
| 3245 | + //error_log("OpenAI API Response Format Error: Expected 'choices[0][message][content]' not found."); | |
| 3748 | 3246 | return "Sorry, I couldn't process that request."; |
| 3749 | 3247 | } |
| 3750 | 3248 | } |
| 3249 | + | |
| 3751 | 3250 | private function mxchat_generate_response_xai($selected_model, $xai_api_key, $conversation_history, $relevant_content) { |
| 3752 | 3251 | // Get system prompt instructions from options |
| 3753 | 3252 | $system_prompt_instructions = isset($this->options['system_prompt_instructions']) ? $this->options['system_prompt_instructions'] : ''; |
| 3754 | 3253 | |
| @@ -3819,107 +3318,83 @@ | ||
| 3819 | 3318 | } |
| 3820 | 3319 | } |
| 3821 | 3320 | |
| 3822 | 3321 | private function mxchat_generate_response_claude($selected_model, $claude_api_key, $conversation_history, $relevant_content) { |
| 3823 | - // Get system prompt instructions from options | |
| 3322 | + // Get system prompt instructions from options for Claude's top-level system parameter | |
| 3824 | 3323 | $system_prompt_instructions = isset($this->options['system_prompt_instructions']) ? $this->options['system_prompt_instructions'] : ''; |
| 3825 | 3324 | |
| 3826 | - // Clean and validate conversation history | |
| 3325 | + // Ensure consistency: Replace 'bot' and 'agent' roles with supported values | |
| 3827 | 3326 | foreach ($conversation_history as &$message) { |
| 3828 | - // Convert bot and agent roles to assistant | |
| 3829 | - if ($message['role'] === 'bot' || $message['role'] === 'agent') { | |
| 3327 | + if ($message['role'] === 'bot') { | |
| 3830 | 3328 | $message['role'] = 'assistant'; |
| 3329 | + } elseif ($message['role'] === 'agent') { | |
| 3330 | + // Tag the message as coming from a live agent | |
| 3331 | + $message['role'] = 'assistant'; | |
| 3332 | + if (!isset($message['metadata'])) { | |
| 3333 | + $message['metadata'] = ['source' => 'live_agent']; | |
| 3334 | + } | |
| 3831 | 3335 | } |
| 3832 | - | |
| 3833 | - // Remove unsupported roles - Claude only supports 'assistant' and 'user' | |
| 3834 | - if (!in_array($message['role'], ['assistant', 'user'])) { | |
| 3835 | - $message['role'] = 'user'; | |
| 3836 | - } | |
| 3837 | 3336 | |
| 3838 | - // Ensure content field exists | |
| 3839 | - if (!isset($message['content']) || empty($message['content'])) { | |
| 3840 | - $message['content'] = ''; | |
| 3337 | + // Ensure all roles are valid | |
| 3338 | + if (!in_array($message['role'], ['system', 'assistant', 'user', 'function', 'tool'])) { | |
| 3339 | + $message['role'] = 'user'; // Default to 'user' | |
| 3841 | 3340 | } |
| 3842 | - | |
| 3843 | - // Remove any unsupported fields | |
| 3844 | - $message = array_intersect_key($message, array_flip(['role', 'content'])); | |
| 3845 | 3341 | } |
| 3846 | 3342 | |
| 3847 | - // Add relevant content as the latest user message | |
| 3343 | + // Add relevant content as the latest user message in conversation history | |
| 3848 | 3344 | $conversation_history[] = [ |
| 3849 | 3345 | 'role' => 'user', |
| 3850 | 3346 | 'content' => $relevant_content |
| 3851 | 3347 | ]; |
| 3852 | 3348 | |
| 3853 | - // Build request body | |
| 3349 | + // Build the request body with Claude's expected structure, using system instructions as a top-level parameter | |
| 3854 | 3350 | $body = json_encode([ |
| 3855 | 3351 | 'model' => $selected_model, |
| 3856 | 3352 | 'max_tokens' => 1000, |
| 3857 | 3353 | 'temperature' => 0.8, |
| 3858 | - 'messages' => $conversation_history, | |
| 3859 | - 'system' => $system_prompt_instructions | |
| 3354 | + 'system' => $system_prompt_instructions, // Set the system prompt at the top level as required | |
| 3355 | + 'messages' => $conversation_history | |
| 3860 | 3356 | ]); |
| 3861 | 3357 | |
| 3862 | - // Set up API request | |
| 3358 | + // Set up the API request with the necessary headers | |
| 3863 | 3359 | $args = [ |
| 3864 | - 'body' => $body, | |
| 3865 | - 'headers' => [ | |
| 3866 | - 'Content-Type' => 'application/json', | |
| 3867 | - 'x-api-key' => $claude_api_key, | |
| 3868 | - 'anthropic-version' => '2023-06-01' | |
| 3869 | - ], | |
| 3870 | - 'timeout' => 60, | |
| 3360 | + 'body' => $body, | |
| 3361 | + 'headers' => [ | |
| 3362 | + 'Content-Type' => 'application/json', | |
| 3363 | + 'x-api-key' => $claude_api_key, | |
| 3364 | + 'anthropic-version' => '2023-06-01', | |
| 3365 | + ], | |
| 3366 | + 'timeout' => 60, | |
| 3871 | 3367 | 'redirection' => 5, |
| 3872 | - 'blocking' => true, | |
| 3368 | + 'blocking' => true, | |
| 3873 | 3369 | 'httpversion' => '1.0', |
| 3874 | - 'sslverify' => true, | |
| 3370 | + 'sslverify' => true, | |
| 3875 | 3371 | ]; |
| 3876 | 3372 | |
| 3877 | - // Make API request | |
| 3373 | + // Make the API request | |
| 3878 | 3374 | $response = wp_remote_post('https://api.anthropic.com/v1/messages', $args); |
| 3879 | 3375 | |
| 3880 | - // Check for WordPress errors | |
| 3376 | +/* | |
| 3377 | + // Check for errors and log the response for debugging | |
| 3881 | 3378 | if (is_wp_error($response)) { |
| 3882 | - //error_log("Claude API request error: " . $response->get_error_message()); | |
| 3883 | - return "Sorry, there was an error connecting to the API."; | |
| 3379 | + error_log("Claude API request error: " . print_r($response->get_error_message(), true)); | |
| 3380 | + return "Sorry, there was an error processing your request."; | |
| 3884 | 3381 | } |
| 3382 | +*/ | |
| 3885 | 3383 | |
| 3886 | - // Check HTTP response code | |
| 3887 | - $http_code = wp_remote_retrieve_response_code($response); | |
| 3888 | - if ($http_code !== 200) { | |
| 3889 | - $error_body = wp_remote_retrieve_body($response); | |
| 3890 | - //error_log("Claude API HTTP error: " . $http_code . " - " . $error_body); | |
| 3891 | - | |
| 3892 | - // Try to extract error message from response | |
| 3893 | - $error_data = json_decode($error_body, true); | |
| 3894 | - $error_message = isset($error_data['error']['message']) ? | |
| 3895 | - $error_data['error']['message'] : | |
| 3896 | - "HTTP error " . $http_code; | |
| 3897 | - | |
| 3898 | - return "Sorry, the API returned an error: " . $error_message; | |
| 3899 | - } | |
| 3900 | 3384 | |
| 3901 | - // Parse response | |
| 3385 | + // Decode the response and parse according to the expected Claude response structure | |
| 3902 | 3386 | $response_body = json_decode(wp_remote_retrieve_body($response), true); |
| 3903 | - | |
| 3904 | - // Check for JSON decode errors | |
| 3905 | - if (json_last_error() !== JSON_ERROR_NONE) { | |
| 3906 | - //error_log("Claude API JSON decode error: " . json_last_error_msg()); | |
| 3907 | - return "Sorry, there was an error processing the API response."; | |
| 3908 | - } | |
| 3387 | + //error_log("Claude API response: " . print_r($response_body, true)); | |
| 3909 | 3388 | |
| 3910 | - // Extract and validate response content | |
| 3911 | - if (isset($response_body['content']) && | |
| 3912 | - is_array($response_body['content']) && | |
| 3913 | - !empty($response_body['content']) && | |
| 3914 | - isset($response_body['content'][0]['text'])) { | |
| 3389 | + // Check if the response has the expected 'content' array with 'text' blocks | |
| 3390 | + if (isset($response_body['content'][0]['text'])) { | |
| 3915 | 3391 | return trim($response_body['content'][0]['text']); |
| 3392 | + } else { | |
| 3393 | + return "Sorry, I couldn't process that request."; | |
| 3916 | 3394 | } |
| 3395 | +} | |
| 3917 | 3396 | |
| 3918 | - // Log unexpected response format | |
| 3919 | - //error_log("Claude API unexpected response format: " . print_r($response_body, true)); | |
| 3920 | - return "Sorry, I received an unexpected response format from the API."; | |
| 3921 | -} | |
| 3922 | 3397 | public function mxchat_dismiss_pre_chat_message() { |
| 3923 | 3398 | // Get and sanitize the user identifier |
| 3924 | 3399 | $user_id = $this->mxchat_get_user_identifier(); |
| 3925 | 3400 | $user_id = sanitize_key($user_id); |
| @@ -3975,10 +3450,10 @@ | ||
| 3975 | 3450 | } |
| 3976 | 3451 | |
| 3977 | 3452 | public function mxchat_enqueue_scripts_styles() { |
| 3978 | 3453 | // Define version numbers for the styles and scripts |
| 3979 | - $chat_style_version = '2.0.3'; // Replace with your actual version | |
| 3980 | - $chat_script_version = '2.0.3'; // Replace with your actual version | |
| 3454 | + $chat_style_version = '1.5.8'; // Replace with your actual version | |
| 3455 | + $chat_script_version = '1.5.8'; // Replace with your actual version | |
| 3981 | 3456 | |
| 3982 | 3457 | // Enqueue the script |
| 3983 | 3458 | wp_enqueue_script( |
| 3984 | 3459 | 'mxchat-chat-js', |
| @@ -3997,9 +3472,8 @@ | ||
| 3997 | 3472 | ); |
| 3998 | 3473 | |
| 3999 | 3474 | // Fetch options from the database |
| 4000 | 3475 | $this->options = get_option('mxchat_options'); |
| 4001 | - $prompts_options = get_option('mxchat_prompts_options', array()); | |
| 4002 | 3476 | |
| 4003 | 3477 | // Prepare settings for JavaScript |
| 4004 | 3478 | $style_settings = array( |
| 4005 | 3479 | 'ajax_url' => admin_url('admin-ajax.php'), |
| @@ -4026,11 +3500,8 @@ | ||
| 4026 | 3500 | 'chat_toolbar_toggle' => $this->options['chat_toolbar_toggle'] ?? 'off', |
| 4027 | 3501 | 'mode_indicator_bg_color' => $this->options['mode_indicator_bg_color'] ?? '#767676', |
| 4028 | 3502 | 'mode_indicator_font_color' => $this->options['mode_indicator_font_color'] ?? '#ffffff', |
| 4029 | 3503 | 'toolbar_icon_color' => $this->options['toolbar_icon_color'] ?? '#212121', |
| 4030 | - | |
| 4031 | - 'use_pinecone' => $prompts_options['mxchat_use_pinecone'] ?? '0', | |
| 4032 | - 'pinecone_enabled' => isset($prompts_options['mxchat_use_pinecone']) && $prompts_options['mxchat_use_pinecone'] === '1' | |
| 4033 | 3504 | ); |
| 4034 | 3505 | |
| 4035 | 3506 | // Pass the settings to the script |
| 4036 | 3507 | wp_localize_script('mxchat-chat-js', 'mxchatChat', $style_settings); |