tejas2110 commited on
Commit
808a55d
Β·
verified Β·
1 Parent(s): 57c9e2e

first commit

Browse files
README.MD ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: Smart Bin AI
3
+ emoji: πŸ—‘οΈ
4
+ colorFrom: green
5
+ colorTo: red
6
+ sdk: gradio
7
+ sdk_version: 4.44.0
8
+ app_file: app.py
9
+ pinned: false
10
+ license: mit
11
+ ---
12
+
13
+ # Smart Bin AI β€” Waste Management Intelligence
14
+
15
+ Two ML models for smart city waste management:
16
+
17
+ **Model 1 β€” Fill Level Predictor**
18
+ - Input: live ultrasonic + weight sensor readings
19
+ - Output: exact fill %, GREEN/YELLOW/RED status, confidence score
20
+ - Algorithm: Random Forest (300 trees)
21
+ - Accuracy: 99%+ classification, MAE < 1%
22
+
23
+ **Model 2 β€” Garbage Flow Forecaster**
24
+ - Input: current sensor readings + fill trend
25
+ - Output: predicted fill % at +6h and +12h
26
+ - Algorithm: Gradient Boosting
27
+ - Accuracy: R2 = 0.77 (6h), 0.70 (12h)
28
+
29
+ **Dataset:** 72,000 rows (100 bins Γ— 720 hours) with realistic IoT sensor simulation including rush hour patterns, weekend effects, zone differences, sensor drift, and collection events.
30
+
31
+ **Validation:** GroupKFold cross-validation (zero bin leakage between train and test)
Requirements.txt ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ gradio==4.44.0
2
+ scikit-learn==1.5.2
3
+ pandas==2.2.3
4
+ numpy==1.26.4
5
+ joblib==1.4.2
app.py ADDED
@@ -0,0 +1,367 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # app.py
2
+ # This is the file Hugging Face looks for automatically.
3
+ # It runs your Gradio interface and exposes the API.
4
+
5
+ import gradio as gr
6
+ import numpy as np
7
+ import pandas as pd
8
+ import joblib
9
+ import os
10
+
11
+ # ── Load all models (Hugging Face runs this once on startup) ──────────────────
12
+ print("Loading models...")
13
+
14
+ reg_model = joblib.load("model1_regression.pkl")
15
+ cls_model = joblib.load("model1_classifier.pkl")
16
+ m1_features = joblib.load("model1_features.pkl")
17
+
18
+ forecast_6h = joblib.load("model2_forecast_6h.pkl")
19
+ forecast_12h = joblib.load("model2_forecast_12h.pkl")
20
+ m2_features = joblib.load("model2_features.pkl")
21
+
22
+ print("All models loaded.")
23
+
24
+ STATUS_NAMES = {0: "🟒 GREEN β€” Empty", 1: "🟑 YELLOW β€” Filling", 2: "πŸ”΄ RED β€” Full"}
25
+ STATUS_ACTION = {
26
+ 0: "No action needed",
27
+ 1: "Monitor β€” schedule collection soon",
28
+ 2: "DISPATCH TRUCK IMMEDIATELY"
29
+ }
30
+
31
+ # ── Shared feature builder ────────────────────────────────────────────────────
32
+ def build_row(ultrasonic, weight, fill_now, hour_of_day, day_of_week,
33
+ bin_type, location, zone,
34
+ fill_rate_1h=0, fill_rate_3h=0, fill_rate_6h=0,
35
+ rolling_fill_3h=None, rolling_fill_6h=None,
36
+ rolling_fill_12h=None, rolling_fill_24h=None,
37
+ hours_since_collection=24, week_number=0):
38
+
39
+ rolling_fill_3h = rolling_fill_3h or fill_now
40
+ rolling_fill_6h = rolling_fill_6h or fill_now
41
+ rolling_fill_12h = rolling_fill_12h or fill_now
42
+ rolling_fill_24h = rolling_fill_24h or fill_now
43
+
44
+ hours_to_full = max(0, min(72,
45
+ (80 - fill_now) / fill_rate_1h if fill_rate_1h > 0.01 else 72
46
+ ))
47
+ fill_acceleration = fill_rate_1h - (fill_rate_3h / 3 if fill_rate_3h else 0)
48
+
49
+ return {
50
+ "ultrasonic": ultrasonic,
51
+ "weight": weight,
52
+ "sensor_ratio": weight / (ultrasonic + 1e-5),
53
+ "fill_percent": fill_now,
54
+ "fill_rate_1h": fill_rate_1h,
55
+ "fill_rate_3h": fill_rate_3h,
56
+ "fill_rate_6h": fill_rate_6h,
57
+ "fill_rate_12h": 0,
58
+ "fill_acceleration": fill_acceleration,
59
+ "rolling_fill_3h": rolling_fill_3h,
60
+ "rolling_fill_6h": rolling_fill_6h,
61
+ "rolling_fill_12h": rolling_fill_12h,
62
+ "rolling_fill_24h": rolling_fill_24h,
63
+ "rolling_weight_3h": weight,
64
+ "hour_of_day": hour_of_day,
65
+ "day_of_week": day_of_week,
66
+ "week_number": week_number,
67
+ "is_weekend": int(day_of_week >= 5),
68
+ "is_rush_hour": int(hour_of_day in [7,8,9,12,13,17,18,19,20]),
69
+ "is_night": int(hour_of_day in [0,1,2,3,4,5]),
70
+ "sin_hour": np.sin(2 * np.pi * hour_of_day / 24),
71
+ "cos_hour": np.cos(2 * np.pi * hour_of_day / 24),
72
+ "sin_day": np.sin(2 * np.pi * day_of_week / 7),
73
+ "cos_day": np.cos(2 * np.pi * day_of_week / 7),
74
+ "hours_since_collection": hours_since_collection,
75
+ "hours_to_full": hours_to_full,
76
+ "bin_type_residential":int(bin_type == "residential"),
77
+ "bin_type_commercial": int(bin_type == "commercial"),
78
+ "location_urban": int(location == "urban"),
79
+ "location_suburban": int(location == "suburban"),
80
+ "location_mall": int(location == "mall"),
81
+ "zone_north": int(zone == "north"),
82
+ "zone_south": int(zone == "south"),
83
+ "zone_east": int(zone == "east"),
84
+ "zone_west": int(zone == "west"),
85
+ "zone_central": int(zone == "central"),
86
+ }
87
+
88
+
89
+ def safe_predict(model, features, row_dict):
90
+ df = pd.DataFrame([row_dict])
91
+ for col in features:
92
+ if col not in df.columns:
93
+ df[col] = 0
94
+ return model.predict(df[features])
95
+
96
+
97
+ # ── PREDICTION FUNCTION 1: Current fill status ────────────────────────────────
98
+ def predict_current_status(
99
+ ultrasonic, weight, fill_now,
100
+ hour_of_day, day_of_week,
101
+ bin_type, location, zone,
102
+ fill_rate_1h, hours_since_collection
103
+ ):
104
+ try:
105
+ row = build_row(
106
+ ultrasonic=ultrasonic, weight=weight, fill_now=fill_now,
107
+ hour_of_day=int(hour_of_day), day_of_week=int(day_of_week),
108
+ bin_type=bin_type, location=location, zone=zone,
109
+ fill_rate_1h=fill_rate_1h,
110
+ hours_since_collection=int(hours_since_collection)
111
+ )
112
+
113
+ fill_pred = float(np.clip(safe_predict(reg_model, m1_features, row)[0], 0, 100))
114
+ status_idx = int(safe_predict(cls_model, m1_features, row)[0])
115
+ proba = cls_model.predict_proba(
116
+ pd.DataFrame([row])[[f for f in m1_features if f in row or True]]
117
+ )[0]
118
+
119
+ # Fix proba dataframe
120
+ df_row = pd.DataFrame([row])
121
+ for col in m1_features:
122
+ if col not in df_row.columns:
123
+ df_row[col] = 0
124
+ proba = cls_model.predict_proba(df_row[m1_features])[0]
125
+ confidence = float(proba.max()) * 100
126
+
127
+ result = f"""
128
+ ## πŸ“Š Current Bin Status
129
+
130
+ | Metric | Value |
131
+ |--------|-------|
132
+ | **Predicted Fill** | {fill_pred:.1f}% |
133
+ | **Status** | {STATUS_NAMES[status_idx]} |
134
+ | **Action** | {STATUS_ACTION[status_idx]} |
135
+ | **Confidence** | {confidence:.1f}% |
136
+
137
+ ### Probability Breakdown
138
+ - 🟒 GREEN (Empty): {proba[0]*100:.1f}%
139
+ - 🟑 YELLOW (Filling): {proba[1]*100:.1f}%
140
+ - πŸ”΄ RED (Full): {proba[2]*100:.1f}%
141
+
142
+ {"⚠️ **DISPATCH TRUCK NOW**" if status_idx == 2 else "βœ… No immediate action required"}
143
+ """
144
+ return result
145
+
146
+ except Exception as e:
147
+ return f"❌ Error: {str(e)}"
148
+
149
+
150
+ # ── PREDICTION FUNCTION 2: Flow forecast ─────────────────────────────────────
151
+ def predict_forecast(
152
+ ultrasonic, weight, fill_now,
153
+ hour_of_day, day_of_week,
154
+ bin_type, location, zone,
155
+ fill_rate_1h, fill_rate_3h
156
+ ):
157
+ try:
158
+ row = build_row(
159
+ ultrasonic=ultrasonic, weight=weight, fill_now=fill_now,
160
+ hour_of_day=int(hour_of_day), day_of_week=int(day_of_week),
161
+ bin_type=bin_type, location=location, zone=zone,
162
+ fill_rate_1h=fill_rate_1h, fill_rate_3h=fill_rate_3h
163
+ )
164
+
165
+ df_row = pd.DataFrame([row])
166
+ for col in m2_features:
167
+ if col not in df_row.columns:
168
+ df_row[col] = 0
169
+ df_row = df_row[m2_features]
170
+
171
+ p6h = float(np.clip(forecast_6h.predict(df_row)[0], 0, 100))
172
+ p12h = float(np.clip(forecast_12h.predict(df_row)[0], 0, 100))
173
+
174
+ # Urgency
175
+ if p6h >= 80:
176
+ urgency = "πŸ”΄ HIGH β€” Collect within 6 hours"
177
+ elif p12h >= 80:
178
+ urgency = "🟑 MEDIUM β€” Collect within 12 hours"
179
+ else:
180
+ urgency = "🟒 LOW β€” No collection needed soon"
181
+
182
+ bar_now = "β–ˆ" * int(fill_now / 5) + "β–‘" * (20 - int(fill_now / 5))
183
+ bar_6h = "β–ˆ" * int(p6h / 5) + "β–‘" * (20 - int(p6h / 5))
184
+ bar_12h = "β–ˆ" * int(p12h / 5) + "β–‘" * (20 - int(p12h / 5))
185
+
186
+ result = f"""
187
+ ## πŸ“ˆ Fill Level Forecast
188
+
189
+ | Time | Predicted Fill | Bar |
190
+ |------|---------------|-----|
191
+ | **Now** | {fill_now:.1f}% | `{bar_now}` |
192
+ | **+6 hours** | {p6h:.1f}% | `{bar_6h}` |
193
+ | **+12 hours** | {p12h:.1f}% | `{bar_12h}` |
194
+
195
+ ### πŸš› Collection Urgency
196
+ **{urgency}**
197
+
198
+ ### For Route Optimization
199
+ ```
200
+ bin_fill_now: {fill_now:.1f}%
201
+ bin_fill_6h: {p6h:.1f}%
202
+ bin_fill_12h: {p12h:.1f}%
203
+ dispatch_urgent: {str(p6h >= 80).lower()}
204
+ ```
205
+ """
206
+ return result
207
+
208
+ except Exception as e:
209
+ return f"❌ Error: {str(e)}"
210
+
211
+
212
+ # ── BUILD GRADIO UI ────────────────────────────────────────────────────────────
213
+ with gr.Blocks(
214
+ title="Smart Bin AI",
215
+ theme=gr.themes.Soft()
216
+ ) as demo:
217
+
218
+ gr.Markdown("""
219
+ # πŸ—‘οΈ Smart Bin AI β€” Waste Management Intelligence
220
+ **Model 1:** Predict current fill level (GREEN / YELLOW / RED)
221
+ **Model 2:** Forecast fill level 6h and 12h into the future
222
+
223
+ > Built with Random Forest + Gradient Boosting on 72,000 sensor readings
224
+ """)
225
+
226
+ # ── TAB 1: Current Status ─────────────────────────────────────────────────
227
+ with gr.Tab("πŸ“‘ Current Fill Status (Model 1)"):
228
+ gr.Markdown("### Enter live sensor readings to get current bin status")
229
+
230
+ with gr.Row():
231
+ with gr.Column():
232
+ ultra1 = gr.Slider(4, 65, value=30, label="Ultrasonic Distance (cm) β€” lower = more full")
233
+ weight1 = gr.Slider(0, 36, value=15, label="Weight (kg)")
234
+ fill1 = gr.Slider(0, 100, value=50, label="Current Fill % (from previous reading)")
235
+ rate1 = gr.Slider(0, 10, value=1.0, label="Fill Rate per hour (%/hr)", step=0.1)
236
+ hours_sc = gr.Slider(0, 72, value=24, label="Hours Since Last Collection")
237
+
238
+ with gr.Column():
239
+ hour1 = gr.Slider(0, 23, value=12, label="Hour of Day (0–23)", step=1)
240
+ day1 = gr.Slider(0, 6, value=1, label="Day of Week (0=Mon, 6=Sun)", step=1)
241
+ btype1 = gr.Dropdown(["residential", "commercial"], value="commercial", label="Bin Type")
242
+ loc1 = gr.Dropdown(["urban", "suburban", "mall"], value="urban", label="Location")
243
+ zone1 = gr.Dropdown(["north","south","east","west","central"], value="central", label="Zone")
244
+
245
+ btn1 = gr.Button("πŸ” Predict Current Status", variant="primary", size="lg")
246
+ output1 = gr.Markdown()
247
+
248
+ btn1.click(
249
+ fn=predict_current_status,
250
+ inputs=[ultra1, weight1, fill1, hour1, day1, btype1, loc1, zone1, rate1, hours_sc],
251
+ outputs=output1
252
+ )
253
+
254
+ gr.Examples(
255
+ examples=[
256
+ [55, 2.5, 8, 9, 1, "residential", "suburban", "north", 0.3, 48],
257
+ [32, 15, 50, 13, 2, "commercial", "urban", "central", 2.0, 24],
258
+ [8, 30, 90, 18, 4, "commercial", "urban", "central", 4.0, 6],
259
+ ],
260
+ inputs=[ultra1, weight1, fill1, hour1, day1, btype1, loc1, zone1, rate1, hours_sc],
261
+ label="Try these examples"
262
+ )
263
+
264
+ # ── TAB 2: Flow Forecast ──────────────────────────────────────────────────
265
+ with gr.Tab("πŸ“ˆ Fill Forecast (Model 2)"):
266
+ gr.Markdown("### Predict how full this bin will be in 6 and 12 hours")
267
+
268
+ with gr.Row():
269
+ with gr.Column():
270
+ ultra2 = gr.Slider(4, 65, value=30, label="Ultrasonic Distance (cm)")
271
+ weight2 = gr.Slider(0, 36, value=15, label="Weight (kg)")
272
+ fill2 = gr.Slider(0, 100, value=50, label="Current Fill %")
273
+ rate1h = gr.Slider(0, 10, value=1.5, label="Fill Rate last 1h (%/hr)", step=0.1)
274
+ rate3h = gr.Slider(0, 30, value=4.0, label="Fill Rate last 3h (total)", step=0.1)
275
+
276
+ with gr.Column():
277
+ hour2 = gr.Slider(0, 23, value=12, label="Hour of Day", step=1)
278
+ day2 = gr.Slider(0, 6, value=1, label="Day of Week", step=1)
279
+ btype2 = gr.Dropdown(["residential","commercial"], value="commercial", label="Bin Type")
280
+ loc2 = gr.Dropdown(["urban","suburban","mall"], value="urban", label="Location")
281
+ zone2 = gr.Dropdown(["north","south","east","west","central"], value="central", label="Zone")
282
+
283
+ btn2 = gr.Button("πŸ“ˆ Forecast Fill Level", variant="primary", size="lg")
284
+ output2 = gr.Markdown()
285
+
286
+ btn2.click(
287
+ fn=predict_forecast,
288
+ inputs=[ultra2, weight2, fill2, hour2, day2, btype2, loc2, zone2, rate1h, rate3h],
289
+ outputs=output2
290
+ )
291
+
292
+ gr.Examples(
293
+ examples=[
294
+ [52, 4, 15, 7, 1, "residential", "suburban", "north", 0.3, 0.8],
295
+ [30, 16, 55, 11, 2, "commercial", "urban", "central", 2.8, 7.5],
296
+ [12, 27, 78, 17, 4, "commercial", "urban", "central", 3.5, 9.0],
297
+ ],
298
+ inputs=[ultra2, weight2, fill2, hour2, day2, btype2, loc2, zone2, rate1h, rate3h],
299
+ label="Try these examples"
300
+ )
301
+
302
+ # ── TAB 3: API Docs for Node.js ───────────────────────────────────────────
303
+ with gr.Tab("πŸ”Œ Node.js API Docs"):
304
+ gr.Markdown("""
305
+ ## Using This As a Node.js API
306
+
307
+ Hugging Face Spaces exposes your Gradio app as a REST API automatically.
308
+ Install the client: `npm install @gradio/client`
309
+
310
+ ### Call Model 1 (Current Status)
311
+ ```javascript
312
+ const { Client } = require("@gradio/client");
313
+
314
+ async function getBinStatus(sensorData) {
315
+ const client = await Client.connect("YOUR_HF_USERNAME/smart-bin-ai");
316
+
317
+ const result = await client.predict("/predict_current_status", {
318
+ ultrasonic: sensorData.ultrasonic,
319
+ weight: sensorData.weight,
320
+ fill_now: sensorData.fill_percent,
321
+ hour_of_day: new Date().getHours(),
322
+ day_of_week: new Date().getDay(),
323
+ bin_type: sensorData.bin_type || "commercial",
324
+ location: sensorData.location || "urban",
325
+ zone: sensorData.zone || "central",
326
+ fill_rate_1h: sensorData.fill_rate || 0,
327
+ hours_since_collection: sensorData.hours_since_collection || 24,
328
+ });
329
+
330
+ return result.data;
331
+ }
332
+ ```
333
+
334
+ ### Call Model 2 (Forecast)
335
+ ```javascript
336
+ async function getForecast(sensorData) {
337
+ const client = await Client.connect("YOUR_HF_USERNAME/smart-bin-ai");
338
+
339
+ const result = await client.predict("/predict_forecast", {
340
+ ultrasonic: sensorData.ultrasonic,
341
+ weight: sensorData.weight,
342
+ fill_now: sensorData.fill_percent,
343
+ hour_of_day: new Date().getHours(),
344
+ day_of_week: new Date().getDay(),
345
+ bin_type: sensorData.bin_type || "commercial",
346
+ location: sensorData.location || "urban",
347
+ zone: sensorData.zone || "central",
348
+ fill_rate_1h: sensorData.fill_rate_1h || 0,
349
+ fill_rate_3h: sensorData.fill_rate_3h || 0,
350
+ });
351
+
352
+ return result.data;
353
+ }
354
+ ```
355
+
356
+ ### Replace `YOUR_HF_USERNAME` with your actual Hugging Face username.
357
+ ### Replace `smart-bin-ai` with your Space name if you chose a different one.
358
+ """)
359
+
360
+ gr.Markdown("""
361
+ ---
362
+ Built for Smart Waste Management | Random Forest (Model 1) + Gradient Boosting (Model 2)
363
+ | 72,000 training rows | GroupKFold validated
364
+ """)
365
+
366
+ # Launch
367
+ demo.launch()
model1_classifier.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:f768e9d7660bdd89725904e73b234f94ede8498fbe137cde87da5d2069fd4420
3
+ size 39330522
model1_features.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:e116ef8f7f85dc8d8c66dbcf664f99c1db9fcbf44a0877829becc5a84d8baf6b
3
+ size 503
model1_regression.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:8706c1634f883a1c129348e16bd8a8ce14bf93c0503f4de71ce52a87cb854ad9
3
+ size 638000922
model2_features.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:e23f401b06f7921a4488457c3022f9dd7b82c53b34b27d578202347dc26bcc70
3
+ size 570
model2_forecast_12h.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:dd63458ecfff528b3569e58db81f1db1a9e9f0484c461c3b755582aeb26903ac
3
+ size 1283875
model2_forecast_24h.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:2d4b8b03f151f27ee6294300a23fffd32762a6cee5a91bc000bec83c976f629d
3
+ size 1301747
model2_forecast_6h.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:48dc70f6ff9e2df79ababa5fd064e154639ae8b47630d8ac966871c9d368f4a5
3
+ size 1281571
model2_metadata.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:9ab3c31a2aed3cadebcc7579099cc9ea395f493ea60b6b72bcd5575524fb04a8
3
+ size 312