Merge pull request 'feat/infer_dev_260211' (#94) from feat/infer_dev_260211 into develop
Reviewed-on: #94
This commit was merged in pull request #94.
This commit is contained in:
@@ -0,0 +1,57 @@
|
|||||||
|
package com.kamco.cd.kamcoback.inference;
|
||||||
|
|
||||||
|
import com.kamco.cd.kamcoback.config.api.ApiResponseDto;
|
||||||
|
import com.kamco.cd.kamcoback.inference.service.InferenceRunService;
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.Parameter;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Content;
|
||||||
|
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 java.util.UUID;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.log4j.Log4j2;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
@Tag(name = "추론 실행", description = "추론 실행")
|
||||||
|
@Log4j2
|
||||||
|
@RequestMapping("/api/inference/run")
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@RestController
|
||||||
|
public class InferenceRunController {
|
||||||
|
|
||||||
|
private final InferenceRunService inferenceRunService;
|
||||||
|
|
||||||
|
@Operation(summary = "추론 진행 여부 확인", description = "어드민 홈 > 추론관리 > 추론관리 > 추론관리 목록")
|
||||||
|
@ApiResponses(
|
||||||
|
value = {
|
||||||
|
@ApiResponse(
|
||||||
|
responseCode = "200",
|
||||||
|
description = "검색 성공",
|
||||||
|
content =
|
||||||
|
@Content(
|
||||||
|
mediaType = "application/json",
|
||||||
|
schema =
|
||||||
|
@Schema(
|
||||||
|
description = "진행 여부 (UUID 있으면 진행중)",
|
||||||
|
type = "UUID",
|
||||||
|
example = "44709877-2e27-4fc5-bacb-8e0328c69b64"))),
|
||||||
|
@ApiResponse(responseCode = "400", description = "잘못된 검색 조건", content = @Content),
|
||||||
|
@ApiResponse(responseCode = "500", description = "서버 오류", content = @Content)
|
||||||
|
})
|
||||||
|
@GetMapping
|
||||||
|
public ApiResponseDto<Void> getProcessing(
|
||||||
|
@Parameter(description = "비교년도", example = "2021") @RequestParam(required = false)
|
||||||
|
Integer compareYear,
|
||||||
|
@Parameter(description = "기준년도", example = "2022") @RequestParam(required = false)
|
||||||
|
Integer targetYear,
|
||||||
|
@Parameter(description = "모델 uuid") @RequestParam(required = false) UUID modelUuid) {
|
||||||
|
|
||||||
|
inferenceRunService.run(compareYear, targetYear, modelUuid);
|
||||||
|
return ApiResponseDto.ok(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,10 +1,12 @@
|
|||||||
package com.kamco.cd.kamcoback.inference.dto;
|
package com.kamco.cd.kamcoback.inference.dto;
|
||||||
|
|
||||||
import com.kamco.cd.kamcoback.postgres.entity.InferenceResultsTestingEntity;
|
import com.kamco.cd.kamcoback.postgres.entity.InferenceResultsTestingEntity;
|
||||||
|
import java.time.ZonedDateTime;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
|
import org.locationtech.jts.geom.Geometry;
|
||||||
|
|
||||||
public class InferenceResultsTestingDto {
|
public class InferenceResultsTestingDto {
|
||||||
|
|
||||||
@@ -22,4 +24,31 @@ public class InferenceResultsTestingDto {
|
|||||||
return new ShpDto(e.getBatchId(), e.getUid(), e.getMapId());
|
return new ShpDto(e.getBatchId(), e.getUid(), e.getMapId());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
public static class Basic {
|
||||||
|
private Double probability;
|
||||||
|
private Long beforeYear;
|
||||||
|
private Long afterYear;
|
||||||
|
private String mapId;
|
||||||
|
private String modelVersion;
|
||||||
|
private String clsModelPath;
|
||||||
|
private String clsModelVersion;
|
||||||
|
private String cdModelType;
|
||||||
|
private Long id;
|
||||||
|
private String modelName;
|
||||||
|
private Long batchId;
|
||||||
|
private Double area;
|
||||||
|
private String beforeC;
|
||||||
|
private Double beforeP;
|
||||||
|
private String afterC;
|
||||||
|
private Double afterP;
|
||||||
|
private Long seq;
|
||||||
|
private ZonedDateTime createdDate;
|
||||||
|
private String uid;
|
||||||
|
private Geometry geometry;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package com.kamco.cd.kamcoback.inference.service;
|
||||||
|
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@RequestMapping("/api/inference/manual")
|
||||||
|
public class InferenceManualApiController {}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package com.kamco.cd.kamcoback.inference.service;
|
||||||
|
|
||||||
|
import com.kamco.cd.kamcoback.inference.dto.InferenceResultsTestingDto;
|
||||||
|
import com.kamco.cd.kamcoback.postgres.core.InferenceResultCoreService;
|
||||||
|
import java.util.List;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class InferenceManualService {
|
||||||
|
private final InferenceResultCoreService inferenceResultCoreService;
|
||||||
|
|
||||||
|
public void getResultsTesting(List<Long> batchIds) {
|
||||||
|
List<InferenceResultsTestingDto.Basic> resultList =
|
||||||
|
inferenceResultCoreService.getInferenceResults(batchIds);
|
||||||
|
|
||||||
|
if (resultList.isEmpty()) {}
|
||||||
|
|
||||||
|
for (InferenceResultsTestingDto.Basic result : resultList) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,181 @@
|
|||||||
|
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("${inference.url}")
|
||||||
|
private String inferenceUrl;
|
||||||
|
|
||||||
|
public void run(Integer compareYear, Integer targetYear, UUID modelUuid) {
|
||||||
|
List<String> compareList = mapSheetMngCoreService.getMapSheetMngHst(compareYear);
|
||||||
|
List<String> targetList = mapSheetMngCoreService.getMapSheetMngHst(targetYear);
|
||||||
|
|
||||||
|
Set<String> compareSet = new HashSet<>(compareList);
|
||||||
|
|
||||||
|
List<String> filteredTargetList =
|
||||||
|
targetList.stream()
|
||||||
|
.filter(compareSet::contains) // 2021에 있는 도협만 남김
|
||||||
|
.distinct() // 필요 없으면 제거
|
||||||
|
.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<String> 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<String> 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<Map<String, Object>> 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(modelInfo.getPriority());
|
||||||
|
return sendDto;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -498,15 +498,16 @@ public class InferenceResultCoreService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 추론 결과 shp파일 생성위해서 조회
|
* 추론 결과 조회
|
||||||
*
|
*
|
||||||
* @param batchIds
|
* @param batchIds
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public List<InferenceResultsTestingDto.ShpDto> getInferenceResults(List<Long> batchIds) {
|
public List<InferenceResultsTestingDto.Basic> getInferenceResults(List<Long> batchIds) {
|
||||||
List<InferenceResultsTestingEntity> list =
|
List<InferenceResultsTestingEntity> list =
|
||||||
inferenceResultsTestingRepository.getInferenceResultList(batchIds);
|
inferenceResultsTestingRepository.getInferenceResultList(batchIds);
|
||||||
return list.stream().map(InferenceResultsTestingDto.ShpDto::fromEntity).toList();
|
|
||||||
|
return list.stream().map(InferenceResultsTestingEntity::toDto).toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Long getInferenceResultCnt(List<Long> batchIds) {
|
public Long getInferenceResultCnt(List<Long> batchIds) {
|
||||||
|
|||||||
@@ -342,4 +342,9 @@ public class MapSheetMngCoreService {
|
|||||||
public List<MngListCompareDto> getByHstMapSheetCompareList(int mngYyyy, List<String> mapId) {
|
public List<MngListCompareDto> getByHstMapSheetCompareList(int mngYyyy, List<String> mapId) {
|
||||||
return mapSheetMngYearRepository.findByHstMapSheetCompareList(mngYyyy, mapId);
|
return mapSheetMngYearRepository.findByHstMapSheetCompareList(mngYyyy, mapId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<String> getMapSheetMngHst(Integer year) {
|
||||||
|
List<MapSheetMngHstEntity> entity = mapSheetMngRepository.getMapSheetMngHst(year);
|
||||||
|
return entity.stream().map(MapSheetMngHstEntity::getMapSheetNum).toList();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package com.kamco.cd.kamcoback.postgres.entity;
|
package com.kamco.cd.kamcoback.postgres.entity;
|
||||||
|
|
||||||
|
import com.kamco.cd.kamcoback.inference.dto.InferenceResultsTestingDto;
|
||||||
import jakarta.persistence.Column;
|
import jakarta.persistence.Column;
|
||||||
import jakarta.persistence.Entity;
|
import jakarta.persistence.Entity;
|
||||||
import jakarta.persistence.Id;
|
import jakarta.persistence.Id;
|
||||||
@@ -84,4 +85,28 @@ public class InferenceResultsTestingEntity {
|
|||||||
|
|
||||||
@Column(name = "geometry", columnDefinition = "geometry")
|
@Column(name = "geometry", columnDefinition = "geometry")
|
||||||
private Geometry geometry;
|
private Geometry geometry;
|
||||||
|
|
||||||
|
public InferenceResultsTestingDto.Basic toDto() {
|
||||||
|
return new InferenceResultsTestingDto.Basic(
|
||||||
|
this.probability,
|
||||||
|
this.beforeYear,
|
||||||
|
this.afterYear,
|
||||||
|
this.mapId,
|
||||||
|
this.modelVersion,
|
||||||
|
this.clsModelPath,
|
||||||
|
this.clsModelVersion,
|
||||||
|
this.cdModelType,
|
||||||
|
this.id,
|
||||||
|
this.modelName,
|
||||||
|
this.batchId,
|
||||||
|
this.area,
|
||||||
|
this.beforeC,
|
||||||
|
this.beforeP,
|
||||||
|
this.afterC,
|
||||||
|
this.afterP,
|
||||||
|
this.seq,
|
||||||
|
this.createdDate,
|
||||||
|
this.uid,
|
||||||
|
this.geometry);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -80,4 +80,6 @@ public interface MapSheetMngRepositoryCustom {
|
|||||||
void updateMapSheetMngHstUploadId(Long hstUid, UUID uuid, String uploadId);
|
void updateMapSheetMngHstUploadId(Long hstUid, UUID uuid, String uploadId);
|
||||||
|
|
||||||
void insertMapSheetMngTile(@Valid AddReq addReq);
|
void insertMapSheetMngTile(@Valid AddReq addReq);
|
||||||
|
|
||||||
|
List<MapSheetMngHstEntity> getMapSheetMngHst(Integer year);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1099,4 +1099,15 @@ public class MapSheetMngRepositoryImpl extends QuerydslRepositorySupport
|
|||||||
"{0} like '%" + searchReq.getSearchValue() + "%'",
|
"{0} like '%" + searchReq.getSearchValue() + "%'",
|
||||||
mapSheetMngHstEntity.mapSheetNum));
|
mapSheetMngHstEntity.mapSheetNum));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<MapSheetMngHstEntity> getMapSheetMngHst(Integer year) {
|
||||||
|
return queryFactory
|
||||||
|
.select(mapSheetMngHstEntity)
|
||||||
|
.from(mapSheetMngHstEntity)
|
||||||
|
.innerJoin(mapSheetMngFileEntity)
|
||||||
|
.on(mapSheetMngFileEntity.hstUid.eq(mapSheetMngHstEntity.hstUid))
|
||||||
|
.where(mapSheetMngHstEntity.mngYyyy.eq(year).and(mapSheetMngHstEntity.syncState.eq("DONE")))
|
||||||
|
.fetch();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user