internal override async Task <RecognizerResult> RecognizeInternalAsync(DialogContext dialogContext, Activity activity, HttpClient httpClient, CancellationToken cancellationToken) { var options = PredictionOptions; if (ExternalEntityRecognizer != null) { // call external entity recognizer var matches = await ExternalEntityRecognizer.RecognizeAsync(dialogContext, activity, cancellationToken).ConfigureAwait(false); if (matches.Entities != null && matches.Entities.Count > 0) { options = new LuisV3.LuisPredictionOptions(options); options.ExternalEntities = new List <LuisV3.ExternalEntity>(); var entities = matches.Entities; var instance = entities["$instance"].ToObject <JObject>(); if (instance != null) { foreach (var child in entities) { // TODO: Checking for "text" because we get an extra non-real entity from the text recognizers if (child.Key != "text" && child.Key != "$instance") { var instances = instance[child.Key]?.ToObject <JArray>(); var values = child.Value.ToObject <JArray>(); if (instances != null && values != null && instances.Count == values.Count) { for (var i = 0; i < values.Count; ++i) { var childInstance = instances[i].ToObject <JObject>(); if (childInstance != null && childInstance.ContainsKey("startIndex") && childInstance.ContainsKey("endIndex")) { var start = childInstance["startIndex"].Value <int>(); var end = childInstance["endIndex"].Value <int>(); options.ExternalEntities.Add(new LuisV3.ExternalEntity(child.Key, start, end - start, child.Value)); } } } } } } } } // call luis recognizer with options.ExternalEntities populated from externalEntityRecognizer. return(await RecognizeAsync(dialogContext.Context, activity?.Text, options, httpClient, cancellationToken).ConfigureAwait(false)); }
public override async Task <RecognizerResult> RecognizeAsync(DialogContext dialogContext, Activity activity, CancellationToken cancellationToken = default, Dictionary <string, string> telemetryProperties = null, Dictionary <string, double> telemetryMetrics = null) { if (this._engine == null) { if (this.Model == null) { var resourceExplorer = dialogContext.Context.TurnState.Get <ResourceExplorer>() ?? throw new ArgumentException("No resource Explorer was found in dialog context"); resourceExplorer.AddResourceType("yaml"); var modelId = ResourceId.GetValue(dialogContext.State); var modelResource = resourceExplorer.GetResource(modelId) ?? throw new ArgumentException($"{modelId} not found"); var yamlOrJson = await modelResource.ReadTextAsync(); this._engine = new LucyEngine(yamlOrJson); } else { this._engine = new LucyEngine(this.Model); } } List <LucyEntity> externalEntities = new List <LucyEntity>(); if (ExternalEntityRecognizer != null) { var results = await ExternalEntityRecognizer.RecognizeAsync(dialogContext, activity, cancellationToken, telemetryProperties, telemetryMetrics).ConfigureAwait(false); externalEntities = GetEntitiesFromObject(activity, results.Entities).ToList(); } var recognizerResult = new RecognizerResult(); var lucyEntities = _engine.MatchEntities(activity.Text ?? string.Empty, externalEntities); recognizerResult.Entities = GetRecognizerEntities(lucyEntities); var intents = this.Intents.GetValue(dialogContext.State) ?? new List <string>(); if (intents.Any()) { foreach (var lucyEntity in lucyEntities.Where(entity => intents.Contains(entity.Type))) { recognizerResult.Intents.Add(lucyEntity.Type, new IntentScore() { Score = lucyEntity.Score }); } } else if (recognizerResult.Entities.Count > externalEntities.Count + 1) { recognizerResult.Intents.Add(MatchedIntent, new IntentScore() { Score = lucyEntities.Max(e => e.Score) }); } if (!recognizerResult.Intents.Any()) { recognizerResult.Intents.Add(NoneIntent, new IntentScore { Score = 1.0f }); } await dialogContext.Context.TraceActivityAsync(nameof(LucyRecognizer), JObject.FromObject(recognizerResult), "RecognizerResult", "Lucy RecognizerResult", cancellationToken).ConfigureAwait(false); this.TrackRecognizerResult(dialogContext, "LucyRecognizerResult", this.FillRecognizerResultTelemetryProperties(recognizerResult, telemetryProperties), telemetryMetrics); return(recognizerResult); }
/// <summary> /// Return recognition results. /// </summary> /// <param name="dc">Context object containing information for a single turn of conversation with a user.</param> /// <param name="activity">The incoming activity received from the user. The Text property value is used as the query text for QnA Maker.</param> /// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param> /// <param name="telemetryProperties">Additional properties to be logged to telemetry with the LuisResult event.</param> /// <param name="telemetryMetrics">Additional metrics to be logged to telemetry with the LuisResult event.</param> /// <returns>A <see cref="RecognizerResult"/> containing the QnA Maker result.</returns> public override async Task <RecognizerResult> RecognizeAsync(DialogContext dc, Schema.Activity activity, CancellationToken cancellationToken, Dictionary <string, string> telemetryProperties = null, Dictionary <string, double> telemetryMetrics = null) { var text = activity.Text ?? string.Empty; var detectAmbiguity = DetectAmbiguousIntents.GetValue(dc.State); _modelFolder = ModelFolder.GetValue(dc.State); _snapshotFile = SnapshotFile.GetValue(dc.State); InitializeModel(); var recognizerResult = new RecognizerResult() { Text = text, Intents = new Dictionary <string, IntentScore>(), }; if (string.IsNullOrWhiteSpace(text)) { // nothing to recognize, return empty recognizerResult return(recognizerResult); } if (ExternalEntityRecognizer != null) { // Run external recognition var externalResults = await ExternalEntityRecognizer.RecognizeAsync(dc, activity, cancellationToken, telemetryProperties, telemetryMetrics).ConfigureAwait(false); recognizerResult.Entities = externalResults.Entities; } // Score with orchestrator var results = _resolver.Score(text); // Add full recognition result as a 'result' property recognizerResult.Properties.Add(ResultProperty, results); if (results.Any()) { var topScore = results[0].Score; // if top scoring intent is less than threshold, return None if (topScore < UnknownIntentFilterScore) { recognizerResult.Intents.Add(NoneIntent, new IntentScore() { Score = 1.0 }); } else { // add top score recognizerResult.Intents.Add(results[0].Label.Name, new IntentScore() { Score = results[0].Score }); // Disambiguate if configured if (detectAmbiguity) { var thresholdScore = DisambiguationScoreThreshold.GetValue(dc.State); var classifyingScore = Math.Round(topScore, 2) - Math.Round(thresholdScore, 2); var ambiguousResults = results.Where(item => item.Score >= classifyingScore).ToList(); if (ambiguousResults.Count > 1) { // create a RecognizerResult for each ambiguous result. var recognizerResults = ambiguousResults.Select(result => new RecognizerResult() { Text = text, AlteredText = result.ClosestText, Entities = recognizerResult.Entities, Properties = recognizerResult.Properties, Intents = new Dictionary <string, IntentScore>() { { result.Label.Name, new IntentScore() { Score = result.Score } } }, }); // replace RecognizerResult with ChooseIntent => Ambiguous recognizerResults as candidates. recognizerResult = CreateChooseIntentResult(recognizerResults.ToDictionary(result => Guid.NewGuid().ToString(), result => result)); } } } } else { // Return 'None' if no intent matched. recognizerResult.Intents.Add(NoneIntent, new IntentScore() { Score = 1.0 }); } await dc.Context.TraceActivityAsync($"{nameof(OrchestratorAdaptiveRecognizer)}Result", JObject.FromObject(recognizerResult), nameof(OrchestratorAdaptiveRecognizer), "Orchestrator Recognition", cancellationToken).ConfigureAwait(false); TrackRecognizerResult(dc, $"{nameof(OrchestratorAdaptiveRecognizer)}Result", FillRecognizerResultTelemetryProperties(recognizerResult, telemetryProperties, dc), telemetryMetrics); return(recognizerResult); }