This repository contains a simple Flask web application that predicts wine quality from chemical properties entered by the user through a browser form.
The project combines three pieces:
- A trained machine learning model saved as
model.pkl - A Flask backend in
app.py - A frontend form in
index.html
The overall idea is straightforward: the user enters 11 wine features, the Flask app converts those values into a numeric array, the trained model makes a prediction, and the result is shown back on the page.
app.py: Flask application and prediction logicindex.html: user interface for collecting feature values and displaying the predictionmodel.pkl: trained machine learning model used for inference
The purpose of this project is to make a machine learning model usable through a web interface instead of only from a notebook or Python script.
From a developer point of view, this repo turns a saved classification model into a small deployable app.
This project uses:
- Python
- Flask
- NumPy
- Pickle
- scikit-learn
- HTML + CSS
The application flow is:
- Flask starts the web server.
- The root route loads the input form.
- The user enters 11 wine-related values.
- The form sends those values to the
/predictroute usingPOST. - Flask reads the form values from
request.form. - The values are converted from strings to
float. - The values are wrapped into a NumPy-compatible 2D input shape.
- The pickled model predicts the wine quality class.
- The prediction is sent back to the same page and displayed to the user.
The backend logic lives in app.py.
from flask import Flask, request, render_template
import pickle
import numpy as npWhy they are used:
Flask: creates the web apprequest: reads submitted form valuesrender_template: renders the HTML pagepickle: loads the trained model from disknumpy: formats the input for model prediction
app = Flask(__name__)This initializes the application object that defines routes and runs the server.
model = pickle.load(open('model.pkl', 'rb'))This loads the saved machine learning model into memory once, when the application starts.
@app.route('/')
def home():
return render_template('index.html')This route serves the main page containing the input form.
@app.route('/predict', methods=['POST'])
def predict():
try:
input_features = [float(x) for x in request.form.values()]
final_features = [np.array(input_features)]
prediction = model.predict(final_features)
return render_template('index.html', prediction_text=f"Prediction Result: {prediction[0]}")
except:
return render_template('index.html', prediction_text="Error: Please enter valid numbers")This is the main inference workflow.
What happens inside it:
- Read all submitted values from the form.
- Convert each value into a floating-point number.
- Put the features into a single row so the model receives the shape it expects.
- Call
model.predict(...). - Render the same page again with the prediction result inserted.
- If conversion fails, show an error message instead of crashing.
if __name__ == "__main__":
app.run(debug=True)This starts the Flask development server locally.
The user interface lives in index.html.
- A title:
Wine Quality Predictor - A short instruction line
- A form with 11 inputs
- A submit button
- A result section that displays the prediction returned by Flask
The form collects these 11 values:
- Fixed Acidity
- Volatile Acidity
- Citric Acid
- Residual Sugar
- Chlorides
- Free Sulfur Dioxide
- Total Sulfur Dioxide
- Density
- pH
- Sulphates
- Alcohol
These align with the features stored in the trained model.
The page uses inline CSS and includes:
- a full-screen gradient background
- a centered glassmorphism-style card
- a two-column input grid
- a styled prediction button
- a colored result section for the returned output
This makes the project more user-friendly than a plain HTML form while keeping the frontend lightweight.
The saved model in model.pkl is:
RandomForestClassifiern_estimators = 100- trained for
11input features - output classes:
0and1
The model expects these feature names in order:
fixed acidityvolatile aciditycitric acidresidual sugarchloridesfree sulfur dioxidetotal sulfur dioxidedensitypHsulphatesalcohol
From the saved metadata, this is a binary classification model, so the prediction result shown in the app is a class label rather than a continuous quality score.
Here is the full workflow as a developer would describe it:
A machine learning model was trained separately and exported into model.pkl using Pickle.
When app.py starts, Flask initializes the app and loads the trained model into memory.
The user opens the homepage and enters 11 numerical values describing the wine sample.
The backend converts those values into the numeric structure expected by the model and generates a prediction.
Flask sends the prediction back into the HTML template so the result appears on the same page.
- Clean beginner-friendly Flask structure
- Uses a real trained machine learning model in a web app
- Simple user workflow
- Good separation of roles between model, backend, and UI
- Friendly interface for quick manual testing
The code uses render_template('index.html'), which means Flask normally expects the HTML file inside a templates/ folder.
At the moment, index.html is stored in the project root. Unless Flask is configured with a custom template folder, the file should usually be moved to:
templates/index.html
The prediction route uses a plain except: block. This prevents crashes, which is helpful for beginners, but it also hides the exact error.
A stronger production version would catch specific exceptions and log them.
The inputs are currently plain text fields. The app would be more robust with:
type="number"stepvalues for decimals- required field validation
- range checks for realistic chemistry values
The model outputs 0 or 1, but the interface does not explain what those classes mean. It would be better to show a more readable result such as:
Good Quality WineNot Good Quality Wine
When reading model.pkl, scikit-learn reports that the model was saved with version 1.6.1 and loaded under version 1.7.2.
That does not always break the app, but it is worth documenting because pickled scikit-learn models are version-sensitive.
- Install the required packages:
pip install flask numpy scikit-learn-
Make sure
model.pklis in the same directory asapp.py. -
Place
index.htmlinside atemplates/folder if you want Flask's default template loading to work correctly.
Example structure:
wine-quality-prediction/
|-- app.py
|-- model.pkl
|-- templates/
| |-- index.html
- Start the app:
python app.py- Open the local Flask URL in your browser, usually:
http://127.0.0.1:5000/
This project demonstrates:
- Flask web application development
- HTML form handling
- Machine learning model deployment
- Model loading with Pickle
- NumPy-based input formatting
- Classification prediction workflow
- Frontend and backend integration
- Basic exception handling in a web app
If I were continuing this repo as the developer, I would improve it in this order:
- move
index.htmlintotemplates/ - replace text inputs with numeric inputs and validation
- map prediction labels
0/1to human-readable quality messages - add a
requirements.txt - show prediction probabilities with
predict_proba()if useful - separate CSS into a static stylesheet
- add logging and more specific error handling
- document how the model was trained
This repository is a small machine-learning deployment project that wraps a trained RandomForestClassifier inside a Flask web app.
The app takes 11 wine chemistry features from the user, sends them to the backend, runs the prediction through the saved model, and displays the result in a simple browser interface. It is a solid beginner project for understanding how a trained model moves from Python code into an interactive web application.