Commit 3ba4dd16713378014482af5311db50e2f21bbb8e

Authored by qianbao
1 parent 9cc28448

添加向量库

src/main/java/com/xly/service/XlyErpService.java
@@ -37,6 +37,7 @@ import dev.langchain4j.service.MemoryId; @@ -37,6 +37,7 @@ import dev.langchain4j.service.MemoryId;
37 import dev.langchain4j.service.V; 37 import dev.langchain4j.service.V;
38 import io.milvus.v2.common.DataType; 38 import io.milvus.v2.common.DataType;
39 import io.milvus.v2.service.collection.request.CreateCollectionReq; 39 import io.milvus.v2.service.collection.request.CreateCollectionReq;
  40 +import jnr.ffi.annotations.In;
40 import lombok.RequiredArgsConstructor; 41 import lombok.RequiredArgsConstructor;
41 import lombok.extern.slf4j.Slf4j; 42 import lombok.extern.slf4j.Slf4j;
42 import org.apache.commons.lang3.time.DateFormatUtils; 43 import org.apache.commons.lang3.time.DateFormatUtils;
@@ -227,6 +228,25 @@ public class XlyErpService { @@ -227,6 +228,25 @@ public class XlyErpService {
227 } 228 }
228 } 229 }
229 230
  231 + /****
  232 + * @Author 钱豹
  233 + * @Date 8:54 2026/4/7
  234 + * @Param [userInput, userId, sUserName, sBrandsId, sSubsidiaryId, sUserType, authorization]
  235 + * @return com.xly.entity.AiResponseDTO
  236 + * @Description 换一换
  237 + **/
  238 + public AiResponseDTO change(String userId ,
  239 + String sUserName ,
  240 + String sBrandsId ,
  241 + String sSubsidiaryId,
  242 + String sUserType,
  243 + String authorization,
  244 + Integer iPage) {
  245 + // 1. 初始化用户场景会话(权限内场景)
  246 + UserSceneSession session = userSceneSessionService.getUserSceneSession(userId,sUserName,sBrandsId,sSubsidiaryId,sUserType,authorization);
  247 + return getChange(session, iPage);
  248 + }
  249 +
230 /*** 250 /***
231 * @Author 钱豹 251 * @Author 钱豹
232 * @Date 19:18 2026/1/27 252 * @Date 19:18 2026/1/27
@@ -270,7 +290,7 @@ public class XlyErpService { @@ -270,7 +290,7 @@ public class XlyErpService {
270 // 3. 未选场景:先展示场景选择界面,处理用户序号选择 290 // 3. 未选场景:先展示场景选择界面,处理用户序号选择
271 if (!session.isSceneSelected() && ValiDataUtil.me().isPureNumber(input)){ 291 if (!session.isSceneSelected() && ValiDataUtil.me().isPureNumber(input)){
272 // 3.1 尝试处理场景选择(输入序号则匹配,否则展示选择提示) 292 // 3.1 尝试处理场景选择(输入序号则匹配,否则展示选择提示)
273 - return handleSceneSelect(userId, input, session); 293 + return handleSceneSelect(userId, input, session,1);
274 } 294 }
275 // 4. 构建Agent,执行业务交互,如果返回为null,说明大模型没有判段出场景,必判断出后才能继续 295 // 4. 构建Agent,执行业务交互,如果返回为null,说明大模型没有判段出场景,必判断出后才能继续
276 ErpAiAgent aiAgent = createErpAiAgent(userId, input, session); 296 ErpAiAgent aiAgent = createErpAiAgent(userId, input, session);
@@ -942,7 +962,7 @@ public class XlyErpService { @@ -942,7 +962,7 @@ public class XlyErpService {
942 /** 962 /**
943 * 处理用户场景选择:输入序号→匹配场景→更新会话状态 963 * 处理用户场景选择:输入序号→匹配场景→更新会话状态
944 */ 964 */
945 - private AiResponseDTO handleSceneSelect(String userId, String userInput, UserSceneSession session) { 965 + private AiResponseDTO handleSceneSelect(String userId, String userInput, UserSceneSession session,Integer page) {
946 // 1. 尝试根据序号匹配场景 966 // 1. 尝试根据序号匹配场景
947 boolean selectSuccess = session.selectSceneByInput(userInput); 967 boolean selectSuccess = session.selectSceneByInput(userInput);
948 String sceneName = StrUtil.EMPTY; 968 String sceneName = StrUtil.EMPTY;
@@ -954,20 +974,34 @@ public class XlyErpService { @@ -954,20 +974,34 @@ public class XlyErpService {
954 UserSceneSessionService.ERP_AGENT_CACHE.remove(userId); 974 UserSceneSessionService.ERP_AGENT_CACHE.remove(userId);
955 //清除记忆缓存 975 //清除记忆缓存
956 operableChatMemoryProvider.clearSpecifiedMemory(userId); 976 operableChatMemoryProvider.clearSpecifiedMemory(userId);
957 - StringBuffer aiText = new StringBuffer().append(" <div style='line-height:1.8;width:100%;'>")  
958 - .append("<div style=\"color: #333;\">")  
959 - .append("智能体选择成功! 现在可以问她相关问题(如" + String.join("、", session.getCurrentScene().getSSceneContext()) + ")")  
960 - .append("</div>");  
961 - //插入用户常用问题  
962 - aiText.append(getSelectAgent(session,1));  
963 - sceneName = ObjectUtil.isNotEmpty(session.getCurrentScene())?session.getCurrentScene().getSSceneName():StrUtil.EMPTY;  
964 - methodName = ObjectUtil.isNotEmpty(session.getCurrentTool())?session.getCurrentTool().getSControlName():StrUtil.EMPTY;  
965 - return AiResponseDTO.builder().sSceneName(sceneName).sMethodName(methodName).aiText(aiText.toString()).sSceneName(session.getCurrentScene().getSSceneName()).build(); 977 + return getChange( session, page);
966 } else { 978 } else {
967 // 3. 选择失败:重新展示场景选择提示 979 // 3. 选择失败:重新展示场景选择提示
968 return AiResponseDTO.builder().sSceneName(sceneName).sMethodName(methodName).aiText(session.buildSceneSelectHint()).build(); 980 return AiResponseDTO.builder().sSceneName(sceneName).sMethodName(methodName).aiText(session.buildSceneSelectHint()).build();
969 } 981 }
970 } 982 }
  983 +
  984 + /***
  985 + * @Author 钱豹
  986 + * @Date 9:00 2026/4/7
  987 + * @Param [session, page]
  988 + * @return com.xly.entity.AiResponseDTO
  989 + * @Description 用户输入数字换一换
  990 + **/
  991 + private AiResponseDTO getChange(UserSceneSession session,Integer page){
  992 + StringBuffer aiText = new StringBuffer().append(" <div style='line-height:1.8;width:100%;'>")
  993 + .append("<div style=\"color: #333;\">")
  994 + .append("智能体选择成功! 现在可以问她相关问题(如" + String.join("、", session.getCurrentScene().getSSceneContext()) + ")")
  995 + .append("</div>");
  996 + //插入用户常用问题
  997 + aiText.append(getSelectAgent(session,page));
  998 + String sceneName = ObjectUtil.isNotEmpty(session.getCurrentScene())?session.getCurrentScene().getSSceneName():StrUtil.EMPTY;
  999 + String methodName = ObjectUtil.isNotEmpty(session.getCurrentTool())?session.getCurrentTool().getSControlName():StrUtil.EMPTY;
  1000 + return AiResponseDTO.builder().sSceneName(sceneName).sMethodName(methodName).aiText(aiText.toString()).sSceneName(session.getCurrentScene().getSSceneName()).build();
  1001 + }
  1002 +
  1003 +
  1004 +
971 /*** 1005 /***
972 * @Author 钱豹 1006 * @Author 钱豹
973 * @Date 11:45 2026/3/13 1007 * @Date 11:45 2026/3/13
@@ -978,18 +1012,24 @@ public class XlyErpService { @@ -978,18 +1012,24 @@ public class XlyErpService {
978 private String getSelectAgent(UserSceneSession session,Integer page){ 1012 private String getSelectAgent(UserSceneSession session,Integer page){
979 List<ToolMeta> toolMetaAll = session.getAuthTool(); 1013 List<ToolMeta> toolMetaAll = session.getAuthTool();
980 String sSceneId = session.getCurrentScene().getSId(); 1014 String sSceneId = session.getCurrentScene().getSId();
  1015 + String sToolId = session.getCurrentTool().getSId();
981 toolMetaAll = toolMetaAll.stream().filter(to-> to.getSSceneId().equals(session.getCurrentScene().getSId())).collect(Collectors.toUnmodifiableList()); 1016 toolMetaAll = toolMetaAll.stream().filter(to-> to.getSSceneId().equals(session.getCurrentScene().getSId())).collect(Collectors.toUnmodifiableList());
982 StringBuffer sb = new StringBuffer(); 1017 StringBuffer sb = new StringBuffer();
983 - List<List<ToolMeta>> firstFive = ListUtil.split(toolMetaAll,5);  
984 - List<ToolMeta> showList;  
985 - if(ObjectUtil.isNotEmpty(firstFive.get(page-1))){  
986 - showList = firstFive.get(page-1);  
987 - page = page + 1;  
988 - }else{  
989 - showList = firstFive.get(0);  
990 - page = 1; 1018 + //获取用户最近五次问题
  1019 + List<Map<String,Object>> data = getAiUserAgentQuestion(session.getUserId(),sSceneId, sToolId, page,3);
  1020 + Integer iPageCount = 0;
  1021 + if(page==1){
  1022 + iPageCount =getAiUserAgentQuestionCount(session.getUserId(), sSceneId, sToolId);
  1023 + }
  1024 + List<ToolMeta> showListAll = new ArrayList<>();
  1025 + if(ObjectUtil.isNotEmpty(data)){
  1026 + data.forEach(one->{
  1027 + ToolMeta tm = new ToolMeta();
  1028 + tm.setSMethodName(one.get("sUserInput").toString());
  1029 + });
991 } 1030 }
992 - showList.forEach(one->{ 1031 + showListAll.addAll(toolMetaAll);
  1032 + showListAll.forEach(one->{
993 sb.append("<div style=\"color: #4096ff; margin-top: 5px;display:flex;align-items:center;font-size:12px;\" data-action=\"reset\" data-text=\"") 1033 sb.append("<div style=\"color: #4096ff; margin-top: 5px;display:flex;align-items:center;font-size:12px;\" data-action=\"reset\" data-text=\"")
994 .append(one.getSMethodName()).append("\" onclick=\"reset(").append(one.getSMethodName()).append("\">") 1034 .append(one.getSMethodName()).append("\" onclick=\"reset(").append(one.getSMethodName()).append("\">")
995 .append("<span style=\"display:inline-block; width:5px; height:5px; background-color:#ccc; border-radius:50%; margin-right:5px;\"></span>") 1035 .append("<span style=\"display:inline-block; width:5px; height:5px; background-color:#ccc; border-radius:50%; margin-right:5px;\"></span>")
@@ -997,11 +1037,53 @@ public class XlyErpService { @@ -997,11 +1037,53 @@ public class XlyErpService {
997 .append(" </div>"); 1037 .append(" </div>");
998 }); 1038 });
999 sb.append("</div>"); 1039 sb.append("</div>");
1000 - sb.append(" <div style=\"color: #4096ff; margin-top: 5px;width:100%;text-align:right;margin-right:10px;font-size:12px;\" data-action=\"resetTag\" data-text=\"").append(sSceneId).append(",").append(page).append("\" onclick=\"reset(换一换)\">"); 1040 + sb.append(" <div style=\"color: #4096ff; margin-top: 5px;width:100%;text-align:right;margin-right:10px;font-size:12px;\" data-action=\"resetTag\" data-text=\"").append(sSceneId).append(",").append(sToolId).append(",").append(page+1).append(",").append(iPageCount).append("\" onclick=\"reset(换一换)\">");
1001 sb.append(" 换一换").append("</div>"); 1041 sb.append(" 换一换").append("</div>");
1002 return sb.toString(); 1042 return sb.toString();
1003 } 1043 }
1004 1044
  1045 + /***
  1046 + * @Author 钱豹
  1047 + * @Date 10:02 2026/4/7
  1048 + * @Param [sLoginId, sSceneId, sMethodId, iPageNum, iPageSize]
  1049 + * @return java.util.List<java.util.Map<java.lang.String,java.lang.Object>>
  1050 + * @Description 换一换获取最近数据
  1051 + **/
  1052 + private List<Map<String,Object>> getAiUserAgentQuestion(String sLoginId, String sSceneId, String sMethodId, Integer iPageNum,Integer iPageSize){
  1053 + StringBuffer sb = new StringBuffer().append("SELECT sId,iUpdate,sUserInput FROM ai_user_agent_question ")
  1054 + .append("WHERE sLoginId = #{sLoginId} ")
  1055 + .append("AND sSceneId = #{sSceneId} ")
  1056 + .append("AND sMethodId = #{sMethodId} ")
  1057 + .append("AND IFNULL(sUserInput,'') <> '' ")
  1058 + .append("ORDER BY iUpdate DESC,tUpdateDate DESC ")
  1059 + .append("LIMIT #{iPageNum},#{iPageSize} ");
  1060 + Map<String,Object> serMap = new HashMap<>();
  1061 + serMap.put("sLoginId",sLoginId);
  1062 + serMap.put("sSceneId",sSceneId);
  1063 + serMap.put("sMethodId",sMethodId);
  1064 + serMap.put("iPageNum",iPageNum);
  1065 + serMap.put("iPageSize",iPageSize);
  1066 + return dynamicExeDbService.findSql(serMap,sb.toString());
  1067 + }
  1068 +
  1069 + private Integer getAiUserAgentQuestionCount(String sLoginId, String sSceneId, String sMethodId){
  1070 + StringBuffer sb = new StringBuffer().append("SELECT COUNT(1) AS iCount FROM ai_user_agent_question ")
  1071 + .append("WHERE sLoginId = #{sLoginId} ")
  1072 + .append("AND sSceneId = #{sSceneId} ")
  1073 + .append("AND sMethodId = #{sMethodId} ")
  1074 + .append("AND IFNULL(sUserInput,'') <> '' ");
  1075 + Map<String,Object> serMap = new HashMap<>();
  1076 + serMap.put("sLoginId",sLoginId);
  1077 + serMap.put("sSceneId",sSceneId);
  1078 + serMap.put("sMethodId",sMethodId);
  1079 + List<Map<String,Object>> data = dynamicExeDbService.findSql(serMap,sb.toString());
  1080 + if(ObjectUtil.isNotEmpty(data)){
  1081 + return (Integer) data.get(0).get("iCount");
  1082 + }
  1083 + return 0;
  1084 + }
  1085 +
  1086 +
1005 /** 1087 /**
1006 * @Author 钱豹 1088 * @Author 钱豹
1007 * @Date 13:32 2026/2/6 1089 * @Date 13:32 2026/2/6
@@ -1056,25 +1138,5 @@ public class XlyErpService { @@ -1056,25 +1138,5 @@ public class XlyErpService {
1056 String sChatMessage = chatiAgent.chat(session.getUserId(), input); 1138 String sChatMessage = chatiAgent.chat(session.getUserId(), input);
1057 return AiResponseDTO.builder().sSceneName(sceneName).sMethodName(methodName).aiText(sChatMessage).systemText(StrUtil.EMPTY).sReturnType(ReturnTypeCode.HTML.getCode()).build(); 1139 return AiResponseDTO.builder().sSceneName(sceneName).sMethodName(methodName).aiText(sChatMessage).systemText(StrUtil.EMPTY).sReturnType(ReturnTypeCode.HTML.getCode()).build();
1058 } 1140 }
1059 - /***  
1060 - * @Author 钱豹  
1061 - * @Date 12:14 2026/3/8  
1062 - * @Param [chatMessage, memoryId]  
1063 - * @return void  
1064 - * @Description 随便聊聊移除最后一个AI 返回信息 跟系统询问的随便聊聊  
1065 - **/  
1066 - private void removeMssageSbll(List<ChatMessage> chatMessage,String memoryId){  
1067 - if(chatMessage!=null){  
1068 -// operableChatMemoryProvider.deleteSingleMessage(memoryId,chatMessage.get(chatMessage.size()-1));  
1069 - for(int i=chatMessage.size()-1;i>0;i--){  
1070 - ChatMessage data = chatMessage.get(i);  
1071 - ChatMessageType sType = data.type();  
1072 - if(ChatMessageType.SYSTEM.equals(sType)){  
1073 - operableChatMemoryProvider.deleteSingleMessage(memoryId,data);  
1074 - return;  
1075 - }  
1076 - }  
1077 - }  
1078 - }  
1079 1141
1080 } 1142 }
1081 \ No newline at end of file 1143 \ No newline at end of file
src/main/java/com/xly/tts/service/PythonTtsProxyService.java
@@ -68,6 +68,26 @@ public class PythonTtsProxyService { @@ -68,6 +68,26 @@ public class PythonTtsProxyService {
68 } 68 }
69 69
70 /** 70 /**
  71 + * @Author 钱豹
  72 + * @Date 8:54 2026/4/7
  73 + * @Param [request]
  74 + * @return org.springframework.http.ResponseEntity<com.xly.tts.bean.TTSResponseDTO>
  75 + * @Description 换一换
  76 + **/
  77 + public ResponseEntity<TTSResponseDTO> change(TTSRequestDTO request) {
  78 + String userInput = request.getText();
  79 + String sUserId = request.getUserid();
  80 + String sUserName = request.getUsername();
  81 + String sBrandsId = request.getBrandsid();
  82 + String sSubsidiaryId = request.getSubsidiaryid();
  83 + String sUserType = request.getUsertype();
  84 + String authorization = request.getAuthorization();
  85 + Integer iPage = Integer.valueOf(userInput);
  86 + AiResponseDTO voiceText = xlyErpService.change(sUserId, sUserName , sBrandsId , sSubsidiaryId, sUserType, authorization,iPage);
  87 + return synthesizeStreamAi(request, voiceText);
  88 + }
  89 +
  90 + /**
71 * 【保持原有返回类型】AI对话 + 流式TTS 91 * 【保持原有返回类型】AI对话 + 流式TTS
72 */ 92 */
73 public ResponseEntity<TTSResponseDTO> synthesizeStreamAi(TTSRequestDTO request) { 93 public ResponseEntity<TTSResponseDTO> synthesizeStreamAi(TTSRequestDTO request) {
src/main/java/com/xly/web/TTSStreamController.java
@@ -77,6 +77,19 @@ public class TTSStreamController { @@ -77,6 +77,19 @@ public class TTSStreamController {
77 pythonTtsProxyService.shutdown(); 77 pythonTtsProxyService.shutdown();
78 } 78 }
79 79
  80 + /***
  81 + * @Author 钱豹
  82 + * @Date 8:53 2026/4/7
  83 + * @Param [request]
  84 + * @return org.springframework.http.ResponseEntity<com.xly.tts.bean.TTSResponseDTO>
  85 + * @Description 换一换
  86 + **/
  87 + @PostMapping(value = "/stream/change", consumes = {MediaType.APPLICATION_JSON_VALUE, MediaType.ALL_VALUE})
  88 + public ResponseEntity<TTSResponseDTO> change(@RequestBody TTSRequestDTO request) {
  89 + return pythonTtsProxyService.change(request);
  90 + }
  91 +
  92 +
80 /** 93 /**
81 * 流式合成语音(代理到Python服务) 94 * 流式合成语音(代理到Python服务)
82 */ 95 */