Sistem-Pakar-Diagnosa-Penya.../backend/controller/diagnosaController.js

284 lines
10 KiB
JavaScript

const { Rule_penyakit, Rule_hama, Gejala, Penyakit, Hama, Histori } = require('../models');
const moment = require('moment');
exports.diagnosa = async (req, res) => {
const { gejala } = req.body; // array of id_gejala
const userId = req.user?.id; // Use optional chaining to avoid errors if req.user is undefined
const tanggal_diagnosa = moment().format('YYYY-MM-DD');
if (!gejala || !Array.isArray(gejala)) {
return res.status(400).json({ message: 'Gejala harus berupa array' });
}
try {
// Mengambil semua data yang dibutuhkan sekaligus
const allGejala = await Gejala.findAll({
where: { id: gejala }
});
// ========== HITUNG TOTAL P(E) UNTUK SEMUA GEJALA ==========
// P(E) seharusnya sama untuk semua penyakit dan hama yang memiliki gejala yang sama
// Object untuk menyimpan P(E) untuk setiap gejala
const evidenceProbabilities = {};
// Hitung P(E) untuk PENYAKIT
for (const idGejala of gejala) {
// Dapatkan semua rule untuk gejala ini di semua penyakit
const penyakitRulesForGejala = await Rule_penyakit.findAll({
where: { id_gejala: idGejala },
include: [{ model: Penyakit, as: 'penyakit' }]
});
let evidenceProbForGejala = 0;
// Hitung P(E) = Σ [P(E|Hi) * P(Hi)] untuk penyakit
for (const rule of penyakitRulesForGejala) {
const pHi = rule.penyakit.nilai_pakar; // P(Hi)
const pEgivenHi = rule.nilai_pakar; // P(E|Hi)
evidenceProbForGejala += pEgivenHi * pHi;
}
// Dapatkan semua rule untuk gejala ini di semua hama
const hamaRulesForGejala = await Rule_hama.findAll({
where: { id_gejala: idGejala },
include: [{ model: Hama, as: 'hama' }]
});
// Hitung P(E) = Σ [P(E|Hi) * P(Hi)] untuk hama
for (const rule of hamaRulesForGejala) {
const pHi = rule.hama.nilai_pakar; // P(Hi)
const pEgivenHi = rule.nilai_pakar; // P(E|Hi)
evidenceProbForGejala += pEgivenHi * pHi;
}
// Simpan P(E) untuk gejala ini
evidenceProbabilities[idGejala] = evidenceProbForGejala;
}
// Hitung total P(E) untuk semua gejala yang diinput
let totalEvidenceProbability = 0;
for (const idGejala of gejala) {
totalEvidenceProbability += evidenceProbabilities[idGejala] || 0;
}
// Pastikan total P(E) tidak nol untuk menghindari division by zero
if (totalEvidenceProbability === 0) {
totalEvidenceProbability = 1.0;
}
// ========== PENYAKIT ==========
const allPenyakitRules = await Rule_penyakit.findAll({
where: { id_gejala: gejala },
include: [{ model: Penyakit, as: 'penyakit' }]
});
// Mendapatkan semua penyakit unik yang memiliki gejala yang dipilih
const uniquePenyakitIds = [...new Set(allPenyakitRules.map(rule => rule.id_penyakit))];
// Hasil perhitungan untuk setiap penyakit
const hasilPenyakit = [];
// Hitung untuk setiap penyakit
for (const idPenyakit of uniquePenyakitIds) {
// Filter rules yang berhubungan dengan penyakit ini
const penyakitRules = allPenyakitRules.filter(rule => rule.id_penyakit === idPenyakit);
if (penyakitRules.length > 0) {
const dataPenyakit = penyakitRules[0].penyakit;
const namaPenyakit = dataPenyakit.nama;
const priorProbability = dataPenyakit.nilai_pakar; // P(H) - prior probability penyakit
// Menghitung P(E|H) untuk setiap gejala
const evidenceGivenHypothesis = {};
for (const rule of penyakitRules) {
evidenceGivenHypothesis[rule.id_gejala] = rule.nilai_pakar; // P(E|H) untuk setiap gejala
}
// Menghitung P(H|E) = [P(E|H) * P(H)] / P(E) untuk semua gejala
let posteriorNumerator = priorProbability; // Inisialisasi dengan P(H)
const evidencesUsed = [];
// Mengalikan dengan nilai P(E|H) untuk setiap gejala yang ada
for (const idGejala of gejala) {
if (evidenceGivenHypothesis[idGejala]) {
posteriorNumerator *= evidenceGivenHypothesis[idGejala];
evidencesUsed.push({
id_gejala: parseInt(idGejala),
P_E_given_H: evidenceGivenHypothesis[idGejala],
nilai_P_E: evidenceProbabilities[idGejala] || 0
});
}
}
// Posterior probability adalah P(H|E)
const posteriorProbability = posteriorNumerator / totalEvidenceProbability;
hasilPenyakit.push({
id_penyakit: idPenyakit,
nama: namaPenyakit,
P_H: priorProbability,
P_E: totalEvidenceProbability,
evidences: evidencesUsed,
posterior_numerator: posteriorNumerator,
posterior_probability: posteriorProbability,
probabilitas: posteriorProbability
});
}
}
// ========== HAMA ==========
const allHamaRules = await Rule_hama.findAll({
where: { id_gejala: gejala },
include: [{ model: Hama, as: 'hama' }]
});
// Mendapatkan semua hama unik yang memiliki gejala yang dipilih
const uniqueHamaIds = [...new Set(allHamaRules.map(rule => rule.id_hama))];
// Hasil perhitungan untuk setiap hama
const hasilHama = [];
// Hitung untuk setiap hama
for (const idHama of uniqueHamaIds) {
// Filter rules yang berhubungan dengan hama ini
const hamaRules = allHamaRules.filter(rule => rule.id_hama === idHama);
if (hamaRules.length > 0) {
const dataHama = hamaRules[0].hama;
const namaHama = dataHama.nama;
const priorProbability = dataHama.nilai_pakar; // P(H) - prior probability hama
// Menghitung P(E|H) untuk setiap gejala
const evidenceGivenHypothesis = {};
for (const rule of hamaRules) {
evidenceGivenHypothesis[rule.id_gejala] = rule.nilai_pakar; // P(E|H) untuk setiap gejala
}
// Menghitung P(H|E) = [P(E|H) * P(H)] / P(E) untuk semua gejala
let posteriorNumerator = priorProbability; // Inisialisasi dengan P(H)
const evidencesUsed = [];
// Mengalikan dengan nilai P(E|H) untuk setiap gejala yang ada
for (const idGejala of gejala) {
if (evidenceGivenHypothesis[idGejala]) {
posteriorNumerator *= evidenceGivenHypothesis[idGejala];
evidencesUsed.push({
id_gejala: parseInt(idGejala),
P_E_given_H: evidenceGivenHypothesis[idGejala],
nilai_P_E: evidenceProbabilities[idGejala] || 0
});
}
}
// Posterior probability adalah P(H|E)
const posteriorProbability = posteriorNumerator / totalEvidenceProbability;
hasilHama.push({
id_hama: idHama,
nama: namaHama,
P_H: priorProbability,
P_E: totalEvidenceProbability,
evidences: evidencesUsed,
posterior_numerator: posteriorNumerator,
posterior_probability: posteriorProbability,
probabilitas: posteriorProbability
});
}
}
// Urutkan hasil berdasarkan probabilitas
const sortedPenyakit = hasilPenyakit.sort((a, b) => b.probabilitas - a.probabilitas);
const sortedHama = hasilHama.sort((a, b) => b.probabilitas - a.probabilitas);
// Buat ringkasan gejala yang dimasukkan
const gejalaSummary = await Gejala.findAll({
where: { id: gejala },
attributes: ['id', 'kode', 'nama']
});
if (!userId) {
console.error('ID user tidak ditemukan pada request. Histori tidak dapat disimpan.');
} else {
const idGejalaDipilih = gejala;
const semuaHasil = [...hasilPenyakit, ...hasilHama];
if (semuaHasil.length > 0) {
const hasilTerbesar = semuaHasil.reduce((max, current) => {
return current.probabilitas > max.probabilitas ? current : max;
});
// Base histori data without id_gejala
const baseHistoriData = {
userId: userId,
tanggal_diagnosa: tanggal_diagnosa,
hasil: hasilTerbesar.probabilitas
};
if (hasilTerbesar.id_penyakit) {
baseHistoriData.id_penyakit = hasilTerbesar.id_penyakit;
} else if (hasilTerbesar.id_hama) {
baseHistoriData.id_hama = hasilTerbesar.id_hama;
}
try {
// Option 1: Store only the first gejala ID if we're limited to one record
// if (idGejalaDipilih.length > 0) {
// await Histori.create({
// ...baseHistoriData,
// id_gejala: parseInt(idGejalaDipilih[0]) // Store as integer
// }, { timestamps: false });
// console.log('Histori berhasil disimpan dengan gejala utama');
// }
// Option 2 (Uncomment if you want to create multiple records):
// Create multiple records - one for each gejala
const historiPromises = idGejalaDipilih.map(gejalaId => {
return Histori.create({
...baseHistoriData,
id_gejala: parseInt(gejalaId) // Store as integer
}, { timestamps: false });
});
await Promise.all(historiPromises);
console.log(`Histori berhasil disimpan untuk ${idGejalaDipilih.length} gejala`);
} catch (error) {
console.error('Gagal menyimpan histori:', error.message);
}
} else {
console.log('Tidak ada hasil untuk disimpan ke histori.');
}
}
// Kirim hasil perhitungan sebagai respons
res.json({
input_gejala: gejalaSummary,
total_evidence_probability: totalEvidenceProbability,
evidence_per_gejala: evidenceProbabilities,
penyakit: sortedPenyakit,
hama: sortedHama,
detail_perhitungan: {
keterangan: "Menggunakan teorema Bayes: P(H|E) = [P(E|H) * P(H)] / P(E)",
formula: {
P_H: "Prior probability (nilai pakar untuk penyakit/hama)",
P_E_given_H: "Likelihood (nilai pakar untuk gejala terhadap penyakit/hama)",
P_E: "Evidence probability = Σ [P(E|Hi) * P(Hi)] untuk semua hipotesis",
P_H_given_E: "Posterior probability (hasil akhir)"
}
}
});
} catch (error) {
console.error('Error dalam perhitungan Bayes:', error);
res.status(500).json({
message: 'Terjadi kesalahan dalam proses diagnosa',
error: error.message
});
}
};