增加在线标注util类

This commit is contained in:
weiweiw 2024-11-25 15:08:17 +08:00
parent a9d0a0d4b8
commit d84c7689f4
13 changed files with 547 additions and 281 deletions

View File

@ -6,13 +6,17 @@ import java.util.stream.Collectors;
import java.util.stream.Stream;
public class OnlineAnnotateUtil {
final static String template = "<View><RectangleLabels name=\"label\" toName=\"image\">.*?</RectangleLabels></View>";
final static String template = "<View><Image name=\"image\" value=\"$image\"/><RectangleLabels name=\"label\" toName=\"image\">.*?</RectangleLabels></View>";
/**
* 替换 View 中的 Label 标签内容
* @param labels 要替换的 labels 列表
* @return 替换后的字符串
*/
public static String rectangleImageLabels(List<String> labels) {
public static String rectangleImageLabels(String labelsStr) {
if ( labelsStr.isEmpty()) {
return "";
}
// 使用 split 分割字符串并转换为 List
List<String> labels = Arrays.asList(labelsStr.split(","));
if (labels == null || labels.isEmpty()){
return "";
}
@ -48,11 +52,11 @@ public class OnlineAnnotateUtil {
* </RectangleLabels>
* </View>
*/
public static void main(String[] args) {
// List<String> labels = Arrays.asList("label1", "label2", "label3");
List<String> labels = Stream.of("label1", "label2", "label3")
.collect(Collectors.toList());
String result = rectangleImageLabels(labels);
System.out.println(result);
}
// public static void main(String[] args) {
//// List<String> labels = Arrays.asList("label1", "label2", "label3");
// List<String> labels = Stream.of("label1", "label2", "label3")
// .collect(Collectors.toList());
// String result = rectangleImageLabels(labels);
// System.out.println(result);
// }
}

View File

@ -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<OnlineAnnotationService> {
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 "";
}
};
}
}

View File

@ -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);
}

View File

@ -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;
}
}
}

View File

@ -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<String> toName;
@JsonProperty("inputs")
private List<Input> inputs;
@JsonProperty("labels")
private List<String> labels;
@JsonProperty("labels_attrs")
private Map<String, LabelAttributes> 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);
}
}

View File

@ -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;
}

View File

@ -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<String, LabelConfig> 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<String> toName;
private List<Input> inputs;
private List<String> labels;
@JsonProperty("labels_attrs")
private Map<String, LabelAttributes> labelsAttrs;
@Data
public static class Label {
@JsonProperty("type")
private String type;
// Getters and Setters
}
@JsonProperty("to_name")
private List<String> toName;
@Data
public static class Input {
private String type;
private String value;
private String valueType;
@JsonProperty("inputs")
private List<com.bonus.ai.client.ParsedLabelConfig.Input> inputs;
// Getters and Setters
}
@JsonProperty("labels")
private List<String> labels;
@Data
public static class LabelAttributes {
private String value;
private String background;
@JsonProperty("labels_attrs")
private Map<String, com.bonus.ai.client.ParsedLabelConfig.LabelAttributes> 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\":\"<View>\\n <Image name=\\\"image\\\" value=\\\"$image\\\"/>\\n <RectangleLabels name=\\\"label\\\" toName=\\\"image\\\">\\n <Label value=\\\"person\\\" background=\\\"#FFA39E\\\"/>\\n <Label value=\\\"cat\\\" background=\\\"#D4380D\\\"/>\\n </RectangleLabels>\\n</View>\",\"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\":\"<View>\\n <Image name=\\\"image\\\" value=\\\"$image\\\"/>\\n <RectangleLabels name=\\\"label\\\" toName=\\\"image\\\">\\n <Label value=\\\"person\\\" background=\\\"#FFA39E\\\"/>\\n <Label value=\\\"cat\\\" background=\\\"#D4380D\\\"/>\\n </RectangleLabels>\\n</View>\",\"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\": \"<View>\\n <Image name=\\\"image\\\" value=\\\"$image\\\"/>\\n <RectangleLabels name=\\\"label\\\" toName=\\\"image\\\">\\n <Label value=\\\"person\\\" background=\\\"#FFA39E\\\"/>\\n <Label value=\\\"cat\\\" background=\\\"#D4380D\\\"/>\\n </RectangleLabels>\\n</View>\",\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\":\"<View>\\n <Image name=\\\"image\\\" value=\\\"$image\\\"/>\\n <RectangleLabels name=\\\"label\\\" toName=\\\"image\\\">\\n <Label value=\\\"person\\\" background=\\\"#FFA39E\\\"/>\\n <Label value=\\\"cat\\\" background=\\\"#D4380D\\\"/>\\n </RectangleLabels>\\n</View>\",\"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);
// }
}

View File

@ -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);
}

View File

@ -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;

View File

@ -54,5 +54,6 @@ public interface AnnotationTaskMapper
int deleteAnnotator(Long taskId);
AnnotationTaskEntity selectAnnotationTaskListUUID(Long taskId);
//这个接口不需要可以扩展selectAnnotationTaskList
// AnnotationTaskEntity selectAnnotationTaskListUUID(Long taskId);
}

View File

@ -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<ProjectParam> 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<DatasetFile> datafile = datasetFileMapper.selectFilesByDatasetId(task.getDatasetId());
//TODO 根据标注任务file list 和标注人信息自动分配
//根据标注任务file list 和标注人信息自动分配
List<AnnotationTaskAnnotatorEntity> 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<AnnotationTaskEntity> 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<AnnotationTaskEntity> 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<AnnotationTaskEntity> 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;
}

View File

@ -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);

View File

@ -14,7 +14,8 @@
<result column="annotation_scene" property="annotateScene" jdbcType="CHAR"/>
<result column="annotation_type" property="annotateType" jdbcType="CHAR"/>
<result column="labels" property="labels" jdbcType="VARCHAR"/>
<result column="is_annotation_team" property="isStartTeam" jdbcType="CHAR"/>
<result column="project_id" property="projectId" jdbcType="BIGINT"/>
<result column="isStartTeam" property="isStartTeam" jdbcType="CHAR"/>
<result column="annotation_status" property="annotateTaskStatus" jdbcType="CHAR"/>
<result column="del_flag" property="delFlag" jdbcType="CHAR"/>
<result column="create_by" property="createBy" jdbcType="VARCHAR"/>
@ -23,6 +24,7 @@
<result column="create_time" property="createTime" jdbcType="TIMESTAMP"/>
</resultMap>
<sql id="selectTaskDetailVo">
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 @@
<!-- TODO 根据审核人id查询所有需要审核文件列表-->
<!-- 查询标注任务列表 -->
<select id="selectAnnotationTaskList" parameterType="com.bonus.ai.domain.dataset.AnnotationTaskEntity" resultType="com.bonus.ai.domain.dataset.AnnotationTaskEntity">
SELECT task_id , dataset_id , task_name , task_uuidd, description, annotation_scene, annotation_type ,
<!-- 根据条件查询标注任务列表 -->
<select id="selectAnnotationTaskList" parameterType="com.bonus.ai.domain.dataset.AnnotationTaskEntity" resultMap="BaseResultMap">
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'
<if test="taskId != null">
AND task_id = #{taskId}
</if>
<if test="datasetId != null">
AND dataset_id = #{datasetId}
</if>
@ -67,9 +72,9 @@
AND annotation_status = #{annotateTaskStatus}
</if>
</select>
<select id="selectAnnotationTaskListUUID" resultType="com.bonus.ai.domain.dataset.AnnotationTaskEntity">
SELECT task_uuid FROM ai_annotation_task where del_flag = 0
</select>
<!-- <select id="selectAnnotationTaskListUUID" resultType="com.bonus.ai.domain.dataset.AnnotationTaskEntity">-->
<!-- SELECT project_id, task_id, task_uuid FROM ai_annotation_task where del_flag = 0-->
<!-- </select>-->
<!-- 插入标注任务 -->
<insert id="insertAnnotationTask" parameterType="com.bonus.ai.domain.dataset.AnnotationTaskEntity">