PluginProbe
MxChat – AI Chatbot & Content Generation for WordPress / 2.5.2
MxChat – AI Chatbot & Content Generation for WordPress v2.5.2
3.2.21 3.2.20 3.2.19 3.2.18 3.2.17 3.2.16 3.2.15 3.2.14 3.2.12 3.2.13 3.2.11 3.2.10 3.2.9 3.2.8 3.2.7 3.2.6 3.2.5 3.2.4 3.2.3 3.2.2 3.2.1 2.0.3 2.0.4 2.0.5 2.0.6 All 152 releases
← All changes | js/test-panel.js +64 -185 3.2.152.5.2 View file →
@@ -257,9 +257,9 @@
257 257
258 258 // NEW: Update approved URLs
259 259 this.updateApprovedUrls(testingData.approved_urls || []);
260 260
261 - this.updateTopMatches(testingData.top_matches || [], testingData.similarity_threshold || 0.75, testingData.sources_used || 0, testingData.total_chunks_used || 0);
261 + this.updateTopMatches(testingData.top_matches || [], testingData.similarity_threshold || 0.75);
262 262
263 263 // NEW: Update action matches
264 264 this.updateActionMatches(testingData.action_matches || []);
265 265
@@ -391,144 +391,60 @@
391 391
392 392 actionsEl.innerHTML = html;
393 393 }
394 394
395 - updateTopMatches(topMatches, threshold, sourcesUsed = 0, totalChunksUsed = 0) {
395 + updateTopMatches(topMatches, threshold) {
396 396 const scoresEl = this.panel.querySelector('#similarity-scores');
397 -
397 +
398 398 if (!topMatches || topMatches.length === 0) {
399 399 scoresEl.innerHTML = '<div class="no-data-message">No similarity data available</div>';
400 400 return;
401 401 }
402 -
403 - // Group matches by source URL
404 - const groupedByUrl = {};
405 - topMatches.forEach((match) => {
406 - const url = match.source_display || 'Unknown';
407 - if (!groupedByUrl[url]) {
408 - groupedByUrl[url] = {
409 - url: url,
410 - isUrl: url.startsWith('http'),
411 - bestScore: 0,
412 - usedForContext: false,
413 - totalChunks: match.total_chunks || 1,
414 - matchedChunks: [],
415 - isChunked: match.is_chunk || false
416 - };
417 - }
418 -
419 - // Track best score
420 - if (match.similarity_percentage > groupedByUrl[url].bestScore) {
421 - groupedByUrl[url].bestScore = match.similarity_percentage;
422 - }
423 -
424 - // Track if any chunk was used for context
425 - if (match.used_for_context) {
426 - groupedByUrl[url].usedForContext = true;
427 - }
428 -
429 - // Add chunk info
430 - groupedByUrl[url].matchedChunks.push({
431 - chunkIndex: match.chunk_index,
432 - score: match.similarity_percentage,
433 - usedForContext: match.used_for_context,
434 - aboveThreshold: match.above_threshold
435 - });
436 - });
437 -
438 - // Convert to array and sort by best score
439 - const urlGroups = Object.values(groupedByUrl).sort((a, b) => b.bestScore - a.bestScore);
440 -
441 - // Use backend counts if available, otherwise fall back to frontend calculation
442 - const usedUrlCount = sourcesUsed > 0 ? sourcesUsed : urlGroups.filter(g => g.usedForContext).length;
443 - const chunksInfo = totalChunksUsed > 0 ? `${totalChunksUsed} chunks sent to AI` : `${topMatches.length} chunk matches`;
444 -
402 +
445 403 let html = `<div class="matches-header">
446 - <strong>${usedUrlCount} source${usedUrlCount === 1 ? '' : 's'} used for AI context</strong>
447 - <span class="matches-subheader">(${chunksInfo})</span>
404 + <strong>Top ${topMatches.length} matches</strong>
448 405 </div>`;
449 -
450 - urlGroups.forEach((group, groupIndex) => {
451 - const cardClass = group.usedForContext ? 'above-threshold' : 'below-threshold';
452 - const statusIcon = group.usedForContext ? '✓' : '✗';
453 - const contextLabel = group.usedForContext ? 'Used for AI context' : 'Not used';
454 -
455 - // Build chunk summary
456 - let chunkSummary = '';
457 - if (group.isChunked && group.totalChunks > 1) {
458 - const usedChunkCount = group.matchedChunks.filter(c => c.usedForContext).length;
459 - chunkSummary = `<span class="chunk-summary">${usedChunkCount}/${group.totalChunks} chunks matched</span>`;
406 +
407 + topMatches.forEach((match, index) => {
408 + const isAboveThreshold = match.above_threshold;
409 + const isUsedForContext = match.used_for_context; // Use the actual flag from PHP
410 + const statusIcon = isAboveThreshold ? '✓' : '✗';
411 +
412 + // Determine the correct label based on actual usage
413 + let contextLabel;
414 + if (isUsedForContext) {
415 + contextLabel = 'Used for AI context';
416 + } else if (isAboveThreshold) {
417 + contextLabel = 'Above threshold (not used)';
418 + } else {
419 + contextLabel = 'Below threshold';
460 420 }
461 -
462 - // Check if this entry has multiple matched chunks to show expand toggle
463 - const hasMultipleChunks = group.matchedChunks.length > 1;
464 - const expandToggle = hasMultipleChunks
465 - ? `<span class="chunk-expand-toggle" data-group="${groupIndex}">▶ Show chunks</span>`
466 - : '';
467 -
421 +
422 + // Determine card styling - should be based on whether it was actually used
423 + const cardClass = isUsedForContext ? 'above-threshold' : 'below-threshold';
424 +
468 425 html += `
469 426 <div class="match-card ${cardClass}">
470 427 <div class="match-header">
471 428 <div class="match-title">
472 429 <span class="status-icon">${statusIcon}</span>
473 - <span class="similarity-score">${group.bestScore}%</span>
474 - ${chunkSummary}
430 + <span class="similarity-score">${match.similarity_percentage}%</span>
475 431 </div>
476 432 <span class="context-label">${contextLabel}</span>
477 433 </div>
478 434 <div class="match-source">
479 - ${group.isUrl ?
480 - `<span class="source-icon link-icon">🔗</span> ${group.url}` :
481 - `<span class="source-icon doc-icon">📄</span> ${group.url}`
435 + ${match.source_display.startsWith('http') ?
436 + `<span class="source-icon link-icon">🔗</span> ${match.source_display}` :
437 + `<span class="source-icon doc-icon">📄</span> ${match.source_display}`
482 438 }
483 439 </div>
484 - ${expandToggle}
485 - ${hasMultipleChunks ? this.renderChunkDetails(group.matchedChunks, groupIndex) : ''}
486 440 </div>
487 441 `;
488 442 });
489 -
443 +
490 444 scoresEl.innerHTML = html;
491 -
492 - // Add click handlers for expand toggles
493 - scoresEl.querySelectorAll('.chunk-expand-toggle').forEach(toggle => {
494 - toggle.addEventListener('click', (e) => {
495 - const groupId = e.target.dataset.group;
496 - const details = scoresEl.querySelector(`.chunk-details[data-group="${groupId}"]`);
497 - if (details) {
498 - const isExpanded = details.classList.toggle('expanded');
499 - e.target.textContent = isExpanded ? '▼ Hide chunks' : '▶ Show chunks';
500 - }
501 - });
502 - });
503 445 }
504 446
505 - renderChunkDetails(chunks, groupIndex) {
506 - // Sort chunks by chunk index
507 - const sortedChunks = [...chunks].sort((a, b) => (a.chunkIndex || 0) - (b.chunkIndex || 0));
508 -
509 - let html = `<div class="chunk-details" data-group="${groupIndex}">`;
510 -
511 - sortedChunks.forEach(chunk => {
512 - const chunkNum = (chunk.chunkIndex !== null && chunk.chunkIndex !== undefined)
513 - ? chunk.chunkIndex + 1
514 - : '?';
515 - const statusClass = chunk.usedForContext ? 'chunk-used' : 'chunk-not-used';
516 - const statusIcon = chunk.usedForContext ? '✓' : '○';
517 -
518 - html += `
519 - <div class="chunk-detail-row ${statusClass}">
520 - <span class="chunk-detail-icon">${statusIcon}</span>
521 - <span class="chunk-detail-num">Chunk ${chunkNum}</span>
522 - <span class="chunk-detail-score">${chunk.score}%</span>
523 - </div>
524 - `;
525 - });
526 -
527 - html += '</div>';
528 - return html;
529 - }
530 -
531 447 updateLastQuery(query, topMatches) {
532 448 const queryEl = this.panel.querySelector('#last-query');
533 449 queryEl.textContent = query;
534 450
@@ -539,49 +455,28 @@
539 455 };
540 456 }
541 457
542 458 clearChatSession() {
543 - // Determine the active bot ID from MxChatInstances
544 - let botId = 'default';
545 - if (typeof MxChatInstances !== 'undefined' && typeof MxChatInstances.getAllBotIds === 'function') {
546 - const botIds = MxChatInstances.getAllBotIds();
547 - if (botIds.length > 0) {
548 - botId = botIds[0];
549 - }
550 - }
551 -
552 - // Get current session ID using the correct bot-suffixed cookie name
553 - const cookieName = 'mxchat_session_id_' + botId;
554 - const sessionId = this.getCookie(cookieName) || this.getCookie('mxchat_session_id') || this.getCurrentSessionId();
555 -
459 + // Get current session ID from cookie (most reliable)
460 + const sessionId = this.getCookie('mxchat_session_id') || this.getCurrentSessionId();
461 +
556 462 if (!sessionId) {
557 - this.log('No active session found');
463 + this.log('❌ No active session found');
558 464 return;
559 465 }
560 -
561 - this.log('Current session ID: ' + sessionId);
562 - this.log('Starting fresh session...');
563 -
564 - // Use MxChatInstances.resetChatSession to properly reset in-memory state + cookie
565 - if (typeof MxChatInstances !== 'undefined' && typeof MxChatInstances.resetChatSession === 'function') {
566 - MxChatInstances.resetChatSession(botId);
567 - }
568 -
569 - // Get the new session ID that was just set by resetChatSession
570 - let newSessionId = '';
571 - if (typeof MxChatInstances !== 'undefined' && typeof MxChatInstances.getChatSession === 'function') {
572 - newSessionId = MxChatInstances.getChatSession(botId);
573 - }
574 -
575 - // Fallback if MxChatInstances wasn't available
576 - if (!newSessionId) {
577 - newSessionId = 'mxchat_chat_' + Math.random().toString(36).substr(2, 9);
578 - this.clearMxChatCookie(botId);
579 - this.setChatSession(newSessionId, botId);
580 - }
581 -
582 - this.log('New session ID: ' + newSessionId);
583 -
466 +
467 + this.log(`🔍 Current session ID: ${sessionId}`);
468 + this.log('🧹 Starting fresh session...');
469 +
470 + // Generate new session ID (using your existing format)
471 + const newSessionId = 'mxchat_chat_' + Math.random().toString(36).substr(2, 9);
472 +
473 + // Clear the old cookie and set new one immediately
474 + this.clearMxChatCookie();
475 + this.setChatSession(newSessionId);
476 +
477 + this.log(`🆕 New session ID: ${newSessionId}`);
478 +
584 479 // Call backend to clear old session data
585 480 fetch(mxchatTestData.ajaxUrl, {
586 481 method: 'POST',
587 482 headers: {
@@ -596,36 +491,36 @@
596 491 })
597 492 .then(response => response.json())
598 493 .then(data => {
599 494 if (data.success) {
600 - this.log('Backend session cleared: ' + data.data.message);
601 -
495 + this.log('✅ Backend session cleared: ' + data.data.message);
496 +
602 497 // Update the session ID everywhere in the DOM
603 498 this.updateSessionIdEverywhere(newSessionId);
604 -
499 +
605 500 // Clear the chat UI
606 501 this.clearChatUI();
607 -
502 +
608 503 // Show popular questions again
609 504 const popularQuestions = document.querySelector('#mxchat-popular-questions');
610 505 if (popularQuestions) {
611 506 popularQuestions.style.display = 'block';
612 507 }
613 -
508 +
614 509 // Clear testing data displays
615 510 this.updateLastQuery('New session started', []);
616 511 this.updateTopMatches([], 0);
617 512 this.updateApprovedUrls([]);
618 -
619 - this.log('Fresh session started successfully');
620 -
513 +
514 + this.log('🎉 Fresh session started successfully');
515 +
621 516 } else {
622 - this.log('Error clearing session: ' + (data.data?.message || 'Unknown error'));
517 + this.log('❌ Error clearing session: ' + (data.data?.message || 'Unknown error'));
623 518 }
624 519 })
625 520 .catch(error => {
626 521 console.error('Error clearing chat session:', error);
627 - this.log('Connection error when clearing session');
522 + this.log('🔌 Connection error when clearing session');
628 523 });
629 524 }
630 525
631 526 // Helper function to get cookie (same as your existing one)
@@ -634,21 +529,19 @@
634 529 let parts = value.split("; " + name + "=");
635 530 if (parts.length == 2) return parts.pop().split(";").shift();
636 531 }
637 532
638 - // Helper function to set session cookie (matches chat-script.js format)
639 - setChatSession(sessionId, botId) {
640 - botId = botId || 'default';
641 - document.cookie = 'mxchat_session_id_' + botId + '=' + sessionId + '; path=/; max-age=86400; SameSite=Lax';
533 + // Helper function to set session cookie (same as your existing one)
534 + setChatSession(sessionId) {
535 + // Set the cookie with a 24-hour expiration (86400 seconds)
536 + document.cookie = "mxchat_session_id=" + sessionId + "; path=/; max-age=86400; SameSite=Lax";
642 537 }
643 538
644 539 // Helper function to clear the MxChat session cookie
645 - clearMxChatCookie(botId) {
646 - botId = botId || 'default';
647 - // Clear both bot-suffixed and legacy cookie formats
648 - document.cookie = 'mxchat_session_id_' + botId + '=; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT; SameSite=Lax';
649 - document.cookie = 'mxchat_session_id=; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT; SameSite=Lax';
650 - this.log('Session cookie cleared');
540 + clearMxChatCookie() {
541 + // Clear the cookie by setting it to expire in the past
542 + document.cookie = "mxchat_session_id=; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT; SameSite=Lax";
543 + this.log('🍪 Session cookie cleared');
651 544 }
652 545
653 546 updateSessionIdEverywhere(newSessionId) {
654 547 // Update global session ID variable if it exists
@@ -707,23 +600,9 @@
707 600 }
708 601 }
709 602
710 603 getCurrentSessionId() {
711 - // Try MxChatInstances first (most reliable — matches chat-script.js)
712 - if (typeof MxChatInstances !== 'undefined' && typeof MxChatInstances.getChatSession === 'function') {
713 - const botIds = typeof MxChatInstances.getAllBotIds === 'function' ? MxChatInstances.getAllBotIds() : ['default'];
714 - const botId = botIds.length > 0 ? botIds[0] : 'default';
715 - const instanceSession = MxChatInstances.getChatSession(botId);
716 - if (instanceSession) {
717 - return instanceSession;
718 - }
719 - }
720 -
721 - // Try bot-suffixed cookie, then legacy cookie
722 - const botCookieId = this.getCookie('mxchat_session_id_default');
723 - if (botCookieId) {
724 - return botCookieId;
725 - }
604 + // First try to get from cookie (most reliable)
726 605 const cookieSessionId = this.getCookie('mxchat_session_id');
727 606 if (cookieSessionId) {
728 607 return cookieSessionId;
729 608 }