dhruvsrawat commited on
Commit
e6dc045
·
verified ·
1 Parent(s): 2156000

Upload 8 files

Browse files
Waste-Management/Frontend/Website.html ADDED
@@ -0,0 +1,718 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
6
+ <title>Smart Waste Management System</title>
7
+ <link href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@300;400;500;600;700;800&display=swap" rel="stylesheet"/>
8
+ <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
9
+ <style>
10
+ *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
11
+
12
+ :root {
13
+ --green: #16a34a;
14
+ --green-d: #064e3b;
15
+ --green-l: #dcfce7;
16
+ --blue: #2563eb;
17
+ --blue-l: #dbeafe;
18
+ --red: #dc2626;
19
+ --red-l: #fee2e2;
20
+ --gray: #6b7280;
21
+ --gray-l: #f3f4f6;
22
+ --bg: #f8faf8;
23
+ --surface: #ffffff;
24
+ --border: #e2ede2;
25
+ --text: #0d1a0d;
26
+ --muted: #6b7280;
27
+ }
28
+
29
+ body {
30
+ font-family: 'Plus Jakarta Sans', sans-serif;
31
+ background: var(--bg);
32
+ color: var(--text);
33
+ display: flex;
34
+ min-height: 100vh;
35
+ }
36
+
37
+ /* ── SIDEBAR ── */
38
+ .sidebar {
39
+ width: 230px;
40
+ min-height: 100vh;
41
+ background: var(--surface);
42
+ border-right: 1px solid var(--border);
43
+ padding: 28px 16px;
44
+ position: fixed;
45
+ top: 0; left: 0;
46
+ display: flex;
47
+ flex-direction: column;
48
+ gap: 4px;
49
+ z-index: 100;
50
+ }
51
+ .sidebar-logo {
52
+ text-align: center;
53
+ padding-bottom: 24px;
54
+ border-bottom: 1px solid var(--border);
55
+ margin-bottom: 16px;
56
+ }
57
+ .sidebar-logo .icon { font-size: 2.6rem; }
58
+ .sidebar-logo .name {
59
+ font-weight: 800;
60
+ font-size: 1rem;
61
+ color: var(--green-d);
62
+ margin-top: 6px;
63
+ }
64
+ .sidebar-logo .sub { font-size: 0.72rem; color: var(--muted); margin-top: 2px; }
65
+
66
+ .nav-btn {
67
+ display: flex;
68
+ align-items: center;
69
+ gap: 10px;
70
+ padding: 10px 14px;
71
+ border-radius: 12px;
72
+ border: none;
73
+ background: transparent;
74
+ color: var(--muted);
75
+ font-family: inherit;
76
+ font-size: 0.9rem;
77
+ font-weight: 600;
78
+ cursor: pointer;
79
+ width: 100%;
80
+ text-align: left;
81
+ transition: background 0.15s, color 0.15s;
82
+ }
83
+ .nav-btn:hover { background: var(--green-l); color: var(--green-d); }
84
+ .nav-btn.active { background: var(--green-l); color: var(--green-d); }
85
+
86
+ .sidebar-footer {
87
+ margin-top: auto;
88
+ padding-top: 20px;
89
+ border-top: 1px solid var(--border);
90
+ font-size: 0.72rem;
91
+ color: #9ca3af;
92
+ line-height: 1.9;
93
+ }
94
+
95
+ /* ── MAIN ── */
96
+ .main {
97
+ margin-left: 230px;
98
+ flex: 1;
99
+ padding: 32px 36px;
100
+ max-width: calc(100vw - 230px);
101
+ }
102
+
103
+ /* ── PAGES ── */
104
+ .page { display: none; }
105
+ .page.active { display: block; }
106
+
107
+ /* ── HERO ── */
108
+ .hero {
109
+ background: linear-gradient(135deg, #064e3b 0%, #065f46 50%, #047857 100%);
110
+ border-radius: 22px;
111
+ padding: 52px 44px;
112
+ margin-bottom: 28px;
113
+ position: relative;
114
+ overflow: hidden;
115
+ }
116
+ .hero::before {
117
+ content: '';
118
+ position: absolute;
119
+ top: -70px; right: -70px;
120
+ width: 280px; height: 280px;
121
+ border-radius: 50%;
122
+ background: rgba(255,255,255,0.06);
123
+ pointer-events: none;
124
+ }
125
+ .hero::after {
126
+ content: '';
127
+ position: absolute;
128
+ bottom: -90px; left: 38%;
129
+ width: 200px; height: 200px;
130
+ border-radius: 50%;
131
+ background: rgba(255,255,255,0.04);
132
+ pointer-events: none;
133
+ }
134
+ .hero-badge {
135
+ display: inline-block;
136
+ background: rgba(255,255,255,0.18);
137
+ color: #d1fae5;
138
+ border: 1px solid rgba(255,255,255,0.28);
139
+ border-radius: 20px;
140
+ padding: 4px 16px;
141
+ font-size: 0.72rem;
142
+ font-weight: 700;
143
+ letter-spacing: 0.1em;
144
+ text-transform: uppercase;
145
+ margin-bottom: 16px;
146
+ }
147
+ .hero h1 { font-size: 2.2rem; font-weight: 800; color: #fff; margin-bottom: 8px; line-height: 1.15; }
148
+ .hero p { color: #a7f3d0; font-size: 0.97rem; font-weight: 400; }
149
+
150
+ /* ── CARDS ── */
151
+ .card {
152
+ background: var(--surface);
153
+ border: 1px solid var(--border);
154
+ border-radius: 18px;
155
+ padding: 24px;
156
+ margin-bottom: 16px;
157
+ box-shadow: 0 2px 14px rgba(0,0,0,0.05);
158
+ }
159
+
160
+ /* ── GRID ── */
161
+ .grid-4 { display: grid; grid-template-columns: repeat(4,1fr); gap: 16px; margin-bottom: 24px; }
162
+ .grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 24px; margin-bottom: 24px; }
163
+
164
+ /* ── CATEGORY CHIPS ── */
165
+ .chip {
166
+ background: var(--surface);
167
+ border: 1px solid var(--border);
168
+ border-radius: 18px;
169
+ padding: 18px 10px;
170
+ text-align: center;
171
+ box-shadow: 0 2px 10px rgba(0,0,0,0.04);
172
+ }
173
+ .chip .c-icon { font-size: 1.8rem; }
174
+ .chip .c-name { font-weight: 700; font-size: 0.92rem; margin-top: 6px; }
175
+ .chip .c-sub { font-size: 0.72rem; color: var(--muted); }
176
+
177
+ /* ── STAT BOXES ── */
178
+ .stat-box {
179
+ background: linear-gradient(135deg, #064e3b, #047857);
180
+ border-radius: 18px;
181
+ padding: 26px 20px;
182
+ text-align: center;
183
+ color: white;
184
+ box-shadow: 0 4px 14px rgba(6,78,59,0.25);
185
+ }
186
+ .stat-box .s-icon { font-size: 1.6rem; margin-bottom: 4px; }
187
+ .stat-box .s-num { font-size: 2.4rem; font-weight: 800; line-height: 1; }
188
+ .stat-box .s-lbl { font-size: 0.78rem; opacity: 0.75; margin-top: 4px; }
189
+
190
+ /* ── SECTION TITLE ── */
191
+ .sec-title {
192
+ font-size: 0.82rem;
193
+ font-weight: 700;
194
+ color: #14532d;
195
+ margin-bottom: 14px;
196
+ text-transform: uppercase;
197
+ letter-spacing: 0.07em;
198
+ }
199
+
200
+ /* ── UPLOAD ZONE ── */
201
+ .upload-zone {
202
+ border: 2px dashed #86efac;
203
+ border-radius: 16px;
204
+ background: #f0fdf4;
205
+ padding: 40px 20px;
206
+ text-align: center;
207
+ cursor: pointer;
208
+ transition: background 0.2s;
209
+ margin-bottom: 16px;
210
+ }
211
+ .upload-zone:hover { background: #dcfce7; }
212
+ .upload-zone .uz-icon { font-size: 2.5rem; margin-bottom: 10px; }
213
+ .upload-zone .uz-text { font-size: 0.9rem; color: var(--muted); font-weight: 500; }
214
+ #file-input { display: none; }
215
+
216
+ #img-preview {
217
+ width: 100%;
218
+ border-radius: 14px;
219
+ object-fit: cover;
220
+ max-height: 260px;
221
+ display: none;
222
+ margin-bottom: 16px;
223
+ }
224
+
225
+ /* ── BUTTON ── */
226
+ .btn {
227
+ background: linear-gradient(135deg, #15803d, #16a34a);
228
+ color: white;
229
+ border: none;
230
+ border-radius: 12px;
231
+ padding: 12px 28px;
232
+ font-family: inherit;
233
+ font-size: 0.95rem;
234
+ font-weight: 700;
235
+ cursor: pointer;
236
+ width: 100%;
237
+ box-shadow: 0 3px 10px rgba(21,128,61,0.3);
238
+ transition: opacity 0.2s;
239
+ }
240
+ .btn:hover { opacity: 0.86; }
241
+
242
+ /* ── RESULT CARD ── */
243
+ .result-empty {
244
+ text-align: center;
245
+ padding: 70px 20px;
246
+ color: var(--muted);
247
+ }
248
+ .result-empty .r-icon { font-size: 3.2rem; margin-bottom: 12px; }
249
+ .result-empty .r-text { font-weight: 700; font-size: 1rem; }
250
+ .result-empty .r-sub { font-size: 0.82rem; margin-top: 6px; }
251
+
252
+ .result-pill {
253
+ display: inline-flex;
254
+ align-items: center;
255
+ gap: 10px;
256
+ border-radius: 50px;
257
+ padding: 12px 26px;
258
+ font-size: 1.2rem;
259
+ font-weight: 800;
260
+ margin: 10px 0;
261
+ }
262
+ .conf-bar-bg {
263
+ background: #f0f7f0;
264
+ border-radius: 8px;
265
+ height: 12px;
266
+ width: 100%;
267
+ overflow: hidden;
268
+ margin-top: 6px;
269
+ }
270
+ .conf-bar-fill { height: 100%; border-radius: 8px; transition: width 0.8s ease; }
271
+
272
+ .bin-tag {
273
+ display: inline-flex;
274
+ align-items: center;
275
+ gap: 10px;
276
+ border-radius: 12px;
277
+ padding: 10px 20px;
278
+ margin-top: 8px;
279
+ font-weight: 800;
280
+ font-size: 1rem;
281
+ }
282
+
283
+ .tip-item {
284
+ background: #f0fdf4;
285
+ border-left: 4px solid var(--green);
286
+ border-radius: 0 10px 10px 0;
287
+ padding: 9px 14px;
288
+ margin-bottom: 8px;
289
+ font-size: 0.86rem;
290
+ color: #166534;
291
+ }
292
+
293
+ /* ── META LABELS ── */
294
+ .meta-label {
295
+ font-size: 0.68rem;
296
+ font-weight: 700;
297
+ text-transform: uppercase;
298
+ letter-spacing: 0.09em;
299
+ color: var(--muted);
300
+ margin-bottom: 4px;
301
+ margin-top: 18px;
302
+ }
303
+ .meta-label:first-child { margin-top: 0; }
304
+
305
+ /* ── SENSOR CARD ── */
306
+ .sensor-row {
307
+ display: grid;
308
+ grid-template-columns: 2fr 1fr 1fr;
309
+ gap: 20px;
310
+ margin-top: 14px;
311
+ }
312
+ .s-label { font-size: 0.68rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.09em; color: var(--muted); margin-bottom: 4px; }
313
+ .s-value { font-size: 1.45rem; font-weight: 800; }
314
+ .fill-bg { background: #f0f7f0; border-radius: 6px; height: 10px; width: 100%; overflow: hidden; margin-top: 8px; }
315
+ .fill-bar { height: 100%; border-radius: 6px; }
316
+
317
+ .status-badge {
318
+ border-radius: 20px;
319
+ padding: 3px 14px;
320
+ font-size: 0.75rem;
321
+ font-weight: 700;
322
+ }
323
+
324
+ .sensor-header {
325
+ display: flex;
326
+ justify-content: space-between;
327
+ align-items: center;
328
+ }
329
+ .sensor-title { font-weight: 800; font-size: 1rem; }
330
+
331
+ /* ── CHART CONTAINER ── */
332
+ .chart-wrap { position: relative; height: 300px; }
333
+
334
+ /* ── SKELETON ── */
335
+ @keyframes shimmer {
336
+ 0% { background-position: -600px 0; }
337
+ 100% { background-position: 600px 0; }
338
+ }
339
+ .skel {
340
+ background: linear-gradient(90deg, #e8f0e8 25%, #d4e8d4 50%, #e8f0e8 75%);
341
+ background-size: 600px 100%;
342
+ animation: shimmer 1.6s infinite linear;
343
+ border-radius: 8px;
344
+ }
345
+ .skel-pill { height: 46px; width: 180px; border-radius: 50px; }
346
+ .skel-score { height: 38px; width: 90px; border-radius: 8px; }
347
+ .skel-bar { height: 12px; width: 100%; border-radius: 8px; }
348
+ .skel-bin { height: 44px; width: 160px; border-radius: 12px; }
349
+ .skel-tip { height: 36px; width: 100%; border-radius: 8px; }
350
+
351
+
352
+ .loading-overlay {
353
+ display: none;
354
+ position: fixed;
355
+ inset: 0;
356
+ background: rgba(0,0,0,0.35);
357
+ z-index: 999;
358
+ align-items: center;
359
+ justify-content: center;
360
+ flex-direction: column;
361
+ gap: 16px;
362
+ }
363
+ .loading-overlay.show { display: flex; }
364
+ .spinner {
365
+ width: 52px; height: 52px;
366
+ border: 5px solid rgba(255,255,255,0.3);
367
+ border-top-color: #fff;
368
+ border-radius: 50%;
369
+ animation: spin 0.8s linear infinite;
370
+ }
371
+ @keyframes spin { to { transform: rotate(360deg); } }
372
+ .loading-text { color: #fff; font-weight: 700; font-size: 1rem; }
373
+
374
+ /* ── HOME TWO-COL ── */
375
+ .home-cols { display: grid; grid-template-columns: 1fr 1fr; gap: 28px; }
376
+
377
+ @media (max-width: 900px) {
378
+ .sidebar { width: 64px; padding: 16px 8px; }
379
+ .sidebar .sidebar-logo .name,
380
+ .sidebar .sidebar-logo .sub,
381
+ .sidebar .nav-btn span,
382
+ .sidebar .sidebar-footer { display: none; }
383
+ .main { margin-left: 64px; max-width: calc(100vw - 64px); padding: 20px 16px; }
384
+ .grid-4 { grid-template-columns: repeat(2,1fr); }
385
+ .grid-2, .home-cols { grid-template-columns: 1fr; }
386
+ .sensor-row { grid-template-columns: 1fr 1fr; }
387
+ }
388
+ </style>
389
+ </head>
390
+ <body>
391
+
392
+ <!-- ═══════════════════════ SIDEBAR ═══════════════════════ -->
393
+ <aside class="sidebar">
394
+ <div class="sidebar-logo">
395
+ <div class="icon">♻️</div>
396
+ <div class="name">SmartWaste AI</div>
397
+ <div class="sub">Frontend Demo</div>
398
+ </div>
399
+
400
+ <button class="nav-btn active" onclick="showPage('home', this)">
401
+ <span>🏠</span><span>Home</span>
402
+ </button>
403
+ <button class="nav-btn" onclick="showPage('dashboard', this)">
404
+ <span>📊</span><span>Dashboard</span>
405
+ </button>
406
+ <button class="nav-btn" onclick="showPage('iot', this)">
407
+ <span>📡</span><span>IoT Sensors</span>
408
+ </button>
409
+
410
+ <div class="sidebar-footer">
411
+ 📡 IoT Sensors (simulated)<br>
412
+ 🐍 Pure HTML · Chart.js
413
+ </div>
414
+ </aside>
415
+
416
+ <!-- ═══════════════════════ MAIN ═══════════════════════ -->
417
+ <main class="main">
418
+
419
+ <!-- ══════════════ PAGE: HOME ══════════════ -->
420
+ <div class="page active" id="page-home">
421
+
422
+ <div class="hero">
423
+ <div class="hero-badge">✨ AI + IoT Powered</div>
424
+ <h1>Smart Waste Management System</h1>
425
+ <p>Upload a photo of your waste — our AI classifier recommends<br>the correct bin for safe, eco-friendly disposal.</p>
426
+ </div>
427
+
428
+ <!-- Category chips -->
429
+ <div class="grid-4">
430
+ <div class="chip"><div class="c-icon">🌿</div><div class="c-name">Organic</div><div class="c-sub">Green Bin</div></div>
431
+ <div class="chip"><div class="c-icon">♻️</div><div class="c-name">Recyclable</div><div class="c-sub">Blue Bin</div></div>
432
+ <div class="chip"><div class="c-icon">⚠️</div><div class="c-name">Hazardous</div><div class="c-sub">Red Bin</div></div>
433
+ <div class="chip"><div class="c-icon">🗑️</div><div class="c-name">General</div><div class="c-sub">Gray Bin</div></div>
434
+ </div>
435
+
436
+ <!-- Upload + Result -->
437
+ <div class="home-cols">
438
+
439
+ <!-- LEFT: Upload -->
440
+ <div>
441
+ <div class="sec-title">📤 Upload Waste Image</div>
442
+ <input type="file" id="file-input" accept="image/*" onchange="handleUpload(event)"/>
443
+ <div class="upload-zone" onclick="document.getElementById('file-input').click()">
444
+ <div class="uz-icon">🖼️</div>
445
+ <div class="uz-text">Drag & drop or <strong>click to browse</strong><br><span style="font-size:0.78rem;">JPG, PNG, WEBP, BMP · Max 10 MB</span></div>
446
+ </div>
447
+ <img id="img-preview" src="" alt="Preview"/>
448
+ <button class="btn" id="classify-btn" style="display:none;">
449
+ 🔍 Classify Waste
450
+ </button>
451
+ </div>
452
+
453
+ <!-- RIGHT: Result -->
454
+ <div>
455
+ <div class="sec-title">🎯 Classification Result</div>
456
+ <div class="card" id="result-panel">
457
+ <!-- Skeleton placeholder — connect a model to populate this -->
458
+ <div class="meta-label" style="margin-bottom:10px;">Detected Category</div>
459
+ <div class="skel skel-pill"></div>
460
+
461
+ <div class="meta-label" style="margin-top:18px;margin-bottom:10px;">Confidence Score</div>
462
+ <div class="skel skel-score"></div>
463
+ <div class="skel skel-bar" style="margin-top:10px;"></div>
464
+
465
+ <div class="meta-label" style="margin-top:18px;margin-bottom:10px;">Recommended Bin</div>
466
+ <div class="skel skel-bin"></div>
467
+
468
+ <div class="meta-label" style="margin-top:18px;margin-bottom:10px;">Disposal Tips</div>
469
+ <div class="skel skel-tip"></div>
470
+ <div class="skel skel-tip" style="width:80%;margin-top:8px;"></div>
471
+ <div class="skel skel-tip" style="width:65%;margin-top:8px;"></div>
472
+ </div>
473
+ </div>
474
+
475
+ </div>
476
+ </div><!-- /page-home -->
477
+
478
+
479
+ <!-- ══════════════ PAGE: DASHBOARD ══════════════ -->
480
+ <div class="page" id="page-dashboard">
481
+
482
+ <div class="hero">
483
+ <div class="hero-badge">📊 Analytics</div>
484
+ <h1>Waste Analytics Dashboard</h1>
485
+ <p>Overview of waste classification statistics and bin performance.</p>
486
+ </div>
487
+
488
+ <!-- Stat boxes -->
489
+ <div class="grid-4">
490
+ <div class="stat-box"><div class="s-icon">🗂️</div><div class="s-num">1,284</div><div class="s-lbl">Total Processed</div></div>
491
+ <div class="stat-box"><div class="s-icon">🌿</div><div class="s-num">512</div><div class="s-lbl">Organic</div></div>
492
+ <div class="stat-box"><div class="s-icon">♻️</div><div class="s-num">430</div><div class="s-lbl">Recyclable</div></div>
493
+ <div class="stat-box"><div class="s-icon">⚠️</div><div class="s-num">97</div><div class="s-lbl">Hazardous</div></div>
494
+ </div>
495
+
496
+ <!-- Charts -->
497
+ <div class="grid-2">
498
+ <div class="card">
499
+ <div class="sec-title">🥧 Waste Type Distribution</div>
500
+ <div class="chart-wrap"><canvas id="pieChart"></canvas></div>
501
+ </div>
502
+ <div class="card">
503
+ <div class="sec-title">📈 Weekly Waste Volume</div>
504
+ <div class="chart-wrap"><canvas id="barChart"></canvas></div>
505
+ </div>
506
+ </div>
507
+
508
+ <!-- Bin fill levels -->
509
+ <div class="sec-title">🗑️ Current Bin Fill Levels</div>
510
+ <div class="grid-4">
511
+ <div class="card" style="padding:18px 16px;">
512
+ <div class="s-label">Organic (Green)</div>
513
+ <div class="s-value" style="color:#16a34a;">72%</div>
514
+ <div class="fill-bg"><div class="fill-bar" style="width:72%;background:#16a34a;"></div></div>
515
+ <div style="font-size:0.72rem;margin-top:8px;color:#f59e0b;font-weight:700;">● Warning</div>
516
+ </div>
517
+ <div class="card" style="padding:18px 16px;">
518
+ <div class="s-label">Recyclable (Blue)</div>
519
+ <div class="s-value" style="color:#2563eb;">45%</div>
520
+ <div class="fill-bg"><div class="fill-bar" style="width:45%;background:#2563eb;"></div></div>
521
+ <div style="font-size:0.72rem;margin-top:8px;color:#16a34a;font-weight:700;">● Normal</div>
522
+ </div>
523
+ <div class="card" style="padding:18px 16px;">
524
+ <div class="s-label">Hazardous (Red)</div>
525
+ <div class="s-value" style="color:#dc2626;">88%</div>
526
+ <div class="fill-bg"><div class="fill-bar" style="width:88%;background:#dc2626;"></div></div>
527
+ <div style="font-size:0.72rem;margin-top:8px;color:#dc2626;font-weight:700;">● Critical</div>
528
+ </div>
529
+ <div class="card" style="padding:18px 16px;">
530
+ <div class="s-label">General (Gray)</div>
531
+ <div class="s-value" style="color:#6b7280;">33%</div>
532
+ <div class="fill-bg"><div class="fill-bar" style="width:33%;background:#6b7280;"></div></div>
533
+ <div style="font-size:0.72rem;margin-top:8px;color:#16a34a;font-weight:700;">● Normal</div>
534
+ </div>
535
+ </div>
536
+
537
+ </div><!-- /page-dashboard -->
538
+
539
+
540
+ <!-- ══════════════ PAGE: IoT SENSORS ══════════════ -->
541
+ <div class="page" id="page-iot">
542
+
543
+ <div class="hero">
544
+ <div class="hero-badge">📡 Live Monitoring</div>
545
+ <h1>IoT Sensor Panel</h1>
546
+ <p>Simulated real-time sensor data from smart bin hardware.</p>
547
+ </div>
548
+
549
+ <!-- Organic -->
550
+ <div class="card" style="border-left:5px solid #16a34a; margin-bottom:16px;">
551
+ <div class="sensor-header">
552
+ <div class="sensor-title">Organic (Green)</div>
553
+ <div class="status-badge" style="background:#f59e0b1a;color:#f59e0b;border:1.5px solid #f59e0b55;">● Warning</div>
554
+ </div>
555
+ <div class="sensor-row">
556
+ <div>
557
+ <div class="s-label">Fill Level</div>
558
+ <div class="s-value" style="color:#16a34a;">72%</div>
559
+ <div class="fill-bg"><div class="fill-bar" style="width:72%;background:#16a34a;"></div></div>
560
+ </div>
561
+ <div>
562
+ <div class="s-label">Gas Detected</div>
563
+ <div class="s-value" style="color:#16a34a;font-size:1.1rem;">✅ NO</div>
564
+ </div>
565
+ <div>
566
+ <div class="s-label">Temperature</div>
567
+ <div class="s-value">28.4°C</div>
568
+ </div>
569
+ </div>
570
+ </div>
571
+
572
+ <!-- Recyclable -->
573
+ <div class="card" style="border-left:5px solid #2563eb; margin-bottom:16px;">
574
+ <div class="sensor-header">
575
+ <div class="sensor-title">Recyclable (Blue)</div>
576
+ <div class="status-badge" style="background:#16a34a1a;color:#16a34a;border:1.5px solid #16a34a55;">● Normal</div>
577
+ </div>
578
+ <div class="sensor-row">
579
+ <div>
580
+ <div class="s-label">Fill Level</div>
581
+ <div class="s-value" style="color:#2563eb;">45%</div>
582
+ <div class="fill-bg"><div class="fill-bar" style="width:45%;background:#2563eb;"></div></div>
583
+ </div>
584
+ <div>
585
+ <div class="s-label">Gas Detected</div>
586
+ <div class="s-value" style="color:#16a34a;font-size:1.1rem;">✅ NO</div>
587
+ </div>
588
+ <div>
589
+ <div class="s-label">Temperature</div>
590
+ <div class="s-value">23.1°C</div>
591
+ </div>
592
+ </div>
593
+ </div>
594
+
595
+ <!-- Hazardous -->
596
+ <div class="card" style="border-left:5px solid #dc2626; margin-bottom:16px;">
597
+ <div class="sensor-header">
598
+ <div class="sensor-title">Hazardous (Red)</div>
599
+ <div class="status-badge" style="background:#dc26261a;color:#dc2626;border:1.5px solid #dc262655;">● Critical</div>
600
+ </div>
601
+ <div class="sensor-row">
602
+ <div>
603
+ <div class="s-label">Fill Level</div>
604
+ <div class="s-value" style="color:#dc2626;">88%</div>
605
+ <div class="fill-bg"><div class="fill-bar" style="width:88%;background:#dc2626;"></div></div>
606
+ </div>
607
+ <div>
608
+ <div class="s-label">Gas Detected</div>
609
+ <div class="s-value" style="color:#dc2626;font-size:1.1rem;">⚠️ YES</div>
610
+ </div>
611
+ <div>
612
+ <div class="s-label">Temperature</div>
613
+ <div class="s-value" style="color:#dc2626;">41.7°C</div>
614
+ </div>
615
+ </div>
616
+ </div>
617
+
618
+ <!-- General -->
619
+ <div class="card" style="border-left:5px solid #6b7280; margin-bottom:16px;">
620
+ <div class="sensor-header">
621
+ <div class="sensor-title">General (Gray)</div>
622
+ <div class="status-badge" style="background:#16a34a1a;color:#16a34a;border:1.5px solid #16a34a55;">● Normal</div>
623
+ </div>
624
+ <div class="sensor-row">
625
+ <div>
626
+ <div class="s-label">Fill Level</div>
627
+ <div class="s-value" style="color:#6b7280;">33%</div>
628
+ <div class="fill-bg"><div class="fill-bar" style="width:33%;background:#6b7280;"></div></div>
629
+ </div>
630
+ <div>
631
+ <div class="s-label">Gas Detected</div>
632
+ <div class="s-value" style="color:#16a34a;font-size:1.1rem;">✅ NO</div>
633
+ </div>
634
+ <div>
635
+ <div class="s-label">Temperature</div>
636
+ <div class="s-value">22.5°C</div>
637
+ </div>
638
+ </div>
639
+ </div>
640
+
641
+ </div><!-- /page-iot -->
642
+
643
+ </main>
644
+
645
+ <script>
646
+ // ── NAVIGATION ──────────────────────────────────────────────
647
+ function showPage(id, btn) {
648
+ document.querySelectorAll('.page').forEach(p => p.classList.remove('active'));
649
+ document.querySelectorAll('.nav-btn').forEach(b => b.classList.remove('active'));
650
+ document.getElementById('page-' + id).classList.add('active');
651
+ btn.classList.add('active');
652
+ }
653
+
654
+ // ── IMAGE UPLOAD ─────────────────────────────────────────────
655
+ function handleUpload(e) {
656
+ const file = e.target.files[0];
657
+ if (!file) return;
658
+ if (file.size > 10 * 1024 * 1024) {
659
+ alert('❌ File exceeds 10 MB. Please upload a smaller image.');
660
+ return;
661
+ }
662
+ const reader = new FileReader();
663
+ reader.onload = ev => {
664
+ const img = document.getElementById('img-preview');
665
+ img.src = ev.target.result;
666
+ img.style.display = 'block';
667
+ document.getElementById('classify-btn').style.display = 'block';
668
+ };
669
+ reader.readAsDataURL(file);
670
+ }
671
+
672
+ // ── CHARTS (Dashboard) ────────────────────────────────────────
673
+ window.addEventListener('DOMContentLoaded', () => {
674
+
675
+ // Pie chart
676
+ new Chart(document.getElementById('pieChart'), {
677
+ type: 'doughnut',
678
+ data: {
679
+ labels: ['Organic', 'Recyclable', 'Hazardous', 'General'],
680
+ datasets: [{
681
+ data: [512, 430, 97, 245],
682
+ backgroundColor: ['#16a34a','#2563eb','#dc2626','#6b7280'],
683
+ borderColor: '#ffffff',
684
+ borderWidth: 3,
685
+ }]
686
+ },
687
+ options: {
688
+ responsive: true, maintainAspectRatio: false,
689
+ plugins: { legend: { position: 'bottom', labels: { font: { family: 'Plus Jakarta Sans', size: 12 } } } },
690
+ cutout: '44%',
691
+ }
692
+ });
693
+
694
+ // Bar chart
695
+ new Chart(document.getElementById('barChart'), {
696
+ type: 'bar',
697
+ data: {
698
+ labels: ['Mon','Tue','Wed','Thu','Fri','Sat','Sun'],
699
+ datasets: [
700
+ { label: 'Organic', data: [48,55,62,44,70,38,52], backgroundColor: '#16a34a' },
701
+ { label: 'Recyclable', data: [35,42,38,50,45,30,40], backgroundColor: '#2563eb' },
702
+ { label: 'Hazardous', data: [8,5,12,7,9,4,6], backgroundColor: '#dc2626' },
703
+ ]
704
+ },
705
+ options: {
706
+ responsive: true, maintainAspectRatio: false,
707
+ plugins: { legend: { position: 'top', labels: { font: { family: 'Plus Jakarta Sans', size: 12 } } } },
708
+ scales: {
709
+ x: { stacked: true, grid: { display: false }, ticks: { font: { family: 'Plus Jakarta Sans' } } },
710
+ y: { stacked: true, grid: { color: 'rgba(0,0,0,0.05)' }, ticks: { font: { family: 'Plus Jakarta Sans' } } },
711
+ }
712
+ }
713
+ });
714
+
715
+ });
716
+ </script>
717
+ </body>
718
+ </html>
Waste-Management/README.md ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ # Waste-Management System
2
+ Science Project Exhibition
3
+
4
+ This is a project where we create an AI Model which can detect and give feedback as to how one can recycle, reuse or manage waste.
5
+
6
+ A user can upload image of the waste/trash and get feedback for how to deal with it
7
+
8
+ This is a college project built by first year students.
Waste-Management/Run-Server.txt ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ To run the API Server Locally (For @Rawin777 only)
2
+
3
+ Step 1. Open the terminal in Waste-Management-main folder
4
+
5
+ Step 2. Activate Virtual Environment:
6
+ venv\Scripts\activate
7
+ must see: (venv)
8
+
9
+ Step 3. Start Server:
10
+ python -m uvicorn main:app --reload
11
+
12
+ Step 4. Open in browser:
13
+ http://127.0.0.1:8000/docs
14
+
15
+ *If something goes wrong*
16
+ ❌ Torch errror
17
+ pip install torch torchvision
18
+
19
+ ❌ FastAPI error
20
+ pip install fastapi uvicorn
21
+
22
+ ❌ Upload Error
23
+ pip install python-multipart
Waste-Management/Weight-Training.ipynb ADDED
@@ -0,0 +1,357 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "code",
5
+ "execution_count": 14,
6
+ "id": "a8ca6784",
7
+ "metadata": {},
8
+ "outputs": [
9
+ {
10
+ "name": "stdout",
11
+ "output_type": "stream",
12
+ "text": [
13
+ "Fri Mar 27 08:05:49 2026 \n",
14
+ "+-----------------------------------------------------------------------------------------+\n",
15
+ "| NVIDIA-SMI 580.82.07 Driver Version: 580.82.07 CUDA Version: 13.0 |\n",
16
+ "+-----------------------------------------+------------------------+----------------------+\n",
17
+ "| GPU Name Persistence-M | Bus-Id Disp.A | Volatile Uncorr. ECC |\n",
18
+ "| Fan Temp Perf Pwr:Usage/Cap | Memory-Usage | GPU-Util Compute M. |\n",
19
+ "| | | MIG M. |\n",
20
+ "|=========================================+========================+======================|\n",
21
+ "| 0 Tesla T4 Off | 00000000:00:04.0 Off | 0 |\n",
22
+ "| N/A 67C P0 31W / 70W | 223MiB / 15360MiB | 0% Default |\n",
23
+ "| | | N/A |\n",
24
+ "+-----------------------------------------+------------------------+----------------------+\n",
25
+ "\n",
26
+ "+-----------------------------------------------------------------------------------------+\n",
27
+ "| Processes: |\n",
28
+ "| GPU GI CI PID Type Process name GPU Memory |\n",
29
+ "| ID ID Usage |\n",
30
+ "|=========================================================================================|\n",
31
+ "| 0 N/A N/A 2100 C /usr/bin/python3 220MiB |\n",
32
+ "+-----------------------------------------------------------------------------------------+\n"
33
+ ]
34
+ }
35
+ ],
36
+ "source": [
37
+ "!nvidia-smi"
38
+ ]
39
+ },
40
+ {
41
+ "cell_type": "code",
42
+ "execution_count": 15,
43
+ "id": "0bb11592",
44
+ "metadata": {},
45
+ "outputs": [
46
+ {
47
+ "name": "stdout",
48
+ "output_type": "stream",
49
+ "text": [
50
+ "Drive already mounted at /content/drive; to attempt to forcibly remount, call drive.mount(\"/content/drive\", force_remount=True).\n"
51
+ ]
52
+ }
53
+ ],
54
+ "source": [
55
+ "import torch\n",
56
+ "import torchvision\n",
57
+ "from torchvision import transforms, datasets, models\n",
58
+ "import torch.nn as nn\n",
59
+ "import torch.optim as optim\n",
60
+ "from google.colab import drive\n",
61
+ "drive.mount('/content/drive')\n",
62
+ "import os\n",
63
+ "import shutil\n",
64
+ "import random"
65
+ ]
66
+ },
67
+ {
68
+ "cell_type": "code",
69
+ "execution_count": 16,
70
+ "id": "054b3dad",
71
+ "metadata": {},
72
+ "outputs": [],
73
+ "source": [
74
+ "device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")"
75
+ ]
76
+ },
77
+ {
78
+ "cell_type": "code",
79
+ "execution_count": 17,
80
+ "id": "c78b4c4a",
81
+ "metadata": {},
82
+ "outputs": [
83
+ {
84
+ "data": {
85
+ "text/plain": [
86
+ "['cardboard', 'glass', 'metal', 'paper', 'plastic', 'trash']"
87
+ ]
88
+ },
89
+ "execution_count": 17,
90
+ "metadata": {},
91
+ "output_type": "execute_result"
92
+ }
93
+ ],
94
+ "source": [
95
+ "os.listdir('/content/drive/MyDrive/TrashNet')"
96
+ ]
97
+ },
98
+ {
99
+ "cell_type": "code",
100
+ "execution_count": 18,
101
+ "id": "598ad20a",
102
+ "metadata": {},
103
+ "outputs": [],
104
+ "source": [
105
+ "source = '/content/drive/MyDrive/TrashNet'\n",
106
+ "base = '/content/drive/MyDrive/waste_dataset'\n",
107
+ "\n",
108
+ "train_dir = os.path.join(base, 'train')\n",
109
+ "val_dir = os.path.join(base, 'val')\n",
110
+ "\n",
111
+ "os.makedirs(train_dir, exist_ok=True)\n",
112
+ "os.makedirs(val_dir, exist_ok=True)\n",
113
+ "\n",
114
+ "for class_name in os.listdir(source):\n",
115
+ " class_path = os.path.join(source, class_name)\n",
116
+ " \n",
117
+ " images = os.listdir(class_path)\n",
118
+ " random.shuffle(images)\n",
119
+ "\n",
120
+ " split = int(0.8 * len(images))\n",
121
+ "\n",
122
+ " train_images = images[:split]\n",
123
+ " val_images = images[split:]\n",
124
+ "\n",
125
+ " os.makedirs(os.path.join(train_dir, class_name), exist_ok=True)\n",
126
+ " os.makedirs(os.path.join(val_dir, class_name), exist_ok=True)\n",
127
+ "\n",
128
+ " for img in train_images:\n",
129
+ " shutil.copy(os.path.join(class_path, img),\n",
130
+ " os.path.join(train_dir, class_name, img))\n",
131
+ "\n",
132
+ " for img in val_images:\n",
133
+ " shutil.copy(os.path.join(class_path, img),\n",
134
+ " os.path.join(val_dir, class_name, img))"
135
+ ]
136
+ },
137
+ {
138
+ "cell_type": "code",
139
+ "execution_count": 21,
140
+ "id": "a743b4fb",
141
+ "metadata": {},
142
+ "outputs": [
143
+ {
144
+ "name": "stdout",
145
+ "output_type": "stream",
146
+ "text": [
147
+ "['cardboard', 'glass', 'metal', 'paper', 'plastic', 'trash']\n",
148
+ "2422\n",
149
+ "911\n"
150
+ ]
151
+ }
152
+ ],
153
+ "source": [
154
+ "train_path = '/content/drive/MyDrive/waste_dataset/train'\n",
155
+ "val_path = '/content/drive/MyDrive/waste_dataset/val'\n",
156
+ "\n",
157
+ "from torchvision import transforms\n",
158
+ "\n",
159
+ "train_transform = transforms.Compose([\n",
160
+ " transforms.Resize((224,224)),\n",
161
+ " transforms.RandomHorizontalFlip(),\n",
162
+ " transforms.RandomRotation(15),\n",
163
+ " transforms.ToTensor(),\n",
164
+ " transforms.Normalize([0.485,0.456,0.406],\n",
165
+ " [0.229,0.224,0.225])\n",
166
+ "])\n",
167
+ "\n",
168
+ "val_transform = transforms.Compose([\n",
169
+ " transforms.Resize((224,224)),\n",
170
+ " transforms.ToTensor(),\n",
171
+ " transforms.Normalize([0.485,0.456,0.406],\n",
172
+ " [0.229,0.224,0.225])\n",
173
+ "])\n",
174
+ "\n",
175
+ "from torchvision import datasets\n",
176
+ "\n",
177
+ "train_data = datasets.ImageFolder(train_path, transform=train_transform)\n",
178
+ "val_data = datasets.ImageFolder(val_path, transform=val_transform)\n",
179
+ "\n",
180
+ "\n",
181
+ "from torch.utils.data import DataLoader\n",
182
+ "\n",
183
+ "train_loader = DataLoader(train_data, batch_size=32, shuffle=True)\n",
184
+ "val_loader = DataLoader(val_data, batch_size=32)\n",
185
+ "\n",
186
+ "\n",
187
+ "print(train_data.classes)\n",
188
+ "print(len(train_data))\n",
189
+ "print(len(val_data))"
190
+ ]
191
+ },
192
+ {
193
+ "cell_type": "code",
194
+ "execution_count": 22,
195
+ "id": "01fc969b",
196
+ "metadata": {},
197
+ "outputs": [
198
+ {
199
+ "name": "stdout",
200
+ "output_type": "stream",
201
+ "text": [
202
+ "Linear(in_features=2048, out_features=6, bias=True)\n"
203
+ ]
204
+ }
205
+ ],
206
+ "source": [
207
+ "from torchvision import models\n",
208
+ "import torch.nn as nn\n",
209
+ "\n",
210
+ "model = models.resnet50(pretrained=True)\n",
211
+ "\n",
212
+ "model.fc = nn.Linear(model.fc.in_features, 6)\n",
213
+ "\n",
214
+ "import torch.optim as optim\n",
215
+ "\n",
216
+ "criterion = nn.CrossEntropyLoss()\n",
217
+ "optimizer = optim.Adam(model.parameters(), lr=0.001)\n",
218
+ "\n",
219
+ "print(model.fc)"
220
+ ]
221
+ },
222
+ {
223
+ "cell_type": "code",
224
+ "execution_count": 23,
225
+ "id": "17fede0a",
226
+ "metadata": {},
227
+ "outputs": [],
228
+ "source": [
229
+ "# Freeze\n",
230
+ "for param in model.parameters():\n",
231
+ " param.requires_grad = False\n",
232
+ "\n",
233
+ "# Replace final layer\n",
234
+ "model.fc = nn.Linear(model.fc.in_features, 6)\n",
235
+ "\n",
236
+ "# Move to GPU\n",
237
+ "model = model.to(device)\n",
238
+ "\n",
239
+ "# Optimizer (IMPORTANT)\n",
240
+ "optimizer = optim.Adam(model.fc.parameters(), lr=0.001)"
241
+ ]
242
+ },
243
+ {
244
+ "cell_type": "code",
245
+ "execution_count": null,
246
+ "id": "b441ea41",
247
+ "metadata": {},
248
+ "outputs": [
249
+ {
250
+ "name": "stdout",
251
+ "output_type": "stream",
252
+ "text": [
253
+ "Epoch [1/3], Loss: 1.1354\n",
254
+ "Validation Accuracy: 69.48%\n",
255
+ "Epoch [2/3], Loss: 0.7224\n",
256
+ "Validation Accuracy: 79.80%\n",
257
+ "Epoch [3/3], Loss: 0.6208\n",
258
+ "Validation Accuracy: 82.44%\n"
259
+ ]
260
+ }
261
+ ],
262
+ "source": [
263
+ "num_epochs = 3\n",
264
+ "\n",
265
+ "for epoch in range(num_epochs):\n",
266
+ " model.train()\n",
267
+ " running_loss = 0.0\n",
268
+ "\n",
269
+ " for images, labels in train_loader:\n",
270
+ " images, labels = images.to(device), labels.to(device)\n",
271
+ "\n",
272
+ " optimizer.zero_grad()\n",
273
+ "\n",
274
+ " outputs = model(images)\n",
275
+ " loss = criterion(outputs, labels)\n",
276
+ "\n",
277
+ " loss.backward()\n",
278
+ " optimizer.step()\n",
279
+ "\n",
280
+ " running_loss += loss.item()\n",
281
+ "\n",
282
+ " print(f\"Epoch [{epoch+1}/{num_epochs}], Loss: {running_loss/len(train_loader):.4f}\")\n",
283
+ "\n",
284
+ " \n",
285
+ " model.eval()\n",
286
+ " correct = 0\n",
287
+ " total = 0\n",
288
+ "\n",
289
+ " with torch.no_grad():\n",
290
+ " for images, labels in val_loader:\n",
291
+ " images, labels = images.to(device), labels.to(device)\n",
292
+ "\n",
293
+ " outputs = model(images)\n",
294
+ " _, predicted = torch.max(outputs, 1)\n",
295
+ "\n",
296
+ " total += labels.size(0)\n",
297
+ " correct += (predicted == labels).sum().item()\n",
298
+ "\n",
299
+ " print(f\"Validation Accuracy: {100 * correct / total:.2f}%\")"
300
+ ]
301
+ },
302
+ {
303
+ "cell_type": "code",
304
+ "execution_count": 27,
305
+ "id": "1a5ce395",
306
+ "metadata": {},
307
+ "outputs": [
308
+ {
309
+ "name": "stdout",
310
+ "output_type": "stream",
311
+ "text": [
312
+ "Model Saved Succesfully\n",
313
+ "['.config', 'waste_classifier.pth', 'drive', 'sample_data']\n"
314
+ ]
315
+ }
316
+ ],
317
+ "source": [
318
+ "torch.save(model.state_dict(), \"waste_classifier.pth\")\n",
319
+ "print(\"Model Saved Succesfully\")\n",
320
+ "\n",
321
+ "print(os.listdir())"
322
+ ]
323
+ },
324
+ {
325
+ "cell_type": "code",
326
+ "execution_count": null,
327
+ "id": "a9556bd6",
328
+ "metadata": {},
329
+ "outputs": [],
330
+ "source": [
331
+ "from google.colab import files\n",
332
+ "files.download('waste_classifier.pth')"
333
+ ]
334
+ }
335
+ ],
336
+ "metadata": {
337
+ "kernelspec": {
338
+ "display_name": "Python 3 (ipykernel)",
339
+ "language": "python",
340
+ "name": "python3"
341
+ },
342
+ "language_info": {
343
+ "codemirror_mode": {
344
+ "name": "ipython",
345
+ "version": 3
346
+ },
347
+ "file_extension": ".py",
348
+ "mimetype": "text/x-python",
349
+ "name": "python",
350
+ "nbconvert_exporter": "python",
351
+ "pygments_lexer": "ipython3",
352
+ "version": "3.12.13"
353
+ }
354
+ },
355
+ "nbformat": 4,
356
+ "nbformat_minor": 5
357
+ }
Waste-Management/app.py ADDED
@@ -0,0 +1,47 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ from PIL import Image
3
+ import torchvision.transforms as transforms
4
+ import gradio as gr
5
+ import os
6
+ import gdown
7
+
8
+ from model import get_model, CLASS_NAMES
9
+
10
+ MODEL_PATH = "waste_classifier.pth"
11
+
12
+ # Download model if not present
13
+ if not os.path.exists(MODEL_PATH):
14
+ url = "https://drive.google.com/uc?id=1RDBXrDvQ7B71SU-nUybDzbIpXkzHBStV"
15
+ gdown.download(url, MODEL_PATH, quiet=False)
16
+
17
+ # Load model
18
+ model = get_model()
19
+ model.load_state_dict(torch.load(MODEL_PATH, map_location="cpu"))
20
+ model.eval()
21
+
22
+ # Transform
23
+ transform = transforms.Compose([
24
+ transforms.Resize((224, 224)),
25
+ transforms.ToTensor()
26
+ ])
27
+
28
+ def predict(image):
29
+ image = image.convert("RGB")
30
+ img = transform(image).unsqueeze(0)
31
+
32
+ with torch.no_grad():
33
+ outputs = model(img)
34
+ _, predicted = torch.max(outputs, 1)
35
+
36
+ return CLASS_NAMES[predicted.item()]
37
+
38
+ # Gradio UI
39
+ interface = gr.Interface(
40
+ fn=predict,
41
+ inputs=gr.Image(type="pil"),
42
+ outputs="text",
43
+ title="Waste Classifier",
44
+ description="Upload an image to classify waste"
45
+ )
46
+
47
+ interface.launch()
Waste-Management/main.py ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import FastAPI, File, UploadFile
2
+ import torch
3
+ from PIL import Image
4
+ import io
5
+ from torchvision import transforms
6
+ import os
7
+ import gdown
8
+
9
+ MODEL_PATH = "waste_classifier.pth"
10
+
11
+ if not os.path.exists(MODEL_PATH):
12
+ url = "https://drive.google.com/uc?id=1RDBXrDvQ7B71SU-nUybDzbIpXkzHBStV"
13
+ gdown.download(url, MODEL_PATH, quiet=False)
14
+
15
+ from model import get_model, CLASS_NAMES
16
+
17
+ app = FastAPI()
18
+
19
+ # Load model
20
+ model = get_model()
21
+ model.load_state_dict(torch.load(MODEL_PATH, map_location="cpu"))
22
+ model.eval()
23
+
24
+ # Transform
25
+ transform = transforms.Compose([
26
+ transforms.Resize((224, 224)),
27
+ transforms.ToTensor(),
28
+ ])
29
+
30
+ @app.get("/")
31
+ def home():
32
+ return {"message": "API working"}
33
+
34
+ @app.post("/classify")
35
+ async def classify(file: UploadFile = File(...)):
36
+ image_bytes = await file.read()
37
+ image = Image.open(io.BytesIO(image_bytes)).convert("RGB")
38
+
39
+ img = transform(image).unsqueeze(0)
40
+
41
+ with torch.no_grad():
42
+ outputs = model(img)
43
+ _, predicted = torch.max(outputs, 1)
44
+
45
+ return {"prediction": CLASS_NAMES[predicted.item()]}
Waste-Management/model.py ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from torchvision import models
2
+ import torch.nn as nn
3
+
4
+ # Class names (IMPORTANT for prediction later)
5
+ CLASS_NAMES = ['cardboard', 'glass', 'metal', 'paper', 'plastic', 'trash']
6
+
7
+
8
+ def get_model():
9
+ """
10
+ Returns the ResNet50 model with modified final layer
11
+ """
12
+ model = models.resnet50(pretrained=False) # DO NOT change this
13
+
14
+ # Replace final layer for 6 classes
15
+ model.fc = nn.Linear(model.fc.in_features, len(CLASS_NAMES))
16
+
17
+ return model
Waste-Management/requirements.txt ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ fastapi
2
+ uvicorn
3
+ torch
4
+ torchvision
5
+ pillow
6
+ python-multipart
7
+ gdown
8
+ gradio