写了个AI聊天框,记录一下前端注意的点

599 阅读4分钟

最近一段时间一直在忙,好久没有更新了,最近做了个AI对话框的项目,现在闲下来了做个总结

这里是直接对接的腾讯的大模型知识引擎,调用的腾讯的开发API接口,前端页面腾讯提供了vue2版本的前端开源项目,但是博主是利用vue3开发的,所以只采用了腾讯的对话渲染组件

腾讯前端页面接入可参考:cloud.tencent.com/document/pr…

1.流式渲染对话

AI对话框最核心的一个点就是对话流式生成,腾讯大模型知识引擎提供了两种交互方式,一种是全双工通道,WebSocket ;另一种是单向通道HTTP SSE。因为该AI聊天框暂时不需要进行双向交互,所以采用的HTTP SSE交互方式。SSE之前我也没有接触过,但是也不难,下面是AI的介绍可以简单参考一下:

SSE的核心特性
  1. 单向通信 SSE 仅支持服务器到客户端的单向通信,适用于服务器主动推送实时数据的场景(如新闻推送、股票价格更新)。相比 WebSocket 的双向通信,SSE 更轻量且实现简单
  2. 流式返回机制 SSE 通过 HTTP 长连接实现流式传输,服务器将数据以事件流(Event Stream)的形式持续发送。每次推送的数据通过 data: 字段标记,客户端通过监听事件逐步接收并处理数据,从而实现“边生成边传输”的效果。例如,ChatGPT 的逐字回复即依赖此机制
  3. 数据格式规范
  • 事件流格式:每个事件由字段组成(如 data、id、event),以换行符分隔,事件之间用两个换行符分隔。

下面是一个返回的数据

image-20250512144516616

所以简单理解就是把消息一遍一遍返回,然后前端进行内容渲染就很简单了

调用方式

这里采用了fetchEventSource,一个基于 Fetch API 实现的 JavaScript 库,专为处理 Server-Sent Events(SSE) 设计,旨在克服浏览器原生 EventSource API 的局限性,提供更灵活、可控的实时数据流处理能力

  1. 安装

    npm install @microsoft/fetch-event-source
    
  2. 基本代码结构

    import { fetchEventSource } from '@microsoft/fetch-event-source';
    
    fetchEventSource('/api/stream', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ query: 'data' }),
      onopen: (response) => { /* 连接验证逻辑 */ },
      onmessage: (msg) => { console.log(msg.data); },
      onerror: (err) => { /* 错误处理 */ }
    });
    

​ onmessage里就是返回的内容,腾讯给的字段很丰富,这里根据字段判断进行渲染就可以了

2.每次生成对话自动定位到对话框底部

这个功能算是一个增加用户体验的功能点,实现也很简单,主要利用原生scrollTo方法

初始化时增加滚动监听,并增加判断是用户手动滚动还是自动滚动

sDom.addEventListener('scroll', () => {
	//msgLists为消息内容列表,is_final来判断是否回答完毕
  if (msgLists.value[msgLists.value.length - 1].is_final === false && !jsScrolling.value) {
  	//若满足条件,则设置 userScrolling.value = true,标记用户正在手动干预滚动位置,暂停自动滚动,
    userScrolling.value = true;
  } else {
  //消息已处于最终状态,滚动行为结束
    jsScrolling.value = false;
  }
});

每次接收消息时,在onmessage中执行滚动

 // 对话框滚动至底部
 const sDom = document.querySelector('.client-chat');
     if (!sDom) return;
     //通过 !userScrolling.value 判断用户未手动滚动,此时允许程序触发自动滚动
     if (!userScrolling.value) {
     	jsScrolling.value = true;
     	 sDom.scrollTo({
                top: sDom.scrollHeight
         });
     }
     //当最后一条消息的 is_final 属性为 true(流式响应结束),设置 userScrolling.value = false,允许后续新消息触发自动滚动。
     if (msgLists.value.length > 0 && msgLists.value[msgLists.value.length - 1].is_final === true) {
     userScrolling.value = false;
 }

其他

AI对话框还是其他很多功能点,比如暂停回答、发送内容、历史对话获取、点赞评论等等功能,这些也都是比较常见的功能点,不再一一列举,其实主要核心点还是对话流式渲染,腾讯这方面很给力,给了模版

题外话

在完成这个项目后,进行了一些测试,发现腾讯渲染组件的一个bug,当回答内容过快且是第一条回答内容时,组件内容会截断,就是停止渲染

就像下面这种,页面展示内容:

image-20250512152127729

而实际接口返回:image-20250512152224395

这里可以已经看到返回完了,一开始还是以为是自己的问题,但经过一段排查发现是组件的问题。

试了同样vue2版本未发现这个问题,而vue3版本组件有这个问题,很奇怪。vue3渲染组件地址

目前采用的解决方法是判断返回内容是最后一条时,通过v-if进行重新渲染该组件,返回内容会重新渲染

不知道各位有没有遇到过这个问题?