AI 提问追问环境demo 添加
This commit is contained in:
@@ -8,6 +8,7 @@ import com.vetti.common.ai.gpt.OpenAiStreamClient;
|
|||||||
import com.vetti.common.ai.gpt.service.OpenAiStreamListenerService;
|
import com.vetti.common.ai.gpt.service.OpenAiStreamListenerService;
|
||||||
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.core.redis.RedisCache;
|
||||||
import com.vetti.common.utils.spring.SpringUtils;
|
import com.vetti.common.utils.spring.SpringUtils;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import okhttp3.*;
|
import okhttp3.*;
|
||||||
@@ -24,6 +25,7 @@ import java.io.*;
|
|||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 语音面试 web处理器
|
* 语音面试 web处理器
|
||||||
@@ -60,6 +62,16 @@ public class ChatWebSocketHandler {
|
|||||||
*/
|
*/
|
||||||
private final Map<String,String> cacheReplyFlag = new ConcurrentHashMap<>();
|
private final Map<String,String> cacheReplyFlag = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 缓存客户端,面试回答信息
|
||||||
|
*/
|
||||||
|
private final Map<String,String> cacheMsgMapData = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 缓存客户端,AI提问的问题结果信息
|
||||||
|
*/
|
||||||
|
private final Map<String,String> cacheQuestionResult = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
// 语音文件保存目录
|
// 语音文件保存目录
|
||||||
private static final String VOICE_STORAGE_DIR = "/voice_files/";
|
private static final String VOICE_STORAGE_DIR = "/voice_files/";
|
||||||
|
|
||||||
@@ -92,6 +104,10 @@ public class ChatWebSocketHandler {
|
|||||||
createWhisperRealtimeSocket(session.getId());
|
createWhisperRealtimeSocket(session.getId());
|
||||||
//是初次自我介绍后的问答环节
|
//是初次自我介绍后的问答环节
|
||||||
cacheReplyFlag.put(session.getId(),"YES");
|
cacheReplyFlag.put(session.getId(),"YES");
|
||||||
|
//初始化面试回答数据记录
|
||||||
|
cacheMsgMapData.put(session.getId(),"");
|
||||||
|
//初始化面试问题
|
||||||
|
cacheQuestionResult.put(session.getId(),"");
|
||||||
//发送初始化面试官语音流
|
//发送初始化面试官语音流
|
||||||
String openingPathUrl = RuoYiConfig.getProfile() + VOICE_SYSTEM_DIR + "opening.wav";
|
String openingPathUrl = RuoYiConfig.getProfile() + VOICE_SYSTEM_DIR + "opening.wav";
|
||||||
try {
|
try {
|
||||||
@@ -128,10 +144,11 @@ public class ChatWebSocketHandler {
|
|||||||
String startFlag = cacheReplyFlag.get(session.getId());
|
String startFlag = cacheReplyFlag.get(session.getId());
|
||||||
//语音结束,开始进行回答解析
|
//语音结束,开始进行回答解析
|
||||||
String cacheResultText = cacheClientTts.get(clientId);
|
String cacheResultText = cacheClientTts.get(clientId);
|
||||||
log.info("返回的结果为:{}", cacheResultText);
|
log.info("面试者回答信息为:{}", cacheResultText);
|
||||||
if (StrUtil.isEmpty(cacheResultText)) {
|
if (StrUtil.isEmpty(cacheResultText)) {
|
||||||
cacheResultText = "Hi.";
|
cacheResultText = "Hi.";
|
||||||
}
|
}
|
||||||
|
String promptJson = "";
|
||||||
if("YES".equals(startFlag)) {
|
if("YES".equals(startFlag)) {
|
||||||
//自我介绍结束后马上返回一个Good
|
//自我介绍结束后马上返回一个Good
|
||||||
//发送初始化面试官语音流
|
//发送初始化面试官语音流
|
||||||
@@ -146,7 +163,37 @@ public class ChatWebSocketHandler {
|
|||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
cacheResultText = "你是面试官,根据Construction Labourer候选人回答生成追问。只要一个问题";
|
Map<String,String> mapEntity = new HashMap<>();
|
||||||
|
mapEntity.put("role","system");
|
||||||
|
mapEntity.put("content","你是面试官,根据Construction Labourer候选人回答生成追问。只要一个问题,问题不要重复");
|
||||||
|
List<Map<String,String>> list = new LinkedList();
|
||||||
|
list.add(mapEntity);
|
||||||
|
promptJson = JSONUtil.toJsonStr(list);
|
||||||
|
//记录缓存中
|
||||||
|
cacheMsgMapData.put(session.getId(),promptJson);
|
||||||
|
}else{
|
||||||
|
//开始根据面试者回答的问题,进行追问回答
|
||||||
|
// {
|
||||||
|
// role: "system",
|
||||||
|
// content: "你是面试官,根据Construction Labourer候选人回答生成追问。"
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// role: "user",
|
||||||
|
// content: `问题:${question}\n候选人回答:${answer}`
|
||||||
|
// }
|
||||||
|
//获取面试者回答信息
|
||||||
|
//获取缓存记录
|
||||||
|
String msgMapData = cacheMsgMapData.get(session.getId());
|
||||||
|
if(StrUtil.isNotEmpty(msgMapData)){
|
||||||
|
List<Map> list = JSONUtil.toList(msgMapData, Map.class);
|
||||||
|
//获取最后一条数据记录
|
||||||
|
Map<String,String> mapEntity = list.get(list.size()-1);
|
||||||
|
//更新问题记录
|
||||||
|
String content = mapEntity.get("content");
|
||||||
|
mapEntity.put("content", StrUtil.format(content, cacheResultText));
|
||||||
|
promptJson = JSONUtil.toJsonStr(list);
|
||||||
|
cacheMsgMapData.put(session.getId(),promptJson);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
//获取完问答数据,直接清空缓存数据
|
//获取完问答数据,直接清空缓存数据
|
||||||
cacheClientTts.put(clientId,"");
|
cacheClientTts.put(clientId,"");
|
||||||
@@ -154,10 +201,18 @@ public class ChatWebSocketHandler {
|
|||||||
log.info("1、开始进行AI回答时间:{}", System.currentTimeMillis() / 1000);
|
log.info("1、开始进行AI回答时间:{}", System.currentTimeMillis() / 1000);
|
||||||
//把提问的文字发送给CPT(流式处理)
|
//把提问的文字发送给CPT(流式处理)
|
||||||
OpenAiStreamClient aiStreamClient = SpringUtils.getBean(OpenAiStreamClient.class);
|
OpenAiStreamClient aiStreamClient = SpringUtils.getBean(OpenAiStreamClient.class);
|
||||||
aiStreamClient.streamChat(cacheResultText, new OpenAiStreamListenerService() {
|
log.info("AI提示词为:{}",promptJson);
|
||||||
|
aiStreamClient.streamChat(promptJson, new OpenAiStreamListenerService() {
|
||||||
@Override
|
@Override
|
||||||
public void onMessage(String content) {
|
public void onMessage(String content) {
|
||||||
log.info("返回AI结果:{}", content);
|
log.info("返回AI结果:{}", content);
|
||||||
|
String questionResult = cacheQuestionResult.get(session.getId());
|
||||||
|
if(StrUtil.isEmpty(questionResult)){
|
||||||
|
questionResult = content;
|
||||||
|
}else{
|
||||||
|
questionResult = questionResult + content;
|
||||||
|
}
|
||||||
|
cacheQuestionResult.put(session.getId(),questionResult);
|
||||||
// 实时输出内容
|
// 实时输出内容
|
||||||
//开始进行语音输出-流式持续输出
|
//开始进行语音输出-流式持续输出
|
||||||
log.info("2、开始进行AI回答时间:{}", System.currentTimeMillis() / 1000);
|
log.info("2、开始进行AI回答时间:{}", System.currentTimeMillis() / 1000);
|
||||||
@@ -185,6 +240,21 @@ public class ChatWebSocketHandler {
|
|||||||
@Override
|
@Override
|
||||||
public void onComplete() {
|
public void onComplete() {
|
||||||
try {
|
try {
|
||||||
|
//开始往缓存中记录提问的问题
|
||||||
|
String questionResult = cacheQuestionResult.get(session.getId());
|
||||||
|
//获取缓存记录
|
||||||
|
String msgMapData = cacheMsgMapData.get(session.getId());
|
||||||
|
if(StrUtil.isNotEmpty(msgMapData)){
|
||||||
|
List<Map> list = JSONUtil.toList(msgMapData, Map.class);
|
||||||
|
Map<String,String> mapEntity = new HashMap<>();
|
||||||
|
mapEntity.put("role","system");
|
||||||
|
mapEntity.put("content","问题:"+questionResult+"\\n候选人回答:{}");
|
||||||
|
list.add(mapEntity);
|
||||||
|
cacheMsgMapData.put(session.getId(),JSONUtil.toJsonStr(list));
|
||||||
|
}
|
||||||
|
//清空问题
|
||||||
|
cacheQuestionResult.put(session.getId(),"");
|
||||||
|
|
||||||
Map<String, String> resultEntity = new HashMap<>();
|
Map<String, String> resultEntity = new HashMap<>();
|
||||||
resultEntity.put("msg", "done");
|
resultEntity.put("msg", "done");
|
||||||
//发送通知告诉客户端已经回答结束了
|
//发送通知告诉客户端已经回答结束了
|
||||||
@@ -454,6 +524,5 @@ public class ChatWebSocketHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import org.springframework.stereotype.Component;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
@@ -37,10 +38,10 @@ public class OpenAiStreamClient {
|
|||||||
/**
|
/**
|
||||||
* 发送流式请求
|
* 发送流式请求
|
||||||
*
|
*
|
||||||
* @param prompt 提示词
|
* @param promptJson 提示词json数据集合
|
||||||
* @param listener 流式响应监听器
|
* @param listener 流式响应监听器
|
||||||
*/
|
*/
|
||||||
public void streamChat(String prompt, OpenAiStreamListenerService listener) {
|
public void streamChat(String promptJson, OpenAiStreamListenerService listener) {
|
||||||
OkHttpClient client = new OkHttpClient.Builder()
|
OkHttpClient client = new OkHttpClient.Builder()
|
||||||
.connectTimeout(30, TimeUnit.SECONDS)
|
.connectTimeout(30, TimeUnit.SECONDS)
|
||||||
.readTimeout(60, TimeUnit.SECONDS)
|
.readTimeout(60, TimeUnit.SECONDS)
|
||||||
@@ -53,13 +54,18 @@ public class OpenAiStreamClient {
|
|||||||
Map<String, Object> requestBody = new HashMap<>();
|
Map<String, Object> requestBody = new HashMap<>();
|
||||||
requestBody.put("model", model);
|
requestBody.put("model", model);
|
||||||
requestBody.put("stream", true);
|
requestBody.put("stream", true);
|
||||||
|
|
||||||
// 构建消息
|
// 构建消息
|
||||||
Map<String, String> message = new HashMap<>();
|
if(StrUtil.isNotEmpty(promptJson)) {
|
||||||
message.put("role", role);
|
List<Map> promptList = JSONUtil.toList(promptJson, Map.class);
|
||||||
message.put("content", prompt);
|
Object[] objects = new Object[promptList.size()];
|
||||||
requestBody.put("messages", new Object[]{message});
|
for (int i = 0; i < promptList.size(); i++) {
|
||||||
|
objects[i] = promptList.get(i);
|
||||||
|
}
|
||||||
|
//获取到的提示
|
||||||
|
requestBody.put("messages", objects);
|
||||||
|
}
|
||||||
|
//开始给AI发送请求数据
|
||||||
|
System.out.println("请求AI数据参数为:"+JSONUtil.toJsonStr(requestBody));
|
||||||
// 创建请求
|
// 创建请求
|
||||||
Request request = new Request.Builder()
|
Request request = new Request.Builder()
|
||||||
.url(apiUrl)
|
.url(apiUrl)
|
||||||
|
|||||||
Reference in New Issue
Block a user