캐릭터 챗봇 #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(
|
||||||
|
|
Loading…
Reference in New Issue