File size: 3,350 Bytes
5902df4
d77d1ca
 
 
5902df4
 
e07fa3a
d77d1ca
e07fa3a
 
d77d1ca
5902df4
e07fa3a
5902df4
e07fa3a
 
5902df4
e07fa3a
 
 
 
 
 
 
 
 
3f2f973
e07fa3a
 
3f2f973
e07fa3a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5902df4
e07fa3a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
71960ff
e07fa3a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5902df4
d77d1ca
e07fa3a
 
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
from fastapi import FastAPI, File, UploadFile, HTTPException
import tensorflow as tf
import numpy as np
from PIL import Image
import io
import sys
from tensorflow.keras.applications.densenet import preprocess_input

# 1. Inisialisasi Aplikasi
app = FastAPI(title="Ashoka Hipospadia Classifier API")

# 2. Load Model
print("Sedang memuat model...")
try:
    model = tf.keras.models.load_model('cnn_kfold_best_model_v2.h5')
    print("Model berhasil dimuat!")
except Exception as e:
    print(f"Error memuat model: {e}")
    sys.exit(1)  # Matikan server jika model gagal load

# Label kelas: 0 = normal, 1 = buried
class_names = ['normal', 'buried']

# 3. Fungsi Preprocessing
def prepare_image(image_bytes):
    """
    Preprocessing gambar untuk model ResNet50
    - Konversi ke RGB (3 channel)
    - Resize ke 224x224
    - Preprocessing ResNet50
    """
    try:
        img = Image.open(io.BytesIO(image_bytes))
        
        # Paksa ubah ke RGB agar PNG transparan tidak error
        img = img.convert("RGB")
        
        # Resize ke ukuran input model (224x224 untuk ResNet50)
        img = img.resize((224, 224))
        
        # Convert ke numpy array
        img_array = np.array(img)
        
        # Tambah batch dimension
        img_array = np.expand_dims(img_array, axis=0)
        
        # Preprocessing ResNet50 (HARUS sama dengan training!)
        img_array = preprocess_input(img_array)
        
        return img_array
    except Exception as e:
        print(f"Error saat memproses gambar: {e}")
        return None

# 4. Endpoint Prediksi
@app.post("/predict")
async def predict(file: UploadFile = File(...)):
    """
    Endpoint untuk prediksi gambar
    Input: File gambar (JPG, PNG, BMP)
    Output: JSON dengan class dan confidence
    """
    try:
        # Baca file gambar
        image_bytes = await file.read()
        
        # Proses gambar
        processed_image = prepare_image(image_bytes)
        
        if processed_image is None:
            raise HTTPException(status_code=400, detail="File bukan gambar yang valid")
        
        # Prediksi
        prediction = model.predict(processed_image)
        pred_value = float(prediction[0][0])
        
        # Hitung probabilitas
        # Model output: 0 = normal, 1 = buried
        prob_normal = (1 - pred_value) * 100
        prob_buried = pred_value * 100
        
        # Tentukan kelas berdasarkan threshold 0.5
        top_class_idx = 1 if pred_value > 0.5 else 0
        
        # Hasil dalam format JSON
        result = {
            "class": class_names[top_class_idx],
            "confidence": float(max(prob_normal, prob_buried)),
            "probabilities": {
                "normal": float(prob_normal),
                "buried": float(prob_buried)
            }
        }
        return result
        
    except Exception as e:
        # Cetak error ke log
        print(f"CRITICAL ERROR: {e}")
        raise HTTPException(status_code=500, detail=str(e))

# 5. Endpoint Home
@app.get("/")
def home():
    """Endpoint root untuk testing API"""
    return {
        "message": "Ashoka Hipospadia Classifier API Online! 🚀\n",
        "model": "DenseNet Binary Classification\n",
        "classes": class_names
    }

# API siap digunakan dengan uvicorn
# Jalankan dengan: uvicorn app:app --host 0.0.0.0 --port 7860