[SPRING] spring + openAI(챗지피티) 사용하기

CHOI IN HO·2024년 1월 30일
0

SPRING

목록 보기
40/45

📌참고 API관련하여 주요 사이트

Open AI API 가격 https://openai.com/pricing
Open AI Key 관리 https://platform.openai.com/api-keys
Open AI 사용량 관리 https://platform.openai.com/usage
Open AI Tokenizer https://platform.openai.com/tokenizer
Open AI 모델 종류 https://platform.openai.com/docs/models/overview
Open AI API Document https://platform.openai.com/docs/introduction
Open AI 최신 모델 API https://platform.openai.com/docs/api-reference/chat
Open AI 레거시 모델 API https://platform.openai.com/docs/api-reference/completions

📌ChatGPT

  • openAI에서 개발한 인공지능 모델, 자연어 처리와 대화 기능을 갖춘 대화형 AI모델-
  • 다양한 주제에 대해 대화하고 질문에 답변할 수 있으며, 일상 대화부터 정보 제공 및 문제 해결까지 다양한 용도로 사용될 수 있다.

📌ChatGPT 모델

  1. ChatGPT-3(babbage-002, davinci-002)
  2. ChatGPT-3.5 instruct(4k)
  3. ChatGPT-3.5 Turbo(16k)
  4. ChatGPT-4(32k)
  5. ChatGPT-4 Turbo(128k)

레거시 모델(2023) : gpt-3.5-turbo-instruct, babbage-002, davinci-002
새로운 모델(2023~) : gpt-4, gpt-4 turbo, gpt-3.5-turbo

-> 참고로 기존에 무료모델이 있었으나 현재는 전부 다 유료로 바뀐 것 같다. 자세한 참고사항은 위의 주요사이트에서 검색

📌ChatGPT 수행과정

사용자가 프롬프트를 입력 -> ChatGPT 모델을 통해서 수행 -> 입력받은 값을 토큰으로 변환 -> 입력 받은 값이 토큰으로 변환이 될 때까지 프로세스를 반복

https://www.baeldung.com/cs/chatgpt-model

📌ChatGPT Token

  • 사용자가 입력한 프롬프트 메시지는 ‘토큰’ 단위로 나뉜다. 이러한 토큰은 단어 또는 단어의 일부가 된다.
  • 토큰에는 한도(limit)가 있다 모델이 지원하는 Token에 따라서 프롬프트 값과 응답받은 값의 합에 따라 한도가 지정.
  • 예를 들어 최대 4097개 토큰이 있는 경우, 프롬프트로 4000개의 토큰을 사용한 경우 최대 97개의 토큰으로 응답 값을 반환.

📌openAI key 발급

  1. 아래의 사이트 접근
    https://platform.openai.com/api-keys

  2. API Keys - "Create new Secret Key"

  3. Create new secret key 화면에서 키 이름을 입력하고 ‘Create secret key’ 버튼 클릭

📌Spring boot 설정

📌build.gradle

📌application.yml

📌ChatGptConfig 설정

📌dto 설정

📌Controller 설정

📌Service 구성

package com.realEstate.realEstate.service.ChatGpt;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.realEstate.realEstate.config.ChatGPTConfig;
import com.realEstate.realEstate.model.dto.ChatGpt.ChatCompletionDto;
import com.realEstate.realEstate.model.dto.ChatGpt.CompletionDto;
import com.realEstate.realEstate.service.ChatGpt.ChatGPTService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.List;
import java.util.Map;


@Slf4j
@Service
@RequiredArgsConstructor
public class ChatGPTServiceImpl implements ChatGPTService {

    private final ChatGPTConfig chatGPTConfig;


    @Value("${openai.url.model}")
    private String modelUrl;

    @Value("${openai.url.model-list}")
    private String modelListUrl;

    @Value("${openai.url.prompt}")
    private String promptUrl;

    @Value("${openai.url.legacy-prompt}")
    private String legacyPromptUrl;

    /**
     * 사용 가능한 모델 리스트를 조회하는 비즈니스 로직
     *
     * @return List<Map < String, Object>>
     */
    @Override
    public List<Map<String, Object>> modelList() {
        log.debug("[+] 모델 리스트를 조회합니다.");
        List<Map<String, Object>> resultList = null;

        // [STEP1] 토큰 정보가 포함된 Header를 가져옵니다.
        HttpHeaders headers = chatGPTConfig.httpHeaders();

        // [STEP2] 통신을 위한 RestTemplate을 구성합니다.
        ResponseEntity<String> response = chatGPTConfig
                .restTemplate()
                .exchange(modelUrl, HttpMethod.GET, new HttpEntity<>(headers), String.class);
        try {
            // [STEP3] Jackson을 기반으로 응답값을 가져옵니다.
            ObjectMapper om = new ObjectMapper();
            Map<String, Object> data = om.readValue(response.getBody(), new TypeReference<>() {
            });

            // [STEP4] 응답 값을 결과값에 넣고 출력을 해봅니다.
            resultList = (List<Map<String, Object>>) data.get("data");
            for (Map<String, Object> object : resultList) {
                log.debug("ID: " + object.get("id"));
                log.debug("Object: " + object.get("object"));
                log.debug("Created: " + object.get("created"));
                log.debug("Owned By: " + object.get("owned_by"));
            }
        } catch (JsonMappingException e) {
            log.debug("JsonMappingException :: " + e.getMessage());
        } catch (JsonProcessingException e) {
            log.debug("JsonProcessingException :: " + e.getMessage());
        } catch (RuntimeException e) {
            log.debug("RuntimeException :: " + e.getMessage());
        }
        return resultList;
    }



    @Override
    public Map<String, Object> isValidModel(String modelName) {
        log.debug("[+] 모델이 유효한지 조회합니다. 모델 : " + modelName);
        Map<String, Object> result = new HashMap<>();

        // [STEP1] 토큰 정보가 포함된 Header를 가져옵니다.
        HttpHeaders headers = chatGPTConfig.httpHeaders();

        // [STEP2] 통신을 위한 RestTemplate을 구성합니다.
        ResponseEntity<String> response = chatGPTConfig
                .restTemplate()
                .exchange(modelListUrl + "/" + modelName, HttpMethod.GET, new HttpEntity<>(headers), String.class);
        try {
            // [STEP3] Jackson을 기반으로 응답값을 가져옵니다.
            ObjectMapper om = new ObjectMapper();
            result = om.readValue(response.getBody(), new TypeReference<>() {
            });
        } catch (JsonProcessingException e) {
            log.debug("JsonMappingException :: " + e.getMessage());
        } catch (RuntimeException e) {
            log.debug("RuntimeException :: " + e.getMessage());
        }
        return result;
    }


    /**
     * ChatGTP 프롬프트 검색
     *
     * @param completionDto completionDto
     * @return Map<String, Object>
     */
    @Override
    public Map<String, Object> legacyPrompt(CompletionDto completionDto) {
        log.debug("[+] 레거시 프롬프트를 수행합니다.");

        // [STEP1] 토큰 정보가 포함된 Header를 가져옵니다.
        HttpHeaders headers = chatGPTConfig.httpHeaders();

        // [STEP5] 통신을 위한 RestTemplate을 구성합니다.
        HttpEntity<CompletionDto> requestEntity = new HttpEntity<>(completionDto, headers);
        ResponseEntity<String> response = chatGPTConfig
                .restTemplate()
                .exchange(legacyPromptUrl, HttpMethod.POST, requestEntity, String.class);

        Map<String, Object> resultMap = new HashMap<>();
        try {
            ObjectMapper om = new ObjectMapper();
            // [STEP6] String -> HashMap 역직렬화를 구성합니다.
            resultMap = om.readValue(response.getBody(), new TypeReference<>() {
            });
        } catch (JsonProcessingException e) {
            log.debug("JsonMappingException :: " + e.getMessage());
        } catch (RuntimeException e) {
            log.debug("RuntimeException :: " + e.getMessage());
        }
        return resultMap;
    }


    /**
     * 신규 모델에 대한 프롬프트
     *
     * @param chatCompletionDto {}
     * @return chatCompletionDto
     */
    @Override
    public Map<String, Object> prompt(ChatCompletionDto chatCompletionDto) {
        log.debug("[+] 신규 프롬프트를 수행합니다.");

        Map<String, Object> resultMap = new HashMap<>();

        // [STEP1] 토큰 정보가 포함된 Header를 가져옵니다.
        HttpHeaders headers = chatGPTConfig.httpHeaders();

        // [STEP5] 통신을 위한 RestTemplate을 구성합니다.
        HttpEntity<ChatCompletionDto> requestEntity = new HttpEntity<>(chatCompletionDto, headers);
        ResponseEntity<String> response = chatGPTConfig
                .restTemplate()
                .exchange(promptUrl, HttpMethod.POST, requestEntity, String.class);
        try {
            // [STEP6] String -> HashMap 역직렬화를 구성합니다.
            ObjectMapper om = new ObjectMapper();
            resultMap = om.readValue(response.getBody(), new TypeReference<>() {
            });
        } catch (JsonProcessingException e) {
            log.debug("JsonMappingException :: " + e.getMessage());
        } catch (RuntimeException e) {
            log.debug("RuntimeException :: " + e.getMessage());
        }
        return resultMap;
    }
}

출처
링크텍스트

profile
개발자기 되기 위해선 무엇이든!

0개의 댓글