File size: 3,496 Bytes
d5d8aa3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
181924b
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
import io
import numpy as np
import tensorflow as tf
from fastapi import FastAPI, File, UploadFile, Form, HTTPException
from PIL import Image

app = FastAPI(
    title="Freshly API",
    description="API deteksi kematangan buah dan sayur.",
    version="1.0.2"
)

# 1. Konfigurasi Model
CONFIG = {
    "banana":  ['banana_ripe', 'banana_rotten', 'banana_unripe'],
    "mango":   ['mango_ripe', 'mango_rotten', 'mango_unripe'],
    "orange":  ['orange_ripe', 'orange_rotten', 'orange_unripe'],
    "chili":   ['chili_ripe', 'chili_rotten', 'chili_unripe'],
    "paprika": ['paprika_ripe', 'paprika_rotten', 'paprika_unripe'],
    "tomato":  ['tomato_ripe', 'tomato_rotten', 'tomato_unripe']
}

IMG_SIZE = (224, 224)
MEAN = np.array([0.485, 0.456, 0.406])
STD = np.array([0.229, 0.224, 0.225])

# 2. Memuat Semua Model ke Memori
models = {}
print("Memulai proses pemuatan semua model...")
for fruit_type in CONFIG.keys():
    model_folder = f"{fruit_type}_saved_model"
    try:
        models[fruit_type] = tf.keras.models.load_model(model_folder)
        print(f" -> Model {fruit_type.upper()} berhasil dimuat.")
    except Exception as e:
        print(f" [X] Gagal memuat model {fruit_type}: {e}")

# 3. Fungsi Preprocessing
def preprocess_image(image_bytes):
    try:
        img = Image.open(io.BytesIO(image_bytes)).convert('RGB')
        img = img.resize(IMG_SIZE)
        img_array = tf.keras.utils.img_to_array(img)
        img_array = img_array / 255.0
        img_array = (img_array - MEAN) / STD
        img_array = np.expand_dims(img_array, axis=0)
        return img_array
    except Exception as e:
        raise ValueError(f"Gagal memproses gambar: {str(e)}")

# ENDPOINT HEALTH CHECK (Untuk UptimeRobot)
@app.get("/health")
def health_check():
    return {"status": "active", "message": "Server is awake and ready!"}

# ENDPOINT PREDIKSI (Satu URL untuk semua model)
@app.post("/predict")
async def predict_fruit(

    # Menerima teks (jenis buah) dan file (gambar) dalam satu Form yang sama

    fruit_type: str = Form(..., description="Tulis: banana, mango, orange, chili, paprika, atau tomato"),

    file: UploadFile = File(...)

):
    fruit_type = fruit_type.lower()
    
    # Validasi jenis buah
    if fruit_type not in models:
        raise HTTPException(
            status_code=404, 
            detail=f"Model '{fruit_type}' tidak ada. Pilihan: {list(models.keys())}"
        )
    
    # Validasi file
    if not file.content_type.startswith('image/'):
        raise HTTPException(status_code=400, detail="File harus berupa gambar.")
    
    try:
        contents = await file.read()
        img_tensor = preprocess_image(contents)
        
        # Prediksi
        active_model = models[fruit_type]
        class_names = CONFIG[fruit_type]
        
        predictions = active_model.predict(img_tensor)
        pred_index = np.argmax(predictions[0])
        confidence = float(predictions[0][pred_index])
        
        return {
            "fruit_type": fruit_type,
            "filename": file.filename,
            "predicted_class": class_names[pred_index],
            "confidence": round(confidence * 100, 2),
            "all_probabilities": {
                class_names[i]: round(float(predictions[0][i]) * 100, 2) for i in range(len(class_names))
            }
        }
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))