diff --git a/components/AIAnalysisPanel.tsx b/components/AIAnalysisPanel.tsx index 4212149..ef565c5 100644 --- a/components/AIAnalysisPanel.tsx +++ b/components/AIAnalysisPanel.tsx @@ -24,6 +24,28 @@ const popularCoins = [ { name: 'Chainlink', symbol: 'LINKUSD', icon: '๐Ÿ”—', color: 'from-blue-400 to-blue-600' }, ] +// Progress tracking interfaces +interface ProgressStep { + id: string + title: string + description: string + status: 'pending' | 'active' | 'completed' | 'error' + startTime?: number + endTime?: number + details?: string +} + +interface AnalysisProgress { + currentStep: number + totalSteps: number + steps: ProgressStep[] + timeframeProgress?: { + current: number + total: number + currentTimeframe?: string + } +} + export default function AIAnalysisPanel() { const [symbol, setSymbol] = useState('BTCUSD') const [selectedLayouts, setSelectedLayouts] = useState(['ai', 'diy']) // Default to both AI and DIY @@ -31,6 +53,7 @@ export default function AIAnalysisPanel() { const [loading, setLoading] = useState(false) const [result, setResult] = useState(null) const [error, setError] = useState(null) + const [progress, setProgress] = useState(null) // Helper function to safely render any value const safeRender = (value: any): string => { @@ -59,6 +82,105 @@ export default function AIAnalysisPanel() { ) } + // Helper function to create initial progress steps + const createProgressSteps = (timeframes: string[], layouts: string[]): ProgressStep[] => { + const steps: ProgressStep[] = [] + + if (timeframes.length > 1) { + steps.push({ + id: 'init', + title: 'Initializing Multi-Timeframe Analysis', + description: `Preparing to analyze ${timeframes.length} timeframes`, + status: 'pending' + }) + } else { + steps.push({ + id: 'init', + title: 'Initializing Analysis', + description: `Setting up screenshot service for ${layouts.join(', ')} layout(s)`, + status: 'pending' + }) + } + + steps.push({ + id: 'browser', + title: 'Starting Browser Sessions', + description: `Launching ${layouts.length} browser session(s)`, + status: 'pending' + }) + + steps.push({ + id: 'auth', + title: 'TradingView Authentication', + description: 'Logging into TradingView accounts', + status: 'pending' + }) + + steps.push({ + id: 'navigation', + title: 'Chart Navigation', + description: 'Navigating to chart layouts and timeframes', + status: 'pending' + }) + + steps.push({ + id: 'loading', + title: 'Chart Data Loading', + description: 'Waiting for chart data and indicators to load', + status: 'pending' + }) + + steps.push({ + id: 'capture', + title: 'Screenshot Capture', + description: 'Capturing high-quality chart screenshots', + status: 'pending' + }) + + steps.push({ + id: 'analysis', + title: 'AI Analysis', + description: 'Analyzing screenshots with AI for trading insights', + status: 'pending' + }) + + return steps + } + + // Helper function to update progress + const updateProgress = (stepId: string, status: ProgressStep['status'], details?: string) => { + setProgress(prev => { + if (!prev) return null + + const updatedSteps = prev.steps.map(step => { + if (step.id === stepId) { + const updatedStep = { + ...step, + status, + details: details || step.details + } + + if (status === 'active' && !step.startTime) { + updatedStep.startTime = Date.now() + } else if ((status === 'completed' || status === 'error') && !step.endTime) { + updatedStep.endTime = Date.now() + } + + return updatedStep + } + return step + }) + + const currentStepIndex = updatedSteps.findIndex(step => step.status === 'active') + + return { + ...prev, + steps: updatedSteps, + currentStep: currentStepIndex >= 0 ? currentStepIndex + 1 : prev.currentStep + } + }) + } + const performAnalysis = async (analysisSymbol = symbol, analysisTimeframes = selectedTimeframes) => { if (loading || selectedLayouts.length === 0 || analysisTimeframes.length === 0) return @@ -66,9 +188,27 @@ export default function AIAnalysisPanel() { setError(null) setResult(null) + // Initialize progress tracking + const steps = createProgressSteps(analysisTimeframes, selectedLayouts) + setProgress({ + currentStep: 0, + totalSteps: steps.length, + steps, + timeframeProgress: analysisTimeframes.length > 1 ? { + current: 0, + total: analysisTimeframes.length + } : undefined + }) + try { + updateProgress('init', 'active') + if (analysisTimeframes.length === 1) { // Single timeframe analysis + await new Promise(resolve => setTimeout(resolve, 500)) // Brief pause for UI + updateProgress('init', 'completed') + updateProgress('browser', 'active', 'Starting browser session...') + const response = await fetch('/api/enhanced-screenshot', { method: 'POST', headers: { 'Content-Type': 'application/json' }, @@ -80,19 +220,63 @@ export default function AIAnalysisPanel() { }) }) + // Since we can't track internal API progress in real-time, we'll simulate logical progression + await new Promise(resolve => setTimeout(resolve, 1000)) + updateProgress('browser', 'completed') + updateProgress('auth', 'active', 'Authenticating with TradingView...') + + await new Promise(resolve => setTimeout(resolve, 2000)) + updateProgress('auth', 'completed') + updateProgress('navigation', 'active', `Navigating to ${analysisSymbol} chart...`) + + await new Promise(resolve => setTimeout(resolve, 2000)) + updateProgress('navigation', 'completed') + updateProgress('loading', 'active', 'Loading chart data and indicators...') + + await new Promise(resolve => setTimeout(resolve, 3000)) + updateProgress('loading', 'completed') + updateProgress('capture', 'active', 'Capturing screenshots...') + const data = await response.json() if (!response.ok) { + updateProgress('capture', 'error', data.error || 'Screenshot capture failed') throw new Error(data.error || 'Analysis failed') } + updateProgress('capture', 'completed', `Captured ${data.screenshots?.length || 0} screenshot(s)`) + updateProgress('analysis', 'active', 'Running AI analysis...') + + await new Promise(resolve => setTimeout(resolve, 1000)) + updateProgress('analysis', 'completed', 'Analysis complete!') + setResult(data) } else { // Multiple timeframe analysis + await new Promise(resolve => setTimeout(resolve, 500)) + updateProgress('init', 'completed', `Starting analysis for ${analysisTimeframes.length} timeframes`) + const results = [] - for (const tf of analysisTimeframes) { - console.log(`๐Ÿงช Analyzing timeframe: ${timeframes.find(t => t.value === tf)?.label || tf}`) + for (let i = 0; i < analysisTimeframes.length; i++) { + const tf = analysisTimeframes[i] + const timeframeLabel = timeframes.find(t => t.value === tf)?.label || tf + + // Update timeframe progress + setProgress(prev => prev ? { + ...prev, + timeframeProgress: { + ...prev.timeframeProgress!, + current: i + 1, + currentTimeframe: timeframeLabel + } + } : null) + + console.log(`๐Ÿงช Analyzing timeframe: ${timeframeLabel}`) + + if (i === 0) { + updateProgress('browser', 'active', `Processing ${timeframeLabel} - Starting browser...`) + } const response = await fetch('/api/enhanced-screenshot', { method: 'POST', @@ -105,18 +289,40 @@ export default function AIAnalysisPanel() { }) }) + if (i === 0) { + updateProgress('browser', 'completed') + updateProgress('auth', 'active', `Processing ${timeframeLabel} - Authenticating...`) + await new Promise(resolve => setTimeout(resolve, 1000)) + updateProgress('auth', 'completed') + } + + updateProgress('navigation', 'active', `Processing ${timeframeLabel} - Navigating to chart...`) + await new Promise(resolve => setTimeout(resolve, 1000)) + + updateProgress('loading', 'active', `Processing ${timeframeLabel} - Loading chart data...`) + await new Promise(resolve => setTimeout(resolve, 1500)) + + updateProgress('capture', 'active', `Processing ${timeframeLabel} - Capturing screenshots...`) + const result = await response.json() results.push({ timeframe: tf, - timeframeLabel: timeframes.find(t => t.value === tf)?.label || tf, + timeframeLabel, success: response.ok, result }) + updateProgress('analysis', 'active', `Processing ${timeframeLabel} - Running AI analysis...`) + // Small delay between requests await new Promise(resolve => setTimeout(resolve, 2000)) } + updateProgress('navigation', 'completed') + updateProgress('loading', 'completed') + updateProgress('capture', 'completed', `Captured screenshots for all ${analysisTimeframes.length} timeframes`) + updateProgress('analysis', 'completed', `Completed analysis for all timeframes!`) + setResult({ type: 'multi_timeframe', symbol: analysisSymbol, @@ -125,7 +331,25 @@ export default function AIAnalysisPanel() { }) } } catch (err) { - setError(err instanceof Error ? err.message : 'Failed to perform analysis') + const errorMessage = err instanceof Error ? err.message : 'Failed to perform analysis' + setError(errorMessage) + + // Mark current active step as error + setProgress(prev => { + if (!prev) return null + const activeStepIndex = prev.steps.findIndex(step => step.status === 'active') + if (activeStepIndex >= 0) { + const updatedSteps = [...prev.steps] + updatedSteps[activeStepIndex] = { + ...updatedSteps[activeStepIndex], + status: 'error', + details: errorMessage, + endTime: Date.now() + } + return { ...prev, steps: updatedSteps } + } + return prev + }) } finally { setLoading(false) } @@ -441,18 +665,138 @@ export default function AIAnalysisPanel() { )} - {loading && ( -
-
-
-
-

AI Processing

-

- Analyzing {symbol} on {selectedTimeframes.length === 1 - ? `${timeframes.find(tf => tf.value === selectedTimeframes[0])?.label} timeframe` - : `${selectedTimeframes.length} timeframes` - }... -

+ {loading && progress && ( +
+ {/* Header */} +
+
+
+
+

AI Analysis in Progress

+

+ Analyzing {symbol} โ€ข {selectedLayouts.join(', ')} layouts +

+
+
+ + {/* Overall Progress */} +
+
+ Step {progress.currentStep} of {progress.totalSteps} +
+
+ {Math.round((progress.currentStep / progress.totalSteps) * 100)}% Complete +
+
+
+ + {/* Multi-timeframe progress */} + {progress.timeframeProgress && ( +
+
+
Multi-Timeframe Analysis
+ + {progress.timeframeProgress.current}/{progress.timeframeProgress.total} timeframes + +
+
+
+
+ {progress.timeframeProgress.currentTimeframe && ( +

+ Current: {progress.timeframeProgress.currentTimeframe} +

+ )} +
+ )} + + {/* Progress Steps */} +
+ {progress.steps.map((step, index) => { + const isActive = step.status === 'active' + const isCompleted = step.status === 'completed' + const isError = step.status === 'error' + const isPending = step.status === 'pending' + + return ( +
+ {/* Step Icon */} +
+ {isCompleted ? 'โœ“' : + isError ? 'โœ—' : + isActive ? 'โŸณ' : + index + 1} +
+ + {/* Step Content */} +
+
+
+ {step.title} +
+ + {/* Timing */} + {(step.startTime || step.endTime) && ( + + {step.endTime && step.startTime ? + `${((step.endTime - step.startTime) / 1000).toFixed(1)}s` : + isActive && step.startTime ? + `${((Date.now() - step.startTime) / 1000).toFixed(0)}s` : + '' + } + + )} +
+ +

+ {step.details || step.description} +

+
+ + {/* Active indicator */} + {isActive && ( +
+
+
+ )} +
+ ) + })} +
+ + {/* Overall Progress Bar */} +
+
+