diff --git a/bonus-modules/bonus-ai/src/main/java/com/bonus/ai/client/TaskParam.java b/bonus-modules/bonus-ai/src/main/java/com/bonus/ai/client/TaskParam.java index 3aee9e7..79e707e 100644 --- a/bonus-modules/bonus-ai/src/main/java/com/bonus/ai/client/TaskParam.java +++ b/bonus-modules/bonus-ai/src/main/java/com/bonus/ai/client/TaskParam.java @@ -15,7 +15,7 @@ import java.util.Map; public class TaskParam { private Data data; - private int id; + private Long id; private Map meta; @JsonProperty("created_at") private String createdAt; @@ -40,7 +40,7 @@ public class TaskParam { private int unresolvedCommentCount; @JsonProperty("last_comment_updated_at") private String lastCommentUpdatedAt; - private int project; + private Long project; @JsonProperty("updated_by") private List updatedBy; @JsonProperty("file_upload") 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 4f5f2e0..56376be 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 @@ -48,7 +48,7 @@ public interface AnnotationTaskMapper */ List selectAnnotationTaskList(AnnotationTaskEntity annotationTask); - int insertAnnotTaskannotator(List annotationTaskAnnotatorEntities); + int insertAnnotTaskannotator(AnnotationTaskAnnotatorEntity annotationTaskAnnotatorEntities); int deleteTaskById(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 c30f47c..c8172ad 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 @@ -2,6 +2,7 @@ package com.bonus.ai.service.Impl.dataset; import com.alibaba.fastjson.JSON; import com.bonus.ai.client.*; +import com.bonus.ai.config.MinioConfig; import com.bonus.ai.config.OnlineAnnotateConfig; import com.bonus.ai.domain.DataSetBasicFileEntity; import com.bonus.ai.domain.dataset.*; @@ -17,6 +18,7 @@ import org.springframework.stereotype.Service; import javax.annotation.Resource; import java.util.List; import java.util.UUID; +import java.util.concurrent.CountDownLatch; import okhttp3.OkHttpClient; @@ -42,40 +44,25 @@ public class AnnotationTaskServiceImpl implements AnnotationTaskService { @Resource private DatasetFileMapper datasetFileMapper; - @Autowired - private AnnotationTaskEntity annotationTaskEntity; - - @Autowired - private AnnotationTaskAnnotatorEntity annotationTaskAnnotatorEntity; + @Resource + private MinioConfig minioConfig; 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){ + int status =0; - //调用label studio 接口获取其project id + //1.调用label studio 接口创建project,将projectid 关联到标注任务里 ProjectInputParam lSProject= new ProjectInputParam(); lSProject.setTitle(task.getTaskName()); lSProject.setDescription(task.getTaskDesc()); //需要将标签转换为json格式 String labelConfig = OnlineAnnotateUtil.rectangleImageLabels(task.getLabels()); lSProject.setLabelConfig(labelConfig); - String project = ""; Long projectId = 0L; try { ProjectParam projectParams = onlineAnnotationService.createProject(lSProject); @@ -85,32 +72,83 @@ public class AnnotationTaskServiceImpl implements AnnotationTaskService { } }catch (Exception e){ e.printStackTrace(); + return 0; } - //需要生成32位uuid + //2.插入标注任务表 String uuid = UUID.randomUUID().toString().replace("-", ""); task.setTaskUuid(uuid); status= annotationTaskMapper.insertAnnotationTask(task); + + AnnotationTaskEntity tempTask = new AnnotationTaskEntity(); + tempTask.setTaskUuid(uuid); + List tempTasks = annotationTaskMapper.selectAnnotationTaskList(task); + Long annotationTaskid; + if (!tempTasks.isEmpty()){ + annotationTaskid = tempTasks.get(0).getTaskId(); + } else { + annotationTaskid = 0L; + } + + //3. 根据标注任务创建标注人等信息,对任务里的文件进行分配 //通过数据集id 从数据集和文件关联关系表获取文件信息 List datafile = datasetFileMapper.selectFilesByDatasetId(task.getDatasetId()); //根据标注任务file list 和标注人信息自动分配 List annotationTaskAnnotatorEntities = AverageUtil.distributeFiles(datafile, task); -// for (AnnotationTaskAnnotatorEntity entity : annotationTaskAnnotatorEntities) { -// //TODO 每个文件都需要创建label studio的 task id 与之唯一对应 -// executorService.execute(()->{ -// TaskParam taskParam = new TaskParam(); -// taskParam.setProject(projectId); -// try { -// onlineAnnotationService.createTask(taskParam); -// }catch(Exception e){ -// e.printStackTrace(); -// } -// }); - //entity.setLabelStudioTaskId(0); -// } - // 获取project id以后调用AnnotationTaskMapper 和AnnotationTaskAnnotatorMapper 插入数据集 + + for (AnnotationTaskAnnotatorEntity entity : annotationTaskAnnotatorEntities) { + //每个文件都需要创建label studio的 task id 与之唯一对应 + entity.setTaskId(annotationTaskid); + } + // 使用 CountDownLatch 来确保所有任务完成后才执行下一步操作 + CountDownLatch latch = new CountDownLatch(annotationTaskAnnotatorEntities.size()); + + //4. 文件分配后需要调用label studio 接口创建task,将taskid与 文件和标注人表进行关联(因为文件较多启用异步调用) + for (AnnotationTaskAnnotatorEntity entity : annotationTaskAnnotatorEntities) { + //每个文件都需要创建label studio的 task id 与之唯一对应 + entity.setTaskId(annotationTaskid); + Long finalProjectId = projectId; + executorService.execute(()->{ + TaskParam taskParam = new TaskParam(); + TaskParam.Data data = new TaskParam.Data(); + String imageUrl = minioConfig.getEndpoint() + "/" + minioConfig.getBucketName() + "/"+ entity.getFileUrl(); + data.setImage(imageUrl); + data.setText("Hello, world!"); + taskParam.setData(data); + taskParam.setProject(finalProjectId); + try { + + TaskParam lStask = onlineAnnotationService.createTask(taskParam); + synchronized (entity) { + entity.setLabelStudioTaskId(lStask.getId()); + } + }catch(Exception e){ + e.printStackTrace(); + } + finally { + latch.countDown(); // 每个任务完成后减少计数 + } + }); + } + + // 等待所有线程完成 + try { + latch.await(); // 主线程会等待所有子线程完成 + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + e.printStackTrace(); + } + + // 5. 将文件和标注人等信息 插入文件和标注人关联表 if(status == 1){ - status = annotationTaskMapper.insertAnnotTaskannotator(annotationTaskAnnotatorEntities); + try { + for(AnnotationTaskAnnotatorEntity entity:annotationTaskAnnotatorEntities){ + status = annotationTaskMapper.insertAnnotTaskannotator(entity); + } + }catch (Exception e){ + log.error("Error updating task: ", e); + throw e; // 抛出异常以触发回滚 + } } return status; } @@ -135,7 +173,12 @@ public class AnnotationTaskServiceImpl implements AnnotationTaskService { @Override public int updateTask(AnnotationTaskEntity task){ - //将信息也同步更新到label studio studio 对应的project + int result = annotationTaskMapper.updateAnnotationTaskById(task); + if (result != 1){ + return 0; + } + + //防止labels信息发生变化,信息也同步更新到label studio studio 对应的project AnnotationTaskEntity newTask = new AnnotationTaskEntity(); newTask.setTaskId(task.getTaskId()); //处理与label studio 相关的更新 diff --git a/bonus-modules/bonus-ai/src/main/java/com/bonus/ai/utils/AverageUtil.java b/bonus-modules/bonus-ai/src/main/java/com/bonus/ai/utils/AverageUtil.java index 5e1b6d2..5214562 100644 --- a/bonus-modules/bonus-ai/src/main/java/com/bonus/ai/utils/AverageUtil.java +++ b/bonus-modules/bonus-ai/src/main/java/com/bonus/ai/utils/AverageUtil.java @@ -4,6 +4,7 @@ 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; +import com.bonus.common.security.utils.SecurityUtils; import java.util.ArrayList; import java.util.List; @@ -22,6 +23,33 @@ public class AverageUtil { List annotators = taskEntity.getAnnotators(); // 获取标注者列表 List reviewers = taskEntity.getReviewers(); // 获取审核者列表 + //标注者与审核者都为空时,默认为当前用户 + if(("1").equals(taskEntity.getIsStartTeam())){ + if (annotators == null || annotators.size() == 0 ) { + annotators = new ArrayList<>(); + Long userId = SecurityUtils.getUserId(); + annotators.add(userId); + } + if (reviewers == null || reviewers.size() == 0) { + reviewers = new ArrayList<>(); + Long userId = SecurityUtils.getUserId(); + reviewers.add(userId); + + } + }else{ + if (annotators == null || annotators.size() == 0) { + annotators = new ArrayList<>(); + Long userId = SecurityUtils.getUserId(); + annotators.add(userId); + } + if (reviewers == null || reviewers.size() == 0) { + reviewers = new ArrayList<>(); + Long userId = SecurityUtils.getUserId(); + reviewers.add(userId); + + } + } + //这里应该是根据标注者列表和审核人列表里的人 与文件相关进行平均分 // 平分文件给标注者 for (int i = 0; i < files.size(); i++) { @@ -39,10 +67,6 @@ public class AverageUtil { for (int i = 0; i < annotatorEntities.size(); i++) { Long reviewerId = reviewers.get(i % reviewers.size()); // 轮流分配给审核者 annotatorEntities.get(i).setReviewerId(reviewerId); -// AnnotationTaskAnnotatorEntity entity = new AnnotationTaskAnnotatorEntity(); -// entity.setAnnotatorId(reviewerId); // 设置审核者 ID -// entity.setFileId(files.get(i).getFileId()); // 假设 DatasetFile 有 getId() 方法 -// annotatorEntities.add(entity); } return annotatorEntities; diff --git a/bonus-modules/bonus-ai/src/main/resources/mapper/AnnotationTaskMapper.xml b/bonus-modules/bonus-ai/src/main/resources/mapper/AnnotationTaskMapper.xml index 27002fc..8f8f54b 100644 --- a/bonus-modules/bonus-ai/src/main/resources/mapper/AnnotationTaskMapper.xml +++ b/bonus-modules/bonus-ai/src/main/resources/mapper/AnnotationTaskMapper.xml @@ -77,7 +77,7 @@ - + INSERT INTO ai_annotation_task dataset_id, @@ -114,73 +114,141 @@ #{updateTime}, - + INSERT INTO ai_annotation_task_annotator_map - task_id + + task_id , + - , file_id + file_id , - , file_url - - - , file_url + file_url , - , label_studio_task_id + label_studio_task_id, - , annotator_id + annotator_id , - , reviewer_id + reviewer_id , - , description + description , - , annotation_status + annotation_status , - , annotation_result + annotation_result , - , annotation_resource + annotation_resource , - - #{taskId} + VALUES + + + + #{taskId}, + - , #{fileId} + #{fileId}, - , #{fileUrl} + #{fileUrl}, - , #{labelStudioTaskId} + #{labelStudioTaskId}, - , #{annotatorId} + #{annotatorId}, - , #{reviewerId} + #{reviewerId}, - - , #{description} + + #{description} , - , #{annotationStatus} + #{annotationStatus}, - , #{annotationResult} + #{annotationResult}, - , #{annotationResource} + #{annotationResource}, + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/bonus-modules/bonus-ai/src/main/resources/mapper/DatasetFileMapper.xml b/bonus-modules/bonus-ai/src/main/resources/mapper/DatasetFileMapper.xml index 991b99d..4327576 100644 --- a/bonus-modules/bonus-ai/src/main/resources/mapper/DatasetFileMapper.xml +++ b/bonus-modules/bonus-ai/src/main/resources/mapper/DatasetFileMapper.xml @@ -46,8 +46,8 @@ diff --git a/sql/bonus_ai.sql b/sql/bonus_ai.sql index 5539f6d..1bca766 100644 --- a/sql/bonus_ai.sql +++ b/sql/bonus_ai.sql @@ -106,6 +106,8 @@ create table ai_dataset data_source char(1) comment '数据来源(0:local,1:obs)', input_path varchar(200) comment '输入路径', output_path varchar(200) comment '输入路径', + input_id bigint(20) comment '输入文件夹id', + output_id bigint(20) comment '输出文件夹id' annotation_status char(1) comment '标注状态(0no, 1 yes)', is_public char(1) default '0' comment '0 no, 1 yes', del_flag char(1) default '0' comment '是否删除(0代表存在,1代表删除)',