微信同声传译插件,语音识别文字及语音播报功能详解
文档地址:https://developers.weixin.qq.com/miniprogram/dev/platform-capabilities/extended/translator.html
1. 语音输入转为文字:
- 长按左下角小图标开始说话
- 松开说话结束,开始识别
- 识别成功后会将识别文字显示在最下面输入框内
//引入插件:微信同声传译
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() 来进行播放音频
- 点击播放按钮会播放语音,播放按钮变成暂停按钮
- 点击暂停按钮暂停播放
- 播放完成后按钮自动变回播放按钮
注意:语音合成功能,限制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',
})
}
这个语音播报在使用过程中,发现了一些问题,他并不是完美的,因此我做了一下修改
详见: