Introduction

The topics for each of our (Aditya, Varun, Tucker) CPT projects collectively came to essentially stocks/business and cooking/food. So, we found a suitable dataset of ordered items from a bakery to combine those elements of business and food/cooking/baking, deciding that our ML model would determine a food order at the bakery (ex: “Bread”, “Coffee”, “Pastry”, etc.) based on the other variables in the dataset (exact military time, general time: “Afternoon/Morning”, and day of the week: “Weekend/Weekday”).

Because our dataset of ~20 thousand total rows/orders included nearly 1/4 “Coffee” as a food item, it was extremely common to get Coffee”” rather than any other item. Therefore, we made two separate Models, APIs, and frontend input fields to include both the normal (skewed by “Coffee”) dataset/CSV file, and another identitical input field that simply used a different Model, API, and dataset and different datset/CSV file with “Coffee” filtered out. Screenshots below.

Project Screenshots

Backend Code

Code - Original API (food.py):

from flask import Flask, jsonify, request
from flask_restful import Resource, Api
import pandas as pd
from model.foods import food
from flask import Flask, request, jsonify
import pandas as pd
import numpy as np
from sklearn.preprocessing import OneHotEncoder
from sklearn.ensemble import RandomForestClassifier
from flask_restful import Resource
from flask import Blueprint, jsonify, request 
from flask_restful import Api, Resource

food_api = Blueprint('food_api', __name__, url_prefix='/api/food')
api = Api(food_api)

class PredictItem(Resource):
    
    def __init__(self):
        self.model = food()  
    def post(self):
        try:
            # get JSON data from the request
            payload = request.get_json()
            print(payload)
            foodModel = food.get_instance()
            # Predict the item purchased from bakery
            response = foodModel.predict(payload)
            print(response)
            
            return jsonify(response)

        except Exception as e:
            return jsonify({'error': str(e)})
        
api.add_resource(PredictItem, '/predict')

Code - Original Model (foods.py):

import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn.preprocessing import OneHotEncoder
# Import the required libraries for the TitanicModel class
from sklearn.tree import DecisionTreeClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import OneHotEncoder
import pandas as pd
import numpy as np
import seaborn as sns

class food:
    _instance = None
    """ _init_(self): creates changeable instances and defines variables used for prediction through self.features and defines target variable to predict through self.target"""
    def __init__(self):
        self.model = None
        self.dt = None
        self.features = ['Hour', 'DayPart', 'DayType']  # Features for prediction
        self.target = 'Items'  # Target variable to predict
        self.data = pd.read_csv('filtered_data.csv')
        
    def _clean(self):
        """_clean(self) Converts data from the csv file into more readable form for ml. In this case, it reads the DayPart column and converts """
        self.data['DayPart'] = self.data['DayPart'].apply(lambda x: 1 if x == 'Morning' else 0)
        self.data['DayType'] = self.data['DayType'].apply(lambda x: 1 if x == 'Weekend' else 0)
        self.data['Hour'] = pd.to_datetime(self.data['Time'], format='%H:%M:%S').dt.hour
        
        
    def _train(self):
        X = self.data[self.features]  # Features
        y = self.data[self.target]  # Target variable
        
        # Train a logistic regression model
        self.model = LogisticRegression(max_iter=1000)
        self.model.fit(X, y)
        
        # Train a decision tree classifier
        self.dt = DecisionTreeClassifier()
        self.dt.fit(X, y)
        
    @classmethod
    def get_instance(cls):
        """Gets, and conditionally cleans and builds, the singleton instance of the Food model."""
        if cls._instance is None:
            cls._instance = cls()
            cls._instance._clean()
            cls._instance._train()
        return cls._instance
    
    def predict(self, payload):
        """Predict the item based on the given features. It is taken from the json input and is cleaned to match previous code so it can be used to predict"""
        # Convert input to DataFrame
        payload_df = pd.DataFrame(payload, index=[0])
        # Convert categorical variables to binary
        payload_df['DayPart'] = payload_df['DayPart'].apply(lambda x: 1 if x == 'Morning' else 0)
        payload_df['DayType'] = payload_df['DayType'].apply(lambda x: 1 if x == 'Weekend' else 0)
        payload_df['Hour'] = pd.to_datetime(payload_df['Time'], format='%H:%M:%S').dt.hour
        #payload_df['Hour'] = pd.to_datetime(payload_df['Time']).dt.hour
        # Predict item using the logistic regression model
        #item = self.model.predict(payload_df)
        item = self.model.predict(payload_df[self.features]) 
        #return {'item': item}
        return {'item': item.tolist()} 
    def feature_weights(self):
        """Get the feature weights
        The weights represent the relative importance of each feature in the prediction model.

        Returns:
            dictionary: contains each feature as a key and its weight of importance as a value
        """
        # extract the feature importances from the decision tree model
        importances = self.dt.feature_importances_
        # return the feature importances as a dictionary, using dictionary comprehension
        return {feature: importance for feature, importance in zip(self.features, importances)}
def initfood():
    food.get_instance()

Code/Data - Modifed/Added Segments in main.py (added model and API and init):

# setup APIs
from api.covid import covid_api # Blueprint import api definition
from api.joke import joke_api # Blueprint import api definition
from api.user import user_api # Blueprint import api definition
from api.player import player_api
from api.titanic import titanic_api
from api.food import food_api
from api.bakery import bakery_api
# database migrations
from model.users import initUsers
from model.players import initPlayers
from model.foods import initfood 
from model.bakeries import initbakery

# setup App pages
from projects.projects import app_projects # Blueprint directory import projects definition


# Initialize the SQLAlchemy object to work with the Flask app instance
db.init_app(app)

# register URIs
app.register_blueprint(joke_api) # register api routes
app.register_blueprint(covid_api) # register api routes
app.register_blueprint(user_api) # register api routes
app.register_blueprint(player_api)
app.register_blueprint(app_projects) # register app pages
app.register_blueprint(titanic_api)
app.register_blueprint(food_api)
app.register_blueprint(bakery_api)
# Define a command to generate data
@custom_cli.command('generate_data')
def generate_data():
    initUsers()
    initPlayers()
    initfood()
    initbakery()

Code - Frontend:

---
permalink: /bakery
layout: nav_ml
---

<html>
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Bakery ML</title>
        <link rel="stylesheet" href="bakery-style.css"> 
    </head>
    <body>
        <div class="container">
            <form class="signUp">
                <h3>Bakery Ml</h3>
                <p id="resultx" aria-hidden="true"></p>
                    <select id="TimeOfDay">
                        <option disabled selected>Time of Day</option>
                        <option value="Morning">Morning</option>
                        <option value="Afternoon">Afternoon</option>
                    </select> 
                    <select id="DayOfWeek">
                        <option disabled selected>Day of Week</option>
                        <option value="Weekend">Weekend</option>
                        <option value="Weekday">Weekday</option>
                    </select>
                    <input id="time" type="text" placeholder="Time" onfocus="(this.type='time')">
                <button class="form-btn sx log-in" type="button">Switch</button>
                <button class="form-btn dx"  type="button"  onclick="extra()">Predict</button>
            </form>
            <form class="signIn">
                <h3>
                    No Coffee Ml 
                </h3>
                <p id="resultx1" aria-hidden="true"></p>
                    <p id="resultx" aria-hidden="true"></p>
                    <select id="TimeOfDay1">
                        <option disabled selected>Time of Day</option>
                        <option value="Morning">Morning</option>
                        <option value="Afternoon">Afternoon</option>
                    </select> 
                    <select id="DayOfWeek1">
                        <option disabled selected>Day of Week</option>
                        <option value="Weekend">Weekend</option>
                        <option value="Weekday">Weekday</option>
                    </select>
                    <input id="time1" type="text" placeholder="Time" onfocus="(this.type='time')">
                <button class="form-btn sx back" type="button">Switch</button>
                <button class="form-btn dx"  type="button"  onclick="extrax()">Predict</button>
            </form>
        </div>
    </body>
</html>
<script>
    document.querySelector(".log-in").addEventListener("click", function() {
        document.querySelector(".signIn").classList.add("active-dx");
        document.querySelector(".signUp").classList.add("inactive-sx");
        document.querySelector(".signUp").classList.remove("active-sx");
        document.querySelector(".signIn").classList.remove("inactive-dx");
    });
    document.querySelector(".back").addEventListener("click", function() {
        document.querySelector(".signUp").classList.add("active-sx");
        document.querySelector(".signIn").classList.add("inactive-dx");
        document.querySelector(".signIn").classList.remove("active-dx");
        document.querySelector(".signUp").classList.remove("inactive-sx");
    });
</script>
<script>
    function extra() {
            var dom = document.getElementById('resultx');
            var TOD = document.getElementById('TimeOfDay').value;
            var DOW = document.getElementById('DayOfWeek').value;
            var time = document.getElementById('time');
            var enteredTime = time.value + ":00"
            var payload = {
                Time: enteredTime,
                DayPart: TOD,
                DayType: DOW,
            };
            var url = 'http://127.0.0.1:8086/api/food/predict'
            var json = JSON.stringify(payload);
            console.log(json)
            const authOptions = {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: json,
                credentials: 'include'
            };
            fetch(url, authOptions)
                .then(response => {
                    if (!response.ok) {
                        throw new Error(`HTTP error! Status: ${response.status}`);
                    }
                    return response.json();
                })
                .then(data => {
                    console.log('success', data);
                    dom.innerText = "Predicted Item: " + data["item"]
                // Display in alert
                    alert("Predicted Item: " + data["item"]);
                })                
                .catch(error => {
                    console.error('error', error);
                    // Handle error
                    dom.innerText = "Error occurred";
                });
        }
    function extrax() {
            var dom = document.getElementById('resultx1');
            var TOD = document.getElementById('TimeOfDay1').value;
            var DOW = document.getElementById('DayOfWeek1').value;
            var time = document.getElementById('time1');
            var enteredTime = time.value + ":00"
            var payload = {
                Time: enteredTime,
                DayPart: TOD,
                DayType: DOW,
            };
            var url = 'http://127.0.0.1:8086/api/bakery/predict'
            var json = JSON.stringify(payload);
            console.log(json)
            const authOptions = {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: json,
                credentials: 'include'
            };
            fetch(url, authOptions)
                .then(response => {
                    if (!response.ok) {
                        throw new Error(`HTTP error! Status: ${response.status}`);
                    }
                    return response.json();
                })
                .then(data => {
                    console.log('success', data);
                    dom.innerText = "Predicted Item: " + data["item"]
                // Display in alert
                    alert("Predicted Item: " + data["item"]);
                })                
                .catch(error => {
                    console.error('error', error);
                    // Handle error
                    dom.innerText = "Error occurred";
                });
        }
</script>