|
|
import gradio as gr |
|
|
import tensorflow as tf |
|
|
import pandas as pd |
|
|
import numpy as np |
|
|
from datetime import datetime |
|
|
from PIL import Image |
|
|
|
|
|
MODEL_PATH = "best_model.h5" |
|
|
class_names = ['layak', 'rusak'] |
|
|
history_data = [] |
|
|
|
|
|
try: |
|
|
best_model = tf.keras.models.load_model(MODEL_PATH) |
|
|
print("β
Model berhasil dimuat.") |
|
|
except Exception as e: |
|
|
print(f"β Gagal memuat model: {e}") |
|
|
|
|
|
best_model = None |
|
|
|
|
|
|
|
|
def get_detailed_info(label, confidence): |
|
|
if label == 'layak': |
|
|
if confidence > 0.85: |
|
|
return "### β
STATUS: SANGAT LAYAK\n**Analisis:** Bangunan dalam kondisi prima. Struktur utama terlihat utuh dan sangat aman untuk dihuni." |
|
|
return "### β οΈ STATUS: LAYAK (DENGAN CATATAN)\n**Analisis:** Bangunan aman dihuni, namun ditemukan indikasi kerusakan minor. Disarankan pengecekan rutin pada area retakan." |
|
|
else: |
|
|
if confidence > 0.85: |
|
|
return "### π¨ STATUS: RUSAK PARAH\n**Analisis:** BAHAYA! Ditemukan kerusakan struktur fatal. Segera kosongkan area dan hubungi pihak berwenang." |
|
|
return "### π§ STATUS: RUSAK RINGAN\n**Analisis:** Terdeteksi kerusakan fisik pada beberapa bagian. Perlu perbaikan teknis sebelum bangunan dinyatakan aman sepenuhnya." |
|
|
|
|
|
def predict_image(img): |
|
|
if best_model is None: |
|
|
return {}, "Model belum dimuat." |
|
|
|
|
|
|
|
|
img = img.resize((224, 224)) |
|
|
img_array = tf.keras.preprocessing.image.img_to_array(img) |
|
|
img_array = tf.expand_dims(img_array, 0) / 255.0 |
|
|
|
|
|
|
|
|
predictions = best_model.predict(img_array)[0] |
|
|
result = {class_names[i]: float(predictions[i]) for i in range(len(class_names))} |
|
|
|
|
|
top_label = max(result, key=result.get) |
|
|
description = get_detailed_info(top_label, result[top_label]) |
|
|
return result, description |
|
|
|
|
|
|
|
|
def handle_upload(img): |
|
|
if img is None: return {}, "_Menunggu foto bangunan..._" |
|
|
return predict_image(img) |
|
|
|
|
|
def handle_report(img, location): |
|
|
if img is None: |
|
|
return {}, pd.DataFrame(history_data, columns=["Waktu", "Status", "Lokasi"]), None, "β Gagal: Foto kosong." |
|
|
|
|
|
output_dict, desc = predict_image(img) |
|
|
status = max(output_dict, key=output_dict.get).upper() |
|
|
now = datetime.now().strftime("%H:%M | %d-%m-%Y") |
|
|
|
|
|
history_data.insert(0, [now, status, location if location else "Pusat Kota"]) |
|
|
df = pd.DataFrame(history_data, columns=["Waktu", "Status", "Lokasi"]) |
|
|
|
|
|
return output_dict, df, None, "β
Laporan berhasil disimpan ke riwayat!" |
|
|
|
|
|
|
|
|
with gr.Blocks(title="HomeCheck AI") as demo: |
|
|
|
|
|
with gr.Row(): |
|
|
with gr.Column(scale=8): |
|
|
gr.Markdown("# π HomeCheck AI") |
|
|
gr.Markdown("### *Sistem Deteksi Kelayakan Bangunan Cerdas*") |
|
|
with gr.Column(scale=2): |
|
|
gr.Markdown("") |
|
|
|
|
|
gr.Markdown("---") |
|
|
|
|
|
with gr.Tabs(): |
|
|
with gr.TabItem("π Analisis Baru"): |
|
|
with gr.Row(): |
|
|
|
|
|
with gr.Column(variant="panel"): |
|
|
gr.Markdown("#### π₯ Input Data") |
|
|
input_img = gr.Image(sources=["upload", "webcam"], type="pil", label="Foto Bangunan") |
|
|
input_loc = gr.Textbox( |
|
|
label="Titik Lokasi", |
|
|
placeholder="Contoh: Perumahan Indah Blok A, Medan", |
|
|
lines=1 |
|
|
) |
|
|
btn_report = gr.Button("π SIMPAN LAPORAN", variant="primary") |
|
|
|
|
|
|
|
|
with gr.Column(): |
|
|
gr.Markdown("#### π Hasil Diagnosa") |
|
|
output_label = gr.Label(num_top_classes=2, label="Probabilitas Akurasi") |
|
|
|
|
|
with gr.Group(): |
|
|
output_description = gr.Markdown( |
|
|
"**Instruksi:**\nSilakan ambil atau upload foto bagian bangunan yang ingin diperiksa.", |
|
|
) |
|
|
|
|
|
with gr.TabItem("π Riwayat Pemeriksaan"): |
|
|
gr.Markdown("#### π Log Laporan Tersimpan") |
|
|
output_history = gr.Dataframe( |
|
|
headers=["Waktu", "Status", "Lokasi"], |
|
|
datatype=["str", "str", "str"], |
|
|
interactive=False |
|
|
) |
|
|
|
|
|
gr.Markdown("---") |
|
|
gr.Markdown("Β© 2026 HomeCheck AI") |
|
|
|
|
|
|
|
|
input_img.change(fn=handle_upload, inputs=input_img, outputs=[output_label, output_description]) |
|
|
|
|
|
btn_report.click( |
|
|
fn=handle_report, |
|
|
inputs=[input_img, input_loc], |
|
|
outputs=[output_label, output_history, input_img, output_description] |
|
|
) |
|
|
|
|
|
if __name__ == "__main__": |
|
|
demo.launch(server_name="0.0.0.0", server_port=7860) |