微信同声传译插件,语音识别文字及语音播报功能详解

文档地址:https://developers.weixin.qq.com/miniprogram/dev/platform-capabilities/extended/translator.html

1. 语音输入转为文字:

  1. 长按左下角小图标开始说话
  2. 松开说话结束,开始识别
  3. 识别成功后会将识别文字显示在最下面输入框内
//引入插件:微信同声传译
const plugin = requirePlugin('WechatSI');
//获取全局唯一的语音识别管理器recordRecoManager
const manager = plugin.getRecordRecognitionManager();

Page({
	data:{
		value:'',
		recordState:false,
		isOver:false
	},
	onLoad:function(options){
		this.initRecord()
	}
	// 初始化
  	initRecord: function () {
	    const that = this;
	    // 有新的识别内容返回,则会调用此事件
	    manager.onRecognize = function (res) {
	      console.log(res);
	    };
	    // 正常开始录音识别时会调用此事件
	    manager.onStart = function (res) {
	      console.log("成功开始录音识别", res);
	    };
	    // 识别错误事件
	    manager.onError = function (res) {
	      that.setData({
	        recordState: false,  // 关闭‘正在说话’弹窗
	        value: '',			 // 输入框值为空	
	      });
	    };
	    //识别结束事件
	    manager.onStop = function (res) {
		    // tempFilePath 录音临时文件地址
		    // duration 录音时长 ms
		    // fileSize 文件大小 B
		    // result 识别结果
		      if (res.result == "") {
		        wx.showModal({
		          title: "提示",
		          content: "听不清楚,请重新说一遍!",
		          showCancel: false,
		          success: function (res) { },
		        });
		        return;
		      }
		      that.setData({
		        value: res.result,   // 输入语音后转为的文字
		        recordState: false,
		      });
	    };
  },
  //语音  --按住说话
  touchStart: function (e) {
    if (this.data.value == '语音识别中,请稍后...') return
    this.setData({
      recordState: true, //录音状态
      value: '语音输入中...'
    });
    // 语音开始识别
    manager.start({
      lang: "zh_CN",
    });
  },
  //语音  --松开结束
  touchEnd: function (e) {
    if (this.data.value == '语音识别中,请稍后...') return
    this.setData({
      recordState: false,
      value: '语音识别中,请稍后...'
    });
    // 语音结束识别
    manager.stop();
  },
})
<view class="question-field">
	    <view class='touch-long'>
	      <image class='warn-style' src='../../../static/images/warning.png'></image>
	      长按语音图标可以进行语音输入
	    </view>
	    <view class="question-bottom">
	      <image
	        class='yuyin-img'
	        src='../../../static/health/yuyin.png'
	        bindtouchstart="touchStart"
	        bindtouchend="touchEnd"
	      ></image>
	      <van-field
	        value="{{ value }}"
	        placeholder="请输入内容"
	        border="{{ false }}"
	        class="input"
	        bind:change='onChange'
	        disabled='{{isOver}}'
	      ></van-field>
	      <p bindtap='sendMsg'>发送</p>
	    </view>
  </view>
  <cover-view class="startYuyinImage" wx:if="{{recordState == true}}">
	  <cover-image src="../../../static/health/yuyinfff.png"></cover-image>
	  <cover-view>正在说话</cover-view>
	</cover-view>
// json
"usingComponents": {
     "van-field":"@vant/weapp/field/index" 
 },

直接复制代码应该是能跑的

2. 语音合成播报功能

语音播报功能除了使用微信同声传译将文字转化为音频文件之外,还需要使用 wx.createInnerAudioContext() 来进行播放音频

语音识别 spddle_语音识别 spddle


语音识别 spddle_微信小程序_02

  1. 点击播放按钮会播放语音,播放按钮变成暂停按钮
  2. 点击暂停按钮暂停播放
  3. 播放完成后按钮自动变回播放按钮
注意:语音合成功能,限制1000个字符,超出1000就会合成失败,下面我也提出了解决办法
<view class="rich-play">
          <view class="message">
            <text class="showDesc">{{dialogue}}</text>
          </view>
          <image
            class="img-play-pause"
            src='../../../static/images/play.png'
            bindtap='readText'
            wx:if="{{type=='play'}}"
          ></image>
          <image
            class="img-play-pause"
            src='../../../static/images/pause.png'
            bindtap='readPause'
            wx:if="{{type=='pause'}}"
          ></image>
        </view>
data:{
	dialogue:'您好,我是您的健康管家"向我提问。您好,我是您的健康管家"质迹"!您有什么疑问都可以在此向我提问。',
	type:'play'
	}
  // 阅读文字
  readText: async function () {
    const that = this;
    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();
      innerAudioContext.src = text;

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

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

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

这个语音播报在使用过程中,发现了一些问题,他并不是完美的,因此我做了一下修改

详见: