diff --git a/bigtop-manager-ai/bigtop-manager-ai-assistant/pom.xml b/bigtop-manager-ai/bigtop-manager-ai-assistant/pom.xml
index 62ca8b3f..f1810e8b 100644
--- a/bigtop-manager-ai/bigtop-manager-ai-assistant/pom.xml
+++ b/bigtop-manager-ai/bigtop-manager-ai-assistant/pom.xml
@@ -39,6 +39,10 @@
org.apache.bigtop
bigtop-manager-ai-core
+
+ org.apache.bigtop
+ bigtop-manager-ai-dashscope
+
org.apache.bigtop
bigtop-manager-dao
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 2bc988e8..7ff16bcf 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.provider.PersistentStoreProvider;
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;
@@ -26,37 +27,36 @@
import org.apache.bigtop.manager.ai.core.factory.AIAssistant;
import org.apache.bigtop.manager.ai.core.factory.ToolBox;
import org.apache.bigtop.manager.ai.core.provider.AIAssistantConfigProvider;
+import org.apache.bigtop.manager.ai.core.provider.MessageStoreProvider;
import org.apache.bigtop.manager.ai.core.provider.SystemPromptProvider;
+import org.apache.bigtop.manager.ai.dashscope.DashScopeAssistant;
import org.apache.bigtop.manager.ai.openai.OpenAIAssistant;
import org.apache.commons.lang3.NotImplementedException;
-import dev.langchain4j.data.message.SystemMessage;
-import dev.langchain4j.store.memory.chat.ChatMemoryStore;
-import dev.langchain4j.store.memory.chat.InMemoryChatMemoryStore;
-
import java.util.Objects;
public class GeneralAssistantFactory extends AbstractAIAssistantFactory {
private final SystemPromptProvider systemPromptProvider;
- private final ChatMemoryStore chatMemoryStore;
+ private final MessageStoreProvider messageStoreProvider;
public GeneralAssistantFactory() {
- this(new LocSystemPromptProvider(), new InMemoryChatMemoryStore());
+ this(new LocSystemPromptProvider(), new PersistentStoreProvider());
}
public GeneralAssistantFactory(SystemPromptProvider systemPromptProvider) {
- this(systemPromptProvider, new InMemoryChatMemoryStore());
+ this(systemPromptProvider, new PersistentStoreProvider());
}
- public GeneralAssistantFactory(ChatMemoryStore chatMemoryStore) {
- this(new LocSystemPromptProvider(), chatMemoryStore);
+ public GeneralAssistantFactory(MessageStoreProvider messageStoreProvider) {
+ this(new LocSystemPromptProvider(), messageStoreProvider);
}
- public GeneralAssistantFactory(SystemPromptProvider systemPromptProvider, ChatMemoryStore chatMemoryStore) {
+ public GeneralAssistantFactory(
+ SystemPromptProvider systemPromptProvider, MessageStoreProvider messageStoreProvider) {
this.systemPromptProvider = systemPromptProvider;
- this.chatMemoryStore = chatMemoryStore;
+ this.messageStoreProvider = messageStoreProvider;
}
@Override
@@ -69,14 +69,19 @@ public AIAssistant createWithPrompt(
if (Objects.requireNonNull(platformType) == PlatformType.OPENAI) {
aiAssistant = OpenAIAssistant.builder()
.id(id)
- .memoryStore(chatMemoryStore)
+ .memoryStore(messageStoreProvider.getChatMemoryStore())
.withConfigProvider(assistantConfig)
.build();
+ } else if (Objects.requireNonNull(platformType) == PlatformType.DASH_SCOPE) {
+ aiAssistant = DashScopeAssistant.builder()
+ .id(id)
+ .withConfigProvider(assistantConfig)
+ .messageRepository(messageStoreProvider.getMessageRepository())
+ .build();
} else {
throw new PlatformNotFoundException(platformType.getValue());
}
-
- SystemMessage systemPrompt = systemPromptProvider.getSystemPrompt(systemPrompts);
+ String systemPrompt = systemPromptProvider.getSystemMessage(systemPrompts);
aiAssistant.setSystemPrompt(systemPrompt);
String locale = assistantConfig.getLanguage();
if (locale != null) {
diff --git a/bigtop-manager-ai/bigtop-manager-ai-assistant/src/main/java/org/apache/bigtop/manager/ai/assistant/provider/AIAssistantConfig.java b/bigtop-manager-ai/bigtop-manager-ai-assistant/src/main/java/org/apache/bigtop/manager/ai/assistant/provider/AIAssistantConfig.java
index fdd3b0da..132c37a1 100644
--- a/bigtop-manager-ai/bigtop-manager-ai-assistant/src/main/java/org/apache/bigtop/manager/ai/assistant/provider/AIAssistantConfig.java
+++ b/bigtop-manager-ai/bigtop-manager-ai-assistant/src/main/java/org/apache/bigtop/manager/ai/assistant/provider/AIAssistantConfig.java
@@ -109,7 +109,9 @@ public Builder addConfig(String key, String value) {
}
public Builder addConfigs(Map configMap) {
- configs.putAll(configMap);
+ if (configMap != null) {
+ configs.putAll(configMap);
+ }
return this;
}
diff --git a/bigtop-manager-ai/bigtop-manager-ai-assistant/src/main/java/org/apache/bigtop/manager/ai/assistant/provider/LocSystemPromptProvider.java b/bigtop-manager-ai/bigtop-manager-ai-assistant/src/main/java/org/apache/bigtop/manager/ai/assistant/provider/LocSystemPromptProvider.java
index 7163fb25..33e16e7d 100644
--- a/bigtop-manager-ai/bigtop-manager-ai-assistant/src/main/java/org/apache/bigtop/manager/ai/assistant/provider/LocSystemPromptProvider.java
+++ b/bigtop-manager-ai/bigtop-manager-ai-assistant/src/main/java/org/apache/bigtop/manager/ai/assistant/provider/LocSystemPromptProvider.java
@@ -23,7 +23,6 @@
import org.springframework.util.ResourceUtils;
-import dev.langchain4j.data.message.SystemMessage;
import lombok.extern.slf4j.Slf4j;
import java.io.File;
@@ -36,7 +35,7 @@
public class LocSystemPromptProvider implements SystemPromptProvider {
@Override
- public SystemMessage getSystemPrompt(SystemPrompt systemPrompt) {
+ public String getSystemMessage(SystemPrompt systemPrompt) {
if (systemPrompt == SystemPrompt.DEFAULT_PROMPT) {
systemPrompt = SystemPrompt.BIGDATA_PROFESSOR;
}
@@ -45,8 +44,8 @@ public SystemMessage getSystemPrompt(SystemPrompt systemPrompt) {
}
@Override
- public SystemMessage getSystemPrompt() {
- return getSystemPrompt(SystemPrompt.DEFAULT_PROMPT);
+ public String getSystemMessage() {
+ return getSystemMessage(SystemPrompt.DEFAULT_PROMPT);
}
private String loadTextFromFile(String fileName) {
@@ -64,23 +63,23 @@ private String loadTextFromFile(String fileName) {
}
}
- private SystemMessage loadPromptFromFile(String fileName) {
+ private String loadPromptFromFile(String fileName) {
final String filePath = fileName + ".st";
String text = loadTextFromFile(filePath);
if (text == null) {
- return SystemMessage.from("You are a helpful assistant.");
+ return "You are a helpful assistant.";
} else {
- return SystemMessage.from(text);
+ return text;
}
}
- public SystemMessage getLanguagePrompt(String locale) {
+ public String getLanguagePrompt(String locale) {
final String filePath = SystemPrompt.LANGUAGE_PROMPT.getValue() + '-' + locale + ".st";
String text = loadTextFromFile(filePath);
if (text == null) {
- return SystemMessage.from("Answer in " + locale);
+ return "Answer in " + locale;
} else {
- return SystemMessage.from(text);
+ return text;
}
}
}
diff --git a/bigtop-manager-ai/bigtop-manager-ai-assistant/src/main/java/org/apache/bigtop/manager/ai/assistant/provider/PersistentStoreProvider.java b/bigtop-manager-ai/bigtop-manager-ai-assistant/src/main/java/org/apache/bigtop/manager/ai/assistant/provider/PersistentStoreProvider.java
new file mode 100644
index 00000000..3e24ced9
--- /dev/null
+++ b/bigtop-manager-ai/bigtop-manager-ai-assistant/src/main/java/org/apache/bigtop/manager/ai/assistant/provider/PersistentStoreProvider.java
@@ -0,0 +1,61 @@
+/*
+ * 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.ai.assistant.provider;
+
+import org.apache.bigtop.manager.ai.assistant.store.PersistentChatMemoryStore;
+import org.apache.bigtop.manager.ai.assistant.store.PersistentMessageRepository;
+import org.apache.bigtop.manager.ai.core.provider.MessageStoreProvider;
+import org.apache.bigtop.manager.ai.core.repository.MessageRepository;
+import org.apache.bigtop.manager.dao.repository.ChatMessageDao;
+import org.apache.bigtop.manager.dao.repository.ChatThreadDao;
+
+import dev.langchain4j.store.memory.chat.ChatMemoryStore;
+import dev.langchain4j.store.memory.chat.InMemoryChatMemoryStore;
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class PersistentStoreProvider implements MessageStoreProvider {
+ private final ChatThreadDao chatThreadDao;
+ private final ChatMessageDao chatMessageDao;
+
+ public PersistentStoreProvider(ChatThreadDao chatThreadDao, ChatMessageDao chatMessageDao) {
+ this.chatThreadDao = chatThreadDao;
+ this.chatMessageDao = chatMessageDao;
+ }
+
+ public PersistentStoreProvider() {
+ chatMessageDao = null;
+ chatThreadDao = null;
+ }
+
+ @Override
+ public MessageRepository getMessageRepository() {
+ return new PersistentMessageRepository(chatThreadDao, chatMessageDao);
+ }
+
+ @Override
+ public ChatMemoryStore getChatMemoryStore() {
+ if (chatThreadDao == null) {
+ return new InMemoryChatMemoryStore();
+ }
+ return new PersistentChatMemoryStore(chatThreadDao, chatMessageDao);
+ }
+}
diff --git a/bigtop-manager-ai/bigtop-manager-ai-assistant/src/main/java/org/apache/bigtop/manager/ai/assistant/store/PersistentMessageRepository.java b/bigtop-manager-ai/bigtop-manager-ai-assistant/src/main/java/org/apache/bigtop/manager/ai/assistant/store/PersistentMessageRepository.java
new file mode 100644
index 00000000..7b9c3715
--- /dev/null
+++ b/bigtop-manager-ai/bigtop-manager-ai-assistant/src/main/java/org/apache/bigtop/manager/ai/assistant/store/PersistentMessageRepository.java
@@ -0,0 +1,80 @@
+/*
+ * 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.ai.assistant.store;
+
+import org.apache.bigtop.manager.ai.core.enums.MessageSender;
+import org.apache.bigtop.manager.ai.core.repository.MessageRepository;
+import org.apache.bigtop.manager.dao.po.ChatMessagePO;
+import org.apache.bigtop.manager.dao.po.ChatThreadPO;
+import org.apache.bigtop.manager.dao.repository.ChatMessageDao;
+import org.apache.bigtop.manager.dao.repository.ChatThreadDao;
+
+public class PersistentMessageRepository implements MessageRepository {
+ private final ChatThreadDao chatThreadDao;
+ private final ChatMessageDao chatMessageDao;
+
+ private boolean noPersistent() {
+ return chatThreadDao == null || chatMessageDao == null;
+ }
+
+ public PersistentMessageRepository(ChatThreadDao chatThreadDao, ChatMessageDao chatMessageDao) {
+ this.chatThreadDao = chatThreadDao;
+ this.chatMessageDao = chatMessageDao;
+ }
+
+ private ChatMessagePO getChatMessagePO(String message, Long threadId, MessageSender sender) {
+ if (noPersistent()) {
+ return null;
+ }
+ ChatThreadPO chatThreadPO = chatThreadDao.findById(threadId);
+ ChatMessagePO chatMessagePO = new ChatMessagePO();
+ chatMessagePO.setUserId(chatThreadPO.getUserId());
+ chatMessagePO.setThreadId(threadId);
+ chatMessagePO.setSender(sender.getValue());
+ chatMessagePO.setMessage(message);
+ return chatMessagePO;
+ }
+
+ @Override
+ public void saveUserMessage(String message, Long threadId) {
+ if (noPersistent()) {
+ return;
+ }
+ ChatMessagePO chatMessagePO = getChatMessagePO(message, threadId, MessageSender.USER);
+ chatMessageDao.save(chatMessagePO);
+ }
+
+ @Override
+ public void saveAiMessage(String message, Long threadId) {
+ if (noPersistent()) {
+ return;
+ }
+ ChatMessagePO chatMessagePO = getChatMessagePO(message, threadId, MessageSender.AI);
+ chatMessageDao.save(chatMessagePO);
+ }
+
+ @Override
+ public void saveSystemMessage(String message, Long threadId) {
+ if (noPersistent()) {
+ return;
+ }
+ ChatMessagePO chatMessagePO = getChatMessagePO(message, threadId, MessageSender.SYSTEM);
+ chatMessageDao.save(chatMessagePO);
+ }
+}
diff --git a/bigtop-manager-ai/bigtop-manager-ai-assistant/src/test/java/org/apache/bigtop/manager/ai/assistant/SystemPromptProviderTests.java b/bigtop-manager-ai/bigtop-manager-ai-assistant/src/test/java/org/apache/bigtop/manager/ai/assistant/SystemPromptProviderTests.java
index 1f768e17..6094a763 100644
--- a/bigtop-manager-ai/bigtop-manager-ai-assistant/src/test/java/org/apache/bigtop/manager/ai/assistant/SystemPromptProviderTests.java
+++ b/bigtop-manager-ai/bigtop-manager-ai-assistant/src/test/java/org/apache/bigtop/manager/ai/assistant/SystemPromptProviderTests.java
@@ -24,8 +24,6 @@
import org.junit.jupiter.api.Test;
-import dev.langchain4j.data.message.SystemMessage;
-
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
@@ -35,12 +33,12 @@ public class SystemPromptProviderTests {
@Test
public void loadSystemPromptByIdTest() {
- SystemMessage systemPrompt1 = systemPromptProvider.getSystemPrompt(SystemPrompt.BIGDATA_PROFESSOR);
- assertFalse(systemPrompt1.text().isEmpty());
+ String systemPrompt1 = systemPromptProvider.getSystemMessage(SystemPrompt.BIGDATA_PROFESSOR);
+ assertFalse(systemPrompt1.isEmpty());
- SystemMessage systemPrompt2 = systemPromptProvider.getSystemPrompt();
- assertFalse(systemPrompt2.text().isEmpty());
+ String systemPrompt2 = systemPromptProvider.getSystemMessage();
+ assertFalse(systemPrompt2.isEmpty());
- assertEquals(systemPrompt1.text(), systemPrompt2.text());
+ assertEquals(systemPrompt1, systemPrompt2);
}
}
diff --git a/bigtop-manager-ai/bigtop-manager-ai-core/src/main/java/org/apache/bigtop/manager/ai/core/AbstractAIAssistant.java b/bigtop-manager-ai/bigtop-manager-ai-core/src/main/java/org/apache/bigtop/manager/ai/core/AbstractAIAssistant.java
index 5b0f383a..d7b155f8 100644
--- a/bigtop-manager-ai/bigtop-manager-ai-core/src/main/java/org/apache/bigtop/manager/ai/core/AbstractAIAssistant.java
+++ b/bigtop-manager-ai/bigtop-manager-ai-core/src/main/java/org/apache/bigtop/manager/ai/core/AbstractAIAssistant.java
@@ -20,85 +20,12 @@
import org.apache.bigtop.manager.ai.core.factory.AIAssistant;
-import dev.langchain4j.data.message.AiMessage;
-import dev.langchain4j.data.message.ChatMessage;
-import dev.langchain4j.data.message.SystemMessage;
-import dev.langchain4j.memory.ChatMemory;
-import dev.langchain4j.model.StreamingResponseHandler;
-import dev.langchain4j.model.chat.ChatLanguageModel;
-import dev.langchain4j.model.chat.StreamingChatLanguageModel;
-import dev.langchain4j.model.output.Response;
-import reactor.core.publisher.Flux;
-import reactor.core.publisher.FluxSink;
-
public abstract class AbstractAIAssistant implements AIAssistant {
- private final ChatLanguageModel chatLanguageModel;
- private final StreamingChatLanguageModel streamingChatLanguageModel;
- private final Object assistantId;
- private final ChatMemory chatMemory;
protected static final Integer MEMORY_LEN = 10;
- public AbstractAIAssistant(
- ChatLanguageModel chatLanguageModel,
- StreamingChatLanguageModel streamingChatLanguageModel,
- ChatMemory chatMemory) {
- this.chatLanguageModel = chatLanguageModel;
- this.streamingChatLanguageModel = streamingChatLanguageModel;
- this.chatMemory = chatMemory;
- this.assistantId = this.chatMemory.id();
- }
-
- @Override
- public Flux streamAsk(ChatMessage chatMessage) {
- chatMemory.add(chatMessage);
- return Flux.create(
- emitter -> streamingChatLanguageModel.generate(chatMemory.messages(), new StreamingResponseHandler<>() {
- @Override
- public void onNext(String token) {
- emitter.next(token);
- }
-
- @Override
- public void onError(Throwable error) {
- emitter.error(error);
- }
-
- @Override
- public void onComplete(Response response) {
- StreamingResponseHandler.super.onComplete(response);
- chatMemory.add(response.content());
- }
- }),
- FluxSink.OverflowStrategy.BUFFER);
- }
-
- @Override
- public String ask(ChatMessage chatMessage) {
- chatMemory.add(chatMessage);
- Response generate = chatLanguageModel.generate(chatMemory.messages());
- String aiMessage = generate.content().text();
- chatMemory.add(AiMessage.from(aiMessage));
- return aiMessage;
- }
-
- @Override
- public void setSystemPrompt(SystemMessage systemPrompt) {
- chatMemory.add(systemPrompt);
- }
-
- @Override
- public Object getId() {
- return chatMemory.id();
- }
-
- @Override
- public void resetMemory() {
- chatMemory.clear();
- }
-
@Override
- public ChatMemory getMemory() {
- return this.chatMemory;
+ public boolean test() {
+ return ask("1+1=") != null;
}
}
diff --git a/bigtop-manager-ai/bigtop-manager-ai-core/src/main/java/org/apache/bigtop/manager/ai/core/enums/PlatformType.java b/bigtop-manager-ai/bigtop-manager-ai-core/src/main/java/org/apache/bigtop/manager/ai/core/enums/PlatformType.java
index cadbb2a6..83029c93 100644
--- a/bigtop-manager-ai/bigtop-manager-ai-core/src/main/java/org/apache/bigtop/manager/ai/core/enums/PlatformType.java
+++ b/bigtop-manager-ai/bigtop-manager-ai-core/src/main/java/org/apache/bigtop/manager/ai/core/enums/PlatformType.java
@@ -27,7 +27,8 @@
@Getter
public enum PlatformType {
- OPENAI("openai");
+ OPENAI("openai"),
+ DASH_SCOPE("dashscope");
private final String value;
diff --git a/bigtop-manager-ai/bigtop-manager-ai-core/src/main/java/org/apache/bigtop/manager/ai/core/factory/AIAssistant.java b/bigtop-manager-ai/bigtop-manager-ai-core/src/main/java/org/apache/bigtop/manager/ai/core/factory/AIAssistant.java
index 6834b051..b79474c5 100644
--- a/bigtop-manager-ai/bigtop-manager-ai-core/src/main/java/org/apache/bigtop/manager/ai/core/factory/AIAssistant.java
+++ b/bigtop-manager-ai/bigtop-manager-ai-core/src/main/java/org/apache/bigtop/manager/ai/core/factory/AIAssistant.java
@@ -20,12 +20,11 @@
import org.apache.bigtop.manager.ai.core.enums.PlatformType;
-import dev.langchain4j.data.message.ChatMessage;
-import dev.langchain4j.data.message.SystemMessage;
-import dev.langchain4j.data.message.UserMessage;
-import dev.langchain4j.memory.ChatMemory;
import reactor.core.publisher.Flux;
+import java.util.HashMap;
+import java.util.Map;
+
public interface AIAssistant {
/**
@@ -40,40 +39,38 @@ public interface AIAssistant {
* @param userMessage
* @return
*/
- Flux streamAsk(ChatMessage userMessage);
+ Flux streamAsk(String userMessage);
/**
* This is a conversation based on blocking output.
* @param userMessage
* @return
*/
- String ask(ChatMessage userMessage);
+ String ask(String userMessage);
/**
- * This is primarily used to retrieve the AI assistant's history of chat conversations.
+ * This is used to get the AIAssistant's Platform
* @return
*/
- ChatMemory getMemory();
+ PlatformType getPlatform();
/**
- * This is used to get the AIAssistant's Platform
+ * This is used to create a thread
* @return
*/
- PlatformType getPlatform();
-
- void setSystemPrompt(SystemMessage systemPrompt);
-
- void resetMemory();
-
- default Flux streamAsk(String message) {
- return streamAsk(UserMessage.from(message));
+ default Map createThread() {
+ return new HashMap<>();
}
- default String ask(String message) {
- return ask(UserMessage.from(message));
- }
+ /**
+ * This is used to set system prompt
+ * @return
+ */
+ void setSystemPrompt(String systemPrompt);
- default void setSystemPrompt(String systemPrompt) {
- setSystemPrompt(SystemMessage.systemMessage(systemPrompt));
- }
+ /**
+ * This is used to test whether the configuration is correct
+ * @return
+ */
+ boolean test();
}
diff --git a/bigtop-manager-ai/bigtop-manager-ai-core/src/main/java/org/apache/bigtop/manager/ai/core/factory/AIAssistantFactory.java b/bigtop-manager-ai/bigtop-manager-ai-core/src/main/java/org/apache/bigtop/manager/ai/core/factory/AIAssistantFactory.java
index d6b24034..5a7d63a0 100644
--- a/bigtop-manager-ai/bigtop-manager-ai-core/src/main/java/org/apache/bigtop/manager/ai/core/factory/AIAssistantFactory.java
+++ b/bigtop-manager-ai/bigtop-manager-ai-core/src/main/java/org/apache/bigtop/manager/ai/core/factory/AIAssistantFactory.java
@@ -22,8 +22,6 @@
import org.apache.bigtop.manager.ai.core.enums.SystemPrompt;
import org.apache.bigtop.manager.ai.core.provider.AIAssistantConfigProvider;
-import java.util.UUID;
-
public interface AIAssistantFactory {
AIAssistant createWithPrompt(
@@ -31,15 +29,8 @@ AIAssistant createWithPrompt(
AIAssistant create(PlatformType platformType, AIAssistantConfigProvider assistantConfig, Object id);
- /**
- * TODO Create AIAssistant without memory, should delete UUID
- *
- * @param platformType platform type
- * @param assistantConfig assistant config
- * @return AIAssistant
- */
default AIAssistant create(PlatformType platformType, AIAssistantConfigProvider assistantConfig) {
- return create(platformType, assistantConfig, UUID.randomUUID().toString());
+ return create(platformType, assistantConfig, null);
}
ToolBox createToolBox(PlatformType platformType);
diff --git a/bigtop-manager-ai/bigtop-manager-ai-core/src/main/java/org/apache/bigtop/manager/ai/core/provider/MessageStoreProvider.java b/bigtop-manager-ai/bigtop-manager-ai-core/src/main/java/org/apache/bigtop/manager/ai/core/provider/MessageStoreProvider.java
new file mode 100644
index 00000000..9e7fee15
--- /dev/null
+++ b/bigtop-manager-ai/bigtop-manager-ai-core/src/main/java/org/apache/bigtop/manager/ai/core/provider/MessageStoreProvider.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.ai.core.provider;
+
+import org.apache.bigtop.manager.ai.core.repository.MessageRepository;
+
+import dev.langchain4j.store.memory.chat.ChatMemoryStore;
+
+public interface MessageStoreProvider {
+ MessageRepository getMessageRepository();
+
+ ChatMemoryStore getChatMemoryStore();
+}
diff --git a/bigtop-manager-ai/bigtop-manager-ai-core/src/main/java/org/apache/bigtop/manager/ai/core/provider/SystemPromptProvider.java b/bigtop-manager-ai/bigtop-manager-ai-core/src/main/java/org/apache/bigtop/manager/ai/core/provider/SystemPromptProvider.java
index 90f0013a..83bb0d50 100644
--- a/bigtop-manager-ai/bigtop-manager-ai-core/src/main/java/org/apache/bigtop/manager/ai/core/provider/SystemPromptProvider.java
+++ b/bigtop-manager-ai/bigtop-manager-ai-core/src/main/java/org/apache/bigtop/manager/ai/core/provider/SystemPromptProvider.java
@@ -20,14 +20,12 @@
import org.apache.bigtop.manager.ai.core.enums.SystemPrompt;
-import dev.langchain4j.data.message.SystemMessage;
-
public interface SystemPromptProvider {
- SystemMessage getSystemPrompt(SystemPrompt systemPrompt);
+ String getSystemMessage(SystemPrompt systemPrompt);
// return default system prompt
- SystemMessage getSystemPrompt();
+ String getSystemMessage();
- SystemMessage getLanguagePrompt(String locale);
+ String getLanguagePrompt(String locale);
}
diff --git a/bigtop-manager-ai/bigtop-manager-ai-core/src/main/java/org/apache/bigtop/manager/ai/core/repository/MessageRepository.java b/bigtop-manager-ai/bigtop-manager-ai-core/src/main/java/org/apache/bigtop/manager/ai/core/repository/MessageRepository.java
new file mode 100644
index 00000000..1ad582f1
--- /dev/null
+++ b/bigtop-manager-ai/bigtop-manager-ai-core/src/main/java/org/apache/bigtop/manager/ai/core/repository/MessageRepository.java
@@ -0,0 +1,27 @@
+/*
+ * 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.ai.core.repository;
+
+public interface MessageRepository {
+ default void saveUserMessage(String message, Long threadId) {}
+
+ default void saveAiMessage(String message, Long threadId) {}
+
+ default void saveSystemMessage(String message, Long threadId) {}
+}
diff --git a/bigtop-manager-ai/bigtop-manager-ai-dashscope/pom.xml b/bigtop-manager-ai/bigtop-manager-ai-dashscope/pom.xml
new file mode 100644
index 00000000..0a7259a1
--- /dev/null
+++ b/bigtop-manager-ai/bigtop-manager-ai-dashscope/pom.xml
@@ -0,0 +1,51 @@
+
+
+
+ 4.0.0
+
+ org.apache.bigtop
+ bigtop-manager-ai
+ ${revision}
+
+
+ bigtop-manager-ai-dashscope
+ ${project.artifactId}
+ Bigtop Manager AI DashScope
+
+
+
+ org.apache.bigtop
+ bigtop-manager-ai-core
+ ${revision}
+
+
+
+ com.alibaba
+ dashscope-sdk-java
+ 2.16.3
+
+
+ org.slf4j
+ slf4j-simple
+
+
+
+
+
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
new file mode 100644
index 00000000..538a6747
--- /dev/null
+++ b/bigtop-manager-ai/bigtop-manager-ai-dashscope/src/main/java/org/apache/bigtop/manager/ai/dashscope/DashScopeAssistant.java
@@ -0,0 +1,325 @@
+/*
+ * 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.ai.dashscope;
+
+import org.apache.bigtop.manager.ai.core.AbstractAIAssistant;
+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.provider.AIAssistantConfigProvider;
+import org.apache.bigtop.manager.ai.core.repository.MessageRepository;
+
+import com.alibaba.dashscope.aigc.generation.Generation;
+import com.alibaba.dashscope.aigc.generation.GenerationParam;
+import com.alibaba.dashscope.assistants.Assistant;
+import com.alibaba.dashscope.assistants.AssistantParam;
+import com.alibaba.dashscope.assistants.Assistants;
+import com.alibaba.dashscope.common.GeneralListParam;
+import com.alibaba.dashscope.common.ListResult;
+import com.alibaba.dashscope.common.Message;
+import com.alibaba.dashscope.common.Role;
+import com.alibaba.dashscope.exception.InputRequiredException;
+import com.alibaba.dashscope.exception.InvalidateParameter;
+import com.alibaba.dashscope.exception.NoApiKeyException;
+import com.alibaba.dashscope.threads.AssistantStreamEvents;
+import com.alibaba.dashscope.threads.AssistantThread;
+import com.alibaba.dashscope.threads.ContentBase;
+import com.alibaba.dashscope.threads.ContentText;
+import com.alibaba.dashscope.threads.ThreadParam;
+import com.alibaba.dashscope.threads.Threads;
+import com.alibaba.dashscope.threads.messages.Messages;
+import com.alibaba.dashscope.threads.messages.TextMessageParam;
+import com.alibaba.dashscope.threads.messages.ThreadMessage;
+import com.alibaba.dashscope.threads.messages.ThreadMessageDelta;
+import com.alibaba.dashscope.threads.runs.AssistantStreamMessage;
+import com.alibaba.dashscope.threads.runs.Run;
+import com.alibaba.dashscope.threads.runs.RunParam;
+import com.alibaba.dashscope.threads.runs.Runs;
+import dev.langchain4j.internal.ValidationUtils;
+import io.reactivex.Flowable;
+import reactor.core.publisher.Flux;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class DashScopeAssistant extends AbstractAIAssistant {
+ private final Assistants assistants = new Assistants();
+ private final Messages messages = new Messages();
+ private final Threads threads = new Threads();
+ private final Runs runs = new Runs();
+ private final MessageRepository messageRepository;
+ private final DashScopeThreadParam dashScopeThreadParam;
+
+ public DashScopeAssistant(MessageRepository messageRepository, DashScopeThreadParam dashScopeThreadParam) {
+ this.messageRepository = messageRepository;
+ this.dashScopeThreadParam = dashScopeThreadParam;
+ }
+
+ private String getValueFromAssistantStreamMessage(AssistantStreamMessage assistantStreamMessage) {
+ ThreadMessageDelta threadMessageDelta = (ThreadMessageDelta) assistantStreamMessage.getData();
+ StringBuilder streamMessage = new StringBuilder();
+
+ List contents = threadMessageDelta.getDelta().getContent();
+ for (ContentBase content : contents) {
+ ContentText contentText = (ContentText) content;
+ streamMessage.append(contentText.getText().getValue());
+ }
+ return streamMessage.toString();
+ }
+
+ @Override
+ public PlatformType getPlatform() {
+ return PlatformType.DASH_SCOPE;
+ }
+
+ @Override
+ public void setSystemPrompt(String systemPrompt) {
+ if (dashScopeThreadParam.getAssistantId() == null) {
+ return;
+ }
+ TextMessageParam textMessageParam = TextMessageParam.builder()
+ .apiKey(dashScopeThreadParam.getApiKey())
+ .role(Role.ASSISTANT.getValue())
+ .content(systemPrompt)
+ .build();
+ try {
+ messages.create(dashScopeThreadParam.getAssistantThreadId(), textMessageParam);
+ } catch (NoApiKeyException | InputRequiredException e) {
+ throw new RuntimeException(e);
+ }
+ RunParam runParam = RunParam.builder()
+ .apiKey(dashScopeThreadParam.getApiKey())
+ .assistantId(dashScopeThreadParam.getAssistantId())
+ .build();
+ try {
+ runs.create(dashScopeThreadParam.getAssistantThreadId(), runParam);
+ } catch (NoApiKeyException | InputRequiredException | InvalidateParameter e) {
+ throw new RuntimeException(e);
+ }
+ messageRepository.saveSystemMessage(systemPrompt, (Long) dashScopeThreadParam.getThreadId());
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ @Override
+ public Object getId() {
+ return dashScopeThreadParam.getThreadId();
+ }
+
+ @Override
+ public Flux streamAsk(String userMessage) {
+ messageRepository.saveUserMessage(userMessage, (Long) dashScopeThreadParam.getThreadId());
+ TextMessageParam textMessageParam = TextMessageParam.builder()
+ .apiKey(dashScopeThreadParam.getApiKey())
+ .role(Role.USER.getValue())
+ .content(userMessage)
+ .build();
+ try {
+ ThreadMessage message = messages.create(dashScopeThreadParam.getAssistantThreadId(), textMessageParam);
+ } catch (NoApiKeyException | InputRequiredException e) {
+ throw new RuntimeException(e);
+ }
+
+ RunParam runParam = RunParam.builder()
+ .apiKey(dashScopeThreadParam.getApiKey())
+ .assistantId(dashScopeThreadParam.getAssistantId())
+ .stream(true)
+ .build();
+ Flowable runFlowable = null;
+ try {
+ runFlowable = runs.createStream(dashScopeThreadParam.getAssistantThreadId(), runParam);
+ } catch (NoApiKeyException | InputRequiredException | InvalidateParameter e) {
+ throw new RuntimeException(e);
+ }
+ StringBuilder finalMessage = new StringBuilder();
+ return Flux.from(runFlowable)
+ .map(assistantStreamMessage -> {
+ String message =
+ assistantStreamMessage.getEvent().equals(AssistantStreamEvents.THREAD_MESSAGE_DELTA)
+ ? getValueFromAssistantStreamMessage(assistantStreamMessage)
+ : "";
+ finalMessage.append(message);
+ return message;
+ })
+ .doOnComplete(() -> {
+ messageRepository.saveAiMessage(finalMessage.toString(), (Long) dashScopeThreadParam.getThreadId());
+ });
+ }
+
+ @Override
+ public String ask(String userMessage) {
+ messageRepository.saveUserMessage(userMessage, (Long) dashScopeThreadParam.getThreadId());
+ TextMessageParam textMessageParam = TextMessageParam.builder()
+ .apiKey(dashScopeThreadParam.getApiKey())
+ .role(Role.USER.getValue())
+ .content(userMessage)
+ .build();
+ try {
+ ThreadMessage message = messages.create(dashScopeThreadParam.getAssistantThreadId(), textMessageParam);
+ } catch (NoApiKeyException | InputRequiredException e) {
+ throw new RuntimeException(e);
+ }
+
+ RunParam runParam = RunParam.builder()
+ .apiKey(dashScopeThreadParam.getApiKey())
+ .assistantId(dashScopeThreadParam.getAssistantId())
+ .build();
+ Run run;
+ try {
+ run = runs.create(dashScopeThreadParam.getAssistantThreadId(), runParam);
+ } catch (NoApiKeyException | InputRequiredException | InvalidateParameter e) {
+ throw new RuntimeException(e);
+ }
+ while (true) {
+ if (run.getStatus().equals(Run.Status.CANCELLED)
+ || run.getStatus().equals(Run.Status.COMPLETED)
+ || run.getStatus().equals(Run.Status.FAILED)
+ || run.getStatus().equals(Run.Status.REQUIRES_ACTION)
+ || run.getStatus().equals(Run.Status.EXPIRED)) {
+ break;
+ } else {
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ try {
+ run = runs.retrieve(
+ dashScopeThreadParam.getAssistantThreadId(), run.getId(), dashScopeThreadParam.getApiKey());
+ } catch (NoApiKeyException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ ListResult threadMessages = null;
+ try {
+ threadMessages = messages.list(
+ dashScopeThreadParam.getAssistantThreadId(),
+ GeneralListParam.builder()
+ .apiKey(dashScopeThreadParam.getApiKey())
+ .build());
+ } catch (NoApiKeyException | InputRequiredException e) {
+ throw new RuntimeException(e);
+ }
+ List threadMessage = threadMessages.getData();
+ if (threadMessage.isEmpty()) {
+ return null;
+ }
+ List contents = threadMessage.get(0).getContent();
+ StringBuilder finalMessage = new StringBuilder();
+ for (ContentBase content : contents) {
+ ContentText contentText = (ContentText) content;
+ finalMessage.append(contentText.getText().getValue());
+ }
+ messageRepository.saveAiMessage(finalMessage.toString(), (Long) dashScopeThreadParam.getThreadId());
+ return finalMessage.toString();
+ }
+
+ @Override
+ public boolean test() {
+ Generation generation = new Generation();
+ GenerationParam param = GenerationParam.builder()
+ .apiKey(dashScopeThreadParam.getApiKey())
+ .model(dashScopeThreadParam.getModel())
+ .build();
+
+ Message userMsg =
+ Message.builder().role(Role.USER.getValue()).content("1+1=").build();
+ param.setMessages(Collections.singletonList(userMsg));
+ try {
+ generation.call(param);
+ } catch (NoApiKeyException | InputRequiredException e) {
+ throw new RuntimeException(e);
+ }
+ return true;
+ }
+
+ @Override
+ public Map createThread() {
+ AssistantParam param = AssistantParam.builder()
+ .model(dashScopeThreadParam.getModel())
+ .apiKey(dashScopeThreadParam.getApiKey())
+ .name("DashScope Assistant")
+ .build();
+ Map threadInfo = new HashMap<>();
+ try {
+ Assistant assistant = assistants.create(param);
+ threadInfo.put("assistantId", assistant.getId());
+ } catch (NoApiKeyException e) {
+ throw new RuntimeException(e);
+ }
+ ThreadParam threadParam =
+ ThreadParam.builder().apiKey(dashScopeThreadParam.getApiKey()).build();
+ try {
+ AssistantThread assistantThread = threads.create(threadParam);
+ threadInfo.put("assistantThreadId", assistantThread.getId());
+ } catch (NoApiKeyException e) {
+ throw new RuntimeException(e);
+ }
+ return threadInfo;
+ }
+
+ public static class Builder {
+ private Object id;
+ private AIAssistantConfigProvider configProvider;
+ private MessageRepository messageRepository;
+
+ public Builder() {}
+
+ public Builder withConfigProvider(AIAssistantConfigProvider configProvider) {
+ this.configProvider = configProvider;
+ return this;
+ }
+
+ public Builder id(Object id) {
+ this.id = id;
+ return this;
+ }
+
+ public Builder messageRepository(MessageRepository messageRepository) {
+ this.messageRepository = messageRepository;
+ return this;
+ }
+
+ public AIAssistant build() {
+ String model = ValidationUtils.ensureNotNull(configProvider.getModel(), "model");
+ String apiKey = ValidationUtils.ensureNotNull(
+ configProvider.getCredentials().get("apiKey"), "apiKey");
+ DashScopeThreadParam param = new DashScopeThreadParam();
+ param.setApiKey(apiKey);
+ param.setModel(model);
+ String assistantThreadId = configProvider.getConfigs().get("assistantThreadId");
+ if (assistantThreadId != null) {
+ param.setAssistantThreadId(assistantThreadId);
+ }
+ String assistantId = configProvider.getConfigs().get("assistantId");
+ if (assistantId != null) {
+ param.setAssistantId(assistantId);
+ }
+ if (id != null) {
+ param.setThreadId(id);
+ }
+ return new DashScopeAssistant(messageRepository, param);
+ }
+ }
+}
diff --git a/bigtop-manager-ai/bigtop-manager-ai-dashscope/src/main/java/org/apache/bigtop/manager/ai/dashscope/DashScopeThreadParam.java b/bigtop-manager-ai/bigtop-manager-ai-dashscope/src/main/java/org/apache/bigtop/manager/ai/dashscope/DashScopeThreadParam.java
new file mode 100644
index 00000000..06e6f088
--- /dev/null
+++ b/bigtop-manager-ai/bigtop-manager-ai-dashscope/src/main/java/org/apache/bigtop/manager/ai/dashscope/DashScopeThreadParam.java
@@ -0,0 +1,36 @@
+/*
+ * 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.ai.dashscope;
+
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class DashScopeThreadParam {
+ private Object threadId;
+
+ private String assistantId;
+
+ private String assistantThreadId;
+
+ private String model;
+
+ private String apiKey;
+}
diff --git a/bigtop-manager-ai/bigtop-manager-ai-dashscope/src/main/java/org/apache/bigtop/manager/ai/dashscope/DashScopeToolBox.java b/bigtop-manager-ai/bigtop-manager-ai-dashscope/src/main/java/org/apache/bigtop/manager/ai/dashscope/DashScopeToolBox.java
new file mode 100644
index 00000000..6a5ac84e
--- /dev/null
+++ b/bigtop-manager-ai/bigtop-manager-ai-dashscope/src/main/java/org/apache/bigtop/manager/ai/dashscope/DashScopeToolBox.java
@@ -0,0 +1,42 @@
+/*
+ * 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.ai.dashscope;
+
+import org.apache.bigtop.manager.ai.core.factory.ToolBox;
+
+import reactor.core.publisher.Flux;
+
+import java.util.List;
+
+public class DashScopeToolBox implements ToolBox {
+ @Override
+ public List getTools() {
+ return null;
+ }
+
+ @Override
+ public String invoke(String toolName) {
+ return null;
+ }
+
+ @Override
+ public Flux streamInvoke(String toolName) {
+ return null;
+ }
+}
diff --git a/bigtop-manager-ai/bigtop-manager-ai-openai/src/main/java/org/apache/bigtop/manager/ai/openai/OpenAIAssistant.java b/bigtop-manager-ai/bigtop-manager-ai-openai/src/main/java/org/apache/bigtop/manager/ai/openai/OpenAIAssistant.java
index f5325802..59eba580 100644
--- a/bigtop-manager-ai/bigtop-manager-ai-openai/src/main/java/org/apache/bigtop/manager/ai/openai/OpenAIAssistant.java
+++ b/bigtop-manager-ai/bigtop-manager-ai-openai/src/main/java/org/apache/bigtop/manager/ai/openai/OpenAIAssistant.java
@@ -20,27 +20,104 @@
import org.apache.bigtop.manager.ai.core.AbstractAIAssistant;
import org.apache.bigtop.manager.ai.core.enums.PlatformType;
+import org.apache.bigtop.manager.ai.core.exception.AssistantConfigNotSetException;
import org.apache.bigtop.manager.ai.core.factory.AIAssistant;
import org.apache.bigtop.manager.ai.core.provider.AIAssistantConfigProvider;
+import dev.langchain4j.data.message.AiMessage;
+import dev.langchain4j.data.message.SystemMessage;
+import dev.langchain4j.data.message.UserMessage;
import dev.langchain4j.internal.ValidationUtils;
import dev.langchain4j.memory.ChatMemory;
import dev.langchain4j.memory.chat.MessageWindowChatMemory;
+import dev.langchain4j.model.StreamingResponseHandler;
import dev.langchain4j.model.chat.ChatLanguageModel;
import dev.langchain4j.model.chat.StreamingChatLanguageModel;
import dev.langchain4j.model.openai.OpenAiChatModel;
import dev.langchain4j.model.openai.OpenAiStreamingChatModel;
+import dev.langchain4j.model.output.Response;
import dev.langchain4j.store.memory.chat.ChatMemoryStore;
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.FluxSink;
public class OpenAIAssistant extends AbstractAIAssistant {
+ private final ChatLanguageModel chatLanguageModel;
+ private final StreamingChatLanguageModel streamingChatLanguageModel;
+ private final ChatMemory chatMemory;
+
private static final String BASE_URL = "https://api.openai.com/v1";
- private OpenAIAssistant(
+ public OpenAIAssistant(
ChatLanguageModel chatLanguageModel,
StreamingChatLanguageModel streamingChatLanguageModel,
ChatMemory chatMemory) {
- super(chatLanguageModel, streamingChatLanguageModel, chatMemory);
+ this.chatLanguageModel = chatLanguageModel;
+ this.streamingChatLanguageModel = streamingChatLanguageModel;
+ this.chatMemory = chatMemory;
+ }
+
+ @Override
+ public Flux streamAsk(String chatMessage) {
+ if (chatMemory == null || streamingChatLanguageModel == null) {
+ throw new AssistantConfigNotSetException("threadId");
+ }
+ chatMemory.add(UserMessage.from(chatMessage));
+ return Flux.create(
+ emitter -> streamingChatLanguageModel.generate(chatMemory.messages(), new StreamingResponseHandler<>() {
+ @Override
+ public void onNext(String token) {
+ emitter.next(token);
+ }
+
+ @Override
+ public void onError(Throwable error) {
+ emitter.error(error);
+ }
+
+ @Override
+ public void onComplete(Response response) {
+ StreamingResponseHandler.super.onComplete(response);
+ chatMemory.add(response.content());
+ }
+ }),
+ FluxSink.OverflowStrategy.BUFFER);
+ }
+
+ @Override
+ public String ask(String chatMessage) {
+ if (chatMemory == null || chatLanguageModel == null) {
+ throw new AssistantConfigNotSetException("threadId");
+ }
+ chatMemory.add(UserMessage.from(chatMessage));
+ Response generate = chatLanguageModel.generate(chatMemory.messages());
+ String aiMessage = generate.content().text();
+ chatMemory.add(AiMessage.from(aiMessage));
+ return aiMessage;
+ }
+
+ @Override
+ public void setSystemPrompt(String systemPrompt) {
+ if (chatMemory == null) {
+ throw new AssistantConfigNotSetException("threadId");
+ }
+ chatMemory.add(SystemMessage.systemMessage(systemPrompt));
+ }
+
+ public void setSystemPrompt(SystemMessage systemPrompt) {
+ if (chatMemory == null) {
+ throw new AssistantConfigNotSetException("threadId");
+ }
+ chatMemory.add(systemPrompt);
+ }
+
+ @Override
+ public Object getId() {
+ return chatMemory.id();
+ }
+
+ public void resetMemory() {
+ chatMemory.clear();
}
@Override
@@ -76,7 +153,6 @@ public Builder memoryStore(ChatMemoryStore chatMemoryStore) {
}
public AIAssistant build() {
- ValidationUtils.ensureNotNull(id, "id");
String model = ValidationUtils.ensureNotNull(configProvider.getModel(), "model");
String apiKey = ValidationUtils.ensureNotNull(
configProvider.getCredentials().get("apiKey"), "apiKey");
@@ -90,11 +166,13 @@ public AIAssistant build() {
.baseUrl(BASE_URL)
.modelName(model)
.build();
- MessageWindowChatMemory chatMemory = MessageWindowChatMemory.builder()
- .id(id)
+ MessageWindowChatMemory.Builder builder = MessageWindowChatMemory.builder()
.chatMemoryStore(chatMemoryStore)
- .maxMessages(MEMORY_LEN)
- .build();
+ .maxMessages(MEMORY_LEN);
+ if (id != null) {
+ builder.id(id);
+ }
+ MessageWindowChatMemory chatMemory = builder.build();
return new OpenAIAssistant(openAiChatModel, openaiStreamChatModel, chatMemory);
}
}
diff --git a/bigtop-manager-ai/pom.xml b/bigtop-manager-ai/pom.xml
index 58a96981..c731441f 100644
--- a/bigtop-manager-ai/pom.xml
+++ b/bigtop-manager-ai/pom.xml
@@ -32,6 +32,7 @@
Bigtop Manager AI
bigtop-manager-ai-openai
+ bigtop-manager-ai-dashscope
bigtop-manager-ai-core
bigtop-manager-ai-assistant
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 e4c8628e..f17cfb33 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
@@ -25,6 +25,7 @@
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import java.io.Serializable;
+import java.util.Map;
@Data
@EqualsAndHashCode(callSuper = true)
@@ -37,6 +38,9 @@ public class ChatThreadPO extends BasePO implements Serializable {
@Column(name = "model", nullable = false, length = 255)
private String model;
+ @Column(name = "thread_info", columnDefinition = "json", nullable = false)
+ private Map threadInfo;
+
@Column(name = "user_id")
private Long userId;
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 a691b7b3..895cba8f 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
@@ -29,6 +29,10 @@ public interface ChatThreadDao extends BaseDao {
ChatThreadPO findById(Long id);
+ ChatThreadPO findByThreadId(@Param("id") Long id);
+
List findAllByPlatformAuthorizedIdAndUserId(
@Param("platformId") Long platformAuthorizedId, @Param("userId") Long userId);
+
+ void saveWithThreadInfo(ChatThreadPO chatThreadPO);
}
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 be702079..5ecd9a2a 100644
--- a/bigtop-manager-dao/src/main/resources/mapper/mysql/ChatThreadMapper.xml
+++ b/bigtop-manager-dao/src/main/resources/mapper/mysql/ChatThreadMapper.xml
@@ -24,6 +24,11 @@
id, user_id, platform_id, model
+
+
+
+
+
+
+
+
+ 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)
+
+
\ No newline at end of file
diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/service/impl/AIChatServiceImpl.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/service/impl/AIChatServiceImpl.java
index 16ef8e54..025b4d48 100644
--- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/service/impl/AIChatServiceImpl.java
+++ b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/service/impl/AIChatServiceImpl.java
@@ -20,7 +20,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.assistant.provider.PersistentStoreProvider;
import org.apache.bigtop.manager.ai.core.enums.MessageSender;
import org.apache.bigtop.manager.ai.core.enums.PlatformType;
import org.apache.bigtop.manager.ai.core.factory.AIAssistant;
@@ -54,6 +54,7 @@
import org.springframework.stereotype.Service;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
+import lombok.extern.slf4j.Slf4j;
import reactor.core.publisher.Flux;
import jakarta.annotation.Resource;
@@ -64,6 +65,7 @@
import java.util.Objects;
@Service
+@Slf4j
public class AIChatServiceImpl implements AIChatService {
@Resource
private PlatformDao platformDao;
@@ -79,21 +81,21 @@ public class AIChatServiceImpl implements AIChatService {
private AIAssistantFactory aiAssistantFactory;
- private final AIAssistantFactory aiTestFactory = new GeneralAssistantFactory();
-
public AIAssistantFactory getAiAssistantFactory() {
if (aiAssistantFactory == null) {
aiAssistantFactory =
- new GeneralAssistantFactory(new PersistentChatMemoryStore(chatThreadDao, chatMessageDao));
+ new GeneralAssistantFactory(new PersistentStoreProvider(chatThreadDao, chatMessageDao));
}
return aiAssistantFactory;
}
- private AIAssistantConfig getAIAssistantConfig(PlatformAuthorizedDTO platformAuthorizedDTO) {
+ private AIAssistantConfig getAIAssistantConfig(
+ PlatformAuthorizedDTO platformAuthorizedDTO, Map configs) {
return AIAssistantConfig.builder()
.setModel(platformAuthorizedDTO.getModel())
.setLanguage(LocaleContextHolder.getLocale().toString())
.addCredentials(platformAuthorizedDTO.getCredentials())
+ .addConfigs(configs)
.build();
}
@@ -101,24 +103,26 @@ private PlatformType getPlatformType(String platformName) {
return PlatformType.getPlatformType(platformName.toLowerCase());
}
- private AIAssistant buildAIAssistant(PlatformAuthorizedDTO platformAuthorizedDTO, Long threadId) {
+ private AIAssistant buildAIAssistant(
+ PlatformAuthorizedDTO platformAuthorizedDTO, Long threadId, Map configs) {
return getAiAssistantFactory()
.create(
getPlatformType(platformAuthorizedDTO.getPlatformName()),
- getAIAssistantConfig(platformAuthorizedDTO),
+ getAIAssistantConfig(platformAuthorizedDTO, configs),
threadId);
}
private Boolean testAuthorization(PlatformAuthorizedDTO platformAuthorizedDTO) {
- AIAssistant aiAssistant = aiTestFactory.create(
- getPlatformType(platformAuthorizedDTO.getPlatformName()), getAIAssistantConfig(platformAuthorizedDTO));
+ AIAssistant aiAssistant = getAiAssistantFactory()
+ .create(
+ getPlatformType(platformAuthorizedDTO.getPlatformName()),
+ getAIAssistantConfig(platformAuthorizedDTO, null),
+ false);
try {
- aiAssistant.ask("1+1=");
+ return aiAssistant.test();
} catch (Exception e) {
throw new ApiException(ApiExceptionEnum.CREDIT_INCORRECT, e.getMessage());
}
-
- return true;
}
@Override
@@ -233,7 +237,13 @@ public ChatThreadVO createChatThreads(Long platformId, String model) {
chatThreadPO.setUserId(userId);
chatThreadPO.setModel(model);
chatThreadPO.setPlatformId(platformAuthorizedPO.getId());
- chatThreadDao.save(chatThreadPO);
+
+ PlatformAuthorizedDTO platformAuthorizedDTO = new PlatformAuthorizedDTO(
+ platformPO.getName(), platformAuthorizedPO.getCredentials(), chatThreadPO.getModel());
+ AIAssistant aiAssistant = buildAIAssistant(platformAuthorizedDTO, null, null);
+ Map threadInfo = aiAssistant.createThread();
+ chatThreadPO.setThreadInfo(threadInfo);
+ chatThreadDao.saveWithThreadInfo(chatThreadPO);
return ChatThreadConverter.INSTANCE.fromPO2VO(chatThreadPO);
}
@@ -267,9 +277,9 @@ public List getAllChatThreads(Long platformId, String model) {
@Override
public SseEmitter talk(Long platformId, Long threadId, String message) {
- ChatThreadPO chatThreadPO = chatThreadDao.findById(threadId);
+ ChatThreadPO chatThreadPO = chatThreadDao.findByThreadId(threadId);
Long userId = SessionUserHolder.getUserId();
- if (chatThreadPO == null || !Objects.equals(userId, chatThreadPO.getUserId())) {
+ if (!Objects.equals(userId, chatThreadPO.getUserId())) {
throw new ApiException(ApiExceptionEnum.CHAT_THREAD_NOT_FOUND);
}
PlatformAuthorizedPO platformAuthorizedPO = platformAuthorizedDao.findByPlatformId(platformId);
@@ -280,7 +290,8 @@ public SseEmitter talk(Long platformId, Long threadId, String message) {
PlatformPO platformPO = platformDao.findById(platformAuthorizedPO.getPlatformId());
PlatformAuthorizedDTO platformAuthorizedDTO = new PlatformAuthorizedDTO(
platformPO.getName(), platformAuthorizedPO.getCredentials(), chatThreadPO.getModel());
- AIAssistant aiAssistant = buildAIAssistant(platformAuthorizedDTO, chatThreadPO.getId());
+ AIAssistant aiAssistant =
+ buildAIAssistant(platformAuthorizedDTO, chatThreadPO.getId(), chatThreadPO.getThreadInfo());
Flux stringFlux = aiAssistant.streamAsk(message);
SseEmitter emitter = new SseEmitter();
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 3988894f..fb6c27f7 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
@@ -342,6 +342,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,
+ `thread_info` JSON DEFAULT NULL,
`create_time` DATETIME DEFAULT CURRENT_TIMESTAMP,
`update_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`create_by` BIGINT DEFAULT NULL,
@@ -374,4 +375,5 @@ VALUES (1, now(), now(), 'Administrator', '21232f297a57a5a743894a0e4a801fc3', tr
-- Adding default ai chat platform
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');
\ No newline at end of file
+(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');
diff --git a/pom.xml b/pom.xml
index 66f14b04..bcf37b4f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -136,6 +136,12 @@
${project.version}
+
+ org.apache.bigtop
+ bigtop-manager-ai-dashscope
+ ${project.version}
+
+
org.apache.bigtop
bigtop-manager-ai-assistant