AjaykumarPilla commited on
Commit
96c45a3
·
verified ·
1 Parent(s): 632f432

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +29 -82
app.py CHANGED
@@ -1,47 +1,45 @@
1
  import streamlit as st
2
  import pandas as pd
3
- import pickle
4
  from prophet import Prophet
5
  from datetime import datetime, timedelta
6
  import numpy as np
7
- import plotly.graph_objects as go
8
-
9
- # Load the trained models (optional, for initialization or fallback)
10
- @st.cache_resource
11
- def load_model():
12
- try:
13
- with open('model.pkl', 'rb') as f:
14
- models = pickle.load(f)
15
- return models
16
- except FileNotFoundError:
17
- return None
18
 
19
  # Prepare data for Prophet
20
  def prepare_prophet_data(usage_series):
21
- # Create a date range for the last 60 days
22
  end_date = datetime.now()
23
  start_date = end_date - timedelta(days=len(usage_series) - 1)
24
  dates = [start_date + timedelta(days=i) for i in range(len(usage_series))]
25
-
26
- # Create Prophet-compatible DataFrame
27
  prophet_df = pd.DataFrame({
28
  'ds': dates,
29
  'y': usage_series
30
  })
 
 
31
  return prophet_df
32
 
33
  # Train or update Prophet model with user-provided usage series
34
  def train_model_with_usage(usage_series):
 
35
  prophet_df = prepare_prophet_data(usage_series)
36
- model = Prophet(yearly_seasonality=False, weekly_seasonality=True, daily_seasonality=True)
 
 
 
 
 
 
37
  model.fit(prophet_df)
38
  return model
39
 
40
  # Function to make forecasts
41
  def make_forecast(model, periods):
42
  future = model.make_future_dataframe(periods=periods)
 
 
43
  forecast = model.predict(future)
44
- return round(forecast['yhat'].tail(periods).sum()) # Round to nearest integer
 
 
45
 
46
  # Function to validate input
47
  def validate_usage_series(usage_str):
@@ -58,110 +56,59 @@ def validate_usage_series(usage_str):
58
  # Main Streamlit app
59
  def main():
60
  st.title("SmartLab Consumables Forecast")
 
 
 
61
 
62
- # Load pre-trained models (optional, for reference)
63
- models = load_model()
64
-
65
- # Input form
66
  st.header("Input Parameters")
67
  consumable_type = st.selectbox("Consumable Type", ['Filters', 'Reagents', 'Vials'])
68
  usage_series = st.text_input("Last 60 Days Usage (comma-separated)", "")
69
  current_stock = st.number_input("Current Stock", min_value=0, value=0)
70
 
71
  if st.button("Generate Forecast"):
72
- # Validate inputs
73
  usage_list, error = validate_usage_series(usage_series)
74
  if error:
75
  st.error(error)
76
  return
 
77
 
78
- # Train a new model with the user-provided usage series
79
  try:
80
  model = train_model_with_usage(usage_list)
81
  except Exception as e:
82
  st.error(f"Error training model: {str(e)}")
83
  return
84
 
85
- # Forecast for 7, 14, and 30 days
86
  forecast_7 = make_forecast(model, 7)
87
  forecast_14 = make_forecast(model, 14)
88
  forecast_30 = make_forecast(model, 30)
89
 
90
- # Display forecasts
91
  st.header("Forecast Results")
92
  st.write(f"**7-Day Forecast**: {forecast_7} units")
93
  st.write(f"**14-Day Forecast**: {forecast_14} units")
94
  st.write(f"**30-Day Forecast**: {forecast_30} units")
95
 
96
- # Threshold alerting
97
  st.header("Threshold Alerts")
98
  if current_stock < forecast_7:
99
  st.warning(f"Alert: Current stock ({current_stock}) is below 7-day forecast ({forecast_7}). 🚩")
 
 
100
  if current_stock < forecast_14:
101
  st.warning(f"Alert: Current stock ({current_stock}) is below 14-day forecast ({forecast_14}). 🚩")
 
 
102
  if current_stock < forecast_30:
103
  st.warning(f"Alert: Current stock ({current_stock}) is below 30-day forecast ({forecast_30}). 🚩")
 
 
104
 
105
- # Order suggestions
106
  st.header("Order Suggestions")
107
- order_7 = max(0, round(forecast_7 - current_stock)) # Round to nearest integer
108
- order_14 = max(0, round(forecast_14 - current_stock)) # Round to nearest integer
109
- order_30 = max(0, round(forecast_30 - current_stock)) # Round to nearest integer
110
 
111
  st.write(f"**For 7 Days**: Order {order_7} additional units.")
112
  st.write(f"**For 14 Days**: Order {order_14} additional units.")
113
  st.write(f"**For 30 Days**: Order {order_30} additional units.")
114
-
115
- # Graphical representation for forecast
116
- st.header("Forecast Visualization")
117
- forecast_data = pd.DataFrame({
118
- 'Period': ['7 Days', '14 Days', '30 Days'],
119
- 'Units': [forecast_7, forecast_14, forecast_30]
120
- })
121
- fig_forecast = go.Figure()
122
- fig_forecast.add_trace(go.Scatter(
123
- x=forecast_data['Period'],
124
- y=forecast_data['Units'],
125
- mode='lines+markers',
126
- name='Forecasted Units',
127
- line=dict(color='blue'),
128
- marker=dict(size=10)
129
- ))
130
- fig_forecast.update_layout(
131
- title='Consumable Usage Forecast',
132
- xaxis_title='Time Period',
133
- yaxis_title='Units',
134
- template='plotly_white'
135
- )
136
- st.plotly_chart(fig_forecast)
137
-
138
- # Graphical representation for threshold alerts
139
- st.header("Threshold Alerts Visualization")
140
- alert_data = pd.DataFrame({
141
- 'Category': ['Current Stock', '7-Day Forecast', '14-Day Forecast', '30-Day Forecast'],
142
- 'Units': [current_stock, forecast_7, forecast_14, forecast_30],
143
- 'Alert': [
144
- False,
145
- current_stock < forecast_7,
146
- current_stock < forecast_14,
147
- current_stock < forecast_30
148
- ]
149
- })
150
- fig_alerts = go.Figure()
151
- fig_alerts.add_trace(go.Bar(
152
- x=alert_data['Category'],
153
- y=alert_data['Units'],
154
- marker_color=['green'] + ['red' if alert else 'blue' for alert in alert_data['Alert'][1:]],
155
- text=[f"🚩" if alert else "" for alert in alert_data['Alert']],
156
- textposition='auto'
157
- ))
158
- fig_alerts.update_layout(
159
- title='Stock vs Forecast with Alerts (🚩 indicates low stock)',
160
- xaxis_title='Category',
161
- yaxis_title='Units',
162
- template='plotly_white'
163
- )
164
- st.plotly_chart(fig_alerts)
165
 
166
  if __name__ == "__main__":
167
- main()
 
1
  import streamlit as st
2
  import pandas as pd
 
3
  from prophet import Prophet
4
  from datetime import datetime, timedelta
5
  import numpy as np
 
 
 
 
 
 
 
 
 
 
 
6
 
7
  # Prepare data for Prophet
8
  def prepare_prophet_data(usage_series):
 
9
  end_date = datetime.now()
10
  start_date = end_date - timedelta(days=len(usage_series) - 1)
11
  dates = [start_date + timedelta(days=i) for i in range(len(usage_series))]
 
 
12
  prophet_df = pd.DataFrame({
13
  'ds': dates,
14
  'y': usage_series
15
  })
16
+ prophet_df['cap'] = 60 # Max observed usage
17
+ prophet_df['floor'] = 0
18
  return prophet_df
19
 
20
  # Train or update Prophet model with user-provided usage series
21
  def train_model_with_usage(usage_series):
22
+ print("Training with changepoint_prior_scale=0.002, usage:", usage_series) # Debug
23
  prophet_df = prepare_prophet_data(usage_series)
24
+ model = Prophet(
25
+ yearly_seasonality=False,
26
+ weekly_seasonality=True,
27
+ daily_seasonality=True,
28
+ changepoint_prior_scale=0.002,
29
+ growth='logistic'
30
+ )
31
  model.fit(prophet_df)
32
  return model
33
 
34
  # Function to make forecasts
35
  def make_forecast(model, periods):
36
  future = model.make_future_dataframe(periods=periods)
37
+ future['cap'] = 60
38
+ future['floor'] = 0
39
  forecast = model.predict(future)
40
+ daily_forecasts = forecast['yhat'].tail(periods).tolist()
41
+ print(f"Daily forecasts for {periods} days:", [round(y) for y in daily_forecasts]) # Debug
42
+ return round(sum(max(0, y) for y in daily_forecasts)) # Clip negative values
43
 
44
  # Function to validate input
45
  def validate_usage_series(usage_str):
 
56
  # Main Streamlit app
57
  def main():
58
  st.title("SmartLab Consumables Forecast")
59
+ if st.button("Clear Cache"):
60
+ st.cache_resource.clear()
61
+ st.write("Cache cleared!")
62
 
 
 
 
 
63
  st.header("Input Parameters")
64
  consumable_type = st.selectbox("Consumable Type", ['Filters', 'Reagents', 'Vials'])
65
  usage_series = st.text_input("Last 60 Days Usage (comma-separated)", "")
66
  current_stock = st.number_input("Current Stock", min_value=0, value=0)
67
 
68
  if st.button("Generate Forecast"):
 
69
  usage_list, error = validate_usage_series(usage_series)
70
  if error:
71
  st.error(error)
72
  return
73
+ st.write("Debug: Input usage series:", usage_list) # Debug
74
 
 
75
  try:
76
  model = train_model_with_usage(usage_list)
77
  except Exception as e:
78
  st.error(f"Error training model: {str(e)}")
79
  return
80
 
 
81
  forecast_7 = make_forecast(model, 7)
82
  forecast_14 = make_forecast(model, 14)
83
  forecast_30 = make_forecast(model, 30)
84
 
 
85
  st.header("Forecast Results")
86
  st.write(f"**7-Day Forecast**: {forecast_7} units")
87
  st.write(f"**14-Day Forecast**: {forecast_14} units")
88
  st.write(f"**30-Day Forecast**: {forecast_30} units")
89
 
 
90
  st.header("Threshold Alerts")
91
  if current_stock < forecast_7:
92
  st.warning(f"Alert: Current stock ({current_stock}) is below 7-day forecast ({forecast_7}). 🚩")
93
+ else:
94
+ st.write("No alert for 7-day forecast.")
95
  if current_stock < forecast_14:
96
  st.warning(f"Alert: Current stock ({current_stock}) is below 14-day forecast ({forecast_14}). 🚩")
97
+ else:
98
+ st.write("No alert for 14-day forecast.")
99
  if current_stock < forecast_30:
100
  st.warning(f"Alert: Current stock ({current_stock}) is below 30-day forecast ({forecast_30}). 🚩")
101
+ else:
102
+ st.write("No alert for 30-day forecast.")
103
 
 
104
  st.header("Order Suggestions")
105
+ order_7 = max(0, round(forecast_7 - current_stock))
106
+ order_14 = max(0, round(forecast_14 - current_stock))
107
+ order_30 = max(0, round(forecast_30 - current_stock))
108
 
109
  st.write(f"**For 7 Days**: Order {order_7} additional units.")
110
  st.write(f"**For 14 Days**: Order {order_14} additional units.")
111
  st.write(f"**For 30 Days**: Order {order_30} additional units.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
112
 
113
  if __name__ == "__main__":
114
+ main()