What I Built
My bachelor’s capstone combines a Laravel interface, a Flask prediction service and a TensorFlow classifier. I upgraded it to run on supported runtimes and measured its bundled model on the notebook’s held-out test images.
Bachelor’s degree capstone
A web application that sends maize leaf images to a convolutional neural network and stores predictions alongside editable disease recommendations. It runs locally on current runtimes and its bundled model is measured on the notebook’s held-out test images.
Problem
The project classifies maize leaf images through a web interface. It supports image uploads, prediction history and stored recommendation lookups. It is an academic prototype with no validated farm advisory use.
Role and scope
My bachelor’s capstone combines a Laravel interface, a Flask prediction service and a TensorFlow classifier. I upgraded it to run on supported runtimes and measured its bundled model on the notebook’s held-out test images.
Laravel 13 provides registration, login, private image uploads, per-user prediction history and administrator-edited disease-to-pesticide recommendations. A local end-to-end run exercises upload, prediction, access control and duplicate handling; password reset and the role screens are not exercised.
The classifier distinguishes Blight, Common Rust, Gray Leaf Spot and Healthy. The four model files are unchanged from the capstone: saved with TensorFlow 2.7.0, they run on TensorFlow 2.21.0 without retraining.
The application runs on the local machine only, on the loopback interface. No retraining, live deployment or field validation is part of the project. The private system-documentation PDF is not published.
Architecture
The local application. The notebook is separate evidence with no verified link to the bundled model.
Signed-in users upload a JPEG or PNG leaf image of up to 2 MB through Laravel. The notebook reads an existing image-folder dataset.
MySQL holds users, predictions keyed by image hash and recommendations; uploads stay in private storage behind an owner check. No user records or uploads are published.
Keras defines a convolutional classifier with image resizing and rescaling, convolution, batch normalization, pooling and a four-class output.
Flask accepts the image bytes, runs the model loaded at startup and returns a class name or a JSON error. Laravel displays the stored result.
Key decisions
The original Laravel posted a filesystem path that Flask read. Flask also reloaded the model for each request. I changed the boundary to a multipart upload and a model loaded once, so the two services share no filesystem.
I moved the interface to Laravel 13 and the service to TensorFlow 2.21 and kept the four model files byte-identical, so any measured result describes the capstone’s own model.
The notebook’s saved result does not identify the exported model, so I evaluated the bundled files on the same held-out images, once with the notebook’s loading pipeline and once through the Flask service.
The original notebook saves the checkpoint with the highest validation accuracy. Its training and validation subsets use different seeds, so overlap weakens that selection criterion.
Evidence
The repository holds the upgraded application, its setup and its limitations.
The evaluation script and the README results record the command, checks and per-class table.
The training notebook contains the saved dataset counts, architecture and test result.
The Flask endpoint and the end-to-end runner show the inference path and how it is checked.
Results and limits
Recall: the share of each class’s test images the model labels correctly.
Of the 172 Blight test images:
Source: README per-class table
Accuracy 0.7946 (499 of 628) and loss 2.1865 on the notebook’s test folder, with identical results in two runs. Through the Flask service, 501 of 628 predictions are correct. Source: the README model evaluation.
Blight recall is 0.3895: 67 of 172 Blight images are classified correctly and 92 are predicted as Common Rust or Gray Leaf Spot. Common Rust and Healthy recall are 1.0. Source: the per-class table.
The notebook’s saved accuracy of 0.8105 comes from the model after its last training epoch, while its checkpoint callback saves the best validation epoch; the bundled model does not reproduce it. Validation overlaps training. The images are public data; no field, agronomist or recommendation validation is claimed. See the README limitations.
Lessons
The saved split settings show why training and validation must share one partition definition. The test folder stays separate, so it remains a usable held-out set.
A notebook metric and an exported model are separate artifacts. Measuring the exported files on the same test images gives a different result from the one the notebook saved.
Overall accuracy hides that most Blight images are misclassified. Per-class recall shows where the model fails and what a recommendation built on it would get wrong.