Randi-Palguna commited on
Commit
49982e9
·
1 Parent(s): 46329a1

feat: refactor app

Browse files
Files changed (1) hide show
  1. src/streamlit_app.py +115 -64
src/streamlit_app.py CHANGED
@@ -8,25 +8,21 @@ SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
8
  MODEL_PATH = os.path.join(SCRIPT_DIR, "best.pt")
9
 
10
  SYMPTOM_QUESTIONS = {
11
- "G1": "Daun berwana putih kecoklatan memanjang seperti mengering pada bagian tepi daun?",
12
  "G2": "Pada pagi hari, dapat ditemukan cairan bakteri terlihat seperti butiran air pada bagian terinfeksi",
13
- "G3": "Gejala terlihat seperti anak panah terdapat di antara urat daun?",
14
- "G4": "Daun Berwarna kuning kecoklatan?",
15
- "G5": "Luka pada daun terlihat transparan bila dihadapkan cahaya matahari?",
16
- "G6": "Daun berbentuk belah ketupat?",
17
- "G7": "Pada daun bagian tengah berwarna abu-abu atau berwarna putih dengan bagian tepi berwarna kecoklatan?",
18
- "G8": "Infeksi pada malai/leher berwarna abu-abu?",
19
- "G9": "Tanaman kerdil dan Gejala pada daun terjadi perubahan warna dari hijau menjadi jingga atau kemerahan?",
20
- "G10": "Daun menguning, menggulung, mengering dan menjadi layu?",
21
- "G11": "Bibit menjadi layu (kresek) tapi sulit dicabut?",
22
- "G12": "Warna luka bercak menjadi jingga kekuningan dari ujung daun ke pangkal daun?",
23
- "G13": "Ada bulatan kecil berwarna kuning pada pelepah daun?",
24
- "G14": "Bercak cokelat pada daun, pelepah, dan bulir gabah?",
25
- "G15": "Bercak daun sering menutupi permukaan daun, menyebabkan daun menjadi layu?",
26
- "G16": "Bercak cokelat pada batang/leher malai?",
27
- "G17": "Terdapat bercak berbentuk oval berwarna abu-abu kehijauan pada pelepah (tulang daun)?",
28
- "G18": "Batang tanaman padi menjadi rapuh dan mudah rebah/jatuh?",
29
- "G19": "Bibit yang sakit menjadi layu dan akhirnya mati?"
30
  }
31
 
32
  YOLO_PROMPTS = {
@@ -34,7 +30,7 @@ YOLO_PROMPTS = {
34
  "bacterial_leaf_streak": ["G4", "G5"],
35
  "blast": ["G6", "G7", "G8"],
36
  "tungro": ["G9"],
37
- "brown_spot": ["G14", "G15", "G16"],
38
  "downy_mildew": [],
39
  "dead_heart": [],
40
  "hispa": [],
@@ -42,13 +38,42 @@ YOLO_PROMPTS = {
42
  }
43
 
44
  PRODUCTION_RULES = [
45
- {"disease": "Bacterial Leaf Blight (Hawar Daun Bakteri)", "symptoms": ["G1", "G2", "G3"], "source": "Literatur 1"},
46
- {"disease": "Bakteri Daun Bergaris (Bacterial Leaf Streak)", "symptoms": ["G4", "G5"], "source": "Literatur 1"},
47
- {"disease": "Blas (Blast)", "symptoms": ["G6", "G7", "G8"], "source": "Literatur 1"},
48
- {"disease": "Tungro", "symptoms": ["G9"], "source": "Literatur 1"},
49
- {"disease": "Hawar Daun Bakteri (Bacterial Leaf Blight)", "symptoms": ["G10", "G11", "G12", "G13"], "source": "Literatur 2"},
50
- {"disease": "Bercak Daun Coklat (Brown Spot)", "symptoms": ["G14", "G15", "G16"], "source": "Literatur 3"},
51
- {"disease": "Hawar Pelepah (Sheath Blight)", "symptoms": ["G17", "G18", "G19"], "source": "Literatur 3"},
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
52
  ]
53
 
54
  @st.cache_resource
@@ -61,65 +86,84 @@ def load_model():
61
 
62
  model = load_model()
63
 
64
- st.title("🌾 Rice Doctor: Sistem Pakar Hibrida")
65
  st.markdown("""
66
- Sistem ini menggunakan metode **Hybrid AI**:
67
- 1. **Model AI (YOLO)** untuk memberikan hipotesis awal.
68
- 2. **Backward Chaining** untuk memverifikasi hipotesis tersebut.
69
- 3. **Forward Chaining** untuk mencari diagnosis alternatif jika hipotesis salah.
70
  """)
71
 
72
  if 'step' not in st.session_state:
73
  st.session_state.step = 1
74
  if 'prediction' not in st.session_state:
75
  st.session_state.prediction = None
 
 
76
  if 'hypothesis_codes' not in st.session_state:
77
  st.session_state.hypothesis_codes = []
78
  if 'user_facts' not in st.session_state:
79
  st.session_state.user_facts = set()
 
 
80
 
81
  if st.session_state.step == 1:
82
- uploaded_file = st.file_uploader("Langkah 1: Unggah Gambar Daun", type=["jpg", "png", "jpeg"])
 
 
83
 
84
  if uploaded_file is not None:
85
  image = Image.open(uploaded_file)
86
- st.image(image, caption="Gambar yang Diunggah", width=300)
 
 
87
 
88
- if st.button("Analisis Gambar (AI Inference)", type="primary"):
89
  if model:
90
- with st.spinner("Model AI sedang menganalisis hipotesis..."):
91
  results = model.predict(image, imgsz=640)
 
92
  raw_name = results[0].names[results[0].probs.top1]
93
  top_class_name = raw_name.lower().strip()
 
 
94
 
 
95
  st.session_state.prediction = top_class_name
 
96
  st.session_state.hypothesis_codes = YOLO_PROMPTS.get(top_class_name, [])
97
  st.session_state.step = 2
98
  st.rerun()
99
 
100
  elif st.session_state.step == 2:
101
  st.divider()
102
- st.subheader("Langkah 2: Backward Chaining (Verifikasi Hipotesis)")
103
 
 
104
  pred = st.session_state.prediction
 
 
105
  codes = st.session_state.hypothesis_codes
106
 
107
- st.info(f"🔍 **Hipotesis AI:** `{pred}`")
108
- st.write("Sistem sedang memverifikasi hipotesis ini menggunakan **Backward Chaining**.")
109
 
110
- if not codes:
111
- st.warning("Model AI memprediksi kelas yang tidak memiliki aturan verifikasi spesifik atau 'Normal'.")
112
- if st.button("Lanjut ke Pengecekan Manual (Forward Chaining)"):
113
  st.session_state.step = 3
114
  st.rerun()
115
  else:
116
- st.write("Jawablah pertanyaan berikut untuk memverifikasi hipotesis:")
 
 
 
 
117
 
118
  bc_answers = {}
119
  for code in codes:
120
  question = SYMPTOM_QUESTIONS.get(code, "Unknown")
121
  ans = st.radio(
122
- f"**({code})** {question}",
123
  options=["Tidak", "Ya"],
124
  index=0,
125
  key=f"bc_{code}"
@@ -129,10 +173,11 @@ elif st.session_state.step == 2:
129
  else:
130
  bc_answers[code] = False
131
 
132
- if st.button("Verifikasi Hipotesis", type="primary"):
133
  all_yes = all(bc_answers.values())
134
 
135
  if all_yes:
 
136
  st.session_state.step = 4
137
  st.rerun()
138
  else:
@@ -142,9 +187,7 @@ elif st.session_state.step == 2:
142
 
143
  elif st.session_state.step == 3:
144
  st.divider()
145
- st.subheader("Langkah 3: Forward Chaining (Pencarian Fakta)")
146
- st.error("❌ **Hipotesis AI Ditolak**")
147
- st.warning("Karena hipotesis awal ditolak (ada gejala yang tidak cocok), sistem beralih ke **Forward Chaining** untuk mencari diagnosis alternatif.")
148
 
149
  all_symptoms_list = [f"{k}: {v}" for k,v in SYMPTOM_QUESTIONS.items()]
150
 
@@ -156,7 +199,7 @@ elif st.session_state.step == 3:
156
  default=pre_selected
157
  )
158
 
159
- if st.button("Proses Diagnosis (Forward Chaining)", type="primary"):
160
  final_facts = set()
161
  for item in other_checks:
162
  code = item.split(":")[0].strip()
@@ -172,27 +215,35 @@ elif st.session_state.step == 3:
172
  matches.append(rule)
173
 
174
  if matches:
175
- st.success("✅ **Hasil Forward Chaining Ditemukan!**")
176
- for m in matches:
177
- st.markdown(f"""
178
- ---
179
- ### {m['disease']}
180
- - **Sumber Aturan:** {m['source']}
181
- - **Gejala Terpenuhi:** {', '.join(m['symptoms'])}
182
- """)
183
  else:
184
- st.info("ℹ️ **Tidak Ditemukan Diagnosis Pasti**")
185
  st.write("Kombinasi gejala yang Anda pilih tidak cocok sepenuhnya dengan aturan penyakit manapun dalam basis pengetahuan.")
186
-
187
- if st.button("Mulai Ulang Analisis"):
188
- st.session_state.step = 1
189
- st.session_state.user_facts = set()
190
- st.rerun()
191
 
192
  elif st.session_state.step == 4:
193
  st.divider()
194
- st.success(f"**Diagnosis Terkonfirmasi: {st.session_state.prediction}**")
195
- st.markdown(f"Hipotesis Backward Chaining bernilai **BENAR**. Semua gejala untuk **{st.session_state.prediction}** telah terpenuhi.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
196
 
197
  if st.button("Mulai Ulang Analisis"):
198
  st.session_state.step = 1
 
8
  MODEL_PATH = os.path.join(SCRIPT_DIR, "best.pt")
9
 
10
  SYMPTOM_QUESTIONS = {
11
+ "G1": "Daun berwana putih kecoklatan memanjang seperti mengering pada bagian tepi daun",
12
  "G2": "Pada pagi hari, dapat ditemukan cairan bakteri terlihat seperti butiran air pada bagian terinfeksi",
13
+ "G3": "Gejala terlihat seperti anak panah terdapat di antara urat daun",
14
+ "G4": "Daun Berwarna kuning kecoklatan",
15
+ "G5": "Luka pada daun terlihat transparan bila dihadapkan cahaya matahari",
16
+ "G6": "Daun berbentuk belah ketupat",
17
+ "G7": "Pada daun bagian tengah berwarna abu-abu atau berwarna putih dengan bagian tepi berwarna kecoklatan",
18
+ "G8": "Infeksi pada malai/leher berwarna abu-abu",
19
+ "G9": "Tanaman kerdil dan Gejala pada daun terjadi perubahan warna dari hijau menjadi jingga atau kemerahan",
20
+ "G10": "Bercak cokelat pada daun, pelepah, dan bulir gabah",
21
+ "G11": "Bercak daun sering menutupi permukaan daun, menyebabkan daun menjadi layu",
22
+ "G12": "Bercak cokelat pada batang/leher malai",
23
+ "G13": "Terdapat bercak berbentuk oval berwarna abu-abu kehijauan pada pelepah (tulang daun)",
24
+ "G14": "Batang tanaman padi menjadi rapuh dan mudah rebah/jatuh",
25
+ "G15": "Bibit yang sakit menjadi layu dan akhirnya mati"
 
 
 
 
26
  }
27
 
28
  YOLO_PROMPTS = {
 
30
  "bacterial_leaf_streak": ["G4", "G5"],
31
  "blast": ["G6", "G7", "G8"],
32
  "tungro": ["G9"],
33
+ "brown_spot": ["G10", "G11", "G12"],
34
  "downy_mildew": [],
35
  "dead_heart": [],
36
  "hispa": [],
 
38
  }
39
 
40
  PRODUCTION_RULES = [
41
+ {
42
+ "yolo_class": "bacterial_leaf_blight",
43
+ "disease": "Bacterial Leaf Blight (Hawar Daun Bakteri)",
44
+ "symptoms": ["G1", "G2", "G3"],
45
+ "source": "Literatur 1"
46
+ },
47
+ {
48
+ "yolo_class": "bacterial_leaf_streak",
49
+ "disease": "Bakteri Daun Bergaris (Bacterial Leaf Streak)",
50
+ "symptoms": ["G4", "G5"],
51
+ "source": "Literatur 1"
52
+ },
53
+ {
54
+ "yolo_class": "blast",
55
+ "disease": "Blas (Blast)",
56
+ "symptoms": ["G6", "G7", "G8"],
57
+ "source": "Literatur 1"
58
+ },
59
+ {
60
+ "yolo_class": "tungro",
61
+ "disease": "Tungro",
62
+ "symptoms": ["G9"],
63
+ "source": "Literatur 1"
64
+ },
65
+ {
66
+ "yolo_class": "brown_spot",
67
+ "disease": "Bercak Daun Coklat (Brown Spot)",
68
+ "symptoms": ["G10", "G11", "G12"],
69
+ "source": "Literatur 3"
70
+ },
71
+ {
72
+ "yolo_class": None,
73
+ "disease": "Hawar Pelepah (Sheath Blight)",
74
+ "symptoms": ["G13", "G14", "G15"],
75
+ "source": "Literatur 3"
76
+ },
77
  ]
78
 
79
  @st.cache_resource
 
86
 
87
  model = load_model()
88
 
89
+ st.title("Rice Doctor: Sistem Pakar Penyakit Padi")
90
  st.markdown("""
91
+ Dalam sistem **Rice Doctor**, pengguna dapat:
92
+ 1. **Unggah Gambar Padi**. Untuk mendeteksi penyakit padi.
93
+ 2. **Verifikasi Gejala Penyakit Padi**. Untuk memverifikasi hasil deteksi penyakit padi.
94
+ 3. **Pengecekan Gejala Penyakit Padi Manual**. Jika hasil deteksi penyakit padi sebelummnya tidak terverifikasi.
95
  """)
96
 
97
  if 'step' not in st.session_state:
98
  st.session_state.step = 1
99
  if 'prediction' not in st.session_state:
100
  st.session_state.prediction = None
101
+ if 'forward_matches' not in st.session_state:
102
+ st.session_state.forward_matches = []
103
  if 'hypothesis_codes' not in st.session_state:
104
  st.session_state.hypothesis_codes = []
105
  if 'user_facts' not in st.session_state:
106
  st.session_state.user_facts = set()
107
+ if 'system_method' not in st.session_state:
108
+ st.session_state.system_method = None
109
 
110
  if st.session_state.step == 1:
111
+ st.divider()
112
+ st.subheader("Langkah 1: Unggah Gambar Padi")
113
+ uploaded_file = st.file_uploader(type=["jpg", "png", "jpeg"])
114
 
115
  if uploaded_file is not None:
116
  image = Image.open(uploaded_file)
117
+ col1, col2, col3 = st.columns([1, 2, 1])
118
+ with col2:
119
+ st.image(image, caption="Gambar yang Diunggah", width=300)
120
 
121
+ if st.button("Deteksi Penyakit Padi", type="primary"):
122
  if model:
123
+ with st.spinner("Model AI sedang menganalisis..."):
124
  results = model.predict(image, imgsz=640)
125
+
126
  raw_name = results[0].names[results[0].probs.top1]
127
  top_class_name = raw_name.lower().strip()
128
+ probs = results[0].probs
129
+ top_conf = probs.top1conf.item()
130
 
131
+ st.session_state.image = image
132
  st.session_state.prediction = top_class_name
133
+ st.session_state.prediction_conf = top_conf
134
  st.session_state.hypothesis_codes = YOLO_PROMPTS.get(top_class_name, [])
135
  st.session_state.step = 2
136
  st.rerun()
137
 
138
  elif st.session_state.step == 2:
139
  st.divider()
140
+ st.subheader("Langkah 2: Verifikasi Gejala Penyakit Padi")
141
 
142
+ image = st.session_state.image
143
  pred = st.session_state.prediction
144
+ conf = st.session_state.prediction_conf
145
+ conf_threshold = 0.9
146
  codes = st.session_state.hypothesis_codes
147
 
148
+ st.info(f"🔍 **Hasil Deteksi Penyakit Padi:** {pred}")
 
149
 
150
+ if not codes or (conf < conf_threshold):
151
+ st.warning("Model AI tidak dapat memprediksi penyakit padi dengan keyakinan tinggi.")
152
+ if st.button("Lanjut ke Pengecekan Manual"):
153
  st.session_state.step = 3
154
  st.rerun()
155
  else:
156
+ col1, col2, col3 = st.columns([1, 2, 1])
157
+ with col2:
158
+ st.image(image, caption="Gambar yang Diunggah", width=300)
159
+
160
+ st.write("Jawablah pertanyaan berikut untuk memverifikasi penyakit:")
161
 
162
  bc_answers = {}
163
  for code in codes:
164
  question = SYMPTOM_QUESTIONS.get(code, "Unknown")
165
  ans = st.radio(
166
+ f"**({code})** {question}?",
167
  options=["Tidak", "Ya"],
168
  index=0,
169
  key=f"bc_{code}"
 
173
  else:
174
  bc_answers[code] = False
175
 
176
+ if st.button("Verifikasi Penyakit Padi", type="primary"):
177
  all_yes = all(bc_answers.values())
178
 
179
  if all_yes:
180
+ st.session_state.system_method = "backward"
181
  st.session_state.step = 4
182
  st.rerun()
183
  else:
 
187
 
188
  elif st.session_state.step == 3:
189
  st.divider()
190
+ st.subheader("Langkah 3: Pengecekan Gejala Penyakit Padi Manual")
 
 
191
 
192
  all_symptoms_list = [f"{k}: {v}" for k,v in SYMPTOM_QUESTIONS.items()]
193
 
 
199
  default=pre_selected
200
  )
201
 
202
+ if st.button("Analisis Penyakit Padi", type="primary"):
203
  final_facts = set()
204
  for item in other_checks:
205
  code = item.split(":")[0].strip()
 
215
  matches.append(rule)
216
 
217
  if matches:
218
+ st.session_state.system_method = "forward"
219
+ st.session_state.forward_matches = matches
220
+ st.session_state.step = 4
221
+ st.rerun()
222
+
 
 
 
223
  else:
224
+ st.info("ℹ️ **Sistem Tidak Menemukan Penyakit Padi Secara Pasti**")
225
  st.write("Kombinasi gejala yang Anda pilih tidak cocok sepenuhnya dengan aturan penyakit manapun dalam basis pengetahuan.")
 
 
 
 
 
226
 
227
  elif st.session_state.step == 4:
228
  st.divider()
229
+ st.success("** Penyakit Padi Ditemukan!**")
230
+
231
+ if st.session_state.system_method == "forward":
232
+ for m in st.session_state.forward_matches:
233
+ st.markdown(f"""
234
+ ### {m['disease']}
235
+ - **Sumber Aturan:** {m['source']}
236
+ """)
237
+
238
+ if st.session_state.system_method == "backward":
239
+ matched_rule = next((r for r in PRODUCTION_RULES if r.get("yolo_class") == st.session_state.prediction), None)
240
+ disease = matched_rule['disease'] if matched_rule else st.session_state.prediction
241
+ source = matched_rule['source'] if matched_rule else "Tidak diketahui"
242
+
243
+ st.markdown(f"""
244
+ ### {disease}
245
+ - **Sumber Aturan:** {source}
246
+ """)
247
 
248
  if st.button("Mulai Ulang Analisis"):
249
  st.session_state.step = 1