Skip to content

Latest commit

 

History

History
205 lines (152 loc) · 8.21 KB

File metadata and controls

205 lines (152 loc) · 8.21 KB

Building an API for the ML Model


Table of Contents


Overview

In the last lesson, we serilized the pre-trained model using Pickle and saved them in the ./model directory. Now, we're getting closer to deploying the model to the web for usage by end users. But before then, we need to build an application with an interface for users to access the model.

The end presentation layer of your machine learning model will vary based on the project's goals and model type. You can build a web, mobile, or embedded system (IoT) application (Raspberry Pi, Arduino, with cameras, speakers, etc.).

We will build an API and web application for this workshop to consume the API. In this lesson, we will discuss how to do that with Flask, HTML, TailwindCSS, and Javascript.

Building the API

I'd assume you already installed all the required packages from the prerequisites section. The following steps outline the overview of the processes required to build an API with Flask:

  1. Create a .env file and add FLASK_DEBUG=1. This will allow us to run Flask in debug mode and automatically reload the server when changes are made to the code.

  2. Create a new directory with the folder structure below (I did mine in app/flask-api):

├── model
├── templates
    ├── main.html
├── app.py
├── .env

  1. Copy the model.pkl and vectorizer.pkl files in the root model/two directory to the newly created directory (app/flask-api/model in my case).

  2. In the main.html, add the markup below (using TailwindCSS for styling). This is just a basic page to render quick instructions on how to use the API.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>MBPTI Personality Test Checker API</title>
    <link
      rel="shortcut icon"
      type="image/png"
      href="https://bolajiayodeji.com/favicon.png"
    />
    <script src="https://cdn.tailwindcss.com"></script>
  </head>

  <main class="flex min-h-screen flex-col items-center justify-between lg:p-24">
    <div class="p-12 border border-black rounded-lg text-center">
      <p class="mb-8">
        Use the <b>/predict</b> API route to make a GET request and pass in the
        data with a <b>?message=</b> parmeter like so:
      </p>
      <a
        class="text-gray-700 text-center"
        href="/predict?message=The last time you considered giving up on your dreams but didn't… what kept you going?"
        >http://127.0.0.1:5000/predict?message=The last time you considered
        giving up on your dreams but didn't… what kept you going?</a
      >
    </div>
  </main>
</html>
  1. In the app.py file, add the code below to import the required packages, load the pre-trained model, and create a new route with the desired request methods.
from flask import Flask, request, render_template, jsonify
import pickle

# Create an instance of the Flask class
# With the name of the application’s modules
# This way Flask knows where to look for templates, static files, etc.
app = Flask(__name__, template_folder='templates')

# Create the / API route and render the root HTML page
@app.route('/', methods=['GET'])
def main():
    return(render_template('main.html'))

# Create the /predict API route
@app.route('/predict', methods=['GET', 'POST'])
def predict():
    # Use pickle to load in vectorizer
    # with open() is a Python function that opens a file object
    # rb means read in binary
    # Learn more: https://docs.python.org/3/tutorial/inputoutput.html#reading-and-writing-files
    with open(f'./model/vectorizer.pkl', 'rb') as f:
        vectorizer = pickle.load(f)

    # Use pickle to load in the pre-trained model
    with open(f'./model/model.pkl', 'rb') as f:
        model = pickle.load(f)
    
    # Get the message from the API request (message parameter)
    message = request.args.get('message')

    if request.method == 'GET' and message != None:

        # A Python dictionary to store the 16 personality types
        # Based on the encoded values in the dataset
        mbpti_types = {
            0: "ENFJ (Extroversion, Intuition, Feeling, Judging)",
            1: "ENFP (Extroversion, Intuition, Feeling, Perceiving)",
            2: "ENTJ (Extroversion, Intuition, Thinking, Judging)",
            3: "ENTP (Extroversion, Intuition, Thinking, Perceiving)",
            4: "ESFJ (Extroversion, Sensing, Feeling, Judging)",
            5: "ESFP (Extroversion, Sensing, Feeling, Perceiving)",
            6: "ESTJ (Extroversion, Sensing, Thinking, Judging)",
            7: "ESTP (Extroversion, Sensing, Thinking, Perceiving)",
            8: "INFJ (Introversion, Intuition, Feeling, Judging)",
            9: "INFP (Introversion, Intuition, Feeling, Perceiving)",
            10: "INTJ (Introversion, Intuition, Thinking, Judging)",
            11: "INTP (Introversion, Intuition, Thinking, Perceiving)",
            12: "ISFJ (Introversion, Sensing, Feeling, Judging)",
            13: "ISFP (Introversion, Sensing, Feeling, Perceiving)",
            14: "ISTJ (Introversion, Sensing, Thinking, Judging)",
            15: "ISTP (Introversion, Sensing, Thinking, Perceiving)"
            }

        # Vectorize the passed messaage and make prediction
        prediction = model.predict(vectorizer.transform([message]))

        # The result is an array containing the predicted personality type number (e.g, [6])
        # Get the prediction text using the mbpti_types dictionary above
        # You can do this automatically by inverting the result
        # Like we did in the notebook using LabelEncoder().inverse_transform()
        # But you will need to fit the encoder first
        # To avoid working with the dataset again here, the mbpti_types dictionary above will suffice
        result = mbpti_types[prediction[0]]

        # Return the result as a JSON response
        data = {
            "message": message,
            "prediction": result
        }
        return jsonify(data)
    
    else :
        # Return an error message if:
        # no valid message parameter was provided
        # or the request method is not GET (e.g, POST)
        # Other request methods will return a different 405 error
        data = {
            "code": 400,
            "description": "Bad Request. No message was provided.",
            "message": "Use the message parameter to make a GET request."
        }
        return jsonify(data), 400

# Run the app
if __name__ == '__main__':
    app.run()
  1. Now, use the command flask run to start the Flask server on http://127.0.0.1:5000.

  1. If you head to http://127.0.0.1:5000/predict, you will get the error:

  1. If you pass a ?message= parameter to the URL (something like http://127.0.0.1:5000/predict?message=The last time you considered giving up on your dreams but didn't… what kept you going?), you will get the prediction result as a JSON response:

That's it! We will discuss more about the process during the workshop.

Testing the API with Postman

If you've installed Postman, you can test the API easily with either the Desktop APP or VSCode Extension.

Now, we can use this API in our web application. After deploying the API, we can even use the API in other types of applications, too.


Thank you for coming this far; you've done well 👏🏾. Please open a new GitHub discussion using the links below and let me know your thoughts about this lesson or any issues you're experiencing.

Share Feedback | Ask Question


<< previous lesson | next lesson >>