daunesia / app.py
firmanaziz's picture
Update app.py
66ad94a verified
import gradio as gr
import torch
import torch.nn as nn
from torchvision import models, transforms
from PIL import Image
import os
import google.generativeai as genai
import pandas as pd
# ==============================================================================
# 1. KONFIGURASI DAN MEMUAT SEMUA MODEL
# ==============================================================================
print("Memuat semua model dan konfigurasi...")
device = torch.device('cpu')
# --- A. Muat data referensi link dari CSV ---
try:
df_referensi = pd.read_csv('link_referensi.csv')
print("File 'link_referensi.csv' berhasil dimuat.")
referensi_loaded = True
except FileNotFoundError:
print("PERINGATAN: File 'link_referensi.csv' tidak ditemukan. Fitur referensi resep lokal akan dinonaktifkan.")
referensi_loaded = False
# --- B. Konfigurasi Gemini API ---
try:
genai.configure(api_key=os.environ['GEMINI_API_KEY'])
gemini_model = genai.GenerativeModel("gemini-1.5-flash")
gemini_enabled = True
print("Koneksi ke Gemini API (gemini-1.5-flash) berhasil.")
except KeyError:
gemini_enabled = False
print("PERINGATAN: GEMINI_API_KEY tidak ditemukan. Fitur deskripsi dinonaktifkan.")
# --- C. Muat Model Klasifikasi Biner ---
model_biner = models.mobilenet_v2(pretrained=False)
model_biner.classifier[1] = nn.Linear(model_biner.last_channel, 1)
model_biner.load_state_dict(torch.load('plant_detector_binary.pth', map_location=device))
model_biner.eval()
print("Model deteksi biner (plant_detector_binary.pth) berhasil dimuat.")
# --- D. Muat Model Klasifikasi Herbal (VGG16) ---
with open('class_names.txt', 'r') as f:
class_names = [line.strip() for line in f.readlines()]
num_classes = len(class_names)
# <<<< PERUBAHAN 1: Menggunakan arsitektur VGG16 agar sesuai dengan file bobot
model_herbal = models.vgg16_bn(pretrained=False)
# Struktur classifier VGG16 sama dengan VGG11, jadi baris ini tidak perlu diubah
num_ftrs = model_herbal.classifier[6].in_features
model_herbal.classifier[6] = nn.Linear(num_ftrs, num_classes)
# Memuat file bobot VGG16 Anda
model_herbal.load_state_dict(torch.load('herbal_vgg16_optimized.pth', map_location=device))
model_herbal.eval()
# <<<< PERUBAHAN 2: Memperbarui teks print agar sesuai
print(f"Model deteksi herbal (herbal_vgg16_optimized.pth) dengan {num_classes} kelas berhasil dimuat.")
# --- E. Definisikan Transformasi Gambar ---
# Ukuran 224x224 sudah benar untuk VGG16
transform = transforms.Compose([
transforms.Resize((224, 224)),
transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
])
# ==============================================================================
# 2. DEFINISIKAN FUNGSI-FUNGSI BANTUAN (Tidak ada perubahan di sini)
# ==============================================================================
def get_plant_info_from_gemini(plant_name):
if not gemini_enabled:
return "Fitur deskripsi tidak aktif karena GEMINI_API_KEY tidak dikonfigurasi."
try:
prompt = f"""
Berikan informasi mengenai tanaman herbal '{plant_name}' dalam Bahasa Indonesia.
Tolong susun jawabannya dalam format yang jelas:
**Deskripsi:**
[Tulis deskripsi singkat tentang apa itu tanaman {plant_name}, asalnya, dan ciri-ciri utamanya di sini]
**Manfaat:**
[Sajikan dalam bentuk daftar poin (bullet points)]
- [Manfaat 1]
- [Manfaat 2]
- [dan seterusnya...]
**Cara Pengolahan Umum:**
[Jelaskan cara pengolahan secara umum untuk penggunaan luar dan konsumsi.]
"""
response = gemini_model.generate_content(prompt)
return response.text
except Exception as e:
return f"Gagal menghubungi Gemini: {e}"
def get_links_from_csv(plant_name):
if not referensi_loaded:
return "File referensi lokal tidak dimuat."
hasil = df_referensi[df_referensi['Nama Tanaman'].str.contains(plant_name, case=False, na=False)]
if hasil.empty:
return f"Tidak ditemukan referensi resep lokal untuk '{plant_name}'."
links_markdown = "### Referensi Resep (dari file lokal):\n"
for index, row in hasil.iterrows():
links_markdown += f"- [{row['URL']}]({row['URL']})\n"
return links_markdown
# ==============================================================================
# 3. DEFINISIKAN FUNGSI PREDIKSI UTAMA (Tidak ada perubahan di sini)
# ==============================================================================
def predict_cascaded(image):
if image is None:
return None, "Tidak ada gambar.", "Silakan unggah gambar.", "Tidak ada data."
image_pil = Image.fromarray(image.astype('uint8'), 'RGB')
image_transformed = transform(image_pil).unsqueeze(0).to(device)
with torch.no_grad():
output_biner = model_biner(image_transformed)
prob_is_plant = torch.sigmoid(output_biner).item()
DETECTION_THRESHOLD = 0.5
if prob_is_plant < DETECTION_THRESHOLD:
return {"Bukan Tanaman": 1 - prob_is_plant}, "Gambar tidak terdeteksi sebagai tanaman.", "Silakan unggah gambar tanaman.", "Tidak ada data."
with torch.no_grad():
outputs_herbal = model_herbal(image_transformed)
probabilities = torch.nn.functional.softmax(outputs_herbal[0], dim=0)
confidences = {class_names[i]: float(probabilities[i]) for i in range(num_classes)}
top_prediction_full_name = max(confidences, key=confidences.get)
top_prediction_name = top_prediction_full_name.split('(')[0].strip()
plant_info_gemini = get_plant_info_from_gemini(top_prediction_name)
plant_links_csv = get_links_from_csv(top_prediction_name)
return confidences, top_prediction_full_name, plant_info_gemini, plant_links_csv
# ==============================================================================
# 4. BUAT DAN LUNCURKAN ANTARMUKA GRADIO (Tidak ada perubahan di sini)
# ==============================================================================
interface = gr.Interface(
fn=predict_cascaded,
inputs=gr.Image(label="Unggah Gambar Tanaman"),
outputs=[
gr.Label(num_top_classes=5, label="Hasil Prediksi (Probabilitas)"),
gr.Textbox(label="Objek Terdeteksi"),
gr.Markdown(label="Informasi Tanaman (dari Gemini)"),
gr.Markdown(label="Referensi Resep (dari File Lokal)")
],
title="🌿 Daunesia: Deteksi Cerdas Tanaman Herbal",
description="Sistem deteksi dua-tahap. Unggah gambar untuk mengidentifikasi jenis tanaman, mendapatkan deskripsi dari AI, dan melihat resep dari file lokal.",
examples=[],
allow_flagging="never",
theme=gr.themes.Soft()
)
if __name__ == "__main__":
interface.launch()