feat(chat): 尝试在对话中加入知识库
This commit is contained in:
@@ -19,6 +19,11 @@
|
||||
<dependency>
|
||||
<groupId>org.springframework.ai</groupId>
|
||||
<artifactId>spring-ai-starter-model-openai</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.ai</groupId>
|
||||
<artifactId>spring-ai-starter-model-deepseek</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
|
||||
@@ -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<MessageVO> messages) {
|
||||
private ChatClient.ChatClientRequestSpec buildRequest(Long knowledgeId, ImmutableList<MessageVO> 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<MessageVO> messages) {
|
||||
String content = buildRequest(messages)
|
||||
public MessageVO chatSync(
|
||||
@RequestParam(value = "knowledge_id", required = false) Long knowledgeId,
|
||||
@RequestBody ImmutableList<MessageVO> messages
|
||||
) {
|
||||
ChatResponse response = buildRequest(knowledgeId, messages)
|
||||
.call()
|
||||
.content();
|
||||
return StrUtil.trimToEmpty(content);
|
||||
.chatResponse();
|
||||
return toMessage(response);
|
||||
}
|
||||
|
||||
@PostMapping("async")
|
||||
public SseEmitter chatAsync(@RequestBody ImmutableList<MessageVO> messages) {
|
||||
public SseEmitter chatAsync(
|
||||
@RequestParam(value = "knowledge_id", required = false) Long knowledgeId,
|
||||
@RequestBody ImmutableList<MessageVO> 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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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<String> 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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 +
|
||||
|
||||
@@ -109,7 +109,6 @@ public class GroupService {
|
||||
Long.class,
|
||||
groupId
|
||||
);
|
||||
logger.info("Delete {} {}", vectorSourceId, groupId);
|
||||
client.deleteAsync(
|
||||
String.valueOf(vectorSourceId),
|
||||
Points.Filter.newBuilder()
|
||||
|
||||
@@ -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<String> 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<Document> documents = vs.similaritySearch(
|
||||
SearchRequest.builder()
|
||||
.query(text)
|
||||
.topK(limit)
|
||||
.similarityThreshold(threshold)
|
||||
.build()
|
||||
);
|
||||
return Lists.immutable.ofAll(documents)
|
||||
.collect(Document::getText);
|
||||
}
|
||||
}
|
||||
@@ -215,8 +215,10 @@ public class EmbeddingNodes {
|
||||
.build();
|
||||
for (Document document : context.getDocuments()) {
|
||||
Map<String, Object> 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()));
|
||||
}
|
||||
|
||||
@@ -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<Document> documents = store.similaritySearch(
|
||||
SearchRequest.builder()
|
||||
.query("Hudi是什么")
|
||||
.topK(5)
|
||||
.similarityThreshold(0.2)
|
||||
.build()
|
||||
);
|
||||
for (Document document : documents) {
|
||||
System.out.println(document.getText());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<String> query(@Query("id") Long id, @Body String text);
|
||||
|
||||
@Post(value = "/query", contentType = "plain/text")
|
||||
ImmutableList<String> query(@Query("id") Long id, @Query("limit") Integer limit, @Query("threshold") Double threshold, @Body String text);
|
||||
}
|
||||
@@ -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<boolean>(true)
|
||||
const [knowledge, setKnowledge] = useState<string>('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<ChatMessage>({
|
||||
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 = `<think>${trim(md.render(item['reason']))}</think>${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 (
|
||||
<Typography>
|
||||
<div dangerouslySetInnerHTML={{__html: content}}/>
|
||||
</Typography>
|
||||
<div>
|
||||
{isStrBlank(reason)
|
||||
? <span/>
|
||||
: <Collapse
|
||||
size="small"
|
||||
items={[
|
||||
{
|
||||
key: 0,
|
||||
label: '思考链',
|
||||
children: (
|
||||
<Typography>
|
||||
<div dangerouslySetInnerHTML={{__html: reason}}/>
|
||||
</Typography>
|
||||
),
|
||||
},
|
||||
]}
|
||||
/>}
|
||||
<Typography>
|
||||
<div dangerouslySetInnerHTML={{__html: content}}/>
|
||||
</Typography>
|
||||
</div>
|
||||
)
|
||||
},
|
||||
},
|
||||
|
||||
@@ -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: '删除',
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user