From 183e36b86d2e45f8116d76b9c119557fd69e2e45 Mon Sep 17 00:00:00 2001 From: overcuriousity Date: Tue, 5 Aug 2025 15:49:23 +0200 Subject: [PATCH] confidence metrics --- src/components/AIQueryInterface.astro | 246 +++++++++++++++++--------- src/styles/global.css | 89 +--------- src/utils/aiPipeline.ts | 8 +- 3 files changed, 166 insertions(+), 177 deletions(-) diff --git a/src/components/AIQueryInterface.astro b/src/components/AIQueryInterface.astro index 076b322..38a5547 100644 --- a/src/components/AIQueryInterface.astro +++ b/src/components/AIQueryInterface.astro @@ -672,6 +672,15 @@ class AIQueryInterface { } 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') { this.displayWorkflowResults(recommendation, originalQuery); } else { @@ -693,16 +702,24 @@ class AIQueryInterface { 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 => { + // DEBUG: Log each tool's confidence data + console.log('[AI Results] Tool confidence data:', recTool.name, recTool.confidence); + if (toolsByPhase[recTool.phase]) { const fullTool = tools.find(t => t.name === recTool.name); if (fullTool) { toolsByPhase[recTool.phase].push({ ...fullTool, recommendation: recTool, - confidence: recTool.confidence, + confidence: recTool.confidence, // Ensure confidence is passed justification: recTool.justification, - priority: recTool.priority + priority: recTool.priority, + recommendationStrength: recTool.recommendationStrength }); } } @@ -737,6 +754,106 @@ class AIQueryInterface { 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 ` + +
+ ${confidence.overall}% + + +
+ `; + } + renderAuditTrail(auditTrail) { if (!auditTrail || !Array.isArray(auditTrail) || auditTrail.length === 0) { return ''; @@ -1003,74 +1120,6 @@ class AIQueryInterface { 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 ` -
-
-
-
-
- - ${confidence.overall}% - - -
- -
- `; - } - renderWorkflowTool(tool) { const hasValidProjectUrl = isToolHosted(tool); const priorityColors = { @@ -1088,14 +1137,13 @@ class AIQueryInterface {
+ 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.confidence ? this.renderConfidenceTooltip(tool.confidence, 'priority') : ''}
- ${tool.confidence ? this.renderConfidenceIndicator(tool.confidence) : ''} -
"${this.sanitizeText(tool.justification || (tool.recommendation && tool.recommendation.justification) || `Empfohlen fĂĽr ${tool.phase}`)}"
@@ -1123,12 +1171,11 @@ class AIQueryInterface {

${tool.name}

- - ${this.getSuitabilityText(recommendation.suitability_score)} + + ${this.getSuitabilityText(recommendation.suitability_score, recommendation.confidence)} ${this.renderToolBadges(tool)}
- ${recommendation.confidence ? this.renderConfidenceIndicator(recommendation.confidence) : ''}
@@ -1230,6 +1277,8 @@ class AIQueryInterface { const phaseTools = toolsByPhase[phase]; if (phaseTools.length === 0) return ''; + console.log(`[AI DEBUG] Phase ${phase} tools:`, phaseTools.map(t => ({name: t.name, hasConfidence: !!t.confidence}))); + return `
@@ -1237,7 +1286,10 @@ class AIQueryInterface {

${phaseNames[phase]}

- ${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('')}
@@ -1248,6 +1300,8 @@ class AIQueryInterface { } renderWorkflowTool(tool) { + console.log(`[AI DEBUG] renderWorkflowTool called for ${tool.name}, confidence:`, tool.confidence); + const hasValidProjectUrl = isToolHosted(tool); const priorityColors = { high: 'var(--color-error)', @@ -1255,21 +1309,29 @@ class AIQueryInterface { 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 ` -
+

${tool.icon ? `${tool.icon}` : ''} ${tool.name}

- - ${tool.recommendation.priority} - +
+ + ${priority} + ${confidenceTooltip} + +
- "${this.sanitizeText(tool.recommendation.justification)}" + "${this.sanitizeText(tool.justification || (tool.recommendation && tool.recommendation.justification) || `Empfohlen fĂĽr ${tool.phase}`)}"
@@ -1301,9 +1363,13 @@ class AIQueryInterface { } 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 suitabilityColors = { high: 'var(--color-accent)', medium: 'var(--color-warning)', low: 'var(--color-text-secondary)' }; + const confidenceTooltip = recommendation.confidence ? this.renderConfidenceTooltip(recommendation.confidence) : ''; + return `
@@ -1312,9 +1378,10 @@ class AIQueryInterface {

${tool.name}

-
- +
+ ${this.getSuitabilityText(recommendation.suitability_score)} + ${confidenceTooltip} ${this.renderToolBadges(tool)}
@@ -1469,13 +1536,18 @@ class AIQueryInterface { } } - getSuitabilityText(score) { + getSuitabilityText(score, confidence = null) { const texts = { high: 'GUT GEEIGNET', medium: '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) { diff --git a/src/styles/global.css b/src/styles/global.css index e784e53..be43144 100644 --- a/src/styles/global.css +++ b/src/styles/global.css @@ -2069,7 +2069,7 @@ input[type="checkbox"] { 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); } @@ -2111,57 +2111,6 @@ input[type="checkbox"] { 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) ================================================================= */ @@ -2563,22 +2512,6 @@ footer { 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) ================================================================= */ @@ -3501,26 +3434,6 @@ footer { width: 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) { diff --git a/src/utils/aiPipeline.ts b/src/utils/aiPipeline.ts index 284b1a5..b1adefa 100644 --- a/src/utils/aiPipeline.ts +++ b/src/utils/aiPipeline.ts @@ -1101,11 +1101,15 @@ ${JSON.stringify(conceptsToSend, null, 2)}`; 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 [domain, keywords] = pair.split(':'); - acc[domain] = keywords.split(','); + if (domain && keywords) { + acc[domain] = keywords.split(','); + } return acc; }, {});