[Springboot] Springboot에서 네이버 텍스트 감정분석 API(Naver CLOVA Sentiment) 사용하기

winluck·2024년 8월 2일
0

Springboot

목록 보기
14/18

현대자동차 소프티어 부트캠프의 프로젝트 요구사항에 욕설 및 부정적인 문장을 필터링하라는 정책이 있어, 네이버 클라우드 플랫폼에서 제공하는 감정분석 API를 활용하여 간단하게 이를 구현해보았다.

환경변수 설정

먼저 네이버 클라우드 플랫폼의 client-id와 client-secret를 발급받고 이를 application-yml과 같은 환경변수에 등록해둔다.

naver:
  client-id: {발급받은 client-id}
  client-secret: {발급받은 clinet-secret}
  url: https://naveropenapi.apigw.ntruss.com/sentiment-analysis/v1/analyze

환경변수가 많으면, @Value가 아닌 @Configuration을 통해 변수를 등록할 수 있다.

@Data
@Configuration
@ConfigurationProperties(prefix = "naver")
public class NaverApiConfig {
    private String clientId;
    private String clientSecret;
    private String url;
}


@RequiredArgsConstructor
@Service
public class ApiService {

    private final NaverApiConfig naverApiConfig;
    
    // 비즈니스 로직..
}

API 요청 준비

참고로 API 요청의 응답은 아래와 같은 형태로 나타난다.
sentiment는 감정의 결과 (positive/negative/neutral)이며, confidence는 구체적인 판정 확률이다.

{
    "document": {
        "sentiment": "positive",
        "confidence": {
            "negative": 0.037957642,
            "positive": 99.957375,
            "neutral": 0.004668334
        }
    },
    "sentences": [
        {
            "content": "현대자동차 만세!",
            "offset": 0,
            "length": 9,
            "sentiment": "positive",
            "confidence": {
                "negative": 0.0022774586,
                "positive": 0.9974425,
                "neutral": 2.8010004E-4
            },
            "highlights": [
                {
                    "offset": 0,
                    "length": 8
                }
            ]
        }
    ]
}

감정분석 API를 활용하는 현재 프로젝트에서는 "부정" 평가의 경우 "부정" 비율이 99.5% 이상이라면 욕설 및 비속어가 포함된 상태로 간주하여 예외를 발생시켜야 한다.

이를 반영하여 ApiService에 코드를 작성하였고, 실행 결과 문제가 없음을 확인하였다.

@RequiredArgsConstructor
@Service
public class ApiService {

    private final NaverApiConfig naverApiConfig;

    public boolean analyzeComment(String content) {
        // 요청 Header 및 Body 설정
        HttpHeaders headers = new HttpHeaders();
        headers.set(ConstantUtil.CLIENT_ID, naverApiConfig.getClientId());
        headers.set(ConstantUtil.CLIENT_SECRET, naverApiConfig.getClientSecret());
        headers.setContentType(MediaType.APPLICATION_JSON);
        HttpEntity<String> requestEntity = new HttpEntity<>(content, headers);

        // RestTemplate을 이용하여 POST로 요청 후 응답 받기
        RestTemplate restTemplate = new RestTemplate();
        ResponseEntity<String> responseEntity = restTemplate.postForEntity(naverApiConfig.getUrl(), requestEntity, String.class);
        String responseBody = responseEntity.getBody();
        boolean isPositive = true;

        // JSON 형식의 API 응답을 분석하여 긍정/부정 여부 확인
        ObjectMapper objectMapper = new ObjectMapper();
        try {
            JsonNode rootNode = objectMapper.readTree(responseBody);

            String sentiment = rootNode.path("document").path("sentiment").asText();
            if (sentiment.equals("negative")) {
                isPositive = false;
                double documentNegativeConfidence = rootNode.path("document").path("confidence").path("negative").asDouble();
                if (documentNegativeConfidence >= ConstantUtil.LIMIT_NEGATIVE_CONFIDENCE) { // 부정이며 확률이 99.5% 이상일 경우 재작성 요청
                    throw new CommentException(ErrorCode.INVALID_COMMENT);
                }
            }
        } catch (JsonProcessingException e) {
            throw new CommentException(ErrorCode.INVALID_JSON);
        }
        return isPositive;
    }
}

크게 요청 Header 및 Body 설정, POST로 요청 후 응답 수신, 응답 분석으로 단계를 나눌 수 있다.

Naver Cloud API 명세서에서 요구하는 요청 헤더 및 content를 설정한 뒤 RestTemplate를 활용해 전송하고 JSON 분석하고 예외처리해주었다.

RestTemplate vs WebClient

Springboot에서 외부로 API를 요청할 때 대표적으로 이 두 가지를 사용한다.

RestTemplate

  • Spring 3부터 지원하는 Blocking, Multi-Thread 기반 HTTP 통신용 템플릿이다.
  • 사용법이 간단하다.
  • 동기식이기 때문에 동시 사용자가 수천 명 이상 늘어날 경우 매우 느려진다.

WebClient

  • Spring 5에서 추가된 Non-Blocking, Single Thread 기반 인터페이스이다.
  • Spring webflux를 기반으로 하는 비동기 처리가 가능하다.
  • 많은 양의 요청을 병렬적으로 처리할 수 있고, 현재 Spring에선 WebClient의 사용을 권고하고 있다.


실제로 Webflux의 경우 1000명 이상의 동시 사용자가 존재할 때 높은 효율을 보여준다.

다만 현재 요구사항 상 1000명이 동시에 Comment를 작성하는 케이스가 발생할 확률은 매우 낮고, 요청 대상이 안정적인 네이버 클라우드의 API이다.

이를 감안하여 나는 전통적인 동기식인 RestTemplate를 활용하여 신속하게 요구사항을 구현하고자 했다.

물론 feign client과 같은 다른 방법도 존재한다.

profile
Discover Tomorrow

0개의 댓글