如何通过FastAPI接收模板上传图像并调用AI模型完成预测?
问题原因分析
- 第一个
FileNotFoundError错误:你使用Form接收文件上传字段,拿到的只是上传文件的文件名字节串,并非图片实际内容,load_img将这个文件名当作本地磁盘路径读取,自然找不到对应文件。 - 第二个
422 Unprocessable Entity错误:两个原因共同导致:- HTML上传表单没有添加
enctype="multipart/form-data"属性,这是文件上传类表单的必填属性,否则浏览器只会传递文件名而非文件内容,请求格式不符合FastAPI的参数校验要求 - 后端接收文件类型参数需要用
File注解,而非Form注解
- HTML上传表单没有添加
修复方案
1. 修改HTML表单代码
给form标签添加enctype属性,修改后代码如下:
<form action="/prediction_page" method="post" enctype="multipart/form-data"> <label for="image-upload" class="custom-file-upload">Select Image:</label> <input type="file" id="image-upload" name="dogcat_img" accept=".jpg,.png"><br> <input class="custom-submit-button" type="submit"> </form>
额外添加了accept属性限制可选文件类型,避免用户上传不符合要求的格式。
2. 修改FastAPI后端代码
修改后的完整代码如下:
from starlette.responses import RedirectResponse from fastapi.staticfiles import StaticFiles from fastapi import FastAPI, File, UploadFile from tensorflow.keras import preprocessing from keras.models import load_model import numpy as np import uvicorn import io app = FastAPI() app.mount("/Templates", StaticFiles(directory="Templates"), name="Templates") # 路径前加r转为原始字符串,避免Windows下反斜杠转义问题 model_dir = r'F:\Saved-Models\Dog-Cat-Models\First_Generation_dog_cat_optuna.h5' model = load_model(model_dir) # 类别映射,方便返回可读结果 CLASS_MAPPING = {0: "猫", 1: "狗"} @app.get('/') async def index(): return RedirectResponse(url="/Templates/index.html") @app.post('/prediction_page') async def prediction_form(dogcat_img: UploadFile = File(...)): # 读取上传的图片内容 img_content = await dogcat_img.read() # 转为字节流对象供load_img读取 img_byte_stream = io.BytesIO(img_content) pp_dogcat_image = preprocessing.image.load_img(img_byte_stream, 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)[0] # 返回可读结果,你也可以根据需求调整返回格式 return {"预测结果": CLASS_MAPPING.get(prediction, "未知类别")} if __name__ == '__main__': uvicorn.run(app, host='localhost', port=8000)
额外注意事项
- 如果你不需要保存上传的文件,直接用
bytes = File(...)接收参数也可以,不需要处理UploadFile的异步读取逻辑,代码更简洁:@app.post('/prediction_page') async def prediction_form(dogcat_img: bytes = File(...)): img_byte_stream = io.BytesIO(dogcat_img) # 后续处理逻辑和上面一致 - 模型加载可以放到启动事件里处理,避免服务运行过程中模型意外被释放,也更符合FastAPI的最佳实践。
内容的提问来源于stack exchange,提问作者Luleo_Primoc
相关产品推荐
相关产品推荐

