[文章]HarmonyOS AI语音播报、朗读输入的文字内容

阅读量0
0
3
1. 介绍      HarmonyOS为应用提供了丰富的AI(Artificial Intelligence)能力,支持开箱即用。开发者可以灵活、便捷地选择AI能力,让应用变得更加智能。语音播报(Text to Speech,下文简称TTS),基于华为智慧引擎(HUAWEI HiAI Engine)中的语音识别引擎,向开发者提供人工智能应用层API。该技术提供将文本转换为语音并进行播报的能力。

通过本项目,您将学习到AI语音播报、线程间通信和计时器的使用方法。项目具体示例如下:程序主体部分是一个可输入文本框,您可以在其中输入需要播报的文本文案,点击"语音播报"即可对文本进行播报,程序会同步记录语音播报的耗时。

   

2. 搭建HarmonyOS环境   
我们首先需要完成HarmonyOS开发环境搭建,可参照如下步骤进行。
  • 安装DevEco Studio,详情请参考下载和安装软件。
  • 设置DevEco Studio开发环境,DevEco Studio开发环境依赖于网络环境,需要连接上网络才能确保工具的正常使用,可以根据如下两种情况来配置开发环境:
    • 如果可以直接访问Internet,只需进行下载HarmonyOS SDK操作。
    • 如果网络不能直接访问Internet,需要通过代理服务器才可以访问,请参考配置开发环境。
  • 开发者可以参考以下链接,完成设备调试的相关配置:
    • 使用真机进行调试
    • 使用模拟器进行调试
3. 语音播报      
TTS提供将文本转换为语音并进行播报的能力。TTS的初始化代码如下所示:
步骤 1 -  创建TTS客户端
  1. private void initTtsEngine() {
  2.     TtsClient.getInstance().create(this, ttsListener);
  3. }
复制代码

步骤 2 -  实现TTS客户端创建成功的回调函数
  1. public void onEvent(int eventType, PacMap pacMap) {
  2.     HiLog.info(LABEL_LOG, "onEvent...");
  3.     // 定义TTS客户端创建成功的回调函数
  4.     if (eventType == TtsEvent.CREATE_TTS_CLIENT_SUCCESS) {
  5.         TtsParams ttsParams = new TtsParams();
  6.         ttsParams.setDeviceId(UUID.randomUUID().toString());
  7.         initItsResult = TtsClient.getInstance().init(ttsParams);
  8.     }
  9. }
复制代码

步骤 3 -  调用TtsClient.getInstance().speakText()方法对文本进行播报
  1. private void readText(Component component) {
  2.     if (initItsResult) {
  3.         HiLog.info(LABEL_LOG, "initItsResult is true, speakText");
  4.         TtsClient.getInstance().speakText(infoText.getText(), null);
  5.     } else {
  6.         HiLog.error(LABEL_LOG, "initItsResult is false");
  7.     }
  8. }
复制代码

4. 计时器和线程间通信      
EventHandler是HarmonyOS用于处理线程间通信的一种机制,在开发过程中,开发者经常需要处理较为耗时的操作,但是又不希望当前的线程受到阻塞,此时,就可以使用EventHandler机制。例如本例中AI语音播报是在子线程9275中执行的,更新播报耗时是在UI主线程9015中执行的,日志如下所示:
  1. 02-20 11:26:56.916 9015-9015/com.huawei.codedemo I 01100/MainAbilitySlice: initItsResult is true, speakText
  2. 02-20 11:26:56.924 9015-9015/com.huawei.codedemo I 01100/MainAbilitySlice: onEvent...
  3. 02-20 11:26:56.926 9015-9864/com.huawei.codedemo I 01100/MainAbilitySlice: onStart...
  4. 02-20 11:26:57.111 9015-9275/com.huawei.codedemo I 01100/MainAbilitySlice: onSpeechStart...
  5. 02-20 11:26:57.117 9015-9015/com.huawei.codedemo I 01100/MainAbilitySlice: 播报耗时:0 s
  6. ...
  7. 02-20 11:27:09.575 9015-9015/com.huawei.codedemo I 01100/MainAbilitySlice: 播报耗时:12 s
  8. 02-20 11:27:09.934 9015-9860/com.huawei.codedemo I 01100/MainAbilitySlice: onSpeechFinish...
复制代码

对于这一场景,就需要使用到EventHandler线程间通信机制。例如,本例中开始发音的时候发送EVENT_MSG_TIME_COUNT事件,开始计时并更新UI页面,示例代码如下所示:
  1. [url=home.php?mod=space&uid=2735960]@Override[/url]
  2. public void onSpeechStart(String utteranceId) {
  3.     // 开始计时
  4.     HiLog.info(LABEL_LOG, "onSpeechStart...");
  5.     if (timer == null && timerTask == null) {
  6.         timer = new Timer();
  7.         timerTask = new TimerTask() {
  8.             public void run() {
  9.                 handler.sendEvent(EVENT_MSG_TIME_COUNT);
  10.             }
  11.         };
  12.         timer.schedule(timerTask, 0, 1000);
  13.     }
  14. }
复制代码

EventHandler更新UI页面的代码如下所示:
  1. private EventHandler handler = new EventHandler(EventRunner.current()) {
  2.     @Override
  3.     protected void processEvent(InnerEvent event) {
  4.         switch (event.eventId) {
  5.             case EVENT_MSG_TIME_COUNT:
  6.                 getUITaskDispatcher().delayDispatch(new Runnable() {
  7.                     @Override
  8.                     public void run() {
  9.                         time = time + 1;
  10.                         HiLog.info(LABEL_LOG, "播报耗时:" + Integer.toString(time) + " s");
  11.                         timeText.setText("播报耗时:" + Integer.toString(time) + " s");
  12.                     }
  13.                 }, 0);
  14.                 break;
  15.             default:
  16.                 break;
  17.         }
  18.     }
  19. };
复制代码

5. 完整示例      
基于AI能力的语音播报系统完整示例代码如下所示:
  1. package com.huawei.texttospeech.slice;

  2. import com.huawei.texttospeech.ResourceTable;
  3. import ohos.aafwk.ability.AbilitySlice;
  4. import ohos.aafwk.content.Intent;
  5. import ohos.agp.components.Button;
  6. import ohos.agp.components.Component;
  7. import ohos.agp.components.Text;
  8. import ohos.agp.components.TextField;
  9. import ohos.ai.tts.TtsClient;
  10. import ohos.ai.tts.TtsListener;
  11. import ohos.ai.tts.TtsParams;
  12. import ohos.ai.tts.constants.TtsEvent;
  13. import ohos.eventhandler.EventHandler;
  14. import ohos.eventhandler.EventRunner;
  15. import ohos.eventhandler.InnerEvent;
  16. import ohos.hiviewdfx.HiLog;
  17. import ohos.hiviewdfx.HiLogLabel;
  18. import ohos.utils.PacMap;

  19. import java.util.Timer;
  20. import java.util.TimerTask;
  21. import java.util.UUID;

  22. public class MainAbilitySlice extends AbilitySlice {
  23.     private static final HiLogLabel LABEL_LOG = new HiLogLabel(3, 0xD001100, "MainAbilitySlice");
  24.     private TextField infoText;
  25.     private Button readBtn;
  26.     private Text timeText;
  27.     private boolean initItsResult;
  28.     private static final int EVENT_MSG_INIT = 0x1000001;
  29.     private static final int EVENT_MSG_TIME_COUNT = 0x1000002;
  30.     private int time = 0;
  31.     private Timer timer = null;
  32.     private TimerTask timerTask = null;

  33.     private EventHandler handler = new EventHandler(EventRunner.current()) {
  34.         @Override
  35.         protected void processEvent(InnerEvent event) {
  36.             switch (event.eventId) {
  37.                 case EVENT_MSG_TIME_COUNT:
  38.                     getUITaskDispatcher().delayDispatch(new Runnable() {
  39.                         @Override
  40.                         public void run() {
  41.                             time = time + 1;
  42.                             HiLog.info(LABEL_LOG, "播报耗时:" + Integer.toString(time) + " s");
  43.                             timeText.setText("播报耗时:" + Integer.toString(time) + " s");
  44.                         }
  45.                     }, 0);
  46.                     break;
  47.                 default:
  48.                     break;
  49.             }
  50.         }
  51.     };

  52.     @Override
  53.     public void onStart(Intent intent) {
  54.         super.onStart(intent);
  55.         super.setUIContent(ResourceTable.Layout_ability_main);
  56.         initView();
  57.         initTtsEngine();
  58.     }

  59.     private void initView() {
  60.         infoText = (TextField) findComponentById(ResourceTable.Id_text);
  61.         readBtn = (Button) findComponentById(ResourceTable.Id_read_btn);
  62.         timeText = (Text) findComponentById(ResourceTable.Id_time);
  63.         readBtn.setClickedListener(this::readText);
  64.     }

  65.     private void initTtsEngine() {
  66.         TtsClient.getInstance().create(this, ttsListener);
  67.     }

  68.     private void readText(Component component) {
  69.         if (initItsResult) {
  70.             HiLog.info(LABEL_LOG, "initItsResult is true, speakText");
  71.             TtsClient.getInstance().speakText(infoText.getText(), null);
  72.         } else {
  73.             HiLog.error(LABEL_LOG, "initItsResult is false");
  74.         }
  75.     }

  76.     private TtsListener ttsListener = new TtsListener() {
  77.         @Override
  78.         public void onEvent(int eventType, PacMap pacMap) {
  79.             HiLog.info(LABEL_LOG, "onEvent...");
  80.             // 定义TTS客户端创建成功的回调函数
  81.             if (eventType == TtsEvent.CREATE_TTS_CLIENT_SUCCESS) {
  82.                 TtsParams ttsParams = new TtsParams();
  83.                 ttsParams.setDeviceId(UUID.randomUUID().toString());
  84.                 initItsResult = TtsClient.getInstance().init(ttsParams);
  85.             }
  86.         }

  87.         @Override
  88.         public void onStart(String utteranceId) {
  89.             HiLog.info(LABEL_LOG, "onStart...");
  90.         }

  91.         @Override
  92.         public void onProgress(String utteranceId, byte[] audioData, int progress) {
  93.         }

  94.         @Override
  95.         public void onFinish(String utteranceId) {
  96.             HiLog.info(LABEL_LOG, "onFinish...");
  97.         }

  98.         @Override
  99.         public void onError(String s, String s1) {
  100.             HiLog.info(LABEL_LOG, "onError...");
  101.         }

  102.         @Override
  103.         public void onSpeechStart(String utteranceId) {
  104.             // 开始计时
  105.             HiLog.info(LABEL_LOG, "onSpeechStart...");
  106.             if (timer == null && timerTask == null) {
  107.                 timer = new Timer();
  108.                 timerTask = new TimerTask() {
  109.                     public void run() {
  110.                         handler.sendEvent(EVENT_MSG_TIME_COUNT);
  111.                     }
  112.                 };
  113.                 timer.schedule(timerTask, 0, 1000);
  114.             }
  115.         }

  116.         @Override
  117.         public void onSpeechProgressChanged(String utteranceId, int progress) {
  118.         }

  119.         @Override
  120.         public void onSpeechFinish(String utteranceId) {
  121.             // 结束计时
  122.             HiLog.info(LABEL_LOG, "onSpeechFinish...");
  123.             timer.cancel();
  124.             time = 0;
  125.             timer = null;
  126.             timerTask = null;
  127.         }
  128.     };
  129. }
复制代码

其中,页面布局文件为ability_main.xml,示例代码如下:
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <DirectionalLayout
  3.     xmlns:ohos="http://schemas.huawei.com/res/ohos"
  4.     ohos:height="match_parent"
  5.     ohos:width="match_parent"
  6.     ohos:orientation="vertical">

  7.     <Text
  8.         ohos:height="match_content"
  9.         ohos:width="match_content"
  10.         ohos:margin="15vp"
  11.         ohos:text="AI语音播报"
  12.         ohos:text_size="23fp"
  13.         ohos:top_margin="40vp"/>

  14.     <TextField
  15.         ohos:id="$+id:text"
  16.         ohos:height="150vp"
  17.         ohos:width="match_content"
  18.         ohos:layout_alignment="horizontal_center"
  19.         ohos:left_margin="20vp"
  20.         ohos:multiple_lines="true"
  21.         ohos:right_margin="20vp"
  22.         ohos:text="华为创立于1987年,是全球领先的ICT(信息与通信)基础设施和智能终端提供商,我们致力于把数字世界带入每个人、每个家庭、每个组织,构建万物互联的智能世界。"
  23.         ohos:text_size="50"
  24.         ohos:top_margin="20vp"
  25.         />

  26.     <DirectionalLayout
  27.         xmlns:ohos="http://schemas.huawei.com/res/ohos"
  28.         ohos:height="match_parent"
  29.         ohos:width="match_parent"
  30.         ohos:orientation="horizontal">

  31.         <Button
  32.             ohos:id="$+id:read_btn"
  33.             ohos:height="35vp"
  34.             ohos:width="80vp"
  35.             ohos:background_element="$graphic:background_button"
  36.             ohos:margin="15vp"
  37.             ohos:text="语音播报"
  38.             ohos:text_size="16fp"/>

  39.         <Text
  40.             ohos:id="$+id:time"
  41.             ohos:height="35vp"
  42.             ohos:width="150vp"
  43.             ohos:margin="15vp"
  44.             ohos:text="播报耗时:0 s"
  45.             ohos:text_size="16fp"/>
  46.     </DirectionalLayout>

  47. </DirectionalLayout>
复制代码

此外您还需在resource/base/graphic目录下添加background_button.xml
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <shape xmlns:ohos="http://schemas.huawei.com/res/ohos"
  3.        ohos:shape="rectangle">
  4.     <corners
  5.         ohos:radius="40"/>
  6.     <solid
  7.         ohos:color="#e9e9e9"/>
  8. </shape>
复制代码
说明以上代码仅demo演示参考使用,产品化的代码需要考虑数据校验和国际化。

6. 恭喜你      

通过对本教程的学习,你已经学会HarmonyOS AI语音播报、线程间通信和计时器的使用。


回帖

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容图片侵权或者其他问题,请联系本站作侵删。 侵权投诉
链接复制成功,分享给好友