This commit is contained in:
overcuriousity 2025-08-17 17:27:08 +02:00
parent 5ecbabea90
commit bcd92af8a0
10 changed files with 18 additions and 77 deletions

View File

@ -1185,7 +1185,6 @@ class AIQueryInterface {
keyInsights.push('Mehrheit der Analyseschritte mit hoher Sicherheit'); keyInsights.push('Mehrheit der Analyseschritte mit hoher Sicherheit');
} }
// Calculate meaningful insights based on response quality
const responseQualityEntries = auditTrail.filter(e => const responseQualityEntries = auditTrail.filter(e =>
e.metadata?.responseConfidence && e.metadata.finalConfidence e.metadata?.responseConfidence && e.metadata.finalConfidence
); );
@ -1204,7 +1203,6 @@ class AIQueryInterface {
potentialIssues.push(`${lowConfidenceSteps} Analyseschritte mit niedriger Konfidenz`); potentialIssues.push(`${lowConfidenceSteps} Analyseschritte mit niedriger Konfidenz`);
} }
// Check for truncated responses
const truncatedResponses = auditTrail.filter(e => const truncatedResponses = auditTrail.filter(e =>
e.output && typeof e.output === 'object' && e.output && typeof e.output === 'object' &&
e.output.response && e.output.response.includes('...') e.output.response && e.output.response.includes('...')
@ -1230,7 +1228,6 @@ class AIQueryInterface {
medium: mediumConfidenceSteps, medium: mediumConfidenceSteps,
low: lowConfidenceSteps low: lowConfidenceSteps
} }
// aiTransparency removed entirely
}, },
analysisQuality, analysisQuality,
keyInsights, keyInsights,
@ -1339,7 +1336,6 @@ class AIQueryInterface {
const details = []; const details = [];
const metadata = entry.metadata || {}; const metadata = entry.metadata || {};
// The backend now provides meaningful inputSummary and outputSummary
if (metadata.inputSummary && metadata.inputSummary !== 'Leer') { if (metadata.inputSummary && metadata.inputSummary !== 'Leer') {
details.push(`<div class="detail-item"><strong>Eingabe:</strong> ${escapeHtml(metadata.inputSummary)}</div>`); details.push(`<div class="detail-item"><strong>Eingabe:</strong> ${escapeHtml(metadata.inputSummary)}</div>`);
} }
@ -1348,12 +1344,10 @@ class AIQueryInterface {
details.push(`<div class="detail-item"><strong>Ausgabe:</strong> ${escapeHtml(metadata.outputSummary)}</div>`); details.push(`<div class="detail-item"><strong>Ausgabe:</strong> ${escapeHtml(metadata.outputSummary)}</div>`);
} }
// Show meaningful reasoning (backend now avoids generic "completed with X%" messages)
if (metadata.reasoning && !metadata.reasoning.includes('completed with')) { if (metadata.reasoning && !metadata.reasoning.includes('completed with')) {
details.push(`<div class="detail-item"><strong>Begründung:</strong> ${escapeHtml(metadata.reasoning)}</div>`); details.push(`<div class="detail-item"><strong>Begründung:</strong> ${escapeHtml(metadata.reasoning)}</div>`);
} }
// Action-specific additional details
if (entry.action === 'similarity-search' && metadata.similarityScores) { if (entry.action === 'similarity-search' && metadata.similarityScores) {
const topScores = Object.entries(metadata.similarityScores) const topScores = Object.entries(metadata.similarityScores)
.sort(([,a], [,b]) => (b) - (a)) .sort(([,a], [,b]) => (b) - (a))
@ -1597,11 +1591,9 @@ class AIQueryInterface {
embeddingsSimilarities: {} embeddingsSimilarities: {}
}; };
// Enhanced export structure with proper audit trail handling
const exportData = { const exportData = {
metadata: { metadata: {
timestamp: new Date().toISOString(), timestamp: new Date().toISOString(),
version: "1.1", // Increment version for improved structure
toolsDataHash: toolsDataHash, toolsDataHash: toolsDataHash,
aiModel: aiModel, aiModel: aiModel,
aiParameters: aiParameters, aiParameters: aiParameters,
@ -1609,16 +1601,13 @@ class AIQueryInterface {
mode: this.currentMode, mode: this.currentMode,
processingStats: processingStats, processingStats: processingStats,
exportedBy: 'ForensicPathways', exportedBy: 'ForensicPathways',
auditTrailVersion: '1.1' // Track audit trail format version
}, },
recommendation: { recommendation: {
// Export recommendation without auditTrail to avoid duplication
...this.currentRecommendation, ...this.currentRecommendation,
auditTrail: undefined // Remove from recommendation as it's at top level auditTrail: undefined
}, },
auditTrail: this.currentRecommendation.auditTrail || [], // Extract to top level auditTrail: this.currentRecommendation.auditTrail || [],
rawContext: rawContext, rawContext: rawContext,
// Add validation checksum for integrity
checksum: this.calculateDataChecksum(this.currentRecommendation) checksum: this.calculateDataChecksum(this.currentRecommendation)
}; };
@ -1647,7 +1636,6 @@ class AIQueryInterface {
if (!data) return 'empty'; if (!data) return 'empty';
try { try {
// Simple checksum based on key data properties
const keyData = { const keyData = {
recommendedToolsCount: data.recommended_tools?.length || 0, recommendedToolsCount: data.recommended_tools?.length || 0,
backgroundKnowledgeCount: data.background_knowledge?.length || 0, backgroundKnowledgeCount: data.background_knowledge?.length || 0,
@ -1661,7 +1649,7 @@ class AIQueryInterface {
for (let i = 0; i < dataString.length; i++) { for (let i = 0; i < dataString.length; i++) {
const char = dataString.charCodeAt(i); const char = dataString.charCodeAt(i);
hash = ((hash << 5) - hash) + char; hash = ((hash << 5) - hash) + char;
hash = hash & hash; // Convert to 32-bit integer hash = hash & hash;
} }
return Math.abs(hash).toString(36); return Math.abs(hash).toString(36);
} catch (error) { } catch (error) {
@ -1680,14 +1668,13 @@ class AIQueryInterface {
typeof data.metadata.timestamp === 'string' && typeof data.metadata.timestamp === 'string' &&
data.recommendation && data.recommendation &&
typeof data.recommendation === 'object' && typeof data.recommendation === 'object' &&
Array.isArray(data.auditTrail) // Audit trail at top level Array.isArray(data.auditTrail)
); );
if (!isValid) { if (!isValid) {
return false; return false;
} }
// Enhanced validation for audit trail structure
if (data.auditTrail.length > 0) { if (data.auditTrail.length > 0) {
const sampleEntry = data.auditTrail[0]; const sampleEntry = data.auditTrail[0];
const hasRequiredFields = !!( const hasRequiredFields = !!(
@ -1718,10 +1705,9 @@ class AIQueryInterface {
this.showUploadedBanner(data.metadata); this.showUploadedBanner(data.metadata);
// Fix: Ensure audit trail is available in recommendation for restoreAIResults
this.currentRecommendation = { this.currentRecommendation = {
...data.recommendation, ...data.recommendation,
auditTrail: data.auditTrail // Restore audit trail to recommendation object auditTrail: data.auditTrail
}; };
this.showResults(); this.showResults();
@ -1813,7 +1799,6 @@ class AIQueryInterface {
throw new Error('Ungültiges Analyse-Dateiformat'); throw new Error('Ungültiges Analyse-Dateiformat');
} }
// Store audit trail separately for restore function
this.uploadedAuditTrail = data.auditTrail; this.uploadedAuditTrail = data.auditTrail;
console.log('[AI Interface] Valid previous analysis file uploaded:', { console.log('[AI Interface] Valid previous analysis file uploaded:', {
@ -2282,7 +2267,6 @@ class AIQueryInterface {
if (this.currentRecommendation && this.elements.results) { if (this.currentRecommendation && this.elements.results) {
this.showResults(); this.showResults();
// Check both locations for audit trail for backward compatibility
const auditTrail = this.currentRecommendation.auditTrail || this.uploadedAuditTrail; const auditTrail = this.currentRecommendation.auditTrail || this.uploadedAuditTrail;
if (auditTrail && Array.isArray(auditTrail) && auditTrail.length > 0) { if (auditTrail && Array.isArray(auditTrail) && auditTrail.length > 0) {

View File

@ -1,5 +1,5 @@
--- ---
// src/components/ContributionButton.astro - CLEANED: Removed duplicate auth script // src/components/ContributionButton.astro
export interface Props { export interface Props {
type: 'edit' | 'new' | 'write'; type: 'edit' | 'new' | 'write';
toolName?: string; toolName?: string;

View File

@ -4,7 +4,6 @@ import { getToolsData } from '../utils/dataService.js';
const data = await getToolsData(); const data = await getToolsData();
const scenarios = data.scenarios || []; const scenarios = data.scenarios || [];
// Configuration
const maxDisplayed = 9; const maxDisplayed = 9;
const displayedScenarios = scenarios.slice(0, maxDisplayed); const displayedScenarios = scenarios.slice(0, maxDisplayed);
--- ---

View File

@ -16,7 +16,7 @@ const knowledgebaseCollection = defineCollection({
tags: z.array(z.string()).default([]), tags: z.array(z.string()).default([]),
published: z.boolean().default(true), published: z.boolean().default(true),
gated_content: z.boolean().default(false), // NEW: Gated content flag gated_content: z.boolean().default(false),
}) })
}); });

View File

@ -1,4 +1,4 @@
// src/pages/api/ai/embeddings-status.ts - Updated // src/pages/api/ai/embeddings-status.ts
import type { APIRoute } from 'astro'; import type { APIRoute } from 'astro';
import { embeddingsService } from '../../../utils/embeddings.js'; import { embeddingsService } from '../../../utils/embeddings.js';

View File

@ -1,4 +1,4 @@
// src/pages/api/ai/enhance-input.ts - Updated to use refactored services // src/pages/api/ai/enhance-input.ts
import type { APIRoute } from 'astro'; import type { APIRoute } from 'astro';
import { withAPIAuth } from '../../../utils/auth.js'; import { withAPIAuth } from '../../../utils/auth.js';
import { apiError, apiServerError, createAuthErrorResponse } from '../../../utils/api.js'; import { apiError, apiServerError, createAuthErrorResponse } from '../../../utils/api.js';

View File

@ -1,4 +1,4 @@
// src/pages/api/ai/query.ts - Updated to use refactored services // src/pages/api/ai/query.ts
import type { APIRoute } from 'astro'; import type { APIRoute } from 'astro';
import { withAPIAuth } from '../../../utils/auth.js'; import { withAPIAuth } from '../../../utils/auth.js';
import { apiError, apiServerError, createAuthErrorResponse } from '../../../utils/api.js'; import { apiError, apiServerError, createAuthErrorResponse } from '../../../utils/api.js';

View File

@ -1,5 +1,5 @@
--- ---
// src/pages/contribute/index.astro - Consolidated Auth // src/pages/contribute/index.astro
import BaseLayout from '../../layouts/BaseLayout.astro'; import BaseLayout from '../../layouts/BaseLayout.astro';
import { withAuth } from '../../utils/auth.js'; import { withAuth } from '../../utils/auth.js';

View File

@ -1,4 +1,4 @@
// src/utils/aiPipeline.ts - Fixed to remove hardcoded values and improve dynamics // src/utils/aiPipeline.ts
import { getCompressedToolsDataForAI, getDataVersion } from './dataService.js'; import { getCompressedToolsDataForAI, getDataVersion } from './dataService.js';
import { aiService } from './aiService.js'; import { aiService } from './aiService.js';
import { toolSelector, type SelectionContext } from './toolSelector.js'; import { toolSelector, type SelectionContext } from './toolSelector.js';
@ -77,7 +77,6 @@ interface PipelineContext {
}>; }>;
seenToolNames: Set<string>; seenToolNames: Set<string>;
embeddingsSimilarities: Map<string, number>; embeddingsSimilarities: Map<string, number>;
// Add phase metadata for dynamic phase handling
phaseMetadata?: { phaseMetadata?: {
phases: any[]; phases: any[];
criticalPhaseIds: string[]; criticalPhaseIds: string[];
@ -128,7 +127,6 @@ class AIPipeline {
currentContextLength: 0, currentContextLength: 0,
seenToolNames: new Set<string>(), seenToolNames: new Set<string>(),
embeddingsSimilarities: new Map<string, number>(), embeddingsSimilarities: new Map<string, number>(),
// Initialize phase metadata dynamically
phaseMetadata: this.initializePhaseMetadata(toolsData.phases) phaseMetadata: this.initializePhaseMetadata(toolsData.phases)
}; };
@ -259,20 +257,17 @@ class AIPipeline {
}; };
} }
// Dynamically determine critical phases based on typical_tools or key_activities
const criticalPhaseIds = phases const criticalPhaseIds = phases
.filter(phase => { .filter(phase => {
const typicalToolsCount = phase.typical_tools?.length || 0; const typicalToolsCount = phase.typical_tools?.length || 0;
const keyActivitiesCount = phase.key_activities?.length || 0; const keyActivitiesCount = phase.key_activities?.length || 0;
// Consider phases with many tools or activities as critical
return typicalToolsCount >= 3 || keyActivitiesCount >= 2; return typicalToolsCount >= 3 || keyActivitiesCount >= 2;
}) })
.map(phase => phase.id); .map(phase => phase.id);
// Calculate phase complexity based on metadata
const phaseComplexity = new Map<string, number>(); const phaseComplexity = new Map<string, number>();
phases.forEach(phase => { phases.forEach(phase => {
let complexity = 1; // Base complexity let complexity = 1;
if (phase.typical_tools?.length > 5) complexity += 1; if (phase.typical_tools?.length > 5) complexity += 1;
if (phase.key_activities?.length > 3) complexity += 1; if (phase.key_activities?.length > 3) complexity += 1;
@ -389,7 +384,6 @@ class AIPipeline {
const moderatedTaskRelevance = this.moderateTaskRelevance(sel.taskRelevance); const moderatedTaskRelevance = this.moderateTaskRelevance(sel.taskRelevance);
const priority = this.derivePriorityFromScore(moderatedTaskRelevance); const priority = this.derivePriorityFromScore(moderatedTaskRelevance);
// Generate dynamic limitations based on context
const dynamicLimitations = this.generateDynamicLimitations(tool, phase, sel); const dynamicLimitations = this.generateDynamicLimitations(tool, phase, sel);
this.addToolToSelection(context, tool, phase.id, priority, sel.justification, moderatedTaskRelevance, dynamicLimitations); this.addToolToSelection(context, tool, phase.id, priority, sel.justification, moderatedTaskRelevance, dynamicLimitations);
@ -444,18 +438,15 @@ class AIPipeline {
): number { ): number {
let confidence = 60; let confidence = 60;
// Use dynamic phase metadata instead of hardcoded values
const isCritical = phaseMetadata?.criticalPhaseIds.includes(phaseId) || false; const isCritical = phaseMetadata?.criticalPhaseIds.includes(phaseId) || false;
const phaseComplexity = phaseMetadata?.phaseComplexity.get(phaseId) || 1; const phaseComplexity = phaseMetadata?.phaseComplexity.get(phaseId) || 1;
// Selection made
if (selectedCount > 0) { if (selectedCount > 0) {
confidence += 20; confidence += 20;
} else { } else {
return 30; return 30;
} }
// Selection ratio (for phases, 20-50% is reasonable)
const ratio = selectedCount / availableCount; const ratio = selectedCount / availableCount;
if (ratio >= 0.2 && ratio <= 0.5) { if (ratio >= 0.2 && ratio <= 0.5) {
confidence += 15; confidence += 15;
@ -463,17 +454,14 @@ class AIPipeline {
confidence += 10; confidence += 10;
} }
// Dynamic critical phase handling
if (isCritical && selectedCount >= 2) { if (isCritical && selectedCount >= 2) {
confidence += 10; confidence += 10;
} }
// Phase complexity factor
if (phaseComplexity > 2 && selectedCount >= phaseComplexity) { if (phaseComplexity > 2 && selectedCount >= phaseComplexity) {
confidence += 5; confidence += 5;
} }
// Quality of selections (based on task relevance)
const avgRelevance = selections.length > 0 ? const avgRelevance = selections.length > 0 ?
selections.reduce((sum, s) => sum + (s.taskRelevance || 70), 0) / selections.length : 0; selections.reduce((sum, s) => sum + (s.taskRelevance || 70), 0) / selections.length : 0;
@ -489,12 +477,10 @@ class AIPipeline {
private generateDynamicLimitations(tool: any, phase: any, selection: any): string[] { private generateDynamicLimitations(tool: any, phase: any, selection: any): string[] {
const limitations: string[] = []; const limitations: string[] = [];
// Add existing limitations if provided
if (selection.limitations && Array.isArray(selection.limitations)) { if (selection.limitations && Array.isArray(selection.limitations)) {
limitations.push(...selection.limitations); limitations.push(...selection.limitations);
} }
// Generate context-aware limitations
if (tool.type === 'software' && !tool.projectUrl) { if (tool.type === 'software' && !tool.projectUrl) {
limitations.push('Installation und Konfiguration erforderlich'); limitations.push('Installation und Konfiguration erforderlich');
} }
@ -507,12 +493,11 @@ class AIPipeline {
limitations.push('Kommerzielle Lizenz erforderlich'); limitations.push('Kommerzielle Lizenz erforderlich');
} }
// Phase-specific limitations
if (phase.id === 'acquisition' && tool.type === 'method') { if (phase.id === 'acquisition' && tool.type === 'method') {
limitations.push('Sorgfältige Dokumentation für Chain of Custody erforderlich'); limitations.push('Sorgfältige Dokumentation für Chain of Custody erforderlich');
} }
return limitations.slice(0, 3); // Limit to 3 most relevant return limitations.slice(0, 3);
} }
private async processToolMode( private async processToolMode(
@ -699,7 +684,6 @@ class AIPipeline {
moderatedTaskRelevance = this.moderateTaskRelevance(75); moderatedTaskRelevance = this.moderateTaskRelevance(75);
} }
// Generate dynamic limitations instead of hardcoded ones
const dynamicLimitations = this.generateCompletionLimitations(tool, phase, selection); const dynamicLimitations = this.generateCompletionLimitations(tool, phase, selection);
this.addToolToSelection( this.addToolToSelection(
@ -754,10 +738,8 @@ class AIPipeline {
private generateCompletionLimitations(tool: any, phase: any, selection: any): string[] { private generateCompletionLimitations(tool: any, phase: any, selection: any): string[] {
const limitations: string[] = []; const limitations: string[] = [];
// Context-specific limitation for completion tools
limitations.push('Nachträgliche Ergänzung - ursprünglich nicht als Hauptmethode identifiziert'); limitations.push('Nachträgliche Ergänzung - ursprünglich nicht als Hauptmethode identifiziert');
// Tool-specific limitations
if (tool.skillLevel === 'expert') { if (tool.skillLevel === 'expert') {
limitations.push('Erfordert Expertenwissen für optimale Nutzung'); limitations.push('Erfordert Expertenwissen für optimale Nutzung');
} }
@ -766,7 +748,6 @@ class AIPipeline {
limitations.push('Zusätzliche Setup-Zeit erforderlich'); limitations.push('Zusätzliche Setup-Zeit erforderlich');
} }
// Phase-specific context
if (phase.typical_tools && !phase.typical_tools.includes(tool.name)) { if (phase.typical_tools && !phase.typical_tools.includes(tool.name)) {
limitations.push(`Nicht typisch für ${phase.name}-Phase - alternative Anwendung`); limitations.push(`Nicht typisch für ${phase.name}-Phase - alternative Anwendung`);
} }

View File

@ -1,4 +1,4 @@
// src/utils/auditService.ts - Fixed with meaningful confidence and reasoning // src/utils/auditService.ts
import 'dotenv/config'; import 'dotenv/config';
function env(key: string, fallback: string | undefined = undefined): string | undefined { function env(key: string, fallback: string | undefined = undefined): string | undefined {
@ -85,7 +85,6 @@ class AuditService {
): void { ): void {
if (!this.config.enabled) return; if (!this.config.enabled) return;
// Skip initialization and completion entries as they don't add transparency
if (action === 'pipeline-start' || action === 'pipeline-end') { if (action === 'pipeline-start' || action === 'pipeline-end') {
return; return;
} }
@ -152,7 +151,6 @@ class AuditService {
startTime: number, startTime: number,
metadata: Record<string, any> = {} metadata: Record<string, any> = {}
): void { ): void {
// Calculate meaningful confidence based on selection quality
const calculatedConfidence = this.calculateSelectionConfidence( const calculatedConfidence = this.calculateSelectionConfidence(
selectedTools, selectedTools,
availableTools, availableTools,
@ -164,7 +162,7 @@ class AuditService {
'tool-selection', 'tool-selection',
'selection-decision', 'selection-decision',
{ {
availableTools: availableTools.slice(0, 10), // Show first 10 for context availableTools: availableTools.slice(0, 10),
totalAvailable: availableTools.length, totalAvailable: availableTools.length,
selectionMethod: selectionMethod selectionMethod: selectionMethod
}, },
@ -191,7 +189,6 @@ class AuditService {
startTime: number, startTime: number,
metadata: Record<string, any> = {} metadata: Record<string, any> = {}
): void { ): void {
// Only add if tools were actually added
if (!addedTools || addedTools.length === 0) { if (!addedTools || addedTools.length === 0) {
console.log(`[AUDIT-SERVICE] Skipping phase completion for ${phaseId} - no tools added`); console.log(`[AUDIT-SERVICE] Skipping phase completion for ${phaseId} - no tools added`);
return; return;
@ -292,21 +289,18 @@ class AuditService {
const selectionRatio = selectedTools.length / availableTools.length; const selectionRatio = selectedTools.length / availableTools.length;
// Good selection ratio (5-20% of available tools)
if (selectionRatio >= 0.05 && selectionRatio <= 0.20) { if (selectionRatio >= 0.05 && selectionRatio <= 0.20) {
confidence += 25; confidence += 25;
} else if (selectionRatio < 0.05) { } else if (selectionRatio < 0.05) {
confidence += 15; // Very selective is good confidence += 15;
} else if (selectionRatio > 0.30) { } else if (selectionRatio > 0.30) {
confidence -= 20; // Too many tools selected confidence -= 20;
} }
// Embeddings usage bonus
if (selectionMethod.includes('embeddings')) { if (selectionMethod.includes('embeddings')) {
confidence += 15; confidence += 15;
} }
// Reasonable number of tools selected
if (selectedTools.length >= 5 && selectedTools.length <= 25) { if (selectedTools.length >= 5 && selectedTools.length <= 25) {
confidence += 10; confidence += 10;
} }
@ -321,22 +315,18 @@ class AuditService {
): number { ): number {
let confidence = 60; let confidence = 60;
// Tools actually added
if (addedTools.length > 0) { if (addedTools.length > 0) {
confidence += 20; confidence += 20;
} }
// Good reasoning provided
if (reasoning && reasoning.length > 50) { if (reasoning && reasoning.length > 50) {
confidence += 15; confidence += 15;
} }
// AI reasoning was used successfully
if (metadata.aiReasoningUsed) { if (metadata.aiReasoningUsed) {
confidence += 10; confidence += 10;
} }
// Not too many tools added (indicates thoughtful selection)
if (addedTools.length <= 2) { if (addedTools.length <= 2) {
confidence += 5; confidence += 5;
} }
@ -347,17 +337,14 @@ class AuditService {
private calculateEmbeddingsConfidence(similarResults: any[], threshold: number): number { private calculateEmbeddingsConfidence(similarResults: any[], threshold: number): number {
let confidence = 50; let confidence = 50;
// Found relevant results
if (similarResults.length > 0) { if (similarResults.length > 0) {
confidence += 20; confidence += 20;
} }
// Good number of results (not too few, not too many)
if (similarResults.length >= 5 && similarResults.length <= 30) { if (similarResults.length >= 5 && similarResults.length <= 30) {
confidence += 15; confidence += 15;
} }
// High similarity scores
const avgSimilarity = similarResults.length > 0 ? const avgSimilarity = similarResults.length > 0 ?
similarResults.reduce((sum, r) => sum + r.similarity, 0) / similarResults.length : 0; similarResults.reduce((sum, r) => sum + r.similarity, 0) / similarResults.length : 0;
@ -367,7 +354,6 @@ class AuditService {
confidence += 10; confidence += 10;
} }
// Reasonable threshold
if (threshold >= 0.3 && threshold <= 0.5) { if (threshold >= 0.3 && threshold <= 0.5) {
confidence += 5; confidence += 5;
} }
@ -378,7 +364,6 @@ class AuditService {
private createSpecificSummary(data: any, action: string, type: 'input' | 'output'): string { private createSpecificSummary(data: any, action: string, type: 'input' | 'output'): string {
if (!data) return 'Leer'; if (!data) return 'Leer';
// Action-specific summaries that show actual meaningful data
switch (action) { switch (action) {
case 'selection-decision': case 'selection-decision':
if (type === 'input') { if (type === 'input') {
@ -476,7 +461,6 @@ class AuditService {
} }
} }
// Enhanced fallback that shows actual key-value content instead of just "X Eigenschaften"
if (typeof data === 'string') { if (typeof data === 'string') {
return data.length > 100 ? data.slice(0, 100) + '...' : data; return data.length > 100 ? data.slice(0, 100) + '...' : data;
} }
@ -491,7 +475,6 @@ class AuditService {
const keys = Object.keys(data); const keys = Object.keys(data);
if (keys.length === 0) return 'Leeres Objekt'; if (keys.length === 0) return 'Leeres Objekt';
// Show actual key-value pairs for small objects instead of just counting properties
if (keys.length <= 2) { if (keys.length <= 2) {
const pairs = keys.map(key => { const pairs = keys.map(key => {
const value = data[key]; const value = data[key];
@ -505,7 +488,6 @@ class AuditService {
}); });
return pairs.join(', '); return pairs.join(', ');
} else { } else {
// For larger objects, show key names and some sample values
const sampleKeys = keys.slice(0, 3); const sampleKeys = keys.slice(0, 3);
const sampleValues = sampleKeys.map(key => { const sampleValues = sampleKeys.map(key => {
const value = data[key]; const value = data[key];
@ -531,7 +513,6 @@ class AuditService {
metadata: Record<string, any>, metadata: Record<string, any>,
confidence: number confidence: number
): string { ): string {
// Use provided reasoning if available and meaningful
if (metadata.reasoning && metadata.reasoning.length > 20 && !metadata.reasoning.includes('completed with')) { if (metadata.reasoning && metadata.reasoning.length > 20 && !metadata.reasoning.includes('completed with')) {
return metadata.reasoning; return metadata.reasoning;
} }
@ -546,11 +527,9 @@ class AuditService {
const totalMatches = const totalMatches =
typeof metadata.totalMatches === 'number' ? metadata.totalMatches : 0; typeof metadata.totalMatches === 'number' ? metadata.totalMatches : 0;
// Safely narrow & cast similarityScores to a number map
const scoresObj = (metadata.similarityScores ?? {}) as Record<string, number>; const scoresObj = (metadata.similarityScores ?? {}) as Record<string, number>;
const scores = Object.values(scoresObj) as number[]; const scores = Object.values(scoresObj) as number[];
// Use totalMatches if it looks sensible; otherwise fall back to scores.length
const denom = totalMatches > 0 ? totalMatches : scores.length; const denom = totalMatches > 0 ? totalMatches : scores.length;
const sum = scores.reduce((acc, v) => acc + (typeof v === 'number' ? v : 0), 0); const sum = scores.reduce((acc, v) => acc + (typeof v === 'number' ? v : 0), 0);
@ -697,9 +676,7 @@ class AuditService {
return Math.min(95, Math.max(25, confidence)); return Math.min(95, Math.max(25, confidence));
} }
// Additional utility methods remain the same...
getAuditStatistics(auditTrail: AuditEntry[]): any { getAuditStatistics(auditTrail: AuditEntry[]): any {
// Implementation remains the same as before
if (!auditTrail || auditTrail.length === 0) { if (!auditTrail || auditTrail.length === 0) {
return { return {
totalTime: 0, totalTime: 0,