TIF_E41253368/api/README.md

7.8 KiB

API Prediksi Harga Cabai

API ini menggunakan Flask, application factory, dan Blueprint pada prefix /api/v1. Model LSTM tidak dilatih ulang dan artifact di models/ hanya dimuat satu kali saat startup.

Menjalankan di Windows

Dari folder api dengan environment Python proyek:

pip install -r requirements.txt
python main.py

Untuk menghentikan proses backend lama dan menjalankannya kembali dengan auto-reloader:

cd C:\PrediksiHargaCabe\api
powershell -ExecutionPolicy Bypass -File .\restart_backend.ps1

Skrip tersebut menghentikan proses backend proyek pada port 8000, lalu menjalankan Flask dengan FLASK_DEBUG=1. Perubahan file Python akan dimuat otomatis selama proses tetap berjalan.

Environment yang tersedia:

  • MODELS_DIR: lokasi folder model, default api/models.
  • DATA_DIR: lokasi data CSV historis, default folder api karena file aktual berada di sana.
  • DATA_SOURCE: sumber data aktif, mysql (default) atau csv.
  • MYSQL_HOST, MYSQL_PORT, MYSQL_DATABASE, MYSQL_USER, MYSQL_PASSWORD: koneksi database MySQL melalui PyMySQL.
  • MYSQL_CONNECT_TIMEOUT: batas waktu koneksi database dalam detik.
  • PRICE_UNIT_SCALE: pengali nilai CSV ke Rupiah penuh, default 1000; sumber CSV penelitian menyimpan 12.000 sebagai 12 ribu Rupiah.
  • CORS_ORIGINS: daftar origin dipisahkan koma; default http://127.0.0.1:5173,http://localhost:5173 untuk development dengan session login.
  • ALLOWED_HORIZONS: default 1,3,7.
  • MAX_HORIZON: default 7.

Endpoint

  • GET /api/v1/health
  • GET /api/v1/commodities
  • GET /api/v1/markets?commodity=rawit
  • GET /api/v1/history?commodity=rawit&market=pasar_tanjung&days=90
  • GET /api/v1/predict?commodity=rawit&market=pasar_tanjung&horizon=7
  • GET /api/v1/predict/map?commodity=rawit&horizon=7

Semua error memakai format { "error": { "code": "...", "message": "...", "details": {} } }.

Format data historis

Dengan DATA_SOURCE=mysql, loader membaca tabel price_history dan melakukan join ke commodities serta markets menggunakan slug. Dengan DATA_SOURCE=csv, loader membaca file aktual harga_cabai_rawit_*.csv, harga_cabe_merah_besar_*.csv, dan harga_cabai_merah_keriting_*.csv dari DATA_DIR. Pada mode CSV, kolom tanggal dapat bernama Tanggal, dan kolom pasar memakai nama Pasar_Tanjung, Pasar_Kreongan, Pasar_Tegal_Besar, Pasar_Mangli, serta Pasar_Wirolegi. Harga bernilai 0, N/A, atau kosong diperlakukan sebagai NaN; hanya gap internal sampai dua titik yang diinterpolasi linear.

Menghubungkan ke MySQL phpMyAdmin

  1. Pastikan service MySQL pada XAMPP/Laragon/WAMP sedang berjalan.
  2. Pastikan database yang dipakai adalah prediksicabe.
  3. Pastikan tabel commodities, markets, dan price_history ada.
  4. Isi data harga ke price_history; seed SQL hanya mengisi master komoditas dan pasar.
  5. Set environment variable pada terminal; file .env.example hanya template dan belum dibaca otomatis oleh aplikasi.
  6. Isi MYSQL_USER dan MYSQL_PASSWORD sesuai akun MySQL lokal.
  7. Jalankan API dari folder api.

Untuk membuat akun admin, daftar dahulu melalui endpoint register atau halaman register website, lalu ubah role akun tersebut melalui phpMyAdmin:

UPDATE users
SET role = 'admin'
WHERE email = 'email-admin-anda@example.com';

Password tetap disimpan dalam bentuk hash oleh API; jangan memasukkan password ke query SQL.

Endpoint admin yang sudah tersedia:

  • GET /api/v1/admin/overview
  • GET /api/v1/admin/models
  • GET /api/v1/admin/scraping/logs
  • GET /api/v1/admin/scraping/logs/<log_id>/records
  • POST /api/v1/admin/scraping/jobs
  • GET /api/v1/admin/scraping/jobs/<job_id>
  • POST /api/v1/admin/preprocessing/jobs dengan {"scraping_log_id": 123} untuk memproses satu riwayat scraping yang dipilih.
  • GET /api/v1/admin/preprocessing/jobs/<job_id>
  • DELETE /api/v1/admin/scraping/history
  • DELETE /api/v1/admin/scraping/logs/<log_id>
  • POST /api/v1/admin/scraping/refresh
  • GET /api/v1/prices?page=1&limit=25 (admin)

Panel admin sekarang memiliki menu dataset dan pembaruan data manual. Endpoint refresh mengambil tabel SISKAPERBAPO, menyimpan observasi baru atau perubahan ke price_history, dan mencatat proses ke scraping_logs. Endpoint records menampilkan tanggal, komoditas, pasar, dan harga dari hasil scraping terakhir. Data baru tidak melatih ulang model; model deployment yang sudah aktif tetap digunakan untuk inference. Scheduler, preprocessing aktif, dan training aktif tetap tidak dijalankan.

Endpoint jobs menerima opsi commodities (array slug), start_date, dan end_date. Jika rentang tanggal dipilih, jumlah observasi dihitung otomatis sebagai hasil tanggal yang tersedia dikalikan pasar yang berhasil dibaca. Proses berjalan di background dan dapat dipantau melalui endpoint status job; panel admin menampilkan progress bar. Penghapusan history menghapus log scraping dan baris price_history dengan source = 'siskaperbapo' saja, sehingga data hasil import CSV tetap aman. Setiap observasi scraping memiliki scraping_log_id, sehingga tombol trash pada baris log menghapus hanya log tersebut dan data yang dihasilkan proses itu. Jika database lama digunakan, application factory otomatis menambahkan kolom dan mengaitkan observasi SISKAPERBAPO lama ke log terakhir.

Konfigurasi scraper:

$env:SISKAPERBAPO_URL="https://siskaperbapo.jatimprov.go.id/harga-komoditas"
$env:SISKAPERBAPO_COMMODITY_PARAM="komoditas"
$env:SISKAPERBAPO_TIMEOUT="30"
$env:SISKAPERBAPO_COMMODITIES="rawit"

Tahap awal scraper dibatasi ke rawit agar tidak mengisi komoditas lain dengan data yang salah apabila halaman sumber mengabaikan parameter komoditas. Tambahkan slug lain setelah URL/parameter sumber sudah diverifikasi. Jika struktur halaman SISKAPERBAPO berubah atau parameter komoditas berbeda, endpoint akan mengembalikan error dan mencatat detailnya sebagai scraping gagal; sistem tidak membuat data sukses palsu.

Untuk mengisi tabel price_history dari CSV penelitian secara manual satu kali:

cd C:\PrediksiHargaCabe\api
C:/Users/alfia/anaconda3/envs/tf_gpu39/python.exe scripts/import_csv_to_mysql.py

Script ini hanya melakukan import manual dan tidak membuat scheduler atau auto-scraping. Jika dijalankan lagi, constraint unik tanggal/komoditas/pasar mencegah duplikat dan nilai akan diperbarui.

Contoh PowerShell:

cd C:\PrediksiHargaCabe\api
$env:DATA_SOURCE="mysql"
$env:MYSQL_DATABASE="prediksicabe"
$env:MYSQL_USER="root"
$env:MYSQL_PASSWORD=""
python main.py

Uji koneksi melalui endpoint:

http://127.0.0.1:8000/api/v1/history?commodity=rawit&market=pasar_tanjung&days=30

Jika response menyatakan tidak ada data, koneksi berhasil tetapi baris harga belum ada untuk kombinasi tersebut. Jika muncul Gagal membaca database MySQL, periksa service MySQL, port, username, password, dan nama database.

Asumsi dan keterbatasan

  • Koordinat pada app/data/markets.json berasal dari spesifikasi dan perlu diverifikasi manual sebelum dipakai sebagai titik final peta.
  • keriting memakai time_step=14. Config dan H5 yang tersedia untuk Kreongan, Mangli, dan Wirolegi sekarang sudah memiliki input 14 langkah dan dapat dipakai oleh registry.
  • Folder model Keriting untuk Tanjung dan Tegal Besar tidak lengkap dan dilaporkan pada /api/v1/health.
  • Evaluasi model yang tersedia adalah satu hari ke depan. Prediksi 7, 24, dan 30 hari memakai recursive forecasting, sehingga error dapat menumpuk dan tidak boleh dianggap memiliki akurasi satu hari.
  • Harga API adalah Rupiah penuh. Scaler/model yang dilatih dalam ribuan Rupiah harus disesuaikan saat artifact inference divalidasi; CSV historis juga harus mengikuti unit yang sama dengan proses training.
  • Semua nilai positif yang disimpan ke price_history menggunakan Rupiah penuh. Scraper menormalkan nilai sumber yang masih dalam ribuan sebelum menyimpannya; nilai 0 diperlakukan sebagai data kosong.