Skip to content

DRoqueProgrammer/pest-detector

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

🐛 PestDetector

AgriTech plant disease & pest classification service. A full-stack reference app: fine-tune a YOLO11-cls model on the public PlantVillage dataset, export to ONNX, serve behind a FastAPI backend, and consume from a Vue 3 SPA. Built as a portfolio capstone aligned with the detection-style pipelines used in modern AgTech products (Solinftec Solix, Climate Fieldview, etc.).

Backend CI Frontend CI License: MIT Stack Stack Stack Stack

🇧🇷 Versão em português · 🇺🇸 English version


🇺🇸 English version

What it does

  1. Trains a YOLO11n-cls model on the 54k-image PlantVillage dataset (38 classes, 14 crops).
  2. Exports the fine-tuned weights to ONNX for fast CPU inference.
  3. Serves a REST API (/health, /model/info, POST /detect) that accepts a leaf image and returns the top-K predicted classes with confidences.
  4. A small Vue 3 SPA lets you drag-and-drop a leaf and see the predictions in a clean list with confidence bars.

Why this project

I am preparing for a Junior Web Developer role at an AgTech company (Solinftec's public stack on GitHub shows a YOLOv5 fork for in-field pest detection, so this project mirrors that choice at portfolio scale). I wanted a small but end-to-end example that demonstrates:

  • I can train and export a vision model, not just call an API.
  • I can build a clean REST API with FastAPI + Pydantic.
  • I can ship a usable Vue 3 frontend.
  • I think about deployment (ONNX, multi-stage Docker, CI).

How to run

Option A — local with the venv helper scripts (no Docker)

# From the repo root, in bash (WSL / git-bash / MSYS)
cd backend
./setup.sh        # creates .venv with Python 3.14 and installs deps
./test.sh         # pytest (4 tests, no model needed)
./lint.sh         # ruff
./run.sh          # uvicorn on http://localhost:8000

From the frontend/ directory:

npm install
npm run dev       # http://localhost:5173 (proxies /api to :8000)

Option B — Docker Compose (everything in containers)

docker compose up --build
# Frontend: http://localhost:5173
# Backend:  http://localhost:8000  (Swagger at /docs)

Note: the model weights are not in the image. Either run python -m scripts.train once on the host (writes into backend/artifacts/, which is mounted as a volume) or drop a pre-trained model.onnx there.

Project layout

.
├── backend/                       # FastAPI service
│   ├── app/
│   │   ├── api/                   # routes + Pydantic schemas
│   │   ├── core/                  # configuration
│   │   └── ml/                    # ONNX + PyTorch backends (Strategy pattern)
│   ├── scripts/
│   │   ├── train.py               # fine-tune YOLO11-cls on PlantVillage
│   │   └── export_onnx.py         # re-export .pt -> .onnx
│   ├── tests/
│   ├── setup.{bat,sh}  test.{bat,sh}  lint.{bat,sh}  run.{bat,sh}
│   └── Dockerfile
├── frontend/                      # Vue 3 SPA
│   ├── src/
│   │   ├── components/            # Predictor, PredictionList, ModelStatus
│   │   ├── api/                   # axios client
│   │   ├── types/                 # TypeScript shapes
│   │   └── utils/                 # class-name formatting
│   ├── Dockerfile + nginx.conf
│   └── package.json
├── docker-compose.yml             # backend + frontend
├── .github/workflows/             # backend-ci + frontend-ci
└── README.md

API quick reference

Method Path Description
GET /health Liveness + model status
GET /model/info Model metadata (class names, imgsz, backend)
POST /detect Multipart upload of an image; returns top-K predictions

Full schema: http://localhost:8000/docs (auto-generated by FastAPI).

Training (optional)

cd backend
./setup.sh
./run.sh false    # don't start uvicorn; just install
.venv/Scripts/python.exe -m scripts.train --epochs 5 --imgsz 224 --batch 32 --device cpu
# or with GPU:  --device 0
# Artifacts land in backend/artifacts/best.pt + backend/artifacts/model.onnx

A 5-epoch CPU run on PlantVillage takes ~1-2 hours; a GPU run is ~10-15 minutes. The included pytest smoke tests do not require a trained model — they verify the app boots and returns proper 4xx/5xx.

What I learned

  • How to fine-tune a YOLO11-cls model on a custom dataset using the Ultralytics Python API and the hf: dataset prefix for Hugging Face Hub datasets.
  • How to export a model to ONNX and serve it without PyTorch at runtime (much smaller image, faster cold start).
  • How to design a backend-agnostic inference layer with a Strategy pattern (ONNX and PyTorch backends implement the same interface).
  • How to write smoke tests that don't need the heavy model weights (TestClient + app.state injection).

Next steps (if I had more time)

  • Add bounding-box detection by switching to YOLO11n (detection) on a dataset like PlantDoc or CottonWeedDet12.
  • Add Grad-CAM saliency maps so the user can see why the model predicted what it predicted.
  • Add a "upload to retrain" endpoint so field photos can improve the model over time.
  • Move inference to a GPU pod behind a queue (Celery / RQ).

License

MIT — see LICENSE.


🇧🇷 Versão em português

O que faz

  1. Treina um modelo YOLO11n-cls no PlantVillage (54k imagens, 38 classes, 14 culturas).
  2. Exporta os pesos pra ONNX, inferência rápida em CPU.
  3. Expõe uma API REST (/health, /model/info, POST /detect) que recebe uma imagem de folha e retorna top-K classes com confiança.
  4. Uma SPA Vue 3 permite arrastar-e-soltar a folha e ver as predições em lista limpa com barras de confiança.

Por que fiz

Estou me preparando pra Analista Desenvolvimento Web Jr numa AgTech (o stack público da Solinftec no GitHub mostra um fork do YOLOv5 pra detecção de pragas em campo, então este projeto espelha essa escolha em escala de portfólio). Eu queria um exemplo pequeno mas end-to-end que demonstrasse:

  • Sei treinar e exportar um modelo de visão, não só chamar API.
  • Sei construir uma API REST limpa com FastAPI + Pydantic.
  • Sei entregar um frontend Vue 3 usável.
  • Penso em deploy (ONNX, multi-stage Docker, CI).

Como rodar

Opção A — local com os scripts do venv (sem Docker):

# Da raiz do repo, em bash (WSL / git-bash / MSYS)
cd backend
./setup.sh        # cria .venv com Python 3.14 e instala deps
./test.sh         # pytest (4 testes, sem precisar de modelo)
./lint.sh         # ruff
./run.sh          # uvicorn em http://localhost:8000

Em frontend/:

npm install
npm run dev       # http://localhost:5173 (proxia /api para :8000)

Opção B — Docker Compose (tudo em containers):

docker compose up --build
# Frontend: http://localhost:5173
# Backend:  http://localhost:8000  (Swagger em /docs)

Os pesos do modelo não vão na imagem. Rode python -m scripts.train uma vez no host (gera em backend/artifacts/, montado como volume) ou coloque um model.onnx já treinado lá.

Endpoints da API

Método Path Descrição
GET /health Liveness + status do modelo
GET /model/info Metadados do modelo (classes, imgsz, backend)
POST /detect Upload multipart de imagem; retorna top-K predições

Schema completo: http://localhost:8000/docs.

Treinamento (opcional)

cd backend
./setup.sh
.venv/Scripts/python.exe -m scripts.train --epochs 5 --imgsz 224 --batch 32 --device cpu
# ou com GPU:  --device 0
# Artefatos em backend/artifacts/best.pt + backend/artifacts/model.onnx

CPU em 5 épocas no PlantVillage leva 1-2h; GPU leva 10-15 min. Os testes de smoke inclusos não precisam de modelo treinado.

O que aprendi

  • Como fazer fine-tuning de YOLO11-cls num dataset customizado usando a API Python do Ultralytics e o prefixo hf: pra datasets do Hugging Face.
  • Como exportar pra ONNX e servir sem PyTorch em runtime (imagem muito menor, cold start mais rápido).
  • Como desenhar uma camada de inferência backend-agnóstica com Strategy pattern (ONNX e PyTorch implementam a mesma interface).
  • Como escrever smoke tests que não precisam dos pesos do modelo (TestClient + app.state).

Próximos passos

  • Trocar pra detecção com bounding boxes usando YOLO11n num dataset tipo PlantDoc ou CottonWeedDet12.
  • Adicionar Grad-CAM pra explicar visualmente a predição.
  • Adicionar endpoint "upload pra retreinar" pra fotos de campo melhorarem o modelo ao longo do tempo.
  • Mover inferência pra um pod com GPU atrás de fila (Celery / RQ).

Licença

MIT — veja LICENSE.


Contributing

Issues e PRs são bem-vindos! Por favor leia CONTRIBUTING.md.

Author

Davi Roquedaviroque.luiz03@gmail.com · LinkedIn · GitHub

Built as a portfolio capstone while preparing for a Junior Web Developer role at an AgTech company (Solinftec — public job posting 4425371310).

About

🐛 PestDetector — full-stack plant disease & pest classification app (Python 3.14 + FastAPI + YOLO11 + ONNX + Vue 3). Portfolio capstone aligned with AgTech products (Solinftec, Syngenta).

Resources

License

Contributing

Stars

Watchers

Forks

Packages

 
 
 

Contributors