将讯飞 腾讯oss(oss 临时秘钥 + 上传) 联合使用时的踩坑记录

最近有一个需求  服务器上存储了很多纯文本的数据   想将文本转化为语音 并上传到腾讯云 

本项目采用的是springboot开发  部署到多个服务器上

一 . 讯飞踩坑

1.参考开发文档 : https://www.xfyun.cn/doc/tts/online_tts/Java-SDK.html#_2%E3%80%81sdk%E9%9B%86%E6%88%90%E6%8C%87%E5%8D%97

2.考虑到这需要后台跑数据  所以采用的是无声合成

 

 

3.下载开发model 找到该方法 copy使用

踩坑点

1.本项目结构如下  需要使用的位置在第一个红框的模块里面   本地调试时使用了很多次居然一直报 找不到so文件20021

经多次尝试必须将文件放到主项目的最外面才能加载到

 

2.同这个问题 由于上传了服务器之后 打包成jar包 并分到不同的服务上部署 一样会报这个错  查了很多资料 最后采取了比较极端的方法直接把这四个包给拷贝到了 服务器的 usr/bin/  下面才解决了

也可以放到 jre 的lib下

 

3. 跑好模板测试的时候 不小心将 path 定义成了项目路径  导致本地测试的时候将文件路径写到了target 里面 导致 springboot 检查到编译文件变动 而不停的重启...

 private void addVoice(String content, String voiceName, Integer sectionId, Integer num) {
        SpeechSynthesizer speechSynthesizer = SpeechSynthesizer
                .createSynthesizer();
        // 设置发音人
        speechSynthesizer.setParameter(SpeechConstant.VOICE_NAME, voiceName);
        //启用合成音频流事件,不需要时,不用设置此参数
        speechSynthesizer.setParameter(SpeechConstant.TTS_BUFFER_EVENT, "1");
//        System.out.println("路径:" + path + "temporary-" + voiceName +"-" + sectionId + ".pcm");
        String pcmPath;
        //todo 本地跑本地路径  项目里的跑相对路径
        log.info("serverPath :" + serverPath);
//        pcmPath = path + "temporary-" + num + "-" + voiceName + "-" + sectionId + ".pcm";
        //服务器路径
        pcmPath = serverPath + "temporary-" + num + "-" + voiceName + "-" + sectionId + ".pcm";
//        }
        speechSynthesizer.synthesizeToUri(content, pcmPath,
                new Listner());
    }

4.由于此次的要求需要循环生成很多数据 导致开始时直接写了一个循环来测试  由于数据量小 文本字数也就几个字 没有测出一个问题

  讯飞这边只支持同时调用的时候只会以最新的文本来生成 单列的 导致使用实际数据测试的时候 只会生成最后一条  哪怕使用线程了也一样

最后的解决办法就是一次只查询一条数据 , 并等待 使用了线程监听语音生成完后再唤醒查询下一条数据

5. 由于文本字数不确定问题  导致正式使用的时候触发了讯飞的字符限制 引出了新的步骤 分割文本 合并音频  由于没有很多的要求 就只是使用了一个最简单的文件续写功能 代码如下

  /**
     * 合并语音
     *
     * @param outFile 输出路径
     * @param inFiles 输入的文档地址数组
     * @return
     */
    public boolean combine(String outFile, String[] inFiles) {
        File[] files = new File[inFiles.length];
        for (int i = 0; i < files.length; i++) {
            files[i] = new File(inFiles[i]);
        }
        FileInputStream fis = null;
        // 合并其实就是文件的续写,写成true
        FileOutputStream fos = null;
        try {
            fos = new FileOutputStream(outFile, true);
            for (int i = 0; i < files.length; i++) {
                fis = new FileInputStream(files[i]);
                int len = 0;
                for (byte[] buf = new byte[1024 * 1024]; (len = fis.read(buf)) != -1; ) {
                    fos.write(buf, 0, len);
                }
            }
            fis.close();
            fos.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        //语音拼接成功 删除掉合并之前的文件
        for (String inFile : inFiles) {
            File file = new File(inFile);
            file.delete();
        }
        return true;

    }

二.腾讯oss上传

前提  : 由于本项目使用的是腾讯云oss 且对应的桶权限是私写公查的  所有得使用获取临时秘钥 通过临时秘钥获取接口

 参考文档 : https://cloud.tencent.com/document/product/436/14048

https://github.com/tencentyun/qcloud-cos-sts-sdk/tree/master/java

 2.使用临时秘钥上传  参考文档 :  https://cloud.tencent.com/document/product/436/14048#cos-sts-sdk

private String getUrl(String credentialDetail, File file, String path) {
        String url = "";
        // bucket 名需包含 appid
        String bucketName = null;
        ConfigureVo courseNameVo = courseSectionMapper.getConfigure();
        if (null != courseNameVo) {
            bucketName = courseNameVo.getValue();
        }
        if (null != bucketName) {
            System.out.println("path" + path);
        //解析临时秘钥
            CredentialsVo credentials = JSONArray.parseObject(credentialDetail, CredentialsVo.class);
            // 用户基本信息
            // 替换为 STS 接口返回给您的临时 SecretId
            String tmpSecretId = credentials.getTmpSecretId();
            // 替换为 STS 接口返回给您的临时 SecretKey
            String tmpSecretKey = credentials.getTmpSecretKey();
            // 替换为 STS 接口返回给您的临时 Token
            String sessionToken = credentials.getSessionToken();
            // 1 初始化用户身份信息(secretId, secretKey)
            COSCredentials cred = new BasicCOSCredentials(tmpSecretId, tmpSecretKey);
            // 2 设置 bucket 区域,详情请参阅 COS 地域 https://cloud.tencent.com/document/product/436/6224
            ClientConfig clientConfig = new ClientConfig(new Region("ap-chengdu"));
            // 3 生成 cos 客户端
            COSClient cosclient = new COSClient(cred, clientConfig);
            // 上传 object, 建议 20M 以下的文件使用该接口
//            File localFile = transferToFile(file);
            PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, path, file);  //这里得注意 path路径只用是桶里面的文件路径不用拼接其他的
            // 设置 x-cos-security-token header 字段
            ObjectMetadata objectMetadata = new ObjectMetadata();
            objectMetadata.setSecurityToken(sessionToken);
            putObjectRequest.setMetadata(objectMetadata);
            try {
                PutObjectResult putObjectResult = cosclient.putObject(putObjectRequest);
                // 成功:putobjectResult 会返回文件的 etag
                String etag = putObjectResult.getETag();
                //拼接返回路径  https://桶路径.cos.ap-XXX.myqcloud.com/20210728/d27ea8fead82b3a0e916f9283e9330b1.jpg
                url = "https://" + bucketName + ".cos.ap-XXX.myqcloud.com/" + path;     // 这里每个人的都不同
         https://" + bucketName + ".cos.ap-XXX.myqcloud.com/  这一串 等于服务器里面的访问域名 因为我这里有很多不同的桶  所以我这儿同名取为了动态的 
// System.out.println(url); } catch (CosServiceException e) { //失败,抛出 CosServiceException  e.printStackTrace(); } catch (CosClientException e) { //失败,抛出 CosClientException  e.printStackTrace(); } // 关闭客户端  cosclient.shutdown(); // System.out.println("end : " + url); return url; } return null; }

 

posted on 2021-09-22 13:34  好名字被谁用了  阅读(201)  评论(0编辑  收藏  举报

导航