활동정리/모각코

2024 하계 모각코 6회차

잔디🌿 2024. 7. 28. 15:53

목표 : RestTemplate을 통해 GPT 연동하는 방법을 정리한다.

 

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

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

 

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

 

1.돈 넣고 키 발급받기

 

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를 눌러 새로운 키를 발급받는다.

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

 

2.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에 연동해보겠다.

 

3.yml파일에 키 값 넣기

 

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

 

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

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

 

4. 요청 보내기

 

우선 우리는 

위 형식으로 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> 형태로 반환되니까 이를 그대로 리턴하도록 한다.

 

5.응답 받기

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의 응답이 들어있다!

 

 

느낀점

다시 정리하니까 확실히 플로우가 잘 보여서 앞으로 블로그 정리를 꼼꼼하게 하는 습관을 가져야겠다고 생각했습니다.