cryogenic22 commited on
Commit
e235220
·
verified ·
1 Parent(s): 1a4a9b5

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +83 -540
app.py CHANGED
@@ -1,289 +1,25 @@
1
- import streamlit as st
2
- import base64
3
- from datetime import datetime
4
- import json
5
- import os
6
- from anthropic import Anthropic
7
- from PIL import Image
8
- import io
9
- import yaml
10
-
11
- def load_anthropic_key():
12
- """Load Anthropic API key from environment variables"""
13
- try:
14
- api_key = os.getenv('ANTHROPIC_API_KEY')
15
- if not api_key:
16
- st.error("Anthropic API key not found. Please set ANTHROPIC_API_KEY in your environment variables.")
17
- return None
18
- return api_key
19
- except Exception as e:
20
- st.error(f"Error loading Anthropic API key: {str(e)}")
21
- return None
22
-
23
- def initialize_anthropic_client():
24
- """Initialize Anthropic client with API key"""
25
- api_key = load_anthropic_key()
26
- if api_key:
27
- return Anthropic(api_key=api_key)
28
- return None
29
-
30
- def create_prompt_template(patterns, indicators):
31
- """Creates a structured prompt for the LLM based on the chart and analysis needs"""
32
- prompt = """You are an expert financial analyst. Please analyze this financial chart (chart type will be detected automatically) and provide insights in the following structured format:
33
-
34
- 1. VISUAL ANALYSIS
35
- - First identify the type of chart (candlestick, line, OHLC, area, etc.)
36
- - Identify and describe the main trend
37
- - Note key price levels visible in the chart
38
- - Describe any significant patterns: {patterns}
39
- - Comment on volume trends if visible
40
- - Analyze these technical indicators: {indicators}
41
-
42
- 2. TECHNICAL INTERPRETATION
43
- - Current market structure and trend strength
44
- - Key support and resistance levels with price points
45
- - Any visible divergences or convergences
46
- - Pattern reliability assessment
47
-
48
- 3. RISK ANALYSIS
49
- - Potential risk levels
50
- - Risk/reward scenarios
51
- - Warning signs or red flags
52
- - Market context considerations
53
-
54
- 4. ACTIONABLE INSIGHTS
55
- - Potential trading scenarios
56
- - Key price targets
57
- - Suggested stop-loss levels
58
- - Timeframe considerations
59
-
60
- 5. SIMPLIFIED EXPLANATION
61
- Provide a 2-3 sentence summary in simple terms for novice traders.
62
-
63
- IMPORTANT: Clearly mark this as AI-generated analysis for informational purposes only.
64
- """
65
- return prompt.format(
66
- patterns=', '.join(patterns) if patterns else 'all visible patterns',
67
- indicators=', '.join(indicators) if indicators else 'visible indicators'
68
- )
69
-
70
- def detect_chart_type(client, image_data):
71
- """Detect chart type using Claude Vision"""
72
- try:
73
- encoded_image = base64.b64encode(image_data).decode('utf-8')
74
-
75
- message = client.messages.create(
76
- model="claude-3-opus-20240229",
77
- max_tokens=50,
78
- messages=[{
79
- "role": "user",
80
- "content": [
81
- {
82
- "type": "text",
83
- "text": "What type of financial chart is this? Choose from: Candlestick, Line, OHLC, Area, or Other. Just respond with one word."
84
- },
85
- {
86
- "type": "image",
87
- "source": {
88
- "type": "base64",
89
- "media_type": "image/jpeg",
90
- "data": encoded_image
91
- }
92
- }
93
- ]
94
- }]
95
- )
96
-
97
- chart_type = message.content[0].text.strip()
98
- return chart_type
99
- except Exception as e:
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 continue_analysis_with_claude(client, question, previous_analysis, image_data=None):
141
- """Continue the analysis based on a follow-up question"""
142
- try:
143
- content = [
144
- {
145
- "type": "text",
146
- "text": f"""Previous analysis: {previous_analysis}
147
-
148
- User's follow-up question: {question}
149
-
150
- Please provide a detailed answer to the follow-up question, maintaining the context of the previous analysis."""
151
- }
152
- ]
153
-
154
- # Add image to the content if available
155
- if image_data:
156
- encoded_image = base64.b64encode(image_data).decode('utf-8')
157
- content.append({
158
- "type": "image",
159
- "source": {
160
- "type": "base64",
161
- "media_type": "image/jpeg",
162
- "data": encoded_image
163
- }
164
- })
165
-
166
- message = client.messages.create(
167
- model="claude-3-opus-20240229",
168
- max_tokens=1000,
169
- messages=[{
170
- "role": "user",
171
- "content": content
172
- }]
173
- )
174
-
175
- return message.content[0].text
176
- except Exception as e:
177
- st.error(f"Error in follow-up analysis: {str(e)}")
178
- return None
179
-
180
- def get_trading_education(client, concept):
181
- """Get educational content about trading concepts"""
182
- try:
183
- message = client.messages.create(
184
- model="claude-3-opus-20240229",
185
- max_tokens=1000,
186
- messages=[{
187
- "role": "user",
188
- "content": f"""Please explain the trading concept '{concept}' in a clear, educational way. Structure your response as follows:
189
-
190
- 1. Basic Definition
191
- 2. How it Works
192
- 3. Key Characteristics
193
- 4. When to Look for It
194
- 5. Trading Implications
195
- 6. Common Mistakes to Avoid
196
- 7. Real-World Example
197
-
198
- If relevant, describe what a typical chart pattern for this concept looks like.
199
- Include any important formulas or calculations if applicable.
200
-
201
- Please make this explanation suitable for beginners while also including enough depth for intermediate traders."""
202
- }]
203
- )
204
-
205
- return message.content[0].text
206
- except Exception as e:
207
- st.error(f"Error in getting educational content: {str(e)}")
208
- return None
209
-
210
- def extract_stock_info(analysis_text):
211
- """Extract stock name and other metadata from analysis text"""
212
- # This is a simple implementation - can be made more sophisticated
213
- stock_name = "Unknown"
214
- try:
215
- # Look for common stock name patterns
216
- if "analyzing" in analysis_text.lower():
217
- words = analysis_text.split()
218
- for i, word in enumerate(words):
219
- if word.lower() == "analyzing":
220
- stock_name = words[i + 1].strip("(),.:")
221
- except:
222
- pass
223
- return stock_name
224
-
225
- def save_chat_history(chat_history, image_data=None, filename=None):
226
- """Saves chat history and associated image to JSON and image files"""
227
- if not os.path.exists("chat_histories"):
228
- os.makedirs("chat_histories")
229
- if not os.path.exists("chat_images"):
230
- os.makedirs("chat_images")
231
-
232
- timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
233
-
234
- # Get the stock name from the latest analysis
235
- stock_name = "Unknown"
236
- if chat_history:
237
- latest_analysis = chat_history[-1]['analysis']
238
- stock_name = extract_stock_info(latest_analysis)
239
-
240
- # Create filename with metadata
241
- if filename:
242
- base_filename = filename
243
- else:
244
- base_filename = f"{stock_name}_{timestamp}"
245
-
246
- # Save image if provided
247
- image_filename = None
248
- if image_data:
249
- image_filename = f"{base_filename}.jpg"
250
- image_path = os.path.join("chat_images", image_filename)
251
- with open(image_path, "wb") as f:
252
- f.write(image_data)
253
-
254
- # Add metadata to chat history
255
- chat_data = {
256
- 'metadata': {
257
- 'stock_name': stock_name,
258
- 'date_created': timestamp,
259
- 'image_file': image_filename
260
- },
261
- 'conversations': chat_history
262
- }
263
-
264
- # Save chat history
265
- json_filename = f"{base_filename}.json"
266
- filepath = os.path.join("chat_histories", json_filename)
267
- with open(filepath, "w") as f:
268
- json.dump(chat_data, f)
269
-
270
- return json_filename
271
-
272
- def load_chat_history(filename):
273
- """Loads chat history and associated image"""
274
- filepath = os.path.join("chat_histories", filename)
275
- with open(filepath, "r") as f:
276
- chat_data = json.load(f)
277
-
278
- # Load associated image if it exists
279
- image_data = None
280
- if chat_data.get('metadata', {}).get('image_file'):
281
- image_path = os.path.join("chat_images", chat_data['metadata']['image_file'])
282
- if os.path.exists(image_path):
283
- with open(image_path, "rb") as f:
284
- image_data = f.read()
285
-
286
- return chat_data, image_data
287
 
288
  def main():
289
  st.set_page_config(
@@ -292,279 +28,86 @@ def main():
292
  initial_sidebar_state="expanded"
293
  )
294
 
295
- # Initialize Anthropic client
296
- client = initialize_anthropic_client()
297
- if not client:
298
- st.error("Failed to initialize Anthropic client. Please check your API key configuration.")
 
 
299
  return
300
 
301
  # Initialize session state
302
- if 'chat_history' not in st.session_state:
303
- st.session_state.chat_history = []
304
- if 'current_image' not in st.session_state:
305
- st.session_state.current_image = None
306
- if 'current_analysis' not in st.session_state:
307
- st.session_state.current_analysis = None
308
-
309
- # Tab selection
310
- tab1, tab2 = st.tabs(["Chart Analysis", "Learn Trading"])
311
 
312
- with tab1:
313
- # Initialize variables
314
- uploaded_file = None
315
- screenshot_taken = False
316
-
317
- # Sidebar
318
- with st.sidebar:
319
- st.title("🚀 Chart Analysis AI")
320
- upload_option = st.radio(
321
- "Choose input method:",
322
- ("Upload Image", "Take Screenshot", "Ask Question"),
323
- key="analysis_upload_option" # Added unique key
324
- )
325
-
326
- # File uploader
327
- if upload_option == "Upload Image":
328
- uploaded_file = st.file_uploader("Upload your chart", type=["png", "jpg", "jpeg"], key="analysis_file_uploader")
329
- if uploaded_file:
330
- st.session_state.current_image = uploaded_file.getvalue()
331
- elif upload_option == "Take Screenshot":
332
- if st.button("Take Screenshot", key="analysis_screenshot_button"):
333
- st.info("Feature coming soon! For now, please use the Upload Image option.")
334
- screenshot_taken = False
335
-
336
- # Analysis Options
337
- st.subheader("Analysis Options")
338
- patterns = st.multiselect(
339
- "Patterns to Look For",
340
- ["Double Top/Bottom", "Head and Shoulders", "Triangle",
341
- "Flag", "Wedge", "Channel", "Support/Resistance"],
342
- key="analysis_patterns"
343
- )
344
-
345
- indicators = st.multiselect(
346
- "Technical Indicators",
347
- ["Moving Averages", "RSI", "MACD", "Bollinger Bands",
348
- "Volume", "Stochastic", "ADX"],
349
- key="analysis_indicators"
350
- )
351
-
352
- # Main content area
353
- st.title("📈 Stock Chart Analysis Assistant")
354
-
355
- # Create two columns for layout
356
- col1, col2 = st.columns([2, 1])
357
-
358
- with col1:
359
- if upload_option == "Ask Question":
360
- user_question = st.text_input("What would you like to know about your chart?")
361
-
362
- # Display uploaded image
363
- if uploaded_file is not None:
364
- st.image(uploaded_file, caption="Uploaded Chart", use_container_width=True)
365
-
366
- # Continue chat section
367
- if st.session_state.current_analysis:
368
- st.subheader("Continue Analysis")
369
- follow_up = st.text_input("Ask a follow-up question about this chart:")
370
- if st.button("Send Follow-up"):
371
- if follow_up:
372
- with st.spinner("Analyzing..."):
373
- follow_up_response = continue_analysis_with_claude(
374
- client,
375
- follow_up,
376
- st.session_state.current_analysis,
377
- st.session_state.current_image
378
- )
379
- if follow_up_response:
380
- st.write(follow_up_response)
381
- # Add to chat history
382
- st.session_state.chat_history.append({
383
- 'timestamp': datetime.now().isoformat(),
384
- 'question': follow_up,
385
- 'analysis': follow_up_response
386
- })
387
-
388
- if st.button("Analyze"):
389
- if upload_option == "Ask Question" and user_question:
390
- st.info("Question-based analysis feature coming soon!")
391
- elif uploaded_file is None and not screenshot_taken:
392
- st.warning("Please upload an image or take a screenshot first.")
393
- else:
394
- with st.spinner("Analyzing chart..."):
395
- # Generate prompt
396
- prompt = create_prompt_template(patterns, indicators)
397
-
398
- if uploaded_file:
399
- # Process image and get analysis
400
- analysis_result, chart_type = analyze_chart_with_claude(
401
- client,
402
- uploaded_file.getvalue(),
403
- prompt
404
- )
405
-
406
- if analysis_result:
407
- # Store current analysis
408
- st.session_state.current_analysis = analysis_result
409
-
410
- # Add to chat history
411
- st.session_state.chat_history.append({
412
- 'timestamp': datetime.now().isoformat(),
413
- 'chart_type': chart_type,
414
- 'analysis': analysis_result
415
- })
416
-
417
- # Display analysis
418
- st.subheader("Analysis Results")
419
- st.write(analysis_result)
420
-
421
- # Risk warning
422
- st.warning(
423
- "⚠️ This analysis is AI-generated and for informational purposes only. "
424
- "Do not make trading decisions solely based on this information."
425
- )
426
-
427
- with col2:
428
- st.subheader("Chat History")
429
-
430
- # Display chat history
431
- for chat in st.session_state.chat_history:
432
- timestamp = datetime.fromisoformat(chat['timestamp']).strftime("%Y-%m-%d %H:%M")
433
- with st.expander(f"Analysis from {timestamp}"):
434
- st.write(chat['analysis'])
435
- if 'question' in chat:
436
- st.write(f"Follow-up: {chat['question']}")
437
-
438
- # Save chat options
439
- save_name = st.text_input("Save chat as (optional):", key="save_chat_name")
440
- if st.button("Save Chat", key="save_chat_button"):
441
- if st.session_state.chat_history:
442
- filename = save_chat_history(
443
- st.session_state.chat_history,
444
- st.session_state.current_image,
445
- f"{save_name}.json" if save_name else None
446
- )
447
- st.success(f"Chat saved as {filename}")
448
- else:
449
- st.warning("No chat history to save.")
450
 
451
- with tab2:
452
- st.title("📚 Learn Trading")
453
-
454
- # Search or select trading concept
455
- concept = st.text_input("Enter a trading concept you'd like to learn about (e.g., 'evening star pattern', 'RSI', 'MACD'):", key="learn_concept")
456
- if st.button("Learn", key="learn_button"):
457
- if concept:
458
- with st.spinner("Getting educational content..."):
459
- education_content = get_trading_education(client, concept)
460
- if education_content:
461
- st.markdown(education_content)
462
-
463
- if __name__ == "__main__":
464
- main()
465
- # Initialize variables
466
- uploaded_file = None
467
- screenshot_taken = False
468
-
469
- # Sidebar
470
- with st.sidebar:
471
- st.title("🚀 Chart Analysis AI")
472
- upload_option = st.radio(
473
- "Choose input method:",
474
- ("Upload Image", "Take Screenshot", "Ask Question")
475
- )
476
-
477
- # File uploader
478
- if upload_option == "Upload Image":
479
- uploaded_file = st.file_uploader("Upload your chart", type=["png", "jpg", "jpeg"])
480
- elif upload_option == "Take Screenshot":
481
- if st.button("Take Screenshot", key="screenshot"):
482
- st.info("Feature coming soon! For now, please use the Upload Image option.")
483
- screenshot_taken = False
484
-
485
- # Analysis Options
486
- st.subheader("Analysis Options")
487
- patterns = st.multiselect(
488
- "Patterns to Look For",
489
- ["Double Top/Bottom", "Head and Shoulders", "Triangle",
490
- "Flag", "Wedge", "Channel", "Support/Resistance"]
491
- )
492
-
493
- indicators = st.multiselect(
494
- "Technical Indicators",
495
- ["Moving Averages", "RSI", "MACD", "Bollinger Bands",
496
- "Volume", "Stochastic", "ADX"]
497
- )
498
-
499
  # Main content area
500
- st.title("📈 Stock Chart Analysis Assistant")
501
-
502
- # Create two columns for layout
503
  col1, col2 = st.columns([2, 1])
504
 
505
  with col1:
 
 
506
  if upload_option == "Ask Question":
507
- user_question = st.text_input("What would you like to know about your chart?")
 
 
 
508
 
509
- # Display uploaded image
510
- if uploaded_file is not None:
511
- st.image(uploaded_file, caption="Uploaded Chart", use_container_width=True)
 
 
512
 
513
- if st.button("Analyze"):
514
- if upload_option == "Ask Question" and user_question:
515
- st.info("Question-based analysis feature coming soon!")
516
- elif uploaded_file is None and not screenshot_taken:
517
- st.warning("Please upload an image or take a screenshot first.")
518
  else:
519
  with st.spinner("Analyzing chart..."):
520
- # Generate prompt
521
- prompt = create_prompt_template(patterns, indicators)
 
 
 
522
 
523
- if uploaded_file:
524
- # Process image and get analysis
525
- analysis_result, chart_type = analyze_chart_with_claude(
526
- client,
527
- uploaded_file.getvalue(),
528
- prompt
529
- )
530
 
531
- if analysis_result:
532
- # Add to chat history
533
- st.session_state.chat_history.append({
534
- 'timestamp': datetime.now().isoformat(),
535
- 'chart_type': chart_type,
536
- 'analysis': analysis_result
537
- })
538
-
539
- # Display analysis
540
- st.subheader("Analysis Results")
541
- st.write(analysis_result)
542
-
543
- # Risk warning
544
- st.warning(
545
- "⚠️ This analysis is AI-generated and for informational purposes only. "
546
- "Do not make trading decisions solely based on this information."
547
- )
 
 
548
 
549
  with col2:
550
- st.subheader("Chat History")
551
-
552
- # Display chat history
553
- for chat in st.session_state.chat_history:
554
- with st.expander(f"Analysis from {chat['timestamp'][:16]}"):
555
- st.write(chat['analysis'])
556
-
557
- # Save chat options
558
- save_name = st.text_input("Save chat as (optional):")
559
- if st.button("Save Chat"):
560
- if st.session_state.chat_history:
561
- filename = save_chat_history(
562
- st.session_state.chat_history,
563
- f"{save_name}.json" if save_name else None
564
- )
565
- st.success(f"Chat saved as {filename}")
566
- else:
567
- st.warning("No chat history to save.")
568
 
569
  if __name__ == "__main__":
570
  main()
 
1
+ # src/main.py
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
 
3
+ import streamlit as st
4
+ from services.claude_service import ClaudeService
5
+ from services.chart_analysis import ChartAnalysisService
6
+ from ui.components import (
7
+ create_sidebar,
8
+ show_analysis_section,
9
+ show_chat_history,
10
+ show_follow_up_section,
11
+ show_save_options
12
+ )
13
+ from utils.file_handlers import save_chat_history
14
+
15
+ def init_session_state():
16
+ """Initialize session state variables"""
17
+ if 'chat_history' not in st.session_state:
18
+ st.session_state.chat_history = []
19
+ if 'current_image' not in st.session_state:
20
+ st.session_state.current_image = None
21
+ if 'current_analysis' not in st.session_state:
22
+ st.session_state.current_analysis = None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
 
24
  def main():
25
  st.set_page_config(
 
28
  initial_sidebar_state="expanded"
29
  )
30
 
31
+ # Initialize services
32
+ try:
33
+ claude_service = ClaudeService()
34
+ analysis_service = ChartAnalysisService(claude_service)
35
+ except ValueError as e:
36
+ st.error(str(e))
37
  return
38
 
39
  # Initialize session state
40
+ init_session_state()
 
 
 
 
 
 
 
 
41
 
42
+ # Create sidebar and get inputs
43
+ upload_option, uploaded_file, patterns, indicators = create_sidebar()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
44
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
45
  # Main content area
 
 
 
46
  col1, col2 = st.columns([2, 1])
47
 
48
  with col1:
49
+ st.title("📈 Stock Chart Analysis Assistant")
50
+
51
  if upload_option == "Ask Question":
52
+ question = st.text_input(
53
+ "What would you like to know?",
54
+ key="main_question_input"
55
+ )
56
 
57
+ # Main analysis section
58
+ if uploaded_file:
59
+ st.session_state.current_image = uploaded_file.getvalue()
60
+
61
+ analyze_clicked = show_analysis_section(uploaded_file)
62
 
63
+ if analyze_clicked:
64
+ if uploaded_file is None:
65
+ st.warning("Please upload an image first.")
 
 
66
  else:
67
  with st.spinner("Analyzing chart..."):
68
+ result = analysis_service.analyze_chart(
69
+ uploaded_file.getvalue(),
70
+ patterns,
71
+ indicators
72
+ )
73
 
74
+ if result:
75
+ st.session_state.current_analysis = result['analysis']
76
+ st.session_state.chat_history.append(result)
 
 
 
 
77
 
78
+ st.subheader("Analysis Results")
79
+ st.write(result['analysis'])
80
+ st.warning(
81
+ "⚠️ This analysis is AI-generated and for informational purposes only."
82
+ )
83
+
84
+ # Follow-up section
85
+ if st.session_state.current_analysis:
86
+ follow_up = show_follow_up_section(st.session_state.current_analysis)
87
+ if follow_up:
88
+ with st.spinner("Processing follow-up..."):
89
+ response = analysis_service.handle_follow_up_question(
90
+ follow_up,
91
+ st.session_state.current_analysis,
92
+ st.session_state.current_image
93
+ )
94
+ if response:
95
+ st.session_state.chat_history.append(response)
96
+ st.write(response['analysis'])
97
 
98
  with col2:
99
+ # Chat history
100
+ show_chat_history(st.session_state.chat_history)
101
+
102
+ # Save options
103
+ save_name = show_save_options()
104
+ if save_name and st.session_state.chat_history:
105
+ filename = save_chat_history(
106
+ st.session_state.chat_history,
107
+ st.session_state.current_image,
108
+ f"{save_name}.json" if save_name else None
109
+ )
110
+ st.success(f"Chat saved as {filename}")
 
 
 
 
 
 
111
 
112
  if __name__ == "__main__":
113
  main()