現(xiàn)代社會節(jié)奏較快,人們看書可能不僅僅只用眼睛,有時候也會用耳朵來“聽書”,語音播報由此誕生,并通過人工智能語音識別引擎實現(xiàn)。HarmonyOS基于華為智慧引擎(HUAWEI HiAI Engine)中的語音識別引擎,向開發(fā)者提供人工智能應用層API,該技術(shù)提供將文本轉(zhuǎn)換為語音并進行播報的能力,可應用于以下兩種場景:
·實時語音交互
生成音頻信息用于語音交互,例如與智能音箱或手機智能助手的交互,后臺會將回答的信息以音頻方式進行語音播報。
·超長文本播報
用于小說、新聞等較長文本的自動朗讀。
本期我們就為大家?guī)沓L文本播報場景下的基于AI語音播報能力的Codelab。當用戶輸入相關(guān)文本內(nèi)容時,點擊“語音播放”按鈕,程序即對文本進行播報并同步記錄語音播報的耗時時長,并呈現(xiàn)在頁面上,是不是能滿足計時“聽書”的需求呢?讓我們一起來看看吧。
首先,讓我們梳理一遍開發(fā)要點:
1)UI頁面的構(gòu)建
2)語音播報接口調(diào)用
3)計時器的創(chuàng)建
4)線程間通信處理機制的使用
請注意,由于需要時刻進行觀察,在邏輯代碼實現(xiàn)中我們會穿插HiLog日志打印,下面我們會逐一指出。
在正式開始敲代碼之前,開發(fā)者們需要先下載安裝Huawei DevEco Studio,如果對這個流程不甚熟悉,可以參照官網(wǎng)的教程來操作。Huawei DevEco Studio安裝指南:
https://developer.harmonyos.com/cn/docs/documentation/doc-guides/software_install-0000001053582415
【注意】本次Codelab針對的是步驟拆解和重點講解,限于篇幅原因不會展示完整代碼,開發(fā)者們可在文末【閱讀原文】中獲取完整代碼哦~
我們打開Huawei DevEco Studio,選擇Phone中的Empty Feature Ability(Java)模板工程,本次Codelab我們將在該模板下完成。有如下操作:
1.我們將在entrysrcmain esourcesaselayoutability_main.xml中構(gòu)建UI頁面;
2.我們在entrysrcmain esourcesasegraphic目錄下新建background_button.xml文件用于實現(xiàn)“語音播報”按鈕的樣式優(yōu)化;
3.文中的邏輯代碼我們將在 entrysrcmainjavacomexampleailistenersliceMainAbilitySlice.java文件中實現(xiàn);讓我們馬上開始。
1)UI界面構(gòu)建
縱觀這個頁面,主要分為以下幾個部分:
·標題
即“AI語音播報”這幾個字,這里我們使用Text組件。
·文本輸入框
可供用戶輸入想要播報的文本內(nèi)容,最大不超過100,000個字符。為了便于大家理解,這里我們已經(jīng)給大家準備了一段文本,我們使用TextField組件來完成。
·播報按鈕
此處展示的文本是“語音播報”,使用的是Button組件。值得注意的是,這里需要優(yōu)化按鈕樣式,如添加陰影及優(yōu)化其為膠囊按鈕,讓按鈕更為醒目美觀。
如前面提到的,我們將在background_button.xml文件中優(yōu)化按鈕樣式,通過color 設(shè)置按鈕背景顏色,通過radius的半徑實現(xiàn)圓角, 代碼如下:
《?xml version=“1.0” encoding=“utf-8”?》 《shape xmlns:ohos=“http://schemas.huawei.com/res/ohos” ohos:shape=“rectangle”》 《corners ohos:radius=“40”/》 《solid ohos:color=“#e9e9e9”/》 《/shape》
·計時文本
用于顯示“播報耗時:0 s”文本,同樣使用Text組件完成。
2)語音播報接口調(diào)用
構(gòu)建完了頁面,我們來到今天的重頭戲之一,也就是使用AI語音播報能力開發(fā)程序。語音播報(Text to Speech,以下簡稱TTS),提供將文本轉(zhuǎn)換為語音并進行播報的能力。
·語音播報官網(wǎng)資料
https://developer.harmonyos.com/cn/docs/documentation/doc-guides/ai-tts-overview-0000001050724400
這里我們主要分三個部分實現(xiàn),創(chuàng)建TTS客戶端、TTS客戶端的初始化和調(diào)用相關(guān)方法對文本進行播報。下面我們來詳細看看各個接口如何調(diào)用。
1. TTS客戶端創(chuàng)建
調(diào)用void create接口創(chuàng)建TTS客戶端。
private void initTtsEngine() { TtsClient.getInstance().create(this, ttsListener); }
2.TTS客戶端的初始化
當TTS客戶端創(chuàng)建成功,即eventType取值
TtsEvent.CREATE_TTS_CLIENT_SUCCESS時,進行TTS客戶端的初始化。
public void onEvent(int eventType, PacMap pacMap) { HiLog.info(LABEL_LOG, “onEvent.。。”); // 定義TTS客戶端創(chuàng)建成功的回調(diào)函數(shù) if (eventType == TtsEvent.CREATE_TTS_CLIENT_SUCCESS) { TtsParams ttsParams = new TtsParams(); ttsParams.setDeviceId(UUID.randomUUID().toString()); initItsResult = TtsClient.getInstance().init(ttsParams); } }
同時我們引入HiLog日志打印,便于觀察相關(guān)情況。
3.調(diào)用相關(guān)方法對文本進行播報
這里我們調(diào)用TtsClient.getInstance().speakText()方法對文本進行播報,同樣也引入HiLog日志打印用于觀察初始化是否成功。
private void readText(Component component) { if (initItsResult) { HiLog.info(LABEL_LOG, “initItsResult is true, speakText”); TtsClient.getInstance().speakText(infoText.getText(), null); } else { HiLog.error(LABEL_LOG, “initItsResult is false”); } }
3)計時器的創(chuàng)建
本Codelab將以秒為單位對AI語音播報速度進行計時,故而我們需要一個計時器。在HarmonyOS中,我們通過計時器Timer和計時器任務(wù)TimerTask類來實現(xiàn)。這里使用到的是構(gòu)建和取消兩種方法,比較簡單。大家可以通過官網(wǎng)資料進一步了解。
·Timerhttps://developer.harmonyos.com/cn/docs/documentation/doc-references/timer-0000001054358579
·TimerTask
https://developer.harmonyos.com/cn/docs/documentation/doc-references/timertask-0000001054558601
同樣我們使用HiLog日志打印來觀察文本語音播報的開始和結(jié)束。
4)線程間通信處理機制的使用
接下來我們將提到本Codelab另外一個重頭戲——線程間通信處理機制的使用。在啟動應用時,系統(tǒng)會為該應用創(chuàng)建一個稱為“主線程”的執(zhí)行線程。該線程隨著應用創(chuàng)建或消失,是應用的核心線程。具體到本Codelab,UI界面的顯示和更新等操作,就是更新播報耗時的界面,是在主線程上進行的,因此主線程也稱為UI線程。示例中分配的是9015,如圖所示:
然而在實際項目中,開發(fā)者可能面臨許多耗時的操作,比如說下載文件、查詢數(shù)據(jù)庫,具體到本Codelab,就是語音播報功能和計時器功能,這些復雜的操作會阻塞 UI線程,導致界面無響應,帶來非常不好的用戶體驗。
因此,我們需要將這些耗時操作放到子線程中,避免阻塞主線程,比如在示例中,我們把AI語音播報放在子線程9275中執(zhí)行:
但同時,我們又需要把操作的結(jié)果數(shù)據(jù)反饋給UI線程,這個時候就必須引入線程間通信處理機制。因此,HarmonyOS 給Java應用開發(fā)提供了EventHandler機制,可以通過EventRunner創(chuàng)建新線程,將耗時的操作放到新線程上執(zhí)行。這樣既不阻塞原來的線程,任務(wù)又可以得到合理的處理。
每一個EventHandler和指定的EventRunner所創(chuàng)建的新線程綁定,并且該新線程內(nèi)部有一個事件隊列。EventHandler可以投遞指定的InnerEvent事件或Runnable任務(wù)到這個事件隊列。
EventRunner從事件隊列里循環(huán)地取出事件:
1)如果取出的事件是InnerEvent事件,將在EventRunner所在線程執(zhí)行processEvent回調(diào);
2)如果取出的事件是Runnable任務(wù),將在EventRunner所在線程執(zhí)行Runnable的run回調(diào)。
·線程間通信開發(fā)概述
https://developer.harmonyos.com/cn/docs/documentation/doc-guides/inter-thread-overview-0000000000038958
在本例中,開始發(fā)音的時候發(fā)送EVENT_MSG_TIME_COUNT事件,此時程序開始計時并更新UI頁面,示例代碼如下所示:
@Override public void onSpeechStart(String utteranceId) { // 開始計時 HiLog.info(LABEL_LOG, “onSpeechStart.。。”); if (timer == null && timerTask == null) { timer = new Timer(); timerTask = new TimerTask() { public void run() { handler.sendEvent(EVENT_MSG_TIME_COUNT); } }; timer.schedule(timerTask, 0, 1000); } }
此時取出的事件是Runnable,需要將Runnable任務(wù)投遞到新的線程,在EventRunner所在線程執(zhí)行Runnable的run回調(diào),并按照優(yōu)先級和延時進行處理,。這里是同步更新UI頁面,代碼如下所示:
private EventHandler handler = new EventHandler(EventRunner.current()) { @Override protected void processEvent(InnerEvent event) { switch (event.eventId) { case EVENT_MSG_TIME_COUNT: getUITaskDispatcher().delayDispatch(new Runnable() { @Override public void run() { time = time + 1; HiLog.info(LABEL_LOG, “播報耗時:” + Integer.toString(time) + “ s”); timeText.setText(“播報耗時:” + Integer.toString(time) + “ s”); } }, 0); break; default: break; } } };
至此,我們已經(jīng)完成本次Codelab的所有關(guān)鍵步驟。
通過這個Codelab,大家可以學習到AI語音播報、線程間通信和計時器的使用方法。
編輯:jq
-
JAVA
+關(guān)注
關(guān)注
19文章
2976瀏覽量
105223 -
AI
+關(guān)注
關(guān)注
87文章
31711瀏覽量
270511 -
語音播報
+關(guān)注
關(guān)注
1文章
28瀏覽量
14601 -
鴻蒙
+關(guān)注
關(guān)注
57文章
2397瀏覽量
43098 -
HarmonyOS
+關(guān)注
關(guān)注
79文章
1983瀏覽量
30637 -
OpenHarmony
+關(guān)注
關(guān)注
25文章
3753瀏覽量
16668
原文標題:【Codelab】懶人“看”書新法—鴻蒙語音播報,到底如何實現(xiàn)?
文章出處:【微信號:HarmonyOS_Dev,微信公眾號:HarmonyOS開發(fā)者】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
評論