针对上一篇微信同声传译语音播报部分坑的解决和优化

1. 上一篇语音播报其实是不完美的,就是如何停止上一个音频开始下一个音频的问题,我在此做一下修改

在这里插入图片描述
比如说:现在正在播放1,我点击2让2开始播放,1停止播放,我上面的写法是有问题的:

  • 通过 innerAudioContext.pause() 是可以停止播放音频的;
  • wx.createInnerAudioContext()的实例,我是在readStart方法里面创建的
  • 再次执行readStart方法,会重新创建wx.createInnerAudioContext()实例
  • 我们如果在点击播放图标的时候执行pause() 方法,执行的不是正在播放的音频的实例

因此:我们需要创建一个全局的实例,这样我们执行pause() 方法时,在同一个实例下,就是停止正在播放的音频
代码如下:

	data:{
	dialogue:'您好,我是您的健康管家"向我提问。您好,我是您的健康管家"质迹"!您有什么疑问都可以在此向我提问。',
	type:'play'
	}
	// 在onLoad中创建一个全局的实例
	onLoad(){
		this.innerAudioContext = wx.createInnerAudioContext();
	}
  // 阅读文字
  readText: async function () {
    const that = this;
    // ------------------------------在点击播放图标之前,我们先执行一个pause()方法,停止上一段音频--------------------
    that.innerAudioContext.pause()
    that.setData({
      type :'pause'
    })
    // 将文字按照每200个长度截取成一段,组成一个数组
    // 切片处理,将超过1000个字符的文字,截取成几段
    let list =this.splitStringByLength(dialogue, 200)
    // 循环遍历数组,将文字转化成音频
    let radioList = list.map(el => {
      return new Promise(resolve => {
        plugin.textToSpeech({
          lang: "zh_CN",
          tts: true,
          content: el,
          success: function (res) {
            resolve(res.filename)
          },
          fail: function (res) {
            wx.showToast({
              title: '语音转换失败',
            })
          }
        })
      })
    })
    // 将promise执行结果放在一起执行(解决for循环中有异步操作的方法之一,经典面试题)
    // 有个弊端: 如果前面的promise有一个执行错误,Promise.all就不会执行,因此:可以用map/filter将radioList过滤一遍(本项目中有一个Promise执行失败,就应该失败)
    Promise.all(radioList).then(res => {
      that.readStart(res)
    })
  },
	// 将字符串每隔length个就截取一段
   splitStringByLength :function (str, length)  {
	  let result = [];
	  for (let i = 0; i < str.length; i += length) {
	    result.push(str.substring(i, i + length));
	  }
	  return result;
	}// 开始阅读
  readStart: async function (radioList) {
    const that = this
    for (let text of radioList) {
    // --------------------------在此就不需要再次创建实例了---------------------------
      // const innerAudioContext = wx.createInnerAudioContext();
      that.innerAudioContext.src = text;

      that.innerAudioContext.onPlay(() => {
        console.log('开始播放当前片段', 'onPlay');
      });

      that.innerAudioContext.onError((err) => {
        console.error('音频播放出错', err);
      });

      that.innerAudioContext.onEnded(async () => {
        // 如果是最后一个片段,这里可以结束,否则不需要await
        if (text === radioList[radioList.length - 1]) {
          that.setData({
            type: 'play',
          })
        }
      });
      // 确保前一个音频播放结束后再播放下一个
      await new Promise(resolve => {
        that.innerAudioContext.onEnded(resolve);
        that.innerAudioContext.play();
      });
    }
  },
  // 暂停阅读
  readPause: function () {
    this.innerAudioContext.pause()
    const that = this;
    that.setData({
      type: 'play',
    })
  }

2. 对于splitStringByLength方法,我也进行了一些优化 (wx.createInnerAudioContext()只支持1000个字符以内的文字转为音频)

下面一段代码是无脑按照长度切割,在进行语音播报的时候,第一段语音和第二段语音之前的衔接会有1-2秒的停顿,语音播报不流畅
比如:您好,我是您的健康管家"向我提问。您好,我是您的健康 | 管家"质迹"!您有什么疑问都可以在此向我提问。
在 | 处切成两段,语音在播放到‘康’的时候,会停顿1-2秒,在开始播放‘管家…’

splitStringByLength :function (str, length)  {
	  let result = [];
	  for (let i = 0; i < str.length; i += length) {
	    result.push(str.substring(i, i + length));
	  }
	  return result;
	}

在此,我对切割方法进行了一下优化

  • 不超过length的长度,不进行切割
  • 超过length的长度,首先找中文句号,在中文句号处切割
  • 如果整个文本都没有中文句号,则在中文逗号处切割
  • 语音在逗号和句号处本来就是会停顿的,在此处切割,这样用户的体验更好一些
const splitStringByLength = (text, length) => {
  const MAX_LENGTH = length;  // 最大长度
  const CHINESE_PERIOD = '。'; // 首个切割条件
  const CHINESE_COMMA = ',';  // 当首个切割条件不存在时的次要切割条件
  let result = [];
  let startIndex = 0;
  // 文本长度不超过最大长度,就不切割,直接返回
  if (text.length < MAX_LENGTH) {
    return [text]
  }
  while (startIndex < text.length) {
    // 查找下一个中文句号的位置,若找不到则返回-1
    let periodIndex = text.indexOf(CHINESE_PERIOD, startIndex);
    if (periodIndex === -1 || periodIndex - startIndex > MAX_LENGTH) {
      // 如果没有找到句号,或者句号距离起始点超过了300个字符
      // 则查找中文逗号的位置,同样,若找不到则返回-1
      let commaIndex = text.lastIndexOf(CHINESE_COMMA, startIndex + MAX_LENGTH);
      if (commaIndex === -1 || commaIndex <= startIndex) {
        // 如果也没有找到逗号,或者逗号位置不满足条件,则直接在MAX_LENGTH处截断
        result.push(text.substring(startIndex, startIndex + MAX_LENGTH));
        startIndex += MAX_LENGTH;
      } else {
        // 找到了逗号并且位置合适,就在逗号后分割
        result.push(text.substring(startIndex, commaIndex + 1));
        startIndex = commaIndex + 1;
      }
    } else {
      // 找到了句号并且位置合适,就在句号后分割
      result.push(text.substring(startIndex, periodIndex + 1));
      startIndex = periodIndex + 1;
    }
  }

  return result;
}

在使用uni-app开发微信小程序时,与直接使用微信网页开发工具开发微信小程序有一些差别。由于uni-app可以开发多平台,因此不同平台的开发需要在指定的位置进行相应的配置才能生效。对于引入微信同声传译小程序,有两种方式可以实现。一种是整个小程序可使用,即小程序中的所有分包都可以使用该功能。另一种是指定对应的分包可使用该功能。在使用插件之前,需要在manifest.json文件的mp-weixin内声明使用的插件,并进行相应的配置。具体的配置可以参考所使用插件的开发文档。在代码中,可以直接使用文档中提供的代码来实现微信同声传译的功能。通过引入插件并调用相应的方法,可以实现文本转语音的功能。例如,可以使用plugin.textToSpeech方法来实现将指定的文本转换为语音的功能。在方法的参数中,可以指定语言、是否启用语音合成等。成功调用该方法后,可以在回调函数中获取到生成的语音文件的信息。 #### 引用[.reference_title] - *1* *2* *3* [uni-app微信小程序开发,引入微信同声传译插件](https://blog.csdn.net/qq_32837111/article/details/106804236)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值