[KC-103] 추론 실행 조건 변경, exception 처리 추가
This commit is contained in:
@@ -181,12 +181,9 @@ public class InferenceResultDto {
|
||||
message = "탐지 데이터 옵션은 '추론제외', '이전 년도 도엽 사용' 만 사용 가능합니다.")
|
||||
private String detectOption;
|
||||
|
||||
@Schema(
|
||||
description = "5k 도협 번호 목록",
|
||||
example =
|
||||
"[{\"mapSheetNum\":33605099,\"mapSheetName\":\"비양도\"},{\"mapSheetNum\":33605100,\"mapSheetName\":\"비양도\"},{\"mapSheetNum\":33606059,\"mapSheetName\":\"한림\"}]")
|
||||
@Schema(description = "5k 도협 번호 목록", example = "[33605,33606, 33610, 34802, 35603, 35611]")
|
||||
@NotNull
|
||||
private List<MapSheetNumDto> mapSheetNum;
|
||||
private List<String> mapSheetNum;
|
||||
}
|
||||
|
||||
@Getter
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
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;
|
||||
@@ -14,7 +15,6 @@ import com.kamco.cd.kamcoback.inference.dto.InferenceResultDto.DetectOption;
|
||||
import com.kamco.cd.kamcoback.inference.dto.InferenceResultDto.InferenceServerStatusDto;
|
||||
import com.kamco.cd.kamcoback.inference.dto.InferenceResultDto.InferenceStatusDetailDto;
|
||||
import com.kamco.cd.kamcoback.inference.dto.InferenceResultDto.MapSheetNumDto;
|
||||
import com.kamco.cd.kamcoback.inference.dto.InferenceResultDto.MapSheetScope;
|
||||
import com.kamco.cd.kamcoback.inference.dto.InferenceResultDto.ResultList;
|
||||
import com.kamco.cd.kamcoback.inference.dto.InferenceResultDto.SaveInferenceAiDto;
|
||||
import com.kamco.cd.kamcoback.inference.dto.InferenceResultDto.Status;
|
||||
@@ -26,10 +26,10 @@ import com.kamco.cd.kamcoback.model.dto.ModelMngDto.Basic;
|
||||
import com.kamco.cd.kamcoback.postgres.core.InferenceResultCoreService;
|
||||
import com.kamco.cd.kamcoback.postgres.core.MapSheetMngCoreService;
|
||||
import com.kamco.cd.kamcoback.postgres.core.ModelMngCoreService;
|
||||
import jakarta.persistence.EntityNotFoundException;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
@@ -57,6 +57,7 @@ public class InferenceResultService {
|
||||
private final MapSheetMngCoreService mapSheetMngCoreService;
|
||||
private final ModelMngCoreService modelMngCoreService;
|
||||
private final ExternalHttpClient externalHttpClient;
|
||||
private final ObjectMapper objectMapper;
|
||||
|
||||
@Value("${inference.url}")
|
||||
private String inferenceUrl;
|
||||
@@ -91,34 +92,107 @@ public class InferenceResultService {
|
||||
@Transactional
|
||||
public UUID saveInferenceInfo(InferenceResultDto.RegReq req) {
|
||||
|
||||
// 분석대상 도엽이 전체일때
|
||||
if (MapSheetScope.ALL.getId().equals(req.getMapSheetScope())) {
|
||||
// 변화탐지 실행 가능 기준 년도 조회
|
||||
List<MngListDto> targetList = mapSheetMngCoreService.getHstMapSheetList(req);
|
||||
|
||||
// 기준년도 조회
|
||||
List<MngListDto> targetList = mapSheetMngCoreService.getHstMapSheetList(req.getTargetYyyy());
|
||||
req.setMapSheetNum(createdMngDto(req, targetList));
|
||||
|
||||
} else {
|
||||
// 부분
|
||||
|
||||
List<String> mapTargetIds = new ArrayList<>();
|
||||
req.getMapSheetNum().forEach(dto -> mapTargetIds.add(dto.getMapSheetNum()));
|
||||
|
||||
// 기준년도 조회
|
||||
List<MngListDto> targetList =
|
||||
mapSheetMngCoreService.getHstMapSheetList(req.getTargetYyyy(), mapTargetIds);
|
||||
req.setMapSheetNum(createdMngDto(req, targetList));
|
||||
if (targetList.isEmpty()) {
|
||||
throw new CustomApiException("NOT_FOUND_TARGET_YEAR", HttpStatus.NOT_FOUND);
|
||||
}
|
||||
|
||||
if (req.getMapSheetNum().isEmpty()) {
|
||||
throw new EntityNotFoundException("분석 대상 정보가 부족합니다.");
|
||||
List<String> mapTargetIds = new ArrayList<>();
|
||||
for (MngListDto target : targetList) {
|
||||
mapTargetIds.add(target.getMapSheetNum());
|
||||
}
|
||||
|
||||
// 추론 테이블 저장
|
||||
UUID uuid = inferenceResultCoreService.saveInferenceInfo(req);
|
||||
// 변화탐지 실행 가능 비교년도 조회
|
||||
List<MngListCompareDto> compareList =
|
||||
mapSheetMngCoreService.getByHstMapSheetCompareList(req.getCompareYyyy(), mapTargetIds);
|
||||
|
||||
// 추론 실행 API 호출
|
||||
startInference(req, uuid);
|
||||
if (compareList.isEmpty()) {
|
||||
throw new CustomApiException("NOT_FOUND_COMPARE_YEAR", HttpStatus.NOT_FOUND);
|
||||
}
|
||||
|
||||
List<Map<String, Object>> totalNumList = new ArrayList<>();
|
||||
|
||||
if (DetectOption.EXCL.getId().equals(req.getDetectOption())) {
|
||||
// "추론제외" 일때 전년도 이전 값이 있어도 전년도 도엽이 없으면 비교 안함
|
||||
for (MngListCompareDto dto : compareList) {
|
||||
if (Objects.equals(dto.getBeforeYear(), req.getCompareYyyy())) {
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
map.put("beforeYear", dto.getBeforeYear());
|
||||
map.put("mapSheetNum", dto.getMapSheetNum());
|
||||
totalNumList.add(map);
|
||||
}
|
||||
}
|
||||
} else if (DetectOption.PREV.getId().equals(req.getDetectOption())) {
|
||||
// "이전 년도 도엽 사용" 이면 전년도 이전 도엽도 사용
|
||||
for (MngListCompareDto dto : compareList) {
|
||||
if (dto.getBeforeYear() != 0) {
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
map.put("beforeYear", dto.getBeforeYear());
|
||||
map.put("mapSheetNum", dto.getMapSheetNum());
|
||||
totalNumList.add(map);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (totalNumList.isEmpty()) {
|
||||
throw new CustomApiException("NOT_FOUND_COMPARE_YEAR", HttpStatus.NOT_FOUND);
|
||||
}
|
||||
|
||||
for (MngListDto target : targetList) {
|
||||
for (Map<String, Object> map : totalNumList) {
|
||||
if (target.getMapSheetNum().equals(map.get("mapSheetNum").toString())) {
|
||||
target.setBeforeYear(map.get("beforeYear").toString());
|
||||
target.setIsSuccess(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 목록 및 추론 대상 도엽정보 저장
|
||||
UUID uuid = inferenceResultCoreService.saveInferenceInfo(req, targetList);
|
||||
|
||||
// 추론에 필요한 geojson 파일 생성
|
||||
List<String> mapSheetNumList =
|
||||
targetList.stream()
|
||||
.filter(t -> Boolean.TRUE.equals(t.getIsSuccess()))
|
||||
.map(MngListDto::getMapSheetNum)
|
||||
.toList();
|
||||
|
||||
// 비교년도 geojson 파일 생성하여 경로 받기
|
||||
String modelComparePath =
|
||||
getSceneInference(
|
||||
String.valueOf(req.getCompareYyyy()), mapSheetNumList, req.getMapSheetScope());
|
||||
|
||||
// 기준년도 geojson 파일 생성하여 경로 받기
|
||||
String modelTargetPath =
|
||||
getSceneInference(
|
||||
String.valueOf(req.getTargetYyyy()), mapSheetNumList, req.getMapSheetScope());
|
||||
|
||||
// ai 서버에 전달할 파라미터 생성
|
||||
pred_requests_areas predRequestsAreas = new pred_requests_areas();
|
||||
predRequestsAreas.setInput1_year(req.getCompareYyyy());
|
||||
predRequestsAreas.setInput2_year(req.getTargetYyyy());
|
||||
predRequestsAreas.setInput1_scene_path(modelComparePath);
|
||||
predRequestsAreas.setInput2_scene_path(modelTargetPath);
|
||||
|
||||
InferenceSendDto m1 = this.getModelInfo(req.getModel1Uuid());
|
||||
m1.setPred_requests_areas(predRequestsAreas);
|
||||
|
||||
// ai 추론 실행 api 호출
|
||||
Long batchId = ensureAccepted(m1);
|
||||
|
||||
// ai 추론 실행후 응답값 update
|
||||
SaveInferenceAiDto saveInferenceAiDto = new SaveInferenceAiDto();
|
||||
saveInferenceAiDto.setUuid(uuid);
|
||||
saveInferenceAiDto.setBatchId(batchId);
|
||||
saveInferenceAiDto.setStatus(Status.IN_PROGRESS.getId());
|
||||
saveInferenceAiDto.setType("M1");
|
||||
saveInferenceAiDto.setInferStartDttm(ZonedDateTime.now());
|
||||
saveInferenceAiDto.setModelComparePath(modelComparePath);
|
||||
saveInferenceAiDto.setModelTargetPath(modelTargetPath);
|
||||
saveInferenceAiDto.setModelStartDttm(ZonedDateTime.now());
|
||||
inferenceResultCoreService.update(saveInferenceAiDto);
|
||||
|
||||
return uuid;
|
||||
}
|
||||
@@ -185,104 +259,67 @@ public class InferenceResultService {
|
||||
return mapSheetNum;
|
||||
}
|
||||
|
||||
/**
|
||||
* 추론 실행 API 호출
|
||||
*
|
||||
* @param req
|
||||
*/
|
||||
private void startInference(InferenceResultDto.RegReq req, UUID uuid) {
|
||||
|
||||
List<MapSheetNumDto> mapSheetNum = req.getMapSheetNum();
|
||||
List<String> mapSheetNumList = new ArrayList<>();
|
||||
|
||||
for (MapSheetNumDto mapSheetDto : mapSheetNum) {
|
||||
mapSheetNumList.add(mapSheetDto.getMapSheetNum());
|
||||
}
|
||||
|
||||
String modelComparePath =
|
||||
getSceneInference(String.valueOf(req.getCompareYyyy()), mapSheetNumList);
|
||||
String modelTargetPath =
|
||||
getSceneInference(String.valueOf(req.getTargetYyyy()), mapSheetNumList);
|
||||
|
||||
pred_requests_areas predRequestsAreas = new pred_requests_areas();
|
||||
predRequestsAreas.setInput1_year(req.getCompareYyyy());
|
||||
predRequestsAreas.setInput2_year(req.getTargetYyyy());
|
||||
predRequestsAreas.setInput1_scene_path(modelComparePath);
|
||||
predRequestsAreas.setInput2_scene_path(modelTargetPath);
|
||||
|
||||
InferenceSendDto m1 = this.getModelInfo(req.getModel1Uuid());
|
||||
InferenceSendDto m2 = this.getModelInfo(req.getModel2Uuid());
|
||||
InferenceSendDto m3 = this.getModelInfo(req.getModel3Uuid());
|
||||
|
||||
m1.setPred_requests_areas(predRequestsAreas);
|
||||
m2.setPred_requests_areas(predRequestsAreas);
|
||||
m3.setPred_requests_areas(predRequestsAreas);
|
||||
|
||||
Long batchId = this.ensureAccepted(m1);
|
||||
|
||||
SaveInferenceAiDto saveInferenceAiDto = new SaveInferenceAiDto();
|
||||
saveInferenceAiDto.setUuid(uuid);
|
||||
saveInferenceAiDto.setBatchId(batchId);
|
||||
saveInferenceAiDto.setStatus(Status.IN_PROGRESS.getId());
|
||||
saveInferenceAiDto.setType("M1");
|
||||
saveInferenceAiDto.setInferStartDttm(ZonedDateTime.now());
|
||||
saveInferenceAiDto.setModelComparePath(modelComparePath);
|
||||
saveInferenceAiDto.setModelTargetPath(modelTargetPath);
|
||||
saveInferenceAiDto.setModelStartDttm(ZonedDateTime.now());
|
||||
inferenceResultCoreService.update(saveInferenceAiDto);
|
||||
}
|
||||
|
||||
/**
|
||||
* 추론 AI API 호출
|
||||
*
|
||||
* @param dto
|
||||
*/
|
||||
private Long ensureAccepted(InferenceSendDto dto) {
|
||||
log.info("dto null? {}", dto == null);
|
||||
ObjectMapper om = new ObjectMapper();
|
||||
try {
|
||||
log.info("dto json={}", om.writeValueAsString(dto));
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage());
|
||||
|
||||
if (dto == null) {
|
||||
log.warn("not InferenceSendDto dto");
|
||||
throw new CustomApiException("BAD_REQUEST", HttpStatus.BAD_REQUEST);
|
||||
}
|
||||
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||
headers.setAccept(List.of(MediaType.APPLICATION_JSON));
|
||||
// 1) 요청 로그 (debug 권장)
|
||||
try {
|
||||
log.debug("Inference request dto={}", objectMapper.writeValueAsString(dto));
|
||||
} catch (JsonProcessingException e) {
|
||||
log.warn("Failed to serialize inference dto", e);
|
||||
}
|
||||
|
||||
// TODO 추후 삭제
|
||||
// 2) local 환경 임시 처리 (NPE 방어)
|
||||
if ("local".equals(profile)) {
|
||||
if (dto.getPred_requests_areas() == null) {
|
||||
throw new IllegalStateException("pred_requests_areas is null");
|
||||
}
|
||||
dto.getPred_requests_areas().setInput1_scene_path("/kamco-nfs/requests/2023_local.geojson");
|
||||
dto.getPred_requests_areas().setInput2_scene_path("/kamco-nfs/requests/2024_local.geojson");
|
||||
}
|
||||
|
||||
// 3) HTTP 호출
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||
headers.setAccept(List.of(MediaType.APPLICATION_JSON));
|
||||
|
||||
ExternalCallResult<String> result =
|
||||
externalHttpClient.call(inferenceUrl, HttpMethod.POST, dto, headers, String.class);
|
||||
|
||||
int status = result.statusCode();
|
||||
String body = result.body();
|
||||
|
||||
if (status < 200 || status >= 300) {
|
||||
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);
|
||||
}
|
||||
|
||||
Long batchId = 0L;
|
||||
|
||||
// 4) 응답 파싱
|
||||
try {
|
||||
List<Map<String, Object>> list =
|
||||
om.readValue(body, new TypeReference<List<Map<String, Object>>>() {});
|
||||
objectMapper.readValue(result.body(), new TypeReference<>() {});
|
||||
|
||||
Integer batchIdInt = (Integer) list.get(0).get("batch_id");
|
||||
batchId = batchIdInt.longValue();
|
||||
if (list.isEmpty()) {
|
||||
throw new IllegalStateException("Inference response is empty");
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage());
|
||||
}
|
||||
Object batchIdObj = list.get(0).get("batch_id");
|
||||
if (batchIdObj == null) {
|
||||
throw new IllegalStateException("batch_id not found in response");
|
||||
}
|
||||
|
||||
return batchId;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -335,11 +372,13 @@ public class InferenceResultService {
|
||||
/**
|
||||
* geojson 파일 생성
|
||||
*
|
||||
* @param yyyy
|
||||
* @param mapSheetNums
|
||||
* @param yyyy 영상관리 파일별 년도
|
||||
* @param mapSheetNums 5k 도엽 번호 리스트
|
||||
* @param mapSheetScope EXCL : 추론제외, PREV 이전 년도 도엽 사용
|
||||
* @return
|
||||
*/
|
||||
private String getSceneInference(String yyyy, List<String> mapSheetNums) {
|
||||
return mapSheetMngCoreService.getSceneInference(yyyy, mapSheetNums);
|
||||
private String getSceneInference(String yyyy, List<String> mapSheetNums, String mapSheetScope) {
|
||||
return mapSheetMngCoreService.getSceneInference(yyyy, mapSheetNums, mapSheetScope);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user