| @@ -283,8 +283,27 @@ | ||
| 283 | 283 | mxchat_render_knowledge_page_scripts(); |
| 284 | 284 | } |
| 285 | 285 | |
| 286 | 286 | /** |
| 287 | + * Whether the selected bot answers from the WordPress database (plan 1f39d9). | |
| 288 | + * That store is one table every bot reads. A bot has knowledge of its own only | |
| 289 | + * on Pinecone (its own host or namespace) or an OpenAI Vector Store, so the | |
| 290 | + * selector must not promise a per-bot knowledge base here. | |
| 291 | + */ | |
| 292 | +function mxchat_knowledge_bot_uses_shared_database($bot_id) { | |
| 293 | + $pinecone = class_exists('MxChat_Pinecone_Documents') ? MxChat_Pinecone_Documents::config($bot_id) : array(); | |
| 294 | + if (!empty($pinecone['use_pinecone'])) { | |
| 295 | + return false; | |
| 296 | + } | |
| 297 | + $vectorstore_options = get_option('mxchat_openai_vectorstore_options', array()); | |
| 298 | + $vectorstore = apply_filters('mxchat_get_bot_vectorstore_config', array( | |
| 299 | + 'use_vectorstore' => (is_array($vectorstore_options) ? ($vectorstore_options['mxchat_use_openai_vectorstore'] ?? '0') : '0') === '1', | |
| 300 | + 'vectorstore_ids' => is_array($vectorstore_options) ? ($vectorstore_options['mxchat_vectorstore_ids'] ?? '') : '', | |
| 301 | + ), $bot_id); | |
| 302 | + return empty($vectorstore['use_vectorstore']); | |
| 303 | +} | |
| 304 | + | |
| 305 | +/** | |
| 287 | 306 | * Render Multi-Bot Selector |
| 288 | 307 | */ |
| 289 | 308 | function mxchat_render_knowledge_bot_selector($multibot_active, $current_bot_id) { |
| 290 | 309 | if (!$multibot_active || !class_exists('MxChat_Multi_Bot_Manager')) { |
| @@ -307,9 +326,15 @@ | ||
| 307 | 326 | </option> |
| 308 | 327 | <?php endforeach; ?> |
| 309 | 328 | </select> |
| 310 | 329 | <span style="color: var(--mxch-text-secondary); font-size: 13px;"> |
| 311 | - <?php esc_html_e('Content will be added to the selected bot\'s knowledge base', 'mxchat'); ?> | |
| 330 | + <?php | |
| 331 | + if (mxchat_knowledge_bot_uses_shared_database($current_bot_id)) { | |
| 332 | + esc_html_e('This bot answers from the WordPress database, which is shared with all bots: content added here is available to every bot that uses it. A bot gets a knowledge base of its own on Pinecone (its own host or namespace) or an OpenAI Vector Store.', 'mxchat'); | |
| 333 | + } else { | |
| 334 | + esc_html_e('Content will be added to the selected bot\'s knowledge base', 'mxchat'); | |
| 335 | + } | |
| 336 | + ?> | |
| 312 | 337 | </span> |
| 313 | 338 | <span id="mxchat-bot-save-status" style="display: none; color: var(--mxch-success); font-size: 13px;"> |
| 314 | 339 | ✓ <?php esc_html_e('Saved', 'mxchat'); ?> |
| 315 | 340 | </span> |
| @@ -439,8 +464,20 @@ | ||
| 439 | 464 | $required_key_type = 'Voyage AI'; |
| 440 | 465 | } elseif (strpos($embedding_model, 'gemini-embedding-') !== false) { |
| 441 | 466 | $required_key_type = 'Google Gemini'; |
| 442 | 467 | } |
| 468 | + | |
| 469 | + // Custom Provider embeddings (plan 418afd): the dropdown above is disabled | |
| 470 | + // on such a site and no OpenAI, Voyage or Gemini key is needed. Ask the | |
| 471 | + // same pre-flight the importers ask, so this notice cannot disagree with them. | |
| 472 | + $embeds_with_custom_provider = is_array($options) && isset($options['custom_provider_for_embeddings']) && $options['custom_provider_for_embeddings'] === 'on'; | |
| 473 | + $custom_embedding_blocker = ''; | |
| 474 | + if ($embeds_with_custom_provider) { | |
| 475 | + $custom_preflight = MxChat_Utils::embedding_preflight($options); | |
| 476 | + $has_required_key = !empty($custom_preflight['ok']); | |
| 477 | + $required_key_type = 'Custom Provider'; | |
| 478 | + $custom_embedding_blocker = (string) ($custom_preflight['reason'] ?? ''); | |
| 479 | + } | |
| 443 | 480 | ?> |
| 444 | 481 | <div id="import-options" class="mxch-section active"> |
| 445 | 482 | <div class="mxch-content-header"> |
| 446 | 483 | <h1 class="mxch-content-title"><?php esc_html_e('Import Options', 'mxchat'); ?></h1> |
| @@ -456,9 +493,18 @@ | ||
| 456 | 493 | <path d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3Z"/><line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/> |
| 457 | 494 | <?php endif; ?> |
| 458 | 495 | </svg> |
| 459 | 496 | <div> |
| 460 | - <?php if ($has_required_key): ?> | |
| 497 | + <?php if ($embeds_with_custom_provider && $has_required_key): ?> | |
| 498 | + <?php | |
| 499 | + /* translators: %s: the embedding model name configured on the Custom Provider */ | |
| 500 | + printf(esc_html__('Knowledge is embedded through your Custom Provider (model: %s). No OpenAI, Voyage AI or Google Gemini key is needed for imports.', 'mxchat'), esc_html(MxChat_Utils::resolve_custom_embedding_model($options))); | |
| 501 | + ?> | |
| 502 | + <?php elseif ($embeds_with_custom_provider): ?> | |
| 503 | + <strong><?php esc_html_e('Important:', 'mxchat'); ?></strong> | |
| 504 | + <?php echo esc_html($custom_embedding_blocker); ?> | |
| 505 | + <a href="<?php echo admin_url('admin.php?page=mxchat-max#api-keys'); ?>"><?php esc_html_e('Go to API Key Settings', 'mxchat'); ?></a> | |
| 506 | + <?php elseif ($has_required_key): ?> | |
| 461 | 507 | <?php echo wp_kses_post(sprintf(__('We detected your %s API key. <strong>Remember to add credits to your %s account</strong> before using the knowledgebase.', 'mxchat'), $required_key_type, $required_key_type)); ?> |
| 462 | 508 | <?php else: ?> |
| 463 | 509 | <strong><?php esc_html_e('Important:', 'mxchat'); ?></strong> |
| 464 | 510 | <?php echo sprintf(esc_html__('Before importing knowledge, you must add a %s API key with sufficient credits in the Chatbot settings.', 'mxchat'), $required_key_type); ?> |
| @@ -675,8 +721,14 @@ | ||
| 675 | 721 | </div> |
| 676 | 722 | <p class="mxch-field-description"> |
| 677 | 723 | <?php esc_html_e('Select a PDF file from your computer to import into the knowledge base. Maximum file size depends on your server settings.', 'mxchat'); ?> |
| 678 | 724 | </p> |
| 725 | + <div class="mxch-field"> | |
| 726 | + <input type="url" name="source_page_url" id="mxchat-pdf-source-url" class="mxch-input" placeholder="<?php esc_attr_e('Enter source URL (Optional)', 'mxchat'); ?>"> | |
| 727 | + <p class="mxch-field-description"> | |
| 728 | + <?php esc_html_e('The page this PDF lives on. Answers drawn from it link to that page. Leave empty and answers name the file and page without a link.', 'mxchat'); ?> | |
| 729 | + </p> | |
| 730 | + </div> | |
| 679 | 731 | <button type="submit" name="submit_pdf_file" class="mxch-btn mxch-btn-primary"> |
| 680 | 732 | <?php esc_html_e('Import PDF', 'mxchat'); ?> |
| 681 | 733 | </button> |
| 682 | 734 | </form> |
| @@ -693,8 +745,14 @@ | ||
| 693 | 745 | </div> |
| 694 | 746 | <p class="mxch-field-description"> |
| 695 | 747 | <?php esc_html_e('Select a .docx, .txt, or .md file to import into the knowledge base. The text is extracted and indexed; the file itself is not stored. Re-uploading a file with the same name replaces its previous content.', 'mxchat'); ?> |
| 696 | 748 | </p> |
| 749 | + <div class="mxch-field"> | |
| 750 | + <input type="url" name="source_page_url" id="mxchat-document-source-url" class="mxch-input" placeholder="<?php esc_attr_e('Enter source URL (Optional)', 'mxchat'); ?>"> | |
| 751 | + <p class="mxch-field-description"> | |
| 752 | + <?php esc_html_e('The page this document lives on. Answers drawn from it link to that page. Leave empty and answers name the file without a link.', 'mxchat'); ?> | |
| 753 | + </p> | |
| 754 | + </div> | |
| 697 | 755 | <button type="submit" name="submit_document_file" class="mxch-btn mxch-btn-primary"> |
| 698 | 756 | <?php esc_html_e('Import Document', 'mxchat'); ?> |
| 699 | 757 | </button> |
| 700 | 758 | </form> |
| @@ -1329,13 +1387,85 @@ | ||
| 1329 | 1387 | <?php endif; ?> |
| 1330 | 1388 | </div> |
| 1331 | 1389 | </div> |
| 1332 | 1390 | </div> |
| 1391 | + | |
| 1392 | + <?php mxchat_render_kb_reimport_card(!empty($current_bot_id) ? $current_bot_id : 'default'); ?> | |
| 1333 | 1393 | </div> |
| 1334 | 1394 | <?php |
| 1335 | 1395 | } |
| 1336 | 1396 | |
| 1337 | 1397 | /** |
| 1398 | + * "Re-import affected entries" card (plan 89739b). | |
| 1399 | + * | |
| 1400 | + * The owner-facing side of wp mxchat kb-reimport: check first (no embedding | |
| 1401 | + * request, nothing written), read the list, then confirm. Both halves run in | |
| 1402 | + * resumable steps through the mxchat_kb_reimport AJAX action; the script is | |
| 1403 | + * js/knowledge-reimport.js. Everything dynamic is drawn there; this is the | |
| 1404 | + * resting markup. | |
| 1405 | + */ | |
| 1406 | +function mxchat_render_kb_reimport_card($current_bot_id = 'default') { | |
| 1407 | + if (!class_exists('MxChat_Knowledge_Manager')) { | |
| 1408 | + return; | |
| 1409 | + } | |
| 1410 | + ?> | |
| 1411 | + <div class="mxch-card mxch-kb-reimport" id="mxchat-kb-reimport" | |
| 1412 | + data-nonce="<?php echo esc_attr(wp_create_nonce('mxchat_kb_reimport')); ?>" | |
| 1413 | + data-bot="<?php echo esc_attr($current_bot_id); ?>"> | |
| 1414 | + <div class="mxch-card-header"> | |
| 1415 | + <h3 class="mxch-card-title"> | |
| 1416 | + <svg class="mxch-card-title-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="23 4 23 10 17 10"/><polyline points="1 20 1 14 7 14"/><path d="M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15"/></svg> | |
| 1417 | + <?php esc_html_e('Re-import affected entries', 'mxchat'); ?> | |
| 1418 | + </h3> | |
| 1419 | + </div> | |
| 1420 | + <div class="mxch-card-body"> | |
| 1421 | + <p class="mxch-field-description"><?php esc_html_e('Earlier versions stored some imported text incorrectly: currency signs and accents were dropped, HTML character codes were left in, and right-to-left PDF text was saved backwards. This finds the entries that still hold that text and rebuilds them from their source. Checking changes nothing.', 'mxchat'); ?></p> | |
| 1422 | + | |
| 1423 | + <div class="mxch-kb-reimport-controls"> | |
| 1424 | + <div class="mxch-field"> | |
| 1425 | + <label class="mxch-field-label" for="mxchat-kb-reimport-before"><?php esc_html_e('Entries last written before', 'mxchat'); ?></label> | |
| 1426 | + <input type="date" id="mxchat-kb-reimport-before" class="mxch-input mxch-input-sm" value="<?php echo esc_attr(MxChat_Knowledge_Manager::REIMPORT_DEFAULT_BEFORE); ?>" max="<?php echo esc_attr(gmdate('Y-m-d', time() + DAY_IN_SECONDS)); ?>" /> | |
| 1427 | + </div> | |
| 1428 | + <button type="button" class="mxch-btn mxch-btn-secondary" id="mxchat-kb-reimport-check"><?php esc_html_e('Check knowledge base', 'mxchat'); ?></button> | |
| 1429 | + </div> | |
| 1430 | + <p class="mxch-field-hint"><?php esc_html_e('The date is the release that carried the last of these fixes. Choose a later one if this site was updated after that.', 'mxchat'); ?></p> | |
| 1431 | + | |
| 1432 | + <div class="mxch-kb-reimport-progress" hidden> | |
| 1433 | + <div class="mxch-progress-bar" hidden><div class="mxch-progress-bar-fill"></div></div> | |
| 1434 | + <p class="mxch-progress-label" aria-live="polite"></p> | |
| 1435 | + </div> | |
| 1436 | + | |
| 1437 | + <div class="mxch-notice mxch-notice-error mxch-kb-reimport-error" role="alert" hidden> | |
| 1438 | + <svg class="mxch-notice-icon" xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/></svg> | |
| 1439 | + <span></span> | |
| 1440 | + </div> | |
| 1441 | + | |
| 1442 | + <div class="mxch-kb-reimport-results" hidden> | |
| 1443 | + <div class="mxch-notice mxch-notice-success mxch-kb-reimport-done" hidden> | |
| 1444 | + <svg class="mxch-notice-icon" xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/><polyline points="22 4 12 14.01 9 11.01"/></svg> | |
| 1445 | + <span></span> | |
| 1446 | + </div> | |
| 1447 | + <div class="mxch-kb-reimport-counts"></div> | |
| 1448 | + <ul class="mxch-kb-reimport-list mxch-kb-reimport-entries" hidden></ul> | |
| 1449 | + <p class="mxch-field-hint mxch-kb-reimport-more" hidden></p> | |
| 1450 | + <details class="mxch-disclosure mxch-kb-reimport-others" hidden> | |
| 1451 | + <summary class="mxch-disclosure-summary"><span class="mxch-disclosure-summary-text"></span><span class="mxch-disclosure-summary-hint"><?php esc_html_e('Never changed or removed by this tool', 'mxchat'); ?></span></summary> | |
| 1452 | + <div class="mxch-disclosure-body"> | |
| 1453 | + <ul class="mxch-kb-reimport-list mxch-kb-reimport-notes"></ul> | |
| 1454 | + </div> | |
| 1455 | + </details> | |
| 1456 | + </div> | |
| 1457 | + </div> | |
| 1458 | + <div class="mxch-card-footer mxch-kb-reimport-footer" hidden> | |
| 1459 | + <button type="button" class="mxch-btn mxch-btn-primary" id="mxchat-kb-reimport-apply"></button> | |
| 1460 | + <button type="button" class="mxch-btn mxch-btn-ghost" id="mxchat-kb-reimport-clear"><?php esc_html_e('Clear', 'mxchat'); ?></button> | |
| 1461 | + <span class="mxch-field-hint mxch-kb-reimport-cost"><?php esc_html_e('Each rewritten entry is embedded again with your embedding provider.', 'mxchat'); ?></span> | |
| 1462 | + </div> | |
| 1463 | + </div> | |
| 1464 | + <?php | |
| 1465 | +} | |
| 1466 | + | |
| 1467 | +/** | |
| 1338 | 1468 | * Render Auto-Sync Section |
| 1339 | 1469 | */ |
| 1340 | 1470 | function mxchat_render_auto_sync_section($knowledge_manager) { |
| 1341 | 1471 | ?> |
| @@ -1888,9 +2018,18 @@ | ||
| 1888 | 2018 | </div> |
| 1889 | 2019 | <script type="application/json" id="mxchat-pinecone-docs-state"><?php echo wp_json_encode(array( |
| 1890 | 2020 | 'verified_host' => $pc_verified, |
| 1891 | 2021 | 'expected_dimension' => (int) $pc_expected_dim, |
| 2022 | + // 47c61f: the status notice's two texts, so the page can | |
| 2023 | + // keep it in step with the host typed in the field. | |
| 2024 | + 'status_checked' => __('Document index checked: %1$s (%2$d dimensions).', 'mxchat'), | |
| 2025 | + 'status_unchecked' => __('Not checked yet. Create a document index below, or enter its host above and click Check index. The index type only saves once the host has been checked.', 'mxchat'), | |
| 1892 | 2026 | 'migration' => $pc_migration, |
| 2027 | + // 3e83e4: what the LIVE chatbot is on right now, so the | |
| 2028 | + // page can tell a copy-in-progress from a switch. | |
| 2029 | + 'index_type' => $pc_index_type, | |
| 2030 | + 'stored_host' => strtolower(trim((string) $pc_current_host, '/')), | |
| 2031 | + 'stored_index' => (string) ($pinecone_options['mxchat_pinecone_index'] ?? ''), | |
| 1893 | 2032 | )); ?></script> |
| 1894 | 2033 | |
| 1895 | 2034 | <div class="mxch-field"> |
| 1896 | 2035 | <label class="mxch-field-label" for="mxchat_pinecone_environment"><?php esc_html_e('Region', 'mxchat'); ?></label> |
| @@ -1940,9 +2079,9 @@ | ||
| 1940 | 2079 | <option value="<?php echo esc_attr($pc_lang_key); ?>" <?php selected($pc_docs_lang, $pc_lang_key); ?>><?php echo esc_html($pc_lang_label); ?></option> |
| 1941 | 2080 | <?php endforeach; ?> |
| 1942 | 2081 | </select> |
| 1943 | 2082 | </div> |
| 1944 | - <p class="mxch-field-description"><?php printf(esc_html__('Create index for me makes a new document index named after the Index Name field, sized for your embedding model (%d dimensions, cosine), with full-text search on the content in the chosen language, then fills in the host. Check index confirms the host above points at a document index MxChat can use.', 'mxchat'), (int) $pc_expected_dim); ?></p> | |
| 2083 | + <p class="mxch-field-description"><?php printf(esc_html__('Create index for me makes a new document index named after the Index Name field (a free name ending in -docs is suggested when you switch to this type), sized for your embedding model (%d dimensions, cosine), with full-text search on the content in the chosen language, then fills in the host. Check index confirms the host above points at a document index MxChat can use. Neither moves your chatbot — that happens when you save.', 'mxchat'), (int) $pc_expected_dim); ?></p> | |
| 1945 | 2084 | </div> |
| 1946 | 2085 | |
| 1947 | 2086 | <div class="mxch-field" style="display: flex; gap: 8px; flex-wrap: wrap;"> |
| 1948 | 2087 | <button type="button" class="mxch-btn mxch-btn-secondary" id="mxchat-pinecone-docs-create"><?php esc_html_e('Create index for me', 'mxchat'); ?></button> |
| @@ -1949,16 +2088,29 @@ | ||
| 1949 | 2088 | <button type="button" class="mxch-btn mxch-btn-secondary" id="mxchat-pinecone-docs-check"><?php esc_html_e('Check index', 'mxchat'); ?></button> |
| 1950 | 2089 | </div> |
| 1951 | 2090 | <div id="mxchat-pinecone-docs-result" style="display: none;"></div> |
| 1952 | 2091 | <p class="mxch-field-hint" id="mxchat-pinecone-docs-gate" style="display: none;"><?php esc_html_e('Check the document index host before saving.', 'mxchat'); ?></p> |
| 2092 | + <div class="mxch-field" id="mxchat-pinecone-docs-switch-gate" style="display: none;"> | |
| 2093 | + <p class="mxch-field-hint" id="mxchat-pinecone-docs-switch-gate-text"></p> | |
| 2094 | + <label class="mxch-field-hint" style="display: flex; align-items: center; gap: 8px; cursor: pointer;"> | |
| 2095 | + <input type="checkbox" id="mxchat_pinecone_docs_switch_anyway" name="mxchat_pinecone_addon_options[mxchat_pinecone_docs_switch_anyway]" value="1"> | |
| 2096 | + <span><?php esc_html_e('Switch anyway — point the chatbot at the document index now and copy the rest afterwards', 'mxchat'); ?></span> | |
| 2097 | + </label> | |
| 2098 | + </div> | |
| 1953 | 2099 | |
| 1954 | 2100 | <div class="mxch-field" style="margin-top: 20px;"> |
| 1955 | 2101 | <label class="mxch-field-label" for="mxchat_pinecone_vector_host"><?php esc_html_e('Copy from vector index host', 'mxchat'); ?></label> |
| 1956 | 2102 | <input type="text" id="mxchat_pinecone_vector_host" name="mxchat_pinecone_addon_options[mxchat_pinecone_vector_host]" value="<?php echo esc_attr($pc_vector_host); ?>" class="mxch-input" placeholder="my-index-xyz123.svc.pinecone.io"> |
| 1957 | - <p class="mxch-field-description"><?php esc_html_e('Migrate copies every record of that index into the document index — text, vector and metadata, same ids — with no embedding calls. Safe to run again: records already copied are simply replaced. Both indexes must use the same embedding dimension.', 'mxchat'); ?></p> | |
| 2103 | + <p class="mxch-field-description"><?php esc_html_e('Migrate copies every record of that index into the document index above — text, vector and metadata, same ids — with no embedding calls. It runs while your chatbot keeps answering from the vector index; save the Pinecone settings afterwards to switch. Safe to run again: records already copied are simply replaced, and an interrupted copy continues where it stopped. Both indexes must use the same embedding dimension.', 'mxchat'); ?></p> | |
| 1958 | 2104 | </div> |
| 1959 | 2105 | <div class="mxch-field" style="display: flex; gap: 12px; align-items: center; flex-wrap: wrap;"> |
| 1960 | 2106 | <button type="button" class="mxch-btn mxch-btn-secondary" id="mxchat-pinecone-docs-migrate"><?php esc_html_e('Migrate', 'mxchat'); ?></button> |
| 2107 | + <?php /* e50d2e: offered only when the source index holds records in more than one namespace (the JS shows it from the start response). No name attribute — it is not a saved setting. */ ?> | |
| 2108 | + <label class="mxch-toggle" id="mxchat-pinecone-docs-all-namespaces" style="display: none;" title="<?php esc_attr_e('Copy the records of every namespace of the vector index, each into the same-named namespace of the document index, in one run.', 'mxchat'); ?>"> | |
| 2109 | + <input type="checkbox" class="mxch-toggle-input" id="mxchat_pinecone_docs_all_namespaces" value="1"> | |
| 2110 | + <span class="mxch-toggle-switch"></span> | |
| 2111 | + <span class="mxch-toggle-label"><?php esc_html_e('Copy every namespace', 'mxchat'); ?></span> | |
| 2112 | + </label> | |
| 1961 | 2113 | <span id="mxchat-pinecone-docs-migrate-counts" class="mxch-field-description"></span> |
| 1962 | 2114 | </div> |
| 1963 | 2115 | <div id="mxchat-pinecone-docs-migrate-progress" style="display: none; margin-bottom: 16px;"> |
| 1964 | 2116 | <div class="mxch-progress-bar"><div class="mxch-progress-bar-fill" style="width: 0%;"></div></div> |