Upload project Klasifikasi Penyakit - AdindaCintya

This commit is contained in:
adindacintya 2026-08-12 10:08:52 +07:00
parent dfa11b62da
commit 9f7349294d
9 changed files with 762 additions and 115 deletions

View File

@ -40,7 +40,7 @@ public function prediksi(Request $request)
if (!$response->successful()) { if (!$response->successful()) {
Log::error('Server prediksi gagal', ['body' => $response->body()]); Log::error('Server prediksi gagal', ['body' => $response->body()]);
return back()->with('error', 'Tidak dapat memproses prediksi.'); return back()->with('error', 'Sistem tidak dapat melakukan klasifikasi, Pastikan gambar yang diunggah merupakan citra daun padi..');
} }
$hasil = $response->json(); $hasil = $response->json();

BIN
public/images/blast.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

BIN
public/images/blight.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

BIN
public/images/healthy.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1024 KiB

BIN
public/images/tungro.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

View File

@ -6,128 +6,576 @@ import numpy as np
from PIL import Image from PIL import Image
from tensorflow.keras.models import load_model from tensorflow.keras.models import load_model
# ==========================================
# FLASK CONFIG
# ==========================================
app = Flask(__name__) app = Flask(__name__)
CORS(app) 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') # 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
# ==========================================
# 2. Sesuaikan dengan urutan class di Colab kamu (4 class)
CLASS_NAMES = [ CLASS_NAMES = [
'Healthy', 'Healthy',
'Blast', 'Blast',
'Blight', 'Blight',
'Non-Padi',
'Tungro' 'Tungro'
] ]
# ==========================================
# DESKRIPSI HASIL
# ==========================================
DESCRIPTIONS = { DESCRIPTIONS = {
'Healthy': { 'Healthy': {
'deskripsi': 'Kondisi tanaman sehat.',
'solusi': 'Lanjutkan perawatan normal dan pemantauan rutin.' 'deskripsi':
'Daun padi dalam kondisi sehat.',
'solusi':
'Pertahankan pemupukan, pengairan, dan perawatan tanaman secara rutin.'
}, },
'Blast': { 'Blast': {
'deskripsi': 'Blast adalah penyakit daun padi akibat jamur Pyricularia oryzae.',
'solusi': 'Lakukan pengendalian jamur dan semprot fungisida sesuai anjuran.' 'deskripsi':
'Blast merupakan penyakit daun padi yang disebabkan oleh jamur Pyricularia oryzae.',
'solusi':
'Gunakan fungisida dan varietas padi yang tahan terhadap penyakit blast.'
}, },
'Blight': { 'Blight': {
'deskripsi': 'Blight merupakan hawar daun bakteri.',
'solusi': 'Gunakan varietas tahan dan sanitasi lahan yang baik.' 'deskripsi':
'Blight merupakan penyakit hawar daun yang disebabkan oleh bakteri.',
'solusi':
'Gunakan benih sehat dan lakukan sanitasi lahan.'
}, },
'Tungro': { 'Tungro': {
'deskripsi': 'Tungro adalah penyakit virus yang ditularkan oleh wereng.',
'solusi': 'Lakukan pengendalian hama wereng dan gunakan benih sehat.' '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
# ==========================================
# LOAD MODEL
# ==========================================
model = None model = None
try: try:
model = load_model(MODEL_PATH) model = load_model(MODEL_PATH)
print('Model berhasil dimuat dari', MODEL_PATH)
print("Model berhasil dimuat")
print(
"Input Shape :",
model.input_shape
)
print(
"Output Shape:",
model.output_shape
)
except Exception as e: except Exception as e:
print("Gagal load model:", e)
print(
"Gagal load model:",
e
)
# ==========================================
# PREPROCESS IMAGE
# ==========================================
def preprocess_image(path): def preprocess_image(path):
image = Image.open(path).convert('RGB') image = Image.open(path)
image = image.resize((224, 224)) image = image.convert('RGB')
image_array = np.array(image).astype('float32') / 255.0
image_array = np.expand_dims(image_array, axis=0) 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 return image_array
@app.route('/prediksi', methods=['POST'])
def prediksi():
# 3. Menerima request dengan key 'gambar'
if 'gambar' not in request.files:
# ==========================================
# TEST API
# ==========================================
@app.route('/')
def home():
return jsonify({ return jsonify({
'error': 'Tidak ada gambar'
}), 400 "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'] file = request.files['gambar']
if file.filename == '': if file.filename == '':
return jsonify({ return jsonify({
'error': 'File kosong'
}), 400
# Simpan gambar "error":
filename = datetime.now().strftime('%Y%m%d%H%M%S_') + file.filename "File kosong"
}),400
filename = (
datetime.now()
.strftime('%Y%m%d%H%M%S_')
+
file.filename
)
filepath = os.path.join(
UPLOAD_FOLDER,
filename
)
filepath = os.path.join(UPLOAD_FOLDER, filename)
file.save(filepath) file.save(filepath)
print("Gambar diterima:", filename)
print("\n====================")
print(
"Gambar diterima:",
filename
)
if model is None: if model is None:
return jsonify({'error': 'Model tidak tersedia. Pastikan file .h5 ada.'}), 500
return jsonify({
"error":
"Model tidak tersedia"
}),500
try: 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}'
confidence_display = f'{confidence:.2f}%'
all_predictions = { # preprocessing
CLASS_NAMES[i]: float(predictions[0][i] * 100.0)
for i in range(len(CLASS_NAMES)) image_array = preprocess_image(filepath)
}
description_data = DESCRIPTIONS.get(label, {
'deskripsi': 'Tidak ada deskripsi tersedia.',
'solusi': 'Tidak ada solusi tersedia.'
}) # 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({ return jsonify({
'penyakit': label,
'confidence': confidence_display, "error":
'all_predictions': all_predictions,
'deskripsi': description_data['deskripsi'], "Gambar tidak dikenali. Pastikan gambar daun padi."
'solusi': description_data['solusi']
}),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: except Exception as e:
print("ERROR:", e)
print(
"ERROR:",
e
)
return jsonify({ return jsonify({
'error': str(e)
}), 500 "error":
str(e)
}),500
# ==========================================
# RUN FLASK
# ==========================================
if __name__ == '__main__': if __name__ == '__main__':
print('=' * 50)
print('Klasifikasi Penyakit Daun Padi')
print('=' * 50) print("="*50)
app.run(host='127.0.0.1', port=5000, debug=False)
print(
"Klasifikasi Penyakit Daun Padi"
)
print("="*50)
app.run(
host='127.0.0.1',
port=5000,
debug=False
)

View File

@ -25,13 +25,6 @@
<h2 class="text-xl font-bold text-gray-800 mb-6">Statistik Penyakit</h2> <h2 class="text-xl font-bold text-gray-800 mb-6">Statistik Penyakit</h2>
<div class="h-64"><canvas id="chartPenyakit"></canvas></div> <div class="h-64"><canvas id="chartPenyakit"></canvas></div>
</div> </div>
<div class="bg-white p-8 rounded-3xl shadow-sm border border-gray-100">
<h2 class="text-xl font-bold text-gray-800 mb-6">Confusion Matrix</h2>
<div class="bg-gray-50 p-4 rounded-2xl border border-dashed border-gray-200">
<img src="https://miro.medium.com/v2/resize:fit:1200/1*Z54JgbS4DUwWSknhDCvNTQ.png" class="rounded-xl w-full">
</div>
</div>
</div>
<div class="mt-10"> <div class="mt-10">
<div class="flex justify-between items-center mb-6"> <div class="flex justify-between items-center mb-6">

View File

@ -21,7 +21,7 @@
<div class="group bg-white rounded-[2rem] shadow-lg hover:shadow-2xl border border-gray-100 overflow-hidden hover:-translate-y-2 transition-all duration-500 flex flex-col"> <div class="group bg-white rounded-[2rem] shadow-lg hover:shadow-2xl border border-gray-100 overflow-hidden hover:-translate-y-2 transition-all duration-500 flex flex-col">
<div class="relative overflow-hidden h-64 shrink-0"> <div class="relative overflow-hidden h-64 shrink-0">
<img src="https://www.irri.org/sites/default/files/styles/large/public/blast-rice.jpg" <img src="{{ asset('images/blast.jpg') }}"
class="w-full h-full object-cover group-hover:scale-110 transition-transform duration-700"> class="w-full h-full object-cover group-hover:scale-110 transition-transform duration-700">
<div class="absolute inset-0 bg-gradient-to-t from-black/50 to-transparent"></div> <div class="absolute inset-0 bg-gradient-to-t from-black/50 to-transparent"></div>
<div class="absolute bottom-6 left-6"> <div class="absolute bottom-6 left-6">
@ -73,7 +73,7 @@ class="w-full h-full object-cover group-hover:scale-110 transition-transform dur
<div class="group bg-white rounded-[2rem] shadow-lg hover:shadow-2xl border border-gray-100 overflow-hidden hover:-translate-y-2 transition-all duration-500 flex flex-col"> <div class="group bg-white rounded-[2rem] shadow-lg hover:shadow-2xl border border-gray-100 overflow-hidden hover:-translate-y-2 transition-all duration-500 flex flex-col">
<div class="relative overflow-hidden h-64 shrink-0"> <div class="relative overflow-hidden h-64 shrink-0">
<img src="https://www.knowledgebank.irri.org/images/stories/xbacterial-blight.jpg.pagespeed.ic.y.jpg" <img src="{{ asset('images/blight.jpg') }}"
class="w-full h-full object-cover group-hover:scale-110 transition-transform duration-700"> class="w-full h-full object-cover group-hover:scale-110 transition-transform duration-700">
<div class="absolute inset-0 bg-gradient-to-t from-black/50 to-transparent"></div> <div class="absolute inset-0 bg-gradient-to-t from-black/50 to-transparent"></div>
<div class="absolute bottom-6 left-6"> <div class="absolute bottom-6 left-6">
@ -125,7 +125,7 @@ class="w-full h-full object-cover group-hover:scale-110 transition-transform dur
<div class="group bg-white rounded-[2rem] shadow-lg hover:shadow-2xl border border-gray-100 overflow-hidden hover:-translate-y-2 transition-all duration-500 flex flex-col"> <div class="group bg-white rounded-[2rem] shadow-lg hover:shadow-2xl border border-gray-100 overflow-hidden hover:-translate-y-2 transition-all duration-500 flex flex-col">
<div class="relative overflow-hidden h-64 shrink-0"> <div class="relative overflow-hidden h-64 shrink-0">
<img src="https://www.knowledgebank.irri.org/images/stories/tungro-rice.jpg" <img src="{{ asset('images/tungro.jpg') }}"
class="w-full h-full object-cover group-hover:scale-110 transition-transform duration-700"> class="w-full h-full object-cover group-hover:scale-110 transition-transform duration-700">
<div class="absolute inset-0 bg-gradient-to-t from-black/50 to-transparent"></div> <div class="absolute inset-0 bg-gradient-to-t from-black/50 to-transparent"></div>
<div class="absolute bottom-6 left-6"> <div class="absolute bottom-6 left-6">
@ -182,7 +182,7 @@ class="w-full h-full object-cover group-hover:scale-110 transition-transform dur
</div> </div>
<div class="relative overflow-hidden h-64 shrink-0"> <div class="relative overflow-hidden h-64 shrink-0">
<img src="https://www.knowledgebank.irri.org/images/stories/healthy-rice.jpg" <img src="{{ asset('images/healthy.jpg') }}"
class="w-full h-full object-cover group-hover:scale-110 transition-transform duration-700"> class="w-full h-full object-cover group-hover:scale-110 transition-transform duration-700">
<div class="absolute inset-0 bg-gradient-to-t from-black/50 to-transparent"></div> <div class="absolute inset-0 bg-gradient-to-t from-black/50 to-transparent"></div>
<div class="absolute bottom-6 left-6"> <div class="absolute bottom-6 left-6">

View File

@ -127,7 +127,7 @@ class="relative rounded-3xl shadow-2xl border-4 border-white transform hover:sca
<div class="absolute top-0 left-0 w-2 h-full bg-green-500"></div> <div class="absolute top-0 left-0 w-2 h-full bg-green-500"></div>
<h2 class="text-3xl font-extrabold text-gray-800 mb-8 text-center"> <h2 class="text-3xl font-extrabold text-gray-800 mb-8 text-center">
Hasil Analisis AI Hasil Analisis
</h2> </h2>
<img src="{{ asset('uploads/' . session('gambar')) }}" class="w-72 rounded-2xl shadow-xl mb-10 mx-auto border-4 border-white transform hover:scale-105 transition-transform duration-500"> <img src="{{ asset('uploads/' . session('gambar')) }}" class="w-72 rounded-2xl shadow-xl mb-10 mx-auto border-4 border-white transform hover:scale-105 transition-transform duration-500">
@ -198,58 +198,264 @@ class="relative rounded-3xl shadow-2xl border-4 border-white transform hover:sca
</div> </div>
</section> </section>
<section class="max-w-7xl mx-auto px-6 pb-24"> <!-- ================= GALERI PENYAKIT ================= -->
<section class="max-w-7xl mx-auto px-6 pb-24">
<div class="text-center mb-16"> <div class="text-center mb-16">
<h2 class="text-4xl font-extrabold text-gray-800 mb-4">Galeri Penyakit Padi</h2>
<p class="text-gray-500 max-w-2xl mx-auto">Kenali berbagai jenis penyakit yang sering menyerang daun padi beserta gejalanya secara visual.</p> <h2 class="text-4xl font-extrabold text-gray-800 mb-4">
Galeri Penyakit Padi
</h2>
<p class="text-gray-500 max-w-2xl mx-auto">
Kenali berbagai jenis penyakit yang sering menyerang daun padi beserta gejalanya secara visual.
</p>
</div> </div>
<div class="grid md:grid-cols-2 lg:grid-cols-4 gap-8"> <div class="grid md:grid-cols-2 lg:grid-cols-4 gap-8">
<div class="group bg-white rounded-3xl shadow-lg hover:shadow-2xl hover:-translate-y-2 transition-all duration-300 overflow-hidden border border-gray-100">
<!-- BLAST -->
<div class="group bg-white rounded-3xl shadow-lg hover:shadow-2xl hover:-translate-y-2 transition-all duration-300 overflow-hidden border">
<div class="relative overflow-hidden"> <div class="relative overflow-hidden">
<img src="https://images.unsplash.com/photo-1592982537447-6f2a6a0f4d4d?q=80&w=1200&auto=format&fit=crop" class="h-56 w-full object-cover group-hover:scale-110 transition-transform duration-700">
<div class="absolute top-4 right-4 bg-white/90 backdrop-blur-sm px-3 py-1 rounded-full text-xs font-bold text-red-600 shadow-sm">Bahaya</div>
</div> <img
<div class="p-6"> src="{{ asset('images/blast.jpg') }}"
<h3 class="text-2xl font-bold text-gray-800 mb-3 group-hover:text-red-600 transition-colors">Blast</h3> class="h-56 w-full object-cover group-hover:scale-110 transition-transform duration-700"
<p class="text-gray-500 text-sm leading-relaxed">Penyakit akibat jamur yang menyerang daun padi, ditandai dengan bercak belah ketupat.</p> >
</div>
<div class="absolute top-4 right-4 bg-white/90 px-3 py-1 rounded-full text-xs font-bold text-red-600">
Bahaya
</div> </div>
<div class="group bg-white rounded-3xl shadow-lg hover:shadow-2xl hover:-translate-y-2 transition-all duration-300 overflow-hidden border border-gray-100">
<div class="relative overflow-hidden">
<img src="https://images.unsplash.com/photo-1500382017468-9049fed747ef?q=80&w=1200&auto=format&fit=crop" class="h-56 w-full object-cover group-hover:scale-110 transition-transform duration-700">
<div class="absolute top-4 right-4 bg-white/90 backdrop-blur-sm px-3 py-1 rounded-full text-xs font-bold text-yellow-600 shadow-sm">Waspada</div>
</div>
<div class="p-6">
<h3 class="text-2xl font-bold text-gray-800 mb-3 group-hover:text-yellow-600 transition-colors">Blight</h3>
<p class="text-gray-500 text-sm leading-relaxed">Hawar daun bakteri yang menyebabkan daun menguning, mengering, dan mati dari ujungnya.</p>
</div>
</div> </div>
<div class="group bg-white rounded-3xl shadow-lg hover:shadow-2xl hover:-translate-y-2 transition-all duration-300 overflow-hidden border border-gray-100">
<div class="relative overflow-hidden">
<img src="https://images.unsplash.com/photo-1464226184884-fa280b87c399?q=80&w=1200&auto=format&fit=crop" class="h-56 w-full object-cover group-hover:scale-110 transition-transform duration-700">
<div class="absolute top-4 right-4 bg-white/90 backdrop-blur-sm px-3 py-1 rounded-full text-xs font-bold text-orange-500 shadow-sm">Virus</div>
</div>
<div class="p-6"> <div class="p-6">
<h3 class="text-2xl font-bold text-gray-800 mb-3 group-hover:text-orange-500 transition-colors">Tungro</h3>
<p class="text-gray-500 text-sm leading-relaxed">Penyakit virus yang ditularkan wereng hijau, menyebabkan tanaman kerdil dan daun kuning-oranye.</p>
</div> <h3 class="text-2xl font-bold text-gray-800 mb-3">
Blast
</h3>
<p class="text-gray-500 text-sm leading-relaxed">
Penyakit daun padi yang disebabkan oleh jamur
<b>Pyricularia oryzae</b> dengan gejala bercak berbentuk belah ketupat.
</p>
</div> </div>
<div class="group bg-white rounded-3xl shadow-lg hover:shadow-2xl hover:-translate-y-2 transition-all duration-300 overflow-hidden border border-gray-100">
</div>
<!-- BLIGHT -->
<div class="group bg-white rounded-3xl shadow-lg hover:shadow-2xl hover:-translate-y-2 transition-all duration-300 overflow-hidden border">
<div class="relative overflow-hidden"> <div class="relative overflow-hidden">
<img src="https://images.unsplash.com/photo-1472396961693-142e6e269027?q=80&w=1200&auto=format&fit=crop" class="h-56 w-full object-cover group-hover:scale-110 transition-transform duration-700">
<div class="absolute top-4 right-4 bg-white/90 backdrop-blur-sm px-3 py-1 rounded-full text-xs font-bold text-green-600 shadow-sm">Aman</div>
<img
src="{{ asset('images/blight.jpg') }}"
class="h-56 w-full object-cover group-hover:scale-110 transition-transform duration-700"
>
<div class="absolute top-4 right-4 bg-white/90 px-3 py-1 rounded-full text-xs font-bold text-yellow-600">
Waspada
</div> </div>
</div>
<div class="p-6"> <div class="p-6">
<h3 class="text-2xl font-bold text-gray-800 mb-3 group-hover:text-green-600 transition-colors">Healthy</h3>
<p class="text-gray-500 text-sm leading-relaxed">Daun padi sehat tanpa gejala penyakit. Memiliki warna hijau merata dan tekstur normal.</p>
<h3 class="text-2xl font-bold text-gray-800 mb-3">
Blight
</h3>
<p class="text-gray-500 text-sm leading-relaxed">
Penyakit hawar daun bakteri yang menyebabkan daun padi
menguning, layu, dan mengalami kerusakan.
</p>
</div> </div>
</div> </div>
<!-- TUNGRO -->
<div class="group bg-white rounded-3xl shadow-lg hover:shadow-2xl hover:-translate-y-2 transition-all duration-300 overflow-hidden border">
<div class="relative overflow-hidden">
<img
src="{{ asset('images/tungro.jpg') }}"
class="h-56 w-full object-cover group-hover:scale-110 transition-transform duration-700"
>
<div class="absolute top-4 right-4 bg-white/90 px-3 py-1 rounded-full text-xs font-bold text-orange-500">
Virus
</div> </div>
</section>
</div>
<div class="p-6">
<h3 class="text-2xl font-bold text-gray-800 mb-3">
Tungro
</h3>
<p class="text-gray-500 text-sm leading-relaxed">
Penyakit yang disebabkan oleh virus dan ditularkan oleh wereng hijau.
Gejalanya berupa daun menguning dan pertumbuhan tanaman terhambat.
</p>
</div>
</div>
<!-- HEALTHY -->
<div class="group bg-white rounded-3xl shadow-lg hover:shadow-2xl hover:-translate-y-2 transition-all duration-300 overflow-hidden border">
<div class="relative overflow-hidden">
<img
src="{{ asset('images/healthy.jpg') }}"
class="h-56 w-full object-cover group-hover:scale-110 transition-transform duration-700"
>
<div class="absolute top-4 right-4 bg-white/90 px-3 py-1 rounded-full text-xs font-bold text-green-600">
Aman
</div>
</div>
<div class="p-6">
<h3 class="text-2xl font-bold text-gray-800 mb-3">
Healthy
</h3>
<p class="text-gray-500 text-sm leading-relaxed">
Kondisi daun padi sehat dengan warna hijau normal,
tidak ditemukan tanda penyakit.
</p>
</div>
</div>
</div>
</section>
</div> </div>
@ -261,7 +467,7 @@ class="relative rounded-3xl shadow-2xl border-4 border-white transform hover:sca
<div class="absolute inset-4 rounded-full border-b-4 border-yellow-400 animate-spin"></div> <div class="absolute inset-4 rounded-full border-b-4 border-yellow-400 animate-spin"></div>
</div> </div>
<h2 class="text-2xl font-extrabold text-gray-800 mb-2">Menganalisis...</h2> <h2 class="text-2xl font-extrabold text-gray-800 mb-2">Menganalisis...</h2>
<p class="text-gray-500 font-medium">AI sedang memproses gambar Anda.</p> <p class="text-gray-500 font-medium">sedang memproses gambar Anda.</p>
</div> </div>
</div> </div>
@endsection @endsection