Flask

Integrasi Model Klasifikasi Gambar (Gunting Batu Kertas)

Kita akan membuat API untuk model Paper Rock Scrissors

Author : Celvine Adi Putra | Date : Desember, 08 2025

Pendahuluan

Kita akan melanjutkan aplikasi flask-diabetes yang telah kamu buat sebelumnya. Fokus kita hari ini adalah menambahkan kemampuan Machine Learning untuk pengolahan citra (gambar).

Secara sederhana, kita akan mengimplementasikan fitur yang mampu mengenali foto tangan dan mengklasifikasikannya menjadi simbol "Gunting", "Batu", atau "Kertas".

Prasyarat:

  • Project flask-diabetes dari pertemuan sebelumnya.
  • File model RPS.keras yang sudah dilatih (tersedia di Materi ini).

Langkah 1: Persiapan Model dan Virtual Environment

Pastikan semua aset dan library sudah disiapkan.

1.1 Folder Model

Download file model dengan ekstensi .keras. Pindahkan file tersebut ke dalam folder models/ di dalam struktur direktori project kamu agar rapi dan mudah diakses.

model_diabetes.pkl
RPS.keras
main.py

1.2 Instalasi Dependensi

Kita memerlukan library keras dan tensorflow untuk memuat dan menjalankan model Deep Learning tersebut. Silakan jalankan perintah berikut di terminal kamu:

uv add keras==3.10.0
uv add tensorflow==2.20.0

Catatan: Jika kamu mengalami kendala instalasi dengan tensorflow versi 2.20.0, kamu dapat mencoba versi 2.19.0 sebagai alternatif agar sama dengan versi yang digunakan oleh google colab.


Langkah 2: Import Library

Buka file main.py. Kita perlu memanggil fungsi-fungsi dari TensorFlow untuk memproses gambar sebelum gambar tersebut dapat dibaca oleh model.

Tambahkan kode berikut di bagian atas file, bergabung dengan import lainnya:

main.py
import joblib
import pandas as pd
import tensorflow as tf
import numpy as np
import io

from flask_cors import CORS
from flask import Flask, jsonify, request

from tensorflow.keras.preprocessing import image
from tensorflow.keras.applications.mobilenet_v3 import preprocess_input

Penjelasan Kode:

  • from tensorflow.keras.preprocessing import image: Modul ini menyediakan alat bantu untuk memuat gambar dari file dan mengubahnya menjadi format array (susunan angka) yang bisa dipahami komputer.
  • from tensorflow.keras.applications.mobilenet_v3 import preprocess_input: Ini adalah fungsi khusus untuk menormalisasi data gambar agar sesuai dengan standar format model MobileNetV3 yang kita gunakan.

Langkah 3: Memuat Model dan Definisi Kelas

Masih di dalam main.py, kita akan memuat model ke dalam memori aplikasi. Tujuannya agar model siap digunakan kapan saja tanpa perlu dimuat ulang setiap kali ada permintaan (request) dari pengguna, yang akan memperlambat aplikasi.

Tambahkan kode ini di bawah inisialisasi aplikasi Flask atau di tempat kamu memuat model diabetes sebelumnya:

main.py
# Memuat model yang telah dilatih
loaded_model = joblib.load("models/model_diabetes.pkl")
loaded_model_rps = tf.keras.models.load_model("models/RPS.keras")


columns = [
    'Pregnancies',
    'Glucose',
    'BloodPressure',
    'SkinThickness',
    'Insulin',
    'BMI',
    'DiabetesPedigreeFunction',
    'Age'
]
# Mendefinisikan label kelas (Wajib berurutan sesuai saat training)
rps_class_names = ['Paper', 'Rock', 'Scissors']

Penjelasan Kode:

  • tf.keras.models.load_model(...): Fungsi ini membaca struktur dan bobot (weights) dari file .keras lalu merekonstruksinya menjadi objek model Python yang siap melakukan prediksi.
  • rps_class_names: Model Deep Learning biasanya hanya mengembalikan hasil berupa angka indeks (misalnya 0, 1, atau 2). List ini berfungsi menerjemahkan angka tersebut menjadi label teks. Penting: Urutannya harus sama persis dengan urutan saat model dilatih (0='Paper', 1='Rock', 2='Scissors').

Langkah 4: Membuat Endpoint Prediksi

Sekarang kita masuk ke pembuatan endpoint. Kita akan membuat rute (route) API baru yang bertugas menerima file gambar dari pengguna, memprosesnya, meminta model melakukan prediksi, dan mengembalikan hasilnya dalam format JSON.

Tambahkan fungsi berikut di bagian bawah file main.py:

main.py
@app.route("/api/predict", methods=["POST"])
def predict():
    # Code prediksi diabetes (sebelumnya)

@app.route("/api/predict-rps", methods=["POST"])
def predict_rps():
    # 1. Validasi request file
    if 'file' not in request.files:
        return jsonify({
            "meta": {
                "status": 400,
                "message": "No file in the request"
            }
        })

    # 2. Membaca File Gambar
    file = request.files['file']
    img_bytes = io.BytesIO(file.read())

    # 3. Preprocessing Gambar
    img = image.load_img(img_bytes, target_size=(150, 150))
    img_array = image.img_to_array(img)
    img_array = preprocess_input(img_array)
    img_batch = np.expand_dims(img_array, axis=0)

    # 4. Proses Prediksi (Inferensi)
    prediction = loaded_model_rps.predict(img_batch)
    predicted_class_index = np.argmax(prediction)

    # 5. Mengembalikan Respons
    return jsonify({
        "meta": {
            "status": 200,
            "message": "Prediction successful"
        },
        "data": {
            "prediction": rps_class_names[predicted_class_index],
            "probability": f"{np.max(prediction) * 100:.2f}%"
        }
    })

Penjelasan Detail Langkah demi Langkah:

Bagian 1: Validasi Kita memeriksa apakah pengirim benar-benar menyertakan data dengan nama kunci file. Jika tidak, server akan merespons dengan status 400 Bad Request untuk mencegah error pada proses selanjutnya.

Bagian 2: Membaca File

  • file.read(): Membaca isi file yang diunggah.
  • io.BytesIO(...): Kita menyimpan file tersebut sementara di memori RAM sebagai aliran byte, bukan menyimpannya ke harddisk server. Ini membuat proses lebih cepat dan efisien.

Bagian 3: Preprocessing (Sangat Penting) Agar model bisa bekerja, gambar input harus disesuaikan dengan format saat model tersebut dilatih:

  1. Resize: target_size=(150, 150) mengubah ukuran gambar menjadi 150x150 piksel secara otomatis.
  2. To Array: Mengubah gambar visual menjadi matriks angka.
  3. Preprocess Input: Menyesuaikan rentang nilai piksel agar sesuai dengan standar MobileNetV3.
  4. Expand Dims: Menambahkan satu dimensi ekstra karena TensorFlow mengharapkan input dalam bentuk tumpukan (batch), meskipun kita hanya memprediksi satu gambar. Dimensi berubah dari (150, 150, 3) menjadi (1, 150, 150, 3).

Bagian 4: Prediksi

  • predict(img_batch): Model menghitung probabilitas untuk setiap kemungkinan kelas. Hasilnya berupa array, contoh: [0.1, 0.8, 0.1].
  • np.argmax(...): Fungsi ini mencari posisi (indeks) yang memiliki nilai probabilitas tertinggi. Dari contoh di atas, nilai tertinggi ada di indeks ke-1.

Bagian 5: Response Kita menyusun hasil akhir dalam format JSON standar.

  • rps_class_names[...]: Mengubah indeks angka (hasil argmax) menjadi nama kelas (misal: "Rock").
  • probability: Mengambil nilai keyakinan model dan memformatnya menjadi persentase.

Uji Coba

Silakan uji coba endpoint /api/predict-rps ini menggunakan aplikasi seperti Postman:

  1. Set method ke POST.
  2. Masuk ke tab Body lalu pilih form-data.
  3. Isi Key dengan file (ubah tipe dari Text menjadi File).
  4. Upload gambar tangan (Gunting, Batu, atau Kertas) dan kirim (Send).