diff --git a/src/main/java/com/kamco/cd/kamcoback/inference/dto/InferenceSendDto.java b/src/main/java/com/kamco/cd/kamcoback/inference/dto/InferenceSendDto.java index fe7dbfaf..143dd054 100644 --- a/src/main/java/com/kamco/cd/kamcoback/inference/dto/InferenceSendDto.java +++ b/src/main/java/com/kamco/cd/kamcoback/inference/dto/InferenceSendDto.java @@ -14,6 +14,9 @@ import lombok.ToString; @ToString public class InferenceSendDto { + private static final String DEV_PATH_PREFIX = "kamco-nfs"; + private static final String PROD_PATH_PREFIX = "data"; + private pred_requests_areas pred_requests_areas; private String model_version; private String cd_model_path; @@ -23,12 +26,17 @@ public class InferenceSendDto { private String cd_model_type; private Double priority; - public String getCd_model_path() { - return cd_model_path == null ? null : cd_model_path.replace("kamcd-nfs", "data"); - } - - public String getCls_model_path() { - return cls_model_path == null ? null : cls_model_path.replace("kamcd-nfs", "data"); + // 프로덕션은 경로가 바뀜 + public void changeValForProd() { + if (pred_requests_areas != null) { + pred_requests_areas.changeValForProd(); + } + if (this.cd_model_path != null) { + this.cd_model_path = this.cd_model_path.replace(DEV_PATH_PREFIX, PROD_PATH_PREFIX); + } + if (this.cls_model_path != null) { + this.cls_model_path = this.cls_model_path.replace(DEV_PATH_PREFIX, PROD_PATH_PREFIX); + } } @Getter @@ -43,13 +51,18 @@ public class InferenceSendDto { private String input1_scene_path; private String input2_scene_path; - public String getInput1_scene_path() { - - return input1_scene_path == null ? null : input1_scene_path.replace("kamcd-nfs", "data"); - } - - public String getInput2_scene_path() { - return input2_scene_path == null ? null : input2_scene_path.replace("kamcd-nfs", "data"); + public void changeValForProd() { + // ai팀에서 kamco-nfs를 data로 세팅했음 + if (this.input1_scene_path != null) { + this.input1_scene_path = + this.input1_scene_path.replace( + InferenceSendDto.DEV_PATH_PREFIX, InferenceSendDto.PROD_PATH_PREFIX); + } + if (this.input2_scene_path != null) { + this.input2_scene_path = + this.input2_scene_path.replace( + InferenceSendDto.DEV_PATH_PREFIX, InferenceSendDto.PROD_PATH_PREFIX); + } } } } diff --git a/src/main/java/com/kamco/cd/kamcoback/inference/service/InferenceResultService.java b/src/main/java/com/kamco/cd/kamcoback/inference/service/InferenceResultService.java index 05a1d331..bf3cd137 100644 --- a/src/main/java/com/kamco/cd/kamcoback/inference/service/InferenceResultService.java +++ b/src/main/java/com/kamco/cd/kamcoback/inference/service/InferenceResultService.java @@ -713,6 +713,14 @@ public class InferenceResultService { sendDto.setCls_model_version(modelInfo.getModelVer()); sendDto.setCd_model_type(modelType); sendDto.setPriority(5d); + + // 운영환경일때 경로수정 dean 260226 + if (profile != null && profile.equals("prod")) { + log.info("profile = {} change inforence req", profile); + sendDto.changeValForProd(); + } + + log.info("[Inference Send]SendDto={}", sendDto); return sendDto; } diff --git a/src/main/java/com/kamco/cd/kamcoback/inference/service/InferenceRunService.java b/src/main/java/com/kamco/cd/kamcoback/inference/service/InferenceRunService.java new file mode 100644 index 00000000..9f24ffff --- /dev/null +++ b/src/main/java/com/kamco/cd/kamcoback/inference/service/InferenceRunService.java @@ -0,0 +1,229 @@ +package com.kamco.cd.kamcoback.inference.service; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.kamco.cd.kamcoback.common.exception.CustomApiException; +import com.kamco.cd.kamcoback.common.geometry.GeoJsonFileWriter.Scene; +import com.kamco.cd.kamcoback.config.resttemplate.ExternalHttpClient; +import com.kamco.cd.kamcoback.config.resttemplate.ExternalHttpClient.ExternalCallResult; +import com.kamco.cd.kamcoback.inference.dto.InferenceSendDto; +import com.kamco.cd.kamcoback.inference.dto.InferenceSendDto.pred_requests_areas; +import com.kamco.cd.kamcoback.model.dto.ModelMngDto.Basic; +import com.kamco.cd.kamcoback.model.dto.ModelMngDto.ModelType; +import com.kamco.cd.kamcoback.postgres.core.MapSheetMngCoreService; +import com.kamco.cd.kamcoback.postgres.core.ModelMngCoreService; +import java.nio.file.Paths; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; +import lombok.RequiredArgsConstructor; +import lombok.extern.log4j.Log4j2; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.stereotype.Service; + +@Service +@Log4j2 +@RequiredArgsConstructor +public class InferenceRunService { + private final ExternalHttpClient externalHttpClient; + private final MapSheetMngCoreService mapSheetMngCoreService; + private final ModelMngCoreService modelMngCoreService; + private final ObjectMapper objectMapper; + + @Value("${spring.profiles.active}") + private String profile; + + @Value("${inference.url}") + private String inferenceUrl; + + public void run(Integer compareYear, Integer targetYear, UUID modelUuid) { + + List compareList = mapSheetMngCoreService.getMapSheetMngHst(compareYear); + List targetList = mapSheetMngCoreService.getMapSheetMngHst(targetYear); + + log.info( + "hst list count compareList = {}, targetList = {}", compareList.size(), targetList.size()); + + Set compareSet = new HashSet<>(compareList); + Set targetSet = new HashSet<>(targetList); + + long intersectionCount = + targetSet.stream() + .distinct() + .filter(compareSet::contains) + .count(); // compare와 target에 공통으로 존재하는 도협 수 + + long excludedTargetCount = + targetSet.stream() + .distinct() + .filter(s -> !compareSet.contains(s)) + .count(); // target 에만 존재하는 도협 수 (compare 에는 없음) + + long onlyCompareCount = + compareSet.stream() + .distinct() + .filter(s -> !targetSet.contains(s)) + .count(); // compare 에만 존재하는 도협 수 (target 에는 없음) + + log.info( + """ + ===== MapSheet Year Comparison ===== + target Total: {} + compare Total: {} + Intersection: {} + target Only (Excluded from compare): {} + compare Only: {} + ==================================== + """, + targetSet.size(), + compareSet.size(), + intersectionCount, + excludedTargetCount, + onlyCompareCount); + + List filteredTargetList = + targetSet.stream() // target 기준으로 + .filter(compareSet::contains) // compare에 있는 도협만 남김 + .toList(); + + Scene modelComparePath = getSceneInference(compareYear.toString(), filteredTargetList, "", ""); + + Scene modelTargetPath = getSceneInference(targetYear.toString(), filteredTargetList, "", ""); + + // ai 서버에 전달할 파라미터 생성 + pred_requests_areas predRequestsAreas = new pred_requests_areas(); + predRequestsAreas.setInput1_year(compareYear); + predRequestsAreas.setInput2_year(targetYear); + predRequestsAreas.setInput1_scene_path(modelComparePath.getFilePath()); + predRequestsAreas.setInput2_scene_path(modelTargetPath.getFilePath()); + + InferenceSendDto m1 = this.getModelInfo(modelUuid); + m1.setPred_requests_areas(predRequestsAreas); + + // ai 추론 실행 api 호출 + Long batchId = ensureAccepted(m1); + } + + private Scene getSceneInference( + String yyyy, List mapSheetNums, String mapSheetScope, String detectOption) { + return mapSheetMngCoreService.getSceneInference( + yyyy, mapSheetNums, mapSheetScope, detectOption); + } + + /** + * 추론 AI API 호출 + * + * @param dto + */ + private Long ensureAccepted(InferenceSendDto dto) { + + if (dto == null) { + log.warn("not InferenceSendDto dto"); + throw new CustomApiException("BAD_REQUEST", HttpStatus.BAD_REQUEST); + } + + // 1) 요청 로그 + try { + log.debug("Inference request dto={}", objectMapper.writeValueAsString(dto)); + } catch (JsonProcessingException e) { + log.warn("Failed to serialize inference dto", e); + } + + // 3) HTTP 호출 + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + headers.setAccept(List.of(MediaType.APPLICATION_JSON)); + + ExternalCallResult result = + externalHttpClient.call(inferenceUrl, HttpMethod.POST, dto, headers, String.class); + + if (result.statusCode() < 200 || result.statusCode() >= 300) { + log.error("Inference API failed. status={}, body={}", result.statusCode(), result.body()); + throw new CustomApiException("BAD_GATEWAY", HttpStatus.BAD_GATEWAY); + } + + // 4) 응답 파싱 + try { + List> list = + objectMapper.readValue(result.body(), new TypeReference<>() {}); + + if (list.isEmpty()) { + throw new IllegalStateException("Inference response is empty"); + } + + Object batchIdObj = list.get(0).get("batch_id"); + if (batchIdObj == null) { + throw new IllegalStateException("batch_id not found in response"); + } + + return Long.valueOf(batchIdObj.toString()); + + } catch (Exception e) { + log.error("Failed to parse inference response. body={}", result.body(), e); + throw new CustomApiException("INVALID_INFERENCE_RESPONSE", HttpStatus.BAD_GATEWAY); + } + } + + /** + * 모델정보 조회 dto 생성 후 반환 + * + * @param uuid + * @return + */ + private InferenceSendDto getModelInfo(UUID uuid) { + + Basic modelInfo = modelMngCoreService.findByModelUuid(uuid); + + String cdModelPath = ""; + String cdModelConfigPath = ""; + String cdClsModelPath = ""; + + if (modelInfo.getCdModelPath() != null && modelInfo.getCdModelFileName() != null) { + cdModelPath = + Paths.get(modelInfo.getCdModelPath(), modelInfo.getCdModelFileName()).toString(); + } + + if (modelInfo.getCdModelConfig() != null && modelInfo.getCdModelConfigFileName() != null) { + cdModelConfigPath = + Paths.get(modelInfo.getCdModelConfig(), modelInfo.getCdModelConfigFileName()).toString(); + } + + if (modelInfo.getClsModelPath() != null && modelInfo.getClsModelFileName() != null) { + cdClsModelPath = + Paths.get(modelInfo.getClsModelPath(), modelInfo.getClsModelFileName()).toString(); + } + + String modelType = ""; + + if (modelInfo.getModelType().equals(ModelType.G1.getId())) { + modelType = ModelType.G1.getId(); + } else if (modelInfo.getModelType().equals(ModelType.G2.getId())) { + modelType = ModelType.G2.getId(); + } else { + modelType = ModelType.G3.getId(); + } + + InferenceSendDto sendDto = new InferenceSendDto(); + sendDto.setModel_version(modelInfo.getModelVer()); + sendDto.setCd_model_path(cdModelPath); + sendDto.setCd_model_config(cdModelConfigPath); + sendDto.setCls_model_path(cdClsModelPath); + sendDto.setCls_model_version(modelInfo.getModelVer()); + sendDto.setCd_model_type(modelType); + sendDto.setPriority(5.0); + // 운영환경일때 경로수정 dean 260226 + if (profile != null && profile.equals("prod")) { + log.info("profile = {} change inforence req", profile); + sendDto.changeValForProd(); + } + + return sendDto; + } +} diff --git a/src/main/java/com/kamco/cd/kamcoback/scheduler/service/MapSheetInferenceJobService.java b/src/main/java/com/kamco/cd/kamcoback/scheduler/service/MapSheetInferenceJobService.java index 3410ddfb..ad0ed616 100644 --- a/src/main/java/com/kamco/cd/kamcoback/scheduler/service/MapSheetInferenceJobService.java +++ b/src/main/java/com/kamco/cd/kamcoback/scheduler/service/MapSheetInferenceJobService.java @@ -355,8 +355,12 @@ public class MapSheetInferenceJobService { m.setCls_model_version(progressDto.getClsModelVersion()); m.setCd_model_type(type); m.setPriority(5d); - - // log.info("InferenceSendDto={}", m); + // 운영환경일때 경로수정 dean 260226 + if (profile != null && profile.equals("prod")) { + log.info("profile = {} [M]change inforence req", profile); + m.changeValForProd(); + } + log.info("[Inference]SendDto={}", m); // 추론 실행 api 호출 Long batchId = ensureAccepted(m);