TTS 返回语音优化
This commit is contained in:
@@ -144,11 +144,6 @@ public class ChatWebSocketHandler {
|
|||||||
log.info("3、开始进行AI回答时间:{}",System.currentTimeMillis()/1000);
|
log.info("3、开始进行AI回答时间:{}",System.currentTimeMillis()/1000);
|
||||||
//持续返回数据流给客户端
|
//持续返回数据流给客户端
|
||||||
try {
|
try {
|
||||||
File inputFile = new File(resultPathUrl);
|
|
||||||
File outputFile = new File(resultPathUrl);
|
|
||||||
// 设置去除尾部的秒数
|
|
||||||
float removeSeconds = 0.25f; // 去除最后5秒
|
|
||||||
trimEndByTime(inputFile, outputFile, removeSeconds);
|
|
||||||
//文件转换成文件流
|
//文件转换成文件流
|
||||||
ByteBuffer outByteBuffer = convertFileToByteBuffer(resultPathUrl);
|
ByteBuffer outByteBuffer = convertFileToByteBuffer(resultPathUrl);
|
||||||
//发送文件流数据
|
//发送文件流数据
|
||||||
@@ -410,44 +405,5 @@ public class ChatWebSocketHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// 裁剪音频文件,去除最后多少秒
|
|
||||||
public void trimEndByTime(File inputFile, File outputFile, float removeSeconds) {
|
|
||||||
try {
|
|
||||||
// 获取音频输入流
|
|
||||||
AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(inputFile);
|
|
||||||
AudioFormat format = audioInputStream.getFormat();
|
|
||||||
|
|
||||||
// 获取音频文件的总帧数
|
|
||||||
long totalFrames = audioInputStream.getFrameLength();
|
|
||||||
|
|
||||||
// 计算音频文件的总时长(秒)
|
|
||||||
float totalDuration = totalFrames / format.getSampleRate();
|
|
||||||
|
|
||||||
// 计算新的结束位置(去除指定的时间后)
|
|
||||||
long newEndFrame = (long) ((totalDuration - removeSeconds) * format.getSampleRate());
|
|
||||||
|
|
||||||
// 确保裁剪的结束帧在合理范围内
|
|
||||||
if (newEndFrame < 0) {
|
|
||||||
System.out.println("去除的时间超过了音频的总时长");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 创建一个新的输入流,裁剪音频数据
|
|
||||||
AudioInputStream trimmedStream = new AudioInputStream(
|
|
||||||
audioInputStream,
|
|
||||||
format,
|
|
||||||
newEndFrame
|
|
||||||
);
|
|
||||||
|
|
||||||
// 创建新的文件并保存裁剪后的音频
|
|
||||||
AudioSystem.write(trimmedStream, AudioFileFormat.Type.WAVE, outputFile);
|
|
||||||
System.out.println("裁剪后的音频已保存到: " + outputFile.getAbsolutePath());
|
|
||||||
|
|
||||||
audioInputStream.close();
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -169,6 +169,7 @@
|
|||||||
<groupId>org.java-websocket</groupId>
|
<groupId>org.java-websocket</groupId>
|
||||||
<artifactId>Java-WebSocket</artifactId>
|
<artifactId>Java-WebSocket</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.tomcat.embed</groupId>
|
<groupId>org.apache.tomcat.embed</groupId>
|
||||||
<artifactId>tomcat-embed-websocket</artifactId>
|
<artifactId>tomcat-embed-websocket</artifactId>
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package com.vetti.common.ai.gpt;
|
package com.vetti.common.ai.gpt;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
import cn.hutool.json.JSONObject;
|
import cn.hutool.json.JSONObject;
|
||||||
import cn.hutool.json.JSONUtil;
|
import cn.hutool.json.JSONUtil;
|
||||||
import com.vetti.common.ai.gpt.service.OpenAiStreamListenerService;
|
import com.vetti.common.ai.gpt.service.OpenAiStreamListenerService;
|
||||||
@@ -9,7 +10,9 @@ import org.springframework.stereotype.Component;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -30,6 +33,12 @@ public class OpenAiStreamClient {
|
|||||||
@Value("${chatGpt.role}")
|
@Value("${chatGpt.role}")
|
||||||
private String role;
|
private String role;
|
||||||
|
|
||||||
|
// 定义作为分割点的标点符号集合
|
||||||
|
private final Set<Character> punctuationSet = new HashSet<>() {{
|
||||||
|
add('。'); add('?'); add('!'); add(';'); // 中文标点
|
||||||
|
add('.'); add('?'); add('!'); add(';'); // 英文标点
|
||||||
|
}};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 发送流式请求
|
* 发送流式请求
|
||||||
*
|
*
|
||||||
@@ -42,6 +51,9 @@ public class OpenAiStreamClient {
|
|||||||
.readTimeout(60, TimeUnit.SECONDS)
|
.readTimeout(60, TimeUnit.SECONDS)
|
||||||
.writeTimeout(30, TimeUnit.SECONDS)
|
.writeTimeout(30, TimeUnit.SECONDS)
|
||||||
.build();
|
.build();
|
||||||
|
// 文本缓冲区
|
||||||
|
StringBuffer bufferStr = new StringBuffer();
|
||||||
|
|
||||||
// 构建请求参数
|
// 构建请求参数
|
||||||
Map<String, Object> requestBody = new HashMap<>();
|
Map<String, Object> requestBody = new HashMap<>();
|
||||||
requestBody.put("model", model);
|
requestBody.put("model", model);
|
||||||
@@ -104,7 +116,19 @@ public class OpenAiStreamClient {
|
|||||||
.getStr("content");
|
.getStr("content");
|
||||||
|
|
||||||
if (content != null && !content.isEmpty()) {
|
if (content != null && !content.isEmpty()) {
|
||||||
listener.onMessage(content);
|
if(punctuationSet.contains(content)){
|
||||||
|
//说明有标点啦,直接返回
|
||||||
|
bufferStr.append(content);
|
||||||
|
listener.onMessage(bufferStr.toString());
|
||||||
|
}else{
|
||||||
|
//加入缓冲区
|
||||||
|
if(StrUtil.isEmpty(bufferStr.toString())){
|
||||||
|
bufferStr.append(content);
|
||||||
|
}else {
|
||||||
|
bufferStr.append(" ").append(content);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
listener.onError(new IOException("Parse error: " + e.getMessage()));
|
listener.onError(new IOException("Parse error: " + e.getMessage()));
|
||||||
|
|||||||
Reference in New Issue
Block a user