HarmonyOS鸿蒙Next中AI朗读控件的集成和使用,源码与流程解答

HarmonyOS鸿蒙Next中AI朗读控件的集成和使用,源码与流程解答

鸿蒙AI朗读控件的集成和使用,源码与流程解答

4 回复

textToSpeech(文本转语音)

文本转语音服务提供将文本信息转换为语音并进行播报的能力,便于用户与设备进行互动,实现实时语音交互,文本播报。

目前本服务支持的语种为中文、英文,支持的音色为聆小珊女声音色、英语(美国)劳拉女声音色、凌飞哲男声音色。

示例:

import { BusinessError } from '@kit.BasicServicesKit';
import { textToSpeech } from '@kit.CoreSpeechKit';
// 创建引擎实例相关参数
let ttsEngine: textToSpeech.TextToSpeechEngine;
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
};
// 调用创建引擎实例接口
textToSpeech.createEngine(initParamsInfo, (err: BusinessError, textToSpeechEngine: textToSpeech.TextToSpeechEngine) => {
  if (!err) {
    console.info('Succeeded in creating engine.');
    // 获得引擎实例
    ttsEngine = textToSpeechEngine;
  } else {
    console.error(`Failed to create engine. Code: ${err.code}, message: ${err.message}.`);
  }
});
@Entry
@Component
struct Page {
  build() {
  }
}

开发文档:https://developer.huawei.com/consumer/cn/doc/harmonyos-references/hms-ai-texttospeech

更多关于HarmonyOS鸿蒙Next中AI朗读控件的集成和使用,源码与流程解答的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


一、结论

图片

鸿蒙系统提供了系统级别的朗读控件,来实现对文本进行朗读的业务需求。不需要复杂的SDK接入和集成,就可实现商业级别的朗读效果。

朗读控件分为听筒组件朗读控制器,以及朗读面板三部分组成。 朗读面板又分为吸边小面板全屏朗读面板

需要注意的是,仅支持中国境内(不包含中国香港、中国澳门、中国台湾)提供服务。并且实时朗读的正文信息长度10000字符以内。

二、代码实现和详细解释

(1)听筒控件TextReaderIcon

提供的听筒控件,可以同步朗读状态,如上动态图所示,有现成的朗读效果,如果业务需要使用,可以用。或者直接跳过也可以,控件参数比较简单

(2)朗读控制器TextReader

TextReader是整个朗读操作逻辑的核心操作对象,系统接口提供了该单例对象。

(3)朗读面板

是个完整的大页面,如gif图所示,可以操控,查看等。

以下为完整的示例DEMO源码,便于理解:

// 导入语音朗读相关的组件和类型
import { TextReader, TextReaderIcon, ReadStateCode } from '@kit.SpeechKit';

@Entry
@Component
struct Index {

  /**
   * 待加载的文章列表
   */
  @State readInfoList: TextReader.ReadInfo[] = [];

  /**
   * 当前选中的文章
   */
  @State selectedReadInfo: TextReader.ReadInfo = this.readInfoList[0];

  /**
   * 朗读状态
   */
  @State readState: ReadStateCode = ReadStateCode.WAITING;

  /**
   * 初始化状态标记
   */
  @State isInit: boolean = false;

  // 组件即将显示时触发
  async aboutToAppear(){
    /**
     * 模拟加载文章数据
     */
    let readInfoList: TextReader.ReadInfo[] = [{
      id: '001',
      title: {
        text:'水调歌头.明月几时有',
        isClickable:true
      },
      author:{
        text:'宋.苏轼',
        isClickable:true
      },
      date: {
        text:'2024/01/01',
        isClickable:false
      },
      bodyInfo: '明月几时有?把酒问青天。不知天上宫阙,今夕是何年?'
    }];

    // 更新状态变量
    this.readInfoList = readInfoList;
    this.selectedReadInfo = this.readInfoList[0];

    // 初始化朗读组件
    this.init();
  }

  /**
   * 初始化朗读组件
   */
  async init() {
    // 朗读参数配置
    const readerParam: TextReader.ReaderParam = {
      isVoiceBrandVisible: true, // 显示品牌信息
      businessBrandInfo: {
        panelName: '小艺朗读', // 面板名称
        panelIcon: $r('app.media.startIcon') // 面板图标
      }
    }

    try {
      // 获取上下文
      let context: Context | undefined = this.getUIContext().getHostContext()
      if (context) {
        // 初始化朗读组件
        await TextReader.init(context, readerParam);
        this.isInit = true; // 标记初始化完成
        this.setActionListener(); // 设置事件监听
      }
    } catch (err) {
      // 初始化失败时打印错误信息
      console.error(`TextReader failed to init. Code: ${err.code}, message: ${err.message}`);
    }
  }

  // 设置朗读事件监听
  setActionListener() {
    // 监听朗读状态变化
    TextReader.on('stateChange', (state: TextReader.ReadState) => {
      this.onStateChanged(state);
    });

    // 监听加载更多请求
    TextReader.on('requestMore', () => {
      TextReader.loadMore([], true);
    })
  }

  // 处理朗读状态变化
  onStateChanged = (state: TextReader.ReadState) => {
    // 只处理当前选中文章的状态变化
    if (this.selectedReadInfo?.id === state.id) {
      this.readState = state.state;
    } else {
      this.readState = ReadStateCode.WAITING;
    }
  }

  // 构建UI界面
  build() {
    Column() {
      // 朗读状态图标
      TextReaderIcon({ readState: this.readState })
        .margin({ right: 20 })
        .width(32)
        .height(32)
        .onClick(async () => {
          // 点击图标时开始朗读
          try {
            await TextReader.start(this.readInfoList, this.selectedReadInfo?.id);
          } catch (err) {
            // 朗读失败时打印错误信息
            console.error(`TextReader failed to start. Code: ${err.code}, message: ${err.message}`);
          }
        })
    }
    .height('100%')
  }
}

三、工具类封装源码共享:

封装ReaderIconView朗读图标,联动管理类的朗读状态,即插即用。

import { ReadStateCode, TextReaderIcon } from "@kit.SpeechKit";
import { TextReaderMgr, TextReaderRegister } from "../mgr/TextReaderMgr";
import { common } from "@kit.AbilityKit";

@Component
export struct ReaderIconView {
  private TAG: string = "ReaderIconView";

  /**
   * 朗读状态
   */
  @State readState: ReadStateCode = ReadStateCode.WAITING;

  private mTextReaderRegister: TextReaderRegister = {
    onStateChange: (state: ReadStateCode): void => {
      this.readState = state;
      console.log(this.TAG, "mTextReaderRegister onStateChange state: " + state);
    }
  }

  aboutToAppear(): void {
    const context = getContext(this) as common.UIAbilityContext;
    TextReaderMgr.Ins().initReader(context, null, null, this.mTextReaderRegister);
    console.log(this.TAG, " aboutToAppear initReader done");
  }


  build() {
    TextReaderIcon({ readState: this.readState })
      .width("100%")
      .height("100%")
  }

}

封装单例朗读管理类,用于便捷操作朗读相关接口,封装细节,方便快速调用:

import { ReadStateCode, TextReader } from "@kit.SpeechKit";

/**
 * 初始化配置对象
 */
export class TextReaderInitData {
  // 全屏面板标题名称
  panelName: string = "";
  // 是否需要吸边小面板
  isMinibarNeeded: boolean = true;
  // 是否需要全屏面板
  isPanelNeeded: boolean = true;
}

/**
 * 控制器操作回调
 */
export interface TextReaderCall {
  onReady: () => void
  onInitFail: (err: string) => void
  onFail: (err: string) => void
}

/**
 * 监听回调
 */
export interface TextReaderRegister {
  onStateChange: (state: ReadStateCode) => void
}

/**
 * 错误码
 */
export enum TextReaderFail {
  UnInit = "0",
  TextReaderInfoNULL = "1"
}

/**
 * 文本朗读对象
 */
export class TextReaderInfo {
  title: string = "";
  content: string = "";
  author?: string = "";
  date?: string = "";
}

/**
 * 文本朗读管理类
 */
export class TextReaderMgr {
  private TAG: string = "TextReaderMgr";
  private static mTextReaderMgr: TextReaderMgr | null = null;
  private mInit: boolean = false;
  private mTextReaderCall: TextReaderCall | null = null;
  private mTextReaderInitData: TextReaderInitData | null = null;
  private mTextReaderRegister: TextReaderRegister | null = null;

  private mCurrentReadInfo: TextReader.ReadInfo | null = null;

  public static Ins() {
    if (!TextReaderMgr.mTextReaderMgr) {
      TextReaderMgr.mTextReaderMgr = new TextReaderMgr();
    }
    return TextReaderMgr.mTextReaderMgr;
  }

  /**
   * 设置朗读事件监听
   */
  private setActionListener() {
    // 监听朗读状态变化
    TextReader.on('stateChange', (state: TextReader.ReadState) => {
      let readState: ReadStateCode = ReadStateCode.WAITING;
      if (this.mCurrentReadInfo?.id === state.id) {
        readState = state.state;
      } else {
        readState = ReadStateCode.WAITING;
      }
      this.mTextReaderRegister?.onStateChange(readState);
    });

    // 监听加载更多请求
    TextReader.on('requestMore', (callbackStr) => {
      console.log(this.TAG, " callbackStr: " + callbackStr);
      let readInfoList: TextReader.ReadInfo[] = [{
        id: '002',
        title: {
          text: '水调歌头.明月几时有2',
          isClickable: true
        },
        author: {
          text: '宋.苏轼2',
          isClickable: true
        },
        date: {
          text: '2025/02/02',
          isClickable: false
        },
        bodyInfo: '2明月几时有?把酒问青天。不知天上宫阙,今夕是何年?'
      }];
      TextReader.loadMore(readInfoList, true);
    })
  }

  /**
   * 初始化朗读播放控件
   */
  public async initReader(context: Context, callback?: TextReaderCall | null, data?: TextReaderInitData | null,
    register?: TextReaderRegister) {
    this.mTextReaderCall = callback ?? null;
    this.mTextReaderInitData = data ?? null;
    this.mTextReaderRegister = register ?? null;

    // 朗读参数配置
    const readerParam: TextReader.ReaderParam = {
      isVoiceBrandVisible: data?.panelName == "" ? false : true ?? true, // 显示品牌信息
      businessBrandInfo: {
        panelName: data?.panelName == "" ? '朗读' : data?.panelName ?? '朗读', // 面板名称
      },
      isMinibarNeeded: data?.isMinibarNeeded ?? true
    }

    try {
      if (context) {
        // 初始化朗读组件
        await TextReader.init(context, readerParam);
        this.mInit = true; // 标记初始化完成
        this.setActionListener(); // 设置事件监听
        this.mTextReaderCall?.onReady();
      }
    } catch (err) {
      // 初始化失败时打印错误信息
      console.error(this.TAG, `TextReader failed to init. Code: ${err.code}, message: ${err.message}`);
      this.mTextReaderCall?.onInitFail(JSON.stringify(err));
    }
  }

  /**
   * 文本朗读播放接口(不显示字幕全屏面板和吸边小面板,直接朗读文本)
   * @param content 实时朗读的正文信息(长度10000字符以内)
   */
  public async startContent(context: Context, content: string) {
    await this.initReader(context);
    let readInfoList: TextReader.ReadInfo[] = [{
      id: '0',
      title: {
        text: '',
        isClickable: true
      },
      bodyInfo: content
    }];
    this.mCurrentReadInfo = readInfoList[0];
    await TextReader.start(readInfoList, this.mCurrentReadInfo.id);
    TextReader.hidePanel();
  }

  /**
   * 启动朗读
   * @param infoArr
   */
  public async start(infoArr: TextReaderInfo[]) {
    // 判断当前是否初始化成功过
    if (!this.mInit) {
      console.error(this.TAG, "start error ! mInit false !");
      this.mTextReaderCall?.onFail(TextReaderFail.UnInit);
      return;
    }
    if (!infoArr) {
      console.error(this.TAG, "start error ! infoArr null !");
      this.mTextReaderCall?.onFail(TextReaderFail.TextReaderInfoNULL);
      return;
    }
    // 朗读启动配置
    const startParams: TextReader.StartParams = {
      isMinibarHidden: this.mTextReaderInitData?.isMinibarNeeded ?? true,
    }
    // 填充朗读内容
    let readInfoList: TextReader.ReadInfo[] = [];
    for (let index = 0; index < infoArr.length; index++) {
      const info = infoArr[index];
      let tempInfo: TextReader.ReadInfo = {
        id: " " + index,
        title: {
          text: info.title,
          isClickable: true,
        },
        bodyInfo: info.content,
        date: {
          text: info.author ?? "",
          isClickable: true,
        },
        author: {
          text: info.author ?? "",
          isClickable: true,
        }
      }
      readInfoList.push(tempInfo);
    }
    this.mCurrentReadInfo = readInfoList[0];
    // 启动朗读
    await TextReader.start(readInfoList, this.mCurrentReadInfo.id, startParams);
  }
}

鸿蒙Next的AI朗读控件基于TTS引擎实现。集成时需在module.json5中添加"ohos.permission.INTERNET"权限,并导入@ohos.multimedia.tts模块。

核心流程:

  1. 初始化TTS引擎;
  2. 配置语音参数(语速/音调/语言);
  3. 调用speak()方法执行朗读;
  4. 通过回调监听播放状态。

关键源码包括createTtsEngine()创建实例和speak()方法调用。需注意Next版本仅支持系统预置语音包,不支持第三方语音引擎扩展。

在HarmonyOS Next中,AI朗读功能主要通过TextToSpeech(TTS)引擎实现,而非一个独立的UI控件。其核心是系统服务,开发者可通过API调用实现文本朗读。以下是集成与使用的关键流程和源码示例:

1. 权限与依赖

  • 权限声明:在module.json5文件中添加ohos.permission.USE_TTS权限。
"requestPermissions": [
  {
    "name": "ohos.permission.USE_TTS"
  }
]
  • SDK依赖:确保API版本≥10(HarmonyOS Next)。

2. 核心API与流程

初始化TTS引擎

import tts from '@ohos.tts';

// 获取TTS实例
let ttsEngine = tts.getTtsEngine();

配置参数与播放

// 设置朗读参数(语速、音调等)
let params: tts.TtsParams = {
  volume: 0.8,    // 音量(0.0-1.0)
  speed: 1.0,     // 语速(0.5-2.0)
  pitch: 1.0      // 音调(0.5-2.0)
};

// 播放文本
ttsEngine.speak('需要朗读的文本', params).then(() => {
  console.info('朗读开始');
}).catch((err: Error) => {
  console.error(`朗读失败: ${err.message}`);
});

事件监听

// 监听状态变化
ttsEngine.on('start', () => {
  console.info('播放开始');
});
ttsEngine.on('finish', () => {
  console.info('播放结束');
});
ttsEngine.on('error', (err: Error) => {
  console.error(`播放错误: ${err.message}`);
});

流程控制

// 暂停/恢复/停止
ttsEngine.pause();
ttsEngine.resume();
ttsEngine.stop();

// 释放资源(页面销毁时调用)
ttsEngine.release();

3. 自定义UI控件封装示例

可基于TTS服务封装可复用的朗读按钮组件:

// TtsButton.ets
@Component
export struct TtsButton {
  private text: string = '';
  private isPlaying: boolean = false;

  build() {
    Button(this.isPlaying ? '停止朗读' : '开始朗读')
      .onClick(() => {
        if (this.isPlaying) {
          tts.getTtsEngine().stop();
        } else {
          tts.getTtsEngine().speak(this.text);
        }
        this.isPlaying = !this.isPlaying;
      })
  }
}

4. 关键注意事项

  • 引擎可用性检查:调用前通过ttsEngine.isSupport()验证设备支持情况。
  • 多语言支持:通过ttsEngine.getVoices()获取支持的语音包,设置params.language参数。
  • 后台播放:需申请ohos.permission.KEEP_BACKGROUND_RUNNING权限并配置长时任务。

5. 完整调用链示例

// 1. 初始化并检查支持
let engine = tts.getTtsEngine();
if (!engine.isSupport()) {
  console.error('设备不支持TTS');
  return;
}

// 2. 设置参数并播放
engine.speak('HarmonyOS Next AI朗读示例', {
  speed: 1.2,
  language: 'zh-CN'
});

// 3. 管理生命周期
// 页面隐藏时暂停
// 页面销毁时调用engine.release()

该实现直接调用系统TTS服务,无需引入第三方库。注意参数配置需在设备支持的范围内,异常处理需覆盖网络依赖(在线语音包下载)场景。

回到顶部