- 微信小程序使用科大讯飞语音评测,保姆级教程!
最近微信小程序项目中,需要添加语音评测功能,就选用了科大讯飞的语音评测流式版接口,但在使用过程中,遇到了很多问题,再网上搜资料,搜了好多,也没直接能用的,好在后来参考了许多资料后,终于调试成功了,接下来,跟大家分享一下我是怎么处理的。 1.第一步,准备所用到的工具,下载官方jsdemo,将 base64js 文件复制到自己的小程序项目中,用npm安装crypto-js xmldom这2个工具 然后,将工具导入到页面中 const CryptoJS = require('crypto-js') const Base64 = require('../../tools/base64js').Base64; var DOMParser = require('xmldom').DOMParser; 2.第二步,初始化用到的变量,定义用到的关键函数 const APPID = '替换成你自己的' const API_SECRET = '替换成你自己的' const API_KEY = '替换成你自己的' let audioData = [] //存储音频流的数组 let socketTask = null //小程序的socketTask let handlerInterval = null // 定时器,用来定时发送数据流 function getWebSocketUrl() {//生成socket使用的url return new Promise((resolve, reject) => { var url = 'wss://ise-api.xfyun.cn/v2/open-ise' var host = 'ise-api.xfyun.cn' var apiKey = API_KEY var apiSecret = API_SECRET var date = new Date().toGMTString() var algorithm = 'hmac-sha256' var headers = 'host date request-line' var signatureOrigin = `host: ${host}\ndate: ${date}\nGET /v2/open-ise HTTP/1.1` var signatureSha = CryptoJS.HmacSHA256(signatureOrigin, apiSecret) var signature = CryptoJS.enc.Base64.stringify(signatureSha) var authorizationOrigin = `api_key="${apiKey}", algorithm="${algorithm}", headers="${headers}", signature="${signature}"` var authorization =Base64.encode(authorizationOrigin) url = `${url}?authorization=${authorization}&date=${date}&host=${host}` resolve(url) }) } 3.开始录音 //开始录音 startVoiceRecord(){ let that = this that.setData({recordState:'recording'}) recorderManager.onStart(() => { console.log('recorder start') }) recorderManager.onPause(() => { console.log('recorder pause') }) recorderManager.onStop((res) => { console.log('recorder stop', res) const { tempFilePath } = res that.startUpRecord()//录音完成,准备调用讯飞接口 }) recorderManager.onFrameRecorded((res) => { const { frameBuffer } = res console.log('frameBuffer.byteLength', frameBuffer.byteLength) let u8Arr = new Uint8Array(frameBuffer) audioData.push(u8Arr) //将每一帧的数据取出,放到audioData中,准备使用 }) const options = { duration: 180000, sampleRate: 16000, numberOfChannels: 1, encodeBitRate: 44100, frameSize: 2, format: 'pcm', } recorderManager.start(options) }, 4. 开始socket连接,准备上传数据并处理 startUpRecord(){ let that = this getWebSocketUrl().then(( url)=>{ let newURL = encodeURI(url) socketTask = wx.connectSocket({ url: newURL, }) socketTask.onOpen(()=>{ console.log('打开了socket') that.webSocketSend() }) socketTask.onMessage((e)=>{ // result 在这里做信息处理 console.log('收到了结果:',e) that.result(e.data) }) socketTask.onError((err)=>{ //结束录音 console.log('socket 出错:',err) }) socketTask.onClose(()=>{ // 结束录音 console.log('socket 关闭:') }) }) }, webSocketSend() { console.log('开始发送数据',audioData) let that = this let audioDataUp = audioData.splice(0, 1) var params = { common: { app_id:APPID, }, business: { category: 'read_sentence', // read_syllable/单字朗读,汉语专有 read_word/词语朗读 read_sentence/句子朗读 https://www.xfyun.cn/doc/Ise/IseAPI.html#%E6%8E%A5%E5%8F%A3%E8%B0%83%E7%94%A8%E6%B5%81%E7%A8%8B rstcd: 'utf8', group: 'pupil', sub: 'ise', ent: 'cn_vip', tte: 'utf-8', cmd: 'ssb', auf: 'audio/L16;rate=16000', aus: 1, aue: 'raw', text: '\uFEFF' + '今天天气怎么样?' }, data: { status: 0, encoding: 'raw', data_type: 1, data: that.toBase64(audioDataUp[0]), }, } console.log(JSON.stringify(params)) socketTask.send({data: JSON.stringify(params)}) handlerInterval = setInterval(() => { // websocket未连接 if (!socketTask) { clearInterval(handlerInterval) return } // 最后一帧 if (audioData.length === 0) { console.log('数据发送完毕') socketTask.send( {data: JSON.stringify({ business: { cmd: 'auw', aus: 4, aue: 'raw' }, data: { status: 2, encoding: 'raw', data_type: 1, data: '', }, })} ) audioData = [] clearInterval(handlerInterval) return false } audioDataUp = audioData.splice(0, 1) // 中间帧 console.log('audioDataUp:',audioDataUp[0]) socketTask.send( { data: JSON.stringify({ business: { cmd: 'auw', aus: 2, aue: 'raw' }, data: { status: 1, encoding: 'raw', data_type: 1, data: that.toBase64(audioDataUp[0]), }, })} ) }, 40) }, result(resultData) { // 识别结束 let jsonData = JSON.parse(resultData) if (jsonData.data && jsonData.data.data) { let data = Base64.decode(jsonData.data.data) const doc=new DOMParser().parseFromString(data,'text/xml'); let sentence = doc.getElementsByTagName('read_sentence')[1] let accuracy_score = sentence.getAttribute('accuracy_score') let emotion_score = sentence.getAttribute('emotion_score') let fluency_score = sentence.getAttribute('fluency_score') let total_score = sentence.getAttribute('total_score') let integrity_score = sentence.getAttribute('integrity_score') let phone_score = sentence.getAttribute('phone_score') let tone_score = sentence.getAttribute('tone_score') let is_rejected = sentence.getAttribute('is_rejected') console.log('parseRes:',accuracy_score,emotion_score,fluency_score,total_score) //评测结果在这里,就出来了,然后就可以拿评测数据去使用了 } if (jsonData.code === 0 && jsonData.data.status === 2) { // 在这里结束socket socketTask.close() } if (jsonData.code !== 0) { socketTask.close() console.log(`${jsonData.code}:${jsonData.message}`) } }, 到这里,整个流程就完了,祝愿大家都能一次调用成功,有什么问题的话,咱们再讨论!
2023-06-13 - 微信开发者工具扩展插件版本能否支持手动更新?
背景 小程序项目接入Eslint后计划在小组内推广,然后同事问我个问题: 微信开发者工具能看到eslint报错的嘛? 这确实是个好问题,这点对于习惯用微信开发者工具的同事来说确实需要考虑下(本人习惯vscode工具开发,然后安装eslint插件这些就很方便,是我考虑不周了)。 落地方案 微信开发者工具-> 设置 -> 扩展设置 -> 编辑器设置-> 安装Eslint && Prettier,安装完后记得重新启动微信开发者工具。 进入测试 发现不满足规则的,开发者工具会置灰,鼠标移上去也支持报错提示&快速fix, 但是好像没有vscode的红色波浪线报错,就好像没这么直观了。 查看下微信开发者工具中集成的eslint的版本还是v2.1.6。 [图片] 对比之后发现是eslint的版本不同导致的效果差异: v2.1.16在vscode无波浪线&问题处无问题;在v2.2.2新版本中有波浪线&问题处能实时看到问题原因。 [图片] [图片] 问题: 官方能否支持开发者手动升级插件的版本?(eg: 在这个demo中若能支持手动升级到v2.2.2的版本,应该是可以更好地优化错误提示的) 官方: 相关文档:https://developers.weixin.qq.com/miniprogram/dev/devtools/editorextensions.html 但本人在测试的时候,并未看到官方相关截图,测试微信开发者工具版本: stable 1.05.2204250。 [图片] 问题处理方案: > 秉承官方出的功能肯定是有落地方案的,在google一波果然发现了解决方案。 找到VSCODE中已经安装好的插件包(windows电脑默认在: C:\Users\xxx\.vscode\extensions), eg: eslint找到微信开发者中扩展插件的安装目录: 右上角编辑-> 打开编辑器扩展目录即可打开。[图片] 找到想要替换的插件包的文件夹,打开其package.json,找到其ID(metadata字段)[图片] [图片] 打开编辑 -> 管理编辑器设置 到这一步就被卡死了,翻天找地都没看到网友说的下面这张图是哪里来的(猜测是版本的问题,这里就不纠结了,换个方案) [图片](下图来源于网络图,若有侵权等行为请随时联系删除) 建议解决方案 找到VSCODE中已经安装好的插件包(windows电脑默认在: C:\Users\xxx\.vscode\extensions), eg: eslint,拷贝该文件夹。扩展插件-> 更多-> 导入已安装的vscode扩展,具体操作如下图:该步骤会把我们vscode工具有的扩展工具都同步过来。注意:这里推荐从已解包的扩展文件夹安装(不一定vscode的插件都用得上,按需导入比较合理) [图片] 啊哦,导入不成功,因为版本不兼容。 [图片] 终极问题:微信开发者工具扩展插件版本能否支持手动更新??对于这种版本不兼容的,普通开发者能做的是什么呢?
2022-05-23 - 如何在微信内外部浏览器唤起小程序
微信外部浏览器唤起微信小程序目的:通过发送短信召回流失用户。官方文档地址https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/url-scheme/urlscheme.generate.html步骤一该API我们主要用到的配置如下:jump_wxa:跳转到的目标小程序信息。该对象内包含两个字段。path:通过scheme码进入的小程序页面路径,必须是已经发布的小程序存在的页面,不可携带queryquery:通过scheme码进入小程序时的query。步骤二需要注意的是,query必传,然而如果我们需要跳转的页面不需要参数,也需要配置上query,默认我们填写的是from=sms, 用于统计是从短信渠道来的。步骤三与后端约定access_token 通过前端传递appKey进行区分,传哪个微信小程序的appKey 就生成对应小程序的access_token。步骤四支持设置scheme的过期时间,默认永久,我们的应用场景很少,暂不详说。步骤五代码里操作如下,由后端聚合参数信息。let postData = { appKey: 'QTSHE_MINI_APP', path: 'pages/partdetails/partdetails', query: 'partJobId=123456' || 'a=1' } this.$axios.post('xxx', postData).then((res) => { if (res.success) { const url = res.data.openlink // 将scheme转为我们平台的短链接,否则在安卓手机上无法打开微信小程序,会默认打开浏览器搜索。 this.$axios.get(`xxx`, {url}).then((res) => { if (res.success) { this.shortLink = res.data // 将weixin://xxxx 转换为 https://b.qtshe.com/xxx } }) } else { this.$Message.error('获取失败,请稍后重试') } }).catch((err) => { console.log(err) this.$Message.error('获取失败,请稍后重试') }) 微信内部浏览器唤起小程序官方文档地址https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_Open_Tag.html步骤一首先需要登录微信公众平台进入“公众号设置”的“功能设置”里填写“JS接口安全域名”,未配置会导致wx.config签名失败,导致无法使用开放标签。步骤二在需要调用JS接口的页面引入如下JS文件:https://res.wx.qq.com/open/js/jweixin-1.6.0.js,1.6.0版本内才增加了上述标签,低于该版本的都无法显示。步骤三通过config接口注入权限验证配置并申请所需开放标签, 在wx.config里增加openTagList标签,内置两个开放标签 [代码]wx-open-launch-app[代码] 微信h5唤起本地已经安装的app,以及 [代码]wx-open-launch-weapp[代码] 微信h5唤起小程序,操作如下:wx.config({ debug: false, appId: window.g_info.wx_appid, // 全局变量appId timestamp: data.data.timestamp, // 调用微信接口返回的 nonceStr: data.data.nonceStr, // 调用微信接口返回的 signature: data.data.signature, // 调用微信接口返回的 jsApiList: ['openLocation', 'getLocation'], // 这里需要任意填写api,不能为空 openTagList: [ 'wx-open-launch-app', 'wx-open-launch-weapp' ] }) 注意点对于Vue等视图框架,为了避免template标签冲突的问题,可使用[代码]<script type="text/wxtag-template"></script>[代码]进行代替,来包裹插槽模版和样式。页面中与布局和定位相关的样式,如[代码]position: fixed; top -100;[代码]等,尽量不要写在插槽模版的节点中,请声明在标签或其父节点上;对于有CSP要求的页面,需要添加白名单frame-src https://*.qq.com webcompt:,才能在页面中正常使用开放标签。// Vue里操作代码如下,如果需要写样式,最好是外部包一个div进行样式编写,内部的内容宽高100%即可,调试样式可使用微信开发者工具的网页模式: .quick-btn { // 这里写样式 width: 3.43rem; height: 0.96rem; display: flex; img { width: 100%; display: block; } } <div class="quick-btn"> <img src="https://qiniu-image.qtshe.com/20220317quick-apply.png" alt="" /> </div> 示例效果[图片] 为了方便运营同学,做了个工具给他们使用。 [图片] 2023年4.11号新版本后的改版方案: 首先做一个落地页:https://b.qtshe.com/1DF43E 代码如下: import toast from 'toast' export default { created() { this.init() }, methods: { // 获取微信scheme地址,并且主动跳转一次 init() { this.$axios.post(`https://xxx/你们的接口地址/user/device/scheme`, this.$route.query).then(res => { if (res.success) { window.location.href = res.data } else { toast(res.msg) } }).catch(() => { toast('服务器错误,请稍后重试') }) } } } 原理:通过地址栏配置需要跳转的参数,h5页面拿到参数后通过接口转换为weixin://xxxx 开头的scheme协议地址,并且主动location.href一次。这样能保证用户每次打开都是新的scheme地址,针对一天50w数量上限的问题,可尝试同一个用户在固定时间内相同的参数,返回相同的scheme地址。 以上限制只存在于除微信外的外部浏览器,微信容器里没有以上的限制。 2023年12月18日后方案: 官方公告如下: https://developers.weixin.qq.com/community/develop/doc/00024e32cbc36055c0c0a34b066401 ,没有外部浏览器、微信环境的限制,可以被多人打开。 使用方式通过明文拼接: weixin://dl/business/?appid=*APPID*&path=*PATH*&query=*QUERY*&env_version=*ENV_VERSION* 示例: // query需要encode编码,ENV_VERSION为控制打开开发版、体验版、线上版本 weixin://dl/business/?appid=wxa7b0b022472e55e6&path=pages/partdetails/partdetails&query=partJobId%3D123456 通过明文 URL Scheme 拉起的小程序(页面)必须要提前在「小程序管理后台 -> 设置 -> 隐私与安全 -> 明文 scheme 拉起此小程序」中进行声明; 小程序:配置能够通过明文 scheme 进入的小程序页面[图片] 这一点很烦很烦,希望能支持下 默认可打开所有的,不然每次都得去配置。
08-07