forensic-ai #4
@ -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) {
|
||||||
|
@ -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) {
|
||||||
|
@ -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;
|
||||||
}, {});
|
}, {});
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user