73 lines
3.1 KiB
Python
73 lines
3.1 KiB
Python
from fastapi import APIRouter, File, UploadFile, Form, HTTPException
|
|
from typing import List, Literal
|
|
import pandas as pd
|
|
import io
|
|
|
|
from services.forecastService import forecast_arima_per_product
|
|
|
|
router = APIRouter()
|
|
|
|
@router.post("/predict-file")
|
|
async def predict(
|
|
sheet: UploadFile = File(...),
|
|
# recordPeriod: Literal["daily", "weekly", "monthly"] = Form(...),
|
|
predictionPeriod: Literal["weekly", "monthly"] = Form(...),
|
|
predictionMode: Literal["auto", "optimal", "custom"] = Form(...),
|
|
arimaModel: str = Form("")
|
|
):
|
|
try:
|
|
# Parse model
|
|
model_values: List[int] = []
|
|
if predictionMode == "custom":
|
|
if not arimaModel:
|
|
raise HTTPException(status_code=400, detail="arimaModel harus diisi saat predictionMode adalah 'custom'")
|
|
try:
|
|
model_values = list(map(int, arimaModel.split(",")))
|
|
if len(model_values) != 3:
|
|
raise ValueError
|
|
except ValueError:
|
|
raise HTTPException(status_code=400, detail="Format arimaModel harus 'p,d,q'.")
|
|
|
|
# Baca file
|
|
content = await sheet.read()
|
|
df = pd.read_csv(io.BytesIO(content)) if sheet.filename.endswith(".csv") else pd.read_excel(io.BytesIO(content))
|
|
if df.empty:
|
|
raise HTTPException(status_code=400, detail="File tidak berisi data.")
|
|
|
|
# Validasi kolom
|
|
if 'product_code' not in df.columns and 'product_name' not in df.columns:
|
|
raise HTTPException(status_code=400, detail="Data harus memiliki kolom 'product_code' atau 'product_name'.")
|
|
if 'date' not in df.columns or 'sold(qty)' not in df.columns:
|
|
raise HTTPException(status_code=400, detail="Data harus memiliki kolom 'date' dan 'sold(qty)'.")
|
|
|
|
product_column = 'product_name' if 'product_name' in df.columns else 'product_code'
|
|
df['date'] = pd.to_datetime(df['date'])
|
|
df = df.sort_values(by=[product_column, 'date'])
|
|
|
|
freq_map = {"daily": "D", "weekly": "W", "monthly": "M"}
|
|
horizon = 3
|
|
|
|
results = []
|
|
for product, group in df.groupby(product_column):
|
|
try:
|
|
result = forecast_arima_per_product(group, freq_map[predictionPeriod], predictionMode, model_values, horizon)
|
|
forecast = result["forecast"]
|
|
results.append({
|
|
"predictionPeriod":predictionPeriod,
|
|
"product": product,
|
|
"order": ",".join(map(str, result["model_params"])),
|
|
"phase1": forecast[0] if len(forecast) > 0 else None,
|
|
"phase2": forecast[1] if len(forecast) > 1 else None,
|
|
"phase3": forecast[2] if len(forecast) > 2 else None,
|
|
})
|
|
except Exception as model_err:
|
|
results.append({
|
|
"product": product,
|
|
"error": str(model_err)
|
|
})
|
|
|
|
return {"status": "success", "data": results}
|
|
|
|
except Exception as e:
|
|
raise HTTPException(status_code=500, detail=f"Terjadi kesalahan saat memproses file: {str(e)}")
|