前言
最近在我的学习卡盒小程序中增加了一个卡片人声朗读的效果,点击右小角的播放按钮就会播放卡片中的文字对应的人声朗读效果。效果如下图:
主要的原理是用到了小程序的同声传译插件,下面就详细讲讲如何将这个插件集成,以及交互应该怎么做.
引用插件
微信的同声传译插件有三个功能,分别是 语音输入,文本翻译和语音合成(文字转语音),我用到的就是语音合成功能。
首先微信服务市场中登录并添加同声传译插件,我是个人账号同样可以申请,链接在这里:fuwu.weixin.qq.com/service/det…
添加完成后在小程序后台 mp.weixin.qq.com/ 点击左下角的账号设置
顶部 Tab 栏选择第三方设置,在插件管理中找到同声传译插件,点击详情
在详情中可以查看插件的 APPID,提前复制好
接下来在小程序项目的 manifest.json
文件中添加一个插件引用:
diff
代码解读
复制代码
"mp-weixin": { "appid": "wxff30426f8850b0d7", "setting": { "urlCheck": false }, "usingComponents": true, + "plugins": { + "WechatSI": { + "provider": "上一步复制的 APPID", + "version": "0.3.6" } } },
如此操作,插件就算是在项目中成功引用了。
功能使用
首先,在代码中引用插件:
ts
代码解读
复制代码
const plugin = requirePlugin('WechatSI')
下一步尝试调用一下 API 看看能不能调通:
ts
代码解读
复制代码
plugin?.textToSpeech({ content, lang: 'zh_CN', success: (res) => { audio.src = res.filename audio.play() }, fail: (err) => { console.log('err: ', err) uni.showToast({ icon: 'none', title: '朗读失败,请稍后重试', }) },
这里的 content
是文本内容,lang
是语言,更多参数可以查看文档,如果能够顺利调通就可以开始尝试搭配功能使用。上面的代码可以看到,调用成功返回了一个音频文件的地址,因此我们需要播放这个音频文件。
ts
代码解读
复制代码
const audio = uni.createInnerAudioContext() audio.src = res.filename audio.play()
音频的播放需要用到小程序的 createInnerAudioContext
API 去创建音频上下文实例,然后修改实例的 src
属性指定播放音频的链接,在执行 play()
就可以将音频播放。
完整的配置大家可以参考我的代码示例,上手即用:
ts
代码解读
复制代码
const onPlaying = ref(false) // 播放状态,true表示正在播放,false表示未播放 const onAudioLoading = ref(false) // 加载状态,true表示正在加载音频,false表示加载完成或未开始加载 // 使用reactive来创建一个响应式对象,用于缓存音频文件的名称 const audioCacheFileName = reactive({}) // 创建一个内部音频上下文,用于控制音频的播放、停止等 const audio = uni.createInnerAudioContext() // 使用lodash的debounce函数来防抖处理点击事件,确保在短时间内多次点击只执行一次操作 const onSpeakBtnClick = _.debounce(() => { // 如果当前正在播放音频,则停止播放 if (onPlaying.value) { audio.stop() return } // 根据当前卡片索引和翻转状态获取要朗读的内容 const content = cardItemList.value[currentCardIndex.value]?.[ isCardFlipped(currentCardIndex.value) ? 'backContent' : 'frontContent' ]?.trim() // 检查缓存中是否已存在该内容的音频文件 if (audioCacheFileName[content]) { // 如果存在,则直接使用缓存的音频文件 audio.src = audioCacheFileName[content] audio.play() return } // 设置加载状态为true,表示开始加载音频 onAudioLoading.value = true // 调用文本转语音插件,将文本转换为语音 plugin?.textToSpeech({ content, // 要转换的文本内容 lang: 'zh_CN', // 使用的语言,这里是中国大陆普通话 success: (res) => { // 成功获取音频文件后,设置音频源为转换后的文件,并缓存文件名 audio.src = res.filename audioCacheFileName[content] = res.filename audio.play() // 播放音频 }, fail: (err) => { // 转换失败时,输出错误信息并显示提示 console.log('err: ', err) uni.showToast({ icon: 'none', title: '朗读失败,请稍后重试', }) }, complete: () => { // 无论成功或失败,完成后都将加载状态设置为false onAudioLoading.value = false }, }) }, 300) // 防抖时间间隔设置为300毫秒 // 监听音频播放事件,当音频开始播放时,将播放状态设置为true audio.onPlay(() => { onPlaying.value = true })
注意点
-
大家可以看到我的代码示例中指定了语言为中文,其实我的小程序中是既有中文也有英文的,在最开始我自己实现了一个判断字符串中英文和符号的函数,但是后面发现无论是中文还是英文,指定为中文都可以正常朗读,省去了很多判断,而且中文的人声更好听,音质也更好,如果指定英文读出来的机械感很重,所以这里大家不必花心思去判断语言类型。
-
API 的调用是有限额的,因此播放按钮最好做个防抖处理。除了防抖,在我的代码中我还简单实现了一个缓存机制,当段文本播放过之后就会放到
audioCacheFileName
对象中,每次播放时,先对比一下当前的文本是不是已经朗读过了,如果已经朗读过了,并且内容没有修改就直接播放已经请求过的那个音频,这样可以大大减少 API 的调用次数。
原文链接:https://juejin.cn/post/7445930510021787685