A model that accepts a tensor is useful to another developer. A model that accepts a photo in a familiar chat interface is easier for someone else to try.
Crop Cure connects a grape-leaf classifier to WhatsApp. A user chooses a language, sends a photograph, and receives a response based on the predicted class. The project supports English, Hindi and Marathi response flows.
The workflow
| Step | Implementation |
|---|---|
| Receive a message | FastAPI and pywa_async handle the WhatsApp flow. |
| Prepare the image | Convert to RGB, resize, centre-crop and normalise. |
| Run inference | A custom PyTorch residual network with channel and spatial attention runs on the CPU. |
| Decide whether to answer | Compare the top softmax score with the configured threshold. |
| Return the response | Use the selected language and the predicted class. |
My work here spans the classifier integration and the surrounding application: getting an image from a message into the model, interpreting the output, and turning that output into a usable reply.
The model has four labels: black rot, esca, leaf blight and healthy. That is a deliberately narrow scope. It is not a general classifier for every crop or every possible leaf condition.
A threshold needs an honest description
The implementation uses a 0.98 confidence threshold. Predictions below it return Unclassified.
That number is not 98% accuracy. It is a threshold applied to a model output. A high softmax score can still be wrong, especially when the photograph differs from the data used to train the model. Lighting, background, camera distance and an unsupported plant all make the input harder to interpret.
The fallback gives the application a way to avoid returning a class for every image. Whether it rejects enough unsuitable images requires evaluation with representative photographs; the public repository does not establish field accuracy.
Where the prototype stops
The repository describes the project as under development and not actively maintained. It is best understood as a research prototype, rather than a deployed agricultural diagnostic service.
Language preferences currently live in an in-memory dictionary, so they do not survive a process restart. Inference also runs synchronously inside the message-handling path. If I continued the project, I would persist conversation state, move inference into a controlled worker path, and evaluate class-specific errors and rejection behaviour on a held-out field dataset.
The interesting engineering lesson is how much of the product sits around the model. The preprocessing contract, supported inputs, fallback behaviour and message flow all determine whether the prediction can be used sensibly.
Implementation details: model and preprocessing and WhatsApp application.