import gradio as gr import spaces import torch import os from PIL import Image from transformers import AutoImageProcessor, AutoModelForImageClassification try: from llama_cpp import Llama except ImportError: Llama = None from huggingface_hub import hf_hub_download # --- 1. SYSTEM INITIALIZATION & MODEL INGESTION --- print("[System] Allocating local models...") VISION_MODEL_ID = "Usefulmech/vit-plant-disease-advisor" try: image_processor = AutoImageProcessor.from_pretrained("google/vit-base-patch16-224") vision_model = AutoModelForImageClassification.from_pretrained(VISION_MODEL_ID) vision_model.eval() print(f"[System] Successfully loaded {VISION_MODEL_ID}") except Exception as e: print(f"[Warning] Failed to load {VISION_MODEL_ID}. Falling back to base model for testing. Error: {e}") VISION_MODEL_ID = "google/vit-base-patch16-224" image_processor = AutoImageProcessor.from_pretrained(VISION_MODEL_ID) vision_model = AutoModelForImageClassification.from_pretrained(VISION_MODEL_ID) vision_model.eval() # B. Local LLM GGUF Setup via llama.cpp try: print("[System] Fetching GGUF weights from Hub...") model_path = hf_hub_download( repo_id="Qwen/Qwen2.5-3B-Instruct-GGUF", filename="qwen2.5-3b-instruct-q4_k_m.gguf", local_dir="./models" ) llm = Llama(model_path=model_path, n_ctx=2048, n_threads=4) print("[System] LLM successfully initialized.") except Exception as e: print(f"[Critical Error] Failed to initialize llama.cpp: {e}") llm = None def parse_label(raw_label): if raw_label == "healthy": return "Healthy plant foliage with no active disease patterns detected" # Convert 'Tomato___Late_blight' to 'Tomato: Late Blight' clean = str(raw_label).replace("___", ": ").replace("__", " ").replace("_", " ") return clean.title() @spaces.GPU def process_field_analysis(input_img): if input_img is None: return "
⚠️ Error: Please input or capture an image before executing analysis.
" try: pil_img = Image.open(input_img).convert("RGB") inputs = image_processor(images=pil_img, return_tensors="pt") with torch.no_grad(): outputs = vision_model(**inputs) logits = outputs.logits predicted_class_idx = logits.argmax(-1).item() raw_label = vision_model.config.id2label[predicted_class_idx] probabilities = torch.nn.functional.softmax(logits, dim=-1) confidence_float = probabilities[0][predicted_class_idx].item() confidence_pct = int(confidence_float * 100) clean_disease_name = parse_label(raw_label) if confidence_float < 0.40: msg = "

⚠️ System Alert

Unable to make a clear diagnosis. Please upload a sharper, close-up photo of the leaf under better lighting.

" return msg system_prompt = ( "You are a helpful tropical agronomist providing organic advice to smallholder farmers. " "Based on the identified plant condition, provide a simple description and a 2-3 step treatment plan. " "Only recommend accessible, local natural remedies like neem oil, wood ash, or removing damaged leaves. " "Never recommend synthetic chemical pesticides. Provide everything strictly in clear, plain English. Be direct and action-oriented." ) user_prompt = f"Plant Condition: {clean_disease_name}. Confidence: {confidence_pct}%." formatted_prompt = f"<|im_start|>system\n{system_prompt}<|im_end|>\n<|im_start|>user\n{user_prompt}<|im_end|>\n<|im_start|>assistant\n" if llm: output = llm(formatted_prompt, max_tokens=350, temperature=0.2, stop=["<|im_end|>"]) ai_response = output["choices"][0]["text"].strip() # Convert simple markdown to HTML for rendering ai_response = ai_response.replace("\n", "
") else: ai_response = "Fallback Report: Model engine offline.

1. Isolate the damaged crop foliage immediately.
2. Ensure neem solution application to prevent further spread." report_html = ( f"
" f"

📋 Diagnostics Report

" f"

Condition Identified: {clean_disease_name}

" f"

Confidence Level: {confidence_pct}%

" f"
" f"

🌿 Agronomist Prescription

" f"
{ai_response}
" f"
" f"" f"" f"
" f"
" ) return report_html except Exception as error: return f"
❌ System Error: {str(error)}
" custom_css = """ @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&family=Playfair+Display:wght@600;700&display=swap'); @import url('https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&display=swap'); body, .gradio-container { background-color: #fef9ef !important; font-family: 'Inter', sans-serif !important; color: #1d1c16 !important; } .gradio-container { max-width: 1000px !important; margin: 0 auto !important; box-shadow: none !important; border: none !important; padding-top: 80px !important; } /* Hide default gradio stuff */ footer { display: none !important; } /* Top App Bar */ .top-app-bar { position: fixed; top: 0; left: 0; width: 100%; z-index: 50; background-color: #fef9ef; border-bottom: 1px solid #e7e2d8; padding: 16px 40px; display: flex; justify-content: center; align-items: center; box-sizing: border-box; } .top-app-bar .logo { display: flex; align-items: center; gap: 8px; font-family: 'Playfair Display', serif; font-size: 24px; font-weight: 600; color: #114616; } /* Hero Section */ .hero-section { text-align: center; margin-bottom: 32px; margin-top: 40px;} .hero-section h1 { font-family: 'Playfair Display', serif; font-size: 48px; color: #114616; font-weight: 700; line-height: 1.1; margin-bottom: 12px; margin-top: 0;} .hero-section p { font-size: 18px; color: #41493f; margin: 0;} /* Upload Area Styling Override */ #image-upload-box { background-color: #ffffff !important; border-radius: 16px !important; padding: 16px !important; border: 1px solid #e7e2d8 !important; box-shadow: 0 4px 12px rgba(0,0,0,0.05) !important; margin-bottom: 24px !important; } /* Buttons */ .action-btn-primary { background-color: #2b5e2b !important; color: #ffffff !important; border-radius: 9999px !important; padding: 16px 32px !important; font-weight: 600 !important; font-size: 16px !important; border: none !important; box-shadow: 0 10px 15px -3px rgba(17, 70, 22, 0.1) !important; transition: transform 0.2s !important; margin: 0 auto !important; display: block !important; width: fit-content !important; min-width: 200px !important;} .action-btn-primary:hover { filter: brightness(1.1); transform: translateY(-2px) !important; } /* Bento Boxes */ .bento-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; margin-top: 48px; } .bento-card { padding: 24px; background-color: #f2ede3; border-radius: 16px; border: 1px solid #c1c9bc; display: flex; flex-direction: column; gap: 8px; } .bento-card .icon { color: #7d562d; font-size: 24px; } .bento-card h3 { font-size: 16px; font-weight: 600; color: #1d1c16; margin: 0; } .bento-card p { font-size: 14px; color: #41493f; margin: 0; } /* Results Card */ .results-card { background-color: #ffffff; padding: 40px; border-radius: 16px; border: 1px solid #c1c9bc; box-shadow: 0 4px 12px rgba(0,0,0,0.05); margin-top: 24px; animation: fadeIn 0.5s ease-out;} @keyframes fadeIn { from { opacity: 0; transform: translateY(-10px); } to { opacity: 1; transform: translateY(0); } } @media (max-width: 768px) { .bento-grid { grid-template-columns: 1fr; } .top-app-bar { padding: 16px 20px; } .hero-section h1 { font-size: 36px; } } /* Print Styles for PDF Export */ @media print { .top-app-bar, .hero-section, #image-upload-box, .bento-grid, .action-btn-primary, .report-actions { display: none !important; } body, .gradio-container { background-color: white !important; padding: 0 !important; } .results-card { box-shadow: none !important; border: 1px solid #000 !important; padding: 20px !important; margin: 0 !important; } } """ with gr.Blocks(css=custom_css, theme=gr.themes.Base()) as demo: gr.HTML("""

Diagnose Your Plant

Get instant analysis and treatment advice for your crops and garden plants.

""") with gr.Column(elem_id="image-upload-box"): camera_input = gr.Image(label="Field Photo Input", sources=["upload", "webcam"], type="filepath") with gr.Row(): analyze_button = gr.Button("Analyze ➔", variant="primary", elem_classes=["action-btn-primary"]) # The results will magically appear right here below the button! output_display = gr.HTML() gr.HTML("""
verified_user

98% Accuracy

Powered by advanced agricultural computer vision.

local_library

Local Remedies

Treatment plans curated for your specific soil and climate.

forum

Expert Support

Connect with local agronomists if a disease is detected.

""") # Connect the button directly to the output display analyze_button.click( fn=process_field_analysis, inputs=[camera_input], outputs=[output_display] ) if __name__ == "__main__": demo.launch()