一、前言
使用 FastAPI 可以帮助我们更简单高效地部署 AI 交互业务。FastAPI 提供了快速构建 API 的能力,开发者可以轻松地定义模型需要的输入和输出格式,并编写好相应的业务逻辑。
FastAPI 的异步高性能架构,可以有效支持大量并发的预测请求,为用户提供流畅的交互体验。此外,FastAPI 还提供了容器化部署能力,开发者可以轻松打包 AI 模型为 Docker 镜像,实现跨环境的部署和扩展。
总之,使用 FastAPI 可以大大提高 AI 应用程序的开发效率和用户体验,为 AI 模型的部署和交互提供全方位的支持。
二、术语
2.1.FastAPI
FastAPI 是一个用于构建 API 的现代、快速(高性能)的 Python Web 框架。它是基于标准 Python 类型注释的 ASGI (Asynchronous Server Gateway Interface) 框架。
FastAPI 具有以下主要特点:
-
快速: FastAPI 使用 ASGI 服务器和 Starlette 框架,在性能测试中表现出色。它可以与 Uvicorn 一起使用,提供非常高的性能。
-
简单: FastAPI 利用 Python 类型注释,使 API 定义变得简单且直观。开发人员只需要定义输入和输出模型,FastAPI 会自动生成 API 文档。
-
现代: FastAPI 支持 OpenAPI 标准,可以自动生成 API 文档和交互式文档。它还支持 JSON Schema 和数据验证。
-
全功能: FastAPI 提供了路由、依赖注入、数据验证、安全性、测试等功能,是一个功能齐全的 Web 框架。
-
可扩展: FastAPI 被设计为可扩展的。开发人员可以轻松地集成其他库和组件,如数据库、身份验证等。
2.2.WebSocket
是一种计算机通信协议,它提供了在单个 TCP 连接上进行全双工通信的机制。它是 HTML5 一个重要的组成部分。
WebSocket 协议主要有以下特点:
-
全双工通信:WebSocket 允许客户端和服务器之间进行双向实时通信,即数据可以同时在两个方向上流动。这与传统的 HTTP 请求-响应模型不同,HTTP 中数据只能单向流动。
-
持久性连接:WebSocket 连接是一种持久性的连接,一旦建立就会一直保持,直到客户端或服务器主动关闭连接。这与 HTTP 的连接是短暂的不同。
-
低开销:相比 HTTP 请求-响应模型,WebSocket 在建立连接时需要较少的数据交换,因此网络开销较小。
-
实时性:由于 WebSocket 连接是持久性的,且数据可以双向流动,因此 WebSocket 非常适用于需要实时、低延迟数据交互的应用场景,如聊天应用、实时游戏、股票行情等。
2.3.FlaskAPI vs Flask
FastAPI 和 Flask 都是 Python 中非常流行的 Web 框架,但它们有一些重要的区别:
-
性能:FastAPI 基于 ASGI 服务器,采用异步编程模型,在处理大量并发请求时表现更出色。据测试,FastAPI 的性能比 Flask 高出 3-4 倍。
-
路由和 API 声明:FastAPI 采用声明式 API 设计,开发者只需定义输入输出模型,FastAPI 就能自动生成路由和文档。而 Flask 需要手动定义路由和处理函数。
-
数据校验:FastAPI 内置了强大的数据校验功能,可以自动校验输入参数的正确性。Flask 则需要自行实现参数校验。
-
自动生成文档:FastAPI 可以自动生成可交互的 API 文档,而 Flask 需要依赖第三方库如 Swagger 来生成文档。
-
部署和扩展:FastAPI 支持容器化部署,可以方便地打包为 Docker 镜像。Flask 则需要依赖其他工具来实现容器化。
-
异步支持:FastAPI 原生支持异步编程,可以轻松地集成基于异步的第三方库。而 Flask 需要依赖第三方库如 Flask-Socketio 来实现异步功能。
-
学习曲线:FastAPI 的声明式 API 设计使得初学者上手较为容易。而 Flask 需要开发者具有更多的 Web 开发经验。
2.4.Uvicorn
是一个非常高效和易用的 ASGI(Asynchronous Server Gateway Interface)服务器,主要用于运行基于ASGI协议的Python Web框架,例如FastAPI。
Uvicorn 的特点:
-
高性能: 使用 Rust 编写的
httptools
库作为其核心HTTP解析器,以及uvloop
高性能的事件循环,使其具有非常出色的性能表现。 -
易用性: 提供了简单的命令行接口,可以轻松地启动和运行基于ASGI协议的应用程序。
-
兼容性: 支持 ASGI 2.0 和 3.0 协议,可以运行各种基于ASGI的 Python Web 框架,如 FastAPI、Starlette 等。
-
多平台支持: 可以在 Windows、macOS 和 Linux 等多个平台上运行。
-
灵活性: 提供了丰富的配置选项,可以根据需要进行定制和扩展。
三、前置条件
3.1. 创建虚拟环境&安装依赖
conda create -n fastapi_test python=3.10
conda activate fastapi_test
pip install fastapi websockets uvicorn
四、技术实现
4.1. 构建简易WebSocket服务端
from fastapi import FastAPI, WebSocket
import uvicorn
app = FastAPI()
@app.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket):
await websocket.accept()
while True:
data = await websocket.receive_text()
await websocket.send_text(f"Message text was: {data}")
if __name__ == '__main__':
uvicorn.run(app, host='0.0.0.0',port=7777)
调用结果:
五、测试
5.1. 使用Fastapi测试
在上面服务端代码的基础上,增加html代码
from fastapi import FastAPI, WebSocket
from fastapi.responses import HTMLResponse
import uvicorn
app = FastAPI()
html = """
<!DOCTYPE html>
<html>
<head>
<title>Chat</title>
</head>
<body>
<h1>WebSocket Chat</h1>
<form action="" onsubmit="sendMessage(event)">
<input type="text" id="messageText" autocomplete="off"/>
<button>Send</button>
</form>
<ul id='messages'>
</ul>
<script>
var ws = new WebSocket("ws://localhost:7777/ws");
ws.onmessage = function(event) {
var messages = document.getElementById('messages')
var message = document.createElement('li')
var content = document.createTextNode(event.data)
message.appendChild(content)
messages.appendChild(message)
};
function sendMessage(event) {
var input = document.getElementById("messageText")
ws.send(input.value)
input.value = ''
event.preventDefault()
}
</script>
</body>
</html>
"""
@app.get("/")
async def get():
return HTMLResponse(html)
@app.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket):
await websocket.accept()
while True:
data = await websocket.receive_text()
await websocket.send_text(f"Message text was: {data}")
if __name__ == '__main__':
uvicorn.run(app, host='0.0.0.0',port=7777)
调用结果:
服务端输出:
浏览器输出:
5.2. 使用在线客户端测试
网址:WebSocket在线测试工具
调用结果:
5.3. 使用html页面测试
页面代码:
<!DOCTYPE html>
<html>
<head>
<title>Chat</title>
</head>
<body>
<h1>WebSocket Chat</h1>
<form action="" onsubmit="sendMessage(event)">
<input type="text" id="messageText" autocomplete="off"/>
<button>Send</button>
</form>
<ul id='messages'>
</ul>
<script>
var ws = new WebSocket("ws://localhost:7777/ws");
ws.onmessage = function(event) {
var messages = document.getElementById('messages')
var message = document.createElement('li')
var content = document.createTextNode(event.data)
message.appendChild(content)
messages.appendChild(message)
};
function sendMessage(event) {
var input = document.getElementById("messageText")
ws.send(input.value)
input.value = ''
event.preventDefault()
}
</script>
</body>
</html>
调用结果:
5.4. 使用postman测试
PS:
各位老铁,千万不要认为上述Demo很简单,万丈高楼平地起,任何复杂的功能都是通过简单的开始逐步演化而来。后面我们将把模型推理集成到上述的示例中。