Add translation support for audio content detail

This commit is contained in:
2025-12-11 22:00:30 +09:00
parent 1748b26318
commit 608898eb0c
5 changed files with 170 additions and 4 deletions

View File

@@ -21,10 +21,14 @@ import kr.co.vividnext.sodalive.content.order.OrderType
import kr.co.vividnext.sodalive.content.pin.PinContent
import kr.co.vividnext.sodalive.content.pin.PinContentRepository
import kr.co.vividnext.sodalive.content.theme.AudioContentThemeQueryRepository
import kr.co.vividnext.sodalive.content.translation.ContentTranslationRepository
import kr.co.vividnext.sodalive.content.translation.TranslatedContent
import kr.co.vividnext.sodalive.explorer.ExplorerQueryRepository
import kr.co.vividnext.sodalive.extensions.convertLocalDateTime
import kr.co.vividnext.sodalive.fcm.FcmEvent
import kr.co.vividnext.sodalive.fcm.FcmEventType
import kr.co.vividnext.sodalive.i18n.translation.PapagoTranslationService
import kr.co.vividnext.sodalive.i18n.translation.TranslateRequest
import kr.co.vividnext.sodalive.member.Member
import kr.co.vividnext.sodalive.member.block.BlockMemberRepository
import kr.co.vividnext.sodalive.utils.generateFileName
@@ -56,6 +60,9 @@ class AudioContentService(
private val audioContentLikeRepository: AudioContentLikeRepository,
private val pinContentRepository: PinContentRepository,
private val translationService: PapagoTranslationService,
private val contentTranslationRepository: ContentTranslationRepository,
private val s3Uploader: S3Uploader,
private val objectMapper: ObjectMapper,
private val audioContentCloudFront: AudioContentCloudFront,
@@ -500,7 +507,8 @@ class AudioContentService(
id: Long,
member: Member,
isAdultContentVisible: Boolean,
timezone: String
timezone: String,
languageCode: String
): GetAudioContentDetailResponse {
val isAdult = member.auth != null && isAdultContentVisible
@@ -718,6 +726,88 @@ class AudioContentService(
listOf()
}
var translated: TranslatedContent? = null
/**
* audioContent.languageCode != languageCode
*
* 번역 콘텐츠를 조회한다. - contentId, locale
* 번역 콘텐츠가 있으면
* TranslatedContent로 가공한다
*
* 번역 콘텐츠가 없으면
* 파파고 API를 통해 번역한 후 저장한다.
*
* 번역 대상: title, detail, tags
*
* 파파고로 번역한 데이터를 TranslatedContent로 가공한다
*/
if (
audioContent.languageCode != null &&
audioContent.languageCode!!.isNotBlank() &&
languageCode.isNotBlank() &&
audioContent.languageCode != languageCode
) {
val locale = languageCode.lowercase()
val existing = contentTranslationRepository
.findByContentIdAndLocale(audioContent.id!!, locale)
if (existing != null) {
val payload = existing.renderedPayload
translated = TranslatedContent(
title = payload.title,
detail = payload.detail,
tags = payload.tags
)
} else {
val texts = mutableListOf<String>()
texts.add(audioContent.title)
texts.add(audioContent.detail)
texts.add(tag)
val sourceLanguage = audioContent.languageCode ?: "ko"
val response = translationService.translate(
request = TranslateRequest(
texts = texts,
sourceLanguage = sourceLanguage,
targetLanguage = locale
)
)
val translatedTexts = response.translatedText
if (translatedTexts.size == texts.size) {
var index = 0
val translatedTitle = translatedTexts[index++]
val translatedDetail = translatedTexts[index++]
val translatedTags = translatedTexts[index]
val payload = kr.co.vividnext.sodalive.content.translation.ContentTranslationPayload(
title = translatedTitle,
detail = translatedDetail,
tags = translatedTags
)
contentTranslationRepository.save(
kr.co.vividnext.sodalive.content.translation.ContentTranslation(
contentId = audioContent.id!!,
locale = locale,
translatedTitle = translatedTitle,
renderedPayload = payload
)
)
translated = TranslatedContent(
title = translatedTitle,
detail = translatedDetail,
tags = translatedTags
)
}
}
}
return GetAudioContentDetailResponse(
contentId = audioContent.id!!,
title = audioContent.title,
@@ -765,7 +855,8 @@ class AudioContentService(
previousContent = previousContent,
nextContent = nextContent,
buyerList = buyerList,
isAvailableUsePoint = audioContent.isPointAvailable
isAvailableUsePoint = audioContent.isPointAvailable,
translated = translated
)
}