Android调用科大讯飞语音转写 API以及解析踩坑之旅

需求

需要对本地音频文件,调用科大讯飞的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("转码失败");
            }

        });
Java调用科大讯飞语音转写功能需要进行以下几个步骤: 1. 首先,需要获取科大讯飞语音转写API的接入凭证。可以在科大讯飞的官方网站上注册并创建应用,获得AppID、API Key和API Secret。 2. 在Java中引入科大讯飞提供的SDK包。可以通过Maven或手动引入jar包的方式将SDK包添加到Java项目中。 3. 进行SDK的初始化配置。在Java代码中,使用获得的AppID、API Key和API Secret进行初始化配置,以便调用接口。 4. 提供需要转写语音文件。将需要转写语音文件存储到本地或云端,并获取其本地路径或URL地址。 5. 通过调用SDK提供的相关接口,传入语音文件路径或URL地址,以及其他必要的参数(如语音格式、语言等),进行语音转写操作。 6. 处理结果。语音转写接口通常会返回转写结果的回调函数或回调地址,我们需要在回调函数中对转写结果进行处理或在回调地址中获取转写结果。 7. 可选的后续处理。根据需要,可以对转写结果进行进一步处理,如文本分析、语义理解等。 需要注意的是,前述的步骤是一个简单的概述,具体的实现细节还需根据具体的开发环境和项目需要进行调整。可以参考科大讯飞提供的官方文档和示例代码,以及进行必要的调试和优化工作。通过以上步骤,我们可以在Java中成功调用科大讯飞语音转写功能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值