From d9c317f94d4fe42f90996580f31d4deac50a341d Mon Sep 17 00:00:00 2001 From: haopeng <657407891@qq.com> Date: Sat, 21 Sep 2024 17:37:59 +0800 Subject: [PATCH] BIGTOP-4226: Support soft deletion in Chatbot (#71) --- .../ai/assistant/GeneralAssistantFactory.java | 6 ++- .../store/PersistentChatMemoryStore.java | 54 ++++++++++++------- .../{MessageSender.java => MessageType.java} | 12 ++--- .../ai/dashscope/DashScopeAssistant.java | 20 +++---- .../bigtop/manager/dao/po/ChatMessagePO.java | 3 ++ .../bigtop/manager/dao/po/ChatThreadPO.java | 3 ++ .../manager/dao/po/PlatformAuthorizedPO.java | 3 ++ .../dao/repository/ChatMessageDao.java | 2 - .../manager/dao/repository/ChatThreadDao.java | 4 +- .../dao/repository/PlatformAuthorizedDao.java | 4 ++ .../mapper/mysql/ChatMessageMapper.xml | 6 +-- .../mapper/mysql/ChatThreadMapper.xml | 11 +++- .../mapper/mysql/PlatformAuthorizedMapper.xml | 12 +++-- .../mapper/postgresql/ChatMessageMapper.xml | 6 +-- .../mapper/postgresql/ChatThreadMapper.xml | 18 ++++--- .../postgresql/PlatformAuthorizedMapper.xml | 11 ++-- .../server/controller/ChatbotController.java | 8 +-- .../model/converter/ChatMessageConverter.java | 6 +-- .../server/model/req/ChatbotMessageReq.java | 29 ++++++++++ .../server/model/vo/ChatMessageVO.java | 6 +-- .../service/impl/ChatbotServiceImpl.java | 29 +++++++--- .../main/resources/ddl/MySQL-DDL-CREATE.sql | 5 +- .../resources/ddl/PostgreSQL-DDL-CREATE.sql | 5 +- .../controller/ChatbotControllerTest.java | 9 ++-- 24 files changed, 180 insertions(+), 92 deletions(-) rename bigtop-manager-ai/bigtop-manager-ai-core/src/main/java/org/apache/bigtop/manager/ai/core/enums/{MessageSender.java => MessageType.java} (83%) create mode 100644 bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/model/req/ChatbotMessageReq.java diff --git a/bigtop-manager-ai/bigtop-manager-ai-assistant/src/main/java/org/apache/bigtop/manager/ai/assistant/GeneralAssistantFactory.java b/bigtop-manager-ai/bigtop-manager-ai-assistant/src/main/java/org/apache/bigtop/manager/ai/assistant/GeneralAssistantFactory.java index 1945ef09..e02b6776 100644 --- a/bigtop-manager-ai/bigtop-manager-ai-assistant/src/main/java/org/apache/bigtop/manager/ai/assistant/GeneralAssistantFactory.java +++ b/bigtop-manager-ai/bigtop-manager-ai-assistant/src/main/java/org/apache/bigtop/manager/ai/assistant/GeneralAssistantFactory.java @@ -19,6 +19,7 @@ package org.apache.bigtop.manager.ai.assistant; import org.apache.bigtop.manager.ai.assistant.provider.LocSystemPromptProvider; +import org.apache.bigtop.manager.ai.assistant.store.PersistentChatMemoryStore; import org.apache.bigtop.manager.ai.core.AbstractAIAssistantFactory; import org.apache.bigtop.manager.ai.core.enums.PlatformType; import org.apache.bigtop.manager.ai.core.enums.SystemPrompt; @@ -70,7 +71,10 @@ public AIAssistant createWithPrompt( case QIANFAN -> QianFanAssistant.builder(); }; AIAssistant aiAssistant = builder.id(id) - .memoryStore((id == null) ? new InMemoryChatMemoryStore() : chatMemoryStore) + .memoryStore( + (id == null) + ? new InMemoryChatMemoryStore() + : ((PersistentChatMemoryStore) chatMemoryStore).clone()) .withConfigProvider(assistantConfig) .build(); diff --git a/bigtop-manager-ai/bigtop-manager-ai-assistant/src/main/java/org/apache/bigtop/manager/ai/assistant/store/PersistentChatMemoryStore.java b/bigtop-manager-ai/bigtop-manager-ai-assistant/src/main/java/org/apache/bigtop/manager/ai/assistant/store/PersistentChatMemoryStore.java index ba4fd95e..a112b7bd 100644 --- a/bigtop-manager-ai/bigtop-manager-ai-assistant/src/main/java/org/apache/bigtop/manager/ai/assistant/store/PersistentChatMemoryStore.java +++ b/bigtop-manager-ai/bigtop-manager-ai-assistant/src/main/java/org/apache/bigtop/manager/ai/assistant/store/PersistentChatMemoryStore.java @@ -18,7 +18,7 @@ */ package org.apache.bigtop.manager.ai.assistant.store; -import org.apache.bigtop.manager.ai.core.enums.MessageSender; +import org.apache.bigtop.manager.ai.core.enums.MessageType; import org.apache.bigtop.manager.dao.po.ChatMessagePO; import org.apache.bigtop.manager.dao.po.ChatThreadPO; import org.apache.bigtop.manager.dao.repository.ChatMessageDao; @@ -33,13 +33,15 @@ import java.util.ArrayList; import java.util.List; -import java.util.stream.Collectors; +import java.util.Objects; public class PersistentChatMemoryStore implements ChatMemoryStore { private final ChatThreadDao chatThreadDao; private final ChatMessageDao chatMessageDao; + private final List systemMessages = new ArrayList<>(); + public PersistentChatMemoryStore(ChatThreadDao chatThreadDao, ChatMessageDao chatMessageDao) { this.chatThreadDao = chatThreadDao; this.chatMessageDao = chatMessageDao; @@ -47,12 +49,10 @@ public PersistentChatMemoryStore(ChatThreadDao chatThreadDao, ChatMessageDao cha private ChatMessage convertToChatMessage(ChatMessagePO chatMessagePO) { String sender = chatMessagePO.getSender().toLowerCase(); - if (sender.equals(MessageSender.AI.getValue())) { + if (sender.equals(MessageType.AI.getValue())) { return new AiMessage(chatMessagePO.getMessage()); - } else if (sender.equals(MessageSender.USER.getValue())) { + } else if (sender.equals(MessageType.USER.getValue())) { return new UserMessage(chatMessagePO.getMessage()); - } else if (sender.equals(MessageSender.SYSTEM.getValue())) { - return new SystemMessage(chatMessagePO.getMessage()); } else { return null; } @@ -61,21 +61,17 @@ private ChatMessage convertToChatMessage(ChatMessagePO chatMessagePO) { private ChatMessagePO convertToChatMessagePO(ChatMessage chatMessage, Long chatThreadId) { ChatMessagePO chatMessagePO = new ChatMessagePO(); if (chatMessage.type().equals(ChatMessageType.AI)) { - chatMessagePO.setSender(MessageSender.AI.getValue()); + chatMessagePO.setSender(MessageType.AI.getValue()); AiMessage aiMessage = (AiMessage) chatMessage; chatMessagePO.setMessage(aiMessage.text()); } else if (chatMessage.type().equals(ChatMessageType.USER)) { - chatMessagePO.setSender(MessageSender.USER.getValue()); + chatMessagePO.setSender(MessageType.USER.getValue()); UserMessage userMessage = (UserMessage) chatMessage; chatMessagePO.setMessage(userMessage.singleText()); - } else if (chatMessage.type().equals(ChatMessageType.SYSTEM)) { - chatMessagePO.setSender(MessageSender.SYSTEM.getValue()); - SystemMessage systemMessage = (SystemMessage) chatMessage; - chatMessagePO.setMessage(systemMessage.text()); } else { - chatMessagePO.setSender(chatMessage.type().toString()); + return null; } - ChatThreadPO chatThreadPO = chatThreadDao.findById(chatThreadId); + ChatThreadPO chatThreadPO = chatThreadDao.findByThreadId(chatThreadId); chatMessagePO.setUserId(chatThreadPO.getUserId()); chatMessagePO.setThreadId(chatThreadId); return chatMessagePO; @@ -84,21 +80,39 @@ private ChatMessagePO convertToChatMessagePO(ChatMessage chatMessage, Long chatT @Override public List getMessages(Object threadId) { List chatMessages = chatMessageDao.findAllByThreadId((Long) threadId); - if (chatMessages.isEmpty()) { - return new ArrayList<>(); - } else { - return chatMessages.stream().map(this::convertToChatMessage).collect(Collectors.toList()); + List allChatMessages = new ArrayList<>(systemMessages); + if (!chatMessages.isEmpty()) { + allChatMessages.addAll(chatMessages.stream() + .map(this::convertToChatMessage) + .filter(Objects::nonNull) + .toList()); } + return allChatMessages; } @Override public void updateMessages(Object threadId, List messages) { - ChatMessagePO chatMessagePO = convertToChatMessagePO(messages.get(messages.size() - 1), (Long) threadId); + ChatMessage newMessage = messages.get(messages.size() - 1); + if (newMessage.type().equals(ChatMessageType.SYSTEM)) { + SystemMessage systemMessage = (SystemMessage) newMessage; + systemMessages.add(systemMessage); + return; + } + ChatMessagePO chatMessagePO = convertToChatMessagePO(newMessage, (Long) threadId); + if (chatMessagePO == null) { + return; + } chatMessageDao.save(chatMessagePO); } @Override public void deleteMessages(Object threadId) { - chatMessageDao.deleteByThreadId((Long) threadId); + List chatMessagePOS = chatMessageDao.findAllByThreadId((Long) threadId); + chatMessagePOS.forEach(chatMessage -> chatMessage.setIsDeleted(true)); + chatMessageDao.partialUpdateByIds(chatMessagePOS); + } + + public PersistentChatMemoryStore clone() { + return new PersistentChatMemoryStore(chatThreadDao, chatMessageDao); } } diff --git a/bigtop-manager-ai/bigtop-manager-ai-core/src/main/java/org/apache/bigtop/manager/ai/core/enums/MessageSender.java b/bigtop-manager-ai/bigtop-manager-ai-core/src/main/java/org/apache/bigtop/manager/ai/core/enums/MessageType.java similarity index 83% rename from bigtop-manager-ai/bigtop-manager-ai-core/src/main/java/org/apache/bigtop/manager/ai/core/enums/MessageSender.java rename to bigtop-manager-ai/bigtop-manager-ai-core/src/main/java/org/apache/bigtop/manager/ai/core/enums/MessageType.java index 1c93085a..9f67b66d 100644 --- a/bigtop-manager-ai/bigtop-manager-ai-core/src/main/java/org/apache/bigtop/manager/ai/core/enums/MessageSender.java +++ b/bigtop-manager-ai/bigtop-manager-ai-core/src/main/java/org/apache/bigtop/manager/ai/core/enums/MessageType.java @@ -26,14 +26,14 @@ import java.util.stream.Collectors; @Getter -public enum MessageSender { +public enum MessageType { USER("user"), AI("ai"), SYSTEM("system"); private final String value; - MessageSender(String value) { + MessageType(String value) { this.value = value; } @@ -41,13 +41,13 @@ public static List getSenders() { return Arrays.stream(values()).map(item -> item.value).collect(Collectors.toList()); } - public static MessageSender getMessageSender(String value) { + public static MessageType getMessageSender(String value) { if (Objects.isNull(value) || value.isEmpty()) { return null; } - for (MessageSender messageSender : MessageSender.values()) { - if (messageSender.value.equals(value)) { - return messageSender; + for (MessageType messageType : MessageType.values()) { + if (messageType.value.equals(value)) { + return messageType; } } diff --git a/bigtop-manager-ai/bigtop-manager-ai-dashscope/src/main/java/org/apache/bigtop/manager/ai/dashscope/DashScopeAssistant.java b/bigtop-manager-ai/bigtop-manager-ai-dashscope/src/main/java/org/apache/bigtop/manager/ai/dashscope/DashScopeAssistant.java index 441fd38d..f178f8f0 100644 --- a/bigtop-manager-ai/bigtop-manager-ai-dashscope/src/main/java/org/apache/bigtop/manager/ai/dashscope/DashScopeAssistant.java +++ b/bigtop-manager-ai/bigtop-manager-ai-dashscope/src/main/java/org/apache/bigtop/manager/ai/dashscope/DashScopeAssistant.java @@ -19,7 +19,7 @@ package org.apache.bigtop.manager.ai.dashscope; import org.apache.bigtop.manager.ai.core.AbstractAIAssistant; -import org.apache.bigtop.manager.ai.core.enums.MessageSender; +import org.apache.bigtop.manager.ai.core.enums.MessageType; import org.apache.bigtop.manager.ai.core.enums.PlatformType; import org.apache.bigtop.manager.ai.core.factory.AIAssistant; @@ -88,13 +88,13 @@ private String getValueFromAssistantStreamMessage(AssistantStreamMessage assista return streamMessage.toString(); } - private void saveMessage(String message, MessageSender sender) { + private void addMessage(String message, MessageType sender) { ChatMessage chatMessage; - if (sender.equals(MessageSender.AI)) { + if (sender.equals(MessageType.AI)) { chatMessage = new AiMessage(message); - } else if (sender.equals(MessageSender.USER)) { + } else if (sender.equals(MessageType.USER)) { chatMessage = new UserMessage(message); - } else if (sender.equals(MessageSender.SYSTEM)) { + } else if (sender.equals(MessageType.SYSTEM)) { chatMessage = new SystemMessage(message); } else { return; @@ -131,7 +131,7 @@ public void setSystemPrompt(String systemPrompt) { } catch (NoApiKeyException | InputRequiredException | InvalidateParameter e) { throw new RuntimeException(e); } - saveMessage(systemPrompt, MessageSender.SYSTEM); + addMessage(systemPrompt, MessageType.SYSTEM); } public static Builder builder() { @@ -140,7 +140,7 @@ public static Builder builder() { @Override public Flux streamAsk(String userMessage) { - saveMessage(userMessage, MessageSender.USER); + addMessage(userMessage, MessageType.USER); TextMessageParam textMessageParam = TextMessageParam.builder() .apiKey(dashScopeThreadParam.getApiKey()) .role(Role.USER.getValue()) @@ -174,13 +174,13 @@ public Flux streamAsk(String userMessage) { return message; }) .doOnComplete(() -> { - saveMessage(finalMessage.toString(), MessageSender.AI); + addMessage(finalMessage.toString(), MessageType.AI); }); } @Override public String ask(String userMessage) { - saveMessage(userMessage, MessageSender.USER); + addMessage(userMessage, MessageType.USER); TextMessageParam textMessageParam = TextMessageParam.builder() .apiKey(dashScopeThreadParam.getApiKey()) .role(Role.USER.getValue()) @@ -244,7 +244,7 @@ public String ask(String userMessage) { ContentText contentText = (ContentText) content; finalMessage.append(contentText.getText().getValue()); } - saveMessage(finalMessage.toString(), MessageSender.AI); + addMessage(finalMessage.toString(), MessageType.AI); return finalMessage.toString(); } diff --git a/bigtop-manager-dao/src/main/java/org/apache/bigtop/manager/dao/po/ChatMessagePO.java b/bigtop-manager-dao/src/main/java/org/apache/bigtop/manager/dao/po/ChatMessagePO.java index 75cf6f63..e84414bd 100644 --- a/bigtop-manager-dao/src/main/java/org/apache/bigtop/manager/dao/po/ChatMessagePO.java +++ b/bigtop-manager-dao/src/main/java/org/apache/bigtop/manager/dao/po/ChatMessagePO.java @@ -45,4 +45,7 @@ public class ChatMessagePO extends BasePO implements Serializable { @Column(name = "thread_id", nullable = false) private Long threadId; + + @Column(name = "is_deleted") + private Boolean isDeleted; } diff --git a/bigtop-manager-dao/src/main/java/org/apache/bigtop/manager/dao/po/ChatThreadPO.java b/bigtop-manager-dao/src/main/java/org/apache/bigtop/manager/dao/po/ChatThreadPO.java index cddbb223..08a9e4b0 100644 --- a/bigtop-manager-dao/src/main/java/org/apache/bigtop/manager/dao/po/ChatThreadPO.java +++ b/bigtop-manager-dao/src/main/java/org/apache/bigtop/manager/dao/po/ChatThreadPO.java @@ -46,4 +46,7 @@ public class ChatThreadPO extends BasePO implements Serializable { @Column(name = "platform_id", nullable = false) private Long platformId; + + @Column(name = "is_deleted") + private Boolean isDeleted; } diff --git a/bigtop-manager-dao/src/main/java/org/apache/bigtop/manager/dao/po/PlatformAuthorizedPO.java b/bigtop-manager-dao/src/main/java/org/apache/bigtop/manager/dao/po/PlatformAuthorizedPO.java index 214f3a90..ecd943bc 100644 --- a/bigtop-manager-dao/src/main/java/org/apache/bigtop/manager/dao/po/PlatformAuthorizedPO.java +++ b/bigtop-manager-dao/src/main/java/org/apache/bigtop/manager/dao/po/PlatformAuthorizedPO.java @@ -41,4 +41,7 @@ public class PlatformAuthorizedPO extends BasePO implements Serializable { @Column(name = "platform_id", nullable = false) private Long platformId; + + @Column(name = "is_deleted") + private Boolean isDeleted; } diff --git a/bigtop-manager-dao/src/main/java/org/apache/bigtop/manager/dao/repository/ChatMessageDao.java b/bigtop-manager-dao/src/main/java/org/apache/bigtop/manager/dao/repository/ChatMessageDao.java index 59721afd..a81e9c6c 100644 --- a/bigtop-manager-dao/src/main/java/org/apache/bigtop/manager/dao/repository/ChatMessageDao.java +++ b/bigtop-manager-dao/src/main/java/org/apache/bigtop/manager/dao/repository/ChatMessageDao.java @@ -26,6 +26,4 @@ public interface ChatMessageDao extends BaseDao { List findAllByThreadId(@Param("threadId") Long threadId); - - void deleteByThreadId(@Param("threadId") Long threadId); } diff --git a/bigtop-manager-dao/src/main/java/org/apache/bigtop/manager/dao/repository/ChatThreadDao.java b/bigtop-manager-dao/src/main/java/org/apache/bigtop/manager/dao/repository/ChatThreadDao.java index 895cba8f..6c1e70b6 100644 --- a/bigtop-manager-dao/src/main/java/org/apache/bigtop/manager/dao/repository/ChatThreadDao.java +++ b/bigtop-manager-dao/src/main/java/org/apache/bigtop/manager/dao/repository/ChatThreadDao.java @@ -27,12 +27,12 @@ public interface ChatThreadDao extends BaseDao { List findAllByUserId(@Param("userId") Long userId); - ChatThreadPO findById(Long id); - ChatThreadPO findByThreadId(@Param("id") Long id); List findAllByPlatformAuthorizedIdAndUserId( @Param("platformId") Long platformAuthorizedId, @Param("userId") Long userId); void saveWithThreadInfo(ChatThreadPO chatThreadPO); + + List findAllByPlatformId(@Param("platformId") Long platformId); } diff --git a/bigtop-manager-dao/src/main/java/org/apache/bigtop/manager/dao/repository/PlatformAuthorizedDao.java b/bigtop-manager-dao/src/main/java/org/apache/bigtop/manager/dao/repository/PlatformAuthorizedDao.java index fd801d76..46da6eca 100644 --- a/bigtop-manager-dao/src/main/java/org/apache/bigtop/manager/dao/repository/PlatformAuthorizedDao.java +++ b/bigtop-manager-dao/src/main/java/org/apache/bigtop/manager/dao/repository/PlatformAuthorizedDao.java @@ -22,8 +22,12 @@ import org.apache.ibatis.annotations.Param; +import java.util.List; + public interface PlatformAuthorizedDao extends BaseDao { PlatformAuthorizedPO findByPlatformId(@Param("id") Long platformId); void saveWithCredentials(PlatformAuthorizedPO platformAuthorizedPO); + + List findAllPlatform(); } diff --git a/bigtop-manager-dao/src/main/resources/mapper/mysql/ChatMessageMapper.xml b/bigtop-manager-dao/src/main/resources/mapper/mysql/ChatMessageMapper.xml index 108410b1..19043443 100644 --- a/bigtop-manager-dao/src/main/resources/mapper/mysql/ChatMessageMapper.xml +++ b/bigtop-manager-dao/src/main/resources/mapper/mysql/ChatMessageMapper.xml @@ -26,11 +26,7 @@ SELECT * FROM llm_chat_message WHERE thread_id = #{threadId} + AND is_deleted = 0 - - DELETE FROM llm_chat_message - WHERE thread_id = #{threadId} - - \ No newline at end of file diff --git a/bigtop-manager-dao/src/main/resources/mapper/mysql/ChatThreadMapper.xml b/bigtop-manager-dao/src/main/resources/mapper/mysql/ChatThreadMapper.xml index 5ecd9a2a..adecfc11 100644 --- a/bigtop-manager-dao/src/main/resources/mapper/mysql/ChatThreadMapper.xml +++ b/bigtop-manager-dao/src/main/resources/mapper/mysql/ChatThreadMapper.xml @@ -33,16 +33,17 @@ SELECT * FROM llm_chat_thread WHERE user_id = #{userId} + AND is_deleted = 0 @@ -55,4 +56,10 @@ thread_info = VALUES(thread_info) + + \ No newline at end of file diff --git a/bigtop-manager-dao/src/main/resources/mapper/mysql/PlatformAuthorizedMapper.xml b/bigtop-manager-dao/src/main/resources/mapper/mysql/PlatformAuthorizedMapper.xml index f065a4c7..e9fa2bf4 100644 --- a/bigtop-manager-dao/src/main/resources/mapper/mysql/PlatformAuthorizedMapper.xml +++ b/bigtop-manager-dao/src/main/resources/mapper/mysql/PlatformAuthorizedMapper.xml @@ -31,15 +31,19 @@ + + INSERT INTO llm_platform_authorized (platform_id, credentials) VALUES (#{platformId}, #{credentials, typeHandler=org.apache.bigtop.manager.dao.handler.JsonTypeHandler}) - ON DUPLICATE KEY UPDATE - platform_id = VALUES(platform_id), - credentials = VALUES(credentials) + ON DUPLICATE KEY UPDATE + platform_id = VALUES(platform_id), + credentials = VALUES(credentials) \ No newline at end of file diff --git a/bigtop-manager-dao/src/main/resources/mapper/postgresql/ChatMessageMapper.xml b/bigtop-manager-dao/src/main/resources/mapper/postgresql/ChatMessageMapper.xml index 108410b1..660399e9 100644 --- a/bigtop-manager-dao/src/main/resources/mapper/postgresql/ChatMessageMapper.xml +++ b/bigtop-manager-dao/src/main/resources/mapper/postgresql/ChatMessageMapper.xml @@ -26,11 +26,7 @@ SELECT * FROM llm_chat_message WHERE thread_id = #{threadId} + AND is_deleted = false - - DELETE FROM llm_chat_message - WHERE thread_id = #{threadId} - - \ No newline at end of file diff --git a/bigtop-manager-dao/src/main/resources/mapper/postgresql/ChatThreadMapper.xml b/bigtop-manager-dao/src/main/resources/mapper/postgresql/ChatThreadMapper.xml index 5ecd9a2a..a742bed3 100644 --- a/bigtop-manager-dao/src/main/resources/mapper/postgresql/ChatThreadMapper.xml +++ b/bigtop-manager-dao/src/main/resources/mapper/postgresql/ChatThreadMapper.xml @@ -33,26 +33,28 @@ SELECT * FROM llm_chat_thread WHERE user_id = #{userId} + AND is_deleted = false INSERT INTO llm_chat_thread (platform_id, user_id, model, thread_info) - VALUES (#{platformId}, #{userId}, #{model}, #{threadInfo, typeHandler=org.apache.bigtop.manager.dao.handler.JsonTypeHandler}) - ON DUPLICATE KEY UPDATE - platform_id = VALUES(platform_id), - user_id = VALUES(user_id), - model = VALUES(model), - thread_info = VALUES(thread_info) + VALUES (#{platformId}, #{userId}, #{model}, #{threadInfo, typeHandler=org.apache.bigtop.manager.dao.handler.JsonTypeHandler}::json) + + \ No newline at end of file diff --git a/bigtop-manager-dao/src/main/resources/mapper/postgresql/PlatformAuthorizedMapper.xml b/bigtop-manager-dao/src/main/resources/mapper/postgresql/PlatformAuthorizedMapper.xml index f065a4c7..518d295d 100644 --- a/bigtop-manager-dao/src/main/resources/mapper/postgresql/PlatformAuthorizedMapper.xml +++ b/bigtop-manager-dao/src/main/resources/mapper/postgresql/PlatformAuthorizedMapper.xml @@ -31,15 +31,16 @@ + + INSERT INTO llm_platform_authorized (platform_id, credentials) - VALUES (#{platformId}, #{credentials, typeHandler=org.apache.bigtop.manager.dao.handler.JsonTypeHandler}) - ON DUPLICATE KEY UPDATE - platform_id = VALUES(platform_id), - credentials = VALUES(credentials) + VALUES (#{platformId}, #{credentials, typeHandler=org.apache.bigtop.manager.dao.handler.JsonTypeHandler}::json) \ No newline at end of file diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/controller/ChatbotController.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/controller/ChatbotController.java index 77711939..c09680a4 100644 --- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/controller/ChatbotController.java +++ b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/controller/ChatbotController.java @@ -20,6 +20,7 @@ import org.apache.bigtop.manager.server.model.converter.PlatformConverter; import org.apache.bigtop.manager.server.model.dto.PlatformDTO; +import org.apache.bigtop.manager.server.model.req.ChatbotMessageReq; import org.apache.bigtop.manager.server.model.req.PlatformReq; import org.apache.bigtop.manager.server.model.vo.ChatMessageVO; import org.apache.bigtop.manager.server.model.vo.ChatThreadVO; @@ -66,7 +67,7 @@ public ResponseEntity> authorizedPlatforms() { return ResponseEntity.success(chatbotService.authorizedPlatforms()); } - @Operation(summary = "platforms", description = "Get authorized platforms") + @Operation(summary = "platforms", description = "Get platform auth credentials") @GetMapping("/platforms/{platformId}/auth/credential") public ResponseEntity> platformsAuthCredential(@PathVariable Long platformId) { return ResponseEntity.success(chatbotService.platformsAuthCredential(platformId)); @@ -106,8 +107,9 @@ public ResponseEntity> getAllChatThreads( @Operation(summary = "talk", description = "Talk with Chatbot") @PostMapping("platforms/{platformId}/threads/{threadId}/talk") - public SseEmitter talk(@PathVariable Long platformId, @PathVariable Long threadId, @RequestParam String message) { - return chatbotService.talk(platformId, threadId, message); + public SseEmitter talk( + @PathVariable Long platformId, @PathVariable Long threadId, @RequestBody ChatbotMessageReq messageReq) { + return chatbotService.talk(platformId, threadId, messageReq.getMessage()); } @Operation(summary = "history", description = "Get chat records") diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/model/converter/ChatMessageConverter.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/model/converter/ChatMessageConverter.java index b2c17238..714f2d1e 100644 --- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/model/converter/ChatMessageConverter.java +++ b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/model/converter/ChatMessageConverter.java @@ -18,7 +18,7 @@ */ package org.apache.bigtop.manager.server.model.converter; -import org.apache.bigtop.manager.ai.core.enums.MessageSender; +import org.apache.bigtop.manager.ai.core.enums.MessageType; import org.apache.bigtop.manager.dao.po.ChatMessagePO; import org.apache.bigtop.manager.server.config.MapStructSharedConfig; import org.apache.bigtop.manager.server.model.vo.ChatMessageVO; @@ -32,12 +32,12 @@ public interface ChatMessageConverter { ChatMessageVO fromPO2VO(ChatMessagePO chatMessagePO); - default MessageSender mapStringToMessageSender(String sender) { + default MessageType mapStringToMessageSender(String sender) { if (sender == null) { return null; } try { - return MessageSender.valueOf(sender.toUpperCase()); + return MessageType.valueOf(sender.toUpperCase()); } catch (IllegalArgumentException e) { return null; } diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/model/req/ChatbotMessageReq.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/model/req/ChatbotMessageReq.java new file mode 100644 index 00000000..3bcbe0cf --- /dev/null +++ b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/model/req/ChatbotMessageReq.java @@ -0,0 +1,29 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.bigtop.manager.server.model.req; + +import lombok.Data; + +import jakarta.validation.constraints.NotEmpty; + +@Data +public class ChatbotMessageReq { + @NotEmpty + private String message; +} diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/model/vo/ChatMessageVO.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/model/vo/ChatMessageVO.java index da226da0..7ad366a8 100644 --- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/model/vo/ChatMessageVO.java +++ b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/model/vo/ChatMessageVO.java @@ -18,19 +18,19 @@ */ package org.apache.bigtop.manager.server.model.vo; -import org.apache.bigtop.manager.ai.core.enums.MessageSender; +import org.apache.bigtop.manager.ai.core.enums.MessageType; import lombok.Data; @Data public class ChatMessageVO { - private MessageSender sender; + private MessageType sender; private String message; private String createTime; - public ChatMessageVO(MessageSender sender, String messageText, String createTime) { + public ChatMessageVO(MessageType sender, String messageText, String createTime) { this.sender = sender; this.message = messageText; this.createTime = createTime; diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/service/impl/ChatbotServiceImpl.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/service/impl/ChatbotServiceImpl.java index c338340e..7148ee32 100644 --- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/service/impl/ChatbotServiceImpl.java +++ b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/service/impl/ChatbotServiceImpl.java @@ -21,7 +21,7 @@ import org.apache.bigtop.manager.ai.assistant.GeneralAssistantFactory; import org.apache.bigtop.manager.ai.assistant.provider.AIAssistantConfig; import org.apache.bigtop.manager.ai.assistant.store.PersistentChatMemoryStore; -import org.apache.bigtop.manager.ai.core.enums.MessageSender; +import org.apache.bigtop.manager.ai.core.enums.MessageType; import org.apache.bigtop.manager.ai.core.enums.PlatformType; import org.apache.bigtop.manager.ai.core.factory.AIAssistant; import org.apache.bigtop.manager.ai.core.factory.AIAssistantFactory; @@ -137,7 +137,7 @@ public List platforms() { @Override public List authorizedPlatforms() { List authorizedPlatforms = new ArrayList<>(); - List authorizedPlatformPOs = platformAuthorizedDao.findAll(); + List authorizedPlatformPOs = platformAuthorizedDao.findAllPlatform(); for (PlatformAuthorizedPO authorizedPlatformPO : authorizedPlatformPOs) { PlatformPO platformPO = platformDao.findById(authorizedPlatformPO.getPlatformId()); authorizedPlatforms.add(PlatformAuthorizedConverter.INSTANCE.fromPO2VO(authorizedPlatformPO, platformPO)); @@ -209,10 +209,19 @@ public List platformsAuthCredential(Long platformId) { @Override public boolean deleteAuthorizedPlatform(Long platformId) { - List authorizedPlatformPOs = platformAuthorizedDao.findAll(); + List authorizedPlatformPOs = platformAuthorizedDao.findAllPlatform(); for (PlatformAuthorizedPO authorizedPlatformPO : authorizedPlatformPOs) { if (authorizedPlatformPO.getId().equals(platformId)) { - platformAuthorizedDao.deleteById(authorizedPlatformPO.getId()); + authorizedPlatformPO.setIsDeleted(true); + platformAuthorizedDao.partialUpdateById(authorizedPlatformPO); + List chatThreadPOS = chatThreadDao.findAllByPlatformId(authorizedPlatformPO.getId()); + chatThreadPOS.forEach(chatThread -> chatThread.setIsDeleted(true)); + chatThreadDao.partialUpdateByIds(chatThreadPOS); + for (ChatThreadPO chatThreadPO : chatThreadPOS) { + List chatMessagePOS = chatMessageDao.findAllByThreadId(chatThreadPO.getId()); + chatMessagePOS.forEach(chatMessage -> chatMessage.setIsDeleted(true)); + chatMessageDao.partialUpdateByIds(chatMessagePOS); + } return true; } } @@ -253,7 +262,11 @@ public boolean deleteChatThreads(Long platformId, Long threadId) { for (ChatThreadPO chatThreadPO : chatThreadPOS) { if (chatThreadPO.getId().equals(threadId) && chatThreadPO.getPlatformId().equals(platformId)) { - chatThreadDao.deleteById(threadId); + chatThreadPO.setIsDeleted(true); + chatThreadDao.partialUpdateById(chatThreadPO); + List chatMessagePOS = chatMessageDao.findAllByThreadId(threadId); + chatMessagePOS.forEach(chatMessage -> chatMessage.setIsDeleted(true)); + chatMessageDao.partialUpdateByIds(chatMessagePOS); return true; } } @@ -312,7 +325,7 @@ public SseEmitter talk(Long platformId, Long threadId, String message) { @Override public List history(Long platformId, Long threadId) { List chatMessages = new ArrayList<>(); - ChatThreadPO chatThreadPO = chatThreadDao.findById(threadId); + ChatThreadPO chatThreadPO = chatThreadDao.findByThreadId(threadId); if (chatThreadPO == null) { throw new ApiException(ApiExceptionEnum.CHAT_THREAD_NOT_FOUND); } @@ -323,11 +336,11 @@ public List history(Long platformId, Long threadId) { List chatMessagePOs = chatMessageDao.findAllByThreadId(threadId); for (ChatMessagePO chatMessagePO : chatMessagePOs) { ChatMessageVO chatMessageVO = ChatMessageConverter.INSTANCE.fromPO2VO(chatMessagePO); - MessageSender sender = chatMessageVO.getSender(); + MessageType sender = chatMessageVO.getSender(); if (sender == null) { continue; } - if (sender.equals(MessageSender.USER) || sender.equals(MessageSender.AI)) { + if (sender.equals(MessageType.USER) || sender.equals(MessageType.AI)) { chatMessages.add(chatMessageVO); } } diff --git a/bigtop-manager-server/src/main/resources/ddl/MySQL-DDL-CREATE.sql b/bigtop-manager-server/src/main/resources/ddl/MySQL-DDL-CREATE.sql index f702df79..dc67ea79 100644 --- a/bigtop-manager-server/src/main/resources/ddl/MySQL-DDL-CREATE.sql +++ b/bigtop-manager-server/src/main/resources/ddl/MySQL-DDL-CREATE.sql @@ -328,6 +328,7 @@ CREATE TABLE `llm_platform_authorized` `id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT, `platform_id` BIGINT(20) UNSIGNED NOT NULL, `credentials` JSON NOT NULL, + `is_deleted` TINYINT(1) DEFAULT 0 NULL, `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP, `update_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, `create_by` BIGINT DEFAULT NULL, @@ -342,6 +343,7 @@ CREATE TABLE `llm_chat_thread` `platform_id` BIGINT(20) UNSIGNED NOT NULL, `user_id` BIGINT(20) UNSIGNED NOT NULL, `model` VARCHAR(255) NOT NULL, + `is_deleted` TINYINT(1) DEFAULT 0 NULL, `thread_info` JSON DEFAULT NULL, `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP, `update_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, @@ -359,6 +361,7 @@ CREATE TABLE `llm_chat_message` `user_id` BIGINT(20) UNSIGNED NOT NULL, `message` TEXT NOT NULL, `sender` VARCHAR(50) NOT NULL, + `is_deleted` TINYINT(1) DEFAULT 0 NULL, `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP, `update_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, `create_by` BIGINT DEFAULT NULL, @@ -376,5 +379,5 @@ VALUES (1, now(), now(), 'Administrator', '21232f297a57a5a743894a0e4a801fc3', tr INSERT INTO bigtop_manager.llm_platform (id, credential, name, support_models) VALUES (1, '{"apiKey": "API Key"}', 'OpenAI', 'gpt-3.5-turbo,gpt-4,gpt-4o,gpt-3.5-turbo-16k,gpt-4-turbo-preview,gpt-4-32k,gpt-4o-mini'), -(2, '{"apiKey": "API Key"}', 'DashScope', 'qwen-max,qwen-plus,qwen-turbo'), +(2, '{"apiKey": "API Key"}', 'DashScope', 'qwen-1.8b-chat,qwen-max,qwen-plus,qwen-turbo'), (3, '{"apiKey": "API Key", "secretKey": "Secret Key"}', 'QianFan','Yi-34B-Chat,ERNIE-4.0-8K,ERNIE-3.5-128K,ERNIE-Speed-8K,Llama-2-7B-Chat,Fuyu-8B'); diff --git a/bigtop-manager-server/src/main/resources/ddl/PostgreSQL-DDL-CREATE.sql b/bigtop-manager-server/src/main/resources/ddl/PostgreSQL-DDL-CREATE.sql index 3a94b405..8ae24936 100644 --- a/bigtop-manager-server/src/main/resources/ddl/PostgreSQL-DDL-CREATE.sql +++ b/bigtop-manager-server/src/main/resources/ddl/PostgreSQL-DDL-CREATE.sql @@ -338,6 +338,7 @@ CREATE TABLE llm_platform_authorized id BIGINT CHECK (id > 0) NOT NULL GENERATED ALWAYS AS IDENTITY, platform_id BIGINT CHECK (platform_id > 0) NOT NULL, credentials JSON NOT NULL, + is_deleted BOOLEAN DEFAULT FALSE, create_time TIMESTAMP(0) DEFAULT CURRENT_TIMESTAMP, update_time TIMESTAMP(0) DEFAULT CURRENT_TIMESTAMP /* ON UPDATE CURRENT_TIMESTAMP */, create_by BIGINT DEFAULT NULL, @@ -354,6 +355,7 @@ CREATE TABLE llm_chat_thread user_id BIGINT CHECK (user_id > 0) NOT NULL, model VARCHAR(255) NOT NULL, thread_info JSON DEFAULT NULL, + is_deleted BOOLEAN DEFAULT FALSE, create_time TIMESTAMP(0) DEFAULT CURRENT_TIMESTAMP, update_time TIMESTAMP(0) DEFAULT CURRENT_TIMESTAMP /* ON UPDATE CURRENT_TIMESTAMP */, create_by BIGINT DEFAULT NULL, @@ -371,6 +373,7 @@ CREATE TABLE llm_chat_message user_id BIGINT CHECK (user_id > 0) NOT NULL, message TEXT NOT NULL, sender VARCHAR(50) NOT NULL, + is_deleted BOOLEAN DEFAULT FALSE, create_time TIMESTAMP(0) DEFAULT CURRENT_TIMESTAMP, update_time TIMESTAMP(0) DEFAULT CURRENT_TIMESTAMP /* ON UPDATE CURRENT_TIMESTAMP */, create_by BIGINT DEFAULT NULL, @@ -387,5 +390,5 @@ VALUES (now(), now(), 'Administrator', '21232f297a57a5a743894a0e4a801fc3', true, INSERT INTO llm_platform (credential, NAME, support_models) VALUES ('{"apiKey": "API Key"}','OpenAI','gpt-3.5-turbo,gpt-4,gpt-4o,gpt-3.5-turbo-16k,gpt-4-turbo-preview,gpt-4-32k,gpt-4o-mini'), -('{"apiKey": "API Key"}','DashScope','qwen-max,qwen-plus,qwen-turbo'), +('{"apiKey": "API Key"}','DashScope','qwen-1.8b-chat,qwen-max,qwen-plus,qwen-turbo'), ('{"apiKey": "API Key", "secretKey": "Secret Key"}','QianFan','Yi-34B-Chat,ERNIE-4.0-8K,ERNIE-3.5-128K,ERNIE-Speed-8K,Llama-2-7B-Chat,Fuyu-8B'); diff --git a/bigtop-manager-server/src/test/java/org/apache/bigtop/manager/server/controller/ChatbotControllerTest.java b/bigtop-manager-server/src/test/java/org/apache/bigtop/manager/server/controller/ChatbotControllerTest.java index d5f12ba8..04148917 100644 --- a/bigtop-manager-server/src/test/java/org/apache/bigtop/manager/server/controller/ChatbotControllerTest.java +++ b/bigtop-manager-server/src/test/java/org/apache/bigtop/manager/server/controller/ChatbotControllerTest.java @@ -19,6 +19,7 @@ package org.apache.bigtop.manager.server.controller; import org.apache.bigtop.manager.server.model.dto.PlatformDTO; +import org.apache.bigtop.manager.server.model.req.ChatbotMessageReq; import org.apache.bigtop.manager.server.model.req.PlatformReq; import org.apache.bigtop.manager.server.model.vo.ChatMessageVO; import org.apache.bigtop.manager.server.model.vo.ChatThreadVO; @@ -174,12 +175,14 @@ void getAllChatThreads() { void talk() { Long platformId = 1L; Long threadId = 1L; - String message = "Hello"; + ChatbotMessageReq messageReq = new ChatbotMessageReq(); + messageReq.setMessage("Hello"); SseEmitter emitter = new SseEmitter(); - when(chatbotService.talk(eq(platformId), eq(threadId), eq(message))).thenReturn(emitter); + when(chatbotService.talk(eq(platformId), eq(threadId), eq(messageReq.getMessage()))) + .thenReturn(emitter); - SseEmitter result = chatbotController.talk(platformId, threadId, message); + SseEmitter result = chatbotController.talk(platformId, threadId, messageReq); assertEquals(emitter, result); }