allow LuisRecognizer to recognize without turnContext (#5362)
Co-authored-by: Michael Richardson <v-micric@microsoft.com>
This commit is contained in:
Родитель
46e623f1b3
Коммит
7db214b603
|
@ -492,6 +492,21 @@ namespace Microsoft.Bot.Builder.AI.Luis
|
|||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return results of the analysis (Suggested actions and intents).
|
||||
/// </summary>
|
||||
/// <remarks>No telemetry is provided when using this method.</remarks>
|
||||
/// <param name="utterance">utterance to recognize.</param>
|
||||
/// <param name="recognizerOptions">A <see cref="LuisRecognizerOptions"/> instance to be used by the call.
|
||||
/// This parameter overrides the default <see cref="LuisRecognizerOptions"/> passed in the constructor.</param>
|
||||
/// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
|
||||
/// <returns>The LUIS results of the analysis of the current message text in the current turn's context activity.</returns>
|
||||
public virtual async Task<RecognizerResult> RecognizeAsync(string utterance, LuisRecognizerOptions recognizerOptions = null, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
recognizerOptions ??= _luisRecognizerOptions;
|
||||
return await RecognizeInternalAsync(utterance, recognizerOptions, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invoked prior to a LuisResult being logged.
|
||||
/// </summary>
|
||||
|
@ -637,6 +652,20 @@ namespace Microsoft.Bot.Builder.AI.Luis
|
|||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a RecognizerResult object.
|
||||
/// </summary>
|
||||
/// <param name="utterance">utterance to recognize.</param>
|
||||
/// <param name="predictionOptions">LuisRecognizerOptions implementation to override current properties.</param>
|
||||
/// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
|
||||
/// <returns>RecognizerResult object.</returns>
|
||||
private async Task<RecognizerResult> RecognizeInternalAsync(string utterance, LuisRecognizerOptions predictionOptions, CancellationToken cancellationToken)
|
||||
{
|
||||
var recognizer = predictionOptions ?? _luisRecognizerOptions;
|
||||
var result = await recognizer.RecognizeInternalAsync(utterance, HttpClient, cancellationToken).ConfigureAwait(false);
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a LuisRecognizerOptionsV2.
|
||||
/// This exists to maintain backwards compatibility with existing constructors.
|
||||
|
|
|
@ -65,5 +65,8 @@ namespace Microsoft.Bot.Builder.AI.Luis
|
|||
|
||||
// Support DialogContext
|
||||
internal abstract Task<RecognizerResult> RecognizeInternalAsync(DialogContext context, Activity activity, HttpClient httpClient, CancellationToken cancellationToken);
|
||||
|
||||
// Support string utterance
|
||||
internal abstract Task<RecognizerResult> RecognizeInternalAsync(string utterance, HttpClient httpClient, CancellationToken cancellationToken);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -65,33 +65,9 @@ namespace Microsoft.Bot.Builder.AI.Luis
|
|||
}
|
||||
else
|
||||
{
|
||||
var credentials = new ApiKeyServiceClientCredentials(Application.EndpointKey);
|
||||
using (var runtime = new LUISRuntimeClient(credentials, httpClient, false) { Endpoint = Application.Endpoint })
|
||||
{
|
||||
luisResult = await runtime.Prediction.ResolveAsync(
|
||||
Application.ApplicationId,
|
||||
utterance,
|
||||
timezoneOffset: PredictionOptions.TimezoneOffset,
|
||||
verbose: PredictionOptions.IncludeAllIntents,
|
||||
staging: PredictionOptions.Staging,
|
||||
spellCheck: PredictionOptions.SpellCheck,
|
||||
bingSpellCheckSubscriptionKey: PredictionOptions.BingSpellCheckSubscriptionKey,
|
||||
log: PredictionOptions.Log ?? true,
|
||||
cancellationToken: cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
luisResult = await GetLuisResultAsync(utterance, httpClient, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
recognizerResult = new RecognizerResult
|
||||
{
|
||||
Text = utterance,
|
||||
AlteredText = luisResult.AlteredQuery,
|
||||
Intents = LuisUtil.GetIntents(luisResult),
|
||||
Entities = LuisUtil.ExtractEntitiesAndMetadata(luisResult.Entities, luisResult.CompositeEntities, PredictionOptions.IncludeInstanceData ?? true, utterance),
|
||||
};
|
||||
LuisUtil.AddProperties(luisResult, recognizerResult);
|
||||
if (IncludeAPIResults)
|
||||
{
|
||||
recognizerResult.Properties.Add("luisResult", luisResult);
|
||||
}
|
||||
recognizerResult = BuildRecognizerResultFromLuisResult(luisResult, utterance);
|
||||
}
|
||||
|
||||
var traceInfo = JObject.FromObject(
|
||||
|
@ -109,5 +85,46 @@ namespace Microsoft.Bot.Builder.AI.Luis
|
|||
await turnContext.TraceActivityAsync("LuisRecognizer", traceInfo, LuisTraceType, LuisTraceLabel, cancellationToken).ConfigureAwait(false);
|
||||
return recognizerResult;
|
||||
}
|
||||
|
||||
internal override async Task<RecognizerResult> RecognizeInternalAsync(string utterance, HttpClient httpClient, CancellationToken cancellationToken)
|
||||
{
|
||||
var luisResult = await GetLuisResultAsync(utterance, httpClient, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
return BuildRecognizerResultFromLuisResult(luisResult, utterance);
|
||||
}
|
||||
|
||||
private async Task<LuisResult> GetLuisResultAsync(string utterance, HttpClient httpClient, CancellationToken cancellationToken)
|
||||
{
|
||||
var credentials = new ApiKeyServiceClientCredentials(Application.EndpointKey);
|
||||
using var runtime = new LUISRuntimeClient(credentials, httpClient, false) { Endpoint = Application.Endpoint };
|
||||
return await runtime.Prediction.ResolveAsync(
|
||||
Application.ApplicationId,
|
||||
utterance,
|
||||
timezoneOffset: PredictionOptions.TimezoneOffset,
|
||||
verbose: PredictionOptions.IncludeAllIntents,
|
||||
staging: PredictionOptions.Staging,
|
||||
spellCheck: PredictionOptions.SpellCheck,
|
||||
bingSpellCheckSubscriptionKey: PredictionOptions.BingSpellCheckSubscriptionKey,
|
||||
log: PredictionOptions.Log ?? true,
|
||||
cancellationToken: cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private RecognizerResult BuildRecognizerResultFromLuisResult(LuisResult luisResult, string utterance)
|
||||
{
|
||||
var recognizerResult = new RecognizerResult
|
||||
{
|
||||
Text = utterance,
|
||||
AlteredText = luisResult.AlteredQuery,
|
||||
Intents = LuisUtil.GetIntents(luisResult),
|
||||
Entities = LuisUtil.ExtractEntitiesAndMetadata(luisResult.Entities, luisResult.CompositeEntities, PredictionOptions.IncludeInstanceData ?? true, utterance),
|
||||
};
|
||||
LuisUtil.AddProperties(luisResult, recognizerResult);
|
||||
if (IncludeAPIResults)
|
||||
{
|
||||
recognizerResult.Properties.Add("luisResult", luisResult);
|
||||
}
|
||||
|
||||
return recognizerResult;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -106,6 +106,11 @@ namespace Microsoft.Bot.Builder.AI.Luis
|
|||
return await RecognizeAsync(turnContext, turnContext?.Activity?.AsMessageActivity()?.Text, PredictionOptions, httpClient, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
internal override async Task<RecognizerResult> RecognizeInternalAsync(string utterance, HttpClient httpClient, CancellationToken cancellationToken)
|
||||
{
|
||||
return await RecognizeAsync(utterance, PredictionOptions, httpClient, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private static JObject BuildRequestBody(string utterance, LuisV3.LuisPredictionOptions options)
|
||||
{
|
||||
var content = new JObject
|
||||
|
@ -162,45 +167,8 @@ namespace Microsoft.Bot.Builder.AI.Luis
|
|||
}
|
||||
else
|
||||
{
|
||||
var uri = BuildUri(options);
|
||||
var content = BuildRequestBody(utterance, options);
|
||||
|
||||
using (var request = new HttpRequestMessage(HttpMethod.Post, uri.Uri))
|
||||
{
|
||||
using (var stringContent = new StringContent(content.ToString(), Encoding.UTF8, "application/json"))
|
||||
{
|
||||
request.Content = stringContent;
|
||||
request.Headers.Add("Ocp-Apim-Subscription-Key", Application.EndpointKey);
|
||||
|
||||
var response = await httpClient.SendAsync(request, cancellationToken).ConfigureAwait(false);
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
luisResponse = (JObject)JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync().ConfigureAwait(false));
|
||||
}
|
||||
}
|
||||
|
||||
var prediction = (JObject)luisResponse["prediction"];
|
||||
recognizerResult = new RecognizerResult();
|
||||
|
||||
recognizerResult.Text = utterance;
|
||||
recognizerResult.AlteredText = prediction["alteredQuery"]?.Value<string>();
|
||||
recognizerResult.Intents = LuisV3.LuisUtil.GetIntents(prediction);
|
||||
recognizerResult.Entities = LuisV3.LuisUtil.ExtractEntitiesAndMetadata(prediction);
|
||||
|
||||
LuisV3.LuisUtil.AddProperties(prediction, recognizerResult);
|
||||
if (IncludeAPIResults)
|
||||
{
|
||||
recognizerResult.Properties.Add("luisResult", luisResponse);
|
||||
}
|
||||
|
||||
if (PredictionOptions.IncludeInstanceData)
|
||||
{
|
||||
var instanceObject = recognizerResult.Entities["$instance"];
|
||||
if (instanceObject == null)
|
||||
{
|
||||
recognizerResult.Entities.Add("$instance", new JObject());
|
||||
}
|
||||
}
|
||||
luisResponse = await GetLuisResponseAsync(utterance, options, httpClient, cancellationToken).ConfigureAwait(false);
|
||||
recognizerResult = BuildRecognizerResultFromLuisResponse(luisResponse, utterance);
|
||||
}
|
||||
|
||||
var traceInfo = JObject.FromObject(
|
||||
|
@ -219,6 +187,67 @@ namespace Microsoft.Bot.Builder.AI.Luis
|
|||
return recognizerResult;
|
||||
}
|
||||
|
||||
private async Task<RecognizerResult> RecognizeAsync(string utterance, LuisV3.LuisPredictionOptions options, HttpClient httpClient, CancellationToken cancellationToken)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(utterance))
|
||||
{
|
||||
return new RecognizerResult
|
||||
{
|
||||
Text = utterance
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
var luisResponse = await GetLuisResponseAsync(utterance, options, httpClient, cancellationToken).ConfigureAwait(false);
|
||||
return BuildRecognizerResultFromLuisResponse(luisResponse, utterance);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<JObject> GetLuisResponseAsync(string utterance, LuisV3.LuisPredictionOptions options, HttpClient httpClient, CancellationToken cancellationToken)
|
||||
{
|
||||
var uri = BuildUri(options);
|
||||
var content = BuildRequestBody(utterance, options);
|
||||
|
||||
using var request = new HttpRequestMessage(HttpMethod.Post, uri.Uri);
|
||||
using var stringContent = new StringContent(content.ToString(), Encoding.UTF8, "application/json");
|
||||
request.Content = stringContent;
|
||||
request.Headers.Add("Ocp-Apim-Subscription-Key", Application.EndpointKey);
|
||||
|
||||
var response = await httpClient.SendAsync(request, cancellationToken).ConfigureAwait(false);
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
return (JObject)JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync().ConfigureAwait(false));
|
||||
}
|
||||
|
||||
private RecognizerResult BuildRecognizerResultFromLuisResponse(JObject luisResponse, string utterance)
|
||||
{
|
||||
var prediction = (JObject)luisResponse["prediction"];
|
||||
var recognizerResult = new RecognizerResult
|
||||
{
|
||||
Text = utterance,
|
||||
AlteredText = prediction["alteredQuery"]?.Value<string>(),
|
||||
Intents = LuisV3.LuisUtil.GetIntents(prediction),
|
||||
Entities = LuisV3.LuisUtil.ExtractEntitiesAndMetadata(prediction)
|
||||
};
|
||||
|
||||
LuisV3.LuisUtil.AddProperties(prediction, recognizerResult);
|
||||
if (IncludeAPIResults)
|
||||
{
|
||||
recognizerResult.Properties.Add("luisResult", luisResponse);
|
||||
}
|
||||
|
||||
if (PredictionOptions.IncludeInstanceData)
|
||||
{
|
||||
var instanceObject = recognizerResult.Entities["$instance"];
|
||||
if (instanceObject == null)
|
||||
{
|
||||
recognizerResult.Entities.Add("$instance", new JObject());
|
||||
}
|
||||
}
|
||||
|
||||
return recognizerResult;
|
||||
}
|
||||
|
||||
private UriBuilder BuildUri(LuisV3.LuisPredictionOptions options)
|
||||
{
|
||||
var path = new StringBuilder(Application.Endpoint);
|
||||
|
|
|
@ -138,6 +138,34 @@ namespace Microsoft.Bot.Builder.AI.Luis.Tests
|
|||
Assert.Empty(result.Entities);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task UtteranceWithoutTurnContext()
|
||||
{
|
||||
const string utterance = "email about something wicked this way comes from bart simpson and also kb435";
|
||||
const string responsePath = "Patterns.json";
|
||||
var expectedPath = GetFilePath(responsePath);
|
||||
JObject oracle;
|
||||
using (var expectedJsonReader = new JsonTextReader(new StreamReader(expectedPath)))
|
||||
{
|
||||
oracle = (JObject)await JToken.ReadFromAsync(expectedJsonReader);
|
||||
}
|
||||
|
||||
var mockResponse = oracle["v2"]["response"];
|
||||
|
||||
GetEnvironmentVars();
|
||||
|
||||
var mockHttp = GetMockHttpClientHandlerObject(utterance, new MemoryStream(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(mockResponse))));
|
||||
var options = new LuisPredictionOptions { IncludeAllIntents = true, IncludeInstanceData = true };
|
||||
var luisRecognizer = GetLuisRecognizer(mockHttp, false, options) as LuisRecognizer;
|
||||
var result = await luisRecognizer.RecognizeAsync(utterance);
|
||||
|
||||
Assert.NotNull(result);
|
||||
Assert.Null(result.AlteredText);
|
||||
Assert.Equal(utterance, result.Text);
|
||||
Assert.NotNull(result.Intents);
|
||||
Assert.NotNull(result.Entities);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task V1DatetimeResolution()
|
||||
{
|
||||
|
|
|
@ -109,6 +109,34 @@ namespace Microsoft.Bot.Builder.AI.Luis.Tests
|
|||
Assert.Empty(result.Entities);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task UtteranceWithoutTurnContext()
|
||||
{
|
||||
const string utterance = "email about something wicked this way comes from bart simpson and also kb435";
|
||||
const string responsePath = "Patterns.json";
|
||||
var expectedPath = GetFilePath(responsePath);
|
||||
JObject oracle;
|
||||
using (var expectedJsonReader = new JsonTextReader(new StreamReader(expectedPath)))
|
||||
{
|
||||
oracle = (JObject)await JToken.ReadFromAsync(expectedJsonReader);
|
||||
}
|
||||
|
||||
var mockResponse = oracle["v3"]["response"];
|
||||
|
||||
GetEnvironmentVars();
|
||||
|
||||
var mockHttp = GetMockHttpClientHandlerObject(utterance, new MemoryStream(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(mockResponse))));
|
||||
var options = new LuisV3.LuisPredictionOptions { IncludeAllIntents = true, IncludeInstanceData = true };
|
||||
var luisRecognizer = GetLuisRecognizer(mockHttp, options) as LuisRecognizer;
|
||||
var result = await luisRecognizer.RecognizeAsync(utterance);
|
||||
|
||||
Assert.NotNull(result);
|
||||
Assert.Null(result.AlteredText);
|
||||
Assert.Equal(utterance, result.Text);
|
||||
Assert.NotNull(result.Intents);
|
||||
Assert.NotNull(result.Entities);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task TraceActivity()
|
||||
{
|
||||
|
|
Загрузка…
Ссылка в новой задаче