daniel 작업본 추가
This commit is contained in:
@@ -454,33 +454,53 @@ public class ModelTrainDetailService {
|
||||
*/
|
||||
public ZipFileListResponse getZipFileListWithFullUrl(
|
||||
UUID uuid, String downloadUuid, HttpServletRequest request) {
|
||||
log.info("ZIP 파일 목록 조회 시작 (전체 URL): modelUuid={}, downloadUuid={}", uuid, downloadUuid);
|
||||
log.info("=== ZIP 파일 목록 조회 시작: modelUuid={}, downloadUuid={} ===", uuid, downloadUuid);
|
||||
|
||||
// 1. 모델 정보 조회
|
||||
Basic modelInfo;
|
||||
try {
|
||||
modelInfo = findByModelByUUID(uuid);
|
||||
if (modelInfo == null) {
|
||||
log.warn("모델을 찾을 수 없음: modelUuid={}", uuid);
|
||||
throw new CustomApiException("NOT_FOUND", HttpStatus.NOT_FOUND, "모델을 찾을 수 없습니다: " + uuid);
|
||||
}
|
||||
log.debug(
|
||||
"모델 정보 조회 성공: modelNo={}, modelVer={}", modelInfo.getModelNo(), modelInfo.getModelVer());
|
||||
} catch (NullPointerException e) {
|
||||
log.error("모델 조회 실패: {}", uuid, e);
|
||||
log.error("모델 조회 중 NullPointerException 발생: modelUuid={}", uuid, e);
|
||||
throw new CustomApiException("NOT_FOUND", HttpStatus.NOT_FOUND, "모델을 찾을 수 없습니다: " + uuid);
|
||||
} catch (CustomApiException e) {
|
||||
// CustomApiException은 그대로 재throw
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
log.error("모델 조회 중 예상치 못한 오류 발생: modelUuid={}", uuid, e);
|
||||
throw new CustomApiException(
|
||||
"INTERNAL_SERVER_ERROR", HttpStatus.INTERNAL_SERVER_ERROR, "모델 조회 중 오류가 발생했습니다.");
|
||||
}
|
||||
|
||||
// 2. 실제 디렉토리 경로 찾기 (uuid 또는 uuid-out)
|
||||
Path baseDir = findActualBasePath(uuid);
|
||||
Path baseDir;
|
||||
try {
|
||||
baseDir = findActualBasePath(uuid);
|
||||
|
||||
if (baseDir == null || !Files.exists(baseDir)) {
|
||||
log.warn(
|
||||
"디렉토리를 찾을 수 없음: modelUuid={}, 시도한 경로: {} 또는 {}-out",
|
||||
"모델 결과 디렉토리를 찾을 수 없음: modelUuid={}, 시도한 경로: {} 또는 {}-out",
|
||||
uuid,
|
||||
responseDir + "/" + uuid,
|
||||
responseDir + "/" + uuid);
|
||||
throw new CustomApiException("NOT_FOUND", HttpStatus.NOT_FOUND, "모델 결과 디렉토리가 존재하지 않습니다.");
|
||||
}
|
||||
|
||||
log.info("디렉토리 발견: basePath={}", baseDir.toString());
|
||||
log.debug("디렉토리 발견: basePath={}", baseDir.toString());
|
||||
} catch (CustomApiException e) {
|
||||
// CustomApiException은 그대로 재throw
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
log.error("디렉토리 경로 확인 중 오류 발생: modelUuid={}", uuid, e);
|
||||
throw new CustomApiException(
|
||||
"INTERNAL_SERVER_ERROR", HttpStatus.INTERNAL_SERVER_ERROR, "디렉토리 경로 확인 중 오류가 발생했습니다.");
|
||||
}
|
||||
|
||||
// 요청에서 도메인 정보 추출
|
||||
String scheme = request.getScheme(); // http 또는 https
|
||||
@@ -497,6 +517,8 @@ public class ModelTrainDetailService {
|
||||
baseUrl = scheme + "://" + serverName + ":" + serverPort + contextPath;
|
||||
}
|
||||
|
||||
log.debug("다운로드 URL 베이스: {}", baseUrl);
|
||||
|
||||
// 3. ZIP 파일 목록 검색
|
||||
List<ZipFileInfo> zipFiles = new ArrayList<>();
|
||||
long totalSize = 0L;
|
||||
@@ -511,7 +533,10 @@ public class ModelTrainDetailService {
|
||||
Comparator.comparing(p -> p.getFileName().toString(), Comparator.reverseOrder()))
|
||||
.toList();
|
||||
|
||||
log.debug("ZIP 파일 필터링 완료: 발견된 파일 개수={}", files.size());
|
||||
|
||||
for (Path file : files) {
|
||||
try {
|
||||
String fileName = file.getFileName().toString();
|
||||
long fileSize = Files.size(file);
|
||||
totalSize += fileSize;
|
||||
@@ -535,14 +560,35 @@ public class ModelTrainDetailService {
|
||||
.isCurrent(isCurrent)
|
||||
.downloadUrl(downloadUrl)
|
||||
.build());
|
||||
}
|
||||
|
||||
log.info("ZIP 파일 {}개 발견", zipFiles.size());
|
||||
log.debug(
|
||||
"ZIP 파일 정보 추가: fileName={}, size={}, version={}, isCurrent={}",
|
||||
fileName,
|
||||
formatFileSize(fileSize),
|
||||
version,
|
||||
isCurrent);
|
||||
|
||||
} catch (IOException e) {
|
||||
log.error("ZIP 파일 목록 조회 실패: {}", baseDir, e);
|
||||
log.warn("ZIP 파일 정보 조회 실패 (건너뜀): file={}", file.getFileName(), e);
|
||||
// 개별 파일 실패 시 전체 프로세스를 중단하지 않고 계속 진행
|
||||
} catch (Exception e) {
|
||||
log.error("ZIP 파일 정보 처리 중 예상치 못한 오류 (건너뜀): file={}", file.getFileName(), e);
|
||||
// 예상치 못한 오류도 전체 프로세스를 중단하지 않음
|
||||
}
|
||||
}
|
||||
|
||||
log.info(" ZIP 파일 목록 조회 완료: 총 {}개 파일, 전체 크기={}", zipFiles.size(), formatFileSize(totalSize));
|
||||
|
||||
} catch (IOException e) {
|
||||
log.error("ZIP 파일 목록 조회 중 IO 오류 발생: basePath={}", baseDir, e);
|
||||
throw new CustomApiException(
|
||||
"INTERNAL_SERVER_ERROR", HttpStatus.INTERNAL_SERVER_ERROR, "ZIP 파일 목록 조회 실패");
|
||||
"INTERNAL_SERVER_ERROR",
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
"ZIP 파일 목록 조회 중 IO 오류가 발생했습니다.");
|
||||
} catch (Exception e) {
|
||||
log.error("ZIP 파일 목록 조회 중 예상치 못한 오류 발생: basePath={}", baseDir, e);
|
||||
throw new CustomApiException(
|
||||
"INTERNAL_SERVER_ERROR", HttpStatus.INTERNAL_SERVER_ERROR, "ZIP 파일 목록 조회 중 오류가 발생했습니다.");
|
||||
}
|
||||
|
||||
return ZipFileListResponse.builder()
|
||||
|
||||
@@ -4,6 +4,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||
import com.kamco.cd.training.common.enums.TrainStatusType;
|
||||
import com.kamco.cd.training.postgres.core.ModelTestMetricsJobCoreService;
|
||||
import com.kamco.cd.training.train.dto.ModelTrainMetricsDto.BestPthInfo;
|
||||
import com.kamco.cd.training.train.dto.ModelTrainMetricsDto.ModelMetricJsonDto;
|
||||
import com.kamco.cd.training.train.dto.ModelTrainMetricsDto.ModelTestFileName;
|
||||
import com.kamco.cd.training.train.dto.ModelTrainMetricsDto.ResponsePathDto;
|
||||
@@ -19,6 +20,8 @@ import java.time.ZonedDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.zip.ZipEntry;
|
||||
@@ -81,13 +84,13 @@ public class ModelTestMetricsJobService {
|
||||
/**
|
||||
* 베스트 에폭 zip파일 생성, 테스트결과 db등록
|
||||
*
|
||||
* @param modelInfo
|
||||
* @param modelInfo 모델 정보 (modelId, responsePath, uuid)
|
||||
*/
|
||||
private void createFile(ResponsePathDto modelInfo) {
|
||||
|
||||
String testPath = responseDir + "/" + modelInfo.getUuid() + "/metrics/test.csv";
|
||||
try (BufferedReader reader =
|
||||
Files.newBufferedReader(Paths.get(testPath), StandardCharsets.UTF_8); ) {
|
||||
Files.newBufferedReader(Paths.get(testPath), StandardCharsets.UTF_8)) {
|
||||
|
||||
CSVParser parser = CSVFormat.DEFAULT.withFirstRecordAsHeader().parse(reader);
|
||||
|
||||
@@ -161,52 +164,60 @@ public class ModelTestMetricsJobService {
|
||||
fileInfo.getBestEpochFileName() + ".pth",
|
||||
fileInfo.getModelVersion() + ".json");
|
||||
|
||||
try {
|
||||
List<Path> files = new ArrayList<>();
|
||||
try (Stream<Path> s = Files.list(responsePath)) {
|
||||
files.addAll(
|
||||
s.filter(Files::isRegularFile)
|
||||
.filter(p -> targetNames.contains(p.getFileName().toString()))
|
||||
.collect(Collectors.toList()));
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
try (Stream<Path> s = Files.list(Path.of(ptPathDir))) {
|
||||
files.addAll(
|
||||
s.filter(Files::isRegularFile)
|
||||
.limit(1) // yolov8_6th-6m.pt 파일 1개만
|
||||
.collect(Collectors.toList()));
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
// PT 파일 정확하게 조회
|
||||
Path ptFile = Paths.get(ptPathDir, ptFileName);
|
||||
if (Files.exists(ptFile)) {
|
||||
files.add(ptFile);
|
||||
} else {
|
||||
log.warn("PT 파일을 찾을 수 없습니다: {}", ptFile);
|
||||
throw new IOException("PT 파일 누락: " + ptFile);
|
||||
}
|
||||
|
||||
try {
|
||||
// 기본 ZIP 생성
|
||||
zipFiles(files, zipPath);
|
||||
log.info(" 기본 ZIP 생성 완료: {}", zipPath.getFileName());
|
||||
|
||||
// 개별 best*.pth ZIP 생성
|
||||
int individualZipCount = createIndividualBestPthZips(modelInfo, responsePath);
|
||||
|
||||
// 모든 ZIP 생성 성공 시 COMPLETED
|
||||
modelTestMetricsJobCoreService.updatePackingEnd(
|
||||
modelInfo.getModelId(), ZonedDateTime.now(), TrainStatusType.COMPLETED.getId());
|
||||
|
||||
log.info(" 전체 ZIP 생성 완료: 기본 1개 + 개별 {}개", individualZipCount);
|
||||
|
||||
} catch (IOException e) {
|
||||
modelTestMetricsJobCoreService.updatePackingEnd(
|
||||
modelInfo.getModelId(), ZonedDateTime.now(), TrainStatusType.ERROR.getId());
|
||||
log.error("ZIP 생성 중 오류 발생: modelId={}", modelInfo.getModelId(), e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
// ===== 추가: 각 best*.pth 파일별 개별 ZIP 생성 =====
|
||||
createIndividualBestPthZips(modelInfo, responsePath, jsonDto);
|
||||
}
|
||||
|
||||
/**
|
||||
* Response 폴더의 모든 best*.pth 파일을 각각 개별 ZIP 파일로 생성
|
||||
*
|
||||
* <p>각 PTH 파일의 Epoch과 메트릭 타입을 파싱하여 해당 Epoch의 메트릭 정보를 조회한 후, 개별 JSON 파일을 생성하고 ZIP으로 패키징합니다.
|
||||
*
|
||||
* @param modelInfo 모델 정보
|
||||
* @param responsePath Response 디렉토리 경로
|
||||
* @param jsonDto JSON 메타데이터
|
||||
* @return 생성된 개별 ZIP 파일 개수
|
||||
*/
|
||||
private void createIndividualBestPthZips(
|
||||
ResponsePathDto modelInfo, Path responsePath, ModelMetricJsonDto jsonDto) {
|
||||
private int createIndividualBestPthZips(ResponsePathDto modelInfo, Path responsePath) {
|
||||
|
||||
log.info("=== 개별 best*.pth ZIP 파일 생성 시작: modelId={} ===", modelInfo.getModelId());
|
||||
|
||||
int successCount = 0;
|
||||
|
||||
try {
|
||||
// 1. Response 폴더에서 모든 best*.pth 파일 찾기
|
||||
List<Path> bestPthFiles;
|
||||
@@ -221,51 +232,88 @@ public class ModelTestMetricsJobService {
|
||||
|
||||
if (bestPthFiles.isEmpty()) {
|
||||
log.warn("best*.pth 파일을 찾을 수 없습니다: path={}", responsePath);
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
|
||||
log.info("발견된 best*.pth 파일 개수: {}", bestPthFiles.size());
|
||||
|
||||
// 2. PT 파일 경로 (모든 ZIP에 공통으로 포함)
|
||||
// 2. PT 파일 경로 확인 (모든 ZIP에 공통으로 포함)
|
||||
Path ptFile = Paths.get(ptPathDir, ptFileName);
|
||||
if (!Files.exists(ptFile)) {
|
||||
log.warn("PT 파일을 찾을 수 없습니다: {}", ptFile);
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// model_config.py 경로 (선택적)
|
||||
Path modelConfigPath = responsePath.resolve("model_config.py");
|
||||
|
||||
// 3. 각 best*.pth 파일별로 개별 ZIP 생성
|
||||
for (Path bestPthFile : bestPthFiles) {
|
||||
String pthFileName = bestPthFile.getFileName().toString();
|
||||
log.info("처리 중인 best PTH 파일: {}", pthFileName);
|
||||
|
||||
try {
|
||||
// 3-1. 개별 JSON 파일 생성
|
||||
String individualJsonName = pthFileName.replace(".pth", ".json");
|
||||
Path individualJsonPath = responsePath.resolve(individualJsonName);
|
||||
writeJsonFile(jsonDto, individualJsonPath);
|
||||
log.info("개별 JSON 생성: {}", individualJsonName);
|
||||
Path individualJsonPath = null;
|
||||
|
||||
// 3-2. 개별 ZIP 파일명 생성
|
||||
try {
|
||||
// 3-1. PTH 파일명에서 Epoch과 메트릭 타입 추출
|
||||
BestPthInfo pthInfo = parsePthFileName(pthFileName);
|
||||
if (pthInfo == null) {
|
||||
log.warn("PTH 파일명 파싱 실패, 기본 JSON 사용: {}", pthFileName);
|
||||
// 파싱 실패 시 기본 메트릭 정보 사용
|
||||
ModelMetricJsonDto defaultJsonDto =
|
||||
modelTestMetricsJobCoreService.getTestMetricPackingInfo(modelInfo.getModelId());
|
||||
individualJsonPath = createIndividualJson(responsePath, pthFileName, defaultJsonDto);
|
||||
} else {
|
||||
// 3-2. 해당 Epoch의 메트릭 정보 조회
|
||||
log.debug(
|
||||
"PTH 파일 파싱 결과: epoch={}, metricType={}",
|
||||
pthInfo.getEpoch(),
|
||||
pthInfo.getMetricType());
|
||||
|
||||
ModelMetricJsonDto individualJsonDto =
|
||||
modelTestMetricsJobCoreService.getMetricsByEpoch(
|
||||
modelInfo.getModelId(), pthInfo.getEpoch(), pthInfo.getMetricType());
|
||||
|
||||
if (individualJsonDto == null) {
|
||||
log.warn("Epoch={} 메트릭 정보 없음, 기본 JSON 사용: {}", pthInfo.getEpoch(), pthFileName);
|
||||
ModelMetricJsonDto defaultJsonDto =
|
||||
modelTestMetricsJobCoreService.getTestMetricPackingInfo(modelInfo.getModelId());
|
||||
individualJsonPath = createIndividualJson(responsePath, pthFileName, defaultJsonDto);
|
||||
} else {
|
||||
// 3-3. 개별 JSON 파일 생성
|
||||
individualJsonPath =
|
||||
createIndividualJson(responsePath, pthFileName, individualJsonDto);
|
||||
log.info(
|
||||
" Epoch별 JSON 생성: epoch={}, file={}",
|
||||
pthInfo.getEpoch(),
|
||||
individualJsonPath.getFileName());
|
||||
}
|
||||
}
|
||||
|
||||
// 3-4. 개별 ZIP 파일명 생성
|
||||
// 형식: {modelVersion}.{pthFileNameWithoutExt}.zip
|
||||
// 예: G1_000001.best_epoch_3.zip
|
||||
// 예: G1_000001.best_fscore_5.zip, G1_000001.best_precision_7.zip
|
||||
String pthFileNameWithoutExt = pthFileName.replace(".pth", "");
|
||||
|
||||
// modelVersion 조회 (JSON에서 추출)
|
||||
ModelTestFileName fileInfo =
|
||||
modelTestMetricsJobCoreService.findModelTestFileNames(modelInfo.getModelId());
|
||||
String individualZipName =
|
||||
jsonDto.getModelVersion() + "." + pthFileNameWithoutExt + ".zip";
|
||||
fileInfo.getModelVersion() + "." + pthFileNameWithoutExt + ".zip";
|
||||
Path individualZipPath = responsePath.resolve(individualZipName);
|
||||
|
||||
// 3-3. ZIP에 포함될 파일 목록 구성
|
||||
// 3-5. ZIP에 포함될 파일 목록 구성
|
||||
List<Path> zipFileList = new ArrayList<>();
|
||||
zipFileList.add(bestPthFile); // best*.pth 파일
|
||||
zipFileList.add(individualJsonPath); // 개별 JSON 파일
|
||||
zipFileList.add(ptFile); // PT 파일
|
||||
|
||||
// model_config.py 파일이 있으면 추가
|
||||
Path modelConfigPath = responsePath.resolve("model_config.py");
|
||||
if (Files.exists(modelConfigPath)) {
|
||||
zipFileList.add(modelConfigPath);
|
||||
}
|
||||
|
||||
// 3-4. 개별 ZIP 생성
|
||||
// 3-6. 개별 ZIP 생성
|
||||
zipFiles(zipFileList, individualZipPath);
|
||||
|
||||
log.info(
|
||||
@@ -274,18 +322,112 @@ public class ModelTestMetricsJobService {
|
||||
pthFileName,
|
||||
Files.size(individualZipPath));
|
||||
|
||||
} catch (IOException e) {
|
||||
// 3-7. 임시 JSON 파일 정리
|
||||
try {
|
||||
Files.deleteIfExists(individualJsonPath);
|
||||
log.debug("임시 JSON 파일 삭제: {}", individualJsonPath.getFileName());
|
||||
} catch (IOException deleteEx) {
|
||||
log.warn("임시 JSON 파일 삭제 실패: {}", individualJsonPath, deleteEx);
|
||||
}
|
||||
|
||||
successCount++;
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("개별 ZIP 생성 실패: pthFile={}", pthFileName, e);
|
||||
|
||||
// 실패한 임시 JSON 파일도 정리 시도
|
||||
if (individualJsonPath != null) {
|
||||
try {
|
||||
Files.deleteIfExists(individualJsonPath);
|
||||
} catch (IOException deleteEx) {
|
||||
log.warn("실패한 임시 JSON 파일 삭제 실패: {}", individualJsonPath, deleteEx);
|
||||
}
|
||||
}
|
||||
|
||||
// 개별 ZIP 실패는 전체 프로세스를 중단하지 않음
|
||||
}
|
||||
}
|
||||
|
||||
log.info("=== 개별 best*.pth ZIP 파일 생성 완료: 총 {}개 ===", bestPthFiles.size());
|
||||
log.info("=== 개별 best*.pth ZIP 파일 생성 완료: 성공 {}/{}개 ===", successCount, bestPthFiles.size());
|
||||
|
||||
} catch (IOException e) {
|
||||
log.error("개별 ZIP 생성 중 오류 발생", e);
|
||||
// 에러 발생해도 기존 ZIP은 이미 생성되었으므로 예외를 던지지 않음
|
||||
}
|
||||
|
||||
return successCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* PTH 파일명에서 Epoch과 메트릭 타입을 추출
|
||||
*
|
||||
* <p>지원되는 파일명 패턴:
|
||||
*
|
||||
* <ul>
|
||||
* <li>best_{metricType}_{epoch}.pth (예: best_fscore_5.pth)
|
||||
* <li>best_epoch_{epoch}.pth (예: best_epoch_10.pth)
|
||||
* <li>best_changed_{metricType}_{epoch}.pth (예: best_changed_fscore_5.pth)
|
||||
* </ul>
|
||||
*
|
||||
* @param fileName PTH 파일명
|
||||
* @return 파싱된 PTH 정보, 실패 시 null
|
||||
*/
|
||||
private BestPthInfo parsePthFileName(String fileName) {
|
||||
try {
|
||||
// 패턴 1: best_changed_{metricType}_{epoch}.pth
|
||||
Pattern pattern1 = Pattern.compile("best_changed_([a-z_]+)_(\\d+)\\.pth");
|
||||
Matcher matcher1 = pattern1.matcher(fileName);
|
||||
if (matcher1.matches()) {
|
||||
String metricType = matcher1.group(1); // "fscore", "precision", "recall"
|
||||
Integer epoch = Integer.parseInt(matcher1.group(2));
|
||||
Path filePath = Paths.get(fileName);
|
||||
return new BestPthInfo(fileName, metricType, epoch, filePath);
|
||||
}
|
||||
|
||||
// 패턴 2: best_{metricType}_{epoch}.pth
|
||||
Pattern pattern2 = Pattern.compile("best_([a-z_]+)_(\\d+)\\.pth");
|
||||
Matcher matcher2 = pattern2.matcher(fileName);
|
||||
if (matcher2.matches()) {
|
||||
String metricType = matcher2.group(1); // "fscore", "precision", "recall"
|
||||
Integer epoch = Integer.parseInt(matcher2.group(2));
|
||||
Path filePath = Paths.get(fileName);
|
||||
return new BestPthInfo(fileName, metricType, epoch, filePath);
|
||||
}
|
||||
|
||||
// 패턴 3: best_epoch_{epoch}.pth (메트릭 타입 없음)
|
||||
Pattern pattern3 = Pattern.compile("best_epoch_(\\d+)\\.pth");
|
||||
Matcher matcher3 = pattern3.matcher(fileName);
|
||||
if (matcher3.matches()) {
|
||||
Integer epoch = Integer.parseInt(matcher3.group(1));
|
||||
Path filePath = Paths.get(fileName);
|
||||
// 메트릭 타입을 "epoch"로 설정 (기본값)
|
||||
return new BestPthInfo(fileName, "epoch", epoch, filePath);
|
||||
}
|
||||
|
||||
log.warn("알 수 없는 PTH 파일명 패턴: {}", fileName);
|
||||
return null;
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("PTH 파일명 파싱 중 오류: {}", fileName, e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 개별 JSON 파일 생성
|
||||
*
|
||||
* @param responsePath Response 디렉토리 경로
|
||||
* @param pthFileName PTH 파일명
|
||||
* @param jsonDto JSON 메타데이터
|
||||
* @return 생성된 JSON 파일 경로
|
||||
* @throws IOException JSON 쓰기 실패 시
|
||||
*/
|
||||
private Path createIndividualJson(
|
||||
Path responsePath, String pthFileName, ModelMetricJsonDto jsonDto) throws IOException {
|
||||
String individualJsonName = pthFileName.replace(".pth", ".json");
|
||||
Path individualJsonPath = responsePath.resolve(individualJsonName);
|
||||
writeJsonFile(jsonDto, individualJsonPath);
|
||||
return individualJsonPath;
|
||||
}
|
||||
|
||||
private void writeJsonFile(Object data, Path outputPath) throws IOException {
|
||||
|
||||
Reference in New Issue
Block a user