package com.twitter.home_mixer.functional_component.decorator import com.twitter.conversions.DurationOps._ import com.twitter.home_mixer.model.HomeFeatures._ import com.twitter.product_mixer.core.feature.featuremap.FeatureMap import com.twitter.timelinemixer.injection.model.candidate.SemanticCoreFeatures import com.twitter.tweetypie.{thriftscala => tpt} object HomeTweetTypePredicates { /** * IMPORTANT: Please avoid logging tweet types that are tied to sensitive * internal author information / labels (e.g. blink labels, abuse labels, or geo-location). */ private[this] val CandidatePredicates: Seq[(String, FeatureMap => Boolean)] = Seq( ("with_candidate", _ => true), ("retweet", _.getOrElse(IsRetweetFeature, false)), ("reply", _.getOrElse(InReplyToTweetIdFeature, None).nonEmpty), ("image", _.getOrElse(EarlybirdFeature, None).exists(_.hasImage)), ("video", _.getOrElse(EarlybirdFeature, None).exists(_.hasVideo)), ("link", _.getOrElse(EarlybirdFeature, None).exists(_.hasVisibleLink)), ("quote", _.getOrElse(EarlybirdFeature, None).exists(_.hasQuote.contains(true))), ("like_social_context", _.getOrElse(NonSelfFavoritedByUserIdsFeature, Seq.empty).nonEmpty), ("protected", _.getOrElse(EarlybirdFeature, None).exists(_.isProtected)), ( "has_exclusive_conversation_author_id", _.getOrElse(ExclusiveConversationAuthorIdFeature, None).nonEmpty), ("is_eligible_for_connect_boost", _.getOrElse(AuthorIsEligibleForConnectBoostFeature, false)), ("hashtag", _.getOrElse(EarlybirdFeature, None).exists(_.numHashtags > 0)), ("has_scheduled_space", _.getOrElse(AudioSpaceMetaDataFeature, None).exists(_.isScheduled)), ("has_recorded_space", _.getOrElse(AudioSpaceMetaDataFeature, None).exists(_.isRecorded)), ("is_read_from_cache", _.getOrElse(IsReadFromCacheFeature, false)), ( "is_self_thread_tweet", _.getOrElse(ConversationFeature, None).exists(_.isSelfThreadTweet.contains(true))), ("get_initial", _.getOrElse(GetInitialFeature, false)), ("get_newer", _.getOrElse(GetNewerFeature, false)), ("get_middle", _.getOrElse(GetMiddleFeature, false)), ("get_older", _.getOrElse(GetOlderFeature, false)), ("pull_to_refresh", _.getOrElse(PullToRefreshFeature, false)), ("polling", _.getOrElse(PollingFeature, false)), ("tls_size_20_plus", _ => false), ("near_empty", _ => false), ("ranked_request", _ => false), ("mutual_follow", _.getOrElse(EarlybirdFeature, None).exists(_.fromMutualFollow)), ("has_ticketed_space", _.getOrElse(AudioSpaceMetaDataFeature, None).exists(_.hasTickets)), ("in_utis_top5", _.getOrElse(PositionFeature, None).exists(_ < 5)), ("is_utis_pos0", _.getOrElse(PositionFeature, None).exists(_ == 0)), ("is_utis_pos1", _.getOrElse(PositionFeature, None).exists(_ == 1)), ("is_utis_pos2", _.getOrElse(PositionFeature, None).exists(_ == 2)), ("is_utis_pos3", _.getOrElse(PositionFeature, None).exists(_ == 3)), ("is_utis_pos4", _.getOrElse(PositionFeature, None).exists(_ == 4)), ( "is_signup_request", candidate => candidate.getOrElse(AccountAgeFeature, None).exists(_.untilNow < 30.minutes)), ("empty_request", _ => false), ("served_size_less_than_5", _.getOrElse(ServedSizeFeature, None).exists(_ < 5)), ("served_size_less_than_10", _.getOrElse(ServedSizeFeature, None).exists(_ < 10)), ("served_size_less_than_20", _.getOrElse(ServedSizeFeature, None).exists(_ < 20)), ("served_size_less_than_50", _.getOrElse(ServedSizeFeature, None).exists(_ < 50)), ( "served_size_between_50_and_100", _.getOrElse(ServedSizeFeature, None).exists(size => size >= 50 && size < 100)), ("authored_by_contextual_user", _.getOrElse(AuthoredByContextualUserFeature, false)), ("has_ancestors", _.getOrElse(AncestorsFeature, Seq.empty).nonEmpty), ("full_scoring_succeeded", _.getOrElse(FullScoringSucceededFeature, false)), ( "account_age_less_than_30_minutes", _.getOrElse(AccountAgeFeature, None).exists(_.untilNow < 30.minutes)), ( "account_age_less_than_1_day", _.getOrElse(AccountAgeFeature, None).exists(_.untilNow < 1.day)), ( "account_age_less_than_7_days", _.getOrElse(AccountAgeFeature, None).exists(_.untilNow < 7.days)), ( "directed_at_user_is_in_first_degree", _.getOrElse(EarlybirdFeature, None).exists(_.directedAtUserIdIsInFirstDegree.contains(true))), ("root_user_is_in_first_degree", _ => false), ( "has_semantic_core_annotation", _.getOrElse(EarlybirdFeature, None).exists(_.semanticCoreAnnotations.nonEmpty)), ("is_request_context_foreground", _.getOrElse(IsForegroundRequestFeature, false)), ( "part_of_utt", _.getOrElse(EarlybirdFeature, None) .exists(_.semanticCoreAnnotations.exists(_.exists(annotation => annotation.domainId == SemanticCoreFeatures.UnifiedTwitterTaxonomy)))), ("is_random_tweet", _.getOrElse(IsRandomTweetFeature, false)), ("has_random_tweet_in_response", _.getOrElse(HasRandomTweetFeature, false)), ("is_random_tweet_above_in_utis", _.getOrElse(IsRandomTweetAboveFeature, false)), ("is_request_context_launch", _.getOrElse(IsLaunchRequestFeature, false)), ("viewer_is_employee", _ => false), ("viewer_is_timelines_employee", _ => false), ("viewer_follows_any_topics", _.getOrElse(UserFollowedTopicsCountFeature, None).exists(_ > 0)), ( "has_ancestor_authored_by_viewer", candidate => candidate .getOrElse(AncestorsFeature, Seq.empty).exists(ancestor => candidate.getOrElse(ViewerIdFeature, 0L) == ancestor.userId)), ("ancestor", _.getOrElse(IsAncestorCandidateFeature, false)), ( "root_ancestor", candidate => candidate.getOrElse(IsAncestorCandidateFeature, false) && candidate .getOrElse(InReplyToTweetIdFeature, None).isEmpty), ( "deep_reply", candidate => candidate.getOrElse(InReplyToTweetIdFeature, None).nonEmpty && candidate .getOrElse(AncestorsFeature, Seq.empty).size > 2), ( "has_simcluster_embeddings", _.getOrElse( SimclustersTweetTopKClustersWithScoresFeature, Map.empty[String, Double]).nonEmpty), ( "tweet_age_less_than_15_seconds", _.getOrElse(OriginalTweetCreationTimeFromSnowflakeFeature, None) .exists(_.untilNow <= 15.seconds)), ("is_followed_topic_tweet", _ => false), ("is_recommended_topic_tweet", _ => false), ("is_topic_tweet", _ => false), ("preferred_language_matches_tweet_language", _ => false), ( "device_language_matches_tweet_language", candidate => candidate.getOrElse(TweetLanguageFeature, None) == candidate.getOrElse(DeviceLanguageFeature, None)), ("question", _.getOrElse(EarlybirdFeature, None).exists(_.hasQuestion.contains(true))), ("in_network", _.getOrElse(FromInNetworkSourceFeature, true)), ("viewer_follows_original_author", _ => false), ("has_account_follow_prompt", _ => false), ("has_relevance_prompt", _ => false), ("has_topic_annotation_haug_prompt", _ => false), ("has_topic_annotation_random_precision_prompt", _ => false), ("has_topic_annotation_prompt", _ => false), ( "has_political_annotation", _.getOrElse(EarlybirdFeature, None).exists( _.semanticCoreAnnotations.exists( _.exists(annotation => SemanticCoreFeatures.PoliticalDomains.contains(annotation.domainId) || (annotation.domainId == SemanticCoreFeatures.UnifiedTwitterTaxonomy && annotation.entityId == SemanticCoreFeatures.UttPoliticsEntityId))))), ( "is_dont_at_me_by_invitation", _.getOrElse(EarlybirdFeature, None).exists( _.conversationControl.exists(_.isInstanceOf[tpt.ConversationControl.ByInvitation]))), ( "is_dont_at_me_community", _.getOrElse(EarlybirdFeature, None) .exists(_.conversationControl.exists(_.isInstanceOf[tpt.ConversationControl.Community]))), ("has_zero_score", _.getOrElse(ScoreFeature, None).exists(_ == 0.0)), ("is_viewer_not_invited_to_reply", _ => false), ("is_viewer_invited_to_reply", _ => false), ("has_gte_10_favs", _.getOrElse(EarlybirdFeature, None).exists(_.favCountV2.exists(_ >= 10))), ("has_gte_100_favs", _.getOrElse(EarlybirdFeature, None).exists(_.favCountV2.exists(_ >= 100))), ("has_gte_1k_favs", _.getOrElse(EarlybirdFeature, None).exists(_.favCountV2.exists(_ >= 1000))), ( "has_gte_10k_favs", _.getOrElse(EarlybirdFeature, None).exists(_.favCountV2.exists(_ >= 1000))), ( "has_gte_100k_favs", _.getOrElse(EarlybirdFeature, None).exists(_.favCountV2.exists(_ >= 100000))), ("above_neighbor_is_topic_tweet", _ => false), ("is_topic_tweet_with_neighbor_below", _ => false), ("has_audio_space", _.getOrElse(AudioSpaceMetaDataFeature, None).exists(_.hasSpace)), ("has_live_audio_space", _.getOrElse(AudioSpaceMetaDataFeature, None).exists(_.isLive)), ( "has_gte_10_retweets", _.getOrElse(EarlybirdFeature, None).exists(_.retweetCountV2.exists(_ >= 10))), ( "has_gte_100_retweets", _.getOrElse(EarlybirdFeature, None).exists(_.retweetCountV2.exists(_ >= 100))), ( "has_gte_1k_retweets", _.getOrElse(EarlybirdFeature, None).exists(_.retweetCountV2.exists(_ >= 1000))), ( "has_us_political_annotation", _.getOrElse(EarlybirdFeature, None) .exists(_.semanticCoreAnnotations.exists(_.exists(annotation => annotation.domainId == SemanticCoreFeatures.UnifiedTwitterTaxonomy && annotation.entityId == SemanticCoreFeatures.usPoliticalTweetEntityId && annotation.groupId == SemanticCoreFeatures.UsPoliticalTweetAnnotationGroupIds.BalancedV0)))), ( "has_toxicity_score_above_threshold", _.getOrElse(EarlybirdFeature, None).exists(_.toxicityScore.exists(_ > 0.91))), ( "text_only", candidate => candidate.getOrElse(HasDisplayedTextFeature, false) && !(candidate.getOrElse(EarlybirdFeature, None).exists(_.hasImage) || candidate.getOrElse(EarlybirdFeature, None).exists(_.hasVideo) || candidate.getOrElse(EarlybirdFeature, None).exists(_.hasCard))), ( "image_only", candidate => candidate.getOrElse(EarlybirdFeature, None).exists(_.hasImage) && !candidate.getOrElse(HasDisplayedTextFeature, false)), ("has_1_image", _.getOrElse(NumImagesFeature, None).exists(_ == 1)), ("has_2_images", _.getOrElse(NumImagesFeature, None).exists(_ == 2)), ("has_3_images", _.getOrElse(NumImagesFeature, None).exists(_ == 3)), ("has_4_images", _.getOrElse(NumImagesFeature, None).exists(_ == 4)), ("has_card", _.getOrElse(EarlybirdFeature, None).exists(_.hasCard)), ("3_or_more_consecutive_not_in_network", _ => false), ("2_or_more_consecutive_not_in_network", _ => false), ("5_out_of_7_not_in_network", _ => false), ("7_out_of_7_not_in_network", _ => false), ("5_out_of_5_not_in_network", _ => false), ("user_follow_count_gte_50", _.getOrElse(UserFollowingCountFeature, None).exists(_ > 50)), ("has_liked_by_social_context", _ => false), ("has_followed_by_social_context", _ => false), ("has_topic_social_context", _ => false), ("timeline_entry_has_banner", _ => false), ("served_in_conversation_module", _.getOrElse(ServedInConversationModuleFeature, false)), ( "conversation_module_has_2_displayed_tweets", _.getOrElse(ConversationModule2DisplayedTweetsFeature, false)), ("conversation_module_has_gap", _.getOrElse(ConversationModuleHasGapFeature, false)), ("served_in_recap_tweet_candidate_module_injection", _ => false), ("served_in_threaded_conversation_module", _ => false) ) val PredicateMap = CandidatePredicates.toMap }