AjaykumarPilla commited on
Commit
a898965
Β·
verified Β·
1 Parent(s): b83e695

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +72 -21
app.py CHANGED
@@ -1,29 +1,42 @@
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
  return prophet_df
17
 
18
- # Train or update Prophet model with user-provided usage series
19
  def train_model_with_usage(usage_series):
20
- print("Training with changepoint_prior_scale=0.01, usage:", usage_series) # Debug
21
  prophet_df = prepare_prophet_data(usage_series)
22
  model = Prophet(
23
  yearly_seasonality=False,
24
  weekly_seasonality=True,
25
  daily_seasonality=True,
26
- changepoint_prior_scale=0.01
 
27
  )
28
  model.fit(prophet_df)
29
  return model
@@ -32,9 +45,7 @@ def train_model_with_usage(usage_series):
32
  def make_forecast(model, periods):
33
  future = model.make_future_dataframe(periods=periods)
34
  forecast = model.predict(future)
35
- daily_forecasts = forecast['yhat'].tail(periods).tolist()
36
- print(f"Daily forecasts for {periods} days:", [round(y) for y in daily_forecasts]) # Debug
37
- return round(sum(max(0, y) for y in daily_forecasts)) # Clip negative values
38
 
39
  # Function to validate input
40
  def validate_usage_series(usage_str):
@@ -51,9 +62,8 @@ def validate_usage_series(usage_str):
51
  # Main Streamlit app
52
  def main():
53
  st.title("SmartLab Consumables Forecast")
54
- if st.button("Clear Cache"):
55
- st.cache_resource.clear()
56
- st.write("Cache cleared!")
57
 
58
  st.header("Input Parameters")
59
  consumable_type = st.selectbox("Consumable Type", ['Filters', 'Reagents', 'Vials'])
@@ -65,7 +75,6 @@ def main():
65
  if error:
66
  st.error(error)
67
  return
68
- st.write("Debug: Input usage series:", usage_list) # Debug
69
 
70
  try:
71
  model = train_model_with_usage(usage_list)
@@ -85,25 +94,67 @@ def main():
85
  st.header("Threshold Alerts")
86
  if current_stock < forecast_7:
87
  st.warning(f"Alert: Current stock ({current_stock}) is below 7-day forecast ({forecast_7}). 🚩")
88
- else:
89
- st.write("No alert for 7-day forecast.")
90
  if current_stock < forecast_14:
91
  st.warning(f"Alert: Current stock ({current_stock}) is below 14-day forecast ({forecast_14}). 🚩")
92
- else:
93
- st.write("No alert for 14-day forecast.")
94
  if current_stock < forecast_30:
95
  st.warning(f"Alert: Current stock ({current_stock}) is below 30-day forecast ({forecast_30}). 🚩")
96
- else:
97
- st.write("No alert for 30-day forecast.")
98
 
99
  st.header("Order Suggestions")
100
- order_7 = max(0, round(forecast_7 - current_stock))
101
- order_14 = max(0, round(forecast_14 - current_stock))
102
- order_30 = max(0, round(forecast_30 - current_stock))
103
-
104
  st.write(f"**For 7 Days**: Order {order_7} additional units.")
105
  st.write(f"**For 14 Days**: Order {order_14} additional units.")
106
  st.write(f"**For 30 Days**: Order {order_30} additional units.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
107
 
108
  if __name__ == "__main__":
109
- main()
 
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
  end_date = datetime.now()
22
  start_date = end_date - timedelta(days=len(usage_series) - 1)
23
  dates = [start_date + timedelta(days=i) for i in range(len(usage_series))]
24
+
25
  prophet_df = pd.DataFrame({
26
  'ds': dates,
27
  'y': usage_series
28
  })
29
  return prophet_df
30
 
31
+ # Train or update Prophet model with reduced sensitivity
32
  def train_model_with_usage(usage_series):
 
33
  prophet_df = prepare_prophet_data(usage_series)
34
  model = Prophet(
35
  yearly_seasonality=False,
36
  weekly_seasonality=True,
37
  daily_seasonality=True,
38
+ changepoint_prior_scale=0.01, # πŸ‘ˆ Reduced sensitivity to recent changes
39
+ changepoint_range=0.6 # πŸ‘ˆ Only look at early 60% of data for trend changes
40
  )
41
  model.fit(prophet_df)
42
  return model
 
45
  def make_forecast(model, periods):
46
  future = model.make_future_dataframe(periods=periods)
47
  forecast = model.predict(future)
48
+ return round(forecast['yhat'].tail(periods).sum())
 
 
49
 
50
  # Function to validate input
51
  def validate_usage_series(usage_str):
 
62
  # Main Streamlit app
63
  def main():
64
  st.title("SmartLab Consumables Forecast")
65
+
66
+ models = load_model()
 
67
 
68
  st.header("Input Parameters")
69
  consumable_type = st.selectbox("Consumable Type", ['Filters', 'Reagents', 'Vials'])
 
75
  if error:
76
  st.error(error)
77
  return
 
78
 
79
  try:
80
  model = train_model_with_usage(usage_list)
 
94
  st.header("Threshold Alerts")
95
  if current_stock < forecast_7:
96
  st.warning(f"Alert: Current stock ({current_stock}) is below 7-day forecast ({forecast_7}). 🚩")
 
 
97
  if current_stock < forecast_14:
98
  st.warning(f"Alert: Current stock ({current_stock}) is below 14-day forecast ({forecast_14}). 🚩")
 
 
99
  if current_stock < forecast_30:
100
  st.warning(f"Alert: Current stock ({current_stock}) is below 30-day forecast ({forecast_30}). 🚩")
 
 
101
 
102
  st.header("Order Suggestions")
103
+ order_7 = max(0, forecast_7 - current_stock)
104
+ order_14 = max(0, forecast_14 - current_stock)
105
+ order_30 = max(0, forecast_30 - current_stock)
 
106
  st.write(f"**For 7 Days**: Order {order_7} additional units.")
107
  st.write(f"**For 14 Days**: Order {order_14} additional units.")
108
  st.write(f"**For 30 Days**: Order {order_30} additional units.")
109
+
110
+ st.header("Forecast Visualization")
111
+ forecast_data = pd.DataFrame({
112
+ 'Period': ['7 Days', '14 Days', '30 Days'],
113
+ 'Units': [forecast_7, forecast_14, forecast_30]
114
+ })
115
+ fig_forecast = go.Figure()
116
+ fig_forecast.add_trace(go.Scatter(
117
+ x=forecast_data['Period'],
118
+ y=forecast_data['Units'],
119
+ mode='lines+markers',
120
+ name='Forecasted Units',
121
+ line=dict(color='blue'),
122
+ marker=dict(size=10)
123
+ ))
124
+ fig_forecast.update_layout(
125
+ title='Consumable Usage Forecast',
126
+ xaxis_title='Time Period',
127
+ yaxis_title='Units',
128
+ template='plotly_white'
129
+ )
130
+ st.plotly_chart(fig_forecast)
131
+
132
+ st.header("Threshold Alerts Visualization")
133
+ alert_data = pd.DataFrame({
134
+ 'Category': ['Current Stock', '7-Day Forecast', '14-Day Forecast', '30-Day Forecast'],
135
+ 'Units': [current_stock, forecast_7, forecast_14, forecast_30],
136
+ 'Alert': [
137
+ False,
138
+ current_stock < forecast_7,
139
+ current_stock < forecast_14,
140
+ current_stock < forecast_30
141
+ ]
142
+ })
143
+ fig_alerts = go.Figure()
144
+ fig_alerts.add_trace(go.Bar(
145
+ x=alert_data['Category'],
146
+ y=alert_data['Units'],
147
+ marker_color=['green'] + ['red' if alert else 'blue' for alert in alert_data['Alert'][1:]],
148
+ text=[f"🚩" if alert else "" for alert in alert_data['Alert']],
149
+ textposition='auto'
150
+ ))
151
+ fig_alerts.update_layout(
152
+ title='Stock vs Forecast with Alerts (🚩 indicates low stock)',
153
+ xaxis_title='Category',
154
+ yaxis_title='Units',
155
+ template='plotly_white'
156
+ )
157
+ st.plotly_chart(fig_alerts)
158
 
159
  if __name__ == "__main__":
160
+ main()