krishna1705 commited on
Commit
b41456e
ยท
verified ยท
1 Parent(s): 30d2918

Upload app.py

Browse files
Files changed (1) hide show
  1. app.py +517 -0
app.py ADDED
@@ -0,0 +1,517 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # ========================
2
+ # IMPORTS
3
+ # ========================
4
+ import os
5
+ import pandas as pd
6
+ import requests
7
+ import numpy as np
8
+ from sklearn.preprocessing import MinMaxScaler
9
+ from sklearn.metrics import mean_absolute_error, mean_squared_error
10
+ from tensorflow.keras.models import Sequential
11
+ from tensorflow.keras.layers import LSTM, Dense
12
+ import streamlit as st
13
+ from prophet import Prophet
14
+ import plotly.graph_objects as go
15
+ import math
16
+
17
+ # ========================
18
+ # CONFIGURATION
19
+ # ========================
20
+ API_KEY = "579b464db66ec23bdd000001cff99e32ded74c1e60ee264b550dd5c6"
21
+ RESOURCE_ID = "35985678-0d79-46b4-9ed6-6f13308a1d24"
22
+ TRAIN_EPOCHS = 10
23
+ FORECAST_HORIZON = 30
24
+ LOOK_BACK = 7
25
+
26
+ FORECAST_DIR = "forecasts"
27
+ os.makedirs(FORECAST_DIR, exist_ok=True)
28
+
29
+ # ========================
30
+ # PAGE SETUP
31
+ # ========================
32
+ st.set_page_config(
33
+ page_title="๐ŸŒพ Commodity Price Predictor",
34
+ page_icon="๐ŸŒฑ",
35
+ layout="wide",
36
+ initial_sidebar_state="expanded"
37
+ )
38
+
39
+ st.markdown("""
40
+ <style>
41
+ /* Main container styling */
42
+ .main {
43
+ background: linear-gradient(135deg, #f5f7fa 0%, #e8f5e9 100%);
44
+ padding: 2rem;
45
+ }
46
+
47
+ /* Header styling */
48
+ h1 {
49
+ text-align: center;
50
+ color: #1b5e20;
51
+ font-size: 3rem;
52
+ font-weight: 700;
53
+ margin-bottom: 0.5rem;
54
+ text-shadow: 2px 2px 4px rgba(0,0,0,0.1);
55
+ }
56
+
57
+ h2 {
58
+ color: #2e7d32;
59
+ border-left: 4px solid #4caf50;
60
+ padding-left: 1rem;
61
+ margin-top: 2rem;
62
+ }
63
+
64
+ h3 {
65
+ color: #388e3c;
66
+ }
67
+
68
+ /* Subtitle */
69
+ .subtitle {
70
+ text-align: center;
71
+ color: #558b2f;
72
+ font-size: 1.2rem;
73
+ margin-bottom: 2rem;
74
+ font-weight: 400;
75
+ }
76
+
77
+ /* Button styling */
78
+ .stButton>button {
79
+ background: linear-gradient(135deg, #2e7d32 0%, #4caf50 100%);
80
+ color: white;
81
+ border-radius: 12px;
82
+ border: none;
83
+ padding: 12px 32px;
84
+ font-size: 1.1rem;
85
+ font-weight: 600;
86
+ box-shadow: 0 4px 12px rgba(46, 125, 50, 0.3);
87
+ transition: all 0.3s ease;
88
+ width: 100%;
89
+ }
90
+ .stButton>button:hover {
91
+ background: linear-gradient(135deg, #1b5e20 0%, #2e7d32 100%);
92
+ transform: translateY(-2px);
93
+ box-shadow: 0 6px 16px rgba(46, 125, 50, 0.4);
94
+ }
95
+
96
+ /* Metric box styling */
97
+ .metric-box {
98
+ background: linear-gradient(135deg, #ffffff 0%, #f1f8e9 100%);
99
+ border-radius: 16px;
100
+ padding: 24px;
101
+ box-shadow: 0px 4px 12px rgba(0,0,0,0.08);
102
+ text-align: center;
103
+ border: 2px solid #c5e1a5;
104
+ transition: transform 0.3s ease;
105
+ }
106
+ .metric-box:hover {
107
+ transform: translateY(-5px);
108
+ box-shadow: 0px 8px 20px rgba(0,0,0,0.12);
109
+ }
110
+ .metric-box h4 {
111
+ color: #2e7d32;
112
+ margin-bottom: 1rem;
113
+ font-size: 1.3rem;
114
+ }
115
+ .metric-value {
116
+ font-size: 1.8rem;
117
+ font-weight: 700;
118
+ color: #1b5e20;
119
+ margin: 0.5rem 0;
120
+ }
121
+
122
+ /* Info boxes */
123
+ .info-card {
124
+ background: white;
125
+ border-radius: 12px;
126
+ padding: 20px;
127
+ box-shadow: 0 2px 8px rgba(0,0,0,0.06);
128
+ margin: 1rem 0;
129
+ border-left: 4px solid #4caf50;
130
+ }
131
+
132
+ /* Select box styling */
133
+ .stSelectbox > div > div {
134
+ background-color: white;
135
+ border-radius: 10px;
136
+ border: 2px solid #c5e1a5;
137
+ }
138
+
139
+ /* Success message */
140
+ .success-banner {
141
+ background: linear-gradient(135deg, #4caf50 0%, #81c784 100%);
142
+ color: white;
143
+ padding: 1.5rem;
144
+ border-radius: 12px;
145
+ text-align: center;
146
+ font-size: 1.3rem;
147
+ font-weight: 600;
148
+ box-shadow: 0 4px 12px rgba(76, 175, 80, 0.3);
149
+ margin: 2rem 0;
150
+ }
151
+
152
+ /* DataFrame styling */
153
+ .dataframe {
154
+ border-radius: 10px;
155
+ overflow: hidden;
156
+ box-shadow: 0 2px 8px rgba(0,0,0,0.08);
157
+ }
158
+
159
+ /* Section divider */
160
+ .divider {
161
+ height: 2px;
162
+ background: linear-gradient(90deg, transparent, #4caf50, transparent);
163
+ margin: 2rem 0;
164
+ }
165
+ </style>
166
+ """, unsafe_allow_html=True)
167
+
168
+ # ========================
169
+ # LOAD DATA
170
+ # ========================
171
+ @st.cache_data
172
+ def load_data():
173
+ url = f"https://api.data.gov.in/resource/{RESOURCE_ID}?api-key={API_KEY}&format=json&limit=10000"
174
+ response = requests.get(url)
175
+ data = response.json()
176
+ df = pd.DataFrame(data["records"])
177
+ df.columns = [c.replace(" ", "_") for c in df.columns]
178
+ df["Arrival_Date"] = pd.to_datetime(df["Arrival_Date"], dayfirst=True)
179
+ df["avg_price"] = (
180
+ df[["Min_Price", "Max_Price", "Modal_Price"]].astype(float).mean(axis=1)
181
+ )
182
+ df = df.dropna(subset=["Commodity_Code", "avg_price", "Commodity"])
183
+ return df
184
+
185
+ df = load_data()
186
+
187
+ # ========================
188
+ # HELPERS
189
+ # ========================
190
+ def prepare_series(df, code):
191
+ temp = df[df["Commodity_Code"] == code][["Arrival_Date", "avg_price"]]
192
+ temp = temp.groupby("Arrival_Date").mean().reset_index()
193
+ temp = temp.sort_values("Arrival_Date")
194
+ temp = temp.rename(columns={"Arrival_Date": "timestamp", "avg_price": "value"})
195
+ return temp
196
+
197
+ def fill_dates(series_df):
198
+ all_days = pd.date_range(series_df["timestamp"].min(), series_df["timestamp"].max(), freq="D")
199
+ series_df = series_df.set_index("timestamp").reindex(all_days).interpolate().reset_index()
200
+ series_df.columns = ["timestamp", "value"]
201
+ return series_df
202
+
203
+ def create_dataset(series, look_back=10):
204
+ X, y = [], []
205
+ for i in range(len(series) - look_back):
206
+ X.append(series[i : i + look_back])
207
+ y.append(series[i + look_back])
208
+ return np.array(X), np.array(y)
209
+
210
+ # ========================
211
+ # UI HEADER
212
+ # ========================
213
+ st.title("๐ŸŒพ Commodity Price Predictor")
214
+ st.markdown('<p class="subtitle">Predict future commodity prices using Deep Learning (LSTM), Facebook Prophet, and hybrid ensemble modeling</p>', unsafe_allow_html=True)
215
+
216
+ # ========================
217
+ # SIDEBAR
218
+ # ========================
219
+ with st.sidebar:
220
+ st.header("๐Ÿ“Š Forecast Settings")
221
+ st.markdown("---")
222
+
223
+ commodity_list = df["Commodity"].unique()
224
+ selected_commodity = st.selectbox(
225
+ "๐ŸŒพ Select Commodity:",
226
+ sorted(commodity_list),
227
+ help="Choose a commodity to forecast"
228
+ )
229
+
230
+ st.markdown("---")
231
+ st.subheader("โš™๏ธ Model Configuration")
232
+ st.info(f"""
233
+ **Current Settings:**
234
+ - Forecast Horizon: {FORECAST_HORIZON} days
235
+ - Look Back Period: {LOOK_BACK} days
236
+ - Training Epochs: {TRAIN_EPOCHS}
237
+ - Hybrid Weight: 60% LSTM, 40% Prophet
238
+ """)
239
+
240
+ st.markdown("---")
241
+ st.subheader("๐Ÿ“ˆ About the Models")
242
+ with st.expander("LSTM Neural Network"):
243
+ st.write("Deep learning model that learns temporal patterns in price data")
244
+ with st.expander("Prophet"):
245
+ st.write("Facebook's time series forecasting tool optimized for business data")
246
+ with st.expander("Hybrid Ensemble"):
247
+ st.write("Combines both models for improved accuracy and stability")
248
+
249
+ # ========================
250
+ # MAIN CONTENT
251
+ # ========================
252
+ col1, col2, col3 = st.columns([1, 2, 1])
253
+ with col2:
254
+ forecast_button = st.button("๐Ÿ”ฎ Generate Forecast", use_container_width=True)
255
+
256
+ if forecast_button:
257
+ code = df[df["Commodity"] == selected_commodity]["Commodity_Code"].iloc[0]
258
+
259
+ # Info card
260
+ st.markdown(f'<div class="info-card">๐Ÿ”„ Processing <b>{selected_commodity}</b> (Code: {code})...</div>', unsafe_allow_html=True)
261
+
262
+ # Prepare and clean data
263
+ series = fill_dates(prepare_series(df, code))
264
+ values = series["value"].values.reshape(-1, 1)
265
+ scaler = MinMaxScaler()
266
+ scaled = scaler.fit_transform(values)
267
+ X, y = create_dataset(scaled, LOOK_BACK)
268
+ X = np.reshape(X, (X.shape[0], X.shape[1], 1))
269
+
270
+ # ========================
271
+ # PROGRESS TRACKING
272
+ # ========================
273
+ progress_bar = st.progress(0)
274
+ status_text = st.empty()
275
+
276
+ # ========================
277
+ # LSTM MODEL
278
+ # ========================
279
+ status_text.text("๐Ÿค– Training LSTM model...")
280
+ progress_bar.progress(20)
281
+
282
+ model = Sequential([
283
+ LSTM(32, input_shape=(LOOK_BACK, 1), activation="tanh"),
284
+ Dense(1)
285
+ ])
286
+ model.compile(optimizer="adam", loss="mse")
287
+ model.fit(X, y, epochs=TRAIN_EPOCHS, batch_size=16, verbose=0)
288
+
289
+ progress_bar.progress(40)
290
+ status_text.text("โœ… LSTM training complete")
291
+
292
+ # Forecast with LSTM
293
+ last_seq = scaled[-LOOK_BACK:]
294
+ preds = []
295
+ for _ in range(FORECAST_HORIZON):
296
+ pred = model.predict(last_seq.reshape(1, LOOK_BACK, 1), verbose=0)
297
+ preds.append(pred[0][0])
298
+ last_seq = np.append(last_seq[1:], pred, axis=0)
299
+ forecast_lstm = scaler.inverse_transform(np.array(preds).reshape(-1, 1)).flatten()
300
+
301
+ # ========================
302
+ # PROPHET MODEL
303
+ # ========================
304
+ status_text.text("๐Ÿ“ˆ Training Prophet model...")
305
+ progress_bar.progress(60)
306
+
307
+ prophet_df = series.rename(columns={"timestamp": "ds", "value": "y"})
308
+ model_prophet = Prophet()
309
+ model_prophet.fit(prophet_df)
310
+ future = model_prophet.make_future_dataframe(periods=FORECAST_HORIZON)
311
+ forecast_prophet = model_prophet.predict(future)
312
+ prophet_values = forecast_prophet["yhat"].tail(FORECAST_HORIZON).values
313
+
314
+ progress_bar.progress(80)
315
+ status_text.text("โœ… Prophet training complete")
316
+
317
+ # ========================
318
+ # HYBRID (FINAL) FORECAST
319
+ # ========================
320
+ status_text.text("๐ŸŒฟ Generating hybrid forecast...")
321
+ progress_bar.progress(90)
322
+
323
+ final_pred = 0.6 * forecast_lstm + 0.4 * prophet_values
324
+
325
+ progress_bar.progress(100)
326
+ status_text.text("โœ… Forecast complete!")
327
+
328
+ st.markdown('<div class="divider"></div>', unsafe_allow_html=True)
329
+
330
+ # ========================
331
+ # VISUALIZATION
332
+ # ========================
333
+ st.subheader("๐Ÿ“Š Forecast Visualization")
334
+
335
+ # Create tabs for different views
336
+ tab1, tab2, tab3 = st.tabs(["๐Ÿ“ˆ Hybrid Forecast", "๐Ÿ” Model Comparison", "๐Ÿ“‰ Historical Context"])
337
+
338
+ with tab1:
339
+ fig_final = go.Figure()
340
+ fig_final.add_trace(go.Scatter(
341
+ y=final_pred,
342
+ mode="lines+markers",
343
+ name="Hybrid Forecast",
344
+ line=dict(color="#2e7d32", width=3),
345
+ marker=dict(size=6),
346
+ fill='tozeroy',
347
+ fillcolor='rgba(46, 125, 50, 0.1)'
348
+ ))
349
+ fig_final.update_layout(
350
+ title=f"๐ŸŒพ 30-Day Hybrid Forecast for {selected_commodity}",
351
+ xaxis_title="Days Ahead",
352
+ yaxis_title="Predicted Price (โ‚น)",
353
+ plot_bgcolor="white",
354
+ hovermode="x unified",
355
+ height=500,
356
+ font=dict(size=12)
357
+ )
358
+ st.plotly_chart(fig_final, use_container_width=True)
359
+
360
+ with tab2:
361
+ fig_compare = go.Figure()
362
+ fig_compare.add_trace(go.Scatter(
363
+ y=forecast_lstm,
364
+ mode="lines",
365
+ name="LSTM",
366
+ line=dict(color="#1976d2", dash="dot")
367
+ ))
368
+ fig_compare.add_trace(go.Scatter(
369
+ y=prophet_values,
370
+ mode="lines",
371
+ name="Prophet",
372
+ line=dict(color="#f57c00", dash="dash")
373
+ ))
374
+ fig_compare.add_trace(go.Scatter(
375
+ y=final_pred,
376
+ mode="lines+markers",
377
+ name="Hybrid Final",
378
+ line=dict(color="#2e7d32", width=3)
379
+ ))
380
+ fig_compare.update_layout(
381
+ title="Model Comparison",
382
+ xaxis_title="Days Ahead",
383
+ yaxis_title="Predicted Price (โ‚น)",
384
+ plot_bgcolor="white",
385
+ hovermode="x unified",
386
+ height=500
387
+ )
388
+ st.plotly_chart(fig_compare, use_container_width=True)
389
+
390
+ with tab3:
391
+ # Historical + Forecast
392
+ fig_hist = go.Figure()
393
+ hist_days = min(90, len(values))
394
+ fig_hist.add_trace(go.Scatter(
395
+ y=values[-hist_days:].flatten(),
396
+ mode="lines",
397
+ name="Historical Prices",
398
+ line=dict(color="#616161")
399
+ ))
400
+ fig_hist.add_trace(go.Scatter(
401
+ y=final_pred,
402
+ mode="lines",
403
+ name="Forecast",
404
+ line=dict(color="#2e7d32", width=2)
405
+ ))
406
+ fig_hist.update_layout(
407
+ title=f"Historical Prices (Last {hist_days} days) + Forecast",
408
+ xaxis_title="Time Period",
409
+ yaxis_title="Price (โ‚น)",
410
+ plot_bgcolor="white",
411
+ hovermode="x unified",
412
+ height=500
413
+ )
414
+ st.plotly_chart(fig_hist, use_container_width=True)
415
+
416
+ st.markdown('<div class="divider"></div>', unsafe_allow_html=True)
417
+
418
+ # ========================
419
+ # METRICS
420
+ # ========================
421
+ st.subheader("๐Ÿ“Š Model Performance Metrics")
422
+
423
+ # Calculate metrics (comparing last 30 days if available)
424
+ if len(values) >= FORECAST_HORIZON:
425
+ mae_lstm = mean_absolute_error(values[-FORECAST_HORIZON:], forecast_lstm[-FORECAST_HORIZON:])
426
+ rmse_lstm = math.sqrt(mean_squared_error(values[-FORECAST_HORIZON:], forecast_lstm[-FORECAST_HORIZON:]))
427
+ mae_prophet = mean_absolute_error(values[-FORECAST_HORIZON:], prophet_values)
428
+ rmse_prophet = math.sqrt(mean_squared_error(values[-FORECAST_HORIZON:], prophet_values))
429
+ else:
430
+ mae_lstm = rmse_lstm = mae_prophet = rmse_prophet = 0
431
+
432
+ col1, col2, col3 = st.columns(3)
433
+
434
+ with col1:
435
+ st.markdown(f'''
436
+ <div class="metric-box">
437
+ <h4>๐Ÿค– LSTM Model</h4>
438
+ <div class="metric-value">MAE: โ‚น{mae_lstm:.2f}</div>
439
+ <div>RMSE: โ‚น{rmse_lstm:.2f}</div>
440
+ </div>
441
+ ''', unsafe_allow_html=True)
442
+
443
+ with col2:
444
+ st.markdown(f'''
445
+ <div class="metric-box">
446
+ <h4>๐Ÿ“ˆ Prophet Model</h4>
447
+ <div class="metric-value">MAE: โ‚น{mae_prophet:.2f}</div>
448
+ <div>RMSE: โ‚น{rmse_prophet:.2f}</div>
449
+ </div>
450
+ ''', unsafe_allow_html=True)
451
+
452
+ with col3:
453
+ avg_pred = np.mean(final_pred)
454
+ min_pred = np.min(final_pred)
455
+ max_pred = np.max(final_pred)
456
+ st.markdown(f'''
457
+ <div class="metric-box">
458
+ <h4>๐ŸŒฟ Hybrid Forecast</h4>
459
+ <div class="metric-value">Avg: โ‚น{avg_pred:.2f}</div>
460
+ <div>Range: โ‚น{min_pred:.2f} - โ‚น{max_pred:.2f}</div>
461
+ </div>
462
+ ''', unsafe_allow_html=True)
463
+
464
+ st.markdown('<div class="divider"></div>', unsafe_allow_html=True)
465
+
466
+ # ========================
467
+ # FORECAST TABLE
468
+ # ========================
469
+ st.subheader("๐Ÿ“… Detailed Forecast Data")
470
+
471
+ forecast_df = pd.DataFrame({
472
+ "Day": np.arange(1, FORECAST_HORIZON + 1),
473
+ "LSTM_Forecast": forecast_lstm,
474
+ "Prophet_Forecast": prophet_values,
475
+ "Final_Hybrid": final_pred
476
+ })
477
+
478
+ st.dataframe(
479
+ forecast_df.style.format({
480
+ "LSTM_Forecast": "โ‚น{:.2f}",
481
+ "Prophet_Forecast": "โ‚น{:.2f}",
482
+ "Final_Hybrid": "โ‚น{:.2f}"
483
+ }).background_gradient(subset=["Final_Hybrid"], cmap="Greens"),
484
+ use_container_width=True,
485
+ height=400
486
+ )
487
+
488
+ # ========================
489
+ # SUMMARY & DOWNLOAD
490
+ # ========================
491
+ st.markdown(f'''
492
+ <div class="success-banner">
493
+ ๐ŸŽฏ Average Predicted Price (Hybrid): โ‚น{avg_pred:.2f}
494
+ </div>
495
+ ''', unsafe_allow_html=True)
496
+
497
+ filename = f"{selected_commodity.replace(' ', '_')}_{code}_forecast.csv"
498
+ forecast_df.to_csv(os.path.join(FORECAST_DIR, filename), index=False)
499
+
500
+ col1, col2, col3 = st.columns([1, 1, 1])
501
+ with col2:
502
+ st.download_button(
503
+ "๐Ÿ“ฅ Download Forecast CSV",
504
+ data=forecast_df.to_csv(index=False),
505
+ file_name=filename,
506
+ use_container_width=True
507
+ )
508
+
509
+ # ========================
510
+ # FOOTER
511
+ # ========================
512
+ st.markdown('<div class="divider"></div>', unsafe_allow_html=True)
513
+ st.markdown("""
514
+ <div style="text-align: center; color: #558b2f; padding: 2rem;">
515
+ <p>๐ŸŒฑ Powered by LSTM Neural Networks & Facebook Prophet | Data from Government of India API</p>
516
+ </div>
517
+ """, unsafe_allow_html=True)