From c2af2d6365b4f5fe0da615ce31017c9fbb5c7746 Mon Sep 17 00:00:00 2001 From: v-zhangjc9 Date: Tue, 3 Jun 2025 20:23:52 +0800 Subject: [PATCH] =?UTF-8?q?feat(chat):=20=E5=B0=9D=E8=AF=95=E5=9C=A8?= =?UTF-8?q?=E5=AF=B9=E8=AF=9D=E4=B8=AD=E5=8A=A0=E5=85=A5=E7=9F=A5=E8=AF=86?= =?UTF-8?q?=E5=BA=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- service-ai/service-ai-chat/pom.xml | 5 ++ .../ai/chat/controller/ChatController.java | 81 ++++++++++++++----- .../service/ai/chat/entity/MessageVO.java | 10 +++ .../src/main/resources/application.yml | 4 +- .../service/ai/chat/TestChat.java | 1 - .../controller/KnowledgeController.java | 12 +++ .../ai/knowledge/entity/vo/KnowledgeVO.java | 10 +++ .../ai/knowledge/service/GroupService.java | 1 - .../knowledge/service/KnowledgeService.java | 38 ++++++++- .../service/node/EmbeddingNodes.java | 6 +- .../service/ai/knowledge/TestEmbedding.java | 27 +++++-- .../forest/service/KnowledgeService.java | 22 +++++ .../client/src/pages/ai/Conversation.tsx | 51 ++++++++---- .../src/pages/ai/knowledge/DataDetail.tsx | 2 +- 14 files changed, 216 insertions(+), 54 deletions(-) create mode 100644 service-forest/src/main/java/com/lanyuanxiaoyao/service/forest/service/KnowledgeService.java diff --git a/service-ai/service-ai-chat/pom.xml b/service-ai/service-ai-chat/pom.xml index efb09c3..3e96a43 100644 --- a/service-ai/service-ai-chat/pom.xml +++ b/service-ai/service-ai-chat/pom.xml @@ -19,6 +19,11 @@ org.springframework.ai spring-ai-starter-model-openai + test + + + org.springframework.ai + spring-ai-starter-model-deepseek diff --git a/service-ai/service-ai-chat/src/main/java/com/lanyuanxiaoyao/service/ai/chat/controller/ChatController.java b/service-ai/service-ai-chat/src/main/java/com/lanyuanxiaoyao/service/ai/chat/controller/ChatController.java index 4df3613..d910542 100644 --- a/service-ai/service-ai-chat/src/main/java/com/lanyuanxiaoyao/service/ai/chat/controller/ChatController.java +++ b/service-ai/service-ai-chat/src/main/java/com/lanyuanxiaoyao/service/ai/chat/controller/ChatController.java @@ -1,9 +1,12 @@ package com.lanyuanxiaoyao.service.ai.chat.controller; +import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; import com.lanyuanxiaoyao.service.ai.chat.entity.MessageVO; import com.lanyuanxiaoyao.service.ai.chat.tools.DatetimeTools; +import com.lanyuanxiaoyao.service.forest.service.KnowledgeService; import java.io.IOException; +import java.util.Optional; import org.eclipse.collections.api.list.ImmutableList; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -11,10 +14,14 @@ import org.springframework.ai.chat.client.ChatClient; import org.springframework.ai.chat.messages.AssistantMessage; import org.springframework.ai.chat.messages.Message; import org.springframework.ai.chat.messages.UserMessage; +import org.springframework.ai.chat.model.ChatResponse; +import org.springframework.ai.chat.model.Generation; +import org.springframework.ai.deepseek.DeepSeekAssistantMessage; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; @@ -28,26 +35,42 @@ import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; @RequestMapping("chat") public class ChatController { private static final Logger logger = LoggerFactory.getLogger(ChatController.class); + private static final String ROLE_ASSISTANT = "assistant"; + private static final String ROLE_USER = "user"; private final ChatClient chatClient; + private final KnowledgeService knowledgeService; - public ChatController(ChatClient.Builder builder) { + @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection") + public ChatController(ChatClient.Builder builder, KnowledgeService knowledgeService) { this.chatClient = builder.build(); + this.knowledgeService = knowledgeService; } - private ChatClient.ChatClientRequestSpec buildRequest(ImmutableList messages) { + private ChatClient.ChatClientRequestSpec buildRequest(Long knowledgeId, ImmutableList messages) { + var systemPromptBuilder = new StringBuilder(); + systemPromptBuilder.append(""" + 你是一名专业的AI运维助手,负责“Hudi数据同步服务平台”的运维工作; + 你将会友好地帮助用户解答关于该平台运维工作的问题,你会尽可能通过各种方式获取知识和数据来解答; + 对于无法通过已有知识回答的问题,你会提示用户你无法解答该问题,而不是虚构不存在的数据或答案; + 对于与该平台无关的问题,你会委婉地拒绝用户,并提示无法回答; + 你将始终在中文语境下进行对话。 + """); + if (ObjectUtil.isNotNull(knowledgeId)) { + var vo = messages.select(message -> StrUtil.equals(message.getRole(), "user")).getLastOptional().orElseThrow(); + var documents = knowledgeService.query(knowledgeId, vo.getContent()); + logger.info("Knowledge id:{}, content:{}", knowledgeId, vo.getContent()); + if (ObjectUtil.isNotEmpty(documents)) { + systemPromptBuilder.append("以下是与用户问题有关的外部知识,优先利用该知识回答用户的提问:\n"); + systemPromptBuilder.append(documents.makeString("\n")); + } + } return chatClient.prompt() - .system(""" - 你是一名专业的AI运维助手,负责“Hudi数据同步服务平台”的运维工作; - 你将会友好地帮助用户解答关于该平台运维工作的问题,你会尽可能通过各种方式获取知识和数据来解答; - 对于无法通过已有知识回答的问题,你会提示用户你无法解答该问题,而不是虚构不存在的数据或答案; - 对于与该平台无关的问题,你会委婉地拒绝用户,并提示无法回答; - 你将始终在中文语境下进行对话。 - """) + .system(systemPromptBuilder.toString()) .tools(new DatetimeTools()) .messages( messages - .collect(message -> StrUtil.equals(message.getRole(), "assistant") + .collect(message -> StrUtil.equals(message.getRole(), ROLE_ASSISTANT) ? new AssistantMessage(message.getContent()) : new UserMessage(message.getContent())) .collect(message -> (Message) message) @@ -57,23 +80,29 @@ public class ChatController { @PostMapping("sync") @ResponseBody - public String chatSync(@RequestBody ImmutableList messages) { - String content = buildRequest(messages) + public MessageVO chatSync( + @RequestParam(value = "knowledge_id", required = false) Long knowledgeId, + @RequestBody ImmutableList messages + ) { + ChatResponse response = buildRequest(knowledgeId, messages) .call() - .content(); - return StrUtil.trimToEmpty(content); + .chatResponse(); + return toMessage(response); } @PostMapping("async") - public SseEmitter chatAsync(@RequestBody ImmutableList messages) { + public SseEmitter chatAsync( + @RequestParam(value = "knowledge_id", required = false) Long knowledgeId, + @RequestBody ImmutableList messages + ) { SseEmitter emitter = new SseEmitter(); - buildRequest(messages) + buildRequest(knowledgeId, messages) .stream() - .content() + .chatResponse() .subscribe( - content -> { + response -> { try { - emitter.send(content); + emitter.send(toMessage(response)); } catch (IOException e) { emitter.completeWithError(e); throw new RuntimeException(e); @@ -84,4 +113,18 @@ public class ChatController { ); return emitter; } + + private MessageVO toMessage(ChatResponse response) { + AssistantMessage message = Optional.ofNullable(response) + .map(ChatResponse::getResult) + .map(Generation::getOutput) + .orElseThrow(() -> new RuntimeException("ChatResponse is null")); + MessageVO vo = new MessageVO(); + vo.setRole(ROLE_ASSISTANT); + vo.setContent(message.getText()); + if (message instanceof DeepSeekAssistantMessage deepseekMessage) { + vo.setReason(deepseekMessage.getReasoningContent()); + } + return vo; + } } diff --git a/service-ai/service-ai-chat/src/main/java/com/lanyuanxiaoyao/service/ai/chat/entity/MessageVO.java b/service-ai/service-ai-chat/src/main/java/com/lanyuanxiaoyao/service/ai/chat/entity/MessageVO.java index 0272189..90603e6 100644 --- a/service-ai/service-ai-chat/src/main/java/com/lanyuanxiaoyao/service/ai/chat/entity/MessageVO.java +++ b/service-ai/service-ai-chat/src/main/java/com/lanyuanxiaoyao/service/ai/chat/entity/MessageVO.java @@ -7,6 +7,7 @@ package com.lanyuanxiaoyao.service.ai.chat.entity; public class MessageVO { private String role; private String content; + private String reason; public String getRole() { return role; @@ -24,11 +25,20 @@ public class MessageVO { this.content = content; } + public String getReason() { + return reason; + } + + public void setReason(String reason) { + this.reason = reason; + } + @Override public String toString() { return "MessageVO{" + "role='" + role + '\'' + ", content='" + content + '\'' + + ", reason='" + reason + '\'' + '}'; } } diff --git a/service-ai/service-ai-chat/src/main/resources/application.yml b/service-ai/service-ai-chat/src/main/resources/application.yml index 600878a..2cc9504 100644 --- a/service-ai/service-ai-chat/src/main/resources/application.yml +++ b/service-ai/service-ai-chat/src/main/resources/application.yml @@ -4,8 +4,8 @@ spring: profiles: include: random-port,common,discovery,metrics,forest ai: - openai: - base-url: http://132.121.206.65:10086 + deepseek: + base-url: http://132.121.206.65:10086/v1 api-key: ENC(K+Hff9QGC+fcyi510VIDd9CaeK/IN5WBJ9rlkUsHEdDgIidW+stHHJlsK0lLPUXXREha+ToQZqqDXJrqSE+GUKCXklFhelD8bRHFXBIeP/ZzT2cxhzgKUXgjw3S0Qw2R) chat: options: diff --git a/service-ai/service-ai-chat/src/test/java/com/lanyuanxiaoyao/service/ai/chat/TestChat.java b/service-ai/service-ai-chat/src/test/java/com/lanyuanxiaoyao/service/ai/chat/TestChat.java index 21463ac..9939241 100644 --- a/service-ai/service-ai-chat/src/test/java/com/lanyuanxiaoyao/service/ai/chat/TestChat.java +++ b/service-ai/service-ai-chat/src/test/java/com/lanyuanxiaoyao/service/ai/chat/TestChat.java @@ -4,7 +4,6 @@ import org.springframework.ai.chat.client.ChatClient; import org.springframework.ai.openai.OpenAiChatModel; import org.springframework.ai.openai.OpenAiChatOptions; import org.springframework.ai.openai.api.OpenAiApi; -import reactor.core.Disposable; /** * @author lanyuanxiaoyao diff --git a/service-ai/service-ai-knowledge/src/main/java/com/lanyuanxiaoyao/service/ai/knowledge/controller/KnowledgeController.java b/service-ai/service-ai-knowledge/src/main/java/com/lanyuanxiaoyao/service/ai/knowledge/controller/KnowledgeController.java index 0b6ad77..c757195 100644 --- a/service-ai/service-ai-knowledge/src/main/java/com/lanyuanxiaoyao/service/ai/knowledge/controller/KnowledgeController.java +++ b/service-ai/service-ai-knowledge/src/main/java/com/lanyuanxiaoyao/service/ai/knowledge/controller/KnowledgeController.java @@ -8,10 +8,12 @@ import com.lanyuanxiaoyao.service.ai.knowledge.service.EmbeddingService; import com.lanyuanxiaoyao.service.ai.knowledge.service.KnowledgeService; import java.util.concurrent.ExecutionException; import org.eclipse.collections.api.factory.Lists; +import org.eclipse.collections.api.list.ImmutableList; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @@ -105,4 +107,14 @@ public class KnowledgeController { throw new IllegalArgumentException("Unsupported type: " + type); } } + + @PostMapping("query") + public ImmutableList query( + @RequestParam("id") Long id, + @RequestParam(value = "limit", defaultValue = "5") Integer limit, + @RequestParam(value = "threshold", defaultValue = "0.6") Double threshold, + @RequestBody String text + ) throws ExecutionException, InterruptedException { + return knowledgeService.query(id, text, limit, threshold); + } } diff --git a/service-ai/service-ai-knowledge/src/main/java/com/lanyuanxiaoyao/service/ai/knowledge/entity/vo/KnowledgeVO.java b/service-ai/service-ai-knowledge/src/main/java/com/lanyuanxiaoyao/service/ai/knowledge/entity/vo/KnowledgeVO.java index 6a2a0ec..5582878 100644 --- a/service-ai/service-ai-knowledge/src/main/java/com/lanyuanxiaoyao/service/ai/knowledge/entity/vo/KnowledgeVO.java +++ b/service-ai/service-ai-knowledge/src/main/java/com/lanyuanxiaoyao/service/ai/knowledge/entity/vo/KnowledgeVO.java @@ -6,6 +6,7 @@ package com.lanyuanxiaoyao.service.ai.knowledge.entity.vo; */ public class KnowledgeVO { private String id; + private String vectorSourceId; private String name; private String strategy; private Long size; @@ -23,6 +24,14 @@ public class KnowledgeVO { this.id = id; } + public String getVectorSourceId() { + return vectorSourceId; + } + + public void setVectorSourceId(String vectorSourceId) { + this.vectorSourceId = vectorSourceId; + } + public String getName() { return name; } @@ -91,6 +100,7 @@ public class KnowledgeVO { public String toString() { return "KnowledgeVO{" + "id='" + id + '\'' + + ", vectorSourceId='" + vectorSourceId + '\'' + ", name='" + name + '\'' + ", strategy='" + strategy + '\'' + ", size=" + size + diff --git a/service-ai/service-ai-knowledge/src/main/java/com/lanyuanxiaoyao/service/ai/knowledge/service/GroupService.java b/service-ai/service-ai-knowledge/src/main/java/com/lanyuanxiaoyao/service/ai/knowledge/service/GroupService.java index bf5ef12..bad5e28 100644 --- a/service-ai/service-ai-knowledge/src/main/java/com/lanyuanxiaoyao/service/ai/knowledge/service/GroupService.java +++ b/service-ai/service-ai-knowledge/src/main/java/com/lanyuanxiaoyao/service/ai/knowledge/service/GroupService.java @@ -109,7 +109,6 @@ public class GroupService { Long.class, groupId ); - logger.info("Delete {} {}", vectorSourceId, groupId); client.deleteAsync( String.valueOf(vectorSourceId), Points.Filter.newBuilder() diff --git a/service-ai/service-ai-knowledge/src/main/java/com/lanyuanxiaoyao/service/ai/knowledge/service/KnowledgeService.java b/service-ai/service-ai-knowledge/src/main/java/com/lanyuanxiaoyao/service/ai/knowledge/service/KnowledgeService.java index 12bf398..09ab7ad 100644 --- a/service-ai/service-ai-knowledge/src/main/java/com/lanyuanxiaoyao/service/ai/knowledge/service/KnowledgeService.java +++ b/service-ai/service-ai-knowledge/src/main/java/com/lanyuanxiaoyao/service/ai/knowledge/service/KnowledgeService.java @@ -9,14 +9,18 @@ import com.lanyuanxiaoyao.service.ai.knowledge.entity.vo.KnowledgeVO; import com.lanyuanxiaoyao.service.common.Constants; import io.qdrant.client.QdrantClient; import io.qdrant.client.grpc.Collections; +import java.util.List; import java.util.concurrent.ExecutionException; import java.util.stream.Collectors; import org.eclipse.collections.api.factory.Lists; import org.eclipse.collections.api.list.ImmutableList; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.ai.document.Document; import org.springframework.ai.embedding.EmbeddingModel; +import org.springframework.ai.vectorstore.SearchRequest; import org.springframework.ai.vectorstore.VectorStore; +import org.springframework.ai.vectorstore.qdrant.QdrantVectorStore; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.RowMapper; import org.springframework.stereotype.Service; @@ -41,13 +45,13 @@ public class KnowledgeService { return knowledge; }; private final JdbcTemplate template; - private final EmbeddingModel embeddingModel; + private final EmbeddingModel model; private final QdrantClient client; private final GroupService groupService; - public KnowledgeService(JdbcTemplate template, EmbeddingModel embeddingModel, VectorStore vectorStore, GroupService groupService) { + public KnowledgeService(JdbcTemplate template, EmbeddingModel model, VectorStore vectorStore, GroupService groupService) { this.template = template; - this.embeddingModel = embeddingModel; + this.model = model; this.client = (QdrantClient) vectorStore.getNativeClient().orElseThrow(); this.groupService = groupService; } @@ -93,7 +97,7 @@ public class KnowledgeService { String.valueOf(vectorSourceId), Collections.VectorParams.newBuilder() .setDistance(Collections.Distance.valueOf(strategy)) - .setSize(embeddingModel.dimensions()) + .setSize(model.dimensions()) .build() ).get(); } @@ -123,6 +127,7 @@ public class KnowledgeService { Collections.CollectionInfo info = client.getCollectionInfoAsync(String.valueOf(knowledge.getVectorSourceId())).get(); KnowledgeVO vo = new KnowledgeVO(); vo.setId(String.valueOf(knowledge.getId())); + vo.setVectorSourceId(String.valueOf(knowledge.getVectorSourceId())); vo.setName(knowledge.getName()); vo.setPoints(info.getPointsCount()); vo.setSegments(info.getSegmentsCount()); @@ -156,4 +161,29 @@ public class KnowledgeService { groupService.removeByKnowledgeId(knowledge.getId()); client.deleteCollectionAsync(String.valueOf(knowledge.getVectorSourceId())).get(); } + + public ImmutableList query( + Long id, + String text, + Integer limit, + Double threshold) throws ExecutionException, InterruptedException { + Knowledge knowledge = get(id); + Boolean exists = client.collectionExistsAsync(String.valueOf(knowledge.getVectorSourceId())).get(); + if (!exists) { + throw new RuntimeException(StrUtil.format("{} not exists", id)); + } + VectorStore vs = QdrantVectorStore.builder(client, model) + .collectionName(String.valueOf(knowledge.getVectorSourceId())) + .initializeSchema(false) + .build(); + List documents = vs.similaritySearch( + SearchRequest.builder() + .query(text) + .topK(limit) + .similarityThreshold(threshold) + .build() + ); + return Lists.immutable.ofAll(documents) + .collect(Document::getText); + } } \ No newline at end of file diff --git a/service-ai/service-ai-knowledge/src/main/java/com/lanyuanxiaoyao/service/ai/knowledge/service/node/EmbeddingNodes.java b/service-ai/service-ai-knowledge/src/main/java/com/lanyuanxiaoyao/service/ai/knowledge/service/node/EmbeddingNodes.java index a031d6f..d7bce25 100644 --- a/service-ai/service-ai-knowledge/src/main/java/com/lanyuanxiaoyao/service/ai/knowledge/service/node/EmbeddingNodes.java +++ b/service-ai/service-ai-knowledge/src/main/java/com/lanyuanxiaoyao/service/ai/knowledge/service/node/EmbeddingNodes.java @@ -215,8 +215,10 @@ public class EmbeddingNodes { .build(); for (Document document : context.getDocuments()) { Map metadata = document.getMetadata(); - metadata.put("filename", context.getFileFormat()); - metadata.put("filepath", context.getFile()); + if (StrUtil.isNotBlank(context.getFileFormat())) + metadata.put("filename", context.getFileFormat()); + if (StrUtil.isNotBlank(context.getFile())) + metadata.put("filepath", context.getFile()); metadata.put("group_id", String.valueOf(context.getGroupId())); metadata.put("vector_source_id", String.valueOf(context.getVectorSourceId())); } diff --git a/service-ai/service-ai-knowledge/src/test/java/com/lanyuanxiaoyao/service/ai/knowledge/TestEmbedding.java b/service-ai/service-ai-knowledge/src/test/java/com/lanyuanxiaoyao/service/ai/knowledge/TestEmbedding.java index e9249cf..6df4f85 100644 --- a/service-ai/service-ai-knowledge/src/test/java/com/lanyuanxiaoyao/service/ai/knowledge/TestEmbedding.java +++ b/service-ai/service-ai-knowledge/src/test/java/com/lanyuanxiaoyao/service/ai/knowledge/TestEmbedding.java @@ -2,7 +2,6 @@ package com.lanyuanxiaoyao.service.ai.knowledge; import io.qdrant.client.QdrantClient; import io.qdrant.client.QdrantGrpcClient; -import io.qdrant.client.grpc.Collections; import java.net.http.HttpClient; import java.util.List; import java.util.concurrent.ExecutionException; @@ -12,6 +11,7 @@ import org.springframework.ai.embedding.EmbeddingModel; import org.springframework.ai.openai.OpenAiEmbeddingModel; import org.springframework.ai.openai.OpenAiEmbeddingOptions; import org.springframework.ai.openai.api.OpenAiApi; +import org.springframework.ai.vectorstore.SearchRequest; import org.springframework.ai.vectorstore.VectorStore; import org.springframework.ai.vectorstore.qdrant.QdrantVectorStore; import org.springframework.http.client.JdkClientHttpRequestFactory; @@ -41,19 +41,30 @@ public class TestEmbedding { .build() ); QdrantClient client = new QdrantClient( - QdrantGrpcClient.newBuilder("localhost", 6334, false).build() + QdrantGrpcClient.newBuilder("132.121.206.65", 29463, false) + .withApiKey("jdHyKdp9qxNqCK3c") + .build() ); - client.createCollectionAsync( - "test", + /* client.createCollectionAsync( + "1927659521614176256", Collections.VectorParams.newBuilder() .setDistance(Collections.Distance.Cosine) .setSize(1024) .build() - ).get(); + ).get(); */ VectorStore store = QdrantVectorStore.builder(client, model) - .initializeSchema(true) - .collectionName("test") + .initializeSchema(false) + .collectionName("1929833382422159361") .build(); - store.add(List.of(new Document("hello world"))); + List documents = store.similaritySearch( + SearchRequest.builder() + .query("Hudi是什么") + .topK(5) + .similarityThreshold(0.2) + .build() + ); + for (Document document : documents) { + System.out.println(document.getText()); + } } } diff --git a/service-forest/src/main/java/com/lanyuanxiaoyao/service/forest/service/KnowledgeService.java b/service-forest/src/main/java/com/lanyuanxiaoyao/service/forest/service/KnowledgeService.java new file mode 100644 index 0000000..c3c8d55 --- /dev/null +++ b/service-forest/src/main/java/com/lanyuanxiaoyao/service/forest/service/KnowledgeService.java @@ -0,0 +1,22 @@ +package com.lanyuanxiaoyao.service.forest.service; + +import com.dtflys.forest.annotation.BaseRequest; +import com.dtflys.forest.annotation.Body; +import com.dtflys.forest.annotation.Post; +import com.dtflys.forest.annotation.Query; +import org.eclipse.collections.api.list.ImmutableList; + +/** + * 队列查询 + * + * @author lanyuanxiaoyao + * @date 2023-05-07 + */ +@BaseRequest(baseURL = "http://service-ai-knowledge/knowledge") +public interface KnowledgeService { + @Post(value = "/query", contentType = "plain/text") + ImmutableList query(@Query("id") Long id, @Body String text); + + @Post(value = "/query", contentType = "plain/text") + ImmutableList query(@Query("id") Long id, @Query("limit") Integer limit, @Query("threshold") Double threshold, @Body String text); +} diff --git a/service-web/client/src/pages/ai/Conversation.tsx b/service-web/client/src/pages/ai/Conversation.tsx index 248f9e1..3b186e9 100644 --- a/service-web/client/src/pages/ai/Conversation.tsx +++ b/service-web/client/src/pages/ai/Conversation.tsx @@ -2,10 +2,10 @@ import {ClearOutlined, FileOutlined, UserOutlined} from '@ant-design/icons' import {Bubble, Sender, useXAgent, useXChat, Welcome} from '@ant-design/x' import {fetchEventSource} from '@echofly/fetch-event-source' import {useMount} from 'ahooks' -import {Button, Divider, Flex, Popover, Radio, Switch, Tooltip, Typography} from 'antd' +import {Button, Collapse, Divider, Flex, Popover, Radio, Switch, Tooltip, Typography} from 'antd' import {isEqual, isStrBlank, trim} from 'licia' import markdownIt from 'markdown-it' -import {useRef, useState} from 'react' +import {useMemo, useRef, useState} from 'react' import styled from 'styled-components' import {commonInfo} from '../../util/amis.tsx' @@ -31,8 +31,8 @@ const ConversationDiv = styled.div` think { color: gray; display: block; - border-left: 3px solid; - padding-left: 5px; + border-left: 3px solid lightgray; + padding-left: 10px; margin-bottom: 10px; } } @@ -52,6 +52,13 @@ function Conversation() { const [think, setThink] = useState(true) const [knowledge, setKnowledge] = useState('0') const [knowledgeList, setKnowledgeList] = useState<{ id: string, name: string }[]>([]) + const requestUrl = useMemo(() => { + let url = `${commonInfo.baseAiChatUrl}/chat/async` + if (!isEqual('0', knowledge)) { + url = `${url}?knowledge_id=${knowledge}` + } + return url + }, [knowledge]) useMount(async () => { let response = await fetch(`${commonInfo.baseAiKnowledgeUrl}/knowledge/list`, { @@ -63,10 +70,6 @@ function Conversation() { const [agent] = useXAgent({ request: async (info, callbacks) => { - let requestUrl = `${commonInfo.baseAiChatUrl}/chat/async` - if (!isEqual('0', knowledge)) { - requestUrl = `${requestUrl}?knowledge=${knowledge}` - } await fetchEventSource(requestUrl, { method: 'POST', headers: commonInfo.authorizationHeaders, @@ -124,17 +127,33 @@ function Conversation() { }, }, messageRender: item => { - let content = '' + let content = '', reason = '' if (!isStrBlank(item['reason'])) { - content = `${trim(md.render(item['reason']))}${trim(md.render(item['content']))}` - } else { - content = trim(md.render(item['content'])) + reason = `${trim(md.render(item['reason']))}` } - console.log(content) + content = trim(md.render(item['content'])) return ( - -
- +
+ {isStrBlank(reason) + ? + : +
+ + ), + }, + ]} + />} + +
+ +
) }, }, diff --git a/service-web/client/src/pages/ai/knowledge/DataDetail.tsx b/service-web/client/src/pages/ai/knowledge/DataDetail.tsx index 8be9b96..3e6f751 100644 --- a/service-web/client/src/pages/ai/knowledge/DataDetail.tsx +++ b/service-web/client/src/pages/ai/knowledge/DataDetail.tsx @@ -146,7 +146,7 @@ const DataDetail: React.FC = () => { level: 'link', size: 'sm', actionType: 'ajax', - api: `${commonInfo.baseAiKnowledgeUrl}/group/delete?id=\${id}`, + api: `get:${commonInfo.baseAiKnowledgeUrl}/group/delete?id=\${id}`, confirmText: '确认删除', confirmTitle: '删除', },