diff --git a/api/pom.xml b/api/pom.xml index 57819e01..99b0fba9 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -43,7 +43,7 @@ coze-api - 0.4.2 + 0.4.3 scm:git:git://github.com/coze-dev/coze-java.git diff --git a/api/src/main/java/com/coze/openapi/api/WorkflowAPI.java b/api/src/main/java/com/coze/openapi/api/WorkflowAPI.java new file mode 100644 index 00000000..b0f481ad --- /dev/null +++ b/api/src/main/java/com/coze/openapi/api/WorkflowAPI.java @@ -0,0 +1,31 @@ +package com.coze.openapi.api; + +import com.coze.openapi.client.common.BaseReq; +import com.coze.openapi.client.common.BaseResponse; +import com.coze.openapi.client.workflows.WorkflowGetResp; +import com.coze.openapi.client.workflows.WorkflowListResp; + +import retrofit2.Call; +import retrofit2.http.GET; +import retrofit2.http.Path; +import retrofit2.http.Query; +import retrofit2.http.Tag; + +public interface WorkflowAPI { + + @GET("/v1/workflows") + Call> list( + @Query("workspace_id") String workspaceId, + @Query("page_num") Integer pageNum, + @Query("page_size") Integer pageSize, + @Query("workflow_mode") String workflowMode, + @Query("app_id") String appId, + @Query("publish_status") String publishStatus, + @Tag BaseReq baseReq); + + @GET("/v1/workflows/{workflow_id}") + Call> get( + @Path("workflow_id") String workflowId, + @Query("include_input_output") Boolean includeInputOutput, + @Tag BaseReq baseReq); +} diff --git a/api/src/main/java/com/coze/openapi/client/workflows/WorkflowGetReq.java b/api/src/main/java/com/coze/openapi/client/workflows/WorkflowGetReq.java new file mode 100644 index 00000000..5408e2c7 --- /dev/null +++ b/api/src/main/java/com/coze/openapi/client/workflows/WorkflowGetReq.java @@ -0,0 +1,29 @@ +package com.coze.openapi.client.workflows; + +import com.coze.openapi.client.common.BaseReq; +import com.fasterxml.jackson.annotation.JsonProperty; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.NonNull; +import lombok.experimental.SuperBuilder; + +@Data +@EqualsAndHashCode(callSuper = true) +@SuperBuilder +@NoArgsConstructor +@AllArgsConstructor +public class WorkflowGetReq extends BaseReq { + + /** 工作流 ID。 */ + @NonNull + @JsonProperty("workflow_id") + private String workflowId; + + /** 是否在返回结果中返回输入和输出参数的结构体。 true:返回输入输出参数结构体 false:不返回输入输出参数结构体 默认值为 false。 */ + @NonNull + @JsonProperty("include_input_output") + private Boolean includeInputOutput; +} diff --git a/api/src/main/java/com/coze/openapi/client/workflows/WorkflowGetResp.java b/api/src/main/java/com/coze/openapi/client/workflows/WorkflowGetResp.java new file mode 100644 index 00000000..203c72ce --- /dev/null +++ b/api/src/main/java/com/coze/openapi/client/workflows/WorkflowGetResp.java @@ -0,0 +1,30 @@ +package com.coze.openapi.client.workflows; + +import com.coze.openapi.client.workflows.model.WorkflowDetail; +import com.coze.openapi.client.workflows.model.WorkflowInput; +import com.coze.openapi.client.workflows.model.WorkflowOutput; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@JsonInclude(JsonInclude.Include.NON_NULL) +public class WorkflowGetResp { + + /** 工作流开始节点的输入参数的结构体。 */ + @JsonProperty("input") + private WorkflowInput input; + /** 工作流结束节点的输出参数的结构体。 */ + @JsonProperty("output") + private WorkflowOutput output; + /** 工作流的详细信息。 */ + @JsonProperty("workflow_detail") + private WorkflowDetail workflowDetail; +} diff --git a/api/src/main/java/com/coze/openapi/client/workflows/WorkflowListReq.java b/api/src/main/java/com/coze/openapi/client/workflows/WorkflowListReq.java new file mode 100644 index 00000000..47ec7d82 --- /dev/null +++ b/api/src/main/java/com/coze/openapi/client/workflows/WorkflowListReq.java @@ -0,0 +1,44 @@ +package com.coze.openapi.client.workflows; + +import com.coze.openapi.client.common.BaseReq; +import com.fasterxml.jackson.annotation.JsonProperty; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.NonNull; +import lombok.experimental.SuperBuilder; + +@Data +@EqualsAndHashCode(callSuper = true) +@SuperBuilder +@NoArgsConstructor +@AllArgsConstructor +public class WorkflowListReq extends BaseReq { + + /** 工作空间 ID,用于指定要查询的工作空间。 */ + @NonNull + @JsonProperty("workspace_id") + private String workspaceId; + + /** 查询结果分页展示时,此参数用于设置查看的页码。最小值为 1。 */ + @NonNull + @JsonProperty("page_num") + private Integer pageNum; + /** 查询结果分页展示时,此参数用于设置每页返回的数据量。取值范围为 1 ~ 30,默认为 10。 */ + @JsonProperty("page_size") + private Integer pageSize; + /** 工作流类型,默认为空,即查询所有工作流类型。枚举值: workflow:工作流。 chatflow:对话流。 */ + @JsonProperty("workflow_mode") + private String workflowMode; + /** 扣子应用 ID,用于查询指定应用关联的工作流。默认为空,即不指定应用。 */ + @JsonProperty("app_id") + private String appId; + /** + * 工作流的发布状态,用于筛选不同发布状态的工作流。枚举值: all :所有状态。 published_online :(默认值)已发布的正式版。 unpublished_draft + * :当前为草稿状态。 + */ + @JsonProperty("publish_status") + private String publishStatus; +} diff --git a/api/src/main/java/com/coze/openapi/client/workflows/WorkflowListResp.java b/api/src/main/java/com/coze/openapi/client/workflows/WorkflowListResp.java new file mode 100644 index 00000000..c3d25d7f --- /dev/null +++ b/api/src/main/java/com/coze/openapi/client/workflows/WorkflowListResp.java @@ -0,0 +1,26 @@ +package com.coze.openapi.client.workflows; + +import java.util.List; + +import com.coze.openapi.client.workflows.model.WorkflowDetail; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@JsonInclude(JsonInclude.Include.NON_NULL) +public class WorkflowListResp { + /** 工作流的基础信息。 */ + @JsonProperty("items") + private List items; + /** 标识当前返回的工作流列表是否还有更多数据未返回。 true :还有更多未返回的回调应用。 false:已返回所有数据。 */ + @JsonProperty("has_more") + private Boolean hasMore; +} diff --git a/api/src/main/java/com/coze/openapi/client/workflows/model/WorkflowCreator.java b/api/src/main/java/com/coze/openapi/client/workflows/model/WorkflowCreator.java new file mode 100644 index 00000000..48b734d3 --- /dev/null +++ b/api/src/main/java/com/coze/openapi/client/workflows/model/WorkflowCreator.java @@ -0,0 +1,22 @@ +package com.coze.openapi.client.workflows.model; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class WorkflowCreator { + + /** 工作流创建者的扣子用户 ID。 */ + @JsonProperty("id") + private String id; + /** 工作流创建者的扣子用户名。 */ + @JsonProperty("name") + private String name; +} diff --git a/api/src/main/java/com/coze/openapi/client/workflows/model/WorkflowDetail.java b/api/src/main/java/com/coze/openapi/client/workflows/model/WorkflowDetail.java new file mode 100644 index 00000000..34343385 --- /dev/null +++ b/api/src/main/java/com/coze/openapi/client/workflows/model/WorkflowDetail.java @@ -0,0 +1,40 @@ +package com.coze.openapi.client.workflows.model; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class WorkflowDetail { + + /** 工作流关联的应用 ID。若工作流未关联任何应用,则该字段值为 0 */ + @JsonProperty("app_id") + private String app_id; + /** 工作流创建者的信息,包含创建者的用户 ID 和用户名 */ + @JsonProperty("creator") + private WorkflowCreator creator; + /** 工作流图标的 URL 地址。 */ + @JsonProperty("icon_url") + private String iconUrl; + /** 工作流的创建时间,以 Unix 时间戳表示,单位为秒 */ + @JsonProperty("created_at") + private String createdAt; + /** 工作流的最后更新时间,以 Unix 时间戳表示,单位为秒 */ + @JsonProperty("updated_at") + private String updatedAt; + /** 工作流的描述。 */ + @JsonProperty("description") + private String description; + /** 工作流 ID。 */ + @JsonProperty("workflow_id") + private String workflowId; + /** 工作流名称。 */ + @JsonProperty("workflow_name") + private String workflowName; +} diff --git a/api/src/main/java/com/coze/openapi/client/workflows/model/WorkflowInput.java b/api/src/main/java/com/coze/openapi/client/workflows/model/WorkflowInput.java new file mode 100644 index 00000000..abe34e24 --- /dev/null +++ b/api/src/main/java/com/coze/openapi/client/workflows/model/WorkflowInput.java @@ -0,0 +1,21 @@ +package com.coze.openapi.client.workflows.model; + +import java.util.Map; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class WorkflowInput { + + /** 开始节点的输入参数结构体。 */ + @JsonProperty("parameters") + private Map parameters; +} diff --git a/api/src/main/java/com/coze/openapi/client/workflows/model/WorkflowOutput.java b/api/src/main/java/com/coze/openapi/client/workflows/model/WorkflowOutput.java new file mode 100644 index 00000000..f71ac34c --- /dev/null +++ b/api/src/main/java/com/coze/openapi/client/workflows/model/WorkflowOutput.java @@ -0,0 +1,27 @@ +package com.coze.openapi.client.workflows.model; + +import java.util.Map; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class WorkflowOutput { + + /** 工作流结束节点输出变量的数组。以键值对形式存储,格式为 { "变量名称": { "type": "变量类型" } }。 */ + @JsonProperty("parameters") + private Map parameters; + /** 工作流结束节点返回文本时,智能体回复内容的结构。仅当 terminate_plan 为 use_answer_content 时会返回。 */ + @JsonProperty("content") + private String content; + /** 结束节点的返回类型,枚举值: return_variables:返回变量。 use_answer_content:返回文本。 */ + @JsonProperty("terminate_plan") + private String terminatePlan; +} diff --git a/api/src/main/java/com/coze/openapi/client/workflows/model/WorkflowParameter.java b/api/src/main/java/com/coze/openapi/client/workflows/model/WorkflowParameter.java new file mode 100644 index 00000000..9a5825f3 --- /dev/null +++ b/api/src/main/java/com/coze/openapi/client/workflows/model/WorkflowParameter.java @@ -0,0 +1,36 @@ +package com.coze.openapi.client.workflows.model; + +import java.util.Map; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class WorkflowParameter { + + /** 该参数的类型。 */ + @JsonProperty("type") + private String type; + /** 当参数类型为 array 时,该字段用于定义数组元素的子类型。 */ + @JsonProperty("items") + private WorkflowParameter items; + /** 标识输入参数是否为必填项。 true:该参数为必填项。 false:该参数为可选项。 */ + @JsonProperty("required") + private Boolean required; + /** 当参数类型为 object 时,该字段用于定义数组元素的子类型。 */ + @JsonProperty("properties") + private Map properties; + /** 该参数的描述信息。 */ + @JsonProperty("description") + private String description; + /** 该参数配置的默认值。 */ + @JsonProperty("default_value") + private String defaultValue; +} diff --git a/api/src/main/java/com/coze/openapi/service/service/CozeAPI.java b/api/src/main/java/com/coze/openapi/service/service/CozeAPI.java index 3f0709a0..60369c4d 100644 --- a/api/src/main/java/com/coze/openapi/service/service/CozeAPI.java +++ b/api/src/main/java/com/coze/openapi/service/service/CozeAPI.java @@ -216,6 +216,7 @@ public CozeAPI build() { retrofit.create(DatasetImageAPI.class)); WorkflowService workflowAPI = new WorkflowService( + retrofit.create(WorkflowAPI.class), retrofit.create(WorkflowRunAPI.class), retrofit.create(WorkflowRunHistoryAPI.class), retrofit.create(WorkflowChatAPI.class)); diff --git a/api/src/main/java/com/coze/openapi/service/service/workflow/WorkflowService.java b/api/src/main/java/com/coze/openapi/service/service/workflow/WorkflowService.java index b9cb5264..b0272c65 100644 --- a/api/src/main/java/com/coze/openapi/service/service/workflow/WorkflowService.java +++ b/api/src/main/java/com/coze/openapi/service/service/workflow/WorkflowService.java @@ -1,17 +1,29 @@ package com.coze.openapi.service.service.workflow; +import com.coze.openapi.api.WorkflowAPI; import com.coze.openapi.api.WorkflowChatAPI; import com.coze.openapi.api.WorkflowRunAPI; import com.coze.openapi.api.WorkflowRunHistoryAPI; +import com.coze.openapi.client.common.BaseResponse; +import com.coze.openapi.client.workflows.WorkflowGetReq; +import com.coze.openapi.client.workflows.WorkflowGetResp; +import com.coze.openapi.client.workflows.WorkflowListReq; +import com.coze.openapi.client.workflows.WorkflowListResp; +import com.coze.openapi.service.utils.Utils; public class WorkflowService { private final WorkflowRunService runService; private final WorkflowChatService chatService; + private final WorkflowAPI workflowAPI; public WorkflowService( - WorkflowRunAPI api, WorkflowRunHistoryAPI historyAPI, WorkflowChatAPI chatAPI) { - this.runService = new WorkflowRunService(api, historyAPI); + WorkflowAPI api, + WorkflowRunAPI runAPI, + WorkflowRunHistoryAPI historyAPI, + WorkflowChatAPI chatAPI) { + this.runService = new WorkflowRunService(runAPI, historyAPI); this.chatService = new WorkflowChatService(chatAPI); + this.workflowAPI = api; } public WorkflowRunService runs() { @@ -21,4 +33,20 @@ public WorkflowRunService runs() { public WorkflowChatService chat() { return chatService; } + + public BaseResponse list(WorkflowListReq req) { + return Utils.execute( + workflowAPI.list( + req.getWorkspaceId(), + req.getPageNum(), + req.getPageSize(), + req.getWorkflowMode(), + req.getAppId(), + req.getPublishStatus(), + req)); + } + + public BaseResponse get(WorkflowGetReq req) { + return Utils.execute(workflowAPI.get(req.getWorkflowId(), req.getIncludeInputOutput(), req)); + } } diff --git a/api/src/test/java/com/coze/openapi/service/service/workflow/WorkFlowServiceTest.java b/api/src/test/java/com/coze/openapi/service/service/workflow/WorkFlowServiceTest.java new file mode 100644 index 00000000..f1ea7545 --- /dev/null +++ b/api/src/test/java/com/coze/openapi/service/service/workflow/WorkFlowServiceTest.java @@ -0,0 +1,164 @@ +package com.coze.openapi.service.service.workflow; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import com.coze.openapi.api.WorkflowAPI; +import com.coze.openapi.api.WorkflowChatAPI; +import com.coze.openapi.api.WorkflowRunAPI; +import com.coze.openapi.api.WorkflowRunHistoryAPI; +import com.coze.openapi.client.common.BaseResponse; +import com.coze.openapi.client.workflows.WorkflowGetReq; +import com.coze.openapi.client.workflows.WorkflowGetResp; +import com.coze.openapi.client.workflows.WorkflowListReq; +import com.coze.openapi.client.workflows.WorkflowListResp; +import com.coze.openapi.client.workflows.model.WorkflowDetail; +import com.coze.openapi.client.workflows.model.WorkflowInput; +import com.coze.openapi.client.workflows.model.WorkflowOutput; +import com.coze.openapi.client.workflows.model.WorkflowParameter; +import com.coze.openapi.utils.Utils; + +import retrofit2.Call; +import retrofit2.Response; + +public class WorkFlowServiceTest { + + @Mock private WorkflowAPI workflowAPI; + + @Mock private WorkflowRunAPI workflowRunAPI; + + @Mock private WorkflowRunHistoryAPI workflowRunHistoryAPI; + + @Mock private WorkflowChatAPI workflowChatAPI; + + private WorkflowService workflowService; + + @BeforeEach + public void setup() { + MockitoAnnotations.openMocks(this); + workflowService = + new WorkflowService(workflowAPI, workflowRunAPI, workflowRunHistoryAPI, workflowChatAPI); + } + + @Test + void testList() throws Exception { + // 准备测试数据 + String workSpaceId = "test_space_id"; + String workflowID = "test_workflow_id"; + Integer pageNum = 1; + + WorkflowListReq req = + WorkflowListReq.builder().workspaceId(workSpaceId).pageNum(pageNum).build(); + + WorkflowDetail detail = + WorkflowDetail.builder() + .workflowId(workflowID) + .workflowName("测试工作流") + .description("这是一个用于单元测试的工作流") + .createdAt("2024-01-01T00:00:00Z") + .updatedAt("2024-01-02T00:00:00Z") + .build(); + + WorkflowListResp data = + WorkflowListResp.builder().items(Arrays.asList(detail)).hasMore(true).build(); + + BaseResponse baseResponse = + BaseResponse.builder() + .code(0) + .msg("success") + .logID(Utils.TEST_LOG_ID) + .data(data) + .build(); + + // 创建 mock Call 对象 + Call> call = mock(Call.class); + when(workflowAPI.list(any(), any(), any(), any(), any(), any(), any())).thenReturn(call); + when(call.execute()).thenReturn(Response.success(baseResponse, Utils.getCommonHeader())); + + // 执行测试 + BaseResponse result = workflowService.list(req); + + // 验证结果 + assertNotNull(result); + assertEquals(workflowID, result.getData().getItems().get(0).getWorkflowId()); + } + + @Test + void testGet() throws Exception { + // 准备测试数据 + String workflowID = "test_workflow_id"; + boolean includeInputOutput = true; + + WorkflowGetReq req = + WorkflowGetReq.builder() + .workflowId(workflowID) + .includeInputOutput(includeInputOutput) + .build(); + + Map inputParameters = new HashMap<>(); + inputParameters.put( + "test_param1", + WorkflowParameter.builder() + .type("string") + .required(true) + .description("测试参数1") + .defaultValue("param1") + .build()); + inputParameters.put( + "test_param2", + WorkflowParameter.builder() + .type("string") + .required(false) + .description("测试参数2") + .defaultValue("param2") + .build()); + WorkflowInput input = WorkflowInput.builder().parameters(inputParameters).build(); + + WorkflowOutput output = + WorkflowOutput.builder().terminatePlan("use_answer_content").content("这里是测试输出参数").build(); + + WorkflowDetail detail = + WorkflowDetail.builder() + .workflowId(workflowID) + .workflowName("测试工作流") + .description("这是一个用于单元测试的工作流") + .createdAt("2024-01-01T00:00:00Z") + .updatedAt("2024-01-02T00:00:00Z") + .build(); + + WorkflowGetResp data = + WorkflowGetResp.builder().input(input).output(output).workflowDetail(detail).build(); + + BaseResponse baseResponse = + BaseResponse.builder() + .code(0) + .msg("success") + .logID(Utils.TEST_LOG_ID) + .data(data) + .build(); + + // 创建 mock Call 对象 + Call> call = mock(Call.class); + when(workflowAPI.get(any(), any(), any())).thenReturn(call); + when(call.execute()).thenReturn(Response.success(baseResponse, Utils.getCommonHeader())); + + // 执行测试 + BaseResponse result = workflowService.get(req); + + // 验证结果 + assertNotNull(result); + assertEquals(workflowID, result.getData().getWorkflowDetail().getWorkflowId()); + } +}