캐릭터 챗봇 #338
| @@ -11,6 +11,7 @@ import kr.co.vividnext.sodalive.chat.character.dto.OtherCharacter | |||||||
| import kr.co.vividnext.sodalive.chat.character.dto.RecentCharacter | import kr.co.vividnext.sodalive.chat.character.dto.RecentCharacter | ||||||
| import kr.co.vividnext.sodalive.chat.character.service.ChatCharacterBannerService | import kr.co.vividnext.sodalive.chat.character.service.ChatCharacterBannerService | ||||||
| import kr.co.vividnext.sodalive.chat.character.service.ChatCharacterService | import kr.co.vividnext.sodalive.chat.character.service.ChatCharacterService | ||||||
|  | import kr.co.vividnext.sodalive.chat.room.service.ChatRoomService | ||||||
| import kr.co.vividnext.sodalive.common.ApiResponse | import kr.co.vividnext.sodalive.common.ApiResponse | ||||||
| import kr.co.vividnext.sodalive.common.SodaException | import kr.co.vividnext.sodalive.common.SodaException | ||||||
| import kr.co.vividnext.sodalive.member.Member | import kr.co.vividnext.sodalive.member.Member | ||||||
| @@ -27,6 +28,7 @@ import org.springframework.web.bind.annotation.RestController | |||||||
| class ChatCharacterController( | class ChatCharacterController( | ||||||
|     private val service: ChatCharacterService, |     private val service: ChatCharacterService, | ||||||
|     private val bannerService: ChatCharacterBannerService, |     private val bannerService: ChatCharacterBannerService, | ||||||
|  |     private val chatRoomService: ChatRoomService, | ||||||
|  |  | ||||||
|     @Value("\${cloud.aws.cloud-front.host}") |     @Value("\${cloud.aws.cloud-front.host}") | ||||||
|     private val imageHost: String |     private val imageHost: String | ||||||
| @@ -45,15 +47,19 @@ class ChatCharacterController( | |||||||
|                 ) |                 ) | ||||||
|             } |             } | ||||||
|  |  | ||||||
|         // 최근 대화한 캐릭터 조회 (회원별 최근 순으로 최대 10개) |         // 최근 대화한 캐릭터(채팅방) 조회 (회원별 최근 순으로 최대 10개) | ||||||
|         val recentCharacters = service.getRecentCharacters(member, 10) |         val recentCharacters = if (member == null || member.auth == null) { | ||||||
|             .map { |             emptyList() | ||||||
|                 RecentCharacter( |         } else { | ||||||
|                     characterId = it.id!!, |             chatRoomService.listMyChatRooms(member, 0, 10) | ||||||
|                     name = it.name, |                 .map { room -> | ||||||
|                     imageUrl = "$imageHost/${it.imagePath ?: "profile/default-profile.png"}" |                     RecentCharacter( | ||||||
|                 ) |                         roomId = room.chatRoomId, | ||||||
|             } |                         name = room.title, | ||||||
|  |                         imageUrl = room.imageUrl | ||||||
|  |                     ) | ||||||
|  |                 } | ||||||
|  |         } | ||||||
|  |  | ||||||
|         // 인기 캐릭터 조회 (현재는 빈 리스트) |         // 인기 캐릭터 조회 (현재는 빈 리스트) | ||||||
|         val popularCharacters = service.getPopularCharacters() |         val popularCharacters = service.getPopularCharacters() | ||||||
|   | |||||||
| @@ -22,7 +22,7 @@ data class Character( | |||||||
| ) | ) | ||||||
|  |  | ||||||
| data class RecentCharacter( | data class RecentCharacter( | ||||||
|     val characterId: Long, |     val roomId: Long, | ||||||
|     val name: String, |     val name: String, | ||||||
|     val imageUrl: String |     val imageUrl: String | ||||||
| ) | ) | ||||||
|   | |||||||
| @@ -1,7 +1,6 @@ | |||||||
| package kr.co.vividnext.sodalive.chat.character.repository | package kr.co.vividnext.sodalive.chat.character.repository | ||||||
|  |  | ||||||
| import kr.co.vividnext.sodalive.chat.character.ChatCharacter | import kr.co.vividnext.sodalive.chat.character.ChatCharacter | ||||||
| import kr.co.vividnext.sodalive.member.Member |  | ||||||
| import org.springframework.data.domain.Page | import org.springframework.data.domain.Page | ||||||
| import org.springframework.data.domain.Pageable | import org.springframework.data.domain.Pageable | ||||||
| import org.springframework.data.jpa.repository.JpaRepository | import org.springframework.data.jpa.repository.JpaRepository | ||||||
| @@ -42,31 +41,6 @@ interface ChatCharacterRepository : JpaRepository<ChatCharacter, Long> { | |||||||
|         pageable: Pageable |         pageable: Pageable | ||||||
|     ): Page<ChatCharacter> |     ): Page<ChatCharacter> | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * 멤버가 최근에 대화한 캐릭터 목록을 반환 (최신 메시지 시간 기준 내림차순) |  | ||||||
|      */ |  | ||||||
|     @Query( |  | ||||||
|         value = """ |  | ||||||
|             SELECT c FROM ChatRoom r |  | ||||||
|             JOIN r.participants pu |  | ||||||
|             JOIN r.participants pc |  | ||||||
|             JOIN pc.character c |  | ||||||
|             LEFT JOIN r.messages m |  | ||||||
|             WHERE pu.member = :member |  | ||||||
|               AND pu.participantType = kr.co.vividnext.sodalive.chat.room.ParticipantType.USER |  | ||||||
|               AND pu.isActive = true |  | ||||||
|               AND pc.participantType = kr.co.vividnext.sodalive.chat.room.ParticipantType.CHARACTER |  | ||||||
|               AND pc.isActive = true |  | ||||||
|               AND r.isActive = true |  | ||||||
|             GROUP BY c.id |  | ||||||
|             ORDER BY MAX(COALESCE(m.createdAt, r.createdAt)) DESC |  | ||||||
|         """ |  | ||||||
|     ) |  | ||||||
|     fun findRecentCharactersByMember( |  | ||||||
|         @Param("member") member: Member, |  | ||||||
|         pageable: Pageable |  | ||||||
|     ): List<ChatCharacter> |  | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * 특정 캐릭터와 태그를 공유하는 다른 캐릭터를 무작위로 조회 (현재 캐릭터 제외) |      * 특정 캐릭터와 태그를 공유하는 다른 캐릭터를 무작위로 조회 (현재 캐릭터 제외) | ||||||
|      */ |      */ | ||||||
|   | |||||||
| @@ -13,7 +13,6 @@ import kr.co.vividnext.sodalive.chat.character.repository.ChatCharacterHobbyRepo | |||||||
| import kr.co.vividnext.sodalive.chat.character.repository.ChatCharacterRepository | import kr.co.vividnext.sodalive.chat.character.repository.ChatCharacterRepository | ||||||
| import kr.co.vividnext.sodalive.chat.character.repository.ChatCharacterTagRepository | import kr.co.vividnext.sodalive.chat.character.repository.ChatCharacterTagRepository | ||||||
| import kr.co.vividnext.sodalive.chat.character.repository.ChatCharacterValueRepository | import kr.co.vividnext.sodalive.chat.character.repository.ChatCharacterValueRepository | ||||||
| import kr.co.vividnext.sodalive.member.Member |  | ||||||
| import org.springframework.data.domain.PageRequest | import org.springframework.data.domain.PageRequest | ||||||
| import org.springframework.stereotype.Service | import org.springframework.stereotype.Service | ||||||
| import org.springframework.transaction.annotation.Transactional | import org.springframework.transaction.annotation.Transactional | ||||||
| @@ -26,16 +25,6 @@ class ChatCharacterService( | |||||||
|     private val hobbyRepository: ChatCharacterHobbyRepository, |     private val hobbyRepository: ChatCharacterHobbyRepository, | ||||||
|     private val goalRepository: ChatCharacterGoalRepository |     private val goalRepository: ChatCharacterGoalRepository | ||||||
| ) { | ) { | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * 최근에 대화한 캐릭터 목록 조회 |  | ||||||
|      */ |  | ||||||
|     @Transactional(readOnly = true) |  | ||||||
|     fun getRecentCharacters(member: Member?, limit: Int = 10): List<ChatCharacter> { |  | ||||||
|         if (member == null) return emptyList() |  | ||||||
|         return chatCharacterRepository.findRecentCharactersByMember(member, PageRequest.of(0, limit)) |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * 일주일간 대화가 가장 많은 인기 캐릭터 목록 조회 |      * 일주일간 대화가 가장 많은 인기 캐릭터 목록 조회 | ||||||
|      * 현재는 채팅방 구현 전이므로 빈 리스트 반환 |      * 현재는 채팅방 구현 전이므로 빈 리스트 반환 | ||||||
|   | |||||||
| @@ -184,9 +184,8 @@ class ChatRoomService( | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Transactional(readOnly = true) |     @Transactional(readOnly = true) | ||||||
|     fun listMyChatRooms(member: Member, page: Int): List<ChatRoomListItemDto> { |     fun listMyChatRooms(member: Member, page: Int, size: Int = 20): List<ChatRoomListItemDto> { | ||||||
|         // 기본 페이지당 20개 고정 |         val pageable = PageRequest.of(if (page < 0) 0 else page, size) | ||||||
|         val pageable = PageRequest.of(if (page < 0) 0 else page, 20) |  | ||||||
|         val rooms: List<ChatRoomListQueryDto> = chatRoomRepository.findMemberRoomsOrderByLastMessageDesc( |         val rooms: List<ChatRoomListQueryDto> = chatRoomRepository.findMemberRoomsOrderByLastMessageDesc( | ||||||
|             member, |             member, | ||||||
|             pageable |             pageable | ||||||
| @@ -200,7 +199,7 @@ class ChatRoomService( | |||||||
|  |  | ||||||
|             val latest = messageRepository.findTopByChatRoomAndIsActiveTrueOrderByCreatedAtDesc(room) |             val latest = messageRepository.findTopByChatRoomAndIsActiveTrueOrderByCreatedAtDesc(room) | ||||||
|             val preview = latest?.message?.let { msg -> |             val preview = latest?.message?.let { msg -> | ||||||
|                 if (msg.length <= 25) msg else msg.substring(0, 25) + "..." |                 if (msg.length <= 25) msg else msg.take(25) + "..." | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             ChatRoomListItemDto( |             ChatRoomListItemDto( | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user