Changeset 3379814
- Timestamp:
- 10/17/2025 01:32:41 AM (4 months ago)
- Location:
- mxchat-basic
- Files:
-
- 103 added
- 10 edited
-
tags/2.4.8 (added)
-
tags/2.4.8/admin (added)
-
tags/2.4.8/admin/class-ajax-handler.php (added)
-
tags/2.4.8/admin/class-knowledge-manager.php (added)
-
tags/2.4.8/admin/class-pinecone-manager.php (added)
-
tags/2.4.8/css (added)
-
tags/2.4.8/css/admin-add-ons.css (added)
-
tags/2.4.8/css/admin-style.css (added)
-
tags/2.4.8/css/chat-style.css (added)
-
tags/2.4.8/css/chat-transcripts.css (added)
-
tags/2.4.8/css/content-selector.css (added)
-
tags/2.4.8/css/intent-style.css (added)
-
tags/2.4.8/css/knowledge-style.css (added)
-
tags/2.4.8/css/test-panel.css (added)
-
tags/2.4.8/images (added)
-
tags/2.4.8/images/Icon-01.svg (added)
-
tags/2.4.8/images/Icon-02.svg (added)
-
tags/2.4.8/images/Icon-03.svg (added)
-
tags/2.4.8/images/Icon-04.svg (added)
-
tags/2.4.8/images/pro-only-dark.png (added)
-
tags/2.4.8/includes (added)
-
tags/2.4.8/includes/class-mxchat-addons.php (added)
-
tags/2.4.8/includes/class-mxchat-admin.php (added)
-
tags/2.4.8/includes/class-mxchat-integrator.php (added)
-
tags/2.4.8/includes/class-mxchat-meta-box.php (added)
-
tags/2.4.8/includes/class-mxchat-public.php (added)
-
tags/2.4.8/includes/class-mxchat-user.php (added)
-
tags/2.4.8/includes/class-mxchat-utils.php (added)
-
tags/2.4.8/includes/class-mxchat-woocommerce.php (added)
-
tags/2.4.8/includes/class-mxchat-word-handler.php (added)
-
tags/2.4.8/includes/pdf-parser (added)
-
tags/2.4.8/includes/pdf-parser/alt_autoload.php (added)
-
tags/2.4.8/includes/pdf-parser/src (added)
-
tags/2.4.8/includes/pdf-parser/src/Smalot (added)
-
tags/2.4.8/includes/pdf-parser/src/Smalot/PdfParser (added)
-
tags/2.4.8/includes/pdf-parser/src/Smalot/PdfParser/Config.php (added)
-
tags/2.4.8/includes/pdf-parser/src/Smalot/PdfParser/Document.php (added)
-
tags/2.4.8/includes/pdf-parser/src/Smalot/PdfParser/Element (added)
-
tags/2.4.8/includes/pdf-parser/src/Smalot/PdfParser/Element.php (added)
-
tags/2.4.8/includes/pdf-parser/src/Smalot/PdfParser/Element/ElementArray.php (added)
-
tags/2.4.8/includes/pdf-parser/src/Smalot/PdfParser/Element/ElementBoolean.php (added)
-
tags/2.4.8/includes/pdf-parser/src/Smalot/PdfParser/Element/ElementDate.php (added)
-
tags/2.4.8/includes/pdf-parser/src/Smalot/PdfParser/Element/ElementHexa.php (added)
-
tags/2.4.8/includes/pdf-parser/src/Smalot/PdfParser/Element/ElementMissing.php (added)
-
tags/2.4.8/includes/pdf-parser/src/Smalot/PdfParser/Element/ElementName.php (added)
-
tags/2.4.8/includes/pdf-parser/src/Smalot/PdfParser/Element/ElementNull.php (added)
-
tags/2.4.8/includes/pdf-parser/src/Smalot/PdfParser/Element/ElementNumeric.php (added)
-
tags/2.4.8/includes/pdf-parser/src/Smalot/PdfParser/Element/ElementString.php (added)
-
tags/2.4.8/includes/pdf-parser/src/Smalot/PdfParser/Element/ElementStruct.php (added)
-
tags/2.4.8/includes/pdf-parser/src/Smalot/PdfParser/Element/ElementXRef.php (added)
-
tags/2.4.8/includes/pdf-parser/src/Smalot/PdfParser/Encoding (added)
-
tags/2.4.8/includes/pdf-parser/src/Smalot/PdfParser/Encoding.php (added)
-
tags/2.4.8/includes/pdf-parser/src/Smalot/PdfParser/Encoding/AbstractEncoding.php (added)
-
tags/2.4.8/includes/pdf-parser/src/Smalot/PdfParser/Encoding/EncodingLocator.php (added)
-
tags/2.4.8/includes/pdf-parser/src/Smalot/PdfParser/Encoding/ISOLatin1Encoding.php (added)
-
tags/2.4.8/includes/pdf-parser/src/Smalot/PdfParser/Encoding/ISOLatin9Encoding.php (added)
-
tags/2.4.8/includes/pdf-parser/src/Smalot/PdfParser/Encoding/MacRomanEncoding.php (added)
-
tags/2.4.8/includes/pdf-parser/src/Smalot/PdfParser/Encoding/PDFDocEncoding.php (added)
-
tags/2.4.8/includes/pdf-parser/src/Smalot/PdfParser/Encoding/PostScriptGlyphs.php (added)
-
tags/2.4.8/includes/pdf-parser/src/Smalot/PdfParser/Encoding/StandardEncoding.php (added)
-
tags/2.4.8/includes/pdf-parser/src/Smalot/PdfParser/Encoding/WinAnsiEncoding.php (added)
-
tags/2.4.8/includes/pdf-parser/src/Smalot/PdfParser/Exception (added)
-
tags/2.4.8/includes/pdf-parser/src/Smalot/PdfParser/Exception/EmptyPdfException.php (added)
-
tags/2.4.8/includes/pdf-parser/src/Smalot/PdfParser/Exception/EncodingNotFoundException.php (added)
-
tags/2.4.8/includes/pdf-parser/src/Smalot/PdfParser/Exception/MissingPdfHeaderException.php (added)
-
tags/2.4.8/includes/pdf-parser/src/Smalot/PdfParser/Exception/NotImplementedException.php (added)
-
tags/2.4.8/includes/pdf-parser/src/Smalot/PdfParser/Font (added)
-
tags/2.4.8/includes/pdf-parser/src/Smalot/PdfParser/Font.php (added)
-
tags/2.4.8/includes/pdf-parser/src/Smalot/PdfParser/Font/FontCIDFontType0.php (added)
-
tags/2.4.8/includes/pdf-parser/src/Smalot/PdfParser/Font/FontCIDFontType2.php (added)
-
tags/2.4.8/includes/pdf-parser/src/Smalot/PdfParser/Font/FontTrueType.php (added)
-
tags/2.4.8/includes/pdf-parser/src/Smalot/PdfParser/Font/FontType0.php (added)
-
tags/2.4.8/includes/pdf-parser/src/Smalot/PdfParser/Font/FontType1.php (added)
-
tags/2.4.8/includes/pdf-parser/src/Smalot/PdfParser/Font/FontType3.php (added)
-
tags/2.4.8/includes/pdf-parser/src/Smalot/PdfParser/Header.php (added)
-
tags/2.4.8/includes/pdf-parser/src/Smalot/PdfParser/PDFObject.php (added)
-
tags/2.4.8/includes/pdf-parser/src/Smalot/PdfParser/Page.php (added)
-
tags/2.4.8/includes/pdf-parser/src/Smalot/PdfParser/Pages.php (added)
-
tags/2.4.8/includes/pdf-parser/src/Smalot/PdfParser/Parser.php (added)
-
tags/2.4.8/includes/pdf-parser/src/Smalot/PdfParser/RawData (added)
-
tags/2.4.8/includes/pdf-parser/src/Smalot/PdfParser/RawData/FilterHelper.php (added)
-
tags/2.4.8/includes/pdf-parser/src/Smalot/PdfParser/RawData/RawDataParser.php (added)
-
tags/2.4.8/includes/pdf-parser/src/Smalot/PdfParser/XObject (added)
-
tags/2.4.8/includes/pdf-parser/src/Smalot/PdfParser/XObject/Form.php (added)
-
tags/2.4.8/includes/pdf-parser/src/Smalot/PdfParser/XObject/Image.php (added)
-
tags/2.4.8/js (added)
-
tags/2.4.8/js/activation-script.js (added)
-
tags/2.4.8/js/admin-status.js (added)
-
tags/2.4.8/js/chat-script.js (added)
-
tags/2.4.8/js/content-selector.js (added)
-
tags/2.4.8/js/embedding-check.js (added)
-
tags/2.4.8/js/floating-script.js (added)
-
tags/2.4.8/js/knowledge-processing.js (added)
-
tags/2.4.8/js/meta-box.js (added)
-
tags/2.4.8/js/mxchat-admin.js (added)
-
tags/2.4.8/js/mxchat-test-streaming.js (added)
-
tags/2.4.8/js/mxchat_transcripts.js (added)
-
tags/2.4.8/js/my-color-picker.js (added)
-
tags/2.4.8/js/test-panel.js (added)
-
tags/2.4.8/languages (added)
-
tags/2.4.8/languages/mxchat.pot (added)
-
tags/2.4.8/mxchat-basic.php (added)
-
tags/2.4.8/readme.txt (added)
-
trunk/admin/class-ajax-handler.php (modified) (1 diff)
-
trunk/css/admin-style.css (modified) (1 diff)
-
trunk/includes/class-mxchat-addons.php (modified) (1 diff)
-
trunk/includes/class-mxchat-admin.php (modified) (25 diffs)
-
trunk/includes/class-mxchat-integrator.php (modified) (18 diffs)
-
trunk/js/chat-script.js (modified) (1 diff)
-
trunk/js/mxchat-admin.js (modified) (9 diffs)
-
trunk/js/test-panel.js (modified) (1 diff)
-
trunk/mxchat-basic.php (modified) (2 diffs)
-
trunk/readme.txt (modified) (7 diffs)
Legend:
- Unmodified
- Added
- Removed
-
mxchat-basic/trunk/admin/class-ajax-handler.php
r3367268 r3379814 75 75 // Handle special cases 76 76 switch ($name) { 77 case 'model': 78 //error_log('MXChat Save: Processing model selection'); 79 //error_log('MXChat Save: Model value received: ' . $value); 80 //error_log('MXChat Save: Value type: ' . gettype($value)); 81 //error_log('MXChat Save: Value length: ' . strlen($value)); 82 //error_log('MXChat Save: Value === "openrouter": ' . ($value === 'openrouter' ? 'YES' : 'NO')); 83 84 // Allow 'openrouter' or validate against whitelist 85 if ($value === 'openrouter') { 86 //error_log('MXChat Save: Setting model to openrouter'); 87 $options['model'] = 'openrouter'; 88 } else { 89 //error_log('MXChat Save: Checking against whitelist'); 90 $allowed_models = array( 91 'gemini-2.0-flash', 'gemini-2.0-flash-lite', 'gemini-1.5-pro', 'gemini-1.5-flash', 92 'grok-4-0709', 'grok-3-beta', 'grok-3-fast-beta', 'grok-3-mini-beta', 93 'grok-3-mini-fast-beta', 'grok-2', 94 'deepseek-chat', 95 'claude-sonnet-4-5-20250929', 'claude-opus-4-1-20250805', 'claude-haiku-4-5-20251001', 96 'claude-opus-4-20250514', 'claude-sonnet-4-20250514', 'claude-3-7-sonnet-20250219', 97 'claude-3-5-sonnet-20241022', 'claude-3-opus-20240229', 'claude-3-sonnet-20240229', 98 'claude-3-haiku-20240307', 99 'gpt-5', 'gpt-5-mini', 'gpt-5-nano', 'gpt-4.1-2025-04-14', 100 'gpt-4o', 'gpt-4o-mini', 'gpt-4-turbo', 'gpt-4', 'gpt-3.5-turbo', 101 ); 102 103 //error_log('MXChat Save: in_array result: ' . (in_array($value, $allowed_models) ? 'YES' : 'NO')); 104 105 if (in_array($value, $allowed_models)) { 106 //error_log('MXChat Save: Model is in whitelist, saving'); 107 $options['model'] = sanitize_text_field($value); 108 } else { 109 //error_log('MXChat Save: Invalid model rejected: ' . $value); 110 //error_log('MXChat Save: Allowed models: ' . print_r($allowed_models, true)); 111 wp_send_json_error(['message' => esc_html__('Invalid model selected', 'mxchat')]); 112 return; 113 } 114 } 115 break; 116 117 case 'openrouter_selected_model': 118 //error_log('MXChat Save: Processing OpenRouter model: ' . $value); 119 $options['openrouter_selected_model'] = sanitize_text_field($value); 120 // Force immediate save for new keys 121 //error_log('MXChat Save: OpenRouter model saved immediately'); 122 break; 123 124 case 'openrouter_selected_model_name': 125 //error_log('MXChat Save: Processing OpenRouter model name: ' . $value); 126 $options['openrouter_selected_model_name'] = sanitize_text_field($value); 127 // Force immediate save for new keys 128 //error_log('MXChat Save: OpenRouter model name saved immediately'); 129 break; 130 131 case 'openrouter_api_key': 132 //error_log('MXChat Save: Processing OpenRouter API key'); 133 $options['openrouter_api_key'] = sanitize_text_field($value); 134 break; 135 136 // REMOVED DUPLICATE case 'openrouter_selected_model_name' HERE! 137 77 138 case 'additional_popular_questions': 78 139 //error_log('MXChat Save: Processing additional_popular_questions'); -
mxchat-basic/trunk/css/admin-style.css
r3364278 r3379814 5366 5366 color: #1e40af; 5367 5367 } 5368 5369 5370 /* Always show OpenRouter API key field */ 5371 tr.mxchat-setting-row[data-provider="openrouter"], 5372 .mxchat-openrouter-wrapper { 5373 display: table-row !important; 5374 } -
mxchat-basic/trunk/includes/class-mxchat-addons.php
r3378505 r3379814 191 191 */ 192 192 public function enqueue_styles() { 193 $plugin_version = '2.4. 7';193 $plugin_version = '2.4.8'; 194 194 195 195 wp_enqueue_style( -
mxchat-basic/trunk/includes/class-mxchat-admin.php
r3378505 r3379814 49 49 add_action('wp_ajax_mxchat_test_streaming', [$this, 'mxchat_handle_test_streaming']); // Keep existing as fallback 50 50 51 add_action('wp_ajax_mxchat_save_selected_bot', array($this, 'mxchat_save_selected_bot')); 51 add_action('wp_ajax_mxchat_save_selected_bot', array($this, 'mxchat_save_selected_bot')); 52 add_action('wp_ajax_mxchat_fetch_openrouter_models', array($this, 'fetch_openrouter_models')); 52 53 } 53 54 … … 1575 1576 $pinecone_api_key = $pinecone_options['mxchat_pinecone_api_key'] ?? ''; 1576 1577 1577 error_log('DEBUG: Bot ' . $current_bot_id . ' - Use Pinecone: ' . ($use_pinecone ? 'YES' : 'NO'));1578 error_log('DEBUG: Bot ' . $current_bot_id . ' - Has API Key: ' . (!empty($pinecone_api_key) ? 'YES' : 'NO'));1579 error_log('DEBUG: Bot ' . $current_bot_id . ' - Host: ' . ($pinecone_options['mxchat_pinecone_host'] ?? 'NOT SET'));1580 error_log('DEBUG: Bot ' . $current_bot_id . ' - Namespace: ' . ($pinecone_options['mxchat_pinecone_namespace'] ?? 'NOT SET'));1578 //error_log('DEBUG: Bot ' . $current_bot_id . ' - Use Pinecone: ' . ($use_pinecone ? 'YES' : 'NO')); 1579 //error_log('DEBUG: Bot ' . $current_bot_id . ' - Has API Key: ' . (!empty($pinecone_api_key) ? 'YES' : 'NO')); 1580 //error_log('DEBUG: Bot ' . $current_bot_id . ' - Host: ' . ($pinecone_options['mxchat_pinecone_host'] ?? 'NOT SET')); 1581 //error_log('DEBUG: Bot ' . $current_bot_id . ' - Namespace: ' . ($pinecone_options['mxchat_pinecone_namespace'] ?? 'NOT SET')); 1581 1582 1582 1583 if ($use_pinecone && !empty($pinecone_api_key)) { 1583 error_log('DEBUG: Using PINECONE data source with bot-specific config');1584 //error_log('DEBUG: Using PINECONE data source with bot-specific config'); 1584 1585 // PINECONE DATA SOURCE 1585 1586 $data_source = 'pinecone'; … … 1589 1590 1590 1591 // TEMPORARY DEBUG - Add this right after the fetch call 1591 error_log('=== DEBUG: Bot switching issue ===');1592 error_log('Current bot ID: ' . $current_bot_id);1593 error_log('Use Pinecone: ' . ($use_pinecone ? 'YES' : 'NO'));1594 error_log('Records returned: ' . count($records['data'] ?? []));1595 error_log('Total records: ' . ($records['total'] ?? 0));1592 //error_log('=== DEBUG: Bot switching issue ==='); 1593 //error_log('Current bot ID: ' . $current_bot_id); 1594 //error_log('Use Pinecone: ' . ($use_pinecone ? 'YES' : 'NO')); 1595 //error_log('Records returned: ' . count($records['data'] ?? [])); 1596 //error_log('Total records: ' . ($records['total'] ?? 0)); 1596 1597 1597 1598 // Check first few records to see their bot_id … … 1599 1600 foreach (array_slice($records['data'], 0, 3) as $i => $record) { 1600 1601 $record_bot_id = $record->bot_id ?? 'NOT_SET'; 1601 error_log('Record ' . ($i+1) . ' bot_id: ' . $record_bot_id . ', content preview: ' . substr($record->article_content ?? '', 0, 30) . '...');1602 //error_log('Record ' . ($i+1) . ' bot_id: ' . $record_bot_id . ', content preview: ' . substr($record->article_content ?? '', 0, 30) . '...'); 1602 1603 } 1603 1604 } 1604 error_log('=== END DEBUG ===');1605 //error_log('=== END DEBUG ==='); 1605 1606 1606 1607 $total_records = $records['total'] ?? 0; … … 1612 1613 1613 1614 } else { 1614 error_log('DEBUG: Using WORDPRESS DB data source');1615 //error_log('DEBUG: Using WORDPRESS DB data source'); 1615 1616 // WORDPRESS DB DATA SOURCE (your existing logic) 1616 1617 $data_source = 'wordpress'; … … 2743 2744 */ 2744 2745 private function get_bot_pinecone_config($bot_id = 'default') { 2745 error_log("MXCHAT DEBUG: get_bot_pinecone_config called for bot: " . $bot_id);2746 //error_log("MXCHAT DEBUG: get_bot_pinecone_config called for bot: " . $bot_id); 2746 2747 2747 2748 // If default bot or multi-bot add-on not active, use default Pinecone config 2748 2749 if ($bot_id === 'default' || !class_exists('MxChat_Multi_Bot_Manager')) { 2749 error_log("MXCHAT DEBUG: Using default Pinecone config (no multi-bot or bot is 'default')");2750 //error_log("MXCHAT DEBUG: Using default Pinecone config (no multi-bot or bot is 'default')"); 2750 2751 $addon_options = get_option('mxchat_pinecone_addon_options', array()); 2751 2752 $config = array( … … 2755 2756 'namespace' => $addon_options['mxchat_pinecone_namespace'] ?? '' 2756 2757 ); 2757 error_log("MXCHAT DEBUG: Default config - use_pinecone: " . ($config['use_pinecone'] ? 'true' : 'false'));2758 //error_log("MXCHAT DEBUG: Default config - use_pinecone: " . ($config['use_pinecone'] ? 'true' : 'false')); 2758 2759 return $config; 2759 2760 } 2760 2761 2761 error_log("MXCHAT DEBUG: Calling filter 'mxchat_get_bot_pinecone_config' for bot: " . $bot_id);2762 //error_log("MXCHAT DEBUG: Calling filter 'mxchat_get_bot_pinecone_config' for bot: " . $bot_id); 2762 2763 2763 2764 // Hook for multi-bot add-on to provide bot-specific Pinecone config … … 2765 2766 2766 2767 if (!empty($bot_pinecone_config)) { 2767 error_log("MXCHAT DEBUG: Got bot-specific config from filter");2768 error_log(" - use_pinecone: " . (isset($bot_pinecone_config['use_pinecone']) ? ($bot_pinecone_config['use_pinecone'] ? 'true' : 'false') : 'not set'));2769 error_log(" - host: " . ($bot_pinecone_config['host'] ?? 'not set'));2770 error_log(" - namespace: " . ($bot_pinecone_config['namespace'] ?? 'not set'));2768 //error_log("MXCHAT DEBUG: Got bot-specific config from filter"); 2769 //error_log(" - use_pinecone: " . (isset($bot_pinecone_config['use_pinecone']) ? ($bot_pinecone_config['use_pinecone'] ? 'true' : 'false') : 'not set')); 2770 //error_log(" - host: " . ($bot_pinecone_config['host'] ?? 'not set')); 2771 //error_log(" - namespace: " . ($bot_pinecone_config['namespace'] ?? 'not set')); 2771 2772 } else { 2772 error_log("MXCHAT DEBUG: Filter returned empty config!");2773 //error_log("MXCHAT DEBUG: Filter returned empty config!"); 2773 2774 } 2774 2775 … … 4321 4322 'mxchat_chatbot_section' 4322 4323 ); 4324 4325 4326 add_settings_field( 4327 'openrouter_api_key', 4328 esc_html__('OpenRouter API Key', 'mxchat'), 4329 array($this, 'openrouter_api_key_callback'), 4330 'mxchat-chatbot', 4331 'mxchat_chatbot_section', 4332 array( 4333 'class' => 'mxchat-setting-row mxchat-openrouter-key-row', // Special class so we can always show it 4334 'data-provider' => 'openrouter' 4335 ) 4336 ); 4323 4337 4324 4338 add_settings_field( … … 5062 5076 echo '<button type="button" id="toggleGeminiApiKeyVisibility">' . esc_html__('Show', 'mxchat') . '</button>'; 5063 5077 echo '<p class="description api-key-notice">' . esc_html__('Required for Google Gemini models. Get your API key from Google AI Studio.', 'mxchat') . '</p>'; 5078 echo '</div>'; 5079 } 5080 5081 5082 // OpenRouter API Key 5083 public function openrouter_api_key_callback() { 5084 $openrouterApiKey = isset($this->options['openrouter_api_key']) ? esc_attr($this->options['openrouter_api_key']) : ''; 5085 echo '<div class="api-key-wrapper" data-provider="openrouter">'; 5086 echo '<input type="password" id="openrouter_api_key" name="openrouter_api_key" value="' . $openrouterApiKey . '" class="regular-text" autocomplete="off" />'; 5087 echo '<button type="button" id="toggleOpenRouterApiKeyVisibility">' . esc_html__('Show', 'mxchat') . '</button>'; 5088 echo '<p class="description api-key-notice">' . esc_html__('Required only if using OpenRouter. Get your API key from OpenRouter.ai', 'mxchat') . '</p>'; 5064 5089 echo '</div>'; 5065 5090 } … … 5262 5287 // Define available models grouped by provider 5263 5288 $models = array( 5289 esc_html__('OpenRouter (100+ Models)', 'mxchat') => array( 5290 'openrouter' => esc_html__('OpenRouter - Select after entering API key', 'mxchat'), 5291 ), 5292 esc_html__('Google Gemini Models', 'mxchat') => array( 5293 'gemini-2.0-flash' => esc_html__('Gemini 2.0 Flash (Next-Gen Features)', 'mxchat'), 5294 'gemini-2.0-flash-lite' => esc_html__('Gemini 2.0 Flash-Lite (Cost-Efficient)', 'mxchat'), 5295 'gemini-1.5-pro' => esc_html__('Gemini 1.5 Pro (Complex Reasoning)', 'mxchat'), 5296 'gemini-1.5-flash' => esc_html__('Gemini 1.5 Flash (Fast & Versatile)', 'mxchat'), 5297 ), 5264 5298 esc_html__('Google Gemini Models', 'mxchat') => array( 5265 5299 'gemini-2.0-flash' => esc_html__('Gemini 2.0 Flash (Next-Gen Features)', 'mxchat'), … … 5280 5314 ), 5281 5315 esc_html__('Claude Models', 'mxchat') => array( 5316 'claude-sonnet-4-5-20250929' => esc_html__('Claude Sonnet 4.5 (Best for Agents & Coding)', 'mxchat'), 5317 'claude-opus-4-1-20250805' => esc_html__('Claude Opus 4.1 (Exceptional for Complex Tasks)', 'mxchat'), 5318 'claude-haiku-4-5-20251001' => esc_html__('Claude Haiku 4.5 (Fastest & Most Intelligent)', 'mxchat'), 5282 5319 'claude-opus-4-20250514' => esc_html__('Claude 4 Opus (Most Capable)', 'mxchat'), 5283 5320 'claude-sonnet-4-20250514' => esc_html__('Claude 4 Sonnet (High Performance)', 'mxchat'), … … 5315 5352 5316 5353 foreach ($group_models as $model_value => $model_label) { 5317 // All models enabled - no disabled attribute or Pro Only label5318 5354 echo '<option value="' . esc_attr($model_value) . '" ' . selected($selected_model, $model_value, false) . '>' . esc_html($model_label) . '</option>'; 5319 5355 } … … 5322 5358 } 5323 5359 5324 // Close the select dropdown5325 5360 echo '</select>'; 5326 5361 5327 // Updated description to remove mention of Pro-only models5328 5362 echo '<p class="description">' . esc_html__('Select the AI model your chatbot will use for chatting.', 'mxchat') . '</p>'; 5329 } 5330 5363 5364 // Add a note for OpenRouter 5365 echo '<p class="description" id="openrouter-model-note" style="display:none; color: #d63638; font-weight: 500;">'; 5366 echo '<span class="dashicons dashicons-info" style="font-size: 16px; vertical-align: middle;"></span> '; 5367 echo esc_html__('After entering your OpenRouter API key above, click the button below to load available models.', 'mxchat'); 5368 echo '</p>'; 5369 // ADD THESE HIDDEN FIELDS RIGHT HERE: 5370 $openrouter_model = isset($this->options['openrouter_selected_model']) ? esc_attr($this->options['openrouter_selected_model']) : ''; 5371 $openrouter_model_name = isset($this->options['openrouter_selected_model_name']) ? esc_attr($this->options['openrouter_selected_model_name']) : ''; 5372 5373 echo '<input type="hidden" id="openrouter_selected_model" name="openrouter_selected_model" value="' . $openrouter_model . '" />'; 5374 echo '<input type="hidden" id="openrouter_selected_model_name" name="openrouter_selected_model_name" value="' . $openrouter_model_name . '" />'; 5375 } 5331 5376 5332 5377 // Update your existing callback method … … 5357 5402 } 5358 5403 5404 // AJAX handler to fetch OpenRouter models 5405 public function fetch_openrouter_models() { 5406 check_ajax_referer('mxchat_fetch_openrouter_models', 'nonce'); 5407 5408 $api_key = isset($_POST['api_key']) ? sanitize_text_field($_POST['api_key']) : ''; 5409 5410 if (empty($api_key)) { 5411 wp_send_json_error(array('message' => 'API key is required')); 5412 } 5413 5414 $response = wp_remote_get('https://openrouter.ai/api/v1/models', array( 5415 'headers' => array( 5416 'Authorization' => 'Bearer ' . $api_key, 5417 'Content-Type' => 'application/json', 5418 ), 5419 'timeout' => 15, 5420 )); 5421 5422 if (is_wp_error($response)) { 5423 wp_send_json_error(array('message' => $response->get_error_message())); 5424 } 5425 5426 $body = wp_remote_retrieve_body($response); 5427 $data = json_decode($body, true); 5428 5429 if (isset($data['data']) && is_array($data['data'])) { 5430 // Format the models for the frontend 5431 $models = array_map(function($model) { 5432 return array( 5433 'id' => $model['id'], 5434 'name' => $model['name'] ?? $model['id'], 5435 'description' => $model['description'] ?? '', 5436 'context_length' => $model['context_length'] ?? 0, 5437 'pricing' => array( 5438 'prompt' => $model['pricing']['prompt'] ?? 0, 5439 'completion' => $model['pricing']['completion'] ?? 0, 5440 ), 5441 ); 5442 }, $data['data']); 5443 5444 wp_send_json_success(array('models' => $models)); 5445 } else { 5446 wp_send_json_error(array('message' => 'Invalid response from OpenRouter')); 5447 } 5448 } 5359 5449 5360 5450 // Callback function for embedding model selection … … 5383 5473 } 5384 5474 echo '</select>'; 5385 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>';5475 echo '<p class="description"><span class="red-warning">IMPORTANT:</span> A vector embedding model is required for MxChat to function. Changing models is not recommended; if you do, you must delete all existing knowledge & intent data and reconfigure them.</p>'; 5386 5476 } 5387 5477 … … 6531 6621 public function mxchat_enqueue_admin_assets() { 6532 6622 // Get plugin version (define this in your main plugin file) 6533 $version = defined('MXCHAT_VERSION') ? MXCHAT_VERSION : '2.4. 7';6623 $version = defined('MXCHAT_VERSION') ? MXCHAT_VERSION : '2.4.8'; 6534 6624 6535 6625 // Use file modification time for development (remove in production) … … 6611 6701 'edit_intent_nonce' => wp_create_nonce('mxchat_edit_intent'), 6612 6702 'toggle_action_nonce' => wp_create_nonce('mxchat_actions_nonce'), 6703 'fetch_openrouter_models_nonce' => wp_create_nonce('mxchat_fetch_openrouter_models'), // ADD THIS LINE 6613 6704 'is_activated' => $this->is_activated ? '1' : '0', 6614 6705 'status_refresh_interval' => 5000, 6615 6706 'prompts_setting_nonce' => wp_create_nonce('mxchat_prompts_setting_nonce'), 6616 'ajaxurl' => admin_url('admin-ajax.php') // For jQuery fallback6707 'ajaxurl' => admin_url('admin-ajax.php') 6617 6708 ); 6618 6709 … … 6885 6976 6886 6977 if (isset($input['model'])) { 6887 $allowed_models = array( 6888 'gemini-2.0-flash', 6889 'gemini-2.0-flash-lite', 6890 'gemini-1.5-pro', 6891 'gemini-1.5-flash', 6892 6893 'grok-4-0709', // New model: Grok 4 added here 6894 'grok-3-beta', 6895 'grok-3-fast-beta', 6896 'grok-3-mini-beta', 6897 'grok-3-mini-fast-beta', 6898 'grok-2', 6899 6900 'deepseek-chat', 6901 6902 'claude-opus-4-20250514', 6903 'claude-sonnet-4-20250514', 6904 'claude-3-7-sonnet-20250219', 6905 'claude-3-5-sonnet-20241022', 6906 'claude-3-opus-20240229', 6907 'claude-3-sonnet-20240229', 6908 'claude-3-haiku-20240307', 6909 6910 // NEW: GPT-5 family 6911 'gpt-5', 6912 'gpt-5-mini', 6913 'gpt-5-nano', 6914 6915 'gpt-4o', 6916 'gpt-4.1-2025-04-14', 6917 'gpt-4o-mini', 6918 'gpt-4-turbo', 6919 'gpt-4', 6920 'gpt-3.5-turbo', 6921 ); 6922 if (in_array($input['model'], $allowed_models)) { 6923 $new_input['model'] = sanitize_text_field($input['model']); 6924 } 6925 } 6978 // If model is 'openrouter', always allow it 6979 if ($input['model'] === 'openrouter') { 6980 $new_input['model'] = 'openrouter'; 6981 } else { 6982 // For other models, validate against whitelist 6983 $allowed_models = array( 6984 'gemini-2.0-flash', 6985 'gemini-2.0-flash-lite', 6986 'gemini-1.5-pro', 6987 'gemini-1.5-flash', 6988 'grok-4-0709', 6989 'grok-3-beta', 6990 'grok-3-fast-beta', 6991 'grok-3-mini-beta', 6992 'grok-3-mini-fast-beta', 6993 'grok-2', 6994 'deepseek-chat', 6995 'claude-sonnet-4-5-20250929', 6996 'claude-opus-4-1-20250805', 6997 'claude-haiku-4-5-20251001', 6998 'claude-opus-4-20250514', 6999 'claude-sonnet-4-20250514', 7000 'claude-3-7-sonnet-20250219', 7001 'claude-3-5-sonnet-20241022', 7002 'claude-3-opus-20240229', 7003 'claude-3-sonnet-20240229', 7004 'claude-3-haiku-20240307', 7005 'gpt-5', 7006 'gpt-5-mini', 7007 'gpt-5-nano', 7008 'gpt-4.1-2025-04-14', 7009 'gpt-4o', 7010 'gpt-4o-mini', 7011 'gpt-4-turbo', 7012 'gpt-4', 7013 'gpt-3.5-turbo', 7014 ); 7015 7016 if (in_array($input['model'], $allowed_models)) { 7017 $new_input['model'] = sanitize_text_field($input['model']); 7018 } 7019 } 7020 } 7021 7022 if (isset($input['openrouter_selected_model'])) { 7023 // Just sanitize it, don't validate against a whitelist 7024 $new_input['openrouter_selected_model'] = sanitize_text_field($input['openrouter_selected_model']); 7025 } 7026 7027 // ADD THIS: 7028 if (isset($input['openrouter_selected_model_name'])) { 7029 $new_input['openrouter_selected_model_name'] = sanitize_text_field($input['openrouter_selected_model_name']); 7030 } 7031 7032 if (isset($input['openrouter_api_key'])) { 7033 $new_input['openrouter_api_key'] = sanitize_text_field($input['openrouter_api_key']); 7034 } 6926 7035 6927 7036 … … 7205 7314 */ 7206 7315 public function mxchat_handle_delete_all_prompts() { 7207 error_log('=== DELETE ALL DEBUG START ===');7316 //error_log('=== DELETE ALL DEBUG START ==='); 7208 7317 7209 7318 // Verify nonce 7210 7319 if (!isset($_POST['mxchat_delete_all_prompts_nonce']) || !wp_verify_nonce($_POST['mxchat_delete_all_prompts_nonce'], 'mxchat_delete_all_prompts_action')) { 7211 error_log('DEBUG: Nonce verification failed');7320 //error_log('DEBUG: Nonce verification failed'); 7212 7321 wp_die(__('Nonce verification failed.', 'mxchat')); 7213 7322 } … … 7215 7324 // Check permissions 7216 7325 if (!current_user_can('manage_options')) { 7217 error_log('DEBUG: Permission check failed');7326 //error_log('DEBUG: Permission check failed'); 7218 7327 wp_die(__('You do not have sufficient permissions to delete all prompts.', 'mxchat')); 7219 7328 } … … 7221 7330 // Get bot_id from POST data 7222 7331 $bot_id = isset($_POST['bot_id']) ? sanitize_text_field($_POST['bot_id']) : 'default'; 7223 error_log('DEBUG: Bot ID from POST: ' . $bot_id);7332 //error_log('DEBUG: Bot ID from POST: ' . $bot_id); 7224 7333 7225 7334 $success = true; … … 7230 7339 $pinecone_options = $pinecone_manager->mxchat_get_bot_pinecone_options($bot_id); 7231 7340 7232 error_log('DEBUG: Pinecone options retrieved:');7233 error_log(' - Use Pinecone: ' . ($pinecone_options['mxchat_use_pinecone'] ?? 'NOT SET'));7234 error_log(' - API Key: ' . (empty($pinecone_options['mxchat_pinecone_api_key']) ? 'EMPTY' : 'SET'));7235 error_log(' - Host: ' . ($pinecone_options['mxchat_pinecone_host'] ?? 'NOT SET'));7341 //error_log('DEBUG: Pinecone options retrieved:'); 7342 //error_log(' - Use Pinecone: ' . ($pinecone_options['mxchat_use_pinecone'] ?? 'NOT SET')); 7343 //error_log(' - API Key: ' . (empty($pinecone_options['mxchat_pinecone_api_key']) ? 'EMPTY' : 'SET')); 7344 //error_log(' - Host: ' . ($pinecone_options['mxchat_pinecone_host'] ?? 'NOT SET')); 7236 7345 7237 7346 $use_pinecone = ($pinecone_options['mxchat_use_pinecone'] ?? '0') === '1'; 7238 7347 7239 7348 if ($use_pinecone && !empty($pinecone_options['mxchat_pinecone_api_key'])) { 7240 error_log('[MXCHAT-DELETE] Pinecone is enabled for bot ' . $bot_id . ' - deleting all from Pinecone');7349 //error_log('[MXCHAT-DELETE] Pinecone is enabled for bot ' . $bot_id . ' - deleting all from Pinecone'); 7241 7350 7242 7351 // Delete from bot-specific Pinecone index 7243 7352 $result = $pinecone_manager->mxchat_delete_all_from_pinecone($pinecone_options); 7244 7353 7245 error_log('DEBUG: Delete all result: ' . ($result['success'] ? 'SUCCESS' : 'FAILED'));7354 //error_log('DEBUG: Delete all result: ' . ($result['success'] ? 'SUCCESS' : 'FAILED')); 7246 7355 if (!$result['success']) { 7247 error_log('DEBUG: Delete all error: ' . $result['message']);7356 //error_log('DEBUG: Delete all error: ' . $result['message']); 7248 7357 } 7249 7358 … … 7256 7365 7257 7366 } else { 7258 error_log('[MXCHAT-DELETE] Pinecone not enabled for bot ' . $bot_id . ' - deleting from WordPress database');7367 //error_log('[MXCHAT-DELETE] Pinecone not enabled for bot ' . $bot_id . ' - deleting from WordPress database'); 7259 7368 7260 7369 // Delete from WordPress database … … 7282 7391 // No cache clearing needed since we removed caching 7283 7392 7284 error_log('=== DELETE ALL DEBUG END ===');7393 //error_log('=== DELETE ALL DEBUG END ==='); 7285 7394 7286 7395 // Redirect back with a success message and bot_id -
mxchat-basic/trunk/includes/class-mxchat-integrator.php
r3378505 r3379814 1399 1399 $current_options['deepseek_api_key'] ?? $this->options['deepseek_api_key'], 1400 1400 $current_options['gemini_api_key'] ?? $this->options['gemini_api_key'], 1401 $current_options['openrouter_api_key'] ?? $this->options['openrouter_api_key'], 1401 1402 $conversation_history, 1402 1403 $is_streaming, 1403 1404 $session_id, 1404 1405 $testing_data, 1405 $selected_model // ADD THIS LINE1406 $selected_model 1406 1407 ); 1407 1408 … … 4310 4311 return 'default'; 4311 4312 } 4312 private function mxchat_generate_response($relevant_content, $api_key, $xai_api_key, $claude_api_key, $deepseek_api_key, $gemini_api_key, $ conversation_history, $streaming = false, $session_id = '', $testing_data = null, $selected_model = 'gpt-4o') {4313 private function mxchat_generate_response($relevant_content, $api_key, $xai_api_key, $claude_api_key, $deepseek_api_key, $gemini_api_key, $openrouter_api_key, $conversation_history, $streaming = false, $session_id = '', $testing_data = null, $selected_model = 'gpt-4o') { 4313 4314 try { 4314 4315 if (!$relevant_content) { … … 4318 4319 ]; 4319 4320 4320 // Add testing data to error response if available4321 4321 if ($testing_data !== null) { 4322 4322 $error_response['testing_data'] = $testing_data; 4323 //error_log("MxChat Testing: Added testing data to no_relevant_content error");4324 4323 } 4325 4324 … … 4327 4326 } 4328 4327 4329 // Ensure conversation_history is an array4330 4328 if (!is_array($conversation_history)) { 4331 4329 $conversation_history = array(); 4332 4330 } 4333 4331 4332 // Check if this is an OpenRouter model 4333 if ($selected_model === 'openrouter') { 4334 // Get the actual OpenRouter model from options 4335 $openrouter_selected_model = $this->options['openrouter_selected_model'] ?? ''; 4336 4337 if (empty($openrouter_selected_model)) { 4338 $error_response = [ 4339 'error' => esc_html__('No OpenRouter model selected. Please select a model in settings.', 'mxchat'), 4340 'error_code' => 'no_openrouter_model_selected' 4341 ]; 4342 if ($testing_data !== null) { 4343 $error_response['testing_data'] = $testing_data; 4344 } 4345 return $error_response; 4346 } 4347 4348 if (empty($openrouter_api_key)) { 4349 $error_response = [ 4350 'error' => esc_html__('OpenRouter API key is not configured', 'mxchat'), 4351 'error_code' => 'missing_openrouter_api_key' 4352 ]; 4353 if ($testing_data !== null) { 4354 $error_response['testing_data'] = $testing_data; 4355 } 4356 return $error_response; 4357 } 4358 4359 if ($streaming) { 4360 return $this->mxchat_generate_response_openrouter_stream( 4361 $openrouter_selected_model, 4362 $openrouter_api_key, 4363 $conversation_history, 4364 $relevant_content, 4365 $session_id, 4366 $testing_data 4367 ); 4368 } else { 4369 $response = $this->mxchat_generate_response_openrouter( 4370 $openrouter_selected_model, 4371 $openrouter_api_key, 4372 $conversation_history, 4373 $relevant_content 4374 ); 4375 } 4376 4377 if (is_array($response) && isset($response['error'])) { 4378 if ($testing_data !== null) { 4379 $response['testing_data'] = $testing_data; 4380 } 4381 return $response; 4382 } 4383 4384 return $response; 4385 } 4334 4386 4335 4387 // Extract model prefix to determine the provider … … 4376 4428 $relevant_content, 4377 4429 $session_id, 4378 $testing_data // Pass testing data4430 $testing_data 4379 4431 ); 4380 4432 } else { … … 4406 4458 $relevant_content, 4407 4459 $session_id, 4408 $testing_data // Pass testing data4460 $testing_data 4409 4461 ); 4410 4462 } else { … … 4436 4488 $relevant_content, 4437 4489 $session_id, 4438 $testing_data // Pass testing data4490 $testing_data 4439 4491 ); 4440 4492 } else { … … 4467 4519 $relevant_content, 4468 4520 $session_id, 4469 $testing_data // Pass testing data4521 $testing_data 4470 4522 ); 4471 4523 } else { … … 4480 4532 4481 4533 default: 4482 // Default to OpenAI for custom models or unrecognized prefixes4483 4534 if (empty($api_key)) { 4484 4535 $error_response = [ … … 4498 4549 $relevant_content, 4499 4550 $session_id, 4500 $testing_data // Pass testing data4551 $testing_data 4501 4552 ); 4502 4553 } else { … … 4511 4562 } 4512 4563 4513 // Check if the response is an error array from the provider-specific function4514 4564 if (is_array($response) && isset($response['error'])) { 4515 // Add testing data to error response if available4516 4565 if ($testing_data !== null) { 4517 4566 $response['testing_data'] = $testing_data; 4518 //error_log("MxChat Testing: Added testing data to provider error response"); 4519 } 4520 return $response; // Pass through the error with testing data 4521 } 4522 4523 // For successful non-streaming responses, we don't add testing data here 4524 // because it will be added in the main handler 4567 } 4568 return $response; 4569 } 4570 4525 4571 return $response; 4526 4572 4527 4573 } catch (Exception $e) { 4528 //error_log('MXChat Error: ' . $e->getMessage());4529 4574 $error_response = [ 4530 4575 'error' => sprintf(esc_html__('An error occurred: %s', 'mxchat'), esc_html($e->getMessage())), … … 4533 4578 ]; 4534 4579 4535 // Add testing data to exception response if available4536 4580 if ($testing_data !== null) { 4537 4581 $error_response['testing_data'] = $testing_data; 4538 //error_log("MxChat Testing: Added testing data to exception response");4539 4582 } 4540 4583 … … 4543 4586 } 4544 4587 4588 private function mxchat_generate_response_openrouter_stream($selected_model, $openrouter_api_key, $conversation_history, $relevant_content, $session_id, $testing_data = null) { 4589 try { 4590 $bot_id = $this->get_current_bot_id($session_id); 4591 $system_prompt_instructions = $this->get_system_instructions($bot_id); 4592 4593 if (!is_array($conversation_history)) { 4594 $conversation_history = array(); 4595 } 4596 4597 $formatted_conversation = array(); 4598 4599 $formatted_conversation[] = array( 4600 'role' => 'system', 4601 'content' => $system_prompt_instructions . " " . $relevant_content 4602 ); 4603 4604 foreach ($conversation_history as $message) { 4605 if (is_array($message) && isset($message['role']) && isset($message['content'])) { 4606 $role = $message['role']; 4607 if ($role === 'bot' || $role === 'agent') { 4608 $role = 'assistant'; 4609 } 4610 if (!in_array($role, ['system', 'assistant', 'user'])) { 4611 $role = 'user'; 4612 } 4613 $formatted_conversation[] = array( 4614 'role' => $role, 4615 'content' => $message['content'] 4616 ); 4617 } 4618 } 4619 4620 if (headers_sent() || !function_exists('curl_init')) { 4621 $regular_response = $this->mxchat_generate_response_openrouter( 4622 $selected_model, 4623 $openrouter_api_key, 4624 $conversation_history, 4625 $relevant_content 4626 ); 4627 4628 $response_data = [ 4629 'text' => $regular_response, 4630 'html' => '', 4631 'session_id' => $session_id 4632 ]; 4633 4634 if ($testing_data !== null) { 4635 $response_data['testing_data'] = $testing_data; 4636 } 4637 4638 header('Content-Type: application/json'); 4639 echo json_encode($response_data); 4640 return true; 4641 } 4642 4643 $body = json_encode([ 4644 'model' => $selected_model, 4645 'messages' => $formatted_conversation, 4646 'temperature' => 1, 4647 'stream' => true 4648 ]); 4649 4650 $ch = curl_init(); 4651 curl_setopt($ch, CURLOPT_URL, 'https://openrouter.ai/api/v1/chat/completions'); 4652 curl_setopt($ch, CURLOPT_RETURNTRANSFER, false); 4653 curl_setopt($ch, CURLOPT_POST, true); 4654 curl_setopt($ch, CURLOPT_POSTFIELDS, $body); 4655 curl_setopt($ch, CURLOPT_HTTPHEADER, array( 4656 'Content-Type: application/json', 4657 'Authorization: Bearer ' . $openrouter_api_key, 4658 'HTTP-Referer: ' . home_url(), 4659 'X-Title: ' . get_bloginfo('name') 4660 )); 4661 curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true); 4662 curl_setopt($ch, CURLOPT_TIMEOUT, 60); 4663 4664 $full_response = ''; 4665 $stream_started = false; 4666 $buffer = ''; 4667 4668 curl_setopt($ch, CURLOPT_WRITEFUNCTION, function($ch, $data) use (&$full_response, &$stream_started, &$buffer, $testing_data) { 4669 if (!$stream_started && $testing_data !== null) { 4670 echo "data: " . json_encode(['testing_data' => $testing_data]) . "\n\n"; 4671 flush(); 4672 $stream_started = true; 4673 } 4674 4675 $buffer .= $data; 4676 $lines = explode("\n", $buffer); 4677 $buffer = array_pop($lines); 4678 4679 foreach ($lines as $line) { 4680 if (trim($line) === '') { 4681 continue; 4682 } 4683 4684 if (strpos($line, 'data: ') !== 0) { 4685 continue; 4686 } 4687 4688 $json_str = substr($line, 6); 4689 4690 if (trim($json_str) === '[DONE]') { 4691 echo "data: [DONE]\n\n"; 4692 flush(); 4693 continue; 4694 } 4695 4696 $json = json_decode(trim($json_str), true); 4697 if ($json && isset($json['choices'][0]['delta']['content'])) { 4698 $content = $json['choices'][0]['delta']['content']; 4699 $full_response .= $content; 4700 4701 echo "data: " . json_encode(['content' => $content]) . "\n\n"; 4702 flush(); 4703 } 4704 } 4705 4706 return strlen($data); 4707 }); 4708 4709 $response = curl_exec($ch); 4710 $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE); 4711 4712 if (curl_errno($ch) || $http_code !== 200) { 4713 curl_close($ch); 4714 4715 $regular_response = $this->mxchat_generate_response_openrouter( 4716 $selected_model, 4717 $openrouter_api_key, 4718 $conversation_history, 4719 $relevant_content 4720 ); 4721 4722 $response_data = [ 4723 'text' => $regular_response, 4724 'html' => '', 4725 'session_id' => $session_id 4726 ]; 4727 4728 if ($testing_data !== null) { 4729 $response_data['testing_data'] = $testing_data; 4730 } 4731 4732 header('Content-Type: application/json'); 4733 echo json_encode($response_data); 4734 return true; 4735 } 4736 4737 curl_close($ch); 4738 4739 if (!empty($full_response) && !empty($session_id)) { 4740 $this->mxchat_save_chat_message($session_id, 'bot', $full_response); 4741 } 4742 4743 return true; 4744 4745 } catch (Exception $e) { 4746 $regular_response = $this->mxchat_generate_response_openrouter( 4747 $selected_model, 4748 $openrouter_api_key, 4749 $conversation_history, 4750 $relevant_content 4751 ); 4752 4753 $response_data = [ 4754 'text' => $regular_response, 4755 'html' => '', 4756 'session_id' => $session_id 4757 ]; 4758 4759 if ($testing_data !== null) { 4760 $response_data['testing_data'] = $testing_data; 4761 } 4762 4763 header('Content-Type: application/json'); 4764 echo json_encode($response_data); 4765 return true; 4766 } 4767 } 4545 4768 private function mxchat_generate_response_openai_stream($selected_model, $api_key, $conversation_history, $relevant_content, $session_id, $testing_data = null) { 4546 4769 try { … … 5424 5647 } 5425 5648 5649 5650 private function mxchat_generate_response_openrouter($selected_model, $openrouter_api_key, $conversation_history, $relevant_content) { 5651 try { 5652 if (!is_array($conversation_history)) { 5653 $conversation_history = array(); 5654 } 5655 5656 $bot_id = $this->get_current_bot_id(''); 5657 $system_prompt_instructions = $this->get_system_instructions($bot_id); 5658 5659 $formatted_conversation = array(); 5660 5661 $formatted_conversation[] = array( 5662 'role' => 'system', 5663 'content' => $system_prompt_instructions . " " . $relevant_content 5664 ); 5665 5666 foreach ($conversation_history as $message) { 5667 if (is_array($message) && isset($message['role']) && isset($message['content'])) { 5668 $role = $message['role']; 5669 5670 if ($role === 'bot' || $role === 'agent') { 5671 $role = 'assistant'; 5672 } 5673 if (!in_array($role, ['system', 'assistant', 'user'])) { 5674 $role = 'user'; 5675 } 5676 5677 $formatted_conversation[] = array( 5678 'role' => $role, 5679 'content' => $message['content'] 5680 ); 5681 } 5682 } 5683 5684 $body = json_encode([ 5685 'model' => $selected_model, 5686 'messages' => $formatted_conversation, 5687 'temperature' => 1, 5688 ]); 5689 5690 $args = [ 5691 'body' => $body, 5692 'headers' => [ 5693 'Content-Type' => 'application/json', 5694 'Authorization' => 'Bearer ' . $openrouter_api_key, 5695 'HTTP-Referer' => home_url(), 5696 'X-Title' => get_bloginfo('name'), 5697 ], 5698 'timeout' => 60, 5699 'redirection' => 5, 5700 'blocking' => true, 5701 'httpversion' => '1.0', 5702 'sslverify' => true, 5703 ]; 5704 5705 $response = wp_remote_post('https://openrouter.ai/api/v1/chat/completions', $args); 5706 5707 if (is_wp_error($response)) { 5708 $error_message = $response->get_error_message(); 5709 return [ 5710 'error' => esc_html__('Connection error when contacting OpenRouter: ', 'mxchat') . esc_html($error_message), 5711 'error_code' => 'openrouter_connection_error', 5712 'provider' => 'openrouter' 5713 ]; 5714 } 5715 5716 $status_code = wp_remote_retrieve_response_code($response); 5717 if ($status_code !== 200) { 5718 $response_body = wp_remote_retrieve_body($response); 5719 $decoded_response = json_decode($response_body, true); 5720 5721 $error_message = isset($decoded_response['error']['message']) 5722 ? $decoded_response['error']['message'] 5723 : 'HTTP Error ' . $status_code; 5724 5725 return [ 5726 'error' => esc_html__('OpenRouter API error: ', 'mxchat') . esc_html($error_message), 5727 'error_code' => 'openrouter_api_error', 5728 'provider' => 'openrouter', 5729 'status_code' => $status_code 5730 ]; 5731 } 5732 5733 $response_body = wp_remote_retrieve_body($response); 5734 $decoded_response = json_decode($response_body, true); 5735 5736 if (isset($decoded_response['choices'][0]['message']['content'])) { 5737 return trim($decoded_response['choices'][0]['message']['content']); 5738 } else { 5739 return [ 5740 'error' => esc_html__('Unexpected response format from OpenRouter.', 'mxchat'), 5741 'error_code' => 'openrouter_response_format_error', 5742 'provider' => 'openrouter' 5743 ]; 5744 } 5745 } catch (Exception $e) { 5746 return [ 5747 'error' => esc_html__('System error when processing OpenRouter request: ', 'mxchat') . esc_html($e->getMessage()), 5748 'error_code' => 'openrouter_exception', 5749 'provider' => 'openrouter' 5750 ]; 5751 } 5752 } 5426 5753 private function mxchat_generate_response_claude($selected_model, $claude_api_key, $conversation_history, $relevant_content) { 5427 5754 … … 6374 6701 public function mxchat_enqueue_scripts_styles() { 6375 6702 // Define version numbers for the styles and scripts 6376 $chat_style_version = '2.4. 7';6377 $chat_script_version = '2.4. 7';6703 $chat_style_version = '2.4.8'; 6704 $chat_script_version = '2.4.8'; 6378 6705 // Enqueue the script 6379 6706 wp_enqueue_script( … … 6971 7298 * AJAX handler to get system information for testing panel 6972 7299 */ 7300 /** 7301 * AJAX handler to get system information for testing panel 7302 */ 6973 7303 public function mxchat_get_system_info() { 6974 7304 // Verify nonce for security … … 6989 7319 : 'No system prompt configured'; 6990 7320 6991 // Get selected model - FIXED: Use $this->options instead of $current_options7321 // Get selected model 6992 7322 $selected_model = isset($this->options['model']) ? $this->options['model'] : 'gpt-4o'; 7323 7324 // Check if OpenRouter is being used 7325 $is_openrouter = ($selected_model === 'openrouter'); 7326 $openrouter_model = ''; 7327 7328 if ($is_openrouter) { 7329 // Get the actual OpenRouter model that's selected 7330 $openrouter_model = isset($this->options['openrouter_selected_model']) 7331 ? $this->options['openrouter_selected_model'] 7332 : 'No OpenRouter model selected'; 7333 7334 // Update selected_model display to show both 7335 $selected_model = 'OpenRouter: ' . $openrouter_model; 7336 } 6993 7337 6994 7338 // Get API key status (just check if they exist, don't expose the keys) … … 6999 7343 $api_status['xai'] = !empty($this->options['xai_api_key']); 7000 7344 $api_status['deepseek'] = !empty($this->options['deepseek_api_key']); 7345 $api_status['openrouter'] = !empty($this->options['openrouter_api_key']); 7001 7346 7002 7347 wp_send_json_success([ 7003 7348 'system_prompt' => $system_prompt, 7004 7349 'selected_model' => $selected_model, 7350 'is_openrouter' => $is_openrouter, 7351 'openrouter_model' => $openrouter_model, 7005 7352 'api_status' => $api_status 7006 7353 ]); -
mxchat-basic/trunk/js/chat-script.js
r3367268 r3379814 941 941 } 942 942 943 //Function to check if streaming is supported for the current model944 943 function isStreamingSupported(model) { 945 944 if (!model) return false; 946 945 947 //console.log("Checking streaming support for model:", model); // Debug log948 949 // Get the model prefix950 946 const modelPrefix = model.split('-')[0].toLowerCase(); 951 952 //console.log("Model prefix:", modelPrefix); // Debug log 953 954 // Support streaming for OpenAI, Claude, Grok, and DeepSeek models 955 const isSupported = modelPrefix === 'gpt' || modelPrefix === 'o1' || modelPrefix === 'claude' || modelPrefix === 'grok' || modelPrefix === 'deepseek'; 956 957 //console.log("Streaming supported:", isSupported); // Debug log 947 948 // Support streaming for OpenAI, Claude, Grok, DeepSeek, and OpenRouter models 949 const isSupported = modelPrefix === 'gpt' || 950 modelPrefix === 'o1' || 951 modelPrefix === 'claude' || 952 modelPrefix === 'grok' || 953 modelPrefix === 'deepseek' || 954 model === 'openrouter'; // Add this line - check full model name for OpenRouter 958 955 959 956 return isSupported; -
mxchat-basic/trunk/js/mxchat-admin.js
r3364278 r3379814 391 391 392 392 // Handle all input changes (including range slider) 393 $autosaveSections.find('input, textarea, select'). on('change', function() {393 $autosaveSections.find('input, textarea, select').not('#model, #openrouter_selected_model').on('change', function() { 394 394 const $field = $(this); 395 395 const name = $field.attr('name'); … … 736 736 '#toggleBotTokenVisibility', 737 737 '#toggleDeepSeekApiKeyVisibility', 738 '#toggleGeminiApiKeyVisibility' // Added Gemini toggle 738 '#toggleGeminiApiKeyVisibility', 739 '#toggleOpenRouterApiKeyVisibility' 739 740 ].forEach(toggleVisibility); 740 741 … … 861 862 } 862 863 863 // Add this to your JavaScript file864 864 function setupMxChatModelSelector() { 865 865 const $modelSelect = $('#model'); … … 877 877 function updateButtonText() { 878 878 const selectedModel = $modelSelect.val(); 879 const selectedModelText = $modelSelect.find('option:selected').text(); 880 $modelSelectorButton.text(selectedModelText); 881 } 882 879 880 // Check if OpenRouter is selected 881 if (selectedModel === 'openrouter') { 882 const openrouterModelId = $('#openrouter_selected_model').val(); 883 const openrouterModelName = $('#openrouter_selected_model_name').val(); 884 885 if (openrouterModelName && openrouterModelName.trim() !== '') { 886 $modelSelectorButton.text('OpenRouter: ' + openrouterModelName); 887 } else if (openrouterModelId && openrouterModelId.trim() !== '') { 888 $modelSelectorButton.text('OpenRouter: ' + openrouterModelId); 889 } else { 890 $modelSelectorButton.text('OpenRouter - Select Model'); 891 } 892 } else { 893 const selectedModelText = $modelSelect.find('option:selected').text(); 894 $modelSelectorButton.text(selectedModelText); 895 } 896 } 897 883 898 // Initialize button text 884 899 updateButtonText(); … … 896 911 <input type="text" id="mxchat_model_search_input" class="mxchat-model-search-input" placeholder="Search models..."> 897 912 </div> 898 <div class="mxchat-model-selector-categories"> 899 <button class="mxchat-model-category-btn active" data-category="all">All</button> 900 <button class="mxchat-model-category-btn" data-category="gemini">Google Gemini</button> 901 <button class="mxchat-model-category-btn" data-category="openai">OpenAI</button> 902 <button class="mxchat-model-category-btn" data-category="claude">Claude</button> 903 <button class="mxchat-model-category-btn" data-category="xai">X.AI</button> 904 <button class="mxchat-model-category-btn" data-category="deepseek">DeepSeek</button> 905 </div> 913 <div class="mxchat-model-selector-categories"> 914 <button class="mxchat-model-category-btn active" data-category="all">All</button> 915 <button class="mxchat-model-category-btn" data-category="openrouter">OpenRouter</button> 916 <button class="mxchat-model-category-btn" data-category="gemini">Google Gemini</button> 917 <button class="mxchat-model-category-btn" data-category="openai">OpenAI</button> 918 <button class="mxchat-model-category-btn" data-category="claude">Claude</button> 919 <button class="mxchat-model-category-btn" data-category="xai">X.AI</button> 920 <button class="mxchat-model-category-btn" data-category="deepseek">DeepSeek</button> 921 </div> 906 922 <div class="mxchat-model-selector-grid" id="mxchat_models_grid"></div> 907 923 </div> … … 915 931 $('body').append(modelSelectorModal); 916 932 917 // Populate models grid 918 // Populate models grid 919 function populateModelsGrid(filter = '', category = 'all') { 920 const $grid = $('#mxchat_models_grid'); 921 $grid.empty(); 922 923 const models = { 924 gemini: [ 925 { value: 'gemini-2.0-flash', label: 'Gemini 2.0 Flash', description: 'Next-Gen features, speed & multimodal generation' }, 926 { value: 'gemini-2.0-flash-lite', label: 'Gemini 2.0 Flash-Lite', description: 'Cost-efficient with low latency' }, 927 { value: 'gemini-1.5-pro', label: 'Gemini 1.5 Pro', description: 'Complex reasoning tasks requiring more intelligence' }, 928 { value: 'gemini-1.5-flash', label: 'Gemini 1.5 Flash', description: 'Fast and versatile performance' }, 929 ], 930 openai: [ 931 // NEW: GPT-5 family 932 { value: 'gpt-5', label: 'GPT-5', description: 'Flagship for coding, reasoning, and agentic tasks across domains' }, 933 { value: 'gpt-5-mini', label: 'GPT-5 Mini', description: 'Faster, more cost-efficient for well-defined tasks and precise prompts' }, 934 { value: 'gpt-5-nano', label: 'GPT-5 Nano', description: 'Fastest and cheapest; ideal for summarization and classification' }, 935 936 // Existing OpenAI models 937 { value: 'gpt-4.1-2025-04-14', label: 'GPT-4.1', description: 'Flagship model for complex tasks' }, 938 { value: 'gpt-4o', label: 'GPT-4o', description: 'Recommended for most use cases' }, 939 { value: 'gpt-4o-mini', label: 'GPT-4o Mini', description: 'Fast and lightweight' }, 940 { value: 'gpt-4-turbo', label: 'GPT-4 Turbo', description: 'High-performance model' }, 941 { value: 'gpt-4', label: 'GPT-4', description: 'High intelligence model' }, 942 { value: 'gpt-3.5-turbo', label: 'GPT-3.5 Turbo', description: 'Affordable and fast' }, 943 ], 944 claude: [ 945 { value: 'claude-opus-4-20250514', label: 'Claude 4 Opus', description: 'Most capable Claude model' }, 946 { value: 'claude-sonnet-4-20250514', label: 'Claude 4 Sonnet', description: 'High performance' }, 947 { value: 'claude-3-7-sonnet-20250219', label: 'Claude 3.7 Sonnet', description: 'High intelligence' }, 948 { value: 'claude-3-5-sonnet-20241022', label: 'Claude 3.5 Sonnet', description: 'Intelligent and balanced' }, 949 { value: 'claude-3-opus-20240229', label: 'Claude 3 Opus', description: 'Highly complex tasks' }, 950 { value: 'claude-3-sonnet-20240229', label: 'Claude 3 Sonnet', description: 'Balanced performance' }, 951 { value: 'claude-3-haiku-20240307', label: 'Claude 3 Haiku', description: 'Fastest Claude model' }, 952 ], 953 xai: [ 954 { value: 'grok-4-0709', label: 'Grok 4', description: 'Latest flagship model - unparalleled performance in natural language, math and reasoning' }, // Added Grok-4 955 { value: 'grok-3-beta', label: 'Grok-3', description: 'Powerful model with 131K context' }, 956 { value: 'grok-3-fast-beta', label: 'Grok-3 Fast', description: 'High performance with faster responses' }, 957 { value: 'grok-3-mini-beta', label: 'Grok-3 Mini', description: 'Affordable model with good performance' }, 958 { value: 'grok-3-mini-fast-beta', label: 'Grok-3 Mini Fast', description: 'Quick and cost-effective' }, 959 { value: 'grok-2', label: 'Grok 2', description: 'Latest X.AI model' }, 960 ], 961 deepseek: [ 962 { value: 'deepseek-chat', label: 'DeepSeek-V3', description: 'Advanced AI assistant' }, 963 ], 933 // MOVE THIS OUTSIDE - Make it a property of the window object so it's accessible globally 934 window.populateModelsGrid = function(filter = '', category = 'all') { 935 const $grid = $('#mxchat_models_grid'); 936 $grid.empty(); 937 938 const models = { 939 openrouter: [ 940 { value: 'openrouter', label: 'OpenRouter', description: 'Access 100+ models from multiple providers (add API key to browse)' } 941 ], 942 gemini: [ 943 { value: 'gemini-2.0-flash', label: 'Gemini 2.0 Flash', description: 'Next-Gen features, speed & multimodal generation' }, 944 { value: 'gemini-2.0-flash-lite', label: 'Gemini 2.0 Flash-Lite', description: 'Cost-efficient with low latency' }, 945 { value: 'gemini-1.5-pro', label: 'Gemini 1.5 Pro', description: 'Complex reasoning tasks requiring more intelligence' }, 946 { value: 'gemini-1.5-flash', label: 'Gemini 1.5 Flash', description: 'Fast and versatile performance' }, 947 ], 948 openai: [ 949 { value: 'gpt-5', label: 'GPT-5', description: 'Flagship for coding, reasoning, and agentic tasks across domains' }, 950 { value: 'gpt-5-mini', label: 'GPT-5 Mini', description: 'Faster, more cost-efficient for well-defined tasks and precise prompts' }, 951 { value: 'gpt-5-nano', label: 'GPT-5 Nano', description: 'Fastest and cheapest; ideal for summarization and classification' }, 952 { value: 'gpt-4.1-2025-04-14', label: 'GPT-4.1', description: 'Flagship model for complex tasks' }, 953 { value: 'gpt-4o', label: 'GPT-4o', description: 'Recommended for most use cases' }, 954 { value: 'gpt-4o-mini', label: 'GPT-4o Mini', description: 'Fast and lightweight' }, 955 { value: 'gpt-4-turbo', label: 'GPT-4 Turbo', description: 'High-performance model' }, 956 { value: 'gpt-4', label: 'GPT-4', description: 'High intelligence model' }, 957 { value: 'gpt-3.5-turbo', label: 'GPT-3.5 Turbo', description: 'Affordable and fast' }, 958 ], 959 claude: [ 960 { value: 'claude-sonnet-4-5-20250929', label: 'Claude Sonnet 4.5', description: 'Best for complex agents and coding' }, 961 { value: 'claude-opus-4-1-20250805', label: 'Claude Opus 4.1', description: 'Exceptional for specialized complex tasks' }, 962 { value: 'claude-haiku-4-5-20251001', label: 'Claude Haiku 4.5', description: 'Fastest and most intelligent Haiku' }, 963 { value: 'claude-opus-4-20250514', label: 'Claude 4 Opus', description: 'Most capable Claude model' }, 964 { value: 'claude-sonnet-4-20250514', label: 'Claude 4 Sonnet', description: 'High performance' }, 965 { value: 'claude-3-7-sonnet-20250219', label: 'Claude 3.7 Sonnet', description: 'High intelligence' }, 966 { value: 'claude-3-5-sonnet-20241022', label: 'Claude 3.5 Sonnet', description: 'Intelligent and balanced' }, 967 { value: 'claude-3-opus-20240229', label: 'Claude 3 Opus', description: 'Highly complex tasks' }, 968 { value: 'claude-3-sonnet-20240229', label: 'Claude 3 Sonnet', description: 'Balanced performance' }, 969 { value: 'claude-3-haiku-20240307', label: 'Claude 3 Haiku', description: 'Fastest Claude model' }, 970 ], 971 xai: [ 972 { value: 'grok-4-0709', label: 'Grok 4', description: 'Latest flagship model - unparalleled performance in natural language, math and reasoning' }, 973 { value: 'grok-3-beta', label: 'Grok-3', description: 'Powerful model with 131K context' }, 974 { value: 'grok-3-fast-beta', label: 'Grok-3 Fast', description: 'High performance with faster responses' }, 975 { value: 'grok-3-mini-beta', label: 'Grok-3 Mini', description: 'Affordable model with good performance' }, 976 { value: 'grok-3-mini-fast-beta', label: 'Grok-3 Mini Fast', description: 'Quick and cost-effective' }, 977 { value: 'grok-2', label: 'Grok 2', description: 'Latest X.AI model' }, 978 ], 979 deepseek: [ 980 { value: 'deepseek-chat', label: 'DeepSeek-V3', description: 'Advanced AI assistant' }, 981 ], 982 }; 983 984 let allModels = []; 985 Object.keys(models).forEach(key => { 986 if (category === 'all' || category === key) { 987 allModels = allModels.concat(models[key]); 988 } 989 }); 990 991 // Filter by search term if present 992 if (filter) { 993 const lowerFilter = filter.toLowerCase(); 994 allModels = allModels.filter(model => 995 model.label.toLowerCase().includes(lowerFilter) || 996 model.description.toLowerCase().includes(lowerFilter) 997 ); 998 } 999 1000 // Create model cards 1001 allModels.forEach(model => { 1002 const isSelected = $modelSelect.val() === model.value; 1003 const $modelCard = $(` 1004 <div class="mxchat-model-selector-card ${isSelected ? 'mxchat-model-selected' : ''}" data-value="${model.value}"> 1005 <div class="mxchat-model-selector-icon">${getModelIcon(model.value)}</div> 1006 <div class="mxchat-model-selector-info"> 1007 <h4 class="mxchat-model-selector-title">${model.label}</h4> 1008 <p class="mxchat-model-selector-description">${model.description}</p> 1009 </div> 1010 ${isSelected ? '<div class="mxchat-model-selector-checkmark">✓</div>' : ''} 1011 </div> 1012 `); 1013 $grid.append($modelCard); 1014 }); 964 1015 }; 965 966 let allModels = []; 967 Object.keys(models).forEach(key => { 968 if (category === 'all' || category === key) { 969 allModels = allModels.concat(models[key]); 970 } 971 }); 972 973 // Filter by search term if present 974 if (filter) { 975 const lowerFilter = filter.toLowerCase(); 976 allModels = allModels.filter(model => 977 model.label.toLowerCase().includes(lowerFilter) || 978 model.description.toLowerCase().includes(lowerFilter) 979 ); 980 } 981 982 // Create model cards 983 allModels.forEach(model => { 984 const isSelected = $modelSelect.val() === model.value; 985 const $modelCard = $(` 986 <div class="mxchat-model-selector-card ${isSelected ? 'mxchat-model-selected' : ''}" data-value="${model.value}"> 987 <div class="mxchat-model-selector-icon">${getModelIcon(model.value)}</div> 988 <div class="mxchat-model-selector-info"> 989 <h4 class="mxchat-model-selector-title">${model.label}</h4> 990 <p class="mxchat-model-selector-description">${model.description}</p> 991 </div> 992 ${isSelected ? '<div class="mxchat-model-selector-checkmark">✓</div>' : ''} 993 </div> 994 `); 995 $grid.append($modelCard); 996 }); 997 } 998 999 1000 1001 // Helper function to get icon for each model 1002 function getModelIcon(modelValue) { 1003 if (modelValue.startsWith('gemini-')) return '<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 48 48" class="mxchat-model-icon-gemini"><defs><path id="a" d="M44.5 20H24v8.5h11.8C34.7 33.9 30.1 37 24 37c-7.2 0-13-5.8-13-13s5.8-13 13-13c3.1 0 5.9 1.1 8.1 2.9l6.4-6.4C34.6 4.1 29.6 2 24 2 11.8 2 2 11.8 2 24s9.8 22 22 22c11 0 21-8 21-22 0-1.3-.2-2.7-.5-4z"></path></defs><clipPath id="b"><use xlink:href="#a" overflow="visible"></use></clipPath><path clip-path="url(#b)" fill="#FBBC05" d="M0 37V11l17 13z"></path><path clip-path="url(#b)" fill="#EA4335" d="M0 11l17 13 7-6.1L48 14V0H0z"></path><path clip-path="url(#b)" fill="#34A853" d="M0 37l30-23 7.9 1L48 0v48H0z"></path><path clip-path="url(#b)" fill="#4285F4" d="M48 48L17 24l-4-3 35-10z"></path></svg>'; 1004 if (modelValue.startsWith('gpt-')) return '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 320" class="mxchat-model-icon-openai"><path fill="currentColor" d="M297 131a80.6 80.6 0 0 0-93.7-104.2 80.6 80.6 0 0 0-137 29A80.6 80.6 0 0 0 23 189a80.6 80.6 0 0 0 93.7 104.2 80.6 80.6 0 0 0 137-29A80.7 80.7 0 0 0 297.1 131zM176.9 299c-14 .1-27.6-4.8-38.4-13.8l1.9-1 63.7-36.9c3.3-1.8 5.3-5.3 5.2-9v-89.9l27 15.6c.3.1.4.4.5.7v74.4a60 60 0 0 1-60 60zM47.9 244a59.7 59.7 0 0 1-7.1-40.1l1.9 1.1 63.7 36.8c3.2 1.9 7.2 1.9 10.5 0l77.8-45V228c0 .3-.2.6-.4.8L129.9 266a60 60 0 0 1-82-22zM31.2 105c7-12.2 18-21.5 31.2-26.3v75.8c0 3.7 2 7.2 5.2 9l77.8 45-27 15.5a1 1 0 0 1-.9 0L53.1 187a60 60 0 0 1-22-82zm221.2 51.5-77.8-45 27-15.5a1 1 0 0 1 .9 0l64.4 37.1a60 60 0 0 1-9.3 108.2v-75.8c0-3.7-2-7.2-5.2-9zm26.8-40.4-1.9-1.1-63.7-36.8a10.4 10.4 0 0 0-10.5 0L125.4 123V92c0-.3 0-.6.3-.8L190.1 54a60 60 0 0 1 89.1 62.1zm-168.5 55.4-27-15.5a1 1 0 0 1-.4-.7V80.9a60 60 0 0 1 98.3-46.1l-1.9 1L116 72.8a10.3 10.3 0 0 0-5.2 9v89.8zm14.6-31.5 34.7-20 34.6 20v40L160 200l-34.7-20z"></path></svg>'; 1005 if (modelValue.startsWith('claude-')) return '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 176" fill="none" class="mxchat-model-icon-claude"><path fill="currentColor" d="m147.487 0l70.081 175.78H256L185.919 0zM66.183 106.221l23.98-61.774l23.98 61.774zM70.07 0L0 175.78h39.18l14.33-36.914h73.308l14.328 36.914h39.179L110.255 0z"></path></svg>'; 1006 if (modelValue.startsWith('grok-')) return '<svg fill="currentColor" fill-rule="evenodd" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" class="mxchat-model-icon-xai"><path d="M6.469 8.776L16.512 23h-4.464L2.005 8.776H6.47zm-.004 7.9l2.233 3.164L6.467 23H2l4.465-6.324zM22 2.582V23h-3.659V7.764L22 2.582zM22 1l-9.952 14.095-2.233-3.163L17.533 1H22z"></path></svg>'; 1007 if (modelValue.startsWith('deepseek-')) return '<svg height="1em" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg" class="mxchat-model-icon-deepseek"><path d="M23.748 4.482c-.254-.124-.364.113-.512.234-.051.039-.094.09-.137.136-.372.397-.806.657-1.373.626-.829-.046-1.537.214-2.163.848-.133-.782-.575-1.248-1.247-1.548-.352-.156-.708-.311-.955-.65-.172-.241-.219-.51-.305-.774-.055-.16-.11-.323-.293-.35-.2-.031-.278.136-.356.276-.313.572-.434 1.202-.422 1.84.027 1.436.633 2.58 1.838 3.393.137.093.172.187.129.323-.082.28-.18.552-.266.833-.055.179-.137.217-.329.14a5.526 5.526 0 01-1.736-1.18c-.857-.828-1.631-1.742-2.597-2.458a11.365 11.365 0 00-.689-.471c-.985-.957.13-1.743.388-1.836.27-.098.093-.432-.779-.428-.872.004-1.67.295-2.687.684a3.055 3.055 0 01-.465.137 9.597 9.597 0 00-2.883-.102c-1.885.21-3.39 1.102-4.497 2.623C.082 8.606-.231 10.684.152 12.85c.403 2.284 1.569 4.175 3.36 5.653 1.858 1.533 3.997 2.284 6.438 2.14 1.482-.085 3.133-.284 4.994-1.86.47.234.962.327 1.78.397.63.059 1.236-.03 1.705-.128.735-.156.684-.837.419-.961-2.155-1.004-1.682-.595-2.113-.926 1.096-1.296 2.746-2.642 3.392-7.003.05-.347.007-.565 0-.845-.004-.17.035-.237.23-.256a4.173 4.173 0 001.545-.475c1.396-.763 1.96-2.015 2.093-3.517.02-.23-.004-.467-.247-.588zM11.581 18c-2.089-1.642-3.102-2.183-3.52-2.16-.392.024-.321.471-.235.763.09.288.207.486.371.739.114.167.192.416-.113.603-.673.416-1.842-.14-1.897-.167-1.361-.802-2.5-1.86-3.301-3.307-.774-1.393-1.224-2.887-1.298-4.482-.02-.386.093-.522.477-.592a4.696 4.696 0 011.529-.039c2.132.312 3.946 1.265 5.468 2.774.868.86 1.525 1.887 2.202 2.891.72 1.066 1.494 2.082 2.48 2.914.348.292.625.514.891.677-.802.09-2.14.11-3.054-.614zm1-6.44a.306.306 0 01.415-.287.302.302 0 01.2.288.306.306 0 01-.31.307.303.303 0 01-.304-.308zm3.11 1.596c-.2.081-.399.151-.59.16a1.245 1.245 0 01-.798-.254c-.274-.23-.47-.358-.552-.758a1.73 1.73 0 01.016-.588c.07-.327-.008-.537-.239-.727-.187-.156-.426-.199-.688-.199a.559.559 0 01-.254-.078c-.11-.054-.2-.19-.114-.358.028-.054.16-.186.192-.21.356-.202.767-.136 1.146.016.352.144.618.408 1.001.782.391.451.462.576.685.914.176.265.336.537.445.848.067.195-.019.354-.25.452z" fill="currentColor"></path></svg>'; 1008 return '<span class="dashicons dashicons-admin-generic mxchat-model-icon-generic"></span>'; 1009 } 1016 1017 // Helper function to get icon for each model 1018 function getModelIcon(modelValue) { 1019 if (modelValue === 'openrouter') return '<span class="dashicons dashicons-networking" style="font-size: 24px; color: #6750A4;"></span>'; 1020 if (modelValue.startsWith('gemini-')) return '<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 48 48" class="mxchat-model-icon-gemini"><defs><path id="a" d="M44.5 20H24v8.5h11.8C34.7 33.9 30.1 37 24 37c-7.2 0-13-5.8-13-13s5.8-13 13-13c3.1 0 5.9 1.1 8.1 2.9l6.4-6.4C34.6 4.1 29.6 2 24 2 11.8 2 2 11.8 2 24s9.8 22 22 22c11 0 21-8 21-22 0-1.3-.2-2.7-.5-4z"></path></defs><clipPath id="b"><use xlink:href="#a" overflow="visible"></use></clipPath><path clip-path="url(#b)" fill="#FBBC05" d="M0 37V11l17 13z"></path><path clip-path="url(#b)" fill="#EA4335" d="M0 11l17 13 7-6.1L48 14V0H0z"></path><path clip-path="url(#b)" fill="#34A853" d="M0 37l30-23 7.9 1L48 0v48H0z"></path><path clip-path="url(#b)" fill="#4285F4" d="M48 48L17 24l-4-3 35-10z"></path></svg>'; 1021 if (modelValue.startsWith('gpt-')) return '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 320" class="mxchat-model-icon-openai"><path fill="currentColor" d="M297 131a80.6 80.6 0 0 0-93.7-104.2 80.6 80.6 0 0 0-137 29A80.6 80.6 0 0 0 23 189a80.6 80.6 0 0 0 93.7 104.2 80.6 80.6 0 0 0 137-29A80.7 80.7 0 0 0 297.1 131zM176.9 299c-14 .1-27.6-4.8-38.4-13.8l1.9-1 63.7-36.9c3.3-1.8 5.3-5.3 5.2-9v-89.9l27 15.6c.3.1.4.4.5.7v74.4a60 60 0 0 1-60 60zM47.9 244a59.7 59.7 0 0 1-7.1-40.1l1.9 1.1 63.7 36.8c3.2 1.9 7.2 1.9 10.5 0l77.8-45V228c0 .3-.2.6-.4.8L129.9 266a60 60 0 0 1-82-22zM31.2 105c7-12.2 18-21.5 31.2-26.3v75.8c0 3.7 2 7.2 5.2 9l77.8 45-27 15.5a1 1 0 0 1-.9 0L53.1 187a60 60 0 0 1-22-82zm221.2 51.5-77.8-45 27-15.5a1 1 0 0 1 .9 0l64.4 37.1a60 60 0 0 1-9.3 108.2v-75.8c0-3.7-2-7.2-5.2-9zm26.8-40.4-1.9-1.1-63.7-36.8a10.4 10.4 0 0 0-10.5 0L125.4 123V92c0-.3 0-.6.3-.8L190.1 54a60 60 0 0 1 89.1 62.1zm-168.5 55.4-27-15.5a1 1 0 0 1-.4-.7V80.9a60 60 0 0 1 98.3-46.1l-1.9 1L116 72.8a10.3 10.3 0 0 0-5.2 9v89.8zm14.6-31.5 34.7-20 34.6 20v40L160 200l-34.7-20z"></path></svg>'; 1022 if (modelValue.startsWith('claude-')) return '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 176" fill="none" class="mxchat-model-icon-claude"><path fill="currentColor" d="m147.487 0l70.081 175.78H256L185.919 0zM66.183 106.221l23.98-61.774l23.98 61.774zM70.07 0L0 175.78h39.18l14.33-36.914h73.308l14.328 36.914h39.179L110.255 0z"></path></svg>'; 1023 if (modelValue.startsWith('grok-')) return '<svg fill="currentColor" fill-rule="evenodd" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" class="mxchat-model-icon-xai"><path d="M6.469 8.776L16.512 23h-4.464L2.005 8.776H6.47zm-.004 7.9l2.233 3.164L6.467 23H2l4.465-6.324zM22 2.582V23h-3.659V7.764L22 2.582zM22 1l-9.952 14.095-2.233-3.163L17.533 1H22z"></path></svg>'; 1024 if (modelValue.startsWith('deepseek-')) return '<svg height="1em" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg" class="mxchat-model-icon-deepseek"><path d="M23.748 4.482c-.254-.124-.364.113-.512.234-.051.039-.094.09-.137.136-.372.397-.806.657-1.373.626-.829-.046-1.537.214-2.163.848-.133-.782-.575-1.248-1.247-1.548-.352-.156-.708-.311-.955-.65-.172-.241-.219-.51-.305-.774-.055-.16-.11-.323-.293-.35-.2-.031-.278.136-.356.276-.313.572-.434 1.202-.422 1.84.027 1.436.633 2.58 1.838 3.393.137.093.172.187.129.323-.082.28-.18.552-.266.833-.055.179-.137.217-.329.14a5.526 5.526 0 01-1.736-1.18c-.857-.828-1.631-1.742-2.597-2.458a11.365 11.365 0 00-.689-.471c-.985-.957.13-1.743.388-1.836.27-.098.093-.432-.779-.428-.872.004-1.67.295-2.687.684a3.055 3.055 0 01-.465.137 9.597 9.597 0 00-2.883-.102c-1.885.21-3.39 1.102-4.497 2.623C.082 8.606-.231 10.684.152 12.85c.403 2.284 1.569 4.175 3.36 5.653 1.858 1.533 3.997 2.284 6.438 2.14 1.482-.085 3.133-.284 4.994-1.86.47.234.962.327 1.78.397.63.059 1.236-.03 1.705-.128.735-.156.684-.837.419-.961-2.155-1.004-1.682-.595-2.113-.926 1.096-1.296 2.746-2.642 3.392-7.003.05-.347.007-.565 0-.845-.004-.17.035-.237.23-.256a4.173 4.173 0 001.545-.475c1.396-.763 1.96-2.015 2.093-3.517.02-.23-.004-.467-.247-.588zM11.581 18c-2.089-1.642-3.102-2.183-3.52-2.16-.392.024-.321.471-.235.763.09.288.207.486.371.739.114.167.192.416-.113.603-.673.416-1.842-.14-1.897-.167-1.361-.802-2.5-1.86-3.301-3.307-.774-1.393-1.224-2.887-1.298-4.482-.02-.386.093-.522.477-.592a4.696 4.696 0 011.529-.039c2.132.312 3.946 1.265 5.468 2.774.868.86 1.525 1.887 2.202 2.891.72 1.066 1.494 2.082 2.48 2.914.348.292.625.514.891.677-.802.09-2.14.11-3.054-.614zm1-6.44a.306.306 0 01.415-.287.302.302 0 01.2.288.306.306 0 01-.31.307.303.303 0 01-.304-.308zm3.11 1.596c-.2.081-.399.151-.59.16a1.245 1.245 0 01-.798-.254c-.274-.23-.47-.358-.552-.758a1.73 1.73 0 01.016-.588c.07-.327-.008-.537-.239-.727-.187-.156-.426-.199-.688-.199a.559.559 0 01-.254-.078c-.11-.054-.2-.19-.114-.358.028-.054.16-.186.192-.21.356-.202.767-.136 1.146.016.352.144.618.408 1.001.782.391.451.462.576.685.914.176.265.336.537.445.848.067.195-.019.354-.25.452z" fill="currentColor"></path></svg>'; 1025 return '<span class="dashicons dashicons-admin-generic mxchat-model-icon-generic"></span>'; 1026 } 1010 1027 1011 1028 // Event handlers 1012 1029 $modelSelectorButton.on('click', function() { 1013 1030 $('#mxchat_model_selector_modal').show(); 1014 populateModelsGrid('', 'all');1031 window.populateModelsGrid('', 'all'); 1015 1032 }); 1016 1033 … … 1024 1041 const category = $(this).data('category'); 1025 1042 const searchTerm = $('#mxchat_model_search_input').val(); 1026 populateModelsGrid(searchTerm, category);1043 window.populateModelsGrid(searchTerm, category); 1027 1044 }); 1028 1045 … … 1030 1047 const searchTerm = $(this).val(); 1031 1048 const activeCategory = $('.mxchat-model-category-btn.active').data('category'); 1032 populateModelsGrid(searchTerm, activeCategory); 1033 }); 1034 1035 $(document).on('click', '.mxchat-model-selector-card', function() { 1036 const modelValue = $(this).data('value'); 1049 window.populateModelsGrid(searchTerm, activeCategory); 1050 }); 1051 1052 $(document).on('click', '.mxchat-model-selector-card', function() { 1053 const modelValue = $(this).data('value'); 1054 const $modelSelect = $('#model'); // Add this line to ensure we have the element 1055 1056 // Check if OpenRouter was selected 1057 if (modelValue === 'openrouter') { 1058 // Load OpenRouter models instead of closing 1059 loadOpenRouterModels(); 1060 } else { 1061 // Normal model selection 1037 1062 $modelSelect.val(modelValue).trigger('change'); 1038 updateButtonText(); 1063 1064 // Manually save the model via AJAX 1065 jQuery.ajax({ 1066 url: mxchatAdmin.ajax_url, 1067 type: 'POST', 1068 data: { 1069 action: 'mxchat_save_setting', 1070 name: 'model', 1071 value: modelValue, 1072 _ajax_nonce: mxchatAdmin.setting_nonce 1073 }, 1074 success: function(response) { 1075 if (response.success) { 1076 // Update button text after successful save 1077 const selectedModelText = $modelSelect.find('option:selected').text(); 1078 $('#mxchat_model_selector_btn').text(selectedModelText); 1079 } 1080 } 1081 }); 1082 1039 1083 $('#mxchat_model_selector_modal').hide(); 1040 }); 1084 } 1085 }); 1041 1086 1042 1087 // Close modal when clicking outside … … 1046 1091 } 1047 1092 }); 1093 } 1094 1095 function loadOpenRouterModels() { 1096 const apiKey = $('#openrouter_api_key').val(); // This line already re-checks the field 1097 const $modal = $('#mxchat_model_selector_modal'); 1098 const $modalBody = $modal.find('.mxchat-model-selector-modal-body'); 1099 1100 if (!apiKey || apiKey.trim() === '') { 1101 // Show error message in modal 1102 $modalBody.html(` 1103 <div style="text-align: center; padding: 40px;"> 1104 <span class="dashicons dashicons-warning" style="font-size: 48px; color: #d63638; margin-bottom: 20px;"></span> 1105 <h3>OpenRouter API Key Required</h3> 1106 <p>Please enter your OpenRouter API key in the settings before selecting a model. If you're seeing this message and recently entered API key, try refreshing.</p> 1107 <button class="button button-primary" id="mxchat_back_to_models">Back to Models</button> 1108 </div> 1109 `); 1110 1111 $('#mxchat_back_to_models').on('click', function(e) { 1112 e.preventDefault(); 1113 // CHANGE THIS: Instead of reloading, restore the original modal content 1114 $modalBody.html(` 1115 <div class="mxchat-model-selector-search-container"> 1116 <input type="text" id="mxchat_model_search_input" class="mxchat-model-search-input" placeholder="Search models..."> 1117 </div> 1118 <div class="mxchat-model-selector-categories"> 1119 <button class="mxchat-model-category-btn active" data-category="all">All</button> 1120 <button class="mxchat-model-category-btn" data-category="openrouter">OpenRouter</button> 1121 <button class="mxchat-model-category-btn" data-category="gemini">Google Gemini</button> 1122 <button class="mxchat-model-category-btn" data-category="openai">OpenAI</button> 1123 <button class="mxchat-model-category-btn" data-category="claude">Claude</button> 1124 <button class="mxchat-model-category-btn" data-category="xai">X.AI</button> 1125 <button class="mxchat-model-category-btn" data-category="deepseek">DeepSeek</button> 1126 </div> 1127 <div class="mxchat-model-selector-grid" id="mxchat_models_grid"></div> 1128 `); 1129 1130 // Re-populate the grid 1131 populateModelsGrid('', 'all'); 1132 1133 // Re-bind event handlers 1134 rebindModalEventHandlers(); 1135 }); 1136 return; 1137 } 1138 1139 // Show loading state 1140 $modalBody.html(` 1141 <div style="text-align: center; padding: 60px 20px;"> 1142 <div class="spinner is-active" style="float: none; margin: 0 auto 20px;"></div> 1143 <h3>Loading OpenRouter Models...</h3> 1144 <p>Fetching available models from OpenRouter</p> 1145 </div> 1146 `); 1147 1148 // Fetch models from OpenRouter 1149 jQuery.ajax({ 1150 url: mxchatAdmin.ajax_url, 1151 type: 'POST', 1152 data: { 1153 action: 'mxchat_fetch_openrouter_models', 1154 api_key: apiKey, 1155 nonce: mxchatAdmin.fetch_openrouter_models_nonce 1156 }, 1157 success: function(response) { 1158 if (response.success && response.data.models) { 1159 displayOpenRouterModels(response.data.models); 1160 } else { 1161 $modalBody.html(` 1162 <div style="text-align: center; padding: 40px;"> 1163 <span class="dashicons dashicons-warning" style="font-size: 48px; color: #d63638; margin-bottom: 20px;"></span> 1164 <h3>Error Loading Models</h3> 1165 <p>${response.data.message || 'Failed to load models from OpenRouter'}</p> 1166 <button class="button button-primary" id="mxchat_back_to_models">Back to Models</button> 1167 </div> 1168 `); 1169 1170 $('#mxchat_back_to_models').on('click', function(e) { 1171 e.preventDefault(); 1172 // CHANGE THIS: Restore original content instead of reloading 1173 restoreOriginalModalContent(); 1174 }); 1175 } 1176 }, 1177 error: function() { 1178 $modalBody.html(` 1179 <div style="text-align: center; padding: 40px;"> 1180 <span class="dashicons dashicons-warning" style="font-size: 48px; color: #d63638; margin-bottom: 20px;"></span> 1181 <h3>Connection Error</h3> 1182 <p>Failed to connect to OpenRouter. Please check your API key and try again.</p> 1183 <button class="button button-primary" id="mxchat_back_to_models">Back to Models</button> 1184 </div> 1185 `); 1186 1187 $('#mxchat_back_to_models').on('click', function(e) { 1188 e.preventDefault(); 1189 // CHANGE THIS: Restore original content instead of reloading 1190 restoreOriginalModalContent(); 1191 }); 1192 } 1193 }); 1194 } 1195 function restoreOriginalModalContent() { 1196 const $modalBody = $('#mxchat_model_selector_modal').find('.mxchat-model-selector-modal-body'); 1197 1198 $modalBody.html(` 1199 <div class="mxchat-model-selector-search-container"> 1200 <input type="text" id="mxchat_model_search_input" class="mxchat-model-search-input" placeholder="Search models..."> 1201 </div> 1202 <div class="mxchat-model-selector-categories"> 1203 <button class="mxchat-model-category-btn active" data-category="all">All</button> 1204 <button class="mxchat-model-category-btn" data-category="openrouter">OpenRouter</button> 1205 <button class="mxchat-model-category-btn" data-category="gemini">Google Gemini</button> 1206 <button class="mxchat-model-category-btn" data-category="openai">OpenAI</button> 1207 <button class="mxchat-model-category-btn" data-category="claude">Claude</button> 1208 <button class="mxchat-model-category-btn" data-category="xai">X.AI</button> 1209 <button class="mxchat-model-category-btn" data-category="deepseek">DeepSeek</button> 1210 </div> 1211 <div class="mxchat-model-selector-grid" id="mxchat_models_grid"></div> 1212 `); 1213 1214 // Re-populate the grid 1215 window.populateModelsGrid('', 'all'); 1216 1217 // Re-bind event handlers 1218 rebindModalEventHandlers(); 1219 } 1220 function rebindModalEventHandlers() { 1221 const $modal = $('#mxchat_model_selector_modal'); 1222 1223 // Re-bind category button clicks 1224 $('.mxchat-model-category-btn').off('click').on('click', function() { 1225 $('.mxchat-model-category-btn').removeClass('active'); 1226 $(this).addClass('active'); 1227 const category = $(this).data('category'); 1228 const searchTerm = $('#mxchat_model_search_input').val(); 1229 window.populateModelsGrid(searchTerm, category); 1230 }); 1231 1232 // Re-bind search input 1233 $('#mxchat_model_search_input').off('input').on('input', function() { 1234 const searchTerm = $(this).val(); 1235 const activeCategory = $('.mxchat-model-category-btn.active').data('category'); 1236 populateModelsGrid(searchTerm, activeCategory); 1237 }); 1238 } 1239 1240 function displayOpenRouterModels(models) { 1241 const $modal = $('#mxchat_model_selector_modal'); 1242 const $modalBody = $modal.find('.mxchat-model-selector-modal-body'); 1243 const currentSelected = $('#openrouter_selected_model').val(); 1244 1245 // Build new modal content with search and models 1246 const newContent = ` 1247 <div class="mxchat-model-selector-search-container"> 1248 <input type="text" id="mxchat_openrouter_search" class="mxchat-model-search-input" placeholder="Search OpenRouter models..."> 1249 <p style="margin: 10px 0; color: #666; font-size: 13px;"> 1250 <strong>${models.length} models available</strong> · 1251 <a href="#" id="mxchat_back_to_provider_select" style="color: #2271b1;">← Back to providers</a> 1252 </p> 1253 </div> 1254 <div class="mxchat-model-selector-grid" id="mxchat_openrouter_models_grid"></div> 1255 `; 1256 1257 $modalBody.html(newContent); 1258 1259 // Function to render models 1260 function renderOpenRouterModels(filterText = '') { 1261 const $grid = $('#mxchat_openrouter_models_grid'); 1262 $grid.empty(); 1263 1264 let filteredModels = models; 1265 if (filterText) { 1266 const lowerFilter = filterText.toLowerCase(); 1267 filteredModels = models.filter(m => 1268 m.id.toLowerCase().includes(lowerFilter) || 1269 m.name.toLowerCase().includes(lowerFilter) || 1270 (m.description && m.description.toLowerCase().includes(lowerFilter)) 1271 ); 1272 } 1273 1274 filteredModels.forEach(model => { 1275 const isSelected = currentSelected === model.id; 1276 const contextLength = model.context_length ? `${(model.context_length / 1000).toFixed(0)}K` : ''; 1277 const promptPrice = model.pricing.prompt ? `$${(model.pricing.prompt * 1000000).toFixed(2)}/1M` : ''; 1278 1279 const $card = jQuery(` 1280 <div class="mxchat-model-selector-card mxchat-openrouter-card ${isSelected ? 'mxchat-model-selected' : ''}" data-model-id="${model.id}"> 1281 <div class="mxchat-model-selector-icon"> 1282 ${getOpenRouterIcon(model.id)} 1283 </div> 1284 <div class="mxchat-model-selector-info"> 1285 <h4 class="mxchat-model-selector-title">${model.name}</h4> 1286 <div style="font-size: 12px; color: #666; margin-top: 5px;"> 1287 ${contextLength ? '<span style="margin-right: 12px;">📄 ' + contextLength + '</span>' : ''} 1288 ${promptPrice ? '<span>💰 ' + promptPrice + '</span>' : ''} 1289 </div> 1290 </div> 1291 ${isSelected ? '<div class="mxchat-model-selector-checkmark">✓</div>' : ''} 1292 </div> 1293 `); 1294 1295 $grid.append($card); 1296 }); 1297 } 1298 1299 // Helper to get icon 1300 function getOpenRouterIcon(modelId) { 1301 if (modelId.includes('gpt') || modelId.includes('openai')) { 1302 return '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 320" class="mxchat-model-icon-openai"><path fill="currentColor" d="M297 131a80.6 80.6 0 0 0-93.7-104.2 80.6 80.6 0 0 0-137 29A80.6 80.6 0 0 0 23 189a80.6 80.6 0 0 0 93.7 104.2 80.6 80.6 0 0 0 137-29A80.7 80.7 0 0 0 297.1 131zM176.9 299c-14 .1-27.6-4.8-38.4-13.8l1.9-1 63.7-36.9c3.3-1.8 5.3-5.3 5.2-9v-89.9l27 15.6c.3.1.4.4.5.7v74.4a60 60 0 0 1-60 60zM47.9 244a59.7 59.7 0 0 1-7.1-40.1l1.9 1.1 63.7 36.8c3.2 1.9 7.2 1.9 10.5 0l77.8-45V228c0 .3-.2.6-.4.8L129.9 266a60 60 0 0 1-82-22zM31.2 105c7-12.2 18-21.5 31.2-26.3v75.8c0 3.7 2 7.2 5.2 9l77.8 45-27 15.5a1 1 0 0 1-.9 0L53.1 187a60 60 0 0 1-22-82zm221.2 51.5-77.8-45 27-15.5a1 1 0 0 1 .9 0l64.4 37.1a60 60 0 0 1-9.3 108.2v-75.8c0-3.7-2-7.2-5.2-9zm26.8-40.4-1.9-1.1-63.7-36.8a10.4 10.4 0 0 0-10.5 0L125.4 123V92c0-.3 0-.6.3-.8L190.1 54a60 60 0 0 1 89.1 62.1zm-168.5 55.4-27-15.5a1 1 0 0 1-.4-.7V80.9a60 60 0 0 1 98.3-46.1l-1.9 1L116 72.8a10.3 10.3 0 0 0-5.2 9v89.8zm14.6-31.5 34.7-20 34.6 20v40L160 200l-34.7-20z"></path></svg>'; 1303 } else if (modelId.includes('claude') || modelId.includes('anthropic')) { 1304 return '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 176" fill="none" class="mxchat-model-icon-claude"><path fill="currentColor" d="m147.487 0l70.081 175.78H256L185.919 0zM66.183 106.221l23.98-61.774l23.98 61.774zM70.07 0L0 175.78h39.18l14.33-36.914h73.308l14.328 36.914h39.179L110.255 0z"></path></svg>'; 1305 } else if (modelId.includes('gemini') || modelId.includes('google')) { 1306 return '<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 48 48" class="mxchat-model-icon-gemini"><defs><path id="a" d="M44.5 20H24v8.5h11.8C34.7 33.9 30.1 37 24 37c-7.2 0-13-5.8-13-13s5.8-13 13-13c3.1 0 5.9 1.1 8.1 2.9l6.4-6.4C34.6 4.1 29.6 2 24 2 11.8 2 2 11.8 2 24s9.8 22 22 22c11 0 21-8 21-22 0-1.3-.2-2.7-.5-4z"></path></defs><clipPath id="b"><use xlink:href="#a" overflow="visible"></use></clipPath><path clip-path="url(#b)" fill="#FBBC05" d="M0 37V11l17 13z"></path><clip-path="url(#b)" fill="#EA4335" d="M0 11l17 13 7-6.1L48 14V0H0z"></path><path clip-path="url(#b)" fill="#34A853" d="M0 37l30-23 7.9 1L48 0v48H0z"></path><path clip-path="url(#b)" fill="#4285F4" d="M48 48L17 24l-4-3 35-10z"></path></svg>'; 1307 } 1308 return '<span class="dashicons dashicons-cloud" style="font-size: 24px; color: #6750A4;"></span>'; 1309 } 1310 1311 // Initial render 1312 renderOpenRouterModels(); 1313 1314 // Search handler 1315 $('#mxchat_openrouter_search').on('input', function() { 1316 renderOpenRouterModels($(this).val()); 1317 }); 1318 1319 $('#mxchat_back_to_provider_select').on('click', function(e) { 1320 e.preventDefault(); 1321 // Instead of location.reload(), restore original content 1322 restoreOriginalModalContent(); 1323 }); 1324 1325 // Model selection 1326 $(document).on('click', '.mxchat-openrouter-card', function() { 1327 const modelId = $(this).data('model-id'); 1328 const modelName = models.find(m => m.id === modelId)?.name || modelId; 1329 1330 // First, save that we're using OpenRouter 1331 jQuery.ajax({ 1332 url: mxchatAdmin.ajax_url, 1333 type: 'POST', 1334 data: { 1335 action: 'mxchat_save_setting', 1336 name: 'model', 1337 value: 'openrouter', 1338 _ajax_nonce: mxchatAdmin.setting_nonce 1339 }, 1340 success: function() { 1341 // After model is set, save the model ID 1342 jQuery.ajax({ 1343 url: mxchatAdmin.ajax_url, 1344 type: 'POST', 1345 data: { 1346 action: 'mxchat_save_setting', 1347 name: 'openrouter_selected_model', 1348 value: modelId, 1349 _ajax_nonce: mxchatAdmin.setting_nonce 1350 }, 1351 success: function() { 1352 // Update DOM immediately 1353 $('#openrouter_selected_model').val(modelId); 1354 1355 // After model ID is saved, save the display name 1356 jQuery.ajax({ 1357 url: mxchatAdmin.ajax_url, 1358 type: 'POST', 1359 data: { 1360 action: 'mxchat_save_setting', 1361 name: 'openrouter_selected_model_name', 1362 value: modelName, 1363 _ajax_nonce: mxchatAdmin.setting_nonce 1364 }, 1365 success: function() { 1366 // Update DOM immediately 1367 $('#openrouter_selected_model_name').val(modelName); 1368 1369 // Update button text 1370 $('#mxchat_model_selector_btn').text('OpenRouter: ' + modelName); 1371 } 1372 }); 1373 } 1374 }); 1375 } 1376 }); 1377 1378 // Close modal 1379 $modal.hide(); 1380 }); 1381 1048 1382 } 1049 1383 -
mxchat-basic/trunk/js/test-panel.js
r3315188 r3379814 607 607 608 608 updateSystemPrompt() { 609 const promptEl = this.panel.querySelector('#system-prompt'); 610 promptEl.textContent = 'Loading system prompt...'; 611 612 fetch(mxchatTestData.ajaxUrl, { 613 method: 'POST', 614 headers: { 615 'Content-Type': 'application/x-www-form-urlencoded', 616 }, 617 body: new URLSearchParams({ 618 action: 'mxchat_get_system_info', 619 nonce: mxchatTestData.nonce 620 }) 609 const promptEl = this.panel.querySelector('#system-prompt'); 610 promptEl.textContent = 'Loading system prompt...'; 611 612 fetch(mxchatTestData.ajaxUrl, { 613 method: 'POST', 614 headers: { 615 'Content-Type': 'application/x-www-form-urlencoded', 616 }, 617 body: new URLSearchParams({ 618 action: 'mxchat_get_system_info', 619 nonce: mxchatTestData.nonce 621 620 }) 622 .then(response => response.json()) 623 .then(data => { 624 if (data.success) { 625 promptEl.textContent = data.data.system_prompt || 'No system prompt configured'; 621 }) 622 .then(response => response.json()) 623 .then(data => { 624 if (data.success) { 625 promptEl.textContent = data.data.system_prompt || 'No system prompt configured'; 626 627 // Enhanced model display with OpenRouter support 628 if (data.data.is_openrouter) { 629 this.log(`🤖 Model: OpenRouter`); 630 this.log(` └─ Using: ${data.data.openrouter_model}`); 631 } else { 626 632 this.log(`🤖 Model: ${data.data.selected_model}`); 627 this.log(`🔑 API Status: ${JSON.stringify(data.data.api_status)}`); 633 } 634 635 // Enhanced API status with OpenRouter 636 const apiStatus = data.data.api_status; 637 const configuredApis = Object.keys(apiStatus).filter(key => apiStatus[key]); 638 639 if (configuredApis.length > 0) { 640 this.log(`🔑 Configured APIs: ${configuredApis.map(api => { 641 // Capitalize and format API names 642 if (api === 'openai') return 'OpenAI'; 643 if (api === 'xai') return 'X.AI'; 644 if (api === 'openrouter') return 'OpenRouter'; 645 return api.charAt(0).toUpperCase() + api.slice(1); 646 }).join(', ')}`); 628 647 } else { 629 promptEl.textContent = 'Error loading system prompt';648 this.log(`⚠️ No API keys configured`); 630 649 } 631 }) 632 .catch(error => { 633 console.error('Error fetching system info:', error); 634 promptEl.textContent = 'Connection error'; 635 }); 636 } 650 651 // Specific warning for OpenRouter if selected but no key 652 if (data.data.is_openrouter && !apiStatus.openrouter) { 653 this.log(`❌ WARNING: OpenRouter selected but no API key configured!`); 654 } 655 } else { 656 promptEl.textContent = 'Error loading system prompt'; 657 } 658 }) 659 .catch(error => { 660 console.error('Error fetching system info:', error); 661 promptEl.textContent = 'Connection error'; 662 }); 663 } 637 664 638 665 updateKnowledgeBaseStatus() { -
mxchat-basic/trunk/mxchat-basic.php
r3378505 r3379814 4 4 * Plugin URI: https://mxchat.ai/ 5 5 * Description: AI chatbot for WordPress with OpenAI, Claude, xAI, DeepSeek, live agent, PDF uploads, WooCommerce, and training on website data. 6 * Version: 2.4. 76 * Version: 2.4.8 7 7 * Author: MxChat 8 8 * Author URI: https://mxchat.ai … … 18 18 19 19 // Define plugin version constant for asset versioning 20 define('MXCHAT_VERSION', '2.4. 7');20 define('MXCHAT_VERSION', '2.4.8'); 21 21 22 22 function mxchat_load_textdomain() { -
mxchat-basic/trunk/readme.txt
r3378505 r3379814 6 6 Tested up to: 6.8 7 7 Requires PHP: 7.2 8 Stable tag: 2.4. 78 Stable tag: 2.4.8 9 9 License: GPLv2 or later 10 10 License URI: https://www.gnu.org/licenses/gpl-2.0.html 11 11 12 AI chatbot with OpenAI, Gemini, Claude, Grok, DeepSeek, live agent, PDF uploads, WooCommerce, and training on website data.12 AI chatbot with OpenAI, Gemini, Claude, Grok, DeepSeek, OpenRouter, live agent, WooCommerce, and training on website data. 13 13 14 14 == Description == … … 32 32 ## Why Choose MxChat AI Chatbot for Your WordPress Website? 33 33 34 ✅ **5 Major AI Providers in One Plugin**: OpenAI GPT, Claude, Gemini, xAI Grok, and DeepSeek - switch between 25+ models instantly 35 ✅ **Train on Your Website Data**: Advanced RAG technology learns from sitemaps, PDFs, URLs, or manual input for ultra-relevant responses 34 ✅ **6 Major AI Providers in One Plugin**: OpenRouter, OpenAI GPT, Claude, Gemini, xAI Grok, and DeepSeek - switch between 100+ models instantly✅ **Train on Your Website Data**: Advanced RAG technology learns from sitemaps, PDFs, URLs, or manual input for ultra-relevant responses 36 35 ✅ **Live Agent Handoff via Slack**: Seamlessly escalate from AI to human support when customers need personal assistance 37 36 ✅ **Real-Time Debug Panel**: See exactly what your chatbot retrieves and triggers with our admin testing interface … … 39 38 ✅ **Extensive Add-On Ecosystem**: Forms, moderation, recommendations, theme customization, and more 40 39 41 ## 🔥 What's New in Version 2.4.4 42 43 🐞 **Bug Fixes** 44 - Default similarity is now accurate across all settings 45 - Improved streaming responses to prevent dropped characters or words 46 47 ⚡ **Enhancements** 48 - Removed unnecessary Pinecone caching in the knowledge database for more accurate results 40 ## 🔥 What's New in Version 2.4.8 41 🚀 **New Features** 42 - **OpenRouter Integration** - Access 100+ AI models from multiple providers using a single API key! Browse and select from hundreds of cutting-edge models including OpenAI, Anthropic, Google, Meta, and more. 43 - **Latest Claude Models** - Added support for Anthropic's newest models: 44 - Claude Sonnet 4.5 - Best for complex agents and coding tasks 45 - Claude Opus 4.1 - Exceptional performance for specialized complex tasks 46 - Claude Haiku 4.5 - Fastest and most intelligent Haiku model with extended thinking 49 47 50 48 ## Core Features That Set MxChat Apart … … 58 56 🟢 **Streaming Responses** – Real-time response streaming for OpenAI, Claude, and Grok models for the fastest possible chat experience 59 57 60 ## Choose from 25+ Premium AI Models 61 58 ## Choose from 100+ Premium AI Models 62 59 Access the world's most advanced AI models based on your specific needs: 63 60 61 **OpenRouter**: 100+ models from multiple providers with a single API key - including OpenAI, Anthropic, Google, Meta, Mistral, and more! 64 62 **OpenAI**: GPT-5, GPT-5-mini, GPT-5-nano, GPT-4.1, GPT-4o, GPT-4o-mini, GPT-4-turbo, GPT-4, GPT-3.5-turbo 65 ** X.AI**: Grok-4, Grok-3, Grok-3 Fast, Grok-3 Mini, Grok-3 Mini Fast, Grok-266 ** Claude**: Claude 4 Sonnet, Claude 4 Opus, Claude 3.7 Sonnet, Claude 3.5 Sonnet, Claude 3 Opus67 ** DeepSeek**: DeepSeek V368 ** Google Gemini**: Gemini 2.0 Flash, Gemini 2.0 Flash-Lite, Gemini 1.5 Pro, Gemini 1.5 Flash63 **Anthropic Claude**: Claude Sonnet 4.5, Claude Opus 4.1, Claude Haiku 4.5, Claude 4 Sonnet, Claude 4 Opus, Claude 3.7 Sonnet, Claude 3.5 Sonnet, Claude 3 Opus 64 **X.AI**: Grok-4, Grok-3, Grok-3 Fast, Grok-3 Mini, Grok-3 Mini Fast, Grok-2 65 **Google Gemini**: Gemini 2.0 Flash, Gemini 2.0 Flash-Lite, Gemini 1.5 Pro, Gemini 1.5 Flash 66 **DeepSeek**: DeepSeek V3 69 67 70 68 ## Supercharge Your eCommerce with AI … … 133 131 134 132 **Service Providers:** 133 - [OpenRouter](https://openrouter.ai/) - [Terms](https://openrouter.ai/terms) | [Privacy](https://openrouter.ai/privacy) 135 134 - [OpenAI](https://openai.com/) - [Terms](https://openai.com/policies/terms-of-use/) | [Privacy](https://openai.com/policies/privacy-policy/) 136 135 - [Anthropic](https://anthropic.com/) - [Terms](https://www.anthropic.com/terms) | [Privacy](https://www.anthropic.com/privacy) … … 181 180 182 181 == Changelog == 182 183 = 2.4.8 - October 16, 2025 = 184 - New: OpenRouter integration - access 100+ AI models with a single API key 185 - New: Added Claude Sonnet 4.5, Claude Opus 4.1, and Claude Haiku 4.5 support 183 186 184 187 = 2.4.7 - October 13, 2025 = … … 556 559 == Upgrade Notice == 557 560 558 = 2.4. 7=559 - Security: Fixed Server-Side Request Forgery (SSRF) vulnerability in PDF processing (CVE-2025-10705) 561 = 2.4.8 = 562 Major update: OpenRouter integration with 100+ models and new Claude Sonnet 4.5, Opus 4.1, and Haiku 4.5 support 560 563 561 564 == License & Warranty ==
Note: See TracChangeset
for help on using the changeset viewer.