一、腾讯语音识别—一句话语音识别
1、账号申请
(1)搜索腾讯云官网
(2)打开语音识别
腾讯云语音识别(Automatic Speech Recognition,ASR)为开发者提供语音转文字服务的最佳体验。经公司内部微信、QQ 、腾讯视频、王者荣耀等大体量业务落地验证,日服务亿级用户,性能稳定。腾讯语音识别技术开放实时语音识别、一句话识别和录音文件识别服务,满足不同类型开发者需求。除公有云接入外,腾讯语音识别技术也支持私有化部署。
小编:微信和王者荣耀的语音识别还是很强大的,其它的虽然并不清楚
(3)先来看下语音识别的接口文档

分别对应接口文档的EngSerViceType(引擎类型)的8K或者16k
16000的采样率识别准确率比8000采样率更高
7>请求频率25次/s
使用多线程进行死循环发现,达到25次/s会把请求延迟一点,并不会报错
8>单声道
注:下文小编会介绍怎么把 任意一个音频文件 转换为一个 符合腾讯云识别标准 的音频文件
2、java 实现语音识别
(1)下载SDK
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 order
TreeMap<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 order
TreeMap<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,SecretKey
String SecretId = "AKID31NbfXbpBLJ4kGJrytc9UfgVAlGltJJ8";
String SecretKey = "kKm26uXCgLtGRWVJvKtGU0LYdWCgOvGP";
// 识别引擎 8k or 16k
String EngSerViceType = "16k";
// 语音数据来源 0:语音url or 1:语音数据bodydata(data数据大小要小于800k)
String SourceType = "0";
//音频格式 wav,mp3
String 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 通过腾讯云可以新建
继续测试 --wav 采样率8000 比特率128kbps 本地文件
public static void main(String[] args) {
//用户需修改为自己的SecretId,SecretKey
String SecretId = "AKID31NbfXbpBLJ4kGJrytc9UfgVAlGltJJ8";
String SecretKey = "kKm26uXCgLtGRWVJvKtGU0LYdWCgOvGP";
// 识别引擎 8k or 16k
String EngSerViceType = "8k";
// 语音数据来源 0:语音url or 1:语音数据bodydata(data数据大小要小于800k)
String SourceType = "1";
//音频格式 wav,mp3
String 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/SK
public 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左右,百度的语音听写类似。