手机录入语音翻译为文字

也许偶尔就会有这样的需求,我是说如果,就是需要在手机端录入语音,然后发往后端,转为文字,再做对应的逻辑处理。是不是一听就很想有copy的想法呢,是的,就是有可以copy的东西。

首先整体思路是用最小的代价,实现我们的功能。那么手机端的语音录入,我们可以借助于微信小程序去实现,小程序内部有api可以调用语音输入。然后将得到的语音发往后端,后端呢,去调用百度的语音接口,就完成了语音翻译。

好了,接下来开启我们的代码之旅吧。

首先需要明确一个概念,在微信的体系内,如何去标识一个用户呢,那就是openId,单个用户的openId在某个微信小程序下是唯一的,我们就用它去标识。那些微信小程序的注册和申请、域名配置啥、小程序开发工具下载啥的咱们就跳过吧。还有一个,如果我们没有https的备案域名,开发的时候也不要紧,只要我们在开发者工具里面将域名校验给关闭掉就可以。

第一步,获取openId,这个任务自然是交给后端去做了。首先在微信小程序端,会获得一个code,这个code只有5分钟的有效期,可以根据code去兑换openId,小程序端的逻辑如下:

App({
  onLaunch() {
    // 登录
    wxUtil.login(code => {//code自动获取
      console.log(code)
      let paramJson = {code: code};
      wxUtil是一个工具类,包装了微信的http请求,不用关注
      wxUtil.post('wx/appletcode2openid', paramJson, wxUtil.audio, { isShowLoading: true }, (result) =>{
        console.log(result);
        wxUtil.setOpenIdByStorage(result.data.openID);
      });
     });
  },
  globalData: {
    userInfo: null
  }
})

对应的后端获取openId的逻辑:

/**
     * 微信小程序根据code获取openId等信息
     *
     * @return
     * @throws
     * @throws IOException
     */
public static WxAppletAuthResultVO getOpenIdByAuthCodeOnApplet(String appId, String appSecret, String code) {
    if(appId==null||appId.trim().isEmpty()){
        throw new RuntimeException("appId为空");
    }
    if(appSecret==null||appSecret.trim().isEmpty()){
        throw new RuntimeException("appSecret为空");
    }
    if(code==null||code.trim().isEmpty()){
        throw new RuntimeException("code为空");
    }
    try {
        String url = "https://api.weixin.qq.com/sns/jscode2session?appid=APPID&secret=SECRET&js_code=JSCODE&grant_type=authorization_code".replace("APPID", appId).replace("SECRET",appSecret).replace("JSCODE", code);
        String result = HttpUtil.doPost(url, null);
        if(result==null||result.isEmpty()){
            throw new RuntimeException("微信小程序根据code获取openId等信息返回为空");
        }
        
        return JSON.parseObject(result, WxAppletAuthResultVO.class);
    } catch (Exception e) {
        e.printStackTrace();
        throw e;
    }
    return null;
}

有了openId,下面我们就可以获取录入的语音了,然后将语音和openId一起发往后端。微信小程序端的js代码:

const wxUtil = require('../../utils/wxutil.js');
const recorderManager = wx.getRecorderManager();
const innerAudioContext = wx.createInnerAudioContext({"useWebAudioImplement": true});

recorderManager.onStop((res) => {//注意  给recorderManager注册了事件  后面会触发
  var tempFilePath = res.tempFilePath;//音频文件地址
  const fs = wx.getFileSystemManager();
  fs.readFile({//读取文件并转为ArrayBuffer
    filePath: tempFilePath,
    success(res) {
      wx.showLoading({
        title: '正在语音识别中...',
      });
      const base64Data = wx.arrayBufferToBase64(res.data);
      var fileSize = res.data.byteLength ;
      var paramJson = {
        format: 'pcm',
        sampleRate: 16000,
        encodeBitRate: 48000,
        data: base64Data
      };
      wxUtil.post('wx/audioupload', paramJson, wxUtil.audio, { isShowLoading: true }, (result) =>{
        console.log( result);
      });
    }
  })
});

Page({
  data: {},
  onLoad() {},
  //语音识别
  handleTouchStart: function(e){
    //录音参数
    const options = {
      sampleRate: 16000,
      numberOfChannels: 1,
      encodeBitRate: 48000,
      format: 'pcm'
    }
    //开启录音
    recorderManager.start(options);
    wx.showLoading({
      title: '正在录音中...',
    });
  },
  handleTouchEnd: function(e){
    recorderManager.stop();//stop之后就会触发onStop事件
  }
})

这样,我们是直接把语音文件转为base64的字符串,发往后端。后端就去调用百度的接口转为文字。百度的接口虽然付费,但是有免费调用量,需要先注册账号,申请应用,然后调用。

调用之前需要先获取百度语音的accessToken:

public static BaiduAudioAccessTokenVO getAccessToken(String apiKey,String secretKey){
    Map<String, String> parameters = new HashMap<>();
    parameters.put("grant_type","client_credentials");
    parameters.put("client_id",apiKey);
    parameters.put("client_secret",secretKey);
    String response = HttpUtil.sendPost("https://aip.baidubce.com/oauth/2.0/token",parameters);
    log.info("调用百度语音accessToken返回:" + response);
    BaiduAudioAccessTokenVO baiduAudioAccessTokenVO = JSON.parseObject(response, BaiduAudioAccessTokenVO.class);
    ParamCheckUtil.objectNull(baiduAudioAccessTokenVO,"调用接口未获取到accessToken");
    ParamCheckUtil.stringEmpty(baiduAudioAccessTokenVO.getAccess_token(),"调用接口未获取到accessToken");
    return baiduAudioAccessTokenVO;
}

接着调用百度语音接口:

public String transToText(String base64Audio,Integer len,String format,Integer rate) {
  //1参数校验
  ParamCheckUtil.stringEmpty(base64Audio,"语音文件为空");
  ParamCheckUtil.stringEmpty(format,"语音格式不能为空");
  ParamCheckUtil.notTrue(
          "pcm".equalsIgnoreCase(format)
                  || "wav".equalsIgnoreCase(format)
                  || "amr".equalsIgnoreCase(format),"语音文件格式不符合要求");

  //2 获取百度语音accessToken
  String accessToken = this.getAccessToken();
  //3 语音转为文字
  BaiduAudio2TextDTO audio2TextDTO = new BaiduAudio2TextDTO();
  audio2TextDTO.setFormat(format);
  audio2TextDTO.setRate(rate);
  audio2TextDTO.setCuid(baiduAudioProperties.getAppID());
  audio2TextDTO.setToken(accessToken);
  audio2TextDTO.setLen(len);
  audio2TextDTO.setBase64Audio(base64Audio);
  String text = BaiduAudioUtil.audio2Text(audio2TextDTO);
  log.info("翻译文字为:" + text);
  return text;
}

//工具类
public static String audio2Text(BaiduAudio2TextDTO baiduAudio2TextDTO){
    Map<String, Object> parameters = new HashMap<>();
    parameters.put("format",baiduAudio2TextDTO.getFormat());
    parameters.put("rate",baiduAudio2TextDTO.getRate());
    parameters.put("channel",1);
    parameters.put("cuid",baiduAudio2TextDTO.getCuid());
    parameters.put("token",baiduAudio2TextDTO.getToken());
    parameters.put("speech",baiduAudio2TextDTO.getBase64Audio());
    parameters.put("len",baiduAudio2TextDTO.getLen());
    String response = HttpUtil.sendPostJson("https://vop.baidu.com/server_api",JSON.toJSONString(parameters));
    log.info("语音转换接口返回:" + response);
    ParamCheckUtil.stringEmpty(response,"语音转换接口返回为空");
    BaiduAudio2TextVO textVO = JSON.parseObject(response, BaiduAudio2TextVO.class);
    return textVO.getResult().get(0);
}

就这样,就完成了。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 200,841评论 5 472
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,415评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 147,904评论 0 333
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,051评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,055评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,255评论 1 278
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,729评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,377评论 0 255
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,517评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,420评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,467评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,144评论 3 317
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,735评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,812评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,029评论 1 256
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,528评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,126评论 2 341

推荐阅读更多精彩内容