728x90
반응형
SMALL
Spring에서 챗봇 만들기
- 본인은 프로젝트 => 개발자 커뮤니티를 구상, 구현 하던 중 챗봇을 만들어보고싶다는 생각이 들어서 OPENAI API를 사용하여 챗봇을 만들어보고자 하였다. 완성작은 위 동영상 확인
- Spring Boot Framework : 3.2.0
- JAVA : 17
- Lombok
우선 해당 ChatBot은 chatGPT에 요청을 보내면 답변이 오는 방식인데 이것을 토대로 데이터베이스에 저장해놓고 다음에 또 불러올 수 있도록 구현하였음
OPENAI API Key 발급 받기
- https://www.baeldung.com/spring-boot-chatgpt-api-openai
- https://platform.openai.com/docs/api-reference/chat/create
- 해당 문서들를 보고 이해하고 사용하였고 내가 이해한 걸 정리해보았음
회원가입
- https://platform.openai.com 로 이동 후 회원가입
API Key 발급 받기
- 이후 사용할 API Key의 이름을 적고 만들면 사용 가능!
Billing System
- 다들 알다시피 chatGPT3.5 의 경우 무료로 사용 할 수 있지만, ChatGPT4의 경우 구독료를 지불해야 한다.
- 하지만 API의 경우 요청 할 때마다 요금이 부과되고 모델마다 가격이 다르다.
- 따라서 API를 사용할 수 있지만 실제 호출을 통해 답변을 원한다면 돈을 내야한다...........
- Payment methods 가 있는 경우, (카드가 등록이 되어있는 경우) 바로 2번을 눌러 카드를 추가해주면 가능 최소 5불 부터 가능
- 1번의 경우 켜져있다면 내가 충전 (결제) 한 만큼의 사용료를 다 사용했을 경우 자동으로 결제가 되기 때문에 일단 본인은 망설임없이 껏음
- Payment methods 가 없다면 위 사진의 버튼을 눌러 추가해주면 가능
위 준비가 마무리 되었다면 API Key를 사용해서 API를 호출 하는 것이 가능해진다.
OPENAI API 제대로 사용하기 위한 이해
$ curl https://api.openai.com/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-d '{
"model": "gpt-3.5-turbo",
"messages": [{"role": "user", "content": "Hello!"}]
}'
- Header에 뭐가 들어가야 하는지를 확인
- 특히 Authorization 이 Bearer $OPEN_API_KEY 를 볼 수 있다.
- 관련해서 Spring에서 이를 어떻게 구현 할 수 있는지가 관건이었다.
application.yml
- api-url의 경우 저 url로 POST 방식으로 요청을 보냈을 때 답변을 받을 수 있다.
{
"model": "gpt-3.5-turbo",
"messages": [
{
"role": "system",
"content": "hey"
},
{
"role": "user",
"content": "hey"
}
],
"temperature": 1,
"max_tokens": 256,
"top_p": 1,
"frequency_penalty": 0,
"presence_penalty": 0
}
- 각 속성에 대한 설명은 공식문서를 통해서 확인 => [https://platform.openai.com/docs/api-reference/chat/create]
Spring에서 사용하기
DTO
- 위의 답변을 보고 해당 요청을 받았을 때, 자바 객체의 구조
- isFromChat 이 1 이면 true, 0이면 false 이고 true면 GPT로 부터 받은 요청이라는 뜻, false 면 GPT로부터 보낸 요청이라는 뜻
RestTemplate
RestTemplate에 대해서는 글을 또 작성할 예정 ==>
Controller
@Qualifier("openaiRestTemplate")
@Autowired
private RestTemplate restTemplate;
@Value("${openai.model}")
private String model;
@Value("${openai.api-url}")
private String apiUrl;
@GetMapping("/chat")
public String chat(@RequestParam("prompt") String prompt, @AuthenticationPrincipal PrincipalDetails userDetails) {
Long id = (userDetails != null) ? userDetails.getUser().getId() : null;
ChatbotMessage newChatMessage = ChatbotMessage
.builder()
.user_id(id)
.context(prompt)
.isFromChat(0)
.build();
chatbotService.add(newChatMessage);
// create a request
ChatbotRequest request = new ChatbotRequest(model, prompt);
ChatbotResponse response = restTemplate.postForObject(apiUrl, request, ChatbotResponse.class);
if (response == null || response.getChoices() == null || response.getChoices().isEmpty()) {
return "No response";
}
newChatMessage = ChatbotMessage
.builder()
.user_id(id)
.context(response.getChoices().get(0).getMessage().getContent())
.isFromChat(1)
.build();
chatbotService.add(newChatMessage);
return response.getChoices().get(0).getMessage().getContent();
}
Service
@Service
public class ChatbotServiceImpl implements ChatbotService
{
private ChatbotRepository chatbotRepository;
public ChatbotServiceImpl(SqlSession sqlSession){
chatbotRepository = sqlSession.getMapper(ChatbotRepository.class);
}
@Override
public int add(ChatbotMessage msg) {
chatbotRepository.save(msg);
return 1;
}
public List<ChatbotMessage> loadByUserId(Long id){
return chatbotRepository.loadByUserId(id);
}
}
Repository
public interface ChatRepository { // ChatRepository 인터페이스 선언
// 채팅 정보 저장
int save(Chat chat);
// 채팅 ID로 특정 채팅 조회
Chat findById(int id);
// 모든 채팅 목록 조회
List<Chat> findAll(int post_id);
// 채팅 정보 업데이트
int update(Chat chat);
// 채팅 삭제
int delete(Chat chat);
}
Mapper
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.lec.spring.repository.user.ChatbotRepository">
<sql id="SELECT_BASE">
SELECT
chatbot_id "id",
user_id "user_id",
context "context",
isFromChat "isFromChat",
reg_date "regDate"
FROM chatbot
WHERE 1 = 1
</sql>
<resultMap id="mapChatbotMessage" type="com.lec.spring.domain.chatbot.ChatbotMessage">
<result column="id" property="id"/>
<result column="user_id" property="user_id"/>
<result column="context" property="context" />
<result column="isFromChat" property="isFromChat"/>
<result column="regDate" property="regDate"/>
</resultMap>
<select id="loadByUserId" resultMap="mapChatbotMessage">
SELECT
chatbot_id "id",
user_id "user_id",
context "context",
isFromChat "isFromChat",
reg_date "regDate"
FROM
chatbot
WHERE
user_id = #{id}
ORDER BY
reg_date
</select>
<insert id="save" flushCache="true" parameterType="com.lec.spring.domain.chatbot.ChatbotMessage"
keyProperty="id" useGeneratedKeys="true" keyColumn="id">
INSERT INTO chatbot (user_id, context, isFromChat)
VALUES(#{user_id},#{context}, #{isFromChat})
</insert>
</mapper>
- 해당 프로젝트느 MyBatis, Mapper를 사용하여 MySQL 로 구현하였음
위와 같이 설정을 해놓으면 요청을 보낸 메세지, 요청을 받는 메세지 모두 데이터베이스에 저장이 되어서 나중에 사용자가 물어본 대답, 사용자가 요청한 대답 또한 볼 수 있다.
728x90
반응형
LIST
'Spring' 카테고리의 다른 글
[Spring] 스프링 스케쥴 작업 적용 방법 (Feat. @EnableScheduling, @Scheduled) (0) | 2024.01.24 |
---|---|
[Spring] Naver OAuth2 로그인 + Spring Security + Naver 검색 API 활용 (1) | 2024.01.24 |
6장 스프링 DB 접근 기술 (1) | 2023.10.08 |
5장 회원관리예제 - 웹 MVC 개발 (0) | 2023.08.29 |
4장 스프링 빈과 의존관계 (0) | 2023.08.25 |