半小时实现GPT纯血鸿蒙版
僅需半小時,即可實現純血鴻蒙版本的ChatGPT!
廢話少說,先看效果圖:
如上圖所示,這個小Demo實現了AI智能問答。靠右加粗的文本是用戶點擊底部提交按鈕后出現的;后面靠左對齊的普通文本是來自AI的回答內容。當然,整個內容是可滑動瀏覽的,當內容被滑動時,屏幕右側將出現滾動條。最后,為什么UI是英文呢?因為鴻蒙的模擬器目前沒有內置中文輸入法,恰好這個AI服務也可以用英文來回答。
值得注意的是:這個小Demo之所以我稱其為Demo,是因為它的功能實在是太簡單了。只有一個基礎的AI對話功能,如果要做成一個產品,我覺得起碼得有個數據持久化的過程,而且還能支持文本的編輯、復制、刪除,還要提供收藏功能。更重要的,UI也需要好好美化一下……
所以,這篇文章就權當拋磚引玉,讓大家體會一下開發原生純血鴻蒙版本的App是有多么輕松。
前置條件
- DevEco 3.1.1 Release;
- 在百度智能云控制臺上創建好應用,保存好API Key和Secret Key。
- 關于1:下載和安裝文檔鏈接;
- 關于2:百度智能云控制臺地址鏈接。
創建項目(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行,你的呢?
總結
以上是生活随笔為你收集整理的半小时实现GPT纯血鸿蒙版的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 面试官:请说一下Mysql事务实现原理
- 下一篇: ChatGPT的中转站(欧派API) o