cryogenic22 commited on
Commit
212c449
·
verified ·
1 Parent(s): 96b4d51

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +283 -35
app.py CHANGED
@@ -100,62 +100,153 @@ def detect_chart_type(client, image_data):
100
  st.error(f"Error in chart type detection: {str(e)}")
101
  return "Other"
102
 
103
- def analyze_chart_with_claude(client, image_data, prompt, chart_type=None):
104
- """Analyze chart using Claude Vision"""
105
  try:
106
- encoded_image = base64.b64encode(image_data).decode('utf-8')
 
 
 
 
 
 
 
 
 
107
 
108
- # If chart type wasn't provided, detect it first
109
- if not chart_type:
110
- chart_type = detect_chart_type(client, image_data)
111
- st.info(f"Detected chart type: {chart_type}")
 
 
 
 
 
 
 
112
 
113
  message = client.messages.create(
114
  model="claude-3-opus-20240229",
115
  max_tokens=1000,
116
  messages=[{
117
  "role": "user",
118
- "content": [
119
- {
120
- "type": "text",
121
- "text": prompt.format(chart_type=chart_type)
122
- },
123
- {
124
- "type": "image",
125
- "source": {
126
- "type": "base64",
127
- "media_type": "image/jpeg",
128
- "data": encoded_image
129
- }
130
- }
131
- ]
132
  }]
133
  )
134
 
135
- return message.content[0].text, chart_type
136
  except Exception as e:
137
- st.error(f"Error in Claude analysis: {str(e)}")
138
- return None, None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
139
 
140
- def save_chat_history(chat_history, filename=None):
141
- """Saves chat history to a JSON file"""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
142
  if not os.path.exists("chat_histories"):
143
  os.makedirs("chat_histories")
 
 
144
 
145
- if filename is None:
146
- timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
147
- filename = f"chat_history_{timestamp}.json"
148
 
149
- filepath = os.path.join("chat_histories", filename)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
150
  with open(filepath, "w") as f:
151
- json.dump(chat_history, f)
152
- return filename
 
153
 
154
  def load_chat_history(filename):
155
- """Loads chat history from a JSON file"""
156
  filepath = os.path.join("chat_histories", filename)
157
  with open(filepath, "r") as f:
158
- return json.load(f)
 
 
 
 
 
 
 
 
 
 
159
 
160
  def main():
161
  st.set_page_config(
@@ -170,10 +261,167 @@ def main():
170
  st.error("Failed to initialize Anthropic client. Please check your API key configuration.")
171
  return
172
 
173
- # Initialize session state for chat history
174
  if 'chat_history' not in st.session_state:
175
  st.session_state.chat_history = []
 
 
 
 
 
 
 
176
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
177
  # Initialize variables
178
  uploaded_file = None
179
  screenshot_taken = False
 
100
  st.error(f"Error in chart type detection: {str(e)}")
101
  return "Other"
102
 
103
+ def continue_analysis_with_claude(client, question, previous_analysis, image_data=None):
104
+ """Continue the analysis based on a follow-up question"""
105
  try:
106
+ content = [
107
+ {
108
+ "type": "text",
109
+ "text": f"""Previous analysis: {previous_analysis}
110
+
111
+ User's follow-up question: {question}
112
+
113
+ Please provide a detailed answer to the follow-up question, maintaining the context of the previous analysis."""
114
+ }
115
+ ]
116
 
117
+ # Add image to the content if available
118
+ if image_data:
119
+ encoded_image = base64.b64encode(image_data).decode('utf-8')
120
+ content.append({
121
+ "type": "image",
122
+ "source": {
123
+ "type": "base64",
124
+ "media_type": "image/jpeg",
125
+ "data": encoded_image
126
+ }
127
+ })
128
 
129
  message = client.messages.create(
130
  model="claude-3-opus-20240229",
131
  max_tokens=1000,
132
  messages=[{
133
  "role": "user",
134
+ "content": content
 
 
 
 
 
 
 
 
 
 
 
 
 
135
  }]
136
  )
137
 
138
+ return message.content[0].text
139
  except Exception as e:
140
+ st.error(f"Error in follow-up analysis: {str(e)}")
141
+ return None
142
+
143
+ def get_trading_education(client, concept):
144
+ """Get educational content about trading concepts"""
145
+ try:
146
+ message = client.messages.create(
147
+ model="claude-3-opus-20240229",
148
+ max_tokens=1000,
149
+ messages=[{
150
+ "role": "user",
151
+ "content": f"""Please explain the trading concept '{concept}' in a clear, educational way. Structure your response as follows:
152
+
153
+ 1. Basic Definition
154
+ 2. How it Works
155
+ 3. Key Characteristics
156
+ 4. When to Look for It
157
+ 5. Trading Implications
158
+ 6. Common Mistakes to Avoid
159
+ 7. Real-World Example
160
 
161
+ If relevant, describe what a typical chart pattern for this concept looks like.
162
+ Include any important formulas or calculations if applicable.
163
+
164
+ Please make this explanation suitable for beginners while also including enough depth for intermediate traders."""
165
+ }]
166
+ )
167
+
168
+ return message.content[0].text
169
+ except Exception as e:
170
+ st.error(f"Error in getting educational content: {str(e)}")
171
+ return None
172
+
173
+ def extract_stock_info(analysis_text):
174
+ """Extract stock name and other metadata from analysis text"""
175
+ # This is a simple implementation - can be made more sophisticated
176
+ stock_name = "Unknown"
177
+ try:
178
+ # Look for common stock name patterns
179
+ if "analyzing" in analysis_text.lower():
180
+ words = analysis_text.split()
181
+ for i, word in enumerate(words):
182
+ if word.lower() == "analyzing":
183
+ stock_name = words[i + 1].strip("(),.:")
184
+ except:
185
+ pass
186
+ return stock_name
187
+
188
+ def save_chat_history(chat_history, image_data=None, filename=None):
189
+ """Saves chat history and associated image to JSON and image files"""
190
  if not os.path.exists("chat_histories"):
191
  os.makedirs("chat_histories")
192
+ if not os.path.exists("chat_images"):
193
+ os.makedirs("chat_images")
194
 
195
+ timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
 
 
196
 
197
+ # Get the stock name from the latest analysis
198
+ stock_name = "Unknown"
199
+ if chat_history:
200
+ latest_analysis = chat_history[-1]['analysis']
201
+ stock_name = extract_stock_info(latest_analysis)
202
+
203
+ # Create filename with metadata
204
+ if filename:
205
+ base_filename = filename
206
+ else:
207
+ base_filename = f"{stock_name}_{timestamp}"
208
+
209
+ # Save image if provided
210
+ image_filename = None
211
+ if image_data:
212
+ image_filename = f"{base_filename}.jpg"
213
+ image_path = os.path.join("chat_images", image_filename)
214
+ with open(image_path, "wb") as f:
215
+ f.write(image_data)
216
+
217
+ # Add metadata to chat history
218
+ chat_data = {
219
+ 'metadata': {
220
+ 'stock_name': stock_name,
221
+ 'date_created': timestamp,
222
+ 'image_file': image_filename
223
+ },
224
+ 'conversations': chat_history
225
+ }
226
+
227
+ # Save chat history
228
+ json_filename = f"{base_filename}.json"
229
+ filepath = os.path.join("chat_histories", json_filename)
230
  with open(filepath, "w") as f:
231
+ json.dump(chat_data, f)
232
+
233
+ return json_filename
234
 
235
  def load_chat_history(filename):
236
+ """Loads chat history and associated image"""
237
  filepath = os.path.join("chat_histories", filename)
238
  with open(filepath, "r") as f:
239
+ chat_data = json.load(f)
240
+
241
+ # Load associated image if it exists
242
+ image_data = None
243
+ if chat_data.get('metadata', {}).get('image_file'):
244
+ image_path = os.path.join("chat_images", chat_data['metadata']['image_file'])
245
+ if os.path.exists(image_path):
246
+ with open(image_path, "rb") as f:
247
+ image_data = f.read()
248
+
249
+ return chat_data, image_data
250
 
251
  def main():
252
  st.set_page_config(
 
261
  st.error("Failed to initialize Anthropic client. Please check your API key configuration.")
262
  return
263
 
264
+ # Initialize session state
265
  if 'chat_history' not in st.session_state:
266
  st.session_state.chat_history = []
267
+ if 'current_image' not in st.session_state:
268
+ st.session_state.current_image = None
269
+ if 'current_analysis' not in st.session_state:
270
+ st.session_state.current_analysis = None
271
+
272
+ # Tab selection
273
+ tab1, tab2 = st.tabs(["Chart Analysis", "Learn Trading"])
274
 
275
+ with tab1:
276
+ # Initialize variables
277
+ uploaded_file = None
278
+ screenshot_taken = False
279
+
280
+ # Sidebar
281
+ with st.sidebar:
282
+ st.title("🚀 Chart Analysis AI")
283
+ upload_option = st.radio(
284
+ "Choose input method:",
285
+ ("Upload Image", "Take Screenshot", "Ask Question")
286
+ )
287
+
288
+ # File uploader
289
+ if upload_option == "Upload Image":
290
+ uploaded_file = st.file_uploader("Upload your chart", type=["png", "jpg", "jpeg"])
291
+ if uploaded_file:
292
+ st.session_state.current_image = uploaded_file.getvalue()
293
+ elif upload_option == "Take Screenshot":
294
+ if st.button("Take Screenshot", key="screenshot"):
295
+ st.info("Feature coming soon! For now, please use the Upload Image option.")
296
+ screenshot_taken = False
297
+
298
+ # Analysis Options
299
+ st.subheader("Analysis Options")
300
+ patterns = st.multiselect(
301
+ "Patterns to Look For",
302
+ ["Double Top/Bottom", "Head and Shoulders", "Triangle",
303
+ "Flag", "Wedge", "Channel", "Support/Resistance"]
304
+ )
305
+
306
+ indicators = st.multiselect(
307
+ "Technical Indicators",
308
+ ["Moving Averages", "RSI", "MACD", "Bollinger Bands",
309
+ "Volume", "Stochastic", "ADX"]
310
+ )
311
+
312
+ # Main content area
313
+ st.title("📈 Stock Chart Analysis Assistant")
314
+
315
+ # Create two columns for layout
316
+ col1, col2 = st.columns([2, 1])
317
+
318
+ with col1:
319
+ if upload_option == "Ask Question":
320
+ user_question = st.text_input("What would you like to know about your chart?")
321
+
322
+ # Display uploaded image
323
+ if uploaded_file is not None:
324
+ st.image(uploaded_file, caption="Uploaded Chart", use_container_width=True)
325
+
326
+ # Continue chat section
327
+ if st.session_state.current_analysis:
328
+ st.subheader("Continue Analysis")
329
+ follow_up = st.text_input("Ask a follow-up question about this chart:")
330
+ if st.button("Send Follow-up"):
331
+ if follow_up:
332
+ with st.spinner("Analyzing..."):
333
+ follow_up_response = continue_analysis_with_claude(
334
+ client,
335
+ follow_up,
336
+ st.session_state.current_analysis,
337
+ st.session_state.current_image
338
+ )
339
+ if follow_up_response:
340
+ st.write(follow_up_response)
341
+ # Add to chat history
342
+ st.session_state.chat_history.append({
343
+ 'timestamp': datetime.now().isoformat(),
344
+ 'question': follow_up,
345
+ 'analysis': follow_up_response
346
+ })
347
+
348
+ if st.button("Analyze"):
349
+ if upload_option == "Ask Question" and user_question:
350
+ st.info("Question-based analysis feature coming soon!")
351
+ elif uploaded_file is None and not screenshot_taken:
352
+ st.warning("Please upload an image or take a screenshot first.")
353
+ else:
354
+ with st.spinner("Analyzing chart..."):
355
+ # Generate prompt
356
+ prompt = create_prompt_template(patterns, indicators)
357
+
358
+ if uploaded_file:
359
+ # Process image and get analysis
360
+ analysis_result, chart_type = analyze_chart_with_claude(
361
+ client,
362
+ uploaded_file.getvalue(),
363
+ prompt
364
+ )
365
+
366
+ if analysis_result:
367
+ # Store current analysis
368
+ st.session_state.current_analysis = analysis_result
369
+
370
+ # Add to chat history
371
+ st.session_state.chat_history.append({
372
+ 'timestamp': datetime.now().isoformat(),
373
+ 'chart_type': chart_type,
374
+ 'analysis': analysis_result
375
+ })
376
+
377
+ # Display analysis
378
+ st.subheader("Analysis Results")
379
+ st.write(analysis_result)
380
+
381
+ # Risk warning
382
+ st.warning(
383
+ "⚠️ This analysis is AI-generated and for informational purposes only. "
384
+ "Do not make trading decisions solely based on this information."
385
+ )
386
+
387
+ with col2:
388
+ st.subheader("Chat History")
389
+
390
+ # Display chat history
391
+ for chat in st.session_state.chat_history:
392
+ timestamp = datetime.fromisoformat(chat['timestamp']).strftime("%Y-%m-%d %H:%M")
393
+ with st.expander(f"Analysis from {timestamp}"):
394
+ st.write(chat['analysis'])
395
+ if 'question' in chat:
396
+ st.write(f"Follow-up: {chat['question']}")
397
+
398
+ # Save chat options
399
+ save_name = st.text_input("Save chat as (optional):")
400
+ if st.button("Save Chat"):
401
+ if st.session_state.chat_history:
402
+ filename = save_chat_history(
403
+ st.session_state.chat_history,
404
+ st.session_state.current_image,
405
+ f"{save_name}.json" if save_name else None
406
+ )
407
+ st.success(f"Chat saved as {filename}")
408
+ else:
409
+ st.warning("No chat history to save.")
410
+
411
+ with tab2:
412
+ st.title("📚 Learn Trading")
413
+
414
+ # Search or select trading concept
415
+ concept = st.text_input("Enter a trading concept you'd like to learn about (e.g., 'evening star pattern', 'RSI', 'MACD'):")
416
+ if st.button("Learn"):
417
+ if concept:
418
+ with st.spinner("Getting educational content..."):
419
+ education_content = get_trading_education(client, concept)
420
+ if education_content:
421
+ st.markdown(education_content)
422
+
423
+ if __name__ == "__main__":
424
+ main()
425
  # Initialize variables
426
  uploaded_file = None
427
  screenshot_taken = False