Dinaliah commited on
Commit
d77d1ca
·
1 Parent(s): c686147

Adding Files

Browse files
Files changed (5) hide show
  1. .dockerignore +27 -0
  2. Dockerfile +16 -0
  3. app.py +112 -0
  4. cnn_kfold_best_model.h5 +3 -0
  5. requirements.txt +6 -0
.dockerignore ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ **/__pycache__
2
+ **/.venv
3
+ **/.classpath
4
+ **/.dockerignore
5
+ **/.env
6
+ **/.git
7
+ **/.gitignore
8
+ **/.project
9
+ **/.settings
10
+ **/.toolstarget
11
+ **/.vs
12
+ **/.vscode
13
+ **/*.*proj.user
14
+ **/*.dbmdl
15
+ **/*.jfm
16
+ **/bin
17
+ **/charts
18
+ **/docker-compose*
19
+ **/compose*
20
+ **/Dockerfile*
21
+ **/node_modules
22
+ **/npm-debug.log
23
+ **/obj
24
+ **/secrets.dev.yaml
25
+ **/values.dev.yaml
26
+ LICENSE
27
+ README.md
Dockerfile ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.12-slim
2
+
3
+ WORKDIR /app
4
+
5
+ COPY requirements.txt .
6
+
7
+ RUN pip install --no-cache-dir --upgrade pip && \
8
+ pip install --no-cache-dir -r requirements.txt
9
+
10
+ # Copy sisa file (model dan app.py) ke dalam container
11
+ COPY . .
12
+
13
+ # Buka Port 7860 (Standar Hugging Face Spaces)
14
+ EXPOSE 7860
15
+
16
+ CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "7860"]
app.py ADDED
@@ -0,0 +1,112 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import FastAPI, File, UploadFile, HTTPException
2
+ import tensorflow as tf
3
+ import numpy as np
4
+ from PIL import Image
5
+ import io
6
+ import sys
7
+ from tensorflow.keras.applications.resnet50 import preprocess_input
8
+
9
+ # 1. Inisialisasi Aplikasi
10
+ app = FastAPI(title="Ashoka Hipospadia Classifier API")
11
+
12
+ # 2. Load Model
13
+ print("Sedang memuat model...")
14
+ try:
15
+ model = tf.keras.models.load_model('cnn_kfold_best_model.h5')
16
+ print("Model berhasil dimuat!")
17
+ except Exception as e:
18
+ print(f"Error memuat model: {e}")
19
+ sys.exit(1) # Matikan server jika model gagal load
20
+
21
+ # Label kelas: 0 = normal, 1 = buried
22
+ class_names = ['normal', 'buried']
23
+
24
+ # 3. Fungsi Preprocessing
25
+ def prepare_image(image_bytes):
26
+ """
27
+ Preprocessing gambar untuk model ResNet50
28
+ - Konversi ke RGB (3 channel)
29
+ - Resize ke 224x224
30
+ - Preprocessing ResNet50
31
+ """
32
+ try:
33
+ img = Image.open(io.BytesIO(image_bytes))
34
+
35
+ # Paksa ubah ke RGB agar PNG transparan tidak error
36
+ img = img.convert("RGB")
37
+
38
+ # Resize ke ukuran input model (224x224 untuk ResNet50)
39
+ img = img.resize((224, 224))
40
+
41
+ # Convert ke numpy array
42
+ img_array = np.array(img)
43
+
44
+ # Tambah batch dimension
45
+ img_array = np.expand_dims(img_array, axis=0)
46
+
47
+ # Preprocessing ResNet50 (HARUS sama dengan training!)
48
+ img_array = preprocess_input(img_array)
49
+
50
+ return img_array
51
+ except Exception as e:
52
+ print(f"Error saat memproses gambar: {e}")
53
+ return None
54
+
55
+ # 4. Endpoint Prediksi
56
+ @app.post("/predict")
57
+ async def predict(file: UploadFile = File(...)):
58
+ """
59
+ Endpoint untuk prediksi gambar
60
+ Input: File gambar (JPG, PNG, BMP)
61
+ Output: JSON dengan class dan confidence
62
+ """
63
+ try:
64
+ # Baca file gambar
65
+ image_bytes = await file.read()
66
+
67
+ # Proses gambar
68
+ processed_image = prepare_image(image_bytes)
69
+
70
+ if processed_image is None:
71
+ raise HTTPException(status_code=400, detail="File bukan gambar yang valid")
72
+
73
+ # Prediksi
74
+ prediction = model.predict(processed_image)
75
+ pred_value = float(prediction[0][0])
76
+
77
+ # Hitung probabilitas
78
+ # Model output: 0 = normal, 1 = buried
79
+ prob_normal = (1 - pred_value) * 100
80
+ prob_buried = pred_value * 100
81
+
82
+ # Tentukan kelas berdasarkan threshold 0.5
83
+ top_class_idx = 1 if pred_value > 0.5 else 0
84
+
85
+ # Hasil dalam format JSON
86
+ result = {
87
+ "class": class_names[top_class_idx],
88
+ "confidence": float(max(prob_normal, prob_buried)),
89
+ "probabilities": {
90
+ "normal": float(prob_normal),
91
+ "buried": float(prob_buried)
92
+ }
93
+ }
94
+ return result
95
+
96
+ except Exception as e:
97
+ # Cetak error ke log
98
+ print(f"CRITICAL ERROR: {e}")
99
+ raise HTTPException(status_code=500, detail=str(e))
100
+
101
+ # 5. Endpoint Home
102
+ @app.get("/")
103
+ def home():
104
+ """Endpoint root untuk testing API"""
105
+ return {
106
+ "message": "Ashoka Hipospadia Classifier API Online! 🚀",
107
+ "model": "ResNet50 Binary Classification",
108
+ "classes": class_names
109
+ }
110
+
111
+ # API siap digunakan dengan uvicorn
112
+ # Jalankan dengan: uvicorn app:app --host 0.0.0.0 --port 7860
cnn_kfold_best_model.h5 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:8a40cfa4dc21f325ef160b7be42ee5a4533088d1cb1fa17baf0cba72ff3bd634
3
+ size 249086792
requirements.txt ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ tensorflow-cpu>=2.16.0
2
+ fastapi
3
+ uvicorn
4
+ python-multipart
5
+ pillow
6
+ numpy