diff --git a/bonus-modules/bonus-ai/src/main/java/com/bonus/ai/client/OnlineAnnotateUtil.java b/bonus-modules/bonus-ai/src/main/java/com/bonus/ai/client/OnlineAnnotateUtil.java index 8df90d3..0e09d85 100644 --- a/bonus-modules/bonus-ai/src/main/java/com/bonus/ai/client/OnlineAnnotateUtil.java +++ b/bonus-modules/bonus-ai/src/main/java/com/bonus/ai/client/OnlineAnnotateUtil.java @@ -6,13 +6,17 @@ import java.util.stream.Collectors; import java.util.stream.Stream; public class OnlineAnnotateUtil { - final static String template = ".*?"; + final static String template = ".*?"; /** * 替换 View 中的 Label 标签内容 - * @param labels 要替换的 labels 列表 * @return 替换后的字符串 */ - public static String rectangleImageLabels(List labels) { + public static String rectangleImageLabels(String labelsStr) { + if ( labelsStr.isEmpty()) { + return ""; + } + // 使用 split 分割字符串并转换为 List + List labels = Arrays.asList(labelsStr.split(",")); if (labels == null || labels.isEmpty()){ return ""; } @@ -48,11 +52,11 @@ public class OnlineAnnotateUtil { * * */ - public static void main(String[] args) { -// List labels = Arrays.asList("label1", "label2", "label3"); - List labels = Stream.of("label1", "label2", "label3") - .collect(Collectors.toList()); - String result = rectangleImageLabels(labels); - System.out.println(result); - } +// public static void main(String[] args) { +//// List labels = Arrays.asList("label1", "label2", "label3"); +// List labels = Stream.of("label1", "label2", "label3") +// .collect(Collectors.toList()); +// String result = rectangleImageLabels(labels); +// System.out.println(result); +// } } diff --git a/bonus-modules/bonus-ai/src/main/java/com/bonus/ai/client/OnlineAnnotationFallbackFactory.java b/bonus-modules/bonus-ai/src/main/java/com/bonus/ai/client/OnlineAnnotationFallbackFactory.java deleted file mode 100644 index cd734a6..0000000 --- a/bonus-modules/bonus-ai/src/main/java/com/bonus/ai/client/OnlineAnnotationFallbackFactory.java +++ /dev/null @@ -1,83 +0,0 @@ -package com.bonus.ai.client; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.cloud.openfeign.FallbackFactory; -import org.springframework.stereotype.Component; - - -@Component -public class OnlineAnnotationFallbackFactory implements FallbackFactory { - private static final Logger log = LoggerFactory.getLogger(OnlineAnnotationFallbackFactory.class); - - @Override - public OnlineAnnotationService create(Throwable throwable) { - - log.error("系统服务调用失败:{}", throwable.getMessage()); - return new OnlineAnnotationService() { - @Override - public String createProject(ProjectParam projectParam, String authorization) { - return null; - - } - - @Override - public String getProjectById(String id, String authorization) { - return ""; - } - - @Override - public boolean deleteProjectById(String id, String authorization) { - return false; - } - - @Override - public String updateProject(ProjectParam projectParam, String authorization) { - return ""; - } - - @Override - public String createTask(TaskParam task, String authorization) { - return null; - } - - @Override - public String getTaskById(String id, String authorization) { - return ""; - } - - @Override - public boolean deleteTaskById(String id, String authorization) { - return false; - } - - @Override - public String updateTask(TaskParam task, String authorization) { - return ""; - } - - @Override - public String createAnnotation(AnnotationParam annotationParam, String authorization) { - return ""; - } - - @Override - public String getAnnotationById(String id, String authorization) { - return ""; - } - - @Override - public boolean deleteAnnotationById(String id, String authorization) { - return false; - } - - @Override - public String updateAnnotation(AnnotationParam annotationParam, String authorization) { - return ""; - } - - - }; - } -} - diff --git a/bonus-modules/bonus-ai/src/main/java/com/bonus/ai/client/OnlineAnnotationService.java b/bonus-modules/bonus-ai/src/main/java/com/bonus/ai/client/OnlineAnnotationService.java deleted file mode 100644 index da3372b..0000000 --- a/bonus-modules/bonus-ai/src/main/java/com/bonus/ai/client/OnlineAnnotationService.java +++ /dev/null @@ -1,72 +0,0 @@ -package com.bonus.ai.client; - -import org.springframework.cloud.openfeign.FeignClient; -import org.springframework.web.bind.annotation.*; - - -@FeignClient(name = "onlineAnnotationService") -public interface OnlineAnnotationService { - - /** - * project <------> 人工智能数据中心的标注任务 - * project 增删改查 - */ - @PostMapping("/api/projects/") - public String createProject(@RequestBody ProjectParam projectParam, @RequestHeader(AIConstants.AUTHORIZATION_HEADER) String authorization); - - @GetMapping("/api/projects/{id}/") - public String getProjectById(@PathVariable("id") String id, @RequestHeader(AIConstants.AUTHORIZATION_HEADER) String authorization); - - @DeleteMapping("/api/projects/{id}/") - public boolean deleteProjectById(@PathVariable("id") String id, @RequestHeader(AIConstants.AUTHORIZATION_HEADER) String authorization); - - @PatchMapping("/api/projects/") - public String updateProject(@RequestBody ProjectParam projectParam, @RequestHeader(AIConstants.AUTHORIZATION_HEADER) String authorization); - - /** - * task <------> 人工智能数据中心的具体的标注文件 - * task 增删改查 - */ - @PostMapping("/api/tasks/") - public String createTask(@RequestBody TaskParam task, @RequestHeader(AIConstants.AUTHORIZATION_HEADER) String authorization); - - @GetMapping("/api/tasks/{id}/") - public String getTaskById(@PathVariable("id") String id, @RequestHeader(AIConstants.AUTHORIZATION_HEADER) String authorization); - - - @DeleteMapping("/api/tasks/{id}/") - public boolean deleteTaskById(@PathVariable("id") String id, @RequestHeader(AIConstants.AUTHORIZATION_HEADER) String authorization); - - @PatchMapping("/api/tasks/") - public String updateTask(@RequestBody TaskParam task, @RequestHeader(AIConstants.AUTHORIZATION_HEADER) String authorization); - - - /** - * annotation <------> 人工智能数据中心的标注结果 - * annotation 增删改查 - */ - @PostMapping("/api/tasks/{id}/annotations/") - public String createAnnotation(@RequestBody AnnotationParam annotationParam, @RequestHeader(AIConstants.AUTHORIZATION_HEADER) String authorization); - - - @GetMapping("/api/annotations/{id}") - public String getAnnotationById(@PathVariable("id") String id, @RequestHeader(AIConstants.AUTHORIZATION_HEADER) String authorization); - - @DeleteMapping("/api/annotations/{id}") - public boolean deleteAnnotationById(@PathVariable("id") String id, @RequestHeader(AIConstants.AUTHORIZATION_HEADER) String authorization); - - - @PatchMapping("/api/tasks/{id}/annotations/") - public String updateAnnotation(@RequestBody AnnotationParam annotationParam, @RequestHeader(AIConstants.AUTHORIZATION_HEADER) String authorization); - - /** - * 导出指定project的所有标注结果 - */ -// @GetMapping("/api/project/{id}/export") -// public String exportAnnotationByProjectId(@PathVariable("id") String id, @RequestHeader(AIConstants.AUTHORIZATION_HEADER) String authorization); -// -// @GetMapping("/api/annotations/{id}") -// public String exportAnnotationByTaskIds(@PathVariable("id") String id, @RequestHeader(AIConstants.AUTHORIZATION_HEADER) String authorization); - - -} diff --git a/bonus-modules/bonus-ai/src/main/java/com/bonus/ai/client/OnlineAnnotationServiceOkHttp.java b/bonus-modules/bonus-ai/src/main/java/com/bonus/ai/client/OnlineAnnotationServiceOkHttp.java new file mode 100644 index 0000000..23b6e70 --- /dev/null +++ b/bonus-modules/bonus-ai/src/main/java/com/bonus/ai/client/OnlineAnnotationServiceOkHttp.java @@ -0,0 +1,159 @@ +package com.bonus.ai.client; + +import com.bonus.ai.config.OnlineAnnotateConfig; +import lombok.extern.slf4j.Slf4j; +import okhttp3.*; +import org.springframework.stereotype.Service; +import java.io.IOException; +import com.fasterxml.jackson.databind.ObjectMapper; + +import javax.annotation.Resource; + +@Slf4j +@Service +public class OnlineAnnotationServiceOkHttp { + + private static final OkHttpClient client = new OkHttpClient(); + private static final ObjectMapper objectMapper = new ObjectMapper(); // 用于JSON序列化和反序列化 + //private static final String BASE_URL = "http://127.0.0.1:8080/api/projects/"; // 替换为实际URL + + @Resource + private OnlineAnnotateConfig onlineAnnotateConfig; + + + /** + * project <------> 人工智能数据中心的标注任务 + * project 增删改查 + */ + // Create project + public ProjectParam createProject(ProjectInputParam projectParam) throws IOException { + String url = onlineAnnotateConfig.getUrl()+ "/projects/"; + String json = objectMapper.writeValueAsString(projectParam); + + RequestBody body = RequestBody.create(json, MediaType.parse("application/json")); + + log.error("Request JSON: " + json); + Request request = new Request.Builder() + .url(url) + .post(body) + .addHeader("Authorization", onlineAnnotateConfig.getApikey()) + .build(); + + String response = executeRequest(request); + return ProjectParam.fromJson(response); + } + + // Get project by ID + public ProjectParam getProjectById(String id) throws IOException { + String url = onlineAnnotateConfig.getUrl()+ "/projects/" + id + "/"; + Request request = new Request.Builder() + .url(url) + .get() + .addHeader("Authorization", onlineAnnotateConfig.getApikey()) + .build(); + + String response = executeRequest(request); + return ProjectParam.fromJson(response); + } + + // Delete project by ID + public boolean deleteProjectById(String id) throws IOException { + String url = onlineAnnotateConfig.getUrl()+ "/projects/" + id + "/"; + Request request = new Request.Builder() + .url(url) + .delete() + .addHeader("Authorization", onlineAnnotateConfig.getApikey()) + .build(); + + String response = executeRequest(request); + return response != null && !response.isEmpty(); + } + + // Update project + public ProjectParam updateProject(ProjectInputParam projectParam) throws IOException { + String url = onlineAnnotateConfig.getUrl()+ "/projects/"+ projectParam.getId() + "/"; + String json = objectMapper.writeValueAsString(projectParam); + + RequestBody body = RequestBody.create(json, MediaType.parse("application/json")); + Request request = new Request.Builder() + .url(url) + .patch(body) + .addHeader("Authorization", onlineAnnotateConfig.getApikey()) + .build(); + + String response = executeRequest(request); + return ProjectParam.fromJson(response); + } + + /** + * task <------> 人工智能数据中心的具体的标注文件 + * task 增删改查 + */ + public TaskParam createTask(TaskParam taskParam) throws IOException { + String url = onlineAnnotateConfig.getUrl()+ "/tasks/"; + String json = objectMapper.writeValueAsString(taskParam); + + RequestBody body = RequestBody.create(json, MediaType.parse("application/json")); + + log.error("Request JSON: " + json); + Request request = new Request.Builder() + .url(url) + .post(body) + .addHeader("Authorization", onlineAnnotateConfig.getApikey()) + .build(); + + String response = executeRequest(request); + return TaskParam.fromJson(response); + } + + public TaskParam getTaskById(String id) throws IOException { + String url = onlineAnnotateConfig.getUrl()+ "/tasks/" + id + "/"; + Request request = new Request.Builder() + .url(url) + .get() + .addHeader("Authorization", onlineAnnotateConfig.getApikey()) + .build(); + + String response = executeRequest(request); + return TaskParam.fromJson(response); + } + + public boolean deleteTaskById(String id) throws IOException { + String url = onlineAnnotateConfig.getUrl()+ "/tasks/" + id + "/"; + Request request = new Request.Builder() + .url(url) + .delete() + .addHeader("Authorization", onlineAnnotateConfig.getApikey()) + .build(); + + String response = executeRequest(request); + return response != null && !response.isEmpty(); + } + + public TaskParam updateTask(TaskParam taskParam) throws IOException { + String url = onlineAnnotateConfig.getUrl()+ "/tasks/"+ taskParam.getId() + "/"; + + String json = objectMapper.writeValueAsString(taskParam); + RequestBody body = RequestBody.create(json, MediaType.parse("application/json")); + Request request = new Request.Builder() + .url(url) + .patch(body) + .addHeader("Authorization", onlineAnnotateConfig.getApikey()) + .build(); + + String response = executeRequest(request); + return TaskParam.fromJson(response); + } + // Execute the request + private String executeRequest(Request request) throws IOException { + try (Response response = client.newCall(request).execute()) { + if (!response.isSuccessful()) { + throw new IOException("Unexpected code " + response); + } + return response.body() != null ? response.body().string() : null; + } + } +} + + + diff --git a/bonus-modules/bonus-ai/src/main/java/com/bonus/ai/client/ParsedLabelConfig.java b/bonus-modules/bonus-ai/src/main/java/com/bonus/ai/client/ParsedLabelConfig.java new file mode 100644 index 0000000..6daec89 --- /dev/null +++ b/bonus-modules/bonus-ai/src/main/java/com/bonus/ai/client/ParsedLabelConfig.java @@ -0,0 +1,124 @@ +package com.bonus.ai.client; + +//public class ParsedLabelConfig { +//} + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.Data; + +import java.util.List; +import java.util.Map; + +@Data +public class ParsedLabelConfig { + + @JsonProperty("label") + private Label label; + + @Data + public static class Label { + @JsonProperty("type") + private String type; + + @JsonProperty("to_name") + private List toName; + + @JsonProperty("inputs") + private List inputs; + + @JsonProperty("labels") + private List labels; + + @JsonProperty("labels_attrs") + private Map labelsAttrs; + } + + @Data + public static class Input { + @JsonProperty("type") + private String type; + + @JsonProperty("value") + private String value; + + @JsonProperty("valueType") + private String valueType; // 注意:JSON 中为 `null`,在 Java 中用 `String` 表示 + } + + @Data + public static class LabelAttributes { + @JsonProperty("value") + private String value; + + @JsonProperty("background") + private String background; + } + + /** + * 将 JSON 字符串解析为实体类对象 + */ + public static ParsedLabelConfig fromJson(String json) throws JsonProcessingException { + ObjectMapper mapper = new ObjectMapper(); + return mapper.readValue(json, ParsedLabelConfig.class); + } + + /** + * 将实体类对象转换为 JSON 字符串 + */ + public String toJson() throws JsonProcessingException { + ObjectMapper mapper = new ObjectMapper(); + return mapper.writeValueAsString(this); + } + + public static void main(String[] args) throws JsonProcessingException { + String json = "{\n" + + " \"parsed_label_config\": {\n" + + " \"label\": {\n" + + " \"type\": \"RectangleLabels\",\n" + + " \"to_name\": [\"image\"],\n" + + " \"inputs\": [\n" + + " {\n" + + " \"type\": \"Image\",\n" + + " \"value\": \"image\",\n" + + " \"valueType\": null\n" + + " }\n" + + " ],\n" + + " \"labels\": [\"person\", \"cat\"],\n" + + " \"labels_attrs\": {\n" + + " \"person\": {\n" + + " \"value\": \"person\",\n" + + " \"background\": \"#FFA39E\"\n" + + " },\n" + + " \"cat\": {\n" + + " \"value\": \"cat\",\n" + + " \"background\": \"#D4380D\"\n" + + " }\n" + + " }\n" + + " }\n" + + " }\n" + + "}"; + + +// ParsedLabelConfig record = ParsedLabelConfig.fromJson(json); +// +// System.out.println(record); + // 提取 "parsed_label_config" 部分 + ObjectMapper mapper = new ObjectMapper(); + + String parsedLabelConfigJson = mapper.readTree(json).get("parsed_label_config").toString(); + + // JSON 转为实体类 + ParsedLabelConfig parsedLabelConfig = ParsedLabelConfig.fromJson(parsedLabelConfigJson); + System.out.println("实体类内容:"); + System.out.println(parsedLabelConfig); + + // 实体类转为 JSON + String jsonOutput = parsedLabelConfig.toJson(); + System.out.println("\n转换回 JSON:"); + System.out.println(jsonOutput); + } + +} + diff --git a/bonus-modules/bonus-ai/src/main/java/com/bonus/ai/client/ProjectInputParam.java b/bonus-modules/bonus-ai/src/main/java/com/bonus/ai/client/ProjectInputParam.java new file mode 100644 index 0000000..bba1633 --- /dev/null +++ b/bonus-modules/bonus-ai/src/main/java/com/bonus/ai/client/ProjectInputParam.java @@ -0,0 +1,34 @@ +package com.bonus.ai.client; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.Data; + +import java.util.List; +import java.util.Map; + +@Data +public class ProjectInputParam { + + private Long id; + private String title; + private String description; + @JsonProperty("label_config") + private String labelConfig; + @JsonProperty("expert_instruction") + private String expertInstruction = "labels"; + @JsonProperty("show_instruction") + private boolean showInstruction = true; + @JsonProperty("show_skip_button") + private boolean showSkipButton = true; + @JsonProperty("enable_empty_annotation") + private boolean enableEmptyAnnotation = true; + @JsonProperty("show_annotation_history") + private boolean showAnnotationHistory = true; + private int organization = 1; + private String color = "color"; + @JsonProperty("maximum_annotations") + private int maximumAnnotations = 1; +} + diff --git a/bonus-modules/bonus-ai/src/main/java/com/bonus/ai/client/ProjectParam.java b/bonus-modules/bonus-ai/src/main/java/com/bonus/ai/client/ProjectParam.java index 4a99286..7c987f8 100644 --- a/bonus-modules/bonus-ai/src/main/java/com/bonus/ai/client/ProjectParam.java +++ b/bonus-modules/bonus-ai/src/main/java/com/bonus/ai/client/ProjectParam.java @@ -1,6 +1,8 @@ package com.bonus.ai.client; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonRawValue; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import lombok.Data; @@ -11,25 +13,29 @@ import java.util.Map; @Data public class ProjectParam { - private int id; + private Long id = 0L; + @JsonProperty("title") private String title; + @JsonProperty("description") private String description; + @JsonProperty("label_config") + @JsonRawValue(true) private String labelConfig; @JsonProperty("expert_instruction") - private String expertInstruction; + private String expertInstruction = "labels"; @JsonProperty("show_instruction") - private boolean showInstruction; + private boolean showInstruction = true; @JsonProperty("show_skip_button") - private boolean showSkipButton; + private boolean showSkipButton = true; @JsonProperty("enable_empty_annotation") - private boolean enableEmptyAnnotation; + private boolean enableEmptyAnnotation = true; @JsonProperty("show_annotation_history") - private boolean showAnnotationHistory; - private int organization; - private String color; + private boolean showAnnotationHistory = true; + private int organization = 1; + private String color = "color"; @JsonProperty("maximum_annotations") - private int maximumAnnotations; + private int maximumAnnotations = 1; @JsonProperty("is_published") private boolean isPublished; @JsonProperty("model_version") @@ -95,13 +101,13 @@ public class ProjectParam { // Getters and Setters for all fields @Data public static class CreatedBy { - private int id; + private int id = 1; @JsonProperty("first_name") - private String firstName; + private String firstName = ""; @JsonProperty("last_name") - private String lastName; - private String email; - private String avatar; + private String lastName = ""; + private String email = "wang272160587@gmail.com"; + private String avatar = null; // Getters and Setters } @@ -117,91 +123,166 @@ public class ProjectParam { @Data public static class ParsedLabelConfig { - private Map label; - // Getters and Setters - } + @JsonProperty("label") + private com.bonus.ai.client.ParsedLabelConfig.Label label; - @Data - public static class LabelConfig { - private String type; - @JsonProperty("to_name") - private List toName; - private List inputs; - private List labels; - @JsonProperty("labels_attrs") - private Map labelsAttrs; + @Data + public static class Label { + @JsonProperty("type") + private String type; - // Getters and Setters - } + @JsonProperty("to_name") + private List toName; - @Data - public static class Input { - private String type; - private String value; - private String valueType; + @JsonProperty("inputs") + private List inputs; - // Getters and Setters - } + @JsonProperty("labels") + private List labels; - @Data - public static class LabelAttributes { - private String value; - private String background; + @JsonProperty("labels_attrs") + private Map labelsAttrs; + } + + @Data + public static class Input { + @JsonProperty("type") + private String type; + + @JsonProperty("value") + private String value; + + @JsonProperty("valueType") + private String valueType; // 注意:JSON 中为 `null`,在 Java 中用 `String` 表示 + } + + @Data + public static class LabelAttributes { + @JsonProperty("value") + private String value; + + @JsonProperty("background") + private String background; + } - // Getters and Setters } public static ProjectParam fromJson(String json) throws JsonProcessingException { - ObjectMapper mapper = new ObjectMapper(); - return mapper.readValue(json, ProjectParam.class); + return new ObjectMapper().readValue(json, ProjectParam.class); } - - public String toJson() throws JsonProcessingException { + public String toJson() throws Exception { ObjectMapper mapper = new ObjectMapper(); return mapper.writeValueAsString(this); } public static void main(String[] args) throws JsonProcessingException { - String json = "{\n" + - " \"data\": {\n" + - " \"image\": \"https://example.com/image.jpg\",\n" + - " \"text\": \"Hello, AI!\"\n" + - " },\n" + - " \"id\": 1,\n" + - " \"meta\": {\n" + - " \"key\": \"value\"\n" + - " },\n" + - " \"created_at\": \"2024-06-18T23:45:46Z\",\n" + - " \"updated_at\": \"2024-06-18T23:45:46Z\",\n" + - " \"is_labeled\": false,\n" + - " \"overlap\": 1,\n" + - " \"inner_id\": 1,\n" + - " \"total_annotations\": 0,\n" + - " \"cancelled_annotations\": 0,\n" + - " \"total_predictions\": 0,\n" + - " \"comment_count\": 0,\n" + - " \"unresolved_comment_count\": 0,\n" + - " \"last_comment_updated_at\": \"2024-01-15T09:30:00Z\",\n" + - " \"project\": 1,\n" + - " \"updated_by\": [\n" + - " {\n" + - " \"user_id\": 1\n" + - " }\n" + - " ],\n" + - " \"file_upload\": \"42d46c4c-my-pic.jpeg\",\n" + - " \"comment_authors\": [\n" + - " 1\n" + - " ]\n" + - "}"; - + String json = "{\"id\":16,\"title\":\"taskName\",\"description\":\"description\",\"label_config\":\"\\n \\n \\n \\n\",\"expert_instruction\":\"labels\",\"show_instruction\":true,\"show_skip_button\":true,\"enable_empty_annotation\":true,\"show_annotation_history\":true,\"organization\":1,\"color\":\"color\",\"maximum_annotations\":1,\"is_published\":false,\"model_version\":\"\",\"is_draft\":false,\"created_by\":{\"id\":1,\"first_name\":\"\",\"last_name\":\"\",\"email\":\"wang272160587@gmail.com\",\"avatar\":null},\"created_at\":\"2024-11-25T01:27:36.414342Z\",\"min_annotations_to_start_training\":0,\"start_training_on_annotation_update\":false,\"show_collab_predictions\":true,\"num_tasks_with_annotations\":null,\"task_number\":null,\"useful_annotation_number\":null,\"ground_truth_number\":null,\"skipped_annotations_number\":null,\"total_annotations_number\":null,\"total_predictions_number\":null,\"sampling\":\"Sequential sampling\",\"show_ground_truth_first\":false,\"show_overlap_first\":false,\"overlap_cohort_percentage\":100,\"task_data_login\":null,\"task_data_password\":null,\"control_weights\":{\"label\":{\"overall\":1.0,\"type\":\"RectangleLabels\",\"labels\":{\"person\":1.0,\"cat\":1.0}}},\"parsed_label_config\":{\"label\":{\"type\":\"RectangleLabels\",\"to_name\":[\"image\"],\"inputs\":[{\"type\":\"Image\",\"value\":\"image\",\"valueType\":null}],\"labels\":[\"person\",\"cat\"],\"labels_attrs\":{\"person\":{\"value\":\"person\",\"background\":\"#FFA39E\"},\"cat\":{\"value\":\"cat\",\"background\":\"#D4380D\"}}}},\"evaluate_predictions_automatically\":false,\"config_has_control_tags\":true,\"skip_queue\":\"REQUEUE_FOR_OTHERS\",\"reveal_preannotations_interactively\":false,\"pinned_at\":null,\"finished_task_number\":null,\"queue_total\":0,\"queue_done\":0}"; +// String json = "{\"id\":16,\"title\":\"taskName\",\"description\":\"description\",\"label_config\":\"\\n \\n \\n \\n\",\"expert_instruction\":\"labels\",\"show_instruction\":true,\"show_skip_button\":true,\"enable_empty_annotation\":true,\"show_annotation_history\":true,\"organization\":1,\"color\":\"color\",\"maximum_annotations\":1,\"is_published\":false}"; +// String json = "{\n" + +// " \"id\": 11,\n" + +// " \"title\": \"测试项目\",\n" + +// " \"description\": \"My Second project\",\n" + +// " \"label_config\": \"\\n \\n \\n \\n\",\n" + +// " \"expert_instruction\": \"Label all cats\",\n" + +// " \"show_instruction\": true,\n" + +// " \"show_skip_button\": true,\n" + +// " \"enable_empty_annotation\": true,\n" + +// " \"show_annotation_history\": true,\n" + +// " \"organization\": 1,\n" + +// " \"color\": \"color\",\n" + +// " \"maximum_annotations\": 1,\n" + +// " \"is_published\": false,\n" + +// " \"model_version\": \"\",\n" + +// " \"is_draft\": false,\n" + +// " \"created_by\": {\n" + +// " \"id\": 1,\n" + +// " \"first_name\": \"\",\n" + +// " \"last_name\": \"\",\n" + +// " \"email\": \"wang272160587@gmail.com\",\n" + +// " \"avatar\": null\n" + +// " },\n" + +// " \"created_at\": \"2024-11-25T00:36:17.622117Z\",\n" + +// " \"min_annotations_to_start_training\": 0,\n" + +// " \"start_training_on_annotation_update\": false,\n" + +// " \"show_collab_predictions\": true,\n" + +// " \"num_tasks_with_annotations\": null,\n" + +// " \"task_number\": null,\n" + +// " \"useful_annotation_number\": null,\n" + +// " \"ground_truth_number\": null,\n" + +// " \"skipped_annotations_number\": null,\n" + +// " \"total_annotations_number\": null,\n" + +// " \"total_predictions_number\": null,\n" + +// " \"sampling\": \"Sequential sampling\",\n" + +// " \"show_ground_truth_first\": false,\n" + +// " \"show_overlap_first\": false,\n" + +// " \"overlap_cohort_percentage\": 100,\n" + +// " \"task_data_login\": null,\n" + +// " \"task_data_password\": null,\n" + +// " \"control_weights\": {\n" + +// " \"label\": {\n" + +// " \"overall\": 1.0,\n" + +// " \"type\": \"RectangleLabels\",\n" + +// " \"labels\": {\n" + +// " \"person\": 1.0,\n" + +// " \"cat\": 1.0\n" + +// " }\n" + +// " }\n" + +// " },\n" + +// " \"parsed_label_config\": {\n" + +// " \"label\": {\n" + +// " \"type\": \"RectangleLabels\",\n" + +// " \"to_name\": [\n" + +// " \"image\"\n" + +// " ],\n" + +// " \"inputs\": [\n" + +// " {\n" + +// " \"type\": \"Image\",\n" + +// " \"value\": \"image\",\n" + +// " \"valueType\": null\n" + +// " }\n" + +// " ],\n" + +// " \"labels\": [\n" + +// " \"person\",\n" + +// " \"cat\"\n" + +// " ],\n" + +// " \"labels_attrs\": {\n" + +// " \"person\": {\n" + +// " \"value\": \"person\",\n" + +// " \"background\": \"#FFA39E\"\n" + +// " },\n" + +// " \"cat\": {\n" + +// " \"value\": \"cat\",\n" + +// " \"background\": \"#D4380D\"\n" + +// " }\n" + +// " }\n" + +// " }\n" + +// " },\n" + +// " \"evaluate_predictions_automatically\": false,\n" + +// " \"config_has_control_tags\": true,\n" + +// " \"skip_queue\": \"REQUEUE_FOR_OTHERS\",\n" + +// " \"reveal_preannotations_interactively\": true,\n" + +// " \"pinned_at\": null,\n" + +// " \"finished_task_number\": null,\n" + +// " \"queue_total\": 0,\n" + +// " \"queue_done\": 0\n" + +// "}"; System.out.println(json); - TaskParam record = TaskParam.fromJson(json); - System.out.println("Create At: " + record.getData()); + ProjectParam record = ProjectParam.fromJson(json); System.out.println("Create At: " + record.getCreatedAt()); - System.out.println("Image URL: " + record.getData().getImage()); } + +// public static void main(String[] args) throws Exception { +// String json = "{\"id\":16,\"title\":\"taskName\",\"description\":\"description\",\"label_config\":\"\\n \\n \\n \\n\",\"expert_instruction\":\"labels\",\"show_instruction\":true,\"show_skip_button\":true,\"enable_empty_annotation\":true,\"show_annotation_history\":true,\"organization\":1,\"color\":\"color\",\"maximum_annotations\":1,\"is_published\":false}"; +// +// ObjectMapper objectMapper = new ObjectMapper(); +// ProjectParam projectParam = objectMapper.readValue(json, ProjectParam.class); +// +// System.out.println(projectParam); +// } + + } diff --git a/bonus-modules/bonus-ai/src/main/java/com/bonus/ai/controller/dataset/AnnotationTaskController.java b/bonus-modules/bonus-ai/src/main/java/com/bonus/ai/controller/dataset/AnnotationTaskController.java index f0c22dc..5ac7880 100644 --- a/bonus-modules/bonus-ai/src/main/java/com/bonus/ai/controller/dataset/AnnotationTaskController.java +++ b/bonus-modules/bonus-ai/src/main/java/com/bonus/ai/controller/dataset/AnnotationTaskController.java @@ -1,5 +1,6 @@ package com.bonus.ai.controller.dataset; +import com.bonus.ai.client.AnnotationParam; import com.bonus.ai.domain.dataset.AnnotationSubTaskEntity; import com.bonus.ai.domain.dataset.AnnotationTaskEntity; import com.bonus.ai.service.DataSetBasicFileService; @@ -39,7 +40,8 @@ public class AnnotationTaskController extends BaseController { @PostMapping("/edit") public AjaxResult edit(@Validated @RequestBody AnnotationTaskEntity task) { - return AjaxResult.success(); + int status = annotationTaskService.updateTask(task); + return status == 1 ? AjaxResult.success() : AjaxResult.error("更新任务失败"); } /** @@ -72,7 +74,8 @@ public class AnnotationTaskController extends BaseController { */ @GetMapping(value = "/{taskId}") public AjaxResult getInfo(@PathVariable Long taskId) { - return AjaxResult.success(new AnnotationTaskEntity()); + AnnotationTaskEntity taskEntity = annotationTaskService.getTaskInfo(taskId); + return AjaxResult.success(taskEntity); } diff --git a/bonus-modules/bonus-ai/src/main/java/com/bonus/ai/domain/dataset/AnnotationTaskAnnotatorEntity.java b/bonus-modules/bonus-ai/src/main/java/com/bonus/ai/domain/dataset/AnnotationTaskAnnotatorEntity.java index 8f05907..35a745f 100644 --- a/bonus-modules/bonus-ai/src/main/java/com/bonus/ai/domain/dataset/AnnotationTaskAnnotatorEntity.java +++ b/bonus-modules/bonus-ai/src/main/java/com/bonus/ai/domain/dataset/AnnotationTaskAnnotatorEntity.java @@ -12,6 +12,8 @@ public class AnnotationTaskAnnotatorEntity { private Long reviewerId; // 审核人员 private Long taskId; // 任务ID private Long fileId; // 文件ID + private String fileUrl; // 文件URL + private Long labelStudioTaskId; //label studio 里对应的任务id private String description; // 描述 private String annotationStatus; // 标注状态 private String annotationResult; // 标注结果 (JSON串) diff --git a/bonus-modules/bonus-ai/src/main/java/com/bonus/ai/domain/dataset/AnnotationTaskEntity.java b/bonus-modules/bonus-ai/src/main/java/com/bonus/ai/domain/dataset/AnnotationTaskEntity.java index be9cb6b..62b7c9f 100644 --- a/bonus-modules/bonus-ai/src/main/java/com/bonus/ai/domain/dataset/AnnotationTaskEntity.java +++ b/bonus-modules/bonus-ai/src/main/java/com/bonus/ai/domain/dataset/AnnotationTaskEntity.java @@ -1,5 +1,6 @@ package com.bonus.ai.domain.dataset; +import com.bonus.ai.client.ProjectParam; import com.bonus.ai.domain.enums.AnnotationFileStatus; import com.bonus.ai.domain.enums.AnnotationTaskStatus; import com.bonus.common.core.web.domain.BaseEntity; @@ -32,10 +33,11 @@ public class AnnotationTaskEntity extends BaseEntity { /**标签集合,标签之间用逗号分隔*/ private String labels; - /**在线标注工具里关联的项目id*/ - Long projectId; + /**在线标注工具里关联的项目id 和label studio里 项目详情*/ + Long labelStudioProjectId; + ProjectParam projectParam; - AnnotationTaskStatus annotateTaskStatus; + private String annotateTaskStatus; /**删除标志(0代表存在 1代表删除) */ private String delFlag; diff --git a/bonus-modules/bonus-ai/src/main/java/com/bonus/ai/mapper/AnnotationTaskMapper.java b/bonus-modules/bonus-ai/src/main/java/com/bonus/ai/mapper/AnnotationTaskMapper.java index 181b014..4f5f2e0 100644 --- a/bonus-modules/bonus-ai/src/main/java/com/bonus/ai/mapper/AnnotationTaskMapper.java +++ b/bonus-modules/bonus-ai/src/main/java/com/bonus/ai/mapper/AnnotationTaskMapper.java @@ -54,5 +54,6 @@ public interface AnnotationTaskMapper int deleteAnnotator(Long taskId); - AnnotationTaskEntity selectAnnotationTaskListUUID(Long taskId); + //这个接口不需要,可以扩展selectAnnotationTaskList +// AnnotationTaskEntity selectAnnotationTaskListUUID(Long taskId); } diff --git a/bonus-modules/bonus-ai/src/main/java/com/bonus/ai/mapper/DatasetFileMapper.java b/bonus-modules/bonus-ai/src/main/java/com/bonus/ai/mapper/DatasetFileMapper.java index b0c1030..85adb74 100644 --- a/bonus-modules/bonus-ai/src/main/java/com/bonus/ai/mapper/DatasetFileMapper.java +++ b/bonus-modules/bonus-ai/src/main/java/com/bonus/ai/mapper/DatasetFileMapper.java @@ -1,5 +1,6 @@ package com.bonus.ai.mapper; +import com.bonus.ai.domain.DataSetBasicFileEntity; import com.bonus.ai.domain.dataset.DatasetFile; import org.apache.ibatis.annotations.Param; @@ -46,7 +47,7 @@ public interface DatasetFileMapper { * @param datasetId 数据集ID * @return 文件映射列表 */ - List selectFilesByDatasetId(Long datasetId); + List selectFilesByDatasetId(Long datasetId); /** * 更新是否已标注状态 diff --git a/bonus-modules/bonus-ai/src/main/java/com/bonus/ai/service/Impl/dataset/AnnotationTaskServiceImpl.java b/bonus-modules/bonus-ai/src/main/java/com/bonus/ai/service/Impl/dataset/AnnotationTaskServiceImpl.java index 55a42a6..c30f47c 100644 --- a/bonus-modules/bonus-ai/src/main/java/com/bonus/ai/service/Impl/dataset/AnnotationTaskServiceImpl.java +++ b/bonus-modules/bonus-ai/src/main/java/com/bonus/ai/service/Impl/dataset/AnnotationTaskServiceImpl.java @@ -1,28 +1,37 @@ package com.bonus.ai.service.Impl.dataset; import com.alibaba.fastjson.JSON; -import com.bonus.ai.client.OnlineAnnotationService; -import com.bonus.ai.client.ProjectParam; +import com.bonus.ai.client.*; import com.bonus.ai.config.OnlineAnnotateConfig; +import com.bonus.ai.domain.DataSetBasicFileEntity; import com.bonus.ai.domain.dataset.*; import com.bonus.ai.mapper.AnnotationTaskMapper; import com.bonus.ai.mapper.DatasetFileMapper; import com.bonus.ai.service.dataset.AnnotationTaskService; import com.bonus.ai.utils.AverageUtil; +import com.bonus.common.core.utils.SpringUtils; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import org.springframework.stereotype.Service; import javax.annotation.Resource; import java.util.List; import java.util.UUID; + +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; + @Slf4j @Service public class AnnotationTaskServiceImpl implements AnnotationTaskService { + private static final int THREAD_POOL_SIZE = 10; @Resource - OnlineAnnotationService onlineAnnotationService; + OnlineAnnotationServiceOkHttp onlineAnnotationService; +// OnlineAnnotationService onlineAnnotationService; @Resource private OnlineAnnotateConfig onlineAnnotateConfig; @@ -39,34 +48,66 @@ public class AnnotationTaskServiceImpl implements AnnotationTaskService { @Autowired private AnnotationTaskAnnotatorEntity annotationTaskAnnotatorEntity; + private final ThreadPoolTaskExecutor executorService = SpringUtils.getBean(ThreadPoolTaskExecutor.class); + + + public void callWithOkHttp() throws Exception { + OkHttpClient client = new OkHttpClient(); + Request request = new Request.Builder() + .url("http://127.0.0.1:8080/api/projects") + .addHeader("Authorization", "Token bb0859020874c95809212f7b9616d15bbdbb2422") + .build(); + + try (Response response = client.newCall(request).execute()) { + System.out.println(response.body().string()); + } + } /** * 创建标注任务 */ @Override - public int createTask(AnnotationTaskEntity task) { + public int createTask(AnnotationTaskEntity task){ int status =0; - // TODO 调用label studio 接口获取其project id - ProjectParam lSProject = new ProjectParam(); + //调用label studio 接口获取其project id + ProjectInputParam lSProject= new ProjectInputParam(); lSProject.setTitle(task.getTaskName()); lSProject.setDescription(task.getTaskDesc()); //需要将标签转换为json格式 - lSProject.setLabelConfig(task.getLabels()); - String project = onlineAnnotationService.createProject(lSProject, onlineAnnotateConfig.getApikey()); - List projectParams = JSON.parseArray(project, ProjectParam.class); - if (projectParams.size() > 0) { - Long projectId = Long.valueOf(projectParams.get(0).getId()); - task.setProjectId(projectId); - for(ProjectParam projectParam: projectParams){ - //需要生成32位uuid - String uuid = UUID.randomUUID().toString().replace("-", ""); - task.setTaskUuid(uuid); - status= annotationTaskMapper.insertAnnotationTask(task); + String labelConfig = OnlineAnnotateUtil.rectangleImageLabels(task.getLabels()); + lSProject.setLabelConfig(labelConfig); + String project = ""; + Long projectId = 0L; + try { + ProjectParam projectParams = onlineAnnotationService.createProject(lSProject); + if (projectParams != null) { + projectId = Long.valueOf(projectParams.getId()); + task.setLabelStudioProjectId(projectId); } + }catch (Exception e){ + e.printStackTrace(); } + + //需要生成32位uuid + String uuid = UUID.randomUUID().toString().replace("-", ""); + task.setTaskUuid(uuid); + status= annotationTaskMapper.insertAnnotationTask(task); //通过数据集id 从数据集和文件关联关系表获取文件信息 - List datafile = datasetFileMapper.selectFilesByDatasetId(task.getDatasetId()); - //TODO 根据标注任务file list 和标注人信息自动分配 + List datafile = datasetFileMapper.selectFilesByDatasetId(task.getDatasetId()); + //根据标注任务file list 和标注人信息自动分配 List annotationTaskAnnotatorEntities = AverageUtil.distributeFiles(datafile, task); +// for (AnnotationTaskAnnotatorEntity entity : annotationTaskAnnotatorEntities) { +// //TODO 每个文件都需要创建label studio的 task id 与之唯一对应 +// executorService.execute(()->{ +// TaskParam taskParam = new TaskParam(); +// taskParam.setProject(projectId); +// try { +// onlineAnnotationService.createTask(taskParam); +// }catch(Exception e){ +// e.printStackTrace(); +// } +// }); + //entity.setLabelStudioTaskId(0); +// } // 获取project id以后调用AnnotationTaskMapper 和AnnotationTaskAnnotatorMapper 插入数据集 if(status == 1){ status = annotationTaskMapper.insertAnnotTaskannotator(annotationTaskAnnotatorEntities); @@ -93,6 +134,30 @@ public class AnnotationTaskServiceImpl implements AnnotationTaskService { */ @Override public int updateTask(AnnotationTaskEntity task){ + + //将信息也同步更新到label studio studio 对应的project + AnnotationTaskEntity newTask = new AnnotationTaskEntity(); + newTask.setTaskId(task.getTaskId()); + //处理与label studio 相关的更新 + List resultTasks = annotationTaskMapper.selectAnnotationTaskList(newTask); + if (!resultTasks.isEmpty()) { + Long project = resultTasks.get(0).getLabelStudioProjectId(); + //调用label studio 接口获取其project id + ProjectInputParam lSProject= new ProjectInputParam(); + lSProject.setTitle(task.getTaskName()); + lSProject.setDescription(task.getTaskDesc()); + //需要将标签转换为json格式 + String labelConfig = OnlineAnnotateUtil.rectangleImageLabels(task.getLabels()); + lSProject.setLabelConfig(labelConfig); + lSProject.setId(project); + try { + ProjectParam projectParam = onlineAnnotationService.updateProject(lSProject); + }catch(Exception e){ + e.printStackTrace(); + } + + //删除对应的标注任务文件关联关系表信息 + } return 0; } @@ -105,16 +170,22 @@ public class AnnotationTaskServiceImpl implements AnnotationTaskService { @Override public int deleteTaskById(Long taskId) { //删除任务需要删除两个个表 对应两个个表删除状态修改成1 + AnnotationTaskEntity task = new AnnotationTaskEntity(); + task.setTaskId(taskId); int status = 0; try{ - //删除主表任务信息 - status = annotationTaskMapper.deleteTaskById(taskId); - //删除团队成员表信息 - status = annotationTaskMapper.deleteAnnotator(taskId); - //查询对应的uuid - AnnotationTaskEntity task = annotationTaskMapper.selectAnnotationTaskListUUID(taskId); - //删除对应的标注任务文件关联关系表信息 - onlineAnnotationService.deleteProjectById(task.getTaskUuid(), onlineAnnotateConfig.getApikey()); +// //删除主表任务信息 +// status = annotationTaskMapper.deleteTaskById(taskId); +// //删除团队成员表信息 +// status = annotationTaskMapper.deleteAnnotator(taskId); +// //查询对应的label studio project id , 删除这个标注任务对应的label studio project + List resultTask = annotationTaskMapper.selectAnnotationTaskList(task); + if (!resultTask.isEmpty()){ + Long project = resultTask.get(0).getLabelStudioProjectId(); + //删除对应的标注任务文件关联关系表信息 + onlineAnnotationService.deleteProjectById(String.valueOf(project)); + } + }catch (Exception e){ e.printStackTrace(); } @@ -129,6 +200,22 @@ public class AnnotationTaskServiceImpl implements AnnotationTaskService { @Override public AnnotationTaskEntity getTaskInfo(Long taskId) { + + AnnotationTaskEntity task = new AnnotationTaskEntity(); + task.setTaskId(taskId); + try { + //查询对应的label studio project id , 从label studio这个标注任务对应的label studio project + List resultTasks = annotationTaskMapper.selectAnnotationTaskList(task); + if (!resultTasks.isEmpty()) { + Long project = resultTasks.get(0).getLabelStudioProjectId(); + //删除对应的标注任务文件关联关系表信息 + ProjectParam projectParam = onlineAnnotationService.getProjectById(String.valueOf(project)); + AnnotationTaskEntity resultTask = resultTasks.get(0); + resultTask.setProjectParam(projectParam); + } + } catch (Exception e){ + e.printStackTrace(); + } return null; } diff --git a/bonus-modules/bonus-ai/src/main/java/com/bonus/ai/service/dataset/AnnotationTaskService.java b/bonus-modules/bonus-ai/src/main/java/com/bonus/ai/service/dataset/AnnotationTaskService.java index 3c76dc0..4c54f53 100644 --- a/bonus-modules/bonus-ai/src/main/java/com/bonus/ai/service/dataset/AnnotationTaskService.java +++ b/bonus-modules/bonus-ai/src/main/java/com/bonus/ai/service/dataset/AnnotationTaskService.java @@ -4,6 +4,8 @@ import com.bonus.ai.domain.dataset.AnnotationSubTaskEntity; import com.bonus.ai.domain.dataset.AnnotationTaskEntity; import com.bonus.ai.domain.dataset.DataSetEntity; +import java.io.IOException; + public interface AnnotationTaskService { /**创建标注任务*/ int createTask(AnnotationTaskEntity task); diff --git a/bonus-modules/bonus-ai/src/main/java/com/bonus/ai/utils/AverageUtil.java b/bonus-modules/bonus-ai/src/main/java/com/bonus/ai/utils/AverageUtil.java index 9970350..5e1b6d2 100644 --- a/bonus-modules/bonus-ai/src/main/java/com/bonus/ai/utils/AverageUtil.java +++ b/bonus-modules/bonus-ai/src/main/java/com/bonus/ai/utils/AverageUtil.java @@ -1,5 +1,6 @@ package com.bonus.ai.utils; +import com.bonus.ai.domain.DataSetBasicFileEntity; import com.bonus.ai.domain.dataset.AnnotationTaskAnnotatorEntity; import com.bonus.ai.domain.dataset.AnnotationTaskEntity; import com.bonus.ai.domain.dataset.DatasetFile; @@ -15,28 +16,33 @@ public class AverageUtil { * @param taskEntity 标注任务实体 * @return 分配结果,包含标注者和审核者的文件分配 */ - public static List distributeFiles(List files, AnnotationTaskEntity taskEntity) { + public static List distributeFiles(List files, AnnotationTaskEntity taskEntity) { List annotatorEntities = new ArrayList<>(); List annotators = taskEntity.getAnnotators(); // 获取标注者列表 List reviewers = taskEntity.getReviewers(); // 获取审核者列表 + //这里应该是根据标注者列表和审核人列表里的人 与文件相关进行平均分 // 平分文件给标注者 for (int i = 0; i < files.size(); i++) { Long annotatorId = annotators.get(i % annotators.size()); // 轮流分配给标注者 AnnotationTaskAnnotatorEntity entity = new AnnotationTaskAnnotatorEntity(); entity.setAnnotatorId(annotatorId); // 设置标注者 ID entity.setFileId(files.get(i).getFileId()); // 假设 DatasetFile 有 getId() 方法 + + //这里需要将基础文件的url也获取并赋值 + entity.setFileUrl(files.get(i).getFileUrl() ); annotatorEntities.add(entity); } // 平分文件给审核者 - for (int i = 0; i < files.size(); i++) { + for (int i = 0; i < annotatorEntities.size(); i++) { Long reviewerId = reviewers.get(i % reviewers.size()); // 轮流分配给审核者 - AnnotationTaskAnnotatorEntity entity = new AnnotationTaskAnnotatorEntity(); - entity.setAnnotatorId(reviewerId); // 设置审核者 ID - entity.setFileId(files.get(i).getFileId()); // 假设 DatasetFile 有 getId() 方法 - annotatorEntities.add(entity); + annotatorEntities.get(i).setReviewerId(reviewerId); +// AnnotationTaskAnnotatorEntity entity = new AnnotationTaskAnnotatorEntity(); +// entity.setAnnotatorId(reviewerId); // 设置审核者 ID +// entity.setFileId(files.get(i).getFileId()); // 假设 DatasetFile 有 getId() 方法 +// annotatorEntities.add(entity); } return annotatorEntities; diff --git a/bonus-modules/bonus-ai/src/main/resources/mapper/AnnotationTaskMapper.xml b/bonus-modules/bonus-ai/src/main/resources/mapper/AnnotationTaskMapper.xml index 33fc212..27002fc 100644 --- a/bonus-modules/bonus-ai/src/main/resources/mapper/AnnotationTaskMapper.xml +++ b/bonus-modules/bonus-ai/src/main/resources/mapper/AnnotationTaskMapper.xml @@ -14,7 +14,8 @@ - + + @@ -23,6 +24,7 @@ + select distinct t.task_id, t.task_uuid, t.task_name, t.description, t.annotation_scene, t.annotation_type, FROM ai_annotation_task t @@ -43,14 +45,17 @@ - - + SELECT task_id , dataset_id , task_name , task_uuid, description, annotation_scene, annotation_type , labels, is_annotation_team AS isStartTeam, annotation_status, - project_id, del_flag, create_by , create_time, + label_studio_project_id, del_flag, create_by , create_time, update_by , update_time FROM ai_annotation_task WHERE del_flag = '0' + + AND task_id = #{taskId} + AND dataset_id = #{datasetId} @@ -67,9 +72,9 @@ AND annotation_status = #{annotateTaskStatus} - + + + @@ -84,7 +89,7 @@ labels, is_annotation_team, annotation_status, - project_id, + label_studio_project_id, del_flag, create_by, create_time, @@ -101,7 +106,7 @@ #{labels}, #{isStartTeam}, #{annotateTaskStatus}, - #{projectId}, + #{labelStudioProjectId}, #{delFlag}, #{createBy}, sysdate(), @@ -113,6 +118,18 @@ INSERT INTO ai_annotation_task_annotator_map task_id + + , file_id + + + , file_url + + + , file_url + + + , label_studio_task_id + , annotator_id @@ -134,6 +151,15 @@ #{taskId} + + , #{fileId} + + + , #{fileUrl} + + + , #{labelStudioTaskId} + , #{annotatorId} @@ -169,7 +195,7 @@ labels = #{labels}, is_annotation_team = #{isStartTeam}, annotation_status = #{annotateTaskStatus}, - project_id = #{projectId}, + label_studio_project_id = #{labelStudioProjectId}, del_flag = #{delFlag}, update_by = #{updateBy}, update_time = sysdate(), diff --git a/bonus-modules/bonus-ai/src/main/resources/mapper/DatasetFileMapper.xml b/bonus-modules/bonus-ai/src/main/resources/mapper/DatasetFileMapper.xml index c496467..d46bffb 100644 --- a/bonus-modules/bonus-ai/src/main/resources/mapper/DatasetFileMapper.xml +++ b/bonus-modules/bonus-ai/src/main/resources/mapper/DatasetFileMapper.xml @@ -42,10 +42,11 @@ - + SELECT bf.file_id AS fileId, bf.file_url AS fileUrl + FROM ai_dataset_file_map df + WHERE df.dataset_id = #{datasetId} + left join ai_basic_file bf on bf.file_id = df.file_id diff --git a/sql/bonus_ai.sql b/sql/bonus_ai.sql index 6acb561..5539f6d 100644 --- a/sql/bonus_ai.sql +++ b/sql/bonus_ai.sql @@ -4,21 +4,22 @@ drop table if exists ai_annotation_task; create table ai_annotation_task ( - task_id bigint(20) not null auto_increment comment '任务id', - dataset_id bigint(20) not null comment '数据集id', - task_name varchar(64) comment '任务名称', - task_uuid varchar(64) comment '任务唯一标识id', - description varchar(500) default '' comment '描述', - annotation_scene char(1) comment '标注场景(对应数据集的数据类型)', - annotation_type char(2) comment '标注类型(不同数据类型有不同的标注类型,如图片:图像分类,物体检测等)', - labels varchar(200) comment '允许的标签集', + task_id bigint(20) not null auto_increment comment '任务id', + dataset_id bigint(20) not null comment '数据集id', + task_name varchar(64) comment '任务名称', + task_uuid varchar(64) comment '任务唯一标识id', + description varchar(500) default '' comment '描述', + annotation_scene char(1) comment '标注场景(对应数据集的数据类型)', + annotation_type char(2) comment '标注类型(不同数据类型有不同的标注类型,如图片:图像分类,物体检测等)', + labels varchar(200) comment '允许的标签集', is_annotation_team char(1) comment '标注团队id(0未启用,1启用团队)', - annotation_status char(1) default '0' comment '0未标注,1正在标注,2已标注,3正在审核,4已审核', - del_flag char(1) default '0' comment '是否删除(0代表存在,1代表删除)', - create_by varchar(64) default '' comment '创建者', - update_by varchar(64) default '' comment '更新者', - update_time datetime default null comment '更新时间', - create_time datetime default null comment '创建时间', + annotation_status char(1) default '0' comment '0未标注,1正在标注,2已标注,3正在审核,4已审核', + label_studio_project_id bigint(20) comment "label studio 对应的projectId" + del_flag char(1) default '0' comment '是否删除(0代表存在,1代表删除)', + create_by varchar(64) default '' comment '创建者', + update_by varchar(64) default '' comment '更新者', + update_time datetime default null comment '更新时间', + create_time datetime default null comment '创建时间', primary key (task_id) )engine=innodb comment = '标注任务'; @@ -32,6 +33,8 @@ create table ai_annotation_task_annotator_map reviewer_id bigint(20) not null comment '审核人员', task_id bigint(20) not null comment '任务id', file_id bigint(20) not null comment '文件id', + file_url varchar(200) default '' comment '文件网络路径', + label_studio_task_id bigint(20) comment "label studio 对应的taskId" description varchar(500) default '' comment '描述', annotation_status char(1) comment '0未标注,1正在标注,2已标注,3正在审核,4 审核驳回,5已审核', annotation_result text comment '标注结果(json串)',