context:通义万相文生图节点功能以及发送邮箱和HTTP请求节点调研

This commit is contained in:
zengxb
2026-02-24 10:34:26 +08:00
parent b40805cb57
commit 0a115f289e
14 changed files with 476 additions and 57 deletions

View File

@@ -4,9 +4,10 @@ import org.ruoyi.workflow.entity.WorkflowComponent;
import org.ruoyi.workflow.entity.WorkflowNode;
import org.ruoyi.workflow.workflow.node.AbstractWfNode;
import org.ruoyi.workflow.workflow.node.EndNode;
import org.ruoyi.workflow.workflow.node.HumanFeedbackNode;
import org.ruoyi.workflow.workflow.node.humanFeedBack.HumanFeedbackNode;
import org.ruoyi.workflow.workflow.node.answer.LLMAnswerNode;
import org.ruoyi.workflow.workflow.node.httpRequest.HttpRequestNode;
import org.ruoyi.workflow.workflow.node.image.ImageNode;
import org.ruoyi.workflow.workflow.node.keywordExtractor.KeywordExtractorNode;
import org.ruoyi.workflow.workflow.node.knowledgeRetrieval.KnowledgeRetrievalNode;
import org.ruoyi.workflow.workflow.node.mailSend.MailSendNode;
@@ -21,6 +22,7 @@ public class WfNodeFactory {
case START -> wfNode = new StartNode(wfComponent, nodeDefinition, wfState, nodeState);
case LLM_ANSWER -> wfNode = new LLMAnswerNode(wfComponent, nodeDefinition, wfState, nodeState);
case KEYWORD_EXTRACTOR -> wfNode = new KeywordExtractorNode(wfComponent, nodeDefinition, wfState, nodeState);
case TONGYI_WANX -> wfNode = new ImageNode(wfComponent, nodeDefinition, wfState, nodeState);
case KNOWLEDGE_RETRIEVER -> wfNode = new KnowledgeRetrievalNode(wfComponent, nodeDefinition, wfState, nodeState);
case END -> wfNode = new EndNode(wfComponent, nodeDefinition, wfState, nodeState);
case MAIL_SEND -> wfNode = new MailSendNode(wfComponent, nodeDefinition, wfState, nodeState);

View File

@@ -13,10 +13,13 @@ import org.bsc.langgraph4j.langchain4j.generators.StreamingChatGenerator;
import org.bsc.langgraph4j.state.AgentState;
import org.ruoyi.common.chat.Service.IChatModelService;
import org.ruoyi.common.chat.Service.IChatService;
import org.ruoyi.common.chat.Service.IImageGenerationService;
import org.ruoyi.common.chat.domain.dto.request.ChatRequest;
import org.ruoyi.common.chat.domain.entity.chat.ChatContext;
import org.ruoyi.common.chat.domain.entity.image.ImageContext;
import org.ruoyi.common.chat.domain.vo.chat.ChatModelVo;
import org.ruoyi.common.chat.factory.ChatServiceFactory;
import org.ruoyi.common.chat.factory.ImageServiceFactory;
import org.ruoyi.workflow.base.NodeInputConfigTypeHandler;
import org.ruoyi.workflow.entity.WorkflowNode;
import org.ruoyi.workflow.enums.WfIODataTypeEnum;
@@ -38,6 +41,9 @@ public class WorkflowUtil {
@Resource
private ChatServiceFactory chatServiceFactory;
@Resource
private ImageServiceFactory imageServiceFactory;
@Resource
private IChatModelService chatModelService;
@@ -213,4 +219,30 @@ public class WorkflowUtil {
.filter(item -> nameSet.contains(item.getName()))
.map(item -> getMessage("user", item.getContent().getValue().toString())).toList();
}
/**
* 调用LLM 根据文字生成图片
*/
public String buildTextToImage(String modelName, String prompt, String size, Integer seed){
log.info("Generate image invoke, modelName: {}", modelName);
// 根据模型名称查询模型信息
ChatModelVo chatModelVo = chatModelService.selectModelByName(modelName);
if (chatModelVo == null) {
throw new IllegalArgumentException("模型不存在: " + modelName);
}
// 根据模型名称找到模型实体
String modelVoCategory = chatModelVo.getCategory();
// 根据 category 获取对应的 IImageGenerationService不使用计费代理工作流场景单独计费
IImageGenerationService imageService = imageServiceFactory.getOriginalService(modelVoCategory);
// 构建文生图上下文对象
ImageContext imageContext = ImageContext.builder()
.chatModelVo(chatModelVo)
.prompt(prompt)
.size(size)
.seed(seed)
.build();
// 调用LLM 生成图片
return imageService.generateImage(imageContext);
}
}

View File

@@ -12,12 +12,6 @@ public class LLMAnswerNodeConfig {
@NotBlank
private String prompt;
/**
* TODO
*/
// @NotBlank
private String category;
@NotNull
@JsonProperty("model_name")
private String modelName;

View File

@@ -1,4 +1,4 @@
package org.ruoyi.workflow.workflow.node;
package org.ruoyi.workflow.workflow.node.humanFeedBack;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
@@ -8,6 +8,7 @@ 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.*;

View File

@@ -0,0 +1,62 @@
package org.ruoyi.workflow.workflow.node.image;
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.util.SpringUtil;
import org.ruoyi.workflow.workflow.NodeProcessResult;
import org.ruoyi.workflow.workflow.WfNodeState;
import org.ruoyi.workflow.workflow.WfState;
import org.ruoyi.workflow.workflow.WorkflowUtil;
import org.ruoyi.workflow.workflow.data.NodeIOData;
import org.ruoyi.workflow.workflow.node.AbstractWfNode;
import static org.ruoyi.workflow.cosntant.AdiConstant.WorkflowConstant.NODE_PROCESS_STATUS_SUCCESS;
/**
* 【节点】文生图 <br/>
* 节点内容固定格式ImageNodeConfig
*/
@Slf4j
public class ImageNode extends AbstractWfNode {
public ImageNode(WorkflowComponent wfComponent, WorkflowNode nodeDef, WfState wfState, WfNodeState nodeState) {
super(wfComponent, nodeDef, wfState, nodeState);
}
/**
* nodeConfig格式
* {"prompt": "{input}","model_name":"wan2.5-t2i-preview","size":"1024*1024"}
*
* @return 图片地址URL
*/
@Override
public NodeProcessResult onProcess() {
ImageNodeConfig nodeConfigObj = checkAndGetConfig(ImageNodeConfig.class);
String inputText = getFirstInputText();
log.info("Image node config:{}", nodeConfigObj);
String prompt = inputText;
if (StringUtils.isNotBlank(nodeConfigObj.getPrompt())) {
prompt = WorkflowUtil.renderTemplate(nodeConfigObj.getPrompt(), state.getInputs());
}
log.info("Image prompt:{}", prompt);
// 获取工作流实例
WorkflowUtil workflowUtil = SpringUtil.getBean(WorkflowUtil.class);
// 获取模型名称
String modelName = nodeConfigObj.getModelName();
// 获取图片大小
String size = nodeConfigObj.getSize();
// 获取随机数种子
Integer seed = nodeConfigObj.getSeed();
// 调用LLM生成图片后续可以将图片保存到OSS中
String imageUrl = workflowUtil.buildTextToImage(modelName, prompt, size, seed);
// 创建节点参数对象
NodeIOData nodeIOData = NodeIOData.createByText("output", "image", imageUrl);
// 添加到输出列表以便给后续节点使用
state.getOutputs().add(nodeIOData);
// 设置为成功状态
state.setProcessStatus(NODE_PROCESS_STATUS_SUCCESS);
return new NodeProcessResult();
}
}

View File

@@ -0,0 +1,37 @@
package org.ruoyi.workflow.workflow.node.image;
import com.fasterxml.jackson.annotation.JsonProperty;
import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import lombok.EqualsAndHashCode;
@EqualsAndHashCode
@Data
public class ImageNodeConfig {
/**
* 提示词
*/
private String prompt;
/**
* 模型名称
*/
@NotNull
@JsonProperty("model_name")
private String modelName;
/**
* 图片尺寸大小
*/
private String size;
/**
* 随机数种子
*/
@Min(value = 0, message = "随机数种子不能小于0")
@Max(value = 2147483647, message = "随机数种子不能大于2147483647")
private Integer seed;
}