之前看过网上其他几位使用讯飞的接口来做微信小程序的。在自己实际跟着别人的博客做的时候,却又会遇到一些问题。所以在此对使用讯飞接口做一个总结。这里我是用WebAPI来做。
1. 申请科大讯飞的接口
进入官网之后,登陆账号(如果没有,可以注册使用)。
登陆之后,点击右上角的控制台。进入控制中心,创建新应用
填写好信息之后便可创建一个新的应用。之后进入这个应用,并且会在左上角看到三个信息:
- APPID
- APISecret
- APIKey
这三个信息是我们的程序调用讯飞的接口时用来验证身份的。这点通过它们的名称就可以猜出来。
2. 创建微信小程序
微信小程序的开发工具的安装和开发账号的申请我就不用多说了;对于微信小程序的一些文件的解释在官方文档中也有讲解。这里对于微信小程序开发的一些基础的内容不在多说。
(1)展示页面
新创建一个微信小程序后,先来写前端展示的页面:
app.wxss文件
page {
height: 100%;
background-color: #ffffff;
}
.container {
height: 100%;
display: flex;
flex-direction: column;
}
index.wxml文件
<view class="container">
<view class="showContent">
<view>{{searchKey}}</view>
</view>
<view class="content">
<button class="btn" bindtouchstart=‘start‘ bindtouchend="stop">点击按钮说话</button>
</view>
</view>
在这里的 bindtouchstart 是当按下这个按钮不松开会执行指定的方法,相同 bindtouchend 则是松开后执行指定的方法。
index.wxss文件
.showContent {
flex: 3 0 auto;
text-align: center;
padding: 100rpx;
font-size: 40rpx;
color: black;
}
.content {
flex: 1 1 auto;
display: flex;
align-items: flex-end;
justify-content: center;
margin-bottom: 60rpx;
width: 100%;
}
.content .btn {
border-radius: 40rpx;
width: 80%;
letter-spacing: 20rpx;
}
因为只是简单的模板,所以界面不是特别好看。
(2)处理鉴权字符串
WebAPI在官方文档中有很多的内容解释。这里也不会多的说明。
使用讯飞的API请求的话需要进行接口鉴权。因为个人对Java比较熟悉,所以使用Java来处理生成鉴权请求的字符串。
使用Spring Boot来做后端
创建一个Spring Boot的应用后,使用通常的MVC模式来处理。
Controller
import com.example.template.service.UrlService;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequiredArgsConstructor
@RequestMapping(path = "/url")
public class UrlController {
private final UrlService urlService;
@GetMapping
public String getUrl() {
return urlService.getUrl();
}
}
这里service的代码中需要添加okhttp的依赖
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.9.1</version>
</dependency>
Service
import okhttp3.HttpUrl;
import org.springframework.stereotype.Service;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.net.URL;
import java.nio.charset.Charset;
import java.text.SimpleDateFormat;
import java.util.Base64;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;
@Service
public class UrlService {
private static final String hostUrl = "https://iat-api.xfyun.cn/v2/iat";
private static final String apiSecret = ""; //在控制台-我的应用-语音听写(流式版)获取
private static final String apiKey = ""; //在控制台-我的应用-语音听写(流式版)获取
public String getUrl() {
try {
String authUrl = getAuthUrl(hostUrl, apiKey, apiSecret);
return authUrl.replace("http://", "ws://").replace("https://", "wss://");
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
// 这个 getAuthUrl() 方法是官网上给出来的,可以在官方文档中找到。
private String getAuthUrl(String hostUrl, String apiKey, String apiSecret) throws Exception {
URL url = new URL(hostUrl);
SimpleDateFormat format = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US);
format.setTimeZone(TimeZone.getTimeZone("GMT"));
String date = format.format(new Date());
StringBuilder builder = new StringBuilder("host: ").append(url.getHost()).append("\n").//
append("date: ").append(date).append("\n").//
append("GET ").append(url.getPath()).append(" HTTP/1.1");
Charset charset = Charset.forName("UTF-8");
Mac mac = Mac.getInstance("hmacsha256");
SecretKeySpec spec = new SecretKeySpec(apiSecret.getBytes(charset), "hmacsha256");
mac.init(spec);
byte[] hexDigits = mac.doFinal(builder.toString().getBytes(charset));
String sha = Base64.getEncoder().encodeToString(hexDigits);
String authorization = String.format("api_key=\"%s\", algorithm=\"%s\", headers=\"%s\", signature=\"%s\"", apiKey, "hmac-sha256", "host date request-line", sha);
HttpUrl httpUrl = HttpUrl.parse("https://" + url.getHost() + url.getPath()).newBuilder().//
addQueryParameter("authorization", Base64.getEncoder().encodeToString(authorization.getBytes(charset))).//
addQueryParameter("date", date).//
addQueryParameter("host", url.getHost()).//
build();
return httpUrl.toString();
}
}
在小程序的js文件中发送请求获得鉴权链接
首先在使用小程序向本地的服务器发送请求的时候要先对微信小程序开发工具进行配置的修改。
如果不进行该配置,则无法请求到本地的服务器进行字符串的处理。
在这里我写了一个单独的函数来进行请求并获取处理后的结果。
getUrl() {
wx.request({
url: ‘http://localhost:8080/url‘,
method: ‘GET‘,
header: {
‘content-type‘: ‘application/json‘ // 默认值
},
success(result) {
apiUrl = result.data;
console.log(apiUrl);
}
})
},
这里的apiUrl是定义的一个全局变量。微信的处理请求方法为wx.request。这个方法还有其他的一些参数可以设置。但现在用这做个请求获得返回的结果就够用了。
在js文件中获取录音
在进行录音前我们需要确定讯飞能够接收的语音的格式。经过和微信文档的对比,在这里可以使用pcm的格式。
这里现在js文件中定义录音文件的参数
const options = {
duration: 60000, // 指定录音的时常,单位ms
sampleRate: 8000, // 采样率
numberOfChannels: 1, // 录音通道数
encodeBitRate: 48000, // 编码码率
format: ‘PCM‘, // 音频格式
frameSize: 5, // 指定帧大小,单位KB
}
这里我们先写一个只是录音的功能。
在微信小程序的官方文档中,录音这个功能可以使用RecorderManager()来整体管理。所以我们首先在全局定义一个recorderManager。
const recorderManager = wx.getRecorderManager();
接着我们需要写两个方法,分别是开始录音和结束录音的方法。
/* 开始录音 */
start: function () {
recorderManager.start(options); // 开始录音
recorderManager.onStart(() => { // 开始录音的监听事件
console.log(‘开始录音‘);
});
},
/* 结束录音 */
stop: function() {
recorderManager.stop(); // 停止录音
recorderManager.onStop((result) => {
console.log(‘录音结束‘ + result.tempFilePath); // tempFilePath是录音的文件暂时的存放路径
});
},
这个时候就可以先简单的测试一下是否能够正常的录音。(如果是首次的话可能会需要开录音的权限,关于权限的问题之后再说明。现在主要是将讯飞的接口和小程序整合)
调用讯飞接口
讯飞的WebAPI接口是需要进行Websocket的链接的。所以小程序要创建Websocket链接。
当我们开始录音的时候就创建链接,所以我们将该功能写在 start 方法中。并且当链接建立成功之后就可以开始录音。
start: function () {
wxst = wx.connectSocket({ // 开启websocket连接
url: apiUrl,
method: ‘GET‘,
success: function (res) {
recorderManager.start(options);//开始录音
}
});
},
另外的一些Websocket监听就卸载onLoad中,一些录音的监听写在onShow中。这里是借鉴了网上的其他大佬。这里是他博客的链接。
微信小程序前台调用讯飞语音识别接口
这些处理完之后就已经是完成这个功能了。
但这个时候还有一个坑:在电脑虚拟机测试的时候,讯飞接口返回来的值一直为空。但是录音是有的。这个解决方法是使用真机调式。用真机调试才会有结果。当然这里的鉴权的url可以先通过后台获得到后直接放在socket请求的url上方便测试。