鸿蒙AI功能开发【hiai引擎框架-文本转语音】 基础视觉服务

hiai引擎框架-文本转语音

介绍

本示例展示了使用hiai引擎框架提供的文本转语音能力。

本示例展示了对一段中文文本,进行语音合成及播报的能力。

需要使用hiai引擎框架文本转语音接口@kit.CoreSpeechKit.d.ts.

效果预览

使用说明:

  1. 在手机的主屏幕,点击"ttsDemo",启动应用。
  2. 点击"CreateEngine"按钮,进行能力初始化。
  3. 点击"speak"按钮,试听文本播报。
  4. 点击"stop"等按钮对播报进行事件控制。
  5. 点击"listVoicesCallback/listVoicesPromise"查询支持的语种和音色。

具体实现

本示例展示了在@kit.CoreSpeechKit.d.ts定义的API:

  • createEngine(createEngineParams: CreateEngineParams, callback: AsyncCallback): void;
  • createEngine(createEngineParams: CreateEngineParams): Promise;
  • speak(text: string, speakParams: SpeakParams, listener: SpeakListener): void;
  • listVoices(params: VoiceQuery, callback: AsyncCallback): void;
  • listVoices(params: VoiceQuery): Promise;
  • stop(): void;
  • isBusy(): boolean;
  • shutdown(): void;

业务使用时,需要先进行import导入textToSpeech。 调用speak等接口,传入想要识别的文本,试听播报,观察日志等。参考:

import { textToSpeech } from '@kit.CoreSpeechKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { TreeMap } from '@kit.ArkTS';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { UuidBasic } from './UuidBasic';

const TAG: string = 'TtsDemo';
let ttsEngine: textToSpeech.TextToSpeechEngine;

@Entry
@Component
struct Index {
  @State createCount: number = 0;
  @State result: boolean = false;
  @State voiceInfo: string = "";
  @State text: string = "";
  @State textContent: string = "";
  @State utteranceId: string = "123456";
  @State originalText: string = "\n\t\t古人学问无遗力,少壮工夫老始成;\n\t\t" +
    "纸上得来终觉浅,绝知此事要躬行。\n\t\t";
  @State illegalText: string = "";
  private pcmData: TreeMap<number, Uint8Array> = new TreeMap();

  build() {
    Column() {
      Scroll() {
        Column() {
          TextArea({ placeholder: 'Please enter tts original text', text: `${this.originalText}` })
            .margin(20)
            .focusable(false)
            .border({ width: 5, color: 0x317AE7, radius: 10, style: BorderStyle.Dotted })
            .onChange((value: string) => {
              this.originalText = value;
              hilog.info(0x0000, TAG, "original text: " + this.originalText);
            })

          Button() {
            Text("CreateEngine")
              .fontColor(Color.White)
              .fontSize(20)
          }
          .type(ButtonType.Capsule)
          .backgroundColor("#0x317AE7")
          .width("80%")
          .height(50)
          .margin(10)
          .onClick(() => {
            this.createCount++;
            console.log(`createByCallback:createCount:${this.createCount}`);
            this.createByCallback();
          })

          Button() {
            Text("CreateEngineByPromise")
              .fontColor(Color.White)
              .fontSize(20)
          }
          .type(ButtonType.Capsule)
          .backgroundColor("#0x317AE7")
          .width("80%")
          .height(50)
          .margin(10)
          .onClick(() => {
            this.createCount++;
            console.log(`createByPromise:createCount:${this.createCount}`);
            this.createByPromise();
          })

          Button() {
            Text("createOfErrorLanguage")
              .fontColor(Color.White)
              .fontSize(20)
          }
          .type(ButtonType.Capsule)
          .backgroundColor("#0x317AE7")
          .width("80%")
          .height(50)
          .margin(10)
          .onClick(() => {
            this.createCount++;
            console.log(`createOfErrorLanguage:createCount:${this.createCount}`);
            this.createOfErrorLanguage();
          })

          Button() {
            Text("createOfErrorPerson")
              .fontColor(Color.White)
              .fontSize(20)
          }
          .type(ButtonType.Capsule)
          .backgroundColor("#0x317AE7")
          .width("80%")
          .height(50)
          .margin(10)
          .onClick(() => {
            this.createCount++;
            console.log(`createOfErrorPerson:createCount:${this.createCount}`);
            this.createOfErrorPerson();
          })

          Button() {
            Text("speak")
              .fontColor(Color.White)
              .fontSize(20)
          }
          .type(ButtonType.Capsule)
          .backgroundColor("#0x317AE7")
          .width("80%")
          .height(50)
          .margin(10)
          .onClick(() => {
            this.createCount++;
            console.log(`speak:createCount:${this.createCount}`)
            this.speak();
          })

          Button() {
            Text("SpeakIllegalText")
              .fontColor(Color.White)
              .fontSize(20)
          }
          .type(ButtonType.Capsule)
          .backgroundColor("#0x317AE7")
          .width("80%")
          .height(50)
          .margin(10)
          .onClick(() => {
            this.createCount++;
            console.log(`illegalSpeak:createCount:${this.createCount}`)
            this.illegalSpeak();
          })

          Button() {
            Text("listVoicesCallback")
              .fontColor(Color.White)
              .fontSize(20)
          }
          .type(ButtonType.Capsule)
          .backgroundColor("#0x317AE7")
          .width("80%")
          .height(50)
          .margin(10)
          .onClick(() => {
            this.listVoicesCallback();
          })

          Button() {
            Text("listVoicesPromise")
              .fontColor(Color.White)
              .fontSize(20)
          }
          .type(ButtonType.Capsule)
          .backgroundColor("#0x317AE7")
          .width("80%")
          .height(50)
          .margin(10)
          .onClick(() => {
            this.listVoicesPromise();
          })


          Button() {
            Text("stop")
              .fontColor(Color.White)
              .fontSize(20)
          }
          .type(ButtonType.Capsule)
          .backgroundColor("#0x317AE7")
          .width("80%")
          .height(50)
          .margin(10)
          .onClick(() => {
            //停止播报
            hilog.info(0x0000, TAG, "isSpeaking click:-->");
            //this.setListener();
            ttsEngine.stop();
          })

          Button() {
            Text("isBusy")
              .fontColor(Color.White)
              .fontSize(20)
          }
          .type(ButtonType.Capsule)
          .backgroundColor("#0x317AE7")
          .width("80%")
          .height(50)
          .margin(10)
          .onClick(() => {
            hilog.info(0x0000, TAG, "isSpeaking click:-->");
            //查询播报状态
            this.setListener();
            let isBusy: boolean = ttsEngine.isBusy();
            console.log('isBusy :' + isBusy);
          })

          Button() {
            Text("shutdown")
              .fontColor(Color.White)
              .fontSize(20)
          }
          .type(ButtonType.Capsule)
          .backgroundColor("#0x317AA7")
          .width("80%")
          .height(50)
          .margin(10)
          .onClick(() => {
            //释放引擎
            ttsEngine.shutdown();
          })

        }
        .layoutWeight(1)
      }
      .width('100%')
      .height('100%')

    }
  }

  //创建引擎,通过callback形式返回
  //当引擎不存在、引擎资源不存在、初始化超时,返回错误码1002300005,引擎创建失败
  private createByCallback() {
    //设置创建引擎参数
    let extraParam: Record<string, Object> = { "style": 'interaction-broadcast', "locate": 'CN', "name": 'EngineName' }
    let initParamsInfo: textToSpeech.CreateEngineParams = {
      language: 'zh-CN',
      person: 0,
      online: 1,
      extraParams: extraParam
    };
    try {
      //调用createEngine方法
      textToSpeech.createEngine(initParamsInfo, (err: BusinessError, textToSpeechEngine: textToSpeech.TextToSpeechEngine) => {
        if (!err) {
          console.log('createEngine is success');
          //接收创建引擎的实例
          ttsEngine = textToSpeechEngine;
        } else {
          //创建引擎失败时返回错误码1002300005,可能原因:引擎不存在、资源不存在、创建引擎超时
          console.error("errCode is " + JSON.stringify(err.code));
          console.error("errMessage is " + JSON.stringify(err.message));
        }
      });
    } catch (error) {
      let message = (error as BusinessError).message;
      let code = (error as BusinessError).code;
      console.error(`createEngine failed, error code: ${code}, message: ${message}.`)
    }
  }

  //创建引擎,通过promise形式返回
  private createByPromise() {
    //设置创建引擎参数
    let extraParam: Record<string, Object> = { "style": 'interaction-broadcast', "locate": 'CN', "name": 'EngineName' }
    let initParamsInfo: textToSpeech.CreateEngineParams = {
      language: 'zh-CN',
      person: 0,
      online: 1,
      extraParams: extraParam
    };

    //调用createEngine方法
    textToSpeech.createEngine(initParamsInfo).then((res: textToSpeech.TextToSpeechEngine) => {
      ttsEngine = res;
      console.log('result:' + JSON.stringify(res));
    }).catch((res: Object) => {
      console.log('result' + JSON.stringify(res));
    });

  }

  //调用speak播报方法
  //未初始化引擎时调用speak方法,返回错误码1002300007,合成及播报失败
  private async speak() {
    //设置播报相关参数
    let extraParam: Record<string, Object> = {
      "queueMode": 0,
      "speed": 1,
      "volume": 2,
      "pitch": 1,
      "languageContext": 'zh-CN',
      "audioType": "pcm",
      "soundChannel": 1,
      "playType": 1
    }
    let speakParams: textToSpeech.SpeakParams = {
      requestId: UuidBasic.createUUID(),
      extraParams: extraParam
    }
    //设置回调
    this.setListener();
    //调用speak播报方法
    ttsEngine.speak(this.originalText, speakParams);
  }

  //查询语种音色信息,以callback形式返回
  private listVoicesCallback() {
    //设置查询相关参数
    let voicesQuery: textToSpeech.VoiceQuery = {
      requestId: UuidBasic.createUUID(),
      online: 1
    }

    //调用listVoices方法,以callback返回
    ttsEngine.listVoices(voicesQuery, (err: BusinessError, voiceInfo: textToSpeech.VoiceInfo[]) => {
      if (!err) {
        //接收目前支持的语种音色等信息
        this.voiceInfo = JSON.stringify(voiceInfo);
        console.log('voiceInfo is ' + JSON.stringify(voiceInfo));
      } else {
        console.error("error is " + JSON.stringify(err));
      }
    });

  };

  //查询语种音色信息,以promise返回
  private listVoicesPromise() {
    //设置查询相关的参数
    let voicesQuery: textToSpeech.VoiceQuery = {
      requestId: UuidBasic.createUUID(),
      online: 1
    }
    //调用listVoice方法
    ttsEngine.listVoices(voicesQuery).then((res: textToSpeech.VoiceInfo[]) => {
      console.log('voiceInfo:' + JSON.stringify(res));
    }).catch((res: Object) => {
      console.error('error is ' + JSON.stringify(res));
    });
  }

  private setListener() {
    let speakListener: textToSpeech.SpeakListener = {
      //开始播报回调
      onStart(utteranceId: string, response: textToSpeech.StartResponse) {
        console.log('speakListener onStart: ' + ' utteranceId: ' + utteranceId + ' response: ' + JSON.stringify(response));
      },
      //完成播报回调
      onComplete(utteranceId: string, response: textToSpeech.CompleteResponse) {
        console.log('speakListener onComplete: ' + ' utteranceId: ' + utteranceId + ' response: ' + JSON.stringify(response));
      },
      //停止播报完成回调,调用stop方法并完成时会触发此回调
      onStop(utteranceId: string, response: textToSpeech.StopResponse) {
        console.log('speakListener onStop: ' + ' utteranceId: ' + utteranceId + ' response: ' + JSON.stringify(response));
      },
      //返回音频流
      onData(utteranceId: string, audio: ArrayBuffer, response: textToSpeech.SynthesisResponse) {
        console.log('speakListener onData: ' + ' utteranceId: ' + utteranceId + ' sequence: ' + JSON.stringify(response) + ' audio: ' + audio);
      },
      //错误回调,播报过程发生错误时触发此回调
      //未创建引擎时调用speak方法时返回错误码1002300007,合成及播报失败
      //连续调用两次speak,第二次speak会返回错误码1002300006,服务正忙碌
      onError(utteranceId: string, errorCode: number, errorMessage: string) {
        console.error('speakListener onError: ' + ' utteranceId: ' + utteranceId + ' errorCode: ' + errorCode + ' errorMessage: ' + errorMessage);
      }
    };
    // 设置回调
    ttsEngine.setListener(speakListener);
  }

  //使用不支持的语种创建引擎,返回错误码1002300002,语种不支持
  private createOfErrorLanguage() {
    //设置创建引擎参数
    let initParamsInfo: textToSpeech.CreateEngineParams = {
      //不支持的语种
      language: 'ZH-CN',
      person: 0,
      online: 1
    };
    try {
      //调用createEngine方法
      textToSpeech.createEngine(initParamsInfo, (err: BusinessError, textToSpeechEngine: textToSpeech.TextToSpeechEngine) => {
        if (!err) {
          console.log('createEngine is success');
          //接收创建引擎的实例
          ttsEngine = textToSpeechEngine;
        } else {
          //返回错误码1002300002,语种不支持
          console.error("errCode is " + JSON.stringify(err.code));
          console.error("errMessage is " + JSON.stringify(err.message));
        }
      });
    } catch (error) {
      let message = (error as BusinessError).message;
      let code = (error as BusinessError).code;
      console.error(`createEngine failed, error code: ${code}, message: ${message}.`)
    }
  }

  //使用不支持的语种创建引擎,返回错误码1002300003,音色不支持
  private createOfErrorPerson() {
    //设置创建引擎参数
    let initParamsInfo: textToSpeech.CreateEngineParams = {
      language: 'zh-CN',
      //不支持的音色
      person: 1,
      online: 1
    };
    try {
      //调用createEngine方法
      textToSpeech.createEngine(initParamsInfo, (err: BusinessError, textToSpeechEngine: textToSpeech.TextToSpeechEngine) => {
        if (!err) {
          console.log('createEngine is success');
          //接收创建引擎的实例
          ttsEngine = textToSpeechEngine;
        } else {
          //返回错误码1002300003,音色不支持
          console.error("errCode is " + JSON.stringify(err.code));
          console.error("errMessage is " + JSON.stringify(err.message));
        }
      });
    } catch (error) {
      let message = (error as BusinessError).message;
      let code = (error as BusinessError).code;
      console.error(`createEngine failed, error code: ${code}, message: ${message}.`)
    }
  }

  //使用非法文本,调用speak播报方法,返回1002300001,文本长度非法
  private illegalSpeak() {
    this.setListener();
    //设置播报相关参数
    let extraParam: Record<string, Object> = { "speed": 1, "volume": 1, "pitch": 1, "audioType": "pcm" }
    let speakParams: textToSpeech.SpeakParams = {
      requestId: UuidBasic.createUUID(),
      extraParams: extraParam
    }
    //调用speak播报方法
    ttsEngine.speak(this.illegalText, speakParams);
  }
}

以上就是本篇文章所带来的鸿蒙开发中一小部分技术讲解;想要学习完整的鸿蒙全栈技术。可以在结尾找我可全部拿到!

下面是鸿蒙的完整学习路线 ,展示如下:

除此之外,根据这个学习鸿蒙全栈学习路线,也附带一整套完整的学习【文档+视频】,内容包含如下

内容包含了:(ArkTS、ArkUI、Stage模型、多端部署、分布式应用开发、音频、视频、WebGL、OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、鸿蒙南向开发、鸿蒙项目实战)等技术知识点。帮助大家在学习鸿蒙路上快速成长!

鸿蒙【北向应用开发+南向系统层开发】文档

鸿蒙【基础+实战项目】视频

鸿蒙面经

为了避免大家在学习过程中产生更多的时间成本,对比我把以上内容全部放在了↓↓↓想要的可以自拿喔!谢谢大家观看!

相关推荐
985小水博一枚呀2 分钟前
【深度学习滑坡制图|论文解读3】基于融合CNN-Transformer网络和深度迁移学习的遥感影像滑坡制图方法
人工智能·深度学习·神经网络·cnn·transformer
AltmanChan3 分钟前
大语言模型安全威胁
人工智能·安全·语言模型
985小水博一枚呀7 分钟前
【深度学习滑坡制图|论文解读2】基于融合CNN-Transformer网络和深度迁移学习的遥感影像滑坡制图方法
人工智能·深度学习·神经网络·cnn·transformer·迁移学习
数据与后端架构提升之路16 分钟前
从神经元到神经网络:深度学习的进化之旅
人工智能·神经网络·学习
爱技术的小伙子22 分钟前
【ChatGPT】如何通过逐步提示提高ChatGPT的细节描写
人工智能·chatgpt
深度学习实战训练营2 小时前
基于CNN-RNN的影像报告生成
人工智能·深度学习
努力变厉害的小超超3 小时前
ArkTS中的组件基础、状态管理、样式处理、class语法以及界面渲染
笔记·鸿蒙
sanzk3 小时前
华为鸿蒙应用开发
华为·harmonyos
昨日之日20064 小时前
Moonshine - 新型开源ASR(语音识别)模型,体积小,速度快,比OpenAI Whisper快五倍 本地一键整合包下载
人工智能·whisper·语音识别
浮生如梦_4 小时前
Halcon基于laws纹理特征的SVM分类
图像处理·人工智能·算法·支持向量机·计算机视觉·分类·视觉检测