Lecture 25 - Deploying Projects as Web Applications

View notebook on Github Open In Collab

25.1 Introduction to Web APIs for Model Serving

After a predictive model for a Data Science (DS) project is developed, the next steps in the project life cycle include deploying the model and serving the model to the end-users. One approach to serving the model is via a web API where the end-users can submit requests to query the model, and obtain the model’s predictions as responses to their queries.

In general, an API (Application Programming Interface) enables software applications to communicate with each other and exchange data. In the context of web APIs, the terms client and server are typically used to refer to the two main components that are involved in the communication between software applications over the web. The client is typically a front-end application that runs in a web browser and allows to access data or services from the server. The client sends a request to the server, usually in the form of an HTTP request. The server is the application that receives and processes requests from clients. The server performs actions based on the requests, and sends a response back to the client. When a response is received from the server, the client presents the data to the end-users and/or it may take other actions based on the response from the server.

257b14e6b06f45a0a7954356bb8cb592

Figure: Web API. Source: [4].

An example of usage of a web API in Data Science is for accessing predictions from a model that is deployed on a server. The end-user interacts with a front-end application that runs in a web browser and submits a request to initiate an API call (e.g., submit an image for classification or submit tabular data inputs for classification). The API calls the server to obtain predictions from the model. After the model makes the prediction, the API transfers the prediction to the end-user in the form of JSON, XML, CSV, or another format.

Similarly, another use of web APIs in Data Science is for accessing data from a database that is hosted on a server, and afterward using the retrieved data to train a predictive model.

25.1.1 REST Architecture

Two common approaches for building web APIs are SOAP (Service Object Access Protocol) and REST (REpresentational State Transfer). Whereas SOAP is a protocol for communication between computer systems, REST is an architecture that defines a set of constraints for communication over a network and promotes simplicity, scalability, and reliability. Because of that, REST has been very popular, since it introduces guidelines regarding the architecture of an API, instead of defining rules of specifications for the data exchange.

REST (REpresentational State Transfer) defines the following architectural constraints:

  • Stateless: The server won’t maintain any state between requests from the client, and every request must contain all necessary information. I.e., the server cannot use information from previous requests by the client.

  • Client-server design: The client and server must be decoupled from each other. The decoupling helps them to evolve independently.

  • Cacheable: The response from the server should be cacheable, and it can be reused later by the client, if needed.

  • Uniform interface: The data transfer from the server to the client will be in a standardized format, instead of a format that is specific to one application.

  • Layered system: The client may access the resources on the server indirectly through other layers. Also, the server can have multiple layers, such as security, application, business logic, and these layers must remain invisible to the client.

  • Code on demand: The client may extend functionalities by downloading code blocks from the server.

An API that adheres to the REST guidelines is referred to as RESTful API or simply REST API.

RESTful APIs provide access to web services through public web URLs, referred to as request endpoints. The client sends an HTTP request to the specific URL, and the RESTful API uses HTTP methods to manage the resources in the web service. Although there are many HTTP methods, the most commonly used methods with RESTful APIs include: GET (retrieve resources), POST (create a new resource), PUT (update an existing resource),PATCH (partially update an existing resource), and DELETE (delete a resource).

25.1.2 RESTful APIs

RESTful APIs can be developed in different programming languages. Examples of libraries include Node.js in Javascript, Roda and Sinatra in Ruby, Spring Boot in Java, etc.

In Python, the most popular libraries for developing RESTful APIs are Flask, Fast API, and Django.

Flask is a micro framework for developing RESTful APIs, which means that it is lightweight and provides the basic components for serving predictive models as web services. Flask is the easiest to learn and use in comparison to the other frameworks, and it is known for its simplicity and flexibility. However, it also has limitations in terms of functionality, since it is designed for low-volume APIs, and does not scale well to large applications. Also, Flask is a general-purpose web framework and may require importing additional libraries for specific functionalities.

Fast API is also a lightweight framework, but it is designed specifically for building web APIs quickly and efficiently. Fast API was introduced in 2018 and it is a newer framework, but it has quickly gained popularity among developers. Its unique characteristic is its speed, as it is the fastest Python framework. FastAPI is explicitly designed for building APIs, and offers many features for automating the building of APIs.

Django is a full-stack web framework, that has many built-in features and a specific project structure. This makes it more difficult to learn than Flask and Fast API. On the other hand, Django is a powerful framework that has been used in many large-scale projects as it offers various features for building APIs. This is considered advantageous by developers who want a more structured framework or who prefer a comprehensive solution without relying on many third-party packages.

There are also other similar Python libraries for developing RESTful APIs. As well as, numerous frameworks for developing RESTful APIs as cloud services are available by the cloud providers such as Amazon SageMaker, Azure ML, Google Cloud ML, IBM Watson Cloud, and others. These cloud frameworks provide access to pretrained models, deployment of custom models, and allow easy integration of predictive models into users’ applications.

In this lecture we will demonstrate building a web API for Data Science projects with Flask, due to its ease of use.

25.2 Deploying a Model for Iris Flowers Classification

This section was inspired by the article Deploying Machine Learning Models using Flask.

The goal is to deploy a simple Machine Learning model for classification of the Iris dataset, which we used in Lecture 13. Recall that the dataset consists of measurements of three different species of irises:

  1. Iris Setosa

  2. Iris Versicolour

  3. Iris Virginica

Each data point has 4 features, which include:

  1. Sepal length in cm

  2. Sepal width in cm

  3. Petal length in cm

  4. Petal width in cm

Let’s load the dataset using Pandas, and display the dataframe.

[1]:
# Importing libraries
import pandas as pd
import numpy as np
from sklearn.linear_model import LogisticRegression
from sklearn.preprocessing import LabelEncoder

import warnings
warnings.filterwarnings('ignore')

# Load the dataset
data = pd.read_csv('Iris-API/iris.csv')
[2]:
data
[2]:
sepal.length sepal.width petal.length petal.width variety
0 5.1 3.5 1.4 0.2 Setosa
1 4.9 3.0 1.4 0.2 Setosa
2 4.7 3.2 1.3 0.2 Setosa
3 4.6 3.1 1.5 0.2 Setosa
4 5.0 3.6 1.4 0.2 Setosa
... ... ... ... ... ...
145 6.7 3.0 5.2 2.3 Virginica
146 6.3 2.5 5.0 1.9 Virginica
147 6.5 3.0 5.2 2.0 Virginica
148 6.2 3.4 5.4 2.3 Virginica
149 5.9 3.0 5.1 1.8 Virginica

150 rows × 5 columns

In the dataframe, the variety column contains the target labels. First, we will convert the labels from categorical values to numerical values by applying the scikit-learn LabelEncoder.

[3]:
# Convert the label column into ordinal format
label_feature = data[['variety']]
label_encoder = LabelEncoder()
label_encoded = label_encoder.fit_transform(label_feature)
data['variety'] = pd.DataFrame(label_encoded, columns=label_feature.columns, index=label_feature.index)

data
[3]:
sepal.length sepal.width petal.length petal.width variety
0 5.1 3.5 1.4 0.2 0
1 4.9 3.0 1.4 0.2 0
2 4.7 3.2 1.3 0.2 0
3 4.6 3.1 1.5 0.2 0
4 5.0 3.6 1.4 0.2 0
... ... ... ... ... ...
145 6.7 3.0 5.2 2.3 2
146 6.3 2.5 5.0 1.9 2
147 6.5 3.0 5.2 2.0 2
148 6.2 3.4 5.4 2.3 2
149 5.9 3.0 5.1 1.8 2

150 rows × 5 columns

25.2.1 Model Training and Prediction

Let’s extract the training features from the dataframe into variable X and the training labels into variable y.

In the following cell, we use a Logistic Regression model from scikit-learn to train a classification model.

[4]:
# Extract the features X and target y variables
X = data.drop(['variety'], axis=1)
y = data['variety']
[5]:
# Train a Logistic Regression model
logreg_model = LogisticRegression()
logreg_model.fit(X, y)
[5]:
LogisticRegression()
In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook.
On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.

Finally, let’s define a function classify that takes 4 input arguments, and predicts the class of the iris flowers. The four inputs a, b, c, and d correspond to the sepal length and width, and petal length and width. The ‘classify’ function first converts the inputs to a numpy array, and reshapes the array to represent a batch with 1 data instance. Afterward, the trained Logistic Regression classifier is used to predict the variety of an iris flower.

[6]:
# Predict the iris class based on inputs a, b, c, d
def classify(a, b, c, d):
    arr = np.array([a, b, c, d], dtype=np.float64) # Convert to numpy array
    query = arr.reshape(1, -1) # Reshape the array
    prediction = logreg_model.predict(query)[0] # Make a prediction
    variety = variety_mappings[prediction] # Map the prediction to iris variety
    return variety # Return the iris variety

# Dictionary containing the mapping
variety_mappings = {0: 'Setosa', 1: 'Versicolor', 2: 'Virginica'}

To make sure that the function classify works, in the following cell a set of four input values is passed to classify. We can see that the output is the iris target label, as expected.

[7]:
classify(1.0, 1.0, 2.0, 2.0)
[7]:
'Setosa'

The above code for classifying iris flowers is saved as model.py under the directory IRIS-API/model.py.

25.2.2 Creating an HTML Webpage

Next, we will build the following simple HTML page to accept inputs from the end-users.

a58113f9ecfc4a4687fec1946afe2a38

Figure: Home webpage to accept inputs from end-users.

The HTML code for the input form is shown below, containing head and body sections. The head defines metadata and styles with the tags <meta> and <style>.

The body contains <div> tags with class='field' for each of the 4 inputs: sepal/petal lengths/widths. Each input tag has class="input", and type="number" to accept numerical values from the end-users. All the <div> tags are enclosed within a form with action="predict" and method="GET". The GET method is used to transport the data from the HTML form to the Flask app.

The HTML code is saved as index.html file under the directory Iris-API/templates/index.html.

10f126ed52f94c4c90757b0be8739aad e56f02097e784e66945539d6177eb3b2

Figure: Head and Body of the home HTML page.

25.2.3 Creating a Flask App

Next, we will use the Flask framework to deploy the Machine Learning model locally. Note that Flask is not typically run from Jupyter Notebooks, and therefore we will save the code from this section as a Python script app.py and we will run the script from the command line in a terminal.

Let’s first import the model module that we created in the previous section. Next, we import the flask library, as well as the related libraries request (for accessing data sent with HTTP requests), and render_template (for generating HTML pages by combining templates with data).

Building the Flask server begins with creating an instance of the Flask application, which we assigned to the name app. The argument __name__ associates the instance with the name of the current module, and Flask uses it to locate the root path of the application. The template_folder argument specifies the directory where Flask will look for HTML templates for rendering the webpages for input parameters and model output.

[ ]:
import model # Import the python file containing the ML model
from flask import Flask, request, render_template # Import flask libraries

# Initialize the flask class and specify the templates directory
app = Flask(__name__, template_folder="templates")

In Flask, routes define the actions that the web API should take when a specific URL is accessed by the end-user in a web browser. Routes in Flask are defined using the @app.route decorator. This decorator is associated with a function that specifies the actions to a particular URL. In this example, we will define two routes: route '/' that corresponds to the home page where the end-user enters the input values for iris flowers, and route '/predict' that sends the input values to the model for inference and displays the model’s prediction.

Therefore, in the next cell we set the default route of the Flask application using @app.route('/'). The route '/' in Flask is the root or home route. When we access the root URL of the application (e.g., http://127.0.01:5000/), the function index_view will be called, and it will render the HTML page 'index.html' in the web browser. The render_template() is a Flask function that takes an HTML file as an argument and processes it for sending as the response to the end-user’s request. This is a common way of creating a simple home page for a web API.

[ ]:
# Default route set as 'index'
@app.route('/')
def index_view():
    return render_template('index.html') # Render index.html

Similarly, in the next cell we create a separate Flask route for the Machine Learning model, that accepts inputs for the model, makes a prediction, and renders the results in a webpage.

Specifically, we use the /predict route with the method 'GET'. This route will retrieve the data from the fields on the index.html webpage through a GET request. For this purpose, we use request.args.get() to extract the data from each of the input fields in the form, using the name attributes for the petal and sepal dimensions.

The retrieved inputs sepal_len, sepal_wid, petal_len, petal_wid are then passed to the classify() method of the Machine Learning model to make a prediction about the variety of the iris flower. The result from the model’s prediction is assigned to the variable variety.

The variable variety is next passed to the HTML file output.html to render the predicted variety of flowers and display it in a new webpage. For this, we used the function render_template(filename, arguments) where we specified the HTML file along with the predicted variable variety.

Finally, if an exception occurs during the execution of the try block (e.g., an error in model prediction or input parameters), the message 'Error' will be returned.

[ ]:
# Route 'predict' accepts GET request
@app.route('/predict', methods=['GET'])
def predict_class():
    try:
        sepal_len = request.args.get('slen') # Get parameters for sepal length
        sepal_wid = request.args.get('swid') # Get parameters for sepal width
        petal_len = request.args.get('plen') # Get parameters for petal length
        petal_wid = request.args.get('pwid') # Get parameters for petal width

        # Get the output from the classification model
        variety = model.classify(sepal_len, sepal_wid, petal_len, petal_wid)

        # Render the output in new HTML page
        return render_template('output.html', variety=variety)
    except:
        return 'Error'

To run the Flask webserver, we use the app.run() method as shown below. The debug=True argument enables the debug mode, which provides additional information in case of errors.

[ ]:
# Run the Flask server
if(__name__=='__main__'):
    app.run(debug=True)

The code for Flask is saved as app.py under the directory IRIS-API/app.py. We will use it later to run the web application.

25.2.4 Output Webpage

We need to also create another even simpler HTML page to display the output of the classification.

73f6982ca262480ca866356b468614e5

Figure: Output webpage to present the model’s prediction to end-users.

The body of the code is shown below, and it is saved as output.html in the directory ./templates/output.html. In the code {{ variety }} specifies the argument that was passed to get rendered in the new HTML file.

aebe9a3d8bc44ee8bb7be3146579419d

Figure: Body of HTML file for the output webpage.

25.2.5 Run the Web Application

To deploy the application, we will execute the command python app.py from the terminal. Don’t forget to first change the directory to Iris-API where the file app.py is saved.

The output is shown in the figure below. We can see that there are warning messages with recommendations for changes in the code, but these warnings do not affect the functionality of the app. There is also a warning that this is a development server, which is primarily intended fro testing and debugging purposes. If we would like to deploy the web application in production, we will need to use WSGI (Web Server Gateway Interface) server that is designed to handle a large number of requests and is optimized fro performance and scalability.

We can also see that the server is running in debug mode on http://127.0.01:5000/ (given with the IP Address:Port).

To start the application on the local machine, we can either click on the URL http://127.0.01:5000/, or we can copy and paste the URL into a web browser.

ad26161963e2450d86c48b9321b03ac8

Figure: Run the application.

The following are screenshots of the application for one example and the predicted iris class is Setosa.

bf1c0398a8614247862b44c74572c819

bb1189c6b560468c9e3347f51e91cf15

Figure: Entered inputs and predicted class.

The folder structure is as follows:

Iris-API
    ├── iris.csv
    ├── model.py
    ├── app.py
    ├── templates
    │   ├── index.html
    │   ├── output.html

25.3 Deploying a Model for MNIST Digits Classification

In this section we will create another web API for classification of MNIST digits. Differently from the previous section, we will use a Convolutional Neural Network model, as well as we will save the trained model and use it for prediction. The code in mostly based on this section from the following blog: Deploying Deep Learning Models Part 1: Preparing the Model.

25.3.1 Model Training and Saving

We will first load the MNIST dataset, and we will create a simple Convolutional Neural Network for classification of the digit images in the dataset.

[1]:
import tensorflow
from tensorflow import keras
from keras.datasets import mnist
from keras.models import Model
from keras.layers import Input, Dense, Dropout, Flatten, Conv2D, MaxPooling2D
[2]:
# Load the data
(x_train, y_train), (x_test, y_test) = mnist.load_data()
[3]:
# Scale the images to the range [0,1]
x_train = x_train.astype('float32')
x_test = x_test.astype('float32')
x_train /= 255
x_test /= 255

# Print the shape and number of samples
print('x_train shape:', x_train.shape)
print(x_train.shape[0], 'train samples')
print(x_test.shape[0], 'test samples')
x_train shape: (60000, 28, 28)
60000 train samples
10000 test samples
[5]:
# Define the layers in the model
inputs = Input(shape=(28, 28, 1))
conv1a = Conv2D(filters=32, kernel_size=3, padding='same')(inputs)
conv1b = Conv2D(filters=64, kernel_size=3, padding='same')(conv1a)
pool1 = MaxPooling2D()(conv1b)
flat = Flatten()(pool1)
dense1 = Dense(128, activation='relu')(flat)
dropout1 = Dropout(0.5)(dense1)
outputs = Dense(10, activation='softmax')(dropout1)

# Define the model with inputs and outputs
model = Model(inputs, outputs)
[6]:
# Compile and train the model
model.compile(loss='sparse_categorical_crossentropy',
              optimizer='adam',
              metrics=['accuracy'])

model.fit(x_train, y_train, batch_size=128, epochs=5, verbose=0)
[6]:
<keras.src.callbacks.History at 0x1bcccb76090>
[7]:
# Evaluate on test dataset
score = model.evaluate(x_test, y_test, verbose=0)
print('Test accuracy:', score[1])
Test accuracy: 0.9840999841690063

Next, we will save the model using the Keras-TensorFlow SaveModel format. We will use the saved model to make predictions in the web application without retraining the model, since training the model takes time and there is no need to train a new model every time the end-users need to make predictions.

[8]:
# save the model to a file
model.save("mnist_model.keras")

To make predictions, we can load the model and compile it, as in the following cell.

[9]:
from tensorflow.keras.models import load_model

# load the weights into new model
loaded_model = load_model("mnist_model.keras")

# Compile and evaluate loaded model
loaded_model.compile(loss='sparse_categorical_crossentropy', optimizer='adam', metrics=['accuracy'])

# Evaluate on test dataset
score = loaded_model.evaluate(x_test, y_test, verbose=0)
print('Test accuracy:', score[1])
Test accuracy: 0.9840999841690063

25.3.2 Creating a Flask App

To deploy the model we will create the app.py file, similarly to the Flask file in the previous section.

We will define again two routes in the Flask app:

  • An index (home) page route '/', for the users to draw a digit image.

  • A predict route '/predict', to predict the class of the digit with the saved model.

In the next cell, we first import the required libraries, and an app object is created that is an instance of the Flask class.

[ ]:
from flask import Flask, render_template, request
from tensorflow.keras.models import load_model
from PIL import Image
import numpy as np
import re
import base64

# Initialize the flask class and specify the templates directory
app = Flask(__name__, template_folder="templates")

Similar to the previous example, we define the home page route using the @app.route decorator, and pass the URL of the main page of the web application index.html.

[ ]:
# Default route set as 'index'
@app.route('/')
def index_view():
    return render_template('index.html')

The '/predict' route is shown next, which gets the image of a digit drawn by the user, and it first applies image resizing and reshaping, and afterward the saved model is used to predict the digit class. Output is the response variable that returns a string of the predicted class.

[ ]:
# Route 'predict'
@app.route('/predict', methods=['GET', 'POST'])
def predict_class():

    # Get the drawn image
    imgData = request.get_data()

    # Convert the image into a png file
    convertImage(imgData)

    # Open the png file
    x = Image.open('output.png')

    # Resize the image to 28x28 pixels
    x = x.resize((28,28))

    # Invert the image into black background and white foreground
    x = np.invert(x)

    # Reshape into a batch with one image
    x = x[:,:,0].reshape(1, 28, 28, 1)

    # Scale to the range [0,1]
    x = x/255

    # Make a prediction
    out = model.predict(x)

    # Get the predicted digit
    response = np.array_str(np.argmax(out, axis=1))

    return response

And finally, we run the app in debug mode.

[ ]:
# Run the Flask server
if __name__ == '__main__':
    app.run(debug=True)

The organization of the directory of the web application is shown below. Beside the app.py, the main directory also contains the saved model mnist_model.keras and the image drawn by the users saved as output.png. The templates sub-directory contains the index.html and draw.html pages. In the static folder, a JavaScript file index.js is used to render a canvas for drawing digits by the users, and style.css is a stylesheet for the web application.

MNIST-API
    ├── app.py
    ├── mnist_model.keras
    ├── output.png
    ├── templates
    │   ├── index.html
    │   ├── draw.html
    ├── static
    │   ├── index.js
    │   ├── style.css

25.3.3 Run the Web Application

We can run the application using python app.py, and we will click on the URL http://127.0.0.1:5000/ to access the web API shown below. We can use the mouse pointer to draw digits, and the Predict button will display the Predicted Output by the model. The Clear button allows to draw again and make a new prediction.

ec35a11fdcde4b6ebb8bc23d70355a02

093744f6ab37424886f52a5fb16894d1

Figure: Run the web application.

Appendix

The material in the Appendix is not required for quizzes and assignments.

Deploying a Model with Fast API

This section explains how to develop a RESTful API for classification of Iris flowers with the Fast API library.

Before we try to develop the API, we need to install the required libraries with pip install, fastapi, python-multipart, uvicorn.

The code for the app.py server in Fast API is shown below.

First, we import modules from Fast API for handling HTTP requests and exceptions, and for template rendering.

Next, we instantiate the app web application from the FastAPI() class. And we define the directory with the HTML templates. Fast API uses Jinja2 for template rendering, allowing to create dynamic HTML pages.

Similar to the Flask app, in Fast API we use the @app.get('/') decorator to associate the HTTP GET method with the default home page of the application. In Fast API, the Request class is used to handle the incoming requests, where request is an instance that contains the information about the HTTP request. The index_view function will render a template of the index.html file and will pass the request object to it.

The '/predict' route will handle the GET request. The predict_class function retrieves the input values slen, swid, plen, and pwid and calls model.classify() to predict the variety of the Iris flower. If there are no errors, the function will render a template of the output.html file and will pass the variety to be displayed to the user.

Finally, the web application is run using the uvicorn server. UVicorn is the default server for Fast API in Python.

The code for the Fast API app is similar to the Flask app, but there are several differences in the syntax and the implementation.

[ ]:
# Import libraries
from fastapi import FastAPI, Request, Depends, Form, HTTPException
from fastapi.templating import Jinja2Templates
from typing import Optional
import model

# Initialize the FastAPI class and specify the templates directory
app = FastAPI()
templates = Jinja2Templates(directory="templates")

# Default route set as 'index'
@app.get('/')
def index_view(request: Request):
    return templates.TemplateResponse("index.html", {"request": request})

# Route 'predict' accepts GET request
@app.get('/predict')
def predict_class(request: Request,
                  slen: Optional[float] = None,
                  swid: Optional[float] = None,
                  plen: Optional[float] = None,
                  pwid: Optional[float] = None):
    try:
        # Get the output from the classification model
        variety = model.classify(slen, swid, plen, pwid)

        # Render the output in a new HTML page
        return templates.TemplateResponse("output.html", {"request": request, "variety": variety})
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"An error occurred: {str(e)}")

# Run the FastAPI server
if __name__ == '__main__':
    import uvicorn
    uvicorn.run(app)

Deploying a Model with Django

The corresponding code for developing a RESTful API for classification of Iris flowers with the Django library is shown below.

The code is similar to the apps in Flask and Fast API. The functions index_view and predict_class define the rendering of the home page and the predicted outputs by the model.

The URL patterns define that the root path maps to the index_view function, and the 'predict' path maps to the predict_class function.

The last part of the code defines the configuration settings and the execution of the server with app.py runserver.

[ ]:
from django.shortcuts import render
from django.http import HttpResponse
from django.urls import path
import model

# Default route set as 'index'
def index_view(request):
    return render(request, 'index.html')

# Route 'predict' accepts GET request
def predict_class(request):
    try:
        slen = float(request.GET.get('slen'))
        swid = float(request.GET.get('swid'))
        plen = float(request.GET.get('plen'))
        pwid = float(request.GET.get('pwid'))

        # Get the output from the classification model
        variety = model.classify(slen, swid, plen, pwid)

        # Render the output in a new HTML page
        return render(request, 'output.html', {'variety': variety})
    except Exception as e:
        return HttpResponse(f"An error occurred: {str(e)}", status=500)

# URL patterns define which function is called for specific URL paths
urlpatterns = [path('', index_view),
    path('predict/', predict_class)]

# Django settings and execution
if __name__ == '__main__':
    from django.conf import settings

    # Define the templates directory and debug mode
    settings.configure(
        DEBUG=True,
        ROOT_URLCONF=__name__,
        TEMPLATES=[
            {
                'BACKEND': 'django.template.backends.django.DjangoTemplates',
                'DIRS': ['templates'],
                'APP_DIRS': True,
            },
        ],
    )

    # Execute the server from the command line
    import django
    django.setup()

    from django.core.management import execute_from_command_line

    execute_from_command_line(['app.py', 'runserver'])

References

  1. Deploying Machine Learning Models using Flask, by Srishilesh P S, available at https://www.section.io/engineering-education/deploying-machine-learning-models-using-flask/.

  2. Deploying Deep Learning Models Part 1: Preparing the Model, by Vihar Kurama, available at: https://blog.paperspace.com/deploying-deep-learning-models-flask-web-python/.

  3. Python and REST APIs: Interacting With Web Service, by Jason Van Schooneveld, available at https://realpython.com/api-integration-in-python/.

  4. Getting Started with RESTful APIs and Fast API, by Sunil Kumar Dash, available at https://www.analyticsvidhya.com/blog/2022/08/getting-started-with-restful-apis-and-fast-api/.

BACK TO TOP