Commit 51694876c0e31062ff1a33d5d5afd50e647dad2b

Authored by qianbao
1 parent f3eace43

1111

logPath_IS_UNDEFINED/2026-02-09/2026-02-09.debug-0.log deleted
logPath_IS_UNDEFINED/2026-02-09/2026-02-09.error-0.log deleted
logPath_IS_UNDEFINED/2026-02-09/2026-02-09.info-0.log deleted
src/main/java/com/xly/agent/DynamicTableNl2SqlAiAgent.java
@@ -25,9 +25,12 @@ public interface DynamicTableNl2SqlAiAgent { @@ -25,9 +25,12 @@ public interface DynamicTableNl2SqlAiAgent {
25 3.1 多表关联必须使用 表名+字段名(如表名.字段名),严格按下面[涉及表名]中的表次序关联,聚合函数(SUM/COUNT/AVG/MIN/MAX)必须加业务化别名,日期过滤使用标准DATE格式(yyyy-MM-dd); 25 3.1 多表关联必须使用 表名+字段名(如表名.字段名),严格按下面[涉及表名]中的表次序关联,聚合函数(SUM/COUNT/AVG/MIN/MAX)必须加业务化别名,日期过滤使用标准DATE格式(yyyy-MM-dd);
26 3.2 SQL所有字段均采用 表名.字段名 方式生成,务必确保 字段名 在相应的 表名 描述的字段中存在,如果不存在重试其它方式,直到满足条件 26 3.2 SQL所有字段均采用 表名.字段名 方式生成,务必确保 字段名 在相应的 表名 描述的字段中存在,如果不存在重试其它方式,直到满足条件
27 3.3 SQL所有字段涉及的所有表名,都要**严格**按下面[涉及表名]中的表次序关联,没有关联不允许使用 27 3.3 SQL所有字段涉及的所有表名,都要**严格**按下面[涉及表名]中的表次序关联,没有关联不允许使用
28 - 3.4 SQL所有的查询条件,如果是字符类型的字段,均需要加不为空判断(如ifnull(customername,'')<>'') 28 + 3.4 SQL所有的查询条件,如果是字符类型的字段,均需要加不为空判断,用示例格式判断,示例:ifnull(customername,'')<>''
  29 + 3.5 SQL所有的显示字段的别名中,不能出现空格,如: tCreateDate as earliest 订单日期,正确的应是 tCreateDate as earliest订单日期
29 4. 安全约束:禁止生成任何DDL/DML语句(DROP/ALTER/INSERT/UPDATE/DELETE等),禁止使用子查询、存储过程、自定义函数、临时表; 30 4. 安全约束:禁止生成任何DDL/DML语句(DROP/ALTER/INSERT/UPDATE/DELETE等),禁止使用子查询、存储过程、自定义函数、临时表;
30 - 5. 精准性:严格按用户需求+传入的表结构生成,仅使用指定字段/表,无多余字段、无无效表关联、无冗余过滤条件; 31 + 5. 精准性:
  32 + 5.1 严格按用户需求+传入的表结构生成,仅使用指定字段/表,无多余字段、无无效表关联、无冗余过滤条件;
  33 + 5.2 用户需求中没有明确的日期条件,默认为全部数据,禁止增加任何日期过滤条件
31 6. 关联规则:多表关联时,必须使用外键/业务唯一键关联,禁止无意义关联。 34 6. 关联规则:多表关联时,必须使用外键/业务唯一键关联,禁止无意义关联。
32 """) 35 """)
33 @UserMessage(""" 36 @UserMessage("""
src/main/java/com/xly/agent/ErpAiAgent.java
@@ -14,7 +14,9 @@ public interface ErpAiAgent { @@ -14,7 +14,9 @@ public interface ErpAiAgent {
14 你是一个专业的 工具方法匹配与参数提取 助手,核心职责是根据用户输入(含历史对话)精准匹配工具方法、提取参数、判断缺失并生成交互式补全提示; 14 你是一个专业的 工具方法匹配与参数提取 助手,核心职责是根据用户输入(含历史对话)精准匹配工具方法、提取参数、判断缺失并生成交互式补全提示;
15 按严格按以下步骤处理,无任何额外输出!规则如下: 15 按严格按以下步骤处理,无任何额外输出!规则如下:
16 1. 方法匹配:先精准拆解用户查询的核心业务意图,再自动匹配唯一符合用户问题的工具方法(MethodNo),禁止自创; 16 1. 方法匹配:先精准拆解用户查询的核心业务意图,再自动匹配唯一符合用户问题的工具方法(MethodNo),禁止自创;
17 - 2. 参数提取:提取该工具的全部参数,与描述完全一致,严格按标注类型赋值,数字无引号,为空时禁止赋值0; 17 + 2. 参数提取:提取该工具的全部参数,与描述完全一致,严格按标注类型赋值,规则如下:
  18 + 2.1 数字无引号,为空时禁止赋值0;
  19 + 2.2 如果有空格需要去掉空格后再提取。
18 """) 20 """)
19 @UserMessage("用户输入:{{userInput}}") 21 @UserMessage("用户输入:{{userInput}}")
20 String chat(@MemoryId String userId, @V("userInput") String userInput); 22 String chat(@MemoryId String userId, @V("userInput") String userInput);
src/main/java/com/xly/mapper/AiToolDetailParamsMapper.java
@@ -12,6 +12,6 @@ import java.util.List; @@ -12,6 +12,6 @@ import java.util.List;
12 public interface AiToolDetailParamsMapper { 12 public interface AiToolDetailParamsMapper {
13 13
14 // XML配置方式 14 // XML配置方式
15 - @Select("SELECT * FROM ai_tool_detail_params") 15 + @Select("SELECT * FROM ai_tool_detail_params ORDER BY iOrder,iIncrement ")
16 List<ParamRule> findAll(); 16 List<ParamRule> findAll();
17 } 17 }
18 \ No newline at end of file 18 \ No newline at end of file
src/main/java/com/xly/service/UserSceneSessionService.java
@@ -75,6 +75,21 @@ public class UserSceneSessionService { @@ -75,6 +75,21 @@ public class UserSceneSessionService {
75 CHAT_AGENT_CACHE.clear(); 75 CHAT_AGENT_CACHE.clear();
76 ERP_DynamicTableNl2SqlAiAgent_CACHE.clear(); 76 ERP_DynamicTableNl2SqlAiAgent_CACHE.clear();
77 } 77 }
  78 +
  79 + /***
  80 + * @Author 钱豹
  81 + * @Date 14:03 2026/2/10
  82 + * @Param []
  83 + * @return void
  84 + * @Description 清除用户记忆
  85 + **/
  86 + public void cleanUserSession(String sUserId){
  87 + USER_SCENE_SESSION_CACHE.remove(sUserId);
  88 + ERP_AGENT_CACHE.remove(sUserId);
  89 + CHAT_AGENT_CACHE.remove(sUserId);
  90 + ERP_DynamicTableNl2SqlAiAgent_CACHE.remove(sUserId);
  91 + }
  92 +
78 public UserSceneSession getUserSceneSession(String sUserId, String sUserType,String authorization){ 93 public UserSceneSession getUserSceneSession(String sUserId, String sUserType,String authorization){
79 if (USER_SCENE_SESSION_CACHE.containsKey(sUserId)) { 94 if (USER_SCENE_SESSION_CACHE.containsKey(sUserId)) {
80 return USER_SCENE_SESSION_CACHE.get(sUserId); 95 return USER_SCENE_SESSION_CACHE.get(sUserId);
src/main/java/com/xly/service/XlyErpService.java
@@ -111,6 +111,7 @@ public class XlyErpService { @@ -111,6 +111,7 @@ public class XlyErpService {
111 ){ 111 ){
112 sResponMessage = getDynamicTableSql(session, input, userId, userInput); 112 sResponMessage = getDynamicTableSql(session, input, userId, userInput);
113 } 113 }
  114 +
114 //如果返回空的进入闲聊模式 115 //如果返回空的进入闲聊模式
115 if (ObjectUtil.isEmpty(sResponMessage)){ 116 if (ObjectUtil.isEmpty(sResponMessage)){
116 return getChatiAgent (input, session); 117 return getChatiAgent (input, session);
@@ -259,6 +260,8 @@ public class XlyErpService { @@ -259,6 +260,8 @@ public class XlyErpService {
259 .toolProvider(dynamicToolProvider) 260 .toolProvider(dynamicToolProvider)
260 .build(); 261 .build();
261 UserSceneSessionService.ERP_AGENT_CACHE.put(userId, aiAgent); 262 UserSceneSessionService.ERP_AGENT_CACHE.put(userId, aiAgent);
  263 +// 初始化AiService 以防止热加载太慢 找不到相应的方法
  264 + aiAgent.chat(userId, "initAiService");
262 log.info("用户{}Agent构建完成,已选场景:{},场景ID{}", 265 log.info("用户{}Agent构建完成,已选场景:{},场景ID{}",
263 userId, session.isSceneSelected() ? session.getCurrentScene().getSSceneName() : "未选(全场景匹配)", dynamicToolProvider.sSceneIdMap.get(userId)); 266 userId, session.isSceneSelected() ? session.getCurrentScene().getSSceneName() : "未选(全场景匹配)", dynamicToolProvider.sSceneIdMap.get(userId));
264 } 267 }
@@ -353,8 +356,7 @@ public class XlyErpService { @@ -353,8 +356,7 @@ public class XlyErpService {
353 .build(); 356 .build();
354 UserSceneSessionService.CHAT_AGENT_CACHE.put(session.getUserId(), chatiAgent); } 357 UserSceneSessionService.CHAT_AGENT_CACHE.put(session.getUserId(), chatiAgent); }
355 String sChatMessage = chatiAgent.chat(session.getUserId(), input); 358 String sChatMessage = chatiAgent.chat(session.getUserId(), input);
356 - String systemText = " 你已进入「随便聊聊」专栏, 可"+CommonConstant.RESET;  
357 - return AiResponseDTO.builder().aiText(sChatMessage).sSceneName("随便聊聊").systemText(systemText).sReturnType(ReturnTypeCode.HTML.getCode()).build(); 359 + return AiResponseDTO.builder().aiText(sChatMessage).sSceneName("随便聊聊").systemText(StrUtil.EMPTY).sReturnType(ReturnTypeCode.HTML.getCode()).build();
358 } 360 }
359 361
360 } 362 }
361 \ No newline at end of file 363 \ No newline at end of file
src/main/java/com/xly/tool/DynamicToolProvider.java
@@ -62,7 +62,7 @@ import java.util.stream.IntStream; @@ -62,7 +62,7 @@ import java.util.stream.IntStream;
62 @RequiredArgsConstructor 62 @RequiredArgsConstructor
63 public class DynamicToolProvider implements ToolProvider { 63 public class DynamicToolProvider implements ToolProvider {
64 64
65 -// private final ToolMetaMapper toolMetaMapper; 65 + // private final ToolMetaMapper toolMetaMapper;
66 private final ObjectMapper objectMapper; 66 private final ObjectMapper objectMapper;
67 private final ToolMetaMapper toolMetaMapper; 67 private final ToolMetaMapper toolMetaMapper;
68 private final ParamRuleMapper paramRuleMapper; 68 private final ParamRuleMapper paramRuleMapper;
@@ -111,7 +111,7 @@ public class DynamicToolProvider implements ToolProvider { @@ -111,7 +111,7 @@ public class DynamicToolProvider implements ToolProvider {
111 String sceneId = meta.getSSceneId(); 111 String sceneId = meta.getSSceneId();
112 List<ToolSpecificationHolder> dataList = new ArrayList<>(); 112 List<ToolSpecificationHolder> dataList = new ArrayList<>();
113 if(ObjectUtil.isNotEmpty(sceneToolCacheMap.get(sceneId))) { 113 if(ObjectUtil.isNotEmpty(sceneToolCacheMap.get(sceneId))) {
114 - dataList = sceneToolCacheMap.get(sceneId); 114 + dataList = sceneToolCacheMap.get(sceneId);
115 } 115 }
116 dataList.add(new ToolSpecificationHolder(spec, executor)); 116 dataList.add(new ToolSpecificationHolder(spec, executor));
117 sceneToolCacheMap.put(sceneId, dataList); 117 sceneToolCacheMap.put(sceneId, dataList);
@@ -141,7 +141,7 @@ public class DynamicToolProvider implements ToolProvider { @@ -141,7 +141,7 @@ public class DynamicToolProvider implements ToolProvider {
141 sAIshowfieldArry.add("sSlaveId"); 141 sAIshowfieldArry.add("sSlaveId");
142 String sSrcFormId = meta.getSSrcFormId(); 142 String sSrcFormId = meta.getSSrcFormId();
143 //获取对应的窗体配置 143 //获取对应的窗体配置
144 - StringBuffer sSql =new StringBuffer().append("SELECT A.sChinese AS label,A.sName,A.sControlName,B.sId AS sFormcustomId,A.sName AS sId FROM gdsconfigformslave AS A ") 144 + StringBuffer sSql =new StringBuffer().append("SELECT 10000 AS iOrderShow,A.sChinese AS label,A.sName,A.sControlName,B.sId AS sFormcustomId,A.sName AS sId FROM gdsconfigformslave AS A ")
145 .append("JOIN gdsconfigformmaster AS B ON A.sParentId = B.sId ") 145 .append("JOIN gdsconfigformmaster AS B ON A.sParentId = B.sId ")
146 .append("WHERE B.sParentId = #{sSrcFormId} AND A.sName <> '' AND INSTR(A.sControlName,'Btn')=0 AND (A.bVisible = 1 OR A.sName =#{sName}) "); 146 .append("WHERE B.sParentId = #{sSrcFormId} AND A.sName <> '' AND INSTR(A.sControlName,'Btn')=0 AND (A.bVisible = 1 OR A.sName =#{sName}) ");
147 Map<String,Object> searMap = new HashMap<>(); 147 Map<String,Object> searMap = new HashMap<>();
@@ -150,11 +150,17 @@ public class DynamicToolProvider implements ToolProvider { @@ -150,11 +150,17 @@ public class DynamicToolProvider implements ToolProvider {
150 List<Map<String,Object>> sAIshowfieldShowAll = dynamicExeDbService.findSql(searMap,sSql.toString()); 150 List<Map<String,Object>> sAIshowfieldShowAll = dynamicExeDbService.findSql(searMap,sSql.toString());
151 if(ObjectUtil.isNotEmpty(sAIshowfieldShowAll)){ 151 if(ObjectUtil.isNotEmpty(sAIshowfieldShowAll)){
152 sAIshowfieldShowAll = sAIshowfieldShowAll.stream().filter(m-> sAIshowfieldArry.contains(m.get("sName").toString())).collect(Collectors.toUnmodifiableList()); 152 sAIshowfieldShowAll = sAIshowfieldShowAll.stream().filter(m-> sAIshowfieldArry.contains(m.get("sName").toString())).collect(Collectors.toUnmodifiableList());
153 - meta.setSAIshowfieldShow(sAIshowfieldShowAll); 153 + sAIshowfieldShowAll.forEach(one->{
  154 + one.put("iOrderShow",sAIshowfieldArry.indexOf(one.get("sName").toString())+1);
  155 + });
  156 + List<Map<String,Object>> sAIshowfieldShowData = new ArrayList<>();
  157 + sAIshowfieldShowData.addAll(sAIshowfieldShowAll);
  158 + sAIshowfieldShowData.sort(Comparator.comparing(h -> Integer.valueOf(h.get("iOrderShow").toString())));
  159 + meta.setSAIshowfieldShow(sAIshowfieldShowData);
154 } 160 }
155 List<ParamRule> paramRuleListNew = new ArrayList<>(paramRuleList); 161 List<ParamRule> paramRuleListNew = new ArrayList<>(paramRuleList);
156 for(int i=0;i<sAIshowfieldShowAll.size();i++){ 162 for(int i=0;i<sAIshowfieldShowAll.size();i++){
157 - Map<String,Object> sAIshowfieldShow = sAIshowfieldShowAll.get(i); 163 + Map<String,Object> sAIshowfieldShow = sAIshowfieldShowAll.get(i);
158 List<ParamRule> one = paramRuleList.stream().filter(m->m.getSParamValue().equals(sAIshowfieldShow.get("sName"))).collect(Collectors.toUnmodifiableList()); 164 List<ParamRule> one = paramRuleList.stream().filter(m->m.getSParamValue().equals(sAIshowfieldShow.get("sName"))).collect(Collectors.toUnmodifiableList());
159 if(ObjectUtil.isEmpty(one)){ 165 if(ObjectUtil.isEmpty(one)){
160 ParamRule pr = new ParamRule(); 166 ParamRule pr = new ParamRule();
@@ -188,7 +194,7 @@ public class DynamicToolProvider implements ToolProvider { @@ -188,7 +194,7 @@ public class DynamicToolProvider implements ToolProvider {
188 // List<ToolSpecification> specs = new ArrayList<>(); 194 // List<ToolSpecification> specs = new ArrayList<>();
189 String sUserId = request.chatMemoryId().toString(); 195 String sUserId = request.chatMemoryId().toString();
190 Map<ToolSpecification, ToolExecutor> executors = new HashMap<>(); 196 Map<ToolSpecification, ToolExecutor> executors = new HashMap<>();
191 - // sceneToolCacheMap.get(sSceneIdMap.get(sUserId)); 197 + // sceneToolCacheMap.get(sSceneIdMap.get(sUserId));
192 //获取Session 198 //获取Session
193 UserSceneSession session = UserSceneSessionService.USER_SCENE_SESSION_CACHE.get(sUserId); 199 UserSceneSession session = UserSceneSessionService.USER_SCENE_SESSION_CACHE.get(sUserId);
194 //过滤对应的权限方法 200 //过滤对应的权限方法
@@ -240,7 +246,7 @@ public class DynamicToolProvider implements ToolProvider { @@ -240,7 +246,7 @@ public class DynamicToolProvider implements ToolProvider {
240 // 示例:{\"客户名称\":\"小羚羊软件开发有限公司\",\"产品名称\":\"企业宣传册\",\"数量\":1000,\"产品描述\":\"黑色注意色差\",\"生产要求\":\"上光,覆膜\"} 246 // 示例:{\"客户名称\":\"小羚羊软件开发有限公司\",\"产品名称\":\"企业宣传册\",\"数量\":1000,\"产品描述\":\"黑色注意色差\",\"生产要求\":\"上光,覆膜\"}
241 Map<String,Object> slMap = new HashMap<>(); 247 Map<String,Object> slMap = new HashMap<>();
242 for (ParamRule paramRule : paramRuleData) { 248 for (ParamRule paramRule : paramRuleData) {
243 - String paramName = ObjectUtil.isEmpty(paramRule.getSParamValue())?null:paramRule.getSParamValue(); 249 +// String paramName = ObjectUtil.isEmpty(paramRule.getSParamValue())?null:paramRule.getSParamValue();
244 String paramDesc = ObjectUtil.isEmpty(paramRule.getSParam())?null:paramRule.getSParam(); 250 String paramDesc = ObjectUtil.isEmpty(paramRule.getSParam())?null:paramRule.getSParam();
245 String paramType = paramRule.getSType(); 251 String paramType = paramRule.getSType();
246 Boolean bEmpty = paramRule.getBEmpty(); 252 Boolean bEmpty = paramRule.getBEmpty();
@@ -251,7 +257,7 @@ public class DynamicToolProvider implements ToolProvider { @@ -251,7 +257,7 @@ public class DynamicToolProvider implements ToolProvider {
251 //中文 257 //中文
252 slMap.put(paramDesc,sExampleValue); 258 slMap.put(paramDesc,sExampleValue);
253 } 259 }
254 - if (paramName == null || paramName.trim().isEmpty()) { 260 + if (paramDesc == null || paramDesc.trim().isEmpty()) {
255 continue; 261 continue;
256 } 262 }
257 // 构建参数属性 263 // 构建参数属性
@@ -335,7 +341,7 @@ public class DynamicToolProvider implements ToolProvider { @@ -335,7 +341,7 @@ public class DynamicToolProvider implements ToolProvider {
335 }else{ 341 }else{
336 sRuleCost = getArrrayBySql(paramRule); 342 sRuleCost = getArrrayBySql(paramRule);
337 } 343 }
338 - // eg: 付款方式(字符串,互斥枚举值[90天、60天、现结],默认值[现结]) 344 + // eg: 付款方式(字符串,互斥枚举值[90天、60天、现结],默认值[现结])
339 if(bEmpty){ 345 if(bEmpty){
340 sbt.append(paramDesc).append("(").append("字符串") .append(",互斥枚举值 [").append(sRuleCost).append("]"); 346 sbt.append(paramDesc).append("(").append("字符串") .append(",互斥枚举值 [").append(sRuleCost).append("]");
341 if(ObjectUtil.isNotEmpty(paramRule.getSDefaultValue())){ 347 if(ObjectUtil.isNotEmpty(paramRule.getSDefaultValue())){
@@ -369,9 +375,9 @@ public class DynamicToolProvider implements ToolProvider { @@ -369,9 +375,9 @@ public class DynamicToolProvider implements ToolProvider {
369 boolean required = bEmpty; 375 boolean required = bEmpty;
370 // 添加参数 376 // 添加参数
371 if (required) { 377 if (required) {
372 - builder.addParameter(paramName, properties); 378 + builder.addParameter(paramDesc, properties);
373 } else { 379 } else {
374 - builder.addOptionalParameter(paramName, properties); 380 + builder.addOptionalParameter(paramDesc, properties);
375 } 381 }
376 } 382 }
377 383
@@ -500,15 +506,14 @@ public class DynamicToolProvider implements ToolProvider { @@ -500,15 +506,14 @@ public class DynamicToolProvider implements ToolProvider {
500 log.warn("参数解析失败,tool={}, args={}", meta.getSMethodNo(), toolExecutionRequest.arguments(), e); 506 log.warn("参数解析失败,tool={}, args={}", meta.getSMethodNo(), toolExecutionRequest.arguments(), e);
501 return String.valueOf(errorResult(toolExecutionRequest, errorMsg)); 507 return String.valueOf(errorResult(toolExecutionRequest, errorMsg));
502 } 508 }
503 - Map<String, Object> argsOld = DeepCopyUtils.deepCopy(args);  
504 - 509 +// Map<String, Object> argsOld = DeepCopyUtils.deepCopy(args);
505 List<ParamRule> paramRuleData = meta.getParamRuleListAll(); 510 List<ParamRule> paramRuleData = meta.getParamRuleListAll();
506 // 2. 【自动补全】应用参数的默认值 511 // 2. 【自动补全】应用参数的默认值
507 args = applyDefaultValues(args, paramRuleData); 512 args = applyDefaultValues(args, paramRuleData);
508 513
509 // 2.1 【补全动态参数】动态参数补全 514 // 2.1 【补全动态参数】动态参数补全
510 try{ 515 try{
511 - args = applyValues(args, meta.getParamRuleListCheck()); 516 + args = applyValues(args, meta.getParamRuleListCheck());
512 }catch (Exception e){ 517 }catch (Exception e){
513 log.error("返回信息",e); 518 log.error("返回信息",e);
514 String sTsMsg = e.getMessage(); 519 String sTsMsg = e.getMessage();
@@ -554,7 +559,7 @@ public class DynamicToolProvider implements ToolProvider { @@ -554,7 +559,7 @@ public class DynamicToolProvider implements ToolProvider {
554 operableChatMemoryProvider.get(memoryId).add(UserMessage.from("SYSTEM: 等待用户确认或选择部分数据操作")); 559 operableChatMemoryProvider.get(memoryId).add(UserMessage.from("SYSTEM: 等待用户确认或选择部分数据操作"));
555 return String.valueOf(successResult(toolExecutionRequest,askconfirmMsg)); 560 return String.valueOf(successResult(toolExecutionRequest,askconfirmMsg));
556 }else{ 561 }else{
557 - askconfirmMsg =getDefMessage(argsOld,meta.getSControlName()); 562 + askconfirmMsg =getDefMessage(args,meta.getSControlName(),meta);
558 } 563 }
559 // 返回需要确认的结果 564 // 返回需要确认的结果
560 return executeWithConfirmation(toolExecutionRequest,askconfirmMsg,operableChatMemoryProvider.get(memoryId), session, meta).text(); 565 return executeWithConfirmation(toolExecutionRequest,askconfirmMsg,operableChatMemoryProvider.get(memoryId), session, meta).text();
@@ -567,17 +572,23 @@ public class DynamicToolProvider implements ToolProvider { @@ -567,17 +572,23 @@ public class DynamicToolProvider implements ToolProvider {
567 * @return java.lang.String 572 * @return java.lang.String
568 * @Description MAP转提示 573 * @Description MAP转提示
569 **/ 574 **/
570 - private String getDefMessage(Map<String,Object> argMap,String sName){ 575 + private String getDefMessage(Map<String,Object> argMap,String sName,ToolMeta meta){
  576 + List<ParamRule> showList = meta.getParamRuleListAll();
  577 + List<ParamRule> showListData = new ArrayList<>();
  578 + showList = showList.stream().filter(one->one.getBTipModel()).collect(Collectors.toUnmodifiableList());
  579 + showListData.addAll(showList);
  580 + showListData.sort(Comparator.comparing(h -> h.getIOrder()));
571 StringBuilder markdown = new StringBuilder().append("\n"); 581 StringBuilder markdown = new StringBuilder().append("\n");
572 markdown.append("\n---\n"); 582 markdown.append("\n---\n");
573 - // 遍历 Map 生成表格行  
574 - argMap.forEach((key, value) -> {  
575 - String valueStr = value != null ? value.toString() : "";  
576 - markdown.append("- ")  
577 - .append(key)  
578 - .append(": `")  
579 - .append(valueStr)  
580 - .append("`\n"); 583 + showListData.forEach(one->{
  584 + if(argMap.containsKey(one.getSParam())){
  585 + String valueStr = argMap.get(one.getSParam()) != null ? argMap.get(one.getSParam()).toString() : "";
  586 + markdown.append("- ")
  587 + .append(one.getSParam())
  588 + .append(": `")
  589 + .append(valueStr)
  590 + .append("`\n");
  591 + }
581 }); 592 });
582 markdown.append("\n---\n"); 593 markdown.append("\n---\n");
583 appendConfirm(markdown,sName); 594 appendConfirm(markdown,sName);
@@ -595,8 +606,8 @@ public class DynamicToolProvider implements ToolProvider { @@ -595,8 +606,8 @@ public class DynamicToolProvider implements ToolProvider {
595 markdown.append("请确认是否执行").append(sName).append("操作?如果全部,直接回复"全部确认",如果部分,选择后回复"部分确认"\n"); 606 markdown.append("请确认是否执行").append(sName).append("操作?如果全部,直接回复"全部确认",如果部分,选择后回复"部分确认"\n");
596 //全部确认 ,部分确认,取消 607 //全部确认 ,部分确认,取消
597 markdown.append("回复:&emsp;&emsp;").append("**<a href=\"#\" data-action=\"reset\" data-text=\"全部确认\">全部确认</a>**").append("&emsp;") 608 markdown.append("回复:&emsp;&emsp;").append("**<a href=\"#\" data-action=\"reset\" data-text=\"全部确认\">全部确认</a>**").append("&emsp;")
598 - .append("**<a href=\"#\" data-action=\"reset\" data-text=\"确认\">部分确认</a>**").append("&emsp;")  
599 - .append("**<a href=\"#\" data-action=\"reset\" data-text=\"取消\">取消</a>**"); 609 + .append("**<a href=\"#\" data-action=\"reset\" data-text=\"确认\">部分确认</a>**").append("&emsp;")
  610 + .append("**<a href=\"#\" data-action=\"reset\" data-text=\"取消\">取消</a>**");
600 } 611 }
601 612
602 /*** 613 /***
@@ -656,7 +667,7 @@ public class DynamicToolProvider implements ToolProvider { @@ -656,7 +667,7 @@ public class DynamicToolProvider implements ToolProvider {
656 } 667 }
657 }); 668 });
658 } 669 }
659 - }); 670 + });
660 return result; 671 return result;
661 } 672 }
662 673
@@ -711,6 +722,12 @@ public class DynamicToolProvider implements ToolProvider { @@ -711,6 +722,12 @@ public class DynamicToolProvider implements ToolProvider {
711 } 722 }
712 } 723 }
713 List<Map<String,Object>> dataListNew = dataList.stream().filter(one-> one.get(sValue).equals(args.get(name)) || one.get(sValue).equals(args.get(sValue))).collect(Collectors.toUnmodifiableList()); 724 List<Map<String,Object>> dataListNew = dataList.stream().filter(one-> one.get(sValue).equals(args.get(name)) || one.get(sValue).equals(args.get(sValue))).collect(Collectors.toUnmodifiableList());
  725 + //如果枚举类型枚举值中又不存在AI 返回的数据
  726 + if("enum".equals(sType) && ObjectUtil.isEmpty(dataListNew)){
  727 + args.remove(name);
  728 + args.remove(sValue);
  729 + continue;
  730 + }
714 if(ObjectUtil.isNotEmpty(dataListNew)){ 731 if(ObjectUtil.isNotEmpty(dataListNew)){
715 dataList = new ArrayList<>(); 732 dataList = new ArrayList<>();
716 dataList.add(dataListNew.get(0)); 733 dataList.add(dataListNew.get(0));
@@ -735,14 +752,14 @@ public class DynamicToolProvider implements ToolProvider { @@ -735,14 +752,14 @@ public class DynamicToolProvider implements ToolProvider {
735 if(dataList.size()>1){ 752 if(dataList.size()>1){
736 List<Map<String, Object>> finalDataList = dataList; 753 List<Map<String, Object>> finalDataList = dataList;
737 IntStream.range(0, dataList.size()) 754 IntStream.range(0, dataList.size())
738 - .forEach(iRowNum ->{  
739 - sData.append((iRowNum + 1)).append(".").append(finalDataList.get(iRowNum).get(pd.getSParamValue()))  
740 - .append("\n"); 755 + .forEach(iRowNum ->{
  756 + sData.append((iRowNum + 1)).append(".").append(finalDataList.get(iRowNum).get(pd.getSParamValue()))
  757 + .append("\n\n");
741 758
742 - }); 759 + });
743 String sParamMissMemo = StrUtil.EMPTY; 760 String sParamMissMemo = StrUtil.EMPTY;
744 if(ObjectUtil.isEmpty(pd.getSParamMissMemo())){ 761 if(ObjectUtil.isEmpty(pd.getSParamMissMemo())){
745 - sParamMissMemo = pd.getSParam()+"存在多个,请选择:"+sData; 762 + sParamMissMemo = pd.getSParam()+"存在多个,请选择:<br/>"+sData;
746 }else{ 763 }else{
747 sParamMissMemo = StrUtil.format(pd.getSParamMissMemo(),sData.toString()); 764 sParamMissMemo = StrUtil.format(pd.getSParamMissMemo(),sData.toString());
748 } 765 }
@@ -779,7 +796,7 @@ public class DynamicToolProvider implements ToolProvider { @@ -779,7 +796,7 @@ public class DynamicToolProvider implements ToolProvider {
779 .filter(pd -> Boolean.TRUE.equals(pd.getBEmpty()) && pd.getBTipModel()) 796 .filter(pd -> Boolean.TRUE.equals(pd.getBEmpty()) && pd.getBTipModel())
780 .filter(pd -> 797 .filter(pd ->
781 (!returnMap.containsKey(pd.getSParam()) || (ObjectUtil.isEmpty(returnMap.get(pd.getSParam())))) 798 (!returnMap.containsKey(pd.getSParam()) || (ObjectUtil.isEmpty(returnMap.get(pd.getSParam()))))
782 - && (!returnMap.containsKey(pd.getSParamValue()) || (ObjectUtil.isEmpty(returnMap.get(pd.getSParamValue())))) 799 + && (!returnMap.containsKey(pd.getSParamValue()) || (ObjectUtil.isEmpty(returnMap.get(pd.getSParamValue()))))
783 ) 800 )
784 .map(ParamRule::getSParam) 801 .map(ParamRule::getSParam)
785 .toList(); 802 .toList();
@@ -807,7 +824,7 @@ public class DynamicToolProvider implements ToolProvider { @@ -807,7 +824,7 @@ public class DynamicToolProvider implements ToolProvider {
807 log.info("执行工具:{},参数:{}", meta.getSMethodNo(), args); 824 log.info("执行工具:{},参数:{}", meta.getSMethodNo(), args);
808 // 2.2 将中文key转换成英文key 825 // 2.2 将中文key转换成英文key
809 args = transformationArgs( args, paramRuleData); 826 args = transformationArgs( args, paramRuleData);
810 - String sReturn ="成功"; 827 + String sReturn ="执行成功";
811 try{ 828 try{
812 sReturn = executeToolAfter(meta, args,toolExecutionRequest,paramRuleData,session); 829 sReturn = executeToolAfter(meta, args,toolExecutionRequest,paramRuleData,session);
813 }catch (Exception e) { 830 }catch (Exception e) {
@@ -827,55 +844,57 @@ public class DynamicToolProvider implements ToolProvider { @@ -827,55 +844,57 @@ public class DynamicToolProvider implements ToolProvider {
827 **/ 844 **/
828 private String executeToolAfter(ToolMeta meta, Map<String, Object> args,ToolExecutionRequest toolExecutionRequest,List<ParamRule> paramDefs,UserSceneSession session) { 845 private String executeToolAfter(ToolMeta meta, Map<String, Object> args,ToolExecutionRequest toolExecutionRequest,List<ParamRule> paramDefs,UserSceneSession session) {
829 // {"1":"存储过程","2":"SQL查询","3":"第三方API","4":"窗体查询","5":"按钮执行","6":"其它"} 846 // {"1":"存储过程","2":"SQL查询","3":"第三方API","4":"窗体查询","5":"按钮执行","6":"其它"}
830 - String sBizContent = meta.getSBizContent();  
831 - Integer iBizType = meta.getIBizType();  
832 - args.put("sUserId",session.getUserId());  
833 - if(iBizType==1 || iBizType==4){  
834 - Map<String,Object> data = new HashMap<>(args);  
835 - data.put("sData", JSONObject.toJSONString(data));  
836 - Map<String, Object> searMap = this.dynamicExeDbService.getDoProMap(sBizContent, data);  
837 - Map<String,Object> sReturn = this.dynamicExeDbService.getCallPro(searMap,sBizContent);  
838 - Integer sCode = ObjectUtil.isNotEmpty(sReturn.get(ProcedureConstant.SCODE))? Integer.valueOf(sReturn.get(ProcedureConstant.SCODE).toString()):0;  
839 - String sMsgText = ObjectUtil.isNotEmpty(sReturn.get(ProcedureConstant.SRETURN))? sReturn.get(ProcedureConstant.SRETURN).toString():"操作成功";  
840 - if(sCode< 0){  
841 - String msg = ObjectUtil.isEmpty(sMsgText) ?"调用过程sCode:"+Integer.valueOf(searMap.get(ProcedureConstant.SCODE).toString()):sMsgText;  
842 - return String.valueOf(askUserResult(toolExecutionRequest, msg));  
843 - }  
844 - return String.valueOf(successResult(toolExecutionRequest, sMsgText));  
845 - }else if(iBizType==2 && ObjectUtil.isNotEmpty(sBizContent)){  
846 - //SQL查询  
847 - if(sBizContent.toLowerCase().startsWith("update")){  
848 - this.dynamicExeDbService.updateSql(args,sBizContent);  
849 - }else if(sBizContent.toLowerCase().startsWith("delete")){  
850 - this.dynamicExeDbService.delSql(args,sBizContent);  
851 - }else if(sBizContent.toLowerCase().startsWith("insert")){  
852 - this.dynamicExeDbService.addSql(args,sBizContent);  
853 - }else{  
854 - List<Map<String,Object>> retData = this.dynamicExeDbService.findSql(args,sBizContent);  
855 - if(ObjectUtil.isNotEmpty(retData)){  
856 - StringBuffer sb = new StringBuffer();  
857 - retData.forEach(one->{  
858 - one.forEach((k,v)->{  
859 - sb.append(v).append(" ");  
860 - });  
861 - sb.append("<br/>");  
862 - });  
863 - if(ObjectUtil.isNotEmpty(retData)){  
864 - sb.append("请根据这些信息安排今天的工作吧!如果有具体任务需要进一步处理,请告诉我");  
865 - }  
866 - session.setSFunPrompts(sb.toString());  
867 - if("queryTodayTask".equals(meta.getSMethodNo())){  
868 - session.setBCleanMemory(true);  
869 - }  
870 - return String.valueOf(successResult(toolExecutionRequest, sb.toString()));  
871 - }else{  
872 - return String.valueOf(askUserResult(toolExecutionRequest, "未找到对应的数据"));  
873 - }  
874 - }  
875 - }else if(iBizType==3){  
876 - return HttpsRequestUtil.me().doRequestHttp(sBizContent,JSONUtil.toJsonStr(args),  
877 - new HashMap<>(),"POST","JSON");  
878 - } 847 + String sBizContent = meta.getSBizContent();
  848 + Integer iBizType = meta.getIBizType();
  849 + args.put("sUserId",session.getUserId());
  850 + if(iBizType==1 || iBizType==4){
  851 + Map<String,Object> data = new HashMap<>(args);
  852 + data.put("sData", JSONObject.toJSONString(data));
  853 + Map<String, Object> searMap = this.dynamicExeDbService.getDoProMap(sBizContent, data);
  854 + Map<String,Object> sReturn = this.dynamicExeDbService.getCallPro(searMap,sBizContent);
  855 + Integer sCode = ObjectUtil.isNotEmpty(sReturn.get(ProcedureConstant.SCODE))? Integer.valueOf(sReturn.get(ProcedureConstant.SCODE).toString()):0;
  856 + String sMsgText = ObjectUtil.isNotEmpty(sReturn.get(ProcedureConstant.SRETURN))? sReturn.get(ProcedureConstant.SRETURN).toString():"操作成功";
  857 + if(sCode< 0){
  858 + String msg = ObjectUtil.isEmpty(sMsgText) ?"调用过程sCode:"+Integer.valueOf(searMap.get(ProcedureConstant.SCODE).toString()):sMsgText;
  859 + return String.valueOf(askUserResult(toolExecutionRequest, msg));
  860 + }
  861 + session.setSFunPrompts(sMsgText);
  862 + return sMsgText;
  863 + }else if(iBizType==2 && ObjectUtil.isNotEmpty(sBizContent)){
  864 + //SQL查询
  865 + if(sBizContent.toLowerCase().startsWith("update")){
  866 + this.dynamicExeDbService.updateSql(args,sBizContent);
  867 + }else if(sBizContent.toLowerCase().startsWith("delete")){
  868 + this.dynamicExeDbService.delSql(args,sBizContent);
  869 + }else if(sBizContent.toLowerCase().startsWith("insert")){
  870 + this.dynamicExeDbService.addSql(args,sBizContent);
  871 + }else{
  872 + List<Map<String,Object>> retData = this.dynamicExeDbService.findSql(args,sBizContent);
  873 + if(ObjectUtil.isNotEmpty(retData)){
  874 + StringBuffer sb = new StringBuffer();
  875 + retData.forEach(one->{
  876 + one.forEach((k,v)->{
  877 + sb.append(v).append(" ");
  878 + });
  879 + sb.append("<br/>");
  880 + });
  881 + if(ObjectUtil.isNotEmpty(retData)){
  882 + sb.append("请根据这些信息安排今天的工作吧!如果有具体任务需要进一步处理,请告诉我");
  883 + }
  884 + session.setSFunPrompts(sb.toString());
  885 + if("queryTodayTask".equals(meta.getSMethodNo())){
  886 + session.setBCleanMemory(true);
  887 + }
  888 + return String.valueOf(successResult(toolExecutionRequest, sb.toString()));
  889 + }else{
  890 + session.setSFunPrompts("未找到对应的数据");
  891 + return "未找到对应的数据";
  892 + }
  893 + }
  894 + }else if(iBizType==3){
  895 + return HttpsRequestUtil.me().doRequestHttp(sBizContent,JSONUtil.toJsonStr(args),
  896 + new HashMap<>(),"POST","JSON");
  897 + }
879 return String.valueOf(successResult(toolExecutionRequest, "操作成功")); 898 return String.valueOf(successResult(toolExecutionRequest, "操作成功"));
880 } 899 }
881 900
@@ -1056,7 +1075,7 @@ public class DynamicToolProvider implements ToolProvider { @@ -1056,7 +1075,7 @@ public class DynamicToolProvider implements ToolProvider {
1056 .filter(Objects::nonNull) 1075 .filter(Objects::nonNull)
1057 .collect(Collectors.toList()); 1076 .collect(Collectors.toList());
1058 } 1077 }
1059 - 1078 +
1060 /** 1079 /**
1061 * 构建确认操作消息 1080 * 构建确认操作消息
1062 */ 1081 */
src/main/java/com/xly/tts/service/PythonTtsProxyService.java
@@ -4,6 +4,7 @@ import cn.hutool.core.util.ObjectUtil; @@ -4,6 +4,7 @@ import cn.hutool.core.util.ObjectUtil;
4 import cn.hutool.core.util.StrUtil; 4 import cn.hutool.core.util.StrUtil;
5 import com.xly.constant.ReturnTypeCode; 5 import com.xly.constant.ReturnTypeCode;
6 import com.xly.entity.AiResponseDTO; 6 import com.xly.entity.AiResponseDTO;
  7 +import com.xly.service.UserSceneSessionService;
7 import com.xly.service.XlyErpService; 8 import com.xly.service.XlyErpService;
8 import com.xly.tts.bean.*; 9 import com.xly.tts.bean.*;
9 import com.xly.util.AdvancedSymbolRemover; 10 import com.xly.util.AdvancedSymbolRemover;
@@ -40,6 +41,8 @@ public class PythonTtsProxyService { @@ -40,6 +41,8 @@ public class PythonTtsProxyService {
40 41
41 private final XlyErpService xlyErpService; 42 private final XlyErpService xlyErpService;
42 43
  44 + private final UserSceneSessionService userSceneSessionService;
  45 +
43 @PostConstruct 46 @PostConstruct
44 public void init() { 47 public void init() {
45 executorService = Executors.newFixedThreadPool(5); 48 executorService = Executors.newFixedThreadPool(5);
@@ -86,6 +89,8 @@ public class PythonTtsProxyService { @@ -86,6 +89,8 @@ public class PythonTtsProxyService {
86 String sUserId = request.getUserid(); 89 String sUserId = request.getUserid();
87 String sUserType = request.getUsertype(); 90 String sUserType = request.getUsertype();
88 String authorization = request.getAuthorization(); 91 String authorization = request.getAuthorization();
  92 + //清空记忆
  93 + userSceneSessionService.cleanUserSession(sUserId);
89 // xlyErpService.initSceneGuide(sUserId,sUserType,StrUtil.EMPTY) 94 // xlyErpService.initSceneGuide(sUserId,sUserType,StrUtil.EMPTY)
90 AiResponseDTO voiceText = xlyErpService.initSceneGuide(StrUtil.EMPTY,sUserId,sUserType, authorization); 95 AiResponseDTO voiceText = xlyErpService.initSceneGuide(StrUtil.EMPTY,sUserId,sUserType, authorization);
91 voiceText.setSReturnType(ReturnTypeCode.HTML.getCode()); 96 voiceText.setSReturnType(ReturnTypeCode.HTML.getCode());
src/main/resources/templates/chat.html
@@ -461,12 +461,12 @@ @@ -461,12 +461,12 @@
461 461
462 <script> 462 <script>
463 let sessionId =""; 463 let sessionId ="";
464 - let userid= "17706006510007934913359242990000";  
465 - // let userid= "17502321750004978169421209637000";  
466 - // let usertype= "sysadmin";  
467 - let usertype= "General";  
468 - let authorization= "B52FF9DBEF24EA7F40A160E78A3AFF39D42BEDC4D9CB33A32B7BE6B68F15AF74F3419238942A93E9AD666629E18D159AF7FE144A6407DE745BA0AEC8B235FC1D686C9F04512DE45F9E176530AFD123789C9A98822AD3F0E3100F8DBBB5963377538155B7ADAEE71E899235DC1122F426";  
469 - // let authorization= "1EDB99C9BF070115F7A57AC43D8CB09F0B8C49F979DAB63A2AEA84B372B2B42BF3419238942A93E9AD666629E18D159AF7FE144A6407DE745BA0AEC8B235FC1D7755CEF7BCCED5C5F3A6D8323EB6C67929D9BB4A0103841ED6E33C9191B264BF538155B7ADAEE71E899235DC1122F426"; 464 + // let userid= "17706006510007934913359242990000";
  465 + let userid= "17502321750004978169421209637000";
  466 + let usertype= "sysadmin";
  467 + // let usertype= "General";
  468 + let authorization="1EDB99C9BF070115F7A57AC43D8CB09F0B8C49F979DAB63A2AEA84B372B2B42BF3419238942A93E9AD666629E18D159AF7FE144A6407DE745BA0AEC8B235FC1D2D86C92E4DCE571A8ECF0767494BBDE2495FD8E662F2065F9430347C7E4472B5538155B7ADAEE71E899235DC1122F426";
  469 + //"1EDB99C9BF070115F7A57AC43D8CB09F0B8C49F979DAB63A2AEA84B372B2B42BF3419238942A93E9AD666629E18D159AF7FE144A6407DE745BA0AEC8B235FC1DC16A7526DEC4395CF09285C2BD330B9FD8668502224FF2D5675E74B8CDD2ABFB538155B7ADAEE71E899235DC1122F426";
470 let hrefLock = window.location.origin+"/xlyAi"; 470 let hrefLock = window.location.origin+"/xlyAi";
471 // ==================== 配置部分 ==================== 471 // ==================== 配置部分 ====================
472 const CONFIG = { 472 const CONFIG = {