前不久寫了個工具型微信小程式(Find周邊),裡面用到了語音識別技術。現將實現細節整理如下:
介面預覽
通過閱讀了解科大訊飛介面文件、小程式介面開發文件以及對後端ThinkPhp框架的學習,我整理了如下開發步驟:
- 註冊科大訊飛賬號(國人的驕傲,全球領先的語音識別技術)
- 進入AIUI開放平臺在應用管理建立應用並記錄APPID和ApiKey
- 進入應用配置,配置符合自己的情景模式、識別方式和技能
- 進行小程式開發錄製需要識別的音訊(下有詳述)
- 後端轉碼錄製的音訊(科大訊飛支援pcm、wav),提交給識別介面(下有詳述)
- 小程式接到識別結果進行接下來業務
音訊錄製介面
- wx.startRecord()和wx.stopRecord()
wx.startRecord()和wx.stopRecord()介面也可以滿足需求,但從1.6.0 版本開始不再被微信團隊維護。建議使用能力更強的 wx.getRecorderManager 介面。該介面獲取到的音訊格式為silk。
silk是webm格式通過base64編碼後的結果,我們解碼後需要將webm轉換成pcm、wav
- wx.getRecorderManager()
相對wx.startRecord()介面,該介面提供的能力更為強大(詳情),可以暫停錄音也可以繼續錄音,根據自己需求設定編碼位元速率,錄音通道數,取樣率。最讓人開心的是可以指定音訊格式,有效值 aac/mp3。不好的是wx.getRecorderManager()在1.6.0才開始被支援。當然如果你要相容低端微信使用者需要使用wx.startRecord()做相容處理。
- 事件監聽細節
// wxjs:
const recorderManager = wx.getRecorderManager()
recorderManager.onStart(() => {
//開始錄製的回撥方法
})
//錄音停止函式
recorderManager.onStop((res) => {
const { tempFilePath } = res;
//上傳錄製的音訊
wx.uploadFile({
url: app.d.hostUrl + '/Api/Index/wxupload', //僅為示例,非真實的介面地址
filePath: tempFilePath,
name: 'viceo',
success: function (res) {
console.log(res);
}
})
})
Page({
//按下按鈕--錄音
startHandel: function () {
console.log("開始")
recorderManager.start({
duration: 10000
})
},
//鬆開按鈕
endHandle: function () {
console.log("結束")
//觸發錄音停止
recorderManager.stop()
}
})
//wxml:
<view bindtouchstart='startHandel' bindtouchend='endHandle' class="tapview">
<text>{{text}}</text>
</view>
複製程式碼
音訊轉換
我這邊後端使用php的開源框架thinkphp,當然node、java、python等後端語言都可以,你根據自己的喜好和能力來。想做好音訊轉碼我們就要藉助音視訊轉碼工具ffmpeg、avconv,它們都依賴於gcc。安裝過程大家可以自行百度,或者關注我後面的文章。
<?php
namespace Api\Controller;
use Think\Controller;
class IndexController extends Controller {
//音訊上傳編解碼
public function wxupload(){
$upload_res=$_FILES['viceo'];
$tempfile = file_get_contents($upload_res['tmp_name']);
$wavname = substr($upload_res['name'],0,strripos($upload_res['name'],".")).".wav";
$arr = explode(",", $tempfile);
$path = 'Aduio/'.$upload_res['name'];
if ($arr && !empty(strstr($tempfile,'base64'))){
//微信模擬器錄製的音訊檔案可以直接儲存返回
file_put_contents($path, base64_decode($arr[1]));
$data['path'] = $path;
apiResponse("success","轉碼成功!",$data);
}else{
//手機錄音檔案
$path = 'Aduio/'.$upload_res['name'];
$newpath = 'Aduio/'.$wavname;
file_put_contents($path, $tempfile);
chmod($path, 0777);
$exec1 = "avconv -i /home/wwwroot/mapxcx.kanziqiang.top/$path -vn -f wav /home/wwwroot/mapxcx.kanziqiang.top/$newpath";
exec($exec1,$info,$status);
chmod($newpath, 0777);
if ( !empty($tempfile) && $status == 0 ) {
$data['path'] = $newpath;
apiResponse("success","轉碼成功!",$data);
}
}
apiResponse("error","發生未知錯誤!");
}
//json資料返回方法封裝
function apiResponse($flag = 'error', $message = '',$data = array()){
$result = array('flag'=>$flag,'message'=>$message,'data'=>$data);
print json_encode($result);exit;
}
}
複製程式碼
呼叫識別介面
當我們把檔案準備好之後,接下來我們就可以將base64編碼之後的音訊檔案通過api介面請求傳輸過去。期間我們要注意嚴格按照文件中所說的規範傳輸,否則將造成不可知的結果。
<?php
namespace Api\Controller;
use Think\Controller;
class IndexController extends Controller {
public function _initialize(){
}
//封裝資料請求方法
public function httpsRequest($url,$data = null,$xparam){
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);
curl_setopt($curl, CURLOPT_HEADER, 0);
$Appid = "";//開放平臺的appid
$Appkey = "";//開放平臺的Appkey
$curtime = time();
$CheckSum = md5($Appkey.$curtime.$xparam.$data);
$headers = array(
'X-Appid:'.$Appid,
'X-CurTime:'.$curtime,
'X-CheckSum:'.$CheckSum,
'X-Param:'.$xparam,
'Content-Type:'.'application/x-www-form-urlencoded; charset=utf-8'
);
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
if (!empty($data)){
curl_setopt($curl, CURLOPT_POST, 1);
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
}
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
$output = curl_exec($curl);
curl_close($curl);
return $output;
}
//請求介面資料處理
public function getVoice($path){
$d = base64_encode($path);
$url = "https://api.xfyun.cn/v1/aiui/v1/voice_semantic";
$xparam = base64_encode( json_encode(array('scene' => 'main','userid'=>'user_0001',"auf"=>"16k","aue"=>"raw","spx_fsize"=>"60" )));
$data = "data=".$d;
$res = $this->httpsRequest($url,$data,$xparam);
if(!empty($res) && $res['code'] == 00000){
apiResponse("success","識別成功!",$res);
}else{
apiResponse("error","識別失敗!");
}
}
//資料返回封裝
function apiResponse($flag = 'error', $message = '',$data = array()){
$result = array('flag'=>$flag,'message'=>$message,'data'=>$data);
print json_encode($result);exit;
}
}
複製程式碼
到這裡基本就完成了。以上程式碼是經過整理之後的,並不一定能夠滿足各位的實際開發需求。如果發現不當之處歡迎微信交流(xiaoqiang0672)。
想看實際案例的可以微信掃碼
關於gcc安裝
關於FFmpeg安裝
關於ffmpeg/avconv安裝