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>