Spaces:
Running
Running
File size: 7,410 Bytes
ce1ca74 63cc014 4d3afde ce1ca74 4d3afde ce1ca74 4d3afde 1481953 4d3afde ce1ca74 4d3afde 63cc014 4d3afde ce1ca74 4d3afde ce1ca74 4d3afde ce1ca74 4d3afde ce1ca74 4d3afde ce1ca74 4d3afde ce1ca74 4d3afde ce1ca74 4d3afde ce1ca74 4d3afde ce1ca74 4d3afde ce1ca74 4d3afde ce1ca74 4d3afde ce1ca74 4d3afde ce1ca74 a79b65e |
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 |
import gradio as gr
import tensorflow as tf
import numpy as np
from PIL import Image
# --- KONFIGURASI ---
IMG_SIZE = (224, 224)
MODEL_PATH = "best_model.h5"
# Definisi Kelas (Sesuai urutan training model Anda)
class_names = [
'Abrasions', 'Bruises', 'Burns', 'Cut', 'Diabetic Wounds',
'Laceration', 'Normal', 'Pressure Wounds', 'Surgical Wounds', 'Venous Wounds'
]
# Mapping Bahasa Inggris -> Indonesia untuk UI
translation_map = {
'Abrasions': 'Luka Lecet (Abrasi)',
'Bruises': 'Memar',
'Burns': 'Luka Bakar',
'Cut': 'Luka Sayat',
'Diabetic Wounds': 'Luka Diabetes',
'Laceration': 'Luka Robek',
'Normal': 'Normal/Sehat',
'Pressure Wounds': 'Luka Tekan (Dekubitus)',
'Surgical Wounds': 'Luka Operasi',
'Venous Wounds': 'Luka Vena'
}
# --- LOAD MODEL ---
try:
best_model = tf.keras.models.load_model(MODEL_PATH)
print("✅ Model berhasil dimuat.")
except Exception as e:
best_model = None
print(f"❌ Error memuat model: {e}")
# --- LOGIKA REKOMENDASI ---
def get_first_aid_recommendation(wound_class):
rekomendasi = {
'Abrasions': (
"1. Bersihkan luka dengan air mengalir untuk membuang kotoran.\n"
"2. Gunakan sabun lembut di sekitar luka (jangan terkena luka langsung).\n"
"3. Oleskan salep antibiotik atau petroleum jelly untuk menjaga kelembapan.\n"
"4. Tutup dengan plester bersih jika luka berada di area yang mudah tergesek."
),
'Bruises': (
"1. Istirahatkan area yang memar.\n"
"2. Kompres dingin selama 15-20 menit untuk mengurangi pembengkakan.\n"
"3. Posisikan bagian tubuh yang memar lebih tinggi dari jantung.\n"
"4. Gunakan obat pereda nyeri jika diperlukan."
),
'Burns': (
"1. Alirkan air biasa (bukan air es) pada area luka selama 10-20 menit.\n"
"2. Lepaskan perhiasan atau pakaian yang ketat sebelum area membengkak.\n"
"3. Tutup longgar dengan kain bersih atau kasa steril.\n"
"4. **Jangan** memecahkan lepuh yang muncul."
),
'Cut': (
"1. Tekan luka kuat-kuat dengan kain bersih selama 5-10 menit hingga darah berhenti.\n"
"2. Bersihkan luka dengan air mengalir.\n"
"3. Oleskan antiseptik pada pinggiran luka.\n"
"4. Rekatkan plester atau perban steril."
),
'Diabetic Wounds': (
"**Peringatan:** Luka diabetes membutuhkan perhatian khusus.\n"
"1. Cuci luka dengan cairan saline (NaCl 0.9%).\n"
"2. Jaga luka tetap kering dan tutup dengan kasa steril.\n"
"3. Periksa tanda-tanda infeksi seperti nanah atau bau.\n"
"4. Segera hubungi dokter spesialis luka."
),
'Laceration': (
"1. Hentikan perdarahan dengan menekan luka secara stabil.\n"
"2. Jika luka dalam dan robekannya lebar, segera tutup dengan kasa.\n"
"3. Jangan mencoba mencuci luka jika perdarahan sangat deras.\n"
"4. **Segera ke IGD** karena mungkin memerlukan jahitan medis."
),
'Normal': "Kulit terlihat normal dan sehat. Tetap jaga kebersihan area tersebut.",
'Pressure Wounds': (
"1. Hilangkan tekanan pada area luka dengan mengubah posisi tubuh.\n"
"2. Gunakan bantal atau bantalan pelindung khusus.\n"
"3. Bersihkan area secara lembut dengan cairan saline.\n"
"4. Jaga kulit di sekitarnya tetap lembap."
),
'Surgical Wounds': (
"1. Ikuti instruksi penggantian perban dari dokter bedah Anda.\n"
"2. Jangan menggaruk area jahitan.\n"
"3. Jaga agar luka tetap kering saat mandi (gunakan penutup tahan air).\n"
"4. Lapor dokter jika jahitan terbuka atau muncul kemerahan hebat."
),
'Venous Wounds': (
"1. Gunakan stoking kompresi jika disarankan oleh medis.\n"
"2. Angkat kaki lebih tinggi dari jantung saat berbaring.\n"
"3. Lakukan aktivitas fisik ringan secara teratur.\n"
"4. Jaga kelembapan kulit di sekitar luka."
)
}
return rekomendasi.get(wound_class, "Rekomendasi belum tersedia. Silakan konsultasi dengan petugas medis.")
# --- FUNGSI PREDIKSI ---
def predict_image(image_input):
if best_model is None:
return {}, "⚠️ Model tidak ditemukan. Harap upload file model (.h5)."
if image_input is None:
return {}, "Silakan upload gambar."
# Preprocessing
img = image_input.resize(IMG_SIZE)
img_array = tf.keras.utils.img_to_array(img)
img_array = tf.expand_dims(img_array, 0)
img_array = img_array / 255.0
# Prediksi
predictions = best_model.predict(img_array)
scores = tf.nn.softmax(predictions[0]).numpy()
# Mapping hasil untuk UI (Bahasa Indonesia)
translated_output_dict = {
translation_map.get(class_names[i], class_names[i]): float(scores[i])
for i in range(len(class_names))
}
# Ambil label tertinggi
top_idx = np.argmax(scores)
top_label_en = class_names[top_idx]
top_confidence = scores[top_idx]
# --- LOGIKA THRESHOLD ---
THRESHOLD = 0.20
if top_confidence < THRESHOLD:
top_label_id = "Normal (Tidak Terdeteksi)"
rekomendasi_teks = (
"**Mohon Maaf:** Model kurang akurat dalam menganalisis foto ini.\n\n"
"**Saran:**\n"
"1. Pastikan area luka terlihat jelas dan tidak blur.\n"
"2. Gunakan pencahayaan yang cukup (terang).\n"
"3. Ambil foto dari sudut tegak lurus ke arah luka.\n\n"
"Jika Anda merasa luka ini serius, segera hubungi tenaga medis meskipun hasil analisis tidak muncul."
)
else:
top_label_id = translation_map.get(top_label_en, top_label_en)
rekomendasi_teks = get_first_aid_recommendation(top_label_en)
# Format Markdown untuk Gradio
formatted_output = (
f"### Analisis: **{top_label_id}**\n\n"
f"**Langkah Pertolongan:**\n{rekomendasi_teks}\n\n"
f"--- \n*Tingkat Keyakinan AI: {top_confidence:.2%}*"
)
return translated_output_dict, formatted_output
# --- UI INTERFACE ---
with gr.Blocks(theme=gr.themes.Soft(primary_hue="red", secondary_hue="slate")) as demo:
gr.Markdown("# 🚨 FirstAidLens")
gr.Markdown("Deteksi jenis luka secara instan dan dapatkan panduan pertolongan pertama yang tepat.")
with gr.Row():
with gr.Column(scale=1):
input_img = gr.Image(
sources=["upload", "webcam"],
type="pil",
label="Ambil Foto Luka"
)
gr.Markdown("> **Penting:** Hasil AI ini hanya referensi awal. Jika luka parah atau pendarahan tidak berhenti, segera hubungi **112**.")
with gr.Column(scale=1):
output_label = gr.Label(num_top_classes=3, label="Hasil Analisis Jenis Luka")
output_markdown = gr.Markdown("### Panduan Pertolongan Pertama\n_Upload atau ambil foto untuk melihat rekomendasi._")
# Trigger otomatis saat gambar diupload/diambil
input_img.change(
fn=predict_image,
inputs=input_img,
outputs=[output_label, output_markdown]
)
# Launch (Server Name 0.0.0.0 wajib untuk Docker)
if __name__ == "__main__":
demo.launch(server_name="0.0.0.0", server_port=7860) |