diff --git a/README.md b/README.md index a1050f1962438683ed4edbc57962159567ac075f..b4e1062442f7de14fddcab02d0f30f8d6a335bf1 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,7 @@ Viewer 是一款基于SpringBoot构建的API敏捷开发平台,突破传统编 - **任意数据库**:默认支持MySQL可通过自定义驱动,通过界面自行扩展,支持所有JDBC连接的数据库 - **多种方式查询**:通过自定义http请求和自定义连接器,实现对第三方系统的集成 - **多数据源**:通过多数据源,支持在一次请求中可跨数据源,跨系统查询 +- **AI辅助**:通过FunctionCall,轻松实现AI与业务数据的结合 - **高性能**:基于SpringBoot的轻量级架构 - **实时生效**:支持动态创建、修改API;动态创建、修改数据源。热部署全程无感。 @@ -105,6 +106,16 @@ kill 进程号 ![mcp server端点截图](images/mcpserver.png) #### mcp server验证 ![mcp server验证截图](images/mcpservershow.png) +### AI 相关 +#### AI端点 +![AI端点截图](images/AiNode.png) +#### 模型设置 +![模型设置截图](images/ModelParam.png) +#### Function Call 逻辑块 +![FunctionCallBlock截图](images/FunctionCallBlock.png) +#### 运行结果 +![FunctionCallResult截图](images/FunctionCallResult.png) + ## ⚙️ 生产环境配置 ### 创建 `application.yml` 文件: @@ -129,10 +140,10 @@ java -jar viewer-apis-client.jar --spring.config.location=application.yml ## 功能规划 1. ✔️MCP SERVER (v1.2.0) -2. ⏳Function Call (目标版本 V1.3.0) -3. ⏳加入AI数据源(deepseek,openai) (目标版本 V1.3.0) -4. MCP CLIENT (计划版本 V1.4.0>> -5. 补充支持mybatis 注解 +2. ✔️Function Call (目标版本 V1.3.0) +3. ✔️加入AI数据源(deepseek,openai,zhipu) (目标版本 V1.3.0) +4. ⏳MCP CLIENT (计划版本 V1.4.0) +5. 补充支持mybatis \ 注解 6. 加入查询缓存 7. 执行算子(lua,js脚本) 8. 支持MCP协议全部功能 @@ -140,8 +151,9 @@ java -jar viewer-apis-client.jar --spring.config.location=application.yml 10. 定时任务 11. 接口认证 12. 优化导出 -13. 结合jdk25+springboot4优化 <> +13. 结合jdk25+springboot4优化 \ 14. spring native +15. AI Agent能力 ## 🤝 参与贡献 diff --git a/ai/viewer-ai-mcp-server/src/main/java/xyz/thoughtset/viewer/ai/mcp/server/MCPServerAutoConfiguration.java b/ai/viewer-ai-mcp-server/src/main/java/xyz/thoughtset/viewer/ai/mcp/server/MCPServerAutoConfiguration.java index e19c76041f30cf9fda0aeda70198f38712cb8c8e..7911288dbf75d94b79377ee3e119150c0d75e888 100644 --- a/ai/viewer-ai-mcp-server/src/main/java/xyz/thoughtset/viewer/ai/mcp/server/MCPServerAutoConfiguration.java +++ b/ai/viewer-ai-mcp-server/src/main/java/xyz/thoughtset/viewer/ai/mcp/server/MCPServerAutoConfiguration.java @@ -8,6 +8,6 @@ import org.springframework.context.annotation.Configuration; @Configuration @ComponentScan @EnableConfigurationProperties -@MapperScan(basePackages = "xyz.thoughtset.viewer.ai.mcp.server") +//@MapperScan(basePackages = "xyz.thoughtset.viewer.ai.mcp.server") public class MCPServerAutoConfiguration { } diff --git a/ai/viewer-ai-mcp-server/src/main/java/xyz/thoughtset/viewer/ai/mcp/server/config/WebMvcSseMcpSyncServerAutoConfiguration.java b/ai/viewer-ai-mcp-server/src/main/java/xyz/thoughtset/viewer/ai/mcp/server/config/WebMvcSseMcpSyncServerAutoConfiguration.java deleted file mode 100644 index 2429cc37d692e6b095aa591e9038c5eec15d1e55..0000000000000000000000000000000000000000 --- a/ai/viewer-ai-mcp-server/src/main/java/xyz/thoughtset/viewer/ai/mcp/server/config/WebMvcSseMcpSyncServerAutoConfiguration.java +++ /dev/null @@ -1,152 +0,0 @@ -package xyz.thoughtset.viewer.ai.mcp.server.config; - -import com.fasterxml.jackson.databind.ObjectMapper; -import io.modelcontextprotocol.server.McpServer; -import io.modelcontextprotocol.server.McpServerFeatures; -import io.modelcontextprotocol.server.McpSyncServer; -import io.modelcontextprotocol.server.McpSyncServerExchange; -import io.modelcontextprotocol.server.transport.WebMvcSseServerTransportProvider; -import io.modelcontextprotocol.spec.McpSchema; -import lombok.extern.slf4j.Slf4j; -import org.springframework.ai.mcp.McpToolUtils; -//import org.springframework.ai.mcp.server.autoconfigure.McpServerAutoConfiguration; -import org.springframework.ai.support.ToolCallbacks; -import org.springframework.beans.factory.ObjectProvider; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.web.servlet.function.RouterFunction; -import org.springframework.web.servlet.function.ServerResponse; -import xyz.thoughtset.viewer.ai.mcp.server.BlockToolCallbackProvider; - -import java.util.List; -import java.util.function.BiConsumer; - -@Deprecated -@Slf4j -//@Configuration -public class WebMvcSseMcpSyncServerAutoConfiguration { -// @Autowired - private ObjectMapper objectMapper; -// @Autowired - private BlockToolCallbackProvider blockToolCallbackProvider; - - @Bean - @ConditionalOnMissingBean - public WebMvcSseServerTransportProvider webMvcSseServerTransportProvider() { - return new WebMvcSseServerTransportProvider(objectMapper, "/mcp/messages2"); -// return WebMvcSseServerTransportProvider.MESSAGE_EVENT_TYPE -// .objectMapper(objectMapper) -// .messageEndpoint(serverProperties.getSseMessageEndpoint()) -// .build(); -// HttpServletSseServerTransportProvider - } - -// @Bean -// public RouterFunction mvcMcpRouterFunction(WebMvcSseServerTransportProvider transportProvider) { -// return transportProvider.getRouterFunction(); -// } - -// McpServerAutoConfiguration - @Bean - public McpSyncServer funMcpSyncServer(WebMvcSseServerTransportProvider transportProvider, - ObjectProvider> tools, - ObjectProvider> resources, - ObjectProvider> prompts, - ObjectProvider> completions, - ObjectProvider>> rootsChangeConsumers) { - -// McpSchema.ServerCapabilities.Builder capabilitiesBuilder = McpSchema.ServerCapabilities.builder(); -// McpServerProperties serverProperties = new McpServerProperties(); -// McpSchema.Implementation serverInfo = new McpSchema.Implementation("mcp-server","1.0.0"); -// -// McpServer.SyncSpecification serverBuilder = McpServer.sync(transportProvider).serverInfo(serverInfo); -// -// // Tools -// if (serverProperties.getCapabilities().isTool()) { -// capabilitiesBuilder.tools(serverProperties.isToolChangeNotification()); -// -// List toolSpecifications = new ArrayList<>( -// tools.stream().flatMap(List::stream).toList()); -// -// if (!CollectionUtils.isEmpty(toolSpecifications)) { -// serverBuilder.tools(toolSpecifications); -// log.info("Registered tools: " + toolSpecifications.size()); -// } -// } -// -// // Resources -// if (serverProperties.getCapabilities().isResource()) { -// log.info("Enable resources capabilities, notification: " -// + serverProperties.isResourceChangeNotification()); -// capabilitiesBuilder.resources(false, serverProperties.isResourceChangeNotification()); -// -// List resourceSpecifications = resources.stream().flatMap(List::stream).toList(); -// if (!CollectionUtils.isEmpty(resourceSpecifications)) { -// serverBuilder.resources(resourceSpecifications); -// log.info("Registered resources: " + resourceSpecifications.size()); -// } -// } -// // Prompts -// if (serverProperties.getCapabilities().isPrompt()) { -// log.info("Enable prompts capabilities, notification: " -// + serverProperties.isPromptChangeNotification()); -// capabilitiesBuilder.prompts(serverProperties.isPromptChangeNotification()); -// -// List promptSpecifications = prompts.stream().flatMap(List::stream).toList(); -// if (!CollectionUtils.isEmpty(promptSpecifications)) { -// serverBuilder.prompts(promptSpecifications); -// log.info("Registered prompts: " + promptSpecifications.size()); -// } -// } -// -// // Completions -// if (serverProperties.getCapabilities().isCompletion()) { -// log.info("Enable completions capabilities"); -// capabilitiesBuilder.completions(); -// -// List completionSpecifications = completions.stream() -// .flatMap(List::stream) -// .toList(); -// if (!CollectionUtils.isEmpty(completionSpecifications)) { -// serverBuilder.completions(completionSpecifications); -// log.info("Registered completions: " + completionSpecifications.size()); -// } -// } -// -// rootsChangeConsumers.ifAvailable(consumer -> { -// BiConsumer> syncConsumer = (exchange, roots) -> consumer -// .accept(exchange, roots); -// serverBuilder.rootsChangeHandler(syncConsumer); -// log.info("Registered roots change consumer"); -// }); -// -// serverBuilder.capabilities(capabilitiesBuilder.build()); -// -// serverBuilder.instructions(serverProperties.getInstructions()); -// -// serverBuilder.requestTimeout(serverProperties.getRequestTimeout()); -// if (environment instanceof StandardServletEnvironment) { -// serverBuilder.immediateExecution(true); -// } - - //临时 - var capabilities = McpSchema.ServerCapabilities.builder() - .tools(true) // Tool support with list changes notifications - .logging() // Logging support - .build(); -// MethodToolCallbackProvider toolCallbackProvider = MethodToolCallbackProvider.builder() -// .toolObjects(new WeatherApiClient()) -// .build(); - // Create the server with both tool and resource capabilities - McpServer.SyncSpecification serverBuilder = McpServer.sync(transportProvider) - .serverInfo("MCP Demo Weather Server", "1.0.0") - .capabilities(capabilities) - .tools(McpToolUtils.toSyncToolSpecifications( - blockToolCallbackProvider.getToolCallbacks() - )); - return serverBuilder.build(); - } - -} diff --git a/ai/viewer-ai-mcp-server/src/main/java/xyz/thoughtset/viewer/ai/mcp/server/factory/McpServerFactory.java b/ai/viewer-ai-mcp-server/src/main/java/xyz/thoughtset/viewer/ai/mcp/server/factory/McpServerFactory.java index deb3ff3dc29463bec273384510927ef6bb7bacbc..957df8822b34f8ceb8b23cbdd05c1c733234e7e0 100644 --- a/ai/viewer-ai-mcp-server/src/main/java/xyz/thoughtset/viewer/ai/mcp/server/factory/McpServerFactory.java +++ b/ai/viewer-ai-mcp-server/src/main/java/xyz/thoughtset/viewer/ai/mcp/server/factory/McpServerFactory.java @@ -11,7 +11,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; -import xyz.thoughtset.viewer.ai.mcp.server.BlockToolCallbackProvider; +import xyz.thoughtset.viewer.executor.blocks.tool.BlockToolCallbackProvider; import xyz.thoughtset.viewer.ai.mcp.server.config.DynamicRouterRegistry; import xyz.thoughtset.viewer.ai.mcp.server.entity.McpServerInfo; import xyz.thoughtset.viewer.ai.mcp.server.exception.UrlConflictException; diff --git a/apis/viewer-apis-client/src/main/java/xyz/thoughtset/viewer/apis/client/controller/McpServerController.java b/apis/viewer-apis-client/src/main/java/xyz/thoughtset/viewer/apis/client/controller/AiSupportController.java similarity index 61% rename from apis/viewer-apis-client/src/main/java/xyz/thoughtset/viewer/apis/client/controller/McpServerController.java rename to apis/viewer-apis-client/src/main/java/xyz/thoughtset/viewer/apis/client/controller/AiSupportController.java index 3d0bd5ad4ef7b17d31039ec2569bcf0b26fa0764..462e6c37d0802ba67318b8082876aa8bd67a71eb 100644 --- a/apis/viewer-apis-client/src/main/java/xyz/thoughtset/viewer/apis/client/controller/McpServerController.java +++ b/apis/viewer-apis-client/src/main/java/xyz/thoughtset/viewer/apis/client/controller/AiSupportController.java @@ -6,12 +6,16 @@ import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; +import xyz.thoughtset.viewer.common.ai.model.factory.ModelsRegistry; import xyz.thoughtset.viewer.common.api.controller.BaseController; +import xyz.thoughtset.viewer.common.core.util.ExtractConstantFieldUtil; import xyz.thoughtset.viewer.modules.mcp.server.service.McpServerInfoService; +import java.util.Collection; + @RestController @RequestMapping -public class McpServerController extends BaseController { +public class AiSupportController extends BaseController { @Autowired private McpServerInfoService mcpServerInfoService; @@ -24,5 +28,13 @@ public class McpServerController extends BaseController { public void unpublishedApi(@RequestParam String apiId){ mcpServerInfoService.unpublishedServer(apiId); } + @GetMapping(value = "/supportProvider") + public Object supportProvider(){ + return ModelsRegistry.supportProvider(); + } + @GetMapping(value = "/modelPurposes") + public Object modelPurposes(){ + return ExtractConstantFieldUtil.extractEnumToList(xyz.thoughtset.viewer.common.ai.model.entity.purpose.ModelPurposeEnum.class); + } } diff --git a/apis/viewer-apis-client/src/main/resources/db/schema.sql b/apis/viewer-apis-client/src/main/resources/db/schema.sql index 82c8a8820d2368fa24ea15370b13e617beb8cc41..ad756cd2991e9570c4e2ed36bc2c694e9f526835 100644 --- a/apis/viewer-apis-client/src/main/resources/db/schema.sql +++ b/apis/viewer-apis-client/src/main/resources/db/schema.sql @@ -1,3 +1,20 @@ +CREATE TABLE IF NOT EXISTS ainode ( + id varchar(32) NOT NULL, + title varchar(32) DEFAULT NULL, + pid varchar(32) DEFAULT NULL, + groupId varchar(32) DEFAULT NULL, + remark text, + orderNum int(11) DEFAULT NULL, + createdAt datetime NOT NULL, + updatedAt datetime NOT NULL, + statesCode int(11) DEFAULT '200', + provider varchar(256) NOT NULL, + baseUrl varchar(256) NOT NULL, + apiKey varchar(256) NOT NULL, + headersStr text, + settingStr text, + PRIMARY KEY (id) +); CREATE TABLE IF NOT EXISTS ApiInfo ( id varchar(32) NOT NULL, @@ -38,48 +55,48 @@ CREATE TABLE IF NOT EXISTS ApiParam( -- -- CREATE INDEX IF NOT EXISTS idx_pid ON ApiParam (pid); -- CREATE INDEX IF NOT EXISTS idx_order_up ON ApiParam (orderNum ASC, updatedAt DESC); -CREATE TABLE IF NOT EXISTS `blockbodyele` ( - `id` varchar(32) NOT NULL, - `title` varchar(32) DEFAULT NULL, - `pid` varchar(32) DEFAULT NULL, - `groupId` varchar(32) DEFAULT NULL, - `remark` text, - `orderNum` int(11) DEFAULT '0', - `createdAt` datetime NOT NULL, - `updatedAt` datetime NOT NULL, - `statesCode` int(11) DEFAULT '200', - `paramsPayload` text, - `type` varchar(32) DEFAULT NULL, - `eleId` varchar(32) DEFAULT NULL, - `valnum` varchar(8) DEFAULT '', - PRIMARY KEY (`id`) +CREATE TABLE IF NOT EXISTS blockbodyele ( + id varchar(32) NOT NULL, + title varchar(32) DEFAULT NULL, + pid varchar(32) DEFAULT NULL, + groupId varchar(32) DEFAULT NULL, + remark text, + orderNum int(11) DEFAULT '0', + createdAt datetime NOT NULL, + updatedAt datetime NOT NULL, + statesCode int(11) DEFAULT '200', + paramsPayload text, + type varchar(32) DEFAULT NULL, + eleId varchar(32) DEFAULT NULL, + valnum varchar(8) DEFAULT '', + PRIMARY KEY (id) ); -CREATE TABLE IF NOT EXISTS `blockinfo` ( - `id` varchar(32) NOT NULL, - `title` varchar(32) DEFAULT NULL, - `pid` varchar(32) DEFAULT NULL, - `groupId` varchar(32) DEFAULT NULL, - `remark` text, - `orderNum` int(11) DEFAULT '0', - `createdAt` datetime NOT NULL, - `updatedAt` datetime NOT NULL, - `statesCode` int(11) DEFAULT '200', - `dataStr` text, - `single` bit(1) DEFAULT NULL, - `cacheId` varchar(32) DEFAULT NULL, - `bodyType` varchar(32) DEFAULT NULL, - PRIMARY KEY (`id`) +CREATE TABLE IF NOT EXISTS blockinfo ( + id varchar(32) NOT NULL, + title varchar(32) DEFAULT NULL, + pid varchar(32) DEFAULT NULL, + groupId varchar(32) DEFAULT NULL, + remark text, + orderNum int(11) DEFAULT '0', + createdAt datetime NOT NULL, + updatedAt datetime NOT NULL, + statesCode int(11) DEFAULT '200', + dataStr text, + single bit(1) DEFAULT NULL, + cacheId varchar(32) DEFAULT NULL, + bodyType varchar(32) DEFAULT NULL, + PRIMARY KEY (id) ); -CREATE TABLE IF NOT EXISTS `blockparam` ( - `id` varchar(32) NOT NULL, - `pid` varchar(32) DEFAULT NULL, - `groupId` varchar(32) DEFAULT NULL, - `createdAt` datetime NOT NULL, - `updatedAt` datetime NOT NULL, - `qpId` varchar(32) DEFAULT NULL, - `dataExp` text, - PRIMARY KEY (`id`) +CREATE TABLE IF NOT EXISTS blockparam ( + id varchar(32) NOT NULL, + pid varchar(32) DEFAULT NULL, + groupId varchar(32) DEFAULT NULL, + createdAt datetime NOT NULL, + updatedAt datetime NOT NULL, + qpId varchar(32) DEFAULT NULL, + dataExp text, + PRIMARY KEY (id) ); CREATE TABLE IF NOT EXISTS DsConfig ( @@ -101,35 +118,35 @@ CREATE TABLE IF NOT EXISTS DsConfig ( PRIMARY KEY (id) ) ; -CREATE TABLE IF NOT EXISTS `envvars` ( - `id` varchar(32) NOT NULL, - `title` varchar(32) NULL DEFAULT NULL, - `pid` varchar(32) NULL DEFAULT NULL, - `groupId` varchar(32) NULL DEFAULT NULL, - `remark` text NULL, - `orderNum` int(11) NULL DEFAULT 0, - `createdAt` datetime(0) NOT NULL, - `updatedAt` datetime(0) NOT NULL, - `statesCode` int(11) NULL DEFAULT 200, - `type` varchar(32) NULL DEFAULT NULL, - `topic` text NULL, - `payload` text NULL, - PRIMARY KEY (`id`) +CREATE TABLE IF NOT EXISTS envvars ( + id varchar(32) NOT NULL, + title varchar(32) NULL DEFAULT NULL, + pid varchar(32) NULL DEFAULT NULL, + groupId varchar(32) NULL DEFAULT NULL, + remark text NULL, + orderNum int(11) NULL DEFAULT 0, + createdAt datetime(0) NOT NULL, + updatedAt datetime(0) NOT NULL, + statesCode int(11) NULL DEFAULT 200, + type varchar(32) NULL DEFAULT NULL, + topic text NULL, + payload text NULL, + PRIMARY KEY (id) ); -CREATE TABLE IF NOT EXISTS `excinfo`( - `id` varchar(32) NOT NULL, - `pid` varchar(32) NULL DEFAULT NULL, - `groupId` varchar(32) NULL DEFAULT NULL, - `createdAt` datetime(0) NOT NULL, - `updatedAt` datetime(0) NOT NULL, - `statesCode` int(11) NULL DEFAULT 200, - `apiId` varchar(32) NULL DEFAULT NULL, - `blockId` varchar(32) NULL DEFAULT NULL, - `errMsg` text NULL, - `paramStr` text NULL, - `errType` text NULL, - PRIMARY KEY (`id`) +CREATE TABLE IF NOT EXISTS excinfo( + id varchar(32) NOT NULL, + pid varchar(32) NULL DEFAULT NULL, + groupId varchar(32) NULL DEFAULT NULL, + createdAt datetime(0) NOT NULL, + updatedAt datetime(0) NOT NULL, + statesCode int(11) NULL DEFAULT 200, + apiId varchar(32) NULL DEFAULT NULL, + blockId varchar(32) NULL DEFAULT NULL, + errMsg text NULL, + paramStr text NULL, + errType text NULL, + PRIMARY KEY (id) ); CREATE TABLE IF NOT EXISTS QueryParam( @@ -190,118 +207,140 @@ CREATE TABLE IF NOT EXISTS BlockParam ( ) ; CREATE TABLE IF NOT EXISTS LinkerConfig ( - `id` varchar(32) NOT NULL, - `title` varchar(32) DEFAULT NULL, - `pid` varchar(32) DEFAULT NULL, - `groupId` varchar(32) DEFAULT NULL, - `remark` text, - `orderNum` int(11) DEFAULT 0, - `createdAt` datetime(0) NOT NULL, - `updatedAt` datetime(0) NOT NULL, - `statesCode` int(11) DEFAULT 200, - `driverClassName` varchar(64) DEFAULT NULL, - `jarFilePath` varchar(256) NOT NULL, - `linkerType` varchar(32) DEFAULT NULL, - `otherSettings` text NULL, - `reactive` BIT, - PRIMARY KEY (`id`) + id varchar(32) NOT NULL, + title varchar(32) DEFAULT NULL, + pid varchar(32) DEFAULT NULL, + groupId varchar(32) DEFAULT NULL, + remark text, + orderNum int(11) DEFAULT 0, + createdAt datetime(0) NOT NULL, + updatedAt datetime(0) NOT NULL, + statesCode int(11) DEFAULT 200, + driverClassName varchar(64) DEFAULT NULL, + jarFilePath varchar(256) NOT NULL, + linkerType varchar(32) DEFAULT NULL, + otherSettings text NULL, + reactive BIT, + PRIMARY KEY (id) ) ; -CREATE TABLE IF NOT EXISTS `exportdatainfo` ( - `id` varchar(32) NOT NULL, - `title` varchar(32) NULL DEFAULT NULL, - `pid` varchar(32) NULL DEFAULT NULL, - `groupId` varchar(32) NULL DEFAULT NULL, - `remark` text NULL, - `orderNum` int(11) NULL DEFAULT NULL, - `createdAt` datetime(0) NOT NULL, - `updatedAt` datetime(0) NOT NULL, - `statesCode` int(11) NULL DEFAULT 200, - `bodyId` varchar(32) NULL DEFAULT NULL, - `templateId` varchar(32) NULL DEFAULT NULL, - `fileName` varchar(32) NULL DEFAULT NULL, - PRIMARY KEY (`id`) +CREATE TABLE IF NOT EXISTS exportdatainfo ( + id varchar(32) NOT NULL, + title varchar(32) NULL DEFAULT NULL, + pid varchar(32) NULL DEFAULT NULL, + groupId varchar(32) NULL DEFAULT NULL, + remark text NULL, + orderNum int(11) NULL DEFAULT NULL, + createdAt datetime(0) NOT NULL, + updatedAt datetime(0) NOT NULL, + statesCode int(11) NULL DEFAULT 200, + bodyId varchar(32) NULL DEFAULT NULL, + templateId varchar(32) NULL DEFAULT NULL, + fileName varchar(32) NULL DEFAULT NULL, + PRIMARY KEY (id) ); -CREATE TABLE IF NOT EXISTS `funinfo` ( - `id` varchar(32) NOT NULL, - `title` varchar(32) NULL DEFAULT NULL, - `pid` varchar(32) NULL DEFAULT NULL, - `groupId` varchar(32) NULL DEFAULT NULL, - `remark` text NULL, - `orderNum` int(11) NULL DEFAULT NULL, - `createdAt` datetime(0) NOT NULL, - `updatedAt` datetime(0) NOT NULL, - `statesCode` int(11) NULL DEFAULT 200, - `cacheTime` int(11) NULL DEFAULT NULL, - PRIMARY KEY (`id`) +CREATE TABLE IF NOT EXISTS funinfo ( + id varchar(32) NOT NULL, + title varchar(32) NULL DEFAULT NULL, + pid varchar(32) NULL DEFAULT NULL, + groupId varchar(32) NULL DEFAULT NULL, + remark text NULL, + orderNum int(11) NULL DEFAULT NULL, + createdAt datetime(0) NOT NULL, + updatedAt datetime(0) NOT NULL, + statesCode int(11) NULL DEFAULT 200, + cacheTime int(11) NULL DEFAULT NULL, + PRIMARY KEY (id) ); -CREATE TABLE IF NOT EXISTS `funparam` ( - `id` varchar(32) NOT NULL, - `title` varchar(32) NULL DEFAULT NULL, - `pid` varchar(32) NULL DEFAULT NULL, - `groupId` varchar(32) NULL DEFAULT NULL, - `remark` text NULL, - `orderNum` int(11) NULL DEFAULT 0, - `createdAt` datetime(0) NOT NULL, - `updatedAt` datetime(0) NOT NULL, - `statesCode` int(11) NULL DEFAULT 200, - `dataType` varchar(32) NULL DEFAULT NULL, - `defaultVal` varchar(32) NULL DEFAULT NULL, - `paramType` int(11) NULL DEFAULT NULL, - PRIMARY KEY (`id`) +CREATE TABLE IF NOT EXISTS funparam ( + id varchar(32) NOT NULL, + title varchar(32) NULL DEFAULT NULL, + pid varchar(32) NULL DEFAULT NULL, + groupId varchar(32) NULL DEFAULT NULL, + remark text NULL, + orderNum int(11) NULL DEFAULT 0, + createdAt datetime(0) NOT NULL, + updatedAt datetime(0) NOT NULL, + statesCode int(11) NULL DEFAULT 200, + dataType varchar(32) NULL DEFAULT NULL, + defaultVal varchar(32) NULL DEFAULT NULL, + paramType int(11) NULL DEFAULT NULL, + PRIMARY KEY (id) ); -- ---------------------------- -- Table structure for loginfo -- ---------------------------- -CREATE TABLE IF NOT EXISTS `loginfo` ( - `id` varchar(32) NOT NULL, - `pid` varchar(32) DEFAULT NULL, - `groupId` varchar(32) NULL DEFAULT NULL, - `createdAt` datetime(0) NOT NULL, - `updatedAt` datetime(0) NOT NULL, - `type` varchar(32), - `active` varchar(32), - `data` text NULL, - PRIMARY KEY (`id`) +CREATE TABLE IF NOT EXISTS loginfo ( + id varchar(32) NOT NULL, + pid varchar(32) DEFAULT NULL, + groupId varchar(32) NULL DEFAULT NULL, + createdAt datetime(0) NOT NULL, + updatedAt datetime(0) NOT NULL, + type varchar(32), + active varchar(32), + data text NULL, + PRIMARY KEY (id) ); -CREATE TABLE IF NOT EXISTS `datarel` ( - `id` varchar(32) NOT NULL, - `pid` varchar(32) DEFAULT NULL, - `groupId` varchar(32) DEFAULT NULL, - `orderNum` int(11) DEFAULT '0', - `createdAt` datetime NOT NULL, - `updatedAt` datetime NOT NULL, - `topic` varchar(32), - `rel` varchar(32), - `source` varchar(32), - `target` varchar(32), - `dataExp` text, - PRIMARY KEY (`id`) +CREATE TABLE IF NOT EXISTS datarel ( + id varchar(32) NOT NULL, + pid varchar(32) DEFAULT NULL, + groupId varchar(32) DEFAULT NULL, + orderNum int(11) DEFAULT '0', + createdAt datetime NOT NULL, + updatedAt datetime NOT NULL, + topic varchar(32), + rel varchar(32), + source varchar(32), + target varchar(32), + dataExp text, + PRIMARY KEY (id) +); + +CREATE TABLE IF NOT EXISTS mcpserverinfo ( + id varchar(32) NOT NULL, + title varchar(128) NOT NULL, + pid varchar(32) NULL DEFAULT NULL, + groupId varchar(32) NULL DEFAULT NULL, + remark text NULL, + orderNum int(11) NULL DEFAULT NULL, + createdAt datetime(0) NOT NULL, + updatedAt datetime(0) NOT NULL, + statesCode int(11) DEFAULT 0, + typeCode int(11) NOT NULL DEFAULT 11, + serverTitle varchar(128) NULL DEFAULT NULL, + version varchar(32) NULL DEFAULT NULL, + baseUrl varchar(32) NULL DEFAULT '', + sseEndpoint varchar(32) NOT NULL, + messageEndpoint varchar(32) NULL DEFAULT NULL, + instructions text NULL, + keepAliveInterval int(11) NULL DEFAULT NULL, + requestTimeout int(11) NULL DEFAULT NULL, + immediateExecution bit(1) NULL DEFAULT NULL, + PRIMARY KEY (id) +); + +CREATE TABLE IF NOT EXISTS modelparam ( + id varchar(32) NOT NULL, + title varchar(32) DEFAULT NULL, + pid varchar(32) DEFAULT NULL, + groupId varchar(32) DEFAULT NULL, + remark text, + orderNum int(11) DEFAULT NULL, + createdAt datetime NOT NULL, + updatedAt datetime NOT NULL, + statesCode int(11) DEFAULT '200', + model varchar(256) NOT NULL, + systemPrompt text, + maxMemory int(11) DEFAULT NULL, + maxTokens bigint(20) DEFAULT NULL, + temperature double DEFAULT NULL, + paramJson text, + purpose varchar(16) NOT NULL, + setting text, + PRIMARY KEY (id) ); -CREATE TABLE IF NOT EXISTS `mcpserverinfo` ( - `id` varchar(32) NOT NULL, - `title` varchar(128) NOT NULL, - `pid` varchar(32) NULL DEFAULT NULL, - `groupId` varchar(32) NULL DEFAULT NULL, - `remark` text NULL, - `orderNum` int(11) NULL DEFAULT NULL, - `createdAt` datetime(0) NOT NULL, - `updatedAt` datetime(0) NOT NULL, - `statesCode` int(11) DEFAULT 0, - `typeCode` int(11) NOT NULL DEFAULT 11, - `serverTitle` varchar(128) NULL DEFAULT NULL, - `version` varchar(32) NULL DEFAULT NULL, - `baseUrl` varchar(32) NULL DEFAULT '', - `sseEndpoint` varchar(32) NOT NULL, - `messageEndpoint` varchar(32) NULL DEFAULT NULL, - `instructions` text NULL, - `keepAliveInterval` int(11) NULL DEFAULT NULL, - `requestTimeout` int(11) NULL DEFAULT NULL, - `immediateExecution` bit(1) NULL DEFAULT NULL, - PRIMARY KEY (`id`) -) diff --git a/apis/viewer-apis-client/src/main/resources/static/html/pages/AiNode.json b/apis/viewer-apis-client/src/main/resources/static/html/pages/AiNode.json new file mode 100644 index 0000000000000000000000000000000000000000..18fa4b4becff19720aa9ff8847bcd2a52ce185e2 --- /dev/null +++ b/apis/viewer-apis-client/src/main/resources/static/html/pages/AiNode.json @@ -0,0 +1,476 @@ +{ + "type": "page", + "title": "AiNode", + "body": [ + { + "id": "u:6e6616d6cf7c", + "type": "crud2", + "mode": "table2", + "dsType": "api", + "syncLocation": false, + "primaryField": "id", + "loadType": "pagination", + "api": { + "url": "/q/findList/aiNode", + "method": "get", + "requestAdaptor": "", + "adaptor": "", + "messages": {} + }, + "quickSaveItemApi": { + "url": "/c/save/aiNode", + "method": "post", + "requestAdaptor": "", + "adaptor": "", + "messages": {}, + "dataType": "json" + }, + "filter": { + "type": "form", + "title": "条件查询", + "mode": "inline", + "columnCount": 3, + "clearValueOnHidden": true, + "behavior": [ + "SimpleQuery" + ], + "body": [ + { + "name": "title", + "label": "标题", + "type": "input-text", + "size": "full", + "required": false, + "behavior": "SimpleQuery", + "id": "u:61520af119d3", + "clearable": true + }, + { + "type": "select", + "label": "厂商", + "name": "provider", + "id": "u:bbfcbd00a80c", + "multiple": false, + "size": "full", + "source": "supportProvider", + "selectFirst": false, + "searchable": true, + "clearable": true + }, + { + "name": "baseUrl", + "label": "baseUrl", + "type": "input-text", + "size": "full", + "required": false, + "behavior": "SimpleQuery", + "id": "u:a99741f525f4", + "clearable": true + } + ], + "actions": [ + { + "type": "button", + "label": "新增", + "onEvent": { + "click": { + "actions": [ + { + "ignoreError": false, + "actionType": "drawer", + "drawer": { + "$ref": "modal-ref-1" + } + } + ] + } + }, + "id": "u:e2219875dd08", + "level": "default", + "themeCss": { + "className": { + "font:hover": {} + } + } + }, + { + "type": "reset", + "label": "重置", + "id": "u:5ce9fc236061" + }, + { + "type": "submit", + "label": "查询", + "level": "primary", + "id": "u:ba7fb3975d54" + } + ], + "id": "u:d38a67c10ea9", + "feat": "Insert" + }, + "headerToolbar": [], + "footerToolbar": [ + { + "type": "flex", + "direction": "row", + "justify": "flex-start", + "alignItems": "stretch", + "style": { + "position": "static", + "flexWrap": "nowrap" + }, + "items": [ + { + "type": "container", + "align": "right", + "body": [ + { + "type": "pagination", + "behavior": "Pagination", + "layout": [ + "total", + "perPage", + "pager" + ], + "perPage": 10, + "perPageAvailable": [ + 10, + 20, + 50, + 100 + ], + "align": "right", + "id": "u:7a8aeed01b15", + "size": "", + "mode": "normal" + } + ], + "wrapperBody": false, + "style": { + "flexGrow": 1, + "flex": "1 1 auto", + "position": "static", + "display": "flex", + "flexBasis": "auto", + "flexDirection": "row", + "flexWrap": "nowrap", + "alignItems": "stretch", + "justifyContent": "flex-end" + }, + "id": "u:e4b9e45be11e" + } + ], + "id": "u:e7bdb59c323f", + "isFixedHeight": false, + "isFixedWidth": false + } + ], + "columns": [ + { + "type": "tpl", + "title": "标题", + "name": "title", + "id": "u:f13387e84576", + "placeholder": "-", + "width": "16%" + }, + { + "type": "tpl", + "title": "厂商", + "name": "provider", + "id": "u:ab634f92276c", + "placeholder": "-" + }, + { + "type": "tpl", + "title": "baseUrl", + "name": "baseUrl", + "id": "u:ed411e99abe0" + }, + { + "type": "tpl", + "title": "备注", + "name": "remark", + "id": "u:8fad2e4eb74c", + "placeholder": "-" + }, + { + "type": "tpl", + "title": "updatedAt", + "name": "updatedAt", + "id": "u:6a0ba56fe926", + "placeholder": "-", + "width": "15%" + }, + { + "type": "tpl", + "title": "id", + "name": "id", + "id": "u:710272271cc3", + "placeholder": "-", + "width": "1%", + "hidden": true + }, + { + "type": "operation", + "title": "操作", + "buttons": [ + { + "type": "button", + "label": "编辑", + "level": "link", + "behavior": "Edit", + "onEvent": { + "click": { + "actions": [ + { + "actionType": "drawer", + "drawer": { + "$ref": "modal-ref-1" + } + } + ] + } + }, + "id": "u:d63d5da1f382" + }, + { + "type": "button", + "label": "删除", + "behavior": "Delete", + "className": "m-r-xs text-danger", + "level": "link", + "confirmText": "确认要删除数据", + "onEvent": { + "click": { + "actions": [ + { + "actionType": "ajax", + "api": { + "method": "post", + "url": "/c/delete/aiNode", + "requestAdaptor": "", + "adaptor": "", + "messages": {}, + "data": { + "pkey": "${id}" + } + }, + "data": { + "&": "$$" + } + }, + { + "actionType": "search", + "groupType": "component", + "componentId": "u:6e6616d6cf7c" + } + ] + } + }, + "id": "u:9eb23a446645" + } + ], + "id": "u:3bdca48cc560", + "width": "11%" + } + ], + "editorSetting": { + "mock": { + "enable": true, + "maxDisplayRows": 5 + } + }, + "showHeader": true, + "resizable": true, + "keepItemSelectionOnPageChange": true + } + ], + "id": "u:3dc63152e7a2", + "asideResizor": false, + "pullRefresh": { + "disabled": false + }, + "regions": [ + "body" + ], + "definitions": { + "modal-ref-1": { + "type": "drawer", + "body": [ + { + "id": "u:ba7bc36478fd", + "type": "form", + "title": "编辑数据", + "mode": "horizontal", + "labelAlign": "left", + "dsType": "api", + "feat": "Edit", + "body": [ + { + "name": "id", + "label": "id", + "type": "input-text", + "id": "u:b25f600700d8", + "hidden": false, + "visible": false + }, + { + "name": "title", + "label": "标题", + "type": "input-text", + "id": "u:79f990bed5ed", + "labelAlign": "inherit", + "labelWidth": "var(--sizes-base-26)", + "wrapperCustomStyle": { + "root": { + "margin-bottom": "6px", + "margin-top": "6px" + } + }, + "required": true + }, + { + "name": "provider", + "label": "ai厂商", + "type": "select", + "id": "u:c7f74bb48a68", + "required": true, + "mode": "horizontal", + "labelAlign": "left", + "wrapperCustomStyle": { + "root": { + "margin-bottom": "6px", + "margin-top": "6px" + } + }, + "multiple": false, + "size": "full", + "source": "supportProvider", + "selectFirst": true, + "searchable": true, + "labelWidth": "var(--sizes-base-26)" + }, + { + "name": "baseUrl", + "label": "baseUrl", + "type": "input-url", + "id": "u:24e37782eb11", + "mode": "horizontal", + "labelAlign": "left", + "wrapperCustomStyle": { + "root": { + "margin-bottom": "6px", + "margin-top": "6px" + } + }, + "required": true, + "labelWidth": "var(--sizes-base-26)" + }, + { + "name": "apiKey", + "label": "apiKey", + "type": "input-text", + "id": "u:4d066fa32996", + "mode": "horizontal", + "labelAlign": "left", + "required": true, + "labelWidth": "var(--sizes-base-26)", + "wrapperCustomStyle": { + "root": { + "margin-bottom": "6px", + "margin-top": "6px" + } + } + }, + { + "type": "textarea", + "label": "备注", + "name": "remark", + "id": "u:24421ea7f7a6", + "minRows": 3, + "maxRows": 20, + "labelWidth": "var(--sizes-base-26)", + "labelAlign": "inherit", + "wrapperCustomStyle": { + "root": { + "margin-bottom": "6px", + "margin-top": "6px" + } + } + } + ], + "api": { + "url": "/c/save/aiNode", + "method": "post", + "requestAdaptor": "", + "adaptor": "", + "messages": {}, + "dataType": "json" + }, + "resetAfterSubmit": true, + "actions": [ + { + "type": "button", + "actionType": "cancel", + "label": "取消" + }, + { + "type": "button", + "actionType": "submit", + "label": "提交", + "level": "primary" + } + ], + "onEvent": { + "submitSucc": { + "actions": [ + { + "actionType": "search", + "groupType": "component", + "componentId": "u:6e6616d6cf7c" + } + ] + } + }, + "initApi": { + "url": "/q/findOne/aiNode", + "method": "get", + "requestAdaptor": "", + "adaptor": "", + "messages": {}, + "data": { + "pkey": "${id}" + }, + "sendOn": "${!ISEMPTY(id)}" + } + } + ], + "title": "编辑ai数据源", + "size": "md", + "actions": [ + { + "type": "button", + "actionType": "cancel", + "label": "取消", + "id": "u:973cf6b3eec4" + }, + { + "type": "button", + "actionType": "submit", + "label": "提交", + "level": "primary", + "id": "u:acba9083c54f" + } + ], + "actionType": "drawer", + "id": "u:059bc573ccbb", + "showCloseButton": true, + "closeOnOutside": false, + "closeOnEsc": false, + "showErrorMsg": true, + "showLoading": true, + "draggable": false + } + } +} \ No newline at end of file diff --git a/apis/viewer-apis-client/src/main/resources/static/html/pages/ModelParam.json b/apis/viewer-apis-client/src/main/resources/static/html/pages/ModelParam.json new file mode 100644 index 0000000000000000000000000000000000000000..f0f28c17b06aebee6cdfe3e84e22c5af451d6ac3 --- /dev/null +++ b/apis/viewer-apis-client/src/main/resources/static/html/pages/ModelParam.json @@ -0,0 +1,526 @@ +{ + "type": "page", + "title": "ModelParam", + "body": [ + { + "id": "u:d6a80c06043f", + "type": "crud2", + "mode": "table2", + "dsType": "api", + "syncLocation": true, + "primaryField": "id", + "loadType": "", + "headerToolbar": [], + "footerToolbar": [ + { + "type": "flex", + "direction": "row", + "justify": "flex-start", + "alignItems": "stretch", + "style": { + "position": "static", + "flexWrap": "nowrap" + }, + "items": [], + "id": "u:3a44f63469d8", + "isFixedHeight": false, + "isFixedWidth": false + } + ], + "columns": [ + { + "type": "tpl", + "title": "标题", + "name": "title", + "id": "u:3a5dd004af07", + "placeholder": "-" + }, + { + "type": "tpl", + "title": "用途", + "name": "purpose", + "id": "u:659469efc312", + "placeholder": "-" + }, + { + "type": "tpl", + "title": "模型", + "name": "model", + "id": "u:db4c11e09de8", + "placeholder": "-" + }, + { + "type": "tpl", + "title": "备注", + "name": "remark", + "id": "u:5ecf6804ea5e", + "placeholder": "-" + }, + { + "type": "tpl", + "title": "updatedAt", + "name": "updatedAt", + "id": "u:8718d95a2242", + "placeholder": "-", + "width": "12%" + }, + { + "type": "tpl", + "title": "id", + "name": "id", + "id": "u:8fbc0ee7091c", + "placeholder": "-", + "width": "1%", + "hidden": true + }, + { + "type": "operation", + "title": "操作", + "buttons": [ + { + "type": "button", + "label": "编辑", + "level": "link", + "behavior": "Edit", + "onEvent": { + "click": { + "actions": [ + { + "actionType": "drawer", + "drawer": { + "$ref": "modal-ref-1" + } + } + ] + } + }, + "id": "u:64fd04718c71" + }, + { + "type": "button", + "label": "删除", + "behavior": "Delete", + "className": "m-r-xs text-danger", + "level": "link", + "confirmText": "确认要删除数据", + "onEvent": { + "click": { + "actions": [ + { + "actionType": "ajax", + "api": { + "method": "post", + "url": "/c/delete/modelParam", + "requestAdaptor": "", + "adaptor": "", + "messages": {}, + "data": { + "pkey": "${id}" + } + }, + "outputVar": "responseResult", + "options": {} + }, + { + "actionType": "search", + "groupType": "component", + "componentId": "u:d6a80c06043f" + } + ] + } + }, + "id": "u:cf1f9b6d88ed" + } + ], + "id": "u:0aef628393af", + "width": "11%" + } + ], + "editorSetting": { + "mock": { + "enable": true, + "maxDisplayRows": 5 + } + }, + "api": { + "url": "/q/findList/modelParam", + "method": "get", + "requestAdaptor": "", + "adaptor": "", + "messages": {} + }, + "quickSaveItemApi": { + "url": "/c/save/modelParam", + "method": "post", + "requestAdaptor": "", + "adaptor": "", + "messages": {}, + "dataType": "json" + }, + "filter": { + "type": "form", + "title": "条件查询", + "mode": "inline", + "columnCount": 3, + "clearValueOnHidden": true, + "behavior": [ + "SimpleQuery" + ], + "body": [ + { + "name": "title", + "label": "标题", + "type": "input-text", + "size": "full", + "required": false, + "behavior": "SimpleQuery", + "id": "u:011c6b545370" + }, + { + "type": "select", + "label": "用途", + "name": "purpose", + "id": "u:18ea50831ac3", + "multiple": false, + "size": "full", + "source": "modelPurposes", + "selectFirst": false, + "searchable": false, + "clearable": true + }, + { + "name": "model", + "label": "模型", + "type": "input-text", + "size": "full", + "required": false, + "behavior": "SimpleQuery", + "id": "u:990e49421eb3" + } + ], + "actions": [ + { + "type": "button", + "label": "新增", + "onEvent": { + "click": { + "actions": [ + { + "ignoreError": false, + "actionType": "drawer", + "drawer": { + "$ref": "modal-ref-1" + } + } + ] + } + }, + "id": "u:e0bfc68369e4", + "level": "default", + "themeCss": { + "className": { + "font:hover": {} + } + } + }, + { + "type": "reset", + "label": "重置", + "id": "u:0ef665da7461" + }, + { + "type": "submit", + "label": "查询", + "level": "primary", + "id": "u:afac63e6ac19" + } + ], + "id": "u:73ce245a7067", + "feat": "Insert" + }, + "showHeader": true, + "resizable": true, + "keepItemSelectionOnPageChange": true, + "autoFillHeight": true + } + ], + "id": "u:b3c253bb3402", + "asideResizor": false, + "pullRefresh": { + "disabled": true + }, + "regions": [ + "body" + ], + "definitions": { + "modal-ref-1": { + "type": "drawer", + "body": [ + { + "type": "form", + "id": "u:d0c5625761aa", + "title": "编辑数据", + "mode": "horizontal", + "labelAlign": "left", + "dsType": "api", + "feat": "Edit", + "body": [ + { + "name": "id", + "label": "id", + "type": "input-text", + "id": "u:bd9da970a208", + "hidden": false, + "visible": false + }, + { + "name": "title", + "label": "标题", + "type": "input-text", + "id": "u:b29d12d6ab23", + "labelAlign": "inherit", + "labelWidth": "var(--sizes-base-24)", + "wrapperCustomStyle": { + "root": { + "margin-bottom": "6px", + "margin-top": "6px" + } + }, + "required": true + }, + { + "type": "select", + "label": "目标ai", + "name": "pid", + "id": "u:fb5b29c4ed9f", + "multiple": false, + "labelAlign": "inherit", + "labelWidth": "var(--sizes-base-24)", + "wrapperCustomStyle": { + "root": { + "margin-bottom": "6px", + "margin-top": "6px" + } + }, + "selectFirst": true, + "source": { + "method": "get", + "url": "/q/findList/aiNode", + "requestAdaptor": "", + "adaptor": "", + "messages": {} + }, + "labelField": "title", + "valueField": "id", + "required": true + }, + { + "type": "select", + "label": "用途", + "name": "purpose", + "id": "u:f58dec9a6fbd", + "multiple": false, + "labelAlign": "inherit", + "labelWidth": "var(--sizes-base-24)", + "wrapperCustomStyle": { + "root": { + "margin-bottom": "6px", + "margin-top": "6px" + } + }, + "selectFirst": true, + "source": { + "method": "get", + "url": "modelPurposes", + "requestAdaptor": "", + "adaptor": "", + "messages": {} + }, + "required": true + }, + { + "name": "model", + "label": "模型", + "type": "input-text", + "id": "u:a1ad0ab131ad", + "labelAlign": "inherit", + "labelWidth": "var(--sizes-base-24)", + "wrapperCustomStyle": { + "root": { + "margin-bottom": "6px", + "margin-top": "6px" + } + }, + "required": true + }, + { + "type": "textarea", + "label": "系统提示词", + "name": "modelArgs.systemPrompt", + "id": "u:f69a7e0c79b5", + "minRows": 5, + "maxRows": 20, + "labelWidth": "var(--sizes-base-24)", + "labelAlign": "top", + "mode": "normal" + }, + { + "name": "modelArgs.temperature", + "label": "随机性", + "type": "input-number", + "id": "u:a62c3df783e5", + "labelAlign": "inherit", + "wrapperCustomStyle": { + "root": { + "margin-bottom": "6px", + "margin-top": "6px" + } + }, + "keyboard": true, + "step": "", + "min": 0, + "value": "", + "precision": 1, + "kilobitSeparator": false, + "max": 1 + }, + { + "type": "service", + "body": [ + { + "name": "modelArgs.maxTokens", + "label": "单次最大Tokens", + "type": "input-number", + "id": "u:68e43de6ec4f", + "labelAlign": "inherit", + "wrapperCustomStyle": { + "root": { + "margin-bottom": "6px", + "margin-top": "6px" + } + }, + "keyboard": true, + "step": 1, + "min": 0, + "value": "", + "precision": "", + "kilobitSeparator": false + } + ], + "id": "u:7004050cb373", + "dsType": "api" + }, + { + "draggable": true, + "type": "input-kv", + "label": "其他参数", + "name": "paramMap", + "id": "u:25ab98e04283", + "multiple": true, + "items": [ + { + "placeholder": "Key", + "type": "input-text", + "unique": true, + "name": "key", + "required": true, + "validateOnChange": true + }, + { + "placeholder": "Value", + "type": "input-text", + "name": "value" + } + ] + }, + { + "type": "textarea", + "label": "备注", + "name": "remark", + "id": "u:faf4e33fcdf6", + "minRows": 3, + "maxRows": 20, + "labelAlign": "inherit" + } + ], + "api": { + "url": "/c/save/modelParam", + "method": "post", + "requestAdaptor": "", + "adaptor": "", + "messages": {}, + "dataType": "json" + }, + "resetAfterSubmit": true, + "actions": [ + { + "type": "button", + "actionType": "cancel", + "label": "取消" + }, + { + "type": "button", + "actionType": "submit", + "label": "提交", + "level": "primary" + } + ], + "onEvent": { + "submitSucc": { + "actions": [ + { + "actionType": "reload", + "groupType": "component", + "componentId": "u:d6a80c06043f", + "args": {} + } + ] + } + }, + "initApi": { + "url": "/q/findOne/modelParam", + "method": "get", + "requestAdaptor": "", + "adaptor": "", + "messages": {}, + "data": { + "pkey": "${id}" + }, + "sendOn": "${!ISEMPTY(id)}" + }, + "debug": false + } + ], + "title": "编辑模型", + "id": "u:84c1d59acdf3", + "actions": [ + { + "type": "button", + "actionType": "cancel", + "label": "取消", + "id": "u:02f3cadcd474" + }, + { + "type": "button", + "actionType": "submit", + "label": "提交", + "id": "u:8fb3e48926ed", + "level": "primary" + } + ], + "showCloseButton": true, + "closeOnOutside": false, + "closeOnEsc": false, + "showErrorMsg": true, + "showLoading": true, + "draggable": false, + "size": "md", + "actionType": "drawer", + "editorSetting": { + "displayName": "" + }, + "resizable": false, + "hideActions": false + } + } +} \ No newline at end of file diff --git a/apis/viewer-apis-client/src/main/resources/static/html/pages/funInfo.json b/apis/viewer-apis-client/src/main/resources/static/html/pages/funInfo.json index 655996c18cab8523a11d2b4d847b6eb25f472194..6879e7cfebbc2658f0abf36b158d7887a40dca93 100644 --- a/apis/viewer-apis-client/src/main/resources/static/html/pages/funInfo.json +++ b/apis/viewer-apis-client/src/main/resources/static/html/pages/funInfo.json @@ -103,14 +103,15 @@ "name": "title", "id": "u:7b5904fba5cc", "placeholder": "-", - "width": "30%" + "width": "25%" }, { "type": "tpl", - "title": "remark", + "title": "说明(备注)", "name": "remark", "id": "u:968da5f1938e", - "placeholder": "-" + "placeholder": "-", + "popOver": false }, { "type": "tpl", @@ -118,7 +119,7 @@ "name": "updatedAt", "id": "u:0c07bb68b2d3", "placeholder": "-", - "width": "16%" + "width": "15%" }, { "type": "operation", @@ -264,38 +265,48 @@ } } }, + { + "type": "textarea", + "label": "说明(备注)", + "name": "remark", + "id": "u:d6669f75c1ce", + "row": 2, + "minRows": 3, + "maxRows": 20 + }, { "type": "input-table", - "name": "params", - "label": "参数设定", "id": "u:904bffd1aa6c", "columns": [ { "label": "id", "name": "id", - "quickEdit": false, "id": "u:0f712b46e01b", "placeholder": "-", + "width": 1, + "quickEdit": false, "inline": true, "visible": false, - "hidden": true, - "width": 1 + "hidden": true }, { "label": "title", "name": "title", + "type": "text", + "id": "u:600e240e8211", + "placeholder": "-", "quickEdit": { "type": "input-text", "name": "title", "mode": "popOver" - }, - "type": "text", - "id": "u:600e240e8211", - "placeholder": "-" + } }, { "label": "dataType", "name": "dataType", + "type": "text", + "id": "u:488b2d50e1d1", + "placeholder": "-", "quickEdit": { "type": "wrapper", "mode": "popOver", @@ -324,22 +335,19 @@ }, "isFixedHeight": false, "isFixedWidth": false - }, - "type": "text", - "id": "u:488b2d50e1d1", - "placeholder": "-" + } }, { "label": "defaultVal", - "name": "defaultVal", "type": "text", + "id": "u:4f6793cda9ec", + "placeholder": "-", + "name": "defaultVal", "quickEdit": { "type": "input-text", "name": "defaultVal", "mode": "popOver" - }, - "id": "u:4f6793cda9ec", - "placeholder": "-" + } }, { "label": "paramType", @@ -390,6 +398,9 @@ } } ], + "draggable": true, + "name": "params", + "label": "参数设定", "addable": true, "footerAddBtn": { "label": "新增", @@ -400,8 +411,7 @@ "copyable": true, "editable": true, "removable": true, - "columnsTogglable": false, - "draggable": true + "columnsTogglable": false }, { "type": "crud", @@ -453,7 +463,7 @@ "outputVar": "responseResult", "options": {}, "api": { - "url": "/c/delete/queryBlock", + "url": "/c/delete/blockInfo", "method": "post", "requestAdaptor": "", "adaptor": "", @@ -780,14 +790,10 @@ "id": "u:e3820994e2e4", "themeCss": { "baseControlClassName": { - "padding-and-margin:default": { - "marginTop": "var(--sizes-size-5)", - "marginRight": "var(--sizes-size-5)", - "marginBottom": "var(--sizes-size-5)", - "marginLeft": "var(--sizes-size-5)" - } + "padding-and-margin:default": {} } - } + }, + "gap": "" }, { "type": "grid", @@ -804,43 +810,53 @@ "value": "task" }, { - "label": "iterator", + "label": "循环", "value": "iterator" }, { - "label": "choose", + "label": "选择", "value": "choose" }, { - "label": "loop", + "label": "循环", "value": "loop" }, { - "label": "value", + "label": "赋值", "value": "value" }, { - "label": "transpose", + "label": "数据转置", "value": "transpose" }, { - "label": "single", + "label": "单一值", "value": "single" }, + { + "label": "FunctionCall", + "value": "FunctionCall" + }, { "label": "mcp", "value": "mcp", - "hiddenOn": "true" + "hiddenOn": "${true}" }, { "label": "parallel", "value": "parallel", "hiddenOn": "${true}" + }, + { + "label": "AI创作", + "value": "execAI", + "hiddenOn": "${true}" } ], "id": "u:fd07835da4f1", "multiple": false, - "value": "task" + "value": "single", + "labelAlign": "inherit" } ], "md": 12, @@ -895,7 +911,19 @@ "title": "spel表达式", "content": "" } - }, + } + ], + "md": 12, + "id": "u:a5bb6d1cfbaf" + } + ], + "id": "u:7dcbec6179e3" + }, + { + "type": "grid", + "columns": [ + { + "body": [ { "type": "input-text", "label": "转置对象", @@ -908,10 +936,11 @@ } ], "md": 12, - "id": "u:a5bb6d1cfbaf" + "id": "u:b0d7d10d715a" } ], - "id": "u:7dcbec6179e3" + "id": "u:c14295a3a82f", + "gap": "" }, { "type": "grid", @@ -970,6 +999,96 @@ "align": "left", "valign": "middle" }, + { + "type": "grid", + "columns": [ + { + "body": [ + { + "type": "select", + "label": "目标模型", + "name": "data.modelId", + "id": "u:8d2a2efc675c", + "value": "", + "visible": true, + "hiddenOn": "${!(bodyType==\"FunctionCall\" || bodyType==\"execAI\" || bodyType==\"mcp\")}", + "clearValueOnHidden": true, + "multiple": false, + "source": { + "method": "get", + "url": "/q/findList/modelParam", + "requestAdaptor": "", + "adaptor": "", + "messages": {} + }, + "labelField": "title", + "valueField": "id", + "required": true + } + ], + "id": "u:7a776752f367", + "md": 8 + }, + { + "body": [ + { + "type": "switch", + "label": "json格式返回", + "option": "", + "name": "data.jsonType", + "falseValue": false, + "trueValue": true, + "id": "u:474142764e7d", + "optionAtLeft": true, + "value": true, + "visible": true, + "hiddenOn": "${!(bodyType==\"FunctionCall\" || bodyType==\"execAI\" || bodyType==\"mcp\")}", + "clearValueOnHidden": true + } + ], + "id": "u:db45bc616979", + "themeCss": { + "baseControlClassName": { + "padding-and-margin:default": {} + } + }, + "md": "auto" + } + ], + "id": "u:7bf7db822a6d", + "gap": "base", + "themeCss": { + "baseControlClassName": { + "padding-and-margin:default": { + "marginBottom": "var(--sizes-size-4)" + } + } + }, + "align": "left", + "valign": "middle" + }, + { + "type": "grid", + "columns": [ + { + "body": [ + { + "type": "textarea", + "label": "提示词", + "name": "data.userMsg", + "id": "u:018b6276b71b", + "minRows": 3, + "maxRows": 20, + "hiddenOn": "${!(bodyType==\"FunctionCall\" || bodyType==\"execAI\" || bodyType==\"mcp\")}", + "clearValueOnHidden": true + } + ], + "md": 12, + "id": "u:95f4ee1686d9" + } + ], + "id": "u:639bc959f389" + }, { "type": "input-table", "name": "bodys", @@ -1319,12 +1438,12 @@ "editBtnIcon": "", "editBtnLabel": "编辑", "clearValueOnHidden": true, - "hiddenOn": "${bodyType==\"transpose\" || bodyType==\"value\"}" + "hiddenOn": "${bodyType==\"transpose\" || bodyType==\"value\" || bodyType==\"execAI\"}" }, { "type": "input-table", "name": "bodys[0].params", - "label": "表格表单", + "label": "参数设置", "columns": [ { "label": "属性名", @@ -1360,7 +1479,7 @@ "removable": true, "showIndex": true, "clearValueOnHidden": true, - "hiddenOn": "${ bodyType!=\"value\"}" + "hiddenOn": "${!(bodyType==\"value\" || bodyType==\"execAI\")}" } ], "id": "u:1bf35f729bae", diff --git a/apis/viewer-apis-client/src/main/resources/static/html/pages/index.json b/apis/viewer-apis-client/src/main/resources/static/html/pages/index.json index 9ee5d6fc4d7f517ef76e3ea7c232ceca6385cdda..94ae109570ab0f999e1a6674141bcdfdc0574039 100644 --- a/apis/viewer-apis-client/src/main/resources/static/html/pages/index.json +++ b/apis/viewer-apis-client/src/main/resources/static/html/pages/index.json @@ -5,12 +5,22 @@ "url": "/", "schemaApi": "/html/pages/queryBody.json" },{ - "label": "Mcp", + "label": "AI 支持", "children": [ { "label": "McpServer", "url": "McpServer", "schemaApi": "/html/pages/McpServer.json" + }, + { + "label": "定义AI源", + "url": "AINode", + "schemaApi": "/html/pages/AINode.json" + }, + { + "label": "模型预设", + "url": "ModelParam", + "schemaApi": "/html/pages/ModelParam.json" } ] }, diff --git a/commons/pom.xml b/commons/pom.xml index ef7bcf798d2950ecf57dfaf4976ce4651065bcab..40e5169cdff72640a02717637efa309e8c5a33a9 100644 --- a/commons/pom.xml +++ b/commons/pom.xml @@ -23,6 +23,7 @@ viewer-common-log viewer-common-annotation + viewer-common-ai-model diff --git a/commons/viewer-common-ai-model/pom.xml b/commons/viewer-common-ai-model/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..5d3e4a20e37891393e0e8fea9e872690c01dd713 --- /dev/null +++ b/commons/viewer-common-ai-model/pom.xml @@ -0,0 +1,37 @@ + + + 4.0.0 + + xyz.thoughtset.viewer + commons + ${revision} + + + viewer-common-ai-model + + + 17 + 17 + UTF-8 + + + + + + xyz.thoughtset.viewer + viewer-common-core + + + xyz.thoughtset.viewer + viewer-common-crud-core + + + org.springframework.ai + spring-ai-client-chat + ${springai.version} + + + + \ No newline at end of file diff --git a/commons/viewer-common-ai-model/src/main/java/xyz/thoughtset/viewer/common/ai/model/CommonAIModelAutoConfiguration.java b/commons/viewer-common-ai-model/src/main/java/xyz/thoughtset/viewer/common/ai/model/CommonAIModelAutoConfiguration.java new file mode 100644 index 0000000000000000000000000000000000000000..57479cbf4b582179d272f54c52f4e23ccb0c2cdb --- /dev/null +++ b/commons/viewer-common-ai-model/src/main/java/xyz/thoughtset/viewer/common/ai/model/CommonAIModelAutoConfiguration.java @@ -0,0 +1,13 @@ +package xyz.thoughtset.viewer.common.ai.model; + +import org.mybatis.spring.annotation.MapperScan; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; + +@Configuration +@ComponentScan +@EnableConfigurationProperties +@MapperScan(basePackages = "xyz.thoughtset.viewer.common.ai.model.dao") +public class CommonAIModelAutoConfiguration { +} diff --git a/commons/viewer-common-ai-model/src/main/java/xyz/thoughtset/viewer/common/ai/model/dao/AiNodeDao.java b/commons/viewer-common-ai-model/src/main/java/xyz/thoughtset/viewer/common/ai/model/dao/AiNodeDao.java new file mode 100644 index 0000000000000000000000000000000000000000..a90463db8010da6e2504d796ea9de458f6c6b8f0 --- /dev/null +++ b/commons/viewer-common-ai-model/src/main/java/xyz/thoughtset/viewer/common/ai/model/dao/AiNodeDao.java @@ -0,0 +1,9 @@ +package xyz.thoughtset.viewer.common.ai.model.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Mapper; +import xyz.thoughtset.viewer.common.ai.model.entity.AiNode; + +@Mapper +public interface AiNodeDao extends BaseMapper { +} diff --git a/commons/viewer-common-ai-model/src/main/java/xyz/thoughtset/viewer/common/ai/model/dao/ModelParamDao.java b/commons/viewer-common-ai-model/src/main/java/xyz/thoughtset/viewer/common/ai/model/dao/ModelParamDao.java new file mode 100644 index 0000000000000000000000000000000000000000..6efb59e7fe1ec70e30cc25309bcce1922326a331 --- /dev/null +++ b/commons/viewer-common-ai-model/src/main/java/xyz/thoughtset/viewer/common/ai/model/dao/ModelParamDao.java @@ -0,0 +1,9 @@ +package xyz.thoughtset.viewer.common.ai.model.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Mapper; +import xyz.thoughtset.viewer.common.ai.model.entity.ModelParam; + +@Mapper +public interface ModelParamDao extends BaseMapper { +} diff --git a/commons/viewer-common-ai-model/src/main/java/xyz/thoughtset/viewer/common/ai/model/entity/AiNode.java b/commons/viewer-common-ai-model/src/main/java/xyz/thoughtset/viewer/common/ai/model/entity/AiNode.java new file mode 100644 index 0000000000000000000000000000000000000000..d078ce6921f917c73fcf630c6536f5ca694df872 --- /dev/null +++ b/commons/viewer-common-ai-model/src/main/java/xyz/thoughtset/viewer/common/ai/model/entity/AiNode.java @@ -0,0 +1,33 @@ +package xyz.thoughtset.viewer.common.ai.model.entity; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import xyz.thoughtset.viewer.common.core.entity.BaseMeta; +import xyz.thoughtset.viewer.common.crud.core.annotation.ApiCRUDPower; + +import java.util.List; +import java.util.Map; + +@TableName +@Data +@NoArgsConstructor +@ApiCRUDPower(insert = false,save = true,update = false,list = true) +public class AiNode extends BaseMeta { + protected String provider = null; + protected String baseUrl; + protected String apiKey; + protected String headersStr; + protected String settingStr; + + @TableField(exist = false) + protected transient Map settingMap; + @TableField(exist = false) + protected transient Map headerMap; + @TableField(exist = false) + protected transient List defaultModelParams; + + +} diff --git a/commons/viewer-common-ai-model/src/main/java/xyz/thoughtset/viewer/common/ai/model/entity/ModelParam.java b/commons/viewer-common-ai-model/src/main/java/xyz/thoughtset/viewer/common/ai/model/entity/ModelParam.java new file mode 100644 index 0000000000000000000000000000000000000000..2f90fd8d06105bf162799ab202cbd1fb4e8893dc --- /dev/null +++ b/commons/viewer-common-ai-model/src/main/java/xyz/thoughtset/viewer/common/ai/model/entity/ModelParam.java @@ -0,0 +1,37 @@ +package xyz.thoughtset.viewer.common.ai.model.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import xyz.thoughtset.viewer.common.ai.model.entity.purpose.BaseModelSetting; +import xyz.thoughtset.viewer.common.ai.model.entity.purpose.ChatModelSetting; +import xyz.thoughtset.viewer.common.ai.model.entity.purpose.ModelPurposeEnum; +import xyz.thoughtset.viewer.common.core.entity.BaseMeta; +import xyz.thoughtset.viewer.common.core.entity.IdMeta; +import xyz.thoughtset.viewer.common.crud.core.annotation.ApiCRUDPower; + +import java.util.Map; + +@TableName +@Data +@NoArgsConstructor +@ApiCRUDPower(insert = false,save = true,update = false,list = true) +public class ModelParam extends BaseMeta { + protected String model; + protected ModelPurposeEnum purpose; + protected String setting; + protected String paramJson; + protected Integer maxMemory = 8; + + protected transient Map paramMap; + protected transient BaseModelSetting modelArgs; + + public String chatSystemPrompt(){ + if(modelArgs!=null && modelArgs instanceof ChatModelSetting){ + return ((ChatModelSetting) modelArgs).getSystemPrompt(); + } + return ""; + } + +} diff --git a/commons/viewer-common-ai-model/src/main/java/xyz/thoughtset/viewer/common/ai/model/entity/purpose/BaseModelSetting.java b/commons/viewer-common-ai-model/src/main/java/xyz/thoughtset/viewer/common/ai/model/entity/purpose/BaseModelSetting.java new file mode 100644 index 0000000000000000000000000000000000000000..62ad41b478acda08017fe8f8d56f25fa6cac1d53 --- /dev/null +++ b/commons/viewer-common-ai-model/src/main/java/xyz/thoughtset/viewer/common/ai/model/entity/purpose/BaseModelSetting.java @@ -0,0 +1,11 @@ +package xyz.thoughtset.viewer.common.ai.model.entity.purpose; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +//@Data +//@NoArgsConstructor +//@AllArgsConstructor +public class BaseModelSetting { +} diff --git a/commons/viewer-common-ai-model/src/main/java/xyz/thoughtset/viewer/common/ai/model/entity/purpose/ChatModelSetting.java b/commons/viewer-common-ai-model/src/main/java/xyz/thoughtset/viewer/common/ai/model/entity/purpose/ChatModelSetting.java new file mode 100644 index 0000000000000000000000000000000000000000..ce0d5eb8b075c5a8f353a8481621a6ac003825fb --- /dev/null +++ b/commons/viewer-common-ai-model/src/main/java/xyz/thoughtset/viewer/common/ai/model/entity/purpose/ChatModelSetting.java @@ -0,0 +1,16 @@ +package xyz.thoughtset.viewer.common.ai.model.entity.purpose; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class ChatModelSetting extends BaseModelSetting { + protected String systemPrompt; + protected Long maxTokens; + protected Double temperature; + + +} diff --git a/commons/viewer-common-ai-model/src/main/java/xyz/thoughtset/viewer/common/ai/model/entity/purpose/ImageModelSetting.java b/commons/viewer-common-ai-model/src/main/java/xyz/thoughtset/viewer/common/ai/model/entity/purpose/ImageModelSetting.java new file mode 100644 index 0000000000000000000000000000000000000000..18e0bfbfcbd37a97993851dc9b4901204d9bb357 --- /dev/null +++ b/commons/viewer-common-ai-model/src/main/java/xyz/thoughtset/viewer/common/ai/model/entity/purpose/ImageModelSetting.java @@ -0,0 +1,12 @@ +package xyz.thoughtset.viewer.common.ai.model.entity.purpose; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class ImageModelSetting extends BaseModelSetting { + private String size; +} diff --git a/commons/viewer-common-ai-model/src/main/java/xyz/thoughtset/viewer/common/ai/model/entity/purpose/ModelPurposeEnum.java b/commons/viewer-common-ai-model/src/main/java/xyz/thoughtset/viewer/common/ai/model/entity/purpose/ModelPurposeEnum.java new file mode 100644 index 0000000000000000000000000000000000000000..3ad8fcf3d54e82d20488daa8f07e53ac8d8c7382 --- /dev/null +++ b/commons/viewer-common-ai-model/src/main/java/xyz/thoughtset/viewer/common/ai/model/entity/purpose/ModelPurposeEnum.java @@ -0,0 +1,32 @@ +package xyz.thoughtset.viewer.common.ai.model.entity.purpose; + +import com.baomidou.mybatisplus.annotation.IEnum; +import com.fasterxml.jackson.annotation.JsonValue; +import lombok.AllArgsConstructor; +import lombok.Getter; +import xyz.thoughtset.viewer.common.core.enums.EnumValue; + +@Getter +@AllArgsConstructor +public enum ModelPurposeEnum implements IEnum { + CHAT("CHAT", ChatModelSetting.class) + ,IMAGE("IMAGE", ImageModelSetting.class) +// ,EMBEDDING("EMBEDDING") +// ,EMBEDDING("EMBEDDING") + ; + + @JsonValue + private final String title; + private final Class settingClass; + +// private ModelPurposeEnum(String title,String value) { +// this.value = value; +// this.title = title; +// } + + + @Override + public String getValue() { + return title; + } +} diff --git a/commons/viewer-common-ai-model/src/main/java/xyz/thoughtset/viewer/common/ai/model/factory/ChatModelBuilder.java b/commons/viewer-common-ai-model/src/main/java/xyz/thoughtset/viewer/common/ai/model/factory/ChatModelBuilder.java new file mode 100644 index 0000000000000000000000000000000000000000..e729e62263a12e4c7e6ea8a380ad2fe2da1bb6f9 --- /dev/null +++ b/commons/viewer-common-ai-model/src/main/java/xyz/thoughtset/viewer/common/ai/model/factory/ChatModelBuilder.java @@ -0,0 +1,20 @@ +package xyz.thoughtset.viewer.common.ai.model.factory; + + +import lombok.Getter; +import lombok.NonNull; + +@Getter +public abstract class ChatModelBuilder extends ModelBuilder{ + + + protected ChatModelBuilder(@NonNull String provider) { + super(provider); + } + + protected ChatModelBuilder(@NonNull String provider, String aiModel) { + super(provider, aiModel); + } + + +} diff --git a/commons/viewer-common-ai-model/src/main/java/xyz/thoughtset/viewer/common/ai/model/factory/DefaultModelBuilder.java b/commons/viewer-common-ai-model/src/main/java/xyz/thoughtset/viewer/common/ai/model/factory/DefaultModelBuilder.java new file mode 100644 index 0000000000000000000000000000000000000000..be6ed16bc9876bc3002aa07198d7cc6c5501787b --- /dev/null +++ b/commons/viewer-common-ai-model/src/main/java/xyz/thoughtset/viewer/common/ai/model/factory/DefaultModelBuilder.java @@ -0,0 +1,29 @@ +package xyz.thoughtset.viewer.common.ai.model.factory; + + +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.Getter; +import lombok.NonNull; +import org.springframework.ai.chat.model.ChatModel; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.util.StringUtils; +import xyz.thoughtset.viewer.common.ai.model.entity.AiNode; +import xyz.thoughtset.viewer.common.ai.model.entity.ModelParam; + +@Getter +public abstract class DefaultModelBuilder extends ModelBuilder{ + + + protected DefaultModelBuilder(@NonNull String provider) { + super(provider); + } + + protected DefaultModelBuilder(@NonNull String provider, String aiModel) { + super(provider, aiModel); + } + + @Override + public boolean wasDefault() { + return true; + } +} diff --git a/commons/viewer-common-ai-model/src/main/java/xyz/thoughtset/viewer/common/ai/model/factory/ModelBuilder.java b/commons/viewer-common-ai-model/src/main/java/xyz/thoughtset/viewer/common/ai/model/factory/ModelBuilder.java new file mode 100644 index 0000000000000000000000000000000000000000..a8e2bac3bf401862402c3f7066672602d177d1fd --- /dev/null +++ b/commons/viewer-common-ai-model/src/main/java/xyz/thoughtset/viewer/common/ai/model/factory/ModelBuilder.java @@ -0,0 +1,65 @@ +package xyz.thoughtset.viewer.common.ai.model.factory; + + +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.Getter; +import lombok.NonNull; +import org.springframework.ai.chat.model.ChatModel; +import org.springframework.ai.model.Model; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.util.ObjectUtils; +import org.springframework.util.StringUtils; +import xyz.thoughtset.viewer.common.ai.model.entity.AiNode; +import xyz.thoughtset.viewer.common.ai.model.entity.ModelParam; +import xyz.thoughtset.viewer.common.ai.model.entity.purpose.ModelPurposeEnum; + +import java.util.List; +import java.util.Optional; + +@Getter +public abstract class ModelBuilder { + protected String provider; + protected List supportModels; +// +// protected ModelPurposeEnum purposeEnum; + + @Autowired + protected ObjectMapper objectMapper; + + protected ModelBuilder(@NonNull String provider) { + this(provider,""); + } + protected ModelBuilder(@NonNull String provider, String aiModel) { + this(provider, List.of(aiModel)); + } + + protected ModelBuilder(String provider, List supportModels) { + this.provider = provider; + this.supportModels = supportModels; + ModelsRegistry.registerModel(this); + } + + public boolean wasDefault(){return false;} + + public boolean checkExecModel(AiNode node, ModelParam modelParam){ + boolean checkFlag = ObjectUtils.isEmpty(this.supportModels); + if (!checkFlag){ + for (String model : this.supportModels) { + //todo: 模型模糊匹配 + if (model.equals(modelParam.getModel())){ + checkFlag = true; + break; + } + } + } + return this.provider.equals(node.getProvider()) && checkFlag; + } + + public abstract Model buildMode(AiNode node, ModelParam modelParam); + + public void setOptionalValue(T value, java.util.function.Consumer setter) { + Optional.ofNullable(value).ifPresent(setter); + } + + +} diff --git a/commons/viewer-common-ai-model/src/main/java/xyz/thoughtset/viewer/common/ai/model/factory/ModelFactory.java b/commons/viewer-common-ai-model/src/main/java/xyz/thoughtset/viewer/common/ai/model/factory/ModelFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..966a82e5794319ed4deea49dcd42395b541bf412 --- /dev/null +++ b/commons/viewer-common-ai-model/src/main/java/xyz/thoughtset/viewer/common/ai/model/factory/ModelFactory.java @@ -0,0 +1,51 @@ +package xyz.thoughtset.viewer.common.ai.model.factory; + +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.slf4j.Slf4j; +import org.springframework.ai.chat.client.ChatClient; +import org.springframework.ai.chat.model.ChatModel; +import org.springframework.ai.model.Model; +import org.springframework.ai.model.tool.ToolCallingManager; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.lang.NonNull; +import org.springframework.stereotype.Component; +import xyz.thoughtset.viewer.common.ai.model.dao.ModelParamDao; +import xyz.thoughtset.viewer.common.ai.model.entity.AiNode; +import xyz.thoughtset.viewer.common.ai.model.entity.ModelParam; +import xyz.thoughtset.viewer.common.ai.model.entity.purpose.BaseModelSetting; +import xyz.thoughtset.viewer.common.ai.model.service.AiNodeService; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +@Slf4j +@Component +public class ModelFactory { + @Autowired + private ObjectMapper objectMapper; + @Autowired + private AiNodeService aiNodeService; + + @Bean + public ToolCallingManager toolCallingManager() { + return ToolCallingManager.builder().build(); + } + + + public Model buildModel(ModelParam modelParam){ + AiNode aiNode = aiNodeService.selectDetail(modelParam.getPid()); + ModelBuilder builder = ModelsRegistry.loadBuilder(aiNode, modelParam); + return builder.buildMode(aiNode, modelParam); + } + + public ChatClient.Builder clientBuilder(@NonNull ModelParam modelParam){ + ChatModel chatModel = (ChatModel) buildModel(modelParam); + + return ChatClient.builder(chatModel); + } + + + +} diff --git a/commons/viewer-common-ai-model/src/main/java/xyz/thoughtset/viewer/common/ai/model/factory/ModelsRegistry.java b/commons/viewer-common-ai-model/src/main/java/xyz/thoughtset/viewer/common/ai/model/factory/ModelsRegistry.java new file mode 100644 index 0000000000000000000000000000000000000000..ae2b5bcb977fce4038ebb8c75808b2d76be6c73f --- /dev/null +++ b/commons/viewer-common-ai-model/src/main/java/xyz/thoughtset/viewer/common/ai/model/factory/ModelsRegistry.java @@ -0,0 +1,43 @@ +package xyz.thoughtset.viewer.common.ai.model.factory; + + +import org.springframework.util.MultiValueMap; +import org.springframework.util.MultiValueMapAdapter; +import xyz.thoughtset.viewer.common.ai.model.entity.AiNode; +import xyz.thoughtset.viewer.common.ai.model.entity.ModelParam; + +import java.util.*; + + +public class ModelsRegistry { + private static final Map DEFAULT_MODEL_BUILDER_MAP = new HashMap(); + private static final MultiValueMap MODEL_BUILDER_MAP = new MultiValueMapAdapter<>(new HashMap<>()); + + public static void registerModel(ModelBuilder modelBuilder){ + String modelProvider = modelBuilder.getProvider(); + if (modelBuilder.wasDefault()){ + DEFAULT_MODEL_BUILDER_MAP.put(modelProvider,modelBuilder); + } + MODEL_BUILDER_MAP.add(modelProvider,modelBuilder); + } + + public static ModelBuilder loadBuilder(AiNode aiNode, ModelParam params){ + List list = MODEL_BUILDER_MAP.get(aiNode.getProvider()); + ModelBuilder targetBuilder = null; + for (ModelBuilder ele : list){ + if (ele.checkExecModel(aiNode,params)){ + targetBuilder = ele; + break; + } + } + if (targetBuilder == null){ + targetBuilder = DEFAULT_MODEL_BUILDER_MAP.get(aiNode.getProvider()); + } + return targetBuilder; + } + + public static Collection supportProvider(){ + return MODEL_BUILDER_MAP.keySet(); + } + +} diff --git a/commons/viewer-common-ai-model/src/main/java/xyz/thoughtset/viewer/common/ai/model/service/AiNodeService.java b/commons/viewer-common-ai-model/src/main/java/xyz/thoughtset/viewer/common/ai/model/service/AiNodeService.java new file mode 100644 index 0000000000000000000000000000000000000000..144acfceaa65066ba6359ef08b4ca992467ea926 --- /dev/null +++ b/commons/viewer-common-ai-model/src/main/java/xyz/thoughtset/viewer/common/ai/model/service/AiNodeService.java @@ -0,0 +1,11 @@ +package xyz.thoughtset.viewer.common.ai.model.service; + + +import xyz.thoughtset.viewer.common.ai.model.entity.AiNode; +import xyz.thoughtset.viewer.common.crud.core.service.BaseService; + +import java.util.List; + +public interface AiNodeService extends BaseService { + +} diff --git a/commons/viewer-common-ai-model/src/main/java/xyz/thoughtset/viewer/common/ai/model/service/AiNodeServiceImpl.java b/commons/viewer-common-ai-model/src/main/java/xyz/thoughtset/viewer/common/ai/model/service/AiNodeServiceImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..9d4906b652c15982c52f268b92feb08bcc619bba --- /dev/null +++ b/commons/viewer-common-ai-model/src/main/java/xyz/thoughtset/viewer/common/ai/model/service/AiNodeServiceImpl.java @@ -0,0 +1,51 @@ +package xyz.thoughtset.viewer.common.ai.model.service; + +import cn.zhxu.bs.BeanSearcher; +import cn.zhxu.bs.util.MapUtils; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.fasterxml.jackson.databind.JavaType; +import jakarta.annotation.PostConstruct; +import lombok.SneakyThrows; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.ObjectUtils; +import org.springframework.util.StringUtils; +import xyz.thoughtset.viewer.common.ai.model.dao.AiNodeDao; +import xyz.thoughtset.viewer.common.ai.model.entity.AiNode; +import xyz.thoughtset.viewer.common.crud.core.service.BaseServiceImpl; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +@Service +public class AiNodeServiceImpl extends BaseServiceImpl implements AiNodeService { + @SneakyThrows + @Override + public AiNode saveData(AiNode data) { + if (!ObjectUtils.isEmpty(data.getSettingMap())){ + data.setSettingStr(mapper.writeValueAsString(data.getSettingMap())); + } + if (!ObjectUtils.isEmpty(data.getHeaderMap())){ + data.setHeadersStr(mapper.writeValueAsString(data.getHeaderMap())); + } + return super.saveData(data); + } + + @Override + @SneakyThrows + public AiNode selectDetail(String pkey) { + AiNode data = super.selectDetail(pkey); + if (StringUtils.hasText(data.getSettingStr())){ + data.setSettingMap(mapper.readValue(data.getSettingStr(), Map.class)); + } + if (StringUtils.hasText(data.getHeadersStr())){ + data.setHeaderMap(mapper.readValue(data.getHeadersStr(), Map.class)); + } + return data; + } +} diff --git a/commons/viewer-common-ai-model/src/main/java/xyz/thoughtset/viewer/common/ai/model/service/ModelParamService.java b/commons/viewer-common-ai-model/src/main/java/xyz/thoughtset/viewer/common/ai/model/service/ModelParamService.java new file mode 100644 index 0000000000000000000000000000000000000000..5e46aa4f434d5406e77982f8ab421833ecb2c3a0 --- /dev/null +++ b/commons/viewer-common-ai-model/src/main/java/xyz/thoughtset/viewer/common/ai/model/service/ModelParamService.java @@ -0,0 +1,9 @@ +package xyz.thoughtset.viewer.common.ai.model.service; + + +import xyz.thoughtset.viewer.common.ai.model.entity.ModelParam; +import xyz.thoughtset.viewer.common.crud.core.service.BaseService; + +public interface ModelParamService extends BaseService { + +} diff --git a/commons/viewer-common-ai-model/src/main/java/xyz/thoughtset/viewer/common/ai/model/service/ModelParamServiceImpl.java b/commons/viewer-common-ai-model/src/main/java/xyz/thoughtset/viewer/common/ai/model/service/ModelParamServiceImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..f54fce1799f1467144c810c5c7c36791e646b216 --- /dev/null +++ b/commons/viewer-common-ai-model/src/main/java/xyz/thoughtset/viewer/common/ai/model/service/ModelParamServiceImpl.java @@ -0,0 +1,42 @@ +package xyz.thoughtset.viewer.common.ai.model.service; + +import lombok.SneakyThrows; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.ObjectUtils; +import org.springframework.util.StringUtils; +import xyz.thoughtset.viewer.common.ai.model.dao.ModelParamDao; +import xyz.thoughtset.viewer.common.ai.model.entity.ModelParam; +import xyz.thoughtset.viewer.common.ai.model.entity.ModelParam; +import xyz.thoughtset.viewer.common.ai.model.entity.purpose.BaseModelSetting; +import xyz.thoughtset.viewer.common.crud.core.service.BaseServiceImpl; + +import java.util.Map; + +@Service +public class ModelParamServiceImpl extends BaseServiceImpl implements ModelParamService { + @SneakyThrows + @Override + public ModelParam saveData(ModelParam data) { + if (!ObjectUtils.isEmpty(data.getModelArgs())){ + data.setSetting(mapper.writeValueAsString(data.getModelArgs())); + } + if (!ObjectUtils.isEmpty(data.getParamMap())){ + data.setParamJson(mapper.writeValueAsString(data.getParamMap())); + } + return super.saveData(data); + } + + @Override + @SneakyThrows + public ModelParam selectDetail(String pkey) { + ModelParam data = super.selectDetail(pkey); + if (StringUtils.hasText(data.getParamJson())){ + data.setParamMap(mapper.readValue(data.getParamJson(), Map.class)); + } + if (StringUtils.hasText(data.getSetting())){ + data.setModelArgs((BaseModelSetting) mapper.readValue(data.getSetting(), data.getPurpose().getSettingClass())); + } + return data; + } +} diff --git a/commons/viewer-common-ai-model/src/main/java/xyz/thoughtset/viewer/common/ai/model/utils/ModelBuilderHelper.java b/commons/viewer-common-ai-model/src/main/java/xyz/thoughtset/viewer/common/ai/model/utils/ModelBuilderHelper.java new file mode 100644 index 0000000000000000000000000000000000000000..0f00db5df7c55f5d9da7a221dfb36f154be804c8 --- /dev/null +++ b/commons/viewer-common-ai-model/src/main/java/xyz/thoughtset/viewer/common/ai/model/utils/ModelBuilderHelper.java @@ -0,0 +1,25 @@ +package xyz.thoughtset.viewer.common.ai.model.utils; + +import lombok.NonNull; +import lombok.experimental.UtilityClass; +import org.springframework.util.ObjectUtils; +import xyz.thoughtset.viewer.common.ai.model.entity.ModelParam; + +import java.util.Map; +import java.util.function.Consumer; + +@UtilityClass +public class ModelBuilderHelper { + +// ModelBuilderHelper.setIfNotNull(modelParam, "topP", builder::topP); + public static void setIfNotNull(ModelParam modelParam, String key, Consumer setter) { + Map map = modelParam.getParamMap(); + setIfNotNull(map, key, setter); + } + public static void setIfNotNull(@NonNull Map map, String key, Consumer setter) { + T value = (T) map.get(key); + if (value != null) { + setter.accept(value); + } + } +} diff --git a/commons/viewer-common-ai-model/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/commons/viewer-common-ai-model/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 0000000000000000000000000000000000000000..2ca0678a331bd0562aad17ab181f7b0f4e58b337 --- /dev/null +++ b/commons/viewer-common-ai-model/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1 @@ +xyz.thoughtset.viewer.common.ai.model.CommonAIModelAutoConfiguration \ No newline at end of file diff --git a/commons/viewer-common-api/src/main/java/xyz/thoughtset/viewer/common/api/advice/SuccessResponseAdvice.java b/commons/viewer-common-api/src/main/java/xyz/thoughtset/viewer/common/api/advice/SuccessResponseAdvice.java index 1d834028a676f50dd49d085046327790b0031e75..6718a479f9593d125249033245195bf1a41e2894 100644 --- a/commons/viewer-common-api/src/main/java/xyz/thoughtset/viewer/common/api/advice/SuccessResponseAdvice.java +++ b/commons/viewer-common-api/src/main/java/xyz/thoughtset/viewer/common/api/advice/SuccessResponseAdvice.java @@ -20,7 +20,9 @@ public class SuccessResponseAdvice { @Around("execution(* xyz.thoughtset.viewer.common.api.controller.BaseController+.*(..))") public Object handleControllerMethod(ProceedingJoinPoint pjp) throws Throwable { Object body; - try{ body = pjp.proceed();} + try{ + body = pjp.proceed(); + } catch (Exception e) {throw e;} if (body instanceof Result) { return body; diff --git a/commons/viewer-common-core/src/main/java/xyz/thoughtset/viewer/common/core/enums/EnumValue.java b/commons/viewer-common-core/src/main/java/xyz/thoughtset/viewer/common/core/enums/EnumValue.java new file mode 100644 index 0000000000000000000000000000000000000000..c1e4c9a609f37df89fa9b2746882385d27d55125 --- /dev/null +++ b/commons/viewer-common-core/src/main/java/xyz/thoughtset/viewer/common/core/enums/EnumValue.java @@ -0,0 +1,11 @@ +package xyz.thoughtset.viewer.common.core.enums; + +import java.io.Serializable; + +public interface EnumValue { + default public String getTitle() { + return null; + } + public T getValue(); + +} diff --git a/commons/viewer-common-core/src/main/java/xyz/thoughtset/viewer/common/core/util/ExtractConstantFieldUtil.java b/commons/viewer-common-core/src/main/java/xyz/thoughtset/viewer/common/core/util/ExtractConstantFieldUtil.java new file mode 100644 index 0000000000000000000000000000000000000000..6c92c298b112762ec7fdfd1c03ead71a396e4bb1 --- /dev/null +++ b/commons/viewer-common-core/src/main/java/xyz/thoughtset/viewer/common/core/util/ExtractConstantFieldUtil.java @@ -0,0 +1,23 @@ +package xyz.thoughtset.viewer.common.core.util; + +import com.baomidou.mybatisplus.annotation.IEnum; +import org.springframework.util.ObjectUtils; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class ExtractConstantFieldUtil { + + public static List extractEnumToList(Class clazz) { + IEnum[] enumConstants = clazz.getEnumConstants(); + if (ObjectUtils.isEmpty(enumConstants)) return Collections.EMPTY_LIST; + List list = new ArrayList(enumConstants.length); + for (IEnum enumConstant : enumConstants) { + list.add(enumConstant.getValue()); + } + return list; + } + + +} diff --git a/executor/viewer-executor-blocks/pom.xml b/executor/viewer-executor-blocks/pom.xml index b02a35e0f1da52d5d09238a4fd7a5f2272ce9767..add729034bfe7fd511b5038a36daccbaaeb17d10 100644 --- a/executor/viewer-executor-blocks/pom.xml +++ b/executor/viewer-executor-blocks/pom.xml @@ -26,6 +26,25 @@ xyz.thoughtset.viewer viewer-modules-fun + + org.springframework.ai + spring-ai-model + ${springai.version} + true + + + + xyz.thoughtset.viewer + viewer-models-deepseek + + + xyz.thoughtset.viewer + viewer-models-openai + + + xyz.thoughtset.viewer + viewer-models-zhipuai + \ No newline at end of file diff --git a/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/entity/AISupportBody.java b/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/entity/AISupportBody.java new file mode 100644 index 0000000000000000000000000000000000000000..cb9e70f50039c6b8dad70f58020fbc3c29714ed1 --- /dev/null +++ b/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/entity/AISupportBody.java @@ -0,0 +1,16 @@ +package xyz.thoughtset.viewer.executor.blocks.entity; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public abstract class AISupportBody extends BaseBlockBody { + + protected String modelId; + protected String userMsg; + protected Boolean jsonType; + +} diff --git a/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/entity/BaseBlockBody.java b/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/entity/BaseBlockBody.java index fd6ce83602fc64e224089f15fe5837e095398eb4..6b9454dcc28bae44e742e65fdaecfb207e40b897 100644 --- a/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/entity/BaseBlockBody.java +++ b/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/entity/BaseBlockBody.java @@ -11,11 +11,22 @@ import java.util.List; @Data @NoArgsConstructor @AllArgsConstructor -public class BaseBlockBody { +public abstract class BaseBlockBody { protected List bodyEles; + protected String bodyType = supportType().getType(); public int listSize() { return !ObjectUtils.isEmpty(bodyEles) ? bodyEles.size()+2 : 0; } + protected abstract BlockTypeEnum supportType(); + + public String getBodyType() { + return supportType().getType(); + } + + public void setBodyType(String bodyType) { + this.bodyType = supportType().getType(); + } + } diff --git a/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/entity/BlockTypeEnum.java b/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/entity/BlockTypeEnum.java index 36b12f1513fd9e4297c0306ececca47ede18a7f1..5f30f845fe84e79ae7d21e9bd0ab24299778839f 100644 --- a/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/entity/BlockTypeEnum.java +++ b/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/entity/BlockTypeEnum.java @@ -16,6 +16,10 @@ public enum BlockTypeEnum { // PARALLEL("parallel", ParallelBody.class), // MCP MCP("mcp", MCPBody.class), + // FunctionCall + FUNCTION_CALL("FunctionCall", FunctionCallBody.class), + // ExecAI + EXECAI("ExecAI", ExecAIBody.class), VALUE("value", ValueBody.class), // 单体块 DEFAULT("default", SingleBody.class), diff --git a/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/entity/ChooseBody.java b/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/entity/ChooseBody.java index 31bf3ca79853904a75b63701b7210801d355f24a..6666606acdbf8c03713f69a84b9716206cc68d31 100644 --- a/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/entity/ChooseBody.java +++ b/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/entity/ChooseBody.java @@ -9,6 +9,11 @@ import lombok.NoArgsConstructor; @AllArgsConstructor public class ChooseBody extends BaseBlockBody { private String caseRepx; - private String bodyType = BlockTypeEnum.CHOOSE.getType(); + // private String bodyType = BlockTypeEnum.CHOOSE.getType(); + + @Override + protected BlockTypeEnum supportType() { + return BlockTypeEnum.CHOOSE; + } } diff --git a/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/entity/ExecAIBody.java b/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/entity/ExecAIBody.java new file mode 100644 index 0000000000000000000000000000000000000000..494135689bcf641f582ae2310853705b919a3426 --- /dev/null +++ b/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/entity/ExecAIBody.java @@ -0,0 +1,19 @@ +package xyz.thoughtset.viewer.executor.blocks.entity; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +//@NoArgsConstructor +//@AllArgsConstructor +public class ExecAIBody extends AISupportBody { + // private String bodyType = BlockTypeEnum.EXECAI.getType(); + + @Override + protected BlockTypeEnum supportType() { + return BlockTypeEnum.EXECAI; + } + + +} diff --git a/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/entity/FunctionCallBody.java b/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/entity/FunctionCallBody.java new file mode 100644 index 0000000000000000000000000000000000000000..eb51b90521521bbfd769b3e39f4f385b78bdaf03 --- /dev/null +++ b/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/entity/FunctionCallBody.java @@ -0,0 +1,19 @@ +package xyz.thoughtset.viewer.executor.blocks.entity; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +//@NoArgsConstructor +//@AllArgsConstructor +public class FunctionCallBody extends AISupportBody { + // private String bodyType = BlockTypeEnum.FUNCTION_CALL.getType(); + + @Override + protected BlockTypeEnum supportType() { + return BlockTypeEnum.FUNCTION_CALL; + } + + +} diff --git a/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/entity/IteratorBody.java b/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/entity/IteratorBody.java index a80f9b06b8a871cd1770b7b455c5734c2d898cd1..6db637831800a353972ffb0ce3b60262a6c0f7ca 100644 --- a/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/entity/IteratorBody.java +++ b/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/entity/IteratorBody.java @@ -9,6 +9,12 @@ import lombok.NoArgsConstructor; @AllArgsConstructor public class IteratorBody extends BaseBlockBody { private String iteratorRepx; - private String bodyType = BlockTypeEnum.ITERATOR.getType(); + // private String bodyType = BlockTypeEnum.ITERATOR.getType(); + + @Override + protected BlockTypeEnum supportType() { + return BlockTypeEnum.ITERATOR; + } + } diff --git a/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/entity/LoopBody.java b/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/entity/LoopBody.java index e113460e7320152a2aaf8b3ac148ddf84034553f..2a04ad7ccca393c3e2dc9c58db2e67c285f6cefa 100644 --- a/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/entity/LoopBody.java +++ b/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/entity/LoopBody.java @@ -10,6 +10,12 @@ import lombok.NoArgsConstructor; public class LoopBody extends BaseBlockBody { private String loopRepx; private boolean doFirst = false; - private String bodyType = BlockTypeEnum.LOOP.getType(); +// private String bodyType = BlockTypeEnum.LOOP.getType(); + + @Override + protected BlockTypeEnum supportType() { + return BlockTypeEnum.LOOP; + } + } diff --git a/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/entity/MCPBody.java b/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/entity/MCPBody.java index c24fb984c409cf9c7027f2d9f26ad2bab59e7261..4c9eaab114a35192a354ec8aff3897cf1f5bf1f8 100644 --- a/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/entity/MCPBody.java +++ b/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/entity/MCPBody.java @@ -5,9 +5,15 @@ import lombok.Data; import lombok.NoArgsConstructor; @Data -@NoArgsConstructor -@AllArgsConstructor +//@NoArgsConstructor +//@AllArgsConstructor public class MCPBody extends BaseBlockBody { - private String bodyType = BlockTypeEnum.MCP.getType(); + +// private String bodyType = BlockTypeEnum.MCP.getType(); + + @Override + protected BlockTypeEnum supportType() { + return BlockTypeEnum.MCP; + } } diff --git a/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/entity/SingleBody.java b/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/entity/SingleBody.java index 22ce9b432806a1ee1eb579a3c6c07ddea33aa34e..518343ed263a990fc73b26e63c6c466333f2a7fe 100644 --- a/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/entity/SingleBody.java +++ b/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/entity/SingleBody.java @@ -6,13 +6,20 @@ import lombok.NoArgsConstructor; import xyz.thoughtset.viewer.modules.step.entity.block.BlockBodyEle; @Data -@NoArgsConstructor -@AllArgsConstructor +//@NoArgsConstructor +//@AllArgsConstructor public class SingleBody extends BaseBlockBody { - private String bodyType = BlockTypeEnum.SINGLE.getType(); + +// private String bodyType = BlockTypeEnum.SINGLE.getType(); public BlockBodyEle getNode(){ return this.getBodyEles().get(0); } + @Override + protected BlockTypeEnum supportType() { + return BlockTypeEnum.SINGLE; + } + + } diff --git a/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/entity/TaskBody.java b/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/entity/TaskBody.java index 0f3183bbd8e67170e3295cf6db90f4712dbc74c0..fc0664c989010a66e0a08d87e230f33443202001 100644 --- a/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/entity/TaskBody.java +++ b/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/entity/TaskBody.java @@ -5,9 +5,16 @@ import lombok.Data; import lombok.NoArgsConstructor; @Data -@NoArgsConstructor -@AllArgsConstructor +//@NoArgsConstructor +//@AllArgsConstructor public class TaskBody extends BaseBlockBody { - private String bodyType = BlockTypeEnum.TASK.getType(); + +// private String bodyType = BlockTypeEnum.TASK.getType(); + + @Override + protected BlockTypeEnum supportType() { + return BlockTypeEnum.TASK; + } + } diff --git a/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/entity/TransposeBody.java b/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/entity/TransposeBody.java index 492d861e5a9ca9a9c91f6ed82d27beefcb678964..68fc38a21ec590d1088c67f6069526fc1c5706b6 100644 --- a/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/entity/TransposeBody.java +++ b/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/entity/TransposeBody.java @@ -9,6 +9,13 @@ import lombok.NoArgsConstructor; @AllArgsConstructor public class TransposeBody extends BaseBlockBody { private String targetRepx; - private String bodyType = BlockTypeEnum.TRANSPOSE.getType(); + +// private String bodyType = BlockTypeEnum.TRANSPOSE.getType(); + + @Override + protected BlockTypeEnum supportType() { + return BlockTypeEnum.TRANSPOSE; + } + } diff --git a/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/entity/ValueBody.java b/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/entity/ValueBody.java index 97b75aec3790f58352c78bfa35d01f6720654774..90fe9bd884effeed739f4d3e1be2ee72900c841e 100644 --- a/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/entity/ValueBody.java +++ b/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/entity/ValueBody.java @@ -5,9 +5,15 @@ import lombok.Data; import lombok.NoArgsConstructor; @Data -@NoArgsConstructor -@AllArgsConstructor +//@NoArgsConstructor +//@AllArgsConstructor public class ValueBody extends BaseBlockBody { - private String bodyType = BlockTypeEnum.VALUE.getType(); +// private String bodyType = BlockTypeEnum.VALUE.getType(); + + @Override + protected BlockTypeEnum supportType() { + return BlockTypeEnum.VALUE; + } + } diff --git a/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/executor/AbstractBlockExecutor.java b/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/executor/AbstractBlockExecutor.java index b7d9786c32dca4c4887e5d8f1757beea9775a002..c88ec12e5c08c203c52017d259963193cad4cd2f 100644 --- a/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/executor/AbstractBlockExecutor.java +++ b/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/executor/AbstractBlockExecutor.java @@ -1,5 +1,6 @@ package xyz.thoughtset.viewer.executor.blocks.executor; +import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import lombok.SneakyThrows; import org.springframework.beans.factory.InitializingBean; @@ -12,6 +13,7 @@ import xyz.thoughtset.viewer.common.exc.exceptions.ExecException; import xyz.thoughtset.viewer.executor.blocks.entity.BaseBlockBody; import xyz.thoughtset.viewer.executor.blocks.entity.BlockTypeEnum; import xyz.thoughtset.viewer.executor.blocks.entity.BodyEle; +import xyz.thoughtset.viewer.executor.blocks.utlis.BlockArgsUtils; import xyz.thoughtset.viewer.modules.ds.core.factory.ExecutorManager; import xyz.thoughtset.viewer.executor.blocks.constants.NodeConstant; import xyz.thoughtset.viewer.modules.step.entity.BlockParam; @@ -35,6 +37,7 @@ public abstract class AbstractBlockExecutor implements protected ObjectMapper objectMapper; @Autowired protected BlockExecutorManager blockExecutorManager; + protected TypeReference DATA_TYPE = new TypeReference>>() {}; @Override public void afterPropertiesSet() throws Exception { @@ -52,7 +55,6 @@ public abstract class AbstractBlockExecutor implements if (superClass instanceof ParameterizedType) { // 获取实际类型参数 Type[] typeArgs = ((ParameterizedType) superClass).getActualTypeArguments(); -// System.out.println("T's type: " + typeArgs[0]); supportType = BlockTypeEnum.fromClass((Class) typeArgs[0]); } } @@ -69,33 +71,20 @@ public abstract class AbstractBlockExecutor implements } body.setBodyEles((List) block.getBodys()); if (ObjectUtils.isEmpty(body.getBodyEles()) + && !BlockTypeEnum.EXECAI.equals(supportType) && !BlockTypeEnum.TRANSPOSE.equals(supportType)) { return null; } - return doQuery(block, body, new HashMap<>(),parser, context); - } - abstract Object doQuery(BlockInfo block, T body, Map params, ExpressionParser parser,StandardEvaluationContext context) throws ExecException; - - protected Map filterParams(BlockBodyEle bodyEle,Map contentMap, ExpressionParser parser,StandardEvaluationContext context){ - Map tmpParamsMap = new HashMap(); - List params = bodyEle.getParams(); - if (Objects.nonNull(params)){ - for (EleParam blockParam : params){ - if(!StringUtils.hasText(blockParam.getDataExp())){ - continue; - } - String exp =blockParam.getDataExp(); - exp = blockParam.getDataExp().startsWith("#")?exp:"#"+exp; - Object value = parser.parseExpression(exp).getValue(context); - context.setVariable(blockParam.getParamId(), value); - tmpParamsMap.put(blockParam.getParamId(), value); - } + if (ObjectUtils.isEmpty(params)) { + params = new HashMap<>(); } - return tmpParamsMap; + return doQuery(block, body, params,parser, context); } + protected abstract Object doQuery(BlockInfo block, T body, Map params, ExpressionParser parser,StandardEvaluationContext context) throws ExecException; + protected Object execNode(BlockBodyEle ele, Map params, ExpressionParser parser, StandardEvaluationContext context){ - Map tmpMap = filterParams(ele, params, parser, context); + Map tmpMap = BlockArgsUtils.filterParams(ele, parser, context); Object val = ele.eleWasFun()? blockExecutorManager.execBlocks(ele.getEleId(),tmpMap,parser): executorManager.execute(ele.getEleId(),tmpMap); if (ObjectUtils.isEmpty(val) || !StringUtils.hasText(ele.getValNum())) { @@ -136,6 +125,8 @@ public abstract class AbstractBlockExecutor implements return val; } + + protected void putItVal(int index, Map params,StandardEvaluationContext context,Object val){ String key = NodeConstant.getDataNodeWithNum(index); params.put(key, val); diff --git a/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/executor/BlockExecutorManager.java b/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/executor/BlockExecutorManager.java index be997792a38a68ea3aa7f9709012e06cc4c06aae..6d6ff9db33677544de04c9f817453235df77d76c 100644 --- a/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/executor/BlockExecutorManager.java +++ b/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/executor/BlockExecutorManager.java @@ -45,14 +45,13 @@ public class BlockExecutorManager { for (BlockInfo block : blocks) { Object queryResult; try{ - //todo: block执行 blockInfoService.loadBlockEles(block); queryResult = ExecutorRegistry.findExecutor(block.getBodyType()) .executeQuery(block, parser, contentMap,context); -// queryResult = blockExecutorManager.(block.getId(), params); }catch (ExecException e){ throw e.addApiId(funId); }catch (Exception e){ + e.printStackTrace(); ExecException exc = ExcInfo.buildAndThrowExc(e,params); exc.addBlockId(block.getId()); exc.addApiId(funId); @@ -100,6 +99,9 @@ public class BlockExecutorManager { for(FunParam param : inputParams) { String key = param.getTitle(); Object paramValue = searchMap.get(key); + if (paramValue == null) { + paramValue = searchMap.get(param.getId()); + } if (paramValue == null) { paramValue = param.getDefaultVal(); } diff --git a/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/executor/ExecAIBlockExecutor.java b/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/executor/ExecAIBlockExecutor.java new file mode 100644 index 0000000000000000000000000000000000000000..a9a450f84b725e980b893824db6a8d5298d1d759 --- /dev/null +++ b/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/executor/ExecAIBlockExecutor.java @@ -0,0 +1,63 @@ +package xyz.thoughtset.viewer.executor.blocks.executor; + +import org.springframework.ai.chat.client.ChatClient; +import org.springframework.ai.model.Model; +import org.springframework.expression.ExpressionParser; +import org.springframework.expression.spel.support.StandardEvaluationContext; +import org.springframework.stereotype.Component; +import org.springframework.util.StringUtils; +import xyz.thoughtset.viewer.common.ai.model.entity.ModelParam; +import xyz.thoughtset.viewer.common.exc.exceptions.ExecException; +import xyz.thoughtset.viewer.executor.blocks.entity.BlockTypeEnum; +import xyz.thoughtset.viewer.executor.blocks.entity.ExecAIBody; +import xyz.thoughtset.viewer.executor.blocks.entity.ValueBody; +import xyz.thoughtset.viewer.executor.blocks.executor.ai.AbstractAISupportBlockExecutor; +import xyz.thoughtset.viewer.modules.step.entity.block.BlockBodyEle; +import xyz.thoughtset.viewer.modules.step.entity.block.BlockInfo; +import xyz.thoughtset.viewer.modules.step.entity.block.EleParam; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +@Component +public class ExecAIBlockExecutor extends AbstractAISupportBlockExecutor { + + + @Override + protected Object doQuery(BlockInfo block, ExecAIBody body, Map params, ExpressionParser parser, StandardEvaluationContext context) throws ExecException { + HashMap resultMaps = new HashMap<>(params); +// BlockBodyEle bodyEle = block.firstBody(); +// List eleParams = bodyEle.getParams(); +// if (Objects.nonNull(eleParams)){ +// int size = eleParams.size(); +// for (EleParam blockParam : eleParams){ +// Object value = null; +// if(StringUtils.hasLength(blockParam.getDataExp())){ +// String exp =blockParam.getDataExp(); +// exp = blockParam.getDataExp().startsWith("#")?exp:"#"+exp; +// value = parser.parseExpression(exp).getValue(context); +// } +// //qbid作为值对应名称进行存入 +// String key = blockParam.getParamId(); +// if (StringUtils.hasText(key)){ +// context.setVariable(key, value); +// params.put(key, value); +// resultMaps.put(key, value); +// } else if (size == 1) { +// return value; +// } +// } +// } +// ModelParam modelParam = loadModelParam(body); +// String userPrompt = fillPrompt(body.getUserMsg(), parser, context); +// String systemPrompt = fillPrompt(modelParam.getSystemPrompt(), parser, context); +// Model aiModel = modelFactory.buildModel(modelParam); +// if (StringUtils.hasText(systemPrompt)){ +// builder.defaultSystem(systemPrompt); +// } +// ChatClient client = builder.build(); + return null; + } +} diff --git a/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/executor/FunctionCallingBlockExecutor.java b/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/executor/FunctionCallingBlockExecutor.java new file mode 100644 index 0000000000000000000000000000000000000000..45c6fbc4da88310aafec3c8cc5ed045aa5ea6987 --- /dev/null +++ b/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/executor/FunctionCallingBlockExecutor.java @@ -0,0 +1,194 @@ +package xyz.thoughtset.viewer.executor.blocks.executor; + +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.springframework.ai.chat.client.ChatClient; +import org.springframework.ai.chat.client.ChatClientResponse; +import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor; +import org.springframework.ai.chat.memory.ChatMemory; +import org.springframework.ai.chat.memory.MessageWindowChatMemory; +import org.springframework.ai.chat.messages.*; +import org.springframework.ai.chat.model.ChatResponse; +import org.springframework.ai.chat.prompt.ChatOptions; +import org.springframework.ai.chat.prompt.DefaultChatOptions; +import org.springframework.ai.chat.prompt.Prompt; +import org.springframework.ai.converter.ListOutputConverter; +import org.springframework.ai.deepseek.DeepSeekChatOptions; +import org.springframework.ai.model.tool.ToolCallingChatOptions; +import org.springframework.ai.model.tool.ToolCallingManager; +import org.springframework.ai.model.tool.ToolExecutionResult; +import org.springframework.ai.tool.ToolCallback; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.expression.ExpressionParser; +import org.springframework.expression.spel.support.StandardEvaluationContext; +import org.springframework.lang.NonNull; +import org.springframework.stereotype.Component; +import org.springframework.util.ObjectUtils; +import org.springframework.util.StringUtils; +import xyz.thoughtset.viewer.common.ai.model.dao.ModelParamDao; +import xyz.thoughtset.viewer.common.ai.model.entity.ModelParam; +import xyz.thoughtset.viewer.common.ai.model.entity.purpose.ChatModelSetting; +import xyz.thoughtset.viewer.common.ai.model.factory.ModelFactory; +import xyz.thoughtset.viewer.common.exc.exceptions.ExecException; +import xyz.thoughtset.viewer.executor.blocks.entity.BlockTypeEnum; +import xyz.thoughtset.viewer.executor.blocks.entity.FunctionCallBody; +import xyz.thoughtset.viewer.executor.blocks.executor.ai.AbstractAISupportBlockExecutor; +import xyz.thoughtset.viewer.executor.blocks.tool.BlockToolCallbackProvider; +import xyz.thoughtset.viewer.executor.blocks.tool.FunctionCallBlockToolCallbackProvider; +import xyz.thoughtset.viewer.modules.step.entity.block.BlockBodyEle; +import xyz.thoughtset.viewer.modules.step.entity.block.BlockInfo; + +import java.util.*; +import java.util.concurrent.atomic.LongAdder; +import java.util.function.Function; +import java.util.stream.Collectors; + + +@Slf4j +@Component +public class FunctionCallingBlockExecutor extends AbstractAISupportBlockExecutor { +// @Autowired +// protected ModelParamDao modelParamDao; +// @Autowired +// protected ModelFactory modelFactory; + @Autowired + private ToolCallingManager toolCallingManager; + @Autowired + private FunctionCallBlockToolCallbackProvider provider; + + +//先选择函数,再加载参数执行函数 + @SneakyThrows + @Override + protected Object doQuery(BlockInfo block, FunctionCallBody body, Map params, ExpressionParser parser, StandardEvaluationContext context) throws ExecException { + ModelParam modelParam = loadModelParam(body); + ChatClient.Builder builder = modelFactory.clientBuilder(modelParam); + MessageWindowChatMemory chatMemory = MessageWindowChatMemory.builder() + .maxMessages(modelParam.getMaxMemory()) + .build(); +// ChatModelSetting settingObj = (ChatModelSetting) modelParam.getModelArgs(); + String limitSystemPrompt = + "选择适当的方法执行,由于部分参数存储在本地,对于非required参数,可以填入建议值或空值。预期值与方法执行结果不一致时,以方法结果为准。"; + String systemText = modelParam.chatSystemPrompt(); + if (body.getJsonType()!=null && body.getJsonType().booleanValue()){ +// systemText = """ +// 请只返回数组类型的JSON,不要任何额外说明,当后续要求与当前冲突时,以当前要求为准! +// 你是一个函数调用助手,请严格按照要求的格式返回结果,不要任何额外说明. +// 1.返回值必须是一个数组,数组的每一项是一个对象 +// 2.对象的key是函数参数名,value是对应的值 +// 3.如果没有值,请返回null,不要返回空字符串,不要省略该key +// 4.如果值是字符串,请确保值是合法的JSON字符串,如果值本身是一个JSON对象或数组,请直接返回该对象或数组,不要转义为字符串 +// 5.如果没有数据,请返回一个空数组,不要返回null,不要返回空对象,不要返回字符串 +// 6.请严格按照要求的格式返回,不要有任何多余的内容,不要有任何拼写错误,不要有任何语法错误""" + // 备用prompt2 +// """ +// 选择适当的方法执行。对于非必需参数,可使用建议值或空值(部分参数已本地存储)。若方法执行结果与预期值不一致,以方法执行结果为准。响应必须严格以JSON数组格式返回,不得包含任何其他内容。确保无拼写错误或语法错误。当后续要求与当前要求冲突时,以当前要求为准。 +// """ + systemText = limitSystemPrompt+""" + 最终结果必须按照JSON数组格式返回,不要有其余任何内容,不要有任何拼写错误,不要有任何语法错误,当后续要求与当前冲突时,以当前要求为准! + """ + + (StringUtils.hasText(systemText) ? systemText : ""); + } + String finalSystemText = systemText; + builder.defaultSystem(s->s.text(finalSystemText).params(params)); + List funs = body.getBodyEles(); + ToolCallingChatOptions.Builder toolCallingBuilder = ToolCallingChatOptions.builder() + .internalToolExecutionEnabled(false); + if (!ObjectUtils.isEmpty(funs)){ + Map funParamMap = funs.parallelStream().collect(Collectors.toMap( + BlockBodyEle::getEleId, Function.identity() + )); + builder.defaultToolCallbacks(provider.getToolCallbacks(block.getId(),funParamMap)); + + toolCallingBuilder = toolCallingBuilder.toolCallbacks(provider.getToolCallbacks(block.getId(),funParamMap)); + } + ChatClient client = builder + .defaultAdvisors(MessageChatMemoryAdvisor.builder(chatMemory).build()) + .build(); + ChatOptions chatOptions = toolCallingBuilder.build(); +// ChatClient.ChatClientRequestSpec spec = client +// .prompt() +// .options(chatOptions) +// .toolContext(params) +// .user(body.getUserMsg()); + UserMessage message = UserMessage.builder() + .text(body.getUserMsg()) + .build(); +// new UserMessage(body.getUserMsg(),params); + String chatId = block.getId()+ UUID.randomUUID(); + saveMegToChatMemory(chatId, Collections.singletonList(message), chatMemory); + Prompt chatPrompt = new Prompt(chatMemory.get(chatId),chatOptions); +// ChatClient.CallResponseSpec callResponseSpec = spec.call(); +// String val = callResponseSpec.content(); + //ToolCallingChatClientAdvisor + // ListOutputConverter + ChatResponse chatResponse = client + .prompt(chatPrompt) + .toolContext(params).call().chatResponse(); + // 处理可能的多轮工具调用 + List messageList = new ArrayList<>(); + while (chatResponse.hasToolCalls()) { + // 获取AI助手的响应消息 + AssistantMessage assistantMessage = chatResponse.getResult().getOutput(); + log.debug("***" + assistantMessage.getText()); + + // 获取AI要求调用的工具列表 + List toolCalls = assistantMessage.getToolCalls(); + toolCalls.forEach(toolCall -> { + log.debug("*** 准备调用工具{}:{},参数:({})", toolCall.type(), toolCall.name(), toolCall.arguments()); + }); + + // 执行工具调用 + ToolExecutionResult toolExecutionResult = null; + try { + toolExecutionResult = toolCallingManager.executeToolCalls(chatPrompt, chatResponse); + } catch (Exception e) { + log.error("调用工具失败", e); + messageList.add(new AssistantMessage("调用工具失败:" + e.getMessage())); + break; + } + + List toolResultMessages = toolExecutionResult.conversationHistory(); + log.debug("*** 执行结果" + toolResultMessages); + + Message lastMessage = toolResultMessages.get(toolResultMessages.size() - 1); + if (lastMessage.getMessageType() == MessageType.TOOL) { + ToolResponseMessage toolMessage = (ToolResponseMessage) lastMessage; + toolMessage.getMetadata().put("toolArguments", toolCalls); + messageList.add(toolMessage); + + // 记录每个工具调用的详细信息 + for (ToolResponseMessage.ToolResponse resp : toolMessage.getResponses()) { + log.debug("*** {}#{}#{}",resp.id(),resp.name(),resp.responseData()); + } + } + saveMegToChatMemory(chatId, toolResultMessages, chatMemory); + chatPrompt = new Prompt(chatMemory.get(chatId), chatOptions); + chatResponse = client + .prompt(chatPrompt) + .call() + .chatResponse(); + } + + String val = chatResponse.getResult().getOutput().getText(); + log.debug("===结果:{}", val); + Object result; + + try { +// List results = callResponseSpec.entity(new ParameterizedTypeReference>() {}); + result = objectMapper.readValue(val, DATA_TYPE); + }catch (Exception e){ + if (!e.getClass().getName().equals("com.fasterxml.jackson.core.JsonParseException")){ + log.error("错误结果:{}", val); + e.printStackTrace(); + } + result = val; + } + + return result; + } + + + +} diff --git a/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/executor/IteratorBlockExecutor.java b/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/executor/IteratorBlockExecutor.java index a17f46bc8a2ee19139876a5a7e70643b216f34df..c1c5b9a4ef716f573c76f2deaea5d0447aaab6b2 100644 --- a/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/executor/IteratorBlockExecutor.java +++ b/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/executor/IteratorBlockExecutor.java @@ -23,7 +23,7 @@ public class IteratorBlockExecutor extends AbstractBlockExecutor @Override - Object doQuery(BlockInfo block, IteratorBody body, Map params, ExpressionParser parser, StandardEvaluationContext context) throws ExecException { + protected Object doQuery(BlockInfo block, IteratorBody body, Map params, ExpressionParser parser, StandardEvaluationContext context) throws ExecException { List results = new ArrayList<>(); LongAdder index = new LongAdder(); context.setVariable(NodeConstant.DATA_NODE, results); diff --git a/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/executor/LoopBlockExecutor.java b/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/executor/LoopBlockExecutor.java index 5a125881d081ad47583675659431905cecede076..17518f5967f4f966e815eaf63e0c3264a0051f80 100644 --- a/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/executor/LoopBlockExecutor.java +++ b/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/executor/LoopBlockExecutor.java @@ -21,7 +21,7 @@ public class LoopBlockExecutor extends AbstractBlockExecutor { @Override - Object doQuery(BlockInfo block, LoopBody body, Map params, ExpressionParser parser, StandardEvaluationContext context) throws ExecException { + protected Object doQuery(BlockInfo block, LoopBody body, Map params, ExpressionParser parser, StandardEvaluationContext context) throws ExecException { List results = new ArrayList<>(); context.setVariable(NodeConstant.DATA_NODE, results); params.put(NodeConstant.DATA_NODE, results); diff --git a/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/executor/MCPBlockExecutor.java b/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/executor/MCPBlockExecutor.java index bfbe8c0109b399a803d005066809c551f75d711d..527a86be9073a3a4af70d5ba205370883588f4bc 100644 --- a/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/executor/MCPBlockExecutor.java +++ b/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/executor/MCPBlockExecutor.java @@ -6,6 +6,7 @@ import org.springframework.stereotype.Component; import org.springframework.util.ObjectUtils; import xyz.thoughtset.viewer.common.exc.exceptions.ExecException; import xyz.thoughtset.viewer.executor.blocks.constants.NodeConstant; +import xyz.thoughtset.viewer.executor.blocks.entity.BlockTypeEnum; import xyz.thoughtset.viewer.executor.blocks.entity.MCPBody; import xyz.thoughtset.viewer.executor.blocks.entity.MCPBody; import xyz.thoughtset.viewer.modules.step.entity.block.BlockBodyEle; @@ -20,10 +21,13 @@ import java.util.concurrent.atomic.LongAdder; //todo //@Component public class MCPBlockExecutor extends AbstractBlockExecutor { - + @Override + BlockTypeEnum getSupportType() { + return BlockTypeEnum.MCP; + } @Override - Object doQuery(BlockInfo block, MCPBody body, Map params, ExpressionParser parser, StandardEvaluationContext context) throws ExecException { + protected Object doQuery(BlockInfo block, MCPBody body, Map params, ExpressionParser parser, StandardEvaluationContext context) throws ExecException { List results = new ArrayList<>(); StringBuilder sb = new StringBuilder("你是方法调度助手,任务是从用户问题中选择最合适的方法,并给出参数。\n可用方法:\n"); // registry.getAll().forEach((name, regMethod) -> diff --git a/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/executor/SingleBlockExecutor.java b/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/executor/SingleBlockExecutor.java index cdb3d9816b03aaf861ad003a95fe2172c37c3ae6..ae4e58a8af5679387c9ab84fb78fd3580da47f30 100644 --- a/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/executor/SingleBlockExecutor.java +++ b/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/executor/SingleBlockExecutor.java @@ -24,7 +24,7 @@ public class SingleBlockExecutor extends AbstractBlockExecutor { } @Override - Object doQuery(BlockInfo block, SingleBody baseBlockBody, Map params, ExpressionParser parser, StandardEvaluationContext context) throws ExecException { + protected Object doQuery(BlockInfo block, SingleBody baseBlockBody, Map params, ExpressionParser parser, StandardEvaluationContext context) throws ExecException { return execNode(baseBlockBody.getNode(), params, parser, context); } diff --git a/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/executor/TaskBlockExecutor.java b/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/executor/TaskBlockExecutor.java index 901a7e8842147e24d4da98f4f8fcb86cfd00337a..2732eb1ba7e4587ccc42fbefb0279e63f821d8f3 100644 --- a/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/executor/TaskBlockExecutor.java +++ b/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/executor/TaskBlockExecutor.java @@ -19,7 +19,7 @@ public class TaskBlockExecutor extends AbstractBlockExecutor { @Override - Object doQuery(BlockInfo block, TaskBody baseBlockBody, Map params, ExpressionParser parser, StandardEvaluationContext context) throws ExecException { + protected Object doQuery(BlockInfo block, TaskBody baseBlockBody, Map params, ExpressionParser parser, StandardEvaluationContext context) throws ExecException { // Implement the logic for executing a loop block here // This is a placeholder implementation List results = new ArrayList<>(baseBlockBody.listSize()); diff --git a/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/executor/TransposeBlockExecutor.java b/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/executor/TransposeBlockExecutor.java index f3f3791b473e88f9dafcead7997ff1f653488c8e..9c2f37e90c85f10b8eadb826167851121864b32c 100644 --- a/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/executor/TransposeBlockExecutor.java +++ b/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/executor/TransposeBlockExecutor.java @@ -26,7 +26,7 @@ public class TransposeBlockExecutor extends AbstractBlockExecutor @Override - Object doQuery(BlockInfo block, TransposeBody body, Map params, ExpressionParser parser, StandardEvaluationContext context) throws ExecException { + protected Object doQuery(BlockInfo block, TransposeBody body, Map params, ExpressionParser parser, StandardEvaluationContext context) throws ExecException { //行列转换 String exp = body.getTargetRepx(); exp = exp.startsWith("#")?exp:"#"+exp; diff --git a/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/executor/ValueBlockExecutor.java b/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/executor/ValueBlockExecutor.java index fa4a4a13042208d5c1f3e1a03dcae81d7c37a592..cc9053dffae1fb59752f888149e5284e2e177617 100644 --- a/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/executor/ValueBlockExecutor.java +++ b/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/executor/ValueBlockExecutor.java @@ -55,7 +55,7 @@ public class ValueBlockExecutor extends AbstractBlockExecutor { } @Override - Object doQuery(BlockInfo block, ValueBody body, Map params, ExpressionParser parser, StandardEvaluationContext context) throws ExecException { + protected Object doQuery(BlockInfo block, ValueBody body, Map params, ExpressionParser parser, StandardEvaluationContext context) throws ExecException { return null; } } diff --git a/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/executor/ai/AbstractAISupportBlockExecutor.java b/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/executor/ai/AbstractAISupportBlockExecutor.java new file mode 100644 index 0000000000000000000000000000000000000000..4f06b0fc2ac9130a295e8e09ea4729439121007e --- /dev/null +++ b/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/executor/ai/AbstractAISupportBlockExecutor.java @@ -0,0 +1,75 @@ +package xyz.thoughtset.viewer.executor.blocks.executor.ai; + +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.springframework.ai.chat.memory.ChatMemory; +import org.springframework.ai.chat.messages.Message; +import org.springframework.ai.chat.messages.MessageType; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.expression.ExpressionParser; +import org.springframework.expression.spel.support.StandardEvaluationContext; +import org.springframework.lang.NonNull; +import org.springframework.util.StringUtils; +import xyz.thoughtset.viewer.common.ai.model.dao.ModelParamDao; +import xyz.thoughtset.viewer.common.ai.model.entity.ModelParam; +import xyz.thoughtset.viewer.common.ai.model.factory.ModelFactory; +import xyz.thoughtset.viewer.common.ai.model.service.ModelParamService; +import xyz.thoughtset.viewer.common.exc.exceptions.ExecException; +import xyz.thoughtset.viewer.executor.blocks.entity.AISupportBody; +import xyz.thoughtset.viewer.executor.blocks.entity.BaseBlockBody; +import xyz.thoughtset.viewer.executor.blocks.entity.FunctionCallBody; +import xyz.thoughtset.viewer.executor.blocks.executor.AbstractBlockExecutor; +import xyz.thoughtset.viewer.modules.step.entity.block.BlockInfo; + +import java.util.List; +import java.util.Map; + +@Slf4j +@SuppressWarnings({"unchecked","SpringJavaInjectionPointsAutowiringInspection"}) +public abstract class AbstractAISupportBlockExecutor extends AbstractBlockExecutor { + @Autowired + protected ModelParamService modelParamService; + @Autowired + protected ModelFactory modelFactory; + + protected void saveMegToChatMemory(String chatId, List messages, ChatMemory chatMemory) { + chatMemory.add(chatId, messages); + + List memoryMessage = chatMemory.get(chatId); + + long assistantCount = memoryMessage.stream() + .filter(m -> m.getMessageType() == MessageType.ASSISTANT) + .count(); + long toolCount = memoryMessage.stream() + .filter(m -> m.getMessageType() == MessageType.TOOL) + .count(); + + if (assistantCount != toolCount) { + log.error("消息不成对{},重置",memoryMessage); + chatMemory.clear(chatId); + chatMemory.add(chatId, memoryMessage.subList(1, memoryMessage.size())); + } + } + @SneakyThrows + protected ModelParam loadModelParam(@NonNull AISupportBody aiBody) throws ExecException { + String modelId = aiBody.getModelId(); + if (!StringUtils.hasText(modelId)){ + throw new Exception("模型参数未配置"); + } + ModelParam modelParam = modelParamService.selectDetail(modelId); + if (modelParam == null){ + throw new Exception("模型参数不存在"); + } + return modelParam; + } + + @SneakyThrows + protected static String fillPrompt(String template, ExpressionParser parser,StandardEvaluationContext context) { + if (!StringUtils.hasText(template)){ + return template; + } + // 使用 SpEL 表达式解析模板并返回填充后的结果 + return parser.parseExpression(template).getValue(context, String.class); + } + +} diff --git a/ai/viewer-ai-mcp-server/src/main/java/xyz/thoughtset/viewer/ai/mcp/server/BlockToolCallbackProvider.java b/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/tool/BlockToolCallbackProvider.java similarity index 81% rename from ai/viewer-ai-mcp-server/src/main/java/xyz/thoughtset/viewer/ai/mcp/server/BlockToolCallbackProvider.java rename to executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/tool/BlockToolCallbackProvider.java index dcf5117f1ce8d2fd8f63f05d4de35819eccde26b..ada0b806729b9f3a480f6007679b96951ecfff91 100644 --- a/ai/viewer-ai-mcp-server/src/main/java/xyz/thoughtset/viewer/ai/mcp/server/BlockToolCallbackProvider.java +++ b/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/tool/BlockToolCallbackProvider.java @@ -1,4 +1,4 @@ -package xyz.thoughtset.viewer.ai.mcp.server; +package xyz.thoughtset.viewer.executor.blocks.tool; import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.ai.tool.ToolCallback; @@ -7,8 +7,8 @@ import org.springframework.ai.tool.definition.DefaultToolDefinition; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; -import xyz.thoughtset.viewer.ai.mcp.server.json.ParamJsonSchemaGenerator; import xyz.thoughtset.viewer.executor.blocks.executor.BlockExecutorManager; +import xyz.thoughtset.viewer.executor.blocks.tool.json.ParamJsonSchemaGenerator; import xyz.thoughtset.viewer.modules.fun.service.FunInfoService; @Component @@ -26,7 +26,7 @@ public class BlockToolCallbackProvider implements ToolCallbackProvider { } public ToolCallback[] getToolCallbacks(String serverId) { - ToolCallback[] toolCallbacks = this.funInfoService.findMcpToolsWithInParam(serverId).stream() + ToolCallback[] toolCallbacks = this.funInfoService.findAIToolsWithInParam(serverId).stream() .map((funInfo) -> { String funTitle = funInfo.getTitle(); String funRemark = funInfo.getRemark(); @@ -35,7 +35,7 @@ public class BlockToolCallbackProvider implements ToolCallbackProvider { .description(StringUtils.hasText(funRemark) ? funRemark : funTitle) .inputSchema(ParamJsonSchemaGenerator.generateForFunInput(funInfo)) .build(); - return new BlockToolCallback(toolDefinition,blockExecutorManager,objectMapper,funInfo.getId()); + return new MCPServerBlockToolCallback(toolDefinition,blockExecutorManager,objectMapper,funInfo.getId()); }) .toArray(ToolCallback[]::new); return toolCallbacks; diff --git a/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/tool/FunctionCallBlockToolCallback.java b/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/tool/FunctionCallBlockToolCallback.java new file mode 100644 index 0000000000000000000000000000000000000000..461a55952cbfbd78b7f6914d6103ff446d10ece2 --- /dev/null +++ b/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/tool/FunctionCallBlockToolCallback.java @@ -0,0 +1,55 @@ +package xyz.thoughtset.viewer.executor.blocks.tool; + +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.springframework.ai.chat.model.ToolContext; +import org.springframework.ai.tool.ToolCallback; +import org.springframework.ai.tool.definition.ToolDefinition; +import org.springframework.ai.tool.metadata.ToolMetadata; +import org.springframework.expression.ExpressionParser; +import org.springframework.expression.spel.support.StandardEvaluationContext; +import org.springframework.util.ObjectUtils; +import xyz.thoughtset.viewer.executor.blocks.executor.BlockExecutorManager; +import xyz.thoughtset.viewer.executor.blocks.utlis.BlockArgsUtils; +import xyz.thoughtset.viewer.modules.step.entity.block.BlockBodyEle; + +import java.util.Map; + +@Slf4j +public record FunctionCallBlockToolCallback(ToolDefinition toolDefinition, + BlockBodyEle bodyEle, + BlockExecutorManager blockExecutorManager, + ObjectMapper objectMapper, String funId) implements ToolCallback { + + + @Override + public ToolDefinition getToolDefinition() { + return toolDefinition; + } + + @Override + public ToolMetadata getToolMetadata() { + return ToolCallback.super.getToolMetadata(); + } + + @Override + public String call(String toolInput) { + return call(toolInput,null); + } + + @SneakyThrows + @Override + public String call(String toolInput, ToolContext toolContext) { + Map paramMap = objectMapper.readValue(toolInput,Map.class); + Map contextMap = toolContext != null && toolContext.getContext() != null ? toolContext.getContext(): Map.of(); + if (!ObjectUtils.isEmpty(contextMap)){ + Map tmpMap = BlockArgsUtils.filterParams(bodyEle, contextMap); + paramMap.putAll(tmpMap); + } +// Map inputMap = BlockArgsUtils.filterParams(bodyEle, paramMap); + Object result = blockExecutorManager.execBlocks(funId,paramMap); + log.info(objectMapper.writeValueAsString(result)); + return objectMapper.writeValueAsString(result); + } +} diff --git a/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/tool/FunctionCallBlockToolCallbackProvider.java b/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/tool/FunctionCallBlockToolCallbackProvider.java new file mode 100644 index 0000000000000000000000000000000000000000..e4a90f947264faa065ca72e10382bf5870d6e7f7 --- /dev/null +++ b/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/tool/FunctionCallBlockToolCallbackProvider.java @@ -0,0 +1,50 @@ +package xyz.thoughtset.viewer.executor.blocks.tool; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.springframework.ai.tool.ToolCallback; +import org.springframework.ai.tool.ToolCallbackProvider; +import org.springframework.ai.tool.definition.DefaultToolDefinition; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.expression.ExpressionParser; +import org.springframework.expression.spel.support.StandardEvaluationContext; +import org.springframework.stereotype.Component; +import org.springframework.util.StringUtils; +import xyz.thoughtset.viewer.executor.blocks.executor.BlockExecutorManager; +import xyz.thoughtset.viewer.executor.blocks.tool.json.ParamJsonSchemaGenerator; +import xyz.thoughtset.viewer.modules.fun.dao.FunInfoDao; +import xyz.thoughtset.viewer.modules.fun.service.FunInfoService; +import xyz.thoughtset.viewer.modules.step.entity.block.BlockBodyEle; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +@Component +public class FunctionCallBlockToolCallbackProvider { + + @Autowired + private FunInfoDao funInfoDao; + @Autowired + private BlockExecutorManager blockExecutorManager; + @Autowired + private ObjectMapper objectMapper; + + + public ToolCallback[] getToolCallbacks(String blockId, Map funParamMap) { + + ToolCallback[] toolCallbacks = this.funInfoDao.findBlockFunsWithInParam(blockId).stream() + .map((funInfo) -> { + String funTitle = funInfo.getTitle(); + String funRemark = funInfo.getRemark(); + DefaultToolDefinition toolDefinition = (DefaultToolDefinition) DefaultToolDefinition.builder() + .name(funTitle) + .description(StringUtils.hasText(funRemark) ? funRemark : funTitle) + .inputSchema(ParamJsonSchemaGenerator.generateForFunInput(funInfo)) + .build(); + String funId = funInfo.getId(); + return new FunctionCallBlockToolCallback(toolDefinition,funParamMap.get(funId),blockExecutorManager,objectMapper,funId); + }) + .toArray(ToolCallback[]::new); + return toolCallbacks; + } + +} diff --git a/ai/viewer-ai-mcp-server/src/main/java/xyz/thoughtset/viewer/ai/mcp/server/BlockToolCallback.java b/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/tool/MCPServerBlockToolCallback.java similarity index 74% rename from ai/viewer-ai-mcp-server/src/main/java/xyz/thoughtset/viewer/ai/mcp/server/BlockToolCallback.java rename to executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/tool/MCPServerBlockToolCallback.java index 91194f92bb8df12efac1f9881c8a9591254ed907..fc576ad2fadc7b2ab525df8fa832c963971b2958 100644 --- a/ai/viewer-ai-mcp-server/src/main/java/xyz/thoughtset/viewer/ai/mcp/server/BlockToolCallback.java +++ b/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/tool/MCPServerBlockToolCallback.java @@ -1,7 +1,6 @@ -package xyz.thoughtset.viewer.ai.mcp.server; +package xyz.thoughtset.viewer.executor.blocks.tool; import com.fasterxml.jackson.databind.ObjectMapper; -import lombok.AllArgsConstructor; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.springframework.ai.chat.model.ToolContext; @@ -13,9 +12,9 @@ import xyz.thoughtset.viewer.executor.blocks.executor.BlockExecutorManager; import java.util.Map; @Slf4j -public record BlockToolCallback(ToolDefinition toolDefinition, - BlockExecutorManager blockExecutorManager, - ObjectMapper objectMapper,String funId) implements ToolCallback { +public record MCPServerBlockToolCallback(ToolDefinition toolDefinition, + BlockExecutorManager blockExecutorManager, + ObjectMapper objectMapper, String funId) implements ToolCallback { // private final ToolDefinition toolDefinition; // private final BlockExecutorManager blockExecutorManager; // private final ObjectMapper objectMapper; @@ -39,6 +38,9 @@ public record BlockToolCallback(ToolDefinition toolDefinition, @Override public String call(String toolInput, ToolContext toolContext) { Map paramMap = objectMapper.readValue(toolInput,Map.class); + if (toolContext != null && toolContext.getContext() != null){ + paramMap.putAll(toolContext.getContext()); + } Object result = blockExecutorManager.execBlocks(funId,paramMap); log.info(objectMapper.writeValueAsString(result)); return objectMapper.writeValueAsString(result); diff --git a/ai/viewer-ai-mcp-server/src/main/java/xyz/thoughtset/viewer/ai/mcp/server/json/ParamJsonSchemaGenerator.java b/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/tool/json/ParamJsonSchemaGenerator.java similarity index 98% rename from ai/viewer-ai-mcp-server/src/main/java/xyz/thoughtset/viewer/ai/mcp/server/json/ParamJsonSchemaGenerator.java rename to executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/tool/json/ParamJsonSchemaGenerator.java index a38e2e81f3e9ac1662d2eb0b12c39be220b779b1..a545bfa2e814e3621373b5236db2ca6d42dc6e19 100644 --- a/ai/viewer-ai-mcp-server/src/main/java/xyz/thoughtset/viewer/ai/mcp/server/json/ParamJsonSchemaGenerator.java +++ b/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/tool/json/ParamJsonSchemaGenerator.java @@ -1,4 +1,4 @@ -package xyz.thoughtset.viewer.ai.mcp.server.json; +package xyz.thoughtset.viewer.executor.blocks.tool.json; import com.fasterxml.jackson.databind.node.ObjectNode; import com.github.victools.jsonschema.generator.*; diff --git a/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/utlis/BlockArgsUtils.java b/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/utlis/BlockArgsUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..76da6b898c88e8fa7b6746b896c3cd7a7f3862cd --- /dev/null +++ b/executor/viewer-executor-blocks/src/main/java/xyz/thoughtset/viewer/executor/blocks/utlis/BlockArgsUtils.java @@ -0,0 +1,47 @@ +package xyz.thoughtset.viewer.executor.blocks.utlis; + +import org.springframework.expression.ExpressionParser; +import org.springframework.expression.spel.standard.SpelExpressionParser; +import org.springframework.expression.spel.support.StandardEvaluationContext; +import org.springframework.util.StringUtils; +import xyz.thoughtset.viewer.modules.step.entity.block.BlockBodyEle; +import xyz.thoughtset.viewer.modules.step.entity.block.EleParam; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +public class BlockArgsUtils { +// new SpelExpressionParser(), new StandardEvaluationContext() + public static Map filterParams(BlockBodyEle bodyEle, Map contentMap){ + ExpressionParser parser = new SpelExpressionParser(); + StandardEvaluationContext context = new StandardEvaluationContext(); + context.setVariables(contentMap); + return filterParams(false,bodyEle, parser, context); + } + + public static Map filterParams(BlockBodyEle bodyEle, ExpressionParser parser, StandardEvaluationContext context){ + return filterParams(true, bodyEle, parser, context); + } + + public static Map filterParams(boolean keyUseId,BlockBodyEle bodyEle, ExpressionParser parser, StandardEvaluationContext context){ + Map tmpParamsMap = new HashMap(); + List params = bodyEle.getParams(); + if (Objects.nonNull(params)){ + for (EleParam blockParam : params){ + if(!StringUtils.hasText(blockParam.getDataExp())){ + continue; + } + String exp =blockParam.getDataExp(); + exp = blockParam.getDataExp().startsWith("#")?exp:"#"+exp; + Object value = parser.parseExpression(exp).getValue(context); + String key = keyUseId?blockParam.getParamId():blockParam.getTitle(); + context.setVariable(key, value); + tmpParamsMap.put(key, value); + } + } + return tmpParamsMap; + } + +} diff --git a/images/AiNode.png b/images/AiNode.png new file mode 100644 index 0000000000000000000000000000000000000000..36a864d76bc71525458032d082b9caa99e7683bf Binary files /dev/null and b/images/AiNode.png differ diff --git a/images/FunctionCallBlock.png b/images/FunctionCallBlock.png new file mode 100644 index 0000000000000000000000000000000000000000..a6aeb53975efdfd0a955913f9f6ca3cddcd9a7e9 Binary files /dev/null and b/images/FunctionCallBlock.png differ diff --git a/images/FunctionCallResult.png b/images/FunctionCallResult.png new file mode 100644 index 0000000000000000000000000000000000000000..d46fef17068af6f894168653ae791c205935526b Binary files /dev/null and b/images/FunctionCallResult.png differ diff --git a/images/ModelParam.png b/images/ModelParam.png new file mode 100644 index 0000000000000000000000000000000000000000..116bb9ed62004b4492b4ba6e619bbc82c28d4b92 Binary files /dev/null and b/images/ModelParam.png differ diff --git a/models/pom.xml b/models/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..a90a5058ce1e1558ab577b6a92c022e2b22ec148 --- /dev/null +++ b/models/pom.xml @@ -0,0 +1,33 @@ + + + 4.0.0 + + xyz.thoughtset.viewer + Viewer + ${revision} + + + models + pom + + viewer-models-deepseek + viewer-models-openai + viewer-models-zhipuai + + + + 17 + 17 + UTF-8 + + + + + xyz.thoughtset.viewer + viewer-common-ai-model + + + + \ No newline at end of file diff --git a/models/viewer-models-deepseek/pom.xml b/models/viewer-models-deepseek/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..a6e22256006c042cc25d758426ddd0e1b97cc8c2 --- /dev/null +++ b/models/viewer-models-deepseek/pom.xml @@ -0,0 +1,28 @@ + + + 4.0.0 + + xyz.thoughtset.viewer + models + ${revision} + + + viewer-models-deepseek + + + 17 + 17 + UTF-8 + + + + + org.springframework.ai + spring-ai-deepseek + ${springai.version} + + + + \ No newline at end of file diff --git a/models/viewer-models-deepseek/src/main/java/xyz/thoughtset/viewer/models/deepseek/DeepSeekBuilder.java b/models/viewer-models-deepseek/src/main/java/xyz/thoughtset/viewer/models/deepseek/DeepSeekBuilder.java new file mode 100644 index 0000000000000000000000000000000000000000..d61948147552a223590e54c592b4a9de669813b5 --- /dev/null +++ b/models/viewer-models-deepseek/src/main/java/xyz/thoughtset/viewer/models/deepseek/DeepSeekBuilder.java @@ -0,0 +1,54 @@ +package xyz.thoughtset.viewer.models.deepseek; + +import lombok.NonNull; +import org.springframework.ai.chat.model.ChatModel; +import org.springframework.ai.deepseek.DeepSeekChatModel; +import org.springframework.ai.deepseek.DeepSeekChatOptions; +import org.springframework.ai.deepseek.api.DeepSeekApi; +import org.springframework.stereotype.Component; +import xyz.thoughtset.viewer.common.ai.model.entity.AiNode; +import xyz.thoughtset.viewer.common.ai.model.entity.ModelParam; +import xyz.thoughtset.viewer.common.ai.model.entity.purpose.ChatModelSetting; +import xyz.thoughtset.viewer.common.ai.model.factory.ModelBuilder; + +import java.util.Optional; + +@Component +public class DeepSeekBuilder extends ModelBuilder { + public DeepSeekBuilder() { + super("DeepSeek"); + } + + @Override + public boolean wasDefault() { + return true; + } + + @Override + public ChatModel buildMode(AiNode node, ModelParam modelParam) { + DeepSeekChatOptions.Builder builder = DeepSeekChatOptions.builder() + .model(modelParam.getModel()); + ChatModelSetting settingObj = (ChatModelSetting) modelParam.getModelArgs(); +// if(settingObj!=null) { +// if (settingObj.getMaxTokens() != null) { +// builder.maxTokens(settingObj.getMaxTokens().intValue()); +// } +// if (settingObj.getTemperature() != null) { +// builder.temperature(settingObj.getTemperature()); +// } +// } + Optional.ofNullable(settingObj).ifPresent(setting -> { + setOptionalValue(setting.getMaxTokens(), value -> builder.maxTokens(value.intValue())); + setOptionalValue(setting.getTemperature(), builder::temperature); + }); + DeepSeekChatOptions options = builder.build(); + DeepSeekApi api = DeepSeekApi.builder() + .baseUrl(node.getBaseUrl()) + .apiKey(node.getApiKey()).build(); + ChatModel chatModel = DeepSeekChatModel.builder() + .defaultOptions(options) + .deepSeekApi(api) + .build(); + return chatModel; + } +} diff --git a/models/viewer-models-deepseek/src/main/java/xyz/thoughtset/viewer/models/deepseek/ModelDeepseekAutoConfiguration.java b/models/viewer-models-deepseek/src/main/java/xyz/thoughtset/viewer/models/deepseek/ModelDeepseekAutoConfiguration.java new file mode 100644 index 0000000000000000000000000000000000000000..918b11477643ad2d20b02779717b8c687d23a331 --- /dev/null +++ b/models/viewer-models-deepseek/src/main/java/xyz/thoughtset/viewer/models/deepseek/ModelDeepseekAutoConfiguration.java @@ -0,0 +1,12 @@ +package xyz.thoughtset.viewer.models.deepseek; + +import org.mybatis.spring.annotation.MapperScan; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; + +@Configuration +@ComponentScan +@EnableConfigurationProperties +public class ModelDeepseekAutoConfiguration { +} diff --git a/models/viewer-models-deepseek/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/models/viewer-models-deepseek/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 0000000000000000000000000000000000000000..ed2a06c830b130fd21fee32442fc5f5de6f365ed --- /dev/null +++ b/models/viewer-models-deepseek/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1 @@ +xyz.thoughtset.viewer.models.deepseek.ModelDeepseekAutoConfiguration \ No newline at end of file diff --git a/models/viewer-models-openai/pom.xml b/models/viewer-models-openai/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..2ece91abc44f843ee0448ff20588a4fd5672ad1f --- /dev/null +++ b/models/viewer-models-openai/pom.xml @@ -0,0 +1,28 @@ + + + 4.0.0 + + xyz.thoughtset.viewer + models + ${revision} + + + viewer-models-openai + + + 17 + 17 + UTF-8 + + + + + org.springframework.ai + spring-ai-openai + ${springai.version} + + + + \ No newline at end of file diff --git a/models/viewer-models-openai/src/main/java/xyz/thoughtset/viewer/models/openai/ModelOpenAIAutoConfiguration.java b/models/viewer-models-openai/src/main/java/xyz/thoughtset/viewer/models/openai/ModelOpenAIAutoConfiguration.java new file mode 100644 index 0000000000000000000000000000000000000000..554512fadd9e34473b5e70c0af083d50e5f3f3bc --- /dev/null +++ b/models/viewer-models-openai/src/main/java/xyz/thoughtset/viewer/models/openai/ModelOpenAIAutoConfiguration.java @@ -0,0 +1,11 @@ +package xyz.thoughtset.viewer.models.openai; + +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; + +@Configuration +@ComponentScan +@EnableConfigurationProperties +public class ModelOpenAIAutoConfiguration { +} diff --git a/models/viewer-models-openai/src/main/java/xyz/thoughtset/viewer/models/openai/OpenAIChatBuilder.java b/models/viewer-models-openai/src/main/java/xyz/thoughtset/viewer/models/openai/OpenAIChatBuilder.java new file mode 100644 index 0000000000000000000000000000000000000000..6d698e90d1cee5a2e9c42ebf3f4a0c0467956a84 --- /dev/null +++ b/models/viewer-models-openai/src/main/java/xyz/thoughtset/viewer/models/openai/OpenAIChatBuilder.java @@ -0,0 +1,48 @@ +package xyz.thoughtset.viewer.models.openai; + +import org.springframework.ai.chat.model.ChatModel; +import org.springframework.ai.openai.OpenAiChatModel; +import org.springframework.ai.openai.OpenAiChatOptions; +import org.springframework.ai.openai.api.OpenAiApi; +import org.springframework.stereotype.Component; +import xyz.thoughtset.viewer.common.ai.model.entity.AiNode; +import xyz.thoughtset.viewer.common.ai.model.entity.ModelParam; +import xyz.thoughtset.viewer.common.ai.model.entity.purpose.ChatModelSetting; +import xyz.thoughtset.viewer.common.ai.model.factory.DefaultModelBuilder; +import xyz.thoughtset.viewer.common.ai.model.factory.ModelBuilder; + +import java.util.Optional; + +@Component +public class OpenAIChatBuilder extends DefaultModelBuilder { + public OpenAIChatBuilder() { + super("OpenAI"); + } + + + @Override + public ChatModel buildMode(AiNode node, ModelParam modelParam) { + OpenAiChatOptions.Builder builder = OpenAiChatOptions.builder() + .model(modelParam.getModel()); + ChatModelSetting settingObj = (ChatModelSetting) modelParam.getModelArgs(); +// if (settingObj.getMaxTokens() != null) { +// builder.maxTokens(settingObj.getMaxTokens().intValue()); +// } +// if (settingObj.getTemperature() != null) { +// builder.temperature(settingObj.getTemperature()); +// } + Optional.ofNullable(settingObj).ifPresent(setting -> { + setOptionalValue(setting.getMaxTokens(), value -> builder.maxTokens(value.intValue())); + setOptionalValue(setting.getTemperature(), builder::temperature); + }); + OpenAiChatOptions options = builder.build(); + OpenAiApi api = OpenAiApi.builder() + .baseUrl(node.getBaseUrl()) + .apiKey(node.getApiKey()).build(); + ChatModel chatModel = OpenAiChatModel.builder() + .defaultOptions(options) + .openAiApi(api) + .build(); + return chatModel; + } +} diff --git a/models/viewer-models-openai/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/models/viewer-models-openai/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 0000000000000000000000000000000000000000..f15a472e456f50e23803ecc61c5f205684db872b --- /dev/null +++ b/models/viewer-models-openai/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1 @@ +xyz.thoughtset.viewer.models.openai.ModelOpenAIAutoConfiguration \ No newline at end of file diff --git a/models/viewer-models-zhipuai/pom.xml b/models/viewer-models-zhipuai/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..466a601cf5d11e4a9ed1b8997f385fdc20d60ef6 --- /dev/null +++ b/models/viewer-models-zhipuai/pom.xml @@ -0,0 +1,28 @@ + + + 4.0.0 + + xyz.thoughtset.viewer + models + ${revision} + + + viewer-models-zhipuai + + + 17 + 17 + UTF-8 + + + + + org.springframework.ai + spring-ai-zhipuai + ${springai.version} + + + + \ No newline at end of file diff --git a/models/viewer-models-zhipuai/src/main/java/xyz/thoughtset/viewer/models/openai/ModelZhipuAIAutoConfiguration.java b/models/viewer-models-zhipuai/src/main/java/xyz/thoughtset/viewer/models/openai/ModelZhipuAIAutoConfiguration.java new file mode 100644 index 0000000000000000000000000000000000000000..47d02f6703281c196e220fe312dcba1efd981fa5 --- /dev/null +++ b/models/viewer-models-zhipuai/src/main/java/xyz/thoughtset/viewer/models/openai/ModelZhipuAIAutoConfiguration.java @@ -0,0 +1,11 @@ +package xyz.thoughtset.viewer.models.openai; + +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; + +@Configuration +@ComponentScan +@EnableConfigurationProperties +public class ModelZhipuAIAutoConfiguration { +} diff --git a/models/viewer-models-zhipuai/src/main/java/xyz/thoughtset/viewer/models/openai/ZhipuChatBuilder.java b/models/viewer-models-zhipuai/src/main/java/xyz/thoughtset/viewer/models/openai/ZhipuChatBuilder.java new file mode 100644 index 0000000000000000000000000000000000000000..ea2fd0e15efd45109f8a2bf89a57dcc804ecf8ca --- /dev/null +++ b/models/viewer-models-zhipuai/src/main/java/xyz/thoughtset/viewer/models/openai/ZhipuChatBuilder.java @@ -0,0 +1,36 @@ +package xyz.thoughtset.viewer.models.openai; + +import org.springframework.ai.chat.model.ChatModel; +import org.springframework.ai.zhipuai.ZhiPuAiChatModel; +import org.springframework.ai.zhipuai.ZhiPuAiChatOptions; +import org.springframework.ai.zhipuai.api.ZhiPuAiApi; +import org.springframework.stereotype.Component; +import xyz.thoughtset.viewer.common.ai.model.entity.AiNode; +import xyz.thoughtset.viewer.common.ai.model.entity.ModelParam; +import xyz.thoughtset.viewer.common.ai.model.entity.purpose.ChatModelSetting; +import xyz.thoughtset.viewer.common.ai.model.factory.DefaultModelBuilder; + +import java.util.Optional; + +@Component +public class ZhipuChatBuilder extends DefaultModelBuilder { + public ZhipuChatBuilder() { + super("ZhipuAI"); + } + + + @Override + public ChatModel buildMode(AiNode node, ModelParam modelParam) { + ZhiPuAiChatOptions.Builder builder = ZhiPuAiChatOptions.builder() + .model(modelParam.getModel()); + ChatModelSetting settingObj = (ChatModelSetting) modelParam.getModelArgs(); + Optional.ofNullable(settingObj).ifPresent(setting -> { + setOptionalValue(setting.getMaxTokens(), value -> builder.maxTokens(value.intValue())); + setOptionalValue(setting.getTemperature(), builder::temperature); + }); + ZhiPuAiChatOptions options = builder.build(); + ZhiPuAiApi api = new ZhiPuAiApi(node.getBaseUrl(), node.getApiKey()); + ChatModel chatModel = new ZhiPuAiChatModel(api, options); + return chatModel; + } +} diff --git a/models/viewer-models-zhipuai/src/main/java/xyz/thoughtset/viewer/models/openai/ZhipuImageBuilder.java b/models/viewer-models-zhipuai/src/main/java/xyz/thoughtset/viewer/models/openai/ZhipuImageBuilder.java new file mode 100644 index 0000000000000000000000000000000000000000..30980663faf801dd45f48f30c2b51a7a8948bab5 --- /dev/null +++ b/models/viewer-models-zhipuai/src/main/java/xyz/thoughtset/viewer/models/openai/ZhipuImageBuilder.java @@ -0,0 +1,41 @@ +package xyz.thoughtset.viewer.models.openai; + +import org.springframework.ai.chat.model.ChatModel; +import org.springframework.ai.model.Model; +import org.springframework.ai.retry.RetryUtils; +import org.springframework.ai.zhipuai.ZhiPuAiChatModel; +import org.springframework.ai.zhipuai.ZhiPuAiChatOptions; +import org.springframework.ai.zhipuai.ZhiPuAiImageModel; +import org.springframework.ai.zhipuai.ZhiPuAiImageOptions; +import org.springframework.ai.zhipuai.api.ZhiPuAiApi; +import org.springframework.ai.zhipuai.api.ZhiPuAiImageApi; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestClient; +import xyz.thoughtset.viewer.common.ai.model.entity.AiNode; +import xyz.thoughtset.viewer.common.ai.model.entity.ModelParam; +import xyz.thoughtset.viewer.common.ai.model.factory.DefaultModelBuilder; +import xyz.thoughtset.viewer.common.ai.model.factory.ModelBuilder; + +import java.util.List; + +@Component +public class ZhipuImageBuilder extends ModelBuilder { + public ZhipuImageBuilder() { + super("ZhipuAI", List.of("CogView-4","Cogview-3-Flash" )); + } + + + @Override + public Model buildMode(AiNode node, ModelParam modelParam) { + ZhiPuAiImageOptions.Builder builder = ZhiPuAiImageOptions.builder() + .model(modelParam.getModel()); + ZhiPuAiImageOptions options = builder.build(); + ZhiPuAiImageApi api = new ZhiPuAiImageApi(node.getBaseUrl(), node.getApiKey(), RestClient.builder()); + ZhiPuAiImageModel model = new ZhiPuAiImageModel(api, options, RetryUtils.DEFAULT_RETRY_TEMPLATE); +// ChatModel chatModel = ZhiPuAiChatModel.builder() +// .defaultOptions(options) +// .openAiApi(api) +// .build(); + return model; + } +} diff --git a/models/viewer-models-zhipuai/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/models/viewer-models-zhipuai/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 0000000000000000000000000000000000000000..f15a472e456f50e23803ecc61c5f205684db872b --- /dev/null +++ b/models/viewer-models-zhipuai/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1 @@ +xyz.thoughtset.viewer.models.openai.ModelOpenAIAutoConfiguration \ No newline at end of file diff --git a/modules/viewer-modules-api/src/main/java/xyz/thoughtset/viewer/modules/api/controller/EasyQueryController.java b/modules/viewer-modules-api/src/main/java/xyz/thoughtset/viewer/modules/api/controller/EasyQueryController.java index b120caf427982c7fa82d6808a53b1146d2f89cc4..789f5c0b10f8680af633aae0d416991cd2986836 100644 --- a/modules/viewer-modules-api/src/main/java/xyz/thoughtset/viewer/modules/api/controller/EasyQueryController.java +++ b/modules/viewer-modules-api/src/main/java/xyz/thoughtset/viewer/modules/api/controller/EasyQueryController.java @@ -66,15 +66,6 @@ public class EasyQueryController extends BaseApiController { Object value = entry.getValue(); writer.fill(value, writeSheet); } - // 填充列表数据,开启 forceNewRow -// FillConfig config = FillConfig.builder().forceNewRow(true).build(); -// writer.fill(data, config, writeSheet); - - // 填充普通变量 -// Map map = new HashMap<>(); -// map.put("date", "2024年11月20日"); -// map.put("total", 1000); -// writer.fill(map, writeSheet); writer.finish(); }catch (Exception e) { throw new RuntimeException(e.getMessage(), e); diff --git a/modules/viewer-modules-fun/src/main/java/xyz/thoughtset/viewer/modules/fun/dao/FunInfoDao.java b/modules/viewer-modules-fun/src/main/java/xyz/thoughtset/viewer/modules/fun/dao/FunInfoDao.java index 6143f0faee8eefa94b6bac9fd0adf21c3f898b81..151f565f8f173edb3bcfdb28f5a23440f6d7109b 100644 --- a/modules/viewer-modules-fun/src/main/java/xyz/thoughtset/viewer/modules/fun/dao/FunInfoDao.java +++ b/modules/viewer-modules-fun/src/main/java/xyz/thoughtset/viewer/modules/fun/dao/FunInfoDao.java @@ -9,6 +9,9 @@ import java.util.List; @Mapper public interface FunInfoDao extends BaseMapper { - List findFunsWithInParam(String funId); - List findMcpToolsWithInParam(String serverId); + List findBlockFunsWithInParam(String blockId); + default List findAIToolsWithInParam(String serverId){ + return findAIToolsWithInParam(serverId,null); + } + List findAIToolsWithInParam(String serverId,String topic); } diff --git a/modules/viewer-modules-fun/src/main/java/xyz/thoughtset/viewer/modules/fun/service/FunInfoService.java b/modules/viewer-modules-fun/src/main/java/xyz/thoughtset/viewer/modules/fun/service/FunInfoService.java index f598b8e5ace55137865a3ec09eb6d9c6c2b1d19f..fa7f75b61f67c2da58ce40388a3d75bbd2f8a0cb 100644 --- a/modules/viewer-modules-fun/src/main/java/xyz/thoughtset/viewer/modules/fun/service/FunInfoService.java +++ b/modules/viewer-modules-fun/src/main/java/xyz/thoughtset/viewer/modules/fun/service/FunInfoService.java @@ -10,6 +10,6 @@ import java.util.List; public interface FunInfoService extends BaseService { List findFunInputParams(String funId); - List findMcpToolsWithInParam(String serverId); + List findAIToolsWithInParam(String serverId); } diff --git a/modules/viewer-modules-fun/src/main/java/xyz/thoughtset/viewer/modules/fun/service/FunInfoServiceImpl.java b/modules/viewer-modules-fun/src/main/java/xyz/thoughtset/viewer/modules/fun/service/FunInfoServiceImpl.java index 477b52d2482f9ad33c5fe37cf424bcad84a39fa4..7207e4f1e966c9f018548d8f9694b31baa0a0203 100644 --- a/modules/viewer-modules-fun/src/main/java/xyz/thoughtset/viewer/modules/fun/service/FunInfoServiceImpl.java +++ b/modules/viewer-modules-fun/src/main/java/xyz/thoughtset/viewer/modules/fun/service/FunInfoServiceImpl.java @@ -93,8 +93,8 @@ public class FunInfoServiceImpl extends BaseServiceImpl imp } @Override - public List findMcpToolsWithInParam(String serverId) { - List list = baseMapper.findMcpToolsWithInParam(serverId); + public List findAIToolsWithInParam(String serverId) { + List list = baseMapper.findAIToolsWithInParam(serverId); return list; } } diff --git a/modules/viewer-modules-fun/src/main/resources/mybatis/FunInfoMapper.xml b/modules/viewer-modules-fun/src/main/resources/mybatis/FunInfoMapper.xml index c5b924b859e4af77b42f59aa27506a683e36b0a4..81f5cd2afbc9858a1637b8a654d3813a8ba848b7 100644 --- a/modules/viewer-modules-fun/src/main/resources/mybatis/FunInfoMapper.xml +++ b/modules/viewer-modules-fun/src/main/resources/mybatis/FunInfoMapper.xml @@ -14,26 +14,8 @@ - - - + SELECT + + FROM + blockbodyele bbe + inner join funinfo i on bbe.eleId = i.id + left join funparam p on i.id = p.pid + WHERE p.paramType = '0' and i.statesCode = ]]> 200 + + AND bbe.pid = #{blockId} + + + + diff --git a/modules/viewer-modules-step/src/main/java/xyz/thoughtset/viewer/modules/step/service/BlockInfoServiceImpl.java b/modules/viewer-modules-step/src/main/java/xyz/thoughtset/viewer/modules/step/service/BlockInfoServiceImpl.java index 0b6b3fd4c128782ac23bcb4dcfc034cc3a810fdc..e78aceca9a9af19642ac605c5f1dc817b2387a51 100644 --- a/modules/viewer-modules-step/src/main/java/xyz/thoughtset/viewer/modules/step/service/BlockInfoServiceImpl.java +++ b/modules/viewer-modules-step/src/main/java/xyz/thoughtset/viewer/modules/step/service/BlockInfoServiceImpl.java @@ -43,15 +43,17 @@ public class BlockInfoServiceImpl extends BaseServiceImpl oldEles = blockEles(entity.getId()); HashSet oldEleIds = new HashSet<>(); diff --git a/pom.xml b/pom.xml index 1537bfbf79b9e78f7e2c1a8a4ced9526f4824923..362576a918382a3bc3ca1a9c907e61bb6574ba0d 100644 --- a/pom.xml +++ b/pom.xml @@ -29,6 +29,7 @@ modules executor ai + models @@ -37,7 +38,7 @@ - 1.2.0 + 1.3.0 17 2025.0.0 true @@ -52,7 +53,6 @@ 4.11.0 0.2.25 3.2.0 - 1.24 1.0.1 0.12.0 @@ -291,6 +291,7 @@ viewer-modules-ds-http-simple ${revision} + xyz.thoughtset.viewer viewer-ai-mcp-server @@ -301,6 +302,27 @@ viewer-modules-mcp-server ${revision} + + xyz.thoughtset.viewer + viewer-common-ai-model + ${revision} + + + xyz.thoughtset.viewer + viewer-models-deepseek + ${revision} + + + xyz.thoughtset.viewer + viewer-models-openai + ${revision} + + + + xyz.thoughtset.viewer + viewer-models-zhipuai + ${revision} + diff --git a/sql/mysql/dv.sql b/sql/mysql/dv.sql index 8c0dda9fa5f9f91c34b260d43e35401a897bfee2..0495e6187c639519b5c017e384e90ae0472c54ef 100644 --- a/sql/mysql/dv.sql +++ b/sql/mysql/dv.sql @@ -1,7 +1,28 @@ - SET NAMES utf8mb4; SET FOREIGN_KEY_CHECKS = 0; +-- ---------------------------- +-- Table structure for ainode +-- ---------------------------- +DROP TABLE IF EXISTS `ainode`; +CREATE TABLE `ainode` ( + `id` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, + `title` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, + `pid` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, + `groupId` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, + `remark` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL, + `orderNum` int(11) NULL DEFAULT NULL, + `createdAt` datetime(0) NOT NULL, + `updatedAt` datetime(0) NOT NULL, + `statesCode` int(11) NULL DEFAULT 200, + `provider` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, + `baseUrl` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, + `apiKey` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, + `headersStr` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL, + `settingStr` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL, + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; + -- ---------------------------- -- Table structure for apiinfo -- ---------------------------- @@ -305,6 +326,31 @@ CREATE TABLE `mcpserverinfo` ( PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; +-- ---------------------------- +-- Table structure for modelparam +-- ---------------------------- +DROP TABLE IF EXISTS `modelparam`; +CREATE TABLE `modelparam` ( + `id` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, + `title` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, + `pid` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, + `groupId` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, + `remark` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL, + `orderNum` int(11) NULL DEFAULT NULL, + `createdAt` datetime(0) NOT NULL, + `updatedAt` datetime(0) NOT NULL, + `statesCode` int(11) NULL DEFAULT 200, + `model` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, + `systemPrompt` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL, + `maxMemory` int(11) NULL DEFAULT NULL, + `maxTokens` bigint(20) NULL DEFAULT NULL, + `temperature` double NULL DEFAULT NULL, + `paramJson` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL, + `purpose` varchar(16) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, + `setting` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL, + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; + -- ---------------------------- -- Table structure for queryblock -- ----------------------------