From 42c1664916c11f29080ec1d6ab7f22e94c1dc392 Mon Sep 17 00:00:00 2001 From: dongyeon1031 Date: Wed, 16 Oct 2024 22:43:20 +0900 Subject: [PATCH] =?UTF-8?q?Feat:=20=ED=95=99=EA=B5=90=EA=B3=B5=EC=A7=80=20?= =?UTF-8?q?=EC=9A=94=EC=95=BD=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 8 --- .../CampusNoticeAdminController.java | 6 +-- .../{LambdaUtil.java => CrawlerUtil.java} | 6 +-- .../common}/config/LambdaConfig.java | 4 +- .../global/common/constant/Constant.java | 6 ++- .../bigbrotherbe/global/llm/DeployBart.py | 0 .../controller/SummarizationController.java | 26 +++++++--- .../global/llm/dto/SummarizeRequest.java | 8 +++ .../llm/sagemakerConfig/SagemakerConfig.java | 31 ------------ .../global/llm/service/BedrockService.java | 5 ++ .../llm/service/BedrockServiceImpl.java | 49 +++++++++++++++++++ .../global/llm/service/SageMakerService.java | 38 -------------- 12 files changed, 94 insertions(+), 93 deletions(-) rename src/main/java/com/example/bigbrotherbe/domain/campusNotice/util/{LambdaUtil.java => CrawlerUtil.java} (80%) rename src/main/java/com/example/bigbrotherbe/{domain/campusNotice => global/common}/config/LambdaConfig.java (89%) delete mode 100644 src/main/java/com/example/bigbrotherbe/global/llm/DeployBart.py create mode 100644 src/main/java/com/example/bigbrotherbe/global/llm/dto/SummarizeRequest.java delete mode 100644 src/main/java/com/example/bigbrotherbe/global/llm/sagemakerConfig/SagemakerConfig.java create mode 100644 src/main/java/com/example/bigbrotherbe/global/llm/service/BedrockService.java create mode 100644 src/main/java/com/example/bigbrotherbe/global/llm/service/BedrockServiceImpl.java delete mode 100644 src/main/java/com/example/bigbrotherbe/global/llm/service/SageMakerService.java diff --git a/build.gradle b/build.gradle index eaf0668..6e27b58 100644 --- a/build.gradle +++ b/build.gradle @@ -75,14 +75,6 @@ dependencies { implementation 'com.amazonaws:aws-java-sdk-core:1.12.50' implementation 'com.fasterxml.jackson.core:jackson-databind:2.17.1' - // SageMaker -// implementation 'software.amazon.awssdk:sagemaker:2.20.0' -// implementation 'software.amazon.awssdk:sdk-core:2.20.0' -// implementation 'software.amazon.awssdk:http-client-netty:2.20.0' - implementation 'software.amazon.awssdk:sagemakerruntime:2.20.92' - implementation 'software.amazon.awssdk:sdk-core:2.20.92' -// implementation 'software.amazon.awssdk:http-client-netty:2.20.92' - // OCR implementation 'org.apache.pdfbox:pdfbox:2.0.27' implementation 'net.sourceforge.tess4j:tess4j:4.5.5' diff --git a/src/main/java/com/example/bigbrotherbe/domain/campusNotice/controller/CampusNoticeAdminController.java b/src/main/java/com/example/bigbrotherbe/domain/campusNotice/controller/CampusNoticeAdminController.java index 587a533..14dfb24 100644 --- a/src/main/java/com/example/bigbrotherbe/domain/campusNotice/controller/CampusNoticeAdminController.java +++ b/src/main/java/com/example/bigbrotherbe/domain/campusNotice/controller/CampusNoticeAdminController.java @@ -4,7 +4,7 @@ import com.example.bigbrotherbe.domain.campusNotice.entity.CampusNotice; import com.example.bigbrotherbe.domain.campusNotice.entity.CampusNoticeType; import com.example.bigbrotherbe.domain.campusNotice.service.CampusNoticeService; -import com.example.bigbrotherbe.domain.campusNotice.util.LambdaUtil; +import com.example.bigbrotherbe.domain.campusNotice.util.CrawlerUtil; import com.example.bigbrotherbe.global.common.exception.response.ApiResponse; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Page; @@ -24,7 +24,7 @@ @RequiredArgsConstructor public class CampusNoticeAdminController { private final CampusNoticeService campusNoticeService; - private final LambdaUtil lambdaUtil; + private final CrawlerUtil crawlerUtil; @GetMapping("/{campusNoticeId}") public ResponseEntity> getCampusNoticeById(@PathVariable("campusNoticeId") Long campusNoticeId) { @@ -50,7 +50,7 @@ public ResponseEntity>> getCampusNoticeList(@Requ @PostMapping public ResponseEntity> crawlerNotice() { - lambdaUtil.invokeLambda(); + crawlerUtil.invokeLambda(); return ResponseEntity.ok().build(); } } diff --git a/src/main/java/com/example/bigbrotherbe/domain/campusNotice/util/LambdaUtil.java b/src/main/java/com/example/bigbrotherbe/domain/campusNotice/util/CrawlerUtil.java similarity index 80% rename from src/main/java/com/example/bigbrotherbe/domain/campusNotice/util/LambdaUtil.java rename to src/main/java/com/example/bigbrotherbe/domain/campusNotice/util/CrawlerUtil.java index fa4ca5b..d464b48 100644 --- a/src/main/java/com/example/bigbrotherbe/domain/campusNotice/util/LambdaUtil.java +++ b/src/main/java/com/example/bigbrotherbe/domain/campusNotice/util/CrawlerUtil.java @@ -9,7 +9,7 @@ @Component @RequiredArgsConstructor -public class LambdaUtil { +public class CrawlerUtil { private final CampusNoticeService campusNoticeService; @@ -18,9 +18,9 @@ public void invokeLambda() { for (CampusNoticeType noticeType : CampusNoticeType.values()){ String payload = "{\"queryStringParameters\": {" + "\"url\": \"" + noticeType.getUrl() + "\"," + - "\"base_url\": \"" + Constant.Lambda.BASE_URL + "\"" + + "\"base_url\": \"" + Constant.Crawler.BASE_URL + "\"" + "}}"; - campusNoticeService.invokeLambda(Constant.Lambda.FUNCTION_NAME, payload, noticeType); + campusNoticeService.invokeLambda(Constant.Crawler.FUNCTION_NAME, payload, noticeType); } } } diff --git a/src/main/java/com/example/bigbrotherbe/domain/campusNotice/config/LambdaConfig.java b/src/main/java/com/example/bigbrotherbe/global/common/config/LambdaConfig.java similarity index 89% rename from src/main/java/com/example/bigbrotherbe/domain/campusNotice/config/LambdaConfig.java rename to src/main/java/com/example/bigbrotherbe/global/common/config/LambdaConfig.java index 7efb125..f00ce31 100644 --- a/src/main/java/com/example/bigbrotherbe/domain/campusNotice/config/LambdaConfig.java +++ b/src/main/java/com/example/bigbrotherbe/global/common/config/LambdaConfig.java @@ -1,4 +1,4 @@ -package com.example.bigbrotherbe.domain.campusNotice.config; +package com.example.bigbrotherbe.global.common.config; import com.amazonaws.auth.AWSStaticCredentialsProvider; import com.amazonaws.auth.BasicAWSCredentials; @@ -21,11 +21,13 @@ public class LambdaConfig { private String region; @Bean + // 자격증명 생성 public BasicAWSCredentials awsCredentials() { return new BasicAWSCredentials(accessKey, secretKey); } @Bean + // Lambda 서비스 접근 클라이언트 생성 public AWSLambda awsLambda(BasicAWSCredentials awsCredentials) { return AWSLambdaClientBuilder.standard() .withRegion(Regions.fromName(region)) diff --git a/src/main/java/com/example/bigbrotherbe/global/common/constant/Constant.java b/src/main/java/com/example/bigbrotherbe/global/common/constant/Constant.java index fc079f3..3b398c6 100644 --- a/src/main/java/com/example/bigbrotherbe/global/common/constant/Constant.java +++ b/src/main/java/com/example/bigbrotherbe/global/common/constant/Constant.java @@ -6,7 +6,7 @@ public static class GetContent { public static final String SIZE_DEFAULT_VALUE = "10"; } - public static class Lambda{ + public static class Crawler { public static final String FUNCTION_NAME = "campusNoticeCrawler"; public static final String BASE_URL = "https://www.mju.ac.kr"; } @@ -19,6 +19,10 @@ public static class Url{ public static final String DOMAIN_URL = "https://api.mju-bigbrother.xyz"; } + public static class LLM{ + public static final String FUNCTION_NAME = "callBedrock"; + } + public static class Entity{ public static final String NOTICE = "notice"; public static final String FAQ = "faq"; diff --git a/src/main/java/com/example/bigbrotherbe/global/llm/DeployBart.py b/src/main/java/com/example/bigbrotherbe/global/llm/DeployBart.py deleted file mode 100644 index e69de29..0000000 diff --git a/src/main/java/com/example/bigbrotherbe/global/llm/controller/SummarizationController.java b/src/main/java/com/example/bigbrotherbe/global/llm/controller/SummarizationController.java index 90c1e24..d3f178c 100644 --- a/src/main/java/com/example/bigbrotherbe/global/llm/controller/SummarizationController.java +++ b/src/main/java/com/example/bigbrotherbe/global/llm/controller/SummarizationController.java @@ -1,17 +1,27 @@ package com.example.bigbrotherbe.global.llm.controller; -import com.example.bigbrotherbe.global.llm.service.SageMakerService; +import com.example.bigbrotherbe.domain.campusNotice.dto.CampusNoticeResponse; +import com.example.bigbrotherbe.domain.campusNotice.service.CampusNoticeService; +import com.example.bigbrotherbe.global.common.exception.response.ApiResponse; +import com.example.bigbrotherbe.global.llm.dto.SummarizeRequest; +import com.example.bigbrotherbe.global.llm.service.BedrockService; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; -import org.springframework.beans.factory.annotation.Autowired; + +import static com.example.bigbrotherbe.global.common.exception.enums.SuccessCode.SUCCESS; @RestController -@RequestMapping("/api/v1/admin/llm") +@RequiredArgsConstructor +@RequestMapping("/api/v1/summarize") public class SummarizationController { - - @Autowired - private SageMakerService sageMakerService; + private final BedrockService bedrockService; + private final CampusNoticeService campusNoticeService; @GetMapping() - public String summarize(@RequestPart(value = "text") String inputText) { - return sageMakerService.getSummary(inputText); + public ResponseEntity> getSummarizeById(@RequestBody SummarizeRequest summarizeRequest) { + CampusNoticeResponse campusNoticeResponse = campusNoticeService.getCampusNoticeById(summarizeRequest.getCampusNoticeId()); + String content = campusNoticeResponse.getContent(); + String response = bedrockService.getSummary(content); + return ResponseEntity.ok(ApiResponse.success(SUCCESS, response)); } } \ No newline at end of file diff --git a/src/main/java/com/example/bigbrotherbe/global/llm/dto/SummarizeRequest.java b/src/main/java/com/example/bigbrotherbe/global/llm/dto/SummarizeRequest.java new file mode 100644 index 0000000..e37a932 --- /dev/null +++ b/src/main/java/com/example/bigbrotherbe/global/llm/dto/SummarizeRequest.java @@ -0,0 +1,8 @@ +package com.example.bigbrotherbe.global.llm.dto; + +import lombok.Getter; + +@Getter +public class SummarizeRequest { + Long campusNoticeId; +} diff --git a/src/main/java/com/example/bigbrotherbe/global/llm/sagemakerConfig/SagemakerConfig.java b/src/main/java/com/example/bigbrotherbe/global/llm/sagemakerConfig/SagemakerConfig.java deleted file mode 100644 index f7c2fdf..0000000 --- a/src/main/java/com/example/bigbrotherbe/global/llm/sagemakerConfig/SagemakerConfig.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.example.bigbrotherbe.global.llm.sagemakerConfig; - -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; -import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider; -import software.amazon.awssdk.regions.Region; -import software.amazon.awssdk.services.sagemakerruntime.SageMakerRuntimeClient; - -@Configuration -public class SagemakerConfig { - @Value("${cloud.aws.credentials.access-key}") - private String accessKey; - - @Value("${cloud.aws.credentials.secret-key}") - private String secretKey; - - @Value("${cloud.aws.region.static}") - private String region; - - @Bean - public SageMakerRuntimeClient sageMakerClient() { - AwsBasicCredentials awsCredentials = AwsBasicCredentials.create(accessKey, secretKey); - - return SageMakerRuntimeClient.builder() - .region(Region.of(region)) - .credentialsProvider(StaticCredentialsProvider.create(awsCredentials)) - .build(); - } -} diff --git a/src/main/java/com/example/bigbrotherbe/global/llm/service/BedrockService.java b/src/main/java/com/example/bigbrotherbe/global/llm/service/BedrockService.java new file mode 100644 index 0000000..66d28a9 --- /dev/null +++ b/src/main/java/com/example/bigbrotherbe/global/llm/service/BedrockService.java @@ -0,0 +1,5 @@ +package com.example.bigbrotherbe.global.llm.service; + +public interface BedrockService { + public String getSummary(String content); +} diff --git a/src/main/java/com/example/bigbrotherbe/global/llm/service/BedrockServiceImpl.java b/src/main/java/com/example/bigbrotherbe/global/llm/service/BedrockServiceImpl.java new file mode 100644 index 0000000..7355a0f --- /dev/null +++ b/src/main/java/com/example/bigbrotherbe/global/llm/service/BedrockServiceImpl.java @@ -0,0 +1,49 @@ +package com.example.bigbrotherbe.global.llm.service; +import com.amazonaws.services.lambda.AWSLambda; +import com.amazonaws.services.lambda.model.InvokeRequest; +import com.amazonaws.services.lambda.model.InvokeResult; +import com.example.bigbrotherbe.global.common.constant.Constant; +import com.example.bigbrotherbe.global.common.exception.BusinessException; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import static com.example.bigbrotherbe.global.common.exception.enums.ErrorCode.FAIL_TO_JSON_PARSING; +import static com.example.bigbrotherbe.global.common.exception.enums.ErrorCode.LAMBDA_FUNCTION_ERROR; + +@Service +@RequiredArgsConstructor +public class BedrockServiceImpl implements BedrockService{ + + private final AWSLambda awsLambda; + private final ObjectMapper objectMapper; + + public String getSummary(String content) { + String payload = this.createPayload(content); + InvokeRequest invokeRequest = new InvokeRequest() + .withFunctionName(Constant.LLM.FUNCTION_NAME) + .withPayload(payload); + + InvokeResult invokeResult = awsLambda.invoke(invokeRequest); + String jsonResponse = new String(invokeResult.getPayload().array()); + + try{ + JsonNode root = objectMapper.readTree(jsonResponse); + return root.get("body").asText(); + } catch ( + JsonProcessingException e) { + throw new BusinessException(FAIL_TO_JSON_PARSING); + } catch (NullPointerException e) { + throw new BusinessException(LAMBDA_FUNCTION_ERROR); + } + } + + private String createPayload(String content) { + return "{" + + "\"content\": \"" + content + "\"" + + "}"; + } + +} \ No newline at end of file diff --git a/src/main/java/com/example/bigbrotherbe/global/llm/service/SageMakerService.java b/src/main/java/com/example/bigbrotherbe/global/llm/service/SageMakerService.java deleted file mode 100644 index 04fd446..0000000 --- a/src/main/java/com/example/bigbrotherbe/global/llm/service/SageMakerService.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.example.bigbrotherbe.global.llm.service; -import lombok.RequiredArgsConstructor; -import software.amazon.awssdk.regions.Region; -import software.amazon.awssdk.services.sagemakerruntime.SageMakerRuntimeClient; -import software.amazon.awssdk.services.sagemakerruntime.model.InvokeEndpointRequest; -import software.amazon.awssdk.services.sagemakerruntime.model.InvokeEndpointResponse; -import software.amazon.awssdk.core.SdkBytes; -import org.springframework.stereotype.Service; - -@Service -@RequiredArgsConstructor - -public class SageMakerService { - - private final SageMakerRuntimeClient sageMakerClient; - - public String getSummary(String inputText) { - // 요청 생성 - // SageMaker 엔드포인트 이름 - String endpointName = "huggingface-bart-endpoint"; - InvokeEndpointRequest request = InvokeEndpointRequest.builder() - .endpointName(endpointName) - .contentType("application/json") - .body(SdkBytes.fromUtf8String("{\"inputs\": \"" + inputText + "\"}")) - .build(); - // 엔드포인트 호출 - InvokeEndpointResponse response = sageMakerClient.invokeEndpoint(request); - - // 응답 결과 처리 - String result = new String(response.body().asByteArray()); - return parseSummaryFromResponse(result); - } - - private String parseSummaryFromResponse(String response) { - // 응답에서 요약 결과 추출 (JSON 파싱) - return response; - } -} \ No newline at end of file