캐릭터 챗봇 #338
| @@ -1,18 +1,24 @@ | ||||
| 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.CharacterBackgroundResponse | ||||
| 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.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.RecentCharacter | ||||
| import kr.co.vividnext.sodalive.chat.character.service.ChatCharacterBannerService | ||||
| import kr.co.vividnext.sodalive.chat.character.service.ChatCharacterService | ||||
| import kr.co.vividnext.sodalive.common.ApiResponse | ||||
| import kr.co.vividnext.sodalive.common.SodaException | ||||
| import kr.co.vividnext.sodalive.member.Member | ||||
| import org.springframework.beans.factory.annotation.Value | ||||
| import org.springframework.data.domain.PageRequest | ||||
| import org.springframework.security.core.annotation.AuthenticationPrincipal | ||||
| 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.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) | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 캐릭터 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