mathaisjustin commited on
Commit
fbbdeab
Β·
1 Parent(s): 19e5ec3

Deploy Fish Disease Detection AI

Browse files
README.md CHANGED
@@ -1,14 +1,242 @@
1
  ---
2
- title: Fish Disease Detection Ai
3
- emoji: πŸ’»
4
- colorFrom: green
5
- colorTo: blue
6
  sdk: gradio
7
- sdk_version: 5.49.1
8
  app_file: app.py
9
  pinned: false
10
  license: mit
11
- short_description: AI-powered fish disease detection using VGG16 CNN with Grad-
 
 
 
 
 
 
 
12
  ---
13
 
14
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  ---
2
+ title: Fish Disease Detection AI
3
+ emoji: 🐟
4
+ colorFrom: blue
5
+ colorTo: green
6
  sdk: gradio
7
+ sdk_version: 5.7.1
8
  app_file: app.py
9
  pinned: false
10
  license: mit
11
+ tags:
12
+ - computer-vision
13
+ - deep-learning
14
+ - vgg16
15
+ - fish-disease
16
+ - grad-cam
17
+ - explainable-ai
18
+ - medical-imaging
19
  ---
20
 
21
+ # 🐟 Fish Disease Detection AI
22
+
23
+ [![Python](https://img.shields.io/badge/Python-3.8+-blue.svg)](https://www.python.org/downloads/)
24
+ [![PyTorch](https://img.shields.io/badge/PyTorch-2.5.1-red.svg)](https://pytorch.org/)
25
+ [![Gradio](https://img.shields.io/badge/Gradio-5.7.1-orange.svg)](https://gradio.app/)
26
+ [![License](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE)
27
+
28
+ **AI-powered fish disease detection system combining VGG16 CNN, Grad-CAM explainability, and Gemini AI for comprehensive diagnosis and treatment recommendations.**
29
+
30
+ ---
31
+
32
+ ## 🎯 Key Features
33
+
34
+ ### πŸŽ“ **High Accuracy**
35
+ - **98.65% test accuracy** on 8 fish disease classes
36
+ - Trained on **5,000+ annotated images**
37
+ - Robust to various image conditions
38
+
39
+ ### πŸ”¬ **Explainable AI**
40
+ - **Grad-CAM heatmap visualization** shows exactly where the model is looking
41
+ - Highlights disease-relevant areas (lesions, discoloration, abnormalities)
42
+ - Builds trust through transparency
43
+
44
+ ### πŸ€– **AI-Powered Treatment**
45
+ - **Google Gemini 2.0** generates disease-specific treatment protocols
46
+ - Immediate actions, medication recommendations, and preventive measures
47
+ - Expected recovery rates and timelines
48
+
49
+ ### ⚑ **Real-Time Performance**
50
+ - **~2-3 second inference** on GPU
51
+ - Supports batch processing
52
+ - Web-based interface accessible anywhere
53
+
54
+ ---
55
+
56
+ ## 🦠 Detected Diseases
57
+
58
+ | Disease | Description | Severity |
59
+ |---------|-------------|----------|
60
+ | **Aeromoniasis** | Bacterial infection causing hemorrhaging | High |
61
+ | **Bacterial Gill Disease** | Respiratory issues, gill damage | High |
62
+ | **Bacterial Red Disease** | External lesions and ulcers | Medium |
63
+ | **EUS** | Epizootic Ulcerative Syndrome | Critical |
64
+ | **Healthy Fish** | No disease detected | None |
65
+ | **Parasitic Diseases** | External/internal parasites | Medium |
66
+ | **Saprolegniasis Fungal** | Fungal infection (cotton-like growth) | Medium |
67
+ | **Viral White Tail** | Viral infection affecting tail | High |
68
+
69
+ ---
70
+
71
+ ## πŸš€ How to Use
72
+
73
+ ### 1️⃣ **Upload Image**
74
+ Upload a clear, well-lit photo of your fish (JPG/PNG, max 10MB)
75
+
76
+ ### 2️⃣ **Analyze**
77
+ Click "Analyze Fish" button for instant diagnosis
78
+
79
+ ### 3️⃣ **Review Results**
80
+ - **Disease prediction** with confidence score
81
+ - **Probability breakdown** for all 8 diseases
82
+ - **Grad-CAM heatmap** showing model focus areas
83
+ - **AI treatment recommendations** with detailed protocols
84
+
85
+ ---
86
+
87
+ ## πŸ“Š Model Architecture
88
+
89
+ Input Image (224Γ—224 RGB)
90
+ ↓
91
+ VGG16 Backbone (Pretrained on ImageNet)
92
+ ↓
93
+ Feature Extraction (4096-dim)
94
+ ↓
95
+ Custom Classification Head
96
+ ↓
97
+ 8-Class Softmax Output
98
+ ↓
99
+ Grad-CAM Activation Mapping
100
+
101
+
102
+ **Technical Specifications:**
103
+ - **Base Model:** VGG16 (transfer learning)
104
+ - **Input Size:** 224Γ—224 pixels
105
+ - **Normalization:** ImageNet mean/std
106
+ - **Framework:** PyTorch 2.5.1
107
+ - **Device:** CUDA/CPU compatible
108
+
109
+ ---
110
+
111
+ ## πŸ“ˆ Performance Metrics
112
+
113
+ | Metric | Score |
114
+ |--------|-------|
115
+ | **Test Accuracy** | 98.65% |
116
+ | **Precision (avg)** | 98.2% |
117
+ | **Recall (avg)** | 98.1% |
118
+ | **F1-Score (avg)** | 98.15% |
119
+ | **Training Samples** | 5,000+ |
120
+ | **Validation Samples** | 1,000+ |
121
+ | **Test Samples** | 500+ |
122
+
123
+ ---
124
+
125
+ ## 🎯 Confidence Thresholds
126
+
127
+ The system uses a **70% confidence threshold** for reliable diagnoses:
128
+
129
+ - **β‰₯ 80%** - 🟒 High confidence (Very reliable)
130
+ - **70-79%** - 🟑 Good confidence (Reliable)
131
+ - **< 70%** - πŸ”΄ Low confidence (Requires verification)
132
+
133
+ When confidence is below 70%, the system:
134
+ - Shows top 3 disease candidates
135
+ - Provides general guidelines
136
+ - Recommends professional consultation
137
+
138
+ ---
139
+
140
+ ## πŸ”¬ Grad-CAM Visualization
141
+
142
+ **Understanding the Heatmap:**
143
+
144
+ - πŸ”΄ **Red areas** - High importance (disease symptoms, lesions)
145
+ - 🟑 **Yellow areas** - Moderate importance
146
+ - 🟒 **Green/Blue areas** - Low importance
147
+
148
+ The heatmap proves the model focuses on actual pathological features, not spurious correlations.
149
+
150
+ ---
151
+
152
+ ## πŸ› οΈ Technical Details
153
+
154
+ ### Dependencies
155
+
156
+ torch==2.5.1
157
+ torchvision==0.20.1
158
+ gradio==5.7.1
159
+ google-generativeai==0.8.3
160
+ pillow==11.0.0
161
+ opencv-python-headless==4.10.0.84
162
+ numpy==1.26.4
163
+ python-dotenv==1.0.0
164
+
165
+
166
+ ### Environment Setup
167
+ This application requires a **Gemini API key** for treatment recommendations. Set it as an environment variable:
168
+
169
+ GEMINI_API_KEY=your_api_key_here
170
+
171
+ ---
172
+
173
+ ## ⚠️ Medical Disclaimer
174
+
175
+ **This is an AI diagnostic tool for preliminary screening only.**
176
+
177
+ ### βœ… Use For:
178
+ - Initial disease screening
179
+ - Educational purposes
180
+ - Research and development
181
+ - Aquaculture monitoring
182
+
183
+ ### ❌ Do NOT Use For:
184
+ - Definitive medical diagnosis
185
+ - Treatment without professional consultation
186
+ - Emergency veterinary decisions
187
+
188
+ **Always consult a qualified aquaculture veterinarian for:**
189
+ - Professional diagnosis confirmation
190
+ - Treatment plan approval
191
+ - Medication dosage recommendations
192
+ - Emergency health situations
193
+
194
+ ---
195
+
196
+ ## πŸŽ“ Research & Citation
197
+
198
+ This project is part of research on AI-assisted aquaculture diagnostics and explainable deep learning.
199
+
200
+ **BibTeX Citation:**
201
+
202
+ @software{fish_disease_detection_2025,
203
+ author = {Justin Mathais},
204
+ title = {Fish Disease Detection AI: VGG16 with Grad-CAM Explainability},
205
+ year = {2025},
206
+ url = {https://github.com/YOUR_USERNAME/fish-disease-detection}
207
+ }
208
+
209
+ ---
210
+
211
+ ## πŸ“§ Contact & Support
212
+
213
+ - **Author:** Your Name
214
+ - **Email:** [email protected]
215
+ - **GitHub:** [github.com/mathaisjustin](https://github.com/mathaisjustin)
216
+ - **Issues:** [Report bugs or suggest features](https://github.com/mathaisjustin/fish-disease-detection/issues)
217
+
218
+ ---
219
+
220
+ ## πŸ“œ License
221
+
222
+ This project is licensed under the **MIT License** - see [LICENSE](LICENSE) file for details.
223
+
224
+ ---
225
+
226
+ ## πŸ™ Acknowledgments
227
+
228
+ - **VGG16 Architecture:** Simonyan & Zisserman ([Paper](https://arxiv.org/abs/1409.1556))
229
+ - **Grad-CAM:** Selvaraju et al. ([Paper](https://arxiv.org/abs/1610.02391))
230
+ - **Google Gemini AI:** Treatment recommendation generation
231
+ - **PyTorch Community:** Deep learning framework
232
+ - **Gradio:** Web interface framework
233
+
234
+ ---
235
+
236
+ ## 🌟 Star History
237
+
238
+ If this project helped you, please consider giving it a ⭐ on [GitHub](https://github.com/YOUR_USERNAME/fish-disease-detection)!
239
+
240
+ ---
241
+
242
+ **Made with ❀️ for aquaculture health**
app.py ADDED
@@ -0,0 +1,270 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Gradio Web UI for Fish Disease Detection
3
+ Enhanced with Gemini-powered treatment and Grad-CAM explainability
4
+ """
5
+
6
+ # Load environment variables from .env file (for local development)
7
+ try:
8
+ from dotenv import load_dotenv
9
+ load_dotenv()
10
+ print("βœ… Environment variables loaded from .env")
11
+ except ImportError:
12
+ print("⚠️ python-dotenv not installed (OK for production deployment)")
13
+
14
+ import gradio as gr
15
+ import google.generativeai as genai
16
+ from PIL import Image
17
+ from backend import config as cfg
18
+ from backend.predictor import FishDiseasePredictor
19
+ from backend.treatment import TreatmentGenerator
20
+ from backend.gradcam import generate_gradcam_visualization
21
+
22
+ # ==================== GEMINI SETUP FOR TREATMENT ====================
23
+ treatment_gemini_model = None
24
+
25
+ if cfg.GEMINI_API_KEY:
26
+ try:
27
+ genai.configure(api_key=cfg.GEMINI_API_KEY)
28
+ treatment_gemini_model = genai.GenerativeModel(cfg.GEMINI_MODEL_NAME)
29
+ print("βœ… Gemini AI enabled for treatment recommendations")
30
+ except Exception as e:
31
+ print(f"❌ Gemini setup failed: {e}")
32
+ treatment_gemini_model = None
33
+ else:
34
+ print("⚠️ Gemini API key not found. Treatment recommendations will be limited.")
35
+
36
+ # Initialize treatment generator
37
+ treatment_generator = TreatmentGenerator(treatment_gemini_model)
38
+
39
+ # Initialize predictor
40
+ config_dict = {
41
+ 'CLASSES': cfg.CLASSES,
42
+ 'MODEL_PATH': cfg.MODEL_PATH,
43
+ 'DEVICE': cfg.DEVICE,
44
+ 'CONFIDENCE_THRESHOLD': cfg.CONFIDENCE_THRESHOLD,
45
+ 'MAX_FILE_SIZE_MB': cfg.MAX_FILE_SIZE_MB,
46
+ 'MIN_IMAGE_SIZE_PX': cfg.MIN_IMAGE_SIZE_PX,
47
+ 'VALID_EXTENSIONS': cfg.VALID_EXTENSIONS
48
+ }
49
+
50
+ predictor = FishDiseasePredictor(config_dict, gemini_model=None)
51
+
52
+ def predict_fish_disease(image):
53
+ """
54
+ Main prediction function with Grad-CAM visualization
55
+
56
+ Args:
57
+ image: PIL Image from Gradio
58
+
59
+ Returns:
60
+ tuple: (result_text, probability_chart, treatment_text, gradcam_image)
61
+ """
62
+ if image is None:
63
+ return "⚠️ Please upload an image", None, "", None
64
+
65
+ # Run prediction
66
+ result = predictor.predict_from_image(image)
67
+
68
+ if not result['success']:
69
+ return f"❌ {result['error']}", None, "", None
70
+
71
+ pred = result['prediction']
72
+ disease = pred['disease'].replace('_', ' ')
73
+ confidence = pred['confidence']
74
+ display_confidence = min(confidence, 100.0)
75
+
76
+ # Get sorted probabilities
77
+ sorted_probs = sorted(pred['probabilities'].items(), key=lambda x: x[1], reverse=True)
78
+
79
+ # GENERATE GRAD-CAM VISUALIZATION
80
+ gradcam_image = None
81
+ try:
82
+ predicted_class_idx = cfg.CLASSES.index(pred['disease'])
83
+ model = predictor.model_loader.model
84
+ transform = predictor.model_loader.transform
85
+
86
+ gradcam_image = generate_gradcam_visualization(
87
+ model, image, predicted_class_idx, transform
88
+ )
89
+ except Exception as e:
90
+ print(f"⚠️ Grad-CAM generation failed: {e}")
91
+ gradcam_image = image # Fallback to original
92
+
93
+ # ENHANCED: Better handling for low confidence cases
94
+ if pred['below_threshold']:
95
+ result_text = f"""
96
+ ## 🐟 Prediction Results
97
+
98
+ **Status:** ❓ **Uncertain - Low Confidence Detection**
99
+
100
+ ⚠️ **Below confidence threshold ({cfg.CONFIDENCE_THRESHOLD}%)**
101
+
102
+ The model detected possible disease signs but cannot confidently identify the specific disease.
103
+
104
+ ### πŸ“Š Most Likely Candidates:
105
+ 1. **{sorted_probs[0][0].replace('_', ' ')}**: {sorted_probs[0][1]:.1f}%
106
+ 2. **{sorted_probs[1][0].replace('_', ' ')}**: {sorted_probs[1][1]:.1f}%
107
+ 3. **{sorted_probs[2][0].replace('_', ' ')}**: {sorted_probs[2][1]:.1f}%
108
+
109
+ ### πŸ’‘ Recommended Actions:
110
+ - Upload a **clearer, well-lit** image if available
111
+ - Capture the fish from **different angles**
112
+ - **Consult a fish health professional** for accurate diagnosis
113
+ - **Monitor the fish** closely for symptom changes
114
+ """
115
+
116
+ ai_treatment = treatment_generator.get_recommendations(pred['disease'], display_confidence)
117
+
118
+ treatment_text = f"""### ⚠️ Low Confidence Warning ({display_confidence:.1f}%)
119
+
120
+ Due to uncertain diagnosis, these are **general guidelines** for the top candidate:
121
+
122
+ ---
123
+
124
+ {ai_treatment}
125
+
126
+ ---
127
+
128
+ ### πŸ”΄ CRITICAL REMINDER:
129
+ This diagnosis has **low confidence** and should **NOT** be used for treatment decisions without professional confirmation.
130
+
131
+ **Next Steps:**
132
+ 1. Get a professional veterinary assessment
133
+ 2. Document symptoms with photos/video
134
+ 3. Monitor water quality parameters
135
+ 4. Isolate affected fish if condition worsens"""
136
+
137
+ else:
138
+ status_emoji = "βœ…" if pred['disease'] == 'Healthy_Fish' else "⚠️"
139
+ status_text = "Healthy" if pred['disease'] == 'Healthy_Fish' else "Diseased"
140
+
141
+ result_text = f"""
142
+ ## 🐟 Prediction Results
143
+
144
+ **Disease:** {disease}
145
+ **Confidence:** {display_confidence:.2f}%
146
+ **Status:** {status_emoji} {status_text}
147
+
148
+ {"βœ… High confidence detection - Results are reliable" if confidence >= 80 else ""}
149
+ """
150
+
151
+ treatment_text = treatment_generator.get_recommendations(pred['disease'], display_confidence)
152
+
153
+ # Convert probabilities for Gradio
154
+ prob_data = {
155
+ disease_name: prob / 100.0
156
+ for disease_name, prob in pred['probabilities'].items()
157
+ }
158
+
159
+ return result_text, prob_data, treatment_text, gradcam_image
160
+
161
+ # ==================== GRADIO INTERFACE ====================
162
+ with gr.Blocks(title="Fish Disease Detection", theme=gr.themes.Soft()) as demo:
163
+
164
+ gr.Markdown("""
165
+ # 🐟 Fish Disease Detection System
166
+ ### AI-Powered Fish Health Diagnosis using VGG16 CNN with Explainable AI
167
+
168
+ Upload a fish image to detect diseases and see **how the AI made its decision** with heatmap visualization.
169
+ """)
170
+
171
+ with gr.Row():
172
+ with gr.Column(scale=1):
173
+ image_input = gr.Image(type="pil", label="Upload Fish Image", height=400)
174
+ predict_btn = gr.Button("πŸ”¬ Analyze Fish", variant="primary", size="lg")
175
+
176
+ gr.Markdown("""
177
+ ### πŸ“‹ Instructions:
178
+ 1. Upload a **clear fish image**
179
+ 2. Click **'Analyze Fish'**
180
+ 3. View **results, AI explanation, and treatment**
181
+
182
+ **Supported:** JPG, PNG (Max 10MB)
183
+
184
+ ### πŸ’‘ Tips for Best Results:
185
+ - Use **well-lit** images
186
+ - Show the **whole fish** clearly
187
+ - Avoid **blurry** or **obstructed** shots
188
+ """)
189
+
190
+ with gr.Column(scale=1):
191
+ result_output = gr.Markdown(label="Results")
192
+ prob_output = gr.Label(label="Disease Probabilities", num_top_classes=8)
193
+
194
+ # Grad-CAM Visualization Row
195
+ with gr.Row():
196
+ gradcam_output = gr.Image(
197
+ label="πŸ” AI Decision Heatmap - Shows which areas the model focused on for diagnosis (Red = High importance)",
198
+ type="pil",
199
+ height=400
200
+ )
201
+
202
+ with gr.Row():
203
+ treatment_output = gr.Textbox(
204
+ label="πŸ’Š Treatment Recommendations",
205
+ lines=15,
206
+ max_lines=25
207
+ )
208
+
209
+ # Example images
210
+ gr.Examples(
211
+ examples=[
212
+ ["data/merged_dataset-all/test/Healthy_Fish/Healthy_Fish_1__1.jpg"],
213
+ ["data/merged_dataset-all/test/Bacterial_gill_disease/Bacterial_gill_disease_1__1.jpg"],
214
+ ],
215
+ inputs=image_input,
216
+ label="πŸ“Έ Example Images"
217
+ )
218
+
219
+ gr.Markdown("""
220
+ ---
221
+ ### πŸ“Š Model Information
222
+ - **Architecture:** VGG16 CNN with Transfer Learning
223
+ - **Test Accuracy:** 98.65%
224
+ - **Training Dataset:** 5,000+ annotated images
225
+ - **Disease Classes:** 8 diseases + Healthy
226
+ - **Confidence Threshold:** 70% (for reliable diagnosis)
227
+ - **Inference Time:** ~2-3 seconds
228
+ - **AI Treatment:** Powered by Google Gemini 2.0
229
+ - **Explainability:** Grad-CAM visualization
230
+
231
+ ### 🎯 Confidence Levels:
232
+ - **β‰₯ 80%**: High confidence - Very reliable
233
+ - **70-79%**: Good confidence - Reliable
234
+ - **< 70%**: Low confidence - Requires verification
235
+
236
+ ### πŸ”¬ Understanding the Heatmap:
237
+ - **πŸ”΄ Red areas**: Model focused here (disease symptoms, lesions, abnormalities)
238
+ - **🟑 Yellow areas**: Moderate importance
239
+ - **🟒 Green/Blue areas**: Less important for diagnosis
240
+
241
+ The heatmap shows the AI is making decisions based on actual disease features, not random patterns.
242
+
243
+ ---
244
+
245
+ ### ⚠️ Medical Disclaimer
246
+ This is an **AI diagnostic tool** for preliminary screening only.
247
+
248
+ **Always consult a qualified aquaculture veterinarian for:**
249
+ - Professional diagnosis confirmation
250
+ - Treatment plan approval
251
+ - Medication dosage recommendations
252
+ - Emergency health situations
253
+
254
+ This tool is intended to **assist**, not **replace** professional veterinary care.
255
+ """)
256
+
257
+ # Connect button with 4 outputs
258
+ predict_btn.click(
259
+ fn=predict_fish_disease,
260
+ inputs=image_input,
261
+ outputs=[result_output, prob_output, treatment_output, gradcam_output]
262
+ )
263
+
264
+ # Launch
265
+ if __name__ == "__main__":
266
+ demo.launch(
267
+ server_name="0.0.0.0",
268
+ server_port=7860,
269
+ share=True # Generates temporary public URL (72 hours)
270
+ )
backend/__init__.py ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Backend package for Fish Disease Detection
3
+ Handles model loading, validation, prediction, and treatment recommendations
4
+ """
5
+
6
+ from .config import (
7
+ CLASSES,
8
+ GEMINI_API_KEY,
9
+ GEMINI_MODEL_NAME,
10
+ MODEL_PATH,
11
+ CONFIDENCE_THRESHOLD,
12
+ DEVICE,
13
+ MAX_FILE_SIZE_MB,
14
+ MIN_IMAGE_SIZE_PX,
15
+ VALID_EXTENSIONS
16
+ )
17
+
18
+ from .predictor import FishDiseasePredictor
19
+
20
+ __version__ = "1.0.0"
21
+ __all__ = [
22
+ 'FishDiseasePredictor',
23
+ 'CLASSES',
24
+ 'GEMINI_API_KEY',
25
+ 'GEMINI_MODEL_NAME',
26
+ 'MODEL_PATH',
27
+ 'CONFIDENCE_THRESHOLD'
28
+ ]
backend/__pycache__/__init__.cpython-313.pyc ADDED
Binary file (674 Bytes). View file
 
backend/__pycache__/config.cpython-313.pyc ADDED
Binary file (2.34 kB). View file
 
backend/__pycache__/gradcam.cpython-313.pyc ADDED
Binary file (4.97 kB). View file
 
backend/__pycache__/model_loader.cpython-313.pyc ADDED
Binary file (4.6 kB). View file
 
backend/__pycache__/predictor.cpython-313.pyc ADDED
Binary file (6.62 kB). View file
 
backend/__pycache__/treatment.cpython-313.pyc ADDED
Binary file (7.57 kB). View file
 
backend/__pycache__/validator.cpython-313.pyc ADDED
Binary file (6.44 kB). View file
 
backend/config.py ADDED
@@ -0,0 +1,60 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Configuration file for Fish Disease Detection System
3
+ Secure deployment with environment variables
4
+ """
5
+
6
+ import os
7
+ import torch
8
+
9
+ # ==================== DISEASE CLASSES ====================
10
+ CLASSES = [
11
+ 'Aeromoniasis',
12
+ 'Bacterial_gill_disease',
13
+ 'Bacterial_red_disease',
14
+ 'EUS',
15
+ 'Healthy_Fish',
16
+ 'Parasitic_diseases',
17
+ 'Saprolegniasis_fungal',
18
+ 'Viral_white_tail'
19
+ ]
20
+
21
+ # ==================== GEMINI API SETTINGS ====================
22
+ # IMPORTANT: Set GEMINI_API_KEY in environment variable (.env file or Hugging Face Secrets)
23
+ GEMINI_API_KEY = os.environ.get('GEMINI_API_KEY')
24
+ GEMINI_MODEL_NAME = os.environ.get('GEMINI_MODEL_NAME', 'gemini-2.0-flash-exp')
25
+
26
+ # Validate API key
27
+ if not GEMINI_API_KEY:
28
+ print("⚠️ WARNING: GEMINI_API_KEY not found in environment variables!")
29
+ print(" Set it in .env file (local) or Hugging Face Space settings (production)")
30
+ print(" Gemini AI features will be disabled.")
31
+
32
+ # ==================== MODEL SETTINGS ====================
33
+ MODEL_PATH = 'models/vgg_resnet/results/vgg_resnet/vgg16_best.pth'
34
+ CONFIDENCE_THRESHOLD = 70.0 # Minimum confidence to report disease
35
+ DEVICE = 'cuda' if torch.cuda.is_available() else 'cpu'
36
+
37
+ # ==================== VALIDATION SETTINGS ====================
38
+ MAX_FILE_SIZE_MB = 10 # Maximum upload size
39
+ MIN_IMAGE_SIZE_PX = 100 # Minimum image dimensions
40
+ VALID_EXTENSIONS = ['.jpg', '.jpeg', '.png', '.JPG', '.JPEG', '.PNG']
41
+
42
+ # ==================== IMAGE PREPROCESSING ====================
43
+ IMAGE_SIZE = 224 # VGG16 input size
44
+ NORMALIZE_MEAN = [0.485, 0.456, 0.406] # ImageNet mean
45
+ NORMALIZE_STD = [0.229, 0.224, 0.225] # ImageNet std
46
+
47
+ # ==================== DEBUG SETTINGS ====================
48
+ DEBUG = os.environ.get('DEBUG', 'False').lower() == 'true'
49
+
50
+ if DEBUG:
51
+ print("="*60)
52
+ print("🐟 Fish Disease Detection - Configuration")
53
+ print("="*60)
54
+ print(f" Model Path: {MODEL_PATH}")
55
+ print(f" Device: {DEVICE}")
56
+ print(f" Classes: {len(CLASSES)}")
57
+ print(f" Confidence Threshold: {CONFIDENCE_THRESHOLD}%")
58
+ print(f" Gemini API Key: {'βœ… Set' if GEMINI_API_KEY else '❌ Not Set'}")
59
+ print(f" Gemini Model: {GEMINI_MODEL_NAME if GEMINI_API_KEY else 'N/A'}")
60
+ print("="*60)
backend/gradcam.py ADDED
@@ -0,0 +1,143 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Grad-CAM implementation for explainable AI
3
+ Shows which parts of the image influenced the model's decision
4
+ """
5
+
6
+ import torch
7
+ import torch.nn.functional as F
8
+ import numpy as np
9
+ import cv2
10
+ from PIL import Image
11
+
12
+ class GradCAM:
13
+ """
14
+ Grad-CAM for VGG16 to visualize model decisions
15
+ """
16
+
17
+ def __init__(self, model, target_layer):
18
+ """
19
+ Initialize Grad-CAM
20
+
21
+ Args:
22
+ model: Trained VGG16 model
23
+ target_layer: Layer to visualize (e.g., model.features[-1])
24
+ """
25
+ self.model = model
26
+ self.target_layer = target_layer
27
+ self.gradients = None
28
+ self.activations = None
29
+
30
+ # Register hooks
31
+ self.target_layer.register_forward_hook(self.save_activation)
32
+ self.target_layer.register_backward_hook(self.save_gradient)
33
+
34
+ def save_activation(self, module, input, output):
35
+ """Save forward activation"""
36
+ self.activations = output.detach()
37
+
38
+ def save_gradient(self, module, grad_input, grad_output):
39
+ """Save backward gradient"""
40
+ self.gradients = grad_output[0].detach()
41
+
42
+ def generate_cam(self, input_tensor, class_idx):
43
+ """
44
+ Generate Class Activation Map
45
+
46
+ Args:
47
+ input_tensor: Preprocessed input image tensor
48
+ class_idx: Target class index
49
+
50
+ Returns:
51
+ numpy array: Heatmap (0-255)
52
+ """
53
+ # Forward pass
54
+ output = self.model(input_tensor)
55
+
56
+ # Zero gradients
57
+ self.model.zero_grad()
58
+
59
+ # Backward pass for target class
60
+ class_score = output[0, class_idx]
61
+ class_score.backward()
62
+
63
+ # Get gradients and activations
64
+ gradients = self.gradients[0] # [C, H, W]
65
+ activations = self.activations[0] # [C, H, W]
66
+
67
+ # Calculate weights (global average pooling of gradients)
68
+ weights = gradients.mean(dim=(1, 2), keepdim=True) # [C, 1, 1]
69
+
70
+ # Weighted combination of activation maps
71
+ cam = (weights * activations).sum(dim=0) # [H, W]
72
+
73
+ # Apply ReLU (only positive influence)
74
+ cam = F.relu(cam)
75
+
76
+ # Normalize to 0-1
77
+ cam = cam - cam.min()
78
+ cam = cam / cam.max()
79
+
80
+ # Convert to numpy and resize to 224x224
81
+ cam = cam.cpu().numpy()
82
+ cam = cv2.resize(cam, (224, 224))
83
+
84
+ # Convert to 0-255 range
85
+ cam = np.uint8(255 * cam)
86
+
87
+ return cam
88
+
89
+ def overlay_heatmap(self, image, heatmap, alpha=0.5):
90
+ """
91
+ Overlay heatmap on original image
92
+
93
+ Args:
94
+ image: Original PIL Image
95
+ heatmap: Heatmap numpy array (0-255)
96
+ alpha: Transparency (0-1)
97
+
98
+ Returns:
99
+ PIL Image with heatmap overlay
100
+ """
101
+ # Resize image to 224x224
102
+ image = image.resize((224, 224))
103
+ image_np = np.array(image)
104
+
105
+ # Apply colormap to heatmap (red = high activation)
106
+ heatmap_colored = cv2.applyColorMap(heatmap, cv2.COLORMAP_JET)
107
+ heatmap_colored = cv2.cvtColor(heatmap_colored, cv2.COLOR_BGR2RGB)
108
+
109
+ # Overlay
110
+ overlayed = cv2.addWeighted(image_np, 1-alpha, heatmap_colored, alpha, 0)
111
+
112
+ return Image.fromarray(overlayed)
113
+
114
+
115
+ def generate_gradcam_visualization(model, image, predicted_class_idx, transform):
116
+ """
117
+ Generate Grad-CAM visualization for a prediction
118
+
119
+ Args:
120
+ model: Trained VGG16 model
121
+ image: PIL Image
122
+ predicted_class_idx: Index of predicted class
123
+ transform: Image transformation pipeline
124
+
125
+ Returns:
126
+ PIL Image: Image with heatmap overlay
127
+ """
128
+ # Set model to eval mode
129
+ model.eval()
130
+
131
+ # Preprocess image
132
+ input_tensor = transform(image).unsqueeze(0)
133
+
134
+ # Create Grad-CAM instance (target last convolutional layer of VGG16)
135
+ gradcam = GradCAM(model, model.features[-1])
136
+
137
+ # Generate heatmap
138
+ heatmap = gradcam.generate_cam(input_tensor, predicted_class_idx)
139
+
140
+ # Overlay on original image
141
+ visualization = gradcam.overlay_heatmap(image, heatmap, alpha=0.4)
142
+
143
+ return visualization
backend/model_loader.py ADDED
@@ -0,0 +1,95 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Model loader - Handles VGG16 loading and inference
3
+ """
4
+
5
+ import torch
6
+ import torch.nn as nn
7
+ from torchvision import models, transforms
8
+ from .config import IMAGE_SIZE, NORMALIZE_MEAN, NORMALIZE_STD
9
+
10
+ class VGG16ModelLoader:
11
+ """Loads and manages VGG16 model for fish disease detection"""
12
+
13
+ def __init__(self, model_path, num_classes, device='cpu'):
14
+ """
15
+ Initialize model loader
16
+
17
+ Args:
18
+ model_path: Path to trained model weights (.pth file)
19
+ num_classes: Number of disease classes
20
+ device: 'cpu' or 'cuda'
21
+ """
22
+ self.model_path = model_path
23
+ self.num_classes = num_classes
24
+ self.device = torch.device(device)
25
+ self.model = None
26
+ self.transform = None
27
+
28
+ self._load_model()
29
+ self._setup_transform()
30
+
31
+ def _load_model(self):
32
+ """Load VGG16 with custom classifier"""
33
+ try:
34
+ # Create VGG16 architecture
35
+ self.model = models.vgg16(weights="IMAGENET1K_V1")
36
+
37
+ # Replace final layer for our classes
38
+ self.model.classifier[6] = nn.Linear(4096, self.num_classes)
39
+
40
+ # Load trained weights
41
+ state_dict = torch.load(
42
+ self.model_path,
43
+ map_location=self.device,
44
+ weights_only=True # Security: only load weights
45
+ )
46
+ self.model.load_state_dict(state_dict)
47
+
48
+ # Move to device and set eval mode
49
+ self.model = self.model.to(self.device)
50
+ self.model.eval()
51
+
52
+ print(f"βœ… Model loaded: {self.model_path}")
53
+ print(f"βœ… Device: {self.device}")
54
+
55
+ except FileNotFoundError:
56
+ raise RuntimeError(f"Model file not found: {self.model_path}")
57
+ except Exception as e:
58
+ raise RuntimeError(f"Failed to load model: {e}")
59
+
60
+ def _setup_transform(self):
61
+ """Setup image preprocessing pipeline"""
62
+ self.transform = transforms.Compose([
63
+ transforms.Resize((IMAGE_SIZE, IMAGE_SIZE)),
64
+ transforms.ToTensor(),
65
+ transforms.Normalize(NORMALIZE_MEAN, NORMALIZE_STD),
66
+ ])
67
+
68
+ def predict(self, image):
69
+ """
70
+ Predict disease from PIL Image
71
+
72
+ Args:
73
+ image: PIL Image in RGB format
74
+
75
+ Returns:
76
+ tuple: (predicted_class_idx, confidence_score, all_probabilities)
77
+ """
78
+ try:
79
+ # Preprocess image
80
+ input_tensor = self.transform(image).unsqueeze(0).to(self.device)
81
+
82
+ # Run inference
83
+ with torch.no_grad():
84
+ outputs = self.model(input_tensor)
85
+ probabilities = torch.nn.functional.softmax(outputs, dim=1)
86
+ confidence, predicted_idx = torch.max(probabilities, 1)
87
+
88
+ return (
89
+ predicted_idx.item(),
90
+ confidence.item() * 100, # Convert to percentage
91
+ probabilities[0]
92
+ )
93
+
94
+ except Exception as e:
95
+ raise RuntimeError(f"Prediction failed: {e}")
backend/predictor.py ADDED
@@ -0,0 +1,194 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Predictor - Orchestrates the complete prediction pipeline
3
+ Combines validation, model inference, and treatment generation
4
+ """
5
+
6
+ from .validator import FishImageValidator
7
+ from .model_loader import VGG16ModelLoader
8
+ from .treatment import TreatmentGenerator
9
+ from .config import CLASSES, CONFIDENCE_THRESHOLD
10
+
11
+ class FishDiseasePredictor:
12
+ """Main prediction pipeline that coordinates all components"""
13
+
14
+ def __init__(self, config, gemini_model=None):
15
+ """
16
+ Initialize predictor with all components
17
+
18
+ Args:
19
+ config: Configuration dictionary with all settings
20
+ gemini_model: Google Gemini model instance (optional)
21
+ """
22
+ self.config = config
23
+ self.gemini_model = gemini_model
24
+ self.confidence_threshold = config.get('CONFIDENCE_THRESHOLD', CONFIDENCE_THRESHOLD)
25
+
26
+ # Initialize all components
27
+ self.validator = FishImageValidator(
28
+ max_size_mb=config.get('MAX_FILE_SIZE_MB', 10),
29
+ min_size_px=config.get('MIN_IMAGE_SIZE_PX', 100),
30
+ valid_extensions=config.get('VALID_EXTENSIONS')
31
+ )
32
+
33
+ self.model_loader = VGG16ModelLoader(
34
+ model_path=config['MODEL_PATH'],
35
+ num_classes=len(config['CLASSES']),
36
+ device=config.get('DEVICE', 'cpu')
37
+ )
38
+
39
+ self.treatment_generator = TreatmentGenerator(gemini_model)
40
+
41
+ def predict(self, image_path):
42
+ """
43
+ Complete prediction pipeline with all validations
44
+
45
+ Args:
46
+ image_path: Path to image file
47
+
48
+ Returns:
49
+ dict: Complete result with validation, prediction, and treatment
50
+ {
51
+ 'success': bool,
52
+ 'error': str or None,
53
+ 'validation': {
54
+ 'file': {'valid': bool, 'message': str},
55
+ 'gemini': {'valid': bool, 'message': str}
56
+ },
57
+ 'prediction': {
58
+ 'disease': str,
59
+ 'confidence': float,
60
+ 'probabilities': dict,
61
+ 'below_threshold': bool
62
+ },
63
+ 'treatment': str or None
64
+ }
65
+ """
66
+ result = {
67
+ 'success': False,
68
+ 'error': None,
69
+ 'validation': {},
70
+ 'prediction': {},
71
+ 'treatment': None
72
+ }
73
+
74
+ # STEP 1: File validation (format, size, corruption)
75
+ print("πŸ” Validating file...")
76
+ is_valid, msg, image = self.validator.validate_file(image_path)
77
+ result['validation']['file'] = {'valid': is_valid, 'message': msg}
78
+
79
+ if not is_valid:
80
+ result['error'] = msg
81
+ return result
82
+
83
+ # STEP 2: Gemini AI validation (fish detection, edge cases)
84
+ print("πŸ€– Validating with Gemini AI...")
85
+ is_valid, msg = self.validator.validate_with_gemini(image, self.gemini_model)
86
+ result['validation']['gemini'] = {'valid': is_valid, 'message': msg}
87
+ print(msg)
88
+
89
+ if not is_valid:
90
+ result['error'] = msg
91
+ return result
92
+
93
+ # STEP 3: VGG16 disease prediction
94
+ print("πŸ”¬ Analyzing fish health...")
95
+ try:
96
+ class_idx, confidence, probabilities = self.model_loader.predict(image)
97
+
98
+ predicted_class = self.config['CLASSES'][class_idx]
99
+
100
+ # Build probability dictionary
101
+ prob_dict = {
102
+ self.config['CLASSES'][i]: float(probabilities[i].item() * 100)
103
+ for i in range(len(self.config['CLASSES']))
104
+ }
105
+
106
+ result['prediction'] = {
107
+ 'disease': predicted_class,
108
+ 'confidence': confidence,
109
+ 'probabilities': prob_dict,
110
+ 'below_threshold': confidence < self.confidence_threshold
111
+ }
112
+
113
+ # STEP 4: Generate treatment (only if confident)
114
+ if confidence >= self.confidence_threshold:
115
+ print("πŸ’Š Generating treatment recommendations...")
116
+ treatment = self.treatment_generator.get_recommendations(
117
+ predicted_class, confidence
118
+ )
119
+ result['treatment'] = treatment
120
+
121
+ result['success'] = True
122
+ return result
123
+
124
+ except Exception as e:
125
+ result['error'] = f"❌ Prediction failed: {str(e)}"
126
+ return result
127
+
128
+ def predict_from_image(self, pil_image):
129
+ """
130
+ Predict directly from PIL Image (for web UI)
131
+
132
+ Args:
133
+ pil_image: PIL Image object
134
+
135
+ Returns:
136
+ dict: Same as predict() method
137
+ """
138
+ result = {
139
+ 'success': False,
140
+ 'error': None,
141
+ 'validation': {},
142
+ 'prediction': {},
143
+ 'treatment': None
144
+ }
145
+
146
+ try:
147
+ # Convert to RGB if needed
148
+ image = pil_image.convert('RGB')
149
+
150
+ # File validation not needed (already have image)
151
+ result['validation']['file'] = {'valid': True, 'message': 'βœ… Image provided'}
152
+
153
+ # Gemini validation
154
+ print("πŸ€– Validating with Gemini AI...")
155
+ is_valid, msg = self.validator.validate_with_gemini(image, self.gemini_model)
156
+ result['validation']['gemini'] = {'valid': is_valid, 'message': msg}
157
+ print(msg)
158
+
159
+ if not is_valid:
160
+ result['error'] = msg
161
+ return result
162
+
163
+ # Model prediction
164
+ print("πŸ”¬ Analyzing fish health...")
165
+ class_idx, confidence, probabilities = self.model_loader.predict(image)
166
+
167
+ predicted_class = self.config['CLASSES'][class_idx]
168
+
169
+ prob_dict = {
170
+ self.config['CLASSES'][i]: float(probabilities[i].item() * 100)
171
+ for i in range(len(self.config['CLASSES']))
172
+ }
173
+
174
+ result['prediction'] = {
175
+ 'disease': predicted_class,
176
+ 'confidence': confidence,
177
+ 'probabilities': prob_dict,
178
+ 'below_threshold': confidence < self.confidence_threshold
179
+ }
180
+
181
+ # Generate treatment
182
+ if confidence >= self.confidence_threshold:
183
+ print("πŸ’Š Generating treatment recommendations...")
184
+ treatment = self.treatment_generator.get_recommendations(
185
+ predicted_class, confidence
186
+ )
187
+ result['treatment'] = treatment
188
+
189
+ result['success'] = True
190
+ return result
191
+
192
+ except Exception as e:
193
+ result['error'] = f"❌ Prediction failed: {str(e)}"
194
+ return result
backend/treatment.py ADDED
@@ -0,0 +1,177 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Treatment module - Generates disease treatment recommendations
3
+ Uses Gemini AI or falls back to predefined treatments
4
+ """
5
+
6
+ class TreatmentGenerator:
7
+ """Generates treatment recommendations for fish diseases"""
8
+
9
+ def __init__(self, gemini_model=None):
10
+ """
11
+ Initialize treatment generator
12
+
13
+ Args:
14
+ gemini_model: Google Gemini model instance (optional)
15
+ """
16
+ self.gemini_model = gemini_model
17
+
18
+ def get_recommendations(self, disease_name, confidence):
19
+ """
20
+ Get treatment recommendations for detected disease
21
+
22
+ Args:
23
+ disease_name: Name of detected disease
24
+ confidence: Confidence score (0-100)
25
+
26
+ Returns:
27
+ str: Formatted treatment recommendations
28
+ """
29
+ if self.gemini_model:
30
+ return self._get_ai_treatment(disease_name, confidence)
31
+ else:
32
+ return self._get_fallback_treatment(disease_name)
33
+
34
+ def _get_ai_treatment(self, disease_name, confidence):
35
+ """Generate AI-powered treatment using Gemini"""
36
+ try:
37
+ prompt = f"""You are an expert aquaculture veterinarian with 20 years of experience.
38
+
39
+ **DIAGNOSIS:**
40
+ - Disease: {disease_name.replace('_', ' ')}
41
+ - Confidence: {confidence:.1f}%
42
+
43
+ Provide a detailed, practical treatment plan in this EXACT format:
44
+
45
+ **IMMEDIATE ACTIONS (First 24 hours):**
46
+ - [List 3-4 urgent steps with specific timing]
47
+
48
+ **TREATMENT PROTOCOL (Days 1-10):**
49
+ - [Medications with exact dosages, frequency, and duration]
50
+ - [Water management with specific parameters]
51
+
52
+ **PREVENTION MEASURES:**
53
+ - [List 4-5 specific preventive measures for future]
54
+
55
+ **EXPECTED OUTCOME:**
56
+ - [Recovery timeline and realistic success rate]
57
+
58
+ Requirements:
59
+ - Be specific with dosages (mg/kg, ppm, etc.)
60
+ - Include water parameter targets (pH, DO, temperature)
61
+ - Use simple language for fish farmers
62
+ - Focus on practical, actionable steps"""
63
+
64
+ response = self.gemini_model.generate_content(prompt)
65
+ return response.text
66
+
67
+ except Exception as e:
68
+ print(f"⚠️ Gemini treatment generation error: {e}")
69
+ return self._get_fallback_treatment(disease_name)
70
+
71
+ def _get_fallback_treatment(self, disease_name):
72
+ """Fallback treatment database (predefined)"""
73
+ treatments = {
74
+ 'Aeromoniasis': """**IMMEDIATE ACTIONS (First 24 hours):**
75
+ - Isolate infected fish immediately to prevent spread
76
+ - Perform 50% water change within 2 hours
77
+ - Increase aeration to maximum capacity
78
+ - Stop feeding for 24 hours to reduce waste
79
+
80
+ **TREATMENT PROTOCOL (Days 1-10):**
81
+ - Antibiotics: Oxytetracycline 50-75 mg/kg feed for 10 consecutive days
82
+ - Salt bath: 3% NaCl solution for 5-10 minutes daily (days 1-7)
83
+ - Maintain water temperature at 25-28Β°C
84
+ - Monitor daily for 14 days post-treatment
85
+
86
+ **PREVENTION MEASURES:**
87
+ - Maintain dissolved oxygen > 5 mg/L at all times
88
+ - Reduce stocking density by 30% if currently overcrowded
89
+ - Implement 14-21 day quarantine for all new fish
90
+ - Weekly health monitoring and immediate isolation of sick fish
91
+ - Regular disinfection of equipment and nets
92
+
93
+ **EXPECTED OUTCOME:**
94
+ 70-80% recovery rate with prompt treatment. Symptoms should improve within 3-5 days. Full recovery typically takes 10-14 days.""",
95
+
96
+ 'Bacterial_gill_disease': """**IMMEDIATE ACTIONS (First 24 hours):**
97
+ - Increase aeration immediately (CRITICAL - survival depends on oxygen)
98
+ - Reduce feeding by 50% to minimize ammonia buildup
99
+ - Test and adjust water quality (pH, ammonia, nitrite)
100
+ - Separate severely affected fish to reduce stress
101
+
102
+ **TREATMENT PROTOCOL (Days 1-10):**
103
+ - Salt bath: 3% NaCl for 5-10 minutes daily for 7 days
104
+ - Improve water circulation (add aerators/water pumps)
105
+ - Reduce stocking density by 40%
106
+ - Antibiotics: Florfenicol 10 mg/kg feed daily for 7-10 days (if severe)
107
+
108
+ **PREVENTION MEASURES:**
109
+ - Maintain dissolved oxygen > 5 mg/L continuously (CRITICAL)
110
+ - Regular pond/tank cleaning (bi-weekly minimum)
111
+ - Daily ammonia monitoring (keep < 0.02 mg/L)
112
+ - Avoid sudden temperature changes (Β±2Β°C maximum)
113
+ - Proper biofilter maintenance and regular backwashing
114
+
115
+ **EXPECTED OUTCOME:**
116
+ 85-90% recovery if caught early (within 2-3 days). Symptoms improve within 48 hours of treatment. Mortality high if delayed beyond 5 days.""",
117
+
118
+ 'EUS': """**IMMEDIATE ACTIONS (First 24 hours):**
119
+ - REPORT TO AUTHORITIES (notifiable disease in many regions)
120
+ - Isolate all affected fish immediately
121
+ - Implement 75% water change
122
+ - Remove and properly dispose of dead/dying fish
123
+
124
+ **TREATMENT PROTOCOL (Days 1-21):**
125
+ - Topical disinfectant: Potassium permanganate 2-5 ppm bath (3 times weekly)
126
+ - NO specific cure available - focus on supportive care
127
+ - Maintain optimal water conditions (see below)
128
+ - Consider humane culling of severely affected fish (>50% body lesions)
129
+ - Secondary infection prevention: Oxytetracycline 50 mg/kg feed
130
+
131
+ **PREVENTION MEASURES:**
132
+ - NEVER use water from infected sources
133
+ - Implement strict biosecurity: footbaths, equipment disinfection
134
+ - Quarantine ALL new fish for minimum 21 days
135
+ - Regular health surveillance (weekly inspections)
136
+ - Maintain year-round optimal water quality
137
+
138
+ **EXPECTED OUTCOME:**
139
+ Variable (40-90% mortality depending on strain and timing). NO cure exists. Early detection critical. Focus on prevention and biosecurity.""",
140
+
141
+ 'Healthy_Fish': """**MAINTENANCE (Continue Good Practices):**
142
+ - Continue current care routine (it's working excellently!)
143
+ - Daily observations for early disease detection
144
+ - Maintain current feeding schedule (adjust seasonally)
145
+ - Regular water quality monitoring
146
+
147
+ **PREVENTION MEASURES:**
148
+ - Weekly water parameter testing (pH, ammonia, nitrite, nitrate, DO)
149
+ - Quarantine new fish for 14-21 days before introduction
150
+ - Clean and disinfect all equipment monthly
151
+ - Daily behavioral observations (feeding response, swimming patterns)
152
+ - Maintain detailed health records
153
+
154
+ **EXPECTED OUTCOME:**
155
+ Excellent prognosis. Continue preventive care to maintain optimal health status. Regular monitoring ensures early detection of any future issues."""
156
+ }
157
+
158
+ # Default treatment for diseases not in database
159
+ default = """**IMPORTANT: Consult a fish health expert immediately.**
160
+
161
+ This disease requires professional veterinary assessment for accurate diagnosis and treatment protocol.
162
+
163
+ **IMMEDIATE STEPS:**
164
+ 1. Isolate affected fish to prevent potential spread
165
+ 2. Improve water quality (50% water change, increase aeration)
166
+ 3. Document all symptoms with photos and notes
167
+ 4. Contact your local aquaculture veterinarian or extension service
168
+
169
+ **EMERGENCY CONTACT:**
170
+ Seek professional help from:
171
+ - Local fish health specialist
172
+ - Aquaculture extension service
173
+ - Veterinary diagnostic laboratory
174
+
175
+ Do NOT attempt unguided treatment as it may worsen the condition."""
176
+
177
+ return treatments.get(disease_name, default)
backend/validator.py ADDED
@@ -0,0 +1,133 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Validation module - Handles all edge cases and input validation
3
+ """
4
+
5
+ import os
6
+ from PIL import Image
7
+ from .config import MAX_FILE_SIZE_MB, MIN_IMAGE_SIZE_PX, VALID_EXTENSIONS
8
+
9
+ class FishImageValidator:
10
+ """Comprehensive image validation with edge case handling"""
11
+
12
+ def __init__(self, max_size_mb=MAX_FILE_SIZE_MB,
13
+ min_size_px=MIN_IMAGE_SIZE_PX,
14
+ valid_extensions=VALID_EXTENSIONS):
15
+ self.max_size_mb = max_size_mb
16
+ self.min_size_px = min_size_px
17
+ self.valid_extensions = valid_extensions
18
+
19
+ def validate_file(self, file_path):
20
+ """
21
+ Validate file exists, type, size, and image integrity
22
+
23
+ Returns:
24
+ tuple: (is_valid: bool, message: str, image: PIL.Image or None)
25
+ """
26
+ # Check 1: File exists
27
+ if not os.path.exists(file_path):
28
+ return False, "❌ File not found", None
29
+
30
+ # Check 2: File extension
31
+ if not any(file_path.lower().endswith(ext.lower()) for ext in self.valid_extensions):
32
+ return False, f"❌ Invalid file type. Accepted: {', '.join(self.valid_extensions)}", None
33
+
34
+ # Check 3: File size
35
+ try:
36
+ file_size_mb = os.path.getsize(file_path) / (1024 * 1024)
37
+ if file_size_mb > self.max_size_mb:
38
+ return False, f"❌ File too large ({file_size_mb:.1f}MB). Max: {self.max_size_mb}MB", None
39
+ except Exception as e:
40
+ return False, f"❌ Cannot read file: {e}", None
41
+
42
+ # Check 4: Valid image file
43
+ try:
44
+ img = Image.open(file_path)
45
+ img.verify() # Check for corruption
46
+ img = Image.open(file_path) # Re-open after verify (verify closes it)
47
+ img = img.convert('RGB') # Ensure RGB format
48
+
49
+ # Check 5: Image dimensions
50
+ if img.width < self.min_size_px or img.height < self.min_size_px:
51
+ return False, f"❌ Image too small ({img.width}x{img.height}px). Min: {self.min_size_px}x{self.min_size_px}px", None
52
+
53
+ return True, "βœ… File validation passed", img
54
+
55
+ except Exception as e:
56
+ return False, f"❌ Invalid or corrupted image: {str(e)}", None
57
+
58
+ def validate_with_gemini(self, image, gemini_model):
59
+ """
60
+ AI-based validation with Gemini Vision
61
+ Handles edge cases: multiple fish, dead fish, toys, drawings, partial fish
62
+ Accepts dataset images with transparent or solid backgrounds
63
+
64
+ Returns:
65
+ tuple: (is_valid: bool, message: str)
66
+ """
67
+ if gemini_model is None:
68
+ return True, "⚠️ Gemini validation disabled"
69
+
70
+ try:
71
+ prompt = """Analyze this image for fish disease diagnosis.
72
+
73
+ Answer these questions:
74
+
75
+ 1. Is there a FISH visible in this image? (Can be a real photo, medical/diagnostic image, or isolated fish specimen on any background including transparent/solid backgrounds)
76
+ 2. How many fish are in the image?
77
+ 3. Is the fish body clearly visible (not just head or tail)?
78
+ 4. Can you see enough fish detail for disease assessment?
79
+
80
+ Respond in this EXACT format:
81
+ CONTAINS_FISH: YES or NO
82
+ FISH_COUNT: [number]
83
+ BODY_VISIBLE: YES or NO
84
+ SUFFICIENT_DETAIL: YES or NO
85
+ REASON: [brief explanation if any answer is NO]
86
+
87
+ IMPORTANT NOTES:
88
+ - Isolated fish on transparent, white, or solid backgrounds ARE ACCEPTABLE (common in medical datasets)
89
+ - Focus on whether the FISH ITSELF is clear and detailed, not the background
90
+ - Reject only if it's clearly NOT a fish (toy, cartoon, drawing of non-fish subject)"""
91
+
92
+ response = gemini_model.generate_content([prompt, image])
93
+ answer = response.text.strip().upper()
94
+
95
+ # Parse and validate responses
96
+
97
+ # Check 1: Contains fish?
98
+ if "CONTAINS_FISH: NO" in answer:
99
+ reason = self._extract_reason(answer)
100
+ return False, f"❌ No fish detected. {reason}"
101
+
102
+ # Check 2: Fish count zero
103
+ if "FISH_COUNT: 0" in answer or "FISH_COUNT: NONE" in answer:
104
+ return False, "❌ No fish found in image"
105
+
106
+ # Check 3: Multiple fish
107
+ for i in range(2, 20):
108
+ if f"FISH_COUNT: {i}" in answer:
109
+ return False, "❌ Multiple fish detected. Upload single fish only"
110
+
111
+ # Check 4: Body visible
112
+ if "BODY_VISIBLE: NO" in answer:
113
+ return False, "❌ Fish body not clearly visible"
114
+
115
+ # Check 5: Sufficient detail
116
+ if "SUFFICIENT_DETAIL: NO" in answer:
117
+ reason = self._extract_reason(answer)
118
+ return False, f"❌ Insufficient detail for diagnosis. {reason}"
119
+
120
+ return True, "βœ… Valid fish image detected"
121
+
122
+ except Exception as e:
123
+ # Graceful degradation - log but don't block
124
+ print(f"⚠️ Gemini validation error: {e}")
125
+ return True, "⚠️ AI validation skipped (error occurred)"
126
+
127
+ @staticmethod
128
+ def _extract_reason(response_text):
129
+ """Extract reason from Gemini response"""
130
+ if "REASON:" in response_text:
131
+ reason = response_text.split("REASON:")[-1].strip()
132
+ return reason[:150] # Limit length
133
+ return "See validation details"
models/vgg_resnet/results/vgg_resnet/vgg16_best.pth ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:38c2a4998fbea8dd33d78afc318ad30da47adbf6ebda811673168f50dd2c6738
3
+ size 537185333
requirements.txt ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ torch==2.5.1
2
+ torchvision==0.20.1
3
+ gradio==5.7.1
4
+ google-generativeai==0.8.3
5
+ pillow==11.0.0
6
+ opencv-python-headless==4.10.0.84
7
+ numpy==1.26.4
8
+ python-dotenv==1.0.0