1.前言
我使用的科大讯飞的录音文件转写。需要购买科大讯飞的产品,可以自行购买
识别的速度有点慢,大概在5s左右。不知道为什么,有喜欢的可以一起研究一下。不喜勿喷,谢谢
2.使用依赖
<!--语音识别使用的依赖-->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.7.21</version>
</dependency>
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20231013</version> <!-- 使用最新版本 -->
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.4</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.11</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.google.cloud</groupId>
<artifactId>google-cloud-speech</artifactId>
<version>0.84.0-beta</version>
</dependency>
3.工具类
import cn.hutool.json.JSONUtil;
import com.hxc.sign.LfasrSignature;
import org.apache.commons.lang.StringEscapeUtils;
import com.google.gson.Gson;
import java.io.*;
import java.security.SignatureException;
import java.util.HashMap;
public class Ifasrdemo {
private static final String HOST = "https://raasr.xfyun.cn";
public static String AUDIO_FILE_PATH = "";
private static final String appid = "自己购买的科大讯飞的appid";
private static final String keySecret = "购买的科大讯飞的keySecret";
private static final Gson gson = new Gson();
public static String a1() throws Exception {
String result = upload();
String jsonStr = StringEscapeUtils.unescapeJavaScript(result);
String orderId = String.valueOf(JSONUtil.getByPath(JSONUtil.parse(jsonStr), "content.orderId"));
return getResult(orderId);
}
private static String upload() throws SignatureException, FileNotFoundException {
HashMap<String, Object> map = new HashMap<>(16);
File audio = new File(AUDIO_FILE_PATH);
String fileName = audio.getName();
long fileSize = audio.length();
map.put("appId", appid);
map.put("fileSize", fileSize);
map.put("fileName", fileName);
map.put("duration", "200");
LfasrSignature lfasrSignature = new LfasrSignature(appid, keySecret);
map.put("signa", lfasrSignature.getSigna());
map.put("ts", lfasrSignature.getTs());
String paramString = HttpUtil.parseMapToPathParam(map);
System.out.println("upload paramString:" + paramString);
String url = HOST + "/v2/api/upload" + "?" + paramString;
System.out.println("upload_url:" + url);
String response = HttpUtil.iflyrecUpload(url, new FileInputStream(audio));
System.out.println("upload response:" + response);
return response;
}
private static String getResult(String orderId) throws SignatureException, InterruptedException, IOException {
HashMap<String, Object> map = new HashMap<>(16);
map.put("orderId", orderId);
LfasrSignature lfasrSignature = new LfasrSignature(appid, keySecret);
map.put("signa", lfasrSignature.getSigna());
map.put("ts", lfasrSignature.getTs());
map.put("appId", appid);
map.put("resultType", "transfer,predict");
String paramString = HttpUtil.parseMapToPathParam(map);
String url = HOST + "/v2/api/getResult" + "?" + paramString;
System.out.println("\nget_result_url:" + url);
while (true) {
String response = HttpUtil.iflyrecGet(url);
JsonParse jsonParse = gson.fromJson(response, JsonParse.class);
if (jsonParse.content.orderInfo.status == 4 || jsonParse.content.orderInfo.status == -1) {
System.out.println("订单完成:" + response);
write(response);
return response;
} else {
System.out.println("进行中...,状态为:" + jsonParse.content.orderInfo.status);
//建议使用回调的方式查询结果,查询接口有请求频率限制
Thread.sleep(7000);
}
}
}
public static void write(String resp) throws IOException {//
//将写入转化为流的形式
BufferedWriter bw = new BufferedWriter(new FileWriter("D:\\MyJavaProject\\springBoot3\\boot3-01\\src\\main\\resources\\output\\test.txt"));
String ss = resp;
bw.write(ss);
//关闭流
bw.close();
System.out.println("写入txt成功");
}
class JsonParse {
Content content;
}
class Content {
OrderInfo orderInfo;
}
class OrderInfo {
Integer status;
}
}
import org.apache.http.Consts;
import org.apache.http.HttpEntity;
import org.apache.http.HttpStatus;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.InputStreamEntity;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.*;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
/**
* HTTP请求工具类
*/
public class HttpUtil {
private HttpUtil() {
}
private static final Logger LOGGER = LoggerFactory.getLogger(HttpUtil.class);
private static final String UTF8 = "UTF-8";
/**
* 组件的httpClient
*/
private static CloseableHttpClient httpClient;
static {
// 听见服务、流控组件连接池
PoolingHttpClientConnectionManager pool = new PoolingHttpClientConnectionManager();
pool.setMaxTotal(600);//客户端总并行链接最大数
pool.setDefaultMaxPerRoute(200);//每个主机的最大并行链接数
httpClient = HttpClients.createMinimal(pool);
}
/**
* 请求的upload接口, 发送音频创建转写订单
*
* @param url 请求地址
* @param in 需要转写的音频流
* @return 返回结果
*/
public static String iflyrecUpload(String url, InputStream in) {
// 1、准备参数
HttpPost httpPost = new HttpPost(url);
// 设置超时时间, 防止504的时候会耗时30分钟
RequestConfig requestConfig = RequestConfig.custom()
//从连接池中获取连接的超时时间
.setConnectionRequestTimeout(5000)
//与服务器连接超时时间, 指的是连接一个url的连接等待时间
.setConnectTimeout(600000)
// 读取超时, 指的是连接上一个url,获取response的返回等待时间
.setSocketTimeout(600000).build();
httpPost.setConfig(requestConfig);
HttpEntity requestEntity = new InputStreamEntity(in, ContentType.APPLICATION_JSON);
//System.out.println("---"+requestEntity);
httpPost.setEntity(requestEntity);
// 2、执行请求
return doExecute(httpPost, null);
}
/**
* 请求听见的获取结果接口
*
* @param url 请求路径
* @return 返回结果
*/
public static String iflyrecGet(String url) {
// 1、准备参数
HttpGet httpget = new HttpGet(url);
// 2、执行请求
return doExecute(httpget, UTF8);
}
/**
* 流控组件调用
*
* @param url 请求路径
* @return 返回结果
*/
public static String flowCtrlGet(String url) {
// 1、准备参数
HttpGet httpget = new HttpGet(url);
RequestConfig requestConfig = RequestConfig.custom()
//从连接池中获取连接的超时时间
.setConnectionRequestTimeout(500)
//与服务器连接超时时间
.setConnectTimeout(500)
// 读取超时
.setSocketTimeout(500).build();
httpget.setConfig(requestConfig);
// 2、执行请求
return doExecute(httpget, null);
}
/**
* 流传输的post
*
* @param url 请求路径
* @param body 字节流数据
* @return 返回结果
*/
public static String post(String url, byte[] body) {
// 1、准备参数
HttpPost httpPost = new HttpPost(url);
httpPost.setEntity(new ByteArrayEntity(body, ContentType.create("application/octet-stream", Consts.UTF_8)));
// 2、执行请求
return doExecute(httpPost, UTF8);
}
/**
* 带字符串参数的post请求
*
* @param url 请求路径
* @param param 字符串参数
* @return 返回结果
*/
public static String post(String url, String param) {
// 1、准备参数
HttpPost httpPost = new HttpPost(url);
// 设置超时时间
RequestConfig requestConfig = RequestConfig.custom()
//从连接池中获取连接的超时时间
.setConnectionRequestTimeout(1000)
//与服务器连接超时时间, 指的是连接一个url的连接等待时间
.setConnectTimeout(10000)
// 读取超时, 指的是连接上一个url,获取response的返回等待时间
.setSocketTimeout(10000).build();
httpPost.setConfig(requestConfig);
httpPost.setEntity(new StringEntity(param, ContentType.APPLICATION_JSON));
// 2、执行请求
return doExecute(httpPost, null);
}
/**
* 发送HttpGet请求
*
* @param url 请求路径
* @return 返回结果
*/
public static String sendGet(String url) {
// 1、准备参数
HttpGet httpget = new HttpGet(url);
// 2、执行请求
return doExecute(httpget, null);
}
/**
* 执行网络请求
*
* @param requestBase http请求对象
* @param charset 字符集
* @return 返回结果
*/
private static String doExecute(HttpRequestBase requestBase, String charset) {
String result = null;
try (CloseableHttpResponse response = httpClient.execute(requestBase)) {
// 3、检查结果状态
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode != HttpStatus.SC_OK) {
LOGGER.error("网络异常");
return null;
}
// 4、获取结果
result = charset == null
? EntityUtils.toString(response.getEntity())
: EntityUtils.toString(response.getEntity(), charset);
} catch (Exception e) {
LOGGER.error("网络异常", e);
}
return result;
}
/**
* 发送post请求
*
* @param url 请求路径
* @param header 请求头
* @param body 请求数据
* @return 返回结果
*/
public static String postWithHeader(String url, Map<String, String> header, String body) {
StringBuilder result = new StringBuilder();
BufferedReader in = null;
PrintWriter out = null;
InputStreamReader is = null;
try {
// 设置 url
URL realUrl = new URL(url);
URLConnection connection = realUrl.openConnection();
// 设置 header
for (Entry<String, String> entry : header.entrySet()) {
connection.setRequestProperty(entry.getKey(), entry.getValue());
}
// 设置请求 body
connection.setDoOutput(true);
connection.setDoInput(true);
out = new PrintWriter(connection.getOutputStream());
// 保存body
out.print(body);
// 发送body
out.flush();
// 获取响应body
is = new InputStreamReader(connection.getInputStream());
in = new BufferedReader(is);
String line;
while ((line = in.readLine()) != null) {
result.append(line);
}
} catch (Exception e) {
LOGGER.error("HttpUtil postWithHeader Exception!", e);
return null;
} finally {
if (is != null) {
try {
is.close();
} catch (IOException e) {
LOGGER.error("close IO resource Exception!", e);
}
}
if (in != null) {
try {
in.close();
} catch (IOException e) {
LOGGER.error("close IO resource Exception!", e);
}
}
if (out != null) {
out.close();
}
}
return result.toString();
}
/**
* 将集合转换为路径参数
*
* @param param 集合参数
* @return 路径参数
* @author white
*/
public static String parseMapToPathParam(Map<String, Object> param) {
StringBuilder sb = new StringBuilder();
try {
Set<Entry<String, Object>> entryset = param.entrySet();
boolean isFirst = true;
for (Entry<String, Object> entry : entryset) {
if (!isFirst) {
sb.append("&");
} else {
isFirst = false;
}
sb.append(URLEncoder.encode(entry.getKey(), UTF8));
sb.append("=");
sb.append(URLEncoder.encode(entry.getValue().toString(), UTF8));
}
} catch (UnsupportedEncodingException e) {
LOGGER.error("HttpUtil parseMapToPathParam Exception!", e);
}
return sb.toString();
}
}
import cn.hutool.json.JSONUtil;
import com.hxc.sign.LfasrSignature;
import org.apache.commons.lang.StringEscapeUtils;
import com.google.gson.Gson;
import java.io.*;
import java.security.SignatureException;
import java.util.HashMap;
public class Ifasrdemo {
private static final String HOST = "https://raasr.xfyun.cn";
public static String AUDIO_FILE_PATH = "";
private static final String appid = "购买的科大讯飞的appid";
private static final String keySecret = "购买的科大讯飞的key";
private static final Gson gson = new Gson();
public static String a1() throws Exception {
String result = upload();
String jsonStr = StringEscapeUtils.unescapeJavaScript(result);
String orderId = String.valueOf(JSONUtil.getByPath(JSONUtil.parse(jsonStr), "content.orderId"));
return getResult(orderId);
}
private static String upload() throws SignatureException, FileNotFoundException {
HashMap<String, Object> map = new HashMap<>(16);
File audio = new File(AUDIO_FILE_PATH);
String fileName = audio.getName();
long fileSize = audio.length();
map.put("appId", appid);
map.put("fileSize", fileSize);
map.put("fileName", fileName);
map.put("duration", "200");
LfasrSignature lfasrSignature = new LfasrSignature(appid, keySecret);
map.put("signa", lfasrSignature.getSigna());
map.put("ts", lfasrSignature.getTs());
String paramString = HttpUtil.parseMapToPathParam(map);
System.out.println("upload paramString:" + paramString);
String url = HOST + "/v2/api/upload" + "?" + paramString;
System.out.println("upload_url:" + url);
String response = HttpUtil.iflyrecUpload(url, new FileInputStream(audio));
System.out.println("upload response:" + response);
return response;
}
private static String getResult(String orderId) throws SignatureException, InterruptedException, IOException {
HashMap<String, Object> map = new HashMap<>(16);
map.put("orderId", orderId);
LfasrSignature lfasrSignature = new LfasrSignature(appid, keySecret);
map.put("signa", lfasrSignature.getSigna());
map.put("ts", lfasrSignature.getTs());
map.put("appId", appid);
map.put("resultType", "transfer,predict");
String paramString = HttpUtil.parseMapToPathParam(map);
String url = HOST + "/v2/api/getResult" + "?" + paramString;
System.out.println("\nget_result_url:" + url);
while (true) {
String response = HttpUtil.iflyrecGet(url);
JsonParse jsonParse = gson.fromJson(response, JsonParse.class);
if (jsonParse.content.orderInfo.status == 4 || jsonParse.content.orderInfo.status == -1) {
System.out.println("订单完成:" + response);
write(response);
return response;
} else {
System.out.println("进行中...,状态为:" + jsonParse.content.orderInfo.status);
//建议使用回调的方式查询结果,查询接口有请求频率限制
Thread.sleep(7000);
}
}
}
public static void write(String resp) throws IOException {//
//将写入转化为流的形式
BufferedWriter bw = new BufferedWriter(new FileWriter("D:\\MyJavaProject\\springBoot3\\boot3-01\\src\\main\\resources\\output\\test.txt"));
String ss = resp;
bw.write(ss);
//关闭流
bw.close();
System.out.println("写入txt成功");
}
class JsonParse {
Content content;
}
class Content {
OrderInfo orderInfo;
}
class OrderInfo {
Integer status;
}
}
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
public class JsonProcessor {
// 读取 JSON 文件
public static JSONObject readJsonFile(String path) throws IOException, JSONException {
StringBuilder content = new StringBuilder();
try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(path)))) {
String line;
while ((line = reader.readLine()) != null) {
content.append(line);
}
}
return new JSONObject(content.toString());
}
// 处理单个 VAD 的结果
public static String mergeResultForOneVad(JSONObject resultVad) throws JSONException {
StringBuilder spkStr = new StringBuilder();
JSONArray rtArray = resultVad.getJSONObject("st").getJSONArray("rt");
for (int i = 0; i < rtArray.length(); i++) {
JSONObject rtDic = rtArray.getJSONObject(i);
//spkStr.append(3 - resultVad.getJSONObject("st").getInt("rl"));
JSONArray wsArray = rtDic.getJSONArray("ws");
for (int j = 0; j < wsArray.length(); j++) {
JSONObject wsDic = wsArray.getJSONObject(j);
JSONArray cwArray = wsDic.getJSONArray("cw");
for (int k = 0; k < cwArray.length(); k++) {
JSONObject cwDic = cwArray.getJSONObject(k);
String wArray = cwDic.getString("w");
//for (int l = 0; l < wArray.length(); l++) {
spkStr.append(wArray);
//}
}
}
//spkStr.append("\n");
}
return spkStr.toString();
}
// 将内容写入文件
public static String contentToFile(List<String> content, String outputFilePath) throws IOException {
StringBuilder contentStr = new StringBuilder();
for (String line : content) {
contentStr.append(line);
}
return contentStr.toString();
}
public static String a2(String s) {
try {
//String pathXunfei = "D:\\java-project-dome\\springboot3-dome\\springboot-dome1\\target\\classes\\output\\test.txt";
String outputPathXunfei = "xunfei_output.txt";
// 读取 JSON 文件
//JSONObject jsXunfei = readJsonFile(pathXunfei);
JSONObject jsXunfei = new JSONObject(s);
JSONObject orderResult = new JSONObject(jsXunfei.getJSONObject("content").getString("orderResult"));
// 处理 lattice 数据
JSONArray latticeArray = orderResult.getJSONArray("lattice");
List<String> content = new ArrayList<>();
for (int i = 0; i < latticeArray.length(); i++) {
JSONObject latticeItem = latticeArray.getJSONObject(i);
JSONObject json1Best = new JSONObject(latticeItem.getString("json_1best"));
content.add(mergeResultForOneVad(json1Best));
}
// 将结果写入文件
String s1 = contentToFile(content, outputPathXunfei);
System.out.println("处理完成,结果已写入文件:" + outputPathXunfei);
return s1;
} catch (IOException | JSONException e) {
e.printStackTrace();
}
return "失败";
}
import java.net.MalformedURLException;
import java.net.URL;
import java.security.SignatureException;
/**
* 加签加密抽象类
*
* @author : jun
* @date : 2021年04月08日
*/
public abstract class AbstractSignature {
/**
* 签名ID
*/
private String id;
/**
* 加密key
*/
private String key;
/**
* 服务url
*/
private String url;
/**
* 加密算法
*/
private String encryptType;
/**
* 待加密原始字符
*/
private String originSign;
/**
* 最终生成的签名
*/
protected String signa;
/**
* 时间戳timestamp
*/
private String ts;
/**
* 请求类型,默认get
*/
protected String requestMethod = "GET";
/**
* @param id
* @param key
* @param url
*/
public AbstractSignature(String id, String key, String url) {
this.id = id;
this.key = key;
this.url = url;
this.ts = generateTs();
}
/**
* 可设置请求类型
* @param id
* @param key
* @param url
* @param isPost 是否为POST
*/
public AbstractSignature(String id, String key, String url, boolean isPost) {
this.id = id;
this.key = key;
this.url = url;
if (isPost) {
this.requestMethod = "POST";
}else{
this.requestMethod = "GET";
}
this.ts = generateTs();
}
/**
* 生成ts时间
*/
public String generateTs() {
return String.valueOf(System.currentTimeMillis() / 1000L);
}
/**
* 完成签名,返回完整签名
*
* @return
* @throws SignatureException
*/
public abstract String getSigna() throws SignatureException;
public String generateOriginSign() throws SignatureException {
try {
URL url = new URL(this.getUrl());
return "host: " + url.getHost() + "\n" +
"date: " + this.getTs() + "\n" +
"GET " + url.getPath() + " HTTP/1.1";
} catch (MalformedURLException e) {
throw new SignatureException("MalformedURLException:" + e.getMessage());
}
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public String getOriginSign() {
return originSign;
}
public void setOriginSign(String originSign) {
this.originSign = originSign;
}
public String getTs() {
return ts;
}
public void setTs(String ts) {
this.ts = ts;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getEncryptType() {
return encryptType;
}
public void setEncryptType(String encryptType) {
this.encryptType = encryptType;
}
}
import cn.hutool.core.util.ObjectUtil;
import com.hxc.sign.utils.CryptTools;
import java.security.NoSuchAlgorithmException;
import java.security.SignatureException;
/**
* Lfasr能力签名实体
*
* @author : jun
* @date : 2021年03月29日
*/
public class LfasrSignature extends AbstractSignature {
/**
*
* @param appId
* @param keySecret
*/
public LfasrSignature(String appId, String keySecret) {
super(appId, keySecret, null);
}
@Override
public String getSigna() throws SignatureException {
if (ObjectUtil.isEmpty(this.signa)) {
this.setOriginSign(generateOriginSign());
this.signa = generateSignature();
}
return this.signa;
}
/**
* 生成最终的签名,需要先生成原始sign
*
* @throws SignatureException
*/
public String generateSignature() throws SignatureException {
return CryptTools.hmacEncrypt(CryptTools.HMAC_SHA1, this.getOriginSign(), this.getKey());
}
/**
* 生成待加密原始字符
*
* @throws NoSuchAlgorithmException
*/
@Override
public String generateOriginSign() throws SignatureException {
return CryptTools.md5Encrypt(this.getId() + this.getTs());
}
}
4.Controller代码
import com.hxc.sign.utils.Ifasrdemo;
import com.hxc.sign.utils.JsonProcessor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import java.io.*;
@RestController
@RequestMapping("/xf")
@Slf4j
public class XfyunController {
@PostMapping("/uploadSdk")
public String uploadSdk(@RequestParam("files") MultipartFile files) throws Exception {
// 指定保存文件的本地路径
String uploadDir = "D:/uploads/"; // 你可以根据实际情况更改路径
// 获取文件原始文件名
String fileName = files.getOriginalFilename();
// 创建目标文件对象
File dest = new File(uploadDir + fileName);
// 创建上传目录(如果没有的话)
if (!dest.getParentFile().exists()) {
dest.getParentFile().mkdirs();
}
// 将文件保存到指定路径
files.transferTo(dest);
Ifasrdemo.AUDIO_FILE_PATH = dest.getAbsolutePath();
String s = Ifasrdemo.a1();
return JsonProcessor.a2(s);
}
}