IntelliStock-AI / app.py
rafhiromadoni's picture
Update app.py
c4d33b3 verified
import gradio as gr
from ultralytics import YOLO
import pandas as pd
import datetime
import os
import numpy as np
import matplotlib.pyplot as plt
# 1. KONFIGURASI
MODEL_PATH = 'yolov8n.pt'
DB_FILE = 'inventory_log.csv'
model = YOLO(MODEL_PATH)
# 2. FUNGSI FORECASTING (PREDIKSI)
def predict_demand():
if not os.path.isfile(DB_FILE):
return "โš ๏ธ Data histori belum cukup untuk prediksi.", None
df = pd.read_csv(DB_FILE)
if len(df) < 3: # Butuh minimal 3 data point untuk melihat tren
return "โš ๏ธ Butuh minimal 3 kali scan untuk menghitung tren prediksi.", None
# Kelompokkan data berdasarkan barang dan hitung rata-rata jumlah per hari
df['Timestamp'] = pd.to_datetime(df['Timestamp'])
df['Date_Ordinal'] = df['Timestamp'].apply(lambda x: x.toordinal())
forecast_results = "### ๐Ÿ”ฎ Prediksi Ketersediaan Stok:\n"
items = df['Barang'].unique()
fig, ax = plt.subplots(figsize=(8, 4))
for item in items:
item_df = df[df['Barang'] == item].sort_values('Timestamp')
X = item_df['Date_Ordinal'].values.reshape(-1, 1)
y = item_df['Jumlah'].values
# Linear Regression Sederhana (Slope & Intercept)
if len(y) > 1:
slope, intercept = np.polyfit(X.flatten(), y, 1)
# Jika tren menurun (slope negatif)
if slope < 0:
days_left = int(-intercept / slope) - datetime.date.today().toordinal()
days_left = max(0, days_left)
forecast_results += f"- **{item}**: Diperkirakan habis dalam **{days_left} hari**.\n"
else:
forecast_results += f"- **{item}**: Stok cenderung stabil/meningkat.\n"
# Plotting histori
ax.plot(item_df['Timestamp'], item_df['Jumlah'], marker='o', label=f"Tren {item}")
ax.set_title("Grafik Perubahan Stok Barang")
ax.set_ylabel("Jumlah Unit")
ax.legend()
plt.xticks(rotation=45)
plt.tight_layout()
return forecast_results, fig
# 3. FUNGSI UTAMA (INTEGRASI SCAN)
def process_inventory(img):
if img is None:
return None, None, "โš ๏ธ Unggah foto.", None, "Silakan scan dulu.", None
results = model(img)
res_plotted = results[0].plot()
detections = results[0].boxes.cls.tolist()
names = model.names
counts = {}
for class_id in detections:
name = names[int(class_id)]
counts[name] = counts.get(name, 0) + 1
inventory_list = []
for item, count in counts.items():
status = "โœ… AMAN" if count >= 5 else "๐Ÿšจ LOW STOCK"
inventory_list.append({"Barang": item.upper(), "Jumlah": count, "Status": status, "Timestamp": datetime.datetime.now()})
df_inventory = pd.DataFrame(inventory_list)
# Save to Database
if not df_inventory.empty:
file_exists = os.path.isfile(DB_FILE)
df_inventory.to_csv(DB_FILE, mode='a', index=False, header=not file_exists)
# Jalankan Forecasting setelah scan
forecast_text, forecast_plot = predict_demand()
return res_plotted, df_inventory, "โœ… Database Updated!", DB_FILE, forecast_text, forecast_plot
# 4. UI GRADIO (TABBED INTERFACE)
with gr.Blocks(theme=gr.themes.Soft()) as demo:
gr.Markdown("# ๐Ÿ™๏ธ IntelliStock AI: End-to-End Warehouse Intelligence")
with gr.Tab("๐Ÿ“ธ Scan & Monitoring"):
with gr.Row():
with gr.Column():
input_img = gr.Image(type="numpy", label="Input Camera/Upload")
scan_btn = gr.Button("๐Ÿ” Run AI Scan & Update", variant="primary")
with gr.Column():
output_img = gr.Image(label="Visual Detection")
output_table = gr.Dataframe(label="Current Inventory")
with gr.Row():
output_file = gr.File(label="๐Ÿ“ฅ Download Database (CSV)")
db_status = gr.Markdown()
with gr.Tab("๐Ÿ”ฎ Demand Forecasting"):
gr.Markdown("### Analisis Prediksi Stok Berdasarkan Histori")
with gr.Row():
with gr.Column():
forecast_output_text = gr.Markdown("Lakukan minimal 3x scan untuk melihat prediksi.")
with gr.Column():
forecast_output_plot = gr.Plot(label="Grafik Tren Stok")
refresh_btn = gr.Button("๐Ÿ”„ Refresh Analisis Prediksi")
# Click Events
scan_btn.click(
fn=process_inventory,
inputs=input_img,
outputs=[output_img, output_table, db_status, output_file, forecast_output_text, forecast_output_plot]
)
refresh_btn.click(fn=predict_demand, outputs=[forecast_output_text, forecast_output_plot])
if __name__ == "__main__":
demo.launch()