AjaykumarPilla commited on
Commit
bc41d2b
Β·
verified Β·
1 Parent(s): 5ba9c8b

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +172 -0
app.py CHANGED
@@ -0,0 +1,172 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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(
37
+ yearly_seasonality=False,
38
+ weekly_seasonality=True,
39
+ daily_seasonality=True,
40
+ changepoint_prior_scale=0.01
41
+ )
42
+ model.fit(prophet_df)
43
+ return model
44
+
45
+ # Function to make forecasts
46
+ def make_forecast(model, periods):
47
+ future = model.make_future_dataframe(periods=periods)
48
+ forecast = model.predict(future)
49
+ return round(forecast['yhat'].tail(periods).sum()) # Round to nearest integer
50
+
51
+ # Function to validate input
52
+ def validate_usage_series(usage_str):
53
+ try:
54
+ usage_list = [float(x) for x in usage_str.split(',')]
55
+ if len(usage_list) != 60:
56
+ return None, "Usage series must contain exactly 60 values."
57
+ if any(x < 0 for x in usage_list):
58
+ return None, "Usage values must be non-negative."
59
+ return usage_list, None
60
+ except:
61
+ return None, "Invalid usage series format. Please enter 60 comma-separated numbers."
62
+
63
+ # Main Streamlit app
64
+ def main():
65
+ st.title("SmartLab Consumables Forecast")
66
+
67
+ # Load pre-trained models (optional, for reference)
68
+ models = load_model()
69
+
70
+ # Input form
71
+ st.header("Input Parameters")
72
+ consumable_type = st.selectbox("Consumable Type", ['Filters', 'Reagents', 'Vials'])
73
+ usage_series = st.text_input("Last 60 Days Usage (comma-separated)", "")
74
+ current_stock = st.number_input("Current Stock", min_value=0, value=0)
75
+
76
+ if st.button("Generate Forecast"):
77
+ # Validate inputs
78
+ usage_list, error = validate_usage_series(usage_series)
79
+ if error:
80
+ st.error(error)
81
+ return
82
+
83
+ # Train a new model with the user-provided usage series
84
+ try:
85
+ model = train_model_with_usage(usage_list)
86
+ except Exception as e:
87
+ st.error(f"Error training model: {str(e)}")
88
+ return
89
+
90
+ # Forecast for 7, 14, and 30 days
91
+ forecast_7 = make_forecast(model, 7)
92
+ forecast_14 = make_forecast(model, 14)
93
+ forecast_30 = make_forecast(model, 30)
94
+
95
+ # Display forecasts
96
+ st.header("Forecast Results")
97
+ st.write(f"**7-Day Forecast**: {forecast_7} units")
98
+ st.write(f"**14-Day Forecast**: {forecast_14} units")
99
+ st.write(f"**30-Day Forecast**: {forecast_30} units")
100
+
101
+ # Threshold alerting
102
+ st.header("Threshold Alerts")
103
+ if current_stock < forecast_7:
104
+ st.warning(f"Alert: Current stock ({current_stock}) is below 7-day forecast ({forecast_7}). 🚩")
105
+ if current_stock < forecast_14:
106
+ st.warning(f"Alert: Current stock ({current_stock}) is below 14-day forecast ({forecast_14}). 🚩")
107
+ if current_stock < forecast_30:
108
+ st.warning(f"Alert: Current stock ({current_stock}) is below 30-day forecast ({forecast_30}). 🚩")
109
+
110
+ # Order suggestions
111
+ st.header("Order Suggestions")
112
+ order_7 = max(0, round(forecast_7 - current_stock)) # Round to nearest integer
113
+ order_14 = max(0, round(forecast_14 - current_stock)) # Round to nearest integer
114
+ order_30 = max(0, round(forecast_30 - current_stock)) # Round to nearest integer
115
+
116
+ st.write(f"**For 7 Days**: Order {order_7} additional units.")
117
+ st.write(f"**For 14 Days**: Order {order_14} additional units.")
118
+ st.write(f"**For 30 Days**: Order {order_30} additional units.")
119
+
120
+ # Graphical representation for forecast
121
+ st.header("Forecast Visualization")
122
+ forecast_data = pd.DataFrame({
123
+ 'Period': ['7 Days', '14 Days', '30 Days'],
124
+ 'Units': [forecast_7, forecast_14, forecast_30]
125
+ })
126
+ fig_forecast = go.Figure()
127
+ fig_forecast.add_trace(go.Scatter(
128
+ x=forecast_data['Period'],
129
+ y=forecast_data['Units'],
130
+ mode='lines+markers',
131
+ name='Forecasted Units',
132
+ line=dict(color='blue'),
133
+ marker=dict(size=10)
134
+ ))
135
+ fig_forecast.update_layout(
136
+ title='Consumable Usage Forecast',
137
+ xaxis_title='Time Period',
138
+ yaxis_title='Units',
139
+ template='plotly_white'
140
+ )
141
+ st.plotly_chart(fig_forecast)
142
+
143
+ # Graphical representation for threshold alerts
144
+ st.header("Threshold Alerts Visualization")
145
+ alert_data = pd.DataFrame({
146
+ 'Category': ['Current Stock', '7-Day Forecast', '14-Day Forecast', '30-Day Forecast'],
147
+ 'Units': [current_stock, forecast_7, forecast_14, forecast_30],
148
+ 'Alert': [
149
+ False,
150
+ current_stock < forecast_7,
151
+ current_stock < forecast_14,
152
+ current_stock < forecast_30
153
+ ]
154
+ })
155
+ fig_alerts = go.Figure()
156
+ fig_alerts.add_trace(go.Bar(
157
+ x=alert_data['Category'],
158
+ y=alert_data['Units'],
159
+ marker_color=['green'] + ['red' if alert else 'blue' for alert in alert_data['Alert'][1:]],
160
+ text=[f"🚩" if alert else "" for alert in alert_data['Alert']],
161
+ textposition='auto'
162
+ ))
163
+ fig_alerts.update_layout(
164
+ title='Stock vs Forecast with Alerts (🚩 indicates low stock)',
165
+ xaxis_title='Category',
166
+ yaxis_title='Units',
167
+ template='plotly_white'
168
+ )
169
+ st.plotly_chart(fig_alerts)
170
+
171
+ if __name__ == "__main__":
172
+ main()