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..64de405 --- /dev/null +++ b/bonus-modules/bonus-ai/src/main/java/com/bonus/ai/client/OnlineAnnotationServiceOkHttp.java @@ -0,0 +1,96 @@ +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; + + + // 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); + } + + // 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/AnnotationTaskEntity.java b/bonus-modules/bonus-ai/src/main/java/com/bonus/ai/domain/dataset/AnnotationTaskEntity.java index be9cb6b..503a375 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*/ + /**在线标注工具里关联的项目id 和label studio里 项目详情*/ Long projectId; + 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/service/Impl/dataset/AnnotationTaskServiceImpl.java b/bonus-modules/bonus-ai/src/main/java/com/bonus/ai/service/Impl/dataset/AnnotationTaskServiceImpl.java index 55a42a6..ce33548 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,7 +1,9 @@ package com.bonus.ai.service.Impl.dataset; import com.alibaba.fastjson.JSON; -import com.bonus.ai.client.OnlineAnnotationService; +import com.bonus.ai.client.OnlineAnnotateUtil; +import com.bonus.ai.client.OnlineAnnotationServiceOkHttp; +import com.bonus.ai.client.ProjectInputParam; import com.bonus.ai.client.ProjectParam; import com.bonus.ai.config.OnlineAnnotateConfig; import com.bonus.ai.domain.dataset.*; @@ -13,8 +15,12 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import javax.annotation.Resource; +import java.io.IOException; import java.util.List; import java.util.UUID; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; @Slf4j @Service @@ -22,7 +28,8 @@ public class AnnotationTaskServiceImpl implements AnnotationTaskService { @Resource - OnlineAnnotationService onlineAnnotationService; + OnlineAnnotationServiceOkHttp onlineAnnotationService; +// OnlineAnnotationService onlineAnnotationService; @Resource private OnlineAnnotateConfig onlineAnnotateConfig; @@ -39,33 +46,49 @@ public class AnnotationTaskServiceImpl implements AnnotationTaskService { @Autowired private AnnotationTaskAnnotatorEntity annotationTaskAnnotatorEntity; + + 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 = ""; + try { + ProjectParam projectParams = onlineAnnotationService.createProject(lSProject); + if (projectParams != null) { + Long projectId = Long.valueOf(projectParams.getId()); + task.setProjectId(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 和标注人信息自动分配 + //根据标注任务file list 和标注人信息自动分配 List annotationTaskAnnotatorEntities = AverageUtil.distributeFiles(datafile, task); // 获取project id以后调用AnnotationTaskMapper 和AnnotationTaskAnnotatorMapper 插入数据集 if(status == 1){ @@ -93,6 +116,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).getProjectId(); + //调用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 +152,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).getProjectId(); + //删除对应的标注任务文件关联关系表信息 + onlineAnnotationService.deleteProjectById(String.valueOf(project)); + } + }catch (Exception e){ e.printStackTrace(); } @@ -129,6 +182,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).getProjectId(); + //删除对应的标注任务文件关联关系表信息 + 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/resources/mapper/AnnotationTaskMapper.xml b/bonus-modules/bonus-ai/src/main/resources/mapper/AnnotationTaskMapper.xml index 33fc212..a963b53 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, 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} - + + +