|
1 | 1 | package org.wikipedia.analytics.eventplatform |
2 | 2 |
|
3 | 3 | import android.content.Context |
| 4 | +import kotlinx.coroutines.Dispatchers |
| 5 | +import kotlinx.coroutines.withContext |
| 6 | +import org.wikipedia.WikipediaApp |
| 7 | +import org.wikipedia.auth.AccountUtil |
| 8 | +import org.wikipedia.dataclient.ServiceFactory |
| 9 | +import org.wikipedia.page.PageTitle |
| 10 | +import org.wikipedia.settings.Prefs |
| 11 | +import org.wikipedia.util.ActiveTimer |
4 | 12 |
|
5 | | -object MachineGeneratedArticleDescriptionsAnalyticsHelper { |
| 13 | +class MachineGeneratedArticleDescriptionsAnalyticsHelper { |
| 14 | + |
| 15 | + private var apiFailed = false |
| 16 | + var apiOrderList = emptyList<String>() |
| 17 | + var displayOrderList = emptyList<String>() |
| 18 | + private var chosenSuggestion = "" |
| 19 | + val timer = ActiveTimer() |
6 | 20 |
|
7 | 21 | fun articleDescriptionEditingStart(context: Context) { |
8 | | - EventPlatformClient.submit( |
9 | | - BreadCrumbLogEvent( |
10 | | - BreadCrumbViewUtil.getReadableScreenName(context), |
11 | | - "ArticleDescriptionEditing.start" |
12 | | - ) |
13 | | - ) |
| 22 | + log(context, composeGroupString() + ".start") |
14 | 23 | } |
15 | 24 |
|
16 | 25 | fun articleDescriptionEditingEnd(context: Context) { |
17 | | - EventPlatformClient.submit( |
18 | | - BreadCrumbLogEvent( |
19 | | - BreadCrumbViewUtil.getReadableScreenName(context), |
20 | | - "ArticleDescriptionEditing.end" |
21 | | - ) |
22 | | - ) |
| 26 | + log(context, composeGroupString() + ".end") |
| 27 | + } |
| 28 | + |
| 29 | + fun logAttempt(context: Context, finalDescription: String, wasChosen: Boolean, wasModified: Boolean, title: PageTitle) { |
| 30 | + log(context, composeLogString(title) + ".attempt:$finalDescription" + |
| 31 | + ".suggestion1:${encode(apiOrderList.first())}" + (if (apiOrderList.size > 1) ".suggestion2:${encode(apiOrderList.last())}" else "") + |
| 32 | + getOrderString(wasChosen, chosenSuggestion) + ".modified:$wasModified.timeSpentMs:${timer.elapsedMillis}") |
| 33 | + } |
| 34 | + |
| 35 | + fun logSuccess(context: Context, finalDescription: String, wasChosen: Boolean, wasModified: Boolean, title: PageTitle, revId: Long) { |
| 36 | + log(context, composeLogString(title) + ".success:$finalDescription" + |
| 37 | + ".suggestion1:${encode(apiOrderList.first())}" + (if (apiOrderList.size > 1) ".suggestion2:${encode(apiOrderList.last())}" else "") + |
| 38 | + getOrderString(wasChosen, chosenSuggestion) + ".modified:$wasModified.timeSpentMs:${timer.elapsedMillis}.revId:$revId") |
| 39 | + } |
| 40 | + |
| 41 | + fun logSuggestionsReceived(context: Context, isBlp: Boolean, title: PageTitle) { |
| 42 | + apiFailed = false |
| 43 | + log(context, composeLogString(title) + ".blp:$isBlp.count:${apiOrderList.size}.suggestion1:${encode(apiOrderList.first())}" + |
| 44 | + if (apiOrderList.size > 1) ".suggestion2:${encode(apiOrderList.last())}" else "") |
| 45 | + } |
| 46 | + |
| 47 | + fun logSuggestionsShown(context: Context, title: PageTitle) { |
| 48 | + log(context, composeLogString(title) + ".count:${displayOrderList.size}.display1:${encode(displayOrderList.first())}" + |
| 49 | + if (displayOrderList.size > 1) ".display2:${encode(displayOrderList.last())}" else "") |
| 50 | + } |
| 51 | + |
| 52 | + fun logSuggestionChosen(context: Context, suggestion: String, title: PageTitle) { |
| 53 | + chosenSuggestion = suggestion |
| 54 | + log(context, composeLogString(title) + ".selected:${encode(suggestion)}${getOrderString(true, suggestion)}") |
| 55 | + } |
| 56 | + |
| 57 | + fun logSuggestionsDismissed(context: Context, title: PageTitle) { |
| 58 | + log(context, composeLogString(title) + ".suggestionsDialog.dismissed") |
| 59 | + } |
| 60 | + |
| 61 | + fun logSuggestionReported(context: Context, suggestion: String, reportReasonsList: List<String>, title: PageTitle) { |
| 62 | + val reportReasons = reportReasonsList.joinToString("|") |
| 63 | + log(context, composeLogString(title) + ".reportDialog.suggestion:${encode(suggestion)}${getOrderString(true, suggestion)}.reasons:$reportReasons.reported") |
| 64 | + } |
| 65 | + |
| 66 | + fun logReportDialogDismissed(context: Context) { |
| 67 | + log(context, composeGroupString() + ".reportDialog.dismissed") |
| 68 | + } |
| 69 | + |
| 70 | + fun logOnboardingShown(context: Context) { |
| 71 | + log(context, composeGroupString() + ".onboardingShown") |
| 72 | + } |
| 73 | + |
| 74 | + fun logGroupAssigned(context: Context, testGroup: Int) { |
| 75 | + log(context, "$MACHINE_GEN_DESC_SUGGESTIONS.groupAssigned:$testGroup") |
| 76 | + } |
| 77 | + |
| 78 | + fun logApiFailed(context: Context, throwable: Throwable, title: PageTitle) { |
| 79 | + log(context, composeLogString(title) + ".apiError:${throwable.message}") |
| 80 | + apiFailed = true |
| 81 | + } |
| 82 | + |
| 83 | + private fun log(context: Context, logString: String) { |
| 84 | + if (!isUserInExperiment || apiFailed) { |
| 85 | + return |
| 86 | + } |
| 87 | + EventPlatformClient.submit(BreadCrumbLogEvent(BreadCrumbViewUtil.getReadableScreenName(context), logString)) |
| 88 | + } |
| 89 | + |
| 90 | + private fun getOrderString(wasChosen: Boolean, suggestion: String): String { |
| 91 | + return ".chosenApiIndex:${if (!wasChosen) -1 else apiOrderList.indexOf(suggestion) + 1}" + |
| 92 | + ".chosenDisplayIndex:${if (!wasChosen) -1 else displayOrderList.indexOf(suggestion) + 1}" |
| 93 | + } |
| 94 | + |
| 95 | + private fun composeLogString(title: PageTitle): String { |
| 96 | + return "${composeGroupString()}.lang:${title.wikiSite.languageCode}.title:${encode(title.prefixedText)}" |
| 97 | + } |
| 98 | + |
| 99 | + private fun composeGroupString(): String { |
| 100 | + return "$MACHINE_GEN_DESC_SUGGESTIONS.group:${abcTest.group}.experienced:${Prefs.suggestedEditsMachineGeneratedDescriptionsIsExperienced}" |
| 101 | + } |
| 102 | + |
| 103 | + companion object { |
| 104 | + private const val MACHINE_GEN_DESC_SUGGESTIONS = "machineSuggestions" |
| 105 | + val abcTest = MachineGeneratedArticleDescriptionABCTest() |
| 106 | + var isUserInExperiment = false |
| 107 | + |
| 108 | + // HACK: We're using periods and colons as delimiting characters in these events, so let's |
| 109 | + // urlencode just those characters, if they appear in our strings. |
| 110 | + private fun encode(str: String): String { |
| 111 | + return str.replace(".", "%2E").replace(":", "%3A") |
| 112 | + } |
| 113 | + |
| 114 | + suspend fun setUserExperienced() = |
| 115 | + withContext(Dispatchers.Default) { |
| 116 | + val totalContributions = ServiceFactory.get(WikipediaApp.instance.wikiSite) |
| 117 | + .globalUserInfo(AccountUtil.userName!!).query?.globalUserInfo?.editCount ?: 0 |
| 118 | + Prefs.suggestedEditsMachineGeneratedDescriptionsIsExperienced = totalContributions > 50 |
| 119 | + } |
23 | 120 | } |
24 | 121 | } |
0 commit comments