confidence metrics

This commit is contained in:
overcuriousity 2025-08-05 15:49:23 +02:00
parent 8c5dc36788
commit 183e36b86d
3 changed files with 166 additions and 177 deletions

View File

@ -672,6 +672,15 @@ class AIQueryInterface {
} }
displayResults(recommendation, originalQuery) { displayResults(recommendation, originalQuery) {
console.log('[AI DEBUG] Full recommendation object:', recommendation);
console.log('[AI DEBUG] Recommended tools:', recommendation.recommended_tools);
if (recommendation.recommended_tools) {
recommendation.recommended_tools.forEach((tool, index) => {
console.log(`[AI DEBUG] Tool ${index}:`, tool.name, 'Confidence:', tool.confidence);
});
}
if (this.currentMode === 'workflow') { if (this.currentMode === 'workflow') {
this.displayWorkflowResults(recommendation, originalQuery); this.displayWorkflowResults(recommendation, originalQuery);
} else { } else {
@ -693,16 +702,24 @@ class AIQueryInterface {
toolsByPhase[phase] = []; toolsByPhase[phase] = [];
}); });
// DEBUG: Log recommendation structure
console.log('[AI Results] Recommendation structure:', recommendation);
console.log('[AI Results] Recommended tools:', recommendation.recommended_tools);
recommendation.recommended_tools?.forEach(recTool => { recommendation.recommended_tools?.forEach(recTool => {
// DEBUG: Log each tool's confidence data
console.log('[AI Results] Tool confidence data:', recTool.name, recTool.confidence);
if (toolsByPhase[recTool.phase]) { if (toolsByPhase[recTool.phase]) {
const fullTool = tools.find(t => t.name === recTool.name); const fullTool = tools.find(t => t.name === recTool.name);
if (fullTool) { if (fullTool) {
toolsByPhase[recTool.phase].push({ toolsByPhase[recTool.phase].push({
...fullTool, ...fullTool,
recommendation: recTool, recommendation: recTool,
confidence: recTool.confidence, confidence: recTool.confidence, // Ensure confidence is passed
justification: recTool.justification, justification: recTool.justification,
priority: recTool.priority priority: recTool.priority,
recommendationStrength: recTool.recommendationStrength
}); });
} }
} }
@ -737,6 +754,106 @@ class AIQueryInterface {
this.elements.results.innerHTML = html; this.elements.results.innerHTML = html;
} }
renderConfidenceTooltip(confidence) {
if (!confidence || typeof confidence.overall !== 'number') {
console.log('[AI DEBUG] No confidence data or invalid format:', confidence);
return '';
}
const confidenceColor = confidence.overall >= 80 ? 'var(--color-accent)' :
confidence.overall >= 60 ? 'var(--color-warning)' : 'var(--color-error)';
const tooltipId = `tooltip-${Math.random().toString(36).substr(2, 9)}`;
console.log(`[AI DEBUG] Generating confidence tooltip: ${confidence.overall}% with ID ${tooltipId}`);
return `
<span class="confidence-tooltip-trigger"
style="display: inline-flex; align-items: center; gap: 0.125rem; cursor: help; margin-left: 0.25rem;"
onmouseenter="document.getElementById('${tooltipId}').style.display = 'block'"
onmouseleave="document.getElementById('${tooltipId}').style.display = 'none'"
onclick="event.stopPropagation();">
<div style="width: 6px; height: 6px; border-radius: 50%; background-color: ${confidenceColor}; flex-shrink: 0;"></div>
<span style="font-size: 0.625rem; color: white; font-weight: 600; text-shadow: 0 1px 2px rgba(0,0,0,0.5);">${confidence.overall}%</span>
<div id="${tooltipId}" style="display: none; position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); z-index: 1001; background: var(--color-bg); border: 1px solid var(--color-border); border-radius: 0.5rem; padding: 1rem; min-width: 320px; max-width: 400px; box-shadow: var(--shadow-lg); font-size: 0.75rem; color: var(--color-text);">
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 0.75rem;">
<strong style="font-size: 0.875rem;">KI-Vertrauenswertung</strong>
<span class="badge badge-mini" style="background-color: ${confidenceColor}; color: white; font-weight: 600;">${confidence.overall}%</span>
</div>
<div style="display: grid; grid-template-columns: 1fr; gap: 0.625rem; margin-bottom: 0.75rem;">
<div style="background: var(--color-bg-secondary); padding: 0.5rem; border-radius: 0.375rem; border-left: 3px solid var(--color-accent);">
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 0.25rem;">
<span style="font-weight: 600; font-size: 0.6875rem;">🔍 Ähnlichkeit zur Anfrage</span>
<strong style="color: var(--color-accent);">${confidence.embeddingsQuality}%</strong>
</div>
<div style="font-size: 0.625rem; color: var(--color-text-secondary); line-height: 1.3;">
Wie gut die Tool-Beschreibung zu Ihrer Suchanfrage passt (basierend auf Vektor-Ähnlichkeit)
</div>
</div>
<div style="background: var(--color-bg-secondary); padding: 0.5rem; border-radius: 0.375rem; border-left: 3px solid var(--color-primary);">
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 0.25rem;">
<span style="font-weight: 600; font-size: 0.6875rem;">🎯 Domain-Passung</span>
<strong style="color: var(--color-primary);">${confidence.domainAlignment}%</strong>
</div>
<div style="font-size: 0.625rem; color: var(--color-text-secondary); line-height: 1.3;">
Wie gut das Tool-Einsatzgebiet zu Ihrem forensischen Szenario passt
</div>
</div>
<div style="background: var(--color-bg-secondary); padding: 0.5rem; border-radius: 0.375rem; border-left: 3px solid var(--color-warning);">
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 0.25rem;">
<span style="font-weight: 600; font-size: 0.6875rem;">🤝 KI-Konsens</span>
<strong style="color: var(--color-warning);">${confidence.consensus}%</strong>
</div>
<div style="font-size: 0.625rem; color: var(--color-text-secondary); line-height: 1.3;">
Wie einig sich die verschiedenen KI-Analyseschritte über dieses Tool sind
</div>
</div>
<div style="background: var(--color-bg-secondary); padding: 0.5rem; border-radius: 0.375rem; border-left: 3px solid var(--color-text-secondary);">
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 0.25rem;">
<span style="font-weight: 600; font-size: 0.6875rem;">🔄 Aktualität</span>
<strong style="color: var(--color-text);">${confidence.freshness}%</strong>
</div>
<div style="font-size: 0.625rem; color: var(--color-text-secondary); line-height: 1.3;">
Wie aktuell und gut gepflegt das Tool ist (basierend auf Hosting-Status, Knowledge Base, Open Source)
</div>
</div>
</div>
${confidence.strengthIndicators && confidence.strengthIndicators.length > 0 ? `
<div style="margin-bottom: 0.75rem; padding: 0.5rem; background: var(--color-oss-bg); border-radius: 0.375rem; border-left: 3px solid var(--color-accent);">
<strong style="color: var(--color-accent); font-size: 0.6875rem; display: flex; align-items: center; gap: 0.25rem; margin-bottom: 0.375rem;">
<span>✓</span> Was für dieses Tool spricht:
</strong>
<ul style="margin: 0; padding-left: 1rem; font-size: 0.625rem; line-height: 1.4;">
${confidence.strengthIndicators.slice(0, 3).map(s => `<li style="margin-bottom: 0.25rem;">${this.sanitizeText(s)}</li>`).join('')}
</ul>
</div>
` : ''}
${confidence.uncertaintyFactors && confidence.uncertaintyFactors.length > 0 ? `
<div style="padding: 0.5rem; background: var(--color-hosted-bg); border-radius: 0.375rem; border-left: 3px solid var(--color-warning);">
<strong style="color: var(--color-warning); font-size: 0.6875rem; display: flex; align-items: center; gap: 0.25rem; margin-bottom: 0.375rem;">
<span>⚠</span> Unsicherheitsfaktoren:
</strong>
<ul style="margin: 0; padding-left: 1rem; font-size: 0.625rem; line-height: 1.4;">
${confidence.uncertaintyFactors.slice(0, 3).map(f => `<li style="margin-bottom: 0.25rem;">${this.sanitizeText(f)}</li>`).join('')}
</ul>
</div>
` : ''}
<div style="margin-top: 0.75rem; padding-top: 0.75rem; border-top: 1px solid var(--color-border); font-size: 0.625rem; color: var(--color-text-secondary); text-align: center;">
Vertrauensscore basiert auf KI-Analyse • Forensisch validiert
</div>
</div>
</span>
`;
}
renderAuditTrail(auditTrail) { renderAuditTrail(auditTrail) {
if (!auditTrail || !Array.isArray(auditTrail) || auditTrail.length === 0) { if (!auditTrail || !Array.isArray(auditTrail) || auditTrail.length === 0) {
return ''; return '';
@ -1003,74 +1120,6 @@ class AIQueryInterface {
return String(data); return String(data);
} }
renderConfidenceIndicator(confidence) {
if (!confidence || typeof confidence.overall !== 'number') return '';
const confidenceColor = confidence.overall >= 80 ? 'var(--color-accent)' :
confidence.overall >= 60 ? 'var(--color-warning)' : 'var(--color-error)';
const strengthText = confidence.overall >= 80 ? 'HOCH' :
confidence.overall >= 60 ? 'MITTEL' : 'NIEDRIG';
return `
<div class="confidence-indicator-integrated" style="display: flex; align-items: center; gap: 0.5rem; margin-bottom: 0.75rem;">
<div class="confidence-bar-wrapper" style="flex: 1; height: 4px; background-color: var(--color-bg-tertiary); border-radius: 2px; overflow: hidden;">
<div class="confidence-bar-fill" style="width: ${confidence.overall}%; height: 100%; background-color: ${confidenceColor}; transition: var(--transition-fast);"></div>
</div>
<div class="confidence-badge-compact" style="display: flex; align-items: center; gap: 0.375rem;">
<span class="badge badge-mini" style="background-color: ${confidenceColor}; color: white; font-weight: 600; font-size: 0.625rem;">
${confidence.overall}%
</span>
<button class="btn-icon" style="width: 16px; height: 16px; padding: 0.125rem; font-size: 0.625rem;" onclick="this.parentElement.nextElementSibling.style.display = this.parentElement.nextElementSibling.style.display === 'none' ? 'block' : 'none'; this.textContent = this.textContent === '' ? '✕' : '';" title="Vertrauens-Details"></button>
</div>
<div style="display: none; position: absolute; z-index: 20; background: var(--color-bg); border: 1px solid var(--color-border); border-radius: 0.5rem; padding: 1rem; margin-top: 6rem; right: 0; min-width: 320px; box-shadow: var(--shadow-lg);" class="confidence-details-popup">
<div style="margin-bottom: 0.75rem;">
<div style="display: flex; justify-content: between; align-items: center; margin-bottom: 0.5rem;">
<strong class="text-sm">Vertrauens-Komponenten</strong>
<span class="badge badge-mini" style="background-color: ${confidenceColor}; color: white;">${strengthText}</span>
</div>
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 0.5rem; font-size: 0.75rem;">
<div style="display: flex; justify-content: space-between; padding: 0.25rem; background: var(--color-bg-secondary); border-radius: 0.25rem;">
<span>Ähnlichkeit:</span>
<span class="font-semibold">${confidence.embeddingsQuality}%</span>
</div>
<div style="display: flex; justify-content: space-between; padding: 0.25rem; background: var(--color-bg-secondary); border-radius: 0.25rem;">
<span>Domain:</span>
<span class="font-semibold">${confidence.domainAlignment}%</span>
</div>
<div style="display: flex; justify-content: space-between; padding: 0.25rem; background: var(--color-bg-secondary); border-radius: 0.25rem;">
<span>Konsens:</span>
<span class="font-semibold">${confidence.consensus}%</span>
</div>
<div style="display: flex; justify-content: space-between; padding: 0.25rem; background: var(--color-bg-secondary); border-radius: 0.25rem;">
<span>Aktualität:</span>
<span class="font-semibold">${confidence.freshness}%</span>
</div>
</div>
</div>
${confidence.strengthIndicators && confidence.strengthIndicators.length > 0 ? `
<div style="margin-bottom: 0.75rem;">
<strong class="text-accent" style="font-size: 0.75rem;">✓ Stärken:</strong>
<ul style="font-size: 0.6875rem; margin-top: 0.25rem; padding-left: 1rem; line-height: 1.3;">
${confidence.strengthIndicators.slice(0, 2).map(strength => `<li style="margin-bottom: 0.25rem;">${this.sanitizeText(strength)}</li>`).join('')}
</ul>
</div>
` : ''}
${confidence.uncertaintyFactors && confidence.uncertaintyFactors.length > 0 ? `
<div style="padding-top: 0.75rem; border-top: 1px solid var(--color-border);">
<strong class="text-warning" style="font-size: 0.75rem;">⚠ Unsicherheiten:</strong>
<ul style="font-size: 0.6875rem; margin-top: 0.25rem; padding-left: 1rem; line-height: 1.3;">
${confidence.uncertaintyFactors.slice(0, 2).map(factor => `<li style="margin-bottom: 0.25rem;">${this.sanitizeText(factor)}</li>`).join('')}
</ul>
</div>
` : ''}
</div>
</div>
`;
}
renderWorkflowTool(tool) { renderWorkflowTool(tool) {
const hasValidProjectUrl = isToolHosted(tool); const hasValidProjectUrl = isToolHosted(tool);
const priorityColors = { const priorityColors = {
@ -1088,14 +1137,13 @@ class AIQueryInterface {
</h4> </h4>
<div class="flex items-center gap-2"> <div class="flex items-center gap-2">
<span class="tool-rec-priority ${tool.recommendation ? tool.recommendation.priority : tool.priority}" <span class="tool-rec-priority ${tool.recommendation ? tool.recommendation.priority : tool.priority}"
style="background-color: ${priorityColors[tool.recommendation ? tool.recommendation.priority : tool.priority]}; color: white; padding: 0.25rem 0.5rem; border-radius: 1rem; font-size: 0.75rem;"> style="background-color: ${priorityColors[tool.recommendation ? tool.recommendation.priority : tool.priority]}; color: white; padding: 0.25rem 0.5rem; border-radius: 1rem; font-size: 0.75rem; position: relative;">
${tool.recommendation ? tool.recommendation.priority : tool.priority} ${tool.recommendation ? tool.recommendation.priority : tool.priority}
${tool.confidence ? this.renderConfidenceTooltip(tool.confidence, 'priority') : ''}
</span> </span>
</div> </div>
</div> </div>
${tool.confidence ? this.renderConfidenceIndicator(tool.confidence) : ''}
<div class="tool-rec-justification" style="background-color: var(--color-bg-tertiary); padding: 0.75rem; border-radius: 0.375rem; border-left: 3px solid var(--color-primary); margin: 0.75rem 0; font-style: italic; white-space: pre-wrap; word-wrap: break-word;"> <div class="tool-rec-justification" style="background-color: var(--color-bg-tertiary); padding: 0.75rem; border-radius: 0.375rem; border-left: 3px solid var(--color-primary); margin: 0.75rem 0; font-style: italic; white-space: pre-wrap; word-wrap: break-word;">
"${this.sanitizeText(tool.justification || (tool.recommendation && tool.recommendation.justification) || `Empfohlen für ${tool.phase}`)}" "${this.sanitizeText(tool.justification || (tool.recommendation && tool.recommendation.justification) || `Empfohlen für ${tool.phase}`)}"
</div> </div>
@ -1123,12 +1171,11 @@ class AIQueryInterface {
<div style="margin-bottom: 1rem;"> <div style="margin-bottom: 1rem;">
<h3 style="margin: 0 0 0.5rem 0;">${tool.name}</h3> <h3 style="margin: 0 0 0.5rem 0;">${tool.name}</h3>
<div style="display: flex; flex-wrap: wrap; gap: 0.5rem; align-items: center; margin-bottom: 0.75rem;"> <div style="display: flex; flex-wrap: wrap; gap: 0.5rem; align-items: center; margin-bottom: 0.75rem;">
<span class="badge" style="background-color: ${suitabilityColors[recommendation.suitability_score]}; color: white;"> <span class="badge" style="background-color: ${suitabilityColors[recommendation.suitability_score]}; color: white; position: relative;">
${this.getSuitabilityText(recommendation.suitability_score)} ${this.getSuitabilityText(recommendation.suitability_score, recommendation.confidence)}
</span> </span>
${this.renderToolBadges(tool)} ${this.renderToolBadges(tool)}
</div> </div>
${recommendation.confidence ? this.renderConfidenceIndicator(recommendation.confidence) : ''}
</div> </div>
<div style="margin-bottom: 1.5rem;"> <div style="margin-bottom: 1.5rem;">
@ -1230,6 +1277,8 @@ class AIQueryInterface {
const phaseTools = toolsByPhase[phase]; const phaseTools = toolsByPhase[phase];
if (phaseTools.length === 0) return ''; if (phaseTools.length === 0) return '';
console.log(`[AI DEBUG] Phase ${phase} tools:`, phaseTools.map(t => ({name: t.name, hasConfidence: !!t.confidence})));
return ` return `
<div class="workflow-phase"> <div class="workflow-phase">
<div class="phase-header"> <div class="phase-header">
@ -1237,7 +1286,10 @@ class AIQueryInterface {
<div class="phase-info"> <div class="phase-info">
<h3 class="phase-title">${phaseNames[phase]}</h3> <h3 class="phase-title">${phaseNames[phase]}</h3>
<div class="phase-tools"> <div class="phase-tools">
${phaseTools.map(tool => this.renderWorkflowTool(tool)).join('')} ${phaseTools.map(tool => {
console.log(`[AI DEBUG] Rendering tool ${tool.name} with confidence:`, tool.confidence);
return this.renderWorkflowTool(tool);
}).join('')}
</div> </div>
</div> </div>
</div> </div>
@ -1248,6 +1300,8 @@ class AIQueryInterface {
} }
renderWorkflowTool(tool) { renderWorkflowTool(tool) {
console.log(`[AI DEBUG] renderWorkflowTool called for ${tool.name}, confidence:`, tool.confidence);
const hasValidProjectUrl = isToolHosted(tool); const hasValidProjectUrl = isToolHosted(tool);
const priorityColors = { const priorityColors = {
high: 'var(--color-error)', high: 'var(--color-error)',
@ -1255,21 +1309,29 @@ class AIQueryInterface {
low: 'var(--color-accent)' low: 'var(--color-accent)'
}; };
const priority = tool.recommendation ? tool.recommendation.priority : tool.priority;
const confidenceTooltip = tool.confidence ? this.renderConfidenceTooltip(tool.confidence) : '';
console.log(`[AI DEBUG] Priority: ${priority}, Confidence tooltip:`, confidenceTooltip ? 'generated' : 'empty');
return ` return `
<div class="tool-recommendation ${this.getToolClass(tool, 'recommendation')}" onclick="window.showToolDetails('${tool.name}')"> <div class="tool-recommendation ${this.getToolClass(tool, 'recommendation')}" onclick="window.showToolDetails('${tool.name}')" style="position: relative;">
<div class="tool-rec-header"> <div class="tool-rec-header">
<h4 class="tool-rec-name"> <h4 class="tool-rec-name">
${tool.icon ? `<span style="margin-right: 0.5rem;">${tool.icon}</span>` : ''} ${tool.icon ? `<span style="margin-right: 0.5rem;">${tool.icon}</span>` : ''}
${tool.name} ${tool.name}
</h4> </h4>
<span class="tool-rec-priority ${tool.recommendation.priority}" <div class="flex items-center gap-2">
style="background-color: ${priorityColors[tool.recommendation.priority]}; color: white; padding: 0.25rem 0.5rem; border-radius: 1rem; font-size: 0.75rem;"> <span class="tool-rec-priority ${priority}"
${tool.recommendation.priority} style="background-color: ${priorityColors[priority]}; color: white; padding: 0.25rem 0.5rem; border-radius: 1rem; font-size: 0.75rem; position: relative; display: flex; align-items: center; gap: 0.25rem;">
${priority}
${confidenceTooltip}
</span> </span>
</div> </div>
</div>
<div class="tool-rec-justification" style="background-color: var(--color-bg-tertiary); padding: 0.75rem; border-radius: 0.375rem; border-left: 3px solid var(--color-primary); margin: 0.75rem 0; font-style: italic; white-space: pre-wrap; word-wrap: break-word;"> <div class="tool-rec-justification" style="background-color: var(--color-bg-tertiary); padding: 0.75rem; border-radius: 0.375rem; border-left: 3px solid var(--color-primary); margin: 0.75rem 0; font-style: italic; white-space: pre-wrap; word-wrap: break-word;">
"${this.sanitizeText(tool.recommendation.justification)}" "${this.sanitizeText(tool.justification || (tool.recommendation && tool.recommendation.justification) || `Empfohlen für ${tool.phase}`)}"
</div> </div>
<div style="font-size: 0.75rem; color: var(--color-text-secondary);"> <div style="font-size: 0.75rem; color: var(--color-text-secondary);">
@ -1301,9 +1363,13 @@ class AIQueryInterface {
} }
renderDetailedTool(tool, recommendation, rank) { renderDetailedTool(tool, recommendation, rank) {
console.log(`[AI DEBUG] renderDetailedTool called for ${tool.name}, recommendation confidence:`, recommendation.confidence);
const rankColors = { 1: 'var(--color-accent)', 2: 'var(--color-primary)', 3: 'var(--color-warning)' }; const rankColors = { 1: 'var(--color-accent)', 2: 'var(--color-primary)', 3: 'var(--color-warning)' };
const suitabilityColors = { high: 'var(--color-accent)', medium: 'var(--color-warning)', low: 'var(--color-text-secondary)' }; const suitabilityColors = { high: 'var(--color-accent)', medium: 'var(--color-warning)', low: 'var(--color-text-secondary)' };
const confidenceTooltip = recommendation.confidence ? this.renderConfidenceTooltip(recommendation.confidence) : '';
return ` return `
<div class="card ${this.getToolClass(tool, 'card')}" style="cursor: pointer; position: relative;" onclick="window.showToolDetails('${tool.name}')"> <div class="card ${this.getToolClass(tool, 'card')}" style="cursor: pointer; position: relative;" onclick="window.showToolDetails('${tool.name}')">
<div style="position: absolute; top: -8px; right: -8px; width: 32px; height: 32px; background-color: ${rankColors[rank]}; color: white; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-weight: bold; font-size: 1.125rem;"> <div style="position: absolute; top: -8px; right: -8px; width: 32px; height: 32px; background-color: ${rankColors[rank]}; color: white; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-weight: bold; font-size: 1.125rem;">
@ -1312,9 +1378,10 @@ class AIQueryInterface {
<div style="margin-bottom: 1rem;"> <div style="margin-bottom: 1rem;">
<h3 style="margin: 0 0 0.5rem 0;">${tool.name}</h3> <h3 style="margin: 0 0 0.5rem 0;">${tool.name}</h3>
<div style="display: flex; flex-wrap: wrap; gap: 0.5rem;"> <div style="display: flex; flex-wrap: wrap; gap: 0.5rem; align-items: center; margin-bottom: 0.75rem;">
<span class="badge" style="background-color: ${suitabilityColors[recommendation.suitability_score]}; color: white;"> <span class="badge" style="background-color: ${suitabilityColors[recommendation.suitability_score]}; color: white; position: relative; display: flex; align-items: center; gap: 0.25rem;">
${this.getSuitabilityText(recommendation.suitability_score)} ${this.getSuitabilityText(recommendation.suitability_score)}
${confidenceTooltip}
</span> </span>
${this.renderToolBadges(tool)} ${this.renderToolBadges(tool)}
</div> </div>
@ -1469,13 +1536,18 @@ class AIQueryInterface {
} }
} }
getSuitabilityText(score) { getSuitabilityText(score, confidence = null) {
const texts = { const texts = {
high: 'GUT GEEIGNET', high: 'GUT GEEIGNET',
medium: 'GEEIGNET', medium: 'GEEIGNET',
low: 'VIELLEICHT GEEIGNET' low: 'VIELLEICHT GEEIGNET'
}; };
return texts[score] || 'GEEIGNET'; const baseText = texts[score] || 'GEEIGNET';
if (confidence) {
return `${baseText} ${this.renderConfidenceTooltip(confidence, 'suitability')}`;
}
return baseText;
} }
escapeHtml(text) { escapeHtml(text) {

View File

@ -2069,7 +2069,7 @@ input[type="checkbox"] {
border-color: var(--color-method); border-color: var(--color-method);
} }
.tool-recommendation:hover .confidence-bar-fill { .tool-recommendation:hover {
box-shadow: 0 0 8px rgba(0,0,0,0.1); box-shadow: 0 0 8px rgba(0,0,0,0.1);
} }
@ -2111,57 +2111,6 @@ input[type="checkbox"] {
border-left: 3px solid var(--color-primary); border-left: 3px solid var(--color-primary);
} }
/* ===================================================================
CONFIDENCE INTEGRATION STYLES
================================================================= */
.confidence-indicator-integrated {
position: relative;
}
.confidence-bar-wrapper {
position: relative;
background-color: var(--color-bg-tertiary);
border-radius: 2px;
overflow: hidden;
border: 1px solid var(--color-border);
}
.confidence-bar-fill {
transition: width 0.6s ease-out;
position: relative;
}
.confidence-bar-fill::after {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: linear-gradient(45deg, transparent 25%, rgba(255,255,255,0.1) 25%, rgba(255,255,255,0.1) 50%, transparent 50%, transparent 75%, rgba(255,255,255,0.1) 75%);
background-size: 8px 8px;
animation: confidence-shimmer 2s linear infinite;
}
.confidence-badge-compact .btn-icon {
transition: var(--transition-fast);
}
.confidence-badge-compact .btn-icon:hover {
background-color: var(--color-bg-secondary);
transform: scale(1.1);
}
.confidence-details-popup {
animation: confidence-popup-in 0.2s ease-out;
}
/* Hover effect for confidence bars */
.confidence-indicator-integrated:hover .confidence-bar-fill {
filter: brightness(1.1);
}
/* =================================================================== /* ===================================================================
18. APPROACH SELECTION (CONSOLIDATED) 18. APPROACH SELECTION (CONSOLIDATED)
================================================================= */ ================================================================= */
@ -2563,22 +2512,6 @@ footer {
animation: ai-spotlight-pulse 0.4s ease-out; animation: ai-spotlight-pulse 0.4s ease-out;
} }
@keyframes confidence-shimmer {
0% { transform: translateX(-8px); }
100% { transform: translateX(8px); }
}
@keyframes confidence-popup-in {
from {
opacity: 0;
transform: translateY(-8px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
/* =================================================================== /* ===================================================================
21. SMART PROMPTING INTERFACE (MISSING STYLES ADDED BACK) 21. SMART PROMPTING INTERFACE (MISSING STYLES ADDED BACK)
================================================================= */ ================================================================= */
@ -3501,26 +3434,6 @@ footer {
width: 14px; width: 14px;
height: 14px; height: 14px;
} }
.confidence-details-popup {
position: fixed !important;
top: 50% !important;
left: 50% !important;
transform: translate(-50%, -50%) !important;
margin: 0 !important;
width: 90vw !important;
max-width: 300px !important;
z-index: 1000 !important;
}
.confidence-indicator-integrated {
margin-bottom: 0.5rem;
}
.confidence-badge-compact .btn-icon {
width: 18px;
height: 18px;
}
} }
@media (width <= 640px) { @media (width <= 640px) {

View File

@ -1101,11 +1101,15 @@ ${JSON.stringify(conceptsToSend, null, 2)}`;
const queryLower = userQuery.toLowerCase(); const queryLower = userQuery.toLowerCase();
const domainKeywordsEnv = process.env.CONFIDENCE_DOMAIN_KEYWORDS || ''; // Load domain keywords from environment with fallback
const domainKeywordsEnv = process.env.CONFIDENCE_DOMAIN_KEYWORDS ||
'incident-response:incident,breach,attack,compromise,response|malware-analysis:malware,virus,trojan,reverse,analysis|network-forensics:network,traffic,packet,pcap,wireshark|mobile-forensics:mobile,android,ios,phone,app|cloud-forensics:cloud,aws,azure,saas,paas';
const domainKeywords = domainKeywordsEnv.split('|').reduce((acc, pair) => { const domainKeywords = domainKeywordsEnv.split('|').reduce((acc, pair) => {
const [domain, keywords] = pair.split(':'); const [domain, keywords] = pair.split(':');
if (domain && keywords) {
acc[domain] = keywords.split(','); acc[domain] = keywords.split(',');
}
return acc; return acc;
}, {}); }, {});