|
|
import torch |
|
|
import torch.nn as nn |
|
|
from torchvision import transforms |
|
|
from PIL import Image |
|
|
import gradio as gr |
|
|
import networkx as nx |
|
|
import os |
|
|
from transformers import AutoModel, AutoConfig |
|
|
from openai import OpenAI |
|
|
import json |
|
|
import gdown |
|
|
|
|
|
|
|
|
MODEL_PATH = "best.pt" |
|
|
if not os.path.exists(MODEL_PATH): |
|
|
|
|
|
file_id = "1bGRLEC2_5GB53E-zEVH1Z4EQdKGA-YGI" |
|
|
url = f"https://drive.google.com/uc?id={file_id}" |
|
|
print("Downloading model from Google Drive...") |
|
|
gdown.download(url, MODEL_PATH, quiet=False) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
G = nx.DiGraph() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
G.add_edge("Olive-brown velvety spots on leaves/fruits", "Apple___Apple_scab") |
|
|
G.add_edge("Dark sunken lesions with concentric rings", "Apple___Black_rot") |
|
|
G.add_edge("Orange/yellow spots with black centers", "Apple___Cedar_apple_rust") |
|
|
G.add_edge("No visible disease", "Apple___healthy") |
|
|
|
|
|
|
|
|
G.add_edge("No visible disease", "Blueberry___healthy") |
|
|
|
|
|
|
|
|
G.add_edge("White powdery coating on leaves", "Cherry_(including_sour)___Powdery_mildew") |
|
|
G.add_edge("No visible disease", "Cherry_(including_sour)___healthy") |
|
|
|
|
|
|
|
|
G.add_edge("Gray/tan lesions with dark borders", "Corn_(maize)___Cercospora_leaf_spot Gray_leaf_spot") |
|
|
G.add_edge("Small reddish-brown pustules on leaves", "Corn_(maize)___Common_rust_") |
|
|
G.add_edge("Cigar-shaped gray-green lesions on leaves", "Corn_(maize)___Northern_Leaf_Blight") |
|
|
G.add_edge("No visible disease", "Corn_(maize)___healthy") |
|
|
|
|
|
|
|
|
G.add_edge("Circular black spots on leaves/fruits", "Grape___Black_rot") |
|
|
G.add_edge("Interveinal chlorosis, necrosis (black measles)", "Grape___Esca_(Black_Measles)") |
|
|
G.add_edge("Irregular brown spots with yellow halo", "Grape___Leaf_blight_(Isariopsis_Leaf_Spot)") |
|
|
G.add_edge("No visible disease", "Grape___healthy") |
|
|
|
|
|
|
|
|
G.add_edge("Yellow shoots, mottled leaves, misshapen fruits", "Orange___Haunglongbing_(Citrus_greening)") |
|
|
|
|
|
|
|
|
G.add_edge("Small dark water-soaked spots on leaves", "Peach___Bacterial_spot") |
|
|
G.add_edge("No visible disease", "Peach___healthy") |
|
|
|
|
|
|
|
|
G.add_edge("Brown lesions with yellow halo", "Pepper,_bell___Bacterial_spot") |
|
|
G.add_edge("No visible disease", "Pepper,_bell___healthy") |
|
|
|
|
|
|
|
|
G.add_edge("Dark concentric spots on leaves", "Potato___Early_blight") |
|
|
G.add_edge("Large irregular brown/black lesions", "Potato___Late_blight") |
|
|
G.add_edge("No visible disease", "Potato___healthy") |
|
|
|
|
|
|
|
|
G.add_edge("No visible disease", "Raspberry___healthy") |
|
|
|
|
|
|
|
|
G.add_edge("No visible disease", "Soybean___healthy") |
|
|
|
|
|
|
|
|
G.add_edge("White powdery patches on leaves", "Squash___Powdery_mildew") |
|
|
|
|
|
|
|
|
G.add_edge("Irregular brown leaf margins, scorching", "Strawberry___Leaf_scorch") |
|
|
G.add_edge("No visible disease", "Strawberry___healthy") |
|
|
|
|
|
|
|
|
G.add_edge("Water-soaked brown spots on leaves", "Tomato___Bacterial_spot") |
|
|
G.add_edge("Concentric rings, target-like spots", "Tomato___Early_blight") |
|
|
G.add_edge("Large dark blotches with fuzzy growth", "Tomato___Late_blight") |
|
|
G.add_edge("Yellow patches on upper leaf, fuzzy underside", "Tomato___Leaf_Mold") |
|
|
G.add_edge("Small circular dark spots with yellow halo", "Tomato___Septoria_leaf_spot") |
|
|
G.add_edge("White/yellow stippling + webbing", "Tomato___Spider_mites Two-spotted_spider_mite") |
|
|
G.add_edge("Brown/black target-like spots", "Tomato___Target_Spot") |
|
|
G.add_edge("Leaf curling + yellow mosaic", "Tomato___Tomato_Yellow_Leaf_Curl_Virus") |
|
|
G.add_edge("Mosaic mottling on leaves", "Tomato___Tomato_mosaic_virus") |
|
|
G.add_edge("No visible disease", "Tomato___healthy") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
G.add_edge("Apple___Apple_scab", "Fungicides (captan, myclobutanil), prune infected leaves") |
|
|
G.add_edge("Apple___Black_rot", "Remove mummified fruits, use fungicides") |
|
|
G.add_edge("Apple___Cedar_apple_rust", "Remove nearby junipers, apply fungicides") |
|
|
G.add_edge("Apple___healthy", "No treatment needed") |
|
|
|
|
|
|
|
|
G.add_edge("Blueberry___healthy", "No treatment needed") |
|
|
|
|
|
|
|
|
G.add_edge("Cherry_(including_sour)___Powdery_mildew", "Fungicides: sulfur, myclobutanil") |
|
|
G.add_edge("Cherry_(including_sour)___healthy", "No treatment needed") |
|
|
|
|
|
|
|
|
G.add_edge("Corn_(maize)___Cercospora_leaf_spot Gray_leaf_spot", "Use resistant hybrids, fungicides") |
|
|
G.add_edge("Corn_(maize)___Common_rust_", "Resistant hybrids, fungicide if severe") |
|
|
G.add_edge("Corn_(maize)___Northern_Leaf_Blight", "Crop rotation, resistant varieties, fungicides") |
|
|
G.add_edge("Corn_(maize)___healthy", "No treatment needed") |
|
|
|
|
|
|
|
|
G.add_edge("Grape___Black_rot", "Fungicides (mancozeb, myclobutanil), prune infected vines") |
|
|
G.add_edge("Grape___Esca_(Black_Measles)", "Remove infected wood, fungicides not very effective") |
|
|
G.add_edge("Grape___Leaf_blight_(Isariopsis_Leaf_Spot)", "Remove infected leaves, fungicides") |
|
|
G.add_edge("Grape___healthy", "No treatment needed") |
|
|
|
|
|
|
|
|
G.add_edge("Orange___Haunglongbing_(Citrus_greening)", "No cure, control psyllid vector, use resistant rootstocks") |
|
|
|
|
|
|
|
|
G.add_edge("Peach___Bacterial_spot", "Copper fungicides, resistant varieties") |
|
|
G.add_edge("Peach___healthy", "No treatment needed") |
|
|
|
|
|
|
|
|
G.add_edge("Pepper,_bell___Bacterial_spot", "Use copper-based bactericides, resistant cultivars") |
|
|
G.add_edge("Pepper,_bell___healthy", "No treatment needed") |
|
|
|
|
|
|
|
|
G.add_edge("Potato___Early_blight", "Use fungicides: Mancozeb, Chlorothalonil") |
|
|
G.add_edge("Potato___Late_blight", "Copper-based fungicides, resistant varieties") |
|
|
G.add_edge("Potato___healthy", "No treatment needed") |
|
|
|
|
|
|
|
|
G.add_edge("Raspberry___healthy", "No treatment needed") |
|
|
|
|
|
|
|
|
G.add_edge("Soybean___healthy", "No treatment needed") |
|
|
|
|
|
|
|
|
G.add_edge("Squash___Powdery_mildew", "Sulfur-based fungicides, resistant varieties") |
|
|
|
|
|
|
|
|
G.add_edge("Strawberry___Leaf_scorch", "Remove infected leaves, apply fungicides") |
|
|
G.add_edge("Strawberry___healthy", "No treatment needed") |
|
|
|
|
|
|
|
|
G.add_edge("Tomato___Bacterial_spot", "Copper sprays, avoid overhead irrigation") |
|
|
G.add_edge("Tomato___Early_blight", "Fungicides: Chlorothalonil, crop rotation") |
|
|
G.add_edge("Tomato___Late_blight", "Copper fungicides, remove infected plants") |
|
|
G.add_edge("Tomato___Leaf_Mold", "Fungicides: Chlorothalonil, improve ventilation") |
|
|
G.add_edge("Tomato___Septoria_leaf_spot", "Apply fungicides, remove infected leaves") |
|
|
G.add_edge("Tomato___Spider_mites Two-spotted_spider_mite", "Insecticidal soap, neem oil, predatory mites") |
|
|
G.add_edge("Tomato___Target_Spot", "Fungicides: Chlorothalonil, Mancozeb") |
|
|
G.add_edge("Tomato___Tomato_Yellow_Leaf_Curl_Virus", "No cure: use resistant varieties, control whiteflies") |
|
|
G.add_edge("Tomato___Tomato_mosaic_virus", "Remove infected plants, disinfect tools") |
|
|
G.add_edge("Tomato___healthy", "No treatment needed") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
symptom_map = { |
|
|
"Apple___Apple_scab": "Olive-brown velvety spots on leaves/fruits", |
|
|
"Apple___Black_rot": "Dark sunken lesions with concentric rings", |
|
|
"Apple___Cedar_apple_rust": "Orange/yellow spots with black centers", |
|
|
"Apple___healthy": "No visible disease", |
|
|
|
|
|
"Blueberry___healthy": "No visible disease", |
|
|
|
|
|
"Cherry_(including_sour)___Powdery_mildew": "White powdery coating on leaves", |
|
|
"Cherry_(including_sour)___healthy": "No visible disease", |
|
|
|
|
|
"Corn_(maize)___Cercospora_leaf_spot Gray_leaf_spot": "Gray/tan lesions with dark borders", |
|
|
"Corn_(maize)___Common_rust_": "Small reddish-brown pustules on leaves", |
|
|
"Corn_(maize)___Northern_Leaf_Blight": "Cigar-shaped gray-green lesions on leaves", |
|
|
"Corn_(maize)___healthy": "No visible disease", |
|
|
|
|
|
"Grape___Black_rot": "Circular black spots on leaves/fruits", |
|
|
"Grape___Esca_(Black_Measles)": "Interveinal chlorosis, necrosis (black measles)", |
|
|
"Grape___Leaf_blight_(Isariopsis_Leaf_Spot)": "Irregular brown spots with yellow halo", |
|
|
"Grape___healthy": "No visible disease", |
|
|
|
|
|
"Orange___Haunglongbing_(Citrus_greening)": "Yellow shoots, mottled leaves, misshapen fruits", |
|
|
|
|
|
"Peach___Bacterial_spot": "Small dark water-soaked spots on leaves", |
|
|
"Peach___healthy": "No visible disease", |
|
|
|
|
|
"Pepper,_bell___Bacterial_spot": "Brown lesions with yellow halo", |
|
|
"Pepper,_bell___healthy": "No visible disease", |
|
|
|
|
|
"Potato___Early_blight": "Dark concentric spots on leaves", |
|
|
"Potato___Late_blight": "Large irregular brown/black lesions", |
|
|
"Potato___healthy": "No visible disease", |
|
|
|
|
|
"Raspberry___healthy": "No visible disease", |
|
|
"Soybean___healthy": "No visible disease", |
|
|
|
|
|
"Squash___Powdery_mildew": "White powdery patches on leaves", |
|
|
|
|
|
"Strawberry___Leaf_scorch": "Irregular brown leaf margins, scorching", |
|
|
"Strawberry___healthy": "No visible disease", |
|
|
|
|
|
"Tomato___Bacterial_spot": "Water-soaked brown spots on leaves", |
|
|
"Tomato___Early_blight": "Concentric rings, target-like spots", |
|
|
"Tomato___Late_blight": "Large dark blotches with fuzzy growth", |
|
|
"Tomato___Leaf_Mold": "Yellow patches on upper leaf, fuzzy underside", |
|
|
"Tomato___Septoria_leaf_spot": "Small circular dark spots with yellow halo", |
|
|
"Tomato___Spider_mites Two-spotted_spider_mite": "White/yellow stippling + webbing", |
|
|
"Tomato___Target_Spot": "Brown/black target-like spots", |
|
|
"Tomato___Tomato_Yellow_Leaf_Curl_Virus": "Leaf curling + yellow mosaic", |
|
|
"Tomato___Tomato_mosaic_virus": "Mosaic mottling on leaves", |
|
|
"Tomato___healthy": "No visible disease" |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class DinoClassifier(nn.Module): |
|
|
def __init__(self, base_model, num_classes, hidden_size): |
|
|
super().__init__() |
|
|
self.base = base_model |
|
|
self.classifier = nn.Linear(hidden_size, num_classes) |
|
|
|
|
|
def forward(self, x): |
|
|
outputs = self.base(x) |
|
|
pooled = outputs.last_hidden_state.mean(dim=1) |
|
|
return self.classifier(pooled) |
|
|
|
|
|
model_name = "facebook/dinov3-vits16-pretrain-lvd1689m" |
|
|
hf_token = os.environ.get("HF_TOKEN") |
|
|
|
|
|
config = AutoConfig.from_pretrained(model_name, use_auth_token=hf_token) |
|
|
base_model = AutoModel.from_pretrained(model_name, config=config, use_auth_token=hf_token) |
|
|
|
|
|
|
|
|
num_classes = 38 |
|
|
model = DinoClassifier(base_model, num_classes, config.hidden_size) |
|
|
checkpoint = torch.load(MODEL_PATH, map_location="cpu") |
|
|
model.load_state_dict(checkpoint["model_state_dict"]) |
|
|
class_names = checkpoint["classes"] |
|
|
model.eval() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
val_test_tfms = transforms.Compose([ |
|
|
transforms.Resize((224, 224)), |
|
|
transforms.ToTensor(), |
|
|
transforms.Normalize(mean=(0.5, 0.5, 0.5), |
|
|
std=(0.5, 0.5, 0.5)), |
|
|
]) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
client = OpenAI(api_key=os.environ.get("OPENAI_API_KEY")) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def predict_pipeline(image: Image.Image, get_explanation: bool = True): |
|
|
|
|
|
x = val_test_tfms(image).unsqueeze(0) |
|
|
|
|
|
|
|
|
with torch.no_grad(): |
|
|
logits = model(x) |
|
|
pred_idx = logits.argmax(1).item() |
|
|
pred_class = class_names[pred_idx] |
|
|
|
|
|
|
|
|
symptom = symptom_map.get(pred_class, "Unknown") |
|
|
treatment = list(G.neighbors(pred_class)) if pred_class in G else ["No treatment found"] |
|
|
|
|
|
|
|
|
result_json = { |
|
|
"Predicted Disease": pred_class, |
|
|
"Symptom": symptom, |
|
|
"Treatment": ", ".join(treatment), |
|
|
} |
|
|
|
|
|
|
|
|
if get_explanation: |
|
|
prompt = f""" |
|
|
You are an agriculture expert. |
|
|
Disease: {pred_class} |
|
|
Symptom: {symptom} |
|
|
Treatment: {', '.join(treatment)} |
|
|
|
|
|
Provide a **detailed explanation** in Markdown with sections: |
|
|
1. What causes it |
|
|
2. How to control it |
|
|
3. Prevention methods |
|
|
""" |
|
|
try: |
|
|
response = client.chat.completions.create( |
|
|
model="gpt-4o-mini", |
|
|
messages=[{"role": "user", "content": prompt}], |
|
|
temperature=0.7 |
|
|
) |
|
|
llm_text = response.choices[0].message.content |
|
|
except Exception as e: |
|
|
llm_text = f"**LLM Error:** {str(e)}" |
|
|
else: |
|
|
llm_text = "GPT explanation skipped for speed." |
|
|
|
|
|
return json.dumps(result_json, indent=2), llm_text |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
demo = gr.Interface( |
|
|
fn=predict_pipeline, |
|
|
inputs=[gr.Image(type="pil")], |
|
|
outputs=[ |
|
|
gr.Textbox(label="π Prediction Summary", lines=10, interactive=False), |
|
|
gr.Markdown(label="π Detailed Explanation") |
|
|
], |
|
|
title="π± Plant Disease Detection App", |
|
|
description="Upload a plant leaf image to detect disease, get symptoms, treatment, and optionally an expert explanation." |
|
|
) |
|
|
|
|
|
if __name__ == "__main__": |
|
|
demo.launch() |
|
|
|
|
|
|