diff --git a/app/Models/Prediction.php b/app/Models/Prediction.php new file mode 100644 index 0000000..2354f37 --- /dev/null +++ b/app/Models/Prediction.php @@ -0,0 +1,10 @@ +id(); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('predictions'); + } +}; diff --git a/python_ai/app.py b/python_ai/app.py index a254657..669a967 100644 --- a/python_ai/app.py +++ b/python_ai/app.py @@ -1,4 +1,5 @@ from flask import Flask, request, jsonify +from flask_cors import CORS import os from datetime import datetime import numpy as np @@ -6,12 +7,15 @@ from PIL import Image from tensorflow.keras.models import load_model app = Flask(__name__) +CORS(app) UPLOAD_FOLDER = os.path.join(os.path.dirname(__file__), 'uploads') os.makedirs(UPLOAD_FOLDER, exist_ok=True) +# 1. Sesuaikan nama file model! MODEL_PATH = os.path.join(os.path.dirname(__file__), 'model_padi.h5') +# 2. Sesuaikan dengan urutan class di Colab kamu (4 class) CLASS_NAMES = [ 'Healthy', 'Blast', @@ -19,23 +23,34 @@ CLASS_NAMES = [ 'Tungro' ] +DESCRIPTIONS = { + 'Healthy': { + 'deskripsi': 'Kondisi tanaman sehat.', + 'solusi': 'Lanjutkan perawatan normal dan pemantauan rutin.' + }, + 'Blast': { + 'deskripsi': 'Blast adalah penyakit daun padi akibat jamur Pyricularia oryzae.', + 'solusi': 'Lakukan pengendalian jamur dan semprot fungisida sesuai anjuran.' + }, + 'Blight': { + 'deskripsi': 'Blight merupakan hawar daun bakteri.', + 'solusi': 'Gunakan varietas tahan dan sanitasi lahan yang baik.' + }, + 'Tungro': { + 'deskripsi': 'Tungro adalah penyakit virus yang ditularkan oleh wereng.', + 'solusi': 'Lakukan pengendalian hama wereng dan gunakan benih sehat.' + } +} # 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) - print("Model Type :", type(model)) - + print('Model berhasil dimuat dari', MODEL_PATH) except Exception as e: print("Gagal load model:", e) - -# Preprocessing gambar def preprocess_image(path): image = Image.open(path).convert('RGB') @@ -48,10 +63,9 @@ def preprocess_image(path): return image_array - @app.route('/prediksi', methods=['POST']) def prediksi(): - + # 3. Menerima request dengan key 'gambar' if 'gambar' not in request.files: return jsonify({ 'error': 'Tidak ada gambar' @@ -74,80 +88,33 @@ def prediksi(): print("Gambar diterima:", filename) if model is None: - return jsonify({ - 'error': 'Model gagal dimuat' - }), 500 + return jsonify({'error': 'Model tidak tersedia. Pastikan file .h5 ada.'}), 500 try: # Preprocessing image_array = preprocess_image(filepath) + predictions = model.predict(image_array, verbose=0) + predicted_index = int(np.argmax(predictions, axis=1)[0]) + confidence = float(np.max(predictions, axis=1)[0]) * 100.0 + label = CLASS_NAMES[predicted_index] if predicted_index < len(CLASS_NAMES) else f'Kelas {predicted_index + 1}' - # Prediksi - predictions = model.predict(image_array) - - print("\n===== HASIL PREDIKSI =====") - - for i, nama in enumerate(CLASS_NAMES): - print(f"{nama}: {predictions[0][i] * 100:.2f}%") - - predicted_index = int(np.argmax(predictions[0])) - - label = CLASS_NAMES[predicted_index] - - confidence_display = round( - float(predictions[0][predicted_index]) * 100, - 2 - ) - - print(f"HASIL AKHIR: {label}") - print(f"CONFIDENCE: {confidence_display}%") - - # Semua probabilitas - all_predictions = {} - - for i, nama in enumerate(CLASS_NAMES): - - all_predictions[nama] = round( - float(predictions[0][i]) * 100, - 2 - ) - - # Deskripsi penyakit - deskripsi = { - 'Blast': { - 'deskripsi': 'Penyakit jamur yang menyebabkan bercak pada daun.', - 'solusi': 'Gunakan fungisida dan varietas tahan penyakit.' - }, - - 'Blight': { - 'deskripsi': 'Hawar daun akibat bakteri.', - 'solusi': 'Gunakan benih sehat dan kurangi kelembapan.' - }, - - 'Healthy': { - 'deskripsi': 'Daun padi sehat tanpa gejala penyakit.', - 'solusi': 'Pertahankan perawatan tanaman.' - }, - - 'Tungro': { - 'deskripsi': 'Penyakit virus yang ditularkan wereng.', - 'solusi': 'Kendalikan wereng dan gunakan varietas tahan.' - } + confidence_display = f'{confidence:.2f}%' + all_predictions = { + CLASS_NAMES[i]: float(predictions[0][i] * 100.0) + for i in range(len(CLASS_NAMES)) } + description_data = DESCRIPTIONS.get(label, { + 'deskripsi': 'Tidak ada deskripsi tersedia.', + 'solusi': 'Tidak ada solusi tersedia.' + }) return jsonify({ - 'penyakit': label, - 'confidence': confidence_display, - 'all_predictions': all_predictions, - - 'deskripsi': deskripsi[label]['deskripsi'], - - 'solusi': deskripsi[label]['solusi'] - + 'deskripsi': description_data['deskripsi'], + 'solusi': description_data['solusi'] }) except Exception as e: @@ -160,4 +127,7 @@ def prediksi(): if __name__ == '__main__': - app.run(debug=True) \ No newline at end of file + print('=' * 50) + print('Klasifikasi Penyakit Daun Padi') + print('=' * 50) + app.run(host='127.0.0.1', port=5000, debug=False) \ No newline at end of file diff --git a/python_ai/requirements.txt b/python_ai/requirements.txt index 2b698e6..65fb86e 100644 --- a/python_ai/requirements.txt +++ b/python_ai/requirements.txt @@ -1,4 +1,5 @@ flask +flask-cors tensorflow pillow numpy