Commit a3e3d13989a505e3f50c1f87e48c99130946e2cb
1 parent
6886121d
AI添加问题 历史问题记录
Showing
5 changed files
with
246 additions
and
183 deletions
src/main/java/com/xly/agent/ErpAiAgent.java
| ... | ... | @@ -14,14 +14,23 @@ public interface ErpAiAgent { |
| 14 | 14 | 1. 方法匹配:先精准拆解用户查询的核心业务意图,再自动匹配唯一符合用户问题的工具方法(MethodNo),禁止自创,规则如下; |
| 15 | 15 | 1.1 匹配方法时,无需考虑工具描述(@TOOL)中 1.必填参数,2.选填参数,示例,parameters内容 四个部分的内容; |
| 16 | 16 | 1.2 匹配方法时,只关注工具描述(@TOOL)中 “当用户” 和 “时,必须调用本工具”两个短语之间的内容; |
| 17 | - 1.3 调用工具前,不需要询问用户提供缺失的参数 | |
| 18 | 17 | 2. 参数提取:提取该工具的全部参数,与描述完全一致,严格按标注类型赋值,规则如下: |
| 19 | 18 | 2.1 数字无引号,为空时禁止赋值0; |
| 20 | 19 | 2.2 如果有空格需要去掉空格后再提取。 |
| 20 | + 2.3 每次都需要进行参数提取 | |
| 21 | 21 | """) |
| 22 | 22 | @UserMessage("用户输入:{{userInput}}") |
| 23 | 23 | String chat(@MemoryId String userId, @V("userInput") String userInput); |
| 24 | 24 | |
| 25 | + @SystemMessage("{{stoolDesc}}") | |
| 26 | + @UserMessage("用户输入:{{userInput}}") | |
| 27 | + String chatCurrentTool(@MemoryId String userId, | |
| 28 | + @V("userInput") String userInput, | |
| 29 | + @V("sMethodNo") String sMethodNo, | |
| 30 | + @V("sMethodName") String sMethodName, | |
| 31 | + @V("stoolDesc") String stoolDesc | |
| 32 | + ); | |
| 33 | + | |
| 25 | 34 | /** |
| 26 | 35 | * 动态表结构:自然语言解释SQL执行结果 |
| 27 | 36 | * 入参:用户问题、执行的SQL、表结构、JSON格式结果 | ... | ... |
src/main/java/com/xly/entity/UserSceneSession.java
src/main/java/com/xly/service/XlyErpService.java
| ... | ... | @@ -83,11 +83,12 @@ public class XlyErpService { |
| 83 | 83 | String authorization) { |
| 84 | 84 | String sceneName = StrUtil.EMPTY; |
| 85 | 85 | String methodName = StrUtil.EMPTY; |
| 86 | + UserSceneSession session=null; | |
| 86 | 87 | try { |
| 87 | 88 | // 0. 预处理用户输入:去空格、转小写(方便匹配) |
| 88 | 89 | String input= InputPreprocessor.preprocessWithCommons(userInput); |
| 89 | 90 | // 1. 初始化用户场景会话(权限内场景) |
| 90 | - UserSceneSession session = userSceneSessionService.getUserSceneSession(userId,sUserName,sBrandsId,sSubsidiaryId,sUserType,authorization); | |
| 91 | + session = userSceneSessionService.getUserSceneSession(userId,sUserName,sBrandsId,sSubsidiaryId,sUserType,authorization); | |
| 91 | 92 | session.setAuthorization(authorization); |
| 92 | 93 | session.setSFunPrompts(null); |
| 93 | 94 | sceneName = ObjectUtil.isNotEmpty(session.getCurrentScene())?session.getCurrentScene().getSSceneName():StrUtil.EMPTY; |
| ... | ... | @@ -102,9 +103,8 @@ public class XlyErpService { |
| 102 | 103 | if (session.getCurrentScene() != null |
| 103 | 104 | && Objects.equals(session.getCurrentScene().getSSceneNo(), "ChatZone")) |
| 104 | 105 | { |
| 105 | - return getChatiAgent(input, session,StrUtil.EMPTY); | |
| 106 | + return getChatiAgent(input, session); | |
| 106 | 107 | } |
| 107 | - | |
| 108 | 108 | // 3. 未选场景:先展示场景选择界面,处理用户序号选择 |
| 109 | 109 | if (!session.isSceneSelected() && ValiDataUtil.me().isPureNumber(input)){ |
| 110 | 110 | // 3.1 尝试处理场景选择(输入序号则匹配,否则展示选择提示) |
| ... | ... | @@ -114,49 +114,44 @@ public class XlyErpService { |
| 114 | 114 | ErpAiAgent aiAgent = createErpAiAgent(userId, input, session); |
| 115 | 115 | // 没有选择到场景,进闲聊模式 |
| 116 | 116 | if (aiAgent == null){ |
| 117 | - return getChatiAgent (input, session,StrUtil.EMPTY); | |
| 117 | + return getChatiAgent (input,session); | |
| 118 | 118 | } |
| 119 | -// List<ChatMessage> chatMessage = operableChatMemoryProvider.getCurrentChatMessages(session.getUserId()); | |
| 120 | - String sResponMessage = aiAgent.chat(userId, input); | |
| 121 | -// List<ChatMessage> chatMessage2 = operableChatMemoryProvider.getCurrentChatMessages(session.getUserId()); | |
| 122 | - String sResponMessageOld = StrUtil.EMPTY; | |
| 123 | -// 调用方法,参数缺失部分提示,就直接使用方法返回的 | |
| 124 | - if(session.getCurrentTool() != null | |
| 125 | - && session.getSFunPrompts()!=null | |
| 119 | + //用户输入添加方法 | |
| 120 | + String sResponMessage = StrUtil.EMPTY; | |
| 121 | + if(ObjectUtil.isNotEmpty(session.getCurrentTool()) | |
| 122 | + && !ObjectUtil.isNotEmpty(session.getCurrentTool().getSInputTabelName()) | |
| 126 | 123 | ){ |
| 127 | - // 缺失的参数明细 | |
| 128 | - sResponMessage = session.getSFunPrompts(); | |
| 129 | - } | |
| 130 | - if (session.getCurrentTool()== null){ | |
| 131 | - sResponMessageOld = sResponMessage; | |
| 132 | - sResponMessage = StrUtil.EMPTY; | |
| 133 | - } | |
| 134 | - //5.执行工具方法后,清除记忆 | |
| 135 | - if(session.getBCleanMemory()){ | |
| 136 | - doCleanUserMemory(session,userId); | |
| 124 | + input = session.getCurrentTool().getSMethodName()+","+input; | |
| 125 | + sResponMessage = aiAgent.chatCurrentTool(userId, input,session.getCurrentTool().getSMethodNo(),session.getCurrentTool().getSMethodName(),session.getCurrentTool().getStoolDesc()); | |
| 126 | + }else{ | |
| 127 | + sResponMessage = aiAgent.chat(userId, input); | |
| 137 | 128 | } |
| 138 | -// 6.找到方法并且本方法带表结构描述时,需要调用 自然语言转SQL智能体 | |
| 129 | + | |
| 130 | +// 1.找到方法并且本方法带表结构描述时,需要调用 自然语言转SQL智能体 | |
| 139 | 131 | if((ObjectUtil.isNotEmpty(session.getCurrentTool()) |
| 140 | 132 | && ObjectUtil.isNotEmpty(session.getCurrentTool().getSInputTabelName()) |
| 141 | 133 | && ObjectUtil.isNotEmpty(session.getCurrentTool().getSStructureMemo())) |
| 142 | 134 | ){ |
| 143 | 135 | sResponMessage = getDynamicTableSql(session, input, userId, userInput,0,StrUtil.EMPTY,StrUtil.EMPTY,"0",StrUtil.EMPTY, aiAgent); |
| 144 | - } | |
| 145 | - //如果返回空的进入闲聊模式 | |
| 146 | - if (ObjectUtil.isEmpty(sResponMessage)){ | |
| 147 | - return getChatiAgent (input, session,sResponMessageOld); | |
| 148 | - } | |
| 149 | - if (session.getCurrentScene()!= null ){ | |
| 150 | - return AiResponseDTO.builder().aiText(sResponMessage) | |
| 151 | - .sSceneName(session.getCurrentScene().getSSceneName()) | |
| 152 | - .sMethodName((ObjectUtil.isEmpty(session.getCurrentTool()))?StrUtil.EMPTY:session.getCurrentTool().getSMethodName()) | |
| 153 | - .sReturnType(ReturnTypeCode.MAKEDOWN.getCode()) | |
| 154 | - .build(); | |
| 155 | - }else { | |
| 136 | + return AiResponseDTO.builder().sSceneName(sceneName).sMethodName(methodName).aiText(sResponMessage).sReturnType(ReturnTypeCode.HTML.getCode()).build(); | |
| 137 | + } else if (ObjectUtil.isNotEmpty(session.getCurrentTool())) { | |
| 138 | + //2.处理工具参数采集结束后业务逻辑处理 | |
| 139 | + //调用方法,参数缺失部分提示,就直接使用方法返回的 | |
| 140 | + sResponMessage = dynamicToolProvider.doDynamicTool(session.getCurrentTool(),session); | |
| 141 | + return AiResponseDTO.builder().sSceneName(sceneName).sMethodName(methodName).aiText(sResponMessage).sReturnType(ReturnTypeCode.HTML.getCode()).build(); | |
| 142 | + }else if(session.getCurrentScene()== null ){ | |
| 156 | 143 | return AiResponseDTO.builder().sSceneName(sceneName).sMethodName(methodName).aiText("当前场景:没有选择 退回当前场景 请输入 "+ CommonConstant.RESET + sResponMessage).sReturnType(ReturnTypeCode.HTML.getCode()).build(); |
| 144 | + }else{ | |
| 145 | + return getChatiAgent (input, session); | |
| 157 | 146 | } |
| 158 | 147 | } catch (Exception e) { |
| 148 | + e.printStackTrace(); | |
| 159 | 149 | return AiResponseDTO.builder().sSceneName(sceneName).sMethodName(methodName).aiText("系统异常:" + e.getMessage() + ",请稍后重试!").sReturnType(ReturnTypeCode.HTML.getCode()).build(); |
| 150 | + }finally { | |
| 151 | + //5.执行工具方法后,清除记忆 | |
| 152 | + if(session !=null && session.getBCleanMemory()){ | |
| 153 | + doCleanUserMemory(session,userId); | |
| 154 | + } | |
| 160 | 155 | } |
| 161 | 156 | } |
| 162 | 157 | |
| ... | ... | @@ -170,6 +165,7 @@ public class XlyErpService { |
| 170 | 165 | UserSceneSession session = userSceneSessionService.getUserSceneSession(userId,sUserName,sBrandsId,sSubsidiaryId,sUserType,authorization); |
| 171 | 166 | operableChatMemoryProvider.clearSpecifiedMemory(userId); |
| 172 | 167 | session.setCurrentTool(null); |
| 168 | + session.setArgs(null); | |
| 173 | 169 | session.setSUserQuestionList(new ArrayList<>()); |
| 174 | 170 | UserSceneSessionService.ERP_AGENT_CACHE.remove(userId); |
| 175 | 171 | UserSceneSessionService.CHAT_AGENT_CACHE.remove(userId); |
| ... | ... | @@ -246,6 +242,7 @@ public class XlyErpService { |
| 246 | 242 | operableChatMemoryProvider.clearSpecifiedMemory(userId); |
| 247 | 243 | session.setCurrentTool(null); |
| 248 | 244 | session.setSUserQuestionList(new ArrayList<>()); |
| 245 | + session.setArgs(new HashMap<>()); | |
| 249 | 246 | // session.setSceneSelected(false); |
| 250 | 247 | UserSceneSessionService.ERP_AGENT_CACHE.remove(userId); |
| 251 | 248 | UserSceneSessionService.CHAT_AGENT_CACHE.remove(userId); |
| ... | ... | @@ -593,12 +590,9 @@ public class XlyErpService { |
| 593 | 590 | * @return java.lang.String |
| 594 | 591 | * @Description 获取智普通智能体 |
| 595 | 592 | **/ |
| 596 | - private AiResponseDTO getChatiAgent (String input,UserSceneSession session,String sResponMessageOld){ | |
| 593 | + private AiResponseDTO getChatiAgent (String input,UserSceneSession session){ | |
| 597 | 594 | String sceneName = ObjectUtil.isNotEmpty(session.getCurrentScene())?session.getCurrentScene().getSSceneName():StrUtil.EMPTY; |
| 598 | 595 | String methodName = ObjectUtil.isNotEmpty(session.getCurrentTool())?session.getCurrentTool().getSMethodName():"随便聊聊"; |
| 599 | - if(ObjectUtil.isNotEmpty(sResponMessageOld)){ | |
| 600 | - return AiResponseDTO.builder().sSceneName(sceneName).sMethodName(methodName).aiText(sResponMessageOld).systemText(StrUtil.EMPTY).sReturnType(ReturnTypeCode.HTML.getCode()).build(); | |
| 601 | - } | |
| 602 | 596 | ChatiAgent chatiAgent = UserSceneSessionService.CHAT_AGENT_CACHE.get(session.getUserId()); |
| 603 | 597 | if(ObjectUtil.isEmpty(chatiAgent)){ |
| 604 | 598 | chatiAgent = AiServices.builder(ChatiAgent.class) | ... | ... |
src/main/java/com/xly/tool/DynamicToolProvider.java
| 1 | 1 | package com.xly.tool; |
| 2 | 2 | |
| 3 | 3 | |
| 4 | +import cn.hutool.core.util.NumberUtil; | |
| 4 | 5 | import cn.hutool.core.util.ObjectUtil; |
| 5 | 6 | import cn.hutool.core.util.StrUtil; |
| 6 | 7 | import cn.hutool.json.JSONUtil; |
| ... | ... | @@ -165,7 +166,7 @@ public class DynamicToolProvider implements ToolProvider { |
| 165 | 166 | pr.setSParamValue(sAIshowfieldShowAll.get(i).get("sName").toString()); |
| 166 | 167 | pr.setSParam(sAIshowfieldShowAll.get(i).get("label").toString()); |
| 167 | 168 | pr.setBEmpty(false); |
| 168 | - pr.setSType("array"); | |
| 169 | + pr.setSType(getDefType(sAIshowfieldShowAll.get(i).get("sName").toString())); | |
| 169 | 170 | if("sSlaveId".equals(sAIshowfieldShowAll.get(i).get("sName"))){ |
| 170 | 171 | pr.setSParam("sSlaveId"); |
| 171 | 172 | } |
| ... | ... | @@ -186,35 +187,56 @@ public class DynamicToolProvider implements ToolProvider { |
| 186 | 187 | meta.setParamRuleListAll(paramRuleListAll); |
| 187 | 188 | } |
| 188 | 189 | |
| 190 | + private String getDefType(String sColumn){ | |
| 191 | + if(sColumn.startsWith("d")){ | |
| 192 | + return "double"; | |
| 193 | + }else{ | |
| 194 | + return "string"; | |
| 195 | + } | |
| 196 | + } | |
| 189 | 197 | @Override |
| 190 | 198 | public ToolProviderResult provideTools(ToolProviderRequest request) { |
| 191 | -// List<ToolSpecification> specs = new ArrayList<>(); | |
| 192 | 199 | String sUserId = request.chatMemoryId().toString(); |
| 193 | 200 | Map<ToolSpecification, ToolExecutor> executors = new HashMap<>(); |
| 194 | - // sceneToolCacheMap.get(sSceneIdMap.get(sUserId)); | |
| 195 | - //获取Session | |
| 201 | + // 获取Session | |
| 196 | 202 | UserSceneSession session = UserSceneSessionService.USER_SCENE_SESSION_CACHE.get(sUserId); |
| 197 | - //过滤对应的权限方法 | |
| 203 | + | |
| 204 | + // 过滤对应的权限方法 | |
| 198 | 205 | List<ToolSpecificationHolder> datalist = new ArrayList<>(); |
| 199 | 206 | List<ToolMeta> toolMetaAll = new ArrayList<>(); |
| 200 | - if(session.getCurrentTool()!=null){ | |
| 207 | + | |
| 208 | + // 确保 currentTool 不为空,或者 authTool 有数据 | |
| 209 | + if(session.getCurrentTool() != null){ | |
| 201 | 210 | toolMetaAll.add(session.getCurrentTool()); |
| 202 | - }else{ | |
| 211 | + log.info("使用 currentTool: {}", session.getCurrentTool().getSMethodNo()); | |
| 212 | + } else { | |
| 203 | 213 | toolMetaAll = session.getAuthTool(); |
| 214 | + log.info("使用 authTool, 数量: {}", toolMetaAll.size()); | |
| 204 | 215 | } |
| 216 | + | |
| 205 | 217 | if(ObjectUtil.isNotEmpty(toolMetaAll)){ |
| 206 | - toolMetaAll = toolMetaAll.stream().filter(to-> to.getSSceneId().equals(sSceneIdMap.get(sUserId))).collect(Collectors.toUnmodifiableList()); | |
| 218 | + toolMetaAll = toolMetaAll.stream() | |
| 219 | + .filter(to -> to.getSSceneId().equals(sSceneIdMap.get(sUserId))) | |
| 220 | + .collect(Collectors.toUnmodifiableList()); | |
| 221 | + | |
| 207 | 222 | if(ObjectUtil.isNotEmpty(toolMetaAll)){ |
| 208 | - toolMetaAll.forEach(to->{ | |
| 209 | - datalist.add(toolCache.get(to.getSMethodNo())); | |
| 223 | + toolMetaAll.forEach(to -> { | |
| 224 | + ToolSpecificationHolder holder = toolCache.get(to.getSMethodNo()); | |
| 225 | + if (holder != null) { | |
| 226 | + datalist.add(holder); | |
| 227 | + log.debug("添加工具到提供器: {}", to.getSMethodNo()); | |
| 228 | + } else { | |
| 229 | + log.warn("工具缓存缺失: {}", to.getSMethodNo()); | |
| 230 | + } | |
| 210 | 231 | }); |
| 211 | 232 | } |
| 212 | 233 | } |
| 213 | - datalist.forEach(holder->{ | |
| 214 | -// specs.add(holder.getToolSpecification()); | |
| 215 | - executors.put(holder.getToolSpecification(),holder.getToolExecutor()); | |
| 216 | -// executors.put(holder.getToolSpecification(), holder.getToolExecutor()); | |
| 234 | + | |
| 235 | + // 将工具添加到返回结果中 | |
| 236 | + datalist.forEach(holder -> { | |
| 237 | + executors.put(holder.getToolSpecification(), holder.getToolExecutor()); | |
| 217 | 238 | }); |
| 239 | + log.info("provideTools 返回工具数量: {}", executors.size()); | |
| 218 | 240 | return ToolProviderResult.builder().addAll(executors).build(); |
| 219 | 241 | } |
| 220 | 242 | |
| ... | ... | @@ -240,10 +262,10 @@ public class DynamicToolProvider implements ToolProvider { |
| 240 | 262 | // stoolDesc.append(",").append("并选择数据后执行["+meta.getSControlName()+"]操作"); |
| 241 | 263 | // } |
| 242 | 264 | stoolDesc.append("时,必须调用本工具").append(meta.getSMethodNo()).append(",").append(meta.getStoolDesc()); |
| 243 | - if (meta.getIBizType()==4){ | |
| 244 | - stoolDesc.append(",").append("并选择数据后执行 "+meta.getSControlName()+" 操作"); | |
| 245 | -// .append("1.全部数据生成多个单据 回复【全部确认】;2.全部数据生成一个单据 回复【合并确认】;3.按自然语义描述生成一个单据 如"1,3行确认""); | |
| 246 | - } | |
| 265 | +// if (meta.getIBizType()==4){ | |
| 266 | +// stoolDesc.append(",").append("并选择数据后执行 "+meta.getSControlName()+" 操作"); | |
| 267 | +//// .append("1.全部数据生成多个单据 回复【全部确认】;2.全部数据生成一个单据 回复【合并确认】;3.按自然语义描述生成一个单据 如"1,3行确认""); | |
| 268 | +// } | |
| 247 | 269 | } |
| 248 | 270 | |
| 249 | 271 | try { |
| ... | ... | @@ -504,115 +526,129 @@ public class DynamicToolProvider implements ToolProvider { |
| 504 | 526 | } |
| 505 | 527 | return paramRuleDataAll; |
| 506 | 528 | } |
| 507 | - | |
| 508 | - | |
| 509 | 529 | /*** |
| 510 | 530 | * @Author 钱豹 |
| 511 | - * @Date 15:09 2026/1/30 | |
| 531 | + * @Date 12:37 2026/3/16 | |
| 512 | 532 | * @Param [meta] |
| 513 | 533 | * @return dev.langchain4j.service.tool.ToolExecutor |
| 514 | - * @Description 创建 ToolExecutor,内部包含参数自动补全与校验逻辑(创建执行器) | |
| 534 | + * @Description 参数采集执行器 | |
| 515 | 535 | **/ |
| 516 | 536 | private ToolExecutor createToolExecutor(ToolMeta meta) { |
| 537 | + log.info("创建工具执行器: {}", meta.getSMethodNo()); | |
| 538 | + | |
| 517 | 539 | return (toolExecutionRequest, memoryId) -> { |
| 540 | + log.info("===== 工具执行器开始执行 ====="); | |
| 541 | + log.info("工具编号: {}", meta.getSMethodNo()); | |
| 542 | + log.info("工具名称: {}", meta.getSMethodName()); | |
| 543 | + log.info("memoryId: {}", memoryId); | |
| 544 | + log.info("请求参数: {}", toolExecutionRequest.arguments()); | |
| 545 | + | |
| 518 | 546 | UserSceneSession session = UserSceneSessionService.USER_SCENE_SESSION_CACHE.get(memoryId.toString()); |
| 519 | - session.setCurrentTool(meta); // 标记一下找到了相应方法 | |
| 520 | - session.setSFunPrompts(null); | |
| 521 | - // 检查条件 - 如果条件满足,直接返回成功结果,不再执行后续逻辑 | |
| 522 | - if (ObjectUtil.isNotEmpty(meta.getSInputTabelName()) | |
| 523 | - && ObjectUtil.isNotEmpty(meta.getSStructureMemo())) { | |
| 524 | - // 直接返回成功结果,阻止后续执行 | |
| 525 | - return createEarlySuccessResult(toolExecutionRequest, "执行成功,终止后续执行"); | |
| 526 | - } | |
| 547 | + session.setCurrentTool(meta); // 标记当前工具 | |
| 527 | 548 | |
| 528 | - // 1. 解析模型传入的参数 | |
| 529 | - Map<String, Object> args; | |
| 549 | + // 1. 解析参数 | |
| 550 | + Map<String, Object> argsNew; | |
| 530 | 551 | try { |
| 531 | - args = objectMapper.readValue(toolExecutionRequest.arguments(), new TypeReference<>() {}); | |
| 552 | + argsNew = objectMapper.readValue(toolExecutionRequest.arguments(), new TypeReference<>() {}); | |
| 553 | + log.info("解析后的参数: {}", argsNew); | |
| 532 | 554 | } catch (Exception e) { |
| 533 | - String errorMsg = "参数 JSON 解析失败,请检查参数格式是否正确。" | |
| 534 | - + "错误详情:" + e.getMessage(); | |
| 535 | - log.warn("参数解析失败,tool={}, args={}", meta.getSMethodNo(), toolExecutionRequest.arguments(), e); | |
| 555 | + log.error("参数解析失败", e); | |
| 556 | + String errorMsg = "参数解析失败,请重新输入"; | |
| 536 | 557 | return String.valueOf(errorResult(toolExecutionRequest, errorMsg)); |
| 537 | 558 | } |
| 538 | -// Map<String, Object> argsOld = DeepCopyUtils.deepCopy(args); | |
| 539 | - List<ParamRule> paramRuleData = meta.getParamRuleListAll(); | |
| 540 | - | |
| 541 | - // 2 【补全动态参数】动态参数补全 | |
| 542 | - try{ | |
| 543 | - args = applyValues(args, meta.getParamRuleListCheck()); | |
| 544 | - }catch (Exception e){ | |
| 545 | - log.error("返回信息",e); | |
| 546 | - String sTsMsg = e.getMessage(); | |
| 547 | - session.setSFunPrompts(sTsMsg); | |
| 548 | - //存在多个数据返回大模型,需要继续盘问选择出唯一结果 | |
| 549 | - return String.valueOf(askUserResult(toolExecutionRequest, sTsMsg)); | |
| 550 | - } | |
| 551 | - | |
| 552 | - // 2.1 【自动补全】应用参数的默认值 | |
| 553 | - args = applyDefaultValues(args, paramRuleData); | |
| 554 | - | |
| 555 | - // 3. 【自动校验】检查必填项 | |
| 556 | - List<String> missing = checkRequiredParams(args, paramRuleData); | |
| 557 | - if (!missing.isEmpty()) { | |
| 558 | - // 4.1 参数缺失,生成“提问”消息,直接返给客户 | |
| 559 | - String askMsg = buildAskUserMessage(meta, missing,args); | |
| 560 | - session.setSFunPrompts(askMsg); | |
| 561 | - return String.valueOf(askUserResult(toolExecutionRequest, askMsg)); | |
| 559 | + Map<String, Object> args = session.getArgs(); | |
| 560 | + if(ObjectUtil.isEmpty(args)){ | |
| 561 | + args = new HashMap<>(); | |
| 562 | 562 | } |
| 563 | + Map<String, Object> finalArgs = args; | |
| 564 | + argsNew.forEach((k, v)->{ | |
| 565 | + //获取对应的英文参数 | |
| 566 | + List<ParamRule> data = meta.getParamRuleList().stream().filter(one->one.getSParam().equals(k)).collect(Collectors.toUnmodifiableList()); | |
| 567 | + if(ObjectUtil.isNotEmpty(data) && data.size()>0){ | |
| 568 | + finalArgs.remove(data.get(0).getSParamValue()); | |
| 569 | + finalArgs.remove(data.get(0).getSParam()); | |
| 570 | + } | |
| 571 | + if(ObjectUtil.isNotEmpty(v)){ | |
| 572 | + finalArgs.put(k,v); | |
| 573 | + } | |
| 574 | + }); | |
| 575 | + session.setArgs(finalArgs); | |
| 576 | + // 2. 获取必填参数规则 | |
| 577 | +// List<ParamRule> sParamRules = meta.getParamRuleListCheck(); | |
| 578 | +// List<String> missingParams = getRequiredParams(sParamRules); | |
| 579 | +// String collectPrompt = buildCollectParamsPrompt(meta, missingParams, args); | |
| 580 | +// log.info("参数缺失,返回收集提示: {}", collectPrompt); | |
| 581 | + return String.valueOf(successResult(toolExecutionRequest, JSONUtil.toJsonStr(finalArgs))); | |
| 582 | + }; | |
| 583 | + } | |
| 563 | 584 | |
| 564 | - // 6. 【最终确认信息】所有检测通过后,需要和客户确认交互 | |
| 565 | - List<ChatMessage> chatMessage = operableChatMemoryProvider.getCurrentChatMessages(memoryId.toString()); | |
| 566 | - ChatMessage userMessage = getLasterUserMssage(chatMessage); | |
| 567 | - String input = StrUtil.replace(userMessage.text(),"用户输入:",StrUtil.EMPTY); | |
| 585 | + public String doDynamicTool(ToolMeta meta,UserSceneSession session) { | |
| 586 | + List<ParamRule> paramRuleData = meta.getParamRuleListAll(); | |
| 587 | + Map<String, Object> args = session.getArgs(); | |
| 588 | + Map<String, Object> argsOld = new HashMap<>(args); | |
| 589 | + // 2 【补全动态参数】动态参数补全 | |
| 590 | + try{ | |
| 591 | + args = applyValues(args, meta.getParamRuleListCheck()); | |
| 592 | + }catch (Exception e){ | |
| 593 | + log.error("返回信息",e); | |
| 594 | + String sTsMsg = e.getMessage(); | |
| 595 | + return sTsMsg; | |
| 596 | + } | |
| 597 | + // 2.1 【自动补全】应用参数的默认值 | |
| 598 | + args = applyDefaultValues(args, paramRuleData); | |
| 599 | + session.setArgs(args); | |
| 600 | + // 3. 【自动校验】检查必填项 | |
| 601 | + List<String> missing = checkRequiredParams(args, paramRuleData); | |
| 602 | + if (!missing.isEmpty()) { | |
| 603 | + // 4.1 参数缺失,生成“提问”消息,直接返给客户 | |
| 604 | + String askMsg = buildAskUserMessage(meta, missing,args); | |
| 605 | + return askMsg; | |
| 606 | + } | |
| 568 | 607 | |
| 608 | + // 6. 【最终确认信息】所有检测通过后,需要和客户确认交互 | |
| 609 | + List<ChatMessage> chatMessage = operableChatMemoryProvider.getCurrentChatMessages(session.getUserId()); | |
| 610 | + ChatMessage userMessage = getLasterUserMssage(chatMessage); | |
| 611 | + String input = StrUtil.replace(userMessage.text(),"用户输入:",StrUtil.EMPTY); | |
| 569 | 612 | // {"0":"查询","1":"执行"} 查询不需要确认 |
| 570 | - Boolean isConfirmed = isConfirmed(input) || input.contains("生成") || input.contains("确认"); | |
| 571 | - //判断是否生成数据 | |
| 572 | - List<Map<String,Object>> sRowData = new ArrayList<>(); | |
| 573 | - String sHandleType = "merge"; | |
| 574 | - if(4== meta.getIBizType() && ObjectUtil.isNotEmpty(session.getCurrentRowData())){ | |
| 575 | - Map<String,Object> sRowDataMap = UserChoseIntentParser.getSelectedRows( input, session.getCurrentRowData()); | |
| 576 | - sRowData = (List<Map<String, Object>>) sRowDataMap.get("sRowData"); | |
| 577 | - sHandleType = sRowDataMap.get("sHandleType").toString(); | |
| 578 | - } | |
| 579 | - //{"1":"存储过程","2":"SQL查询","3":"第三方API","4":"ERP未清","5":"ERP列表(报表)","6":"ERP单据","7":"其它","8":"自然语言TEXT2SQL"} | |
| 580 | - | |
| 581 | - if((isConfirmed && (4== meta.getIBizType() ||1== meta.getIBizType())) | |
| 582 | - || 2== meta.getIBizType() | |
| 583 | - || 3== meta.getIBizType() | |
| 584 | - || 6== meta.getIBizType() | |
| 585 | - || 7== meta.getIBizType() | |
| 586 | - || 8== meta.getIBizType() | |
| 587 | - ) | |
| 588 | - { | |
| 589 | - // 确认后必填项校验 | |
| 590 | - List<String> missingAfter = checkConfirmAfterParam(args, paramRuleData); | |
| 591 | - if (!missingAfter.isEmpty()) { | |
| 592 | - // 4.1 参数缺失,生成“提问”消息,直接返给客户 | |
| 593 | - String askMsg = buildAskUserMessage(meta, missingAfter,args); | |
| 594 | - session.setSFunPrompts(askMsg); | |
| 595 | - return String.valueOf(askUserResult(toolExecutionRequest, askMsg)); | |
| 596 | - } | |
| 597 | - // 7. 【业务校验】执行业务层面的逻辑校验 + 所有校验通过,执行核心业务逻辑 | |
| 598 | - return executeTool(toolExecutionRequest, meta, args, paramRuleData, memoryId.toString(), session); | |
| 599 | - } | |
| 600 | - String askconfirmMsg =StrUtil.EMPTY; | |
| 601 | -// if(0== meta.getIActionType() && 4!= meta.getIBizType() && 5!= meta.getIBizType()){ | |
| 602 | -// askconfirmMsg = buildConfirmUserMessage(meta, args); | |
| 603 | -// }else | |
| 604 | - if(4== meta.getIBizType() || meta.getIBizType()==5){ | |
| 605 | - askconfirmMsg = doGetFromData( meta,args,session); | |
| 606 | -// session.setSFunPrompts(askconfirmMsg); | |
| 607 | -// operableChatMemoryProvider.get(memoryId).add(UserMessage.from("SYSTEM: 等待用户确认或选择部分数据操作")); | |
| 608 | - return executeWithConfirmation(toolExecutionRequest,askconfirmMsg,operableChatMemoryProvider.get(memoryId), session, meta).text(); | |
| 609 | - }else{ | |
| 610 | - askconfirmMsg =getDefMessage(args,meta.getSControlName(),meta); | |
| 613 | + Boolean isConfirmed = isConfirmed(input) || input.contains("生成") || input.contains("确认"); | |
| 614 | + //判断是否生成数据 | |
| 615 | + List<Map<String,Object>> sRowData = new ArrayList<>(); | |
| 616 | + String sHandleType = "merge"; | |
| 617 | + if(4== meta.getIBizType() && ObjectUtil.isNotEmpty(session.getCurrentRowData())){ | |
| 618 | + Map<String,Object> sRowDataMap = UserChoseIntentParser.getSelectedRows( input, session.getCurrentRowData()); | |
| 619 | + sRowData = (List<Map<String, Object>>) sRowDataMap.get("sRowData"); | |
| 620 | + sHandleType = sRowDataMap.get("sHandleType").toString(); | |
| 621 | + } | |
| 622 | + //{"1":"存储过程","2":"SQL查询","3":"第三方API","4":"ERP未清","5":"ERP列表(报表)","6":"ERP单据","7":"其它","8":"自然语言TEXT2SQL"} | |
| 623 | + if((isConfirmed && (4== meta.getIBizType() ||1== meta.getIBizType())) | |
| 624 | + || 2== meta.getIBizType() | |
| 625 | + || 3== meta.getIBizType() | |
| 626 | + || 6== meta.getIBizType() | |
| 627 | + || 7== meta.getIBizType() | |
| 628 | + || 8== meta.getIBizType() | |
| 629 | + ) | |
| 630 | + { | |
| 631 | + // 确认后必填项校验 | |
| 632 | + List<String> missingAfter = checkConfirmAfterParam(args, paramRuleData); | |
| 633 | + if (!missingAfter.isEmpty()) { | |
| 634 | + // 4.1 参数缺失,生成“提问”消息,直接返给客户 | |
| 635 | + String askMsg = buildAskUserMessage(meta, missingAfter,args); | |
| 636 | + return askMsg; | |
| 611 | 637 | } |
| 612 | - // 返回需要确认的结果 | |
| 613 | - return executeWithConfirmation(toolExecutionRequest,askconfirmMsg,operableChatMemoryProvider.get(memoryId), session, meta).text(); | |
| 614 | - }; | |
| 638 | + // 7. 【业务校验】执行业务层面的逻辑校验 + 所有校验通过,执行核心业务逻辑 | |
| 639 | + return executeTool(meta, args, paramRuleData, session.getUserId(), session); | |
| 640 | + } | |
| 641 | + String askconfirmMsg =StrUtil.EMPTY; | |
| 642 | + if(4== meta.getIBizType() || meta.getIBizType()==5){ | |
| 643 | + askconfirmMsg = doGetFromData( meta,args,session); | |
| 644 | + return executeWithConfirmation(askconfirmMsg,operableChatMemoryProvider.get(session.getUserId()), session, meta); | |
| 645 | + }else{ | |
| 646 | + askconfirmMsg =getDefMessage(args,meta.getSControlName(),meta); | |
| 647 | + } | |
| 648 | + // 返回需要确认的结果 | |
| 649 | + return executeWithConfirmation(askconfirmMsg,operableChatMemoryProvider.get(session.getUserId()), session, meta); | |
| 615 | 650 | } |
| 651 | + | |
| 616 | 652 | /*** |
| 617 | 653 | * @Author 钱豹 |
| 618 | 654 | * @Date 15:16 2026/2/9 |
| ... | ... | @@ -651,7 +687,7 @@ public class DynamicToolProvider implements ToolProvider { |
| 651 | 687 | **/ |
| 652 | 688 | private void appendConfirmAll(StringBuilder markdown,String sName){ |
| 653 | 689 | sName = ObjectUtil.isEmpty(sName)?StrUtil.EMPTY:"["+sName+"]"; |
| 654 | - markdown.append("请确认是否执行").append(sName).append("操作?1.全部数据生成多个单据 回复【全部确认】;2.全部数据生成一个单据 回复【合并确认】;3.按自然语义描述生成一个单据 如"1,3行确认"\n"); | |
| 690 | + markdown.append("请确认是否执行").append(sName).append("操作?1.全部数据生成多个单据 回复【全部确认】;2.全部数据生成一个单据 回复【合并确认】;3.按自然语义描述生成一个单据 如"第1行确认"\n"); | |
| 655 | 691 | //全部确认 ,部分确认,取消 |
| 656 | 692 | markdown.append("回复:  ").append("**<a href=\"#\" data-action=\"reset\" data-text=\"全部确认\" >全部确认</a>**").append(" ") |
| 657 | 693 | .append("**<a href=\"#\" data-action=\"reset\" data-text=\"合并确认\" >合并确认</a>**").append(" ") |
| ... | ... | @@ -666,9 +702,7 @@ public class DynamicToolProvider implements ToolProvider { |
| 666 | 702 | **/ |
| 667 | 703 | private void appendConfirm(StringBuilder markdown,String sName){ |
| 668 | 704 | sName = ObjectUtil.isEmpty(sName)?StrUtil.EMPTY:"["+sName+"]"; |
| 669 | - markdown.append("请确认是否执行").append(sName).append("操作?请直接回复"确认"或"取消"\n"); | |
| 670 | - //全部确认 ,部分确认,取消 | |
| 671 | - markdown.append("回复:  ").append("**<a href=\"#\" data-action=\"reset\" data-text=\"确认\">确认</a>**").append(" ") | |
| 705 | + markdown.append("请确认是否执行").append(sName).append("操作?请回复:  ").append("**<a href=\"#\" data-action=\"reset\" data-text=\"确认\">确认</a>**").append(" ") | |
| 672 | 706 | .append("**<a href=\"#\" data-action=\"reset\" data-text=\"取消\">取消</a>**"); |
| 673 | 707 | } |
| 674 | 708 | |
| ... | ... | @@ -836,6 +870,14 @@ public class DynamicToolProvider implements ToolProvider { |
| 836 | 870 | } |
| 837 | 871 | return result; |
| 838 | 872 | } |
| 873 | + /** | |
| 874 | + * 检查必填参数 | |
| 875 | + */ | |
| 876 | + private List<String> getRequiredParams(List<ParamRule> paramDefs) { | |
| 877 | + return paramDefs.stream() | |
| 878 | + .map(ParamRule::getSParam) | |
| 879 | + .toList(); | |
| 880 | + } | |
| 839 | 881 | |
| 840 | 882 | /** |
| 841 | 883 | * 检查必填参数 |
| ... | ... | @@ -845,8 +887,11 @@ public class DynamicToolProvider implements ToolProvider { |
| 845 | 887 | return paramDefs.stream() |
| 846 | 888 | .filter(pd -> Boolean.TRUE.equals(pd.getBEmpty()) && pd.getBTipModel()) |
| 847 | 889 | .filter(pd -> |
| 848 | - (!returnMap.containsKey(pd.getSParam()) || (ObjectUtil.isEmpty(returnMap.get(pd.getSParam())))) | |
| 849 | - && (!returnMap.containsKey(pd.getSParamValue()) || (ObjectUtil.isEmpty(returnMap.get(pd.getSParamValue())))) | |
| 890 | + (!returnMap.containsKey(pd.getSParam()) | |
| 891 | + || (ObjectUtil.isEmpty(returnMap.get(pd.getSParam()))) | |
| 892 | + || (pd.getSParamValue().startsWith("d") && 0==Double.valueOf (returnMap.get(pd.getSParam()).toString())) | |
| 893 | + ) | |
| 894 | + && (!returnMap.containsKey(pd.getSParamValue()) || (ObjectUtil.isEmpty(returnMap.get(pd.getSParamValue())))) | |
| 850 | 895 | ) |
| 851 | 896 | .map(ParamRule::getSParam) |
| 852 | 897 | .toList(); |
| ... | ... | @@ -867,16 +912,17 @@ public class DynamicToolProvider implements ToolProvider { |
| 867 | 912 | .toList(); |
| 868 | 913 | } |
| 869 | 914 | |
| 915 | + | |
| 870 | 916 | /** |
| 871 | 917 | * 模拟执行工具 |
| 872 | 918 | */ |
| 873 | - public String executeTool(ToolExecutionRequest toolExecutionRequest,ToolMeta meta, Map<String, Object> args, List<ParamRule> paramRuleData,String userId,UserSceneSession session ) { | |
| 919 | + public String executeTool(ToolMeta meta, Map<String, Object> args, List<ParamRule> paramRuleData,String userId,UserSceneSession session ) { | |
| 874 | 920 | log.info("执行工具:{},参数:{}", meta.getSMethodNo(), args); |
| 875 | 921 | // 2.2 将中文key转换成英文key |
| 876 | 922 | args = transformationArgs( args, paramRuleData); |
| 877 | 923 | String sReturn ="执行成功"; |
| 878 | 924 | try{ |
| 879 | - sReturn = executeToolAfter(meta, args,toolExecutionRequest,paramRuleData,session); | |
| 925 | + sReturn = executeToolAfter(meta, args,paramRuleData,session); | |
| 880 | 926 | }catch (BusinessException e) { |
| 881 | 927 | return e.getMessage(); |
| 882 | 928 | } |
| ... | ... | @@ -893,7 +939,7 @@ public class DynamicToolProvider implements ToolProvider { |
| 893 | 939 | * @return |
| 894 | 940 | * @Description 返回结果后 执行业务类 |
| 895 | 941 | **/ |
| 896 | - private String executeToolAfter(ToolMeta meta, Map<String, Object> args,ToolExecutionRequest toolExecutionRequest,List<ParamRule> paramDefs,UserSceneSession session) { | |
| 942 | + private String executeToolAfter(ToolMeta meta, Map<String, Object> args,List<ParamRule> paramDefs,UserSceneSession session) { | |
| 897 | 943 | // {"1":"存储过程","2":"SQL查询","3":"第三方API","4":"ERP未清","5":"ERP列表(报表)","6":"ERP单据","7":"其它","8":"自然语言TEXT2SQL"} |
| 898 | 944 | String sBizContent = meta.getSBizContent(); |
| 899 | 945 | Integer iBizType = meta.getIBizType(); |
| ... | ... | @@ -950,7 +996,7 @@ public class DynamicToolProvider implements ToolProvider { |
| 950 | 996 | if ("queryTodayTask".equals(meta.getSMethodNo())) { |
| 951 | 997 | session.setBCleanMemory(true); |
| 952 | 998 | } |
| 953 | - return String.valueOf(successResult(toolExecutionRequest, sb.toString())); | |
| 999 | + return sb.toString(); | |
| 954 | 1000 | } else { |
| 955 | 1001 | String sMsgText = "未找到对应的数据"; |
| 956 | 1002 | session.setSFunPrompts(sMsgText); |
| ... | ... | @@ -961,7 +1007,7 @@ public class DynamicToolProvider implements ToolProvider { |
| 961 | 1007 | return HttpsRequestUtil.me().doRequestHttp(sBizContent, JSONUtil.toJsonStr(args), |
| 962 | 1008 | new HashMap<>(), "POST", "JSON"); |
| 963 | 1009 | } |
| 964 | - return String.valueOf(successResult(toolExecutionRequest, "操作成功")); | |
| 1010 | + return "操作成功"; | |
| 965 | 1011 | } |
| 966 | 1012 | |
| 967 | 1013 | |
| ... | ... | @@ -1051,8 +1097,37 @@ public class DynamicToolProvider implements ToolProvider { |
| 1051 | 1097 | } |
| 1052 | 1098 | List<Map<String, Object>> recordData = findFieldNameByChinese(sAIshowfieldShow, rows); |
| 1053 | 1099 | int recordCount = dataset != null ? dataset.getTotalCount() : 0; |
| 1100 | + // 动态生成表头 | |
| 1101 | + Set<String> headers = new LinkedHashSet<>(); | |
| 1102 | + for (Map<String, Object> record : sAIshowfieldShow) { | |
| 1103 | + String chineseName = (String) record.get("label"); | |
| 1104 | + if (chineseName != null && !"sSlaveId".equals(record.get("sName"))) { | |
| 1105 | + headers.add(chineseName); | |
| 1106 | + } | |
| 1107 | + } | |
| 1108 | + | |
| 1054 | 1109 | StringBuilder markdown = new StringBuilder(); |
| 1055 | 1110 | //状态 |
| 1111 | + if(ObjectUtil.isNotEmpty(session.getArgs())){ | |
| 1112 | + markdown.append("**查询条件**:"); | |
| 1113 | + List<ParamRule> pr = session.getCurrentTool().getParamRuleListCheck(); | |
| 1114 | + Map<String, Object> argsOld = new HashMap<>(session.getArgs()); | |
| 1115 | + pr.forEach(one->{ | |
| 1116 | + if(argsOld.containsKey(one.getSParam())){ | |
| 1117 | + if(ObjectUtil.isNotEmpty(argsOld.get(one.getSParam()))){ | |
| 1118 | + if(one.getSParamValue().startsWith("d")){ | |
| 1119 | + if(Double.valueOf(argsOld.get(one.getSParam()).toString())>0){ | |
| 1120 | + markdown.append(one.getSParam()).append(":").append(argsOld.get(one.getSParam()).toString()).append(" "); | |
| 1121 | + } | |
| 1122 | + }else{ | |
| 1123 | + markdown.append(one.getSParam()).append(":").append(argsOld.get(one.getSParam()).toString()).append(" "); | |
| 1124 | + } | |
| 1125 | + } | |
| 1126 | + } | |
| 1127 | + }); | |
| 1128 | + markdown.append("\n\n"); | |
| 1129 | + } | |
| 1130 | + markdown.append("**结果**:"); | |
| 1056 | 1131 | String sStatus = erpResult.getCode()<0?ErrorCode.ERRORMSG.getMessage():ErrorCode.SUCCESSMSG.getMessage(); |
| 1057 | 1132 | markdown.append(sStatus).append("\n"); |
| 1058 | 1133 | if(erpResult.getCode()<0){ |
| ... | ... | @@ -1067,14 +1142,6 @@ public class DynamicToolProvider implements ToolProvider { |
| 1067 | 1142 | } |
| 1068 | 1143 | // markdown.append("\n---\n"); |
| 1069 | 1144 | markdown.append("\n\n").append("| 序号 | "); |
| 1070 | - // 动态生成表头 | |
| 1071 | - Set<String> headers = new LinkedHashSet<>(); | |
| 1072 | - for (Map<String, Object> record : sAIshowfieldShow) { | |
| 1073 | - String chineseName = (String) record.get("label"); | |
| 1074 | - if (chineseName != null && !"sSlaveId".equals(record.get("sName"))) { | |
| 1075 | - headers.add(chineseName); | |
| 1076 | - } | |
| 1077 | - } | |
| 1078 | 1145 | headers.forEach(header -> markdown.append(header).append(" | ")); |
| 1079 | 1146 | markdown.append("\n|").append("---|".repeat(headers.size() + 1)).append("\n"); |
| 1080 | 1147 | // 填充表格数据 |
| ... | ... | @@ -1256,20 +1323,9 @@ public class DynamicToolProvider implements ToolProvider { |
| 1256 | 1323 | } |
| 1257 | 1324 | |
| 1258 | 1325 | /** |
| 1259 | - * 询问用户工具执行结果 | |
| 1260 | - * @param request 工具执行请求 | |
| 1261 | - * @param text 回复文本内容 | |
| 1262 | - * @return 工具执行结果消息 | |
| 1263 | - * @author 钱豹 | |
| 1264 | - */ | |
| 1265 | - private ToolExecutionResultMessage askUserResult(ToolExecutionRequest request, String text) { | |
| 1266 | - // 直接返回标准结果 | |
| 1267 | - return ToolExecutionResultMessage.from(request, text); | |
| 1268 | - } | |
| 1269 | - /** | |
| 1270 | 1326 | * 执行方法后需要用户确认的扩展版本 |
| 1271 | 1327 | */ |
| 1272 | - private ToolExecutionResultMessage executeWithConfirmation(ToolExecutionRequest request, String initialResult,ChatMemory chatMemory, UserSceneSession session,ToolMeta meta) { | |
| 1328 | + private String executeWithConfirmation(String initialResult,ChatMemory chatMemory, UserSceneSession session,ToolMeta meta) { | |
| 1273 | 1329 | |
| 1274 | 1330 | // 第一步:执行原始操作,返回初步结果 |
| 1275 | 1331 | Map<String, Object> step1Result = new HashMap<>(); |
| ... | ... | @@ -1278,18 +1334,19 @@ public class DynamicToolProvider implements ToolProvider { |
| 1278 | 1334 | step1Result.put("confirmationRequired", true); |
| 1279 | 1335 | step1Result.put("confirmationMessage", initialResult); |
| 1280 | 1336 | // // 将确认状态保存到对话记忆 |
| 1281 | - chatMemory.add(UserMessage.from("SYSTEM: 等待用户确认操作")); | |
| 1337 | +// chatMemory.add(UserMessage.from("SYSTEM: 等待用户确认操作")); | |
| 1282 | 1338 | String userMessage = formatConfirmationResult(step1Result); |
| 1283 | 1339 | session.setCurrentTool(meta); |
| 1284 | - session.setSFunPrompts(userMessage); | |
| 1340 | +// session.setSFunPrompts(userMessage); | |
| 1285 | 1341 | // 6. 返回确认请求 |
| 1286 | - return ToolExecutionResultMessage.from(request,userMessage); | |
| 1342 | +// return ToolExecutionResultMessage.from(request,userMessage); | |
| 1343 | + return userMessage; | |
| 1287 | 1344 | } |
| 1288 | 1345 | |
| 1289 | 1346 | private String formatConfirmationResult(Map<String, Object> result) { |
| 1290 | 1347 | return String.format( |
| 1291 | 1348 | """ |
| 1292 | - **结果** : %s | |
| 1349 | + %s | |
| 1293 | 1350 | """, |
| 1294 | 1351 | result.get("initialResult"), |
| 1295 | 1352 | result.get("confirmationMessage") | ... | ... |
src/main/resources/templates/chat.html
| ... | ... | @@ -468,7 +468,7 @@ |
| 468 | 468 | let subsidiaryid= "1111111111"; |
| 469 | 469 | let usertype= "sysadmin"; |
| 470 | 470 | // let usertype= "General"; |
| 471 | - let authorization="CE444885A9BCFDDE1FD793F8A0931301E9D7DE6CEDD9DE4B83ECE2219C7829A8F3419238942A93E9AD666629E18D159AF7FE144A6407DE745BA0AEC8B235FC1D59FCE41E63C9FE20948A232F9F67AAE5687D4EF8281542FFC87C4EB776974C6A538155B7ADAEE71E899235DC1122F426"; | |
| 471 | + let authorization="CE444885A9BCFDDE1FD793F8A0931301E9D7DE6CEDD9DE4B83ECE2219C7829A8F3419238942A93E9AD666629E18D159AF7FE144A6407DE745BA0AEC8B235FC1D0771D239F1C61B14219E1D1B3A166D73495FD8E662F2065F9430347C7E4472B5538155B7ADAEE71E899235DC1122F426"; | |
| 472 | 472 | let hrefLock = window.location.origin+"/xlyAi"; |
| 473 | 473 | // ==================== 配置部分 ==================== |
| 474 | 474 | const CONFIG = { | ... | ... |