From 8fac71869fa2ba9f469f537523a7d8dfe07a1592 Mon Sep 17 00:00:00 2001 From: tanglong <842690096@qq.com> Date: Mon, 3 Aug 2026 09:54:11 +0800 Subject: [PATCH] =?UTF-8?q?=E5=9B=9E=E8=B0=83=E6=8E=A8=E9=80=81=E6=B6=88?= =?UTF-8?q?=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../assistant/api/AssistantApiController.java | 32 +++++++++++++++++-- .../api/AssistantApiControllerTest.java | 17 ++++++++-- 2 files changed, 43 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/company/agentfoundation/assistant/api/AssistantApiController.java b/src/main/java/com/company/agentfoundation/assistant/api/AssistantApiController.java index eedd1d9..dfc8291 100644 --- a/src/main/java/com/company/agentfoundation/assistant/api/AssistantApiController.java +++ b/src/main/java/com/company/agentfoundation/assistant/api/AssistantApiController.java @@ -1,6 +1,7 @@ package com.company.agentfoundation.assistant.api; import com.company.agentfoundation.integration.coze.service.CozeWorkflowService; +import com.company.agentfoundation.integration.wecom.client.WecomClient; import com.company.agentfoundation.semantic.SemanticDispatchResult; import com.company.agentfoundation.semantic.SemanticDispatchService; import com.company.agentfoundation.semantic.SemanticReplyAttachment; @@ -35,6 +36,7 @@ public class AssistantApiController { private static final Logger log = LoggerFactory.getLogger(AssistantApiController.class); private final CozeWorkflowService cozeWorkflowService; + private final WecomClient wecomClient; private final SemanticDispatchService semanticDispatchService; private final AssistantFileStore fileStore; private final Executor assistantTaskExecutor; @@ -43,11 +45,13 @@ public class AssistantApiController { public AssistantApiController( CozeWorkflowService cozeWorkflowService, + WecomClient wecomClient, SemanticDispatchService semanticDispatchService, AssistantFileStore fileStore, @Qualifier("wecomTaskExecutor") Executor assistantTaskExecutor ) { this.cozeWorkflowService = cozeWorkflowService; + this.wecomClient = wecomClient; this.semanticDispatchService = semanticDispatchService; this.fileStore = fileStore; this.assistantTaskExecutor = assistantTaskExecutor; @@ -57,11 +61,14 @@ public class AssistantApiController { value = {"/general/query", "/general/query/", "/general/query/general"}, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) - public AssistantQueryResponse generalQuery(@RequestBody AssistantQueryRequest request) { + public AssistantQueryResponse generalQuery( + @RequestBody AssistantQueryRequest request, + HttpServletRequest httpRequest + ) { String query = request == null ? "" : request.normalizedQuery(); if (query.isEmpty()) return AssistantQueryResponse.failure("query不能为空"); if (isCustomerCreation(query)) { - return acceptCustomerCreation(query); + return acceptCustomerCreation(query, resolveUserId(request, httpRequest)); } try { return AssistantQueryResponse.success( @@ -72,7 +79,7 @@ public class AssistantApiController { } } - private AssistantQueryResponse acceptCustomerCreation(String query) { + private AssistantQueryResponse acceptCustomerCreation(String query, String userId) { String requestKey = query.toLowerCase(Locale.ROOT).replaceAll("\\s+", ""); if (!runningGeneralWrites.add(requestKey)) { return AssistantQueryResponse.success( @@ -84,9 +91,11 @@ public class AssistantApiController { String reply = toRobotPlainText(cozeWorkflowService.chatDefault(query)); log.info("assistant general async customer creation completed query={} reply={}", query, reply); + notifyCustomerCreationResult(userId, true, reply); } catch (RuntimeException exception) { log.error("assistant general async customer creation failed query={} err={}", query, exception.getMessage(), exception); + notifyCustomerCreationResult(userId, false, "客户新增失败,请稍后重试。"); } finally { runningGeneralWrites.remove(requestKey); } @@ -101,6 +110,23 @@ public class AssistantApiController { } } + private void notifyCustomerCreationResult(String userId, boolean success, String result) { + if (userId == null || userId.isBlank()) { + log.warn("assistant general async result cannot be pushed because WeCom UserID is missing"); + return; + } + String safeResult = result == null || result.isBlank() + ? (success ? "客户新增处理完成。" : "客户新增失败,请稍后重试。") + : result; + String message = (success ? "✅ 客户新增完成\n" : "❌ 客户新增失败\n") + safeResult; + try { + wecomClient.sendText("general", userId, message); + } catch (RuntimeException exception) { + log.error("assistant general async result push failed userId={} err={}", + userId, exception.getMessage(), exception); + } + } + private boolean isCustomerCreation(String query) { String compact = query == null ? "" : query.replaceAll("\\s+", ""); boolean hasCreationVerb = compact.contains("新增") diff --git a/src/test/java/com/company/agentfoundation/assistant/api/AssistantApiControllerTest.java b/src/test/java/com/company/agentfoundation/assistant/api/AssistantApiControllerTest.java index c8beaac..92e7356 100644 --- a/src/test/java/com/company/agentfoundation/assistant/api/AssistantApiControllerTest.java +++ b/src/test/java/com/company/agentfoundation/assistant/api/AssistantApiControllerTest.java @@ -1,6 +1,7 @@ package com.company.agentfoundation.assistant.api; import com.company.agentfoundation.integration.coze.service.CozeWorkflowService; +import com.company.agentfoundation.integration.wecom.client.WecomClient; import com.company.agentfoundation.semantic.SemanticDispatchResult; import com.company.agentfoundation.semantic.SemanticDispatchService; import com.company.agentfoundation.semantic.SemanticReplyAttachment; @@ -44,10 +45,15 @@ class AssistantApiControllerTest { @Test void generalApiAcceptsCustomerCreationAsynchronously() throws Exception { CozeWorkflowService coze = mock(CozeWorkflowService.class); + when(coze.chatDefault("新增客户 名称 张三 电话 13632363654")) + .thenReturn("企业微信智能表格批量写入成功"); + WecomClient wecom = mock(WecomClient.class); CapturingExecutor executor = new CapturingExecutor(); - MockMvc mvc = mvc(coze, mock(SemanticDispatchService.class), new AssistantFileStore(), executor); + MockMvc mvc = mvc( + coze, wecom, mock(SemanticDispatchService.class), new AssistantFileStore(), executor); mvc.perform(post("/api/assistant/general/query") + .header("X-WeCom-UserId", "YiNianYiQingJing") .contentType(MediaType.APPLICATION_JSON) .content("{\"query\":\"新增客户 名称 张三 电话 13632363654\"}")) .andExpect(status().isOk()) @@ -57,6 +63,10 @@ class AssistantApiControllerTest { org.mockito.Mockito.verifyNoInteractions(coze); executor.runCaptured(); verify(coze).chatDefault("新增客户 名称 张三 电话 13632363654"); + verify(wecom).sendText( + "general", + "YiNianYiQingJing", + "✅ 客户新增完成\n企业微信智能表格批量写入成功"); } @Test @@ -204,17 +214,18 @@ class AssistantApiControllerTest { SemanticDispatchService semantic, AssistantFileStore files ) { - return mvc(coze, semantic, files, Runnable::run); + return mvc(coze, mock(WecomClient.class), semantic, files, Runnable::run); } private MockMvc mvc( CozeWorkflowService coze, + WecomClient wecom, SemanticDispatchService semantic, AssistantFileStore files, Executor executor ) { return MockMvcBuilders.standaloneSetup( - new AssistantApiController(coze, semantic, files, executor)) + new AssistantApiController(coze, wecom, semantic, files, executor)) .setMessageConverters( new MappingJackson2HttpMessageConverter(), new ByteArrayHttpMessageConverter())