이전 블로그에 이어 시작한다.
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);
}
}

서비스 레이어가 호출되면 회원 정보를 레파지토리에서 불러온다.
userMessage 는 사용자가 입력한 메세지이다. 여기에 DB에서 조회된 데이터 userInfo를 사용자가 입력한 메세지에 포함시켜 API 로 요청보낸다.

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);
}
}

조회된 데이터를 DTO에 담은 후 userMessage 와 함께 AIP 요청을 한다.

서버에서 조회된 데이터를 바탕으로 채팅을 할 수 있다.
Share article