当前位置:网站首页>小程序-语音播报功能
小程序-语音播报功能
2022-08-10 14:31:00 【吟秋知忆】
功能需求
实现通过传入“语音文案自动播报”,如:“测试播报”,语音自动播报“测试播报”
方案
使用wx.playVoice播放语音文件
优点:使用简单,直接播放录制好的音频文件
缺点:只能播放录制好的语音文件
第三方语音服务 + wx.createInnerAudioContext
优点:功能强大,可定制,可以满足复杂的场景;
缺点:需要服务端对接,付费
小程序插件 + wx.createInnerAudioContext
优点:简单快捷,适用于简单场景;
缺点:功能单一,无法定制,大写英文无法识别,部分小写英文发音不准
第三方语音平台
语音平台
服务端
对接第三方平台,将转换后的语音数据交给小程序。
小程序
1.添加请求
wx.request({
url: 'https://xxxx.com',
data: { data: "待合成的语音数据"},
method: "get",
header: {
'content-type': 'application/json' // 默认值
},
dataType: "json",
success: function (res) {
const innerAudioContext = wx.createInnerAudioContext();
innerAudioContext.src = res.filename;
innerAudioContext.play();
}
})
微信插件
添加 微信同声传译
插件:在微信公众平台配置,找到设置–第三方设置–插件管理–点击添加插件搜索 微信同声传译
,点击添加引入插件:在项目根目录app.json文件中配置
"plugins": {
// 引入插件
"WechatSI": { // 自定义的名字
"version": "0.3.5", // 引入插件的版本号
"provider": "wx069ba97219f66d99" // 引入插件的appID
}
}
使用
const plugin = requirePlugin('WechatSI');
onReady() {
this.innerAudioContext = wx.createInnerAudioContext();
const that = this;
plugin.textToSpeech({
// 调用插件的方法
lang: 'zh_CN',
content: '测试语音播报',
success: function (res) {
that.playAudio(res.filename);
}
});
},
playAudio(e) {
this.innerAudioContext.src = e;
this.innerAudioContext.play();
},
封装优化
const plugin = requirePlugin('WechatSI');
import { trim, isLetter } from '@/shared/index';
class PluginService {
innerAudioContext;
audioBroadcast(content: string): Promise<any> {
return new Promise((resolve, reject) => {
this.innerAudioContext = wx.createInnerAudioContext();
plugin.textToSpeech({
// 调用插件的方法
lang: 'zh_CN',
content,
success: res => {
this.playAudio(res.filename, resolve, reject);
},
fail: reject
});
});
}
playAudio(e, resolve, reject) {
this.innerAudioContext.src = e;
this.innerAudioContext.play();
this.innerAudioContext.onStop(() => {
console.log('[ onStop ] >');
resolve({
type: 'stop'
});
});
this.innerAudioContext.onEnded(() => {
//播放结束,销毁该实例
this.innerAudioContext.destroy();
console.log('[ onEnded ] >');
resolve({
type: 'end'
});
});
this.innerAudioContext.onError(error => {
console.log('[ onError ] >', error);
this.innerAudioContext.destroy();
reject(error);
});
}
stopAudio() {
this.innerAudioContext.stop();
this.innerAudioContext.destroy();
}
}
export default new PluginService();
在shared/index中工具函数:
// 去掉字符串中所有空格(包括中间空格,需要设置第2个参数为:true)
export function trim(str: string, isGlobal = true) {
if (!str) {
return str;
}
const result = str.replace(/(^\s+)|(\s+$)/g, '');
return isGlobal ? result.replace(/\s/g, '') : result;
}
// 判断是否为字母
export function isLetter(str) {
const reg = /^[A-Za-z]+$/;
return reg.test(str);
}
// 字母转中文
export function translateAlphabet(letters) {
if (!letters || !(letters.length > 0)) {
return letters;
}
let tLetters = '';
for (const key of letters) {
tLetters += alphabetComparison(key);
}
return trim(tLetters);
}
// 字母中文读法
export function alphabetComparison(letter) {
if (!letter || !isLetter(letter)) {
return letter;
}
const letterCase = letter.toUpperCase();
const letterMap = {
A: '诶',
B: 'b',
C: '西',
D: '帝',
E: '伊',
F: 'f',
G: 'g',
H: 'h',
I: 'i',
J: 'j',
K: 'k',
L: 'l',
M: 'm',
N: 'n',
O: '欧',
P: 'p',
Q: 'q',
R: 'r',
S: '爱死',
T: 't',
U: '优',
V: 'v',
W: 'w',
X: 'x',
Y: '歪',
Z: 'z'
};
return letterMap[letterCase];
}
在页面中使用
import { pluginService, translateAlphabet } from '@util';
import { formatCabinetNo, getCacheCabinet } from '@/shared/index';
Page({
...
onLoad(e) {
// 获取订单结果类型
this.autoPlay();
},
onUnload() {
pluginService.stopAudio();
},
// 轮询播放多次
autoPlay(timerCount = 0, maxCount = 100) {
const { address, lockerName } = this.data;
console.log('timerCount:', timerCount);
if (timerCount > maxCount) {
return;
}
const tAddress = translateAlphabet(address);
console.log('[ translateAlphabet ] >', tAddress);
// '认准柜门号再存放,不要存错门'
const message = `您的柜门号是${tAddress}${lockerName},请认准柜门号存放,不要存错门`;
pluginService
.audioBroadcast(message)
.then(res => {
if (res.type !== 'stop') {
this.autoPlay(++timerCount);
}
console.log('audioBroadcast.complete', res);
})
.catch(err => {
console.log('[ audioBroadcast.err ] >', err);
this.autoPlay(timerCount);
});
}
});
注意:
语音输入配额:每个小程序250条/分钟,3w条/天。 文本翻译配额:每个小程序500次/分钟,10w次/天。 语音合成配额:每个小程序100次/分钟,2w次/天。
问题归档
在小程序onHide,onUnload函数里调用 stop
方法无效;需要同时调用destroy
方法
this.innerAudioContext.stop();
this.innerAudioContext.destroy();
经测试发现中文中的大写英文字母无法识别,部分小写英文字母发音有误
参考
关注我
利用空闲时间免费兼职(无门槛,长期有效),请联系我(PS:关注公众号后,点击“联系我”获取联系方式)~
边栏推荐
- CSP-J1 CSP-S1 初赛 第1轮(2022.08.09)
- 写不完的数学试卷-----试卷生成器(Qt含源码)
- High-paid programmers & interview questions series 135 How do you understand distributed?Do you know CAP theory?
- 1004 (tree array + offline operation + discretization)
- laravel 抛错给钉钉
- 2022年网络安全培训火了,缺口达95%,揭开网络安全岗位神秘面纱
- 【MinIO】Using tools
- Understanding_Data_Types_in_Go
- 注意力模型---Attention Model
- 简单的写一个防抖跟节流
猜你喜欢
随机推荐
PyTorch 多机多卡训练:DDP 实战与技巧
【Gazebo入门教程】第三讲 SDF文件的静/动态编程建模
vue 怎么清除tab 切换缓存问题 ?
antd组件中a-modal设置固定高度,内容滚动显示
systemui状态栏添加新图标
Error: Rule can only have one resource source (provided resource and test + include + exclude)
如何完成新媒体产品策划?
MySQL advanced (thirty-three) MySQL data table adding fields
使用mysq语句操作数据库
win2012安装Oraclerac失败
机器学习总结(一)
实现一个深克隆
八大排序总是忘?快来这里~
redhat替换yum源时redhat.repo无法删除或无法禁用的问题解决方法
每个月工资表在数据库如何存储?求一个设计思路
紫金示例
BFT机器人带你走进智慧生活 ——探索遨博机器人i系列的多种应用
Understanding_Data_Types_in_Go
"Thesis Reading" PLATO: Pre-trained Dialogue Generation Model with Discrete Latent Variable
符合信创要求的堡垒机有哪些?支持哪些系统?