动动小手学鸿蒙 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)
  }
}

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

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

相关推荐
*才华有限公司*1 小时前
安卓前后端连接教程
android
氦客1 小时前
Android Compose中的附带效应
android·compose·effect·jetpack·composable·附带效应·side effect
雨白2 小时前
Kotlin 协程的灵魂:结构化并发详解
android·kotlin
我命由我123452 小时前
Android 开发问题:getLeft、getRight、getTop、getBottom 方法返回的值都为 0
android·java·java-ee·android studio·android jetpack·android-studio·android runtime
Modu_MrLiu2 小时前
Android实战进阶 - 用户闲置超时自动退出登录功能详解
android·超时保护·实战进阶·长时间未操作超时保护·闲置超时
Jeled2 小时前
Android 网络层最佳实践:Retrofit + OkHttp 封装与实战
android·okhttp·kotlin·android studio·retrofit
信田君95272 小时前
瑞莎星瑞(Radxa Orion O6) 基于 Android OS 使用 NPU的图片模糊查找APP 开发
android·人工智能·深度学习·神经网络
tangweiguo030519873 小时前
Kotlin 实现 Android 网络状态检测工具类
android·网络·kotlin
nvvas4 小时前
Android Studio JAVA开发按钮跳转功能
android·java·android studio