From 9288b44d5e995d668c1f59207ace3736aab780d6 Mon Sep 17 00:00:00 2001 From: Klaus Date: Fri, 10 Jul 2026 03:20:11 +0900 Subject: [PATCH] =?UTF-8?q?feat(home):=20AI=20=EC=BA=90=EB=A6=AD=ED=84=B0?= =?UTF-8?q?=20=EC=B6=94=EC=B2=9C=20=EC=A0=90=EC=88=98=20=EC=A0=95=EC=B1=85?= =?UTF-8?q?=EC=9D=84=20=EB=B3=80=EA=B2=BD=ED=95=9C=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/RecommendationScorePolicy.kt | 14 ++++++-- .../domain/RecommendationScoreSpec.kt | 8 +++-- .../domain/RecommendationScorePolicyTest.kt | 36 ++++++++++++------- 3 files changed, 40 insertions(+), 18 deletions(-) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/v2/recommendation/domain/RecommendationScorePolicy.kt b/src/main/kotlin/kr/co/vividnext/sodalive/v2/recommendation/domain/RecommendationScorePolicy.kt index 73cb0e7a..83a65f2d 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/v2/recommendation/domain/RecommendationScorePolicy.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/v2/recommendation/domain/RecommendationScorePolicy.kt @@ -9,7 +9,13 @@ class RecommendationScorePolicy { } fun calculateAiCharacterNewBoost(createdAt: LocalDateTime, now: LocalDateTime): Double { - return calculateNewBoost(createdAt, now) + val days = ChronoUnit.DAYS.between(createdAt.toLocalDate(), now.toLocalDate()) + return when { + days <= RecommendationScoreSpec.NEW_BOOST_10_DAY_LIMIT -> RecommendationScoreSpec.AI_NEW_BOOST_10_DAYS + days <= RecommendationScoreSpec.NEW_BOOST_20_DAY_LIMIT -> RecommendationScoreSpec.AI_NEW_BOOST_20_DAYS + days <= RecommendationScoreSpec.NEW_BOOST_30_DAY_LIMIT -> RecommendationScoreSpec.AI_NEW_BOOST_30_DAYS + else -> RecommendationScoreSpec.DEFAULT_NEW_BOOST + } } fun calculateDebutCreatorScore( @@ -28,11 +34,13 @@ class RecommendationScorePolicy { fun calculateAiChatScore( recentChatCount: Long, recentActiveUserCount: Long, + followIncreaseCount: Long, newBoost: Double ): Double { return ( - (RecommendationScoreSpec.AI_RECENT_CHAT_WEIGHT * recentChatCount) + - (RecommendationScoreSpec.AI_RECENT_ACTIVE_USER_WEIGHT * recentActiveUserCount) + (RecommendationScoreSpec.AI_CHAT_WEIGHT * recentChatCount) + + (RecommendationScoreSpec.AI_ACTIVE_USER_WEIGHT * recentActiveUserCount) + + (RecommendationScoreSpec.AI_FOLLOW_INCREASE_WEIGHT * followIncreaseCount) ) * newBoost } diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/v2/recommendation/domain/RecommendationScoreSpec.kt b/src/main/kotlin/kr/co/vividnext/sodalive/v2/recommendation/domain/RecommendationScoreSpec.kt index 5a93090c..82a0d98b 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/v2/recommendation/domain/RecommendationScoreSpec.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/v2/recommendation/domain/RecommendationScoreSpec.kt @@ -9,8 +9,9 @@ object RecommendationScoreSpec { const val DEBUT_CONTENT_ACTIVITY_WEIGHT = 0.3 const val DEBUT_COMMUNICATION_WEIGHT = 0.2 - const val AI_RECENT_CHAT_WEIGHT = 0.45 - const val AI_RECENT_ACTIVE_USER_WEIGHT = 0.35 + const val AI_CHAT_WEIGHT = 0.45 + const val AI_ACTIVE_USER_WEIGHT = 0.35 + const val AI_FOLLOW_INCREASE_WEIGHT = 0.20 const val CHEER_DONATION_AMOUNT_WEIGHT = 0.6 const val CHEER_FAN_TALK_WEIGHT = 0.3 @@ -23,5 +24,8 @@ object RecommendationScoreSpec { const val NEW_BOOST_10_DAYS = 1.5 const val NEW_BOOST_20_DAYS = 1.3 const val NEW_BOOST_30_DAYS = 1.2 + const val AI_NEW_BOOST_10_DAYS = 1.15 + const val AI_NEW_BOOST_20_DAYS = 1.10 + const val AI_NEW_BOOST_30_DAYS = 1.05 const val DEFAULT_NEW_BOOST = 1.0 } diff --git a/src/test/kotlin/kr/co/vividnext/sodalive/v2/recommendation/domain/RecommendationScorePolicyTest.kt b/src/test/kotlin/kr/co/vividnext/sodalive/v2/recommendation/domain/RecommendationScorePolicyTest.kt index ffeee339..883a8f41 100644 --- a/src/test/kotlin/kr/co/vividnext/sodalive/v2/recommendation/domain/RecommendationScorePolicyTest.kt +++ b/src/test/kotlin/kr/co/vividnext/sodalive/v2/recommendation/domain/RecommendationScorePolicyTest.kt @@ -27,10 +27,20 @@ class RecommendationScorePolicyTest { fun shouldApplyAiCharacterNewBoostByCreatedDays() { val now = LocalDateTime.of(2026, 5, 30, 12, 0) - assertEquals(1.5, policy.calculateAiCharacterNewBoost(now.minusDays(10), now), 0.0001) - assertEquals(1.3, policy.calculateAiCharacterNewBoost(now.minusDays(20), now), 0.0001) - assertEquals(1.2, policy.calculateAiCharacterNewBoost(now.minusDays(30), now), 0.0001) + assertEquals(1.15, RecommendationScoreSpec.AI_NEW_BOOST_10_DAYS, 0.0001) + assertEquals(1.10, RecommendationScoreSpec.AI_NEW_BOOST_20_DAYS, 0.0001) + assertEquals(1.05, RecommendationScoreSpec.AI_NEW_BOOST_30_DAYS, 0.0001) + assertEquals(1.15, policy.calculateAiCharacterNewBoost(now, now), 0.0001) + assertEquals(1.15, policy.calculateAiCharacterNewBoost(now.minusDays(10), now), 0.0001) + assertEquals(1.10, policy.calculateAiCharacterNewBoost(now.minusDays(11), now), 0.0001) + assertEquals(1.10, policy.calculateAiCharacterNewBoost(now.minusDays(20), now), 0.0001) + assertEquals(1.05, policy.calculateAiCharacterNewBoost(now.minusDays(21), now), 0.0001) + assertEquals(1.05, policy.calculateAiCharacterNewBoost(now.minusDays(30), now), 0.0001) assertEquals(1.0, policy.calculateAiCharacterNewBoost(now.minusDays(31), now), 0.0001) + + assertEquals(1.5, policy.calculateCreatorNewBoost(now.minusDays(10), now), 0.0001) + assertEquals(1.3, policy.calculateCreatorNewBoost(now.minusDays(20), now), 0.0001) + assertEquals(1.2, policy.calculateCreatorNewBoost(now.minusDays(30), now), 0.0001) } @Test @@ -51,18 +61,18 @@ class RecommendationScorePolicyTest { } @Test - @DisplayName("AI 채팅 추천 점수는 이번 스프린트에서 팔로우 증가량을 제외한다") + @DisplayName("AI 채팅 추천 점수는 AI 발화 수, 활성 사용자 수, 팔로우 증가량 가중치와 신규 부스트를 적용한다") fun shouldCalculateAiChatScore() { - assertEquals(0.45, RecommendationScoreSpec.AI_RECENT_CHAT_WEIGHT, 0.0001) - assertEquals(0.35, RecommendationScoreSpec.AI_RECENT_ACTIVE_USER_WEIGHT, 0.0001) + assertEquals(0.45, RecommendationScoreSpec.AI_CHAT_WEIGHT, 0.0001) + assertEquals(0.35, RecommendationScoreSpec.AI_ACTIVE_USER_WEIGHT, 0.0001) + assertEquals(0.20, RecommendationScoreSpec.AI_FOLLOW_INCREASE_WEIGHT, 0.0001) - val score = policy.calculateAiChatScore( - recentChatCount = 100, - recentActiveUserCount = 20, - newBoost = 1.3 - ) - - assertEquals(67.6, score, 0.0001) + assertEquals(0.0, policy.calculateAiChatScore(0, 0, 0, 1.0), 0.0001) + assertEquals(4.5, policy.calculateAiChatScore(10, 0, 0, 1.0), 0.0001) + assertEquals(3.5, policy.calculateAiChatScore(0, 10, 0, 1.0), 0.0001) + assertEquals(2.0, policy.calculateAiChatScore(0, 0, 10, 1.0), 0.0001) + assertEquals(10.0, policy.calculateAiChatScore(10, 10, 10, 1.0), 0.0001) + assertEquals(11.5, policy.calculateAiChatScore(10, 10, 10, 1.15), 0.0001) } @Test