aidevhund commited on
Commit
4542f7d
Β·
verified Β·
1 Parent(s): 5c5eb33

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +147 -151
app.py CHANGED
@@ -4,201 +4,197 @@ import os
4
  import cv2
5
  import numpy as np
6
  import base64
7
- import json
8
  from typing import Tuple, Dict, Any
9
  from datetime import datetime
10
 
11
  # OpenAI API Configuration
12
  openai.api_key = os.getenv("OPENAI_API_KEY")
13
- ANALYSIS_MODEL = "gpt-4o-mini"
14
- MAX_TOKENS = 1500
15
 
16
  class ChartAnalyzer:
17
  def __init__(self):
18
- self.previous_analysis = {}
19
- self.trend_history = []
20
- self.user_preferences = {}
21
 
22
  def encode_image(self, image_path: str) -> str:
23
- """Encode image to base64 with error handling"""
24
- try:
25
- with open(image_path, "rb") as image_file:
26
- return base64.b64encode(image_file.read()).decode('utf-8')
27
- except Exception as e:
28
- raise ValueError(f"Image encoding error: {str(e)}")
29
-
30
- def dynamic_trend_calculation(self, analysis_text: str) -> Dict[str, Any]:
31
- """Calculate dynamic trend parameters from analysis text"""
32
- trend_data = {
33
- 'short_term': {'slope': 0, 'direction': 'neutral'},
34
- 'medium_term': {'slope': 0, 'direction': 'neutral'},
35
- 'long_term': {'slope': 0, 'direction': 'neutral'}
 
 
 
 
36
  }
37
 
38
- # Simplified slope calculation example
39
- if "uptrend" in analysis_text.lower():
40
- trend_data['short_term']['slope'] = 0.5
41
- trend_data['short_term']['direction'] = 'bullish'
42
- if "downtrend" in analysis_text.lower():
43
- trend_data['short_term']['slope'] = -0.5
44
- trend_data['short_term']['direction'] = 'bearish'
45
 
46
- return trend_data
47
-
48
- def calculate_confidence_score(self, analysis_text: str) -> float:
49
- """Calculate confidence score based on analysis content"""
50
- score = 0.5 # Base score
51
- keywords = {
52
- 'strong support': 0.2,
53
- 'clear resistance': 0.15,
54
- 'confirmed pattern': 0.25,
55
- 'high volume': 0.1,
56
- 'breakout': 0.2
57
- }
58
 
59
- for keyword, value in keywords.items():
60
- if keyword in analysis_text.lower():
61
- score += value
62
- return min(max(score, 0), 1) # Clamp between 0-1
63
-
64
- def calculate_price_targets(self, analysis_text: str, current_price: float) -> Dict[str, float]:
65
- """Calculate price targets based on detected patterns"""
66
- targets = {}
67
- if "triangle" in analysis_text.lower():
68
- targets['pattern_target'] = current_price * 1.1
69
- if "double bottom" in analysis_text.lower():
70
- targets['pattern_target'] = current_price * 1.15
71
- return targets
 
 
 
 
 
 
 
 
 
 
72
 
73
- def analyze_chart(self, image_path: str, user_message: str, time_horizon: str) -> Tuple[str, str]:
74
- """Main analysis function with enhanced features"""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
75
  try:
76
  # Image processing
77
  base64_image = self.encode_image(image_path)
78
  image_url = f"data:image/jpeg;base64,{base64_image}"
79
-
80
- # Prepare AI request with time horizon context
81
- system_message = f"""You are an expert crypto analyst. Analyze this chart considering {time_horizon} time horizon.
82
- Include: trend analysis, pattern recognition (flag, wedge, H&S), support/resistance zones,
83
- volume analysis, and risk assessment. Provide specific price targets where applicable."""
84
-
85
  response = openai.ChatCompletion.create(
86
  model=ANALYSIS_MODEL,
87
  messages=[
88
- {"role": "system", "content": system_message},
89
- {"role": "user", "content": user_message},
90
- {"role": "user", "content": {"type": "image_url", "image_url": image_url}}
 
 
 
 
 
 
91
  ],
92
  max_tokens=MAX_TOKENS
93
  )
94
-
95
- raw_output = response.choices[0].message.content
96
 
97
- # Enhanced processing
98
- confidence = self.calculate_confidence_score(raw_output)
99
- trends = self.dynamic_trend_calculation(raw_output)
100
- price_targets = self.calculate_price_targets(raw_output, 100) # Replace with actual price
101
 
102
- # Format insights with new features
103
- formatted_insights = f"""
104
- ## πŸ“ˆ Multi-Timeframe Analysis ({time_horizon})
105
- **Confidence Score:** {confidence*100:.1f}%
106
- **Trend Dynamics:**
107
- - Short Term: {trends['short_term']['direction'].upper()} (Slope: {trends['short_term']['slope']})
108
- - Medium Term: {trends['medium_term']['direction'].upper()}
 
 
 
 
 
 
 
 
109
 
110
- ### 🎯 Price Targets:
111
- {json.dumps(price_targets, indent=2)}
 
112
 
113
- ### πŸ” Detailed Analysis:
114
- {raw_output}
115
- """
116
 
117
- # Process image with all overlays
118
- marked_image = self.overlay_patterns(image_path, raw_output, trends)
 
119
 
120
- # Store analysis for comparison
121
- self.store_analysis_result(marked_image, formatted_insights)
122
 
123
- return formatted_insights, marked_image
124
-
125
  except Exception as e:
126
- return f"⚠️ Analysis Error: {str(e)}", None
127
-
128
- def overlay_patterns(self, image_path: str, analysis: str, trends: Dict) -> str:
129
- """Advanced pattern overlay with dynamic elements"""
130
- img = cv2.imread(image_path)
131
- if img is None:
132
- return None
133
-
134
- h, w = img.shape[:2]
135
- overlay = img.copy()
136
-
137
- # Dynamic trend lines
138
- for timeframe in ['short_term', 'medium_term']:
139
- if trends[timeframe]['direction'] != 'neutral':
140
- color = (0, 255, 0) if 'bull' in trends[timeframe]['direction'] else (0, 0, 255)
141
- thickness = 2 if timeframe == 'short_term' else 1
142
- cv2.line(overlay, (0, int(h*(0.5 - trends[timeframe]['slope']*0.1))),
143
- (w, int(h*(0.5 - trends[timeframe]['slope']*0.2))),
144
- color, thickness)
145
-
146
- # Support/Resistance bands
147
- if "support" in analysis.lower():
148
- cv2.rectangle(overlay, (0, int(h*0.75)), (w, int(h*0.85)), (0, 255, 0, 50), -1)
149
- if "resistance" in analysis.lower():
150
- cv2.rectangle(overlay, (0, int(h*0.15)), (w, int(h*0.25)), (0, 0, 255, 50), -1)
151
 
152
- # Pattern annotations
153
- if "triangle" in analysis.lower():
154
- cv2.drawContours(overlay, [np.array([[w//4, h//2], [3*w//4, h//3], [3*w//4, 2*h//3]])], 0, (255,255,0), 2)
155
-
156
- # Blending overlays
157
- alpha = 0.4
158
- img = cv2.addWeighted(overlay, alpha, img, 1 - alpha, 0)
159
-
160
- # Add confidence meter
161
- cv2.rectangle(img, (w-120, 20), (w-20, 40), (50,50,50), -1)
162
- cv2.rectangle(img, (w-120, 20), (w-120 + int(100*0.8), 40), (0,255,0), -1) # Example 80% confidence
163
-
164
- output_path = f"marked_{datetime.now().strftime('%Y%m%d%H%M%S')}.png"
165
- cv2.imwrite(output_path, img)
166
- return output_path
167
-
168
- def store_analysis_result(self, image_path: str, analysis: str):
169
- """Store current analysis for future comparison"""
170
- self.previous_analysis = {
171
- 'timestamp': datetime.now(),
172
- 'image': image_path,
173
- 'analysis': analysis
174
- }
175
-
176
- # Gradio Interface Components
177
  analyzer = ChartAnalyzer()
178
 
179
- with gr.Blocks(theme=gr.themes.Soft()) as demo:
180
- gr.Markdown("# πŸš€ Pro Crypto Analysis Suite")
181
 
182
  with gr.Row():
183
  with gr.Column(scale=1):
184
- time_horizon = gr.Dropdown(["Short Term (1D-1W)", "Medium Term (1W-1M)", "Long Term (1M+)"],
185
- label="Trading Horizon", value="Medium Term (1W-1M)")
186
- user_query = gr.Textbox(label="Analysis Request", placeholder="Specify your analysis focus...")
187
- chart_input = gr.Image(type="filepath", label="Upload Chart", sources=["upload"])
188
- analyze_btn = gr.Button("Run Full Analysis", variant="primary")
 
 
189
 
190
  with gr.Column(scale=2):
191
- insights_output = gr.Markdown(label="Analysis Results")
192
- annotated_chart = gr.Image(label="Annotated Chart", interactive=False)
193
- comparison_section = gr.Markdown("## πŸ”„ Historical Comparison")
194
-
195
- # Event handling
 
196
  analyze_btn.click(
197
  fn=analyzer.analyze_chart,
198
- inputs=[chart_input, user_query, time_horizon],
199
- outputs=[insights_output, annotated_chart]
200
  )
201
 
202
- # Launch configuration
203
  if __name__ == "__main__":
204
  demo.launch()
 
4
  import cv2
5
  import numpy as np
6
  import base64
7
+ import re
8
  from typing import Tuple, Dict, Any
9
  from datetime import datetime
10
 
11
  # OpenAI API Configuration
12
  openai.api_key = os.getenv("OPENAI_API_KEY")
13
+ ANALYSIS_MODEL = "gpt-4o"
14
+ MAX_TOKENS = 4096
15
 
16
  class ChartAnalyzer:
17
  def __init__(self):
18
+ self.last_analysis = {}
 
 
19
 
20
  def encode_image(self, image_path: str) -> str:
21
+ """Encode image to base64 with validation"""
22
+ if not os.path.exists(image_path):
23
+ raise FileNotFoundError("File not found")
24
+ if not image_path.lower().endswith(('.png', '.jpg', '.jpeg')):
25
+ raise ValueError("Unsupported file format")
26
+
27
+ with open(image_path, "rb") as image_file:
28
+ return base64.b64encode(image_file.read()).decode('utf-8')
29
+
30
+ def extract_financial_data(self, analysis_text: str) -> Dict[str, Any]:
31
+ """Extract structured data from analysis text"""
32
+ data = {
33
+ 'current_price': None,
34
+ 'support_levels': [],
35
+ 'resistance_levels': [],
36
+ 'patterns': [],
37
+ 'timeframe': None
38
  }
39
 
40
+ # Price extraction
41
+ price_match = re.search(r'\$?(\d+\.?\d*)', analysis_text)
42
+ if price_match:
43
+ data['current_price'] = float(price_match.group(1))
 
 
 
44
 
45
+ # Timeframe detection
46
+ timeframe_match = re.search(r'(1[5m]|4h|1[WD]|1M|1Y)', analysis_text)
47
+ if timeframe_match:
48
+ data['timeframe'] = timeframe_match.group(0)
49
+
50
+ # Pattern detection
51
+ patterns = ['triangle', 'wedge', 'head and shoulders', 'flag', 'double top', 'double bottom']
52
+ data['patterns'] = [p for p in patterns if p in analysis_text.lower()]
 
 
 
 
53
 
54
+ # Level extraction
55
+ levels = re.findall(r'\$?(\d+\.?\d*)\s*(support|resistance)', analysis_text, re.IGNORECASE)
56
+ for value, level_type in levels:
57
+ if level_type.lower() == 'support':
58
+ data['support_levels'].append(float(value))
59
+ else:
60
+ data['resistance_levels'].append(float(value))
61
+
62
+ return data
63
+
64
+ def calculate_confidence(self, analysis_text: str) -> float:
65
+ """Dynamic confidence calculation"""
66
+ confidence_signals = {
67
+ 'clear pattern': 0.3,
68
+ 'strong volume': 0.2,
69
+ 'key level break': 0.25,
70
+ 'multiple indicators': 0.15,
71
+ 'market alignment': 0.1
72
+ }
73
+ return min(sum(
74
+ value for key, value in confidence_signals.items()
75
+ if key in analysis_text.lower()
76
+ ), 1.0)
77
 
78
+ def generate_annotations(self, img: np.ndarray, analysis: Dict) -> np.ndarray:
79
+ """Advanced chart annotations"""
80
+ h, w = img.shape[:2]
81
+ overlay = img.copy()
82
+
83
+ # Trend lines
84
+ cv2.line(overlay, (0, h//2), (w, h//3), (0,255,0), 2)
85
+ cv2.line(overlay, (0, h//2), (w, 2*h//3), (0,0,255), 2)
86
+
87
+ # Support/resistance zones
88
+ if analysis['support_levels']:
89
+ y_pos = int(h * 0.75)
90
+ cv2.rectangle(overlay, (0, y_pos), (w, y_pos+10), (0,255,0), -1)
91
+
92
+ if analysis['resistance_levels']:
93
+ y_pos = int(h * 0.25)
94
+ cv2.rectangle(overlay, (0, y_pos), (w, y_pos+10), (0,0,255), -1)
95
+
96
+ # Pattern highlights
97
+ if 'triangle' in analysis['patterns']:
98
+ pts = np.array([[w//4, h//2], [3*w//4, h//3], [3*w//4, 2*h//3]])
99
+ cv2.drawContours(overlay, [pts], -1, (255,255,0), 3)
100
+
101
+ # Confidence indicator
102
+ confidence = self.calculate_confidence(analysis['raw_text'])
103
+ cv2.rectangle(overlay, (w-150, 20), (w-50, 40), (50,50,50), -1)
104
+ cv2.rectangle(overlay, (w-150, 20),
105
+ (w-150 + int(100*confidence), 40),
106
+ (0,255,0), -1)
107
+
108
+ return cv2.addWeighted(overlay, 0.3, img, 0.7, 0)
109
+
110
+ def analyze_chart(self, image_path: str) -> Tuple[str, str]:
111
+ """Complete analysis pipeline"""
112
  try:
113
  # Image processing
114
  base64_image = self.encode_image(image_path)
115
  image_url = f"data:image/jpeg;base64,{base64_image}"
116
+
117
+ # AI Analysis
 
 
 
 
118
  response = openai.ChatCompletion.create(
119
  model=ANALYSIS_MODEL,
120
  messages=[
121
+ {"role": "system", "content": """Expert Crypto Chart Analysis:
122
+ - Identify exact price levels and timeframe from the chart
123
+ - Detect all technical patterns
124
+ - List key support/resistance levels
125
+ - Provide actionable trade ideas"""},
126
+ {"role": "user", "content": [
127
+ {"type": "text", "text": "Analyze this chart in detail"},
128
+ {"type": "image_url", "image_url": image_url}
129
+ ]}
130
  ],
131
  max_tokens=MAX_TOKENS
132
  )
 
 
133
 
134
+ raw_text = response.choices[0].message.content
135
+ analysis = self.extract_financial_data(raw_text)
136
+ analysis['raw_text'] = raw_text
 
137
 
138
+ # Image annotation
139
+ img = cv2.imread(image_path)
140
+ if img is not None:
141
+ img = cv2.resize(img, (1024, 512))
142
+ annotated_img = self.generate_annotations(img, analysis)
143
+ output_path = f"analyzed_{datetime.now().strftime('%Y%m%d%H%M%S')}.png"
144
+ cv2.imwrite(output_path, annotated_img)
145
+ else:
146
+ output_path = None
147
+
148
+ # Format results
149
+ formatted_output = f"""
150
+ ## πŸ“Š Comprehensive Analysis
151
+ **Current Price:** ${analysis['current_price']:.2f if analysis['current_price'] else 'N/A'}
152
+ **Timeframe:** {analysis['timeframe'] or 'Auto-detected'}
153
 
154
+ ### πŸ”‘ Key Levels
155
+ - Support: {', '.join(map(str, analysis['support_levels']))}
156
+ - Resistance: {', '.join(map(str, analysis['resistance_levels']))}
157
 
158
+ ### πŸŒ€ Detected Patterns
159
+ {', '.join(analysis['patterns']) or 'No clear patterns'}
 
160
 
161
+ ### πŸ“ Detailed Analysis
162
+ {raw_text}
163
+ """
164
 
165
+ return formatted_output, output_path
 
166
 
 
 
167
  except Exception as e:
168
+ return f"Analysis Error: {str(e)}", None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
169
 
170
+ # Gradio Interface
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
171
  analyzer = ChartAnalyzer()
172
 
173
+ with gr.Blocks(theme=gr.themes.Soft(primary_hue="emerald")) as demo:
174
+ gr.Markdown("# πŸ”₯ Instant Crypto Chart Analysis")
175
 
176
  with gr.Row():
177
  with gr.Column(scale=1):
178
+ chart_input = gr.Image(
179
+ type="filepath",
180
+ label="Upload Chart (PNG/JPG)",
181
+ sources=["upload"],
182
+ height=300
183
+ )
184
+ analyze_btn = gr.Button("Analyze Now", variant="primary")
185
 
186
  with gr.Column(scale=2):
187
+ with gr.Tabs():
188
+ with gr.TabItem("Full Analysis"):
189
+ analysis_output = gr.Markdown()
190
+ with gr.TabItem("Annotated Chart"):
191
+ chart_output = gr.Image(interactive=False)
192
+
193
  analyze_btn.click(
194
  fn=analyzer.analyze_chart,
195
+ inputs=chart_input,
196
+ outputs=[analysis_output, chart_output]
197
  )
198
 
 
199
  if __name__ == "__main__":
200
  demo.launch()