AI 面试业务逻辑初始化

This commit is contained in:
wangxiangshun
2025-10-07 14:30:50 +08:00
parent e04f5e3091
commit 2222d4fa81
3 changed files with 41 additions and 82 deletions

View File

@@ -4,52 +4,34 @@ import com.vetti.common.ai.elevenLabs.ElevenLabsClient;
import com.vetti.common.ai.gpt.ChatGPTClient; import com.vetti.common.ai.gpt.ChatGPTClient;
import com.vetti.common.ai.whisper.WhisperClient; import com.vetti.common.ai.whisper.WhisperClient;
import com.vetti.common.config.RuoYiConfig; import com.vetti.common.config.RuoYiConfig;
import com.vetti.common.utils.spring.SpringUtils;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import javax.sound.sampled.AudioFileFormat;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.websocket.*; import javax.websocket.*;
import javax.websocket.server.PathParam; import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint; import javax.websocket.server.ServerEndpoint;
import java.io.*; import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.channels.FileChannel; import java.nio.channels.FileChannel;
/** /**
* 语音面试 web处理器 * 语音面试 web处理器
*
*/ */
@Slf4j @Slf4j
@ServerEndpoint("/voice-websocket/{clientId}") @ServerEndpoint("/voice-websocket/{clientId}")
@Component @Component
public class ChatWebSocketHandler { public class ChatWebSocketHandler {
// 音频参数配置 - 根据实际发送的音频流参数调整
private static final float SAMPLE_RATE = 16000.0f; // 采样率
private static final int SAMPLE_SIZE_IN_BITS = 16; // 采样位数
private static final int CHANNELS = 1; // 声道数 (1=单声道, 2=立体声)
private static final boolean SIGNED = true; // 是否有符号
private static final boolean BIG_ENDIAN = false; // 字节序
// 语音文件保存目录 // 语音文件保存目录
private static final String VOICE_STORAGE_DIR = "/voice_files/"; private static final String VOICE_STORAGE_DIR = "/voice_files/";
// 语音结果文件保存目录 // 语音结果文件保存目录
private static final String VOICE_STORAGE_RESULT_DIR = "/voice_result_files/"; private static final String VOICE_STORAGE_RESULT_DIR = "/voice_result_files/";
@Autowired
private ElevenLabsClient elevenLabsClient;
@Autowired
private ChatGPTClient chatGPTClient;
@Autowired
private WhisperClient whisperClient;
public ChatWebSocketHandler() { public ChatWebSocketHandler() {
// 初始化存储目录 // 初始化存储目录
@@ -91,30 +73,36 @@ public class ChatWebSocketHandler {
try { try {
log.info("客户端ID为:{}", clientId); log.info("客户端ID为:{}", clientId);
// 处理二进制流数据 // 处理二进制流数据
byte[] data = new byte[byteBuffer.remaining()]; byte[] bytes = new byte[byteBuffer.remaining()];
//从缓冲区中读取数据并存储到指定的字节数组中
byteBuffer.get(bytes);
// 生成唯一文件名 // 生成唯一文件名
String fileName = clientId + "_" + System.currentTimeMillis() + ".mp3"; String fileName = clientId + "_" + System.currentTimeMillis() + ".webm";
String pathUrl = RuoYiConfig.getProfile()+VOICE_STORAGE_DIR + fileName; String pathUrl = RuoYiConfig.getProfile()+VOICE_STORAGE_DIR + fileName;
// String pathUrl = "/Users/wangxiangshun/Desktop/0.8733346782733291.webm";
log.info("文件路径为:{}", pathUrl); log.info("文件路径为:{}", pathUrl);
saveAsWebM(data,pathUrl); saveAsWebM(bytes, pathUrl);
// //拿到文件进行文字转换 //拿到文件进行文字转换
// String resultText = whisperClient.handleVoiceToText(pathUrl); WhisperClient whisperClient = SpringUtils.getBean(WhisperClient.class);
// //把提问的文字发送给CPT String resultText = whisperClient.handleVoiceToText(pathUrl);
// String resultMsg = chatGPTClient.handleAiChat(resultText); //把提问的文字发送给CPT
// //把结果文字转成语音文件 ChatGPTClient chatGPTClient = SpringUtils.getBean(ChatGPTClient.class);
// //生成文件 String resultMsg = chatGPTClient.handleAiChat(resultText);
// // 生成唯一文件 //把结果文字转成语音文件
// String resultFileName = clientId + "_" + System.currentTimeMillis() + ".webm"; //生成文件
// String resultPathUrl = RuoYiConfig.getProfile()+VOICE_STORAGE_DIR + resultFileName; // 生成唯一文件名
// elevenLabsClient.handleTextToVoice(resultMsg,resultPathUrl); String resultFileName = clientId + "_" + System.currentTimeMillis() + ".webm";
String resultPathUrl = RuoYiConfig.getProfile() + VOICE_STORAGE_RESULT_DIR + resultFileName;
ElevenLabsClient elevenLabsClient = SpringUtils.getBean(ElevenLabsClient.class);
elevenLabsClient.handleTextToVoice(resultMsg, resultPathUrl);
//把语音文件转换成流,发送给前端 //把语音文件转换成流,发送给前端
System.out.println("接收到二进制数据,长度: " + data.length + " bytes"); System.out.println("接收到二进制数据,长度: " + bytes.length + " bytes");
try { try {
//文件转换成文件流 //文件转换成文件流
// ByteBuffer outByteBuffer = convertFileToByteBuffer(resultPathUrl); ByteBuffer outByteBuffer = convertFileToByteBuffer(resultPathUrl);
// session.getBasicRemote().sendBinary(outByteBuffer); session.getBasicRemote().sendBinary(outByteBuffer);
// 发送响应确认 // 发送响应确认
session.getBasicRemote().sendText("已收到二进制数据,长度: " + data.length); session.getBasicRemote().sendText("已收到二进制数据,长度: " + bytes.length);
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
} }
@@ -138,6 +126,7 @@ public class ChatWebSocketHandler {
/** /**
* 将字节数组保存为WebM文件 * 将字节数组保存为WebM文件
*
* @param byteData 包含WebM数据的字节数组 * @param byteData 包含WebM数据的字节数组
* @param filePath 目标文件路径 * @param filePath 目标文件路径
* @return 操作是否成功 * @return 操作是否成功
@@ -181,39 +170,9 @@ public class ChatWebSocketHandler {
return false; return false;
} }
/**
* 将接收的音频数据保存为WAV文件
*/
private void saveAudioToFile(byte[] audioData,String pathUrl) {
if (audioData == null || audioData.length == 0) {
System.out.println("没有接收到音频数据,不保存文件");
return;
}
try {
// 合并所有音频数据
// 创建音频格式
AudioFormat format = new AudioFormat(
SAMPLE_RATE,
SAMPLE_SIZE_IN_BITS,
CHANNELS,
SIGNED,
BIG_ENDIAN
);
// 创建音频输入流
ByteArrayInputStream bais = new ByteArrayInputStream(audioData);
AudioInputStream ais = new AudioInputStream(bais, format, audioData.length / format.getFrameSize());
// 保存为WAV文件
File outputFile = new File(pathUrl);
AudioSystem.write(ais, AudioFileFormat.Type.WAVE, outputFile);
System.out.println("音频文件保存成功: " + outputFile.getAbsolutePath());
} catch (IOException e) {
System.err.println("保存音频文件失败: " + e.getMessage());
e.printStackTrace();
}
}
/** /**
* File 转换成 ByteBuffer * File 转换成 ByteBuffer
*
* @param fileUrl 文件路径 * @param fileUrl 文件路径
* @return * @return
*/ */

View File

@@ -152,7 +152,7 @@ whisper:
apiUrl: https://api.openai.com/v1/audio/transcriptions apiUrl: https://api.openai.com/v1/audio/transcriptions
model: whisper-1 model: whisper-1
apiKey: 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 apiKey: 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
language: zh language: en
# AI 聊天 # AI 聊天
chatGpt: chatGpt:

View File

@@ -152,7 +152,7 @@ whisper:
apiUrl: https://api.openai.com/v1/audio/transcriptions apiUrl: https://api.openai.com/v1/audio/transcriptions
model: whisper-1 model: whisper-1
apiKey: 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 apiKey: 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
language: zh language: en
# AI 聊天 # AI 聊天
chatGpt: chatGpt: