from pathlib import Path import gradio as gr import numpy as np from PIL import Image from tensorflow import keras PROJECT_ROOT = Path(__file__).resolve().parent MODEL_PATH = PROJECT_ROOT / "face_mask_model.keras" IMAGE_SIZE = (224, 224) CLASS_NAMES = ["with_mask", "without_mask"] if not MODEL_PATH.exists(): raise FileNotFoundError( f"Model tidak ditemukan di {MODEL_PATH}. Pastikan file .keras tersedia." ) model = keras.models.load_model(MODEL_PATH) def build_examples() -> list[list[str]]: example_paths = [] candidate_files = [ PROJECT_ROOT / "data" / "with_mask" / "with_mask_1.jpg", PROJECT_ROOT / "data" / "without_mask" / "without_mask_1.jpg", PROJECT_ROOT / "data" / "with_mask" / "with_mask_10.jpg", PROJECT_ROOT / "data" / "without_mask" / "without_mask_10.jpg", ] for path in candidate_files: if path.exists(): example_paths.append([str(path)]) return example_paths def predict_mask(image: Image.Image): if image is None: raise gr.Error("Silakan unggah gambar wajah terlebih dahulu.") image = image.convert("RGB").resize(IMAGE_SIZE) image_array = np.asarray(image, dtype=np.float32) batch = np.expand_dims(image_array, axis=0) predictions = model.predict(batch, verbose=0)[0] scores = {label: float(score) for label, score in zip(CLASS_NAMES, predictions)} predicted_index = int(np.argmax(predictions)) predicted_label = CLASS_NAMES[predicted_index] confidence = float(predictions[predicted_index]) * 100 summary = ( f"Prediksi: {predicted_label.replace('_', ' ').title()} | " f"Confidence: {confidence:.2f}%" ) return scores, summary custom_css = """ body { background: radial-gradient(circle at top left, #fff5d6 0%, transparent 32%), radial-gradient(circle at top right, #d8f5ff 0%, transparent 30%), linear-gradient(135deg, #f7f2e8 0%, #eef7ff 48%, #f5efe4 100%); } .gradio-container { max-width: 1100px !important; } .hero { padding: 20px 24px; border-radius: 24px; background: linear-gradient(135deg, rgba(17, 24, 39, 0.94), rgba(31, 41, 55, 0.88)); color: #f9fafb; box-shadow: 0 16px 40px rgba(15, 23, 42, 0.15); margin-bottom: 16px; } .hero h1 { margin: 0 0 8px 0; font-size: 2.2rem; } .hero p { margin: 0; color: #e5e7eb; line-height: 1.6; } """ with gr.Blocks( theme=gr.themes.Soft( primary_hue="cyan", secondary_hue="amber", neutral_hue="slate", ), css=custom_css, title="Face Mask Detector", ) as demo: gr.HTML( """

Face Mask Detector

Unggah gambar wajah untuk mendeteksi apakah orang tersebut memakai masker atau tidak. Model diambil langsung dari file face_mask_model.keras.

""" ) with gr.Row(): with gr.Column(scale=5): image_input = gr.Image( type="pil", label="Input Wajah", sources=["upload", "webcam"], ) predict_button = gr.Button("Prediksi Sekarang", variant="primary") with gr.Column(scale=4): label_output = gr.Label( label="Probabilitas Kelas", num_top_classes=2, ) summary_output = gr.Textbox( label="Ringkasan Hasil", interactive=False, ) examples = build_examples() if examples: gr.Examples( examples=examples, inputs=image_input, label="Contoh Gambar", ) predict_button.click( fn=predict_mask, inputs=image_input, outputs=[label_output, summary_output], ) image_input.change( fn=predict_mask, inputs=image_input, outputs=[label_output, summary_output], ) if __name__ == "__main__": demo.launch()