需求
需要对本地音频文件,调用科大讯飞的api进行转文字,本来呢,以为很简单,结果坑不少。
语音转写 API 文档
坑1:解析
下载demo,代码也挺简单,放到idea中,替换一下key,直接运行,但是看到返回,傻眼了
{“code”:“000000”,“descInfo”:“success”,“content”:{“orderInfo”:{“orderId”:“111”,“failType”:11,“status”:-1,“originalDuration”:200,“realDuration”:20173,“expireTime”:1727867828000},“orderResult”:“{“lattice”:[{“json_1best”:”{\“st\”:{\“sc\”:\“0.00\”,\“pa\”:\“0\”,\“rt\”:[{\“ws\”:[{\“cw\”:[{\“w\”:\“观察\”,\“wp\”:\“n\”,\“wc\”:\“0.0000\”}],\“wb\”:1,\“we\”:24},{\“cw\”:[{\“w\”:\“右侧\”,\“wp\”:\“n\”,\“wc\”:\“0.0000\”}],\“wb\”:25,\“we\”:56},{\“cw\”:[{\“w\”:\“柱\”,\“wp\”:\“n\”,\“wc\”:\“0.0000\”}],\“wb\”:57,\“we\”:68},{\“cw\”:[{\“w\”:\“体\”,\“wp\”:\“n\”,\“wc\”:\“0.0000\”}],\“wb\”:69,\“we\”:80},{\“cw\”:[{\“w\”:\“,\”,\“wp\”:\“p\”,\“wc\”:\“0.0000\”}],\“wb\”:80,\“we\”:80},{\“cw\”:[{\“w\”:\“判断\”,\“wp\”:\“n\”,\“wc\”:\“0.0000\”}],\“wb\”:81,\“we\”:116},{\“cw\”:[{\“w\”:\“Mike\”,\“wp\”:\“n\”,\“sm\”:\“replace_list\”,\“wc\”:\“0.0000\”}],\“wb\”:117,\“we\”:144},{\“cw\”:[{\“w\”:\“是否\”,\“wp\”:\“n\”,\“wc\”:\“0.0000\”}],\“wb\”:145,\“we\”:168},{\“cw\”:[{\“w\”:\“正常\”,\“wp\”:\“n\”,\“wc\”:\“0.0000\”}],\“wb\”:169,\“we\”:204},{\“cw\”:[{\“w\”:\“。\”,\“wp\”:\“p\”,\“wc\”:\“0.0000\”}],\“wb\”:204,\“we\”:204}]}],\“bg\”:\“730\”,\“rl\”:\“0\”,\“ed\”:\“2930\”}}“},{“json_1best”:”{\“st\”:{\“sc\”:\“0.00\”,\“pa\”:\“0\”,\“rt\”:[{\“ws\”:[{\“cw\”:[{\“w\”:\“123456789\”,\“og\”:\“一\”,\“wp\”:\“n\”,\“wc\”:\“0.0000\”}],\“wb\”:1,\“we\”:88},{\“cw\”:[{\“w\”:\" 10\“,\“og\”:\” 十\“,\“wp\”:\“n\”,\“wc\”:\“0.0000\”}],\“wb\”:89,\“we\”:100},{\“cw\”:[{\“w\”:\” 11\“,\“og\”:\” 十一\“,\“wp\”:\“n\”,\“wc\”:\“0.0000\”}],\“wb\”:101,\“we\”:116},{\“cw\”:[{\“w\”:\“小时\”,\“wp\”:\“n\”,\“wc\”:\“0.0000\”}],\“wb\”:117,\“we\”:136},{\“cw\”:[{\“w\”:\”,\“,\“wp\”:\“p\”,\“wc\”:\“0.0000\”}],\“wb\”:136,\“we\”:136},{\“cw\”:[{\“w\”:\“吧\”,\“wp\”:\“s\”,\“wc\”:\“0.0000\”}],\“wb\”:137,\“we\”:144},{\“cw\”:[{\“w\”:\“谢谢\”,\“wp\”:\“n\”,\“wc\”:\“0.0000\”}],\“wb\”:145,\“we\”:264},{\“cw\”:[{\“w\”:\”。\“,\“wp\”:\“p\”,\“wc\”:\“0.0000\”}],\“wb\”:264,\“we\”:264}]}],\“bg\”:\“3660\”,\“rl\”:\“0\”,\“ed\”:\“6460\”}}”},{“json_1best”:“{\“st\”:{\“sc\”:\“0.00\”,\“pa\”:\“0\”,\“rt\”:[{\“ws\”:[{\“cw\”:[{\“w\”:\“嗯\”,\“wp\”:\“s\”,\“wc\”:\“0.0000\”}],\“wb\”:1,\“we\”:32},{\“cw\”:[{\“w\”:\“快\”,\“wp\”:\“n\”,\“wc\”:\“0.0000\”}],\“wb\”:33,\“we\”:52},{\“cw\”:[{\“w\”:\”。\“,\“wp\”:\“p\”,\“wc\”:\“0.0000\”}],\“wb\”:52,\“we\”:52}]}],\“bg\”:\“7910\”,\“rl\”:\“0\”,\“ed\”:\“8630\”}}”},{“json_1best”:“{\“st\”:{\“sc\”:\“0.00\”,\“pa\”:\“0\”,\“rt\”:[{\“ws\”:[{\“cw\”:[{\“w\”:\“不要\”,\“wp\”:\“n\”,\“wc\”:\“0.0000\”}],\“wb\”:1,\“we\”:16},{\“cw\”:[{\“w\”:\“发生\”,\“wp\”:\“n\”,\“wc\”:\“0.0000\”}],\“wb\”:17,\“we\”:40},{\“cw\”:[{\“w\”:\“问题\”,\“wp\”:\“n\”,\“wc\”:\“0.0000\”}],\“wb\”:41,\“we\”:64},{\“cw\”:[{\“w\”:\“了\”,\“wp\”:\“n\”,\“wc\”:\“0.0000\”}],\“wb\”:65,\“we\”:76},{\“cw\”:[{\“w\”:\“就\”,\“wp\”:\“n\”,\“wc\”:\“0.0000\”}],\“wb\”:77,\“we\”:84},{\“cw\”:[{\“w\”:\“行\”,\“wp\”:\“n\”,\“wc\”:\“0.0000\”}],\“wb\”:85,\“we\”:108},{\“cw\”:[{\“w\”:\”。\“,\“wp\”:\“p\”,\“wc\”:\“0.0000\”}],\“wb\”:108,\“we\”:108}]}],\“bg\”:\“15140\”,\“rl\”:\“0\”,\“ed\”:\“16290\”}}”},{“json_1best”:“{\“st\”:{\“sc\”:\“0.00\”,\“pa\”:\“0\”,\“rt\”:[{\“ws\”:[{\“cw\”:[{\“w\”:\“问题\”,\“wp\”:\“n\”,\“wc\”:\“0.0000\”}],\“wb\”:1,\“we\”:36},{\“cw\”:[{\“w\”:\”。\“,\“wp\”:\“p\”,\“wc\”:\“0.0000\”}],\“wb\”:36,\“we\”:36},{\“cw\”:[{\“w\”:\”\“,\“wp\”:\“g\”,\“wc\”:\“0.0000\”}],\“wb\”:36,\“we\”:36}]}],\“bg\”:\“17560\”,\“rl\”:\“0\”,\“ed\”:\“17970\”}}”}],“lattice2”:[{“lid”:“0”,“end”:“2930”,“begin”:“730”,“json_1best”:{“st”:{“sc”:“0.00”,“pa”:“0”,“rt”:[{“nb”:“1”,“nc”:“1.0”,“ws”:[{“cw”:[{“w”:“观察”,“wp”:“n”,“wc”:“0.0000”}],“wb”:1,“we”:24},{“cw”:[{“w”:“右侧”,“wp”:“n”,“wc”:“0.0000”}],“wb”:25,“we”:56},{“cw”:[{“w”:“柱”,“wp”:“n”,“wc”:“0.0000”}],“wb”:57,“we”:68},{“cw”:[{“w”:“体”,“wp”:“n”,“wc”:“0.0000”}],“wb”:69,“we”:80},{“cw”:[{“w”:“,”,“wp”:“p”,“wc”:“0.0000”}],“wb”:80,“we”:80},{“cw”:[{“w”:“判断”,“wp”:“n”,“wc”:“0.0000”}],“wb”:81,“we”:116},{“cw”:[{“w”:“Mike”,“wp”:“n”,“sm”:“replace_list”,“wc”:“0.0000”}],“wb”:117,“we”:144},{“cw”:[{“w”:“是否”,“wp”:“n”,“wc”:“0.0000”}],“wb”:145,“we”:168},{“cw”:[{“w”:“正常”,“wp”:“n”,“wc”:“0.0000”}],“wb”:169,“we”:204},{“cw”:[{“w”:“。”,“wp”:“p”,“wc”:“0.0000”}],“wb”:204,“we”:204}]}],“pt”:“replace_list”,“bg”:“730”,“si”:“0”,“rl”:“0”,“ed”:“2930”}},“spk”:“段落-0”},{“lid”:“0”,“end”:“6460”,“begin”:“3660”,“json_1best”:{“st”:{“sc”:“0.00”,“pa”:“0”,“rt”:[{“nb”:“1”,“nc”:“1.0”,“ws”:[{“cw”:[{“w”:“123456789”,“og”:“一”,“wp”:“n”,“wc”:“0.0000”}],“wb”:1,“we”:88},{“cw”:[{“w”:" 10",“og”:" 十",“wp”:“n”,“wc”:“0.0000”}],“wb”:89,“we”:100},{“cw”:[{“w”:" 11",“og”:" 十一",“wp”:“n”,“wc”:“0.0000”}],“wb”:101,“we”:116},{“cw”:[{“w”:“小时”,“wp”:“n”,“wc”:“0.0000”}],“wb”:117,“we”:136},{“cw”:[{“w”:“吧”,“wp”:“n”,“wc”:“0.0000”}],“wb”:137,“we”:144},{“cw”:[{“w”:“,”,“wp”:“p”,“wc”:“0.0000”}],“wb”:144,“we”:144},{“cw”:[{“w”:“谢谢”,“wp”:“n”,“wc”:“0.0000”}],“wb”:145,“we”:264},{“cw”:[{“w”:“。”,“wp”:“p”,“wc”:“0.0000”}],“wb”:264,“we”:264}]}],“pt”:“reserved”,“bg”:“3660”,“si”:“1”,“rl”:“0”,“ed”:“6460”}},“spk”:“段落-0”},{“lid”:“0”,“end”:“8630”,“begin”:“7910”,“json_1best”:{“st”:{“sc”:“0.00”,“pa”:“0”,“rt”:[{“nb”:“1”,“nc”:“1.0”,“ws”:[{“cw”:[{“w”:“嗯”,“wp”:“n”,“wc”:“0.0000”}],“wb”:1,“we”:32},{“cw”:[{“w”:“快”,“wp”:“n”,“wc”:“0.0000”}],“wb”:33,“we”:52},{“cw”:[{“w”:“。”,“wp”:“p”,“wc”:“0.0000”}],“wb”:52,“we”:52}]}],“pt”:“reserved”,“bg”:“7910”,“si”:“2”,“rl”:“0”,“ed”:“8630”}},“spk”:“段落-0”},{“lid”:“0”,“end”:“16290”,“begin”:“15140”,“json_1best”:{“st”:{“sc”:“0.00”,“pa”:“0”,“rt”:[{“nb”:“1”,“nc”:“1.0”,“ws”:[{“cw”:[{“w”:“不要”,“wp”:“n”,“wc”:“0.0000”}],“wb”:1,“we”:16},{“cw”:[{“w”:“发生”,“wp”:“n”,“wc”:“0.0000”}],“wb”:17,“we”:40},{“cw”:[{“w”:“问题”,“wp”:“n”,“wc”:“0.0000”}],“wb”:41,“we”:64},{“cw”:[{“w”:“了”,“wp”:“n”,“wc”:“0.0000”}],“wb”:65,“we”:76},{“cw”:[{“w”:“就”,“wp”:“n”,“wc”:“0.0000”}],“wb”:77,“we”:84},{“cw”:[{“w”:“行”,“wp”:“n”,“wc”:“0.0000”}],“wb”:85,“we”:108},{“cw”:[{“w”:“。”,“wp”:“p”,“wc”:“0.0000”}],“wb”:108,“we”:108}]}],“pt”:“reserved”,“bg”:“15140”,“si”:“3”,“rl”:“0”,“ed”:“16290”}},“spk”:“段落-0”},{“lid”:“0”,“end”:“17970”,“begin”:“17560”,“json_1best”:{“st”:{“sc”:“0.00”,“pa”:“0”,“rt”:[{“nb”:“1”,“nc”:“1.0”,“ws”:[{“cw”:[{“w”:“问题”,“wp”:“n”,“wc”:“0.0000”}],“wb”:1,“we”:36},{“cw”:[{“w”:“。”,“wp”:“p”,“wc”:“0.0000”}],“wb”:36,“we”:36},{“cw”:[{“w”:“”,“wp”:“g”,“wc”:“0.0000”}],“wb”:36,“we”:36}]}],“pt”:“reserved”,“bg”:“17560”,“si”:“4”,“rl”:“0”,“ed”:“17970”}},“spk”:“段落-0”}]}",“taskEstimateTime”:0}}
不知道为什么要这样返回,在线找的一些json转JavaBean的工具都解析不出来,最后没办法,只能自己剥洋葱一样,一点一点解析,拿到需要的结果(我不知道有没有更好的办法,我只能用这个笨办法了)
public class Ifasrdemo {
private static final String HOST = "https://raasr.xfyun.cn";
private static String AUDIO_FILE_PATH;
private static final String appid = "";
private static final String keySecret = "";
private static final Gson gson = new Gson();
static {
try {
AUDIO_FILE_PATH = Ifasrdemo.class.getResource("/").toURI().getPath() + "/audio/pcmqile.pcm";
} catch (URISyntaxException e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws Exception {
String result = upload();
String jsonStr = StringEscapeUtils.unescapeJavaScript(result);
String orderId = String.valueOf(JSONUtil.getByPath(JSONUtil.parse(jsonStr), "content.orderId"));
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);
StringBuilder resultText=new StringBuilder();
while (true) {
String response = HttpUtil.iflyrecGet(url);
Root jsonParse = gson.fromJson(response, Root.class);
if(jsonParse.content.orderResult!=null&&!jsonParse.content.orderResult.equals("")){
JSONObject jsonObject = new JSONObject(jsonParse.content.orderResult);
JSONArray jsonArray= (JSONArray) jsonObject.get("lattice");
for (Object o : jsonArray) {
JSONObject json1best= new JSONObject(o);
STRoot stRoot = gson.fromJson((String) json1best.get("json_1best"), STRoot.class);
List<Rt> rt = stRoot.getSt().getRt();
for (Rt rt1 : rt) {
for (Ws w : rt1.getWs()) {
for (Cw cw : w.getCw()) {
resultText.append(cw.getW());
}
}
}
}
System.out.println("resultText:"+resultText.toString());
}
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("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;
// }
public class OrderInfo
{
private String orderId;
private int failType;
private int status;
private int originalDuration;
private int realDuration;
private long expireTime;
public void setOrderId(String orderId){
this.orderId = orderId;
}
public String getOrderId(){
return this.orderId;
}
public void setFailType(int failType){
this.failType = failType;
}
public int getFailType(){
return this.failType;
}
public void setStatus(int status){
this.status = status;
}
public int getStatus(){
return this.status;
}
public void setOriginalDuration(int originalDuration){
this.originalDuration = originalDuration;
}
public int getOriginalDuration(){
return this.originalDuration;
}
public void setRealDuration(int realDuration){
this.realDuration = realDuration;
}
public int getRealDuration(){
return this.realDuration;
}
public void setExpireTime(long expireTime){
this.expireTime = expireTime;
}
public long getExpireTime(){
return this.expireTime;
}
}
public class Content
{
private OrderInfo orderInfo;
private String orderResult;
private int taskEstimateTime;
public void setOrderInfo(OrderInfo orderInfo){
this.orderInfo = orderInfo;
}
public OrderInfo getOrderInfo(){
return this.orderInfo;
}
public void setOrderResult(String orderResult){
this.orderResult = orderResult;
}
public String getOrderResult(){
return this.orderResult;
}
public void setTaskEstimateTime(int taskEstimateTime){
this.taskEstimateTime = taskEstimateTime;
}
public int getTaskEstimateTime(){
return this.taskEstimateTime;
}
}
public class Root
{
private String code;
private String descInfo;
private Content content;
public void setCode(String code){
this.code = code;
}
public String getCode(){
return this.code;
}
public void setDescInfo(String descInfo){
this.descInfo = descInfo;
}
public String getDescInfo(){
return this.descInfo;
}
public void setContent(Content content){
this.content = content;
}
public Content getContent(){
return this.content;
}
}
public class Cw
{
private String w;
private String wp;
private String wc;
public void setW(String w){
this.w = w;
}
public String getW(){
return this.w;
}
public void setWp(String wp){
this.wp = wp;
}
public String getWp(){
return this.wp;
}
public void setWc(String wc){
this.wc = wc;
}
public String getWc(){
return this.wc;
}
}
public class Ws
{
private List<Cw> cw;
private int wb;
private int we;
public void setCw(List<Cw> cw){
this.cw = cw;
}
public List<Cw> getCw(){
return this.cw;
}
public void setWb(int wb){
this.wb = wb;
}
public int getWb(){
return this.wb;
}
public void setWe(int we){
this.we = we;
}
public int getWe(){
return this.we;
}
}
public class Rt
{
private List<Ws> ws;
public void setWs(List<Ws> ws){
this.ws = ws;
}
public List<Ws> getWs(){
return this.ws;
}
}
public class St
{
private String sc;
private String pa;
private List<Rt> rt;
private String bg;
private String rl;
private String ed;
public void setSc(String sc){
this.sc = sc;
}
public String getSc(){
return this.sc;
}
public void setPa(String pa){
this.pa = pa;
}
public String getPa(){
return this.pa;
}
public void setRt(List<Rt> rt){
this.rt = rt;
}
public List<Rt> getRt(){
return this.rt;
}
public void setBg(String bg){
this.bg = bg;
}
public String getBg(){
return this.bg;
}
public void setRl(String rl){
this.rl = rl;
}
public String getRl(){
return this.rl;
}
public void setEd(String ed){
this.ed = ed;
}
public String getEd(){
return this.ed;
}
}
public class STRoot
{
private St st;
public void setSt(St st){
this.st = st;
}
public St getSt(){
return this.st;
}
}
}
这是后台代码,可以定一个方法作为回调,但是呢,又没有提供其他平台的sdk,所以android的怎么定义回调?总不能去后台绕一圈吧,所以只能走
Thread.sleep(7000);
这个就是很被动了。
坑2:android包冲突
本来觉得都是java代码,直接拿到android工程里就能用,在maven库里找到对应依赖的gradle版本,结果一运行,傻眼了,报错
java.lang.NoSuchFieldError: No static field INSTANCE of type Lorg/apache/http/conn/ssl/AllowAllHostnameVerifier; in class Lorg/apache/http/conn/ssl/AllowAllHostnameVerifier; or its superclasses (declaration of ‘org.apache.http.conn.ssl.AllowAllHostnameVerifier’ appears in /system/framework/framework.jar!classes3.dex)
原因:经查看是 android_sdk中有一个 AllowAllHostnameVerifier 类 没有INSTANCE字段
而httpclient-4.5.3.jar 中有 AllowAllHostnameVerifier 类 有INSTANCE字段,而代码运行优先使用sdk中的AllowAllHostnameVerifier类了,所以报No static field INSTANCE;
就这个问题,在网上找了好几篇博客,按照他们的方法,都没有解决,发现一篇有用的博客,就是引入了cz.msebera.android:httpclient这个库代替HttpClient,然后把对应的org.apache.http的引用换成cz.msebera.android.httpclient,完美解决
cz.msebera.android:httpclient 最新版本
No static field INSTANCE of type Lorg/apache/http/conn/ssl/AllowAllHostnameVerifier;
坑3:用okhttp调用上传接口失败
既然用apache的网络引用有问题,那就换成android上的okhttp吧,但是这个upload接口比较奇怪,我用postman测试,
上传pcm文件,只能通过body的binary方式,其他的我试过,都不行。
试了好几种okhttp上传文件的方法,都行不通
public class OkhttpUtil {
private static final String HOST = "https://raasr.xfyun.cn";
private String AUDIO_FILE_PATH;
private static final String appid = "111";
private static final String keySecret = "111";
private static final Gson gson = new Gson();
private Activity activity;
private static final String UTF8 = "UTF-8";
public OkhttpUtil(String AUDIO_FILE_PATH, Activity activity) {
this.AUDIO_FILE_PATH = AUDIO_FILE_PATH;
this.activity=activity;
}
public void upload() throws SignatureException {
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 = parseMapToPathParam(map);
byte[] fileContent = new byte[(int) audio.length()];
try (FileInputStream fileInputStream = new FileInputStream(audio)) {
// 读取文件内容到byte数组
fileInputStream.read(fileContent);
} catch (IOException e) {
e.printStackTrace();
}
OkHttpClient client = new OkHttpClient();
// 构造 MultipartBody 对象来包装要上传的文件数据
MediaType mediaType = MediaType.parse("application/octet-stream");
RequestBody requestBody = RequestBody.create(mediaType,fileContent);
//RequestBody requestFile = RequestBody.create(mediaType, audio);
// 构建请求
Request request = new Request.Builder()
.url("https://raasr.xfyun.cn/v2/api/upload?duration=200&signa=ycOd3kgAunVw%2FahO7V0ht9ChKc8%3D&fileName=C4%3A16%3AAB%3AEF%3A10%3AD8--20240929_110929.pcm&fileSize=53200&appId=f7355f0b&ts=1727669949")
.addHeader("Content-Type","application/octet-stream")
.post(requestBody)
.build();
//
// RequestBody fileBody = RequestBody.create(MediaType.parse("application/octet-stream"), audio);
// RequestBody multipartBody = null;
//
// multipartBody = new MultipartBody.Builder()
// .setType(MultipartBody.FORM)
// .addFormDataPart("file", fileName,fileBody)//文件主体
// .build();
//
//
// Request request = new Request.Builder()
// .post(multipartBody)
//
// .url("https://raasr.xfyun.cn/v2/api/upload"+"?"+paramString)
// .build();
client.newCall(request).enqueue(new Callback() {
@Override
public void onResponse(Call call, Response response) throws IOException {
if(response.isSuccessful()){//回调的方法执行在子线程。
String result = response.body().string();
Logger.show("result",result);
}else{
}
}
@Override
public void onFailure(Call call, IOException e) {
e.printStackTrace();
}
});
}
public static String parseMapToPathParam(Map<String, Object> param) {
StringBuilder sb = new StringBuilder();
try {
Set<Map.Entry<String, Object>> entryset = param.entrySet();
boolean isFirst = true;
for (Map.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.show("HttpUtil","HttpUtil parseMapToPathParam Exception!");
}
return sb.toString();
}
}
坑4:Android进程切换
Java代码不涉及到控件和网络的切换,但是Android会涉及到,直接用java代码会报错:
android.os.NetworkOnMainThreadException
所以只能切换到子线程,但是得到结果以后,又要给控件赋值,又得切回到主线程
public class XunfeiRequest {
private static final String HOST = "https://raasr.xfyun.cn";
private String AUDIO_FILE_PATH;
private static final String appid = "f7355f0b";
private static final String keySecret = "777e2077d71f092bca0c4b5eb74a9a62";
private static final Gson gson = new Gson();
public XunfeiRequest(String AUDIO_FILE_PATH) throws Exception {
this.AUDIO_FILE_PATH = AUDIO_FILE_PATH;
new Thread(new Runnable() {
@Override
public void run() {
String result = null;
try {
result = upload();
String jsonStr = StringEscapeUtils.unescapeJavaScript(result);
String orderId = String.valueOf(JSONUtil.getByPath(JSONUtil.parse(jsonStr), "content.orderId"));
getResult(orderId);
} catch (SignatureException e) {
throw new RuntimeException(e);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}).start();
}
private 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 void 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);
StringBuilder resultText = new StringBuilder();
while (true) {
String response = HttpUtil.iflyrecGet(url);
Root jsonParse = gson.fromJson(response, Root.class);
if (jsonParse.content.orderInfo.status == 4 || jsonParse.content.orderInfo.status == -1) {
System.out.println("订单完成:" + response);
if (jsonParse.content.orderResult != null && !jsonParse.content.orderResult.equals("")) {
JSONObject jsonObject = new JSONObject(jsonParse.content.orderResult);
JSONArray jsonArray = (JSONArray) jsonObject.get("lattice");
for (Object o : jsonArray) {
JSONObject json1best = new JSONObject(o);
STRoot stRoot = gson.fromJson((String) json1best.get("json_1best"), STRoot.class);
List<Rt> rt = stRoot.getSt().getRt();
for (Rt rt1 : rt) {
for (Ws w : rt1.getWs()) {
for (Cw cw : w.getCw()) {
resultText.append(cw.getW());
}
}
}
}
System.out.println("resultText:" + resultText.toString());
}
final Handler mainHandler = new Handler(Looper.getMainLooper());
// 在子线程中更新数据并刷新RecyclerView
new Thread(new Runnable() {
@Override
public void run() {
// 这里进行数据的更新操作
// updateYourData();
// 使用Handler将刷新操作切换到UI线程
mainHandler.post(new Runnable() {
@Override
public void run() {
if (iXunfeiRequest != null) {
iXunfeiRequest.getXunfeiResult(resultText.toString(),jsonParse.content.orderInfo.failType);
}
}
});
}
}).start();
break;
} else {
System.out.println("进行中...,状态为:" + jsonParse.content.orderInfo.status);
//建议使用回调的方式查询结果,查询接口有请求频率限制
Thread.sleep(5000);
}
}
}
IXunfeiRequest iXunfeiRequest;
public void setiXunfeiRequest(IXunfeiRequest iXunfeiRequest) {
this.iXunfeiRequest = iXunfeiRequest;
}
public interface IXunfeiRequest {
void getXunfeiResult(String result,int failType);
}
public class OrderInfo {
private String orderId;
private int failType;
private int status;
private int originalDuration;
private int realDuration;
private long expireTime;
public void setOrderId(String orderId) {
this.orderId = orderId;
}
public String getOrderId() {
return this.orderId;
}
public void setFailType(int failType) {
this.failType = failType;
}
public int getFailType() {
return this.failType;
}
public void setStatus(int status) {
this.status = status;
}
public int getStatus() {
return this.status;
}
public void setOriginalDuration(int originalDuration) {
this.originalDuration = originalDuration;
}
public int getOriginalDuration() {
return this.originalDuration;
}
public void setRealDuration(int realDuration) {
this.realDuration = realDuration;
}
public int getRealDuration() {
return this.realDuration;
}
public void setExpireTime(long expireTime) {
this.expireTime = expireTime;
}
public long getExpireTime() {
return this.expireTime;
}
}
public class Content {
private OrderInfo orderInfo;
private String orderResult;
private int taskEstimateTime;
public void setOrderInfo(OrderInfo orderInfo) {
this.orderInfo = orderInfo;
}
public OrderInfo getOrderInfo() {
return this.orderInfo;
}
public void setOrderResult(String orderResult) {
this.orderResult = orderResult;
}
public String getOrderResult() {
return this.orderResult;
}
public void setTaskEstimateTime(int taskEstimateTime) {
this.taskEstimateTime = taskEstimateTime;
}
public int getTaskEstimateTime() {
return this.taskEstimateTime;
}
}
public class Root {
private String code;
private String descInfo;
private Content content;
public void setCode(String code) {
this.code = code;
}
public String getCode() {
return this.code;
}
public void setDescInfo(String descInfo) {
this.descInfo = descInfo;
}
public String getDescInfo() {
return this.descInfo;
}
public void setContent(Content content) {
this.content = content;
}
public Content getContent() {
return this.content;
}
}
public class Cw {
private String w;
private String wp;
private String wc;
public void setW(String w) {
this.w = w;
}
public String getW() {
return this.w;
}
public void setWp(String wp) {
this.wp = wp;
}
public String getWp() {
return this.wp;
}
public void setWc(String wc) {
this.wc = wc;
}
public String getWc() {
return this.wc;
}
}
public class Ws {
private List<Cw> cw;
private int wb;
private int we;
public void setCw(List<Cw> cw) {
this.cw = cw;
}
public List<Cw> getCw() {
return this.cw;
}
public void setWb(int wb) {
this.wb = wb;
}
public int getWb() {
return this.wb;
}
public void setWe(int we) {
this.we = we;
}
public int getWe() {
return this.we;
}
}
public class Rt {
private List<Ws> ws;
public void setWs(List<Ws> ws) {
this.ws = ws;
}
public List<Ws> getWs() {
return this.ws;
}
}
public class St {
private String sc;
private String pa;
private List<Rt> rt;
private String bg;
private String rl;
private String ed;
public void setSc(String sc) {
this.sc = sc;
}
public String getSc() {
return this.sc;
}
public void setPa(String pa) {
this.pa = pa;
}
public String getPa() {
return this.pa;
}
public void setRt(List<Rt> rt) {
this.rt = rt;
}
public List<Rt> getRt() {
return this.rt;
}
public void setBg(String bg) {
this.bg = bg;
}
public String getBg() {
return this.bg;
}
public void setRl(String rl) {
this.rl = rl;
}
public String getRl() {
return this.rl;
}
public void setEd(String ed) {
this.ed = ed;
}
public String getEd() {
return this.ed;
}
}
public class STRoot {
private St st;
public void setSt(St st) {
this.st = st;
}
public St getSt() {
return this.st;
}
}
}
用到回调的地方
adapter.setiChangeWord(filePath -> {
setMessage(getString(R.string.voice_transcription_in_progress));
XunfeiRequest xunfeiRequest= null;
try {
String filePathUpload=FileUtil.getSDPath(App.getInstance(),filePath);
xunfeiRequest = new XunfeiRequest(filePathUpload);
xunfeiRequest.setiXunfeiRequest(new XunfeiRequest.IXunfeiRequest() {
@Override
public void getXunfeiResult(String result,int failType) {
dismissProgressDialog();
String msg="失败";
String tip=getRsString(R.string.error_tip);
if(!"".equals(result)){
msg=result;
tip=getRsString(R.string.hint);
}else if(failType==1){
msg="音频上传失败";
}else if(failType==2){
msg="音频转码失败";
}else if(failType==3){
msg="音频识别失败";
}else if(failType==4){
msg="音频时长超限";
}else if(failType==5){
msg="音频校验失败";
}else if(failType==6){
msg="失败,是静音文件";
}else if(failType==7){
msg="翻译失败";
}
new XPopup.Builder(VoiceRecordingActivity.this).asConfirm(tip, msg,
() -> {
}).show();
}
});
} catch (Exception e) {
e.printStackTrace();
dismissProgressDialog();
ToastUtils.show("转码失败");
}
});