airefactor #19

Merged
mstoeck3 merged 25 commits from airefactor into main 2025-08-17 22:59:31 +00:00
Showing only changes of commit 1d91dbf478 - Show all commits

View File

@ -965,23 +965,12 @@ class AIQueryInterface {
</div> </div>
</div> </div>
</div> </div>
<svg class="toggle-icon" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="transform: rotate(90deg);"> <svg class="toggle-icon" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="transform: rotate(0deg);">
<polyline points="9 18 15 12 9 6"/> <polyline points="9 18 15 12 9 6"/>
</svg> </svg>
</div> </div>
<div style="margin: 0.5rem 0 1rem 0;"> <div class="audit-trail-details collapsed">
<button id="download-results-btn" class="btn btn-secondary">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="margin-right: 0.5rem;">
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/>
<polyline points="7 10 12 15 17 10"/>
<line x1="12" y1="15" x2="12" y2="3"/>
</svg>
Download Analyse (JSON)
</button>
</div>
<div class="audit-trail-details">
<!-- Audit Summary --> <!-- Audit Summary -->
<div class="audit-summary"> <div class="audit-summary">
<div class="summary-header">📊 Analyse-Zusammenfassung</div> <div class="summary-header">📊 Analyse-Zusammenfassung</div>
@ -1021,6 +1010,16 @@ class AIQueryInterface {
<div class="audit-process-flow"> <div class="audit-process-flow">
${this.renderPhaseGroups(rawAuditTrail, stats)} ${this.renderPhaseGroups(rawAuditTrail, stats)}
</div> </div>
<div style="margin: 0.5rem 0 1rem 0;">
<button id="download-results-btn" class="btn btn-secondary">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="margin-right: 0.5rem;">
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/>
<polyline points="7 10 12 15 17 10"/>
<line x1="12" y1="15" x2="12" y2="3"/>
</svg>
Download Analyse (JSON)
</button>
</div>
</div> </div>
</div> </div>
`; `;
@ -1918,32 +1917,38 @@ class AIQueryInterface {
const priority = tool.recommendation ? tool.recommendation.priority : tool.priority; const priority = tool.recommendation ? tool.recommendation.priority : tool.priority;
const confidenceTooltip = tool.confidence ? this.renderConfidenceTooltip(tool.confidence) : ''; const confidenceTooltip = tool.confidence ? this.renderConfidenceTooltip(tool.confidence) : '';
const cardClass = this.getToolClass(tool, 'recommendation'); const cardClass = this.getToolClass(tool, 'recommendation');
return ` return `
<div class="tool-recommendation ${cardClass}" onclick="window.showToolDetails('${tool.name}')"> <div class="tool-recommendation ${cardClass}" onclick="window.showToolDetails('${tool.name}')"
<div class="tool-rec-header"> style="position: relative; cursor: pointer; transition: var(--transition-fast);"
<h4 class="tool-rec-name"> onmouseover="this.style.transform='translateY(-2px)'; this.style.boxShadow='var(--shadow-md)';"
${tool.icon ? `<span class="mr-2 text-lg">${tool.icon}</span>` : ''} onmouseout="this.style.transform='translateY(0)'; this.style.boxShadow='';">
<div class="tool-rec-header" style="display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 0.75rem;">
<h4 class="tool-rec-name" style="font-weight: 600; font-size: 1rem; margin: 0; color: var(--color-text); flex: 1; margin-right: 0.75rem;">
${tool.icon ? `<span style="margin-right: 0.5rem; font-size: 1.125rem;">${tool.icon}</span>` : ''}
${tool.name} ${tool.name}
</h4> </h4>
<div class="flex items-center gap-1 flex-shrink-0"> <div style="display: flex; align-items: center; gap: 0.375rem; flex-shrink: 0;">
<span class="tool-rec-priority ${priority}" style="background-color: ${priorityColors[priority]};"> <span class="tool-rec-priority ${priority}"
style="background-color: ${priorityColors[priority]}; color: white; padding: 0.25rem 0.5rem; border-radius: 1rem; font-size: 0.75rem; font-weight: 500; text-transform: uppercase; position: relative; display: flex; align-items: center; gap: 0.25rem;">
${priority} ${priority}
${confidenceTooltip} ${confidenceTooltip}
</span> </span>
</div> </div>
</div> </div>
<div class="tool-rec-justification"> <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; font-size: 0.875rem; line-height: 1.5; color: var(--color-text-secondary);">
"${sanitizeText(tool.justification || (tool.recommendation && tool.recommendation.justification) || `Empfohlen für ${tool.phase}`)}" "${sanitizeText(tool.justification || (tool.recommendation && tool.recommendation.justification) || `Empfohlen für ${tool.phase}`)}"
</div> </div>
<div class="text-xs text-secondary mt-auto"> <div style="font-size: 0.75rem; color: var(--color-text-secondary); margin-top: auto;">
<div class="flex flex-wrap gap-1 mb-2"> <div style="display: flex; flex-wrap: wrap; gap: 0.375rem; margin-bottom: 0.5rem;">
${this.renderToolBadges(tool)} ${this.renderToolBadges(tool)}
</div> </div>
<div class="flex justify-between items-center"> <div style="display: flex; justify-content: space-between; align-items: center;">
<span>${tool.type === 'method' ? 'Methode' : tool.platforms.slice(0, 2).join(', ')}</span> <span>${tool.type === 'method' ? 'Methode' : tool.platforms.slice(0, 2).join(', ')}</span>
<span>${tool.skillLevel}</span> <span>${tool.skillLevel}</span>
</div> </div>
@ -2021,15 +2026,15 @@ class AIQueryInterface {
const confidenceTooltip = recommendation.confidence ? this.renderConfidenceTooltip(recommendation.confidence) : ''; const confidenceTooltip = recommendation.confidence ? this.renderConfidenceTooltip(recommendation.confidence) : '';
return ` return `
<div class="card ${this.getToolClass(tool, 'card')} cursor-pointer 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;">
${rank} ${rank}
</div> </div>
<div class="mb-4"> <div style="margin-bottom: 1rem;">
<h3 class="mb-2">${tool.name}</h3> <h3 style="margin: 0 0 0.5rem 0;">${tool.name}</h3>
<div class="flex flex-wrap gap-2 items-center mb-3"> <div style="display: flex; flex-wrap: wrap; gap: 0.5rem; align-items: center; margin-bottom: 0.75rem;">
<span class="badge text-white relative flex items-center gap-1" style="background-color: ${suitabilityColors[recommendation.suitability_score]};"> <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} ${confidenceTooltip}
</span> </span>
@ -2037,13 +2042,13 @@ class AIQueryInterface {
</div> </div>
</div> </div>
<div class="mb-6"> <div style="margin-bottom: 1.5rem;">
<h4 class="mb-3 text-accent">Warum diese Methode?</h4> <h4 style="margin: 0.8rem 0 0.75rem 0; color: var(--color-accent);">Warum diese Methode?</h4>
<div class="leading-relaxed">${sanitizeText(recommendation.detailed_explanation)}</div> <div style="margin: 0; line-height: 1.6; white-space: pre-wrap; word-wrap: break-word;">${sanitizeText(recommendation.detailed_explanation)}</div>
${recommendation.implementation_approach ? ` ${recommendation.implementation_approach ? `
<h4 class="mt-3 mb-3 text-primary">Anwendungsansatz</h4> <h4 style="margin: 0.8rem 0 0.75rem 0; color: var(--color-primary);">Anwendungsansatz</h4>
<div class="leading-relaxed">${sanitizeText(recommendation.implementation_approach)}</div> <div style="margin: 0; line-height: 1.6; white-space: pre-wrap; word-wrap: break-word;">${sanitizeText(recommendation.implementation_approach)}</div>
` : ''} ` : ''}
</div> </div>
@ -2058,66 +2063,69 @@ class AIQueryInterface {
if (!confidence || typeof confidence.overall !== 'number') return ''; if (!confidence || typeof confidence.overall !== 'number') return '';
const confidenceColor = getConfidenceColor(confidence.overall); const confidenceColor = getConfidenceColor(confidence.overall);
const tooltipId = `tooltip-${Math.random().toString(36).substr(2, 9)}`;
return ` return `
<span class="inline-flex items-center gap-1 cursor-pointer ml-1 relative" <span class="confidence-tooltip-trigger"
style="display: inline-flex; align-items: center; gap: 0.125rem; cursor: help; margin-left: 0.25rem; position: relative;"
onmouseenter="this.querySelector('.confidence-tooltip').style.display = 'block'" onmouseenter="this.querySelector('.confidence-tooltip').style.display = 'block'"
onmouseleave="this.querySelector('.confidence-tooltip').style.display = 'none'" onmouseleave="this.querySelector('.confidence-tooltip').style.display = 'none'"
onclick="event.stopPropagation();"> onclick="event.stopPropagation();">
<div class="w-1.5 h-1.5 rounded-xl flex-shrink-0" style="background-color: ${confidenceColor};"></div> <div style="width: 6px; height: 6px; border-radius: 50%; background-color: ${confidenceColor}; flex-shrink: 0;"></div>
<span class="text-xs font-semibold text-white">${confidence.overall}%</span> <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 class="confidence-tooltip hidden absolute top-full right-0 z-50 bg-primary text-white p-4 rounded-lg shadow-lg text-xs" style="min-width: 320px; max-width: 400px; margin-top: 0.5rem;"> <div class="confidence-tooltip"
<div class="flex justify-between items-center mb-3"> style="display: none; position: absolute; top: 100%; right: 0; 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); margin-top: 0.5rem;">
<strong class="text-sm">KI-Vertrauenswertung</strong> <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 0.75rem;">
<span class="font-semibold px-2 py-1 rounded text-xs" style="background-color: ${confidenceColor};">${confidence.overall}%</span> <strong style="font-size: 0.875rem; color: var(--color-primary);">KI-Vertrauenswertung</strong>
<span style="background-color: ${confidenceColor}; color: white; font-weight: 600; padding: 0.125rem 0.375rem; border-radius: 0.25rem; font-size: 0.625rem;">${confidence.overall}%</span>
</div> </div>
<div class="grid gap-2 mb-3"> <div style="display: grid; grid-template-columns: 1fr; gap: 0.625rem; margin-bottom: 0.75rem;">
<div class="bg-secondary p-2 rounded border-l-4" style="border-left-color: var(--color-accent);"> <div style="background: var(--color-bg-secondary); padding: 0.5rem; border-radius: 0.375rem; border-left: 3px solid var(--color-accent);">
<div class="flex justify-between items-center mb-1"> <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 0.25rem;">
<span class="font-semibold text-xs">🔍 Semantische Relevanz</span> <span style="font-weight: 600; font-size: 0.6875rem; color: var(--color-text);">🔍 Semantische Relevanz</span>
<strong class="text-accent">${confidence.semanticRelevance}%</strong> <strong style="color: var(--color-accent);">${confidence.semanticRelevance}%</strong>
</div> </div>
<div class="text-xs text-secondary leading-tight"> <div style="font-size: 0.625rem; color: var(--color-text-secondary); line-height: 1.3;">
Wie gut die Tool-Beschreibung semantisch zu Ihrer Anfrage passt Wie gut die Tool-Beschreibung semantisch zu Ihrer Anfrage passt
</div> </div>
</div> </div>
<div class="bg-secondary p-2 rounded border-l-4" style="border-left-color: var(--color-primary);"> <div style="background: var(--color-bg-secondary); padding: 0.5rem; border-radius: 0.375rem; border-left: 3px solid var(--color-primary);">
<div class="flex justify-between items-center mb-1"> <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 0.25rem;">
<span class="font-semibold text-xs">🎯 Aufgaben-Eignung</span> <span style="font-weight: 600; font-size: 0.6875rem; color: var(--color-text);">🎯 Aufgaben-Eignung</span>
<strong class="text-primary">${confidence.taskSuitability}%</strong> <strong style="color: var(--color-primary);">${confidence.taskSuitability}%</strong>
</div> </div>
<div class="text-xs text-secondary leading-tight"> <div style="font-size: 0.625rem; color: var(--color-text-secondary); line-height: 1.3;">
KI-bewertete Eignung für Ihre spezifische Aufgabenstellung KI-bewertete Eignung für Ihre spezifische Aufgabenstellung
</div> </div>
</div> </div>
</div> </div>
${confidence.strengthIndicators && confidence.strengthIndicators.length > 0 ? ` ${confidence.strengthIndicators && confidence.strengthIndicators.length > 0 ? `
<div class="mb-3 p-2 rounded border-l-4" style="background-color: var(--color-oss-bg); border-left-color: var(--color-accent);"> <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 class="text-accent text-xs flex items-center gap-1 mb-1"> <strong style="color: var(--color-accent); font-size: 0.6875rem; display: flex; align-items: center; gap: 0.25rem; margin-bottom: 0.375rem;">
<span>✓</span> Stärken dieser Empfehlung: <span>✓</span> Stärken dieser Empfehlung:
</strong> </strong>
<ul class="ml-4 text-xs leading-normal"> <ul style="margin: 0; padding-left: 1rem; font-size: 0.625rem; line-height: 1.4; color: var(--color-text);">
${confidence.strengthIndicators.slice(0, 3).map(s => `<li class="mb-1">${sanitizeText(s)}</li>`).join('')} ${confidence.strengthIndicators.slice(0, 3).map(s => `<li style="margin-bottom: 0.25rem;">${sanitizeText(s)}</li>`).join('')}
</ul> </ul>
</div> </div>
` : ''} ` : ''}
${confidence.uncertaintyFactors && confidence.uncertaintyFactors.length > 0 ? ` ${confidence.uncertaintyFactors && confidence.uncertaintyFactors.length > 0 ? `
<div class="p-2 rounded border-l-4" style="background-color: var(--color-hosted-bg); border-left-color: var(--color-warning);"> <div style="padding: 0.5rem; background: var(--color-hosted-bg); border-radius: 0.375rem; border-left: 3px solid var(--color-warning);">
<strong class="text-warning text-xs flex items-center gap-1 mb-1"> <strong style="color: var(--color-warning); font-size: 0.6875rem; display: flex; align-items: center; gap: 0.25rem; margin-bottom: 0.375rem;">
<span>⚠</span> Mögliche Einschränkungen: <span>⚠</span> Mögliche Einschränkungen:
</strong> </strong>
<ul class="ml-4 text-xs leading-normal"> <ul style="margin: 0; padding-left: 1rem; font-size: 0.625rem; line-height: 1.4; color: var(--color-text);">
${confidence.uncertaintyFactors.slice(0, 3).map(f => `<li class="mb-1">${sanitizeText(f)}</li>`).join('')} ${confidence.uncertaintyFactors.slice(0, 3).map(f => `<li style="margin-bottom: 0.25rem;">${sanitizeText(f)}</li>`).join('')}
</ul> </ul>
</div> </div>
` : ''} ` : ''}
<div class="mt-3 pt-3 border-t border-secondary text-xs text-secondary text-center"> <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;">
Forensisch fundierte KI-Analyse Forensisch fundierte KI-Analyse
</div> </div>
</div> </div>
@ -2151,18 +2159,18 @@ class AIQueryInterface {
if (!pros?.length && !cons?.length) return ''; if (!pros?.length && !cons?.length) return '';
return ` return `
<div class="grid grid-cols-2 gap-4 mb-6"> <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; margin-bottom: 1.5rem;">
${pros?.length ? ` ${pros?.length ? `
<div class="card-info-sm border-l-4" style="border-left-color: var(--color-accent); background-color: var(--color-oss-bg);"> <div style="background-color: var(--color-oss-bg); padding: 1rem; border-radius: 0.5rem; border-left: 3px solid var(--color-accent);">
<h5 class="mb-2 text-accent text-sm">✓ Vorteile</h5> <h5 style="margin: 0 0 0.5rem 0; color: var(--color-accent); font-size: 0.875rem;">✓ Vorteile</h5>
<ul style="margin: 0; padding-left: 1rem;"> <ul style="margin: 0; padding-left: 1rem;">
${pros.map(pro => `<li style="margin-bottom: 0.25rem;">${sanitizeText(pro)}</li>`).join('')} ${pros.map(pro => `<li style="margin-bottom: 0.25rem;">${sanitizeText(pro)}</li>`).join('')}
</ul> </ul>
</div> </div>
` : ''} ` : ''}
${cons?.length ? ` ${cons?.length ? `
<div class="card-info-sm border-l-4" style="border-left-color: var(--color-warning); background-color: var(--color-hosted-bg);"> <div style="background-color: var(--color-hosted-bg); padding: 1rem; border-radius: 0.5rem; border-left: 3px solid var(--color-warning);">
<h5 class="mb-2 text-warning text-sm">✗ Nachteile</h5> <h5 style="margin: 0 0 0.5rem 0; color: var(--color-warning); font-size: 0.875rem;">✗ Nachteile</h5>
<ul style="margin: 0; padding-left: 1rem;"> <ul style="margin: 0; padding-left: 1rem;">
${cons.map(con => `<li style="margin-bottom: 0.25rem;">${sanitizeText(con)}</li>`).join('')} ${cons.map(con => `<li style="margin-bottom: 0.25rem;">${sanitizeText(con)}</li>`).join('')}
</ul> </ul>
@ -2176,7 +2184,7 @@ class AIQueryInterface {
const isMethod = tool.type === 'method'; const isMethod = tool.type === 'method';
return ` return `
<div class="grid grid-auto-fit gap-3 text-sm text-secondary mb-4 p-3 bg-secondary rounded"> <div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 0.75rem; font-size: 0.8125rem; color: var(--color-text-secondary); margin-bottom: 1rem; padding: 0.75rem; background-color: var(--color-bg-secondary); border-radius: 0.375rem;">
${!isMethod ? `<div><strong>Plattformen:</strong> ${tool.platforms.join(', ')}</div>` : ''} ${!isMethod ? `<div><strong>Plattformen:</strong> ${tool.platforms.join(', ')}</div>` : ''}
<div><strong>Skill Level:</strong> ${tool.skillLevel}</div> <div><strong>Skill Level:</strong> ${tool.skillLevel}</div>
${!isMethod ? `<div><strong>Lizenz:</strong> ${tool.license}</div>` : ''} ${!isMethod ? `<div><strong>Lizenz:</strong> ${tool.license}</div>` : ''}
@ -2187,9 +2195,9 @@ class AIQueryInterface {
renderAlternatives(alternatives) { renderAlternatives(alternatives) {
return ` return `
<div class="bg-secondary p-4 rounded mb-4"> <div style="background-color: var(--color-bg-secondary); padding: 1rem; border-radius: 0.5rem; margin-bottom: 1rem;">
<h5 class="mb-2 text-secondary text-sm">Alternative Ansätze</h5> <h5 style="margin: 0 0 0.5rem 0; color: var(--color-text-secondary); font-size: 0.875rem;">Alternative Ansätze</h5>
<div class="leading-relaxed">${sanitizeText(alternatives)}</div> <div style="margin: 0; line-height: 1.6; white-space: pre-wrap; word-wrap: break-word;">${sanitizeText(alternatives)}</div>
</div> </div>
`; `;
} }
@ -2231,6 +2239,15 @@ class AIQueryInterface {
} }
} }
getSuitabilityText(score) {
const texts = {
high: 'GUT GEEIGNET',
medium: 'GEEIGNET',
low: 'VIELLEICHT GEEIGNET'
};
return texts[score] || 'GEEIGNET';
}
showLoading() { showLoading() {
showElement(this.elements.loading); showElement(this.elements.loading);
} }