FastAPI上传音频文件遇Internal Server Error及文件未找到问题求助
问题分析与解决方案
你遇到的Internal Server Error核心原因是:FastAPI的UploadFile对象的filename只是上传文件的原始名称,并不是服务器本地的文件路径——上传的文件此时仅存在于内存中,librosa.load()找不到对应的本地文件,自然会抛出"文件未找到"的错误。
你确实需要处理上传文件的读取逻辑,不一定非要保存到永久文件夹,用临时文件或者直接在内存中处理都可以,下面给你两种可行方案:
方案1:使用临时文件处理(简单直观)
利用Python的tempfile模块创建临时文件,把上传的文件内容写入后,再用librosa加载这个临时文件:
import tempfile from fastapi import FastAPI, File, UploadFile import librosa import numpy as np from tensorflow.keras.models import load_model import os app = FastAPI() # 提前加载模型,避免每次请求都加载,节省资源 model = load_model("trained_heartbeat_classifier.h5") @app.post("/uploadfile/") async def create_upload_file(file: UploadFile = File(...)): # 创建临时文件,保留原文件的后缀格式 with tempfile.NamedTemporaryFile(delete=False, suffix=f".{file.filename.split('.')[-1]}") as temp_file: # 把上传文件的内容写入临时文件 temp_file.write(await file.read()) temp_file_path = temp_file.name try: # 从临时文件加载音频数据 y, sr = librosa.load(temp_file_path) # 提取音频特征 S = librosa.feature.melspectrogram( y, sr=sr, n_fft=2048, hop_length=512, n_mels=128) mfccs = librosa.feature.mfcc(S=librosa.power_to_db(S), n_mfcc=40) # 适配模型输入格式并完成预测 x_test = np.asarray([mfccs]) x_test = x_test.reshape(x_test.shape[0], x_test.shape[1], x_test.shape[2], 1) pred = model.predict(x_test, verbose=1) # 替代已弃用的predict_classes方法 pred_class = np.argmax(pred, axis=1) # 整理返回结果 result = { "filename": file.filename, "prediction": "Normal heartbeat" if pred_class[0] else "Abnormal heartbeat", "confidence": float(pred[0][1] if pred_class[0] else pred[0][0]) } return result finally: # 用完临时文件后删除,避免磁盘占用 os.unlink(temp_file_path) if __name__ == "__main__": # 启动FastAPI服务,而非直接处理命令行参数 import uvicorn uvicorn.run(app, host="0.0.0.0", port=8000)
方案2:内存中直接处理(更高效,无需磁盘IO)
librosa.load()支持读取类文件对象,所以可以直接把上传的文件内容读取到BytesIO中,不用写入磁盘,减少IO开销:
from fastapi import FastAPI, File, UploadFile import librosa import numpy as np from tensorflow.keras.models import load_model import io app = FastAPI() model = load_model("trained_heartbeat_classifier.h5") @app.post("/uploadfile/") async def create_upload_file(file: UploadFile = File(...)): # 读取上传文件内容到内存中的BytesIO对象 file_content = await file.read() audio_file = io.BytesIO(file_content) # 直接从内存对象加载音频 y, sr = librosa.load(audio_file) # 特征提取逻辑和方案1一致 S = librosa.feature.melspectrogram( y, sr=sr, n_fft=2048, hop_length=512, n_mels=128) mfccs = librosa.feature.mfcc(S=librosa.power_to_db(S), n_mfcc=40) # 模型预测与结果返回 x_test = np.asarray([mfccs]) x_test = x_test.reshape(x_test.shape[0], x_test.shape[1], x_test.shape[2], 1) pred = model.predict(x_test, verbose=1) pred_class = np.argmax(pred, axis=1) result = { "filename": file.filename, "prediction": "Normal heartbeat" if pred_class[0] else "Abnormal heartbeat", "confidence": float(pred[0][1] if pred_class[0] else pred[0][0]) } return result if __name__ == "__main__": import uvicorn uvicorn.run(app, host="0.0.0.0", port=8000)
额外注意点
- 你原代码的
main函数逻辑有误:create_upload_file是异步的API端点函数,不能像普通同步函数那样直接调用;同时Keras的predict_classes方法已被弃用,改用np.argmax(pred, axis=1)替代更稳妥。 - 模型要提前加载(放在API端点外部),避免每次请求都重新加载模型,大幅降低服务响应时间。
内容的提问来源于stack exchange,提问作者Faizan.shaikh
相关产品推荐
相关产品推荐

