Recently, while implementing my Deep Neural Network (DNN) model into a WebAPI I faced multiple issues,
- my usage of absl-flags for command line arguments somehow clashed with the flask’s run command.
- in receiving image file back as an output from the server side, i received the following errors,
AttributeError: 'Image' object has no attribute 'read'
AttributeError: 'numpy.ndarray' object has no attribute 'read
I could have switched from using absl-py to some other module (for example, argparse) to set the default values for my command line arguments (unsure if this would have worked, since I did not test) but that would have required me to make changes all throughout my code. So, it is obvious why I was not in favor of doing that. Below I share the solution that helped me overcome these issues and finally helped me realize a working Flask WebAPI that takes in and returns an image file.
First the customary
# Import the necessary modules
import sysimport iofrom absl import flags
from flask import Flask, request, send_file
from PIL import Image# Define the flags
Up until this point, everything is as if you’d write a python code to be executed on your local machine. Below are the extra things, that need to be included to make absl-flags and flask app run smoothly together.
Include extra flags for the flask app
flags.DEFINE_string("host", None, "flag for host IP address")
flags.DEFINE_string("port", None, "flag for the port number")
without the above, we have the following error
absl.flags._exceptions.UnrecognizedFlagError: Unknown command line flag 'host'
Get the values for the FLAGs
The most important bit for obtaining the flag values, suggested here.
Continue the way you’d normally do with a Flask API
# Preparing the model
model = Model(MODEL_DIR)# create the Flask instance
flask_app = Flask(__name__)# define the desired functionality@flask_app.route("/infer", methods=["POST"])def infer():
# Retrieving the image
img = Image.open(request.files["file"]).convert("RGB")
# run the model on the image
output = model.single_inference(img)
# Convert to image object
img_out = Image.fromarray(output)
Convert the image object to byte array
The only way I could figure out to receive an image file back from the server.
... # Convert the image to byte array
img_byte_arr = io.BytesIO()
# move to beginning of file for `send_file()` to read from
return send_file(img_byte_arr, mimetype="image/PNG")
After finishing with all the above preparations, you can finally set up your API, with the following command line input (provided API is defined in app.py in the working directory).
python -m flask run --host=*.*.*.* --port=5000
To send a request to the server, enter the following command.
curl -X POST -H "Content-Type: multipart/form-data" http://*.*.*.*:5000/infer -F "file=@Data/input.png" > output.png
Note: Do not forget @ mark above
In this article, I share my solution to the issues I faced with implementing a Flask WebAPI for image based input/output, absl-flags for command line arguments. If you have a better solution or are facing some other hindrance, please do share.