Files
trading_bot_v3/lib/ai-analysis.ts
mindesbunister 142d271c2c Fix progress tracking synchronization issues
- Enhanced EventSource message handling to properly reset UI state on completion
- Added completion detection based on all steps being finished
- Extended session deletion timeout from 1s to 3s for better UI updates
- Separated loading state management for single vs multi-timeframe analysis
- Ensured loading state is only reset by progress tracking for single timeframe
- Added immediate UI reset on errors to prevent stuck loading states
- Improved completion logging and state management
2025-07-17 12:35:59 +02:00

682 lines
28 KiB
TypeScript

import OpenAI from 'openai'
import fs from 'fs/promises'
import path from 'path'
import { enhancedScreenshotService, ScreenshotConfig } from './enhanced-screenshot'
import { TradingViewCredentials } from './tradingview-automation'
import { progressTracker } from './progress-tracker'
const openai = new OpenAI({
apiKey: process.env.OPENAI_API_KEY,
})
export interface AnalysisResult {
summary: string
marketSentiment: 'BULLISH' | 'BEARISH' | 'NEUTRAL'
keyLevels: {
support: number[]
resistance: number[]
}
recommendation: 'BUY' | 'SELL' | 'HOLD'
confidence: number // 0-100
reasoning: string
// Enhanced trading analysis (optional)
entry?: {
price: number
buffer?: string
rationale: string
}
stopLoss?: {
price: number
rationale: string
}
takeProfits?: {
tp1?: {
price: number
description: string
rsiExpectation?: string
obvExpectation?: string
}
tp2?: {
price: number
description: string
rsiExpectation?: string
obvExpectation?: string
}
}
riskToReward?: string
confirmationTrigger?: string
indicatorAnalysis?: {
rsi?: string
vwap?: string
obv?: string
macd?: string
crossLayoutConsensus?: string
}
layoutComparison?: {
aiLayout?: string
diyLayout?: string
consensus?: string
divergences?: string
}
timeframeRisk?: {
assessment?: string
positionSize?: string
leverageRecommendation?: string
}
alternatives?: {
tigherStopOption?: string
scaledEntry?: string
invalidationScenario?: string
}
}
export class AIAnalysisService {
async analyzeScreenshot(filenameOrPath: string): Promise<AnalysisResult | null> {
try {
let imagePath: string
// Check if it's already a full path or just a filename
if (path.isAbsolute(filenameOrPath)) {
// It's already a full path
imagePath = filenameOrPath
} else {
// It's just a filename, construct the full path
const screenshotsDir = path.join(process.cwd(), 'screenshots')
imagePath = path.join(screenshotsDir, filenameOrPath)
}
// Read image file
const imageBuffer = await fs.readFile(imagePath)
const base64Image = imageBuffer.toString('base64')
const prompt = `You are now a professional trading assistant. You behave with the precision and decisiveness of a top proprietary desk trader. No vagueness, no fluff.
⚠️ CRITICAL RSI READING INSTRUCTION: The RSI indicator shows a numerical value AND a line position. IGNORE the number if it conflicts with the visual line position. If the RSI line appears in the top area of the indicator (above the 70 horizontal line), report it as OVERBOUGHT regardless of what number is displayed.
**CRITICAL: FIRST IDENTIFY THE LAYOUT TYPE**
Before analyzing any indicators, you MUST determine which layout you are looking at:
**AI Layout identification:**
- Has RSI at the TOP of the chart
- Has MACD at the BOTTOM of the chart
- Has EMAs (9, 20, 50, 200) visible on the main chart
- Does NOT have VWAP or OBV
**DIY Layout identification:**
- Has Stochastic RSI at the TOP of the chart
- Has OBV (On-Balance Volume) at the BOTTOM of the chart
- Has VWAP (thick line) visible on the main chart
- Does NOT have regular RSI or MACD
**LAYOUT-SPECIFIC INDICATOR INFORMATION:**
If this is an AI Layout screenshot, it contains:
- TOP: RSI indicator (overbought above 70, oversold below 30)
- MIDDLE (on chart): SVP, ATR Bands, EMA 9, EMA 20, EMA 50, EMA 200
- BOTTOM: MACD indicator (NOT AT TOP - this is at the bottom of the chart)
* MACD has two lines: MACD line (usually blue/faster) and Signal line (usually red/slower)
* Bullish crossover = MACD line crosses ABOVE signal line (upward momentum)
* Bearish crossover = MACD line crosses BELOW signal line (downward momentum)
* Histogram bars: Green = bullish momentum, Red = bearish momentum
* Zero line: Above = overall bullish trend, Below = overall bearish trend
If this is a DIY Module Layout screenshot, it contains:
- TOP: Stochastic RSI indicator
- MIDDLE (on chart): VWAP, Smart Money Concepts by Algo
- BOTTOM: OBV (On-Balance Volume) indicator
**TRADING ANALYSIS REQUIREMENTS:**
1. **TIMEFRAME RISK ASSESSMENT**: Based on the timeframe shown in the screenshot, adjust risk accordingly:
- Lower timeframes (1m-15m): Higher risk, use at least 10x leverage for scalps, smaller position sizes
- Higher timeframes (4H+): Lower risk, larger position sizes, swing trades
- 5-minute scalps require at least 10x leverage
2. **BE 100% SPECIFIC** - Provide exact levels with clear rationale:
**ENTRY**: Exact price level (with ± buffer if needed)
- Rationale: e.g., "Rejection from 15 EMA + VWAP confluence near intraday supply"
**STOP-LOSS**: Exact level (not arbitrary)
- Explain WHY it's there: "Above VWAP + failed breakout zone"
**TAKE PROFITS**:
- TP1: Immediate structure (previous low/high, key level)
- TP2: Extended target if momentum continues
- Mention expected RSI/OBV behavior at each TP zone
3. **RISK-TO-REWARD**: Show R:R ratio with dollar amounts if possible
4. **CONFIRMATION TRIGGERS**: Exact signals to wait for:
- Specific candle patterns, indicator crosses, volume confirmations
- RSI/Stoch RSI behavior:
* MANDATORY: State if RSI is "OVERBOUGHT" (line above 70), "OVERSOLD" (line below 30), or "NEUTRAL" (between 30-70)
* Do NOT say "above 50 line" - only report overbought/oversold/neutral status
* If RSI line appears in upper area of indicator box, it's likely overbought regardless of number
- VWAP: "If price retakes VWAP with bullish momentum → consider invalidation"
- OBV: "If OBV starts climbing while price stays flat → early exit or reconsider bias"
- MACD: Analyze MACD crossovers at the BOTTOM indicator panel.
* Bullish crossover = MACD line (faster line) crosses ABOVE signal line (slower line) - indicates upward momentum
* Bearish crossover = MACD line crosses BELOW signal line - indicates downward momentum
* Histogram: Green bars = increasing bullish momentum, Red bars = increasing bearish momentum
* Report specific crossover direction and current momentum state
- EMA alignment: Check 9/20/50/200 EMA positioning and price relationship
- Smart Money Concepts: Identify supply/demand zones and market structure
5. **LAYOUT-SPECIFIC ANALYSIS**:
- AI Layout: Focus on RSI momentum (MUST identify overbought/oversold status), EMA alignment, MACD signals, and ATR bands for volatility
- DIY Layout: Emphasize VWAP positioning, Stoch RSI oversold/overbought levels, OBV volume confirmation, and Smart Money Concepts structure
Examine the chart and identify:
- Current price action and trend direction
- Key support and resistance levels visible on the chart
- Technical indicator readings (RSI, moving averages, volume if visible)
- Chart patterns or formations
- Market structure elements
Provide your analysis in this exact JSON format (replace values with your analysis):
{
"layoutDetected": "AI Layout|DIY Layout",
"summary": "Objective technical analysis with timeframe risk assessment and specific trading setup",
"marketSentiment": "BULLISH|BEARISH|NEUTRAL",
"keyLevels": {
"support": [list of visible support price levels as numbers],
"resistance": [list of visible resistance price levels as numbers]
},
"recommendation": "BUY|SELL|HOLD",
"confidence": 75,
"reasoning": "Specific technical analysis reasoning with exact rationale for each level",
"entry": {
"price": 150.50,
"buffer": "±0.25",
"rationale": "Specific technical reasoning: rejection from 15 EMA + VWAP confluence near intraday supply"
},
"stopLoss": {
"price": 148.00,
"rationale": "Exact reasoning: Above VWAP + failed breakout zone"
},
"takeProfits": {
"tp1": {
"price": 152.00,
"description": "Immediate structure target with indicator expectations",
"rsiExpectation": "RSI should reach 60-65 zone",
"obvExpectation": "OBV confirming momentum"
},
"tp2": {
"price": 154.00,
"description": "Extended target if momentum continues",
"rsiExpectation": "RSI approaching 70+ overbought",
"obvExpectation": "OBV making new highs with price"
}
},
"riskToReward": "1:2",
"confirmationTrigger": "Specific signal: Bearish engulfing candle on rejection from VWAP zone with RSI under 50",
"indicatorAnalysis": {
"rsi": "ONLY if AI Layout detected: RSI status - MUST be 'OVERBOUGHT' (above 70 line), 'OVERSOLD' (below 30 line), or 'NEUTRAL' (30-70). Do NOT reference 50 line position.",
"stochRsi": "ONLY if DIY Layout detected: Stochastic RSI oversold/overbought conditions - check both %K and %D lines",
"vwap": "ONLY if DIY Layout detected: VWAP relationship to price with exact invalidation levels",
"obv": "ONLY if DIY Layout detected: OBV volume analysis with specific behavioral expectations",
"macd": "ONLY if AI Layout detected: MACD analysis - The MACD is located at the BOTTOM of the chart. Analyze: 1) Histogram bars (green = bullish momentum, red = bearish), 2) Signal line crossover (MACD line crossing ABOVE signal line = bullish crossover, BELOW = bearish crossover), 3) Zero line position. Report specific crossover direction and current momentum state.",
"emaAlignment": "If AI Layout: EMA 9/20/50/200 positioning and price relationship - note stack order and price position",
"atrBands": "If AI Layout: ATR bands for volatility and support/resistance",
"smartMoney": "If DIY Layout: Smart Money Concepts supply/demand zones and structure"
},
"timeframeRisk": {
"assessment": "Risk level based on detected timeframe",
"positionSize": "Suggested position sizing based on timeframe",
"leverageRecommendation": "Specific leverage suggestion for the timeframe"
},
"alternatives": {
"tigherStopOption": "Alternative setup with tighter stop if original SL is too far",
"scaledEntry": "Scaled entry approach if better levels become available",
"invalidationScenario": "What price action would invalidate this setup completely"
}
}
Return only the JSON object with your technical analysis.`
const response = await openai.chat.completions.create({
model: "gpt-4o-mini", // Cost-effective vision model
messages: [
{
role: "user",
content: [
{ type: "text", text: prompt },
{
type: "image_url",
image_url: {
url: `data:image/png;base64,${base64Image}`,
detail: "low" // Reduce token usage
}
}
]
}
],
max_tokens: 1024,
temperature: 0.1
})
const content = response.choices[0]?.message?.content
if (!content) return null
console.log('AI response content:', content)
// Extract JSON from response
const match = content.match(/\{[\s\S]*\}/)
if (!match) {
console.error('No JSON found in response. Full content:', content)
return null
}
const json = match[0]
console.log('Raw JSON from AI:', json)
let result
try {
result = JSON.parse(json)
console.log('Parsed result:', result)
} catch (parseError) {
console.error('Failed to parse JSON:', parseError)
console.error('Raw JSON that failed:', json)
return null
}
// Sanitize the result to ensure no nested objects cause React issues
const sanitizedResult = {
summary: typeof result.summary === 'string' ? result.summary : String(result.summary || ''),
marketSentiment: result.marketSentiment || 'NEUTRAL',
keyLevels: {
support: Array.isArray(result.keyLevels?.support) ? result.keyLevels.support : [],
resistance: Array.isArray(result.keyLevels?.resistance) ? result.keyLevels.resistance : []
},
recommendation: result.recommendation || 'HOLD',
confidence: typeof result.confidence === 'number' ? result.confidence : 0,
reasoning: typeof result.reasoning === 'string' ? result.reasoning : String(result.reasoning || 'Basic technical analysis'),
...(result.entry && { entry: result.entry }),
...(result.stopLoss && { stopLoss: result.stopLoss }),
...(result.takeProfits && { takeProfits: result.takeProfits }),
...(result.riskToReward && { riskToReward: String(result.riskToReward) }),
...(result.confirmationTrigger && { confirmationTrigger: String(result.confirmationTrigger) }),
...(result.indicatorAnalysis && { indicatorAnalysis: result.indicatorAnalysis })
}
// Optionally: validate result structure here
return sanitizedResult as AnalysisResult
} catch (e) {
console.error('AI analysis error:', e)
return null
}
}
async analyzeMultipleScreenshots(filenamesOrPaths: string[]): Promise<AnalysisResult | null> {
try {
// Read all image files and convert to base64
const images = await Promise.all(
filenamesOrPaths.map(async (filenameOrPath) => {
let imagePath: string
// Check if it's already a full path or just a filename
if (path.isAbsolute(filenameOrPath)) {
// It's already a full path
imagePath = filenameOrPath
} else {
// It's just a filename, construct the full path
const screenshotsDir = path.join(process.cwd(), 'screenshots')
imagePath = path.join(screenshotsDir, filenameOrPath)
}
const imageBuffer = await fs.readFile(imagePath)
const base64Image = imageBuffer.toString('base64')
return {
type: "image_url" as const,
image_url: {
url: `data:image/png;base64,${base64Image}`,
detail: "high" as const
}
}
})
)
const layoutInfo = filenamesOrPaths.map(f => {
const filename = path.basename(f) // Extract filename from path
if (filename.includes('_ai_')) return 'AI Layout'
if (f.includes('_diy_') || f.includes('_Diy module_')) return 'DIY Module Layout'
return 'Unknown Layout'
}).join(' and ')
const prompt = `You are now a professional trading assistant. You behave with the precision and decisiveness of a top proprietary desk trader. No vagueness, no fluff.
I'm providing you with ${filenamesOrPaths.length} TradingView chart screenshots from different layouts: ${layoutInfo}.
⚠️ CRITICAL RSI READING INSTRUCTION: The RSI indicator shows a numerical value AND a line position. IGNORE the number if it conflicts with the visual line position. If the RSI line appears in the top area of the indicator (above the 70 horizontal line), report it as OVERBOUGHT regardless of what number is displayed.
**LAYOUT-SPECIFIC INDICATOR INFORMATION:**
**AI Layout Structure:**
- TOP: RSI indicator (14-period) - Look for EXACT numerical value displayed and visual position relative to 30/50/70 levels
- MIDDLE (on chart): SVP, ATR Bands, EMA 9 (yellow), EMA 20 (orange), EMA 50 (blue), EMA 200 (red)
- BOTTOM: MACD indicator with signal line and histogram
**DIY Module Layout Structure:**
- TOP: Stochastic RSI indicator - Check both %K and %D lines relative to 20/50/80 levels
- MIDDLE (on chart): VWAP (thick line), Smart Money Concepts by Algo (supply/demand zones)
- BOTTOM: OBV (On-Balance Volume) indicator showing volume flow
**CRITICAL: ACCURATE INDICATOR READING:**
- RSI: IGNORE the numerical value if it conflicts with visual position. The RSI line position on the chart is what matters:
* If RSI line is visually ABOVE the 70 horizontal line = OVERBOUGHT (regardless of number shown)
* If RSI line is visually BELOW the 30 horizontal line = OVERSOLD (regardless of number shown)
* If RSI line is between 30-70 = NEUTRAL zone
* Example: If number shows "56.61" but line appears above 70 level, report as "RSI OVERBOUGHT at 70+ level"
- MACD: Check histogram bars (green/red) and signal line crossovers
- EMA Alignment: Note price position relative to each EMA and EMA stack order
- VWAP: Identify if price is above/below VWAP and by how much
**TRADING ANALYSIS REQUIREMENTS:**
1. **TIMEFRAME RISK ASSESSMENT**: Based on the timeframe shown in the screenshots, adjust risk accordingly:
- Lower timeframes (1m-15m): Higher risk, use at least 10x leverage for scalps, smaller position sizes
- Higher timeframes (4H+): Lower risk, larger position sizes, swing trades
- 5-minute scalps require at least 10x leverage
2. **BE 100% SPECIFIC** - Provide exact levels with clear rationale:
**ENTRY**: Exact price level (with ± buffer if needed)
- Rationale: e.g., "Rejection from 15 EMA + VWAP confluence near intraday supply"
**STOP-LOSS**: Exact level (not arbitrary)
- Explain WHY it's there: "Above VWAP + failed breakout zone"
**TAKE PROFITS**:
- TP1: Immediate structure (previous low/high, key level)
- TP2: Extended target if momentum continues
- Mention expected RSI/OBV behavior at each TP zone
3. **RISK-TO-REWARD**: Show R:R ratio with dollar amounts if possible
4. **CONFIRMATION TRIGGERS**: Exact signals to wait for:
- Specific candle patterns, indicator crosses, volume confirmations
- RSI/Stoch RSI behavior: "If RSI crosses above 70 while price is under resistance → wait"
* CRITICAL: Read RSI visually - if the line appears above 70 level regardless of numerical display, treat as overbought
* If RSI line appears below 30 level visually, treat as oversold regardless of number shown
- VWAP: "If price retakes VWAP with bullish momentum → consider invalidation"
- OBV: "If OBV starts climbing while price stays flat → early exit or reconsider bias"
- MACD: Analyze MACD crossovers at the BOTTOM indicator panel.
* Bullish crossover = MACD line (faster line) crosses ABOVE signal line (slower line) - indicates upward momentum
* Bearish crossover = MACD line crosses BELOW signal line - indicates downward momentum
* Histogram: Green bars = increasing bullish momentum, Red bars = increasing bearish momentum
* Report specific crossover direction and current momentum state
- EMA alignment: Check 9/20/50/200 EMA positioning and price relationship
- Smart Money Concepts: Identify supply/demand zones and market structure
5. **CROSS-LAYOUT ANALYSIS**:
- Compare insights from different chart layouts for confirmations/contradictions
- AI Layout insights: RSI momentum + EMA alignment + MACD signals
- DIY Layout insights: VWAP positioning + Stoch RSI + OBV volume + Smart Money structure
- Use multiple perspectives to increase confidence
- Note which layout provides clearest signals
6. **ALTERNATIVES**: If SL is far, offer tighter alternatives or scaled entries
**Response Format** (return only valid JSON):
{
"summary": "Comprehensive multi-layout analysis with timeframe risk assessment and cross-layout insights",
"marketSentiment": "BULLISH|BEARISH|NEUTRAL",
"keyLevels": {
"support": [array of support levels from all charts],
"resistance": [array of resistance levels from all charts]
},
"recommendation": "BUY|SELL|HOLD",
"confidence": 85,
"reasoning": "Multi-layout technical analysis with specific rationale for each level and timeframe-adjusted risk assessment",
"entry": {
"price": 150.50,
"buffer": "±0.25",
"rationale": "Specific technical reasoning: rejection from 15 EMA + VWAP confluence near intraday supply"
},
"stopLoss": {
"price": 148.00,
"rationale": "Exact reasoning: Above VWAP + failed breakout zone"
},
"takeProfits": {
"tp1": {
"price": 152.00,
"description": "Immediate structure target with RSI/OBV expectations",
"rsiExpectation": "RSI should reach 60-65 zone",
"obvExpectation": "OBV confirming momentum"
},
"tp2": {
"price": 154.00,
"description": "Extended target if momentum continues",
"rsiExpectation": "RSI approaching 70+ overbought",
"obvExpectation": "OBV making new highs with price"
}
},
"riskToReward": "1:2.5",
"confirmationTrigger": "Specific signal: Bearish engulfing candle on rejection from VWAP zone with RSI under 50",
"indicatorAnalysis": {
"rsi": "AI Layout: RSI status - MUST be 'OVERBOUGHT' (above 70 line), 'OVERSOLD' (below 30 line), or 'NEUTRAL' (30-70). Do NOT reference 50 line position.",
"stochRsi": "DIY Layout: Stochastic RSI oversold/overbought conditions",
"vwap": "DIY Layout: VWAP relationship to price with exact invalidation levels",
"obv": "DIY Layout: OBV volume analysis with specific behavioral expectations",
"macd": "AI Layout: MACD signal line crosses and histogram momentum analysis - green/red bars and signal line position",
"emaAlignment": "AI Layout: EMA 9/20/50/200 positioning and price relationship - note stack order and price position",
"atrBands": "AI Layout: ATR bands for volatility and support/resistance",
"smartMoney": "DIY Layout: Smart Money Concepts supply/demand zones and structure",
"crossLayoutConsensus": "Detailed comparison of how different layouts confirm or contradict signals"
},
"layoutComparison": {
"aiLayout": "Specific insights and edge from AI layout analysis",
"diyLayout": "Specific insights and edge from DIY module layout analysis",
"consensus": "Exact areas where both layouts strongly agree with confidence boost",
"divergences": "Specific contradictions between layouts and how to resolve them"
},
"timeframeRisk": {
"assessment": "Risk level based on detected timeframe",
"positionSize": "Suggested position sizing based on timeframe",
"leverageRecommendation": "Specific leverage suggestion for the timeframe"
},
"alternatives": {
"tigherStopOption": "Alternative setup with tighter stop if original SL is too far",
"scaledEntry": "Scaled entry approach if better levels become available",
"invalidationScenario": "What price action would invalidate this setup completely"
}
}
Analyze all provided screenshots comprehensively and return only the JSON response.`
const messages = [
{
role: "user" as const,
content: [
{ type: "text" as const, text: prompt },
...images
]
}
]
console.log(`🤖 Sending ${filenamesOrPaths.length} screenshots to OpenAI for multi-layout analysis...`)
const response = await openai.chat.completions.create({
model: "gpt-4o-mini", // Cost-effective model with vision capabilities
messages,
max_tokens: 2000,
temperature: 0.1
})
const content = response.choices[0]?.message?.content
if (!content) {
throw new Error('No response from OpenAI')
}
console.log('🔍 Raw OpenAI response:', content.substring(0, 200) + '...')
// Parse JSON response
const jsonMatch = content.match(/\{[\s\S]*\}/)
if (!jsonMatch) {
throw new Error('No JSON found in response')
}
const analysis = JSON.parse(jsonMatch[0])
console.log('✅ Multi-layout analysis parsed successfully')
return analysis as AnalysisResult
} catch (error: any) {
console.error('❌ Multi-screenshot AI analysis failed:', error.message)
console.error('Full error:', error)
return null
}
}
async captureAndAnalyze(
symbol: string,
timeframe: string,
credentials: TradingViewCredentials
): Promise<AnalysisResult | null> {
try {
console.log(`Starting automated capture and analysis for ${symbol} ${timeframe}`)
// Capture screenshot using automation
const screenshot = await enhancedScreenshotService.captureQuick(symbol, timeframe, credentials)
if (!screenshot) {
throw new Error('Failed to capture screenshot')
}
console.log(`Screenshot captured: ${screenshot}`)
// Analyze the captured screenshot
const analysis = await this.analyzeScreenshot(screenshot)
if (!analysis) {
throw new Error('Failed to analyze screenshot')
}
console.log(`Analysis completed for ${symbol} ${timeframe}`)
return analysis
} catch (error) {
console.error('Automated capture and analysis failed:', error)
return null
}
}
async captureAndAnalyzeMultiple(
symbols: string[],
timeframes: string[],
credentials: TradingViewCredentials
): Promise<Array<{ symbol: string; timeframe: string; analysis: AnalysisResult | null }>> {
const results: Array<{ symbol: string; timeframe: string; analysis: AnalysisResult | null }> = []
for (const symbol of symbols) {
for (const timeframe of timeframes) {
try {
console.log(`Processing ${symbol} ${timeframe}...`)
const analysis = await this.captureAndAnalyze(symbol, timeframe, credentials)
results.push({
symbol,
timeframe,
analysis
})
// Small delay between captures to avoid overwhelming the system
await new Promise(resolve => setTimeout(resolve, 2000))
} catch (error) {
console.error(`Failed to process ${symbol} ${timeframe}:`, error)
results.push({
symbol,
timeframe,
analysis: null
})
}
}
}
return results
}
async captureAndAnalyzeWithConfig(config: ScreenshotConfig): Promise<{
screenshots: string[]
analysis: AnalysisResult | null
}> {
const { sessionId } = config
try {
console.log(`Starting automated capture with config for ${config.symbol} ${config.timeframe}`)
// Capture screenshots using enhanced service (this will handle its own progress)
const screenshots = await enhancedScreenshotService.captureWithLogin(config)
if (screenshots.length === 0) {
throw new Error('No screenshots captured')
}
console.log(`${screenshots.length} screenshot(s) captured`)
// Add AI analysis step to progress if sessionId exists
if (sessionId) {
progressTracker.updateStep(sessionId, 'analysis', 'active', 'Running AI analysis on screenshots...')
}
let analysis: AnalysisResult | null = null
if (screenshots.length === 1) {
// Single screenshot analysis
analysis = await this.analyzeScreenshot(screenshots[0])
} else {
// Multiple screenshots analysis
analysis = await this.analyzeMultipleScreenshots(screenshots)
}
if (!analysis) {
if (sessionId) {
progressTracker.updateStep(sessionId, 'analysis', 'error', 'AI analysis failed to generate results')
}
throw new Error('Failed to analyze screenshots')
}
console.log(`Analysis completed for ${config.symbol} ${config.timeframe}`)
if (sessionId) {
progressTracker.updateStep(sessionId, 'analysis', 'completed', 'AI analysis completed successfully!')
// Mark session as complete with longer delay to ensure UI receives updates
setTimeout(() => progressTracker.deleteSession(sessionId), 3000)
}
return {
screenshots,
analysis
}
} catch (error) {
console.error('Automated capture and analysis with config failed:', error)
if (sessionId) {
// Find the active step and mark it as error
const progress = progressTracker.getProgress(sessionId)
if (progress) {
const activeStep = progress.steps.find(step => step.status === 'active')
if (activeStep) {
progressTracker.updateStep(sessionId, activeStep.id, 'error', error instanceof Error ? error.message : 'Unknown error')
}
}
// Clean up session
setTimeout(() => progressTracker.deleteSession(sessionId), 5000)
}
return {
screenshots: [],
analysis: null
}
}
}
}
export const aiAnalysisService = new AIAnalysisService()