Commit e2f66c93 authored by 赵啸非's avatar 赵啸非

修改音频识别结果

parent 9f18dc7a
......@@ -11,6 +11,7 @@ import com.mortals.xhx.base.system.upload.service.UploadService;
import com.mortals.xhx.common.utils.IatATWSUtil;
import com.mortals.xhx.common.utils.IatModelMulMain;
import com.mortals.xhx.common.utils.IatModelMulUtil;
import com.mortals.xhx.common.utils.WebIATWS;
import lombok.extern.slf4j.Slf4j;
import okhttp3.OkHttpClient;
import okhttp3.Request;
......@@ -99,31 +100,35 @@ public class ApiSendMsgController {
String jsonStr = "";
try {
if (file == null || file.getSize() == 0L) throw new AppException("文件为空!");
// if (!"pcm".equalsIgnoreCase(FileUtil.getSuffix(file.getOriginalFilename())))
// throw new AppException("只支持pcm!");
// //if (file.getOriginalFilename())
// String filePath = uploadService.saveFileUpload(file, prePath, null);
// filePath = uploadService.getFilePath(filePath);
//
// log.info("filePath==>" + filePath);
if (!"pcm".equalsIgnoreCase(FileUtil.getSuffix(file.getOriginalFilename())))
throw new AppException("只支持pcm!");
//if (file.getOriginalFilename())
String filePath = uploadService.saveFileUpload(file, prePath, null);
filePath = uploadService.getFilePath(filePath);
byte[] bytes = file.getBytes();
log.info("filePath==>" + filePath);
WebIATWS webIATWS = new WebIATWS(filePath);
String authUrl = WebIATWS.getAuthUrl(hostUrl, apiKey, apiSecret);
// byte[] bytes = file.getBytes();
// IatModelMulUtil iatModelMulUtil = new IatModelMulUtil(filePath, appid);
// IatModelMulUtil iatModelMulUtil = new IatModelMulUtil(bytes, appid);
IatATWSUtil iatModelMulUtil = new IatATWSUtil(bytes, appid);
// IatATWSUtil iatModelMulUtil = new IatATWSUtil(bytes, appid);
String authUrl = IatATWSUtil.getAuthUrl(hostUrl, apiKey, apiSecret);
//String authUrl = IatATWSUtil.getAuthUrl(hostUrl, apiKey, apiSecret);
//log.info("authUrl==>" + authUrl);
OkHttpClient client = new OkHttpClient.Builder().build();
String url = authUrl.toString().replace("http://", "ws://").replace("https://", "wss://");
Request request = new Request.Builder().url(url).build();
WebSocket webSocket = client.newWebSocket(request, iatModelMulUtil);
WebSocket webSocket = client.newWebSocket(request, webIATWS);
// 等待返回结果(阻塞直到收到完整数据或超时)
String result = iatModelMulUtil.getResultFuture().get(60, TimeUnit.SECONDS);
String result = webIATWS.getResultFuture().get(60, TimeUnit.SECONDS);
log.info("识别结果:" + result);
model.put("result", result);
// model.put("url", filePath);
......
......@@ -156,7 +156,7 @@ public class IatATWSUtil extends WebSocketListener {
@Override
public void onMessage(WebSocket webSocket, String text) {
super.onMessage(webSocket, text);
log.info("onMessage==>" + text);
// log.info("onMessage==>" + text);
ResponseData resp = gson.fromJson(text, ResponseData.class);
if (resp != null) {
if (resp.getCode() != 0) {
......@@ -167,7 +167,7 @@ public class IatATWSUtil extends WebSocketListener {
if (resp.getData() != null) {
if (resp.getData().getResult() != null) {
Text te = resp.getData().getResult().getText();
//System.out.println(te.toString());
System.out.println(te.toString());
try {
decoder.decode(te);
// System.out.println("中间识别结果 ==》" + decoder.toString());
......
package com.mortals.xhx.common.utils;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import okhttp3.*;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URL;
import java.nio.charset.Charset;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.CompletableFuture;
/**
* 语音听写流式 WebAPI 接口调用示例 接口文档(必看):https://doc.xfyun.cn/rest_api/语音听写(流式版).html
* webapi 听写服务参考帖子(必看):http://bbs.xfyun.cn/forum.php?mod=viewthread&tid=38947&extra=
* 语音听写流式WebAPI 服务,热词使用方式:登陆开放平台https://www.xfyun.cn/后,找到控制台--我的应用---语音听写---个性化热词,上传热词
* 注意:热词只能在识别的时候会增加热词的识别权重,需要注意的是增加相应词条的识别率,但并不是绝对的,具体效果以您测试为准。
* 错误码链接:https://www.xfyun.cn/document/error-code (code返回错误码时必看)
* 语音听写流式WebAPI 服务,方言或小语种试用方法:登陆开放平台https://www.xfyun.cn/后,在控制台--语音听写(流式)--方言/语种处添加
* 添加后会显示该方言/语种的参数值
* @author iflytek
*/
public class WebIATWS extends WebSocketListener {
private final CompletableFuture<String> future = new CompletableFuture<>();
private static final String hostUrl = "https://iat-api.xfyun.cn/v2/iat"; //中英文,http url 不支持解析 ws/wss schema
// private static final String hostUrl = "https://iat-niche-api.xfyun.cn/v2/iat";//小语种
private static final String appid = "3cc52607"; //在控制台-我的应用获取
private static final String apiSecret = "ZTdmMjFjMGYxYmJhN2VmYjFlMTg3N2Rk"; //在控制台-我的应用-语音听写(流式版)获取
private static final String apiKey = "d0f73d44e996c2da9924c4476c578a30"; //在控制台-我的应用-语音听写(流式版)获取
private String file = ""; // 中文
public static final int StatusFirstFrame = 0;
public static final int StatusContinueFrame = 1;
public static final int StatusLastFrame = 2;
public static final Gson json = new Gson();
Decoder decoder = new Decoder();
// 开始时间
private static Date dateBegin = new Date();
// 结束时间
private static Date dateEnd = new Date();
private static final SimpleDateFormat sdf = new SimpleDateFormat("yyy-MM-dd HH:mm:ss.SSS");
public WebIATWS(String file) {
this.file = file;
}
@Override
public void onOpen(WebSocket webSocket, Response response) {
super.onOpen(webSocket, response);
new Thread(()->{
//连接成功,开始发送数据
int frameSize = 8192; //每一帧音频的大小,建议每 40ms 发送 122B
int intervel = 40;
int status = 0; // 音频的状态
try (FileInputStream fs = new FileInputStream(file)) {
byte[] buffer = new byte[frameSize];
// 发送音频
end:
while (true) {
int len = fs.read(buffer);
if (len == -1) {
status = StatusLastFrame; //文件读完,改变status 为 2
}
switch (status) {
case StatusFirstFrame: // 第一帧音频status = 0
JsonObject frame = new JsonObject();
JsonObject business = new JsonObject(); //第一帧必须发送
JsonObject common = new JsonObject(); //第一帧必须发送
JsonObject data = new JsonObject(); //每一帧都要发送
// 填充common
common.addProperty("app_id", appid);
//填充business
business.addProperty("language", "zh_cn");
//business.addProperty("language", "en_us");//英文
//business.addProperty("language", "ja_jp");//日语,在控制台可添加试用或购买
//business.addProperty("language", "ko_kr");//韩语,在控制台可添加试用或购买
//business.addProperty("language", "ru-ru");//俄语,在控制台可添加试用或购买
business.addProperty("domain", "iat");
business.addProperty("accent", "cn_lmz");//中文方言请在控制台添加试用,添加后即展示相应参数值
//business.addProperty("nunum", 0);
//business.addProperty("ptt", 0);//标点符号
//business.addProperty("rlang", "zh-hk"); // zh-cn :简体中文(默认值)zh-hk :繁体香港(若未授权不生效,在控制台可免费开通)
//business.addProperty("vinfo", 1);
business.addProperty("dwa", "wpgs");//动态修正(若未授权不生效,在控制台可免费开通)
//business.addProperty("nbest", 5);// 句子多候选(若未授权不生效,在控制台可免费开通)
//business.addProperty("wbest", 3);// 词级多候选(若未授权不生效,在控制台可免费开通)
//填充data
data.addProperty("status", StatusFirstFrame);
data.addProperty("format", "audio/L16;rate=16000");
data.addProperty("encoding", "raw");
data.addProperty("audio", Base64.getEncoder().encodeToString(Arrays.copyOf(buffer, len)));
//填充frame
frame.add("common", common);
frame.add("business", business);
frame.add("data", data);
System.out.println("send first:"+frame.toString());
webSocket.send(frame.toString());
status = StatusContinueFrame; // 发送完第一帧改变status 为 1
break;
case StatusContinueFrame: //中间帧status = 1
JsonObject frame1 = new JsonObject();
JsonObject data1 = new JsonObject();
data1.addProperty("status", StatusContinueFrame);
data1.addProperty("format", "audio/L16;rate=16000");
data1.addProperty("encoding", "raw");
data1.addProperty("audio", Base64.getEncoder().encodeToString(Arrays.copyOf(buffer, len)));
frame1.add("data", data1);
webSocket.send(frame1.toString());
// System.out.println("send continue:"+frame1.toString());
break;
case StatusLastFrame: // 最后一帧音频status = 2 ,标志音频发送结束
JsonObject frame2 = new JsonObject();
JsonObject data2 = new JsonObject();
data2.addProperty("status", StatusLastFrame);
data2.addProperty("audio", "");
data2.addProperty("format", "audio/L16;rate=16000");
data2.addProperty("encoding", "raw");
frame2.add("data", data2);
webSocket.send(frame2.toString());
System.out.println("sendlast");
break end;
}
Thread.sleep(intervel); //模拟音频采样延时
}
System.out.println("all data is send");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
}
@Override
public void onMessage(WebSocket webSocket, String text) {
super.onMessage(webSocket, text);
//System.out.println(text);
ResponseData resp = json.fromJson(text, ResponseData.class);
if (resp != null) {
if (resp.getCode() != 0) {
System.out.println( "code=>" + resp.getCode() + " error=>" + resp.getMessage() + " sid=" + resp.getSid());
System.out.println( "错误码查询链接:https://www.xfyun.cn/document/error-code");
return;
}
if (resp.getData() != null) {
if (resp.getData().getResult() != null) {
Text te = resp.getData().getResult().getText();
//System.out.println(te.toString());
try {
decoder.decode(te);
// System.out.println("中间识别结果 ==》" + decoder.toString());
} catch (Exception e) {
e.printStackTrace();
}
}
if (resp.getData().getStatus() == 2) {
// todo resp.data.status ==2 说明数据全部返回完毕,可以关闭连接,释放资源
System.out.println("session end ");
dateEnd = new Date();
System.out.println(sdf.format(dateBegin) + "开始");
System.out.println(sdf.format(dateEnd) + "结束");
System.out.println("耗时:" + (dateEnd.getTime() - dateBegin.getTime()) + "ms");
System.out.println("最终识别结果 ==》" + decoder.toString());
System.out.println("本次识别sid ==》" + resp.getSid());
future.complete(decoder.toString());
decoder.discard();
webSocket.close(1000, "");
} else {
// todo 根据返回的数据处理
}
}
}
}
@Override
public void onFailure(WebSocket webSocket, Throwable t, Response response) {
super.onFailure(webSocket, t, response);
try {
if (null != response) {
int code = response.code();
System.out.println("onFailure code:" + code);
System.out.println("onFailure body:" + response.body().string());
if (101 != code) {
System.out.println("connection failed");
System.exit(0);
}
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
future.completeExceptionally(t);
}
public static void main(String[] args) throws Exception {
// 构建鉴权url
String authUrl = getAuthUrl(hostUrl, apiKey, apiSecret);
OkHttpClient client = new OkHttpClient.Builder().build();
//将url中的 schema http://和https://分别替换为ws:// 和 wss://
String url = authUrl.toString().replace("http://", "ws://").replace("https://", "wss://");
//System.out.println(url);
Request request = new Request.Builder().url(url).build();
// System.out.println(client.newCall(request).execute());
//System.out.println("url===>" + url);
// WebSocket webSocket = client.newWebSocket(request, new WebIATWS());
}
public static String getAuthUrl(String hostUrl, String apiKey, String apiSecret) throws Exception {
URL url = new URL(hostUrl);
SimpleDateFormat format = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US);
format.setTimeZone(TimeZone.getTimeZone("GMT"));
String date = format.format(new Date());
StringBuilder builder = new StringBuilder("host: ").append(url.getHost()).append("\n").//
append("date: ").append(date).append("\n").//
append("GET ").append(url.getPath()).append(" HTTP/1.1");
//System.out.println(builder);
Charset charset = Charset.forName("UTF-8");
Mac mac = Mac.getInstance("hmacsha256");
SecretKeySpec spec = new SecretKeySpec(apiSecret.getBytes(charset), "hmacsha256");
mac.init(spec);
byte[] hexDigits = mac.doFinal(builder.toString().getBytes(charset));
String sha = Base64.getEncoder().encodeToString(hexDigits);
//System.out.println(sha);
String authorization = String.format("api_key=\"%s\", algorithm=\"%s\", headers=\"%s\", signature=\"%s\"", apiKey, "hmac-sha256", "host date request-line", sha);
//System.out.println(authorization);
HttpUrl httpUrl = HttpUrl.parse("https://" + url.getHost() + url.getPath()).newBuilder().//
addQueryParameter("authorization", Base64.getEncoder().encodeToString(authorization.getBytes(charset))).//
addQueryParameter("date", date).//
addQueryParameter("host", url.getHost()).//
build();
return httpUrl.toString();
}
public CompletableFuture<String> getResultFuture() {
return future;
}
public static class ResponseData {
private int code;
private String message;
private String sid;
private Data data;
public int getCode() {
return code;
}
public String getMessage() {
return this.message;
}
public String getSid() {
return sid;
}
public Data getData() {
return data;
}
}
public static class Data {
private int status;
private Result result;
public int getStatus() {
return status;
}
public Result getResult() {
return result;
}
}
public static class Result {
int bg;
int ed;
String pgs;
int[] rg;
int sn;
Ws[] ws;
boolean ls;
JsonObject vad;
public Text getText() {
Text text = new Text();
StringBuilder sb = new StringBuilder();
for (Ws ws : this.ws) {
sb.append(ws.cw[0].w);
}
text.sn = this.sn;
text.text = sb.toString();
text.sn = this.sn;
text.rg = this.rg;
text.pgs = this.pgs;
text.bg = this.bg;
text.ed = this.ed;
text.ls = this.ls;
text.vad = this.vad==null ? null : this.vad;
return text;
}
}
public static class Ws {
Cw[] cw;
int bg;
int ed;
}
public static class Cw {
int sc;
String w;
}
public static class Text {
int sn;
int bg;
int ed;
String text;
String pgs;
int[] rg;
boolean deleted;
boolean ls;
JsonObject vad;
@Override
public String toString() {
return "Text{" +
"bg=" + bg +
", ed=" + ed +
", ls=" + ls +
", sn=" + sn +
", text='" + text + '\'' +
", pgs=" + pgs +
", rg=" + Arrays.toString(rg) +
", deleted=" + deleted +
", vad=" + (vad==null ? "null" : vad.getAsJsonArray("ws").toString()) +
'}';
}
}
//解析返回数据,仅供参考
public static class Decoder {
private Text[] texts;
private int defc = 10;
public Decoder() {
this.texts = new Text[this.defc];
}
public synchronized void decode(Text text) {
if (text.sn >= this.defc) {
this.resize();
}
if ("rpl".equals(text.pgs)) {
for (int i = text.rg[0]; i <= text.rg[1]; i++) {
this.texts[i].deleted = true;
}
}
this.texts[text.sn] = text;
}
public String toString() {
StringBuilder sb = new StringBuilder();
for (Text t : this.texts) {
if (t != null && !t.deleted) {
sb.append(t.text);
}
}
return sb.toString();
}
public void resize() {
int oc = this.defc;
this.defc <<= 1;
Text[] old = this.texts;
this.texts = new Text[this.defc];
for (int i = 0; i < oc; i++) {
this.texts[i] = old[i];
}
}
public void discard(){
for(int i=0;i<this.texts.length;i++){
this.texts[i]= null;
}
}
}
}
\ No newline at end of file
......@@ -40,9 +40,9 @@ POST {{baseUrl}}/audio/upload
Content-Type: multipart/form-data; boundary=WebAppBoundary
--WebAppBoundary
Content-Disposition: form-data; name="file"; filename="test.pcm"
Content-Disposition: form-data; name="file"; filename="recording.pcm"
< ./test.pcm
< ./recording.pcm
--WebAppBoundary--
###测试链接数据库
......
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