This commit is contained in:
tanglong 2026-07-31 17:59:10 +08:00
parent 35d1245529
commit 1e61d35d5c
2 changed files with 36 additions and 3 deletions

View File

@ -55,7 +55,8 @@ public class AssistantApiController {
String query = request == null ? "" : request.normalizedQuery(); String query = request == null ? "" : request.normalizedQuery();
if (query.isEmpty()) return AssistantQueryResponse.failure("query不能为空"); if (query.isEmpty()) return AssistantQueryResponse.failure("query不能为空");
try { try {
return AssistantQueryResponse.success(cozeWorkflowService.chatDefault(query), List.of()); return AssistantQueryResponse.success(
toRobotPlainText(cozeWorkflowService.chatDefault(query)), List.of());
} catch (RuntimeException exception) { } catch (RuntimeException exception) {
log.error("assistant general api failed err={}", exception.getMessage(), exception); log.error("assistant general api failed err={}", exception.getMessage(), exception);
return AssistantQueryResponse.failure("扣子问答调用失败,请稍后重试。"); return AssistantQueryResponse.failure("扣子问答调用失败,请稍后重试。");
@ -133,8 +134,9 @@ public class AssistantApiController {
String reply, String reply,
List<AssistantQueryResponse.Attachment> attachments List<AssistantQueryResponse.Attachment> attachments
) { ) {
if (attachments.isEmpty()) return reply == null ? "" : reply; String robotReply = toRobotPlainText(reply);
StringBuilder content = new StringBuilder(reply == null ? "" : reply); if (attachments.isEmpty()) return robotReply;
StringBuilder content = new StringBuilder(robotReply);
content.append("\n\n附件:"); content.append("\n\n附件:");
for (AssistantQueryResponse.Attachment attachment : attachments) { for (AssistantQueryResponse.Attachment attachment : attachments) {
content.append("\n- [").append(attachment.name()).append("](") content.append("\n- [").append(attachment.name()).append("](")
@ -143,6 +145,19 @@ public class AssistantApiController {
return content.toString(); return content.toString();
} }
/**
* API plugins render responses as plain text, so application-message font tags must not leak
* into the robot conversation.
*/
private String toRobotPlainText(String value) {
if (value == null || value.isBlank()) return "";
return value
.replaceAll("(?i)</?font\\b[^>]*>", "")
.replace("\r\n", "\n")
.replace('\r', '\n')
.trim();
}
private String resolveUserId( private String resolveUserId(
AssistantQueryRequest request, AssistantQueryRequest request,
HttpServletRequest httpRequest HttpServletRequest httpRequest

View File

@ -162,6 +162,24 @@ class AssistantApiControllerTest {
.andExpect(jsonPath("$.content").value(org.hamcrest.Matchers.containsString("UserID"))); .andExpect(jsonPath("$.content").value(org.hamcrest.Matchers.containsString("UserID")));
} }
@Test
void sportsVenueApiRemovesUnsupportedWecomFontTags() throws Exception {
SemanticDispatchService semantic = mock(SemanticDispatchService.class);
when(semantic.dispatchWithAttachments("tester", "daily report"))
.thenReturn(new SemanticDispatchResult(
"new: <font color=\"info\">35</font>\n"
+ "warning: <font color=\"warning\">low rate</font>",
List.of()));
MockMvc mvc = mvc(mock(CozeWorkflowService.class), semantic, new AssistantFileStore());
mvc.perform(post("/api/assistant/sports-venue/query")
.header("X-WeCom-UserId", "tester")
.contentType(MediaType.APPLICATION_JSON)
.content("{\"query\":\"daily report\"}"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.content").value("new: 35\nwarning: low rate"));
}
private MockMvc mvc( private MockMvc mvc(
CozeWorkflowService coze, CozeWorkflowService coze,
SemanticDispatchService semantic, SemanticDispatchService semantic,