340 lines
18 KiB
HTML
340 lines
18 KiB
HTML
{% extends "base.html" %}
|
|
|
|
{% block title %}Sistem Pakar PMK{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="row justify-content-center">
|
|
<div class="col-md-8">
|
|
<div class="card shadow">
|
|
<div class="card-header bg-success text-white">
|
|
<h4 class="mb-0"><i class="fas fa-stethoscope me-2"></i>Sistem Pakar Forward Chaining - Diagnosis PMK</h4>
|
|
</div>
|
|
<div class="card-body">
|
|
{% set is_image_mode = context_mode == 'image' %}
|
|
|
|
<!-- Breadcrumb -->
|
|
<nav aria-label="breadcrumb">
|
|
<ol class="breadcrumb">
|
|
<li class="breadcrumb-item"><a href="{{ url_for('index') }}">Home</a></li>
|
|
<li class="breadcrumb-item active" aria-current="page">Sistem Pakar</li>
|
|
</ol>
|
|
</nav>
|
|
|
|
<!-- Info Panel -->
|
|
<div class="alert alert-info mb-4">
|
|
<i class="fas fa-info-circle me-2"></i>
|
|
<strong>Cara Penggunaan:</strong> Pilih gejala yang Anda amati pada sapi, kemudian klik tombol diagnosis untuk mendapatkan hasil.
|
|
</div>
|
|
{% if is_image_mode %}
|
|
<div class="alert alert-success mb-4">
|
|
<i class="fas fa-image me-2"></i>
|
|
Mode ini mengikuti hasil deteksi gambar sebelumnya.
|
|
</div>
|
|
{% else %}
|
|
<div class="alert alert-secondary mb-4">
|
|
<i class="fas fa-brain me-2"></i>
|
|
Mode ini berjalan langsung sebagai sistem pakar tanpa keterikatan gambar.
|
|
</div>
|
|
{% endif %}
|
|
|
|
{% if upload_images and upload_images|length > 0 %}
|
|
<div class="card mb-4 border-success">
|
|
<div class="card-header bg-success text-white">
|
|
<h5 class="mb-0"><i class="fas fa-camera me-2"></i>Hasil Deteksi Gambar ({{ upload_images|length }} gambar)</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="row">
|
|
{% for img in upload_images %}
|
|
<div class="col-md-4 col-6 mb-3">
|
|
<div class="card h-100">
|
|
<img src="{{ url_for('uploaded_file', filename=img.filename) }}"
|
|
class="card-img-top" style="height:120px;object-fit:cover"
|
|
alt="{{ img.original_filename }}">
|
|
<div class="card-body p-2 text-center">
|
|
<small class="d-block text-truncate">{{ img.original_filename }}</small>
|
|
<span class="badge {% if img.prediction == 'sakit' %}bg-warning text-dark{% else %}bg-success{% endif %}">
|
|
{{ img.prediction|upper }}
|
|
</span>
|
|
{% if img.pmk_type %}
|
|
<span class="badge bg-info">{{ img.pmk_type }}</span>
|
|
{% endif %}
|
|
<small class="d-block text-muted">{{ img.confidence|round(1) }}%</small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endfor %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% elif image_info %}
|
|
<div class="alert alert-success mb-4">
|
|
<h5 class="alert-heading"><i class="fas fa-camera me-2"></i>Informasi Deteksi Sebelumnya</h5>
|
|
<div class="row">
|
|
<div class="col-md-8">
|
|
<p class="mb-1"><strong>File:</strong> {{ image_info.filename }}</p>
|
|
<p class="mb-1"><strong>Hasil Deteksi:</strong>
|
|
<span class="badge {% if image_info.prediction == 'sakit' %}bg-warning text-dark{% else %}bg-success{% endif %}">
|
|
{{ image_info.prediction|upper }}
|
|
</span>
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
|
|
{% if diagnosis %}
|
|
<!-- Hasil Diagnosis -->
|
|
<div class="alert alert-info" id="hasil">
|
|
<h5 class="alert-heading mb-3">
|
|
<i class="fas fa-clipboard-check me-2"></i>Hasil Diagnosis
|
|
</h5>
|
|
|
|
{% if diagnosis.status == 'terdiagnosis' %}
|
|
<div class="alert alert-success mb-3">
|
|
<strong>Status:</strong> Positif PMK
|
|
<div class="mt-2">
|
|
Diagnosis utama akan ditampilkan di bawah sebagai bentuk PMK yang paling sesuai.
|
|
</div>
|
|
</div>
|
|
|
|
{% for diag in diagnosis.diagnosis %}
|
|
<div class="card mb-3 {% if loop.first %}border-success border-3{% endif %}">
|
|
<div class="card-header {% if loop.first %}bg-success text-white{% else %}bg-light{% endif %}">
|
|
<h5 class="mb-0">
|
|
<i class="fas fa-diagnoses me-2"></i>{{ diag.nama }}
|
|
{% if loop.first %}
|
|
<span class="badge bg-light text-success float-end">{{ diag.persentase|default(diag.score * 100)|round(2) }}%</span>
|
|
{% endif %}
|
|
</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="mb-3">
|
|
<label class="fw-bold">Kategori Penyakit:</label>
|
|
<div class="mt-2">
|
|
{% if diag.severity == 'oral' %}
|
|
<span class="badge bg-info fs-6">PMK ORAL</span>
|
|
{% elif diag.severity == 'podal' %}
|
|
<span class="badge bg-warning text-dark fs-6">PMK PODAL</span>
|
|
{% elif diag.severity == 'laktasi' %}
|
|
<span class="badge bg-primary fs-6">PMK LAKTASI</span>
|
|
{% elif diag.severity == 'akut umum' %}
|
|
<span class="badge bg-dark fs-6">PMK AKUT UMUM</span>
|
|
{% else %}
|
|
<span class="badge bg-secondary fs-6">PMK</span>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mb-3">
|
|
<label class="fw-bold">Deskripsi:</label>
|
|
<p class="mb-0">{{ diag.deskripsi }}</p>
|
|
</div>
|
|
|
|
{% if diag.bukti_aturan %}
|
|
<div class="mb-3">
|
|
<label class="fw-bold">Bukti Aturan yang Cocok:</label>
|
|
<ul class="mb-0 mt-2">
|
|
{% for bukti in diag.bukti_aturan %}
|
|
<li>{{ bukti.kode }} - {{ bukti.deskripsi }}</li>
|
|
{% endfor %}
|
|
</ul>
|
|
</div>
|
|
{% endif %}
|
|
|
|
<div class="mb-0">
|
|
<label class="fw-bold">Rekomendasi Penanganan:</label>
|
|
<ol class="mb-0">
|
|
{% for s in diag.solusi %}
|
|
<li class="mb-1">{{ s }}</li>
|
|
{% endfor %}
|
|
</ol>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endfor %}
|
|
|
|
<div class="card mt-3">
|
|
<div class="card-header bg-secondary text-white">
|
|
<h5 class="mb-0"><i class="fas fa-list me-2"></i>Gejala yang Diamati</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<ul class="list-group">
|
|
{% for g in diagnosis.gejala_teramati %}
|
|
<li class="list-group-item">
|
|
<i class="fas fa-check-circle text-success me-2"></i>
|
|
{{ g }}
|
|
</li>
|
|
{% endfor %}
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="alert alert-warning mt-3">
|
|
<i class="fas fa-exclamation-triangle me-2"></i>
|
|
<strong>Penanganan Awal:</strong> isolasi sapi yang terindikasi PMK, sediakan pakan lunak dan air minum cukup, jaga kebersihan kandang, dan hubungi dokter hewan secepatnya.
|
|
</div>
|
|
|
|
<div class="mt-4 text-center">
|
|
<button class="btn btn-success" onclick="window.print()">
|
|
<i class="fas fa-print me-2"></i>Cetak Hasil
|
|
</button>
|
|
<a href="{{ url_for('expert_system_page', mode=context_mode) }}" class="btn btn-primary">
|
|
<i class="fas fa-redo me-2"></i>Konsultasi Lagi
|
|
</a>
|
|
<a href="{{ url_for('index') }}" class="btn btn-secondary">
|
|
<i class="fas fa-home me-2"></i>Kembali ke Home
|
|
</a>
|
|
</div>
|
|
|
|
{% else %}
|
|
<div class="alert alert-warning">
|
|
<i class="fas fa-exclamation-circle me-2"></i>
|
|
{{ diagnosis.message }}
|
|
</div>
|
|
<div class="text-center">
|
|
<a href="{{ url_for('expert_system_page', mode=context_mode) }}" class="btn btn-primary">
|
|
<i class="fas fa-redo me-2"></i>Coba Lagi
|
|
</a>
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
|
|
{% else %}
|
|
<!-- Form Gejala -->
|
|
<form method="POST" action="{{ url_for('expert_system_page', mode=context_mode) }}" id="expertForm">
|
|
<input type="hidden" name="mode" value="{{ context_mode }}">
|
|
<div class="mb-4">
|
|
<h5 class="mb-3"><i class="fas fa-list-ul me-2"></i>Pilih Gejala yang Diamati:</h5>
|
|
|
|
<!-- Kategori Gejala (semua terbuka) -->
|
|
{% for group_key, group in gejala_groups.items() %}
|
|
<div class="card mb-3">
|
|
<div class="card-header bg-light">
|
|
<h5 class="mb-0">
|
|
{% if group_key == 'umum' %}<i class="fas fa-thermometer-half me-2"></i>{% elif group_key == 'mulut' %}<i class="fas fa-tooth me-2"></i>{% elif group_key == 'kaki' %}<i class="fas fa-shoe-prints me-2"></i>{% elif group_key == 'ambing' %}<i class="fas fa-cow me-2"></i>{% else %}<i class="fas fa-exclamation-triangle me-2"></i>{% endif %}
|
|
{{ group.title }}
|
|
</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="row">
|
|
{% for kode in group.codes %}
|
|
<div class="col-md-6 mb-2">
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="checkbox"
|
|
name="gejala" value="{{ kode }}"
|
|
id="gejala{{ kode }}"
|
|
{% if selected_gejala and kode in selected_gejala %}checked{% endif %}>
|
|
<label class="form-check-label" for="gejala{{ kode }}">
|
|
<strong>{{ kode }}:</strong> {{ gejala_list[kode] }}
|
|
</label>
|
|
</div>
|
|
</div>
|
|
{% endfor %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endfor %}
|
|
</div>
|
|
|
|
<!-- Action Buttons -->
|
|
<div class="mt-4 text-center">
|
|
<button type="submit" class="btn btn-success btn-lg">
|
|
<i class="fas fa-diagnoses me-2"></i>{% if is_image_mode %}Diagnosis dari Gambar{% else %}Diagnosis Langsung{% endif %}
|
|
</button>
|
|
<button type="reset" class="btn btn-secondary btn-lg">
|
|
<i class="fas fa-undo me-2"></i>Reset
|
|
</button>
|
|
</div>
|
|
|
|
<!-- Tombol Pilih Semua -->
|
|
<div class="mt-3 text-center">
|
|
<button type="button" class="btn btn-outline-primary btn-sm" id="selectAll">
|
|
<i class="fas fa-check-double me-2"></i>Pilih Semua
|
|
</button>
|
|
<button type="button" class="btn btn-outline-secondary btn-sm" id="unselectAll">
|
|
<i class="fas fa-times me-2"></i>Hapus Semua
|
|
</button>
|
|
</div>
|
|
</form>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Informasi Tambahan -->
|
|
<div class="card mt-3">
|
|
<div class="card-header bg-info text-white">
|
|
<h5 class="mb-0"><i class="fas fa-question-circle me-2"></i>Tentang Sistem Pakar</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<p>Sistem pakar ini menggunakan metode <strong>Forward Chaining</strong> untuk mendiagnosis PMK pada sapi berdasarkan gejala yang diamati.</p>
|
|
<ul class="mb-0">
|
|
<li>Total gejala: {{ gejala_list|length }} gejala</li>
|
|
<li>Fokus hasil: status positif PMK dan penanganan awal</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<style>
|
|
.form-check-input:checked {
|
|
background-color: #28a745;
|
|
border-color: #28a745;
|
|
}
|
|
</style>
|
|
{% endblock %}
|
|
|
|
{% block scripts %}
|
|
<script>
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
// Simpan predictions.id ke localStorage agar riwayat deteksi hanya menampilkan data terkait
|
|
(function() {
|
|
var predId = Number('{{ diagnosis.saved_prediction_id if diagnosis and diagnosis.saved_prediction_id else (image_info.db_id if image_info and image_info.db_id else 0) }}');
|
|
if (predId <= 0) return;
|
|
|
|
var storageKey = 'pmk_predictions_ids';
|
|
var storedIds = [];
|
|
try {
|
|
storedIds = JSON.parse(localStorage.getItem(storageKey) || '[]');
|
|
if (!Array.isArray(storedIds)) storedIds = [];
|
|
} catch (e) {
|
|
storedIds = [];
|
|
}
|
|
if (storedIds.indexOf(predId) === -1) {
|
|
storedIds.unshift(predId);
|
|
localStorage.setItem(storageKey, JSON.stringify(storedIds));
|
|
}
|
|
})();
|
|
|
|
// Reset button
|
|
document.querySelector('button[type="reset"]')?.addEventListener('click', function(e) {
|
|
e.preventDefault();
|
|
document.querySelectorAll('input[type="checkbox"]').forEach(cb => cb.checked = false);
|
|
});
|
|
|
|
// Select All button
|
|
document.getElementById('selectAll')?.addEventListener('click', function() {
|
|
document.querySelectorAll('input[type="checkbox"]').forEach(cb => cb.checked = true);
|
|
});
|
|
|
|
// Unselect All button
|
|
document.getElementById('unselectAll')?.addEventListener('click', function() {
|
|
document.querySelectorAll('input[type="checkbox"]').forEach(cb => cb.checked = false);
|
|
});
|
|
|
|
// Auto scroll to hasil diagnosis
|
|
if (window.location.hash === '#hasil') {
|
|
document.getElementById('hasil')?.scrollIntoView({ behavior: 'smooth' });
|
|
}
|
|
|
|
// Form validation
|
|
document.getElementById('expertForm')?.addEventListener('submit', function(e) {
|
|
const checkedBoxes = document.querySelectorAll('input[type="checkbox"]:checked');
|
|
if (checkedBoxes.length === 0) {
|
|
e.preventDefault();
|
|
alert('Pilih minimal satu gejala untuk melakukan diagnosis!');
|
|
}
|
|
});
|
|
});
|
|
</script>
|
|
{% endblock %} |