微信小程序语音与讯飞语音识别接口(Java)

项目需求,需要使用讯飞的语音识别接口,将微信小程序上传的录音文件识别成文字返回

而微信小程序上传的文件格式是silk的,而讯飞接口能识别wav 格式的文件,所以需要将小程序上传的silk文件转成wav的格式

由于小程序上传的silk文件是变异的silk(小程序上传的silk文件中在编码头多添加了一个字节)文件,所以需要将他处理成正常的silk文件

由于项目是运行在Linux上,所以写了一个简单的shell脚本以供java程序调用处理

这个脚本的作用是删除输入文件中#!SILK_V3所在行的第一个字节

好了,文件处理完了,现在就是格式转换了

经调研,发现一般是先将silk文件转换成pcm,这里使用的是Kronopath/SILKCodec,下载到linux服务器上,然后在SILK_SDK_SRC_ARM里执行

make lib
make decoder

执行之后会生成命令行工具decoder

使用方法:

./decoder  要转换文件.silk   要生成文件.pcm

执行完上面代码就会生成.pcm文件,然后就是将pcm转成wav格式了,这里使用的是ffmpeg,没有安装的可以参考一下

ubuntu14.04安装ffmpeg:http://blog.csdn.net/leezha/article/details/77849286

阿里云linux安装ffmpeg:http://blog.csdn.net/baijinwen/article/details/77235725

安装ffmpeg可能出现的问题:http://blog.51cto.com/zlyang/1709508

为了保证语音识别的准确性,使用一下代码识别生成的wav文件,讯飞接口识别结果最好

ffmpeg -f s16le -ar 12k -ac 2 -i /path/to/pcm -f wav -ar 16k -ac 1 /path/to/wav

下面就是java的讯飞语音接口开发了,直接贴代码

package com.example.utils;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;

/**
 * Created by songzs on 2017/12/12.
* 封装的转码工具类 */ public class FFMPEGUtil { public static String silk2Pcm(String inputfile,String outputfile){ List<String> commend = new ArrayList<String>(); commend.add("/usr/local/silk2pcm_tool/SILKCodec/SILK_SDK_SRC_ARM/./decoder"); commend.add(inputfile); commend.add(outputfile); StringBuffer test=new StringBuffer(); for(int i=0;i<commend.size();i++) test.append(commend.get(i)+" "); System.out.println("decoder命令:"+test+""); exec(test); return outputfile; } public static String pcm2Wav(String inputfile,String outputfile){ //ffmpeg -f s16le -ar 12k -ac 2 -i /path/to/pcm -f wav -ar 16k -ac 1 /path/to/wav List<String> commend = new ArrayList<String>(); commend.add("ffmpeg"); commend.add("-f"); commend.add("s16le"); commend.add("-ar"); commend.add("12k"); commend.add("-ac"); commend.add("2"); commend.add("-i"); commend.add(inputfile); commend.add("-f"); commend.add("wav"); commend.add("-ar"); commend.add("16k"); commend.add("-ac"); commend.add("1"); commend.add(outputfile); StringBuffer test=new StringBuffer(); for(int i=0;i<commend.size();i++) test.append(commend.get(i)+" "); System.out.println("ffmpeg命令:"+test+""); exec(test); return outputfile; } public static String silk_remove_word(String filepath){ List<String> commend = new ArrayList<String>(); commend.add("/home/workspace/./test.sh"); commend.add(filepath); StringBuffer test=new StringBuffer(); for(int i=0;i<commend.size();i++) test.append(commend.get(i)+" "); System.out.println("test命令:"+test+""); exec(test); return filepath; } private static void exec(StringBuffer test){ try { Runtime rt = Runtime.getRuntime(); Process proc = rt.exec(test.toString()); InputStream stderr = proc.getErrorStream(); InputStreamReader isr = new InputStreamReader(stderr); BufferedReader br = new BufferedReader(isr); String line = null; while ( (line = br.readLine()) != null) ; } catch (Exception e) { e.printStackTrace(); } } }

 语音结果处理工具类(代码简陋,见谅)

package com.example.utils;

import com.alibaba.fastjson.JSON;

import java.util.List;
import java.util.Map;

/**
 * Created by songzs on 2017/12/15.
 */
public class SR2Words {

    public static String sr2words(String jsonString){
        StringBuffer sb = new StringBuffer();
        String[] split = jsonString.split("}]}]}");
        for (int i = 0; i < split.length; i++) {
            String s = split[i] + "}]}]}";
            System.out.println(s);
            Map parse = (Map) JSON.parse(s);
            List<Map> ws = (List<Map>) parse.get("ws");
            for (int i1 = 0; i1 < ws.size(); i1++) {
                List<Map> cw = (List<Map>)ws.get(i1).get("cw");
                String w = cw.get(0).get("w").toString();
                sb.append(w);
            }

        }
        return sb.toString();
    }
}

小程序录音文件上传与讯飞语音识别

package com.example.service.impl;

import com.example.service.XunFeiService;
import com.example.utils.FFMPEGUtil;
import com.example.utils.SR2Words;
import com.example.utils.SRTool;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

/**
 * Created by songzs on 2017/12/12.
 */
@Service
public class XunFeiServiceImpl implements XunFeiService {

    @Override
    public Map<String,String> speechRecognition(MultipartFile multi) {
        Map<String,String> map =new HashMap<>();
        UUID uuid = UUID.randomUUID();
        String path = "/home/workspace/audio";
        String fileName = uuid.toString()+".silk";
        //临时silk文件
        String tempFile = "/home/workspace/audio/"+uuid.toString()+".silk";
        //中间过渡pcm文件
        String pcmFile = "/home/workspace/audio/"+uuid.toString()+".pcm";
        //可识别的wav文件
        String wavFile = "/home/workspace/audio/"+uuid.toString()+".wav";
        File file = new File(path,fileName);
        try {
            multi.transferTo(file);
        } catch (IOException e) {
            e.printStackTrace();
        }
        /*移除临时silk文件首字节start*/
        //标准silk文件
        String silkFile = FFMPEGUtil.silk_remove_word(tempFile);
        /*移除临时silk文件首字节end*/
        //silk文件转换成pcm文件
        String silk2Pcm = FFMPEGUtil.silk2Pcm(silkFile, pcmFile);
        //pcm文件转换成wav文件
        String pcm2Wav = FFMPEGUtil.pcm2Wav(silk2Pcm, wavFile);
        //讯飞语音识别接口识别wav音频文件,转成文字返回
        SRTool sr = new SRTool();
        String words = null;
        try {
            words = sr.voice2words(pcm2Wav);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        System.out.println("讯飞识别的语音结果:"+words);
        if("".equals(words)){
            System.out.println("讯飞识别的语音结果:null");
            map.put("status","error");
            map.put("content","对不起,请您在描述一遍!");
            return map;
        }
        String result = SR2Words.sr2words(words);
        System.out.println("讯飞识别的语音结果:"+result);
        map.put("status","success");
        map.put("content",result);
        return map;
    }
}

*小程序上传接口必须是https请求,所以可能需要搭建https,相关内容可以参考我上一篇文章

posted on 2017-12-15 18:42 宋宋宋哥 阅读() 评论() 编辑 收藏

版权声明:本文为SongG-blogs原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:http://www.cnblogs.com/SongG-blogs/p/8044474.html