in libraries/Microsoft.Bot.Builder.AI.Orchestrator/OrchestratorRecognizer.cs [135:249]
public override async Task<RecognizerResult> RecognizeAsync(DialogContext dc, Schema.Activity activity, CancellationToken cancellationToken, Dictionary<string, string> telemetryProperties = null, Dictionary<string, double> telemetryMetrics = null)
{
if (_resolver == null)
{
string modelFolder = ModelFolder.GetValue(dc.State);
string snapshotFile = SnapshotFile.GetValue(dc.State);
InitializeModel(modelFolder, snapshotFile, null);
}
var text = activity.Text ?? string.Empty;
var detectAmbiguity = DetectAmbiguousIntents.GetValue(dc.State);
var recognizerResult = new RecognizerResult()
{
Text = text,
Intents = new Dictionary<string, IntentScore>(),
};
if (string.IsNullOrWhiteSpace(text))
{
// nothing to recognize, return empty recognizerResult
return recognizerResult;
}
// Score with orchestrator
var results = _resolver.Score(text)?.ToList();
if ((results != null) && results.Any())
{
// Add full recognition result as a 'result' property
recognizerResult.Properties.Add(ResultProperty, results);
var topScore = results[0].Score;
// if top scoring intent is less than threshold, return None
if (topScore < UnknownIntentFilterScore)
{
// remove existing None intents
for (int i = 0; i < results.Count; ++i)
{
if (results[i].Label.Name == NoneIntent)
{
results.RemoveAt(i--);
}
}
results.Insert(0, new Result() { Score = 1.0, Label = new Label() { Name = NoneIntent, Type = LabelType.Intent } });
foreach (var result in results)
{
recognizerResult.Intents.Add(result.Label.Name, new IntentScore()
{
Score = result.Score
});
}
}
else
{
// add top score
foreach (var result in results)
{
recognizerResult.Intents.Add(result.Label.Name, new IntentScore()
{
Score = result.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 });
}
if (ExternalEntityRecognizer != null)
{
// Run external recognition
var externalResults = await ExternalEntityRecognizer.RecognizeAsync(dc, activity, cancellationToken, telemetryProperties, telemetryMetrics).ConfigureAwait(false);
recognizerResult.Entities = externalResults.Entities;
}
TryScoreEntities(text, recognizerResult);
// Add full recognition result as a 'result' property
await dc.Context.TraceActivityAsync($"{nameof(OrchestratorRecognizer)}Result", JObject.FromObject(recognizerResult), nameof(OrchestratorRecognizer), "Orchestrator Recognition", cancellationToken).ConfigureAwait(false);
TrackRecognizerResult(dc, $"{nameof(OrchestratorRecognizer)}Result", FillRecognizerResultTelemetryProperties(recognizerResult, telemetryProperties, dc), telemetryMetrics);
return recognizerResult;
}