动动小手学鸿蒙 HarmonyOS APP(04)AI聊天页面

ChatGpt类产品在输出答案的时候有一个明显特征,回答问题的文字是一个一个字蹦出来的。这种展示方式基于人工智能答案生成原理而设计。因为大语言模型在生成答案时就是逐字逐句一点点生成的。如果等整篇答案完全生成后再返回给前端,用户等待的时间就太长了。会严重影响用户体验。

根据ChatGpt介绍可以了解到,前端请求并不是使用webSocket,由于WebSocket需要client和server都持续占用一个socket,server侧成本比较高。ChatGPT使用的是一种折中方案: server-sent event(简称SSE).

SSE 模式下,client只需要向server发送一次请求,server就能持续输出,直到需要结束。 SSE仍然使用HTTP作为应用层传输协议,充分利用HTTP的长连接能力,实现服务端推送能力。

从代码层面来看,SSE模式与单次HTTP请求不同的点有:

  1. client端需要开启 keep-alive,保证连接不会超时。
  2. HTTP响应的Header包含 Content-Type=text/event-stream,Cache-Cnotallow=no-cache 等。
  3. HTTP响应的body一般是 "data: ..." 这样的结构。
  4. HTTP响应里可能有一些空数据,以避免连接超时。

看到这里,我们可以了解到通过这种SSE请求的方式,前端正是逐字得到的答案,所以在展示时就是按请求返回来展示出陆陆续续得到的文本答案。

了解了原理,本篇主要展示在鸿蒙中模拟展示这种逐字文本展示的AI聊天界面。

先看下效果:

本demo中仅实现UI效果,并未真正发送请求来获得数据。通过预置文本和定时器来实现一个字一个字蹦出来的效果。

聊天页面中外层为Stack布局,底部是输入TextInput和发送按钮,上部按顺序展示用户输入和系统回答文本。

正式项目中需要考虑加入加载动画,请求异常处理,代码以及表格图片等展示组件,聊天区域的滚动展示等问题。

非常简单,就直接贴代码了

ts 复制代码
build() {
  Stack({ alignContent: Alignment.Bottom }) {
    Column() {
      Row() {
        Text('你好呀我是聊天助手,有什么话想对我说吗?希望可以和你一起分享生活中的点点滴滴!')
          .fontSize(18)
          .fontColor('#1a1c1f')
          .padding(12)
          .backgroundColor('#f4f6f9')
          .margin({top: 12})
          .clip(new Rect({ width: '100%', height: '100%', radius: 12 }))
      }
      .width('100%')
      .justifyContent(FlexAlign.Start)

      if (this.answer.length > 0) {
        Row() {
          Text(this.question)
            .fontSize(18)
            .fontColor('#fefbf9')
            .padding(12)
            .margin({top: 12})
            .backgroundColor('#2e74f7')
            .clip(new Rect({ width: '100%', height: '100%', radius: 12 }))
        }
        .width('100%')
        .justifyContent(FlexAlign.End)

        Row() {
          Text(this.answer)
            .fontSize(18)
            .fontColor('#1a1c1f')
            .padding(12)
            .backgroundColor('#f4f6f9')
            .margin({top: 12})
            .clip(new Rect({ width: '100%', height: '100%', radius: 12 }))
        }
        .width('100%')
        .justifyContent(FlexAlign.Start)
      }
    }
    .height('100%')
    .width('100%')
    .padding(12)

    Row() {
      TextInput()
        .fontSize(18)
        .width('80%')
        .fontColor('#fefbf9')
        .padding(12)
        .clip(new Rect({ width: '100%', height: '100%', radius: 12 }))

      Blank().width(12)

      Text('发送')
        .fontSize(18)
        .padding(8)
        .fontColor('#fefbf9')
        .backgroundColor('#2e74f7')
        .clip(new Rect({ width: '100%', height: '100%', radius: 12 }))
        .onClick(() => {
          this.answer = '';
          this.pos = 0;
          clearInterval(this.intervalID);
          setTimeout(() => {
            this.intervalID = setInterval(() => {
              if (this.pos < this.text.length) {
                this.answer = this.answer.concat(this.text.charAt(this.pos))
                this.pos += 1;
              } else {
                clearInterval(this.intervalID);
              }
            }, 100)
          }, 500);
        })
    }
    .width('100%')
    .height(80)
    .padding({left: 12, right: 12})
    .alignItems(VerticalAlign.Center)
    .justifyContent(FlexAlign.End)
  }
}

通过本例可以熟悉这些知识:基础组件布局组件定时器等常用鸿蒙开发知识。

边学边写,欢迎留言。感谢各位大佬点赞

相关推荐
baobao熊1 小时前
【HarmonyOS】时间处理Dayjs
华为·harmonyos
网络研究院2 小时前
Android 安卓内存安全漏洞数量大幅下降的原因
android·安全·编程·安卓·内存·漏洞·技术
凉亭下2 小时前
android navigation 用法详细使用
android
小比卡丘5 小时前
C语言进阶版第17课—自定义类型:联合和枚举
android·java·c语言
前行的小黑炭5 小时前
一篇搞定Android 实现扫码支付:如何对接海外的第三方支付;项目中的真实经验分享;如何高效对接,高效开发
android
zhongcx6 小时前
鸿蒙应用示例:DevEco Testing 工具的常用功能及使用场景
harmonyos
落落落sss7 小时前
MybatisPlus
android·java·开发语言·spring·tomcat·rabbitmq·mybatis
代码敲上天.7 小时前
数据库语句优化
android·数据库·adb
@海~涛8 小时前
鸿蒙OpenHarmony
华为·harmonyos
GEEKVIP10 小时前
手机使用技巧:8 个 Android 锁屏移除工具 [解锁 Android]
android·macos·ios·智能手机·电脑·手机·iphone