Merge pull request 'test' (#5) from test into master
Reviewed-on: http://git.feashow.cn/clay/metis/pulls/5
This commit is contained in:
33
.drone.yml
33
.drone.yml
@@ -27,11 +27,9 @@ steps:
|
|||||||
from_secret: docker_password
|
from_secret: docker_password
|
||||||
REGISTRY:
|
REGISTRY:
|
||||||
from_secret: registry
|
from_secret: registry
|
||||||
REGISTRY_NAMESPACE:
|
|
||||||
from_secret: registry_namespace
|
|
||||||
commands:
|
commands:
|
||||||
- sed -i 's/$REGISTRY/'"$REGISTRY"'/' deployment.yml
|
- sed -i 's/$REGISTRY/'"$REGISTRY"'/' deployment.yml
|
||||||
- sed -i 's/$REGISTRY_NAMESPACE/'"$REGISTRY_NAMESPACE"'/' deployment.yml
|
- sed -i 's/$REGISTRY_NAMESPACE/'"metis"'/' deployment.yml
|
||||||
- sed -i 's/$DRONE_COMMIT/${DRONE_COMMIT}/' deployment.yml
|
- sed -i 's/$DRONE_COMMIT/${DRONE_COMMIT}/' deployment.yml
|
||||||
- sed -i 's/$DRONE_REPO_NAME/${DRONE_REPO_NAME}/' deployment.yml
|
- sed -i 's/$DRONE_REPO_NAME/${DRONE_REPO_NAME}/' deployment.yml
|
||||||
- echo $DOCKER_PASSWORD | docker login $REGISTRY --username $DOCKER_USERNAME --password-stdin
|
- echo $DOCKER_PASSWORD | docker login $REGISTRY --username $DOCKER_USERNAME --password-stdin
|
||||||
@@ -47,6 +45,35 @@ steps:
|
|||||||
- kubectl apply -f deployment.yml -n metis --kubeconfig=/app/config/base-taishan-kubectl.yml
|
- kubectl apply -f deployment.yml -n metis --kubeconfig=/app/config/base-taishan-kubectl.yml
|
||||||
|
|
||||||
|
|
||||||
|
- name: notify
|
||||||
|
image: 10.7.127.190:38080/plugins/webhook:latest
|
||||||
|
environment:
|
||||||
|
NOTIFY_WX_URL:
|
||||||
|
from_secret: notify_wx_url
|
||||||
|
when:
|
||||||
|
status: [ success,failure ]
|
||||||
|
settings:
|
||||||
|
urls:
|
||||||
|
from_secret: notify_wx_url
|
||||||
|
content_type: application/json
|
||||||
|
template: |
|
||||||
|
{
|
||||||
|
"msgtype": "markdown",
|
||||||
|
"markdown": {
|
||||||
|
"content": "{{#success build.status}}<font color=\"green\">✅ 构建成功</font>{{else}}<font color=\"red\">❌ 构建失败</font>{{/success}}
|
||||||
|
>**构建编号**: #{{build.number}}
|
||||||
|
>**构建状态**: {{build.status}}
|
||||||
|
>**代码分支**: {{build.branch}}
|
||||||
|
>**提交哈希**: {{build.commit}}
|
||||||
|
>**提交作者**: {{build.author}}
|
||||||
|
>**持续时间**: {{build.duration}}秒
|
||||||
|
>**提交信息**: {{build.message}}
|
||||||
|
>[查看构建详情]({{build.link}})
|
||||||
|
>{{^success build.status}}[查看失败日志]({{build.link}}/logs){{/success}}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
- name: config
|
- name: config
|
||||||
host:
|
host:
|
||||||
|
|||||||
@@ -6,6 +6,6 @@ WORKDIR /app
|
|||||||
# 定义时区参数并设置时区
|
# 定义时区参数并设置时区
|
||||||
ENV TZ=Asia/Shanghai
|
ENV TZ=Asia/Shanghai
|
||||||
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
|
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
|
||||||
COPY ./target/metis-1.0.0-SNAPSHOT.jar /app/metis.jar
|
COPY ./metis-applicant/target/metis-applicant-1.0.0-SNAPSHOT.jar /app/metis.jar
|
||||||
RUN chmod 755 -R /app/
|
RUN chmod 755 -R /app/
|
||||||
CMD java -jar /app/metis.jar -Xms256m -Xmx512m --spring.profiles.active=${PROFILES} --server.port=${SERVICE_PORTS}
|
CMD java -jar /app/metis.jar -Xms256m -Xmx512m --spring.profiles.active=${PROFILES} --server.port=${SERVICE_PORTS}
|
||||||
|
|||||||
93
metis-applicant/pom.xml
Normal file
93
metis-applicant/pom.xml
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<parent>
|
||||||
|
<groupId>com.metis</groupId>
|
||||||
|
<artifactId>metis</artifactId>
|
||||||
|
<version>1.0.0-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<artifactId>metis-applicant</artifactId>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<maven.compiler.source>17</maven.compiler.source>
|
||||||
|
<maven.compiler.target>17</maven.compiler.target>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.metis</groupId>
|
||||||
|
<artifactId>metis-starter</artifactId>
|
||||||
|
<version>1.0.0-SNAPSHOT</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.xiaoymin</groupId>
|
||||||
|
<artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId>
|
||||||
|
<version>4.4.0</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<!-- 默认生效的插件 -->
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<goals>
|
||||||
|
<goal>repackage</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
<!-- 排除静态编译类的插件,为打包的 jar 瘦身 -->
|
||||||
|
<configuration>
|
||||||
|
<excludes>
|
||||||
|
<exclude>
|
||||||
|
<groupId>org.projectlombok</groupId>
|
||||||
|
<artifactId>lombok</artifactId>
|
||||||
|
</exclude>
|
||||||
|
<exclude>
|
||||||
|
<groupId>org.mapstruct</groupId>
|
||||||
|
<artifactId>mapstruct-processor</artifactId>
|
||||||
|
</exclude>
|
||||||
|
</excludes>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<!-- 编译插件 -->
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<source>17</source>
|
||||||
|
<target>17</target>
|
||||||
|
<encoding>UTF-8</encoding>
|
||||||
|
<compilerArgs>
|
||||||
|
<arg>-parameters</arg>
|
||||||
|
<arg>--add-opens</arg>
|
||||||
|
<arg>java.base/java.lang=ALL-UNNAMED</arg>
|
||||||
|
</compilerArgs>
|
||||||
|
<!-- 注解静态编译功能 注:仅支持 maven-compiler-plugin 的 version 在3.6.0 以上才生效 -->
|
||||||
|
<annotationProcessorPaths>
|
||||||
|
<!-- 必须配置 lombok 的注解编译,否则会因为配置了(mapstruct-processor)启动了导致 lombok 对内部类的静态编译失效 -->
|
||||||
|
<path>
|
||||||
|
<groupId>org.projectlombok</groupId>
|
||||||
|
<artifactId>lombok</artifactId>
|
||||||
|
<version>${lombok.version}</version>
|
||||||
|
</path>
|
||||||
|
<path>
|
||||||
|
<groupId>org.mapstruct</groupId>
|
||||||
|
<artifactId>mapstruct-processor</artifactId>
|
||||||
|
<version>${org.mapstruct.version}</version>
|
||||||
|
</path>
|
||||||
|
</annotationProcessorPaths>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
|
||||||
|
</build>
|
||||||
|
</project>
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.metis;
|
package com.metisapp;
|
||||||
|
|
||||||
import org.springframework.boot.SpringApplication;
|
import org.springframework.boot.SpringApplication;
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
package com.metis.config;
|
package com.metisapp.config;
|
||||||
|
|
||||||
import io.swagger.v3.oas.models.OpenAPI;
|
import io.swagger.v3.oas.models.OpenAPI;
|
||||||
import io.swagger.v3.oas.models.info.Contact;
|
|
||||||
import io.swagger.v3.oas.models.info.Info;
|
import io.swagger.v3.oas.models.info.Info;
|
||||||
import io.swagger.v3.oas.models.info.License;
|
import io.swagger.v3.oas.models.info.License;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
package com.metisapp.controller;
|
||||||
|
|
||||||
|
import com.metis.domain.bo.BuildApp;
|
||||||
|
import com.metis.engine.AppFlowEngineRunnerService;
|
||||||
|
import com.metis.runner.FlowRunningContext;
|
||||||
|
import com.metis.runner.RunnerResult;
|
||||||
|
import com.metis.validator.ValidatorService;
|
||||||
|
import com.metis.result.Result;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/test")
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class TestController {
|
||||||
|
|
||||||
|
|
||||||
|
private final ValidatorService validatorService;
|
||||||
|
private final AppFlowEngineRunnerService engineRunnerService;
|
||||||
|
|
||||||
|
@PostMapping
|
||||||
|
public Result<String> test(@RequestBody BuildApp app) {
|
||||||
|
validatorService.validate(app);
|
||||||
|
return Result.ok("测试成功");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@PostMapping("/run")
|
||||||
|
public Result<RunnerResult> run(@RequestBody FlowRunningContext context) {
|
||||||
|
RunnerResult running = engineRunnerService.running(context);
|
||||||
|
return Result.ok(running);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package com.metisapp.custom;
|
||||||
|
|
||||||
|
import com.metis.domain.entity.base.NodeConfig;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
public class CustomTestConfig extends NodeConfig {
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
package com.metisapp.custom;
|
||||||
|
|
||||||
|
import com.metis.domain.context.RunningContext;
|
||||||
|
import com.metis.domain.context.RunningResult;
|
||||||
|
import com.metis.domain.entity.base.Edge;
|
||||||
|
import com.metis.domain.entity.base.Node;
|
||||||
|
import com.metis.runner.CustomNodeRunner;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
public class CustomTestRunner implements CustomNodeRunner<CustomTestConfig> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getCustomNodeType() {
|
||||||
|
return "test";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RunningResult run(RunningContext context, Node node, List<Edge> edges) {
|
||||||
|
log.info("自定义节点测试");
|
||||||
|
return RunningResult.buildResult();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
package com.metisapp.custom;
|
||||||
|
|
||||||
|
import com.metis.domain.entity.base.Edge;
|
||||||
|
import com.metis.domain.entity.base.Node;
|
||||||
|
import com.metis.validator.CustomNodeValidator;
|
||||||
|
import com.metis.validator.ValidatorResult;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
public class CustomTestValidator implements CustomNodeValidator<CustomTestConfig> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getCustomNodeType() {
|
||||||
|
return "test";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ValidatorResult validateValue(Node node) {
|
||||||
|
CustomTestConfig config = node.getConfig();
|
||||||
|
return ValidatorResult.valid();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ValidatorResult validateRelation(Node node, List<Edge> sources, List<Edge> targets) {
|
||||||
|
CustomTestConfig config = node.getConfig();
|
||||||
|
return ValidatorResult.valid();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -34,10 +34,6 @@ springdoc:
|
|||||||
swagger-ui:
|
swagger-ui:
|
||||||
tags-sorter: alpha
|
tags-sorter: alpha
|
||||||
group-configs:
|
group-configs:
|
||||||
- group: bis
|
|
||||||
display-name: "业务接口文档"
|
|
||||||
paths-to-match: '/**'
|
|
||||||
packages-to-scan: org.shi9.module.bis
|
|
||||||
- group: system
|
- group: system
|
||||||
display-name: "系统接口文档"
|
display-name: "系统接口文档"
|
||||||
paths-to-match: '/**'
|
paths-to-match: '/**'
|
||||||
7
metis-applicant/src/main/resources/json/run.json
Normal file
7
metis-applicant/src/main/resources/json/run.json
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"appId": "1909636986931470336",
|
||||||
|
"userId": 1,
|
||||||
|
"custom": {
|
||||||
|
"context": "测试内容!"
|
||||||
|
}
|
||||||
|
}
|
||||||
567
metis-applicant/src/main/resources/json/test.json
Normal file
567
metis-applicant/src/main/resources/json/test.json
Normal file
@@ -0,0 +1,567 @@
|
|||||||
|
{
|
||||||
|
"id": 0,
|
||||||
|
"name": "测试流程",
|
||||||
|
"description": "测试流程",
|
||||||
|
"graph": {
|
||||||
|
"nodes": [
|
||||||
|
{
|
||||||
|
"id": "5",
|
||||||
|
"type": "start",
|
||||||
|
"initialized": false,
|
||||||
|
"position": {
|
||||||
|
"x": -81.81250000000003,
|
||||||
|
"y": 275.49609375
|
||||||
|
},
|
||||||
|
"data": {
|
||||||
|
"label": "开始",
|
||||||
|
"icon": "SuitcaseLine",
|
||||||
|
"toolbarPosition": "right",
|
||||||
|
"description": "开始述描述",
|
||||||
|
"config": {
|
||||||
|
"parent": "234"
|
||||||
|
},
|
||||||
|
"handles": [
|
||||||
|
{
|
||||||
|
"id": "51",
|
||||||
|
"position": "right",
|
||||||
|
"type": "source",
|
||||||
|
"connectable": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"item": {
|
||||||
|
"id": "2",
|
||||||
|
"type": "run",
|
||||||
|
"labelType": "knowledge",
|
||||||
|
"label": "知识检索"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"width": 200,
|
||||||
|
"height": 40
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "6",
|
||||||
|
"type": "end",
|
||||||
|
"initialized": false,
|
||||||
|
"position": {
|
||||||
|
"x": 1281.582055572882,
|
||||||
|
"y": 236.2912067630247
|
||||||
|
},
|
||||||
|
"data": {
|
||||||
|
"label": "结束",
|
||||||
|
"toolbarPosition": "right",
|
||||||
|
"handles": [
|
||||||
|
{
|
||||||
|
"id": "61",
|
||||||
|
"position": "left",
|
||||||
|
"type": "target",
|
||||||
|
"connectable": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"width": 200,
|
||||||
|
"height": 40
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "188",
|
||||||
|
"type": "custom",
|
||||||
|
"customType": "test",
|
||||||
|
"initialized": false,
|
||||||
|
"position": {
|
||||||
|
"x": 265.87532955148635,
|
||||||
|
"y": 71.40983063296031
|
||||||
|
},
|
||||||
|
"data": {
|
||||||
|
"label": "llm1",
|
||||||
|
"icon": "",
|
||||||
|
"description": "llm描述描述",
|
||||||
|
"toolbarPosition": "right",
|
||||||
|
"config": {
|
||||||
|
"labelType": "llm"
|
||||||
|
},
|
||||||
|
"handles": [
|
||||||
|
{
|
||||||
|
"id": "11",
|
||||||
|
"position": "left",
|
||||||
|
"type": "source",
|
||||||
|
"connectable": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "45",
|
||||||
|
"position": "right",
|
||||||
|
"type": "source",
|
||||||
|
"connectable": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"width": 200,
|
||||||
|
"height": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "850",
|
||||||
|
"type": "llm",
|
||||||
|
"initialized": false,
|
||||||
|
"position": {
|
||||||
|
"x": 269.7896091295129,
|
||||||
|
"y": 253.80570624004747
|
||||||
|
},
|
||||||
|
"data": {
|
||||||
|
"label": "llm2",
|
||||||
|
"icon": "",
|
||||||
|
"description": "llm描述描述",
|
||||||
|
"toolbarPosition": "right",
|
||||||
|
"config": {
|
||||||
|
"labelType": "llm"
|
||||||
|
},
|
||||||
|
"handles": [
|
||||||
|
{
|
||||||
|
"id": "43",
|
||||||
|
"position": "left",
|
||||||
|
"type": "source",
|
||||||
|
"connectable": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "57",
|
||||||
|
"position": "right",
|
||||||
|
"type": "source",
|
||||||
|
"connectable": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"width": 200,
|
||||||
|
"height": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "979",
|
||||||
|
"type": "llm",
|
||||||
|
"initialized": false,
|
||||||
|
"position": {
|
||||||
|
"x": 257.0893454883237,
|
||||||
|
"y": 360
|
||||||
|
},
|
||||||
|
"data": {
|
||||||
|
"label": "llm3",
|
||||||
|
"icon": "",
|
||||||
|
"description": "llm描述描述",
|
||||||
|
"toolbarPosition": "right",
|
||||||
|
"config": {
|
||||||
|
"labelType": "llm"
|
||||||
|
},
|
||||||
|
"handles": [
|
||||||
|
{
|
||||||
|
"id": "40",
|
||||||
|
"position": "left",
|
||||||
|
"type": "source",
|
||||||
|
"connectable": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "46",
|
||||||
|
"position": "right",
|
||||||
|
"type": "source",
|
||||||
|
"connectable": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"item": {
|
||||||
|
"id": "1",
|
||||||
|
"type": "run",
|
||||||
|
"labelType": "llm",
|
||||||
|
"label": "llm"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"width": 200,
|
||||||
|
"height": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "818",
|
||||||
|
"type": "questionClassifier",
|
||||||
|
"initialized": false,
|
||||||
|
"position": {
|
||||||
|
"x": 247.56414775743187,
|
||||||
|
"y": 467.44099824508874
|
||||||
|
},
|
||||||
|
"data": {
|
||||||
|
"label": "知识检索条件",
|
||||||
|
"icon": "",
|
||||||
|
"description": "知识检索描述描述",
|
||||||
|
"toolbarPosition": "right",
|
||||||
|
"config": {
|
||||||
|
"labelType": "knowledge"
|
||||||
|
},
|
||||||
|
"handles": [
|
||||||
|
{
|
||||||
|
"id": "86",
|
||||||
|
"position": "left",
|
||||||
|
"type": "source",
|
||||||
|
"connectable": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "11",
|
||||||
|
"position": "right",
|
||||||
|
"type": "source",
|
||||||
|
"connectable": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"item": {
|
||||||
|
"id": "1",
|
||||||
|
"type": "run",
|
||||||
|
"labelType": "llm",
|
||||||
|
"label": "llm"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"width": 200,
|
||||||
|
"height": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "288",
|
||||||
|
"type": "llm",
|
||||||
|
"initialized": false,
|
||||||
|
"position": {
|
||||||
|
"x": 545.6891477574318,
|
||||||
|
"y": 431.4042601585389
|
||||||
|
},
|
||||||
|
"data": {
|
||||||
|
"label": "llm5",
|
||||||
|
"icon": "",
|
||||||
|
"description": "llm描述描述",
|
||||||
|
"toolbarPosition": "right",
|
||||||
|
"config": {
|
||||||
|
"labelType": "llm"
|
||||||
|
},
|
||||||
|
"handles": [
|
||||||
|
{
|
||||||
|
"id": "27",
|
||||||
|
"position": "left",
|
||||||
|
"type": "source",
|
||||||
|
"connectable": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "90",
|
||||||
|
"position": "right",
|
||||||
|
"type": "source",
|
||||||
|
"connectable": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"width": 200,
|
||||||
|
"height": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "873",
|
||||||
|
"type": "llm",
|
||||||
|
"initialized": false,
|
||||||
|
"position": {
|
||||||
|
"x": 561.0654659633774,
|
||||||
|
"y": 547.6673703535477
|
||||||
|
},
|
||||||
|
"data": {
|
||||||
|
"label": "llm6",
|
||||||
|
"icon": "",
|
||||||
|
"description": "llm描述描述",
|
||||||
|
"toolbarPosition": "right",
|
||||||
|
"config": {
|
||||||
|
"labelType": "llm"
|
||||||
|
},
|
||||||
|
"handles": [
|
||||||
|
{
|
||||||
|
"id": "31",
|
||||||
|
"position": "left",
|
||||||
|
"type": "source",
|
||||||
|
"connectable": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "51",
|
||||||
|
"position": "right",
|
||||||
|
"type": "source",
|
||||||
|
"connectable": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"width": 200,
|
||||||
|
"height": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "244",
|
||||||
|
"type": "llm",
|
||||||
|
"initialized": false,
|
||||||
|
"position": {
|
||||||
|
"x": 543.1540601095024,
|
||||||
|
"y": 653.309197614774
|
||||||
|
},
|
||||||
|
"data": {
|
||||||
|
"label": "llm7",
|
||||||
|
"icon": "",
|
||||||
|
"description": "llm描述描述",
|
||||||
|
"toolbarPosition": "right",
|
||||||
|
"config": {
|
||||||
|
"labelType": "llm"
|
||||||
|
},
|
||||||
|
"handles": [
|
||||||
|
{
|
||||||
|
"id": "33",
|
||||||
|
"position": "left",
|
||||||
|
"type": "source",
|
||||||
|
"connectable": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "13",
|
||||||
|
"position": "right",
|
||||||
|
"type": "source",
|
||||||
|
"connectable": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"width": 200,
|
||||||
|
"height": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "308",
|
||||||
|
"type": "llm",
|
||||||
|
"initialized": false,
|
||||||
|
"position": {
|
||||||
|
"x": 588.7086470279171,
|
||||||
|
"y": 318.8609378786052
|
||||||
|
},
|
||||||
|
"data": {
|
||||||
|
"label": "llm4",
|
||||||
|
"icon": "",
|
||||||
|
"description": "llm描述描述",
|
||||||
|
"toolbarPosition": "right",
|
||||||
|
"config": {
|
||||||
|
"labelType": "llm"
|
||||||
|
},
|
||||||
|
"handles": [
|
||||||
|
{
|
||||||
|
"id": "17",
|
||||||
|
"position": "left",
|
||||||
|
"type": "source",
|
||||||
|
"connectable": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "73",
|
||||||
|
"position": "right",
|
||||||
|
"type": "source",
|
||||||
|
"connectable": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"width": 200,
|
||||||
|
"height": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"edges": [
|
||||||
|
{
|
||||||
|
"id": "188",
|
||||||
|
"type": "default",
|
||||||
|
"source": "5",
|
||||||
|
"target": "188",
|
||||||
|
"sourceHandle": "51",
|
||||||
|
"targetHandle": "11",
|
||||||
|
"data": {},
|
||||||
|
"label": "",
|
||||||
|
"animated": true,
|
||||||
|
"sourceX": 124.52083333333331,
|
||||||
|
"sourceY": 295.3294270833333,
|
||||||
|
"targetX": 262.70866773530213,
|
||||||
|
"targetY": 98.2431395846395
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "vueflow__edge-18845-661",
|
||||||
|
"type": "default",
|
||||||
|
"source": "188",
|
||||||
|
"target": "6",
|
||||||
|
"sourceHandle": "45",
|
||||||
|
"targetHandle": "61",
|
||||||
|
"data": {},
|
||||||
|
"label": "",
|
||||||
|
"sourceX": 472.20841119628,
|
||||||
|
"sourceY": 98.2431395846395,
|
||||||
|
"targetX": 1278.4153889062152,
|
||||||
|
"targetY": 256.12454009635803
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "850",
|
||||||
|
"type": "default",
|
||||||
|
"source": "5",
|
||||||
|
"target": "850",
|
||||||
|
"sourceHandle": "51",
|
||||||
|
"targetHandle": "43",
|
||||||
|
"data": {},
|
||||||
|
"label": "",
|
||||||
|
"animated": true,
|
||||||
|
"sourceX": 124.52083333333331,
|
||||||
|
"sourceY": 295.3294270833333,
|
||||||
|
"targetX": 266.62293379655364,
|
||||||
|
"targetY": 280.6389855757115
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "vueflow__edge-85057-661",
|
||||||
|
"type": "default",
|
||||||
|
"source": "850",
|
||||||
|
"target": "6",
|
||||||
|
"sourceHandle": "57",
|
||||||
|
"targetHandle": "61",
|
||||||
|
"data": {},
|
||||||
|
"label": "",
|
||||||
|
"sourceX": 476.1223496202179,
|
||||||
|
"sourceY": 280.6389855757115,
|
||||||
|
"targetX": 1278.4153889062152,
|
||||||
|
"targetY": 256.12454009635803
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "979",
|
||||||
|
"type": "default",
|
||||||
|
"source": "5",
|
||||||
|
"target": "979",
|
||||||
|
"sourceHandle": "51",
|
||||||
|
"targetHandle": "40",
|
||||||
|
"data": {},
|
||||||
|
"label": "",
|
||||||
|
"animated": true,
|
||||||
|
"sourceX": 124.52083333333331,
|
||||||
|
"sourceY": 295.3294270833333,
|
||||||
|
"targetX": 253.92267015536444,
|
||||||
|
"targetY": 386.83332778318527
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "818",
|
||||||
|
"type": "default",
|
||||||
|
"source": "5",
|
||||||
|
"target": "818",
|
||||||
|
"sourceHandle": "51",
|
||||||
|
"targetHandle": "86",
|
||||||
|
"data": {},
|
||||||
|
"label": "",
|
||||||
|
"animated": true,
|
||||||
|
"sourceX": 124.52083333333331,
|
||||||
|
"sourceY": 295.3294270833333,
|
||||||
|
"targetX": 244.3974724244726,
|
||||||
|
"targetY": 494.2742291332315
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "288",
|
||||||
|
"type": "default",
|
||||||
|
"source": "818",
|
||||||
|
"target": "288",
|
||||||
|
"sourceHandle": "11",
|
||||||
|
"targetHandle": "27",
|
||||||
|
"data": {},
|
||||||
|
"label": "",
|
||||||
|
"animated": true,
|
||||||
|
"sourceX": 453.89688824813686,
|
||||||
|
"sourceY": 494.2742291332315,
|
||||||
|
"targetX": 542.5224239769512,
|
||||||
|
"targetY": 458.2374910466816
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "873",
|
||||||
|
"type": "default",
|
||||||
|
"source": "818",
|
||||||
|
"target": "873",
|
||||||
|
"sourceHandle": "11",
|
||||||
|
"targetHandle": "31",
|
||||||
|
"data": {},
|
||||||
|
"label": "",
|
||||||
|
"animated": true,
|
||||||
|
"sourceX": 453.89688824813686,
|
||||||
|
"sourceY": 494.2742291332315,
|
||||||
|
"targetX": 557.8988921284383,
|
||||||
|
"targetY": 574.5006486940537
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "244",
|
||||||
|
"type": "default",
|
||||||
|
"source": "818",
|
||||||
|
"target": "244",
|
||||||
|
"sourceHandle": "11",
|
||||||
|
"targetHandle": "33",
|
||||||
|
"data": {},
|
||||||
|
"label": "",
|
||||||
|
"animated": true,
|
||||||
|
"sourceX": 453.89688824813686,
|
||||||
|
"sourceY": 494.2742291332315,
|
||||||
|
"targetX": 539.9875200651626,
|
||||||
|
"targetY": 680.1424930622838
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "vueflow__edge-28890-661",
|
||||||
|
"type": "default",
|
||||||
|
"source": "288",
|
||||||
|
"target": "6",
|
||||||
|
"sourceHandle": "90",
|
||||||
|
"targetHandle": "61",
|
||||||
|
"data": {},
|
||||||
|
"label": "",
|
||||||
|
"sourceX": 752.0218882481367,
|
||||||
|
"sourceY": 458.2374910466816,
|
||||||
|
"targetX": 1278.4153889062152,
|
||||||
|
"targetY": 256.12454009635803
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "vueflow__edge-87351-661",
|
||||||
|
"type": "default",
|
||||||
|
"source": "873",
|
||||||
|
"target": "6",
|
||||||
|
"sourceHandle": "51",
|
||||||
|
"targetHandle": "61",
|
||||||
|
"data": {},
|
||||||
|
"label": "",
|
||||||
|
"sourceX": 767.3988903613488,
|
||||||
|
"sourceY": 574.5006486940537,
|
||||||
|
"targetX": 1278.4153889062152,
|
||||||
|
"targetY": 256.12454009635803
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "vueflow__edge-24413-661",
|
||||||
|
"type": "default",
|
||||||
|
"source": "244",
|
||||||
|
"target": "6",
|
||||||
|
"sourceHandle": "13",
|
||||||
|
"targetHandle": "61",
|
||||||
|
"data": {},
|
||||||
|
"label": "",
|
||||||
|
"sourceX": 749.4874144445799,
|
||||||
|
"sourceY": 680.1424930622838,
|
||||||
|
"targetX": 1278.4153889062152,
|
||||||
|
"targetY": 256.12454009635803
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "308",
|
||||||
|
"type": "default",
|
||||||
|
"source": "979",
|
||||||
|
"target": "308",
|
||||||
|
"sourceHandle": "46",
|
||||||
|
"targetHandle": "17",
|
||||||
|
"data": {},
|
||||||
|
"label": "",
|
||||||
|
"animated": true,
|
||||||
|
"sourceX": 463.42208597902874,
|
||||||
|
"sourceY": 386.83332778318527,
|
||||||
|
"targetX": 585.5419963013785,
|
||||||
|
"targetY": 345.6941732530918
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "vueflow__edge-30873-661",
|
||||||
|
"type": "default",
|
||||||
|
"source": "308",
|
||||||
|
"target": "6",
|
||||||
|
"sourceHandle": "73",
|
||||||
|
"targetHandle": "61",
|
||||||
|
"data": {},
|
||||||
|
"label": "",
|
||||||
|
"sourceX": 795.0417833691082,
|
||||||
|
"sourceY": 345.6941732530918,
|
||||||
|
"targetX": 1278.4153889062152,
|
||||||
|
"targetY": 256.12454009635803
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"position": [
|
||||||
|
447.2060780237498,
|
||||||
|
377.80084997067763
|
||||||
|
],
|
||||||
|
"zoom": 0.8311688311688327,
|
||||||
|
"viewport": {
|
||||||
|
"x": 447.2060780237498,
|
||||||
|
"y": 377.80084997067763,
|
||||||
|
"zoom": 0.8311688311688327
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
104
metis-starter/pom.xml
Normal file
104
metis-starter/pom.xml
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<parent>
|
||||||
|
<groupId>com.metis</groupId>
|
||||||
|
<artifactId>metis</artifactId>
|
||||||
|
<version>1.0.0-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<artifactId>metis-starter</artifactId>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-web</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-validation</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>dev.langchain4j</groupId>
|
||||||
|
<artifactId>langchain4j-open-ai</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>dev.langchain4j</groupId>
|
||||||
|
<artifactId>langchain4j-mcp</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.alibaba.fastjson2</groupId>
|
||||||
|
<artifactId>fastjson2</artifactId>
|
||||||
|
<version>2.0.52</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.projectlombok</groupId>
|
||||||
|
<artifactId>lombok</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.mikesamuel</groupId>
|
||||||
|
<artifactId>json-sanitizer</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.baomidou</groupId>
|
||||||
|
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>mysql</groupId>
|
||||||
|
<artifactId>mysql-connector-java</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>cn.hutool</groupId>
|
||||||
|
<artifactId>hutool-all</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<!-- 类转换 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.mapstruct</groupId>
|
||||||
|
<artifactId>mapstruct</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.projectlombok</groupId>
|
||||||
|
<artifactId>lombok-mapstruct-binding</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springdoc</groupId>
|
||||||
|
<artifactId>springdoc-openapi-starter-webmvc-api</artifactId>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<!-- 默认生效的插件 -->
|
||||||
|
<plugins>
|
||||||
|
<!-- 编译插件 -->
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<source>17</source>
|
||||||
|
<target>17</target>
|
||||||
|
<encoding>UTF-8</encoding>
|
||||||
|
<compilerArgs>
|
||||||
|
<arg>-parameters</arg>
|
||||||
|
</compilerArgs>
|
||||||
|
<!-- 注解静态编译功能 注:仅支持 maven-compiler-plugin 的 version 在3.6.0 以上才生效 -->
|
||||||
|
<annotationProcessorPaths>
|
||||||
|
<!-- 必须配置 lombok 的注解编译,否则会因为配置了(mapstruct-processor)启动了导致 lombok 对内部类的静态编译失效 -->
|
||||||
|
<path>
|
||||||
|
<groupId>org.projectlombok</groupId>
|
||||||
|
<artifactId>lombok</artifactId>
|
||||||
|
<version>${lombok.version}</version>
|
||||||
|
</path>
|
||||||
|
<path>
|
||||||
|
<groupId>org.mapstruct</groupId>
|
||||||
|
<artifactId>mapstruct-processor</artifactId>
|
||||||
|
<version>${org.mapstruct.version}</version>
|
||||||
|
</path>
|
||||||
|
</annotationProcessorPaths>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
|
||||||
|
</build>
|
||||||
|
</project>
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package com.metis.config;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.mybatis.spring.annotation.MapperScan;
|
||||||
|
import org.springframework.context.annotation.ComponentScan;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Configuration
|
||||||
|
@MapperScan(basePackages = {"com.metis.mapper"})
|
||||||
|
@ComponentScan("com.metis.*")
|
||||||
|
public class MetisStarterAutoConfiguration {
|
||||||
|
|
||||||
|
|
||||||
|
static {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.metis.flow.constant;
|
package com.metis.constant;
|
||||||
|
|
||||||
public interface BaseConstant {
|
public interface BaseConstant {
|
||||||
|
|
||||||
@@ -2,7 +2,7 @@ package com.metis.controller;
|
|||||||
|
|
||||||
import com.metis.domain.bo.ProcessBo;
|
import com.metis.domain.bo.ProcessBo;
|
||||||
import com.metis.facade.ProcessDefinitionFacade;
|
import com.metis.facade.ProcessDefinitionFacade;
|
||||||
import com.metis.flow.domain.entity.App;
|
import com.metis.domain.entity.App;
|
||||||
import com.metis.result.Result;
|
import com.metis.result.Result;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
@@ -16,9 +16,9 @@ public class ProcessDefinitionController {
|
|||||||
|
|
||||||
|
|
||||||
@PostMapping("/create")
|
@PostMapping("/create")
|
||||||
public Result<String> create(@RequestBody ProcessBo processBo) {
|
public Result<Long> create(@RequestBody ProcessBo processBo) {
|
||||||
processDefinitionFacade.create(processBo);
|
Long workflowId = processDefinitionFacade.create(processBo);
|
||||||
return Result.ok();
|
return Result.ok(workflowId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@PutMapping("/update")
|
@PutMapping("/update")
|
||||||
@@ -1,9 +1,10 @@
|
|||||||
package com.metis.flow.convert;
|
package com.metis.convert;
|
||||||
|
|
||||||
import com.metis.flow.domain.entity.*;
|
import com.metis.domain.bo.BuildApp;
|
||||||
import com.metis.flow.domain.bo.BuildApp;
|
import com.metis.domain.bo.CreateApp;
|
||||||
import com.metis.flow.domain.bo.CreateApp;
|
import com.metis.domain.bo.UpdateApp;
|
||||||
import com.metis.flow.domain.bo.UpdateApp;
|
import com.metis.domain.entity.App;
|
||||||
|
import com.metis.domain.entity.BaseApp;
|
||||||
import org.mapstruct.Mapper;
|
import org.mapstruct.Mapper;
|
||||||
import org.mapstruct.Mapping;
|
import org.mapstruct.Mapping;
|
||||||
import org.mapstruct.Mappings;
|
import org.mapstruct.Mappings;
|
||||||
@@ -23,6 +24,13 @@ public interface BaseAppConvert {
|
|||||||
* @param buildApp 基础应用
|
* @param buildApp 基础应用
|
||||||
* @return {@link App }
|
* @return {@link App }
|
||||||
*/
|
*/
|
||||||
|
@Mappings({
|
||||||
|
@Mapping(target = "id", ignore = true),
|
||||||
|
@Mapping(target = "workflowId", ignore = true),
|
||||||
|
@Mapping(target = "createTime", ignore = true),
|
||||||
|
@Mapping(target = "version", ignore = true),
|
||||||
|
@Mapping(target = "defaultUse", ignore = true),
|
||||||
|
})
|
||||||
App toApp(BuildApp buildApp);
|
App toApp(BuildApp buildApp);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -32,7 +40,7 @@ public interface BaseAppConvert {
|
|||||||
* @return {@link App }
|
* @return {@link App }
|
||||||
*/
|
*/
|
||||||
@Mappings({
|
@Mappings({
|
||||||
@Mapping(target = "graph", expression = "java(com.alibaba.fastjson2.JSON.parseObject(baseApp.getGraphJson(), com.metis.flow.domain.bo.Graph.class))"),
|
@Mapping(target = "graph", expression = "java(com.alibaba.fastjson2.JSON.parseObject(baseApp.getGraphJson(), com.metis.domain.entity.base.Graph.class))"),
|
||||||
@Mapping(target = "workflowId", source = "id")
|
@Mapping(target = "workflowId", source = "id")
|
||||||
})
|
})
|
||||||
App toApp(BaseApp baseApp);
|
App toApp(BaseApp baseApp);
|
||||||
@@ -44,7 +52,13 @@ public interface BaseAppConvert {
|
|||||||
* @return {@link BaseApp }
|
* @return {@link BaseApp }
|
||||||
*/
|
*/
|
||||||
@Mappings({
|
@Mappings({
|
||||||
@Mapping(target = "graphJson", expression = "java(com.alibaba.fastjson2.JSON.toJSONString(buildApp.getGraph()))")
|
@Mapping(target = "graphJson", expression = "java(com.alibaba.fastjson2.JSON.toJSONString(buildApp.getGraph()))"),
|
||||||
|
@Mapping(target = "createTime", ignore = true),
|
||||||
|
@Mapping(target = "updateTime", ignore = true),
|
||||||
|
@Mapping(target = "isDeleted", ignore = true),
|
||||||
|
@Mapping(target = "id", ignore = true),
|
||||||
|
@Mapping(target = "createUserId", ignore = true),
|
||||||
|
@Mapping(target = "defaultUse", ignore = true)
|
||||||
})
|
})
|
||||||
BaseApp toBaseApp(BuildApp buildApp);
|
BaseApp toBaseApp(BuildApp buildApp);
|
||||||
|
|
||||||
@@ -63,6 +77,9 @@ public interface BaseAppConvert {
|
|||||||
* @param createApp 创建应用程序
|
* @param createApp 创建应用程序
|
||||||
* @return {@link BuildApp }
|
* @return {@link BuildApp }
|
||||||
*/
|
*/
|
||||||
|
@Mappings({
|
||||||
|
@Mapping(target = "appId", ignore = true)
|
||||||
|
})
|
||||||
BuildApp toBuildApp(CreateApp createApp);
|
BuildApp toBuildApp(CreateApp createApp);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -71,6 +88,9 @@ public interface BaseAppConvert {
|
|||||||
* @param updateApp 更新应用程序
|
* @param updateApp 更新应用程序
|
||||||
* @return {@link BuildApp }
|
* @return {@link BuildApp }
|
||||||
*/
|
*/
|
||||||
|
@Mappings({
|
||||||
|
@Mapping(target = "userId", ignore = true)
|
||||||
|
})
|
||||||
BuildApp toBuildApp(UpdateApp updateApp);
|
BuildApp toBuildApp(UpdateApp updateApp);
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
package com.metis.convert;
|
||||||
|
|
||||||
|
|
||||||
|
import com.metis.domain.bo.GraphBO;
|
||||||
|
import com.metis.domain.entity.base.Graph;
|
||||||
|
import org.mapstruct.Mapper;
|
||||||
|
import org.mapstruct.factory.Mappers;
|
||||||
|
|
||||||
|
@Mapper
|
||||||
|
public interface GraphConvert {
|
||||||
|
|
||||||
|
GraphConvert INSTANCE = Mappers.getMapper(GraphConvert.class);
|
||||||
|
|
||||||
|
|
||||||
|
Graph toEntity(GraphBO graph);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
package com.metis.flow.domain.bo;
|
package com.metis.domain.bo;
|
||||||
|
|
||||||
|
import com.metis.domain.entity.base.Graph;
|
||||||
import jakarta.validation.Valid;
|
import jakarta.validation.Valid;
|
||||||
import jakarta.validation.constraints.NotBlank;
|
import jakarta.validation.constraints.NotBlank;
|
||||||
import jakarta.validation.constraints.NotNull;
|
import jakarta.validation.constraints.NotNull;
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
package com.metis.flow.domain.bo;
|
package com.metis.domain.bo;
|
||||||
|
|
||||||
|
import com.metis.domain.entity.base.Graph;
|
||||||
import jakarta.validation.Valid;
|
import jakarta.validation.Valid;
|
||||||
import jakarta.validation.constraints.NotBlank;
|
import jakarta.validation.constraints.NotBlank;
|
||||||
import jakarta.validation.constraints.NotNull;
|
import jakarta.validation.constraints.NotNull;
|
||||||
66
metis-starter/src/main/java/com/metis/domain/bo/EdgeBO.java
Normal file
66
metis-starter/src/main/java/com/metis/domain/bo/EdgeBO.java
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
package com.metis.domain.bo;
|
||||||
|
|
||||||
|
import com.metis.enums.EdgeType;
|
||||||
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class EdgeBO {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 唯一标识符
|
||||||
|
*/
|
||||||
|
@NotNull(message = "唯一标识符不能为空")
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 标签
|
||||||
|
*/
|
||||||
|
private String label;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 节点类型
|
||||||
|
*/
|
||||||
|
@NotNull(message = "线类型不能为空")
|
||||||
|
private EdgeType type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 源节点ID,对应节点id
|
||||||
|
*/
|
||||||
|
@NotNull(message = "源节点ID不能为空")
|
||||||
|
private Long source;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 目标节点ID,对应节点id
|
||||||
|
*/
|
||||||
|
@NotNull(message = "目标节点ID不能为空")
|
||||||
|
private Long target;
|
||||||
|
/**
|
||||||
|
* 源句柄id
|
||||||
|
*/
|
||||||
|
@NotNull(message = "源句柄ID不能为空")
|
||||||
|
private Long sourceHandle;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 目标句柄id
|
||||||
|
*/
|
||||||
|
@NotNull(message = "目标句柄ID不能为空")
|
||||||
|
private Long targetHandle;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 边是否动画true/false
|
||||||
|
*/
|
||||||
|
private Boolean animated;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 开始标志
|
||||||
|
*/
|
||||||
|
private String markerStart;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 结束标记
|
||||||
|
*/
|
||||||
|
private String markerEnd;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
43
metis-starter/src/main/java/com/metis/domain/bo/GraphBO.java
Normal file
43
metis-starter/src/main/java/com/metis/domain/bo/GraphBO.java
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
package com.metis.domain.bo;
|
||||||
|
|
||||||
|
import jakarta.validation.Valid;
|
||||||
|
import jakarta.validation.constraints.NotEmpty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class GraphBO {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 边缘
|
||||||
|
*/
|
||||||
|
@Valid
|
||||||
|
@NotEmpty(message = "连线不能为空")
|
||||||
|
private List<EdgeBO> edges;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 节点
|
||||||
|
*/
|
||||||
|
@Valid
|
||||||
|
@NotEmpty(message = "节点不能为空")
|
||||||
|
private List<NodeBO> nodes;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 位置
|
||||||
|
*/
|
||||||
|
private List<Double> position;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 变焦
|
||||||
|
*/
|
||||||
|
private Double zoom;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 视窗
|
||||||
|
*/
|
||||||
|
private ViewportBo viewport;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
package com.metis.domain.bo;
|
||||||
|
|
||||||
|
import com.metis.enums.HandleType;
|
||||||
|
import com.metis.enums.PositionType;
|
||||||
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 句柄对象
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class HandleBO {
|
||||||
|
/**
|
||||||
|
* 句柄id
|
||||||
|
*/
|
||||||
|
@NotNull(message = "句柄id不能为空")
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 句柄类型
|
||||||
|
*/
|
||||||
|
@NotNull(message = "句柄类型不能为空")
|
||||||
|
private HandleType type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 句柄位置
|
||||||
|
*/
|
||||||
|
@NotNull(message = "句柄位置不能为空")
|
||||||
|
private PositionType position;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否可以连接
|
||||||
|
*/
|
||||||
|
@NotNull(message = "是否可以连接不能为空")
|
||||||
|
private Boolean connectable;
|
||||||
|
}
|
||||||
60
metis-starter/src/main/java/com/metis/domain/bo/NodeBO.java
Normal file
60
metis-starter/src/main/java/com/metis/domain/bo/NodeBO.java
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
package com.metis.domain.bo;
|
||||||
|
|
||||||
|
import com.metis.enums.NodeType;
|
||||||
|
import jakarta.validation.Valid;
|
||||||
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class NodeBO {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* id
|
||||||
|
*/
|
||||||
|
@NotNull(message = "节点id不能为空")
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 类型
|
||||||
|
*/
|
||||||
|
@NotNull(message = "节点类型不能为空")
|
||||||
|
private NodeType type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自定义类型
|
||||||
|
*/
|
||||||
|
private String customType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 位置
|
||||||
|
*/
|
||||||
|
@Valid
|
||||||
|
@NotNull(message = "节点位置不能为空")
|
||||||
|
private PositionBO position;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 业务数据
|
||||||
|
*/
|
||||||
|
@Valid
|
||||||
|
@NotNull(message = "节点业务数据不能为空")
|
||||||
|
private NodeDataBO data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 宽度
|
||||||
|
*/
|
||||||
|
// @NotNull(message = "节点宽度不能为空")
|
||||||
|
private Integer width;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 高度
|
||||||
|
*/
|
||||||
|
// @NotNull(message = "节点高度不能为空")
|
||||||
|
private Integer height;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 节点是否选中
|
||||||
|
*/
|
||||||
|
private Boolean selected;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
package com.metis.domain.bo;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
|
import com.metis.enums.PositionType;
|
||||||
|
import jakarta.validation.Valid;
|
||||||
|
import jakarta.validation.constraints.NotBlank;
|
||||||
|
import jakarta.validation.constraints.NotEmpty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class NodeDataBO {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 标签
|
||||||
|
*/
|
||||||
|
@NotBlank(message = "标签不能为空")
|
||||||
|
private String label;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 图标
|
||||||
|
*/
|
||||||
|
private String icon;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 工具栏位置
|
||||||
|
*/
|
||||||
|
private PositionType toolbarPosition;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 配置
|
||||||
|
*/
|
||||||
|
private JSONObject config;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 句柄列表
|
||||||
|
*/
|
||||||
|
@Valid
|
||||||
|
@NotEmpty(message = "句柄列表不能为空")
|
||||||
|
private List<HandleBO> handles;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package com.metis.domain.bo;
|
||||||
|
|
||||||
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class PositionBO {
|
||||||
|
/**
|
||||||
|
* x坐标
|
||||||
|
*/
|
||||||
|
@NotNull(message = "x坐标不能为空")
|
||||||
|
private Double x;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* y坐标
|
||||||
|
*/
|
||||||
|
@NotNull(message = "y坐标不能为空")
|
||||||
|
private Double y;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
package com.metis.domain.bo;
|
package com.metis.domain.bo;
|
||||||
|
|
||||||
import com.metis.enums.YesOrNoEnum;
|
import com.metis.enums.YesOrNoEnum;
|
||||||
import com.metis.flow.domain.bo.Graph;
|
import com.metis.domain.bo.GraphBO;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
@@ -13,7 +13,7 @@ public class ProcessBo {
|
|||||||
|
|
||||||
private String description;
|
private String description;
|
||||||
|
|
||||||
private Graph graph;
|
private GraphBO graph;
|
||||||
|
|
||||||
private YesOrNoEnum defaultUse;
|
private YesOrNoEnum defaultUse;
|
||||||
|
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
package com.metis.flow.domain.bo;
|
package com.metis.domain.bo;
|
||||||
|
|
||||||
import com.metis.enums.YesOrNoEnum;
|
import com.metis.enums.YesOrNoEnum;
|
||||||
|
import com.metis.domain.entity.base.Graph;
|
||||||
import jakarta.validation.Valid;
|
import jakarta.validation.Valid;
|
||||||
import jakarta.validation.constraints.NotBlank;
|
import jakarta.validation.constraints.NotBlank;
|
||||||
import jakarta.validation.constraints.NotNull;
|
import jakarta.validation.constraints.NotNull;
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package com.metis.domain.bo;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class ViewportBo {
|
||||||
|
private Double x;
|
||||||
|
private Double y;
|
||||||
|
private Double zoom;
|
||||||
|
}
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
package com.metis.domain.context;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
|
import com.metis.runner.FlowRunningContext;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Builder
|
||||||
|
public class RunningContext {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 系统数据
|
||||||
|
*/
|
||||||
|
private SysContext sys;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自定义数据
|
||||||
|
*/
|
||||||
|
private JSONObject custom;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 节点运行上下文, 需要数据进行传递
|
||||||
|
*/
|
||||||
|
private Map<Long, JSONObject> nodeRunningContext;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 下一个运行节点id集合, 可能是多个, 执行器每一次清空该节点
|
||||||
|
*/
|
||||||
|
private Set<Long> nextRunNodeId;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加节点运行环境
|
||||||
|
*
|
||||||
|
* @param nodeId 节点id
|
||||||
|
* @param nodeRunningContext 节点运行背景信息
|
||||||
|
*/
|
||||||
|
public void addNodeRunningContext(Long nodeId, JSONObject nodeRunningContext) {
|
||||||
|
this.nodeRunningContext.put(nodeId, nodeRunningContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
public JSONObject getRunningContext(Long nodeId) {
|
||||||
|
return this.nodeRunningContext.get(nodeId);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构建上下文
|
||||||
|
*
|
||||||
|
* @param context 上下文
|
||||||
|
* @return {@link RunningContext }
|
||||||
|
*/
|
||||||
|
public static RunningContext buildContext(SysContext sysContext, FlowRunningContext context) {
|
||||||
|
return RunningContext.builder()
|
||||||
|
.sys(sysContext)
|
||||||
|
.custom(context.getCustom())
|
||||||
|
.nodeRunningContext(new HashMap<>())
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
package com.metis.domain.context;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
public class RunningResult {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 节点上下文
|
||||||
|
*/
|
||||||
|
private JSONObject nodeContext;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 下一个运行节点id, 一些特殊节点需要, 必须条件节点满足后, 才会运行下一个节点
|
||||||
|
*/
|
||||||
|
private Set<Long> nextRunNodeId;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构建结果
|
||||||
|
*
|
||||||
|
* @param nodeContext 节点上下文
|
||||||
|
* @param nextRunNodeId 下一个运行节点id
|
||||||
|
* @return {@link RunningResult }
|
||||||
|
*/
|
||||||
|
public static RunningResult buildResult(JSONObject nodeContext, Set<Long> nextRunNodeId) {
|
||||||
|
return RunningResult.builder()
|
||||||
|
.nodeContext(nodeContext)
|
||||||
|
.nextRunNodeId(nextRunNodeId)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构建结果
|
||||||
|
*
|
||||||
|
* @param nextRunNodeId 下一个运行节点id
|
||||||
|
* @return {@link RunningResult }
|
||||||
|
*/
|
||||||
|
public static RunningResult buildResult(Set<Long> nextRunNodeId) {
|
||||||
|
return RunningResult.builder()
|
||||||
|
.nextRunNodeId(nextRunNodeId)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构建结果
|
||||||
|
*
|
||||||
|
* @param nodeContext 节点上下文
|
||||||
|
* @return {@link RunningResult }
|
||||||
|
*/
|
||||||
|
public static RunningResult buildResult(JSONObject nodeContext) {
|
||||||
|
return RunningResult.builder()
|
||||||
|
.nodeContext(nodeContext)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static RunningResult buildResult() {
|
||||||
|
return RunningResult.builder()
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
package com.metis.domain.context;
|
||||||
|
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
public class SysContext {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文件列表
|
||||||
|
*/
|
||||||
|
private List<String> files;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 沟通的内容
|
||||||
|
*/
|
||||||
|
private String query;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对话数
|
||||||
|
*/
|
||||||
|
private Integer dialogueCount;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 沟通的id
|
||||||
|
*/
|
||||||
|
private String conversationId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 应用程序id
|
||||||
|
*/
|
||||||
|
private Long appId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户id
|
||||||
|
*/
|
||||||
|
private Long userId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 工作流id
|
||||||
|
*/
|
||||||
|
private Long workflowId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 实例id
|
||||||
|
*/
|
||||||
|
private Long instanceId;
|
||||||
|
}
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
package com.metis.flow.domain.entity;
|
package com.metis.domain.entity;
|
||||||
|
|
||||||
|
|
||||||
import com.metis.enums.YesOrNoEnum;
|
import com.metis.enums.YesOrNoEnum;
|
||||||
import com.metis.flow.domain.bo.Graph;
|
import com.metis.domain.entity.base.Graph;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.metis.flow.domain.entity;
|
package com.metis.domain.entity;
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.annotation.TableField;
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
import com.baomidou.mybatisplus.annotation.TableId;
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
@@ -0,0 +1,131 @@
|
|||||||
|
package com.metis.domain.entity;
|
||||||
|
|
||||||
|
|
||||||
|
import com.metis.domain.entity.base.Edge;
|
||||||
|
import com.metis.domain.entity.base.Graph;
|
||||||
|
import com.metis.domain.entity.base.Node;
|
||||||
|
import com.metis.enums.NodeType;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
public class GraphDto {
|
||||||
|
|
||||||
|
private final Map<Long, Node> nodeMap;
|
||||||
|
|
||||||
|
private final Map<Long, Boolean> nodeReadyMap;
|
||||||
|
|
||||||
|
private final Map<Long, List<Edge>> edgeMap;
|
||||||
|
|
||||||
|
private final Map<Long, List<Long>> adjacencyList = new HashMap<>();
|
||||||
|
|
||||||
|
private final List<Node> sortedNodes = new ArrayList<>();
|
||||||
|
|
||||||
|
|
||||||
|
public List<Node> getSortedNodes() {
|
||||||
|
return new ArrayList<>(sortedNodes);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Edge> getEdgeNodeId(Long nodeId) {
|
||||||
|
return edgeMap.getOrDefault(nodeId, new ArrayList<>());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Node getEndNode(){
|
||||||
|
return sortedNodes.stream()
|
||||||
|
.filter(node -> NodeType.END.equals(node.getType()))
|
||||||
|
.findFirst()
|
||||||
|
.orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Node getNode(Long nodeId) {
|
||||||
|
return nodeMap.get(nodeId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateNodeReadyMap(Long nodeId, Boolean ready) {
|
||||||
|
nodeReadyMap.put(nodeId, ready);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean isNodeReady(Long nodeId) {
|
||||||
|
return nodeReadyMap.get(nodeId);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private GraphDto(List<Node> nodes, List<Edge> edges) {
|
||||||
|
this.edgeMap = edges.stream()
|
||||||
|
.collect(Collectors.groupingBy(Edge::getSource));
|
||||||
|
this.nodeMap = nodes.stream()
|
||||||
|
.collect(Collectors.toMap(Node::getId, Function.identity()));
|
||||||
|
this.nodeReadyMap = nodes.stream()
|
||||||
|
.collect(Collectors.toMap(Node::getId, node -> false));
|
||||||
|
initAdjacencyList(edges);
|
||||||
|
List<Node> nodeList = topologicalSort();
|
||||||
|
this.sortedNodes.addAll(nodeList);
|
||||||
|
Node node = sortedNodes.get(0);
|
||||||
|
if (NodeType.START.equals(node.getType())) {
|
||||||
|
nodeReadyMap.put(node.getId(), true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initAdjacencyList(List<Edge> edges) {
|
||||||
|
for (Edge edge : edges) {
|
||||||
|
List<Long> targetList = adjacencyList.getOrDefault(edge.getSource(), new ArrayList<>());
|
||||||
|
targetList.add(edge.getTarget());
|
||||||
|
adjacencyList.put(edge.getSource(), targetList);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 拓扑排序
|
||||||
|
*
|
||||||
|
* @return {@link List }<{@link Node }>
|
||||||
|
*/
|
||||||
|
private List<Node> topologicalSort() {
|
||||||
|
List<Node> sortedNodes = new ArrayList<>();
|
||||||
|
Set<Long> visited = new HashSet<>();
|
||||||
|
Set<Long> visiting = new HashSet<>();
|
||||||
|
for (Long nodeId : nodeMap.keySet()) {
|
||||||
|
if (!visited.contains(nodeId)) {
|
||||||
|
dfs(nodeId, visited, visiting, sortedNodes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Collections.reverse(sortedNodes);
|
||||||
|
return sortedNodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 深度遍历找到运行顺序
|
||||||
|
*
|
||||||
|
* @param nodeId 节点id
|
||||||
|
* @param visited 参观了
|
||||||
|
* @param visiting 参观
|
||||||
|
* @param sortedNodes 排序节点
|
||||||
|
*/
|
||||||
|
private void dfs(Long nodeId, Set<Long> visited, Set<Long> visiting, List<Node> sortedNodes) {
|
||||||
|
if (visiting.contains(nodeId)) {
|
||||||
|
throw new IllegalStateException("Cycle detected in the graph");
|
||||||
|
}
|
||||||
|
if (!visited.contains(nodeId)) {
|
||||||
|
visiting.add(nodeId);
|
||||||
|
for (Long neighbor : adjacencyList.getOrDefault(nodeId, new ArrayList<>())) {
|
||||||
|
dfs(neighbor, visited, visiting, sortedNodes);
|
||||||
|
}
|
||||||
|
visiting.remove(nodeId);
|
||||||
|
visited.add(nodeId);
|
||||||
|
sortedNodes.add(nodeMap.get(nodeId));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构建对象
|
||||||
|
*
|
||||||
|
* @param graph 图
|
||||||
|
* @return {@link GraphDto }
|
||||||
|
*/
|
||||||
|
public static GraphDto of(Graph graph) {
|
||||||
|
return new GraphDto(graph.getNodes(), graph.getEdges());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
package com.metis.flow.domain.entity.base;
|
package com.metis.domain.entity.base;
|
||||||
|
|
||||||
import com.metis.flow.enums.EdgeType;
|
import com.metis.enums.EdgeType;
|
||||||
import jakarta.validation.constraints.NotBlank;
|
|
||||||
import jakarta.validation.constraints.NotNull;
|
import jakarta.validation.constraints.NotNull;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
@@ -11,7 +10,7 @@ public class Edge {
|
|||||||
/**
|
/**
|
||||||
* 唯一标识符
|
* 唯一标识符
|
||||||
*/
|
*/
|
||||||
@NotBlank(message = "唯一标识符不能为空")
|
@NotNull(message = "唯一标识符不能为空")
|
||||||
private String id;
|
private String id;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -28,25 +27,25 @@ public class Edge {
|
|||||||
/**
|
/**
|
||||||
* 源节点ID,对应节点id
|
* 源节点ID,对应节点id
|
||||||
*/
|
*/
|
||||||
@NotBlank(message = "源节点ID不能为空")
|
@NotNull(message = "源节点ID不能为空")
|
||||||
private String source;
|
private Long source;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 目标节点ID,对应节点id
|
* 目标节点ID,对应节点id
|
||||||
*/
|
*/
|
||||||
@NotBlank(message = "目标节点ID不能为空")
|
@NotNull(message = "目标节点ID不能为空")
|
||||||
private String target;
|
private Long target;
|
||||||
/**
|
/**
|
||||||
* 源句柄id
|
* 源句柄id
|
||||||
*/
|
*/
|
||||||
@NotBlank(message = "源句柄ID不能为空")
|
@NotNull(message = "源句柄ID不能为空")
|
||||||
private String sourceHandle;
|
private Long sourceHandle;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 目标句柄id
|
* 目标句柄id
|
||||||
*/
|
*/
|
||||||
@NotBlank(message = "目标句柄ID不能为空")
|
@NotNull(message = "目标句柄ID不能为空")
|
||||||
private String targetHandle;
|
private Long targetHandle;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 边是否动画true/false
|
* 边是否动画true/false
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
package com.metis.domain.entity.base;
|
||||||
|
|
||||||
|
import jakarta.validation.Valid;
|
||||||
|
import jakarta.validation.constraints.NotEmpty;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
public class Graph {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 边缘
|
||||||
|
*/
|
||||||
|
@Valid
|
||||||
|
@NotEmpty(message = "连线不能为空")
|
||||||
|
private List<Edge> edges;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 节点
|
||||||
|
*/
|
||||||
|
@Valid
|
||||||
|
@NotEmpty(message = "节点不能为空")
|
||||||
|
private List<Node> nodes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 位置
|
||||||
|
*/
|
||||||
|
private List<Double> position;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 变焦
|
||||||
|
*/
|
||||||
|
private Double zoom;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 视窗
|
||||||
|
*/
|
||||||
|
private Viewport viewport;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,8 +1,7 @@
|
|||||||
package com.metis.flow.domain.entity.base;
|
package com.metis.domain.entity.base;
|
||||||
|
|
||||||
import com.metis.flow.enums.PositionType;
|
import com.metis.enums.HandleType;
|
||||||
import com.metis.flow.enums.HandleType;
|
import com.metis.enums.PositionType;
|
||||||
import jakarta.validation.constraints.NotBlank;
|
|
||||||
import jakarta.validation.constraints.NotNull;
|
import jakarta.validation.constraints.NotNull;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
@@ -14,8 +13,8 @@ public class Handle {
|
|||||||
/**
|
/**
|
||||||
* 句柄id
|
* 句柄id
|
||||||
*/
|
*/
|
||||||
@NotBlank(message = "句柄id不能为空")
|
@NotNull(message = "句柄id不能为空")
|
||||||
private String id;
|
private Long id;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 句柄类型
|
* 句柄类型
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
package com.metis.domain.entity.base;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
|
import com.metis.enums.NodeType;
|
||||||
|
import jakarta.validation.Valid;
|
||||||
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class Node {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* id
|
||||||
|
*/
|
||||||
|
@NotNull(message = "节点id不能为空")
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 类型
|
||||||
|
*/
|
||||||
|
@NotNull(message = "节点类型不能为空")
|
||||||
|
private NodeType type;
|
||||||
|
|
||||||
|
private String customType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 位置
|
||||||
|
*/
|
||||||
|
@Valid
|
||||||
|
@NotNull(message = "节点位置不能为空")
|
||||||
|
private Position position;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 业务数据
|
||||||
|
*/
|
||||||
|
@Valid
|
||||||
|
@NotNull(message = "节点业务数据不能为空")
|
||||||
|
private NodeData data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 宽度
|
||||||
|
*/
|
||||||
|
// @NotNull(message = "节点宽度不能为空")
|
||||||
|
private Integer width;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 高度
|
||||||
|
*/
|
||||||
|
// @NotNull(message = "节点高度不能为空")
|
||||||
|
private Integer height;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 节点是否选中
|
||||||
|
*/
|
||||||
|
private Boolean selected;
|
||||||
|
|
||||||
|
private transient Class<?> configClass;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取配置
|
||||||
|
*
|
||||||
|
* @return {@link T }
|
||||||
|
*/
|
||||||
|
public <T> T getConfig() {
|
||||||
|
if (ObjectUtil.isNull(data.getConfig())) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return (T) data.getConfig().to(configClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置配置类
|
||||||
|
*
|
||||||
|
* @param configClass 配置类
|
||||||
|
*/
|
||||||
|
public <T> void setConfigClass(Class<T> configClass) {
|
||||||
|
if (ObjectUtil.isNotNull(this.configClass)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.configClass = configClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
package com.metis.domain.entity.base;
|
||||||
|
|
||||||
|
public abstract class NodeConfig {
|
||||||
|
}
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
package com.metis.flow.domain.entity.base;
|
package com.metis.domain.entity.base;
|
||||||
|
|
||||||
import com.alibaba.fastjson2.JSONObject;
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
import com.metis.flow.enums.PositionType;
|
import com.metis.enums.PositionType;
|
||||||
import jakarta.validation.Valid;
|
import jakarta.validation.Valid;
|
||||||
import jakarta.validation.constraints.NotNull;
|
import jakarta.validation.constraints.NotBlank;
|
||||||
import jakarta.validation.constraints.Size;
|
import jakarta.validation.constraints.NotEmpty;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -15,6 +15,7 @@ public class NodeData {
|
|||||||
/**
|
/**
|
||||||
* 标签
|
* 标签
|
||||||
*/
|
*/
|
||||||
|
@NotBlank(message = "标签不能为空")
|
||||||
private String label;
|
private String label;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -27,6 +28,7 @@ public class NodeData {
|
|||||||
*/
|
*/
|
||||||
private PositionType toolbarPosition;
|
private PositionType toolbarPosition;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 配置
|
* 配置
|
||||||
*/
|
*/
|
||||||
@@ -36,8 +38,7 @@ public class NodeData {
|
|||||||
* 句柄列表
|
* 句柄列表
|
||||||
*/
|
*/
|
||||||
@Valid
|
@Valid
|
||||||
@NotNull(message = "句柄列表不能为空")
|
@NotEmpty(message = "句柄列表不能为空")
|
||||||
@Size(min = 1, message = "句柄列表不能为空")
|
|
||||||
private List<Handle> handles;
|
private List<Handle> handles;
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,98 @@
|
|||||||
|
package com.metis.domain.entity.base;
|
||||||
|
|
||||||
|
import cn.hutool.core.lang.Assert;
|
||||||
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
|
import com.metis.enums.FileUploadType;
|
||||||
|
import com.metis.enums.NodeVariableType;
|
||||||
|
import jakarta.validation.Valid;
|
||||||
|
import jakarta.validation.constraints.NotBlank;
|
||||||
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class NodeVariable {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 参数字段
|
||||||
|
*/
|
||||||
|
@NotBlank(message = "参数字段不能为空")
|
||||||
|
private String variable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 标签
|
||||||
|
*/
|
||||||
|
private String label;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 最大长度
|
||||||
|
*/
|
||||||
|
private Integer maxLength;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 类型
|
||||||
|
*/
|
||||||
|
@NotNull(message = "类型不能为空")
|
||||||
|
private String type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否必填
|
||||||
|
*/
|
||||||
|
@NotNull(message = "是否必填不能为空")
|
||||||
|
private Boolean required;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 选项
|
||||||
|
*/
|
||||||
|
@Valid
|
||||||
|
private List<VariableOption> options;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 允许上传方式
|
||||||
|
*/
|
||||||
|
private List<FileUploadType> allowedFileUploadMethods;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 允许文件类型
|
||||||
|
*/
|
||||||
|
private List<String> allowedFileTypes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 允许文件扩展名
|
||||||
|
*/
|
||||||
|
private List<String> allowedFileExtensions;
|
||||||
|
|
||||||
|
|
||||||
|
@JsonIgnore
|
||||||
|
public Object getValue(JSONObject custom) {
|
||||||
|
Object serializable = getSerializable(custom);
|
||||||
|
Assert.isTrue(!(ObjectUtil.isNull(serializable) && ObjectUtil.isNotNull(required) && required), "参数字段 {} 的值不能为空", variable);
|
||||||
|
return serializable;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Object getSerializable(JSONObject custom) {
|
||||||
|
switch (getVariableType()) {
|
||||||
|
case TEXT_INPUT, PARAGRAPH, SELECT, FILE -> {
|
||||||
|
return custom.getString(variable);
|
||||||
|
}
|
||||||
|
case NUMBER -> {
|
||||||
|
return custom.getInteger(variable);
|
||||||
|
}
|
||||||
|
case FILE_LIST -> {
|
||||||
|
return custom.getList(variable, String.class);
|
||||||
|
}
|
||||||
|
default -> throw new RuntimeException("不支持的类型");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@JsonIgnore
|
||||||
|
public NodeVariableType getVariableType() {
|
||||||
|
return NodeVariableType.get(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.metis.flow.domain.entity.base;
|
package com.metis.domain.entity.base;
|
||||||
|
|
||||||
import jakarta.validation.constraints.NotNull;
|
import jakarta.validation.constraints.NotNull;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package com.metis.domain.entity.base;
|
||||||
|
|
||||||
|
|
||||||
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class VariableOption {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 标签
|
||||||
|
*/
|
||||||
|
private String label;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 值
|
||||||
|
*/
|
||||||
|
@NotNull(message = "值不能为空")
|
||||||
|
private String value;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package com.metis.domain.entity.base;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class Viewport {
|
||||||
|
private Double x;
|
||||||
|
private Double y;
|
||||||
|
private Double zoom;
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package com.metis.domain.entity.config.node;
|
||||||
|
|
||||||
|
import com.metis.domain.entity.base.NodeConfig;
|
||||||
|
import jakarta.validation.constraints.NotBlank;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
public class DocumentExtractorNodeConfig extends NodeConfig {
|
||||||
|
|
||||||
|
@NotBlank(message = "文件类型不能为空")
|
||||||
|
private String fileType;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package com.metis.domain.entity.config.node;
|
||||||
|
|
||||||
|
import com.metis.domain.entity.base.NodeConfig;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
public class EndNodeConfig extends NodeConfig {
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package com.metis.domain.entity.config.node;
|
||||||
|
|
||||||
|
import com.metis.domain.entity.base.NodeConfig;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
public class LLMNodeConfig extends NodeConfig {
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package com.metis.domain.entity.config.node;
|
||||||
|
|
||||||
|
import com.metis.domain.entity.base.NodeConfig;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
public class QuestionClassifierConfig extends NodeConfig {
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package com.metis.domain.entity.config.node;
|
||||||
|
|
||||||
|
import com.metis.domain.entity.base.NodeConfig;
|
||||||
|
import com.metis.domain.entity.base.NodeVariable;
|
||||||
|
import jakarta.validation.Valid;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
public class StartNodeConfig extends NodeConfig {
|
||||||
|
|
||||||
|
@Valid
|
||||||
|
private List<NodeVariable> variables;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
package com.metis.domain.entity.config;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.metis.flow.domain.query;
|
package com.metis.domain.query;
|
||||||
|
|
||||||
import lombok.Builder;
|
import lombok.Builder;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
@@ -1,9 +1,10 @@
|
|||||||
package com.metis.flow.engine;
|
package com.metis.engine;
|
||||||
|
|
||||||
import com.metis.flow.domain.query.AppQuery;
|
|
||||||
import com.metis.flow.domain.entity.App;
|
import com.metis.domain.bo.CreateApp;
|
||||||
import com.metis.flow.domain.bo.CreateApp;
|
import com.metis.domain.bo.UpdateApp;
|
||||||
import com.metis.flow.domain.bo.UpdateApp;
|
import com.metis.domain.entity.App;
|
||||||
|
import com.metis.domain.query.AppQuery;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@@ -26,6 +27,14 @@ public interface AppEngineService {
|
|||||||
List<App> list(AppQuery query);
|
List<App> list(AppQuery query);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过应用id获取
|
||||||
|
*
|
||||||
|
* @param appId 应用程序id
|
||||||
|
* @return {@link App }
|
||||||
|
*/
|
||||||
|
App getByAppId(Long appId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 按身份证领取
|
* 按身份证领取
|
||||||
*
|
*
|
||||||
@@ -37,10 +46,10 @@ public interface AppEngineService {
|
|||||||
/**
|
/**
|
||||||
* 通过部署id获取
|
* 通过部署id获取
|
||||||
*
|
*
|
||||||
* @param deploymentId 部署id
|
* @param workflowId 部署id
|
||||||
* @return {@link App }
|
* @return {@link App }
|
||||||
*/
|
*/
|
||||||
App getByDeploymentId(Long deploymentId);
|
App getByWorkflowId(Long workflowId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 按id列表
|
* 按id列表
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
package com.metis.engine;
|
||||||
|
|
||||||
|
import com.metis.runner.FlowRunningContext;
|
||||||
|
import com.metis.runner.RunnerResult;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 应用引擎运行器服务
|
||||||
|
*
|
||||||
|
* @author clay
|
||||||
|
* @date 2025/04/07
|
||||||
|
*/
|
||||||
|
public interface AppFlowEngineRunnerService {
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 运行
|
||||||
|
*
|
||||||
|
* @param context 上下文
|
||||||
|
* @return {@link RunnerResult }
|
||||||
|
*/
|
||||||
|
RunnerResult running(FlowRunningContext context);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,19 +1,20 @@
|
|||||||
package com.metis.flow.engine.impl;
|
package com.metis.engine.impl;
|
||||||
|
|
||||||
import cn.hutool.core.lang.Assert;
|
import cn.hutool.core.lang.Assert;
|
||||||
import cn.hutool.core.util.IdUtil;
|
import cn.hutool.core.util.IdUtil;
|
||||||
import cn.hutool.core.util.ObjectUtil;
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
|
import com.metis.constant.BaseConstant;
|
||||||
|
import com.metis.convert.BaseAppConvert;
|
||||||
|
import com.metis.domain.bo.BuildApp;
|
||||||
|
import com.metis.domain.bo.CreateApp;
|
||||||
|
import com.metis.domain.bo.UpdateApp;
|
||||||
|
import com.metis.domain.entity.App;
|
||||||
|
import com.metis.domain.entity.BaseApp;
|
||||||
|
import com.metis.domain.query.AppQuery;
|
||||||
|
import com.metis.engine.AppEngineService;
|
||||||
import com.metis.enums.YesOrNoEnum;
|
import com.metis.enums.YesOrNoEnum;
|
||||||
import com.metis.flow.constant.BaseConstant;
|
import com.metis.service.BaseAppService;
|
||||||
import com.metis.flow.convert.BaseAppConvert;
|
import com.metis.validator.ValidatorService;
|
||||||
import com.metis.flow.domain.bo.BuildApp;
|
|
||||||
import com.metis.flow.domain.bo.CreateApp;
|
|
||||||
import com.metis.flow.domain.bo.UpdateApp;
|
|
||||||
import com.metis.flow.domain.query.AppQuery;
|
|
||||||
import com.metis.flow.domain.entity.*;
|
|
||||||
import com.metis.flow.engine.AppEngineService;
|
|
||||||
import com.metis.flow.service.BaseAppService;
|
|
||||||
import com.metis.flow.validator.ValidatorService;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
@@ -42,6 +43,12 @@ public class AppEngineServiceImpl implements AppEngineService {
|
|||||||
return BaseAppConvert.INSTANCE.toApps(list);
|
return BaseAppConvert.INSTANCE.toApps(list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public App getByAppId(Long appId) {
|
||||||
|
BaseApp baseApp = baseAppService.getByAppId(appId);
|
||||||
|
return BaseAppConvert.INSTANCE.toApp(baseApp);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public App getByAppId(Long appId, Integer version) {
|
public App getByAppId(Long appId, Integer version) {
|
||||||
BaseApp baseApp = baseAppService.getByAppIdAndVersion(appId, version);
|
BaseApp baseApp = baseAppService.getByAppIdAndVersion(appId, version);
|
||||||
@@ -49,8 +56,8 @@ public class AppEngineServiceImpl implements AppEngineService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public App getByDeploymentId(Long deploymentId) {
|
public App getByWorkflowId(Long workflowId) {
|
||||||
BaseApp baseApp = baseAppService.getById(deploymentId);
|
BaseApp baseApp = baseAppService.getById(workflowId);
|
||||||
return BaseAppConvert.INSTANCE.toApp(baseApp);
|
return BaseAppConvert.INSTANCE.toApp(baseApp);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,6 +68,7 @@ public class AppEngineServiceImpl implements AppEngineService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public App create(CreateApp createApp) {
|
public App create(CreateApp createApp) {
|
||||||
BuildApp buildApp = BaseAppConvert.INSTANCE.toBuildApp(createApp);
|
BuildApp buildApp = BaseAppConvert.INSTANCE.toBuildApp(createApp);
|
||||||
// 校验
|
// 校验
|
||||||
@@ -0,0 +1,159 @@
|
|||||||
|
package com.metis.engine.impl;
|
||||||
|
|
||||||
|
import cn.hutool.core.collection.CollUtil;
|
||||||
|
import cn.hutool.core.lang.Assert;
|
||||||
|
import cn.hutool.core.util.IdUtil;
|
||||||
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import com.alibaba.fastjson2.JSON;
|
||||||
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
|
import com.metis.domain.context.RunningContext;
|
||||||
|
import com.metis.domain.context.RunningResult;
|
||||||
|
import com.metis.domain.context.SysContext;
|
||||||
|
import com.metis.domain.entity.App;
|
||||||
|
import com.metis.domain.entity.GraphDto;
|
||||||
|
import com.metis.domain.entity.base.Edge;
|
||||||
|
import com.metis.domain.entity.base.Node;
|
||||||
|
import com.metis.engine.AppEngineService;
|
||||||
|
import com.metis.engine.AppFlowEngineRunnerService;
|
||||||
|
import com.metis.enums.NodeType;
|
||||||
|
import com.metis.runner.FlowRunningContext;
|
||||||
|
import com.metis.runner.NodeRunner;
|
||||||
|
import com.metis.runner.RunnerResult;
|
||||||
|
import com.metis.runner.factory.NodeRunnerFactory;
|
||||||
|
import com.metis.utils.GenericInterfacesUtils;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class AppFlowEngineRunnerServiceImpl implements AppFlowEngineRunnerService {
|
||||||
|
|
||||||
|
private final AppEngineService appEngineService;
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RunnerResult running(FlowRunningContext context) {
|
||||||
|
App app = getApp(context);
|
||||||
|
Assert.isTrue(ObjectUtil.isNotNull(app), "app为空");
|
||||||
|
// 构建运行实例, 并将运行实例放入上下文
|
||||||
|
Long instanceId = IdUtil.getSnowflakeNextId();
|
||||||
|
// 构建系统上下文信息
|
||||||
|
SysContext sysContext = SysContext.builder()
|
||||||
|
.files(context.getFiles())
|
||||||
|
.appId(app.getId())
|
||||||
|
.workflowId(app.getWorkflowId())
|
||||||
|
.instanceId(instanceId)
|
||||||
|
.build();
|
||||||
|
// 构建运行中上下文
|
||||||
|
RunningContext runningContext = RunningContext.buildContext(sysContext, context);
|
||||||
|
// 构建节点映射对象
|
||||||
|
GraphDto graph = GraphDto.of(app.getGraph());
|
||||||
|
Set<Node> readyRunningNode = new HashSet<>();
|
||||||
|
|
||||||
|
// 获取到开始节点
|
||||||
|
// 开始节点为空,则表示数据存在异常
|
||||||
|
Assert.isTrue(ObjectUtil.isNotNull(readyRunningNode), "流程图不存在开始节点");
|
||||||
|
for (Node node : graph.getSortedNodes()) {
|
||||||
|
Long nodeId = node.getId();
|
||||||
|
if (!graph.isNodeReady(nodeId)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
log.info("当前运行节点 id:{}, name:{}, type:{}", node.getId(), node.getData().getLabel(), node.getType());
|
||||||
|
// 当前节点接下来的连接线信息
|
||||||
|
List<Edge> edges = graph.getEdgeNodeId(nodeId);
|
||||||
|
// 执行
|
||||||
|
NodeRunner nodeRunner = getNodeRunner(node);
|
||||||
|
node.setConfigClass(GenericInterfacesUtils.getClass(nodeRunner));
|
||||||
|
// 下一个需要运行的节点id加入到可以运行的节点中
|
||||||
|
// 获取到返回结果
|
||||||
|
RunningResult result = nodeRunner.run(runningContext, node, edges);
|
||||||
|
log.info("节点执行结果:{}", JSON.toJSONString(result));
|
||||||
|
// 节点执行结果参数放入上下文中
|
||||||
|
if (ObjectUtil.isNotNull(result.getNodeContext())) {
|
||||||
|
runningContext.addNodeRunningContext(node.getId(), result.getNodeContext());
|
||||||
|
}
|
||||||
|
// 下一个需要运行的节点id加入到可以运行的节点中
|
||||||
|
if (CollUtil.isNotEmpty(result.getNextRunNodeId())) {
|
||||||
|
for (Long nextNodeId : result.getNextRunNodeId()) {
|
||||||
|
graph.updateNodeReadyMap(nextNodeId, true);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 如果没有返回, 则认为所有的下级节点都需要运行
|
||||||
|
edges.forEach(edge -> {
|
||||||
|
graph.updateNodeReadyMap(edge.getTarget(), true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Node endNode = graph.getEndNode();
|
||||||
|
|
||||||
|
JSONObject endRunningContext = runningContext.getRunningContext(endNode.getId());
|
||||||
|
|
||||||
|
return RunnerResult.builder()
|
||||||
|
.result(endRunningContext)
|
||||||
|
.context(sysContext)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void doRunning(Set<Node> readyRunningNode, Map<Long, List<Edge>> edgeMap, RunningContext runningContext) {
|
||||||
|
Set<Long> nextRunningNodeId = new HashSet<>();
|
||||||
|
for (Node runningNode : readyRunningNode) {
|
||||||
|
// 当前节点接下来的连接线信息
|
||||||
|
List<Edge> edges = edgeMap.getOrDefault(runningNode.getId(), new ArrayList<>());
|
||||||
|
// 执行
|
||||||
|
NodeRunner nodeRunner = getNodeRunner(runningNode);
|
||||||
|
runningNode.setConfigClass(GenericInterfacesUtils.getClass(nodeRunner));
|
||||||
|
// 获取到返回结果
|
||||||
|
RunningResult result = nodeRunner.run(runningContext, runningNode, edges);
|
||||||
|
// 节点执行结果参数放入上下文中
|
||||||
|
if (ObjectUtil.isNotNull(result.getNodeContext())) {
|
||||||
|
runningContext.addNodeRunningContext(runningNode.getId(), result.getNodeContext());
|
||||||
|
}
|
||||||
|
if (CollUtil.isNotEmpty(result.getNextRunNodeId())) {
|
||||||
|
nextRunningNodeId.addAll(result.getNextRunNodeId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private RunningResult doRunning(RunningContext runningContext, Node node, List<Edge> edges) {
|
||||||
|
NodeRunner nodeRunner = getNodeRunner(node);
|
||||||
|
node.setConfigClass(GenericInterfacesUtils.getClass(nodeRunner));
|
||||||
|
// 获取到返回结果
|
||||||
|
return nodeRunner.run(runningContext, node, edges);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取节点运行程序
|
||||||
|
*
|
||||||
|
* @param node 节点
|
||||||
|
* @return {@link NodeRunner }
|
||||||
|
*/
|
||||||
|
private NodeRunner getNodeRunner(Node node) {
|
||||||
|
if (NodeType.CUSTOM.equals(node.getType())) {
|
||||||
|
Assert.isTrue(StrUtil.isNotBlank(node.getCustomType()), "自定义节点类型不能为空");
|
||||||
|
return NodeRunnerFactory.getCustom(node.getCustomType());
|
||||||
|
}
|
||||||
|
return NodeRunnerFactory.get(node.getType());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取到应用程序信息
|
||||||
|
*
|
||||||
|
* @param context 上下文
|
||||||
|
* @return {@link App }
|
||||||
|
*/
|
||||||
|
private App getApp(FlowRunningContext context) {
|
||||||
|
if (ObjectUtil.isNotNull(context.getWorkflowId())) {
|
||||||
|
return appEngineService.getByWorkflowId(context.getWorkflowId());
|
||||||
|
}
|
||||||
|
return appEngineService.getByAppId(context.getAppId());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.metis.flow.enums;
|
package com.metis.enums;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||||
import com.fasterxml.jackson.annotation.JsonValue;
|
import com.fasterxml.jackson.annotation.JsonValue;
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
package com.metis.enums;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonValue;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文件上传类型
|
||||||
|
*
|
||||||
|
* @author clay
|
||||||
|
* @date 2025/04/08
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@AllArgsConstructor
|
||||||
|
public enum FileUploadType {
|
||||||
|
LOCAL_FILE(1, "localFile", "本地文件"),
|
||||||
|
REMOTE_URL(2, "remoteUrl", "远程URL");
|
||||||
|
|
||||||
|
|
||||||
|
private final Integer code;
|
||||||
|
|
||||||
|
@JsonValue
|
||||||
|
private final String value;
|
||||||
|
|
||||||
|
private final String name;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 枚举序列化器(前端传code时自动转换为对应枚举)
|
||||||
|
*
|
||||||
|
* @param value 值
|
||||||
|
* @return 枚举
|
||||||
|
*/
|
||||||
|
@JsonCreator(mode = JsonCreator.Mode.DELEGATING)
|
||||||
|
public static FileUploadType get(String value) {
|
||||||
|
return Arrays.stream(FileUploadType.class.getEnumConstants())
|
||||||
|
.filter(e -> e.getValue().equals(value))
|
||||||
|
.findFirst()
|
||||||
|
.orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.metis.flow.enums;
|
package com.metis.enums;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||||
import com.fasterxml.jackson.annotation.JsonValue;
|
import com.fasterxml.jackson.annotation.JsonValue;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.metis.flow.enums;
|
package com.metis.enums;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||||
import com.fasterxml.jackson.annotation.JsonValue;
|
import com.fasterxml.jackson.annotation.JsonValue;
|
||||||
@@ -11,8 +11,14 @@ import java.util.Arrays;
|
|||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public enum NodeType {
|
public enum NodeType {
|
||||||
|
|
||||||
START(1, "start", "开始", Object.class),
|
START(1, "start", "开始"),
|
||||||
END(2, "end", "结束", Object.class),
|
END(2, "end", "结束"),
|
||||||
|
DOCUMENT_EXTRACTOR(3, "documentExtractor", "文档提取器"),
|
||||||
|
CUSTOM(4, "custom", "自定义节点"),
|
||||||
|
LLM(5, "llm", "LLM"),
|
||||||
|
QUESTION_CLASSIFIER(6, "questionClassifier", "问题分类器"),
|
||||||
|
IF_ELSE(7, "ifElse", "条件判断"),
|
||||||
|
|
||||||
|
|
||||||
;
|
;
|
||||||
|
|
||||||
@@ -24,8 +30,6 @@ public enum NodeType {
|
|||||||
|
|
||||||
private final String name;
|
private final String name;
|
||||||
|
|
||||||
private final Class<?> configClass;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 枚举序列化器(前端传code时自动转换为对应枚举)
|
* 枚举序列化器(前端传code时自动转换为对应枚举)
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
package com.metis.enums;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonValue;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 节点变量类型
|
||||||
|
*
|
||||||
|
* @author clay
|
||||||
|
* @date 2025/04/08
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@AllArgsConstructor
|
||||||
|
public enum NodeVariableType {
|
||||||
|
TEXT_INPUT(1, "text-input", "文本"),
|
||||||
|
PARAGRAPH(2, "paragraph", "段落"),
|
||||||
|
SELECT(3, "select", "下拉框"),
|
||||||
|
NUMBER(4, "number", "数字"),
|
||||||
|
FILE(5, "file", "文件"),
|
||||||
|
FILE_LIST(6, "file-list", "文件列表")
|
||||||
|
;
|
||||||
|
|
||||||
|
|
||||||
|
private final Integer code;
|
||||||
|
|
||||||
|
@JsonValue
|
||||||
|
private final String value;
|
||||||
|
|
||||||
|
private final String name;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 枚举序列化器(前端传code时自动转换为对应枚举)
|
||||||
|
*
|
||||||
|
* @param value 值
|
||||||
|
* @return 枚举
|
||||||
|
*/
|
||||||
|
@JsonCreator(mode = JsonCreator.Mode.DELEGATING)
|
||||||
|
public static NodeVariableType get(String value) {
|
||||||
|
return Arrays.stream(NodeVariableType.class.getEnumConstants())
|
||||||
|
.filter(e -> e.getValue().equals(value))
|
||||||
|
.findFirst()
|
||||||
|
.orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.metis.flow.enums;
|
package com.metis.enums;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||||
import com.fasterxml.jackson.annotation.JsonValue;
|
import com.fasterxml.jackson.annotation.JsonValue;
|
||||||
@@ -1,10 +1,12 @@
|
|||||||
package com.metis.facade;
|
package com.metis.facade;
|
||||||
|
|
||||||
|
import com.metis.convert.GraphConvert;
|
||||||
|
import com.metis.domain.bo.CreateApp;
|
||||||
import com.metis.domain.bo.ProcessBo;
|
import com.metis.domain.bo.ProcessBo;
|
||||||
import com.metis.flow.domain.entity.App;
|
import com.metis.domain.bo.UpdateApp;
|
||||||
import com.metis.flow.domain.bo.CreateApp;
|
import com.metis.domain.entity.App;
|
||||||
import com.metis.flow.domain.bo.UpdateApp;
|
import com.metis.domain.entity.base.Graph;
|
||||||
import com.metis.flow.engine.AppEngineService;
|
import com.metis.engine.AppEngineService;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
@@ -21,24 +23,27 @@ public class ProcessDefinitionFacade {
|
|||||||
*
|
*
|
||||||
* @param processBo 过程业务对象
|
* @param processBo 过程业务对象
|
||||||
*/
|
*/
|
||||||
public void create(ProcessBo processBo) {
|
public Long create(ProcessBo processBo) {
|
||||||
|
Graph graph = GraphConvert.INSTANCE.toEntity(processBo.getGraph());
|
||||||
CreateApp createApp = CreateApp.builder()
|
CreateApp createApp = CreateApp.builder()
|
||||||
.name(processBo.getName())
|
.name(processBo.getName())
|
||||||
.graph(processBo.getGraph())
|
.graph(graph)
|
||||||
.build();
|
.build();
|
||||||
App app = appEngineService.create(createApp);
|
App app = appEngineService.create(createApp);
|
||||||
|
return app.getWorkflowId();
|
||||||
}
|
}
|
||||||
|
|
||||||
public App getByDeploymentId(Long deploymentId) {
|
public App getByDeploymentId(Long deploymentId) {
|
||||||
return appEngineService.getByDeploymentId(deploymentId);
|
return appEngineService.getByWorkflowId(deploymentId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void update(ProcessBo processBo) {
|
public void update(ProcessBo processBo) {
|
||||||
|
Graph graph = GraphConvert.INSTANCE.toEntity(processBo.getGraph());
|
||||||
appEngineService.update(UpdateApp.builder()
|
appEngineService.update(UpdateApp.builder()
|
||||||
.defaultUse(processBo.getDefaultUse())
|
.defaultUse(processBo.getDefaultUse())
|
||||||
.appId(processBo.getAppId())
|
.appId(processBo.getAppId())
|
||||||
.name(processBo.getName())
|
.name(processBo.getName())
|
||||||
.graph(processBo.getGraph())
|
.graph(graph)
|
||||||
.build());
|
.build());
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
package com.metis.flow.mapper;
|
package com.metis.mapper;
|
||||||
|
|
||||||
import com.metis.flow.domain.entity.BaseApp;
|
import com.metis.domain.entity.BaseApp;
|
||||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
import org.apache.ibatis.annotations.Mapper;
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package com.metis.runner;
|
||||||
|
|
||||||
|
import com.metis.domain.entity.base.NodeConfig;
|
||||||
|
import com.metis.enums.NodeType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自定义节点运行器
|
||||||
|
*
|
||||||
|
* @author clay
|
||||||
|
* @date 2025/04/20
|
||||||
|
*/
|
||||||
|
public interface CustomNodeRunner<T extends NodeConfig> extends NodeRunner<T> {
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取自定义节点的节点类型
|
||||||
|
*
|
||||||
|
* @return {@link String }
|
||||||
|
*/
|
||||||
|
String getCustomNodeType();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 得到类型
|
||||||
|
*
|
||||||
|
* @return {@link NodeType }
|
||||||
|
*/
|
||||||
|
default NodeType getType() {
|
||||||
|
return NodeType.CUSTOM;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
package com.metis.runner;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 运行上下文
|
||||||
|
*
|
||||||
|
* @author clay
|
||||||
|
* @date 2025/04/07
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
public class FlowRunningContext {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文件列表
|
||||||
|
*/
|
||||||
|
private List<String> files;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 应用程序id
|
||||||
|
*/
|
||||||
|
private Long appId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户id
|
||||||
|
*/
|
||||||
|
private Long userId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 工作流id
|
||||||
|
*/
|
||||||
|
private Long workflowId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自定义
|
||||||
|
*/
|
||||||
|
private JSONObject custom;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
56
metis-starter/src/main/java/com/metis/runner/NodeRunner.java
Normal file
56
metis-starter/src/main/java/com/metis/runner/NodeRunner.java
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
package com.metis.runner;
|
||||||
|
|
||||||
|
import cn.hutool.core.collection.CollUtil;
|
||||||
|
import com.metis.domain.context.RunningContext;
|
||||||
|
import com.metis.domain.context.RunningResult;
|
||||||
|
import com.metis.domain.entity.base.Edge;
|
||||||
|
import com.metis.domain.entity.base.Node;
|
||||||
|
import com.metis.domain.entity.base.NodeConfig;
|
||||||
|
import com.metis.enums.NodeType;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 内置节点运行器
|
||||||
|
*
|
||||||
|
* @author clay
|
||||||
|
* @date 2025/04/20
|
||||||
|
*/
|
||||||
|
public interface NodeRunner<T extends NodeConfig> {
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 运行
|
||||||
|
*
|
||||||
|
* @param context 上下文
|
||||||
|
* @param node 节点配置信息
|
||||||
|
* @param edges 当前接下来的连线信息, 一些特殊节点需要节点内部判断下一个运行节点
|
||||||
|
* @return {@link RunningContext }
|
||||||
|
*/
|
||||||
|
RunningResult run(RunningContext context, Node node, List<Edge> edges);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取节点类型
|
||||||
|
*
|
||||||
|
* @return {@link NodeType }
|
||||||
|
*/
|
||||||
|
NodeType getType();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取下一个节点id
|
||||||
|
*
|
||||||
|
* @param edges 边缘
|
||||||
|
* @return {@link Set }<{@link Long }>
|
||||||
|
*/
|
||||||
|
default Set<Long> getNextNodeIds(List<Edge> edges) {
|
||||||
|
if (CollUtil.isEmpty(edges)) {
|
||||||
|
return Set.of();
|
||||||
|
}
|
||||||
|
return edges.stream().map(Edge::getTarget).collect(Collectors.toSet());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
package com.metis.runner;
|
||||||
|
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
|
import com.metis.domain.context.SysContext;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 运行结果
|
||||||
|
*
|
||||||
|
* @author clay
|
||||||
|
* @date 2025/04/07
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
public class RunnerResult {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 运行内容
|
||||||
|
*/
|
||||||
|
private JSONObject result;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 上下文
|
||||||
|
*/
|
||||||
|
private SysContext context;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
package com.metis.runner.factory;
|
||||||
|
|
||||||
|
import cn.hutool.core.lang.Assert;
|
||||||
|
import com.metis.enums.NodeType;
|
||||||
|
import com.metis.runner.CustomNodeRunner;
|
||||||
|
import com.metis.runner.NodeRunner;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
public final class NodeRunnerFactory {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 内置节点运行器
|
||||||
|
*/
|
||||||
|
private static final Map<NodeType, NodeRunner> NODE_MAP = new ConcurrentHashMap<>(8);
|
||||||
|
/**
|
||||||
|
* 自定义节点映射
|
||||||
|
*/
|
||||||
|
private static final Map<String, NodeRunner> CUSTOM_NODE_MAP = new ConcurrentHashMap<>(8);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 注册
|
||||||
|
*
|
||||||
|
* @param runner 跑步者
|
||||||
|
*/
|
||||||
|
static void register(NodeRunner runner) {
|
||||||
|
NODE_MAP.put(runner.getType(), runner);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 得到
|
||||||
|
*
|
||||||
|
* @param type 类型
|
||||||
|
* @return {@link NodeRunner }
|
||||||
|
*/
|
||||||
|
public static NodeRunner get(NodeType type) {
|
||||||
|
return NODE_MAP.get(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 注册自定义节点
|
||||||
|
*
|
||||||
|
* @param runner 跑步者
|
||||||
|
*/
|
||||||
|
static void registerCustom(CustomNodeRunner runner) {
|
||||||
|
Assert.isTrue(!CUSTOM_NODE_MAP.containsKey(runner.getCustomNodeType()), "已存在类型:{}, class:{}的运行器", runner.getCustomNodeType(), runner.getClass());
|
||||||
|
CUSTOM_NODE_MAP.put(runner.getCustomNodeType(), runner);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 得到自定义节点运行器
|
||||||
|
*
|
||||||
|
* @param type 类型
|
||||||
|
* @return {@link NodeRunner }
|
||||||
|
*/
|
||||||
|
public static NodeRunner getCustom(String type) {
|
||||||
|
return CUSTOM_NODE_MAP.get(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
package com.metis.runner.factory;
|
||||||
|
|
||||||
|
import cn.hutool.core.lang.Assert;
|
||||||
|
import com.metis.enums.NodeType;
|
||||||
|
import com.metis.runner.CustomNodeRunner;
|
||||||
|
import com.metis.runner.NodeRunner;
|
||||||
|
import org.springframework.beans.BeansException;
|
||||||
|
import org.springframework.context.ApplicationContext;
|
||||||
|
import org.springframework.context.ApplicationContextAware;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* runner初始化
|
||||||
|
*
|
||||||
|
* @author clay
|
||||||
|
* @date 2025/04/07
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class RunnerInitialize implements ApplicationContextAware {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
||||||
|
|
||||||
|
Map<String, NodeRunner> runnerMap = applicationContext.getBeansOfType(NodeRunner.class);
|
||||||
|
|
||||||
|
runnerMap.forEach((runnerBeanName, runner) -> {
|
||||||
|
if (NodeType.CUSTOM.equals(runner.getType())) {
|
||||||
|
Assert.isTrue(runner instanceof CustomNodeRunner, "自定义节点必须实现CustomNodeRunner接口");
|
||||||
|
NodeRunnerFactory.registerCustom((CustomNodeRunner) runner);
|
||||||
|
} else {
|
||||||
|
NodeRunnerFactory.register(runner);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package com.metis.runner.impl;
|
||||||
|
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
|
import com.metis.domain.context.RunningContext;
|
||||||
|
import com.metis.domain.context.RunningResult;
|
||||||
|
import com.metis.domain.entity.base.Edge;
|
||||||
|
import com.metis.domain.entity.base.Node;
|
||||||
|
import com.metis.domain.entity.config.node.EndNodeConfig;
|
||||||
|
import com.metis.enums.NodeType;
|
||||||
|
import com.metis.runner.NodeRunner;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
public class EndNodeRunner implements NodeRunner<EndNodeConfig> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RunningResult run(RunningContext context, Node node, List<Edge> edges) {
|
||||||
|
JSONObject contextNodeValue = new JSONObject();
|
||||||
|
contextNodeValue.put("userId", context.getSys().getAppId());
|
||||||
|
return RunningResult.buildResult(contextNodeValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public NodeType getType() {
|
||||||
|
return NodeType.END;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
package com.metis.runner.impl;
|
||||||
|
|
||||||
|
import com.metis.domain.context.RunningContext;
|
||||||
|
import com.metis.domain.context.RunningResult;
|
||||||
|
import com.metis.domain.entity.base.Edge;
|
||||||
|
import com.metis.domain.entity.base.Node;
|
||||||
|
import com.metis.domain.entity.config.node.LLMNodeConfig;
|
||||||
|
import com.metis.enums.NodeType;
|
||||||
|
import com.metis.runner.NodeRunner;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
public class LLMNodeRunner implements NodeRunner<LLMNodeConfig> {
|
||||||
|
@Override
|
||||||
|
public RunningResult run(RunningContext context, Node node, List<Edge> edges) {
|
||||||
|
return RunningResult.buildResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public NodeType getType() {
|
||||||
|
return NodeType.LLM;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
package com.metis.runner.impl;
|
||||||
|
|
||||||
|
import com.metis.domain.context.RunningContext;
|
||||||
|
import com.metis.domain.context.RunningResult;
|
||||||
|
import com.metis.domain.entity.base.Edge;
|
||||||
|
import com.metis.domain.entity.base.Node;
|
||||||
|
import com.metis.domain.entity.config.node.QuestionClassifierConfig;
|
||||||
|
import com.metis.enums.NodeType;
|
||||||
|
import com.metis.runner.NodeRunner;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Random;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
public class QuestionClassifierRunner implements NodeRunner<QuestionClassifierConfig> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RunningResult run(RunningContext context, Node node, List<Edge> edges) {
|
||||||
|
Set<Long> nextNodeIds = getNextNodeIds(edges);
|
||||||
|
// 生成随机索引
|
||||||
|
Random random = new Random();
|
||||||
|
int randomIndex = random.nextInt(nextNodeIds.size());
|
||||||
|
List<Long> nodeIds = new ArrayList<>(nextNodeIds);
|
||||||
|
return RunningResult.buildResult(Set.of(nodeIds.get(randomIndex)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public NodeType getType() {
|
||||||
|
return NodeType.QUESTION_CLASSIFIER;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
package com.metis.runner.impl;
|
||||||
|
|
||||||
|
import cn.hutool.core.collection.CollUtil;
|
||||||
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
|
import com.metis.domain.context.RunningContext;
|
||||||
|
import com.metis.domain.context.RunningResult;
|
||||||
|
import com.metis.domain.entity.base.Edge;
|
||||||
|
import com.metis.domain.entity.base.Node;
|
||||||
|
import com.metis.domain.entity.base.NodeVariable;
|
||||||
|
import com.metis.domain.entity.config.node.StartNodeConfig;
|
||||||
|
import com.metis.enums.NodeType;
|
||||||
|
import com.metis.runner.NodeRunner;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 启动节点运行器, 开始节点功能主要为将用户传入的参数进行校验, 并放入到上下文中
|
||||||
|
*
|
||||||
|
* @author clay
|
||||||
|
* @date 2025/04/08
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
public class StartNodeRunner implements NodeRunner<StartNodeConfig> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RunningResult run(RunningContext context, Node node, List<Edge> edges) {
|
||||||
|
StartNodeConfig config = node.getConfig();
|
||||||
|
// 获取到节点的自定义参数
|
||||||
|
List<NodeVariable> variables = config.getVariables();
|
||||||
|
// 如果没有自定义参数, 则直接返回
|
||||||
|
if (CollUtil.isEmpty(variables)) {
|
||||||
|
return RunningResult.buildResult();
|
||||||
|
}
|
||||||
|
// 获取用户自定义参数
|
||||||
|
JSONObject custom = context.getCustom();
|
||||||
|
JSONObject contextNodeValue = new JSONObject();
|
||||||
|
for (NodeVariable variable : variables) {
|
||||||
|
Object value = variable.getValue(custom);
|
||||||
|
contextNodeValue.put(variable.getVariable(), value);
|
||||||
|
}
|
||||||
|
return RunningResult.buildResult(contextNodeValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public NodeType getType() {
|
||||||
|
return NodeType.START;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
package com.metis.flow.service;
|
package com.metis.service;
|
||||||
|
|
||||||
import com.metis.enums.YesOrNoEnum;
|
import com.metis.enums.YesOrNoEnum;
|
||||||
import com.metis.flow.domain.query.AppQuery;
|
import com.metis.domain.query.AppQuery;
|
||||||
import com.metis.flow.domain.entity.BaseApp;
|
import com.metis.domain.entity.BaseApp;
|
||||||
import com.baomidou.mybatisplus.extension.service.IService;
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.metis.flow.service.impl;
|
package com.metis.service.impl;
|
||||||
|
|
||||||
import cn.hutool.core.util.ObjectUtil;
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
@@ -6,10 +6,10 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|||||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
import com.metis.enums.YesOrNoEnum;
|
import com.metis.enums.YesOrNoEnum;
|
||||||
import com.metis.flow.domain.query.AppQuery;
|
import com.metis.domain.query.AppQuery;
|
||||||
import com.metis.flow.domain.entity.BaseApp;
|
import com.metis.domain.entity.BaseApp;
|
||||||
import com.metis.flow.mapper.BaseAppMapper;
|
import com.metis.mapper.BaseAppMapper;
|
||||||
import com.metis.flow.service.BaseAppService;
|
import com.metis.service.BaseAppService;
|
||||||
import com.metis.utils.PageConditionUtil;
|
import com.metis.utils.PageConditionUtil;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package com.metis.utils;
|
||||||
|
|
||||||
|
import java.lang.reflect.ParameterizedType;
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
|
||||||
|
public class GenericInterfacesUtils {
|
||||||
|
|
||||||
|
|
||||||
|
public static <T> Class<T> getClass(Object object) {
|
||||||
|
|
||||||
|
Type[] genericInterfaces = object.getClass().getGenericInterfaces();
|
||||||
|
for (Type genericInterface : genericInterfaces) {
|
||||||
|
if (genericInterface instanceof ParameterizedType) {
|
||||||
|
ParameterizedType parameterizedType = (ParameterizedType) genericInterface;
|
||||||
|
Type[] typeArguments = parameterizedType.getActualTypeArguments();
|
||||||
|
if (typeArguments.length > 0) {
|
||||||
|
return (Class<T>) typeArguments[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new IllegalStateException("无法获取泛型类型");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user