From d5bf485e72944c92234bb5232ff2dd68fc845690 Mon Sep 17 00:00:00 2001 From: mindesbunister Date: Sun, 27 Jul 2025 12:38:32 +0200 Subject: [PATCH] fix: Complete automation v2 page runtime error fixes - Fixed ES modules error by converting automation-with-learning-v2.js to pure ES6 - Fixed singleton pattern in automation-singleton.js for proper async handling - Fixed EnhancedAILearningPanel to handle recommendation objects correctly - Updated API routes to use correct import paths (../../../../lib/) - Created proper db.js utility with ES6 exports - Fixed simplified-stop-loss-learner imports and exports Automation v2 page now loads without errors AI learning system fully integrated and operational Learning status API working with detailed reports Recommendation rendering fixed for object structure --- app/api/automation/learning-status/route.js | 8 +- app/api/automation/start/route.js | 2 +- app/api/automation/status/route.js | 2 +- app/api/automation/stop/route.js | 2 +- components/EnhancedAILearningPanel.tsx | 79 ++++++++++++++++---- lib/automation-singleton.js | 12 +-- lib/automation-with-learning-v2.js | 2 +- lib/db.js | 42 +---------- lib/simplified-stop-loss-learner-fixed.js | 6 +- prisma/prisma/dev.db | Bin 3670016 -> 3747840 bytes 10 files changed, 84 insertions(+), 71 deletions(-) diff --git a/app/api/automation/learning-status/route.js b/app/api/automation/learning-status/route.js index c5358ac..e28b8a1 100644 --- a/app/api/automation/learning-status/route.js +++ b/app/api/automation/learning-status/route.js @@ -5,7 +5,7 @@ import { NextResponse } from 'next/server'; async function getAutomationInstance() { try { // Import the singleton automation instance - const { getAutomationInstance } = await import('../../../lib/automation-singleton.js'); + const { getAutomationInstance } = await import('../../../../lib/automation-singleton.js'); return getAutomationInstance(); } catch (error) { console.error('❌ Could not get automation instance:', error); @@ -44,9 +44,9 @@ export async function GET() { success: true, learningSystem: { ...learningStatus, - automationRunning: automationStatus.isRunning, - totalCycles: automationStatus.stats.totalCycles, - totalTrades: automationStatus.stats.totalTrades + automationRunning: automationStatus.isActive || automationStatus.isRunning, + totalCycles: automationStatus.totalCycles || automationStatus.stats?.totalCycles || 0, + totalTrades: automationStatus.totalTrades || automationStatus.stats?.totalTrades || 0 }, visibility: { decisionTrackingActive: learningStatus.activeDecisions > 0, diff --git a/app/api/automation/start/route.js b/app/api/automation/start/route.js index 611829d..3337434 100644 --- a/app/api/automation/start/route.js +++ b/app/api/automation/start/route.js @@ -3,7 +3,7 @@ import { NextResponse } from 'next/server'; // Import singleton automation manager async function getAutomationInstance() { try { - const { getAutomationInstance } = await import('../../../lib/automation-singleton.js'); + const { getAutomationInstance } = await import('../../../../lib/automation-singleton.js'); return await getAutomationInstance(); } catch (error) { console.error('❌ Could not get automation instance:', error); diff --git a/app/api/automation/status/route.js b/app/api/automation/status/route.js index fa62b68..a3f2d72 100644 --- a/app/api/automation/status/route.js +++ b/app/api/automation/status/route.js @@ -3,7 +3,7 @@ import { NextResponse } from 'next/server'; // Import singleton automation manager async function getAutomationInstance() { try { - const { getAutomationInstance } = await import('../../../lib/automation-singleton.js'); + const { getAutomationInstance } = await import('../../../../lib/automation-singleton.js'); return await getAutomationInstance(); } catch (error) { console.error('❌ Could not get automation instance:', error); diff --git a/app/api/automation/stop/route.js b/app/api/automation/stop/route.js index 4288055..ef07965 100644 --- a/app/api/automation/stop/route.js +++ b/app/api/automation/stop/route.js @@ -1,7 +1,7 @@ // Import singleton automation manager async function getAutomationInstance() { try { - const { getAutomationInstance } = await import('../../../lib/automation-singleton.js'); + const { getAutomationInstance } = await import('../../../../lib/automation-singleton.js'); return await getAutomationInstance(); } catch (error) { console.error('❌ Could not get automation instance:', error); diff --git a/components/EnhancedAILearningPanel.tsx b/components/EnhancedAILearningPanel.tsx index 108ff75..ff03cdd 100644 --- a/components/EnhancedAILearningPanel.tsx +++ b/components/EnhancedAILearningPanel.tsx @@ -17,7 +17,11 @@ interface LearningData { thresholds?: any; confidenceLevel?: number; }; - recommendations?: string[]; + recommendations?: Array<{ + type: string; + message: string; + priority: string; + } | string>; }; }; visibility?: { @@ -47,15 +51,43 @@ const EnhancedAILearningPanel = () => { const learningData = await learningResponse.json(); const statusData = await statusResponse.json(); - setLearningData({ - ...learningData, + // Ensure we have a proper data structure even if APIs return errors + const safeData = { + learningSystem: learningData.learningSystem || { + enabled: false, + message: learningData.message || 'Learning system not available', + activeDecisions: 0 + }, + visibility: learningData.visibility || { + decisionTrackingActive: false, + learningDatabaseConnected: false, + aiEnhancementsActive: false, + lastUpdateTime: new Date().toISOString() + }, automationStatus: statusData - }); + }; + setLearningData(safeData); setError(null); } catch (err) { console.error('Error fetching learning status:', err); setError(err instanceof Error ? err.message : 'Unknown error'); + + // Set default data structure on error + setLearningData({ + learningSystem: { + enabled: false, + message: 'Failed to fetch learning status', + activeDecisions: 0 + }, + visibility: { + decisionTrackingActive: false, + learningDatabaseConnected: false, + aiEnhancementsActive: false, + lastUpdateTime: new Date().toISOString() + }, + automationStatus: null + }); } finally { setLoading(false); } @@ -109,8 +141,23 @@ const EnhancedAILearningPanel = () => { const { learningSystem, visibility } = learningData; + // Safety check for learningSystem + if (!learningSystem) { + return ( +
+
+
+

+ 🧠 AI Learning System +

+
+
Loading learning system data...
+
+ ); + } + const renderLearningStatus = () => { - if (!learningSystem.enabled) { + if (!learningSystem || !learningSystem.enabled) { return (
@@ -120,9 +167,9 @@ const EnhancedAILearningPanel = () => {
- {learningSystem.message || 'The AI learning system is not currently integrated with the automation.'} + {learningSystem?.message || 'The AI learning system is not currently integrated with the automation.'}
- {learningSystem.recommendation && ( + {learningSystem?.recommendation && (
💡 {learningSystem.recommendation}
@@ -145,7 +192,7 @@ const EnhancedAILearningPanel = () => { AI Learning Active
- {learningSystem.report && ( + {learningSystem?.report && (
Total Decisions
@@ -192,15 +239,15 @@ const EnhancedAILearningPanel = () => {
-
0 ? 'bg-blue-500' : 'bg-gray-500'}`}>
- 0 ? 'text-blue-400' : 'text-gray-400'}> - Active Decisions ({learningSystem.activeDecisions || 0}) +
0 ? 'bg-blue-500' : 'bg-gray-500'}`}>
+ 0 ? 'text-blue-400' : 'text-gray-400'}> + Active Decisions ({learningSystem?.activeDecisions || 0})
- {learningSystem.report?.insights && ( + {learningSystem?.report?.insights && (
🎯 Learning Insights
@@ -214,13 +261,13 @@ const EnhancedAILearningPanel = () => {
)} - {learningSystem.report?.recommendations && learningSystem.report.recommendations.length > 0 && ( + {learningSystem?.report?.recommendations && learningSystem.report.recommendations.length > 0 && (
💡 AI Recommendations
- {learningSystem.report.recommendations.map((rec: string, index: number) => ( + {learningSystem.report.recommendations.map((rec: any, index: number) => (
- • {rec} + • {typeof rec === 'string' ? rec : rec.message || rec.type || 'No message'}
))}
@@ -234,7 +281,7 @@ const EnhancedAILearningPanel = () => {
-
+

🧠 AI Learning System

diff --git a/lib/automation-singleton.js b/lib/automation-singleton.js index 1c6f605..7e208c5 100644 --- a/lib/automation-singleton.js +++ b/lib/automation-singleton.js @@ -4,7 +4,7 @@ let automationInstance = null; async function createAutomationInstance() { try { // Try to import the learning-enhanced automation first - const AutomationWithLearning = require('./automation-with-learning-v2.js'); + const AutomationWithLearning = (await import('./automation-with-learning-v2.js')).default; console.log('✅ Creating automation instance with AI learning system'); return new AutomationWithLearning(); } catch (error) { @@ -23,24 +23,24 @@ async function createAutomationInstance() { } } -function getAutomationInstance() { +async function getAutomationInstance() { if (!automationInstance) { - automationInstance = createAutomationInstance(); + automationInstance = await createAutomationInstance(); } return automationInstance; } -function resetAutomationInstance() { +async function resetAutomationInstance() { if (automationInstance) { console.log('🔄 Resetting automation instance'); if (typeof automationInstance.stop === 'function') { - automationInstance.stop(); + await automationInstance.stop(); } } automationInstance = null; } -module.exports = { +export { getAutomationInstance, resetAutomationInstance }; diff --git a/lib/automation-with-learning-v2.js b/lib/automation-with-learning-v2.js index a20e622..385ecef 100644 --- a/lib/automation-with-learning-v2.js +++ b/lib/automation-with-learning-v2.js @@ -445,4 +445,4 @@ class AutomationWithLearning { } } -module.exports = AutomationWithLearning; +export default AutomationWithLearning; diff --git a/lib/db.js b/lib/db.js index d44d2e4..5be8f47 100644 --- a/lib/db.js +++ b/lib/db.js @@ -1,46 +1,12 @@ -/** - * Database utility for Prisma client - * - * Provides a global Prisma instance to avoid connection issues - */ +import { PrismaClient } from '@prisma/client'; -const { PrismaClient } = require('@prisma/client'); +let prisma; -// Global Prisma instance -let prisma = null; - -/** - * Get the global Prisma database instance - */ -async function getDB() { +function getDB() { if (!prisma) { prisma = new PrismaClient(); - - // Test the connection - try { - await prisma.$connect(); - console.log('✅ Database connection established'); - } catch (error) { - console.error('❌ Database connection failed:', error.message); - throw error; - } } - return prisma; } -/** - * Close the database connection - */ -async function closeDB() { - if (prisma) { - await prisma.$disconnect(); - prisma = null; - console.log('✅ Database connection closed'); - } -} - -module.exports = { - getDB, - closeDB -}; +export { getDB }; \ No newline at end of file diff --git a/lib/simplified-stop-loss-learner-fixed.js b/lib/simplified-stop-loss-learner-fixed.js index 2072655..5d1edde 100644 --- a/lib/simplified-stop-loss-learner-fixed.js +++ b/lib/simplified-stop-loss-learner-fixed.js @@ -5,8 +5,8 @@ * without complex statistical analysis. */ -const { PrismaClient } = require('@prisma/client'); -const getDB = require('./database-util'); +import { PrismaClient } from '@prisma/client'; +import { getDB } from './db.js'; class SimplifiedStopLossLearner { constructor() { @@ -527,4 +527,4 @@ class SimplifiedStopLossLearner { } } -module.exports = SimplifiedStopLossLearner; +export { SimplifiedStopLossLearner }; diff --git a/prisma/prisma/dev.db b/prisma/prisma/dev.db index a12c0ec53e9f13ed36069fff0cc93ac64b68e195..7a43a4451277001466124b1f44d29f8beb62ca4a 100644 GIT binary patch delta 20904 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 delta 2101 zcmZ9MZBSI_702&$-|uDbz550$f`Bd>Brhy_*}J|qN#mGKtp*~3k!F?%ww(8kCI(ET!f;S=HC`PN+R29kJXaI>(gcR4GM!VYL~SS)o--l zXqVMW15xRTrVB}7It5C@_lDx#T_gHG-)8)1qma3)=!!HKik1?CS)*9QcaE;0kjL-LUVWTshqbk>D2@i^+ zb7`5}AS0wt?N!^=DA`FGNx8aGEg_{aQf?H$_(44rqWyXiTv7;N{lqbO0$u<{|UV>$L8B`xVkiJw;|vzl z!UbVKEEKnh{}RtAy-K?hRaPn`iqmn+ao%y%(IFp@cgPWWx%`mKNPm?MOKnnE3QCID zAwD7eM`#j?_*Op1UE_w>+w3W}i+zcGik-vUV?JYgnUag0NE>&(T-AaW*IW9U{9l?xi@=a=lqG01b z;)R<}8g8Clh!>j+8A}X5#Cmie6!Zn%(79iKP$4HMX;VYEaZBno1iG!)u)%sLKDe}B zcS~IEeH~(SARl%o^h}dIpyx9juTtD5xIqG)aPB=l3l{Y1izPmsP9Gtdo)Y#MWv&e7 zYd)El`lh6TUfshA6;ux7%_{RjISD*#doH0M3EgQ&>6Bx9VVTRzToiLCcdG5pb&b*W z;Zmc_n(dElbICz8iw$Y>l|y^-Rep0LVoavHk!5f9vG zF`P8Jz@Ej>y^t3*`iQN)&}KN{YC`XTcY1WUm68S9rW;P44Pb#`*eDxbIN77SY)PF6 zxvk0#DIw3$=Y{5l*VjcNFE?$BHn0yrz*NvvKZ&`rUk?&{juTgcShG-FN)^G_M5xe? z9)DMNv+6Ka4mVE)XF+f>RBQ{QhpqG(nu_V?27G`#=ckOy{*8y=dig>%)04|c9KQX}%h*m%fm$8L7nWAnnl|AFe4 ztBfqTwARS9r@ixA!%eem?Nq5IZ5Kbc!fWjC^W9isX${VKsM08cq3X0*S#5YorIj?- zuJ+aUc&cj^c2ZoGE_G-%ddjQrd-hhLWrdw%tWM`t{*d<7PQ?oLpgK^6-JbZ9b;Y09 zM~(R)eY@FkFVsO>N|E*9Giz#$(=<#hwc1%^+pVW#evr`LB7?OCyGx|yb(G_K ic^yuuN>*OYY^(KF%%-SVNy{_v+;k(yd~Mu#k^3J$UeM$K