JAVA调用腾讯云API-实现语音识别(ASR)(二)

 本章分享调用腾讯云API文档,实现语音合成的技术。

package com.example.combat.controller;

import com.example.combat.service.ASRService;
import com.example.combat.asrutils.R;
import com.example.combat.asrutils.param.CreateRecTask;
import com.example.combat.asrutils.param.SentenceRecognition;
import com.example.combat.afsutils.Base64ConvertUtils;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

/**
 * @description:
 * @author: zhucj
 * @date: 2019-11-25 9:30
 */
@RestController
@RequestMapping("/afs")
public class ASRControllerl {

    @Autowired
    private ASRService asrService;

    @ApiOperation(value = "一句话语音识别,60秒时间")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "sourceType",value = "语音数据来源。0:语音 URL;1:语音数据(post body)",required = true,dataType = "Integer"),
            @ApiImplicitParam(name = "url",value = "语音 URL,公网可下载。当 SourceType 值为 0(语音 URL上传) 时须填写该字段",dataType = "String"),
            @ApiImplicitParam(name = "file",value ="语音数据,当SourceType 值为1(本地语音数据上传)时必须填写",dataType = "MultipartFile"),
    })
    @PostMapping(value = "sentence")
    public R sentenceRecognition(@RequestParam(value = "sourceType") Integer sourceType,
                                 @RequestParam(value = "file",required = false)MultipartFile file,
                                 @RequestParam(value = "url",required = false) String url){
        return asrService.sentenceRecognition(SentenceRecognition
                .builder()
                .sourceType(sourceType)
                .voiceFormat(file==null?url.substring(url.length()-3,url.length()):file.getOriginalFilename().substring(file.getOriginalFilename().length()-3,file.getOriginalFilename().length()))
                .dataLen(file==null?null:Integer.valueOf(String.valueOf(file.getSize())))
                .data(file==null?null: Base64ConvertUtils.getImageStr(file))
                .url(url==null?null:url)
                .build());
    }


    @ApiOperation(value = "录音文件识别")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "sourceType",value = "语音数据来源。0:语音 URL;1:语音数据(post body)",required = true,dataType = "Integer"),
            @ApiImplicitParam(name = "url",value = "语音 URL,公网可下载。当 SourceType 值为 0(语音 URL上传) 时须填写该字段",dataType = "String"),
            @ApiImplicitParam(name = "file",value ="语音数据,当SourceType 值为1(本地语音数据上传)时必须填写",dataType = "MultipartFile"),
    })
    @PostMapping(value = "createRecTask")
    public R createRecTask(@RequestParam(value = "sourceType") Integer sourceType,
                                 @RequestParam(value = "file",required = false)MultipartFile file,
                                 @RequestParam(value = "url",required = false) String url){

        return asrService.createRecTask(CreateRecTask
                .builder()
                .sourceType(sourceType)
                .dataLen(file==null?null:Integer.valueOf(String.valueOf(file.getSize())))
                .data(file==null?null: Base64ConvertUtils.getImageStr(file))
                .url(url==null?null:url)
                .build());
    }
}
package com.example.combat.service;

import com.example.combat.asrutils.R;
import com.example.combat.asrutils.param.CreateRecTask;
import com.example.combat.asrutils.param.SentenceRecognition;

/**
 * @description: 语音识别接口
 * @author: zhucj
 * @date: 2019-11-25 9:23
 */
public interface ASRService {


    /**
     * 一句话识别接口
     * @param param
     * @return
     */
    R sentenceRecognition(SentenceRecognition param);

    /**
     * 录音文件识别
     * @param createRecTask
     * @return
     */
    R createRecTask(CreateRecTask createRecTask);
}
package com.example.combat.service.Impl;

import com.example.combat.service.ASRService;
import com.example.combat.asrutils.ASRUtil;
import com.example.combat.asrutils.R;
import com.example.combat.asrutils.param.CreateRecTask;
import com.example.combat.asrutils.param.SentenceRecognition;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * @description: 语音识别实现类
 * @author: zhucj
 * @date: 2019-11-25 9:28
 */
@Service
public class ASRServiceImpl implements ASRService {

    @Autowired
    private ASRUtil asrUtil;


    @Override
    public R sentenceRecognition(SentenceRecognition param) {
        return asrUtil.sentenceRecognition(param);
    }

    @Override
    public R createRecTask(CreateRecTask createRecTask) {
        return asrUtil.createRecTask(createRecTask);
    }
}
package com.example.combat.asrutils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.example.combat.config.constant.ContentTypeEnum;
import com.example.combat.config.constant.HttpMethodEnum;
import com.example.combat.config.constant.SignMenodEnum;
import com.example.combat.asrutils.param.*;
import com.example.combat.afsutils.HttpUtil;
import com.example.combat.afsutils.SignUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.util.*;

/**
 * @description: 语音识别工具类
 * @author: zhucj
 * @date: 2019-11-23 15:30
 */
@Component
@Slf4j
public class ASRUtil {

    @Value("${tencent.secretId}")
    private String sercretId;

    @Value("${tencent.secretKey}")
    private String sercretKey;



    /**
     * 一句话识别
     * @param param
     * @return
     */
    public R sentenceRecognition(SentenceRecognition param){
        //获取公共请求参数
        TreeMap treeMap = createPublicMap("SentenceRecognition", "2019-06-14");
        HashMap hashMap = new HashMap<>();
        hashMap.put("ProjectId",0);
        hashMap.put("SubServiceType",2);
        hashMap.put("EngSerViceType","8k");
        hashMap.put("SourceType",param.getSourceType());
        verifyVoiceFormat(param.getVoiceFormat());
        hashMap.put("VoiceFormat",param.getVoiceFormat());
        hashMap.put("UsrAudioKey",IDUtil.createIdbyUUID());
        if (Objects.equals(0,param.getSourceType())){
            if (StringUtils.isEmpty(param.getUrl())){
                throw new ASRRuntimeException(SystemConstants.PARAM_INCORRECT_CODE,"传入语音Url类型时,传入的url不能为空");
            }
            //如果是语音Url,只需要传Url
            hashMap.put("Url",param.getUrl());
        }else if (Objects.equals(1,param.getSourceType())){
            if (StringUtils.isEmpty(param.getData()) ||StringUtils.isEmpty(param.getDataLen()) ){
                throw new ASRRuntimeException(SystemConstants.PARAM_INCORRECT_CODE,"传入语音数据类型时,传入的语音数据和长度不能为空");
            }
            if(param.getDataLen()>614400){ throw new ASRRuntimeException(SystemConstants.PARAM_INCORRECT_CODE,"传入的音频文件不能超过600kb");}
            hashMap.put("Data",param.getData());
            hashMap.put("DataLen",param.getDataLen());
        }else {
            throw new ASRRuntimeException(SystemConstants.PARAM_INCORRECT_CODE,"语音数据来源,传入的类型错误");
        }
        //签名,公共参数不需要放到body中
        String sign = null;
        try {
            sign = SignUtils.sign(treeMap, HttpMethodEnum.POST, SignMenodEnum.TC3_HMAC_SHA256, JSON.toJSONString(hashMap)
                    , SentenceRecognitionApi.SENTENCE_RECOGNITION, sercretKey, ContentTypeEnum.JSON);
        } catch (Exception e) {
            log.error("签名异常:{}",e.getMessage());
            return R.error("签名异常").setCode(SystemConstants.SERVER_ERROR_CODE);
        }
        try {
            String respJson = HttpUtil.httpPost(SentenceRecognitionApi.SENTENCE_RECOGNITION, JSON.parseObject(sign,Map.class),hashMap);
            JSONObject jsonObject = JSON.parseObject(respJson);
            String response = jsonObject.getString("Response");
            JSONObject error =(JSONObject) JSON.parseObject(response).get("Error");
            if (Objects.nonNull(error)){
                return R.error(String.valueOf(error.get("Message"))).setCode(SystemConstants.SERVER_ERROR_CODE);
            }else {
                SentenceResponse sentenceResponse = JSON.parseObject(response, SentenceResponse.class);
                return R.ok(sentenceResponse.getResult()).setCode(SystemConstants.SUCCESS_CODE);
            }

        } catch (Exception e) {
            log.error("语音识别失败:{}",e.getMessage());
            return R.error("语音识别失败").setCode(SystemConstants.SERVER_ERROR_CODE);
        }

    }

    /**
     * 录音文件识别
     * @param createRecTask
     * @return
     */
    public R createRecTask(CreateRecTask createRecTask){
        TreeMap treeMap = createPublicMap("CreateRecTask", "2019-06-14");
        HashMap hashMap = new HashMap();
        hashMap.put("EngineModelType","8k_0");
        hashMap.put("ChannelNum",1);
        hashMap.put("ResTextFormat",0);
        hashMap.put("SourceType",createRecTask.getSourceType());
        if (Objects.equals(createRecTask.getSourceType(),0)){
            hashMap.put("Url",createRecTask.getUrl());
        }else if (Objects.equals(createRecTask.getSourceType(),1)){
            hashMap.put("Data",createRecTask.getData());
            if (createRecTask.getDataLen()>5*1024*1024){
                throw new ASRRuntimeException(SystemConstants.PARAM_INCORRECT_CODE,"录音文件不能超过5MB");
            }
            hashMap.put("DataLen",createRecTask.getDataLen());
        }
        //签名,公共参数不需要放到body中
        String sign = null;
        try {
            sign = SignUtils.sign(treeMap, HttpMethodEnum.POST, SignMenodEnum.TC3_HMAC_SHA256, JSON.toJSONString(hashMap)
                    , SentenceRecognitionApi.SENTENCE_RECOGNITION, sercretKey, ContentTypeEnum.JSON);
        } catch (Exception e) {
            log.error("签名异常:{}",e.getMessage());
            return R.error("签名异常").setCode(SystemConstants.SERVER_ERROR_CODE);
        }
        try {
            String respJson = HttpUtil.httpPost(SentenceRecognitionApi.SENTENCE_RECOGNITION, JSON.parseObject(sign,Map.class),hashMap);
            JSONObject jsonObject = JSON.parseObject(respJson);
            String response = jsonObject.getString("Response");
            JSONObject error =(JSONObject) JSON.parseObject(response).get("Error");
            if (Objects.nonNull(error)){
                return R.error(String.valueOf(error.get("Message"))).setCode(SystemConstants.SERVER_ERROR_CODE);
            }else {
                JSONObject data =(JSONObject) JSON.parseObject(response).get("Data");
                String taskId =String.valueOf(data.get("TaskId"));
                //通过TaskId查询识别内容
                return describeTaskStatus(taskId);
            }

        } catch (Exception e) {
            log.error("语音识别失败:{}",e.getMessage());
            return R.error("语音识别失败").setCode(SystemConstants.SERVER_ERROR_CODE);
        }
    }


    /**
     * 通过任务ID查询识别结果
     * @param taskId
     * @return
     */
    public R describeTaskStatus(String taskId){
        TreeMap treeMap = createPublicMap("DescribeTaskStatus", "2019-06-14");
        HashMap hashMap = new HashMap<>();
        hashMap.put("TaskId",Integer.valueOf(taskId));
        //签名,公共参数不需要放到body中
        String sign = null;
        try {
            sign = SignUtils.sign(treeMap, HttpMethodEnum.POST, SignMenodEnum.TC3_HMAC_SHA256, JSON.toJSONString(hashMap)
                    , SentenceRecognitionApi.SENTENCE_RECOGNITION, sercretKey, ContentTypeEnum.JSON);
        } catch (Exception e) {
            log.error("签名异常:{}",e.getMessage());
            return R.error("签名异常").setCode(SystemConstants.SERVER_ERROR_CODE);
        }
        try {
            String respJson = HttpUtil.httpPost(SentenceRecognitionApi.SENTENCE_RECOGNITION, JSON.parseObject(sign,Map.class),hashMap);
            JSONObject jsonObject = JSON.parseObject(respJson);
            String response = jsonObject.getString("Response");
            CreateRecTaskResponse createRecTaskResponse= JSON.parseObject(response, CreateRecTaskResponse.class);
            Data data = createRecTaskResponse.getData();
            if (Objects.equals(data.getStatus(),0)){
               return describeTaskStatus(taskId);
            }else if (Objects.equals(data.getStatus(),1)){
                return describeTaskStatus(taskId);
            }else if (Objects.equals(data.getStatus(),2)){
                return R.ok(data.getResult()).setCode(SystemConstants.SUCCESS_CODE);
            }else {
                return R.error(data.getErrorMsg()).setCode(SystemConstants.SERVER_ERROR_CODE);
            }
        } catch (Exception e) {
            log.error("任务ID查询识别失败:{}",e.getMessage());
            return R.error("任务ID查询识别失败").setCode(SystemConstants.SERVER_ERROR_CODE);
        }
    }
    /**
     * 封装请求公共参数
     * @param action
     * @param version
     * @return
     */
    public TreeMap createPublicMap(String action, String version){

        TreeMap treeMap = new TreeMap<>();
        treeMap.put("Action",action);
        treeMap.put("Version",version);
        treeMap.put("Timestamp",getCurrentTimestamp());
        treeMap.put("Nonce",new Random().nextInt(Integer.MAX_VALUE));
        treeMap.put("SecretId",sercretId);
        return treeMap;
    }

    /**
     * 获取当前时间戳,单位秒
     * @return
     */
    public static long getCurrentTimestamp() {
        return System.currentTimeMillis()/1000;
    }


    public void verifyVoiceFormat(String type){

        if (Objects.equals("mp3",type) || Objects.equals("wav",type)){
            return;
        }else {
            throw new ASRRuntimeException(SystemConstants.PARAM_INCORRECT_CODE,"传入识别音频的音频格式错误");
        }
    }
}
package com.example.combat.asrutils;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.UUID;

/**
 * 名称:IDUtil 
* 描述:ID 生成工具类
* *
@author zhucj * @version 1.0 * @since 1.0.0 */ public class IDUtil { /** * 主要功能:生成流水号 yyyyMMddHHmmssSSS + 3位随机数 * 注意事项:无 * * @return 流水号 */ public static String createIdByDate() { // 精确到毫秒 SimpleDateFormat fmt = new SimpleDateFormat("(yyyyMMddHHmmssSSS)"); String suffix = fmt.format(new Date()); suffix = suffix + "-" + Math.round((Math.random() * 100000)); return suffix; } /** * 主要功能:生成uuid * 注意事项:无 * * @return uuid 32 位 */ public static String createIdbyUUID() { return UUID.randomUUID().toString().replaceAll("-", ""); } }
package com.example.combat.asrutils;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.ToString;

import java.io.Serializable;

/**
 * 返回类型
 * @author choleece
 * @date 2018/9/27
 */
@ApiModel
@ToString
public class R implements Serializable {

    private static final long serialVersionUID = -6287952131441663819L;

    /**
     * 编码
     */
    @ApiModelProperty(value = "响应码", example = "200")
    private int code = 200;

    /**
     * 成功标志
     */
    @ApiModelProperty(value = "成功标志", example = "true")
    private Boolean success;

    /**
     * 返回消息
     */
    @ApiModelProperty(value = "返回消息说明", example = "操作成功")
    private String msg="操作成功";

    /**
     * 返回数据
     */
    @ApiModelProperty(value = "返回数据")
    private T data;

    /**
     * 创建实例
     * @return
     */
    public static R instance() {
        return new R();
    }

    public int getCode() {
        return code;
    }

    public R setCode(int code) {
        this.code = code;
        return this;
    }

    public Boolean getSuccess() {
        return success;
    }

    public R setSuccess(Boolean success) {
        this.success = success;
        return this;
    }

    public String getMsg() {
        return msg;
    }

    public R setMsg(String msg) {
        this.msg = msg;
        return this;
    }

    public T getData() {
        return data;
    }
    public R setData(T data) {
        this.data = data;
        return this;
    }

    public static R ok() {
        return R.instance().setSuccess(true);
    }

    public static R ok(Object data) {
        return ok().setData(data);
    }

    public static R ok(Object data, String msg) {
        return ok(data).setMsg(msg);
    }

    public static R error() {
        return R.instance().setSuccess(false);
    }

    public static R error(String msg) {
        return error().setMsg(msg);
    }

    /**
     * 无参
     */
    public R() {
    }

    public R(int code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    public R(int code, T data){
        this.code = code;
        this.data = data;
    }

    /**
     * 有全参
     * @param code
     * @param msg
     * @param data
     * @param success
     */
    public R(int code, String msg, T data, Boolean success) {
        this.code = code;
        this.msg = msg;
        this.data = data;
        this.success = success;
    }

    /**
     * 有参
     * @param code
     * @param msg
     * @param data
     */
    public R(int code, String msg, T data) {
        this.code = code;
        this.msg = msg;
        this.data = data;
    }

   
}
package com.example.combat.asrutils.param;

/**
 * @description: 语音识别异常类
 * @author: 朱传捷  80004071
 * @date: 2019-11-23 15:46
 */
public class ASRRuntimeException extends RuntimeException{

    /**
     * 错误码
     */
    private Integer errorCode;
    /**
     * 错误描述
     */
    private String errorMsg;


    public ASRRuntimeException(Integer errorCode, String errorMsg){
        super(errorMsg);
        this.errorCode = errorCode;
        this.errorMsg = errorMsg;
    }

    public Integer getErrorCode() {
        return errorCode;
    }


    public String getErrorMsg() {
        return errorMsg;
    }
}
package com.example.combat.asrutils.param;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @description: 录音文件识别请求参数
 * @author: 朱传捷  80004071
 * @date: 2019-11-25 12:22
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class CreateRecTask {


    /**
     * 语音数据来源。0:语音 URL;1:语音数据(post body)。
     */
    private Integer sourceType;

    /**
     * 回调 URL,用户自行搭建的用于接收识别结果的服务器地址, 长度小于2048字节
     */
    private String CallbackUrl;

    /**
     * 语音的URL地址,需要公网可下载当 SourceType 值为 0 时须填写该字段,为 1 时不需要填写。
     * 注意:请确保录音文件时长在一个小时之内,否则可能识别失败。请保证文件的下载速度,否则可能下载失败。
     */
    private String url;

    /**
     * 语音数据,当SourceType 值为1时必须填写,为0可不写。
     */
    private String data;

    /**
     * 数据长度,当 SourceType 值为1时必须填写,为0可不写(此数据长度为数据未进行base64编码时的数据长度)。
     */
    private Integer dataLen;

}
package com.example.combat.asrutils.param;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @description: 录音识别返回结果
 * @author: 朱传捷  80004071
 * @date: 2019-11-25 14:05
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class CreateRecTaskResponse extends Response {

    private com.example.combat.asrutils.param.Data Data;
}
package com.example.combat.asrutils.param;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.NoArgsConstructor;

/**
 * @description:
 * @author: 朱传捷  80004071
 * @date: 2019-11-25 14:18
 */
@lombok.Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class Data {

    private Integer TaskId;

    private Integer Status;

    private String StatusStr;

    private String Result;

    private String ErrorMsg;
}
package com.example.combat.asrutils.param;

import lombok.Data;

/**
 * @description:
 * @author: 朱传捷  80004071
 * @date: 2019-10-18 15:58
 */
@Data
public class Error {

    private String Code;

    private String Messag;
}
package com.example.combat.asrutils.param;
import lombok.Data;

/**
 * @description: 请求返回公共参数
 * @author: 朱传捷  80004071
 * @date: 2019-10-18 15:56
 */
@Data
public class Response {

    private String RequestId;

    private Error Error;
}
package com.example.combat.asrutils.param;

import lombok.Builder;
import lombok.Data;

import javax.validation.constraints.NotNull;

/**
 * @description: 语音识别实体
 * @author: 朱传捷  80004071
 * @date: 2019-11-23 15:21
 */
@Data
@Builder
public class SentenceRecognition {



    /**
     * 语音数据来源。0:语音 URL;1:语音数据(post body)。
     */
    @NotNull(message = "语音数据来源不能为空")
    private Integer sourceType;

    /**
     * 识别音频的音频格式。mp3、wav。
     */
    @NotNull(message = "识别音频的音频格式不为空")
    private String voiceFormat;

    /**
     * 语音 URL,公网可下载。当 SourceType 值为 0(语音 URL上传) 时须填写该字段,
     * 为 1 时不填;URL 的长度大于 0,小于 2048,需进行urlencode编码。音频时间长度要小于60s。
     */
    private String url;

    /**
     * 语音数据,当SourceType 值为1(本地语音数据上传)时必须填写,当SourceType 值为0(语音 URL上传)可不写。
     * 要使用base64编码(采用python语言时注意读取文件应该为string而不是byte,
     * 以byte格式读取后要decode()。编码后的数据不可带有回车换行符)。音频数据要小于600KB。
     */
    private String data;

    /**
     * 数据长度,单位为字节。当 SourceType 值为1(本地语音数据上传)时必须填写,当 SourceType 值为0
     * (语音 URL上传)可不写(此数据长度为数据未进行base64编码时的数据长度)。
     */
    private Integer dataLen;
}
package com.example.combat.asrutils.param;

/**
 * @description: 语音识别API
 * @author: 朱传捷  80004071
 * @date: 2019-11-23 16:07
 */
public class SentenceRecognitionApi {


    /**
     * 语音识别
     */
    public static final String SENTENCE_RECOGNITION = "https://asr.ap-shenzhen-fsi.tencentcloudapi.com";
}
package com.example.combat.asrutils.param;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @description: 返回响应参数
 * @author: 朱传捷  80004071
 * @date: 2019-11-23 15:32
 */
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class SentenceResponse extends Response {

    /**
     * 识别结果
     */
    private String Result;
}
package com.example.combat.asrutils.param;

/**
 * @ClassName SystemConstants
 * @Description 常量字段
 * @Author YangLei
 * @Date 2019/5/7 11:13
 * @Version 1.0
 **/
public class SystemConstants {
   
    /** 传参不规范,code:400*/
    public static final Integer PARAM_INCORRECT_CODE = 400;

    /** 成功,code:200*/
    public static final Integer SUCCESS_CODE = 200;

    /** 服务内部调用失败,code:500*/
    public static final Integer SERVER_ERROR_CODE = 500;

    /** 登录失效,code:401*/
    public static final Integer AUTH_FAIL_CODE = 401;

    /** 无对应接口权限,code:402*/
    public static final Integer HAVE_NOT_PERMISSION_CODE = 402;

    /** 操作无记录,code:403*/
    public static final Integer NO_RECORD_OPERATION = 403;

    //http请求方式
    public static final String HTTP_METHOD_POST = "POST";
    public static final String HTTP_METHOD_GET = "GET";
    public static final String HTTP_METHOD_PUT = "PUT";
    public static final String HTTP_METHOD_DELETE = "DELETE";

}
#腾讯云服务配置
tencent:
  secretId: *********
  secretKey: ********
                
            io.springfox
            springfox-      swagger2
            2.6.0
        
        
            io.springfox
            springfox-swagger-ui
            2.6.0
        

        
            com.alibaba
            fastjson
            1.2.55
        
        
                             org.apache.httpcomponents
            httpclient
            4.5.6
        
                 
            org.projectlombok
            lombok
            true
        

 

你可能感兴趣的:(JAVA调用腾讯云API-实现语音识别(ASR)(二))