Feat: Report 틀 구현 S11P21S002-215

This commit is contained in:
kimtaesoo7 2024-09-24 15:44:47 +09:00
parent 650e3ec6ee
commit 22de4b5b34
12 changed files with 348 additions and 1 deletions

View File

@ -127,7 +127,7 @@ public class AiModelService {
}
@CheckPrivilege(PrivilegeType.EDITOR)
public void train(final Integer projectId, Integer modelId) {
public void train(final Integer projectId, final Integer modelId) {
trainProgressCheck(projectId);
// FastAPI 서버로 학습 요청을 전송

View File

@ -0,0 +1,24 @@
package com.worlabel.domain.report.controller;
import com.worlabel.domain.report.entity.dto.ReportResponse;
import com.worlabel.domain.report.service.ReportService;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
@RequestMapping("/api/reports")
@RequiredArgsConstructor
public class ReportController {
private final ReportService reportService;
@GetMapping("/model/{model_id}")
public List<ReportResponse> getReportsByModelId(@PathVariable("model_id") final Integer modelId) {
return reportService.getReportsByModelId(modelId);
}
}

View File

@ -0,0 +1,51 @@
package com.worlabel.domain.report.entity;
import com.worlabel.domain.model.entity.AiModel;
import com.worlabel.global.common.BaseEntity;
import jakarta.persistence.*;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor;
@Getter
@Entity
@Table(name = "report")
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Report extends BaseEntity {
@Id
@Column(name = "report_id", nullable = false)
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
/**
* 소속된 모델
*/
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "model_id", nullable = false)
private AiModel aiModel;
/**
* 전체 에포크
*/
@Column(name = "total_epochs", nullable = false)
private Integer totalEpochs;
/**
* 현재 에포크
*/
@Column(name = "epoch", nullable = false)
private Integer epoch;
@Column(name = "box_loss", nullable = false)
private double boxLoss;
@Column(name = "cls_loss", nullable = false)
private double clsLoss;
@Column(name = "dfl_loss", nullable = false)
private double dflLoss;
@Column(name = "fitness", nullable = false)
private double fitness;
}

View File

@ -0,0 +1,29 @@
package com.worlabel.domain.report.entity.dto;
import com.worlabel.domain.report.entity.Report;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;
@Getter
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public class ReportResponse {
private Integer id;
private Integer totalEpochs;
private Integer epoch;
private double boxLoss;
private double clsLoss;
private double dflLoss;
private double fitness;
public static ReportResponse from(final Report report) {
return new ReportResponse(
report.getId(),
report.getTotalEpochs(),
report.getEpoch(),
report.getBoxLoss(),
report.getClsLoss(),
report.getDflLoss(),
report.getFitness());
}
}

View File

@ -0,0 +1,11 @@
package com.worlabel.domain.report.repository;
import com.worlabel.domain.report.entity.Report;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;
public interface ReportRepository extends JpaRepository<Report, Integer> {
List<Report> findByAiModelId(Integer modelId);
}

View File

@ -0,0 +1,25 @@
package com.worlabel.domain.report.service;
import com.worlabel.domain.report.entity.Report;
import com.worlabel.domain.report.entity.dto.ReportResponse;
import com.worlabel.domain.report.repository.ReportRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
@Service
@Transactional
@RequiredArgsConstructor
public class ReportService {
private final ReportRepository reportRepository;
public List<ReportResponse> getReportsByModelId(final Integer modelId) {
List<Report> reports = reportRepository.findByAiModelId(modelId);
return reports.stream()
.map(ReportResponse::from)
.toList();
}
}

View File

@ -0,0 +1,33 @@
package com.worlabel.domain.result.controller;
import com.worlabel.domain.result.entity.dto.ResultResponse;
import com.worlabel.domain.result.service.ResultService;
import com.worlabel.global.config.swagger.SwaggerApiError;
import com.worlabel.global.config.swagger.SwaggerApiSuccess;
import com.worlabel.global.exception.ErrorCode;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@Tag(name = "결과 관련 API")
@RestController
@RequestMapping("/api/results")
@RequiredArgsConstructor
public class ResultController {
private final ResultService resultService;
@Operation(summary = "모델 결과 조회", description = "모델 결과를 조회합니다.")
@SwaggerApiSuccess(description = "모델 결과를 성공적으로 조회합니다")
@SwaggerApiError({ErrorCode.EMPTY_REQUEST_PARAMETER, ErrorCode.SERVER_ERROR})
@GetMapping("/model/{model_id}")
public List<ResultResponse> getResultsByModelId(@PathVariable("model_id") final Integer modelId) {
return resultService.getResultsByModelId(modelId);
}
}

View File

@ -0,0 +1,36 @@
package com.worlabel.domain.result.entity;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonValue;
public enum Optimizer {
AUTO("AUTO"),
SGD("SGD"),
ADAM("ADAM"),
ADAMW("ADAMW"),
NADAM("NADAM"),
RADAM("RADAM"),
RMSPROP("RMSPROP");
private final String value;
Optimizer(String value) {
this.value = value;
}
@JsonCreator
public static Optimizer from(String value) {
for (Optimizer status : Optimizer.values()) {
if (status.getValue().equals(value.toUpperCase())) {
return status;
}
}
return null;
}
@JsonValue
public String getValue() {
return value;
}
}

View File

@ -0,0 +1,61 @@
package com.worlabel.domain.result.entity;
import com.worlabel.domain.model.entity.AiModel;
import com.worlabel.global.common.BaseEntity;
import jakarta.persistence.*;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor;
@Getter
@Entity
@Table(name = "result")
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Result extends BaseEntity {
@Id
@Column(name = "result_id", nullable = false)
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
/**
* 소속된 모델
*/
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "model_id", nullable = false)
private AiModel aiModel;
@Column(name = "precision", nullable = false)
private double precision;
@Column(name = "recall", nullable = false)
private double recall;
@Column(name = "mAP50", nullable = false)
private double mAP50;
@Column(name = "mAP50-95", nullable = false)
private double mAP5095;
@Column(name = "fitness", nullable = false)
private double fitness;
@Column(name = "ratio", nullable = false)
private double ratio;
@Column(name = "epochs", nullable = false)
private double epochs;
@Column(name = "batch", nullable = false)
private double batch;
@Column(name = "ir0", nullable = false)
private double ir0;
@Column(name = "irf", nullable = false)
private double irf;
@Column(name = "optimizer", nullable = false)
@Enumerated(EnumType.STRING)
private Optimizer optimizer;
}

View File

@ -0,0 +1,41 @@
package com.worlabel.domain.result.entity.dto;
import com.worlabel.domain.result.entity.Optimizer;
import com.worlabel.domain.result.entity.Result;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
@Getter
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public class ResultResponse {
private Integer id;
private double precision;
private double recall;
private double mAP50;
private double mAP5095;
private double fitness;
private double ratio;
private double epochs;
private double batch;
private double ir0;
private double irf;
private Optimizer optimizer;
public static ResultResponse fromResult(final Result result) {
return new ResultResponse(
result.getId(),
result.getPrecision(),
result.getRecall(),
result.getMAP50(),
result.getMAP5095(),
result.getFitness(),
result.getRatio(),
result.getEpochs(),
result.getBatch(),
result.getIr0(),
result.getIrf(),
result.getOptimizer());
}
}

View File

@ -0,0 +1,11 @@
package com.worlabel.domain.result.repository;
import com.worlabel.domain.result.entity.Result;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;
public interface ResultRepository extends JpaRepository<Result, Integer> {
List<Result> findByAiModelId(Integer modelId);
}

View File

@ -0,0 +1,25 @@
package com.worlabel.domain.result.service;
import com.worlabel.domain.result.entity.Result;
import com.worlabel.domain.result.entity.dto.ResultResponse;
import com.worlabel.domain.result.repository.ResultRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
@Service
@Transactional
@RequiredArgsConstructor
public class ResultService {
private final ResultRepository resultRepository;
public List<ResultResponse> getResultsByModelId(final Integer modelId) {
List<Result> results = resultRepository.findByAiModelId(modelId);
return results.stream()
.map(ResultResponse::fromResult)
.toList();
}
}