// ── Embedding Debug Page ── registerPage('embedding-debug', { async init() { if (!currentUser || !currentUser.isAdmin) { navigateTo('dashboard'); return; } var queryInput = document.getElementById('embDebugQuery'); var agentSelect = document.getElementById('embDebugAgent'); var topNInput = document.getElementById('embDebugTopN'); var searchBtn = document.getElementById('embDebugSearchBtn'); var statsBtn = document.getElementById('embDebugStatsBtn'); var reEmbedBtn = document.getElementById('embDebugReEmbedBtn'); var summaryEl = document.getElementById('embDebugSummary'); var resultsEl = document.getElementById('embDebugResults'); // Agents laden try { var resp = await fetch('/api/agents/available'); var agents = await resp.json(); (agents || []).forEach(function(a) { var opt = document.createElement('option'); opt.value = a.agentId; opt.textContent = a.name; agentSelect.appendChild(opt); }); } catch (e) { /* ignore */ } searchBtn.addEventListener('click', doSearch); queryInput.addEventListener('keydown', function(e) { if (e.key === 'Enter') doSearch(); }); statsBtn.addEventListener('click', doStats); if (reEmbedBtn) { reEmbedBtn.addEventListener('click', async function() { if (!confirm('Alle Embeddings löschen und neu generieren?\n\nDas kann bei vielen Messages einige Minuten dauern.')) return; reEmbedBtn.disabled = true; reEmbedBtn.innerHTML = ' Läuft...'; try { var resp = await fetch('/api/admin/embedding-debug/re-embed', { method: 'POST' }); var data = await resp.json(); summaryEl.innerHTML = '
' + esc(data.status || data.error) + (data.model ? ' (Modell: ' + esc(data.model) + ')' : '') + '
'; } catch (e) { summaryEl.innerHTML = '
Fehler: ' + esc(e.message) + '
'; } finally { reEmbedBtn.disabled = false; reEmbedBtn.innerHTML = ' Re-Embed All'; } }); } async function doSearch() { var query = queryInput.value.trim(); if (!query) return; searchBtn.disabled = true; searchBtn.innerHTML = ' Suche...'; summaryEl.innerHTML = ''; resultsEl.innerHTML = ''; try { var params = new URLSearchParams({ q: query, agentId: agentSelect.value, topN: topNInput.value || '20' }); var resp = await fetch('/api/admin/embedding-debug?' + params); var data = await resp.json(); if (data.error) { summaryEl.innerHTML = '
' + esc(data.error) + '
'; return; } renderSummary(data.summary); renderResults(data.messages, data.memory); } catch (e) { summaryEl.innerHTML = '
Fehler: ' + esc(e.message) + '
'; } finally { searchBtn.disabled = false; searchBtn.innerHTML = ' Suchen'; } } async function doStats() { statsBtn.disabled = true; statsBtn.innerHTML = ''; summaryEl.innerHTML = ''; resultsEl.innerHTML = ''; try { var resp = await fetch('/api/admin/embedding-debug/stats'); var data = await resp.json(); renderStats(data); } catch (e) { summaryEl.innerHTML = '
Fehler: ' + esc(e.message) + '
'; } finally { statsBtn.disabled = false; statsBtn.innerHTML = ' Statistiken'; } } function renderSummary(s) { summaryEl.innerHTML = '
' + '
' + '
' + s.totalMessageResults + 'Treffer gesamt
' + '
' + s.aboveThreshold035 + '≥ 0.35 (Threshold)
' + '
' + s.belowThreshold + '< 0.35
' + '
' + s.wouldAppearInAutoContext + '→ AutoContext
' + '
' + s.filteredByChain + 'Chain-gefiltert
' + '
' + s.filteredByLength + 'Zu kurz (<20)
' + '
' + (s.totalMemoryResults > 0 ? '
' + '
' + s.totalMemoryResults + 'Memory-Treffer
' + '
' + s.memoryAboveThreshold + 'Memory ≥ 0.35
' + '
' : '') + '
'; } function renderResults(messages, memory) { var html = ''; if (messages && messages.length > 0) { html += '

Message-Ergebnisse

'; html += '
'; messages.forEach(function(r, i) { var scoreClass = r.score >= 0.35 ? 'score-good' : (r.score >= 0.2 ? 'score-medium' : 'score-low'); var filterTags = ''; if (r.wouldBeFilteredByChain) filterTags += 'Chain'; if (r.wouldBeFilteredByLength) filterTags += 'Kurz'; if (r.wouldAppearInAutoContext) filterTags += 'AutoContext'; else if (r.wouldPassThreshold) filterTags += 'Threshold OK'; var hasFullText = r.fullText && r.fullText.length > (r.textPreview || '').length; html += '
' + '
' + '#' + (i + 1) + '' + '' + r.score.toFixed(4) + '' + '' + esc(r.role) + '' + '' + esc(r.createdAt ? r.createdAt.substring(0, 16) : '') + '' + filterTags + (hasFullText ? 'Full' : '') + '
' + '
' + esc(r.textPreview || '(kein Preview)') + '
' + (hasFullText ? '' : '') + '
MsgID: ' + r.messageId + ' | Session: ' + esc(r.sessionId || '').substring(0, 8) + ' | Chain: ' + esc(r.chainId || '').substring(0, 8) + '
' + '
'; }); html += '
'; } if (memory && memory.length > 0) { html += '

Memory-Ergebnisse

'; html += '
'; memory.forEach(function(r, i) { var scoreClass = r.score >= 0.35 ? 'score-good' : (r.score >= 0.2 ? 'score-medium' : 'score-low'); var hasFullText = r.fullText && r.fullText.length > (r.textPreview || '').length; html += '
' + '
' + '#' + (i + 1) + '' + '' + r.score.toFixed(4) + '' + 'memory' + '' + esc(r.filePath || '') + '' + (r.score >= 0.35 ? 'AutoContext' : '') + (hasFullText ? 'Full' : '') + '
' + '
' + esc(r.textPreview || '(kein Preview)') + '
' + (hasFullText ? '' : '') + '
'; }); html += '
'; } if (!html) { html = '

Keine Ergebnisse gefunden (auch nicht unter Threshold).

'; } resultsEl.innerHTML = html; } function renderStats(data) { var html = '

Embedding-Statistiken

'; html += '
' + '
' + (data.totalMessages || 0).toLocaleString() + 'Message-Embeddings
' + '
' + (data.totalMemory || 0).toLocaleString() + 'Memory-Chunks
' + '
'; if (data.perAgent && data.perAgent.length > 0) { html += '

Pro Agent

'; html += ''; data.perAgent.forEach(function(a) { html += '' + '' + ''; }); html += '
AgentMessagesMemory
' + esc(a.agentName || a.agentId || '(kein Agent)') + '' + (a.messageCount || 0).toLocaleString() + '' + (a.memoryChunks || 0).toLocaleString() + '
'; } resultsEl.innerHTML = html; } } });