Spring boot 对接 讯飞 实现 文字转语音和语音转文字

1.Controller

package com.ruoyi.inherit.apicontroller;

import com.ruoyi.common.core.web.domain.AjaxResult;
import com.ruoyi.inherit.utils.XfTalkUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.InputStreamResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.*;

@RestController
@RequestMapping("/api/test")
public class TestController {

    @Autowired
    private XfTalkUtil xfTalkUtil;

    /**
     * 文本转语音
     * @param text
     * @param response
     * @return
     */
    @GetMapping(value = "/tts")
    public ResponseEntity tts(String text, HttpServletResponse response)
    {
        File tts = xfTalkUtil.tts(text);
        if (tts.exists()) {
            InputStreamResource resource = null;
            try {
                resource = new InputStreamResource(new FileInputStream(tts));
            } catch (FileNotFoundException e) {
                throw new RuntimeException(e);
            }
            return ResponseEntity.ok()
                    .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + tts.getName() + "\"")
                    .contentType(MediaType.APPLICATION_OCTET_STREAM)
                    .contentLength(tts.length()) // 设置文件大小
                    .body(resource);
        } else {
            return ResponseEntity.notFound().build();
        }
    }

    /**
     * 语音转文字
     * @param file
     * @return
     */
    @GetMapping(value = "/iat")
    public AjaxResult iat(@RequestParam("file") MultipartFile file)
    {
        // 创建一个临时文件
        File tempFile = null;
        try {
            tempFile = File.createTempFile("uploadMp3-", file.getOriginalFilename());
            tempFile.deleteOnExit(); // 确保临时文件在程序退出时被删除

            // 将上传的文件保存到临时文件
            file.transferTo(tempFile);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }


        String iat = xfTalkUtil.iat(tempFile);
        return AjaxResult.success("获取成功",iat);
    }
}
package com.ruoyi.inherit.utils;

import cn.xfyun.api.IatClient;
import cn.xfyun.api.TtsClient;
import cn.xfyun.model.response.TtsResponse;
import cn.xfyun.model.response.iat.IatResponse;
import cn.xfyun.model.response.iat.IatResult;
import cn.xfyun.service.iat.AbstractIatWebSocketListener;
import cn.xfyun.service.tts.AbstractTtsWebSocketListener;
import com.ruoyi.common.core.utils.uuid.UUID;
import okhttp3.Response;
import okhttp3.WebSocket;
import org.springframework.stereotype.Component;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.security.SignatureException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

@Component
public class XfTalkUtil {
    private static final String appId = "dfb";
    private static final String apiKey = "876d6ff";
    private static final String apiSecret = "YmVjM";

    String ffmpegPath = "I:\\ffmpeg-7.1-full_build\\bin\\ffmpeg.exe";
    /**
     * 文本转语音
     * @param text
     * @return
     */
    public File tts(String text){

        UUID uuid = UUID.randomUUID();
        String uuidString = uuid.toString().replace("-", "");

        String tempDir = System.getProperty("java.io.tmpdir");
        File tempFile = null;
        try {
            tempFile = File.createTempFile(uuidString, ".mp3", new File(tempDir));

            tempFile.deleteOnExit();//退出时删除
        } catch (IOException e) {
            throw new RuntimeException(e);
        }


        TtsClient ttsClient = null;
        try {
            ttsClient = new TtsClient.Builder()
                    .signature(appId, apiKey, apiSecret)
                    .build();
        } catch (MalformedURLException e) {
            throw new RuntimeException(e);
        } catch (SignatureException e) {
            throw new RuntimeException(e);
        }

        CountDownLatch latch = new CountDownLatch(1);

        try {
            ttsClient.send(text, new AbstractTtsWebSocketListener(tempFile) {
                @Override
                public void onSuccess(byte[] bytes) {
                    latch.countDown(); // 任务完成,减少计数器
                }

                @Override
                public void onFail(WebSocket webSocket, Throwable throwable, Response response) {
                    System.out.println(throwable.getMessage());
                    latch.countDown(); // 任务完成,减少计数器
                }

                @Override
                public void onBusinessFail(WebSocket webSocket, TtsResponse ttsResponse) {
                    System.out.println(ttsResponse.toString());
                    latch.countDown(); // 任务完成,减少计数器
                }
            });
        }catch (Exception e){
            System.out.println(e.getMessage());
            System.out.println("错误码查询链接:https://www.xfyun.cn/document/error-code");
        }

        try {
            if (!latch.await(60, TimeUnit.SECONDS)) {
                System.err.println("TTS request timed out.");
            }
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }

        return tempFile;
    }

    public String iat(File mp3) {

        //输出文件绝对路径
        String tempDir = System.getProperty("java.io.tmpdir");
        String out=tempDir+mp3.getName()+".pcm";

        try {

            Process process = Runtime.getRuntime().exec(ffmpegPath+" -i "+mp3.getAbsolutePath()+" -ar 16000 -ac 1 -acodec pcm_s16le -f s16le "+out);
            // 等待命令执行完成
            int exitCode = process.waitFor(); // 阻塞当前线程,直到命令执行完成
        } catch (IOException e) {
            throw new RuntimeException(e);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }


        IatClient iatClient = new IatClient.Builder()
                .signature(appId, apiKey, apiSecret)
                .build();

        SimpleDateFormat sdf = new SimpleDateFormat("yyy-MM-dd HH:mm:ss.SSS");
        Date dateBegin = new Date();

        File file = new File(out);
        StringBuffer finalResult = new StringBuffer();

        CountDownLatch latch = new CountDownLatch(1);

        try {
            iatClient.send(file, new AbstractIatWebSocketListener() {
                @Override
                public void onSuccess(WebSocket webSocket, IatResponse iatResponse) {
                    if (iatResponse.getCode() != 0) {
                        System.out.println("code=>" + iatResponse.getCode() + " error=>" + iatResponse.getMessage() + " sid=" + iatResponse.getSid());
                        System.out.println("错误码查询链接:https://www.xfyun.cn/document/error-code");
                        latch.countDown(); // 任务完成,减少计数器
                    }

                    if (iatResponse.getData() != null) {
                        if (iatResponse.getData().getResult() != null) {
                            IatResult.Ws[] wss = iatResponse.getData().getResult().getWs();
                            String text = "";
                            for (IatResult.Ws ws : wss) {
                                IatResult.Cw[] cws = ws.getCw();

                                for (IatResult.Cw cw : cws) {
                                    text += cw.getW();
                                }
                            }

                            try {
                                finalResult.append(text);
                                System.out.println("中间识别结果 ==》" + text);
                            } catch (Exception e) {
                                e.printStackTrace();
                            }
                        }

                        if (iatResponse.getData().getStatus() == 2) {
                            // resp.data.status ==2 说明数据全部返回完毕,可以关闭连接,释放资源
                            System.out.println("session end ");
                            Date dateEnd = new Date();
                            System.out.println(sdf.format(dateBegin) + "开始");
                            System.out.println(sdf.format(dateEnd) + "结束");
                            System.out.println("耗时:" + (dateEnd.getTime() - dateBegin.getTime()) + "ms");
                            System.out.println("最终识别结果 ==》" + finalResult.toString());
                            System.out.println("本次识别sid ==》" + iatResponse.getSid());
                            iatClient.closeWebsocket();

                            latch.countDown(); // 任务完成,减少计数器
                        } else {
                            // 根据返回的数据处理
                            //System.out.println(StringUtils.gson.toJson(iatResponse));
                        }
                    }
                }

                @Override
                public void onFail(WebSocket webSocket, Throwable t, Response response) {
                    latch.countDown(); // 任务完成,减少计数器
                }
            });
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        } catch (MalformedURLException e) {
            throw new RuntimeException(e);
        } catch (SignatureException e) {
            throw new RuntimeException(e);
        }

        try {
            if (!latch.await(60, TimeUnit.SECONDS)) {
                System.err.println("TTS request timed out.");
            }
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }

        return finalResult.toString();
    }
}

uniapp 录制mp3文件,作为参数获取音频文件的文本内容

<template>
  <view class="container">
    <button @click="startRecording">开始录音</button>
    <button @click="stopRecording">停止录音</button>
    <text v-if="audioPath">录音文件路径:{{ audioPath }}</text>
  </view>
</template>

<script>
export default {
  data() {
    return {
      audioPath: '', // 录音文件路径
      recorderManager: uni.getRecorderManager() // 录音管理器
    };
  },
  onReady() {
  },
  methods: {
    startRecording() {
      // this.recorderManager = uni.getRecorderManager();
      this.recorderManager.start({
        format: 'wav', // 指定录音格式为PCM
        sampleRate: 16000, // 采样率
        encodeBitRate: 16000 // 编码码率
      });

      this.recorderManager.onStart(() => {
        console.log('录音开始');
      });

      this.recorderManager.onError((err) => {
        console.error('录音出错', err);
      });
    },
    stopRecording() {
		console.log(this.recorderManager);
      this.recorderManager.stop();
      this.recorderManager.onStop((res) => {
        console.log('录音结束,文件路径:', res.tempFilePath);
        this.audioPath = res.tempFilePath;
		 uni.saveFile({
		      tempFilePath: res.tempFilePath,
		      success: function (res) {
		        // var savedFilePath = res.savedFilePath;
		      }
		    });
      });
    }
  }
};
</script>

<style>
.container {
  display: flex;
  flex-direction: column;
  align-items: center;
  margin-top: 20px;
}
button {
  margin: 10px 0;
}
</style>

Spring Boot中使用文字语音功能,可以通过调用语音合成API实现。下面是一个简单的示例代码: 首先,你需要在开放平台注册账号并创建一个应用,获取到相应的AppIDAPI Key。 然后,在Spring Boot项目的配置文件中添加语音合成的相关配置: ```yaml xfyun: app-id: YOUR_APP_ID api-key: YOUR_API_KEY ``` 接下来,创建一个SpeechUtil工具类,用于调用语音合成API: ```java import com.iflytek.cloud.speech.*; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; @Component public class SpeechUtil { @Value("${xfyun.app-id}") private String appId; @Value("${xfyun.api-key}") private String apiKey; public void textToSpeech(String text, String filePath) { SpeechUtility.createUtility(SpeechConstant.APPID + "=" + appId); SpeechSynthesizer synthesizer = SpeechSynthesizer.createSynthesizer(); synthesizer.setParameter(SpeechConstant.VOICE_NAME, "xiaoyan"); synthesizer.setParameter(SpeechConstant.SPEED, "50"); synthesizer.setParameter(SpeechConstant.VOLUME, "80"); synthesizer.setParameter(SpeechConstant.ENGINE_TYPE, SpeechConstant.TYPE_CLOUD); synthesizer.setParameter(SpeechConstant.TTS_AUDIO_PATH, filePath); synthesizer.startSpeaking(text, null); synthesizer.destroy(); } } ``` 在需要调用文字语音功能的地方,注入SpeechUtil并调用textToSpeech方法即可: ```java @Autowired private SpeechUtil speechUtil; public void convertTextToSpeech(String text, String filePath) { speechUtil.textToSpeech(text, filePath); } ``` 以上代码仅为示例,实际使用时需要根据语音合成API的文档进行相应的参数配置异常处理。 希望对你有所帮助!如有更多问题,请继续提问。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值