在小程序中实现ChatGPT 聊天打字兼自动滚动效果

2023-12-05 0 212
目录
  • 一 前言
  • 二 实现打字效果
    • 2.1.预热内容—数据请求与接收
    • 2.2.小程序中接口处理
    • 2.3.打字效果实现
  • 三 如何实现视图跟随内容滚动
    • 3.1 实现原理
  • 四 总结

    一 前言

    ChatGPT 已经长时间大火,未来将会是AI的天下。人们需要更多地学习和掌握AI,而不是被AI所取代。

    目前市面上已经有很多类似 chatGPT 的智能应用,应用有可能是 web h5 应用,也有可能是小程序或者是 Native 应用。随着 ChatGPT 深入,移动端也会再次火爆起来。

    在 ChatGPT 的背景下,我们今天来聊聊在小程序中怎么实现类似 chatGPT 的聊天打字效果,并且实现滚动效果,具体如下:

    在小程序中实现ChatGPT 聊天打字兼自动滚动效果

    这篇文章将深入一下内容:

    • 小程序怎么样实现动态打字效果。
    • 怎么实现随打字效果滚动。
    • 请求分片知识点。
    • scroll-view 细节处理等。

    二 实现打字效果

    2.1.预热内容—数据请求与接收

    开发者可以接入 openAi 提供的接口,实现自定义的问答流程。在聊天会话中,我们问 chatGPT 一句话:

    介绍一下跨端开发

    那么和平常的请求不同的是,数据并不是一次性返回的,而是采用 stream 流式返回的。我们可以在 Network 中看到 response 的大体结构:

    在小程序中实现ChatGPT 聊天打字兼自动滚动效果

    如上可以看到返回的 text 是分片处理的,每次会返回一小段内容,只要前端根据返回这一小段内容就可以了,也就自然形成了打字的效果。

    可能会有同学好奇,这种分片的数据结构,前端应该怎么接收呢?实际很简单,我们拿 axios 为例子,开发者可以通过监听onDownloadProgress 事件来接受服务端返回的文本片段。具体例子如下:

    axios({
    method: \’post\’,
    url: \’https:xxx.xxx,
    onDownloadProgress: function({ event }) {
    const xhr = event.target
    const { responseText } = xhr
    /* 获取返回的内容,本质上是 json 字符串 */
    let chunk = responseText
    try{
    /* 序列化返回的内容 */
    const data = JSON.parse(chunk)
    /* chatGPT 返回的内容 */
    console.log(data.text)
    }catch(e){
    }
    }
    })

    这里描述请求的流程,通过 onDownloadProgress 来监听返回的内容,然后获取到返回的内容,JSON.parse 解析内容,这里有一个注意事项,就是对于 JSON.parse 应该加上 try catch ,防止解析的失败。

    2.2.小程序中接口处理

    小程序没有如上 axios 里面监听 stream 流式响应数据的能力,也没有处理 onDownloadProgress 的回调函数。简单来说 onDownloadProgress 的实现,本质上是 axios 在浏览器发起 http 请求,会创建一个 XHR 对象,其用于发送请求和接收响应,在创建 XHR 对象后,axios 会注册一个 progress 事件监听器到 XHR 对象上,用于获取下载的进度信息。

    那么小程序中如何实现分片流式下载呢?在小程序中,统一收口到 request 中,在 request 中可以用 RequestTask 的 onChunkReceived 来接收服务端的分片数据。这个方法可以监听 Transfer-Encoding Chunk Received 事件。当接收到新的 chunk 时触发。

    我们来看看具体怎么使用:

    const requestTask = wx.request({
    enableChunked:true, // 开启分片模式

    })
    requestTask.onChunkReceived((res)=>{
    // 接收分片的数据
    })

    这样就可以通过分片来实现打字的效果。

    2.3.打字效果实现

    接下来我们看一下小程序是如何实现打字效果的,先不考虑返回的数据是 stream 流式结构,先认为返回的数据格式是整个文本,那么应该怎么样处理文本呢。

    首先我们聊天的内容如下所示:

    在小程序中实现ChatGPT 聊天打字兼自动滚动效果

    如上, 每一个消息都是一个 message-item ,所有的 message 保存到了 messageList 列表中,在 wxml 中如下所示:

    <view wx:for=\”{{messageList}}\” wx:key=\”id\” id=\”item-{{item.id}}\”>
    <message-item
    data-index=\”{{index}}\”
    role=\”{{item.role}}\”
    content=\”{{item.content}}\”
    finished=\”{{item.finished}}\”
    bind:share=\”handleMessageShare\”
    />
    </view>

    如上,可以看到 message-item 保存了一条会话内容。

    当我们发一条信息的时候,产生一条 message-item 。接下来 chatGPT 返回内容后,也会产生一条 message-item ,要实现打字效果就是这条 message-item 。

    我们只需要将这条 message-item 的内容,通过 setData 方式分片渲染就可以了。比如我们想打字实现 ‘您好GPT’,那么分五次 setData 渲染就可以了,比如如下:

    • 您好
    • 您好G
    • 您好GP
    • 您好GPT

    如上就是分五次渲染,每一次渲染的结果。接下来就是代码的实现。

    this.handleRequestResolve(data.text)

    比如 chatGPT 每次返回一条内容,都用 handleRequestResolve 函数处理返回的内容。看一下 handleRequestResolve 的核心实现。

    handleRequestResolve(result){
    const timestamp = Date.now();
    const index = this.data.messageList.length
    const newMessageList = `messageList[${index}]`
    const contentCharArr = result.trim().split(\”\”)
    const content_key = `messageList[${index}].content`
    const finished_key = `messageList[${index}].finished`
    this.setData({
    thinking: false,
    [newMessageList]: {
    id: timestamp,
    role: \’assistant\’,
    finished: false
    }
    })
    currentContent = \’\’
    this.showText(0, content_key, finished_key, contentCharArr);
    }

    在 handleRequestResolve 中会构建一条新的 message-item ,然后就是showText展示内容,来看一下 showText 怎么处理内容。

    showText(key = 0, content_key, finished_key, value) {
    /* 所有内容展示完成 */
    if (key >= value.length) {
    this.setData({
    loading: false,
    [finished_key]: true
    })
    wx.vibrateShort()
    return;
    }
    currentContent = currentContent + value[key]
    /* 渲染回话内容 */
    this.setData({
    [content_key]: currentContent,
    })
    setTimeout(() => {
    /* 递归渲染内容 */
    this.showText(key + 1, content_key, finished_key, value);
    }, 50);
    },

    这样用递归就实现了打字效果。我们来看一下效果:

    在小程序中实现ChatGPT 聊天打字兼自动滚动效果

    通过上面可以看到,在文字打印的过程中,列表不能跟随一起滚动,当文字内容超出一屏幕之后,视图就停止了(本质上数据在后面追加),这是一个很不好的效果。

    接下来,我们进行优化处理,让视图可以根据内容自动滚动。

    三 如何实现视图跟随内容滚动

    3.1 实现原理

    实现视图跟随内容滚动实际很简单,因为 message-item 的容器本质上就是一个 scroll-view , 那么想要 scroll-view 视图跟随返回内容变化,只需要动态设置 scroll-view 的 scroll-top 值就可以了。

    视图跟随内容滚动,本质上就是让 scroll-view 一直自动滚动到底部, 如何要让 scroll-view 一直滚动到底部呢?先看一下如下示意图:

    在小程序中实现ChatGPT 聊天打字兼自动滚动效果

    如上可以看到,想让 scroll-view 一直滚动到底部,只需要让 scroll-top 等于 scroll-view 内容高度减去 scroll-view 容器本身高度就可以了。

    所以需要我们给 scroll-view 里面的内容,用一个 view 包裹如下:

    在小程序中实现ChatGPT 聊天打字兼自动滚动效果

    如上 scroll-view 的类名为content, scroll-view 内部元素的类名为scroll-view-content,接下来可以通过如下代码设置 scroll-top 值了。

    handleScollTop() {
    return new Promise((resolve) => {
    const query = wx.createSelectorQuery()
    query.select(\’.content\’).boundingClientRect()
    query.select(\’.scroll-view-content\’).boundingClientRect()
    query.exec((res) => {
    const scrollViewHeight = res[0].height
    const scrollContentHeight = res[1].height
    if (scrollContentHeight > scrollViewHeight) {
    const scrollTop = scrollContentHeight – scrollViewHeight
    this.setData({
    scrollTop
    }, () => {
    resolve()
    })
    }else{
    resolve()
    }
    })
    })
    },

    如上通过 createSelectorQuery 分别获取 scroll-view 和 scroll-view 内部元素的高度,两者的差值就是 scroll-top 值。

    接下里在渲染会话内容的时候,渲染之后,调用 handleScollTop 来动态设置 scroll-top 就可以了。

    showText(key = 0, content_key, finished_key, value) {
    if (key >= value.length) {
    this.setData({
    loading: false,
    [finished_key]: true
    })
    wx.vibrateShort()
    return;
    }
    currentContent = currentContent + value[key]
    this.setData({
    [content_key]: currentContent,
    },()=>{
    this.handleScollTop().then(()=>{
    setTimeout(() => {
    this.showText(key + 1, content_key, finished_key, value);
    }, 20);
    })
    })
    },

    这里有一个小细节,就是在渲染上一次文本内容之后,需要先校验一下 scroll-top 值,然后再次调用 showText 来渲染会话内容。

    我们来看一下效果。

    在小程序中实现ChatGPT 聊天打字兼自动滚动效果

    后续优化: 本质上不需要在每次 showText 之后都通过 createSelectorQuery 异步获取元素 scroll-top 并再次渲染,这无疑是性能的浪费,实际可以控制 createSelectorQuery 到 setData 设置 scroll-top 值的频率来提升性能。

    四 总结

    感兴趣的同学可以自己实现一个会话打字效果,其中还有很多小细节这里就不讲了。

    以上就是小程序实现ChatGPT 聊天打字兼自动滚动效果的详细内容,更多关于ChatGPT聊天自动滚动的资料请关注悠久资源网其它相关文章!

    您可能感兴趣的文章:

    • macbook安装环境chatglm2-6b的详细过程
    • ChatGPT平替- ChatGLM多用户并行访问部署过程
    • ChatGPT平替-ChatGLM环境搭建与部署运行效果
    • ChatGLM 集成LangChain工具详解
    • 基于prompt tuning v2训练好一个垂直领域的chatglm-6b
    • ChatGPT将批量文档翻译成中文的方法
    • 一文带你快速梳理ChatGPT、GPT4和OpenAPI的关系
    • 深入探究ChatGPT的工作原理
    • linux环境部署清华大学大模型最新版chatglm2-6b图文教程

    收藏 (0) 打赏

    感谢您的支持,我会继续努力的!

    打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
    点赞 (0)

    悠久资源 编程综合 在小程序中实现ChatGPT 聊天打字兼自动滚动效果 https://www.u-9.cn/biancheng/bczonghe/98514.html

    常见问题

    相关文章

    发表评论
    暂无评论
    官方客服团队

    为您解决烦忧 - 24小时在线 专业服务