diff --git a/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/annotation/AIClassify.java b/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/annotation/AIClassify.java index afd07627c..84bf83d19 100644 --- a/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/annotation/AIClassify.java +++ b/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/annotation/AIClassify.java @@ -1,7 +1,11 @@ package com.yomahub.liteflow.ai.annotation; -import com.yomahub.liteflow.ai.engine.model.chat.entity.ChatOptions; -import com.yomahub.liteflow.ai.engine.model.chat.entity.ChatRequest; +import com.yomahub.liteflow.ai.context.ChatContext; +import com.yomahub.liteflow.ai.engine.tool.registry.DelegatingToolRegistry; +import com.yomahub.liteflow.ai.engine.tool.registry.ScanningToolRegistry; +import com.yomahub.liteflow.ai.engine.tool.registry.StaticToolRegistry; +import com.yomahub.liteflow.ai.engine.tool.registry.ToolRegistry; +import com.yomahub.liteflow.ai.tool.SpringBeanToolRegistry; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; @@ -19,41 +23,6 @@ import java.lang.annotation.Target; @Target(ElementType.TYPE) public @interface AIClassify { - /** - * 从上下文中获取的请求参数的上下文路径表达式。 - *

- * 如果你不希望在注解中进行静态的模型配置,或者你希望使用特定厂商实现的 ChatRequest(其中可能存在一些独有的参数), - * 请使用这个属性,并在上下文中提供对应的 {@link ChatRequest} 值。 - * 如果不提供,框架将统一使用 {@link ChatRequest} 发起请求。 - *

- * {@link ChatRequest} 可以是对应提供商的具体实现类。 - *

- * 如果你使用了这个属性可以不进行 {@link AIChat#systemPrompt()} 和 {@link AIChat#userPrompt()} 和 {@link AIChat#streaming()} 的配置, - * 因为这些配置会从 {@link ChatRequest} 中获取。如果进行了配置,优先使用 {@link ChatRequest} 中的配置。 - *

- * 以及,你会发现 {@link ChatRequest#getOptions()} 的 {@link ChatOptions} 和 {@link AIComponent} 中的配置有重合。 - * 同样的,即使你进行了 {@link AIComponent} 的配置,会优先使用 {@link ChatRequest} 的配置。 - *

- * 请注意:如果相关的配置为空或默认值,则会使用 {@link AIComponent} 和 {@link AIChat} 中的配置!!! - *

- * 该方法用于从一个必须提供 {@code get} 方法的上下文中检索数据。 - *

- * 表达式支持以下两种形式: - *

- */ - String getChatRequest() default ""; - /** * 系统提示词 */ @@ -73,4 +42,22 @@ public @interface AIClassify { * 是否多标签分类,默认 false */ boolean multiLabel() default false; + + /** + * 需要启用的工具名列表(默认全部启用) + *

+ * 工具注册于 {@link ChatContext#getToolRegistry()},请于上下文中传入 + *

+ * 如果上下文中没有传入工具注册器,则会使用注册为 Spring Bean 的 {@link ToolRegistry} + * ,框架默认实现了 {@link SpringBeanToolRegistry}。 + * 可以将 Tool 注册为 Bean 实现自动发现与注册。 + *

+ * + * @see ToolRegistry + * @see StaticToolRegistry + * @see ScanningToolRegistry + * @see DelegatingToolRegistry + * @see SpringBeanToolRegistry + */ + String[] toolNames() default {}; } diff --git a/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/domain/dto/ParsedClassifyAnnotationConfig.java b/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/domain/dto/ParsedClassifyAnnotationConfig.java index 98494ad23..44f806369 100644 --- a/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/domain/dto/ParsedClassifyAnnotationConfig.java +++ b/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/domain/dto/ParsedClassifyAnnotationConfig.java @@ -1,9 +1,10 @@ package com.yomahub.liteflow.ai.domain.dto; +import java.util.ArrayList; import java.util.List; /** - * TODO + * AIClassify注解解析后配置 * * @author 苍镜月 * @since TODO @@ -15,6 +16,8 @@ public class ParsedClassifyAnnotationConfig extends ParsedAnnotationConfig { private boolean multiLabel; + private List toolNames = new ArrayList<>(); + public List getCategories() { return categories; } @@ -23,6 +26,10 @@ public class ParsedClassifyAnnotationConfig extends ParsedAnnotationConfig { return multiLabel; } + public List getToolNames() { + return toolNames; + } + public void setCategories(List categories) { this.categories = categories; } @@ -30,4 +37,8 @@ public class ParsedClassifyAnnotationConfig extends ParsedAnnotationConfig { public void setMultiLabel(boolean multiLabel) { this.multiLabel = multiLabel; } + + public void setToolNames(List toolNames) { + this.toolNames = toolNames; + } } diff --git a/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/parse/assemble/ClassifyRequestAssembler.java b/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/parse/assemble/ClassifyRequestAssembler.java index 0a11fd4bd..01e0d2a27 100644 --- a/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/parse/assemble/ClassifyRequestAssembler.java +++ b/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/parse/assemble/ClassifyRequestAssembler.java @@ -1,12 +1,31 @@ package com.yomahub.liteflow.ai.parse.assemble; import com.yomahub.liteflow.ai.context.ChatContext; +import com.yomahub.liteflow.ai.context.StreamHandler; import com.yomahub.liteflow.ai.domain.dto.ModelConfigAggregator; import com.yomahub.liteflow.ai.domain.dto.ParsedClassifyAnnotationConfig; +import com.yomahub.liteflow.ai.engine.interact.transport.TransportType; +import com.yomahub.liteflow.ai.engine.model.chat.entity.ChatOptions; import com.yomahub.liteflow.ai.engine.model.chat.entity.ChatRequest; +import com.yomahub.liteflow.ai.engine.model.chat.message.Message; +import com.yomahub.liteflow.ai.engine.model.chat.message.SystemMessage; +import com.yomahub.liteflow.ai.engine.model.chat.message.UserMessage; +import com.yomahub.liteflow.ai.engine.model.output.ResponseType; +import com.yomahub.liteflow.ai.engine.model.output.structure.TypeReference; +import com.yomahub.liteflow.ai.engine.tool.registry.StaticToolRegistry; +import com.yomahub.liteflow.ai.engine.tool.registry.ToolRegistry; +import com.yomahub.liteflow.ai.model.ModelFactory; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +import static com.yomahub.liteflow.ai.util.SetUtil.setIfPresent; /** - * TODO + * ChatRequest 组装器(意图识别) * * @author 苍镜月 * @since TODO @@ -14,12 +33,113 @@ import com.yomahub.liteflow.ai.engine.model.chat.entity.ChatRequest; public class ClassifyRequestAssembler extends AbstractRequestAssembler { + @SuppressWarnings("rawtypes") @Override protected ChatRequest doAssemble(ParsedClassifyAnnotationConfig annotationConfig, ModelConfigAggregator config, ChatContext context) { - // TODO + ChatRequest.Builder builder = ModelFactory.getChatRequestBuilder(config.getProvider()); + // 1. 连接 StreamHandler 回调 + StreamHandler streamHandler = context.getStreamHandler(); + if (Objects.nonNull(streamHandler)) { + LOG.info("Connecting StreamHandler to ChatRequest"); + builder.onStart(streamHandler::onStart) + .onClose(streamHandler::onClose) + .onError(streamHandler::onError) + .onText(streamHandler::onText) + .onThinking(streamHandler::onThinking) + .onToolsCalling(streamHandler::onToolsCalling) + .onUsage(streamHandler::onUsage) + .onGrounding(streamHandler::onGrounding) + .onCompletion(streamHandler::onCompletion) + .onFinal(streamHandler::onFinal); + } + + // 2. ChatOptions + ChatOptions.Builder optionsBuilder = ChatOptions.builder(); + setIfPresent(optionsBuilder::temperature, config.getTemperature()); + setIfPresent(optionsBuilder::topP, config.getTopP()); + setIfPresent(optionsBuilder::topK, config.getTopK()); + setIfPresent(optionsBuilder::maxTokens, config.getMaxTokens()); + setIfPresent(optionsBuilder::seed, config.getSeed()); + setIfPresent(optionsBuilder::enableThinking, config.getEnableThinking().toBool()); + builder.options(optionsBuilder.build()); + + + // 3. Message + List messages = new ArrayList<>(); + // 意图分类的系统消息 + messages.add(buildClassifyMessage(annotationConfig)); + setIfPresent(t -> messages.add(new SystemMessage(t)), annotationConfig.getSystemPrompt()); + setIfPresent(t -> messages.add(new UserMessage(t)), annotationConfig.getUserPrompt()); + + builder.messages(messages); + + // 4. streaming 相关参数 // 定死使用阻塞式传输 + builder.streaming(false); + builder.transportType(TransportType.HTTP); - return null; + // 4. 结构化输出 + // 如果开启了多意图分类,那么返回值就是 List,否则就是单一的 String + if (annotationConfig.isMultiLabel()) { + builder.targetType(new TypeReference>() { + }); + builder.responseType(ResponseType.JSON); + builder.strict(true); + } else { + builder.targetType(new TypeReference() { + }); + builder.responseType(ResponseType.TEXT); + builder.strict(false); + } + + // 5. 工具调用 + ToolRegistry toolRegistry = context.getToolRegistry(); + if (Objects.nonNull(toolRegistry)) { + StaticToolRegistry staticToolRegistry = new StaticToolRegistry(); + HashSet targetToolNames = new HashSet<>(annotationConfig.getToolNames()); + toolRegistry.getAllTools() + .stream() + .filter(tool -> targetToolNames.isEmpty() || targetToolNames.contains(tool.getName())) + .forEach(staticToolRegistry::register); + builder.toolRegistry(staticToolRegistry); + } + + return builder.build(); + } + + /** + * 构建意图分类的系统消息 + * + * @param annotationConfig 注解配置 + * @return 系统消息 + */ + private Message buildClassifyMessage(ParsedClassifyAnnotationConfig annotationConfig) { + StringBuilder sb = new StringBuilder(); + sb.append("You are an expert intent classifier.\n"); + sb.append("Your task is to analyze the user's query and classify it based on the predefined categories.\n\n"); + sb.append("Available categories are:\n"); + + String categoriesString = annotationConfig.getCategories().stream() + .map(c -> String.format("- %s", c)) + .collect(Collectors.joining("\n")); + sb.append(categoriesString); + sb.append("\n\n"); + + sb.append("Follow these rules strictly:\n"); + + if (annotationConfig.isMultiLabel()) { + sb.append("1. You may select one or more categories that are relevant to the user's query.\n"); + sb.append("2. Your response MUST be a valid JSON array of strings, containing only the names of the selected categories.\n"); + sb.append("3. For example: [\"category1\", \"category2\"]\n"); + } else { + sb.append("1. You must select only ONE category that best matches the user's query.\n"); + sb.append("2. Your response MUST be only the name of that single category.\n"); + sb.append("3. For example: category1\n"); + } + + sb.append("4. Do NOT provide any explanations, introductions, or any text other than the category name(s) in the specified format."); + + return new SystemMessage(sb.toString()); } } diff --git a/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/parse/context/ContextAccessor.java b/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/parse/context/ContextAccessor.java index fa3ab27f5..24fe6a894 100644 --- a/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/parse/context/ContextAccessor.java +++ b/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/parse/context/ContextAccessor.java @@ -59,19 +59,18 @@ public class ContextAccessor { if (StrUtil.isBlank(expression) || Objects.isNull(value)) return; // 检查结果是否为 Response 类型 - if (!(value instanceof Response)) { - throw new LiteFlowAIException("AI node output value must be of type Response."); - } - // 如果 request 是 ChatRequest 且 value 是 ChatResponse,则尝试进行结构化转换 - if (context.getModelRequest() instanceof ChatRequest && value instanceof ChatResponse) { - ChatRequest chatRequest = context.getModelRequest().toChatRequest(); - if (ResponseType.JSON.equals(chatRequest.getResponseType())) { - value = ((ChatResponse) value).as(chatRequest.getOutputParser()); + if (value instanceof Response) { + // 如果 request 是 ChatRequest 且 value 是 ChatResponse,则尝试进行结构化转换 + if (context.getModelRequest() instanceof ChatRequest && value instanceof ChatResponse) { + ChatRequest chatRequest = context.getModelRequest().toChatRequest(); + if (ResponseType.JSON.equals(chatRequest.getResponseType())) { + value = ((ChatResponse) value).as(chatRequest.getOutputParser()); + } else { + value = ((ChatResponse) value).getContent(); + } } else { - value = ((ChatResponse) value).getContent(); + value = ((Response) value).getContent(); } - } else { - value = ((Response) value).getContent(); } NodeComponent nodeComponent = context.getNodeComponent(); diff --git a/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/proxy/handler/AbstractAIComponentHandler.java b/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/proxy/handler/AbstractAIComponentHandler.java index 737524731..d9999d508 100644 --- a/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/proxy/handler/AbstractAIComponentHandler.java +++ b/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/proxy/handler/AbstractAIComponentHandler.java @@ -129,7 +129,7 @@ public abstract class AbstractAIComponentHandler { .subclass(nodeComponentClass) .name(generateProxyClassName(wrapBean)) .implement(wrapBean.getInterfaceClass()) - .method(getInterceptMethodName()) + .method(getInterceptMethodName(wrapBean)) .intercept(InvocationHandlerAdapter.of(getInvocationHandler(wrapBean))) .make() .load(this.getClass().getClassLoader(), ClassLoadingStrategy.Default.WRAPPER) @@ -174,7 +174,7 @@ public abstract class AbstractAIComponentHandler { * * @return 拦截方法名称 */ - protected abstract ElementMatcher getInterceptMethodName(); + protected abstract ElementMatcher getInterceptMethodName(AIProxyWrapBean wrapBean); /** * 判断是否支持指定的注解类型 diff --git a/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/proxy/handler/ChatComponentHandler.java b/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/proxy/handler/ChatComponentHandler.java index 249495101..5549e0ca0 100644 --- a/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/proxy/handler/ChatComponentHandler.java +++ b/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/proxy/handler/ChatComponentHandler.java @@ -45,7 +45,7 @@ public class ChatComponentHandler extends AbstractAIComponentHandler { } @Override - protected ElementMatcher getInterceptMethodName() { + protected ElementMatcher getInterceptMethodName(AIProxyWrapBean wrapBean) { return ElementMatchers.named(INTERCEPT_METHOD_NAME); } } \ No newline at end of file diff --git a/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/proxy/handler/ClassifyComponentHandler.java b/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/proxy/handler/ClassifyComponentHandler.java index 39fc1480c..7a72bdbad 100644 --- a/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/proxy/handler/ClassifyComponentHandler.java +++ b/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/proxy/handler/ClassifyComponentHandler.java @@ -21,7 +21,8 @@ import java.lang.reflect.InvocationHandler; */ public class ClassifyComponentHandler extends AbstractAIComponentHandler { - private static final String INTERCEPT_METHOD_NAME = "processSwitch"; + private static final String INTERCEPT_SWITCH_METHOD_NAME = "processSwitch"; + private static final String INTERCEPT_MULTI_SWITCH_METHOD_NAME = "processMultiSwitch"; @Override public AITypeEnum getAIType() { @@ -45,7 +46,11 @@ public class ClassifyComponentHandler extends AbstractAIComponentHandler getInterceptMethodName() { - return ElementMatchers.named(INTERCEPT_METHOD_NAME); + protected ElementMatcher getInterceptMethodName(AIProxyWrapBean wrapBean) { + if (wrapBean.getAnnotation().multiLabel()) { + return ElementMatchers.named(INTERCEPT_MULTI_SWITCH_METHOD_NAME); + } else { + return ElementMatchers.named(INTERCEPT_SWITCH_METHOD_NAME); + } } } \ No newline at end of file diff --git a/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/proxy/invocation/ClassifyAIInvocationHandler.java b/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/proxy/invocation/ClassifyAIInvocationHandler.java index 93e9ce88c..b485e4d8e 100644 --- a/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/proxy/invocation/ClassifyAIInvocationHandler.java +++ b/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/proxy/invocation/ClassifyAIInvocationHandler.java @@ -2,6 +2,7 @@ package com.yomahub.liteflow.ai.proxy.invocation; import com.yomahub.liteflow.ai.domain.dto.ParsedClassifyAnnotationConfig; import com.yomahub.liteflow.ai.engine.model.chat.ChatModel; +import com.yomahub.liteflow.ai.engine.model.chat.entity.ChatResponse; import com.yomahub.liteflow.ai.exception.LiteFlowAIException; import com.yomahub.liteflow.ai.model.ModelFactory; import com.yomahub.liteflow.ai.parse.context.ProcessorContext; @@ -30,18 +31,18 @@ public class ClassifyAIInvocationHandler extends AbstractAIInvocationHandler 1) { - throw new LiteFlowAIException("Multi-label classification is not allowed when multiLabel is false"); - } - if (annotationConfig.isMultiLabel() && annotationConfig.getCategories().size() < 2) { - throw new LiteFlowAIException("At least two categories are required for multi-label classification"); - } } @Override protected Object doExecuteAIProcess(ProcessorContext processorContext, Object[] args) { ChatModel chatModel = ModelFactory.getChatModel(wrapBean); - return chatModel.chat(processorContext.getModelRequest().toChatRequest()); + ChatResponse response = chatModel.chat(processorContext.getModelRequest().toChatRequest()); + ParsedClassifyAnnotationConfig annotationConfig = (ParsedClassifyAnnotationConfig) processorContext.getParsedAnnotationConfig(); + // 如果是多标签则返回结构化转换的list, 单标签返回 String + if (annotationConfig.isMultiLabel()) { + return response.as(processorContext.getModelRequest().toChatRequest().getOutputParser()); + } else { + return response.getContent().getContent(); + } } } diff --git a/liteflow-testcase-el/liteflow-testcase-el-ai/src/test/java/com/yomahub/liteflow/test/ai/core/proxy/ChatTest.java b/liteflow-testcase-el/liteflow-testcase-el-ai/src/test/java/com/yomahub/liteflow/test/ai/core/chat/ChatTest.java similarity index 62% rename from liteflow-testcase-el/liteflow-testcase-el-ai/src/test/java/com/yomahub/liteflow/test/ai/core/proxy/ChatTest.java rename to liteflow-testcase-el/liteflow-testcase-el-ai/src/test/java/com/yomahub/liteflow/test/ai/core/chat/ChatTest.java index 4ef553d39..6366b2970 100644 --- a/liteflow-testcase-el/liteflow-testcase-el-ai/src/test/java/com/yomahub/liteflow/test/ai/core/proxy/ChatTest.java +++ b/liteflow-testcase-el/liteflow-testcase-el-ai/src/test/java/com/yomahub/liteflow/test/ai/core/chat/ChatTest.java @@ -1,4 +1,4 @@ -package com.yomahub.liteflow.test.ai.core.proxy; +package com.yomahub.liteflow.test.ai.core.chat; import com.yomahub.liteflow.ai.context.ChatContext; import com.yomahub.liteflow.ai.context.StreamHandler; @@ -21,24 +21,17 @@ import javax.annotation.Resource; * @since TODO */ -@TestPropertySource(properties = {"spring.config.location=classpath:core/proxy/application.yaml"}) +@TestPropertySource(properties = {"spring.config.location=classpath:core/chat/application.yaml"}) @SpringBootTest(classes = {ChatTest.class, SpringUtil.class}) @EnableAutoConfiguration -@ComponentScan({"com.yomahub.liteflow.test.ai.core.proxy.cmp"}) +@ComponentScan({"com.yomahub.liteflow.test.ai.core.chat.cmp"}) public class ChatTest { @Resource private FlowExecutor flowExecutor; - @Test - public void testBlockingChat() { - LiteflowResponse liteflowResponse = flowExecutor.execute2Resp("chain1", null, ChatContext.class); - Assertions.assertTrue(liteflowResponse.isSuccess()); - } - - @Test - public void testStreaming() { - StreamHandler streamHandler = StreamHandler.builder() + private StreamHandler getStreamHandler() { + return StreamHandler.builder() .onStart(context -> System.out.println("chat start")) .onClose(context -> System.out.println("chat close")) .onError((context, t) -> { @@ -61,10 +54,45 @@ public class ChatTest { return response; }) .build(); + } - ChatContext chatContext = new ChatContext(streamHandler); + @Test + public void testDashScopeChat() { + LiteflowResponse liteflowResponse = flowExecutor.execute2Resp("chain1", null, ChatContext.class); + Assertions.assertTrue(liteflowResponse.isSuccess()); + } + @Test + public void testDashScopeStream() { + ChatContext chatContext = new ChatContext(getStreamHandler()); LiteflowResponse liteflowResponse = flowExecutor.execute2Resp("chain2", null, chatContext); Assertions.assertTrue(liteflowResponse.isSuccess()); } + + + @Test + public void testOllamaChat() { + LiteflowResponse liteflowResponse = flowExecutor.execute2Resp("chain3", null, ChatContext.class); + Assertions.assertTrue(liteflowResponse.isSuccess()); + } + + @Test + public void testOllamaStream() { + ChatContext chatContext = new ChatContext(getStreamHandler()); + LiteflowResponse liteflowResponse = flowExecutor.execute2Resp("chain4", null, chatContext); + Assertions.assertTrue(liteflowResponse.isSuccess()); + } + + @Test + public void testOpenAIChat() { + LiteflowResponse liteflowResponse = flowExecutor.execute2Resp("chain5", null, ChatContext.class); + Assertions.assertTrue(liteflowResponse.isSuccess()); + } + + @Test + public void testOpenAIStream() { + ChatContext chatContext = new ChatContext(getStreamHandler()); + LiteflowResponse liteflowResponse = flowExecutor.execute2Resp("chain6", null, chatContext); + Assertions.assertTrue(liteflowResponse.isSuccess()); + } } diff --git a/liteflow-testcase-el/liteflow-testcase-el-ai/src/test/java/com/yomahub/liteflow/test/ai/core/proxy/cmp/ACmp.java b/liteflow-testcase-el/liteflow-testcase-el-ai/src/test/java/com/yomahub/liteflow/test/ai/core/chat/cmp/ACmp.java similarity index 86% rename from liteflow-testcase-el/liteflow-testcase-el-ai/src/test/java/com/yomahub/liteflow/test/ai/core/proxy/cmp/ACmp.java rename to liteflow-testcase-el/liteflow-testcase-el-ai/src/test/java/com/yomahub/liteflow/test/ai/core/chat/cmp/ACmp.java index 4e7f4fdad..7f04724bd 100644 --- a/liteflow-testcase-el/liteflow-testcase-el-ai/src/test/java/com/yomahub/liteflow/test/ai/core/proxy/cmp/ACmp.java +++ b/liteflow-testcase-el/liteflow-testcase-el-ai/src/test/java/com/yomahub/liteflow/test/ai/core/chat/cmp/ACmp.java @@ -1,4 +1,4 @@ -package com.yomahub.liteflow.test.ai.core.proxy.cmp; +package com.yomahub.liteflow.test.ai.core.chat.cmp; import com.yomahub.liteflow.core.NodeComponent; import org.springframework.stereotype.Component; diff --git a/liteflow-testcase-el/liteflow-testcase-el-ai/src/test/java/com/yomahub/liteflow/test/ai/core/proxy/cmp/BCmp.java b/liteflow-testcase-el/liteflow-testcase-el-ai/src/test/java/com/yomahub/liteflow/test/ai/core/chat/cmp/BCmp.java similarity index 87% rename from liteflow-testcase-el/liteflow-testcase-el-ai/src/test/java/com/yomahub/liteflow/test/ai/core/proxy/cmp/BCmp.java rename to liteflow-testcase-el/liteflow-testcase-el-ai/src/test/java/com/yomahub/liteflow/test/ai/core/chat/cmp/BCmp.java index d0e51d08a..38f5348ab 100644 --- a/liteflow-testcase-el/liteflow-testcase-el-ai/src/test/java/com/yomahub/liteflow/test/ai/core/proxy/cmp/BCmp.java +++ b/liteflow-testcase-el/liteflow-testcase-el-ai/src/test/java/com/yomahub/liteflow/test/ai/core/chat/cmp/BCmp.java @@ -1,4 +1,4 @@ -package com.yomahub.liteflow.test.ai.core.proxy.cmp; +package com.yomahub.liteflow.test.ai.core.chat.cmp; import com.yomahub.liteflow.core.NodeComponent; import org.springframework.stereotype.Component; diff --git a/liteflow-testcase-el/liteflow-testcase-el-ai/src/test/java/com/yomahub/liteflow/test/ai/core/proxy/cmp/Output.java b/liteflow-testcase-el/liteflow-testcase-el-ai/src/test/java/com/yomahub/liteflow/test/ai/core/chat/cmp/Output.java similarity index 87% rename from liteflow-testcase-el/liteflow-testcase-el-ai/src/test/java/com/yomahub/liteflow/test/ai/core/proxy/cmp/Output.java rename to liteflow-testcase-el/liteflow-testcase-el-ai/src/test/java/com/yomahub/liteflow/test/ai/core/chat/cmp/Output.java index 05ea5bafb..38f9fed71 100644 --- a/liteflow-testcase-el/liteflow-testcase-el-ai/src/test/java/com/yomahub/liteflow/test/ai/core/proxy/cmp/Output.java +++ b/liteflow-testcase-el/liteflow-testcase-el-ai/src/test/java/com/yomahub/liteflow/test/ai/core/chat/cmp/Output.java @@ -1,4 +1,4 @@ -package com.yomahub.liteflow.test.ai.core.proxy.cmp; +package com.yomahub.liteflow.test.ai.core.chat.cmp; /** * 测试结构化输出使用 diff --git a/liteflow-testcase-el/liteflow-testcase-el-ai/src/test/java/com/yomahub/liteflow/test/ai/core/proxy/cmp/AIBlockingChatCmp.java b/liteflow-testcase-el/liteflow-testcase-el-ai/src/test/java/com/yomahub/liteflow/test/ai/core/chat/cmp/dashscope/DashScopeChatCmp.java similarity index 66% rename from liteflow-testcase-el/liteflow-testcase-el-ai/src/test/java/com/yomahub/liteflow/test/ai/core/proxy/cmp/AIBlockingChatCmp.java rename to liteflow-testcase-el/liteflow-testcase-el-ai/src/test/java/com/yomahub/liteflow/test/ai/core/chat/cmp/dashscope/DashScopeChatCmp.java index 9d10ecc78..be0606fdf 100644 --- a/liteflow-testcase-el/liteflow-testcase-el-ai/src/test/java/com/yomahub/liteflow/test/ai/core/proxy/cmp/AIBlockingChatCmp.java +++ b/liteflow-testcase-el/liteflow-testcase-el-ai/src/test/java/com/yomahub/liteflow/test/ai/core/chat/cmp/dashscope/DashScopeChatCmp.java @@ -1,4 +1,4 @@ -package com.yomahub.liteflow.test.ai.core.proxy.cmp; +package com.yomahub.liteflow.test.ai.core.chat.cmp.dashscope; import com.yomahub.liteflow.ai.annotation.*; import com.yomahub.liteflow.ai.engine.interact.transport.TransportType; @@ -13,20 +13,17 @@ import com.yomahub.liteflow.ai.util.TriState; */ @AIComponent( - nodeId = "aiBlockingChatCmpId", - nodeName = "aiBlockingChatCmpName", -// provider = "ollama", -// apiUrl = "http://localhost:11434", -// model = "qwen3:32b", + nodeId = "DashScopeChat", + nodeName = "DashScopeChat", provider = "dashscope", apiUrl = "https://dashscope.aliyuncs.com/compatible-mode/v1", - model = "deepseek-r1", + model = "qwen-flash", enableThinking = TriState.FALSE, readTimeout = "10m", connectTimeout = "10m" ) @AIChat( - systemPrompt = "classpath:core/proxy/system_prompt.txt", + systemPrompt = "classpath:core/chat/system_prompt.txt", userPrompt = "{{question}}", streaming = false, transportType = TransportType.HTTP @@ -38,10 +35,10 @@ import com.yomahub.liteflow.ai.util.TriState; ) @AIOutput( responseType = ResponseType.JSON, - typeName = "com.yomahub.liteflow.test.ai.core.proxy.cmp.Output", + typeName = "com.yomahub.liteflow.test.ai.core.chat.cmp.Output", methodExpress = "setData", useKeyIndex = true, key = "result" ) -public interface AIBlockingChatCmp { +public interface DashScopeChatCmp { } diff --git a/liteflow-testcase-el/liteflow-testcase-el-ai/src/test/java/com/yomahub/liteflow/test/ai/core/proxy/cmp/AIStreamingChatCmp.java b/liteflow-testcase-el/liteflow-testcase-el-ai/src/test/java/com/yomahub/liteflow/test/ai/core/chat/cmp/dashscope/DashScopeStreamCmp.java similarity index 64% rename from liteflow-testcase-el/liteflow-testcase-el-ai/src/test/java/com/yomahub/liteflow/test/ai/core/proxy/cmp/AIStreamingChatCmp.java rename to liteflow-testcase-el/liteflow-testcase-el-ai/src/test/java/com/yomahub/liteflow/test/ai/core/chat/cmp/dashscope/DashScopeStreamCmp.java index 88ab5485b..df56c9207 100644 --- a/liteflow-testcase-el/liteflow-testcase-el-ai/src/test/java/com/yomahub/liteflow/test/ai/core/proxy/cmp/AIStreamingChatCmp.java +++ b/liteflow-testcase-el/liteflow-testcase-el-ai/src/test/java/com/yomahub/liteflow/test/ai/core/chat/cmp/dashscope/DashScopeStreamCmp.java @@ -1,4 +1,4 @@ -package com.yomahub.liteflow.test.ai.core.proxy.cmp; +package com.yomahub.liteflow.test.ai.core.chat.cmp.dashscope; import com.yomahub.liteflow.ai.annotation.*; import com.yomahub.liteflow.ai.engine.interact.transport.TransportType; @@ -13,13 +13,8 @@ import com.yomahub.liteflow.ai.util.TriState; */ @AIComponent( - nodeId = "aiStreamingChatCmpId", - nodeName = "aiStreamingChatCmpName", -// provider = "ollama", -// apiUrl = "http://localhost:11434", -// model = "qwen3:32b", -// provider = "openai", -// apiUrl = "https://dashscope.aliyuncs.com/compatible-mode/v1", + nodeId = "DashScopeStream", + nodeName = "DashScopeStream", provider = "dashscope", apiUrl = "https://dashscope.aliyuncs.com/compatible-mode/v1", model = "deepseek-r1", @@ -28,7 +23,7 @@ import com.yomahub.liteflow.ai.util.TriState; connectTimeout = "10m" ) @AIChat( - systemPrompt = "classpath:core/proxy/system_prompt.txt", + systemPrompt = "classpath:core/chat/system_prompt.txt", userPrompt = "{{question}}", streaming = true, transportType = TransportType.SSE @@ -40,10 +35,10 @@ import com.yomahub.liteflow.ai.util.TriState; ) @AIOutput( responseType = ResponseType.TEXT, - typeName = "com.yomahub.liteflow.test.ai.core.proxy.cmp.Output", + typeName = "com.yomahub.liteflow.test.ai.core.chat.cmp.Output", methodExpress = "setData", useKeyIndex = true, key = "result" ) -public interface AIStreamingChatCmp { +public interface DashScopeStreamCmp { } diff --git a/liteflow-testcase-el/liteflow-testcase-el-ai/src/test/java/com/yomahub/liteflow/test/ai/core/chat/cmp/ollama/OllamaChatCmp.java b/liteflow-testcase-el/liteflow-testcase-el-ai/src/test/java/com/yomahub/liteflow/test/ai/core/chat/cmp/ollama/OllamaChatCmp.java new file mode 100644 index 000000000..5cd56a355 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-ai/src/test/java/com/yomahub/liteflow/test/ai/core/chat/cmp/ollama/OllamaChatCmp.java @@ -0,0 +1,44 @@ +package com.yomahub.liteflow.test.ai.core.chat.cmp.ollama; + +import com.yomahub.liteflow.ai.annotation.*; +import com.yomahub.liteflow.ai.engine.interact.transport.TransportType; +import com.yomahub.liteflow.ai.engine.model.output.ResponseType; +import com.yomahub.liteflow.ai.util.TriState; + +/** + * TODO + * + * @author 苍镜月 + * @since TODO + */ + +@AIComponent( + nodeId = "OllamaChat", + nodeName = "OllamaChat", + provider = "ollama", + apiUrl = "http://localhost:11434", + model = "qwen3:32b", + enableThinking = TriState.FALSE, + readTimeout = "10m", + connectTimeout = "10m" +) +@AIChat( + systemPrompt = "classpath:core/chat/system_prompt.txt", + userPrompt = "{{question}}", + streaming = false, + transportType = TransportType.HTTP +) +@AIInput( + mapping = { + @InputField(name = "question", expression = "test", defaultValue = "What is LiteFlow?"), + } +) +@AIOutput( + responseType = ResponseType.JSON, + typeName = "com.yomahub.liteflow.test.ai.core.chat.cmp.Output", + methodExpress = "setData", + useKeyIndex = true, + key = "result" +) +public interface OllamaChatCmp { +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-ai/src/test/java/com/yomahub/liteflow/test/ai/core/chat/cmp/ollama/OllamaStreamCmp.java b/liteflow-testcase-el/liteflow-testcase-el-ai/src/test/java/com/yomahub/liteflow/test/ai/core/chat/cmp/ollama/OllamaStreamCmp.java new file mode 100644 index 000000000..1d2df4ac6 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-ai/src/test/java/com/yomahub/liteflow/test/ai/core/chat/cmp/ollama/OllamaStreamCmp.java @@ -0,0 +1,44 @@ +package com.yomahub.liteflow.test.ai.core.chat.cmp.ollama; + +import com.yomahub.liteflow.ai.annotation.*; +import com.yomahub.liteflow.ai.engine.interact.transport.TransportType; +import com.yomahub.liteflow.ai.engine.model.output.ResponseType; +import com.yomahub.liteflow.ai.util.TriState; + +/** + * TODO + * + * @author 苍镜月 + * @since TODO + */ + +@AIComponent( + nodeId = "OllamaStream", + nodeName = "OllamaStream", + provider = "ollama", + apiUrl = "http://localhost:11434", + model = "qwen3:32b", + enableThinking = TriState.TRUE, + readTimeout = "10m", + connectTimeout = "10m" +) +@AIChat( + systemPrompt = "classpath:core/chat/system_prompt.txt", + userPrompt = "{{question}}", + streaming = true, + transportType = TransportType.DnJson +) +@AIInput( + mapping = { + @InputField(name = "question", expression = "test", defaultValue = "简短讲解什么是 LiteFlow?"), + } +) +@AIOutput( + responseType = ResponseType.TEXT, + typeName = "com.yomahub.liteflow.test.ai.core.chat.cmp.Output", + methodExpress = "setData", + useKeyIndex = true, + key = "result" +) +public interface OllamaStreamCmp { +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-ai/src/test/java/com/yomahub/liteflow/test/ai/core/chat/cmp/openai/OpenAIChatCmp.java b/liteflow-testcase-el/liteflow-testcase-el-ai/src/test/java/com/yomahub/liteflow/test/ai/core/chat/cmp/openai/OpenAIChatCmp.java new file mode 100644 index 000000000..46a24e702 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-ai/src/test/java/com/yomahub/liteflow/test/ai/core/chat/cmp/openai/OpenAIChatCmp.java @@ -0,0 +1,44 @@ +package com.yomahub.liteflow.test.ai.core.chat.cmp.openai; + +import com.yomahub.liteflow.ai.annotation.*; +import com.yomahub.liteflow.ai.engine.interact.transport.TransportType; +import com.yomahub.liteflow.ai.engine.model.output.ResponseType; +import com.yomahub.liteflow.ai.util.TriState; + +/** + * TODO + * + * @author 苍镜月 + * @since TODO + */ + +@AIComponent( + nodeId = "OpenAIChat", + nodeName = "OpenAIChat", + provider = "openai", + apiUrl = "https://ark.cn-beijing.volces.com/api/v3", + model = "doubao-seed-1-6-250615", + enableThinking = TriState.FALSE, + readTimeout = "10m", + connectTimeout = "10m" +) +@AIChat( + systemPrompt = "classpath:core/chat/system_prompt.txt", + userPrompt = "{{question}}", + streaming = false, + transportType = TransportType.HTTP +) +@AIInput( + mapping = { + @InputField(name = "question", expression = "test", defaultValue = "What is LiteFlow?"), + } +) +@AIOutput( + responseType = ResponseType.JSON, + typeName = "com.yomahub.liteflow.test.ai.core.chat.cmp.Output", + methodExpress = "setData", + useKeyIndex = true, + key = "result" +) +public interface OpenAIChatCmp { +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-ai/src/test/java/com/yomahub/liteflow/test/ai/core/chat/cmp/openai/OpenAIStreamCmp.java b/liteflow-testcase-el/liteflow-testcase-el-ai/src/test/java/com/yomahub/liteflow/test/ai/core/chat/cmp/openai/OpenAIStreamCmp.java new file mode 100644 index 000000000..04cc6f8db --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-ai/src/test/java/com/yomahub/liteflow/test/ai/core/chat/cmp/openai/OpenAIStreamCmp.java @@ -0,0 +1,44 @@ +package com.yomahub.liteflow.test.ai.core.chat.cmp.openai; + +import com.yomahub.liteflow.ai.annotation.*; +import com.yomahub.liteflow.ai.engine.interact.transport.TransportType; +import com.yomahub.liteflow.ai.engine.model.output.ResponseType; +import com.yomahub.liteflow.ai.util.TriState; + +/** + * TODO + * + * @author 苍镜月 + * @since TODO + */ + +@AIComponent( + nodeId = "OpenAIStream", + nodeName = "OpenAIStream", + provider = "openai", + apiUrl = "https://ark.cn-beijing.volces.com/api/v3", + model = "doubao-seed-1-6-250615", + enableThinking = TriState.TRUE, + readTimeout = "10m", + connectTimeout = "10m" +) +@AIChat( + systemPrompt = "classpath:core/chat/system_prompt.txt", + userPrompt = "{{question}}", + streaming = true, + transportType = TransportType.SSE +) +@AIInput( + mapping = { + @InputField(name = "question", expression = "test", defaultValue = "简短讲解什么是 LiteFlow?"), + } +) +@AIOutput( + responseType = ResponseType.TEXT, + typeName = "com.yomahub.liteflow.test.ai.core.chat.cmp.Output", + methodExpress = "setData", + useKeyIndex = true, + key = "result" +) +public interface OpenAIStreamCmp { +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-ai/src/test/java/com/yomahub/liteflow/test/ai/core/classify/ClassifyTest.java b/liteflow-testcase-el/liteflow-testcase-el-ai/src/test/java/com/yomahub/liteflow/test/ai/core/classify/ClassifyTest.java new file mode 100644 index 000000000..af42fdb54 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-ai/src/test/java/com/yomahub/liteflow/test/ai/core/classify/ClassifyTest.java @@ -0,0 +1,37 @@ +package com.yomahub.liteflow.test.ai.core.classify; + +import com.yomahub.liteflow.ai.context.ChatContext; +import com.yomahub.liteflow.ai.util.SpringUtil; +import com.yomahub.liteflow.core.FlowExecutor; +import com.yomahub.liteflow.flow.LiteflowResponse; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.test.context.TestPropertySource; + +import javax.annotation.Resource; + +/** + * TODO + * + * @author 苍镜月 + * @since TODO + */ + +@TestPropertySource(properties = {"spring.config.location=classpath:core/classify/application.yaml"}) +@SpringBootTest(classes = {ClassifyTest.class, SpringUtil.class}) +@EnableAutoConfiguration +@ComponentScan({"com.yomahub.liteflow.test.ai.core.classify.cmp"}) +public class ClassifyTest { + + @Resource + private FlowExecutor flowExecutor; + + @Test + public void testClassify() { + LiteflowResponse response = flowExecutor.execute2Resp("chain1", null, ChatContext.class); + Assertions.assertTrue(response.isSuccess()); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-ai/src/test/java/com/yomahub/liteflow/test/ai/core/classify/cmp/ACmp.java b/liteflow-testcase-el/liteflow-testcase-el-ai/src/test/java/com/yomahub/liteflow/test/ai/core/classify/cmp/ACmp.java new file mode 100644 index 000000000..1bdb1506f --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-ai/src/test/java/com/yomahub/liteflow/test/ai/core/classify/cmp/ACmp.java @@ -0,0 +1,20 @@ +package com.yomahub.liteflow.test.ai.core.classify.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.springframework.stereotype.Component; + +/** + * TODO + * + * @author 苍镜月 + * @since TODO + */ + +@Component("a") +public class ACmp extends NodeComponent { + + @Override + public void process() throws Exception { + System.out.println("ACmp executed!"); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-ai/src/test/java/com/yomahub/liteflow/test/ai/core/classify/cmp/AIClassifyCmp.java b/liteflow-testcase-el/liteflow-testcase-el-ai/src/test/java/com/yomahub/liteflow/test/ai/core/classify/cmp/AIClassifyCmp.java new file mode 100644 index 000000000..bc17d996c --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-ai/src/test/java/com/yomahub/liteflow/test/ai/core/classify/cmp/AIClassifyCmp.java @@ -0,0 +1,41 @@ +package com.yomahub.liteflow.test.ai.core.classify.cmp; + +import com.yomahub.liteflow.ai.annotation.*; +import com.yomahub.liteflow.ai.util.TriState; + +/** + * TODO + * + * @author 苍镜月 + * @since TODO + */ + +@AIComponent( + nodeId = "ai", + nodeName = "ai", +// provider = "ollama", +// apiUrl = "http://localhost:11434", +// model = "qwen3:32b", + provider = "openai", + apiUrl = "https://ark.cn-beijing.volces.com/api/v3", + model = "doubao-seed-1-6-250615", + enableThinking = TriState.FALSE, + readTimeout = "10m", + connectTimeout = "10m" +) +@AIClassify( + systemPrompt = "你是一个意图识别高手,你需要识别用户的意图", + userPrompt = "{{question}}", + categories = {"java", "python"}) +@AIInput( + mapping = { + @InputField(name = "question", expression = "test", defaultValue = "请帮我写一段Java代码"), + } +) +@AIOutput( + methodExpress = "setData", + useKeyIndex = true, + key = "result" +) +public interface AIClassifyCmp { +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-ai/src/test/java/com/yomahub/liteflow/test/ai/core/classify/cmp/JavaCmp.java b/liteflow-testcase-el/liteflow-testcase-el-ai/src/test/java/com/yomahub/liteflow/test/ai/core/classify/cmp/JavaCmp.java new file mode 100644 index 000000000..b5aa0521f --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-ai/src/test/java/com/yomahub/liteflow/test/ai/core/classify/cmp/JavaCmp.java @@ -0,0 +1,20 @@ +package com.yomahub.liteflow.test.ai.core.classify.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.springframework.stereotype.Component; + +/** + * TODO + * + * @author 苍镜月 + * @since TODO + */ + +@Component("java") +public class JavaCmp extends NodeComponent { + + @Override + public void process() throws Exception { + System.out.println("Java component executed."); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-ai/src/test/java/com/yomahub/liteflow/test/ai/core/classify/cmp/PythonCmp.java b/liteflow-testcase-el/liteflow-testcase-el-ai/src/test/java/com/yomahub/liteflow/test/ai/core/classify/cmp/PythonCmp.java new file mode 100644 index 000000000..6972057dc --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-ai/src/test/java/com/yomahub/liteflow/test/ai/core/classify/cmp/PythonCmp.java @@ -0,0 +1,20 @@ +package com.yomahub.liteflow.test.ai.core.classify.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.springframework.stereotype.Component; + +/** + * TODO + * + * @author 苍镜月 + * @since TODO + */ + +@Component("python") +public class PythonCmp extends NodeComponent { + + @Override + public void process() throws Exception { + System.out.println("Python component executed."); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-ai/src/test/java/com/yomahub/liteflow/test/ai/core/proxy/TmpTest.java b/liteflow-testcase-el/liteflow-testcase-el-ai/src/test/java/com/yomahub/liteflow/test/ai/core/proxy/TmpTest.java deleted file mode 100644 index 904c2ea8c..000000000 --- a/liteflow-testcase-el/liteflow-testcase-el-ai/src/test/java/com/yomahub/liteflow/test/ai/core/proxy/TmpTest.java +++ /dev/null @@ -1,58 +0,0 @@ -package com.yomahub.liteflow.test.ai.core.proxy; - -/** - * TODO - * - * @author 苍镜月 - * @since TODO - */ - -public class TmpTest { -// -// @Test -// public void test1() { -// Provider provider = new Provider() { -// @Override -// public Optional getString() { -// return Optional.empty(); -// } -// -// @Override -// public Optional getDouble() { -// return Optional.empty(); -// } -// }; -// -// System.out.println(provider.getDouble().orElseThrow(() -> new RuntimeException("No value present"))); -// -// } -// -// -// static interface Provider { -// Optional getString(); -// -// Optional getDouble(); -// } -// -// -// -// @Test -// public void testProxyFactoryBean() throws Exception { -//// AIComponentProxyFactoryBean factoryBean = new AIComponentProxyFactoryBean<>(cmp.class); -//// -//// System.out.println(cmp.class.getAnnotations()); -//// Class interfaceClass = factoryBean.getInterfaceClass(); -//// Class objectType = factoryBean.getObjectType(); -//// -//// System.out.println(interfaceClass); -//// System.out.println(Arrays.toString(interfaceClass.getAnnotations())); -//// -//// System.out.println(objectType); -//// System.out.println(Arrays.toString(objectType.getAnnotations())); -// } -// -// @AIComponent -// @AIChat -// @AIInput -// public interface cmp {} -} diff --git a/liteflow-testcase-el/liteflow-testcase-el-ai/src/test/java/com/yomahub/liteflow/test/ai/core/tool/cmp/AIBlockingChatCmp.java b/liteflow-testcase-el/liteflow-testcase-el-ai/src/test/java/com/yomahub/liteflow/test/ai/core/tool/cmp/AIBlockingChatCmp.java index fa910ef54..c49148952 100644 --- a/liteflow-testcase-el/liteflow-testcase-el-ai/src/test/java/com/yomahub/liteflow/test/ai/core/tool/cmp/AIBlockingChatCmp.java +++ b/liteflow-testcase-el/liteflow-testcase-el-ai/src/test/java/com/yomahub/liteflow/test/ai/core/tool/cmp/AIBlockingChatCmp.java @@ -20,9 +20,12 @@ import com.yomahub.liteflow.ai.util.TriState; // provider = "ollama", // apiUrl = "http://localhost:11434", // model = "qwen3:32b", - provider = "dashscope", - apiUrl = "https://dashscope.aliyuncs.com/compatible-mode/v1", - model = "deepseek-r1", +// provider = "dashscope", +// apiUrl = "https://dashscope.aliyuncs.com/compatible-mode/v1", +// model = "deepseek-r1", + provider = "openai", + apiUrl = "https://ark.cn-beijing.volces.com/api/v3", + model = "doubao-seed-1-6-250615", enableThinking = TriState.FALSE, readTimeout = "10m", connectTimeout = "10m" diff --git a/liteflow-testcase-el/liteflow-testcase-el-ai/src/test/resources/core/chat/application.yaml b/liteflow-testcase-el/liteflow-testcase-el-ai/src/test/resources/core/chat/application.yaml new file mode 100644 index 000000000..7648bd5a5 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-ai/src/test/resources/core/chat/application.yaml @@ -0,0 +1,10 @@ +liteflow: + rule-source: core/chat/flow.el.xml + ai: + base-packages: + - com.yomahub.liteflow.test.ai.core.chat.cmp + enable: true + openai: + api-key: + dashscope: + api-key: \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-ai/src/test/resources/core/chat/flow.el.xml b/liteflow-testcase-el/liteflow-testcase-el-ai/src/test/resources/core/chat/flow.el.xml new file mode 100644 index 000000000..47dc71af1 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-ai/src/test/resources/core/chat/flow.el.xml @@ -0,0 +1,27 @@ + + + + + THEN(a, DashScopeChat, b); + + + + THEN(a, DashScopeStream); + + + + THEN(a, OllamaChat, b); + + + + THEN(a, OllamaStream); + + + + THEN(a, OpenAIChat, b); + + + + THEN(a, OpenAIStream); + + diff --git a/liteflow-testcase-el/liteflow-testcase-el-ai/src/test/resources/core/proxy/system_prompt.txt b/liteflow-testcase-el/liteflow-testcase-el-ai/src/test/resources/core/chat/system_prompt.txt similarity index 100% rename from liteflow-testcase-el/liteflow-testcase-el-ai/src/test/resources/core/proxy/system_prompt.txt rename to liteflow-testcase-el/liteflow-testcase-el-ai/src/test/resources/core/chat/system_prompt.txt diff --git a/liteflow-testcase-el/liteflow-testcase-el-ai/src/test/resources/core/classify/application.yaml b/liteflow-testcase-el/liteflow-testcase-el-ai/src/test/resources/core/classify/application.yaml new file mode 100644 index 000000000..22e33e9b8 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-ai/src/test/resources/core/classify/application.yaml @@ -0,0 +1,10 @@ +liteflow: + rule-source: core/classify/flow.el.xml + ai: + base-packages: + - com.yomahub.liteflow.test.ai.core.classify.cmp + enable: true + openai: + api-key: + dashscope: + api-key: \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-ai/src/test/resources/core/proxy/flow.el.xml b/liteflow-testcase-el/liteflow-testcase-el-ai/src/test/resources/core/classify/flow.el.xml similarity index 54% rename from liteflow-testcase-el/liteflow-testcase-el-ai/src/test/resources/core/proxy/flow.el.xml rename to liteflow-testcase-el/liteflow-testcase-el-ai/src/test/resources/core/classify/flow.el.xml index 3aa3d6e6a..b5e3ef41a 100644 --- a/liteflow-testcase-el/liteflow-testcase-el-ai/src/test/resources/core/proxy/flow.el.xml +++ b/liteflow-testcase-el/liteflow-testcase-el-ai/src/test/resources/core/classify/flow.el.xml @@ -2,10 +2,6 @@ - THEN(a, aiBlockingChatCmpId, b); - - - - THEN(a, aiStreamingChatCmpId); + THEN(a, SWITCH(ai).TO(java, python)); diff --git a/liteflow-testcase-el/liteflow-testcase-el-ai/src/test/resources/core/proxy/application.yaml b/liteflow-testcase-el/liteflow-testcase-el-ai/src/test/resources/core/proxy/application.yaml deleted file mode 100644 index acab13888..000000000 --- a/liteflow-testcase-el/liteflow-testcase-el-ai/src/test/resources/core/proxy/application.yaml +++ /dev/null @@ -1,6 +0,0 @@ -liteflow: - rule-source: core/proxy/flow.el.xml - ai: - base-packages: - - com.yomahub.liteflow.test.ai.core.proxy.cmp - enable: true \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-ai/src/test/resources/core/tool/application.yaml b/liteflow-testcase-el/liteflow-testcase-el-ai/src/test/resources/core/tool/application.yaml index ee85c9f1a..387de1fb7 100644 --- a/liteflow-testcase-el/liteflow-testcase-el-ai/src/test/resources/core/tool/application.yaml +++ b/liteflow-testcase-el/liteflow-testcase-el-ai/src/test/resources/core/tool/application.yaml @@ -3,4 +3,8 @@ liteflow: ai: base-packages: - com.yomahub.liteflow.test.ai.core.tool.cmp - enable: true \ No newline at end of file + enable: true + openai: + api-key: + dashscope: + api-key: