| @@ -45,8 +45,9 @@ | ||
| 45 | 45 | add_action('post_updated', array($this, 'handle_post_update'), 10, 3); |
| 46 | 46 | add_action('wp_ajax_mxchat_save_setting', array($this, 'mxchat_save_setting_callback')); |
| 47 | 47 | add_action('wp_trash_post', array($this, 'mxchat_handle_post_delete')); |
| 48 | 48 | add_action('before_delete_post', array($this, 'mxchat_handle_post_delete')); |
| 49 | + add_action('wp_ajax_mxchat_export_transcripts', array($this, 'export_chat_transcripts')); | |
| 49 | 50 | add_action('wp_ajax_mxchat_save_prompts_setting', array($this, 'mxchat_save_prompts_setting_callback')); |
| 50 | 51 | if (isset($this->options['enable_woocommerce_integration']) && |
| 51 | 52 | ($this->options['enable_woocommerce_integration'] === '1' || |
| 52 | 53 | $this->options['enable_woocommerce_integration'] === 'on')) { |
| @@ -55,8 +56,12 @@ | ||
| 55 | 56 | add_action('wp_insert_post', array($this, 'mxchat_handle_product_change'), 10, 3); |
| 56 | 57 | add_action('wp_trash_post', array($this, 'mxchat_handle_product_delete')); |
| 57 | 58 | add_action('before_delete_post', array($this, 'mxchat_handle_product_delete')); |
| 58 | 59 | } |
| 60 | + | |
| 61 | + add_action('wp_ajax_mxchat_get_status_updates', array($this, 'ajax_get_status_updates')); | |
| 62 | + add_action('admin_notices', array($this, 'display_admin_notices')); | |
| 63 | + | |
| 59 | 64 | } |
| 60 | 65 | |
| 61 | 66 | // Method to check if the license is active |
| 62 | 67 | private function is_license_active() { |
| @@ -70,8 +75,10 @@ | ||
| 70 | 75 | 'api_key' => '', |
| 71 | 76 | 'xai_api_key' => '', |
| 72 | 77 | 'claude_api_key' => '', |
| 73 | 78 | 'deepseek_api_key' => '', |
| 79 | + 'voyage_api_key' => '', | |
| 80 | + 'embedding_model' => 'text-embedding-ada-002', | |
| 74 | 81 | 'system_prompt_instructions' => esc_html__('[EXAMPLE INSTRUCTIONS] You are an AI Chatbot assistant for this website. The primary subject you should focus on is [insert proper subject here]. Your main goal is to assist visitors with questions related to this specific topic. Here are some key things to keep in mind: |
| 75 | 82 | - Your name is [Chatbot Name]. |
| 76 | 83 | - Stay focused on topics related to [insert proper subject here]. If a visitor asks about an unrelated topic, politely redirect the conversation to how you can assist them with this subject. |
| 77 | 84 | - Do not make up links to pages. Only use specific links you see in your knowledgebase from [insert your domain]. Do not make assumptions or make up URLs. |
| @@ -114,8 +121,10 @@ | ||
| 114 | 121 | 'pdf_intent_trigger_text' => esc_html__("Please provide the URL to the PDF you'd like to discuss.", 'mxchat'), |
| 115 | 122 | 'pdf_intent_success_text' => esc_html__("I've processed the PDF. What questions do you have about it?", 'mxchat'), |
| 116 | 123 | 'pdf_intent_error_text' => esc_html__("Sorry, I couldn't process the PDF. Please ensure it's a valid file.", 'mxchat'), |
| 117 | 124 | 'pdf_max_pages' => 69, |
| 125 | + 'show_pdf_upload_button' => 'on', | |
| 126 | + 'show_word_upload_button' => 'on', | |
| 118 | 127 | |
| 119 | 128 | // Live Agent Integration |
| 120 | 129 | 'live_agent_webhook_url' => '', |
| 121 | 130 | 'live_agent_secret_key' => '', |
| @@ -173,26 +182,24 @@ | ||
| 173 | 182 | 'mxchat-prompts', |
| 174 | 183 | array($this, 'mxchat_create_prompts_page') |
| 175 | 184 | ); |
| 176 | 185 | |
| 177 | - // Submenu page for Chat Transcripts | |
| 178 | 186 | add_submenu_page( |
| 179 | - 'mxchat-max', // Corrected parent slug to match the main menu | |
| 187 | + 'mxchat-max', | |
| 180 | 188 | esc_html__('Chat Transcripts', 'mxchat'), |
| 181 | 189 | esc_html__('Transcripts', 'mxchat'), |
| 182 | 190 | 'manage_options', |
| 183 | 191 | 'mxchat-transcripts', |
| 184 | - array($this, 'mxchat_create_transcripts_page') // Prefixed function name with mxchat_ | |
| 192 | + array($this, 'mxchat_create_transcripts_page') | |
| 185 | 193 | ); |
| 186 | 194 | |
| 187 | - // Submenu page for Intents | |
| 188 | 195 | add_submenu_page( |
| 189 | - 'mxchat-max', // Parent slug | |
| 190 | - esc_html__('MxChat Intents', 'mxchat'), // Page title | |
| 191 | - esc_html__('Intents', 'mxchat'), // Menu title | |
| 192 | - 'manage_options', // Capability | |
| 193 | - 'mxchat-intents', // Menu slug | |
| 194 | - array($this, 'mxchat_intents_page_html') // Callback function | |
| 196 | + 'mxchat-max', | |
| 197 | + esc_html__('MxChat Intents', 'mxchat'), | |
| 198 | + esc_html__('Intents', 'mxchat'), | |
| 199 | + 'manage_options', | |
| 200 | + 'mxchat-intents', | |
| 201 | + array($this, 'mxchat_intents_page_html') | |
| 195 | 202 | ); |
| 196 | 203 | |
| 197 | 204 | add_submenu_page( |
| 198 | 205 | 'mxchat-max', |
| @@ -224,16 +231,20 @@ | ||
| 224 | 231 | check_ajax_referer('mxchat_save_setting_nonce'); |
| 225 | 232 | if (!current_user_can('manage_options')) { |
| 226 | 233 | wp_send_json_error(['message' => esc_html__('Unauthorized', 'mxchat')]); |
| 227 | 234 | } |
| 235 | + | |
| 228 | 236 | $name = isset($_POST['name']) ? $_POST['name'] : ''; |
| 229 | 237 | // Strip slashes from the value before saving |
| 230 | 238 | $value = isset($_POST['value']) ? stripslashes($_POST['value']) : ''; |
| 239 | + | |
| 231 | 240 | if (empty($name)) { |
| 232 | 241 | wp_send_json_error(['message' => esc_html__('Invalid field name', 'mxchat')]); |
| 233 | 242 | } |
| 243 | + | |
| 234 | 244 | // Load the full options array |
| 235 | 245 | $options = get_option('mxchat_options', []); |
| 246 | + | |
| 236 | 247 | // Handle special cases |
| 237 | 248 | switch ($name) { |
| 238 | 249 | case 'additional_popular_questions': |
| 239 | 250 | $questions = json_decode($value, true); // No need for stripslashes here |
| @@ -242,8 +253,12 @@ | ||
| 242 | 253 | // Also update old option for backwards compatibility |
| 243 | 254 | update_option('additional_popular_questions', $questions); |
| 244 | 255 | } |
| 245 | 256 | break; |
| 257 | + case 'similarity_threshold': | |
| 258 | + // Save to the options array | |
| 259 | + $options[$name] = $value; | |
| 260 | + break; | |
| 246 | 261 | case 'user_message_bg_color': |
| 247 | 262 | case 'user_message_font_color': |
| 248 | 263 | case 'bot_message_bg_color': |
| 249 | 264 | case 'bot_message_font_color': |
| @@ -288,9 +303,11 @@ | ||
| 288 | 303 | if (strpos($name, 'toggle') !== false || in_array($name, [ |
| 289 | 304 | 'chat_persistence_toggle', |
| 290 | 305 | 'privacy_toggle', |
| 291 | 306 | 'complianz_toggle', |
| 292 | - 'chat_toolbar_toggle' // Removed live_agent_status from here | |
| 307 | + 'chat_toolbar_toggle', | |
| 308 | + 'show_pdf_upload_button', | |
| 309 | + 'show_word_upload_button' | |
| 293 | 310 | ])) { |
| 294 | 311 | $options[$name] = ($value === 'on') ? 'on' : 'off'; |
| 295 | 312 | } else { |
| 296 | 313 | // Store all other values directly |
| @@ -297,17 +314,12 @@ | ||
| 297 | 314 | $options[$name] = $value; |
| 298 | 315 | } |
| 299 | 316 | break; |
| 300 | 317 | } |
| 301 | - // Save all updates | |
| 318 | + | |
| 319 | + // Save all updates to the options array | |
| 302 | 320 | $updated = update_option('mxchat_options', $options); |
| 303 | - // Handle backwards compatibility for certain fields | |
| 304 | - $legacy_fields = ['brave_api_key', 'brave_image_count', 'brave_safe_search', 'brave_news_count', | |
| 305 | - 'brave_country', 'brave_language', 'similarity_threshold']; | |
| 306 | - if (in_array($name, $legacy_fields)) { | |
| 307 | - // Also update the individual option for backwards compatibility | |
| 308 | - update_option($name, $value); | |
| 309 | - } | |
| 321 | + | |
| 310 | 322 | if ($updated) { |
| 311 | 323 | wp_send_json_success(['message' => esc_html__('Setting saved', 'mxchat')]); |
| 312 | 324 | } else { |
| 313 | 325 | wp_send_json_error(['message' => esc_html__('Update failed or no changes', 'mxchat')]); |
| @@ -312,9 +324,8 @@ | ||
| 312 | 324 | } else { |
| 313 | 325 | wp_send_json_error(['message' => esc_html__('Update failed or no changes', 'mxchat')]); |
| 314 | 326 | } |
| 315 | 327 | } |
| 316 | - | |
| 317 | 328 | /** |
| 318 | 329 | * Handles AJAX auto-save for prompts and auto-sync settings. |
| 319 | 330 | */ |
| 320 | 331 | public function mxchat_save_prompts_setting_callback() { |
| @@ -398,188 +409,215 @@ | ||
| 398 | 409 | |
| 399 | 410 | public function mxchat_create_admin_page() { |
| 400 | 411 | |
| 401 | 412 | ?> |
| 402 | - <div class="wrap mxchat-admin"> | |
| 403 | - <?php if (!$this->is_activated): ?> | |
| 404 | - <div class="mxchat-pro-banner"> | |
| 405 | - <p> | |
| 406 | - <?php echo esc_html__('For a limited time, get lifetime access and save $20 on MxChat Pro!', 'mxchat'); ?> | |
| 407 | - <a href="https://mxchat.ai/" target="_blank"><?php echo esc_html__('Upgrade to Pro today', 'mxchat'); ?></a> | |
| 408 | - </p> | |
| 413 | + <div class="wrap mxchat-wrapper"> | |
| 414 | + <!-- Hero Section --> | |
| 415 | + <div class="mxchat-hero"> | |
| 416 | + <h1 class="mxchat-main-title"> | |
| 417 | + <span class="mxchat-gradient-text">MxChat</span> Settings | |
| 418 | + </h1> | |
| 419 | + <p class="mxchat-hero-subtitle"> | |
| 420 | + <?php esc_html_e('Configure your AI chatbot, manage integrations and explore tutorials to get the most out of MxChat.', 'mxchat'); ?> | |
| 421 | + </p> | |
| 409 | 422 | </div> |
| 410 | - <?php endif; ?> | |
| 411 | 423 | |
| 412 | - <div class="mxchat-agents-banner"> | |
| 413 | - <p> | |
| 414 | - <strong><?php echo esc_html__('The MxChat Add-Ons Platform', 'mxchat'); ?></strong><?php echo esc_html__(' is here! Pro users get unlimited access to our growing collection of powerful add-ons. ', 'mxchat'); ?><a href="<?php echo admin_url('admin.php?page=mxchat-addons'); ?>"><?php echo esc_html__('Explore all add-ons', 'mxchat'); ?></a><?php echo esc_html__(' including Forms Builder, Theme Customizer, Content Moderation, and more – all included with your lifetime Pro license!', 'mxchat'); ?> | |
| 415 | - </p> | |
| 416 | - </div> | |
| 424 | + <div class="mxchat-content"> | |
| 425 | + <?php if (!$this->is_activated): ?> | |
| 426 | + <div class="mxchat-pro-card"> | |
| 427 | + <div class="mxchat-pro-notification"> | |
| 428 | + <div class="mxchat-pro-content"> | |
| 429 | + <h3>🚀 Limited Time Offer: Save $20 on MxChat Pro Lifetime Access!</h3> | |
| 430 | + <p>Unlock <strong>unlimited access</strong> to our growing collection of powerful add-ons including Forms Builder, Theme Customizer, WooCommerce, Perplexity, and more – all included with your lifetime license!</p> | |
| 431 | + </div> | |
| 432 | + <div class="mxchat-pro-cta"> | |
| 433 | + <a href="https://mxchat.ai/" target="_blank" class="mxchat-button"><?php echo esc_html__('Upgrade to Pro Today', 'mxchat'); ?></a> | |
| 434 | + <a href="<?php echo admin_url('admin.php?page=mxchat-addons'); ?>" class="mxchat-link"><?php echo esc_html__('Preview Add-ons', 'mxchat'); ?></a> | |
| 435 | + </div> | |
| 436 | + </div> | |
| 437 | + </div> | |
| 438 | + <?php endif; ?> | |
| 417 | 439 | |
| 418 | - <h2 class="mxchat-nav-tab-wrapper"> | |
| 419 | - <a href="#chatbot" class="mxchat-nav-tab mxchat-nav-tab-active" data-tab="chatbot"><?php echo esc_html__('Chatbot', 'mxchat'); ?></a> | |
| 420 | - <a href="#embed" class="mxchat-nav-tab" data-tab="embed"><?php echo esc_html__('Integrations', 'mxchat'); ?></a> | |
| 421 | - <a href="#general" class="mxchat-nav-tab" data-tab="general"><?php echo esc_html__('FAQ', 'mxchat'); ?></a> | |
| 422 | - </h2> | |
| 423 | - | |
| 424 | - <div id="chatbot" class="mxchat-tab-content active"> | |
| 425 | - <div class="mxchat-autosave-section"> | |
| 426 | - <?php do_settings_sections('mxchat-chatbot'); ?> | |
| 440 | + <!-- Tabs Navigation --> | |
| 441 | + <div class="mxchat-tabs"> | |
| 442 | + <button class="mxchat-tab-button active" data-tab="chatbot"><?php echo esc_html__('Chatbot', 'mxchat'); ?></button> | |
| 443 | + <button class="mxchat-tab-button" data-tab="embed"><?php echo esc_html__('Integrations', 'mxchat'); ?></button> | |
| 444 | + <button class="mxchat-tab-button" data-tab="general"><?php echo esc_html__('YouTube Tutorials', 'mxchat'); ?></button> | |
| 427 | 445 | </div> |
| 428 | - </div> | |
| 429 | 446 | |
| 430 | - <div id="embed" class="mxchat-tab-content"> | |
| 431 | - <div class="mxchat-autosave-section"> | |
| 432 | - <div class="mxchat-settings-section"> | |
| 433 | - <h2><?php echo esc_html__('WooCommerce Settings', 'mxchat'); ?></h2> | |
| 434 | - <table class="form-table"> | |
| 435 | - <?php do_settings_fields('mxchat-embed', 'mxchat_woocommerce_section'); ?> | |
| 436 | - </table> | |
| 447 | + <!-- Tab Contents --> | |
| 448 | + <div id="chatbot" class="mxchat-tab-content active"> | |
| 449 | + <div class="mxchat-card"> | |
| 450 | + <div class="mxchat-autosave-section"> | |
| 451 | + <?php do_settings_sections('mxchat-chatbot'); ?> | |
| 452 | + </div> | |
| 437 | 453 | </div> |
| 438 | - <div class="section-divider"></div> | |
| 454 | + </div> | |
| 439 | 455 | |
| 440 | - <div class="mxchat-settings-section"> | |
| 441 | - <h2><?php echo esc_html__('Loops Settings', 'mxchat'); ?></h2> | |
| 442 | - <table class="form-table"> | |
| 443 | - <?php do_settings_fields('mxchat-embed', 'mxchat_loops_section'); ?> | |
| 444 | - </table> | |
| 456 | + <div id="embed" class="mxchat-tab-content"> | |
| 457 | + <div class="mxchat-card"> | |
| 458 | + <h2><?php esc_html_e('Loops Settings', 'mxchat'); ?></h2> | |
| 459 | + <div class="mxchat-autosave-section"> | |
| 460 | + <table class="form-table"> | |
| 461 | + <?php do_settings_fields('mxchat-embed', 'mxchat_loops_section'); ?> | |
| 462 | + </table> | |
| 463 | + </div> | |
| 445 | 464 | </div> |
| 446 | 465 | |
| 447 | - <div class="section-divider"></div> | |
| 448 | - | |
| 449 | - <div class="mxchat-settings-section"> | |
| 450 | - <h2><?php echo esc_html__('Brave Search Settings', 'mxchat'); ?></h2> | |
| 451 | - <table class="form-table"> | |
| 452 | - <?php do_settings_fields('mxchat-embed', 'mxchat_brave_section'); ?> | |
| 453 | - </table> | |
| 466 | + <div class="mxchat-card"> | |
| 467 | + <h2><?php esc_html_e('Brave Search Settings', 'mxchat'); ?></h2> | |
| 468 | + <div class="mxchat-autosave-section"> | |
| 469 | + <table class="form-table"> | |
| 470 | + <?php do_settings_fields('mxchat-embed', 'mxchat_brave_section'); ?> | |
| 471 | + </table> | |
| 472 | + </div> | |
| 454 | 473 | </div> |
| 455 | 474 | |
| 456 | - <div class="section-divider"></div> | |
| 457 | - | |
| 458 | - <div class="mxchat-settings-section"> | |
| 459 | - <h2><?php echo esc_html__('Toolbar Settings & Intents', 'mxchat'); ?></h2> | |
| 460 | - <table class="form-table"> | |
| 461 | - <?php do_settings_fields('mxchat-embed', 'mxchat_pdf_intent_section'); ?> | |
| 462 | - </table> | |
| 475 | + <div class="mxchat-card"> | |
| 476 | + <h2><?php esc_html_e('Toolbar Settings & Intents', 'mxchat'); ?></h2> | |
| 477 | + <div class="mxchat-autosave-section"> | |
| 478 | + <table class="form-table"> | |
| 479 | + <?php do_settings_fields('mxchat-embed', 'mxchat_pdf_intent_section'); ?> | |
| 480 | + </table> | |
| 481 | + </div> | |
| 463 | 482 | </div> |
| 464 | 483 | |
| 465 | - <div class="section-divider"></div> | |
| 466 | - | |
| 467 | - <!-- Live Agent Settings Section --> | |
| 468 | - <div class="mxchat-settings-section"> | |
| 469 | - <h2><?php echo esc_html__('Live Agent Settings', 'mxchat'); ?></h2> | |
| 470 | - <p><?php echo esc_html__('Visit our', 'mxchat'); ?> <a href="https://mxchat.ai/documentation/#slack_integration" target="_blank"><?php echo esc_html__('documentation page', 'mxchat'); ?></a> <?php echo esc_html__('to set up live agent transfer via Slack.', 'mxchat'); ?></p> | |
| 471 | - <table class="form-table"> | |
| 472 | - <?php do_settings_fields('mxchat-embed', 'mxchat_live_agent_section'); ?> | |
| 473 | - </table> | |
| 484 | + <div class="mxchat-card"> | |
| 485 | + <h2><?php esc_html_e('Live Agent Settings', 'mxchat'); ?></h2> | |
| 486 | + <div class="mxchat-autosave-section"> | |
| 487 | + <p><?php echo esc_html__('Visit our', 'mxchat'); ?> <a href="https://mxchat.ai/documentation/#slack_integration" target="_blank"><?php echo esc_html__('documentation page', 'mxchat'); ?></a> <?php echo esc_html__('to set up live agent transfer via Slack.', 'mxchat'); ?></p> | |
| 488 | + <table class="form-table"> | |
| 489 | + <?php do_settings_fields('mxchat-embed', 'mxchat_live_agent_section'); ?> | |
| 490 | + </table> | |
| 491 | + </div> | |
| 474 | 492 | </div> |
| 475 | 493 | </div> |
| 476 | - </div> | |
| 477 | 494 | |
| 495 | + <div id="general" class="mxchat-tab-content"> | |
| 496 | + <div class="mxchat-card"> | |
| 497 | + <?php do_settings_sections('mxchat-general'); ?> | |
| 498 | + <div class="video-tutorials-section"> | |
| 478 | 499 | |
| 479 | - <div id="general" class="mxchat-tab-content"> | |
| 480 | - <?php do_settings_sections('mxchat-general'); ?> | |
| 481 | - <p> | |
| 482 | - <?php echo esc_html__('If you’re having trouble with setup or getting the responses you need, we encourage you to review our', 'mxchat'); ?> | |
| 483 | - <a href="https://mxchat.ai/documentation/" target="_blank" rel="noopener noreferrer"><?php echo esc_html__('documentation', 'mxchat'); ?></a> <?php echo esc_html__('or', 'mxchat'); ?> | |
| 484 | - <a href="https://wordpress.org/support/plugin/mxchat-basic/" target="_blank" rel="noopener noreferrer"><?php echo esc_html__('create a support ticket', 'mxchat'); ?></a>. | |
| 485 | - </p> | |
| 486 | - <p> | |
| 487 | - <?php echo esc_html__('If you like our plugin, please consider', 'mxchat'); ?> <a href="https://wordpress.org/plugins/mxchat-basic/#reviews" target="_blank" rel="noopener noreferrer"><?php echo esc_html__('leaving us a review', 'mxchat'); ?></a>. | |
| 488 | - </p> | |
| 489 | - | |
| 490 | - <div class="faq-item"> | |
| 491 | - <h3><?php echo esc_html__('How does the Claude API integration work?', 'mxchat'); ?></h3> | |
| 492 | - <p> | |
| 493 | - <?php echo esc_html__('The Claude API, provided by Anthropic, allows for intelligent, context-aware chatbot responses in MxChat. To use it, you will need both an OpenAI API key and a Claude API key. This is necessary because the system utilizes OpenAI for vector embedding in the Retrieval-Augmented Generation (RAG) process, as Claude does not currently offer an embedding API.', 'mxchat'); ?> | |
| 494 | - </p> | |
| 495 | - <p> | |
| 496 | - <?php echo esc_html__('When using the Claude API, your custom content is sent to Claude for generating responses, while the embeddings are processed through OpenAI. This ensures your chatbot provides accurate and engaging responses while maintaining knowledge relevant to your website.', 'mxchat'); ?> | |
| 497 | - </p> | |
| 498 | - <p> | |
| 499 | - <?php echo esc_html__('You can obtain your Claude API key by signing up on the', 'mxchat'); ?> <a href="https://www.anthropic.com/api" target="_blank" rel="noopener"><?php echo esc_html__('Anthropic API page', 'mxchat'); ?></a>. | |
| 500 | - </p> | |
| 500 | + <div class="tutorial-grid"> | |
| 501 | + <div class="tutorial-item"> | |
| 502 | + <h3><?php echo esc_html__('MxChat Forms Tutorial', 'mxchat'); ?></h3> | |
| 503 | + <div class="video-description"> | |
| 504 | + <p><?php echo esc_html__('Learn how to create and manage smart forms that automatically trigger during chat conversations.', 'mxchat'); ?></p> | |
| 505 | + <a href="https://www.youtube.com/watch?v=3MrWy5dRalA" target="_blank" rel="noopener" class="video-link"> | |
| 506 | + <span class="video-icon"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 19c-2.3 0-6.4-.2-8.1-.6-.7-.2-1.2-.7-1.4-1.4-.3-1.1-.5-3.4-.5-5s.2-3.9.5-5c.2-.7.7-1.2 1.4-1.4C5.6 5.2 9.7 5 12 5s6.4.2 8.1.6c.7.2 1.2.7 1.4 1.4.3 1.1.5 3.4.5 5s-.2 3.9-.5 5c-.2.7-.7 1.2-1.4 1.4-1.7.4-5.8.6-8.1.6z"></path><polygon points="10 15 15 12 10 9 10 15"></polygon></svg></span> | |
| 507 | + <?php echo esc_html__('Watch MxChat Forms Tutorial', 'mxchat'); ?> | |
| 508 | + </a> | |
| 501 | 509 | </div> |
| 510 | + </div> | |
| 502 | 511 | |
| 503 | - <div class="faq-item"> | |
| 504 | - <h3><?php echo esc_html__('How does the X.AI API integration work?', 'mxchat'); ?></h3> | |
| 505 | - <p> | |
| 506 | - <?php echo esc_html__('The X.AI API, released on 10.21.24, is currently in beta. To use it, you will need both an OpenAI API key and an X.AI API key. This is because OpenAI handles vector embeddings in the Retrieval-Augmented Generation (RAG) process, as X.AI does not yet provide an embedding API.', 'mxchat'); ?> | |
| 507 | - </p> | |
| 508 | - <p> | |
| 509 | - <?php echo esc_html__('Custom content is sent to the X.AI API for generating responses, while OpenAI processes the embeddings. This allows the chatbot to provide advanced responses while maintaining context from your website. You can get your X.AI API key from the', 'mxchat'); ?> <a href="https://docs.x.ai/docs" target="_blank" rel="noopener"><?php echo esc_html__('X.AI API documentation', 'mxchat'); ?></a>. | |
| 510 | - </p> | |
| 512 | + <div class="tutorial-item"> | |
| 513 | + <h3><?php echo esc_html__('Intent Tester Guide', 'mxchat'); ?></h3> | |
| 514 | + <div class="video-description"> | |
| 515 | + <p><?php echo esc_html__('Discover how to use the Intent Tester to fine-tune your chatbot\'s responses and ensure it accurately understands user queries.', 'mxchat'); ?></p> | |
| 516 | + <a href="https://www.youtube.com/watch?v=uTr14tn59Hc" target="_blank" rel="noopener" class="video-link"> | |
| 517 | + <span class="video-icon"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 19c-2.3 0-6.4-.2-8.1-.6-.7-.2-1.2-.7-1.4-1.4-.3-1.1-.5-3.4-.5-5s.2-3.9.5-5c.2-.7.7-1.2 1.4-1.4C5.6 5.2 9.7 5 12 5s6.4.2 8.1.6c.7.2 1.2.7 1.4 1.4.3 1.1.5 3.4.5 5s-.2 3.9-.5 5c-.2.7-.7 1.2-1.4 1.4-1.7.4-5.8.6-8.1.6z"></path><polygon points="10 15 15 12 10 9 10 15"></polygon></svg></span> | |
| 518 | + <?php echo esc_html__('Watch Intent Tester Tutorial', 'mxchat'); ?> | |
| 519 | + </a> | |
| 511 | 520 | </div> |
| 521 | + </div> | |
| 512 | 522 | |
| 513 | - <div class="faq-item"> | |
| 514 | - <h3><?php echo esc_html__('Do I need an OpenAI API key to use the chatbot?', 'mxchat'); ?></h3> | |
| 515 | - <p> | |
| 516 | - <?php echo esc_html__('Yes, you will need an OpenAI API key to power the chatbot. You can obtain an API key by signing up on the', 'mxchat'); ?> <a href="https://platform.openai.com/signup" target="_blank" rel="noopener"><?php echo esc_html__('OpenAI platform', 'mxchat'); ?></a>. <?php echo esc_html__('After signing up, you must add credits to your account—typically, $5 in credits is sufficient to get started.', 'mxchat'); ?> | |
| 517 | - </p> | |
| 518 | - <p> | |
| 519 | - <?php echo esc_html__('Once you have your API key, simply enter it in the chatbot\'s settings to enable functionality. The chatbot relies on OpenAI’s models for generating responses, so having sufficient credits in your OpenAI account is essential for smooth operation.', 'mxchat'); ?> | |
| 520 | - </p> | |
| 523 | + <div class="tutorial-item"> | |
| 524 | + <h3><?php echo esc_html__('WooCommerce Integration', 'mxchat'); ?></h3> | |
| 525 | + <div class="video-description"> | |
| 526 | + <p><?php echo esc_html__('See how to integrate MxChat with your WooCommerce store to provide product recommendations and shopping assistance to your customers.', 'mxchat'); ?></p> | |
| 527 | + <a href="https://www.youtube.com/watch?v=WsqAppHRGdA" target="_blank" rel="noopener" class="video-link"> | |
| 528 | + <span class="video-icon"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 19c-2.3 0-6.4-.2-8.1-.6-.7-.2-1.2-.7-1.4-1.4-.3-1.1-.5-3.4-.5-5s.2-3.9.5-5c.2-.7.7-1.2 1.4-1.4C5.6 5.2 9.7 5 12 5s6.4.2 8.1.6c.7.2 1.2.7 1.4 1.4.3 1.1.5 3.4.5 5s-.2 3.9-.5 5c-.2.7-.7 1.2-1.4 1.4-1.7.4-5.8.6-8.1.6z"></path><polygon points="10 15 15 12 10 9 10 15"></polygon></svg></span> | |
| 529 | + <?php echo esc_html__('Watch WooCommerce Integration Tutorial', 'mxchat'); ?> | |
| 530 | + </a> | |
| 521 | 531 | </div> |
| 532 | + </div> | |
| 522 | 533 | |
| 523 | - <div class="faq-item"> | |
| 524 | - <h3><?php echo esc_html__('How do I add the chatbot to my site?', 'mxchat'); ?></h3> | |
| 525 | - <p> | |
| 526 | - <?php echo esc_html__('You can add the chatbot using the shortcode', 'mxchat'); ?> <code>[mxchat_chatbot floating="yes"]</code> <?php echo esc_html__('or', 'mxchat'); ?> <code>[mxchat_chatbot floating="no"]</code>. <?php echo esc_html__('For initial testing and styling, it\'s best to use the shortcode on a draft or non-public page. Once you’re ready to go live, enable the “Append Chat Widget to Body” option in the settings for site-wide integration (recommended) or add shortcode to the footer.', 'mxchat'); ?> | |
| 527 | - </p> | |
| 534 | + <div class="tutorial-item"> | |
| 535 | + <h3><?php echo esc_html__('Knowledge Base Setup', 'mxchat'); ?></h3> | |
| 536 | + <div class="video-description"> | |
| 537 | + <p><?php echo esc_html__('Learn how to set up your knowledge base using PDFs, sitemaps, and manual entries to enhance your chatbot\'s responses with site-specific information.', 'mxchat'); ?></p> | |
| 538 | + <p><small><?php echo esc_html__('Note: This tutorial uses an older UI, but the process remains the same.', 'mxchat'); ?></small></p> | |
| 539 | + <a href="https://www.youtube.com/watch?v=8Ztjs66-VTo" target="_blank" rel="noopener" class="video-link"> | |
| 540 | + <span class="video-icon"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 19c-2.3 0-6.4-.2-8.1-.6-.7-.2-1.2-.7-1.4-1.4-.3-1.1-.5-3.4-.5-5s.2-3.9.5-5c.2-.7.7-1.2 1.4-1.4C5.6 5.2 9.7 5 12 5s6.4.2 8.1.6c.7.2 1.2.7 1.4 1.4.3 1.1.5 3.4.5 5s-.2 3.9-.5 5c-.2.7-.7 1.2-1.4 1.4-1.7.4-5.8.6-8.1.6z"></path><polygon points="10 15 15 12 10 9 10 15"></polygon></svg></span> | |
| 541 | + <?php echo esc_html__('Watch Knowledge Base Setup Tutorial', 'mxchat'); ?> | |
| 542 | + </a> | |
| 528 | 543 | </div> |
| 544 | + </div> | |
| 529 | 545 | |
| 530 | - <div class="faq-item"> | |
| 531 | - <h3><?php echo esc_html__('How does the chatbot use my content to generate responses?', 'mxchat'); ?></h3> | |
| 532 | - <p> | |
| 533 | - <?php echo esc_html__('The chatbot uses AI and vector embeddings to connect users with relevant information. When you submit content, it converts it into a mathematical format. When a user asks a question, the bot matches it to your stored content and generates a response based on relevance. For example, submitting "Our phone number is 910-123-4567" allows the bot to retrieve this information when asked about contact details. To ensure related information is provided together, submit it in one entry.', 'mxchat'); ?> | |
| 534 | - </p> | |
| 546 | + <div class="tutorial-item"> | |
| 547 | + <h3><?php echo esc_html__('Toolbar Chat with Documents', 'mxchat'); ?></h3> | |
| 548 | + <div class="video-description"> | |
| 549 | + <p><?php echo esc_html__('See how to use the MxChat toolbar to chat with PDF and Word documents for enhanced document analysis and information retrieval.', 'mxchat'); ?></p> | |
| 550 | + <a href="https://www.youtube.com/watch?v=j_c45WWCTG0" target="_blank" rel="noopener" class="video-link"> | |
| 551 | + <span class="video-icon"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 19c-2.3 0-6.4-.2-8.1-.6-.7-.2-1.2-.7-1.4-1.4-.3-1.1-.5-3.4-.5-5s.2-3.9.5-5c.2-.7.7-1.2 1.4-1.4C5.6 5.2 9.7 5 12 5s6.4.2 8.1.6c.7.2 1.2.7 1.4 1.4.3 1.1.5 3.4.5 5s-.2 3.9-.5 5c-.2.7-.7 1.2-1.4 1.4-1.7.4-5.8.6-8.1.6z"></path><polygon points="10 15 15 12 10 9 10 15"></polygon></svg></span> | |
| 552 | + <?php echo esc_html__('Watch Document Chat Tutorial', 'mxchat'); ?> | |
| 553 | + </a> | |
| 535 | 554 | </div> |
| 536 | - | |
| 537 | - <div class="faq-item"> | |
| 538 | - <h3><?php echo esc_html__('Why does the chatbot sometimes make up links or information?', 'mxchat'); ?></h3> | |
| 539 | - <p> | |
| 540 | - <?php echo esc_html__('Occasionally, the chatbot may generate inaccurate links or information, known as "hallucinations." To minimize this, you can add system instructions to guide its behavior. For example, include an instruction like: "Only provide links you directly have access to or retrieve from the knowledge base. Do not make up links or information that you do not have direct access to." This helps the bot stay aligned with your content.', 'mxchat'); ?> | |
| 541 | - </p> | |
| 555 | + </div> | |
| 556 | + | |
| 557 | + <div class="tutorial-item"> | |
| 558 | + <h3><?php echo esc_html__('Perplexity Integration', 'mxchat'); ?></h3> | |
| 559 | + <div class="video-description"> | |
| 560 | + <p><?php echo esc_html__('Learn how to integrate Perplexity with your chatbot for real-time web search capabilities. This tutorial covers intent recognition, the toolbar toggle button, and how to enable your chatbot to search the web and provide up-to-date information to your visitors.', 'mxchat'); ?></p> | |
| 561 | + <a href="https://youtu.be/wpKkbt24-bo" target="_blank" rel="noopener" class="video-link"> | |
| 562 | + <span class="video-icon"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 19c-2.3 0-6.4-.2-8.1-.6-.7-.2-1.2-.7-1.4-1.4-.3-1.1-.5-3.4-.5-5s.2-3.9.5-5c.2-.7.7-1.2 1.4-1.4C5.6 5.2 9.7 5 12 5s6.4.2 8.1.6c.7.2 1.2.7 1.4 1.4.3 1.1.5 3.4.5 5s-.2 3.9-.5 5c-.2.7-.7 1.2-1.4 1.4-1.7.4-5.8.6-8.1.6z"></path><polygon points="10 15 15 12 10 9 10 15"></polygon></svg></span> | |
| 563 | + <?php echo esc_html__('Watch Perplexity Integration Tutorial', 'mxchat'); ?> | |
| 564 | + </a> | |
| 542 | 565 | </div> |
| 566 | + </div> | |
| 543 | 567 | |
| 544 | - <div class="faq-item"> | |
| 545 | - <h3><?php echo esc_html__('How do intents work in MxChat?', 'mxchat'); ?></h3> | |
| 546 | - <p> | |
| 547 | - <?php echo esc_html__('Intents allow MxChat to recognize user requests and trigger specific actions, such as capturing emails or displaying product information. This helps provide a more interactive and responsive experience. For a detailed explanation of each intent, please refer to our', 'mxchat'); ?> <a href="https://mxchat.ai/documentation/#intents" target="_blank" rel="noopener noreferrer"><?php echo esc_html__('Intents Documentation', 'mxchat'); ?></a>. | |
| 548 | - </p> | |
| 568 | + <div class="tutorial-item"> | |
| 569 | + <h3><?php echo esc_html__('Brave Search Intent', 'mxchat'); ?></h3> | |
| 570 | + <div class="video-description"> | |
| 571 | + <p><?php echo esc_html__('Learn how to leverage Brave Search intent capabilities to improve your chatbot\'s understanding of user queries and provide more accurate responses.', 'mxchat'); ?></p> | |
| 572 | + <a href="https://www.youtube.com/watch?v=7vDL5H7vToc" target="_blank" rel="noopener" class="video-link"> | |
| 573 | + <span class="video-icon"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 19c-2.3 0-6.4-.2-8.1-.6-.7-.2-1.2-.7-1.4-1.4-.3-1.1-.5-3.4-.5-5s.2-3.9.5-5c.2-.7.7-1.2 1.4-1.4C5.6 5.2 9.7 5 12 5s6.4.2 8.1.6c.7.2 1.2.7 1.4 1.4.3 1.1.5 3.4.5 5s-.2 3.9-.5 5c-.2.7-.7 1.2-1.4 1.4-1.7.4-5.8.6-8.1.6z"></path><polygon points="10 15 15 12 10 9 10 15"></polygon></svg></span> | |
| 574 | + <?php echo esc_html__('Watch Brave Search Intent Tutorial', 'mxchat'); ?> | |
| 575 | + </a> | |
| 549 | 576 | </div> |
| 577 | + </div> | |
| 550 | 578 | |
| 551 | - <div class="faq-item"> | |
| 552 | - <h3><?php echo esc_html__('How does the Complianz integration work?', 'mxchat'); ?></h3> | |
| 553 | - <p> | |
| 554 | - <?php echo esc_html__('The Pro version offers direct integration with the Complianz GDPR plugin, making it easy to stay compliant with GDPR. If Complianz is enabled on your website, users must accept consent before the chatbot widget appears. The chatbot will only display once the user has accepted, ensuring compliance with data privacy regulations.', 'mxchat'); ?> | |
| 555 | - </p> | |
| 579 | + <div class="tutorial-item"> | |
| 580 | + <h3><?php echo esc_html__('Loops Email Capture', 'mxchat'); ?></h3> | |
| 581 | + <div class="video-description"> | |
| 582 | + <p><?php echo esc_html__('Discover how to set up email capture with MxChat using Loops to grow your mailing list while providing value through your chatbot.', 'mxchat'); ?></p> | |
| 583 | + <p><small><?php echo esc_html__('Note: This tutorial uses an older UI, but the process remains the same.', 'mxchat'); ?></small></p> | |
| 584 | + <a href="https://www.youtube.com/watch?v=CNgm5TYDyTc" target="_blank" rel="noopener" class="video-link"> | |
| 585 | + <span class="video-icon"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 19c-2.3 0-6.4-.2-8.1-.6-.7-.2-1.2-.7-1.4-1.4-.3-1.1-.5-3.4-.5-5s.2-3.9.5-5c.2-.7.7-1.2 1.4-1.4C5.6 5.2 9.7 5 12 5s6.4.2 8.1.6c.7.2 1.2.7 1.4 1.4.3 1.1.5 3.4.5 5s-.2 3.9-.5 5c-.2.7-.7 1.2-1.4 1.4-1.7.4-5.8.6-8.1.6z"></path><polygon points="10 15 15 12 10 9 10 15"></polygon></svg></span> | |
| 586 | + <?php echo esc_html__('Watch Loops Email Capture Tutorial', 'mxchat'); ?> | |
| 587 | + </a> | |
| 556 | 588 | </div> |
| 589 | + </div> | |
| 557 | 590 | |
| 558 | - <div class="faq-item"> | |
| 559 | - <h3><?php echo esc_html__('How does the WooCommerce integration work?', 'mxchat'); ?></h3> | |
| 560 | - <p> | |
| 561 | - <?php echo esc_html__('With WooCommerce integration, the chatbot automatically embeds new products and updates existing ones. For already-published products, you can click update or submit the product sitemap. The “Order History Access” setting allows the bot to access users\' order history (requires login) and assist with order inquiries. To enable the “Add to Cart” feature, add this system instruction: “After discussing a product, ask if the user wants to add it to their cart. The user must say \'Add to cart\' exactly.” Currently, this feature supports English only, with more languages coming soon.', 'mxchat'); ?> | |
| 562 | - </p> | |
| 591 | + <div class="tutorial-item"> | |
| 592 | + <h3><?php echo esc_html__('MxChat AI Agent Testing Service', 'mxchat'); ?></h3> | |
| 593 | + <div class="video-description"> | |
| 594 | + <p><?php echo esc_html__('Learn how to use the MxChat AI Agent Testing Service to evaluate and improve your chatbot\'s performance and accuracy.', 'mxchat'); ?></p> | |
| 595 | + <p><small><?php echo esc_html__('Note: This tutorial uses an older UI, but the process remains the same.', 'mxchat'); ?></small></p> | |
| 596 | + <a href="https://www.youtube.com/watch?v=A0jowbpyX54" target="_blank" rel="noopener" class="video-link"> | |
| 597 | + <span class="video-icon"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 19c-2.3 0-6.4-.2-8.1-.6-.7-.2-1.2-.7-1.4-1.4-.3-1.1-.5-3.4-.5-5s.2-3.9.5-5c.2-.7.7-1.2 1.4-1.4C5.6 5.2 9.7 5 12 5s6.4.2 8.1.6c.7.2 1.2.7 1.4 1.4.3 1.1.5 3.4.5 5s-.2 3.9-.5 5c-.2.7-.7 1.2-1.4 1.4-1.7.4-5.8.6-8.1.6z"></path><polygon points="10 15 15 12 10 9 10 15"></polygon></svg></span> | |
| 598 | + <?php echo esc_html__('Watch AI Agent Testing Tutorial', 'mxchat'); ?> | |
| 599 | + </a> | |
| 563 | 600 | </div> |
| 601 | + </div> | |
| 602 | + </div> | |
| 564 | 603 | |
| 565 | - <div class="faq-item"> | |
| 566 | - <h3><?php echo esc_html__('Why isn\'t my chatbot responding as expected?', 'mxchat'); ?></h3> | |
| 567 | - <p> | |
| 568 | - <?php echo esc_html__('AI chatbots can sometimes behave in unexpected ways, especially if you\'re new to configuring AI for specific tasks. We\'re committed to helping you get the most out of your chatbot experience. While we’re working on comprehensive guides and video tutorials, our team is here to assist you directly. If your chatbot isn\'t delivering the responses you need, please don’t hesitate to', 'mxchat'); ?> <a href="https://mxchat.ai/contact/" target="_blank" rel="noopener noreferrer"><?php echo esc_html__('contact us', 'mxchat'); ?></a> <?php echo esc_html__('for personalized support.', 'mxchat'); ?> | |
| 569 | - </p> | |
| 570 | - <p> | |
| 571 | - <?php echo esc_html__('We’re dedicated to your success and ready to guide you in aligning the AI\'s behavior to meet your goals.', 'mxchat'); ?> | |
| 572 | - </p> | |
| 604 | + <div class="support-section"> | |
| 605 | + <h3><?php echo esc_html__('Need Help?', 'mxchat'); ?></h3> | |
| 606 | + <div class="support-content"> | |
| 607 | + <p> | |
| 608 | + <?php echo esc_html__('If you\'re having trouble with setup or getting the responses you need, we encourage you to review our', 'mxchat'); ?> | |
| 609 | + <a href="https://mxchat.ai/documentation/" target="_blank" rel="noopener noreferrer"><?php echo esc_html__('documentation', 'mxchat'); ?></a> <?php echo esc_html__('or', 'mxchat'); ?> | |
| 610 | + <a href="https://wordpress.org/support/plugin/mxchat-basic/" target="_blank" rel="noopener noreferrer"><?php echo esc_html__('create a support ticket', 'mxchat'); ?></a>. | |
| 611 | + </p> | |
| 612 | + <p> | |
| 613 | + <?php echo esc_html__('If you like our plugin, please consider', 'mxchat'); ?> <a href="https://wordpress.org/plugins/mxchat-basic/#reviews" target="_blank" rel="noopener noreferrer"><?php echo esc_html__('leaving us a review', 'mxchat'); ?></a>. | |
| 614 | + </p> | |
| 615 | + </div> | |
| 616 | + </div> | |
| 617 | + </div> | |
| 618 | + </div> | |
| 573 | 619 | </div> |
| 574 | - | |
| 575 | - <div class="faq-item"> | |
| 576 | - <h3><?php echo esc_html__('What is Loops, and how do I get an API key?', 'mxchat'); ?></h3> | |
| 577 | - <p> | |
| 578 | - <?php echo esc_html__('Loops is a powerful SaaS email service that helps you automate and enhance your email marketing campaigns, making it easy to reach and engage with your audience. To integrate Loops with MxChat, you’ll need an API key from Loops. You can obtain this key by logging into your Loops account and navigating to the API settings. Visit the', 'mxchat'); ?> <a href="https://loops.so" target="_blank" rel="noopener noreferrer"><?php echo esc_html__('Loops website', 'mxchat'); ?></a> <?php echo esc_html__('to get started or to sign up for an account.', 'mxchat'); ?> | |
| 579 | - </p> | |
| 580 | - </div> | |
| 581 | - | |
| 582 | 620 | </div> |
| 583 | 621 | </div> |
| 584 | 622 | <?php |
| 585 | 623 | } |
| @@ -584,73 +622,348 @@ | ||
| 584 | 622 | <?php |
| 585 | 623 | } |
| 586 | 624 | |
| 587 | 625 | |
| 588 | - | |
| 589 | 626 | public function mxchat_create_transcripts_page() { |
| 590 | 627 | global $wpdb; |
| 591 | 628 | $table_name = $wpdb->prefix . 'mxchat_chat_transcripts'; |
| 592 | - | |
| 629 | + | |
| 593 | 630 | // Get basic stats |
| 594 | 631 | $total_chats = $wpdb->get_var("SELECT COUNT(DISTINCT session_id) FROM $table_name"); |
| 595 | 632 | $total_messages = $wpdb->get_var("SELECT COUNT(*) FROM $table_name"); |
| 596 | - $total_users = $wpdb->get_var("SELECT COUNT(DISTINCT user_email) FROM $table_name WHERE user_email != ''"); | |
| 633 | + | |
| 634 | + // Count unique users with detailed breakdown | |
| 635 | + $total_users = $wpdb->get_var(" | |
| 636 | + SELECT COUNT(DISTINCT | |
| 637 | + CASE | |
| 638 | + WHEN user_email != '' AND user_email IS NOT NULL THEN user_email | |
| 639 | + WHEN user_id != 0 THEN CONCAT('user_', user_id) | |
| 640 | + WHEN user_identifier NOT LIKE 'Tech-Savvy User' | |
| 641 | + AND user_identifier NOT LIKE 'Detail-Oriented User' | |
| 642 | + AND user_identifier NOT LIKE 'Language Learner' | |
| 643 | + AND user_identifier NOT LIKE 'Casual Browser' | |
| 644 | + AND user_identifier NOT LIKE 'Policy Enforcer' | |
| 645 | + AND user_identifier NOT LIKE 'Researcher' | |
| 646 | + AND user_identifier NOT LIKE 'Loyalty Member' | |
| 647 | + AND user_identifier NOT LIKE 'Gift Buyer' | |
| 648 | + AND user_identifier NOT LIKE 'Parent or Caregiver' | |
| 649 | + THEN user_identifier | |
| 650 | + ELSE session_id | |
| 651 | + END | |
| 652 | + ) | |
| 653 | + FROM $table_name | |
| 654 | + WHERE role != 'assistant' | |
| 655 | + "); | |
| 656 | + | |
| 657 | + // Get user type breakdown | |
| 658 | + $registered_users = $wpdb->get_var(" | |
| 659 | + SELECT COUNT(DISTINCT user_email) | |
| 660 | + FROM $table_name | |
| 661 | + WHERE user_email != '' AND user_email IS NOT NULL | |
| 662 | + "); | |
| 663 | + | |
| 664 | + $guest_users = $wpdb->get_var(" | |
| 665 | + SELECT COUNT(DISTINCT user_identifier) | |
| 666 | + FROM $table_name | |
| 667 | + WHERE (user_email = '' OR user_email IS NULL) | |
| 668 | + AND role != 'assistant' | |
| 669 | + AND user_identifier NOT LIKE 'Tech-Savvy User' | |
| 670 | + AND user_identifier NOT LIKE 'Detail-Oriented User' | |
| 671 | + AND user_identifier NOT LIKE 'Language Learner' | |
| 672 | + AND user_identifier NOT LIKE 'Casual Browser' | |
| 673 | + AND user_identifier NOT LIKE 'Policy Enforcer' | |
| 674 | + AND user_identifier NOT LIKE 'Researcher' | |
| 675 | + AND user_identifier NOT LIKE 'Loyalty Member' | |
| 676 | + AND user_identifier NOT LIKE 'Gift Buyer' | |
| 677 | + AND user_identifier NOT LIKE 'Parent or Caregiver' | |
| 678 | + "); | |
| 679 | + | |
| 680 | + // Get agent test messages count | |
| 681 | + $agent_tests = $wpdb->get_var(" | |
| 682 | + SELECT COUNT(DISTINCT session_id) | |
| 683 | + FROM $table_name | |
| 684 | + WHERE user_identifier IN ( | |
| 685 | + 'Tech-Savvy User', | |
| 686 | + 'Detail-Oriented User', | |
| 687 | + 'Language Learner', | |
| 688 | + 'Casual Browser', | |
| 689 | + 'Policy Enforcer', | |
| 690 | + 'Researcher', | |
| 691 | + 'Loyalty Member', | |
| 692 | + 'Gift Buyer', | |
| 693 | + 'Parent or Caregiver' | |
| 694 | + ) | |
| 695 | + "); | |
| 597 | 696 | ?> |
| 598 | - <div class="wrap mxchat-admin"> | |
| 599 | - <!-- Stats Cards --> | |
| 600 | - <div class="mxchat-stats-grid"> | |
| 601 | - <div class="mxchat-stat-card"> | |
| 602 | - <div class="stat-icon">💬</div> | |
| 603 | - <div class="stat-content"> | |
| 604 | - <span class="stat-value"><?php echo esc_html($total_chats); ?></span> | |
| 605 | - <span class="stat-label"><?php esc_html_e('Total Chats', 'mxchat'); ?></span> | |
| 697 | + <div class="wrap mxchat-transcripts-wrapper"> | |
| 698 | + <!-- Hero Section --> | |
| 699 | + <div class="mxchat-transcripts-hero"> | |
| 700 | + <h1 class="mxchat-main-title"> | |
| 701 | + Chat <span class="mxchat-gradient-text">Transcripts</span> | |
| 702 | + </h1> | |
| 703 | + <p class="mxchat-hero-subtitle"> | |
| 704 | + <?php esc_html_e('Review and manage your chatbot conversations with detailed message history.', 'mxchat'); ?> | |
| 705 | + </p> | |
| 706 | + </div> | |
| 707 | + <div class="mxchat-content"> | |
| 708 | + <!-- Stats Cards --> | |
| 709 | + <div class="mxchat-stats-grid"> | |
| 710 | + <div class="mxchat-stat-card"> | |
| 711 | + <div class="stat-icon">💬</div> | |
| 712 | + <div class="stat-content"> | |
| 713 | + <span class="stat-value"><?php echo esc_html($total_chats); ?></span> | |
| 714 | + <span class="stat-label"><?php esc_html_e('Total Chats', 'mxchat'); ?></span> | |
| 715 | + </div> | |
| 606 | 716 | </div> |
| 607 | - </div> | |
| 608 | - <div class="mxchat-stat-card"> | |
| 609 | - <div class="stat-icon">📝</div> | |
| 610 | - <div class="stat-content"> | |
| 611 | - <span class="stat-value"><?php echo esc_html($total_messages); ?></span> | |
| 612 | - <span class="stat-label"><?php esc_html_e('Total Messages', 'mxchat'); ?></span> | |
| 717 | + <div class="mxchat-stat-card"> | |
| 718 | + <div class="stat-icon">📝</div> | |
| 719 | + <div class="stat-content"> | |
| 720 | + <span class="stat-value"><?php echo esc_html($total_messages); ?></span> | |
| 721 | + <span class="stat-label"><?php esc_html_e('Total Messages', 'mxchat'); ?></span> | |
| 722 | + </div> | |
| 613 | 723 | </div> |
| 724 | + <div class="mxchat-stat-card"> | |
| 725 | + <div class="stat-icon">👥</div> | |
| 726 | + <div class="stat-content"> | |
| 727 | + <span class="stat-value"><?php echo esc_html($total_users); ?></span> | |
| 728 | + <span class="stat-label"><?php esc_html_e('Unique Users', 'mxchat'); ?></span> | |
| 729 | + <span class="stat-sublabel"> | |
| 730 | + <?php | |
| 731 | + echo sprintf( | |
| 732 | + esc_html__('%d registered, %d guests, %d agent tests', 'mxchat'), | |
| 733 | + $registered_users, | |
| 734 | + $guest_users, | |
| 735 | + $agent_tests | |
| 736 | + ); | |
| 737 | + ?> | |
| 738 | + </span> | |
| 739 | + </div> | |
| 740 | + </div> | |
| 614 | 741 | </div> |
| 615 | - <div class="mxchat-stat-card"> | |
| 616 | - <div class="stat-icon">👥</div> | |
| 617 | - <div class="stat-content"> | |
| 618 | - <span class="stat-value"><?php echo esc_html($total_users); ?></span> | |
| 619 | - <span class="stat-label"><?php esc_html_e('Unique Users', 'mxchat'); ?></span> | |
| 742 | + <!-- Search and Filter Controls --> | |
| 743 | + <div class="mxchat-controls-wrapper"> | |
| 744 | + <div class="mxchat-search-box"> | |
| 745 | + <input type="text" id="mxchat-search-transcripts" | |
| 746 | + placeholder="<?php esc_attr_e('Search transcripts...', 'mxchat'); ?>" | |
| 747 | + class="regular-text"> | |
| 620 | 748 | </div> |
| 749 | + <form id="mxchat-delete-form" method="post"> | |
| 750 | + <?php wp_nonce_field('mxchat_delete_chat_history', 'mxchat_delete_chat_nonce'); ?> | |
| 751 | + <div class="mxchat-controls"> | |
| 752 | + <button type="button" id="mxchat-export-transcripts" class="mxchat-action-button"> | |
| 753 | + <span class="dashicons dashicons-download"></span> | |
| 754 | + <?php esc_html_e('Export All Chats', 'mxchat'); ?> | |
| 755 | + </button> | |
| 756 | + <button type="button" id="mxchat-select-all-transcripts" class="mxchat-select-button"> | |
| 757 | + <span class="dashicons dashicons-yes-alt"></span> | |
| 758 | + <span class="button-text"><?php esc_html_e('Select All', 'mxchat'); ?></span> | |
| 759 | + </button> | |
| 760 | + <button type="submit" class="button delete-chats-button"> | |
| 761 | + <span class="dashicons dashicons-trash"></span> | |
| 762 | + <?php esc_html_e('Delete Selected', 'mxchat'); ?> | |
| 763 | + </button> | |
| 764 | + </div> | |
| 765 | + </form> | |
| 621 | 766 | </div> |
| 767 | + <!-- Transcripts Container --> | |
| 768 | + <div id="mxchat-transcripts"></div> | |
| 622 | 769 | </div> |
| 770 | + </div> | |
| 771 | + <?php | |
| 772 | +} | |
| 623 | 773 | |
| 624 | - <!-- Search and Filter Controls --> | |
| 625 | - <div class="mxchat-controls-wrapper"> | |
| 626 | - <div class="mxchat-search-box"> | |
| 627 | - <input type="text" id="mxchat-search-transcripts" | |
| 628 | - placeholder="<?php esc_attr_e('Search transcripts...', 'mxchat'); ?>" | |
| 629 | - class="regular-text"> | |
| 630 | - </div> | |
| 774 | +public function export_chat_transcripts() { | |
| 775 | + if (!current_user_can('manage_options')) { | |
| 776 | + wp_die(esc_html__('You do not have sufficient permissions to access this page.', 'mxchat')); | |
| 777 | + } | |
| 631 | 778 | |
| 632 | - <form id="mxchat-delete-form" method="post"> | |
| 633 | - <?php wp_nonce_field('mxchat_delete_chat_history', 'mxchat_delete_chat_nonce'); ?> | |
| 634 | - <div class="mxchat-controls"> | |
| 635 | - <button type="button" id="mxchat-select-all-transcripts" class="mxchat-select-button"> | |
| 636 | - <span class="dashicons dashicons-yes-alt"></span> | |
| 637 | - <span class="button-text"><?php esc_html_e('Select All', 'mxchat'); ?></span> | |
| 638 | - </button> | |
| 639 | - <button type="submit" class="button delete-chats-button"> | |
| 640 | - <span class="dashicons dashicons-trash"></span> | |
| 641 | - <?php esc_html_e('Delete Selected', 'mxchat'); ?> | |
| 642 | - </button> | |
| 643 | - </div> | |
| 644 | - </form> | |
| 645 | - </div> | |
| 779 | + check_ajax_referer('mxchat_export_transcripts', 'security'); | |
| 646 | 780 | |
| 647 | - <!-- Transcripts Container --> | |
| 648 | - <div id="mxchat-transcripts"></div> | |
| 649 | - </div> | |
| 650 | - <?php | |
| 781 | + global $wpdb; | |
| 782 | + $table_name = $wpdb->prefix . 'mxchat_chat_transcripts'; | |
| 783 | + | |
| 784 | + // Get all transcripts ordered by session and timestamp | |
| 785 | + $results = $wpdb->get_results( | |
| 786 | + "SELECT session_id, user_email, user_identifier, role, message, timestamp | |
| 787 | + FROM {$table_name} | |
| 788 | + ORDER BY session_id, timestamp ASC" | |
| 789 | + ); | |
| 790 | + | |
| 791 | + if (empty($results)) { | |
| 792 | + wp_send_json_error(array('message' => 'No transcripts found.')); | |
| 793 | + wp_die(); | |
| 794 | + } | |
| 795 | + | |
| 796 | + // Set headers for CSV download | |
| 797 | + header('Content-Type: text/csv'); | |
| 798 | + header('Content-Disposition: attachment; filename="chat-transcripts-' . date('Y-m-d') . '.csv"'); | |
| 799 | + header('Pragma: no-cache'); | |
| 800 | + header('Expires: 0'); | |
| 801 | + | |
| 802 | + // Create output stream | |
| 803 | + $output = fopen('php://output', 'w'); | |
| 804 | + | |
| 805 | + // Add UTF-8 BOM for proper Excel encoding | |
| 806 | + fputs($output, "\xEF\xBB\xBF"); | |
| 807 | + | |
| 808 | + // Add CSV headers | |
| 809 | + fputcsv($output, array( | |
| 810 | + 'Session ID', | |
| 811 | + 'Email', | |
| 812 | + 'User Identifier', | |
| 813 | + 'Role', | |
| 814 | + 'Message', | |
| 815 | + 'Timestamp' | |
| 816 | + )); | |
| 817 | + | |
| 818 | + // Add data rows | |
| 819 | + foreach ($results as $row) { | |
| 820 | + fputcsv($output, array( | |
| 821 | + $row->session_id, | |
| 822 | + $row->user_email, | |
| 823 | + $row->user_identifier, | |
| 824 | + $row->role, | |
| 825 | + $row->message, | |
| 826 | + $row->timestamp | |
| 827 | + )); | |
| 828 | + } | |
| 829 | + | |
| 830 | + fclose($output); | |
| 831 | + wp_die(); | |
| 651 | 832 | } |
| 652 | 833 | |
| 834 | +public function mxchat_fetch_chat_history() { | |
| 835 | + global $wpdb; | |
| 836 | + $table_name = $wpdb->prefix . 'mxchat_chat_transcripts'; | |
| 837 | + | |
| 838 | + if (!current_user_can('manage_options')) { | |
| 839 | + wp_die(esc_html__('You do not have sufficient permissions to view this page.', 'mxchat')); | |
| 840 | + } | |
| 841 | + | |
| 842 | + // First get unique session IDs ordered by most recent message in each session | |
| 843 | + $session_ids = $wpdb->get_col( | |
| 844 | + $wpdb->prepare( | |
| 845 | + "SELECT DISTINCT session_id | |
| 846 | + FROM {$table_name} | |
| 847 | + GROUP BY session_id | |
| 848 | + ORDER BY MAX(timestamp) DESC" | |
| 849 | + ) | |
| 850 | + ); | |
| 851 | + | |
| 852 | + if (empty($session_ids)) { | |
| 853 | + wp_die(esc_html__('No chat history available.', 'mxchat')); | |
| 854 | + } | |
| 855 | + | |
| 856 | + ob_start(); | |
| 857 | + echo '<div class="mxchat-transcript">'; | |
| 858 | + | |
| 859 | + // Iterate through sessions from newest to oldest | |
| 860 | + foreach ($session_ids as $session_id) { | |
| 861 | + // Get the email associated with this session (if available) | |
| 862 | + $email = $wpdb->get_var( | |
| 863 | + $wpdb->prepare( | |
| 864 | + "SELECT user_email | |
| 865 | + FROM {$table_name} | |
| 866 | + WHERE session_id = %s AND user_email != '' | |
| 867 | + ORDER BY timestamp ASC | |
| 868 | + LIMIT 1", | |
| 869 | + $session_id | |
| 870 | + ) | |
| 871 | + ); | |
| 872 | + | |
| 873 | + // Debug: Check email retrieval | |
| 874 | + if (empty($email)) { | |
| 875 | + //error_log("No email found for session {$session_id}"); | |
| 876 | + } else { | |
| 877 | + //error_log("Email for session {$session_id}: " . $email); | |
| 878 | + } | |
| 879 | + | |
| 880 | + // Get messages for this session ordered by timestamp | |
| 881 | + $messages = $wpdb->get_results( | |
| 882 | + $wpdb->prepare( | |
| 883 | + "SELECT * FROM {$table_name} | |
| 884 | + WHERE session_id = %s | |
| 885 | + ORDER BY timestamp ASC", | |
| 886 | + $session_id | |
| 887 | + ) | |
| 888 | + ); | |
| 889 | + | |
| 890 | + // Start session block | |
| 891 | + echo '<div class="mxchat-session">'; | |
| 892 | + echo '<div class="mxchat-session-header">'; | |
| 893 | + // Wrap checkbox and session ID in one block | |
| 894 | + echo '<div class="mxchat-session-id">'; | |
| 895 | + echo '<input type="checkbox" name="delete_session_ids[]" value="' . esc_attr($session_id) . '"> '; | |
| 896 | + echo '<strong>' . esc_html__('Session ID:', 'mxchat') . '</strong> ' . esc_html($session_id); | |
| 897 | + echo '</div>'; | |
| 898 | + | |
| 899 | + // Place email directly below the session ID block | |
| 900 | + if (!empty($email)) { | |
| 901 | + echo '<div class="mxchat-session-email">'; | |
| 902 | + echo '<strong>' . esc_html__('Email:', 'mxchat') . '</strong> ' . esc_html($email); | |
| 903 | + echo '</div>'; | |
| 904 | + } | |
| 905 | + echo '</div>'; | |
| 906 | + | |
| 907 | + echo '<div class="mxchat-messages">'; | |
| 908 | + | |
| 909 | + // Display messages for this session | |
| 910 | + foreach ($messages as $transcript) { | |
| 911 | + $formatted_timestamp = date_i18n('F j, Y g:i a', strtotime($transcript->timestamp)); | |
| 912 | + | |
| 913 | + // Determine message styling | |
| 914 | + switch ($transcript->role) { | |
| 915 | + case 'assistant': | |
| 916 | + case 'bot': | |
| 917 | + $message_class = 'bot-message'; | |
| 918 | + $display_role = esc_html__('Chatbot', 'mxchat'); | |
| 919 | + break; | |
| 920 | + case 'user': | |
| 921 | + $message_class = 'user-message'; | |
| 922 | + $display_role = !empty($transcript->user_identifier) | |
| 923 | + ? sanitize_text_field($transcript->user_identifier) | |
| 924 | + : esc_html__('User', 'mxchat'); | |
| 925 | + break; | |
| 926 | + case 'agent': | |
| 927 | + $message_class = 'agent-message'; | |
| 928 | + $display_role = esc_html__('Agent', 'mxchat'); | |
| 929 | + break; | |
| 930 | + default: | |
| 931 | + $message_class = 'unknown-message'; | |
| 932 | + $display_role = esc_html__('Unknown', 'mxchat'); | |
| 933 | + } | |
| 934 | + | |
| 935 | + // Process message content | |
| 936 | + $message_content = wp_kses( | |
| 937 | + stripslashes($transcript->message), | |
| 938 | + [ | |
| 939 | + 'b' => [], 'strong' => [], 'i' => [], 'em' => [], 'u' => [], | |
| 940 | + 'br' => [], 'p' => [], 'ul' => [], 'ol' => [], 'li' => [], | |
| 941 | + 'a' => ['href' => [], 'title' => []] | |
| 942 | + ] | |
| 943 | + ); | |
| 944 | + $message_content = nl2br($message_content); | |
| 945 | + | |
| 946 | + // Render message | |
| 947 | + echo '<div class="mxchat-message ' . esc_attr($message_class) . '">'; | |
| 948 | + echo '<div class="mxchat-message-header">' . esc_html($display_role) . '</div>'; | |
| 949 | + echo '<div class="mxchat-message-content">' . $message_content . '</div>'; | |
| 950 | + echo '<div class="mxchat-timestamp">' . esc_html($formatted_timestamp) . '</div>'; | |
| 951 | + echo '</div>'; | |
| 952 | + } | |
| 953 | + | |
| 954 | + // Close session block | |
| 955 | + echo '</div></div>'; | |
| 956 | + } | |
| 957 | + | |
| 958 | + echo '</div>'; | |
| 959 | + $output = ob_get_clean(); | |
| 960 | + echo $output; | |
| 961 | + wp_die(); | |
| 962 | +} | |
| 963 | + | |
| 964 | + | |
| 965 | + | |
| 653 | 966 | public function mxchat_create_prompts_page() { |
| 654 | 967 | global $wpdb; |
| 655 | 968 | $table_name = $wpdb->prefix . 'mxchat_system_prompt_content'; |
| 656 | 969 | |
| @@ -731,10 +1044,39 @@ | ||
| 731 | 1044 | <div class="mxchat-content"> |
| 732 | 1045 | <!-- Import Settings Card --> |
| 733 | 1046 | <div class="mxchat-card"> |
| 734 | 1047 | <h2><?php esc_html_e('Knowledge Import Settings', 'mxchat'); ?></h2> |
| 735 | - <p><?php esc_html_e('Using the free Pinecone DB Manager add-on is recommended for high performance and a knowledge database of more than 500.', 'mxchat'); ?></p> | |
| 1048 | +<?php | |
| 1049 | +// Check if the appropriate embedding API key exists | |
| 1050 | +$embedding_model = isset($this->options['embedding_model']) ? esc_attr($this->options['embedding_model']) : 'text-embedding-ada-002'; | |
| 1051 | +$has_openai_key = !empty($this->options['api_key']); | |
| 1052 | +$has_voyage_key = !empty($this->options['voyage_api_key']); | |
| 736 | 1053 | |
| 1054 | +// Determine if they have the needed API key for their selected embedding model | |
| 1055 | +$has_required_key = false; | |
| 1056 | +$required_key_type = ''; | |
| 1057 | + | |
| 1058 | +if (strpos($embedding_model, 'text-embedding-') !== false && $has_openai_key) { | |
| 1059 | + $has_required_key = true; | |
| 1060 | + $required_key_type = 'OpenAI'; | |
| 1061 | +} elseif (strpos($embedding_model, 'voyage-') !== false && $has_voyage_key) { | |
| 1062 | + $has_required_key = true; | |
| 1063 | + $required_key_type = 'Voyage AI'; | |
| 1064 | +} elseif (strpos($embedding_model, 'text-embedding-') !== false) { | |
| 1065 | + $required_key_type = 'OpenAI'; | |
| 1066 | +} elseif (strpos($embedding_model, 'voyage-') !== false) { | |
| 1067 | + $required_key_type = 'Voyage AI'; | |
| 1068 | +} | |
| 1069 | +?> | |
| 1070 | + | |
| 1071 | +<div class="mxchat-knowledge-warning <?php echo $has_required_key ? 'success' : 'warning'; ?>"> | |
| 1072 | + <?php if ($has_required_key): ?> | |
| 1073 | + <p><span class="dashicons dashicons-yes-alt"></span> <?php echo wp_kses_post(sprintf(__('We detected your %s API key. <strong>You must have added credits to your %s account</strong> before using the knowledgebase.', 'mxchat'), $required_key_type, $required_key_type)); ?></p> | |
| 1074 | + <?php else: ?> | |
| 1075 | + <p><span class="dashicons dashicons-warning"></span> <strong><?php esc_html_e('Important:', 'mxchat'); ?></strong> <?php echo sprintf(esc_html__('Before importing knowledge, you must add a %s API key with sufficient credits in the Chatbot settings.', 'mxchat'), $required_key_type); ?> <a href="<?php echo admin_url('admin.php?page=mxchat-max'); ?>"><?php esc_html_e('Go to API Key Settings', 'mxchat'); ?></a></p> | |
| 1076 | + <?php endif; ?> | |
| 1077 | +</div> | |
| 1078 | + | |
| 737 | 1079 | <!-- Tab Contents --> |
| 738 | 1080 | <div class="mxchat-tab-contents"> |
| 739 | 1081 | <!-- Default Database Tab --> |
| 740 | 1082 | <div id="default-db" class="mxchat-tab-content active"> |
| @@ -781,10 +1123,9 @@ | ||
| 781 | 1123 | <!-- Import Methods --> |
| 782 | 1124 | <div class="mxchat-import-methods"> |
| 783 | 1125 | <div class="mxchat-method-card"> |
| 784 | 1126 | <h4><?php esc_html_e('Sitemap Import', 'mxchat'); ?></h4> |
| 785 | - <p><?php esc_html_e('Import all content from your sitemap automatically.', 'mxchat'); ?></p> | |
| 786 | - </div> | |
| 1127 | + <p><span class="red-warning">IMPORTANT:</span> <?php esc_html_e('Use a content-specific sub-sitemap, not the sitemap index.', 'mxchat'); ?></p> </div> | |
| 787 | 1128 | <div class="mxchat-method-card"> |
| 788 | 1129 | <h4><?php esc_html_e('PDF Import', 'mxchat'); ?></h4> |
| 789 | 1130 | <p><?php esc_html_e('Import knowledge directly from PDF documents.', 'mxchat'); ?></p> |
| 790 | 1131 | </div> |
| @@ -893,8 +1234,10 @@ | ||
| 893 | 1234 | <?php endif; ?> |
| 894 | 1235 | </div> |
| 895 | 1236 | </div> |
| 896 | 1237 | <?php endif; ?> |
| 1238 | + | |
| 1239 | + | |
| 897 | 1240 | </div> |
| 898 | 1241 | |
| 899 | 1242 | |
| 900 | 1243 | </div> |
| @@ -1091,30 +1434,134 @@ | ||
| 1091 | 1434 | |
| 1092 | 1435 | wp_safe_redirect(add_query_arg(array('page' => 'mxchat-prompts', 'deleted' => 'true'), admin_url('admin.php'))); |
| 1093 | 1436 | exit; |
| 1094 | 1437 | } |
| 1095 | -public function mxchat_generate_embedding($text) { | |
| 1096 | - $options = get_option('mxchat_options'); | |
| 1097 | - $api_key = $options['api_key'] ?? esc_html__('default_api_key', 'mxchat'); | |
| 1098 | 1438 | |
| 1099 | - $response = wp_remote_post('https://api.openai.com/v1/embeddings', array( | |
| 1100 | - 'body' => wp_json_encode(array( | |
| 1101 | - 'model' => esc_html__('text-embedding-ada-002', 'mxchat'), | |
| 1102 | - 'input' => $text | |
| 1103 | - )), | |
| 1104 | - 'headers' => array( | |
| 1105 | - 'Authorization' => 'Bearer ' . $api_key, | |
| 1106 | - 'Content-Type' => esc_html__('application/json', 'mxchat') | |
| 1107 | - ), | |
| 1108 | - )); | |
| 1109 | 1439 | |
| 1110 | - if (is_wp_error($response)) { | |
| 1111 | - return null; | |
| 1440 | +public function mxchat_generate_embedding($text) { | |
| 1441 | + //error_log('[MXCHAT-EMBED] Starting embedding generation. Text length: ' . strlen($text) . ' bytes'); | |
| 1442 | + //error_log('[MXCHAT-EMBED] Text preview: ' . substr($text, 0, 100) . '...'); | |
| 1443 | + | |
| 1444 | + $options = get_option('mxchat_options'); | |
| 1445 | + $selected_model = $options['embedding_model'] ?? 'text-embedding-ada-002'; | |
| 1446 | + //error_log('[MXCHAT-EMBED] Selected embedding model: ' . $selected_model); | |
| 1447 | + | |
| 1448 | + // Determine provider and endpoint | |
| 1449 | + if (strpos($selected_model, 'voyage') === 0) { | |
| 1450 | + $api_key = $options['voyage_api_key'] ?? ''; | |
| 1451 | + $endpoint = 'https://api.voyageai.com/v1/embeddings'; | |
| 1452 | + //error_log('[MXCHAT-EMBED] Using Voyage AI API'); | |
| 1453 | + } else { | |
| 1454 | + $api_key = $options['api_key'] ?? ''; | |
| 1455 | + $endpoint = 'https://api.openai.com/v1/embeddings'; | |
| 1456 | + //error_log('[MXCHAT-EMBED] Using OpenAI API'); | |
| 1457 | + } | |
| 1458 | + | |
| 1459 | + //error_log('[MXCHAT-EMBED] Using endpoint: ' . $endpoint); | |
| 1460 | + | |
| 1461 | + if (empty($api_key)) { | |
| 1462 | + //error_log('[MXCHAT-EMBED] Error: API key not configured'); | |
| 1463 | + return 'Missing API key. Please configure your API key in the settings.'; | |
| 1464 | + } | |
| 1465 | + | |
| 1466 | + // Check if text is too long (for OpenAI, roughly estimate tokens as words/0.75) | |
| 1467 | + $estimated_tokens = ceil(str_word_count($text) / 0.75); | |
| 1468 | + //error_log('[MXCHAT-EMBED] Estimated token count: ~' . $estimated_tokens); | |
| 1469 | + | |
| 1470 | + if ($estimated_tokens > 8000 && strpos($selected_model, 'voyage') === false) { | |
| 1471 | + //error_log('[MXCHAT-EMBED] Warning: Text may exceed OpenAI token limits (8K for most models)'); | |
| 1472 | + // Consider truncating text here | |
| 1473 | + } | |
| 1474 | + | |
| 1475 | + // Prepare request body | |
| 1476 | + $request_body = array( | |
| 1477 | + 'model' => $selected_model, | |
| 1478 | + 'input' => $text | |
| 1479 | + ); | |
| 1480 | + | |
| 1481 | + // Add output_dimension for voyage-3-large model | |
| 1482 | + if ($selected_model === 'voyage-3-large') { | |
| 1483 | + $request_body['output_dimension'] = 2048; | |
| 1484 | + } | |
| 1485 | + | |
| 1486 | + //error_log('[MXCHAT-EMBED] Request prepared with model: ' . $selected_model); | |
| 1487 | + | |
| 1488 | + // Make API request | |
| 1489 | + //error_log('[MXCHAT-EMBED] Sending API request to: ' . $endpoint); | |
| 1490 | + $response = wp_remote_post($endpoint, array( | |
| 1491 | + 'body' => wp_json_encode($request_body), | |
| 1492 | + 'headers' => array( | |
| 1493 | + 'Authorization' => 'Bearer ' . $api_key, | |
| 1494 | + 'Content-Type' => 'application/json' | |
| 1495 | + ), | |
| 1496 | + 'timeout' => 60 // Increased timeout for large inputs | |
| 1497 | + )); | |
| 1498 | + | |
| 1499 | + // Handle wp_remote_post errors | |
| 1500 | + if (is_wp_error($response)) { | |
| 1501 | + $error_message = $response->get_error_message(); | |
| 1502 | + //error_log('[MXCHAT-EMBED] WP Remote Post Error: ' . $error_message); | |
| 1503 | + return 'Connection error: ' . $error_message; | |
| 1504 | + } | |
| 1505 | + | |
| 1506 | + // Get and check HTTP response code | |
| 1507 | + $http_code = wp_remote_retrieve_response_code($response); | |
| 1508 | + //error_log('[MXCHAT-EMBED] API Response Code: ' . $http_code); | |
| 1509 | + | |
| 1510 | + if ($http_code !== 200) { | |
| 1511 | + $error_body = wp_remote_retrieve_body($response); | |
| 1512 | + //error_log('[MXCHAT-EMBED] API Error Response Body: ' . $error_body); | |
| 1513 | + | |
| 1514 | + // Try to parse error for more details | |
| 1515 | + $error_json = json_decode($error_body, true); | |
| 1516 | + if (json_last_error() === JSON_ERROR_NONE && isset($error_json['error'])) { | |
| 1517 | + $error_type = $error_json['error']['type'] ?? 'unknown'; | |
| 1518 | + $error_message = $error_json['error']['message'] ?? 'No message'; | |
| 1519 | + //error_log('[MXCHAT-EMBED] API Error Type: ' . $error_type); | |
| 1520 | + //error_log('[MXCHAT-EMBED] API Error Message: ' . $error_message); | |
| 1521 | + return "API Error ($error_type): $error_message"; | |
| 1112 | 1522 | } |
| 1523 | + | |
| 1524 | + return "API Error (HTTP $http_code): Unable to generate embedding"; | |
| 1525 | + } | |
| 1526 | + | |
| 1527 | + // Parse response body | |
| 1528 | + $response_body = wp_remote_retrieve_body($response); | |
| 1529 | + //error_log('[MXCHAT-EMBED] Received response length: ' . strlen($response_body) . ' bytes'); | |
| 1530 | + | |
| 1531 | + $response_data = json_decode($response_body, true); | |
| 1532 | + | |
| 1533 | + if (json_last_error() !== JSON_ERROR_NONE) { | |
| 1534 | + $error = json_last_error_msg(); | |
| 1535 | + //error_log('[MXCHAT-EMBED] JSON Parse Error: ' . $error); | |
| 1536 | + //error_log('[MXCHAT-EMBED] Response preview: ' . substr($response_body, 0, 200)); | |
| 1537 | + return "Failed to parse API response: $error"; | |
| 1538 | + } | |
| 1539 | + | |
| 1540 | + // Both APIs use the same structure, so we can extract the embedding the same way | |
| 1541 | + if (isset($response_data['data'][0]['embedding'])) { | |
| 1542 | + $embedding_dimensions = count($response_data['data'][0]['embedding']); | |
| 1543 | + //error_log('[MXCHAT-EMBED] Successfully extracted embedding with ' . $embedding_dimensions . ' dimensions'); | |
| 1544 | + | |
| 1545 | + // Check if embedding dimensions are as expected | |
| 1546 | + if (($selected_model === 'text-embedding-ada-002' && $embedding_dimensions !== 1536) || | |
| 1547 | + ($selected_model === 'voyage-3-large' && $embedding_dimensions !== 2048)) { | |
| 1548 | + } | |
| 1549 | + | |
| 1550 | + return $response_data['data'][0]['embedding']; | |
| 1551 | + } else { | |
| 1552 | + //error_log('[MXCHAT-EMBED] Error: No embedding found in response'); | |
| 1553 | + //error_log('[MXCHAT-EMBED] Response structure: ' . wp_json_encode(array_keys($response_data))); | |
| 1554 | + | |
| 1555 | + if (isset($response_data['error'])) { | |
| 1556 | + //error_log('[MXCHAT-EMBED] API Error in response: ' . wp_json_encode($response_data['error'])); | |
| 1557 | + return "API Error in response: " . wp_json_encode($response_data['error']); | |
| 1558 | + } | |
| 1559 | + | |
| 1560 | + return "Invalid API response format: No embedding found"; | |
| 1561 | + } | |
| 1562 | +} | |
| 1113 | 1563 | |
| 1114 | - $response_data = json_decode(wp_remote_retrieve_body($response), true); | |
| 1115 | - return $response_data['data'][0]['embedding'] ?? null; | |
| 1116 | - } | |
| 1117 | 1564 | public function mxchat_delete_chat_history() { |
| 1118 | 1565 | if (!current_user_can('manage_options')) { |
| 1119 | 1566 | echo wp_json_encode(['error' => esc_html__('You do not have sufficient permissions.', 'mxchat')]); |
| 1120 | 1567 | wp_die(); |
| @@ -1339,8 +1786,10 @@ | ||
| 1339 | 1786 | 'success' => true, |
| 1340 | 1787 | 'message' => 'Successfully stored in Pinecone' |
| 1341 | 1788 | ); |
| 1342 | 1789 | } |
| 1790 | + | |
| 1791 | + | |
| 1343 | 1792 | // Helper method for WordPress DB storage |
| 1344 | 1793 | private function store_in_wordpress_db($content, $url, $embedding_vector) { |
| 1345 | 1794 | global $wpdb; |
| 1346 | 1795 | $table_name = $wpdb->prefix . 'mxchat_system_prompt_content'; |
| @@ -1716,19 +2165,26 @@ | ||
| 1716 | 2165 | 'status' => sanitize_text_field($status['status']), |
| 1717 | 2166 | 'last_update' => human_time_diff(absint($status['last_update']), time()) . ' ' . esc_html__('ago', 'mxchat') |
| 1718 | 2167 | ); |
| 1719 | 2168 | } |
| 2169 | + | |
| 1720 | 2170 | public function mxchat_handle_sitemap_submission() { |
| 2171 | + // Start logging the submission process | |
| 2172 | + //error_log('[MXCHAT-URL] ===== Starting URL submission process ====='); | |
| 2173 | + | |
| 1721 | 2174 | // Check if the form was submitted and verify permissions |
| 1722 | 2175 | if (!isset($_POST['submit_sitemap']) || !current_user_can('manage_options')) { |
| 2176 | + //error_log('[MXCHAT-URL] Error: Unauthorized access or form not submitted properly'); | |
| 1723 | 2177 | wp_die(esc_html__('Unauthorized access', 'mxchat')); |
| 1724 | 2178 | } |
| 1725 | 2179 | |
| 1726 | 2180 | // Verify nonce |
| 2181 | + //error_log('[MXCHAT-URL] Verifying nonce'); | |
| 1727 | 2182 | check_admin_referer('mxchat_submit_sitemap_action', 'mxchat_submit_sitemap_nonce'); |
| 1728 | 2183 | |
| 1729 | 2184 | // Validate URL |
| 1730 | 2185 | if (!isset($_POST['sitemap_url']) || empty($_POST['sitemap_url'])) { |
| 2186 | + //error_log('[MXCHAT-URL] Error: Empty or missing URL'); | |
| 1731 | 2187 | set_transient('mxchat_admin_notice_error', |
| 1732 | 2188 | esc_html__('Please provide a valid URL.', 'mxchat'), |
| 1733 | 2189 | 30 |
| 1734 | 2190 | ); |
| @@ -1736,12 +2192,16 @@ | ||
| 1736 | 2192 | exit; |
| 1737 | 2193 | } |
| 1738 | 2194 | |
| 1739 | 2195 | $submitted_url = esc_url_raw($_POST['sitemap_url']); |
| 2196 | + //error_log('[MXCHAT-URL] Processing URL: ' . $submitted_url); | |
| 2197 | + | |
| 2198 | + //error_log('[MXCHAT-URL] Fetching URL content'); | |
| 1740 | 2199 | $response = wp_remote_get($submitted_url, array('timeout' => 30)); |
| 1741 | 2200 | |
| 1742 | 2201 | if (is_wp_error($response) || wp_remote_retrieve_response_code($response) !== 200) { |
| 1743 | - $error_message = is_wp_error($response) ? $response->get_error_message() : __('Failed to fetch URL', 'mxchat'); | |
| 2202 | + $error_message = is_wp_error($response) ? $response->get_error_message() : 'HTTP Status: ' . wp_remote_retrieve_response_code($response); | |
| 2203 | + //error_log('[MXCHAT-URL] Error fetching URL: ' . $error_message); | |
| 1744 | 2204 | set_transient('mxchat_admin_notice_error', |
| 1745 | 2205 | sprintf( |
| 1746 | 2206 | esc_html__('Failed to fetch the URL: %s', 'mxchat'), |
| 1747 | 2207 | esc_html($error_message) |
| @@ -1752,11 +2212,13 @@ | ||
| 1752 | 2212 | exit; |
| 1753 | 2213 | } |
| 1754 | 2214 | |
| 1755 | 2215 | $content_type = wp_remote_retrieve_header($response, 'content-type'); |
| 2216 | + //error_log('[MXCHAT-URL] Content type: ' . $content_type); | |
| 1756 | 2217 | $body_content = wp_remote_retrieve_body($response); |
| 1757 | 2218 | |
| 1758 | 2219 | if (empty($body_content)) { |
| 2220 | + //error_log('[MXCHAT-URL] Error: Empty response body'); | |
| 1759 | 2221 | set_transient('mxchat_admin_notice_error', |
| 1760 | 2222 | esc_html__('Empty response received from URL.', 'mxchat'), |
| 1761 | 2223 | 30 |
| 1762 | 2224 | ); |
| @@ -1762,12 +2224,15 @@ | ||
| 1762 | 2224 | ); |
| 1763 | 2225 | wp_safe_redirect(esc_url(admin_url('admin.php?page=mxchat-prompts'))); |
| 1764 | 2226 | exit; |
| 1765 | 2227 | } |
| 2228 | + //error_log('[MXCHAT-URL] Retrieved body content length: ' . strlen($body_content) . ' bytes'); | |
| 1766 | 2229 | |
| 1767 | 2230 | // Handle PDF URL |
| 1768 | 2231 | if ($this->is_pdf_url($submitted_url, $response)) { |
| 2232 | + //error_log('[MXCHAT-URL] Detected PDF URL, handling PDF for knowledge base'); | |
| 1769 | 2233 | $result = $this->handle_pdf_for_knowledge_base($submitted_url, $response); |
| 2234 | + //error_log('[MXCHAT-URL] PDF handling result: ' . $result); | |
| 1770 | 2235 | |
| 1771 | 2236 | if ($result === 'scheduled') { |
| 1772 | 2237 | set_transient( |
| 1773 | 2238 | 'mxchat_last_pdf_url', |
| @@ -1779,9 +2244,9 @@ | ||
| 1779 | 2244 | 30 |
| 1780 | 2245 | ); |
| 1781 | 2246 | } else { |
| 1782 | 2247 | set_transient('mxchat_admin_notice_error', |
| 1783 | - esc_html__('Failed to start PDF processing. Please try again.', 'mxchat'), | |
| 2248 | + esc_html__('Failed to start PDF processing: ', 'mxchat') . esc_html($result), | |
| 1784 | 2249 | 30 |
| 1785 | 2250 | ); |
| 1786 | 2251 | } |
| 1787 | 2252 | |
| @@ -1790,8 +2255,9 @@ | ||
| 1790 | 2255 | } |
| 1791 | 2256 | |
| 1792 | 2257 | // Handle Sitemap XML |
| 1793 | 2258 | if (strpos($content_type, 'xml') !== false || strpos($body_content, '<urlset') !== false) { |
| 2259 | + //error_log('[MXCHAT-URL] Detected XML content, processing as sitemap'); | |
| 1794 | 2260 | libxml_use_internal_errors(true); |
| 1795 | 2261 | $xml = simplexml_load_string($body_content); |
| 1796 | 2262 | $xml_errors = libxml_get_errors(); |
| 1797 | 2263 | libxml_clear_errors(); |
| @@ -1796,8 +2262,15 @@ | ||
| 1796 | 2262 | $xml_errors = libxml_get_errors(); |
| 1797 | 2263 | libxml_clear_errors(); |
| 1798 | 2264 | |
| 1799 | 2265 | if ($xml === false || !empty($xml_errors)) { |
| 2266 | + //error_log('[MXCHAT-URL] Error: Invalid XML format'); | |
| 2267 | + if (!empty($xml_errors)) { | |
| 2268 | + foreach ($xml_errors as $error) { | |
| 2269 | + //error_log('[MXCHAT-URL] XML Error: ' . $error->message); | |
| 2270 | + } | |
| 2271 | + } | |
| 2272 | + | |
| 1800 | 2273 | set_transient('mxchat_admin_notice_error', |
| 1801 | 2274 | esc_html__('Invalid sitemap XML. Please provide a valid sitemap.', 'mxchat'), |
| 1802 | 2275 | 30 |
| 1803 | 2276 | ); |
| @@ -1804,9 +2277,11 @@ | ||
| 1804 | 2277 | wp_safe_redirect(esc_url(admin_url('admin.php?page=mxchat-prompts'))); |
| 1805 | 2278 | exit; |
| 1806 | 2279 | } |
| 1807 | 2280 | |
| 2281 | + //error_log('[MXCHAT-URL] Valid XML found, handling sitemap for knowledge base'); | |
| 1808 | 2282 | $result = $this->handle_sitemap_for_knowledge_base($xml, $submitted_url); |
| 2283 | + //error_log('[MXCHAT-URL] Sitemap handling result: ' . $result); | |
| 1809 | 2284 | |
| 1810 | 2285 | if ($result === 'scheduled') { |
| 1811 | 2286 | set_transient( |
| 1812 | 2287 | 'mxchat_last_sitemap_url', |
| @@ -1817,10 +2292,12 @@ | ||
| 1817 | 2292 | esc_html__('Sitemap processing has started in the background. You can check the progress in the Knowledge Base section.', 'mxchat'), |
| 1818 | 2293 | 30 |
| 1819 | 2294 | ); |
| 1820 | 2295 | } else { |
| 2296 | + // Return to the admin page without a redirect for better error display | |
| 2297 | + // The error is already stored in the sitemap status transient | |
| 1821 | 2298 | set_transient('mxchat_admin_notice_error', |
| 1822 | - esc_html__('Failed to start sitemap processing. Please try again.', 'mxchat'), | |
| 2299 | + esc_html__('Failed to start sitemap processing. Please check the status below for details.', 'mxchat'), | |
| 1823 | 2300 | 30 |
| 1824 | 2301 | ); |
| 1825 | 2302 | } |
| 1826 | 2303 | |
| @@ -1828,12 +2305,17 @@ | ||
| 1828 | 2305 | exit; |
| 1829 | 2306 | } |
| 1830 | 2307 | |
| 1831 | 2308 | // Handle Regular URL |
| 2309 | + //error_log('[MXCHAT-URL] Processing as regular webpage'); | |
| 1832 | 2310 | $page_content = $this->mxchat_extract_main_content($body_content); |
| 2311 | + //error_log('[MXCHAT-URL] Extracted content length: ' . strlen($page_content) . ' bytes'); | |
| 2312 | + | |
| 1833 | 2313 | $sanitized_content = $this->mxchat_sanitize_content_for_api($page_content); |
| 2314 | + //error_log('[MXCHAT-URL] Sanitized content length: ' . strlen($sanitized_content) . ' bytes'); | |
| 1834 | 2315 | |
| 1835 | 2316 | if (empty($sanitized_content)) { |
| 2317 | + //error_log('[MXCHAT-URL] Error: No valid content after sanitization'); | |
| 1836 | 2318 | set_transient('mxchat_admin_notice_error', |
| 1837 | 2319 | esc_html__('No valid content found on the provided URL.', 'mxchat'), |
| 1838 | 2320 | 30 |
| 1839 | 2321 | ); |
| @@ -1840,29 +2322,59 @@ | ||
| 1840 | 2322 | wp_safe_redirect(esc_url(admin_url('admin.php?page=mxchat-prompts'))); |
| 1841 | 2323 | exit; |
| 1842 | 2324 | } |
| 1843 | 2325 | |
| 2326 | + //error_log('[MXCHAT-URL] Generating embedding for content'); | |
| 1844 | 2327 | $embedding_vector = $this->mxchat_generate_embedding($sanitized_content); |
| 2328 | + | |
| 2329 | + // Check if embedding_vector is a string (error message) | |
| 2330 | + if (is_string($embedding_vector)) { | |
| 2331 | + //error_log('[MXCHAT-URL] Error generating embedding: ' . $embedding_vector); | |
| 2332 | + set_transient('mxchat_admin_notice_error', | |
| 2333 | + esc_html__('Failed to generate embedding: ', 'mxchat') . esc_html($embedding_vector), | |
| 2334 | + 30 | |
| 2335 | + ); | |
| 2336 | + wp_safe_redirect(esc_url(admin_url('admin.php?page=mxchat-prompts'))); | |
| 2337 | + exit; | |
| 2338 | + } | |
| 2339 | + | |
| 1845 | 2340 | if (is_array($embedding_vector)) { |
| 1846 | - MxChat_Utils::submit_content_to_db( | |
| 2341 | + //error_log('[MXCHAT-URL] Successfully generated embedding with ' . count($embedding_vector) . ' dimensions'); | |
| 2342 | + | |
| 2343 | + $db_result = MxChat_Utils::submit_content_to_db( | |
| 1847 | 2344 | $sanitized_content, |
| 1848 | 2345 | $submitted_url, |
| 1849 | 2346 | $this->options['api_key'] |
| 1850 | 2347 | ); |
| 2348 | + | |
| 2349 | + if (is_wp_error($db_result)) { | |
| 2350 | + //error_log('[MXCHAT-URL] Error: Failed to store content in database: ' . $db_result->get_error_message()); | |
| 2351 | + set_transient('mxchat_admin_notice_error', | |
| 2352 | + esc_html__('Failed to store content in database: ', 'mxchat') . esc_html($db_result->get_error_message()), | |
| 2353 | + 30 | |
| 2354 | + ); | |
| 2355 | + wp_safe_redirect(esc_url(admin_url('admin.php?page=mxchat-prompts'))); | |
| 2356 | + exit; | |
| 2357 | + } | |
| 2358 | + | |
| 2359 | + //error_log('[MXCHAT-URL] Successfully stored content in database'); | |
| 1851 | 2360 | set_transient('mxchat_admin_notice_success', |
| 1852 | 2361 | esc_html__('URL content successfully submitted!', 'mxchat'), |
| 1853 | 2362 | 30 |
| 1854 | 2363 | ); |
| 1855 | 2364 | } else { |
| 2365 | + //error_log('[MXCHAT-URL] Error: Failed to generate embedding. Unexpected result type: ' . gettype($embedding_vector)); | |
| 1856 | 2366 | set_transient('mxchat_admin_notice_error', |
| 1857 | - esc_html__('Failed to generate embedding for the URL content. Please check your API key and try again.', 'mxchat'), | |
| 2367 | + esc_html__('Failed to generate embedding: Unexpected result type. Please check your API key and try again.', 'mxchat'), | |
| 1858 | 2368 | 30 |
| 1859 | 2369 | ); |
| 1860 | 2370 | } |
| 1861 | 2371 | |
| 2372 | + //error_log('[MXCHAT-URL] ===== Completed URL submission process ====='); | |
| 1862 | 2373 | wp_safe_redirect(esc_url(admin_url('admin.php?page=mxchat-prompts'))); |
| 1863 | 2374 | exit; |
| 1864 | 2375 | } |
| 2376 | + | |
| 1865 | 2377 | private function handle_sitemap_for_knowledge_base($xml, $sitemap_url) { |
| 1866 | 2378 | if (!current_user_can('manage_options')) { |
| 1867 | 2379 | //error_log(esc_html__('Unauthorized sitemap processing attempt', 'mxchat')); |
| 1868 | 2380 | return false; |
| @@ -1874,8 +2386,40 @@ | ||
| 1874 | 2386 | if (!$xml || !is_object($xml)) { |
| 1875 | 2387 | throw new Exception(__('Invalid XML object provided', 'mxchat')); |
| 1876 | 2388 | } |
| 1877 | 2389 | |
| 2390 | + // Add embedding validation before processing | |
| 2391 | + // Test embedding with a small sample text to verify API key is working | |
| 2392 | + $test_result = $this->mxchat_generate_embedding("This is a test to verify the embedding API key is working."); | |
| 2393 | + | |
| 2394 | + // Check if test_result is a string (error message) rather than an array (valid embedding) | |
| 2395 | + if (is_string($test_result)) { | |
| 2396 | + //error_log('[MXCHAT-URL] Embedding API validation failed: ' . $test_result); | |
| 2397 | + | |
| 2398 | + // Store the error in the status transient so it can be displayed later | |
| 2399 | + $status_data = array( | |
| 2400 | + 'total_urls' => 0, | |
| 2401 | + 'processed_urls' => 0, | |
| 2402 | + 'status' => 'error', | |
| 2403 | + 'error' => __('Embedding API validation failed: ', 'mxchat') . $test_result, | |
| 2404 | + 'last_update' => time() | |
| 2405 | + ); | |
| 2406 | + | |
| 2407 | + set_transient( | |
| 2408 | + sanitize_key('mxchat_sitemap_status_' . md5($sitemap_url)), | |
| 2409 | + array_map('sanitize_text_field', $status_data), | |
| 2410 | + DAY_IN_SECONDS | |
| 2411 | + ); | |
| 2412 | + | |
| 2413 | + throw new Exception(__('Embedding API validation failed: ', 'mxchat') . $test_result); | |
| 2414 | + } | |
| 2415 | + | |
| 2416 | + // Make sure it's an array (valid embedding) | |
| 2417 | + if (!is_array($test_result)) { | |
| 2418 | + //error_log('[MXCHAT-URL] Embedding API returned unexpected result type: ' . gettype($test_result)); | |
| 2419 | + throw new Exception(__('Embedding API returned unexpected result type. Please check your configuration.', 'mxchat')); | |
| 2420 | + } | |
| 2421 | + | |
| 1878 | 2422 | $urls = []; |
| 1879 | 2423 | foreach ($xml->url as $url_element) { |
| 1880 | 2424 | $url = esc_url_raw((string)$url_element->loc); |
| 1881 | 2425 | if ($url) { |
| @@ -1912,12 +2456,36 @@ | ||
| 1912 | 2456 | |
| 1913 | 2457 | return __('scheduled', 'mxchat'); |
| 1914 | 2458 | |
| 1915 | 2459 | } catch (\Exception $e) { |
| 1916 | - //error_log(sprintf(esc_html__('Error preparing sitemap for processing: %s', 'mxchat'), esc_html($e->getMessage()))); | |
| 1917 | - return false; | |
| 2460 | + $error_message = $e->getMessage(); | |
| 2461 | + //error_log(sprintf(esc_html__('Error preparing sitemap for processing: %s', 'mxchat'), esc_html($error_message))); | |
| 2462 | + | |
| 2463 | + // Store the sitemap URL and error in transients so they can be displayed | |
| 2464 | + set_transient( | |
| 2465 | + 'mxchat_last_sitemap_url', | |
| 2466 | + sanitize_text_field($sitemap_url), | |
| 2467 | + DAY_IN_SECONDS | |
| 2468 | + ); | |
| 2469 | + | |
| 2470 | + $status_data = array( | |
| 2471 | + 'total_urls' => 0, | |
| 2472 | + 'processed_urls' => 0, | |
| 2473 | + 'status' => 'error', | |
| 2474 | + 'error' => $error_message, | |
| 2475 | + 'last_update' => time() | |
| 2476 | + ); | |
| 2477 | + | |
| 2478 | + set_transient( | |
| 2479 | + sanitize_key('mxchat_sitemap_status_' . md5($sitemap_url)), | |
| 2480 | + array_map('sanitize_text_field', $status_data), | |
| 2481 | + DAY_IN_SECONDS | |
| 2482 | + ); | |
| 2483 | + | |
| 2484 | + return $error_message; | |
| 1918 | 2485 | } |
| 1919 | 2486 | } |
| 2487 | + | |
| 1920 | 2488 | public static function process_sitemap_urls_cron($urls, $sitemap_url, $total_urls, $batch_size, $batch_pause) { |
| 1921 | 2489 | // Validate inputs |
| 1922 | 2490 | $sitemap_url = esc_url_raw($sitemap_url); |
| 1923 | 2491 | $total_urls = absint($total_urls); |
| @@ -1943,11 +2511,38 @@ | ||
| 1943 | 2511 | // Track failures in batch |
| 1944 | 2512 | $batch_stats = [ |
| 1945 | 2513 | 'processed' => 0, |
| 1946 | 2514 | 'failed' => 0, |
| 1947 | - 'last_error' => '' | |
| 2515 | + 'last_error' => '', | |
| 2516 | + 'embedding_errors' => 0 // Track specifically embedding errors | |
| 1948 | 2517 | ]; |
| 1949 | 2518 | |
| 2519 | + // Check embedding configuration with first URL | |
| 2520 | + if ($start_url === 0) { | |
| 2521 | + $page_url = esc_url_raw($urls[0]); | |
| 2522 | + $page_response = wp_remote_get($page_url); | |
| 2523 | + | |
| 2524 | + if (!is_wp_error($page_response) && wp_remote_retrieve_response_code($page_response) === 200) { | |
| 2525 | + $page_html = wp_remote_retrieve_body($page_response); | |
| 2526 | + $page_content = $instance->mxchat_extract_main_content($page_html); | |
| 2527 | + $sanitized_content = $instance->mxchat_sanitize_content_for_api($page_content); | |
| 2528 | + | |
| 2529 | + if (!empty($sanitized_content)) { | |
| 2530 | + $embedding_vector = $instance->mxchat_generate_embedding($sanitized_content); | |
| 2531 | + | |
| 2532 | + // Check if embedding_vector is a string (error message) | |
| 2533 | + if (is_string($embedding_vector)) { | |
| 2534 | + throw new Exception('Embedding generation failed: ' . $embedding_vector); | |
| 2535 | + } | |
| 2536 | + | |
| 2537 | + // Make sure it's an array (valid embedding) | |
| 2538 | + if (!is_array($embedding_vector)) { | |
| 2539 | + throw new Exception('Embedding generation returned unexpected result type: ' . gettype($embedding_vector)); | |
| 2540 | + } | |
| 2541 | + } | |
| 2542 | + } | |
| 2543 | + } | |
| 2544 | + | |
| 1950 | 2545 | for ($i = $start_url; $i < $end_url; $i++) { |
| 1951 | 2546 | $page_url = esc_url_raw($urls[$i]); |
| 1952 | 2547 | $page_response = wp_remote_get($page_url); |
| 1953 | 2548 | |
| @@ -1952,8 +2547,10 @@ | ||
| 1952 | 2547 | $page_response = wp_remote_get($page_url); |
| 1953 | 2548 | |
| 1954 | 2549 | if (is_wp_error($page_response) || wp_remote_retrieve_response_code($page_response) !== 200) { |
| 1955 | 2550 | $batch_stats['failed']++; |
| 2551 | + $error_message = is_wp_error($page_response) ? $page_response->get_error_message() : 'HTTP Status: ' . wp_remote_retrieve_response_code($page_response); | |
| 2552 | + $batch_stats['last_error'] = 'Failed to fetch URL: ' . $error_message; | |
| 1956 | 2553 | continue; |
| 1957 | 2554 | } |
| 1958 | 2555 | |
| 1959 | 2556 | $page_html = wp_remote_retrieve_body($page_response); |
| @@ -1962,8 +2559,22 @@ | ||
| 1962 | 2559 | |
| 1963 | 2560 | if (!empty($sanitized_content)) { |
| 1964 | 2561 | $embedding_vector = $instance->mxchat_generate_embedding($sanitized_content); |
| 1965 | 2562 | |
| 2563 | + // Check if embedding_vector is a string (error message) | |
| 2564 | + if (is_string($embedding_vector)) { | |
| 2565 | + $batch_stats['failed']++; | |
| 2566 | + $batch_stats['embedding_errors']++; | |
| 2567 | + $batch_stats['last_error'] = 'Failed to generate embedding: ' . $embedding_vector; | |
| 2568 | + | |
| 2569 | + // If we have multiple embedding errors, stop processing | |
| 2570 | + if ($batch_stats['embedding_errors'] >= 3) { | |
| 2571 | + throw new Exception('Multiple embedding failures detected: ' . $embedding_vector); | |
| 2572 | + } | |
| 2573 | + continue; | |
| 2574 | + } | |
| 2575 | + | |
| 2576 | + // Check if it's an array (valid embedding) | |
| 1966 | 2577 | if (is_array($embedding_vector)) { |
| 1967 | 2578 | $options = get_option('mxchat_options'); |
| 1968 | 2579 | $submission_result = MxChat_Utils::submit_content_to_db($sanitized_content, $page_url, $options['api_key']); |
| 1969 | 2580 | |
| @@ -1975,9 +2586,15 @@ | ||
| 1975 | 2586 | |
| 1976 | 2587 | $batch_stats['processed']++; |
| 1977 | 2588 | } else { |
| 1978 | 2589 | $batch_stats['failed']++; |
| 1979 | - $batch_stats['last_error'] = 'Failed to generate embedding. Please check OpenAI API key.'; | |
| 2590 | + $batch_stats['embedding_errors']++; | |
| 2591 | + $batch_stats['last_error'] = 'Failed to generate embedding: Unexpected result type: ' . gettype($embedding_vector); | |
| 2592 | + | |
| 2593 | + // If we have multiple embedding errors, stop processing | |
| 2594 | + if ($batch_stats['embedding_errors'] >= 3) { | |
| 2595 | + throw new Exception('Multiple embedding failures detected. Please check your embedding API configuration.'); | |
| 2596 | + } | |
| 1980 | 2597 | } |
| 1981 | 2598 | } |
| 1982 | 2599 | |
| 1983 | 2600 | $status['processed_urls'] = absint($i + 1); |
| @@ -2018,8 +2635,9 @@ | ||
| 2018 | 2635 | set_transient($status_key, array_map('sanitize_text_field', $status), DAY_IN_SECONDS); |
| 2019 | 2636 | } |
| 2020 | 2637 | } |
| 2021 | 2638 | |
| 2639 | + | |
| 2022 | 2640 | public function get_sitemap_processing_status($sitemap_url) { |
| 2023 | 2641 | $sitemap_url = esc_url_raw($sitemap_url); |
| 2024 | 2642 | $status = get_transient(sanitize_key('mxchat_sitemap_status_' . md5($sitemap_url))); |
| 2025 | 2643 | |
| @@ -2040,8 +2658,42 @@ | ||
| 2040 | 2658 | 'last_error' => isset($status['last_error']) ? sanitize_text_field($status['last_error']) : '' |
| 2041 | 2659 | ); |
| 2042 | 2660 | } |
| 2043 | 2661 | |
| 2662 | + | |
| 2663 | + | |
| 2664 | +/** | |
| 2665 | + * AJAX handler to return the current processing status | |
| 2666 | + */ | |
| 2667 | +public function ajax_get_status_updates() { | |
| 2668 | + // Verify the request | |
| 2669 | + check_ajax_referer('mxchat_status_nonce', 'nonce'); | |
| 2670 | + | |
| 2671 | + // Get the status just like in your admin page | |
| 2672 | + $pdf_url = get_transient('mxchat_last_pdf_url'); | |
| 2673 | + $sitemap_url = get_transient('mxchat_last_sitemap_url'); | |
| 2674 | + $pdf_status = $pdf_url ? $this->get_pdf_processing_status($pdf_url) : false; | |
| 2675 | + $sitemap_status = $sitemap_url ? $this->get_sitemap_processing_status($sitemap_url) : false; | |
| 2676 | + | |
| 2677 | + if ($pdf_status && $pdf_status['status'] === 'complete') { | |
| 2678 | + delete_transient('mxchat_last_pdf_url'); | |
| 2679 | + $pdf_status = false; | |
| 2680 | + } | |
| 2681 | + if ($sitemap_status && $sitemap_status['status'] === 'complete') { | |
| 2682 | + delete_transient('mxchat_last_sitemap_url'); | |
| 2683 | + $sitemap_status = false; | |
| 2684 | + } | |
| 2685 | + | |
| 2686 | + // Return JSON response with the status data | |
| 2687 | + wp_send_json(array( | |
| 2688 | + 'pdf_status' => $pdf_status, | |
| 2689 | + 'sitemap_status' => $sitemap_status, | |
| 2690 | + 'is_processing' => ($pdf_status && ($pdf_status['status'] === 'processing' || $pdf_status['status'] === 'error')) | |
| 2691 | + || ($sitemap_status && ($sitemap_status['status'] === 'processing' || $sitemap_status['status'] === 'error')) | |
| 2692 | + )); | |
| 2693 | +} | |
| 2694 | + | |
| 2695 | + | |
| 2044 | 2696 | public function mxchat_stop_processing() { |
| 2045 | 2697 | // Verify permissions |
| 2046 | 2698 | if (!current_user_can('manage_options')) { |
| 2047 | 2699 | wp_die(esc_html__('Unauthorized access', 'mxchat')); |
| @@ -2077,27 +2729,53 @@ | ||
| 2077 | 2729 | ); |
| 2078 | 2730 | wp_safe_redirect(admin_url('admin.php?page=mxchat-prompts')); |
| 2079 | 2731 | exit; |
| 2080 | 2732 | } |
| 2733 | + | |
| 2734 | + | |
| 2081 | 2735 | private function mxchat_sanitize_content_for_api($content) { |
| 2736 | + //error_log('[MXCHAT-SANITIZE] Original content preview: ' . substr($content, 0, 500) . '...'); | |
| 2737 | + | |
| 2082 | 2738 | // Remove script, style tags, and HTML comments |
| 2083 | 2739 | $content = preg_replace('/<script\b[^>]*>(.*?)<\/script>/is', '', $content); |
| 2084 | 2740 | $content = preg_replace('/<style\b[^>]*>(.*?)<\/style>/is', '', $content); |
| 2085 | 2741 | $content = preg_replace('/<!--(.|\s)*?-->/', '', $content); |
| 2086 | - | |
| 2742 | + | |
| 2087 | 2743 | // Remove all HTML tags and decode HTML entities |
| 2088 | 2744 | $content = wp_strip_all_tags($content); |
| 2089 | 2745 | $content = html_entity_decode($content, ENT_QUOTES | ENT_HTML5); |
| 2090 | - | |
| 2746 | + | |
| 2091 | 2747 | // Trim and normalize whitespace |
| 2092 | 2748 | $content = trim(preg_replace('/\s+/', ' ', $content)); |
| 2093 | - | |
| 2749 | + | |
| 2750 | + // Remove control characters (which can cause database issues) | |
| 2751 | + $content = preg_replace('/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/u', '', $content); | |
| 2752 | + | |
| 2753 | + // Remove NULL bytes which can cause database errors | |
| 2754 | + $content = str_replace("\0", "", $content); | |
| 2755 | + | |
| 2756 | + // Ensure valid UTF-8 encoding | |
| 2757 | + $content = wp_check_invalid_utf8($content); | |
| 2758 | + | |
| 2759 | + // Remove any extremely long strings without spaces (often garbage) | |
| 2760 | + $content = preg_replace('/\S{300,}/', ' ', $content); | |
| 2761 | + | |
| 2762 | + // Replace problematic characters that often cause database issues | |
| 2763 | + $content = preg_replace('/[\x{10000}-\x{10FFFF}]/u', '', $content); // Remove emoji and other high Unicode characters | |
| 2764 | + | |
| 2765 | + // Replace any remaining potentially problematic characters with spaces | |
| 2766 | + $content = preg_replace('/[^\p{L}\p{N}\p{P}\p{Z}\p{Sm}]/u', ' ', $content); | |
| 2767 | + | |
| 2768 | + // Limit to reasonable length if needed | |
| 2769 | + $max_length = 65000; // Just under MySQL TEXT field limit | |
| 2770 | + if (strlen($content) > $max_length) { | |
| 2771 | + $content = substr($content, 0, $max_length); | |
| 2772 | + } | |
| 2773 | + | |
| 2774 | + //error_log('[MXCHAT-SANITIZE] Sanitized content preview: ' . substr($content, 0, 500) . '...'); | |
| 2094 | 2775 | return $content; |
| 2095 | 2776 | } |
| 2096 | 2777 | |
| 2097 | - | |
| 2098 | - | |
| 2099 | - | |
| 2100 | 2778 | public function mxchat_handle_product_change($post_id, $post, $update) { |
| 2101 | 2779 | if ($post->post_type !== 'product') { |
| 2102 | 2780 | return; |
| 2103 | 2781 | } |
| @@ -2206,8 +2884,9 @@ | ||
| 2206 | 2884 | $wpdb->delete($table_name, array('source_url' => $source_url), array('%s')); |
| 2207 | 2885 | } |
| 2208 | 2886 | } |
| 2209 | 2887 | |
| 2888 | + | |
| 2210 | 2889 | /** |
| 2211 | 2890 | * Delete vectors from Pinecone by source URL |
| 2212 | 2891 | * |
| 2213 | 2892 | * @param array $urls Array of source URLs to delete |
| @@ -2296,139 +2975,11 @@ | ||
| 2296 | 2975 | ); |
| 2297 | 2976 | } |
| 2298 | 2977 | |
| 2299 | 2978 | |
| 2300 | -public function mxchat_fetch_chat_history() { | |
| 2301 | - global $wpdb; | |
| 2302 | - $table_name = $wpdb->prefix . 'mxchat_chat_transcripts'; | |
| 2303 | 2979 | |
| 2304 | - if (!current_user_can('manage_options')) { | |
| 2305 | - wp_die(esc_html__('You do not have sufficient permissions to view this page.', 'mxchat')); | |
| 2306 | - } | |
| 2307 | 2980 | |
| 2308 | - // First get unique session IDs ordered by most recent message in each session | |
| 2309 | - $session_ids = $wpdb->get_col( | |
| 2310 | - $wpdb->prepare( | |
| 2311 | - "SELECT DISTINCT session_id | |
| 2312 | - FROM {$table_name} | |
| 2313 | - GROUP BY session_id | |
| 2314 | - ORDER BY MAX(timestamp) DESC" | |
| 2315 | - ) | |
| 2316 | - ); | |
| 2317 | 2981 | |
| 2318 | - if (empty($session_ids)) { | |
| 2319 | - wp_die(esc_html__('No chat history available.', 'mxchat')); | |
| 2320 | - } | |
| 2321 | - | |
| 2322 | - ob_start(); | |
| 2323 | - echo '<div class="mxchat-transcript">'; | |
| 2324 | - | |
| 2325 | - // Iterate through sessions from newest to oldest | |
| 2326 | - foreach ($session_ids as $session_id) { | |
| 2327 | - // Get the email associated with this session (if available) | |
| 2328 | - $email = $wpdb->get_var( | |
| 2329 | - $wpdb->prepare( | |
| 2330 | - "SELECT user_email | |
| 2331 | - FROM {$table_name} | |
| 2332 | - WHERE session_id = %s AND user_email != '' | |
| 2333 | - ORDER BY timestamp ASC | |
| 2334 | - LIMIT 1", | |
| 2335 | - $session_id | |
| 2336 | - ) | |
| 2337 | - ); | |
| 2338 | - | |
| 2339 | - // Debug: Check email retrieval | |
| 2340 | - if (empty($email)) { | |
| 2341 | - //error_log("No email found for session {$session_id}"); | |
| 2342 | - } else { | |
| 2343 | - //error_log("Email for session {$session_id}: " . $email); | |
| 2344 | - } | |
| 2345 | - | |
| 2346 | - // Get messages for this session ordered by timestamp | |
| 2347 | - $messages = $wpdb->get_results( | |
| 2348 | - $wpdb->prepare( | |
| 2349 | - "SELECT * FROM {$table_name} | |
| 2350 | - WHERE session_id = %s | |
| 2351 | - ORDER BY timestamp ASC", | |
| 2352 | - $session_id | |
| 2353 | - ) | |
| 2354 | - ); | |
| 2355 | - | |
| 2356 | - // Start session block | |
| 2357 | - echo '<div class="mxchat-session">'; | |
| 2358 | - echo '<div class="mxchat-session-header">'; | |
| 2359 | - // Wrap checkbox and session ID in one block | |
| 2360 | - echo '<div class="mxchat-session-id">'; | |
| 2361 | - echo '<input type="checkbox" name="delete_session_ids[]" value="' . esc_attr($session_id) . '"> '; | |
| 2362 | - echo '<strong>' . esc_html__('Session ID:', 'mxchat') . '</strong> ' . esc_html($session_id); | |
| 2363 | - echo '</div>'; | |
| 2364 | - | |
| 2365 | - // Place email directly below the session ID block | |
| 2366 | - if (!empty($email)) { | |
| 2367 | - echo '<div class="mxchat-session-email">'; | |
| 2368 | - echo '<strong>' . esc_html__('Email:', 'mxchat') . '</strong> ' . esc_html($email); | |
| 2369 | - echo '</div>'; | |
| 2370 | - } | |
| 2371 | - echo '</div>'; | |
| 2372 | - | |
| 2373 | - echo '<div class="mxchat-messages">'; | |
| 2374 | - | |
| 2375 | - // Display messages for this session | |
| 2376 | - foreach ($messages as $transcript) { | |
| 2377 | - $formatted_timestamp = date_i18n('F j, Y g:i a', strtotime($transcript->timestamp)); | |
| 2378 | - | |
| 2379 | - // Determine message styling | |
| 2380 | - switch ($transcript->role) { | |
| 2381 | - case 'assistant': | |
| 2382 | - case 'bot': | |
| 2383 | - $message_class = 'bot-message'; | |
| 2384 | - $display_role = esc_html__('Chatbot', 'mxchat'); | |
| 2385 | - break; | |
| 2386 | - case 'user': | |
| 2387 | - $message_class = 'user-message'; | |
| 2388 | - $display_role = !empty($transcript->user_identifier) | |
| 2389 | - ? sanitize_text_field($transcript->user_identifier) | |
| 2390 | - : esc_html__('User', 'mxchat'); | |
| 2391 | - break; | |
| 2392 | - case 'agent': | |
| 2393 | - $message_class = 'agent-message'; | |
| 2394 | - $display_role = esc_html__('Agent', 'mxchat'); | |
| 2395 | - break; | |
| 2396 | - default: | |
| 2397 | - $message_class = 'unknown-message'; | |
| 2398 | - $display_role = esc_html__('Unknown', 'mxchat'); | |
| 2399 | - } | |
| 2400 | - | |
| 2401 | - // Process message content | |
| 2402 | - $message_content = wp_kses( | |
| 2403 | - stripslashes($transcript->message), | |
| 2404 | - [ | |
| 2405 | - 'b' => [], 'strong' => [], 'i' => [], 'em' => [], 'u' => [], | |
| 2406 | - 'br' => [], 'p' => [], 'ul' => [], 'ol' => [], 'li' => [], | |
| 2407 | - 'a' => ['href' => [], 'title' => []] | |
| 2408 | - ] | |
| 2409 | - ); | |
| 2410 | - $message_content = nl2br($message_content); | |
| 2411 | - | |
| 2412 | - // Render message | |
| 2413 | - echo '<div class="mxchat-message ' . esc_attr($message_class) . '">'; | |
| 2414 | - echo '<div class="mxchat-message-header">' . esc_html($display_role) . '</div>'; | |
| 2415 | - echo '<div class="mxchat-message-content">' . $message_content . '</div>'; | |
| 2416 | - echo '<div class="mxchat-timestamp">' . esc_html($formatted_timestamp) . '</div>'; | |
| 2417 | - echo '</div>'; | |
| 2418 | - } | |
| 2419 | - | |
| 2420 | - // Close session block | |
| 2421 | - echo '</div></div>'; | |
| 2422 | - } | |
| 2423 | - | |
| 2424 | - echo '</div>'; | |
| 2425 | - $output = ob_get_clean(); | |
| 2426 | - echo $output; | |
| 2427 | - wp_die(); | |
| 2428 | -} | |
| 2429 | - | |
| 2430 | - | |
| 2431 | 2982 | public function mxchat_create_activation_page() { |
| 2432 | 2983 | $license_status = get_option('mxchat_license_status', 'inactive'); |
| 2433 | 2984 | $license_error = get_option('mxchat_license_error', ''); |
| 2434 | 2985 | ?> |
| @@ -3037,22 +3588,12 @@ | ||
| 3037 | 3588 | |
| 3038 | 3589 | private function mxchat_get_available_callbacks($grouped = false) { |
| 3039 | 3590 | $callbacks = [ |
| 3040 | 3591 | 'mxchat_handle_email_capture' => [ |
| 3041 | - 'label' => __('Email Capture', 'mxchat'), | |
| 3592 | + 'label' => __('Loops Email Capture', 'mxchat'), | |
| 3042 | 3593 | 'pro_only' => false, |
| 3043 | 3594 | 'group' => __('Customer Engagement', 'mxchat'), |
| 3044 | 3595 | ], |
| 3045 | - 'mxchat_handle_product_inquiry' => [ | |
| 3046 | - 'label' => __('Show Product Card', 'mxchat'), | |
| 3047 | - 'pro_only' => true, | |
| 3048 | - 'group' => __('WooCommerce Features', 'mxchat'), | |
| 3049 | - ], | |
| 3050 | - 'mxchat_handle_order_history' => [ | |
| 3051 | - 'label' => __('Order History', 'mxchat'), | |
| 3052 | - 'pro_only' => true, | |
| 3053 | - 'group' => __('WooCommerce Features', 'mxchat'), | |
| 3054 | - ], | |
| 3055 | 3596 | 'mxchat_generate_image' => [ |
| 3056 | 3597 | 'label' => __('Generate Image', 'mxchat'), |
| 3057 | 3598 | 'pro_only' => true, |
| 3058 | 3599 | 'group' => __('Other Features', 'mxchat'), |
| @@ -3066,28 +3607,13 @@ | ||
| 3066 | 3607 | 'label' => __('Brave Image Search', 'mxchat'), |
| 3067 | 3608 | 'pro_only' => false, |
| 3068 | 3609 | 'group' => __('Search Features', 'mxchat'), |
| 3069 | 3610 | ], |
| 3070 | - 'mxchat_handle_add_to_cart_intent' => [ | |
| 3071 | - 'label' => __('Add to Cart', 'mxchat'), | |
| 3072 | - 'pro_only' => true, | |
| 3073 | - 'group' => __('WooCommerce Features', 'mxchat'), | |
| 3074 | - ], | |
| 3075 | - 'mxchat_handle_checkout_intent' => [ | |
| 3076 | - 'label' => __('Proceed to Checkout', 'mxchat'), | |
| 3077 | - 'pro_only' => true, | |
| 3078 | - 'group' => __('WooCommerce Features', 'mxchat'), | |
| 3079 | - ], | |
| 3080 | 3611 | 'mxchat_handle_pdf_discussion' => [ |
| 3081 | 3612 | 'label' => __('Chat with PDF', 'mxchat'), |
| 3082 | 3613 | 'pro_only' => true, |
| 3083 | 3614 | 'group' => __('Other Features', 'mxchat'), |
| 3084 | 3615 | ], |
| 3085 | - 'mxchat_handle_product_recommendations' => [ | |
| 3086 | - 'label' => __('Product Recommendations', 'mxchat'), | |
| 3087 | - 'pro_only' => true, | |
| 3088 | - 'group' => __('WooCommerce Features', 'mxchat'), | |
| 3089 | - ], | |
| 3090 | 3616 | 'mxchat_live_agent_handover' => [ |
| 3091 | 3617 | 'label' => __('Live Agent', 'mxchat'), |
| 3092 | 3618 | 'pro_only' => true, |
| 3093 | 3619 | 'group' => __('Customer Engagement', 'mxchat'), |
| @@ -3098,8 +3624,11 @@ | ||
| 3098 | 3624 | 'group' => __('Customer Engagement', 'mxchat'), |
| 3099 | 3625 | ], |
| 3100 | 3626 | ]; |
| 3101 | 3627 | |
| 3628 | + // Allow other plugins to add their callbacks | |
| 3629 | + $callbacks = apply_filters('mxchat_available_callbacks', $callbacks); | |
| 3630 | + | |
| 3102 | 3631 | // Return grouped structure if requested |
| 3103 | 3632 | if ($grouped) { |
| 3104 | 3633 | $grouped_callbacks = []; |
| 3105 | 3634 | foreach ($callbacks as $key => $data) { |
| @@ -3110,14 +3639,12 @@ | ||
| 3110 | 3639 | ]; |
| 3111 | 3640 | } |
| 3112 | 3641 | return $grouped_callbacks; |
| 3113 | 3642 | } |
| 3114 | - | |
| 3115 | 3643 | return $callbacks; |
| 3116 | 3644 | } |
| 3117 | 3645 | |
| 3118 | 3646 | |
| 3119 | - | |
| 3120 | 3647 | private function mxchat_average_vectors($vectors) { |
| 3121 | 3648 | $vector_length = count($vectors[0]); |
| 3122 | 3649 | $sum_vector = array_fill(0, $vector_length, 0); |
| 3123 | 3650 | |
| @@ -3203,41 +3730,86 @@ | ||
| 3203 | 3730 | ); |
| 3204 | 3731 | |
| 3205 | 3732 | |
| 3206 | 3733 | // Existing fields... |
| 3207 | - add_settings_field( | |
| 3208 | - 'api_key', | |
| 3209 | - esc_html__('OpenAI API Key', 'mxchat'), | |
| 3210 | - array($this, 'api_key_callback'), | |
| 3211 | - 'mxchat-chatbot', | |
| 3212 | - 'mxchat_chatbot_section' | |
| 3213 | - ); | |
| 3734 | + add_settings_field( | |
| 3735 | + 'api_key', | |
| 3736 | + esc_html__('OpenAI API Key', 'mxchat'), | |
| 3737 | + array($this, 'api_key_callback'), | |
| 3738 | + 'mxchat-chatbot', | |
| 3739 | + 'mxchat_chatbot_section', | |
| 3740 | + array( | |
| 3741 | + 'class' => 'mxchat-setting-row', | |
| 3742 | + 'data-provider' => 'openai' | |
| 3743 | + ) | |
| 3744 | + ); | |
| 3745 | + | |
| 3746 | + add_settings_field( | |
| 3747 | + 'xai_api_key', | |
| 3748 | + esc_html__('X.AI API Key', 'mxchat'), | |
| 3749 | + array($this, 'xai_api_key_callback'), | |
| 3750 | + 'mxchat-chatbot', | |
| 3751 | + 'mxchat_chatbot_section', | |
| 3752 | + array( | |
| 3753 | + 'class' => 'mxchat-setting-row', | |
| 3754 | + 'data-provider' => 'xai' | |
| 3755 | + ) | |
| 3756 | + ); | |
| 3757 | + | |
| 3758 | + add_settings_field( | |
| 3759 | + 'claude_api_key', | |
| 3760 | + esc_html__('Claude API Key', 'mxchat'), | |
| 3761 | + array($this, 'claude_api_key_callback'), | |
| 3762 | + 'mxchat-chatbot', | |
| 3763 | + 'mxchat_chatbot_section', | |
| 3764 | + array( | |
| 3765 | + 'class' => 'mxchat-setting-row', | |
| 3766 | + 'data-provider' => 'claude' | |
| 3767 | + ) | |
| 3768 | + ); | |
| 3769 | + | |
| 3770 | + add_settings_field( | |
| 3771 | + 'deepseek_api_key', | |
| 3772 | + esc_html__('DeepSeek API Key', 'mxchat'), | |
| 3773 | + array($this, 'deepseek_api_key_callback'), | |
| 3774 | + 'mxchat-chatbot', | |
| 3775 | + 'mxchat_chatbot_section', | |
| 3776 | + array( | |
| 3777 | + 'class' => 'mxchat-setting-row', | |
| 3778 | + 'data-provider' => 'deepseek' | |
| 3779 | + ) | |
| 3780 | + ); | |
| 3781 | + | |
| 3782 | + add_settings_field( | |
| 3783 | + 'voyage_api_key', | |
| 3784 | + esc_html__('Voyage AI API Key', 'mxchat'), | |
| 3785 | + array($this, 'voyage_api_key_callback'), | |
| 3786 | + 'mxchat-chatbot', | |
| 3787 | + 'mxchat_chatbot_section', | |
| 3788 | + array( | |
| 3789 | + 'class' => 'mxchat-setting-row', | |
| 3790 | + 'data-provider' => 'voyage' | |
| 3791 | + ) | |
| 3792 | + ); | |
| 3214 | 3793 | |
| 3215 | 3794 | add_settings_field( |
| 3216 | - 'xai_api_key', | |
| 3217 | - esc_html__('X.AI API Key', 'mxchat'), | |
| 3218 | - array($this, 'xai_api_key_callback'), | |
| 3795 | + 'model', | |
| 3796 | + esc_html__('Chat Model', 'mxchat'), | |
| 3797 | + array($this, 'mxchat_model_callback'), | |
| 3219 | 3798 | 'mxchat-chatbot', |
| 3220 | 3799 | 'mxchat_chatbot_section' |
| 3221 | 3800 | ); |
| 3222 | - | |
| 3801 | + | |
| 3802 | + // Add the settings field | |
| 3223 | 3803 | add_settings_field( |
| 3224 | - 'claude_api_key', | |
| 3225 | - esc_html__('Claude API Key', 'mxchat'), | |
| 3226 | - array($this, 'claude_api_key_callback'), | |
| 3804 | + 'embedding_model', | |
| 3805 | + esc_html__('Embedding Model', 'mxchat'), | |
| 3806 | + array($this, 'embedding_model_callback'), | |
| 3227 | 3807 | 'mxchat-chatbot', |
| 3228 | 3808 | 'mxchat_chatbot_section' |
| 3229 | 3809 | ); |
| 3230 | - | |
| 3810 | + | |
| 3231 | 3811 | add_settings_field( |
| 3232 | - 'deepseek_api_key', | |
| 3233 | - esc_html__('DeepSeek API Key', 'mxchat'), | |
| 3234 | - array($this, 'deepseek_api_key_callback'), | |
| 3235 | - 'mxchat-chatbot', | |
| 3236 | - 'mxchat_chatbot_section' | |
| 3237 | - ); | |
| 3238 | - | |
| 3239 | - add_settings_field( | |
| 3240 | 3812 | 'system_prompt_instructions', |
| 3241 | 3813 | esc_html__('AI Instructions (Behavior)', 'mxchat'), |
| 3242 | 3814 | array($this, 'system_prompt_instructions_callback'), |
| 3243 | 3815 | 'mxchat-chatbot', |
| @@ -3243,15 +3815,8 @@ | ||
| 3243 | 3815 | 'mxchat-chatbot', |
| 3244 | 3816 | 'mxchat_chatbot_section' |
| 3245 | 3817 | ); |
| 3246 | 3818 | |
| 3247 | - add_settings_field( | |
| 3248 | - 'model', | |
| 3249 | - esc_html__('Model', 'mxchat'), | |
| 3250 | - array($this, 'mxchat_model_callback'), | |
| 3251 | - 'mxchat-chatbot', | |
| 3252 | - 'mxchat_chatbot_section' | |
| 3253 | - ); | |
| 3254 | 3819 | |
| 3255 | 3820 | add_settings_field( |
| 3256 | 3821 | 'top_bar_title', |
| 3257 | 3822 | esc_html__('Top Bar Title', 'mxchat'), |
| @@ -3365,9 +3930,9 @@ | ||
| 3365 | 3930 | ); |
| 3366 | 3931 | |
| 3367 | 3932 | add_settings_field( |
| 3368 | 3933 | 'popular_question_1', |
| 3369 | - esc_html__('Popular Question 1', 'mxchat'), | |
| 3934 | + esc_html__('Quick Question 1', 'mxchat'), | |
| 3370 | 3935 | array($this, 'mxchat_popular_question_1_callback'), |
| 3371 | 3936 | 'mxchat-chatbot', |
| 3372 | 3937 | 'mxchat_chatbot_section' |
| 3373 | 3938 | ); |
| @@ -3373,9 +3938,9 @@ | ||
| 3373 | 3938 | ); |
| 3374 | 3939 | |
| 3375 | 3940 | add_settings_field( |
| 3376 | 3941 | 'popular_question_2', |
| 3377 | - esc_html__('Popular Question 2', 'mxchat'), | |
| 3942 | + esc_html__('Quick Question 2', 'mxchat'), | |
| 3378 | 3943 | array($this, 'mxchat_popular_question_2_callback'), |
| 3379 | 3944 | 'mxchat-chatbot', |
| 3380 | 3945 | 'mxchat_chatbot_section' |
| 3381 | 3946 | ); |
| @@ -3381,9 +3946,9 @@ | ||
| 3381 | 3946 | ); |
| 3382 | 3947 | |
| 3383 | 3948 | add_settings_field( |
| 3384 | 3949 | 'popular_question_3', |
| 3385 | - esc_html__('Popular Question 3', 'mxchat'), | |
| 3950 | + esc_html__('Quick Question 3', 'mxchat'), | |
| 3386 | 3951 | array($this, 'mxchat_popular_question_3_callback'), |
| 3387 | 3952 | 'mxchat-chatbot', |
| 3388 | 3953 | 'mxchat_chatbot_section' |
| 3389 | 3954 | ); |
| @@ -3389,21 +3954,14 @@ | ||
| 3389 | 3954 | ); |
| 3390 | 3955 | |
| 3391 | 3956 | add_settings_field( |
| 3392 | 3957 | 'additional_popular_questions', |
| 3393 | - esc_html__('Additional Popular Questions', 'mxchat'), | |
| 3958 | + esc_html__('Additional Quick Questions', 'mxchat'), | |
| 3394 | 3959 | array($this, 'mxchat_additional_popular_questions_callback'), |
| 3395 | 3960 | 'mxchat-chatbot', |
| 3396 | 3961 | 'mxchat_chatbot_section' |
| 3397 | 3962 | ); |
| 3398 | 3963 | |
| 3399 | - // WooCommerce Settings Section | |
| 3400 | - add_settings_section( | |
| 3401 | - 'mxchat_woocommerce_section', | |
| 3402 | - esc_html__('WooCommerce Settings', 'mxchat'), | |
| 3403 | - null, | |
| 3404 | - 'mxchat-embed' | |
| 3405 | - ); | |
| 3406 | 3964 | |
| 3407 | 3965 | // Loops Settings Section |
| 3408 | 3966 | add_settings_section( |
| 3409 | 3967 | 'mxchat_loops_section', |
| @@ -3411,33 +3969,8 @@ | ||
| 3411 | 3969 | null, |
| 3412 | 3970 | 'mxchat-embed' |
| 3413 | 3971 | ); |
| 3414 | 3972 | |
| 3415 | - // WooCommerce Settings Fields | |
| 3416 | - add_settings_field( | |
| 3417 | - 'enable_woocommerce_integration', | |
| 3418 | - esc_html__('Automatically Embed Products', 'mxchat'), | |
| 3419 | - array($this, 'mxchat_enable_woocommerce_integration_callback'), | |
| 3420 | - 'mxchat-embed', | |
| 3421 | - 'mxchat_woocommerce_section' | |
| 3422 | - ); | |
| 3423 | - | |
| 3424 | - add_settings_field( | |
| 3425 | - 'woocommerce_consumer_key', | |
| 3426 | - esc_html__('WooCommerce Consumer Key', 'mxchat'), | |
| 3427 | - array($this, 'mxchat_woocommerce_consumer_key_callback'), | |
| 3428 | - 'mxchat-embed', | |
| 3429 | - 'mxchat_woocommerce_section' | |
| 3430 | - ); | |
| 3431 | - | |
| 3432 | - add_settings_field( | |
| 3433 | - 'woocommerce_consumer_secret', | |
| 3434 | - esc_html__('WooCommerce Consumer Secret', 'mxchat'), | |
| 3435 | - array($this, 'mxchat_woocommerce_consumer_secret_callback'), | |
| 3436 | - 'mxchat-embed', | |
| 3437 | - 'mxchat_woocommerce_section' | |
| 3438 | - ); | |
| 3439 | - | |
| 3440 | 3973 | // Loops Settings Fields |
| 3441 | 3974 | add_settings_field( |
| 3442 | 3975 | 'loops_api_key', |
| 3443 | 3976 | esc_html__('Loops API Key', 'mxchat'), |
| @@ -3540,8 +4073,26 @@ | ||
| 3540 | 4073 | array($this, 'mxchat_chat_toolbar_toggle_callback'), |
| 3541 | 4074 | 'mxchat-embed', |
| 3542 | 4075 | 'mxchat_pdf_intent_section' |
| 3543 | 4076 | ); |
| 4077 | + | |
| 4078 | + // PDF Upload Button Toggle | |
| 4079 | + add_settings_field( | |
| 4080 | + 'show_pdf_upload_button', | |
| 4081 | + __('Show PDF Upload Button', 'mxchat'), | |
| 4082 | + array($this, 'mxchat_show_pdf_upload_button_callback'), | |
| 4083 | + 'mxchat-embed', | |
| 4084 | + 'mxchat_pdf_intent_section' | |
| 4085 | + ); | |
| 4086 | + | |
| 4087 | + // Word Upload Button Toggle | |
| 4088 | + add_settings_field( | |
| 4089 | + 'show_word_upload_button', | |
| 4090 | + __('Show Word Upload Button', 'mxchat'), | |
| 4091 | + array($this, 'mxchat_show_word_upload_button_callback'), | |
| 4092 | + 'mxchat-embed', | |
| 4093 | + 'mxchat_pdf_intent_section' | |
| 4094 | + ); | |
| 3544 | 4095 | |
| 3545 | 4096 | add_settings_field( |
| 3546 | 4097 | 'pdf_intent_trigger_text', |
| 3547 | 4098 | __('Intent Trigger Text', 'mxchat'), |
| @@ -3638,9 +4189,9 @@ | ||
| 3638 | 4189 | |
| 3639 | 4190 | // General Settings Section |
| 3640 | 4191 | add_settings_section( |
| 3641 | 4192 | 'mxchat_general_section', |
| 3642 | - esc_html__('Frequently Asked Questions (FAQ)', 'mxchat'), | |
| 4193 | + esc_html__('YouTube Tutorials', 'mxchat'), | |
| 3643 | 4194 | null, |
| 3644 | 4195 | 'mxchat-general' |
| 3645 | 4196 | ); |
| 3646 | 4197 | } |
| @@ -3883,52 +4434,8 @@ | ||
| 3883 | 4434 | echo '</div>'; |
| 3884 | 4435 | } |
| 3885 | 4436 | |
| 3886 | 4437 | |
| 3887 | -public function mxchat_enable_woocommerce_integration_callback() { | |
| 3888 | - // Load from mxchat_options array | |
| 3889 | - $options = get_option('mxchat_options', []); | |
| 3890 | - | |
| 3891 | - // Get WooCommerce integration status with backwards compatibility | |
| 3892 | - $woo_integration = isset($options['enable_woocommerce_integration']) | |
| 3893 | - ? $options['enable_woocommerce_integration'] | |
| 3894 | - : ''; | |
| 3895 | - | |
| 3896 | - // Support both old ('1') and new ('on') values | |
| 3897 | - $checked = ($woo_integration === 'on' || $woo_integration === '1') ? 'checked' : ''; | |
| 3898 | - | |
| 3899 | - // Check if the feature is activated (paid feature) | |
| 3900 | - $disabled = $this->is_activated ? '' : 'disabled'; | |
| 3901 | - $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive'; | |
| 3902 | - | |
| 3903 | - echo '<div class="' . esc_attr($class) . '">'; | |
| 3904 | - | |
| 3905 | - echo '<label class="toggle-switch">'; | |
| 3906 | - echo sprintf( | |
| 3907 | - '<input type="checkbox" id="enable_woocommerce_integration" name="enable_woocommerce_integration" value="on" %s %s />', | |
| 3908 | - esc_attr($checked), | |
| 3909 | - esc_attr($disabled) | |
| 3910 | - ); | |
| 3911 | - echo '<span class="slider"></span>'; | |
| 3912 | - echo '</label>'; | |
| 3913 | - | |
| 3914 | - echo '<p class="description">' . esc_html__('Automatically syncs new product additions, updates, and removals to the knowledge base. For existing products, submit your product sitemap in the Knowledge Base section to add them initially.', 'mxchat') . '</p>'; | |
| 3915 | - | |
| 3916 | - // Pro feature overlay for non-activated users | |
| 3917 | - if (!$this->is_activated) { | |
| 3918 | - echo '<div class="pro-feature-overlay">'; | |
| 3919 | - echo '<a href="https://mxchat.ai/" target="_blank">'; | |
| 3920 | - echo '<img src="' . esc_url(plugin_dir_url(__FILE__) . '../images/pro-only-dark.png') . '" alt="' . esc_attr__('Pro Only', 'mxchat') . '" />'; | |
| 3921 | - echo '</a>'; | |
| 3922 | - echo '</div>'; | |
| 3923 | - } | |
| 3924 | - | |
| 3925 | - echo '</div>'; | |
| 3926 | -} | |
| 3927 | - | |
| 3928 | - | |
| 3929 | - | |
| 3930 | - | |
| 3931 | 4438 | private function mxchat_add_option_field($id, $title, $callback = '') { |
| 3932 | 4439 | add_settings_field( |
| 3933 | 4440 | $id, |
| 3934 | 4441 | __($title, 'mxchat'), |
| @@ -3937,149 +4444,68 @@ | ||
| 3937 | 4444 | 'mxchat_setting_section_id', |
| 3938 | 4445 | $id === 'model' ? ['label_for' => 'model'] : [] |
| 3939 | 4446 | ); |
| 3940 | 4447 | } |
| 3941 | - | |
| 4448 | + | |
| 4449 | +// OpenAI API Key | |
| 3942 | 4450 | public function api_key_callback() { |
| 3943 | - // Retrieve from your stored 'api_key' in the mxchat_options array | |
| 3944 | 4451 | $apiKey = isset($this->options['api_key']) ? esc_attr($this->options['api_key']) : ''; |
| 3945 | - | |
| 3946 | - // Notice we changed the name to "api_key" (no array notation). | |
| 4452 | + | |
| 4453 | + echo '<div class="api-key-wrapper" data-provider="openai">'; | |
| 3947 | 4454 | echo '<input type="password" id="api_key" name="api_key" value="' . $apiKey . '" class="regular-text" />'; |
| 3948 | 4455 | echo '<button type="button" id="toggleApiKeyVisibility">' . esc_html__('Show', 'mxchat') . '</button>'; |
| 3949 | - echo '<p class="description">' . esc_html__('The OpenAI API key is required even when using other models as it is used for vector embedding functionality. You must add credits to your OpenAI billing account before use.', 'mxchat') . '</p>'; | |
| 4456 | + echo '<p class="description api-key-notice">' . esc_html__('Required for your selected chat model. Important: You must add credits before use.', 'mxchat') . '</p>'; | |
| 4457 | + echo '</div>'; | |
| 3950 | 4458 | } |
| 4459 | + | |
| 4460 | +// X.AI API Key | |
| 3951 | 4461 | public function xai_api_key_callback() { |
| 3952 | - // Check if the feature is activated (paid feature) | |
| 3953 | - $disabled = $this->is_activated ? '' : 'disabled'; // Disable input if not activated | |
| 3954 | - $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive'; // CSS class to style the wrapper based on activation status | |
| 3955 | - | |
| 3956 | - // Retrieve the X.AI API key value | |
| 3957 | 4462 | $xaiApiKey = isset($this->options['xai_api_key']) ? esc_attr($this->options['xai_api_key']) : ''; |
| 3958 | - | |
| 3959 | - // Render the input field for the X.AI API key | |
| 3960 | - echo '<div class="' . esc_attr($class) . '">'; | |
| 3961 | - printf( | |
| 3962 | - '<input type="password" id="xai_api_key" name="xai_api_key" value="%s" class="regular-text" %s />', | |
| 3963 | - $xaiApiKey, | |
| 3964 | - $disabled | |
| 3965 | - ); | |
| 4463 | + | |
| 4464 | + echo '<div class="api-key-wrapper" data-provider="xai">'; | |
| 4465 | + echo '<input type="password" id="xai_api_key" name="xai_api_key" value="' . $xaiApiKey . '" class="regular-text" />'; | |
| 3966 | 4466 | echo '<button type="button" id="toggleXaiApiKeyVisibility">' . esc_html__('Show', 'mxchat') . '</button>'; |
| 3967 | - | |
| 3968 | - // If the feature is not activated, show the overlay with a "Pro Only" message | |
| 3969 | - if (!$this->is_activated) { | |
| 3970 | - echo '<div class="pro-feature-overlay">'; | |
| 3971 | - echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="' . esc_attr__('Pro Only', 'mxchat') . '" /></a>'; | |
| 3972 | - echo '</div>'; | |
| 3973 | - } | |
| 3974 | - | |
| 4467 | + echo '<p class="description api-key-notice">' . esc_html__('Required for your selected chat model. Important: You must add credits before use.', 'mxchat') . '</p>'; | |
| 3975 | 4468 | echo '</div>'; |
| 3976 | 4469 | } |
| 4470 | + | |
| 4471 | +// Claude API Key | |
| 3977 | 4472 | public function claude_api_key_callback() { |
| 3978 | - // Check if the feature is activated (paid feature) | |
| 3979 | - $disabled = $this->is_activated ? '' : 'disabled'; | |
| 3980 | - $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive'; | |
| 3981 | - | |
| 3982 | - // Retrieve the Claude API key value directly like the others | |
| 3983 | 4473 | $claudeApiKey = isset($this->options['claude_api_key']) ? esc_attr($this->options['claude_api_key']) : ''; |
| 3984 | 4474 | |
| 3985 | - // Use direct name field like the other working API keys | |
| 3986 | - echo '<div class="' . esc_attr($class) . '">'; | |
| 3987 | - printf( | |
| 3988 | - '<input type="password" id="claude_api_key" name="claude_api_key" value="%s" class="regular-text" %s />', | |
| 3989 | - $claudeApiKey, | |
| 3990 | - $disabled | |
| 3991 | - ); | |
| 4475 | + echo '<div class="api-key-wrapper" data-provider="claude">'; | |
| 4476 | + echo '<input type="password" id="claude_api_key" name="claude_api_key" value="' . $claudeApiKey . '" class="regular-text" />'; | |
| 3992 | 4477 | echo '<button type="button" id="toggleClaudeApiKeyVisibility">' . esc_html__('Show', 'mxchat') . '</button>'; |
| 3993 | - | |
| 3994 | - if (!$this->is_activated) { | |
| 3995 | - echo '<div class="pro-feature-overlay">'; | |
| 3996 | - echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="' . esc_attr__('Pro Only', 'mxchat') . '" /></a>'; | |
| 3997 | - echo '</div>'; | |
| 3998 | - } | |
| 4478 | + echo '<p class="description api-key-notice">' . esc_html__('Required for your selected chat model. Important: You must add credits before use.', 'mxchat') . '</p>'; | |
| 3999 | 4479 | echo '</div>'; |
| 4000 | 4480 | } |
| 4481 | + | |
| 4482 | +// DeepSeek API Key | |
| 4001 | 4483 | public function deepseek_api_key_callback() { |
| 4002 | - // Retrieve from your stored 'deepseek_api_key' in the mxchat_options array | |
| 4003 | 4484 | $apiKey = isset($this->options['deepseek_api_key']) ? esc_attr($this->options['deepseek_api_key']) : ''; |
| 4004 | - | |
| 4005 | - // Notice we changed the name to "deepseek_api_key" (no array notation). | |
| 4485 | + | |
| 4486 | + echo '<div class="api-key-wrapper" data-provider="deepseek">'; | |
| 4006 | 4487 | echo '<input type="password" id="deepseek_api_key" name="deepseek_api_key" value="' . $apiKey . '" class="regular-text" />'; |
| 4007 | 4488 | echo '<button type="button" id="toggleDeepSeekApiKeyVisibility">' . esc_html__('Show', 'mxchat') . '</button>'; |
| 4489 | + echo '<p class="description api-key-notice">' . esc_html__('Required for your selected chat model. Important: You must add credits before use.', 'mxchat') . '</p>'; | |
| 4490 | + echo '</div>'; | |
| 4008 | 4491 | } |
| 4009 | 4492 | |
| 4010 | - | |
| 4011 | -public function mxchat_woocommerce_consumer_key_callback() { | |
| 4012 | - // Load the entire 'mxchat_options' array | |
| 4013 | - $all_options = get_option('mxchat_options', []); | |
| 4014 | - | |
| 4015 | - // Retrieve the WooCommerce consumer key or set a default | |
| 4016 | - $consumer_key = isset($all_options['woocommerce_consumer_key']) ? $all_options['woocommerce_consumer_key'] : ''; | |
| 4017 | - | |
| 4018 | - // Check if the feature is activated (paid feature) | |
| 4019 | - $disabled = $this->is_activated ? '' : 'disabled'; | |
| 4020 | - $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive'; | |
| 4021 | - | |
| 4022 | - echo '<div class="' . esc_attr($class) . '">'; | |
| 4023 | - | |
| 4024 | - // Render the input field | |
| 4025 | - printf( | |
| 4026 | - '<input type="text" id="woocommerce_consumer_key" name="woocommerce_consumer_key" value="%s" class="regular-text" %s />', | |
| 4027 | - esc_attr($consumer_key), | |
| 4028 | - esc_attr($disabled) | |
| 4029 | - ); | |
| 4030 | - | |
| 4031 | - // Description for the input field | |
| 4032 | - echo '<p class="description">' . esc_html__('Enter your WooCommerce consumer key for integration.', 'mxchat') . '</p>'; | |
| 4033 | - | |
| 4034 | - // Pro feature overlay for non-activated users | |
| 4035 | - if (!$this->is_activated) { | |
| 4036 | - echo '<div class="pro-feature-overlay">'; | |
| 4037 | - echo '<a href="https://mxchat.ai/" target="_blank"><img src="' . plugin_dir_url(__FILE__) . '../images/pro-only-dark.png" alt="' . esc_attr__('Pro Only', 'mxchat') . '" /></a>'; | |
| 4038 | - echo '</div>'; | |
| 4039 | - } | |
| 4040 | - | |
| 4493 | +// Voyage API Key | |
| 4494 | +public function voyage_api_key_callback() { | |
| 4495 | + $apiKey = isset($this->options['voyage_api_key']) ? esc_attr($this->options['voyage_api_key']) : ''; | |
| 4496 | + | |
| 4497 | + echo '<div class="api-key-wrapper" data-provider="voyage">'; | |
| 4498 | + echo '<input type="password" id="voyage_api_key" name="voyage_api_key" value="' . $apiKey . '" class="regular-text" />'; | |
| 4499 | + echo '<button type="button" id="toggleVoyageAPIKeyVisibility">' . esc_html__('Show', 'mxchat') . '</button>'; | |
| 4500 | + echo '<p class="description api-key-notice">' . esc_html__('Required for your selected embedding model. Important: You must add credits before use.', 'mxchat') . '</p>'; | |
| 4041 | 4501 | echo '</div>'; |
| 4042 | 4502 | } |
| 4043 | 4503 | |
| 4044 | -public function mxchat_woocommerce_consumer_secret_callback() { | |
| 4045 | - // Get value with fallback | |
| 4046 | - $consumer_secret = isset($this->options['woocommerce_consumer_secret']) | |
| 4047 | - ? esc_attr($this->options['woocommerce_consumer_secret']) | |
| 4048 | - : ''; | |
| 4049 | 4504 | |
| 4050 | - // Check if the feature is activated (paid feature) | |
| 4051 | - $disabled = $this->is_activated ? '' : 'disabled'; | |
| 4052 | - $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive'; | |
| 4053 | 4505 | |
| 4054 | - echo '<div class="' . esc_attr($class) . '">'; | |
| 4055 | 4506 | |
| 4056 | - // Output the password input | |
| 4057 | - echo sprintf( | |
| 4058 | - '<input type="password" | |
| 4059 | - id="woocommerce_consumer_secret" | |
| 4060 | - name="woocommerce_consumer_secret" | |
| 4061 | - value="%s" | |
| 4062 | - class="regular-text" | |
| 4063 | - %s />', | |
| 4064 | - $consumer_secret, | |
| 4065 | - esc_attr($disabled) | |
| 4066 | - ); | |
| 4067 | 4507 | |
| 4068 | - // Add show/hide button | |
| 4069 | - echo '<button type="button" id="toggleWooCommerceSecretVisibility">' . esc_html__('Show', 'mxchat') . '</button>'; | |
| 4070 | - | |
| 4071 | - // Pro feature overlay | |
| 4072 | - if (!$this->is_activated) { | |
| 4073 | - echo '<div class="pro-feature-overlay">'; | |
| 4074 | - echo '<a href="https://mxchat.ai/" target="_blank">'; | |
| 4075 | - echo '<img src="' . esc_url(plugin_dir_url(__FILE__) . '../images/pro-only-dark.png') . '" alt="' . esc_attr__('Pro Only', 'mxchat') . '" />'; | |
| 4076 | - echo '</a>'; | |
| 4077 | - echo '</div>'; | |
| 4078 | - } | |
| 4079 | - | |
| 4080 | - echo '</div>'; | |
| 4081 | -} | |
| 4082 | 4508 | public function mxchat_loops_api_key_callback() { |
| 4083 | 4509 | // Support both old and new format |
| 4084 | 4510 | $loops_api_key = isset($this->options['loops_api_key']) ? esc_attr($this->options['loops_api_key']) : ''; |
| 4085 | 4511 | |
| @@ -4089,9 +4515,9 @@ | ||
| 4089 | 4515 | $loops_api_key |
| 4090 | 4516 | ); |
| 4091 | 4517 | echo '<button type="button" id="toggleLoopsApiKeyVisibility">' . esc_html__('Show', 'mxchat') . '</button>'; |
| 4092 | 4518 | echo '</div>'; |
| 4093 | - echo '<p class="description">' . esc_html__('Enter your Loops API Key here. (See FAQ for details)', 'mxchat') . '</p>'; | |
| 4519 | + echo '<p class="description">' . esc_html__('Enter your Loops API Key here. Once entered, refreshed page to load list (See FAQ for details)', 'mxchat') . '</p>'; | |
| 4094 | 4520 | } |
| 4095 | 4521 | |
| 4096 | 4522 | public function mxchat_loops_mailing_list_callback() { |
| 4097 | 4523 | // Add error handling and type checking |
| @@ -4200,9 +4626,10 @@ | ||
| 4200 | 4626 | esc_html__('DeepSeek Models', 'mxchat') => array( |
| 4201 | 4627 | 'deepseek-chat' => esc_html__('DeepSeek-V3', 'mxchat'), |
| 4202 | 4628 | ), |
| 4203 | 4629 | esc_html__('Claude Models', 'mxchat') => array( |
| 4204 | - 'claude-3-5-sonnet-20241022' => esc_html__('Claude 3.5 Sonnet (Most Intelligent)', 'mxchat'), | |
| 4630 | + 'claude-3-7-sonnet-20250219' => esc_html__('Claude 3.7 Sonnet (Most Intelligent)', 'mxchat'), | |
| 4631 | + 'claude-3-5-sonnet-20241022' => esc_html__('Claude 3.5 Sonnet (Intelligent)', 'mxchat'), | |
| 4205 | 4632 | 'claude-3-opus-20240229' => esc_html__('Claude 3 Opus (Highly Complex Tasks)', 'mxchat'), |
| 4206 | 4633 | 'claude-3-sonnet-20240229' => esc_html__('Claude 3 Sonnet (Balanced)', 'mxchat'), |
| 4207 | 4634 | 'claude-3-haiku-20240307' => esc_html__('Claude 3 Haiku (Fastest)', 'mxchat') |
| 4208 | 4635 | ), |
| @@ -4213,40 +4640,63 @@ | ||
| 4213 | 4640 | 'gpt-4' => esc_html__('GPT-4 (High Intelligence)', 'mxchat'), |
| 4214 | 4641 | 'gpt-3.5-turbo' => esc_html__('GPT-3.5 Turbo (Affordable and Fast)', 'mxchat') |
| 4215 | 4642 | ) |
| 4216 | 4643 | ); |
| 4217 | - | |
| 4644 | + | |
| 4218 | 4645 | // Retrieve the currently selected model from saved options |
| 4219 | 4646 | $selected_model = isset($this->options['model']) ? esc_attr($this->options['model']) : 'gpt-4o'; |
| 4220 | - | |
| 4647 | + | |
| 4221 | 4648 | // Begin the select dropdown |
| 4222 | - echo '<select id="model" name="model">'; // No array notation in name attribute | |
| 4223 | - | |
| 4649 | + echo '<select id="model" name="model">'; | |
| 4650 | + | |
| 4224 | 4651 | // Iterate over groups of models |
| 4225 | 4652 | foreach ($models as $group_label => $group_models) { |
| 4226 | 4653 | echo '<optgroup label="' . esc_attr($group_label) . '">'; |
| 4227 | - | |
| 4654 | + | |
| 4228 | 4655 | foreach ($group_models as $model_value => $model_label) { |
| 4229 | - // Disable Pro-only models for non-activated users | |
| 4230 | - $disabled = (!$this->is_activated && ($group_label === esc_html__('X.AI Models', 'mxchat') || $group_label === esc_html__('Claude Models', 'mxchat'))) ? 'disabled' : ''; | |
| 4231 | - $label_suffix = (!$this->is_activated && ($group_label === esc_html__('X.AI Models', 'mxchat') || $group_label === esc_html__('Claude Models', 'mxchat'))) ? esc_html__(' (Pro Only)', 'mxchat') : ''; | |
| 4232 | - | |
| 4233 | - // Output the option element | |
| 4234 | - echo '<option value="' . esc_attr($model_value) . '" ' . selected($selected_model, $model_value, false) . ' ' . $disabled . '>' . esc_html($model_label . $label_suffix) . '</option>'; | |
| 4656 | + // All models enabled - no disabled attribute or Pro Only label | |
| 4657 | + echo '<option value="' . esc_attr($model_value) . '" ' . selected($selected_model, $model_value, false) . '>' . esc_html($model_label) . '</option>'; | |
| 4235 | 4658 | } |
| 4236 | - | |
| 4659 | + | |
| 4237 | 4660 | echo '</optgroup>'; |
| 4238 | 4661 | } |
| 4239 | - | |
| 4662 | + | |
| 4240 | 4663 | // Close the select dropdown |
| 4241 | 4664 | echo '</select>'; |
| 4665 | + | |
| 4666 | + // Updated description to remove mention of Pro-only models | |
| 4667 | + echo '<p class="description">' . esc_html__('Select the AI model your chatbot will use for chatting.', 'mxchat') . '</p>'; | |
| 4668 | +} | |
| 4242 | 4669 | |
| 4243 | - // Add a description below the dropdown | |
| 4244 | - echo '<p class="description">' . esc_html__('Select the AI model to use for your chatbot. Pro-only models are marked accordingly.', 'mxchat') . '</p>'; | |
| 4670 | +// Callback function for embedding model selection | |
| 4671 | +public function embedding_model_callback() { | |
| 4672 | + $models = array( | |
| 4673 | + esc_html__('OpenAI Embeddings', 'mxchat') => array( | |
| 4674 | + 'text-embedding-3-small' => esc_html__('TE3 Small (1536, Efficient)', 'mxchat'), | |
| 4675 | + 'text-embedding-ada-002' => esc_html__('Ada 2 (1536, Recommended)', 'mxchat'), | |
| 4676 | + 'text-embedding-3-large' => esc_html__('TE3 Large (3072, Powerful)', 'mxchat'), | |
| 4677 | + ), | |
| 4678 | + esc_html__('Voyage AI Embeddings', 'mxchat') => array( | |
| 4679 | + 'voyage-3-large' => esc_html__('Voyage-3 Large (2048, Most Capable)', 'mxchat'), | |
| 4680 | + ) | |
| 4681 | + ); | |
| 4682 | + | |
| 4683 | + $selected_model = isset($this->options['embedding_model']) ? esc_attr($this->options['embedding_model']) : 'text-embedding-ada-002'; | |
| 4684 | + | |
| 4685 | + echo '<select id="embedding_model" name="embedding_model">'; | |
| 4686 | + foreach ($models as $group_label => $group_models) { | |
| 4687 | + echo '<optgroup label="' . esc_attr($group_label) . '">'; | |
| 4688 | + foreach ($group_models as $model_value => $model_label) { | |
| 4689 | + echo '<option value="' . esc_attr($model_value) . '" ' . selected($selected_model, $model_value, false) . '>' . esc_html($model_label) . '</option>'; | |
| 4690 | + } | |
| 4691 | + echo '</optgroup>'; | |
| 4692 | + } | |
| 4693 | + echo '</select>'; | |
| 4694 | +echo '<p class="description"><span class="red-warning">IMPORTANT:</span> Select the model for vector embeddings. Changing models is not recommended; if you do, you must delete all existing knowledge & intent data and reconfigure them.</p>'; | |
| 4695 | + | |
| 4245 | 4696 | } |
| 4246 | 4697 | |
| 4247 | 4698 | |
| 4248 | - | |
| 4249 | 4699 | public function mxchat_top_bar_title_callback() { |
| 4250 | 4700 | // Retrieve the current value of the top bar title from saved options |
| 4251 | 4701 | $top_bar_title = isset($this->options['top_bar_title']) ? esc_attr($this->options['top_bar_title']) : ''; |
| 4252 | 4702 | |
| @@ -4909,13 +5359,13 @@ | ||
| 4909 | 5359 | // Render the input field |
| 4910 | 5360 | printf( |
| 4911 | 5361 | '<input type="text" id="popular_question_1" name="popular_question_1" value="%s" placeholder="%s" class="regular-text" />', |
| 4912 | 5362 | esc_attr($popular_question_1), |
| 4913 | - esc_attr__('Enter Popular Question 1', 'mxchat') | |
| 5363 | + esc_attr__('Enter Quick Question 1', 'mxchat') | |
| 4914 | 5364 | ); |
| 4915 | 5365 | |
| 4916 | 5366 | // Add a description for the field |
| 4917 | - echo '<p class="description">' . esc_html__('This will be the first popular question in the chatbot.', 'mxchat') . '</p>'; | |
| 5367 | + echo '<p class="description">' . esc_html__('This will be the first Quick Question in the chatbot, displayed above the input field.', 'mxchat') . '</p>'; | |
| 4918 | 5368 | } |
| 4919 | 5369 | |
| 4920 | 5370 | |
| 4921 | 5371 | public function mxchat_popular_question_2_callback() { |
| @@ -4928,13 +5378,13 @@ | ||
| 4928 | 5378 | // Render the input field |
| 4929 | 5379 | printf( |
| 4930 | 5380 | '<input type="text" id="popular_question_2" name="popular_question_2" value="%s" placeholder="%s" class="regular-text" />', |
| 4931 | 5381 | esc_attr($popular_question_2), |
| 4932 | - esc_attr__('Enter Popular Question 2', 'mxchat') | |
| 5382 | + esc_attr__('Enter Quick Question 2', 'mxchat') | |
| 4933 | 5383 | ); |
| 4934 | 5384 | |
| 4935 | 5385 | // Add a description for the field |
| 4936 | - echo '<p class="description">' . esc_html__('This will be the second popular question in the chatbot.', 'mxchat') . '</p>'; | |
| 5386 | + echo '<p class="description">' . esc_html__('This will be the second Quick Question in the chatbot.', 'mxchat') . '</p>'; | |
| 4937 | 5387 | } |
| 4938 | 5388 | |
| 4939 | 5389 | |
| 4940 | 5390 | public function mxchat_popular_question_3_callback() { |
| @@ -4947,13 +5397,13 @@ | ||
| 4947 | 5397 | // Render the input field |
| 4948 | 5398 | printf( |
| 4949 | 5399 | '<input type="text" id="popular_question_3" name="popular_question_3" value="%s" placeholder="%s" class="regular-text" />', |
| 4950 | 5400 | esc_attr($popular_question_3), |
| 4951 | - esc_attr(__('Enter Popular Question 3', 'mxchat')) | |
| 5401 | + esc_attr(__('Enter Quick Question 3', 'mxchat')) | |
| 4952 | 5402 | ); |
| 4953 | 5403 | |
| 4954 | 5404 | // Add a description for the field |
| 4955 | - echo '<p class="description">' . esc_html__('This will be the third popular question in the chatbot.', 'mxchat') . '</p>'; | |
| 5405 | + echo '<p class="description">' . esc_html__('This will be the third Quick Question in the chatbot.', 'mxchat') . '</p>'; | |
| 4956 | 5406 | } |
| 4957 | 5407 | |
| 4958 | 5408 | public function mxchat_additional_popular_questions_callback() { |
| 4959 | 5409 | $options = get_option('mxchat_options', []); |
| @@ -4974,9 +5424,9 @@ | ||
| 4974 | 5424 | <button type="button" class="button mxchat-remove-question" |
| 4975 | 5425 | aria-label="%s">%s</button> |
| 4976 | 5426 | </div>', |
| 4977 | 5427 | esc_attr($question), |
| 4978 | - esc_attr(sprintf(__('Enter Additional Popular Question %d', 'mxchat'), $index + 4)), | |
| 5428 | + esc_attr(sprintf(__('Enter Additional Quick Question %d', 'mxchat'), $index + 4)), | |
| 4979 | 5429 | $index, |
| 4980 | 5430 | esc_attr(__('Remove question', 'mxchat')), |
| 4981 | 5431 | esc_html__('Remove', 'mxchat') |
| 4982 | 5432 | ); |
| @@ -4991,9 +5441,9 @@ | ||
| 4991 | 5441 | data-question-index="0" /> |
| 4992 | 5442 | <button type="button" class="button mxchat-remove-question" |
| 4993 | 5443 | aria-label="%s">%s</button> |
| 4994 | 5444 | </div>', |
| 4995 | - esc_attr(__('Enter Additional Popular Question 4', 'mxchat')), | |
| 5445 | + esc_attr(__('Enter Additional Quick Question 4', 'mxchat')), | |
| 4996 | 5446 | esc_attr(__('Remove question', 'mxchat')), |
| 4997 | 5447 | esc_html__('Remove', 'mxchat') |
| 4998 | 5448 | ); |
| 4999 | 5449 | } |
| @@ -5002,9 +5452,9 @@ | ||
| 5002 | 5452 | '<button type="button" class="button mxchat-add-question" aria-label="%s">%s</button>', |
| 5003 | 5453 | esc_attr(__('Add question', 'mxchat')), |
| 5004 | 5454 | esc_html__('Add Question', 'mxchat') |
| 5005 | 5455 | ); |
| 5006 | - echo '<p class="description">' . esc_html__('Add as many popular questions as you need.', 'mxchat') . '</p>'; | |
| 5456 | + echo '<p class="description">' . esc_html__('Add as many Quick Questions as you need.', 'mxchat') . '</p>'; | |
| 5007 | 5457 | echo '</div>'; |
| 5008 | 5458 | } |
| 5009 | 5459 | |
| 5010 | 5460 | public function mxchat_brave_api_key_callback() { |
| @@ -5136,9 +5586,78 @@ | ||
| 5136 | 5586 | echo '</div>'; |
| 5137 | 5587 | echo '<p class="description">' . esc_html__('Enable to display the chat toolbar, adding two icons below the chatbot input field for uploading PDF and Word documents (default is hidden).', 'mxchat') . '</p>'; |
| 5138 | 5588 | } |
| 5139 | 5589 | |
| 5590 | +/** | |
| 5591 | + * Callback for PDF upload button toggle setting | |
| 5592 | + */ | |
| 5593 | +public function mxchat_show_pdf_upload_button_callback() { | |
| 5594 | + // Get toggle value with fallback | |
| 5595 | + $show_pdf_button = isset($this->options['show_pdf_upload_button']) ? $this->options['show_pdf_upload_button'] : 'on'; | |
| 5596 | + $checked = ($show_pdf_button === 'on') ? 'checked' : ''; | |
| 5597 | + // Check if the plugin is activated (paid feature) | |
| 5598 | + $disabled = $this->is_activated ? '' : 'disabled'; | |
| 5599 | + $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive'; | |
| 5600 | + | |
| 5601 | + echo '<div class="' . esc_attr($class) . '">'; | |
| 5602 | + // Output the toggle switch | |
| 5603 | + echo '<label class="toggle-switch">'; | |
| 5604 | + echo sprintf( | |
| 5605 | + '<input type="checkbox" id="show_pdf_upload_button" name="show_pdf_upload_button" value="on" %s %s />', | |
| 5606 | + esc_attr($checked), | |
| 5607 | + esc_attr($disabled) | |
| 5608 | + ); | |
| 5609 | + echo '<span class="slider"></span>'; | |
| 5610 | + echo '</label>'; | |
| 5611 | + | |
| 5612 | + // Pro feature overlay if needed | |
| 5613 | + if (!$this->is_activated) { | |
| 5614 | + echo '<div class="pro-feature-overlay">'; | |
| 5615 | + echo '<a href="https://mxchat.ai/" target="_blank">'; | |
| 5616 | + echo '<img src="' . esc_url(plugin_dir_url(__FILE__) . '../images/pro-only-dark.png') . '" alt="' . esc_attr__('Pro Only', 'mxchat') . '" />'; | |
| 5617 | + echo '</a>'; | |
| 5618 | + echo '</div>'; | |
| 5619 | + } | |
| 5620 | + | |
| 5621 | + echo '</div>'; | |
| 5622 | + echo '<p class="description">' . esc_html__('Enable to show the PDF upload button in the chatbot toolbar. Disable to hide it.', 'mxchat') . '</p>'; | |
| 5623 | +} | |
| 5140 | 5624 | |
| 5625 | +/** | |
| 5626 | + * Callback for Word upload button toggle setting | |
| 5627 | + */ | |
| 5628 | +public function mxchat_show_word_upload_button_callback() { | |
| 5629 | + // Get toggle value with fallback | |
| 5630 | + $show_word_button = isset($this->options['show_word_upload_button']) ? $this->options['show_word_upload_button'] : 'on'; | |
| 5631 | + $checked = ($show_word_button === 'on') ? 'checked' : ''; | |
| 5632 | + // Check if the plugin is activated (paid feature) | |
| 5633 | + $disabled = $this->is_activated ? '' : 'disabled'; | |
| 5634 | + $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive'; | |
| 5635 | + | |
| 5636 | + echo '<div class="' . esc_attr($class) . '">'; | |
| 5637 | + // Output the toggle switch | |
| 5638 | + echo '<label class="toggle-switch">'; | |
| 5639 | + echo sprintf( | |
| 5640 | + '<input type="checkbox" id="show_word_upload_button" name="show_word_upload_button" value="on" %s %s />', | |
| 5641 | + esc_attr($checked), | |
| 5642 | + esc_attr($disabled) | |
| 5643 | + ); | |
| 5644 | + echo '<span class="slider"></span>'; | |
| 5645 | + echo '</label>'; | |
| 5646 | + | |
| 5647 | + // Pro feature overlay if needed | |
| 5648 | + if (!$this->is_activated) { | |
| 5649 | + echo '<div class="pro-feature-overlay">'; | |
| 5650 | + echo '<a href="https://mxchat.ai/" target="_blank">'; | |
| 5651 | + echo '<img src="' . esc_url(plugin_dir_url(__FILE__) . '../images/pro-only-dark.png') . '" alt="' . esc_attr__('Pro Only', 'mxchat') . '" />'; | |
| 5652 | + echo '</a>'; | |
| 5653 | + echo '</div>'; | |
| 5654 | + } | |
| 5655 | + | |
| 5656 | + echo '</div>'; | |
| 5657 | + echo '<p class="description">' . esc_html__('Enable to show the Word document upload button in the chatbot toolbar. Disable to hide it.', 'mxchat') . '</p>'; | |
| 5658 | +} | |
| 5659 | + | |
| 5141 | 5660 | public function mxchat_pdf_intent_trigger_text_callback() { |
| 5142 | 5661 | $disabled = $this->is_activated ? '' : 'disabled'; |
| 5143 | 5662 | $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive'; |
| 5144 | 5663 | $default_text = __("Please provide the URL to the PDF you'd like to discuss.", 'mxchat'); |
| @@ -5359,24 +5878,21 @@ | ||
| 5359 | 5878 | } |
| 5360 | 5879 | echo '</div>'; |
| 5361 | 5880 | } |
| 5362 | 5881 | |
| 5363 | - | |
| 5364 | 5882 | public function mxchat_similarity_threshold_callback() { |
| 5365 | 5883 | // Load from mxchat_options array |
| 5366 | 5884 | $options = get_option('mxchat_options', []); |
| 5367 | - | |
| 5368 | - // Get value with backwards compatibility | |
| 5369 | - $threshold = isset($options['similarity_threshold']) | |
| 5370 | - ? $options['similarity_threshold'] | |
| 5371 | - : get_option('mxchat_similarity_threshold', 80); | |
| 5372 | - | |
| 5885 | + | |
| 5886 | + // Get value from options array with default of 80 | |
| 5887 | + $threshold = isset($options['similarity_threshold']) ? $options['similarity_threshold'] : 35; | |
| 5888 | + | |
| 5373 | 5889 | echo '<div class="slider-container">'; |
| 5374 | 5890 | echo sprintf( |
| 5375 | 5891 | '<input type="range" |
| 5376 | 5892 | id="similarity_threshold" |
| 5377 | 5893 | name="similarity_threshold" |
| 5378 | - min="70" | |
| 5894 | + min="20" | |
| 5379 | 5895 | max="85" |
| 5380 | 5896 | step="1" |
| 5381 | 5897 | value="%s" |
| 5382 | 5898 | class="range-slider" />', |
| @@ -5386,16 +5902,14 @@ | ||
| 5386 | 5902 | '<span id="threshold_value" class="range-value">%s</span>', |
| 5387 | 5903 | esc_html($threshold) |
| 5388 | 5904 | ); |
| 5389 | 5905 | echo '</div>'; |
| 5390 | - | |
| 5391 | 5906 | echo '<p class="description">'; |
| 5392 | - echo esc_html__('Set the similarity threshold (recommended: 75) to balance accuracy; too high might limit your bot\'s ability to find relevant knowledge.', 'mxchat'); | |
| 5907 | + echo esc_html__('Set the similarity threshold to balance accuracy; too high might limit your bot\'s ability to find relevant knowledge. If your bot is not matching content, move to lowest setting to test.', 'mxchat'); | |
| 5393 | 5908 | echo '</p>'; |
| 5394 | 5909 | } |
| 5395 | 5910 | |
| 5396 | 5911 | |
| 5397 | - | |
| 5398 | 5912 | public function mxchat_live_agent_secret_key_callback() { |
| 5399 | 5913 | $disabled = $this->is_activated ? '' : 'disabled'; |
| 5400 | 5914 | $class = $this->is_activated ? 'pro-feature-wrapper active' : 'pro-feature-wrapper inactive'; |
| 5401 | 5915 | |
| @@ -5440,9 +5954,9 @@ | ||
| 5440 | 5954 | public function mxchat_enqueue_admin_assets() { |
| 5441 | 5955 | wp_enqueue_style('wp-color-picker'); |
| 5442 | 5956 | |
| 5443 | 5957 | // Get the plugin version or file modification time for cache busting |
| 5444 | - $plugin_version = '2.0.3'; // Replace this with your plugin's version | |
| 5958 | + $plugin_version = '2.1.1'; // Replace this with your plugin's version | |
| 5445 | 5959 | |
| 5446 | 5960 | // File paths |
| 5447 | 5961 | $color_picker_js_path = plugin_dir_path(__FILE__) . '../js/my-color-picker.js'; |
| 5448 | 5962 | $embedding_check_js_path = plugin_dir_path(__FILE__) . '../js/embedding-check.js'; |
| @@ -5448,10 +5962,12 @@ | ||
| 5448 | 5962 | $embedding_check_js_path = plugin_dir_path(__FILE__) . '../js/embedding-check.js'; |
| 5449 | 5963 | $admin_css_path = plugin_dir_path(__FILE__) . '../css/admin-style.css'; |
| 5450 | 5964 | $knowledge_css_path = plugin_dir_path(__FILE__) . '../css/knowledge-style.css'; |
| 5451 | 5965 | $intent_css_path = plugin_dir_path(__FILE__) . '../css/intent-style.css'; |
| 5966 | + $transcripts_css_path = plugin_dir_path(__FILE__) . '../css/chat-transcripts.css'; | |
| 5452 | 5967 | $transcripts_js_path = plugin_dir_path(__FILE__) . '../js/mxchat_transcripts.js'; |
| 5453 | 5968 | |
| 5969 | + | |
| 5454 | 5970 | // Check if files exist and get modification times |
| 5455 | 5971 | $color_picker_version = file_exists($color_picker_js_path) ? filemtime($color_picker_js_path) : $plugin_version; |
| 5456 | 5972 | $embedding_check_version = file_exists($embedding_check_js_path) ? filemtime($embedding_check_js_path) : $plugin_version; |
| 5457 | 5973 | $admin_css_version = file_exists($admin_css_path) ? filemtime($admin_css_path) : $plugin_version; |
| @@ -5456,10 +5972,36 @@ | ||
| 5456 | 5972 | $embedding_check_version = file_exists($embedding_check_js_path) ? filemtime($embedding_check_js_path) : $plugin_version; |
| 5457 | 5973 | $admin_css_version = file_exists($admin_css_path) ? filemtime($admin_css_path) : $plugin_version; |
| 5458 | 5974 | $knowledge_css_version = file_exists($knowledge_css_path) ? filemtime($knowledge_css_path) : $plugin_version; |
| 5459 | 5975 | $intent_css_version = file_exists($intent_css_path) ? filemtime($intent_css_path) : $plugin_version; |
| 5976 | + $transcripts_css_version = file_exists($transcripts_css_path) ? filemtime($transcripts_css_path) : $plugin_version; | |
| 5460 | 5977 | $transcripts_js_version = file_exists($transcripts_js_path) ? filemtime($transcripts_js_path) : $plugin_version; |
| 5461 | - | |
| 5978 | + | |
| 5979 | + $admin_status_js_path = plugin_dir_path(__FILE__) . '../js/admin-status.js'; | |
| 5980 | + $admin_status_js_version = file_exists($admin_status_js_path) ? filemtime($admin_status_js_path) : $plugin_version; | |
| 5981 | + | |
| 5982 | + | |
| 5983 | + // Only enqueue on the prompts page | |
| 5984 | + if (isset($_GET['page']) && $_GET['page'] === 'mxchat-prompts') { | |
| 5985 | + wp_enqueue_script( | |
| 5986 | + 'mxchat-status-updater', | |
| 5987 | + plugin_dir_url(__FILE__) . '../js/admin-status.js', | |
| 5988 | + array('jquery'), | |
| 5989 | + $admin_status_js_version, | |
| 5990 | + true | |
| 5991 | + ); | |
| 5992 | + | |
| 5993 | + // Add the nonce for the status updater | |
| 5994 | + wp_localize_script( | |
| 5995 | + 'mxchat-status-updater', | |
| 5996 | + 'mxchat_status_data', | |
| 5997 | + array( | |
| 5998 | + 'ajax_url' => admin_url('admin-ajax.php'), | |
| 5999 | + 'nonce' => wp_create_nonce('mxchat_status_nonce') | |
| 6000 | + ) | |
| 6001 | + ); | |
| 6002 | + } | |
| 6003 | + | |
| 5462 | 6004 | // Enqueue scripts and styles with corrected paths |
| 5463 | 6005 | wp_enqueue_script( |
| 5464 | 6006 | 'mxchat-color-picker', |
| 5465 | 6007 | plugin_dir_url(__FILE__) . '../js/my-color-picker.js', |
| @@ -5476,16 +6018,8 @@ | ||
| 5476 | 6018 | true |
| 5477 | 6019 | ); |
| 5478 | 6020 | |
| 5479 | 6021 | wp_enqueue_script( |
| 5480 | - 'mxchat-transcripts-js', | |
| 5481 | - plugin_dir_url(__FILE__) . '../js/mxchat_transcripts.js', | |
| 5482 | - array('jquery'), | |
| 5483 | - $transcripts_js_version, | |
| 5484 | - true | |
| 5485 | - ); | |
| 5486 | - | |
| 5487 | - wp_enqueue_script( | |
| 5488 | 6022 | 'mxchat-admin-js', |
| 5489 | 6023 | plugin_dir_url(__FILE__) . '../js/mxchat-admin.js', |
| 5490 | 6024 | array('jquery'), |
| 5491 | 6025 | $plugin_version, |
| @@ -5496,8 +6030,9 @@ | ||
| 5496 | 6030 | 'ajax_url' => admin_url('admin-ajax.php'), |
| 5497 | 6031 | 'license_nonce' => wp_create_nonce('mxchat_activate_license_nonce'), |
| 5498 | 6032 | 'inline_edit_nonce' => wp_create_nonce('mxchat_save_inline_nonce'), |
| 5499 | 6033 | 'setting_nonce' => wp_create_nonce('mxchat_save_setting_nonce'), |
| 6034 | + 'export_nonce' => wp_create_nonce('mxchat_export_transcripts'), | |
| 5500 | 6035 | )); |
| 5501 | 6036 | |
| 5502 | 6037 | // Enqueue the admin CSS |
| 5503 | 6038 | wp_enqueue_style( |
| @@ -5505,9 +6040,26 @@ | ||
| 5505 | 6040 | plugin_dir_url(__FILE__) . '../css/admin-style.css', |
| 5506 | 6041 | array(), |
| 5507 | 6042 | $admin_css_version |
| 5508 | 6043 | ); |
| 5509 | - | |
| 6044 | + | |
| 6045 | + if (isset($_GET['page']) && $_GET['page'] === 'mxchat-transcripts') { | |
| 6046 | + wp_enqueue_style( | |
| 6047 | + 'mxchat-chat-transcripts-css', | |
| 6048 | + plugin_dir_url(__FILE__) . '../css/chat-transcripts.css', | |
| 6049 | + array(), | |
| 6050 | + $transcripts_css_version | |
| 6051 | + ); | |
| 6052 | + | |
| 6053 | + wp_enqueue_script( | |
| 6054 | + 'mxchat-transcripts-js', | |
| 6055 | + plugin_dir_url(__FILE__) . '../js/mxchat_transcripts.js', | |
| 6056 | + array('jquery'), | |
| 6057 | + $transcripts_js_version, | |
| 6058 | + true | |
| 6059 | + ); | |
| 6060 | + } | |
| 6061 | + | |
| 5510 | 6062 | wp_enqueue_style( |
| 5511 | 6063 | 'mxchat-knowledge-css', |
| 5512 | 6064 | plugin_dir_url(__FILE__) . '../css/knowledge-style.css', |
| 5513 | 6065 | array(), |
| @@ -5557,8 +6109,10 @@ | ||
| 5557 | 6109 | 'live_agent_bot_token' => $this->options['live_agent_bot_token'] ?? '', |
| 5558 | 6110 | 'live_agent_message_bg_color' => $this->options['live_agent_message_bg_color'] ?? '#ffffff', |
| 5559 | 6111 | 'live_agent_message_font_color' => $this->options['live_agent_message_font_color'] ?? '#333333', |
| 5560 | 6112 | 'chat_toolbar_toggle' => $this->options['chat_toolbar_toggle'] ?? 'off', |
| 6113 | + 'show_pdf_upload_button' => $this->options['show_pdf_upload_button'] ?? 'on', // Add this line | |
| 6114 | + 'show_word_upload_button' => $this->options['show_word_upload_button'] ?? 'on', // Add this line | |
| 5561 | 6115 | 'mode_indicator_bg_color' => $this->options['mode_indicator_bg_color'] ?? '#767676', |
| 5562 | 6116 | 'mode_indicator_font_color' => $this->options['mode_indicator_font_color'] ?? '#ffffff', |
| 5563 | 6117 | 'toolbar_icon_color' => $this->options['toolbar_icon_color'] ?? '#212121', |
| 5564 | 6118 | )); |
| @@ -5573,9 +6127,9 @@ | ||
| 5573 | 6127 | } |
| 5574 | 6128 | |
| 5575 | 6129 | if (isset($input['similarity_threshold'])) { |
| 5576 | 6130 | $new_input['similarity_threshold'] = absint($input['similarity_threshold']); // Ensure it's an integer |
| 5577 | - $new_input['similarity_threshold'] = min(max($new_input['similarity_threshold'], 70), 85); // Enforce range | |
| 6131 | + $new_input['similarity_threshold'] = min(max($new_input['similarity_threshold'], 20), 85); // Enforce range | |
| 5578 | 6132 | } |
| 5579 | 6133 | |
| 5580 | 6134 | if (isset($input['xai_api_key'])) { |
| 5581 | 6135 | $new_input['xai_api_key'] = sanitize_text_field($input['xai_api_key']); |
| @@ -5679,8 +6233,25 @@ | ||
| 5679 | 6233 | |
| 5680 | 6234 | if (isset($input['pre_chat_message'])) { |
| 5681 | 6235 | $new_input['pre_chat_message'] = sanitize_textarea_field($input['pre_chat_message']); |
| 5682 | 6236 | } |
| 6237 | + | |
| 6238 | + if (isset($input['voyage_api_key'])) { | |
| 6239 | + $new_input['voyage_api_key'] = sanitize_text_field($input['voyage_api_key']); | |
| 6240 | + } | |
| 6241 | + | |
| 6242 | + // Add to your sanitize function | |
| 6243 | + if (isset($input['embedding_model'])) { | |
| 6244 | + $allowed_models = array( | |
| 6245 | + 'text-embedding-ada-002', | |
| 6246 | + 'text-embedding-3-small', | |
| 6247 | + 'text-embedding-3-large', | |
| 6248 | + 'voyage-3-large' | |
| 6249 | + ); | |
| 6250 | + if (in_array($input['embedding_model'], $allowed_models)) { | |
| 6251 | + $new_input['embedding_model'] = sanitize_text_field($input['embedding_model']); | |
| 6252 | + } | |
| 6253 | + } | |
| 5683 | 6254 | |
| 5684 | 6255 | if (isset($input['model'])) { |
| 5685 | 6256 | $allowed_models = array( |
| 5686 | 6257 | 'grok-beta', |
| @@ -5685,8 +6256,9 @@ | ||
| 5685 | 6256 | $allowed_models = array( |
| 5686 | 6257 | 'grok-beta', |
| 5687 | 6258 | 'grok-2', |
| 5688 | 6259 | 'deepseek-chat', |
| 6260 | + 'claude-3-7-sonnet-20250219', | |
| 5689 | 6261 | 'claude-3-5-sonnet-20241022', |
| 5690 | 6262 | 'claude-3-opus-20240229', |
| 5691 | 6263 | 'claude-3-sonnet-20240229', |
| 5692 | 6264 | 'claude-3-haiku-20240307', |
| @@ -5855,8 +6427,22 @@ | ||
| 5855 | 6427 | |
| 5856 | 6428 | if (isset($input['chat_toolbar_toggle'])) { |
| 5857 | 6429 | $new_input['chat_toolbar_toggle'] = $input['chat_toolbar_toggle'] === 'on' ? 'on' : 'off'; |
| 5858 | 6430 | } |
| 6431 | + | |
| 6432 | + // Sanitize PDF upload button toggle | |
| 6433 | + if (isset($input['show_pdf_upload_button'])) { | |
| 6434 | + $new_input['show_pdf_upload_button'] = $input['show_pdf_upload_button'] === 'on' ? 'on' : 'off'; | |
| 6435 | + } else { | |
| 6436 | + $new_input['show_pdf_upload_button'] = 'off'; // If checkbox is unchecked | |
| 6437 | + } | |
| 6438 | + | |
| 6439 | + // Sanitize Word upload button toggle | |
| 6440 | + if (isset($input['show_word_upload_button'])) { | |
| 6441 | + $new_input['show_word_upload_button'] = $input['show_word_upload_button'] === 'on' ? 'on' : 'off'; | |
| 6442 | + } else { | |
| 6443 | + $new_input['show_word_upload_button'] = 'off'; // If checkbox is unchecked | |
| 6444 | + } | |
| 5859 | 6445 | |
| 5860 | 6446 | if (isset($input['pdf_intent_trigger_text'])) { |
| 5861 | 6447 | $new_input['pdf_intent_trigger_text'] = sanitize_text_field($input['pdf_intent_trigger_text']); |
| 5862 | 6448 | } |
| @@ -6011,8 +6597,69 @@ | ||
| 6011 | 6597 | } |
| 6012 | 6598 | } |
| 6013 | 6599 | |
| 6014 | 6600 | |
| 6601 | +/** | |
| 6602 | + * Display admin notices from transients | |
| 6603 | + */ | |
| 6604 | +public function display_admin_notices() { | |
| 6605 | + // Check if we're on the right admin page | |
| 6606 | + $screen = get_current_screen(); | |
| 6607 | + if (!$screen || $screen->base !== 'toplevel_page_mxchat-prompts') { | |
| 6608 | + return; | |
| 6609 | + } | |
| 6610 | + | |
| 6611 | + // Check for error notices | |
| 6612 | + $error_notice = get_transient('mxchat_admin_notice_error'); | |
| 6613 | + if ($error_notice) { | |
| 6614 | + echo '<div class="notice notice-error is-dismissible"><p>' . esc_html($error_notice) . '</p></div>'; | |
| 6615 | + delete_transient('mxchat_admin_notice_error'); | |
| 6616 | + } | |
| 6617 | + | |
| 6618 | + // Check for success notices | |
| 6619 | + $success_notice = get_transient('mxchat_admin_notice_success'); | |
| 6620 | + if ($success_notice) { | |
| 6621 | + echo '<div class="notice notice-success is-dismissible"><p>' . esc_html($success_notice) . '</p></div>'; | |
| 6622 | + delete_transient('mxchat_admin_notice_success'); | |
| 6623 | + } | |
| 6624 | + | |
| 6625 | + // Check for info notices | |
| 6626 | + $info_notice = get_transient('mxchat_admin_notice_info'); | |
| 6627 | + if ($info_notice) { | |
| 6628 | + echo '<div class="notice notice-info is-dismissible"><p>' . esc_html($info_notice) . '</p></div>'; | |
| 6629 | + delete_transient('mxchat_admin_notice_info'); | |
| 6630 | + } | |
| 6631 | + | |
| 6632 | + // Display active processing status | |
| 6633 | + $this->display_processing_status(); | |
| 6634 | +} | |
| 6635 | + | |
| 6636 | +/** | |
| 6637 | + * Display current processing status | |
| 6638 | + */ | |
| 6639 | +private function display_processing_status() { | |
| 6640 | + $pdf_url = get_transient('mxchat_last_pdf_url'); | |
| 6641 | + $sitemap_url = get_transient('mxchat_last_sitemap_url'); | |
| 6642 | + | |
| 6643 | + if (!$pdf_url && !$sitemap_url) { | |
| 6644 | + return; | |
| 6645 | + } | |
| 6646 | + | |
| 6647 | + $pdf_status = $pdf_url ? $this->get_pdf_processing_status($pdf_url) : false; | |
| 6648 | + $sitemap_status = $sitemap_url ? $this->get_sitemap_processing_status($sitemap_url) : false; | |
| 6649 | + | |
| 6650 | + if ($sitemap_status && isset($sitemap_status['error']) && !empty($sitemap_status['error'])) { | |
| 6651 | + echo '<div class="notice notice-error is-dismissible">'; | |
| 6652 | + echo '<p><strong>' . esc_html__('Sitemap Processing Error:', 'mxchat') . '</strong> ' . esc_html($sitemap_status['error']) . '</p>'; | |
| 6653 | + echo '</div>'; | |
| 6654 | + } | |
| 6655 | + | |
| 6656 | + if ($pdf_status && isset($pdf_status['error']) && !empty($pdf_status['error'])) { | |
| 6657 | + echo '<div class="notice notice-error is-dismissible">'; | |
| 6658 | + echo '<p><strong>' . esc_html__('PDF Processing Error:', 'mxchat') . '</strong> ' . esc_html($pdf_status['error']) . '</p>'; | |
| 6659 | + echo '</div>'; | |
| 6660 | + } | |
| 6661 | +} | |
| 6015 | 6662 | |
| 6016 | 6663 | |
| 6017 | 6664 | } |
| 6018 | 6665 | ?> |