
이 글을 보는 사람은 프로젝트 생성정도는 할 줄 알거라 판단하고
간단하게 글로만 적고 넘기도록함
jdk 17
spring boot 3.2.0
Spring web
Lombok

properties에 사용할 gpt 모델과 gpt api key
gpt api url을 아래와 같이 설정해준다
gpt.model=gpt-3.5-turbo
gpt.api.key=발급 받은 api키
gpt.api.url=https://api.openai.com/v1/chat/completions
우선 요청을 보내기 위해 RestTemplate을 설정하는 클래스가 필요하다
package com.example.demo.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
@Configuration
public class GPTConfig {
@Value("${gpt.api.key}")
private String apiKey;
@Bean
public RestTemplate restTemplate(){
RestTemplate template = new RestTemplate();
template.getInterceptors().add((request, body, execution) -> {
request.getHeaders().add(
"Authorization"
,"Bearer "+apiKey);
return execution.execute(request,body);
});
return template;
}
}
restTemplate를 @Bean 어노테이션을 사용하여 Bean에 등록 시켜준다
RestTemplate 인스턴스를 생성하고 HTTP 요청의 헤더에 Authorization 헤더를 추가하는 인터셉터를 설정함 이 인터셉터는 이제 모든 요청에 대해 OpenAI API 키를 포함시킴
요청을 보낼때 Json 형식이
다음과 같이 필요로하다
{
"model": "gpt-3.5-turbo",
"messages": [
{
"role": "user",
"content": ""
}
],
"temperature": 1,
"max_tokens": 256,
"top_p": 1,
"frequency_penalty": 0,
"presence_penalty": 0
}
"temperature": 1,
"max_tokens": 256,
"top_p": 1,
"frequency_penalty": 0,
"presence_penalty": 0
는 필수가 아니라 있어도 되고 없어도 되는거 같다
package com.example.demo.dto;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.PropertyNamingStrategies;
import com.fasterxml.jackson.databind.annotation.JsonNaming;
import lombok.Data;
import java.util.ArrayList;
import java.util.List;
@Data
@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)
public class GPTRequest {
private String model;
private List<Message> messages;
private int temperature;
private int maxTokens;
private int topP;
private int frequencyPenalty;
private int presencePenalty;
public GPTRequest(String model
, String prompt
, int temperature
, int maxTokens
, int topP
, int frequencyPenalty
, int presencePenalty) {
this.model = model;
this.messages = new ArrayList<>();
this.messages.add(new Message("user",prompt));
this.temperature = temperature;
this.maxTokens = maxTokens;
this.topP=topP;
this.frequencyPenalty=frequencyPenalty;
this.presencePenalty = presencePenalty;
}
}
@JsonProperty 어노테이션을 사용해 필드에 하나씩 다 매핑 해주는 방법도 있지만
@JsonNaming을 사용하면 간단하게 snake case로 바꿔준다 혹시 @JsonNaming을 처음 본다면
아래 주소를 참고
생성자는 List를 구현하는 ArrayList로 한 다음
Message을 생성할때 roler과 prompt를 추가해준다.
Meesage 클래스는 DTO 마지막에 있다
아까도 말했지만
"temperature": 1,
"max_tokens": 256,
"top_p": 1,
"frequency_penalty": 0,
"presence_penalty": 0
얘네는 필수가 아니다
model,messages만 있어도 동작함
요청을 보냈으니 응답을 받을 클레스도 필요하다
아래와 같이 만들어주면 된다.
package com.example.demo.dto;
import lombok.*;
import java.util.List;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class GPTResponse {
private List<Choice> choices;
@Data
@AllArgsConstructor
@NoArgsConstructor
public static class Choice {
//gpt 대화 인덱스 번호
private int index;
// 지피티로 부터 받은 메세지
// 여기서 content는 유저의 prompt가 아닌 gpt로부터 받은 response
private Message message;
}
}
내부 클레스로 Choice를 만들어서
인덱스 번호와 message를 뽑아오면 된다
이제 응답과 요청을 주고 받을떄
필요한 Message 클레스를 만들면 된다.
package com.example.demo.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Message {
private String role;
private String content;
}
여기서 content는 요청을 보낼땐 prompt가 되고 받을땐 gpt가 응답한 내용이 된다
이제 api tester로 테스트 하기위한 컨트롤러를 만들어준다.
package com.example.demo.controller;
import com.example.demo.dto.GPTRequest;
import com.example.demo.dto.GPTResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
@RestController
@RequestMapping("/gpt")
@RequiredArgsConstructor
public class GPTController {
@Value("${gpt.model}")
private String model;
@Value("${gpt.api.url}")
private String apiUrl;
private final RestTemplate restTemplate;
@GetMapping("/chat")
public String chat(@RequestParam("prompt") String prompt){
GPTRequest request = new GPTRequest(
model,prompt,1,256,1,2,2);
GPTResponse gptResponse = restTemplate.postForObject(
apiUrl
, request
, GPTResponse.class
);
return gptResponse.getChoices().get(0).getMessage().getContent();
}
}
Message 클래스에 content는 보낼땐 prompt가 되고
받을땐 gpt로부터 받은 응답내용이 된다.
"temperature": 1,
"max_tokens": 256,
"top_p": 1,
"frequency_penalty": 0,
"presence_penalty": 0
이 부분을 필드에 지정 하지 않았다면 GPTRequest 생성자 매개변수에
prompt 이후 부분은 다 필요없다

성공적으로 됐지만 개인적으로 0으로 맞추는거 추천
frequency penalty,presence penalty를 높였더니 애가 이상해짐
이상한 부분이나 잘못된 부분이 있다면 지적 부탁드립니당
테스트 어떤걸로 하신거에요 ? (마지막 사진)