|

How do you pass in an image through a template and use a model to predict with FastAPI?

Question Description: I am trying to create a machine learning web application. I have an HTML page that takes in an image (jpg or png) and I am loading my model into the API to predict the image and output results. The lines under the prediction function of FastAPI have worked in a separate file but I think something is wrong with the data format that is taken in b

from starlette.responses import RedirectResponse
from fastapi.staticfiles import StaticFiles
from fastapi import FastAPI, Form
from tensorflow.keras import preprocessing
from keras.models import load_model
import numpy as np
import uvicorn

app = FastAPI()
app.mount("/Templates", StaticFiles(directory="Templates"), name="Templates")

model_dir = 'F:\\Saved-Models\\Dog-Cat-Models\\First_Generation_dog_cat_optuna.h5'
model = load_model(model_dir)


@app.get('/')
async def index():
    return RedirectResponse(url="/Templates/index.html")


@app.post('/prediction_page')
async def prediction_form(dogcat_img: bytes = Form(...)):
    pp_dogcat_image = preprocessing.image.load_img(dogcat_img, target_size=(150, 150))
    pp_dogcat_image_arr = preprocessing.image.img_to_array(pp_dogcat_image)
    input_arr = np.array([pp_dogcat_image_arr])
    prediction = np.argmax(model.predict(input_arr), axis=-1)
    print(prediction)


if __name__ == '__main__':
    uvicorn.run(app, host='localhost', port=8000)

The error I get:

FileNotFoundError: [Errno 2] No such file or directory: b'cat.83.jpg'

It shouldn’t need a full path because the image is getting passed through the webpage right? I have also tried UploadFile instead of bytes and got this error:

INFO:     ::1:6918 - "POST /prediction_page HTTP/1.1" 422 Unprocessable Entity

Edit: HTML Code:

<form action="/prediction_page" method="post">
        <label for="image-upload" class="custom-file-upload">Select Image:</label>
        <input type="file" id="image-upload" name="dogcat_img"><br>
        <input class="custom-submit-button" type="submit">
    </form>

Expert Answer

Use async def prediction_form(dogcat_img: bytes = File(...)): if you want to get bytes data.

In your case: pp_dogcat_image = preprocessing.image.load_img(dogcat_img, target_size=(150, 150)) seem this line will load a file from local file path. So i suggest you use UploadFile type instead of bytes. And your function be like:

# ...
from fastapi import File, UploadFile
# ...

async def prediction_form(dogcat_img: UploadFile = File(...)):
    # ...
    pp_dogcat_image = preprocessing.image.load_img(dogcat_img.file_name, target_size=(150, 150))

Similar Posts