Spaces:
Sleeping
Sleeping
| import streamlit as st | |
| import numpy as np | |
| import joblib | |
| import os | |
| from PIL import Image | |
| from tensorflow.keras.applications import ResNet50 | |
| from tensorflow.keras.applications.resnet50 import preprocess_input | |
| from tensorflow.keras.preprocessing.image import img_to_array | |
| # Konfigurasi halaman | |
| st.set_page_config(page_title="Deteksi Kanker Payudara", page_icon="π©Ί", layout="wide") | |
| # Fungsi untuk mencari file secara rekursif | |
| import pathlib | |
| def find_file(filename): | |
| root = pathlib.Path(".") | |
| for path in root.rglob(filename): | |
| return str(path) | |
| return None | |
| # Load model bawaan ResNet50 dan model LightGBM | |
| def load_models(): | |
| resnet = ResNet50(weights="imagenet", include_top=False, pooling="avg") | |
| lgb_path = find_file("lightgbm11_classifier_optimized.pkl") | |
| if not lgb_path: | |
| raise FileNotFoundError("File lightgbm11_classifier_optimized.pkl tidak ditemukan di direktori mana pun.") | |
| lgb = joblib.load(lgb_path) | |
| return resnet, lgb | |
| resnet_model, lgb_model = load_models() | |
| class_labels = {0: "Benign", 1: "Malignant", 2: "Normal"} | |
| # Sidebar | |
| st.sidebar.image("https://cdn-icons-png.flaticon.com/512/3774/3774299.png", width=100) | |
| st.sidebar.markdown("### 𧬠Aplikasi Deteksi Kanker Payudara") | |
| st.sidebar.markdown("**Mata Kuliah: Kecerdasan Buatan** \n**Kelompok 8**") | |
| st.sidebar.info( | |
| "π Model CNN (ResNet50) digunakan untuk ekstraksi fitur dari gambar mamografi, " | |
| "kemudian diklasifikasikan menggunakan LightGBM. Optimasi dilakukan dengan algoritma " | |
| "**Root Mean Square Propagation (RMSProp)**." | |
| ) | |
| # Header | |
| st.markdown("<h1 style='text-align: center;'>π· Sistem Deteksi Otomatis Kanker Payudara</h1>", unsafe_allow_html=True) | |
| st.markdown("<p style='text-align: center;'>Unggah gambar mamografi untuk mengklasifikasi: <b>Benign</b>, <b>Malignant</b>, atau <b>Normal</b>.</p>", unsafe_allow_html=True) | |
| st.markdown("---") | |
| # Formulir Pasien | |
| with st.expander("π§Ύ Formulir Pasien"): | |
| nama = st.text_input("π€ Nama Pasien") | |
| usia = st.number_input("π Usia", min_value=1, max_value=120, value=30) | |
| tanggal = st.date_input("π Tanggal Pemeriksaan") | |
| # Upload gambar | |
| uploaded_file = st.file_uploader("π€ Upload Gambar Mamografi", type=["jpg", "jpeg", "png"]) | |
| if uploaded_file: | |
| try: | |
| col1, col2 = st.columns([1, 2]) | |
| with col1: | |
| image = Image.open(uploaded_file).convert("RGB") | |
| st.image(image, caption="πΌοΈ Gambar Mamografi", use_column_width=True) | |
| with col2: | |
| st.info("π Gambar sedang diproses...") | |
| image = image.resize((224, 224)) | |
| img_array = img_to_array(image) | |
| img_array = np.expand_dims(img_array, axis=0) | |
| img_array = preprocess_input(img_array) | |
| features = resnet_model.predict(img_array, verbose=0) | |
| prediction = lgb_model.predict(features) | |
| result_index = int(prediction[0]) | |
| result = class_labels.get(result_index, "Unknown") | |
| st.subheader("π§ Hasil Klasifikasi") | |
| if result == "Benign": | |
| st.success("π’ Hasil: Benign (Jinak)") | |
| st.markdown("Tumor jinak umumnya tidak menyebar dan tidak bersifat agresif. Tetap lakukan pemeriksaan berkala.") | |
| elif result == "Malignant": | |
| st.error("π΄ Hasil: Malignant (Ganas)") | |
| st.markdown("Tumor ganas dapat menyebar cepat. Segera konsultasikan ke dokter spesialis.") | |
| elif result == "Normal": | |
| st.success("β Hasil: Normal") | |
| st.markdown("Tidak ditemukan indikasi kelainan. Pemeriksaan rutin tetap disarankan.") | |
| # Confidence Score | |
| if st.checkbox("π Tampilkan Confidence Score (%)", value=True): | |
| if hasattr(lgb_model, "predict_proba"): | |
| proba = lgb_model.predict_proba(features)[0] | |
| persentase = np.round(proba * 100, 2) | |
| st.markdown("#### π¬ Probabilitas Klasifikasi") | |
| for label, score in zip(class_labels.values(), persentase): | |
| emoji = "π’" if label == result else "βͺ" | |
| st.markdown(f"{emoji} **{label}**: {score:.2f}%") | |
| st.progress(float(score) / 100) | |
| st.markdown("#### π Tabel Confidence Score") | |
| st.table({ | |
| "Kelas": list(class_labels.values()), | |
| "Probabilitas (%)": [f"{p:.2f}%" for p in persentase] | |
| }) | |
| else: | |
| st.warning("β οΈ Model tidak mendukung probabilitas prediksi.") | |
| except Exception as e: | |
| st.error(f"β Terjadi kesalahan saat prediksi: {str(e)}") | |
| else: | |
| st.warning("π Silakan unggah gambar terlebih dahulu.") | |
| # Edukasi tambahan | |
| with st.expander("βΉοΈ Tentang Kanker Payudara"): | |
| st.markdown(""" | |
| - **Benign**: Tumor tidak ganas, tidak menyebar. Tetap perlu pemantauan. | |
| - **Malignant**: Kanker ganas. Butuh penanganan medis segera. | |
| - **Normal**: Tidak ada indikasi kelainan. | |
| π Lakukan pemeriksaan rutin dan konsultasikan dengan tenaga medis profesional. | |
| """) | |