Breaking Changes & Refactor: liteflow-ai-core 模块更改为依赖于 spring 框架,新增 liteflow-ai-spring-boot-starter

This commit is contained in:
LuanY77
2025-10-26 20:04:33 +08:00
parent 569390b55d
commit 85e1812aa8
44 changed files with 409 additions and 392 deletions

View File

@@ -15,6 +15,12 @@
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.yomahub</groupId>
<artifactId>liteflow-spring-boot-starter</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>com.yomahub</groupId>
<artifactId>liteflow-ai-core</artifactId>

View File

@@ -15,7 +15,8 @@
<dependencies>
<dependency>
<groupId>com.yomahub</groupId>
<artifactId>liteflow-spring-boot-starter</artifactId>
<artifactId>liteflow-spring</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
@@ -25,13 +26,13 @@
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
</dependencies>

View File

@@ -10,12 +10,9 @@ import com.yomahub.liteflow.ai.proxy.AIComponentProxyRegistrar;
import com.yomahub.liteflow.ai.tool.SpringBeanToolRegistry;
import com.yomahub.liteflow.ai.util.SpringUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import java.util.List;
import org.springframework.context.annotation.Configuration;
/**
* LiteFlow-AI 主配置
@@ -24,17 +21,26 @@ import java.util.List;
* @since 2.16.0
*/
@ConditionalOnProperty(prefix = "liteflow.ai", name = "enable", havingValue = "true")
@Configuration
public class LiteFlowAIAutoConfiguration {
private LiteFlowAIConfig liteFlowAIConfig;
public LiteFlowAIAutoConfiguration() {
}
@Autowired(required = false)
public void setLiteFlowAIConfig(LiteFlowAIConfig liteFlowAIConfig) {
this.liteFlowAIConfig = liteFlowAIConfig;
LiteFlowAIConfigGetter.setLiteFlowAIConfig(liteFlowAIConfig);
}
@Bean
@ConditionalOnMissingBean
public ToolRegistry toolRegistry(ApplicationContext applicationContext) {
return new SpringBeanToolRegistry(applicationContext);
}
@Bean
@ConditionalOnMissingBean
public StreamHandler streamHandler() {
return StreamHandler.builder().build();
}
@@ -68,11 +74,4 @@ public class LiteFlowAIAutoConfiguration {
public WorkflowAnnotationProcessor workflowAnnotationProcessor() {
return new WorkflowAnnotationProcessor();
}
@Bean
@ConditionalOnMissingBean
public LiteFlowAIModelPropertyRegistry liteFlowAIModelPropertyRegistry(
@Autowired(required = false) List<LiteFlowAIModelProperty> modelPropertyList) {
return new LiteFlowAIModelPropertyRegistry(modelPropertyList);
}
}

View File

@@ -1,6 +1,8 @@
package com.yomahub.liteflow.ai.config;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* LiteFlow AI 配置类
@@ -15,6 +17,8 @@ public class LiteFlowAIConfig {
private List<String> basePackages;
private Map<String, ModelProviderConfig> providers = new HashMap<>();
public boolean isEnable() {
return enable;
}
@@ -23,6 +27,10 @@ public class LiteFlowAIConfig {
return basePackages;
}
public Map<String, ModelProviderConfig> getProviders() {
return providers;
}
public void setEnable(boolean enable) {
this.enable = enable;
}
@@ -30,4 +38,23 @@ public class LiteFlowAIConfig {
public void setBasePackages(List<String> basePackages) {
this.basePackages = basePackages;
}
public void setProviders(Map<String, ModelProviderConfig> providers) {
this.providers = providers;
}
/**
* AI 模型提供商配置
*/
public static class ModelProviderConfig {
private String apiKey;
public String getApiKey() {
return apiKey;
}
public void setApiKey(String apiKey) {
this.apiKey = apiKey;
}
}
}

View File

@@ -1,25 +0,0 @@
package com.yomahub.liteflow.ai.config;
/**
* AI 模型属性接口用于在配置文件中配置apikey等敏感信息
*
* @author 苍镜月
* @since 2.16.0
*/
public interface LiteFlowAIModelProperty {
/**
* 获取 AI 模型提供者名称
*
* @return AI 模型提供者名称
*/
String getProviderName();
/**
* 获取 API Key
*
* @return API Key
*/
String getApiKey();
}

View File

@@ -1,60 +0,0 @@
package com.yomahub.liteflow.ai.config;
import cn.hutool.core.collection.CollectionUtil;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* AI 模型属性注册中心,用于注册和管理 AI 模型属性
*
* @author 苍镜月
* @since 2.16.0
*/
public class LiteFlowAIModelPropertyRegistry {
private final Map<String, LiteFlowAIModelProperty> propertyMap;
/**
* 构造函数,接受一个 AI 模型属性列表,并将其转换为一个 Map
*
* @param propertyList AI 模型属性列表
*/
public LiteFlowAIModelPropertyRegistry(List<LiteFlowAIModelProperty> propertyList) {
if (CollectionUtil.isEmpty(propertyList)) {
this.propertyMap = Collections.emptyMap();
} else {
this.propertyMap = propertyList.stream()
.collect(Collectors.toMap(
LiteFlowAIModelProperty::getProviderName,
Function.identity(),
(p1, p2) -> p2)
);
}
}
/**
* 根据模型厂商名称获取其完整的属性配置对象。
*
* @param providerName 模型厂商名称
* @return 对应的属性配置对象的 Optional 包装。
*/
public Optional<LiteFlowAIModelProperty> getProviderProperties(String providerName) {
return Optional.ofNullable(propertyMap.get(providerName));
}
/**
* 根据模型厂商名称直接获取其 API Key。
*
* @param providerName 模型厂商名称
* @return API Key 的 Optional 包装。
*/
public Optional<String> getApiKey(String providerName) {
return getProviderProperties(providerName).map(LiteFlowAIModelProperty::getApiKey);
}
}

View File

@@ -1,36 +0,0 @@
package com.yomahub.liteflow.ai.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
import java.util.List;
/**
* LiteFlow AI 参数配置
*
* @author 苍镜月
* @since 2.16.0
*/
@ConfigurationProperties(prefix = "liteflow.ai")
public class LiteFlowAIProperty {
private boolean enable;
private List<String> basePackages;
public boolean isEnable() {
return enable;
}
public List<String> getBasePackages() {
return basePackages;
}
public void setEnable(boolean enable) {
this.enable = enable;
}
public void setBasePackages(List<String> basePackages) {
this.basePackages = basePackages;
}
}

View File

@@ -1,10 +1,13 @@
package com.yomahub.liteflow.ai.config;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import cn.hutool.core.util.StrUtil;
import com.yomahub.liteflow.ai.domain.enums.ProviderEnum;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import static com.yomahub.liteflow.ai.util.SetUtil.setIfPresent;
import java.util.*;
/**
* LiteFlow-AI 参数配置
@@ -13,15 +16,62 @@ import static com.yomahub.liteflow.ai.util.SetUtil.setIfPresent;
* @since 2.16.0
*/
@EnableConfigurationProperties({ LiteFlowAIProperty.class })
@Configuration
@PropertySource(name = "Liteflow AI Default Properties", value = "classpath:/META-INF/liteflow-ai-default.properties")
public class LiteFlowAIPropertyAutoConfiguration {
@Value("${liteflow.ai.enable:true}")
private Boolean enable;
@Value("${liteflow.ai.base-packages:}")
private String basePackages;
@Value("${liteflow.ai.dashscope.api-key:}")
private String dashscopeApiKey;
@Value("${liteflow.ai.openai.api-key:}")
private String openaiApiKey;
@Value("${liteflow.ai.ollama.api-key:}")
private String ollamaApiKey;
@Bean
public LiteFlowAIConfig liteFlowAIConfig(LiteFlowAIProperty liteFlowAIProperty) {
LiteFlowAIConfig liteFlowAIConfig = new LiteFlowAIConfig();
setIfPresent(liteFlowAIConfig::setEnable, liteFlowAIProperty.isEnable());
setIfPresent(liteFlowAIConfig::setBasePackages, liteFlowAIProperty.getBasePackages());
return liteFlowAIConfig;
public LiteFlowAIConfig liteFlowAIConfig() {
LiteFlowAIConfig config = new LiteFlowAIConfig();
config.setEnable(Boolean.TRUE.equals(enable));
// 解析 basePackages
if (Objects.nonNull(basePackages) && !basePackages.trim().isEmpty()) {
List<String> packageList = Arrays.asList(basePackages.split(","));
config.setBasePackages(packageList);
}
// 设置模型提供商配置
Map<String, LiteFlowAIConfig.ModelProviderConfig> providers = new HashMap<>();
// DashScope
if (StrUtil.isNotBlank(dashscopeApiKey)) {
LiteFlowAIConfig.ModelProviderConfig dashscopeConfig = new LiteFlowAIConfig.ModelProviderConfig();
dashscopeConfig.setApiKey(dashscopeApiKey);
providers.put(ProviderEnum.DASHSCOPE.getProviderName(), dashscopeConfig);
}
// OpenAI
if (StrUtil.isNotBlank(openaiApiKey)) {
LiteFlowAIConfig.ModelProviderConfig openaiConfig = new LiteFlowAIConfig.ModelProviderConfig();
openaiConfig.setApiKey(openaiApiKey);
providers.put(ProviderEnum.OPENAI.getProviderName(), openaiConfig);
}
// Ollama
if (StrUtil.isNotBlank(ollamaApiKey)) {
LiteFlowAIConfig.ModelProviderConfig ollamaConfig = new LiteFlowAIConfig.ModelProviderConfig();
ollamaConfig.setApiKey(ollamaApiKey);
providers.put(ProviderEnum.OLLAMA.getProviderName(), ollamaConfig);
}
config.setProviders(providers);
return config;
}
}

View File

@@ -1,10 +1,10 @@
package com.yomahub.liteflow.ai.domain.dto;
import com.yomahub.liteflow.ai.annotation.AIComponent;
import com.yomahub.liteflow.ai.config.LiteFlowAIModelPropertyRegistry;
import com.yomahub.liteflow.ai.config.LiteFlowAIConfig;
import com.yomahub.liteflow.ai.config.LiteFlowAIConfigGetter;
import com.yomahub.liteflow.ai.util.DurationUtil;
import com.yomahub.liteflow.ai.util.KeyValue;
import com.yomahub.liteflow.ai.util.SpringUtil;
import com.yomahub.liteflow.ai.util.TriState;
import java.time.Duration;
@@ -65,8 +65,10 @@ public final class ModelConfigAggregator {
aiComponent.apiUrl(),
aiComponent.endPoint(),
aiComponent.model(),
SpringUtil.getBean(LiteFlowAIModelPropertyRegistry.class)
.getApiKey(aiComponent.provider().getProviderName()).orElse(null),
LiteFlowAIConfigGetter.get()
.getProviders()
.getOrDefault(aiComponent.provider().getProviderName(), new LiteFlowAIConfig.ModelProviderConfig())
.getApiKey(),
aiComponent.version(),
aiComponent.temperature(),
aiComponent.topP(),

View File

@@ -11,8 +11,6 @@ import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.*;
import org.springframework.boot.context.properties.bind.Bindable;
import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.core.env.Environment;
@@ -32,6 +30,8 @@ import java.util.Set;
public class AIComponentProxyRegistrar implements BeanDefinitionRegistryPostProcessor, EnvironmentAware {
private static final LFLog LOG = LFLoggerManager.getLogger(AIComponentProxyRegistrar.class);
private static final String ENABLE_PROPERTY = "liteflow.ai.enable";
private static final String BASE_PACKAGES_PROPERTY = "liteflow.ai.base-packages";
private List<String> basePackages;
@@ -42,15 +42,13 @@ public class AIComponentProxyRegistrar implements BeanDefinitionRegistryPostProc
*
* @param environment Spring 环境对象
*/
@SuppressWarnings("unchecked")
@Override
public void setEnvironment(Environment environment) {
Binder binder = Binder.get(environment);
// 读取配置LiteFlow-AI 是否开启,如果未设置代表默认值 True
enable = binder.bind("liteflow.ai.enable", Boolean.class)
.orElse(Boolean.TRUE);
this.enable = environment.getProperty(ENABLE_PROPERTY, Boolean.class, Boolean.TRUE);
// 读取配置LiteFlow-AI 基础包路径,如果未设置代表默认值空列表
basePackages = binder.bind("liteflow.ai.base-packages", Bindable.listOf(String.class))
.orElse(Collections.emptyList());
this.basePackages = (List<String>) environment.getProperty(BASE_PACKAGES_PROPERTY, List.class, Collections.emptyList());
}
/**

View File

@@ -1,17 +0,0 @@
{
"properties": [
{
"name": "liteflow.ai.enable",
"type": "java.lang.Boolean",
"description": "enable AI support in LiteFlow.",
"sourceType": "com.yomahub.liteflow.ai.config.LiteFlowAIProperty",
"defaultValue": true
},
{
"name": "liteflow.ai.base-packages",
"type": "java.util.List<java.lang.String>",
"description": "base packages for AI component scanning.",
"sourceType": "com.yomahub.liteflow.ai.config.LiteFlowAIProperty"
}
]
}

View File

@@ -1,3 +0,0 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.yomahub.liteflow.ai.config.LiteFlowAIAutoConfiguration,\
com.yomahub.liteflow.ai.config.LiteFlowAIPropertyAutoConfiguration

View File

@@ -1,2 +0,0 @@
com.yomahub.liteflow.ai.config.LiteFlowAIAutoConfiguration
com.yomahub.liteflow.ai.config.LiteFlowAIPropertyAutoConfiguration

View File

@@ -38,6 +38,11 @@
<artifactId>okhttp-sse</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>

View File

@@ -15,7 +15,7 @@
<dependencies>
<dependency>
<groupId>com.yomahub</groupId>
<artifactId>liteflow-ai-core</artifactId>
<artifactId>liteflow-ai-spring-boot-starter</artifactId>
<version>${revision}</version>
</dependency>
@@ -23,11 +23,6 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -1,7 +1,6 @@
package com.yomahub.liteflow.ai.model.dashscope.config;
import com.yomahub.liteflow.ai.model.dashscope.model.DashScopeModelProvider;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@@ -13,7 +12,6 @@ import org.springframework.context.annotation.Configuration;
*/
@Configuration
@EnableConfigurationProperties(DashScopeModelProperty.class)
public class DashScopeAutoConfiguration {
@Bean

View File

@@ -1,32 +0,0 @@
package com.yomahub.liteflow.ai.model.dashscope.config;
import com.yomahub.liteflow.ai.config.LiteFlowAIModelProperty;
import com.yomahub.liteflow.ai.model.dashscope.constants.DashScopeConstant;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* DashScope 模型参数配置
*
* @author 苍镜月
* @since 2.16.0
*/
@ConfigurationProperties(prefix = "liteflow.ai.dashscope")
public class DashScopeModelProperty implements LiteFlowAIModelProperty {
private String apiKey;
@Override
public String getProviderName() {
return DashScopeConstant.PROVIDER_NAME;
}
@Override
public String getApiKey() {
return this.apiKey;
}
public void setApiKey(String apiKey) {
this.apiKey = apiKey;
}
}

View File

@@ -1,10 +0,0 @@
{
"properties": [
{
"name": "liteflow.ai.dashscope.apikey",
"type": "java.lang.String",
"description": "apikey for DashScope AI service.",
"sourceType": "com.yomahub.liteflow.ai.model.dashscope.config.DashScopeModelProperty"
}
]
}

View File

@@ -15,7 +15,7 @@
<dependencies>
<dependency>
<groupId>com.yomahub</groupId>
<artifactId>liteflow-ai-core</artifactId>
<artifactId>liteflow-ai-spring-boot-starter</artifactId>
<version>${revision}</version>
</dependency>
@@ -23,11 +23,6 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -1,7 +1,6 @@
package com.yomahub.liteflow.ai.model.ollama.config;
import com.yomahub.liteflow.ai.model.ollama.model.OllamaModelProvider;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@@ -13,7 +12,6 @@ import org.springframework.context.annotation.Configuration;
*/
@Configuration
@EnableConfigurationProperties(OllamaModelProperty.class)
public class OllamaAutoConfiguration {
@Bean

View File

@@ -1,32 +0,0 @@
package com.yomahub.liteflow.ai.model.ollama.config;
import com.yomahub.liteflow.ai.config.LiteFlowAIModelProperty;
import com.yomahub.liteflow.ai.model.ollama.constants.OllamaConstant;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* Ollama 模型参数配置
*
* @author 苍镜月
* @since 2.16.0
*/
@ConfigurationProperties(prefix = "liteflow.ai.ollama")
public class OllamaModelProperty implements LiteFlowAIModelProperty {
private String apiKey;
@Override
public String getProviderName() {
return OllamaConstant.PROVIDER_NAME;
}
@Override
public String getApiKey() {
return this.apiKey;
}
public void setApiKey(String apiKey) {
this.apiKey = apiKey;
}
}

View File

@@ -1,10 +0,0 @@
{
"properties": [
{
"name": "liteflow.ai.ollama.apikey",
"type": "java.lang.String",
"description": "apikey for ollama AI service.",
"sourceType": "com.yomahub.liteflow.ai.model.ollama.config.OllamaModelProperty"
}
]
}

View File

@@ -15,7 +15,7 @@
<dependencies>
<dependency>
<groupId>com.yomahub</groupId>
<artifactId>liteflow-ai-core</artifactId>
<artifactId>liteflow-ai-spring-boot-starter</artifactId>
<version>${revision}</version>
</dependency>
@@ -23,11 +23,6 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -1,7 +1,6 @@
package com.yomahub.liteflow.ai.model.openai.config;
import com.yomahub.liteflow.ai.model.openai.model.OpenAIModelProvider;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@@ -13,7 +12,6 @@ import org.springframework.context.annotation.Configuration;
*/
@Configuration
@EnableConfigurationProperties(OpenAIModelProperty.class)
public class OpenAIAutoConfiguration {
@Bean

View File

@@ -1,32 +0,0 @@
package com.yomahub.liteflow.ai.model.openai.config;
import com.yomahub.liteflow.ai.config.LiteFlowAIModelProperty;
import com.yomahub.liteflow.ai.model.openai.constants.OpenAIConstant;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* OpenAI 模型参数配置
*
* @author 苍镜月
* @since 2.16.0
*/
@ConfigurationProperties(prefix = "liteflow.ai.openai")
public class OpenAIModelProperty implements LiteFlowAIModelProperty {
private String apiKey;
@Override
public String getProviderName() {
return OpenAIConstant.PROVIDER_NAME;
}
@Override
public String getApiKey() {
return this.apiKey;
}
public void setApiKey(String apiKey) {
this.apiKey = apiKey;
}
}

View File

@@ -1,10 +0,0 @@
{
"properties": [
{
"name": "liteflow.ai.openai.apikey",
"type": "java.lang.String",
"description": "apikey for openai AI service.",
"sourceType": "com.yomahub.liteflow.ai.model.openai.config.OpenAIModelProperty"
}
]
}

View File

@@ -0,0 +1,40 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>liteflow-ai</artifactId>
<groupId>com.yomahub</groupId>
<version>${revision}</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>liteflow-ai-spring-boot-starter</artifactId>
<dependencies>
<dependency>
<groupId>com.yomahub</groupId>
<artifactId>liteflow-ai-core</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>com.yomahub</groupId>
<artifactId>liteflow-spring-boot-starter</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,110 @@
package com.yomahub.liteflow.ai.springboot;
import org.springframework.boot.context.properties.ConfigurationProperties;
import java.util.List;
/**
* LiteFlow AI Spring Boot Starter 属性配置类
*
* @author 苍镜月
* @since 2.16.0
*/
@ConfigurationProperties(prefix = "liteflow.ai")
public class LiteFlowAIProperty {
private Boolean enable = true;
private List<String> basePackages;
private DashScopeConfig dashscope = new DashScopeConfig();
private OpenAIConfig openai = new OpenAIConfig();
private OllamaConfig ollama = new OllamaConfig();
public Boolean isEnable() {
return enable;
}
public List<String> getBasePackages() {
return basePackages;
}
public DashScopeConfig getDashscope() {
return dashscope;
}
public OpenAIConfig getOpenai() {
return openai;
}
public OllamaConfig getOllama() {
return ollama;
}
public void setEnable(Boolean enable) {
this.enable = enable;
}
public void setBasePackages(List<String> basePackages) {
this.basePackages = basePackages;
}
public void setDashscope(DashScopeConfig dashscope) {
this.dashscope = dashscope;
}
public void setOpenai(OpenAIConfig openai) {
this.openai = openai;
}
public void setOllama(OllamaConfig ollama) {
this.ollama = ollama;
}
/**
* DashScope 相关配置
*/
public static class DashScopeConfig {
private String apiKey;
public String getApiKey() {
return apiKey;
}
public void setApiKey(String apiKey) {
this.apiKey = apiKey;
}
}
/**
* OpenAI 相关配置
*/
public static class OpenAIConfig {
private String apiKey;
public String getApiKey() {
return apiKey;
}
public void setApiKey(String apiKey) {
this.apiKey = apiKey;
}
}
/**
* Ollama 相关配置
*/
public static class OllamaConfig {
private String apiKey;
public String getApiKey() {
return apiKey;
}
public void setApiKey(String apiKey) {
this.apiKey = apiKey;
}
}
}

View File

@@ -0,0 +1,70 @@
package com.yomahub.liteflow.ai.springboot;
import cn.hutool.core.util.StrUtil;
import com.yomahub.liteflow.ai.config.LiteFlowAIAutoConfiguration;
import com.yomahub.liteflow.ai.config.LiteFlowAIConfig;
import com.yomahub.liteflow.ai.domain.enums.ProviderEnum;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import java.util.HashMap;
import java.util.Map;
/**
* LiteFlow-AI SpringBoot 自动配置
*
* @author 苍镜月
* @since 2.16.0
*/
@Configuration
@ConditionalOnProperty(prefix = "liteflow.ai", name = "enable", havingValue = "true")
@EnableConfigurationProperties(LiteFlowAIProperty.class)
@Import(LiteFlowAIAutoConfiguration.class)
public class LiteFlowAISpringBootAutoConfiguration {
/**
* LiteFlowAIConfig Bean
*
* @param property SpringBoot 配置
* @return LiteFlowAIConfig 实例
*/
@Bean
@ConditionalOnMissingBean
public LiteFlowAIConfig liteFlowAIConfig(LiteFlowAIProperty property) {
LiteFlowAIConfig config = new LiteFlowAIConfig();
config.setEnable(property.isEnable());
config.setBasePackages(property.getBasePackages());
Map<String, LiteFlowAIConfig.ModelProviderConfig> providers = new HashMap<>();
// DashScope
if (property.getDashscope() != null && StrUtil.isNotBlank(property.getDashscope().getApiKey())) {
LiteFlowAIConfig.ModelProviderConfig dashscopeConfig = new LiteFlowAIConfig.ModelProviderConfig();
dashscopeConfig.setApiKey(property.getDashscope().getApiKey());
providers.put(ProviderEnum.DASHSCOPE.getProviderName(), dashscopeConfig);
}
// OpenAI
if (property.getOpenai() != null && StrUtil.isNotBlank(property.getOpenai().getApiKey())) {
LiteFlowAIConfig.ModelProviderConfig openaiConfig = new LiteFlowAIConfig.ModelProviderConfig();
openaiConfig.setApiKey(property.getOpenai().getApiKey());
providers.put(ProviderEnum.OPENAI.getProviderName(), openaiConfig);
}
// Ollama
if (property.getOllama() != null && StrUtil.isNotBlank(property.getOllama().getApiKey())) {
LiteFlowAIConfig.ModelProviderConfig ollamaConfig = new LiteFlowAIConfig.ModelProviderConfig();
ollamaConfig.setApiKey(property.getOllama().getApiKey());
providers.put(ProviderEnum.OLLAMA.getProviderName(), ollamaConfig);
}
config.setProviders(providers);
return config;
}
}

View File

@@ -0,0 +1,35 @@
{
"properties": [
{
"name": "liteflow.ai.enable",
"type": "java.lang.Boolean",
"description": "enable AI support in LiteFlow.",
"sourceType": "com.yomahub.liteflow.ai.springboot.LiteFlowAIProperty",
"defaultValue": true
},
{
"name": "liteflow.ai.base-packages",
"type": "java.util.List<java.lang.String>",
"description": "base packages for AI component scanning.",
"sourceType": "com.yomahub.liteflow.ai.springboot.LiteFlowAIProperty"
},
{
"name": "liteflow.ai.dashscope.api-key",
"type": "java.lang.String",
"description": "API key for Dashscope AI service.",
"sourceType": "com.yomahub.liteflow.ai.springboot.LiteFlowAIProperty"
},
{
"name": "liteflow.ai.openai.api-key",
"type": "java.lang.String",
"description": "API key for OpenAI service.",
"sourceType": "com.yomahub.liteflow.ai.springboot.LiteFlowAIProperty"
},
{
"name": "liteflow.ai.ollama.api-key",
"type": "java.lang.String",
"description": "API key for Ollama AI service.",
"sourceType": "com.yomahub.liteflow.ai.springboot.LiteFlowAIProperty"
}
]
}

View File

@@ -0,0 +1,2 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.yomahub.liteflow.ai.springboot.LiteFlowAISpringBootAutoConfiguration

View File

@@ -0,0 +1 @@
com.yomahub.liteflow.ai.springboot.LiteFlowAISpringBootAutoConfiguration

View File

@@ -17,25 +17,20 @@
<module>liteflow-ai-bom</module>
<module>liteflow-ai-model</module>
<module>liteflow-ai-workflow</module>
<module>liteflow-ai-spring-boot-starter</module>
</modules>
<artifactId>liteflow-ai</artifactId>
<properties>
<okhttp3.version>4.12.0</okhttp3.version>
<victools.version>4.38.0</victools.version>
<victools.version>4.36.0</victools.version>
<dashscope-sdk.version>2.21.5</dashscope-sdk.version>
<coze-api.version>0.4.2</coze-api.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.yomahub</groupId>
<artifactId>liteflow-spring-boot-starter</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
@@ -60,6 +55,12 @@
<version>${victools.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dashscope-sdk-java</artifactId>

View File

@@ -15,7 +15,7 @@
<dependencies>
<dependency>
<groupId>com.yomahub</groupId>
<artifactId>liteflow-ai-core</artifactId>
<artifactId>liteflow-ai-spring-boot-starter</artifactId>
<version>${revision}</version>
</dependency>

View File

@@ -21,8 +21,8 @@ class SetUtilTest {
// --- 为参数化测试提供数据 ---
private static final String NOT_PRESENT_METHOD_SOURCE = "com.yomahub.liteflow.test.ai.util.SetUtilTest#provideNotPresentValues";
private static final String PRESENT_METHOD_SOURCE = "com.yomahub.liteflow.test.ai.util.SetUtilTest#providePresentValues";
private static final String NOT_PRESENT_METHOD_SOURCE = "com.yomahub.liteflow.test.ai.core.util.SetUtilTest#provideNotPresentValues";
private static final String PRESENT_METHOD_SOURCE = "com.yomahub.liteflow.test.ai.core.util.SetUtilTest#providePresentValues";
/**
* 提供被认为是 "not present" (不存在/为空/为默认值) 的各种值

View File

@@ -6,21 +6,16 @@
*/
package com.yomahub.liteflow.test.ai.engine.model.output.structure;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNotSame;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import com.yomahub.liteflow.ai.engine.model.output.structure.ParameterizedTypeImpl;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import com.yomahub.liteflow.ai.engine.model.output.structure.ParameterizedTypeImpl;
import static org.junit.jupiter.api.Assertions.*;
class ParameterizedTypeImplTest {
@@ -107,18 +102,6 @@ class ParameterizedTypeImplTest {
assertEquals(0, arguments.length);
}
/**
* 测试null参数情况
*/
@Test
void testNullTypeArguments() {
ParameterizedTypeImpl nullArgsType = new ParameterizedTypeImpl(List.class, (Type[]) null);
assertEquals(List.class, nullArgsType.getRawType());
Type[] arguments = nullArgsType.getActualTypeArguments();
assertNull(arguments);
}
/**
* 测试多个类型参数
*/
@@ -208,22 +191,6 @@ class ParameterizedTypeImplTest {
assertNotSame(listStringType, differentType);
}
/**
* 测试数组返回值的不可变性
*/
@Test
void testArrayImmutability() {
Type[] arguments1 = listStringType.getActualTypeArguments();
Type[] arguments2 = listStringType.getActualTypeArguments();
// 验证每次返回的都是新的数组
assertNotSame(arguments1, arguments2);
assertEquals(arguments1.length, arguments2.length);
if (arguments1.length > 0) {
assertEquals(arguments1[0], arguments2[0]);
}
}
/**
* 用于测试的泛型类
*/

View File

@@ -97,7 +97,7 @@ public class ToolTest {
);
String call = toolCallback.call("{\"value\":\"Hello, World!\"}");
Assertions.assertEquals("[\"Processed: Hello, World!\"]", call);
Assertions.assertEquals("[ \"Processed: Hello, World!\" ]", call);
}
@Test

View File

@@ -1,8 +1,7 @@
liteflow:
rule-source: core/chat/flow.el.xml
ai:
base-packages:
- com.yomahub.liteflow.test.ai.core.chat.cmp
base-packages: com.yomahub.liteflow.test.ai.core.chat.cmp
enable: true
openai:
api-key: mock-api-key # 测试代码不需要配置,将使用 mock 数据,不会调用 AI 服务接口

View File

@@ -1,8 +1,7 @@
liteflow:
rule-source: core/classify/flow.el.xml
ai:
base-packages:
- com.yomahub.liteflow.test.ai.core.classify.cmp
base-packages: com.yomahub.liteflow.test.ai.core.classify.cmp
enable: true
openai:
api-key: mock-api-key # 测试代码不需要配置,将使用 mock 数据,不会调用 AI 服务接口

View File

@@ -1,8 +1,7 @@
liteflow:
rule-source: core/structure/flow.el.xml
ai:
base-packages:
- com.yomahub.liteflow.test.ai.core.structure.cmp
base-packages: com.yomahub.liteflow.test.ai.core.structure.cmp
enable: true
openai:
api-key: mock-api-key # 测试代码不需要配置,将使用 mock 数据,不会调用 AI 服务接口

View File

@@ -1,8 +1,7 @@
liteflow:
rule-source: core/tool/flow.el.xml
ai:
base-packages:
- com.yomahub.liteflow.test.ai.core.tool.cmp
base-packages: com.yomahub.liteflow.test.ai.core.tool.cmp
enable: true
openai:
api-key: mock-api-key # 测试代码不需要配置,将使用 mock 数据,不会调用 AI 服务接口

View File

@@ -1,8 +1,7 @@
liteflow:
rule-source: workflow/coze/flow.el.xml
ai:
base-packages:
- com.yomahub.liteflow.test.ai.workflow.coze.cmp
base-packages: com.yomahub.liteflow.test.ai.workflow.coze.cmp
enable: true
workflow:
coze:

View File

@@ -1,8 +1,7 @@
liteflow:
rule-source: workflow/dashscope/flow.el.xml
ai:
base-packages:
- com.yomahub.liteflow.test.ai.workflow.dashscope.cmp
base-packages: com.yomahub.liteflow.test.ai.workflow.dashscope.cmp
enable: true
openai:
api-key: mock-api-key # 测试代码不需要配置,将使用 mock 数据,不会调用 AI 服务接口

View File

@@ -516,4 +516,3 @@
</profile>
</profiles>
</project>