Jeremy Live commited on
Commit
bc80b7a
Β·
1 Parent(s): b95abeb
Files changed (2) hide show
  1. app.py +231 -54
  2. stock_plot.py +157 -0
app.py CHANGED
@@ -175,73 +175,250 @@ def run_crewai_process(user_query, model, temperature):
175
  with open(temp_script_path, "w") as f:
176
  f.write(generated_code)
177
 
178
- # Execute the temporary script using subprocess
179
- try:
180
- # Add debug info and ensure plot is saved with absolute path
181
- debug_script = f"""
182
- import traceback
183
- import sys
184
  import os
185
- import matplotlib
186
- # Use non-interactive backend to avoid display issues
187
- matplotlib.use('Agg')
188
- import matplotlib.pyplot as plt
189
-
190
- # Debug info
191
- print("="*80)
192
- print("STARTING SCRIPT EXECUTION")
193
- print("="*80)
194
- print(f"[DEBUG] Python version: {{sys.version}}")
195
- print(f"[DEBUG] Working directory: {{os.getcwd()}}")
196
- print("[DEBUG] Directory contents:")
197
- for f in os.listdir('.'):
198
- print(f" - {{f}}{' (dir)' if os.path.isdir(f) else ''}")
199
- print("\n" + "="*80 + "\n")
200
 
201
  try:
202
- # Create a test plot first to verify matplotlib is working
203
- test_fig, test_ax = plt.subplots()
204
- test_ax.plot([1, 2, 3], [1, 4, 9])
205
- test_ax.set_title('Test Plot - If you see this, matplotlib is working')
206
- test_plot_path = 'test_plot.png'
207
- test_fig.savefig(test_plot_path, bbox_inches='tight')
208
- print(f"[DEBUG] Test plot saved to: {{os.path.abspath(test_plot_path)}}")
209
- print(f"[DEBUG] Test plot size: {{os.path.getsize(test_plot_path)}} bytes")
210
 
211
- # Execute the original script
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
212
  print("\n" + "="*80)
213
- print("EXECUTING USER SCRIPT")
214
  print("="*80)
215
- {generated_code}
216
 
217
- # Ensure any pending plots are drawn
218
- plt.ioff()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
219
 
220
- # Save any open figures
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
221
  print("\n" + "="*80)
222
- print("SAVING PLOTS")
223
  print("="*80)
224
 
225
- # Get list of all figure numbers
226
- fig_nums = plt.get_fignums()
227
- print(f"[DEBUG] Found {{len(fig_nums)}} open figures")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
228
 
229
- if fig_nums:
230
- # Save the last figure as plot.png
231
- last_fig = plt.figure(fig_nums[-1])
232
- plot_path = os.path.abspath('plot.png')
233
- last_fig.savefig(plot_path, bbox_inches='tight', dpi=100)
234
- print(f"[DEBUG] Saved plot to: {{plot_path}}")
235
- print(f"[DEBUG] Plot file size: {{os.path.getsize(plot_path)}} bytes")
 
 
 
 
 
 
 
 
236
 
237
- # Save all figures with unique names
238
- for i, num in enumerate(fig_nums, 1):
239
- fig = plt.figure(num)
240
- fig_path = os.path.abspath(f'plot_{{i}}.png')
241
- fig.savefig(fig_path, bbox_inches='tight', dpi=100)
242
- print(f"[DEBUG] Saved additional plot to: {{fig_path}} ({{os.path.getsize(fig_path)}} bytes)")
243
- else:
244
- print("[WARNING] No figures were created in the script")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
245
 
246
  # Print final directory contents
247
  print("\n" + "="*80)
 
175
  with open(temp_script_path, "w") as f:
176
  f.write(generated_code)
177
 
178
+ # Create a debug script that will be executed in a subprocess
179
+ debug_script = """
 
 
 
 
180
  import os
181
+ import sys
182
+ import traceback
 
 
 
 
 
 
 
 
 
 
 
 
 
183
 
184
  try:
185
+ print("\n" + "="*80)
186
+ print("STOCK PLOT GENERATION")
187
+ print("="*80)
 
 
 
 
 
188
 
189
+ # Import the stock plot module
190
+ try:
191
+ import stock_plot
192
+
193
+ # Generate the plot using the module
194
+ plot_path = stock_plot.plot_stock_gain(["META"], "ytd")
195
+
196
+ print("\n" + "="*80)
197
+ print("PLOT GENERATION COMPLETE")
198
+ print("="*80)
199
+
200
+ if plot_path and os.path.exists(plot_path):
201
+ file_size = os.path.getsize(plot_path)
202
+ print(f"βœ“ Plot generated successfully: {os.path.abspath(plot_path)}")
203
+ print(f"βœ“ File size: {file_size} bytes")
204
+
205
+ # Also check for plot.png in the root directory
206
+ if os.path.exists('plot.png'):
207
+ print(f"βœ“ Main plot.png found: {os.path.abspath('plot.png')}")
208
+ else:
209
+ print("ℹ️ plot.png not found in root directory")
210
+ else:
211
+ print("❌ Failed to generate plot or plot file not found")
212
+
213
+ except ImportError as e:
214
+ print(f"❌ Error importing stock_plot module: {e}")
215
+ print("Make sure the stock_plot.py file exists in the same directory.")
216
+ raise
217
+
218
  print("\n" + "="*80)
219
+ print("DIRECTORY CONTENTS")
220
  print("="*80)
 
221
 
222
+ # List all files in the current directory
223
+ for f in sorted(os.listdir('.')):
224
+ try:
225
+ fpath = os.path.join('.', f)
226
+ if os.path.isfile(fpath):
227
+ size = os.path.getsize(fpath)
228
+ print(f" - {f} ({size} bytes)")
229
+ else:
230
+ print(f" - {f}/ (dir)")
231
+ except Exception as e:
232
+ print(f" - {f} (error: {e})")
233
+
234
+ # Check for generated_plots directory
235
+ plots_dir = 'generated_plots'
236
+ if os.path.exists(plots_dir) and os.path.isdir(plots_dir):
237
+ print(f"\nContents of {plots_dir}/:")
238
+ try:
239
+ for f in sorted(os.listdir(plots_dir)):
240
+ try:
241
+ fpath = os.path.join(plots_dir, f)
242
+ if os.path.isfile(fpath):
243
+ size = os.path.getsize(fpath)
244
+ print(f" - {f} ({size} bytes)")
245
+ except Exception as e:
246
+ print(f" - {f} (error: {e})")
247
+ except Exception as e:
248
+ print(f" Error reading {plots_dir}: {e}")
249
+
250
+ except Exception as e:
251
+ print(f"\n❌ UNEXPECTED ERROR: {str(e)}")
252
+ print("\nTraceback:")
253
+ traceback.print_exc()
254
+ sys.exit(1)
255
+ """
256
+
257
+ # Create a simple test plot
258
+ try:
259
+ # Create a new figure with a larger size
260
+ fig, ax = plt.subplots(figsize=(10, 6))
261
+
262
+ # Generate some sample data
263
+ x = [1, 2, 3, 4, 5]
264
+ y = [1, 4, 9, 16, 25]
265
+
266
+ # Create the plot
267
+ ax.plot(x, y, 'b-', linewidth=2, label='Sample Data')
268
+
269
+ # Add labels and title
270
+ ax.set_title('Test Plot - Matplotlib Verification', fontsize=14)
271
+ ax.set_xlabel('X Axis', fontsize=12)
272
+ ax.set_ylabel('Y Axis', fontsize=12)
273
+
274
+ # Add grid and legend
275
+ ax.grid(True, linestyle='--', alpha=0.7)
276
+ ax.legend(fontsize=10)
277
+
278
+ # Adjust layout to prevent label cutoff
279
+ plt.tight_layout()
280
+
281
+ # Save the test plot
282
+ test_plot_path = 'test_plot.png'
283
+ fig.savefig(test_plot_path, dpi=120, bbox_inches='tight')
284
+ print(f"βœ“ Test plot saved to: {os.path.abspath(test_plot_path)}")
285
+
286
+ # Close the figure to free memory
287
+ plt.close(fig)
288
+
289
+ except Exception as e:
290
+ print(f"❌ Error creating test plot: {e}")
291
+ print("Traceback:")
292
+ traceback.print_exc()
293
+
294
+ # Save with different formats and verify
295
+ test_formats = [
296
+ ('test_plot.png', 'PNG'),
297
+ ('test_plot.jpg', 'JPEG'),
298
+ ('test_plot.pdf', 'PDF')
299
+ ]
300
 
301
+ for filename, fmt in test_formats:
302
+ try:
303
+ test_fig.savefig(filename, bbox_inches='tight', dpi=100)
304
+ abs_path = os.path.abspath(filename)
305
+ file_size = os.path.getsize(filename)
306
+ print(f"βœ“ Saved {{fmt}} to: {{abs_path}} ({{file_size}} bytes)")
307
+
308
+ # Verify file is not empty
309
+ if file_size == 0:
310
+ print(f" βœ— WARNING: {{fmt}} file is empty!")
311
+ elif file_size < 1024: # Very small file might be corrupted
312
+ print(f" ⚠ WARNING: {{fmt}} file is unusually small ({{file_size}} bytes)")
313
+
314
+ except Exception as e:
315
+ print(f"βœ— Failed to save {{fmt}}: {{str(e)}}")
316
+
317
+ # Clean up
318
+ plt.close(test_fig)
319
+
320
+ # Test 2: Verify file system access
321
  print("\n" + "="*80)
322
+ print("TEST 2: FILE SYSTEM VERIFICATION")
323
  print("="*80)
324
 
325
+ # Check if files were created
326
+ for filename, _ in test_formats:
327
+ if os.path.exists(filename):
328
+ try:
329
+ file_size = os.path.getsize(filename)
330
+ print(f"βœ“ Found {{filename}} ({{file_size}} bytes)")
331
+ # Try to read the file
332
+ with open(filename, 'rb') as f:
333
+ header = f.read(4)
334
+ print(f" File header: {{header[:20].hex()}}...")
335
+ except Exception as e:
336
+ print(f"βœ— Error reading {{filename}}: {{str(e)}}")
337
+ else:
338
+ print(f"βœ— File not found: {{filename}}")
339
+
340
+ # Execute the original script with error handling
341
+ print("\n" + "="*80)
342
+ print("EXECUTING USER SCRIPT")
343
+ print("="*80)
344
 
345
+ # Create a safe execution environment
346
+ try:
347
+ # Execute the user's code
348
+ exec_globals = {{'plt': plt, 'pd': __import__('pandas')}}
349
+ exec_globals.update({{'__builtins__': __builtins__}})
350
+
351
+ # Execute in a separate namespace to avoid polluting globals
352
+ user_namespace = {{}}
353
+ user_code = compile(
354
+ {generated_code!r}.lstrip('\n').lstrip(' '),
355
+ '<user_code>', 'exec',
356
+ dont_inherit=True,
357
+ optimize=2
358
+ )
359
+ exec(user_code, user_namespace, user_namespace)
360
 
361
+ # Ensure any pending plots are drawn
362
+ plt.ioff()
363
+
364
+ # Save any open figures
365
+ print("\n" + "="*80)
366
+ print("SAVING PLOTS")
367
+ print("="*80)
368
+
369
+ # Get list of all figure numbers
370
+ fig_nums = plt.get_fignums()
371
+ print(f"Found {{len(fig_nums)}} open figures")
372
+
373
+ if fig_nums:
374
+ # Create plots directory if it doesn't exist
375
+ plots_dir = 'generated_plots'
376
+ os.makedirs(plots_dir, exist_ok=True)
377
+
378
+ # Save all figures with unique names
379
+ saved_plots = []
380
+ for i, num in enumerate(fig_nums, 1):
381
+ try:
382
+ fig = plt.figure(num)
383
+ plot_name = f'plot_{{i}}.png'
384
+ plot_path = os.path.abspath(os.path.join(plots_dir, plot_name))
385
+
386
+ # Save with high DPI and tight layout
387
+ fig.savefig(
388
+ plot_path,
389
+ bbox_inches='tight',
390
+ dpi=150,
391
+ facecolor=fig.get_facecolor(),
392
+ edgecolor='none',
393
+ transparent=False
394
+ )
395
+
396
+ file_size = os.path.getsize(plot_path)
397
+ print(f"βœ“ Saved plot {{i}} to: {{plot_path}} ({{file_size}} bytes)")
398
+ saved_plots.append(plot_path)
399
+
400
+ # If this is the last figure, also save as plot.png in root
401
+ if i == len(fig_nums):
402
+ root_plot_path = os.path.abspath('plot.png')
403
+ fig.savefig(root_plot_path, bbox_inches='tight', dpi=150)
404
+ print(f"βœ“ Saved main plot to: {{root_plot_path}}")
405
+ saved_plots.append(root_plot_path)
406
+
407
+ except Exception as e:
408
+ print(f"βœ— Error saving figure {{num}}: {{str(e)}}")
409
+
410
+ if saved_plots:
411
+ generated_plot_path = saved_plots[-1] # Use the last saved plot as the main plot
412
+ print(f"\nSuccessfully saved {{len(saved_plots)}} plot(s)")
413
+
414
+ else:
415
+ print("ℹ️ No figures were created by the user script")
416
+
417
+ except Exception as e:
418
+ print(f"\n❌ Error executing user script: {{str(e)}}")
419
+ print("\nTraceback:")
420
+ traceback.print_exc()
421
+ raise
422
 
423
  # Print final directory contents
424
  print("\n" + "="*80)
stock_plot.py ADDED
@@ -0,0 +1,157 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Stock Plot Generation Script
3
+
4
+ This script generates stock gain plots using yfinance and matplotlib.
5
+ It includes robust error handling and debugging information.
6
+ """
7
+
8
+ import os
9
+ import sys
10
+ import traceback
11
+ import platform
12
+ from datetime import datetime
13
+
14
+ # Configure matplotlib before importing pyplot
15
+ import matplotlib
16
+ matplotlib.use('Agg') # Non-interactive backend
17
+ import matplotlib.pyplot as plt
18
+ import pandas as pd
19
+ import yfinance as yf
20
+
21
+
22
+ def setup_environment():
23
+ """Print environment information and verify dependencies."""
24
+ print("\n" + "=" * 80)
25
+ print("ENVIRONMENT INFORMATION")
26
+ print("=" * 80)
27
+ print(f"Python: {sys.version}")
28
+ print(f"Platform: {platform.platform()}")
29
+ print(f"Current directory: {os.getcwd()}")
30
+ print(f"Python executable: {sys.executable}")
31
+ print(f"Current time: {datetime.now().isoformat()}")
32
+
33
+ # Verify required packages
34
+ print("\nChecking dependencies:")
35
+ for pkg in [('pandas', pd), ('matplotlib', matplotlib), ('yfinance', yf)]:
36
+ try:
37
+ print(f" βœ“ {pkg[0]}: {pkg[1].__version__}")
38
+ except Exception as e:
39
+ print(f" βœ— {pkg[0]}: Not available ({e})")
40
+
41
+
42
+ def plot_stock_gain(symbols, timeframe="3mo"):
43
+ """
44
+ Generate and save stock gain plots.
45
+
46
+ Args:
47
+ symbols: List of stock symbols or a single symbol string
48
+ timeframe: Time period to fetch data for (e.g., '1mo', '3mo', '1y')
49
+
50
+ Returns:
51
+ str: Path to the saved plot file, or None if failed
52
+ """
53
+ # Convert single symbol to list
54
+ if isinstance(symbols, str):
55
+ symbols = [symbols]
56
+
57
+ print(f"\nProcessing symbols: {', '.join(symbols)} for timeframe: {timeframe}")
58
+
59
+ # Create output directory if it doesn't exist
60
+ output_dir = 'generated_plots'
61
+ os.makedirs(output_dir, exist_ok=True)
62
+
63
+ plot_paths = []
64
+
65
+ for symbol in symbols:
66
+ try:
67
+ print(f"\n{'='*40}")
68
+ print(f"Processing: {symbol}")
69
+ print(f"{'='*40}")
70
+
71
+ # Download stock data
72
+ print(f"Downloading {timeframe} data for {symbol}...")
73
+ ticker = yf.Ticker(symbol)
74
+ stock_data = ticker.history(period=timeframe)
75
+
76
+ if stock_data.empty:
77
+ print(f"⚠ No data found for {symbol}")
78
+ continue
79
+
80
+ print(f"Retrieved {len(stock_data)} data points from {stock_data.index[0].date()} to {stock_data.index[-1].date()}")
81
+
82
+ # Calculate percentage gain
83
+ stock_data['Gain'] = stock_data['Close'].pct_change().fillna(0).cumsum()
84
+
85
+ # Create plot
86
+ plt.figure(figsize=(12, 6))
87
+ plt.plot(stock_data.index, stock_data['Gain'],
88
+ linewidth=2,
89
+ label=f'{symbol} Gain')
90
+
91
+ # Format plot
92
+ plt.title(f'{symbol} Cumulative Gain - {timeframe.upper()}', fontsize=14)
93
+ plt.xlabel('Date', fontsize=12)
94
+ plt.ylabel('Cumulative Gain', fontsize=12)
95
+ plt.legend()
96
+ plt.grid(True, linestyle='--', alpha=0.7)
97
+ plt.tight_layout()
98
+
99
+ # Save plot
100
+ timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
101
+ plot_filename = f"{symbol}_{timeframe}_{timestamp}.png"
102
+ plot_path = os.path.join(output_dir, plot_filename)
103
+
104
+ plt.savefig(plot_path, dpi=120, bbox_inches='tight')
105
+ plt.close() # Close the figure to free memory
106
+
107
+ # Verify the file was created
108
+ if os.path.exists(plot_path):
109
+ file_size = os.path.getsize(plot_path)
110
+ print(f"βœ“ Plot saved: {plot_path} ({file_size} bytes)")
111
+ plot_paths.append(plot_path)
112
+
113
+ # Also save as plot.png in root for compatibility
114
+ if symbol == symbols[-1]: # Only for the last symbol
115
+ main_plot_path = 'plot.png'
116
+ plt.figure(plt.get_fignums()[-1]) # Get the last figure
117
+ plt.savefig(main_plot_path, dpi=120, bbox_inches='tight')
118
+ print(f"βœ“ Main plot saved as: {os.path.abspath(main_plot_path)}")
119
+ else:
120
+ print("❌ Failed to save plot")
121
+
122
+ except Exception as e:
123
+ print(f"❌ Error processing {symbol}: {str(e)}")
124
+ print("Traceback:")
125
+ traceback.print_exc()
126
+
127
+ return plot_paths[0] if plot_paths else None
128
+
129
+
130
+ def main():
131
+ """Main execution function."""
132
+ try:
133
+ setup_environment()
134
+
135
+ # Default symbols and timeframe
136
+ symbols = ["META"]
137
+ timeframe = "ytd"
138
+
139
+ # Generate plots
140
+ plot_path = plot_stock_gain(symbols, timeframe)
141
+
142
+ if plot_path:
143
+ print(f"\nβœ… Successfully generated plot: {os.path.abspath(plot_path)}")
144
+ return 0
145
+ else:
146
+ print("\n❌ Failed to generate any plots")
147
+ return 1
148
+
149
+ except Exception as e:
150
+ print(f"\n❌ Fatal error: {str(e)}")
151
+ print("Traceback:")
152
+ traceback.print_exc()
153
+ return 1
154
+
155
+
156
+ if __name__ == "__main__":
157
+ sys.exit(main())