|
|
import pandas as pd |
|
|
from flask import Flask, request, jsonify |
|
|
import joblib |
|
|
import numpy as np |
|
|
import logging |
|
|
import sys |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
logger = logging.getLogger("capacity_logger") |
|
|
logger.setLevel(logging.INFO) |
|
|
handler = logging.StreamHandler(sys.stdout) |
|
|
handler.setLevel(logging.INFO) |
|
|
formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s') |
|
|
handler.setFormatter(formatter) |
|
|
logger.addHandler(handler) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
app = Flask("Store Capacity Predictor") |
|
|
|
|
|
|
|
|
pipeline = joblib.load("catbooster_model_v1_0.joblib") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@app.get('/') |
|
|
def home(): |
|
|
return "Welcome to the Store Capacity Prediction API" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@app.post('/v1/predict') |
|
|
def predict_capacity(): |
|
|
try: |
|
|
sales_data = request.get_json() |
|
|
input_data = pd.DataFrame([sales_data]) |
|
|
input_data["Date"] = pd.to_datetime(input_data["Date"]) |
|
|
|
|
|
logger.info("Single prediction input:\n%s", input_data) |
|
|
|
|
|
|
|
|
prediction = pipeline.predict(input_data).tolist()[0] |
|
|
|
|
|
|
|
|
if not np.isfinite(prediction): |
|
|
logger.warning("Single prediction invalid (%s), replacing with 0", prediction) |
|
|
prediction = 0 |
|
|
else: |
|
|
prediction = int(np.clip(prediction, 0, 10000)) |
|
|
|
|
|
logger.info("Single prediction output: %s", prediction) |
|
|
|
|
|
return jsonify({'Predicted_Capacity': prediction}) |
|
|
|
|
|
except Exception as e: |
|
|
logger.error("Error in single prediction: %s", e, exc_info=True) |
|
|
return jsonify({'error': str(e)}), 400 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@app.post('/v1/predict_batch') |
|
|
def predict_capacity_batch(): |
|
|
try: |
|
|
|
|
|
file = request.files['file'] |
|
|
|
|
|
|
|
|
input_data = pd.read_csv(file) |
|
|
|
|
|
input_data["Date"] = pd.to_datetime(input_data["Date"]) |
|
|
input_data["SpecialEvent"] = input_data["SpecialEvent"].fillna("").astype(str) |
|
|
|
|
|
logger.info("Batch input shape: %s", input_data.shape) |
|
|
logger.info("Batch input preview:\n%s", input_data.head()) |
|
|
|
|
|
predictions = pipeline.predict(input_data).tolist() |
|
|
clean_predictions = [] |
|
|
|
|
|
for idx, p in enumerate(predictions): |
|
|
if not np.isfinite(p): |
|
|
logger.warning("Row %d prediction invalid (%s), replacing with 0", idx, p) |
|
|
clean_predictions.append(0) |
|
|
else: |
|
|
clean_predictions.append(int(np.clip(p, 0, 10000))) |
|
|
|
|
|
logger.info("Batch predictions: %s", clean_predictions) |
|
|
|
|
|
output_df = pd.DataFrame({ |
|
|
"BU": input_data["BU"], |
|
|
"Date": input_data["Date"], |
|
|
"Store": input_data["Store"], |
|
|
"LocationType": input_data["LocationType"], |
|
|
"Slot": input_data["Slot"], |
|
|
"Predicted_Capacity": clean_predictions |
|
|
}) |
|
|
|
|
|
return output_df.to_html(index=False) |
|
|
|
|
|
except Exception as e: |
|
|
logger.error("Error in batch prediction: %s", e, exc_info=True) |
|
|
return jsonify({"error": str(e)}), 400 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__': |
|
|
app.run(debug=True) |
|
|
|