private async Task AnalyzeTextAsync()
        {
            try
            {
                if (!string.IsNullOrEmpty(this.speechRecognitionTextBox.Text))
                {
                    SentimentResult textAnalysisResult = await TextAnalyticsHelper.GetTextSentimentAsync(new string[] { this.speechRecognitionTextBox.Text });

                    double score = textAnalysisResult.Scores.ElementAt(0);
                    this.sentimentControl.Sentiment = score;
                }
                else
                {
                    this.sentimentControl.Sentiment = 0.5;
                }

                this.OnSpeechRecognitionAndSentimentProcessed(new SpeechRecognitionAndSentimentResult {
                    SpeechRecognitionText = this.speechRecognitionTextBox.Text, TextAnalysisSentiment = this.sentimentControl.Sentiment
                });
            }
            catch (Exception ex)
            {
                await Util.GenericApiCallExceptionHandler(ex, "Error during Text Analytics call.");
            }
        }
        public static async Task Run(
            [BlobTrigger("searchabledocuments/{name}.{ext}", Connection = "AzureWebJobsStorage")] Stream myBlob,
            string name, string ext, TraceWriter log)
        {
            // Because suffix filters don't work yet - this should take non-pdfs off the todo list
            if (ext.ToLower() != "pdf")
            {
                return;
            }

            log.Info($"Text Processing beginning for {name} ({myBlob.Length} Bytes)");

            log.Info($"Extracting text from the PDF (including OCR");
            var pages = iTextPDFHelper.GetPDFPages(myBlob, log, ocrImages: true);

            log.Info($"Calling Text Analytics to determine key phrases");
            Dictionary <string, int> keyPhrases = await TextAnalyticsHelper.GetKeyPhrases(pages, log);

            log.Info($"Uploading document to Azure Search");
            foreach (var page in pages)
            {
                string pageId = HttpServerUtility.UrlTokenEncode(Encoding.UTF8.GetBytes(name + "." + ext + page.Number));
                await AzureSearchHelper.UploadToAzureSearch(pageId, name + "." + ext, page.Number, page.KeyPhrases, page.Text, log);
            }
        }
示例#3
0
        public static async Task Run(
            [BlobTrigger("summariseddocuments/{name}.{ext}")] Stream myBlob,
            [Blob("summariseddocuments/{name}.{ext}.summary.txt", FileAccess.Write)] CloudBlobStream summaryBlob,
            string name,
            string ext,
            TraceWriter log
            )
        {
            // Because suffix filters don't work yet - this should take non-pdfs off the todo list
            if (ext.ToLower() != "pdf")
            {
                return;
            }

            log.Info($"Text Processing beginning for {name} ({myBlob.Length} Bytes)");

            log.Info($"Extracting text from the PDF");
            var pages = iTextPDFHelper.GetPDFPages(myBlob, log, ocrImages: true);

            log.Info($"Calling Text Analytics to determine key phrases");
            Dictionary <string, int> keyPhrases = await TextAnalyticsHelper.GetKeyPhrases(pages, log);

            var topPhrases = keyPhrases.OrderByDescending(pair => pair.Value).Take(20).ToList();

            log.Info($"Building summary");
            string summary = TextAnalyticsHelper.BuildSummary(pages, topPhrases);

            log.Info($"Saving summary to new blob");
            using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(summary), false))
            {
                stream.CopyTo(summaryBlob);
            }
        }
示例#4
0
        private async Task SearchAsync(string query)
        {
            try
            {
                this.TopKeyPhrases.Clear();
                this.latestSearchResult.Clear();
                this.FilteredNewsResults.Clear();
                this.sentimentDistributionControl.UpdateData(Enumerable.Empty <double>());

                this.progressRing.IsActive = true;

                string userLanguage = this.languageComboBox.SelectedValue.ToString();

                var news = await BingSearchHelper.GetNewsSearchResults(query, count : 50, offset : 0, market : GetBingSearchMarketFromLanguage(userLanguage));

                Task <SentimentResult> sentimentTask = TextAnalyticsHelper.GetTextSentimentAsync(news.Select(n => n.Title).ToArray(), language: GetTextAnalyticsLanguageCodeFromLanguage(userLanguage));

                Task <KeyPhrasesResult> keyPhrasesTask;
                if (IsLanguageSupportedByKeyPhraseAPI(userLanguage))
                {
                    keyPhrasesTask = TextAnalyticsHelper.GetKeyPhrasesAsync(news.Select(n => n.Title).ToArray(), language: GetTextAnalyticsLanguageCodeFromLanguage(userLanguage));
                }
                else
                {
                    keyPhrasesTask = Task.FromResult(new KeyPhrasesResult {
                        KeyPhrases = new string[][] { new string [] { "Not available in this language" } }
                    });
                }

                await Task.WhenAll(sentimentTask, keyPhrasesTask);

                var sentiment = sentimentTask.Result;

                for (int i = 0; i < news.Count(); i++)
                {
                    NewsArticle article = news.ElementAt(i);
                    this.latestSearchResult.Add(new NewsAndSentimentScore {
                        Article = article, TitleSentiment = Math.Round(sentiment.Scores.ElementAt(i), 2)
                    });
                }

                UpdateFilteredResults();

                this.sentimentDistributionControl.UpdateData(this.latestSearchResult.Select(n => n.TitleSentiment));

                var wordGroups = keyPhrasesTask.Result.KeyPhrases.SelectMany(k => k).GroupBy(phrase => phrase, StringComparer.OrdinalIgnoreCase).OrderByDescending(g => g.Count()).Take(10).OrderBy(g => g.Key);
                this.TopKeyPhrases.AddRange(wordGroups.Select(g => new KeyPhraseCount {
                    KeyPhrase = g.Key, Count = g.Count()
                }));
            }
            catch (HttpRequestException ex)
            {
                await Util.GenericApiCallExceptionHandler(ex, "Processing error");
            }
            finally
            {
                this.progressRing.IsActive = false;
            }
        }
示例#5
0
 public Form1()
 {
     InitializeComponent();
     speechConfig        = SpeechConfig.FromSubscription(subscriptionKey, speechRegion);
     recognizer          = new SpeechRecognizer(speechConfig);
     stopRecognition     = new TaskCompletionSource <int>();
     textAnalyticsHelper = new TextAnalyticsHelper(textAnalyticsEndpoint, textAnalyticsKey);
 }
示例#6
0
        private async Task GetKeyPhrasesAsync()
        {
            try
            {
                KeyPhrasesResult keyPhrasesResult = await TextAnalyticsHelper.GetKeyPhrasesAsync(this.CallerTextBox.Text);

                this.KeyPhrases.AddRange(keyPhrasesResult.KeyPhrases.OrderBy(i => i));
            }
            catch (Exception ex)
            {
                await Util.GenericApiCallExceptionHandler(ex, "Error during Text Analytics 'Key Phrases' call.");
            }
        }
示例#7
0
        public Startup(IWebHostEnvironment env, ILoggerFactory loggerFactory)
        {
            var builder = new ConfigurationBuilder()
                          .SetBasePath(env.ContentRootPath)
                          .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
                          .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
                          .AddJsonFile("cognitivemodels.json", optional: true)
                          .AddJsonFile($"cognitivemodels.{env.EnvironmentName}.json", optional: true)
                          .AddEnvironmentVariables();

            Configuration = builder.Build();

            DBHelper.Configuration = Configuration;
            TextAnalyticsHelper.Configure(Configuration);
            JournalHelper.Configure(Configuration);
            TokensController.Configuration = Configuration;
            GraphHelper.Configure(Configuration);
            this.HostingEnvironment = env;
        }
示例#8
0
        private async Task DetectLanguageAsync()
        {
            try
            {
                if (!string.IsNullOrEmpty(this.speechRecognitionTextBox.Text))
                {
                    DetectLanguageResult textDetectResult = await TextAnalyticsHelper.GetDetectedLanguageAsync(this.speechRecognitionTextBox.Text);

                    this.detectedLanguage = new string[] { textDetectResult.Language["iso6391Name"], textDetectResult.Language["name"] };
                }
                else
                {
                    this.detectedLanguage = new string[] { "en", string.Empty };
                }
            }
            catch (Exception ex)
            {
                await Util.GenericApiCallExceptionHandler(ex, "Error during Text Analytics 'Detect' call.");
            }
        }
示例#9
0
        private async Task AnalyzeTextAsync()
        {
            try
            {
                if (!string.IsNullOrEmpty(this.speechRecognitionTextBox.Text))
                {
                    SentimentResult textAnalysisResult = await TextAnalyticsHelper.GetTextSentimentAsync(this.translatedText, this.detectedLanguage[0]);

                    this.sentimentControl.Sentiment = textAnalysisResult.Score;
                }
                else
                {
                    this.sentimentControl.Sentiment = 0.5;
                }

                this.OnSpeechRecognitionAndSentimentProcessed(new SpeechRecognitionAndSentimentResult {
                    SpeechRecognitionText = this.speechRecognitionTextBox.Text, TextAnalysisSentiment = this.sentimentControl.Sentiment, DetectedLanguage = this.detectedLanguage[1], TranslatedText = this.translatedText
                });
            }
            catch (Exception ex)
            {
                await Util.GenericApiCallExceptionHandler(ex, "Error during Text Analytics 'Sentiment' call.");
            }
        }
        //DelegateCommand _ShowBusyCommand;
        //public DelegateCommand ShowBusyCommand
        //    => _ShowBusyCommand ?? (_ShowBusyCommand = new DelegateCommand(async () =>
        //    {
        //        Views.Busy.SetBusy(true, _BusyText);
        //        await Task.Delay(5000);
        //        Views.Busy.SetBusy(false);
        //    }, () => !string.IsNullOrEmpty(BusyText)));

        public async Task GotoDetailsPage()
        {
            Views.Busy.SetBusy(true, "Getting your score...");
            UnconsciousBiasResult result = null;
            var graphClient = await AuthenticationHelper.GetAuthenticatedClientAsync();

            if (graphClient != null)
            {
                var emails = await graphClient.Me
                             .Messages
                             .Request()
                             .Search($"\"to:{Value}\"")
                             .Select("UniqueBody")
                             .GetAsync();

                StringBuilder sb = new StringBuilder();
                sb.Append("{\"documents\":[");
                int i = 1;
                foreach (var email in emails)
                {
                    Debug.WriteLine(email.UniqueBody);

                    // This is super-hacky processing out the HTML tags from the email.
                    // TODO: replace this with a proper library that will do this better.
                    string body = email.UniqueBody.Content;
                    string bodyWithoutHTMLtags = WebUtility.HtmlDecode(Regex.Replace(body, "<[^>]*(>|$)", string.Empty));
                    string step2 = Regex.Replace(bodyWithoutHTMLtags, @"[\s\r\n]+", " ");
                    sb.Append("{\"id\":\"" + i + "\",\"text\":\"" + step2 + "\"},");
                    i++;
                }

                // Remove the trailing comma to get well-formatted JSON
                string tempString = sb.ToString();
                if (tempString.LastIndexOf(",") == tempString.Length - 1)
                {
                    sb.Remove(tempString.Length - 1, 1);
                }

                // Close JSON message
                sb.Append("]}");

                List <double> sentimentScores = await TextAnalyticsHelper.GetSentiment(sb.ToString());

                // Calculate average sentiment score
                double scoreSum   = 0.0;
                int    scoreCount = 0;
                foreach (double sentimentScore in sentimentScores)
                {
                    scoreSum += sentimentScore;
                    scoreCount++;
                }
                double averageSentimentScore = scoreSum / scoreCount;
                int    sentimentPercentage   = Convert.ToInt32(averageSentimentScore * 100);

                result = new UnconsciousBiasResult()
                {
                    Positivity      = sentimentPercentage,
                    KeyWords        = "TODO",
                    Topics          = "TODO",
                    PositivityGraph = sentimentScores,
                    Person          = Value
                };
            }

            // can pass value to other screen and do fancy display
            NavigationService.Navigate(typeof(Views.DetailPage), result);

            await Task.CompletedTask;
        }
        private async Task <AnalyzeTextResult> AnalyzeNewsAsync(IEnumerable <NewsArticle> news, string userLanguage)
        {
            var scores        = new List <double>();
            var topKeyPhrases = new List <KeyPhraseCount>();

            // prepare news titles to text string
            string[] newsTitleList     = news.Select(n => n.Title.Replace(".", ";")).ToArray();
            string   newsTitles        = string.Join(". ", newsTitleList);
            var      strInfo           = new StringInfo(newsTitles);
            int      lenInTextElements = strInfo.LengthInTextElements;

            // check Text Analytics data limits
            string languageCode = GetTextAnalyticsLanguageCodeFromLanguage(userLanguage);
            bool   isLangSupportedForKeyPhrases = IsLanguageSupportedByKeyPhraseAPI(userLanguage);

            if (lenInTextElements < TextAnalyticsHelper.MaximumLengthOfTextDocument)
            {
                Task <DocumentSentiment>   sentimentTask  = TextAnalyticsHelper.AnalyzeSentimentAsync(newsTitles, languageCode);
                Task <KeyPhraseCollection> keyPhrasesTask = isLangSupportedForKeyPhrases ? TextAnalyticsHelper.ExtractKeyPhrasesAsync(newsTitles, languageCode) : Task.FromResult <KeyPhraseCollection>(null);
                await Task.WhenAll(sentimentTask, keyPhrasesTask);

                var sentimentResult  = sentimentTask.Result;
                var keyPhrasesResult = keyPhrasesTask.Result;

                scores = sentimentResult.Sentences.Select(s => GetSentimentScore(s)).ToList();
                var wordGroups = keyPhrasesResult?.GroupBy(phrase => phrase, StringComparer.OrdinalIgnoreCase).OrderByDescending(g => g.Count()).Take(10).OrderBy(g => g.Key).ToList();
                topKeyPhrases = wordGroups != null && wordGroups.Any()
                    ? wordGroups.Select(w => new KeyPhraseCount {
                    KeyPhrase = w.Key, Count = w.Count()
                }).ToList()
                    : new List <KeyPhraseCount>()
                {
                    new KeyPhraseCount {
                        KeyPhrase = "Not available in this language", Count = 1
                    }
                };
            }
            else
            {
                // if the input data is larger than max limit then split the input data into several different requests
                var sentimentTaskList  = new List <Task <AnalyzeSentimentResultCollection> >();
                var keyPhrasesTaskList = new List <Task <ExtractKeyPhrasesResultCollection> >();

                int maxDocsPerRequest = Math.Min(TextAnalyticsHelper.MaxDocumentsPerRequestForSentimentAnalysis, TextAnalyticsHelper.MaxDocumentsPerRequestForKeyPhraseExtraction);
                int batchSize         = Math.Min((int)Math.Ceiling((decimal)TotalNewsCount / maxDocsPerRequest), maxDocsPerRequest);
                for (int i = 0; i < TextAnalyticsHelper.MaxRequestsPerSecond; i++)
                {
                    int      skip            = i * batchSize;
                    string[] newsTitlesBatch = newsTitleList.Skip(skip).Take(batchSize).ToArray();
                    if (!newsTitlesBatch.Any())
                    {
                        break;
                    }

                    sentimentTaskList.Add(TextAnalyticsHelper.AnalyzeSentimentAsync(newsTitlesBatch, languageCode));
                    if (isLangSupportedForKeyPhrases)
                    {
                        keyPhrasesTaskList.Add(TextAnalyticsHelper.ExtractKeyPhrasesAsync(newsTitlesBatch, languageCode));
                    }
                }

                var taskList = new List <Task>();
                taskList.AddRange(sentimentTaskList);
                taskList.AddRange(keyPhrasesTaskList);
                await Task.WhenAll(taskList);

                foreach (var sentimentTask in sentimentTaskList)
                {
                    AnalyzeSentimentResultCollection sentimentResult = sentimentTask.Result;
                    scores.AddRange(sentimentResult.SelectMany(d => d.DocumentSentiment.Sentences).Select(s => GetSentimentScore(s)).ToList());
                }

                var keyPhrasesList = new List <string>();
                foreach (var keyPhrasesTask in keyPhrasesTaskList)
                {
                    ExtractKeyPhrasesResultCollection keyPhrasesResult = keyPhrasesTask.Result;
                    keyPhrasesList.AddRange(keyPhrasesResult.SelectMany(k => k.KeyPhrases));
                }

                var wordGroups = keyPhrasesList.GroupBy(phrase => phrase, StringComparer.OrdinalIgnoreCase).OrderByDescending(g => g.Count()).Take(10).OrderBy(g => g.Key).ToList();
                topKeyPhrases = wordGroups.Any()
                    ? wordGroups.Select(w => new KeyPhraseCount {
                    KeyPhrase = w.Key, Count = w.Count()
                }).ToList()
                    : new List <KeyPhraseCount>()
                {
                    new KeyPhraseCount {
                        KeyPhrase = "Not available in this language", Count = 1
                    }
                };
            }

            return(new AnalyzeTextResult
            {
                Scores = scores,
                TopKeyPhrases = topKeyPhrases
            });
        }
        /// <summary>
        /// Logs an incoming message to the Bot. Core channel information is stored along with the original message and sentiment.
        /// Logs an event called "BotMessageReceived".
        /// Logs the following properties: conversation id, from user id, conversation name, channel id, client info.
        /// Other info logged based on configuration: from user name, original message, sentiment.
        /// </summary>
        /// <param name="activity">The incoming Activity from the Bot Framework.</param>
        /// <param name="additionalProperties">Additional properties to log.</param>
        public void LogIncomingMessage(ITurnContext context, Dictionary <string, string> additionalProperties = null)
        {
            // Simple guard statements
            EnsureNotNull(context, "Context activity cannot be null");

            // Track the event with an exception wrapper
            TrackEventWithExceptionWrapper((TelemetryClient tc) =>
            {
                var activity = context.Activity.AsMessageActivity();
                Dictionary <string, string> telemetryProperties = new Dictionary <string, string>();

                // Set the Telemetry context as we don't have a BF Telemetry Initializer at this time...
                if (!string.IsNullOrEmpty(activity.Conversation.Id))
                {
                    tc.Context.Session.Id = activity.Conversation.Id;
                }

                if (!string.IsNullOrEmpty(activity.From.Id))
                {
                    tc.Context.User.Id = activity.From.Id;
                }

                // General message metadata, defensive to cover for discrepancies across channels
                if (!string.IsNullOrEmpty(activity.ChannelId))
                {
                    telemetryProperties.Add(TelemetryHelper.ChannelProperty, activity.ChannelId);
                }

                if (!string.IsNullOrEmpty(activity.From.Id))
                {
                    telemetryProperties.Add(TelemetryHelper.FromIdProperty, activity.From.Id);
                }

                if (!string.IsNullOrEmpty(activity.Conversation.Id))
                {
                    telemetryProperties.Add(TelemetryHelper.ConversationIdProperty, activity.Conversation.Id);
                }

                if (!string.IsNullOrEmpty(activity.Conversation.Name))
                {
                    telemetryProperties.Add(TelemetryHelper.ConversationNameProperty, activity.Conversation.Name);
                }

                if (additionalProperties != null)
                {
                    foreach (KeyValuePair <string, string> valuePair in additionalProperties)
                    {
                        if (telemetryProperties.ContainsKey(valuePair.Key))
                        {
                            telemetryProperties[valuePair.Key] = valuePair.Value;
                        }
                        else
                        {
                            telemetryProperties.Add(valuePair.Key, valuePair.Value);
                        }
                    }
                }

                // Now check for specific entities such as client info...
                if (activity.Entities != null)
                {
                    // Do we have any client info? e.g. language, locale, device type
                    var clientEntity = activity.Entities.FirstOrDefault(e => e.Type == TelemetryHelper.ClientInfoIdentifier);

                    if (clientEntity != null && clientEntity.Properties != null)
                    {
                        string prop = clientEntity.Properties.ToString();
                        telemetryProperties.Add(TelemetryHelper.ClientInfoProperty, prop);
                    }
                }

                // For some customers, logging user name within Application Insights might be an issue so have provided a config setting to disable this feature
                if (logUserName && !string.IsNullOrEmpty(activity.From.Name))
                {
                    telemetryProperties.Add(TelemetryHelper.FromNameProperty, activity.From.Name);
                }

                // For some customers, logging the utterances within Application Insights might be an so have provided a config setting to disable this feature
                if (logOriginalMessages && !string.IsNullOrEmpty(activity.Text))
                {
                    telemetryProperties.Add(TelemetryHelper.TextProperty, activity.Text);
                }

                // Only perform Text Analytics operations if we have a valid key and log sentiment is set to true
                if (!string.IsNullOrEmpty(textAnalyticsKey) && logSentimentAndKeyPhrases && !string.IsNullOrEmpty(activity.Text))
                {
                    try
                    {
                        // Crude but gets a good sense of the utterance length.
                        // NOTE: before splitting, replace multiple instances of spaces with a single space
                        // and trim either end, so that we do not skew the amount of words in the trimmed list.
                        string modifiedText = Regex.Replace(activity.Text, @"\s+", " ").Trim();
                        string[] words      = activity.Text.Split(' ');

                        // Sentiment and Key Phrase extraction is not effective on short utterances so we skip if less than the provided threshold
                        if (words.Length >= sentimentWordThreshold)
                        {
                            // For each utterance we identify the language in order to then extract key-phrases and sentiment which is addded to the Telemetry
                            // LUIS now performs Key Phrase Extraction and Sentiment for you but not exposed as part of the v4SDK, once fixed this can be removed.
                            var(identifiedLanguage, keyPhrases, sentiment) = TextAnalyticsHelper.EvaluateUtterance(textAnalyticsClient, activity.Text);

                            if (!string.IsNullOrEmpty(identifiedLanguage))
                            {
                                telemetryProperties.Add(TelemetryHelper.LanguageProperty, identifiedLanguage);
                            }

                            if (!string.IsNullOrEmpty(keyPhrases))
                            {
                                telemetryProperties.Add(TelemetryHelper.KeyPhrasesProperty, keyPhrases);
                            }

                            if (sentiment != int.MinValue)
                            {
                                string sentimentScore = sentiment.ToString("N2");
                                telemetryProperties.Add(TelemetryHelper.SentimentProperty, sentimentScore);
                            }
                        }
                        else
                        {
                            tc.TrackTrace($"TelemetryHelper::LogIncomingMessage::No sentiment calculated for a utterance with {words.Length} word(s).");
                        }
                    }
                    catch (Exception e)
                    {
                        tc.TrackException(e);
                        tc.TrackTrace($"TelemetryHelper::Exception ocurred whilst calculating sentiment - skipping but still logging without it. {e.Message}");
                    }
                }

                // Log the event
                tc.TrackEvent(TelemetryHelper.BotMessageReceivedEvent, telemetryProperties);
            });
        }
        private async Task AnalyzeTextAsync()
        {
            try
            {
                this.progressControl.IsActive = true;
                DisplayProcessingUI();

                string input = this.inputText.Text;
                var    detectedLanguageTask       = TextAnalyticsHelper.DetectLanguageAsync(input);
                var    detectedKeyPhrasesTask     = TextAnalyticsHelper.ExtractKeyPhrasesAsync(input);
                var    documentSentimentTask      = TextAnalyticsHelper.AnalyzeSentimentAsync(input, sentimentAnalyses: AdditionalSentimentAnalyses.OpinionMining);
                var    namedEntitiesResponseTask  = TextAnalyticsHelper.RecognizeEntitiesAsync(input);
                var    linkedEntitiesResponseTask = TextAnalyticsHelper.RecognizeLinkedEntitiesAsync(input);

                await Task.WhenAll(detectedLanguageTask, detectedKeyPhrasesTask, documentSentimentTask, namedEntitiesResponseTask, linkedEntitiesResponseTask);

                var detectedLanguage       = detectedLanguageTask.Result;
                var detectedKeyPhrases     = detectedKeyPhrasesTask.Result;
                var documentSentiment      = documentSentimentTask.Result;
                var namedEntitiesResponse  = namedEntitiesResponseTask.Result;
                var linkedEntitiesResponse = linkedEntitiesResponseTask.Result;

                // detected language and key phrases
                this.detectedLangTextBlock.Text       = !string.IsNullOrEmpty(detectedLanguage.Name) ? $"{detectedLanguage.Name} (confidence: {(int)(detectedLanguage.ConfidenceScore * 100)}%)" : "Not found";
                this.detectedKeyPhrasesTextBlock.Text = detectedKeyPhrases.Any() ? string.Join(", ", detectedKeyPhrases) : "Not found";

                // document sentiment
                CreateSentimentChart(documentSentiment);

                // mined opinions
                OpinionMiningCollection.Clear();
                var minedOpinions = documentSentiment?.Sentences.SelectMany(s => s.MinedOpinions);
                if (minedOpinions != null && minedOpinions.Any())
                {
                    var minedOpinionList = minedOpinions.Select(om => new MinedOpinion()
                    {
                        Aspect   = om.Aspect.Text,
                        Opinions = string.Join(", ", om.Opinions.Select(o => $"{o.Text} ({o.Sentiment.ToString("G")})"))
                    });
                    OpinionMiningCollection.AddRange(minedOpinionList);
                }

                // entities
                if (namedEntitiesResponse.Any())
                {
                    this.namesEntitiesGridView.ItemsSource = namedEntitiesResponse.Select(x => new { x.Text, Category = $"[{x.Category}]" });
                }
                else
                {
                    this.namesEntitiesGridView.ItemsSource = new[] { new { Text = "No entities" } };
                }

                // linked entities
                if (linkedEntitiesResponse.Any())
                {
                    this.linkedEntitiesGridView.ItemsSource = linkedEntitiesResponse.Select(x => new { Name = $"{x.Name} ({x.DataSource})", x.Url });
                }
                else
                {
                    this.linkedEntitiesGridView.ItemsSource = new[] { new { Name = "No linked entities" } };
                }

                // prepare json result
                var jsonResult = new
                {
                    LanguageDetection = detectedLanguage,
                    KeyPhrases        = detectedKeyPhrases,
                    Sentiment         = documentSentiment,
                    Entities          = namedEntitiesResponse,
                    EntityLinking     = linkedEntitiesResponse
                };
                this.jsonResultTextBlock.Text = JsonConvert.SerializeObject(jsonResult, Formatting.Indented);
            }
            catch (Exception ex)
            {
                await Util.GenericApiCallExceptionHandler(ex, "Failure analyzing text");
            }
            finally
            {
                this.progressControl.IsActive = false;
            }
        }
        private async Task AnalyzeTextAsync()
        {
            try
            {
                this.progressControl.IsActive = true;
                DisplayProcessingUI();

                // detect language
                string           input            = this.inputText.Text;
                DetectedLanguage detectedLanguage = await TextAnalyticsHelper.DetectLanguageAsync(input);

                string languageCode = TextAnalyticsHelper.GetLanguageCode(detectedLanguage);

                // check supported languages
                bool isOpinionMiningSupported = TextAnalyticsHelper.OpinionMiningSupportedLanguages.Any(l => string.Equals(l, languageCode, StringComparison.OrdinalIgnoreCase));
                bool isSentimentSupported     = TextAnalyticsHelper.SentimentAnalysisSupportedLanguages.Any(l => string.Equals(l, languageCode, StringComparison.OrdinalIgnoreCase));
                bool isKeyPhraseSupported     = TextAnalyticsHelper.KeyPhraseExtractionSupportedLanguages.Any(l => string.Equals(l, languageCode, StringComparison.OrdinalIgnoreCase));
                bool isNamedEntitySupported   = TextAnalyticsHelper.NamedEntitySupportedLanguages.Any(l => string.Equals(l, languageCode, StringComparison.OrdinalIgnoreCase));
                bool isEntityLinkingSupported = TextAnalyticsHelper.EntityLinkingSupportedLanguages.Any(l => string.Equals(l, languageCode, StringComparison.OrdinalIgnoreCase));

                // sentiment analysis, key phrase extraction, named entity recognition and entity linking
                Task <DocumentSentiment>           documentSentimentTask      = isSentimentSupported ? TextAnalyticsHelper.AnalyzeSentimentAsync(input, languageCode, isOpinionMiningSupported) : Task.FromResult <DocumentSentiment>(null);
                Task <KeyPhraseCollection>         detectedKeyPhrasesTask     = isKeyPhraseSupported ? TextAnalyticsHelper.ExtractKeyPhrasesAsync(input, languageCode) : Task.FromResult <KeyPhraseCollection>(null);
                Task <CategorizedEntityCollection> namedEntitiesResponseTask  = isNamedEntitySupported ? TextAnalyticsHelper.RecognizeEntitiesAsync(input, languageCode) : Task.FromResult <CategorizedEntityCollection>(null);
                Task <LinkedEntityCollection>      linkedEntitiesResponseTask = isEntityLinkingSupported ? TextAnalyticsHelper.RecognizeLinkedEntitiesAsync(input, languageCode) : Task.FromResult <LinkedEntityCollection>(null);

                await Task.WhenAll(documentSentimentTask, detectedKeyPhrasesTask, namedEntitiesResponseTask, linkedEntitiesResponseTask);

                DocumentSentiment           documentSentiment      = documentSentimentTask.Result;
                KeyPhraseCollection         detectedKeyPhrases     = detectedKeyPhrasesTask.Result;
                CategorizedEntityCollection namedEntitiesResponse  = namedEntitiesResponseTask.Result;
                LinkedEntityCollection      linkedEntitiesResponse = linkedEntitiesResponseTask.Result;

                // display results
                this.detectedLangTextBlock.Text = !string.IsNullOrEmpty(detectedLanguage.Name) ? $"{detectedLanguage.Name} (confidence: {(int)(detectedLanguage.ConfidenceScore * 100)}%)" : NotFound;

                this.detectedKeyPhrasesTextBlock.Text = detectedKeyPhrases != null && detectedKeyPhrases.Any()
                    ? string.Join(", ", detectedKeyPhrases)
                    : isKeyPhraseSupported?NotFound : LanguageNotSupported;

                this.namesEntitiesGridView.ItemsSource = namedEntitiesResponse != null && namedEntitiesResponse.Any()
                    ? namedEntitiesResponse.Select(x => new { x.Text, Category = $"[{x.Category}]" })
                    : new[] { new { Text = isNamedEntitySupported ? "No entities" : LanguageNotSupported, Category = "" } };

                this.linkedEntitiesGridView.ItemsSource = linkedEntitiesResponse != null && linkedEntitiesResponse.Any()
                    ? linkedEntitiesResponse.Select(x => new { Name = $"{x.Name} ({x.DataSource})", x.Url })
                    : new[] {
                    isEntityLinkingSupported
                        ? new { Name = "No linked entities", Url = new Uri("about:blank") }
                        : new { Name = LanguageNotSupported, Url = TextAnalyticsHelper.LanguageSupportUri }
                };

                if (isSentimentSupported)
                {
                    CreateSentimentChart(documentSentiment);

                    // mined opinions
                    OpinionMiningCollection.Clear();
                    var minedOpinions = documentSentiment?.Sentences.SelectMany(s => s.MinedOpinions);
                    if (minedOpinions != null && minedOpinions.Any())
                    {
                        var minedOpinionList = minedOpinions.Select(om => new MinedOpinion()
                        {
                            Aspect   = om.Aspect.Text,
                            Opinions = string.Join(", ", om.Opinions.Select(o => $"{o.Text} ({o.Sentiment.ToString("G")})"))
                        });
                        OpinionMiningCollection.AddRange(minedOpinionList);
                    }
                }
                else
                {
                    this.sentimentTextBlock.Text   = LanguageNotSupported;
                    this.sentimentChart.Visibility = Visibility.Collapsed;
                }

                // prepare json result
                var jsonResult = new
                {
                    LanguageDetection = detectedLanguage,
                    KeyPhrases        = detectedKeyPhrases,
                    Sentiment         = documentSentiment,
                    Entities          = namedEntitiesResponse,
                    EntityLinking     = linkedEntitiesResponse
                };
                this.jsonResultTextBlock.Text = JsonConvert.SerializeObject(jsonResult, Formatting.Indented);
            }
            catch (Exception ex)
            {
                await Util.GenericApiCallExceptionHandler(ex, "Failure analyzing text");
            }
            finally
            {
                this.progressControl.IsActive = false;
            }
        }
示例#15
0
        private async Task <DialogTurnResult> CheckTodaysEntry(WaterfallStepContext stepContext, CancellationToken cancellationToken)
        {
            await PopulateStateObjects(stepContext);

            _graphHelper.Authenticate();

            var section      = stepContext.Values["Section"] as OnenoteSection;
            var contextId    = _discussionState.SignedInUserId;
            var currentPages = await _graphHelper.GetNotebookPagesInSection(section);

            DateTime entryDate = DateTime.Today;

            List <JournalPageMetadata> journalPages = new List <JournalPageMetadata>();
            int currentDay  = entryDate.Day;
            int daysInMonth = DateTime.DaysInMonth(entryDate.Year, entryDate.Month);
            int year        = entryDate.Year;
            int month       = entryDate.Month;
            List <JournalEntry> userEntries = DBHelper.GetJournalEntries(contextId,
                                                                         new DateTime(year, month, 1),
                                                                         new DateTime(year, month, daysInMonth));

            var invalidEntries = new KeyValuePair <string, List <string> >(
                contextId, new List <string>());

            // Remove pages that do not exist in the current pages collection
            for (int i = userEntries.Count - 1; i >= 0; i--)
            {
                var expectedPage = userEntries[i];
                if (!currentPages.Exists(ce => ce.Id == expectedPage.Id))
                {
                    invalidEntries.Value.Add(expectedPage.Id);
                    userEntries.Remove(expectedPage);
                }
            }
            if (invalidEntries.Value.Count > 0)
            {
                DBHelper.RemoveInvalidJournalEntries(invalidEntries);
            }

            var sentimentNeeded = userEntries.Where(j => {
                var cp = currentPages.First(p => p.Id == j.Id);
                return(
                    (j.Sentiment == null) ||
                    ((j.Sentiment != null) &&
                     (cp.LastModifiedDateTime > j.LastModified)));
            }).ToList();

            if (sentimentNeeded.Count > 0)
            {
                var sentimentDocuments = new Dictionary <String, TextDocumentInput[]>();
                foreach (var item in sentimentNeeded)
                {
                    var prompt = "Checking out your" +
                                 (item.Sentiment != null ? " updated" : "") +
                                 $" entry for {item.EntryDate.ToLongDateString()}";
                    await stepContext.Context.SendActivityAsync(MessageFactory.Text(prompt));

                    string content = await _graphHelper.GetNotebookPageContent(item.Id);

                    HtmlDocument doc = new HtmlDocument();
                    doc.LoadHtml(content);
                    var body      = doc.DocumentNode.SelectSingleNode("//body");
                    var divHeader = doc.DocumentNode.SelectSingleNode("//div[@data-id='_default']");

                    var paragraphs     = new List <String>();
                    var paragraphNodes = divHeader.SelectNodes(".//p");
                    if (paragraphNodes?.Count > 0)
                    {
                        paragraphs.AddRange(paragraphNodes.Select(p => p.InnerText).ToArray());
                    }

                    var remainingHtml = body.InnerHtml.Replace(divHeader.OuterHtml, "");
                    var remainingDoc  = new HtmlDocument();
                    remainingDoc.LoadHtml(remainingHtml);

                    paragraphNodes = remainingDoc.DocumentNode.SelectNodes("//p");
                    if (paragraphNodes?.Count > 0)
                    {
                        paragraphs.AddRange(paragraphNodes.Select(p => p.InnerText).ToArray());
                    }

                    if (paragraphs.Count > 0)
                    {
                        var combinedText = System.Web.HttpUtility.HtmlDecode(String.Join("\n", paragraphs));
                        AddInputDocument(sentimentDocuments, item.Id, combinedText);
                        prompt = "That's new.. I'll have to consider what you wrote.";
                    }
                    else
                    {
                        prompt = "Nothing new for me to check out here!";
                    }
                    await stepContext.Context.SendActivityAsync(MessageFactory.Text(prompt));
                }

                if (sentimentDocuments.Count > 0)
                {
                    await stepContext.Context.SendActivityAsync(MessageFactory.Text(
                                                                    "Assessing what you wrote..."));
                }

                var sentimentResults = TextAnalyticsHelper.GetSentiment(sentimentDocuments);
                foreach (var entryKey in sentimentResults.Keys)
                {
                    var assessedPage = currentPages.First(e => e.Id == entryKey);
                    var lastModified = assessedPage.LastModifiedDateTime;
                    var ds           = sentimentResults[entryKey];
                    DBHelper.SaveJournalEntryAssessment(new JournalEntryAssessment
                    {
                        Id           = entryKey,
                        Sentiment    = ds,
                        LastModified = lastModified?.UtcDateTime
                    });

                    var prompt = $"Your entry on {assessedPage.Title} was {ds.Sentiment}";
                    await stepContext.Context.SendActivityAsync(MessageFactory.Text(prompt));
                }
            }

            var         monthMode   = false;
            var         createdPage = false;
            OnenotePage currentPage = null;
            var         pageId      = String.Empty;

            //Month mode
            if (monthMode)
            {
                for (int i = currentDay; i <= daysInMonth; i++)
                {
                    DateTime current = new DateTime(year, month, i);
                    if (!userEntries.Exists(e => e.EntryDate == current))
                    {
                        journalPages.Add(new JournalPageMetadata(current));
                    }
                }
            }
            else
            {
                await stepContext.Context.SendActivityAsync(MessageFactory.Text(
                                                                "Looking for today's journal entry"));

                var existingPage = userEntries.FirstOrDefault(e => e.EntryDate == entryDate);
                if (existingPage == null)
                {
                    await stepContext.Context.SendActivityAsync(MessageFactory.Text(
                                                                    "Hmmm... didn't find today's entry. Don't worry I'll create one for you."));

                    journalPages.Add(new JournalPageMetadata(entryDate));
                }
                else
                {
                    pageId = existingPage.Id;
                    await stepContext.Context.SendActivityAsync(MessageFactory.Text(
                                                                    "Found it!"));
                }
            }

            if (String.IsNullOrEmpty(pageId))
            {
                var weeks        = journalPages.GroupBy(p => p.Week).ToList();
                var pageTemplate = ResourceHelper
                                   .ReadManifestData <JournalingDialog>("JournalPageTemplate.htm");
                var headerPageTemplate = ResourceHelper
                                         .ReadManifestData <JournalingDialog>("JournalHeaderTemplate.htm");

                foreach (var grp in weeks)
                {
                    var headerPageTitle = $"Week {grp.Key}";
                    var headerEntryDate = entryDate.ToString("yyyy-MM-ddTHH:mm:ss.0000000");
                    Console.Write($" {headerPageTitle} ");
                    var headerPage = currentPages.FirstOrDefault(p => p.Title == headerPageTitle);

                    if (headerPage == null)
                    {
                        var headerHtml   = String.Format(headerPageTemplate, headerPageTitle, headerEntryDate);
                        var headerPageId = await _graphHelper.CreateNotebookPage(section.Id, headerHtml);

                        Console.WriteLine(headerPageId);
                    }
                    else
                    {
                        Console.WriteLine(headerPage.Id);
                    }

                    foreach (var item in grp)
                    {
                        var jp = DBHelper.GetJournalPrompt();

                        var pageTitle = $"{item.DayOfWeek} the {item.Day.AsOrdinal()}";
                        Console.Write($"\t{pageTitle} ");
                        var newEntryDate = item.EntryDate.ToString("yyyy-MM-ddTHH:mm:ss.0000000");

                        var prompt       = jp.Prompt;
                        var details      = jp.Details;
                        var promptSource = jp.Source;

                        var html = String.Format(pageTemplate, pageTitle, newEntryDate,
                                                 prompt, details, promptSource,
                                                 entryDate.Ticks, jp.SourceIndex, jp.PromptIndex);

                        currentPage = await _graphHelper.CreateNotebookPage(section.Id, html);

                        pageId      = currentPage.Id;
                        createdPage = true;
                        var je = new JournalEntry
                        {
                            UserContextId  = contextId,
                            Id             = pageId,
                            PromptSourceId = jp.SourceIndex,
                            PromptIndexId  = jp.PromptIndex,
                            EntryDate      = item.EntryDate
                        };
                        DBHelper.CreateJournalEntry(je);
                        await _graphHelper.UpdateNotebookPageLevel(pageId, 1);

                        await stepContext.Context.SendActivityAsync(MessageFactory.Text(
                                                                        "All done setting up today's entry for you!. Ping me when you want me to take a look."));

                        Console.WriteLine($"{pageId}");
                    }
                }
            }

            if ((currentPage == null) && !String.IsNullOrEmpty(pageId))
            {
                currentPage = await _graphHelper.GetNotebookPage(pageId);
            }
            AddUpdateStepContextValue(stepContext, "CurrentPage", currentPage);
            return(await stepContext.NextAsync(null, cancellationToken));
        }