ArnabDeo commited on
Commit
2b43840
Β·
verified Β·
1 Parent(s): cee27a9

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +461 -461
app.py CHANGED
@@ -1,461 +1,461 @@
1
- import gradio as gr
2
- import yfinance as yf
3
- import pandas as pd
4
- import numpy as np
5
- import plotly.graph_objects as go
6
- import warnings
7
- import time
8
- import gc
9
- import os
10
- import torch
11
- from datetime import datetime, timedelta
12
- from typing import Optional, Dict, Any, Tuple
13
-
14
- warnings.filterwarnings('ignore')
15
-
16
- # Environment optimizations for Hugging Face Spaces
17
- os.environ['TOKENIZERS_PARALLELISM'] = 'false'
18
- os.environ['HF_HUB_DISABLE_PROGRESS_BARS'] = '1'
19
- os.environ['HF_HUB_DISABLE_TELEMETRY'] = '1'
20
- os.environ['TRANSFORMERS_VERBOSITY'] = 'error'
21
-
22
- if torch.cuda.is_available():
23
- torch.cuda.empty_cache()
24
- torch.set_num_threads(min(4, os.cpu_count() or 1))
25
-
26
- class FastAIStockAnalyzer:
27
- """Optimized AI Stock Analyzer for Gradio"""
28
-
29
- def __init__(self):
30
- self.context_length = 32
31
- self.prediction_length = 7
32
- self.device = "cpu"
33
- self.model_cache = {}
34
-
35
- def fetch_stock_data(self, symbol: str, period: str = "6mo") -> Tuple[Optional[pd.DataFrame], Optional[Dict]]:
36
- """Fetch stock data with error handling"""
37
- try:
38
- ticker = yf.Ticker(symbol)
39
- data = ticker.history(period=period, interval="1d",
40
- actions=False, auto_adjust=True,
41
- back_adjust=False, repair=False)
42
-
43
- if data.empty:
44
- return None, None
45
-
46
- try:
47
- info = {
48
- 'longName': ticker.info.get('longName', symbol),
49
- 'sector': ticker.info.get('sector', 'Unknown'),
50
- 'marketCap': ticker.info.get('marketCap', 0)
51
- }
52
- except:
53
- info = {'longName': symbol, 'sector': 'Unknown', 'marketCap': 0}
54
-
55
- return data, info
56
-
57
- except Exception as e:
58
- return None, None
59
-
60
- def load_chronos_tiny(self) -> Tuple[Optional[Any], str]:
61
- """Load Chronos model with caching"""
62
- model_key = "chronos_tiny"
63
-
64
- if model_key in self.model_cache:
65
- return self.model_cache[model_key], "chronos"
66
-
67
- try:
68
- from chronos import ChronosPipeline
69
-
70
- pipeline = ChronosPipeline.from_pretrained(
71
- "amazon/chronos-t5-tiny",
72
- device_map="cpu",
73
- torch_dtype=torch.float32,
74
- low_cpu_mem_usage=True,
75
- trust_remote_code=True
76
- )
77
-
78
- self.model_cache[model_key] = pipeline
79
- return pipeline, "chronos"
80
-
81
- except Exception as e:
82
- return None, None
83
-
84
- def load_moirai_small(self) -> Tuple[Optional[Any], str]:
85
- """Load Moirai model with caching"""
86
- model_key = "moirai_small"
87
-
88
- if model_key in self.model_cache:
89
- return self.model_cache[model_key], "moirai"
90
-
91
- try:
92
- from uni2ts.model.moirai import MoiraiForecast, MoiraiModule
93
-
94
- module = MoiraiModule.from_pretrained(
95
- "Salesforce/moirai-1.0-R-small",
96
- low_cpu_mem_usage=True,
97
- device_map="cpu",
98
- torch_dtype=torch.float32,
99
- trust_remote_code=True
100
- )
101
-
102
- model = MoiraiForecast(
103
- module=module,
104
- prediction_length=self.prediction_length,
105
- context_length=self.context_length,
106
- patch_size="auto",
107
- num_samples=15,
108
- target_dim=1,
109
- feat_dynamic_real_dim=0,
110
- past_feat_dynamic_real_dim=0
111
- )
112
-
113
- self.model_cache[model_key] = model
114
- return model, "moirai"
115
-
116
- except Exception as e:
117
- return None, None
118
-
119
- def predict_chronos_fast(self, pipeline: Any, data: np.ndarray) -> Optional[Dict]:
120
- """Fast Chronos prediction"""
121
- try:
122
- context_data = data[-self.context_length:]
123
- context = torch.tensor(context_data, dtype=torch.float32).unsqueeze(0)
124
-
125
- with torch.no_grad():
126
- forecast = pipeline.predict(
127
- context=context,
128
- prediction_length=self.prediction_length,
129
- num_samples=10,
130
- temperature=1.0,
131
- top_k=50,
132
- top_p=1.0
133
- )
134
-
135
- forecast_array = forecast[0].numpy()
136
- predictions = {
137
- 'mean': np.median(forecast_array, axis=0),
138
- 'q10': np.quantile(forecast_array, 0.1, axis=0),
139
- 'q90': np.quantile(forecast_array, 0.9, axis=0),
140
- 'std': np.std(forecast_array, axis=0)
141
- }
142
-
143
- return predictions
144
-
145
- except Exception as e:
146
- return None
147
-
148
- def predict_moirai_fast(self, model: Any, data: np.ndarray) -> Optional[Dict]:
149
- """Fast Moirai prediction"""
150
- try:
151
- from gluonts.dataset.common import ListDataset
152
-
153
- dataset = ListDataset([{
154
- "item_id": "stock",
155
- "start": "2023-01-01",
156
- "target": data[-self.context_length:].tolist()
157
- }], freq='D')
158
-
159
- predictor = model.create_predictor(
160
- batch_size=1,
161
- num_parallel_samples=10
162
- )
163
-
164
- forecasts = list(predictor.predict(dataset))
165
- forecast = forecasts[0]
166
-
167
- predictions = {
168
- 'mean': forecast.mean,
169
- 'q10': forecast.quantile(0.1),
170
- 'q90': forecast.quantile(0.9),
171
- 'std': np.std(forecast.samples, axis=0)
172
- }
173
-
174
- return predictions
175
-
176
- except Exception as e:
177
- return None
178
-
179
- # Initialize analyzer globally for caching
180
- analyzer = FastAIStockAnalyzer()
181
-
182
- def analyze_stock(stock_symbol, model_choice, investment_amount, progress=gr.Progress()):
183
- """Main analysis function for Gradio"""
184
-
185
- progress(0.1, desc="Fetching stock data...")
186
-
187
- # Fetch data
188
- stock_data, stock_info = analyzer.fetch_stock_data(stock_symbol)
189
-
190
- if stock_data is None or len(stock_data) < 50:
191
- return (
192
- "❌ Error: Insufficient data for analysis. Please check the stock symbol.",
193
- None,
194
- None,
195
- "N/A",
196
- "N/A"
197
- )
198
-
199
- current_price = stock_data['Close'].iloc[-1]
200
- company_name = stock_info.get('longName', stock_symbol) if stock_info else stock_symbol
201
-
202
- progress(0.3, desc="Loading AI model...")
203
-
204
- # Load model
205
- model_type = "chronos" if "Chronos" in model_choice else "moirai"
206
-
207
- if model_type == "chronos":
208
- model, loaded_type = analyzer.load_chronos_tiny()
209
- model_name = "Amazon Chronos Tiny"
210
- else:
211
- model, loaded_type = analyzer.load_moirai_small()
212
- model_name = "Salesforce Moirai Small"
213
-
214
- if model is None:
215
- return (
216
- "❌ Error: Failed to load AI model. Please try again.",
217
- None,
218
- None,
219
- "N/A",
220
- "N/A"
221
- )
222
-
223
- progress(0.6, desc="Generating AI predictions...")
224
-
225
- # Generate predictions
226
- if model_type == "chronos":
227
- predictions = analyzer.predict_chronos_fast(model, stock_data['Close'].values)
228
- else:
229
- predictions = analyzer.predict_moirai_fast(model, stock_data['Close'].values)
230
-
231
- if predictions is None:
232
- return (
233
- "❌ Error: Prediction failed. Please try again.",
234
- None,
235
- None,
236
- "N/A",
237
- "N/A"
238
- )
239
-
240
- progress(0.8, desc="Calculating investment scenarios...")
241
-
242
- # Analysis results
243
- mean_pred = predictions['mean']
244
- final_pred = mean_pred[-1]
245
- week_change = ((final_pred - current_price) / current_price) * 100
246
-
247
- # Decision logic
248
- if week_change > 5:
249
- decision = "🟒 STRONG BUY"
250
- explanation = "AI expects significant gains!"
251
- elif week_change > 2:
252
- decision = "🟒 BUY"
253
- explanation = "AI expects moderate gains"
254
- elif week_change < -5:
255
- decision = "πŸ”΄ STRONG SELL"
256
- explanation = "AI expects significant losses"
257
- elif week_change < -2:
258
- decision = "πŸ”΄ SELL"
259
- explanation = "AI expects losses"
260
- else:
261
- decision = "βšͺ HOLD"
262
- explanation = "AI expects stable prices"
263
-
264
- # Create analysis text
265
- analysis_text = f"""
266
- # 🎯 {company_name} ({stock_symbol}) Analysis
267
-
268
- ## πŸ€– AI RECOMMENDATION: {decision}
269
- **{explanation}**
270
- *Powered by {model_name}*
271
-
272
- ## πŸ“Š Key Metrics
273
- - **Current Price**: ${current_price:.2f}
274
- - **7-Day Prediction**: ${final_pred:.2f} ({week_change:+.2f}%)
275
- - **AI Confidence**: {min(100, max(50, 70 + abs(week_change) * 1.5)):.0f}%
276
- - **Model Used**: {model_name}
277
-
278
- ## πŸ’° Investment Scenario (${investment_amount:,.0f})
279
- - **Shares**: {investment_amount/current_price:.2f}
280
- - **Predicted Value**: ${investment_amount + ((final_pred - current_price) * (investment_amount/current_price)):,.2f}
281
- - **Profit/Loss**: ${((final_pred - current_price) * (investment_amount/current_price)):+,.2f} ({week_change:+.2f}%)
282
-
283
- ⚠️ **DISCLAIMER**: This is AI-generated analysis for educational purposes only. Not financial advice.
284
- """
285
-
286
- progress(0.9, desc="Creating charts...")
287
-
288
- # Create chart
289
- fig = go.Figure()
290
-
291
- # Historical data (last 30 days)
292
- recent = stock_data.tail(30)
293
- fig.add_trace(go.Scatter(
294
- x=recent.index,
295
- y=recent['Close'],
296
- mode='lines',
297
- name='Historical Price',
298
- line=dict(color='blue', width=2)
299
- ))
300
-
301
- # Predictions
302
- future_dates = pd.date_range(
303
- start=stock_data.index[-1] + pd.Timedelta(days=1),
304
- periods=7,
305
- freq='D'
306
- )
307
-
308
- fig.add_trace(go.Scatter(
309
- x=future_dates,
310
- y=mean_pred,
311
- mode='lines+markers',
312
- name='AI Prediction',
313
- line=dict(color='red', width=3),
314
- marker=dict(size=8)
315
- ))
316
-
317
- # Confidence bands
318
- if 'q10' in predictions and 'q90' in predictions:
319
- fig.add_trace(go.Scatter(
320
- x=future_dates.tolist() + future_dates[::-1].tolist(),
321
- y=predictions['q90'].tolist() + predictions['q10'][::-1].tolist(),
322
- fill='toself',
323
- fillcolor='rgba(255,0,0,0.1)',
324
- line=dict(color='rgba(255,255,255,0)'),
325
- name='Confidence Range',
326
- showlegend=True
327
- ))
328
-
329
- fig.update_layout(
330
- title=f"{stock_symbol} - AI Stock Forecast",
331
- xaxis_title="Date",
332
- yaxis_title="Price ($)",
333
- height=500,
334
- showlegend=True,
335
- template="plotly_white"
336
- )
337
-
338
- progress(1.0, desc="Analysis complete!")
339
-
340
- # Create summary metrics
341
- day_change = stock_data['Close'].iloc[-1] - stock_data['Close'].iloc[-2]
342
- day_change_pct = (day_change / stock_data['Close'].iloc[-2]) * 100
343
-
344
- current_metrics = f"${current_price:.2f} ({day_change_pct:+.2f}%)"
345
- prediction_metrics = f"${final_pred:.2f} ({week_change:+.2f}%)"
346
-
347
- return (
348
- analysis_text,
349
- fig,
350
- decision,
351
- current_metrics,
352
- prediction_metrics
353
- )
354
-
355
- # Create Gradio interface[1][2][9][12]
356
- with gr.Blocks(
357
- theme=gr.themes.Soft(),
358
- title="⚑ Fast AI Stock Predictor",
359
- css="footer {visibility: hidden}"
360
- ) as demo:
361
-
362
- gr.HTML("""
363
- <div style="text-align: center; padding: 20px;">
364
- <h1>⚑ Fast AI Stock Predictor</h1>
365
- <p><strong>πŸ€– Powered by Amazon Chronos & Salesforce Moirai</strong></p>
366
- <p style="color: #666; font-size: 14px;">⚠️ Educational use only - Not financial advice</p>
367
- </div>
368
- """)
369
-
370
- with gr.Row():
371
- with gr.Column(scale=1):
372
- gr.HTML("<h3>🎯 Configuration</h3>")
373
-
374
- stock_input = gr.Dropdown(
375
- choices=["AAPL", "GOOGL", "MSFT", "TSLA", "AMZN", "META", "NFLX", "NVDA"],
376
- value="AAPL",
377
- label="Select Stock",
378
- allow_custom_value=True,
379
- info="Choose from popular stocks or enter custom symbol"
380
- )
381
-
382
- model_input = gr.Radio(
383
- choices=["πŸš€ Chronos (Fast)", "🎯 Moirai (Accurate)"],
384
- value="πŸš€ Chronos (Fast)",
385
- label="AI Model",
386
- info="Chronos: Faster | Moirai: More accurate"
387
- )
388
-
389
- investment_input = gr.Slider(
390
- minimum=500,
391
- maximum=50000,
392
- value=5000,
393
- step=500,
394
- label="Investment Amount ($)",
395
- info="Amount to analyze for profit/loss scenarios"
396
- )
397
-
398
- analyze_btn = gr.Button(
399
- "πŸš€ Analyze Stock",
400
- variant="primary",
401
- size="lg"
402
- )
403
-
404
- with gr.Column(scale=2):
405
- gr.HTML("<h3>πŸ“Š Results</h3>")
406
-
407
- with gr.Row():
408
- current_price_display = gr.Textbox(
409
- label="Current Price",
410
- interactive=False,
411
- container=True
412
- )
413
- prediction_display = gr.Textbox(
414
- label="7-Day Prediction",
415
- interactive=False,
416
- container=True
417
- )
418
- decision_display = gr.Textbox(
419
- label="AI Decision",
420
- interactive=False,
421
- container=True
422
- )
423
-
424
- with gr.Row():
425
- analysis_output = gr.Markdown(
426
- label="Analysis Report",
427
- value="Click 'Analyze Stock' to generate AI-powered analysis..."
428
- )
429
-
430
- with gr.Row():
431
- chart_output = gr.Plot(
432
- label="Price Chart & Predictions",
433
- container=True
434
- )
435
-
436
- # Event handlers
437
- analyze_btn.click(
438
- fn=analyze_stock,
439
- inputs=[stock_input, model_input, investment_input],
440
- outputs=[
441
- analysis_output,
442
- chart_output,
443
- decision_display,
444
- current_price_display,
445
- prediction_display
446
- ]
447
- )
448
-
449
- # Examples
450
- gr.Examples(
451
- examples=[
452
- ["AAPL", "πŸš€ Chronos (Fast)", 5000],
453
- ["TSLA", "🎯 Moirai (Accurate)", 10000],
454
- ["GOOGL", "πŸš€ Chronos (Fast)", 2500],
455
- ],
456
- inputs=[stock_input, model_input, investment_input],
457
- label="Try these examples:"
458
- )
459
-
460
- if __name__ == "__main__":
461
- demo.launch()
 
1
+ import gradio as gr
2
+ import yfinance as yf
3
+ import pandas as pd
4
+ import numpy as np
5
+ import plotly.graph_objects as go
6
+ import warnings
7
+ import time
8
+ import gc
9
+ import os
10
+ import torch
11
+ from datetime import datetime, timedelta
12
+ from typing import Optional, Dict, Any, Tuple
13
+
14
+ warnings.filterwarnings('ignore')
15
+
16
+ # Environment optimizations for Hugging Face Spaces
17
+ os.environ['TOKENIZERS_PARALLELISM'] = 'false'
18
+ os.environ['HF_HUB_DISABLE_PROGRESS_BARS'] = '1'
19
+ os.environ['HF_HUB_DISABLE_TELEMETRY'] = '1'
20
+ os.environ['TRANSFORMERS_VERBOSITY'] = 'error'
21
+
22
+ if torch.cuda.is_available():
23
+ torch.cuda.empty_cache()
24
+ torch.set_num_threads(min(4, os.cpu_count() or 1))
25
+
26
+ class FastAIStockAnalyzer:
27
+ """Optimized AI Stock Analyzer for Gradio"""
28
+
29
+ def __init__(self):
30
+ self.context_length = 32
31
+ self.prediction_length = 7
32
+ self.device = "cpu"
33
+ self.model_cache = {}
34
+
35
+ def fetch_stock_data(self, symbol: str, period: str = "6mo") -> Tuple[Optional[pd.DataFrame], Optional[Dict]]:
36
+ """Fetch stock data with error handling"""
37
+ try:
38
+ ticker = yf.Ticker(symbol)
39
+ data = ticker.history(period=period, interval="1d",
40
+ actions=False, auto_adjust=True,
41
+ back_adjust=False, repair=False)
42
+
43
+ if data.empty:
44
+ return None, None
45
+
46
+ try:
47
+ info = {
48
+ 'longName': ticker.info.get('longName', symbol),
49
+ 'sector': ticker.info.get('sector', 'Unknown'),
50
+ 'marketCap': ticker.info.get('marketCap', 0)
51
+ }
52
+ except:
53
+ info = {'longName': symbol, 'sector': 'Unknown', 'marketCap': 0}
54
+
55
+ return data, info
56
+
57
+ except Exception as e:
58
+ return None, None
59
+
60
+ def load_chronos_tiny(self) -> Tuple[Optional[Any], str]:
61
+ """Load Chronos model with caching"""
62
+ model_key = "chronos_tiny"
63
+
64
+ if model_key in self.model_cache:
65
+ return self.model_cache[model_key], "chronos"
66
+
67
+ try:
68
+ from chronos import ChronosPipeline
69
+
70
+ pipeline = ChronosPipeline.from_pretrained(
71
+ "amazon/chronos-t5-tiny",
72
+ device_map="cpu",
73
+ torch_dtype=torch.float32,
74
+ low_cpu_mem_usage=True,
75
+ trust_remote_code=True
76
+ )
77
+
78
+ self.model_cache[model_key] = pipeline
79
+ return pipeline, "chronos"
80
+
81
+ except Exception as e:
82
+ return None, None
83
+
84
+ def load_moirai_small(self) -> Tuple[Optional[Any], str]:
85
+ """Load Moirai model with caching"""
86
+ model_key = "moirai_small"
87
+
88
+ if model_key in self.model_cache:
89
+ return self.model_cache[model_key], "moirai"
90
+
91
+ try:
92
+ from uni2ts.model.moirai import MoiraiForecast, MoiraiModule
93
+
94
+ module = MoiraiModule.from_pretrained(
95
+ "Salesforce/moirai-1.0-R-small",
96
+ low_cpu_mem_usage=True,
97
+ device_map="cpu",
98
+ torch_dtype=torch.float32,
99
+ trust_remote_code=True
100
+ )
101
+
102
+ model = MoiraiForecast(
103
+ module=module,
104
+ prediction_length=self.prediction_length,
105
+ context_length=self.context_length,
106
+ patch_size="auto",
107
+ num_samples=15,
108
+ target_dim=1,
109
+ feat_dynamic_real_dim=0,
110
+ past_feat_dynamic_real_dim=0
111
+ )
112
+
113
+ self.model_cache[model_key] = model
114
+ return model, "moirai"
115
+
116
+ except Exception as e:
117
+ return None, None
118
+
119
+ def predict_chronos_fast(self, pipeline: Any, data: np.ndarray) -> Optional[Dict]:
120
+ """Fast Chronos prediction"""
121
+ try:
122
+ context_data = data[-self.context_length:]
123
+ context = torch.tensor(context_data, dtype=torch.float32).unsqueeze(0)
124
+
125
+ with torch.no_grad():
126
+ forecast = pipeline.predict(
127
+ context=context,
128
+ prediction_length=self.prediction_length,
129
+ num_samples=10,
130
+ temperature=1.0,
131
+ top_k=50,
132
+ top_p=1.0
133
+ )
134
+
135
+ forecast_array = forecast[0].numpy()
136
+ predictions = {
137
+ 'mean': np.median(forecast_array, axis=0),
138
+ 'q10': np.quantile(forecast_array, 0.1, axis=0),
139
+ 'q90': np.quantile(forecast_array, 0.9, axis=0),
140
+ 'std': np.std(forecast_array, axis=0)
141
+ }
142
+
143
+ return predictions
144
+
145
+ except Exception as e:
146
+ return None
147
+
148
+ def predict_moirai_fast(self, model: Any, data: np.ndarray) -> Optional[Dict]:
149
+ """Fast Moirai prediction"""
150
+ try:
151
+ from gluonts.dataset.common import ListDataset
152
+
153
+ dataset = ListDataset([{
154
+ "item_id": "stock",
155
+ "start": "2023-01-01",
156
+ "target": data[-self.context_length:].tolist()
157
+ }], freq='D')
158
+
159
+ predictor = model.create_predictor(
160
+ batch_size=1,
161
+ num_parallel_samples=10
162
+ )
163
+
164
+ forecasts = list(predictor.predict(dataset))
165
+ forecast = forecasts[0]
166
+
167
+ predictions = {
168
+ 'mean': forecast.mean,
169
+ 'q10': forecast.quantile(0.1),
170
+ 'q90': forecast.quantile(0.9),
171
+ 'std': np.std(forecast.samples, axis=0)
172
+ }
173
+
174
+ return predictions
175
+
176
+ except Exception as e:
177
+ return None
178
+
179
+ # Initialize analyzer globally for caching
180
+ analyzer = FastAIStockAnalyzer()
181
+
182
+ def analyze_stock(stock_symbol, model_choice, investment_amount, progress=gr.Progress()):
183
+ """Main analysis function for Gradio"""
184
+
185
+ progress(0.1, desc="Fetching stock data...")
186
+
187
+ # Fetch data
188
+ stock_data, stock_info = analyzer.fetch_stock_data(stock_symbol)
189
+
190
+ if stock_data is None or len(stock_data) < 50:
191
+ return (
192
+ "❌ Error: Insufficient data for analysis. Please check the stock symbol.",
193
+ None,
194
+ None,
195
+ "N/A",
196
+ "N/A"
197
+ )
198
+
199
+ current_price = stock_data['Close'].iloc[-1]
200
+ company_name = stock_info.get('longName', stock_symbol) if stock_info else stock_symbol
201
+
202
+ progress(0.3, desc="Loading AI model...")
203
+
204
+ # Load model
205
+ model_type = "chronos" if "Chronos" in model_choice else "moirai"
206
+
207
+ if model_type == "chronos":
208
+ model, loaded_type = analyzer.load_chronos_tiny()
209
+ model_name = "Amazon Chronos Tiny"
210
+ else:
211
+ model, loaded_type = analyzer.load_moirai_small()
212
+ model_name = "Salesforce Moirai Small"
213
+
214
+ if model is None:
215
+ return (
216
+ "❌ Error: Failed to load AI model. Please try again.",
217
+ None,
218
+ None,
219
+ "N/A",
220
+ "N/A"
221
+ )
222
+
223
+ progress(0.6, desc="Generating AI predictions...")
224
+
225
+ # Generate predictions
226
+ if model_type == "chronos":
227
+ predictions = analyzer.predict_chronos_fast(model, stock_data['Close'].values)
228
+ else:
229
+ predictions = analyzer.predict_moirai_fast(model, stock_data['Close'].values)
230
+
231
+ if predictions is None:
232
+ return (
233
+ "❌ Error: Prediction failed. Please try again.",
234
+ None,
235
+ None,
236
+ "N/A",
237
+ "N/A"
238
+ )
239
+
240
+ progress(0.8, desc="Calculating investment scenarios...")
241
+
242
+ # Analysis results
243
+ mean_pred = predictions['mean']
244
+ final_pred = mean_pred[-1]
245
+ week_change = ((final_pred - current_price) / current_price) * 100
246
+
247
+ # Decision logic
248
+ if week_change > 5:
249
+ decision = "🟒 STRONG BUY"
250
+ explanation = "AI expects significant gains!"
251
+ elif week_change > 2:
252
+ decision = "🟒 BUY"
253
+ explanation = "AI expects moderate gains"
254
+ elif week_change < -5:
255
+ decision = "πŸ”΄ STRONG SELL"
256
+ explanation = "AI expects significant losses"
257
+ elif week_change < -2:
258
+ decision = "πŸ”΄ SELL"
259
+ explanation = "AI expects losses"
260
+ else:
261
+ decision = "βšͺ HOLD"
262
+ explanation = "AI expects stable prices"
263
+
264
+ # Create analysis text
265
+ analysis_text = f"""
266
+ # 🎯 {company_name} ({stock_symbol}) Analysis
267
+
268
+ ## πŸ€– AI RECOMMENDATION: {decision}
269
+ **{explanation}**
270
+ *Powered by {model_name}*
271
+
272
+ ## πŸ“Š Key Metrics
273
+ - **Current Price**: ${current_price:.2f}
274
+ - **7-Day Prediction**: ${final_pred:.2f} ({week_change:+.2f}%)
275
+ - **AI Confidence**: {min(100, max(50, 70 + abs(week_change) * 1.5)):.0f}%
276
+ - **Model Used**: {model_name}
277
+
278
+ ## πŸ’° Investment Scenario (${investment_amount:,.0f})
279
+ - **Shares**: {investment_amount/current_price:.2f}
280
+ - **Predicted Value**: ${investment_amount + ((final_pred - current_price) * (investment_amount/current_price)):,.2f}
281
+ - **Profit/Loss**: ${((final_pred - current_price) * (investment_amount/current_price)):+,.2f} ({week_change:+.2f}%)
282
+
283
+ ⚠️ **DISCLAIMER**: This is AI-generated analysis for educational purposes only. Not financial advice.
284
+ """
285
+
286
+ progress(0.9, desc="Creating charts...")
287
+
288
+ # Create chart
289
+ fig = go.Figure()
290
+
291
+ # Historical data (last 30 days)
292
+ recent = stock_data.tail(30)
293
+ fig.add_trace(go.Scatter(
294
+ x=recent.index,
295
+ y=recent['Close'],
296
+ mode='lines',
297
+ name='Historical Price',
298
+ line=dict(color='blue', width=2)
299
+ ))
300
+
301
+ # Predictions
302
+ future_dates = pd.date_range(
303
+ start=stock_data.index[-1] + pd.Timedelta(days=1),
304
+ periods=7,
305
+ freq='D'
306
+ )
307
+
308
+ fig.add_trace(go.Scatter(
309
+ x=future_dates,
310
+ y=mean_pred,
311
+ mode='lines+markers',
312
+ name='AI Prediction',
313
+ line=dict(color='red', width=3),
314
+ marker=dict(size=8)
315
+ ))
316
+
317
+ # Confidence bands
318
+ if 'q10' in predictions and 'q90' in predictions:
319
+ fig.add_trace(go.Scatter(
320
+ x=future_dates.tolist() + future_dates[::-1].tolist(),
321
+ y=predictions['q90'].tolist() + predictions['q10'][::-1].tolist(),
322
+ fill='toself',
323
+ fillcolor='rgba(255,0,0,0.1)',
324
+ line=dict(color='rgba(255,255,255,0)'),
325
+ name='Confidence Range',
326
+ showlegend=True
327
+ ))
328
+
329
+ fig.update_layout(
330
+ title=f"{stock_symbol} - AI Stock Forecast",
331
+ xaxis_title="Date",
332
+ yaxis_title="Price ($)",
333
+ height=500,
334
+ showlegend=True,
335
+ template="plotly_white"
336
+ )
337
+
338
+ progress(1.0, desc="Analysis complete!")
339
+
340
+ # Create summary metrics
341
+ day_change = stock_data['Close'].iloc[-1] - stock_data['Close'].iloc[-2]
342
+ day_change_pct = (day_change / stock_data['Close'].iloc[-2]) * 100
343
+
344
+ current_metrics = f"${current_price:.2f} ({day_change_pct:+.2f}%)"
345
+ prediction_metrics = f"${final_pred:.2f} ({week_change:+.2f}%)"
346
+
347
+ return (
348
+ analysis_text,
349
+ fig,
350
+ decision,
351
+ current_metrics,
352
+ prediction_metrics
353
+ )
354
+
355
+ # Create Gradio interface[1][2][9][12]
356
+ with gr.Blocks(
357
+ theme=gr.themes.Soft(),
358
+ title="⚑ Fast AI Stock Predictor",
359
+ css="footer {visibility: hidden}"
360
+ ) as demo:
361
+
362
+ gr.HTML("""
363
+ <div style="text-align: center; padding: 20px;">
364
+ <h1>⚑ Fast AI Stock Predictor</h1>
365
+ <p><strong>πŸ€– Powered by Amazon Chronos & Salesforce Moirai</strong></p>
366
+ <p style="color: #666; font-size: 14px;">⚠️ Educational use only - Not financial advice</p>
367
+ </div>
368
+ """)
369
+
370
+ with gr.Row():
371
+ with gr.Column(scale=1):
372
+ gr.HTML("<h3>🎯 Configuration</h3>")
373
+
374
+ stock_input = gr.Dropdown(
375
+ choices=["AAPL", "GOOGL", "MSFT", "TSLA", "AMZN", "META", "NFLX", "NVDA"],
376
+ value="AAPL",
377
+ label="Select Stock",
378
+ allow_custom_value=True,
379
+ info="Choose from popular stocks or enter custom symbol"
380
+ )
381
+
382
+ model_input = gr.Radio(
383
+ choices=["πŸš€ Chronos (Fast)", "🎯 Moirai (Accurate)"],
384
+ value="πŸš€ Chronos (Fast)",
385
+ label="AI Model",
386
+ info="Chronos: Faster | Moirai: More accurate"
387
+ )
388
+
389
+ investment_input = gr.Slider(
390
+ minimum=500,
391
+ maximum=50000,
392
+ value=5000,
393
+ step=500,
394
+ label="Investment Amount ($)",
395
+ info="Amount to analyze for profit/loss scenarios"
396
+ )
397
+
398
+ analyze_btn = gr.Button(
399
+ "πŸš€ Analyze Stock",
400
+ variant="primary",
401
+ size="lg"
402
+ )
403
+
404
+ with gr.Column(scale=2):
405
+ gr.HTML("<h3>πŸ“Š Results</h3>")
406
+
407
+ with gr.Row():
408
+ current_price_display = gr.Textbox(
409
+ label="Current Price",
410
+ interactive=False,
411
+ container=True
412
+ )
413
+ prediction_display = gr.Textbox(
414
+ label="7-Day Prediction",
415
+ interactive=False,
416
+ container=True
417
+ )
418
+ decision_display = gr.Textbox(
419
+ label="AI Decision",
420
+ interactive=False,
421
+ container=True
422
+ )
423
+
424
+ with gr.Row():
425
+ analysis_output = gr.Markdown(
426
+ label="Analysis Report",
427
+ value="Click 'Analyze Stock' to generate AI-powered analysis..."
428
+ )
429
+
430
+ with gr.Row():
431
+ chart_output = gr.Plot(
432
+ label="Price Chart & Predictions",
433
+ container=True
434
+ )
435
+
436
+ # Event handlers
437
+ analyze_btn.click(
438
+ fn=analyze_stock,
439
+ inputs=[stock_input, model_input, investment_input],
440
+ outputs=[
441
+ analysis_output,
442
+ chart_output,
443
+ decision_display,
444
+ current_price_display,
445
+ prediction_display
446
+ ]
447
+ )
448
+
449
+ # Examples
450
+ gr.Examples(
451
+ examples=[
452
+ ["AAPL", "πŸš€ Chronos (Fast)", 5000],
453
+ ["TSLA", "🎯 Moirai (Accurate)", 10000],
454
+ ["GOOGL", "πŸš€ Chronos (Fast)", 2500],
455
+ ],
456
+ inputs=[stock_input, model_input, investment_input],
457
+ label="Try these examples:"
458
+ )
459
+
460
+ if __name__ == "__main__":
461
+ demo.launch(share=True)