예제 #1
0
        public static async Task <TweetProcessingData> ProcessTweet(
            [OrchestrationTrigger] IDurableOrchestrationContext context,
            ILogger log)
        {
            TweetProcessingData tpd = context.GetInput <TweetProcessingData>();

            if (!context.IsReplaying)
            {
                log.LogInformation("P_ProcessTweet call A_GetBusinessLogicScore");
            }

            // The following function is not async, so it could be called directly rather than through the activity model.
            PublishLabel tmpLabelBL = PublishLabel.NotAssigned;

            (tpd.Score, tmpLabelBL, tpd.TextWithoutTagsHighlighted) = await
                                                                      context.CallActivityAsync <Tuple <double, PublishLabel, string> >("A_GetBusinessLogicScore", tpd.TextWithoutTags);

            tpd.LabelBL = (int)tmpLabelBL;

            if (tpd.LabelBL != (int)PublishLabel.Negative)
            {
                log.LogInformation("Minimum BL score exceeded, query ML filter.");

                var mlResult = await context.CallActivityAsync <MlResult>("A_GetMlScore", tpd.TextWithoutTags);

                tpd.ScoreML   = mlResult.Score;
                tpd.LabelML   = (int)mlResult.Label;
                tpd.VersionML = mlResult.MlVersion;

                if (!(tpd.VersionML is null))
                {
                    log.LogInformation(
                        $"ML-inference OK, label: {tpd.LabelML}, "
                        + $"score: {tpd.ScoreML.ToString("F", CultureInfo.InvariantCulture)}, "
                        + $"version: {tpd.VersionML}");
                }
                else
                {
                    // Did not get a reply from the ML function, therefore
                    // we fall back and continue according to the traditional
                    // logic's result; indicated by tpd.VersionML is null.
                    log.LogInformation("ML inference failed or did not reply, rely on conventional logic.");
                }
            }
예제 #2
0
        public static async Task <List <TweetProcessingData> > GetTweets([ActivityTrigger] string lastTweetId, ILogger log)
        {
            log.LogInformation($"A_GetTweets: Getting new tweets after {lastTweetId}.");
            KeyVaultAccessor kva    = KeyVaultAccessor.GetInstance();
            string           apiKey = await kva.GetSecretAsync("TwitterApiKey");   // aka consumer key

            string apiSecretKey = await kva.GetSecretAsync("TwitterApiSecretKey"); // aka consumer secret

            string accessToken = await kva.GetSecretAsync("TwitterAccessToken");

            string accessTokenSecret = await kva.GetSecretAsync("TwitterAccessTokenSecret");

            string monitoredTwitterAccount  = Environment.GetEnvironmentVariable("MonitoredTwitterAccount");
            List <TweetProcessingData> tpds = new List <TweetProcessingData>(); // return value, empty list if Twitter connection failure

            var userCredentials = Auth.SetUserCredentials(apiKey, apiSecretKey, accessToken, accessTokenSecret);

            try
            {
                // This variable is not used later, but seems to leave an id for the library.
                var authenticatedUser = User.GetAuthenticatedUser(userCredentials);
            }
            catch (AggregateException ae)
            {
                // Inserted try-catch after a seemingly intermittent exception that lead to
                // the service stopping completely, 20210102, ca. 11 am.
                log.LogWarning($"A_GetTweets: User authentication failure: {ae.Message}. Return no tweets and retry in next cycle.");
                return(tpds);
            }

            // Note: The following does NOT get MaximumNumberOfResults tweets
            //       from after lastTweetId!!! Rather it gets the most recent
            //       tweets with the early limit defined by lastTweetId OR the
            //       defined maximum, whichever is more limiting!
            //       (Therefore, in order to test on past tweets, one may need
            //       to increase MaximumNumberOfResults considerably to get ALL
            //       tweets from the one targeted to the current one.
            SearchTweetsParameters searchParameter = new SearchTweetsParameters($"from:{monitoredTwitterAccount}")
            {
                MaximumNumberOfResults = 15,
                SinceId = long.Parse(lastTweetId)
            };

            IEnumerable <ITweet> tweets = null;

            try
            {
                tweets = await SearchAsync.SearchTweets(searchParameter);
            }
            catch (Exception e)
            {
                // Inserted try-catch after a seemingly intermittent exception that lead to
                // the service stopping completely, 20201213, ca. 7 am.
                log.LogWarning($"A_GetTweets: SearchTweets failed with exception: {e.Message}");
            }
            if (tweets is null)
            {
                log.LogWarning($"A_GetTweets: Twitter connection failure. Return no tweets and retry in next cycle.");
                return(tpds);
            }
            // Since the further processing can scramble the order again, we don't need to sort here.

            foreach (var tweet in tweets)
            {
                // Copy the data that we need over to a serializable struct.
                TweetProcessingData tpd = new TweetProcessingData();
                tpd.IdStr     = tweet.IdStr;
                tpd.CreatedAt = tweet.CreatedAt;
                tpd.FullText  = tweet.FullText;

                tpd.Hashtags = String.Join("|", tweet.Hashtags.Select(t => t.Text));

                tpd.InReplyToStatusIdStr = tweet.InReplyToStatusIdStr;
                tpd.Url = tweet.Url;

                tpd.TextWithoutTags = TweetAnalysis.removeHashtagsFromText(tweet.FullText, tweet.Hashtags);

                tpds.Add(tpd);
            }
            log.LogInformation($"A_GetTweets: Done, got {tweets.Count()} new tweets.");

            return(tpds);
        }