写点什么

半小时实现 GPT 纯血鸿蒙版

  • 2024-01-13
    福建
  • 本文字数:3350 字

    阅读完需:约 11 分钟

仅需半小时,即可实现纯血鸿蒙版本的 ChatGPT!


废话少说,先看效果图:



如上图所示,这个小 Demo 实现了 AI 智能问答。靠右加粗的文本是用户点击底部提交按钮后出现的;后面靠左对齐的普通文本是来自 AI 的回答内容。当然,整个内容是可滑动浏览的,当内容被滑动时,屏幕右侧将出现滚动条。最后,为什么 UI 是英文呢?因为鸿蒙的模拟器目前没有内置中文输入法,恰好这个 AI 服务也可以用英文来回答。


值得注意的是:这个小 Demo 之所以我称其为 Demo,是因为它的功能实在是太简单了。只有一个基础的 AI 对话功能,如果要做成一个产品,我觉得起码得有个数据持久化的过程,而且还能支持文本的编辑、复制、删除,还要提供收藏功能。更重要的,UI 也需要好好美化一下……


所以,这篇文章就权当抛砖引玉,让大家体会一下开发原生纯血鸿蒙版本的 App 是有多么轻松。


前置条件


  1. DevEco 3.1.1 Release;


  1. 在百度智能云控制台上创建好应用,保存好 API Key 和 Secret Key。



创建项目(5 分钟)


使用 DevEco 创建项目仅需两步,第一步选择类型,第二步填写项目信息。


对于第一步,我们选择 Application(应用程序)->Empty Ability(空白 Ability);

对于第二步,我们选择迄今为止最新的 Compile SDK,即 3.1.0(API 9),Model 选择 Stage,不开启“Enable Super Visual”。其余的内容大家根据自身环境配置进行填写就好。


编码实现(20 分钟)


整个编码过程分为三个步骤,首先添加权限,然后实现 UI,最后实现网络操作。


添加权限(2 分钟)


在整个 App 的项目结构中,找到默认创建的 entry 模块,依次定位到 src->main->module.json5,权限在该文件中进行配置。


这个 Demo 功能非常简单,但仍需对其添加必要的网络访问权限,以确保可以打开网络套接字,完成 HTTP 请求和响应。


代码片段如下:


"requestPermissions": [  {    "name": "ohos.permission.INTERNET",  }],
复制代码


UI 实现(10 分钟)


回过头来看本文最上方的截图,经过布局分析后,可以得到如下结论:整个界面是纵向布局,由两个部分构成。一是可滚动的对话历史;二是下方的输入框和提交按钮。


因此,整个 UI 布局最外层应该是一个 Column,表示纵向布局。其中,占据 90%高度的对话历史区域,占据 10%高度的输入框和按钮区域。


先来看对话历史区域,它其实本质上也是一个 Column,每个 item 就是一段文字。根据文字的类型来判断是居左还是居右。在这个 Column 之外,为了让整个对话历史区域可以上下滚动查看,因此还需要 Scroll 组件将整个 Column 组件包裹起来。


代码片段如下:


@State messagesList: Object[] = [{ 'role': 'user', 'content': 'What can I help you with?' }]// 历史问答Scroll() {  Column() {    ForEach(this.messagesList, (item: Object) => {      if (item['role'] == 'user') {        Text(item['content']).fontSize(20).fontWeight(FontWeight.Bold).width('100%').textAlign(TextAlign.End)      } else {        Text(item['content']).fontSize(20).width('100%').textAlign(TextAlign.Start)      }    })  }.width('100%').alignItems(HorizontalAlign.Center)}.scrollable(ScrollDirection.Vertical).scrollBar(BarState.Auto).scrollBarColor(Color.Gray).scrollBarWidth(10).edgeEffect(EdgeEffect.Fade).height('90%').width('100%')
复制代码


请注意这段代码中的 messagesList,它是一个对象数组。role 表示角色,即该条消息是用户发送的,还是服务器返回的;content 表示文字内容。


在由 Scroll 包裹的 Column 组件之中,使用了 ArkTS 提供的 ForEach 渲染方式进行逐条消息的渲染,并使用 if...else...条件判断语句对角色来源进行区分。


再来看底部的输入框和操作按钮,由于它们是横向排列的,所以使用 Row 组件进行布局。在此,我将文本输入框设定了 80%的宽度,提交按钮设定了 20%的宽度。


代码片段如下:


@State questionStr: string = ''// 文本输入和提交Row() {  TextInput({ placeholder: 'Please input your question', text: this.questionStr })    .type(InputType.Normal)    .onChange((value: string) => {      this.questionStr = value    })    .width('80%')  Button('提交').type(ButtonType.Capsule).onClick(() => {    this.messagesList.push({ 'role': 'user', 'content': this.questionStr })    getAnswer(this.questionStr, this.messagesList)    this.questionStr = ''  }).width('20%')}.height('10%').width('100%')
复制代码


在这段代码中,questionStr 表示输入框中的文字字符串。getAnswer()函数发起并接收 HTTP 请求,向服务器提交用户问题字符串,并等待接收响应内容,将问题的回答放入 messagesList 对象数组之中,完成整个问答流程。


最后,将上述 Scroll 组件和 Row 组件一并放入 Column 内,完成整个 UI 绘制。


网络访问(8 分钟)


根据百度官方的开发文档,完成整个 AI 问答过程至少需要两个步骤:获取 access_token 和获取问题答案。

获取 access_token 的过程在程序一开始就可以进行了,因为在后续的操作中都要用到 access_token。因此,我声明了 access_token 的全局变量,并将获取该值的方法封装为 getToken()函数,具体代码如下:


var access_token: string = ''function getToken() {  let httpRequest = http.createHttp();  httpRequest.on('headersReceive', (header) => {    console.info('header: ' + JSON.stringify(header));  });  httpRequest.request(    "https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=[你的应用的API Key]&client_secret=[你的应用的Secret Key]",    {      method: http.RequestMethod.POST,      header: {        'Content-Type': 'application/json',      },      expectDataType: http.HttpDataType.OBJECT,      usingCache: true,      priority: 1,      connectTimeout: 60000,      readTimeout: 60000,      usingProtocol: http.HttpProtocol.HTTP1_1,    }, (err, data) => {    if (!err) {      access_token = data.result['access_token']    } else {      httpRequest.off('headersReceive')      httpRequest.destroy()    }  });}
复制代码


getToken()函数我在回调的 onPageShow()函数中使用,即程序启动后,就获取 access_token。


最后,我们来实现 getAnswer()函数,它是向服务器提交问题和接收响应的函数,具体代码如下:


function getAnswer(questionStr: string, messageList: Object[]) {  let httpRequest = http.createHttp();  httpRequest.on('headersReceive', (header) => {    console.info('header: ' + JSON.stringify(header));  });  httpRequest.request(    "https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/yi_34b_chat?access_token=" + access_token,    {      method: http.RequestMethod.POST,      header: {        'Content-Type': 'application/json'      },      extraData: { "messages": [{        "role": "user",        "content": questionStr      }] },      expectDataType: http.HttpDataType.OBJECT,      usingCache: true,      priority: 1,      connectTimeout: 60000,      readTimeout: 60000,      usingProtocol: http.HttpProtocol.HTTP1_1,    }, (err, data) => {    if (!err) {      messageList.push({ 'role': 'assist', 'content': data.result['result'] })    } else {      httpRequest.off('headersReceive')      httpRequest.destroy()    }  }  );}
复制代码


还需要做些别的吗?


答案是:没有了,真的不用了。


运行项目(5 分钟)


无论是本地模拟器,还是真机,抑或是远程模拟器,只需要启动其中一个,然后让这个程序跑起来吧!如无意外,你将会得到一个超级简易的 AI 问答机器人,纯血鸿蒙版。


当然,这里我写了需要 5 分钟,是包括了下载模拟器镜像的时间,如果你有真机或是使用远程模拟器的话,那就会更快了。


最后,我们来对比一下。我完成上述功能,Index.ets 一共 117 行,你的呢?


文章转载自:萧文翰

原文链接:https://www.cnblogs.com/wenhanxiao/p/17960622

体验地址:http://www.jnpfsoft.com/?from=001

用户头像

还未添加个人签名 2023-06-19 加入

还未添加个人简介

评论

发布
暂无评论
半小时实现GPT纯血鸿蒙版_人工智能_不在线第一只蜗牛_InfoQ写作社区