ProChat专注于快速构建大型语言模型聊天对话框框架,ProChat 作为 AI 会话的前端解决方案,自然默认集成了这项流式输出的能力。只需要在 request 中配置一个返回流式文本的 Response (Web标准的 Response 对象),就可以轻松实现流式效果的集成。
非流式读取
对于非流式的请求,只需要返回一个进过 Response 包装的 String 即可。
<ProChat
request={async (messages) => {
const text = await delay(
`这是一条模拟非流式输出的消息的消息。本次会话传入了${messages.length}条消息`,
);
return new Response(text);
}}
style={{ height: '100vh' }}
/>
流式读取
Server-Sent Events(SSE)是一种让服务器能够向浏览器实时推送更新数据的技术。SSE允许服务器在事件发生时通过HTTP连接主动将数据发送到客户端,而不需要客户端发起请求。这种技术基于一个持久化的单向连接,客户端通过创建EventSource对象与服务器建立连接,并监听来自服务器的事件流。
SSE的数据格式是简单的文本格式,每条消息由数据字段承载,内容类型为text/event-stream。每个消息块遵循特定的语法,可以包含事件类型、事件ID以及自定义数据等信息。例如:
data: message1
data: message2
event: update
data: {"key": "value"}
id: 12345
data: some other data
对于流式请求处理,ProChat的核心关注点在于从返回的字节流中读取并解析内容。可以通过Reader对象来逐步读取响应流中的数据,并将其转换为所需格式的字符串信息。最终,尽管底层处理的是复杂的流式数据,但组件对外提供的接口仍简洁明了,仅暴露包含处理后内容的Stream流给上层调用者,从而实现对流式数据的有效封装与利用。
<ProChat
request={async (messages: any) => {
// 正常业务中如下:
const response = await fetch('/api/chat/completion', {
method: 'POST',
headers: {
'Content-Type': 'application/json;charset=UTF-8',
},
body: JSON.stringify({
messages,
stream: true,
}),
});
console.log('messages', messages);
// 确保服务器响应是成功的
if (!response.ok || !response.body) {
throw new Error(`HTTP error! status: ${response.status}`);
}
// 获取 reader
const reader = response.body.getReader();
const decoder = new TextDecoder('utf-8');
const encoder = new TextEncoder();
const readableStream = new ReadableStream({
async start(controller) {
function push() {
reader
.read()
.then(({ done, value }) => {
if (done) {
controller.close();
return;
}
const chunk = decoder.decode(value, { stream: true });
const message = chunk.replace('data: ', '');
const parsed = JSON.parse(message);
controller.enqueue(encoder.encode(parsed.choices[0].delta.content));
push();
})
.catch((err) => {
console.error('读取流中的数据时发生错误', err);
controller.error(err);
});
}
push();
},
});
return new Response(readableStream);
}}
/>
代码中需要,数据需要通过TextEncoder再次编码,否则组件无法识别数据:
controller.enqueue(encoder.encode(parsed.choices[0].delta.content));