Skip to content

Latest commit

 

History

History
193 lines (145 loc) · 6.39 KB

File metadata and controls

193 lines (145 loc) · 6.39 KB

Building a Nextjs Web Application for the ML Model


Table of Contents


Overview

So far, we have successfully built the machine learning model using Python and Sckit-Learn, a simple API using Flask, and a web application using Flask. In this lesson, we will discuss an alternative way of building a hybrid Nextjs + Python web application using the same Flask API as the backend but with Nextjs as the frontend. During the workshop, we will discuss how this works in detail.

Getting Started

To get started, kindly follow the steps below:

  1. Run the command below to start a project using Vercel's Nextjs Flask starter. This will download the files and install all the packages required.
npx create-next-app nextjs-flask-app --example "https://github.com/vercel/examples/tree/main/python/nextjs-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. Update the requirements.txt file to the following:

Flask==2.3.3
scikit-learn==1.3.1
  1. Copy the model.pkl and vectorizer.pkl files in the root model/two directory to the newly created Nextjs app (app/nextjs-flask-app/model/ in my case).

  2. Now start the development server using the command below:

npm run dev

This will start the Flask server on http://127.0.0.1:5328 and Nextjs on http://localhost:3000.

How it Works

The Python Flask server is mapped into Nextjs from the /api/ directory. This is implemented using next.config.js rewrites, which maps any request to /api/:path* to the Flask API. So, Flask will receive the API request and return a response as usual, and the response can be handled in Nextjs as desired.

/** @type {import('next').NextConfig} */
const nextConfig = {
  rewrites: async () => {
    return [
      {
        source: '/api/:path*',
        destination:
          process.env.NODE_ENV === 'development'
            ? 'http://127.0.0.1:5328/api/:path*'
            : '/api/',
      },
    ]
  },
}

module.exports = nextConfig

Note

On localhost, the rewrite is made to the 127.0.0.1:5328 port, where the Flask server runs. While in production, the Flask server is hosted as Python serverless functions.


We will then add our Flask backend code to the /api/index.py file, create a /api/predict route and return the data as JSON. The response data will then be handled in the Nextjs frontend and displayed to the user.

from flask import Flask, request, redirect, url_for, jsonify
import pickle

# Create an instance of the Flask class
# with the name of the application’s modules
app = Flask(__name__, template_folder='templates')

# Create the / API route to return a welcome message
@app.route('/', methods=['GET'])
def main():
    return jsonify({
            "description": "Welcome to the MBPTI API!",
            "message": "Please use the form on the Nextjs frontend (http://localhost:3000)"
        })

# Create the /predict API route
@app.route('/api/predict', methods=['GET', 'POST'])
def predict():
    # Use pickle to load in vectorizer.
    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)

    if request.method == 'POST':
        name = request.form['name']
        country = request.form['country']
        message = request.form['message']

        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)"
        }

        prediction = model.predict(vectorizer.transform([message]))
        result = mbpti_types[prediction[0]]

    else:
        return(redirect(url_for('main')))

    return({
        "name": name,
        "country": country,
        "prediction": result,
    })

if __name__ == '__main__':
    app.run()

Finally, we will use a form to send the request using Fetch API and handle the response.

export default function Home() {
  const [predictionData, setPredictionData] = useState<PredictionData | null>(
    null
  );

  async function handleSubmit(event: FormEvent<HTMLFormElement>) {
    event.preventDefault();

    const formData = new FormData(event.currentTarget);
    await fetch("/api/predict", {
      method: "POST",
      body: formData,
    }).then(async (response) => {
      setPredictionData(await response.json());
    });
  }

  return (
    <main className="flex min-h-screen flex-col items-center justify-between p-24">
      <div className="relative flex place-items-center">
        {predictionData === null ? (
          <Form onSubmit={handleSubmit} />
        ) : (
          <Result {...predictionData} />
        )}
      </div>
      <Footer />
    </main>
  );
}

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 >>