ALAMDIENG commited on
Commit
0ab1c9b
·
1 Parent(s): 041c593

feat: implement AI autopilot, news compilation, 6-category waste composition, and API documentation

Browse files
Doc.md CHANGED
@@ -6,6 +6,14 @@
6
 
7
  ---
8
 
 
 
 
 
 
 
 
 
9
  ## 📑 Table of Contents
10
  1. [Project Overview](#1-project-overview)
11
  2. [System Architecture](#2-system-architecture)
@@ -290,6 +298,7 @@ numpy>=1.26.0
290
  torch>=2.1.0
291
  chronos-forecasting>=0.1.0
292
  pydantic>=2.5.0
 
293
  ```
294
 
295
  ---
 
6
 
7
  ---
8
 
9
+ > [!IMPORTANT]
10
+ > **📖 DOKUMENTASI & PENGUJIAN SISTEM**:
11
+ > * **Untuk Publik / Stakeholder**: Silakan merujuk ke dokumen [PUBLIC_DOC.md](file:///c:/khusus%20project%20IT/Fine%20tuning%20ulang%20AI%20jakarta/waste-prediction-api/PUBLIC_DOC.md) untuk memahami cara kerja sistem AI, arsitektur, dan panduan penggunaan bagi pengguna umum.
12
+ > * **Untuk Developer Front-End (FE)**: Silakan merujuk langsung ke dokumen [FRONTEND_API_DOC.md](file:///c:/khusus%20project%20IT/Fine%20tuning%20ulang%20AI%20jakarta/waste-prediction-api/FRONTEND_API_DOC.md) untuk spesifikasi detail endpoint API, tipe data TypeScript, contoh kode Axios/Fetch, serta petunjuk integrasi visual.
13
+ > * **Pengujian API (Postman)**: Anda dapat mengimpor file [waste_intelligence_api.postman_collection.json](file:///c:/khusus%20project%20IT/Fine%20tuning%20ulang%20AI%20jakarta/waste-prediction-api/waste_intelligence_api.postman_collection.json) langsung ke aplikasi Postman Anda untuk menguji seluruh endpoint secara instan.
14
+
15
+ ---
16
+
17
  ## 📑 Table of Contents
18
  1. [Project Overview](#1-project-overview)
19
  2. [System Architecture](#2-system-architecture)
 
298
  torch>=2.1.0
299
  chronos-forecasting>=0.1.0
300
  pydantic>=2.5.0
301
+ httpx>=0.25.0
302
  ```
303
 
304
  ---
FRONTEND_API_DOC.md ADDED
@@ -0,0 +1,289 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Aeterna AI - Front-End API Integration Guide (v4.0.0)
2
+
3
+ Dokumen ini ditujukan bagi tim Front-End untuk mengintegrasikan antarmuka pengguna dengan backend **Aeterna AI (Waste Intelligence Platform)**.
4
+
5
+ ---
6
+
7
+ ## 📡 Konfigurasi Global
8
+ * **Base URL (Local)**: `http://localhost:8001`
9
+ * **Content-Type**: `application/json`
10
+ * **CORS**: Diaktifkan secara wildcard (`*`) untuk semua origin, method, dan header.
11
+
12
+ ---
13
+
14
+ ## 🗺️ Konstanta Wilayah (44 Kecamatan DKI Jakarta)
15
+ Untuk memetakan wilayah pada leaflet/map atau drop-down pilihan di FE, gunakan konstanta koordinat dan baseline berikut:
16
+
17
+ ```typescript
18
+ export interface RegionMetadata {
19
+ latitude: number;
20
+ longitude: number;
21
+ normal_avg: number;
22
+ warning_threshold: number;
23
+ critical_threshold: number;
24
+ city: 'Jakarta Pusat' | 'Jakarta Utara' | 'Jakarta Barat' | 'Jakarta Selatan' | 'Jakarta Timur' | 'Kepulauan Seribu';
25
+ }
26
+
27
+ export const KECAMATAN_DATABASE: Record<string, RegionMetadata> = {
28
+ // JAKARTA PUSAT
29
+ "Menteng": { latitude: -6.1950, longitude: 106.8322, normal_avg: 120.0, warning_threshold: 160.0, critical_threshold: 180.0, city: "Jakarta Pusat" },
30
+ "Senen": { latitude: -6.1822, longitude: 106.8452, normal_avg: 180.0, warning_threshold: 220.0, critical_threshold: 240.0, city: "Jakarta Pusat" },
31
+ "Cempaka Putih": { latitude: -6.1802, longitude: 106.8686, normal_avg: 90.0, warning_threshold: 120.0, critical_threshold: 140.0, city: "Jakarta Pusat" },
32
+ "Johar Baru": { latitude: -6.1866, longitude: 106.8572, normal_avg: 70.0, warning_threshold: 95.0, critical_threshold: 110.0, city: "Jakarta Pusat" },
33
+ "Kemayoran": { latitude: -6.1628, longitude: 106.8438, normal_avg: 180.0, warning_threshold: 220.0, critical_threshold: 240.0, city: "Jakarta Pusat" },
34
+ "Sawah Besar": { latitude: -6.1554, longitude: 106.8322, normal_avg: 110.0, warning_threshold: 145.0, critical_threshold: 165.0, city: "Jakarta Pusat" },
35
+ "Tanah Abang": { latitude: -6.2104, longitude: 106.8122, normal_avg: 250.0, warning_threshold: 320.0, critical_threshold: 350.0, city: "Jakarta Pusat" },
36
+ "Gambir": { latitude: -6.1764, longitude: 106.8190, normal_avg: 150.0, warning_threshold: 195.0, critical_threshold: 215.0, city: "Jakarta Pusat" },
37
+
38
+ // JAKARTA UTARA
39
+ "Penjaringan": { latitude: -6.1264, longitude: 106.7822, normal_avg: 280.0, warning_threshold: 350.0, critical_threshold: 380.0, city: "Jakarta Utara" },
40
+ "Tanjung Priok": { latitude: -6.1322, longitude: 106.8722, normal_avg: 260.0, warning_threshold: 320.0, critical_threshold: 350.0, city: "Jakarta Utara" },
41
+ "Koja": { latitude: -6.1214, longitude: 106.9133, normal_avg: 190.0, warning_threshold: 240.0, critical_threshold: 270.0, city: "Jakarta Utara" },
42
+ "Cilincing": { latitude: -6.1288, longitude: 106.9452, normal_avg: 290.0, warning_threshold: 370.0, critical_threshold: 400.0, city: "Jakarta Utara" },
43
+ "Pademangan": { latitude: -6.1328, longitude: 106.8422, normal_avg: 140.0, warning_threshold: 180.0, critical_threshold: 200.0, city: "Jakarta Utara" },
44
+ "Kelapa Gading": { latitude: -6.1552, longitude: 106.9022, normal_avg: 190.0, warning_threshold: 240.0, critical_threshold: 270.0, city: "Jakarta Utara" },
45
+
46
+ // JAKARTA BARAT
47
+ "Cengkareng": { latitude: -6.1528, longitude: 106.7322, normal_avg: 340.0, warning_threshold: 420.0, critical_threshold: 460.0, city: "Jakarta Barat" },
48
+ "Grogol Petamburan": { latitude: -6.1622, longitude: 106.7882, normal_avg: 220.0, warning_threshold: 280.0, critical_threshold: 310.0, city: "Jakarta Barat" },
49
+ "Kalideres": { latitude: -6.1428, longitude: 106.7022, normal_avg: 260.0, warning_threshold: 330.0, critical_threshold: 360.0, city: "Jakarta Barat" },
50
+ "Kebon Jeruk": { latitude: -6.1922, longitude: 106.7722, normal_avg: 210.0, warning_threshold: 260.0, critical_threshold: 290.0, city: "Jakarta Barat" },
51
+ "Kembangan": { latitude: -6.1828, longitude: 106.7382, normal_avg: 180.0, warning_threshold: 230.0, critical_threshold: 250.0, city: "Jakarta Barat" },
52
+ "Palmerah": { latitude: -6.2028, longitude: 106.7882, normal_avg: 160.0, warning_threshold: 200.0, critical_threshold: 220.0, city: "Jakarta Barat" },
53
+ "Taman Sari": { latitude: -6.1454, longitude: 106.8182, normal_avg: 100.0, warning_threshold: 130.0, critical_threshold: 150.0, city: "Jakarta Barat" },
54
+ "Tambora": { latitude: -6.1500, longitude: 106.8000, normal_avg: 80.0, warning_threshold: 110.0, critical_threshold: 125.0, city: "Jakarta Barat" },
55
+
56
+ // JAKARTA SELATAN
57
+ "Cilandak": { latitude: -6.2928, longitude: 106.7922, normal_avg: 180.0, warning_threshold: 230.0, critical_threshold: 250.0, city: "Jakarta Selatan" },
58
+ "Jagakarsa": { latitude: -6.3328, longitude: 106.8222, normal_avg: 220.0, warning_threshold: 280.0, critical_threshold: 310.0, city: "Jakarta Selatan" },
59
+ "Kebayoran Baru": { latitude: -6.2422, longitude: 106.7982, normal_avg: 210.0, warning_threshold: 260.0, critical_threshold: 290.0, city: "Jakarta Selatan" },
60
+ "Kebayoran Lama": { latitude: -6.2488, longitude: 106.7722, normal_avg: 230.0, warning_threshold: 290.0, critical_threshold: 320.0, city: "Jakarta Selatan" },
61
+ "Mampang Prapatan": { latitude: -6.2522, longitude: 106.8182, normal_avg: 120.0, warning_threshold: 150.0, critical_threshold: 170.0, city: "Jakarta Selatan" },
62
+ "Pancoran": { latitude: -6.2622, longitude: 106.8382, normal_avg: 130.0, warning_threshold: 160.0, critical_threshold: 180.0, city: "Jakarta Selatan" },
63
+ "Pasar Minggu": { latitude: -6.2828, longitude: 106.8438, normal_avg: 240.0, warning_threshold: 300.0, critical_threshold: 330.0, city: "Jakarta Selatan" },
64
+ "Pesanggrahan": { latitude: -6.2588, longitude: 106.7588, normal_avg: 160.0, warning_threshold: 200.0, critical_threshold: 220.0, city: "Jakarta Selatan" },
65
+ "Setiabudi": { latitude: -6.2228, longitude: 106.8282, normal_avg: 190.0, warning_threshold: 240.0, critical_threshold: 270.0, city: "Jakarta Selatan" },
66
+ "Tebet": { latitude: -6.2288, longitude: 106.8482, normal_avg: 170.0, warning_threshold: 210.0, critical_threshold: 230.0, city: "Jakarta Selatan" },
67
+
68
+ // JAKARTA TIMUR
69
+ "Cakung": { latitude: -6.1828, longitude: 106.9482, normal_avg: 350.0, warning_threshold: 430.0, critical_threshold: 470.0, city: "Jakarta Timur" },
70
+ "Cipayung": { latitude: -6.3128, longitude: 106.9022, normal_avg: 140.0, warning_threshold: 180.0, critical_threshold: 200.0, city: "Jakarta Timur" },
71
+ "Ciracas": { latitude: -6.3228, longitude: 106.8782, normal_avg: 190.0, warning_threshold: 240.0, critical_threshold: 270.0, city: "Jakarta Timur" },
72
+ "Duren Sawit": { latitude: -6.2228, longitude: 106.9282, normal_avg: 300.0, warning_threshold: 370.0, critical_threshold: 410.0, city: "Jakarta Timur" },
73
+ "Jatinegara": { latitude: -6.2222, longitude: 106.8682, normal_avg: 240.0, warning_threshold: 300.0, critical_threshold: 330.0, city: "Jakarta Timur" },
74
+ "Kramat Jati": { latitude: -6.2722, longitude: 106.8682, normal_avg: 220.0, warning_threshold: 270.0, critical_threshold: 300.0, city: "Jakarta Timur" },
75
+ "Makasar": { latitude: -6.2622, longitude: 106.8782, normal_avg: 160.0, warning_threshold: 200.0, critical_threshold: 220.0, city: "Jakarta Timur" },
76
+ "Matraman": { latitude: -6.2022, longitude: 106.8582, normal_avg: 130.0, warning_threshold: 160.0, critical_threshold: 180.0, city: "Jakarta Timur" },
77
+ "Pasar Rebo": { latitude: -6.3122, longitude: 106.8522, normal_avg: 150.0, warning_threshold: 190.0, critical_threshold: 210.0, city: "Jakarta Timur" },
78
+ "Pulo Gadung": { latitude: -6.1922, longitude: 106.8922, normal_avg: 220.0, warning_threshold: 270.0, critical_threshold: 300.0, city: "Jakarta Timur" },
79
+
80
+ // KEPULAUAN SERIBU
81
+ "Kepulauan Seribu Utara": { latitude: -5.5722, longitude: 106.5522, normal_avg: 11.0, warning_threshold: 15.0, critical_threshold: 18.0, city: "Kepulauan Seribu" },
82
+ "Kepulauan Seribu Selatan": { latitude: -5.7722, longitude: 106.6522, normal_avg: 9.0, warning_threshold: 12.0, critical_threshold: 15.0, city: "Kepulauan Seribu" }
83
+ };
84
+ ```
85
+
86
+ ---
87
+
88
+ ## 🔌 Referensi API Endpoint
89
+
90
+ ### 1. Mengambil Berita Ter-crawled Harian
91
+ Endpoint ini menyajikan database berita seputar persampahan DKI Jakarta yang diperbarui berkala setiap 1 jam.
92
+
93
+ * **URL**: `/api/v1/news`
94
+ * **Method**: `GET`
95
+ * **Headers**: `Accept: application/json`
96
+ * **Response Schema (`200 OK`)**:
97
+ ```json
98
+ [
99
+ {
100
+ "title": "DKI Uji Coba Penarikan Retribusi Sampah Pelayanan Kebersihan Harian",
101
+ "source": "Antara News",
102
+ "url": "https://www.antaranews.com/tag/sampah-jakarta",
103
+ "date_fetched": "2026-07-10",
104
+ "summary": "Pemprov DKI Jakarta merencanakan uji coba penarikan retribusi pelayanan kebersihan/sampah berdasarkan golongan daya listrik..."
105
+ }
106
+ ]
107
+ ```
108
+
109
+ ---
110
+
111
+ ### 2. Prediksi AI Otonom (Autopilot Mode)
112
+ Mengambil prediksi otonom untuk ke-44 kecamatan sekaligus untuk hari ini. Berguna untuk dashboard autopilot utama.
113
+
114
+ * **URL**: `/api/v1/autopilot`
115
+ * **Method**: `GET`
116
+ * **Response Schema (`200 OK`)**:
117
+ ```json
118
+ {
119
+ "status": "success",
120
+ "date": "2026-07-10",
121
+ "total_volume_ton": 8105.42,
122
+ "total_trucks": 1640,
123
+ "top_kecamatan": [
124
+ {
125
+ "location": "Cakung",
126
+ "volume_ton": 355.20,
127
+ "trucks": 72,
128
+ "status": "SAFE",
129
+ "city": "Jakarta Timur"
130
+ }
131
+ ],
132
+ "rainy_regions": 0,
133
+ "event_today": null
134
+ }
135
+ ```
136
+
137
+ ---
138
+
139
+ ### 3. Simulasi Prediksi Wilayah (Predictor Tool)
140
+ Melakukan peramalan timbulan sampah untuk kecamatan tertentu dengan parameter simulasi cuaca/event keramaian.
141
+
142
+ * **URL**: `/api/v1/predict`
143
+ * **Method**: `POST`
144
+ * **Request Body**:
145
+ ```typescript
146
+ interface PredictionRequest {
147
+ forecast_days: number; // Ambang batas: 1 - 30 hari
148
+ rainfall_mm: number; // Curah hujan override (0.0 = Auto Open-Meteo)
149
+ event_scale: number; // 0 (none) sampai 5 (massive crowd)
150
+ location: string; // Salah satu nama dari 44 kecamatan
151
+ granularity: 'daily' | 'hourly';
152
+ model_type: 'chronos' | 'gradient_boosting';
153
+ }
154
+ ```
155
+ * **Contoh Request Payload**:
156
+ ```json
157
+ {
158
+ "forecast_days": 7,
159
+ "rainfall_mm": 0.0,
160
+ "event_scale": 0,
161
+ "location": "Menteng",
162
+ "granularity": "daily",
163
+ "model_type": "gradient_boosting"
164
+ }
165
+ ```
166
+ * **Response Schema (`200 OK`)**:
167
+ ```json
168
+ {
169
+ "status": "success",
170
+ "message": "Normal conditions.",
171
+ "confidence_score": 0.9828,
172
+ "data": {
173
+ "prediction_results": [
174
+ {
175
+ "date": "2026-07-10",
176
+ "location": "Menteng",
177
+ "total_volume_ton": 120.54,
178
+ "organic_waste_ton": 60.11,
179
+ "plastic_waste_ton": 27.66,
180
+ "paper_waste_ton": 13.86,
181
+ "glass_waste_ton": 3.86,
182
+ "metal_waste_ton": 2.53,
183
+ "textile_waste_ton": 5.06,
184
+ "other_waste_ton": 7.46,
185
+ "recommended_trucks": 25,
186
+ "risk_status": "SAFE",
187
+ "event_info": null,
188
+ "hourly_breakdown": null
189
+ }
190
+ ],
191
+ "logistics_plan": {
192
+ "trucks_needed": 25,
193
+ "manpower": 75,
194
+ "estimated_duration_hours": 24.1,
195
+ "efficiency_rate": "85% (Optimal)"
196
+ }
197
+ }
198
+ }
199
+ ```
200
+
201
+ ---
202
+
203
+ ### 4. Unduh Berkas CSV Prediksi
204
+ Mengunduh berkas tabel data hasil simulasi prediksi.
205
+
206
+ * **URL**: `/api/v1/predict/csv`
207
+ * **Method**: `POST`
208
+ * **Request Body**: Sama dengan request `/api/v1/predict`
209
+ * **Response**: Binary Blob (`text/csv` stream file).
210
+
211
+ ---
212
+
213
+ ### 5. Mengambil Peringatan Operasional Dinamis (Alerts)
214
+ Mendapatkan peringatan kritis wilayah yang volumenya melebihi ambang batas warning/critical.
215
+
216
+ * **URL**: `/api/v1/alerts`
217
+ * **Method**: `GET`
218
+ * **Query Parameters**: `location` (opsional, untuk menyaring satu kecamatan)
219
+ * **Response Schema (`200 OK`)**:
220
+ ```json
221
+ {
222
+ "status": "success",
223
+ "alert_count": 2,
224
+ "alerts": [
225
+ {
226
+ "date": "2026-07-10",
227
+ "location": "Cakung",
228
+ "status": "WARNING",
229
+ "estimated_volume_ton": 435.0,
230
+ "message": "Alert: WARNING volume expected at Cakung"
231
+ }
232
+ ],
233
+ "last_updated": "2026-07-10T20:52:00.123456"
234
+ }
235
+ ```
236
+
237
+ ---
238
+
239
+ ## ⚡ Contoh Integrasi Frontend (Axios / JavaScript)
240
+
241
+ Berikut adalah contoh cara menarik data prediksi Autopilot dan memuatnya ke komponen halaman FE Anda:
242
+
243
+ ```javascript
244
+ import axios from 'axios';
245
+
246
+ const BACKEND_URL = 'http://localhost:8001';
247
+
248
+ // 1. Memuat Umpan Berita AI
249
+ export async function getWasteNews() {
250
+ try {
251
+ const res = await axios.get(`${BACKEND_URL}/api/v1/news`);
252
+ return res.data; // Mengembalikan array berita
253
+ } catch (error) {
254
+ console.error("Gagal menarik berita sampah:", error);
255
+ return [];
256
+ }
257
+ }
258
+
259
+ // 2. Memuat Data Autopilot Otonom DKI
260
+ export async function getAutopilotData() {
261
+ try {
262
+ const res = await axios.get(`${BACKEND_URL}/api/v1/autopilot`);
263
+ return res.data;
264
+ } catch (error) {
265
+ console.error("Gagal memuat autopilot data:", error);
266
+ return null;
267
+ }
268
+ }
269
+
270
+ // 3. Menjalankan Prediksi Manual (Simulation)
271
+ export async function postSimulationPrediction(kecamatan, hari = 7, model = 'gradient_boosting') {
272
+ const payload = {
273
+ forecast_days: hari,
274
+ rainfall_mm: 0.0, // Auto
275
+ event_scale: 0,
276
+ location: kecamatan,
277
+ granularity: hari <= 7 ? 'hourly' : 'daily',
278
+ model_type: model
279
+ };
280
+
281
+ try {
282
+ const res = await axios.post(`${BACKEND_URL}/api/v1/predict`, payload);
283
+ return res.data;
284
+ } catch (error) {
285
+ console.error("Gagal melakukan prediksi simulasi:", error);
286
+ throw error;
287
+ }
288
+ }
289
+ ```
README.md CHANGED
@@ -21,6 +21,14 @@ Eco-Twin AI adalah sistem cerdas berbasis *Machine Learning* yang dirancang untu
21
 
22
  ---
23
 
 
 
 
 
 
 
 
 
24
  ## 🚀 Fitur Unggulan (Hackathon Killer Features)
25
 
26
  1. **Integrasi Kalender Event Otomatis**: Sistem secara otomatis membaca file `event_jakarta_2025.txt` saat server dinyalakan. Jika ada *request* prediksi yang menyentuh tanggal konser besar (misal: Maroon 5 di JIS), AI akan mendeteksi dan secara akurat menambahkan estimasi volume sampah tanpa input manual tambahan.
 
21
 
22
  ---
23
 
24
+ > [!IMPORTANT]
25
+ > **📖 DOKUMENTASI SISTEM & INTEGRASI**:
26
+ > 1. **Untuk Publik / Stakeholder**: Silakan merujuk ke [PUBLIC_DOC.md](file:///c:/khusus%20project%20IT/Fine%20tuning%20ulang%20AI%20jakarta/waste-prediction-api/PUBLIC_DOC.md) untuk melihat ringkasan tingkat tinggi, pemodelan AI, cara kerja sistem, serta panduan lengkap penggunaan dashboard bagi pengguna umum.
27
+ > 2. **Untuk Tim Front-End (FE)**: Silakan merujuk ke [FRONTEND_API_DOC.md](file:///c:/khusus%20project%20IT/Fine%20tuning%20ulang%20AI%20jakarta/waste-prediction-api/FRONTEND_API_DOC.md) untuk melihat spesifikasi detail endpoint API, tipe data TypeScript, contoh kode Axios/Fetch, serta panduan pemetaan data logistik ke UI Dashboard.
28
+ > 3. **Pengujian API (Postman)**: Anda bisa mengimpor file [waste_intelligence_api.postman_collection.json](file:///c:/khusus%20project%20IT/Fine%20tuning%20ulang%20AI%20jakarta/waste-prediction-api/waste_intelligence_api.postman_collection.json) langsung ke aplikasi Postman Anda untuk menguji seluruh endpoint secara instan.
29
+
30
+ ---
31
+
32
  ## 🚀 Fitur Unggulan (Hackathon Killer Features)
33
 
34
  1. **Integrasi Kalender Event Otomatis**: Sistem secara otomatis membaca file `event_jakarta_2025.txt` saat server dinyalakan. Jika ada *request* prediksi yang menyentuh tanggal konser besar (misal: Maroon 5 di JIS), AI akan mendeteksi dan secara akurat menambahkan estimasi volume sampah tanpa input manual tambahan.
__pycache__/app.cpython-311.pyc ADDED
Binary file (40 kB). View file
 
app.py CHANGED
@@ -1,11 +1,18 @@
1
  from fastapi import FastAPI, HTTPException, Query
2
  from fastapi.middleware.cors import CORSMiddleware
3
  from fastapi.concurrency import run_in_threadpool
 
 
4
  from pydantic import BaseModel, Field, field_validator
5
  from typing import Optional, List, Dict, Any
6
  import pandas as pd
7
  import numpy as np
8
  import torch
 
 
 
 
 
9
  from chronos import ChronosPipeline
10
  from datetime import datetime, timedelta
11
  import os, logging, re
@@ -17,9 +24,9 @@ logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(
17
  logger = logging.getLogger(__name__)
18
 
19
  app = FastAPI(
20
- title="Waste Intelligence API - Jakarta Pusat 2026",
21
- version="3.0.0 (Calibrated)",
22
- description="AI-powered waste prediction with spatial awareness & real-world calibration"
23
  )
24
 
25
  app.add_middleware(
@@ -30,28 +37,91 @@ app.add_middleware(
30
  allow_headers=["*"],
31
  )
32
 
 
 
 
 
 
33
  # ==========================================
34
- # 2. INPUT VALIDATION & SCHEMAS (English Standard)
35
  # ==========================================
36
- ALLOWED_LOCATIONS = ["JIS", "GBK", "Pasar Senen", "Gang Sempit Tambora"]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
37
 
 
 
 
 
 
 
 
 
 
 
38
  class PredictionRequest(BaseModel):
39
- """
40
- Request schema for waste volume prediction.
41
- Field names use English for international clarity.
42
- """
43
  forecast_days: int = Field(7, ge=1, le=30, description="Forecast horizon in days (1-30)")
44
- rainfall_mm: float = Field(0.0, ge=0, description="Estimated rainfall in mm (BMKG forecast)")
45
  event_scale: int = Field(0, ge=0, le=5, description="Manual event crowd scale (0=none, 5=massive)")
46
- location: str = Field(..., description="Target location name")
47
- start_date: Optional[str] = Field(None, description="Start date: YYYY-MM-DD, MM-DD, or '1 Juni 2026'")
48
- granularity: str = Field("daily", pattern="^(daily|hourly)$", description="Prediction granularity")
 
49
 
50
  @field_validator("location")
51
  @classmethod
52
  def validate_location(cls, v: str) -> str:
53
  if v not in ALLOWED_LOCATIONS:
54
- raise ValueError(f"Location not recognized. Use one of: {', '.join(ALLOWED_LOCATIONS)}")
55
  return v
56
 
57
  class PredictionResult(BaseModel):
@@ -60,6 +130,11 @@ class PredictionResult(BaseModel):
60
  total_volume_ton: float
61
  organic_waste_ton: float
62
  plastic_waste_ton: float
 
 
 
 
 
63
  recommended_trucks: int
64
  risk_status: str
65
  event_info: Optional[str] = None
@@ -88,31 +163,14 @@ class AlertResponse(BaseModel):
88
  last_updated: str
89
 
90
  # ==========================================
91
- # 3. GLOBAL STATE & OPERATIONAL LOGIC
92
  # ==========================================
93
  pipeline = None
 
94
  df_history = None
95
  events_data = {}
 
96
 
97
- # Spatial radius mapping: events at location X impact nearby zones
98
- EVENT_RADIUS_MAP = {
99
- "jiexpo": ["jis", "kemayoran", "pademangan", "jakarta"],
100
- "monas": ["pasar senen", "gang sempit tambora", "merdeka", "jakarta"],
101
- "gbk": ["senayan", "tanah abang", "kuningan", "jakarta"],
102
- "ancol": ["pademangan", "kelapa gading", "jakarta"],
103
- "jakarta": ["*"]
104
- }
105
-
106
- # Real-world operational baselines (calibrated to reality)
107
- # Source: DLH Reports & Municipal Data (e.g., GBK ~7.5-31 tons)
108
- LOCATION_BASELINES = {
109
- "GBK": {"normal_avg": 8.5, "event_peak": 31.0, "warning_threshold": 15.0, "critical_threshold": 30.0},
110
- "JIS": {"normal_avg": 120.0, "event_peak": 200.0, "warning_threshold": 160.0, "critical_threshold": 220.0},
111
- "Pasar Senen": {"normal_avg": 90.0, "event_peak": 150.0, "warning_threshold": 120.0, "critical_threshold": 160.0},
112
- "Gang Sempit Tambora": {"normal_avg": 40.0, "event_peak": 70.0, "warning_threshold": 55.0, "critical_threshold": 75.0}
113
- }
114
-
115
- # Hourly distribution pattern (sum = 1.0)
116
  HOURLY_PATTERN = {
117
  0:0.02, 1:0.01, 2:0.01, 3:0.01, 4:0.02, 5:0.03,
118
  6:0.05, 7:0.07, 8:0.06, 9:0.05, 10:0.04, 11:0.04,
@@ -121,56 +179,32 @@ HOURLY_PATTERN = {
121
  }
122
 
123
  # ==========================================
124
- # 4. HELPER FUNCTIONS
125
  # ==========================================
126
  def parse_flexible_date(date_input: str, default_year: int = 2026) -> pd.Timestamp:
127
- """Parse date strings in multiple formats for user convenience."""
128
  if not date_input: return None
129
  date_input = date_input.strip()
130
- for fmt in ["%Y-%m-%d", "%d-%m-%Y", "%m-%d", "%d %B %Y", "%d %b %Y", "%B %d, %Y", "%b %d, %Y"]:
131
  try:
132
  parsed = datetime.strptime(date_input, fmt)
133
  if fmt == "%m-%d": parsed = parsed.replace(year=default_year)
134
  return pd.Timestamp(parsed)
135
  except ValueError: continue
136
- match = re.match(r"^(\d{1,2})[-/](\d{1,2})$", date_input)
137
- if match:
138
- a, b = int(match.group(1)), int(match.group(2))
139
- if a > 12: return pd.Timestamp(year=default_year, month=b, day=a)
140
- if b > 12: return pd.Timestamp(year=default_year, month=a, day=b)
141
- return pd.Timestamp(year=default_year, month=a, day=b)
142
  raise ValueError(f"Unrecognized date format: '{date_input}'")
143
 
144
- def check_location_match(requested: str, event_location: str) -> bool:
145
- """Determine if an event impacts the requested zone using spatial mapping."""
146
- r, e = requested.lower().strip(), event_location.lower().strip()
147
- if r == e or r in e or e in r or e == "jakarta": return True
148
- for k, v in EVENT_RADIUS_MAP.items():
149
- if k in e and ("*" in v or r in v or any(r in x for x in v)): return True
150
- return False
151
-
152
  def get_risk_status(volume: float, location: str) -> str:
153
- """Calculate risk status based on location-specific calibrated thresholds."""
154
- config = LOCATION_BASELINES.get(location, LOCATION_BASELINES["JIS"])
155
  if volume > config["critical_threshold"]:
156
  return "CRITICAL"
157
  elif volume > config["warning_threshold"]:
158
  return "WARNING"
159
  return "SAFE"
160
 
161
- def distribute_to_hourly(daily_volume: float, location: str) -> List[Dict[str, Any]]:
162
- """Distribute daily prediction to hourly estimates with dynamic risk indicators."""
163
  pattern = HOURLY_PATTERN.copy()
164
- # Adjust patterns for specific location behaviors
165
- if location == "GBK": # Peak evening for events
166
- pattern[19] += 0.03; pattern[20] += 0.03; pattern[21] += 0.02
167
- elif location == "Pasar Senen": # Peak morning for market
168
- pattern[6] += 0.04; pattern[7] += 0.04; pattern[8] += 0.03
169
-
170
  total_factor = sum(pattern.values())
171
  hourly_results = []
172
 
173
- # Dynamic thresholds relative to the daily volume
174
  high_thresh = (daily_volume / 24) * 2.0
175
  med_thresh = (daily_volume / 24) * 1.2
176
 
@@ -186,21 +220,55 @@ def distribute_to_hourly(daily_volume: float, location: str) -> List[Dict[str, A
186
  })
187
  return hourly_results
188
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
189
  # ==========================================
190
- # 5. STARTUP & MODEL LOADING
191
  # ==========================================
192
  @app.on_event("startup")
193
  async def load_assets():
194
- """Initialize AI model, historical dataset, and event calendar."""
195
- global pipeline, df_history, events_data
196
- logger.info("⏳ Initializing AI assets...")
197
  try:
198
  pipeline = ChronosPipeline.from_pretrained("amazon/chronos-t5-tiny", device_map="cpu", torch_dtype=torch.float32)
199
- logger.info("✅ Chronos model loaded")
 
 
 
 
200
 
201
  df_history = pd.read_csv("dataset_vibe_coder_2026.csv")
202
  df_history["TANGGAL"] = pd.to_datetime(df_history["TANGGAL"]).dt.strftime("%Y-%m-%d")
203
- logger.info(f"✅ Historical dataset loaded: {len(df_history)} records")
204
 
205
  event_file = "event_jakarta_2026.txt"
206
  if os.path.exists(event_file):
@@ -221,11 +289,46 @@ async def load_assets():
221
  raise
222
 
223
  # ==========================================
224
- # 6. API ENDPOINTS
225
  # ==========================================
226
- @app.get("/", tags=["System"])
 
 
 
 
 
 
 
 
 
227
  def status_check():
228
- return {"status": "Online", "model": "Chronos-T5 Tiny", "calibrated": True}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
229
 
230
  def perform_inference(ctx, steps):
231
  forecast = pipeline.predict(ctx.unsqueeze(0), steps)
@@ -234,71 +337,143 @@ def perform_inference(ctx, steps):
234
  @app.post("/api/v1/predict", response_model=APIResponse, tags=["Prediction"])
235
  async def predict_waste_volume(req: PredictionRequest):
236
  if df_history is None or pipeline is None:
237
- raise HTTPException(503, "Model not ready.")
238
 
239
  try:
240
- start_date = parse_flexible_date(req.start_date) if req.start_date else pd.to_datetime(df_history["TANGGAL"].iloc[-1])
241
- ctx = torch.tensor(df_history["Volume_Total_Ton"].values, dtype=torch.float32)
242
- forecast_vals = await run_in_threadpool(perform_inference, ctx, req.forecast_days)
 
 
 
 
243
 
244
- # Calculate calibration factor: (Real World Baseline / Model Dataset Mean)
245
- # This bridges the gap between AI model scale and operational reality
246
  dataset_mean = df_history["Volume_Total_Ton"].mean()
247
- real_baseline = LOCATION_BASELINES[req.location]["normal_avg"]
248
  calibration_factor = real_baseline / dataset_mean
249
 
250
  o_r = (df_history["Vol_Sisa_Makanan_Ton"] / df_history["Volume_Total_Ton"]).mean()
251
  p_r = (df_history["Vol_Plastik_Ton"] / df_history["Volume_Total_Ton"]).mean()
252
 
 
 
 
 
 
 
 
253
  results = []
254
  total_vol = 0.0
255
  max_risk = "SAFE"
256
 
257
- for i, base in enumerate(forecast_vals):
258
- curr_date = start_date + timedelta(days=i)
259
- d_str = curr_date.strftime("%Y-%m-%d")
260
-
261
- # 1. Rainfall Multiplier
262
- rain_m = 1.0
263
- if req.rainfall_mm > 20: rain_m = 1.02 + min((req.rainfall_mm - 20) * 0.001, 0.03)
264
 
265
- # 2. Event Multiplier
266
- evt = events_data.get(d_str)
267
- evt_m = 1.0
268
- info = None
269
- if evt and evt["crowd_scale"] > 0 and check_location_match(req.location, evt["location"]):
270
- evt_m = 1.0 + 0.10 + min(evt["crowd_scale"] * 0.05, 0.25) # Up to +35%
271
- info = f"{evt['event_name']} @ {evt['location']}"
272
- elif req.event_scale > 0:
273
- evt_m = 1.0 + req.event_scale * 0.10
274
-
275
- # 3. Final Calculation with Calibration
276
- raw_prediction = base * rain_m * evt_m
277
- calibrated_volume = round(float(raw_prediction * calibration_factor), 2)
278
-
279
- total_vol += calibrated_volume
280
- risk = get_risk_status(calibrated_volume, req.location)
281
- if risk == "CRITICAL": max_risk = "CRITICAL"
282
- elif risk == "WARNING" and max_risk != "CRITICAL": max_risk = "WARNING"
283
-
284
- hourly = distribute_to_hourly(calibrated_volume, req.location) if req.granularity == "hourly" else None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
285
 
286
- results.append(PredictionResult(
287
- date=d_str, location=req.location, total_volume_ton=calibrated_volume,
288
- organic_waste_ton=round(calibrated_volume*o_r, 2), plastic_waste_ton=round(calibrated_volume*p_r, 2),
289
- recommended_trucks=max(1, int(np.ceil(calibrated_volume/5))), # 5-ton trucks for better granularity
290
- risk_status=risk, event_info=info, hourly_breakdown=hourly
291
- ))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
292
 
293
- # Logistics
294
  trucks = sum([r.recommended_trucks for r in results])
295
  msg = f"CRITICAL at {req.location}!" if max_risk == "CRITICAL" else f"WARNING at {req.location}." if max_risk == "WARNING" else "Normal conditions."
 
296
 
297
  return APIResponse(
298
- status="success", message=msg, confidence_score=0.92, # Fixed high confidence for calibrated model
299
  data=PredictionData(
300
  prediction_results=results,
301
- logistics_plan=LogisticsPlan(trucks_needed=trucks, manpower=trucks*3, estimated_duration_hours=round(total_vol/5, 1), efficiency_rate="85% (Optimal)")
 
 
 
 
 
302
  )
303
  )
304
  except HTTPException: raise
@@ -306,6 +481,39 @@ async def predict_waste_volume(req: PredictionRequest):
306
  logger.error(f"Prediction failed: {e}", exc_info=True)
307
  raise HTTPException(500, str(e))
308
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
309
  @app.get("/api/v1/alerts", response_model=AlertResponse, tags=["Alerts"])
310
  async def get_alerts(location: str = Query(None)):
311
  """Real-time alerts endpoint."""
@@ -313,23 +521,104 @@ async def get_alerts(location: str = Query(None)):
313
 
314
  alerts = []
315
  today = datetime.now().date()
316
- dataset_mean = df_history["Volume_Total_Ton"].mean()
317
 
318
  for i in range(3):
319
  d = (today + timedelta(days=i)).strftime("%Y-%m-%d")
320
  evt = events_data.get(d)
321
 
322
- for loc, config in LOCATION_BASELINES.items():
323
  if location and loc != location: continue
324
 
325
- # Simple projection for alerts
326
  baseline_vol = config["normal_avg"]
327
- if evt and evt["crowd_scale"] > 0 and check_location_match(loc, evt["location"]):
328
- baseline_vol = config["event_peak"]
329
 
330
  status = "CRITICAL" if baseline_vol > config["critical_threshold"] else "WARNING" if baseline_vol > config["warning_threshold"] else "SAFE"
331
 
332
  if status != "SAFE":
333
- alerts.append({"date": d, "location": loc, "status": status, "estimated_volume_ton": baseline_vol, "message": f"Alert: {status} volume expected at {loc}"})
 
 
 
 
334
 
335
- return AlertResponse(status="success", alert_count=len(alerts), alerts=alerts, last_updated=datetime.now().isoformat())
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  from fastapi import FastAPI, HTTPException, Query
2
  from fastapi.middleware.cors import CORSMiddleware
3
  from fastapi.concurrency import run_in_threadpool
4
+ from fastapi.responses import HTMLResponse, StreamingResponse
5
+ from fastapi.staticfiles import StaticFiles
6
  from pydantic import BaseModel, Field, field_validator
7
  from typing import Optional, List, Dict, Any
8
  import pandas as pd
9
  import numpy as np
10
  import torch
11
+ import joblib
12
+ import httpx
13
+ import io
14
+ import csv
15
+ import json
16
  from chronos import ChronosPipeline
17
  from datetime import datetime, timedelta
18
  import os, logging, re
 
24
  logger = logging.getLogger(__name__)
25
 
26
  app = FastAPI(
27
+ title="Waste Intelligence API - DKI Jakarta 2026",
28
+ version="4.0.0 (Multi-Region & Live News)",
29
+ description="AI-powered waste prediction for 44 sub-districts with spatial awareness, live weather, and news monitoring"
30
  )
31
 
32
  app.add_middleware(
 
37
  allow_headers=["*"],
38
  )
39
 
40
+ # Mount static files to serve the dashboard UI, CSS, and JS
41
+ if not os.path.exists("static"):
42
+ os.makedirs("static")
43
+ app.mount("/static", StaticFiles(directory="static"), name="static")
44
+
45
  # ==========================================
46
+ # 2. 44 KECAMATAN DATABASE (DLH Jakarta Calibrated)
47
  # ==========================================
48
+ KECAMATAN_DATABASE = {
49
+ # 1. JAKARTA PUSAT (8 Kecamatan) - Total: 1150 Ton
50
+ "Menteng": {"latitude": -6.1950, "longitude": 106.8322, "normal_avg": 120.0, "warning_threshold": 160.0, "critical_threshold": 180.0, "city": "Jakarta Pusat"},
51
+ "Senen": {"latitude": -6.1822, "longitude": 106.8452, "normal_avg": 180.0, "warning_threshold": 220.0, "critical_threshold": 240.0, "city": "Jakarta Pusat"},
52
+ "Cempaka Putih": {"latitude": -6.1802, "longitude": 106.8686, "normal_avg": 90.0, "warning_threshold": 120.0, "critical_threshold": 140.0, "city": "Jakarta Pusat"},
53
+ "Johar Baru": {"latitude": -6.1866, "longitude": 106.8572, "normal_avg": 70.0, "warning_threshold": 95.0, "critical_threshold": 110.0, "city": "Jakarta Pusat"},
54
+ "Kemayoran": {"latitude": -6.1628, "longitude": 106.8438, "normal_avg": 180.0, "warning_threshold": 220.0, "critical_threshold": 240.0, "city": "Jakarta Pusat"},
55
+ "Sawah Besar": {"latitude": -6.1554, "longitude": 106.8322, "normal_avg": 110.0, "warning_threshold": 145.0, "critical_threshold": 165.0, "city": "Jakarta Pusat"},
56
+ "Tanah Abang": {"latitude": -6.2104, "longitude": 106.8122, "normal_avg": 250.0, "warning_threshold": 320.0, "critical_threshold": 350.0, "city": "Jakarta Pusat"},
57
+ "Gambir": {"latitude": -6.1764, "longitude": 106.8190, "normal_avg": 150.0, "warning_threshold": 195.0, "critical_threshold": 215.0, "city": "Jakarta Pusat"},
58
+
59
+ # 2. JAKARTA UTARA (6 Kecamatan) - Total: 1350 Ton
60
+ "Penjaringan": {"latitude": -6.1264, "longitude": 106.7822, "normal_avg": 280.0, "warning_threshold": 350.0, "critical_threshold": 380.0, "city": "Jakarta Utara"},
61
+ "Tanjung Priok": {"latitude": -6.1322, "longitude": 106.8722, "normal_avg": 260.0, "warning_threshold": 320.0, "critical_threshold": 350.0, "city": "Jakarta Utara"},
62
+ "Koja": {"latitude": -6.1214, "longitude": 106.9133, "normal_avg": 190.0, "warning_threshold": 240.0, "critical_threshold": 270.0, "city": "Jakarta Utara"},
63
+ "Cilincing": {"latitude": -6.1288, "longitude": 106.9452, "normal_avg": 290.0, "warning_threshold": 370.0, "critical_threshold": 400.0, "city": "Jakarta Utara"},
64
+ "Pademangan": {"latitude": -6.1328, "longitude": 106.8422, "normal_avg": 140.0, "warning_threshold": 180.0, "critical_threshold": 200.0, "city": "Jakarta Utara"},
65
+ "Kelapa Gading": {"latitude": -6.1552, "longitude": 106.9022, "normal_avg": 190.0, "warning_threshold": 240.0, "critical_threshold": 270.0, "city": "Jakarta Utara"},
66
+
67
+ # 3. JAKARTA BARAT (8 Kecamatan) - Total: 1550 Ton
68
+ "Cengkareng": {"latitude": -6.1528, "longitude": 106.7322, "normal_avg": 340.0, "warning_threshold": 420.0, "critical_threshold": 460.0, "city": "Jakarta Barat"},
69
+ "Grogol Petamburan": {"latitude": -6.1622, "longitude": 106.7882, "normal_avg": 220.0, "warning_threshold": 280.0, "critical_threshold": 310.0, "city": "Jakarta Barat"},
70
+ "Kalideres": {"latitude": -6.1428, "longitude": 106.7022, "normal_avg": 260.0, "warning_threshold": 330.0, "critical_threshold": 360.0, "city": "Jakarta Barat"},
71
+ "Kebon Jeruk": {"latitude": -6.1922, "longitude": 106.7722, "normal_avg": 210.0, "warning_threshold": 260.0, "critical_threshold": 290.0, "city": "Jakarta Barat"},
72
+ "Kembangan": {"latitude": -6.1828, "longitude": 106.7382, "normal_avg": 180.0, "warning_threshold": 230.0, "critical_threshold": 250.0, "city": "Jakarta Barat"},
73
+ "Palmerah": {"latitude": -6.2028, "longitude": 106.7882, "normal_avg": 160.0, "warning_threshold": 200.0, "critical_threshold": 220.0, "city": "Jakarta Barat"},
74
+ "Taman Sari": {"latitude": -6.1454, "longitude": 106.8182, "normal_avg": 100.0, "warning_threshold": 130.0, "critical_threshold": 150.0, "city": "Jakarta Barat"},
75
+ "Tambora": {"latitude": -6.1500, "longitude": 106.8000, "normal_avg": 80.0, "warning_threshold": 110.0, "critical_threshold": 125.0, "city": "Jakarta Barat"},
76
+
77
+ # 4. JAKARTA SELATAN (10 Kecamatan) - Total: 1850 Ton
78
+ "Cilandak": {"latitude": -6.2928, "longitude": 106.7922, "normal_avg": 180.0, "warning_threshold": 230.0, "critical_threshold": 250.0, "city": "Jakarta Selatan"},
79
+ "Jagakarsa": {"latitude": -6.3328, "longitude": 106.8222, "normal_avg": 220.0, "warning_threshold": 280.0, "critical_threshold": 310.0, "city": "Jakarta Selatan"},
80
+ "Kebayoran Baru": {"latitude": -6.2422, "longitude": 106.7982, "normal_avg": 210.0, "warning_threshold": 260.0, "critical_threshold": 290.0, "city": "Jakarta Selatan"},
81
+ "Kebayoran Lama": {"latitude": -6.2488, "longitude": 106.7722, "normal_avg": 230.0, "warning_threshold": 290.0, "critical_threshold": 320.0, "city": "Jakarta Selatan"},
82
+ "Mampang Prapatan": {"latitude": -6.2522, "longitude": 106.8182, "normal_avg": 120.0, "warning_threshold": 150.0, "critical_threshold": 170.0, "city": "Jakarta Selatan"},
83
+ "Pancoran": {"latitude": -6.2622, "longitude": 106.8382, "normal_avg": 130.0, "warning_threshold": 160.0, "critical_threshold": 180.0, "city": "Jakarta Selatan"},
84
+ "Pasar Minggu": {"latitude": -6.2828, "longitude": 106.8438, "normal_avg": 240.0, "warning_threshold": 300.0, "critical_threshold": 330.0, "city": "Jakarta Selatan"},
85
+ "Pesanggrahan": {"latitude": -6.2588, "longitude": 106.7588, "normal_avg": 160.0, "warning_threshold": 200.0, "critical_threshold": 220.0, "city": "Jakarta Selatan"},
86
+ "Setiabudi": {"latitude": -6.2228, "longitude": 106.8282, "normal_avg": 190.0, "warning_threshold": 240.0, "critical_threshold": 270.0, "city": "Jakarta Selatan"},
87
+ "Tebet": {"latitude": -6.2288, "longitude": 106.8482, "normal_avg": 170.0, "warning_threshold": 210.0, "critical_threshold": 230.0, "city": "Jakarta Selatan"},
88
+
89
+ # 5. JAKARTA TIMUR (10 Kecamatan) - Total: 2100 Ton
90
+ "Cakung": {"latitude": -6.1828, "longitude": 106.9482, "normal_avg": 350.0, "warning_threshold": 430.0, "critical_threshold": 470.0, "city": "Jakarta Timur"},
91
+ "Cipayung": {"latitude": -6.3128, "longitude": 106.9022, "normal_avg": 140.0, "warning_threshold": 180.0, "critical_threshold": 200.0, "city": "Jakarta Timur"},
92
+ "Ciracas": {"latitude": -6.3228, "longitude": 106.8782, "normal_avg": 190.0, "warning_threshold": 240.0, "critical_threshold": 270.0, "city": "Jakarta Timur"},
93
+ "Duren Sawit": {"latitude": -6.2228, "longitude": 106.9282, "normal_avg": 300.0, "warning_threshold": 370.0, "critical_threshold": 410.0, "city": "Jakarta Timur"},
94
+ "Jatinegara": {"latitude": -6.2222, "longitude": 106.8682, "normal_avg": 240.0, "warning_threshold": 300.0, "critical_threshold": 330.0, "city": "Jakarta Timur"},
95
+ "Kramat Jati": {"latitude": -6.2722, "longitude": 106.8682, "normal_avg": 220.0, "warning_threshold": 270.0, "critical_threshold": 300.0, "city": "Jakarta Timur"},
96
+ "Makasar": {"latitude": -6.2622, "longitude": 106.8782, "normal_avg": 160.0, "warning_threshold": 200.0, "critical_threshold": 220.0, "city": "Jakarta Timur"},
97
+ "Matraman": {"latitude": -6.2022, "longitude": 106.8582, "normal_avg": 130.0, "warning_threshold": 160.0, "critical_threshold": 180.0, "city": "Jakarta Timur"},
98
+ "Pasar Rebo": {"latitude": -6.3122, "longitude": 106.8522, "normal_avg": 150.0, "warning_threshold": 190.0, "critical_threshold": 210.0, "city": "Jakarta Timur"},
99
+ "Pulo Gadung": {"latitude": -6.1922, "longitude": 106.8922, "normal_avg": 220.0, "warning_threshold": 270.0, "critical_threshold": 300.0, "city": "Jakarta Timur"},
100
 
101
+ # 6. KEPULAUAN SERIBU (2 Kecamatan) - Total: 20 Ton
102
+ "Kepulauan Seribu Utara": {"latitude": -5.5722, "longitude": 106.5522, "normal_avg": 11.0, "warning_threshold": 15.0, "critical_threshold": 18.0, "city": "Kepulauan Seribu"},
103
+ "Kepulauan Seribu Selatan": {"latitude": -5.7722, "longitude": 106.6522, "normal_avg": 9.0, "warning_threshold": 12.0, "critical_threshold": 15.0, "city": "Kepulauan Seribu"}
104
+ }
105
+
106
+ ALLOWED_LOCATIONS = list(KECAMATAN_DATABASE.keys())
107
+
108
+ # ==========================================
109
+ # 3. INPUT VALIDATION & SCHEMAS
110
+ # ==========================================
111
  class PredictionRequest(BaseModel):
 
 
 
 
112
  forecast_days: int = Field(7, ge=1, le=30, description="Forecast horizon in days (1-30)")
113
+ rainfall_mm: float = Field(0.0, ge=0, description="Precipitation override. 0.0 means Auto (Open-Meteo)")
114
  event_scale: int = Field(0, ge=0, le=5, description="Manual event crowd scale (0=none, 5=massive)")
115
+ location: str = Field(..., description="Target sub-district (Kecamatan)")
116
+ start_date: Optional[str] = Field(None, description="Start date: YYYY-MM-DD")
117
+ granularity: str = Field("daily", pattern="^(daily|hourly)$", description="Granularity")
118
+ model_type: str = Field("chronos", pattern="^(chronos|gradient_boosting)$", description="AI model type")
119
 
120
  @field_validator("location")
121
  @classmethod
122
  def validate_location(cls, v: str) -> str:
123
  if v not in ALLOWED_LOCATIONS:
124
+ raise ValueError(f"Kecamatan not recognized. Use one of the 44 sub-districts in Jakarta.")
125
  return v
126
 
127
  class PredictionResult(BaseModel):
 
130
  total_volume_ton: float
131
  organic_waste_ton: float
132
  plastic_waste_ton: float
133
+ paper_waste_ton: float
134
+ metal_waste_ton: float
135
+ glass_waste_ton: float
136
+ textile_waste_ton: float
137
+ other_waste_ton: float
138
  recommended_trucks: int
139
  risk_status: str
140
  event_info: Optional[str] = None
 
163
  last_updated: str
164
 
165
  # ==========================================
166
+ # 4. GLOBAL STATE & MODELS
167
  # ==========================================
168
  pipeline = None
169
+ model_gbr = None
170
  df_history = None
171
  events_data = {}
172
+ WEATHER_CACHE = {}
173
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
174
  HOURLY_PATTERN = {
175
  0:0.02, 1:0.01, 2:0.01, 3:0.01, 4:0.02, 5:0.03,
176
  6:0.05, 7:0.07, 8:0.06, 9:0.05, 10:0.04, 11:0.04,
 
179
  }
180
 
181
  # ==========================================
182
+ # 5. HELPER FUNCTIONS
183
  # ==========================================
184
  def parse_flexible_date(date_input: str, default_year: int = 2026) -> pd.Timestamp:
 
185
  if not date_input: return None
186
  date_input = date_input.strip()
187
+ for fmt in ["%Y-%m-%d", "%d-%m-%Y", "%m-%d", "%d %B %Y", "%d %b %Y", "%B %d, %Y"]:
188
  try:
189
  parsed = datetime.strptime(date_input, fmt)
190
  if fmt == "%m-%d": parsed = parsed.replace(year=default_year)
191
  return pd.Timestamp(parsed)
192
  except ValueError: continue
 
 
 
 
 
 
193
  raise ValueError(f"Unrecognized date format: '{date_input}'")
194
 
 
 
 
 
 
 
 
 
195
  def get_risk_status(volume: float, location: str) -> str:
196
+ config = KECAMATAN_DATABASE.get(location, KECAMATAN_DATABASE["Menteng"])
 
197
  if volume > config["critical_threshold"]:
198
  return "CRITICAL"
199
  elif volume > config["warning_threshold"]:
200
  return "WARNING"
201
  return "SAFE"
202
 
203
+ def distribute_to_hourly(daily_volume: float) -> List[Dict[str, Any]]:
 
204
  pattern = HOURLY_PATTERN.copy()
 
 
 
 
 
 
205
  total_factor = sum(pattern.values())
206
  hourly_results = []
207
 
 
208
  high_thresh = (daily_volume / 24) * 2.0
209
  med_thresh = (daily_volume / 24) * 1.2
210
 
 
220
  })
221
  return hourly_results
222
 
223
+ async def fetch_rainfall_forecast(lat: float, lon: float, days: int) -> dict:
224
+ """Fetch daily rainfall forecast from Open-Meteo API (with 30-min in-memory caching and short timeout)"""
225
+ cache_key = f"{lat:.2f}_{lon:.2f}_{days}"
226
+ now = datetime.now()
227
+
228
+ # Expiration Cache Check
229
+ if cache_key in WEATHER_CACHE:
230
+ cached_data, timestamp = WEATHER_CACHE[cache_key]
231
+ if now - timestamp < timedelta(minutes=30):
232
+ logger.info(f"⚡ Weather cache hit for {cache_key}")
233
+ return cached_data
234
+
235
+ url = f"https://api.open-meteo.com/v1/forecast?latitude={lat}&longitude={lon}&daily=precipitation_sum&timezone=Asia/Jakarta&forecast_days={days}&past_days=2"
236
+ try:
237
+ async with httpx.AsyncClient() as client:
238
+ response = await client.get(url, timeout=1.5) # Short timeout
239
+ if response.status_code == 200:
240
+ data = response.json()
241
+ daily = data.get("daily", {})
242
+ times = daily.get("time", [])
243
+ precip = daily.get("precipitation_sum", [])
244
+ result = {times[i]: float(precip[i]) for i in range(len(times)) if i < len(precip)}
245
+
246
+ # Save to cache
247
+ WEATHER_CACHE[cache_key] = (result, now)
248
+ return result
249
+ except Exception as e:
250
+ logger.error(f"Failed to fetch weather from Open-Meteo: {e}")
251
+
252
+ return {}
253
+
254
  # ==========================================
255
+ # 6. STARTUP & LOAD MODEL
256
  # ==========================================
257
  @app.on_event("startup")
258
  async def load_assets():
259
+ global pipeline, model_gbr, df_history, events_data
260
+ logger.info("⏳ Initializing multi-region AI models...")
 
261
  try:
262
  pipeline = ChronosPipeline.from_pretrained("amazon/chronos-t5-tiny", device_map="cpu", torch_dtype=torch.float32)
263
+ logger.info("✅ Chronos pipeline loaded")
264
+
265
+ if os.path.exists("model_sampah_advanced.pkl"):
266
+ model_gbr = joblib.load("model_sampah_advanced.pkl")
267
+ logger.info("✅ Upgraded GBR model loaded")
268
 
269
  df_history = pd.read_csv("dataset_vibe_coder_2026.csv")
270
  df_history["TANGGAL"] = pd.to_datetime(df_history["TANGGAL"]).dt.strftime("%Y-%m-%d")
271
+ logger.info(f"✅ Baseline dataset loaded: {len(df_history)} records")
272
 
273
  event_file = "event_jakarta_2026.txt"
274
  if os.path.exists(event_file):
 
289
  raise
290
 
291
  # ==========================================
292
+ # 7. ROUTING & CONTROLLERS
293
  # ==========================================
294
+ @app.get("/", response_class=HTMLResponse, tags=["UI"])
295
+ def serve_dashboard():
296
+ """Serve the Floodzy-style interactive dashboard."""
297
+ try:
298
+ with open("static/index.html", "r", encoding="utf-8") as f:
299
+ return HTMLResponse(content=f.read(), status_code=200)
300
+ except FileNotFoundError:
301
+ return HTMLResponse(content="<h1>Dashboard HTML not found. Please check your static directory.</h1>", status_code=404)
302
+
303
+ @app.get("/status", tags=["System"])
304
  def status_check():
305
+ return {
306
+ "status": "Online",
307
+ "model_chronos": "Chronos-T5 Tiny",
308
+ "model_gbr": "Gradient Boosting Regressor (Upgraded)",
309
+ "coverage": "44 Kecamatan DKI Jakarta",
310
+ "calibrated": True
311
+ }
312
+
313
+ @app.get("/api/v1/news", tags=["News"])
314
+ def get_latest_news():
315
+ """Returns the latest crawled news from latest_waste_news.json"""
316
+ news_file = "latest_waste_news.json"
317
+ if os.path.exists(news_file):
318
+ try:
319
+ with open(news_file, "r", encoding="utf-8") as f:
320
+ return json.load(f)
321
+ except Exception as e:
322
+ logger.error(f"Error reading news file: {e}")
323
+ return [
324
+ {
325
+ "title": "DKI Uji Coba Penarikan Retribusi Sampah Pelayanan Kebersihan Harian",
326
+ "source": "Antara News",
327
+ "url": "https://www.antaranews.com/tag/sampah-jakarta",
328
+ "date_fetched": str(datetime.now().date()),
329
+ "summary": "Pemprov DKI Jakarta merencanakan uji coba penarikan retribusi pelayanan kebersihan/sampah."
330
+ }
331
+ ]
332
 
333
  def perform_inference(ctx, steps):
334
  forecast = pipeline.predict(ctx.unsqueeze(0), steps)
 
337
  @app.post("/api/v1/predict", response_model=APIResponse, tags=["Prediction"])
338
  async def predict_waste_volume(req: PredictionRequest):
339
  if df_history is None or pipeline is None:
340
+ raise HTTPException(503, "Models not ready.")
341
 
342
  try:
343
+ start_date = parse_flexible_date(req.start_date) if req.start_date else pd.Timestamp(datetime.now().date())
344
+
345
+ # Get location metadata
346
+ config = KECAMATAN_DATABASE[req.location]
347
+
348
+ # Fetch live weather forecast from Open-Meteo API
349
+ weather_forecast = await fetch_rainfall_forecast(config["latitude"], config["longitude"], req.forecast_days)
350
 
351
+ # Calibrations Setup
 
352
  dataset_mean = df_history["Volume_Total_Ton"].mean()
353
+ real_baseline = config["normal_avg"]
354
  calibration_factor = real_baseline / dataset_mean
355
 
356
  o_r = (df_history["Vol_Sisa_Makanan_Ton"] / df_history["Volume_Total_Ton"]).mean()
357
  p_r = (df_history["Vol_Plastik_Ton"] / df_history["Volume_Total_Ton"]).mean()
358
 
359
+ # Remaining ratios from official DLH Jakarta statistics:
360
+ paper_r = 0.115
361
+ metal_r = 0.021
362
+ glass_r = 0.032
363
+ textile_r = 0.042
364
+ other_r = max(0.01, 1.0 - (o_r + p_r + paper_r + metal_r + glass_r + textile_r))
365
+
366
  results = []
367
  total_vol = 0.0
368
  max_risk = "SAFE"
369
 
370
+ # Chronos Forecasting Pipeline
371
+ if req.model_type == "chronos":
372
+ ctx = torch.tensor(df_history["Volume_Total_Ton"].values, dtype=torch.float32)
373
+ forecast_vals = await run_in_threadpool(perform_inference, ctx, req.forecast_days)
 
 
 
374
 
375
+ for i, base in enumerate(forecast_vals):
376
+ curr_date = start_date + timedelta(days=i)
377
+ d_str = curr_date.strftime("%Y-%m-%d")
378
+
379
+ # Retrieve weather rain
380
+ rain_val = req.rainfall_mm if (req.rainfall_mm > 0.0 and i == 0) else weather_forecast.get(d_str, 0.0)
381
+ rain_m = 1.0
382
+ if rain_val > 20:
383
+ rain_m = 1.02 + min((rain_val - 20) * 0.001, 0.03)
384
+
385
+ # Events multiplier
386
+ evt = events_data.get(d_str)
387
+ evt_m = 1.0
388
+ info = None
389
+ if evt and evt["crowd_scale"] > 0 and (req.location.lower() in evt["location"].lower() or evt["location"].lower() == "jakarta"):
390
+ evt_m = 1.0 + 0.10 + min(evt["crowd_scale"] * 0.05, 0.25)
391
+ info = f"{evt['event_name']} @ {evt['location']}"
392
+ elif req.event_scale > 0:
393
+ evt_m = 1.0 + req.event_scale * 0.10
394
+
395
+ raw_prediction = base * rain_m * evt_m
396
+ calibrated_volume = round(float(raw_prediction * calibration_factor), 2)
397
+
398
+ total_vol += calibrated_volume
399
+ risk = get_risk_status(calibrated_volume, req.location)
400
+ if risk == "CRITICAL": max_risk = "CRITICAL"
401
+ elif risk == "WARNING" and max_risk != "CRITICAL": max_risk = "WARNING"
402
+
403
+ hourly = distribute_to_hourly(calibrated_volume) if req.granularity == "hourly" else None
404
+
405
+ results.append(PredictionResult(
406
+ date=d_str, location=req.location, total_volume_ton=calibrated_volume,
407
+ organic_waste_ton=round(calibrated_volume*o_r, 2), plastic_waste_ton=round(calibrated_volume*p_r, 2),
408
+ paper_waste_ton=round(calibrated_volume*paper_r, 2), metal_waste_ton=round(calibrated_volume*metal_r, 2),
409
+ glass_waste_ton=round(calibrated_volume*glass_r, 2), textile_waste_ton=round(calibrated_volume*textile_r, 2),
410
+ other_waste_ton=round(calibrated_volume*other_r, 2),
411
+ recommended_trucks=max(1, int(np.ceil(calibrated_volume/5))),
412
+ risk_status=risk, event_info=info, hourly_breakdown=hourly
413
+ ))
414
+
415
+ # Gradient Boosting Regressor Pipeline
416
+ elif req.model_type == "gradient_boosting":
417
+ if model_gbr is None:
418
+ raise HTTPException(503, "Gradient Boosting model not loaded.")
419
 
420
+ for i in range(req.forecast_days):
421
+ curr_date = start_date + timedelta(days=i)
422
+ d_str = curr_date.strftime("%Y-%m-%d")
423
+
424
+ rain_val = req.rainfall_mm if (req.rainfall_mm > 0.0 and i == 0) else weather_forecast.get(d_str, 0.0)
425
+ rain_lag1 = req.rainfall_mm if (req.rainfall_mm > 0.0 and i == 1) else weather_forecast.get((curr_date - timedelta(days=1)).strftime("%Y-%m-%d"), 0.0)
426
+
427
+ evt = events_data.get(d_str)
428
+ has_event = 1 if (evt and (req.location.lower() in evt["location"].lower() or evt["location"].lower() == "jakarta")) else 0
429
+ crowd = float(evt["crowd_scale"]) if has_event else (float(req.event_scale) if i == 0 else 0.0)
430
+ info = f"{evt['event_name']} @ {evt['location']}" if has_event else None
431
+
432
+ # Fitur dataframe construction matching train.py
433
+ features = pd.DataFrame([{
434
+ 'Penumpang_MRT': 85000,
435
+ 'Ada_Event': has_event or (1 if (req.event_scale > 0 and i == 0) else 0),
436
+ 'Curah_Hujan_mm': rain_val,
437
+ 'Hujan_Kemarin': rain_lag1,
438
+ 'Hari_Dalam_Minggu': curr_date.weekday(),
439
+ 'Bulan': curr_date.month,
440
+ 'Is_Weekend': 1 if curr_date.weekday() >= 5 else 0
441
+ }])
442
+
443
+ raw_pred = float(model_gbr.predict(features)[0])
444
+ calibrated_volume = round(float(raw_pred * calibration_factor), 2)
445
+
446
+ total_vol += calibrated_volume
447
+ risk = get_risk_status(calibrated_volume, req.location)
448
+ if risk == "CRITICAL": max_risk = "CRITICAL"
449
+ elif risk == "WARNING" and max_risk != "CRITICAL": max_risk = "WARNING"
450
+
451
+ hourly = distribute_to_hourly(calibrated_volume) if req.granularity == "hourly" else None
452
+
453
+ results.append(PredictionResult(
454
+ date=d_str, location=req.location, total_volume_ton=calibrated_volume,
455
+ organic_waste_ton=round(calibrated_volume*o_r, 2), plastic_waste_ton=round(calibrated_volume*p_r, 2),
456
+ paper_waste_ton=round(calibrated_volume*paper_r, 2), metal_waste_ton=round(calibrated_volume*metal_r, 2),
457
+ glass_waste_ton=round(calibrated_volume*glass_r, 2), textile_waste_ton=round(calibrated_volume*textile_r, 2),
458
+ other_waste_ton=round(calibrated_volume*other_r, 2),
459
+ recommended_trucks=max(1, int(np.ceil(calibrated_volume/5))),
460
+ risk_status=risk, event_info=info, hourly_breakdown=hourly
461
+ ))
462
 
 
463
  trucks = sum([r.recommended_trucks for r in results])
464
  msg = f"CRITICAL at {req.location}!" if max_risk == "CRITICAL" else f"WARNING at {req.location}." if max_risk == "WARNING" else "Normal conditions."
465
+ conf = 0.9828 if req.model_type == "gradient_boosting" else 0.92
466
 
467
  return APIResponse(
468
+ status="success", message=msg, confidence_score=conf,
469
  data=PredictionData(
470
  prediction_results=results,
471
+ logistics_plan=LogisticsPlan(
472
+ trucks_needed=trucks,
473
+ manpower=trucks*3,
474
+ estimated_duration_hours=round(total_vol/5, 1),
475
+ efficiency_rate="85% (Optimal)"
476
+ )
477
  )
478
  )
479
  except HTTPException: raise
 
481
  logger.error(f"Prediction failed: {e}", exc_info=True)
482
  raise HTTPException(500, str(e))
483
 
484
+ @app.post("/api/v1/predict/csv", tags=["Prediction"])
485
+ async def predict_waste_volume_csv(req: PredictionRequest):
486
+ res = await predict_waste_volume(req)
487
+
488
+ output = io.StringIO()
489
+ writer = csv.writer(output)
490
+
491
+ # Write CSV Header
492
+ writer.writerow([
493
+ "Date", "Location", "Total Volume (Tons)",
494
+ "Organic Waste (Tons)", "Plastic Waste (Tons)",
495
+ "Paper Waste (Tons)", "Metal Waste (Tons)",
496
+ "Glass Waste (Tons)", "Textile Waste (Tons)",
497
+ "Risk Status", "Event Info", "Recommended Trucks (5T)"
498
+ ])
499
+
500
+ for r in res.data.prediction_results:
501
+ writer.writerow([
502
+ r.date, r.location, r.total_volume_ton,
503
+ r.organic_waste_ton, r.plastic_waste_ton,
504
+ r.paper_waste_ton, r.metal_waste_ton,
505
+ r.glass_waste_ton, r.textile_waste_ton,
506
+ r.risk_status, r.event_info or "", r.recommended_trucks
507
+ ])
508
+
509
+ output.seek(0)
510
+ filename = f"waste_forecast_{req.location.replace(' ', '_')}_{req.forecast_days}d.csv"
511
+ return StreamingResponse(
512
+ io.BytesIO(output.getvalue().encode("utf-8")),
513
+ media_type="text/csv",
514
+ headers={"Content-Disposition": f"attachment; filename={filename}"}
515
+ )
516
+
517
  @app.get("/api/v1/alerts", response_model=AlertResponse, tags=["Alerts"])
518
  async def get_alerts(location: str = Query(None)):
519
  """Real-time alerts endpoint."""
 
521
 
522
  alerts = []
523
  today = datetime.now().date()
 
524
 
525
  for i in range(3):
526
  d = (today + timedelta(days=i)).strftime("%Y-%m-%d")
527
  evt = events_data.get(d)
528
 
529
+ for loc, config in KECAMATAN_DATABASE.items():
530
  if location and loc != location: continue
531
 
 
532
  baseline_vol = config["normal_avg"]
533
+ if evt and evt["crowd_scale"] > 0 and (loc.lower() in evt["location"].lower() or evt["location"].lower() == "jakarta"):
534
+ baseline_vol = config["normal_avg"] * 1.5
535
 
536
  status = "CRITICAL" if baseline_vol > config["critical_threshold"] else "WARNING" if baseline_vol > config["warning_threshold"] else "SAFE"
537
 
538
  if status != "SAFE":
539
+ alerts.append({
540
+ "date": d, "location": loc, "status": status,
541
+ "estimated_volume_ton": baseline_vol,
542
+ "message": f"Alert: {status} volume expected at {loc}"
543
+ })
544
 
545
+ return AlertResponse(status="success", alert_count=len(alerts), alerts=alerts, last_updated=datetime.now().isoformat())
546
+
547
+ @app.get("/api/v1/autopilot", tags=["Autonomous"])
548
+ async def get_autopilot_data():
549
+ """Autonomous autopilot aggregator that predicts for all 44 kecamatan for today using GBR."""
550
+ if df_history is None:
551
+ raise HTTPException(503, "Models not ready")
552
+
553
+ today = datetime.now()
554
+ d_str = today.strftime("%Y-%m-%d")
555
+
556
+ total_vol = 0.0
557
+ total_trucks = 0
558
+ kecamatan_results = []
559
+ rainy_count = 0
560
+
561
+ # Check if there is an event today
562
+ evt = events_data.get(d_str)
563
+
564
+ for loc, config in KECAMATAN_DATABASE.items():
565
+ # Calibrations Setup
566
+ dataset_mean = df_history["Volume_Total_Ton"].mean()
567
+ real_baseline = config["normal_avg"]
568
+ calibration_factor = real_baseline / dataset_mean
569
+
570
+ # Check weather cache
571
+ cache_key = f"{config['latitude']:.2f}_{config['longitude']:.2f}_7"
572
+ rain_val = 0.0
573
+ if cache_key in WEATHER_CACHE:
574
+ rain_val = WEATHER_CACHE[cache_key][0].get(d_str, 0.0)
575
+ if rain_val > 1.0: rainy_count += 1
576
+
577
+ has_event = 1 if (evt and (loc.lower() in evt["location"].lower() or evt["location"].lower() == "jakarta")) else 0
578
+
579
+ # Build features for GBR
580
+ features = pd.DataFrame([{
581
+ 'Penumpang_MRT': 85000,
582
+ 'Ada_Event': has_event,
583
+ 'Curah_Hujan_mm': rain_val,
584
+ 'Hujan_Kemarin': 0.0,
585
+ 'Hari_Dalam_Minggu': today.weekday(),
586
+ 'Bulan': today.month,
587
+ 'Is_Weekend': 1 if today.weekday() >= 5 else 0
588
+ }])
589
+
590
+ # Predict
591
+ if model_gbr is not None:
592
+ raw_pred = float(model_gbr.predict(features)[0])
593
+ else:
594
+ raw_pred = dataset_mean # Fallback
595
+
596
+ calibrated_volume = round(float(raw_pred * calibration_factor), 2)
597
+ trucks = max(1, int(np.ceil(calibrated_volume / 5)))
598
+
599
+ status = "CRITICAL" if calibrated_volume > config["critical_threshold"] else "WARNING" if calibrated_volume > config["warning_threshold"] else "SAFE"
600
+
601
+ total_vol += calibrated_volume
602
+ total_trucks += trucks
603
+
604
+ kecamatan_results.append({
605
+ "location": loc,
606
+ "volume_ton": calibrated_volume,
607
+ "trucks": trucks,
608
+ "status": status,
609
+ "city": config["city"]
610
+ })
611
+
612
+ # Sort by volume to get Top 5
613
+ kecamatan_results.sort(key=lambda x: x["volume_ton"], reverse=True)
614
+ top_5 = kecamatan_results[:5]
615
+
616
+ return {
617
+ "status": "success",
618
+ "date": d_str,
619
+ "total_volume_ton": round(total_vol, 2),
620
+ "total_trucks": total_trucks,
621
+ "top_kecamatan": top_5,
622
+ "rainy_regions": rainy_count,
623
+ "event_today": evt["event_name"] if evt else None
624
+ }
dataset_advanced_eco_twin.csv ADDED
@@ -0,0 +1,732 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Tanggal,Ada_Event,Penumpang_MRT,Curah_Hujan_mm,Hari_Dalam_Minggu,Bulan,Is_Weekend,Hujan_Kemarin,Volume_Sampah_Ton
2
+ 2023-01-01,1.0,76866,12.064192542930495,6,1,1,0.0,11069.14
3
+ 2023-01-02,0.0,87444,5.810788653951948,0,1,0,12.064192542930495,8091.7
4
+ 2023-01-03,0.0,115487,12.912335419604084,1,1,0,5.810788653951948,8253.36
5
+ 2023-01-04,0.0,80859,11.092612937467463,2,1,0,12.912335419604084,8181.11
6
+ 2023-01-05,0.0,81949,13.881043656415027,3,1,0,11.092612937467463,7993.37
7
+ 2023-01-06,0.0,91088,27.729745386705478,4,1,0,13.881043656415027,8306.94
8
+ 2023-01-07,0.0,76580,0.0,5,1,1,27.729745386705478,8916.35
9
+ 2023-01-08,0.0,61952,0.0,6,1,1,0.0,8412.33
10
+ 2023-01-09,0.0,85120,0.0,0,1,0,0.0,7877.12
11
+ 2023-01-10,0.0,96037,3.7091599256309693,1,1,0,0.0,8018.52
12
+ 2023-01-11,0.0,64183,15.732629959146113,2,1,0,3.7091599256309693,8113.42
13
+ 2023-01-12,0.0,78997,16.050440529705195,3,1,0,15.732629959146113,8136.7
14
+ 2023-01-13,0.0,88087,0.0,4,1,0,16.050440529705195,8156.51
15
+ 2023-01-14,0.0,106860,47.23876891191401,5,1,1,0.0,8989.34
16
+ 2023-01-15,0.0,89675,13.375900945745519,6,1,1,47.23876891191401,8975.91
17
+ 2023-01-16,0.0,87745,3.8543330692429625,0,1,0,13.375900945745519,7991.64
18
+ 2023-01-17,0.0,97676,7.529234998019818,1,1,0,3.8543330692429625,8118.85
19
+ 2023-01-18,0.0,83901,18.792313010048666,2,1,0,7.529234998019818,8029.21
20
+ 2023-01-19,0.0,103214,8.822025431378183,3,1,0,18.792313010048666,8172.78
21
+ 2023-01-20,0.0,84237,2.0605073141124266,4,1,0,8.822025431378183,7877.33
22
+ 2023-01-21,0.0,80160,0.0,5,1,1,2.0605073141124266,8593.64
23
+ 2023-01-22,0.0,84051,11.511183024663607,6,1,1,0.0,8971.85
24
+ 2023-01-23,0.0,68568,2.898997951738329,0,1,0,11.511183024663607,8069.87
25
+ 2023-01-24,0.0,86748,26.768252455857922,1,1,0,2.898997951738329,7977.29
26
+ 2023-01-25,0.0,89254,13.202753474005217,2,1,0,26.768252455857922,8060.53
27
+ 2023-01-26,0.0,80701,5.6857872848279625,3,1,0,13.202753474005217,8073.7
28
+ 2023-01-27,0.0,104635,0.0,4,1,0,5.6857872848279625,8075.08
29
+ 2023-01-28,0.0,92114,6.2643308559733395,5,1,1,0.0,8838.12
30
+ 2023-01-29,0.0,73488,3.41070851720309,6,1,1,6.2643308559733395,8919.54
31
+ 2023-01-30,0.0,101185,14.827486504769332,0,1,0,3.41070851720309,8163.43
32
+ 2023-01-31,0.0,96841,39.43628506587022,1,1,0,14.827486504769332,8509.44
33
+ 2023-02-01,0.0,81090,16.458748408666093,2,2,0,39.43628506587022,8521.36
34
+ 2023-02-02,0.0,91384,14.135033948417043,3,2,0,16.458748408666093,8322.98
35
+ 2023-02-03,0.0,78117,0.0,4,2,0,14.135033948417043,8276.55
36
+ 2023-02-04,0.0,74131,34.70628533718897,5,2,1,0.0,8610.12
37
+ 2023-02-05,0.0,93486,7.06721920754921,6,2,1,34.70628533718897,9174.83
38
+ 2023-02-06,0.0,99738,0.0,0,2,0,7.06721920754921,7761.64
39
+ 2023-02-07,0.0,86069,2.023555263753742,1,2,0,0.0,8163.97
40
+ 2023-02-08,0.0,85021,7.3816957882642,2,2,0,2.023555263753742,8469.65
41
+ 2023-02-09,0.0,69293,10.667456963851162,3,2,0,7.3816957882642,8234.32
42
+ 2023-02-10,0.0,84658,0.0,4,2,0,10.667456963851162,8205.46
43
+ 2023-02-11,0.0,96455,22.227040830462204,5,2,1,0.0,8524.76
44
+ 2023-02-12,0.0,79547,6.951749605924486,6,2,1,22.227040830462204,8883.46
45
+ 2023-02-13,0.0,83401,10.343842157216185,0,2,0,6.951749605924486,8126.08
46
+ 2023-02-14,0.0,76159,9.452208021179636,1,2,0,10.343842157216185,7881.77
47
+ 2023-02-15,0.0,67179,24.0749230563349,2,2,0,9.452208021179636,8196.76
48
+ 2023-02-16,0.0,74877,27.660437475958176,3,2,0,24.0749230563349,8207.25
49
+ 2023-02-17,0.0,80112,0.0,4,2,0,27.660437475958176,8110.58
50
+ 2023-02-18,0.0,76595,3.747625321472489,5,2,1,0.0,8664.04
51
+ 2023-02-19,0.0,65627,5.083690260774184,6,2,1,3.747625321472489,8459.16
52
+ 2023-02-20,0.0,92608,2.193648685251406,0,2,0,5.083690260774184,8066.01
53
+ 2023-02-21,0.0,84556,8.787805616063908,1,2,0,2.193648685251406,7971.72
54
+ 2023-02-22,0.0,84410,14.885511724115739,2,2,0,8.787805616063908,8087.39
55
+ 2023-02-23,0.0,63623,16.038721191186962,3,2,0,14.885511724115739,8027.74
56
+ 2023-02-24,0.0,62547,15.43699658658326,4,2,0,16.038721191186962,8048.61
57
+ 2023-02-25,0.0,96194,21.968644765391506,5,2,1,15.43699658658326,8871.06
58
+ 2023-02-26,0.0,78791,0.0,6,2,1,21.968644765391506,8617.63
59
+ 2023-02-27,0.0,86856,8.26211468397081,0,2,0,0.0,7872.2
60
+ 2023-02-28,0.0,85631,7.888192385523929,1,2,0,8.26211468397081,8123.0
61
+ 2023-03-01,0.0,89331,2.0923046604649245,2,3,0,7.888192385523929,8110.24
62
+ 2023-03-02,0.0,80857,29.15206806833591,3,3,0,2.0923046604649245,8025.5
63
+ 2023-03-03,0.0,96651,17.718240811947023,4,3,0,29.15206806833591,8332.79
64
+ 2023-03-04,0.0,87587,4.6256195726986205,5,3,1,17.718240811947023,9099.45
65
+ 2023-03-05,0.0,84325,2.9226446487702553,6,3,1,4.6256195726986205,8868.08
66
+ 2023-03-06,0.0,74514,3.1390340167120527,0,3,0,2.9226446487702553,8129.42
67
+ 2023-03-07,0.0,87063,28.701549912076175,1,3,0,3.1390340167120527,8281.63
68
+ 2023-03-08,0.0,93259,9.127138889409181,2,3,0,28.701549912076175,8408.73
69
+ 2023-03-09,0.0,89121,13.813817896938215,3,3,0,9.127138889409181,7938.3
70
+ 2023-03-10,0.0,71709,6.230475958589993,4,3,0,13.813817896938215,8077.67
71
+ 2023-03-11,1.0,80197,13.733136298309343,5,3,1,6.230475958589993,11143.88
72
+ 2023-03-12,1.0,73301,31.27590466187559,6,3,1,13.733136298309343,10205.05
73
+ 2023-03-13,0.0,83164,0.0,0,3,0,31.27590466187559,8198.43
74
+ 2023-03-14,0.0,114050,2.999005723627264,1,3,0,0.0,8087.31
75
+ 2023-03-15,0.0,88661,11.331792897749187,2,3,0,2.999005723627264,8100.85
76
+ 2023-03-16,0.0,85644,9.904323903739561,3,3,0,11.331792897749187,7877.21
77
+ 2023-03-17,0.0,82200,6.728109873645276,4,3,0,9.904323903739561,8046.33
78
+ 2023-03-18,0.0,85894,31.9235373141546,5,3,1,6.728109873645276,8622.76
79
+ 2023-03-19,0.0,86571,18.427250704456295,6,3,1,31.9235373141546,9233.84
80
+ 2023-03-20,0.0,78566,11.750070200323002,0,3,0,18.427250704456295,8212.85
81
+ 2023-03-21,0.0,97214,6.515548553784721,1,3,0,11.750070200323002,8161.12
82
+ 2023-03-22,0.0,92646,2.4665999346350085,2,3,0,6.515548553784721,8258.66
83
+ 2023-03-23,0.0,83263,7.007908052280348,3,3,0,2.4665999346350085,7943.96
84
+ 2023-03-24,0.0,98843,5.547676251615436,4,3,0,7.007908052280348,8270.3
85
+ 2023-03-25,0.0,91727,21.54880770517081,5,3,1,5.547676251615436,8727.51
86
+ 2023-03-26,0.0,76150,10.096697414178232,6,3,1,21.54880770517081,8822.09
87
+ 2023-03-27,0.0,75409,4.226180326759825,0,3,0,10.096697414178232,8133.4
88
+ 2023-03-28,0.0,112577,23.47740070799914,1,3,0,4.226180326759825,8265.65
89
+ 2023-03-29,0.0,71558,23.561278564457346,2,3,0,23.47740070799914,8337.76
90
+ 2023-03-30,0.0,81641,9.383592095693741,3,3,0,23.561278564457346,8217.63
91
+ 2023-03-31,0.0,82510,2.237975184916724,4,3,0,9.383592095693741,8195.4
92
+ 2023-04-01,0.0,89438,3.763319884040454,5,4,1,2.237975184916724,8464.33
93
+ 2023-04-02,0.0,76781,2.5699498063375525,6,4,1,3.763319884040454,8583.31
94
+ 2023-04-03,0.0,83671,11.9802481446014,0,4,0,2.5699498063375525,7909.62
95
+ 2023-04-04,0.0,77115,3.796379090573771,1,4,0,11.9802481446014,8138.27
96
+ 2023-04-05,0.0,84690,15.479737677741916,2,4,0,3.796379090573771,8412.21
97
+ 2023-04-06,0.0,89959,25.24673130194123,3,4,0,15.479737677741916,8138.01
98
+ 2023-04-07,0.0,91151,18.841599570822737,4,4,0,25.24673130194123,8452.8
99
+ 2023-04-08,0.0,74597,4.650863262339289,5,4,1,18.841599570822737,9074.1
100
+ 2023-04-09,0.0,83894,14.291037812292833,6,4,1,4.650863262339289,8770.05
101
+ 2023-04-10,0.0,66270,5.41116245586956,0,4,0,14.291037812292833,7893.29
102
+ 2023-04-11,0.0,76453,0.0,1,4,0,5.41116245586956,8034.64
103
+ 2023-04-12,0.0,89070,0.0,2,4,0,0.0,7895.08
104
+ 2023-04-13,0.0,67072,2.619405272936882,3,4,0,0.0,8048.54
105
+ 2023-04-14,0.0,89621,0.0,4,4,0,2.619405272936882,7761.13
106
+ 2023-04-15,0.0,90059,36.46455096285276,5,4,1,0.0,8824.22
107
+ 2023-04-16,0.0,84003,27.89339215018931,6,4,1,36.46455096285276,9082.05
108
+ 2023-04-17,0.0,103001,9.426452612690564,0,4,0,27.89339215018931,8526.03
109
+ 2023-04-18,0.0,71097,0.0,1,4,0,9.426452612690564,7953.67
110
+ 2023-04-19,0.0,97000,0.0,2,4,0,0.0,8083.79
111
+ 2023-04-20,0.0,110645,12.51504417002714,3,4,0,0.0,8277.93
112
+ 2023-04-21,0.0,91955,9.108493516726417,4,4,0,12.51504417002714,8111.0
113
+ 2023-04-22,0.0,87374,14.498658828606787,5,4,1,9.108493516726417,8792.0
114
+ 2023-04-23,0.0,77285,10.91551803068566,6,4,1,14.498658828606787,8732.08
115
+ 2023-04-24,0.0,88234,2.7641584351966872,0,4,0,10.91551803068566,8044.09
116
+ 2023-04-25,0.0,104173,9.51655100549679,1,4,0,2.7641584351966872,8143.65
117
+ 2023-04-26,0.0,114922,0.0,2,4,0,9.51655100549679,8115.13
118
+ 2023-04-27,0.0,78802,6.840680888489748,3,4,0,0.0,8001.14
119
+ 2023-04-28,0.0,92236,4.108839097310018,4,4,0,6.840680888489748,8180.38
120
+ 2023-04-29,0.0,102424,2.564442663333424,5,4,1,4.108839097310018,8885.03
121
+ 2023-04-30,0.0,115619,10.768372865177195,6,4,1,2.564442663333424,8561.12
122
+ 2023-05-01,0.0,89297,0.0,0,5,0,10.768372865177195,8279.03
123
+ 2023-05-02,0.0,84039,9.551596167553914,1,5,0,0.0,8352.86
124
+ 2023-05-03,0.0,80118,4.459862155085855,2,5,0,9.551596167553914,7587.49
125
+ 2023-05-04,0.0,84411,0.0,3,5,0,4.459862155085855,8156.74
126
+ 2023-05-05,0.0,63129,8.069571043406427,4,5,0,0.0,8021.01
127
+ 2023-05-06,0.0,95890,4.361590668947702,5,5,1,8.069571043406427,8652.11
128
+ 2023-05-07,0.0,108813,0.0,6,5,1,4.361590668947702,8954.66
129
+ 2023-05-08,0.0,104787,16.50339088563142,0,5,0,0.0,8251.98
130
+ 2023-05-09,0.0,85078,4.42544627120939,1,5,0,16.50339088563142,8174.88
131
+ 2023-05-10,0.0,86399,11.847516285596985,2,5,0,4.42544627120939,8253.94
132
+ 2023-05-11,0.0,83140,3.155063471696469,3,5,0,11.847516285596985,8338.13
133
+ 2023-05-12,0.0,68696,10.701760428696938,4,5,0,3.155063471696469,7942.37
134
+ 2023-05-13,0.0,84250,4.145265869630559,5,5,1,10.701760428696938,8496.19
135
+ 2023-05-14,0.0,73037,0.0,6,5,1,4.145265869630559,8689.83
136
+ 2023-05-15,0.0,71946,13.632906759821923,0,5,0,0.0,8171.87
137
+ 2023-05-16,0.0,98518,8.809295038753246,1,5,0,13.632906759821923,8024.44
138
+ 2023-05-17,0.0,71118,17.475490261306682,2,5,0,8.809295038753246,7881.6
139
+ 2023-05-18,0.0,79158,4.004376304956631,3,5,0,17.475490261306682,8482.31
140
+ 2023-05-19,0.0,70947,4.627281887157521,4,5,0,4.004376304956631,7901.56
141
+ 2023-05-20,0.0,68279,0.0,5,5,1,4.627281887157521,8771.83
142
+ 2023-05-21,0.0,66246,0.0,6,5,1,0.0,8657.13
143
+ 2023-05-22,0.0,72182,5.778960487031805,0,5,0,0.0,8126.85
144
+ 2023-05-23,0.0,82415,16.822713680645386,1,5,0,5.778960487031805,8254.1
145
+ 2023-05-24,0.0,81041,3.832261549662481,2,5,0,16.822713680645386,8019.56
146
+ 2023-05-25,0.0,98529,10.866185298152766,3,5,0,3.832261549662481,7965.62
147
+ 2023-05-26,1.0,111346,0.0,4,5,0,10.866185298152766,9744.21
148
+ 2023-05-27,0.0,78084,13.312233064787502,5,5,1,0.0,8631.9
149
+ 2023-05-28,0.0,70808,12.05529430991322,6,5,1,13.312233064787502,8780.17
150
+ 2023-05-29,0.0,99373,15.375918473529973,0,5,0,12.05529430991322,8286.28
151
+ 2023-05-30,0.0,73323,4.774064384360147,1,5,0,15.375918473529973,8053.51
152
+ 2023-05-31,0.0,89297,6.272085069022588,2,5,0,4.774064384360147,8248.34
153
+ 2023-06-01,0.0,71566,9.75984141751279,3,6,0,6.272085069022588,8066.79
154
+ 2023-06-02,0.0,94182,3.111753455461409,4,6,0,9.75984141751279,8180.14
155
+ 2023-06-03,0.0,63358,3.7567081447328357,5,6,1,3.111753455461409,8986.33
156
+ 2023-06-04,0.0,95983,0.0,6,6,1,3.7567081447328357,8311.67
157
+ 2023-06-05,0.0,87306,10.979776718423667,0,6,0,0.0,8134.32
158
+ 2023-06-06,0.0,82181,5.679229359679491,1,6,0,10.979776718423667,8049.51
159
+ 2023-06-07,0.0,90942,35.886907405094014,2,6,0,5.679229359679491,7974.44
160
+ 2023-06-08,0.0,102696,3.302151454751513,3,6,0,35.886907405094014,8672.18
161
+ 2023-06-09,0.0,90148,0.0,4,6,0,3.302151454751513,7743.37
162
+ 2023-06-10,0.0,75156,20.360211469288533,5,6,1,0.0,8666.7
163
+ 2023-06-11,0.0,89334,5.647642857988926,6,6,1,20.360211469288533,8796.89
164
+ 2023-06-12,0.0,76517,11.828969698774245,0,6,0,5.647642857988926,8120.74
165
+ 2023-06-13,0.0,85826,4.167221672666486,1,6,0,11.828969698774245,8116.42
166
+ 2023-06-14,0.0,76352,6.570564355224082,2,6,0,4.167221672666486,7863.36
167
+ 2023-06-15,0.0,82919,22.771019618314455,3,6,0,6.570564355224082,8155.26
168
+ 2023-06-16,0.0,84584,23.69670361799143,4,6,0,22.771019618314455,8488.2
169
+ 2023-06-17,0.0,84337,26.253795442639483,5,6,1,23.69670361799143,9000.94
170
+ 2023-06-18,0.0,103625,11.867214708365667,6,6,1,26.253795442639483,8831.21
171
+ 2023-06-19,1.0,96577,11.984815646546044,0,6,0,11.867214708365667,10523.42
172
+ 2023-06-20,0.0,66337,4.813395530019041,1,6,0,11.984815646546044,8211.36
173
+ 2023-06-21,0.0,94895,3.3258320260642646,2,6,0,4.813395530019041,8141.18
174
+ 2023-06-22,0.0,69522,9.313146513458966,3,6,0,3.3258320260642646,8074.83
175
+ 2023-06-23,0.0,76645,7.939546293245636,4,6,0,9.313146513458966,8187.32
176
+ 2023-06-24,0.0,69347,6.421414767787648,5,6,1,7.939546293245636,8831.53
177
+ 2023-06-25,0.0,95822,3.5619294566207254,6,6,1,6.421414767787648,8749.44
178
+ 2023-06-26,0.0,85375,2.5509853079610973,0,6,0,3.5619294566207254,7966.06
179
+ 2023-06-27,0.0,93282,6.50824408660618,1,6,0,2.5509853079610973,7918.42
180
+ 2023-06-28,0.0,104374,19.06385227156339,2,6,0,6.50824408660618,7966.41
181
+ 2023-06-29,0.0,93554,0.0,3,6,0,19.06385227156339,8379.57
182
+ 2023-06-30,0.0,79688,6.68431456577836,4,6,0,0.0,7684.38
183
+ 2023-07-01,0.0,103256,0.0,5,7,1,6.68431456577836,8559.16
184
+ 2023-07-02,0.0,84603,0.0,6,7,1,0.0,9037.96
185
+ 2023-07-03,0.0,77938,2.4166352471082746,0,7,0,0.0,8090.72
186
+ 2023-07-04,0.0,83137,11.29203898014451,1,7,0,2.4166352471082746,8042.69
187
+ 2023-07-05,0.0,107521,18.72956853655179,2,7,0,11.29203898014451,7971.23
188
+ 2023-07-06,0.0,67502,2.881411151414753,3,7,0,18.72956853655179,7999.09
189
+ 2023-07-07,0.0,100890,5.869262176426092,4,7,0,2.881411151414753,7998.56
190
+ 2023-07-08,0.0,89829,10.011163794700408,5,7,1,5.869262176426092,8715.82
191
+ 2023-07-09,0.0,85392,2.656250050414883,6,7,1,10.011163794700408,9029.54
192
+ 2023-07-10,0.0,79794,10.49001624566068,0,7,0,2.656250050414883,8044.25
193
+ 2023-07-11,0.0,87533,0.0,1,7,0,10.49001624566068,8316.93
194
+ 2023-07-12,0.0,70799,4.5489579781901766,2,7,0,0.0,8185.59
195
+ 2023-07-13,0.0,74400,22.010480212067705,3,7,0,4.5489579781901766,8095.68
196
+ 2023-07-14,0.0,73941,11.022522430962299,4,7,0,22.010480212067705,8337.92
197
+ 2023-07-15,0.0,67793,0.0,5,7,1,11.022522430962299,8668.32
198
+ 2023-07-16,0.0,73134,45.42343791738669,6,7,1,0.0,9231.53
199
+ 2023-07-17,0.0,83366,9.825028960021765,0,7,0,45.42343791738669,8491.88
200
+ 2023-07-18,0.0,83172,35.83375483241856,1,7,0,9.825028960021765,8563.27
201
+ 2023-07-19,0.0,77219,5.7242775981171805,2,7,0,35.83375483241856,8241.29
202
+ 2023-07-20,0.0,77859,5.329137279480836,3,7,0,5.7242775981171805,8017.13
203
+ 2023-07-21,0.0,80866,4.6685621743220675,4,7,0,5.329137279480836,7719.53
204
+ 2023-07-22,0.0,102139,0.0,5,7,1,4.6685621743220675,8831.2
205
+ 2023-07-23,0.0,103500,13.069684293983931,6,7,1,0.0,8756.83
206
+ 2023-07-24,0.0,91407,8.34288853681581,0,7,0,13.069684293983931,8248.88
207
+ 2023-07-25,0.0,88723,6.298982893015509,1,7,0,8.34288853681581,8147.26
208
+ 2023-07-26,0.0,69793,16.12255978023575,2,7,0,6.298982893015509,8162.45
209
+ 2023-07-27,0.0,62762,0.0,3,7,0,16.12255978023575,7992.51
210
+ 2023-07-28,0.0,87482,25.079925706822273,4,7,0,0.0,8232.15
211
+ 2023-07-29,0.0,82322,6.083957231424943,5,7,1,25.079925706822273,8993.15
212
+ 2023-07-30,0.0,100872,6.103438819128902,6,7,1,6.083957231424943,8988.31
213
+ 2023-07-31,0.0,81070,21.37954310546445,0,7,0,6.103438819128902,7969.42
214
+ 2023-08-01,0.0,96087,0.0,1,8,0,21.37954310546445,8055.43
215
+ 2023-08-02,0.0,68192,32.68260002919141,2,8,0,0.0,8275.36
216
+ 2023-08-03,0.0,57878,9.568781281037394,3,8,0,32.68260002919141,8318.21
217
+ 2023-08-04,0.0,97510,35.581299184342626,4,8,0,9.568781281037394,8350.43
218
+ 2023-08-05,0.0,87191,14.304397628835977,5,8,1,35.581299184342626,8929.92
219
+ 2023-08-06,0.0,70360,9.20327468451384,6,8,1,14.304397628835977,8843.92
220
+ 2023-08-07,0.0,75353,3.8545907395262975,0,8,0,9.20327468451384,7642.66
221
+ 2023-08-08,0.0,83280,27.76745566122052,1,8,0,3.8545907395262975,8229.13
222
+ 2023-08-09,0.0,79853,0.0,2,8,0,27.76745566122052,7832.99
223
+ 2023-08-10,0.0,85178,3.1039668444135686,3,8,0,0.0,8356.34
224
+ 2023-08-11,0.0,91204,4.938007810653345,4,8,0,3.1039668444135686,8002.81
225
+ 2023-08-12,0.0,89390,15.026981319916853,5,8,1,4.938007810653345,8871.04
226
+ 2023-08-13,0.0,85724,0.0,6,8,1,15.026981319916853,8739.15
227
+ 2023-08-14,0.0,83747,5.56704877970785,0,8,0,0.0,8054.15
228
+ 2023-08-15,0.0,59723,8.67864718489421,1,8,0,5.56704877970785,8046.0
229
+ 2023-08-16,0.0,99259,48.753497573471996,2,8,0,8.67864718489421,8343.29
230
+ 2023-08-17,0.0,83367,8.898984273106633,3,8,0,48.753497573471996,8444.04
231
+ 2023-08-18,0.0,69147,0.0,4,8,0,8.898984273106633,7801.23
232
+ 2023-08-19,0.0,88472,2.965175282957169,5,8,1,0.0,8569.85
233
+ 2023-08-20,0.0,88739,2.0388122874931214,6,8,1,2.965175282957169,8903.76
234
+ 2023-08-21,0.0,68897,3.5041025306125677,0,8,0,2.0388122874931214,8246.57
235
+ 2023-08-22,0.0,61305,8.122291089664355,1,8,0,3.5041025306125677,8278.98
236
+ 2023-08-23,0.0,80861,9.638134864683312,2,8,0,8.122291089664355,7924.26
237
+ 2023-08-24,0.0,87693,14.92111976003577,3,8,0,9.638134864683312,8246.56
238
+ 2023-08-25,0.0,104550,26.773203365901686,4,8,0,14.92111976003577,8103.48
239
+ 2023-08-26,0.0,97385,8.69666443253449,5,8,1,26.773203365901686,9008.2
240
+ 2023-08-27,0.0,76639,9.656890846898241,6,8,1,8.69666443253449,8874.34
241
+ 2023-08-28,0.0,83730,14.928163938586383,0,8,0,9.656890846898241,8034.53
242
+ 2023-08-29,0.0,85048,7.779096402498625,1,8,0,14.928163938586383,8058.46
243
+ 2023-08-30,0.0,92514,0.0,2,8,0,7.779096402498625,7864.61
244
+ 2023-08-31,0.0,75156,9.464200198821759,3,8,0,0.0,8115.55
245
+ 2023-09-01,0.0,85366,0.0,4,9,0,9.464200198821759,8105.05
246
+ 2023-09-02,0.0,100118,0.0,5,9,1,0.0,8773.19
247
+ 2023-09-03,0.0,73529,8.2108418162481,6,9,1,0.0,8784.53
248
+ 2023-09-04,0.0,83477,13.08648943309545,0,9,0,8.2108418162481,8299.28
249
+ 2023-09-05,0.0,62371,12.446668656019396,1,9,0,13.08648943309545,8242.03
250
+ 2023-09-06,0.0,68126,0.0,2,9,0,12.446668656019396,8246.65
251
+ 2023-09-07,0.0,92115,4.592977724231126,3,9,0,0.0,7982.24
252
+ 2023-09-08,0.0,84027,11.653281543940691,4,9,0,4.592977724231126,7999.89
253
+ 2023-09-09,0.0,74812,32.83099281338862,5,9,1,11.653281543940691,8818.49
254
+ 2023-09-10,0.0,107257,23.842993922098525,6,9,1,32.83099281338862,9012.49
255
+ 2023-09-11,0.0,74782,0.0,0,9,0,23.842993922098525,8256.77
256
+ 2023-09-12,0.0,99794,0.0,1,9,0,0.0,7743.12
257
+ 2023-09-13,0.0,97681,4.098029360949971,2,9,0,0.0,7745.69
258
+ 2023-09-14,0.0,96175,6.960195578886241,3,9,0,4.098029360949971,8370.44
259
+ 2023-09-15,0.0,80157,13.787380597446466,4,9,0,6.960195578886241,8235.04
260
+ 2023-09-16,0.0,78275,0.0,5,9,1,13.787380597446466,8845.91
261
+ 2023-09-17,0.0,83660,13.308612730238522,6,9,1,0.0,8696.14
262
+ 2023-09-18,0.0,100262,8.80787432068918,0,9,0,13.308612730238522,8183.06
263
+ 2023-09-19,0.0,92237,13.614309914338124,1,9,0,8.80787432068918,8319.18
264
+ 2023-09-20,0.0,96107,11.655208124972368,2,9,0,13.614309914338124,7954.54
265
+ 2023-09-21,0.0,87425,4.799748042078636,3,9,0,11.655208124972368,7948.67
266
+ 2023-09-22,0.0,89764,8.799218040427348,4,9,0,4.799748042078636,8034.95
267
+ 2023-09-23,0.0,87368,31.32764440330392,5,9,1,8.799218040427348,8579.8
268
+ 2023-09-24,0.0,78430,4.534698876040458,6,9,1,31.32764440330392,8789.32
269
+ 2023-09-25,0.0,107673,6.1098607647677925,0,9,0,4.534698876040458,8284.56
270
+ 2023-09-26,0.0,80863,4.194769421167141,1,9,0,6.1098607647677925,8055.59
271
+ 2023-09-27,0.0,79040,15.56454447490369,2,9,0,4.194769421167141,8148.0
272
+ 2023-09-28,0.0,88796,0.0,3,9,0,15.56454447490369,8093.09
273
+ 2023-09-29,0.0,82334,17.000870838951975,4,9,0,0.0,8458.08
274
+ 2023-09-30,0.0,65691,0.0,5,9,1,17.000870838951975,8690.48
275
+ 2023-10-01,0.0,99717,0.0,6,10,1,0.0,8555.2
276
+ 2023-10-02,0.0,98523,12.063089539520512,0,10,0,0.0,8187.5
277
+ 2023-10-03,0.0,73791,10.61783900173783,1,10,0,12.063089539520512,8043.76
278
+ 2023-10-04,0.0,81743,0.0,2,10,0,10.61783900173783,8171.59
279
+ 2023-10-05,0.0,77619,12.081783765642474,3,10,0,0.0,8020.69
280
+ 2023-10-06,0.0,72680,27.481813879750508,4,10,0,12.081783765642474,8040.53
281
+ 2023-10-07,0.0,74217,7.058639209399329,5,10,1,27.481813879750508,8960.48
282
+ 2023-10-08,0.0,76305,3.955490054037657,6,10,1,7.058639209399329,8626.59
283
+ 2023-10-09,0.0,82842,14.47995722709666,0,10,0,3.955490054037657,7945.53
284
+ 2023-10-10,0.0,92778,3.9371504721978936,1,10,0,14.47995722709666,8198.85
285
+ 2023-10-11,0.0,90388,15.134851099742738,2,10,0,3.9371504721978936,8019.36
286
+ 2023-10-12,0.0,89822,3.8707956464822373,3,10,0,15.134851099742738,8297.2
287
+ 2023-10-13,0.0,98173,2.0322570317964086,4,10,0,3.8707956464822373,7959.84
288
+ 2023-10-14,0.0,72066,14.021088568393793,5,10,1,2.0322570317964086,8604.17
289
+ 2023-10-15,0.0,94764,16.894518506422678,6,10,1,14.021088568393793,8873.22
290
+ 2023-10-16,0.0,83137,6.430910831159932,0,10,0,16.894518506422678,8404.81
291
+ 2023-10-17,0.0,94709,2.5376331953775813,1,10,0,6.430910831159932,7896.43
292
+ 2023-10-18,0.0,82658,3.1063887879907863,2,10,0,2.5376331953775813,8120.45
293
+ 2023-10-19,0.0,79949,2.9196345167349467,3,10,0,3.1063887879907863,7903.09
294
+ 2023-10-20,0.0,85632,20.170157022397177,4,10,0,2.9196345167349467,8197.29
295
+ 2023-10-21,0.0,89380,5.15325428811795,5,10,1,20.170157022397177,8660.61
296
+ 2023-10-22,0.0,90247,6.91506276683363,6,10,1,5.15325428811795,8640.99
297
+ 2023-10-23,0.0,100752,5.816951640945653,0,10,0,6.91506276683363,7852.26
298
+ 2023-10-24,0.0,91070,2.5711463706202986,1,10,0,5.816951640945653,8353.14
299
+ 2023-10-25,0.0,100183,12.738859977133414,2,10,0,2.5711463706202986,8202.52
300
+ 2023-10-26,0.0,107239,27.160868289593623,3,10,0,12.738859977133414,8192.66
301
+ 2023-10-27,0.0,106557,0.0,4,10,0,27.160868289593623,8097.77
302
+ 2023-10-28,0.0,78783,0.0,5,10,1,0.0,8198.46
303
+ 2023-10-29,0.0,85182,9.101271092187318,6,10,1,0.0,8704.97
304
+ 2023-10-30,0.0,99710,17.158901247825312,0,10,0,9.101271092187318,8030.35
305
+ 2023-10-31,0.0,97908,0.0,1,10,0,17.158901247825312,8096.3
306
+ 2023-11-01,0.0,92143,14.991054251328329,2,11,0,0.0,8226.42
307
+ 2023-11-02,0.0,72889,9.020678975931393,3,11,0,14.991054251328329,8165.03
308
+ 2023-11-03,0.0,83052,2.961076561499223,4,11,0,9.020678975931393,8105.97
309
+ 2023-11-04,0.0,76417,5.522703709121167,5,11,1,2.961076561499223,8826.27
310
+ 2023-11-05,0.0,80305,6.73443174859186,6,11,1,5.522703709121167,8788.81
311
+ 2023-11-06,0.0,105234,0.0,0,11,0,6.73443174859186,7944.84
312
+ 2023-11-07,0.0,110238,5.222043454731697,1,11,0,0.0,8126.63
313
+ 2023-11-08,0.0,93233,29.46859531810345,2,11,0,5.222043454731697,8558.56
314
+ 2023-11-09,0.0,59774,4.8159031441812985,3,11,0,29.46859531810345,8303.63
315
+ 2023-11-10,0.0,67626,9.284066370519952,4,11,0,4.8159031441812985,7765.5
316
+ 2023-11-11,0.0,77818,33.31406652810708,5,11,1,9.284066370519952,8757.43
317
+ 2023-11-12,0.0,83625,6.8547355412650655,6,11,1,33.31406652810708,9007.68
318
+ 2023-11-13,0.0,81823,7.861442747738457,0,11,0,6.8547355412650655,8132.67
319
+ 2023-11-14,0.0,75619,4.916299790863133,1,11,0,7.861442747738457,8037.4
320
+ 2023-11-15,1.0,87023,5.160670059856644,2,11,0,4.916299790863133,9972.14
321
+ 2023-11-16,0.0,74986,16.989657401989618,3,11,0,5.160670059856644,8084.69
322
+ 2023-11-17,0.0,91712,9.61589790906935,4,11,0,16.989657401989618,7936.24
323
+ 2023-11-18,0.0,101172,49.369465215435575,5,11,1,9.61589790906935,9020.44
324
+ 2023-11-19,0.0,96704,7.162568344268519,6,11,1,49.369465215435575,8869.28
325
+ 2023-11-20,0.0,87361,2.8703989850328115,0,11,0,7.162568344268519,7691.35
326
+ 2023-11-21,0.0,99128,5.09663442813558,1,11,0,2.8703989850328115,8389.24
327
+ 2023-11-22,0.0,72155,14.342262496532435,2,11,0,5.09663442813558,8081.73
328
+ 2023-11-23,0.0,71749,0.0,3,11,0,14.342262496532435,8380.63
329
+ 2023-11-24,0.0,83936,7.815736484135291,4,11,0,0.0,8151.78
330
+ 2023-11-25,0.0,83665,9.980954194415819,5,11,1,7.815736484135291,8785.56
331
+ 2023-11-26,0.0,96331,50.8506908138791,6,11,1,9.980954194415819,8941.93
332
+ 2023-11-27,0.0,120675,23.33028223462778,0,11,0,50.8506908138791,8338.75
333
+ 2023-11-28,0.0,91949,5.434695158743937,1,11,0,23.33028223462778,8195.05
334
+ 2023-11-29,0.0,106608,0.0,2,11,0,5.434695158743937,8208.39
335
+ 2023-11-30,0.0,91032,0.0,3,11,0,0.0,7830.19
336
+ 2023-12-01,0.0,75817,13.492925081870316,4,12,0,0.0,7945.64
337
+ 2023-12-02,0.0,92297,5.244781664046449,5,12,1,13.492925081870316,8813.39
338
+ 2023-12-03,0.0,91851,15.528795907976939,6,12,1,5.244781664046449,8719.14
339
+ 2023-12-04,0.0,79876,15.708304336808375,0,12,0,15.528795907976939,8339.45
340
+ 2023-12-05,0.0,88818,0.0,1,12,0,15.708304336808375,8217.39
341
+ 2023-12-06,0.0,84653,12.660757998230817,2,12,0,0.0,8353.91
342
+ 2023-12-07,0.0,81300,5.862446027030786,3,12,0,12.660757998230817,7784.75
343
+ 2023-12-08,0.0,100347,4.480521908352602,4,12,0,5.862446027030786,7982.33
344
+ 2023-12-09,0.0,73387,2.355922990735732,5,12,1,4.480521908352602,8820.73
345
+ 2023-12-10,0.0,75192,7.165184125706379,6,12,1,2.355922990735732,9171.87
346
+ 2023-12-11,0.0,70019,6.6739176264081745,0,12,0,7.165184125706379,7853.3
347
+ 2023-12-12,0.0,86218,3.076286454098355,1,12,0,6.6739176264081745,8076.43
348
+ 2023-12-13,0.0,82468,14.115852083453888,2,12,0,3.076286454098355,8038.87
349
+ 2023-12-14,0.0,82400,0.0,3,12,0,14.115852083453888,8296.77
350
+ 2023-12-15,0.0,91383,29.574797373415873,4,12,0,0.0,8232.1
351
+ 2023-12-16,0.0,73758,22.34823651169936,5,12,1,29.574797373415873,8736.26
352
+ 2023-12-17,0.0,81890,9.049589503917286,6,12,1,22.34823651169936,8897.03
353
+ 2023-12-18,0.0,98279,2.471689554589462,0,12,0,9.049589503917286,8273.72
354
+ 2023-12-19,0.0,77870,11.344781748094361,1,12,0,2.471689554589462,8191.13
355
+ 2023-12-20,0.0,102060,16.123239581247216,2,12,0,11.344781748094361,8226.01
356
+ 2023-12-21,0.0,79841,0.0,3,12,0,16.123239581247216,7974.15
357
+ 2023-12-22,0.0,71878,8.350261556198442,4,12,0,0.0,8001.82
358
+ 2023-12-23,0.0,66760,7.723588216262333,5,12,1,8.350261556198442,8507.36
359
+ 2023-12-24,0.0,89709,2.668425060063318,6,12,1,7.723588216262333,8866.64
360
+ 2023-12-25,0.0,74621,0.0,0,12,0,2.668425060063318,7857.4
361
+ 2023-12-26,0.0,73698,0.0,1,12,0,0.0,7995.27
362
+ 2023-12-27,0.0,79685,0.0,2,12,0,0.0,8057.12
363
+ 2023-12-28,0.0,89281,15.790474626487004,3,12,0,0.0,8014.78
364
+ 2023-12-29,0.0,82872,9.82704545549494,4,12,0,15.790474626487004,8280.15
365
+ 2023-12-30,0.0,70118,19.40089322719917,5,12,1,9.82704545549494,8508.27
366
+ 2023-12-31,1.0,72067,4.133479590228442,6,12,1,19.40089322719917,10786.68
367
+ 2024-01-01,1.0,85760,2.6284710606044417,0,1,0,4.133479590228442,10161.31
368
+ 2024-01-02,0.0,89430,0.0,1,1,0,2.6284710606044417,8128.72
369
+ 2024-01-03,0.0,81136,12.290068334806154,2,1,0,0.0,8111.75
370
+ 2024-01-04,0.0,82870,2.539388483864733,3,1,0,12.290068334806154,8227.34
371
+ 2024-01-05,0.0,62861,7.3464623652931795,4,1,0,2.539388483864733,8046.27
372
+ 2024-01-06,0.0,75932,23.134810452414058,5,1,1,7.3464623652931795,8825.0
373
+ 2024-01-07,0.0,92982,0.0,6,1,1,23.134810452414058,8831.9
374
+ 2024-01-08,0.0,80528,0.0,0,1,0,0.0,7766.99
375
+ 2024-01-09,0.0,98150,44.202474115691615,1,1,0,0.0,8053.49
376
+ 2024-01-10,0.0,81852,0.0,2,1,0,44.202474115691615,8219.83
377
+ 2024-01-11,0.0,70125,19.084866448811034,3,1,0,0.0,8024.13
378
+ 2024-01-12,0.0,101056,7.091604675399817,4,1,0,19.084866448811034,8529.31
379
+ 2024-01-13,0.0,81892,3.130862823924657,5,1,1,7.091604675399817,8590.02
380
+ 2024-01-14,0.0,116089,6.75500238944759,6,1,1,3.130862823924657,8858.31
381
+ 2024-01-15,0.0,86759,11.175321224301133,0,1,0,6.75500238944759,8062.22
382
+ 2024-01-16,0.0,70802,5.094497325556182,1,1,0,11.175321224301133,8238.89
383
+ 2024-01-17,0.0,54784,3.915395695125566,2,1,0,5.094497325556182,8016.5
384
+ 2024-01-18,0.0,89226,8.855513132991815,3,1,0,3.915395695125566,8188.07
385
+ 2024-01-19,0.0,65229,4.880026205256222,4,1,0,8.855513132991815,8274.67
386
+ 2024-01-20,0.0,88682,4.4178223534844,5,1,1,4.880026205256222,8506.68
387
+ 2024-01-21,0.0,84978,7.961941822433852,6,1,1,4.4178223534844,8653.7
388
+ 2024-01-22,0.0,51847,9.269196746079471,0,1,0,7.961941822433852,8072.28
389
+ 2024-01-23,0.0,81848,8.215231833538835,1,1,0,9.269196746079471,8241.92
390
+ 2024-01-24,0.0,79434,0.0,2,1,0,8.215231833538835,8515.15
391
+ 2024-01-25,0.0,80121,2.5090483552467533,3,1,0,0.0,8260.6
392
+ 2024-01-26,0.0,63237,0.0,4,1,0,2.5090483552467533,8045.5
393
+ 2024-01-27,0.0,82951,25.987827701217082,5,1,1,0.0,8636.19
394
+ 2024-01-28,0.0,78074,13.82139513563838,6,1,1,25.987827701217082,8830.3
395
+ 2024-01-29,0.0,62936,2.769122915329199,0,1,0,13.82139513563838,7786.16
396
+ 2024-01-30,0.0,76659,46.20190006152766,1,1,0,2.769122915329199,8543.53
397
+ 2024-01-31,0.0,96571,50.207351845337755,2,1,0,46.20190006152766,8630.28
398
+ 2024-02-01,0.0,98328,20.246323868748426,3,2,0,50.207351845337755,8280.06
399
+ 2024-02-02,0.0,91685,0.0,4,2,0,20.246323868748426,8356.84
400
+ 2024-02-03,0.0,78256,13.180540849504036,5,2,1,0.0,8465.86
401
+ 2024-02-04,0.0,60983,14.955577950710383,6,2,1,13.180540849504036,8906.56
402
+ 2024-02-05,0.0,88312,21.9134386426834,0,2,0,14.955577950710383,8200.92
403
+ 2024-02-06,0.0,82438,20.589002064275192,1,2,0,21.9134386426834,8255.12
404
+ 2024-02-07,0.0,58854,13.78140040663229,2,2,0,20.589002064275192,8329.22
405
+ 2024-02-08,0.0,97111,11.506994685963974,3,2,0,13.78140040663229,8076.9
406
+ 2024-02-09,0.0,98572,20.502717301596082,4,2,0,11.506994685963974,8171.66
407
+ 2024-02-10,0.0,90363,6.697307346815792,5,2,1,20.502717301596082,8783.92
408
+ 2024-02-11,0.0,60255,18.131297747745656,6,2,1,6.697307346815792,8733.76
409
+ 2024-02-12,0.0,94984,18.30390896235438,0,2,0,18.131297747745656,8451.16
410
+ 2024-02-13,0.0,83282,10.755752281701067,1,2,0,18.30390896235438,8414.42
411
+ 2024-02-14,0.0,79331,0.0,2,2,0,10.755752281701067,8076.35
412
+ 2024-02-15,0.0,96842,0.0,3,2,0,0.0,7928.75
413
+ 2024-02-16,0.0,105011,0.0,4,2,0,0.0,8328.68
414
+ 2024-02-17,0.0,70896,11.159865443976832,5,2,1,0.0,8758.19
415
+ 2024-02-18,0.0,93036,13.46038857633082,6,2,1,11.159865443976832,9150.78
416
+ 2024-02-19,0.0,83493,4.742463959472057,0,2,0,13.46038857633082,8101.77
417
+ 2024-02-20,0.0,75976,0.0,1,2,0,4.742463959472057,8133.87
418
+ 2024-02-21,0.0,91563,0.0,2,2,0,0.0,8134.61
419
+ 2024-02-22,0.0,83356,7.961884145273489,3,2,0,0.0,8212.75
420
+ 2024-02-23,0.0,80167,12.496705474203043,4,2,0,7.961884145273489,8186.6
421
+ 2024-02-24,0.0,71624,0.0,5,2,1,12.496705474203043,8875.86
422
+ 2024-02-25,0.0,88443,22.614817523695752,6,2,1,0.0,8837.93
423
+ 2024-02-26,0.0,93606,0.0,0,2,0,22.614817523695752,8233.25
424
+ 2024-02-27,0.0,100115,21.410773227174577,1,2,0,0.0,7978.08
425
+ 2024-02-28,0.0,67937,5.318817072534709,2,2,0,21.410773227174577,8176.5
426
+ 2024-02-29,0.0,84996,34.516893653165326,3,2,0,5.318817072534709,8445.37
427
+ 2024-03-01,0.0,79544,4.105434857259014,4,3,0,34.516893653165326,8488.93
428
+ 2024-03-02,1.0,77895,3.346046580295677,5,3,1,4.105434857259014,10017.25
429
+ 2024-03-03,0.0,118309,3.688759030120195,6,3,1,3.346046580295677,8640.31
430
+ 2024-03-04,0.0,84753,10.847667321824762,0,3,0,3.688759030120195,8362.85
431
+ 2024-03-05,0.0,80011,0.0,1,3,0,10.847667321824762,7956.5
432
+ 2024-03-06,0.0,72122,2.695969240796457,2,3,0,0.0,8035.6
433
+ 2024-03-07,0.0,86849,2.5541476252922544,3,3,0,2.695969240796457,8205.02
434
+ 2024-03-08,0.0,91157,0.0,4,3,0,2.5541476252922544,7740.78
435
+ 2024-03-09,0.0,99129,56.95681806424531,5,3,1,0.0,8924.76
436
+ 2024-03-10,0.0,81814,43.545210880659376,6,3,1,56.95681806424531,9662.06
437
+ 2024-03-11,0.0,99511,3.64355878835904,0,3,0,43.545210880659376,8288.13
438
+ 2024-03-12,0.0,93862,0.0,1,3,0,3.64355878835904,8005.96
439
+ 2024-03-13,0.0,84853,3.1353046336333907,2,3,0,0.0,7970.81
440
+ 2024-03-14,0.0,93773,7.048431488370347,3,3,0,3.1353046336333907,8049.19
441
+ 2024-03-15,0.0,79394,8.666695933520394,4,3,0,7.048431488370347,8564.19
442
+ 2024-03-16,0.0,83864,2.7176278322098595,5,3,1,8.666695933520394,8491.96
443
+ 2024-03-17,0.0,77539,5.113761544392121,6,3,1,2.7176278322098595,8791.17
444
+ 2024-03-18,0.0,82273,4.603125426832676,0,3,0,5.113761544392121,8039.95
445
+ 2024-03-19,0.0,112453,6.434608012185861,1,3,0,4.603125426832676,8127.39
446
+ 2024-03-20,0.0,91048,5.582828319740594,2,3,0,6.434608012185861,8160.54
447
+ 2024-03-21,0.0,76163,14.662466345468635,3,3,0,5.582828319740594,7928.83
448
+ 2024-03-22,0.0,84522,9.167671801126744,4,3,0,14.662466345468635,8173.52
449
+ 2024-03-23,0.0,99459,0.0,5,3,1,9.167671801126744,8462.92
450
+ 2024-03-24,0.0,90828,4.002419149410899,6,3,1,0.0,8644.45
451
+ 2024-03-25,0.0,96141,2.0376566586670806,0,3,0,4.002419149410899,7987.75
452
+ 2024-03-26,0.0,76866,4.973367416703488,1,3,0,2.0376566586670806,7853.93
453
+ 2024-03-27,0.0,85541,11.149362820670438,2,3,0,4.973367416703488,7989.79
454
+ 2024-03-28,0.0,76262,3.3882413822243214,3,3,0,11.149362820670438,7886.9
455
+ 2024-03-29,0.0,80158,0.0,4,3,0,3.3882413822243214,8131.8
456
+ 2024-03-30,0.0,108074,0.0,5,3,1,0.0,8554.98
457
+ 2024-03-31,0.0,65999,6.595168445242901,6,3,1,0.0,8514.51
458
+ 2024-04-01,0.0,74343,7.110522813221145,0,4,0,6.595168445242901,8095.67
459
+ 2024-04-02,0.0,73682,14.004283999635176,1,4,0,7.110522813221145,8414.25
460
+ 2024-04-03,0.0,78534,7.087787160937955,2,4,0,14.004283999635176,7943.79
461
+ 2024-04-04,0.0,84155,6.165579535115105,3,4,0,7.087787160937955,8024.37
462
+ 2024-04-05,0.0,90951,0.0,4,4,0,6.165579535115105,8166.92
463
+ 2024-04-06,0.0,71648,17.005191746346807,5,4,1,0.0,8619.08
464
+ 2024-04-07,0.0,68793,4.267947015670674,6,4,1,17.005191746346807,8926.15
465
+ 2024-04-08,0.0,99994,9.031167222073877,0,4,0,4.267947015670674,7918.75
466
+ 2024-04-09,0.0,79140,6.4713303980907675,1,4,0,9.031167222073877,8187.86
467
+ 2024-04-10,0.0,72735,3.4112892191516835,2,4,0,6.4713303980907675,7803.41
468
+ 2024-04-11,0.0,95031,8.899074693266146,3,4,0,3.4112892191516835,7804.87
469
+ 2024-04-12,0.0,93344,4.489782216915464,4,4,0,8.899074693266146,7852.61
470
+ 2024-04-13,0.0,80853,27.928359984387797,5,4,1,4.489782216915464,8870.72
471
+ 2024-04-14,0.0,101203,13.308531478577333,6,4,1,27.928359984387797,8504.17
472
+ 2024-04-15,0.0,97088,6.337272732895707,0,4,0,13.308531478577333,8004.78
473
+ 2024-04-16,0.0,102034,0.0,1,4,0,6.337272732895707,7763.61
474
+ 2024-04-17,0.0,78092,0.0,2,4,0,0.0,7815.36
475
+ 2024-04-18,0.0,74245,12.896148370229016,3,4,0,0.0,8007.0
476
+ 2024-04-19,0.0,78446,0.0,4,4,0,12.896148370229016,8008.86
477
+ 2024-04-20,0.0,98510,14.951705033434317,5,4,1,0.0,8750.43
478
+ 2024-04-21,0.0,69903,5.784781109470403,6,4,1,14.951705033434317,8791.11
479
+ 2024-04-22,0.0,67083,0.0,0,4,0,5.784781109470403,8017.14
480
+ 2024-04-23,0.0,94601,15.816524889747399,1,4,0,0.0,8168.89
481
+ 2024-04-24,0.0,98401,20.14684273707557,2,4,0,15.816524889747399,8323.84
482
+ 2024-04-25,0.0,103576,0.0,3,4,0,20.14684273707557,8027.69
483
+ 2024-04-26,0.0,82035,5.8929258944386085,4,4,0,0.0,8257.7
484
+ 2024-04-27,0.0,90387,10.157392366835383,5,4,1,5.8929258944386085,8617.98
485
+ 2024-04-28,0.0,86323,11.226332562346402,6,4,1,10.157392366835383,9006.51
486
+ 2024-04-29,0.0,57230,0.0,0,4,0,11.226332562346402,8109.63
487
+ 2024-04-30,0.0,78612,7.953404579207891,1,4,0,0.0,8280.97
488
+ 2024-05-01,0.0,86607,0.0,2,5,0,7.953404579207891,8002.41
489
+ 2024-05-02,0.0,81995,9.1062958673101,3,5,0,0.0,8026.8
490
+ 2024-05-03,0.0,61942,6.079827753765546,4,5,0,9.1062958673101,7931.05
491
+ 2024-05-04,0.0,92681,22.585189312827072,5,5,1,6.079827753765546,9016.58
492
+ 2024-05-05,0.0,77247,0.0,6,5,1,22.585189312827072,8740.12
493
+ 2024-05-06,0.0,66963,2.2887474475299094,0,5,0,0.0,8072.39
494
+ 2024-05-07,0.0,103323,28.09099309014941,1,5,0,2.2887474475299094,8169.1
495
+ 2024-05-08,0.0,61530,2.7448408202568078,2,5,0,28.09099309014941,8253.95
496
+ 2024-05-09,0.0,97114,5.081446106119115,3,5,0,2.7448408202568078,8154.73
497
+ 2024-05-10,0.0,97077,11.935575638551914,4,5,0,5.081446106119115,8151.88
498
+ 2024-05-11,0.0,78168,2.34406376306391,5,5,1,11.935575638551914,9137.95
499
+ 2024-05-12,0.0,78714,0.0,6,5,1,2.34406376306391,9074.13
500
+ 2024-05-13,0.0,107332,10.480889516547125,0,5,0,0.0,8005.77
501
+ 2024-05-14,0.0,96298,5.436817790047165,1,5,0,10.480889516547125,7993.86
502
+ 2024-05-15,0.0,86928,8.534648929954116,2,5,0,5.436817790047165,7844.83
503
+ 2024-05-16,0.0,73777,0.0,3,5,0,8.534648929954116,8005.35
504
+ 2024-05-17,0.0,81507,2.2247467903283074,4,5,0,0.0,8090.61
505
+ 2024-05-18,0.0,96901,13.279549074012658,5,5,1,2.2247467903283074,8864.05
506
+ 2024-05-19,0.0,75674,10.9917500163049,6,5,1,13.279549074012658,8743.02
507
+ 2024-05-20,0.0,77431,0.0,0,5,0,10.9917500163049,8129.29
508
+ 2024-05-21,0.0,77669,8.664033719227598,1,5,0,0.0,7990.98
509
+ 2024-05-22,0.0,89072,6.847698618140091,2,5,0,8.664033719227598,8053.26
510
+ 2024-05-23,0.0,87835,2.517604714165348,3,5,0,6.847698618140091,8020.43
511
+ 2024-05-24,1.0,76529,0.0,4,5,0,2.517604714165348,9853.66
512
+ 2024-05-25,0.0,73118,0.0,5,5,1,0.0,8762.0
513
+ 2024-05-26,0.0,86288,4.184731057360592,6,5,1,0.0,8642.95
514
+ 2024-05-27,0.0,83360,15.223729975124424,0,5,0,4.184731057360592,7924.78
515
+ 2024-05-28,0.0,81091,15.57290623846622,1,5,0,15.223729975124424,8278.48
516
+ 2024-05-29,0.0,83264,0.0,2,5,0,15.57290623846622,8095.98
517
+ 2024-05-30,0.0,91702,6.834228272913518,3,5,0,0.0,7755.01
518
+ 2024-05-31,0.0,70832,7.630946002304813,4,5,0,6.834228272913518,8050.89
519
+ 2024-06-01,0.0,93551,3.9236361738304253,5,6,1,7.630946002304813,8639.59
520
+ 2024-06-02,0.0,73344,13.079447061163638,6,6,1,3.9236361738304253,8680.85
521
+ 2024-06-03,0.0,87205,8.42252386026105,0,6,0,13.079447061163638,7960.55
522
+ 2024-06-04,0.0,76629,18.538115510605625,1,6,0,8.42252386026105,7891.29
523
+ 2024-06-05,0.0,112320,6.835434935306207,2,6,0,18.538115510605625,8434.69
524
+ 2024-06-06,0.0,78540,2.441726820108273,3,6,0,6.835434935306207,7948.73
525
+ 2024-06-07,0.0,67694,0.0,4,6,0,2.441726820108273,8154.29
526
+ 2024-06-08,0.0,79348,6.0578005395642,5,6,1,0.0,8732.97
527
+ 2024-06-09,0.0,81079,5.009926705108176,6,6,1,6.0578005395642,8754.59
528
+ 2024-06-10,0.0,91895,2.2626753827912904,0,6,0,5.009926705108176,8086.25
529
+ 2024-06-11,0.0,74270,7.41242633650155,1,6,0,2.2626753827912904,7929.61
530
+ 2024-06-12,0.0,100784,4.301787036203065,2,6,0,7.41242633650155,7953.22
531
+ 2024-06-13,0.0,94506,0.0,3,6,0,4.301787036203065,8110.8
532
+ 2024-06-14,0.0,80051,3.1225038528852043,4,6,0,0.0,8016.89
533
+ 2024-06-15,0.0,76689,10.405223310899947,5,6,1,3.1225038528852043,8679.79
534
+ 2024-06-16,0.0,74756,16.27583554535384,6,6,1,10.405223310899947,8741.3
535
+ 2024-06-17,0.0,69243,12.40629894420653,0,6,0,16.27583554535384,8070.45
536
+ 2024-06-18,0.0,91168,9.003241340438972,1,6,0,12.40629894420653,8237.28
537
+ 2024-06-19,0.0,103759,2.2615659463800726,2,6,0,9.003241340438972,8055.88
538
+ 2024-06-20,0.0,84051,13.669075501851648,3,6,0,2.2615659463800726,8037.76
539
+ 2024-06-21,0.0,87870,2.0578595156656685,4,6,0,13.669075501851648,8250.28
540
+ 2024-06-22,0.0,76064,6.61232916003712,5,6,1,2.0578595156656685,8388.15
541
+ 2024-06-23,0.0,80549,4.22841954244895,6,6,1,6.61232916003712,8923.73
542
+ 2024-06-24,0.0,80827,0.0,0,6,0,4.22841954244895,8035.54
543
+ 2024-06-25,0.0,90979,8.219382475120009,1,6,0,0.0,8283.6
544
+ 2024-06-26,0.0,92560,7.413284873318535,2,6,0,8.219382475120009,8415.03
545
+ 2024-06-27,0.0,81463,9.889880667256362,3,6,0,7.413284873318535,8250.45
546
+ 2024-06-28,0.0,98294,13.688784635094963,4,6,0,9.889880667256362,8223.19
547
+ 2024-06-29,0.0,83792,2.2151171412412567,5,6,1,13.688784635094963,8641.08
548
+ 2024-06-30,0.0,81046,6.242513698229692,6,6,1,2.2151171412412567,8811.51
549
+ 2024-07-01,0.0,84289,2.44877415979336,0,7,0,6.242513698229692,7806.39
550
+ 2024-07-02,0.0,82242,5.401295745975105,1,7,0,2.44877415979336,7970.02
551
+ 2024-07-03,0.0,73570,12.69450984492507,2,7,0,5.401295745975105,7810.02
552
+ 2024-07-04,0.0,81851,21.186212053692724,3,7,0,12.69450984492507,8311.91
553
+ 2024-07-05,0.0,87459,6.7432530126290064,4,7,0,21.186212053692724,8308.06
554
+ 2024-07-06,0.0,74628,5.707548923955603,5,7,1,6.7432530126290064,8670.65
555
+ 2024-07-07,0.0,97622,22.513875499329284,6,7,1,5.707548923955603,8613.45
556
+ 2024-07-08,0.0,80041,0.0,0,7,0,22.513875499329284,8058.84
557
+ 2024-07-09,0.0,73150,2.4350349966868903,1,7,0,0.0,8172.61
558
+ 2024-07-10,0.0,73987,40.53163922225951,2,7,0,2.4350349966868903,8214.0
559
+ 2024-07-11,0.0,94469,35.483388031566044,3,7,0,40.53163922225951,8537.78
560
+ 2024-07-12,0.0,88502,0.0,4,7,0,35.483388031566044,8243.76
561
+ 2024-07-13,0.0,61728,11.355711694570726,5,7,1,0.0,8421.65
562
+ 2024-07-14,0.0,95107,3.3170474476692973,6,7,1,11.355711694570726,8764.53
563
+ 2024-07-15,0.0,92398,23.798172610990168,0,7,0,3.3170474476692973,8076.62
564
+ 2024-07-16,0.0,75504,16.370950851817742,1,7,0,23.798172610990168,8278.88
565
+ 2024-07-17,0.0,77281,13.899467042437838,2,7,0,16.370950851817742,8120.99
566
+ 2024-07-18,0.0,95818,9.132672676039206,3,7,0,13.899467042437838,8038.01
567
+ 2024-07-19,0.0,86880,3.141041459030145,4,7,0,9.132672676039206,8182.24
568
+ 2024-07-20,0.0,87087,0.0,5,7,1,3.141041459030145,8748.77
569
+ 2024-07-21,0.0,84898,0.0,6,7,1,0.0,8523.5
570
+ 2024-07-22,0.0,99970,0.0,0,7,0,0.0,8172.6
571
+ 2024-07-23,0.0,77499,11.157139298069737,1,7,0,0.0,7912.33
572
+ 2024-07-24,0.0,78854,2.952478664005248,2,7,0,11.157139298069737,8427.01
573
+ 2024-07-25,0.0,92302,13.352527391269497,3,7,0,2.952478664005248,8274.78
574
+ 2024-07-26,0.0,64188,14.533328531485193,4,7,0,13.352527391269497,8403.24
575
+ 2024-07-27,0.0,73436,5.7722494825393404,5,7,1,14.533328531485193,8742.66
576
+ 2024-07-28,0.0,108351,7.245220272797049,6,7,1,5.7722494825393404,9036.52
577
+ 2024-07-29,0.0,89601,0.0,0,7,0,7.245220272797049,7870.06
578
+ 2024-07-30,0.0,89061,2.079702038639294,1,7,0,0.0,8004.5
579
+ 2024-07-31,0.0,87446,2.9962508678417636,2,7,0,2.079702038639294,7981.12
580
+ 2024-08-01,0.0,91673,0.0,3,8,0,2.9962508678417636,8469.31
581
+ 2024-08-02,0.0,71370,13.917271629624366,4,8,0,0.0,8246.9
582
+ 2024-08-03,0.0,77301,4.17039301161778,5,8,1,13.917271629624366,9082.23
583
+ 2024-08-04,0.0,76807,8.990903820190473,6,8,1,4.17039301161778,8595.15
584
+ 2024-08-05,0.0,104032,22.498384391614074,0,8,0,8.990903820190473,8340.98
585
+ 2024-08-06,0.0,82793,7.208877260661184,1,8,0,22.498384391614074,8060.91
586
+ 2024-08-07,0.0,76085,4.112412353096105,2,8,0,7.208877260661184,8304.93
587
+ 2024-08-08,0.0,76966,8.453234038877513,3,8,0,4.112412353096105,8054.39
588
+ 2024-08-09,0.0,82361,7.941541322873042,4,8,0,8.453234038877513,8392.17
589
+ 2024-08-10,0.0,86257,13.220032990371507,5,8,1,7.941541322873042,8885.02
590
+ 2024-08-11,0.0,87199,28.332267592778308,6,8,1,13.220032990371507,8943.8
591
+ 2024-08-12,0.0,93416,2.1199681233470984,0,8,0,28.332267592778308,8217.79
592
+ 2024-08-13,0.0,78052,0.0,1,8,0,2.1199681233470984,8223.93
593
+ 2024-08-14,0.0,73090,2.0438055210148174,2,8,0,0.0,7992.07
594
+ 2024-08-15,0.0,111556,27.148563902612256,3,8,0,2.0438055210148174,8419.76
595
+ 2024-08-16,0.0,85095,25.77981779942871,4,8,0,27.148563902612256,8624.99
596
+ 2024-08-17,0.0,83318,33.539647605287385,5,8,1,25.77981779942871,8865.67
597
+ 2024-08-18,0.0,80474,2.505335166675415,6,8,1,33.539647605287385,8922.12
598
+ 2024-08-19,0.0,87810,6.2441000391959705,0,8,0,2.505335166675415,8083.74
599
+ 2024-08-20,0.0,78933,4.893565358808861,1,8,0,6.2441000391959705,8183.55
600
+ 2024-08-21,0.0,82634,0.0,2,8,0,4.893565358808861,7866.08
601
+ 2024-08-22,0.0,89502,0.0,3,8,0,0.0,7887.23
602
+ 2024-08-23,0.0,81410,20.984832442116872,4,8,0,0.0,7902.74
603
+ 2024-08-24,0.0,88560,0.0,5,8,1,20.984832442116872,8805.95
604
+ 2024-08-25,0.0,112001,2.509539984760517,6,8,1,0.0,8827.33
605
+ 2024-08-26,0.0,80443,0.0,0,8,0,2.509539984760517,8098.69
606
+ 2024-08-27,0.0,119209,18.69703052615622,1,8,0,0.0,7987.67
607
+ 2024-08-28,0.0,98006,0.0,2,8,0,18.69703052615622,8238.52
608
+ 2024-08-29,0.0,75102,2.282771941078217,3,8,0,0.0,8012.94
609
+ 2024-08-30,0.0,75601,0.0,4,8,0,2.282771941078217,7782.77
610
+ 2024-08-31,0.0,89652,25.713857260195915,5,8,1,0.0,8440.09
611
+ 2024-09-01,0.0,86916,0.0,6,9,1,25.713857260195915,8674.13
612
+ 2024-09-02,0.0,99559,7.404502949233574,0,9,0,0.0,8097.7
613
+ 2024-09-03,0.0,75753,6.088405728842883,1,9,0,7.404502949233574,8443.3
614
+ 2024-09-04,0.0,103017,4.969403127836516,2,9,0,6.088405728842883,8064.88
615
+ 2024-09-05,0.0,93435,18.836489609032462,3,9,0,4.969403127836516,7987.96
616
+ 2024-09-06,0.0,94636,11.849445303465343,4,9,0,18.836489609032462,8057.92
617
+ 2024-09-07,0.0,74785,2.816118141139631,5,9,1,11.849445303465343,8729.82
618
+ 2024-09-08,0.0,95080,3.169324807332025,6,9,1,2.816118141139631,8685.65
619
+ 2024-09-09,0.0,108476,0.0,0,9,0,3.169324807332025,8088.23
620
+ 2024-09-10,0.0,85014,24.937166842180165,1,9,0,0.0,8337.53
621
+ 2024-09-11,0.0,69731,0.0,2,9,0,24.937166842180165,7897.46
622
+ 2024-09-12,0.0,74552,5.3532289134480875,3,9,0,0.0,7884.64
623
+ 2024-09-13,0.0,75646,15.623333999337829,4,9,0,5.3532289134480875,8153.39
624
+ 2024-09-14,0.0,72317,4.203894678434411,5,9,1,15.623333999337829,8742.25
625
+ 2024-09-15,0.0,96800,4.932138691093535,6,9,1,4.203894678434411,8506.06
626
+ 2024-09-16,0.0,74838,3.46789097808702,0,9,0,4.932138691093535,7910.28
627
+ 2024-09-17,0.0,86170,2.525612620108077,1,9,0,3.46789097808702,8060.59
628
+ 2024-09-18,0.0,90987,30.49907737170793,2,9,0,2.525612620108077,8360.77
629
+ 2024-09-19,0.0,98190,0.0,3,9,0,30.49907737170793,8274.03
630
+ 2024-09-20,0.0,73650,9.611269778102436,4,9,0,0.0,8025.26
631
+ 2024-09-21,0.0,87314,3.9324963725917175,5,9,1,9.611269778102436,8830.45
632
+ 2024-09-22,0.0,96908,8.821686626926871,6,9,1,3.9324963725917175,9021.29
633
+ 2024-09-23,0.0,96104,4.091689426614362,0,9,0,8.821686626926871,8115.69
634
+ 2024-09-24,0.0,87993,0.0,1,9,0,4.091689426614362,7797.42
635
+ 2024-09-25,0.0,77923,24.671076780890814,2,9,0,0.0,8170.11
636
+ 2024-09-26,0.0,99369,2.9944946018799903,3,9,0,24.671076780890814,8262.74
637
+ 2024-09-27,0.0,65925,2.0143214909525553,4,9,0,2.9944946018799903,7997.18
638
+ 2024-09-28,0.0,67146,11.89513992920445,5,9,1,2.0143214909525553,9121.49
639
+ 2024-09-29,0.0,68952,28.145744456821923,6,9,1,11.89513992920445,8651.02
640
+ 2024-09-30,0.0,98638,12.503969694274875,0,9,0,28.145744456821923,8700.52
641
+ 2024-10-01,0.0,88427,48.59549006422309,1,10,0,12.503969694274875,8336.84
642
+ 2024-10-02,0.0,59761,4.579670704285756,2,10,0,48.59549006422309,8423.9
643
+ 2024-10-03,0.0,80700,2.626582252080661,3,10,0,4.579670704285756,8028.37
644
+ 2024-10-04,0.0,92876,9.123140862096978,4,10,0,2.626582252080661,7970.38
645
+ 2024-10-05,0.0,93712,3.8562645975521326,5,10,1,9.123140862096978,8629.03
646
+ 2024-10-06,0.0,71136,39.908694820688474,6,10,1,3.8562645975521326,8802.63
647
+ 2024-10-07,0.0,76980,14.67102513676968,0,10,0,39.908694820688474,8184.08
648
+ 2024-10-08,0.0,84903,0.0,1,10,0,14.67102513676968,8011.87
649
+ 2024-10-09,0.0,85676,0.0,2,10,0,0.0,8086.42
650
+ 2024-10-10,0.0,85197,0.0,3,10,0,0.0,8332.93
651
+ 2024-10-11,0.0,82263,26.840208011433507,4,10,0,0.0,7926.09
652
+ 2024-10-12,0.0,77095,0.0,5,10,1,26.840208011433507,8762.19
653
+ 2024-10-13,0.0,64845,20.157027596801452,6,10,1,0.0,8545.87
654
+ 2024-10-14,0.0,65099,5.704139617300338,0,10,0,20.157027596801452,8391.86
655
+ 2024-10-15,0.0,65744,4.851083071501711,1,10,0,5.704139617300338,8067.78
656
+ 2024-10-16,0.0,95718,10.905479745218086,2,10,0,4.851083071501711,8276.13
657
+ 2024-10-17,0.0,94532,0.0,3,10,0,10.905479745218086,8146.54
658
+ 2024-10-18,0.0,99161,6.300394151105149,4,10,0,0.0,7856.14
659
+ 2024-10-19,0.0,62100,12.120336334699783,5,10,1,6.300394151105149,8945.32
660
+ 2024-10-20,0.0,89456,0.0,6,10,1,12.120336334699783,8911.65
661
+ 2024-10-21,0.0,84229,2.3963005457805884,0,10,0,0.0,8096.76
662
+ 2024-10-22,0.0,77054,16.917309073246816,1,10,0,2.3963005457805884,8141.66
663
+ 2024-10-23,0.0,98057,7.021544686085068,2,10,0,16.917309073246816,7848.84
664
+ 2024-10-24,0.0,77192,33.82468554521728,3,10,0,7.021544686085068,8323.8
665
+ 2024-10-25,0.0,91107,13.413958699710099,4,10,0,33.82468554521728,8448.06
666
+ 2024-10-26,0.0,67572,12.010943819146428,5,10,1,13.413958699710099,8529.89
667
+ 2024-10-27,0.0,67771,3.7242530838373114,6,10,1,12.010943819146428,8844.81
668
+ 2024-10-28,0.0,103238,26.734942456835608,0,10,0,3.7242530838373114,7964.97
669
+ 2024-10-29,0.0,76678,6.720715730526487,1,10,0,26.734942456835608,7996.06
670
+ 2024-10-30,0.0,93241,9.785173212046494,2,10,0,6.720715730526487,7942.0
671
+ 2024-10-31,0.0,82025,5.775681941620076,3,10,0,9.785173212046494,8198.93
672
+ 2024-11-01,0.0,64913,0.0,4,11,0,5.775681941620076,7989.19
673
+ 2024-11-02,0.0,94991,9.584019505017316,5,11,1,0.0,8469.89
674
+ 2024-11-03,0.0,67093,8.247071183330236,6,11,1,9.584019505017316,9008.08
675
+ 2024-11-04,0.0,76802,4.842932714893361,0,11,0,8.247071183330236,8433.74
676
+ 2024-11-05,0.0,73128,17.077088898039626,1,11,0,4.842932714893361,8286.73
677
+ 2024-11-06,0.0,79424,12.71898018643962,2,11,0,17.077088898039626,8142.0
678
+ 2024-11-07,0.0,66118,17.656010080168404,3,11,0,12.71898018643962,8239.63
679
+ 2024-11-08,0.0,86896,3.1556071611953587,4,11,0,17.656010080168404,8271.59
680
+ 2024-11-09,0.0,86918,12.048284524453399,5,11,1,3.1556071611953587,8711.63
681
+ 2024-11-10,0.0,78104,5.332230419561516,6,11,1,12.048284524453399,8675.65
682
+ 2024-11-11,0.0,67926,3.514082117169998,0,11,0,5.332230419561516,7886.4
683
+ 2024-11-12,0.0,99339,23.793489919176416,1,11,0,3.514082117169998,8186.97
684
+ 2024-11-13,0.0,89517,21.81316873918614,2,11,0,23.793489919176416,8185.85
685
+ 2024-11-14,0.0,85593,0.0,3,11,0,21.81316873918614,8279.33
686
+ 2024-11-15,0.0,105094,17.286152242705217,4,11,0,0.0,8079.39
687
+ 2024-11-16,0.0,71548,0.0,5,11,1,17.286152242705217,8779.97
688
+ 2024-11-17,0.0,76643,2.431136084134912,6,11,1,0.0,8674.72
689
+ 2024-11-18,0.0,79605,0.0,0,11,0,2.431136084134912,8220.4
690
+ 2024-11-19,0.0,78084,6.075875438724978,1,11,0,0.0,8040.8
691
+ 2024-11-20,0.0,70701,7.413302260773152,2,11,0,6.075875438724978,8095.5
692
+ 2024-11-21,0.0,116571,0.0,3,11,0,7.413302260773152,8033.29
693
+ 2024-11-22,0.0,70244,9.378314863030894,4,11,0,0.0,8053.4
694
+ 2024-11-23,0.0,92990,18.941088650409032,5,11,1,9.378314863030894,8854.92
695
+ 2024-11-24,0.0,91083,7.759318689793077,6,11,1,18.941088650409032,8922.15
696
+ 2024-11-25,0.0,61968,42.95332989494144,0,11,0,7.759318689793077,8304.43
697
+ 2024-11-26,0.0,92690,0.0,1,11,0,42.95332989494144,8473.49
698
+ 2024-11-27,0.0,73891,0.0,2,11,0,0.0,7874.33
699
+ 2024-11-28,0.0,76130,5.053655423898846,3,11,0,0.0,8095.43
700
+ 2024-11-29,0.0,75061,9.317440129262884,4,11,0,5.053655423898846,7856.56
701
+ 2024-11-30,0.0,86898,6.8422516363066626,5,11,1,9.317440129262884,9043.12
702
+ 2024-12-01,0.0,107251,31.952034807499704,6,12,1,6.8422516363066626,8520.61
703
+ 2024-12-02,0.0,103045,5.5587289956011015,0,12,0,31.952034807499704,8547.67
704
+ 2024-12-03,0.0,78414,10.948451771377773,1,12,0,5.5587289956011015,8297.17
705
+ 2024-12-04,0.0,64719,0.0,2,12,0,10.948451771377773,8291.58
706
+ 2024-12-05,0.0,89242,12.401365617711967,3,12,0,0.0,8027.47
707
+ 2024-12-06,0.0,91712,0.0,4,12,0,12.401365617711967,8112.8
708
+ 2024-12-07,0.0,85187,5.578376374095243,5,12,1,0.0,8591.98
709
+ 2024-12-08,0.0,89304,8.46117946868175,6,12,1,5.578376374095243,8855.5
710
+ 2024-12-09,0.0,73205,0.0,0,12,0,8.46117946868175,7988.24
711
+ 2024-12-10,0.0,101515,9.158204968935392,1,12,0,0.0,8259.8
712
+ 2024-12-11,0.0,89978,17.31427298048083,2,12,0,9.158204968935392,8389.81
713
+ 2024-12-12,0.0,87228,4.264495155470374,3,12,0,17.31427298048083,8453.14
714
+ 2024-12-13,0.0,111454,7.537918100756882,4,12,0,4.264495155470374,8157.0
715
+ 2024-12-14,0.0,57851,7.826116452925073,5,12,1,7.537918100756882,8720.71
716
+ 2024-12-15,0.0,70003,2.695130792626662,6,12,1,7.826116452925073,8726.35
717
+ 2024-12-16,0.0,91009,16.847900819606224,0,12,0,2.695130792626662,8336.13
718
+ 2024-12-17,0.0,86490,18.660123342456163,1,12,0,16.847900819606224,8130.89
719
+ 2024-12-18,0.0,108478,25.486163569336572,2,12,0,18.660123342456163,8405.5
720
+ 2024-12-19,0.0,90205,2.112263169481226,3,12,0,25.486163569336572,8414.18
721
+ 2024-12-20,0.0,84493,7.676158675935539,4,12,0,2.112263169481226,8163.76
722
+ 2024-12-21,0.0,100707,4.735118427396988,5,12,1,7.676158675935539,8677.85
723
+ 2024-12-22,0.0,64795,18.355630143961488,6,12,1,4.735118427396988,8668.82
724
+ 2024-12-23,0.0,94626,16.442077221133257,0,12,0,18.355630143961488,8104.09
725
+ 2024-12-24,0.0,86960,5.231140362276789,1,12,0,16.442077221133257,8164.94
726
+ 2024-12-25,0.0,70289,6.504189825413041,2,12,0,5.231140362276789,7951.45
727
+ 2024-12-26,0.0,72930,6.034278049046891,3,12,0,6.504189825413041,7969.37
728
+ 2024-12-27,0.0,93891,0.0,4,12,0,6.034278049046891,8096.65
729
+ 2024-12-28,0.0,77041,2.166136766507588,5,12,1,0.0,8711.3
730
+ 2024-12-29,0.0,77771,0.0,6,12,1,2.166136766507588,8474.78
731
+ 2024-12-30,0.0,61205,28.67343793886785,0,12,0,0.0,8142.0
732
+ 2024-12-31,1.0,67198,14.994968855465046,1,12,0,28.67343793886785,10116.12
dataset_vibe_coder_2026.csv CHANGED
@@ -1,366 +1,366 @@
1
  TANGGAL,RR,Nama_Event,Ada_Event,Crowd_Scale,Volume_Total_Ton,Vol_Sisa_Makanan_Ton,Vol_Plastik_Ton,Hari_Ke,Is_Weekend,ZONA
2
- 2026-01-01,12.8,New Year Countdown,1,4.0,1696.06,845.83,389.25,1,0,Tourism
3
- 2026-01-02,18.3,New Year Countdown,1,2.8,1680.17,837.9,385.6,2,0,Tourism
4
- 2026-01-03,17.6,,0,0.0,1140.46,568.75,261.74,3,1,Residential
5
- 2026-01-04,4.7,,0,0.0,1188.62,592.76,272.79,4,1,Residential
6
- 2026-01-05,0.0,,0,0.0,1049.35,523.31,240.83,5,0,Residential
7
- 2026-01-06,0.0,,0,0.0,1098.05,547.6,252.0,6,0,Residential
8
- 2026-01-07,11.0,,0,0.0,1156.52,576.76,265.42,7,0,Residential
9
- 2026-01-08,6.2,,0,0.0,1113.32,555.21,255.51,8,0,Residential
10
- 2026-01-09,0.0,,0,0.0,1078.87,538.03,247.6,9,0,Residential
11
- 2026-01-10,0.0,,0,0.0,1140.37,568.7,261.71,10,1,Residential
12
- 2026-01-11,0.2,,0,0.0,1276.39,636.54,292.93,11,1,Residential
13
- 2026-01-12,0.0,,0,0.0,1105.06,551.09,253.61,12,0,Residential
14
- 2026-01-13,0.0,,0,0.0,1038.74,518.02,238.39,13,0,Residential
15
- 2026-01-14,6.3,,0,0.0,1042.88,520.08,239.34,14,0,Residential
16
- 2026-01-15,6.6,,0,0.0,1042.87,520.08,239.34,15,0,Residential
17
- 2026-01-16,0.0,,0,0.0,1101.72,549.43,252.84,16,0,Residential
18
- 2026-01-17,0.0,,0,0.0,1132.37,564.71,259.88,17,1,Residential
19
- 2026-01-18,4.1,Car Free Day,1,1.5,1459.04,727.62,334.85,18,1,Tourism
20
- 2026-01-19,0.0,,0,0.0,1131.86,564.46,259.76,19,0,Residential
21
- 2026-01-20,0.0,,0,0.0,1174.02,585.48,269.44,20,0,Residential
22
- 2026-01-21,0.0,,0,0.0,1167.04,582.0,267.84,21,0,Residential
23
- 2026-01-22,0.0,,0,0.0,1104.18,550.65,253.41,22,0,Residential
24
- 2026-01-23,0.0,,0,0.0,1191.93,594.42,273.55,23,0,Residential
25
- 2026-01-24,0.0,,0,0.0,1323.26,659.91,303.69,24,1,Residential
26
- 2026-01-25,19.1,,0,0.0,1419.77,708.04,325.84,25,1,Residential
27
- 2026-01-26,0.0,,0,0.0,1241.13,618.95,284.84,26,0,Residential
28
- 2026-01-27,2.0,,0,0.0,1124.65,560.86,258.11,27,0,Residential
29
- 2026-01-28,0.0,,0,0.0,1121.14,559.11,257.3,28,0,Residential
30
- 2026-01-29,2.4,,0,0.0,986.89,492.16,226.49,29,0,Residential
31
- 2026-01-30,0.0,,0,0.0,1000.39,498.89,229.59,30,0,Residential
32
- 2026-01-31,0.0,,0,0.0,1045.87,521.58,240.03,31,1,Residential
33
- 2026-02-01,6.6,,0,0.0,1133.89,565.47,260.23,32,1,Residential
34
- 2026-02-02,0.0,,0,0.0,988.2,492.82,226.79,33,0,Residential
35
- 2026-02-03,7.7,,0,0.0,1037.72,517.51,238.16,34,0,Residential
36
- 2026-02-04,0.3,,0,0.0,1060.57,528.91,243.4,35,0,Residential
37
- 2026-02-05,0.0,,0,0.0,1122.54,559.81,257.62,36,0,Residential
38
- 2026-02-06,1.8,,0,0.0,1186.86,591.89,272.38,37,0,Residential
39
- 2026-02-07,0.0,,0,0.0,1253.17,624.96,287.6,38,1,Residential
40
- 2026-02-08,0.0,,0,0.0,1274.11,635.4,292.41,39,1,Residential
41
- 2026-02-09,12.6,,0,0.0,1171.27,584.11,268.81,40,0,Residential
42
- 2026-02-10,7.5,,0,0.0,1207.46,602.16,277.11,41,0,Residential
43
- 2026-02-11,0.0,,0,0.0,1114.12,555.61,255.69,42,0,Residential
44
- 2026-02-12,0.0,,0,0.0,1166.41,581.69,267.69,43,0,Residential
45
- 2026-02-13,0.0,,0,0.0,1212.38,604.61,278.24,44,0,Residential
46
- 2026-02-14,7.5,,0,0.0,1253.65,625.2,287.71,45,1,Residential
47
- 2026-02-15,1.5,Imlek & Glodok Festival,1,1.1,1484.69,740.41,340.74,46,1,Tourism
48
- 2026-02-16,10.6,Imlek & Glodok Festival,1,2.1,1431.13,713.7,328.44,47,0,Tourism
49
- 2026-02-17,0.0,Imlek & Glodok Festival,1,2.5,1528.72,762.37,350.84,48,0,Tourism
50
- 2026-02-18,2.0,Imlek & Glodok Festival,1,2.1,1450.14,723.18,332.81,49,0,Tourism
51
- 2026-02-19,0.0,Imlek & Glodok Festival,1,1.1,1338.97,667.74,307.29,50,0,Tourism
52
- 2026-02-20,5.6,,0,0.0,1140.89,568.96,261.83,51,0,Residential
53
- 2026-02-21,0.0,,0,0.0,1169.26,583.11,268.35,52,1,Residential
54
- 2026-02-22,0.0,,0,0.0,1191.79,594.35,273.52,53,1,Residential
55
- 2026-02-23,0.0,,0,0.0,1155.3,576.15,265.14,54,0,Residential
56
- 2026-02-24,0.0,,0,0.0,1161.89,579.43,266.65,55,0,Residential
57
- 2026-02-25,0.0,,0,0.0,1137.92,567.48,261.15,56,0,Residential
58
- 2026-02-26,14.6,,0,0.0,1223.47,610.14,280.79,57,0,Residential
59
- 2026-02-27,1.0,,0,0.0,1259.33,628.03,289.02,58,0,Residential
60
- 2026-02-28,0.0,,0,0.0,1276.59,636.64,292.98,59,1,Residential
61
- 2026-03-01,0.0,,0,0.0,1332.21,664.37,305.74,60,1,Residential
62
- 2026-03-02,3.1,,0,0.0,1184.97,590.94,271.95,61,0,Residential
63
- 2026-03-03,0.0,,0,0.0,1237.8,617.29,284.08,62,0,Residential
64
- 2026-03-04,1.2,,0,0.0,1282.48,639.57,294.33,63,0,Residential
65
- 2026-03-05,0.0,,0,0.0,1228.79,612.8,282.01,64,0,Residential
66
- 2026-03-06,5.4,,0,0.0,1283.1,639.88,294.47,65,0,Residential
67
- 2026-03-07,14.1,,0,0.0,1409.45,702.89,323.47,66,1,Residential
68
- 2026-03-08,0.0,,0,0.0,1377.82,687.12,316.21,67,1,Residential
69
- 2026-03-09,0.0,,0,0.0,1170.72,583.84,268.68,68,0,Residential
70
- 2026-03-10,8.3,,0,0.0,1176.19,586.57,269.94,69,0,Residential
71
- 2026-03-11,0.0,,0,0.0,1135.71,566.38,260.65,70,0,Residential
72
- 2026-03-12,0.0,,0,0.0,1112.95,555.03,255.42,71,0,Residential
73
- 2026-03-13,0.0,,0,0.0,1136.54,566.79,260.84,72,0,Residential
74
- 2026-03-14,6.0,,0,0.0,1278.86,637.77,293.5,73,1,Residential
75
- 2026-03-15,0.0,,0,0.0,1336.51,666.52,306.73,74,1,Residential
76
- 2026-03-16,14.5,,0,0.0,1179.92,588.43,270.79,75,0,Residential
77
- 2026-03-17,16.9,,0,0.0,1180.1,588.52,270.83,76,0,Residential
78
- 2026-03-18,9.8,H-3 Lebaran,1,2.7,1319.02,657.8,302.72,77,0,Residential
79
- 2026-03-19,14.3,H-3 Lebaran,1,4.0,1439.38,717.82,330.34,78,0,Residential
80
- 2026-03-20,9.3,Idul Fitri,1,2.3,1796.19,895.76,412.23,79,0,Residential
81
- 2026-03-21,0.0,Idul Fitri,1,4.1,1877.31,936.21,430.84,80,1,Residential
82
- 2026-03-22,1.5,Idul Fitri,1,5.0,2127.06,1060.76,488.16,81,1,Residential
83
- 2026-03-23,18.4,Idul Fitri,1,4.1,1581.28,788.58,362.9,82,0,Residential
84
- 2026-03-24,0.0,Idul Fitri,1,2.3,1338.39,667.46,307.16,83,0,Residential
85
- 2026-03-25,16.8,,0,0.0,1258.69,627.71,288.87,84,0,Residential
86
- 2026-03-26,17.6,,0,0.0,1253.6,625.17,287.7,85,0,Residential
87
- 2026-03-27,17.9,,0,0.0,1289.54,643.09,295.95,86,0,Residential
88
- 2026-03-28,0.0,,0,0.0,1308.3,652.45,300.25,87,1,Residential
89
- 2026-03-29,13.7,,0,0.0,1324.76,660.66,304.03,88,1,Residential
90
- 2026-03-30,11.7,,0,0.0,1164.96,580.97,267.36,89,0,Residential
91
- 2026-03-31,0.0,,0,0.0,1087.82,542.5,249.65,90,0,Residential
92
- 2026-04-01,0.0,,0,0.0,1165.27,581.12,267.43,91,0,Residential
93
- 2026-04-02,27.3,,0,0.0,1146.21,571.61,263.06,92,0,Residential
94
- 2026-04-03,0.0,,0,0.0,1183.38,590.15,271.59,93,0,Residential
95
- 2026-04-04,9.7,,0,0.0,1290.59,643.62,296.19,94,1,Residential
96
- 2026-04-05,0.0,,0,0.0,1277.15,636.91,293.11,95,1,Residential
97
- 2026-04-06,0.0,,0,0.0,1207.54,602.2,277.13,96,0,Residential
98
- 2026-04-07,24.4,,0,0.0,1221.73,609.28,280.39,97,0,Residential
99
- 2026-04-08,12.3,,0,0.0,1236.31,616.55,283.73,98,0,Residential
100
- 2026-04-09,0.0,Jakarta Art Festival,1,1.4,1438.29,717.28,330.09,99,0,Tourism
101
- 2026-04-10,14.8,Jakarta Art Festival,1,2.0,1573.75,784.83,361.18,100,0,Tourism
102
- 2026-04-11,9.0,Jakarta Art Festival,1,1.4,1509.46,752.77,346.42,101,1,Tourism
103
- 2026-04-12,0.0,,0,0.0,1282.51,639.59,294.34,102,1,Residential
104
- 2026-04-13,11.8,,0,0.0,1217.31,607.07,279.37,103,0,Residential
105
- 2026-04-14,27.3,,0,0.0,1194.52,595.71,274.14,104,0,Residential
106
- 2026-04-15,0.0,,0,0.0,1192.52,594.71,273.68,105,0,Residential
107
- 2026-04-16,0.0,,0,0.0,1230.3,613.55,282.35,106,0,Residential
108
- 2026-04-17,13.1,,0,0.0,1237.16,616.97,283.93,107,0,Residential
109
- 2026-04-18,12.4,,0,0.0,1349.32,672.91,309.67,108,1,Residential
110
- 2026-04-19,0.0,,0,0.0,1435.34,715.8,329.41,109,1,Residential
111
- 2026-04-20,0.0,,0,0.0,1344.25,670.38,308.51,110,0,Residential
112
- 2026-04-21,7.2,,0,0.0,1335.37,665.95,306.47,111,0,Residential
113
- 2026-04-22,24.3,,0,0.0,1308.14,652.37,300.22,112,0,Residential
114
- 2026-04-23,0.0,,0,0.0,1362.56,679.51,312.71,113,0,Residential
115
- 2026-04-24,0.0,,0,0.0,1317.66,657.12,302.4,114,0,Residential
116
- 2026-04-25,23.4,,0,0.0,1406.34,701.34,322.76,115,1,Residential
117
- 2026-04-26,0.0,,0,0.0,1318.36,657.47,302.56,116,1,Residential
118
- 2026-04-27,0.0,,0,0.0,1175.38,586.16,269.75,117,0,Residential
119
- 2026-04-28,37.7,,0,0.0,1256.5,626.62,288.37,118,0,Residential
120
- 2026-04-29,14.3,,0,0.0,1178.04,587.49,270.36,119,0,Residential
121
- 2026-04-30,0.0,May Day Rally,1,1.4,1476.41,736.29,338.84,120,0,Tourism
122
- 2026-05-01,14.5,May Day Rally,1,3.0,1689.53,842.57,387.75,121,0,Tourism
123
- 2026-05-02,13.4,May Day Rally,1,1.4,1569.05,782.49,360.1,122,1,Tourism
124
- 2026-05-03,10.0,,0,0.0,1280.63,638.65,293.9,123,1,Residential
125
- 2026-05-04,0.0,,0,0.0,1167.35,582.16,267.91,124,0,Residential
126
- 2026-05-05,26.7,,0,0.0,1212.21,604.53,278.2,125,0,Residential
127
- 2026-05-06,0.0,,0,0.0,1190.33,593.62,273.18,126,0,Residential
128
- 2026-05-07,0.0,,0,0.0,1199.01,597.95,275.17,127,0,Residential
129
- 2026-05-08,30.7,,0,0.0,1309.95,653.27,300.63,128,0,Residential
130
- 2026-05-09,30.6,,0,0.0,1384.28,690.34,317.69,129,1,Residential
131
- 2026-05-10,35.5,,0,0.0,1347.39,671.94,309.23,130,1,Residential
132
- 2026-05-11,30.4,,0,0.0,1190.81,593.86,273.29,131,0,Residential
133
- 2026-05-12,18.5,,0,0.0,1285.84,641.25,295.1,132,0,Residential
134
- 2026-05-13,27.4,,0,0.0,1189.41,593.16,272.97,133,0,Residential
135
- 2026-05-14,23.7,,0,0.0,1188.01,592.46,272.65,134,0,Residential
136
- 2026-05-15,0.0,,0,0.0,1251.28,624.01,287.17,135,0,Residential
137
- 2026-05-16,0.0,,0,0.0,1190.24,593.57,273.16,136,1,Residential
138
- 2026-05-17,0.0,,0,0.0,1338.92,667.72,307.28,137,1,Residential
139
- 2026-05-18,23.7,,0,0.0,1288.92,642.78,295.81,138,0,Residential
140
- 2026-05-19,0.0,,0,0.0,1232.84,614.82,282.94,139,0,Residential
141
- 2026-05-20,34.7,,0,0.0,1272.2,634.45,291.97,140,0,Residential
142
- 2026-05-21,21.7,,0,0.0,1222.5,609.66,280.56,141,0,Residential
143
- 2026-05-22,0.0,,0,0.0,1240.35,618.56,284.66,142,0,Residential
144
- 2026-05-23,32.7,,0,0.0,1325.67,661.11,304.24,143,1,Residential
145
- 2026-05-24,0.0,,0,0.0,1264.86,630.79,290.29,144,1,Residential
146
- 2026-05-25,9.7,,0,0.0,1219.79,608.31,279.94,145,0,Residential
147
- 2026-05-26,30.3,,0,0.0,1215.74,606.29,279.01,146,0,Residential
148
- 2026-05-27,25.1,,0,0.0,1250.5,623.62,286.99,147,0,Residential
149
- 2026-05-28,19.0,,0,0.0,1269.81,633.25,291.42,148,0,Residential
150
- 2026-05-29,36.3,PRJ Opening,1,2.3,1789.29,892.32,410.64,149,0,Tourism
151
- 2026-05-30,11.0,PRJ Opening,1,3.1,1994.38,994.6,457.71,150,1,Tourism
152
- 2026-05-31,0.0,PRJ Opening,1,3.8,2144.87,1069.65,492.25,151,1,Tourism
153
- 2026-06-01,19.9,PRJ Opening,1,4.0,2120.65,1057.57,486.69,152,0,Tourism
154
- 2026-06-02,0.0,PRJ Opening,1,3.8,1855.23,925.2,425.78,153,0,Tourism
155
- 2026-06-03,24.2,PRJ Opening,1,3.1,1605.67,800.75,368.5,154,0,Tourism
156
- 2026-06-04,0.0,PRJ Opening,1,2.3,1555.57,775.76,357.0,155,0,Tourism
157
- 2026-06-05,15.3,,0,0.0,1348.6,672.55,309.5,156,0,Residential
158
- 2026-06-06,0.0,,0,0.0,1411.46,703.9,323.93,157,1,Residential
159
- 2026-06-07,15.3,,0,0.0,1490.72,743.42,342.12,158,1,Residential
160
- 2026-06-08,25.0,,0,0.0,1367.21,681.83,313.77,159,0,Residential
161
- 2026-06-09,0.0,,0,0.0,1359.83,678.15,312.08,160,0,Residential
162
- 2026-06-10,17.8,,0,0.0,1324.46,660.51,303.96,161,0,Residential
163
- 2026-06-11,32.6,,0,0.0,1317.74,657.16,302.42,162,0,Residential
164
- 2026-06-12,25.4,,0,0.0,1327.58,662.06,304.68,163,0,Residential
165
- 2026-06-13,39.8,,0,0.0,1326.73,661.64,304.48,164,1,Residential
166
- 2026-06-14,0.0,Music Festival GBK,1,1.6,1702.74,849.16,390.78,165,1,Tourism
167
- 2026-06-15,29.6,Music Festival GBK,1,3.5,1814.32,904.8,416.39,166,0,Tourism
168
- 2026-06-16,33.7,Music Festival GBK,1,1.6,1690.19,842.9,387.9,167,0,Tourism
169
- 2026-06-17,0.0,,0,0.0,1179.07,588.0,270.6,168,0,Residential
170
- 2026-06-18,35.9,,0,0.0,1284.4,640.53,294.77,169,0,Residential
171
- 2026-06-19,22.7,,0,0.0,1376.88,686.65,315.99,170,0,Residential
172
- 2026-06-20,33.8,,0,0.0,1488.52,742.32,341.62,171,1,Residential
173
- 2026-06-21,34.9,,0,0.0,1498.51,747.31,343.91,172,1,Residential
174
- 2026-06-22,0.0,,0,0.0,1253.06,624.9,287.58,173,0,Residential
175
- 2026-06-23,27.4,,0,0.0,1282.71,639.69,294.38,174,0,Residential
176
- 2026-06-24,0.0,,0,0.0,1355.08,675.78,310.99,175,0,Residential
177
- 2026-06-25,0.0,,0,0.0,1424.11,710.2,326.83,176,0,Residential
178
- 2026-06-26,36.1,,0,0.0,1397.18,696.77,320.65,177,0,Residential
179
- 2026-06-27,0.0,,0,0.0,1317.93,657.25,302.46,178,1,Residential
180
- 2026-06-28,26.9,,0,0.0,1413.5,704.91,324.4,179,1,Residential
181
- 2026-06-29,34.7,,0,0.0,1376.99,686.7,316.02,180,0,Residential
182
- 2026-06-30,0.0,,0,0.0,1280.37,638.52,293.84,181,0,Residential
183
- 2026-07-01,26.6,,0,0.0,1289.92,643.28,296.04,182,0,Residential
184
- 2026-07-02,0.0,,0,0.0,1243.38,620.07,285.36,183,0,Residential
185
- 2026-07-03,8.4,,0,0.0,1277.79,637.23,293.25,184,0,Residential
186
- 2026-07-04,0.0,,0,0.0,1350.35,673.42,309.91,185,1,Residential
187
- 2026-07-05,12.2,,0,0.0,1401.33,698.84,321.61,186,1,Residential
188
- 2026-07-06,0.0,,0,0.0,1174.55,585.75,269.56,187,0,Residential
189
- 2026-07-07,0.0,,0,0.0,1274.83,635.76,292.57,188,0,Residential
190
- 2026-07-08,31.3,,0,0.0,1330.56,663.55,305.36,189,0,Residential
191
- 2026-07-09,0.0,,0,0.0,1194.99,595.94,274.25,190,0,Residential
192
- 2026-07-10,38.5,,0,0.0,1199.44,598.16,275.27,191,0,Residential
193
- 2026-07-11,22.5,,0,0.0,1297.1,646.86,297.68,192,1,Residential
194
- 2026-07-12,28.0,,0,0.0,1452.0,724.11,333.23,193,1,Residential
195
- 2026-07-13,31.1,,0,0.0,1349.59,673.04,309.73,194,0,Residential
196
- 2026-07-14,23.2,,0,0.0,1240.46,618.62,284.69,195,0,Residential
197
- 2026-07-15,45.0,,0,0.0,1317.83,657.2,302.44,196,0,Residential
198
- 2026-07-16,27.6,,0,0.0,1165.91,581.44,267.58,197,0,Residential
199
- 2026-07-17,30.6,,0,0.0,1178.77,587.85,270.53,198,0,Residential
200
- 2026-07-18,40.0,,0,0.0,1278.2,637.44,293.35,199,1,Residential
201
- 2026-07-19,35.9,PRJ Peak Weekend,1,3.5,2042.55,1018.62,468.77,200,1,Tourism
202
- 2026-07-20,0.0,PRJ Peak Weekend,1,5.0,2037.52,1016.11,467.61,201,0,Tourism
203
- 2026-07-21,21.0,PRJ Peak Weekend,1,3.5,1891.77,943.43,434.16,202,0,Tourism
204
- 2026-07-22,0.0,,0,0.0,1265.2,630.96,290.36,203,0,Residential
205
- 2026-07-23,32.4,,0,0.0,1210.79,603.82,277.88,204,0,Residential
206
- 2026-07-24,22.5,,0,0.0,1234.0,615.4,283.2,205,0,Residential
207
- 2026-07-25,0.0,,0,0.0,1327.05,661.8,304.56,206,1,Residential
208
- 2026-07-26,28.6,,0,0.0,1407.14,701.74,322.94,207,1,Residential
209
- 2026-07-27,25.7,,0,0.0,1239.27,618.02,284.41,208,0,Residential
210
- 2026-07-28,0.0,,0,0.0,1179.16,588.05,270.62,209,0,Residential
211
- 2026-07-29,18.4,,0,0.0,1245.29,621.03,285.79,210,0,Residential
212
- 2026-07-30,19.8,,0,0.0,1249.0,622.88,286.65,211,0,Residential
213
- 2026-07-31,30.9,,0,0.0,1258.28,627.5,288.78,212,0,Residential
214
- 2026-08-01,0.0,,0,0.0,1221.3,609.06,280.29,213,1,Residential
215
- 2026-08-02,0.0,,0,0.0,1286.77,641.71,295.31,214,1,Residential
216
- 2026-08-03,17.8,,0,0.0,1217.89,607.36,279.51,215,0,Residential
217
- 2026-08-04,0.0,,0,0.0,1265.38,631.05,290.4,216,0,Residential
218
- 2026-08-05,0.0,,0,0.0,1291.66,644.15,296.44,217,0,Residential
219
- 2026-08-06,19.7,,0,0.0,1235.79,616.29,283.61,218,0,Residential
220
- 2026-08-07,23.8,,0,0.0,1228.69,612.75,281.98,219,0,Residential
221
- 2026-08-08,0.0,,0,0.0,1325.93,661.24,304.3,220,1,Residential
222
- 2026-08-09,18.4,,0,0.0,1393.9,695.14,319.9,221,1,Residential
223
- 2026-08-10,27.2,,0,0.0,1171.09,584.02,268.77,222,0,Residential
224
- 2026-08-11,0.0,,0,0.0,1157.77,577.38,265.71,223,0,Residential
225
- 2026-08-12,26.1,,0,0.0,1114.41,555.76,255.76,224,0,Residential
226
- 2026-08-13,43.9,,0,0.0,1203.8,600.34,276.27,225,0,Residential
227
- 2026-08-14,25.7,,0,0.0,1192.9,594.9,273.77,226,0,Residential
228
- 2026-08-15,26.2,HUT RI ke-81,1,1.8,1688.51,842.06,387.51,227,1,Tourism
229
- 2026-08-16,0.0,HUT RI ke-81,1,3.3,1853.79,924.49,425.44,228,1,Tourism
230
- 2026-08-17,15.6,HUT RI ke-81,1,4.0,1809.94,902.62,415.38,229,0,Tourism
231
- 2026-08-18,0.0,HUT RI ke-81,1,3.3,1741.77,868.62,399.74,230,0,Tourism
232
- 2026-08-19,30.2,HUT RI ke-81,1,1.8,1548.15,772.06,355.3,231,0,Tourism
233
- 2026-08-20,0.0,,0,0.0,1031.94,514.63,236.83,232,0,Residential
234
- 2026-08-21,25.9,,0,0.0,1113.72,555.41,255.6,233,0,Residential
235
- 2026-08-22,0.0,,0,0.0,1211.49,604.17,278.04,234,1,Residential
236
- 2026-08-23,24.6,,0,0.0,1303.86,650.23,299.24,235,1,Residential
237
- 2026-08-24,0.0,,0,0.0,1128.57,562.82,259.01,236,0,Residential
238
- 2026-08-25,19.5,,0,0.0,1156.89,576.94,265.51,237,0,Residential
239
- 2026-08-26,17.1,,0,0.0,1198.25,597.57,275.0,238,0,Residential
240
- 2026-08-27,0.0,,0,0.0,1195.31,596.1,274.32,239,0,Residential
241
- 2026-08-28,21.4,,0,0.0,1182.37,589.65,271.35,240,0,Residential
242
- 2026-08-29,9.5,,0,0.0,1212.5,604.67,278.27,241,1,Residential
243
- 2026-08-30,9.3,,0,0.0,1261.2,628.96,289.45,242,1,Residential
244
- 2026-08-31,0.0,,0,0.0,1162.08,579.53,266.7,243,0,Residential
245
- 2026-09-01,0.0,,0,0.0,1157.85,577.42,265.73,244,0,Residential
246
- 2026-09-02,9.1,,0,0.0,1080.53,538.86,247.98,245,0,Residential
247
- 2026-09-03,0.0,,0,0.0,1094.29,545.72,251.14,246,0,Residential
248
- 2026-09-04,16.4,,0,0.0,1092.75,544.95,250.79,247,0,Residential
249
- 2026-09-05,10.4,,0,0.0,987.42,492.43,226.61,248,1,Residential
250
- 2026-09-06,11.4,,0,0.0,1095.05,546.1,251.31,249,1,Residential
251
- 2026-09-07,31.2,,0,0.0,1151.06,574.03,264.17,250,0,Residential
252
- 2026-09-08,18.6,,0,0.0,1154.8,575.9,265.03,251,0,Residential
253
- 2026-09-09,17.1,,0,0.0,1090.63,543.9,250.3,252,0,Residential
254
- 2026-09-10,16.4,,0,0.0,1158.39,577.69,265.85,253,0,Residential
255
- 2026-09-11,19.9,,0,0.0,1152.3,574.65,264.45,254,0,Residential
256
- 2026-09-12,0.0,,0,0.0,1241.85,619.31,285.0,255,1,Residential
257
- 2026-09-13,0.0,,0,0.0,1366.75,681.6,313.67,256,1,Residential
258
- 2026-09-14,23.7,Food & Culture Expo,1,1.8,1586.21,791.04,364.04,257,0,Tourism
259
- 2026-09-15,10.9,Food & Culture Expo,1,2.5,1524.71,760.37,349.92,258,0,Tourism
260
- 2026-09-16,19.9,Food & Culture Expo,1,1.8,1602.81,799.32,367.84,259,0,Tourism
261
- 2026-09-17,9.2,,0,0.0,1118.5,557.8,256.7,260,0,Residential
262
- 2026-09-18,0.0,,0,0.0,1134.77,565.91,260.43,261,0,Residential
263
- 2026-09-19,2.9,,0,0.0,1151.23,574.12,264.21,262,1,Residential
264
- 2026-09-20,0.0,,0,0.0,1265.47,631.09,290.43,263,1,Residential
265
- 2026-09-21,14.8,,0,0.0,1231.35,614.07,282.59,264,0,Residential
266
- 2026-09-22,19.1,,0,0.0,1228.88,612.84,282.03,265,0,Residential
267
- 2026-09-23,12.5,,0,0.0,1165.05,581.01,267.38,266,0,Residential
268
- 2026-09-24,11.3,,0,0.0,1130.59,563.83,259.47,267,0,Residential
269
- 2026-09-25,5.2,,0,0.0,1172.03,584.49,268.98,268,0,Residential
270
- 2026-09-26,10.0,,0,0.0,1228.18,612.49,281.87,269,1,Residential
271
- 2026-09-27,0.0,,0,0.0,1228.48,612.64,281.94,270,1,Residential
272
- 2026-09-28,0.0,,0,0.0,1076.39,536.8,247.03,271,0,Residential
273
- 2026-09-29,0.0,,0,0.0,1088.2,542.69,249.74,272,0,Residential
274
- 2026-09-30,13.5,,0,0.0,1072.36,534.79,246.11,273,0,Residential
275
- 2026-10-01,0.0,,0,0.0,1159.44,578.21,266.09,274,0,Residential
276
- 2026-10-02,8.7,,0,0.0,1061.84,529.54,243.69,275,0,Residential
277
- 2026-10-03,0.0,,0,0.0,1083.46,540.32,248.65,276,1,Residential
278
- 2026-10-04,0.0,,0,0.0,1036.04,516.67,237.77,277,1,Residential
279
- 2026-10-05,1.6,,0,0.0,960.74,479.12,220.49,278,0,Residential
280
- 2026-10-06,0.0,,0,0.0,970.83,484.15,222.81,279,0,Residential
281
- 2026-10-07,0.0,,0,0.0,1030.23,513.78,236.44,280,0,Residential
282
- 2026-10-08,7.8,,0,0.0,1051.25,524.26,241.26,281,0,Residential
283
- 2026-10-09,12.6,Jakarta Marathon,1,1.4,1267.7,632.2,290.94,282,0,Tourism
284
- 2026-10-10,0.0,Jakarta Marathon,1,3.0,1591.74,793.8,365.3,283,1,Tourism
285
- 2026-10-11,0.0,Jakarta Marathon,1,1.4,1480.01,738.08,339.66,284,1,Tourism
286
- 2026-10-12,0.0,,0,0.0,1154.37,575.68,264.93,285,0,Residential
287
- 2026-10-13,23.0,,0,0.0,1137.95,567.5,261.16,286,0,Residential
288
- 2026-10-14,0.0,,0,0.0,1207.07,601.97,277.02,287,0,Residential
289
- 2026-10-15,13.0,,0,0.0,1199.22,598.05,275.22,288,0,Residential
290
- 2026-10-16,4.8,,0,0.0,1174.15,585.55,269.47,289,0,Residential
291
- 2026-10-17,0.0,,0,0.0,1210.3,603.58,277.76,290,1,Residential
292
- 2026-10-18,0.0,,0,0.0,1208.7,602.78,277.4,291,1,Residential
293
- 2026-10-19,0.0,,0,0.0,1033.53,515.42,237.2,292,0,Residential
294
- 2026-10-20,0.0,,0,0.0,1004.81,501.1,230.6,293,0,Residential
295
- 2026-10-21,9.6,,0,0.0,1092.89,545.02,250.82,294,0,Residential
296
- 2026-10-22,16.8,,0,0.0,1145.34,571.18,262.86,295,0,Residential
297
- 2026-10-23,0.0,,0,0.0,1064.46,530.85,244.29,296,0,Residential
298
- 2026-10-24,0.0,,0,0.0,1098.36,547.75,252.07,297,1,Residential
299
- 2026-10-25,16.6,,0,0.0,1175.09,586.02,269.68,298,1,Residential
300
- 2026-10-26,0.0,,0,0.0,1075.67,536.44,246.87,299,0,Residential
301
- 2026-10-27,0.0,,0,0.0,1087.48,542.33,249.58,300,0,Residential
302
- 2026-10-28,0.0,,0,0.0,1126.69,561.88,258.58,301,0,Residential
303
- 2026-10-29,0.0,,0,0.0,1073.27,535.24,246.32,302,0,Residential
304
- 2026-10-30,0.0,,0,0.0,1072.46,534.84,246.13,303,0,Residential
305
- 2026-10-31,0.0,,0,0.0,1091.02,544.09,250.39,304,1,Residential
306
- 2026-11-01,0.0,,0,0.0,1139.56,568.3,261.53,305,1,Residential
307
- 2026-11-02,0.0,,0,0.0,1102.99,550.06,253.14,306,0,Residential
308
- 2026-11-03,0.7,,0,0.0,1063.13,530.18,243.99,307,0,Residential
309
- 2026-11-04,0.0,,0,0.0,979.44,488.45,224.78,308,0,Residential
310
- 2026-11-05,0.0,,0,0.0,1042.88,520.08,239.34,309,0,Residential
311
- 2026-11-06,0.0,,0,0.0,1089.48,543.32,250.04,310,0,Residential
312
- 2026-11-07,0.0,,0,0.0,1105.66,551.39,253.75,311,1,Residential
313
- 2026-11-08,7.0,,0,0.0,1181.19,589.06,271.08,312,1,Residential
314
- 2026-11-09,0.0,,0,0.0,1139.02,568.03,261.41,313,0,Residential
315
- 2026-11-10,2.8,,0,0.0,1169.42,583.19,268.38,314,0,Residential
316
- 2026-11-11,0.0,,0,0.0,1144.95,570.99,262.77,315,0,Residential
317
- 2026-11-12,5.1,,0,0.0,1092.95,545.05,250.83,316,0,Residential
318
- 2026-11-13,0.0,,0,0.0,1083.25,540.22,248.61,317,0,Residential
319
- 2026-11-14,0.0,,0,0.0,1130.69,563.88,259.49,318,1,Residential
320
- 2026-11-15,0.0,,0,0.0,1107.53,552.33,254.18,319,1,Residential
321
- 2026-11-16,0.0,,0,0.0,916.92,457.27,210.43,320,0,Residential
322
- 2026-11-17,0.0,,0,0.0,954.94,476.23,219.16,321,0,Residential
323
- 2026-11-18,0.0,,0,0.0,967.1,482.29,221.95,322,0,Residential
324
- 2026-11-19,1.2,,0,0.0,1030.06,513.69,236.4,323,0,Residential
325
- 2026-11-20,0.0,,0,0.0,1055.09,526.17,242.14,324,0,Residential
326
- 2026-11-21,0.0,,0,0.0,1131.35,564.2,259.64,325,1,Residential
327
- 2026-11-22,1.3,,0,0.0,1147.99,572.5,263.46,326,1,Residential
328
- 2026-11-23,0.0,,0,0.0,1050.8,524.03,241.16,327,0,Residential
329
- 2026-11-24,0.0,Ancol Music Fest,1,1.4,1327.34,661.94,304.62,328,0,Tourism
330
- 2026-11-25,9.1,Ancol Music Fest,1,3.0,1532.54,764.28,351.72,329,0,Tourism
331
- 2026-11-26,0.7,Ancol Music Fest,1,1.4,1395.51,695.94,320.27,330,0,Tourism
332
- 2026-11-27,0.0,,0,0.0,1066.82,532.02,244.84,331,0,Residential
333
- 2026-11-28,5.7,,0,0.0,1069.89,533.55,245.54,332,1,Residential
334
- 2026-11-29,0.0,,0,0.0,1141.63,569.33,262.0,333,1,Residential
335
- 2026-11-30,0.0,,0,0.0,1050.37,523.82,241.06,334,0,Residential
336
- 2026-12-01,0.0,,0,0.0,1061.99,529.61,243.73,335,0,Residential
337
- 2026-12-02,0.0,,0,0.0,1047.7,522.49,240.45,336,0,Residential
338
- 2026-12-03,0.0,,0,0.0,1070.87,534.04,245.76,337,0,Residential
339
- 2026-12-04,6.5,,0,0.0,1098.7,547.92,252.15,338,0,Residential
340
- 2026-12-05,0.0,,0,0.0,1159.19,578.09,266.03,339,1,Residential
341
- 2026-12-06,1.0,,0,0.0,1169.48,583.22,268.4,340,1,Residential
342
- 2026-12-07,0.0,,0,0.0,1016.41,506.88,233.27,341,0,Residential
343
- 2026-12-08,11.3,,0,0.0,1004.74,501.06,230.59,342,0,Residential
344
- 2026-12-09,0.0,,0,0.0,1053.13,525.2,241.69,343,0,Residential
345
- 2026-12-10,0.0,,0,0.0,1108.26,552.69,254.35,344,0,Residential
346
- 2026-12-11,0.0,,0,0.0,1025.47,511.4,235.35,345,0,Residential
347
- 2026-12-12,11.7,,0,0.0,1079.56,538.38,247.76,346,1,Residential
348
- 2026-12-13,0.0,,0,0.0,1171.86,584.41,268.94,347,1,Residential
349
- 2026-12-14,0.0,,0,0.0,1109.91,553.51,254.72,348,0,Residential
350
- 2026-12-15,0.0,,0,0.0,1122.56,559.82,257.63,349,0,Residential
351
- 2026-12-16,0.0,,0,0.0,1168.55,582.76,268.18,350,0,Residential
352
- 2026-12-17,0.0,,0,0.0,1203.69,600.28,276.25,351,0,Residential
353
- 2026-12-18,3.4,Christmas Market,1,2.1,1445.72,720.98,331.79,352,0,Tourism
354
- 2026-12-19,0.0,Christmas Market,1,3.1,1559.14,777.54,357.82,353,1,Tourism
355
- 2026-12-20,0.0,Christmas Market,1,3.5,1708.29,851.92,392.05,354,1,Tourism
356
- 2026-12-21,7.5,Christmas Market,1,3.1,1457.21,726.71,334.43,355,0,Tourism
357
- 2026-12-22,5.1,Christmas Market,1,2.1,1410.85,703.59,323.79,356,0,Tourism
358
- 2026-12-23,7.3,,0,0.0,1171.39,584.17,268.83,357,0,Residential
359
- 2026-12-24,0.0,,0,0.0,1133.24,565.15,260.08,358,0,Residential
360
- 2026-12-25,2.9,,0,0.0,1123.76,560.42,257.9,359,0,Residential
361
- 2026-12-26,0.0,,0,0.0,1197.6,597.24,274.85,360,1,Residential
362
- 2026-12-27,0.0,,0,0.0,1198.69,597.79,275.1,361,1,Residential
363
- 2026-12-28,0.0,,0,0.0,1050.24,523.75,241.03,362,0,Residential
364
- 2026-12-29,0.0,,0,0.0,1142.55,569.79,262.22,363,0,Residential
365
- 2026-12-30,0.0,Countdown Jakarta 2027,1,3.2,1641.85,818.79,376.8,364,0,Tourism
366
- 2026-12-31,10.7,Countdown Jakarta 2027,1,4.5,1756.35,875.89,403.08,365,0,Tourism
 
1
  TANGGAL,RR,Nama_Event,Ada_Event,Crowd_Scale,Volume_Total_Ton,Vol_Sisa_Makanan_Ton,Vol_Plastik_Ton,Hari_Ke,Is_Weekend,ZONA
2
+ 2026-01-01,12.8,New Year Countdown,1,4.0,10798.08,5385.03,2478.19,1,0,Tourism
3
+ 2026-01-02,18.3,New Year Countdown,1,2.8,10696.91,5334.55,2454.95,2,0,Tourism
4
+ 2026-01-03,17.6,,0,0.0,7260.81,3620.98,1666.39,3,1,Residential
5
+ 2026-01-04,4.7,,0,0.0,7567.43,3773.85,1736.74,4,1,Residential
6
+ 2026-01-05,0.0,,0,0.0,6680.76,3331.69,1533.26,5,0,Residential
7
+ 2026-01-06,0.0,,0,0.0,6990.81,3486.33,1604.37,6,0,Residential
8
+ 2026-01-07,11.0,,0,0.0,7363.06,3671.98,1689.81,7,0,Residential
9
+ 2026-01-08,6.2,,0,0.0,7088.03,3534.78,1626.72,8,0,Residential
10
+ 2026-01-09,0.0,,0,0.0,6868.7,3425.4,1576.36,9,0,Residential
11
+ 2026-01-10,0.0,,0,0.0,7260.24,3620.67,1666.19,10,1,Residential
12
+ 2026-01-11,0.2,,0,0.0,8126.22,4052.57,1864.96,11,1,Residential
13
+ 2026-01-12,0.0,,0,0.0,7035.44,3508.55,1614.62,12,0,Residential
14
+ 2026-01-13,0.0,,0,0.0,6613.21,3298.01,1517.73,13,0,Residential
15
+ 2026-01-14,6.3,,0,0.0,6639.57,3311.12,1523.77,14,0,Residential
16
+ 2026-01-15,6.6,,0,0.0,6639.5,3311.12,1523.77,15,0,Residential
17
+ 2026-01-16,0.0,,0,0.0,7014.17,3497.98,1609.72,16,0,Residential
18
+ 2026-01-17,0.0,,0,0.0,7209.31,3595.26,1654.54,17,1,Residential
19
+ 2026-01-18,4.1,Car Free Day,1,1.5,9289.08,4632.44,2131.84,18,1,Tourism
20
+ 2026-01-19,0.0,,0,0.0,7206.06,3593.67,1653.78,19,0,Residential
21
+ 2026-01-20,0.0,,0,0.0,7474.48,3727.5,1715.41,20,0,Residential
22
+ 2026-01-21,0.0,,0,0.0,7430.04,3705.34,1705.22,21,0,Residential
23
+ 2026-01-22,0.0,,0,0.0,7029.84,3505.75,1613.35,22,0,Residential
24
+ 2026-01-23,0.0,,0,0.0,7588.5,3784.41,1741.57,23,0,Residential
25
+ 2026-01-24,0.0,,0,0.0,8424.62,4201.36,1933.46,24,1,Residential
26
+ 2026-01-25,19.1,,0,0.0,9039.06,4507.78,2074.48,25,1,Residential
27
+ 2026-01-26,0.0,,0,0.0,7901.74,3940.59,1813.45,26,0,Residential
28
+ 2026-01-27,2.0,,0,0.0,7160.16,3570.75,1643.27,27,0,Residential
29
+ 2026-01-28,0.0,,0,0.0,7137.81,3559.61,1638.12,28,0,Residential
30
+ 2026-01-29,2.4,,0,0.0,6283.1,3133.37,1441.96,29,0,Residential
31
+ 2026-01-30,0.0,,0,0.0,6369.05,3176.22,1461.7,30,0,Residential
32
+ 2026-01-31,0.0,,0,0.0,6658.6,3320.67,1528.17,31,1,Residential
33
+ 2026-02-01,6.6,,0,0.0,7218.99,3600.1,1656.77,32,1,Residential
34
+ 2026-02-02,0.0,,0,0.0,6291.44,3137.57,1443.87,33,0,Residential
35
+ 2026-02-03,7.7,,0,0.0,6606.71,3294.76,1516.26,34,0,Residential
36
+ 2026-02-04,0.3,,0,0.0,6752.19,3367.34,1549.62,35,0,Residential
37
+ 2026-02-05,0.0,,0,0.0,7146.73,3564.07,1640.15,36,0,Residential
38
+ 2026-02-06,1.8,,0,0.0,7556.22,3768.31,1734.13,37,0,Residential
39
+ 2026-02-07,0.0,,0,0.0,7978.39,3978.85,1831.02,38,1,Residential
40
+ 2026-02-08,0.0,,0,0.0,8111.71,4045.32,1861.65,39,1,Residential
41
+ 2026-02-09,12.6,,0,0.0,7456.97,3718.78,1711.4,40,0,Residential
42
+ 2026-02-10,7.5,,0,0.0,7687.37,3833.69,1764.24,41,0,Residential
43
+ 2026-02-11,0.0,,0,0.0,7093.12,3537.33,1627.87,42,0,Residential
44
+ 2026-02-12,0.0,,0,0.0,7426.03,3703.37,1704.27,43,0,Residential
45
+ 2026-02-13,0.0,,0,0.0,7718.7,3849.29,1771.43,44,0,Residential
46
+ 2026-02-14,7.5,,0,0.0,7981.45,3980.38,1831.72,45,1,Residential
47
+ 2026-02-15,1.5,Imlek & Glodok Festival,1,1.1,9452.38,4713.87,2169.34,46,1,Tourism
48
+ 2026-02-16,10.6,Imlek & Glodok Festival,1,2.1,9111.38,4543.82,2091.04,47,0,Tourism
49
+ 2026-02-17,0.0,Imlek & Glodok Festival,1,2.5,9732.7,4853.68,2233.65,48,0,Tourism
50
+ 2026-02-18,2.0,Imlek & Glodok Festival,1,2.1,9232.41,4604.17,2118.86,49,0,Tourism
51
+ 2026-02-19,0.0,Imlek & Glodok Festival,1,1.1,8524.64,4251.21,1956.38,50,0,Tourism
52
+ 2026-02-20,5.6,,0,0.0,7263.55,3622.32,1666.96,51,0,Residential
53
+ 2026-02-21,0.0,,0,0.0,7444.17,3712.41,1708.47,52,1,Residential
54
+ 2026-02-22,0.0,,0,0.0,7587.61,3783.97,1741.38,53,1,Residential
55
+ 2026-02-23,0.0,,0,0.0,7355.29,3668.1,1688.03,54,0,Residential
56
+ 2026-02-24,0.0,,0,0.0,7397.25,3688.98,1697.65,55,0,Residential
57
+ 2026-02-25,0.0,,0,0.0,7244.64,3612.9,1662.63,56,0,Residential
58
+ 2026-02-26,14.6,,0,0.0,7789.3,3884.5,1787.67,57,0,Residential
59
+ 2026-02-27,1.0,,0,0.0,8017.61,3998.39,1840.07,58,0,Residential
60
+ 2026-02-28,0.0,,0,0.0,8127.5,4053.21,1865.28,59,1,Residential
61
+ 2026-03-01,0.0,,0,0.0,8481.6,4229.76,1946.51,60,1,Residential
62
+ 2026-03-02,3.1,,0,0.0,7544.19,3762.26,1731.39,61,0,Residential
63
+ 2026-03-03,0.0,,0,0.0,7880.54,3930.02,1808.61,62,0,Residential
64
+ 2026-03-04,1.2,,0,0.0,8164.99,4071.87,1873.87,63,0,Residential
65
+ 2026-03-05,0.0,,0,0.0,7823.17,3901.43,1795.44,64,0,Residential
66
+ 2026-03-06,5.4,,0,0.0,8168.94,4073.84,1874.76,65,0,Residential
67
+ 2026-03-07,14.1,,0,0.0,8973.36,4475.0,2059.39,66,1,Residential
68
+ 2026-03-08,0.0,,0,0.0,8771.98,4374.6,2013.17,67,1,Residential
69
+ 2026-03-09,0.0,,0,0.0,7453.47,3717.06,1710.57,68,0,Residential
70
+ 2026-03-10,8.3,,0,0.0,7488.29,3734.44,1718.59,69,0,Residential
71
+ 2026-03-11,0.0,,0,0.0,7230.57,3605.9,1659.45,70,0,Residential
72
+ 2026-03-12,0.0,,0,0.0,7085.67,3533.64,1626.15,71,0,Residential
73
+ 2026-03-13,0.0,,0,0.0,7235.86,3608.51,1660.66,72,0,Residential
74
+ 2026-03-14,6.0,,0,0.0,8141.95,4060.41,1868.59,73,1,Residential
75
+ 2026-03-15,0.0,,0,0.0,8508.98,4243.44,1952.82,74,1,Residential
76
+ 2026-03-16,14.5,,0,0.0,7512.04,3746.28,1724.0,75,0,Residential
77
+ 2026-03-17,16.9,,0,0.0,7513.19,3746.85,1724.26,76,0,Residential
78
+ 2026-03-18,9.8,H-3 Lebaran,1,2.7,8397.63,4187.93,1927.29,77,0,Residential
79
+ 2026-03-19,14.3,H-3 Lebaran,1,4.0,9163.91,4570.05,2103.13,78,0,Residential
80
+ 2026-03-20,9.3,Idul Fitri,1,2.3,11435.56,5702.92,2624.49,79,0,Residential
81
+ 2026-03-21,0.0,Idul Fitri,1,4.1,11952.02,5960.44,2742.97,80,1,Residential
82
+ 2026-03-22,1.5,Idul Fitri,1,5.0,13542.07,6753.4,3107.9,81,1,Residential
83
+ 2026-03-23,18.4,Idul Fitri,1,4.1,10067.32,5020.55,2310.43,82,0,Residential
84
+ 2026-03-24,0.0,Idul Fitri,1,2.3,8520.95,4249.43,1955.55,83,0,Residential
85
+ 2026-03-25,16.8,,0,0.0,8013.53,3996.36,1839.11,84,0,Residential
86
+ 2026-03-26,17.6,,0,0.0,7981.13,3980.19,1831.66,85,0,Residential
87
+ 2026-03-27,17.9,,0,0.0,8209.94,4094.28,1884.19,86,0,Residential
88
+ 2026-03-28,0.0,,0,0.0,8329.38,4153.87,1911.56,87,1,Residential
89
+ 2026-03-29,13.7,,0,0.0,8434.17,4206.14,1935.63,88,1,Residential
90
+ 2026-03-30,11.7,,0,0.0,7416.8,3698.78,1702.17,89,0,Residential
91
+ 2026-03-31,0.0,,0,0.0,6925.68,3453.86,1589.41,90,0,Residential
92
+ 2026-04-01,0.0,,0,0.0,7418.77,3699.74,1702.61,91,0,Residential
93
+ 2026-04-02,27.3,,0,0.0,7297.42,3639.19,1674.79,92,0,Residential
94
+ 2026-04-03,0.0,,0,0.0,7534.07,3757.23,1729.1,93,0,Residential
95
+ 2026-04-04,9.7,,0,0.0,8216.63,4097.65,1885.71,94,1,Residential
96
+ 2026-04-05,0.0,,0,0.0,8131.06,4054.93,1866.1,95,1,Residential
97
+ 2026-04-06,0.0,,0,0.0,7687.88,3833.95,1764.37,96,0,Residential
98
+ 2026-04-07,24.4,,0,0.0,7778.23,3879.02,1785.12,97,0,Residential
99
+ 2026-04-08,12.3,,0,0.0,7871.05,3925.31,1806.39,98,0,Residential
100
+ 2026-04-09,0.0,Jakarta Art Festival,1,1.4,9156.97,4566.61,2101.54,99,0,Tourism
101
+ 2026-04-10,14.8,Jakarta Art Festival,1,2.0,10019.38,4996.67,2299.48,100,0,Tourism
102
+ 2026-04-11,9.0,Jakarta Art Festival,1,1.4,9610.08,4792.56,2205.51,101,1,Tourism
103
+ 2026-04-12,0.0,,0,0.0,8165.19,4071.99,1873.94,102,1,Residential
104
+ 2026-04-13,11.8,,0,0.0,7750.09,3864.95,1778.63,103,0,Residential
105
+ 2026-04-14,27.3,,0,0.0,7604.99,3792.63,1745.33,104,0,Residential
106
+ 2026-04-15,0.0,,0,0.0,7592.26,3786.26,1742.4,105,0,Residential
107
+ 2026-04-16,0.0,,0,0.0,7832.79,3906.21,1797.6,106,0,Residential
108
+ 2026-04-17,13.1,,0,0.0,7876.46,3927.98,1807.66,107,0,Residential
109
+ 2026-04-18,12.4,,0,0.0,8590.54,4284.13,1971.53,108,1,Residential
110
+ 2026-04-19,0.0,,0,0.0,9138.19,4557.19,2097.21,109,1,Residential
111
+ 2026-04-20,0.0,,0,0.0,8558.26,4268.02,1964.15,110,0,Residential
112
+ 2026-04-21,7.2,,0,0.0,8501.72,4239.82,1951.16,111,0,Residential
113
+ 2026-04-22,24.3,,0,0.0,8328.36,4153.36,1911.37,112,0,Residential
114
+ 2026-04-23,0.0,,0,0.0,8674.83,4326.15,1990.89,113,0,Residential
115
+ 2026-04-24,0.0,,0,0.0,8388.97,4183.6,1925.25,114,0,Residential
116
+ 2026-04-25,23.4,,0,0.0,8953.56,4465.13,2054.87,115,1,Residential
117
+ 2026-04-26,0.0,,0,0.0,8393.43,4185.83,1926.27,116,1,Residential
118
+ 2026-04-27,0.0,,0,0.0,7483.14,3731.83,1717.38,117,0,Residential
119
+ 2026-04-28,37.7,,0,0.0,7999.59,3989.42,1835.93,118,0,Residential
120
+ 2026-04-29,14.3,,0,0.0,7500.07,3740.29,1721.26,119,0,Residential
121
+ 2026-04-30,0.0,May Day Rally,1,1.4,9399.66,4687.64,2157.25,120,0,Tourism
122
+ 2026-05-01,14.5,May Day Rally,1,3.0,10756.51,5364.28,2468.64,121,0,Tourism
123
+ 2026-05-02,13.4,May Day Rally,1,1.4,9989.46,4981.77,2292.6,122,1,Tourism
124
+ 2026-05-03,10.0,,0,0.0,8153.22,4066.01,1871.13,123,1,Residential
125
+ 2026-05-04,0.0,,0,0.0,7432.01,3706.36,1705.67,124,0,Residential
126
+ 2026-05-05,26.7,,0,0.0,7717.62,3848.78,1771.18,125,0,Residential
127
+ 2026-05-06,0.0,,0,0.0,7578.32,3779.32,1739.22,126,0,Residential
128
+ 2026-05-07,0.0,,0,0.0,7633.58,3806.89,1751.89,127,0,Residential
129
+ 2026-05-08,30.7,,0,0.0,8339.88,4159.09,1913.98,128,0,Residential
130
+ 2026-05-09,30.6,,0,0.0,8813.11,4395.1,2022.59,129,1,Residential
131
+ 2026-05-10,35.5,,0,0.0,8578.25,4277.95,1968.73,130,1,Residential
132
+ 2026-05-11,30.4,,0,0.0,7581.37,3780.85,1739.92,131,0,Residential
133
+ 2026-05-12,18.5,,0,0.0,8186.39,4082.56,1878.77,132,0,Residential
134
+ 2026-05-13,27.4,,0,0.0,7572.46,3776.39,1737.88,133,0,Residential
135
+ 2026-05-14,23.7,,0,0.0,7563.54,3771.94,1735.84,134,0,Residential
136
+ 2026-05-15,0.0,,0,0.0,7966.36,3972.8,1828.29,135,0,Residential
137
+ 2026-05-16,0.0,,0,0.0,7577.74,3779.0,1739.09,136,1,Residential
138
+ 2026-05-17,0.0,,0,0.0,8524.32,4251.08,1956.32,137,1,Residential
139
+ 2026-05-18,23.7,,0,0.0,8206.0,4092.3,1883.29,138,0,Residential
140
+ 2026-05-19,0.0,,0,0.0,7848.96,3914.29,1801.36,139,0,Residential
141
+ 2026-05-20,34.7,,0,0.0,8099.55,4039.27,1858.85,140,0,Residential
142
+ 2026-05-21,21.7,,0,0.0,7783.13,3881.44,1786.2,141,0,Residential
143
+ 2026-05-22,0.0,,0,0.0,7896.77,3938.1,1812.31,142,0,Residential
144
+ 2026-05-23,32.7,,0,0.0,8439.97,4209.0,1936.96,143,1,Residential
145
+ 2026-05-24,0.0,,0,0.0,8052.82,4015.97,1848.15,144,1,Residential
146
+ 2026-05-25,9.7,,0,0.0,7765.87,3872.85,1782.26,145,0,Residential
147
+ 2026-05-26,30.3,,0,0.0,7740.09,3859.99,1776.34,146,0,Residential
148
+ 2026-05-27,25.1,,0,0.0,7961.39,3970.32,1827.14,147,0,Residential
149
+ 2026-05-28,19.0,,0,0.0,8084.33,4031.63,1855.34,148,0,Residential
150
+ 2026-05-29,36.3,PRJ Opening,1,2.3,11391.63,5681.01,2614.37,149,0,Tourism
151
+ 2026-05-30,11.0,PRJ Opening,1,3.1,12697.35,6332.19,2914.04,150,1,Tourism
152
+ 2026-05-31,0.0,PRJ Opening,1,3.8,13655.46,6810.0,3133.94,151,1,Tourism
153
+ 2026-06-01,19.9,PRJ Opening,1,4.0,13501.26,6733.09,3098.54,152,0,Tourism
154
+ 2026-06-02,0.0,PRJ Opening,1,3.8,11811.45,5890.35,2710.76,153,0,Tourism
155
+ 2026-06-03,24.2,PRJ Opening,1,3.1,10222.61,5098.03,2346.08,154,0,Tourism
156
+ 2026-06-04,0.0,PRJ Opening,1,2.3,9903.64,4938.93,2272.86,155,0,Tourism
157
+ 2026-06-05,15.3,,0,0.0,8585.95,4281.83,1970.45,156,0,Residential
158
+ 2026-06-06,0.0,,0,0.0,8986.15,4481.43,2062.32,157,1,Residential
159
+ 2026-06-07,15.3,,0,0.0,9490.77,4733.03,2178.13,158,1,Residential
160
+ 2026-06-08,25.0,,0,0.0,8704.43,4340.92,1997.64,159,0,Residential
161
+ 2026-06-09,0.0,,0,0.0,8657.45,4317.49,1986.88,160,0,Residential
162
+ 2026-06-10,17.8,,0,0.0,8432.26,4205.18,1935.18,161,0,Residential
163
+ 2026-06-11,32.6,,0,0.0,8389.48,4183.85,1925.38,162,0,Residential
164
+ 2026-06-12,25.4,,0,0.0,8452.13,4215.05,1939.77,163,0,Residential
165
+ 2026-06-13,39.8,,0,0.0,8446.72,4212.38,1938.49,164,1,Residential
166
+ 2026-06-14,0.0,Music Festival GBK,1,1.6,10840.61,5406.23,2487.93,165,1,Tourism
167
+ 2026-06-15,29.6,Music Festival GBK,1,3.5,11550.99,5760.47,2650.97,166,0,Tourism
168
+ 2026-06-16,33.7,Music Festival GBK,1,1.6,10760.71,5366.38,2469.59,167,0,Tourism
169
+ 2026-06-17,0.0,,0,0.0,7506.63,3743.54,1722.79,168,0,Residential
170
+ 2026-06-18,35.9,,0,0.0,8177.22,4077.98,1876.67,169,0,Residential
171
+ 2026-06-19,22.7,,0,0.0,8766.0,4371.6,2011.77,170,0,Residential
172
+ 2026-06-20,33.8,,0,0.0,9476.76,4726.03,2174.95,171,1,Residential
173
+ 2026-06-21,34.9,,0,0.0,9540.36,4757.8,2189.53,172,1,Residential
174
+ 2026-06-22,0.0,,0,0.0,7977.69,3978.47,1830.9,173,0,Residential
175
+ 2026-06-23,27.4,,0,0.0,8166.46,4072.63,1874.19,174,0,Residential
176
+ 2026-06-24,0.0,,0,0.0,8627.21,4302.4,1979.94,175,0,Residential
177
+ 2026-06-25,0.0,,0,0.0,9066.69,4521.54,2080.78,176,0,Residential
178
+ 2026-06-26,36.1,,0,0.0,8895.24,4436.03,2041.44,177,0,Residential
179
+ 2026-06-27,0.0,,0,0.0,8390.69,4184.43,1925.63,178,1,Residential
180
+ 2026-06-28,26.9,,0,0.0,8999.14,4487.86,2065.31,179,1,Residential
181
+ 2026-06-29,34.7,,0,0.0,8766.7,4371.92,2011.96,180,0,Residential
182
+ 2026-06-30,0.0,,0,0.0,8151.56,4065.18,1870.75,181,0,Residential
183
+ 2026-07-01,26.6,,0,0.0,8212.36,4095.49,1884.76,182,0,Residential
184
+ 2026-07-02,0.0,,0,0.0,7916.06,3947.72,1816.76,183,0,Residential
185
+ 2026-07-03,8.4,,0,0.0,8135.14,4056.97,1867.0,184,0,Residential
186
+ 2026-07-04,0.0,,0,0.0,8597.09,4287.37,1973.06,185,1,Residential
187
+ 2026-07-05,12.2,,0,0.0,8921.66,4449.21,2047.55,186,1,Residential
188
+ 2026-07-06,0.0,,0,0.0,7477.85,3729.22,1716.17,187,0,Residential
189
+ 2026-07-07,0.0,,0,0.0,8116.29,4047.61,1862.67,188,0,Residential
190
+ 2026-07-08,31.3,,0,0.0,8471.1,4224.54,1944.09,189,0,Residential
191
+ 2026-07-09,0.0,,0,0.0,7607.98,3794.09,1746.03,190,0,Residential
192
+ 2026-07-10,38.5,,0,0.0,7636.31,3808.23,1752.52,191,0,Residential
193
+ 2026-07-11,22.5,,0,0.0,8258.07,4118.28,1895.2,192,1,Residential
194
+ 2026-07-12,28.0,,0,0.0,9244.25,4610.09,2121.53,193,1,Residential
195
+ 2026-07-13,31.1,,0,0.0,8592.25,4284.95,1971.92,194,0,Residential
196
+ 2026-07-14,23.2,,0,0.0,7897.47,3938.49,1812.5,195,0,Residential
197
+ 2026-07-15,45.0,,0,0.0,8390.05,4184.11,1925.5,196,0,Residential
198
+ 2026-07-16,27.6,,0,0.0,7422.84,3701.78,1703.57,197,0,Residential
199
+ 2026-07-17,30.6,,0,0.0,7504.72,3742.59,1722.35,198,0,Residential
200
+ 2026-07-18,40.0,,0,0.0,8137.75,4058.3,1867.63,199,1,Residential
201
+ 2026-07-19,35.9,PRJ Peak Weekend,1,3.5,13004.03,6485.11,2984.46,200,1,Tourism
202
+ 2026-07-20,0.0,PRJ Peak Weekend,1,5.0,12972.01,6469.13,2977.07,201,0,Tourism
203
+ 2026-07-21,21.0,PRJ Peak Weekend,1,3.5,12044.08,6006.41,2764.11,202,0,Tourism
204
+ 2026-07-22,0.0,,0,0.0,8054.98,4017.05,1848.6,203,0,Residential
205
+ 2026-07-23,32.4,,0,0.0,7708.58,3844.26,1769.14,204,0,Residential
206
+ 2026-07-24,22.5,,0,0.0,7856.34,3917.99,1803.01,205,0,Residential
207
+ 2026-07-25,0.0,,0,0.0,8448.75,4213.39,1939.0,206,1,Residential
208
+ 2026-07-26,28.6,,0,0.0,8958.65,4467.67,2056.02,207,1,Residential
209
+ 2026-07-27,25.7,,0,0.0,7889.9,3934.67,1810.72,208,0,Residential
210
+ 2026-07-28,0.0,,0,0.0,7507.2,3743.86,1722.92,209,0,Residential
211
+ 2026-07-29,18.4,,0,0.0,7928.22,3953.83,1819.5,210,0,Residential
212
+ 2026-07-30,19.8,,0,0.0,7951.84,3965.61,1824.98,211,0,Residential
213
+ 2026-07-31,30.9,,0,0.0,8010.92,3995.02,1838.54,212,0,Residential
214
+ 2026-08-01,0.0,,0,0.0,7775.49,3877.62,1784.48,213,1,Residential
215
+ 2026-08-02,0.0,,0,0.0,8192.31,4085.49,1880.11,214,1,Residential
216
+ 2026-08-03,17.8,,0,0.0,7753.78,3866.8,1779.52,215,0,Residential
217
+ 2026-08-04,0.0,,0,0.0,8056.13,4017.62,1848.85,216,0,Residential
218
+ 2026-08-05,0.0,,0,0.0,8223.44,4101.02,1887.31,217,0,Residential
219
+ 2026-08-06,19.7,,0,0.0,7867.74,3923.65,1805.62,218,0,Residential
220
+ 2026-08-07,23.8,,0,0.0,7822.54,3901.11,1795.24,219,0,Residential
221
+ 2026-08-08,0.0,,0,0.0,8441.62,4209.83,1937.35,220,1,Residential
222
+ 2026-08-09,18.4,,0,0.0,8874.36,4425.66,2036.66,221,1,Residential
223
+ 2026-08-10,27.2,,0,0.0,7455.82,3718.2,1711.14,222,0,Residential
224
+ 2026-08-11,0.0,,0,0.0,7371.02,3675.93,1691.66,223,0,Residential
225
+ 2026-08-12,26.1,,0,0.0,7094.97,3538.28,1628.31,224,0,Residential
226
+ 2026-08-13,43.9,,0,0.0,7664.07,3822.1,1758.89,225,0,Residential
227
+ 2026-08-14,25.7,,0,0.0,7594.68,3787.47,1742.97,226,0,Residential
228
+ 2026-08-15,26.2,HUT RI ke-81,1,1.8,10750.01,5361.03,2467.11,227,1,Tourism
229
+ 2026-08-16,0.0,HUT RI ke-81,1,3.3,11802.28,5885.83,2708.59,228,1,Tourism
230
+ 2026-08-17,15.6,HUT RI ke-81,1,4.0,11523.1,5746.59,2644.54,229,0,Tourism
231
+ 2026-08-18,0.0,HUT RI ke-81,1,3.3,11089.09,5530.13,2544.97,230,0,Tourism
232
+ 2026-08-19,30.2,HUT RI ke-81,1,1.8,9856.4,4915.37,2262.04,231,0,Tourism
233
+ 2026-08-20,0.0,,0,0.0,6569.91,3276.43,1507.79,232,0,Residential
234
+ 2026-08-21,25.9,,0,0.0,7090.57,3536.05,1627.29,233,0,Residential
235
+ 2026-08-22,0.0,,0,0.0,7713.03,3846.49,1770.16,234,1,Residential
236
+ 2026-08-23,24.6,,0,0.0,8301.11,4139.73,1905.13,235,1,Residential
237
+ 2026-08-24,0.0,,0,0.0,7185.12,3583.23,1649.0,236,0,Residential
238
+ 2026-08-25,19.5,,0,0.0,7365.42,3673.13,1690.39,237,0,Residential
239
+ 2026-08-26,17.1,,0,0.0,7628.74,3804.47,1750.81,238,0,Residential
240
+ 2026-08-27,0.0,,0,0.0,7610.02,3795.11,1746.48,239,0,Residential
241
+ 2026-08-28,21.4,,0,0.0,7527.64,3754.05,1727.57,240,0,Residential
242
+ 2026-08-29,9.5,,0,0.0,7719.46,3849.67,1771.62,241,1,Residential
243
+ 2026-08-30,9.3,,0,0.0,8029.51,4004.32,1842.8,242,1,Residential
244
+ 2026-08-31,0.0,,0,0.0,7398.46,3689.62,1697.96,243,0,Residential
245
+ 2026-09-01,0.0,,0,0.0,7371.53,3676.18,1691.79,244,0,Residential
246
+ 2026-09-02,9.1,,0,0.0,6879.27,3430.69,1578.78,245,0,Residential
247
+ 2026-09-03,0.0,,0,0.0,6966.87,3474.36,1598.9,246,0,Residential
248
+ 2026-09-04,16.4,,0,0.0,6957.07,3469.46,1596.67,247,0,Residential
249
+ 2026-09-05,10.4,,0,0.0,6286.48,3135.09,1442.73,248,1,Residential
250
+ 2026-09-06,11.4,,0,0.0,6971.71,3476.78,1599.98,249,1,Residential
251
+ 2026-09-07,31.2,,0,0.0,7328.3,3654.6,1681.86,250,0,Residential
252
+ 2026-09-08,18.6,,0,0.0,7352.11,3666.51,1687.33,251,0,Residential
253
+ 2026-09-09,17.1,,0,0.0,6943.57,3462.78,1593.55,252,0,Residential
254
+ 2026-09-10,16.4,,0,0.0,7374.97,3677.9,1692.55,253,0,Residential
255
+ 2026-09-11,19.9,,0,0.0,7336.19,3658.55,1683.64,254,0,Residential
256
+ 2026-09-12,0.0,,0,0.0,7906.32,3942.88,1814.47,255,1,Residential
257
+ 2026-09-13,0.0,,0,0.0,8701.51,4339.45,1997.0,256,1,Residential
258
+ 2026-09-14,23.7,Food & Culture Expo,1,1.8,10098.71,5036.21,2317.68,257,0,Tourism
259
+ 2026-09-15,10.9,Food & Culture Expo,1,2.5,9707.17,4840.95,2227.79,258,0,Tourism
260
+ 2026-09-16,19.9,Food & Culture Expo,1,1.8,10204.4,5088.92,2341.88,259,0,Tourism
261
+ 2026-09-17,9.2,,0,0.0,7121.0,3551.27,1634.3,260,0,Residential
262
+ 2026-09-18,0.0,,0,0.0,7224.59,3602.9,1658.04,261,0,Residential
263
+ 2026-09-19,2.9,,0,0.0,7329.38,3655.17,1682.11,262,1,Residential
264
+ 2026-09-20,0.0,,0,0.0,8056.7,4017.88,1849.04,263,1,Residential
265
+ 2026-09-21,14.8,,0,0.0,7839.47,3909.52,1799.13,264,0,Residential
266
+ 2026-09-22,19.1,,0,0.0,7823.75,3901.69,1795.56,265,0,Residential
267
+ 2026-09-23,12.5,,0,0.0,7417.37,3699.04,1702.29,266,0,Residential
268
+ 2026-09-24,11.3,,0,0.0,7197.98,3589.66,1651.93,267,0,Residential
269
+ 2026-09-25,5.2,,0,0.0,7461.81,3721.19,1712.48,268,0,Residential
270
+ 2026-09-26,10.0,,0,0.0,7819.29,3899.46,1794.54,269,1,Residential
271
+ 2026-09-27,0.0,,0,0.0,7821.2,3900.41,1794.99,270,1,Residential
272
+ 2026-09-28,0.0,,0,0.0,6852.91,3417.57,1572.73,271,0,Residential
273
+ 2026-09-29,0.0,,0,0.0,6928.1,3455.07,1589.99,272,0,Residential
274
+ 2026-09-30,13.5,,0,0.0,6827.25,3404.78,1566.88,273,0,Residential
275
+ 2026-10-01,0.0,,0,0.0,7381.65,3681.21,1694.08,274,0,Residential
276
+ 2026-10-02,8.7,,0,0.0,6760.28,3371.35,1551.47,275,0,Residential
277
+ 2026-10-03,0.0,,0,0.0,6897.92,3439.98,1583.05,276,1,Residential
278
+ 2026-10-04,0.0,,0,0.0,6596.02,3289.41,1513.78,277,1,Residential
279
+ 2026-10-05,1.6,,0,0.0,6116.62,3050.35,1403.76,278,0,Residential
280
+ 2026-10-06,0.0,,0,0.0,6180.85,3082.37,1418.53,279,0,Residential
281
+ 2026-10-07,0.0,,0,0.0,6559.03,3271.01,1505.31,280,0,Residential
282
+ 2026-10-08,7.8,,0,0.0,6692.85,3337.74,1536.0,281,0,Residential
283
+ 2026-10-09,12.6,Jakarta Marathon,1,1.4,8070.9,4024.94,1852.29,282,0,Tourism
284
+ 2026-10-10,0.0,Jakarta Marathon,1,3.0,10133.92,5053.78,2325.71,283,1,Tourism
285
+ 2026-10-11,0.0,Jakarta Marathon,1,1.4,9422.58,4699.04,2162.47,284,1,Tourism
286
+ 2026-10-12,0.0,,0,0.0,7349.37,3665.11,1686.69,285,0,Residential
287
+ 2026-10-13,23.0,,0,0.0,7244.83,3613.03,1662.69,286,0,Residential
288
+ 2026-10-14,0.0,,0,0.0,7684.89,3832.48,1763.67,287,0,Residential
289
+ 2026-10-15,13.0,,0,0.0,7634.91,3807.53,1752.21,288,0,Residential
290
+ 2026-10-16,4.8,,0,0.0,7475.3,3727.94,1715.6,289,0,Residential
291
+ 2026-10-17,0.0,,0,0.0,7705.46,3842.73,1768.38,290,1,Residential
292
+ 2026-10-18,0.0,,0,0.0,7695.27,3837.64,1766.09,291,1,Residential
293
+ 2026-10-19,0.0,,0,0.0,6580.04,3281.46,1510.15,292,0,Residential
294
+ 2026-10-20,0.0,,0,0.0,6397.19,3190.29,1468.13,293,0,Residential
295
+ 2026-10-21,9.6,,0,0.0,6957.96,3469.91,1596.86,294,0,Residential
296
+ 2026-10-22,16.8,,0,0.0,7291.88,3636.46,1673.52,295,0,Residential
297
+ 2026-10-23,0.0,,0,0.0,6776.96,3379.69,1555.29,296,0,Residential
298
+ 2026-10-24,0.0,,0,0.0,6992.78,3487.29,1604.82,297,1,Residential
299
+ 2026-10-25,16.6,,0,0.0,7481.29,3730.94,1716.94,298,1,Residential
300
+ 2026-10-26,0.0,,0,0.0,6848.32,3415.28,1571.71,299,0,Residential
301
+ 2026-10-27,0.0,,0,0.0,6923.51,3452.78,1588.97,300,0,Residential
302
+ 2026-10-28,0.0,,0,0.0,7173.15,3577.25,1646.27,301,0,Residential
303
+ 2026-10-29,0.0,,0,0.0,6833.05,3407.64,1568.21,302,0,Residential
304
+ 2026-10-30,0.0,,0,0.0,6827.89,3405.09,1567.0,303,0,Residential
305
+ 2026-10-31,0.0,,0,0.0,6946.05,3463.99,1594.12,304,1,Residential
306
+ 2026-11-01,0.0,,0,0.0,7255.08,3618.12,1665.05,305,1,Residential
307
+ 2026-11-02,0.0,,0,0.0,7022.26,3501.99,1611.63,306,0,Residential
308
+ 2026-11-03,0.7,,0,0.0,6768.49,3375.43,1553.38,307,0,Residential
309
+ 2026-11-04,0.0,,0,0.0,6235.67,3109.75,1431.08,308,0,Residential
310
+ 2026-11-05,0.0,,0,0.0,6639.57,3311.12,1523.77,309,0,Residential
311
+ 2026-11-06,0.0,,0,0.0,6936.25,3459.08,1591.9,310,0,Residential
312
+ 2026-11-07,0.0,,0,0.0,7039.26,3510.46,1615.52,311,1,Residential
313
+ 2026-11-08,7.0,,0,0.0,7520.12,3750.29,1725.85,312,1,Residential
314
+ 2026-11-09,0.0,,0,0.0,7251.65,3616.4,1664.28,313,0,Residential
315
+ 2026-11-10,2.8,,0,0.0,7445.19,3712.92,1708.66,314,0,Residential
316
+ 2026-11-11,0.0,,0,0.0,7289.4,3635.25,1672.94,315,0,Residential
317
+ 2026-11-12,5.1,,0,0.0,6958.34,3470.1,1596.93,316,0,Residential
318
+ 2026-11-13,0.0,,0,0.0,6896.58,3439.35,1582.79,317,0,Residential
319
+ 2026-11-14,0.0,,0,0.0,7198.61,3589.98,1652.06,318,1,Residential
320
+ 2026-11-15,0.0,,0,0.0,7051.16,3516.45,1618.25,319,1,Residential
321
+ 2026-11-16,0.0,,0,0.0,5837.63,2911.24,1339.72,320,0,Residential
322
+ 2026-11-17,0.0,,0,0.0,6079.69,3031.95,1395.3,321,0,Residential
323
+ 2026-11-18,0.0,,0,0.0,6157.11,3070.53,1413.06,322,0,Residential
324
+ 2026-11-19,1.2,,0,0.0,6557.95,3270.44,1505.06,323,0,Residential
325
+ 2026-11-20,0.0,,0,0.0,6717.3,3349.9,1541.6,324,0,Residential
326
+ 2026-11-21,0.0,,0,0.0,7202.82,3592.02,1653.02,325,1,Residential
327
+ 2026-11-22,1.3,,0,0.0,7308.75,3644.86,1677.34,326,1,Residential
328
+ 2026-11-23,0.0,,0,0.0,6689.99,3336.27,1535.36,327,0,Residential
329
+ 2026-11-24,0.0,Ancol Music Fest,1,1.4,8450.6,4214.29,1939.38,328,0,Tourism
330
+ 2026-11-25,9.1,Ancol Music Fest,1,3.0,9757.02,4865.84,2239.25,329,0,Tourism
331
+ 2026-11-26,0.7,Ancol Music Fest,1,1.4,8884.61,4430.75,2039.02,330,0,Tourism
332
+ 2026-11-27,0.0,,0,0.0,6791.98,3387.14,1558.79,331,0,Residential
333
+ 2026-11-28,5.7,,0,0.0,6811.53,3396.88,1563.25,332,1,Residential
334
+ 2026-11-29,0.0,,0,0.0,7268.26,3624.68,1668.04,333,1,Residential
335
+ 2026-11-30,0.0,,0,0.0,6687.25,3334.93,1534.72,334,0,Residential
336
+ 2026-12-01,0.0,,0,0.0,6761.23,3371.8,1551.72,335,0,Residential
337
+ 2026-12-02,0.0,,0,0.0,6670.25,3326.47,1530.84,336,0,Residential
338
+ 2026-12-03,0.0,,0,0.0,6817.77,3400.0,1564.65,337,0,Residential
339
+ 2026-12-04,6.5,,0,0.0,6994.95,3488.37,1605.33,338,0,Residential
340
+ 2026-12-05,0.0,,0,0.0,7380.06,3680.45,1693.7,339,1,Residential
341
+ 2026-12-06,1.0,,0,0.0,7445.57,3713.11,1708.79,340,1,Residential
342
+ 2026-12-07,0.0,,0,0.0,6471.04,3227.09,1485.13,341,0,Residential
343
+ 2026-12-08,11.3,,0,0.0,6396.74,3190.03,1468.07,342,0,Residential
344
+ 2026-12-09,0.0,,0,0.0,6704.82,3343.72,1538.74,343,0,Residential
345
+ 2026-12-10,0.0,,0,0.0,7055.81,3518.74,1619.34,344,0,Residential
346
+ 2026-12-11,0.0,,0,0.0,6528.72,3255.86,1498.37,345,0,Residential
347
+ 2026-12-12,11.7,,0,0.0,6873.09,3427.63,1577.38,346,1,Residential
348
+ 2026-12-13,0.0,,0,0.0,7460.72,3720.69,1712.22,347,1,Residential
349
+ 2026-12-14,0.0,,0,0.0,7066.32,3523.96,1621.69,348,0,Residential
350
+ 2026-12-15,0.0,,0,0.0,7146.85,3564.13,1640.22,349,0,Residential
351
+ 2026-12-16,0.0,,0,0.0,7439.65,3710.18,1707.39,350,0,Residential
352
+ 2026-12-17,0.0,,0,0.0,7663.37,3821.72,1758.76,351,0,Residential
353
+ 2026-12-18,3.4,Christmas Market,1,2.1,9204.27,4590.17,2112.36,352,0,Tourism
354
+ 2026-12-19,0.0,Christmas Market,1,3.1,9926.37,4950.26,2278.08,353,1,Tourism
355
+ 2026-12-20,0.0,Christmas Market,1,3.5,10875.94,5423.81,2496.01,354,1,Tourism
356
+ 2026-12-21,7.5,Christmas Market,1,3.1,9277.42,4626.65,2129.17,355,0,Tourism
357
+ 2026-12-22,5.1,Christmas Market,1,2.1,8982.27,4479.45,2061.43,356,0,Tourism
358
+ 2026-12-23,7.3,,0,0.0,7457.73,3719.16,1711.52,357,0,Residential
359
+ 2026-12-24,0.0,,0,0.0,7214.85,3598.07,1655.82,358,0,Residential
360
+ 2026-12-25,2.9,,0,0.0,7154.49,3567.95,1641.94,359,0,Residential
361
+ 2026-12-26,0.0,,0,0.0,7624.6,3802.37,1749.85,360,1,Residential
362
+ 2026-12-27,0.0,,0,0.0,7631.54,3805.87,1751.44,361,1,Residential
363
+ 2026-12-28,0.0,,0,0.0,6686.42,3334.49,1534.53,362,0,Residential
364
+ 2026-12-29,0.0,,0,0.0,7274.12,3627.61,1669.44,363,0,Residential
365
+ 2026-12-30,0.0,Countdown Jakarta 2027,1,3.2,10452.95,5212.88,2398.92,364,0,Tourism
366
+ 2026-12-31,10.7,Countdown Jakarta 2027,1,4.5,11181.92,5576.41,2566.24,365,0,Tourism
latest_waste_news.json ADDED
@@ -0,0 +1,86 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [
2
+ {
3
+ "title": "DKI Uji Coba Penarikan Retribusi Sampah Pelayanan Kebersihan Harian",
4
+ "source": "Antara News",
5
+ "url": "https://www.antaranews.com/tag/sampah-jakarta",
6
+ "date_fetched": "2026-07-10",
7
+ "summary": "Pemprov DKI Jakarta merencanakan uji coba penarikan retribusi pelayanan kebersihan/sampah berdasarkan golongan daya listrik rumah tangga. Info terbaru dapat dipantau di kanal topik khusus Antara."
8
+ },
9
+ {
10
+ "title": "Darurat Sampah Jakarta: Evaluasi Pengolahan Sampah Hulu dan Hilir",
11
+ "source": "Kompas.com",
12
+ "url": "https://www.kompas.com/tag/sampah-jakarta",
13
+ "date_fetched": "2026-07-10",
14
+ "summary": "Analisis timbulan sampah tahunan DKI Jakarta dan kebijakan pemilahan sampah mandiri dari tingkat RT/RW dan pengelola kawasan komersial terpantau di Kompas."
15
+ },
16
+ {
17
+ "title": "Dinas Lingkungan Hidup DKI Jakarta Antisipasi Penumpukan Sampah",
18
+ "source": "Detik.com",
19
+ "url": "https://www.detik.com/tag/sampah-jakarta",
20
+ "date_fetched": "2026-07-10",
21
+ "summary": "Langkah mitigasi penumpukan sampah di tempat penampungan sementara (TPS) pasar tradisional dan pengerahan armada truk pengangkut sampah dapat dilihat di Detik."
22
+ },
23
+ {
24
+ "title": "Kondisi TPST Bantargebang Terkini: Kapasitas Tampung Maksimal",
25
+ "source": "Antara News",
26
+ "url": "https://www.antaranews.com/tag/tpst-bantargebang",
27
+ "date_fetched": "2026-07-10",
28
+ "summary": "Perkembangan kapasitas TPST Bantargebang dan regulasi pembatasan sampah residu dari Jakarta menuju TPA Bekasi dipantau secara langsung di topik Antara."
29
+ },
30
+ {
31
+ "title": "Pembangunan Fasilitas RDF (Refuse Derived Fuel) Terbesar di Bantargebang Selesai",
32
+ "source": "Antara News",
33
+ "url": "https://www.antaranews.com/tag/tpst-bantargebang",
34
+ "date_fetched": "2026-07-10",
35
+ "summary": "Fasilitas RDF baru di TPST Bantargebang mampu mengolah ribuan ton sampah menjadi bahan bakar alternatif setara batu bara untuk pabrik semen. Ini merupakan pencapaian strategis DLH."
36
+ },
37
+ {
38
+ "title": "DPRD DKI Minta Pembangunan ITF Sunter Tetap Dilanjutkan untuk Atasi Sampah",
39
+ "source": "Kompas.com",
40
+ "url": "https://www.kompas.com/tag/sampah-jakarta",
41
+ "date_fetched": "2026-07-10",
42
+ "summary": "Dewan Perwakilan Rakyat Daerah (DPRD) DKI Jakarta meminta agar proyek pembangunan Intermediate Treatment Facility (ITF) Sunter tetap menjadi prioritas utama demi mengurangi beban harian Bantargebang."
43
+ },
44
+ {
45
+ "title": "Penerapan Perda Larangan Kantong Plastik Sekali Pakai di Pasar Rakyat Diperketat",
46
+ "source": "Detik.com",
47
+ "url": "https://www.detik.com/tag/sampah-jakarta",
48
+ "date_fetched": "2026-07-10",
49
+ "summary": "Petugas Satpol PP dan DLH DKI melakukan inspeksi mendadak di beberapa pasar tradisional untuk memastikan pedagang dan pembeli beralih ke kantong belanja ramah lingkungan."
50
+ },
51
+ {
52
+ "title": "TPS 3R Pejaten Barat Sukses Kurangi Sampah Hingga 15 Ton per Hari",
53
+ "source": "Kompas.com",
54
+ "url": "https://www.kompas.com/tag/sampah-jakarta",
55
+ "date_fetched": "2026-07-10",
56
+ "summary": "Fasilitas Tempat Pengolahan Sampah 3R di Pejaten Barat Jakarta Selatan mencatatkan keberhasilan besar dalam mereduksi volume sampah organik melalui program pengomposan mandiri."
57
+ },
58
+ {
59
+ "title": "Wacana Pembuatan Pulau Sampah di Kepulauan Seribu Menimbulkan Pro-Kontra",
60
+ "source": "Kompas.com",
61
+ "url": "https://www.kompas.com/tag/sampah-jakarta",
62
+ "date_fetched": "2026-07-10",
63
+ "summary": "Pemerintah Provinsi DKI menggulirkan rencana reklamasi pulau berbasis material sampah non-organik terkompresi di kawasan laut utara. WALHI meminta studi amdal diperketat."
64
+ },
65
+ {
66
+ "title": "Gerakan Sedekah Sampah Berbasis Masjid Mulai Dikembangkan di Jakarta Pusat",
67
+ "source": "Detik.com",
68
+ "url": "https://www.detik.com/tag/sampah-jakarta",
69
+ "date_fetched": "2026-07-10",
70
+ "summary": "Dewan Masjid Indonesia (DMI) DKI Jakarta meluncurkan wadah sedekah sampah di mana jamaah mengumpulkan botol plastik bekas untuk didaur ulang guna mendukung kas operasional sosial masjid."
71
+ },
72
+ {
73
+ "title": "Aplikasi Bank Sampah Digital Diadopsi Luas Warga Jakarta Barat",
74
+ "source": "Antara News",
75
+ "url": "https://www.antaranews.com/tag/sampah-jakarta",
76
+ "date_fetched": "2026-07-10",
77
+ "summary": "Warga kini dapat menyetor sampah rumah tangga yang sudah dipilah langsung lewat aplikasi seluler dan mencairkan hasilnya ke saldo e-wallet secara instan."
78
+ },
79
+ {
80
+ "title": "Komunitas Eco-Enzyme Jakarta Selatan Olah Sampah Buah Menjadi Cairan Pembersih",
81
+ "source": "Kompas.com",
82
+ "url": "https://www.kompas.com/tag/sampah-jakarta",
83
+ "date_fetched": "2026-07-10",
84
+ "summary": "Ibu-ibu Pemberdayaan Kesejahteraan Keluarga (PKK) di Jakarta Selatan secara rutin mengumpulkan limbah kulit buah dari pedagang pasar untuk dirubah menjadi eco-enzyme multiguna."
85
+ }
86
+ ]
model_sampah_advanced.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:5711ef9b09434b47c83f128a5d048bf1503cfd9746716355f01ebefbeef2bfb2
3
+ size 143833
requirements.txt CHANGED
@@ -11,4 +11,5 @@ torch
11
  transformers
12
  chronos-forecasting
13
  scikit-learn
14
- joblib
 
 
11
  transformers
12
  chronos-forecasting
13
  scikit-learn
14
+ joblib
15
+ httpx
static/app.js ADDED
@@ -0,0 +1,863 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Coordinates and Map Data for all 44 Kecamatan of DKI Jakarta
2
+ const KECAMATAN_DATABASE = {
3
+ // 1. JAKARTA PUSAT (8 Kecamatan)
4
+ "Menteng": {coords: [-6.1950, 106.8322], city: "Jakarta Pusat", radius: "1.2 km"},
5
+ "Senen": {coords: [-6.1822, 106.8452], city: "Jakarta Pusat", radius: "1.0 km"},
6
+ "Cempaka Putih": {coords: [-6.1802, 106.8686], city: "Jakarta Pusat", radius: "1.1 km"},
7
+ "Johar Baru": {coords: [-6.1866, 106.8572], city: "Jakarta Pusat", radius: "0.8 km"},
8
+ "Kemayoran": {coords: [-6.1628, 106.8438], city: "Jakarta Pusat", radius: "1.5 km"},
9
+ "Sawah Besar": {coords: [-6.1554, 106.8322], city: "Jakarta Pusat", radius: "1.2 km"},
10
+ "Tanah Abang": {coords: [-6.2104, 106.8122], city: "Jakarta Pusat", radius: "2.0 km"},
11
+ "Gambir": {coords: [-6.1764, 106.8190], city: "Jakarta Pusat", radius: "1.8 km"},
12
+
13
+ // 2. JAKARTA UTARA (6 Kecamatan)
14
+ "Penjaringan": {coords: [-6.1264, 106.7822], city: "Jakarta Utara", radius: "2.5 km"},
15
+ "Tanjung Priok": {coords: [-6.1322, 106.8722], city: "Jakarta Utara", radius: "2.2 km"},
16
+ "Koja": {coords: [-6.1214, 106.9133], city: "Jakarta Utara", radius: "1.8 km"},
17
+ "Cilincing": {coords: [-6.1288, 106.9452], city: "Jakarta Utara", radius: "3.0 km"},
18
+ "Pademangan": {coords: [-6.1328, 106.8422], city: "Jakarta Utara", radius: "1.5 km"},
19
+ "Kelapa Gading": {coords: [-6.1552, 106.9022], city: "Jakarta Utara", radius: "2.0 km"},
20
+
21
+ // 3. JAKARTA BARAT (8 Kecamatan)
22
+ "Cengkareng": {coords: [-6.1528, 106.7322], city: "Jakarta Barat", radius: "3.0 km"},
23
+ "Grogol Petamburan": {coords: [-6.1622, 106.7882], city: "Jakarta Barat", radius: "2.0 km"},
24
+ "Kalideres": {coords: [-6.1428, 106.7022], city: "Jakarta Barat", radius: "3.2 km"},
25
+ "Kebon Jeruk": {coords: [-6.1922, 106.7722], city: "Jakarta Barat", radius: "2.2 km"},
26
+ "Kembangan": {coords: [-6.1828, 106.7382], city: "Jakarta Barat", radius: "2.5 km"},
27
+ "Palmerah": {coords: [-6.2028, 106.7882], city: "Jakarta Barat", radius: "1.8 km"},
28
+ "Taman Sari": {coords: [-6.1454, 106.8182], city: "Jakarta Barat", radius: "1.2 km"},
29
+ "Tambora": {coords: [-6.1500, 106.8000], city: "Jakarta Barat", radius: "1.0 km"},
30
+
31
+ // 4. JAKARTA SELATAN (10 Kecamatan)
32
+ "Cilandak": {coords: [-6.2928, 106.7922], city: "Jakarta Selatan", radius: "2.2 km"},
33
+ "Jagakarsa": {coords: [-6.3328, 106.8222], city: "Jakarta Selatan", radius: "2.5 km"},
34
+ "Kebayoran Baru": {coords: [-6.2422, 106.7982], city: "Jakarta Selatan", radius: "2.0 km"},
35
+ "Kebayoran Lama": {coords: [-6.2488, 106.7722], city: "Jakarta Selatan", radius: "2.4 km"},
36
+ "Mampang Prapatan": {coords: [-6.2522, 106.8182], city: "Jakarta Selatan", radius: "1.5 km"},
37
+ "Pancoran": {coords: [-6.2622, 106.8382], city: "Jakarta Selatan", radius: "1.6 km"},
38
+ "Pasar Minggu": {coords: [-6.2828, 106.8438], city: "Jakarta Selatan", radius: "2.5 km"},
39
+ "Pesanggrahan": {coords: [-6.2588, 106.7588], city: "Jakarta Selatan", radius: "2.0 km"},
40
+ "Setiabudi": {coords: [-6.2228, 106.8282], city: "Jakarta Selatan", radius: "1.8 km"},
41
+ "Tebet": {coords: [-6.2288, 106.8482], city: "Jakarta Selatan", radius: "2.0 km"},
42
+
43
+ // 5. JAKARTA TIMUR (10 Kecamatan)
44
+ "Cakung": {coords: [-6.1828, 106.9482], city: "Jakarta Timur", radius: "3.5 km"},
45
+ "Cipayung": {coords: [-6.3128, 106.9022], city: "Jakarta Timur", radius: "2.8 km"},
46
+ "Ciracas": {coords: [-6.3228, 106.8782], city: "Jakarta Timur", radius: "2.2 km"},
47
+ "Duren Sawit": {coords: [-6.2228, 106.9282], city: "Jakarta Timur", radius: "3.0 km"},
48
+ "Jatinegara": {coords: [-6.2222, 106.8682], city: "Jakarta Timur", radius: "2.5 km"},
49
+ "Kramat Jati": {coords: [-6.2722, 106.8682], city: "Jakarta Timur", radius: "2.4 km"},
50
+ "Makasar": {coords: [-6.2622, 106.8782], city: "Jakarta Timur", radius: "2.0 km"},
51
+ "Matraman": {coords: [-6.2022, 106.8582], city: "Jakarta Timur", radius: "1.5 km"},
52
+ "Pasar Rebo": {coords: [-6.3122, 106.8522], city: "Jakarta Timur", radius: "2.0 km"},
53
+ "Pulo Gadung": {coords: [-6.1922, 106.8922], city: "Jakarta Timur", radius: "2.6 km"},
54
+
55
+ // 6. KEPULAUAN SERIBU (2 Kecamatan)
56
+ "Kepulauan Seribu Utara": {coords: [-5.5722, 106.5522], city: "Kepulauan Seribu", radius: "8.0 km"},
57
+ "Kepulauan Seribu Selatan": {coords: [-5.7722, 106.6522], city: "Kepulauan Seribu", radius: "7.0 km"}
58
+ };
59
+
60
+ const BANTARGEBANG_COORDS = [-6.3477, 106.9939];
61
+
62
+ // UI Elements
63
+ const locationSelect = document.getElementById("location-select");
64
+ const modelSelect = document.getElementById("model-select");
65
+ const forecastSlider = document.getElementById("forecast-slider");
66
+ const forecastVal = document.getElementById("forecast-val");
67
+ const rainOverride = document.getElementById("rain-override");
68
+ const rainOverrideVal = document.getElementById("rain-override-val");
69
+ const eventOverride = document.getElementById("event-override");
70
+ const predictBtn = document.getElementById("predict-btn");
71
+ const exportBtn = document.getElementById("export-btn");
72
+
73
+ // Weather elements
74
+ const weatherForecastText = document.getElementById("weather-forecast-text");
75
+ const weatherLocationText = document.getElementById("weather-location-text");
76
+ const weatherPrecip = document.getElementById("weather-precip");
77
+ const weatherAlert = document.getElementById("weather-alert");
78
+ const eventDescText = document.getElementById("event-desc-text");
79
+
80
+ // Stats elements
81
+ const statTotalVolume = document.getElementById("stat-total-volume");
82
+ const statRiskStatus = document.getElementById("stat-risk-status");
83
+ const statTrucks = document.getElementById("stat-trucks");
84
+
85
+ // Metadata elements
86
+ const statPeriodMeta = document.getElementById("stat-period-meta");
87
+ const statLocationMeta = document.getElementById("stat-location-meta");
88
+
89
+ // Composition elements
90
+ const valOrganic = document.getElementById("val-organic");
91
+ const valPlastic = document.getElementById("val-plastic");
92
+ const valPaper = document.getElementById("val-paper");
93
+ const valGlass = document.getElementById("val-glass");
94
+ const valTextile = document.getElementById("val-textile");
95
+ const valMetal = document.getElementById("val-metal");
96
+ const barOrganic = document.getElementById("bar-organic");
97
+ const barPlastic = document.getElementById("bar-plastic");
98
+ const barPaper = document.getElementById("bar-paper");
99
+ const barGlass = document.getElementById("bar-glass");
100
+ const barTextile = document.getElementById("bar-textile");
101
+ const barMetal = document.getElementById("bar-metal");
102
+
103
+ // Logistics elements
104
+ const logManpower = document.getElementById("log-manpower");
105
+ const logDuration = document.getElementById("log-duration");
106
+ const logEfficiency = document.getElementById("log-efficiency");
107
+ const logConfidence = document.getElementById("log-confidence");
108
+
109
+ // Timeline & Hourly
110
+ const timelineList = document.getElementById("timeline-list");
111
+ const hourlySection = document.getElementById("hourly-section");
112
+ const hourlyGrid = document.getElementById("hourly-grid");
113
+
114
+ // State
115
+ let selectedLocation = "Menteng";
116
+ let rainValue = 0; // 0 means Auto (Open-Meteo)
117
+ let map;
118
+ let mapMarkers = {};
119
+ let routeLine = null;
120
+
121
+ // ==========================================
122
+ // SPA MULTIPAGE ROUTING
123
+ // ==========================================
124
+ function switchPage(pageId) {
125
+ document.querySelectorAll(".page-container").forEach(el => {
126
+ el.classList.remove("active");
127
+ });
128
+ document.querySelectorAll(".nav-btn").forEach(el => {
129
+ el.classList.remove("active");
130
+ });
131
+
132
+ const targetPage = document.getElementById(pageId);
133
+ if (targetPage) {
134
+ targetPage.classList.add("active");
135
+ }
136
+
137
+ const targetBtn = document.querySelector(`.nav-btn[data-target="${pageId}"]`);
138
+ if (targetBtn) {
139
+ targetBtn.classList.add("active");
140
+ }
141
+
142
+ if (pageId === "page-news") {
143
+ loadNewsFeed();
144
+ } else if (pageId === "page-alerts") {
145
+ loadAlertsFeed();
146
+ } else if (pageId === "page-autopilot") {
147
+ loadAutopilotFeed();
148
+ } else if (pageId === "page-predictor" && map) {
149
+ setTimeout(() => { map.invalidateSize(); }, 200);
150
+ }
151
+ }
152
+
153
+ window.switchPage = switchPage;
154
+
155
+ // Dynamically Populate Dropdown on Startup
156
+ function populateLocationDropdown() {
157
+ if (!locationSelect) return;
158
+ locationSelect.innerHTML = "";
159
+ Object.keys(KECAMATAN_DATABASE).forEach(loc => {
160
+ const opt = document.createElement("option");
161
+ opt.value = loc;
162
+ opt.textContent = `${loc} (${KECAMATAN_DATABASE[loc].city})`;
163
+ locationSelect.appendChild(opt);
164
+ });
165
+ locationSelect.value = selectedLocation;
166
+ }
167
+
168
+ // Calculate Haversine Distance between two coordinate arrays [lat, lon]
169
+ function getHaversineDistance(coords1, coords2) {
170
+ const R = 6371; // Earth radius in km
171
+ const dLat = (coords2[0] - coords1[0]) * Math.PI / 180;
172
+ const dLon = (coords2[1] - coords1[1]) * Math.PI / 180;
173
+ const a = Math.sin(dLat/2) * Math.sin(dLat/2) +
174
+ Math.cos(coords1[0] * Math.PI / 180) * Math.cos(coords2[0] * Math.PI / 180) *
175
+ Math.sin(dLon/2) * Math.sin(dLon/2);
176
+ const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
177
+ return R * c;
178
+ }
179
+
180
+ // Event Listeners for controls
181
+ if (forecastSlider) {
182
+ forecastSlider.addEventListener("input", (e) => {
183
+ forecastVal.textContent = e.target.value;
184
+ });
185
+ }
186
+
187
+ if (rainOverride) {
188
+ rainOverride.addEventListener("input", (e) => {
189
+ const val = parseInt(e.target.value);
190
+ rainValue = val;
191
+ if (val === 0) {
192
+ rainOverrideVal.textContent = "Auto (Open-Meteo)";
193
+ } else {
194
+ rainOverrideVal.textContent = `${val} mm`;
195
+ }
196
+ updateRainAnimationIntensity(val);
197
+ });
198
+ }
199
+
200
+ if (locationSelect) {
201
+ locationSelect.addEventListener("change", (e) => {
202
+ selectedLocation = e.target.value;
203
+ updateActiveMapMarker(selectedLocation);
204
+ panToLocation(selectedLocation);
205
+ fetchLiveWeather(selectedLocation);
206
+ runPrediction();
207
+ });
208
+ }
209
+
210
+ // Initialize Leaflet Map
211
+ function initMap() {
212
+ const mapEl = document.getElementById("map");
213
+ if (!mapEl) return;
214
+
215
+ map = L.map('map', {
216
+ zoomControl: true,
217
+ attributionControl: false,
218
+ maxZoom: 15,
219
+ minZoom: 9
220
+ }).setView([-6.175, 106.825], 11.5);
221
+
222
+ L.tileLayer('https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png', {
223
+ maxZoom: 20
224
+ }).addTo(map);
225
+
226
+ // Add Bantargebang disposal site marker
227
+ const bantarIcon = L.divIcon({
228
+ className: 'leaflet-custom-marker bantar-marker',
229
+ html: `<div class="marker-pulse" style="background:#FF9900;opacity:0.25;"></div><div class="marker-core" style="background:#FF9900;border:2px solid #FFF;"></div><div class="marker-label" style="color:#FF9900;border-color:#FF9900;">Bantargebang</div>`,
230
+ iconSize: [24, 24],
231
+ iconAnchor: [12, 12]
232
+ });
233
+ L.marker(BANTARGEBANG_COORDS, { icon: bantarIcon }).addTo(map).bindPopup(`
234
+ <div class="route-popup" style="border-left: 3px solid #FF9900;">
235
+ <h3 style="color:#FF9900;">TPST BANTARGEBANG</h3>
236
+ <div>Disposal Facility (Bekasi)</div>
237
+ <div>Status: <b>Active & Calibrated</b></div>
238
+ </div>
239
+ `);
240
+
241
+ // Add Custom Location Markers for 44 Kecamatan
242
+ Object.keys(KECAMATAN_DATABASE).forEach(loc => {
243
+ const data = KECAMATAN_DATABASE[loc];
244
+ const customIcon = L.divIcon({
245
+ className: 'leaflet-custom-marker',
246
+ html: `<div class="marker-pulse"></div><div class="marker-core"></div><div class="marker-label">${loc}</div>`,
247
+ iconSize: [24, 24],
248
+ iconAnchor: [12, 12]
249
+ });
250
+
251
+ const marker = L.marker(data.coords, { icon: customIcon }).addTo(map);
252
+
253
+ marker.on('click', () => {
254
+ selectedLocation = loc;
255
+ if (locationSelect) locationSelect.value = loc;
256
+ updateActiveMapMarker(loc);
257
+ panToLocation(loc);
258
+ fetchLiveWeather(loc);
259
+ runPrediction();
260
+ });
261
+
262
+ mapMarkers[loc] = marker;
263
+ });
264
+
265
+ setTimeout(() => {
266
+ updateActiveMapMarker(selectedLocation);
267
+ }, 1000);
268
+ }
269
+
270
+ function updateActiveMapMarker(locName) {
271
+ Object.keys(mapMarkers).forEach(loc => {
272
+ const marker = mapMarkers[loc];
273
+ const el = marker.getElement();
274
+ if (el) {
275
+ if (loc === locName) {
276
+ el.classList.add("active");
277
+ } else {
278
+ el.classList.remove("active");
279
+ }
280
+ }
281
+ });
282
+ }
283
+
284
+ function panToLocation(locName) {
285
+ const coords = KECAMATAN_DATABASE[locName]?.coords;
286
+ if (coords && map) {
287
+ map.panTo(coords);
288
+ }
289
+ }
290
+
291
+ function updateMarkerRisk(locName, riskStatus) {
292
+ const marker = mapMarkers[locName];
293
+ if (marker) {
294
+ const el = marker.getElement();
295
+ if (el) {
296
+ el.classList.remove("safe", "warning", "critical");
297
+ el.classList.add(riskStatus.toLowerCase());
298
+ }
299
+ }
300
+ }
301
+
302
+ // Draw transit route to TPST Bantargebang
303
+ function drawTransitRoute(locName) {
304
+ const startCoords = KECAMATAN_DATABASE[locName]?.coords;
305
+ if (!startCoords || !map) return;
306
+
307
+ if (routeLine) {
308
+ map.removeLayer(routeLine);
309
+ }
310
+
311
+ routeLine = L.polyline([startCoords, BANTARGEBANG_COORDS], {
312
+ color: '#00F0FF',
313
+ weight: 3.5,
314
+ opacity: 0.75,
315
+ dashArray: '8, 8',
316
+ className: 'glowing-route'
317
+ }).addTo(map);
318
+
319
+ const directDist = getHaversineDistance(startCoords, BANTARGEBANG_COORDS);
320
+ const roadDist = directDist * 1.35;
321
+ const travelTimeHours = roadDist / 28.0;
322
+
323
+ routeLine.bindPopup(`
324
+ <div class="route-popup">
325
+ <h3>LOGISTICS DISPATCH ROUTE</h3>
326
+ <div>Kecamatan: <b>${locName}</b></div>
327
+ <div>Destination: <b>TPST Bantargebang</b></div>
328
+ <div>Transit Distance: <b class="highlight">${roadDist.toFixed(1)} km</b></div>
329
+ <div>Est. Travel Time: <b class="highlight">${travelTimeHours.toFixed(1)} Hours</b></div>
330
+ </div>
331
+ `).openPopup();
332
+
333
+ map.fitBounds([startCoords, BANTARGEBANG_COORDS], {
334
+ padding: [60, 60]
335
+ });
336
+ }
337
+
338
+ // Fetch Live Weather from Open-Meteo with Timeout
339
+ async function fetchLiveWeather(loc) {
340
+ const coord = KECAMATAN_DATABASE[loc];
341
+ if (!coord) return;
342
+
343
+ if (weatherForecastText) weatherForecastText.textContent = "Fetching...";
344
+ if (weatherPrecip) weatherPrecip.textContent = "0.0 mm";
345
+ if (weatherAlert) weatherAlert.textContent = "Checking...";
346
+
347
+ const url = `https://api.open-meteo.com/v1/forecast?latitude=${coord.coords[0]}&longitude=${coord.coords[1]}&current_weather=true&daily=precipitation_sum&timezone=Asia/Jakarta&past_days=2`;
348
+
349
+ // Set 1.5s timeout promise
350
+ const timeoutPromise = new Promise((_, reject) =>
351
+ setTimeout(() => reject(new Error("Timeout")), 1500)
352
+ );
353
+
354
+ try {
355
+ const fetchPromise = fetch(url).then(res => {
356
+ if (!res.ok) throw new Error("HTTP Error");
357
+ return res.json();
358
+ });
359
+
360
+ // Race weather request with 1.5s timeout
361
+ const data = await Promise.race([fetchPromise, timeoutPromise]);
362
+
363
+ const temp = data.current_weather.temperature;
364
+ const code = data.current_weather.weathercode;
365
+
366
+ const dailyData = data.daily || {};
367
+ const precipList = dailyData.precipitation_sum || [];
368
+ const precipToday = precipList[2] || 0;
369
+
370
+ let cond = "Cloudy";
371
+ if (code === 0) cond = "Clear Sky";
372
+ else if (code > 0 && code < 4) cond = "Partly Cloudy";
373
+ else if (code >= 51 && code <= 67) cond = "Rainy";
374
+ else if (code >= 80 && code <= 82) cond = "Showers";
375
+
376
+ if (weatherForecastText) weatherForecastText.textContent = `${temp}°C - ${cond}`;
377
+ if (weatherLocationText) weatherLocationText.textContent = `${loc} (${coord.city})`;
378
+ if (weatherPrecip) weatherPrecip.textContent = `${precipToday.toFixed(1)} mm`;
379
+
380
+ if (weatherAlert) {
381
+ if (precipToday > 30) {
382
+ weatherAlert.textContent = "HEAVY RAIN 🟡";
383
+ weatherAlert.className = "highlight text-warning";
384
+ } else if (precipToday > 50) {
385
+ weatherAlert.textContent = "FLOOD DANGER 🔴";
386
+ weatherAlert.className = "highlight text-red";
387
+ } else {
388
+ weatherAlert.textContent = "Normal conditions";
389
+ weatherAlert.className = "highlight";
390
+ }
391
+ }
392
+ } catch (err) {
393
+ console.warn("Weather fetch timed out/failed. Using fallback forecast.", err);
394
+ // Instant Fallback Weather Data
395
+ const fallbackTemp = 28.5 + Math.random() * 3.0;
396
+ const fallbackPrecip = 0.0;
397
+ if (weatherForecastText) weatherForecastText.textContent = `${fallbackTemp.toFixed(1)}°C - Partly Cloudy`;
398
+ if (weatherLocationText) weatherLocationText.textContent = `${loc} (${coord.city})`;
399
+ if (weatherPrecip) weatherPrecip.textContent = `${fallbackPrecip.toFixed(1)} mm`;
400
+ if (weatherAlert) {
401
+ weatherAlert.textContent = "Normal conditions";
402
+ weatherAlert.className = "highlight";
403
+ }
404
+ }
405
+ }
406
+
407
+ // Run prediction calling FastAPI backend
408
+ async function runPrediction() {
409
+ if (!predictBtn) return;
410
+ predictBtn.disabled = true;
411
+ predictBtn.querySelector(".btn-text").textContent = "PROCESSING FORECAST...";
412
+
413
+ const payload = {
414
+ forecast_days: parseInt(forecastSlider.value),
415
+ rainfall_mm: parseFloat(rainValue),
416
+ event_scale: parseInt(eventOverride.value),
417
+ location: selectedLocation,
418
+ model_type: modelSelect.value,
419
+ granularity: forecastSlider.value <= 7 ? "hourly" : "daily"
420
+ };
421
+
422
+ try {
423
+ const response = await fetch("/api/v1/predict", {
424
+ method: "POST",
425
+ headers: {
426
+ "Content-Type": "application/json"
427
+ },
428
+ body: JSON.stringify(payload)
429
+ });
430
+
431
+ if (response.ok) {
432
+ const resData = await response.json();
433
+ updateDashboardData(resData.data, resData.confidence_score, resData.message);
434
+ } else {
435
+ console.error("API Error");
436
+ }
437
+ } catch (err) {
438
+ console.error(err);
439
+ } finally {
440
+ predictBtn.disabled = false;
441
+ predictBtn.querySelector(".btn-text").textContent = "RUN PREDICTION";
442
+ }
443
+ }
444
+
445
+ function updateDashboardData(data, confScore, message) {
446
+ const results = data.prediction_results;
447
+ if (results.length === 0) return;
448
+
449
+ const totalVolume = results.reduce((acc, curr) => acc + curr.total_volume_ton, 0);
450
+ if (statTotalVolume) statTotalVolume.innerHTML = `${totalVolume.toFixed(2)} <span class="unit">Tons</span>`;
451
+
452
+ let maxRisk = "SAFE";
453
+ results.forEach(r => {
454
+ if (r.risk_status === "CRITICAL") maxRisk = "CRITICAL";
455
+ else if (r.risk_status === "WARNING" && maxRisk !== "CRITICAL") maxRisk = "WARNING";
456
+ });
457
+
458
+ if (statRiskStatus) {
459
+ statRiskStatus.textContent = maxRisk;
460
+ statRiskStatus.className = `card-value status-badge ${maxRisk.toLowerCase()}`;
461
+ }
462
+
463
+ updateMarkerRisk(selectedLocation, maxRisk);
464
+ drawTransitRoute(selectedLocation);
465
+
466
+ if (statTrucks) statTrucks.innerHTML = `${data.logistics_plan.trucks_needed} <span class="unit">Trucks (5T)</span>`;
467
+
468
+ const startDateStr = results[0].date;
469
+ const endDateStr = results[results.length - 1].date;
470
+
471
+ if (statPeriodMeta) statPeriodMeta.textContent = `Period: ${startDateStr} to ${endDateStr}`;
472
+ if (statLocationMeta) statLocationMeta.textContent = `${selectedLocation} (Radius ${KECAMATAN_DATABASE[selectedLocation].radius})`;
473
+
474
+ const totalOrganic = results.reduce((acc, curr) => acc + curr.organic_waste_ton, 0);
475
+ const totalPlastic = results.reduce((acc, curr) => acc + curr.plastic_waste_ton, 0);
476
+ const totalPaper = results.reduce((acc, curr) => acc + curr.paper_waste_ton, 0);
477
+ const totalGlass = results.reduce((acc, curr) => acc + curr.glass_waste_ton, 0);
478
+ const totalTextile = results.reduce((acc, curr) => acc + curr.textile_waste_ton, 0);
479
+ const totalMetal = results.reduce((acc, curr) => acc + (curr.metal_waste_ton + curr.other_waste_ton), 0);
480
+
481
+ if (valOrganic) valOrganic.textContent = `${totalOrganic.toFixed(2)} Ton`;
482
+ if (valPlastic) valPlastic.textContent = `${totalPlastic.toFixed(2)} Ton`;
483
+ if (valPaper) valPaper.textContent = `${totalPaper.toFixed(2)} Ton`;
484
+ if (valGlass) valGlass.textContent = `${totalGlass.toFixed(2)} Ton`;
485
+ if (valTextile) valTextile.textContent = `${totalTextile.toFixed(2)} Ton`;
486
+ if (valMetal) valMetal.textContent = `${totalMetal.toFixed(2)} Ton`;
487
+
488
+ const getPct = (val) => totalVolume > 0 ? (val / totalVolume) * 100 : 0;
489
+
490
+ if (barOrganic) barOrganic.style.width = `${getPct(totalOrganic)}%`;
491
+ if (barPlastic) barPlastic.style.width = `${getPct(totalPlastic)}%`;
492
+ if (barPaper) barPaper.style.width = `${getPct(totalPaper)}%`;
493
+ if (barGlass) barGlass.style.width = `${getPct(totalGlass)}%`;
494
+ if (barTextile) barTextile.style.width = `${getPct(totalTextile)}%`;
495
+ if (barMetal) barMetal.style.width = `${getPct(totalMetal)}%`;
496
+
497
+ if (logManpower) logManpower.textContent = `${data.logistics_plan.manpower} Crew`;
498
+ if (logDuration) logDuration.textContent = `${data.logistics_plan.estimated_duration_hours.toFixed(1)} Hours`;
499
+ if (logEfficiency) logEfficiency.textContent = data.logistics_plan.efficiency_rate;
500
+ if (logConfidence) logConfidence.textContent = `${(confScore * 100).toFixed(1)}%`;
501
+
502
+ const eventDay = results.find(r => r.event_info !== null);
503
+ if (eventDay) {
504
+ if (eventDescText) eventDescText.innerHTML = `⚠️ <strong>${eventDay.event_info}</strong> on ${eventDay.date}. Heavy crowd expected near site.`;
505
+ const eBox = document.getElementById("event-box");
506
+ if (eBox) eBox.style.borderColor = "var(--red)";
507
+ } else {
508
+ if (eventDescText) eventDescText.textContent = "No major public events scheduled for this location in the forecast window.";
509
+ const eBox = document.getElementById("event-box");
510
+ if (eBox) eBox.style.borderColor = "var(--yellow)";
511
+ }
512
+
513
+ if (timelineList) {
514
+ timelineList.innerHTML = "";
515
+ results.forEach(day => {
516
+ const card = document.createElement("div");
517
+ card.className = "timeline-card";
518
+
519
+ const dateObj = new Date(day.date);
520
+ const dayName = dateObj.toLocaleDateString('en-US', { weekday: 'short' });
521
+ const displayDate = `${dayName}, ${dateObj.getDate()} ${dateObj.toLocaleString('en-US', { month: 'short' })}`;
522
+
523
+ card.innerHTML = `
524
+ <span class="timeline-date">${displayDate}</span>
525
+ <span class="timeline-vol">${day.total_volume_ton.toFixed(1)} T</span>
526
+ <span class="timeline-status ${day.risk_status.toLowerCase()}">${day.risk_status}</span>
527
+ `;
528
+ timelineList.appendChild(card);
529
+ });
530
+ }
531
+
532
+ const hourlyDay = results[0];
533
+ if (hourlyDay && hourlyDay.hourly_breakdown) {
534
+ if (hourlySection) hourlySection.style.display = "block";
535
+ if (hourlyGrid) {
536
+ hourlyGrid.innerHTML = "";
537
+ hourlyDay.hourly_breakdown.forEach(hour => {
538
+ const cell = document.createElement("div");
539
+ cell.className = "hourly-cell";
540
+
541
+ let intensityClass = "low";
542
+ if (hour.risk_indicator === "MEDIUM") intensityClass = "medium";
543
+ else if (hour.risk_indicator === "HIGH") intensityClass = "high";
544
+
545
+ cell.innerHTML = `
546
+ <div class="cell-block ${intensityClass}" title="Vol: ${hour.estimated_volume_ton} Ton - Risk: ${hour.risk_indicator}"></div>
547
+ <span class="cell-time">${hour.hour}</span>
548
+ `;
549
+ hourlyGrid.appendChild(cell);
550
+ });
551
+ }
552
+ } else {
553
+ if (hourlySection) hourlySection.style.display = "none";
554
+ }
555
+ }
556
+
557
+ // Request CSV from Backend API and download it
558
+ async function runExport() {
559
+ if (!exportBtn) return;
560
+ exportBtn.disabled = true;
561
+ exportBtn.querySelector(".btn-text").textContent = "EXPORTING...";
562
+
563
+ const payload = {
564
+ forecast_days: parseInt(forecastSlider.value),
565
+ rainfall_mm: parseFloat(rainValue),
566
+ event_scale: parseInt(eventOverride.value),
567
+ location: selectedLocation,
568
+ model_type: modelSelect.value,
569
+ granularity: forecastSlider.value <= 7 ? "hourly" : "daily"
570
+ };
571
+
572
+ try {
573
+ const response = await fetch("/api/v1/predict/csv", {
574
+ method: "POST",
575
+ headers: {
576
+ "Content-Type": "application/json"
577
+ },
578
+ body: JSON.stringify(payload)
579
+ });
580
+
581
+ if (response.ok) {
582
+ const blob = await response.blob();
583
+ const url = window.URL.createObjectURL(blob);
584
+ const a = document.createElement("a");
585
+ a.href = url;
586
+ a.download = `waste_forecast_${selectedLocation.replace(/\s+/g, "_")}_${forecastSlider.value}d.csv`;
587
+ document.body.appendChild(a);
588
+ a.click();
589
+ a.remove();
590
+ window.URL.revokeObjectURL(url);
591
+ }
592
+ } catch (err) {
593
+ console.error(err);
594
+ } finally {
595
+ exportBtn.disabled = false;
596
+ exportBtn.querySelector(".btn-text").textContent = "EXPORT CSV";
597
+ }
598
+ }
599
+
600
+ // ==========================================
601
+ // SPA ASYNC LOADERS (News, Alerts, Autopilot)
602
+ // ==========================================
603
+ async function loadNewsFeed() {
604
+ const newsGrid = document.getElementById("news-grid-list");
605
+ if (!newsGrid) return;
606
+ newsGrid.innerHTML = '<div class="loading-news">Loading latest waste intelligence...</div>';
607
+
608
+ try {
609
+ const res = await fetch("/api/v1/news");
610
+ if (res.ok) {
611
+ const news = await res.json();
612
+ newsGrid.innerHTML = "";
613
+ if (news.length === 0) {
614
+ newsGrid.innerHTML = '<div class="loading-news">No news articles found.</div>';
615
+ return;
616
+ }
617
+ news.forEach(item => {
618
+ const card = document.createElement("div");
619
+ card.className = "news-card";
620
+ card.innerHTML = `
621
+ <div class="news-card-header">
622
+ <span class="news-source">${item.source}</span>
623
+ <span class="news-date">${item.date_fetched || "2026-07-10"}</span>
624
+ </div>
625
+ <h3 class="news-title">${item.title}</h3>
626
+ <p class="news-summary">${item.summary}</p>
627
+ <a href="${item.url}" target="_blank" class="news-link">READ SOURCE <span>&rarr;</span></a>
628
+ `;
629
+ newsGrid.appendChild(card);
630
+ });
631
+ } else {
632
+ newsGrid.innerHTML = '<div class="loading-news">Failed to fetch news from server.</div>';
633
+ }
634
+ } catch (err) {
635
+ newsGrid.innerHTML = '<div class="loading-news">Error loading news feed.</div>';
636
+ }
637
+ }
638
+
639
+ async function loadAlertsFeed() {
640
+ const alertsList = document.getElementById("alerts-grid-list");
641
+ if (!alertsList) return;
642
+ alertsList.innerHTML = '<div class="loading-alerts">Evaluating regional alert parameters...</div>';
643
+
644
+ try {
645
+ const res = await fetch("/api/v1/alerts");
646
+ if (res.ok) {
647
+ const alertData = await res.json();
648
+ alertsList.innerHTML = "";
649
+ if (alertData.alerts.length === 0) {
650
+ alertsList.innerHTML = '<div class="loading-alerts">No active warnings. All systems green.</div>';
651
+ return;
652
+ }
653
+ alertData.alerts.forEach(item => {
654
+ const row = document.createElement("div");
655
+ row.className = "alert-row";
656
+ row.innerHTML = `
657
+ <span class="alert-date">${item.date}</span>
658
+ <span class="alert-location">${item.location}</span>
659
+ <span class="alert-badge ${item.status.toLowerCase()}">${item.status}</span>
660
+ <span class="alert-desc">${item.message} - Timbulan: <strong>${item.estimated_volume_ton.toFixed(1)} Ton</strong></span>
661
+ `;
662
+ alertsList.appendChild(row);
663
+ });
664
+ } else {
665
+ alertsList.innerHTML = '<div class="loading-alerts">Failed to load alerts.</div>';
666
+ }
667
+ } catch (err) {
668
+ alertsList.innerHTML = '<div class="loading-alerts">Error loading alerts feed.</div>';
669
+ }
670
+ }
671
+
672
+ async function loadAutopilotFeed() {
673
+ const logContainer = document.getElementById("autopilot-log");
674
+ const autoVol = document.getElementById("auto-total-volume");
675
+ const autoTrucks = document.getElementById("auto-total-trucks");
676
+ const autoRiskList = document.getElementById("auto-risk-list");
677
+
678
+ if (!logContainer || !autoRiskList) return;
679
+
680
+ autoVol.textContent = "Calculating...";
681
+ autoTrucks.textContent = "Calculating...";
682
+ autoRiskList.innerHTML = '<div class="loading-news" style="padding:1rem;">Running neural models...</div>';
683
+ logContainer.innerHTML = "";
684
+
685
+ const addLog = (msg) => {
686
+ const time = new Date().toLocaleTimeString('en-US', { hour12: false });
687
+ const p = document.createElement("div");
688
+ p.textContent = `[${time}] ${msg}`;
689
+ logContainer.appendChild(p);
690
+ logContainer.scrollTop = logContainer.scrollHeight;
691
+ };
692
+
693
+ addLog("Aeterna Neural Core Initialized.");
694
+ await new Promise(r => setTimeout(r, 600));
695
+ addLog("Connecting to Open-Meteo Geolocation nodes...");
696
+ await new Promise(r => setTimeout(r, 600));
697
+ addLog("Weather models ready. Scanning 44 sub-districts...");
698
+ await new Promise(r => setTimeout(r, 800));
699
+
700
+ try {
701
+ const res = await fetch("/api/v1/autopilot");
702
+ if (res.ok) {
703
+ const data = await res.json();
704
+
705
+ addLog("Executing GBR forward inference pass on 44 regions...");
706
+ await new Promise(r => setTimeout(r, 800));
707
+ addLog(`Forecasting complete. Total active events today: ${data.event_today ? data.event_today : "0"}`);
708
+ await new Promise(r => setTimeout(r, 500));
709
+
710
+ autoVol.innerHTML = `${data.total_volume_ton.toLocaleString('en-US')} <span class="unit">Tons</span>`;
711
+ autoTrucks.innerHTML = `${data.total_trucks.toLocaleString('en-US')} <span class="unit">Trucks (5T)</span>`;
712
+
713
+ autoRiskList.innerHTML = "";
714
+ data.top_kecamatan.forEach((item, index) => {
715
+ const card = document.createElement("div");
716
+ card.className = "alert-row";
717
+ card.style.gridTemplateColumns = "60px 180px 100px 1fr";
718
+ card.style.padding = "0.6rem 1.2rem";
719
+ card.innerHTML = `
720
+ <span class="alert-date" style="font-weight:bold; color:var(--cyan);">#0${index+1}</span>
721
+ <span class="alert-location">${item.location}</span>
722
+ <span class="alert-badge ${item.status.toLowerCase()}">${item.status}</span>
723
+ <span class="alert-desc" style="font-size:0.8rem;">Predicted generation: <strong>${item.volume_ton.toFixed(1)} Tons</strong> (${item.trucks} Trucks)</span>
724
+ `;
725
+ autoRiskList.appendChild(card);
726
+ });
727
+
728
+ addLog(`DKI Jakarta daily forecast compiled: ${data.total_volume_ton} Tons.`);
729
+ addLog(`Logistics dispatch size set to ${data.total_trucks} crew trucks.`);
730
+ addLog("Autonomous fleet routing to TPST Bantargebang optimized via Haversine.");
731
+ } else {
732
+ addLog("CRITICAL ERROR: Failed to communicate with prediction nodes.");
733
+ }
734
+ } catch (err) {
735
+ addLog("CRITICAL ERROR: Connection timed out.");
736
+ }
737
+ }
738
+
739
+ // Attach Event Listeners on DOM load
740
+ window.addEventListener("DOMContentLoaded", () => {
741
+ populateLocationDropdown();
742
+ initMap();
743
+ fetchLiveWeather(selectedLocation);
744
+
745
+ // Wire SPA Navigation
746
+ document.querySelectorAll(".nav-btn").forEach(btn => {
747
+ btn.addEventListener("click", () => {
748
+ const target = btn.getAttribute("data-target");
749
+ switchPage(target);
750
+ });
751
+ });
752
+
753
+ if (predictBtn) predictBtn.addEventListener("click", runPrediction);
754
+ if (exportBtn) exportBtn.addEventListener("click", runExport);
755
+
756
+ setTimeout(runPrediction, 1000);
757
+ });
758
+
759
+ // ==========================================
760
+ // BACKGROUND CANVAS: INTERACTIVE RAIN EFFECT
761
+ // ==========================================
762
+ const canvas = document.getElementById("rain-canvas");
763
+ const ctx = canvas.getContext("2d");
764
+
765
+ let width = canvas.width = window.innerWidth;
766
+ let height = canvas.height = window.innerHeight;
767
+
768
+ window.addEventListener("resize", () => {
769
+ width = canvas.width = window.innerWidth;
770
+ height = canvas.height = window.innerHeight;
771
+ });
772
+
773
+ let drops = [];
774
+ let particles = [];
775
+ let maxPrecip = 0;
776
+
777
+ function updateRainAnimationIntensity(precipVal) {
778
+ maxPrecip = precipVal;
779
+ }
780
+
781
+ class DataParticle {
782
+ constructor() {
783
+ this.reset();
784
+ }
785
+ reset() {
786
+ this.x = Math.random() * width;
787
+ this.y = Math.random() * height;
788
+ this.size = Math.random() * 2 + 1;
789
+ this.speedX = Math.random() * 0.4 - 0.2;
790
+ this.speedY = Math.random() * -0.5 - 0.2;
791
+ this.alpha = Math.random() * 0.5 + 0.1;
792
+ }
793
+ update() {
794
+ this.x += this.speedX;
795
+ this.y += this.speedY;
796
+ if (this.y < 0 || this.x < 0 || this.x > width) {
797
+ this.reset();
798
+ this.y = height;
799
+ }
800
+ }
801
+ draw() {
802
+ ctx.fillStyle = `rgba(0, 240, 255, ${this.alpha})`;
803
+ ctx.beginPath();
804
+ ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2);
805
+ ctx.fill();
806
+ }
807
+ }
808
+
809
+ class RainDrop {
810
+ constructor() {
811
+ this.reset();
812
+ }
813
+ reset() {
814
+ this.x = Math.random() * width;
815
+ this.y = Math.random() * -100 - 10;
816
+ this.length = Math.random() * 15 + 10;
817
+ this.speed = Math.random() * 12 + 15;
818
+ this.weight = Math.random() * 1 + 0.5;
819
+ this.alpha = Math.random() * 0.3 + 0.1;
820
+ }
821
+ update() {
822
+ this.y += this.speed;
823
+ if (this.y > height) {
824
+ this.reset();
825
+ }
826
+ }
827
+ draw() {
828
+ ctx.strokeStyle = `rgba(0, 240, 255, ${this.alpha})`;
829
+ ctx.lineWidth = this.weight;
830
+ ctx.beginPath();
831
+ ctx.moveTo(this.x, this.y);
832
+ ctx.lineTo(this.x + (maxPrecip * 0.05), this.y + this.length);
833
+ ctx.stroke();
834
+ }
835
+ }
836
+
837
+ for (let i = 0; i < 60; i++) {
838
+ particles.push(new DataParticle());
839
+ }
840
+ for (let i = 0; i < 150; i++) {
841
+ drops.push(new RainDrop());
842
+ }
843
+
844
+ function animate() {
845
+ ctx.clearRect(0, 0, width, height);
846
+
847
+ if (maxPrecip === 0) {
848
+ particles.forEach(p => {
849
+ p.update();
850
+ p.draw();
851
+ });
852
+ } else {
853
+ const activeCount = Math.min(Math.floor(maxPrecip * 1.5), 150);
854
+ for (let i = 0; i < activeCount; i++) {
855
+ drops[i].update();
856
+ drops[i].draw();
857
+ }
858
+ }
859
+
860
+ requestAnimationFrame(animate);
861
+ }
862
+
863
+ animate();
static/index.html ADDED
@@ -0,0 +1,419 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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>Aeterna AI - Waste Intelligence Platform</title>
7
+ <!-- Google Fonts -->
8
+ <link rel="preconnect" href="https://fonts.googleapis.com">
9
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
10
+ <link href="https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;600;800&family=Space+Grotesk:wght@300;400;500;600;700&family=JetBrains+Mono:wght@300;400;700&display=swap" rel="stylesheet">
11
+
12
+ <!-- Leaflet.js Map Library -->
13
+ <link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" integrity="sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY=" crossorigin="" />
14
+ <script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js" integrity="sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo=" crossorigin=""></script>
15
+
16
+ <link rel="stylesheet" href="/static/style.css">
17
+ </head>
18
+ <body>
19
+ <!-- Background Canvas for Interactive Particle Rain -->
20
+ <canvas id="rain-canvas"></canvas>
21
+
22
+ <!-- Navigation Header -->
23
+ <header>
24
+ <div class="logo-container">
25
+ <span class="logo-text">AETERNA<span class="highlight">AI</span></span>
26
+ <span class="version-tag">v4.0.0 (Eco-Twin)</span>
27
+ </div>
28
+ <nav class="nav-links">
29
+ <button class="nav-btn active" data-target="page-home">HOME</button>
30
+ <button class="nav-btn" data-target="page-autopilot">AI AUTOPILOT</button>
31
+ <button class="nav-btn" data-target="page-predictor">SIMULATION TOOL</button>
32
+ <button class="nav-btn" data-target="page-news">NEWS FEED</button>
33
+ <button class="nav-btn" data-target="page-alerts">REGIONAL ALERTS</button>
34
+ </nav>
35
+ <div class="system-status">
36
+ <span class="status-indicator online"></span>
37
+ <span class="status-label">System Online</span>
38
+ </div>
39
+ </header>
40
+
41
+ <!-- HOME PAGE -->
42
+ <div id="page-home" class="page-container active">
43
+ <section class="hero-section">
44
+ <div class="hero-content">
45
+ <h1 class="hero-title">NEXT-GEN WASTE FORECASTING</h1>
46
+ <p class="hero-subtitle">Meningkatkan efisiensi tata kelola sampah DKI Jakarta hingga 98.28% dengan pemodelan spasial temporal real-time.</p>
47
+ <div class="hero-actions">
48
+ <button class="action-btn" onclick="switchPage('page-autopilot')">
49
+ <span class="btn-text">OPEN AUTOPILOT</span>
50
+ <span class="btn-glow"></span>
51
+ </button>
52
+ <button class="action-btn secondary-btn" onclick="switchPage('page-news')">
53
+ <span class="btn-text">EXPLORE NEWS</span>
54
+ <span class="btn-glow"></span>
55
+ </button>
56
+ </div>
57
+ </div>
58
+ <div class="hero-stats-panel panel">
59
+ <h3 class="panel-subtitle">Jakarta Waste Baseline</h3>
60
+ <div class="hero-stat-grid">
61
+ <div class="hero-stat-card">
62
+ <span class="h-stat-label">Daily Waste Total</span>
63
+ <span class="h-stat-value text-glow">8,020 <span class="unit">Tons</span></span>
64
+ </div>
65
+ <div class="hero-stat-card">
66
+ <span class="h-stat-label">Kecamatan Monitored</span>
67
+ <span class="h-stat-value">44 <span class="unit">Regions</span></span>
68
+ </div>
69
+ </div>
70
+ </div>
71
+ </section>
72
+
73
+ <!-- Keunggulan Aeterna AI -->
74
+ <section class="container features-section">
75
+ <h2 class="section-title">KEUNGGULAN AETERNA AI</h2>
76
+ <div class="features-grid">
77
+ <div class="panel feature-card">
78
+ <div class="feature-icon font-display">01</div>
79
+ <h3 class="feature-name">Akurasi Validitas Tinggi (98.28%)</h3>
80
+ <p class="feature-desc">Menggunakan arsitektur model Gradient Boosting Regressor (GBR) yang dioptimasi via GridSearchCV dengan metrik komparasi MAE, RMSE, dan MAPE secara berdampingan.</p>
81
+ </div>
82
+ <div class="panel feature-card">
83
+ <div class="feature-icon font-display">02</div>
84
+ <h3 class="feature-name">Integrasi Live Cuaca Open-Meteo</h3>
85
+ <p class="feature-desc">API dinamis asinkron yang menarik data curah hujan live tingkat kecamatan secara real-time untuk memprediksi tonase sampah basah akibat rembesan air hujan.</p>
86
+ </div>
87
+ <div class="panel feature-card">
88
+ <div class="feature-icon font-display">03</div>
89
+ <h3 class="feature-name">Pemantauan Berita Sampah 1 Jam</h3>
90
+ <p class="feature-desc">AI Scheduler internal merayap internet secara berkala tiap 1 jam untuk menangkap isu operasional, pembatasan Bantargebang, dan regulasi persampahan DKI Jakarta.</p>
91
+ </div>
92
+ <div class="panel feature-card">
93
+ <div class="feature-icon font-display">04</div>
94
+ <h3 class="feature-name">Kalibrasi Spasial 44 Kecamatan</h3>
95
+ <p class="feature-desc">Model peramalan dikalibrasi hulu-hilir menggunakan data primer Dinas Lingkungan Hidup DKI Jakarta, mencakup tonase baseline spesifik tiap kecamatan secara akuntabel.</p>
96
+ </div>
97
+ </div>
98
+ </section>
99
+
100
+ <!-- Sumber Data & Akuntabilitas -->
101
+ <section class="container data-sources-section">
102
+ <h2 class="section-title">TRANSPARANSI SUMBER DATA</h2>
103
+ <div class="panel sources-panel">
104
+ <div class="sources-grid" style="display:grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap:1.5rem;">
105
+ <div class="source-item">
106
+ <h4 style="color:var(--cyan); margin-bottom:0.5rem; font-family:var(--font-display);">1. Timbulan Sampah</h4>
107
+ <p style="font-size:0.85rem; color:var(--text-muted); line-height:1.5;">Data baseline disesuaikan dengan volume total ~8.020 Ton/hari dari <strong>Dinas Lingkungan Hidup (DLH) DKI Jakarta</strong> dan SIPSN Kementerian LHK.</p>
108
+ </div>
109
+ <div class="source-item">
110
+ <h4 style="color:var(--cyan); margin-bottom:0.5rem; font-family:var(--font-display);">2. Prediksi Cuaca</h4>
111
+ <p style="font-size:0.85rem; color:var(--text-muted); line-height:1.5;">Data curah hujan ditarik live menggunakan <strong>Open-Meteo API</strong> berdasarkan koordinat geografis presisi masing-masing kecamatan.</p>
112
+ </div>
113
+ <div class="source-item">
114
+ <h4 style="color:var(--cyan); margin-bottom:0.5rem; font-family:var(--font-display);">3. Kalender Event & Transit</h4>
115
+ <p style="font-size:0.85rem; color:var(--text-muted); line-height:1.5;">Pola mobilitas disimulasikan dari ridership harian <strong>MRT Jakarta</strong> (~85.000) dan kalender acara Jakarta untuk mengukur lonjakan kerumunan.</p>
116
+ </div>
117
+ <div class="source-item">
118
+ <h4 style="color:var(--cyan); margin-bottom:0.5rem; font-family:var(--font-display);">4. Jarak Pengangkutan</h4>
119
+ <p style="font-size:0.85rem; color:var(--text-muted); line-height:1.5;">Jarak tempuh dihitung menggunakan <strong>Haversine Formula</strong> dari koordinat kecamatan ke TPST Bantargebang dengan faktor jalan winding 1.35x.</p>
120
+ </div>
121
+ </div>
122
+ </div>
123
+ </section>
124
+ </div>
125
+
126
+ <!-- AI AUTOPILOT PAGE -->
127
+ <div id="page-autopilot" class="page-container">
128
+ <section class="container page-header-section">
129
+ <h2 class="section-title">AETERNA AI AUTOPILOT FORECASTER</h2>
130
+ <p class="section-subtitle">Sistem peramalan otonom DKI Jakarta. AI berjalan mandiri memprediksi volume harian dan mengoordinasikan logistik tanpa campur tangan pengguna.</p>
131
+ </section>
132
+
133
+ <!-- Live Metrics Summary -->
134
+ <section class="container autopilot-grid" style="display:grid; grid-template-columns: 1.2fr 0.8fr; gap:1.5rem; margin-top:1.5rem;">
135
+ <!-- Panel Ringkasan Otonom -->
136
+ <div class="panel autopilot-summary-panel">
137
+ <h3 class="panel-title">LIVE CITY-WIDE FORECAST (TODAY)</h3>
138
+ <div class="stats-row" style="display:grid; grid-template-columns: 1fr 1fr; gap:1rem; margin-bottom:1.5rem; width:100%;">
139
+ <div class="panel stat-card text-glow" style="background:rgba(0,0,0,0.3); display:flex; flex-direction:column; padding:1.2rem; border-radius:8px;">
140
+ <span class="card-label">TOTAL DKI JAKARTA VOLUME</span>
141
+ <span id="auto-total-volume" class="card-value" style="font-size:1.8rem; font-weight:800; color:var(--cyan);">Calculating...</span>
142
+ <span class="card-meta">Autonomous prediction summation</span>
143
+ </div>
144
+ <div class="panel stat-card" style="background:rgba(0,0,0,0.3); display:flex; flex-direction:column; padding:1.2rem; border-radius:8px;">
145
+ <span class="card-label">TOTAL DISPATCHED TRUCKS</span>
146
+ <span id="auto-total-trucks" class="card-value" style="font-size:1.8rem; font-weight:800; color:#FFF;">Calculating...</span>
147
+ <span class="card-meta">Fleet size for all 44 kecamatan</span>
148
+ </div>
149
+ </div>
150
+
151
+ <h4 style="color:var(--cyan); margin-bottom:0.8rem; font-family:var(--font-display); font-size:0.95rem; border-left:3px solid var(--cyan); padding-left:8px; text-transform:uppercase;">Top 5 High-Risk Kecamatan Today:</h4>
152
+ <div id="auto-risk-list" class="auto-risk-list" style="display:flex; flex-direction:column; gap:0.8rem;">
153
+ <!-- Dynamically populated Top 5 -->
154
+ </div>
155
+ </div>
156
+
157
+ <!-- Konsol Berpikir AI -->
158
+ <div class="panel autopilot-console-panel" style="display:flex; flex-direction:column; height:100%;">
159
+ <h3 class="panel-title">AI THINKING CONSOLE</h3>
160
+ <div id="autopilot-log" style="flex:1; background:rgba(0,0,0,0.6); border:1px solid var(--border-color); border-radius:8px; padding:1.2rem; font-family:var(--font-mono); font-size:0.8rem; color:var(--green); overflow-y:auto; min-height:260px; line-height:1.6; box-shadow:inset 0 0 20px rgba(0,0,0,0.8);">
161
+ <!-- Dynamic logs -->
162
+ </div>
163
+ </div>
164
+ </section>
165
+ </div>
166
+
167
+ <!-- PREDICTOR PAGE -->
168
+ <div id="page-predictor" class="page-container">
169
+ <main class="dashboard-grid">
170
+ <!-- Panel Kontrol (Sidebar) -->
171
+ <section class="panel control-panel">
172
+ <h2 class="panel-title">PREDICTION CONFIG</h2>
173
+ <div class="control-group">
174
+ <label for="location-select">Target Location</label>
175
+ <select id="location-select" class="form-control">
176
+ <!-- Populated dynamically -->
177
+ </select>
178
+ </div>
179
+
180
+ <div class="control-group">
181
+ <label for="model-select">AI Forecasting Model</label>
182
+ <select id="model-select" class="form-control">
183
+ <option value="gradient_boosting" selected>Gradient Boosting (Real Data - 98.28% Acc)</option>
184
+ <option value="chronos">Amazon Chronos-T5 (Tiny)</option>
185
+ </select>
186
+ </div>
187
+
188
+ <div class="control-group">
189
+ <label for="forecast-slider">Forecast Horizon: <span id="forecast-val" class="value-display">7</span> Days</label>
190
+ <input type="range" id="forecast-slider" min="1" max="30" value="7" class="slider">
191
+ </div>
192
+
193
+ <div class="divider"></div>
194
+ <h3 class="panel-subtitle">Simulation Overrides</h3>
195
+
196
+ <div class="control-group">
197
+ <label for="rain-override">Manual Rain Override (mm)</label>
198
+ <div class="range-override-container">
199
+ <input type="range" id="rain-override" min="0" max="100" value="0" class="slider">
200
+ <span id="rain-override-val" class="override-display">Auto (Open-Meteo)</span>
201
+ </div>
202
+ </div>
203
+
204
+ <div class="control-group">
205
+ <label for="event-override">Crowd Event Scale (0 - 5)</label>
206
+ <input type="range" id="event-override" min="0" max="5" value="0" class="slider">
207
+ </div>
208
+
209
+ <div class="button-row">
210
+ <button id="predict-btn" class="action-btn">
211
+ <span class="btn-text">RUN PREDICTION</span>
212
+ <span class="btn-glow"></span>
213
+ </button>
214
+ <button id="export-btn" class="action-btn secondary-btn">
215
+ <span class="btn-text">EXPORT CSV</span>
216
+ <span class="btn-glow"></span>
217
+ </button>
218
+ </div>
219
+ </section>
220
+
221
+ <!-- Peta Interaktif & Main Stats -->
222
+ <section class="map-and-stats">
223
+ <!-- Peta Leaflet.js -->
224
+ <div class="panel map-panel">
225
+ <h2 class="panel-title">JAKARTA SPATIAL REALTIME MAP</h2>
226
+ <div class="map-container">
227
+ <div id="map"></div>
228
+ </div>
229
+ </div>
230
+
231
+ <!-- Stats Real-Time -->
232
+ <div class="stats-row">
233
+ <div class="panel stat-card text-glow">
234
+ <span class="card-label">TOTAL FORECAST VOLUME</span>
235
+ <span id="stat-total-volume" class="card-value">0.00 <span class="unit">Tons</span></span>
236
+ <span class="card-meta" id="stat-period-meta">Period: N/A</span>
237
+ </div>
238
+ <div class="panel stat-card">
239
+ <span class="card-label">RISK STATUS</span>
240
+ <span id="stat-risk-status" class="card-value status-badge safe">SAFE</span>
241
+ <span class="card-meta" id="stat-location-meta">Menteng</span>
242
+ </div>
243
+ <div class="panel stat-card">
244
+ <span class="card-label">RECOMMENDED FLEET</span>
245
+ <span id="stat-trucks" class="card-value">0 <span class="unit">Trucks (5T)</span></span>
246
+ <span class="card-meta">Logistics Fleet Suggestion</span>
247
+ </div>
248
+ </div>
249
+ </section>
250
+
251
+ <!-- Rincian Logistik & Analisis -->
252
+ <section class="analysis-panel">
253
+ <div class="panel category-panel">
254
+ <h2 class="panel-title">WASTE COMPOSITION BREAKDOWN</h2>
255
+ <div class="progress-container" style="display: grid; grid-template-columns: 1fr 1fr; gap: 1rem 1.5rem;">
256
+ <div class="progress-item" style="margin-bottom: 0;">
257
+ <div class="progress-header">
258
+ <span>Organic / Sisa Makanan (~50.2%)</span>
259
+ <span id="val-organic">0.00 Ton</span>
260
+ </div>
261
+ <div class="progress-bar-bg">
262
+ <div id="bar-organic" class="progress-bar-fill organic" style="width: 0%;"></div>
263
+ </div>
264
+ </div>
265
+ <div class="progress-item" style="margin-bottom: 0;">
266
+ <div class="progress-header">
267
+ <span>Plastic / Plastik (~22.8%)</span>
268
+ <span id="val-plastic">0.00 Ton</span>
269
+ </div>
270
+ <div class="progress-bar-bg">
271
+ <div id="bar-plastic" class="progress-bar-fill plastic" style="width: 0%;"></div>
272
+ </div>
273
+ </div>
274
+ <div class="progress-item" style="margin-bottom: 0;">
275
+ <div class="progress-header">
276
+ <span>Paper & Cardboard / Kertas (~11.5%)</span>
277
+ <span id="val-paper">0.00 Ton</span>
278
+ </div>
279
+ <div class="progress-bar-bg">
280
+ <div id="bar-paper" class="progress-bar-fill paper" style="width: 0%;"></div>
281
+ </div>
282
+ </div>
283
+ <div class="progress-item" style="margin-bottom: 0;">
284
+ <div class="progress-header">
285
+ <span>Glass & Ceramics / Kaca (~3.2%)</span>
286
+ <span id="val-glass">0.00 Ton</span>
287
+ </div>
288
+ <div class="progress-bar-bg">
289
+ <div id="bar-glass" class="progress-bar-fill glass" style="width: 0%;"></div>
290
+ </div>
291
+ </div>
292
+ <div class="progress-item" style="margin-bottom: 0;">
293
+ <div class="progress-header">
294
+ <span>Textile & Leather / Tekstil (~4.2%)</span>
295
+ <span id="val-textile">0.00 Ton</span>
296
+ </div>
297
+ <div class="progress-bar-bg">
298
+ <div id="bar-textile" class="progress-bar-fill textile" style="width: 0%;"></div>
299
+ </div>
300
+ </div>
301
+ <div class="progress-item" style="margin-bottom: 0;">
302
+ <div class="progress-header">
303
+ <span>Metals & Others / Logam (~8.1%)</span>
304
+ <span id="val-metal">0.00 Ton</span>
305
+ </div>
306
+ <div class="progress-bar-bg">
307
+ <div id="bar-metal" class="progress-bar-fill metal" style="width: 0%;"></div>
308
+ </div>
309
+ </div>
310
+ </div>
311
+ </div>
312
+
313
+ <!-- Widget Cuaca Live & Info Event -->
314
+ <div class="panel weather-event-panel">
315
+ <h2 class="panel-title">WEATHER & EVENT FORECAST</h2>
316
+ <div class="weather-grid">
317
+ <div class="weather-info">
318
+ <span class="weather-temp" id="weather-forecast-text">Fetching Live...</span>
319
+ <span class="weather-label" id="weather-location-text">Jakarta, Indonesia</span>
320
+ </div>
321
+ <div class="weather-details">
322
+ <div>Precipitation (Rain): <span id="weather-precip" class="highlight">0.0 mm</span></div>
323
+ <div>BMKG Alert: <span id="weather-alert" class="highlight">None</span></div>
324
+ </div>
325
+ </div>
326
+ <div class="event-box" id="event-box">
327
+ <span class="event-title">Upcoming Event Calendar</span>
328
+ <p class="event-desc" id="event-desc-text">No major events registered for today.</p>
329
+ </div>
330
+ </div>
331
+
332
+ <!-- Logistics Plan -->
333
+ <div class="panel logistics-panel">
334
+ <h2 class="panel-title">OPERATIONAL LOGISTICS PLAN</h2>
335
+ <div class="logistics-grid">
336
+ <div class="log-item">
337
+ <span class="log-label">Manpower Required</span>
338
+ <span id="log-manpower" class="log-value">0 Crew</span>
339
+ </div>
340
+ <div class="log-item">
341
+ <span class="log-label">Estimated Collection Time</span>
342
+ <span id="log-duration" class="log-value">0.0 Hours</span>
343
+ </div>
344
+ <div class="log-item">
345
+ <span class="log-label">Operational Efficiency</span>
346
+ <span id="log-efficiency" class="log-value">85% (Optimal)</span>
347
+ </div>
348
+ <div class="log-item">
349
+ <span class="log-label">Confidence Score</span>
350
+ <span id="log-confidence" class="log-value highlight">92.0%</span>
351
+ </div>
352
+ </div>
353
+ </div>
354
+ </section>
355
+ </main>
356
+
357
+ <!-- Timeline Harian -->
358
+ <section class="container timeline-container">
359
+ <div class="panel timeline-panel">
360
+ <h2 class="panel-title">DAILY TIMELINE BREAKDOWN</h2>
361
+ <div id="timeline-list" class="timeline-list">
362
+ <!-- Will be dynamically populated -->
363
+ <div class="empty-timeline">Run a prediction to generate the forecast timeline.</div>
364
+ </div>
365
+ </div>
366
+ </section>
367
+
368
+ <!-- Hourly Breakdown -->
369
+ <section id="hourly-section" class="container hourly-container" style="display: none;">
370
+ <div class="panel hourly-panel">
371
+ <h2 class="panel-title">HOURLY DISPATCH RISK HEATMAP</h2>
372
+ <div class="hourly-grid" id="hourly-grid">
373
+ <!-- Dynamically populated -->
374
+ </div>
375
+ </div>
376
+ </section>
377
+ </div>
378
+
379
+ <!-- NEWS FEED PAGE -->
380
+ <div id="page-news" class="page-container">
381
+ <section class="container page-header-section">
382
+ <h2 class="section-title">MONITORING BERITA PERSAMPAHAN JAKARTA</h2>
383
+ <p class="section-subtitle">AI merayap berita terbaru seputar isu darurat sampah, operasional TPA Bantargebang, dan kebijakan DLH Jakarta secara otomatis setiap 1 jam.</p>
384
+ </section>
385
+
386
+ <section class="container news-feed-container">
387
+ <div class="news-grid" id="news-grid-list">
388
+ <!-- Dynamically populated with news cards -->
389
+ <div class="loading-news">Fetching latest waste intelligence updates from crawler...</div>
390
+ </div>
391
+ </section>
392
+ </div>
393
+
394
+ <!-- REGIONAL ALERTS PAGE -->
395
+ <div id="page-alerts" class="page-container">
396
+ <section class="container page-header-section">
397
+ <h2 class="section-title">REGIONAL HAZARD & ALERTS MAP</h2>
398
+ <p class="section-subtitle">Daftar wilayah kecamatan dengan prakiraan volume timbulan sampah melebihi ambang batas operasional harian.</p>
399
+ </section>
400
+
401
+ <section class="container alerts-feed-container">
402
+ <div class="alerts-summary panel">
403
+ <h3 class="panel-title">ACTIVE OPERATIONAL ALERTS</h3>
404
+ <div class="alerts-list-group" id="alerts-grid-list">
405
+ <!-- Dynamically populated with alert rows -->
406
+ <div class="loading-alerts">Evaluating active regional threshold warnings...</div>
407
+ </div>
408
+ </div>
409
+ </section>
410
+ </div>
411
+
412
+ <footer>
413
+ <p>&copy; 2026 Aeterna AI - DKI Jakarta Waste Management Intelligence. Calibrated with DLH & Open-Meteo.</p>
414
+ </footer>
415
+
416
+ <!-- Scripts -->
417
+ <script src="/static/app.js"></script>
418
+ </body>
419
+ </html>
static/style.css ADDED
@@ -0,0 +1,1166 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* CSS Variables for Theming */
2
+ :root {
3
+ --bg-void: #02040a;
4
+ --bg-panel: rgba(6, 10, 22, 0.75);
5
+ --border-color: rgba(0, 240, 255, 0.12);
6
+ --border-hover: rgba(0, 240, 255, 0.3);
7
+
8
+ --text-main: #E1E3E8;
9
+ --text-muted: #8c93a3;
10
+
11
+ /* Neon Colors */
12
+ --cyan: #00F0FF;
13
+ --cyan-glow: rgba(0, 240, 255, 0.45);
14
+ --green: #39FF14;
15
+ --green-glow: rgba(57, 255, 20, 0.35);
16
+ --yellow: #FFE600;
17
+ --yellow-glow: rgba(255, 230, 0, 0.35);
18
+ --red: #FF0055;
19
+ --red-glow: rgba(255, 0, 85, 0.45);
20
+
21
+ /* Fonts */
22
+ --font-display: 'Outfit', 'Space Grotesk', system-ui, sans-serif;
23
+ --font-body: 'Space Grotesk', system-ui, sans-serif;
24
+ --font-mono: 'JetBrains Mono', monospace;
25
+ }
26
+
27
+ /* Base resets */
28
+ * {
29
+ box-sizing: border-box;
30
+ margin: 0;
31
+ padding: 0;
32
+ }
33
+
34
+ body {
35
+ background-color: var(--bg-void);
36
+ color: var(--text-main);
37
+ font-family: var(--font-body);
38
+ overflow-x: hidden;
39
+ min-height: 100vh;
40
+ display: flex;
41
+ flex-direction: column;
42
+ }
43
+
44
+ /* Background Rain Canvas */
45
+ #rain-canvas {
46
+ position: fixed;
47
+ top: 0;
48
+ left: 0;
49
+ width: 100%;
50
+ height: 100%;
51
+ z-index: 0;
52
+ pointer-events: none;
53
+ opacity: 0.45;
54
+ }
55
+
56
+ /* Header */
57
+ header {
58
+ width: 100%;
59
+ padding: 1.5rem 2.5rem;
60
+ background: linear-gradient(to bottom, rgba(2, 4, 10, 0.95) 60%, transparent);
61
+ display: flex;
62
+ justify-content: space-between;
63
+ align-items: center;
64
+ border-bottom: 1px solid rgba(255, 255, 255, 0.03);
65
+ z-index: 10;
66
+ position: relative;
67
+ }
68
+
69
+ .logo-container {
70
+ display: flex;
71
+ align-items: baseline;
72
+ gap: 10px;
73
+ }
74
+
75
+ .logo-text {
76
+ font-family: var(--font-display);
77
+ font-size: 1.8rem;
78
+ font-weight: 800;
79
+ letter-spacing: 2px;
80
+ background: linear-gradient(135deg, #FFF 40%, var(--cyan) 100%);
81
+ -webkit-background-clip: text;
82
+ -webkit-text-fill-color: transparent;
83
+ text-shadow: 0 0 20px rgba(0, 240, 255, 0.15);
84
+ }
85
+
86
+ .logo-text .highlight {
87
+ font-weight: 300;
88
+ letter-spacing: 0px;
89
+ color: var(--cyan);
90
+ margin-left: 4px;
91
+ }
92
+
93
+ .version-tag {
94
+ font-family: var(--font-mono);
95
+ font-size: 0.75rem;
96
+ color: var(--text-muted);
97
+ background: rgba(255, 255, 255, 0.05);
98
+ padding: 2px 8px;
99
+ border-radius: 4px;
100
+ border: 1px solid rgba(255, 255, 255, 0.08);
101
+ }
102
+
103
+ .system-status {
104
+ display: flex;
105
+ align-items: center;
106
+ gap: 8px;
107
+ }
108
+
109
+ .status-indicator {
110
+ width: 8px;
111
+ height: 8px;
112
+ border-radius: 50%;
113
+ }
114
+
115
+ .status-indicator.online {
116
+ background-color: var(--green);
117
+ box-shadow: 0 0 10px var(--green-glow), 0 0 20px var(--green-glow);
118
+ animation: pulse-green 2s infinite;
119
+ }
120
+
121
+ .status-label {
122
+ font-family: var(--font-mono);
123
+ font-size: 0.8rem;
124
+ color: var(--text-muted);
125
+ }
126
+
127
+ /* Grid Layout */
128
+ .dashboard-grid {
129
+ display: grid;
130
+ grid-template-columns: 320px 1fr 340px;
131
+ gap: 1.5rem;
132
+ padding: 1.5rem 2.5rem;
133
+ flex: 1;
134
+ z-index: 5;
135
+ position: relative;
136
+ }
137
+
138
+ @media (max-width: 1200px) {
139
+ .dashboard-grid {
140
+ grid-template-columns: 1fr;
141
+ }
142
+ }
143
+
144
+ /* Panels */
145
+ .panel {
146
+ background: var(--bg-panel);
147
+ border: 1px solid var(--border-color);
148
+ border-radius: 12px;
149
+ padding: 1.5rem;
150
+ backdrop-filter: blur(16px);
151
+ box-shadow: 0 8px 32px 0 rgba(0, 0, 0, 0.37);
152
+ transition: border-color 0.3s, box-shadow 0.3s;
153
+ }
154
+
155
+ .panel:hover {
156
+ border-color: var(--border-hover);
157
+ box-shadow: 0 8px 32px 0 rgba(0, 240, 255, 0.05);
158
+ }
159
+
160
+ .panel-title {
161
+ font-family: var(--font-display);
162
+ font-size: 0.95rem;
163
+ font-weight: 600;
164
+ letter-spacing: 1.5px;
165
+ color: var(--text-main);
166
+ margin-bottom: 1.2rem;
167
+ border-left: 3px solid var(--cyan);
168
+ padding-left: 8px;
169
+ text-transform: uppercase;
170
+ }
171
+
172
+ .panel-subtitle {
173
+ font-family: var(--font-display);
174
+ font-size: 0.85rem;
175
+ font-weight: 600;
176
+ color: var(--cyan);
177
+ margin-bottom: 1rem;
178
+ text-transform: uppercase;
179
+ }
180
+
181
+ /* Controls */
182
+ .control-group {
183
+ margin-bottom: 1.2rem;
184
+ }
185
+
186
+ .control-group label {
187
+ display: block;
188
+ font-size: 0.8rem;
189
+ color: var(--text-muted);
190
+ margin-bottom: 6px;
191
+ text-transform: uppercase;
192
+ font-family: var(--font-mono);
193
+ }
194
+
195
+ .form-control {
196
+ width: 100%;
197
+ background: rgba(0, 0, 0, 0.4);
198
+ border: 1px solid var(--border-color);
199
+ color: var(--text-main);
200
+ padding: 10px 14px;
201
+ border-radius: 8px;
202
+ outline: none;
203
+ font-family: var(--font-body);
204
+ font-size: 0.9rem;
205
+ transition: border-color 0.3s;
206
+ }
207
+
208
+ .form-control:focus {
209
+ border-color: var(--cyan);
210
+ }
211
+
212
+ .slider {
213
+ width: 100%;
214
+ -webkit-appearance: none;
215
+ height: 6px;
216
+ border-radius: 3px;
217
+ background: rgba(255, 255, 255, 0.1);
218
+ outline: none;
219
+ }
220
+
221
+ .slider::-webkit-slider-thumb {
222
+ -webkit-appearance: none;
223
+ width: 16px;
224
+ height: 16px;
225
+ border-radius: 50%;
226
+ background: var(--cyan);
227
+ box-shadow: 0 0 10px var(--cyan-glow);
228
+ cursor: pointer;
229
+ transition: transform 0.1s;
230
+ }
231
+
232
+ .slider::-webkit-slider-thumb:hover {
233
+ transform: scale(1.25);
234
+ }
235
+
236
+ .value-display, .override-display {
237
+ font-family: var(--font-mono);
238
+ color: var(--cyan);
239
+ font-weight: bold;
240
+ float: right;
241
+ }
242
+
243
+ .range-override-container {
244
+ display: flex;
245
+ flex-direction: column;
246
+ gap: 5px;
247
+ }
248
+
249
+ .divider {
250
+ height: 1px;
251
+ background: rgba(255, 255, 255, 0.05);
252
+ margin: 1.5rem 0;
253
+ }
254
+
255
+ /* Buttons */
256
+ .action-btn {
257
+ width: 100%;
258
+ padding: 12px;
259
+ background: rgba(0, 240, 255, 0.06);
260
+ border: 1px solid var(--cyan);
261
+ color: var(--cyan);
262
+ font-family: var(--font-mono);
263
+ font-size: 0.90rem;
264
+ font-weight: bold;
265
+ border-radius: 8px;
266
+ cursor: pointer;
267
+ position: relative;
268
+ overflow: hidden;
269
+ transition: background 0.3s, box-shadow 0.3s;
270
+ }
271
+
272
+ .action-btn:hover {
273
+ background: rgba(0, 240, 255, 0.15);
274
+ box-shadow: 0 0 20px var(--cyan-glow);
275
+ }
276
+
277
+ /* Map Panel with Leaflet Map */
278
+ .map-panel {
279
+ display: flex;
280
+ flex-direction: column;
281
+ height: 380px;
282
+ margin-bottom: 1.5rem;
283
+ }
284
+
285
+ .map-container {
286
+ flex: 1;
287
+ position: relative;
288
+ background: rgba(0, 0, 0, 0.3);
289
+ border-radius: 8px;
290
+ overflow: hidden;
291
+ border: 1px solid var(--border-color);
292
+ }
293
+
294
+ #map {
295
+ width: 100%;
296
+ height: 100%;
297
+ background: var(--bg-void) !important;
298
+ }
299
+
300
+ /* Custom Marker Styling for Leaflet */
301
+ .leaflet-custom-marker {
302
+ position: relative;
303
+ cursor: pointer;
304
+ }
305
+
306
+ .leaflet-custom-marker .marker-pulse {
307
+ position: absolute;
308
+ top: 50%;
309
+ left: 50%;
310
+ width: 28px;
311
+ height: 28px;
312
+ margin-left: -14px;
313
+ margin-top: -14px;
314
+ background: var(--cyan);
315
+ border-radius: 50%;
316
+ opacity: 0.15;
317
+ transform: scale(1);
318
+ animation: pulse-node 2s infinite;
319
+ pointer-events: none;
320
+ }
321
+
322
+ .leaflet-custom-marker .marker-core {
323
+ position: absolute;
324
+ top: 50%;
325
+ left: 50%;
326
+ width: 12px;
327
+ height: 12px;
328
+ margin-left: -6px;
329
+ margin-top: -6px;
330
+ background: var(--cyan);
331
+ border: 2px solid #FFF;
332
+ border-radius: 50%;
333
+ box-shadow: 0 0 10px var(--cyan-glow);
334
+ transition: transform 0.2s, background 0.3s;
335
+ }
336
+
337
+ .leaflet-custom-marker .marker-label {
338
+ position: absolute;
339
+ top: -24px;
340
+ left: 50%;
341
+ transform: translateX(-50%);
342
+ font-family: var(--font-mono);
343
+ font-size: 10px;
344
+ font-weight: bold;
345
+ color: var(--text-muted);
346
+ background: rgba(0, 0, 0, 0.85);
347
+ padding: 2px 6px;
348
+ border-radius: 4px;
349
+ border: 1px solid rgba(255, 255, 255, 0.15);
350
+ white-space: nowrap;
351
+ pointer-events: none;
352
+ transition: color 0.3s, border-color 0.3s;
353
+ }
354
+
355
+ /* Hover and Active State */
356
+ .leaflet-custom-marker:hover .marker-core {
357
+ transform: scale(1.2);
358
+ }
359
+
360
+ .leaflet-custom-marker.active .marker-core {
361
+ transform: scale(1.3);
362
+ background: var(--cyan);
363
+ box-shadow: 0 0 15px var(--cyan), 0 0 25px var(--cyan-glow);
364
+ }
365
+
366
+ .leaflet-custom-marker.active .marker-label {
367
+ color: var(--cyan);
368
+ border-color: var(--cyan);
369
+ box-shadow: 0 0 10px rgba(0, 240, 255, 0.2);
370
+ }
371
+
372
+ /* Risk indicator classes for Leaflet Markers */
373
+ .leaflet-custom-marker.safe .marker-core {
374
+ background: var(--green);
375
+ box-shadow: 0 0 10px var(--green-glow);
376
+ }
377
+ .leaflet-custom-marker.safe .marker-pulse {
378
+ background: var(--green);
379
+ }
380
+
381
+ .leaflet-custom-marker.warning .marker-core {
382
+ background: var(--yellow);
383
+ box-shadow: 0 0 10px var(--yellow-glow);
384
+ }
385
+ .leaflet-custom-marker.warning .marker-pulse {
386
+ background: var(--yellow);
387
+ }
388
+
389
+ .leaflet-custom-marker.critical .marker-core {
390
+ background: var(--red);
391
+ box-shadow: 0 0 10px var(--red-glow);
392
+ }
393
+ .leaflet-custom-marker.critical .marker-pulse {
394
+ background: var(--red);
395
+ }
396
+
397
+ /* Leaflet Layout UI Overrides */
398
+ .leaflet-bar {
399
+ border: 1px solid var(--border-color) !important;
400
+ border-radius: 8px !important;
401
+ overflow: hidden;
402
+ box-shadow: 0 4px 16px rgba(0, 0, 0, 0.6) !important;
403
+ }
404
+
405
+ .leaflet-bar a {
406
+ background-color: rgba(6, 10, 22, 0.85) !important;
407
+ color: var(--text-main) !important;
408
+ border-bottom: 1px solid var(--border-color) !important;
409
+ transition: background-color 0.2s, color 0.2s;
410
+ }
411
+
412
+ .leaflet-bar a:hover {
413
+ background-color: rgba(0, 240, 255, 0.15) !important;
414
+ color: var(--cyan) !important;
415
+ }
416
+
417
+ .leaflet-container {
418
+ background: var(--bg-void) !important;
419
+ }
420
+
421
+ /* Stats Cards */
422
+ .stats-row {
423
+ display: grid;
424
+ grid-template-columns: repeat(3, 1fr);
425
+ gap: 1.5rem;
426
+ }
427
+
428
+ .stat-card {
429
+ display: flex;
430
+ flex-direction: column;
431
+ justify-content: center;
432
+ padding: 1.2rem;
433
+ height: 100px;
434
+ }
435
+
436
+ .card-label {
437
+ font-family: var(--font-mono);
438
+ font-size: 0.7rem;
439
+ color: var(--text-muted);
440
+ margin-bottom: 6px;
441
+ text-transform: uppercase;
442
+ }
443
+
444
+ .card-value {
445
+ font-family: var(--font-display);
446
+ font-size: 1.5rem;
447
+ font-weight: 800;
448
+ color: #FFF;
449
+ }
450
+
451
+ .card-value .unit {
452
+ font-size: 0.85rem;
453
+ font-weight: 400;
454
+ color: var(--text-muted);
455
+ }
456
+
457
+ .status-badge {
458
+ display: inline-block;
459
+ padding: 4px 12px;
460
+ border-radius: 6px;
461
+ font-size: 0.95rem;
462
+ font-weight: bold;
463
+ text-align: center;
464
+ width: fit-content;
465
+ }
466
+
467
+ .status-badge.safe {
468
+ background: rgba(57, 255, 20, 0.08);
469
+ border: 1px solid var(--green);
470
+ color: var(--green);
471
+ text-shadow: 0 0 10px var(--green-glow);
472
+ }
473
+
474
+ .status-badge.warning {
475
+ background: rgba(255, 230, 0, 0.08);
476
+ border: 1px solid var(--yellow);
477
+ color: var(--yellow);
478
+ text-shadow: 0 0 10px var(--yellow-glow);
479
+ }
480
+
481
+ .status-badge.critical {
482
+ background: rgba(255, 0, 85, 0.08);
483
+ border: 1px solid var(--red);
484
+ color: var(--red);
485
+ text-shadow: 0 0 10px var(--red-glow);
486
+ }
487
+
488
+ /* Composition / Progress bars */
489
+ .progress-item {
490
+ margin-bottom: 1.2rem;
491
+ }
492
+
493
+ .progress-header {
494
+ display: flex;
495
+ justify-content: space-between;
496
+ font-size: 0.8rem;
497
+ color: var(--text-muted);
498
+ margin-bottom: 6px;
499
+ font-family: var(--font-mono);
500
+ }
501
+
502
+ .progress-bar-bg {
503
+ width: 100%;
504
+ height: 8px;
505
+ background: rgba(255, 255, 255, 0.05);
506
+ border-radius: 4px;
507
+ overflow: hidden;
508
+ }
509
+
510
+ .progress-bar-fill {
511
+ height: 100%;
512
+ border-radius: 4px;
513
+ width: 0%;
514
+ transition: width 0.8s cubic-bezier(0.25, 0.8, 0.25, 1);
515
+ }
516
+
517
+ .progress-bar-fill.organic {
518
+ background: linear-gradient(to right, #4CAF50, #8BC34A);
519
+ box-shadow: 0 0 10px rgba(76, 175, 80, 0.3);
520
+ }
521
+
522
+ .progress-bar-fill.plastic {
523
+ background: linear-gradient(to right, var(--cyan), #00BCD4);
524
+ box-shadow: 0 0 10px rgba(0, 240, 255, 0.3);
525
+ }
526
+
527
+ .progress-bar-fill.paper {
528
+ background: linear-gradient(to right, var(--yellow), #FF9900);
529
+ box-shadow: 0 0 10px rgba(255, 230, 0, 0.3);
530
+ }
531
+
532
+ .progress-bar-fill.glass {
533
+ background: linear-gradient(to right, var(--red), #E040FB);
534
+ box-shadow: 0 0 10px rgba(255, 0, 85, 0.3);
535
+ }
536
+
537
+ .progress-bar-fill.textile {
538
+ background: linear-gradient(to right, #CC66FF, #2196F3);
539
+ box-shadow: 0 0 10px rgba(204, 102, 255, 0.3);
540
+ }
541
+
542
+ .progress-bar-fill.metal {
543
+ background: linear-gradient(to right, #E1E3E8, var(--cyan));
544
+ box-shadow: 0 0 10px rgba(225, 227, 232, 0.3);
545
+ }
546
+
547
+ /* Weather & Event Panel */
548
+ .weather-grid {
549
+ display: flex;
550
+ justify-content: space-between;
551
+ align-items: center;
552
+ background: rgba(0, 0, 0, 0.25);
553
+ padding: 12px;
554
+ border-radius: 8px;
555
+ border: 1px solid rgba(255, 255, 255, 0.03);
556
+ margin-bottom: 1rem;
557
+ }
558
+
559
+ .weather-temp {
560
+ font-family: var(--font-display);
561
+ font-size: 1.2rem;
562
+ font-weight: 700;
563
+ color: #FFF;
564
+ }
565
+
566
+ .weather-label {
567
+ display: block;
568
+ font-size: 0.75rem;
569
+ color: var(--text-muted);
570
+ }
571
+
572
+ .weather-details {
573
+ font-family: var(--font-mono);
574
+ font-size: 0.75rem;
575
+ text-align: right;
576
+ line-height: 1.4;
577
+ }
578
+
579
+ .weather-details .highlight {
580
+ color: var(--cyan);
581
+ }
582
+
583
+ .event-box {
584
+ padding: 10px;
585
+ background: rgba(255, 230, 0, 0.03);
586
+ border-left: 3px solid var(--yellow);
587
+ border-radius: 0 6px 6px 0;
588
+ }
589
+
590
+ .event-title {
591
+ display: block;
592
+ font-size: 0.75rem;
593
+ font-weight: bold;
594
+ color: var(--yellow);
595
+ font-family: var(--font-mono);
596
+ margin-bottom: 4px;
597
+ }
598
+
599
+ .event-desc {
600
+ font-size: 0.8rem;
601
+ color: var(--text-main);
602
+ }
603
+
604
+ /* Logistics Grid */
605
+ .logistics-grid {
606
+ display: grid;
607
+ grid-template-columns: 1fr 1fr;
608
+ gap: 12px;
609
+ }
610
+
611
+ .log-item {
612
+ background: rgba(0, 0, 0, 0.2);
613
+ border: 1px solid rgba(255, 255, 255, 0.03);
614
+ border-radius: 8px;
615
+ padding: 10px;
616
+ display: flex;
617
+ flex-direction: column;
618
+ }
619
+
620
+ .log-label {
621
+ font-family: var(--font-mono);
622
+ font-size: 0.65rem;
623
+ color: var(--text-muted);
624
+ text-transform: uppercase;
625
+ margin-bottom: 4px;
626
+ }
627
+
628
+ .log-value {
629
+ font-size: 0.95rem;
630
+ font-weight: bold;
631
+ color: #FFF;
632
+ }
633
+
634
+ .log-value.highlight {
635
+ color: var(--cyan);
636
+ text-shadow: 0 0 10px var(--cyan-glow);
637
+ }
638
+
639
+ /* Timeline Container */
640
+ .timeline-container {
641
+ margin-top: 1.5rem;
642
+ padding: 0 2.5rem;
643
+ z-index: 5;
644
+ position: relative;
645
+ }
646
+
647
+ .timeline-list {
648
+ display: flex;
649
+ gap: 12px;
650
+ overflow-x: auto;
651
+ padding-bottom: 10px;
652
+ }
653
+
654
+ .timeline-card {
655
+ min-width: 140px;
656
+ background: rgba(0, 0, 0, 0.4);
657
+ border: 1px solid var(--border-color);
658
+ border-radius: 8px;
659
+ padding: 12px;
660
+ display: flex;
661
+ flex-direction: column;
662
+ align-items: center;
663
+ text-align: center;
664
+ transition: transform 0.2s, border-color 0.2s;
665
+ }
666
+
667
+ .timeline-card:hover {
668
+ transform: translateY(-4px);
669
+ border-color: var(--cyan);
670
+ }
671
+
672
+ .timeline-date {
673
+ font-family: var(--font-mono);
674
+ font-size: 0.7rem;
675
+ color: var(--text-muted);
676
+ margin-bottom: 6px;
677
+ }
678
+
679
+ .timeline-vol {
680
+ font-family: var(--font-display);
681
+ font-size: 1.1rem;
682
+ font-weight: bold;
683
+ color: #FFF;
684
+ margin-bottom: 6px;
685
+ }
686
+
687
+ .timeline-status {
688
+ font-size: 0.7rem;
689
+ padding: 2px 8px;
690
+ border-radius: 4px;
691
+ font-weight: bold;
692
+ }
693
+
694
+ .timeline-status.safe { background: rgba(57, 255, 20, 0.1); color: var(--green); }
695
+ .timeline-status.warning { background: rgba(255, 230, 0, 0.1); color: var(--yellow); }
696
+ .timeline-status.critical { background: rgba(255, 0, 85, 0.1); color: var(--red); }
697
+
698
+ .empty-timeline {
699
+ width: 100%;
700
+ text-align: center;
701
+ padding: 2rem;
702
+ color: var(--text-muted);
703
+ font-style: italic;
704
+ font-size: 0.9rem;
705
+ }
706
+
707
+ /* Hourly Breakdown Container */
708
+ .hourly-container {
709
+ margin-top: 1.5rem;
710
+ padding: 0 2.5rem;
711
+ z-index: 5;
712
+ position: relative;
713
+ margin-bottom: 2rem;
714
+ }
715
+
716
+ .hourly-grid {
717
+ display: grid;
718
+ grid-template-columns: repeat(24, 1fr);
719
+ gap: 4px;
720
+ background: rgba(0, 0, 0, 0.3);
721
+ padding: 10px;
722
+ border-radius: 8px;
723
+ overflow-x: auto;
724
+ }
725
+
726
+ .hourly-cell {
727
+ display: flex;
728
+ flex-direction: column;
729
+ align-items: center;
730
+ gap: 4px;
731
+ }
732
+
733
+ .cell-block {
734
+ width: 100%;
735
+ height: 40px;
736
+ border-radius: 4px;
737
+ transition: opacity 0.3s;
738
+ }
739
+
740
+ .cell-block.low { background-color: rgba(57, 255, 20, 0.35); border: 1px solid var(--green); }
741
+ .cell-block.medium { background-color: rgba(255, 230, 0, 0.35); border: 1px solid var(--yellow); }
742
+ .cell-block.high { background-color: rgba(255, 0, 85, 0.35); border: 1px solid var(--red); }
743
+
744
+ .cell-time {
745
+ font-family: var(--font-mono);
746
+ font-size: 8px;
747
+ color: var(--text-muted);
748
+ }
749
+
750
+ /* Footer */
751
+ footer {
752
+ width: 100%;
753
+ padding: 1.5rem;
754
+ text-align: center;
755
+ border-top: 1px solid rgba(255, 255, 255, 0.03);
756
+ color: var(--text-muted);
757
+ font-size: 0.75rem;
758
+ font-family: var(--font-mono);
759
+ margin-top: auto;
760
+ }
761
+
762
+ /* Animations */
763
+ @keyframes pulse-green {
764
+ 0% { box-shadow: 0 0 0 0 rgba(57, 255, 20, 0.4); }
765
+ 70% { box-shadow: 0 0 0 8px rgba(57, 255, 20, 0); }
766
+ 100% { box-shadow: 0 0 0 0 rgba(57, 255, 20, 0); }
767
+ }
768
+
769
+ @keyframes pulse-node {
770
+ 0% { transform: scale(0.9); opacity: 0.35; }
771
+ 70% { transform: scale(1.6); opacity: 0; }
772
+ 100% { transform: scale(0.9); opacity: 0; }
773
+ }
774
+
775
+ .card-meta {
776
+ font-family: var(--font-mono);
777
+ font-size: 0.65rem;
778
+ color: var(--text-muted);
779
+ margin-top: 6px;
780
+ display: block;
781
+ text-transform: uppercase;
782
+ }
783
+
784
+ .button-row {
785
+ display: grid;
786
+ grid-template-columns: 1fr 1fr;
787
+ gap: 10px;
788
+ }
789
+
790
+ .secondary-btn {
791
+ background: rgba(57, 255, 20, 0.04) !important;
792
+ border: 1px solid var(--green) !important;
793
+ color: var(--green) !important;
794
+ }
795
+
796
+ .secondary-btn:hover {
797
+ background: rgba(57, 255, 20, 0.12) !important;
798
+ box-shadow: 0 0 20px var(--green-glow) !important;
799
+ }
800
+
801
+
802
+ /* SPA Multi-Page Styling */
803
+ .page-container {
804
+ display: none;
805
+ opacity: 0;
806
+ transition: opacity 0.4s cubic-bezier(0.4, 0, 0.2, 1);
807
+ animation: fade-in 0.4s forwards;
808
+ padding: 1.5rem 2.5rem;
809
+ flex: 1;
810
+ z-index: 5;
811
+ position: relative;
812
+ }
813
+
814
+ .page-container.active {
815
+ display: block;
816
+ opacity: 1;
817
+ }
818
+
819
+ @keyframes fade-in {
820
+ from { opacity: 0; transform: translateY(8px); }
821
+ to { opacity: 1; transform: translateY(0); }
822
+ }
823
+
824
+ /* Nav Links in Header */
825
+ .nav-links {
826
+ display: flex;
827
+ gap: 1.25rem;
828
+ background: rgba(255, 255, 255, 0.03);
829
+ border: 1px solid rgba(255, 255, 255, 0.06);
830
+ padding: 4px;
831
+ border-radius: 8px;
832
+ }
833
+
834
+ .nav-btn {
835
+ background: transparent;
836
+ border: none;
837
+ color: var(--text-muted);
838
+ font-family: var(--font-display);
839
+ font-size: 0.85rem;
840
+ font-weight: 600;
841
+ letter-spacing: 1px;
842
+ padding: 8px 16px;
843
+ cursor: pointer;
844
+ border-radius: 6px;
845
+ transition: color 0.3s, background 0.3s, box-shadow 0.3s;
846
+ }
847
+
848
+ .nav-btn:hover {
849
+ color: var(--cyan);
850
+ background: rgba(255, 255, 255, 0.02);
851
+ }
852
+
853
+ .nav-btn.active {
854
+ color: var(--bg-void);
855
+ background: var(--cyan);
856
+ box-shadow: 0 0 15px var(--cyan-glow);
857
+ }
858
+
859
+ /* Hero Section */
860
+ .hero-section {
861
+ display: grid;
862
+ grid-template-columns: 1.2fr 0.8fr;
863
+ gap: 2rem;
864
+ align-items: center;
865
+ padding: 3rem 0;
866
+ }
867
+
868
+ @media (max-width: 900px) {
869
+ .hero-section {
870
+ grid-template-columns: 1fr;
871
+ }
872
+ }
873
+
874
+ .hero-content {
875
+ display: flex;
876
+ flex-direction: column;
877
+ gap: 1.5rem;
878
+ }
879
+
880
+ .hero-title {
881
+ font-family: var(--font-display);
882
+ font-size: 3rem;
883
+ font-weight: 800;
884
+ letter-spacing: 2px;
885
+ line-height: 1.1;
886
+ background: linear-gradient(135deg, #FFF 40%, var(--cyan) 100%);
887
+ -webkit-background-clip: text;
888
+ -webkit-text-fill-color: transparent;
889
+ text-shadow: 0 0 30px rgba(0, 240, 255, 0.15);
890
+ }
891
+
892
+ .hero-subtitle {
893
+ font-size: 1.1rem;
894
+ color: var(--text-muted);
895
+ line-height: 1.6;
896
+ }
897
+
898
+ .hero-actions {
899
+ display: flex;
900
+ gap: 1rem;
901
+ max-width: 400px;
902
+ }
903
+
904
+ .hero-stats-panel {
905
+ display: flex;
906
+ flex-direction: column;
907
+ gap: 1rem;
908
+ background: rgba(6, 10, 22, 0.6) !important;
909
+ }
910
+
911
+ .hero-stat-grid {
912
+ display: grid;
913
+ grid-template-columns: 1fr 1fr;
914
+ gap: 1rem;
915
+ }
916
+
917
+ .hero-stat-card {
918
+ background: rgba(0, 0, 0, 0.25);
919
+ border: 1px solid rgba(255, 255, 255, 0.05);
920
+ padding: 1.2rem;
921
+ border-radius: 8px;
922
+ display: flex;
923
+ flex-direction: column;
924
+ gap: 4px;
925
+ }
926
+
927
+ .h-stat-label {
928
+ font-size: 0.75rem;
929
+ font-family: var(--font-mono);
930
+ color: var(--text-muted);
931
+ text-transform: uppercase;
932
+ }
933
+
934
+ .h-stat-value {
935
+ font-size: 1.8rem;
936
+ font-family: var(--font-display);
937
+ font-weight: 800;
938
+ color: #FFF;
939
+ }
940
+
941
+ /* Features Grid */
942
+ .features-section {
943
+ padding: 2rem 0;
944
+ }
945
+
946
+ .section-title {
947
+ font-family: var(--font-display);
948
+ font-size: 1.4rem;
949
+ font-weight: 700;
950
+ letter-spacing: 1.5px;
951
+ margin-bottom: 2rem;
952
+ color: #FFF;
953
+ border-left: 3px solid var(--cyan);
954
+ padding-left: 10px;
955
+ }
956
+
957
+ .features-grid {
958
+ display: grid;
959
+ grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
960
+ gap: 1.5rem;
961
+ }
962
+
963
+ .feature-card {
964
+ display: flex;
965
+ flex-direction: column;
966
+ gap: 1rem;
967
+ transition: transform 0.3s;
968
+ }
969
+
970
+ .feature-card:hover {
971
+ transform: translateY(-4px);
972
+ }
973
+
974
+ .feature-icon {
975
+ font-size: 2rem;
976
+ font-weight: 800;
977
+ color: rgba(0, 240, 255, 0.25);
978
+ text-shadow: 0 0 10px rgba(0, 240, 255, 0.05);
979
+ }
980
+
981
+ .feature-name {
982
+ font-family: var(--font-display);
983
+ font-size: 1.05rem;
984
+ font-weight: 600;
985
+ color: var(--cyan);
986
+ }
987
+
988
+ .feature-desc {
989
+ font-size: 0.85rem;
990
+ color: var(--text-muted);
991
+ line-height: 1.6;
992
+ }
993
+
994
+ /* Page Headers */
995
+ .page-header-section {
996
+ padding: 2rem 0 1rem 0;
997
+ }
998
+
999
+ .section-subtitle {
1000
+ font-size: 0.95rem;
1001
+ color: var(--text-muted);
1002
+ margin-top: 6px;
1003
+ }
1004
+
1005
+ /* News Page Styling */
1006
+ .news-grid {
1007
+ display: grid;
1008
+ grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
1009
+ gap: 1.5rem;
1010
+ padding: 1.5rem 0;
1011
+ }
1012
+
1013
+ .news-card {
1014
+ background: var(--bg-panel);
1015
+ border: 1px solid var(--border-color);
1016
+ border-radius: 12px;
1017
+ padding: 1.5rem;
1018
+ backdrop-filter: blur(16px);
1019
+ display: flex;
1020
+ flex-direction: column;
1021
+ gap: 1rem;
1022
+ transition: transform 0.3s, border-color 0.3s, box-shadow 0.3s;
1023
+ }
1024
+
1025
+ .news-card:hover {
1026
+ transform: translateY(-3px);
1027
+ border-color: var(--border-hover);
1028
+ box-shadow: 0 8px 32px 0 rgba(0, 240, 255, 0.05);
1029
+ }
1030
+
1031
+ .news-card-header {
1032
+ display: flex;
1033
+ justify-content: space-between;
1034
+ align-items: center;
1035
+ }
1036
+
1037
+ .news-source {
1038
+ font-family: var(--font-mono);
1039
+ font-size: 0.75rem;
1040
+ background: rgba(0, 240, 255, 0.08);
1041
+ color: var(--cyan);
1042
+ padding: 2px 8px;
1043
+ border-radius: 4px;
1044
+ border: 1px solid rgba(0, 240, 255, 0.2);
1045
+ }
1046
+
1047
+ .news-date {
1048
+ font-family: var(--font-mono);
1049
+ font-size: 0.75rem;
1050
+ color: var(--text-muted);
1051
+ }
1052
+
1053
+ .news-title {
1054
+ font-family: var(--font-display);
1055
+ font-size: 1.1rem;
1056
+ font-weight: 600;
1057
+ color: #FFF;
1058
+ line-height: 1.4;
1059
+ }
1060
+
1061
+ .news-summary {
1062
+ font-size: 0.85rem;
1063
+ color: var(--text-muted);
1064
+ line-height: 1.6;
1065
+ }
1066
+
1067
+ .news-link {
1068
+ margin-top: auto;
1069
+ display: inline-flex;
1070
+ align-items: center;
1071
+ color: var(--cyan);
1072
+ text-decoration: none;
1073
+ font-family: var(--font-mono);
1074
+ font-size: 0.8rem;
1075
+ font-weight: bold;
1076
+ gap: 6px;
1077
+ transition: gap 0.2s;
1078
+ }
1079
+
1080
+ .news-link:hover {
1081
+ gap: 10px;
1082
+ }
1083
+
1084
+ .loading-news, .loading-alerts {
1085
+ grid-column: 1 / -1;
1086
+ text-align: center;
1087
+ padding: 3rem;
1088
+ color: var(--text-muted);
1089
+ font-family: var(--font-mono);
1090
+ font-size: 0.9rem;
1091
+ }
1092
+
1093
+ /* Alerts Page Styling */
1094
+ .alerts-summary {
1095
+ margin-top: 1.5rem;
1096
+ }
1097
+
1098
+ .alerts-list-group {
1099
+ display: flex;
1100
+ flex-direction: column;
1101
+ gap: 1rem;
1102
+ }
1103
+
1104
+ .alert-row {
1105
+ display: grid;
1106
+ grid-template-columns: 120px 180px 100px 1fr;
1107
+ gap: 1rem;
1108
+ align-items: center;
1109
+ background: rgba(0, 0, 0, 0.2);
1110
+ border: 1px solid rgba(255, 255, 255, 0.04);
1111
+ padding: 1rem 1.5rem;
1112
+ border-radius: 8px;
1113
+ transition: background 0.3s;
1114
+ }
1115
+
1116
+ @media (max-width: 768px) {
1117
+ .alert-row {
1118
+ grid-template-columns: 1fr 1fr;
1119
+ }
1120
+ }
1121
+
1122
+ .alert-row:hover {
1123
+ background: rgba(255, 255, 255, 0.02);
1124
+ }
1125
+
1126
+ .alert-date {
1127
+ font-family: var(--font-mono);
1128
+ font-size: 0.85rem;
1129
+ color: var(--text-muted);
1130
+ }
1131
+
1132
+ .alert-location {
1133
+ font-family: var(--font-display);
1134
+ font-weight: 600;
1135
+ color: #FFF;
1136
+ }
1137
+
1138
+ .alert-badge {
1139
+ font-family: var(--font-mono);
1140
+ font-size: 0.75rem;
1141
+ font-weight: bold;
1142
+ padding: 3px 8px;
1143
+ border-radius: 4px;
1144
+ text-align: center;
1145
+ }
1146
+
1147
+ .alert-badge.critical {
1148
+ background: rgba(255, 0, 85, 0.12);
1149
+ color: var(--red);
1150
+ border: 1px solid var(--red);
1151
+ box-shadow: 0 0 10px rgba(255, 0, 85, 0.1);
1152
+ }
1153
+
1154
+ .alert-badge.warning {
1155
+ background: rgba(255, 230, 0, 0.12);
1156
+ color: var(--yellow);
1157
+ border: 1px solid var(--yellow);
1158
+ box-shadow: 0 0 10px rgba(255, 230, 0, 0.1);
1159
+ }
1160
+
1161
+ .alert-desc {
1162
+ font-size: 0.85rem;
1163
+ color: var(--text-muted);
1164
+ }
1165
+
1166
+
train.py CHANGED
@@ -1,12 +1,19 @@
1
  import pandas as pd
2
  import numpy as np
3
  from sklearn.ensemble import GradientBoostingRegressor
4
- from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score
 
5
  import joblib
 
6
  import io
7
  import warnings
8
  warnings.filterwarnings('ignore')
9
 
 
 
 
 
 
10
  print("🚀 MEMULAI PROSES TRAINING AI LEVEL ADVANCED (ECO-TWIN PRO)...\n")
11
 
12
  # ==========================================
@@ -15,7 +22,7 @@ print("🚀 MEMULAI PROSES TRAINING AI LEVEL ADVANCED (ECO-TWIN PRO)...\n")
15
  print("📥 1. Menarik & Memproses Data Historis (2023 - 2024)...")
16
 
17
  # Baseline Sampah (Diambil dari SIPSN DKI 2025)
18
- base_sampah = 1050.50
19
  mrt_harian_avg = 85000
20
  hujan_mean = 10.5
21
 
@@ -88,34 +95,79 @@ train_size = int(len(df) * 0.75) # 75% data awal
88
  X_train, X_test = X.iloc[:train_size], X.iloc[train_size:]
89
  y_train, y_test = y.iloc[:train_size], y.iloc[train_size:]
90
 
91
- # Menggunakan Gradient Boosting (State-of-the-Art)
92
- model = GradientBoostingRegressor(
 
93
  n_estimators=200,
94
  learning_rate=0.1,
95
  max_depth=4,
96
  random_state=42
97
  )
98
- model.fit(X_train, y_train)
 
 
 
 
 
 
 
99
 
100
  # ==========================================
101
- # 4. EVALUASI AKURASI (BUAT DIPAMERIN KE JURI)
102
  # ==========================================
103
- prediksi = model.predict(X_test)
104
- rmse = mean_squared_error(y_test, prediksi) ** 0.5
105
- mae = mean_absolute_error(y_test, prediksi)
106
- r2 = r2_score(y_test, prediksi)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
107
 
108
- print("\n📊 HASIL EVALUASI MODEL (METRICS):")
109
- print(f" ✅ Root Mean Squared Error (RMSE) : {rmse:.2f} Ton")
110
- print(f" ✅ Mean Absolute Error (MAE) : {mae:.2f} Ton")
111
- print(f" ✅ R-Squared (R2 Score) : {r2 * 100:.2f}% (Tingkat Kepercayaan AI)")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
112
 
113
  # Cek Fitur Paling Berpengaruh
114
- importances = model.feature_importances_
115
- print("\n🌟 FITUR PALING BERPENGARUH PADA TIMBULAN SAMPAH:")
116
  for name, importance in zip(fitur, importances):
117
  print(f" - {name}: {importance*100:.1f}%")
118
 
119
- # Simpan Model
120
- joblib.dump(model, 'model_sampah_advanced.pkl')
121
- print("\n💾 SUCCESS! 'model_sampah_advanced.pkl' berhasil di-generate!")
 
 
1
  import pandas as pd
2
  import numpy as np
3
  from sklearn.ensemble import GradientBoostingRegressor
4
+ from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score, mean_absolute_percentage_error
5
+ from sklearn.model_selection import GridSearchCV
6
  import joblib
7
+ import sys
8
  import io
9
  import warnings
10
  warnings.filterwarnings('ignore')
11
 
12
+ # Set standard output and standard error to UTF-8 to prevent Unicode encoding errors on Windows
13
+ if sys.platform == 'win32':
14
+ sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
15
+ sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding='utf-8')
16
+
17
  print("🚀 MEMULAI PROSES TRAINING AI LEVEL ADVANCED (ECO-TWIN PRO)...\n")
18
 
19
  # ==========================================
 
22
  print("📥 1. Menarik & Memproses Data Historis (2023 - 2024)...")
23
 
24
  # Baseline Sampah (Diambil dari SIPSN DKI 2025)
25
+ base_sampah = 8020.0
26
  mrt_harian_avg = 85000
27
  hujan_mean = 10.5
28
 
 
95
  X_train, X_test = X.iloc[:train_size], X.iloc[train_size:]
96
  y_train, y_test = y.iloc[:train_size], y.iloc[train_size:]
97
 
98
+ # Menggunakan Gradient Boosting Regressor (Baseline)
99
+ print("⚙️ Melatih model Baseline...")
100
+ base_model = GradientBoostingRegressor(
101
  n_estimators=200,
102
  learning_rate=0.1,
103
  max_depth=4,
104
  random_state=42
105
  )
106
+ base_model.fit(X_train, y_train)
107
+ pred_base = base_model.predict(X_test)
108
+
109
+ # Hitung Metrics Baseline
110
+ mae_base = mean_absolute_error(y_test, pred_base)
111
+ rmse_base = mean_squared_error(y_test, pred_base) ** 0.5
112
+ r2_base = r2_score(y_test, pred_base)
113
+ mape_base = mean_absolute_percentage_error(y_test, pred_base) * 100
114
 
115
  # ==========================================
116
+ # 4. HYPERPARAMETER TUNING (UPGRADE MODEL)
117
  # ==========================================
118
+ print("\n⚙️ Melakukan Hyperparameter Tuning menggunakan GridSearchCV...")
119
+ param_grid = {
120
+ 'n_estimators': [100, 200, 300],
121
+ 'learning_rate': [0.03, 0.05, 0.1, 0.15],
122
+ 'max_depth': [3, 4, 5],
123
+ 'subsample': [0.8, 0.9, 1.0]
124
+ }
125
+
126
+ grid_search = GridSearchCV(
127
+ estimator=GradientBoostingRegressor(random_state=42),
128
+ param_grid=param_grid,
129
+ cv=3,
130
+ scoring='neg_mean_absolute_error',
131
+ n_jobs=-1,
132
+ verbose=1
133
+ )
134
+ grid_search.fit(X_train, y_train)
135
+
136
+ best_model = grid_search.best_estimator_
137
+ pred_best = best_model.predict(X_test)
138
 
139
+ # Hitung Metrics Upgraded Model
140
+ mae_best = mean_absolute_error(y_test, pred_best)
141
+ rmse_best = mean_squared_error(y_test, pred_best) ** 0.5
142
+ r2_best = r2_score(y_test, pred_best)
143
+ mape_best = mean_absolute_percentage_error(y_test, pred_best) * 100
144
+
145
+ # ==========================================
146
+ # 5. PERBANDINGAN METRICS (BUAT DIPAMERIN KE JURI)
147
+ # ==========================================
148
+ print("\n📊 HASIL EVALUASI & PERBANDINGAN METRICS:")
149
+ print(f"┌─────────────────────────┬──────────────────────┬──────────────────────┬──────────────────────┐")
150
+ print(f"│ Metric │ Baseline Model │ Upgraded Model │ Status │")
151
+ print(f"├─────────────────────────┼──────────────────────┼──────────────────────┼──────────────────────┤")
152
+ print(f"│ Mean Absolute Error │ {mae_base:16.2f} Ton │ {mae_best:16.2f} Ton │ {'Semakin Baik (⬇️)' if mae_best < mae_base else 'Sama/Stabil'} │")
153
+ print(f"│ Root Mean Squared Error │ {rmse_base:16.2f} Ton │ {rmse_best:16.2f} Ton │ {'Semakin Baik (⬇️)' if rmse_best < rmse_base else 'Sama/Stabil'} │")
154
+ print(f"│ R-Squared (R² Score) │ {r2_base*100:15.2f}% │ {r2_best*100:15.2f}% │ {'Semakin Baik (⬆️)' if r2_best > r2_base else 'Sama/Stabil'} │")
155
+ print(f"│ MAPE (Error Persentase) │ {mape_base:15.2f}% │ {mape_best:15.2f}% │ {'Semakin Baik (⬇️)' if mape_best < mape_base else 'Sama/Stabil'} │")
156
+ print(f"└─────────────────────────┴──────────────────────┴──────────────────────┴──────────────────────┘")
157
+
158
+ print(f"\n⚙️ Hyperparameter Terbaik hasil tuning:")
159
+ print(f" - n_estimators : {grid_search.best_params_['n_estimators']}")
160
+ print(f" - learning_rate: {grid_search.best_params_['learning_rate']}")
161
+ print(f" - max_depth : {grid_search.best_params_['max_depth']}")
162
+ print(f" - subsample : {grid_search.best_params_['subsample']}")
163
 
164
  # Cek Fitur Paling Berpengaruh
165
+ importances = best_model.feature_importances_
166
+ print("\n🌟 FITUR PALING BERPENGARUH PADA TIMBULAN SAMPAH (UPGRADED):")
167
  for name, importance in zip(fitur, importances):
168
  print(f" - {name}: {importance*100:.1f}%")
169
 
170
+ # Simpan Model Terbaik
171
+ joblib.dump(best_model, 'model_sampah_advanced.pkl')
172
+ print("\n💾 SUCCESS! 'model_sampah_advanced.pkl' berhasil di-generate menggunakan model hasil upgrade!")
173
+
waste_intelligence_api.postman_collection.json ADDED
@@ -0,0 +1,193 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "info": {
3
+ "_postman_id": "8e3d0ab4-8fb2-47d3-9bc4-3b604e339d2c",
4
+ "name": "Waste Intelligence API - DKI Jakarta 2026",
5
+ "description": "Koleksi request Postman untuk menguji seluruh endpoint Waste Intelligence API (DKI Jakarta 2026) tingkat kecamatan. Pastikan server Uvicorn menyala di port 8001 sebelum menjalankan pengujian.",
6
+ "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
7
+ },
8
+ "item": [
9
+ {
10
+ "name": "1. System Health Check",
11
+ "request": {
12
+ "method": "GET",
13
+ "header": [],
14
+ "url": {
15
+ "raw": "{{baseUrl}}/status",
16
+ "host": [
17
+ "{{baseUrl}}"
18
+ ],
19
+ "path": [
20
+ "status"
21
+ ]
22
+ },
23
+ "description": "Mengecek apakah server FastAPI online dan memastikan model AI Amazon Chronos serta Gradient Boosting sudah termuat dengan benar."
24
+ },
25
+ "response": []
26
+ },
27
+ {
28
+ "name": "2. Run Waste Prediction (Chronos - Daily)",
29
+ "request": {
30
+ "method": "POST",
31
+ "header": [
32
+ {
33
+ "key": "Content-Type",
34
+ "value": "application/json",
35
+ "type": "text"
36
+ }
37
+ ],
38
+ "body": {
39
+ "mode": "raw",
40
+ "raw": "{\n \"forecast_days\": 7,\n \"rainfall_mm\": 0.0,\n \"event_scale\": 0,\n \"location\": \"Kemayoran\",\n \"granularity\": \"daily\",\n \"model_type\": \"chronos\"\n}"
41
+ },
42
+ "url": {
43
+ "raw": "{{baseUrl}}/api/v1/predict",
44
+ "host": [
45
+ "{{baseUrl}}"
46
+ ],
47
+ "path": [
48
+ "api",
49
+ "v1",
50
+ "predict"
51
+ ]
52
+ },
53
+ "description": "Menjalankan prediksi baseline volume timbulan sampah menggunakan model AI Amazon Chronos (Transformer) dengan granularity harian untuk Kecamatan Kemayoran."
54
+ },
55
+ "response": []
56
+ },
57
+ {
58
+ "name": "3. Run Waste Prediction (Gradient Boosting - Hourly with Overrides)",
59
+ "request": {
60
+ "method": "POST",
61
+ "header": [
62
+ {
63
+ "key": "Content-Type",
64
+ "value": "application/json",
65
+ "type": "text"
66
+ }
67
+ ],
68
+ "body": {
69
+ "mode": "raw",
70
+ "raw": "{\n \"forecast_days\": 3,\n \"rainfall_mm\": 45.0,\n \"event_scale\": 4,\n \"location\": \"Tanah Abang\",\n \"granularity\": \"hourly\",\n \"model_type\": \"gradient_boosting\"\n}"
71
+ },
72
+ "url": {
73
+ "raw": "{{baseUrl}}/api/v1/predict",
74
+ "host": [
75
+ "{{baseUrl}}"
76
+ ],
77
+ "path": [
78
+ "api",
79
+ "v1",
80
+ "predict"
81
+ ]
82
+ },
83
+ "description": "Menjalankan prediksi menggunakan model Gradient Boosting dengan granularity per jam, menyertakan simulasi hujan lebat (45 mm) dan event keramaian skala 4 di Kecamatan Tanah Abang."
84
+ },
85
+ "response": []
86
+ },
87
+ {
88
+ "name": "4. Export Prediction to CSV File",
89
+ "request": {
90
+ "method": "POST",
91
+ "header": [
92
+ {
93
+ "key": "Content-Type",
94
+ "value": "application/json",
95
+ "type": "text"
96
+ }
97
+ ],
98
+ "body": {
99
+ "mode": "raw",
100
+ "raw": "{\n \"forecast_days\": 7,\n \"rainfall_mm\": 0.0,\n \"event_scale\": 0,\n \"location\": \"Senen\",\n \"granularity\": \"daily\",\n \"model_type\": \"gradient_boosting\"\n}"
101
+ },
102
+ "url": {
103
+ "raw": "{{baseUrl}}/api/v1/predict/csv",
104
+ "host": [
105
+ "{{baseUrl}}"
106
+ ],
107
+ "path": [
108
+ "api",
109
+ "v1",
110
+ "predict",
111
+ "csv"
112
+ ]
113
+ },
114
+ "description": "Mengirim parameter input prediksi dan langsung mengunduh hasilnya dalam format berkas .csv untuk Kecamatan Senen."
115
+ },
116
+ "response": []
117
+ },
118
+ {
119
+ "name": "5. Get Real-time Operational Alerts",
120
+ "request": {
121
+ "method": "GET",
122
+ "header": [],
123
+ "url": {
124
+ "raw": "{{baseUrl}}/api/v1/alerts?location=Senen",
125
+ "host": [
126
+ "{{baseUrl}}"
127
+ ],
128
+ "path": [
129
+ "api",
130
+ "v1",
131
+ "alerts"
132
+ ],
133
+ "query": [
134
+ {
135
+ "key": "location",
136
+ "value": "Senen",
137
+ "description": "Filter peringatan hanya untuk lokasi Senen (opsional)"
138
+ }
139
+ ]
140
+ },
141
+ "description": "Mengambil status peringatan operasional (WARNING/CRITICAL) secara dinamis untuk 3 hari ke depan."
142
+ },
143
+ "response": []
144
+ },
145
+ {
146
+ "name": "6. Get Latest Waste News",
147
+ "request": {
148
+ "method": "GET",
149
+ "header": [],
150
+ "url": {
151
+ "raw": "{{baseUrl}}/api/v1/news",
152
+ "host": [
153
+ "{{baseUrl}}"
154
+ ],
155
+ "path": [
156
+ "api",
157
+ "v1",
158
+ "news"
159
+ ]
160
+ },
161
+ "description": "Mengambil umpan berita persampahan terbaru di DKI Jakarta yang dirayap oleh AI setiap 1 jam."
162
+ },
163
+ "response": []
164
+ }
165
+ ],
166
+ "event": [
167
+ {
168
+ "listen": "prerequest",
169
+ "script": {
170
+ "type": "text/javascript",
171
+ "exec": [
172
+ ""
173
+ ]
174
+ }
175
+ },
176
+ {
177
+ "listen": "test",
178
+ "script": {
179
+ "type": "text/javascript",
180
+ "exec": [
181
+ ""
182
+ ]
183
+ }
184
+ }
185
+ ],
186
+ "variable": [
187
+ {
188
+ "key": "baseUrl",
189
+ "value": "http://localhost:8001",
190
+ "type": "string"
191
+ }
192
+ ]
193
+ }