From 95094bf949f9edd9d6330715a60e3bb87b3b02e6 Mon Sep 17 00:00:00 2001 From: hardwoong Date: Mon, 27 Oct 2025 15:11:33 +0900 Subject: [PATCH 1/5] =?UTF-8?q?feat:=20=EB=9D=BC=EC=9D=B4=EB=B8=8C?= =?UTF-8?q?=EB=9F=AC=EB=A6=AC=20=EB=B9=84=EA=B5=90=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=ED=8B=80=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../library/controller/LibraryController.java | 57 ++++ .../library/dto/LibraryCompareRequestDTO.java | 26 ++ .../dto/LibraryCompareResponseDTO.java | 111 +++++++ .../library/service/LibraryService.java | 271 ++++++++++++++++++ .../panel/controller/PanelController.java | 9 - .../domain/panel/dto/PanelRequestDTO.java | 29 -- .../domain/panel/dto/PanelResponseDTO.java | 94 ------ .../global/fastapi/FastApiRequestType.java | 9 +- .../global/fastapi/FastApiService.java | 7 + .../dto/request/FastPanelRequestDTO.java | 5 +- .../FastLibraryCompareResponseDTO.java | 55 ++++ 11 files changed, 538 insertions(+), 135 deletions(-) create mode 100644 src/main/java/DiffLens/back_end/domain/library/dto/LibraryCompareRequestDTO.java create mode 100644 src/main/java/DiffLens/back_end/domain/library/dto/LibraryCompareResponseDTO.java delete mode 100644 src/main/java/DiffLens/back_end/domain/panel/dto/PanelRequestDTO.java create mode 100644 src/main/java/DiffLens/back_end/global/fastapi/dto/response/FastLibraryCompareResponseDTO.java diff --git a/src/main/java/DiffLens/back_end/domain/library/controller/LibraryController.java b/src/main/java/DiffLens/back_end/domain/library/controller/LibraryController.java index 3661da7..9ca8a30 100644 --- a/src/main/java/DiffLens/back_end/domain/library/controller/LibraryController.java +++ b/src/main/java/DiffLens/back_end/domain/library/controller/LibraryController.java @@ -2,6 +2,8 @@ import DiffLens.back_end.domain.library.dto.LibraryRequestDto; import DiffLens.back_end.domain.library.dto.LibraryResponseDTO; +import DiffLens.back_end.domain.library.dto.LibraryCompareRequestDTO; +import DiffLens.back_end.domain.library.dto.LibraryCompareResponseDTO; import DiffLens.back_end.domain.library.service.LibraryService; import DiffLens.back_end.domain.members.entity.Member; import DiffLens.back_end.domain.members.service.auth.CurrentUserService; @@ -148,4 +150,59 @@ public ApiResponse addSearchHistoryToLibrary( createResult.getPanelCount()); return ApiResponse.onSuccess(result); } + + @PostMapping("/compare") + @Operation(summary = "라이브러리 비교", description = """ + ## 개요 + 두 개의 라이브러리를 비교하여 특성, 차트, 기본 통계를 제공하는 API입니다. + + ## Request Body + - libraryId1 : 첫 번째 라이브러리 ID (필수) + - libraryId2 : 두 번째 라이브러리 ID (필수) + + ## 응답 데이터 + - group1, group2 : 각 라이브러리 기본 정보 + - keyCharacteristics : 주요 특성 비교 (차이점 포함) + - comparisonCharts : 비교 차트 데이터 (Chart.js 형식) + - basicComparison : 기본 통계 비교 + + ## 권한 + 본인이 생성한 라이브러리만 비교할 수 있습니다. + + ## 제약사항 + - 동일한 라이브러리는 비교할 수 없습니다. + - 두 라이브러리 모두 존재해야 합니다. + + """) + public ApiResponse compareLibraries( + @RequestBody @Valid LibraryCompareRequestDTO.Compare request) { + Member member = currentUserService.getCurrentUser(); + LibraryCompareResponseDTO.CompareResult result = libraryService.compareLibraries(request, member); + return ApiResponse.onSuccess(result); + } + + @PostMapping("/compare/test") + @Operation(summary = "라이브러리 비교 (테스트용)", description = """ + ## 개요 + AI 서버 연동 없이 하드코딩된 테스트 데이터로 라이브러리 비교를 제공하는 API입니다. + 개발 및 테스트 목적으로 사용됩니다. + + ## Request Body + - libraryId1 : 첫 번째 라이브러리 ID (필수) + - libraryId2 : 두 번째 라이브러리 ID (필수) + + ## 응답 데이터 + - 하드코딩된 테스트 데이터 반환 + - 실제 라이브러리 데이터는 사용하지 않음 + + ## 권한 + 인증된 사용자만 접근 가능합니다. + + """) + public ApiResponse compareLibrariesTest( + @RequestBody @Valid LibraryCompareRequestDTO.Compare request) { + Member member = currentUserService.getCurrentUser(); + LibraryCompareResponseDTO.CompareResult result = libraryService.compareLibrariesTest(request, member); + return ApiResponse.onSuccess(result); + } } diff --git a/src/main/java/DiffLens/back_end/domain/library/dto/LibraryCompareRequestDTO.java b/src/main/java/DiffLens/back_end/domain/library/dto/LibraryCompareRequestDTO.java new file mode 100644 index 0000000..f461fb7 --- /dev/null +++ b/src/main/java/DiffLens/back_end/domain/library/dto/LibraryCompareRequestDTO.java @@ -0,0 +1,26 @@ +package DiffLens.back_end.domain.library.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +public class LibraryCompareRequestDTO { + + @Getter + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class Compare { + + @NotNull(message = "첫 번째 라이브러리 ID는 필수입니다") + @JsonProperty("libraryId1") + private Long libraryId1; + + @NotNull(message = "두 번째 라이브러리 ID는 필수입니다") + @JsonProperty("libraryId2") + private Long libraryId2; + } +} diff --git a/src/main/java/DiffLens/back_end/domain/library/dto/LibraryCompareResponseDTO.java b/src/main/java/DiffLens/back_end/domain/library/dto/LibraryCompareResponseDTO.java new file mode 100644 index 0000000..a917505 --- /dev/null +++ b/src/main/java/DiffLens/back_end/domain/library/dto/LibraryCompareResponseDTO.java @@ -0,0 +1,111 @@ +package DiffLens.back_end.domain.library.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +import java.util.List; +import java.util.Map; + +public class LibraryCompareResponseDTO { + + @Getter + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class CompareResult { + + @JsonProperty("group1") + private GroupInfo group1; + + @JsonProperty("group2") + private GroupInfo group2; + + @JsonProperty("keyCharacteristics") + private List keyCharacteristics; + + @JsonProperty("comparisonCharts") + private List comparisonCharts; + + @JsonProperty("basicComparison") + private List basicComparison; + } + + @Getter + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class GroupInfo { + + @JsonProperty("libraryId") + private Long libraryId; + + @JsonProperty("libraryName") + private String libraryName; + + @JsonProperty("totalCount") + private Integer totalCount; + + @JsonProperty("color") + private String color; + } + + @Getter + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class KeyCharacteristic { + + @JsonProperty("characteristic") + private String characteristic; + + @JsonProperty("description") + private String description; + + @JsonProperty("group1Percentage") + private Integer group1Percentage; + + @JsonProperty("group2Percentage") + private Integer group2Percentage; + + @JsonProperty("difference") + private Integer difference; + } + + @Getter + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class ComparisonChart { + + @JsonProperty("chartType") + private String chartType; + + @JsonProperty("title") + private String title; + + @JsonProperty("data") + private Map data; + + @JsonProperty("options") + private Map options; + } + + @Getter + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class BasicComparison { + + @JsonProperty("metric") + private String metric; + + @JsonProperty("group1Value") + private String group1Value; + + @JsonProperty("group2Value") + private String group2Value; + } +} diff --git a/src/main/java/DiffLens/back_end/domain/library/service/LibraryService.java b/src/main/java/DiffLens/back_end/domain/library/service/LibraryService.java index 3879087..17e7bca 100644 --- a/src/main/java/DiffLens/back_end/domain/library/service/LibraryService.java +++ b/src/main/java/DiffLens/back_end/domain/library/service/LibraryService.java @@ -2,6 +2,8 @@ import DiffLens.back_end.domain.library.dto.LibraryRequestDto; import DiffLens.back_end.domain.library.dto.LibraryResponseDTO; +import DiffLens.back_end.domain.library.dto.LibraryCompareRequestDTO; +import DiffLens.back_end.domain.library.dto.LibraryCompareResponseDTO; import DiffLens.back_end.domain.library.entity.Library; import DiffLens.back_end.domain.library.entity.LibraryPanel; import DiffLens.back_end.domain.library.entity.LibraryPanelKey; @@ -15,6 +17,9 @@ import DiffLens.back_end.domain.panel.repository.PanelRepository; import DiffLens.back_end.domain.search.entity.SearchHistory; import DiffLens.back_end.domain.search.repository.SearchHistoryRepository; +import DiffLens.back_end.global.fastapi.FastApiService; +import DiffLens.back_end.global.fastapi.dto.request.FastPanelRequestDTO; +import DiffLens.back_end.global.fastapi.dto.response.FastLibraryCompareResponseDTO; import DiffLens.back_end.global.responses.code.status.error.ErrorStatus; import DiffLens.back_end.global.responses.exception.handler.ErrorHandler; import lombok.RequiredArgsConstructor; @@ -22,6 +27,7 @@ import org.springframework.transaction.annotation.Transactional; import java.util.List; +import java.util.Map; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -34,6 +40,7 @@ public class LibraryService { private final SearchHistoryLibraryRepository searchHistoryLibraryRepository; private final SearchHistoryRepository searchHistoryRepository; private final PanelRepository panelRepository; + private final FastApiService fastApiService; @Transactional public LibraryCreateResult createLibrary(LibraryRequestDto.Create request, Member member) { @@ -284,6 +291,270 @@ private LibraryResponseDTO.LibraryDetail.Statistics createStatistics(List .build(); } + @Transactional(readOnly = true) + public LibraryCompareResponseDTO.CompareResult compareLibraries(LibraryCompareRequestDTO.Compare request, + Member member) { + // 1. 요청 검증 - 같은 라이브러리 비교 불가 + if (request.getLibraryId1().equals(request.getLibraryId2())) { + throw new ErrorHandler(ErrorStatus.BAD_REQUEST); + } + + // 2. 라이브러리 조회 및 권한 확인 + Library library1 = libraryRepository.findById(request.getLibraryId1()) + .orElseThrow(() -> new ErrorHandler(ErrorStatus.BAD_REQUEST)); + + Library library2 = libraryRepository.findById(request.getLibraryId2()) + .orElseThrow(() -> new ErrorHandler(ErrorStatus.BAD_REQUEST)); + + // 3. 권한 검증 - 본인의 라이브러리만 비교 가능 + if (!library1.getMember().getId().equals(member.getId()) || + !library2.getMember().getId().equals(member.getId())) { + throw new ErrorHandler(ErrorStatus.FORBIDDEN); + } + + // 4. FastAPI 서버로 비교 요청 + FastPanelRequestDTO.FastLibraryCompare fastApiRequest = FastPanelRequestDTO.FastLibraryCompare.builder() + .libraryId1(library1.getId()) + .libraryId2(library2.getId()) + .panelIds1(library1.getPanelIds()) + .panelIds2(library2.getPanelIds()) + .build(); + + FastLibraryCompareResponseDTO.CompareResult fastApiResponse = fastApiService + .compareLibraries(fastApiRequest); + + // 5. 응답 데이터 구성 + return LibraryCompareResponseDTO.CompareResult.builder() + .group1(LibraryCompareResponseDTO.GroupInfo.builder() + .libraryId(library1.getId()) + .libraryName(library1.getLibraryName()) + .totalCount(library1.getPanelIds().size()) + .color("#4169E1") + .build()) + .group2(LibraryCompareResponseDTO.GroupInfo.builder() + .libraryId(library2.getId()) + .libraryName(library2.getLibraryName()) + .totalCount(library2.getPanelIds().size()) + .color("#32CD32") + .build()) + .keyCharacteristics(convertKeyCharacteristics(fastApiResponse.getKeyCharacteristics())) + .comparisonCharts(convertComparisonCharts(fastApiResponse.getComparisonCharts())) + .basicComparison(convertBasicComparison(fastApiResponse.getBasicComparison())) + .build(); + } + + @Transactional(readOnly = true) + public LibraryCompareResponseDTO.CompareResult compareLibrariesTest(LibraryCompareRequestDTO.Compare request, + Member member) { + // 1. 요청 검증 - 같은 라이브러리 비교 불가 + if (request.getLibraryId1().equals(request.getLibraryId2())) { + throw new ErrorHandler(ErrorStatus.BAD_REQUEST); + } + + // 2. 라이브러리 조회 및 권한 확인 (실제 데이터는 사용하지 않지만 검증은 함) + Library library1 = libraryRepository.findById(request.getLibraryId1()) + .orElseThrow(() -> new ErrorHandler(ErrorStatus.BAD_REQUEST)); + + Library library2 = libraryRepository.findById(request.getLibraryId2()) + .orElseThrow(() -> new ErrorHandler(ErrorStatus.BAD_REQUEST)); + + // 3. 권한 검증 - 본인의 라이브러리만 비교 가능 + if (!library1.getMember().getId().equals(member.getId()) || + !library2.getMember().getId().equals(member.getId())) { + throw new ErrorHandler(ErrorStatus.FORBIDDEN); + } + + // 4. 하드코딩된 테스트 데이터 반환 + return createTestCompareResult(library1, library2); + } + + private LibraryCompareResponseDTO.CompareResult createTestCompareResult(Library library1, Library library2) { + // 하드코딩된 테스트 데이터 생성 + List keyCharacteristics = List.of( + LibraryCompareResponseDTO.KeyCharacteristic.builder() + .characteristic("특성1") + .description("차량 보유율") + .group1Percentage(30) + .group2Percentage(70) + .difference(40) + .build(), + LibraryCompareResponseDTO.KeyCharacteristic.builder() + .characteristic("특성2") + .description("고소득 비율") + .group1Percentage(32) + .group2Percentage(68) + .difference(36) + .build(), + LibraryCompareResponseDTO.KeyCharacteristic.builder() + .characteristic("특성3") + .description("기혼 비율") + .group1Percentage(32) + .group2Percentage(68) + .difference(36) + .build(), + LibraryCompareResponseDTO.KeyCharacteristic.builder() + .characteristic("특성4") + .description("OTT 구독률") + .group1Percentage(40) + .group2Percentage(60) + .difference(20) + .build(), + LibraryCompareResponseDTO.KeyCharacteristic.builder() + .characteristic("특성5") + .description("해외여행 경험") + .group1Percentage(47) + .group2Percentage(53) + .difference(6) + .build()); + + List comparisonCharts = List.of( + LibraryCompareResponseDTO.ComparisonChart.builder() + .chartType("bar") + .title("직업 분포") + .data(Map.of( + "labels", List.of("경영/관리직", "사무직", "자영업", "학생", "프리랜서"), + "datasets", List.of( + Map.of( + "label", "20대 남성", + "data", + List.of(10, 45, 20, 15, + 10), + "backgroundColor", + "#4169E1"), + Map.of( + "label", "40대 여성", + "data", + List.of(25, 50, 15, 5, + 5), + "backgroundColor", + "#32CD32")))) + .options(Map.of( + "scales", Map.of( + "y", Map.of( + "beginAtZero", true, + "title", Map.of( + "display", + true, + "text", + "패널 수 (%)"))), + "plugins", Map.of( + "legend", Map.of("position", "top")))) + .build(), + LibraryCompareResponseDTO.ComparisonChart.builder() + .chartType("line") + .title("월평균 개인소득") + .data(Map.of( + "labels", List.of( + "100만원 미만", "100-199만원", "200-299만원", + "300-399만원", "400-499만원", "500만원 이상"), + "datasets", List.of( + Map.of( + "label", "20대 남성", + "data", + List.of(5, 15, 25, 30, + 20, 5), + "borderColor", + "#4169E1", + "backgroundColor", + "rgba(65, 105, 225, 0.1)", + "tension", 0.4, + "fill", true), + Map.of( + "label", "40대 여성", + "data", + List.of(2, 8, 15, 25, + 30, 20), + "borderColor", + "#32CD32", + "backgroundColor", + "rgba(50, 205, 50, 0.1)", + "tension", 0.4, + "fill", true)))) + .options(Map.of( + "scales", Map.of( + "y", Map.of( + "beginAtZero", true, + "title", Map.of( + "display", + true, + "text", + "패널 수 (%)"))), + "plugins", Map.of( + "legend", Map.of("position", "top")))) + .build()); + + List basicComparison = List.of( + LibraryCompareResponseDTO.BasicComparison.builder() + .metric("평균 연령") + .group1Value("24.5세") + .group2Value("43.2세") + .build(), + LibraryCompareResponseDTO.BasicComparison.builder() + .metric("평균 소득") + .group1Value("250만원") + .group2Value("320만원") + .build(), + LibraryCompareResponseDTO.BasicComparison.builder() + .metric("기혼 비율") + .group1Value("15%") + .group2Value("85%") + .build()); + + return LibraryCompareResponseDTO.CompareResult.builder() + .group1(LibraryCompareResponseDTO.GroupInfo.builder() + .libraryId(library1.getId()) + .libraryName(library1.getLibraryName()) + .totalCount(library1.getPanelIds().size()) + .color("#4169E1") + .build()) + .group2(LibraryCompareResponseDTO.GroupInfo.builder() + .libraryId(library2.getId()) + .libraryName(library2.getLibraryName()) + .totalCount(library2.getPanelIds().size()) + .color("#32CD32") + .build()) + .keyCharacteristics(keyCharacteristics) + .comparisonCharts(comparisonCharts) + .basicComparison(basicComparison) + .build(); + } + + private List convertKeyCharacteristics( + List fastApiCharacteristics) { + return fastApiCharacteristics.stream() + .map(fast -> LibraryCompareResponseDTO.KeyCharacteristic.builder() + .characteristic(fast.getCharacteristic()) + .description(fast.getDescription()) + .group1Percentage(fast.getGroup1Percentage()) + .group2Percentage(fast.getGroup2Percentage()) + .difference(fast.getDifference()) + .build()) + .toList(); + } + + private List convertComparisonCharts( + List fastApiCharts) { + return fastApiCharts.stream() + .map(fast -> LibraryCompareResponseDTO.ComparisonChart.builder() + .chartType(fast.getChartType()) + .title(fast.getTitle()) + .data(fast.getData()) + .options(fast.getOptions()) + .build()) + .toList(); + } + + private List convertBasicComparison( + List fastApiComparison) { + return fastApiComparison.stream() + .map(fast -> LibraryCompareResponseDTO.BasicComparison.builder() + .metric(fast.getMetric()) + .group1Value(fast.getGroup1Value()) + .group2Value(fast.getGroup2Value()) + .build()) + .toList(); + } + private void createLibraryPanels(Library library, List panelIds) { List panels = panelRepository.findByIdList(panelIds); diff --git a/src/main/java/DiffLens/back_end/domain/panel/controller/PanelController.java b/src/main/java/DiffLens/back_end/domain/panel/controller/PanelController.java index b0c6373..a11a45e 100644 --- a/src/main/java/DiffLens/back_end/domain/panel/controller/PanelController.java +++ b/src/main/java/DiffLens/back_end/domain/panel/controller/PanelController.java @@ -1,6 +1,5 @@ package DiffLens.back_end.domain.panel.controller; -import DiffLens.back_end.domain.panel.dto.PanelRequestDTO; import DiffLens.back_end.domain.panel.dto.PanelResponseDTO; import DiffLens.back_end.domain.panel.service.PanelService; import DiffLens.back_end.global.responses.exception.ApiResponse; @@ -36,12 +35,4 @@ public ApiResponse details(@PathVariable("panelId return ApiResponse.onSuccess(result); } - @PostMapping("/compare") - @Operation(summary = "패널 그룹 비교 분석 ( 미구현 ) ") - public ApiResponse groupCompare( - @RequestBody @Valid PanelRequestDTO.GroupAnal request) { - PanelResponseDTO.GroupCompare result = new PanelResponseDTO.GroupCompare(); - return ApiResponse.onSuccess(result); - } - } diff --git a/src/main/java/DiffLens/back_end/domain/panel/dto/PanelRequestDTO.java b/src/main/java/DiffLens/back_end/domain/panel/dto/PanelRequestDTO.java deleted file mode 100644 index 6d9f0b6..0000000 --- a/src/main/java/DiffLens/back_end/domain/panel/dto/PanelRequestDTO.java +++ /dev/null @@ -1,29 +0,0 @@ -package DiffLens.back_end.domain.panel.dto; - -import com.fasterxml.jackson.annotation.JsonProperty; -import jakarta.validation.constraints.NotNull; -import lombok.Getter; -import lombok.Setter; - -import java.util.List; - -public class PanelRequestDTO { - - @Setter - @Getter - public static class GroupAnal{ - - @NotNull - @JsonProperty("library_a_id") - private Long libraryAId; - - @NotNull - @JsonProperty("library_b_id") - private Long libraryBId; - - @JsonProperty("comparison_metrics") - private List comparisonMetrics; - - } - -} diff --git a/src/main/java/DiffLens/back_end/domain/panel/dto/PanelResponseDTO.java b/src/main/java/DiffLens/back_end/domain/panel/dto/PanelResponseDTO.java index f02aae5..f954139 100644 --- a/src/main/java/DiffLens/back_end/domain/panel/dto/PanelResponseDTO.java +++ b/src/main/java/DiffLens/back_end/domain/panel/dto/PanelResponseDTO.java @@ -70,98 +70,4 @@ public static class Attribute { } } - - @Getter - @Builder - @NoArgsConstructor - @AllArgsConstructor - public static class GroupCompare { - - @JsonProperty("library_a_id") - private LibraryInfo libraryA; - - @JsonProperty("library_b_id") - private LibraryInfo libraryB; - - @JsonProperty("feature_comparison") - private List featureComparison; - - @JsonProperty("comparison_charts") - private List comparisonCharts; - - @JsonProperty("basic_comparison") - private List basicComparison; - - @Getter - @Builder - @NoArgsConstructor - @AllArgsConstructor - public static class LibraryInfo { - private Long id; - private String name; - } - - @Getter - @Builder - @NoArgsConstructor - @AllArgsConstructor - public static class FeatureComparison { - @JsonProperty("feature_name") - private String featureName; - - @JsonProperty("a_value") - private Double aValue; - - @JsonProperty("b_value") - private Double bValue; - } - - @Getter - @Builder - @NoArgsConstructor - @AllArgsConstructor - public static class ComparisonChart { - @JsonProperty("chart_type") - private String chartType; - - private String title; - - @JsonProperty("data_points") - private List dataPoints; - - @Getter - @Builder - @NoArgsConstructor - @AllArgsConstructor - public static class DataPoint { - private String label; - @JsonProperty("group_a") - private Double groupA; - @JsonProperty("group_b") - private Double groupB; - - @JsonProperty("month") - private String month; - @JsonProperty("a_income") - private Integer aIncome; - @JsonProperty("b_income") - private Integer bIncome; - } - } - - @Getter - @Builder - @NoArgsConstructor - @AllArgsConstructor - public static class BasicComparison { - private String metric; - - @JsonProperty("a_value") - private Double aValue; - - @JsonProperty("b_value") - private Double bValue; - } - } - } diff --git a/src/main/java/DiffLens/back_end/global/fastapi/FastApiRequestType.java b/src/main/java/DiffLens/back_end/global/fastapi/FastApiRequestType.java index 1efcacc..0823979 100644 --- a/src/main/java/DiffLens/back_end/global/fastapi/FastApiRequestType.java +++ b/src/main/java/DiffLens/back_end/global/fastapi/FastApiRequestType.java @@ -2,6 +2,7 @@ import DiffLens.back_end.global.fastapi.dto.request.FastPanelRequestDTO; import DiffLens.back_end.global.fastapi.dto.response.FastNaturalSearchResponseDTO; +import DiffLens.back_end.global.fastapi.dto.response.FastLibraryCompareResponseDTO; import lombok.AllArgsConstructor; import lombok.Getter; @@ -9,8 +10,12 @@ @AllArgsConstructor public enum FastApiRequestType { - NATURAL_SEARCH("/search/natural", FastPanelRequestDTO.FastNaturalSearch.class, FastNaturalSearchResponseDTO.SearchResult.class), -// REFINE_SEARCH("/search/refine", FastNaturalSearchResponseDTO.SearchResult.class), + NATURAL_SEARCH("/search/natural", FastPanelRequestDTO.FastNaturalSearch.class, + FastNaturalSearchResponseDTO.SearchResult.class), + LIBRARY_COMPARE("/libraries/compare", FastPanelRequestDTO.FastLibraryCompare.class, + FastLibraryCompareResponseDTO.CompareResult.class), + // REFINE_SEARCH("/search/refine", + // FastNaturalSearchResponseDTO.SearchResult.class), ; private final String uri; diff --git a/src/main/java/DiffLens/back_end/global/fastapi/FastApiService.java b/src/main/java/DiffLens/back_end/global/fastapi/FastApiService.java index bad2409..0720e99 100644 --- a/src/main/java/DiffLens/back_end/global/fastapi/FastApiService.java +++ b/src/main/java/DiffLens/back_end/global/fastapi/FastApiService.java @@ -2,6 +2,7 @@ import DiffLens.back_end.global.fastapi.dto.request.FastPanelRequestDTO; import DiffLens.back_end.global.fastapi.dto.response.FastNaturalSearchResponseDTO; +import DiffLens.back_end.global.fastapi.dto.response.FastLibraryCompareResponseDTO; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; @@ -19,4 +20,10 @@ public FastNaturalSearchResponseDTO.SearchResult getNaturalSearch(FastPanelReque return fastApiClient.sendRequest(FastApiRequestType.NATURAL_SEARCH, request); } + // 라이브러리 비교 + public FastLibraryCompareResponseDTO.CompareResult compareLibraries( + FastPanelRequestDTO.FastLibraryCompare request) { + return fastApiClient.sendRequest(FastApiRequestType.LIBRARY_COMPARE, request); + } + } diff --git a/src/main/java/DiffLens/back_end/global/fastapi/dto/request/FastPanelRequestDTO.java b/src/main/java/DiffLens/back_end/global/fastapi/dto/request/FastPanelRequestDTO.java index cfecc6c..e33fc92 100644 --- a/src/main/java/DiffLens/back_end/global/fastapi/dto/request/FastPanelRequestDTO.java +++ b/src/main/java/DiffLens/back_end/global/fastapi/dto/request/FastPanelRequestDTO.java @@ -71,7 +71,10 @@ public static class FastRecommendation { @NoArgsConstructor public static class FastLibraryCompare { - private String tempColumn; + private Long libraryId1; + private Long libraryId2; + private List panelIds1; + private List panelIds2; } diff --git a/src/main/java/DiffLens/back_end/global/fastapi/dto/response/FastLibraryCompareResponseDTO.java b/src/main/java/DiffLens/back_end/global/fastapi/dto/response/FastLibraryCompareResponseDTO.java new file mode 100644 index 0000000..bb2e73a --- /dev/null +++ b/src/main/java/DiffLens/back_end/global/fastapi/dto/response/FastLibraryCompareResponseDTO.java @@ -0,0 +1,55 @@ +package DiffLens.back_end.global.fastapi.dto.response; + +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; + +import java.util.List; +import java.util.Map; + +/** + * Fast API -> Spring Boot 응답 형태 + * 라이브러리 비교 응답 + */ +public class FastLibraryCompareResponseDTO { + + @Getter + @Setter + @ToString + public static class CompareResult { + + private List keyCharacteristics; + private List comparisonCharts; + private List basicComparison; + } + + @Getter + @Setter + @ToString + public static class KeyCharacteristic { + private String characteristic; + private String description; + private Integer group1Percentage; + private Integer group2Percentage; + private Integer difference; + } + + @Getter + @Setter + @ToString + public static class ComparisonChart { + private String chartType; + private String title; + private Map data; + private Map options; + } + + @Getter + @Setter + @ToString + public static class BasicComparison { + private String metric; + private String group1Value; + private String group2Value; + } +} From 656f7dea8acab11ec824f74ad8d8bee28c770225 Mon Sep 17 00:00:00 2001 From: junyong Date: Mon, 27 Oct 2025 15:40:38 +0900 Subject: [PATCH 2/5] =?UTF-8?q?feat=20:=20=EB=A9=94=EC=9D=B8=20<->=20?= =?UTF-8?q?=EC=84=9C=EB=B8=8C=20=EC=84=9C=EB=B2=84=20=EA=B0=84=20=EC=86=8C?= =?UTF-8?q?=ED=86=B5=20dto=20=EC=9E=91=EC=84=B1=20=20=20-=20=EC=9E=90?= =?UTF-8?q?=EC=97=B0=EC=96=B4=20=EA=B2=80=EC=83=89=20dto=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD=EC=9C=BC=EB=A1=9C=20=EC=9D=B8=ED=95=9C=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20=EC=88=98=EC=A0=95=20=ED=8F=AC=ED=95=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../search/converter/FilterDtoConverter.java | 6 +- .../converter/PanelResponseConverter.java | 7 +- .../search/converter/SummaryDtoConverter.java | 7 +- .../domain/search/enums/chart/ChartType.java | 4 +- .../service/implement/ChartServiceImpl.java | 20 ++-- .../implement/NaturalSearchService.java | 28 +++--- .../implement/SearchHistoryServiceImpl.java | 8 +- .../service/interfaces/ChartService.java | 5 +- .../interfaces/SearchHistoryService.java | 4 +- .../global/fastapi/FastApiRequestType.java | 14 ++- .../global/fastapi/FastApiService.java | 6 +- .../dto/request/FastHomeRequestDTO.java | 37 ++++++++ .../dto/request/FastLibraryRequestDTO.java | 29 ++++++ .../FastNaturalLanguageRequestDTO.java | 47 ++++++++++ .../dto/request/FastPanelRequestDTO.java | 94 ------------------- .../dto/request/FastReSearchRequestDTO.java | 39 ++++++++ .../dto/response/FastHomeResponseDTO.java | 49 ++++++++++ ...va => FastNaturalLanguageResponseDTO.java} | 48 ++++++++-- .../dto/response/FastReSearchResponseDTO.java | 28 ++++++ .../fastapi/dto/response/FastSearchChart.java | 61 ++++++++++++ 20 files changed, 388 insertions(+), 153 deletions(-) create mode 100644 src/main/java/DiffLens/back_end/global/fastapi/dto/request/FastHomeRequestDTO.java create mode 100644 src/main/java/DiffLens/back_end/global/fastapi/dto/request/FastLibraryRequestDTO.java create mode 100644 src/main/java/DiffLens/back_end/global/fastapi/dto/request/FastNaturalLanguageRequestDTO.java delete mode 100644 src/main/java/DiffLens/back_end/global/fastapi/dto/request/FastPanelRequestDTO.java create mode 100644 src/main/java/DiffLens/back_end/global/fastapi/dto/request/FastReSearchRequestDTO.java create mode 100644 src/main/java/DiffLens/back_end/global/fastapi/dto/response/FastHomeResponseDTO.java rename src/main/java/DiffLens/back_end/global/fastapi/dto/response/{FastNaturalSearchResponseDTO.java => FastNaturalLanguageResponseDTO.java} (54%) create mode 100644 src/main/java/DiffLens/back_end/global/fastapi/dto/response/FastReSearchResponseDTO.java create mode 100644 src/main/java/DiffLens/back_end/global/fastapi/dto/response/FastSearchChart.java diff --git a/src/main/java/DiffLens/back_end/domain/search/converter/FilterDtoConverter.java b/src/main/java/DiffLens/back_end/domain/search/converter/FilterDtoConverter.java index 988096b..f24fd57 100644 --- a/src/main/java/DiffLens/back_end/domain/search/converter/FilterDtoConverter.java +++ b/src/main/java/DiffLens/back_end/domain/search/converter/FilterDtoConverter.java @@ -1,6 +1,6 @@ package DiffLens.back_end.domain.search.converter; -import DiffLens.back_end.global.fastapi.dto.response.FastNaturalSearchResponseDTO; +import DiffLens.back_end.global.fastapi.dto.response.FastNaturalLanguageResponseDTO; import DiffLens.back_end.domain.search.dto.SearchResponseDTO.SearchResult.AppliedFilter; import DiffLens.back_end.domain.search.entity.Filter; import DiffLens.back_end.domain.search.entity.SearchHistory; @@ -12,12 +12,12 @@ @Component @RequiredArgsConstructor -public class FilterDtoConverter implements SearchDtoConverter, SearchHistory>{ +public class FilterDtoConverter implements SearchDtoConverter, SearchHistory>{ private final FilterService filterService; @Override - public List requestToDto(FastNaturalSearchResponseDTO.SearchResult response, SearchHistory searchHistory) { + public List requestToDto(FastNaturalLanguageResponseDTO.NaturalSearch response, SearchHistory searchHistory) { List filterIdList = searchHistory.getSearchFilter().getFilters(); List filters = filterService.findFilters(filterIdList); diff --git a/src/main/java/DiffLens/back_end/domain/search/converter/PanelResponseConverter.java b/src/main/java/DiffLens/back_end/domain/search/converter/PanelResponseConverter.java index 0a7c941..45875e1 100644 --- a/src/main/java/DiffLens/back_end/domain/search/converter/PanelResponseConverter.java +++ b/src/main/java/DiffLens/back_end/domain/search/converter/PanelResponseConverter.java @@ -1,17 +1,16 @@ package DiffLens.back_end.domain.search.converter; import DiffLens.back_end.domain.panel.repository.projection.PanelWithRawDataDTO; -import DiffLens.back_end.global.fastapi.dto.response.FastNaturalSearchResponseDTO; -import DiffLens.back_end.domain.panel.entity.Panel; +import DiffLens.back_end.global.fastapi.dto.response.FastNaturalLanguageResponseDTO; import DiffLens.back_end.domain.search.dto.SearchPanelDTO; import org.springframework.stereotype.Component; import java.util.List; @Component -public class PanelResponseConverter implements SearchDtoConverter>{ +public class PanelResponseConverter implements SearchDtoConverter>{ @Override - public SearchPanelDTO.PanelData requestToDto(FastNaturalSearchResponseDTO.SearchResult response, List info) { + public SearchPanelDTO.PanelData requestToDto(FastNaturalLanguageResponseDTO.NaturalSearch response, List info) { // TODO : 개별 응답데이터 처리 로직 작성 return new SearchPanelDTO.PanelData(); } diff --git a/src/main/java/DiffLens/back_end/domain/search/converter/SummaryDtoConverter.java b/src/main/java/DiffLens/back_end/domain/search/converter/SummaryDtoConverter.java index 34cb5d5..288b9a1 100644 --- a/src/main/java/DiffLens/back_end/domain/search/converter/SummaryDtoConverter.java +++ b/src/main/java/DiffLens/back_end/domain/search/converter/SummaryDtoConverter.java @@ -2,8 +2,7 @@ import DiffLens.back_end.domain.panel.repository.projection.PanelWithRawDataDTO; -import DiffLens.back_end.global.fastapi.dto.response.FastNaturalSearchResponseDTO; -import DiffLens.back_end.domain.panel.entity.Panel; +import DiffLens.back_end.global.fastapi.dto.response.FastNaturalLanguageResponseDTO; import DiffLens.back_end.domain.search.dto.SearchResponseDTO; import org.springframework.stereotype.Component; @@ -12,10 +11,10 @@ import java.util.List; @Component -public class SummaryDtoConverter implements SearchDtoConverter> { +public class SummaryDtoConverter implements SearchDtoConverter> { @Override - public SearchResponseDTO.SearchResult.Summary requestToDto(FastNaturalSearchResponseDTO.SearchResult response, List panelList) { + public SearchResponseDTO.SearchResult.Summary requestToDto(FastNaturalLanguageResponseDTO.Data response, List panelList) { return SearchResponseDTO.SearchResult.Summary.builder() .totalRespondents(panelList.size()) diff --git a/src/main/java/DiffLens/back_end/domain/search/enums/chart/ChartType.java b/src/main/java/DiffLens/back_end/domain/search/enums/chart/ChartType.java index c38c725..1044464 100644 --- a/src/main/java/DiffLens/back_end/domain/search/enums/chart/ChartType.java +++ b/src/main/java/DiffLens/back_end/domain/search/enums/chart/ChartType.java @@ -8,7 +8,9 @@ public enum ChartType { BAR, - PIE + PIE, + DOUGHNUT, + ; diff --git a/src/main/java/DiffLens/back_end/domain/search/service/implement/ChartServiceImpl.java b/src/main/java/DiffLens/back_end/domain/search/service/implement/ChartServiceImpl.java index 823124d..8c0982d 100644 --- a/src/main/java/DiffLens/back_end/domain/search/service/implement/ChartServiceImpl.java +++ b/src/main/java/DiffLens/back_end/domain/search/service/implement/ChartServiceImpl.java @@ -2,12 +2,13 @@ import DiffLens.back_end.domain.panel.repository.projection.PanelWithRawDataDTO; import DiffLens.back_end.domain.rawData.dto.PanelDTO; -import DiffLens.back_end.global.fastapi.dto.response.FastNaturalSearchResponseDTO; +import DiffLens.back_end.global.fastapi.dto.response.FastNaturalLanguageResponseDTO; import DiffLens.back_end.domain.panel.util.ReflectionUtil; import DiffLens.back_end.domain.search.entity.Chart; import DiffLens.back_end.domain.search.entity.SearchHistory; import DiffLens.back_end.domain.search.enums.chart.ChartType; import DiffLens.back_end.domain.search.service.interfaces.ChartService; +import DiffLens.back_end.global.fastapi.dto.response.FastSearchChart; import DiffLens.back_end.global.responses.code.status.error.SearchStatus; import DiffLens.back_end.global.responses.exception.handler.ErrorHandler; import lombok.RequiredArgsConstructor; @@ -15,29 +16,28 @@ import java.util.*; -import static java.util.Map.entry; - @Service @RequiredArgsConstructor public class ChartServiceImpl implements ChartService { @Override - public List makeChart(FastNaturalSearchResponseDTO.SearchResult searchResult, SearchHistory searchHistory, List foundPanels) { + public List makeChart(FastNaturalLanguageResponseDTO.Data naturalSearch, SearchHistory searchHistory, List foundPanels) { - List fastApiChartResponse = searchResult.getCharts(); + List chartResponses = new ArrayList<>(List.of(naturalSearch.getMainChart())); + chartResponses.addAll(naturalSearch.getSubCharts()); // fast api 로부터 받은 응답값을 List로 변환 - List charts = fastApiChartResponse.stream() + List charts = chartResponses.stream() .map(chart -> Chart.builder() .reason(chart.getReason()) .chartType(ChartType.valueOf(chart.getChartType().toUpperCase())) .panelColumn(chart.getPanelColumn()) .title(chart.getTitle()) - .xAxis(chart.getXaxis()) - .yAxis(chart.getYaxis()) - .labels(new ArrayList<>()) - .values(new ArrayList<>()) + .xAxis("TODO : 있어야하나??") + .yAxis("TODO : 있어야하나?? ver.2") + .labels(chart.getData().getLabels()) + .values(chart.getData().getDataSets().getFirst().getData()) // 기획에 따라 getFirst 없애고 전부 넣을수도 있음 .build() ).toList(); diff --git a/src/main/java/DiffLens/back_end/domain/search/service/implement/NaturalSearchService.java b/src/main/java/DiffLens/back_end/domain/search/service/implement/NaturalSearchService.java index a02fd02..dd2f72f 100644 --- a/src/main/java/DiffLens/back_end/domain/search/service/implement/NaturalSearchService.java +++ b/src/main/java/DiffLens/back_end/domain/search/service/implement/NaturalSearchService.java @@ -5,8 +5,8 @@ import DiffLens.back_end.domain.panel.repository.PanelRepository; import DiffLens.back_end.domain.panel.repository.projection.PanelWithRawDataDTO; import DiffLens.back_end.global.fastapi.FastApiService; -import DiffLens.back_end.global.fastapi.dto.request.FastPanelRequestDTO; -import DiffLens.back_end.global.fastapi.dto.response.FastNaturalSearchResponseDTO; +import DiffLens.back_end.global.fastapi.dto.request.FastNaturalLanguageRequestDTO; +import DiffLens.back_end.global.fastapi.dto.response.FastNaturalLanguageResponseDTO; import DiffLens.back_end.domain.search.converter.SearchDtoConverter; import DiffLens.back_end.domain.search.dto.ChartDTO; import DiffLens.back_end.domain.search.dto.SearchRequestDTO; @@ -36,8 +36,8 @@ public class NaturalSearchService implements SearchService> summaryConverter; - private final SearchDtoConverter, SearchHistory> filterConverter; + private final SearchDtoConverter> summaryConverter; + private final SearchDtoConverter, SearchHistory> filterConverter; private final SearchDtoConverter, List> chartConverter; // private final SearchDtoConverter> panelResponseConverter; @@ -51,32 +51,34 @@ public SearchResponseDTO.SearchResult search(SearchRequestDTO.NaturalLanguage re Member currentUser = currentUserService.getCurrentUser(); // TODO : 추후 fast api 에서 불러오도록 수정해야 함 - FastNaturalSearchResponseDTO.SearchResult response = fastApiService.getNaturalSearch( - FastPanelRequestDTO.FastNaturalSearch.builder() - .question(request.getQuestion()) - .mode(request.getMode().getKr()) - .filters(new FastPanelRequestDTO.FastSearchFilters()) + FastNaturalLanguageResponseDTO.NaturalSearch response = fastApiService.getNaturalSearch( + FastNaturalLanguageRequestDTO.NaturalSearch.builder() + .query(request.getQuestion()) + .searchMode(request.getMode().getKr()) + .filters(new FastNaturalLanguageRequestDTO.NaturalSearchFilters()) .build() ); // FastNaturalSearchResponseDTO.SearchResult response = new FastNaturalSearchResponseDTO.SearchResult(); + FastNaturalLanguageResponseDTO.Data responseData = response.getData(); + // id List 추출 - List panelIdList = response.getPanelList(); + List panelIdList = responseData.getMatchedPanelIds(); // DB 에서 Panel 목록 가져옴 List foundPanels = panelRepository.findPanelsWithRawDataByIds(panelIdList); // SearchHistory 데이터 생성 및 저장 - SearchHistory searchHistory = searchHistoryService.makeSearchHistory(request, response); + SearchHistory searchHistory = searchHistoryService.makeSearchHistory(request, responseData); searchHistory.setMember(currentUser); // SearchResult.Summary 생성 - SearchResponseDTO.SearchResult.Summary summary = summaryConverter.requestToDto(response, foundPanels); + SearchResponseDTO.SearchResult.Summary summary = summaryConverter.requestToDto(responseData, foundPanels); // SearchResult.AppliedFilter 생성 List appliedFiltersSummary = filterConverter.requestToDto(response, searchHistory); // 차트 생성 - List charts = chartService.makeChart(response, searchHistory, foundPanels); + List charts = chartService.makeChart(responseData, searchHistory, foundPanels); charts.forEach(searchHistory::addChart); // 연관관계 편의 메서드 호출 // 차트 변환 diff --git a/src/main/java/DiffLens/back_end/domain/search/service/implement/SearchHistoryServiceImpl.java b/src/main/java/DiffLens/back_end/domain/search/service/implement/SearchHistoryServiceImpl.java index b888197..7ea6c8a 100644 --- a/src/main/java/DiffLens/back_end/domain/search/service/implement/SearchHistoryServiceImpl.java +++ b/src/main/java/DiffLens/back_end/domain/search/service/implement/SearchHistoryServiceImpl.java @@ -1,7 +1,7 @@ package DiffLens.back_end.domain.search.service.implement; import DiffLens.back_end.domain.panel.repository.projection.PanelWithRawDataDTO; -import DiffLens.back_end.global.fastapi.dto.response.FastNaturalSearchResponseDTO; +import DiffLens.back_end.global.fastapi.dto.response.FastNaturalLanguageResponseDTO; import DiffLens.back_end.domain.rawData.service.RawDataService; import DiffLens.back_end.domain.search.dto.SearchRequestDTO; import DiffLens.back_end.domain.search.dto.SearchResponseDTO; @@ -37,15 +37,15 @@ public class SearchHistoryServiceImpl implements SearchHistoryService { private final List keys = List.of("응답자ID-respondent_id", "성별-gender", "나이-age", "거주지-residence", "월소득-personal_income", "일치율-concordance_rate"); @Override - public SearchHistory makeSearchHistory(SearchRequestDTO.NaturalLanguage request, FastNaturalSearchResponseDTO.SearchResult fastApiResponse) { + public SearchHistory makeSearchHistory(SearchRequestDTO.NaturalLanguage request, FastNaturalLanguageResponseDTO.Data fastApiResponse) { // SearchHistory 데이터 생성 및 저장 SearchHistory searchHistory = historyRepository.save( SearchHistory.builder() .date(LocalDate.now()) .content(request.getQuestion()) - .panelIds(fastApiResponse.getPanelList()) - .concordanceRate(fastApiResponse.getAccuracyList()) + .panelIds(fastApiResponse.getMatchedPanelIds()) + .concordanceRate(fastApiResponse.getMatchScores()) .charts(new ArrayList<>()) .build() ); diff --git a/src/main/java/DiffLens/back_end/domain/search/service/interfaces/ChartService.java b/src/main/java/DiffLens/back_end/domain/search/service/interfaces/ChartService.java index c2bc6d7..81c2597 100644 --- a/src/main/java/DiffLens/back_end/domain/search/service/interfaces/ChartService.java +++ b/src/main/java/DiffLens/back_end/domain/search/service/interfaces/ChartService.java @@ -1,13 +1,12 @@ package DiffLens.back_end.domain.search.service.interfaces; import DiffLens.back_end.domain.panel.repository.projection.PanelWithRawDataDTO; -import DiffLens.back_end.global.fastapi.dto.response.FastNaturalSearchResponseDTO; -import DiffLens.back_end.domain.panel.entity.Panel; +import DiffLens.back_end.global.fastapi.dto.response.FastNaturalLanguageResponseDTO; import DiffLens.back_end.domain.search.entity.Chart; import DiffLens.back_end.domain.search.entity.SearchHistory; import java.util.List; public interface ChartService { - public List makeChart(FastNaturalSearchResponseDTO.SearchResult fastPanelResponseDTO, SearchHistory searchHistory, List foundPanels); + public List makeChart(FastNaturalLanguageResponseDTO.Data fastPanelResponseDTO, SearchHistory searchHistory, List foundPanels); } diff --git a/src/main/java/DiffLens/back_end/domain/search/service/interfaces/SearchHistoryService.java b/src/main/java/DiffLens/back_end/domain/search/service/interfaces/SearchHistoryService.java index 6d37988..dd755e6 100644 --- a/src/main/java/DiffLens/back_end/domain/search/service/interfaces/SearchHistoryService.java +++ b/src/main/java/DiffLens/back_end/domain/search/service/interfaces/SearchHistoryService.java @@ -1,11 +1,11 @@ package DiffLens.back_end.domain.search.service.interfaces; -import DiffLens.back_end.global.fastapi.dto.response.FastNaturalSearchResponseDTO; +import DiffLens.back_end.global.fastapi.dto.response.FastNaturalLanguageResponseDTO; import DiffLens.back_end.domain.search.dto.SearchRequestDTO; import DiffLens.back_end.domain.search.dto.SearchResponseDTO; import DiffLens.back_end.domain.search.entity.SearchHistory; public interface SearchHistoryService { - SearchHistory makeSearchHistory(SearchRequestDTO.NaturalLanguage request, FastNaturalSearchResponseDTO.SearchResult fastApiResponse); + SearchHistory makeSearchHistory(SearchRequestDTO.NaturalLanguage request, FastNaturalLanguageResponseDTO.Data fastApiResponse); SearchResponseDTO.EachResponses getEachResponses(Long searchHistoryId, Integer pageNum, Integer size); } diff --git a/src/main/java/DiffLens/back_end/global/fastapi/FastApiRequestType.java b/src/main/java/DiffLens/back_end/global/fastapi/FastApiRequestType.java index 1efcacc..06bbf45 100644 --- a/src/main/java/DiffLens/back_end/global/fastapi/FastApiRequestType.java +++ b/src/main/java/DiffLens/back_end/global/fastapi/FastApiRequestType.java @@ -1,7 +1,12 @@ package DiffLens.back_end.global.fastapi; -import DiffLens.back_end.global.fastapi.dto.request.FastPanelRequestDTO; -import DiffLens.back_end.global.fastapi.dto.response.FastNaturalSearchResponseDTO; +import DiffLens.back_end.global.fastapi.dto.request.FastHomeRequestDTO; +import DiffLens.back_end.global.fastapi.dto.request.FastLibraryRequestDTO; +import DiffLens.back_end.global.fastapi.dto.request.FastNaturalLanguageRequestDTO; +import DiffLens.back_end.global.fastapi.dto.request.FastReSearchRequestDTO; +import DiffLens.back_end.global.fastapi.dto.response.FastHomeResponseDTO; +import DiffLens.back_end.global.fastapi.dto.response.FastNaturalLanguageResponseDTO; +import DiffLens.back_end.global.fastapi.dto.response.FastReSearchResponseDTO; import lombok.AllArgsConstructor; import lombok.Getter; @@ -9,7 +14,10 @@ @AllArgsConstructor public enum FastApiRequestType { - NATURAL_SEARCH("/search/natural", FastPanelRequestDTO.FastNaturalSearch.class, FastNaturalSearchResponseDTO.SearchResult.class), + NATURAL_SEARCH("/search", FastNaturalLanguageRequestDTO.NaturalSearch.class, FastNaturalLanguageResponseDTO.NaturalSearch.class), + RE_SEARCH("/re-search", FastReSearchRequestDTO.ReSearch.class, FastReSearchResponseDTO.ReSearch.class), + RECOMMENDATIONS("/recommendations", FastHomeRequestDTO.HomeRecommendRequest.class, FastHomeResponseDTO.HomeRecommend.class), + COMPARE("/compare", FastLibraryRequestDTO.LibraryCompare.class, FastNaturalLanguageResponseDTO.NaturalSearch.class), // TODO : 응답 DTO 만든 브랜치 머지하면 적용 // REFINE_SEARCH("/search/refine", FastNaturalSearchResponseDTO.SearchResult.class), ; diff --git a/src/main/java/DiffLens/back_end/global/fastapi/FastApiService.java b/src/main/java/DiffLens/back_end/global/fastapi/FastApiService.java index bad2409..6cafe23 100644 --- a/src/main/java/DiffLens/back_end/global/fastapi/FastApiService.java +++ b/src/main/java/DiffLens/back_end/global/fastapi/FastApiService.java @@ -1,7 +1,7 @@ package DiffLens.back_end.global.fastapi; -import DiffLens.back_end.global.fastapi.dto.request.FastPanelRequestDTO; -import DiffLens.back_end.global.fastapi.dto.response.FastNaturalSearchResponseDTO; +import DiffLens.back_end.global.fastapi.dto.request.FastNaturalLanguageRequestDTO; +import DiffLens.back_end.global.fastapi.dto.response.FastNaturalLanguageResponseDTO; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; @@ -15,7 +15,7 @@ public class FastApiService { private final FastApiClient fastApiClient; // 자연어 검색 - public FastNaturalSearchResponseDTO.SearchResult getNaturalSearch(FastPanelRequestDTO.FastNaturalSearch request) { + public FastNaturalLanguageResponseDTO.NaturalSearch getNaturalSearch(FastNaturalLanguageRequestDTO.NaturalSearch request) { return fastApiClient.sendRequest(FastApiRequestType.NATURAL_SEARCH, request); } diff --git a/src/main/java/DiffLens/back_end/global/fastapi/dto/request/FastHomeRequestDTO.java b/src/main/java/DiffLens/back_end/global/fastapi/dto/request/FastHomeRequestDTO.java new file mode 100644 index 0000000..ee726b0 --- /dev/null +++ b/src/main/java/DiffLens/back_end/global/fastapi/dto/request/FastHomeRequestDTO.java @@ -0,0 +1,37 @@ +package DiffLens.back_end.global.fastapi.dto.request; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +import java.util.List; + +/** + * + * 홈화면 추천 + * Spring Boot -> Fast API 요청 형태 + * + */ +public class FastHomeRequestDTO { + + @Getter + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class HomeRecommendRequest { + private Long memberId; + private HomeRecommendOnboarding onboarding; + private List recentSearches; + } + + @Getter + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class HomeRecommendOnboarding{ + private String job; + private String industry; + } + +} diff --git a/src/main/java/DiffLens/back_end/global/fastapi/dto/request/FastLibraryRequestDTO.java b/src/main/java/DiffLens/back_end/global/fastapi/dto/request/FastLibraryRequestDTO.java new file mode 100644 index 0000000..f8ef73c --- /dev/null +++ b/src/main/java/DiffLens/back_end/global/fastapi/dto/request/FastLibraryRequestDTO.java @@ -0,0 +1,29 @@ +package DiffLens.back_end.global.fastapi.dto.request; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +import java.util.List; + +/** + * + * 라이브러리 비교 + * Spring Boot -> Fast API 요청 형태 + * + */ +public class FastLibraryRequestDTO { + + @Getter + @Builder + @AllArgsConstructor + @NoArgsConstructor + public static class LibraryCompare{ + private Long libraryId1; + private Long libraryId2; + private List panelIds1; + private List panelIds2; + } + +} diff --git a/src/main/java/DiffLens/back_end/global/fastapi/dto/request/FastNaturalLanguageRequestDTO.java b/src/main/java/DiffLens/back_end/global/fastapi/dto/request/FastNaturalLanguageRequestDTO.java new file mode 100644 index 0000000..e55532a --- /dev/null +++ b/src/main/java/DiffLens/back_end/global/fastapi/dto/request/FastNaturalLanguageRequestDTO.java @@ -0,0 +1,47 @@ +package DiffLens.back_end.global.fastapi.dto.request; + +import lombok.*; + +import java.util.List; + +/** + * + * 자연어 검색 + * Spring Boot -> Fast API 요청 형태 + * + */ +public class FastNaturalLanguageRequestDTO { + + // 자연어 검색 요청 + @Getter + @Builder + @AllArgsConstructor + @NoArgsConstructor + public static class NaturalSearch { + + private String query; + + private String searchMode; + + private NaturalSearchFilters filters; + + } + + @Getter + @Setter + @NoArgsConstructor + @AllArgsConstructor + public static class NaturalSearchFilters { + + private String respondentCount; + private String gender; + private String ageGroup; + private List region; + private String martialStatus; + private String childrenCount; + private String occupation; + + } + + +} diff --git a/src/main/java/DiffLens/back_end/global/fastapi/dto/request/FastPanelRequestDTO.java b/src/main/java/DiffLens/back_end/global/fastapi/dto/request/FastPanelRequestDTO.java deleted file mode 100644 index cfecc6c..0000000 --- a/src/main/java/DiffLens/back_end/global/fastapi/dto/request/FastPanelRequestDTO.java +++ /dev/null @@ -1,94 +0,0 @@ -package DiffLens.back_end.global.fastapi.dto.request; - -import lombok.*; - -import java.util.List; - -/** - * - * Spring Boot -> Fast API 요청 형태 - * - */ -public class FastPanelRequestDTO { - - // 자연어 검색 요청 - @Getter - @Builder - @AllArgsConstructor - @NoArgsConstructor - public static class FastNaturalSearch{ - - private String question; - - private String mode; - - private FastSearchFilters filters; - - } - - // 재검색 요청 - @Getter - @Builder - @AllArgsConstructor - @NoArgsConstructor - public static class FastRefineSearch{ - - private String question; - - private String mode; - - private FastSearchFilters filters; - - - } - - // 차트 - @Getter - @Builder - @AllArgsConstructor - @NoArgsConstructor - public static class FastChart{ - - private String tempColumn; - - } - - // 추천 - @Getter - @Builder - @AllArgsConstructor - @NoArgsConstructor - public static class FastRecommendation { - - private String tempColumn; - - } - - // 라이브러리 비교 - @Getter - @Builder - @AllArgsConstructor - @NoArgsConstructor - public static class FastLibraryCompare { - - private String tempColumn; - - } - - // ------------------------------- - // 아 아래는 위에서 필요한 클래스들 - - @Getter - @Setter - @NoArgsConstructor - @AllArgsConstructor - public static class FastSearchFilters{ - - private Integer count; - private String gender; - private List filters; - - } - - -} diff --git a/src/main/java/DiffLens/back_end/global/fastapi/dto/request/FastReSearchRequestDTO.java b/src/main/java/DiffLens/back_end/global/fastapi/dto/request/FastReSearchRequestDTO.java new file mode 100644 index 0000000..6323ae0 --- /dev/null +++ b/src/main/java/DiffLens/back_end/global/fastapi/dto/request/FastReSearchRequestDTO.java @@ -0,0 +1,39 @@ +package DiffLens.back_end.global.fastapi.dto.request; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +import java.util.List; + +/** + * + * 재검색 + * Spring Boot -> Fast API 요청 형태 + * + */ +public class FastReSearchRequestDTO { + + @Getter + @Builder + @AllArgsConstructor + @NoArgsConstructor + public static class ReSearch { + + private String query; + private String searchMode; + private ReSearchFilters filters; + private List existingPanelIds; + + } + + @Getter + @Builder + @AllArgsConstructor + @NoArgsConstructor + public static class ReSearchFilters { + private List occupations; + } + +} diff --git a/src/main/java/DiffLens/back_end/global/fastapi/dto/response/FastHomeResponseDTO.java b/src/main/java/DiffLens/back_end/global/fastapi/dto/response/FastHomeResponseDTO.java new file mode 100644 index 0000000..07266da --- /dev/null +++ b/src/main/java/DiffLens/back_end/global/fastapi/dto/response/FastHomeResponseDTO.java @@ -0,0 +1,49 @@ +package DiffLens.back_end.global.fastapi.dto.response; + +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; + +import java.util.List; + +public class FastHomeResponseDTO { + + @Getter + @Builder + public static class HomeRecommend{ + + private Boolean success; + private Data data; + + } + + @Getter + @Setter + public static class Data{ + private List recommendations; + } + + @Getter + @Setter + public static class Recommendation{ + private Long id; + private String title; + private String description; + private String icon; + private String query; + private RecommendationFilter filters; + } + + @Getter + @Setter + public static class RecommendationFilter{ + private String respondentCount; + private List region; + private List occupation; + private String gender; + private String martialStatus; + private String reason; + } + + +} diff --git a/src/main/java/DiffLens/back_end/global/fastapi/dto/response/FastNaturalSearchResponseDTO.java b/src/main/java/DiffLens/back_end/global/fastapi/dto/response/FastNaturalLanguageResponseDTO.java similarity index 54% rename from src/main/java/DiffLens/back_end/global/fastapi/dto/response/FastNaturalSearchResponseDTO.java rename to src/main/java/DiffLens/back_end/global/fastapi/dto/response/FastNaturalLanguageResponseDTO.java index 82e79fe..e32839d 100644 --- a/src/main/java/DiffLens/back_end/global/fastapi/dto/response/FastNaturalSearchResponseDTO.java +++ b/src/main/java/DiffLens/back_end/global/fastapi/dto/response/FastNaturalLanguageResponseDTO.java @@ -8,12 +8,11 @@ /** * - * Fast API -> Spring Boot 응답 형태 * 자연어 응답 - * + * Fast API -> Spring Boot 응답 형태 * */ -public class FastNaturalSearchResponseDTO { +public class FastNaturalLanguageResponseDTO { /** * fast api에서 패널 식별자 목록을 불러와 db에서 패널 데이터를 불러옵니다. @@ -21,19 +20,50 @@ public class FastNaturalSearchResponseDTO { @Getter @Setter @ToString - public static class SearchResult { + public static class NaturalSearch { + + private Boolean success; + + private Data data; + + + // 매칭된 패널 Id 배열 + + + // 개별응답 종류 +// private List panelColumns; // SearchResponseDTO.EachResponses로 분리 + + } + // ------------ NaturalSearch에서 필요한 클래스들 ------ + @Getter + @Setter + public static class Data{ // 일반적인 데이터 private Float accuracy; - private List panelList; - private List accuracyList; // 일치율 + private List matchedPanelIds; // 매칭된 패널 ID 목록 + private List matchScores; // 일치율 // 차트 관련 - private List charts; + private FastSearchChart mainChart; // 메인차트 - // 개별응답 종류 -// private List panelColumns; // SearchResponseDTO.EachResponses로 분리 + private List subCharts; // 서브차트 + + private Integer totalCount; + + private ProcessingInfo processingInfo; + + + } + + @Getter + @Setter + public static class ProcessingInfo{ + private Double embeddingTime; + private Double searchTime; + private Double chartGenerationTime; + private Double totalTime; } diff --git a/src/main/java/DiffLens/back_end/global/fastapi/dto/response/FastReSearchResponseDTO.java b/src/main/java/DiffLens/back_end/global/fastapi/dto/response/FastReSearchResponseDTO.java new file mode 100644 index 0000000..98e4c02 --- /dev/null +++ b/src/main/java/DiffLens/back_end/global/fastapi/dto/response/FastReSearchResponseDTO.java @@ -0,0 +1,28 @@ +package DiffLens.back_end.global.fastapi.dto.response; + +import lombok.Getter; +import lombok.Setter; + +import java.util.List; + +public class FastReSearchResponseDTO { + + @Getter + @Setter + public static class ReSearch { + private Boolean success; + private Data data; + } + + @Getter + @Setter + public static class Data{ + private FastSearchChart mainChart; + private List subCharts; + private List matchedPanelIds; + private List matchScores; + private Integer totalCount; + private FastNaturalLanguageResponseDTO.ProcessingInfo processingInfo; + } + +} diff --git a/src/main/java/DiffLens/back_end/global/fastapi/dto/response/FastSearchChart.java b/src/main/java/DiffLens/back_end/global/fastapi/dto/response/FastSearchChart.java new file mode 100644 index 0000000..c0f9322 --- /dev/null +++ b/src/main/java/DiffLens/back_end/global/fastapi/dto/response/FastSearchChart.java @@ -0,0 +1,61 @@ +package DiffLens.back_end.global.fastapi.dto.response; + +import lombok.Getter; +import lombok.Setter; + +import java.util.List; + +@Getter +@Setter +public class FastSearchChart { + + private String chartType; + private String title; + private String reason; + private String panelColumn; + private Data data; + private Option options; + private MetaData metadata; + + @Getter + @Setter + public static class Data { + private List labels; + private List dataSets; + } + + @Getter + @Setter + public static class DataSet { + private String label; + private List data; + private List backgroundColor; + } + + @Getter + @Setter + public static class Option { + private Plugins plugins; + } + + @Getter + @Setter + public static class Plugins { + private Legend legend; + } + + @Getter + @Setter + public static class Legend { + private String position; + } + + @Getter + @Setter + public static class MetaData { + private Integer totalPanels; + private String queryIntent; + private Double confidence; + private String relevance; + } +} From 6271203cab3035cc586175892fdd2918fe7d3094 Mon Sep 17 00:00:00 2001 From: junyong Date: Mon, 27 Oct 2025 15:44:18 +0900 Subject: [PATCH 3/5] =?UTF-8?q?refactor=20:=20=EC=84=9C=EB=B8=8C=20?= =?UTF-8?q?=EC=84=9C=EB=B2=84=20=ED=86=B5=EC=8B=A0=20dto=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1=20=EC=A4=91=20=EC=83=9D=EA=B8=B4=20=EB=B6=88=ED=95=84?= =?UTF-8?q?=EC=9A=94=20=ED=81=B4=EB=9E=98=EC=8A=A4=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../response/FastNaturalLanguageResponseDTO.java | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/src/main/java/DiffLens/back_end/global/fastapi/dto/response/FastNaturalLanguageResponseDTO.java b/src/main/java/DiffLens/back_end/global/fastapi/dto/response/FastNaturalLanguageResponseDTO.java index e32839d..6927ae3 100644 --- a/src/main/java/DiffLens/back_end/global/fastapi/dto/response/FastNaturalLanguageResponseDTO.java +++ b/src/main/java/DiffLens/back_end/global/fastapi/dto/response/FastNaturalLanguageResponseDTO.java @@ -67,20 +67,5 @@ public static class ProcessingInfo{ } - /** - * 차트 - */ - @Getter - @Setter - @ToString - public static class ChartFastResult { - private String chartType; // 차트 유형 - private String title; // 차트 제목 - private String reason; // 차트 선정 이유 - private String xaxis; // x축 항목 - private String yaxis; // y축 항목 - private String panelColumn; // 표에 표시할 정보 ex) 직업분포, 월평균 소득 등 - } - } From eed743b5d015fa78d1e14bee03031cb2f4b2c88f Mon Sep 17 00:00:00 2001 From: hardwoong Date: Mon, 27 Oct 2025 22:27:32 +0900 Subject: [PATCH 4/5] =?UTF-8?q?fix:=20fast=20api=20dto=20=EA=B5=AC?= =?UTF-8?q?=EC=A1=B0=20=EB=B3=80=EA=B2=BD=EC=97=90=20=EB=94=B0=EB=A5=B8=20?= =?UTF-8?q?=EB=AC=B8=EC=A0=9C=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/library/service/LibraryService.java | 4 ++-- .../back_end/global/fastapi/FastApiRequestType.java | 3 ++- .../back_end/global/fastapi/FastApiService.java | 10 +++++++++- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/main/java/DiffLens/back_end/domain/library/service/LibraryService.java b/src/main/java/DiffLens/back_end/domain/library/service/LibraryService.java index 17e7bca..fca648d 100644 --- a/src/main/java/DiffLens/back_end/domain/library/service/LibraryService.java +++ b/src/main/java/DiffLens/back_end/domain/library/service/LibraryService.java @@ -18,7 +18,7 @@ import DiffLens.back_end.domain.search.entity.SearchHistory; import DiffLens.back_end.domain.search.repository.SearchHistoryRepository; import DiffLens.back_end.global.fastapi.FastApiService; -import DiffLens.back_end.global.fastapi.dto.request.FastPanelRequestDTO; +import DiffLens.back_end.global.fastapi.dto.request.FastLibraryRequestDTO; import DiffLens.back_end.global.fastapi.dto.response.FastLibraryCompareResponseDTO; import DiffLens.back_end.global.responses.code.status.error.ErrorStatus; import DiffLens.back_end.global.responses.exception.handler.ErrorHandler; @@ -313,7 +313,7 @@ public LibraryCompareResponseDTO.CompareResult compareLibraries(LibraryCompareRe } // 4. FastAPI 서버로 비교 요청 - FastPanelRequestDTO.FastLibraryCompare fastApiRequest = FastPanelRequestDTO.FastLibraryCompare.builder() + FastLibraryRequestDTO.LibraryCompare fastApiRequest = FastLibraryRequestDTO.LibraryCompare.builder() .libraryId1(library1.getId()) .libraryId2(library2.getId()) .panelIds1(library1.getPanelIds()) diff --git a/src/main/java/DiffLens/back_end/global/fastapi/FastApiRequestType.java b/src/main/java/DiffLens/back_end/global/fastapi/FastApiRequestType.java index 2834131..63f42ba 100644 --- a/src/main/java/DiffLens/back_end/global/fastapi/FastApiRequestType.java +++ b/src/main/java/DiffLens/back_end/global/fastapi/FastApiRequestType.java @@ -7,6 +7,7 @@ import DiffLens.back_end.global.fastapi.dto.response.FastHomeResponseDTO; import DiffLens.back_end.global.fastapi.dto.response.FastNaturalLanguageResponseDTO; import DiffLens.back_end.global.fastapi.dto.response.FastReSearchResponseDTO; +import DiffLens.back_end.global.fastapi.dto.response.FastLibraryCompareResponseDTO; import lombok.AllArgsConstructor; import lombok.Getter; @@ -20,7 +21,7 @@ public enum FastApiRequestType { RECOMMENDATIONS("/recommendations", FastHomeRequestDTO.HomeRecommendRequest.class, FastHomeResponseDTO.HomeRecommend.class), COMPARE("/compare", FastLibraryRequestDTO.LibraryCompare.class, - FastNaturalLanguageResponseDTO.NaturalSearch.class), // TODO : 응답 DTO 만든 브랜치 머지하면 적용 + FastLibraryCompareResponseDTO.CompareResult.class), // REFINE_SEARCH("/search/refine", // FastNaturalSearchResponseDTO.SearchResult.class), ; diff --git a/src/main/java/DiffLens/back_end/global/fastapi/FastApiService.java b/src/main/java/DiffLens/back_end/global/fastapi/FastApiService.java index 6cafe23..b0e4307 100644 --- a/src/main/java/DiffLens/back_end/global/fastapi/FastApiService.java +++ b/src/main/java/DiffLens/back_end/global/fastapi/FastApiService.java @@ -1,7 +1,9 @@ package DiffLens.back_end.global.fastapi; import DiffLens.back_end.global.fastapi.dto.request.FastNaturalLanguageRequestDTO; +import DiffLens.back_end.global.fastapi.dto.request.FastLibraryRequestDTO; import DiffLens.back_end.global.fastapi.dto.response.FastNaturalLanguageResponseDTO; +import DiffLens.back_end.global.fastapi.dto.response.FastLibraryCompareResponseDTO; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; @@ -15,8 +17,14 @@ public class FastApiService { private final FastApiClient fastApiClient; // 자연어 검색 - public FastNaturalLanguageResponseDTO.NaturalSearch getNaturalSearch(FastNaturalLanguageRequestDTO.NaturalSearch request) { + public FastNaturalLanguageResponseDTO.NaturalSearch getNaturalSearch( + FastNaturalLanguageRequestDTO.NaturalSearch request) { return fastApiClient.sendRequest(FastApiRequestType.NATURAL_SEARCH, request); } + // 라이브러리 비교 + public FastLibraryCompareResponseDTO.CompareResult compareLibraries(FastLibraryRequestDTO.LibraryCompare request) { + return fastApiClient.sendRequest(FastApiRequestType.COMPARE, request); + } + } From 9cc26207fe4280fd9d5e1565782c16ab1b7a312f Mon Sep 17 00:00:00 2001 From: junyong Date: Wed, 29 Oct 2025 10:49:50 +0900 Subject: [PATCH 5/5] =?UTF-8?q?chore=20:=20=ED=94=84=EB=A1=9C=EB=A9=94?= =?UTF-8?q?=ED=85=8C=EC=9A=B0=EC=8A=A4=20=EC=9D=98=EC=A1=B4=EC=84=B1=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/build.gradle b/build.gradle index 3b9a14f..332eb03 100644 --- a/build.gradle +++ b/build.gradle @@ -64,6 +64,11 @@ dependencies { // AOP implementation 'org.springframework.boot:spring-boot-starter-aop' + // prometheus + implementation 'org.springframework.boot:spring-boot-starter-actuator' + implementation 'io.micrometer:micrometer-registry-prometheus' + + }