cleanup
This commit is contained in:
parent
1c0025796a
commit
b515a45e1e
@ -702,12 +702,10 @@ class AIQueryInterface {
|
|||||||
toolsByPhase[phase] = [];
|
toolsByPhase[phase] = [];
|
||||||
});
|
});
|
||||||
|
|
||||||
// DEBUG: Log recommendation structure
|
|
||||||
console.log('[AI Results] Recommendation structure:', recommendation);
|
console.log('[AI Results] Recommendation structure:', recommendation);
|
||||||
console.log('[AI Results] Recommended tools:', recommendation.recommended_tools);
|
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);
|
console.log('[AI Results] Tool confidence data:', recTool.name, recTool.confidence);
|
||||||
|
|
||||||
if (toolsByPhase[recTool.phase]) {
|
if (toolsByPhase[recTool.phase]) {
|
||||||
@ -716,7 +714,7 @@ class AIQueryInterface {
|
|||||||
toolsByPhase[recTool.phase].push({
|
toolsByPhase[recTool.phase].push({
|
||||||
...fullTool,
|
...fullTool,
|
||||||
recommendation: recTool,
|
recommendation: recTool,
|
||||||
confidence: recTool.confidence, // Ensure confidence is passed
|
confidence: recTool.confidence,
|
||||||
justification: recTool.justification,
|
justification: recTool.justification,
|
||||||
priority: recTool.priority,
|
priority: recTool.priority,
|
||||||
recommendationStrength: recTool.recommendationStrength
|
recommendationStrength: recTool.recommendationStrength
|
||||||
@ -836,13 +834,11 @@ class AIQueryInterface {
|
|||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate summary statistics
|
|
||||||
const totalTime = auditTrail.reduce((sum, entry) => sum + entry.processingTimeMs, 0);
|
const totalTime = auditTrail.reduce((sum, entry) => sum + entry.processingTimeMs, 0);
|
||||||
const avgConfidence = auditTrail.reduce((sum, entry) => sum + entry.confidence, 0) / auditTrail.length;
|
const avgConfidence = auditTrail.reduce((sum, entry) => sum + entry.confidence, 0) / auditTrail.length;
|
||||||
const lowConfidenceSteps = auditTrail.filter(entry => entry.confidence < 60).length;
|
const lowConfidenceSteps = auditTrail.filter(entry => entry.confidence < 60).length;
|
||||||
const highConfidenceSteps = auditTrail.filter(entry => entry.confidence >= 80).length;
|
const highConfidenceSteps = auditTrail.filter(entry => entry.confidence >= 80).length;
|
||||||
|
|
||||||
// Group entries by phase for better organization
|
|
||||||
const groupedEntries = auditTrail.reduce((groups, entry) => {
|
const groupedEntries = auditTrail.reduce((groups, entry) => {
|
||||||
if (!groups[entry.phase]) groups[entry.phase] = [];
|
if (!groups[entry.phase]) groups[entry.phase] = [];
|
||||||
groups[entry.phase].push(entry);
|
groups[entry.phase].push(entry);
|
||||||
@ -1048,7 +1044,6 @@ class AIQueryInterface {
|
|||||||
second: '2-digit'
|
second: '2-digit'
|
||||||
});
|
});
|
||||||
|
|
||||||
// Reuse existing grid and text utilities
|
|
||||||
return `
|
return `
|
||||||
<div class="border-l-2 pl-3 py-2 mb-2" style="border-left-color: ${confidenceColor};">
|
<div class="border-l-2 pl-3 py-2 mb-2" style="border-left-color: ${confidenceColor};">
|
||||||
<div class="flex justify-between items-center mb-1">
|
<div class="flex justify-between items-center mb-1">
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
export const AI_PROMPTS = {
|
export const AI_PROMPTS = {
|
||||||
|
|
||||||
// Main tool selection prompt
|
|
||||||
toolSelection: (mode: string, userQuery: string, selectionMethod: string, maxSelectedItems: number) => {
|
toolSelection: (mode: string, userQuery: string, selectionMethod: string, maxSelectedItems: number) => {
|
||||||
const modeInstruction = mode === 'workflow'
|
const modeInstruction = mode === 'workflow'
|
||||||
? 'Der Benutzer möchte einen UMFASSENDEN WORKFLOW mit mehreren Tools/Methoden über verschiedene Phasen. Wählen Sie 15-25 Tools aus, die den vollständigen Untersuchungslebenszyklus abdecken.'
|
? 'Der Benutzer möchte einen UMFASSENDEN WORKFLOW mit mehreren Tools/Methoden über verschiedene Phasen. Wählen Sie 15-25 Tools aus, die den vollständigen Untersuchungslebenszyklus abdecken.'
|
||||||
@ -51,7 +50,6 @@ Antworten Sie NUR mit diesem JSON-Format:
|
|||||||
}`;
|
}`;
|
||||||
},
|
},
|
||||||
|
|
||||||
// Scenario analysis prompt
|
|
||||||
scenarioAnalysis: (isWorkflow: boolean, userQuery: string) => {
|
scenarioAnalysis: (isWorkflow: boolean, userQuery: string) => {
|
||||||
const analysisType = isWorkflow ? 'forensische Szenario' : 'technische Problem';
|
const analysisType = isWorkflow ? 'forensische Szenario' : 'technische Problem';
|
||||||
const considerations = isWorkflow ?
|
const considerations = isWorkflow ?
|
||||||
@ -74,7 +72,6 @@ ${considerations}
|
|||||||
WICHTIG: Antworten Sie NUR in fließendem deutschen Text ohne Listen, Aufzählungen oder Markdown-Formatierung. Maximum 150 Wörter.`;
|
WICHTIG: Antworten Sie NUR in fließendem deutschen Text ohne Listen, Aufzählungen oder Markdown-Formatierung. Maximum 150 Wörter.`;
|
||||||
},
|
},
|
||||||
|
|
||||||
// Investigation approach prompt
|
|
||||||
investigationApproach: (isWorkflow: boolean, userQuery: string) => {
|
investigationApproach: (isWorkflow: boolean, userQuery: string) => {
|
||||||
const approachType = isWorkflow ? 'Untersuchungsansatz' : 'Lösungsansatz';
|
const approachType = isWorkflow ? 'Untersuchungsansatz' : 'Lösungsansatz';
|
||||||
const considerations = isWorkflow ?
|
const considerations = isWorkflow ?
|
||||||
@ -96,7 +93,6 @@ ${considerations}
|
|||||||
WICHTIG: Antworten Sie NUR in fließendem deutschen Text ohne Listen oder Markdown. Maximum 150 Wörter.`;
|
WICHTIG: Antworten Sie NUR in fließendem deutschen Text ohne Listen oder Markdown. Maximum 150 Wörter.`;
|
||||||
},
|
},
|
||||||
|
|
||||||
// Critical considerations prompt
|
|
||||||
criticalConsiderations: (isWorkflow: boolean, userQuery: string) => {
|
criticalConsiderations: (isWorkflow: boolean, userQuery: string) => {
|
||||||
const considerationType = isWorkflow ? 'kritische forensische Überlegungen' : 'wichtige methodische Voraussetzungen';
|
const considerationType = isWorkflow ? 'kritische forensische Überlegungen' : 'wichtige methodische Voraussetzungen';
|
||||||
const aspects = isWorkflow ?
|
const aspects = isWorkflow ?
|
||||||
@ -179,7 +175,6 @@ WICHTIG:
|
|||||||
- "pros" soll die Stärken für diese spezifische Aufgabe hervorheben`;
|
- "pros" soll die Stärken für diese spezifische Aufgabe hervorheben`;
|
||||||
},
|
},
|
||||||
|
|
||||||
// Background knowledge selection prompt
|
|
||||||
backgroundKnowledgeSelection: (userQuery: string, mode: string, selectedToolNames: string[], availableConcepts: any[]) => {
|
backgroundKnowledgeSelection: (userQuery: string, mode: string, selectedToolNames: string[], availableConcepts: any[]) => {
|
||||||
return `Wählen Sie relevante forensische Konzepte für das Verständnis der empfohlenen Methodik.
|
return `Wählen Sie relevante forensische Konzepte für das Verständnis der empfohlenen Methodik.
|
||||||
|
|
||||||
@ -200,7 +195,6 @@ Antworten Sie AUSSCHLIESSLICH mit diesem JSON-Format:
|
|||||||
]`;
|
]`;
|
||||||
},
|
},
|
||||||
|
|
||||||
// Final recommendations prompt
|
|
||||||
finalRecommendations: (isWorkflow: boolean, userQuery: string, selectedToolNames: string[]) => {
|
finalRecommendations: (isWorkflow: boolean, userQuery: string, selectedToolNames: string[]) => {
|
||||||
const prompt = isWorkflow ?
|
const prompt = isWorkflow ?
|
||||||
`Erstellen Sie eine Workflow-Empfehlung basierend auf DFIR-Prinzipien.
|
`Erstellen Sie eine Workflow-Empfehlung basierend auf DFIR-Prinzipien.
|
||||||
@ -225,7 +219,6 @@ WICHTIG: Antworten Sie NUR in fließendem deutschen Text ohne Listen oder Markdo
|
|||||||
}
|
}
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
// Type-safe prompt function with proper overloads
|
|
||||||
export function getPrompt(key: 'toolSelection', mode: string, userQuery: string, selectionMethod: string, maxSelectedItems: number): string;
|
export function getPrompt(key: 'toolSelection', mode: string, userQuery: string, selectionMethod: string, maxSelectedItems: number): string;
|
||||||
export function getPrompt(key: 'scenarioAnalysis', isWorkflow: boolean, userQuery: string): string;
|
export function getPrompt(key: 'scenarioAnalysis', isWorkflow: boolean, userQuery: string): string;
|
||||||
export function getPrompt(key: 'investigationApproach', isWorkflow: boolean, userQuery: string): string;
|
export function getPrompt(key: 'investigationApproach', isWorkflow: boolean, userQuery: string): string;
|
||||||
@ -238,7 +231,6 @@ export function getPrompt(promptKey: keyof typeof AI_PROMPTS, ...args: any[]): s
|
|||||||
try {
|
try {
|
||||||
const promptFunction = AI_PROMPTS[promptKey];
|
const promptFunction = AI_PROMPTS[promptKey];
|
||||||
if (typeof promptFunction === 'function') {
|
if (typeof promptFunction === 'function') {
|
||||||
// Use type assertion since we've validated the function exists
|
|
||||||
return (promptFunction as (...args: any[]) => string)(...args);
|
return (promptFunction as (...args: any[]) => string)(...args);
|
||||||
} else {
|
} else {
|
||||||
console.error(`[PROMPTS] Invalid prompt key: ${promptKey}`);
|
console.error(`[PROMPTS] Invalid prompt key: ${promptKey}`);
|
||||||
|
@ -265,20 +265,15 @@ const phases = data.phases;
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// AI Button click handler
|
|
||||||
if (aiQueryBtn) {
|
if (aiQueryBtn) {
|
||||||
aiQueryBtn.addEventListener('click', () => {
|
aiQueryBtn.addEventListener('click', () => {
|
||||||
// Visual feedback
|
|
||||||
aiQueryBtn.classList.add('activated');
|
aiQueryBtn.classList.add('activated');
|
||||||
setTimeout(() => aiQueryBtn.classList.remove('activated'), 400);
|
setTimeout(() => aiQueryBtn.classList.remove('activated'), 400);
|
||||||
|
|
||||||
// Switch to AI view
|
|
||||||
switchToView('ai');
|
switchToView('ai');
|
||||||
|
|
||||||
// Trigger existing view change system
|
|
||||||
window.dispatchEvent(new CustomEvent('viewChanged', { detail: 'ai' }));
|
window.dispatchEvent(new CustomEvent('viewChanged', { detail: 'ai' }));
|
||||||
|
|
||||||
// Scroll to AI interface
|
|
||||||
if (window.scrollToElementById) {
|
if (window.scrollToElementById) {
|
||||||
window.scrollToElementById('ai-interface');
|
window.scrollToElementById('ai-interface');
|
||||||
} else {
|
} else {
|
||||||
@ -294,14 +289,12 @@ const phases = data.phases;
|
|||||||
const filtersSection = document.getElementById('filters-section');
|
const filtersSection = document.getElementById('filters-section');
|
||||||
const noResults = document.getElementById('no-results');
|
const noResults = document.getElementById('no-results');
|
||||||
|
|
||||||
// Hide all views first
|
|
||||||
if (toolsGrid) toolsGrid.style.display = 'none';
|
if (toolsGrid) toolsGrid.style.display = 'none';
|
||||||
if (matrixContainer) matrixContainer.style.display = 'none';
|
if (matrixContainer) matrixContainer.style.display = 'none';
|
||||||
if (aiInterface) aiInterface.style.display = 'none';
|
if (aiInterface) aiInterface.style.display = 'none';
|
||||||
if (filtersSection) filtersSection.style.display = 'none';
|
if (filtersSection) filtersSection.style.display = 'none';
|
||||||
if (noResults) noResults.style.display = 'none';
|
if (noResults) noResults.style.display = 'none';
|
||||||
|
|
||||||
// Show selected view
|
|
||||||
switch (view) {
|
switch (view) {
|
||||||
case 'grid':
|
case 'grid':
|
||||||
if (toolsGrid) toolsGrid.style.display = 'block';
|
if (toolsGrid) toolsGrid.style.display = 'block';
|
||||||
|
@ -63,17 +63,15 @@ interface AnalysisContext {
|
|||||||
|
|
||||||
auditTrail: AuditEntry[];
|
auditTrail: AuditEntry[];
|
||||||
|
|
||||||
// Store actual similarity data from embeddings
|
|
||||||
embeddingsSimilarities: Map<string, number>;
|
embeddingsSimilarities: Map<string, number>;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ConfidenceMetrics {
|
interface ConfidenceMetrics {
|
||||||
overall: number; // 0-100: Combined confidence score
|
overall: number;
|
||||||
semanticRelevance: number; // How well tool description matches query (from embeddings)
|
semanticRelevance: number;
|
||||||
taskSuitability: number; // AI-determined fitness for this specific task
|
taskSuitability: number;
|
||||||
methodologicalConsistency: number; // How well different analysis steps agree
|
uncertaintyFactors: string[];
|
||||||
uncertaintyFactors: string[]; // Specific reasons why this might not work
|
strengthIndicators: string[];
|
||||||
strengthIndicators: string[]; // Specific reasons why this is a good choice
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class ImprovedMicroTaskAIPipeline {
|
class ImprovedMicroTaskAIPipeline {
|
||||||
@ -102,10 +100,10 @@ class ImprovedMicroTaskAIPipeline {
|
|||||||
};
|
};
|
||||||
|
|
||||||
private confidenceConfig: {
|
private confidenceConfig: {
|
||||||
semanticWeight: number; // Weight for embeddings similarity
|
semanticWeight: number;
|
||||||
suitabilityWeight: number; // Weight for AI task fit evaluation
|
suitabilityWeight: number;
|
||||||
consistencyWeight: number; // Weight for cross-validation agreement
|
consistencyWeight: number;
|
||||||
reliabilityWeight: number; // Weight for tool quality indicators
|
reliabilityWeight: number;
|
||||||
minimumThreshold: number;
|
minimumThreshold: number;
|
||||||
mediumThreshold: number;
|
mediumThreshold: number;
|
||||||
highThreshold: number;
|
highThreshold: number;
|
||||||
@ -143,10 +141,9 @@ class ImprovedMicroTaskAIPipeline {
|
|||||||
retentionHours: parseInt(process.env.FORENSIC_AUDIT_RETENTION_HOURS || '72', 10)
|
retentionHours: parseInt(process.env.FORENSIC_AUDIT_RETENTION_HOURS || '72', 10)
|
||||||
};
|
};
|
||||||
|
|
||||||
// Updated confidence weights - more focused on AI evaluation
|
|
||||||
this.confidenceConfig = {
|
this.confidenceConfig = {
|
||||||
semanticWeight: parseFloat(process.env.CONFIDENCE_SEMANTIC_WEIGHT || '0.3'), // Embeddings similarity
|
semanticWeight: parseFloat(process.env.CONFIDENCE_SEMANTIC_WEIGHT || '0.3'),
|
||||||
suitabilityWeight: parseFloat(process.env.CONFIDENCE_SUITABILITY_WEIGHT || '0.7'), // AI task fit evaluation
|
suitabilityWeight: parseFloat(process.env.CONFIDENCE_SUITABILITY_WEIGHT || '0.7'),
|
||||||
consistencyWeight: 0,
|
consistencyWeight: 0,
|
||||||
reliabilityWeight: 0,
|
reliabilityWeight: 0,
|
||||||
minimumThreshold: parseInt(process.env.CONFIDENCE_MINIMUM_THRESHOLD || '40', 10),
|
minimumThreshold: parseInt(process.env.CONFIDENCE_MINIMUM_THRESHOLD || '40', 10),
|
||||||
@ -235,7 +232,7 @@ class ImprovedMicroTaskAIPipeline {
|
|||||||
const selectionRatio = result.selectedTools.length / candidateCount;
|
const selectionRatio = result.selectedTools.length / candidateCount;
|
||||||
const hasReasoning = result.reasoning && result.reasoning.length > 50;
|
const hasReasoning = result.reasoning && result.reasoning.length > 50;
|
||||||
|
|
||||||
let confidence = 60; // Base confidence
|
let confidence = 60;
|
||||||
|
|
||||||
if (selectionRatio > 0.05 && selectionRatio < 0.3) confidence += 20;
|
if (selectionRatio > 0.05 && selectionRatio < 0.3) confidence += 20;
|
||||||
else if (selectionRatio <= 0.05) confidence -= 10;
|
else if (selectionRatio <= 0.05) confidence -= 10;
|
||||||
@ -386,7 +383,6 @@ class ImprovedMicroTaskAIPipeline {
|
|||||||
let candidateConcepts: any[] = [];
|
let candidateConcepts: any[] = [];
|
||||||
let selectionMethod = 'unknown';
|
let selectionMethod = 'unknown';
|
||||||
|
|
||||||
// Initialize embeddings similarities storage
|
|
||||||
context.embeddingsSimilarities = new Map<string, number>();
|
context.embeddingsSimilarities = new Map<string, number>();
|
||||||
|
|
||||||
if (process.env.AI_EMBEDDINGS_ENABLED === 'true') {
|
if (process.env.AI_EMBEDDINGS_ENABLED === 'true') {
|
||||||
@ -409,7 +405,6 @@ class ImprovedMicroTaskAIPipeline {
|
|||||||
|
|
||||||
console.log(`[AI PIPELINE] Embeddings found ${similarItems.length} similar items`);
|
console.log(`[AI PIPELINE] Embeddings found ${similarItems.length} similar items`);
|
||||||
|
|
||||||
// Store actual similarity scores for confidence calculation
|
|
||||||
similarItems.forEach(item => {
|
similarItems.forEach(item => {
|
||||||
context.embeddingsSimilarities.set(item.name, item.similarity);
|
context.embeddingsSimilarities.set(item.name, item.similarity);
|
||||||
});
|
});
|
||||||
@ -707,18 +702,14 @@ ${JSON.stringify(conceptsToSend, null, 2)}`;
|
|||||||
limitations: string[] = []
|
limitations: string[] = []
|
||||||
): ConfidenceMetrics {
|
): ConfidenceMetrics {
|
||||||
|
|
||||||
// 1. Semantic Relevance: Real embeddings similarity score
|
|
||||||
const rawSemanticRelevance = context.embeddingsSimilarities.has(tool.name) ?
|
const rawSemanticRelevance = context.embeddingsSimilarities.has(tool.name) ?
|
||||||
context.embeddingsSimilarities.get(tool.name)! * 100 : 50;
|
context.embeddingsSimilarities.get(tool.name)! * 100 : 50;
|
||||||
|
|
||||||
// 2. Task Suitability: Enhanced with phase-awareness for workflow mode
|
|
||||||
let enhancedTaskSuitability = taskRelevance;
|
let enhancedTaskSuitability = taskRelevance;
|
||||||
|
|
||||||
if (context.mode === 'workflow') {
|
if (context.mode === 'workflow') {
|
||||||
// In workflow mode, boost score if tool is well-matched to its assigned phase
|
|
||||||
const toolSelection = context.selectedTools?.find(st => st.tool.name === tool.name);
|
const toolSelection = context.selectedTools?.find(st => st.tool.name === tool.name);
|
||||||
if (toolSelection && tool.phases && tool.phases.includes(toolSelection.phase)) {
|
if (toolSelection && tool.phases && tool.phases.includes(toolSelection.phase)) {
|
||||||
// Boost for phase alignment (but cap at 100)
|
|
||||||
const phaseBonus = Math.min(15, 100 - taskRelevance);
|
const phaseBonus = Math.min(15, 100 - taskRelevance);
|
||||||
enhancedTaskSuitability = Math.min(100, taskRelevance + phaseBonus);
|
enhancedTaskSuitability = Math.min(100, taskRelevance + phaseBonus);
|
||||||
|
|
||||||
@ -726,7 +717,6 @@ ${JSON.stringify(conceptsToSend, null, 2)}`;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Simple weighted combination - no artificial scaling
|
|
||||||
const overall = (
|
const overall = (
|
||||||
rawSemanticRelevance * this.confidenceConfig.semanticWeight +
|
rawSemanticRelevance * this.confidenceConfig.semanticWeight +
|
||||||
enhancedTaskSuitability * this.confidenceConfig.suitabilityWeight
|
enhancedTaskSuitability * this.confidenceConfig.suitabilityWeight
|
||||||
@ -747,7 +737,6 @@ ${JSON.stringify(conceptsToSend, null, 2)}`;
|
|||||||
overall: Math.round(overall),
|
overall: Math.round(overall),
|
||||||
semanticRelevance: Math.round(rawSemanticRelevance),
|
semanticRelevance: Math.round(rawSemanticRelevance),
|
||||||
taskSuitability: Math.round(enhancedTaskSuitability),
|
taskSuitability: Math.round(enhancedTaskSuitability),
|
||||||
methodologicalConsistency: 0,
|
|
||||||
uncertaintyFactors,
|
uncertaintyFactors,
|
||||||
strengthIndicators
|
strengthIndicators
|
||||||
};
|
};
|
||||||
@ -756,18 +745,15 @@ ${JSON.stringify(conceptsToSend, null, 2)}`;
|
|||||||
private identifySpecificUncertaintyFactors(tool: any, context: AnalysisContext, limitations: string[], confidence: number): string[] {
|
private identifySpecificUncertaintyFactors(tool: any, context: AnalysisContext, limitations: string[], confidence: number): string[] {
|
||||||
const factors: string[] = [];
|
const factors: string[] = [];
|
||||||
|
|
||||||
// Add AI-identified limitations first (most specific)
|
|
||||||
if (limitations && limitations.length > 0) {
|
if (limitations && limitations.length > 0) {
|
||||||
factors.push(...limitations.slice(0, 2)); // Limit to top 2 to leave room for others
|
factors.push(...limitations.slice(0, 2));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Low semantic similarity
|
|
||||||
const similarity = context.embeddingsSimilarities.get(tool.name) || 0.5;
|
const similarity = context.embeddingsSimilarities.get(tool.name) || 0.5;
|
||||||
if (similarity < 0.7) {
|
if (similarity < 0.7) {
|
||||||
factors.push('Geringe semantische Ähnlichkeit zur Anfrage - Tool-Beschreibung passt möglicherweise nicht optimal');
|
factors.push('Geringe semantische Ähnlichkeit zur Anfrage - Tool-Beschreibung passt möglicherweise nicht optimal');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Skill level vs scenario complexity mismatch
|
|
||||||
if (tool.skillLevel === 'expert' && /schnell|rapid|triage|urgent|sofort/i.test(context.userQuery)) {
|
if (tool.skillLevel === 'expert' && /schnell|rapid|triage|urgent|sofort/i.test(context.userQuery)) {
|
||||||
factors.push('Experten-Tool für zeitkritisches Szenario - Setup und Einarbeitung könnten zu lange dauern');
|
factors.push('Experten-Tool für zeitkritisches Szenario - Setup und Einarbeitung könnten zu lange dauern');
|
||||||
}
|
}
|
||||||
@ -776,35 +762,29 @@ ${JSON.stringify(conceptsToSend, null, 2)}`;
|
|||||||
factors.push('Einsteiger-Tool für komplexe Analyse - könnte funktionale Limitierungen haben');
|
factors.push('Einsteiger-Tool für komplexe Analyse - könnte funktionale Limitierungen haben');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Access and deployment concerns
|
|
||||||
if (tool.type === 'software' && !isToolHosted(tool) && tool.accessType === 'download') {
|
if (tool.type === 'software' && !isToolHosted(tool) && tool.accessType === 'download') {
|
||||||
factors.push('Installation und Setup erforderlich');
|
factors.push('Installation und Setup erforderlich');
|
||||||
}
|
}
|
||||||
|
|
||||||
// License restrictions
|
|
||||||
if (tool.license === 'Proprietary') {
|
if (tool.license === 'Proprietary') {
|
||||||
factors.push('Kommerzielle Software - Lizenzkosten und rechtliche Beschränkungen zu beachten');
|
factors.push('Kommerzielle Software - Lizenzkosten und rechtliche Beschränkungen zu beachten');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Low overall confidence warning
|
|
||||||
if (confidence < 60) {
|
if (confidence < 60) {
|
||||||
factors.push('Moderate Gesamtbewertung - alternative Ansätze sollten ebenfalls betrachtet werden');
|
factors.push('Moderate Gesamtbewertung - alternative Ansätze sollten ebenfalls betrachtet werden');
|
||||||
}
|
}
|
||||||
|
|
||||||
return factors.slice(0, 4); // Limit to 4 most relevant factors
|
return factors.slice(0, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
// NEW: Identify specific strength indicators
|
|
||||||
private identifySpecificStrengthIndicators(tool: any, context: AnalysisContext, confidence: number): string[] {
|
private identifySpecificStrengthIndicators(tool: any, context: AnalysisContext, confidence: number): string[] {
|
||||||
const indicators: string[] = [];
|
const indicators: string[] = [];
|
||||||
|
|
||||||
// High semantic similarity
|
|
||||||
const similarity = context.embeddingsSimilarities.get(tool.name) || 0.5;
|
const similarity = context.embeddingsSimilarities.get(tool.name) || 0.5;
|
||||||
if (similarity >= 0.7) {
|
if (similarity >= 0.7) {
|
||||||
indicators.push('Sehr gute semantische Übereinstimmung mit Ihrer Anfrage');
|
indicators.push('Sehr gute semantische Übereinstimmung mit Ihrer Anfrage');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Quality indicators
|
|
||||||
if (tool.knowledgebase === true) {
|
if (tool.knowledgebase === true) {
|
||||||
indicators.push('Umfassende Dokumentation und Wissensbasis verfügbar');
|
indicators.push('Umfassende Dokumentation und Wissensbasis verfügbar');
|
||||||
}
|
}
|
||||||
@ -813,17 +793,15 @@ ${JSON.stringify(conceptsToSend, null, 2)}`;
|
|||||||
indicators.push('Sofort verfügbar über gehostete Lösung - kein Setup erforderlich');
|
indicators.push('Sofort verfügbar über gehostete Lösung - kein Setup erforderlich');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Skill level match
|
|
||||||
if (tool.skillLevel === 'intermediate' || tool.skillLevel === 'advanced') {
|
if (tool.skillLevel === 'intermediate' || tool.skillLevel === 'advanced') {
|
||||||
indicators.push('Ausgewogenes Verhältnis zwischen Funktionalität und Benutzerfreundlichkeit');
|
indicators.push('Ausgewogenes Verhältnis zwischen Funktionalität und Benutzerfreundlichkeit');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Method alignment
|
|
||||||
if (tool.type === 'method' && /methodik|vorgehen|prozess|ansatz/i.test(context.userQuery)) {
|
if (tool.type === 'method' && /methodik|vorgehen|prozess|ansatz/i.test(context.userQuery)) {
|
||||||
indicators.push('Methodischer Ansatz passt zu Ihrer prozeduralen Anfrage');
|
indicators.push('Methodischer Ansatz passt zu Ihrer prozeduralen Anfrage');
|
||||||
}
|
}
|
||||||
|
|
||||||
return indicators.slice(0, 4); // Limit to 4 most important indicators
|
return indicators.slice(0, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async analyzeScenario(context: AnalysisContext): Promise<MicroTaskResult> {
|
private async analyzeScenario(context: AnalysisContext): Promise<MicroTaskResult> {
|
||||||
@ -902,11 +880,9 @@ ${JSON.stringify(conceptsToSend, null, 2)}`;
|
|||||||
validSelections.forEach((sel: any) => {
|
validSelections.forEach((sel: any) => {
|
||||||
const tool = phaseTools.find((t: any) => t.name === sel.toolName);
|
const tool = phaseTools.find((t: any) => t.name === sel.toolName);
|
||||||
if (tool) {
|
if (tool) {
|
||||||
// Ensure taskRelevance is a number
|
|
||||||
const taskRelevance = typeof sel.taskRelevance === 'number' ?
|
const taskRelevance = typeof sel.taskRelevance === 'number' ?
|
||||||
sel.taskRelevance : parseInt(String(sel.taskRelevance)) || 70;
|
sel.taskRelevance : parseInt(String(sel.taskRelevance)) || 70;
|
||||||
|
|
||||||
// Derive priority automatically from score
|
|
||||||
const priority = this.derivePriorityFromScore(taskRelevance);
|
const priority = this.derivePriorityFromScore(taskRelevance);
|
||||||
|
|
||||||
this.addToolToSelection(context, tool, phase.id, priority, sel.justification, taskRelevance, sel.limitations);
|
this.addToolToSelection(context, tool, phase.id, priority, sel.justification, taskRelevance, sel.limitations);
|
||||||
@ -967,7 +943,7 @@ ${JSON.stringify(conceptsToSend, null, 2)}`;
|
|||||||
hasExplanation: !!evaluation.detailed_explanation,
|
hasExplanation: !!evaluation.detailed_explanation,
|
||||||
hasImplementationApproach: !!evaluation.implementation_approach,
|
hasImplementationApproach: !!evaluation.implementation_approach,
|
||||||
prosCount: evaluation.pros?.length || 0,
|
prosCount: evaluation.pros?.length || 0,
|
||||||
limitationsCount: evaluation.limitations?.length || 0, // ← Updated field name
|
limitationsCount: evaluation.limitations?.length || 0,
|
||||||
hasLimitations: Array.isArray(evaluation.limitations) && evaluation.limitations.length > 0
|
hasLimitations: Array.isArray(evaluation.limitations) && evaluation.limitations.length > 0
|
||||||
},
|
},
|
||||||
70,
|
70,
|
||||||
@ -1101,7 +1077,7 @@ ${JSON.stringify(conceptsToSend, null, 2)}`;
|
|||||||
const context: AnalysisContext = {
|
const context: AnalysisContext = {
|
||||||
userQuery,
|
userQuery,
|
||||||
mode,
|
mode,
|
||||||
filteredData: {}, // Will be populated by getIntelligentCandidates
|
filteredData: {},
|
||||||
contextHistory: [],
|
contextHistory: [],
|
||||||
maxContextLength: this.maxContextTokens,
|
maxContextLength: this.maxContextTokens,
|
||||||
currentContextLength: 0,
|
currentContextLength: 0,
|
||||||
@ -1124,9 +1100,7 @@ ${JSON.stringify(conceptsToSend, null, 2)}`;
|
|||||||
startTime,
|
startTime,
|
||||||
{ auditEnabled: this.auditConfig.enabled, confidenceScoringEnabled: true }
|
{ auditEnabled: this.auditConfig.enabled, confidenceScoringEnabled: true }
|
||||||
);
|
);
|
||||||
|
|
||||||
// MICRO-TASK SEQUENCE WITH ENHANCED CONFIDENCE TRACKING
|
|
||||||
|
|
||||||
const analysisResult = await this.analyzeScenario(context);
|
const analysisResult = await this.analyzeScenario(context);
|
||||||
if (analysisResult.success) completeTasks++; else failedTasks++;
|
if (analysisResult.success) completeTasks++; else failedTasks++;
|
||||||
await this.delay(this.microTaskDelay);
|
await this.delay(this.microTaskDelay);
|
||||||
@ -1234,7 +1208,6 @@ ${JSON.stringify(conceptsToSend, null, 2)}`;
|
|||||||
components: {
|
components: {
|
||||||
semantic: confidence.semanticRelevance,
|
semantic: confidence.semanticRelevance,
|
||||||
suitability: confidence.taskSuitability,
|
suitability: confidence.taskSuitability,
|
||||||
consistency: confidence.methodologicalConsistency
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
confidence.overall,
|
confidence.overall,
|
||||||
@ -1286,7 +1259,7 @@ ${JSON.stringify(conceptsToSend, null, 2)}`;
|
|||||||
detailed_explanation: st.tool.evaluation?.detailed_explanation || '',
|
detailed_explanation: st.tool.evaluation?.detailed_explanation || '',
|
||||||
implementation_approach: st.tool.evaluation?.implementation_approach || '',
|
implementation_approach: st.tool.evaluation?.implementation_approach || '',
|
||||||
pros: st.tool.evaluation?.pros || [],
|
pros: st.tool.evaluation?.pros || [],
|
||||||
cons: st.tool.evaluation?.limitations || [], // ← FIXED: Use limitations as cons for display
|
cons: st.tool.evaluation?.limitations || [],
|
||||||
alternatives: st.tool.evaluation?.alternatives || '',
|
alternatives: st.tool.evaluation?.alternatives || '',
|
||||||
confidence: confidence,
|
confidence: confidence,
|
||||||
recommendationStrength: confidence.overall >= this.confidenceConfig.highThreshold ? 'strong' :
|
recommendationStrength: confidence.overall >= this.confidenceConfig.highThreshold ? 'strong' :
|
||||||
|
@ -31,7 +31,7 @@ interface SimilarityResult extends EmbeddingData {
|
|||||||
class EmbeddingsService {
|
class EmbeddingsService {
|
||||||
private embeddings: EmbeddingData[] = [];
|
private embeddings: EmbeddingData[] = [];
|
||||||
private isInitialized = false;
|
private isInitialized = false;
|
||||||
private initializationPromise: Promise<void> | null = null; // ADD THIS LINE
|
private initializationPromise: Promise<void> | null = null;
|
||||||
private readonly embeddingsPath = path.join(process.cwd(), 'data', 'embeddings.json');
|
private readonly embeddingsPath = path.join(process.cwd(), 'data', 'embeddings.json');
|
||||||
private readonly batchSize: number;
|
private readonly batchSize: number;
|
||||||
private readonly batchDelay: number;
|
private readonly batchDelay: number;
|
||||||
@ -43,24 +43,19 @@ class EmbeddingsService {
|
|||||||
this.batchDelay = parseInt(process.env.AI_EMBEDDINGS_BATCH_DELAY_MS || '1000', 10);
|
this.batchDelay = parseInt(process.env.AI_EMBEDDINGS_BATCH_DELAY_MS || '1000', 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
// REPLACE the existing initialize method with this:
|
|
||||||
async initialize(): Promise<void> {
|
async initialize(): Promise<void> {
|
||||||
// If initialization is already in progress, wait for it
|
|
||||||
if (this.initializationPromise) {
|
if (this.initializationPromise) {
|
||||||
return this.initializationPromise;
|
return this.initializationPromise;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If already initialized, return immediately
|
|
||||||
if (this.isInitialized) {
|
if (this.isInitialized) {
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start initialization and store the promise
|
|
||||||
this.initializationPromise = this.performInitialization();
|
this.initializationPromise = this.performInitialization();
|
||||||
return this.initializationPromise;
|
return this.initializationPromise;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ADD THIS NEW METHOD:
|
|
||||||
private async performInitialization(): Promise<void> {
|
private async performInitialization(): Promise<void> {
|
||||||
if (!this.enabled) {
|
if (!this.enabled) {
|
||||||
console.log('[EMBEDDINGS] Embeddings disabled, skipping initialization');
|
console.log('[EMBEDDINGS] Embeddings disabled, skipping initialization');
|
||||||
@ -70,13 +65,11 @@ class EmbeddingsService {
|
|||||||
try {
|
try {
|
||||||
console.log('[EMBEDDINGS] Initializing embeddings system...');
|
console.log('[EMBEDDINGS] Initializing embeddings system...');
|
||||||
|
|
||||||
// Create data directory if it doesn't exist
|
|
||||||
await fs.mkdir(path.dirname(this.embeddingsPath), { recursive: true });
|
await fs.mkdir(path.dirname(this.embeddingsPath), { recursive: true });
|
||||||
|
|
||||||
const toolsData = await getCompressedToolsDataForAI();
|
const toolsData = await getCompressedToolsDataForAI();
|
||||||
const currentDataHash = this.hashData(toolsData);
|
const currentDataHash = this.hashData(toolsData);
|
||||||
|
|
||||||
// Try to load existing embeddings
|
|
||||||
const existingEmbeddings = await this.loadEmbeddings();
|
const existingEmbeddings = await this.loadEmbeddings();
|
||||||
|
|
||||||
if (existingEmbeddings && existingEmbeddings.version === currentDataHash) {
|
if (existingEmbeddings && existingEmbeddings.version === currentDataHash) {
|
||||||
@ -336,12 +329,10 @@ class EmbeddingsService {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Global instance
|
|
||||||
const embeddingsService = new EmbeddingsService();
|
const embeddingsService = new EmbeddingsService();
|
||||||
|
|
||||||
export { embeddingsService, type EmbeddingData, type SimilarityResult };
|
export { embeddingsService, type EmbeddingData, type SimilarityResult };
|
||||||
|
|
||||||
// Auto-initialize on import in server environment
|
|
||||||
if (typeof window === 'undefined' && process.env.NODE_ENV !== 'test') {
|
if (typeof window === 'undefined' && process.env.NODE_ENV !== 'test') {
|
||||||
embeddingsService.initialize().catch(error => {
|
embeddingsService.initialize().catch(error => {
|
||||||
console.error('[EMBEDDINGS] Auto-initialization failed:', error);
|
console.error('[EMBEDDINGS] Auto-initialization failed:', error);
|
||||||
|
@ -96,7 +96,6 @@ class RateLimitedQueue {
|
|||||||
|
|
||||||
this.tasks.push(queuedTask);
|
this.tasks.push(queuedTask);
|
||||||
|
|
||||||
// Kick the processor soon.
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this.processQueue();
|
this.processQueue();
|
||||||
}, 100);
|
}, 100);
|
||||||
@ -170,7 +169,7 @@ class RateLimitedQueue {
|
|||||||
.filter((t) => t.status === "queued")
|
.filter((t) => t.status === "queued")
|
||||||
.sort((a, b) => a.addedAt - b.addedAt)[0];
|
.sort((a, b) => a.addedAt - b.addedAt)[0];
|
||||||
|
|
||||||
if (!nextTask) break; // No more work
|
if (!nextTask) break;
|
||||||
|
|
||||||
nextTask.status = "processing";
|
nextTask.status = "processing";
|
||||||
nextTask.startedAt = Date.now();
|
nextTask.startedAt = Date.now();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user