Skip to content

微信小程序H5页面接入语音识别

约 1996 字大约 7 分钟

weixin

2025-01-20

之前做过一个项目,Web端使用百度实时语音识别,提供让用户语音输入的功能,但嵌入微信小程序的H5页面,不能使用Web原生的方式获取到音频流。此时如果需要接入语音识别,可以使用微信提供的weixin-js-sdk相关api接入语音识别。

注意 该方案为非实时识别的解决方案,实时方案只能原生支持。

接入流程

  1. 因使用weixin-js-sdk中微信提供的api需要公众号授权。所以需要先完成公众号授权。
  2. 授权后H5页面需要通过config接口注入权限验证配置,才可使用对应的api
  3. config注入接口需要校验签名,签名需要ticket,而获取ticket需要access_token,所以我们需要先获取access_token然后再获取ticket。最后调用config接口注入权限验证配置。
  4. 注入api权限后,使用相关api完成录音与音频识别功能。

1.公众号授权

公众号授权相关流程如下:

  1. 绑定域名
  2. 获取access_token
  3. 获取ticket
  4. 添加ip白名单(聚合2,3两步的接口时才需要添加)

1.1 绑定域名

先登录微信公众平台进入“设置与开发”“公众号设置”“功能设置”下设置“JS接口安全域名”

提示:添加的安全域名不需要协议部分,如:www.baidu.com备注:登录后可在“开发者中心”查看对应的接口权限。

1.2 获取access_token

通过公众号appidsecret来获取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_intoken的过期时间,单位是秒。

备注 建议通过expires_in设置缓存。

获取 Access token

Access token调试

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_intoken的过期时间,单位是秒。

备注 建议通过expires_in设置缓存。

获取ticket

1.4 添加ip白名单

获取access_token获取ticket两个接口都是有时效的,且调用资源有限。因此可以通过后端接口缓存一下值,后面可以使用更新缓存值,顺便可以将两个接口聚合成我们系统中的一个接口。 测试时可以手动调用前面两个接口,拿到ticket完成测试流程。

如果通过后端获取ticket,则需要添加服务器IP白名单。微信公众平台进入“设置与开发”``“基本配置”“公众号开发信息”中的“IP白名单”中添加访问微信相关接口的ip

2. 注入权限验证配置

完成公众号授权相关的内容后,即可开始在H5页面中通过config接口注入权限验证配置。以便后续使用weixin-js-sdk中微信提供的api

  1. 获取ticket
  2. 获取signature
  3. 注入权限

备注 不要忘了导入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}&timestamp=${timeStr}&url=${url}`).digest("hex");
  • ticket由上一步流程中获取。
  • nonceStr随意,建议userId之类的。
  • timeStr唯一,建议时间戳。
  • url必须是1.1 绑定域名中添加的地址。

注意 url为完整路径,包括参数等。#之后的不需要,因此可以使用location.href.split('#')[0]动态获取,避免错误。

signature校验

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注入权限验证配置时,可以通过readyerror监听状态。
  • 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("识别失败");
   },
  });
};

参考文档

JS-SDK说明文档

获取 Access token

获取ticket

Access token调试

signature校验