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

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

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

相关推荐
雨白5 小时前
Android 快捷方式实战指南:静态、动态与固定快捷方式详解
android
hqk5 小时前
鸿蒙项目实战:手把手带你实现 WanAndroid 布局与交互
android·前端·harmonyos
TT_Close5 小时前
【Flutter×鸿蒙】一个"插队"技巧,解决90%的 command not found
flutter·harmonyos
LING5 小时前
RN容器启动优化实践
android·react native
恋猫de小郭8 小时前
Flutter 发布官方 Skills ,Flutter 在 AI 领域再添一助力
android·前端·flutter
Kapaseker13 小时前
一杯美式搞懂 Any、Unit、Nothing
android·kotlin
黄林晴13 小时前
你的 Android App 还没接 AI?Gemini API 接入全攻略
android
恋猫de小郭1 天前
2026 Flutter VS React Native ,同时在 AI 时代 VS Native 开发,你没见过的版本
android·前端·flutter
冬奇Lab1 天前
PowerManagerService(上):电源状态与WakeLock管理
android·源码阅读
BoomHe1 天前
Now in Android 架构模式全面分析
android·android jetpack