微信小程序H5页面接入语音识别
之前做过一个项目,Web
端使用百度实时语音识别,提供让用户语音输入的功能,但嵌入微信小程序的H5
页面,不能使用Web
原生的方式获取到音频流。此时如果需要接入语音识别,可以使用微信提供的weixin-js-sdk
相关api
接入语音识别。
注意 该方案为非实时识别的解决方案,实时方案只能原生支持。
接入流程
- 因使用
weixin-js-sdk
中微信提供的api
需要公众号授权。所以需要先完成公众号授权。 - 授权后
H5
页面需要通过config
接口注入权限验证配置,才可使用对应的api
。 config
注入接口需要校验签名,签名需要ticket
,而获取ticket
需要access_token
,所以我们需要先获取access_token
然后再获取ticket
。最后调用config
接口注入权限验证配置。- 注入
api
权限后,使用相关api
完成录音与音频识别功能。
1.公众号授权
公众号授权相关流程如下:
- 绑定域名
- 获取
access_token
- 获取
ticket
- 添加
ip
白名单(聚合2,3
两步的接口时才需要添加)
1.1 绑定域名
先登录微信公众平台进入“设置与开发”
的“公众号设置”
的“功能设置”
下设置“JS接口安全域名”
。
提示:添加的安全域名不需要协议部分,如:www.baidu.com
。 备注:登录后可在“开发者中心”
查看对应的接口权限。
1.2 获取access_token
通过公众号
的appid
和secret
来获取access_token
。
发起GET
如:https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={公众号appid}&secret={公众号secretkey}
的请求。
grant_type
为固定值client_credential
appid
为公众号appid
secretkey
为为公众号secretkey
。
返回结果如下:
{
"access_token": "73_toXyG5jzwxY6uRzQ79IwHjvDfX0vuaiwR5qxPU-4FQ06Ve0dJfFPoaY381h8sxMJG_koOch1iDvFuAwlsFD3DVbR7OZOe3jpzqnZ_MoyAimyIGMterY6zI17tPIEQIcACASEW",
"expires_in": 7200
}
access_token
就是我们需要用到的。expires_in
为token
的过期时间,单位是秒。
备注 建议通过expires_in
设置缓存。
1.3 获取ticket
通过上一步获取的access_token
获取ticket
。
发起GET
如:https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi&access_token={上步获取的access_token}
的请求。
type
为固定值jsapi
access_token
为上步获取的access_token
。
返回结果如下:
{
"errcode": 0,
"errmsg": "ok",
"ticket": "kgt8ON7yVITDhtdwci0qeb6KHbTBSX4gULhsMOnjEaYeZEp6TZtETgDmizN7VJ_Y9S6xumxabaPeOEFtxhCqwA",
"expires_in": 7200
}
ticket
就是我们需要用到的。expires_in
为token
的过期时间,单位是秒。
备注 建议通过expires_in
设置缓存。
1.4 添加ip
白名单
获取access_token
和获取ticket
两个接口都是有时效的,且调用资源有限。因此可以通过后端接口缓存一下值,后面可以使用更新缓存值,顺便可以将两个接口聚合成我们系统中的一个接口。 测试时可以手动调用前面两个接口,拿到ticket
完成测试流程。
如果通过后端获取ticket
,则需要添加服务器IP白名单
。微信公众平台进入“设置与开发”``“基本配置”
的“公众号开发信息”
中的“IP白名单”
中添加访问微信相关接口的ip
。
2. 注入权限验证配置
完成公众号授权
相关的内容后,即可开始在H5
页面中通过config
接口注入权限验证配置。以便后续使用weixin-js-sdk
中微信提供的api
。
- 获取
ticket
- 获取
signature
- 注入权限
备注 不要忘了导入weixin-js-sdk
2.1 获取ticket
前面步骤公共聚合接口直接获取ticket
。或者直接调用获取。
2.2 获取signature
config
的调用方式如下:
import wx from "weixin-js-sdk";
wx.config({
debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
appId: '', // 必填,公众号的唯一标识
timestamp: , // 必填,生成签名的时间戳
nonceStr: '', // 必填,生成签名的随机串
signature: '',// 必填,签名
jsApiList: [] // 必填,需要使用的JS接口列表
});
可以看出需要签名,所以生成signature
,参考如下:
import crypto from "crypto";
const nonceStr = '******';
const timeStr = Math.floor(new Date().getTime() / 1000).toString();
const url = 'https://pro.fofinvesting.com/copilot/';
const signature = crypto.createHash("sha1").update(`jsapi_ticket=${ticket}&noncestr=${nonceStr}×tamp=${timeStr}&url=${url}`).digest("hex");
ticket
由上一步流程中获取。nonceStr
随意,建议userId
之类的。timeStr
唯一,建议时间戳。url
必须是1.1 绑定域名
中添加的地址。
注意 url
为完整路径,包括参数等。#
之后的不需要,因此可以使用location.href.split('#')[0]
动态获取,避免错误。
2.3 注入权限
获取signature
后,接着注入权限验证配置。参考:
import WeiXin from "weixin-js-sdk";
WeiXin.config({
debug: process.env.NEXT_PUBLIC_DOMAIN_ENV !== "production", // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
appId: "wx1f30fbc870cb3877", // 必填,公众号的唯一标识
timestamp: timeStr, // 必填,生成签名的时间戳
nonceStr, // 必填,生成签名的随机串
signature, // 必填,签名
jsApiList: ["startRecord", "stopRecord", "translateVoice"], // 必填,需要使用的JS接口列表
});
WeiXin.ready(function () {
// config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后,config是一个客户端的异步操作,
// 所以如果需要在页面加载时就调用相关接口,则须把相关接口放在ready函数中调用来确保正确执行。
// 对于用户触发时才调用的接口,则可以直接调用,不需要放在ready函数中。
console.log("config success");
});
WeiXin.error(function (res: any) {
// config信息验证失败会执行error函数,如签名过期导致验证失败,具体错误信息可以打开config的debug模式查看,也可以在返回的res参数中查看,对于SPA可以在这里更新签名。
console.log("config err", res);
});
- 通过
config
注入权限验证配置时,可以通过ready
和error
监听状态。 jsApiList
包含我们需要使用到的api
。
提示 如果路由不改变则注入权限逻辑可只执行一次。建议提早注册。注册过程为异步,需要等待ready
回调后再使用相关api
。
3. 获取音频
使用startRecord
开始录音,stopRecord
结束录音。
import WeiXin from "weixin-js-sdk";
/**
* 手指按下
* @param e
*/
const onTouchStart = (e: React.TouchEvent<HTMLDivElement>) => {
// 手指按下去
// 开始录音
WeiXin.startRecord();
// 录音时间超过一分钟没有停止的时候会执行 complete 回调
WeiXin.onVoiceRecordEnd({
complete: (res: any) => {
var localId = res.localId;
// 语音识别
wxTranslateVoice(localId);
},
});
};
/**
* 手指离开
* @param e
*/
const onTouchEnd = (e: React.TouchEvent<HTMLDivElement>) => {
// 手指离开屏幕
// 结束录音
WeiXin.stopRecord({
success: (res: any) => {
const localId = res.localId;
// 语音识别
wxTranslateVoice(localId);
},
fail: function (res: any) {
console.log("stopRecord fail", res);
},
});
};
4. 语音识别
使用translateVoice
完成录音识别。
import WeiXin from "weixin-js-sdk";
/**
* 识别
* @param localId
*/
const wxTranslateVoice = (localId: any) => {
WeiXin.translateVoice({
localId, // 需要识别的音频的本地Id,由录音相关接口获得
isShowProgressTips: 1, // 默认为1,显示进度提示
success: (res: any) => {
alert(res.translateResult); // 语音识别的结果
},
fail: (res: any) => {
message.error("识别失败");
},
});
};