Merge branch 'feature_20250930_work_flow' of https://github.com/MuSan-Li/ruoyi-ai into main

# Conflicts:
#	pom.xml
#	ruoyi-admin/pom.xml
#	ruoyi-modules/pom.xml
#	ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/DeepSeekChatImpl.java
This commit is contained in:
lihao05
2025-10-21 10:17:50 +08:00
116 changed files with 6839 additions and 25 deletions

View File

@@ -1,8 +1,16 @@
package org.ruoyi.chat.service.chat;
import dev.langchain4j.data.message.AiMessage;
import dev.langchain4j.data.message.ChatMessage;
import dev.langchain4j.data.message.SystemMessage;
import dev.langchain4j.data.message.UserMessage;
import dev.langchain4j.model.chat.response.StreamingChatResponseHandler;
import org.ruoyi.common.chat.request.ChatRequest;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import java.util.ArrayList;
import java.util.List;
/**
* 对话Service接口
*
@@ -13,9 +21,36 @@ public interface IChatService {
/**
* 客户端发送消息到服务端
*
* @param chatRequest 请求对象
*/
SseEmitter chat(ChatRequest chatRequest,SseEmitter emitter);
SseEmitter chat(ChatRequest chatRequest, SseEmitter emitter);
/**
* 工作流场景:支持 langchain4j 的 StreamingChatResponseHandler
*
* @param chatRequest ruoyi-ai 的请求对象
* @param handler langchain4j 的流式响应处理器
*/
default void chat(ChatRequest chatRequest, StreamingChatResponseHandler handler) {
throw new UnsupportedOperationException("此服务暂不支持工作流场景");
}
default dev.langchain4j.model.chat.request.ChatRequest convertToLangchainRequest(ChatRequest request) {
List<ChatMessage> messages = new ArrayList<>();
for (org.ruoyi.common.chat.entity.chat.Message msg : request.getMessages()) {
// 简单转换,您可以根据实际需求调整
if ("user".equals(msg.getRole())) {
messages.add(UserMessage.from(msg.getContent().toString()));
} else if ("system".equals(msg.getRole())) {
messages.add(SystemMessage.from(msg.getContent().toString()));
} else if ("assistant".equals(msg.getRole())) {
messages.add(AiMessage.from(msg.getContent().toString()));
}
}
return dev.langchain4j.model.chat.request.ChatRequest.builder().messages(messages).build();
}
/**
* 获取此服务支持的模型类别
*/

View File

@@ -1,6 +1,10 @@
package org.ruoyi.chat.service.chat.impl;
import dev.langchain4j.data.message.ChatMessage;
import dev.langchain4j.data.message.SystemMessage;
import dev.langchain4j.data.message.UserMessage;
import dev.langchain4j.data.message.AiMessage;
import dev.langchain4j.data.message.ChatMessage;
import dev.langchain4j.data.message.SystemMessage;
import dev.langchain4j.data.message.UserMessage;
@@ -34,6 +38,9 @@ import java.io.BufferedReader;
import java.io.InputStreamReader;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.ArrayList;
import java.util.List;
/**
* deepseek
*/
@@ -74,7 +81,7 @@ public class DeepSeekChatImpl implements IChatService {
try {
// 构建消息列表,包含历史对话消息和当前用户消息
List<ChatMessage> messages = new ArrayList<>();
// 添加历史对话消息
if (chatRequest.getMessages() != null) {
for (Message message : chatRequest.getMessages()) {
@@ -82,7 +89,7 @@ public class DeepSeekChatImpl implements IChatService {
if (message.getContent() == null || String.valueOf(message.getContent()).trim().isEmpty()) {
continue; // 跳过空消息
}
if (Message.Role.SYSTEM.getName().equals(message.getRole())) {
messages.add(new SystemMessage(String.valueOf(message.getContent())));
} else if (Message.Role.USER.getName().equals(message.getRole())) {
@@ -92,7 +99,7 @@ public class DeepSeekChatImpl implements IChatService {
}
}
}
// 添加当前用户消息
messages.add(new UserMessage(chatRequest.getPrompt()));
@@ -127,6 +134,34 @@ public class DeepSeekChatImpl implements IChatService {
return emitter;
}
/**
* 工作流场景:支持 langchain4j handler
*/
@Override
public void chat(ChatRequest request, StreamingChatResponseHandler handler) {
log.info("workflow chat, model: {}", request.getModel());
ChatModelVo chatModelVo = chatModelService.selectModelByName(request.getModel());
StreamingChatModel chatModel = OpenAiStreamingChatModel.builder()
.baseUrl(chatModelVo.getApiHost())
.apiKey(chatModelVo.getApiKey())
.modelName(chatModelVo.getModelName())
.logRequests(true)
.logResponses(true)
.temperature(0.7)
.build();
try {
// 将 ruoyi-ai 的 ChatRequest 转换为 langchain4j 的格式
dev.langchain4j.model.chat.request.ChatRequest chatRequest = convertToLangchainRequest(request);
chatModel.chat(chatRequest, handler);
} catch (Exception e) {
log.error("workflow deepseek请求失败{}", e.getMessage(), e);
throw new RuntimeException("DeepSeek workflow chat failed: " + e.getMessage(), e);
}
}
/**
* 处理启用深度思考的deepseek模型请求
*/
@@ -157,13 +192,13 @@ public class DeepSeekChatImpl implements IChatService {
if (message.getContent() == null || String.valueOf(message.getContent()).trim().isEmpty()) {
continue; // 跳过空消息
}
// DeepSeek模型在深度思考模式下只接受user和assistant角色的消息
if (Message.Role.SYSTEM.getName().equals(message.getRole())) {
// 跳过系统消息
continue;
}
Map<String, Object> historyMessage = new HashMap<>();
historyMessage.put("role", message.getRole());
historyMessage.put("content", String.valueOf(message.getContent()));

View File

@@ -8,13 +8,13 @@ import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.ruoyi.chat.enums.ChatModeType;
import org.ruoyi.chat.service.chat.IChatService;
import org.ruoyi.chat.support.ChatServiceHelper;
import org.ruoyi.common.chat.request.ChatRequest;
import org.ruoyi.domain.vo.ChatModelVo;
import org.ruoyi.service.IChatModelService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import org.ruoyi.chat.support.ChatServiceHelper;
/**
@@ -22,7 +22,7 @@ import org.ruoyi.chat.support.ChatServiceHelper;
*/
@Service
@Slf4j
public class QianWenAiChatServiceImpl implements IChatService {
public class QianWenAiChatServiceImpl implements IChatService {
@Autowired
private IChatModelService chatModelService;
@@ -37,7 +37,6 @@ public class QianWenAiChatServiceImpl implements IChatService {
.build();
// 发送流式消息
try {
model.chat(chatRequest.getPrompt(), new StreamingChatResponseHandler() {
@@ -70,11 +69,34 @@ public class QianWenAiChatServiceImpl implements IChatService {
}
/**
* 工作流场景:支持 langchain4j handler
*/
@Override
public void chat(ChatRequest request, StreamingChatResponseHandler handler) {
log.info("workflow chat, model: {}", request.getModel());
ChatModelVo chatModelVo = chatModelService.selectModelByName(request.getModel());
StreamingChatModel model = QwenStreamingChatModel.builder()
.apiKey(chatModelVo.getApiKey())
.modelName(chatModelVo.getModelName())
.build();
try {
// 将 ruoyi-ai 的 ChatRequest 转换为 langchain4j 的格式
dev.langchain4j.model.chat.request.ChatRequest chatRequest = convertToLangchainRequest(request);
model.chat(chatRequest, handler);
} catch (Exception e) {
log.error("workflow 千问请求失败:{}", e.getMessage(), e);
throw new RuntimeException("QianWen workflow chat failed: " + e.getMessage(), e);
}
}
@Override
public String getCategory() {
return ChatModeType.QIANWEN.getCode();
}
}