CropScan is a full-stack crop disease diagnosis app. A user signs in, uploads or captures a leaf photo, receives predictions from two PyTorch image classifiers, reviews AI-generated treatment guidance, and can ask follow-up questions about the diagnosis.
The app is built for smallholder farmers, backyard growers, and agricultural extension-style field work.
- Account signup, login, profile editing, and protected routes
- Leaf image upload and browser camera capture
- Dual-model prediction with EfficientNet-B0 and MobileNetV2
- 38 PlantVillage disease and healthy classes
- Low-confidence fallback behavior
- Image suitability check before disease inference
- Gemini-backed recommendation summary
- Diagnosis follow-up chat with a 10-question limit per scan
- Product-category and supply-plan recommendations
- Saved scan history and field notes
- Docker setup for one-command local runs
- Vercel frontend and Render backend deployment path
| Layer | Technology |
|---|---|
| Frontend | React, TypeScript, Vite, Tailwind CSS, React Router |
| Backend | FastAPI, Pydantic, PyMongo, JWT auth |
| AI / ML | PyTorch, torchvision, EfficientNet-B0, MobileNetV2, Gemini |
| Database | MongoDB Atlas or any MongoDB-compatible database |
| Local containers | Docker Compose |
| Deployment | Vercel frontend, Render backend |
backend/ FastAPI API, auth, MongoDB access, model loading, prediction, Gemini
cropscan/ React frontend
notebooks/ model training and experimentation notebooks
You need:
- MongoDB connection string
- JWT secret
- Gemini API key if you want AI recommendations and chat
- model files in
backend/models
Required model files:
backend/models/efficientnet_b0_cropscan.pth
backend/models/mobilenetv2_cropscan.pth
If the model files are missing, the upload endpoint will fail when it tries to load the classifiers.
Use local .env files. Do not commit real secrets.
Create:
backend/.env
cropscan/.env
The repo includes:
backend/.env.example
cropscan/.env.example
ENVIRONMENT=development
MONGODB_URL=mongodb+srv://<username>:<password>@cluster.mongodb.net/cropscan
MONGODB_DB_NAME=cropscan
JWT_SECRET_KEY=replace-with-secrets-token-urlsafe-48-or-another-32-plus-character-secret
JWT_ALGORITHM=HS256
ACCESS_TOKEN_EXPIRE_MINUTES=60
PREDICTION_TOKEN_EXPIRE_MINUTES=30
CORS_ORIGINS=http://localhost:5173,http://127.0.0.1:5173
CORS_ORIGIN_REGEX=^https?://(localhost|127\.0\.0\.1)(:\d+)?$
MODEL_DIR=models
GEMINI_API_KEY=replace-with-your-gemini-api-key
GEMINI_MODEL=gemini-2.5-flash
RESEND_API_KEY=replace-with-your-resend-api-key
RESEND_FROM_EMAIL=CropScan <onboarding@yourdomain.com>
APP_BASE_URL=http://localhost:5173
PASSWORD_RESET_OTP_EXPIRE_MINUTES=10
EMAIL_DEBUG_OTP=false
RATE_LIMIT_ENABLED=true
RATE_LIMIT_STORAGE_URI=
TRUST_PROXY_HEADERS=false
PASSWORD_RESET_RESPONSE_DELAY_SECONDS=0.3
PASSWORD_RESET_MAX_ATTEMPTS=5
PASSWORD_RESET_LOCKOUT_MINUTES=60
MAX_SCANS_PER_USER=2000
MAX_PLOTS_PER_USER=50For deployed production on Render, set:
ENVIRONMENT=production
CORS_ORIGINS=https://cropscan.tech,https://www.cropscan.tech
RATE_LIMIT_STORAGE_URI=rediss://<upstash-redis-url>
EMAIL_DEBUG_OTP=falseUse a shared Redis-compatible RATE_LIMIT_STORAGE_URI in production. Without it, rate limits are process-local and only correct for a single backend worker.
Set TRUST_PROXY_HEADERS=true only behind a trusted proxy such as Render. Keep it false for local Docker or direct uvicorn runs.
For normal local development:
VITE_API_BASE_URL=http://127.0.0.1:8000/api/v1For Vercel production:
VITE_API_BASE_URL=/api/v1Vercel uses cropscan/vercel.json to proxy /api/v1/* to the Render backend.
This is the easiest path for teammates and demo reviewers.
Copy-Item backend\.env.example backend\.env
Copy-Item cropscan\.env.example cropscan\.env
docker compose up --buildcp backend/.env.example backend/.env
cp cropscan/.env.example cropscan/.env
docker compose up --buildThen open:
- Frontend:
http://localhost:5173 - Backend:
http://localhost:8000 - Backend docs:
http://localhost:8000/docs
Stop containers:
docker compose downDocker still requires valid values in backend/.env.
Use this path if you are developing without Docker.
- Python 3.11
- Node.js 18+ and npm
- MongoDB connection string
Python 3.11 is important because the backend uses PyTorch and torchvision.
cd backend
py -3.11 -m venv .venv
.\.venv\Scripts\Activate.ps1
python -m pip install --upgrade pip
pip install -r requirements.txt
Copy-Item .env.example .env
uvicorn app.main:app --reloadIf python3.11 is installed:
cd backend
python3.11 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
pip install -r requirements.txt
cp .env.example .env
uvicorn app.main:app --reloadIf you use Homebrew:
brew install python@3.11Then rerun the setup above.
cd backend
python3.11 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
pip install -r requirements.txt
cp .env.example .env
uvicorn app.main:app --reloadOn Ubuntu/Debian, if Python 3.11 venv support is missing:
sudo apt update
sudo apt install python3.11 python3.11-venv python3.11-devBackend URLs:
- API root:
http://127.0.0.1:8000 - Docs:
http://127.0.0.1:8000/docs - Health:
http://127.0.0.1:8000/health
Open a second terminal from the project root.
cd cropscan
npm install
Copy-Item .env.example .env
npm run devcd cropscan
npm install
cp .env.example .env
npm run devFrontend URL:
http://127.0.0.1:5173
If Vite chooses another port, add that origin to backend/.env under CORS_ORIGINS or rely on the existing local CORS regex.
- Start the backend.
- Start the frontend.
- Open the frontend URL.
- Create an account or log in.
- Go to the scan page.
- Upload a leaf image or use camera capture.
- Review both model predictions.
- Review the recommendation and supply plan.
- Ask follow-up questions in chat.
- Open the dashboard to review saved history.
Main routes:
GET /healthPOST /api/v1/auth/signupPOST /api/v1/auth/loginGET /api/v1/auth/mePATCH /api/v1/auth/mePOST /api/v1/auth/change-passwordPOST /api/v1/auth/forgot-password/requestPOST /api/v1/auth/forgot-password/confirmPOST /api/v1/uploadPOST /api/v1/chat
Protected routes require:
Authorization: Bearer <token>
Password reset uses a Resend-backed one-time code. In local development only, set EMAIL_DEBUG_OTP=true to return the code in the API response while email is not configured.
cd cropscan
npm run lint
npm run buildWindows PowerShell:
cd backend
.\.venv\Scripts\Activate.ps1
python -m pytest tests
python -m compileall appmacOS / Linux:
cd backend
source .venv/bin/activate
python -m pytest tests
python -m compileall appdocker compose build
docker compose upProduction is split across Vercel and Render:
- Frontend: Vercel
- Backend: Render
- Database: MongoDB Atlas
- Domain:
cropscan.tech
Create a Render Web Service from the repo.
Use:
Root Directory: backend
Environment: Docker
Branch: master
Health Check Path: /health
Set backend environment variables in the Render dashboard, not in Git.
Production CORS:
CORS_ORIGINS=https://cropscan.tech,https://www.cropscan.techCreate a Vercel project from the same repo.
Use:
Root Directory: cropscan
Framework Preset: Vite
Build Command: npm run build
Output Directory: dist
Production Branch: master
Set:
VITE_API_BASE_URL=/api/v1The file cropscan/vercel.json forwards /api/v1/* requests to the Render backend and sends client-side routes back to the React app.
Point cropscan.tech and www.cropscan.tech to Vercel using the records shown in the Vercel dashboard. Use Vercel's displayed DNS values because they are the source of truth for the project.
Install Python 3.11 and recreate the backend virtual environment.
Confirm both model files exist in backend/models.
Check:
- backend is running
- frontend
.envuseshttp://127.0.0.1:8000/api/v1 - backend
.envincludes the frontend origin or local CORS regex - backend was restarted after
.envchanges
Check Render:
CORS_ORIGINS=https://cropscan.tech,https://www.cropscan.techCheck Vercel:
VITE_API_BASE_URL=/api/v1Then redeploy both services.
Free Render services can sleep after inactivity. The first request may take longer while the service wakes and loads the PyTorch models.
Use feature branches for active work, merge into develop after verification, then promote to master for deployment.
feature branch -> develop -> master
Run frontend and backend checks before merging into master.