Merge remote-tracking branch 'origin/feat/training_260202' into feat/training_260202

# Conflicts:
#	src/main/java/com/kamco/cd/training/postgres/core/ModelTrainMngCoreService.java
This commit is contained in:
2026-02-12 16:55:52 +09:00
9 changed files with 47 additions and 36 deletions

View File

@@ -14,6 +14,7 @@ services:
- /mnt/nfs_share/images:/app/original-images - /mnt/nfs_share/images:/app/original-images
- /mnt/nfs_share/model_output:/app/model-outputs - /mnt/nfs_share/model_output:/app/model-outputs
- /mnt/nfs_share/train_dataset:/app/train-dataset - /mnt/nfs_share/train_dataset:/app/train-dataset
- /home/kcomu/data:/home/kcomu/data
networks: networks:
- kamco-cds - kamco-cds
restart: unless-stopped restart: unless-stopped

View File

@@ -14,15 +14,11 @@ import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid; import jakarta.validation.Valid;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.core.io.Resource; import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
@@ -230,11 +226,7 @@ public class DatasetApiController {
throws Exception { throws Exception {
String path = datasetService.getFilePathByUUIDPathType(uuid, pathType); String path = datasetService.getFilePathByUUIDPathType(uuid, pathType);
Path filePath = Paths.get(path); return datasetService.getFilePathByFile(path);
Resource resource = new UrlResource(filePath.toUri());
return ResponseEntity.ok().contentType(MediaType.APPLICATION_OCTET_STREAM).body(resource);
} }
@Operation(summary = "객체별 파일 Path 조회", description = "파일 Path 조회") @Operation(summary = "객체별 파일 Path 조회", description = "파일 Path 조회")

View File

@@ -4,9 +4,6 @@ import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode; import com.fasterxml.jackson.databind.node.ObjectNode;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.Session;
import com.kamco.cd.training.common.enums.LearnDataType; import com.kamco.cd.training.common.enums.LearnDataType;
import com.kamco.cd.training.common.exception.CustomApiException; import com.kamco.cd.training.common.exception.CustomApiException;
import com.kamco.cd.training.common.service.FormatStorage; import com.kamco.cd.training.common.service.FormatStorage;
@@ -32,7 +29,6 @@ import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Properties;
import java.util.UUID; import java.util.UUID;
import java.util.stream.Stream; import java.util.stream.Stream;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
@@ -502,29 +498,9 @@ public class DatasetService {
public ResponseEntity<Resource> getFilePathByFile(String remoteFilePath) { public ResponseEntity<Resource> getFilePathByFile(String remoteFilePath) {
String host = "192.168.2.86";
String user = "kcomu";
String password = "Kamco2025!";
Session session = null;
ChannelSftp sftp = null;
try { try {
JSch jsch = new JSch(); Path path = Paths.get(remoteFilePath);
InputStream inputStream = Files.newInputStream(path);
session = jsch.getSession(user, host, 22);
session.setPassword(password);
Properties config = new Properties();
config.put("StrictHostKeyChecking", "no");
session.setConfig(config);
session.connect(10_000);
sftp = (ChannelSftp) session.openChannel("sftp");
sftp.connect(5_000);
// 86 서버 파일을 스트림으로 연다
InputStream inputStream = sftp.get(normalizeLinuxPath(remoteFilePath));
InputStreamResource resource = InputStreamResource resource =
new InputStreamResource(inputStream) { new InputStreamResource(inputStream) {

View File

@@ -149,4 +149,22 @@ public class ModelTrainMngApiController {
req.setDataType(selectType); req.setDataType(selectType);
return ApiResponseDto.ok(modelTrainMngService.getDatasetSelectList(req)); return ApiResponseDto.ok(modelTrainMngService.getDatasetSelectList(req));
} }
@Operation(summary = "모델학습 1단계 실행중인 것이 있는지 count", description = "모델학습 1단계 실행중인 것이 있는지 count")
@ApiResponses(
value = {
@ApiResponse(
responseCode = "200",
description = "검색 성공",
content =
@Content(
mediaType = "application/json",
schema = @Schema(implementation = Long.class))),
@ApiResponse(responseCode = "400", description = "잘못된 검색 조건", content = @Content),
@ApiResponse(responseCode = "500", description = "서버 오류", content = @Content)
})
@GetMapping("/ing-training-cnt")
public ApiResponseDto<Long> findModelStep1InProgressCnt() {
return ApiResponseDto.ok(modelTrainMngService.findModelStep1InProgressCnt());
}
} }

View File

@@ -136,4 +136,8 @@ public class ModelTrainMngService {
return modelTrainMngCoreService.getDatasetSelectG2G3List(req); return modelTrainMngCoreService.getDatasetSelectG2G3List(req);
} }
} }
public Long findModelStep1InProgressCnt() {
return modelTrainMngCoreService.findModelStep1InProgressCnt();
}
} }

View File

@@ -513,4 +513,8 @@ public class ModelTrainMngCoreService {
return datasetUids; return datasetUids;
} }
public Long findModelStep1InProgressCnt() {
return modelMngRepository.findModelStep1InProgressCnt();
}
} }

View File

@@ -22,4 +22,6 @@ public interface ModelMngRepositoryCustom {
Optional<ModelMasterEntity> findFirstByStatusCdAndDelYn(String statusCd, Boolean delYn); Optional<ModelMasterEntity> findFirstByStatusCdAndDelYn(String statusCd, Boolean delYn);
TrainRunRequest findTrainRunRequest(Long modelId); TrainRunRequest findTrainRunRequest(Long modelId);
Long findModelStep1InProgressCnt();
} }

View File

@@ -4,6 +4,7 @@ import static com.kamco.cd.training.postgres.entity.QModelConfigEntity.modelConf
import static com.kamco.cd.training.postgres.entity.QModelHyperParamEntity.modelHyperParamEntity; import static com.kamco.cd.training.postgres.entity.QModelHyperParamEntity.modelHyperParamEntity;
import static com.kamco.cd.training.postgres.entity.QModelMasterEntity.modelMasterEntity; import static com.kamco.cd.training.postgres.entity.QModelMasterEntity.modelMasterEntity;
import com.kamco.cd.training.common.enums.TrainStatusType;
import com.kamco.cd.training.model.dto.ModelTrainMngDto; import com.kamco.cd.training.model.dto.ModelTrainMngDto;
import com.kamco.cd.training.postgres.entity.ModelMasterEntity; import com.kamco.cd.training.postgres.entity.ModelMasterEntity;
import com.kamco.cd.training.train.dto.TrainRunRequest; import com.kamco.cd.training.train.dto.TrainRunRequest;
@@ -147,4 +148,13 @@ public class ModelMngRepositoryImpl implements ModelMngRepositoryCustom {
.where(modelMasterEntity.id.eq(modelId)) .where(modelMasterEntity.id.eq(modelId))
.fetchOne(); .fetchOne();
} }
@Override
public Long findModelStep1InProgressCnt() {
return queryFactory
.select(modelMasterEntity.id.count())
.from(modelMasterEntity)
.where(modelMasterEntity.step1State.eq(TrainStatusType.IN_PROGRESS.getId()))
.fetchOne();
}
} }

View File

@@ -27,6 +27,10 @@ public class ModelTrainMetricsJobService {
@Value("${spring.profiles.active}") @Value("${spring.profiles.active}")
private String profile; private String profile;
// 학습 결과가 저장될 호스트 디렉토리
@Value("${train.docker.responseDir}")
private String responseDir;
/** /**
* 실행중인 profile * 실행중인 profile
* *
@@ -51,7 +55,7 @@ public class ModelTrainMetricsJobService {
for (ResponsePathDto modelInfo : modelIds) { for (ResponsePathDto modelInfo : modelIds) {
String trainPath = modelInfo.getResponsePath() + "/metrics/train.csv"; String trainPath = responseDir + "{uuid}/metrics/train.csv"; // TODO
try (BufferedReader reader = try (BufferedReader reader =
Files.newBufferedReader(Paths.get(trainPath), StandardCharsets.UTF_8); ) { Files.newBufferedReader(Paths.get(trainPath), StandardCharsets.UTF_8); ) {