|
import joblib
|
|
import pandas as pd
|
|
import numpy as np
|
|
from scipy.stats import poisson
|
|
|
|
model = joblib.load("inventory_model.pkl")
|
|
|
|
INDUSTRIAL_PARAMS = {
|
|
"service_levels": {"A": 2.33, "B": 1.65, "C": 1.28},
|
|
"risk_thresholds": {"Low": 15, "Medium": 40, "High": 100}
|
|
}
|
|
|
|
def predict_stockout(order_quantity: float, lead_time: float, safety_stock: float, product_class: str) -> str:
|
|
if not (0 <= order_quantity <= 10000 and 0 <= lead_time <= 90 and 0 <= safety_stock <= 10000):
|
|
return "Error: Inputs out of range (Demand: 0-10,000, Lead Time: 0-90 days, Safety Stock: 0-10,000)."
|
|
if any(x < 0 for x in [order_quantity, lead_time, safety_stock]):
|
|
return "Error: Negative values not allowed."
|
|
if product_class not in INDUSTRIAL_PARAMS["service_levels"]:
|
|
return "Error: Invalid product class. Use A, B, or C."
|
|
|
|
daily_demand = order_quantity / 30
|
|
expected_demand = daily_demand * lead_time
|
|
poisson_risk = max(0, min(1, 1 - poisson.cdf(safety_stock, max(1, expected_demand))))
|
|
|
|
safety_stock_impact = safety_stock / (order_quantity + 1e-6)
|
|
lead_time_impact = lead_time / 90
|
|
order_quantity_impact = order_quantity / 10000
|
|
|
|
ml_input = pd.DataFrame({"safety_stock_impact": [safety_stock_impact], "lead_time_impact": [lead_time_impact], "order_quantity_impact": [order_quantity_impact]})
|
|
ml_risk = max(0, min(1, model.predict(ml_input)[0]))
|
|
|
|
weight_poisson = min(1, max(0, 1 - (order_quantity / 1000)))
|
|
weight_ml = 1 - weight_poisson
|
|
blended_risk = (weight_poisson * poisson_risk + weight_ml * ml_risk)
|
|
risk_percentage = np.clip(blended_risk * 100, 0, 100)
|
|
|
|
thresholds = INDUSTRIAL_PARAMS["risk_thresholds"]
|
|
if risk_percentage < thresholds["Low"]:
|
|
return f"<div class='risk-low'>Low Risk (Class {product_class})<br>Risk: {risk_percentage:.1f}%<br>No action needed</div>"
|
|
elif risk_percentage < thresholds["Medium"]:
|
|
return f"<div class='risk-medium'>Medium Risk (Class {product_class})<br>Risk: {risk_percentage:.1f}%<br>Monitor closely</div>"
|
|
else:
|
|
return f"<div class='risk-high'>High Risk (Class {product_class})<br>Risk: {risk_percentage:.1f}%<br>Replenish inventory</div>" |