Commit 5466a93e authored by helinlin's avatar helinlin

添加阿里云音频识别demo

parent 380a87d9
package com.yeejoin.amos.speech.util;
import com.alibaba.nls.client.AccessToken;
import com.alibaba.nls.client.protocol.NlsClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import static com.yeejoin.amos.speech.util.SpeechConfig.AccessKeId;
import static com.yeejoin.amos.speech.util.SpeechConfig.AccessKeySecret;
/**
* 阿里云nlsClient语音识别客户端
* 应用全局创建一个NlsClient实例,默认服务地址为阿里云线上服务地址,默认值:wss://nls-gateway.cn-shanghai.aliyuncs.com/ws/v1
*/
public class AppNslClient {
private static final Logger logger = LoggerFactory.getLogger(AppNslClientToken.class);
private volatile static NlsClient nlsClient;
private AppNslClient() {
}
public static NlsClient instance() {
if (nlsClient == null) {
synchronized (NlsClient.class) {
if (nlsClient == null) {
logger.warn("AppNslClient语音识别客户端为空,开始创建...");
nlsClient = new NlsClient(AppNslClientToken.instance().getToken());
return nlsClient;
}
}
}
//设置访问token
nlsClient.setToken(AppNslClientToken.instance().getToken());
return nlsClient;
}
}
/**
* AppNslClientToken
*/
class AppNslClientToken {
private static final Logger logger = LoggerFactory.getLogger(AppNslClientToken.class);
private volatile static AccessToken accessToken;
private static long getTokenTime;
private AppNslClientToken() {
}
public static AccessToken instance() {
if (accessToken == null) {
synchronized (NlsClient.class) {
if (accessToken == null) {
logger.warn("token为空,开始获取token...");
accessToken = getAccessToken();
getTokenTime = System.currentTimeMillis();
}
}
}
//token过期自更新
if (getTokenTime + accessToken.getExpireTime() <= System.currentTimeMillis()) {
logger.warn("token已过期,开始重新获取...");
accessToken = getAccessToken();
getTokenTime = System.currentTimeMillis();
} else {
long time = getTokenTime + accessToken.getExpireTime() - System.currentTimeMillis();
logger.warn("token过期还剩:" + "(" + time / (1000 * 60 * 60 * 24) + "天)");
}
return accessToken;
}
/**
* 获取访问Token,包含token和过期时间(2021-11-30测试Token过期时间为18天)
* 集成项目中,token放到缓存中,避免多次获取可能导致已进行的任务token失效
*
* @return token 访问token
*/
private static AccessToken getAccessToken() {
AccessToken accessToken = new AccessToken(AccessKeId, AccessKeySecret);
try {
accessToken.apply();
logger.warn("获取到最新的token: " + accessToken.getToken() + ", 过期时间: " + accessToken.getExpireTime() + "(" + accessToken.getExpireTime() / (1000 * 60 * 60 * 24) + "天)");
return accessToken;
} catch (IOException e) {
logger.error("获取语音识别客户端token失败!原因:" + e.getMessage());
throw new RuntimeException("获取语音识别客户端token失败!原因:" + e.getMessage());
}
}
}
......@@ -22,13 +22,7 @@ public class HttpUtil {
.build();
public static String sendPostFile(String url, HashMap<String, String> headers, File speechFile) {
RequestBody body;
if (!speechFile.isFile()) {
System.err.println("The filePath is not a file: " + speechFile.getPath());
return null;
} else {
body = RequestBody.create(MediaType.parse("application/octet-stream"), speechFile);
}
RequestBody body = RequestBody.create(MediaType.parse("application/octet-stream"), speechFile);
Headers.Builder hb = new Headers.Builder();
if (headers != null && !headers.isEmpty()) {
for (Map.Entry<String, String> entry : headers.entrySet()) {
......
package com.yeejoin.amos.speech.util;
import com.alibaba.nls.client.AccessToken;
import java.io.IOException;
/**
* 阿里云语音识别
* <p>
......@@ -23,23 +19,12 @@ import java.io.IOException;
* 商用版按每自然日使用量计费,无免费额度,不使用则不产生费用。北京时间每日24时,系统将自动对当日用量进行全量计算并计费,账单生成将稍有延迟。
* 开通商用版后,不建议再次降配为试用版。商用版降配试用版后,可用并发数将置为0,服务将无法继续使用。
*/
public class SpeechUtil {
public class SpeechConfig {
/**
* 测试信息
* 测试信息,可在阿里云上配置
*/
public static final String AccessKeId = "LTAI5t7mGN6dYoCwMdKiLTgt";
public static final String AccessKeySecret = "0LYdEnvKzQxBg0lpIahDp5rzB2r4Dp";
public static final String AppKey = "EG5fJBBIqkNMj6bM";
/**
* 获取访问Token(测试Token过期时间为18天)
*
* @return token
*/
public static String getToken() throws IOException {
AccessToken accessToken = new AccessToken(AccessKeId, AccessKeySecret);
accessToken.apply();
System.out.println("get token: " + accessToken.getToken() + ", expire time: " + accessToken.getExpireTime());
return accessToken.getToken();
}
}
......@@ -29,11 +29,7 @@ public class SpeechFlashRecognizerDemo {
String format = "mp3";
int sampleRate = 16000;
SpeechFlashRecognizerDemo demo = new SpeechFlashRecognizerDemo(new File(fileName));
try {
demo.process(SpeechUtil.getToken(), format, sampleRate);
} catch (IOException e) {
e.printStackTrace();
}
demo.process(AppNslClientToken.instance().getToken(), format, sampleRate);
}
public SpeechFlashRecognizerDemo(File speechFile) {
......@@ -49,7 +45,7 @@ public class SpeechFlashRecognizerDemo {
*/
public void process(String token, String format, int sampleRate) {
String request = "https://nls-gateway.cn-shanghai.aliyuncs.com/stream/v1/FlashRecognizer";
request = request + "?appkey=" + SpeechUtil.AppKey;
request = request + "?appkey=" + SpeechConfig.AppKey;
request = request + "&token=" + token;
request = request + "&format=" + format;
request = request + "&sample_rate=" + sampleRate;
......
......@@ -88,7 +88,7 @@ public class SpeechRecognizerDemo {
e.printStackTrace();
}
// 创建DefaultAcsClient实例并初始化
DefaultProfile profile = DefaultProfile.getProfile(REGIONID, SpeechUtil.AccessKeId, SpeechUtil.AccessKeySecret);
DefaultProfile profile = DefaultProfile.getProfile(REGIONID, SpeechConfig.AccessKeId, SpeechConfig.AccessKeySecret);
this.client = new DefaultAcsClient(profile);
}
......@@ -113,7 +113,7 @@ public class SpeechRecognizerDemo {
*/
JSONObject taskObject = new JSONObject();
// 设置appkey
taskObject.put(KEY_APP_KEY, SpeechUtil.AppKey);
taskObject.put(KEY_APP_KEY, SpeechConfig.AppKey);
// 设置音频文件访问链接
taskObject.put(KEY_FILE_LINK, fileLink);
// 新接入请使用4.0版本,已接入(默认2.0)如需维持现状,请注释掉该参数设置。
......
package com.yeejoin.amos.speech.util;
import com.alibaba.nls.client.protocol.InputFormatEnum;
import com.alibaba.nls.client.protocol.NlsClient;
import com.alibaba.nls.client.protocol.SampleRateEnum;
import com.alibaba.nls.client.protocol.asr.SpeechTranscriber;
import com.alibaba.nls.client.protocol.asr.SpeechTranscriberListener;
......@@ -14,7 +13,7 @@ import java.io.FileInputStream;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import static com.yeejoin.amos.speech.util.SpeechUtil.AppKey;
import static com.yeejoin.amos.speech.util.SpeechConfig.AppKey;
/**
......@@ -24,50 +23,21 @@ import static com.yeejoin.amos.speech.util.SpeechUtil.AppKey;
* 支持的音频采样率:8000 Hz和16000 Hz。
*/
public class SpeechTranscriberDemo {
private final NlsClient client;
private final File speechFile;
private static final Logger logger = LoggerFactory.getLogger(SpeechTranscriberDemo.class);
private final File speechFile;
private final SpeechTranscriberListener listener;
/**
* 使用示例
*
*/
public static void main(String[] args) {
//本案例使用本地文件模拟发送实时流数据。您在实际使用时,可以实时采集或接收语音流并发送到ASR服务端。
String fileLink = "https://gw.alipayobjects.com/os/bmw-prod/0574ee2e-f494-45a5-820f-63aee583045a.wav";
//将上面fileLink文件下载到本地后,替换filepath为本地地址测试
String filepath = "D:\\ffmpeg-4.4-full_build-shared\\bin\\test1.wav";
SpeechTranscriberDemo transcriberDemo;
try {
transcriberDemo = new SpeechTranscriberDemo(new File(filepath));
transcriberDemo.process();
} catch (IOException e) {
e.printStackTrace();
}
}
public SpeechTranscriberDemo(File speechFile) throws IOException {
if (speechFile != null && speechFile.exists() && speechFile.isFile()) {
this.speechFile = speechFile;
// 默认值:wss://nls-gateway.cn-shanghai.aliyuncs.com/ws/v1。
//应用全局创建一个NlsClient实例,默认服务地址为阿里云线上服务地址。
client = new NlsClient(SpeechUtil.getToken());
} else {
throw new IllegalArgumentException("识别文件异常");
}
}
//根据二进制数据大小计算对应的同等语音长度。
//sampleRate:支持8000或16000。
public static int getSleepDelta(int dataSize, int sampleRate) {
// 仅支持16位采样。
int sampleBytes = 16;
// 仅支持单通道。
int soundChannel = 1;
return (dataSize * 10 * 8000) / (160 * sampleRate);
}
public void process() {
SpeechTranscriber transcriber = null;
try {
//创建实例、建立连接。
transcriber = new SpeechTranscriber(client, new SpeechTranscriberListener() {
SpeechTranscriberDemo transcriberDemo = new SpeechTranscriberDemo(new File(filepath), new SpeechTranscriberListener() {
/**
* 语音识别过程中返回的结果。仅当setEnableIntermediateResult为true时,才会返回该消息。
*/
......@@ -155,6 +125,27 @@ public class SpeechTranscriberDemo {
+ ", status_text: " + response.getStatusText());
}
});
transcriberDemo.process();
}
public SpeechTranscriberDemo(File speechFile, SpeechTranscriberListener listener) {
if (speechFile != null && speechFile.exists() && speechFile.isFile()) {
this.speechFile = speechFile;
this.listener = listener;
} else {
throw new IllegalArgumentException("待识别的文件存在异常");
}
}
/**
* 开始语音识别
*/
public void process() {
SpeechTranscriber transcriber = null;
try {
//创建实例、建立连接。
transcriber = new SpeechTranscriber(AppNslClient.instance(), listener);
transcriber.setAppKey(AppKey);
//输入音频编码方式。
transcriber.setFormat(InputFormatEnum.PCM);
......@@ -166,6 +157,7 @@ public class SpeechTranscriberDemo {
transcriber.setEnablePunctuation(true);
//是否将返回结果规整化,比如将一百返回为100。
transcriber.setEnableITN(false);
//设置vad断句参数。默认值:800ms,有效值:200ms~2000ms。
//transcriber.addCustomedParam("max_sentence_silence", 600);
//设置是否语义断句。
......@@ -195,10 +187,8 @@ public class SpeechTranscriberDemo {
while ((len = fis.read(b)) > 0) {
logger.info("send data pack length: " + len);
transcriber.send(b, len);
//本案例用读取本地文件的形式模拟实时获取语音流并发送的,因为读取速度较快,这里需要设置sleep。
//如果实时获取语音则无需设置sleep, 如果是8k采样率语音第二个参数设置为8000。
int deltaSleep = getSleepDelta(len, 16000);
TimeUnit.MILLISECONDS.sleep(deltaSleep);
//本案例用读取本地文件的形式模拟实时获取语音流并发送的,因为读取速度较快,这里需要设置sleep,如果实时获取语音则无需设置sleep
TimeUnit.MILLISECONDS.sleep(1000);
}
//通知服务端语音数据发送完毕,等待服务端处理完成。
long now = System.currentTimeMillis();
......@@ -211,9 +201,6 @@ public class SpeechTranscriberDemo {
if (null != transcriber) {
transcriber.close();
}
if (client != null) {
client.shutdown();
}
}
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment