背景
不久前,OpenAI 正式宣布了 TTS 模型的正式放出,我也在第一时间尝试为我的小应用 译站 接入对应的功能。接入是在后端完成,而我目前用的后端框架是 Flask。
但当我开始写代码时,却发现了一个严重的问题:我希望做到流处理生成,而 openai 模块提供的对应函数定义为:
@override
async def aiter_bytes(self, chunk_size: Optional[int] = None) -> AsyncIterator[bytes]:
return self.response.aiter_bytes(chunk_size)
如上图,这是一个 async
函数,而其返回的内容也是异步迭代器;而 Flask 是一个基于 WSGI 的框架,其不支持异步操作(准确的说,是没法直接迭代异步迭代器来做流式返回)。在历经了几天将 AsyncGenertor
转化成 Generator
的失败尝试后,我最终决定直接更换框架。所幸,我找到了 Quart。
Quart 是一个基于 ASGI(Asynchronous Server Gateway Interface)的框架,其 API 与 Flask 几乎完全相同,但其支持异步操作。
在完成代码的备份后,我开始了迁移。
迁移
全局替换
首先,我将所有的 flask
替换成 quart
,并将 Flask
替换成 Quart
。这一步是最简单的,因为 Quart 的 API 与 Flask 的 API 几乎完全相同,也就是说,对于原本的项目导入:
from flask import Flask, request, jsonify
app = Flask(__name__)
只需要将其替换为:
from quart import Quart, request, jsonify
app = Quart(__name__)
即可。这一步直接在 VSCode 中完成。
一些 Extension 的替换
项目中用到了一些 Flask 的 Extension,比如 flask_cors
、flask_jwt_extended
等,经过一番查询后,发现这些 Extension 很多都有对应的 Quart 版本,参考 Quart Extensions 找到对应的替换,按 README 中的说明进行替换即可。很多 Extension 也都保持了与 Flask 版本相同的 API,所以替换起来也很简单。
问题
本来以为到这儿,大头就完成了。没想到这才是一切的开始。当我运行项目时,却发现了一个问题:Quart 的 request
对象与 Flask 的 request
对象不同,很多 flask 原本的属性,在 Quart 中变成了 awaitable 的!官方 给出的列表如下:
await request.data
await request.get_json()
await request.form
await request.files
await render_template()
await render_template_string()
也就是说,对于原本的代码
# Flask
@bp_api.route("/")
def test():
a: int = int(request.form.get("a", 0))
try:
return render_template("index.html")
except Exception as e:
return make_response(f"error, {e}")
在 Quart 中,需要改写为:
# Quart
@bp_api.route("/")
async def test():
form = await request.form
a: int = int(form.get("a", 0))
try:
return await render_template("