Spaces:
Runtime error
Runtime error
| """ | |
| Poultry Disease Classification System | |
| Professional diagnostic tool using EfficientNetV2 | |
| """ | |
| import gradio as gr | |
| import numpy as np | |
| import tensorflow as tf | |
| from PIL import Image | |
| import keras | |
| # Load model | |
| MODEL_PATH = "poultry_disease_classification_efficientnet_model.keras" | |
| print("Loading model...") | |
| try: | |
| model = keras.models.load_model(MODEL_PATH) | |
| print("Model loaded successfully") | |
| except Exception as e: | |
| print(f"Error loading model: {e}") | |
| raise | |
| # Class definitions | |
| CLASS_NAMES = ['Coccidiosis', 'Healthy', 'Newcastle Disease', 'Salmonella'] | |
| # Disease information - clinical and concise | |
| DISEASE_INFO = { | |
| 'Coccidiosis': { | |
| 'description': 'Parasitic infection of the intestinal tract caused by coccidia protozoa.', | |
| 'symptoms': [ | |
| 'Bloody or watery droppings', | |
| 'Lethargy and weakness', | |
| 'Reduced appetite', | |
| 'Pale comb and wattles' | |
| ], | |
| 'treatment': [ | |
| 'Anticoccidial medication (Amprolium, Sulfonamides)', | |
| 'Electrolyte supplementation', | |
| 'Isolation of affected birds', | |
| 'Veterinary consultation required' | |
| ], | |
| 'prevention': [ | |
| 'Maintain dry, clean housing', | |
| 'Regular disinfection protocols', | |
| 'Adequate ventilation' | |
| ] | |
| }, | |
| 'Healthy': { | |
| 'description': 'No signs of disease detected. Bird appears to be in good health.', | |
| 'symptoms': [ | |
| 'Alert and active behavior', | |
| 'Normal appetite and droppings', | |
| 'Clear eyes', | |
| 'Well-groomed feathers' | |
| ], | |
| 'treatment': [ | |
| 'Continue standard care protocols', | |
| 'Monitor regularly', | |
| 'Maintain balanced nutrition' | |
| ], | |
| 'prevention': [ | |
| 'Balanced feed formulation', | |
| 'Clean environment', | |
| 'Vaccination schedule' | |
| ] | |
| }, | |
| 'Newcastle Disease': { | |
| 'description': 'Highly contagious viral infection affecting respiratory, nervous, and digestive systems.', | |
| 'symptoms': [ | |
| 'Respiratory distress', | |
| 'Neurological signs (tremors, paralysis)', | |
| 'Green watery diarrhea', | |
| 'Reduced egg production', | |
| 'Head and neck swelling' | |
| ], | |
| 'treatment': [ | |
| 'No specific antiviral treatment available', | |
| 'Supportive care and isolation', | |
| 'Vaccination of unaffected birds', | |
| 'Strict biosecurity enforcement' | |
| ], | |
| 'prevention': [ | |
| 'Vaccination program (primary prevention)', | |
| 'Biosecurity protocols', | |
| 'Quarantine procedures for new birds' | |
| ] | |
| }, | |
| 'Salmonella': { | |
| 'description': 'Bacterial infection with zoonotic potential. Affects gastrointestinal system.', | |
| 'symptoms': [ | |
| 'Greenish diarrhea', | |
| 'Decreased appetite', | |
| 'Dehydration', | |
| 'Lethargy', | |
| 'Poor growth in young birds' | |
| ], | |
| 'treatment': [ | |
| 'Antibiotic therapy (veterinary prescribed)', | |
| 'Fluid and electrolyte therapy', | |
| 'Probiotic supplementation', | |
| 'Enhanced sanitation measures' | |
| ], | |
| 'prevention': [ | |
| 'Biosecurity compliance', | |
| 'Water and feed quality control', | |
| 'Proper waste management' | |
| ] | |
| } | |
| } | |
| def preprocess_image(image): | |
| """Preprocess image for model input""" | |
| if isinstance(image, np.ndarray): | |
| image = Image.fromarray(image.astype('uint8')) | |
| image = image.resize((360, 360)) | |
| img_array = np.array(image) | |
| img_array = img_array.astype('float32') / 255.0 | |
| img_array = np.expand_dims(img_array, axis=0) | |
| return img_array | |
| def predict_disease(image): | |
| """Generate disease prediction and analysis""" | |
| if image is None: | |
| return None, "<div class='error-msg'>Please upload an image to begin analysis</div>" | |
| try: | |
| processed_image = preprocess_image(image) | |
| predictions = model.predict(processed_image, verbose=0)[0] | |
| predicted_idx = np.argmax(predictions) | |
| predicted_class = CLASS_NAMES[predicted_idx] | |
| confidence = predictions[predicted_idx] * 100 | |
| # Strict threshold - only proceed if confidence >= 99% | |
| CONFIDENCE_THRESHOLD = 98.7 | |
| if confidence < CONFIDENCE_THRESHOLD: | |
| # Simple rejection message - NO analysis details | |
| error_html = """ | |
| <div class='error-container'> | |
| <strong>⚠️ Invalid Image Detected</strong><br><br> | |
| The uploaded image does not appear to be a poultry bird or is not suitable for analysis.<br><br> | |
| <strong>Please upload:</strong> | |
| <ul style='margin: 0.5rem 0; padding-left: 1.5rem; line-height: 1.6;'> | |
| <li>A clear photograph of a chicken or poultry bird</li> | |
| <li>Well-lit image with good focus</li> | |
| <li>Bird clearly visible in the frame</li> | |
| <li>No other animals or unrelated objects</li> | |
| </ul> | |
| <p style='margin-top: 1rem; font-size: 0.85rem; color: #6c757d;'> | |
| This system is specifically trained to classify poultry diseases and requires | |
| high-confidence detections to ensure diagnostic accuracy. | |
| </p> | |
| </div> | |
| """ | |
| return None, error_html | |
| # Proceed with normal analysis for high-confidence predictions (≥99%) | |
| prediction_dict = {CLASS_NAMES[i]: float(predictions[i]) for i in range(len(CLASS_NAMES))} | |
| disease_info = DISEASE_INFO[predicted_class] | |
| # Confidence assessment (for valid predictions only) | |
| if confidence >= 99.5: | |
| conf_level = "Very High" | |
| conf_class = "conf-high" | |
| elif confidence >= 99.0: | |
| conf_level = "High" | |
| conf_class = "conf-high" | |
| else: | |
| # This shouldn't happen, but keeping as fallback | |
| conf_level = "Moderate" | |
| conf_class = "conf-moderate" | |
| # Build clean, professional result display | |
| result_html = f""" | |
| <div class='result-container'> | |
| <div class='result-header'> | |
| <div class='diagnosis'> | |
| <span class='label'>Diagnosis</span> | |
| <span class='value'>{predicted_class}</span> | |
| </div> | |
| <div class='confidence {conf_class}'> | |
| <span class='label'>Confidence</span> | |
| <span class='value'>{confidence:.2f}%</span> | |
| <span class='level'>{conf_level}</span> | |
| </div> | |
| </div> | |
| <div class='info-section'> | |
| <h3>Clinical Overview</h3> | |
| <p>{disease_info['description']}</p> | |
| </div> | |
| <div class='info-section'> | |
| <h3>Key Symptoms</h3> | |
| <ul> | |
| {''.join([f'<li>{symptom}</li>' for symptom in disease_info['symptoms']])} | |
| </ul> | |
| </div> | |
| <div class='info-section'> | |
| <h3>Treatment Protocol</h3> | |
| <ul> | |
| {''.join([f'<li>{treatment}</li>' for treatment in disease_info['treatment']])} | |
| </ul> | |
| </div> | |
| <div class='info-section'> | |
| <h3>Prevention</h3> | |
| <ul> | |
| {''.join([f'<li>{prevention}</li>' for prevention in disease_info['prevention']])} | |
| </ul> | |
| </div> | |
| <div class='disclaimer'> | |
| <strong>Professional Consultation Required</strong><br> | |
| This AI diagnostic tool provides preliminary screening only. | |
| Consult a licensed veterinarian for definitive diagnosis and treatment. | |
| </div> | |
| </div> | |
| """ | |
| return prediction_dict, result_html | |
| except Exception as e: | |
| error_html = f""" | |
| <div class='error-container'> | |
| <strong>Analysis Error</strong><br> | |
| {str(e)}<br><br> | |
| Please verify the image and try again. | |
| </div> | |
| """ | |
| return None, error_html | |
| # Professional CSS styling | |
| custom_css = """ | |
| * { | |
| font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif; | |
| } | |
| .gradio-container { | |
| max-width: 1200px !important; | |
| margin: 0 auto !important; | |
| } | |
| .header { | |
| background: linear-gradient(135deg, #1e3c72 0%, #2a5298 100%); | |
| color: white !important; | |
| padding: 2.5rem 2rem; | |
| border-radius: 8px; | |
| margin-bottom: 2rem; | |
| } | |
| .header h1 { | |
| font-size: 1.75rem; | |
| font-weight: 600; | |
| margin: 0 0 0.5rem 0; | |
| letter-spacing: -0.02em; | |
| color: white !important; | |
| } | |
| .header p { | |
| font-size: 0.95rem; | |
| margin: 0; | |
| opacity: 0.95; | |
| font-weight: 400; | |
| color: white !important; | |
| } | |
| .classes-grid { | |
| display: grid; | |
| grid-template-columns: repeat(4, 1fr); | |
| gap: 1rem; | |
| margin: 2rem 0; | |
| padding: 0 0.5rem; | |
| } | |
| .class-card { | |
| background: #f8f9fa; | |
| padding: 1rem; | |
| border-radius: 6px; | |
| text-align: center; | |
| border: 1px solid #e9ecef; | |
| } | |
| .class-card h4 { | |
| font-size: 0.9rem; | |
| font-weight: 600; | |
| color: #212529; | |
| margin: 0 0 0.25rem 0; | |
| } | |
| .class-card p { | |
| font-size: 0.8rem; | |
| color: #6c757d; | |
| margin: 0; | |
| } | |
| /* Dark mode support */ | |
| @media (prefers-color-scheme: dark) { | |
| .class-card { | |
| background: #2d3748; | |
| border: 1px solid #4a5568; | |
| } | |
| .class-card h4 { | |
| color: #e2e8f0 !important; | |
| } | |
| .class-card p { | |
| color: #cbd5e0 !important; | |
| } | |
| } | |
| /* Hide the label/title above upload section */ | |
| .upload-section label.block { | |
| display: none !important; | |
| } | |
| .upload-section .gr-block { | |
| border: none !important; | |
| padding: 0 !important; | |
| } | |
| .upload-section { | |
| background: transparent; | |
| padding: 0; | |
| border: none; | |
| } | |
| .section-title { | |
| font-size: 1rem; | |
| font-weight: 600; | |
| color: #212529; | |
| margin: 0 0 1rem 0; | |
| background: white; | |
| padding: 1rem; | |
| border-radius: 8px 8px 0 0; | |
| border: 1px solid #e9ecef; | |
| border-bottom: none; | |
| } | |
| /* Dark mode for section title */ | |
| @media (prefers-color-scheme: dark) { | |
| .section-title { | |
| background: #1a202c; | |
| color: #e2e8f0 !important; | |
| border-color: #4a5568; | |
| } | |
| } | |
| .image-tips { | |
| background: #f8f9fa; | |
| padding: 1rem; | |
| border-radius: 6px; | |
| margin-top: 1rem; | |
| border-left: 3px solid #2a5298; | |
| } | |
| .image-tips h4 { | |
| font-size: 0.85rem; | |
| font-weight: 600; | |
| color: #212529; | |
| margin: 0 0 0.5rem 0; | |
| } | |
| .image-tips ul { | |
| margin: 0; | |
| padding-left: 1.25rem; | |
| font-size: 0.85rem; | |
| color: #495057; | |
| line-height: 1.6; | |
| } | |
| /* Dark mode for image tips */ | |
| @media (prefers-color-scheme: dark) { | |
| .image-tips { | |
| background: #2d3748; | |
| border-left-color: #4299e1; | |
| } | |
| .image-tips h4 { | |
| color: #e2e8f0 !important; | |
| } | |
| .image-tips ul { | |
| color: #cbd5e0 !important; | |
| } | |
| } | |
| .result-container { | |
| background: #ffffff; | |
| border-radius: 8px; | |
| overflow: hidden; | |
| border: 1px solid #e9ecef; | |
| } | |
| /* Dark mode for results */ | |
| @media (prefers-color-scheme: dark) { | |
| .result-container { | |
| background: #1a202c; | |
| border-color: #4a5568; | |
| } | |
| } | |
| .result-header { | |
| display: grid; | |
| grid-template-columns: 1fr 1fr; | |
| gap: 1rem; | |
| padding: 1.5rem; | |
| background: #f8f9fa; | |
| border-bottom: 1px solid #e9ecef; | |
| } | |
| /* Dark mode for result header */ | |
| @media (prefers-color-scheme: dark) { | |
| .result-header { | |
| background: #2d3748; | |
| border-bottom-color: #4a5568; | |
| } | |
| } | |
| .diagnosis, .confidence { | |
| display: flex; | |
| flex-direction: column; | |
| } | |
| .label { | |
| font-size: 0.75rem; | |
| text-transform: uppercase; | |
| letter-spacing: 0.05em; | |
| color: #6c757d; | |
| font-weight: 600; | |
| margin-bottom: 0.25rem; | |
| } | |
| .value { | |
| font-size: 1.5rem; | |
| font-weight: 600; | |
| color: #212529; | |
| } | |
| .level { | |
| font-size: 0.85rem; | |
| color: #6c757d; | |
| margin-top: 0.25rem; | |
| } | |
| /* Dark mode for labels and values */ | |
| @media (prefers-color-scheme: dark) { | |
| .label { | |
| color: #a0aec0 !important; | |
| } | |
| .value { | |
| color: #e2e8f0 !important; | |
| } | |
| .level { | |
| color: #a0aec0 !important; | |
| } | |
| } | |
| .conf-high .value { color: #28a745 !important; } | |
| .conf-moderate .value { color: #ffc107 !important; } | |
| .conf-low .value { color: #dc3545 !important; } | |
| .info-section { | |
| padding: 1.5rem; | |
| border-bottom: 1px solid #e9ecef; | |
| } | |
| .info-section:last-of-type { | |
| border-bottom: none; | |
| } | |
| .info-section h3 { | |
| font-size: 0.95rem; | |
| font-weight: 600; | |
| color: #212529; | |
| margin: 0 0 0.75rem 0; | |
| } | |
| .info-section p { | |
| font-size: 0.9rem; | |
| color: #495057; | |
| line-height: 1.6; | |
| margin: 0; | |
| } | |
| .info-section ul { | |
| margin: 0; | |
| padding-left: 1.25rem; | |
| font-size: 0.9rem; | |
| color: #495057; | |
| line-height: 1.7; | |
| } | |
| .info-section li { | |
| margin-bottom: 0.5rem; | |
| } | |
| /* Dark mode for info sections */ | |
| @media (prefers-color-scheme: dark) { | |
| .info-section { | |
| border-bottom-color: #4a5568; | |
| } | |
| .info-section h3 { | |
| color: #e2e8f0 !important; | |
| } | |
| .info-section p { | |
| color: #cbd5e0 !important; | |
| } | |
| .info-section ul { | |
| color: #cbd5e0 !important; | |
| } | |
| } | |
| .disclaimer { | |
| background: #fff3cd; | |
| padding: 1rem; | |
| font-size: 0.85rem; | |
| color: #856404; | |
| line-height: 1.5; | |
| margin-top: 1rem; | |
| border-radius: 6px; | |
| } | |
| /* Dark mode for disclaimer */ | |
| @media (prefers-color-scheme: dark) { | |
| .disclaimer { | |
| background: #744210; | |
| color: #fef3c7 !important; | |
| } | |
| } | |
| .error-msg, .error-container { | |
| background: #f8d7da; | |
| color: #721c24; | |
| padding: 1rem; | |
| border-radius: 6px; | |
| font-size: 0.9rem; | |
| } | |
| /* Dark mode for errors */ | |
| @media (prefers-color-scheme: dark) { | |
| .error-msg, .error-container { | |
| background: #742a2a; | |
| color: #feb2b2 !important; | |
| } | |
| } | |
| .model-stats { | |
| display: grid; | |
| grid-template-columns: repeat(4, 1fr); | |
| gap: 1rem; | |
| margin: 2rem 0; | |
| padding: 0 0.5rem; | |
| } | |
| .stat-card { | |
| background: #f8f9fa; | |
| padding: 1.25rem; | |
| border-radius: 6px; | |
| text-align: center; | |
| border: 1px solid #e9ecef; | |
| } | |
| .stat-value { | |
| font-size: 1.75rem; | |
| font-weight: 600; | |
| color: #2a5298; | |
| display: block; | |
| } | |
| .stat-label { | |
| font-size: 0.85rem; | |
| color: #6c757d; | |
| margin-top: 0.25rem; | |
| } | |
| /* Dark mode for stats */ | |
| @media (prefers-color-scheme: dark) { | |
| .stat-card { | |
| background: #2d3748; | |
| border-color: #4a5568; | |
| } | |
| .stat-value { | |
| color: #4299e1 !important; | |
| } | |
| .stat-label { | |
| color: #cbd5e0 !important; | |
| } | |
| } | |
| .footer-note { | |
| background: #f8f9fa; | |
| padding: 1.5rem; | |
| border-radius: 8px; | |
| margin-top: 2rem; | |
| text-align: center; | |
| border: 1px solid #e9ecef; | |
| } | |
| .footer-note h4 { | |
| font-size: 0.9rem; | |
| font-weight: 600; | |
| color: #212529; | |
| margin: 0 0 0.5rem 0; | |
| } | |
| .footer-note p { | |
| font-size: 0.85rem; | |
| color: #6c757d; | |
| line-height: 1.6; | |
| margin: 0 0 1rem 0; | |
| } | |
| .tech-stack { | |
| font-size: 0.8rem; | |
| color: #868e96; | |
| margin-top: 1rem; | |
| } | |
| /* Dark mode for footer */ | |
| @media (prefers-color-scheme: dark) { | |
| .footer-note { | |
| background: #2d3748; | |
| border-color: #4a5568; | |
| } | |
| .footer-note h4 { | |
| color: #e2e8f0 !important; | |
| } | |
| .footer-note p { | |
| color: #cbd5e0 !important; | |
| } | |
| .tech-stack { | |
| color: #a0aec0 !important; | |
| } | |
| } | |
| button { | |
| font-weight: 500 !important; | |
| border-radius: 6px !important; | |
| } | |
| .primary { | |
| background: linear-gradient(135deg, #1e3c72 0%, #2a5298 100%) !important; | |
| border: none !important; | |
| } | |
| footer { | |
| display: none !important; | |
| } | |
| /* Mobile Responsiveness */ | |
| @media (max-width: 768px) { | |
| .header h1 { | |
| font-size: 1.25rem; | |
| } | |
| .header p { | |
| font-size: 0.85rem; | |
| } | |
| .classes-grid { | |
| grid-template-columns: repeat(2, 1fr); | |
| gap: 0.75rem; | |
| } | |
| .model-stats { | |
| grid-template-columns: repeat(2, 1fr); | |
| gap: 0.75rem; | |
| } | |
| .result-header { | |
| grid-template-columns: 1fr; | |
| gap: 1rem; | |
| } | |
| .value { | |
| font-size: 1.25rem; | |
| } | |
| .stat-value { | |
| font-size: 1.5rem; | |
| } | |
| .gradio-container { | |
| padding: 0.5rem; | |
| } | |
| .header { | |
| padding: 1.5rem 1rem; | |
| } | |
| } | |
| @media (max-width: 480px) { | |
| .classes-grid { | |
| grid-template-columns: 1fr; | |
| } | |
| .model-stats { | |
| grid-template-columns: 1fr; | |
| } | |
| .header h1 { | |
| font-size: 1.1rem; | |
| } | |
| .header p { | |
| font-size: 0.8rem; | |
| } | |
| } | |
| """ | |
| # Build interface | |
| with gr.Blocks(css=custom_css, theme=gr.themes.Soft(), title="Poultry Disease Classifier") as demo: | |
| # Header | |
| gr.HTML(""" | |
| <div class='header'> | |
| <h1>Poultry Disease Classification System</h1> | |
| <p>AI-powered diagnostic screening using EfficientNetV2 deep learning architecture</p> | |
| </div> | |
| """) | |
| # Disease classes | |
| gr.HTML(""" | |
| <div class='classes-grid'> | |
| <div class='class-card'> | |
| <h4>Coccidiosis</h4> | |
| <p>Parasitic</p> | |
| </div> | |
| <div class='class-card'> | |
| <h4>Healthy</h4> | |
| <p>No disease</p> | |
| </div> | |
| <div class='class-card'> | |
| <h4>Newcastle</h4> | |
| <p>Viral</p> | |
| </div> | |
| <div class='class-card'> | |
| <h4>Salmonella</h4> | |
| <p>Bacterial</p> | |
| </div> | |
| </div> | |
| """) | |
| # Main interface | |
| with gr.Row(): | |
| with gr.Column(scale=1): | |
| input_image = gr.Image( | |
| type="pil", | |
| label="Upload Image", | |
| height=400 | |
| ) | |
| with gr.Row(): | |
| clear_btn = gr.ClearButton( | |
| components=[input_image], | |
| value="Clear", | |
| size="lg" | |
| ) | |
| predict_btn = gr.Button( | |
| "Analyze", | |
| variant="primary", | |
| size="lg", | |
| elem_classes="primary" | |
| ) | |
| gr.HTML(""" | |
| <div class='image-tips'> | |
| <h4>Image Guidelines</h4> | |
| <ul> | |
| <li>Use clear, well-lit images</li> | |
| <li>Ensure bird is clearly visible</li> | |
| <li>Avoid blurry or dark photos</li> | |
| <li>Close-up shots preferred</li> | |
| </ul> | |
| </div> | |
| """) | |
| with gr.Column(scale=1): | |
| output_label = gr.Label( | |
| label="Analysis Results - Classification Confidence", | |
| num_top_classes=4 | |
| ) | |
| output_text = gr.HTML() | |
| # Model information | |
| gr.HTML(""" | |
| <div class='model-stats'> | |
| <div class='stat-card'> | |
| <span class='stat-value'>97%</span> | |
| <span class='stat-label'>Accuracy</span> | |
| </div> | |
| <div class='stat-card'> | |
| <span class='stat-value'>5.9M</span> | |
| <span class='stat-label'>Parameters</span> | |
| </div> | |
| <div class='stat-card'> | |
| <span class='stat-value'>360px</span> | |
| <span class='stat-label'>Input Size</span> | |
| </div> | |
| <div class='stat-card'> | |
| <span class='stat-value'>4</span> | |
| <span class='stat-label'>Classes</span> | |
| </div> | |
| </div> | |
| <div class='footer-note'> | |
| <h4>Clinical Notice</h4> | |
| <p>This diagnostic tool is intended for preliminary screening and educational purposes only. | |
| Results should not replace professional veterinary examination and diagnosis. | |
| Always consult a licensed veterinarian for accurate diagnosis and treatment recommendations.</p> | |
| <div class='tech-stack'> | |
| TensorFlow • Keras • EfficientNetV2-B0 • Gradio | Updated February 2026 | |
| </div> | |
| </div> | |
| """) | |
| # Connect prediction | |
| predict_btn.click( | |
| fn=predict_disease, | |
| inputs=input_image, | |
| outputs=[output_label, output_text] | |
| ) | |
| if __name__ == "__main__": | |
| demo.launch( | |
| server_name="0.0.0.0", | |
| server_port=7860, | |
| share=True, | |
| show_error=True | |
| ) |