| @@ -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 | |
| @@ -274,19 +274,8 @@ | ||
| 274 | 274 | // NEW: Log approved URLs count |
| 275 | 275 | if (testingData.approved_urls && testingData.approved_urls.length > 0) { |
| 276 | 276 | this.log(`🔗 Approved URLs for citations: ${testingData.approved_urls.length}`); |
| 277 | 277 | } |
| 278 | - | |
| 279 | - // 58f8b4: URL-guard outcome — stripping used to be completely silent, | |
| 280 | - // which is why fabricated/stripped links were invisible from this panel. | |
| 281 | - if (testingData.url_validation) { | |
| 282 | - const uv = testingData.url_validation; | |
| 283 | - if (uv.removed_count > 0) { | |
| 284 | - this.log(`🚫 URL guard stripped ${uv.removed_count} unapproved link${uv.removed_count !== 1 ? 's' : ''}: ${(uv.removed_urls || []).join(', ')}`); | |
| 285 | - } else if (uv.checked > 0) { | |
| 286 | - this.log(`🔗 URL guard: all ${uv.checked} link${uv.checked !== 1 ? 's' : ''} in the answer approved (${uv.strict ? 'strict' : 'lenient'} mode)`); | |
| 287 | - } | |
| 288 | - } | |
| 289 | 278 | |
| 290 | 279 | // Show summary in debug console |
| 291 | 280 | if (testingData.top_matches && testingData.top_matches.length > 0) { |
| 292 | 281 | const aboveThreshold = testingData.top_matches.filter(match => match.above_threshold).length; |
| @@ -402,9 +391,9 @@ | ||
| 402 | 391 | |
| 403 | 392 | actionsEl.innerHTML = html; |
| 404 | 393 | } |
| 405 | 394 | |
| 406 | - updateTopMatches(topMatches, threshold, sourcesUsed = 0, totalChunksUsed = 0) { | |
| 395 | + updateTopMatches(topMatches, threshold) { | |
| 407 | 396 | const scoresEl = this.panel.querySelector('#similarity-scores'); |
| 408 | 397 | |
| 409 | 398 | if (!topMatches || topMatches.length === 0) { |
| 410 | 399 | scoresEl.innerHTML = '<div class="no-data-message">No similarity data available</div>'; |
| @@ -410,12 +399,8 @@ | ||
| 410 | 399 | scoresEl.innerHTML = '<div class="no-data-message">No similarity data available</div>'; |
| 411 | 400 | return; |
| 412 | 401 | } |
| 413 | 402 | |
| 414 | - // Hybrid keyword boost (38ffa1): rows carry matched_via + fused_rank | |
| 415 | - // when hybrid retrieval was on for this message. | |
| 416 | - const hybridOn = topMatches.some(m => m.matched_via); | |
| 417 | - | |
| 418 | 403 | // Group matches by source URL |
| 419 | 404 | const groupedByUrl = {}; |
| 420 | 405 | topMatches.forEach((match) => { |
| 421 | 406 | const url = match.source_display || 'Unknown'; |
| @@ -426,11 +411,9 @@ | ||
| 426 | 411 | bestScore: 0, |
| 427 | 412 | usedForContext: false, |
| 428 | 413 | totalChunks: match.total_chunks || 1, |
| 429 | 414 | matchedChunks: [], |
| 430 | - isChunked: match.is_chunk || false, | |
| 431 | - bestFusedRank: Infinity, | |
| 432 | - viaSet: {} | |
| 415 | + isChunked: match.is_chunk || false | |
| 433 | 416 | }; |
| 434 | 417 | } |
| 435 | 418 | |
| 436 | 419 | // Track best score |
| @@ -442,15 +425,8 @@ | ||
| 442 | 425 | if (match.used_for_context) { |
| 443 | 426 | groupedByUrl[url].usedForContext = true; |
| 444 | 427 | } |
| 445 | 428 | |
| 446 | - if (match.fused_rank && match.fused_rank < groupedByUrl[url].bestFusedRank) { | |
| 447 | - groupedByUrl[url].bestFusedRank = match.fused_rank; | |
| 448 | - } | |
| 449 | - if (match.matched_via) { | |
| 450 | - groupedByUrl[url].viaSet[match.matched_via] = true; | |
| 451 | - } | |
| 452 | - | |
| 453 | 429 | // Add chunk info |
| 454 | 430 | groupedByUrl[url].matchedChunks.push({ |
| 455 | 431 | chunkIndex: match.chunk_index, |
| 456 | 432 | score: match.similarity_percentage, |
| @@ -458,23 +434,17 @@ | ||
| 458 | 434 | aboveThreshold: match.above_threshold |
| 459 | 435 | }); |
| 460 | 436 | }); |
| 461 | 437 | |
| 462 | - // Convert to array: fused-rank order when hybrid is on, best cosine otherwise | |
| 463 | - const urlGroups = Object.values(groupedByUrl).sort((a, b) => { | |
| 464 | - if (hybridOn && a.bestFusedRank !== b.bestFusedRank) { | |
| 465 | - return a.bestFusedRank - b.bestFusedRank; | |
| 466 | - } | |
| 467 | - return b.bestScore - a.bestScore; | |
| 468 | - }); | |
| 438 | + // Convert to array and sort by best score | |
| 439 | + const urlGroups = Object.values(groupedByUrl).sort((a, b) => b.bestScore - a.bestScore); | |
| 469 | 440 | |
| 470 | - // Use backend counts if available, otherwise fall back to frontend calculation | |
| 471 | - const usedUrlCount = sourcesUsed > 0 ? sourcesUsed : urlGroups.filter(g => g.usedForContext).length; | |
| 472 | - const chunksInfo = totalChunksUsed > 0 ? `${totalChunksUsed} chunks sent to AI` : `${topMatches.length} chunk matches`; | |
| 441 | + // Count unique URLs used for context | |
| 442 | + const usedUrlCount = urlGroups.filter(g => g.usedForContext).length; | |
| 473 | 443 | |
| 474 | 444 | let html = `<div class="matches-header"> |
| 475 | - <strong>${usedUrlCount} source${usedUrlCount === 1 ? '' : 's'} used for AI context</strong> | |
| 476 | - <span class="matches-subheader">(${chunksInfo})</span> | |
| 445 | + <strong>${usedUrlCount} entr${usedUrlCount === 1 ? 'y' : 'ies'} used for AI context</strong> | |
| 446 | + <span class="matches-subheader">(from ${topMatches.length} chunk matches)</span> | |
| 477 | 447 | </div>`; |
| 478 | 448 | |
| 479 | 449 | urlGroups.forEach((group, groupIndex) => { |
| 480 | 450 | const cardClass = group.usedForContext ? 'above-threshold' : 'below-threshold'; |
| @@ -493,18 +463,8 @@ | ||
| 493 | 463 | const expandToggle = hasMultipleChunks |
| 494 | 464 | ? `<span class="chunk-expand-toggle" data-group="${groupIndex}">▶ Show chunks</span>` |
| 495 | 465 | : ''; |
| 496 | 466 | |
| 497 | - let viaChip = ''; | |
| 498 | - if (hybridOn) { | |
| 499 | - const vias = Object.keys(group.viaSet); | |
| 500 | - if (vias.length) { | |
| 501 | - const viaLabel = (vias.length > 1 || vias[0] === 'both') ? 'Both' | |
| 502 | - : (vias[0] === 'keyword' ? 'Keyword' : 'Vector'); | |
| 503 | - viaChip = `<span class="mxch-rag-via-chip mxch-rag-via-${viaLabel.toLowerCase()}">${viaLabel}</span>`; | |
| 504 | - } | |
| 505 | - } | |
| 506 | - | |
| 507 | 467 | html += ` |
| 508 | 468 | <div class="match-card ${cardClass}"> |
| 509 | 469 | <div class="match-header"> |
| 510 | 470 | <div class="match-title"> |
| @@ -509,9 +469,8 @@ | ||
| 509 | 469 | <div class="match-header"> |
| 510 | 470 | <div class="match-title"> |
| 511 | 471 | <span class="status-icon">${statusIcon}</span> |
| 512 | 472 | <span class="similarity-score">${group.bestScore}%</span> |
| 513 | - ${viaChip} | |
| 514 | 473 | ${chunkSummary} |
| 515 | 474 | </div> |
| 516 | 475 | <span class="context-label">${contextLabel}</span> |
| 517 | 476 | </div> |
| @@ -579,49 +538,28 @@ | ||
| 579 | 538 | }; |
| 580 | 539 | } |
| 581 | 540 | |
| 582 | 541 | clearChatSession() { |
| 583 | - // Determine the active bot ID from MxChatInstances | |
| 584 | - let botId = 'default'; | |
| 585 | - if (typeof MxChatInstances !== 'undefined' && typeof MxChatInstances.getAllBotIds === 'function') { | |
| 586 | - const botIds = MxChatInstances.getAllBotIds(); | |
| 587 | - if (botIds.length > 0) { | |
| 588 | - botId = botIds[0]; | |
| 589 | - } | |
| 590 | - } | |
| 591 | - | |
| 592 | - // Get current session ID using the correct bot-suffixed cookie name | |
| 593 | - const cookieName = 'mxchat_session_id_' + botId; | |
| 594 | - const sessionId = this.getCookie(cookieName) || this.getCookie('mxchat_session_id') || this.getCurrentSessionId(); | |
| 595 | - | |
| 542 | + // Get current session ID from cookie (most reliable) | |
| 543 | + const sessionId = this.getCookie('mxchat_session_id') || this.getCurrentSessionId(); | |
| 544 | + | |
| 596 | 545 | if (!sessionId) { |
| 597 | - this.log('No active session found'); | |
| 546 | + this.log('❌ No active session found'); | |
| 598 | 547 | return; |
| 599 | 548 | } |
| 600 | - | |
| 601 | - this.log('Current session ID: ' + sessionId); | |
| 602 | - this.log('Starting fresh session...'); | |
| 603 | - | |
| 604 | - // Use MxChatInstances.resetChatSession to properly reset in-memory state + cookie | |
| 605 | - if (typeof MxChatInstances !== 'undefined' && typeof MxChatInstances.resetChatSession === 'function') { | |
| 606 | - MxChatInstances.resetChatSession(botId); | |
| 607 | - } | |
| 608 | - | |
| 609 | - // Get the new session ID that was just set by resetChatSession | |
| 610 | - let newSessionId = ''; | |
| 611 | - if (typeof MxChatInstances !== 'undefined' && typeof MxChatInstances.getChatSession === 'function') { | |
| 612 | - newSessionId = MxChatInstances.getChatSession(botId); | |
| 613 | - } | |
| 614 | - | |
| 615 | - // Fallback if MxChatInstances wasn't available | |
| 616 | - if (!newSessionId) { | |
| 617 | - newSessionId = 'mxchat_chat_' + Math.random().toString(36).substr(2, 9); | |
| 618 | - this.clearMxChatCookie(botId); | |
| 619 | - this.setChatSession(newSessionId, botId); | |
| 620 | - } | |
| 621 | - | |
| 622 | - this.log('New session ID: ' + newSessionId); | |
| 623 | - | |
| 549 | + | |
| 550 | + this.log(`🔍 Current session ID: ${sessionId}`); | |
| 551 | + this.log('🧹 Starting fresh session...'); | |
| 552 | + | |
| 553 | + // Generate new session ID (using your existing format) | |
| 554 | + const newSessionId = 'mxchat_chat_' + Math.random().toString(36).substr(2, 9); | |
| 555 | + | |
| 556 | + // Clear the old cookie and set new one immediately | |
| 557 | + this.clearMxChatCookie(); | |
| 558 | + this.setChatSession(newSessionId); | |
| 559 | + | |
| 560 | + this.log(`🆕 New session ID: ${newSessionId}`); | |
| 561 | + | |
| 624 | 562 | // Call backend to clear old session data |
| 625 | 563 | fetch(mxchatTestData.ajaxUrl, { |
| 626 | 564 | method: 'POST', |
| 627 | 565 | headers: { |
| @@ -636,36 +574,36 @@ | ||
| 636 | 574 | }) |
| 637 | 575 | .then(response => response.json()) |
| 638 | 576 | .then(data => { |
| 639 | 577 | if (data.success) { |
| 640 | - this.log('Backend session cleared: ' + data.data.message); | |
| 641 | - | |
| 578 | + this.log('✅ Backend session cleared: ' + data.data.message); | |
| 579 | + | |
| 642 | 580 | // Update the session ID everywhere in the DOM |
| 643 | 581 | this.updateSessionIdEverywhere(newSessionId); |
| 644 | - | |
| 582 | + | |
| 645 | 583 | // Clear the chat UI |
| 646 | 584 | this.clearChatUI(); |
| 647 | - | |
| 585 | + | |
| 648 | 586 | // Show popular questions again |
| 649 | 587 | const popularQuestions = document.querySelector('#mxchat-popular-questions'); |
| 650 | 588 | if (popularQuestions) { |
| 651 | 589 | popularQuestions.style.display = 'block'; |
| 652 | 590 | } |
| 653 | - | |
| 591 | + | |
| 654 | 592 | // Clear testing data displays |
| 655 | 593 | this.updateLastQuery('New session started', []); |
| 656 | 594 | this.updateTopMatches([], 0); |
| 657 | 595 | this.updateApprovedUrls([]); |
| 658 | - | |
| 659 | - this.log('Fresh session started successfully'); | |
| 660 | - | |
| 596 | + | |
| 597 | + this.log('🎉 Fresh session started successfully'); | |
| 598 | + | |
| 661 | 599 | } else { |
| 662 | - this.log('Error clearing session: ' + (data.data?.message || 'Unknown error')); | |
| 600 | + this.log('❌ Error clearing session: ' + (data.data?.message || 'Unknown error')); | |
| 663 | 601 | } |
| 664 | 602 | }) |
| 665 | 603 | .catch(error => { |
| 666 | 604 | console.error('Error clearing chat session:', error); |
| 667 | - this.log('Connection error when clearing session'); | |
| 605 | + this.log('🔌 Connection error when clearing session'); | |
| 668 | 606 | }); |
| 669 | 607 | } |
| 670 | 608 | |
| 671 | 609 | // Helper function to get cookie (same as your existing one) |
| @@ -674,21 +612,19 @@ | ||
| 674 | 612 | let parts = value.split("; " + name + "="); |
| 675 | 613 | if (parts.length == 2) return parts.pop().split(";").shift(); |
| 676 | 614 | } |
| 677 | 615 | |
| 678 | - // Helper function to set session cookie (matches chat-script.js format) | |
| 679 | - setChatSession(sessionId, botId) { | |
| 680 | - botId = botId || 'default'; | |
| 681 | - document.cookie = 'mxchat_session_id_' + botId + '=' + sessionId + '; path=/; max-age=86400; SameSite=Lax'; | |
| 616 | + // Helper function to set session cookie (same as your existing one) | |
| 617 | + setChatSession(sessionId) { | |
| 618 | + // Set the cookie with a 24-hour expiration (86400 seconds) | |
| 619 | + document.cookie = "mxchat_session_id=" + sessionId + "; path=/; max-age=86400; SameSite=Lax"; | |
| 682 | 620 | } |
| 683 | 621 | |
| 684 | 622 | // Helper function to clear the MxChat session cookie |
| 685 | - clearMxChatCookie(botId) { | |
| 686 | - botId = botId || 'default'; | |
| 687 | - // Clear both bot-suffixed and legacy cookie formats | |
| 688 | - document.cookie = 'mxchat_session_id_' + botId + '=; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT; SameSite=Lax'; | |
| 689 | - document.cookie = 'mxchat_session_id=; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT; SameSite=Lax'; | |
| 690 | - this.log('Session cookie cleared'); | |
| 623 | + clearMxChatCookie() { | |
| 624 | + // Clear the cookie by setting it to expire in the past | |
| 625 | + document.cookie = "mxchat_session_id=; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT; SameSite=Lax"; | |
| 626 | + this.log('🍪 Session cookie cleared'); | |
| 691 | 627 | } |
| 692 | 628 | |
| 693 | 629 | updateSessionIdEverywhere(newSessionId) { |
| 694 | 630 | // Update global session ID variable if it exists |
| @@ -747,23 +683,9 @@ | ||
| 747 | 683 | } |
| 748 | 684 | } |
| 749 | 685 | |
| 750 | 686 | getCurrentSessionId() { |
| 751 | - // Try MxChatInstances first (most reliable — matches chat-script.js) | |
| 752 | - if (typeof MxChatInstances !== 'undefined' && typeof MxChatInstances.getChatSession === 'function') { | |
| 753 | - const botIds = typeof MxChatInstances.getAllBotIds === 'function' ? MxChatInstances.getAllBotIds() : ['default']; | |
| 754 | - const botId = botIds.length > 0 ? botIds[0] : 'default'; | |
| 755 | - const instanceSession = MxChatInstances.getChatSession(botId); | |
| 756 | - if (instanceSession) { | |
| 757 | - return instanceSession; | |
| 758 | - } | |
| 759 | - } | |
| 760 | - | |
| 761 | - // Try bot-suffixed cookie, then legacy cookie | |
| 762 | - const botCookieId = this.getCookie('mxchat_session_id_default'); | |
| 763 | - if (botCookieId) { | |
| 764 | - return botCookieId; | |
| 765 | - } | |
| 687 | + // First try to get from cookie (most reliable) | |
| 766 | 688 | const cookieSessionId = this.getCookie('mxchat_session_id'); |
| 767 | 689 | if (cookieSessionId) { |
| 768 | 690 | return cookieSessionId; |
| 769 | 691 | } |