Merge remote-tracking branch 'origin/main'
This commit is contained in:
commit
14ae1e1fb3
|
|
@ -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);
|
||||
// }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 "";
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -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);
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
@ -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);
|
||||
// }
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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串)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -54,5 +54,6 @@ public interface AnnotationTaskMapper
|
|||
|
||||
int deleteAnnotator(Long taskId);
|
||||
|
||||
AnnotationTaskEntity selectAnnotationTaskListUUID(Long taskId);
|
||||
//这个接口不需要,可以扩展selectAnnotationTaskList
|
||||
// AnnotationTaskEntity selectAnnotationTaskListUUID(Long taskId);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<DatasetFile> selectFilesByDatasetId(Long datasetId);
|
||||
List<DataSetBasicFileEntity> selectFilesByDatasetId(Long datasetId);
|
||||
|
||||
/**
|
||||
* 更新是否已标注状态
|
||||
|
|
|
|||
|
|
@ -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<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 = "";
|
||||
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<DatasetFile> datafile = datasetFileMapper.selectFilesByDatasetId(task.getDatasetId());
|
||||
//TODO 根据标注任务file list 和标注人信息自动分配
|
||||
List<DataSetBasicFileEntity> datafile = datasetFileMapper.selectFilesByDatasetId(task.getDatasetId());
|
||||
//根据标注任务file list 和标注人信息自动分配
|
||||
List<AnnotationTaskAnnotatorEntity> 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<AnnotationTaskEntity> 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<AnnotationTaskEntity> 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<AnnotationTaskEntity> 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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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<AnnotationTaskAnnotatorEntity> distributeFiles(List<DatasetFile> files, AnnotationTaskEntity taskEntity) {
|
||||
public static List<AnnotationTaskAnnotatorEntity> distributeFiles(List<DataSetBasicFileEntity> files, AnnotationTaskEntity taskEntity) {
|
||||
List<AnnotationTaskAnnotatorEntity> annotatorEntities = new ArrayList<>();
|
||||
|
||||
List<Long> annotators = taskEntity.getAnnotators(); // 获取标注者列表
|
||||
List<Long> 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;
|
||||
|
|
|
|||
|
|
@ -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="label_studio_project_id" property="labelStudioProjectId" 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,
|
||||
label_studio_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 label_studio_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">
|
||||
|
|
@ -84,7 +89,7 @@
|
|||
<if test="labels != null">labels,</if>
|
||||
<if test="isStartTeam != null">is_annotation_team,</if>
|
||||
<if test="annotateTaskStatus != null">annotation_status,</if>
|
||||
<if test="projectId != null">project_id,</if>
|
||||
<if test="labelStudioProjectId != null">label_studio_project_id,</if>
|
||||
<if test="delFlag != null">del_flag,</if>
|
||||
<if test="createBy != null">create_by,</if>
|
||||
create_time,
|
||||
|
|
@ -101,7 +106,7 @@
|
|||
<if test="labels != null">#{labels},</if>
|
||||
<if test="isStartTeam != null">#{isStartTeam},</if>
|
||||
<if test="annotateTaskStatus != null">#{annotateTaskStatus},</if>
|
||||
<if test="projectId != null">#{projectId},</if>
|
||||
<if test="labelStudioProjectId != null">#{labelStudioProjectId},</if>
|
||||
<if test="delFlag != null">#{delFlag},</if>
|
||||
<if test="createBy != null">#{createBy},</if>
|
||||
sysdate(),
|
||||
|
|
@ -113,6 +118,18 @@
|
|||
INSERT INTO ai_annotation_task_annotator_map
|
||||
<trim prefix="(" suffix=")" suffixOverrides=",">
|
||||
task_id
|
||||
<if test="fileId != null">
|
||||
, file_id
|
||||
</if>
|
||||
<if test="fileUrl != null">
|
||||
, file_url
|
||||
</if>
|
||||
<if test="fileUrl != null">
|
||||
, file_url
|
||||
</if>
|
||||
<if test="labelStudioTaskId != null">
|
||||
, label_studio_task_id
|
||||
</if>
|
||||
<if test="annotatorId != null">
|
||||
, annotator_id
|
||||
</if>
|
||||
|
|
@ -134,6 +151,15 @@
|
|||
</trim>
|
||||
<trim prefix="VALUES (" suffix=")" suffixOverrides=",">
|
||||
#{taskId}
|
||||
<if test="fileId != null">
|
||||
, #{fileId}
|
||||
</if>
|
||||
<if test="fileUrl != null">
|
||||
, #{fileUrl}
|
||||
</if>
|
||||
<if test="labelStudioTaskId != null">
|
||||
, #{labelStudioTaskId}
|
||||
</if>
|
||||
<if test="annotatorId != null">
|
||||
, #{annotatorId}
|
||||
</if>
|
||||
|
|
@ -169,7 +195,7 @@
|
|||
<if test="labels != null">labels = #{labels},</if>
|
||||
<if test="isStartTeam != null">is_annotation_team = #{isStartTeam},</if>
|
||||
<if test="annotateTaskStatus != null">annotation_status = #{annotateTaskStatus},</if>
|
||||
<if test="projectId != null">project_id = #{projectId},</if>
|
||||
<if test="labelStudioProjectId != null">label_studio_project_id = #{labelStudioProjectId},</if>
|
||||
<if test="delFlag != null">del_flag = #{delFlag},</if>
|
||||
<if test="updateBy != null">update_by = #{updateBy},</if>
|
||||
update_time = sysdate(),
|
||||
|
|
|
|||
|
|
@ -42,10 +42,11 @@
|
|||
<!-- </delete>-->
|
||||
|
||||
<!-- 根据数据集ID查询文件列表 -->
|
||||
<select id="selectFilesByDatasetId" resultType="com.bonus.ai.domain.dataset.DatasetFile">
|
||||
SELECT file_id AS fileId, dataset_id AS datasetId
|
||||
FROM ai_dataset_file_map
|
||||
WHERE dataset_id = #{datasetId}
|
||||
<select id="selectFilesByDatasetId" parameterType="Long" resultType="com.bonus.ai.domain.DataSetBasicFileEntity">
|
||||
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
|
||||
</select>
|
||||
|
||||
<!-- 更新是否已标注状态 -->
|
||||
|
|
|
|||
|
|
@ -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串)',
|
||||
|
|
|
|||
Loading…
Reference in New Issue