Commit 51694876c0e31062ff1a33d5d5afd50e647dad2b
1 parent
f3eace43
1111
Showing
11 changed files
with
142 additions
and
96 deletions
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 | 25 | 3.1 多表关联必须使用 表名+字段名(如表名.字段名),严格按下面[涉及表名]中的表次序关联,聚合函数(SUM/COUNT/AVG/MIN/MAX)必须加业务化别名,日期过滤使用标准DATE格式(yyyy-MM-dd); |
| 26 | 26 | 3.2 SQL所有字段均采用 表名.字段名 方式生成,务必确保 字段名 在相应的 表名 描述的字段中存在,如果不存在重试其它方式,直到满足条件 |
| 27 | 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 | 30 | 4. 安全约束:禁止生成任何DDL/DML语句(DROP/ALTER/INSERT/UPDATE/DELETE等),禁止使用子查询、存储过程、自定义函数、临时表; |
| 30 | - 5. 精准性:严格按用户需求+传入的表结构生成,仅使用指定字段/表,无多余字段、无无效表关联、无冗余过滤条件; | |
| 31 | + 5. 精准性: | |
| 32 | + 5.1 严格按用户需求+传入的表结构生成,仅使用指定字段/表,无多余字段、无无效表关联、无冗余过滤条件; | |
| 33 | + 5.2 用户需求中没有明确的日期条件,默认为全部数据,禁止增加任何日期过滤条件 | |
| 31 | 34 | 6. 关联规则:多表关联时,必须使用外键/业务唯一键关联,禁止无意义关联。 |
| 32 | 35 | """) |
| 33 | 36 | @UserMessage(""" | ... | ... |
src/main/java/com/xly/agent/ErpAiAgent.java
| ... | ... | @@ -14,7 +14,9 @@ public interface ErpAiAgent { |
| 14 | 14 | 你是一个专业的 工具方法匹配与参数提取 助手,核心职责是根据用户输入(含历史对话)精准匹配工具方法、提取参数、判断缺失并生成交互式补全提示; |
| 15 | 15 | 按严格按以下步骤处理,无任何额外输出!规则如下: |
| 16 | 16 | 1. 方法匹配:先精准拆解用户查询的核心业务意图,再自动匹配唯一符合用户问题的工具方法(MethodNo),禁止自创; |
| 17 | - 2. 参数提取:提取该工具的全部参数,与描述完全一致,严格按标注类型赋值,数字无引号,为空时禁止赋值0; | |
| 17 | + 2. 参数提取:提取该工具的全部参数,与描述完全一致,严格按标注类型赋值,规则如下: | |
| 18 | + 2.1 数字无引号,为空时禁止赋值0; | |
| 19 | + 2.2 如果有空格需要去掉空格后再提取。 | |
| 18 | 20 | """) |
| 19 | 21 | @UserMessage("用户输入:{{userInput}}") |
| 20 | 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 | 12 | public interface AiToolDetailParamsMapper { |
| 13 | 13 | |
| 14 | 14 | // XML配置方式 |
| 15 | - @Select("SELECT * FROM ai_tool_detail_params") | |
| 15 | + @Select("SELECT * FROM ai_tool_detail_params ORDER BY iOrder,iIncrement ") | |
| 16 | 16 | List<ParamRule> findAll(); |
| 17 | 17 | } |
| 18 | 18 | \ No newline at end of file | ... | ... |
src/main/java/com/xly/service/UserSceneSessionService.java
| ... | ... | @@ -75,6 +75,21 @@ public class UserSceneSessionService { |
| 75 | 75 | CHAT_AGENT_CACHE.clear(); |
| 76 | 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 | 93 | public UserSceneSession getUserSceneSession(String sUserId, String sUserType,String authorization){ |
| 79 | 94 | if (USER_SCENE_SESSION_CACHE.containsKey(sUserId)) { |
| 80 | 95 | return USER_SCENE_SESSION_CACHE.get(sUserId); | ... | ... |
src/main/java/com/xly/service/XlyErpService.java
| ... | ... | @@ -111,6 +111,7 @@ public class XlyErpService { |
| 111 | 111 | ){ |
| 112 | 112 | sResponMessage = getDynamicTableSql(session, input, userId, userInput); |
| 113 | 113 | } |
| 114 | + | |
| 114 | 115 | //如果返回空的进入闲聊模式 |
| 115 | 116 | if (ObjectUtil.isEmpty(sResponMessage)){ |
| 116 | 117 | return getChatiAgent (input, session); |
| ... | ... | @@ -259,6 +260,8 @@ public class XlyErpService { |
| 259 | 260 | .toolProvider(dynamicToolProvider) |
| 260 | 261 | .build(); |
| 261 | 262 | UserSceneSessionService.ERP_AGENT_CACHE.put(userId, aiAgent); |
| 263 | +// 初始化AiService 以防止热加载太慢 找不到相应的方法 | |
| 264 | + aiAgent.chat(userId, "initAiService"); | |
| 262 | 265 | log.info("用户{}Agent构建完成,已选场景:{},场景ID{}", |
| 263 | 266 | userId, session.isSceneSelected() ? session.getCurrentScene().getSSceneName() : "未选(全场景匹配)", dynamicToolProvider.sSceneIdMap.get(userId)); |
| 264 | 267 | } |
| ... | ... | @@ -353,8 +356,7 @@ public class XlyErpService { |
| 353 | 356 | .build(); |
| 354 | 357 | UserSceneSessionService.CHAT_AGENT_CACHE.put(session.getUserId(), chatiAgent); } |
| 355 | 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 | 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 | 62 | @RequiredArgsConstructor |
| 63 | 63 | public class DynamicToolProvider implements ToolProvider { |
| 64 | 64 | |
| 65 | -// private final ToolMetaMapper toolMetaMapper; | |
| 65 | + // private final ToolMetaMapper toolMetaMapper; | |
| 66 | 66 | private final ObjectMapper objectMapper; |
| 67 | 67 | private final ToolMetaMapper toolMetaMapper; |
| 68 | 68 | private final ParamRuleMapper paramRuleMapper; |
| ... | ... | @@ -111,7 +111,7 @@ public class DynamicToolProvider implements ToolProvider { |
| 111 | 111 | String sceneId = meta.getSSceneId(); |
| 112 | 112 | List<ToolSpecificationHolder> dataList = new ArrayList<>(); |
| 113 | 113 | if(ObjectUtil.isNotEmpty(sceneToolCacheMap.get(sceneId))) { |
| 114 | - dataList = sceneToolCacheMap.get(sceneId); | |
| 114 | + dataList = sceneToolCacheMap.get(sceneId); | |
| 115 | 115 | } |
| 116 | 116 | dataList.add(new ToolSpecificationHolder(spec, executor)); |
| 117 | 117 | sceneToolCacheMap.put(sceneId, dataList); |
| ... | ... | @@ -141,7 +141,7 @@ public class DynamicToolProvider implements ToolProvider { |
| 141 | 141 | sAIshowfieldArry.add("sSlaveId"); |
| 142 | 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 | 145 | .append("JOIN gdsconfigformmaster AS B ON A.sParentId = B.sId ") |
| 146 | 146 | .append("WHERE B.sParentId = #{sSrcFormId} AND A.sName <> '' AND INSTR(A.sControlName,'Btn')=0 AND (A.bVisible = 1 OR A.sName =#{sName}) "); |
| 147 | 147 | Map<String,Object> searMap = new HashMap<>(); |
| ... | ... | @@ -150,11 +150,17 @@ public class DynamicToolProvider implements ToolProvider { |
| 150 | 150 | List<Map<String,Object>> sAIshowfieldShowAll = dynamicExeDbService.findSql(searMap,sSql.toString()); |
| 151 | 151 | if(ObjectUtil.isNotEmpty(sAIshowfieldShowAll)){ |
| 152 | 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 | 161 | List<ParamRule> paramRuleListNew = new ArrayList<>(paramRuleList); |
| 156 | 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 | 164 | List<ParamRule> one = paramRuleList.stream().filter(m->m.getSParamValue().equals(sAIshowfieldShow.get("sName"))).collect(Collectors.toUnmodifiableList()); |
| 159 | 165 | if(ObjectUtil.isEmpty(one)){ |
| 160 | 166 | ParamRule pr = new ParamRule(); |
| ... | ... | @@ -188,7 +194,7 @@ public class DynamicToolProvider implements ToolProvider { |
| 188 | 194 | // List<ToolSpecification> specs = new ArrayList<>(); |
| 189 | 195 | String sUserId = request.chatMemoryId().toString(); |
| 190 | 196 | Map<ToolSpecification, ToolExecutor> executors = new HashMap<>(); |
| 191 | - // sceneToolCacheMap.get(sSceneIdMap.get(sUserId)); | |
| 197 | + // sceneToolCacheMap.get(sSceneIdMap.get(sUserId)); | |
| 192 | 198 | //获取Session |
| 193 | 199 | UserSceneSession session = UserSceneSessionService.USER_SCENE_SESSION_CACHE.get(sUserId); |
| 194 | 200 | //过滤对应的权限方法 |
| ... | ... | @@ -240,7 +246,7 @@ public class DynamicToolProvider implements ToolProvider { |
| 240 | 246 | // 示例:{\"客户名称\":\"小羚羊软件开发有限公司\",\"产品名称\":\"企业宣传册\",\"数量\":1000,\"产品描述\":\"黑色注意色差\",\"生产要求\":\"上光,覆膜\"} |
| 241 | 247 | Map<String,Object> slMap = new HashMap<>(); |
| 242 | 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 | 250 | String paramDesc = ObjectUtil.isEmpty(paramRule.getSParam())?null:paramRule.getSParam(); |
| 245 | 251 | String paramType = paramRule.getSType(); |
| 246 | 252 | Boolean bEmpty = paramRule.getBEmpty(); |
| ... | ... | @@ -251,7 +257,7 @@ public class DynamicToolProvider implements ToolProvider { |
| 251 | 257 | //中文 |
| 252 | 258 | slMap.put(paramDesc,sExampleValue); |
| 253 | 259 | } |
| 254 | - if (paramName == null || paramName.trim().isEmpty()) { | |
| 260 | + if (paramDesc == null || paramDesc.trim().isEmpty()) { | |
| 255 | 261 | continue; |
| 256 | 262 | } |
| 257 | 263 | // 构建参数属性 |
| ... | ... | @@ -335,7 +341,7 @@ public class DynamicToolProvider implements ToolProvider { |
| 335 | 341 | }else{ |
| 336 | 342 | sRuleCost = getArrrayBySql(paramRule); |
| 337 | 343 | } |
| 338 | - // eg: 付款方式(字符串,互斥枚举值[90天、60天、现结],默认值[现结]) | |
| 344 | + // eg: 付款方式(字符串,互斥枚举值[90天、60天、现结],默认值[现结]) | |
| 339 | 345 | if(bEmpty){ |
| 340 | 346 | sbt.append(paramDesc).append("(").append("字符串") .append(",互斥枚举值 [").append(sRuleCost).append("]"); |
| 341 | 347 | if(ObjectUtil.isNotEmpty(paramRule.getSDefaultValue())){ |
| ... | ... | @@ -369,9 +375,9 @@ public class DynamicToolProvider implements ToolProvider { |
| 369 | 375 | boolean required = bEmpty; |
| 370 | 376 | // 添加参数 |
| 371 | 377 | if (required) { |
| 372 | - builder.addParameter(paramName, properties); | |
| 378 | + builder.addParameter(paramDesc, properties); | |
| 373 | 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 | 506 | log.warn("参数解析失败,tool={}, args={}", meta.getSMethodNo(), toolExecutionRequest.arguments(), e); |
| 501 | 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 | 510 | List<ParamRule> paramRuleData = meta.getParamRuleListAll(); |
| 506 | 511 | // 2. 【自动补全】应用参数的默认值 |
| 507 | 512 | args = applyDefaultValues(args, paramRuleData); |
| 508 | 513 | |
| 509 | 514 | // 2.1 【补全动态参数】动态参数补全 |
| 510 | 515 | try{ |
| 511 | - args = applyValues(args, meta.getParamRuleListCheck()); | |
| 516 | + args = applyValues(args, meta.getParamRuleListCheck()); | |
| 512 | 517 | }catch (Exception e){ |
| 513 | 518 | log.error("返回信息",e); |
| 514 | 519 | String sTsMsg = e.getMessage(); |
| ... | ... | @@ -554,7 +559,7 @@ public class DynamicToolProvider implements ToolProvider { |
| 554 | 559 | operableChatMemoryProvider.get(memoryId).add(UserMessage.from("SYSTEM: 等待用户确认或选择部分数据操作")); |
| 555 | 560 | return String.valueOf(successResult(toolExecutionRequest,askconfirmMsg)); |
| 556 | 561 | }else{ |
| 557 | - askconfirmMsg =getDefMessage(argsOld,meta.getSControlName()); | |
| 562 | + askconfirmMsg =getDefMessage(args,meta.getSControlName(),meta); | |
| 558 | 563 | } |
| 559 | 564 | // 返回需要确认的结果 |
| 560 | 565 | return executeWithConfirmation(toolExecutionRequest,askconfirmMsg,operableChatMemoryProvider.get(memoryId), session, meta).text(); |
| ... | ... | @@ -567,17 +572,23 @@ public class DynamicToolProvider implements ToolProvider { |
| 567 | 572 | * @return java.lang.String |
| 568 | 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 | 581 | StringBuilder markdown = new StringBuilder().append("\n"); |
| 572 | 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 | 593 | markdown.append("\n---\n"); |
| 583 | 594 | appendConfirm(markdown,sName); |
| ... | ... | @@ -595,8 +606,8 @@ public class DynamicToolProvider implements ToolProvider { |
| 595 | 606 | markdown.append("请确认是否执行").append(sName).append("操作?如果全部,直接回复"全部确认",如果部分,选择后回复"部分确认"\n"); |
| 596 | 607 | //全部确认 ,部分确认,取消 |
| 597 | 608 | markdown.append("回复:  ").append("**<a href=\"#\" data-action=\"reset\" data-text=\"全部确认\">全部确认</a>**").append(" ") |
| 598 | - .append("**<a href=\"#\" data-action=\"reset\" data-text=\"确认\">部分确认</a>**").append(" ") | |
| 599 | - .append("**<a href=\"#\" data-action=\"reset\" data-text=\"取消\">取消</a>**"); | |
| 609 | + .append("**<a href=\"#\" data-action=\"reset\" data-text=\"确认\">部分确认</a>**").append(" ") | |
| 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 | 667 | } |
| 657 | 668 | }); |
| 658 | 669 | } |
| 659 | - }); | |
| 670 | + }); | |
| 660 | 671 | return result; |
| 661 | 672 | } |
| 662 | 673 | |
| ... | ... | @@ -711,6 +722,12 @@ public class DynamicToolProvider implements ToolProvider { |
| 711 | 722 | } |
| 712 | 723 | } |
| 713 | 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 | 731 | if(ObjectUtil.isNotEmpty(dataListNew)){ |
| 715 | 732 | dataList = new ArrayList<>(); |
| 716 | 733 | dataList.add(dataListNew.get(0)); |
| ... | ... | @@ -735,14 +752,14 @@ public class DynamicToolProvider implements ToolProvider { |
| 735 | 752 | if(dataList.size()>1){ |
| 736 | 753 | List<Map<String, Object>> finalDataList = dataList; |
| 737 | 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 | 760 | String sParamMissMemo = StrUtil.EMPTY; |
| 744 | 761 | if(ObjectUtil.isEmpty(pd.getSParamMissMemo())){ |
| 745 | - sParamMissMemo = pd.getSParam()+"存在多个,请选择:"+sData; | |
| 762 | + sParamMissMemo = pd.getSParam()+"存在多个,请选择:<br/>"+sData; | |
| 746 | 763 | }else{ |
| 747 | 764 | sParamMissMemo = StrUtil.format(pd.getSParamMissMemo(),sData.toString()); |
| 748 | 765 | } |
| ... | ... | @@ -779,7 +796,7 @@ public class DynamicToolProvider implements ToolProvider { |
| 779 | 796 | .filter(pd -> Boolean.TRUE.equals(pd.getBEmpty()) && pd.getBTipModel()) |
| 780 | 797 | .filter(pd -> |
| 781 | 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 | 801 | .map(ParamRule::getSParam) |
| 785 | 802 | .toList(); |
| ... | ... | @@ -807,7 +824,7 @@ public class DynamicToolProvider implements ToolProvider { |
| 807 | 824 | log.info("执行工具:{},参数:{}", meta.getSMethodNo(), args); |
| 808 | 825 | // 2.2 将中文key转换成英文key |
| 809 | 826 | args = transformationArgs( args, paramRuleData); |
| 810 | - String sReturn ="成功"; | |
| 827 | + String sReturn ="执行成功"; | |
| 811 | 828 | try{ |
| 812 | 829 | sReturn = executeToolAfter(meta, args,toolExecutionRequest,paramRuleData,session); |
| 813 | 830 | }catch (Exception e) { |
| ... | ... | @@ -827,55 +844,57 @@ public class DynamicToolProvider implements ToolProvider { |
| 827 | 844 | **/ |
| 828 | 845 | private String executeToolAfter(ToolMeta meta, Map<String, Object> args,ToolExecutionRequest toolExecutionRequest,List<ParamRule> paramDefs,UserSceneSession session) { |
| 829 | 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 | 898 | return String.valueOf(successResult(toolExecutionRequest, "操作成功")); |
| 880 | 899 | } |
| 881 | 900 | |
| ... | ... | @@ -1056,7 +1075,7 @@ public class DynamicToolProvider implements ToolProvider { |
| 1056 | 1075 | .filter(Objects::nonNull) |
| 1057 | 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 | 4 | import cn.hutool.core.util.StrUtil; |
| 5 | 5 | import com.xly.constant.ReturnTypeCode; |
| 6 | 6 | import com.xly.entity.AiResponseDTO; |
| 7 | +import com.xly.service.UserSceneSessionService; | |
| 7 | 8 | import com.xly.service.XlyErpService; |
| 8 | 9 | import com.xly.tts.bean.*; |
| 9 | 10 | import com.xly.util.AdvancedSymbolRemover; |
| ... | ... | @@ -40,6 +41,8 @@ public class PythonTtsProxyService { |
| 40 | 41 | |
| 41 | 42 | private final XlyErpService xlyErpService; |
| 42 | 43 | |
| 44 | + private final UserSceneSessionService userSceneSessionService; | |
| 45 | + | |
| 43 | 46 | @PostConstruct |
| 44 | 47 | public void init() { |
| 45 | 48 | executorService = Executors.newFixedThreadPool(5); |
| ... | ... | @@ -86,6 +89,8 @@ public class PythonTtsProxyService { |
| 86 | 89 | String sUserId = request.getUserid(); |
| 87 | 90 | String sUserType = request.getUsertype(); |
| 88 | 91 | String authorization = request.getAuthorization(); |
| 92 | + //清空记忆 | |
| 93 | + userSceneSessionService.cleanUserSession(sUserId); | |
| 89 | 94 | // xlyErpService.initSceneGuide(sUserId,sUserType,StrUtil.EMPTY) |
| 90 | 95 | AiResponseDTO voiceText = xlyErpService.initSceneGuide(StrUtil.EMPTY,sUserId,sUserType, authorization); |
| 91 | 96 | voiceText.setSReturnType(ReturnTypeCode.HTML.getCode()); | ... | ... |
src/main/resources/templates/chat.html
| ... | ... | @@ -461,12 +461,12 @@ |
| 461 | 461 | |
| 462 | 462 | <script> |
| 463 | 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 | 470 | let hrefLock = window.location.origin+"/xlyAi"; |
| 471 | 471 | // ==================== 配置部分 ==================== |
| 472 | 472 | const CONFIG = { | ... | ... |