From 999e413305e69737c022551d7ba617bbfd3e0b82 Mon Sep 17 00:00:00 2001 From: teddy Date: Mon, 2 Feb 2026 19:13:18 +0900 Subject: [PATCH] =?UTF-8?q?=EB=AA=A8=EB=8D=B8=EA=B4=80=EB=A6=AC=20?= =?UTF-8?q?=ED=95=99=EC=8A=B5=20=EC=A1=B0=ED=9A=8C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../training/model/ModelMngApiController.java | 2 +- .../cd/training/model/dto/ModelMngDto.java | 25 ++-- .../postgres/core/ModelMngCoreService.java | 11 +- .../entity/ModelTrainMasterEntity.java | 112 ++++++++++-------- .../model/ModelMngRepositoryImpl.java | 9 +- 5 files changed, 82 insertions(+), 77 deletions(-) diff --git a/src/main/java/com/kamco/cd/training/model/ModelMngApiController.java b/src/main/java/com/kamco/cd/training/model/ModelMngApiController.java index 2d71708..286e302 100644 --- a/src/main/java/com/kamco/cd/training/model/ModelMngApiController.java +++ b/src/main/java/com/kamco/cd/training/model/ModelMngApiController.java @@ -27,7 +27,7 @@ import org.springframework.web.bind.annotation.RestController; @RestController @RequiredArgsConstructor -@Tag(name = "모델관리", description = "모델관리 (학습 모델, 하이퍼파라미터, 메모)") +@Tag(name = "모델관리", description = "어드민 홈 > 모델학습관리 > 모델관리 > 목록") @RequestMapping("/api/models") public class ModelMngApiController { private final ModelMngService modelMngService; diff --git a/src/main/java/com/kamco/cd/training/model/dto/ModelMngDto.java b/src/main/java/com/kamco/cd/training/model/dto/ModelMngDto.java index e4f6d24..0f05ff6 100644 --- a/src/main/java/com/kamco/cd/training/model/dto/ModelMngDto.java +++ b/src/main/java/com/kamco/cd/training/model/dto/ModelMngDto.java @@ -8,6 +8,7 @@ import jakarta.validation.constraints.NotNull; import java.time.ZonedDateTime; import java.util.List; import java.util.Map; +import java.util.UUID; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; @@ -27,14 +28,16 @@ public class ModelMngDto { public static class Basic { private Long id; - private String modelNm; + private UUID uuid; + private String modelVer; @JsonFormatDttm private ZonedDateTime startDttm; - @JsonFormatDttm private ZonedDateTime trainingEndDttm; - @JsonFormatDttm private ZonedDateTime testEndDttm; - private String durationDttm; - private String processStage; - private String statusCd; - private String status; + @JsonFormatDttm private ZonedDateTime step1EndDttm; + @JsonFormatDttm private ZonedDateTime step1Duration; + @JsonFormatDttm private ZonedDateTime step2EndDttm; + @JsonFormatDttm private ZonedDateTime step2Duration; + private String step1Status; + private String step2Status; + private String transferStatus; } @Schema(name = "searchReq", description = "모델 관리 목록조회 파라미터") @@ -75,11 +78,11 @@ public class ModelMngDto { @JsonFormatDttm private ZonedDateTime step1EndDttm; - private String step1Duration; + private ZonedDateTime step1Duration; @JsonFormatDttm private ZonedDateTime step2EndDttm; - private String step2Duration; + private ZonedDateTime step2Duration; private Integer progressRate; @JsonFormatDttm private ZonedDateTime createdDttm; @@ -109,11 +112,11 @@ public class ModelMngDto { @JsonFormatDttm private ZonedDateTime step1EndDttm; - private String step1Duration; + private ZonedDateTime step1Duration; @JsonFormatDttm private ZonedDateTime step2EndDttm; - private String step2Duration; + private ZonedDateTime step2Duration; @JsonFormatDttm private ZonedDateTime createdDttm; diff --git a/src/main/java/com/kamco/cd/training/postgres/core/ModelMngCoreService.java b/src/main/java/com/kamco/cd/training/postgres/core/ModelMngCoreService.java index 0e5bd82..6fed74c 100644 --- a/src/main/java/com/kamco/cd/training/postgres/core/ModelMngCoreService.java +++ b/src/main/java/com/kamco/cd/training/postgres/core/ModelMngCoreService.java @@ -50,10 +50,8 @@ public class ModelMngCoreService { return ModelMngDto.Detail.builder() .uuid(entity.getUuid().toString()) .modelVer(entity.getModelVer()) - .hyperVer(entity.getHyperVer()) .epochVer(entity.getEpochVer()) .processStep(entity.getProcessStep()) - .statusCd(entity.getStatusCd()) .trainStartDttm(entity.getTrainStartDttm()) .epochCnt(entity.getEpochCnt()) .datasetRatio(entity.getDatasetRatio()) @@ -97,7 +95,6 @@ public class ModelMngCoreService { ModelMngDto.TrainListRes.builder() .uuid(entity.getUuid().toString()) .modelVer(entity.getModelVer()) - .status(entity.getStatusCd()) .processStep(entity.getProcessStep()) .trainStartDttm(entity.getTrainStartDttm()) .progressRate(entity.getProgressRate()) @@ -135,10 +132,8 @@ public class ModelMngCoreService { public ModelTrainMasterEntity createTrainMaster(ModelMngDto.TrainStartReq trainReq) { ModelTrainMasterEntity entity = new ModelTrainMasterEntity(); entity.setModelVer(trainReq.getHyperVer()); - entity.setHyperVer(trainReq.getHyperVer()); entity.setEpochVer(String.valueOf(trainReq.getEpoch())); entity.setProcessStep("STEP1"); - entity.setStatusCd("READY"); entity.setTrainStartDttm(ZonedDateTime.now()); entity.setEpochCnt(trainReq.getEpoch()); entity.setDatasetRatio(trainReq.getDatasetRatio()); @@ -191,9 +186,9 @@ public class ModelMngCoreService { ModelTrainMasterEntity entity = findByUuid(uuid); // 진행 중인 모델은 삭제 불가 - if ("RUNNING".equals(entity.getStatusCd())) { - throw new BadRequestException("진행 중인 모델은 삭제할 수 없습니다."); - } + // if ("RUNNING".equals(entity.getStatusCd())) { + // throw new BadRequestException("진행 중인 모델은 삭제할 수 없습니다."); + // } entity.setDelYn(true); entity.setUpdatedDttm(ZonedDateTime.now()); diff --git a/src/main/java/com/kamco/cd/training/postgres/entity/ModelTrainMasterEntity.java b/src/main/java/com/kamco/cd/training/postgres/entity/ModelTrainMasterEntity.java index a7a0019..ff577fe 100644 --- a/src/main/java/com/kamco/cd/training/postgres/entity/ModelTrainMasterEntity.java +++ b/src/main/java/com/kamco/cd/training/postgres/entity/ModelTrainMasterEntity.java @@ -3,10 +3,12 @@ package com.kamco.cd.training.postgres.entity; import com.kamco.cd.training.model.dto.ModelMngDto; import jakarta.persistence.Column; import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; -import jakarta.persistence.PrePersist; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; import jakarta.persistence.Table; import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.Size; @@ -16,6 +18,8 @@ import java.util.UUID; import lombok.Getter; import lombok.Setter; import org.hibernate.annotations.ColumnDefault; +import org.hibernate.annotations.OnDelete; +import org.hibernate.annotations.OnDeleteAction; @Getter @Setter @@ -28,17 +32,14 @@ public class ModelTrainMasterEntity { @Column(name = "model_uid", nullable = false) private Long id; - @Column(name = "uuid", columnDefinition = "uuid", nullable = false, updatable = false) - private UUID uuid; - @Size(max = 50) @NotNull @Column(name = "model_ver", nullable = false, length = 50) private String modelVer; - @Size(max = 50) - @Column(name = "hyper_ver", length = 50) - private String hyperVer; + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "hyper_ver") + private ModelHyperParamEntity hyperVer; @Size(max = 50) @Column(name = "epoch_ver", length = 50) @@ -48,10 +49,6 @@ public class ModelTrainMasterEntity { @Column(name = "process_step", length = 50) private String processStep; - @Size(max = 20) - @Column(name = "status_cd", length = 20) - private String statusCd; - @Column(name = "train_start_dttm") private ZonedDateTime trainStartDttm; @@ -68,19 +65,18 @@ public class ModelTrainMasterEntity { @Column(name = "step1_end_dttm") private ZonedDateTime step1EndDttm; - @Size(max = 50) @Column(name = "step1_duration", length = 50) - private String step1Duration; + private ZonedDateTime step1Duration; @Column(name = "step2_end_dttm") private ZonedDateTime step2EndDttm; - @Size(max = 50) @Column(name = "step2_duration", length = 50) - private String step2Duration; + private ZonedDateTime step2Duration; + @NotNull @ColumnDefault("false") - @Column(name = "del_yn") + @Column(name = "del_yn", nullable = false) private Boolean delYn = false; @Column(name = "created_uid") @@ -113,19 +109,6 @@ public class ModelTrainMasterEntity { @Column(name = "error_msg", length = Integer.MAX_VALUE) private String errorMsg; - // ==================== Resume Training (학습 재시작) ==================== - - @Column(name = "last_checkpoint_epoch") - private Integer lastCheckpointEpoch; - - @Size(max = 500) - @Column(name = "checkpoint_path", length = 500) - private String checkpointPath; - - @ColumnDefault("false") - @Column(name = "can_resume") - private Boolean canResume = false; - @Column(name = "step2_start_dttm") private Instant step2StartDttm; @@ -136,35 +119,60 @@ public class ModelTrainMasterEntity { @Column(name = "memo", length = Integer.MAX_VALUE) private String memo; - @Column(name = "base_model_uid") - private Integer baseModelUid; + @ManyToOne(fetch = FetchType.LAZY) + @OnDelete(action = OnDeleteAction.SET_NULL) + @JoinColumn(name = "base_model_uid") + private ModelTrainMasterEntity baseModelUid; @Size(max = 1000) @Column(name = "pretrained_model_path", length = 1000) private String pretrainedModelPath; - @PrePersist - public void prePersist() { - if (this.uuid == null) { - this.uuid = UUID.randomUUID(); - } - } + @Column(name = "last_checkpoint_epoch") + private Integer lastCheckpointEpoch; + + @Size(max = 500) + @ColumnDefault("NULL") + @Column(name = "checkpoint_path", length = 500) + private String checkpointPath; + + @ColumnDefault("false") + @Column(name = "can_resume") + private Boolean canResume; + + @NotNull + @ColumnDefault("uuid_generate_v4()") + @Column(name = "uuid", nullable = false) + private UUID uuid; + + @Size(max = 10) + @Column(name = "step1_status", length = 10) + private String step1Status; + + @Size(max = 10) + @Column(name = "step2_status", length = 10) + private String step2Status; + + @Size(max = 10) + @Column(name = "transfer_status", length = 10) + private String transferStatus; + + @Size(max = 10) + @Column(name = "status_cd", length = 10) + private String statusCd; public ModelMngDto.Basic toDto() { - ModelMngDto.Basic dto = new ModelMngDto.Basic(); - dto.setId(this.id); - dto.setModelNm(this.modelVer); - dto.setStartDttm(this.trainStartDttm); - dto.setTrainingEndDttm(this.step1EndDttm); - dto.setTestEndDttm(this.step2EndDttm); - dto.setDurationDttm(this.step2Duration); - dto.setProcessStage(this.processStep); - dto.setStatusCd(this.statusCd); - return dto; - } - - /** UUID 필드가 제대로 설정되었는지 확인 (디버그용) */ - public String getUuidString() { - return this.uuid != null ? this.uuid.toString() : null; + return new ModelMngDto.Basic( + this.id, + this.uuid, + this.modelVer, + this.trainStartDttm, + this.step1EndDttm, + this.step1Duration, + this.step2EndDttm, + this.step2Duration, + this.step1Status, + this.step2Status, + this.transferStatus); } } diff --git a/src/main/java/com/kamco/cd/training/postgres/repository/model/ModelMngRepositoryImpl.java b/src/main/java/com/kamco/cd/training/postgres/repository/model/ModelMngRepositoryImpl.java index cf3b6c0..faf8814 100644 --- a/src/main/java/com/kamco/cd/training/postgres/repository/model/ModelMngRepositoryImpl.java +++ b/src/main/java/com/kamco/cd/training/postgres/repository/model/ModelMngRepositoryImpl.java @@ -8,7 +8,6 @@ import com.querydsl.jpa.impl.JPAQueryFactory; import java.util.List; import java.util.Optional; import lombok.RequiredArgsConstructor; -import org.apache.commons.lang3.StringUtils; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageImpl; import org.springframework.data.domain.Pageable; @@ -31,10 +30,10 @@ public class ModelMngRepositoryImpl implements ModelMngRepositoryCustom { public Page findByModels(ModelMngDto.SearchReq searchReq) { Pageable pageable = searchReq.toPageable(); BooleanBuilder builder = new BooleanBuilder(); - - if (StringUtils.isNotBlank(searchReq.getStatus())) { - builder.and(modelMng.statusCd.eq(searchReq.getStatus())); - } + // + // if (StringUtils.isNotBlank(searchReq.getStatus())) { + // builder.and(modelMng.statusCd.eq(searchReq.getStatus())); + // } // Entity 직접 조회 (Projections 사용 지양) List content =