Spaces:
Sleeping
Sleeping
| # app.py | |
| # This is the file Hugging Face looks for automatically. | |
| # It runs your Gradio interface and exposes the API. | |
| import gradio as gr | |
| import numpy as np | |
| import pandas as pd | |
| import joblib | |
| import os | |
| # ββ Load all models (Hugging Face runs this once on startup) ββββββββββββββββββ | |
| print("Loading models...") | |
| reg_model = joblib.load("model1_regression.pkl") | |
| cls_model = joblib.load("model1_classifier.pkl") | |
| m1_features = joblib.load("model1_features.pkl") | |
| forecast_6h = joblib.load("model2_forecast_6h.pkl") | |
| forecast_12h = joblib.load("model2_forecast_12h.pkl") | |
| m2_features = joblib.load("model2_features.pkl") | |
| print("All models loaded.") | |
| STATUS_NAMES = {0: "π’ GREEN β Empty", 1: "π‘ YELLOW β Filling", 2: "π΄ RED β Full"} | |
| STATUS_ACTION = { | |
| 0: "No action needed", | |
| 1: "Monitor β schedule collection soon", | |
| 2: "DISPATCH TRUCK IMMEDIATELY" | |
| } | |
| # ββ Shared feature builder ββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| def build_row(ultrasonic, weight, fill_now, hour_of_day, day_of_week, | |
| bin_type, location, zone, | |
| fill_rate_1h=0, fill_rate_3h=0, fill_rate_6h=0, | |
| rolling_fill_3h=None, rolling_fill_6h=None, | |
| rolling_fill_12h=None, rolling_fill_24h=None, | |
| hours_since_collection=24, week_number=0): | |
| rolling_fill_3h = rolling_fill_3h or fill_now | |
| rolling_fill_6h = rolling_fill_6h or fill_now | |
| rolling_fill_12h = rolling_fill_12h or fill_now | |
| rolling_fill_24h = rolling_fill_24h or fill_now | |
| hours_to_full = max(0, min(72, | |
| (80 - fill_now) / fill_rate_1h if fill_rate_1h > 0.01 else 72 | |
| )) | |
| fill_acceleration = fill_rate_1h - (fill_rate_3h / 3 if fill_rate_3h else 0) | |
| return { | |
| "ultrasonic": ultrasonic, | |
| "weight": weight, | |
| "sensor_ratio": weight / (ultrasonic + 1e-5), | |
| "fill_percent": fill_now, | |
| "fill_rate_1h": fill_rate_1h, | |
| "fill_rate_3h": fill_rate_3h, | |
| "fill_rate_6h": fill_rate_6h, | |
| "fill_rate_12h": 0, | |
| "fill_acceleration": fill_acceleration, | |
| "rolling_fill_3h": rolling_fill_3h, | |
| "rolling_fill_6h": rolling_fill_6h, | |
| "rolling_fill_12h": rolling_fill_12h, | |
| "rolling_fill_24h": rolling_fill_24h, | |
| "rolling_weight_3h": weight, | |
| "hour_of_day": hour_of_day, | |
| "day_of_week": day_of_week, | |
| "week_number": week_number, | |
| "is_weekend": int(day_of_week >= 5), | |
| "is_rush_hour": int(hour_of_day in [7,8,9,12,13,17,18,19,20]), | |
| "is_night": int(hour_of_day in [0,1,2,3,4,5]), | |
| "sin_hour": np.sin(2 * np.pi * hour_of_day / 24), | |
| "cos_hour": np.cos(2 * np.pi * hour_of_day / 24), | |
| "sin_day": np.sin(2 * np.pi * day_of_week / 7), | |
| "cos_day": np.cos(2 * np.pi * day_of_week / 7), | |
| "hours_since_collection": hours_since_collection, | |
| "hours_to_full": hours_to_full, | |
| "bin_type_residential":int(bin_type == "residential"), | |
| "bin_type_commercial": int(bin_type == "commercial"), | |
| "location_urban": int(location == "urban"), | |
| "location_suburban": int(location == "suburban"), | |
| "location_mall": int(location == "mall"), | |
| "zone_north": int(zone == "north"), | |
| "zone_south": int(zone == "south"), | |
| "zone_east": int(zone == "east"), | |
| "zone_west": int(zone == "west"), | |
| "zone_central": int(zone == "central"), | |
| } | |
| def safe_predict(model, features, row_dict): | |
| df = pd.DataFrame([row_dict]) | |
| for col in features: | |
| if col not in df.columns: | |
| df[col] = 0 | |
| return model.predict(df[features]) | |
| # ββ PREDICTION FUNCTION 1: Current fill status ββββββββββββββββββββββββββββββββ | |
| def predict_current_status( | |
| ultrasonic, weight, fill_now, | |
| hour_of_day, day_of_week, | |
| bin_type, location, zone, | |
| fill_rate_1h, hours_since_collection | |
| ): | |
| try: | |
| row = build_row( | |
| ultrasonic=ultrasonic, weight=weight, fill_now=fill_now, | |
| hour_of_day=int(hour_of_day), day_of_week=int(day_of_week), | |
| bin_type=bin_type, location=location, zone=zone, | |
| fill_rate_1h=fill_rate_1h, | |
| hours_since_collection=int(hours_since_collection) | |
| ) | |
| fill_pred = float(np.clip(safe_predict(reg_model, m1_features, row)[0], 0, 100)) | |
| status_idx = int(safe_predict(cls_model, m1_features, row)[0]) | |
| proba = cls_model.predict_proba( | |
| pd.DataFrame([row])[[f for f in m1_features if f in row or True]] | |
| )[0] | |
| # Fix proba dataframe | |
| df_row = pd.DataFrame([row]) | |
| for col in m1_features: | |
| if col not in df_row.columns: | |
| df_row[col] = 0 | |
| proba = cls_model.predict_proba(df_row[m1_features])[0] | |
| confidence = float(proba.max()) * 100 | |
| result = f""" | |
| ## π Current Bin Status | |
| | Metric | Value | | |
| |--------|-------| | |
| | **Predicted Fill** | {fill_pred:.1f}% | | |
| | **Status** | {STATUS_NAMES[status_idx]} | | |
| | **Action** | {STATUS_ACTION[status_idx]} | | |
| | **Confidence** | {confidence:.1f}% | | |
| ### Probability Breakdown | |
| - π’ GREEN (Empty): {proba[0]*100:.1f}% | |
| - π‘ YELLOW (Filling): {proba[1]*100:.1f}% | |
| - π΄ RED (Full): {proba[2]*100:.1f}% | |
| {"β οΈ **DISPATCH TRUCK NOW**" if status_idx == 2 else "β No immediate action required"} | |
| """ | |
| return result | |
| except Exception as e: | |
| return f"β Error: {str(e)}" | |
| # ββ PREDICTION FUNCTION 2: Flow forecast βββββββββββββββββββββββββββββββββββββ | |
| def predict_forecast( | |
| ultrasonic, weight, fill_now, | |
| hour_of_day, day_of_week, | |
| bin_type, location, zone, | |
| fill_rate_1h, fill_rate_3h | |
| ): | |
| try: | |
| row = build_row( | |
| ultrasonic=ultrasonic, weight=weight, fill_now=fill_now, | |
| hour_of_day=int(hour_of_day), day_of_week=int(day_of_week), | |
| bin_type=bin_type, location=location, zone=zone, | |
| fill_rate_1h=fill_rate_1h, fill_rate_3h=fill_rate_3h | |
| ) | |
| df_row = pd.DataFrame([row]) | |
| for col in m2_features: | |
| if col not in df_row.columns: | |
| df_row[col] = 0 | |
| df_row = df_row[m2_features] | |
| p6h = float(np.clip(forecast_6h.predict(df_row)[0], 0, 100)) | |
| p12h = float(np.clip(forecast_12h.predict(df_row)[0], 0, 100)) | |
| # Urgency | |
| if p6h >= 80: | |
| urgency = "π΄ HIGH β Collect within 6 hours" | |
| elif p12h >= 80: | |
| urgency = "π‘ MEDIUM β Collect within 12 hours" | |
| else: | |
| urgency = "π’ LOW β No collection needed soon" | |
| bar_now = "β" * int(fill_now / 5) + "β" * (20 - int(fill_now / 5)) | |
| bar_6h = "β" * int(p6h / 5) + "β" * (20 - int(p6h / 5)) | |
| bar_12h = "β" * int(p12h / 5) + "β" * (20 - int(p12h / 5)) | |
| result = f""" | |
| ## π Fill Level Forecast | |
| | Time | Predicted Fill | Bar | | |
| |------|---------------|-----| | |
| | **Now** | {fill_now:.1f}% | `{bar_now}` | | |
| | **+6 hours** | {p6h:.1f}% | `{bar_6h}` | | |
| | **+12 hours** | {p12h:.1f}% | `{bar_12h}` | | |
| ### π Collection Urgency | |
| **{urgency}** | |
| ### For Route Optimization | |
| ``` | |
| bin_fill_now: {fill_now:.1f}% | |
| bin_fill_6h: {p6h:.1f}% | |
| bin_fill_12h: {p12h:.1f}% | |
| dispatch_urgent: {str(p6h >= 80).lower()} | |
| ``` | |
| """ | |
| return result | |
| except Exception as e: | |
| return f"β Error: {str(e)}" | |
| # ββ BUILD GRADIO UI ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| with gr.Blocks(title="Smart Bin AI") as demo: | |
| gr.Markdown(""" | |
| # ποΈ Smart Bin AI β Waste Management Intelligence | |
| **Model 1:** Predict current fill level (GREEN / YELLOW / RED) | |
| **Model 2:** Forecast fill level 6h and 12h into the future | |
| > Built with Random Forest + Gradient Boosting on 72,000 sensor readings | |
| """) | |
| # ββ TAB 1: Current Status βββββββββββββββββββββββββββββββββββββββββββββββββ | |
| with gr.Tab("π‘ Current Fill Status (Model 1)"): | |
| gr.Markdown("### Enter live sensor readings to get current bin status") | |
| with gr.Row(): | |
| with gr.Column(): | |
| ultra1 = gr.Slider(4, 65, value=30, label="Ultrasonic Distance (cm) β lower = more full") | |
| weight1 = gr.Slider(0, 36, value=15, label="Weight (kg)") | |
| fill1 = gr.Slider(0, 100, value=50, label="Current Fill % (from previous reading)") | |
| rate1 = gr.Slider(0, 10, value=1.0, label="Fill Rate per hour (%/hr)", step=0.1) | |
| hours_sc = gr.Slider(0, 72, value=24, label="Hours Since Last Collection") | |
| with gr.Column(): | |
| hour1 = gr.Slider(0, 23, value=12, label="Hour of Day (0β23)", step=1) | |
| day1 = gr.Slider(0, 6, value=1, label="Day of Week (0=Mon, 6=Sun)", step=1) | |
| btype1 = gr.Dropdown(["residential", "commercial"], value="commercial", label="Bin Type") | |
| loc1 = gr.Dropdown(["urban", "suburban", "mall"], value="urban", label="Location") | |
| zone1 = gr.Dropdown(["north","south","east","west","central"], value="central", label="Zone") | |
| btn1 = gr.Button("π Predict Current Status", variant="primary", size="lg") | |
| output1 = gr.Markdown() | |
| btn1.click( | |
| fn=predict_current_status, | |
| inputs=[ultra1, weight1, fill1, hour1, day1, btype1, loc1, zone1, rate1, hours_sc], | |
| outputs=output1 | |
| ) | |
| gr.Examples( | |
| examples=[ | |
| [55, 2.5, 8, 9, 1, "residential", "suburban", "north", 0.3, 48], | |
| [32, 15, 50, 13, 2, "commercial", "urban", "central", 2.0, 24], | |
| [8, 30, 90, 18, 4, "commercial", "urban", "central", 4.0, 6], | |
| ], | |
| inputs=[ultra1, weight1, fill1, hour1, day1, btype1, loc1, zone1, rate1, hours_sc], | |
| label="Try these examples" | |
| ) | |
| # ββ TAB 2: Flow Forecast ββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| with gr.Tab("π Fill Forecast (Model 2)"): | |
| gr.Markdown("### Predict how full this bin will be in 6 and 12 hours") | |
| with gr.Row(): | |
| with gr.Column(): | |
| ultra2 = gr.Slider(4, 65, value=30, label="Ultrasonic Distance (cm)") | |
| weight2 = gr.Slider(0, 36, value=15, label="Weight (kg)") | |
| fill2 = gr.Slider(0, 100, value=50, label="Current Fill %") | |
| rate1h = gr.Slider(0, 10, value=1.5, label="Fill Rate last 1h (%/hr)", step=0.1) | |
| rate3h = gr.Slider(0, 30, value=4.0, label="Fill Rate last 3h (total)", step=0.1) | |
| with gr.Column(): | |
| hour2 = gr.Slider(0, 23, value=12, label="Hour of Day", step=1) | |
| day2 = gr.Slider(0, 6, value=1, label="Day of Week", step=1) | |
| btype2 = gr.Dropdown(["residential","commercial"], value="commercial", label="Bin Type") | |
| loc2 = gr.Dropdown(["urban","suburban","mall"], value="urban", label="Location") | |
| zone2 = gr.Dropdown(["north","south","east","west","central"], value="central", label="Zone") | |
| btn2 = gr.Button("π Forecast Fill Level", variant="primary", size="lg") | |
| output2 = gr.Markdown() | |
| btn2.click( | |
| fn=predict_forecast, | |
| inputs=[ultra2, weight2, fill2, hour2, day2, btype2, loc2, zone2, rate1h, rate3h], | |
| outputs=output2 | |
| ) | |
| gr.Examples( | |
| examples=[ | |
| [52, 4, 15, 7, 1, "residential", "suburban", "north", 0.3, 0.8], | |
| [30, 16, 55, 11, 2, "commercial", "urban", "central", 2.8, 7.5], | |
| [12, 27, 78, 17, 4, "commercial", "urban", "central", 3.5, 9.0], | |
| ], | |
| inputs=[ultra2, weight2, fill2, hour2, day2, btype2, loc2, zone2, rate1h, rate3h], | |
| label="Try these examples" | |
| ) | |
| # ββ TAB 3: API Docs for Node.js βββββββββββββββββββββββββββββββββββββββββββ | |
| with gr.Tab("π Node.js API Docs"): | |
| gr.Markdown(""" | |
| ## Using This As a Node.js API | |
| Hugging Face Spaces exposes your Gradio app as a REST API automatically. | |
| Install the client: `npm install @gradio/client` | |
| ### Call Model 1 (Current Status) | |
| ```javascript | |
| const { Client } = require("@gradio/client"); | |
| async function getBinStatus(sensorData) { | |
| const client = await Client.connect("YOUR_HF_USERNAME/smart-bin-ai"); | |
| const result = await client.predict("/predict_current_status", { | |
| ultrasonic: sensorData.ultrasonic, | |
| weight: sensorData.weight, | |
| fill_now: sensorData.fill_percent, | |
| hour_of_day: new Date().getHours(), | |
| day_of_week: new Date().getDay(), | |
| bin_type: sensorData.bin_type || "commercial", | |
| location: sensorData.location || "urban", | |
| zone: sensorData.zone || "central", | |
| fill_rate_1h: sensorData.fill_rate || 0, | |
| hours_since_collection: sensorData.hours_since_collection || 24, | |
| }); | |
| return result.data; | |
| } | |
| ``` | |
| ### Call Model 2 (Forecast) | |
| ```javascript | |
| async function getForecast(sensorData) { | |
| const client = await Client.connect("YOUR_HF_USERNAME/smart-bin-ai"); | |
| const result = await client.predict("/predict_forecast", { | |
| ultrasonic: sensorData.ultrasonic, | |
| weight: sensorData.weight, | |
| fill_now: sensorData.fill_percent, | |
| hour_of_day: new Date().getHours(), | |
| day_of_week: new Date().getDay(), | |
| bin_type: sensorData.bin_type || "commercial", | |
| location: sensorData.location || "urban", | |
| zone: sensorData.zone || "central", | |
| fill_rate_1h: sensorData.fill_rate_1h || 0, | |
| fill_rate_3h: sensorData.fill_rate_3h || 0, | |
| }); | |
| return result.data; | |
| } | |
| ``` | |
| ### Replace `YOUR_HF_USERNAME` with your actual Hugging Face username. | |
| ### Replace `smart-bin-ai` with your Space name if you chose a different one. | |
| """) | |
| gr.Markdown(""" | |
| --- | |
| Built for Smart Waste Management | Random Forest (Model 1) + Gradient Boosting (Model 2) | |
| | 72,000 training rows | GroupKFold validated | |
| """) | |
| # Launch | |
| demo.launch(server_name="0.0.0.0", server_port=7860) |