mirror of
https://gitcode.com/ageerle/ruoyi-ai.git
synced 2026-04-04 23:37:32 +00:00
人机交互节点逻辑修改
This commit is contained in:
@@ -98,7 +98,7 @@ public class WorkflowComponentService extends ServiceImpl<WorkflowComponentMappe
|
||||
return baseMapper.selectPage(new Page<>(currentPage, pageSize), wrapper);
|
||||
}
|
||||
|
||||
@Cacheable(cacheNames = WORKFLOW_COMPONENTS)
|
||||
// @Cacheable(cacheNames = WORKFLOW_COMPONENTS)
|
||||
public List<WorkflowComponent> getAllEnable() {
|
||||
return ChainWrappers.lambdaQueryChain(baseMapper)
|
||||
.eq(WorkflowComponent::getIsEnable, true)
|
||||
|
||||
@@ -6,6 +6,7 @@ import org.ruoyi.workflow.workflow.node.AbstractWfNode;
|
||||
import org.ruoyi.workflow.workflow.node.EndNode;
|
||||
import org.ruoyi.workflow.workflow.node.answer.LLMAnswerNode;
|
||||
import org.ruoyi.workflow.workflow.node.httpRequest.HttpRequestNode;
|
||||
import org.ruoyi.workflow.workflow.node.humanFeedBack.HumanFeedbackNode;
|
||||
import org.ruoyi.workflow.workflow.node.keywordExtractor.KeywordExtractorNode;
|
||||
import org.ruoyi.workflow.workflow.node.knowledgeRetrieval.KnowledgeRetrievalNode;
|
||||
import org.ruoyi.workflow.workflow.node.mailSend.MailSendNode;
|
||||
@@ -25,6 +26,7 @@ public class WfNodeFactory {
|
||||
case MAIL_SEND -> wfNode = new MailSendNode(wfComponent, nodeDefinition, wfState, nodeState);
|
||||
case HTTP_REQUEST -> wfNode = new HttpRequestNode(wfComponent, nodeDefinition, wfState, nodeState);
|
||||
case SWITCHER -> wfNode = new SwitcherNode(wfComponent, nodeDefinition, wfState, nodeState);
|
||||
case HUMAN_FEEDBACK -> wfNode = new HumanFeedbackNode(wfComponent, nodeDefinition, wfState, nodeState);
|
||||
default -> {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,6 +35,12 @@ public class WorkflowUtil {
|
||||
@Resource
|
||||
private ChatServiceFactory chatServiceFactory;
|
||||
|
||||
// 添加默认名称的成员变量
|
||||
private static final String DEFAULT_NODE_NAME = "input";
|
||||
|
||||
// 添加文档解析的前缀字段
|
||||
private static final String UPLOAD_FILE_API_PREFIX = "fileid";
|
||||
|
||||
public static String renderTemplate(String template, List<NodeIOData> values) {
|
||||
// 🔒 关键修复:如果 template 为 null,直接返回 null 或空字符串
|
||||
if (template == null) {
|
||||
@@ -125,9 +131,9 @@ public class WorkflowUtil {
|
||||
// 构建 ruoyi-ai 的 ChatRequest
|
||||
List<Message> messages = new ArrayList<>();
|
||||
|
||||
addUserMessage(node, state.getInputs(), messages);
|
||||
|
||||
addSystemMessage(systemMessage, messages);
|
||||
List<NodeIOData> inputs = state.getInputs();
|
||||
addUserMessage(node, inputs, messages);
|
||||
addSystemMessage(systemMessage, inputs, messages);
|
||||
|
||||
ChatRequest chatRequest = new ChatRequest();
|
||||
chatRequest.setModel(modelName);
|
||||
@@ -150,20 +156,44 @@ public class WorkflowUtil {
|
||||
}
|
||||
|
||||
WfNodeInputConfig nodeInputConfig = NodeInputConfigTypeHandler.fillNodeInputConfig(node.getInputConfig());
|
||||
|
||||
List<WfNodeParamRef> refInputs = nodeInputConfig.getRefInputs();
|
||||
|
||||
Set<String> nameSet = CollStreamUtil.toSet(refInputs, WfNodeParamRef::getName);
|
||||
|
||||
userMessage.stream().filter(item -> nameSet.contains(item.getName()))
|
||||
.map(item -> getMessage("user", item.getContent().getValue())).forEach(messages::add);
|
||||
|
||||
if (CollUtil.isNotEmpty(messages)) {
|
||||
return;
|
||||
// 检查是否存在包含fileId的NodeIOData对象
|
||||
boolean hasFileIdData = hasFileIdData(userMessage);
|
||||
// 构建消息列表
|
||||
List<Message> messageList = buildMessageList(userMessage, nameSet, hasFileIdData, DEFAULT_NODE_NAME);
|
||||
// 如果没有找到匹配的消息,尝试使用input字段
|
||||
if (CollUtil.isEmpty(messageList)) {
|
||||
messageList = buildMessageList(userMessage, Set.of("input"), hasFileIdData, DEFAULT_NODE_NAME);
|
||||
}
|
||||
messages.addAll(messageList);
|
||||
}
|
||||
|
||||
userMessage.stream().filter(item -> "input".equals(item.getName()))
|
||||
.map(item -> getMessage("user", item.getContent().getValue())).forEach(messages::add);
|
||||
|
||||
/**
|
||||
* 检查是否包含fileId数据
|
||||
*/
|
||||
private boolean hasFileIdData(List<NodeIOData> userMessage) {
|
||||
return userMessage.stream().anyMatch(item ->
|
||||
item != null &&
|
||||
item.getContent() != null &&
|
||||
item.getContent().getValue() != null &&
|
||||
String.valueOf(item.getContent().getValue()).toLowerCase().contains(UPLOAD_FILE_API_PREFIX)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建消息列表
|
||||
*/
|
||||
private List<Message> buildMessageList(List<NodeIOData> userMessage, Set<String> nameSet, boolean hasFileIdData, String defaultName) {
|
||||
String role = hasFileIdData ? "system" : "user";
|
||||
|
||||
return userMessage.stream()
|
||||
.filter(item -> item != null && item.getName() != null)
|
||||
.filter(item -> nameSet.contains(item.getName()) || defaultName.equals(item.getName()))
|
||||
.map(item -> getMessage(role, item.getContent().getValue()))
|
||||
.toList();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -187,14 +217,22 @@ public class WorkflowUtil {
|
||||
* @param systemMessage
|
||||
* @param messages
|
||||
*/
|
||||
private void addSystemMessage(List<UserMessage> systemMessage, List<Message> messages) {
|
||||
log.info("addSystemMessage received: {}", systemMessage); // 🔥 加这一行
|
||||
private void addSystemMessage(List<UserMessage> systemMessage, List<NodeIOData> userMessage, List<Message> messages) {
|
||||
log.info("addSystemMessage received: {}", systemMessage);
|
||||
|
||||
if (CollUtil.isEmpty(systemMessage)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查是否存在包含fileId的NodeIOData对象
|
||||
boolean hasFileIdData = hasFileIdData(userMessage);
|
||||
|
||||
// 根据是否有fileId数据确定消息角色
|
||||
String role = hasFileIdData ? "user" : "system";
|
||||
|
||||
// 添加消息
|
||||
systemMessage.stream()
|
||||
.map(userMsg -> getMessage("system", userMsg.singleText()))
|
||||
.map(userMsg -> getMessage(role, userMsg.singleText()))
|
||||
.forEach(messages::add);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ import lombok.Data;
|
||||
import lombok.Getter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.SerializationUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.ruoyi.common.core.exception.base.BaseException;
|
||||
import org.ruoyi.workflow.base.NodeInputConfigTypeHandler;
|
||||
import org.ruoyi.workflow.entity.WorkflowComponent;
|
||||
@@ -124,14 +123,6 @@ public abstract class AbstractWfNode {
|
||||
log.info("↓↓↓↓↓ node process start,name:{},uuid:{}", node.getTitle(), node.getUuid());
|
||||
state.setProcessStatus(NODE_PROCESS_STATUS_DOING);
|
||||
initInput();
|
||||
//HumanFeedback的情况
|
||||
Object humanFeedbackState = state.data().get(HUMAN_FEEDBACK_KEY);
|
||||
if (null != humanFeedbackState) {
|
||||
String userInput = humanFeedbackState.toString();
|
||||
if (StringUtils.isNotBlank(userInput)) {
|
||||
state.getInputs().add(NodeIOData.createByText(HUMAN_FEEDBACK_KEY, "default", userInput));
|
||||
}
|
||||
}
|
||||
if (null != inputConsumer) {
|
||||
inputConsumer.accept(state);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
package org.ruoyi.workflow.workflow.node.humanFeedBack;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.ruoyi.workflow.entity.WorkflowComponent;
|
||||
import org.ruoyi.workflow.entity.WorkflowNode;
|
||||
import org.ruoyi.workflow.workflow.NodeProcessResult;
|
||||
import org.ruoyi.workflow.workflow.WfNodeState;
|
||||
import org.ruoyi.workflow.workflow.WfState;
|
||||
import org.ruoyi.workflow.workflow.data.NodeIOData;
|
||||
import org.ruoyi.workflow.workflow.node.AbstractWfNode;
|
||||
|
||||
import static org.ruoyi.workflow.cosntant.AdiConstant.WorkflowConstant.*;
|
||||
|
||||
/**
|
||||
* 人机交互节点实现类
|
||||
*/
|
||||
@Slf4j
|
||||
public class HumanFeedbackNode extends AbstractWfNode {
|
||||
|
||||
public HumanFeedbackNode(WorkflowComponent component, WorkflowNode nodeDefinition, WfState wfState, WfNodeState nodeState) {
|
||||
super(component, nodeDefinition, wfState, nodeState);
|
||||
}
|
||||
|
||||
// 人机交互节点的处理逻辑
|
||||
@Override
|
||||
public NodeProcessResult onProcess() {
|
||||
log.info("Processing HumanFeedback node: {}", node.getTitle());
|
||||
// 从状态中获取用户输入数据
|
||||
Object humanFeedbackState = state.data().get(HUMAN_FEEDBACK_KEY);
|
||||
if (null != humanFeedbackState) {
|
||||
String userInput = humanFeedbackState.toString();
|
||||
if (StringUtils.isNotBlank(userInput)) {
|
||||
// 用户已提供输入,将用户输入添加到节点输入和输出中
|
||||
NodeIOData feedbackData = NodeIOData.createByText("output", "default", userInput);
|
||||
// 添加到输入列表,这样当前节点处理时可以使用
|
||||
state.getInputs().add(feedbackData);
|
||||
// 添加到输出列表,这样后续节点可以使用
|
||||
state.getOutputs().add(feedbackData);
|
||||
// 设置为成功状态
|
||||
state.setProcessStatus(NODE_PROCESS_STATUS_SUCCESS);
|
||||
log.info("Human feedback processed for node: {}, content: {}", node.getTitle(), userInput);
|
||||
} else {
|
||||
// 用户输入为空,设置等待状态
|
||||
state.setProcessStatus(NODE_PROCESS_STATUS_DOING);
|
||||
log.info("Human feedback is empty for node: {}", node.getTitle());
|
||||
}
|
||||
} else {
|
||||
// 没有用户输入,这可能是正常情况(等待用户输入)
|
||||
// 但为了确保流程可以继续,我们仍然标记为成功
|
||||
state.setProcessStatus(NODE_PROCESS_STATUS_SUCCESS);
|
||||
log.info("No human feedback found for node: {}, continuing workflow", node.getTitle());
|
||||
}
|
||||
return new NodeProcessResult();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user