Spaces:
Sleeping
Sleeping
| 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() |