from flask import Flask, request, jsonify from flask_cors import CORS import os from datetime import datetime import numpy as np from PIL import Image from tensorflow.keras.models import load_model # ========================================== # FLASK CONFIG # ========================================== app = Flask(__name__) CORS(app) # ========================================== # FOLDER & MODEL # ========================================== UPLOAD_FOLDER = os.path.join( os.path.dirname(__file__), 'uploads' ) os.makedirs( UPLOAD_FOLDER, exist_ok=True ) MODEL_PATH = os.path.join( os.path.dirname(__file__), 'model_padi.h5' ) # ========================================== # CLASS SESUAI TRAINING MODEL # ========================================== CLASS_NAMES = [ 'Healthy', 'Blast', 'Blight', 'Non-Padi', 'Tungro' ] # ========================================== # DESKRIPSI HASIL # ========================================== DESCRIPTIONS = { 'Healthy': { 'deskripsi': 'Daun padi dalam kondisi sehat.', 'solusi': 'Pertahankan pemupukan, pengairan, dan perawatan tanaman secara rutin.' }, 'Blast': { 'deskripsi': 'Blast merupakan penyakit daun padi yang disebabkan oleh jamur Pyricularia oryzae.', 'solusi': 'Gunakan fungisida dan varietas padi yang tahan terhadap penyakit blast.' }, 'Blight': { 'deskripsi': 'Blight merupakan penyakit hawar daun yang disebabkan oleh bakteri.', 'solusi': 'Gunakan benih sehat dan lakukan sanitasi lahan.' }, 'Tungro': { 'deskripsi': 'Tungro merupakan penyakit virus yang ditularkan oleh wereng hijau.', 'solusi': 'Lakukan pengendalian wereng dan gunakan varietas tahan tungro.' }, 'Non-Padi': { 'deskripsi': 'Gambar yang diunggah bukan daun padi.', 'solusi': 'Silakan upload gambar daun padi yang jelas.' } } # ========================================== # LOAD MODEL # ========================================== model = None try: model = load_model(MODEL_PATH) print("Model berhasil dimuat") print( "Input Shape :", model.input_shape ) print( "Output Shape:", model.output_shape ) except Exception as e: print( "Gagal load model:", e ) # ========================================== # PREPROCESS IMAGE # ========================================== def preprocess_image(path): image = Image.open(path) image = image.convert('RGB') image = image.resize( (224,224) ) image_array = np.array(image) image_array = ( image_array.astype('float32') / 255.0 ) image_array = np.expand_dims( image_array, axis=0 ) return image_array # ========================================== # TEST API # ========================================== @app.route('/') def home(): return jsonify({ "status": "API Klasifikasi Penyakit Daun Padi Aktif" }) # ========================================== # PREDIKSI # ========================================== @app.route( '/prediksi', methods=['POST'] ) def prediksi(): if 'gambar' not in request.files: return jsonify({ "error": "Tidak ada gambar dikirim" }),400 file = request.files['gambar'] if file.filename == '': return jsonify({ "error": "File kosong" }),400 filename = ( datetime.now() .strftime('%Y%m%d%H%M%S_') + file.filename ) filepath = os.path.join( UPLOAD_FOLDER, filename ) file.save(filepath) print("\n====================") print( "Gambar diterima:", filename ) if model is None: return jsonify({ "error": "Model tidak tersedia" }),500 try: # preprocessing image_array = preprocess_image(filepath) # prediksi predictions = model.predict( image_array, verbose=0 ) predicted_index = int( np.argmax(predictions[0]) ) confidence = float( np.max(predictions[0]) ) confidence_percent = confidence * 100 label = CLASS_NAMES[ predicted_index ] print("\nHASIL PREDIKSI") for i,nama in enumerate(CLASS_NAMES): print( nama, ":", round( predictions[0][i]*100, 2 ), "%" ) print( "HASIL AKHIR:", label ) print( "CONFIDENCE:", confidence_percent ) # ============================== # FILTER GAMBAR TIDAK JELAS # ============================== if confidence_percent < 60: return jsonify({ "error": "Gambar tidak dikenali. Pastikan gambar daun padi." }),400 # ============================== # TOLAK NON PADI # ============================== if label == "Non-Padi": return jsonify({ "error": "Gambar bukan daun padi. Silakan upload daun padi." }),400 all_predictions = {} for i in range(len(CLASS_NAMES)): all_predictions[ CLASS_NAMES[i] ] = round( float( predictions[0][i]*100 ), 2 ) detail = DESCRIPTIONS[label] return jsonify({ "penyakit": label, "confidence": f"{confidence_percent:.2f}%", "all_predictions": all_predictions, "deskripsi": detail['deskripsi'], "solusi": detail['solusi'] }) except Exception as e: print( "ERROR:", e ) return jsonify({ "error": str(e) }),500 # ========================================== # RUN FLASK # ========================================== if __name__ == '__main__': print("="*50) print( "Klasifikasi Penyakit Daun Padi" ) print("="*50) app.run( host='127.0.0.1', port=5000, debug=False )