docs: write comprehensive frontend and backend documentation
Browse files- BACKEND_DOC.md +133 -0
- FRONTEND_API_DOC.md +87 -257
BACKEND_DOC.md
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Aeterna AI - Backend Architecture & ML Engine Documentation (v4.0.0)
|
| 2 |
+
|
| 3 |
+
Dokumen ini menjelaskan detail teknis arsitektur sistem backend, model machine learning (Gradient Boosting & Amazon Chronos), rekayasa fitur (*feature engineering*), serta panduan kontainerisasi dan *deployment* untuk **Aeterna AI (Waste Intelligence Platform)**.
|
| 4 |
+
|
| 5 |
+
---
|
| 6 |
+
|
| 7 |
+
## 🏗️ 1. Desain Arsitektur Backend
|
| 8 |
+
|
| 9 |
+
Backend Aeterna AI dibangun menggunakan **FastAPI (Python)**, sebuah kerangka kerja web asinkron dengan performa tinggi yang setara dengan Node.js dan Go.
|
| 10 |
+
|
| 11 |
+
```
|
| 12 |
+
+-----------------------------------------------------------------+
|
| 13 |
+
| FASTAPI BACKEND |
|
| 14 |
+
| |
|
| 15 |
+
| [ /api/v1/predict ] [ /api/v1/autopilot ] [ /api/v1/news ]
|
| 16 |
+
| | | | |
|
| 17 |
+
| v v | |
|
| 18 |
+
| +---------------+ +------------------+ | |
|
| 19 |
+
| | Chronos T5 | | GBR Model | | |
|
| 20 |
+
| | Transformer | | (GridSearchCV) | | |
|
| 21 |
+
| +---------------+ +------------------+ | |
|
| 22 |
+
| | | | |
|
| 23 |
+
| +------------+------------+ | |
|
| 24 |
+
| | | |
|
| 25 |
+
| v v |
|
| 26 |
+
| +-----------------------+ +-------------+ |
|
| 27 |
+
| | Feature Engineering | | News DB | |
|
| 28 |
+
| | - Weather (OpenMeteo) | | (JSON) | |
|
| 29 |
+
| | - Event Multipliers | +-------------+ |
|
| 30 |
+
| | - Spatial Calibration | |
|
| 31 |
+
| +-----------------------+ |
|
| 32 |
+
+-----------------------------------------------------------------+
|
| 33 |
+
```
|
| 34 |
+
|
| 35 |
+
### Komponen Utama:
|
| 36 |
+
1. **Asynchronous Handling**: Memanfaatkan FastAPI dengan `run_in_threadpool` untuk menjalankan inferensi deep learning (Chronos Transformer) tanpa memblokir thread event loop utama.
|
| 37 |
+
2. **CORS Security Middleware**: Dikonfigurasi secara wildcard (`*`) untuk mengizinkan aplikasi client-side (seperti dashboard Vercel) melakukan kueri asinkron lintas asal (*cross-origin*).
|
| 38 |
+
3. **Automatic Swagger Docs**: Endpoint mendefinisikan tipe data masukan menggunakan model **Pydantic** yang secara otomatis membuat spesifikasi OpenAPI dan dokumentasi interaktif di `/docs`.
|
| 39 |
+
|
| 40 |
+
---
|
| 41 |
+
|
| 42 |
+
## 🧠 2. Mesin Machine Learning (ML Engine)
|
| 43 |
+
|
| 44 |
+
Aeterna AI mengadopsi arsitektur model hibrida:
|
| 45 |
+
|
| 46 |
+
### A. Gradient Boosting Regressor (GBR) - Model Prediksi Harian
|
| 47 |
+
Model regresi teroptimasi yang memprediksi volume timbulan sampah harian tingkat kecamatan berdasarkan fitur-fitur spasial dan kontekstual.
|
| 48 |
+
* **Hyperparameter Terbaik (GridSearchCV)**:
|
| 49 |
+
* `n_estimators` (Jumlah pohon keputusan): **100**
|
| 50 |
+
* `learning_rate` (Laju pembelajaran): **0.03**
|
| 51 |
+
* `max_depth` (Kedalaman pohon maksimal): **3**
|
| 52 |
+
* `subsample` (Rasio sampel acak per pohon): **0.9**
|
| 53 |
+
* **Metrik Evaluasi Model**:
|
| 54 |
+
* **Mean Absolute Error (MAE)**: `132.29 Ton` (Rata-rata kesalahan tebakan sekitar 132 ton).
|
| 55 |
+
* **Root Mean Squared Error (RMSE)**: `165.46 Ton` (Tebakan stabil tanpa kesalahan ekstrem).
|
| 56 |
+
* **R-Squared ($R^2$ Score)**: `81.51%` (81.5% pola data berhasil dijelaskan oleh fitur).
|
| 57 |
+
* **Mean Absolute Percentage Error (MAPE)**: **`1.59%`** (Tingkat persentase kesalahan di bawah 2%, masuk kategori *Highly Accurate Forecasting*).
|
| 58 |
+
|
| 59 |
+
### B. Amazon Chronos-T5 (Tiny) - Model Deret Waktu (Time-Series)
|
| 60 |
+
Model Transformer terlatih dari Amazon yang digunakan untuk memprediksi tren masa depan 7 s.d. 30 hari ke depan pada kueri simulasi. Chronos membaca barisan data historis dan melakukan peramalan probabilistik (diambil kuantil median `0.5`).
|
| 61 |
+
|
| 62 |
+
---
|
| 63 |
+
|
| 64 |
+
## 🌦️ 3. Rekayasa Fitur Dinamis (Feature Engineering)
|
| 65 |
+
|
| 66 |
+
AI mengalibrasi prediksi mentah berdasarkan faktor riil eksternal:
|
| 67 |
+
|
| 68 |
+
### A. Multiplier Curah Hujan (Rainfall Multiplier)
|
| 69 |
+
Sampah terbuka di Tempat Penampungan Sementara (TPS) menyerap air hujan, yang meningkatkan berat massa jenis sampah basah.
|
| 70 |
+
* Sistem memanggil **Open-Meteo API** secara dinamis menggunakan titik koordinat presisi dari kecamatan target.
|
| 71 |
+
* **Multiplier Formula**:
|
| 72 |
+
$$\text{Volume}_{\text{calibrated}} = \text{Volume}_{\text{pred}} \times \left(1.0 + \frac{\text{Precipitation (mm)}}{1000} \right)$$
|
| 73 |
+
*Curah hujan lebat (misal 50 mm) akan menambah berat jenis timbulan sekitar 5%.*
|
| 74 |
+
|
| 75 |
+
### B. Multiplier Skala Keramaian & Event (Event Multiplier)
|
| 76 |
+
Jadwal acara besar Jakarta (`event_jakarta_2026.txt`) dipindai secara berkala berdasarkan tanggal kueri.
|
| 77 |
+
* Jika ada event aktif, sistem mendeteksi nama acara dan skala keramaian (1 s.d. 5).
|
| 78 |
+
* **Skala Multiplier**:
|
| 79 |
+
* Skala 1 s.d. 2 (Keramaian lokal): **+10% s.d. +15%** volume sampah.
|
| 80 |
+
* Skala 3 s.d. 4 (Keramaian regional, misal BTN Marathon): **+20% s.d. +25%** volume sampah.
|
| 81 |
+
* Skala 5 (Keramaian masif, misal Idul Fitri): **+30% s.d. +35%** volume sampah.
|
| 82 |
+
|
| 83 |
+
---
|
| 84 |
+
|
| 85 |
+
## ⏰ 4. Timezone-Aware Engine (WIB / Asia/Jakarta)
|
| 86 |
+
|
| 87 |
+
Agar hasil prediksi antara server lokal pengembang dan server Hugging Face (yang biasanya berlokasi di Amerika Serikat) sinkron 100%, backend Aeterna AI dilengkapi dengan pengunci zona waktu WIB (UTC+7):
|
| 88 |
+
|
| 89 |
+
```python
|
| 90 |
+
from datetime import datetime, timezone, timedelta
|
| 91 |
+
|
| 92 |
+
def get_jakarta_now() -> datetime:
|
| 93 |
+
# Memaksa system time menggunakan Waktu Indonesia Barat (WIB)
|
| 94 |
+
return datetime.now(timezone(timedelta(hours=7)))
|
| 95 |
+
```
|
| 96 |
+
Semua query default, pencocokan kalender event, serta umpan berita menggunakan `get_jakarta_now()` untuk mencegah pergeseran penanggalan akibat perbedaan lokasi server fisik.
|
| 97 |
+
|
| 98 |
+
---
|
| 99 |
+
|
| 100 |
+
## 🐳 5. Panduan Kontainerisasi & Deployment (Hugging Face Spaces)
|
| 101 |
+
|
| 102 |
+
Aplikasi dideploy ke **Hugging Face Spaces** menggunakan **Docker**.
|
| 103 |
+
|
| 104 |
+
### Berkas Dockerfile:
|
| 105 |
+
```dockerfile
|
| 106 |
+
FROM python:3.11-slim
|
| 107 |
+
|
| 108 |
+
# System setup
|
| 109 |
+
WORKDIR /code
|
| 110 |
+
RUN apt-get update && apt-get install -y git && rm -rf /var/lib/apt/lists/*
|
| 111 |
+
|
| 112 |
+
# Install dependencies
|
| 113 |
+
COPY requirements.txt .
|
| 114 |
+
RUN pip install --no-cache-dir -r requirements.txt
|
| 115 |
+
|
| 116 |
+
# Copy application files
|
| 117 |
+
COPY . .
|
| 118 |
+
|
| 119 |
+
# Expose port (Hugging Face standard port)
|
| 120 |
+
CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "7860"]
|
| 121 |
+
```
|
| 122 |
+
|
| 123 |
+
### Langkah Deployment ke Hugging Face:
|
| 124 |
+
1. Buat Space baru di Hugging Face, pilih SDK **Docker** (Blank template).
|
| 125 |
+
2. Tambahkan remote git Hugging Face ke repositori lokal Anda:
|
| 126 |
+
```bash
|
| 127 |
+
git remote add huggingface https://huggingface.co/spaces/USERNAME/SPACE_NAME
|
| 128 |
+
```
|
| 129 |
+
3. Dorong perubahan langsung ke Space:
|
| 130 |
+
```bash
|
| 131 |
+
git push huggingface main
|
| 132 |
+
```
|
| 133 |
+
4. Hugging Face akan mendeteksi `Dockerfile`, membangun *image*, dan menyalakan API pada port `7860` secara otomatis.
|
FRONTEND_API_DOC.md
CHANGED
|
@@ -1,289 +1,119 @@
|
|
| 1 |
-
# Aeterna AI - Front-End API Integration Guide (v4.0.0)
|
| 2 |
|
| 3 |
-
Dokumen ini ditujukan bagi
|
| 4 |
|
| 5 |
---
|
| 6 |
|
| 7 |
-
## 📡 Konfigurasi
|
| 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 |
-
|
| 57 |
-
|
| 58 |
-
|
| 59 |
-
|
| 60 |
-
|
| 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 |
-
##
|
| 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 |
-
*
|
| 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 |
-
|
| 140 |
-
|
|
|
|
| 141 |
|
| 142 |
-
|
| 143 |
-
*
|
| 144 |
-
|
| 145 |
-
|
| 146 |
-
|
| 147 |
-
|
| 148 |
-
|
| 149 |
-
|
| 150 |
-
|
| 151 |
-
|
| 152 |
-
|
| 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 |
-
##
|
| 204 |
-
Mengunduh berkas tabel data hasil simulasi prediksi.
|
| 205 |
|
| 206 |
-
|
| 207 |
-
* **Method**: `POST`
|
| 208 |
-
* **Request Body**: Sama dengan request `/api/v1/predict`
|
| 209 |
-
* **Response**: Binary Blob (`text/csv` stream file).
|
| 210 |
|
| 211 |
-
|
| 212 |
-
|
| 213 |
-
|
| 214 |
-
|
|
|
|
|
|
|
|
|
|
| 215 |
|
| 216 |
-
|
| 217 |
-
|
| 218 |
-
|
| 219 |
-
|
| 220 |
-
|
| 221 |
-
|
| 222 |
-
|
| 223 |
-
|
| 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 |
-
##
|
| 240 |
|
| 241 |
-
|
| 242 |
|
| 243 |
```javascript
|
| 244 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 245 |
|
| 246 |
-
|
| 247 |
|
| 248 |
-
|
| 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 |
-
|
| 260 |
-
|
| 261 |
-
|
| 262 |
-
|
| 263 |
-
|
| 264 |
-
|
| 265 |
-
|
| 266 |
-
|
| 267 |
-
}
|
| 268 |
}
|
| 269 |
|
| 270 |
-
|
| 271 |
-
|
| 272 |
-
|
| 273 |
-
|
| 274 |
-
|
| 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 |
```
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Aeterna AI - Front-End API Integration & UI Development Guide (v4.0.0)
|
| 2 |
|
| 3 |
+
Dokumen ini ditujukan sebagai panduan bagi developer Front-End (FE) untuk mengintegrasikan antarmuka pengguna dengan backend **Aeterna AI (Waste Intelligence Platform)**, menjelaskan konfigurasi perutean, Leaflet map, interaktivitas, dan visualisasi chart.
|
| 4 |
|
| 5 |
---
|
| 6 |
|
| 7 |
+
## 📡 1. Konfigurasi Dynamic Routing & Vercel Compatibility
|
|
|
|
|
|
|
|
|
|
| 8 |
|
| 9 |
+
Untuk memastikan frontend dapat dipublikasikan secara terpisah di **Vercel** dan berkomunikasi secara aman dengan API backend di **Hugging Face Spaces**, perutean URL disetel secara dinamis di `frontend/app.js`:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 10 |
|
| 11 |
+
```javascript
|
| 12 |
+
// Deteksi otomatis domain client untuk perutean API
|
| 13 |
+
const API_BASE_URL = window.location.hostname === "localhost" || window.location.hostname === "127.0.0.1"
|
| 14 |
+
? "" // Menggunakan path relatif jika berjalan di lokal (localhost)
|
| 15 |
+
: "https://alamdieng-waste-prediction-api.hf.space"; // Mengarah langsung ke API Hugging Face jika di-host di Vercel
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 16 |
```
|
| 17 |
+
Semua pemanggilan AJAX `fetch()` harus menggunakan template literal `${API_BASE_URL}` (contoh: `fetch(`${API_BASE_URL}/api/v1/news`)`).
|
| 18 |
|
| 19 |
---
|
| 20 |
|
| 21 |
+
## 🗺️ 2. Integrasi Leaflet Map & Custom Markers
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 22 |
|
| 23 |
+
Peta interaktif menggunakan **Leaflet.js** untuk memvisualisasikan timbulan sampah di 44 kecamatan:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 24 |
|
| 25 |
+
### A. Pengelompokan Kelas Risiko Spasial
|
| 26 |
+
Tiap penanda (marker) kecamatan di peta memiliki kelas CSS dinamis berdasarkan tingkat bahayanya:
|
| 27 |
+
* `.safe`: Warna hijau (`--green`), menyala redup.
|
| 28 |
+
* `.warning`: Warna kuning (`--yellow`), berdenyut sedang.
|
| 29 |
+
* `.critical`: Warna merah (`--red`), berdenyut kencang.
|
| 30 |
|
| 31 |
+
### B. Route Drawing & Haversine Formula
|
| 32 |
+
Ketika penanda kecamatan diklik, rute pengiriman logistik langsung digambar ke **TPST Bantargebang** (`[-6.3477, 106.9939]`):
|
| 33 |
+
```javascript
|
| 34 |
+
// polyline digambar putus-putus berwarna cyan bercahaya
|
| 35 |
+
routeLine = L.polyline([startCoords, BANTARGEBANG_COORDS], {
|
| 36 |
+
color: '#00F0FF',
|
| 37 |
+
weight: 3.5,
|
| 38 |
+
opacity: 0.75,
|
| 39 |
+
dashArray: '8, 8',
|
| 40 |
+
className: 'glowing-route'
|
| 41 |
+
}).addTo(map);
|
| 42 |
+
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 43 |
|
| 44 |
---
|
| 45 |
|
| 46 |
+
## 🖱️ 3. Interaktivitas Cyber HUD & Custom Cursor
|
|
|
|
| 47 |
|
| 48 |
+
UI terinspirasi dari `floodzy.id` menggunakan kursor delay kustom di desktop:
|
|
|
|
|
|
|
|
|
|
| 49 |
|
| 50 |
+
### A. Animasi Kursor Lerp (Linear Interpolation)
|
| 51 |
+
Kursor dibagi menjadi dua bagian: titik tengah (`#cursor-dot`) dan cincin luar (`#cursor-ring`). Cincin luar bergerak mengikuti kursor dengan sedikit delay menggunakan rumus interpolasi lerp:
|
| 52 |
+
```javascript
|
| 53 |
+
// Lerp formula untuk pergerakan cincin kursor yang smooth
|
| 54 |
+
ringX += (mouseX - ringX) * 0.15;
|
| 55 |
+
ringY += (mouseY - ringY) * 0.15;
|
| 56 |
+
```
|
| 57 |
|
| 58 |
+
### B. Hover State
|
| 59 |
+
Saat kursor melintasi elemen interaktif (tombol, tautan berita, baris alert), kelas `.hover-state` diterapkan ke cincin luar untuk memperbesar ukurannya dan memancarkan bias cahaya cyan:
|
| 60 |
+
```javascript
|
| 61 |
+
document.querySelectorAll("a, button, select, input, .alert-row").forEach(el => {
|
| 62 |
+
el.addEventListener("mouseenter", () => cursorRing.classList.add("hover-state"));
|
| 63 |
+
el.addEventListener("mouseleave", () => cursorRing.classList.remove("hover-state"));
|
| 64 |
+
});
|
| 65 |
+
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 66 |
|
| 67 |
---
|
| 68 |
|
| 69 |
+
## 🚨 4. Aliran Navigasi Interaktif (Clickable Alerts & Autopilot)
|
| 70 |
|
| 71 |
+
Semua baris peringatan di tab **REGIONAL ALERTS** dan daftar **Top 5 High-Risk** di halaman Autopilot dikonfigurasi agar dapat diklik oleh pengguna untuk berpindah halaman dan menampilkan detail secara otomatis:
|
| 72 |
|
| 73 |
```javascript
|
| 74 |
+
row.addEventListener("click", () => {
|
| 75 |
+
// 1. Pilih kecamatan target di dropdown
|
| 76 |
+
selectedLocation = item.location;
|
| 77 |
+
if (locationSelect) locationSelect.value = item.location;
|
| 78 |
+
|
| 79 |
+
// 2. Geser dan fokuskan peta ke kecamatan target
|
| 80 |
+
updateActiveMapMarker(item.location);
|
| 81 |
+
panToLocation(item.location);
|
| 82 |
+
fetchLiveWeather(item.location);
|
| 83 |
+
|
| 84 |
+
// 3. Pindah tab navigasi ke menu "SIMULATION TOOL"
|
| 85 |
+
switchPage("page-predictor");
|
| 86 |
+
|
| 87 |
+
// 4. Jalankan inferensi AI secara instan setelah tab terbuka
|
| 88 |
+
setTimeout(() => {
|
| 89 |
+
runPrediction();
|
| 90 |
+
}, 500);
|
| 91 |
+
});
|
| 92 |
+
```
|
| 93 |
+
|
| 94 |
+
---
|
| 95 |
|
| 96 |
+
## 📊 5. Format Data Tipe Komposisi & Truk Sampah
|
| 97 |
|
| 98 |
+
Timbulan sampah total dipecah menjadi 6 kategori persentase untuk divisualisasikan dalam bentuk progress bar neon di UI:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 99 |
|
| 100 |
+
```typescript
|
| 101 |
+
interface WasteCompositionBreakdown {
|
| 102 |
+
organic_waste_ton: number; // ~50.2% (Sisa Makanan)
|
| 103 |
+
plastic_waste_ton: number; // ~22.8% (Plastik)
|
| 104 |
+
paper_waste_ton: number; // ~11.5% (Kertas)
|
| 105 |
+
glass_waste_ton: number; // ~3.2% (Kaca)
|
| 106 |
+
textile_waste_ton: number; // ~4.2% (Tekstil)
|
| 107 |
+
metal_waste_ton: number; // ~8.1% (Logam/Lainnya)
|
|
|
|
| 108 |
}
|
| 109 |
|
| 110 |
+
interface LogisticsPlan {
|
| 111 |
+
trucks_needed: number; // Total timbulan / 5 Ton kapasitas truk
|
| 112 |
+
manpower: number; // Jumlah truk * 4 crew (1 sopir + 3 petugas)
|
| 113 |
+
estimated_duration_hours: number; // Jarak rute / 28 km/jam kecepatan truk
|
| 114 |
+
efficiency_rate: string; // Status efisiensi rute pengangkutan
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 115 |
}
|
| 116 |
```
|
| 117 |
+
Untuk memperbarui lebar grafik bar di HTML, hitung persentase dinamis:
|
| 118 |
+
$$\text{Width (\%)} = \left( \frac{\text{Kategori Ton}}{\text{Total Timbulan Ton}} \right) \times 100$$
|
| 119 |
+
Lalu masukkan nilainya ke CSS `style.width` masing-masing baris.
|