微信小程式:nodejs+百度語音識別開發實踐

CopperDong發表於2018-02-25

今天,終於成功使用nodejs研究出百度語音識別了。目前使用小程式最新錄音管理api測試,小程式錄音只支援aac,mp3格式,並且保持的是臨時地址。而百度語音識別目前只支援pcm,wav,amr格式。因此服務端需要先儲存好錄音檔案並經過一次音訊轉換。具體步驟如下:

1、安裝ffmpeg外掛。我使用的windows系統,具體安裝方法看這裡,該博主文章講的非常詳細,按照步驟走即可。這個外掛是使用fluent-ffmpeg依賴的前提條件

2、使用express生成器生成專案開發介面。需要提前安裝好幾個個依賴: 
npm install fluent-ffmpeg –save-dev//mp3轉wav依賴 
npm install multiparty –save-dev//獲取multipart/form-data上傳檔案依賴 
npm install baidu-aip-sdk –save-dev//百度AI依賴

上文提及的申請應用生成的appid和appkey和secretkey仍然需要,具體程式碼如下:

routes資料夾下建立AiSpeechRecognition.js::

var express=require('express');
var router=express.Router();
var fs=require('fs');
var Multiparty =require('multiparty');
var ffmpeg=require('fluent-ffmpeg');//建立一個ffmpeg命令
var AipSpeechServer=require('baidu-aip-sdk').speech;

//設定appid/appkey/appsecret
var APP_ID = "申請的應用appid";
var API_KEY = "申請的應用appkey";
var SECRET_KEY = "申請的應用secretkey";

// 新建一個物件,建議只儲存一個物件呼叫服務介面
var client =new AipSpeechServer(APP_ID, API_KEY, SECRET_KEY);
router.post('/recognition', function(req, res, next){
  //生成multiparty物件,並配置上傳目標路徑
  var form =new Multiparty.Form({ uploadDir: './public/audio'});
  //上傳完成後處理
  form.parse(req, function(err, fields, files){
    var filesTemp=JSON.stringify(files, null, 2);
    if(err){
      //console.log('parse error: '+err);
      res.json({
        ret: -1,
        data:{},
        msg: '未知錯誤'
      });
    }else{
      //console.log('parse files: '+filesTemp);
      var inputFile=files.file[0];
      var uploadedPath=inputFile.path;
      var command=ffmpeg();
      command.addInput(uploadedPath)
      //.saveToFile('./public/audio/222.wav')//儲存編碼檔案到資料夾 --儲存成wav是可以的,但是pcm報錯
      .saveToFile('./public/audio/16k.wav')
      .on('error', function(err){
        console.log(err)
      })
      .on('end', function(){
        //呼叫百度語音合成介面
        var voice = fs.readFileSync('./public/audio/16k.wav');
        var voiceBuffer=new Buffer(voice);
        client.recognize(voiceBuffer, 'wav', 16000).then(function(result){
          //console.log(result);
          var data=[];
          if(result.err_no===0){
            data=result.result;
          }
          res.json({
            ret: result.err_no,
            data: {
              data: data
            },
            msg: result.err_msg
          });
        }, function(err){
          console.log(err);
        });
        //語音識別 end

        //刪除上傳的臨時音訊檔案
        fs.unlink(uploadedPath, function(err){
          if(err){
            console.log(uploadedPath+'檔案刪除失敗');
            console.log(err);
          }else{
            console.log(uploadedPath+'檔案刪除成功');
          }
        });
        //刪除mp3轉成wav格式的音訊
        fs.unlink('./public/audio/16k.wav', function(err){
          if(err){
            console.log('16k.wav檔案刪除失敗');
            console.log(err);
          }else{
            console.log('16k.wav檔案刪除成功');
          }
        });
      });
    }
  });
});

module.exports=router;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84

專案根目錄app.js配置好訪問介面:

var recognition=require('./routes/AiSpeechRecognition.js');
app.use('/baiduAI2', recognition);
  • 1
  • 2

目前做的測試介面用,很多邏輯沒有程式碼片都沒有整合,直接寫在一個介面上,如果是要拿到實際生產線,請自行封裝下。然後執行npm start執行後端專案。

前端程式碼: 
BDSpeechRecognition.js::

const recorderManager = wx.getRecorderManager();
Page({
  data: {
    result: '',//語音識別結果
    recording: false//是否正在錄音
  },
  //開始錄製語音
  startRecord(e){
    this.setData({recording: true});
    recorderManager.start({
      duration: 60000,//百度最多支援60s語音
      sampleRate: 16000,
      //encodeBitRate: 48000,
      numberOfChannels: 1,//必須指定錄音通道數
      format: 'mp3'
    });
    recorderManager.onStart(() => {
      //console.log('recorder start')
    });
  },
  //停止錄音
  stopRecord(e) {
    let that=this;
    this.setData({ recording: false });
    recorderManager.stop();//停止錄音
    recorderManager.onStop((res)=>{
      const { tempFilePath } = res;
      //uploadfile start
      wx.uploadFile({
        url: 'http://你的ip:3000/baiduAI2/recognition',
        filePath: tempFilePath,
        name: 'file',
        success(res){
          //console.log(res);
          let data=typeof res.data==='string'? JSON.parse(res.data) : res.data;
          if(data.ret==0){
            //console.log(data.data.data[0])
            that.setData({
              result: data.data.data[0]
            });
          }else{
            that.setData({
              result: '我不知道你在說什麼'
            });
          }
        },
        fail(err){
          console.log(err);
        }
      });
    })
  }
})
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53

BDSpeechRecognition.wxml::

<view class="title">語音識別</view>
<view class="test" bindtap="startRecord" wx:if="{{!recording}}">開始錄音</view>
<view class="test" bindtap="stopRecord" wx:if="{{recording}}">停止錄音</view>

<view class="result" wx:if="{{result}}">
<view class="title">語音識別結果:</view>
{{result}}
</view>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

BDSpeechRecognition.wxss::

page{
  background-color: #eee;
}
.title{
  width: 100%;
  height: 120rpx;
  line-height: 120rpx;
  font-size: 48rpx;
  color: #333;
  text-indent:  20rpx;
}
.test{
  width: 100%;
  height: 90rpx;
  line-height: 90rpx;
  font-size: 32rpx;
  color: #00f;
  border: solid 1px #999;
  border-left: 0;
  border-right: 0;
  background-color: #fff;
  text-indent:  20rpx;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

最後執行除錯測試,演示結果如下: 
演示效果

最後,我把後端測試程式碼整合到了碼雲上了。

目前發現使用ffmpeg命令將mp3音訊轉換為pcm檔案是成功的,但是我用fflunt-ffmpeg轉換失敗,所以只能採用轉為wav音訊由百度內部自行在轉換一次。會比較耗時,還沒有解決方案。

相關文章