[OpenAI] OpenAI 를 활용한 챗봇 만들기 2 - DB에서 데이터 가져오기

류재성's avatar
Jun 30, 2024
[OpenAI] OpenAI 를 활용한 챗봇 만들기 2 - DB에서 데이터 가져오기
 
 
이전 블로그에 이어 시작한다.
 

1. 테이블 생성

 
package org.example.chatai.user; import jakarta.persistence.*; import lombok.Data; import lombok.NoArgsConstructor; @Data @NoArgsConstructor @Table(name = "user_tb") @Entity public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String name; private String info; }
 
간단한 회원 테이블을 만든다.
 
package org.example.chatai.user; import org.springframework.data.jpa.repository.JpaRepository; public interface UserRepository extends JpaRepository<User, Long> { }
 
데이터를 불러오기 위해 레파지토리도 만든다.
 
INSERT INTO user_tb (name, info) VALUES ('Alice', 'Alice info'); INSERT INTO user_tb (name, info) VALUES ('Bob', 'Bob info');
 
더미 데이터를 추가한다.
 

2. 데이터 불러오기

 
ChatController
package org.example.chatai.chat; import lombok.RequiredArgsConstructor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.messaging.handler.annotation.MessageMapping; import org.springframework.messaging.handler.annotation.Payload; import org.springframework.messaging.simp.SimpMessageHeaderAccessor; import org.springframework.stereotype.Controller; @RequiredArgsConstructor @Controller public class ChatController { private final ChatService chatService; @MessageMapping("/chat.sendMessage") public void sendMessage(@Payload ChatRequest.ChatMessageDTO requestDTO) { chatService.processMessage(requestDTO); } @MessageMapping("/chat.addUser") public void addUser(@Payload ChatRequest.ChatMessageDTO chatMessage, SimpMessageHeaderAccessor headerAccessor) { headerAccessor.getSessionAttributes().put("username", chatMessage.getSender()); } }
 
사용자가 메세지를 보내면 컨트롤러가 서비스의 processMessage() 를 호출한다.
 
ChatService
package org.example.chatai.chat; import lombok.RequiredArgsConstructor; import org.example.chatai.OpenAI.OpenAIService; import org.example.chatai.user.User; import org.example.chatai.user.UserRepository; import org.springframework.messaging.simp.SimpMessagingTemplate; import org.springframework.stereotype.Service; import java.util.List; import java.util.stream.Collectors; @RequiredArgsConstructor @Service public class ChatService { private final SimpMessagingTemplate messagingTemplate; private final OpenAIService openAIService; private final UserRepository userRepository; public void processMessage(ChatRequest.ChatMessageDTO message) { String userMessage = message.getContent(); // DB에서 모든 사용자 조회 List<User> users = userRepository.findAll(); String userInfo = users.stream() .map(User::getName) .collect(Collectors.joining(", ")); // OpenAI API 요청 String prompt = userMessage + "\nCurrent users in DB: " + userInfo; String aiResponse = openAIService.askOpenAI(prompt); // 응답 메시지 생성 및 전송 ChatRequest.ChatMessageDTO aiMessage = new ChatRequest.ChatMessageDTO(); aiMessage.setContent(aiResponse); aiMessage.setSender("AI"); messagingTemplate.convertAndSend("/topic/messages", aiMessage); } }
 
notion image
 
서비스 레이어가 호출되면 회원 정보를 레파지토리에서 불러온다.
 
💡
userMessage 는 사용자가 입력한 메세지이다. 여기에 DB에서 조회된 데이터 userInfo를 사용자가 입력한 메세지에 포함시켜 API 로 요청보낸다.
 
notion image
 
DB에 있는 데이터 정보를 챗봇을 통해 알 수 있다.
 

3. 데이터가 여러 건일 때

 
💡
샘플링 코드는 name 만 가져왔지만 프로젝트에 적용할 때는 데이터가 여러건이라 데이터를 받을 DTO를 만들었다.
 
song/SongResponse
@Data public static class AIChatDTO{ private Integer songId; private String songTitle; private String genre; private String artistName; private String albumTitle; private Long listenCount; public AIChatDTO(Song song) { this.songId = song.getId(); this.songTitle = song.getTitle(); this.genre = song.getGenre(); this.artistName = song.getArtist().getName(); this.albumTitle = song.getAlbum().getTitle(); this.listenCount = song.getListenCount(); } }
 
필요한 데이터를 담을 DTO를 만든다.
 
package org.example.projectspringfalling.song; import org.example.projectspringfalling.admin.AdminResponse; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; import java.util.List; import java.util.Optional; public interface SongRepository extends JpaRepository<Song, Integer> { @Query("select s,ar,al from Song s join fetch s.album al join fetch s.artist ar") List<Song> findByJoinAlbumAndArtist(); }
 
필요한 데이터를 조회한다.
 
ChatService
package org.example.projectspringfalling.ai.chat; import lombok.RequiredArgsConstructor; import org.example.projectspringfalling.ai.OpenAI.OpenAIService; import org.example.projectspringfalling.album.AlbumRepository; import org.example.projectspringfalling.artist.ArtistRepository; import org.example.projectspringfalling.playlist.PlaylistRepository; import org.example.projectspringfalling.song.Song; import org.example.projectspringfalling.song.SongRepository; import org.example.projectspringfalling.song.SongResponse; import org.springframework.messaging.simp.SimpMessagingTemplate; import org.springframework.stereotype.Service; import java.util.List; import java.util.regex.Pattern; import java.util.stream.Collectors; import static org.example.projectspringfalling._core.utils.ChatLinkUtil.addSongLinks; @RequiredArgsConstructor @Service public class ChatService { private final SimpMessagingTemplate messagingTemplate; private final OpenAIService openAIService; private final SongRepository songRepository; private final AlbumRepository albumRepository; private final ArtistRepository artistRepository; private final PlaylistRepository playlistRepository; public void processMessage(ChatRequest.ChatMessageDTO message) { String userMessage = message.getContent(); // DB에서 모든 사용자 조회 List<Song> songs = songRepository.findByJoinAlbumAndArtist(); String songInfo = songs.stream() .map(song -> new SongResponse.AIChatDTO(song)) .map(aiChatDTO -> aiChatDTO.toString()) // AIChatDTO를 문자열로 변환 .collect(Collectors.joining("; ")); // OpenAI API 요청 String prompt = userMessage + "\nCurrent songs in DB: " + songInfo; String aiResponse = openAIService.askOpenAI(prompt); // 노래 제목을 링크로 변환 String responseWithLinks = addSongLinks(aiResponse, songs); // 응답 메시지 생성 및 전송 ChatResponse.ChatMessageDTO aiMessage = new ChatResponse.ChatMessageDTO(responseWithLinks); messagingTemplate.convertAndSend("/topic/messages", aiMessage); } }
 
notion image
 
조회된 데이터를 DTO에 담은 후 userMessage 와 함께 AIP 요청을 한다.
 
notion image
 
서버에서 조회된 데이터를 바탕으로 채팅을 할 수 있다.
Share article

{CODE-RYU};