SpringBoot项目接入阿里云通义大模型实现语音转文字

对接这个语音转文字主要遇到的一个问题就是文件转换, 前端一般传过来的时mp3文件, 而它需要的文件类型是wav, 使用java自带的一些转文件依赖文件会受损, 所以就用了一个ffmpeg, 还是用现成的好, 转了就能用哈哈.

 可以先看看官网的参考API
Paraformer实时语音识别Java API_大模型服务平台百炼(Model Studio)-阿里云帮助中心

前提条件一定要看, 先把要用到的东西准备好.

另外说一下配置API-KEY到环境变量, 这个就看自己了, 你能直接写到.apikey()中, 也能放到yml文件中, 也可以放环境变量, 这个都可以.

以下是逻辑代码, 注释尽量写的很详细了.

这个代码块中的convertMp3ToWav(mp3Path,wavPath)方法我写到下边另外一个代码块了, 这两个方法在一个类中, 如果要看包引用就看第一个代码块的import就好.

import cn.dev33.satoken.stp.StpUtil;
import com.alibaba.dashscope.audio.asr.recognition.Recognition;
import com.alibaba.dashscope.audio.asr.recognition.RecognitionParam;
import com.alibaba.dashscope.exception.NoApiKeyException;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import org.jbase.common.utils.ResultBean;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

@RestController
@RequestMapping("/obj")
public class UploadImageRest {

    //临时存放mp3文件的文件夹
    private final String MP3_UPLOAD_DIR = "C:\\Users\\Administrator\\Desktop\\yinpin\\mp3\\";

    //临时存放wav文件的文件夹
    private final String WAV_UPLOAD_DIR = "C:\\Users\\Administrator\\Desktop\\yinpin\\wav\\";

    @PostMapping("voiceToText")
    public ResultBean voiceToText(@RequestParam("file") MultipartFile file)throws NoApiKeyException, InterruptedException {
        // 检查文件是否为空
        if (file.isEmpty()) {
            return ResultBean.fireFail().setMsg("文件不能为空");
        }

        try {
            // 创建mp3上传目录(如果不存在)
            File uploadDir = new File(MP3_UPLOAD_DIR);
            if (!uploadDir.exists()) {
                uploadDir.mkdirs();
            }

            // 创建wav上传目录(如果不存在)
            File wavUploadDir = new File(WAV_UPLOAD_DIR);
            if (!wavUploadDir.exists()) {
                wavUploadDir.mkdirs();
            }

            //获取了一下当前登录用户的id, 用来拼接文件名, 可忽视
            int mid = StpUtil.getLoginIdAsInt();
            //时间戳
            long l = System.currentTimeMillis();
            //拼接mp3文件名
            String fileName = mid + "_" + l + ".mp3";
            //拼接wav文件名
            String wavFileName = mid + "_" + l + ".wav";
            // 创建两个文件的文件路径
            Path mp3FilePath = Paths.get(MP3_UPLOAD_DIR + fileName);
            Path wavFilePath = Paths.get(WAV_UPLOAD_DIR + wavFileName);

            //上传mp3文件
            Files.write(mp3FilePath, file.getBytes());

            //上传成功之后调用转换文件格式的方法创建wav文件, 该方法在下边, 可以看详情
            convertMp3ToWav(mp3FilePath.toString(),wavFilePath.toString());

            //此时wav文件就可以使用了, 符合了阿里云的格式要求, 开始转文字
            //获取文件
            File audioFile = new File(wavFilePath.toString());

            //文件是否存在
            if (!audioFile.exists() || !audioFile.isFile()) {
                System.out.println("音频文件不存在或路径无效: " + wavFilePath.toString());
                System.exit(1);
            }

            // 识别参数
            RecognitionParam param = RecognitionParam.builder()
                    //模型选择, 在阿里云广场挑选合适的模型
                    .model("paraformer-realtime-v2")
                    //传入的文件格式, 我们转成了wav格式, 就使用wav
                    .format("wav") // 可选格式: pcm, wav, opus, speex, aac, amr
                    //采样率这个模型支持16000及以上, 我们在转文件格式时也设置的16000,所以直接设置16000就可以
                    .sampleRate(16000) // 8000 或 16000
                    //应该是识别语言, 看需求吧, 可以参考官网参数
                    .parameter("language_hints", new String[]{"zh", "en"})
                    //API-KEY 可以写到配置文件中, 这里我就直接填写了
                    .apiKey("sk-50bba6b3f5874a0aab22031e2dcbc978")
                    .build();

            Recognition recognizer = new Recognition();
            System.out.println("正在处理文件: " + wavFilePath.toString());

            // 开始识别
            String result = recognizer.call(param, audioFile);

            // 解析并输出文本
            Gson gson = new GsonBuilder().setPrettyPrinting().create();
            JsonObject jsonObject = gson.fromJson(result, JsonObject.class);
            //创建一个接收结果的str
            StringBuilder str = new StringBuilder();
            if (jsonObject.has("sentences")) {
                System.out.println("\n识别文本:");
                for (JsonElement sent : jsonObject.get("sentences").getAsJsonArray()) {
                    JsonObject sentObj = sent.getAsJsonObject();
                    //将结果放入str
                    str.append(sentObj.get("text").getAsString());
                }
                System.out.println(str.toString());
            } else {
                System.out.println("未找到识别文本");
            }

            //在识别成功后将两个文件夹的文件删除, 也可以删除, 反正没啥用, 一次性的文件
            // 构建文件路径
            File mp3 = mp3FilePath.toFile();
            File wav = wavFilePath.toFile();
            mp3.delete();
            wav.delete();
            //将结果返回  记的改为你自己项目的结果封装类
            return ResultBean.fireSuccess().setMsg(str.toString());
            //System.exit(0);
        } catch (IOException e) {
            e.printStackTrace();
            return ResultBean.fireFail().setMsg("文件失败");
        }
    }

    
}

接下来说convertMp3ToWav(mp3Path,wavPath)方法, 该方法就是通过ffmpeg将mp3转为wav, 但是在使用之前需要下载ffmpeg, 首先找到它的官网: Download FFmpeg        有Linux, Win和Mac, 我用的是Win的, 直接下载就行, 免费的, 我就不贴压缩包了.
下载下来之后解压到目标文件夹, 然后将bin目录放入到环境变量中, 还有重要的一点就是重启电脑, 不重启电脑在代码中使用指令会报错 :"Cannot run program “ffmpeg“: CreateProcess error=2, 系统找不到指定的文件。"

可以参考文章文件上传遇到IO异常——解决Cannot run program “ffmpeg“: CreateProcess error=2, 系统找不到指定的文件。_cannot run program "ffmpeg": createprocess error=2-CSDN博客

这些都弄好之后就可以直接调该方法了 

private void convertMp3ToWav(String mp3FilePath, String wavFilePath) {

        // 使用ProcessBuilder调用ffmpeg命令,设置采样率为16000
        ProcessBuilder processBuilder = new ProcessBuilder(
                "ffmpeg",
                "-i", mp3FilePath,
                "-ar", "16000",   // 设置采样率为16000Hz
                wavFilePath
        );

        processBuilder.redirectErrorStream(true);  // 合并错误输出

        try {
            // 启动进程执行命令
            Process process = processBuilder.start();

            // 等待进程执行完成
            int exitCode = process.waitFor();

            if (exitCode == 0) {
                System.out.println("转换成功!");
            } else {
                System.out.println("转换失败!退出代码:" + exitCode);
            }
        } catch (IOException | InterruptedException e) {
            e.printStackTrace();
        }
    }

最后还有一点可能遇到的问题, 就是请求被阻塞, 会一直在等待, 原因就是convertMp3ToWav()方法中实际是在发送指令

ffmpeg -i "C:\Users\Administrator\Desktop\yinpin\mp3\aaaa.mp3" -ar 16000 "C:\Users\Administrator\Desktop\yinpin\wav\aaaa.wav"

而调用这个指令时, 如果要转换的文件比如"C:\Users\Administrator\Desktop\yinpin\wav\aaaa.wav"已经存在了, 那么他会询问是否覆盖源文件, N/Y, 需要再输入一下Y来执行下一步, 这是我在测试的时候发现的, 正常来说上边的代码不会出现这个问题, 因为文件名都是随机的, 而且文件在使用完毕之后会删除掉. 如果想保险起见可以在店指令时附加-y参数, 就是总是选择是就好了, 就像这样

// 使用ProcessBuilder调用ffmpeg命令,设置采样率为16000
        ProcessBuilder processBuilder = new ProcessBuilder(
                "ffmpeg",
                "-y",    //在此处添加-y参数
                "-i", mp3FilePath,
                "-ar", "16000",   // 设置采样率为16000Hz
                wavFilePath
        );

不过我没这样试过, 不知道能不能行得通, 但是原因肯定是对的, 如果不行可以搜一下其他方法.

好了, 现在就可以调接口了.

大家觉得哪里可以优化或者有问题可以告诉我, 我是小白, 错误可以让我学到更多东西.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值