之前看過網上其他幾位使用訊飛的接口來做微信小程序的。在自己實際跟着別人的博客做的時候,卻又會遇到一些問題。所以在此對使用訊飛接口做一個總結。這里我是用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上方便測試。