diff --git a/app/api/batch-analysis/route.js b/app/api/batch-analysis/route.js new file mode 100644 index 0000000..efd17a5 --- /dev/null +++ b/app/api/batch-analysis/route.js @@ -0,0 +1,265 @@ +import { NextResponse } from 'next/server' +import { enhancedScreenshotService } from '../../../lib/enhanced-screenshot' +import { aiAnalysisService } from '../../../lib/ai-analysis' +import { progressTracker } from '../../../lib/progress-tracker' + +export async function POST(request) { + try { + const body = await request.json() + const { symbol, layouts, timeframes, selectedLayouts, analyze = true } = body + + console.log('๐ Batch analysis request:', { symbol, layouts, timeframes, selectedLayouts }) + + // Validate inputs + if (!symbol || !timeframes || !Array.isArray(timeframes) || timeframes.length === 0) { + return NextResponse.json( + { success: false, error: 'Invalid request: symbol and timeframes array required' }, + { status: 400 } + ) + } + + // Generate unique session ID for progress tracking + const sessionId = `batch_analysis_${Date.now()}_${Math.random().toString(36).substr(2, 9)}` + console.log('๐ Created batch analysis session ID:', sessionId) + + // Create progress tracking session with initial steps + const initialSteps = [ + { + id: 'init', + title: 'Initializing Batch Analysis', + description: 'Starting multi-timeframe analysis...', + status: 'pending' + }, + { + id: 'auth', + title: 'TradingView Authentication', + description: 'Logging into TradingView accounts', + status: 'pending' + }, + { + id: 'navigation', + title: 'Chart Navigation', + description: 'Navigating to chart layouts', + status: 'pending' + }, + { + id: 'loading', + title: 'Chart Data Loading', + description: 'Waiting for chart data and indicators', + status: 'pending' + }, + { + id: 'capture', + title: 'Screenshot Capture', + description: `Capturing screenshots for ${timeframes.length} timeframes`, + status: 'pending' + }, + { + id: 'analysis', + title: 'AI Analysis', + description: 'Analyzing all screenshots with AI', + status: 'pending' + } + ] + + // Create the progress session + progressTracker.createSession(sessionId, initialSteps) + + // Prepare base configuration + const baseConfig = { + symbol: symbol || 'BTCUSD', + layouts: layouts || selectedLayouts || ['ai', 'diy'], + sessionId, + credentials: { + email: process.env.TRADINGVIEW_EMAIL, + password: process.env.TRADINGVIEW_PASSWORD + } + } + + console.log('๐ง Base config:', baseConfig) + + let allScreenshots = [] + const screenshotResults = [] + + try { + // STEP 1: Collect ALL screenshots from ALL timeframes FIRST + console.log(`๐ Starting batch screenshot collection for ${timeframes.length} timeframes...`) + + progressTracker.updateStep(sessionId, 'init', 'active', 'Starting batch screenshot collection...') + + for (let i = 0; i < timeframes.length; i++) { + const timeframe = timeframes[i] + const timeframeLabel = getTimeframeLabel(timeframe) + + console.log(`๐ธ Collecting screenshots for ${symbol} ${timeframeLabel} (${i + 1}/${timeframes.length})`) + + // Update progress for current timeframe + progressTracker.updateStep(sessionId, 'capture', 'active', + `Capturing ${timeframeLabel} screenshots (${i + 1}/${timeframes.length})` + ) + + try { + const config = { + ...baseConfig, + timeframe: timeframe, + sessionId: i === 0 ? sessionId : undefined // Only track progress for first timeframe + } + + // Capture screenshots WITHOUT analysis + const screenshots = await enhancedScreenshotService.captureWithLogin(config) + + if (screenshots && screenshots.length > 0) { + console.log(`โ Captured ${screenshots.length} screenshots for ${timeframeLabel}`) + + // Store screenshots with metadata + const screenshotData = { + timeframe: timeframe, + timeframeLabel: timeframeLabel, + screenshots: screenshots, + success: true + } + + screenshotResults.push(screenshotData) + allScreenshots.push(...screenshots) + + } else { + console.warn(`โ ๏ธ No screenshots captured for ${timeframeLabel}`) + screenshotResults.push({ + timeframe: timeframe, + timeframeLabel: timeframeLabel, + screenshots: [], + success: false, + error: 'No screenshots captured' + }) + } + + } catch (timeframeError) { + console.error(`โ Error capturing ${timeframeLabel}:`, timeframeError) + screenshotResults.push({ + timeframe: timeframe, + timeframeLabel: timeframeLabel, + screenshots: [], + success: false, + error: timeframeError.message + }) + } + + // Small delay between captures + if (i < timeframes.length - 1) { + await new Promise(resolve => setTimeout(resolve, 1000)) + } + } + + console.log(`๐ Batch screenshot collection completed: ${allScreenshots.length} total screenshots`) + progressTracker.updateStep(sessionId, 'capture', 'completed', `Captured ${allScreenshots.length} total screenshots`) + + // STEP 2: Send ALL screenshots to AI for comprehensive analysis + let analysis = null + + if (analyze && allScreenshots.length > 0) { + console.log(`๐ค Starting comprehensive AI analysis on ${allScreenshots.length} screenshots...`) + progressTracker.updateStep(sessionId, 'analysis', 'active', 'Running comprehensive AI analysis...') + + try { + if (allScreenshots.length === 1) { + analysis = await aiAnalysisService.analyzeScreenshot(allScreenshots[0]) + } else { + analysis = await aiAnalysisService.analyzeMultipleScreenshots(allScreenshots) + } + + if (analysis) { + console.log('โ Comprehensive AI analysis completed') + progressTracker.updateStep(sessionId, 'analysis', 'completed', 'AI analysis completed successfully!') + } else { + throw new Error('AI analysis returned null') + } + + } catch (analysisError) { + console.error('โ AI analysis failed:', analysisError) + progressTracker.updateStep(sessionId, 'analysis', 'error', `AI analysis failed: ${analysisError.message}`) + + // Don't fail the entire request - return screenshots without analysis + analysis = null + } + } + + // STEP 3: Format comprehensive results + const result = { + success: true, + type: 'batch_analysis', + sessionId, + timestamp: Date.now(), + symbol: symbol, + timeframes: timeframes, + layouts: baseConfig.layouts, + summary: `Batch analysis completed for ${timeframes.length} timeframes`, + totalScreenshots: allScreenshots.length, + screenshotResults: screenshotResults, + allScreenshots: allScreenshots.map(path => ({ + url: `/screenshots/${path.split('/').pop()}`, + timestamp: Date.now() + })), + analysis: analysis, // Comprehensive analysis of ALL screenshots + message: `Successfully captured ${allScreenshots.length} screenshots${analysis ? ' with comprehensive AI analysis' : ''}` + } + + // Clean up session + setTimeout(() => progressTracker.deleteSession(sessionId), 2000) + + return NextResponse.json(result) + + } catch (error) { + console.error('โ Batch analysis failed:', error) + progressTracker.updateStep(sessionId, 'analysis', 'error', `Batch analysis failed: ${error.message}`) + setTimeout(() => progressTracker.deleteSession(sessionId), 5000) + + return NextResponse.json( + { + success: false, + error: 'Batch analysis failed', + message: error.message, + sessionId: sessionId + }, + { status: 500 } + ) + } + + } catch (error) { + console.error('Batch analysis API error:', error) + return NextResponse.json( + { + success: false, + error: 'Batch analysis failed', + message: error.message + }, + { status: 500 } + ) + } +} + +// Helper function to get timeframe label +function getTimeframeLabel(timeframe) { + const timeframes = [ + { label: '1m', value: '1' }, + { label: '5m', value: '5' }, + { label: '15m', value: '15' }, + { label: '30m', value: '30' }, + { label: '1h', value: '60' }, + { label: '2h', value: '120' }, + { label: '4h', value: '240' }, + { label: '1d', value: 'D' }, + { label: '1w', value: 'W' }, + { label: '1M', value: 'M' }, + ] + + return timeframes.find(t => t.value === timeframe)?.label || timeframe +} + +export async function GET() { + return NextResponse.json({ + message: 'Batch Analysis API - use POST method for multi-timeframe analysis', + endpoints: { + POST: '/api/batch-analysis - Run multi-timeframe analysis with parameters' + } + }) +} diff --git a/components/AIAnalysisPanel.tsx b/components/AIAnalysisPanel.tsx index aca9133..3f57dfd 100644 --- a/components/AIAnalysisPanel.tsx +++ b/components/AIAnalysisPanel.tsx @@ -251,68 +251,57 @@ export default function AIAnalysisPanel({ onAnalysisComplete }: AIAnalysisPanelP onAnalysisComplete(data.analysis, analysisSymbol) } } else { - // Multiple timeframe analysis - const results = [] + // Multiple timeframe analysis - use batch analysis endpoint + console.log(`๐งช Starting batch analysis for ${analysisTimeframes.length} timeframes`) - for (let i = 0; i < analysisTimeframes.length; i++) { - const tf = analysisTimeframes[i] - const timeframeLabel = timeframes.find(t => t.value === tf)?.label || tf - - console.log(`๐งช Analyzing timeframe: ${timeframeLabel}`) - - const response = await fetch('/api/enhanced-screenshot', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ - symbol: analysisSymbol, - timeframe: tf, - layouts: selectedLayouts, - analyze: true - }) - }) - - const result = await response.json() - results.push({ - timeframe: tf, - timeframeLabel, - success: response.ok, - result + const response = await fetch('/api/batch-analysis', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + symbol: analysisSymbol, + timeframes: analysisTimeframes, + layouts: selectedLayouts, + analyze: true }) + }) - // Start progress tracking for the first timeframe session - if (i === 0 && result.sessionId) { - startProgressTracking(result.sessionId) - } - - // Update timeframe progress manually for multi-timeframe - setProgress(prev => prev ? { - ...prev, - timeframeProgress: { - current: i + 1, - total: analysisTimeframes.length, - currentTimeframe: timeframeLabel - } - } : null) - - // Small delay between requests - await new Promise(resolve => setTimeout(resolve, 1000)) - } + const data = await response.json() - const multiResult = { + if (!response.ok) { + throw new Error(data.error || 'Batch analysis failed') + } + + // Start real-time progress tracking if sessionId is provided + if (data.sessionId) { + startProgressTracking(data.sessionId) + } + + // Convert batch analysis result to compatible format + const batchResult = { type: 'multi_timeframe', symbol: analysisSymbol, - summary: `Analyzed ${results.length} timeframes for ${analysisSymbol}`, - results + summary: data.summary, + analysis: data.analysis, // Comprehensive analysis of ALL screenshots + totalScreenshots: data.totalScreenshots, + results: data.screenshotResults?.map((sr: any) => ({ + timeframe: sr.timeframe, + timeframeLabel: sr.timeframeLabel, + success: sr.success, + result: { + screenshots: sr.screenshots?.map((path: string) => ({ + url: `/screenshots/${path.split('/').pop()}`, + timestamp: Date.now() + })) || [], + analysis: sr.timeframe === analysisTimeframes[0] ? data.analysis : null // Only show comprehensive analysis on first timeframe + } + })) || [] } - setResult(multiResult) + setResult(batchResult) - // Call the callback with the first successful analysis result if provided - if (onAnalysisComplete) { - const firstSuccessfulResult = results.find(r => r.success && r.result?.analysis) - if (firstSuccessfulResult) { - onAnalysisComplete(firstSuccessfulResult.result.analysis, analysisSymbol) - } + // Call the callback with the comprehensive analysis result if provided + if (onAnalysisComplete && data.analysis) { + onAnalysisComplete(data.analysis, analysisSymbol) } } } catch (err) { @@ -1397,15 +1386,28 @@ export default function AIAnalysisPanel({ onAnalysisComplete }: AIAnalysisPanelP )} - {/* Position Calculator */} - {result && result.analysis && ( -