FastAPI如何获取POST接口后台任务返回值并传入Jinja2 HTML模板
FastAPI猫狗分类应用问题解决方案
1. 后台任务无法获取返回值问题
核心原因:FastAPI的BackgroundTasks设计目的是在响应完全返回给客户端之后再执行异步任务,不会将任务的返回值传递给当前请求的响应流程,因此你无法直接通过background_tasks.add_task的返回值拿到预测结果,这和你的需求「拿到预测结果返回给用户」本质冲突。
你注释里写的「无论图片数据处理耗时多久,都可以先返回响应」如果是真实需求,你需要额外引入状态存储(比如Redis)存储任务ID与预测结果的映射,先给用户返回任务ID,前端通过定时轮询接口拉取最终结果,属于异步交互方案。
但猫狗分类预测属于毫秒级耗时任务,完全不需要用后台任务,直接调用预测函数即可,这也是最符合你当前需求的解决方案。
2. POST请求下Jinja2模板渲染实现
你之前的代码有两个错误导致模板无法渲染:
- 将模板目录
Templates挂载为了静态资源目录,FastAPI会优先返回静态html文件,不会解析模板变量 - POST接口没有调用Jinja2的模板渲染方法,也没有传入必填的
Request对象
修改后的完整代码
后端代码
from starlette.responses import RedirectResponse from fastapi.templating import Jinja2Templates from fastapi import FastAPI, File, UploadFile, Request from tensorflow.keras import preprocessing from fastapi.staticfiles import StaticFiles from keras.models import load_model from PIL import Image import numpy as np import uvicorn app = FastAPI() # 静态资源单独挂载到static目录,不要和模板目录混用 app.mount("/static", StaticFiles(directory="static"), name="static") # 模板目录单独配置 templates = Jinja2Templates(directory="templates") model_dir = 'F:\\Saved-Models\\Dog-Cat-Models\\json_function_test_dog_cat_optuna.h5' model = load_model(model_dir) def predict_image(image): pp_dogcat_image = Image.open(image.file).resize((150, 150), Image.NEAREST).convert("RGB") 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) if str(prediction) == '[1]': answer = "It's a Dog" else: answer = "It's a Cat" return answer @app.get('/') async def index(): # 首页重定向到渲染后的模板页,不是静态文件 return RedirectResponse(url="/prediction_page") # 同时支持GET和POST请求,GET返回空表单,POST返回带结果的页面 @app.get('/prediction_page') async def show_form(request: Request): return templates.TemplateResponse("prediction.html", {"request": request, "answer": ""}) @app.post('/prediction_page') async def prediction_form(request: Request, dogcat_img: UploadFile = File(...)): # 直接调用预测函数拿到结果 answer = predict_image(dogcat_img) # 返回渲染后的模板,传入预测结果 return templates.TemplateResponse("prediction.html", {"request": request, "answer": answer}) if __name__ == '__main__': uvicorn.run(app, host='localhost', port=8000)
目录结构调整
- 新建
templates文件夹,将你的html文件存入该目录,命名为prediction.html - 新建
static文件夹,存放css、js、图片等静态资源
前端代码(templates/prediction.html)
<!DOCTYPE html> <html> <head> <title>猫狗分类预测</title> </head> <body> <div class="prediction_box"><p>Select an image of a dog or a cat and the AI will print out a prediction of what he thinks it is.....</p><br> <!--enctype="multipart/form-data" 允许UploadFile类型数据传输--> <form action="/prediction_page" enctype="multipart/form-data" 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> <p>{{answer}}</p> </div> </body> </html>
运行说明
启动服务后访问http://localhost:8000即可进入预测页面,上传图片提交后会直接在当前页面显示预测结果。
内容的提问来源于stack exchange,提问作者Luleo_Primoc
相关产品推荐
相关产品推荐

