크리에이터 콘텐츠 카테고리 언어 감지 및 번역 기능 추가
This commit is contained in:
@@ -3,6 +3,7 @@ package kr.co.vividnext.sodalive.content
|
|||||||
import kr.co.vividnext.sodalive.chat.character.comment.CharacterCommentRepository
|
import kr.co.vividnext.sodalive.chat.character.comment.CharacterCommentRepository
|
||||||
import kr.co.vividnext.sodalive.chat.character.repository.ChatCharacterRepository
|
import kr.co.vividnext.sodalive.chat.character.repository.ChatCharacterRepository
|
||||||
import kr.co.vividnext.sodalive.chat.original.OriginalWorkRepository
|
import kr.co.vividnext.sodalive.chat.original.OriginalWorkRepository
|
||||||
|
import kr.co.vividnext.sodalive.content.category.CategoryRepository
|
||||||
import kr.co.vividnext.sodalive.content.comment.AudioContentCommentRepository
|
import kr.co.vividnext.sodalive.content.comment.AudioContentCommentRepository
|
||||||
import kr.co.vividnext.sodalive.content.series.ContentSeriesRepository
|
import kr.co.vividnext.sodalive.content.series.ContentSeriesRepository
|
||||||
import kr.co.vividnext.sodalive.explorer.profile.CreatorCheersRepository
|
import kr.co.vividnext.sodalive.explorer.profile.CreatorCheersRepository
|
||||||
@@ -34,7 +35,9 @@ enum class LanguageDetectTargetType {
|
|||||||
CHARACTER_COMMENT,
|
CHARACTER_COMMENT,
|
||||||
CREATOR_CHEERS,
|
CREATOR_CHEERS,
|
||||||
SERIES,
|
SERIES,
|
||||||
ORIGINAL_WORK
|
ORIGINAL_WORK,
|
||||||
|
|
||||||
|
CREATOR_CONTENT_CATEGORY
|
||||||
}
|
}
|
||||||
|
|
||||||
class LanguageDetectEvent(
|
class LanguageDetectEvent(
|
||||||
@@ -56,6 +59,7 @@ class LanguageDetectListener(
|
|||||||
private val creatorCheersRepository: CreatorCheersRepository,
|
private val creatorCheersRepository: CreatorCheersRepository,
|
||||||
private val seriesRepository: ContentSeriesRepository,
|
private val seriesRepository: ContentSeriesRepository,
|
||||||
private val originalWorkRepository: OriginalWorkRepository,
|
private val originalWorkRepository: OriginalWorkRepository,
|
||||||
|
private val categoryRepository: CategoryRepository,
|
||||||
|
|
||||||
private val applicationEventPublisher: ApplicationEventPublisher,
|
private val applicationEventPublisher: ApplicationEventPublisher,
|
||||||
|
|
||||||
@@ -89,6 +93,7 @@ class LanguageDetectListener(
|
|||||||
LanguageDetectTargetType.CREATOR_CHEERS -> handleCreatorCheersLanguageDetect(event)
|
LanguageDetectTargetType.CREATOR_CHEERS -> handleCreatorCheersLanguageDetect(event)
|
||||||
LanguageDetectTargetType.SERIES -> handleSeriesLanguageDetect(event)
|
LanguageDetectTargetType.SERIES -> handleSeriesLanguageDetect(event)
|
||||||
LanguageDetectTargetType.ORIGINAL_WORK -> handleOriginalWorkLanguageDetect(event)
|
LanguageDetectTargetType.ORIGINAL_WORK -> handleOriginalWorkLanguageDetect(event)
|
||||||
|
LanguageDetectTargetType.CREATOR_CONTENT_CATEGORY -> handleCreatorContentCategoryLanguageDetect(event)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -341,6 +346,25 @@ class LanguageDetectListener(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun handleCreatorContentCategoryLanguageDetect(event: LanguageDetectEvent) {
|
||||||
|
val categoryId = event.id
|
||||||
|
|
||||||
|
val category = categoryRepository.findByIdOrNull(categoryId) ?: return
|
||||||
|
if (!category.languageCode.isNullOrBlank()) return
|
||||||
|
|
||||||
|
val langCode = requestPapagoLanguageCode(event.query, categoryId) ?: return
|
||||||
|
|
||||||
|
category.languageCode = langCode
|
||||||
|
categoryRepository.save(category)
|
||||||
|
|
||||||
|
applicationEventPublisher.publishEvent(
|
||||||
|
LanguageTranslationEvent(
|
||||||
|
id = categoryId,
|
||||||
|
targetType = LanguageTranslationTargetType.CREATOR_CONTENT_CATEGORY
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private fun requestPapagoLanguageCode(query: String, targetIdForLog: Long): String? {
|
private fun requestPapagoLanguageCode(query: String, targetIdForLog: Long): String? {
|
||||||
return try {
|
return try {
|
||||||
val headers = HttpHeaders().apply {
|
val headers = HttpHeaders().apply {
|
||||||
|
|||||||
@@ -8,9 +8,10 @@ import javax.persistence.JoinColumn
|
|||||||
import javax.persistence.ManyToOne
|
import javax.persistence.ManyToOne
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
data class Category(
|
class Category(
|
||||||
var title: String,
|
var title: String,
|
||||||
var orders: Int = 1,
|
var orders: Int = 1,
|
||||||
|
var languageCode: String? = null,
|
||||||
var isActive: Boolean = true
|
var isActive: Boolean = true
|
||||||
) : BaseEntity() {
|
) : BaseEntity() {
|
||||||
@ManyToOne(fetch = FetchType.LAZY)
|
@ManyToOne(fetch = FetchType.LAZY)
|
||||||
|
|||||||
@@ -2,8 +2,13 @@ package kr.co.vividnext.sodalive.content.category
|
|||||||
|
|
||||||
import kr.co.vividnext.sodalive.common.SodaException
|
import kr.co.vividnext.sodalive.common.SodaException
|
||||||
import kr.co.vividnext.sodalive.content.AudioContentRepository
|
import kr.co.vividnext.sodalive.content.AudioContentRepository
|
||||||
|
import kr.co.vividnext.sodalive.content.LanguageDetectEvent
|
||||||
|
import kr.co.vividnext.sodalive.content.LanguageDetectTargetType
|
||||||
|
import kr.co.vividnext.sodalive.i18n.translation.LanguageTranslationEvent
|
||||||
|
import kr.co.vividnext.sodalive.i18n.translation.LanguageTranslationTargetType
|
||||||
import kr.co.vividnext.sodalive.member.Member
|
import kr.co.vividnext.sodalive.member.Member
|
||||||
import kr.co.vividnext.sodalive.member.block.BlockMemberRepository
|
import kr.co.vividnext.sodalive.member.block.BlockMemberRepository
|
||||||
|
import org.springframework.context.ApplicationEventPublisher
|
||||||
import org.springframework.stereotype.Service
|
import org.springframework.stereotype.Service
|
||||||
import org.springframework.transaction.annotation.Transactional
|
import org.springframework.transaction.annotation.Transactional
|
||||||
|
|
||||||
@@ -12,7 +17,9 @@ class CategoryService(
|
|||||||
private val repository: CategoryRepository,
|
private val repository: CategoryRepository,
|
||||||
private val contentRepository: AudioContentRepository,
|
private val contentRepository: AudioContentRepository,
|
||||||
private val blockMemberRepository: BlockMemberRepository,
|
private val blockMemberRepository: BlockMemberRepository,
|
||||||
private val categoryContentRepository: CategoryContentRepository
|
private val categoryContentRepository: CategoryContentRepository,
|
||||||
|
|
||||||
|
private val applicationEventPublisher: ApplicationEventPublisher
|
||||||
) {
|
) {
|
||||||
@Transactional
|
@Transactional
|
||||||
fun createCategory(request: CreateCategoryRequest, member: Member) {
|
fun createCategory(request: CreateCategoryRequest, member: Member) {
|
||||||
@@ -40,6 +47,14 @@ class CategoryService(
|
|||||||
)
|
)
|
||||||
categoryContent.isActive = true
|
categoryContent.isActive = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
applicationEventPublisher.publishEvent(
|
||||||
|
LanguageDetectEvent(
|
||||||
|
id = category.id!!,
|
||||||
|
query = request.title,
|
||||||
|
targetType = LanguageDetectTargetType.CREATOR_CONTENT_CATEGORY
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
@@ -50,6 +65,13 @@ class CategoryService(
|
|||||||
if (!request.title.isNullOrBlank()) {
|
if (!request.title.isNullOrBlank()) {
|
||||||
validateTitle(title = request.title)
|
validateTitle(title = request.title)
|
||||||
category.title = request.title
|
category.title = request.title
|
||||||
|
|
||||||
|
applicationEventPublisher.publishEvent(
|
||||||
|
LanguageTranslationEvent(
|
||||||
|
id = request.categoryId,
|
||||||
|
targetType = LanguageTranslationTargetType.CREATOR_CONTENT_CATEGORY
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
for (contentId in request.addContentIdList) {
|
for (contentId in request.addContentIdList) {
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package kr.co.vividnext.sodalive.content.category
|
||||||
|
|
||||||
|
import kr.co.vividnext.sodalive.common.BaseEntity
|
||||||
|
import javax.persistence.Entity
|
||||||
|
import javax.persistence.Table
|
||||||
|
import javax.persistence.UniqueConstraint
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(
|
||||||
|
uniqueConstraints = [
|
||||||
|
UniqueConstraint(columnNames = ["categoryId", "locale"])
|
||||||
|
]
|
||||||
|
)
|
||||||
|
class CategoryTranslation(
|
||||||
|
val categoryId: Long,
|
||||||
|
val locale: String,
|
||||||
|
var category: String
|
||||||
|
) : BaseEntity()
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package kr.co.vividnext.sodalive.content.category
|
||||||
|
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository
|
||||||
|
|
||||||
|
interface CategoryTranslationRepository : JpaRepository<CategoryTranslation, Long> {
|
||||||
|
fun findByCategoryIdAndLocale(categoryId: Long, locale: String): CategoryTranslation?
|
||||||
|
}
|
||||||
@@ -13,6 +13,9 @@ import kr.co.vividnext.sodalive.chat.original.translation.OriginalWorkTranslatio
|
|||||||
import kr.co.vividnext.sodalive.chat.original.translation.OriginalWorkTranslationPayload
|
import kr.co.vividnext.sodalive.chat.original.translation.OriginalWorkTranslationPayload
|
||||||
import kr.co.vividnext.sodalive.chat.original.translation.OriginalWorkTranslationRepository
|
import kr.co.vividnext.sodalive.chat.original.translation.OriginalWorkTranslationRepository
|
||||||
import kr.co.vividnext.sodalive.content.AudioContentRepository
|
import kr.co.vividnext.sodalive.content.AudioContentRepository
|
||||||
|
import kr.co.vividnext.sodalive.content.category.CategoryRepository
|
||||||
|
import kr.co.vividnext.sodalive.content.category.CategoryTranslation
|
||||||
|
import kr.co.vividnext.sodalive.content.category.CategoryTranslationRepository
|
||||||
import kr.co.vividnext.sodalive.content.series.translation.SeriesGenreTranslation
|
import kr.co.vividnext.sodalive.content.series.translation.SeriesGenreTranslation
|
||||||
import kr.co.vividnext.sodalive.content.series.translation.SeriesGenreTranslationRepository
|
import kr.co.vividnext.sodalive.content.series.translation.SeriesGenreTranslationRepository
|
||||||
import kr.co.vividnext.sodalive.content.series.translation.SeriesTranslation
|
import kr.co.vividnext.sodalive.content.series.translation.SeriesTranslation
|
||||||
@@ -41,7 +44,9 @@ enum class LanguageTranslationTargetType {
|
|||||||
SERIES,
|
SERIES,
|
||||||
SERIES_GENRE,
|
SERIES_GENRE,
|
||||||
|
|
||||||
ORIGINAL_WORK
|
ORIGINAL_WORK,
|
||||||
|
|
||||||
|
CREATOR_CONTENT_CATEGORY
|
||||||
}
|
}
|
||||||
|
|
||||||
class LanguageTranslationEvent(
|
class LanguageTranslationEvent(
|
||||||
@@ -65,6 +70,9 @@ class LanguageTranslationListener(
|
|||||||
private val seriesGenreTranslationRepository: SeriesGenreTranslationRepository,
|
private val seriesGenreTranslationRepository: SeriesGenreTranslationRepository,
|
||||||
private val originalWorkTranslationRepository: OriginalWorkTranslationRepository,
|
private val originalWorkTranslationRepository: OriginalWorkTranslationRepository,
|
||||||
|
|
||||||
|
private val categoryRepository: CategoryRepository,
|
||||||
|
private val categoryTranslationRepository: CategoryTranslationRepository,
|
||||||
|
|
||||||
private val translationService: PapagoTranslationService
|
private val translationService: PapagoTranslationService
|
||||||
) {
|
) {
|
||||||
@Async
|
@Async
|
||||||
@@ -78,6 +86,7 @@ class LanguageTranslationListener(
|
|||||||
LanguageTranslationTargetType.SERIES -> handleSeriesLanguageTranslation(event)
|
LanguageTranslationTargetType.SERIES -> handleSeriesLanguageTranslation(event)
|
||||||
LanguageTranslationTargetType.SERIES_GENRE -> handleSeriesGenreLanguageTranslation(event)
|
LanguageTranslationTargetType.SERIES_GENRE -> handleSeriesGenreLanguageTranslation(event)
|
||||||
LanguageTranslationTargetType.ORIGINAL_WORK -> handleOriginalWorkLanguageTranslation(event)
|
LanguageTranslationTargetType.ORIGINAL_WORK -> handleOriginalWorkLanguageTranslation(event)
|
||||||
|
LanguageTranslationTargetType.CREATOR_CONTENT_CATEGORY -> handleCreatorContentCategoryLanguageTranslation(event)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -453,4 +462,45 @@ class LanguageTranslationListener(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun handleCreatorContentCategoryLanguageTranslation(event: LanguageTranslationEvent) {
|
||||||
|
val category = categoryRepository.findByIdOrNull(event.id)
|
||||||
|
|
||||||
|
if (category == null || !category.isActive || category.languageCode.isNullOrBlank()) return
|
||||||
|
|
||||||
|
val sourceLanguage = category.languageCode ?: "ko"
|
||||||
|
getTranslatableLanguageCodes(sourceLanguage).forEach { locale ->
|
||||||
|
val texts = mutableListOf<String>()
|
||||||
|
texts.add(category.title)
|
||||||
|
|
||||||
|
val response = translationService.translate(
|
||||||
|
request = TranslateRequest(
|
||||||
|
texts = texts,
|
||||||
|
sourceLanguage = sourceLanguage,
|
||||||
|
targetLanguage = locale
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
val translatedTexts = response.translatedText
|
||||||
|
if (translatedTexts.size == texts.size) {
|
||||||
|
val translatedCategory = translatedTexts[0]
|
||||||
|
|
||||||
|
val existing = categoryTranslationRepository
|
||||||
|
.findByCategoryIdAndLocale(category.id!!, locale)
|
||||||
|
|
||||||
|
if (existing == null) {
|
||||||
|
categoryTranslationRepository.save(
|
||||||
|
CategoryTranslation(
|
||||||
|
categoryId = category.id!!,
|
||||||
|
locale = locale,
|
||||||
|
category = translatedCategory
|
||||||
|
)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
existing.category = translatedCategory
|
||||||
|
categoryTranslationRepository.save(existing)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user