An end-to-end deep learning application that detects plant diseases from leaf images and provides detailed remedy suggestions.
- 📸 Upload leaf images via drag-and-drop or file picker
- 🤖 AI disease prediction using MobileNetV2 transfer learning
- 📊 Confidence score with top-5 prediction breakdown
- 💊 Disease description, symptoms, causes, and remedies
- 🛡️ Prevention tips for each condition
- ⚡ Real-time inference via FastAPI REST API
- 📱 Responsive modern UI (React + Tailwind CSS)
| Plant | Conditions |
|---|---|
| Tomato | Bacterial Spot, Early Blight, Late Blight, Leaf Mold, Septoria Leaf Spot, Spider Mites, Target Spot, Yellow Leaf Curl Virus, Mosaic Virus, Healthy (10 classes) |
| Potato | Early Blight, Late Blight, Healthy (3 classes) |
| Bell Pepper | Bacterial Spot, Healthy (2 classes) |
| Blueberry | Healthy (1 class) |
| Orange | Huanglongbing/Citrus Greening (1 class) |
| Raspberry | Healthy (1 class) |
Training Dataset Distribution:
- Total Classes: 18
- Total Plant Types: 6 (Tomato, Potato, Bell Pepper, Blueberry, Orange, Raspberry)
- Healthy Classes: 6
- Disease Classes: 12
crop-disease-detection/
├── backend/ # FastAPI server
│ ├── app/
│ │ ├── main.py # App entry + CORS + lifespan
│ │ ├── api/
│ │ │ └── routes.py # /predict & /health endpoints
│ │ ├── core/
│ │ │ └── config.py # Settings via pydantic-settings
│ │ ├── models/
│ │ │ └── schemas.py # Pydantic request/response models
│ │ └── services/
│ │ ├── prediction_service.py # Model load + inference
│ │ └── remedy_service.py # Disease database + remedies
│ ├── trained_model/ # Model files (generated by training)
│ │ ├── crop_disease_model.keras
│ │ └── class_names.json
│ ├── requirements.txt
│ └── .env.example
│
├── frontend/ # React + Vite application
│ ├── src/
│ │ ├── App.jsx # Root component + layout
│ │ ├── main.jsx # React entry point
│ │ ├── index.css # Tailwind + global styles
│ │ ├── components/
│ │ │ ├── ui/ # Header, LoadingSpinner, ErrorAlert
│ │ │ ├── upload/ # UploadZone (drag & drop)
│ │ │ └── prediction/ # PredictionCard, ConfidenceBar
│ │ ├── hooks/
│ │ │ └── usePrediction.js # Upload + predict state logic
│ │ ├── services/
│ │ │ └── api.js # Axios instance + API calls
│ │ └── utils/
│ │ └── helpers.js # Color helpers, formatters
│ ├── package.json
│ ├── vite.config.js
│ ├── tailwind.config.js
│ └── .env.example
│
├── ml/ # Machine learning pipeline
│ ├── train.py # Full training script
│ ├── requirements.txt
│ └── outputs/ # Training plots + checkpoints
│
├── Dataset/ # PlantVillage dataset (not committed)
│ └── PlantVillage/
│ ├── Tomato_Bacterial_spot/
│ ├── Tomato_healthy/
│ └── ... (16 classes)
│
├── .gitignore
└── README.md
- Python 3.10+
- Node.js 18+
- npm 9+
git clone https://github.com/yourusername/crop-disease-detection.git
cd crop-disease-detectionPlace your PlantVillage dataset at:
crop-disease-detection/Dataset/PlantVillage/
The folder must contain subdirectories named after each class:
Dataset/PlantVillage/
Blueberry___healthy/
Orange___Haunglongbing_(Citrus_greening)
Potato___Early_blight/
Potato___Late_blight/
Potato___healthy/
Pepper__bell___Bacterial_spot/
Pepper__bell___healthy/
Raspberry___healthy/
Tomato_Bacterial_spot/
Tomato_Early_blight/
Tomato_Late_blight/
Tomato_Leaf_Mold/
Tomato_Septoria_leaf_spot/
Tomato_Spider_mites_Two_spotted_spider_mite/
Tomato__Target_Spot/
Tomato__Tomato_YellowLeaf__Curl_Virus/
Tomato__Tomato_mosaic_virus/
Tomato_healthy/
cd ml
# Create and activate virtual environment
python -m venv .venv
.\.venv\Scripts\Activate.ps1 # Linux/macOS: source .venv/bin/activate
# Install ML dependencies
pip install -r requirements.txt
# Run training (GPU recommended; CPU works but is slow)
python train.pyThis will:
- Train MobileNetV2 with transfer learning (two phases: head + fine-tune)
- Save the model to
backend/trained_model/crop_disease_model.keras - Save class names to
backend/trained_model/class_names.json - Generate training accuracy/loss plots in
ml/outputs/
Training time: ~20–40 min on GPU, ~2–4 hours on CPU.
cd backend
# Create and activate virtual environment
python -m venv .venv
.\.venv\Scripts\Activate.ps1 # Linux/macOS: source .venv/bin/activate
# Install dependencies
pip install -r requirements.txt
# Copy environment file
cp .env.example .env
# Start the server
uvicorn app.main:app --reload --host 0.0.0.0 --port 8000API will be available at: http://localhost:8000
Interactive docs: http://localhost:8000/docs
cd frontend
# Install dependencies
npm install
# Copy environment file
cp .env.example .env
# Start development server
npm run devApp will be available at: http://localhost:5173
{
"status": "ok",
"model_loaded": true,
"message": "Model ready for predictions."
}Request: multipart/form-data with a file field (JPEG, PNG, or WebP image, max 10 MB)
Response:
{
"success": true,
"class_name": "Tomato_Late_blight",
"display_name": "Tomato – Late Blight",
"plant": "Tomato",
"disease": "Late Blight",
"confidence": 0.9734,
"confidence_pct": 97.34,
"description": "Tomato late blight is caused by Phytophthora infestans...",
"symptoms": [
"Large, irregular, greasy-looking grayish-green to dark brown spots on leaves",
"White, downy fungal growth on undersides of leaves in humid conditions"
],
"causes": "Phytophthora infestans; spread by wind and rain...",
"remedies": [
"Apply metalaxyl-M (Ridomil Gold) at first symptoms",
"Spray dimethomorph (Acrobat) or cymoxanil as curative treatment"
],
"prevention": [
"Plant resistant tomato varieties (e.g., Mountain Magic, Defiant)"
],
"severity": "high",
"top5_predictions": [
{ "class_name": "Tomato_Late_blight", "confidence": 0.9734, "confidence_pct": 97.34 },
{ "class_name": "Tomato_Early_blight", "confidence": 0.0201, "confidence_pct": 2.01 }
],
"filename": "leaf.jpg"
}Input (224×224×3)
└── MobileNetV2 (ImageNet pretrained, frozen)
└── GlobalAveragePooling2D
└── BatchNormalization
└── Dense(512, relu) + Dropout(0.4)
└── Dense(256, relu) + Dropout(0.3)
└── Dense(15, softmax)
Training strategy:
- Phase 1 (head training): Freeze base, train classifier head for 10 epochs at lr=1e-3
- Phase 2 (fine-tuning): Unfreeze top layers (after layer 100), train for 15 epochs at lr=1e-5
Both the backend and frontend are deployed on Render using the render.yaml blueprint in the repo root.
- A Render account (free tier works)
- Repository pushed to GitHub
- Trained model file (
backend/trained_model/crop_disease_model.keras) committed to Git
⚠️ Important: Make sure.gitignoredoes NOT exclude*.kerasfiles, otherwise the model won't be pushed to GitHub and the backend will fail to start on Render.
┌─────────────────────────┐ ┌─────────────────────────┐
│ Frontend (Static) │ │ Backend (Web Service) │
│ Render Static Site │──────▶│ Render Web Service │
│ React + Vite │ │ FastAPI + TensorFlow │
│ cropguard-frontend │ │ cropguard-backend │
└─────────────────────────┘ └─────────────────────────┘
- Push your repo to GitHub
- Go to render.com → Sign in with GitHub
- Click "New" → "Blueprint"
- Select your repository
- Render auto-detects the
render.yamland creates both services - Click "Apply"
The render.yaml defines two services:
Backend (Web Service):
- type: web
name: cropguard-backend
runtime: python
plan: free
buildCommand: cd backend && pip install -r requirements.txt
startCommand: cd backend && uvicorn app.main:app --host 0.0.0.0 --port $PORT
healthCheckPath: /api/v1/healthFrontend (Static Site):
- type: static_site
name: cropguard-frontend
rootDir: frontend
buildCommand: npm install && npm run build
staticPublishPath: distAfter both services are created, note their URLs from the Render dashboard (e.g., https://cropguard-backend-xxxx.onrender.com and https://cropguard-frontend-xxxx.onrender.com).
Backend environment variables (Service → Environment):
| Key | Value |
|---|---|
PYTHONUNBUFFERED |
1 |
MODEL_PATH |
./trained_model/crop_disease_model.keras |
CORS_ORIGINS |
https://cropguard-frontend-xxxx.onrender.com |
ENVIRONMENT |
production |
Frontend environment variables (Service → Environment):
| Key | Value |
|---|---|
VITE_API_BASE_URL |
https://cropguard-backend-xxxx.onrender.com |
⚠️ Important: The env var must beVITE_API_BASE_URL(notVITE_API_URL). This must match what the frontend code reads insrc/services/api.js.
After updating environment variables:
- Backend: Go to the backend service → Manual Deploy → Deploy latest commit
- Frontend: Go to the frontend service → Manual Deploy → Clear build cache & deploy
💡 The frontend must be rebuilt (not just redeployed) because
VITE_*environment variables are baked into the JavaScript bundle at build time.
Test the backend API:
curl https://cropguard-backend-xxxx.onrender.com/api/v1/healthExpected response:
{
"status": "ok",
"model_loaded": true,
"message": "Model ready for predictions."
}Test the frontend:
Visit https://cropguard-frontend-xxxx.onrender.com — the "Backend server is offline" banner should NOT appear.
The backend reads the CORS_ORIGINS environment variable at startup and adds those origins to the allowed list (see backend/app/core/config.py). Local development origins (localhost:5173, localhost:3000) are included by default.
You do not need to edit backend/app/main.py for CORS — just set the CORS_ORIGINS env var in Render with your frontend URL.
❌ "Publish directory dist does not exist!" on frontend deploy?
- Ensure
rootDiris set tofrontendin Render dashboard (Settings → Root Directory) - Publish Directory should be
dist(notfrontend/dist) - The
vite.config.jsmust havebuild.outDir: "dist"set explicitly
❌ Backend crashes / model not loading?
- Verify
backend/trained_model/crop_disease_model.kerasis committed to Git (check.gitignore) - Check Render logs: Service → Logs
- Ensure
MODEL_PATHenv var is set to./trained_model/crop_disease_model.keras
❌ "Backend server is offline" on frontend?
- Verify the backend is running: visit
https://your-backend.onrender.com/api/v1/health - Ensure
VITE_API_BASE_URL(notVITE_API_URL) is set correctly in frontend env vars - Rebuild the frontend after changing env vars (Clear build cache & deploy)
❌ "Cannot reach the server" when clicking Analyze?
- Check CORS:
CORS_ORIGINSon the backend must include the exact frontend URL - Check browser DevTools → Network tab for CORS errors
- Ensure the backend start command uses
--port $PORT(not a hardcoded port)
❌ Cold start too slow?
- Render free tier sleeps after 15 mins of inactivity
- First request after sleep takes ~30–60 seconds (TensorFlow model loading)
- Upgrade to paid tier for always-on production use
MIT License. For educational and research use.
⚠️ This tool is for educational purposes only. Always consult a certified agronomist for farm management decisions.