본문 바로가기

Spring

[Spring] OpenAI API를 활용하여 ChatBot만들기

728x90
반응형
SMALL
구현한 챗봇 동작

Spring에서 챗봇 만들기

  • 본인은 프로젝트 => 개발자 커뮤니티를 구상, 구현 하던 중 챗봇을 만들어보고싶다는 생각이 들어서 OPENAI API를 사용하여 챗봇을 만들어보고자 하였다. 완성작은 위 동영상 확인
  • Spring Boot Framework : 3.2.0
  • JAVA : 17
  • Lombok

우선 해당 ChatBot은 chatGPT에 요청을 보내면 답변이 오는 방식인데 이것을 토대로 데이터베이스에 저장해놓고 다음에 또 불러올 수 있도록 구현하였음

 

 

OPENAI API Key 발급 받기

회원가입

API Key 발급 받기

API Keys로 이동

 

해당 버튼 클릭

  • 이후 사용할 API Key의 이름을 적고 만들면 사용 가능!

 

Billing System

  • 다들 알다시피 chatGPT3.5 의 경우 무료로 사용 할 수 있지만, ChatGPT4의 경우 구독료를 지불해야 한다.
  • 하지만 API의 경우 요청 할 때마다 요금이 부과되고 모델마다 가격이 다르다.
  • 따라서 API를 사용할 수 있지만 실제 호출을 통해 답변을 원한다면 돈을 내야한다...........

 

Settings 밑에 있는 Billing 선택

  • 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

openAI API를 요청할 때 필요한 값들

  • api-url의 경우 저 url로 POST 방식으로 요청을 보냈을 때 답변을 받을 수 있다.

 

Auth 부분
Header 부분

{
  "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
}

 

요청을 했을 때의 예시

 

Spring에서 사용하기

DTO

  • 위의 답변을 보고 해당 요청을 받았을 때, 자바 객체의 구조

Message
Post 보낼때
요청을 받을 때
데이터베이스에 저장하기 위해 만든 자바 객체

  • isFromChat 이 1 이면 true, 0이면 false 이고 true면 GPT로 부터 받은 요청이라는 뜻, false 면 GPT로부터 보낸 요청이라는 뜻

RestTemplate

MVCconfig 파일을 하나 만들어주고 configuration 어노테이션을 걸어주고 메세지를 보낼때마다 지속적으로 사용할 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