diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/chat/character/controller/ChatCharacterController.kt b/src/main/kotlin/kr/co/vividnext/sodalive/chat/character/controller/ChatCharacterController.kt index a0ffc0f..b3653fe 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/chat/character/controller/ChatCharacterController.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/chat/character/controller/ChatCharacterController.kt @@ -7,6 +7,7 @@ import kr.co.vividnext.sodalive.chat.character.dto.CharacterDetailResponse import kr.co.vividnext.sodalive.chat.character.dto.CharacterMainResponse import kr.co.vividnext.sodalive.chat.character.dto.CharacterPersonalityResponse import kr.co.vividnext.sodalive.chat.character.dto.CurationSection +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.service.ChatCharacterBannerService import kr.co.vividnext.sodalive.chat.character.service.ChatCharacterService @@ -127,6 +128,20 @@ class ChatCharacterController( ) } + // 다른 캐릭터 조회 (태그 기반, 랜덤 10개, 현재 캐릭터 제외) + val others = service.getOtherCharactersBySharedTags(characterId, 10) + .map { other -> + val otherTags = other.tagMappings + .map { it.tag.tag } + .joinToString(" ") { if (it.startsWith("#")) it else "#$it" } + OtherCharacter( + characterId = other.id!!, + name = other.name, + imageUrl = "$imageHost/${other.imagePath ?: "profile/default-profile.png"}", + tags = otherTags + ) + } + // 응답 생성 ApiResponse.ok( CharacterDetailResponse( @@ -137,7 +152,11 @@ class ChatCharacterController( imageUrl = "$imageHost/${character.imagePath ?: "profile/default-profile.png"}", personalities = personality, backgrounds = background, - tags = tags + tags = tags, + originalTitle = character.originalTitle, + originalLink = character.originalLink, + characterType = character.characterType, + others = others ) ) } diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/chat/character/dto/CharacterDetailResponse.kt b/src/main/kotlin/kr/co/vividnext/sodalive/chat/character/dto/CharacterDetailResponse.kt index f8ba56f..cb3f90f 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/chat/character/dto/CharacterDetailResponse.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/chat/character/dto/CharacterDetailResponse.kt @@ -1,5 +1,7 @@ package kr.co.vividnext.sodalive.chat.character.dto +import kr.co.vividnext.sodalive.chat.character.CharacterType + data class CharacterDetailResponse( val characterId: Long, val name: String, @@ -8,6 +10,17 @@ data class CharacterDetailResponse( val imageUrl: String, val personalities: CharacterPersonalityResponse?, val backgrounds: CharacterBackgroundResponse?, + val tags: String, + val originalTitle: String?, + val originalLink: String?, + val characterType: CharacterType, + val others: List +) + +data class OtherCharacter( + val characterId: Long, + val name: String, + val imageUrl: String, val tags: String ) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/chat/character/repository/ChatCharacterRepository.kt b/src/main/kotlin/kr/co/vividnext/sodalive/chat/character/repository/ChatCharacterRepository.kt index ee760aa..bcc19fb 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/chat/character/repository/ChatCharacterRepository.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/chat/character/repository/ChatCharacterRepository.kt @@ -66,4 +66,25 @@ interface ChatCharacterRepository : JpaRepository { @Param("member") member: Member, pageable: Pageable ): List + + /** + * 특정 캐릭터와 태그를 공유하는 다른 캐릭터를 무작위로 조회 (현재 캐릭터 제외) + */ + @Query( + """ + SELECT DISTINCT c FROM ChatCharacter c + JOIN c.tagMappings tm + JOIN tm.tag t + WHERE c.isActive = true + AND c.id <> :characterId + AND t.id IN ( + SELECT t2.id FROM ChatCharacterTagMapping tm2 JOIN tm2.tag t2 WHERE tm2.chatCharacter.id = :characterId + ) + ORDER BY function('RAND') + """ + ) + fun findRandomBySharedTags( + @Param("characterId") characterId: Long, + pageable: Pageable + ): List } diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/chat/character/service/ChatCharacterService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/chat/character/service/ChatCharacterService.kt index 4732670..73ac088 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/chat/character/service/ChatCharacterService.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/chat/character/service/ChatCharacterService.kt @@ -53,6 +53,20 @@ class ChatCharacterService( return chatCharacterRepository.findByIsActiveTrueOrderByCreatedAtDesc(PageRequest.of(0, limit)) } + /** + * 특정 캐릭터와 태그를 공유하는 다른 캐릭터를 무작위로 조회 (현재 캐릭터 제외) + */ + @Transactional(readOnly = true) + fun getOtherCharactersBySharedTags(characterId: Long, limit: Int = 10): List { + val others = chatCharacterRepository.findRandomBySharedTags( + characterId, + PageRequest.of(0, limit) + ) + // 태그 초기화 (지연 로딩 문제 방지) + others.forEach { it.tagMappings.size } + return others + } + /** * 태그를 찾거나 생성하여 캐릭터에 연결 */