캐릭터 챗봇 #338
| @@ -21,6 +21,7 @@ import org.springframework.retry.annotation.Backoff | ||||
| import org.springframework.retry.annotation.Retryable | ||||
| import org.springframework.security.access.prepost.PreAuthorize | ||||
| import org.springframework.web.bind.annotation.GetMapping | ||||
| import org.springframework.web.bind.annotation.PathVariable | ||||
| import org.springframework.web.bind.annotation.PostMapping | ||||
| import org.springframework.web.bind.annotation.PutMapping | ||||
| import org.springframework.web.bind.annotation.RequestMapping | ||||
| @@ -68,6 +69,21 @@ class AdminChatCharacterController( | ||||
|         ApiResponse.ok(response) | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 캐릭터 상세 정보 조회 API | ||||
|      * | ||||
|      * @param characterId 캐릭터 ID | ||||
|      * @return 캐릭터 상세 정보 | ||||
|      */ | ||||
|     @GetMapping("/{characterId}") | ||||
|     fun getCharacterDetail( | ||||
|         @PathVariable characterId: Long | ||||
|     ) = run { | ||||
|         val response = adminService.getChatCharacterDetail(characterId, imageHost) | ||||
|  | ||||
|         ApiResponse.ok(response) | ||||
|     } | ||||
|  | ||||
|     @PostMapping("/register") | ||||
|     @Retryable( | ||||
|         value = [Exception::class], | ||||
|   | ||||
| @@ -0,0 +1,83 @@ | ||||
| package kr.co.vividnext.sodalive.admin.chat.character.dto | ||||
|  | ||||
| import kr.co.vividnext.sodalive.chat.character.ChatCharacter | ||||
|  | ||||
| data class ChatCharacterDetailResponse( | ||||
|     val id: Long, | ||||
|     val characterUUID: String, | ||||
|     val name: String, | ||||
|     val imageUrl: String?, | ||||
|     val description: String, | ||||
|     val systemPrompt: String, | ||||
|     val age: Int?, | ||||
|     val gender: String?, | ||||
|     val mbti: String?, | ||||
|     val speechPattern: String?, | ||||
|     val speechStyle: String?, | ||||
|     val appearance: String?, | ||||
|     val isActive: Boolean, | ||||
|     val tags: List<String>, | ||||
|     val hobbies: List<String>, | ||||
|     val values: List<String>, | ||||
|     val goals: List<String>, | ||||
|     val relationships: List<String>, | ||||
|     val personalities: List<PersonalityResponse>, | ||||
|     val backgrounds: List<BackgroundResponse>, | ||||
|     val memories: List<MemoryResponse> | ||||
| ) { | ||||
|     companion object { | ||||
|         fun from(chatCharacter: ChatCharacter, imageHost: String = ""): ChatCharacterDetailResponse { | ||||
|             val fullImagePath = if (chatCharacter.imagePath != null && imageHost.isNotEmpty()) { | ||||
|                 "$imageHost/${chatCharacter.imagePath}" | ||||
|             } else { | ||||
|                 chatCharacter.imagePath | ||||
|             } | ||||
|  | ||||
|             return ChatCharacterDetailResponse( | ||||
|                 id = chatCharacter.id!!, | ||||
|                 characterUUID = chatCharacter.characterUUID, | ||||
|                 name = chatCharacter.name, | ||||
|                 imageUrl = fullImagePath, | ||||
|                 description = chatCharacter.description, | ||||
|                 systemPrompt = chatCharacter.systemPrompt, | ||||
|                 age = chatCharacter.age, | ||||
|                 gender = chatCharacter.gender, | ||||
|                 mbti = chatCharacter.mbti, | ||||
|                 speechPattern = chatCharacter.speechPattern, | ||||
|                 speechStyle = chatCharacter.speechStyle, | ||||
|                 appearance = chatCharacter.appearance, | ||||
|                 isActive = chatCharacter.isActive, | ||||
|                 tags = chatCharacter.tagMappings.map { it.tag.tag }, | ||||
|                 hobbies = chatCharacter.hobbyMappings.map { it.hobby.hobby }, | ||||
|                 values = chatCharacter.valueMappings.map { it.value.value }, | ||||
|                 goals = chatCharacter.goalMappings.map { it.goal.goal }, | ||||
|                 relationships = chatCharacter.relationships.map { it.relationShip }, | ||||
|                 personalities = chatCharacter.personalities.map { | ||||
|                     PersonalityResponse(it.trait, it.description) | ||||
|                 }, | ||||
|                 backgrounds = chatCharacter.backgrounds.map { | ||||
|                     BackgroundResponse(it.topic, it.description) | ||||
|                 }, | ||||
|                 memories = chatCharacter.memories.map { | ||||
|                     MemoryResponse(it.title, it.content, it.emotion) | ||||
|                 } | ||||
|             ) | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| data class PersonalityResponse( | ||||
|     val trait: String, | ||||
|     val description: String | ||||
| ) | ||||
|  | ||||
| data class BackgroundResponse( | ||||
|     val topic: String, | ||||
|     val description: String | ||||
| ) | ||||
|  | ||||
| data class MemoryResponse( | ||||
|     val title: String, | ||||
|     val content: String, | ||||
|     val emotion: String | ||||
| ) | ||||
| @@ -1,8 +1,10 @@ | ||||
| package kr.co.vividnext.sodalive.admin.chat.character.service | ||||
|  | ||||
| import kr.co.vividnext.sodalive.admin.chat.character.dto.ChatCharacterDetailResponse | ||||
| import kr.co.vividnext.sodalive.admin.chat.character.dto.ChatCharacterListPageResponse | ||||
| import kr.co.vividnext.sodalive.admin.chat.character.dto.ChatCharacterListResponse | ||||
| import kr.co.vividnext.sodalive.chat.character.repository.ChatCharacterRepository | ||||
| import kr.co.vividnext.sodalive.common.SodaException | ||||
| import org.springframework.data.domain.PageRequest | ||||
| import org.springframework.data.domain.Pageable | ||||
| import org.springframework.data.domain.Sort | ||||
| @@ -43,4 +45,20 @@ class AdminChatCharacterService( | ||||
|     fun createDefaultPageRequest(page: Int = 0, size: Int = 20): PageRequest { | ||||
|         return PageRequest.of(page, size, Sort.by(Sort.Direction.DESC, "createdAt")) | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 캐릭터 상세 정보 조회 | ||||
|      * | ||||
|      * @param characterId 캐릭터 ID | ||||
|      * @param imageHost 이미지 호스트 URL | ||||
|      * @return 캐릭터 상세 정보 | ||||
|      * @throws SodaException 캐릭터를 찾을 수 없는 경우 | ||||
|      */ | ||||
|     @Transactional(readOnly = true) | ||||
|     fun getChatCharacterDetail(characterId: Long, imageHost: String = ""): ChatCharacterDetailResponse { | ||||
|         val chatCharacter = chatCharacterRepository.findById(characterId) | ||||
|             .orElseThrow { SodaException("해당 ID의 캐릭터를 찾을 수 없습니다: $characterId") } | ||||
|  | ||||
|         return ChatCharacterDetailResponse.from(chatCharacter, imageHost) | ||||
|     } | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user