const baseUrl = ""; const apiPrefix = "/api"; // DEBUG: Check if JS is loaded console.log("JS Loaded"); alert("DEBUG: JS LOADED SUCCESSFULLY! Klik OK untuk melanjutkan."); function formatRupiah(angka) { var number_string = angka.toString(), sisa = number_string.length % 3, rupiah = number_string.substr(0, sisa), ribuan = number_string.substr(sisa).match(/\d{3}/g); if (ribuan) { separator = sisa ? '.' : ''; rupiah += separator + ribuan.join('.'); } return 'Rp ' + rupiah; } function openTab(evt, tabName, btn) { var i, tabcontent, tablinks; tabcontent = document.getElementsByClassName("tab-content"); for (i = 0; i < tabcontent.length; i++) { tabcontent[i].style.display = "none"; } tablinks = document.getElementsByClassName("tab-button"); for (i = 0; i < tablinks.length; i++) { tablinks[i].className = tablinks[i].className.replace(" active", ""); } document.getElementById(tabName).style.display = "block"; if (btn) { btn.className += " active"; } else if (evt && evt.currentTarget) { evt.currentTarget.className += " active"; } } // Robust Initialization function logToPage(message) { const logDiv = document.getElementById('debug-log'); if (logDiv) { const entry = document.createElement('div'); entry.textContent = `[${new Date().toLocaleTimeString()}] ${message}`; entry.style.borderBottom = "1px solid #ddd"; logDiv.appendChild(entry); logDiv.scrollTop = logDiv.scrollHeight; } console.log(message); } function initDashboard() { logToPage("๐ Initializing Dashboard Logic..."); // Visual Debugging: Green underline on title to prove JS ran const title = document.querySelector('h1'); if (title) { title.style.borderBottom = "5px solid #4caf50"; title.setAttribute('title', 'JS Active'); } // --- Modul 9: Dasbor Rekomendasi Terpadu --- const integratedForm = document.getElementById('integrated-recommendation-form'); const resultIntegratedDiv = document.getElementById('result-integrated'); if (integratedForm) { logToPage("โ Modul 9 Form Found"); integratedForm.style.borderLeft = "5px solid #4caf50"; // Visual confirmation integratedForm.addEventListener('submit', async (event) => { event.preventDefault(); logToPage('๐ Modul 9: Integrated Recommendation form submitted!'); // Create result div if it doesn't exist (it might be missing in HTML) let targetDiv = resultIntegratedDiv; if (!targetDiv) { targetDiv = document.createElement('div'); targetDiv.id = 'result-integrated'; targetDiv.className = 'result-box'; targetDiv.style.marginTop = '20px'; integratedForm.parentNode.appendChild(targetDiv); } targetDiv.innerHTML = '
Sedang memproses rekomendasi terpadu...
'; const requestData = { ketinggian: document.getElementById('ketinggian-select').value, iklim: document.getElementById('iklim-select').value, fase: document.getElementById('fase-select').value, masalah: document.getElementById('masalah-select').value }; try { logToPage(`Fetching: ${baseUrl}${apiPrefix}/recommendation/integrated`); const response = await fetch(`${baseUrl}${apiPrefix}/recommendation/integrated`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(requestData) }); logToPage(`Response Status: ${response.status}`); const data = await response.json(); logToPage(`Data Received: ${JSON.stringify(data).substring(0, 50)}...`); if (data.success) { const rec = data.data; let html = `Kriteria: ${rec.bibit.kriteria}
Contoh Varietas: ${rec.bibit.rekomendasi.join(', ')}
Tips: ${rec.bibit.tips}
`; // 2. Pemupukan html += `${rec.pengendalian}
`; } else { const p = rec.pengendalian; html += `${p.strategy.description}
Tidak ada rekomendasi pengendalian spesifik.
`; } targetDiv.innerHTML = html; } else { targetDiv.innerHTML = `Error: ${data.error}
`; } } catch (error) { console.error("Error:", error); logToPage(`Error: ${error.message}`); targetDiv.innerHTML = `Error: Gagal terhubung ke server.
`; } }); } // --- Logika untuk Modul 1 (Analisis BWD) --- const formBwd = document.getElementById('upload-form'); const resultBwdDiv = document.getElementById('result-bwd'); const bwdInput = document.getElementById('bwd-input'); if (formBwd) { formBwd.addEventListener('submit', async (event) => { event.preventDefault(); console.log('๐ Modul 1: BWD Analysis: Form submitted!'); resultBwdDiv.innerHTML = 'Menganalisis gambar...
'; const formData = new FormData(formBwd); try { const response = await fetch(`${baseUrl}${apiPrefix}/analysis/bwd`, { method: 'POST', body: formData }); if (!response.ok && response.status !== 201) { throw new Error(`HTTP error! status: ${response.status}`); } const data = await response.json(); if (data.success) { resultBwdDiv.innerHTML = `Skor BWD: ${data.bwd_score} | Kepercayaan: ${data.confidence_percent}%
`; if (bwdInput) bwdInput.value = data.bwd_score; } else { resultBwdDiv.innerHTML = `Error: ${data.message || data.error}
`; } } catch (error) { console.error("Error:", error); resultBwdDiv.innerHTML = `Error: Gagal terhubung.
`; } }); } // --- Logika untuk Modul 12 (Panduan Budidaya) --- const guideForm = document.getElementById('guide-form'); const resultGuideDiv = document.getElementById('result-guide'); if (guideForm) { guideForm.addEventListener('submit', async (event) => { event.preventDefault(); const guideSelect = document.getElementById('guide-commodity-select'); if (!guideSelect.value) return; resultGuideDiv.style.display = 'block'; resultGuideDiv.innerHTML = 'Memuat panduan...
'; try { const commodity = guideSelect.value; const response = await fetch(`${baseUrl}${apiPrefix}/knowledge/guide/${commodity}`); const data = await response.json(); if (data.success) { const gd = data.data; let html = `${gd.description}
`; html += 'Asumsi: Lahan ${analysis.assumptions.Luas_Lahan}, populasi ${analysis.assumptions.Populasi_Tanaman}.
`; html += `| Komponen | Kebutuhan | Biaya |
|---|---|---|
| ${i.item} | ${i.amount} | ${formatRupiah(i.cost)} |
| Total Biaya | ${formatRupiah(totalCost)} | |
| Skenario Harga | Panen Konservatif | Panen Optimal |
|---|---|---|
| ${s.price_level} (${formatRupiah(s.price_per_kg)}/kg) | ${formatRupiah(revCons)} | ${formatRupiah(revOpt)} |
Error: ${data.error}
`; } } catch (error) { console.error("Error:", error); resultGuideDiv.innerHTML = `Gagal terhubung.
`; } }); } // --- Logika untuk Modul 13 (Pusat Pengetahuan pH) --- const showPhBtn = document.getElementById('show-ph-info-btn'); const resultPhDiv = document.getElementById('result-ph-info'); if (showPhBtn) { showPhBtn.addEventListener('click', async (event) => { event.preventDefault(); if (resultPhDiv.style.display === 'block') { resultPhDiv.style.display = 'none'; showPhBtn.textContent = 'Tampilkan Informasi Lengkap'; return; } resultPhDiv.style.display = 'block'; showPhBtn.textContent = 'Sembunyikan Informasi'; resultPhDiv.innerHTML = 'Memuat informasi...
'; try { const response = await fetch(`${baseUrl}${apiPrefix}/knowledge/ph-info`); if (!response.ok && response.status !== 201) { throw new Error(`HTTP error! status: ${response.status}`); } const data = await response.json(); if (data.success) { const pd = data.data; let html = `Error: ${data.error}
`; } } catch (error) { console.error("Error:", error); resultPhDiv.innerHTML = `Gagal terhubung.
`; } }); } // --- Logika untuk Modul 14 (Rekomendasi Tanaman) --- const cropForm = document.getElementById('crop-recommendation-form'); const resultCropDiv = document.getElementById('result-crop'); if (cropForm) { cropForm.addEventListener('submit', async (event) => { event.preventDefault(); resultCropDiv.innerHTML = 'Menganalisis data dan mencari rekomendasi terbaik...
'; const requestData = { n_value: document.getElementById('crop-n-input').value, p_value: document.getElementById('crop-p-input').value, k_value: document.getElementById('crop-k-input').value, temperature: document.getElementById('crop-temp-input').value, humidity: document.getElementById('crop-humidity-input').value, ph: document.getElementById('crop-ph-input').value, rainfall: document.getElementById('crop-rainfall-input').value }; try { const response = await fetch(`${baseUrl}${apiPrefix}/ml/recommend-crop`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(requestData) }); const responseData = await response.json(); if (responseData.success) { resultCropDiv.innerHTML = `${responseData.recommended_crop}
Rekomendasi ini dihasilkan oleh model Machine Learning berdasarkan data yang Anda masukkan.
`; } else { resultCropDiv.innerHTML = `Error: ${responseData.error}
`; } } catch (error) { console.error("Error:", error); resultCropDiv.innerHTML = `Error: Tidak dapat terhubung ke server.
`; } }); } // --- Logika untuk Modul 15 (Prediksi Panen) --- const yieldForm = document.getElementById('yield-prediction-form'); const resultYieldDiv = document.getElementById('result-yield'); if (yieldForm) { yieldForm.addEventListener('submit', async (event) => { event.preventDefault(); resultYieldDiv.innerHTML = 'Menganalisis data dan membuat prediksi...
'; const requestData = { nitrogen: document.getElementById('yield-n-input').value, phosphorus: document.getElementById('yield-p-input').value, potassium: document.getElementById('yield-k-input').value, temperature: document.getElementById('yield-temp-input').value, rainfall: document.getElementById('yield-rainfall-input').value, ph: document.getElementById('yield-ph-input').value, }; try { const response = await fetch(`${baseUrl}${apiPrefix}/ml/predict-yield`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(requestData) }); const responseData = await response.json(); if (responseData.success) { resultYieldDiv.innerHTML = `${responseData.predicted_yield_ton_ha} ton/ha
Estimasi ini dihasilkan oleh model Machine Learning berdasarkan data yang Anda masukkan.
`; } else { resultYieldDiv.innerHTML = `Error: ${responseData.error}
`; } } catch (error) { console.error("Error:", error); resultYieldDiv.innerHTML = `Error: Tidak dapat terhubung ke server.
`; } }); } // --- Logika untuk Modul 16 (Prediksi Panen XAI) --- const xaiYieldForm = document.getElementById('xai-yield-prediction-form'); const resultXaiYieldDiv = document.getElementById('result-xai-yield'); let importanceChart; if (xaiYieldForm) { xaiYieldForm.addEventListener('submit', async (event) => { event.preventDefault(); resultXaiYieldDiv.style.display = 'block'; resultXaiYieldDiv.innerHTML = 'Menganalisis data dengan XAI...
'; const requestData = { nitrogen: document.getElementById('xai-nitrogen').value, phosphorus: document.getElementById('xai-phosphorus').value, potassium: document.getElementById('xai-potassium').value, temperature: document.getElementById('xai-temperature').value, rainfall: document.getElementById('xai-rainfall').value, ph: document.getElementById('xai-ph').value, }; try { const response = await fetch(`${baseUrl}${apiPrefix}/ml/predict-yield-advanced`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(requestData) }); const data = await response.json(); if (data.success) { if (importanceChart) { importanceChart.destroy(); } let htmlResult = `Estimasi Panen: ${data.predicted_yield_ton_ha} ton/ha
Analisis ini menjelaskan mengapa prediksi Anda berbeda dari rata-rata (${data.base_value} ton/ha).
Error: ${data.error}
`; } } catch (error) { console.error('Error fetching XAI prediction:', error); resultXaiYieldDiv.innerHTML = `Error: Tidak dapat terhubung ke server.
`; } }); } // --- Logika untuk Modul 17 (Kalkulator Konversi Pupuk) --- const fertConversionForm = document.getElementById('fertilizer-conversion-form'); const resultFertConversionDiv = document.getElementById('result-fertilizer-conversion'); if (fertConversionForm) { fertConversionForm.addEventListener('submit', async (event) => { event.preventDefault(); resultFertConversionDiv.innerHTML = 'Menghitung konversi...
'; const requestData = { nutrient_needed: document.getElementById('nutrient-needed-select').value, nutrient_amount_kg: document.getElementById('nutrient-amount-input').value, fertilizer_type: document.getElementById('fertilizer-type-select').value }; try { const response = await fetch(`${baseUrl}${apiPrefix}/ml/calculate-fertilizer-bags`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(requestData) }); const data = await response.json(); if (data.success) { resultFertConversionDiv.innerHTML = `Untuk memenuhi kebutuhan ${data.nutrient_amount_kg} kg unsur hara ${data.nutrient_needed}, Anda memerlukan:
${data.required_fertilizer_kg} kg pupuk ${data.fertilizer_name}
`; } else { resultFertConversionDiv.innerHTML = `Error: ${data.error}
`; } } catch (error) { console.error("Error:", error); resultFertConversionDiv.innerHTML = `Error: Tidak dapat terhubung ke server.
`; } }); } // --- Logika untuk Modul 18 (Diagnostik Gejala Cerdas) --- const startBtn = document.getElementById('start-diagnostic-btn'); const questionsDiv = document.getElementById('diagnostic-questions'); const resultDiv = document.getElementById('diagnostic-result'); let diagnosticTree = null; if (startBtn) { async function startDiagnostic() { startBtn.style.display = 'none'; questionsDiv.style.display = 'block'; resultDiv.style.display = 'none'; resultDiv.innerHTML = ''; questionsDiv.innerHTML = 'Memuat data diagnostik...
'; try { if (!diagnosticTree) { const response = await fetch(`${baseUrl}${apiPrefix}/knowledge/diagnostic-tree`); const responseData = await response.json(); if (responseData.success) { diagnosticTree = responseData.data; } else { throw new Error(responseData.error); } } renderQuestion(diagnosticTree.start, []); } catch (error) { console.error("Error:", error); questionsDiv.innerHTML = `Error: ${error.message}
`; } } function renderQuestion(node, path) { questionsDiv.innerHTML = `${diagnosis}
`; document.getElementById('restart-diagnostic-btn').onclick = () => { startBtn.style.display = 'block'; questionsDiv.style.display = 'none'; resultDiv.style.display = 'none'; return; } }; startBtn.addEventListener('click', startDiagnostic); } // --- Logika untuk Modul 19 (Perencana Hasil Panen) --- const yieldPlanForm = document.getElementById('yield-plan-form'); const resultYieldPlanDiv = document.getElementById('result-yield-plan'); if (yieldPlanForm) { yieldPlanForm.addEventListener('submit', async (event) => { event.preventDefault(); resultYieldPlanDiv.innerHTML = 'Mencari resep lahan optimal...
'; const requestData = { commodity: document.getElementById('plan-commodity-select').value, target_yield: document.getElementById('plan-target-yield-input').value }; try { const response = await fetch(`${baseUrl}${apiPrefix}/ml/generate-yield-plan`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(requestData) }); const data = await response.json(); if (data.success) { let htmlResult = `Untuk mencapai target panen sekitar ${requestData.target_yield} ton/ha, berikut adalah resep kondisi lahan berdasarkan data kami yang paling mendekati:
Error: ${data.error}
`; } } catch (error) { console.error("Error:", error); resultYieldPlanDiv.innerHTML = `Error: Gagal terhubung ke server.
`; } }); } // --- Logika untuk Modul 21 (Analis Risiko Keberhasilan) --- const successPredictionForm = document.getElementById('success-prediction-form'); const resultSuccessPredictionDiv = document.getElementById('result-success-prediction'); if (successPredictionForm) { successPredictionForm.addEventListener('submit', async (event) => { event.preventDefault(); console.log('๐ Modul 21: Success Prediction form submitted!'); resultSuccessPredictionDiv.innerHTML = 'Menganalisis probabilitas keberhasilan...
'; const requestData = { nitrogen: document.getElementById('sp-nitrogen').value, phosphorus: document.getElementById('sp-phosphorus').value, potassium: document.getElementById('sp-potassium').value, temperature: document.getElementById('sp-temperature').value, rainfall: document.getElementById('sp-rainfall').value, ph: document.getElementById('sp-ph').value, penggunaan_benih: document.getElementById('sp-benih').value, aplikasi_organik: document.getElementById('sp-organik').value, manajemen_gulma: document.getElementById('sp-gulma').value }; try { const response = await fetch(`${baseUrl}${apiPrefix}/ml/predict-success`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(requestData) }); const data = await response.json(); if (data.success) { const statusColor = data.status === "Berhasil" ? "text-green-600" : "text-red-600"; resultSuccessPredictionDiv.innerHTML = `Berdasarkan parameter yang Anda masukkan, status rencana tanam Anda adalah:
${data.status}
Dengan probabilitas keberhasilan sebesar ${data.probability_of_success}%
`; } else { resultSuccessPredictionDiv.innerHTML = `Error: ${data.error}
`; } } catch (error) { console.error('Error fetching success probability:', error); resultSuccessPredictionDiv.innerHTML = `Error: Tidak dapat terhubung ke server.
`; } }); } // --- Logika untuk Modul 20 (Dokter Tanaman Canggih - Roboflow AI) --- const advancedDiseaseForm = document.getElementById('advanced-disease-form'); const resultAdvancedDiseaseDiv = document.getElementById('result-advanced-disease'); if (advancedDiseaseForm) { advancedDiseaseForm.addEventListener('submit', async (event) => { event.preventDefault(); console.log('๐ Modul 20: Roboflow form submitted!'); resultAdvancedDiseaseDiv.innerHTML = 'Menganalisis dengan Roboflow AI...
'; const fileInput = document.getElementById('disease-image-input'); const file = fileInput.files[0]; if (!file) { resultAdvancedDiseaseDiv.innerHTML = `Error: Silakan pilih file gambar terlebih dahulu.
`; return; } const formData = new FormData(); formData.append('file', file); try { const response = await fetch(`${baseUrl}${apiPrefix}/analysis/disease-advanced`, { method: 'POST', body: formData }); const backendResponse = await response.json(); if (backendResponse.success) { displayRoboflowResults(backendResponse.data); } else { resultAdvancedDiseaseDiv.innerHTML = `Error dari server: ${backendResponse.error || 'Gagal menganalisis.'}
`; } } catch (error) { console.error('Error calling backend for advanced analysis:', error); resultAdvancedDiseaseDiv.innerHTML = `Error: Tidak dapat terhubung ke server backend Anda.
`; } }); function displayRoboflowResults(results) { let html = 'Tidak ada hasil deteksi atau klasifikasi yang ditemukan dalam gambar.
'; } resultAdvancedDiseaseDiv.innerHTML = html; } } } // Run initialization when DOM is ready if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', initDashboard); } else { initDashboard(); }