캐릭터 챗봇 #338
| @@ -1,18 +1,24 @@ | |||||||
| package kr.co.vividnext.sodalive.chat.character.controller | package kr.co.vividnext.sodalive.chat.character.controller | ||||||
|  |  | ||||||
| import kr.co.vividnext.sodalive.chat.character.dto.Character | import kr.co.vividnext.sodalive.chat.character.dto.Character | ||||||
|  | import kr.co.vividnext.sodalive.chat.character.dto.CharacterBackgroundResponse | ||||||
| import kr.co.vividnext.sodalive.chat.character.dto.CharacterBannerResponse | import kr.co.vividnext.sodalive.chat.character.dto.CharacterBannerResponse | ||||||
|  | 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.CharacterMainResponse | ||||||
|  | import kr.co.vividnext.sodalive.chat.character.dto.CharacterMemoryResponse | ||||||
|  | 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.CurationSection | ||||||
| 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.common.ApiResponse | import kr.co.vividnext.sodalive.common.ApiResponse | ||||||
|  | import kr.co.vividnext.sodalive.common.SodaException | ||||||
| import kr.co.vividnext.sodalive.member.Member | import kr.co.vividnext.sodalive.member.Member | ||||||
| import org.springframework.beans.factory.annotation.Value | import org.springframework.beans.factory.annotation.Value | ||||||
| import org.springframework.data.domain.PageRequest | import org.springframework.data.domain.PageRequest | ||||||
| import org.springframework.security.core.annotation.AuthenticationPrincipal | import org.springframework.security.core.annotation.AuthenticationPrincipal | ||||||
| import org.springframework.web.bind.annotation.GetMapping | import org.springframework.web.bind.annotation.GetMapping | ||||||
|  | import org.springframework.web.bind.annotation.PathVariable | ||||||
| import org.springframework.web.bind.annotation.RequestMapping | import org.springframework.web.bind.annotation.RequestMapping | ||||||
| import org.springframework.web.bind.annotation.RestController | import org.springframework.web.bind.annotation.RestController | ||||||
|  |  | ||||||
| @@ -85,4 +91,76 @@ class ChatCharacterController( | |||||||
|             ) |             ) | ||||||
|         ) |         ) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 캐릭터 상세 정보 조회 API | ||||||
|  |      * 캐릭터 ID를 받아 해당 캐릭터의 상세 정보를 반환합니다. | ||||||
|  |      */ | ||||||
|  |     @GetMapping("/{characterId}") | ||||||
|  |     fun getCharacterDetail( | ||||||
|  |         @PathVariable characterId: Long, | ||||||
|  |         @AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member? | ||||||
|  |     ) = run { | ||||||
|  |         if (member == null) throw SodaException("로그인 정보를 확인해주세요.") | ||||||
|  |         if (member.auth == null) throw SodaException("본인인증을 하셔야 합니다.") | ||||||
|  |  | ||||||
|  |         // 캐릭터 상세 정보 조회 | ||||||
|  |         val character = service.getCharacterDetail(characterId) | ||||||
|  |             ?: throw SodaException("캐릭터를 찾을 수 없습니다.") | ||||||
|  |  | ||||||
|  |         // 태그, 가치관, 취미, 목표 추출 | ||||||
|  |         val tags = character.tagMappings.map { it.tag.tag } | ||||||
|  |         val values = character.valueMappings.map { it.value.value } | ||||||
|  |         val hobbies = character.hobbyMappings.map { it.hobby.hobby } | ||||||
|  |         val goals = character.goalMappings.map { it.goal.goal } | ||||||
|  |  | ||||||
|  |         // 메모리, 성격, 배경, 관계 변환 | ||||||
|  |         val memories = character.memories.map { | ||||||
|  |             CharacterMemoryResponse( | ||||||
|  |                 title = it.title, | ||||||
|  |                 content = it.content, | ||||||
|  |                 emotion = it.emotion | ||||||
|  |             ) | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         val personalities = character.personalities.map { | ||||||
|  |             CharacterPersonalityResponse( | ||||||
|  |                 trait = it.trait, | ||||||
|  |                 description = it.description | ||||||
|  |             ) | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         val backgrounds = character.backgrounds.map { | ||||||
|  |             CharacterBackgroundResponse( | ||||||
|  |                 topic = it.topic, | ||||||
|  |                 description = it.description | ||||||
|  |             ) | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         val relationships = character.relationships.map { it.relationShip } | ||||||
|  |  | ||||||
|  |         // 응답 생성 | ||||||
|  |         ApiResponse.ok( | ||||||
|  |             CharacterDetailResponse( | ||||||
|  |                 characterId = character.id!!, | ||||||
|  |                 name = character.name, | ||||||
|  |                 description = character.description, | ||||||
|  |                 age = character.age, | ||||||
|  |                 gender = character.gender, | ||||||
|  |                 mbti = character.mbti, | ||||||
|  |                 speechPattern = character.speechPattern, | ||||||
|  |                 speechStyle = character.speechStyle, | ||||||
|  |                 appearance = character.appearance, | ||||||
|  |                 imageUrl = "$imageHost/${character.imagePath ?: "profile/default-profile.png"}", | ||||||
|  |                 memories = memories, | ||||||
|  |                 personalities = personalities, | ||||||
|  |                 backgrounds = backgrounds, | ||||||
|  |                 relationships = relationships, | ||||||
|  |                 tags = tags, | ||||||
|  |                 values = values, | ||||||
|  |                 hobbies = hobbies, | ||||||
|  |                 goals = goals | ||||||
|  |             ) | ||||||
|  |         ) | ||||||
|  |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -0,0 +1,38 @@ | |||||||
|  | package kr.co.vividnext.sodalive.chat.character.dto | ||||||
|  |  | ||||||
|  | data class CharacterDetailResponse( | ||||||
|  |     val characterId: Long, | ||||||
|  |     val name: String, | ||||||
|  |     val description: String, | ||||||
|  |     val age: Int?, | ||||||
|  |     val gender: String?, | ||||||
|  |     val mbti: String?, | ||||||
|  |     val speechPattern: String?, | ||||||
|  |     val speechStyle: String?, | ||||||
|  |     val appearance: String?, | ||||||
|  |     val imageUrl: String, | ||||||
|  |     val memories: List<CharacterMemoryResponse> = emptyList(), | ||||||
|  |     val personalities: List<CharacterPersonalityResponse> = emptyList(), | ||||||
|  |     val backgrounds: List<CharacterBackgroundResponse> = emptyList(), | ||||||
|  |     val relationships: List<String> = emptyList(), | ||||||
|  |     val tags: List<String> = emptyList(), | ||||||
|  |     val values: List<String> = emptyList(), | ||||||
|  |     val hobbies: List<String> = emptyList(), | ||||||
|  |     val goals: List<String> = emptyList() | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | data class CharacterMemoryResponse( | ||||||
|  |     val title: String, | ||||||
|  |     val content: String, | ||||||
|  |     val emotion: String | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | data class CharacterPersonalityResponse( | ||||||
|  |     val trait: String, | ||||||
|  |     val description: String | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | data class CharacterBackgroundResponse( | ||||||
|  |     val topic: String, | ||||||
|  |     val description: String | ||||||
|  | ) | ||||||
| @@ -172,6 +172,27 @@ class ChatCharacterService( | |||||||
|         return chatCharacterRepository.findById(id).orElse(null) |         return chatCharacterRepository.findById(id).orElse(null) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 캐릭터 ID로 상세 정보를 조회합니다. | ||||||
|  |      * 태그, 가치관, 취미, 목표 등의 관계 정보도 함께 조회합니다. | ||||||
|  |      */ | ||||||
|  |     @Transactional(readOnly = true) | ||||||
|  |     fun getCharacterDetail(id: Long): ChatCharacter? { | ||||||
|  |         val character = findById(id) ?: return null | ||||||
|  |  | ||||||
|  |         // 지연 로딩된 관계 데이터 초기화 | ||||||
|  |         character.tagMappings.size | ||||||
|  |         character.valueMappings.size | ||||||
|  |         character.hobbyMappings.size | ||||||
|  |         character.goalMappings.size | ||||||
|  |         character.memories.size | ||||||
|  |         character.personalities.size | ||||||
|  |         character.backgrounds.size | ||||||
|  |         character.relationships.size | ||||||
|  |  | ||||||
|  |         return character | ||||||
|  |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * 캐릭터 생성 및 관련 엔티티 연결 |      * 캐릭터 생성 및 관련 엔티티 연결 | ||||||
|      */ |      */ | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user