/// <summary>
        /// Submits text analytics requests depending on the settings (sentimentAnalysisSetting). Every utterance will be submitted independently to text analytics.
        /// (This means for instance that every utterance will have a separate sentiment score).
        /// </summary>
        /// <param name="speechTranscript">The speech transcript object.</param>
        /// <param name="sentimentAnalysisSetting">The sentiment analysis setting.</param>
        /// <returns>The job ids and errors, if any were found.</returns>
        public async Task <(IEnumerable <string> jobIds, IEnumerable <string> errors)> SubmitUtteranceLevelRequests(
            SpeechTranscript speechTranscript,
            SentimentAnalysisSetting sentimentAnalysisSetting)
        {
            speechTranscript = speechTranscript ?? throw new ArgumentNullException(nameof(speechTranscript));

            if (sentimentAnalysisSetting != SentimentAnalysisSetting.UtteranceLevel)
            {
                return(new List <string>(), new List <string>());
            }

            var documents = speechTranscript.RecognizedPhrases.Where(r => r.NBest.FirstOrDefault() != null && !string.IsNullOrEmpty(r.NBest.First().Display)).Select(r => new TextDocumentInput($"{r.Channel}_{r.Offset}", r.NBest.First().Display)
            {
                Language = Locale
            });

            var actions = new TextAnalyticsActions
            {
                DisplayName             = "IngestionClient",
                AnalyzeSentimentActions = new List <AnalyzeSentimentAction>()
                {
                    new AnalyzeSentimentAction()
                }
            };

            return(await SubmitDocumentsAsync(documents, actions).ConfigureAwait(false));
        }
        /// <summary>
        /// Submits text analytics requests depending on the settings (sentimentAnalysisSetting). The whole transcript (per channel) will be submitted in a single request.
        /// (This means for instance that one single sentiment score will be generated per channel).
        /// </summary>
        /// <param name="speechTranscript">The speech transcript object.</param>
        /// <param name="sentimentAnalysisSetting">The sentiment analysis setting.</param>
        /// <param name="piiRedactionSetting">The PII redaction setting.</param>
        /// <returns>The job ids and errors, if any were found.</returns>
        public async Task <(IEnumerable <string> jobIds, IEnumerable <string> errors)> SubmitAudioLevelRequests(
            SpeechTranscript speechTranscript,
            SentimentAnalysisSetting sentimentAnalysisSetting,
            PiiRedactionSetting piiRedactionSetting)
        {
            speechTranscript = speechTranscript ?? throw new ArgumentNullException(nameof(speechTranscript));

            if (sentimentAnalysisSetting != SentimentAnalysisSetting.AudioLevel && piiRedactionSetting != PiiRedactionSetting.UtteranceAndAudioLevel)
            {
                return(new List <string>(), new List <string>());
            }

            var documents = speechTranscript.CombinedRecognizedPhrases.Where(r => !string.IsNullOrEmpty(r.Display)).Select(r => new TextDocumentInput($"{r.Channel}", r.Display)
            {
                Language = Locale
            });

            var actions = new TextAnalyticsActions
            {
                DisplayName = "IngestionClient"
            };

            if (sentimentAnalysisSetting == SentimentAnalysisSetting.AudioLevel)
            {
                actions.AnalyzeSentimentActions = new List <AnalyzeSentimentAction>()
                {
                    new AnalyzeSentimentAction()
                };
            }

            if (piiRedactionSetting == PiiRedactionSetting.UtteranceAndAudioLevel)
            {
                var action = new RecognizePiiEntitiesAction();

                if (!string.IsNullOrEmpty(FetchTranscriptionEnvironmentVariables.PiiCategories))
                {
                    var piiEntityCategories = FetchTranscriptionEnvironmentVariables.PiiCategories.Split(",").Select(c => new PiiEntityCategory(c));

                    foreach (var category in piiEntityCategories)
                    {
                        action.CategoriesFilter.Add(category);
                    }
                }

                actions.RecognizePiiEntitiesActions = new List <RecognizePiiEntitiesAction>()
                {
                    action
                };
            }

            return(await SubmitDocumentsAsync(documents, actions).ConfigureAwait(false));
        }
示例#3
0
        public async Task <IEnumerable <string> > AddUtteranceLevelEntitiesAsync(
            SpeechTranscript speechTranscript,
            SentimentAnalysisSetting sentimentAnalysisSetting)
        {
            speechTranscript = speechTranscript ?? throw new ArgumentNullException(nameof(speechTranscript));

            var errors = new List <string>();

            if (sentimentAnalysisSetting != SentimentAnalysisSetting.UtteranceLevel)
            {
                return(errors);
            }

            var documents = speechTranscript.RecognizedPhrases.Where(r => r.NBest.FirstOrDefault() != null && !string.IsNullOrEmpty(r.NBest.First().Display)).Select(r => new TextDocumentInput($"{r.Channel}_{r.Offset}", r.NBest.First().Display)
            {
                Language = Locale
            });

            var actions = new TextAnalyticsActions
            {
                DisplayName             = "IngestionClient",
                AnalyzeSentimentActions = new List <AnalyzeSentimentAction>()
                {
                    new AnalyzeSentimentAction()
                }
            };

            var(sentimentResults, piiResults, requestErrors) = await this.GetDocumentResultsAsync(documents, actions).ConfigureAwait(false);

            errors.AddRange(requestErrors);

            foreach (var recognizedPhrase in speechTranscript.RecognizedPhrases)
            {
                var index      = $"{recognizedPhrase.Channel}_{recognizedPhrase.Offset}";
                var firstNBest = recognizedPhrase.NBest.FirstOrDefault();

                var sentimentResult = sentimentResults.Where(s => s.Id == index).FirstOrDefault();

                if (firstNBest != null)
                {
                    firstNBest.Sentiment = new Sentiment()
                    {
                        Negative = sentimentResult?.DocumentSentiment.ConfidenceScores.Negative ?? 0.0,
                        Positive = sentimentResult?.DocumentSentiment.ConfidenceScores.Positive ?? 0.0,
                        Neutral  = sentimentResult?.DocumentSentiment.ConfidenceScores.Neutral ?? 0.0,
                    };
                }
            }

            return(errors);
        }
        public static double GetCostEstimation(
            TimeSpan timeSpan,
            int numberOfChannels,
            bool isCustomModel,
            SentimentAnalysisSetting sentimentSetting,
            PiiRedactionSetting entityRedactionSetting)
        {
            double costPerHour = isCustomModel ? STTCustomModelCostPerHour : STTCostPerHour;
            var    price       = timeSpan.TotalHours * costPerHour;

            if (sentimentSetting != SentimentAnalysisSetting.None)
            {
                price += timeSpan.TotalHours * TextAnalyticsCostPerHour;
            }

            if (entityRedactionSetting != PiiRedactionSetting.None)
            {
                price += timeSpan.TotalHours * TextAnalyticsCostPerHour;
            }

            price *= numberOfChannels;
            return(price);
        }
        public async Task <IEnumerable <string> > AddSentimentToTranscriptAsync(SpeechTranscript speechTranscript, SentimentAnalysisSetting sentimentSetting)
        {
            if (speechTranscript == null)
            {
                throw new ArgumentNullException(nameof(speechTranscript));
            }

            var sentimentErrors = new List <string>();

            try
            {
                var textAnalyticsChunks = new List <TextAnalyticsRequestsChunk>();

                if (sentimentSetting == SentimentAnalysisSetting.UtteranceLevel)
                {
                    textAnalyticsChunks = CreateUtteranceLevelRequests(speechTranscript, SentimentRequestLimit);
                }
                else if (sentimentSetting == SentimentAnalysisSetting.AudioLevel)
                {
                    textAnalyticsChunks = CreateAudioLevelRequests(speechTranscript, SentimentRequestLimit);
                }

                var responses = new List <HttpResponseMessage>();
                foreach (var chunk in textAnalyticsChunks)
                {
                    var chunkString = JsonConvert.SerializeObject(chunk);
                    var response    = await MakeRequestAsync(chunkString, SentimentSuffix).ConfigureAwait(false);

                    responses.Add(response);
                }

                Log.LogInformation($"Total responses: {responses.Count}");
                sentimentErrors = await AddSentimentToSpeechTranscriptAsync(responses, speechTranscript, sentimentSetting).ConfigureAwait(false);

                return(sentimentErrors);
            }
            catch (Exception e)
            {
                var sentimentError = $"Sentiment Analysis failed with exception: {e.Message}";
                Log.LogError(sentimentError);
                sentimentErrors.Add(sentimentError);
                return(sentimentErrors);
            }
        }
        private async Task <List <string> > AddSentimentToSpeechTranscriptAsync(List <HttpResponseMessage> responses, SpeechTranscript speechTranscript, SentimentAnalysisSetting sentimentSetting)
        {
            var sentimentErrors = new List <string>();

            if (!speechTranscript.RecognizedPhrases.Any())
            {
                return(sentimentErrors);
            }

            var textAnalyticsDocuments = new List <TextAnalyticsDocument>();

            foreach (var message in responses)
            {
                message.EnsureSuccessStatusCode();

                var responseBody = await message.Content.ReadAsStringAsync().ConfigureAwait(false);

                var textAnalyticsResponse = JsonConvert.DeserializeObject <TextAnalyticsResponse>(responseBody);

                foreach (var error in textAnalyticsResponse.Errors)
                {
                    var errorMessage = $"Sentiment extraction failed with error: {error.Error.InnerError.Message}";
                    Log.LogError(errorMessage);
                    sentimentErrors.Add(errorMessage);
                }

                textAnalyticsDocuments.AddRange(textAnalyticsResponse.Documents);
            }

            if (sentimentSetting == SentimentAnalysisSetting.UtteranceLevel)
            {
                foreach (var document in textAnalyticsDocuments)
                {
                    // Matching sentiment and transcription JSON by using the timestamp
                    var target = speechTranscript.RecognizedPhrases.Where(e => $"{e.Channel}_{e.Offset}".Equals(document.Id, StringComparison.Ordinal)).FirstOrDefault();

                    var nBest = target.NBest.FirstOrDefault();
                    if (nBest != null)
                    {
                        if (nBest.Sentiment == null)
                        {
                            nBest.Sentiment = new Sentiment();
                        }

                        nBest.Sentiment.Negative = document.ConfidenceScores.Negative;
                        nBest.Sentiment.Positive = document.ConfidenceScores.Positive;
                        nBest.Sentiment.Neutral  = document.ConfidenceScores.Neutral;
                    }
                }
            }
            else if (sentimentSetting == SentimentAnalysisSetting.AudioLevel)
            {
                foreach (var combinedRecognizedPhrase in speechTranscript.CombinedRecognizedPhrases)
                {
                    var documents = textAnalyticsDocuments.Where(document => document.Id.StartsWith($"{combinedRecognizedPhrase.Channel}_", StringComparison.OrdinalIgnoreCase));

                    if (!documents.Any())
                    {
                        continue;
                    }

                    if (combinedRecognizedPhrase.Sentiment == null)
                    {
                        combinedRecognizedPhrase.Sentiment = new Sentiment();
                    }

                    combinedRecognizedPhrase.Sentiment.Negative = documents.Average(d => d.ConfidenceScores.Negative);
                    combinedRecognizedPhrase.Sentiment.Positive = documents.Average(d => d.ConfidenceScores.Positive);
                    combinedRecognizedPhrase.Sentiment.Neutral  = documents.Average(d => d.ConfidenceScores.Neutral);
                }
            }

            return(sentimentErrors);
        }
示例#7
0
        public async Task <IEnumerable <string> > AddAudioLevelEntitiesAsync(
            SpeechTranscript speechTranscript,
            SentimentAnalysisSetting sentimentAnalysisSetting,
            PiiRedactionSetting piiRedactionSetting)
        {
            speechTranscript = speechTranscript ?? throw new ArgumentNullException(nameof(speechTranscript));

            var errors = new List <string>();

            if (sentimentAnalysisSetting != SentimentAnalysisSetting.AudioLevel && piiRedactionSetting != PiiRedactionSetting.UtteranceAndAudioLevel)
            {
                return(errors);
            }

            // Remove other nBests if pii is redacted
            if (piiRedactionSetting != PiiRedactionSetting.None)
            {
                speechTranscript.RecognizedPhrases.ToList().ForEach(phrase =>
                {
                    if (phrase.NBest != null && phrase.NBest.Any())
                    {
                        var firstNBest = phrase.NBest.First();
                        phrase.NBest   = new[] { firstNBest };
                    }
                });
            }

            var documents = speechTranscript.CombinedRecognizedPhrases.Where(r => !string.IsNullOrEmpty(r.Display)).Select(r => new TextDocumentInput($"{r.Channel}", r.Display)
            {
                Language = Locale
            });

            var actions = new TextAnalyticsActions
            {
                DisplayName = "IngestionClient"
            };

            if (sentimentAnalysisSetting == SentimentAnalysisSetting.AudioLevel)
            {
                actions.AnalyzeSentimentActions = new List <AnalyzeSentimentAction>()
                {
                    new AnalyzeSentimentAction()
                };
            }

            if (piiRedactionSetting == PiiRedactionSetting.UtteranceAndAudioLevel)
            {
                var action = new RecognizePiiEntitiesAction();

                if (!string.IsNullOrEmpty(FetchTranscriptionEnvironmentVariables.PiiCategories))
                {
                    var piiEntityCategories = FetchTranscriptionEnvironmentVariables.PiiCategories.Split(",").Select(c => new PiiEntityCategory(c));

                    foreach (var category in piiEntityCategories)
                    {
                        action.CategoriesFilter.Add(category);
                    }
                }

                actions.RecognizePiiEntitiesActions = new List <RecognizePiiEntitiesAction>()
                {
                    action
                };
            }

            var(sentimentResults, piiResults, requestErrors) = await this.GetDocumentResultsAsync(documents, actions).ConfigureAwait(false);

            errors.AddRange(requestErrors);

            foreach (var combinedRecognizedPhrase in speechTranscript.CombinedRecognizedPhrases)
            {
                var channel         = combinedRecognizedPhrase.Channel;
                var sentimentResult = sentimentResults.Where(document => document.Id.Equals($"{channel}", StringComparison.OrdinalIgnoreCase)).SingleOrDefault();

                if (sentimentResult != null)
                {
                    combinedRecognizedPhrase.Sentiment = new Sentiment()
                    {
                        Negative = sentimentResult.DocumentSentiment.ConfidenceScores.Negative,
                        Positive = sentimentResult.DocumentSentiment.ConfidenceScores.Positive,
                        Neutral  = sentimentResult.DocumentSentiment.ConfidenceScores.Neutral,
                    };
                }

                var piiResult = piiResults.Where(document => document.Id.Equals($"{channel}", StringComparison.OrdinalIgnoreCase)).SingleOrDefault();
                if (piiResult != null)
                {
                    var redactedText = piiResult.Entities.RedactedText;

                    combinedRecognizedPhrase.Display   = redactedText;
                    combinedRecognizedPhrase.ITN       = string.Empty;
                    combinedRecognizedPhrase.MaskedITN = string.Empty;
                    combinedRecognizedPhrase.Lexical   = string.Empty;

                    var phrases = speechTranscript.RecognizedPhrases.Where(phrase => phrase.Channel == channel);

                    var startIndex = 0;
                    foreach (var phrase in phrases)
                    {
                        var firstNBest = phrase.NBest.FirstOrDefault();

                        if (firstNBest != null && !string.IsNullOrEmpty(firstNBest.Display))
                        {
                            firstNBest.Display   = redactedText.Substring(startIndex, firstNBest.Display.Length);
                            firstNBest.ITN       = string.Empty;
                            firstNBest.MaskedITN = string.Empty;
                            firstNBest.Lexical   = string.Empty;

                            startIndex += firstNBest.Display.Length + 1;
                        }
                    }
                }
            }

            return(errors);
        }