| @@ -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 | } |