본문 바로가기
Back-end/Spring

[Spring] RestTemplate로 ChetGPT 연결하기

by 잔디🌿 2024. 8. 7.

    이번 해커톤 프로젝트를 하면서 chetGPT를 연동해야 할 일이 생겼다.

    위와 같이 일기를 쓰면 그에 대한 코멘트를 챗지피티를 통해 보여준다.(일기 마저도 챗 지피티에서 따왔다ㅋㅋ)

     

    팀원분이 지피티를 연동해보는 경험을 해봤으면 좋겠다고 하셔서 내가 하게 되었다. 처음에는 좀 어려워보이는 기능이라 겁먹었지만 막상 하니까 그렇게 어렵진 않았다. 역시 경험이 중요하다는 것을 깨닫게 되었다.

     

    돈 넣고 키 발급받기

     

    GPT를 그냥 쓸 때는 3.5는 무료로 쓸 수 있지만, OpenAI를 통해서 GPT를 쓰기 위해서는 3.5도 돈을 내야한다.

    새로 만든 계정에는 몇달러 준다는 말도 있던데 나는 아니었다..ㅜㅜ

     

    https://platform.openai.com/playground/chat?models=gpt-4o

    OpenAi 사이트에 들어가서 회원가입을 한 후 Billing에 들어간다.

    그 다음 Add to credit balance를 클릭하면 돈을 넣을 수 있다.

    GPT는 돈이 생각보다 많이 안나온다. 프로젝트로 부스운영도 했는데 0.16달러 썼다. 그래서 최소 금액인 5달러만 넣는 것을 추천한다.

     

    이제 키를 발급받아야한다. 이 키 관리는 너무너무 중요하다. 만약 키가 노출되면 누구든 여러분의 계정으로 지피티를 돌릴 수 있다. (돈이 순식간에 다 나가버릴 수 있다). 프로그램 내에 작성해두고 git에 push할 때 특히 주의해야한다.

    실수로 그냥 push할 뻔 했는데 인텔리제이에 다행히 키가 포함된 코드를 push하면 막아주는 기능이 있었다! 다행이다.

     

    Your profile -> User API keys에 들어가서 Create new secret key를 눌러 새로운 키를 발급받는다.

    키 복사는 발급받은 직후만 가능하므로, 바로 복사해서 메모장에 저장해둬야한다.

     

    PostMan을 통해서 테스트해보기

     

    키가 정상적으로 발급되었는지, 요청에 대한 응답이 잘 오는지를 postman을 통해  테스트 해 보아야한다.

    POST요청으로 보내고, url은 https://api.openai.com/v1/chat/completions로 한다.

    그 다음 Body값을 넣어준다.

    "model"에는 사용할 GPT모델명을 넣는다. 나는 3.5 터보 모델을 사용했다.

    그 다음 messages내의 role에는 "user"을 넣고, "content" 부분에는 GPT에게 보낼 내용을 넣는다. 나는 일기와 함께 GPT에게 요구하는 내용을 보냈다.

     

    내 키 지켜

     

    그 다음 헤더에 Authorization을 추가하고 "Bearer 키값" 을 넣는다.

     

    요청을 보내면

    위와 같이 응답이 잘 오는 것을 볼 수 있다.

    우리가 원하는 응답은 choices -> message -> content에 있다.

     

    이제 본격적으로 sping에 연동해보겠다.

     

    yml파일에 키 값 넣기

     

    아까 언급했듯이 키값은 매우 소중하다. 그래서 깃에 올릴 파일들에 직접 넣으면 안되고, yml파일에서 다루고, 이를 Value를 통해서 가져오는 방식을 사용해야한다.

     

    src -> main -> resources 안에 yml파일을 만들어준다.(없으면!)

    그 다음 yml파일 안에 위와 같이 입력해준다.

     

    요청 보내기

     

    우선 우리는 

    위 형식으로 GPT에게 우리의 요청을 보내야한다. 이를 위해서 DTO를 생성해보았다.

    package com.backend.filb.dto.request;
    
    import com.backend.filb.domain.entity.Message;
    
    import java.util.List;
    
    public record DiaryRequestToGpt(
            String model,
            List<Message> messages
    ) {
    }

    record로 작성했고, String형의 model과 List<Message>형의 messages를 만들었다.

     

    package com.backend.filb.domain.entity;
    
    public class Message {
        private String role;
        private String content;
    
        public Message() {}
    
        public Message(String role, String content) {
            this.role = role;
            this.content = content;
        }
    
        public String getRole() {
            return role;
        }
    
        public String getContent() {
            return content;
        }
    }
    

    Message DTO는 위와 같이 구성하였다.

     

        private final String chatGptUrl = "https://api.openai.com/v1/chat/completions";
    
        @Value("${chatgpt.api-key}")
        private String gptKey;
        
            public ResponseEntity<Object> getReport(String content) throws JsonProcessingException {
            String messages = content + " 위 일기에 대해서 ~때문에 ~ 감정을 느끼신 것 같다 형식으로 감정을 공감해주고 해결책을 제시해주는 방향으로 이야기해줘.";
    
            Message message = new Message("user",messages);
            List<Message> messageList = new LinkedList<>();
            messageList.add(message);
    
            DiaryRequestToGpt diaryRequestToGpt = new DiaryRequestToGpt("gpt-3.5-turbo",messageList);
    
            String jsonBody = objectMapper.writeValueAsString(diaryRequestToGpt);
    
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(APPLICATION_JSON);
            headers.add("Authorization","Bearer " + gptKey);
    
            HttpEntity<String> requestEntity = new HttpEntity<>(jsonBody, headers);
            return restTemplate.exchange(chatGptUrl, HttpMethod.POST, requestEntity, Object.class);
        }

    이제 restTemplate를 통해서 gpt에게 요청을 보낸다.

    chatGptUrl에는 https://api.openai.com/v1/chat/completions를 넣고

    gptKey값은 yml에 있는 값을 가져오기 위해 @Value 어노테이션을 사용한다.

     

    그 다음 gpt에게 보낼 메세지를 만든다. 나는 해당 메서드의 파라미터로 일기를 받아서 이 일기에다가 gpt에게 바라는 요구사항을 붙여서 message를 만들었다. 그 다음 이를 사용해서 Message 객체를 만들고, 만든 객체를 메세지리스트에 넣었다. 

    이 리스트와 함께 모델명을 담은 값을 넣어 DiaryRequestToGpt 객체를 만든다.

    이를 objectMapper을 통해서 json형태로 만들어준다. 

    이렇게 하면 body가 완성된다.

     

    이제 header에 키값을 넣는다. header에 키 값은 "Authorization"으로, value값은 "Bearer " + gptKey를 넣는다.

    그 다음 HttpEntity<String>을 만든다. 여기에는 그냥 만든 header과 body를 넣으면 된다.

     

    이제 restTemplate를 통해 api를 보낸다. 헤더와 바디가 있으니까 exchange를 사용하였다.

    exchange안에는 chatGptUrl,HttpMethod.POST(POST로 보내니까), requestEntity, Object.class를 넣는다.

    exchange를 하면 ResponseEntity<Object> 형태로 반환되니까 이를 그대로 리턴하도록 한다.

     

    응답 받기

    public String getFeedBack(String content) throws JsonProcessingException {
        ObjectMapper objectMapper = new ObjectMapper();
        ResponseEntity<Object> feedBack = emotionApi.getReport(content);
        String responseBody = objectMapper.writeValueAsString(feedBack.getBody());
    
        JsonNode rootNode = objectMapper.readTree(responseBody);
        String extractedContent = rootNode.path("choices").get(0).path("message").path("content").asText();
    
        return extractedContent;
    }

    이제 응답받은 값에서 gpt의 답을 추출해야한다.

    feedBack에는 위에서 받은 ResponseEntity가 들어있습니다. 이 값의 body를 꺼내서 writeValueAsString 을 통해 String 형태로 바꾸고 이를 ObjectMapper.readTree를 통해서 JsonNode로 파싱한다. 그 다음 이 안에 있는 값을 text로 꺼내온다.

    이 안에는 우리가 원하는 gpt의 응답이 들어있다!