需要将文件上传到 FastAPI 端点,将其转换为 Markdown 并将文本保存到 Redis(文件大小最大为 4mb)。
到目前为止我发现的唯一逻辑是将文件上传为
UploadFile
,读取内容,使用正确的扩展名将它们保存到磁盘,将该路径传递到https://github.com/microsoft/markitdown库,再次读取该 markdown 文件,然后将其传递给 Redis。 I/O 太多了。
有没有办法在内存中完成所有这些?
(为了代码简单起见,我删除了所有错误处理,我假设只有文本文件)
@router.post("/upload")
async def uploadPost(filepond: UploadFile = File()):
"""
Convert a textual file to markdown.
Store in Redis
"""
# Create a temporary file to save the uploaded content
# for sake of simplicity I use txt for everything
with NamedTemporaryFile(delete=False,suffix=".txt") as temp_file:
temp_file_path = temp_file.name
content = await filepond.read()
temp_file.write(content)
temp_file.close()
md = MarkItDown()
result = md.convert(temp_file_path)
redis.setex("some key", 3600, result.text_content)
os.remove(temp_file_path)
您似乎受到当前使用的库的限制,不是 FastAPI,它提供了一种方法来在请求正文到达时以块的形式获取(使用
request.stream()
而不是UploadFile
)—请参阅这个答案和这个答案。
convert_stream()
方法,但它似乎并没有按照名称实际含义进行操作。 stream
参数(没有明确的类型)用于一次读取全部内容,并将它们简单地存储到临时文件中(本质上,类似于您当前的方法)。
考虑到库的限制,您可能仍然会受益于使用
request.stream()
(即使文件大小高达 4MB,正如您所提到的,可能并不那么明显)在块到达时写入它们直接使用 NamedTemporaryFile
与使用 UploadFile
相比,后者会将大于 1MB 的文件存储到您可以使用的 SpooledTemporaryFile
稍后需要阅读其中的内容,如此答案中所述。因此,您至少会避免不必要地写入和读取两个临时文件,如问题中提供的示例所示。类似的例子可以在这里、这里和这里找到。
from fastapi import FastAPI, Request, HTTPException
from fastapi.concurrency import run_in_threadpool
from tempfile import NamedTemporaryFile
import aiofiles
import os
app = FastAPI()
@app.post('/upload')
async def upload(request: Request):
try:
async with aiofiles.tempfile.NamedTemporaryFile("wb", delete=False, suffix=".txt") as temp:
try:
async for chunk in request.stream():
await temp.write(chunk)
except Exception:
raise HTTPException(status_code=500, detail='Something went wrong')
# You could have the `convert` function run in an external ThreadPool/ProcessPool,
# in order to avoid blocking the event loop
md = MarkItDown()
res = await run_in_threadpool(md.convert, temp.name)
except Exception:
raise HTTPException(status_code=500, detail='Something went wrong')
finally:
os.remove(temp.name)
您对使用 tmpfs 在内存中存储临时文件有何看法?
我认为像“内存临时文件”这样的库值得考虑。