diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/admin/chat/character/AdminChatCharacterController.kt b/src/main/kotlin/kr/co/vividnext/sodalive/admin/chat/character/AdminChatCharacterController.kt index dfa8c3a..21a7bda 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/admin/chat/character/AdminChatCharacterController.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/admin/chat/character/AdminChatCharacterController.kt @@ -13,8 +13,11 @@ import kr.co.vividnext.sodalive.chat.character.CharacterType 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.content.LanguageDetectEvent +import kr.co.vividnext.sodalive.content.LanguageDetectTargetType import kr.co.vividnext.sodalive.utils.generateFileName import org.springframework.beans.factory.annotation.Value +import org.springframework.context.ApplicationEventPublisher import org.springframework.http.HttpEntity import org.springframework.http.HttpHeaders import org.springframework.http.HttpMethod @@ -40,6 +43,7 @@ class AdminChatCharacterController( private val adminService: AdminChatCharacterService, private val s3Uploader: S3Uploader, private val originalWorkService: AdminOriginalWorkService, + private val applicationEventPublisher: ApplicationEventPublisher, @Value("\${weraser.api-key}") private val apiKey: String, @@ -165,6 +169,18 @@ class AdminChatCharacterController( originalWorkService.assignOneCharacter(request.originalWorkId, chatCharacter.id!!) } + // 5. 언어 코드가 지정되지 않은 경우, 파파고 언어 감지 API를 통해 비동기로 언어를 식별한다. + // 언어 감지에 사용할 내용은 chatCharacter.description 만 사용한다. + if (chatCharacter.languageCode.isNullOrBlank() && chatCharacter.description.isNotBlank()) { + applicationEventPublisher.publishEvent( + LanguageDetectEvent( + id = chatCharacter.id!!, + query = chatCharacter.description, + targetType = LanguageDetectTargetType.CHARACTER + ) + ) + } + ApiResponse.ok(null) } diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/chat/character/ChatCharacter.kt b/src/main/kotlin/kr/co/vividnext/sodalive/chat/character/ChatCharacter.kt index 981b6f1..5a62851 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/chat/character/ChatCharacter.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/chat/character/ChatCharacter.kt @@ -22,6 +22,8 @@ class ChatCharacter( // 캐릭터 한 줄 소개 var description: String, + var languageCode: String? = null, + // AI 시스템 프롬프트 @Column(columnDefinition = "TEXT", nullable = false) var systemPrompt: String, diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/content/LanguageDetectEvent.kt b/src/main/kotlin/kr/co/vividnext/sodalive/content/LanguageDetectEvent.kt index feb06c6..64a3bfb 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/content/LanguageDetectEvent.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/content/LanguageDetectEvent.kt @@ -1,6 +1,7 @@ package kr.co.vividnext.sodalive.content import kr.co.vividnext.sodalive.chat.character.comment.CharacterCommentRepository +import kr.co.vividnext.sodalive.chat.character.repository.ChatCharacterRepository import kr.co.vividnext.sodalive.content.comment.AudioContentCommentRepository import kr.co.vividnext.sodalive.explorer.profile.CreatorCheersRepository import org.slf4j.LoggerFactory @@ -23,6 +24,7 @@ import org.springframework.web.client.RestTemplate enum class LanguageDetectTargetType { CONTENT, COMMENT, + CHARACTER, CHARACTER_COMMENT, CREATOR_CHEERS } @@ -41,6 +43,7 @@ data class PapagoLanguageDetectResponse( class LanguageDetectListener( private val audioContentRepository: AudioContentRepository, private val audioContentCommentRepository: AudioContentCommentRepository, + private val chatCharacterRepository: ChatCharacterRepository, private val characterCommentRepository: CharacterCommentRepository, private val creatorCheersRepository: CreatorCheersRepository, @@ -69,11 +72,43 @@ class LanguageDetectListener( when (event.targetType) { LanguageDetectTargetType.CONTENT -> handleContentLanguageDetect(event) LanguageDetectTargetType.COMMENT -> handleCommentLanguageDetect(event) + LanguageDetectTargetType.CHARACTER -> handleCharacterLanguageDetect(event) LanguageDetectTargetType.CHARACTER_COMMENT -> handleCharacterCommentLanguageDetect(event) LanguageDetectTargetType.CREATOR_CHEERS -> handleCreatorCheersLanguageDetect(event) } } + private fun handleCharacterLanguageDetect(event: LanguageDetectEvent) { + val characterId = event.id + + val character = chatCharacterRepository.findById(characterId).orElse(null) + if (character == null) { + log.warn("[PapagoLanguageDetect] ChatCharacter not found. characterId={}", characterId) + return + } + + // 이미 언어 코드가 설정된 경우 호출하지 않음 + if (!character.languageCode.isNullOrBlank()) { + log.debug( + "[PapagoLanguageDetect] languageCode already set. Skip language detection. characterId={}, languageCode={}", + characterId, + character.languageCode + ) + return + } + + val langCode = requestPapagoLanguageCode(event.query, characterId) ?: return + + character.languageCode = langCode + chatCharacterRepository.save(character) + + log.info( + "[PapagoLanguageDetect] languageCode updated from Papago. characterId={}, langCode={}", + characterId, + langCode + ) + } + private fun handleContentLanguageDetect(event: LanguageDetectEvent) { val contentId = event.id