캐릭터 챗봇 #338
| @@ -7,16 +7,16 @@ import javax.persistence.JoinColumn | ||||
| import javax.persistence.ManyToOne | ||||
| 
 | ||||
| @Entity | ||||
| class CharacterChatMessage( | ||||
| class ChatMessage( | ||||
|     val message: String, | ||||
| 
 | ||||
|     @ManyToOne(fetch = FetchType.LAZY) | ||||
|     @JoinColumn(name = "chat_room_id", nullable = false) | ||||
|     val chatRoom: CharacterChatRoom, | ||||
|     val chatRoom: ChatRoom, | ||||
| 
 | ||||
|     @ManyToOne(fetch = FetchType.LAZY) | ||||
|     @JoinColumn(name = "participant_id", nullable = false) | ||||
|     val participant: CharacterChatParticipant, | ||||
|     val participant: ChatParticipant, | ||||
| 
 | ||||
|     val isActive: Boolean = true | ||||
| ) : BaseEntity() | ||||
| @@ -13,10 +13,10 @@ import javax.persistence.ManyToOne | ||||
| import javax.persistence.OneToMany | ||||
| 
 | ||||
| @Entity | ||||
| class CharacterChatParticipant( | ||||
| class ChatParticipant( | ||||
|     @ManyToOne(fetch = FetchType.LAZY) | ||||
|     @JoinColumn(name = "chat_room_id", nullable = false) | ||||
|     val chatRoom: CharacterChatRoom, | ||||
|     val chatRoom: ChatRoom, | ||||
| 
 | ||||
|     @Enumerated(EnumType.STRING) | ||||
|     val participantType: ParticipantType, | ||||
| @@ -32,7 +32,7 @@ class CharacterChatParticipant( | ||||
|     var isActive: Boolean = true | ||||
| ) : BaseEntity() { | ||||
|     @OneToMany(mappedBy = "participant", cascade = [CascadeType.ALL], fetch = FetchType.LAZY) | ||||
|     val messages: MutableList<CharacterChatMessage> = mutableListOf() | ||||
|     val messages: MutableList<ChatMessage> = mutableListOf() | ||||
| } | ||||
| 
 | ||||
| enum class ParticipantType { | ||||
| @@ -7,14 +7,14 @@ import javax.persistence.FetchType | ||||
| import javax.persistence.OneToMany | ||||
| 
 | ||||
| @Entity | ||||
| class CharacterChatRoom( | ||||
| class ChatRoom( | ||||
|     val sessionId: String, | ||||
|     val title: String, | ||||
|     val isActive: Boolean = true | ||||
| ) : BaseEntity() { | ||||
|     @OneToMany(mappedBy = "chatRoom", cascade = [CascadeType.ALL], fetch = FetchType.LAZY) | ||||
|     val messages: MutableList<CharacterChatMessage> = mutableListOf() | ||||
|     val messages: MutableList<ChatMessage> = mutableListOf() | ||||
| 
 | ||||
|     @OneToMany(mappedBy = "chatRoom", cascade = [CascadeType.ALL], fetch = FetchType.LAZY) | ||||
|     val participants: MutableList<CharacterChatParticipant> = mutableListOf() | ||||
|     val participants: MutableList<ChatParticipant> = mutableListOf() | ||||
| } | ||||
| @@ -1,18 +1,18 @@ | ||||
| package kr.co.vividnext.sodalive.chat.room.repository | ||||
| 
 | ||||
| import kr.co.vividnext.sodalive.chat.room.CharacterChatMessage | ||||
| import kr.co.vividnext.sodalive.chat.room.CharacterChatRoom | ||||
| import kr.co.vividnext.sodalive.chat.room.ChatMessage | ||||
| import kr.co.vividnext.sodalive.chat.room.ChatRoom | ||||
| import org.springframework.data.jpa.repository.JpaRepository | ||||
| import org.springframework.stereotype.Repository | ||||
| 
 | ||||
| @Repository | ||||
| interface CharacterChatMessageRepository : JpaRepository<CharacterChatMessage, Long> { | ||||
|     fun findTopByChatRoomAndIsActiveTrueOrderByCreatedAtDesc(chatRoom: CharacterChatRoom): CharacterChatMessage? | ||||
| interface ChatMessageRepository : JpaRepository<ChatMessage, Long> { | ||||
|     fun findTopByChatRoomAndIsActiveTrueOrderByCreatedAtDesc(chatRoom: ChatRoom): ChatMessage? | ||||
| 
 | ||||
|     fun findTop20ByChatRoomAndIsActiveTrueOrderByIdDesc(chatRoom: CharacterChatRoom): List<CharacterChatMessage> | ||||
|     fun findTop20ByChatRoomAndIsActiveTrueOrderByIdDesc(chatRoom: ChatRoom): List<ChatMessage> | ||||
| 
 | ||||
|     fun findTop20ByChatRoomAndIdLessThanAndIsActiveTrueOrderByIdDesc( | ||||
|         chatRoom: CharacterChatRoom, | ||||
|         chatRoom: ChatRoom, | ||||
|         id: Long | ||||
|     ): List<CharacterChatMessage> | ||||
|     ): List<ChatMessage> | ||||
| } | ||||
| @@ -1,36 +1,36 @@ | ||||
| package kr.co.vividnext.sodalive.chat.room.repository | ||||
| 
 | ||||
| import kr.co.vividnext.sodalive.chat.room.CharacterChatParticipant | ||||
| import kr.co.vividnext.sodalive.chat.room.CharacterChatRoom | ||||
| import kr.co.vividnext.sodalive.chat.room.ChatParticipant | ||||
| import kr.co.vividnext.sodalive.chat.room.ChatRoom | ||||
| import kr.co.vividnext.sodalive.chat.room.ParticipantType | ||||
| import kr.co.vividnext.sodalive.member.Member | ||||
| import org.springframework.data.jpa.repository.JpaRepository | ||||
| import org.springframework.stereotype.Repository | ||||
| 
 | ||||
| @Repository | ||||
| interface CharacterChatParticipantRepository : JpaRepository<CharacterChatParticipant, Long> { | ||||
| interface ChatParticipantRepository : JpaRepository<ChatParticipant, Long> { | ||||
| 
 | ||||
|     /** | ||||
|      * 특정 채팅방에 참여 중인 멤버 참여자 찾기 | ||||
|      */ | ||||
|     fun findByChatRoomAndMemberAndIsActiveTrue( | ||||
|         chatRoom: CharacterChatRoom, | ||||
|         chatRoom: ChatRoom, | ||||
|         member: Member | ||||
|     ): CharacterChatParticipant? | ||||
|     ): ChatParticipant? | ||||
| 
 | ||||
|     /** | ||||
|      * 특정 채팅방에 특정 타입(CHARACTER/USER)으로 활성 상태인 참여자 찾기 | ||||
|      */ | ||||
|     fun findByChatRoomAndParticipantTypeAndIsActiveTrue( | ||||
|         chatRoom: CharacterChatRoom, | ||||
|         chatRoom: ChatRoom, | ||||
|         participantType: ParticipantType | ||||
|     ): CharacterChatParticipant? | ||||
|     ): ChatParticipant? | ||||
| 
 | ||||
|     /** | ||||
|      * 특정 채팅방의 활성 USER 참여자 수 | ||||
|      */ | ||||
|     fun countByChatRoomAndParticipantTypeAndIsActiveTrue( | ||||
|         chatRoom: CharacterChatRoom, | ||||
|         chatRoom: ChatRoom, | ||||
|         participantType: ParticipantType | ||||
|     ): Long | ||||
| } | ||||
| @@ -1,7 +1,7 @@ | ||||
| package kr.co.vividnext.sodalive.chat.room.repository | ||||
| 
 | ||||
| import kr.co.vividnext.sodalive.chat.character.ChatCharacter | ||||
| import kr.co.vividnext.sodalive.chat.room.CharacterChatRoom | ||||
| import kr.co.vividnext.sodalive.chat.room.ChatRoom | ||||
| import kr.co.vividnext.sodalive.chat.room.dto.ChatRoomListQueryDto | ||||
| import kr.co.vividnext.sodalive.member.Member | ||||
| import org.springframework.data.jpa.repository.JpaRepository | ||||
| @@ -10,14 +10,14 @@ import org.springframework.data.repository.query.Param | ||||
| import org.springframework.stereotype.Repository | ||||
| 
 | ||||
| @Repository | ||||
| interface CharacterChatRoomRepository : JpaRepository<CharacterChatRoom, Long> { | ||||
| interface ChatRoomRepository : JpaRepository<ChatRoom, Long> { | ||||
| 
 | ||||
|     /** | ||||
|      * 특정 멤버와 캐릭터가 참여 중인 활성화된 채팅방을 찾는 쿼리 | ||||
|      */ | ||||
|     @Query( | ||||
|         """ | ||||
|         SELECT DISTINCT r FROM CharacterChatRoom r | ||||
|         SELECT DISTINCT r FROM ChatRoom r | ||||
|         JOIN r.participants p1 | ||||
|         JOIN r.participants p2 | ||||
|         WHERE p1.member = :member AND p1.isActive = true | ||||
| @@ -28,7 +28,7 @@ interface CharacterChatRoomRepository : JpaRepository<CharacterChatRoom, Long> { | ||||
|     fun findActiveChatRoomByMemberAndCharacter( | ||||
|         @Param("member") member: Member, | ||||
|         @Param("character") character: ChatCharacter | ||||
|     ): CharacterChatRoom? | ||||
|     ): ChatRoom? | ||||
| 
 | ||||
|     /** | ||||
|      * 멤버가 참여 중인 채팅방을 최근 메시지 시간 순으로 페이징 조회 | ||||
| @@ -41,7 +41,7 @@ interface CharacterChatRoomRepository : JpaRepository<CharacterChatRoom, Long> { | ||||
|                 r.title, | ||||
|                 pc.character.imagePath | ||||
|             ) | ||||
|             FROM CharacterChatRoom r | ||||
|             FROM ChatRoom r | ||||
|             JOIN r.participants p | ||||
|             JOIN r.participants pc | ||||
|             LEFT JOIN r.messages m | ||||
| @@ -2,9 +2,9 @@ package kr.co.vividnext.sodalive.chat.room.service | ||||
|  | ||||
| import com.fasterxml.jackson.databind.ObjectMapper | ||||
| import kr.co.vividnext.sodalive.chat.character.service.ChatCharacterService | ||||
| import kr.co.vividnext.sodalive.chat.room.CharacterChatMessage | ||||
| import kr.co.vividnext.sodalive.chat.room.CharacterChatParticipant | ||||
| import kr.co.vividnext.sodalive.chat.room.CharacterChatRoom | ||||
| import kr.co.vividnext.sodalive.chat.room.ChatMessage | ||||
| import kr.co.vividnext.sodalive.chat.room.ChatParticipant | ||||
| import kr.co.vividnext.sodalive.chat.room.ChatRoom | ||||
| import kr.co.vividnext.sodalive.chat.room.ParticipantType | ||||
| import kr.co.vividnext.sodalive.chat.room.dto.ChatMessageItemDto | ||||
| import kr.co.vividnext.sodalive.chat.room.dto.ChatRoomListItemDto | ||||
| @@ -14,9 +14,9 @@ import kr.co.vividnext.sodalive.chat.room.dto.ExternalChatSendResponse | ||||
| import kr.co.vividnext.sodalive.chat.room.dto.ExternalChatSessionCreateResponse | ||||
| import kr.co.vividnext.sodalive.chat.room.dto.ExternalChatSessionGetResponse | ||||
| import kr.co.vividnext.sodalive.chat.room.dto.SendChatMessageResponse | ||||
| import kr.co.vividnext.sodalive.chat.room.repository.CharacterChatMessageRepository | ||||
| import kr.co.vividnext.sodalive.chat.room.repository.CharacterChatParticipantRepository | ||||
| import kr.co.vividnext.sodalive.chat.room.repository.CharacterChatRoomRepository | ||||
| import kr.co.vividnext.sodalive.chat.room.repository.ChatMessageRepository | ||||
| import kr.co.vividnext.sodalive.chat.room.repository.ChatParticipantRepository | ||||
| import kr.co.vividnext.sodalive.chat.room.repository.ChatRoomRepository | ||||
| import kr.co.vividnext.sodalive.common.SodaException | ||||
| import kr.co.vividnext.sodalive.member.Member | ||||
| import org.slf4j.LoggerFactory | ||||
| @@ -33,9 +33,9 @@ import java.util.UUID | ||||
|  | ||||
| @Service | ||||
| class ChatRoomService( | ||||
|     private val chatRoomRepository: CharacterChatRoomRepository, | ||||
|     private val participantRepository: CharacterChatParticipantRepository, | ||||
|     private val messageRepository: CharacterChatMessageRepository, | ||||
|     private val chatRoomRepository: ChatRoomRepository, | ||||
|     private val participantRepository: ChatParticipantRepository, | ||||
|     private val messageRepository: ChatMessageRepository, | ||||
|     private val characterService: ChatCharacterService, | ||||
|  | ||||
|     @Value("\${weraser.api-key}") | ||||
| @@ -78,7 +78,7 @@ class ChatRoomService( | ||||
|         val sessionId = callExternalApiForChatSession(userId, character.characterUUID) | ||||
|  | ||||
|         // 5. 채팅방 생성 | ||||
|         val chatRoom = CharacterChatRoom( | ||||
|         val chatRoom = ChatRoom( | ||||
|             sessionId = sessionId, | ||||
|             title = character.name, | ||||
|             isActive = true | ||||
| @@ -86,7 +86,7 @@ class ChatRoomService( | ||||
|         val savedChatRoom = chatRoomRepository.save(chatRoom) | ||||
|  | ||||
|         // 6. 채팅방 참여자 추가 (멤버) | ||||
|         val memberParticipant = CharacterChatParticipant( | ||||
|         val memberParticipant = ChatParticipant( | ||||
|             chatRoom = savedChatRoom, | ||||
|             participantType = ParticipantType.USER, | ||||
|             member = member, | ||||
| @@ -96,7 +96,7 @@ class ChatRoomService( | ||||
|         participantRepository.save(memberParticipant) | ||||
|  | ||||
|         // 7. 채팅방 참여자 추가 (캐릭터) | ||||
|         val characterParticipant = CharacterChatParticipant( | ||||
|         val characterParticipant = ChatParticipant( | ||||
|             chatRoom = savedChatRoom, | ||||
|             participantType = ParticipantType.CHARACTER, | ||||
|             member = null, | ||||
| @@ -186,7 +186,7 @@ class ChatRoomService( | ||||
|     fun listMyChatRooms(member: Member): List<ChatRoomListItemDto> { | ||||
|         val rooms: List<ChatRoomListQueryDto> = chatRoomRepository.findMemberRoomsOrderByLastMessageDesc(member) | ||||
|         return rooms.map { q -> | ||||
|             val room = CharacterChatRoom( | ||||
|             val room = ChatRoom( | ||||
|                 sessionId = "", | ||||
|                 title = q.title, | ||||
|                 isActive = true | ||||
| @@ -388,7 +388,7 @@ class ChatRoomService( | ||||
|         val characterReply = callExternalApiForChatSendWithRetry(userId, characterUUID, message, sessionId) | ||||
|  | ||||
|         // 6) 내 메시지 저장 | ||||
|         val myMsgEntity = CharacterChatMessage( | ||||
|         val myMsgEntity = ChatMessage( | ||||
|             message = message, | ||||
|             chatRoom = room, | ||||
|             participant = myParticipant, | ||||
| @@ -397,7 +397,7 @@ class ChatRoomService( | ||||
|         messageRepository.save(myMsgEntity) | ||||
|  | ||||
|         // 7) 캐릭터 메시지 저장 | ||||
|         val characterMsgEntity = CharacterChatMessage( | ||||
|         val characterMsgEntity = ChatMessage( | ||||
|             message = characterReply, | ||||
|             chatRoom = room, | ||||
|             participant = characterParticipant, | ||||
|   | ||||
		Reference in New Issue
	
	Block a user