Daunesia / app.py
GwFirman's picture
Update app.py
b966c01 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. Impor library pandas
# ==============================================================================
# 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 ---
with open('class_names.txt', 'r') as f:
class_names = [line.strip() for line in f.readlines()]
num_classes = len(class_names)
model_herbal = models.vgg11_bn(pretrained=False)
num_ftrs = model_herbal.classifier[6].in_features
model_herbal.classifier[6] = nn.Linear(num_ftrs, num_classes)
model_herbal.load_state_dict(torch.load('herbal_vgg11_optimized.pth', map_location=device))
model_herbal.eval()
print(f"Model deteksi herbal (herbal_vgg11_optimized.pth) dengan {num_classes} kelas berhasil dimuat.")
# --- E. Definisikan Transformasi Gambar ---
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
# ==============================================================================
def get_plant_info_from_gemini(plant_name):
"""Meminta informasi tanaman dari Gemini (tanpa resep)."""
if not gemini_enabled:
return "Fitur deskripsi tidak aktif karena GEMINI_API_KEY tidak dikonfigurasi."
try:
# Prompt diubah untuk tidak secara eksplisit meminta link resep lagi
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}"
# 2. Fungsi baru untuk mencari link di file CSV
def get_links_from_csv(plant_name):
"""Mencari link referensi dari file CSV yang sudah dimuat."""
if not referensi_loaded:
return "File referensi lokal tidak dimuat."
# Cari baris yang cocok dengan plant_name
# Menggunakan .str.contains untuk pencarian yang lebih fleksibel, case=False agar tidak sensitif huruf besar/kecil
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}'."
# Format output menjadi markdown list
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
# ==============================================================================
def predict_cascaded(image):
"""Fungsi utama yang menjalankan semua tahap prediksi."""
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)
# --- Tahap 1: Deteksi Biner ---
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."
# --- Tahap 2: Identifikasi Jenis Herbal ---
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)}
# Mendapatkan nama prediksi teratas tanpa nama latinnya
top_prediction_full_name = max(confidences, key=confidences.get)
# Membersihkan nama tanaman, mengambil bagian sebelum tanda kurung buka
top_prediction_name = top_prediction_full_name.split('(')[0].strip()
# --- Tahap 3: Dapatkan Informasi dari Gemini dan File CSV ---
plant_info_gemini = get_plant_info_from_gemini(top_prediction_name)
plant_links_csv = get_links_from_csv(top_prediction_name) # Panggil fungsi baru
# 3. Kembalikan 4 nilai output
return confidences, top_prediction_full_name, plant_info_gemini, plant_links_csv
# ==============================================================================
# 4. BUAT DAN LUNCURKAN ANTARMUKA GRADIO
# ==============================================================================
interface = gr.Interface(
fn=predict_cascaded,
inputs=gr.Image(label="Unggah Gambar Tanaman"),
# 4. Tambahkan output baru untuk menampilkan link dari CSV
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)") # Output baru
],
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=[
# Anda mungkin perlu mengganti contoh ini dengan file gambar yang Anda miliki
# ["nangkacempedak.jpg"],
# ["aloevera.jpeg"]
],
allow_flagging="never",
theme=gr.themes.Soft()
)
if __name__ == "__main__":
interface.launch()