如何在FastAPI中处理来自多个客户端的文件而不将文件保存到磁盘

问题描述 投票:0回答:1

我正在使用 FastAPI 创建一个 API,用于从移动应用程序接收小音频文件。在此 API 中,我对信号进行处理,并且能够在对声音进行分类后返回响应。最终目标是将分类发送回用户。

这是我到目前为止正在做的事情:

@app.post("/predict")

def predict(file: UploadFile = File(...)):   # Upload the wav audio sent from the mobile app user

 with open(name_file, "wb") as buffer:
        shutil.copyfileobj(file.file, buffer)  #creating a file with the received audio data
...

prev= test.my_classification_module(name_file) #some processing and the goal response in PREV variable

my_classification_module()
,我有这个:

X, sr = librosa.load(sound_file)

我想避免创建一个用

librosa
进行分类的文件。我想使用临时文件来执行此操作,而不会不必要地使用内存,并避免多个用户使用应用程序时文件重叠。

python file-upload classification fastapi
1个回答
4
投票

如果您的函数支持 file-like 对象,您可以使用

.file
UploadFile
属性,例如
file.file
(这是一个
SpooledTemporaryFile
实例),或者如果您的函数需要该文件在
bytes
格式中,使用
.read()
async 方法(请参阅 文档)。如果您希望保留使用
def
而不是
async def
定义的路线(有关 def
async def
的更多信息,请查看
this answer
),您可以使用
.read() 方法直接类文件对象,例如
file.file.read()

更新 - 如何解决
File contains data in an unknown format
错误

  1. 确保音频文件未损坏。比方说,如果您保存它并使用媒体播放器打开它,声音文件会播放吗?

  2. 确保您安装了最新版本的

    librosa
    模块。

  3. 尝试安装

    ffmpeg
    并将其添加到系统路径,如建议这里

  4. 此处和中所述 documentation,

    librosa.load()
    可以采用 file-like 对象作为文件路径的替代 - 因此,使用
    file.file
    file.file._file
    通常应该没问题(根据 documentation,
    _file
    属性是
    io.BytesIO
    io.TextIOWrapper
    对象...)。

    但是,正如文档herehere以及github讨论中所述,您还可以使用soundfile模块从file-like对象读取音频。示例:

    import soundfile as sf 
    
    data, samplerate = sf.read(file.file)
    
  5. 您还可以将上传文件的文件

    contents
    写入BytesIO流,然后将其传递给
    sf.read()
    librosa.load()
    :

    from io import BytesIO
    
    contents = file.file.read()
    buffer = BytesIO(contents)
    data, samplerate = librosa.load(buffer)  # ussing librosa module
    #data, samplerate = sf.read(buffer)      # using soundfile module
    buffer.close()
    
  6. 另一种选择是将文件

    contents
    保存到
    NamedTemporaryFile
    ,它“在文件系统中具有可见的名称”,“可用于打开文件”。完成后,您可以使用
    remove()
    unlink()
    方法手动删除它。

    from FastAPI import HTTPException
    from tempfile import NamedTemporaryFile
    import os
    
    contents = file.file.read()
    temp = NamedTemporaryFile(delete=False)
    try:
        with temp as f:
            f.write(contents);
        data, samplerate = librosa.load(temp.name)   # ussing librosa module
        #data, samplerate = sf.read(temp.name)       # using soundfile module
    except Exception:
        raise HTTPException(status_code=500, detail='Something went wrong')
    finally:
        #temp.close()  # the `with` statement above takes care of closing the file
        os.remove(temp.name)
    
© www.soinside.com 2019 - 2024. All rights reserved.