aidevhund commited on
Commit
44bb60b
·
verified ·
1 Parent(s): 212b5f4

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +36 -193
app.py CHANGED
@@ -1,21 +1,30 @@
1
  import gradio as gr
2
  import openai
3
  import os
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"""
@@ -23,147 +32,31 @@ class ChartAnalyzer:
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
- # Improved price extraction with currency symbols
41
- price_match = re.search(r'(?:\$|€|£)?(\d+\.?\d*)', analysis_text)
42
- if price_match:
43
- try:
44
- data['current_price'] = float(price_match.group(1))
45
- except ValueError:
46
- pass
47
-
48
- # Enhanced timeframe detection
49
- timeframe_pattern = r'(?:timeframe|period|chart)\s*(?:is|shows|of)\s*([1-9][0-9]*[mhDWMY])'
50
- timeframe_match = re.search(timeframe_pattern, analysis_text, re.IGNORECASE)
51
- if timeframe_match:
52
- data['timeframe'] = timeframe_match.group(1)
53
-
54
- # Pattern detection with variations
55
- patterns = {
56
- 'triangle': r'triangle|symmetrical|ascending|descending',
57
- 'wedge': r'wedge|rising wedge|falling wedge',
58
- 'head and shoulders': r'head\s*and\s*shoulders|H&S',
59
- 'flag': r'flag|bull flag|bear flag',
60
- 'double top': r'double top|M pattern',
61
- 'double bottom': r'double bottom|W pattern'
62
- }
63
-
64
- for pattern_name, pattern_regex in patterns.items():
65
- if re.search(pattern_regex, analysis_text, re.IGNORECASE):
66
- data['patterns'].append(pattern_name)
67
-
68
- # Level extraction with multiple formats
69
- level_pattern = r'(support|resistance)\s*(?:at|level:?)\s*\$?(\d+\.?\d*)'
70
- levels = re.findall(level_pattern, analysis_text, re.IGNORECASE)
71
- for level_type, value in levels:
72
- try:
73
- numeric_value = float(value)
74
- if level_type.lower() == 'support':
75
- data['support_levels'].append(numeric_value)
76
- else:
77
- data['resistance_levels'].append(numeric_value)
78
- except ValueError:
79
- pass
80
-
81
- return data
82
-
83
- def calculate_confidence(self, analysis_text: str) -> float:
84
- """Dynamic confidence calculation"""
85
- confidence_signals = {
86
- r'\bclear pattern\b': 0.3,
87
- r'\bstrong volume\b': 0.2,
88
- r'\bkey level (break|test)\b': 0.25,
89
- r'\bmultiple indicators\b': 0.15,
90
- r'\balignment with\b': 0.1
91
- }
92
-
93
- confidence = 0.0
94
- for pattern, value in confidence_signals.items():
95
- if re.search(pattern, analysis_text, re.IGNORECASE):
96
- confidence += value
97
-
98
- return min(max(confidence, 0.0), 1.0)
99
-
100
- def generate_annotations(self, img: np.ndarray, analysis: Dict) -> np.ndarray:
101
- """Advanced chart annotations"""
102
- h, w = img.shape[:2]
103
- overlay = img.copy()
104
-
105
- # Dynamic trend lines based on patterns
106
- if any(p in analysis['patterns'] for p in ['triangle', 'wedge']):
107
- cv2.line(overlay, (w//4, h//4), (3*w//4, 3*h//4), (0,255,255), 2)
108
-
109
- # Support/resistance zones with labels
110
- for i, level in enumerate(analysis['support_levels']):
111
- y_pos = int(h * 0.85 - i*20)
112
- cv2.line(overlay, (0, y_pos), (w, y_pos), (0,255,0), 2)
113
- cv2.putText(overlay, f"S: {level}", (10, y_pos-5),
114
- cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0,255,0), 1)
115
-
116
- for i, level in enumerate(analysis['resistance_levels']):
117
- y_pos = int(h * 0.15 + i*20)
118
- cv2.line(overlay, (0, y_pos), (w, y_pos), (0,0,255), 2)
119
- cv2.putText(overlay, f"R: {level}", (10, y_pos+15),
120
- cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0,0,255), 1)
121
-
122
- # Confidence meter with percentage
123
- confidence = self.calculate_confidence(analysis['raw_text'])
124
- cv2.rectangle(overlay, (w-150, 20), (w-50, 40), (50,50,50), -1)
125
- cv2.rectangle(overlay, (w-150, 20),
126
- (w-150 + int(100*confidence), 40),
127
- (0,255,0), -1)
128
- cv2.putText(overlay, f"{confidence*100:.0f}%", (w-140, 35),
129
- cv2.FONT_HERSHEY_SIMPLEX, 0.6, (255,255,255), 1)
130
-
131
- return cv2.addWeighted(overlay, 0.3, img, 0.7, 0)
132
-
133
- def analyze_chart(self, image_path: str) -> Tuple[str, str]:
134
- """Complete analysis pipeline"""
135
  try:
136
- # Validate image first
137
- if not os.path.exists(image_path):
138
- raise ValueError("Image file not found")
139
-
140
- if os.path.getsize(image_path) > 5*1024*1024: # 5MB limit
141
- raise ValueError("Image size exceeds 5MB limit")
142
-
143
- # Image processing
144
  base64_image = self.encode_image(image_path)
145
- image_url = f"data:image/jpeg;base64,{base64_image}"
146
 
147
- # AI Analysis
148
  response = openai.ChatCompletion.create(
149
  model=ANALYSIS_MODEL,
150
  messages=[
151
  {
152
  "role": "system",
153
- "content": """Expert Crypto Chart Analysis Protocol:
154
- 1. Identify exact numerical price levels (e.g., $32,500.75)
155
- 2. Detect chart timeframe from axis/price action
156
- 3. List all technical patterns with confidence
157
- 4. Analyze volume and momentum indicators
158
- 5. Provide specific trade entry/exit levels"""
159
  },
160
  {
161
  "role": "user",
162
  "content": [
163
- {"type": "text", "text": "Perform full technical analysis:"},
164
  {
165
  "type": "image_url",
166
- "image_url": {"url": image_url}
167
  }
168
  ]
169
  }
@@ -171,65 +64,19 @@ class ChartAnalyzer:
171
  max_tokens=MAX_TOKENS
172
  )
173
 
174
- raw_text = response.choices[0].message.content
175
- analysis = self.extract_financial_data(raw_text)
176
- analysis['raw_text'] = raw_text
177
-
178
- # Image annotation
179
- img = cv2.imread(image_path)
180
- if img is not None:
181
- img = cv2.resize(img, (1024, 512))
182
- annotated_img = self.generate_annotations(img, analysis)
183
- output_path = f"analyzed_{datetime.now().strftime('%Y%m%d%H%M%S')}.png"
184
- cv2.imwrite(output_path, annotated_img)
185
- else:
186
- output_path = None
187
-
188
- # Safe formatting
189
- current_price_str = (
190
- f"{analysis['current_price']:.2f}"
191
- if analysis['current_price'] is not None
192
- else "N/A"
193
- )
194
 
195
- support_levels = (
196
- ', '.join(map(lambda x: f"{x:.2f}", analysis['support_levels']))
197
- or "None"
198
- )
199
-
200
- resistance_levels = (
201
- ', '.join(map(lambda x: f"{x:.2f}", analysis['resistance_levels']))
202
- or "None"
203
- )
204
-
205
- formatted_output = f"""
206
- ## 📊 Comprehensive Analysis
207
- **Current Price:** ${current_price_str}
208
- **Timeframe:** {analysis['timeframe'] or 'Auto-detected'}
209
-
210
- ### 🔑 Key Levels
211
- - Support: {support_levels}
212
- - Resistance: {resistance_levels}
213
-
214
- ### 🌀 Detected Patterns
215
- {', '.join(analysis['patterns']).title() or 'No clear patterns detected'}
216
-
217
- ### 📝 Detailed Analysis
218
- {raw_text}
219
- """
220
-
221
- return formatted_output, output_path
222
-
223
- except openai.error.InvalidRequestError as e:
224
- return f"API Error: {str(e)}", None
225
  except Exception as e:
226
- return f"Analysis Error: {str(e)}", None
227
 
228
  # Gradio Interface
229
  analyzer = ChartAnalyzer()
230
 
231
- with gr.Blocks(theme=gr.themes.Soft(primary_hue="emerald")) as demo:
232
- gr.Markdown("# 🔥 Pro Crypto Chart Analyzer")
233
 
234
  with gr.Row():
235
  with gr.Column(scale=1):
@@ -237,24 +84,20 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="emerald")) as demo:
237
  type="filepath",
238
  label="Upload Chart (PNG/JPG)",
239
  sources=["upload"],
240
- height=300
241
  )
242
- analyze_btn = gr.Button("Analyze Now", variant="primary")
243
 
244
  with gr.Column(scale=2):
245
- with gr.Tabs():
246
- with gr.TabItem("Technical Report"):
247
- analysis_output = gr.Markdown()
248
- with gr.TabItem("Annotated Chart"):
249
- chart_output = gr.Image(
250
- label="Pattern Recognition",
251
- interactive=False
252
- )
253
 
254
  analyze_btn.click(
255
  fn=analyzer.analyze_chart,
256
  inputs=chart_input,
257
- outputs=[analysis_output, chart_output]
258
  )
259
 
260
  if __name__ == "__main__":
 
1
  import gradio as gr
2
  import openai
3
  import os
 
 
4
  import base64
5
+ from typing import Tuple
 
 
6
 
7
  # OpenAI API Configuration
8
  openai.api_key = os.getenv("OPENAI_API_KEY")
9
  ANALYSIS_MODEL = "gpt-4o"
10
  MAX_TOKENS = 4096
11
 
12
+ # System Prompt Configuration
13
+ SYSTEM_PROMPT = """Professional Crypto Technical Analyst:
14
+ 1. Identify all technical patterns in the chart
15
+ 2. Determine key support/resistance levels
16
+ 3. Analyze volume and momentum indicators
17
+ 4. Calculate risk/reward ratios
18
+ 5. Provide clear trading recommendations
19
+ 6. Include specific price targets
20
+ 7. Assess market sentiment
21
+ 8. Evaluate trend strength
22
+ 9. Identify potential breakout/breakdown levels
23
+ 10. Provide time-based projections"""
24
+
25
  class ChartAnalyzer:
26
  def __init__(self):
27
+ self.last_analysis = ""
28
 
29
  def encode_image(self, image_path: str) -> str:
30
  """Encode image to base64 with validation"""
 
32
  raise FileNotFoundError("File not found")
33
  if not image_path.lower().endswith(('.png', '.jpg', '.jpeg')):
34
  raise ValueError("Unsupported file format")
35
+ if os.path.getsize(image_path) > 5 * 1024 * 1024:
36
+ raise ValueError("Maximum file size is 5MB")
37
 
38
  with open(image_path, "rb") as image_file:
39
  return base64.b64encode(image_file.read()).decode('utf-8')
40
 
41
+ def analyze_chart(self, image_path: str) -> str:
42
+ """Core analysis function"""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
43
  try:
 
 
 
 
 
 
 
 
44
  base64_image = self.encode_image(image_path)
 
45
 
 
46
  response = openai.ChatCompletion.create(
47
  model=ANALYSIS_MODEL,
48
  messages=[
49
  {
50
  "role": "system",
51
+ "content": SYSTEM_PROMPT
 
 
 
 
 
52
  },
53
  {
54
  "role": "user",
55
  "content": [
56
+ {"type": "text", "text": "Perform detailed technical analysis of this chart:"},
57
  {
58
  "type": "image_url",
59
+ "image_url": {"url": f"data:image/jpeg;base64,{base64_image}"}
60
  }
61
  ]
62
  }
 
64
  max_tokens=MAX_TOKENS
65
  )
66
 
67
+ self.last_analysis = response.choices[0].message.content
68
+ return self.last_analysis
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
69
 
70
+ except openai.error.APIError as e:
71
+ return f"OpenAI API Error: {str(e)}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
72
  except Exception as e:
73
+ return f"Analysis Error: {str(e)}"
74
 
75
  # Gradio Interface
76
  analyzer = ChartAnalyzer()
77
 
78
+ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue")) as demo:
79
+ gr.Markdown("# 🚀 Advanced Crypto Analysis System")
80
 
81
  with gr.Row():
82
  with gr.Column(scale=1):
 
84
  type="filepath",
85
  label="Upload Chart (PNG/JPG)",
86
  sources=["upload"],
87
+ height=200
88
  )
89
+ analyze_btn = gr.Button("Start Analysis", variant="primary")
90
 
91
  with gr.Column(scale=2):
92
+ analysis_output = gr.Markdown(
93
+ label="Professional Analysis Report",
94
+ elem_classes=["analysis-box"]
95
+ )
 
 
 
 
96
 
97
  analyze_btn.click(
98
  fn=analyzer.analyze_chart,
99
  inputs=chart_input,
100
+ outputs=analysis_output
101
  )
102
 
103
  if __name__ == "__main__":