import gradio as gr import torch import torch.nn.functional as F from transformers import ViTImageProcessor, ViTForImageClassification from PIL import Image import google.generativeai as genai import os import logging import asyncio from typing import Tuple, Optional import time # Configure logging logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) # Configure Gemini API GEMINI_API_KEY = os.getenv('GEMINI_API_KEY') if GEMINI_API_KEY: genai.configure(api_key=GEMINI_API_KEY) gemini_model = genai.GenerativeModel('gemini-2.0-flash-exp') else: logger.warning("GEMINI_API_KEY not found. Remedy suggestions will be disabled.") gemini_model = None # Global variables for model caching model = None processor = None # Improved crop and disease mapping CROP_DISEASE_MAPPING = { # Tomato diseases "tomato___bacterial_spot": ("Tomato", "Bacterial Spot"), "tomato___early_blight": ("Tomato", "Early Blight"), "tomato___late_blight": ("Tomato", "Late Blight"), "tomato___leaf_mold": ("Tomato", "Leaf Mold"), "tomato___septoria_leaf_spot": ("Tomato", "Septoria Leaf Spot"), "tomato___spider_mites_two_spotted_spider_mite": ("Tomato", "Two-Spotted Spider Mite"), "tomato___target_spot": ("Tomato", "Target Spot"), "tomato___tomato_yellow_leaf_curl_virus": ("Tomato", "Yellow Leaf Curl Virus"), "tomato___tomato_mosaic_virus": ("Tomato", "Mosaic Virus"), "tomato___healthy": ("Tomato", "Healthy"), # Potato diseases "potato___early_blight": ("Potato", "Early Blight"), "potato___late_blight": ("Potato", "Late Blight"), "potato___healthy": ("Potato", "Healthy"), # Apple diseases "apple___apple_scab": ("Apple", "Apple Scab"), "apple___black_rot": ("Apple", "Black Rot"), "apple___cedar_apple_rust": ("Apple", "Cedar Apple Rust"), "apple___healthy": ("Apple", "Healthy"), # Corn diseases "corn_(maize)___cercospora_leaf_spot": ("Corn/Maize", "Cercospora Leaf Spot"), "corn_(maize)___common_rust": ("Corn/Maize", "Common Rust"), "corn_(maize)___northern_leaf_blight": ("Corn/Maize", "Northern Leaf Blight"), "corn_(maize)___healthy": ("Corn/Maize", "Healthy"), # Grape diseases "grape___black_rot": ("Grape", "Black Rot"), "grape___esca_(black_measles)": ("Grape", "Esca (Black Measles)"), "grape___leaf_blight_(isariopsis_leaf_spot)": ("Grape", "Leaf Blight"), "grape___healthy": ("Grape", "Healthy"), # Bell Pepper diseases "pepper,_bell___bacterial_spot": ("Bell Pepper", "Bacterial Spot"), "pepper,_bell___healthy": ("Bell Pepper", "Healthy"), # Cherry diseases "cherry_(including_sour)___powdery_mildew": ("Cherry", "Powdery Mildew"), "cherry_(including_sour)___healthy": ("Cherry", "Healthy"), # Peach diseases "peach___bacterial_spot": ("Peach", "Bacterial Spot"), "peach___healthy": ("Peach", "Healthy"), # Strawberry diseases "strawberry___leaf_scorch": ("Strawberry", "Leaf Scorch"), "strawberry___healthy": ("Strawberry", "Healthy"), # Other crops "soybean___healthy": ("Soybean", "Healthy"), "squash___powdery_mildew": ("Squash", "Powdery Mildew"), "orange___haunglongbing_(citrus_greening)": ("Orange", "Huanglongbing (Citrus Greening)"), "raspberry___healthy": ("Raspberry", "Healthy"), } def load_model(): """Load the ViT model for crop disease classification""" global model, processor try: model_name = "wambugu71/crop_leaf_diseases_vit" logger.info(f"Loading model: {model_name}") processor = ViTImageProcessor.from_pretrained(model_name) model = ViTForImageClassification.from_pretrained(model_name) logger.info("Model loaded successfully!") return True except Exception as e: logger.error(f"Error loading model: {str(e)}") return False def parse_label(raw_label: str) -> Tuple[str, str]: """Parse the raw model output to extract crop and disease information""" label = raw_label.lower().strip() # Check if we have a direct mapping if label in CROP_DISEASE_MAPPING: return CROP_DISEASE_MAPPING[label] # Try to parse common patterns if "___" in label: parts = label.split("___") if len(parts) >= 2: crop_part = parts[0].replace("_", " ").title() disease_part = parts[1].replace("_", " ").title() # Clean up crop names crop_part = crop_part.replace("(", "").replace(")", "") if "Corn Maize" in crop_part: crop_part = "Corn/Maize" elif "Pepper Bell" in crop_part: crop_part = "Bell Pepper" elif "Cherry Including Sour" in crop_part: crop_part = "Cherry" return crop_part, disease_part return "Unknown Crop", "Unknown Disease" def get_detailed_disease_info(crop: str, disease: str) -> str: """Get detailed information about the specific crop disease""" if disease == "Healthy": return f"โœ… **Healthy {crop}** - Your plant appears to be in good condition! Continue with proper care practices." elif "blight" in disease.lower(): return f"๐Ÿ‚ **{disease}** detected in **{crop}** - This is a fungal disease that causes tissue death and browning." elif "spot" in disease.lower(): return f"โšซ **{disease}** found on **{crop}** - Characterized by dark lesions on plant tissues." elif "rust" in disease.lower(): return f"๐Ÿฆ  **{disease}** affecting **{crop}** - Shows as orange/reddish pustules on plant surfaces." elif "virus" in disease.lower(): return f"๐Ÿฆ  **{disease}** in **{crop}** - Viral infection causing various symptoms including mottling and distortion." else: return f"๐Ÿ” **{disease}** detected in **{crop}** - This condition requires attention and proper management." async def get_enhanced_remedy_suggestions(crop: str, disease: str, confidence: float) -> str: """Get AI-powered remedy suggestions using Gemini API with crop-specific context""" if not gemini_model: return get_offline_remedy_suggestions(crop, disease) try: prompt = f""" As an expert plant pathologist and agricultural consultant, provide comprehensive treatment recommendations for {disease} affecting {crop} plants. The diagnosis confidence is {confidence:.1%}. Please provide a detailed response with the following sections: 1. **Immediate Actions** (2-3 urgent steps to take right now) 2. **Treatment Options**: - Organic/biological treatments - Chemical fungicides/bactericides (if needed) - Cultural control methods 3. **Prevention Strategy** (4-5 preventive measures) 4. **Monitoring & Follow-up** (what to watch for) 5. **Expected Timeline** (recovery expectations) Make it specific to {crop} cultivation and {disease} characteristics. Include product names where appropriate and be practical for farmers. Format with clear headings and bullet points for easy reading. """ response = gemini_model.generate_content( prompt, generation_config=genai.types.GenerationConfig( temperature=0.7, max_output_tokens=1200, ) ) return f"๐Ÿค– **AI-Powered Treatment Plan for {crop} - {disease}:**\n\n{response.text}" except Exception as e: logger.error(f"Error getting AI remedy suggestions: {str(e)}") return get_offline_remedy_suggestions(crop, disease) def get_offline_remedy_suggestions(crop: str, disease: str) -> str: """Fallback offline remedy suggestions""" return f""" **๐Ÿ“‹ General Treatment Approach for {crop} - {disease}:** **๐Ÿšจ Immediate Actions:** โ€ข Remove affected plant parts immediately โ€ข Improve air circulation around plants โ€ข Apply appropriate fungicide or treatment โ€ข Isolate infected plants if possible **๐Ÿงช Treatment Options:** โ€ข For fungal diseases: Use copper-based fungicides or neem oil โ€ข For bacterial diseases: Apply copper compounds โ€ข For viral diseases: Remove infected plants, control insect vectors โ€ข Organic options: Baking soda spray, compost tea **๐Ÿ›ก๏ธ Prevention Strategy:** โ€ข Choose disease-resistant varieties โ€ข Practice crop rotation (3-4 year cycle) โ€ข Maintain proper plant spacing โ€ข Water at soil level, avoid wetting leaves โ€ข Regular monitoring and early detection **๐Ÿ“ž Recommendation:** Consult local agricultural extension services for region-specific advice and approved treatments. """ def classify_disease_enhanced(image: Image.Image) -> Tuple[str, str, float, str]: """Enhanced disease classification with better parsing""" if model is None or processor is None: return "Unknown Crop", "Error", 0.0, "Model not loaded properly." try: inputs = processor(image, return_tensors="pt") with torch.no_grad(): outputs = model(**inputs) probabilities = F.softmax(outputs.logits, dim=-1) confidence = torch.max(probabilities).item() predicted_class_id = outputs.logits.argmax().item() predicted_label = model.config.id2label[predicted_class_id] crop, disease = parse_label(predicted_label) disease_info = get_detailed_disease_info(crop, disease) logger.info(f"Raw prediction: {predicted_label}") logger.info(f"Parsed: Crop={crop}, Disease={disease}, Confidence={confidence:.2%}") return crop, disease, confidence, disease_info except Exception as e: logger.error(f"Error in classification: {str(e)}") return "Unknown Crop", "Error", 0.0, f"Classification failed: {str(e)}" async def process_image_enhanced(image: Image.Image) -> Tuple[str, str]: """Enhanced image processing with better crop and disease identification""" if image is None: return "โš ๏ธ No image provided", "" crop, disease, confidence, disease_info = classify_disease_enhanced(image) if disease == "Error": return f"โŒ **Classification Error**\n{disease_info}", "" confidence_emoji = "๐ŸŽฏ" if confidence > 0.8 else "๐Ÿ“Š" if confidence > 0.6 else "โš ๏ธ" main_result = f""" ## ๐Ÿ”ฌ **Crop Disease Detector Analysis Results** ### ๐ŸŒฑ **Identified Crop:** `{crop}` ### ๐Ÿฆ  **Disease Status:** `{disease}` ### ๐Ÿ“Š **Confidence Score:** {confidence_emoji} `{confidence:.2%}` --- ### ๐Ÿ“‹ **Disease Information:** {disease_info} ### ๐Ÿ” **Analysis Notes:** - Higher confidence scores (>80%) indicate more reliable identification - Multiple factors including image quality affect accuracy - Consider consulting agricultural experts for critical decisions --- """.strip() remedy_text = await get_enhanced_remedy_suggestions(crop, disease, confidence) return main_result, remedy_text # Custom CSS for agricultural theme custom_css = """ @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&family=Space+Grotesk:wght@300;400;500;600;700&display=swap'); body, html { height: 100% !important; margin: 0 !important; padding: 0 !important; overflow-x: hidden !important; } .gradio-container { background: linear-gradient(135deg, #1a2e1a 0%, #2d4a2d 15%, #1e3a1e 35%, #3d5a3d 55%, #2a4d2a 75%, #1f361f 100%); color: #ffffff; font-family: 'Space Grotesk', 'Inter', -apple-system, BlinkMacSystemFont, sans-serif; min-height: 100vh !important; max-height: 100vh !important; overflow-y: auto !important; overflow-x: hidden !important; } #main-container { margin: 0 !important; padding: 20px !important; margin-bottom: 0 !important; padding-bottom: 0 !important; } .gr-block { margin-bottom: 0 !important; } /* Logo styling */ .agri-logo { width: 60px; height: 60px; display: inline-block; margin-right: 15px; vertical-align: middle; border-radius: 8px; object-fit: contain; } .nav-header-with-logo { background: linear-gradient(135deg, #1a2e1a 0%, #2d4a2d 50%, #1e3a1e 100%); padding: 20px 0; text-align: center; border-bottom: 3px solid #7FB069; margin-bottom: 30px; display: flex; align-items: center; justify-content: center; flex-direction: column; } .logo-title-container { display: flex; align-items: center; justify-content: center; margin-bottom: 10px; } /* Navigation styling */ .nav-header { background: linear-gradient(135deg, #1a2e1a 0%, #2d4a2d 50%, #1e3a1e 100%); padding: 20px 0; text-align: center; border-bottom: 3px solid #7FB069; margin-bottom: 30px; } .nav-title { background: linear-gradient(45deg, #B7E4C7, #7FB069); -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text; font-size: 2.5rem; font-weight: 700; margin: 0; } .nav-subtitle { color: #B7E4C7; font-size: 1.1rem; margin: 10px 0 0 0; } /* Page content styling */ .page-container { max-width: 1200px; margin: 0 auto; padding: 20px; } .feature-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 20px; margin: 30px 0; } .feature-card { background: rgba(26, 46, 26, 0.85); border: 1px solid rgba(127, 176, 105, 0.3); border-radius: 15px; padding: 25px; text-align: center; transition: all 0.3s ease; } .feature-card:hover { transform: translateY(-5px); box-shadow: 0 10px 30px rgba(127, 176, 105, 0.2); } .feature-icon { font-size: 3rem; margin-bottom: 15px; display: block; } /* Pricing card alignment and spacing */ .pricing-container { display: flex; justify-content: center; align-items: stretch; gap: 20px; margin: 30px 0; flex-wrap: wrap; } .pricing-card { background: rgba(26, 46, 26, 0.9); border: 2px solid rgba(127, 176, 105, 0.4); border-radius: 20px; padding: 30px; text-align: center; position: relative; transition: all 0.3s ease; flex: 1; min-width: 280px; max-width: 350px; display: flex; flex-direction: column; justify-content: space-between; } .pricing-card:hover { transform: translateY(-3px); box-shadow: 0 8px 25px rgba(127, 176, 105, 0.3); } .price { font-size: 3rem; font-weight: bold; background: linear-gradient(45deg, #B7E4C7, #7FB069); -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text; } /* Enterprise section alignment */ .enterprise-container { display: flex; justify-content: center; align-items: stretch; gap: 30px; margin: 30px 0; flex-wrap: wrap; } .enterprise-container .pricing-card { max-width: 400px; } /* Upload area styling */ .upload-area { border: 3px dashed #7FB069; border-radius: 25px; background: linear-gradient(135deg, rgba(26, 46, 26, 0.6) 0%, rgba(45, 74, 45, 0.4) 100%); transition: all 0.5s ease; } .upload-area:hover { border-color: #A7C957; background: linear-gradient(135deg, rgba(26, 46, 26, 0.8) 0%, rgba(45, 74, 45, 0.6) 100%); box-shadow: 0 0 40px rgba(167, 201, 87, 0.3); } .disease-result { background: linear-gradient(135deg, rgba(127, 176, 105, 0.12) 0%, rgba(183, 228, 199, 0.08) 100%); border-radius: 25px; padding: 2.5rem; margin: 2rem 0; border: 1px solid rgba(127, 176, 105, 0.2); color: #F8F9F0; backdrop-filter: blur(15px); position: relative; } .disease-result::before { content: ''; position: absolute; top: 0; left: 0; width: 5px; height: 100%; background: linear-gradient(180deg, #7FB069 0%, #A7C957 100%); border-radius: 0 5px 5px 0; } .remedy-result { background: linear-gradient(135deg, rgba(167, 201, 87, 0.12) 0%, rgba(149, 213, 178, 0.08) 100%); border-radius: 25px; padding: 2.5rem; margin: 2rem 0; border: 1px solid rgba(167, 201, 87, 0.2); color: #F8F9F0; backdrop-filter: blur(15px); position: relative; } .remedy-result::before { content: ''; position: absolute; top: 0; left: 0; width: 5px; height: 100%; background: linear-gradient(180deg, #A7C957 0%, #95D5B2 100%); border-radius: 0 5px 5px 0; } /* Popup styling */ .popup-overlay { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0, 0, 0, 0.8); display: flex; justify-content: center; align-items: center; z-index: 1000; } .popup-content { background: rgba(26, 46, 26, 0.95); border: 2px solid #7FB069; border-radius: 20px; padding: 40px; text-align: center; max-width: 400px; position: relative; } .popup-close { position: absolute; top: 10px; right: 15px; background: none; border: none; color: #fff; font-size: 24px; cursor: pointer; } /* Button styling */ .upgrade-btn, .contact-btn, .analyze-btn { background: linear-gradient(45deg, #7FB069, #A7C957); color: white; border: none; border-radius: 25px; padding: 12px 25px; font-weight: 600; cursor: pointer; transition: all 0.3s ease; margin: 10px 5px; width: 100%; } .analyze-btn { padding: 20px 45px; font-size: 18px; text-transform: uppercase; letter-spacing: 1.5px; font-family: 'Space Grotesk', sans-serif; } .upgrade-btn:hover, .contact-btn:hover, .analyze-btn:hover { transform: translateY(-2px); box-shadow: 0 8px 25px rgba(127, 176, 105, 0.4); } /* Header styling */ .header-text { text-align: center; color: #F8F9F0; background: rgba(26, 46, 26, 0.4); backdrop-filter: blur(25px); border: 1px solid rgba(183, 228, 199, 0.15); border-radius: 30px; padding: 2.5rem; margin: 2rem auto; max-width: 900px; box-shadow: 0 20px 60px rgba(106, 153, 78, 0.2); } .header-text h1 { background: linear-gradient(135deg, #B7E4C7 0%, #7FB069 30%, #6A994E 60%, #95D5B2 100%); -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text; font-size: 3.8rem; font-weight: 800; margin-bottom: 1rem; font-family: 'Space Grotesk', sans-serif; } /* Accessibility improvements */ .skip-link { position: absolute; top: -40px; left: 6px; background: #7FB069; color: #000; padding: 8px; text-decoration: none; border-radius: 4px; z-index: 1000; transition: top 0.3s; } .skip-link:focus { top: 6px; } a:focus, button:focus, input:focus, textarea:focus, select:focus { outline: 2px solid #7FB069; outline-offset: 2px; } @media (prefers-reduced-motion: reduce) { * { animation-duration: 0.01ms !important; animation-iteration-count: 1 !important; transition-duration: 0.01ms !important; } } /* Mobile responsive */ @media (max-width: 768px) { .nav-title { font-size: 2rem; } .agri-logo { width: 45px; height: 45px; margin-right: 10px; } .feature-grid { grid-template-columns: 1fr; } .pricing-container, .enterprise-container { flex-direction: column; align-items: center; } .pricing-card { max-width: 100%; margin: 10px 0; } .header-text h1 { font-size: 2.5rem; } } """ # Crop Disease Detector URL (you can replace with your actual logo) AGRI_LOGO_URL = "๐ŸŒฑ" # Using emoji as placeholder - replace with your actual logo URL def create_home_page(): """Create the home page for Crop Disease Detector""" with gr.Column(): gr.HTML(f""" """) gr.HTML("""

Transforming Agriculture with AI

Empowering farmers worldwide with instant plant disease detection using advanced AI. Upload a photo of your crop and get expert diagnosis in seconds.

""") with gr.Row(): with gr.Column(): gr.HTML("""
โšก

Instant Diagnosis

Photo โ†’ Disease identification in 30 seconds. No laboratory testing required.

""") with gr.Column(): gr.HTML("""
๐Ÿง 

AI-Powered Treatment

Get detailed, actionable treatment recommendations powered by Gemini AI.

""") with gr.Column(): gr.HTML("""
๐Ÿ“ฑ

Smartphone Accessible

Works on any smartphone with camera. No special hardware needed.

""") with gr.Row(): with gr.Column(): gr.HTML("""
๐ŸŒพ

Multi-Crop Support

Detects diseases in tomatoes, potatoes, corn, apples, grapes, and many more crops.

""") with gr.Column(): gr.HTML("""
๐Ÿ’š

Organic Solutions

Prioritizes eco-friendly and organic treatment options for sustainable farming.

""") with gr.Column(): gr.HTML("""
๐Ÿ†“

Free to Use

Basic disease detection is completely free. Premium features available for advanced users.

""") gr.HTML("""

Our Mission

To democratize agricultural expertise and prevent crop losses through accessible AI technology, ensuring food security and supporting farmer livelihoods worldwide.

""") gr.HTML("""

๐ŸŽฏ Impact: Addressing โ‚น1,40,000 crores annual crop losses in India โ€ข Supporting SDG 2 (Zero Hunger) โ€ข Empowering 146 million agricultural households

""") def create_crop_detection_demo(): """Create the main crop disease detection page""" with gr.Column(): gr.HTML('') # Header with logo gr.HTML("""

๐ŸŒฑ Crop Disease Detector

Advanced Crop Disease Detection & Treatment System

Enhanced AI โ€ข Precise Crop Identification โ€ข Expert Treatment Plans

""") if not model_loaded: gr.Warning("โš ๏ธ Model failed to load. Please refresh the page or contact support.") return with gr.Row(): # Input Column with gr.Column(scale=1, elem_classes="input-container"): gr.HTML("""

๐Ÿ“ค Upload Plant Image

""") image_input = gr.Image( type="pil", label="Drop your plant image here or click to upload", elem_classes="upload-area", height=300, elem_id="main-app" ) analyze_btn = gr.Button( "๐Ÿ”ฌ Analyze Plant Disease", variant="primary", size="lg", elem_classes="analyze-btn" ) # Output Section gr.HTML("""

๐Ÿ“Š AI Analysis Results

""") with gr.Row(): with gr.Column(scale=1): disease_output = gr.Markdown( label="Disease Classification", elem_classes="disease-result" ) with gr.Column(scale=1): remedy_output = gr.Markdown( label="Treatment Recommendations", elem_classes="remedy-result" ) # Event handlers async def handle_analysis(image): if image is None: return "โš ๏ธ Please upload an image first.", "" try: disease_result, remedy_result = await process_image_enhanced(image) return disease_result, remedy_result except Exception as e: error_msg = f"โŒ **Analysis Error**: {str(e)}" return error_msg, "" analyze_btn.click( fn=handle_analysis, inputs=[image_input], outputs=[disease_output, remedy_output] ) # Auto-analyze on image upload image_input.change( fn=handle_analysis, inputs=[image_input], outputs=[disease_output, remedy_output] ) # Footer information gr.HTML("""
๐Ÿง 
Enhanced Vision AI
Advanced Plant Analysis
๐ŸŒฑ
Crop-Specific Detection
Precise Identification
โšก
Instant Treatment Plans
Expert Recommendations

๐Ÿš€ Revolutionizing Agriculture with Enhanced AI โ€ข Built with Gradio โ€ข Powered by Transformers

Empowering farmers worldwide with precise crop disease detection

""") def create_pricing_page(): """Create the pricing page for Crop Disease Detector""" with gr.Column(): # State variable to control popup visibility popup_state = gr.State(False) popup = gr.HTML(visible=False, elem_id="popup") gr.HTML(""" """) # Individual plans section gr.HTML('
') with gr.Row(): with gr.Column(): gr.HTML("""

Always Free

โ‚น0

per month


""") free_btn = gr.Button("Get Started Free", elem_classes="upgrade-btn") with gr.Column(): gr.HTML("""

Farmer Pro

โ‚น199

per month


""") pro_btn = gr.Button("Upgrade to Pro", elem_classes="upgrade-btn") with gr.Column(): gr.HTML("""

Agricultural Expert

โ‚น499

per month


""") expert_btn = gr.Button("Upgrade to Expert", elem_classes="upgrade-btn") gr.HTML('
') # Close pricing-container gr.HTML("""

Enterprise & Cooperative Solutions

""") # Enterprise section gr.HTML('
') with gr.Row(): with gr.Column(): gr.HTML("""

Cooperative Basic

โ‚น15,000

per year (100+ farmers)


""") coop_btn = gr.Button("Contact for Cooperatives", elem_classes="contact-btn") with gr.Column(): gr.HTML("""

Enterprise

Custom

pricing


""") enterprise_btn = gr.Button("Contact Enterprise Sales", elem_classes="contact-btn") gr.HTML('
') # Close enterprise-container # Popup mechanism def toggle_popup(current_state): """Toggle popup visibility""" new_state = not current_state if new_state: popup_content = """ """ return new_state, gr.update(visible=True, value=popup_content) else: return new_state, gr.update(visible=False, value="") # Connect buttons with popup pro_btn.click( fn=toggle_popup, inputs=[popup_state], outputs=[popup_state, popup] ) expert_btn.click( fn=toggle_popup, inputs=[popup_state], outputs=[popup_state, popup] ) coop_btn.click( fn=toggle_popup, inputs=[popup_state], outputs=[popup_state, popup] ) enterprise_btn.click( fn=toggle_popup, inputs=[popup_state], outputs=[popup_state, popup] ) return free_btn # Initialize the model logger.info("Initializing Crop Disease Detector...") model_loaded = load_model() # Create the multi-page application with gr.Blocks(css=custom_css, theme=gr.themes.Soft(), title="Crop Disease Detector - Your Crop's AI Doctor") as app: gr.HTML('') with gr.Tabs(elem_id="main-content") as tabs: with gr.Tab("๐Ÿ  Home", elem_id="home-tab"): create_home_page() with gr.Tab("๐Ÿ”ฌ Crop Disease Detection", elem_id="detection-tab"): create_crop_detection_demo() with gr.Tab("๐Ÿ’ฐ Pricing", elem_id="pricing-tab"): free_button = create_pricing_page() # JavaScript functionality for tab switching free_button.click( lambda: None, outputs=[], js=""" function() { // Find the detection tab and click it const tabs = document.querySelectorAll('button[role="tab"]'); for (let tab of tabs) { if (tab.textContent.includes('Crop Disease Detection')) { tab.click(); break; } } } """ ) # Launch configuration if __name__ == "__main__": app.launch( share=True, server_name="0.0.0.0", server_port=7860, show_error=True, show_api=False, favicon_path=None, app_kwargs={"docs_url": None} )