Java/Spring Boot
[Java] Spring Boot 환경에서 ChatGPT API 활용하기 -1 : 정의, 환경구성, 간단한 활용방법
adjh54
2023. 12. 30. 16:46
반응형
해당 글에서는 Spring Boot ChatGPT API를 호출하여 ChatGPT를 사용하는 방법에 대해 알아봅니다.
💡 [참고] 2024년 1월 기준으로 변경됨에 따라 아래의 글을 읽으시는 것을 권장드립니다.
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 | 제공된 프롬프트 및 매개변수에 대한 완성을 만듭니다. |
💡 [참고] Deprecated 관련 궁금하시면 아래의 글을 참고하시면 도움이 됩니다.
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
💡 [참고] 환경 파일에 대해 궁금하시면 아래의 글을 참고하시면 도움이 됩니다.
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에서 소스코드를 확인하며 테스트 해볼 수 있습니다.
오늘도 감사합니다. 😀
반응형