package com.twitter.home_mixer.model import com.twitter.core_workflows.user_model.{thriftscala => um} import com.twitter.dal.personal_data.{thriftjava => pd} import com.twitter.escherbird.{thriftscala => esb} import com.twitter.gizmoduck.{thriftscala => gt} import com.twitter.home_mixer.{thriftscala => hmt} import com.twitter.ml.api.constant.SharedFeatures import com.twitter.product_mixer.component_library.model.candidate.TweetCandidate import com.twitter.product_mixer.core.feature.Feature import com.twitter.product_mixer.core.feature.FeatureWithDefaultOnFailure import com.twitter.product_mixer.core.feature.datarecord.BoolDataRecordCompatible import com.twitter.product_mixer.core.feature.datarecord.DataRecordFeature import com.twitter.product_mixer.core.feature.datarecord.LongDiscreteDataRecordCompatible import com.twitter.product_mixer.core.model.marshalling.response.urt.metadata.TopicContextFunctionalityType import com.twitter.product_mixer.core.pipeline.PipelineQuery import com.twitter.search.common.features.{thriftscala => sc} import com.twitter.timelinemixer.clients.manhattan.DismissInfo import com.twitter.timelinemixer.clients.persistence.TimelineResponseV3 import com.twitter.timelinemixer.injection.model.candidate.AudioSpaceMetaData import com.twitter.timelines.conversation_features.v1.thriftscala.ConversationFeatures import com.twitter.timelines.impression.{thriftscala => imp} import com.twitter.timelines.impressionbloomfilter.{thriftscala => blm} import com.twitter.timelines.model.UserId import com.twitter.timelines.prediction.features.common.TimelinesSharedFeatures import com.twitter.timelines.prediction.features.recap.RecapFeatures import com.twitter.timelines.prediction.features.request_context.RequestContextFeatures import com.twitter.timelines.service.{thriftscala => tst} import com.twitter.timelineservice.model.FeedbackEntry import com.twitter.timelineservice.suggests.logging.candidate_tweet_source_id.{thriftscala => cts} import com.twitter.timelineservice.suggests.{thriftscala => st} import com.twitter.tsp.{thriftscala => tsp} import com.twitter.tweetconvosvc.tweet_ancestor.{thriftscala => ta} import com.twitter.util.Time object HomeFeatures { // Candidate Features object AncestorsFeature extends Feature[TweetCandidate, Seq[ta.TweetAncestor]] object AudioSpaceMetaDataFeature extends Feature[TweetCandidate, Option[AudioSpaceMetaData]] object TwitterListIdFeature extends Feature[TweetCandidate, Option[Long]] /** * For Retweets, this should refer to the retweeting user. Use [[SourceUserIdFeature]] if you want to know * who created the Tweet that was retweeted. */ object AuthorIdFeature extends Feature[TweetCandidate, Option[Long]] with LongDiscreteDataRecordCompatible { override val featureName: String = SharedFeatures.AUTHOR_ID.getFeatureName override val personalDataTypes: Set[pd.PersonalDataType] = Set(pd.PersonalDataType.UserId) } object AuthorIsEligibleForConnectBoostFeature extends Feature[TweetCandidate, Boolean] object AuthorIsBlueVerifiedFeature extends Feature[TweetCandidate, Boolean] object AuthoredByContextualUserFeature extends Feature[TweetCandidate, Boolean] object CachedCandidatePipelineIdentifierFeature extends Feature[TweetCandidate, Option[String]] object CandidateSourceIdFeature extends Feature[TweetCandidate, Option[cts.CandidateTweetSourceId]] object ConversationFeature extends Feature[TweetCandidate, Option[ConversationFeatures]] /** * This field should be set to the focal Tweet's tweetId for all tweets which are expected to * be rendered in the same convo module. For non-convo module Tweets, this will be * set to None. Note this is different from how TweetyPie defines ConversationId which is defined * on all Tweets and points to the root tweet. This feature is used for grouping convo modules together. */ object ConversationModuleFocalTweetIdFeature extends Feature[TweetCandidate, Option[Long]] /** * This field should always be set to the root Tweet in a conversation for all Tweets. For replies, this will * point back to the root Tweet. For non-replies, this will be the candidate's Tweet id. This is consistent with * the TweetyPie definition of ConversationModuleId. */ object ConversationModuleIdFeature extends Feature[TweetCandidate, Option[Long]] object DirectedAtUserIdFeature extends Feature[TweetCandidate, Option[Long]] object EarlybirdFeature extends Feature[TweetCandidate, Option[sc.ThriftTweetFeatures]] object EarlybirdScoreFeature extends Feature[TweetCandidate, Option[Double]] object EntityTokenFeature extends Feature[TweetCandidate, Option[String]] object ExclusiveConversationAuthorIdFeature extends Feature[TweetCandidate, Option[Long]] object FavoritedByUserIdsFeature extends Feature[TweetCandidate, Seq[Long]] object FeedbackHistoryFeature extends Feature[TweetCandidate, Seq[FeedbackEntry]] object RetweetedByEngagerIdsFeature extends Feature[TweetCandidate, Seq[Long]] object RepliedByEngagerIdsFeature extends Feature[TweetCandidate, Seq[Long]] object FollowedByUserIdsFeature extends Feature[TweetCandidate, Seq[Long]] object TopicIdSocialContextFeature extends Feature[TweetCandidate, Option[Long]] object TopicContextFunctionalityTypeFeature extends Feature[TweetCandidate, Option[TopicContextFunctionalityType]] object FromInNetworkSourceFeature extends Feature[TweetCandidate, Boolean] object FullScoringSucceededFeature extends Feature[TweetCandidate, Boolean] object HasDisplayedTextFeature extends Feature[TweetCandidate, Boolean] object InReplyToTweetIdFeature extends Feature[TweetCandidate, Option[Long]] object InReplyToUserIdFeature extends Feature[TweetCandidate, Option[Long]] object IsAncestorCandidateFeature extends Feature[TweetCandidate, Boolean] object IsExtendedReplyFeature extends DataRecordFeature[TweetCandidate, Boolean] with BoolDataRecordCompatible { override val featureName: String = RecapFeatures.IS_EXTENDED_REPLY.getFeatureName override val personalDataTypes: Set[pd.PersonalDataType] = Set.empty } object IsRandomTweetFeature extends Feature[TweetCandidate, Boolean] with BoolDataRecordCompatible { override val featureName: String = TimelinesSharedFeatures.IS_RANDOM_TWEET.getFeatureName override val personalDataTypes: Set[pd.PersonalDataType] = Set.empty } object IsReadFromCacheFeature extends Feature[TweetCandidate, Boolean] object IsRetweetFeature extends Feature[TweetCandidate, Boolean] object IsRetweetedReplyFeature extends Feature[TweetCandidate, Boolean] object LastScoredTimestampMsFeature extends Feature[TweetCandidate, Option[Long]] object NonSelfFavoritedByUserIdsFeature extends Feature[TweetCandidate, Seq[Long]] object NumImagesFeature extends Feature[TweetCandidate, Option[Int]] object OriginalTweetCreationTimeFromSnowflakeFeature extends Feature[TweetCandidate, Option[Time]] object PositionFeature extends Feature[TweetCandidate, Option[Int]] // Internal id generated per prediction service request object PredictionRequestIdFeature extends Feature[TweetCandidate, Option[Long]] object QuotedTweetIdFeature extends Feature[TweetCandidate, Option[Long]] object QuotedUserIdFeature extends Feature[TweetCandidate, Option[Long]] object ScoreFeature extends Feature[TweetCandidate, Option[Double]] object SemanticCoreIdFeature extends Feature[TweetCandidate, Option[Long]] // Key for kafka logging object ServedIdFeature extends Feature[TweetCandidate, Option[Long]] object SimclustersTweetTopKClustersWithScoresFeature extends Feature[TweetCandidate, Map[String, Double]] object SocialContextFeature extends Feature[TweetCandidate, Option[tst.SocialContext]] object SourceTweetIdFeature extends Feature[TweetCandidate, Option[Long]] with LongDiscreteDataRecordCompatible { override val featureName: String = TimelinesSharedFeatures.SOURCE_TWEET_ID.getFeatureName override val personalDataTypes: Set[pd.PersonalDataType] = Set(pd.PersonalDataType.TweetId) } object SourceUserIdFeature extends Feature[TweetCandidate, Option[Long]] object StreamToKafkaFeature extends Feature[TweetCandidate, Boolean] object SuggestTypeFeature extends Feature[TweetCandidate, Option[st.SuggestType]] object TSPMetricTagFeature extends Feature[TweetCandidate, Set[tsp.MetricTag]] object TweetLanguageFeature extends Feature[TweetCandidate, Option[String]] object TweetUrlsFeature extends Feature[TweetCandidate, Seq[String]] object VideoDurationMsFeature extends Feature[TweetCandidate, Option[Int]] object ViewerIdFeature extends Feature[TweetCandidate, Long] with LongDiscreteDataRecordCompatible { override def featureName: String = SharedFeatures.USER_ID.getFeatureName override def personalDataTypes: Set[pd.PersonalDataType] = Set(pd.PersonalDataType.UserId) } object WeightedModelScoreFeature extends Feature[TweetCandidate, Option[Double]] object MentionUserIdFeature extends Feature[TweetCandidate, Seq[Long]] object MentionScreenNameFeature extends Feature[TweetCandidate, Seq[String]] object SemanticAnnotationFeature extends Feature[TweetCandidate, Seq[esb.TweetEntityAnnotation]] object HasImageFeature extends Feature[TweetCandidate, Boolean] object HasVideoFeature extends Feature[TweetCandidate, Boolean] // Tweetypie VF Features object IsHydratedFeature extends FeatureWithDefaultOnFailure[TweetCandidate, Boolean] { override val defaultValue: Boolean = true } object IsNsfwFeature extends Feature[TweetCandidate, Boolean] object QuotedTweetDroppedFeature extends Feature[TweetCandidate, Boolean] // Raw Tweet Text from Tweetypie object TweetTextFeature extends Feature[TweetCandidate, Option[String]] // SGS Features /** * By convention, this is set to true for retweets of non-followed authors * E.g. where somebody the viewer follows retweets a Tweet from somebody the viewer doesn't follow */ object InNetworkFeature extends FeatureWithDefaultOnFailure[TweetCandidate, Boolean] { override val defaultValue: Boolean = true } // Query Features object AccountAgeFeature extends Feature[PipelineQuery, Option[Time]] object ClientIdFeature extends Feature[PipelineQuery, Option[Long]] with LongDiscreteDataRecordCompatible { override def featureName: String = SharedFeatures.CLIENT_ID.getFeatureName override def personalDataTypes: Set[pd.PersonalDataType] = Set(pd.PersonalDataType.ClientType) } object CachedScoredTweetsFeature extends Feature[PipelineQuery, Seq[hmt.CachedScoredTweet]] object DeviceLanguageFeature extends Feature[PipelineQuery, Option[String]] object DismissInfoFeature extends FeatureWithDefaultOnFailure[PipelineQuery, Map[st.SuggestType, Option[DismissInfo]]] { override def defaultValue: Map[st.SuggestType, Option[DismissInfo]] = Map.empty } object FollowingLastNonPollingTimeFeature extends Feature[PipelineQuery, Option[Time]] object GetInitialFeature extends Feature[PipelineQuery, Boolean] with BoolDataRecordCompatible { override def featureName: String = RequestContextFeatures.IS_GET_INITIAL.getFeatureName override def personalDataTypes: Set[pd.PersonalDataType] = Set.empty } object GetMiddleFeature extends Feature[PipelineQuery, Boolean] with BoolDataRecordCompatible { override def featureName: String = RequestContextFeatures.IS_GET_MIDDLE.getFeatureName override def personalDataTypes: Set[pd.PersonalDataType] = Set.empty } object GetNewerFeature extends Feature[PipelineQuery, Boolean] with BoolDataRecordCompatible { override def featureName: String = RequestContextFeatures.IS_GET_NEWER.getFeatureName override def personalDataTypes: Set[pd.PersonalDataType] = Set.empty } object GetOlderFeature extends Feature[PipelineQuery, Boolean] with BoolDataRecordCompatible { override def featureName: String = RequestContextFeatures.IS_GET_OLDER.getFeatureName override def personalDataTypes: Set[pd.PersonalDataType] = Set.empty } object GuestIdFeature extends Feature[PipelineQuery, Option[Long]] with LongDiscreteDataRecordCompatible { override def featureName: String = SharedFeatures.GUEST_ID.getFeatureName override def personalDataTypes: Set[pd.PersonalDataType] = Set(pd.PersonalDataType.GuestId) } object HasDarkRequestFeature extends Feature[TweetCandidate, Option[Boolean]] object ImpressionBloomFilterFeature extends FeatureWithDefaultOnFailure[PipelineQuery, blm.ImpressionBloomFilterSeq] { override def defaultValue: blm.ImpressionBloomFilterSeq = blm.ImpressionBloomFilterSeq(Seq.empty) } object IsForegroundRequestFeature extends Feature[PipelineQuery, Boolean] object IsLaunchRequestFeature extends Feature[PipelineQuery, Boolean] object LastNonPollingTimeFeature extends Feature[PipelineQuery, Option[Time]] object NonPollingTimesFeature extends Feature[PipelineQuery, Seq[Long]] object PersistenceEntriesFeature extends Feature[PipelineQuery, Seq[TimelineResponseV3]] object PollingFeature extends Feature[PipelineQuery, Boolean] object PullToRefreshFeature extends Feature[PipelineQuery, Boolean] // Scores from Real Graph representing the relationship between the viewer and another user object RealGraphInNetworkScoresFeature extends Feature[PipelineQuery, Map[UserId, Double]] object RequestJoinIdFeature extends Feature[TweetCandidate, Option[Long]] // Internal id generated per request, mainly to deduplicate re-served cached tweets in logging object ServedRequestIdFeature extends Feature[PipelineQuery, Option[Long]] object ServedTweetIdsFeature extends Feature[PipelineQuery, Seq[Long]] object TweetImpressionsFeature extends Feature[PipelineQuery, Seq[imp.TweetImpressionsEntry]] object UserFollowedTopicsCountFeature extends Feature[PipelineQuery, Option[Int]] object UserFollowingCountFeature extends Feature[PipelineQuery, Option[Int]] object UserScreenNameFeature extends Feature[PipelineQuery, Option[String]] object UserStateFeature extends Feature[PipelineQuery, Option[um.UserState]] object UserTypeFeature extends Feature[PipelineQuery, Option[gt.UserType]] object WhoToFollowExcludedUserIdsFeature extends FeatureWithDefaultOnFailure[PipelineQuery, Seq[Long]] { override def defaultValue = Seq.empty } // Result Features object ServedSizeFeature extends Feature[PipelineQuery, Option[Int]] object HasRandomTweetFeature extends Feature[PipelineQuery, Boolean] object IsRandomTweetAboveFeature extends Feature[TweetCandidate, Boolean] object ServedInConversationModuleFeature extends Feature[TweetCandidate, Boolean] object ConversationModule2DisplayedTweetsFeature extends Feature[TweetCandidate, Boolean] object ConversationModuleHasGapFeature extends Feature[TweetCandidate, Boolean] object SGSValidLikedByUserIdsFeature extends Feature[TweetCandidate, Seq[Long]] object SGSValidFollowedByUserIdsFeature extends Feature[TweetCandidate, Seq[Long]] object PerspectiveFilteredLikedByUserIdsFeature extends Feature[TweetCandidate, Seq[Long]] object ScreenNamesFeature extends Feature[TweetCandidate, Map[Long, String]] object RealNamesFeature extends Feature[TweetCandidate, Map[Long, String]] /** * Features around the focal Tweet for Tweets which should be rendered in convo modules. * These are needed in order to render social context above the root tweet in a convo modules. * For example if we have a convo module A-B-C (A Tweets, B replies to A, C replies to B), the descendant features are * for the Tweet C. These features are None except for the root Tweet for Tweets which should render into * convo modules. */ object FocalTweetAuthorIdFeature extends Feature[TweetCandidate, Option[Long]] object FocalTweetInNetworkFeature extends Feature[TweetCandidate, Option[Boolean]] object FocalTweetRealNamesFeature extends Feature[TweetCandidate, Option[Map[Long, String]]] object FocalTweetScreenNamesFeature extends Feature[TweetCandidate, Option[Map[Long, String]]] object MediaUnderstandingAnnotationIdsFeature extends Feature[TweetCandidate, Seq[Long]] }