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()