From 350d622e5a5c997e30536cca1dbf058e98576f27 Mon Sep 17 00:00:00 2001 From: teddy Date: Wed, 4 Feb 2026 18:26:02 +0900 Subject: [PATCH 1/6] =?UTF-8?q?=EB=AF=B8=EC=82=AC=EC=9A=A9=20=EC=86=8C?= =?UTF-8?q?=EC=8A=A4=20=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../hyperparam/HyperParamApiController.java | 3 +- .../model/ModelTrainMngApiController.java | 175 -------- .../cd/training/model/dto/ModelMngDto.java | 374 ------------------ .../cd/training/model/dto/ModelVerDto.java | 61 --- .../model/service/ModelTrainMngService.java | 11 - .../model/service/ModelTrainService.java | 334 ---------------- .../postgres/core/DatasetCoreService.java | 99 ----- .../core/ModelTrainMngCoreService.java | 73 ---- 8 files changed, 1 insertion(+), 1129 deletions(-) delete mode 100644 src/main/java/com/kamco/cd/training/model/dto/ModelMngDto.java delete mode 100644 src/main/java/com/kamco/cd/training/model/dto/ModelVerDto.java delete mode 100644 src/main/java/com/kamco/cd/training/model/service/ModelTrainService.java diff --git a/src/main/java/com/kamco/cd/training/hyperparam/HyperParamApiController.java b/src/main/java/com/kamco/cd/training/hyperparam/HyperParamApiController.java index aacd39a..60ff8d2 100644 --- a/src/main/java/com/kamco/cd/training/hyperparam/HyperParamApiController.java +++ b/src/main/java/com/kamco/cd/training/hyperparam/HyperParamApiController.java @@ -5,7 +5,6 @@ import com.kamco.cd.training.config.api.ApiResponseDto; import com.kamco.cd.training.hyperparam.dto.HyperParamDto; import com.kamco.cd.training.hyperparam.dto.HyperParamDto.List; import com.kamco.cd.training.hyperparam.service.HyperParamService; -import com.kamco.cd.training.model.dto.ModelMngDto; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.media.Content; @@ -154,7 +153,7 @@ public class HyperParamApiController { content = @Content( mediaType = "application/json", - schema = @Schema(implementation = ModelMngDto.HyperParamInfo.class))), + schema = @Schema(implementation = HyperParamDto.Basic.class))), @ApiResponse(responseCode = "404", description = "하이퍼파라미터를 찾을 수 없음", content = @Content), @ApiResponse(responseCode = "500", description = "서버 오류", content = @Content) }) diff --git a/src/main/java/com/kamco/cd/training/model/ModelTrainMngApiController.java b/src/main/java/com/kamco/cd/training/model/ModelTrainMngApiController.java index 88ce615..ce685b0 100644 --- a/src/main/java/com/kamco/cd/training/model/ModelTrainMngApiController.java +++ b/src/main/java/com/kamco/cd/training/model/ModelTrainMngApiController.java @@ -83,179 +83,4 @@ public class ModelTrainMngApiController { modelTrainMngService.createModelTrain(req); return ApiResponseDto.ok("ok"); } - - // - // @Operation(summary = "학습 모델 상세 조회", description = "학습 모델의 상세 정보를 UUID로 조회합니다") - // @ApiResponses( - // value = { - // @ApiResponse( - // responseCode = "200", - // description = "조회 성공", - // content = - // @Content( - // mediaType = "application/json", - // schema = @Schema(implementation = ModelMngDto.Detail.class))), - // @ApiResponse(responseCode = "404", description = "모델을 찾을 수 없음", content = @Content), - // @ApiResponse(responseCode = "500", description = "서버 오류", content = @Content) - // }) - // @GetMapping("/{uuid}") - // public ApiResponseDto getModelDetail( - // @Parameter(description = "모델 UUID", example = "b7e99739-6736-45f9-a224-8161ecddf287") - // @PathVariable - // String uuid) { - // return ApiResponseDto.ok(modelTrainMngService.getModelDetailByUuid(uuid)); - // } - // - // // ==================== 학습 모델학습관리 API (5종) ==================== - // - // @Operation(summary = "학습 모델 통합 조회", description = "학습 관리 화면에서 학습 이력 리스트와 현재 상태를 조회합니다") - // @ApiResponses( - // value = { - // @ApiResponse( - // responseCode = "200", - // description = "조회 성공", - // content = - // @Content( - // mediaType = "application/json", - // schema = @Schema(implementation = List.class))), - // @ApiResponse(responseCode = "500", description = "서버 오류", content = @Content) - // }) - // @GetMapping("/train") - // public ApiResponseDto> getTrainModelList() { - // return ApiResponseDto.ok(modelTrainService.getTrainModelList()); - // } - // - // @Operation(summary = "학습 설정 통합 조회", description = "학습 실행 팝업 구성에 필요한 모든 데이터를 한 번에 반환합니다") - // @ApiResponses( - // value = { - // @ApiResponse( - // responseCode = "200", - // description = "조회 성공", - // content = - // @Content( - // mediaType = "application/json", - // schema = @Schema(implementation = ModelMngDto.FormConfigRes.class))), - // @ApiResponse(responseCode = "500", description = "서버 오류", content = @Content) - // }) - // @GetMapping("/train/form-config") - // public ApiResponseDto getFormConfig() { - // return ApiResponseDto.ok(modelTrainService.getFormConfig()); - // } - // - // @Operation(summary = "학습 시작", description = "모든 설정(Step 1~3)을 마치고 최종적으로 학습 프로세스를 시작합니다") - // @ApiResponses( - // value = { - // @ApiResponse( - // responseCode = "200", - // description = "학습 시작 성공", - // content = - // @Content( - // mediaType = "application/json", - // schema = @Schema(implementation = ModelMngDto.TrainStartRes.class))), - // @ApiResponse(responseCode = "400", description = "잘못된 요청", content = @Content), - // @ApiResponse(responseCode = "500", description = "서버 오류", content = @Content) - // }) - // @PostMapping("/train") - // public ApiResponseDto startTraining( - // @Valid @RequestBody ModelMngDto.TrainStartReq trainReq) { - // return ApiResponseDto.ok(modelTrainService.startTraining(trainReq)); - // } - // - // @Operation(summary = "학습 모델 삭제", description = "목록에서 특정 학습 모델을 삭제합니다") - // @ApiResponses( - // value = { - // @ApiResponse(responseCode = "200", description = "삭제 성공", content = @Content), - // @ApiResponse(responseCode = "400", description = "진행 중인 모델은 삭제 불가", content = @Content), - // @ApiResponse(responseCode = "404", description = "모델을 찾을 수 없음", content = @Content), - // @ApiResponse(responseCode = "500", description = "서버 오류", content = @Content) - // }) - // @DeleteMapping("/train/{uuid}") - // public ApiResponseDto deleteTrainModel( - // @Parameter(description = "모델 UUID") @PathVariable String uuid) { - // modelTrainService.deleteTrainModel(uuid); - // return ApiResponseDto.ok(null); - // } - // - // // ==================== Resume Training (학습 재시작) ==================== - // - // @Operation(summary = "학습 재시작 정보 조회", description = "중단된 학습의 재시작 가능 여부와 Checkpoint 정보를 조회합니다") - // @ApiResponses( - // value = { - // @ApiResponse( - // responseCode = "200", - // description = "조회 성공", - // content = - // @Content( - // mediaType = "application/json", - // schema = @Schema(implementation = ModelMngDto.ResumeInfo.class))), - // @ApiResponse(responseCode = "404", description = "모델을 찾을 수 없음", content = @Content), - // @ApiResponse(responseCode = "500", description = "서버 오류", content = @Content) - // }) - // @GetMapping("/train/{uuid}/resume-info") - // public ApiResponseDto getResumeInfo( - // @Parameter(description = "모델 UUID") @PathVariable String uuid) { - // return ApiResponseDto.ok(modelTrainService.getResumeInfo(uuid)); - // } - // - // @Operation(summary = "학습 재시작", description = "중단된 지점(Checkpoint)부터 학습을 재개합니다") - // @ApiResponses( - // value = { - // @ApiResponse( - // responseCode = "200", - // description = "재시작 성공", - // content = - // @Content( - // mediaType = "application/json", - // schema = @Schema(implementation = ModelMngDto.ResumeResponse.class))), - // @ApiResponse(responseCode = "400", description = "재시작 불가능한 상태", content = @Content), - // @ApiResponse(responseCode = "404", description = "모델을 찾을 수 없음", content = @Content), - // @ApiResponse(responseCode = "500", description = "서버 오류", content = @Content) - // }) - // @PostMapping("/train/{uuid}/resume") - // public ApiResponseDto resumeTraining( - // @Parameter(description = "모델 UUID") @PathVariable String uuid, - // @Valid @RequestBody ModelMngDto.ResumeRequest resumeReq) { - // return ApiResponseDto.ok(modelTrainService.resumeTraining(uuid, resumeReq)); - // } - // - // // ==================== Best Epoch Setting (Best Epoch 설정) ==================== - // - // @Operation(summary = "Best Epoch 설정", description = "사용자가 직접 Best Epoch를 선택하여 설정합니다") - // @ApiResponses( - // value = { - // @ApiResponse( - // responseCode = "200", - // description = "설정 성공", - // content = - // @Content( - // mediaType = "application/json", - // schema = @Schema(implementation = ModelMngDto.BestEpochResponse.class))), - // @ApiResponse(responseCode = "404", description = "모델을 찾을 수 없음", content = @Content), - // @ApiResponse(responseCode = "500", description = "서버 오류", content = @Content) - // }) - // @PostMapping("/train/{uuid}/best-epoch") - // public ApiResponseDto setBestEpoch( - // @Parameter(description = "모델 UUID") @PathVariable String uuid, - // @Valid @RequestBody ModelMngDto.BestEpochRequest bestEpochReq) { - // return ApiResponseDto.ok(modelTrainService.setBestEpoch(uuid, bestEpochReq)); - // } - // - // @Operation(summary = "Epoch별 성능 지표 조회", description = "학습된 모델의 Epoch별 성능 지표를 조회합니다") - // @ApiResponses( - // value = { - // @ApiResponse( - // responseCode = "200", - // description = "조회 성공", - // content = - // @Content( - // mediaType = "application/json", - // schema = @Schema(implementation = List.class))), - // @ApiResponse(responseCode = "404", description = "모델을 찾을 수 없음", content = @Content), - // @ApiResponse(responseCode = "500", description = "서버 오류", content = @Content) - // }) - // @GetMapping("/train/{uuid}/epoch-metrics") - // public ApiResponseDto> getEpochMetrics( - // @Parameter(description = "모델 UUID") @PathVariable String uuid) { - // return ApiResponseDto.ok(modelTrainService.getEpochMetrics(uuid)); - // } } 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 deleted file mode 100644 index 245d19e..0000000 --- a/src/main/java/com/kamco/cd/training/model/dto/ModelMngDto.java +++ /dev/null @@ -1,374 +0,0 @@ -package com.kamco.cd.training.model.dto; - -import com.kamco.cd.training.common.utils.interfaces.JsonFormatDttm; -import io.swagger.v3.oas.annotations.media.Schema; -import jakarta.validation.constraints.NotBlank; -import jakarta.validation.constraints.NotEmpty; -import jakarta.validation.constraints.NotNull; -import java.time.ZonedDateTime; -import java.util.List; -import java.util.Map; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; - -public class ModelMngDto { - - @Schema(name = "Detail", description = "모델 상세 정보") - @Getter - @Builder - public static class Detail { - private String uuid; - private String modelVer; - private String hyperVer; - private String epochVer; - private String processStep; - private String statusCd; - private String statusText; - - @JsonFormatDttm private ZonedDateTime trainStartDttm; - - private Integer epochCnt; - private String datasetRatio; - private Integer bestEpoch; - private Integer confirmedBestEpoch; - - @JsonFormatDttm private ZonedDateTime step1EndDttm; - - private ZonedDateTime step1Duration; - - @JsonFormatDttm private ZonedDateTime step2EndDttm; - - private ZonedDateTime step2Duration; - private Integer progressRate; - - @JsonFormatDttm private ZonedDateTime createdDttm; - - @JsonFormatDttm private ZonedDateTime updatedDttm; - - private String modelPath; - private String errorMsg; - } - - @Schema(name = "TrainListRes", description = "학습 모델 목록 응답") - @Getter - @Setter - @NoArgsConstructor - @AllArgsConstructor - @Builder - public static class TrainListRes { - private String uuid; - private String modelVer; - private String status; - private String processStep; - - @JsonFormatDttm private ZonedDateTime trainStartDttm; - - private Integer progressRate; - private Integer epochCnt; - - @JsonFormatDttm private ZonedDateTime step1EndDttm; - - private ZonedDateTime step1Duration; - - @JsonFormatDttm private ZonedDateTime step2EndDttm; - - private ZonedDateTime step2Duration; - - @JsonFormatDttm private ZonedDateTime createdDttm; - - private String errorMsg; - - private Boolean canResume; - private Integer lastCheckpointEpoch; - } - - @Schema(name = "FormConfigRes", description = "학습 설정 통합 조회 응답") - @Getter - @Setter - @NoArgsConstructor - @AllArgsConstructor - @Builder - public static class FormConfigRes { - private Boolean isTrainAvailable; - private List hyperParams; - private List datasets; - private String runningModelUuid; - } - - @Schema(name = "HyperParamInfo", description = "하이퍼파라미터 정보") - @Getter - @Setter - @NoArgsConstructor - @AllArgsConstructor - @Builder - public static class HyperParamInfo { - @Schema(description = "하이퍼파라미터 버전", example = "V3.99.251221.120518") - private String hyperVer; - - // Important - @Schema(description = "백본", example = "large") - private String backbone; - - @Schema(description = "입력 사이즈", example = "256,256") - private String inputSize; - - @Schema(description = "크롭 사이즈", example = "256,256") - private String cropSize; - - @Schema(description = "에폭 수", example = "200") - private Integer epochCnt; - - @Schema(description = "배치 사이즈", example = "16") - private Integer batchSize; - - // Architecture - @Schema(description = "Drop Path Rate", example = "0.3") - private Double dropPathRate; - - @Schema(description = "Frozen Stages", example = "-1") - private Integer frozenStages; - - @Schema(description = "Neck Policy", example = "abs_diff") - private String neckPolicy; - - @Schema(description = "Decoder Channels", example = "512,256,128,64") - private String decoderChannels; - - @Schema(description = "Class Weight", example = "1,1") - private String classWeight; - - @Schema(description = "레이어 수", example = "24") - private Integer numLayers; - - // Optimization - @Schema(description = "Learning Rate", example = "0.00006") - private Double learningRate; - - @Schema(description = "Weight Decay", example = "0.05") - private Double weightDecay; - - @Schema(description = "Layer Decay Rate", example = "0.9") - private Double layerDecayRate; - - @Schema(description = "DDP Unused Params 찾기", example = "true") - private Boolean ddpFindUnusedParams; - - @Schema(description = "Ignore Index", example = "255") - private Integer ignoreIndex; - - // Data - @Schema(description = "Train Workers", example = "16") - private Integer trainNumWorkers; - - @Schema(description = "Val Workers", example = "8") - private Integer valNumWorkers; - - @Schema(description = "Test Workers", example = "8") - private Integer testNumWorkers; - - @Schema(description = "Train Shuffle", example = "true") - private Boolean trainShuffle; - - @Schema(description = "Train Persistent", example = "true") - private Boolean trainPersistent; - - @Schema(description = "Val Persistent", example = "true") - private Boolean valPersistent; - - // Evaluation - @Schema(description = "Metrics", example = "mFscore,mIoU") - private String metrics; - - @Schema(description = "Save Best", example = "changed_fscore") - private String saveBest; - - @Schema(description = "Save Best Rule", example = "greater") - private String saveBestRule; - - @Schema(description = "Val Interval", example = "10") - private Integer valInterval; - - @Schema(description = "Log Interval", example = "400") - private Integer logInterval; - - @Schema(description = "Vis Interval", example = "1") - private Integer visInterval; - - // Hardware - @Schema(description = "GPU 수", example = "4") - private Integer gpuCnt; - - @Schema(description = "GPU IDs", example = "0,1,2,3") - private String gpuIds; - - @Schema(description = "Master Port", example = "1122") - private Integer masterPort; - - // Augmentation - @Schema(description = "Rotation 확률", example = "0.5") - private Double rotProb; - - @Schema(description = "Flip 확률", example = "0.5") - private Double flipProb; - - @Schema(description = "Rotation 각도", example = "-20,20") - private String rotDegree; - - @Schema(description = "Exchange 확률", example = "0.5") - private Double exchangeProb; - - @Schema(description = "Brightness Delta", example = "10") - private Integer brightnessDelta; - - @Schema(description = "Contrast Range", example = "0.8,1.2") - private String contrastRange; - - @Schema(description = "Saturation Range", example = "0.8,1.2") - private String saturationRange; - - @Schema(description = "Hue Delta", example = "10") - private Integer hueDelta; - - // Legacy - private Double dropoutRatio; - private Integer cnnFilterCnt; - - // Common - @Schema(description = "메모", example = "안녕하세요 캠코담당자 입니다. 하이퍼파라미터 신규등록합니다") - private String memo; - - @JsonFormatDttm private ZonedDateTime createdDttm; - } - - @Schema(name = "DatasetInfo", description = "데이터셋 정보") - @Getter - @Setter - @NoArgsConstructor - @AllArgsConstructor - @Builder - public static class DatasetInfo { - private Long id; - private String title; - private String groupTitle; - private Long totalItems; - private String totalSize; - private Map classCounts; - private String memo; - - @JsonFormatDttm private ZonedDateTime createdDttm; - } - - @Schema(name = "TrainStartReq", description = "학습 시작 요청") - @Getter - @Setter - @NoArgsConstructor - @AllArgsConstructor - public static class TrainStartReq { - @NotBlank(message = "하이퍼파라미터 버전은 필수입니다") - @Schema(example = "V3.99.251221.120518") - private String hyperVer; - - @NotEmpty(message = "데이터셋은 최소 1개 이상 선택해야 합니다") - private List datasetIds; - - @NotNull(message = "에폭 수는 필수입니다") - @jakarta.validation.constraints.Min(value = 1, message = "에폭 수는 최소 1 이상이어야 합니다") - @jakarta.validation.constraints.Max(value = 200, message = "에폭 수는 최대 200까지 설정 가능합니다") - @Schema(example = "200") - private Integer epoch; - - @Schema(example = "7:2:1", description = "데이터 분할 비율 (Training:Validation:Test)") - private String datasetRatio; - } - - @Schema(name = "TrainStartRes", description = "학습 시작 응답") - @Getter - @Setter - @NoArgsConstructor - @AllArgsConstructor - @Builder - public static class TrainStartRes { - private String uuid; - private String status; - } - - @Schema(name = "ResumeInfo", description = "학습 재시작 정보") - @Getter - @Setter - @NoArgsConstructor - @AllArgsConstructor - @Builder - public static class ResumeInfo { - private Boolean canResume; - private Integer lastEpoch; - private Integer totalEpoch; - private String checkpointPath; - @JsonFormatDttm private ZonedDateTime failedAt; - } - - @Schema(name = "ResumeRequest", description = "학습 재시작 요청") - @Getter - @Setter - @NoArgsConstructor - @AllArgsConstructor - public static class ResumeRequest { - @NotNull(message = "재시작 Epoch는 필수입니다") - private Integer resumeFromEpoch; - - private Integer newTotalEpoch; - } - - @Schema(name = "ResumeResponse", description = "학습 재시작 응답") - @Getter - @Setter - @NoArgsConstructor - @AllArgsConstructor - @Builder - public static class ResumeResponse { - private String uuid; - private String status; - private Integer resumedFromEpoch; - } - - @Schema(name = "BestEpochRequest", description = "Best Epoch 설정 요청") - @Getter - @Setter - @NoArgsConstructor - @AllArgsConstructor - public static class BestEpochRequest { - @NotNull(message = "Best Epoch는 필수입니다") - private Integer bestEpoch; - - private String reason; - } - - @Schema(name = "BestEpochResponse", description = "Best Epoch 설정 응답") - @Getter - @Setter - @NoArgsConstructor - @AllArgsConstructor - @Builder - public static class BestEpochResponse { - private String uuid; - private Integer bestEpoch; - private Integer confirmedBestEpoch; - private Integer previousBestEpoch; - } - - @Schema(name = "EpochMetric", description = "Epoch별 성능 지표") - @Getter - @Setter - @NoArgsConstructor - @AllArgsConstructor - @Builder - public static class EpochMetric { - private Integer epoch; - private Double mIoU; - private Double mFscore; - private Double loss; - private Boolean isBest; - } -} diff --git a/src/main/java/com/kamco/cd/training/model/dto/ModelVerDto.java b/src/main/java/com/kamco/cd/training/model/dto/ModelVerDto.java deleted file mode 100644 index b589925..0000000 --- a/src/main/java/com/kamco/cd/training/model/dto/ModelVerDto.java +++ /dev/null @@ -1,61 +0,0 @@ -package com.kamco.cd.training.model.dto; - -import com.kamco.cd.training.common.utils.interfaces.JsonFormatDttm; -import io.swagger.v3.oas.annotations.media.Schema; -import java.time.ZonedDateTime; -import lombok.Getter; - -public class ModelVerDto { - - @Schema(name = "modelVer Basic", description = "모델버전 엔티티 기본 정보") - @Getter - public static class Basic { - - private final Long id; - private final Long modelUid; - - private final String modelCate; - private final String modelVer; - - private final String usedState; - private final String modelState; - private final Double qualityProb; - private final String deployState; - private final String modelPath; - - @JsonFormatDttm private final ZonedDateTime createdDttm; - private final Long createdUid; - - @JsonFormatDttm private final ZonedDateTime updatedDttm; - private final Long updatedUid; - - public Basic( - Long id, - Long modelUid, - String modelCate, - String modelVer, - String usedState, - String modelState, - Double qualityProb, - String deployState, - String modelPath, - ZonedDateTime createdDttm, - Long createdUid, - ZonedDateTime updatedDttm, - Long updatedUid) { - this.id = id; - this.modelUid = modelUid; - this.modelCate = modelCate; - this.modelVer = modelVer; - this.usedState = usedState; - this.modelState = modelState; - this.qualityProb = qualityProb; - this.deployState = deployState; - this.modelPath = modelPath; - this.createdDttm = createdDttm; - this.createdUid = createdUid; - this.updatedDttm = updatedDttm; - this.updatedUid = updatedUid; - } - } -} diff --git a/src/main/java/com/kamco/cd/training/model/service/ModelTrainMngService.java b/src/main/java/com/kamco/cd/training/model/service/ModelTrainMngService.java index 05b2b72..b271f0d 100644 --- a/src/main/java/com/kamco/cd/training/model/service/ModelTrainMngService.java +++ b/src/main/java/com/kamco/cd/training/model/service/ModelTrainMngService.java @@ -3,7 +3,6 @@ package com.kamco.cd.training.model.service; import com.kamco.cd.training.common.dto.HyperParam; import com.kamco.cd.training.common.enums.HyperParamSelectType; import com.kamco.cd.training.hyperparam.dto.HyperParamDto; -import com.kamco.cd.training.model.dto.ModelMngDto; import com.kamco.cd.training.model.dto.ModelTrainMngDto; import com.kamco.cd.training.model.dto.ModelTrainMngDto.SearchReq; import com.kamco.cd.training.postgres.core.HyperParamCoreService; @@ -74,14 +73,4 @@ public class ModelTrainMngService { // 모델 config 저장 modelTrainMngCoreService.saveModelConfig(modelId, req.getModelConfig()); } - - /** - * 모델학습 상세 조회 - * - * @param modelUid 모델 UID - * @return 모델 상세 정보 - */ - public ModelMngDto.Detail getModelDetail(Long modelUid) { - return modelTrainMngCoreService.getModelDetail(modelUid); - } } diff --git a/src/main/java/com/kamco/cd/training/model/service/ModelTrainService.java b/src/main/java/com/kamco/cd/training/model/service/ModelTrainService.java deleted file mode 100644 index 8b5b73b..0000000 --- a/src/main/java/com/kamco/cd/training/model/service/ModelTrainService.java +++ /dev/null @@ -1,334 +0,0 @@ -package com.kamco.cd.training.model.service; - -import com.kamco.cd.training.common.exception.BadRequestException; -import com.kamco.cd.training.common.exception.NotFoundException; -import com.kamco.cd.training.model.dto.ModelMngDto; -import com.kamco.cd.training.postgres.core.DatasetCoreService; -import com.kamco.cd.training.postgres.core.ModelTrainMngCoreService; -import com.kamco.cd.training.postgres.core.SystemMetricsCoreService; -import com.kamco.cd.training.postgres.entity.ModelMasterEntity; -import java.util.List; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -@Service -@RequiredArgsConstructor -@Transactional(readOnly = true) -@Slf4j -public class ModelTrainService { - - private final ModelTrainMngCoreService modelMngCoreService; - private final DatasetCoreService datasetCoreService; - private final SystemMetricsCoreService systemMetricsCoreService; - - /** - * 학습 설정 통합 조회 - * - * @return 학습 설정 폼 데이터 - */ - public ModelMngDto.FormConfigRes getFormConfig() { - // 1. 현재 실행 중인 모델 확인 - String runningModelUuid = modelMngCoreService.findRunningModelUuid(); - boolean isTrainAvailable = (runningModelUuid == null); - - // 2. 저장공간 체크 (10GB 미만 시 학습 불가) - if (isTrainAvailable) { - isTrainAvailable = systemMetricsCoreService.isStorageAvailableForTraining(); - long availableMB = systemMetricsCoreService.getAvailableStorageMB(); - log.info("저장공간 체크 완료: {}MB 사용 가능, 학습 가능 여부: {}", availableMB, isTrainAvailable); - } - - // 3. 하이퍼파라미터 목록 - List hyperParams = - null; // hyperParamCoreService.findAllActiveHyperParams(); - - // 4. 데이터셋 목록 - List datasets = datasetCoreService.findAllActiveDatasetsForTraining(); - - return ModelMngDto.FormConfigRes.builder() - .isTrainAvailable(isTrainAvailable) - .hyperParams(hyperParams) - .datasets(datasets) - .runningModelUuid(runningModelUuid) - .build(); - } - - /** - * 학습 시작 - * - * @param trainReq 학습 시작 요청 - * @return 학습 시작 응답 - */ - @Transactional - public ModelMngDto.TrainStartRes startTraining(ModelMngDto.TrainStartReq trainReq) { - // 1. 동시 실행 방지 검증 - String runningModelUuid = modelMngCoreService.findRunningModelUuid(); - if (runningModelUuid != null) { - throw new BadRequestException( - "이미 실행 중인 학습이 있습니다. 학습은 한 번에 한 개만 실행할 수 있습니다. (실행 중인 모델: " + runningModelUuid + ")"); - } - - // 2. 저장공간 체크 (10GB 미만 시 학습 불가) - if (!systemMetricsCoreService.isStorageAvailableForTraining()) { - long availableMB = systemMetricsCoreService.getAvailableStorageMB(); - long requiredMB = 10 * 1024; // 10GB - throw new BadRequestException( - String.format( - "저장공간이 부족하여 학습을 시작할 수 없습니다. (필요: %dMB, 사용 가능: %dMB)", requiredMB, availableMB)); - } - - // 3. 데이터셋 상태 검증 (COMPLETED 상태만 학습 가능) - validateDatasetStatus(trainReq.getDatasetIds()); - - // 4. 데이터 분할 비율 검증 (예: "7:2:1" 형식) - if (trainReq.getDatasetRatio() != null && !trainReq.getDatasetRatio().isEmpty()) { - validateDatasetRatio(trainReq.getDatasetRatio()); - } - - // 5. 학습 마스터 생성 - ModelMasterEntity entity = modelMngCoreService.createTrainMaster(trainReq); - - // 5. 데이터셋 매핑 생성 - modelMngCoreService.createDatasetMappings(entity.getId(), trainReq.getDatasetIds()); - - // 6. 실제 UUID 사용 - String uuid = entity.getUuid().toString(); - - log.info( - "학습 시작: uuid={}, hyperVer={}, epoch={}, datasets={}", - uuid, - trainReq.getHyperVer(), - trainReq.getEpoch(), - trainReq.getDatasetIds()); - - // TODO: 비동기 GPU 학습 프로세스 트리거 로직 추가 - - return ModelMngDto.TrainStartRes.builder().uuid(uuid).status(entity.getStatusCd()).build(); - } - - /** - * 데이터셋 상태 검증 - * - * @param datasetIds 데이터셋 ID 목록 - */ - private void validateDatasetStatus(List datasetIds) { - for (Long datasetId : datasetIds) { - try { - var dataset = datasetCoreService.getOneById(datasetId); - - // COMPLETED 상태가 아닌 데이터셋이 포함되어 있으면 예외 발생 - if (dataset.getStatus() == null || !"COMPLETED".equals(dataset.getStatus())) { - throw new BadRequestException( - String.format( - "학습에 사용할 수 없는 데이터셋입니다. (ID: %d, 상태: %s). COMPLETED 상태의 데이터셋만 선택 가능합니다.", - datasetId, dataset.getStatus() != null ? dataset.getStatus() : "NULL")); - } - - log.debug("데이터셋 상태 검증 통과: ID={}, Status={}", datasetId, dataset.getStatus()); - } catch (NotFoundException e) { - throw new BadRequestException("존재하지 않는 데이터셋입니다. ID: " + datasetId); - } - } - log.info("모든 데이터셋 상태 검증 완료: {} 개", datasetIds.size()); - } - - /** - * 데이터 분할 비율 검증 - * - * @param datasetRatio 데이터셋 비율 (예: "7:2:1") - */ - private void validateDatasetRatio(String datasetRatio) { - try { - String[] parts = datasetRatio.split(":"); - if (parts.length != 3) { - throw new BadRequestException("데이터 분할 비율은 'Training:Validation:Test' 형식이어야 합니다 (예: 7:2:1)"); - } - - int train = Integer.parseInt(parts[0].trim()); - int validation = Integer.parseInt(parts[1].trim()); - int test = Integer.parseInt(parts[2].trim()); - - int sum = train + validation + test; - if (sum != 10) { - throw new BadRequestException( - String.format("데이터 분할 비율의 합계는 10이어야 합니다. (현재 합계: %d, 입력값: %s)", sum, datasetRatio)); - } - - if (train <= 0 || validation < 0 || test < 0) { - throw new BadRequestException("데이터 분할 비율은 모두 0 이상이어야 합니다 (Training은 1 이상)"); - } - - log.info( - "데이터 분할 비율 검증 완료: Training={}0%, Validation={}0%, Test={}0%", train, validation, test); - } catch (NumberFormatException e) { - throw new BadRequestException("데이터 분할 비율은 숫자로만 구성되어야 합니다: " + datasetRatio); - } - } - - // ==================== Resume Training (학습 재시작) ==================== - // - // /** - // * 학습 재시작 정보 조회 - // * - // * @param uuid 모델 UUID - // * @return 재시작 정보 - // */ - // public ModelMngDto.ResumeInfo getResumeInfo(String uuid) { - // ModelTrainMasterEntity entity = modelMngCoreService.findByUuid(uuid); - // - // return ModelMngDto.ResumeInfo.builder() - // .canResume(entity.getCanResume() != null && entity.getCanResume()) - // .lastEpoch(entity.getLastCheckpointEpoch()) - // .totalEpoch(entity.getEpochCnt()) - // .checkpointPath(entity.getCheckpointPath()) - // // .failedAt( - // // entity.getStopDttm() != null - // // ? entity.getStopDttm().atZone(java.time.ZoneId.systemDefault()) - // // : null) - // .build(); - // } - - /** - * 학습 재시작 - * - * @param uuid 모델 UUID - * @param resumeReq 재시작 요청 - * @return 재시작 응답 - */ - @Transactional - public ModelMngDto.ResumeResponse resumeTraining( - String uuid, ModelMngDto.ResumeRequest resumeReq) { - // ModelTrainMasterEntity entity = modelMngCoreService.findByUuid(uuid); - // - // // 재시작 가능 여부 검증 - // if (entity.getCanResume() == null || !entity.getCanResume()) { - // throw new IllegalStateException("학습 재시작이 불가능한 모델입니다: " + uuid); - // } - // - // if (entity.getLastCheckpointEpoch() == null) { - // throw new IllegalStateException("Checkpoint가 존재하지 않습니다: " + uuid); - // } - // - // // 상태 업데이트 - // entity.setStatusCd("RUNNING"); - // entity.setProgressRate(0); - // - // // 총 Epoch 수 변경 (선택사항) - // if (resumeReq.getNewTotalEpoch() != null) { - // entity.setEpochCnt(resumeReq.getNewTotalEpoch()); - // } - // - // log.info( - // "학습 재시작: uuid={}, resumeFromEpoch={}, totalEpoch={}", - // uuid, - // resumeReq.getResumeFromEpoch(), - // entity.getEpochCnt()); - // - // // TODO: 비동기 GPU 학습 재시작 프로세스 트리거 로직 추가 - // // - Checkpoint 파일 로드 - // // - 지정된 Epoch부터 학습 재개 - - return null; - // ModelMngDto.ResumeResponse.builder() - // .uuid(uuid) - // .status(entity.getStatusCd()) - // .resumedFromEpoch(resumeReq.getResumeFromEpoch()) - // .build(); - } - - // ==================== Best Epoch Setting (Best Epoch 설정) ==================== - - /** - * Best Epoch 설정 - * - * @param uuid 모델 UUID - * @param bestEpochReq Best Epoch 요청 - * @return Best Epoch 응답 - */ - @Transactional - public ModelMngDto.BestEpochResponse setBestEpoch( - String uuid, ModelMngDto.BestEpochRequest bestEpochReq) { - // ModelTrainMasterEntity entity = modelMngCoreService.findByUuid(uuid); - // - // // 1차 학습 완료 상태 검증 - // if (!"STEP1_COMPLETED".equals(entity.getStatusCd()) - // && !"STEP1".equals(entity.getProcessStep())) { - // log.warn( - // "Best Epoch 설정 시도: 현재 상태={}, processStep={}", - // entity.getStatusCd(), - // entity.getProcessStep()); - // } - // - // Integer previousBestEpoch = entity.getConfirmedBestEpoch(); - // - // // 사용자가 확정한 Best Epoch 설정 - // entity.setConfirmedBestEpoch(bestEpochReq.getBestEpoch()); - // - // // 2차 학습(Test) 단계로 상태 전이 - // entity.setProcessStep("STEP2"); - // entity.setStatusCd("STEP2_RUNNING"); - // entity.setProgressRate(0); - // entity.setUpdatedDttm(java.time.ZonedDateTime.now()); - // - // log.info( - // "Best Epoch 설정 및 2차 학습 시작: uuid={}, newBestEpoch={}, previousBestEpoch={}, reason={}, - // newStatus={}", - // uuid, - // bestEpochReq.getBestEpoch(), - // previousBestEpoch, - // bestEpochReq.getReason(), - // entity.getStatusCd()); - - // TODO: 비동기 GPU 2차 학습(Test) 프로세스 트리거 로직 추가 - // - Best Epoch 모델 로드 - // - Test 데이터셋으로 성능 평가 실행 - // - 완료 시 STEP2_COMPLETED 상태로 전환 - - return null; - // ModelMngDto.BestEpochResponse.builder() - // .uuid(uuid) - // .bestEpoch(entity.getBestEpoch()) // 자동 선택된 값 - // .confirmedBestEpoch(entity.getConfirmedBestEpoch()) // 사용자 확정 값 - // .previousBestEpoch(previousBestEpoch) - // .build(); - } - - /** - * Epoch별 성능 지표 조회 - * - * @param uuid 모델 UUID - * @return Epoch별 성능 지표 목록 - */ - public List getEpochMetrics(String uuid) { - // ModelTrainMasterEntity entity = modelMngCoreService.findByUuid(uuid); - // - // // TODO: 실제 학습 로그 파일이나 DB에서 Epoch별 성능 지표 조회 - // // 현재는 샘플 데이터 반환 - // List metrics = new java.util.ArrayList<>(); - // - // if (entity.getEpochCnt() != null && entity.getBestEpoch() != null) { - // // 샘플 데이터 생성 (실제로는 학습 로그 파일 파싱 또는 별도 테이블 조회) - // for (int i = 1; i <= Math.min(entity.getEpochCnt(), 10); i++) { - // int epoch = entity.getBestEpoch() - 5 + i; - // if (epoch <= 0 || epoch > entity.getEpochCnt()) { - // continue; - // } - // - // metrics.add( - // ModelMngDto.EpochMetric.builder() - // .epoch(epoch) - // .mIoU(0.80 + (Math.random() * 0.15)) // 샘플 데이터 - // .mFscore(0.85 + (Math.random() * 0.10)) // 샘플 데이터 - // .loss(0.3 - (Math.random() * 0.15)) // 샘플 데이터 - // .isBest(entity.getBestEpoch() != null && epoch == entity.getBestEpoch()) - // .build()); - // } - // } - // - // log.info("Epoch별 성능 지표 조회: uuid={}, metricsCount={}", uuid, metrics.size()); - - return null; // metrics; - } -} diff --git a/src/main/java/com/kamco/cd/training/postgres/core/DatasetCoreService.java b/src/main/java/com/kamco/cd/training/postgres/core/DatasetCoreService.java index 91cd5f4..d254aef 100644 --- a/src/main/java/com/kamco/cd/training/postgres/core/DatasetCoreService.java +++ b/src/main/java/com/kamco/cd/training/postgres/core/DatasetCoreService.java @@ -1,6 +1,5 @@ package com.kamco.cd.training.postgres.core; -import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import com.kamco.cd.training.common.enums.LearnDataRegister; import com.kamco.cd.training.common.enums.LearnDataType; @@ -10,15 +9,12 @@ import com.kamco.cd.training.dataset.dto.DatasetDto; import com.kamco.cd.training.dataset.dto.DatasetDto.SelectDataSet; import com.kamco.cd.training.dataset.dto.DatasetObjDto.Basic; import com.kamco.cd.training.dataset.dto.DatasetObjDto.SearchReq; -import com.kamco.cd.training.model.dto.ModelMngDto; import com.kamco.cd.training.postgres.entity.DatasetEntity; import com.kamco.cd.training.postgres.entity.DatasetObjEntity; import com.kamco.cd.training.postgres.repository.dataset.DatasetObjRepository; import com.kamco.cd.training.postgres.repository.dataset.DatasetRepository; import java.time.ZonedDateTime; -import java.util.HashMap; import java.util.List; -import java.util.Map; import java.util.UUID; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -187,101 +183,6 @@ public class DatasetCoreService summaryReq.getDatasetIds().size(), totalMapSheets, totalFileSize, averageMapSheets); } - /** - * 활성 데이터셋 전체 조회 (학습 관리용) - * - * @return 데이터셋 정보 목록 - */ - public List findAllActiveDatasetsForTraining() { - List entities = datasetRepository.findByDeletedOrderByCreatedDttmDesc(false); - - return entities.stream() - .map( - entity -> { - // totalSize를 읽기 쉬운 형식으로 변환 - String totalSizeStr = formatFileSize(entity.getTotalSize()); - - // classCounts JSON 파싱 - Map classCounts = entity.getClassCounts(); - - return ModelMngDto.DatasetInfo.builder() - .id(entity.getId()) - .title(entity.getTitle()) - .totalItems(entity.getTotalItems()) - .totalSize(totalSizeStr) - .classCounts(classCounts) - .memo(entity.getMemo()) - .createdDttm(entity.getCreatedDttm()) - .build(); - }) - .toList(); - } - - /** - * JSON 문자열을 Map으로 파싱 - * - * @param jsonStr JSON 문자열 - * @return 클래스별 카운트 맵 - */ - private Map parseClassCounts(String jsonStr) { - if (jsonStr == null || jsonStr.trim().isEmpty()) { - return new HashMap<>(); - } - - try { - return objectMapper.readValue(jsonStr, new TypeReference>() {}); - } catch (Exception e) { - log.warn("클래스 통계 JSON 파싱 실패: {}", jsonStr, e); - return new HashMap<>(); - } - } - - /** - * 데이터셋의 클래스 통계 계산 및 저장 - * - * @param datasetId 데이터셋 ID - * @param classCounts 클래스별 카운트 - */ - public void updateClassCounts(Long datasetId, Map classCounts) { - DatasetEntity entity = - datasetRepository - .findById(datasetId) - .orElseThrow(() -> new NotFoundException("데이터셋을 찾을 수 없습니다. ID: " + datasetId)); - - try { - entity.setClassCounts(classCounts); - datasetRepository.save(entity); - log.info("데이터셋 클래스 통계 업데이트 완료: datasetId={}, classes={}", datasetId, classCounts.keySet()); - } catch (Exception e) { - log.error("클래스 통계 JSON 변환 실패: datasetId={}", datasetId, e); - } - } - - /** - * 파일 크기를 읽기 쉬운 형식으로 변환 - * - * @param size 바이트 단위 크기 - * @return 형식화된 문자열 (예: "1.5GB") - */ - private String formatFileSize(Long size) { - if (size == null || size == 0) { - return "0 GB"; - } - - double gb = size / (1024.0 * 1024.0 * 1024.0); - if (gb >= 1.0) { - return String.format("%.2f GB", gb); - } - - double mb = size / (1024.0 * 1024.0); - if (mb >= 1.0) { - return String.format("%.2f MB", mb); - } - - double kb = size / 1024.0; - return String.format("%.2f KB", kb); - } - public Page searchDatasetObjectList(SearchReq searchReq) { Page entityPage = datasetObjRepository.searchDatasetObjectList(searchReq); return entityPage.map(DatasetObjEntity::toDto); diff --git a/src/main/java/com/kamco/cd/training/postgres/core/ModelTrainMngCoreService.java b/src/main/java/com/kamco/cd/training/postgres/core/ModelTrainMngCoreService.java index 1f5f084..e16e488 100644 --- a/src/main/java/com/kamco/cd/training/postgres/core/ModelTrainMngCoreService.java +++ b/src/main/java/com/kamco/cd/training/postgres/core/ModelTrainMngCoreService.java @@ -6,7 +6,6 @@ import com.kamco.cd.training.common.exception.BadRequestException; import com.kamco.cd.training.common.exception.CustomApiException; import com.kamco.cd.training.common.exception.NotFoundException; import com.kamco.cd.training.common.utils.UserUtil; -import com.kamco.cd.training.model.dto.ModelMngDto; import com.kamco.cd.training.model.dto.ModelTrainMngDto; import com.kamco.cd.training.model.dto.ModelTrainMngDto.Basic; import com.kamco.cd.training.model.dto.ModelTrainMngDto.TrainingDataset; @@ -161,78 +160,6 @@ public class ModelTrainMngCoreService { return modelConfigRepository.save(entity).getId(); } - /** - * 모델 상세 조회 - * - * @param modelUid 모델 UID - * @return 모델 상세 정보 - */ - public ModelMngDto.Detail getModelDetail(Long modelUid) { - ModelMasterEntity entity = - modelMngRepository - .findById(modelUid) - .orElseThrow(() -> new NotFoundException("모델을 찾을 수 없습니다. ID: " + modelUid)); - - if (Boolean.TRUE.equals(entity.getDelYn())) { - throw new NotFoundException("삭제된 모델입니다. ID: " + modelUid); - } - - return null; - // ModelMngDto.Detail.builder() - // .uuid(entity.getUuid().toString()) - // .modelVer(entity.getModelVer()) - // .epochVer(entity.getEpochVer()) - // .processStep(entity.getProcessStep()) - // .trainStartDttm(entity.getTrainStartDttm()) - // .epochCnt(entity.getEpochCnt()) - // .datasetRatio(entity.getDatasetRatio()) - // .bestEpoch(entity.getBestEpoch()) - // .confirmedBestEpoch(entity.getConfirmedBestEpoch()) - // .step1EndDttm(entity.getStep1EndDttm()) - // .step1Duration(entity.getStep1Duration()) - // .step2EndDttm(entity.getStep2EndDttm()) - // .step2Duration(entity.getStep2Duration()) - // .progressRate(entity.getProgressRate()) - // .createdDttm(entity.getCreatedDttm()) - // .updatedDttm(entity.getUpdatedDttm()) - // .modelPath(entity.getModelPath()) - // .errorMsg(entity.getErrorMsg()) - // .build(); - } - - /** - * 현재 실행 중인 모델 확인 - * - * @return 실행 중인 모델 UUID (없으면 null) - */ - public String findRunningModelUuid() { - return modelMngRepository - .findFirstByStatusCdAndDelYn("RUNNING", false) - .map(entity -> entity.getUuid().toString()) - .orElse(null); - } - - /** - * 학습 마스터 생성 - * - * @param trainReq 학습 시작 요청 - * @return 생성된 모델 Entity - */ - public ModelMasterEntity createTrainMaster(ModelMngDto.TrainStartReq trainReq) { - // ModelMasterEntity entity = new ModelMasterEntity(); - // entity.setModelVer(trainReq.getHyperVer()); - // entity.setEpochVer(String.valueOf(trainReq.getEpoch())); - // entity.setProcessStep("STEP1"); - // entity.setTrainStartDttm(ZonedDateTime.now()); - // entity.setEpochCnt(trainReq.getEpoch()); - // entity.setDatasetRatio(trainReq.getDatasetRatio()); - // entity.setDelYn(false); - // entity.setCreatedDttm(ZonedDateTime.now()); - // entity.setProgressRate(0); - - return null; // modelMngRepository.save(entity); - } - /** * 데이터셋 매핑 생성 * From 200b384e1965ecb645c63e192e2d9fec146a6fb5 Mon Sep 17 00:00:00 2001 From: teddy Date: Wed, 4 Feb 2026 18:41:34 +0900 Subject: [PATCH 2/6] =?UTF-8?q?=EB=AA=A8=EB=8D=B8=20=EC=A2=85=EB=A5=98=20?= =?UTF-8?q?=EC=9D=B4=EB=A6=84=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/kamco/cd/training/common/enums/ModelType.java | 6 +++--- .../kamco/cd/training/dataset/DatasetApiController.java | 2 +- .../cd/training/dataset/service/DatasetService.java | 2 +- .../cd/training/model/ModelTrainMngApiController.java | 9 ++++++++- .../kamco/cd/training/model/dto/ModelTrainMngDto.java | 3 ++- .../cd/training/model/service/ModelTrainMngService.java | 1 - .../training/postgres/core/ModelTrainMngCoreService.java | 6 +++--- .../repository/model/ModelMngRepositoryImpl.java | 4 ++++ 8 files changed, 22 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/kamco/cd/training/common/enums/ModelType.java b/src/main/java/com/kamco/cd/training/common/enums/ModelType.java index b8e3292..8eb327d 100644 --- a/src/main/java/com/kamco/cd/training/common/enums/ModelType.java +++ b/src/main/java/com/kamco/cd/training/common/enums/ModelType.java @@ -9,9 +9,9 @@ import lombok.Getter; @Getter @AllArgsConstructor public enum ModelType implements EnumType { - M1("M1"), - M2("M2"), - M3("M3"); + G1("G1"), + G2("G2"), + G3("G3"); private String desc; diff --git a/src/main/java/com/kamco/cd/training/dataset/DatasetApiController.java b/src/main/java/com/kamco/cd/training/dataset/DatasetApiController.java index 41a4ec0..18f01c2 100644 --- a/src/main/java/com/kamco/cd/training/dataset/DatasetApiController.java +++ b/src/main/java/com/kamco/cd/training/dataset/DatasetApiController.java @@ -213,7 +213,7 @@ public class DatasetApiController { @Parameter( description = "모델 구분", example = "", - schema = @Schema(allowableValues = {"M1", "M2", "M3"})) + schema = @Schema(allowableValues = {"G1", "G2", "G3"})) @RequestParam String modelType, @Parameter( diff --git a/src/main/java/com/kamco/cd/training/dataset/service/DatasetService.java b/src/main/java/com/kamco/cd/training/dataset/service/DatasetService.java index 2e5e4a1..ed5ab75 100644 --- a/src/main/java/com/kamco/cd/training/dataset/service/DatasetService.java +++ b/src/main/java/com/kamco/cd/training/dataset/service/DatasetService.java @@ -97,7 +97,7 @@ public class DatasetService { } public List getDatasetSelectList(String modelType, String selectType) { - if (modelType.equals("M1")) { + if (modelType.equals("G1")) { return datasetCoreService.getDatasetSelectM1List(modelType, selectType); } else { return datasetCoreService.getDatasetSelectM2M3List(modelType, selectType); diff --git a/src/main/java/com/kamco/cd/training/model/ModelTrainMngApiController.java b/src/main/java/com/kamco/cd/training/model/ModelTrainMngApiController.java index ce685b0..ad73849 100644 --- a/src/main/java/com/kamco/cd/training/model/ModelTrainMngApiController.java +++ b/src/main/java/com/kamco/cd/training/model/ModelTrainMngApiController.java @@ -51,9 +51,16 @@ public class ModelTrainMngApiController { schema = @Schema(allowableValues = {"", "IN_PROGRESS", "COMPLETED"})) @RequestParam(required = false) String status, + @Parameter( + description = "모델", + example = "G1", + schema = @Schema(allowableValues = {"G1", "G2", "G3"})) + @RequestParam(required = false) + String modelNo, @Parameter(description = "페이지 번호") @RequestParam(defaultValue = "0") int page, @Parameter(description = "페이지 크기") @RequestParam(defaultValue = "20") int size) { - ModelTrainMngDto.SearchReq searchReq = new ModelTrainMngDto.SearchReq(status, page, size); + ModelTrainMngDto.SearchReq searchReq = + new ModelTrainMngDto.SearchReq(status, modelNo, page, size); return ApiResponseDto.ok(modelTrainMngService.getModelList(searchReq)); } diff --git a/src/main/java/com/kamco/cd/training/model/dto/ModelTrainMngDto.java b/src/main/java/com/kamco/cd/training/model/dto/ModelTrainMngDto.java index 4996f0d..cacbd40 100644 --- a/src/main/java/com/kamco/cd/training/model/dto/ModelTrainMngDto.java +++ b/src/main/java/com/kamco/cd/training/model/dto/ModelTrainMngDto.java @@ -107,6 +107,7 @@ public class ModelTrainMngDto { public static class SearchReq { private String status; + private String modelNo; // 페이징 파라미터 private int page = 0; private int size = 20; @@ -124,7 +125,7 @@ public class ModelTrainMngDto { public static class AddReq { @NotNull - @Schema(description = "모델 종류 M1, M2, M3", example = "M1") + @Schema(description = "모델 종류 G1, G2, G3", example = "G1") private String modelNo; @NotNull diff --git a/src/main/java/com/kamco/cd/training/model/service/ModelTrainMngService.java b/src/main/java/com/kamco/cd/training/model/service/ModelTrainMngService.java index b271f0d..c408a08 100644 --- a/src/main/java/com/kamco/cd/training/model/service/ModelTrainMngService.java +++ b/src/main/java/com/kamco/cd/training/model/service/ModelTrainMngService.java @@ -53,7 +53,6 @@ public class ModelTrainMngService { HyperParam hyperParam = req.getHyperParam(); HyperParamDto.Basic hyper = new HyperParamDto.Basic(); - /** OPTIMIZED(최적화 파라미터), EXISTING(기존 파라미터), NEW(신규 파라미터) * */ if (HyperParamSelectType.NEW.getId().equals(req.getHyperParamType())) { // 하이퍼파라미터 등록 hyper = hyperParamCoreService.createHyperParam(hyperParam); diff --git a/src/main/java/com/kamco/cd/training/postgres/core/ModelTrainMngCoreService.java b/src/main/java/com/kamco/cd/training/postgres/core/ModelTrainMngCoreService.java index e16e488..45d0e3b 100644 --- a/src/main/java/com/kamco/cd/training/postgres/core/ModelTrainMngCoreService.java +++ b/src/main/java/com/kamco/cd/training/postgres/core/ModelTrainMngCoreService.java @@ -108,12 +108,12 @@ public class ModelTrainMngCoreService { modelMasterEntity.setId(modelId); datasetEntity.setModel(modelMasterEntity); - if (addReq.getModelNo().equals(ModelType.M1.getId())) { + if (addReq.getModelNo().equals(ModelType.G1.getId())) { datasetEntity.setBuildingCnt(dataset.getSummary().getBuildingCnt()); datasetEntity.setContainerCnt(dataset.getSummary().getContainerCnt()); - } else if (addReq.getModelNo().equals(ModelType.M2.getId())) { + } else if (addReq.getModelNo().equals(ModelType.G2.getId())) { datasetEntity.setWasteCnt(dataset.getSummary().getWasteCnt()); - } else if (addReq.getModelNo().equals(ModelType.M3.getId())) { + } else if (addReq.getModelNo().equals(ModelType.G3.getId())) { datasetEntity.setLandCoverCnt(dataset.getSummary().getLandCoverCnt()); } 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 70fabb7..12297e8 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 @@ -36,6 +36,10 @@ public class ModelMngRepositoryImpl implements ModelMngRepositoryCustom { builder.and(modelMasterEntity.statusCd.eq(req.getStatus())); } + if (req.getModelNo() != null && !req.getModelNo().isEmpty()) { + builder.and(modelMasterEntity.modelNo.eq(req.getModelNo())); + } + List content = queryFactory .selectFrom(modelMasterEntity) From ce69bacb01d7466a2f08e2f288573593266a41f1 Mon Sep 17 00:00:00 2001 From: teddy Date: Wed, 4 Feb 2026 19:15:10 +0900 Subject: [PATCH 3/6] =?UTF-8?q?=EB=AA=A8=EB=8D=B8=ED=95=99=EC=8A=B5=20?= =?UTF-8?q?=EB=8D=B0=EC=9D=B4=ED=84=B0=20=EB=93=B1=EB=A1=9D=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../training/config/api/ApiResponseDto.java | 1 + .../hyperparam/HyperParamApiController.java | 3 +- .../model/ModelTrainMngApiController.java | 3 +- .../model/service/ModelTrainMngService.java | 1 + .../postgres/core/HyperParamCoreService.java | 5 +++- .../core/ModelTrainMngCoreService.java | 28 +++++++++++++++---- .../postgres/entity/ModelMasterEntity.java | 4 +-- .../hyperparam/HyperParamRepository.java | 5 +++- 8 files changed, 38 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/kamco/cd/training/config/api/ApiResponseDto.java b/src/main/java/com/kamco/cd/training/config/api/ApiResponseDto.java index 886031c..5beef94 100644 --- a/src/main/java/com/kamco/cd/training/config/api/ApiResponseDto.java +++ b/src/main/java/com/kamco/cd/training/config/api/ApiResponseDto.java @@ -164,6 +164,7 @@ public class ApiResponseDto { NOT_FOUND_USER_FOR_EMAIL("이메일로 유저를 찾을 수 없습니다."), NOT_FOUND_USER("사용자를 찾을 수 없습니다."), UNPROCESSABLE_ENTITY("이 데이터는 삭제할 수 없습니다."), + UNPROCESSABLE_ENTITY_UPDATE("이 데이터는 수정할 수 없습니다."), LOGIN_ID_NOT_FOUND("아이디를 잘못 입력하셨습니다."), LOGIN_PASSWORD_MISMATCH("비밀번호를 잘못 입력하셨습니다."), LOGIN_PASSWORD_EXCEEDED("비밀번호 오류 횟수를 초과하여 이용하실 수 없습니다.\n로그인 오류에 대해 관리자에게 문의하시기 바랍니다."), diff --git a/src/main/java/com/kamco/cd/training/hyperparam/HyperParamApiController.java b/src/main/java/com/kamco/cd/training/hyperparam/HyperParamApiController.java index 60ff8d2..964ba74 100644 --- a/src/main/java/com/kamco/cd/training/hyperparam/HyperParamApiController.java +++ b/src/main/java/com/kamco/cd/training/hyperparam/HyperParamApiController.java @@ -65,6 +65,7 @@ public class HyperParamApiController { mediaType = "application/json", schema = @Schema(implementation = String.class))), @ApiResponse(responseCode = "400", description = "잘못된 요청", content = @Content), + @ApiResponse(responseCode = "422", description = "HPs_0001 수정 불가", content = @Content), @ApiResponse(responseCode = "500", description = "서버 오류", content = @Content) }) @PutMapping("/{uuid}") @@ -132,7 +133,7 @@ public class HyperParamApiController { @ApiResponses( value = { @ApiResponse(responseCode = "200", description = "삭제 성공", content = @Content), - @ApiResponse(responseCode = "409", description = "HPs_0001 삭제 불가", content = @Content), + @ApiResponse(responseCode = "422", description = "HPs_0001 삭제 불가", content = @Content), @ApiResponse(responseCode = "404", description = "하이퍼파라미터를 찾을 수 없음", content = @Content), }) @DeleteMapping("/{uuid}") diff --git a/src/main/java/com/kamco/cd/training/model/ModelTrainMngApiController.java b/src/main/java/com/kamco/cd/training/model/ModelTrainMngApiController.java index ad73849..c306895 100644 --- a/src/main/java/com/kamco/cd/training/model/ModelTrainMngApiController.java +++ b/src/main/java/com/kamco/cd/training/model/ModelTrainMngApiController.java @@ -11,6 +11,7 @@ import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; import java.util.UUID; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Page; @@ -86,7 +87,7 @@ public class ModelTrainMngApiController { @ApiResponse(responseCode = "500", description = "서버 오류", content = @Content) }) @PostMapping - public ApiResponseDto createModelTrain(@RequestBody ModelTrainMngDto.AddReq req) { + public ApiResponseDto createModelTrain(@Valid @RequestBody ModelTrainMngDto.AddReq req) { modelTrainMngService.createModelTrain(req); return ApiResponseDto.ok("ok"); } diff --git a/src/main/java/com/kamco/cd/training/model/service/ModelTrainMngService.java b/src/main/java/com/kamco/cd/training/model/service/ModelTrainMngService.java index c408a08..2c19c4d 100644 --- a/src/main/java/com/kamco/cd/training/model/service/ModelTrainMngService.java +++ b/src/main/java/com/kamco/cd/training/model/service/ModelTrainMngService.java @@ -53,6 +53,7 @@ public class ModelTrainMngService { HyperParam hyperParam = req.getHyperParam(); HyperParamDto.Basic hyper = new HyperParamDto.Basic(); + // 하이파라미터 신규저장 if (HyperParamSelectType.NEW.getId().equals(req.getHyperParamType())) { // 하이퍼파라미터 등록 hyper = hyperParamCoreService.createHyperParam(hyperParam); diff --git a/src/main/java/com/kamco/cd/training/postgres/core/HyperParamCoreService.java b/src/main/java/com/kamco/cd/training/postgres/core/HyperParamCoreService.java index d3b1f4b..853eec7 100644 --- a/src/main/java/com/kamco/cd/training/postgres/core/HyperParamCoreService.java +++ b/src/main/java/com/kamco/cd/training/postgres/core/HyperParamCoreService.java @@ -57,6 +57,9 @@ public class HyperParamCoreService { .findHyperParamByUuid(uuid) .orElseThrow(() -> new CustomApiException("NOT_FOUND_DATA", HttpStatus.NOT_FOUND)); + if (entity.getHyperVer().equals("HPs_0001")) { + throw new CustomApiException("UNPROCESSABLE_ENTITY_UPDATE", HttpStatus.UNPROCESSABLE_ENTITY); + } applyHyperParam(entity, createReq); // user @@ -120,7 +123,7 @@ public class HyperParamCoreService { .orElseThrow(() -> new CustomApiException("NOT_FOUND_DATA", HttpStatus.NOT_FOUND)); if (entity.getHyperVer().equals("HPs_0001")) { - throw new CustomApiException("CONFLICT", HttpStatus.CONFLICT, "HPs_0001 버전은 삭제할수 없습니다."); + throw new CustomApiException("UNPROCESSABLE_ENTITY", HttpStatus.UNPROCESSABLE_ENTITY); } entity.setDelYn(true); diff --git a/src/main/java/com/kamco/cd/training/postgres/core/ModelTrainMngCoreService.java b/src/main/java/com/kamco/cd/training/postgres/core/ModelTrainMngCoreService.java index 45d0e3b..7bab856 100644 --- a/src/main/java/com/kamco/cd/training/postgres/core/ModelTrainMngCoreService.java +++ b/src/main/java/com/kamco/cd/training/postgres/core/ModelTrainMngCoreService.java @@ -1,5 +1,6 @@ package com.kamco.cd.training.postgres.core; +import com.kamco.cd.training.common.enums.HyperParamSelectType; import com.kamco.cd.training.common.enums.ModelType; import com.kamco.cd.training.common.enums.TrainStatusType; import com.kamco.cd.training.common.exception.BadRequestException; @@ -71,22 +72,37 @@ public class ModelTrainMngCoreService { */ public Long saveModel(ModelTrainMngDto.AddReq addReq) { ModelMasterEntity entity = new ModelMasterEntity(); - ModelHyperParamEntity hyperParamEntity = - hyperParamRepository.findHyperParamByUuid(addReq.getHyperUuid()).orElse(null); + ModelHyperParamEntity hyperParamEntity = new ModelHyperParamEntity(); - entity.setModelNo(addReq.getModelNo()); - entity.setTrainType(addReq.getTrainType()); + // 최적화 파라미터는 HPs_0001 사용 + if (HyperParamSelectType.OPTIMIZED.getId().equals(addReq.getHyperParamType())) { + hyperParamEntity = hyperParamRepository.findByHyperVer("HPs_0001").orElse(null); - if (hyperParamEntity != null) { - entity.setHyperParamId(hyperParamEntity.getId()); + } else { + hyperParamEntity = + hyperParamRepository.findHyperParamByUuid(addReq.getHyperUuid()).orElse(null); } + if (hyperParamEntity == null || hyperParamEntity.getHyperVer() == null) { + throw new CustomApiException("NOT_FOUND_DATA", HttpStatus.NOT_FOUND); + } + + String modelVer = + String.join( + ".", addReq.getModelNo(), hyperParamEntity.getHyperVer(), entity.getUuid().toString()); + entity.setModelVer(modelVer); + entity.setHyperParamId(hyperParamEntity.getId()); + entity.setModelNo(addReq.getModelNo()); + entity.setTrainType(addReq.getTrainType()); // 일반, 전이 + if (addReq.getIsStart()) { entity.setModelStep((short) 1); entity.setStatusCd(TrainStatusType.IN_PROGRESS.getId()); entity.setStrtDttm(ZonedDateTime.now()); entity.setStep1StrtDttm(ZonedDateTime.now()); entity.setStep1State(TrainStatusType.IN_PROGRESS.getId()); + } else { + entity.setStatusCd(TrainStatusType.READY.getId()); } entity.setCreatedUid(userUtil.getId()); diff --git a/src/main/java/com/kamco/cd/training/postgres/entity/ModelMasterEntity.java b/src/main/java/com/kamco/cd/training/postgres/entity/ModelMasterEntity.java index 1e9dee4..9497cce 100644 --- a/src/main/java/com/kamco/cd/training/postgres/entity/ModelMasterEntity.java +++ b/src/main/java/com/kamco/cd/training/postgres/entity/ModelMasterEntity.java @@ -32,8 +32,8 @@ public class ModelMasterEntity { @Column(name = "model_no", length = 10) private String modelNo; - @Size(max = 50) - @Column(name = "model_ver", length = 50) + @Size(max = 200) + @Column(name = "model_ver", length = 200) private String modelVer; @Column(name = "model_step") diff --git a/src/main/java/com/kamco/cd/training/postgres/repository/hyperparam/HyperParamRepository.java b/src/main/java/com/kamco/cd/training/postgres/repository/hyperparam/HyperParamRepository.java index 529bc81..6e1d5e1 100644 --- a/src/main/java/com/kamco/cd/training/postgres/repository/hyperparam/HyperParamRepository.java +++ b/src/main/java/com/kamco/cd/training/postgres/repository/hyperparam/HyperParamRepository.java @@ -1,9 +1,12 @@ package com.kamco.cd.training.postgres.repository.hyperparam; import com.kamco.cd.training.postgres.entity.ModelHyperParamEntity; +import java.util.Optional; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; @Repository public interface HyperParamRepository - extends JpaRepository, HyperParamRepositoryCustom {} + extends JpaRepository, HyperParamRepositoryCustom { + Optional findByHyperVer(String hyperVer); +} From b2be43a76eefa75ee539924650ffcdbb11646b4d Mon Sep 17 00:00:00 2001 From: "gayoun.park" Date: Wed, 4 Feb 2026 19:46:57 +0900 Subject: [PATCH 4/6] =?UTF-8?q?=EB=AA=A8=EB=8D=B8=20=EC=83=81=EC=84=B8=20A?= =?UTF-8?q?PI=20=EC=BB=A4=EB=B0=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../model/ModelTrainDetailApiController.java | 43 ++++++ .../model/dto/ModelTrainDetailDto.java | 144 ++++++++++++++++++ .../service/ModelTrainDetailService.java | 45 ++++++ .../core/ModelTrainDetailCoreService.java | 56 +++++++ .../model/ModelDetailRepository.java | 7 + .../model/ModelDetailRepositoryCustom.java | 20 +++ .../model/ModelDetailRepositoryImpl.java | 109 +++++++++++++ 7 files changed, 424 insertions(+) create mode 100644 src/main/java/com/kamco/cd/training/model/ModelTrainDetailApiController.java create mode 100644 src/main/java/com/kamco/cd/training/model/dto/ModelTrainDetailDto.java create mode 100644 src/main/java/com/kamco/cd/training/model/service/ModelTrainDetailService.java create mode 100644 src/main/java/com/kamco/cd/training/postgres/core/ModelTrainDetailCoreService.java create mode 100644 src/main/java/com/kamco/cd/training/postgres/repository/model/ModelDetailRepository.java create mode 100644 src/main/java/com/kamco/cd/training/postgres/repository/model/ModelDetailRepositoryCustom.java create mode 100644 src/main/java/com/kamco/cd/training/postgres/repository/model/ModelDetailRepositoryImpl.java diff --git a/src/main/java/com/kamco/cd/training/model/ModelTrainDetailApiController.java b/src/main/java/com/kamco/cd/training/model/ModelTrainDetailApiController.java new file mode 100644 index 0000000..6ee176f --- /dev/null +++ b/src/main/java/com/kamco/cd/training/model/ModelTrainDetailApiController.java @@ -0,0 +1,43 @@ +package com.kamco.cd.training.model; + +import com.kamco.cd.training.config.api.ApiResponseDto; +import com.kamco.cd.training.model.dto.ModelTrainDetailDto; +import com.kamco.cd.training.model.dto.ModelTrainDetailDto.MappingDataset; +import com.kamco.cd.training.model.service.ModelTrainDetailService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import java.util.List; +import java.util.UUID; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequiredArgsConstructor +@Tag(name = "모델학습 관리", description = "어드민 홈 > 모델학습관리 > 모델관리 > 목록") +@RequestMapping("/api/models") +public class ModelTrainDetailApiController { + private final ModelTrainDetailService modelTrainDetailService; + + @Operation(summary = "모델학습 상세 요약 정보", description = "모델학습 상세 요약 정보 API") + @GetMapping("/summary/{uuid}") + public ApiResponseDto getModelDetailSummary( + @PathVariable UUID uuid) { + return ApiResponseDto.ok(modelTrainDetailService.getModelDetailSummary(uuid)); + } + + @Operation(summary = "모델학습 상세 > 하이퍼파라미터 요약 정보", description = "모델학습 상세 하이퍼파라미터 요약 정보 API") + @GetMapping("/hyper-summary/{uuid}") + public ApiResponseDto getByModelHyperParamSummary( + @PathVariable UUID uuid) { + return ApiResponseDto.ok(modelTrainDetailService.getByModelHyperParamSummary(uuid)); + } + + @Operation(summary = "모델학습 상세 > 데이터셋 정보", description = "모델학습 상세 데이터셋 정보 API") + @GetMapping("/mapp-dataset/{uuid}") + public ApiResponseDto> getByModelMappingDataset(@PathVariable UUID uuid) { + return ApiResponseDto.ok(modelTrainDetailService.getByModelMappingDataset(uuid)); + } +} diff --git a/src/main/java/com/kamco/cd/training/model/dto/ModelTrainDetailDto.java b/src/main/java/com/kamco/cd/training/model/dto/ModelTrainDetailDto.java new file mode 100644 index 0000000..2f7b93a --- /dev/null +++ b/src/main/java/com/kamco/cd/training/model/dto/ModelTrainDetailDto.java @@ -0,0 +1,144 @@ +package com.kamco.cd.training.model.dto; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.kamco.cd.training.common.enums.LearnDataType; +import com.kamco.cd.training.common.enums.TrainStatusType; +import com.kamco.cd.training.common.enums.TrainType; +import com.kamco.cd.training.common.utils.enums.Enums; +import com.kamco.cd.training.common.utils.interfaces.JsonFormatDttm; +import io.swagger.v3.oas.annotations.media.Schema; +import java.time.Duration; +import java.time.ZonedDateTime; +import java.util.UUID; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +public class ModelTrainDetailDto { + @Schema(name = "모델학습관리 목록", description = "모델학습관리 목록") + @Getter + @Setter + @NoArgsConstructor + @AllArgsConstructor + @Builder + public static class DetailSummary { + + private Long modelId; + private UUID uuid; + private String modelNo; + private String modelVer; + @JsonFormatDttm private ZonedDateTime step1StrtDttm; + @JsonFormatDttm private ZonedDateTime step2EndDttm; + private String statusCd; + private String trainType; + + public String getStatusName() { + if (this.statusCd == null || this.statusCd.isBlank()) return null; + try { + return TrainStatusType.valueOf(this.statusCd).getText(); // 또는 getName() + } catch (IllegalArgumentException e) { + return this.statusCd; // 매핑 못하면 코드 그대로 반환(원하면 null 처리) + } + } + + public String getTrainTypeName() { + if (this.trainType == null || this.trainType.isBlank()) return null; + try { + return TrainType.valueOf(this.trainType).getText(); // 또는 getName() + } catch (IllegalArgumentException e) { + return this.trainType; // 매핑 못하면 코드 그대로 반환(원하면 null 처리) + } + } + + private String formatDuration(ZonedDateTime start, ZonedDateTime end) { + if (end == null) { + end = ZonedDateTime.now(); + } + + if (start == null) { + return null; + } + + long totalSeconds = Math.abs(Duration.between(start, end).getSeconds()); + + long hours = totalSeconds / 3600; + long minutes = (totalSeconds % 3600) / 60; + long seconds = totalSeconds % 60; + + return String.format("%d시간 %d분 %d초", hours, minutes, seconds); + } + + public String getStepAllDuration() { + return formatDuration(this.step1StrtDttm, this.step2EndDttm); + } + } + + @Schema(name = "모델학습관리 목록", description = "모델학습관리 목록") + @Getter + @Setter + @NoArgsConstructor + @AllArgsConstructor + @Builder + public static class HyperSummary { + private UUID uuid; + private Long hyperParamId; + private String hyperVer; + private String backbone; + private String inputSize; + private Integer batchSize; + } + + @Schema(name = "선택한 데이터셋 목록", description = "선택한 데이터셋 목록") + @Getter + @Setter + @NoArgsConstructor + public static class MappingDataset { + private Long modelId; + private String dataType; + private Integer compareYyyy; + private Integer targetYyyy; + private Long roundNo; + private String dataTypeName; + + @JsonInclude(JsonInclude.Include.NON_NULL) + private Long buildingCnt; + + @JsonInclude(JsonInclude.Include.NON_NULL) + private Long containerCnt; + + @JsonInclude(JsonInclude.Include.NON_NULL) + private Long wasteCnt; + + @JsonInclude(JsonInclude.Include.NON_NULL) + private Long landCoverCnt; + + public MappingDataset( + Long modelId, + String dataType, + Integer compareYyyy, + Integer targetYyyy, + Long roundNo, + Long buildingCnt, + Long containerCnt, + Long wasteCnt, + Long landCoverCnt) { + this.modelId = modelId; + this.dataType = dataType; + this.compareYyyy = compareYyyy; + this.targetYyyy = targetYyyy; + this.roundNo = roundNo; + this.buildingCnt = buildingCnt; + this.containerCnt = containerCnt; + this.wasteCnt = wasteCnt; + this.landCoverCnt = landCoverCnt; + this.dataTypeName = getDataTypeName(this.dataType); + } + + public String getDataTypeName(String groupTitleCd) { + LearnDataType type = Enums.fromId(LearnDataType.class, groupTitleCd); + return type == null ? null : type.getText(); + } + } +} diff --git a/src/main/java/com/kamco/cd/training/model/service/ModelTrainDetailService.java b/src/main/java/com/kamco/cd/training/model/service/ModelTrainDetailService.java new file mode 100644 index 0000000..d2cc297 --- /dev/null +++ b/src/main/java/com/kamco/cd/training/model/service/ModelTrainDetailService.java @@ -0,0 +1,45 @@ +package com.kamco.cd.training.model.service; + +import com.kamco.cd.training.model.dto.ModelTrainDetailDto.DetailSummary; +import com.kamco.cd.training.model.dto.ModelTrainDetailDto.HyperSummary; +import com.kamco.cd.training.model.dto.ModelTrainDetailDto.MappingDataset; +import com.kamco.cd.training.postgres.core.ModelTrainDetailCoreService; +import java.util.List; +import java.util.UUID; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@RequiredArgsConstructor +@Transactional(readOnly = true) +@Slf4j +public class ModelTrainDetailService { + + private final ModelTrainDetailCoreService modelTrainDetailCoreService; + + /** + * 모델 상세정보 요약 + * + * @param uuid + * @return + */ + public DetailSummary getModelDetailSummary(UUID uuid) { + return modelTrainDetailCoreService.getModelDetailSummary(uuid); + } + + /** + * 모델 하이퍼파라미터 요약 + * + * @param uuid + * @return + */ + public HyperSummary getByModelHyperParamSummary(UUID uuid) { + return modelTrainDetailCoreService.getByModelHyperParamSummary(uuid); + } + + public List getByModelMappingDataset(UUID uuid) { + return modelTrainDetailCoreService.getByModelMappingDataset(uuid); + } +} diff --git a/src/main/java/com/kamco/cd/training/postgres/core/ModelTrainDetailCoreService.java b/src/main/java/com/kamco/cd/training/postgres/core/ModelTrainDetailCoreService.java new file mode 100644 index 0000000..dc7fce4 --- /dev/null +++ b/src/main/java/com/kamco/cd/training/postgres/core/ModelTrainDetailCoreService.java @@ -0,0 +1,56 @@ +package com.kamco.cd.training.postgres.core; + +import com.kamco.cd.training.common.exception.BadRequestException; +import com.kamco.cd.training.common.exception.NotFoundException; +import com.kamco.cd.training.common.utils.UserUtil; +import com.kamco.cd.training.model.dto.ModelTrainDetailDto.DetailSummary; +import com.kamco.cd.training.model.dto.ModelTrainDetailDto.HyperSummary; +import com.kamco.cd.training.model.dto.ModelTrainDetailDto.MappingDataset; +import com.kamco.cd.training.postgres.entity.ModelMasterEntity; +import com.kamco.cd.training.postgres.repository.model.ModelDetailRepository; +import java.util.List; +import java.util.UUID; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor +public class ModelTrainDetailCoreService { + private final ModelDetailRepository modelDetailRepository; + private final UserUtil userUtil; + + /** + * UUID로 모델 조회 + * + * @param uuid UUID + * @return 모델 Entity + */ + public ModelMasterEntity findByUuid(String uuid) { + try { + UUID uuidObj = UUID.fromString(uuid); + return modelDetailRepository + .findByUuid(uuidObj) + .orElseThrow(() -> new NotFoundException("모델을 찾을 수 없습니다. UUID: " + uuid)); + } catch (IllegalArgumentException e) { + throw new BadRequestException("잘못된 UUID 형식입니다: " + uuid); + } + } + + /** + * 상세정보 페이지 > 요약정보 + * + * @param uuid + * @return + */ + public DetailSummary getModelDetailSummary(UUID uuid) { + return modelDetailRepository.getModelDetailSummary(uuid); + } + + public HyperSummary getByModelHyperParamSummary(UUID uuid) { + return modelDetailRepository.getByModelHyperParamSummary(uuid); + } + + public List getByModelMappingDataset(UUID uuid) { + return modelDetailRepository.getByModelMappingDataset(uuid); + } +} diff --git a/src/main/java/com/kamco/cd/training/postgres/repository/model/ModelDetailRepository.java b/src/main/java/com/kamco/cd/training/postgres/repository/model/ModelDetailRepository.java new file mode 100644 index 0000000..631c9f9 --- /dev/null +++ b/src/main/java/com/kamco/cd/training/postgres/repository/model/ModelDetailRepository.java @@ -0,0 +1,7 @@ +package com.kamco.cd.training.postgres.repository.model; + +import com.kamco.cd.training.postgres.entity.ModelMasterEntity; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface ModelDetailRepository + extends JpaRepository, ModelDetailRepositoryCustom {} diff --git a/src/main/java/com/kamco/cd/training/postgres/repository/model/ModelDetailRepositoryCustom.java b/src/main/java/com/kamco/cd/training/postgres/repository/model/ModelDetailRepositoryCustom.java new file mode 100644 index 0000000..49e43ca --- /dev/null +++ b/src/main/java/com/kamco/cd/training/postgres/repository/model/ModelDetailRepositoryCustom.java @@ -0,0 +1,20 @@ +package com.kamco.cd.training.postgres.repository.model; + +import com.kamco.cd.training.model.dto.ModelTrainDetailDto.DetailSummary; +import com.kamco.cd.training.model.dto.ModelTrainDetailDto.HyperSummary; +import com.kamco.cd.training.model.dto.ModelTrainDetailDto.MappingDataset; +import com.kamco.cd.training.postgres.entity.ModelMasterEntity; +import java.util.List; +import java.util.Optional; +import java.util.UUID; + +public interface ModelDetailRepositoryCustom { + + Optional findByUuid(UUID uuid); + + DetailSummary getModelDetailSummary(UUID uuid); + + HyperSummary getByModelHyperParamSummary(UUID uuid); + + List getByModelMappingDataset(UUID uuid); +} diff --git a/src/main/java/com/kamco/cd/training/postgres/repository/model/ModelDetailRepositoryImpl.java b/src/main/java/com/kamco/cd/training/postgres/repository/model/ModelDetailRepositoryImpl.java new file mode 100644 index 0000000..3e41fce --- /dev/null +++ b/src/main/java/com/kamco/cd/training/postgres/repository/model/ModelDetailRepositoryImpl.java @@ -0,0 +1,109 @@ +package com.kamco.cd.training.postgres.repository.model; + +import static com.kamco.cd.training.postgres.entity.QDatasetEntity.datasetEntity; +import static com.kamco.cd.training.postgres.entity.QModelDatasetEntity.modelDatasetEntity; +import static com.kamco.cd.training.postgres.entity.QModelDatasetMappEntity.modelDatasetMappEntity; +import static com.kamco.cd.training.postgres.entity.QModelHyperParamEntity.modelHyperParamEntity; +import static com.kamco.cd.training.postgres.entity.QModelMasterEntity.modelMasterEntity; + +import com.kamco.cd.training.model.dto.ModelTrainDetailDto.DetailSummary; +import com.kamco.cd.training.model.dto.ModelTrainDetailDto.HyperSummary; +import com.kamco.cd.training.model.dto.ModelTrainDetailDto.MappingDataset; +import com.kamco.cd.training.postgres.entity.ModelMasterEntity; +import com.querydsl.core.types.Projections; +import com.querydsl.jpa.JPAExpressions; +import com.querydsl.jpa.impl.JPAQueryFactory; +import java.util.List; +import java.util.Optional; +import java.util.UUID; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Repository; + +@Repository +@RequiredArgsConstructor +public class ModelDetailRepositoryImpl implements ModelDetailRepositoryCustom { + + private final JPAQueryFactory queryFactory; + + /** + * 모델 조회 + * + * @param uuid + * @return + */ + @Override + public Optional findByUuid(UUID uuid) { + return Optional.ofNullable( + queryFactory + .select(modelMasterEntity) + .from(modelMasterEntity) + .where(modelMasterEntity.uuid.eq(uuid)) + .fetchOne()); + } + + @Override + public DetailSummary getModelDetailSummary(UUID uuid) { + return queryFactory + .select( + Projections.constructor( + DetailSummary.class, + modelMasterEntity.id, + modelMasterEntity.uuid, + modelMasterEntity.modelNo, + modelMasterEntity.modelVer, + modelMasterEntity.step1StrtDttm, + modelMasterEntity.step2EndDttm, + modelMasterEntity.statusCd, + modelMasterEntity.trainType)) + .from(modelMasterEntity) + .where(modelMasterEntity.uuid.eq(uuid)) + .fetchOne(); + } + + @Override + public HyperSummary getByModelHyperParamSummary(UUID uuid) { + return queryFactory + .select( + Projections.constructor( + HyperSummary.class, + modelHyperParamEntity.uuid, + modelHyperParamEntity.id, + modelHyperParamEntity.hyperVer, + modelHyperParamEntity.backbone, + modelHyperParamEntity.inputSize, + modelHyperParamEntity.batchSize)) + .from(modelHyperParamEntity) + .where( + modelHyperParamEntity.id.eq( + JPAExpressions.select(modelMasterEntity.hyperParamId) + .from(modelMasterEntity) + .where(modelMasterEntity.uuid.eq(uuid)))) + .fetchOne(); + } + + @Override + public List getByModelMappingDataset(UUID uuid) { + return queryFactory + .select( + Projections.constructor( + MappingDataset.class, + modelMasterEntity.id, + datasetEntity.dataType, + datasetEntity.compareYyyy, + datasetEntity.targetYyyy, + datasetEntity.roundNo, + modelDatasetEntity.buildingCnt, + modelDatasetEntity.containerCnt, + modelDatasetEntity.wasteCnt, + modelDatasetEntity.landCoverCnt)) + .from(modelMasterEntity) + .innerJoin(modelDatasetEntity) + .on(modelMasterEntity.id.eq(modelDatasetEntity.model.id)) + .innerJoin(modelDatasetMappEntity) + .on(modelMasterEntity.id.eq(modelDatasetMappEntity.modelUid)) + .innerJoin(datasetEntity) + .on(modelDatasetMappEntity.datasetUid.eq(datasetEntity.id)) + .where(modelMasterEntity.uuid.eq(uuid)) + .fetch(); + } +} From 474a3c119eeec127f434aa8997238c5d24e219fe Mon Sep 17 00:00:00 2001 From: teddy Date: Wed, 4 Feb 2026 19:51:43 +0900 Subject: [PATCH 5/6] =?UTF-8?q?=EB=AA=A8=EB=8D=B8=ED=95=99=EC=8A=B5=20conf?= =?UTF-8?q?ig=20=EC=A0=95=EB=B3=B4=20=EC=A1=B0=ED=9A=8C=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../model/ModelTrainMngApiController.java | 19 ++++++++++ .../cd/training/model/dto/ModelConfigDto.java | 23 ++++++++++++ .../model/service/ModelTrainMngService.java | 12 ++++++ .../core/ModelTrainMngCoreService.java | 26 +++++++++---- .../model/ModelConfigRepository.java | 3 +- .../model/ModelConfigRepositoryCustom.java | 8 ++++ .../model/ModelConfigRepositoryImpl.java | 37 +++++++++++++++++++ 7 files changed, 120 insertions(+), 8 deletions(-) create mode 100644 src/main/java/com/kamco/cd/training/model/dto/ModelConfigDto.java create mode 100644 src/main/java/com/kamco/cd/training/postgres/repository/model/ModelConfigRepositoryCustom.java create mode 100644 src/main/java/com/kamco/cd/training/postgres/repository/model/ModelConfigRepositoryImpl.java diff --git a/src/main/java/com/kamco/cd/training/model/ModelTrainMngApiController.java b/src/main/java/com/kamco/cd/training/model/ModelTrainMngApiController.java index c306895..7f190e2 100644 --- a/src/main/java/com/kamco/cd/training/model/ModelTrainMngApiController.java +++ b/src/main/java/com/kamco/cd/training/model/ModelTrainMngApiController.java @@ -1,6 +1,7 @@ package com.kamco.cd.training.model; import com.kamco.cd.training.config.api.ApiResponseDto; +import com.kamco.cd.training.model.dto.ModelConfigDto; import com.kamco.cd.training.model.dto.ModelTrainMngDto; import com.kamco.cd.training.model.dto.ModelTrainMngDto.Basic; import com.kamco.cd.training.model.service.ModelTrainMngService; @@ -91,4 +92,22 @@ public class ModelTrainMngApiController { modelTrainMngService.createModelTrain(req); return ApiResponseDto.ok("ok"); } + + @Operation(summary = "모델학습 config 정보 조회", description = "모델학습 config 정보 조회 API") + @ApiResponses( + value = { + @ApiResponse( + responseCode = "200", + description = "검색 성공", + content = + @Content( + mediaType = "application/json", + schema = @Schema(implementation = ModelConfigDto.Basic.class))), + @ApiResponse(responseCode = "400", description = "잘못된 검색 조건", content = @Content), + @ApiResponse(responseCode = "500", description = "서버 오류", content = @Content) + }) + @GetMapping("/config/{uuid}") + public ApiResponseDto updateModelTrain(@PathVariable UUID uuid) { + return ApiResponseDto.ok(modelTrainMngService.getModelConfigByModelId(uuid)); + } } diff --git a/src/main/java/com/kamco/cd/training/model/dto/ModelConfigDto.java b/src/main/java/com/kamco/cd/training/model/dto/ModelConfigDto.java new file mode 100644 index 0000000..9d6a651 --- /dev/null +++ b/src/main/java/com/kamco/cd/training/model/dto/ModelConfigDto.java @@ -0,0 +1,23 @@ +package com.kamco.cd.training.model.dto; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +public class ModelConfigDto { + + @Getter + @Setter + @NoArgsConstructor + @AllArgsConstructor + public static class Basic { + private Long configId; + private Long modelId; + private Integer epochCount; + private Float trainPercent; + private Float validationPercent; + private Float testPercent; + private String memo; + } +} diff --git a/src/main/java/com/kamco/cd/training/model/service/ModelTrainMngService.java b/src/main/java/com/kamco/cd/training/model/service/ModelTrainMngService.java index 2c19c4d..65d4b7e 100644 --- a/src/main/java/com/kamco/cd/training/model/service/ModelTrainMngService.java +++ b/src/main/java/com/kamco/cd/training/model/service/ModelTrainMngService.java @@ -3,6 +3,7 @@ package com.kamco.cd.training.model.service; import com.kamco.cd.training.common.dto.HyperParam; import com.kamco.cd.training.common.enums.HyperParamSelectType; import com.kamco.cd.training.hyperparam.dto.HyperParamDto; +import com.kamco.cd.training.model.dto.ModelConfigDto; import com.kamco.cd.training.model.dto.ModelTrainMngDto; import com.kamco.cd.training.model.dto.ModelTrainMngDto.SearchReq; import com.kamco.cd.training.postgres.core.HyperParamCoreService; @@ -38,6 +39,7 @@ public class ModelTrainMngService { * * @param uuid */ + @Transactional public void deleteModelTrain(UUID uuid) { modelTrainMngCoreService.deleteModel(uuid); } @@ -73,4 +75,14 @@ public class ModelTrainMngService { // 모델 config 저장 modelTrainMngCoreService.saveModelConfig(modelId, req.getModelConfig()); } + + /** + * 모델학습 모델학습 uuid config정보 조회 + * + * @param uuid 모델학습 uuid + * @return + */ + public ModelConfigDto.Basic getModelConfigByModelId(UUID uuid) { + return modelTrainMngCoreService.findModelConfigByModelId(uuid); + } } diff --git a/src/main/java/com/kamco/cd/training/postgres/core/ModelTrainMngCoreService.java b/src/main/java/com/kamco/cd/training/postgres/core/ModelTrainMngCoreService.java index 7bab856..0465217 100644 --- a/src/main/java/com/kamco/cd/training/postgres/core/ModelTrainMngCoreService.java +++ b/src/main/java/com/kamco/cd/training/postgres/core/ModelTrainMngCoreService.java @@ -5,8 +5,8 @@ import com.kamco.cd.training.common.enums.ModelType; import com.kamco.cd.training.common.enums.TrainStatusType; import com.kamco.cd.training.common.exception.BadRequestException; import com.kamco.cd.training.common.exception.CustomApiException; -import com.kamco.cd.training.common.exception.NotFoundException; import com.kamco.cd.training.common.utils.UserUtil; +import com.kamco.cd.training.model.dto.ModelConfigDto; import com.kamco.cd.training.model.dto.ModelTrainMngDto; import com.kamco.cd.training.model.dto.ModelTrainMngDto.Basic; import com.kamco.cd.training.model.dto.ModelTrainMngDto.TrainingDataset; @@ -162,7 +162,7 @@ public class ModelTrainMngCoreService { * @param req 요청 파라미터 * @return */ - public Long saveModelConfig(Long modelId, ModelTrainMngDto.ModelConfig req) { + public void saveModelConfig(Long modelId, ModelTrainMngDto.ModelConfig req) { ModelMasterEntity modelMasterEntity = new ModelMasterEntity(); ModelConfigEntity entity = new ModelConfigEntity(); modelMasterEntity.setId(modelId); @@ -173,7 +173,7 @@ public class ModelTrainMngCoreService { entity.setTestPercent(req.getTestCnt()); entity.setMemo(req.getMemo()); - return modelConfigRepository.save(entity).getId(); + modelConfigRepository.save(entity); } /** @@ -198,14 +198,26 @@ public class ModelTrainMngCoreService { * @param uuid UUID * @return 모델 Entity */ - public ModelMasterEntity findByUuid(String uuid) { + public ModelMasterEntity findByUuid(UUID uuid) { try { - java.util.UUID uuidObj = java.util.UUID.fromString(uuid); return modelMngRepository - .findByUuid(uuidObj) - .orElseThrow(() -> new NotFoundException("모델을 찾을 수 없습니다. UUID: " + uuid)); + .findByUuid(uuid) + .orElseThrow(() -> new CustomApiException("NOT_FOUND_DATA", HttpStatus.NOT_FOUND)); } catch (IllegalArgumentException e) { throw new BadRequestException("잘못된 UUID 형식입니다: " + uuid); } } + + /** + * 모델학습 아이디로 config정보 조회 + * + * @param uuid + * @return + */ + public ModelConfigDto.Basic findModelConfigByModelId(UUID uuid) { + ModelMasterEntity modelEntity = findByUuid(uuid); + return modelConfigRepository + .findModelConfigByModelId(modelEntity.getId()) + .orElseThrow(() -> new CustomApiException("NOT_FOUND_DATA", HttpStatus.NOT_FOUND)); + } } diff --git a/src/main/java/com/kamco/cd/training/postgres/repository/model/ModelConfigRepository.java b/src/main/java/com/kamco/cd/training/postgres/repository/model/ModelConfigRepository.java index 8b0d02e..4974ba7 100644 --- a/src/main/java/com/kamco/cd/training/postgres/repository/model/ModelConfigRepository.java +++ b/src/main/java/com/kamco/cd/training/postgres/repository/model/ModelConfigRepository.java @@ -3,4 +3,5 @@ package com.kamco.cd.training.postgres.repository.model; import com.kamco.cd.training.postgres.entity.ModelConfigEntity; import org.springframework.data.jpa.repository.JpaRepository; -public interface ModelConfigRepository extends JpaRepository {} +public interface ModelConfigRepository + extends JpaRepository, ModelConfigRepositoryCustom {} diff --git a/src/main/java/com/kamco/cd/training/postgres/repository/model/ModelConfigRepositoryCustom.java b/src/main/java/com/kamco/cd/training/postgres/repository/model/ModelConfigRepositoryCustom.java new file mode 100644 index 0000000..53ad7f3 --- /dev/null +++ b/src/main/java/com/kamco/cd/training/postgres/repository/model/ModelConfigRepositoryCustom.java @@ -0,0 +1,8 @@ +package com.kamco.cd.training.postgres.repository.model; + +import com.kamco.cd.training.model.dto.ModelConfigDto; +import java.util.Optional; + +public interface ModelConfigRepositoryCustom { + Optional findModelConfigByModelId(Long modelId); +} diff --git a/src/main/java/com/kamco/cd/training/postgres/repository/model/ModelConfigRepositoryImpl.java b/src/main/java/com/kamco/cd/training/postgres/repository/model/ModelConfigRepositoryImpl.java new file mode 100644 index 0000000..2852218 --- /dev/null +++ b/src/main/java/com/kamco/cd/training/postgres/repository/model/ModelConfigRepositoryImpl.java @@ -0,0 +1,37 @@ +package com.kamco.cd.training.postgres.repository.model; + +import static com.kamco.cd.training.postgres.entity.QModelConfigEntity.modelConfigEntity; + +import com.kamco.cd.training.model.dto.ModelConfigDto.Basic; +import com.querydsl.core.types.Projections; +import com.querydsl.jpa.impl.JPAQueryFactory; +import java.util.Optional; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Repository; + +@Repository +@RequiredArgsConstructor +public class ModelConfigRepositoryImpl implements ModelConfigRepositoryCustom { + + private final JPAQueryFactory queryFactory; + + @Override + public Optional findModelConfigByModelId(Long modelId) { + + return Optional.ofNullable( + queryFactory + .select( + Projections.constructor( + Basic.class, + modelConfigEntity.id, + modelConfigEntity.model.id, + modelConfigEntity.epochCount, + modelConfigEntity.trainPercent, + modelConfigEntity.validationPercent, + modelConfigEntity.testPercent, + modelConfigEntity.memo)) + .from(modelConfigEntity) + .where(modelConfigEntity.model.id.eq(modelId)) + .fetchOne()); + } +} From f038fdd1db8df939b5ae633a013eb241fb353f28 Mon Sep 17 00:00:00 2001 From: "gayoun.park" Date: Wed, 4 Feb 2026 19:54:00 +0900 Subject: [PATCH 6/6] =?UTF-8?q?=EB=AA=A8=EB=8D=B8=20=EC=83=81=EC=84=B8=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=20API=20=EC=BB=A4=EB=B0=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cd/training/model/ModelTrainDetailApiController.java | 7 +++++++ .../training/model/service/ModelTrainDetailService.java | 5 +++++ .../postgres/core/ModelTrainDetailCoreService.java | 6 ++++++ .../repository/model/ModelDetailRepositoryCustom.java | 2 ++ .../repository/model/ModelDetailRepositoryImpl.java | 8 ++++++++ 5 files changed, 28 insertions(+) diff --git a/src/main/java/com/kamco/cd/training/model/ModelTrainDetailApiController.java b/src/main/java/com/kamco/cd/training/model/ModelTrainDetailApiController.java index 6ee176f..452a7d1 100644 --- a/src/main/java/com/kamco/cd/training/model/ModelTrainDetailApiController.java +++ b/src/main/java/com/kamco/cd/training/model/ModelTrainDetailApiController.java @@ -3,6 +3,7 @@ package com.kamco.cd.training.model; import com.kamco.cd.training.config.api.ApiResponseDto; import com.kamco.cd.training.model.dto.ModelTrainDetailDto; import com.kamco.cd.training.model.dto.ModelTrainDetailDto.MappingDataset; +import com.kamco.cd.training.model.dto.ModelTrainMngDto.Basic; import com.kamco.cd.training.model.service.ModelTrainDetailService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; @@ -21,6 +22,12 @@ import org.springframework.web.bind.annotation.RestController; public class ModelTrainDetailApiController { private final ModelTrainDetailService modelTrainDetailService; + @Operation(summary = "모델학습 상세 조회", description = "모델학습 상세 조회 API") + @GetMapping("/detail/{uuid}") + public ApiResponseDto findByModelByUUID(@PathVariable UUID uuid) { + return ApiResponseDto.ok(modelTrainDetailService.findByModelByUUID(uuid)); + } + @Operation(summary = "모델학습 상세 요약 정보", description = "모델학습 상세 요약 정보 API") @GetMapping("/summary/{uuid}") public ApiResponseDto getModelDetailSummary( diff --git a/src/main/java/com/kamco/cd/training/model/service/ModelTrainDetailService.java b/src/main/java/com/kamco/cd/training/model/service/ModelTrainDetailService.java index d2cc297..5fa8d90 100644 --- a/src/main/java/com/kamco/cd/training/model/service/ModelTrainDetailService.java +++ b/src/main/java/com/kamco/cd/training/model/service/ModelTrainDetailService.java @@ -3,6 +3,7 @@ package com.kamco.cd.training.model.service; import com.kamco.cd.training.model.dto.ModelTrainDetailDto.DetailSummary; import com.kamco.cd.training.model.dto.ModelTrainDetailDto.HyperSummary; import com.kamco.cd.training.model.dto.ModelTrainDetailDto.MappingDataset; +import com.kamco.cd.training.model.dto.ModelTrainMngDto.Basic; import com.kamco.cd.training.postgres.core.ModelTrainDetailCoreService; import java.util.List; import java.util.UUID; @@ -42,4 +43,8 @@ public class ModelTrainDetailService { public List getByModelMappingDataset(UUID uuid) { return modelTrainDetailCoreService.getByModelMappingDataset(uuid); } + + public Basic findByModelByUUID(UUID uuid) { + return modelTrainDetailCoreService.findByModelByUUID(uuid); + } } diff --git a/src/main/java/com/kamco/cd/training/postgres/core/ModelTrainDetailCoreService.java b/src/main/java/com/kamco/cd/training/postgres/core/ModelTrainDetailCoreService.java index dc7fce4..a23a4ea 100644 --- a/src/main/java/com/kamco/cd/training/postgres/core/ModelTrainDetailCoreService.java +++ b/src/main/java/com/kamco/cd/training/postgres/core/ModelTrainDetailCoreService.java @@ -6,6 +6,7 @@ import com.kamco.cd.training.common.utils.UserUtil; import com.kamco.cd.training.model.dto.ModelTrainDetailDto.DetailSummary; import com.kamco.cd.training.model.dto.ModelTrainDetailDto.HyperSummary; import com.kamco.cd.training.model.dto.ModelTrainDetailDto.MappingDataset; +import com.kamco.cd.training.model.dto.ModelTrainMngDto.Basic; import com.kamco.cd.training.postgres.entity.ModelMasterEntity; import com.kamco.cd.training.postgres.repository.model.ModelDetailRepository; import java.util.List; @@ -53,4 +54,9 @@ public class ModelTrainDetailCoreService { public List getByModelMappingDataset(UUID uuid) { return modelDetailRepository.getByModelMappingDataset(uuid); } + + public Basic findByModelByUUID(UUID uuid) { + ModelMasterEntity entity = modelDetailRepository.findByModelByUUID(uuid); + return entity.toDto(); + } } diff --git a/src/main/java/com/kamco/cd/training/postgres/repository/model/ModelDetailRepositoryCustom.java b/src/main/java/com/kamco/cd/training/postgres/repository/model/ModelDetailRepositoryCustom.java index 49e43ca..775b23b 100644 --- a/src/main/java/com/kamco/cd/training/postgres/repository/model/ModelDetailRepositoryCustom.java +++ b/src/main/java/com/kamco/cd/training/postgres/repository/model/ModelDetailRepositoryCustom.java @@ -17,4 +17,6 @@ public interface ModelDetailRepositoryCustom { HyperSummary getByModelHyperParamSummary(UUID uuid); List getByModelMappingDataset(UUID uuid); + + ModelMasterEntity findByModelByUUID(UUID uuid); } diff --git a/src/main/java/com/kamco/cd/training/postgres/repository/model/ModelDetailRepositoryImpl.java b/src/main/java/com/kamco/cd/training/postgres/repository/model/ModelDetailRepositoryImpl.java index 3e41fce..f376ec6 100644 --- a/src/main/java/com/kamco/cd/training/postgres/repository/model/ModelDetailRepositoryImpl.java +++ b/src/main/java/com/kamco/cd/training/postgres/repository/model/ModelDetailRepositoryImpl.java @@ -106,4 +106,12 @@ public class ModelDetailRepositoryImpl implements ModelDetailRepositoryCustom { .where(modelMasterEntity.uuid.eq(uuid)) .fetch(); } + + @Override + public ModelMasterEntity findByModelByUUID(UUID uuid) { + return queryFactory + .selectFrom(modelMasterEntity) + .where(modelMasterEntity.uuid.eq(uuid)) + .fetchOne(); + } }