使用React&FastAPI&Doubao-lite-32k实现简易AI对话功能
趁着在掘金青训营学习,复习了一下JS和React,随手做了个界面,作为前端实践选题之一;
用到的技术/资源主要有:
- React
- FastAPI
- fastapi_boot
- tailwindcss
- Ant Design
- MDN EventSource
- 阮一峰的网络日志 SSE
- 火山引擎 豆包模型接口调用
- volc-sdk-python Github
- md-editor-rt
1. 理论
首先介绍一下SSE:
SSE(Server-Sent Events)是一种服务器主动向客户端推送实时数据的技术,主要有以下特点:
-
单向通信:允许服务器向客户端单向推送数据,而客户端不能通过这个连接向服务器发送数据。
-
基于HTTP协议:使用标准的HTTP协议进行通信,这意味着它不需要像WebSocket那样创建一个新的协议连接。
-
自动重连:支持断线重连,当连接意外断开时,客户端可以自动尝试重新连接。
-
文本格式数据:默认传输文本格式的数据,如果需要传输二进制数据,则需要进行编码。
-
浏览器支持:大多数现代浏览器都支持SSE,除了早期的Edge和IE浏览器。
-
轻量级和简单:与WebSocket相比,SSE 更加轻量级和简单,适用于不需要复杂双向通信的场景。
-
事件流:SSE 数据流由一系列的字段组成,每个字段都以键值对的形式出现,字段之间用换行符分隔,包括可选的事件名、必须的数据内容、可选的唯一标识符和重试时间间隔等。由于AI对话的回复要做一个打字机的效果,所以非常适合用流数据渲染,每次在原消息的基础上加上新返回的消息;
-
减少网络负担:与传统的轮询方式相比,SSE 通过单一的HTTP连接推送多个事件,减少了网络请求的次数,从而减轻了网络负担。
-
适用于实时更新:适用于需要即时更新的应用场景,如实时聊天、在线协作工具、实时数据展示和通知推送等。
2. 准备AI
登录/注册火山引擎,在控制台创建Access Key和Secret Key:
这里选Doubao-pro-32k做演示:
创建推理接入点:
这里的Access Key、Secret Key以及接入点名称下面的id后面会用到。
3. 后端
1. config
整体项目目录如下,app用来写前端,server用来写后端:
config.toml
配置及对应关系:
config/DoubaoConfig.py
中注入配置并初始化MaasService
:
代码都有点多,贴出来应该超过伴学笔记的70%了...就放图了
2. model
model/chat.py
存放一些请求、响应和传输的类型
- AI的一次性回复长这样:
- 流式回复消息格式长这样:
可以看到,AI的响应分为消息和本次调用用量,一次性回复会把二者拼起来返回,而流式调用前面的只有消息,最后一次是消息+用量。所以有了如下模型设计:
3. ChatService
主要作用是:
- 注入之前写的
endpoint_id
和MaasService
依赖; - 在
chat
方法中接收消息,调用MaasService
实例的chat
方法,包装为ChatVO
返回; - 在
chat_stream
方法中接收消息,调用MaasService
的chat_stream
方法,返回一个生成器; - 异常处理,参考github文档,调用出现
MaasException
异常时返回500;
4. Controller
主要作用:
- 通过
POST /chat
调用一次性响应接口; - 通过
GET /chat
调用流式响应接口,并通过gen_sse_str
函数把结果封装为SSE相应格式,返回StreamingResponse
;
使用SSE时需要把响应消息中的\n
替换一下,避免被SSE识别为消息结束符,前端收到后再换回来,不然本次传输中\n
后面的消息就丢了,后面写好前端会有个测试。
调用时间测试
在相同问题的情况下,流式返回的时间比一次性更少,而且用户体验明显更好;
5. 启动
uvicorn main:app --reload
4. 前端
用到的主要依赖前面已经给出来了,下面主要看实现:
1. 类型
和后端的DTO和VO对应就行,过了;
2. useEventSource
随便写了一个,没有用ReactUse
中的;
主要用法:
- 初始化时传
url
,以及开始接收、有新消息、关闭、结束、错误等时间点需要调用的方法; - 返回累积的消息、是否正在接收,还有开始(
start
)和关闭(close
)的方法; - 因为请求的url都是一样的,每次请求的查询参数可能不同,所以每次请求时只需调用
start
并传递role
和content
,不需要再use; - 需要替换后端返回字符串中的指定字符为
\n
。
3. DoubaoChat.tsx
界面很简单,就不拆组件了,下面按效果挨个说明用法:
4. 效果
1. 空白界面:header、body和footer
2. 切换角色、发送消息
没错,头像真的是豆包:
3. 可中断,结果可复制
4. 分辨率宽高适应
5. 如果不替换'\n'
代码、表格、列表中的换行挺多,如果不换格式基本全乱了。
5. 总结
用React、FastAPI、豆包搭了个简单的AI对话应用;
如果后期还想做的话,可以加一些功能,比如:登录注册、对话历史、模型选择、function calling等。