Spaces:
Sleeping
Sleeping
File size: 14,595 Bytes
3c32191 6b49084 11672f5 6b49084 11672f5 6b49084 29d2e28 3bab7f4 49982e9 29d2e28 49982e9 29d2e28 49982e9 29d2e28 6b49084 3bab7f4 6b49084 3bab7f4 49982e9 29d2e28 6b49084 49982e9 4978f67 49982e9 4978f67 49982e9 4978f67 49982e9 4978f67 49982e9 29d2e28 4978f67 29d2e28 4978f67 49982e9 29d2e28 49982e9 29d2e28 4978f67 29d2e28 4978f67 49982e9 29d2e28 6b49084 49982e9 6b49084 49982e9 6b49084 79ab3a4 6b49084 79ab3a4 49982e9 79ab3a4 49982e9 6b49084 79ab3a4 49982e9 06c19dc 6b49084 79ab3a4 49982e9 79ab3a4 49982e9 79ab3a4 49982e9 79ab3a4 49982e9 79ab3a4 49982e9 79ab3a4 49982e9 79ab3a4 49982e9 79ab3a4 6b49084 79ab3a4 6b49084 49982e9 6b49084 49982e9 79ab3a4 49982e9 79ab3a4 805280d 6b49084 49982e9 5107171 49982e9 79ab3a4 6b49084 5107171 49982e9 79ab3a4 46329a1 49982e9 46329a1 49982e9 46329a1 79ab3a4 46329a1 49982e9 46329a1 bf863db 6b49084 79ab3a4 6b49084 49982e9 0604226 805280d 6b49084 79ab3a4 49982e9 79ab3a4 6b49084 79ab3a4 6b49084 79ab3a4 6b49084 49982e9 6b49084 49982e9 79ab3a4 46329a1 523bfa2 5107171 46329a1 49982e9 bf863db 0604226 49982e9 4978f67 49982e9 4978f67 946449e 4978f67 46329a1 523bfa2 79ab3a4 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 | import streamlit as st
from ultralytics import YOLO
from PIL import Image
import numpy as np
import os
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
MODEL_PATH = os.path.join(SCRIPT_DIR, "best.pt")
SYMPTOM_QUESTIONS = {
"G1": "Daun berwarna putih kecoklatan memanjang seperti mengering pada bagian tepi daun",
"G2": "Pada pagi hari, dapat ditemukan cairan bakteri terlihat seperti butiran air pada bagian terinfeksi",
"G3": "Gejala terlihat seperti anak panah terdapat di antara urat daun",
"G4": "Daun berwarna kuning kecoklatan",
"G5": "Luka pada daun terlihat transparan bila dihadapkan cahaya matahari",
"G6": "Daun berbentuk belah ketupat",
"G7": "Pada daun bagian tengah berwarna abu-abu atau berwarna putih dengan bagian tepi berwarna kecoklatan",
"G8": "Infeksi pada malai/leher berwarna abu-abu",
"G9": "Tanaman kerdil dan gejala pada daun terjadi perubahan warna dari hijau menjadi jingga atau kemerahan",
"G10": "Bercak cokelat pada daun, pelepah, dan bulir gabah",
"G11": "Bercak daun sering menutupi permukaan daun, menyebabkan daun menjadi layu",
"G12": "Bercak cokelat pada batang/leher malai",
"G13": "Terdapat bercak berbentuk oval berwarna abu-abu kehijauan pada pelepah (tulang daun)",
"G14": "Batang tanaman padi menjadi rapuh dan mudah rebah/jatuh",
"G15": "Bibit yang sakit menjadi layu dan akhirnya mati",
"G20": "Daun menebal, tekstur kasar/berbintil (warty), serta kaku dan tegak",
"G21": "Daun bagian atas melintir (twisted) atau mengeriting",
"G22": "Tanaman kerdil dengan anakan berlebihan membentuk gumpalan padat",
"G23": "Malai gagal keluar atau mengalami deformasi (melengkung/membesar)",
"G24": "Pucuk tengah (pupus) mengering dan berwarna coklat kemerahan",
"G25": "Pucuk yang kering mudah dicabut dari pangkalnya dengan tangan",
"G26": "Terdapat lubang gerekan kecil pada pangkal batang atau kotoran ulat",
"G27": "Terdapat garis-garis putih transparan sejajar tulang daun (akibat Imago)",
"G28": "Permukaan atas daun terkelupas/dikikis menyisakan kulit ari bawah",
"G29": "Terdapat lepuhan/kantung putih tidak beraturan pada daun (akibat Larva)",
"G30": "Hamparan sawah tampak memutih seperti terbakar (hopperburn)"
}
YOLO_PROMPTS = {
"bacterial_leaf_blight": ["G1", "G2", "G3"],
"bacterial_leaf_streak": ["G4", "G5"],
"blast": ["G6", "G7", "G8"],
"tungro": ["G9"],
"brown_spot": ["G10", "G11", "G12"],
"downy_mildew": ["G20", "G21", "G22", "G23"],
"dead_heart": ["G24", "G25", "G26"],
"hispa": ["G27", "G28", "G29", "G30"],
"bacterial_panicle_blight": [],
"normal": []
}
PRODUCTION_RULES = [
{
"yolo_class": "bacterial_leaf_blight",
"disease": "Bacterial Leaf Blight (Hawar Daun Bakteri)",
"symptoms": ["G1", "G2", "G3"],
"source": "Literatur 1",
"solutions": [
"Gunakan varietas tahan (contoh: Inpari 32, Inpari 48, atau Ciherang).",
"Terapkan pengairan berselang (intermittent), hindari penggenangan terus-menerus.",
"Hindari pemupukan Nitrogen berlebih saat musim hujan."
]
},
{
"yolo_class": "bacterial_leaf_streak",
"disease": "Bakteri Daun Bergaris (Bacterial Leaf Streak)",
"symptoms": ["G4", "G5"],
"source": "Literatur 1",
"solutions": [
"Lakukan perlakuan benih dengan air panas (52°C selama 30 menit) atau antibiotik.",
"Semprotkan bakterisida berbahan tembaga (Copper oxychloride) jika serangan parah.",
"Musnahkan gulma inang di sekitar pematang."
]
},
{
"yolo_class": "blast",
"disease": "Blas (Blast)",
"symptoms": ["G6", "G7", "G8"],
"source": "Literatur 1",
"solutions": [
"Rendam benih dengan fungisida sistemik (misal: trisiklazol) sebelum semai.",
"Hindari waktu tanam terlambat dari jadwal petani sekitar.",
"Gunakan varietas tahan akan penyakit."
]
},
{
"yolo_class": "tungro",
"disease": "Tungro",
"symptoms": ["G9"],
"source": "Literatur 1",
"solutions": [
"Wajib tanam serempak dalam satu hamparan luas.",
"Kendalikan vektor Wereng Hijau dengan insektisida tepat sasaran.",
"Eradikasi (cabut dan musnahkan) tanaman yang menunjukkan gejala kerdil."
]
},
{
"yolo_class": "brown_spot",
"disease": "Bercak Daun Coklat (Brown Spot)",
"symptoms": ["G10", "G11", "G12"],
"source": "Literatur 2",
"solutions": [
"Hindari aplikasi pupuk nitrogen yang terlalu banyak.",
"Ada beberapa fungisida yang efektif tetapi secara ekonomi tidak direkomendasikan."
]
},
{
"yolo_class": None,
"disease": "Hawar Pelepah (Sheath Blight)",
"symptoms": ["G13", "G14", "G15"],
"source": "Literatur 2",
"solutions": [
"Berikan pupuk Kalium (K) dan bahan organik (kompos jerami) untuk menyehatkan tanah.",
"Lakukan perlakuan benih (seed treatment) dengan fungisida sebelum semai.",
"Gunakan varietas yang tahan (cara paling praktis)."
]
},
{
"yolo_class": "downy_mildew",
"disease": "Downy Mildew (Embun Bulu)",
"symptoms": ["G20", "G21", "G22", "G23"],
"source": "Literatur 3",
"solutions": [
"Perbaiki drainase lahan (permukaan dan bawah tanah) agar lahan tidak tergenang >24 jam.",
"Bersihkan gulma rumput-rumputan di sekitar sawah yang menjadi inang alternatif jamur.",
"Gunakan benih yang bersih dan bebas dari sisa tanaman sakit sebelumnya."
]
},
{
"yolo_class": "dead_heart",
"disease": "Dead Heart / Sundep (Penggerek Batang)",
"symptoms": ["G24", "G25", "G26"],
"source": "Literatur 4",
"solutions": [
"Kumpulkan dan musnahkan kelompok telur yang ditemukan pada persemaian secara manual.",
"Potong jerami serendah mungkin saat panen untuk mematikan larva yang bersembunyi di pangkal batang.",
"Lakukan tanam serempak untuk memutus siklus hidup hama."
]
},
{
"yolo_class": "hispa",
"disease": "Rice Hispa (Hama Putih)",
"symptoms": ["G27", "G28", "G29", "G30"],
"source": "Literatur 5",
"solutions": [
"Pangkas ujung daun bibit sebelum pindah tanam untuk membuang telur hama yang menempel.",
"Lakukan penyapuan (sweeping) dengan jaring serangga pada pagi hari untuk menangkap kumbang dewasa.",
"Bersihkan gulma di sekitar sawah dan hindari jarak tanam yang terlalu rapat."
]
}
]
@st.cache_resource
def load_model():
try:
return YOLO(MODEL_PATH)
except Exception as e:
st.error(f"Error loading model: {e}")
return None
model = load_model()
st.title("Rice Doctor: Sistem Pakar Penyakit Padi")
st.markdown("""
Dalam sistem **Rice Doctor**, pengguna dapat:
1. **Unggah Gambar Padi**. Untuk mendeteksi penyakit padi.
2. **Verifikasi Gejala Penyakit Padi**. Untuk memverifikasi hasil deteksi penyakit padi.
3. **Pengecekan Gejala Penyakit Padi Manual**. Jika hasil deteksi penyakit padi sebelummnya tidak terverifikasi.
""")
if 'step' not in st.session_state:
st.session_state.step = 1
if 'prediction' not in st.session_state:
st.session_state.prediction = None
if 'forward_matches' not in st.session_state:
st.session_state.forward_matches = []
if 'hypothesis_codes' not in st.session_state:
st.session_state.hypothesis_codes = []
if 'user_facts' not in st.session_state:
st.session_state.user_facts = set()
if 'system_method' not in st.session_state:
st.session_state.system_method = None
if st.session_state.step == 1:
st.divider()
st.subheader("Langkah 1: Unggah Gambar Padi")
uploaded_file = st.file_uploader("Unggah Gambar", type=["jpg", "png", "jpeg"])
if uploaded_file is not None:
image = Image.open(uploaded_file)
col1, col2, col3 = st.columns([1, 2, 1])
with col2:
st.image(image, caption="Gambar yang Diunggah", width=300)
if st.button("Deteksi Penyakit Padi", type="primary"):
if model:
with st.spinner("Model AI sedang menganalisis..."):
results = model.predict(image, imgsz=640)
raw_name = results[0].names[results[0].probs.top1]
top_class_name = raw_name.lower().strip()
probs = results[0].probs
top_conf = probs.top1conf.item()
st.session_state.image = image
st.session_state.prediction = top_class_name
st.session_state.prediction_conf = top_conf
st.session_state.hypothesis_codes = YOLO_PROMPTS.get(top_class_name, [])
st.session_state.step = 2
st.rerun()
elif st.session_state.step == 2:
st.divider()
st.subheader("Langkah 2: Verifikasi Gejala Penyakit Padi")
image = st.session_state.image
pred = st.session_state.prediction
conf = st.session_state.prediction_conf
conf_threshold = 0.9
codes = st.session_state.hypothesis_codes
col1, col2, col3 = st.columns([1, 2, 1])
with col2:
st.image(image, caption="Gambar yang Diunggah", width=300)
if not codes or (conf < conf_threshold):
st.warning("Model AI tidak dapat mendeteksi penyakit padi.")
if st.button("Lanjut ke Pengecekan Manual"):
st.session_state.step = 3
st.rerun()
else:
st.info(f"🔍 **Hasil Deteksi Penyakit Padi:** {pred}")
st.write("Jawablah pertanyaan berikut untuk memverifikasi penyakit:")
bc_answers = {}
for code in codes:
question = SYMPTOM_QUESTIONS.get(code, "Unknown")
ans = st.radio(
f"**({code})** {question}?",
options=["Tidak", "Ya"],
index=0,
key=f"bc_{code}"
)
if ans == "Ya":
bc_answers[code] = True
else:
bc_answers[code] = False
if st.button("Verifikasi Penyakit Padi", type="primary"):
all_yes = all(bc_answers.values())
if all_yes:
st.session_state.system_method = "backward"
st.session_state.step = 4
st.rerun()
else:
st.session_state.user_facts = {k for k, v in bc_answers.items() if v}
st.toast("Sistem tidak dapat memverifikasi penyakit padi. Beralih ke Pengecekan Manual...")
st.session_state.step = 3
st.rerun()
elif st.session_state.step == 3:
st.divider()
st.subheader("Langkah 3: Pengecekan Gejala Penyakit Padi Manual")
st.info("ℹ️ Sistem tidak dapat memverifikasi penyakit padi. Beralih ke Pengecekan Manual.")
image = st.session_state.image
col1, col2, col3 = st.columns([1, 2, 1])
with col2:
st.image(image, caption="Gambar yang Diunggah", width=300)
all_symptoms_list = [f"{k}: {v}" for k,v in SYMPTOM_QUESTIONS.items()]
pre_selected = [f"{code}: {SYMPTOM_QUESTIONS[code]}" for code in st.session_state.user_facts if code in SYMPTOM_QUESTIONS]
other_checks = st.multiselect(
"Silakan pilih semua gejala yang terlihat pada tanaman:",
all_symptoms_list,
default=pre_selected
)
if st.button("Analisis Penyakit Padi", type="primary"):
final_facts = set()
for item in other_checks:
code = item.split(":")[0].strip()
final_facts.add(code)
if not final_facts:
st.error("Mohon pilih setidaknya satu gejala.")
else:
matches = []
for rule in PRODUCTION_RULES:
required = set(rule['symptoms'])
if required.issubset(final_facts):
matches.append(rule)
if matches:
st.session_state.system_method = "forward"
st.session_state.forward_matches = matches
st.session_state.step = 4
st.rerun()
else:
st.info("ℹ️ **Sistem Tidak Menemukan Penyakit Padi Secara Pasti**")
st.write("Kombinasi gejala yang Anda pilih tidak cocok sepenuhnya dengan aturan penyakit manapun dalam basis pengetahuan.")
st.divider()
if st.button("Mulai Ulang Analisis"):
st.session_state.step = 1
st.session_state.user_facts = set()
st.rerun()
elif st.session_state.step == 4:
st.divider()
image = st.session_state.image
col1, col2, col3 = st.columns([1, 2, 1])
with col2:
st.image(image, caption="Gambar yang Diunggah", width=300)
st.success("**✅ Penyakit Padi Ditemukan!**")
if st.session_state.system_method == "forward":
for m in st.session_state.forward_matches:
st.markdown(f"""
### {m['disease']}
- **Sumber Aturan:** {m['source']}
""")
if 'solutions' in m and m['solutions']:
sol_text = "- **Solusi Pengendalian:**\n"
for sol in m['solutions']:
sol_text += f" - {sol}\n"
st.markdown(sol_text)
if st.session_state.system_method == "backward":
matched_rule = next((r for r in PRODUCTION_RULES if r.get("yolo_class") == st.session_state.prediction), None)
disease = matched_rule['disease'] if matched_rule else st.session_state.prediction
source = matched_rule['source'] if matched_rule else "Tidak diketahui"
st.markdown(f"""
### {disease}
- **Sumber Aturan:** {source}
""")
if matched_rule and 'solutions' in matched_rule and matched_rule['solutions']:
sol_text = "- **Solusi Pengendalian:**\n"
for sol in matched_rule['solutions']:
sol_text += f" - {sol}\n"
st.markdown(sol_text)
st.divider()
if st.button("Mulai Ulang Analisis"):
st.session_state.step = 1
st.session_state.user_facts = set()
st.rerun() |