myavana-bot-test-core 2.0.2 → 2.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.js +131 -43
- package/package.json +1 -1
- package/src/fallbacks/conversationAnalyticsFallback.js +105 -0
- package/src/fallbacks/errorRecoveryFallback.js +154 -0
- package/src/fallbacks/personalizationEngineFallback.js +149 -0
- package/src/fallbacks/responseCacheFallback.js +48 -0
- package/src/fallbacks/smartPromptManagerFallback.js +146 -0
- package/src/fallbacks/unifiedChatHandlerFallback.js +169 -0
- package/src/monitor-production.js +185 -0
- package/src/smartPromptManager.js +117 -37
- package/src/test-fixes.js +177 -0
- package/src/unifiedChatHandler.js +369 -462
package/index.js
CHANGED
|
@@ -1,54 +1,142 @@
|
|
|
1
|
-
//
|
|
2
|
-
|
|
1
|
+
// packages/core/index.js - Fixed exports with proper module loading
|
|
2
|
+
const path = require('path');
|
|
3
|
+
|
|
4
|
+
// Helper function to safely load modules
|
|
5
|
+
function safeRequire(modulePath, moduleName) {
|
|
6
|
+
try {
|
|
7
|
+
const module = require(modulePath);
|
|
8
|
+
console.log(`✅ Successfully loaded ${moduleName}`);
|
|
9
|
+
return module;
|
|
10
|
+
} catch (error) {
|
|
11
|
+
console.error(`❌ Failed to load ${moduleName}:`, error.message);
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// Load all modules with error handling
|
|
17
|
+
const modules = {
|
|
3
18
|
// Database and utilities (Enhanced)
|
|
4
|
-
connectDatabases:
|
|
5
|
-
pgClient:
|
|
6
|
-
redisClient:
|
|
19
|
+
connectDatabases: safeRequire('./src/database', 'database').connectDatabases,
|
|
20
|
+
pgClient: safeRequire('./src/database', 'database').pgClient,
|
|
21
|
+
redisClient: safeRequire('./src/database', 'database').redisClient,
|
|
7
22
|
|
|
8
23
|
// Enhanced database management
|
|
9
|
-
DatabaseManager:
|
|
10
|
-
createDatabaseManager:
|
|
11
|
-
getDatabaseManager:
|
|
24
|
+
DatabaseManager: safeRequire('./src/enhancedDatabase', 'DatabaseManager')?.DatabaseManager,
|
|
25
|
+
createDatabaseManager: safeRequire('./src/enhancedDatabase', 'DatabaseManager')?.createDatabaseManager,
|
|
26
|
+
getDatabaseManager: safeRequire('./src/enhancedDatabase', 'DatabaseManager')?.getDatabaseManager,
|
|
12
27
|
|
|
13
28
|
// AI and session management
|
|
14
|
-
ai:
|
|
15
|
-
DatabaseSessionStore:
|
|
29
|
+
ai: safeRequire('./src/ai', 'ai'),
|
|
30
|
+
DatabaseSessionStore: safeRequire('./src/session', 'DatabaseSessionStore'),
|
|
16
31
|
|
|
17
32
|
// User and conversation management
|
|
18
|
-
getUserDetails:
|
|
19
|
-
getAllConversationsSummary:
|
|
20
|
-
getConversationHistory:
|
|
21
|
-
saveConversation:
|
|
22
|
-
generateConversationSummary:
|
|
33
|
+
getUserDetails: safeRequire('./src/user', 'user')?.getUserDetails,
|
|
34
|
+
getAllConversationsSummary: safeRequire('./src/conversation', 'conversation')?.getAllConversationsSummary,
|
|
35
|
+
getConversationHistory: safeRequire('./src/conversation', 'conversation')?.getConversationHistory,
|
|
36
|
+
saveConversation: safeRequire('./src/conversation', 'conversation')?.saveConversation,
|
|
37
|
+
generateConversationSummary: safeRequire('./src/conversation', 'conversation')?.generateConversationSummary,
|
|
23
38
|
|
|
24
39
|
// Post-processing and hair issues
|
|
25
|
-
postProcessConversation:
|
|
26
|
-
postResponseProcessing:
|
|
27
|
-
updateUserProfile:
|
|
28
|
-
saveHairIssue:
|
|
29
|
-
getHairIssuesForUser:
|
|
30
|
-
postResponseProductCheck:
|
|
40
|
+
postProcessConversation: safeRequire('./src/postResponseProcessing', 'postResponseProcessing')?.postProcessConversation,
|
|
41
|
+
postResponseProcessing: safeRequire('./src/postResponseProcessing', 'postResponseProcessing')?.postResponseProcessing,
|
|
42
|
+
updateUserProfile: safeRequire('./src/postResponseProcessing', 'postResponseProcessing')?.updateUserProfile,
|
|
43
|
+
saveHairIssue: safeRequire('./src/hairIssues', 'hairIssues')?.saveHairIssue,
|
|
44
|
+
getHairIssuesForUser: safeRequire('./src/hairIssues', 'hairIssues')?.getHairIssuesForUser,
|
|
45
|
+
postResponseProductCheck: safeRequire('./src/postResponseProcessing', 'postResponseProcessing')?.postResponseProductCheck,
|
|
31
46
|
|
|
32
47
|
// Utilities
|
|
33
|
-
getAllProducts:
|
|
34
|
-
getAllFaqs:
|
|
35
|
-
getAllYoutubeVideos:
|
|
36
|
-
getAllTestimonials:
|
|
37
|
-
getAdditionalInstructions:
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
UnifiedChatHandler:
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
48
|
+
getAllProducts: safeRequire('./src/utils', 'utils')?.getAllProducts,
|
|
49
|
+
getAllFaqs: safeRequire('./src/utils', 'utils')?.getAllFaqs,
|
|
50
|
+
getAllYoutubeVideos: safeRequire('./src/utils', 'utils')?.getAllYoutubeVideos,
|
|
51
|
+
getAllTestimonials: safeRequire('./src/utils', 'utils')?.getAllTestimonials,
|
|
52
|
+
getAdditionalInstructions: safeRequire('./src/utils', 'utils')?.getAdditionalInstructions,
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
// Smart systems - Load with proper error handling and fallbacks
|
|
56
|
+
const smartModules = {
|
|
57
|
+
SmartPromptManager: null,
|
|
58
|
+
ResponseCache: null,
|
|
59
|
+
ConversationAnalytics: null,
|
|
60
|
+
ErrorRecoveryManager: null,
|
|
61
|
+
PersonalizationEngine: null,
|
|
62
|
+
UnifiedChatHandler: null
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
// Try to load smart modules
|
|
66
|
+
const smartModulePaths = {
|
|
67
|
+
SmartPromptManager: './src/smartPromptManager',
|
|
68
|
+
ResponseCache: './src/responseCache',
|
|
69
|
+
ConversationAnalytics: './src/conversationAnalytics',
|
|
70
|
+
ErrorRecoveryManager: './src/errorRecovery',
|
|
71
|
+
PersonalizationEngine: './src/personalizationEngine',
|
|
72
|
+
UnifiedChatHandler: './src/unifiedChatHandler'
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
// Load each smart module with fallback
|
|
76
|
+
for (const [moduleName, modulePath] of Object.entries(smartModulePaths)) {
|
|
77
|
+
try {
|
|
78
|
+
const loadedModule = require(modulePath);
|
|
79
|
+
|
|
80
|
+
// Check if it's a constructor or needs default export
|
|
81
|
+
if (typeof loadedModule === 'function') {
|
|
82
|
+
smartModules[moduleName] = loadedModule;
|
|
83
|
+
console.log(`✅ Loaded ${moduleName} as constructor`);
|
|
84
|
+
} else if (loadedModule.default && typeof loadedModule.default === 'function') {
|
|
85
|
+
smartModules[moduleName] = loadedModule.default;
|
|
86
|
+
console.log(`✅ Loaded ${moduleName} from default export`);
|
|
87
|
+
} else if (loadedModule[moduleName] && typeof loadedModule[moduleName] === 'function') {
|
|
88
|
+
smartModules[moduleName] = loadedModule[moduleName];
|
|
89
|
+
console.log(`✅ Loaded ${moduleName} from named export`);
|
|
90
|
+
} else {
|
|
91
|
+
throw new Error(`Module ${moduleName} is not a constructor`);
|
|
92
|
+
}
|
|
93
|
+
} catch (error) {
|
|
94
|
+
console.error(`❌ Failed to load ${moduleName}:`, error.message);
|
|
95
|
+
|
|
96
|
+
// Create fallback classes
|
|
97
|
+
switch (moduleName) {
|
|
98
|
+
case 'SmartPromptManager':
|
|
99
|
+
smartModules[moduleName] = require('./src/fallbacks/smartPromptManagerFallback');
|
|
100
|
+
break;
|
|
101
|
+
case 'ResponseCache':
|
|
102
|
+
smartModules[moduleName] = require('./src/fallbacks/responseCacheFallback');
|
|
103
|
+
break;
|
|
104
|
+
case 'ConversationAnalytics':
|
|
105
|
+
smartModules[moduleName] = require('./src/fallbacks/conversationAnalyticsFallback');
|
|
106
|
+
break;
|
|
107
|
+
case 'ErrorRecoveryManager':
|
|
108
|
+
smartModules[moduleName] = require('./src/fallbacks/errorRecoveryFallback');
|
|
109
|
+
break;
|
|
110
|
+
case 'PersonalizationEngine':
|
|
111
|
+
smartModules[moduleName] = require('./src/fallbacks/personalizationEngineFallback');
|
|
112
|
+
break;
|
|
113
|
+
case 'UnifiedChatHandler':
|
|
114
|
+
smartModules[moduleName] = require('./src/fallbacks/unifiedChatHandlerFallback');
|
|
115
|
+
break;
|
|
116
|
+
}
|
|
117
|
+
console.log(`⚠️ Using fallback for ${moduleName}`);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Enhanced systems
|
|
122
|
+
const enhancedModules = {
|
|
123
|
+
Logger: safeRequire('./src/logger', 'Logger')?.Logger,
|
|
124
|
+
createLogger: safeRequire('./src/logger', 'Logger')?.createLogger,
|
|
125
|
+
getLogger: safeRequire('./src/logger', 'Logger')?.getLogger,
|
|
126
|
+
Validator: safeRequire('./src/validation', 'Validator'),
|
|
127
|
+
ErrorHandler: safeRequire('./src/errorHandler', 'ErrorHandler'),
|
|
128
|
+
HealthMonitor: safeRequire('./src/healthMonitor', 'HealthMonitor')
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
// Export all modules
|
|
132
|
+
module.exports = {
|
|
133
|
+
...modules,
|
|
134
|
+
...smartModules,
|
|
135
|
+
...enhancedModules
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
// Log export summary
|
|
139
|
+
console.log('📦 Core module exports summary:');
|
|
140
|
+
console.log(`- Basic modules: ${Object.keys(modules).filter(k => modules[k] !== null).length}/${Object.keys(modules).length}`);
|
|
141
|
+
console.log(`- Smart modules: ${Object.keys(smartModules).filter(k => smartModules[k] !== null).length}/${Object.keys(smartModules).length}`);
|
|
142
|
+
console.log(`- Enhanced modules: ${Object.keys(enhancedModules).filter(k => enhancedModules[k] !== null).length}/${Object.keys(enhancedModules).length}`);
|
package/package.json
CHANGED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
// conversationAnalyticsFallback.js - Minimal analytics tracking
|
|
2
|
+
class ConversationAnalyticsFallback {
|
|
3
|
+
constructor() {
|
|
4
|
+
console.log('⚠️ Using ConversationAnalytics fallback implementation');
|
|
5
|
+
this.events = [];
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
async trackWelcomeEvent(userId) {
|
|
9
|
+
this.logEvent('welcome', userId, { timestamp: new Date() });
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
async trackUserMessage(userId, conversationId, message, contextAnalysis) {
|
|
13
|
+
this.logEvent('user_message', userId, {
|
|
14
|
+
conversationId,
|
|
15
|
+
messageLength: message.length,
|
|
16
|
+
timestamp: new Date()
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
async trackAIResponse(userId, conversationId, response, model, responseTime, cached) {
|
|
21
|
+
this.logEvent('ai_response', userId, {
|
|
22
|
+
conversationId,
|
|
23
|
+
model,
|
|
24
|
+
responseTime,
|
|
25
|
+
cached,
|
|
26
|
+
timestamp: new Date()
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
// Log warnings for xAI usage
|
|
30
|
+
if (model.includes('xai')) {
|
|
31
|
+
console.warn('⚠️ xAI model used - this should be rare!');
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async trackImageAnalysis(userId, conversationId, imageUrl, result, processingTime) {
|
|
36
|
+
this.logEvent('image_analysis', userId, {
|
|
37
|
+
conversationId,
|
|
38
|
+
processingTime,
|
|
39
|
+
success: !!result,
|
|
40
|
+
timestamp: new Date()
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
async trackConversionEvent(userId, conversationId, eventType, data) {
|
|
45
|
+
this.logEvent('conversion', userId, {
|
|
46
|
+
conversationId,
|
|
47
|
+
eventType,
|
|
48
|
+
...data,
|
|
49
|
+
timestamp: new Date()
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
async trackUserSatisfaction(userId, conversationId, score, feedback) {
|
|
54
|
+
this.logEvent('satisfaction', userId, {
|
|
55
|
+
conversationId,
|
|
56
|
+
score,
|
|
57
|
+
feedback,
|
|
58
|
+
timestamp: new Date()
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
async trackModelFailure(model, error, responseTime) {
|
|
63
|
+
console.error(`🚨 Model failure: ${model} - ${error.message}`);
|
|
64
|
+
this.logEvent('model_failure', 'system', {
|
|
65
|
+
model,
|
|
66
|
+
error: error.message,
|
|
67
|
+
responseTime,
|
|
68
|
+
timestamp: new Date()
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
logEvent(type, userId, data) {
|
|
73
|
+
const event = { type, userId, data, timestamp: new Date() };
|
|
74
|
+
this.events.push(event);
|
|
75
|
+
|
|
76
|
+
// Keep only last 1000 events in memory
|
|
77
|
+
if (this.events.length > 1000) {
|
|
78
|
+
this.events = this.events.slice(-1000);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
console.log(`📊 Event tracked (fallback): ${type}`);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
async getUserAnalytics(userId, days = 30) {
|
|
85
|
+
const relevantEvents = this.events.filter(e => e.userId === userId);
|
|
86
|
+
return {
|
|
87
|
+
totalEvents: relevantEvents.length,
|
|
88
|
+
eventTypes: [...new Set(relevantEvents.map(e => e.type))]
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
detectHairJourneyStage(message) {
|
|
93
|
+
// Simple stage detection
|
|
94
|
+
const content = message.toLowerCase();
|
|
95
|
+
if (content.includes('new') || content.includes('starting')) return 'Stage 1: Something New';
|
|
96
|
+
if (content.includes('love') || content.includes('happy')) return 'Stage 2: I\'m Rocking This!';
|
|
97
|
+
if (content.includes('experiment') || content.includes('try')) return 'Stage 3: Experimenting';
|
|
98
|
+
if (content.includes('bored')) return 'Stage 4: Boredom';
|
|
99
|
+
if (content.includes('desperate') || content.includes('help')) return 'Stage 5: Desperation';
|
|
100
|
+
if (content.includes('damage') || content.includes('repair')) return 'Stage 6: Damage or Protection';
|
|
101
|
+
return 'Unknown';
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
module.exports = ConversationAnalyticsFallback;
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
// errorRecoveryFallback.js - Critical error recovery fallback
|
|
2
|
+
class ErrorRecoveryManagerFallback {
|
|
3
|
+
constructor() {
|
|
4
|
+
console.log('⚠️ Using ErrorRecoveryManager fallback implementation');
|
|
5
|
+
|
|
6
|
+
this.modelFailures = {
|
|
7
|
+
'gemini20FlashExp': 0,
|
|
8
|
+
'gemini15Flash': 0,
|
|
9
|
+
'gemini15Pro': 0,
|
|
10
|
+
'xai-grok-3-mini-fast': 0
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
this.failureThreshold = 3;
|
|
14
|
+
this.resetInterval = 300000; // 5 minutes
|
|
15
|
+
|
|
16
|
+
// Reset failure counts periodically
|
|
17
|
+
setInterval(() => this.resetFailureCounts(), this.resetInterval);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
classifyError(error) {
|
|
21
|
+
const message = (error.message || '').toLowerCase();
|
|
22
|
+
|
|
23
|
+
if (message.includes('rate limit') || message.includes('quota')) {
|
|
24
|
+
return 'rate_limit';
|
|
25
|
+
}
|
|
26
|
+
if (message.includes('timeout')) {
|
|
27
|
+
return 'timeout';
|
|
28
|
+
}
|
|
29
|
+
if (message.includes('context') || message.includes('token')) {
|
|
30
|
+
return 'context_too_large';
|
|
31
|
+
}
|
|
32
|
+
if (message.includes('json') || message.includes('parse')) {
|
|
33
|
+
return 'parsing_error';
|
|
34
|
+
}
|
|
35
|
+
return 'unknown';
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
canMakeRequest(modelName) {
|
|
39
|
+
return this.modelFailures[modelName] < this.failureThreshold;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
recordSuccess(modelName) {
|
|
43
|
+
if (this.modelFailures[modelName] > 0) {
|
|
44
|
+
this.modelFailures[modelName]--;
|
|
45
|
+
console.log(`✅ ${modelName} success recorded, failures: ${this.modelFailures[modelName]}`);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
recordFailure(modelName) {
|
|
50
|
+
this.modelFailures[modelName]++;
|
|
51
|
+
console.warn(`❌ ${modelName} failure recorded, total: ${this.modelFailures[modelName]}`);
|
|
52
|
+
|
|
53
|
+
if (this.modelFailures[modelName] >= this.failureThreshold) {
|
|
54
|
+
console.error(`🚨 ${modelName} has reached failure threshold!`);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
async attemptRecovery(error, operation, modelName, attempt = 1) {
|
|
59
|
+
const errorType = this.classifyError(error);
|
|
60
|
+
console.log(`🔄 Recovery attempt ${attempt} for ${errorType} error on ${modelName}`);
|
|
61
|
+
|
|
62
|
+
this.recordFailure(modelName);
|
|
63
|
+
|
|
64
|
+
// Simple retry logic
|
|
65
|
+
if (attempt > 2) {
|
|
66
|
+
console.error(`Max retries exceeded for ${modelName}`);
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Wait before retry based on error type
|
|
71
|
+
const delays = {
|
|
72
|
+
rate_limit: 60000,
|
|
73
|
+
timeout: 5000,
|
|
74
|
+
context_too_large: 0,
|
|
75
|
+
parsing_error: 1000,
|
|
76
|
+
unknown: 2000
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
const delay = delays[errorType] || 2000;
|
|
80
|
+
|
|
81
|
+
if (delay > 0) {
|
|
82
|
+
console.log(`⏳ Waiting ${delay}ms before retry...`);
|
|
83
|
+
await new Promise(resolve => setTimeout(resolve, delay));
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return null; // Let caller handle retry
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
getEmergencyResponse() {
|
|
90
|
+
return {
|
|
91
|
+
messageType: 'html',
|
|
92
|
+
message: '<html><head><style>body{font-family:\'Archivo\',sans-serif;background-color:#f5f5f7;color:#222323;font-size:15px;line-height:1.5;}.highlight{font-family:\'Archivo Expanded Black\',sans-serif;font-size:14px;text-transform:uppercase;background-color:#fce5d7;color:#222323;padding:2px 6px;border-radius:4px;}</style></head><body><p>I\'m experiencing some technical difficulties. Let me connect you with a MYAVANA expert!</p><p>Try our <span class="highlight">HairAI™</span> analysis or book a consultation.</p></body></html>',
|
|
93
|
+
metadata: {
|
|
94
|
+
contentType: '300',
|
|
95
|
+
templateId: '12',
|
|
96
|
+
payload: [
|
|
97
|
+
{ title: 'Connect to expert', message: 'Connect me to a human expert' },
|
|
98
|
+
{ title: 'Learn about HairAI™', message: 'Tell me about HairAI™' },
|
|
99
|
+
{ title: 'Book consultation', message: 'I want to book a consultation' }
|
|
100
|
+
]
|
|
101
|
+
},
|
|
102
|
+
emergency: true
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
getReducedContext(chatHistory, maxMessages = 3) {
|
|
107
|
+
if (!chatHistory || chatHistory.length <= maxMessages) {
|
|
108
|
+
return chatHistory;
|
|
109
|
+
}
|
|
110
|
+
return chatHistory.slice(-maxMessages);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
getSimplifiedPrompt(prompt) {
|
|
114
|
+
// Extract essential parts only
|
|
115
|
+
const lines = prompt.split('\n');
|
|
116
|
+
const essential = lines.filter(line => {
|
|
117
|
+
const lower = line.toLowerCase();
|
|
118
|
+
return lower.includes('you are mya') ||
|
|
119
|
+
lower.includes('critical') ||
|
|
120
|
+
lower.includes('json') ||
|
|
121
|
+
lower.includes('user:');
|
|
122
|
+
});
|
|
123
|
+
return essential.join('\n');
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
getAvailableModels() {
|
|
127
|
+
return Object.entries(this.modelFailures)
|
|
128
|
+
.filter(([model, failures]) => failures < this.failureThreshold)
|
|
129
|
+
.map(([model]) => model);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
resetFailureCounts() {
|
|
133
|
+
for (const model in this.modelFailures) {
|
|
134
|
+
if (this.modelFailures[model] > 0) {
|
|
135
|
+
this.modelFailures[model] = Math.max(0, this.modelFailures[model] - 1);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
console.log('🔄 Model failure counts decremented');
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
getHealthStatus() {
|
|
142
|
+
const status = {};
|
|
143
|
+
for (const [model, failures] of Object.entries(this.modelFailures)) {
|
|
144
|
+
status[model] = {
|
|
145
|
+
available: failures < this.failureThreshold,
|
|
146
|
+
failures,
|
|
147
|
+
health: failures === 0 ? 'healthy' : failures < this.failureThreshold ? 'degraded' : 'unhealthy'
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
return status;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
module.exports = ErrorRecoveryManagerFallback;
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
// personalizationEngineFallback.js - Basic personalization fallback
|
|
2
|
+
class PersonalizationEngineFallback {
|
|
3
|
+
constructor() {
|
|
4
|
+
console.log('⚠️ Using PersonalizationEngine fallback implementation');
|
|
5
|
+
this.userProfiles = new Map();
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
async analyzeUserPersona(userId) {
|
|
9
|
+
// Simple persona detection based on recent interactions
|
|
10
|
+
const profile = this.userProfiles.get(userId) || {
|
|
11
|
+
messageCount: 0,
|
|
12
|
+
topics: [],
|
|
13
|
+
persona: 'hair_journey_beginner'
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
// Basic persona assignment
|
|
17
|
+
if (profile.messageCount > 20) {
|
|
18
|
+
profile.persona = 'hair_enthusiast';
|
|
19
|
+
} else if (profile.topics.includes('quick') || profile.topics.includes('simple')) {
|
|
20
|
+
profile.persona = 'busy_professional';
|
|
21
|
+
} else if (profile.topics.includes('problem') || profile.topics.includes('issue')) {
|
|
22
|
+
profile.persona = 'problem_solver';
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return {
|
|
26
|
+
persona: profile.persona,
|
|
27
|
+
confidence: 0.7,
|
|
28
|
+
details: this.getPersonaDetails(profile.persona)
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
getPersonaDetails(persona) {
|
|
33
|
+
const personas = {
|
|
34
|
+
'hair_enthusiast': {
|
|
35
|
+
name: 'Hair Enthusiast',
|
|
36
|
+
response_style: 'detailed_technical'
|
|
37
|
+
},
|
|
38
|
+
'busy_professional': {
|
|
39
|
+
name: 'Busy Professional',
|
|
40
|
+
response_style: 'concise_actionable'
|
|
41
|
+
},
|
|
42
|
+
'hair_journey_beginner': {
|
|
43
|
+
name: 'Hair Journey Beginner',
|
|
44
|
+
response_style: 'educational_supportive'
|
|
45
|
+
},
|
|
46
|
+
'problem_solver': {
|
|
47
|
+
name: 'Problem Solver',
|
|
48
|
+
response_style: 'problem_solution_focused'
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
return personas[persona] || personas['hair_journey_beginner'];
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
async getPersonalizedResponse(userId, query, baseResponse, context = {}) {
|
|
56
|
+
try {
|
|
57
|
+
// Track user interaction
|
|
58
|
+
const profile = this.userProfiles.get(userId) || {
|
|
59
|
+
messageCount: 0,
|
|
60
|
+
topics: [],
|
|
61
|
+
persona: 'hair_journey_beginner'
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
profile.messageCount++;
|
|
65
|
+
|
|
66
|
+
// Simple topic tracking
|
|
67
|
+
const queryLower = query.toLowerCase();
|
|
68
|
+
if (queryLower.includes('product')) profile.topics.push('product');
|
|
69
|
+
if (queryLower.includes('routine')) profile.topics.push('routine');
|
|
70
|
+
if (queryLower.includes('problem')) profile.topics.push('problem');
|
|
71
|
+
|
|
72
|
+
this.userProfiles.set(userId, profile);
|
|
73
|
+
|
|
74
|
+
// For fallback, just return the base response
|
|
75
|
+
// Real personalization would modify the response based on persona
|
|
76
|
+
return baseResponse;
|
|
77
|
+
|
|
78
|
+
} catch (error) {
|
|
79
|
+
console.error('Personalization fallback error:', error);
|
|
80
|
+
return baseResponse;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
async getPersonalizationContext(userId) {
|
|
85
|
+
const profile = this.userProfiles.get(userId) || {
|
|
86
|
+
messageCount: 0,
|
|
87
|
+
topics: [],
|
|
88
|
+
persona: 'hair_journey_beginner',
|
|
89
|
+
lastActive: new Date()
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
return {
|
|
93
|
+
messageCount: profile.messageCount,
|
|
94
|
+
topicsDiscussed: profile.topics,
|
|
95
|
+
persona: profile.persona,
|
|
96
|
+
isNewUser: profile.messageCount < 5
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
async trackPersonalizationMetrics(userId, persona, query, response) {
|
|
101
|
+
console.log(`📊 Personalization tracked (fallback): ${persona} for user ${userId}`);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Helper methods for basic personalization
|
|
105
|
+
shouldUseDetailedResponse(persona) {
|
|
106
|
+
return persona === 'hair_enthusiast';
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
shouldUseConciseResponse(persona) {
|
|
110
|
+
return persona === 'busy_professional';
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
shouldIncludeEducation(persona) {
|
|
114
|
+
return persona === 'hair_journey_beginner';
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
getRecommendedSuggestions(persona) {
|
|
118
|
+
const suggestions = {
|
|
119
|
+
'hair_enthusiast': [
|
|
120
|
+
{ title: 'Latest hair science', message: 'Tell me about the latest hair science' },
|
|
121
|
+
{ title: 'Ingredient analysis', message: 'Analyze ingredients in my products' },
|
|
122
|
+
{ title: 'Advanced techniques', message: 'What are advanced hair care techniques?' }
|
|
123
|
+
],
|
|
124
|
+
'busy_professional': [
|
|
125
|
+
{ title: 'Quick routine', message: 'Give me a 5-minute hair routine' },
|
|
126
|
+
{ title: 'Time-saving tips', message: 'What are time-saving hair tips?' },
|
|
127
|
+
{ title: 'Low maintenance', message: 'Suggest low maintenance styles' }
|
|
128
|
+
],
|
|
129
|
+
'hair_journey_beginner': [
|
|
130
|
+
{ title: 'Hair type', message: 'What\'s my hair type?' },
|
|
131
|
+
{ title: 'Basic routine', message: 'Help me create a basic hair routine' },
|
|
132
|
+
{ title: 'Learn about HairAI™', message: 'What is HairAI™?' }
|
|
133
|
+
],
|
|
134
|
+
'problem_solver': [
|
|
135
|
+
{ title: 'Diagnose issue', message: 'Help diagnose my hair problem' },
|
|
136
|
+
{ title: 'Treatment options', message: 'What treatments do you recommend?' },
|
|
137
|
+
{ title: 'Expert consultation', message: 'Should I book a consultation?' }
|
|
138
|
+
]
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
return suggestions[persona] || suggestions['hair_journey_beginner'];
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
clearUserProfile(userId) {
|
|
145
|
+
this.userProfiles.delete(userId);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
module.exports = PersonalizationEngineFallback;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
// responseCacheFallback.js - Minimal fallback for ResponseCache
|
|
2
|
+
class ResponseCacheFallback {
|
|
3
|
+
constructor() {
|
|
4
|
+
console.log('⚠️ Using ResponseCache fallback implementation');
|
|
5
|
+
this.cache = new Map();
|
|
6
|
+
this.maxCacheSize = 100;
|
|
7
|
+
this.ttl = 300000; // 5 minutes
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
async getCachedResponse(userId, query) {
|
|
11
|
+
const key = `${userId}:${query.toLowerCase().trim()}`;
|
|
12
|
+
const cached = this.cache.get(key);
|
|
13
|
+
|
|
14
|
+
if (cached && Date.now() - cached.timestamp < this.ttl) {
|
|
15
|
+
console.log('📦 Cache hit (fallback)');
|
|
16
|
+
return cached.response;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
async cacheResponse(userId, query, response) {
|
|
23
|
+
// Don't cache emergency responses or errors
|
|
24
|
+
if (response.emergency || response.error) return;
|
|
25
|
+
|
|
26
|
+
const key = `${userId}:${query.toLowerCase().trim()}`;
|
|
27
|
+
|
|
28
|
+
// Simple LRU - remove oldest if at capacity
|
|
29
|
+
if (this.cache.size >= this.maxCacheSize) {
|
|
30
|
+
const firstKey = this.cache.keys().next().value;
|
|
31
|
+
this.cache.delete(firstKey);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
this.cache.set(key, {
|
|
35
|
+
response,
|
|
36
|
+
timestamp: Date.now()
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
console.log('💾 Response cached (fallback)');
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
clearCache() {
|
|
43
|
+
this.cache.clear();
|
|
44
|
+
console.log('🧹 Cache cleared (fallback)');
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
module.exports = ResponseCacheFallback;
|