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 = `

๐ŸŒฑ Hasil Rekomendasi Terpadu

`; // 1. Bibit html += `

๐ŸŒพ Rekomendasi Bibit & Varietas

Kriteria: ${rec.bibit.kriteria}

Contoh Varietas: ${rec.bibit.rekomendasi.join(', ')}

Tips: ${rec.bibit.tips}

`; // 2. Pemupukan html += `

๐Ÿงช Rekomendasi Pemupukan (${rec.pemupukan.fase})

`; // 3. Pengendalian html += `

๐Ÿ›ก๏ธ Pengendalian Hama & Penyakit

`; if (rec.pengendalian) { if (typeof rec.pengendalian === 'string') { html += `

${rec.pengendalian}

`; } else { const p = rec.pengendalian; html += `
${p.strategy.name}

${p.strategy.description}

`; if (p.protocol) { html += `
${p.protocol.title}
`; } } } else { html += `

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.icon} Panduan Lengkap: ${gd.name}

${gd.description}

`; html += '
'; html += ``; html += ``; html += '
'; html += `
`; for (const [phase, steps] of Object.entries(gd.sop)) { html += `

${phase}

`; } html += `
`; const analysis = gd.business_analysis; html += `

${analysis.title}

Asumsi: Lahan ${analysis.assumptions.Luas_Lahan}, populasi ${analysis.assumptions.Populasi_Tanaman}.

`; html += `

Estimasi Biaya Produksi

`; let totalCost = 0; analysis.costs.forEach(i => { html += ``; totalCost += i.cost; }); html += `
Komponen Kebutuhan Biaya
${i.item} ${i.amount} ${formatRupiah(i.cost)}
Total Biaya ${formatRupiah(totalCost)}
`; html += `

Simulasi Pendapatan

`; analysis.revenue_scenarios.forEach(s => { const revCons = analysis.yield_potential[0].total_yield_kg * s.price_per_kg; const revOpt = analysis.yield_potential[1].total_yield_kg * s.price_per_kg; html += ``; }); html += `
Skenario Harga Panen Konservatif Panen Optimal
${s.price_level} (${formatRupiah(s.price_per_kg)}/kg) ${formatRupiah(revCons)} ${formatRupiah(revOpt)}

Disclaimer: Angka ini adalah estimasi.
`; resultGuideDiv.innerHTML = html; } else { resultGuideDiv.innerHTML = `

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 = `

${pd.icon} ${pd.title}

`; Object.keys(pd.sections).forEach((k, i) => { html += ``; }); html += '
'; Object.entries(pd.sections).forEach(([k, s], i) => { html += `
`; }); resultPhDiv.innerHTML = html; } else { resultPhDiv.innerHTML = `

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 = `

Rekomendasi Tanaman Optimal

${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 = `

Estimasi Potensi Hasil Panen

${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 = `

Hasil Prediksi & Analisis

Estimasi Panen: ${data.predicted_yield_ton_ha} ton/ha

Faktor Pendorong & Penghambat (Analisis SHAP)

Analisis ini menjelaskan mengapa prediksi Anda berbeda dari rata-rata (${data.base_value} ton/ha).

Faktor Paling Berpengaruh (Secara Umum)

`; resultXaiYieldDiv.innerHTML = htmlResult; const chartCtx = document.getElementById('importance-chart').getContext('2d'); const labels = data.feature_importances.map(item => item[0]); const values = data.feature_importances.map(item => item[1]); importanceChart = new Chart(chartCtx, { type: 'bar', data: { labels: labels, datasets: [{ label: 'Tingkat Kepentingan', data: values, backgroundColor: 'rgba(76, 175, 80, 0.6)', borderColor: 'rgba(46, 125, 50, 1)', borderWidth: 1 }] }, options: { indexAxis: 'y', responsive: true, plugins: { legend: { display: false }, title: { display: true, text: 'Faktor yang Paling Memengaruhi Hasil Panen' } } } }); } else { resultXaiYieldDiv.innerHTML = `

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 = `

Hasil Perhitungan

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 = `

${node.question}

`; for (const [key, nextNode] of Object.entries(node.options)) { const button = document.createElement('button'); button.textContent = key.replace(/_/g, ' ').replace(/\b\w/g, l => l.toUpperCase()); button.classList.add('option-button'); button.onclick = () => { if (typeof nextNode === 'string') { renderResult(nextNode); } else { renderQuestion(nextNode, [...path, key]); } }; questionsDiv.appendChild(button); } } function renderResult(diagnosis) { questionsDiv.style.display = 'none'; resultDiv.style.display = 'block'; resultDiv.innerHTML = `

Hasil Diagnosis

${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 = `

Rekomendasi Kondisi Lahan

Untuk mencapai target panen sekitar ${requestData.target_yield} ton/ha, berikut adalah resep kondisi lahan berdasarkan data kami yang paling mendekati:


Disclaimer: Ini adalah target berdasarkan data historis, bukan jaminan.`; resultYieldPlanDiv.innerHTML = htmlResult; } else { resultYieldPlanDiv.innerHTML = `

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 = `

Hasil Analisis Risiko

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 = '

Hasil Diagnosis dari Roboflow AI

'; if (results && results.outputs && results.outputs.length > 0) { html += ''; } else { 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(); }