File size: 3,209 Bytes
75170ac
 
 
 
 
 
 
bd20b63
 
 
 
 
 
75170ac
bd20b63
75170ac
 
bd20b63
 
 
 
 
 
 
3dee800
bd20b63
 
 
 
 
 
 
 
 
 
 
 
 
 
 
75170ac
 
bd20b63
 
75170ac
 
 
bd20b63
75170ac
bd20b63
 
75170ac
bd20b63
 
 
75170ac
 
 
 
 
bd20b63
75170ac
 
 
bd20b63
75170ac
 
bd20b63
75170ac
 
bd20b63
 
 
 
75170ac
 
 
 
 
bd20b63
75170ac
bd20b63
 
75170ac
 
bd20b63
75170ac
 
bd20b63
 
 
 
 
 
75170ac
bd20b63
 
75170ac
 
bd20b63
75170ac
 
 
 
bd20b63
 
 
 
75170ac
 
 
bd20b63
 
75170ac
 
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
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 import MobileNetV2
from tensorflow.keras.applications.mobilenet_v2 import preprocess_input
from tensorflow.keras.layers import GlobalAveragePooling2D, Dense, Dropout
from tensorflow.keras.models import Model

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

# ===============================
# 2. Build Model (SAMA DENGAN TRAINING)
# ===============================
def build_model():
    base_model = MobileNetV2(
        input_shape=(224, 224, 3),
        include_top=False,
        weights="imagenet"
    )
    base_model.trainable = False

    x = base_model.output
    x = GlobalAveragePooling2D()(x)
    x = Dropout(0.2)(x)
    output = Dense(1, activation="sigmoid")(x)

    model = Model(inputs=base_model.input, outputs=output)
    return model


# ===============================
# 3. Load Weights
# ===============================
print("Sedang memuat model...")
try:
    model = build_model()
    model.load_weights("sultan_model.weights.h5")
    print("Model berhasil dimuat!")
except Exception as e:
    print(f"Error memuat model: {e}")
    sys.exit(1)

# Label kelas
class_names = ["normal", "buried"]

# ===============================
# 4. Preprocessing Image
# ===============================
def prepare_image(image_bytes):
    try:
        img = Image.open(io.BytesIO(image_bytes))
        img = img.convert("RGB")
        img = img.resize((224, 224))

        img_array = np.array(img)
        img_array = np.expand_dims(img_array, axis=0)
        img_array = preprocess_input(img_array)

        return img_array
    except Exception as e:
        print(f"Error preprocessing image: {e}")
        return None


# ===============================
# 5. Endpoint Prediksi
# ===============================
@app.post("/predict")
async def predict(file: UploadFile = File(...)):
    try:
        image_bytes = await file.read()
        processed_image = prepare_image(image_bytes)

        if processed_image is None:
            raise HTTPException(status_code=400, detail="Invalid image file")

        prediction = model.predict(processed_image)
        pred_value = float(prediction[0][0])

        prob_normal = (1 - pred_value) * 100
        prob_buried = pred_value * 100

        predicted_class = "buried" if pred_value > 0.5 else "normal"

        return {
            "class": predicted_class,
            "confidence": max(prob_normal, prob_buried),
            "probabilities": {
                "normal": prob_normal,
                "buried": prob_buried
            }
        }

    except Exception as e:
        print(f"CRITICAL ERROR: {e}")
        raise HTTPException(status_code=500, detail=str(e))


# ===============================
# 6. Endpoint Root
# ===============================
@app.get("/")
def home():
    return {
        "message": "Ashoka Hipospadia Classifier API Online 🚀",
        "model": "MobileNetV2 Binary Classification",
        "classes": class_names
    }