Java/Spring Boot

[Java] Spring Boot 환경에서 ChatGPT API 활용하기 -1 : 정의, 환경구성, 간단한 활용방법

adjh54 2023. 12. 30. 16:46
반응형
해당 글에서는 Spring Boot ChatGPT API를 호출하여 ChatGPT를 사용하는 방법에 대해 알아봅니다.





 

💡 [참고] 2024년 1월 기준으로 변경됨에 따라 아래의 글을 읽으시는 것을 권장드립니다.
 

[Java] Spring Boot 환경에서 ChatGPT API 활용하기 -2 : 생태계, 레거시, 새로운 모델

해당 글에서는 Spring Boot 환경에서 ChatGPT API를 사용할 때에 2023년 AI 검색도구의 추세를 확인해 보고 API를 사용하는데 필수 개념과 레거시 모델이나 신규 모델을 호출하여 사용하는 방법에 대해

adjh54.tistory.com

 

 

 

 

1) ChatGPT


💡 ChatGPT

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

 

 

💡 OpenAPI 모델 상세 설명
모델 설명
GPT-4 and GPT-4 Turbo GPT-3.5를 개선한 모델들로, 자연어나 코드를 이해하고 생성할 수 있습니다.
GPT-3.5 GPT-3를 개선한 모델들로, 자연어나 코드를 이해하고 생성할 수 있습니다.
DALL·E 자연어 프롬프트를 기반으로 이미지를 생성하고 편집할 수 있는 모델입니다.
TTS 텍스트를 자연스러운 음성 오디오로 변환할 수 있는 모델들의 집합입니다.
Whisper 오디오를 텍스트로 변환할 수 있는 모델입니다.
Embeddings 텍스트를 숫자 형태로 변환할 수 있는 모델들의 집합입니다.
Moderation 민감하거나 안전하지 않은 텍스트를 감지할 수 있는 미세 조정된 모델입니다.
GPT base 지시 사항을 따르지 않는 모델들로, 자연어나 코드를 이해하고 생성할 수 있습니다.
GPT-3 : Legacy 자연어를 이해하고 생성할 수 있는 모델들입니다.
Deprecated 폐기된 모델들과 권장 대체 모델의 전체 목록입니다.

 

 

 

1. ChatGPT Model(GPT-4, GPT-3.5) : 유료


 💡 ChatGPT Model(GPT-4, GPT-3.5) : 유료

- 주된 유료 모델로는 GPT-4, GPT-3.5가 이에 해당이 됩니다.
ChatGTP Group ChatGPT Model Endpoint
Newer models (2023–) gpt-4, gpt-4 turbo, gpt-3.5-turbo https://api.openai.com/v1/chat/completions
Updated legacy models (2023) gpt-3.5-turbo-instruct, babbage-002, davinci-002 https://api.openai.com/v1/completions
Legacy models (2020–2022) text-davinci-003, text-davinci-002, davinci, curie, babbage, ada https://api.openai.com/v1/completions

 

 

 

2. ChatGPT Model(GPT-3) : 무료


💡 GPT-3

- GPT-3 모델들은 자연어를 이해하고 생성할 수 있습니다. 이 모델들은 보다 강력한 GPT-3.5 세대 모델로 대체되었습니다.
- 그러나 GPT-3 베이스 모델인 davinci, curie, ada, and babbage는 현재 유일하게 세세하게 조정할 수 있는 모델들입니다.

💡 ChatGPT Model(GPT-3) : 무료

- 주된 무료 모델로는 GPT-3가 이에 해당이 됩니다.
모델 설명
text-davinci-001 - 일반적인 자연어 이해 및 생성에 사용되는 강력한 대화형 AI 모델입니다.
- 다른 모델들이 할 수 있는 모든 작업을 수행할 수 있으며, 종종 더 높은 품질로 수행합니다.
text-curie-001 - 다양한 자연어 작업에 사용되는 강력한 대화형 AI 모델입니다.
- 매우 능숙하며, Davinci보다 빠르고 저렴합니다. 
text-babbage-001  - 자연어 생성 작업에 사용되는 AI 모델입니다.
- 간단한 작업에 적합하며 매우 빠르고 저렴합니다.
text-ada-001 - 코드 생성 및 프로그래밍 작업에 사용되는 AI 모델입니다.
- 매우 간단한 작업에 적합하며 GPT-3 시리즈 중에서 가장 빠르고 저렴합니다. 

 

 

💡 [참고] 아쉽지만 2024년 01월 04일부로 무료 버전은 Deprecated 되었습니다.

 

 

 

 

2) ChatGPT API reference


 💡 ChatGPT API reference

- ChatGPT API reference에서 제공해 주는 API에 대해서 알아봅니다.

- 해당 API는 변동이 있을 수 있습니다. 2023년 12월 30일 기준으로 작성하였습니다.

 

1. 공통


💡 Models

- API에서 사용할 수 있는 다양한 모델을 나열하고 설명합니다.
- 모델 설명서를 참조하여 사용 가능한 모델과 모델 간의 차이점을 이해할 수 있습니다.
분류 상세 분류 HTTP Method Endpoint 설명
Models List Models GET https://api.openai.com/v1/models 현재 사용 가능한 모델을 나열하고, 각 모델의 소유자와 가용성과 같은 기본 정보를 제공합니다.
Models Retrieve Models GET https://api.openai.com/v1/models/{model} 모델 인스턴스를 검색하여 소유자, 권한 등 모델에 대한 기본 정보를 제공합니다.
Models Delete a fine-tuned model DELETE https://api.openai.com/v1/models/{model} 미세 조정된 모델을 삭제합니다. 모델을 삭제하려면 조직의 소유자 역할이 있어야 합니
다.

 

 

 

2. 유료 버전 API


 💡 Chat

- 대화를 구성하는 메시지 목록이 주어지면 모델은 응답을 반환합니다.
분류 상세 분류 HTTP Method Endpoint 설명
Chat Create chat completion POST https://api.openai.com/v1/chat/completions 지정된 채팅 대화에 대한 모델 응답을 생성합니다.

 

 

 

3. 무료 버전 API


💡 Completion

- 프롬프트가 주어지면 모델은 각 위치에서 대체 토큰의 확률과 함께 하나 이상의 예상 완료를 반환합니다.
- 대부분의 개발자는 최고의 최신 모델을 활용하기 위해 Chat Completions API를 사용해야 합니다.
- 레거시 완료 엔드포인트를 지원하는 대부분의 모델은 2024년 1월 4일에 종료됩니다.
분류 상세 분류 HTTP Method Endpoint 설명
Completion Create Completion POST https://api.openai.com/v1/completions 제공된 프롬프트 및 매개변수에 대한 완성을 만듭니다.

OpenAI Platform

 

 

💡 [참고] Deprecated 관련 궁금하시면 아래의 글을 참고하시면 도움이 됩니다.

OpenAI Platform

 

 

 

3) ChatGPT 개발환경 및 구성-1 : OpenAI API Key 발급


 💡 OpenAI API Key 발급

- ChatGPT와 통신을 하기 위해 OpenAI API Key를 발급받는 과정에 대해 알아봅니다.

 

 

1. 아래의 사이트에 접근합니다.


https://platform.openai.com/api-keys

 

 

2. OpenAI에 접속하여 API Keys - ‘Create new Secret Key’ 버튼을 선택합니다.


 

 

 

 

3. Create new secret key 화면에서 키 이름을 입력하고 ‘Create secret key’ 버튼을 누릅니다.


💡 해당 발급되는 Key 값에 대해서는 이후 따로 확인이 불가능하기에 별도의 키를 관리하셔야 합니다.

 

 

 

4. 아래와 같이 API Key가 발급되었습니다.


 

 

 

 

4) ChatGPT 개발환경 및 구성-1 : 개발환경 및 활용방법


 

1. 개발환경 구조


💡 개발환경 구조

1. User → Controller

- 사용자는 API로 Prompt를 입력하여 API Call을 수행합니다.

2.Controller → Service
- Controller에서 해당 엔드포인트를 받아주고 Service를 호출합니다.

3. Serivce → ServiceImpl → ChatGPT3
- ServiceImpl에서는 RestTemplate을 이용하여 ChatGPT3로 SecretKey와 함께 주요 정보를 전달합니다.

4. ChatGPT3 → ServiceImpl → Controller → User
- 처리된 응답 결과를 반환해 줍니다.

 

 

 

💡 디렉터리 패키지 구조

 

 

 

2. 라이브러리 추가


 💡 라이브러리 추가

- Spring Boot Web: API 통신과 RestTemplate을 이용할 때 사용합니다.
- Lombok: 기본적인 DTO 구성을 위해 사용합니다.
dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web'
    compileOnly 'org.projectlombok:lombok'
    annotationProcessor 'org.projectlombok:lombok'
    providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat'
}

 

 

 

3. application.properties 구성


 💡 application.properties 구성

- 공통 사용 및 키 값 노출을 위해 properties 파일에 사용할 모델과 secret-key를 입력하였습니다.
openai.model=text-davinci-001
openai.secret-key= xxxxxxxxxx

 

 💡 [참고] 환경 파일에 대해 궁금하시면 아래의 글을 참고하시면 도움이 됩니다.
 

[Java] 개발 환경에 따라 각각 환경 파일 구성 방법: application.properties

해당 글에서는 Spring Boot 기반 로컬, QA, 운영 환경에서 각각 다른 환경파일을 사용하는 방법에 대해서 공유합니다. 1) 개발환경 분류 이름 버전 언어 Java 11 프레임워크 Spring Boot 2.7.12 프레임워크 Sp

adjh54.tistory.com

 

 

4. ChatGPT Config


💡 ChatGPT Config

1. RestTemplate을 사용하기 위한 객체를 구성하였습니다.
2. HttpHeader에서 JWT 토큰으로 Bearer 토큰 값을 입력하여서 전송하기 위한 공통 Header를 구성하였습니다.
package com.multiflex.multiflexchatgpt.config;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.web.client.RestTemplate;

/**
 * ChatGPT에서 사용하는 환경 구성
 *
 * @author : lee
 * @fileName : RestTemplate
 * @since : 12/29/23
 */
@Configuration
public class ChatGPTConfig {

    @Value("${openai.secret-key}")
    private String secretKey;

    @Bean
    public RestTemplate restTemplate() {
        RestTemplate restTemplate = new RestTemplate();
        return restTemplate;
    }

    @Bean
    public HttpHeaders httpHeaders() {
        HttpHeaders headers = new HttpHeaders();
        headers.set("Authorization", "Bearer " + secretKey);
        headers.setContentType(MediaType.APPLICATION_JSON);
        return headers;
    }
}

 

 

 

5. ChatGPT DTO


💡 ChatGPT DTO

- 요청 및 응답 값에 대해 객체로 구성하기 위한 방법으로 우선적으로 Prompt로 호출하는 DTO만 구성하였습니다.
package com.multiflex.multiflexchatgpt.dto;

import lombok.AccessLevel;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

/**
 * 프롬프트 요청 DTO
 *
 * @author : lee
 * @fileName : CompletionRequestDto
 * @since : 12/29/23
 */
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class CompletionRequestDto {

    private String model;

    private String prompt;

    private float temperature;

    @Builder
    CompletionRequestDto(String model, String prompt, float temperature) {
        this.model = model;
        this.prompt = prompt;
        this.temperature = temperature;
    }

}

 

 

 

6. ChatGPT Controller


💡 ChatGPT Controller

- 해당 글에서는 3가지 API 테스트를 진행할 예정입니다.
API Endpoint HTTP Methods 설명 Open API Endpoint
/api/v1/chatGpt/modelList GET OpenAPI의 사용가능한 모델 리스트를 조회하는 API https://api.openai.com/v1/models
/api/v1/chatGpt/model GET OpenAPI에서 유효한 모델인지 체크를 하는 API https://api.openai.com/v1/models/{modelName}
/api/v1/chatGpt/prompt POST ChatGPT 모델을 이용하여 프롬프트를 호출하는 API https://api.openai.com/v1/completions
package com.multiflex.multiflexchatgpt.controller;

import com.multiflex.multiflexchatgpt.dto.CompletionRequestDto;
import com.multiflex.multiflexchatgpt.service.ChatGPTService;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

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

/**
 * ChatGPT API
 *
 * @author : lee
 * @fileName : ChatGPTController
 * @since : 12/29/23
 */
@RestController
@RequestMapping(value = "/api/v1/chatGpt")
public class ChatGPTController {

    private final ChatGPTService chatGPTService;

    public ChatGPTController(ChatGPTService chatGPTService) {
        this.chatGPTService = chatGPTService;
    }

    /**
     * [API] ChatGPT 모델 리스트를 조회합니다.
     */
    @GetMapping("/modelList")
    public ResponseEntity<List<Map<String, Object>>> selectModelList() {
        List<Map<String, Object>> result = chatGPTService.modelList();
        return new ResponseEntity<>(result, HttpStatus.OK);
    }

    /**
     * [API] ChatGPT 유효한 모델인지 조회합니다.
     *
     * @param modelName
     * @return
     */
    @GetMapping("/model")
    public ResponseEntity<Map<String, Object>> isValidModel(@RequestParam(name = "modelName") String modelName) {
        Map<String, Object> result = chatGPTService.isValidModel(modelName);
        return new ResponseEntity<>(result, HttpStatus.OK);
    }

    /**
     * [API] ChatGPT 모델 리스트를 조회합니다.
     */
    @PostMapping("/prompt")
    public ResponseEntity<Map<String, Object>> selectPrompt(@RequestBody CompletionRequestDto completionRequestDto) {
        Map<String, Object> result = chatGPTService.prompt(completionRequestDto);
        return new ResponseEntity<>(result, HttpStatus.OK);
    }

}

 

 

 

 

7. ChatGPT Service (interface)


package com.multiflex.multiflexchatgpt.service;

import com.multiflex.multiflexchatgpt.dto.CompletionRequestDto;
import org.springframework.stereotype.Service;

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

/**
 * ChatGPT 서비스 인터페이스
 *
 * @author : lee
 * @fileName : ChatGPTService
 * @since : 12/29/23
 */

@Service
public interface ChatGPTService {

    List<Map<String, Object>> modelList();

    Map<String, Object> prompt(CompletionRequestDto completionRequestDto);

    Map<String, Object> isValidModel(String modelName);

}

 

 

 

 

 

8. ChatGPT ServiceImpl(implements)


package com.multiflex.multiflexchatgpt.service.impl;

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.multiflex.multiflexchatgpt.config.ChatGPTConfig;
import com.multiflex.multiflexchatgpt.dto.CompletionRequestDto;
import com.multiflex.multiflexchatgpt.service.ChatGPTService;
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;

/**
 * ChatGPT Service 구현체
 *
 * @author : lee
 * @fileName : ChatGPTServiceImpl
 * @since : 12/29/23
 */
@Slf4j
@Service
public class ChatGPTServiceImpl implements ChatGPTService {

    private final ChatGPTConfig chatGPTConfig;

    public ChatGPTServiceImpl(ChatGPTConfig chatGPTConfig) {
        this.chatGPTConfig = chatGPTConfig;
    }

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

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

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

        // [STEP2] 통신을 위한 RestTemplate을 구성합니다.
        ResponseEntity response = chatGPTConfig.restTemplate()
                .exchange(
                        "<https://api.openai.com/v1/models>",
                        HttpMethod.GET,
                        new HttpEntity<>(headers),
                        String.class);

        try {
            // [STEP3] Jackson을 기반으로 응답값을 가져옵니다.
            ObjectMapper om = new ObjectMapper();
            List<Map<String, Object>> data = om.readValue(response.getBody(), new TypeReference<>() {
            });

            // [STEP4] 응답 값을 결과값에 넣고 출력을 해봅니다.
            resultList = (List<Map<String, Object>>) data.get("data");
            for (List<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("RuntimeException :: " + e.getMessage());
        }
        return resultList;
    }

    /**
     * 모델이 유효한지 확인하는 비즈니스 로직
     *
     * @param modelName
     * @return
     */
    @Override
    public List<Map<String, Object>> isValidModel(String modelName) {
        log.debug("[+] 모델이 유효한지 조회합니다. 모델 : " + modelName);
        List<Map<String, Object>> result;

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

        // [STEP2] 통신을 위한 RestTemplate을 구성합니다.
        ResponseEntity response = chatGPTConfig.restTemplate()
                .exchange(
                        "<https://api.openai.com/v1/models/>" + 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) {
            throw new RuntimeException(e);
        }
        return result;
    }

    /**
     * ChatGTP 프롬프트 검색
     *
     * @param completionRequestDto
     * @return
     */
    @Override
    public List<Map<String, Object>> prompt(CompletionRequestDto completionRequestDto) {
        log.debug("[+] 프롬프트를 수행합니다.");

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

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

        String requestBody = "";
        ObjectMapper om = new ObjectMapper();

        // [STEP3] properties의 model을 가져와서 객체에 추가합니다.
        completionRequestDto = completionRequestDto.builder()
                .model(model)
                .prompt(completionRequestDto.getPrompt())
                .temperature(0.8f)
                .build();

        try {
            // [STEP4] Object -> String 직렬화를 구성합니다.
            requestBody = om.writeValueAsString(completionRequestDto);
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }

        // [STEP5] 통신을 위한 RestTemplate을 구성합니다.
        HttpEntity requestEntity = new HttpEntity<>(completionRequestDto, headers);
        ResponseEntity response = chatGPTConfig.restTemplate()
                .exchange(
                        "<https://api.openai.com/v1/completions>",
                        HttpMethod.POST,
                        requestEntity,
                        String.class);
        try {
            // [STEP6] String -> HashMap 역직렬화를 구성합니다.
            result = om.readValue(response.getBody(), new TypeReference<>() {
            });
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
        return result;
    }
}

 

 

 

 

5) 결과 확인


💡 결과 확인

- 아래에 API Endpoint로 호출을 수행하여 결과를 확인합니다.

 

API Endpoint HTTP Method  설명 Open API Endpoint
/api/v1/chatGpt/modelList GET OpenAPI의 사용가능한 모델 리스트를 조회하는 API https://api.openai.com/v1/models
/api/v1/chatGpt/model GET OpenAPI에서 유효한 모델인지 체크를 하는 API https://api.openai.com/v1/models/{modelName}
/api/v1/chatGpt/prompt POST ChatGPT 모델을 이용하여 프롬프트를 호출하는 API https://api.openai.com/v1/completions

 

 

1. 모델 리스트 조회


💡 모델 리스트 조회

- ”http://localhost:8080/api/v1/chatGpt/modelList“ API Endpoint로 호출을 하여 결과를 얻었습니다.

https://platform.openai.com/docs/api-reference/models/list

 

 

 

2. 유효한 모델 조회


💡 유효한 모델 조회

- “http://localhost:8080/api/v1/chatGpt/model?modelName=text-davinci-001” API Endpoint로 호출을 하여 OpenAI에서 사용하려는 모델에 대해 유효한지에 대한 여부를 확인해 봅니다.

https://platform.openai.com/docs/api-reference/models/retrieve

 

 

 

3. 프롬프트 호출


💡 프롬프트 호출

- “http://localhost:8080/api/v1/chatGpt/prompt”API Endpoint로 호출을 하여 프롬프트를 호출하였습니다.

 

파라미터 필수여부 설명
model 필수 사용할 모델의 ID입니다. 모델 목록 API를 사용하여 사용 가능한 모든 모델을 확인하거나 모델 개요에서 해당 모델에 대한 설명을 볼 수 있습니다.
prompt 필수 문자열, 문자열 배열, 토큰 배열 또는 토큰 배열로 인코딩된 완성을 생성하기 위한 프롬프트입니다.
max_token 선택 완료 시 생성될 수 있는 최대 토큰 수입니다.
temperature 선택 사용할 샘플링 온도는 0에서 2 사이입니다. 0.8과 같이 값이 높을수록 출력이 더 무작위로 만들어지고, 0.2와 같이 값이 낮을수록 더 집중적이고 결정적이게 됩니다.

 

 

💡 [참고] max_token에 대해 궁금하시면 아래의 글을 참고하시면 도움이 됩니다.

https://platform.openai.com/tokenizer

 

 

 

https://platform.openai.com/docs/api-reference/completions/create

 

 

 

 

4. 사용량 확인


💡 사용량 확인

- Usage 탭을 이용하면 API 호출 횟수와 금액이 출력이 됩니다.

 

 

 

 

💡 [참고] 아래의 Repository에서 소스코드를 확인하며 테스트 해볼 수 있습니다.
 

blog-codes/spring-boot-chatgpt at main · adjh54ir/blog-codes

Contributor9 티스토리 블로그 내에서 활용한 내용들을 담은 레포지토리입니다. Contribute to adjh54ir/blog-codes development by creating an account on GitHub.

github.com

 

 

 

 

 

 

오늘도 감사합니다. 😀

 

 

 

 

반응형