phase 2
This commit is contained in:
@@ -217,7 +217,6 @@ const domainAgnosticSoftware = data['domain-agnostic-software'] || [];
|
||||
|
||||
<script type="module" define:vars={{ tools, phases, domainAgnosticSoftware }}>
|
||||
|
||||
// Utility functions (inline to avoid import issues)
|
||||
function showElement(element) {
|
||||
if (element) {
|
||||
element.style.display = 'block';
|
||||
@@ -908,40 +907,537 @@ class AIQueryInterface {
|
||||
}
|
||||
|
||||
renderAuditTrail(rawAuditTrail) {
|
||||
// Simplified audit trail rendering - remove complex processor
|
||||
const container = document.getElementById('audit-trail-container');
|
||||
if (!container || !rawAuditTrail || !Array.isArray(rawAuditTrail)) return;
|
||||
if (!container || !rawAuditTrail || !Array.isArray(rawAuditTrail)) {
|
||||
console.warn('[AI Interface] Cannot render audit trail: invalid container or data');
|
||||
return;
|
||||
}
|
||||
|
||||
const totalTime = rawAuditTrail.reduce((sum, entry) => sum + (entry.processingTimeMs || 0), 0);
|
||||
const avgConfidence = rawAuditTrail.length > 0
|
||||
? Math.round(rawAuditTrail.reduce((sum, entry) => sum + (entry.confidence || 0), 0) / rawAuditTrail.length)
|
||||
: 0;
|
||||
console.log('[AI Interface] Rendering comprehensive audit trail with', rawAuditTrail.length, 'entries');
|
||||
|
||||
container.innerHTML = `
|
||||
<div class="audit-trail-container">
|
||||
<div class="audit-trail-header">
|
||||
<div class="audit-trail-title">
|
||||
<div class="audit-icon">
|
||||
<div class="audit-icon-gradient">✓</div>
|
||||
<h4>KI-Entscheidungspfad</h4>
|
||||
try {
|
||||
// Calculate audit statistics
|
||||
const stats = this.calculateAuditStats(rawAuditTrail);
|
||||
|
||||
container.innerHTML = `
|
||||
<div class="audit-trail-container">
|
||||
<div class="audit-trail-header clickable" onclick="this.parentElement.querySelector('.audit-trail-details').classList.toggle('collapsed'); this.querySelector('.toggle-icon').style.transform = this.parentElement.querySelector('.audit-trail-details').classList.contains('collapsed') ? 'rotate(0deg)' : 'rotate(90deg)';">
|
||||
<div class="audit-trail-title">
|
||||
<div class="audit-icon">
|
||||
<div class="audit-icon-gradient">🔍</div>
|
||||
<h4>KI-Entscheidungspfad</h4>
|
||||
</div>
|
||||
<div class="audit-stats">
|
||||
<div class="stat-item">
|
||||
<div class="stat-dot stat-time"></div>
|
||||
<span>${formatDuration(stats.totalTime)}</span>
|
||||
</div>
|
||||
<div class="stat-item">
|
||||
<div class="stat-dot" style="background-color: ${getConfidenceColor(stats.avgConfidence)};"></div>
|
||||
<span>${stats.avgConfidence}% Vertrauen</span>
|
||||
</div>
|
||||
<div class="stat-item">
|
||||
<span>${rawAuditTrail.length} Schritte</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="audit-stats">
|
||||
<div class="stat-item">
|
||||
<span>${formatDuration(totalTime)}</span>
|
||||
<svg class="toggle-icon" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="transform: rotate(90deg);">
|
||||
<polyline points="9 18 15 12 9 6"/>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<div class="audit-trail-details">
|
||||
<!-- Audit Summary -->
|
||||
<div class="audit-summary">
|
||||
<div class="summary-header">📊 Analyse-Zusammenfassung</div>
|
||||
<div class="summary-grid">
|
||||
<div class="summary-stat">
|
||||
<div class="summary-value success">${stats.aiDecisionCount}</div>
|
||||
<div class="summary-label">KI-Entscheidungen</div>
|
||||
</div>
|
||||
<div class="summary-stat">
|
||||
<div class="summary-value ${stats.embeddingsUsageCount > 0 ? 'success' : 'warning'}">${stats.embeddingsUsageCount}</div>
|
||||
<div class="summary-label">Semantische Suchen</div>
|
||||
</div>
|
||||
<div class="summary-stat">
|
||||
<div class="summary-value success">${stats.toolSelectionCount}</div>
|
||||
<div class="summary-label">Tool-Auswahlen</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="stat-item">
|
||||
<span>${avgConfidence}% Vertrauen</span>
|
||||
</div>
|
||||
<div class="stat-item">
|
||||
<span>${rawAuditTrail.length} Schritte</span>
|
||||
|
||||
<div class="insights-section">
|
||||
${stats.qualityMetrics.aiTransparency >= 80 ? `
|
||||
<div class="insights-header success">✅ Hohe Transparenz</div>
|
||||
<ul class="insights-list">
|
||||
<li>${stats.qualityMetrics.aiTransparency}% der Entscheidungen mit nachvollziehbarer Begründung</li>
|
||||
<li>Durchschnittliche Verarbeitungszeit: ${formatDuration(stats.qualityMetrics.avgProcessingTime)}</li>
|
||||
</ul>
|
||||
` : `
|
||||
<div class="insights-header warning">⚠️ Transparenz-Hinweise</div>
|
||||
<ul class="insights-list">
|
||||
<li>Nur ${stats.qualityMetrics.aiTransparency}% der Entscheidungen vollständig dokumentiert</li>
|
||||
<li>Einige KI-Entscheidungen ohne detaillierte Begründung</li>
|
||||
</ul>
|
||||
`}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Process Flow -->
|
||||
<div class="audit-process-flow">
|
||||
${this.renderPhaseGroups(rawAuditTrail, stats)}
|
||||
</div>
|
||||
|
||||
<!-- Download/Upload Controls -->
|
||||
<div class="ai-results-controls" style="margin-top: 1.5rem; text-align: center; border-top: 1px solid var(--color-border); padding-top: 1rem;">
|
||||
<button id="download-results-btn" class="btn btn-secondary" style="margin-right: 0.5rem;">
|
||||
<svg width="16" height="16" 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>
|
||||
Analyse herunterladen
|
||||
</button>
|
||||
|
||||
<label for="upload-results" class="btn btn-secondary">
|
||||
<svg width="16" height="16" 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="17 8 12 3 7 8"/>
|
||||
<line x1="12" y1="3" x2="12" y2="15"/>
|
||||
</svg>
|
||||
Analyse hochladen
|
||||
<input type="file" id="upload-results" accept=".json" style="display: none;" />
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<!-- Technical Details Toggle -->
|
||||
<div class="technical-toggle">
|
||||
<button class="technical-toggle-btn" onclick="this.parentElement.parentElement.querySelector('.technical-details').classList.toggle('collapsed'); this.textContent = this.parentElement.parentElement.querySelector('.technical-details').classList.contains('collapsed') ? 'Technische Details anzeigen' : 'Technische Details verbergen';">
|
||||
Technische Details anzeigen
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Technical Details -->
|
||||
<div class="technical-details collapsed">
|
||||
${this.renderTechnicalDetails(rawAuditTrail)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
// Setup download functionality
|
||||
this.setupDownloadUpload();
|
||||
|
||||
} catch (error) {
|
||||
console.error('[AI Interface] Error rendering audit trail:', error);
|
||||
container.innerHTML = `
|
||||
<div class="audit-trail-container">
|
||||
<div class="audit-trail-header">
|
||||
<div class="audit-trail-title">
|
||||
<div class="audit-icon">
|
||||
<div class="audit-icon-gradient">⚠️</div>
|
||||
<h4>Audit Trail Fehler</h4>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="audit-trail-details">
|
||||
<p style="color: var(--color-error); padding: 1rem;">
|
||||
Fehler beim Rendern des Audit Trails. Details in der Konsole.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
calculateAuditStats(auditTrail) {
|
||||
if (!auditTrail || auditTrail.length === 0) {
|
||||
return {
|
||||
totalTime: 0,
|
||||
avgConfidence: 0,
|
||||
stepCount: 0,
|
||||
aiDecisionCount: 0,
|
||||
embeddingsUsageCount: 0,
|
||||
toolSelectionCount: 0,
|
||||
qualityMetrics: {
|
||||
avgProcessingTime: 0,
|
||||
aiTransparency: 0
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const totalTime = auditTrail.reduce((sum, entry) => sum + (entry.processingTimeMs || 0), 0);
|
||||
const validConfidenceEntries = auditTrail.filter(entry => typeof entry.confidence === 'number');
|
||||
const avgConfidence = validConfidenceEntries.length > 0
|
||||
? Math.round(validConfidenceEntries.reduce((sum, entry) => sum + entry.confidence, 0) / validConfidenceEntries.length)
|
||||
: 0;
|
||||
|
||||
const aiDecisionCount = auditTrail.filter(entry => entry.action === 'ai-decision').length;
|
||||
const embeddingsUsageCount = auditTrail.filter(entry => entry.metadata?.embeddingsUsed).length;
|
||||
const toolSelectionCount = auditTrail.filter(entry => entry.action === 'selection-decision').length;
|
||||
|
||||
const avgProcessingTime = auditTrail.length > 0 ? totalTime / auditTrail.length : 0;
|
||||
const aiTransparency = auditTrail.length > 0 ?
|
||||
(auditTrail.filter(entry => entry.metadata?.aiPrompt || entry.metadata?.reasoning).length / auditTrail.length) * 100 : 0;
|
||||
|
||||
return {
|
||||
totalTime,
|
||||
avgConfidence,
|
||||
stepCount: auditTrail.length,
|
||||
aiDecisionCount,
|
||||
embeddingsUsageCount,
|
||||
toolSelectionCount,
|
||||
qualityMetrics: {
|
||||
avgProcessingTime,
|
||||
aiTransparency: Math.round(aiTransparency)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
renderPhaseGroups(auditTrail, stats) {
|
||||
// Group audit entries by phase
|
||||
const phaseGroups = new Map();
|
||||
|
||||
auditTrail.forEach(entry => {
|
||||
const phase = entry.phase || 'unknown';
|
||||
if (!phaseGroups.has(phase)) {
|
||||
phaseGroups.set(phase, []);
|
||||
}
|
||||
// FIXED: Remove non-null assertion, use proper null checking
|
||||
const phaseEntries = phaseGroups.get(phase);
|
||||
if (phaseEntries) {
|
||||
phaseEntries.push(entry);
|
||||
}
|
||||
});
|
||||
|
||||
let html = '';
|
||||
let groupIndex = 0;
|
||||
|
||||
for (const [phaseName, entries] of phaseGroups) {
|
||||
const isLastPhase = groupIndex === phaseGroups.size - 1;
|
||||
const phaseAvgConfidence = entries.reduce((sum, e) => sum + (e.confidence || 0), 0) / entries.length;
|
||||
|
||||
html += `
|
||||
<div class="phase-group ${isLastPhase ? 'last-phase' : ''}">
|
||||
<div class="phase-header" style="display: flex; align-items: center; gap: 1rem; margin-bottom: 1rem;">
|
||||
<div style="display: flex; align-items: center; gap: 0.75rem;">
|
||||
<div class="phase-icon">${this.getPhaseIcon(phaseName)}</div>
|
||||
<div class="phase-name">${this.getPhaseDisplayName(phaseName)}</div>
|
||||
</div>
|
||||
<div class="phase-divider"></div>
|
||||
<div class="phase-stats">
|
||||
<div class="confidence-bar">
|
||||
<div class="confidence-fill" style="width: ${phaseAvgConfidence}%; background-color: ${getConfidenceColor(phaseAvgConfidence)};"></div>
|
||||
</div>
|
||||
<span class="confidence-text">${Math.round(phaseAvgConfidence)}%</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="phase-entries">
|
||||
${entries.map(entry => this.renderAuditEntry(entry)).join('')}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
groupIndex++;
|
||||
}
|
||||
|
||||
return html;
|
||||
}
|
||||
|
||||
renderAuditEntry(entry) {
|
||||
const confidenceColor = getConfidenceColor(entry.confidence || 0);
|
||||
const processingTime = formatDuration(entry.processingTimeMs || 0);
|
||||
|
||||
return `
|
||||
<div class="audit-entry">
|
||||
<div class="entry-main">
|
||||
<div class="entry-action">${this.getActionDisplayName(entry.action)}</div>
|
||||
<div class="entry-meta">
|
||||
<div class="confidence-indicator" style="background-color: ${confidenceColor};"></div>
|
||||
<span class="confidence-value">${entry.confidence || 0}%</span>
|
||||
<span class="processing-time">${processingTime}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
${this.renderEntryDetails(entry)}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
renderEntryDetails(entry) {
|
||||
const details = [];
|
||||
|
||||
// AI-specific details
|
||||
if (entry.action === 'ai-decision' && entry.metadata?.reasoning) {
|
||||
details.push(`<div class="detail-item"><strong>Begründung:</strong> ${truncateText(entry.metadata.reasoning, 200)}</div>`);
|
||||
}
|
||||
|
||||
// Tool selection details
|
||||
if (entry.action === 'selection-decision') {
|
||||
if (entry.metadata?.selectedToolsCount && entry.metadata?.availableToolsCount) {
|
||||
details.push(`<div class="detail-item"><strong>Auswahl:</strong> ${entry.metadata.selectedToolsCount} von ${entry.metadata.availableToolsCount} Tools</div>`);
|
||||
}
|
||||
if (entry.metadata?.selectionMethod) {
|
||||
details.push(`<div class="detail-item"><strong>Methode:</strong> ${entry.metadata.selectionMethod}</div>`);
|
||||
}
|
||||
}
|
||||
|
||||
// Embeddings details
|
||||
if (entry.metadata?.embeddingsUsed && entry.metadata?.totalMatches) {
|
||||
details.push(`<div class="detail-item"><strong>Semantische Treffer:</strong> ${entry.metadata.totalMatches}</div>`);
|
||||
}
|
||||
|
||||
// Confidence factors
|
||||
if (entry.metadata?.confidenceFactors?.length > 0) {
|
||||
const factors = entry.metadata.confidenceFactors.slice(0, 2).join(', ');
|
||||
details.push(`<div class="detail-item"><strong>Faktoren:</strong> ${factors}</div>`);
|
||||
}
|
||||
|
||||
if (details.length === 0) return '';
|
||||
|
||||
return `
|
||||
<div class="entry-details">
|
||||
${details.join('')}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
renderTechnicalDetails(auditTrail) {
|
||||
return auditTrail.map(entry => `
|
||||
<div class="technical-entry">
|
||||
<div class="technical-header">
|
||||
<div class="technical-phase">${entry.phase}/${entry.action}</div>
|
||||
<div class="technical-time">${new Date(entry.timestamp).toLocaleTimeString('de-DE')}</div>
|
||||
</div>
|
||||
<div class="technical-content">
|
||||
${entry.metadata?.aiModel ? `<div class="technical-row">Model: ${entry.metadata.aiModel}</div>` : ''}
|
||||
${entry.metadata?.promptTokens ? `<div class="technical-row">Tokens: ${entry.metadata.promptTokens}/${entry.metadata.completionTokens}</div>` : ''}
|
||||
${entry.metadata?.microTaskType ? `<div class="technical-row">Task: ${entry.metadata.microTaskType}</div>` : ''}
|
||||
${entry.metadata?.selectionMethod ? `<div class="technical-row">Method: ${entry.metadata.selectionMethod}</div>` : ''}
|
||||
<div class="technical-row">Confidence: ${entry.confidence}% (${entry.processingTimeMs}ms)</div>
|
||||
</div>
|
||||
</div>
|
||||
`).join('');
|
||||
}
|
||||
|
||||
getPhaseIcon(phase) {
|
||||
const icons = {
|
||||
'initialization': '🚀',
|
||||
'tool-selection': '🔧',
|
||||
'contextual-analysis': '🧠',
|
||||
'workflow-phase': '⚡',
|
||||
'tool-reasoning': '💭',
|
||||
'knowledge-synthesis': '📚',
|
||||
'confidence-scoring': '📊',
|
||||
'phase-completion': '✅',
|
||||
'completion': '🎯',
|
||||
'embeddings': '🔍',
|
||||
'unknown': '❓'
|
||||
};
|
||||
return icons[phase] || icons['unknown'];
|
||||
}
|
||||
|
||||
getPhaseDisplayName(phase) {
|
||||
const names = {
|
||||
'initialization': 'Initialisierung',
|
||||
'tool-selection': 'Tool-Auswahl',
|
||||
'contextual-analysis': 'Kontext-Analyse',
|
||||
'workflow-phase': 'Workflow-Phase',
|
||||
'tool-reasoning': 'Tool-Bewertung',
|
||||
'knowledge-synthesis': 'Wissens-Synthese',
|
||||
'confidence-scoring': 'Vertrauenswertung',
|
||||
'phase-completion': 'Phasen-Vervollständigung',
|
||||
'completion': 'Abschluss',
|
||||
'embeddings': 'Semantische Suche',
|
||||
'unknown': 'Unbekannt'
|
||||
};
|
||||
return names[phase] || phase;
|
||||
}
|
||||
|
||||
getActionDisplayName(action) {
|
||||
const actions = {
|
||||
'pipeline-start': 'Analyse gestartet',
|
||||
'selection-decision': 'Tools ausgewählt',
|
||||
'ai-decision': 'KI-Entscheidung',
|
||||
'phase-tool-selection': 'Phasen-Tools evaluiert',
|
||||
'tool-added-to-phase': 'Tool zur Phase hinzugefügt',
|
||||
'concept-selection': 'Konzepte ausgewählt',
|
||||
'tool-confidence': 'Vertrauen berechnet',
|
||||
'phase-enhancement': 'Phase vervollständigt',
|
||||
'similarity-search': 'Ähnlichkeitssuche',
|
||||
'pipeline-end': 'Analyse abgeschlossen'
|
||||
};
|
||||
return actions[action] || action;
|
||||
}
|
||||
|
||||
setupDownloadUpload() {
|
||||
const downloadBtn = document.getElementById('download-results-btn');
|
||||
const uploadInput = document.getElementById('upload-results');
|
||||
|
||||
if (downloadBtn) {
|
||||
downloadBtn.addEventListener('click', () => this.downloadResults());
|
||||
}
|
||||
|
||||
if (uploadInput) {
|
||||
uploadInput.addEventListener('change', (event) => {
|
||||
// FIXED: Remove TypeScript casting
|
||||
const files = event.target.files;
|
||||
const file = files ? files[0] : null;
|
||||
if (file) {
|
||||
this.handleFileUpload(file);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
downloadResults() {
|
||||
if (!this.currentRecommendation) {
|
||||
alert('Keine Analyse zum Herunterladen verfügbar.');
|
||||
return;
|
||||
}
|
||||
|
||||
// FIXED: Use safer property access
|
||||
const inputValue = this.elements.input ? this.elements.input.value : '';
|
||||
|
||||
const exportData = {
|
||||
metadata: {
|
||||
timestamp: new Date().toISOString(),
|
||||
version: "1.0",
|
||||
toolsDataHash: "current", // This would come from dataService
|
||||
aiModel: "claude-sonnet-4", // This would come from aiService
|
||||
aiParameters: {},
|
||||
userQuery: inputValue,
|
||||
mode: this.currentMode,
|
||||
processingStats: {},
|
||||
exportedBy: 'ForensicPathways'
|
||||
},
|
||||
recommendation: this.currentRecommendation,
|
||||
auditTrail: this.currentRecommendation.auditTrail || [],
|
||||
rawContext: {
|
||||
selectedTools: [],
|
||||
backgroundKnowledge: [],
|
||||
contextHistory: [],
|
||||
embeddingsSimilarities: {}
|
||||
}
|
||||
};
|
||||
|
||||
const blob = new Blob([JSON.stringify(exportData, null, 2)], {
|
||||
type: 'application/json'
|
||||
});
|
||||
|
||||
const url = URL.createObjectURL(blob);
|
||||
const a = document.createElement('a');
|
||||
a.href = url;
|
||||
a.download = `forensic-ai-analysis-${Date.now()}.json`;
|
||||
a.click();
|
||||
URL.revokeObjectURL(url);
|
||||
|
||||
console.log('[AI Interface] Analysis downloaded');
|
||||
}
|
||||
|
||||
async handleFileUpload(file) {
|
||||
try {
|
||||
// Security validation
|
||||
if (file.size > 10 * 1024 * 1024) {
|
||||
throw new Error('Datei zu groß (max 10MB)');
|
||||
}
|
||||
|
||||
if (!file.name.endsWith('.json')) {
|
||||
throw new Error('Ungültiger Dateityp - nur JSON-Dateien werden unterstützt');
|
||||
}
|
||||
|
||||
const text = await file.text();
|
||||
let data;
|
||||
|
||||
try {
|
||||
data = JSON.parse(text);
|
||||
} catch (error) {
|
||||
throw new Error('Ungültiges JSON-Format');
|
||||
}
|
||||
|
||||
if (!this.validateUploadStructure(data)) {
|
||||
throw new Error('Ungültiges Analyse-Dateiformat');
|
||||
}
|
||||
|
||||
console.log('[AI Interface] Valid analysis file uploaded');
|
||||
this.displayUploadedResults(data);
|
||||
|
||||
} catch (error) {
|
||||
console.error('[AI Interface] Upload failed:', error);
|
||||
alert(`Upload fehlgeschlagen: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
validateUploadStructure(data) {
|
||||
try {
|
||||
return !!(
|
||||
data &&
|
||||
typeof data === 'object' &&
|
||||
data.metadata &&
|
||||
typeof data.metadata === 'object' &&
|
||||
typeof data.metadata.timestamp === 'string' &&
|
||||
data.recommendation &&
|
||||
typeof data.recommendation === 'object' &&
|
||||
Array.isArray(data.auditTrail)
|
||||
);
|
||||
} catch (error) {
|
||||
console.error('[AI Interface] Structure validation error:', error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
displayUploadedResults(data) {
|
||||
try {
|
||||
// Show upload banner
|
||||
this.showUploadedBanner(data.metadata);
|
||||
|
||||
// Restore interface state
|
||||
this.currentRecommendation = data.recommendation;
|
||||
|
||||
// Display the uploaded analysis
|
||||
this.showResults();
|
||||
|
||||
// Update the recommendation display
|
||||
if (data.metadata.mode === 'workflow') {
|
||||
this.displayWorkflowResults(data.recommendation, data.metadata.userQuery);
|
||||
} else {
|
||||
this.displayToolResults(data.recommendation, data.metadata.userQuery);
|
||||
}
|
||||
|
||||
// Render the uploaded audit trail
|
||||
setTimeout(() => {
|
||||
this.renderAuditTrail(data.auditTrail);
|
||||
}, 100);
|
||||
|
||||
console.log('[AI Interface] Uploaded analysis displayed successfully');
|
||||
} catch (error) {
|
||||
console.error('[AI Interface] Error displaying uploaded results:', error);
|
||||
alert('Fehler beim Anzeigen der hochgeladenen Analyse');
|
||||
}
|
||||
}
|
||||
|
||||
showUploadedBanner(metadata) {
|
||||
const banner = `
|
||||
<div class="uploaded-results-banner" style="background: var(--color-bg-secondary); border: 1px solid var(--color-warning); border-radius: 0.5rem; padding: 1rem; margin-bottom: 1rem; display: flex; align-items: center; gap: 1rem;">
|
||||
<div style="font-size: 1.5rem;">📁</div>
|
||||
<div style="flex: 1;">
|
||||
<strong style="color: var(--color-warning);">Hochgeladene Analyse</strong>
|
||||
<div style="font-size: 0.875rem; color: var(--color-text-secondary); margin-top: 0.25rem;">
|
||||
Erstellt: ${new Date(metadata.timestamp).toLocaleString('de-DE')} |
|
||||
Modus: ${metadata.mode} |
|
||||
${metadata.toolsDataHash ? `Hash: ${metadata.toolsDataHash.slice(0, 8)}...` : ''}
|
||||
</div>
|
||||
</div>
|
||||
<button onclick="this.parentElement.remove()" style="background: none; border: none; color: var(--color-text-secondary); cursor: pointer; font-size: 1.25rem;">×</button>
|
||||
</div>
|
||||
`;
|
||||
|
||||
// FIXED: Add null checking
|
||||
if (this.elements && this.elements.results) {
|
||||
this.elements.results.insertAdjacentHTML('afterbegin', banner);
|
||||
}
|
||||
}
|
||||
|
||||
renderHeader(title, query) {
|
||||
return `
|
||||
<div style="text-align: center; margin-bottom: 2rem; padding: 1.5rem; background: linear-gradient(135deg, var(--color-primary) 0%, #525252 100%); color: white; border-radius: 0.75rem;">
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
import { createToolSlug } from '../utils/toolHelpers.js';
|
||||
import { createToolSlug } from '../utils/clientUtils.js';
|
||||
|
||||
export interface Props {
|
||||
toolName: string;
|
||||
|
||||
Reference in New Issue
Block a user