一、腾讯语音识别—一句话语音识别
1、账号申请
(1)搜索腾讯云官网
https://cloud.tencent.com/?fromSource=gwzcw.2212127.2212127.2212127&utm_medium=cpd&utm_id=gwzcw.2212127.2212127.2212127
(2)打开语音识别
腾讯云语音识别(Automatic Speech Recognition,ASR)为开发者提供语音转文字服务的最佳体验。经公司内部微信、QQ 、腾讯视频、王者荣耀等大体量业务落地验证,日服务亿级用户,性能稳定。腾讯语音识别技术开放实时语音识别、一句话识别和录音文件识别服务,满足不同类型开发者需求。除公有云接入外,腾讯语音识别技术也支持私有化部署。
小编:微信和王者荣耀的语音识别还是很强大的,其它的虽然并不清楚
(3)先来看下语音识别的接口文档
![1552371855329](C:\Users\lichuanran\AppData\Roaming\Typora\typora-user-images\15523718
1>通过post请求来发送语音数据,从而得到结果
2>请求大小不能超过600k
超过600k不会报错,但是识别时长会有点长
3>音频时长不可超过60s
4>支持音频格式 wav 、mp3
5>比特率128k或者256k
256k比128k保存的数据更具体,对应的文件大小也更大
6>音频流的采样率8000或者16000 (单位时间内有多少数据来描述采样点)
分别对应接口文档的EngSerViceType(引擎类型)的8K或者16k
16000的采样率识别准确率比8000采样率更高
7>请求频率25次/s
使用多线程进行死循环发现,达到25次/s会把请求延迟一点,并不会报错
8>单声道
注:下文小编会介绍怎么把 任意一个音频文件 转换为一个 符合腾讯云识别标准 的音频文件
2、java 实现语音识别
(1)下载SDK
https://cloud.tencent.com/document/product/441/19814
1>打开SDK会发现有两个类 SASRsdk 和 SASRtest 一个wav格式的语音文件
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.File;
import java.io.FileInputStream;
import java.io.UnsupportedEncodingException;
import java.util.Base64;
import java.util.Map;
import java.util.Random;
import java.util.TreeMap;
import java.net.URLEncoder;
import java.io.OutputStream;
import java.io.InputStream;
import java.io.BufferedReader;
import java.net.URL;
import java.net.HttpURLConnection;
import java.io.InputStreamReader;public class SASRsdk {private static String SecretId, SecretKey, EngSerViceType, SourceType, VoiceFormat, fileURI;
public static String formSignstr(String serverUrl, Map<String, String> mapReq) {StringBuilder strBuilder = new StringBuilder(serverUrl);// to make that all the parameters are sorted by ASC orderTreeMap<String, String> sortedMap = new TreeMap(mapReq);for (Map.Entry<String, String> entry : sortedMap.entrySet()) {strBuilder.append(entry.getKey());strBuilder.append('=');strBuilder.append(entry.getValue());strBuilder.append('&');}if (mapReq.size() > 0) {strBuilder.setLength(strBuilder.length() - 1);}//System.out.println("sign str: " + strBuilder);return strBuilder.toString();
}public static String formPostbody(Map<String, String> mapReq) {StringBuilder stringBuilder = new StringBuilder();// to make that all the parameters are sorted by ASC orderTreeMap<String, String> sortedMap = new TreeMap(mapReq);for (Map.Entry<String, String> entry : sortedMap.entrySet()) {try {stringBuilder.append(URLEncoder.encode(entry.getKey(), "UTF-8"));stringBuilder.append('=');stringBuilder.append(URLEncoder.encode(entry.getValue(), "UTF-8"));stringBuilder.append('&');} catch (UnsupportedEncodingException e) {e.printStackTrace();}}return stringBuilder.toString();
}public static String base64_hmac_sha1(String value, String keyStr) {String encoded = "";String type = "HmacSHA1";try {byte[] key = (keyStr).getBytes("UTF-8");byte[] Sequence = (value).getBytes("UTF-8");Mac HMAC = Mac.getInstance(type);SecretKeySpec secretKey = new SecretKeySpec(key, type);HMAC.init(secretKey);byte[] Hash = HMAC.doFinal(Sequence);encoded = Base64.getEncoder().encodeToString(Hash);} catch (Exception e) {e.printStackTrace();}return encoded;
}/*- 获得unix时间戳*/public static String toUNIXEpoch() {long unixTime = System.currentTimeMillis() / 1000L;return unixTime + "";}/*- 生成随机nonce*/public static String toUNIXNonce() {long unixTime = System.currentTimeMillis() / 1000L;String str = unixTime + "";String nonce = str.substring(0, 4);return nonce;}public static String createSign(String signStr, String secretKey) {return base64_hmac_sha1(signStr, secretKey);
}private static String getRandomString(int length) {//定义一个字符串(A-Z,a-z,0-9)即62位;String str = "zxcvbnmlkjhgfdsaqwertyuiopQWERTYUIOPASDFGHJKLZXCVBNM1234567890";//由Random生成随机数Random random = new Random();StringBuffer sb = new StringBuffer();//长度为几就循环几次for (int i = 0; i < length; ++i) {//产生0-61的数字int number = random.nextInt(62);//将产生的数字通过length次承载到sb中sb.append(str.charAt(number));}//将承载的字符转换成字符串return sb.toString();
}public static int setConfig(String SecretId,String SecretKey,String EngSerViceType,String SourceType,String VoiceFormat,String fileURI
) {if (SecretId.length() <= 0) {System.out.println("SecretId can not be empty!");return -1;}if (SecretKey.length() <= 0) {System.out.println("SecretKey can not be empty!");return -1;}if (EngSerViceType.length() <= 0 || (EngSerViceType.compareTo("8k") != 0 && EngSerViceType.compareTo("16k") != 0)) {System.out.println("EngSerViceTyp is not valied !");return -1;}if (SourceType.length() <= 0 || (SourceType.compareTo("0") != 0 && SourceType.compareTo("1") != 0)) {System.out.println("SourceType is not valied !");return -1;}if (VoiceFormat.length() <= 0 || (VoiceFormat.compareTo("mp3") != 0 && VoiceFormat.compareTo("wav") != 0)) {System.out.println("VoiceFormat is not valied !");return -1;}if (fileURI.length() <= 0) {System.out.println("fileURI can not be empty!");return -1;}SASRsdk.SecretId = SecretId;SASRsdk.SecretKey = SecretKey;SASRsdk.EngSerViceType = EngSerViceType;SASRsdk.SourceType = SourceType;SASRsdk.VoiceFormat = VoiceFormat;SASRsdk.fileURI = fileURI;return 0;
}public static int sendVoice() {Map<String, String> reqMap = new TreeMap();reqMap.put("Action", "SentenceRecognition");reqMap.put("SecretId", SecretId);reqMap.put("Timestamp", toUNIXEpoch());reqMap.put("Nonce", toUNIXNonce());reqMap.put("Version", "2018-05-22");reqMap.put("ProjectId", "0");reqMap.put("SubServiceType", "2");reqMap.put("EngSerViceType", EngSerViceType);reqMap.put("SourceType", SourceType);if (SourceType.compareTo("0") == 0) {try {String Url = URLEncoder.encode(fileURI, "UTF-8");reqMap.put("Url", Url);} catch (UnsupportedEncodingException e) {e.printStackTrace();}} else if (SourceType.compareTo("1") == 0) {FileInputStream fileInputStream = null;try {fileInputStream = new FileInputStream(new File(fileURI));int datalen = fileInputStream.available();byte[] dataPacket = new byte[datalen];int n = fileInputStream.read(dataPacket);//System.out.println("n :"+n);String Data = Base64.getEncoder().encodeToString(dataPacket);String DataLen = datalen + "";// System.out.println("data len: "+DataLen);reqMap.put("Data", Data);reqMap.put("DataLen", DataLen);
} catch (Exception e) {e.printStackTrace();}} else {return -3;}reqMap.put("VoiceFormat", VoiceFormat);String UsrAudioKey = getRandomString(16);reqMap.put("UsrAudioKey", UsrAudioKey);String _url = "POSTaai.tencentcloudapi.com/?";String signstr = formSignstr(_url, reqMap);// System.out.println("signstr: " + signstr);String signing = createSign(signstr, SecretKey);// System.out.println("签名: " + signing);String tmppostdata = formPostbody(reqMap);String sign = "";try {sign = URLEncoder.encode(signing, "UTF-8");} catch (UnsupportedEncodingException e) {e.printStackTrace();}StringBuilder postdata = new StringBuilder(tmppostdata);postdata.append("Signature=");postdata.append(sign);String post = postdata.toString();//System.out.println("post : "+post);String serverUrl = "https://aai.tencentcloudapi.com";HttpURLConnection con = null;StringBuilder sbResult = new StringBuilder();try {URL url = new URL(serverUrl);con = (HttpURLConnection) url.openConnection();con.setRequestMethod("POST");con.setDoOutput(true);con.setDoInput(true);con.setUseCaches(false);con.setRequestProperty("Host", "aai.tencentcloudapi.com");con.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");con.setRequestProperty("Charset", "utf-8");// 往服务器写入数据OutputStream out = con.getOutputStream();out.write(post.getBytes());out.flush();// 接收服务器返回的数据InputStream in = con.getInputStream();BufferedReader br = new BufferedReader(new InputStreamReader(in));String line;// 每一行的数据while ((line = br.readLine()) != null) {sbResult.append(line);}System.out.println(sbResult.toString());} catch (Exception e) {throw new RuntimeException(e);} finally {if (con != null) {con.disconnect();con = null;}}return 0;
}}
(2)进行初步测试 --wav 采样率16000 比特率256kbps 远程文件
public static void main(String[] args) {//用户需修改为自己的SecretId,SecretKeyString SecretId = "AKID31NbfXbpBLJ4kGJrytc9UfgVAlGltJJ8";String SecretKey = "kKm26uXCgLtGRWVJvKtGU0LYdWCgOvGP";// 识别引擎 8k or 16kString EngSerViceType = "16k";// 语音数据来源 0:语音url or 1:语音数据bodydata(data数据大小要小于800k)String SourceType = "0";//音频格式 wav,mp3String VoiceFormat = "wav";// 语音数据地址String fileURI="http://liqiansunvoice-1255628450.cosgz.myqcloud.com/30s.wav";//调用setConfig函数设置相关参数int res = SASRsdk.setConfig(SecretId, SecretKey, EngSerViceType, SourceType, VoiceFormat, fileURI);if (res < 0) {return;}//调用sendVoice函数获得音频识别结果SASRsdk.sendVoice();}
1>测试结果
{"Response":{"Result":"雨是最寻常的一下就是三两天。可别恼看像牛毛像花针像细丝密密地斜织着。人家屋顶上全笼着一层烟雾树叶却绿的发亮,小草也青得逼你的眼,傍晚的时候上灯了。一点点黄晕的光。烘托出一片安静而和平的夜在乡下在小路上石桥边默默撑着伞的人。","RequestId":"b08e7b64-3b0b-4658-a478-a4650f2a7c48"}}
2>根据语音数据地址,下载文件
文件的比特率为256kbps 因此 识别引擎(EngSerViceType)16k 、语音数据来源 (SourceType)0
3>SecretId和SecretKey 通过腾讯云可以新建
![1552377914206](C:\Users\li
(3)继续测试 --wav 采样率8000 比特率128kbps 本地文件
public static void main(String[] args) {//用户需修改为自己的SecretId,SecretKeyString SecretId = "AKID31NbfXbpBLJ4kGJrytc9UfgVAlGltJJ8";String SecretKey = "kKm26uXCgLtGRWVJvKtGU0LYdWCgOvGP";// 识别引擎 8k or 16kString EngSerViceType = "8k";// 语音数据来源 0:语音url or 1:语音数据bodydata(data数据大小要小于800k)String SourceType = "1";//音频格式 wav,mp3String VoiceFormat = "wav";// 语音数据地址String fileURI = "D:\\test.wav";//调用setConfig函数设置相关参数int res = SASRsdk.setConfig(SecretId, SecretKey, EngSerViceType, SourceType, VoiceFormat, fileURI);if (res < 0) {return;}//调用sendVoice函数获得音频识别结果SASRsdk.sendVoice();
}
1>测试结果
{"Response":{"Result":"张先生,您好。那个为了规范保险从业人员的销售行为。也为了更好的保护您的合法权益。根据保监会规定我们将。哎。您能不能说话客气点。你会不会好好说话,会不会会不会会不会好像说。","RequestId":"2b93994a-7c01-4237-9c3a-07dfa14eb34d"}}
2>使用的语音文件为SDK自带
文件比特率为128kbps、采样率为8000 即 识别引擎(EngSerViceType)8k 、本地文件 SourceType=1
3>如果不按上面所示进行测试,得到的结果会识别不准确哦
(4)使用自己的文件进行测试(MP3)
1>使用16k识别引擎
{"Response":{"Result":"�","RequestId":"6c18c00a-1a6e-4da4-b3a7-701088c864c8"}}
2>使用8k识别引擎
{"Response":{"Result":"嗯。嗯嗯。呃,嗯。呃。嗯嗯。嗯嗯,呃。呃。嗯。嗯嗯。嗯嗯,呃。呃。嗯。嗯。嗯。嗯。嗯。","RequestId":"7d03d1fc-a586-470a-bdfb-81b4ccbf8fc5"}}
3>我们发现,识别结果有严重的误差
原因:语音文件为320kbps,采样率远远大于41000。导致识别失败,或者结果全是语气词
4>将自己的语音文件转换成 比特率为128kbps,采样率为16000,单声道 (下面会介绍用java怎么转换)
使用16k识别引擎测试—>识别成功
5>将自己的语音文件转换成 比特率为128kbps,采样率为8000 ,单声道
使用8k识别引擎测试—>识别成功
缺点:较16k识别引擎。准确率更低,文件的大小却无差别
3、文件转换
(1)、把 任意格式的语音文件 转换为 符合腾讯接口的格式文件
1>导入jar包
<!-- https://mvnrepository.com/artifact/com.github.dadiyang/jave -->
<dependency><groupId>com.github.dadiyang</groupId><artifactId>jave</artifactId><version>1.0.2</version>
</dependency>
2> JAVE 简介 和 作用
J 即java ,A 即 audio , V 即 voice ,E 即 encoding。它一个工具,一个用纯java语言写的跨平台的,一通用的Ascii码图形化的文本编辑器。其功能和微软的记事本有些类似,主要是一个字处理工具,但提供图形化输入;操作像是微软的画图软件,因为该软件主要是通过鼠标进行文本的编辑。进一步看了一下该软件的功能,操作和功能并不复杂。该软件主要的卖点是授权开发源代码方式,其用百分之百java语言开发的跨平台特点。
可以用来给音频,视频 重新编码 , 视频剪辑 , 视频格式的转换等一系列强大的功能。
3>
try {//File source = new File("file path source");//File target = new File("file path target");// Audio Attributes/音频编码属性AudioAttributes audio = new AudioAttributes();/** 它设置将用于音频流转码的编解码器的名称。您必须从当前Encoder实例的getAudioEncoders()方法返回的列表中选择一个值。否则,* 您可以传递AudioAttributes.DIRECT_STREAM_COPY特殊值,该值需要源文件中原始音频流的副本。*/audio.setCodec("libmp3lame");/** 它设置新重新编码的音频流的比特率值。如果未设置比特率值,编码器将选择默认值。该值应以每秒位数表示。例如,如果你想要128 kb /* s比特率,你应该调用setBitRate(new Integer(128000))。*/audio.setBitRate(128000);/* 它设置将在重新编码的音频流中使用的音频通道的数量(1 =单声道,2 =立体声)。如果未设置通道值,编码器将选择默认值。 */audio.setChannels(1);/** 它设置新重新编码的音频流的采样率。如果未设置采样率值,编码器将选择默认值。该值应以赫兹表示。例如,如果您想要类似CD的44100* Hz采样率,则应调用setSamplingRate(new Integer(44100))。*///audio.setSamplingRate(44100);audio.setSamplingRate(16000);/* 可以调用此方法来改变音频流的音量。值256表示没有音量变化。因此,小于256的值是音量减小,而大于256的值将增加音频流的音量。 */audio.setVolume(new Integer(256));// Encoding attributes/编码属性EncodingAttributes attrs = new EncodingAttributes();/** 它设置将用于新编码文件的流容器的格式。给定参数表示格式名称。* 编码格式名称有效且仅在它出现在正在使用的Encoder实例的getSupportedEncodingFormats()方法返回的列表中时才受支持。*/attrs.setFormat("mp3");/* 它设置音频编码属性。如果从未调用过新的EncodingAttributes实例,或者给定参数为null,则编码文件中不会包含任何音频流 */attrs.setAudioAttributes(audio);/** 它为转码操作设置偏移量。源文件将从其开始的偏移秒开始重新编码。例如,如果您想剪切源文件的前五秒,* 则应在传递给编码器的EncodingAttributes对象上调用setOffset(5)。*/// attrs.setOffset(5F);/** 它设置转码操作的持续时间。只有源的持续时间秒才会在目标文件中重新编码。例如,如果您想从源中提取和转码30秒的一部分,* 则应在传递给编码器的EncodingAttributes对象上调用setDuration(30)*/// attrs.setDuration(30F);// Encode/编码Encoder encoder = new Encoder();encoder.encode(source, target, attrs);} catch (Exception ex) {ex.printStackTrace();}
二、百度语音识别
1、应用创建
(1)、搜索 百度AI开放平台
(2)、创建应用
(3)、查看技术文档
(4)、选择java SDK
(5)、SDK下载 选择java SDK进行下载
2、使用百度Api进行开发
(1)、创建maven工程
(2)、加入依赖
<dependency><groupId>com.baidu.aip</groupId><artifactId>java-sdk</artifactId><version>4.1.1</version>
</dependency>
(3)、创建wav语音格式的音频
目前格式仅仅支持pcm,wav或amr,填写mp3即会有此错误(mp3转pcm会出现音频质量过差的错误)
如何获取以上某种格式的音频,用来测试呢
手机下载录音专家,录音后会有形成wav格式的音频,在 手机文件存储 (一般是过1分钟左右,会出现在音频文件中) 中找到生成的wav格式文件,发送到电脑上
音频文件不能过大,小于4M,音频长度要小于60s
(4)、
**
public class Sample {//设置APPID/AK/SKpublic static final String APP_ID = "15598353";public static final String API_KEY = **"IwqPzfgVlGLKMbUIw3TVlF77";public static final String SECRET_KEY = "xxxxxxxxxxxxxxx";public static void main(String[] args) {// 初始化一个AipSpeech AipSpeech client = new AipSpeech(APP_ID, API_KEY, SECRET_KEY);// 可选:设置网络连接参数 client.setConnectionTimeoutInMillis(2000);client.setSocketTimeoutInMillis(60000);// 可选:设置代理服务器地址, http和socket二选一,或者均不设置 //client.setHttpProxy("proxy_host", proxy_port); // 设置http代理 //client.setSocketProxy("proxy_host", proxy_port); // 设置socket代理 // 可选:设置log4j日志输出格式,若不设置,则使用默认配置 //也可以直接通过jvm启动参数设置此环境变量 System.setProperty("aip.log4j.conf", "log4j.properties");new Sample().asr(client);// 调用接口 //JSONObject res = client.asr("test.pcm", "pcm", 16000, null); //System.out.println(res.toString(2));
}public void asr(AipSpeech client){// 对本地语音文件进行识别 String path = "D:\\测试文件\\970f1c080e0c78476d337a80ba5114f9.wav";JSONObject asrRes = client.asr(path, **"wav"**, 16000, **null**);System.out.println(asrRes);// 对语音二进制数据进行识别 byte[] data = new byte[0]; //readFileByBytes仅为获取二进制数据示例 try {data = Util.readFileByBytes(path);} catch (IOException e) {e.printStackTrace();}JSONObject asrRes2 = client.asr(data, "wav", 16000, null);System.out.println(asrRes.getInt("err_no")==0);System.out.println(asrRes2.get("result"));}
}
注:APP_ID API_KEY SECRET_KEY 在百度AI开放平台 注册服务后,会有这3个的值
(5)、测试结果:
三、讯飞语音识别
1、应用创建
(1)、
1>我们可以看到有语音听写、语音转写
语音听写:一分钟以内 人机对话、输入法、语音搜索
语音转写:五小时以内 日常对话、演讲
2>支持格式
语音听写:采样率为8kHz或16kHz,位长16bit,单声道的wav、pcm
语音转写:单声道、多声道的wav、flac、opus、m4a、mp3
3>语音听写创建
1、
2、
3、
4、
5、
4>语音转写创建
1、
2、
3、语音转写可以选择java哦,我这个是webapi的
总结:
本文介绍了腾讯、百度、讯飞的语音识别。百度和讯飞使用简单,腾讯相对使用就比较复杂点了。
腾讯一句话识别是最突出的功能,支持识别mp3格式的语音文件。腾讯的语音识别在王者荣耀、微信
都有大量的使用,并发还是可以的,虽然给客户1s 25次的请求比较少,但是出问题的可能性比较小。
并且腾讯语音识别时间是非常短的,本地测试2s多一点,真正使用也就是1s左右。讯飞的语音转写时
间就比较长了,在8s左右一个请求。讯飞的语音听写时间在3s左右,百度的语音听写类似。