Initial split into V2 and V3 projects.

This commit is contained in:
Chris McConnell 2019-07-02 12:29:34 -07:00
Родитель 76e6e7f80a
Коммит 474d82939d
52 изменённых файлов: 11213 добавлений и 3477 удалений

Просмотреть файл

@ -25,6 +25,9 @@ EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Bot.Builder.AI.Luis", "libraries\Microsoft.Bot.Builder.AI.LUIS\Microsoft.Bot.Builder.AI.Luis.csproj", "{67AA3C00-E2C5-4D13-BA5E-72EB0E5B8DAA}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Bot.Builder.AI.Luis.Tests", "tests\Microsoft.Bot.Builder.AI.LUIS.Tests\Microsoft.Bot.Builder.AI.Luis.Tests.csproj", "{7BCEBDC1-D57F-4717-9B15-4FACD5473489}"
ProjectSection(ProjectDependencies) = postProject
{6FFAE815-387F-4D24-8572-4C13712D396E} = {6FFAE815-387F-4D24-8572-4C13712D396E}
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Bot.Builder.Integration.AspNet.WebApi", "libraries\integration\Microsoft.Bot.Builder.Integration.AspNet.WebApi\Microsoft.Bot.Builder.Integration.AspNet.WebApi.csproj", "{BD0B82EF-1601-4E87-B78A-B43DE7EB36B0}"
EndProject
@ -84,7 +87,11 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Bot.Builder.Testi
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Bot.Builder.TestBot.Tests", "tests\Microsoft.Bot.Builder.TestBot.Tests\Microsoft.Bot.Builder.TestBot.Tests.csproj", "{76391566-9F22-4994-8B0F-02EFC0E9E228}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Bot.Builder.AI.Luis-preview", "libraries\Microsoft.Bot.Builder.AI.LUIS-preview\Microsoft.Bot.Builder.AI.Luis-preview.csproj", "{66A04273-E854-4793-A19D-49DEFAADB5E9}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Bot.Builder.AI.LuisPreview", "libraries\Microsoft.Bot.Builder.AI.LUISPreview\Microsoft.Bot.Builder.AI.LuisPreview.csproj", "{6FFAE815-387F-4D24-8572-4C13712D396E}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Bot.Builder.AI.LuisPreview.Tests", "tests\Microsoft.Bot.Builder.Ai.LUISPreview.tests\Microsoft.Bot.Builder.AI.LuisPreview.Tests.csproj", "{74C31403-930E-42A1-A06E-E85B4CAB9854}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Bot.Builder.AI.Luis.TestUtils", "tests\Microsoft.Bot.Builder.AI.Luis.TestUtils\Microsoft.Bot.Builder.AI.Luis.TestUtils.csproj", "{685271A8-6C69-46E4-9B11-89AF9761CE0A}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -303,9 +310,24 @@ Global
{76391566-9F22-4994-8B0F-02EFC0E9E228}.Debug|Any CPU.Build.0 = Debug|Any CPU
{76391566-9F22-4994-8B0F-02EFC0E9E228}.Release|Any CPU.ActiveCfg = Release|Any CPU
{76391566-9F22-4994-8B0F-02EFC0E9E228}.Release|Any CPU.Build.0 = Release|Any CPU
{66A04273-E854-4793-A19D-49DEFAADB5E9}.Debug - NuGet Packages|Any CPU.ActiveCfg = Debug - NuGet Packages|Any CPU
{66A04273-E854-4793-A19D-49DEFAADB5E9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{66A04273-E854-4793-A19D-49DEFAADB5E9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6FFAE815-387F-4D24-8572-4C13712D396E}.Debug - NuGet Packages|Any CPU.ActiveCfg = Debug - NuGet Packages|Any CPU
{6FFAE815-387F-4D24-8572-4C13712D396E}.Debug - NuGet Packages|Any CPU.Build.0 = Debug - NuGet Packages|Any CPU
{6FFAE815-387F-4D24-8572-4C13712D396E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6FFAE815-387F-4D24-8572-4C13712D396E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6FFAE815-387F-4D24-8572-4C13712D396E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6FFAE815-387F-4D24-8572-4C13712D396E}.Release|Any CPU.Build.0 = Release|Any CPU
{74C31403-930E-42A1-A06E-E85B4CAB9854}.Debug - NuGet Packages|Any CPU.ActiveCfg = Debug|Any CPU
{74C31403-930E-42A1-A06E-E85B4CAB9854}.Debug - NuGet Packages|Any CPU.Build.0 = Debug|Any CPU
{74C31403-930E-42A1-A06E-E85B4CAB9854}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{74C31403-930E-42A1-A06E-E85B4CAB9854}.Debug|Any CPU.Build.0 = Debug|Any CPU
{74C31403-930E-42A1-A06E-E85B4CAB9854}.Release|Any CPU.ActiveCfg = Release|Any CPU
{74C31403-930E-42A1-A06E-E85B4CAB9854}.Release|Any CPU.Build.0 = Release|Any CPU
{685271A8-6C69-46E4-9B11-89AF9761CE0A}.Debug - NuGet Packages|Any CPU.ActiveCfg = Debug|Any CPU
{685271A8-6C69-46E4-9B11-89AF9761CE0A}.Debug - NuGet Packages|Any CPU.Build.0 = Debug|Any CPU
{685271A8-6C69-46E4-9B11-89AF9761CE0A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{685271A8-6C69-46E4-9B11-89AF9761CE0A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{685271A8-6C69-46E4-9B11-89AF9761CE0A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{685271A8-6C69-46E4-9B11-89AF9761CE0A}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -349,7 +371,9 @@ Global
{060F070A-BBFA-490E-BE89-3844C857B771} = {4269F3C3-6B42-419B-B64A-3E6DC0F1574A}
{E4E13301-9193-4106-B0E3-41276B478E7C} = {AD743B78-D61F-4FBF-B620-FA83CE599A50}
{76391566-9F22-4994-8B0F-02EFC0E9E228} = {AD743B78-D61F-4FBF-B620-FA83CE599A50}
{66A04273-E854-4793-A19D-49DEFAADB5E9} = {763168FA-A590-482C-84D8-2922F7ADB1A2}
{6FFAE815-387F-4D24-8572-4C13712D396E} = {763168FA-A590-482C-84D8-2922F7ADB1A2}
{74C31403-930E-42A1-A06E-E85B4CAB9854} = {AD743B78-D61F-4FBF-B620-FA83CE599A50}
{685271A8-6C69-46E4-9B11-89AF9761CE0A} = {AD743B78-D61F-4FBF-B620-FA83CE599A50}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {7173C9F3-A7F9-496E-9078-9156E35D6E16}

Просмотреть файл

@ -13,7 +13,7 @@ namespace Microsoft.Bot.Builder.AI.Luis
{
internal class LuisDelegatingHandler : DelegatingHandler
{
protected async override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
// Bot Builder Package name and version.
var assemblyName = this.GetType().Assembly.GetName();

Просмотреть файл

@ -0,0 +1,24 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.Bot.Builder.AI.LuisPreview
{
/// <summary>
/// Strongly typed LUIS builtin_age.
/// </summary>
public class Age : NumberWithUnits
{
/// <summary>
/// Initializes a new instance of the <see cref="Age"/> class.
/// </summary>
/// <param name="age">Age.</param>
/// <param name="units">Units for age.</param>
public Age(double age, string units)
: base(age, units)
{
}
/// <inheritdoc/>
public override string ToString() => $"Age({Number} {Units})";
}
}

Просмотреть файл

@ -0,0 +1,75 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
namespace Microsoft.Bot.Builder.AI.LuisPreview
{
/// <summary>
/// Represents the built-in LUIS date-time type.
/// </summary>
/// <remarks>
/// LUIS recognizes time expressions like "next monday" and converts those to a type and set of timex expressions.
/// More information on timex can be found here: http://www.timeml.org/publications/timeMLdocs/timeml_1.2.1.html#timex3.
/// More information on the library which does the recognition can be found here: https://github.com/Microsoft/Recognizers-Text.
/// </remarks>
public class DateTimeSpec
{
/// <summary>
/// Initializes a new instance of the <see cref="DateTimeSpec"/> class.
/// </summary>
/// <param name="type">The type of TIMEX expression.</param>
/// <param name="expressions">The TIMEX expression.</param>
/// <exception cref="ArgumentNullException"><paramref name="type"/> is null or contains only white space,
/// or <paramref name="expressions"/> is null.</exception>
public DateTimeSpec(string type, IEnumerable<string> expressions)
{
if (string.IsNullOrWhiteSpace(type))
{
throw new ArgumentNullException(nameof(type));
}
if (expressions == null)
{
throw new ArgumentNullException(nameof(expressions));
}
Type = type;
Expressions = expressions.ToList();
}
/// <summary>
/// Gets type of expression.
/// </summary>
/// <remarks>Example types include:
/// <list type="*">
/// <item>time -- simple time expression like "3pm".</item>
/// <item>date -- simple date like "july 3rd".</item>
/// <item>datetime -- combination of date and time like "march 23 2pm".</item>
/// <item>timerange -- a range of time like "2pm to 4pm".</item>
/// <item>daterange -- a range of dates like "march 23rd to 24th".</item>
/// <item>datetimerang -- a range of dates and times like "july 3rd 2pm to 5th 4pm".</item>
/// <item>set -- a recurrence like "every monday".</item>
/// </list>
/// </remarks>
/// <value>
/// The type of expression.
/// </value>
[JsonProperty("type")]
public string Type { get; }
/// <summary>
/// Gets Timex expressions.
/// </summary>
/// <value>
/// Timex expressions.
/// </value>
[JsonProperty("timex")]
public IReadOnlyList<string> Expressions { get; }
/// <inheritdoc/>
public override string ToString() => $"DateTimeSpec({Type}, [{string.Join(", ", Expressions)}]";
}
}

Просмотреть файл

@ -0,0 +1,24 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.Bot.Builder.AI.LuisPreview
{
/// <summary>
/// Strongly typed LUIS builtin_dimension.
/// </summary>
public class Dimension : NumberWithUnits
{
/// <summary>
/// Initializes a new instance of the <see cref="Dimension"/> class.
/// </summary>
/// <param name="number">Number.</param>
/// <param name="units">Units for number.</param>
public Dimension(double number, string units)
: base(number, units)
{
}
/// <inheritdoc/>
public override string ToString() => $"Dimension({Number} {Units})";
}
}

Просмотреть файл

@ -0,0 +1,57 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using Newtonsoft.Json;
namespace Microsoft.Bot.Builder.AI.LuisPreview
{
/// <summary>
/// Strongly typed LUIS builtin GeographyV2.
/// </summary>
public class GeographyV2
{
/// <summary>
/// Initializes a new instance of the <see cref="GeographyV2"/> class.
/// </summary>
/// <param name="type">Type of geographic location from <see cref="Types"/>.</param>
/// <param name="location">Geographic location.</param>
public GeographyV2(string type, string location)
{
Type = type;
Location = location;
}
/// <summary>
/// Gets or sets type of geographic location.
/// </summary>
/// <value>
/// Type of geographic location from <see cref="Types"/>.
/// </value>
[JsonProperty("type")]
public string Type { get; set; }
/// <summary>
/// Gets or sets geographic location.
/// </summary>
/// <value>
/// Geographic location.
/// </value>
[JsonProperty("location")]
public string Location { get; set; }
/// <inheritdoc/>
public override string ToString() => $"GeographyV2({Type}, {Location})";
/// <summary>
/// Different types of geographic locations.
/// </summary>
public abstract class Types
{
public const string POI = "poi";
public const string City = "city";
public const string CountryRegion = "countryRegion";
public const string Continent = "continent";
public const string State = "state";
}
}
}

Просмотреть файл

@ -0,0 +1,76 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System.Collections.Generic;
using Newtonsoft.Json;
namespace Microsoft.Bot.Builder.AI.LuisPreview
{
/// <summary>
/// Strongly typed information corresponding to LUIS $instance value.
/// </summary>
public class InstanceData
{
/// <summary>
/// Gets or sets 0-based index in the analyzed text for where entity starts.
/// </summary>
/// <value>
/// 0-based index in the analyzed text for where entity starts.
/// </value>
[JsonProperty("startIndex")]
public int StartIndex { get; set; }
/// <summary>
/// Gets or sets 0-based index of the first character beyond the recognized entity.
/// </summary>
/// <value>
/// 0-based index of the first character beyond the recognized entity.
/// </value>
[JsonProperty("endIndex")]
public int EndIndex { get; set; }
/// <summary>
/// Gets or sets word broken and normalized text for the entity.
/// </summary>
/// <value>
/// Word broken and normalized text for the entity.
/// </value>
[JsonProperty("text")]
public string Text { get; set; }
/// <summary>
/// Gets or sets optional confidence in the recognition.
/// </summary>
/// <value>
/// Optional confidence in the recognition.
/// </value>
[JsonProperty("score")]
public double? Score { get; set; }
/// <summary>
/// Gets or sets optional type for the entity.
/// </summary>
/// <value>
/// Optional entity type.
/// </value>
[JsonProperty("type")]
public string Type { get; set; }
/// <summary>
/// Gets or sets optional subtype for the entity.
/// </summary>
/// <value>
/// Optional entity subtype.
/// </value>
[JsonProperty("subtype")]
public string Subtype { get; set; }
/// <summary>
/// Gets or sets any extra properties.
/// </summary>
/// <value>
/// Any extra properties.
/// </value>
[JsonExtensionData(ReadData = true, WriteData = true)]
public IDictionary<string, object> Properties { get; set; }
}
}

Просмотреть файл

@ -0,0 +1,26 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using Newtonsoft.Json;
namespace Microsoft.Bot.Builder.AI.LuisPreview
{
/// <summary>
/// Strongly typed LUIS builtin_money.
/// </summary>
public class Money : NumberWithUnits
{
/// <summary>
/// Initializes a new instance of the <see cref="Money"/> class.
/// </summary>
/// <param name="money">Money amount.</param>
/// <param name="units">Currency units.</param>
public Money(double money, string units)
: base(money, units)
{
}
/// <inheritdoc/>
public override string ToString() => $"Currency({Number} {Units})";
}
}

Просмотреть файл

@ -0,0 +1,45 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using Newtonsoft.Json;
namespace Microsoft.Bot.Builder.AI.LuisPreview
{
/// <summary>
/// Strongly typed class for LUIS number and units entity recognition.
/// </summary>
/// <remarks>
/// Specific subtypes of this class are generated to match the builtin age, currency, dimension and temperature entities.
/// </remarks>
public class NumberWithUnits
{
/// <summary>
/// Initializes a new instance of the <see cref="NumberWithUnits"/> class.
/// </summary>
/// <param name="number">Number.</param>
/// <param name="units">Units for number.</param>
public NumberWithUnits(double? number, string units)
{
Number = number;
Units = units;
}
/// <summary>
/// Gets or sets recognized number, or null if unit only.
/// </summary>
/// <value>
/// Recognized number, or null if unit only.
/// </value>
[JsonProperty("number")]
public double? Number { get; set; }
/// <summary>
/// Gets or sets normalized recognized unit.
/// </summary>
/// <value>
/// Normalized recognized unit.
/// </value>
[JsonProperty("units")]
public string Units { get; set; }
}
}

Просмотреть файл

@ -0,0 +1,55 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using Newtonsoft.Json;
namespace Microsoft.Bot.Builder.AI.LuisPreview
{
/// <summary>
/// Strongly typed LUIS builtin OrdinalV2.
/// </summary>
public class OrdinalV2
{
/// <summary>
/// Initializes a new instance of the <see cref="OrdinalV2"/> class.
/// </summary>
/// <param name="offset">Offset from <see cref="RelativeTo"/>.</param>
/// <param name="relativeTo">Position that anchors offset.</param>
public OrdinalV2(string relativeTo, long offset)
{
RelativeTo = relativeTo;
Offset = offset;
}
/// <summary>
/// Gets or sets the anchor for the offset.
/// </summary>
/// <value>
/// The base position in a sequence one of <see cref="Anchor"/>.
/// </value>
[JsonProperty("relativeTo")]
public string RelativeTo { get; set; }
/// <summary>
/// Gets or sets the offset in the sequence with respect to <see cref="RelativeTo"/>.
/// </summary>
/// <value>
/// Offset in sequence relative to <see cref="RelativeTo"/>.
/// </value>
[JsonProperty("offset")]
public long Offset { get; set; }
/// <inheritdoc/>
public override string ToString() => $"OrdinalV2({RelativeTo}, {Offset})";
/// <summary>
/// Possible anchors for offsets.
/// </summary>
public abstract class Anchor
{
public const string Current = "current";
public const string End = "end";
public const string Start = "start";
}
}
}

Просмотреть файл

@ -0,0 +1,26 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using Newtonsoft.Json;
namespace Microsoft.Bot.Builder.AI.LuisPreview
{
/// <summary>
/// Strongly typed LUIS builtin_temperature.
/// </summary>
public class Temperature : NumberWithUnits
{
/// <summary>
/// Initializes a new instance of the <see cref="Temperature"/> class.
/// </summary>
/// <param name="temperature">Temperature.</param>
/// <param name="units">Units.</param>
public Temperature(double temperature, string units)
: base(temperature, units)
{
}
/// <inheritdoc/>
public override string ToString() => $"Temperature({Number} {Units})";
}
}

Просмотреть файл

@ -13,7 +13,7 @@ namespace Microsoft.Bot.Builder.AI.LuisPreview
{
internal class LuisDelegatingHandler : DelegatingHandler
{
protected async override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
// Bot Builder Package name and version.
var assemblyName = this.GetType().Assembly.GetName();

Просмотреть файл

@ -124,7 +124,7 @@ namespace Microsoft.Bot.Builder.AI.LuisPreview
/// <value>
/// LUIS slot name to access.
/// </value>
public string Slot { get; set; }
public string Slot { get; set; } = "production";
/// <summary>
/// Gets or sets the specific version of the model to access.

Просмотреть файл

@ -123,7 +123,7 @@ namespace Microsoft.Bot.Builder.AI.LuisPreview
}
string topIntent = null;
double topScore = -1.0;
var topScore = -1.0;
if (results.Intents.Count > 0)
{
foreach (var intent in results.Intents)
@ -189,10 +189,8 @@ namespace Microsoft.Bot.Builder.AI.LuisPreview
/// <param name="telemetryMetrics">Additional metrics to be logged to telemetry with the LuisResult event.</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(ITurnContext turnContext, Dictionary<string, string> telemetryProperties, Dictionary<string, double> telemetryMetrics = null, CancellationToken cancellationToken = default(CancellationToken))
{
return await RecognizeInternalAsync(turnContext, null, telemetryProperties, telemetryMetrics, cancellationToken).ConfigureAwait(false);
}
public virtual async Task<RecognizerResult> RecognizeAsync(ITurnContext turnContext, Dictionary<string, string> telemetryProperties, Dictionary<string, double> telemetryMetrics = null, CancellationToken cancellationToken = default)
=> await RecognizeInternalAsync(turnContext, null, telemetryProperties, telemetryMetrics, cancellationToken).ConfigureAwait(false);
/// <summary>
/// Return results of the analysis (Suggested actions and intents).
@ -204,10 +202,8 @@ namespace Microsoft.Bot.Builder.AI.LuisPreview
/// <param name="telemetryMetrics">Additional metrics to be logged to telemetry with the LuisResult event.</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(ITurnContext turnContext, LuisPredictionOptions predictionOptions, Dictionary<string, string> telemetryProperties, Dictionary<string, double> telemetryMetrics = null, CancellationToken cancellationToken = default(CancellationToken))
{
return await RecognizeInternalAsync(turnContext, predictionOptions, telemetryProperties, telemetryMetrics, cancellationToken).ConfigureAwait(false);
}
public virtual async Task<RecognizerResult> RecognizeAsync(ITurnContext turnContext, LuisPredictionOptions predictionOptions, Dictionary<string, string> telemetryProperties, Dictionary<string, double> telemetryMetrics = null, CancellationToken cancellationToken = default)
=> await RecognizeInternalAsync(turnContext, predictionOptions, telemetryProperties, telemetryMetrics, cancellationToken).ConfigureAwait(false);
/// <summary>
/// Return results of the analysis (Suggested actions and intents).
@ -218,7 +214,7 @@ namespace Microsoft.Bot.Builder.AI.LuisPreview
/// <param name="telemetryMetrics">Additional metrics to be logged to telemetry with the LuisResult event.</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<T> RecognizeAsync<T>(ITurnContext turnContext, Dictionary<string, string> telemetryProperties, Dictionary<string, double> telemetryMetrics = null, CancellationToken cancellationToken = default(CancellationToken))
public virtual async Task<T> RecognizeAsync<T>(ITurnContext turnContext, Dictionary<string, string> telemetryProperties, Dictionary<string, double> telemetryMetrics = null, CancellationToken cancellationToken = default)
where T : IRecognizerConvert, new()
{
var result = new T();
@ -237,7 +233,7 @@ namespace Microsoft.Bot.Builder.AI.LuisPreview
/// <param name="telemetryMetrics">Additional metrics to be logged to telemetry with the LuisResult event.</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<T> RecognizeAsync<T>(ITurnContext turnContext, LuisPredictionOptions predictionOptions, Dictionary<string, string> telemetryProperties, Dictionary<string, double> telemetryMetrics = null, CancellationToken cancellationToken = default(CancellationToken))
public virtual async Task<T> RecognizeAsync<T>(ITurnContext turnContext, LuisPredictionOptions predictionOptions, Dictionary<string, string> telemetryProperties, Dictionary<string, double> telemetryMetrics = null, CancellationToken cancellationToken = default)
where T : IRecognizerConvert, new()
{
var result = new T();
@ -254,7 +250,7 @@ namespace Microsoft.Bot.Builder.AI.LuisPreview
/// <param name="telemetryMetrics">Additional metrics to be logged to telemetry with the LuisResult event.</param>
/// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
/// <returns><see cref="Task"/>.</returns>
protected virtual async Task OnRecognizerResultAsync(RecognizerResult recognizerResult, ITurnContext turnContext, Dictionary<string, string> telemetryProperties = null, Dictionary<string, double> telemetryMetrics = null, CancellationToken cancellationToken = default(CancellationToken))
protected virtual async Task OnRecognizerResultAsync(RecognizerResult recognizerResult, ITurnContext turnContext, Dictionary<string, string> telemetryProperties = null, Dictionary<string, double> telemetryMetrics = null, CancellationToken cancellationToken = default)
{
var properties = await FillLuisEventPropertiesAsync(recognizerResult, turnContext, telemetryProperties, cancellationToken).ConfigureAwait(false);
@ -272,7 +268,7 @@ namespace Microsoft.Bot.Builder.AI.LuisPreview
/// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
/// additionalProperties
/// <returns>A dictionary that is sent as "Properties" to IBotTelemetryClient.TrackEvent method for the BotMessageSend event.</returns>
protected Task<Dictionary<string, string>> FillLuisEventPropertiesAsync(RecognizerResult recognizerResult, ITurnContext turnContext, Dictionary<string, string> telemetryProperties = null, CancellationToken cancellationToken = default(CancellationToken))
protected Task<Dictionary<string, string>> FillLuisEventPropertiesAsync(RecognizerResult recognizerResult, ITurnContext turnContext, Dictionary<string, string> telemetryProperties = null, CancellationToken cancellationToken = default)
{
var topTwoIntents = (recognizerResult.Intents.Count > 0) ? recognizerResult.Intents.OrderByDescending(x => x.Value.Score).Take(2).ToArray() : null;
@ -333,7 +329,7 @@ namespace Microsoft.Bot.Builder.AI.LuisPreview
var utterance = turnContext.Activity?.AsMessageActivity()?.Text;
RecognizerResult recognizerResult;
PredictionResponse luisResult = null;
PredictionResponse luisResponse = null;
if (string.IsNullOrWhiteSpace(utterance))
{
@ -348,50 +344,51 @@ namespace Microsoft.Bot.Builder.AI.LuisPreview
{
if (luisPredictionOptions.Version == null)
{
luisResult = await _runtime.Prediction.GetSlotPredictionAsync(
luisResponse = await _runtime.Prediction.GetSlotPredictionAsync(
appId: new Guid(_application.ApplicationId),
slotName: luisPredictionOptions.Slot,
new PredictionRequest
predictionRequest: new PredictionRequest
{
DynamicLists = luisPredictionOptions.DynamicLists,
ExternalEntities = luisPredictionOptions.ExternalEntities,
Options = new PredictionRequestOptions { DatetimeReference = luisPredictionOptions.DatetimeReference, OverridePredictions = luisPredictionOptions.PreferExternalEntities },
Query = utterance,
},
verbose: predictionOptions.IncludeInstanceData,
showAllIntents: predictionOptions.IncludeAllIntents,
log: predictionOptions.Log ?? true,
verbose: luisPredictionOptions.IncludeInstanceData,
showAllIntents: luisPredictionOptions.IncludeAllIntents,
log: luisPredictionOptions.Log,
cancellationToken: cancellationToken).ConfigureAwait(false);
}
else
{
luisResult = await _runtime.Prediction.GetVersionPredictionAsync(
luisResponse = await _runtime.Prediction.GetVersionPredictionAsync(
appId: new Guid(_application.ApplicationId),
versionId: luisPredictionOptions.Version,
new PredictionRequest
predictionRequest: new PredictionRequest
{
DynamicLists = luisPredictionOptions.DynamicLists,
ExternalEntities = luisPredictionOptions.ExternalEntities,
Options = new PredictionRequestOptions { DatetimeReference = luisPredictionOptions.DatetimeReference, OverridePredictions = luisPredictionOptions.PreferExternalEntities },
Query = utterance,
},
verbose: predictionOptions.IncludeInstanceData,
showAllIntents: predictionOptions.IncludeAllIntents,
log: predictionOptions.Log ?? true,
verbose: luisPredictionOptions.IncludeInstanceData,
showAllIntents: luisPredictionOptions.IncludeAllIntents,
log: luisPredictionOptions.Log,
cancellationToken: cancellationToken).ConfigureAwait(false);
}
var luisResult = luisResponse.Prediction;
recognizerResult = new RecognizerResult
{
Text = utterance,
AlteredText = luisResult.Prediction.AlteredQuery,
AlteredText = luisResponse.Prediction.AlteredQuery,
Intents = LuisUtil.GetIntents(luisResult),
Entities = LuisUtil.ExtractEntitiesAndMetadata(luisResult.Entities, luisResult.CompositeEntities, luisPredictionOptions.IncludeInstanceData ?? true),
Entities = LuisUtil.ExtractEntitiesAndMetadata(luisResult),
};
LuisUtil.AddProperties(luisResult, recognizerResult);
if (_includeApiResults)
{
recognizerResult.Properties.Add("luisResult", luisResult);
recognizerResult.Properties.Add("luisResult", luisResponse);
}
}
@ -407,7 +404,7 @@ namespace Microsoft.Bot.Builder.AI.LuisPreview
ModelID = _application.ApplicationId,
},
luisOptions = luisPredictionOptions,
luisResult,
luisResponse,
});
await turnContext.TraceActivityAsync("LuisRecognizer", traceInfo, LuisTraceType, LuisTraceLabel, cancellationToken).ConfigureAwait(false);
@ -415,8 +412,7 @@ namespace Microsoft.Bot.Builder.AI.LuisPreview
}
private LuisPredictionOptions MergeDefaultOptionsWithProvidedOptions(LuisPredictionOptions defaultOptions, LuisPredictionOptions overridenOptions)
{
return new LuisPredictionOptions()
=> new LuisPredictionOptions()
{
DatetimeReference = overridenOptions.DatetimeReference ?? defaultOptions.DatetimeReference,
DynamicLists = overridenOptions.DynamicLists ?? defaultOptions.DynamicLists,
@ -428,7 +424,6 @@ namespace Microsoft.Bot.Builder.AI.LuisPreview
Slot = overridenOptions.Slot ?? defaultOptions.Slot,
Version = overridenOptions.Version ?? defaultOptions.Version,
};
}
private DelegatingHandler CreateHttpHandlerPipeline(HttpClientHandler httpClientHandler, params DelegatingHandler[] handlers)
{

Просмотреть файл

@ -29,14 +29,69 @@ namespace Microsoft.Bot.Builder.AI.LuisPreview
return intents;
}
internal static JObject ExtractEntitiesAndMetadata(Prediction prediction)
internal static JToken MapProperties(JToken source, Dictionary<string, string> mappings)
{
// DateTimeV2 -> DateTime
// DateTime -> DateTimeV1
//
return (JObject)prediction.Entities;
JToken result = source;
if (source is JObject obj)
{
var nobj = new JObject();
foreach (var property in obj.Properties())
{
if (mappings.TryGetValue(property.Name, out string to))
{
if (to != null)
{
nobj.Add(to, MapProperties(property.Value, mappings));
}
}
else
{
nobj.Add(property.Name, property.Value);
}
}
result = nobj;
}
else if (source is JArray arr)
{
var narr = new JArray();
foreach (var elt in arr)
{
narr.Add(MapProperties(elt, mappings));
}
result = narr;
}
return result;
}
internal static void FixInstance(JToken object)
{
// TODO: need to figure out how to only drop text inside $instance
// TODO: need to figure out how to endIndex
}
internal static JObject ExtractEntitiesAndMetadata(Prediction prediction)
{
var entities = (JObject) JObject.FromObject(prediction.Entities);
return (JObject) MapProperties(entities, new Dictionary<string, string> {
{ "datetimeV2", "datetime" },
{ "datetime", "datetimeV1" },
{ "unit", "units" },
{ "modelType", null },
{ "modelTypeId", null },
{ "recognitionSources", null },
});
// Age, Dimension, Money, Temperature: unit -> units
// DateTimeV2 -> DateTime
// DateTime -> DateTimeV1
// In $instance use length to compute endIndex.
// Drop modelType, modelTypeId, recognitionSources, text
return
}
/* TODO: Remove
internal static JObject ExtractEntitiesAndMetadata(IList<EntityModel> entities, IList<CompositeEntityModel> compositeEntities, bool verbose)
{
var entitiesAndMetadata = new JObject();
@ -289,14 +344,15 @@ namespace Microsoft.Bot.Builder.AI.LuisPreview
}
}
}
*/
internal static void AddProperties(LuisResult luis, RecognizerResult result)
internal static void AddProperties(Prediction luis, RecognizerResult result)
{
if (luis.SentimentAnalysis != null)
if (luis.Sentiment != null)
{
result.Properties.Add("sentiment", new JObject(
new JProperty("label", luis.SentimentAnalysis.Label),
new JProperty("score", luis.SentimentAnalysis.Score)));
new JProperty("label", luis.Sentiment.Label),
new JProperty("score", luis.Sentiment.Score)));
}
}
}

Просмотреть файл

@ -13,6 +13,7 @@ using System.Threading.Tasks;
using Microsoft.Bot.Builder.Adapters;
using Microsoft.Bot.Builder.AI.Luis;
using Microsoft.Bot.Builder.AI.Luis.Tests;
using Microsoft.Bot.Builder.AI.Luis.TestUtils;
using Microsoft.Bot.Configuration;
using Microsoft.Bot.Connector;
using Microsoft.Bot.Schema;
@ -39,17 +40,6 @@ namespace Microsoft.Bot.Builder.AI.Luis.Tests
private string _endpoint = "https://westus.api.cognitive.microsoft.com";
private string _subscriptionKey = null;
// NOTE: The file Contoso_app.cs is generated by running the LUISGen tool like this:
// LUISGen "Contoso app.json" -cs Microsoft.Bot.Builder.AI.Luis.Tests.Contoso_App
private readonly RecognizerResult _mockedResults = new RecognizerResult
{
Intents = new Dictionary<string, IntentScore>()
{
{ "Test", new IntentScore { Score = 0.2 } },
{ "Greeting", new IntentScore { Score = 0.4 } },
},
};
// LUIS tests run off of recorded HTTP responses to avoid service dependencies.
// To update the recorded responses:
// 1) Change _mock to false below
@ -61,6 +51,17 @@ namespace Microsoft.Bot.Builder.AI.Luis.Tests
// This is useful in order to see if the oracles for mocking or testing have changed.
private readonly bool _mock = true;
// NOTE: The file Contoso_app.cs is generated by running the LUISGen tool like this:
// LUISGen "Contoso app.json" -cs Microsoft.Bot.Builder.AI.Luis.Tests.Contoso_App
private readonly RecognizerResult _mockedResults = new RecognizerResult
{
Intents = new Dictionary<string, IntentScore>()
{
{ "Test", new IntentScore { Score = 0.2 } },
{ "Greeting", new IntentScore { Score = 0.4 } },
},
};
[TestMethod]
public void LuisRecognizerConstruction()
{
@ -92,7 +93,7 @@ namespace Microsoft.Bot.Builder.AI.Luis.Tests
var expectedTimeout = 300;
var recognizerWithTimeout = new LuisRecognizer(endpoint, optionsWithTimeout);
Assert.IsNotNull(recognizerWithTimeout);
Assert.AreEqual(expectedTimeout, LuisRecognizer.DefaultHttpClient.Timeout.Milliseconds);
}
@ -147,7 +148,7 @@ namespace Microsoft.Bot.Builder.AI.Luis.Tests
var luisRecognizer = new LuisRecognizer(service, null, false, new MockedHttpClientHandler(mockHttp.ToHttpClient()));
var context = GetContext(utterance);
var context = Utils.GetContext(utterance);
var result = await luisRecognizer.RecognizeAsync(context, CancellationToken.None);
Assert.IsNotNull(result);
@ -164,7 +165,7 @@ namespace Microsoft.Bot.Builder.AI.Luis.Tests
Assert.IsNotNull(result.Entities["$instance"]["Name"]);
Assert.AreEqual(11, (int)result.Entities["$instance"]["Name"].First["startIndex"]);
Assert.AreEqual(15, (int)result.Entities["$instance"]["Name"].First["endIndex"]);
AssertScore(result.Entities["$instance"]["Name"].First["score"]);
Utils.AssertScore(result.Entities["$instance"]["Name"].First["score"]);
}
[TestMethod]
@ -172,6 +173,7 @@ namespace Microsoft.Bot.Builder.AI.Luis.Tests
public void LuisRecognizer_NullLuisAppArg()
{
var recognizerWithNullLuisApplication = new LuisRecognizer(application: null);
Assert.IsNotNull(recognizerWithNullLuisApplication);
}
[TestMethod]
@ -183,7 +185,7 @@ namespace Microsoft.Bot.Builder.AI.Luis.Tests
GetEnvironmentVarsLuis();
var mockHttp = GetMockHttpClientHandlerObject(utterance, responsePath);
var luisRecognizer = GetLuisRecognizer(mockHttp, verbose: true);
var context = GetContext(utterance);
var context = Utils.GetContext(utterance);
var result = await luisRecognizer.RecognizeAsync(context, CancellationToken.None);
Assert.IsNotNull(result);
@ -200,7 +202,7 @@ namespace Microsoft.Bot.Builder.AI.Luis.Tests
Assert.IsNotNull(result.Entities["$instance"]["Name"]);
Assert.AreEqual(11, (int)result.Entities["$instance"]["Name"].First["startIndex"]);
Assert.AreEqual(15, (int)result.Entities["$instance"]["Name"].First["endIndex"]);
AssertScore(result.Entities["$instance"]["Name"].First["score"]);
Utils.AssertScore(result.Entities["$instance"]["Name"].First["score"]);
}
[TestMethod]
@ -212,7 +214,7 @@ namespace Microsoft.Bot.Builder.AI.Luis.Tests
GetEnvironmentVarsLuis();
var mockHttp = GetMockHttpClientHandlerObject(utterance, responsePath);
var luisRecognizer = GetLuisRecognizer(mockHttp, verbose: true);
var context = GetContext(utterance);
var context = Utils.GetContext(utterance);
var result = await luisRecognizer.RecognizeAsync(context, CancellationToken.None);
Assert.IsNotNull(result);
@ -235,7 +237,7 @@ namespace Microsoft.Bot.Builder.AI.Luis.Tests
GetEnvironmentVarsLuis();
var mockHttp = GetMockHttpClientHandlerObject(utterance, responsePath);
var luisRecognizer = GetLuisRecognizer(mockHttp, true, new LuisPredictionOptions { IncludeAllIntents = true });
var context = GetContext(utterance);
var context = Utils.GetContext(utterance);
var result = await luisRecognizer.RecognizeAsync(context, CancellationToken.None);
Assert.IsNotNull(result);
@ -272,7 +274,7 @@ namespace Microsoft.Bot.Builder.AI.Luis.Tests
GetEnvironmentVarsLuis();
var mockHttp = GetMockHttpClientHandlerObject(utterance, responsePath);
var luisRecognizer = GetLuisRecognizer(mockHttp, true, new LuisPredictionOptions { IncludeAllIntents = true });
var context = GetContext(utterance);
var context = Utils.GetContext(utterance);
var result = await luisRecognizer.RecognizeAsync(context, CancellationToken.None);
Assert.IsNotNull(result);
@ -298,7 +300,7 @@ namespace Microsoft.Bot.Builder.AI.Luis.Tests
GetEnvironmentVarsLuis();
var mockHttp = GetMockHttpClientHandlerObject(utterance, responsePath);
var luisRecognizer = GetLuisRecognizer(mockHttp, true, new LuisPredictionOptions { IncludeAllIntents = true });
var context = GetContext(utterance);
var context = Utils.GetContext(utterance);
var result = await luisRecognizer.RecognizeAsync(context, CancellationToken.None);
Assert.IsNotNull(result);
@ -325,7 +327,7 @@ namespace Microsoft.Bot.Builder.AI.Luis.Tests
GetEnvironmentVarsLuis();
var mockHttp = GetMockHttpClientHandlerObject(utterance, responsePath);
var luisRecognizer = GetLuisRecognizer(mockHttp, true, new LuisPredictionOptions { IncludeAllIntents = true });
var context = GetContext(utterance);
var context = Utils.GetContext(utterance);
var result = await luisRecognizer.RecognizeAsync(context, CancellationToken.None);
Assert.IsNotNull(result);
@ -354,7 +356,7 @@ namespace Microsoft.Bot.Builder.AI.Luis.Tests
GetEnvironmentVarsLuis();
var mockHttp = GetMockHttpClientHandlerObject(utterance, responsePath);
var luisRecognizer = GetLuisRecognizer(mockHttp, true, new LuisPredictionOptions { IncludeAllIntents = true });
var context = GetContext(utterance);
var context = Utils.GetContext(utterance);
var result = await luisRecognizer.RecognizeAsync(context, CancellationToken.None);
Assert.IsNotNull(result);
@ -374,7 +376,7 @@ namespace Microsoft.Bot.Builder.AI.Luis.Tests
Assert.IsNotNull(result.Entities["$instance"]["Address"]);
Assert.AreEqual(21, result.Entities["$instance"]["Address"][0]["startIndex"]);
Assert.AreEqual(29, result.Entities["$instance"]["Address"][0]["endIndex"]);
AssertScore(result.Entities["$instance"]["Address"][0]["score"]);
Utils.AssertScore(result.Entities["$instance"]["Address"][0]["score"]);
Assert.IsNotNull(result.Entities["Address"][0]["$instance"]);
Assert.IsNotNull(result.Entities["Address"][0]["$instance"]["number"]);
Assert.AreEqual(21, result.Entities["Address"][0]["$instance"]["number"][0]["startIndex"]);
@ -385,7 +387,7 @@ namespace Microsoft.Bot.Builder.AI.Luis.Tests
Assert.AreEqual(29, result.Entities["Address"][0]["$instance"]["State"][0]["endIndex"]);
Assert.AreEqual("wa", result.Entities["Address"][0]["$instance"]["State"][0]["text"]);
Assert.AreEqual("WA", result.Text.Substring(27, 29 - 27));
AssertScore(result.Entities["Address"][0]["$instance"]["State"][0]["score"]);
Utils.AssertScore(result.Entities["Address"][0]["$instance"]["State"][0]["score"]);
}
[TestMethod]
@ -397,7 +399,7 @@ namespace Microsoft.Bot.Builder.AI.Luis.Tests
GetEnvironmentVarsLuis();
var mockHttp = GetMockHttpClientHandlerObject(utterance, responsePath);
var luisRecognizer = GetLuisRecognizer(mockHttp, true, new LuisPredictionOptions { IncludeAllIntents = true });
var context = GetContext(utterance);
var context = Utils.GetContext(utterance);
var result = await luisRecognizer.RecognizeAsync(context, CancellationToken.None);
Assert.IsNotNull(result.Entities["datetime"]);
@ -423,7 +425,7 @@ namespace Microsoft.Bot.Builder.AI.Luis.Tests
GetEnvironmentVarsLuis();
var mockHttp = GetMockHttpClientHandler(utterance, responsePath);
var luisRecognizer = GetLuisRecognizer(mockHttp, true, new LuisPredictionOptions { IncludeAllIntents = true });
var context = GetContext(utterance);
var context = Utils.GetContext(utterance);
var result = await luisRecognizer.RecognizeAsync(context, CancellationToken.None);
Assert.IsNotNull(result.Entities["datetime_time"]);
@ -433,55 +435,25 @@ namespace Microsoft.Bot.Builder.AI.Luis.Tests
Assert.AreEqual(1, result.Entities["$instance"]["datetime_time"].Count());
}
public async Task TestEndpoint<T>(string expectedPath, JToken oracle, string version)
where T : IRecognizerConvert, new()
{
var newPath = expectedPath + ".new";
using (var mockResponse = new MemoryStream(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(oracle[version]))))
{
var text = oracle["text"] ?? oracle["Text"];
var query = text.ToString();
var context = GetContext(query);
var mockHttp = GetMockHttpClientHandlerObject(query, mockResponse);
var luisRecognizer = GetLuisRecognizer(mockHttp, true, new LuisPredictionOptions { IncludeAllIntents = true });
var typedResult = await luisRecognizer.RecognizeAsync<T>(context, CancellationToken.None);
var typedJson = Json(typedResult);
typedJson[version] = typedJson["luisResult"];
typedJson.Remove("luisResult");
if (!WithinDelta(oracle, typedJson, 0.1))
{
using (var writer = new StreamWriter(newPath))
{
writer.Write(typedJson);
}
Assert.Fail($"Returned JSON in {newPath} != expected JSON in {expectedPath}");
}
else
{
File.Delete(expectedPath + ".new");
}
}
}
// To create a file to test:
// 1) Create a <name>.json file with an object { Text:<query> } in it.
// 2) Run this test which will fail and generate a <name>.json.new file.
// 3) Check the .new file and if correct, replace the original .json file with it.
// NOTE: The same oracle files are shared between Luis and LuisPreview in order to ensure the mapping is the same.
public async Task TestJson<T>(string file)
where T : IRecognizerConvert, new()
{
var expectedPath = GetFilePath(file);
GetEnvironmentVarsLuis();
using (var expectedJsonReader = new JsonTextReader(new StreamReader(expectedPath)))
{
var expectedJson = await JToken.ReadFromAsync(expectedJsonReader);
await TestEndpoint<T>(expectedPath, expectedJson, "v2");
}
var version = "v2";
await Utils.TestJsonOracle<T>(
GetFilePath(file),
version,
(oracle) =>
{
GetEnvironmentVarsLuis();
var mockResponse = new MemoryStream(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(oracle[version])));
var mockHttp = GetMockHttpClientHandlerObject((string)oracle["text"], mockResponse);
return GetLuisRecognizer(mockHttp, true, new LuisPredictionOptions { IncludeAllIntents = true });
});
}
[TestMethod]
@ -586,6 +558,8 @@ namespace Microsoft.Bot.Builder.AI.Luis.Tests
{
RecognizerResult nullResults = null;
var noIntent = LuisRecognizer.TopIntent(nullResults);
Assert.Fail();
Assert.IsNotNull(noIntent);
}
[TestMethod]
@ -622,6 +596,7 @@ namespace Microsoft.Bot.Builder.AI.Luis.Tests
var turnContext = new TurnContext(adapter, activity);
var recognizerResult = recognizer.RecognizeAsync(turnContext, CancellationToken.None).Result;
Assert.IsNotNull(recognizerResult);
var userAgent = clientHandler.UserAgent;
@ -1064,106 +1039,13 @@ namespace Microsoft.Bot.Builder.AI.Luis.Tests
Assert.AreEqual(((Dictionary<string, double>)telemetryClient.Invocations[0].Arguments[2])["luis"], 1.0001);
}
private static TurnContext GetContext(string utterance)
{
var testAdapter = new TestAdapter();
var activity = new Activity
{
Type = ActivityTypes.Message,
Text = utterance,
Conversation = new ConversationAccount(),
Recipient = new ChannelAccount(),
From = new ChannelAccount(),
};
return new TurnContext(testAdapter, activity);
}
private static TurnContext GetNonMessageContext(string utterance)
{
var b = new TestAdapter();
var a = new Activity
{
Type = ActivityTypes.ConversationUpdate,
Text = utterance,
Conversation = new ConversationAccount(),
Recipient = new ChannelAccount(),
From = new ChannelAccount(),
};
return new TurnContext(b, a);
}
// Compare two JSON structures and ensure entity and intent scores are within delta
private bool WithinDelta(JToken token1, JToken token2, double delta, bool compare = false)
{
var withinDelta = true;
if (token1.Type == JTokenType.Object && token2.Type == JTokenType.Object)
{
var obj1 = (JObject)token1;
var obj2 = (JObject)token2;
withinDelta = obj1.Count == obj2.Count;
foreach (var property in obj1)
{
if (!withinDelta)
{
break;
}
withinDelta = obj2.TryGetValue(property.Key, out var val2) && WithinDelta(property.Value, val2, delta, compare || property.Key == "score" || property.Key == "intents");
}
}
else if (token1.Type == JTokenType.Array && token2.Type == JTokenType.Array)
{
var arr1 = (JArray)token1;
var arr2 = (JArray)token2;
withinDelta = arr1.Count() == arr2.Count();
for (var i = 0; withinDelta && i < arr1.Count(); ++i)
{
withinDelta = WithinDelta(arr1[i], arr2[i], delta);
if (!withinDelta)
{
break;
}
}
}
else if (!token1.Equals(token2))
{
if (token1.Type == token2.Type)
{
var val1 = (JValue)token1;
var val2 = (JValue)token2;
withinDelta = false;
if (compare &&
double.TryParse((string)val1, out var num1)
&& double.TryParse((string)val2, out var num2))
{
withinDelta = Math.Abs(num1 - num2) < delta;
}
}
else
{
withinDelta = false;
}
}
return withinDelta;
}
private JObject Json<T>(T result)
=> (JObject)JsonConvert.DeserializeObject(JsonConvert.SerializeObject(result, new JsonSerializerSettings { Formatting = Formatting.Indented, NullValueHandling = NullValueHandling.Ignore }));
private void AssertScore(JToken scoreToken)
{
var score = (double)scoreToken;
Assert.IsTrue(score >= 0);
Assert.IsTrue(score <= 1);
}
private IRecognizer GetLuisRecognizer(MockedHttpClientHandler httpClientHandler, bool verbose = false, LuisPredictionOptions options = null)
{
var luisApp = new LuisApplication(_luisAppId, _subscriptionKey, _endpoint);
return new LuisRecognizer(luisApp, options, verbose, httpClientHandler);
}
private MockedHttpClientHandler GetMockHttpClientHandlerObject(string example, string responsePath)
{
var response = GetResponse(responsePath);

Просмотреть файл

@ -21,6 +21,7 @@
<ItemGroup>
<ProjectReference Include="..\..\libraries\Microsoft.Bot.Builder.AI.LUIS\Microsoft.Bot.Builder.AI.Luis.csproj" />
<ProjectReference Include="..\Microsoft.Bot.Builder.AI.Luis.TestUtils\Microsoft.Bot.Builder.AI.Luis.TestUtils.csproj" />
<ProjectReference Include="..\Microsoft.Bot.Builder.Tests\Microsoft.Bot.Builder.Tests.csproj" />
</ItemGroup>

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -1,55 +1,19 @@
{
"text": "http://foo.com is where you can fly from seattle to dallas via denver",
"intents": {
"EntityTests": {
"score": 0.944987357
},
"Travel": {
"score": 0.0452092439
},
"Roles": {
"score": 0.0297764745
},
"Weather_GetForecast": {
"score": 0.0231683664
},
"search": {
"score": 0.008871362
},
"None": {
"score": 0.004223796
},
"SpecifyName": {
"score": 0.00236839615
},
"Delivery": {
"score": 0.0013232599
},
"Help": {
"score": 0.0005449379
},
"Cancel": {
"score": 0.000226470322
},
"Greeting": {
"score": 0.000151786517
}
},
"entities": {
"$instance": {
"Composite2": [
{
"startIndex": 0,
"endIndex": 69,
"score": 0.962469339,
"startIndex": 0,
"text": "http : / / foo . com is where you can fly from seattle to dallas via denver",
"type": "Composite2",
"score": 0.962469339
"type": "Composite2"
}
],
"geographyV2": [
{
"startIndex": 41,
"endIndex": 48,
"startIndex": 41,
"text": "seattle",
"type": "builtin.geographyV2.city"
}
@ -60,71 +24,171 @@
"$instance": {
"City": [
{
"startIndex": 63,
"endIndex": 69,
"score": 0.984729,
"startIndex": 63,
"text": "denver",
"type": "City",
"score": 0.984729
}
],
"url": [
{
"startIndex": 0,
"endIndex": 14,
"text": "http://foo.com",
"type": "builtin.url"
"type": "City"
}
],
"From": [
{
"startIndex": 41,
"endIndex": 48,
"score": 0.9992566,
"startIndex": 41,
"text": "seattle",
"type": "City::From",
"score": 0.9992566
"type": "City::From"
}
],
"To": [
{
"startIndex": 52,
"endIndex": 58,
"score": 0.998420954,
"startIndex": 52,
"text": "dallas",
"type": "City::To",
"score": 0.998420954
"type": "City::To"
}
],
"url": [
{
"endIndex": 14,
"startIndex": 0,
"text": "http://foo.com",
"type": "builtin.url"
}
]
},
"City": [
"denver"
],
"url": [
"http://foo.com"
],
"From": [
"seattle"
],
"To": [
"dallas"
],
"url": [
"http://foo.com"
]
}
],
"geographyV2": [
{
"type": "city",
"location": "seattle"
"location": "seattle",
"type": "city"
}
]
},
"intents": {
"Cancel": {
"score": 0.000226470322
},
"Delivery": {
"score": 0.0013232599
},
"EntityTests": {
"score": 0.944987357
},
"Greeting": {
"score": 0.000151786517
},
"Help": {
"score": 0.0005449379
},
"None": {
"score": 0.004223796
},
"Roles": {
"score": 0.0297764745
},
"search": {
"score": 0.008871362
},
"SpecifyName": {
"score": 0.00236839615
},
"Travel": {
"score": 0.0452092439
},
"Weather_GetForecast": {
"score": 0.0231683664
}
},
"sentiment": {
"label": "neutral",
"score": 0.5
},
"text": "http://foo.com is where you can fly from seattle to dallas via denver",
"v2": {
"query": "http://foo.com is where you can fly from seattle to dallas via denver",
"topScoringIntent": {
"intent": "EntityTests",
"score": 0.944987357
},
"compositeEntities": [
{
"children": [
{
"type": "City",
"value": "denver"
},
{
"type": "builtin.url",
"value": "http://foo.com"
},
{
"type": "City::From",
"value": "seattle"
},
{
"type": "City::To",
"value": "dallas"
}
],
"parentType": "Composite2",
"value": "http : / / foo . com is where you can fly from seattle to dallas via denver"
}
],
"entities": [
{
"endIndex": 57,
"entity": "dallas",
"score": 0.998420954,
"startIndex": 52,
"type": "City::To"
},
{
"endIndex": 47,
"entity": "seattle",
"score": 0.9992566,
"startIndex": 41,
"type": "City::From"
},
{
"endIndex": 68,
"entity": "denver",
"score": 0.984729,
"startIndex": 63,
"type": "City"
},
{
"endIndex": 68,
"entity": "http : / / foo . com is where you can fly from seattle to dallas via denver",
"score": 0.962469339,
"startIndex": 0,
"type": "Composite2"
},
{
"endIndex": 47,
"entity": "seattle",
"startIndex": 41,
"type": "builtin.geographyV2.city"
},
{
"endIndex": 13,
"entity": "http://foo.com",
"resolution": {
"value": "http://foo.com"
},
"startIndex": 0,
"type": "builtin.url"
}
],
"intents": [
{
"intent": "EntityTests",
@ -171,78 +235,14 @@
"score": 0.000151786517
}
],
"entities": [
{
"entity": "dallas",
"type": "City::To",
"startIndex": 52,
"endIndex": 57,
"score": 0.998420954
},
{
"entity": "seattle",
"type": "City::From",
"startIndex": 41,
"endIndex": 47,
"score": 0.9992566
},
{
"entity": "denver",
"type": "City",
"startIndex": 63,
"endIndex": 68,
"score": 0.984729
},
{
"entity": "http : / / foo . com is where you can fly from seattle to dallas via denver",
"type": "Composite2",
"startIndex": 0,
"endIndex": 68,
"score": 0.962469339
},
{
"entity": "seattle",
"type": "builtin.geographyV2.city",
"startIndex": 41,
"endIndex": 47
},
{
"entity": "http://foo.com",
"type": "builtin.url",
"startIndex": 0,
"endIndex": 13,
"resolution": {
"value": "http://foo.com"
}
}
],
"compositeEntities": [
{
"parentType": "Composite2",
"value": "http : / / foo . com is where you can fly from seattle to dallas via denver",
"children": [
{
"type": "City",
"value": "denver"
},
{
"type": "builtin.url",
"value": "http://foo.com"
},
{
"type": "City::From",
"value": "seattle"
},
{
"type": "City::To",
"value": "dallas"
}
]
}
],
"query": "http://foo.com is where you can fly from seattle to dallas via denver",
"sentimentAnalysis": {
"label": "neutral",
"score": 0.5
},
"topScoringIntent": {
"intent": "EntityTests",
"score": 0.944987357
}
}
}

Просмотреть файл

@ -1,110 +1,44 @@
{
"text": "Deliver from 12345 VA to 12346 WA",
"intents": {
"Roles": {
"score": 0.999888361
},
"Delivery": {
"score": 0.00234605442
},
"search": {
"score": 9.343347E-06
},
"Travel": {
"score": 3.04712876E-06
},
"None": {
"score": 1.15824787E-06
},
"Weather_GetForecast": {
"score": 1.01009994E-06
},
"SpecifyName": {
"score": 3.01666669E-09
},
"Greeting": {
"score": 1.06875E-09
},
"Cancel": {
"score": 1E-09
},
"Help": {
"score": 1E-09
},
"EntityTests": {
"score": 4.6666665E-10
}
},
"entities": {
"$instance": {
"Source": [
{
"startIndex": 13,
"endIndex": 21,
"text": "12345 va",
"type": "Address",
"score": 0.9377045
}
],
"Destination": [
{
"startIndex": 25,
"endIndex": 33,
"score": 0.9818967,
"startIndex": 25,
"text": "12346 wa",
"type": "Address",
"score": 0.9818967
"type": "Address"
}
],
"Source": [
{
"endIndex": 21,
"score": 0.9377045,
"startIndex": 13,
"text": "12345 va",
"type": "Address"
}
]
},
"Source": [
{
"$instance": {
"number": [
{
"startIndex": 13,
"endIndex": 18,
"text": "12345",
"type": "builtin.number",
"subtype": "integer"
}
],
"State": [
{
"startIndex": 19,
"endIndex": 21,
"text": "va",
"type": "State",
"score": 0.9417667
}
]
},
"number": [
12345
],
"State": [
"va"
]
}
],
"Destination": [
{
"$instance": {
"number": [
{
"startIndex": 25,
"endIndex": 30,
"startIndex": 25,
"subtype": "integer",
"text": "12346",
"type": "builtin.number",
"subtype": "integer"
"type": "builtin.number"
}
],
"State": [
{
"startIndex": 31,
"endIndex": 33,
"score": 0.9899993,
"startIndex": 31,
"text": "wa",
"type": "State",
"score": 0.9899993
"type": "State"
}
]
},
@ -115,18 +49,161 @@
"wa"
]
}
],
"Source": [
{
"$instance": {
"number": [
{
"endIndex": 18,
"startIndex": 13,
"subtype": "integer",
"text": "12345",
"type": "builtin.number"
}
],
"State": [
{
"endIndex": 21,
"score": 0.9417667,
"startIndex": 19,
"text": "va",
"type": "State"
}
]
},
"number": [
12345
],
"State": [
"va"
]
}
]
},
"intents": {
"Cancel": {
"score": 1E-09
},
"Delivery": {
"score": 0.00234605442
},
"EntityTests": {
"score": 4.6666665E-10
},
"Greeting": {
"score": 1.06875E-09
},
"Help": {
"score": 1E-09
},
"None": {
"score": 1.15824787E-06
},
"Roles": {
"score": 0.999888361
},
"search": {
"score": 9.343347E-06
},
"SpecifyName": {
"score": 3.01666669E-09
},
"Travel": {
"score": 3.04712876E-06
},
"Weather_GetForecast": {
"score": 1.01009994E-06
}
},
"sentiment": {
"label": "neutral",
"score": 0.5
},
"text": "Deliver from 12345 VA to 12346 WA",
"v2": {
"query": "Deliver from 12345 VA to 12346 WA",
"topScoringIntent": {
"intent": "Roles",
"score": 0.999888361
},
"compositeEntities": [
{
"children": [
{
"type": "builtin.number",
"value": "12345"
},
{
"type": "State",
"value": "va"
}
],
"parentType": "Address",
"value": "12345 va"
},
{
"children": [
{
"type": "builtin.number",
"value": "12346"
},
{
"type": "State",
"value": "wa"
}
],
"parentType": "Address",
"value": "12346 wa"
}
],
"entities": [
{
"endIndex": 20,
"entity": "va",
"score": 0.9417667,
"startIndex": 19,
"type": "State"
},
{
"endIndex": 32,
"entity": "wa",
"score": 0.9899993,
"startIndex": 31,
"type": "State"
},
{
"endIndex": 20,
"entity": "12345 va",
"role": "Source",
"score": 0.9377045,
"startIndex": 13,
"type": "Address"
},
{
"endIndex": 32,
"entity": "12346 wa",
"role": "Destination",
"score": 0.9818967,
"startIndex": 25,
"type": "Address"
},
{
"endIndex": 17,
"entity": "12345",
"resolution": {
"subtype": "integer",
"value": "12345"
},
"startIndex": 13,
"type": "builtin.number"
},
{
"endIndex": 29,
"entity": "12346",
"resolution": {
"subtype": "integer",
"value": "12346"
},
"startIndex": 25,
"type": "builtin.number"
}
],
"intents": [
{
"intent": "Roles",
@ -173,91 +250,14 @@
"score": 4.6666665E-10
}
],
"entities": [
{
"entity": "va",
"type": "State",
"startIndex": 19,
"endIndex": 20,
"score": 0.9417667
},
{
"entity": "wa",
"type": "State",
"startIndex": 31,
"endIndex": 32,
"score": 0.9899993
},
{
"entity": "12345 va",
"type": "Address",
"startIndex": 13,
"endIndex": 20,
"score": 0.9377045,
"role": "Source"
},
{
"entity": "12346 wa",
"type": "Address",
"startIndex": 25,
"endIndex": 32,
"score": 0.9818967,
"role": "Destination"
},
{
"entity": "12345",
"type": "builtin.number",
"startIndex": 13,
"endIndex": 17,
"resolution": {
"subtype": "integer",
"value": "12345"
}
},
{
"entity": "12346",
"type": "builtin.number",
"startIndex": 25,
"endIndex": 29,
"resolution": {
"subtype": "integer",
"value": "12346"
}
}
],
"compositeEntities": [
{
"parentType": "Address",
"value": "12345 va",
"children": [
{
"type": "builtin.number",
"value": "12345"
},
{
"type": "State",
"value": "va"
}
]
},
{
"parentType": "Address",
"value": "12346 wa",
"children": [
{
"type": "builtin.number",
"value": "12346"
},
{
"type": "State",
"value": "wa"
}
]
}
],
"query": "Deliver from 12345 VA to 12346 WA",
"sentimentAnalysis": {
"label": "neutral",
"score": 0.5
},
"topScoringIntent": {
"intent": "Roles",
"score": 0.999888361
}
}
}

Просмотреть файл

@ -1,20 +1,89 @@
{
"text": "go from next to last to last move london to jakarta and homer simpson is the parent of lisa simpson",
"entities": {
"$instance": {
"child": [
{
"endIndex": 99,
"startIndex": 87,
"text": "lisa simpson",
"type": "builtin.personName"
}
],
"endloc": [
{
"endIndex": 51,
"startIndex": 44,
"text": "jakarta",
"type": "builtin.geographyV2.city"
}
],
"endpos": [
{
"endIndex": 28,
"startIndex": 24,
"text": "last",
"type": "builtin.ordinalV2.relative"
}
],
"parent": [
{
"endIndex": 69,
"startIndex": 56,
"text": "homer simpson",
"type": "builtin.personName"
}
],
"startloc": [
{
"endIndex": 40,
"startIndex": 34,
"text": "london",
"type": "builtin.geographyV2.city"
}
],
"startpos": [
{
"endIndex": 20,
"startIndex": 8,
"text": "next to last",
"type": "builtin.ordinalV2.relative"
}
]
},
"child": [
"lisa simpson"
],
"endloc": [
{
"location": "jakarta",
"type": "city"
}
],
"endpos": [
{
"offset": 0,
"relativeTo": "end"
}
],
"parent": [
"homer simpson"
],
"startloc": [
{
"location": "london",
"type": "city"
}
],
"startpos": [
{
"offset": -1,
"relativeTo": "end"
}
]
},
"intents": {
"Roles": {
"score": 0.999204934
},
"search": {
"score": 0.0309635121
},
"None": {
"score": 0.0109820236
},
"Travel": {
"score": 0.01095186
},
"Weather_GetForecast": {
"score": 0.0106523167
"Cancel": {
"score": 0.000107549029
},
"Delivery": {
"score": 0.00123035291
@ -22,111 +91,89 @@
"EntityTests": {
"score": 0.0009487789
},
"SpecifyName": {
"score": 0.0009410849
"Greeting": {
"score": 5.293933E-05
},
"Help": {
"score": 0.0001358991
},
"Cancel": {
"score": 0.000107549029
"None": {
"score": 0.0109820236
},
"Greeting": {
"score": 5.293933E-05
"Roles": {
"score": 0.999204934
},
"search": {
"score": 0.0309635121
},
"SpecifyName": {
"score": 0.0009410849
},
"Travel": {
"score": 0.01095186
},
"Weather_GetForecast": {
"score": 0.0106523167
}
},
"entities": {
"$instance": {
"startloc": [
{
"startIndex": 34,
"endIndex": 40,
"text": "london",
"type": "builtin.geographyV2.city"
}
],
"endloc": [
{
"startIndex": 44,
"endIndex": 51,
"text": "jakarta",
"type": "builtin.geographyV2.city"
}
],
"startpos": [
{
"startIndex": 8,
"endIndex": 20,
"text": "next to last",
"type": "builtin.ordinalV2.relative"
}
],
"endpos": [
{
"startIndex": 24,
"endIndex": 28,
"text": "last",
"type": "builtin.ordinalV2.relative"
}
],
"parent": [
{
"startIndex": 56,
"endIndex": 69,
"text": "homer simpson",
"type": "builtin.personName"
}
],
"child": [
{
"startIndex": 87,
"endIndex": 99,
"text": "lisa simpson",
"type": "builtin.personName"
}
]
},
"startloc": [
{
"type": "city",
"location": "london"
}
],
"endloc": [
{
"type": "city",
"location": "jakarta"
}
],
"startpos": [
{
"relativeTo": "end",
"offset": -1
}
],
"endpos": [
{
"relativeTo": "end",
"offset": 0
}
],
"parent": [
"homer simpson"
],
"child": [
"lisa simpson"
]
},
"sentiment": {
"label": "neutral",
"score": 0.5
},
"text": "go from next to last to last move london to jakarta and homer simpson is the parent of lisa simpson",
"v2": {
"query": "go from next to last to last move london to jakarta and homer simpson is the parent of lisa simpson",
"topScoringIntent": {
"intent": "Roles",
"score": 0.999204934
},
"entities": [
{
"endIndex": 39,
"entity": "london",
"role": "startloc",
"startIndex": 34,
"type": "builtin.geographyV2.city"
},
{
"endIndex": 50,
"entity": "jakarta",
"role": "endloc",
"startIndex": 44,
"type": "builtin.geographyV2.city"
},
{
"endIndex": 19,
"entity": "next to last",
"resolution": {
"offset": "-1",
"relativeTo": "end"
},
"role": "startpos",
"startIndex": 8,
"type": "builtin.ordinalV2.relative"
},
{
"endIndex": 27,
"entity": "last",
"resolution": {
"offset": "0",
"relativeTo": "end"
},
"role": "endpos",
"startIndex": 24,
"type": "builtin.ordinalV2.relative"
},
{
"endIndex": 68,
"entity": "homer simpson",
"role": "parent",
"startIndex": 56,
"type": "builtin.personName"
},
{
"endIndex": 98,
"entity": "lisa simpson",
"role": "child",
"startIndex": 87,
"type": "builtin.personName"
}
],
"intents": [
{
"intent": "Roles",
@ -173,61 +220,14 @@
"score": 5.293933E-05
}
],
"entities": [
{
"entity": "london",
"type": "builtin.geographyV2.city",
"startIndex": 34,
"endIndex": 39,
"role": "startloc"
},
{
"entity": "jakarta",
"type": "builtin.geographyV2.city",
"startIndex": 44,
"endIndex": 50,
"role": "endloc"
},
{
"entity": "next to last",
"type": "builtin.ordinalV2.relative",
"startIndex": 8,
"endIndex": 19,
"resolution": {
"offset": "-1",
"relativeTo": "end"
},
"role": "startpos"
},
{
"entity": "last",
"type": "builtin.ordinalV2.relative",
"startIndex": 24,
"endIndex": 27,
"resolution": {
"offset": "0",
"relativeTo": "end"
},
"role": "endpos"
},
{
"entity": "homer simpson",
"type": "builtin.personName",
"startIndex": 56,
"endIndex": 68,
"role": "parent"
},
{
"entity": "lisa simpson",
"type": "builtin.personName",
"startIndex": 87,
"endIndex": 98,
"role": "child"
}
],
"query": "go from next to last to last move london to jakarta and homer simpson is the parent of lisa simpson",
"sentimentAnalysis": {
"label": "neutral",
"score": 0.5
},
"topScoringIntent": {
"intent": "Roles",
"score": 0.999204934
}
}
}

Просмотреть файл

@ -1,109 +1,139 @@
{
"text": "email about something wicked this way comes from bart simpson and also kb435",
"intents": {
"search": {
"score": 0.9999993
},
"EntityTests": {
"score": 1.044335E-05
},
"Roles": {
"score": 5.98274755E-06
},
"Travel": {
"score": 3.09763345E-06
},
"None": {
"score": 2.38094663E-06
},
"Weather_GetForecast": {
"score": 1.02792524E-06
},
"SpecifyName": {
"score": 3.0666667E-09
},
"Delivery": {
"score": 1.8E-09
},
"Greeting": {
"score": 1.0875E-09
},
"Cancel": {
"score": 1.01764708E-09
},
"Help": {
"score": 1.01764708E-09
}
},
"entities": {
"$instance": {
"personName": [
"extra": [
{
"startIndex": 49,
"endIndex": 61,
"text": "bart simpson",
"type": "builtin.personName"
"endIndex": 76,
"startIndex": 71,
"text": "kb435",
"type": "subject"
}
],
"Part": [
{
"startIndex": 71,
"endIndex": 76,
"startIndex": 71,
"text": "kb435",
"type": "Part"
}
],
"subject": [
{
"startIndex": 12,
"endIndex": 43,
"text": "something wicked this way comes",
"type": "subject"
}
],
"person": [
{
"startIndex": 49,
"endIndex": 61,
"startIndex": 49,
"text": "bart simpson",
"type": "person"
}
],
"extra": [
"personName": [
{
"startIndex": 71,
"endIndex": 76,
"text": "kb435",
"endIndex": 61,
"startIndex": 49,
"text": "bart simpson",
"type": "builtin.personName"
}
],
"subject": [
{
"endIndex": 43,
"startIndex": 12,
"text": "something wicked this way comes",
"type": "subject"
}
]
},
"personName": [
"bart simpson"
"extra": [
"kb435"
],
"Part": [
"kb435"
],
"subject": [
"something wicked this way comes"
],
"person": [
"bart simpson"
],
"extra": [
"kb435"
"personName": [
"bart simpson"
],
"subject": [
"something wicked this way comes"
]
},
"intents": {
"Cancel": {
"score": 1.01764708E-09
},
"Delivery": {
"score": 1.8E-09
},
"EntityTests": {
"score": 1.044335E-05
},
"Greeting": {
"score": 1.0875E-09
},
"Help": {
"score": 1.01764708E-09
},
"None": {
"score": 2.38094663E-06
},
"Roles": {
"score": 5.98274755E-06
},
"search": {
"score": 0.9999993
},
"SpecifyName": {
"score": 3.0666667E-09
},
"Travel": {
"score": 3.09763345E-06
},
"Weather_GetForecast": {
"score": 1.02792524E-06
}
},
"sentiment": {
"label": "negative",
"score": 0.210341513
},
"text": "email about something wicked this way comes from bart simpson and also kb435",
"v2": {
"query": "email about something wicked this way comes from bart simpson and also kb435",
"topScoringIntent": {
"intent": "search",
"score": 0.9999993
},
"entities": [
{
"endIndex": 60,
"entity": "bart simpson",
"startIndex": 49,
"type": "builtin.personName"
},
{
"endIndex": 75,
"entity": "kb435",
"startIndex": 71,
"type": "Part"
},
{
"endIndex": 42,
"entity": "something wicked this way comes",
"role": "",
"startIndex": 12,
"type": "subject"
},
{
"endIndex": 60,
"entity": "bart simpson",
"role": "",
"startIndex": 49,
"type": "person"
},
{
"endIndex": 75,
"entity": "kb435",
"role": "extra",
"startIndex": 71,
"type": "subject"
}
],
"intents": [
{
"intent": "search",
@ -150,44 +180,14 @@
"score": 1.01764708E-09
}
],
"entities": [
{
"entity": "bart simpson",
"type": "builtin.personName",
"startIndex": 49,
"endIndex": 60
},
{
"entity": "kb435",
"type": "Part",
"startIndex": 71,
"endIndex": 75
},
{
"entity": "something wicked this way comes",
"type": "subject",
"startIndex": 12,
"endIndex": 42,
"role": ""
},
{
"entity": "bart simpson",
"type": "person",
"startIndex": 49,
"endIndex": 60,
"role": ""
},
{
"entity": "kb435",
"type": "subject",
"startIndex": 71,
"endIndex": 75,
"role": "extra"
}
],
"query": "email about something wicked this way comes from bart simpson and also kb435",
"sentimentAnalysis": {
"label": "negative",
"score": 0.210341513
},
"topScoringIntent": {
"intent": "search",
"score": 0.9999993
}
}
}

Просмотреть файл

@ -1,55 +1,19 @@
{
"text": "http://foo.com is where you can get a weather forecast for seattle",
"intents": {
"Weather_GetForecast": {
"score": 0.669524968
},
"EntityTests": {
"score": 0.342939854
},
"Roles": {
"score": 0.0432791822
},
"None": {
"score": 0.0175834317
},
"search": {
"score": 0.014743383
},
"Travel": {
"score": 0.013458414
},
"SpecifyName": {
"score": 0.00172697916
},
"Delivery": {
"score": 0.0011408634
},
"Help": {
"score": 0.0005502715
},
"Cancel": {
"score": 0.000171828113
},
"Greeting": {
"score": 0.0001518702
}
},
"entities": {
"$instance": {
"Composite2": [
{
"startIndex": 0,
"endIndex": 66,
"score": 0.456283748,
"startIndex": 0,
"text": "http : / / foo . com is where you can get a weather forecast for seattle",
"type": "Composite2",
"score": 0.456283748
"type": "Composite2"
}
],
"geographyV2": [
{
"startIndex": 59,
"endIndex": 66,
"startIndex": 59,
"text": "seattle",
"type": "builtin.geographyV2.city"
}
@ -60,19 +24,19 @@
"$instance": {
"url": [
{
"startIndex": 0,
"endIndex": 14,
"startIndex": 0,
"text": "http://foo.com",
"type": "builtin.url"
}
],
"Weather_Location": [
{
"startIndex": 59,
"endIndex": 66,
"score": 0.76184386,
"startIndex": 59,
"text": "seattle",
"type": "Weather.Location",
"score": 0.76184386
"type": "Weather.Location"
}
]
},
@ -86,21 +50,99 @@
],
"geographyV2": [
{
"type": "city",
"location": "seattle"
"location": "seattle",
"type": "city"
}
]
},
"intents": {
"Cancel": {
"score": 0.000171828113
},
"Delivery": {
"score": 0.0011408634
},
"EntityTests": {
"score": 0.342939854
},
"Greeting": {
"score": 0.0001518702
},
"Help": {
"score": 0.0005502715
},
"None": {
"score": 0.0175834317
},
"Roles": {
"score": 0.0432791822
},
"search": {
"score": 0.014743383
},
"SpecifyName": {
"score": 0.00172697916
},
"Travel": {
"score": 0.013458414
},
"Weather_GetForecast": {
"score": 0.669524968
}
},
"sentiment": {
"label": "neutral",
"score": 0.5
},
"text": "http://foo.com is where you can get a weather forecast for seattle",
"v2": {
"query": "http://foo.com is where you can get a weather forecast for seattle",
"topScoringIntent": {
"intent": "Weather.GetForecast",
"score": 0.669524968
},
"compositeEntities": [
{
"children": [
{
"type": "builtin.url",
"value": "http://foo.com"
},
{
"type": "Weather.Location",
"value": "seattle"
}
],
"parentType": "Composite2",
"value": "http : / / foo . com is where you can get a weather forecast for seattle"
}
],
"entities": [
{
"endIndex": 65,
"entity": "seattle",
"score": 0.76184386,
"startIndex": 59,
"type": "Weather.Location"
},
{
"endIndex": 65,
"entity": "http : / / foo . com is where you can get a weather forecast for seattle",
"score": 0.456283748,
"startIndex": 0,
"type": "Composite2"
},
{
"endIndex": 65,
"entity": "seattle",
"startIndex": 59,
"type": "builtin.geographyV2.city"
},
{
"endIndex": 13,
"entity": "http://foo.com",
"resolution": {
"value": "http://foo.com"
},
"startIndex": 0,
"type": "builtin.url"
}
],
"intents": [
{
"intent": "Weather.GetForecast",
@ -147,56 +189,14 @@
"score": 0.0001518702
}
],
"entities": [
{
"entity": "seattle",
"type": "Weather.Location",
"startIndex": 59,
"endIndex": 65,
"score": 0.76184386
},
{
"entity": "http : / / foo . com is where you can get a weather forecast for seattle",
"type": "Composite2",
"startIndex": 0,
"endIndex": 65,
"score": 0.456283748
},
{
"entity": "seattle",
"type": "builtin.geographyV2.city",
"startIndex": 59,
"endIndex": 65
},
{
"entity": "http://foo.com",
"type": "builtin.url",
"startIndex": 0,
"endIndex": 13,
"resolution": {
"value": "http://foo.com"
}
}
],
"compositeEntities": [
{
"parentType": "Composite2",
"value": "http : / / foo . com is where you can get a weather forecast for seattle",
"children": [
{
"type": "builtin.url",
"value": "http://foo.com"
},
{
"type": "Weather.Location",
"value": "seattle"
}
]
}
],
"query": "http://foo.com is where you can get a weather forecast for seattle",
"sentimentAnalysis": {
"label": "neutral",
"score": 0.5
},
"topScoringIntent": {
"intent": "Weather.GetForecast",
"score": 0.669524968
}
}
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -1,106 +1,148 @@
{
"text": "http://foo.com is where you can get a weather forecast for seattle",
"intents": {
"Weather_GetForecast": {
"score": 0.669524968
},
"EntityTests": {
"score": 0.342939854
},
"Roles": {
"score": 0.0432791822
},
"None": {
"score": 0.0175834317
},
"search": {
"score": 0.014743383
},
"Travel": {
"score": 0.013458414
},
"SpecifyName": {
"score": 0.00172697916
},
"Delivery": {
"score": 0.0011408634
},
"Help": {
"score": 0.0005502715
},
"Cancel": {
"score": 0.000171828113
},
"Greeting": {
"score": 0.0001518702
}
},
"entities": {
"geographyV2": [
{
"type": "city",
"location": "seattle"
}
],
"$instance": {
"Composite2": [
{
"endIndex": 66,
"score": 0.456283748,
"startIndex": 0,
"text": "http : / / foo . com is where you can get a weather forecast for seattle",
"type": "Composite2"
}
],
"geographyV2": [
{
"endIndex": 66,
"startIndex": 59,
"text": "seattle",
"type": "builtin.geographyV2.city"
}
]
},
"Composite2": [
{
"url": [
"http://foo.com"
],
"Weather_Location": [
"seattle"
],
"$instance": {
"url": [
{
"startIndex": 0,
"endIndex": 14,
"startIndex": 0,
"text": "http://foo.com",
"type": "builtin.url"
}
],
"Weather_Location": [
{
"startIndex": 59,
"endIndex": 66,
"text": "seattle",
"score": 0.76184386,
"startIndex": 59,
"text": "seattle",
"type": "Weather.Location"
}
]
}
},
"url": [
"http://foo.com"
],
"Weather_Location": [
"seattle"
]
}
],
"$instance": {
"Composite2": [
{
"startIndex": 0,
"endIndex": 66,
"text": "http : / / foo . com is where you can get a weather forecast for seattle",
"score": 0.456283748,
"type": "Composite2"
}
],
"geographyV2": [
{
"startIndex": 59,
"endIndex": 66,
"text": "seattle",
"type": "builtin.geographyV2.city"
}
]
"geographyV2": [
{
"location": "seattle",
"type": "city"
}
]
},
"intents": {
"Cancel": {
"score": 0.000171828113
},
"Delivery": {
"score": 0.0011408634
},
"EntityTests": {
"score": 0.342939854
},
"Greeting": {
"score": 0.0001518702
},
"Help": {
"score": 0.0005502715
},
"None": {
"score": 0.0175834317
},
"Roles": {
"score": 0.0432791822
},
"search": {
"score": 0.014743383
},
"SpecifyName": {
"score": 0.00172697916
},
"Travel": {
"score": 0.013458414
},
"Weather_GetForecast": {
"score": 0.669524968
}
},
"sentiment": {
"label": "neutral",
"score": 0.5
},
"text": "http://foo.com is where you can get a weather forecast for seattle",
"v2": {
"query": "http://foo.com is where you can get a weather forecast for seattle",
"topScoringIntent": {
"intent": "Weather.GetForecast",
"score": 0.669524968
},
"compositeEntities": [
{
"children": [
{
"type": "builtin.url",
"value": "http://foo.com"
},
{
"type": "Weather.Location",
"value": "seattle"
}
],
"parentType": "Composite2",
"value": "http : / / foo . com is where you can get a weather forecast for seattle"
}
],
"entities": [
{
"endIndex": 65,
"entity": "seattle",
"score": 0.76184386,
"startIndex": 59,
"type": "Weather.Location"
},
{
"endIndex": 65,
"entity": "http : / / foo . com is where you can get a weather forecast for seattle",
"score": 0.456283748,
"startIndex": 0,
"type": "Composite2"
},
{
"endIndex": 65,
"entity": "seattle",
"startIndex": 59,
"type": "builtin.geographyV2.city"
},
{
"endIndex": 13,
"entity": "http://foo.com",
"resolution": {
"value": "http://foo.com"
},
"startIndex": 0,
"type": "builtin.url"
}
],
"intents": [
{
"intent": "Weather.GetForecast",
@ -147,56 +189,14 @@
"score": 0.0001518702
}
],
"entities": [
{
"entity": "seattle",
"type": "Weather.Location",
"startIndex": 59,
"endIndex": 65,
"score": 0.76184386
},
{
"entity": "http : / / foo . com is where you can get a weather forecast for seattle",
"type": "Composite2",
"startIndex": 0,
"endIndex": 65,
"score": 0.456283748
},
{
"entity": "seattle",
"type": "builtin.geographyV2.city",
"startIndex": 59,
"endIndex": 65
},
{
"entity": "http://foo.com",
"type": "builtin.url",
"startIndex": 0,
"endIndex": 13,
"resolution": {
"value": "http://foo.com"
}
}
],
"compositeEntities": [
{
"parentType": "Composite2",
"value": "http : / / foo . com is where you can get a weather forecast for seattle",
"children": [
{
"type": "builtin.url",
"value": "http://foo.com"
},
{
"type": "Weather.Location",
"value": "seattle"
}
]
}
],
"query": "http://foo.com is where you can get a weather forecast for seattle",
"sentimentAnalysis": {
"label": "neutral",
"score": 0.5
},
"topScoringIntent": {
"intent": "Weather.GetForecast",
"score": 0.669524968
}
}
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.1.1" />
<PackageReference Include="MSTest.TestFramework" Version="1.4.0" />
<PackageReference Include="Newtonsoft.Json" Version="10.0.3" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\libraries\Microsoft.Bot.Builder\Microsoft.Bot.Builder.csproj" />
<ProjectReference Include="..\..\libraries\Microsoft.Bot.Schema\Microsoft.Bot.Schema.csproj" />
</ItemGroup>
</Project>

Просмотреть файл

@ -1,24 +1,11 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Bot.Builder.Adapters;
using Microsoft.Bot.Configuration;
using Microsoft.Bot.Schema;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using RichardSzalay.MockHttp;
namespace Microsoft.Bot.Builder.AI.Luis.Tests
namespace Microsoft.Bot.Builder.AI.Luis.TestUtils
{
public class MockedHttpClientHandler : HttpClientHandler
{

Просмотреть файл

@ -0,0 +1,189 @@
using System;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Bot.Builder.Adapters;
using Microsoft.Bot.Schema;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace Microsoft.Bot.Builder.AI.Luis.TestUtils
{
public class Utils
{
public static TurnContext GetContext(string utterance)
{
var testAdapter = new TestAdapter();
var activity = new Activity
{
Type = ActivityTypes.Message,
Text = utterance,
Conversation = new ConversationAccount(),
Recipient = new ChannelAccount(),
From = new ChannelAccount(),
};
return new TurnContext(testAdapter, activity);
}
public static TurnContext GetNonMessageContext(string utterance)
{
var b = new TestAdapter();
var a = new Activity
{
Type = ActivityTypes.ConversationUpdate,
Text = utterance,
Conversation = new ConversationAccount(),
Recipient = new ChannelAccount(),
From = new ChannelAccount(),
};
return new TurnContext(b, a);
}
public static void AssertScore(JToken scoreToken)
{
var score = (double)scoreToken;
Assert.IsTrue(score >= 0);
Assert.IsTrue(score <= 1);
}
// Compare two JSON structures and ensure entity and intent scores are within delta
public static bool WithinDelta(JToken token1, JToken token2, double delta, bool compare = false)
{
var withinDelta = true;
if (token1.Type == JTokenType.Object && token2.Type == JTokenType.Object)
{
var obj1 = (JObject)token1;
var obj2 = (JObject)token2;
withinDelta = obj1.Count == obj2.Count;
foreach (var property in obj1)
{
if (!withinDelta)
{
break;
}
withinDelta = obj2.TryGetValue(property.Key, out var val2) && WithinDelta(property.Value, val2, delta, compare || property.Key == "score" || property.Key == "intents");
}
}
else if (token1.Type == JTokenType.Array && token2.Type == JTokenType.Array)
{
var arr1 = (JArray)token1;
var arr2 = (JArray)token2;
withinDelta = arr1.Count == arr2.Count;
for (var i = 0; withinDelta && i < arr1.Count; ++i)
{
withinDelta = WithinDelta(arr1[i], arr2[i], delta);
if (!withinDelta)
{
break;
}
}
}
else if (!token1.Equals(token2))
{
if (token1.Type == token2.Type)
{
var val1 = (JValue)token1;
var val2 = (JValue)token2;
withinDelta = false;
if (compare &&
double.TryParse((string)val1, out var num1)
&& double.TryParse((string)val2, out var num2))
{
withinDelta = Math.Abs(num1 - num2) < delta;
}
}
else
{
withinDelta = false;
}
}
return withinDelta;
}
public static JToken SortJSON(JToken source)
{
var result = source;
if (source is JObject obj)
{
var nobj = new JObject();
foreach (var property in obj.Properties().OrderBy(p => p.Name))
{
nobj.Add(property.Name, SortJSON(property.Value));
}
result = nobj;
}
else if (source is JArray arr)
{
var narr = new JArray();
foreach (var elt in arr)
{
narr.Add(SortJSON(elt));
}
result = narr;
}
return result;
}
public static JObject Json<T>(T result, string version, JObject oracle)
{
var json = (JObject)JsonConvert.DeserializeObject(JsonConvert.SerializeObject(result, new JsonSerializerSettings { Formatting = Formatting.Indented, NullValueHandling = NullValueHandling.Ignore }));
if (oracle["v2"] != null)
{
json["v2"] = oracle["v2"];
}
if (oracle["v3"] != null)
{
json["v3"] = oracle["v3"];
}
json[version] = json["luisResult"];
json.Remove("luisResult");
return (JObject)Utils.SortJSON(json);
}
// To create a file to test:
// 1) Create a <name>.json file with an object { text:<query> } in it.
// 2) Run this test which will fail and generate a <name>.json.new file.
// 3) Check the .new file and if correct, replace the original .json file with it.
// The version parameter controls where in the expected json the luisResult is put. This allows multiple endpoint responses like from
// LUIS V2 and V3 endpoints.
public static async Task TestJsonOracle<T>(string expectedPath, string version, Func<JObject, IRecognizer> buildRecognizer)
where T : IRecognizerConvert, new()
{
JObject expectedJson;
using (var expectedJsonReader = new JsonTextReader(new StreamReader(expectedPath)))
{
expectedJson = (JObject)await JToken.ReadFromAsync(expectedJsonReader);
}
var newPath = expectedPath + ".new";
var query = expectedJson["text"].ToString();
var context = GetContext(query);
var luisRecognizer = buildRecognizer(expectedJson);
var typedResult = await luisRecognizer.RecognizeAsync<T>(context, CancellationToken.None);
var typedJson = Utils.Json(typedResult, version, expectedJson);
if (!Utils.WithinDelta(expectedJson, typedJson, 0.1))
{
using (var writer = new StreamWriter(newPath))
{
writer.Write(typedJson);
}
Assert.Fail($"Returned JSON in {newPath} != expected JSON in {expectedPath}");
}
else
{
File.Delete(expectedPath + ".new");
}
}
}
}

Просмотреть файл

@ -0,0 +1,428 @@
{
"entities": {
"$instance": {
"Composite2": [
{
"length": 69,
"modelType": "Composite Entity Extractor",
"modelTypeId": 4,
"recognitionSources": [
"model"
],
"score": 0.9501543,
"startIndex": 0,
"text": "http://foo.com is where you can fly from seattle to dallas via denver",
"type": "Composite2"
}
],
"geographyV2": [
{
"length": 7,
"modelType": "Prebuilt Entity Extractor",
"modelTypeId": 2,
"recognitionSources": [
"model"
],
"startIndex": 41,
"text": "seattle",
"type": "builtin.geographyV2.city"
}
]
},
"Composite2": [
{
"$instance": {
"City": [
{
"length": 6,
"modelType": "Hierarchical Entity Extractor",
"modelTypeId": 3,
"recognitionSources": [
"model"
],
"score": 0.9857553,
"startIndex": 63,
"text": "denver",
"type": "City"
}
],
"City::From": [
{
"length": 7,
"modelType": "Hierarchical Entity Extractor",
"modelTypeId": 3,
"recognitionSources": [
"model"
],
"score": 0.9997592,
"startIndex": 41,
"text": "seattle",
"type": "City::From"
}
],
"City::To": [
{
"length": 6,
"modelType": "Hierarchical Entity Extractor",
"modelTypeId": 3,
"recognitionSources": [
"model"
],
"score": 0.9990426,
"startIndex": 52,
"text": "dallas",
"type": "City::To"
}
],
"url": [
{
"length": 14,
"modelType": "Prebuilt Entity Extractor",
"modelTypeId": 2,
"recognitionSources": [
"model"
],
"startIndex": 0,
"text": "http://foo.com",
"type": "builtin.url"
}
]
},
"City": [
"denver"
],
"City::From": [
"seattle"
],
"City::To": [
"dallas"
],
"url": [
"http://foo.com"
]
}
],
"geographyV2": [
"seattle"
]
},
"intents": {
"Cancel": {
"score": 0.000227437369
},
"Delivery": {
"score": 0.001310123
},
"EntityTests": {
"score": 0.94500196
},
"Greeting": {
"score": 0.000152356763
},
"Help": {
"score": 0.000547201431
},
"None": {
"score": 0.004187195
},
"Roles": {
"score": 0.0300086979
},
"search": {
"score": 0.0211907644
},
"SpecifyName": {
"score": 0.00157370011
},
"Travel": {
"score": 0.0778588
},
"Weather_GetForecast": {
"score": 0.0237181056
}
},
"sentiment": {
"label": "neutral",
"score": 0.5
},
"text": "http://foo.com is where you can fly from seattle to dallas via denver",
"v2": {
"compositeEntities": [
{
"children": [
{
"type": "City",
"value": "denver"
},
{
"type": "builtin.url",
"value": "http://foo.com"
},
{
"type": "City::From",
"value": "seattle"
},
{
"type": "City::To",
"value": "dallas"
}
],
"parentType": "Composite2",
"value": "http : / / foo . com is where you can fly from seattle to dallas via denver"
}
],
"entities": [
{
"endIndex": 57,
"entity": "dallas",
"score": 0.998420954,
"startIndex": 52,
"type": "City::To"
},
{
"endIndex": 47,
"entity": "seattle",
"score": 0.9992566,
"startIndex": 41,
"type": "City::From"
},
{
"endIndex": 68,
"entity": "denver",
"score": 0.984729,
"startIndex": 63,
"type": "City"
},
{
"endIndex": 68,
"entity": "http : / / foo . com is where you can fly from seattle to dallas via denver",
"score": 0.962469339,
"startIndex": 0,
"type": "Composite2"
},
{
"endIndex": 47,
"entity": "seattle",
"startIndex": 41,
"type": "builtin.geographyV2.city"
},
{
"endIndex": 13,
"entity": "http://foo.com",
"resolution": {
"value": "http://foo.com"
},
"startIndex": 0,
"type": "builtin.url"
}
],
"intents": [
{
"intent": "EntityTests",
"score": 0.944987357
},
{
"intent": "Travel",
"score": 0.0452092439
},
{
"intent": "Roles",
"score": 0.0297764745
},
{
"intent": "Weather.GetForecast",
"score": 0.0231683664
},
{
"intent": "search",
"score": 0.008871362
},
{
"intent": "None",
"score": 0.004223796
},
{
"intent": "SpecifyName",
"score": 0.00236839615
},
{
"intent": "Delivery",
"score": 0.0013232599
},
{
"intent": "Help",
"score": 0.0005449379
},
{
"intent": "Cancel",
"score": 0.000226470322
},
{
"intent": "Greeting",
"score": 0.000151786517
}
],
"query": "http://foo.com is where you can fly from seattle to dallas via denver",
"sentimentAnalysis": {
"label": "neutral",
"score": 0.5
},
"topScoringIntent": {
"intent": "EntityTests",
"score": 0.944987357
}
},
"v3": {
"prediction": {
"entities": {
"$instance": {
"Composite2": [
{
"length": 69,
"modelType": "Composite Entity Extractor",
"modelTypeId": 4,
"recognitionSources": [
"model"
],
"score": 0.9501543,
"startIndex": 0,
"text": "http://foo.com is where you can fly from seattle to dallas via denver",
"type": "Composite2"
}
],
"geographyV2": [
{
"length": 7,
"modelType": "Prebuilt Entity Extractor",
"modelTypeId": 2,
"recognitionSources": [
"model"
],
"startIndex": 41,
"text": "seattle",
"type": "builtin.geographyV2.city"
}
]
},
"Composite2": [
{
"$instance": {
"City": [
{
"length": 6,
"modelType": "Hierarchical Entity Extractor",
"modelTypeId": 3,
"recognitionSources": [
"model"
],
"score": 0.9857553,
"startIndex": 63,
"text": "denver",
"type": "City"
}
],
"City::From": [
{
"length": 7,
"modelType": "Hierarchical Entity Extractor",
"modelTypeId": 3,
"recognitionSources": [
"model"
],
"score": 0.9997592,
"startIndex": 41,
"text": "seattle",
"type": "City::From"
}
],
"City::To": [
{
"length": 6,
"modelType": "Hierarchical Entity Extractor",
"modelTypeId": 3,
"recognitionSources": [
"model"
],
"score": 0.9990426,
"startIndex": 52,
"text": "dallas",
"type": "City::To"
}
],
"url": [
{
"length": 14,
"modelType": "Prebuilt Entity Extractor",
"modelTypeId": 2,
"recognitionSources": [
"model"
],
"startIndex": 0,
"text": "http://foo.com",
"type": "builtin.url"
}
]
},
"City": [
"denver"
],
"City::From": [
"seattle"
],
"City::To": [
"dallas"
],
"url": [
"http://foo.com"
]
}
],
"geographyV2": [
"seattle"
]
},
"intents": {
"Cancel": {
"score": 0.000227437369
},
"Delivery": {
"score": 0.001310123
},
"EntityTests": {
"score": 0.94500196
},
"Greeting": {
"score": 0.000152356763
},
"Help": {
"score": 0.000547201431
},
"None": {
"score": 0.004187195
},
"Roles": {
"score": 0.0300086979
},
"search": {
"score": 0.0211907644
},
"SpecifyName": {
"score": 0.00157370011
},
"Travel": {
"score": 0.0778588
},
"Weather.GetForecast": {
"score": 0.0237181056
}
},
"normalizedQuery": "http://foo.com is where you can fly from seattle to dallas via denver",
"sentiment": {
"label": "neutral",
"score": 0.5
},
"topIntent": "EntityTests"
},
"query": "http://foo.com is where you can fly from seattle to dallas via denver"
}
}

Просмотреть файл

@ -0,0 +1,451 @@
{
"entities": {
"$instance": {
"Destination": [
{
"length": 8,
"modelType": "Composite Entity Extractor",
"modelTypeId": 4,
"recognitionSources": [
"model"
],
"role": "Destination",
"score": 0.982723653,
"startIndex": 25,
"text": "12346 WA",
"type": "Address"
}
],
"Source": [
{
"length": 8,
"modelType": "Composite Entity Extractor",
"modelTypeId": 4,
"recognitionSources": [
"model"
],
"role": "Source",
"score": 0.933905244,
"startIndex": 13,
"text": "12345 VA",
"type": "Address"
}
]
},
"Destination": [
{
"$instance": {
"number": [
{
"length": 5,
"modelType": "Prebuilt Entity Extractor",
"modelTypeId": 2,
"recognitionSources": [
"model"
],
"startIndex": 25,
"text": "12346",
"type": "builtin.number"
}
],
"State": [
{
"length": 2,
"modelType": "Entity Extractor",
"modelTypeId": 1,
"recognitionSources": [
"model"
],
"score": 0.9893949,
"startIndex": 31,
"text": "WA",
"type": "State"
}
]
},
"number": [
12346
],
"State": [
"WA"
]
}
],
"Source": [
{
"$instance": {
"number": [
{
"length": 5,
"modelType": "Prebuilt Entity Extractor",
"modelTypeId": 2,
"recognitionSources": [
"model"
],
"startIndex": 13,
"text": "12345",
"type": "builtin.number"
}
],
"State": [
{
"length": 2,
"modelType": "Entity Extractor",
"modelTypeId": 1,
"recognitionSources": [
"model"
],
"score": 0.937490761,
"startIndex": 19,
"text": "VA",
"type": "State"
}
]
},
"number": [
12345
],
"State": [
"VA"
]
}
]
},
"intents": {
"Cancel": {
"score": 1.01764708E-09
},
"Delivery": {
"score": 0.00238572317
},
"EntityTests": {
"score": 4.757576E-10
},
"Greeting": {
"score": 1.0875E-09
},
"Help": {
"score": 1.01764708E-09
},
"None": {
"score": 1.17844979E-06
},
"Roles": {
"score": 0.999911964
},
"search": {
"score": 9.494859E-06
},
"SpecifyName": {
"score": 3.0666667E-09
},
"Travel": {
"score": 3.09763345E-06
},
"Weather_GetForecast": {
"score": 1.02792524E-06
}
},
"sentiment": {
"label": "neutral",
"score": 0.5
},
"text": "Deliver from 12345 VA to 12346 WA",
"v2": {
"compositeEntities": [
{
"children": [
{
"type": "builtin.number",
"value": "12345"
},
{
"type": "State",
"value": "va"
}
],
"parentType": "Address",
"value": "12345 va"
},
{
"children": [
{
"type": "builtin.number",
"value": "12346"
},
{
"type": "State",
"value": "wa"
}
],
"parentType": "Address",
"value": "12346 wa"
}
],
"entities": [
{
"endIndex": 20,
"entity": "va",
"score": 0.9417667,
"startIndex": 19,
"type": "State"
},
{
"endIndex": 32,
"entity": "wa",
"score": 0.9899993,
"startIndex": 31,
"type": "State"
},
{
"endIndex": 20,
"entity": "12345 va",
"role": "Source",
"score": 0.9377045,
"startIndex": 13,
"type": "Address"
},
{
"endIndex": 32,
"entity": "12346 wa",
"role": "Destination",
"score": 0.9818967,
"startIndex": 25,
"type": "Address"
},
{
"endIndex": 17,
"entity": "12345",
"resolution": {
"subtype": "integer",
"value": "12345"
},
"startIndex": 13,
"type": "builtin.number"
},
{
"endIndex": 29,
"entity": "12346",
"resolution": {
"subtype": "integer",
"value": "12346"
},
"startIndex": 25,
"type": "builtin.number"
}
],
"intents": [
{
"intent": "Roles",
"score": 0.999888361
},
{
"intent": "Delivery",
"score": 0.00234605442
},
{
"intent": "search",
"score": 9.343347E-06
},
{
"intent": "Travel",
"score": 3.04712876E-06
},
{
"intent": "None",
"score": 1.15824787E-06
},
{
"intent": "Weather.GetForecast",
"score": 1.01009994E-06
},
{
"intent": "SpecifyName",
"score": 3.01666669E-09
},
{
"intent": "Greeting",
"score": 1.06875E-09
},
{
"intent": "Cancel",
"score": 1E-09
},
{
"intent": "Help",
"score": 1E-09
},
{
"intent": "EntityTests",
"score": 4.6666665E-10
}
],
"query": "Deliver from 12345 VA to 12346 WA",
"sentimentAnalysis": {
"label": "neutral",
"score": 0.5
},
"topScoringIntent": {
"intent": "Roles",
"score": 0.999888361
}
},
"v3": {
"prediction": {
"entities": {
"$instance": {
"Destination": [
{
"length": 8,
"modelType": "Composite Entity Extractor",
"modelTypeId": 4,
"recognitionSources": [
"model"
],
"role": "Destination",
"score": 0.982723653,
"startIndex": 25,
"text": "12346 WA",
"type": "Address"
}
],
"Source": [
{
"length": 8,
"modelType": "Composite Entity Extractor",
"modelTypeId": 4,
"recognitionSources": [
"model"
],
"role": "Source",
"score": 0.933905244,
"startIndex": 13,
"text": "12345 VA",
"type": "Address"
}
]
},
"Destination": [
{
"$instance": {
"number": [
{
"length": 5,
"modelType": "Prebuilt Entity Extractor",
"modelTypeId": 2,
"recognitionSources": [
"model"
],
"startIndex": 25,
"text": "12346",
"type": "builtin.number"
}
],
"State": [
{
"length": 2,
"modelType": "Entity Extractor",
"modelTypeId": 1,
"recognitionSources": [
"model"
],
"score": 0.9893949,
"startIndex": 31,
"text": "WA",
"type": "State"
}
]
},
"number": [
12346
],
"State": [
"WA"
]
}
],
"Source": [
{
"$instance": {
"number": [
{
"length": 5,
"modelType": "Prebuilt Entity Extractor",
"modelTypeId": 2,
"recognitionSources": [
"model"
],
"startIndex": 13,
"text": "12345",
"type": "builtin.number"
}
],
"State": [
{
"length": 2,
"modelType": "Entity Extractor",
"modelTypeId": 1,
"recognitionSources": [
"model"
],
"score": 0.937490761,
"startIndex": 19,
"text": "VA",
"type": "State"
}
]
},
"number": [
12345
],
"State": [
"VA"
]
}
]
},
"intents": {
"Cancel": {
"score": 1.01764708E-09
},
"Delivery": {
"score": 0.00238572317
},
"EntityTests": {
"score": 4.757576E-10
},
"Greeting": {
"score": 1.0875E-09
},
"Help": {
"score": 1.01764708E-09
},
"None": {
"score": 1.17844979E-06
},
"Roles": {
"score": 0.999911964
},
"search": {
"score": 9.494859E-06
},
"SpecifyName": {
"score": 3.0666667E-09
},
"Travel": {
"score": 3.09763345E-06
},
"Weather.GetForecast": {
"score": 1.02792524E-06
}
},
"normalizedQuery": "deliver from 12345 va to 12346 wa",
"sentiment": {
"label": "neutral",
"score": 0.5
},
"topIntent": "Roles"
},
"query": "Deliver from 12345 VA to 12346 WA"
}
}

Просмотреть файл

@ -0,0 +1,421 @@
{
"entities": {
"$instance": {
"child": [
{
"length": 12,
"modelType": "Prebuilt Entity Extractor",
"modelTypeId": 2,
"recognitionSources": [
"model"
],
"role": "child",
"startIndex": 87,
"text": "lisa simpson",
"type": "builtin.personName"
}
],
"endloc": [
{
"length": 7,
"modelType": "Prebuilt Entity Extractor",
"modelTypeId": 2,
"recognitionSources": [
"model"
],
"role": "endloc",
"startIndex": 44,
"text": "jakarta",
"type": "builtin.geographyV2.city"
}
],
"endpos": [
{
"length": 4,
"modelType": "Prebuilt Entity Extractor",
"modelTypeId": 2,
"recognitionSources": [
"model"
],
"role": "endpos",
"startIndex": 24,
"text": "last",
"type": "builtin.ordinalV2.relative"
}
],
"parent": [
{
"length": 13,
"modelType": "Prebuilt Entity Extractor",
"modelTypeId": 2,
"recognitionSources": [
"model"
],
"role": "parent",
"startIndex": 56,
"text": "homer simpson",
"type": "builtin.personName"
}
],
"startloc": [
{
"length": 6,
"modelType": "Prebuilt Entity Extractor",
"modelTypeId": 2,
"recognitionSources": [
"model"
],
"role": "startloc",
"startIndex": 34,
"text": "london",
"type": "builtin.geographyV2.city"
}
],
"startpos": [
{
"length": 12,
"modelType": "Prebuilt Entity Extractor",
"modelTypeId": 2,
"recognitionSources": [
"model"
],
"role": "startpos",
"startIndex": 8,
"text": "next to last",
"type": "builtin.ordinalV2.relative"
}
]
},
"child": [
"lisa simpson"
],
"endloc": [
"jakarta"
],
"endpos": [
{
"offset": 0,
"relativeTo": "end"
}
],
"parent": [
"homer simpson"
],
"startloc": [
"london"
],
"startpos": [
{
"offset": -1,
"relativeTo": "end"
}
]
},
"intents": {
"Cancel": {
"score": 0.000107549029
},
"Delivery": {
"score": 0.00123035291
},
"EntityTests": {
"score": 0.0009487789
},
"Greeting": {
"score": 5.293933E-05
},
"Help": {
"score": 0.0001358991
},
"None": {
"score": 0.0109820236
},
"Roles": {
"score": 0.999204934
},
"search": {
"score": 0.0309635121
},
"SpecifyName": {
"score": 0.0009410849
},
"Travel": {
"score": 0.01095186
},
"Weather_GetForecast": {
"score": 0.0106523167
}
},
"sentiment": {
"label": "neutral",
"score": 0.5
},
"text": "go from next to last to last move london to jakarta and homer simpson is the parent of lisa simpson",
"v2": {
"entities": [
{
"endIndex": 39,
"entity": "london",
"role": "startloc",
"startIndex": 34,
"type": "builtin.geographyV2.city"
},
{
"endIndex": 50,
"entity": "jakarta",
"role": "endloc",
"startIndex": 44,
"type": "builtin.geographyV2.city"
},
{
"endIndex": 19,
"entity": "next to last",
"resolution": {
"offset": "-1",
"relativeTo": "end"
},
"role": "startpos",
"startIndex": 8,
"type": "builtin.ordinalV2.relative"
},
{
"endIndex": 27,
"entity": "last",
"resolution": {
"offset": "0",
"relativeTo": "end"
},
"role": "endpos",
"startIndex": 24,
"type": "builtin.ordinalV2.relative"
},
{
"endIndex": 68,
"entity": "homer simpson",
"role": "parent",
"startIndex": 56,
"type": "builtin.personName"
},
{
"endIndex": 98,
"entity": "lisa simpson",
"role": "child",
"startIndex": 87,
"type": "builtin.personName"
}
],
"intents": [
{
"intent": "Roles",
"score": 0.999204934
},
{
"intent": "search",
"score": 0.0309635121
},
{
"intent": "None",
"score": 0.0109820236
},
{
"intent": "Travel",
"score": 0.01095186
},
{
"intent": "Weather.GetForecast",
"score": 0.0106523167
},
{
"intent": "Delivery",
"score": 0.00123035291
},
{
"intent": "EntityTests",
"score": 0.0009487789
},
{
"intent": "SpecifyName",
"score": 0.0009410849
},
{
"intent": "Help",
"score": 0.0001358991
},
{
"intent": "Cancel",
"score": 0.000107549029
},
{
"intent": "Greeting",
"score": 5.293933E-05
}
],
"query": "go from next to last to last move london to jakarta and homer simpson is the parent of lisa simpson",
"sentimentAnalysis": {
"label": "neutral",
"score": 0.5
},
"topScoringIntent": {
"intent": "Roles",
"score": 0.999204934
}
},
"v3": {
"prediction": {
"entities": {
"$instance": {
"child": [
{
"length": 12,
"modelType": "Prebuilt Entity Extractor",
"modelTypeId": 2,
"recognitionSources": [
"model"
],
"role": "child",
"startIndex": 87,
"text": "lisa simpson",
"type": "builtin.personName"
}
],
"endloc": [
{
"length": 7,
"modelType": "Prebuilt Entity Extractor",
"modelTypeId": 2,
"recognitionSources": [
"model"
],
"role": "endloc",
"startIndex": 44,
"text": "jakarta",
"type": "builtin.geographyV2.city"
}
],
"endpos": [
{
"length": 4,
"modelType": "Prebuilt Entity Extractor",
"modelTypeId": 2,
"recognitionSources": [
"model"
],
"role": "endpos",
"startIndex": 24,
"text": "last",
"type": "builtin.ordinalV2.relative"
}
],
"parent": [
{
"length": 13,
"modelType": "Prebuilt Entity Extractor",
"modelTypeId": 2,
"recognitionSources": [
"model"
],
"role": "parent",
"startIndex": 56,
"text": "homer simpson",
"type": "builtin.personName"
}
],
"startloc": [
{
"length": 6,
"modelType": "Prebuilt Entity Extractor",
"modelTypeId": 2,
"recognitionSources": [
"model"
],
"role": "startloc",
"startIndex": 34,
"text": "london",
"type": "builtin.geographyV2.city"
}
],
"startpos": [
{
"length": 12,
"modelType": "Prebuilt Entity Extractor",
"modelTypeId": 2,
"recognitionSources": [
"model"
],
"role": "startpos",
"startIndex": 8,
"text": "next to last",
"type": "builtin.ordinalV2.relative"
}
]
},
"child": [
"lisa simpson"
],
"endloc": [
"jakarta"
],
"endpos": [
{
"offset": 0,
"relativeTo": "end"
}
],
"parent": [
"homer simpson"
],
"startloc": [
"london"
],
"startpos": [
{
"offset": -1,
"relativeTo": "end"
}
]
},
"intents": {
"Cancel": {
"score": 0.000107549029
},
"Delivery": {
"score": 0.00123035291
},
"EntityTests": {
"score": 0.0009487789
},
"Greeting": {
"score": 5.293933E-05
},
"Help": {
"score": 0.0001358991
},
"None": {
"score": 0.0109820236
},
"Roles": {
"score": 0.999204934
},
"search": {
"score": 0.0309635121
},
"SpecifyName": {
"score": 0.0009410849
},
"Travel": {
"score": 0.01095186
},
"Weather.GetForecast": {
"score": 0.0106523167
}
},
"normalizedQuery": "go from next to last to last move london to jakarta and homer simpson is the parent of lisa simpson",
"sentiment": {
"label": "neutral",
"score": 0.5
},
"topIntent": "Roles"
},
"query": "go from next to last to last move london to jakarta and homer simpson is the parent of lisa simpson"
}
}

Просмотреть файл

@ -0,0 +1,350 @@
{
"entities": {
"$instance": {
"extra": [
{
"length": 5,
"modelType": "Pattern.Any Entity Extractor",
"modelTypeId": 7,
"recognitionSources": [
"model"
],
"role": "extra",
"startIndex": 71,
"text": "kb435",
"type": "subject"
}
],
"Part": [
{
"length": 5,
"modelType": "Regex Entity Extractor",
"modelTypeId": 8,
"recognitionSources": [
"model"
],
"startIndex": 71,
"text": "kb435",
"type": "Part"
}
],
"person": [
{
"length": 12,
"modelType": "Pattern.Any Entity Extractor",
"modelTypeId": 7,
"recognitionSources": [
"model"
],
"startIndex": 49,
"text": "bart simpson",
"type": "person"
}
],
"personName": [
{
"length": 12,
"modelType": "Prebuilt Entity Extractor",
"modelTypeId": 2,
"recognitionSources": [
"model"
],
"startIndex": 49,
"text": "bart simpson",
"type": "builtin.personName"
}
],
"subject": [
{
"length": 31,
"modelType": "Pattern.Any Entity Extractor",
"modelTypeId": 7,
"recognitionSources": [
"model"
],
"startIndex": 12,
"text": "something wicked this way comes",
"type": "subject"
}
]
},
"extra": [
"kb435"
],
"Part": [
"kb435"
],
"person": [
"bart simpson"
],
"personName": [
"bart simpson"
],
"subject": [
"something wicked this way comes"
]
},
"intents": {
"Cancel": {
"score": 1.01764708E-09
},
"Delivery": {
"score": 1.8E-09
},
"EntityTests": {
"score": 1.044335E-05
},
"Greeting": {
"score": 1.0875E-09
},
"Help": {
"score": 1.01764708E-09
},
"None": {
"score": 2.38094663E-06
},
"Roles": {
"score": 5.98274755E-06
},
"search": {
"score": 0.9999993
},
"SpecifyName": {
"score": 3.0666667E-09
},
"Travel": {
"score": 3.09763345E-06
},
"Weather_GetForecast": {
"score": 1.02792524E-06
}
},
"sentiment": {
"label": "negative",
"score": 0.210341513
},
"text": "email about something wicked this way comes from bart simpson and also kb435",
"v2": {
"entities": [
{
"endIndex": 60,
"entity": "bart simpson",
"startIndex": 49,
"type": "builtin.personName"
},
{
"endIndex": 75,
"entity": "kb435",
"startIndex": 71,
"type": "Part"
},
{
"endIndex": 42,
"entity": "something wicked this way comes",
"role": "",
"startIndex": 12,
"type": "subject"
},
{
"endIndex": 60,
"entity": "bart simpson",
"role": "",
"startIndex": 49,
"type": "person"
},
{
"endIndex": 75,
"entity": "kb435",
"role": "extra",
"startIndex": 71,
"type": "subject"
}
],
"intents": [
{
"intent": "search",
"score": 0.9999993
},
{
"intent": "EntityTests",
"score": 1.044335E-05
},
{
"intent": "Roles",
"score": 5.98274755E-06
},
{
"intent": "Travel",
"score": 3.09763345E-06
},
{
"intent": "None",
"score": 2.38094663E-06
},
{
"intent": "Weather.GetForecast",
"score": 1.02792524E-06
},
{
"intent": "SpecifyName",
"score": 3.0666667E-09
},
{
"intent": "Delivery",
"score": 1.8E-09
},
{
"intent": "Greeting",
"score": 1.0875E-09
},
{
"intent": "Cancel",
"score": 1.01764708E-09
},
{
"intent": "Help",
"score": 1.01764708E-09
}
],
"query": "email about something wicked this way comes from bart simpson and also kb435",
"sentimentAnalysis": {
"label": "negative",
"score": 0.210341513
},
"topScoringIntent": {
"intent": "search",
"score": 0.9999993
}
},
"v3": {
"prediction": {
"entities": {
"$instance": {
"extra": [
{
"length": 5,
"modelType": "Pattern.Any Entity Extractor",
"modelTypeId": 7,
"recognitionSources": [
"model"
],
"role": "extra",
"startIndex": 71,
"text": "kb435",
"type": "subject"
}
],
"Part": [
{
"length": 5,
"modelType": "Regex Entity Extractor",
"modelTypeId": 8,
"recognitionSources": [
"model"
],
"startIndex": 71,
"text": "kb435",
"type": "Part"
}
],
"person": [
{
"length": 12,
"modelType": "Pattern.Any Entity Extractor",
"modelTypeId": 7,
"recognitionSources": [
"model"
],
"startIndex": 49,
"text": "bart simpson",
"type": "person"
}
],
"personName": [
{
"length": 12,
"modelType": "Prebuilt Entity Extractor",
"modelTypeId": 2,
"recognitionSources": [
"model"
],
"startIndex": 49,
"text": "bart simpson",
"type": "builtin.personName"
}
],
"subject": [
{
"length": 31,
"modelType": "Pattern.Any Entity Extractor",
"modelTypeId": 7,
"recognitionSources": [
"model"
],
"startIndex": 12,
"text": "something wicked this way comes",
"type": "subject"
}
]
},
"extra": [
"kb435"
],
"Part": [
"kb435"
],
"person": [
"bart simpson"
],
"personName": [
"bart simpson"
],
"subject": [
"something wicked this way comes"
]
},
"intents": {
"Cancel": {
"score": 1.01764708E-09
},
"Delivery": {
"score": 1.8E-09
},
"EntityTests": {
"score": 1.044335E-05
},
"Greeting": {
"score": 1.0875E-09
},
"Help": {
"score": 1.01764708E-09
},
"None": {
"score": 2.38094663E-06
},
"Roles": {
"score": 5.98274755E-06
},
"search": {
"score": 0.9999993
},
"SpecifyName": {
"score": 3.0666667E-09
},
"Travel": {
"score": 3.09763345E-06
},
"Weather.GetForecast": {
"score": 1.02792524E-06
}
},
"normalizedQuery": "email about something wicked this way comes from bart simpson and also kb435",
"sentiment": {
"label": "negative",
"score": 0.210341513
},
"topIntent": "search"
},
"query": "email about something wicked this way comes from bart simpson and also kb435"
}
}

Просмотреть файл

@ -0,0 +1,338 @@
{
"entities": {
"$instance": {
"Composite2": [
{
"length": 66,
"modelType": "Composite Entity Extractor",
"modelTypeId": 4,
"recognitionSources": [
"model"
],
"score": 0.456283748,
"startIndex": 0,
"text": "http://foo.com is where you can get a weather forecast for seattle",
"type": "Composite2"
}
],
"geographyV2": [
{
"length": 7,
"modelType": "Prebuilt Entity Extractor",
"modelTypeId": 2,
"recognitionSources": [
"model"
],
"startIndex": 59,
"text": "seattle",
"type": "builtin.geographyV2.city"
}
]
},
"Composite2": [
{
"$instance": {
"url": [
{
"length": 14,
"modelType": "Prebuilt Entity Extractor",
"modelTypeId": 2,
"recognitionSources": [
"model"
],
"startIndex": 0,
"text": "http://foo.com",
"type": "builtin.url"
}
],
"Weather.Location": [
{
"length": 7,
"modelType": "Entity Extractor",
"modelTypeId": 1,
"recognitionSources": [
"model"
],
"score": 0.76184386,
"startIndex": 59,
"text": "seattle",
"type": "Weather.Location"
}
]
},
"url": [
"http://foo.com"
],
"Weather.Location": [
"seattle"
]
}
],
"geographyV2": [
"seattle"
]
},
"intents": {
"Cancel": {
"score": 0.000171828113
},
"Delivery": {
"score": 0.0011408634
},
"EntityTests": {
"score": 0.342939854
},
"Greeting": {
"score": 0.0001518702
},
"Help": {
"score": 0.0005502715
},
"None": {
"score": 0.0175834317
},
"Roles": {
"score": 0.0432791822
},
"search": {
"score": 0.014743383
},
"SpecifyName": {
"score": 0.00172697916
},
"Travel": {
"score": 0.013458414
},
"Weather_GetForecast": {
"score": 0.669524968
}
},
"sentiment": {
"label": "neutral",
"score": 0.5
},
"text": "http://foo.com is where you can get a weather forecast for seattle",
"v2": {
"compositeEntities": [
{
"children": [
{
"type": "builtin.url",
"value": "http://foo.com"
},
{
"type": "Weather.Location",
"value": "seattle"
}
],
"parentType": "Composite2",
"value": "http : / / foo . com is where you can get a weather forecast for seattle"
}
],
"entities": [
{
"endIndex": 65,
"entity": "seattle",
"score": 0.76184386,
"startIndex": 59,
"type": "Weather.Location"
},
{
"endIndex": 65,
"entity": "http : / / foo . com is where you can get a weather forecast for seattle",
"score": 0.456283748,
"startIndex": 0,
"type": "Composite2"
},
{
"endIndex": 65,
"entity": "seattle",
"startIndex": 59,
"type": "builtin.geographyV2.city"
},
{
"endIndex": 13,
"entity": "http://foo.com",
"resolution": {
"value": "http://foo.com"
},
"startIndex": 0,
"type": "builtin.url"
}
],
"intents": [
{
"intent": "Weather.GetForecast",
"score": 0.669524968
},
{
"intent": "EntityTests",
"score": 0.342939854
},
{
"intent": "Roles",
"score": 0.0432791822
},
{
"intent": "None",
"score": 0.0175834317
},
{
"intent": "search",
"score": 0.014743383
},
{
"intent": "Travel",
"score": 0.013458414
},
{
"intent": "SpecifyName",
"score": 0.00172697916
},
{
"intent": "Delivery",
"score": 0.0011408634
},
{
"intent": "Help",
"score": 0.0005502715
},
{
"intent": "Cancel",
"score": 0.000171828113
},
{
"intent": "Greeting",
"score": 0.0001518702
}
],
"query": "http://foo.com is where you can get a weather forecast for seattle",
"sentimentAnalysis": {
"label": "neutral",
"score": 0.5
},
"topScoringIntent": {
"intent": "Weather.GetForecast",
"score": 0.669524968
}
},
"v3": {
"prediction": {
"entities": {
"$instance": {
"Composite2": [
{
"length": 66,
"modelType": "Composite Entity Extractor",
"modelTypeId": 4,
"recognitionSources": [
"model"
],
"score": 0.456283748,
"startIndex": 0,
"text": "http://foo.com is where you can get a weather forecast for seattle",
"type": "Composite2"
}
],
"geographyV2": [
{
"length": 7,
"modelType": "Prebuilt Entity Extractor",
"modelTypeId": 2,
"recognitionSources": [
"model"
],
"startIndex": 59,
"text": "seattle",
"type": "builtin.geographyV2.city"
}
]
},
"Composite2": [
{
"$instance": {
"url": [
{
"length": 14,
"modelType": "Prebuilt Entity Extractor",
"modelTypeId": 2,
"recognitionSources": [
"model"
],
"startIndex": 0,
"text": "http://foo.com",
"type": "builtin.url"
}
],
"Weather.Location": [
{
"length": 7,
"modelType": "Entity Extractor",
"modelTypeId": 1,
"recognitionSources": [
"model"
],
"score": 0.76184386,
"startIndex": 59,
"text": "seattle",
"type": "Weather.Location"
}
]
},
"url": [
"http://foo.com"
],
"Weather.Location": [
"seattle"
]
}
],
"geographyV2": [
"seattle"
]
},
"intents": {
"Cancel": {
"score": 0.000171828113
},
"Delivery": {
"score": 0.0011408634
},
"EntityTests": {
"score": 0.342939854
},
"Greeting": {
"score": 0.0001518702
},
"Help": {
"score": 0.0005502715
},
"None": {
"score": 0.0175834317
},
"Roles": {
"score": 0.0432791822
},
"search": {
"score": 0.014743383
},
"SpecifyName": {
"score": 0.00172697916
},
"Travel": {
"score": 0.013458414
},
"Weather.GetForecast": {
"score": 0.669524968
}
},
"normalizedQuery": "http://foo.com is where you can get a weather forecast for seattle",
"sentiment": {
"label": "neutral",
"score": 0.5
},
"topIntent": "Weather.GetForecast"
},
"query": "http://foo.com is where you can get a weather forecast for seattle"
}
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,293 @@
// <auto-generated>
// Code generated by LUISGen Contoso App.json -cs Microsoft.Bot.Builder.AI.LuisPreview.Tests.Contoso_App -o
// Tool github: https://github.com/microsoft/botbuilder-tools
// Changes may cause incorrect behavior and will be lost if the code is
// regenerated.
// </auto-generated>
using Newtonsoft.Json;
using System.Collections.Generic;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.AI.LuisPreview;
namespace Microsoft.Bot.Builder.AI.LuisPreview.Tests
{
public partial class Contoso_App: IRecognizerConvert
{
[JsonProperty("text")]
public string Text;
[JsonProperty("alteredText")]
public string AlteredText;
public enum Intent {
Cancel,
Delivery,
EntityTests,
Greeting,
Help,
None,
Roles,
search,
SpecifyName,
Travel,
Weather_GetForecast
};
[JsonProperty("intents")]
public Dictionary<Intent, IntentScore> Intents;
public class _Entities
{
// Simple entities
public string[] City;
public string[] To;
public string[] From;
public string[] Name;
public string[] likee;
public string[] liker;
public string[] State;
public string[] Weather_Location;
public string[] destination;
public string[] source;
// Built-in entities
public Age[] age;
public Age[] begin;
public Age[] end;
public DateTimeSpec[] datetime;
public DateTimeSpec[] arrive;
public DateTimeSpec[] leave;
public Dimension[] dimension;
public Dimension[] length;
public Dimension[] width;
public string[] email;
public string[] receiver;
public string[] sender;
public GeographyV2[] geographyV2;
public GeographyV2[] endloc;
public GeographyV2[] startloc;
public Money[] money;
public Money[] max;
public Money[] min;
public double[] number;
public double[] ordinal;
public double[] start;
public OrdinalV2[] ordinalV2;
public OrdinalV2[] endpos;
public OrdinalV2[] startpos;
public double[] percentage;
public double[] maximum;
public double[] minimum;
public string[] personName;
public string[] child;
public string[] parent;
public string[] phonenumber;
public string[] newPhone;
public string[] old;
public Temperature[] temperature;
public Temperature[] a;
public Temperature[] b;
public string[] url;
public string[] oldURL;
// Lists
public string[][] Airline;
public string[][] Buyer;
public string[][] Seller;
// Regex entities
public string[] Part;
public string[] buy;
public string[] sell;
// Pattern.any
public string[] person;
public string[] from;
public string[] to;
public string[] subject;
public string[] extra;
// Composites
public class _InstanceAddress
{
public InstanceData[] number;
public InstanceData[] State;
}
public class AddressClass
{
public double[] number;
public string[] State;
[JsonProperty("$instance")]
public _InstanceAddress _instance;
}
public AddressClass[] Address;
public class _InstanceComposite1
{
public InstanceData[] age;
public InstanceData[] datetime;
public InstanceData[] dimension;
public InstanceData[] email;
public InstanceData[] money;
public InstanceData[] number;
public InstanceData[] ordinal;
public InstanceData[] percentage;
public InstanceData[] phonenumber;
public InstanceData[] temperature;
}
public class Composite1Class
{
public Age[] age;
public DateTimeSpec[] datetime;
public Dimension[] dimension;
public string[] email;
public Money[] money;
public double[] number;
public double[] ordinal;
public double[] percentage;
public string[] phonenumber;
public Temperature[] temperature;
[JsonProperty("$instance")]
public _InstanceComposite1 _instance;
}
public Composite1Class[] Composite1;
public class _InstanceComposite2
{
public InstanceData[] Airline;
public InstanceData[] City;
public InstanceData[] url;
public InstanceData[] From;
public InstanceData[] To;
public InstanceData[] Weather_Location;
}
public class Composite2Class
{
public string[][] Airline;
public string[] City;
public string[] url;
public string[] From;
public string[] To;
public string[] Weather_Location;
[JsonProperty("$instance")]
public _InstanceComposite2 _instance;
}
public Composite2Class[] Composite2;
// Instance
public class _Instance
{
public InstanceData[] Address;
public InstanceData[] Destination;
public InstanceData[] Source;
public InstanceData[] Airline;
public InstanceData[] Buyer;
public InstanceData[] Seller;
public InstanceData[] City;
public InstanceData[] Composite1;
public InstanceData[] Composite2;
public InstanceData[] Name;
public InstanceData[] likee;
public InstanceData[] liker;
public InstanceData[] Part;
public InstanceData[] buy;
public InstanceData[] sell;
public InstanceData[] State;
public InstanceData[] Weather_Location;
public InstanceData[] destination;
public InstanceData[] source;
public InstanceData[] age;
public InstanceData[] begin;
public InstanceData[] end;
public InstanceData[] datetime;
public InstanceData[] arrive;
public InstanceData[] leave;
public InstanceData[] dimension;
public InstanceData[] length;
public InstanceData[] width;
public InstanceData[] email;
public InstanceData[] receiver;
public InstanceData[] sender;
public InstanceData[] geographyV2;
public InstanceData[] endloc;
public InstanceData[] startloc;
public InstanceData[] money;
public InstanceData[] max;
public InstanceData[] min;
public InstanceData[] number;
public InstanceData[] ordinal;
public InstanceData[] start;
public InstanceData[] ordinalV2;
public InstanceData[] endpos;
public InstanceData[] startpos;
public InstanceData[] percentage;
public InstanceData[] maximum;
public InstanceData[] minimum;
public InstanceData[] person;
public InstanceData[] from;
public InstanceData[] to;
public InstanceData[] personName;
public InstanceData[] child;
public InstanceData[] parent;
public InstanceData[] phonenumber;
public InstanceData[] newPhone;
public InstanceData[] old;
public InstanceData[] subject;
public InstanceData[] extra;
public InstanceData[] temperature;
public InstanceData[] a;
public InstanceData[] b;
public InstanceData[] url;
public InstanceData[] oldURL;
}
[JsonProperty("$instance")]
public _Instance _instance;
}
[JsonProperty("entities")]
public _Entities Entities;
[JsonExtensionData(ReadData = true, WriteData = true)]
public IDictionary<string, object> Properties {get; set; }
public void Convert(dynamic result)
{
var app = JsonConvert.DeserializeObject<Contoso_App>(JsonConvert.SerializeObject(result, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }));
Text = app.Text;
AlteredText = app.AlteredText;
Intents = app.Intents;
Entities = app.Entities;
Properties = app.Properties;
}
public (Intent intent, double score) TopIntent()
{
Intent maxIntent = Intent.None;
var max = 0.0;
foreach (var entry in Intents)
{
if (entry.Value.Score > max)
{
maxIntent = entry.Key;
max = entry.Value.Score.Value;
}
}
return (maxIntent, max);
}
}
}

Просмотреть файл

@ -0,0 +1,34 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System.Net;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
namespace Microsoft.Bot.Builder.AI.LuisPreview.Tests
{
/// <inheritdoc />
/// <summary>
/// An HttpClientHandler that returns a hard coded response equivalent to a LUIS no-match-found result.
/// </summary>
public class EmptyLuisResponseClientHandler : HttpClientHandler
{
public string UserAgent { get; private set; }
public HttpRequestMessage RequestMessage { get; private set; }
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
// Capture the user-agent and the HttpRequestMessage so we can examine it after the call completes.
UserAgent = request.Headers.UserAgent.ToString();
RequestMessage = request;
return Task.FromResult(new HttpResponseMessage
{
StatusCode = HttpStatusCode.OK,
Content = new StringContent("{ \"query\": null, \"intents\": [], \"entities\": [] }"),
});
}
}
}

Просмотреть файл

@ -0,0 +1,94 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using Microsoft.Bot.Configuration;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Newtonsoft.Json;
namespace Microsoft.Bot.Builder.AI.LuisPreview.Tests
{
[TestClass]
public class LuisApplicationTests
{
private const string Endpoint = "https://westus.api.cognitive.microsoft.com";
[TestMethod]
public void LuisApplication_Construction()
{
var model = GetValidModel();
Assert.IsNotNull(model);
Assert.ThrowsException<ArgumentException>(() => new LuisApplication(null, Guid.NewGuid().ToString(), Endpoint));
Assert.ThrowsException<ArgumentException>(() => new LuisApplication(string.Empty, Guid.NewGuid().ToString(), Endpoint));
Assert.ThrowsException<ArgumentException>(() => new LuisApplication("0000", Guid.NewGuid().ToString(), Endpoint));
Assert.ThrowsException<ArgumentException>(() => new LuisApplication(Guid.NewGuid().ToString(), null, Endpoint));
Assert.ThrowsException<ArgumentException>(() => new LuisApplication(Guid.NewGuid().ToString(), string.Empty, Endpoint));
Assert.ThrowsException<ArgumentException>(() => new LuisApplication(Guid.NewGuid().ToString(), "0000", Endpoint));
var luisApp = new LuisApplication(Guid.NewGuid().ToString(), Guid.NewGuid().ToString(), Endpoint);
Assert.AreEqual(Endpoint, luisApp.Endpoint);
}
[TestMethod]
public void LuisApplication_Serialization()
{
var model = GetValidModel();
var serialized = JsonConvert.SerializeObject(model);
var deserialized = JsonConvert.DeserializeObject<LuisApplication>(serialized);
Assert.IsNotNull(deserialized);
Assert.AreEqual(model.ApplicationId, deserialized.ApplicationId);
Assert.AreEqual(model.EndpointKey, deserialized.EndpointKey);
Assert.AreEqual(model.Endpoint, deserialized.Endpoint);
}
[TestMethod]
public void LuisApplication_Configuration()
{
// Arrange
var service = new LuisService
{
AppId = Guid.NewGuid().ToString(),
SubscriptionKey = Guid.NewGuid().ToString(),
Region = "westus",
};
// Act
var model = new LuisApplication(service);
// Assert
Assert.AreEqual(service.AppId, model.ApplicationId);
Assert.AreEqual(service.SubscriptionKey, model.EndpointKey);
Assert.AreEqual(service.GetEndpoint(), model.Endpoint);
}
[TestMethod]
public void ListApplicationFromLuisEndpoint()
{
// Arrange
// Note this is NOT a real LUIS application ID nor a real LUIS subscription-key
// theses are GUIDs edited to look right to the parsing and validation code.
var endpoint = "https://westus.api.cognitive.microsoft.com/luis/v2.0/apps/b31aeaf3-3511-495b-a07f-571fc873214b?verbose=true&timezoneOffset=-360&subscription-key=048ec46dc58e495482b0c447cfdbd291&q=";
// Act
var app = new LuisApplication(endpoint);
// Assert
Assert.AreEqual("b31aeaf3-3511-495b-a07f-571fc873214b", app.ApplicationId);
Assert.AreEqual("048ec46dc58e495482b0c447cfdbd291", app.EndpointKey);
Assert.AreEqual("https://westus.api.cognitive.microsoft.com", app.Endpoint);
}
[TestMethod]
public void ListApplicationFromLuisEndpointBadArguments()
{
Assert.ThrowsException<ArgumentException>(() => new LuisApplication("this.is.not.a.uri"));
Assert.ThrowsException<ArgumentException>(() => new LuisApplication("https://westus.api.cognitive.microsoft.com/luis/v2.0/apps/b31aeaf3-3511-495b-a07f-571fc873214b?verbose=true&timezoneOffset=-360&q="));
Assert.ThrowsException<ArgumentException>(() => new LuisApplication("https://westus.api.cognitive.microsoft.com?verbose=true&timezoneOffset=-360&subscription-key=048ec46dc58e495482b0c447cfdbd291&q="));
}
private LuisApplication GetValidModel()
=> new LuisApplication(Guid.NewGuid().ToString(), Guid.NewGuid().ToString(), Endpoint);
}
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,150 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Globalization;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using System.Web;
using Microsoft.Bot.Builder.Adapters;
using Microsoft.Bot.Schema;
using Xunit;
namespace Microsoft.Bot.Builder.AI.LuisPreview.Tests
{
public class LuisRecognizerTests
{
private readonly LuisApplication _luisApp;
private readonly EmptyLuisResponseClientHandler _mockHttpClientHandler;
public LuisRecognizerTests()
{
_luisApp = new LuisApplication(Guid.NewGuid().ToString(), Guid.NewGuid().ToString(), "https://someluisendpoint");
_mockHttpClientHandler = new EmptyLuisResponseClientHandler();
}
[Theory]
[InlineData(false, 42, false, "Fake2806-EC0A-472D-95B7-A7132D159E03", false, false)]
[InlineData(true, 42, false, "Fake2806-EC0A-472D-95B7-A7132D159E03", false, false)]
[InlineData(false, 42, true, "Fake2806-EC0A-472D-95B7-A7132D159E03", false, false)]
[InlineData(false, 42, false, "Fake2806-EC0A-472D-95B7-A7132D159E03", true, false)]
[InlineData(false, 42, false, "Fake2806-EC0A-472D-95B7-A7132D159E03", false, true)]
[InlineData(null, 42, false, "Fake2806-EC0A-472D-95B7-A7132D159E03", false, false)]
[InlineData(false, null, false, "Fake2806-EC0A-472D-95B7-A7132D159E03", false, false)]
[InlineData(false, 42, null, "Fake2806-EC0A-472D-95B7-A7132D159E03", false, false)]
[InlineData(false, 42, false, null, false, false)]
[InlineData(false, 42, false, "Fake2806-EC0A-472D-95B7-A7132D159E03", null, false)]
[InlineData(false, 42, false, "Fake2806-EC0A-472D-95B7-A7132D159E03", false, null)]
[InlineData(null, null, null, null, null, null)]
public async Task LuisPredictionOptionsAreUsedInTheRequest(bool? includeAllIntents, double? timezoneOffset, bool? spellCheck, string bingSpellCheckSubscriptionKey, bool? log, bool? staging)
{
// Arrange
var expectedOptions = new LuisPredictionOptions()
{
IncludeAllIntents = includeAllIntents,
TimezoneOffset = timezoneOffset,
SpellCheck = spellCheck,
BingSpellCheckSubscriptionKey = bingSpellCheckSubscriptionKey,
Log = log ?? true,
Staging = staging,
};
var sut = new LuisRecognizer(_luisApp, expectedOptions, clientHandler: _mockHttpClientHandler);
// Act
await sut.RecognizeAsync(BuildTurnContextForUtterance("hi"), CancellationToken.None);
// Assert
AssertLuisRequest(_mockHttpClientHandler.RequestMessage, expectedOptions);
}
[Theory]
[InlineData(false, null, null, null, null, null)]
[InlineData(null, 55, null, null, null, null)]
[InlineData(null, null, false, null, null, null)]
[InlineData(null, null, null, "Override-EC0A-472D-95B7-A7132D159E03", null, null)]
[InlineData(null, null, null, null, true, null)]
[InlineData(null, null, null, null, null, false)]
[InlineData(null, null, null, null, null, null)]
public async Task ShouldOverridePredictionOptionsIfProvided(bool? includeAllIntents, double? timezoneOffset, bool? spellCheck, string bingSpellCheckSubscriptionKey, bool? log, bool? staging)
{
// Arrange
// Initialize options with non default values so we can assert they have been overriden.
var constructorOptions = new LuisPredictionOptions()
{
IncludeAllIntents = true,
TimezoneOffset = 42,
SpellCheck = true,
BingSpellCheckSubscriptionKey = "Fake2806-EC0A-472D-95B7-A7132D159E03",
Log = false,
Staging = true,
};
// Create overriden options for call
var overridenOptions = new LuisPredictionOptions()
{
IncludeAllIntents = includeAllIntents,
TimezoneOffset = timezoneOffset,
SpellCheck = spellCheck,
BingSpellCheckSubscriptionKey = bingSpellCheckSubscriptionKey,
Log = log,
Staging = staging,
};
// Create combined options for assertion taking the test case value if not null or the constructor value if not null.
var expectedOptions = new LuisPredictionOptions()
{
IncludeAllIntents = includeAllIntents ?? constructorOptions.IncludeAllIntents,
TimezoneOffset = timezoneOffset ?? constructorOptions.TimezoneOffset,
SpellCheck = spellCheck ?? constructorOptions.SpellCheck,
BingSpellCheckSubscriptionKey = bingSpellCheckSubscriptionKey ?? constructorOptions.BingSpellCheckSubscriptionKey,
Log = log ?? constructorOptions.Log,
Staging = staging ?? constructorOptions.Staging,
LogPersonalInformation = constructorOptions.LogPersonalInformation,
};
var sut = new LuisRecognizer(_luisApp, constructorOptions, clientHandler: _mockHttpClientHandler);
// Act/Assert RecognizeAsync override
await sut.RecognizeAsync(BuildTurnContextForUtterance("hi"), overridenOptions, CancellationToken.None);
AssertLuisRequest(_mockHttpClientHandler.RequestMessage, expectedOptions);
// these values can't be overriden and should stay unchanged.
Assert.Equal(constructorOptions.TelemetryClient, sut.TelemetryClient);
Assert.Equal(constructorOptions.LogPersonalInformation, sut.LogPersonalInformation);
// Act/Assert RecognizeAsync<T> override
await sut.RecognizeAsync<Contoso_App>(BuildTurnContextForUtterance("hi"), overridenOptions, CancellationToken.None);
AssertLuisRequest(_mockHttpClientHandler.RequestMessage, expectedOptions);
// these values can't be overriden and should stay unchanged.
Assert.Equal(constructorOptions.TelemetryClient, sut.TelemetryClient);
Assert.Equal(constructorOptions.LogPersonalInformation, sut.LogPersonalInformation);
}
private static void AssertLuisRequest(HttpRequestMessage httpRequestForLuis, LuisPredictionOptions expectedOptions)
{
var queryStringParameters = HttpUtility.ParseQueryString(httpRequestForLuis.RequestUri.Query);
Assert.Equal(expectedOptions.BingSpellCheckSubscriptionKey?.ToString(CultureInfo.InvariantCulture), queryStringParameters["bing-spell-check-subscription-key"]);
Assert.Equal(expectedOptions.SpellCheck?.ToString(CultureInfo.InvariantCulture).ToLower(), queryStringParameters["spellCheck"]);
Assert.Equal(expectedOptions.IncludeAllIntents?.ToString(CultureInfo.InvariantCulture).ToLower(), queryStringParameters["verbose"]);
Assert.Equal(expectedOptions.Staging?.ToString(CultureInfo.InvariantCulture).ToLower(), queryStringParameters["staging"]);
Assert.Equal(expectedOptions.Log?.ToString(CultureInfo.InvariantCulture).ToLower(), queryStringParameters["log"]);
}
private static TurnContext BuildTurnContextForUtterance(string utterance)
{
var testAdapter = new TestAdapter();
var activity = new Activity
{
Type = ActivityTypes.Message,
Text = utterance,
Conversation = new ConversationAccount(),
Recipient = new ChannelAccount(),
From = new ChannelAccount(),
};
return new TurnContext(testAdapter, activity);
}
}
}

Просмотреть файл

@ -0,0 +1,33 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
<IsPackable>false</IsPackable>
<GenerateDocumentationFile>false</GenerateDocumentationFile>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.1.1" />
<PackageReference Include="Moq" Version="4.11.0" />
<PackageReference Include="MSTest.TestAdapter" Version="1.4.0" />
<PackageReference Include="MSTest.TestFramework" Version="1.4.0" />
<PackageReference Include="RichardSzalay.MockHttp" Version="5.0.0" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\libraries\Microsoft.Bot.Builder.AI.LUISPreview\Microsoft.Bot.Builder.AI.LuisPreview.csproj" />
<ProjectReference Include="..\Microsoft.Bot.Builder.AI.Luis.TestUtils\Microsoft.Bot.Builder.AI.Luis.TestUtils.csproj" />
<ProjectReference Include="..\Microsoft.Bot.Builder.Tests\Microsoft.Bot.Builder.Tests.csproj" />
</ItemGroup>
<ItemGroup>
<Reference Include="System">
<HintPath>System</HintPath>
</Reference>
</ItemGroup>
</Project>

Просмотреть файл

@ -0,0 +1,76 @@
<?xml version="1.0" encoding="utf-8"?>
<RuleSet Name="Microsoft Managed Recommended Rules" Description="These rules focus on the most critical problems in your code, including potential security holes, application crashes, and other important logic and design errors. It is recommended to include this rule set in any custom rule set you create for your projects." ToolsVersion="10.0">
<Localization ResourceAssembly="Microsoft.VisualStudio.CodeAnalysis.RuleSets.Strings.dll" ResourceBaseName="Microsoft.VisualStudio.CodeAnalysis.RuleSets.Strings.Localized">
<Name Resource="MinimumRecommendedRules_Name" />
<Description Resource="MinimumRecommendedRules_Description" />
</Localization>
<Rules AnalyzerId="Microsoft.Analyzers.ManagedCodeAnalysis" RuleNamespace="Microsoft.Rules.Managed">
<Rule Id="CA1001" Action="Warning" />
<Rule Id="CA1009" Action="Warning" />
<Rule Id="CA1016" Action="Warning" />
<Rule Id="CA1033" Action="Warning" />
<Rule Id="CA1049" Action="Warning" />
<Rule Id="CA1060" Action="Warning" />
<Rule Id="CA1061" Action="Warning" />
<Rule Id="CA1063" Action="Warning" />
<Rule Id="CA1065" Action="Warning" />
<Rule Id="CA1301" Action="Warning" />
<Rule Id="CA1400" Action="Warning" />
<Rule Id="CA1401" Action="Warning" />
<Rule Id="CA1403" Action="Warning" />
<Rule Id="CA1404" Action="Warning" />
<Rule Id="CA1405" Action="Warning" />
<Rule Id="CA1410" Action="Warning" />
<Rule Id="CA1415" Action="Warning" />
<Rule Id="CA1821" Action="Warning" />
<Rule Id="CA1900" Action="Warning" />
<Rule Id="CA1901" Action="Warning" />
<Rule Id="CA2002" Action="Warning" />
<Rule Id="CA2100" Action="Warning" />
<Rule Id="CA2101" Action="Warning" />
<Rule Id="CA2108" Action="Warning" />
<Rule Id="CA2111" Action="Warning" />
<Rule Id="CA2112" Action="Warning" />
<Rule Id="CA2114" Action="Warning" />
<Rule Id="CA2116" Action="Warning" />
<Rule Id="CA2117" Action="Warning" />
<Rule Id="CA2122" Action="Warning" />
<Rule Id="CA2123" Action="Warning" />
<Rule Id="CA2124" Action="Warning" />
<Rule Id="CA2126" Action="Warning" />
<Rule Id="CA2131" Action="Warning" />
<Rule Id="CA2132" Action="Warning" />
<Rule Id="CA2133" Action="Warning" />
<Rule Id="CA2134" Action="Warning" />
<Rule Id="CA2137" Action="Warning" />
<Rule Id="CA2138" Action="Warning" />
<Rule Id="CA2140" Action="Warning" />
<Rule Id="CA2141" Action="Warning" />
<Rule Id="CA2146" Action="Warning" />
<Rule Id="CA2147" Action="Warning" />
<Rule Id="CA2149" Action="Warning" />
<Rule Id="CA2200" Action="Warning" />
<Rule Id="CA2202" Action="Warning" />
<Rule Id="CA2207" Action="Warning" />
<Rule Id="CA2212" Action="Warning" />
<Rule Id="CA2213" Action="Warning" />
<Rule Id="CA2214" Action="Warning" />
<Rule Id="CA2216" Action="Warning" />
<Rule Id="CA2220" Action="Warning" />
<Rule Id="CA2229" Action="Warning" />
<Rule Id="CA2231" Action="Warning" />
<Rule Id="CA2232" Action="Warning" />
<Rule Id="CA2235" Action="Warning" />
<Rule Id="CA2236" Action="Warning" />
<Rule Id="CA2237" Action="Warning" />
<Rule Id="CA2238" Action="Warning" />
<Rule Id="CA2240" Action="Warning" />
<Rule Id="CA2241" Action="Warning" />
<Rule Id="CA2242" Action="Warning" />
</Rules>
<Rules AnalyzerId="StyleCop.Analyzers" RuleNamespace="StyleCop.Analyzers">
<Rule Id="SA1200" Action="None" />
<Rule Id="SA1633" Action="None" />
<Rule Id="SA1600" Action="None" />
</Rules>
</RuleSet>

Просмотреть файл

@ -0,0 +1,22 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Bot.Schema;
namespace Microsoft.Bot.Builder.AI.LuisPreview.Tests
{
/// <summary>
/// This is a BotAdapter that does nothing on the Send operation, equivallent to piping to /dev/null.
/// </summary>
public class NullAdapter : BotAdapter
{
public override Task DeleteActivityAsync(ITurnContext turnContext, ConversationReference reference, CancellationToken cancellationToken) => throw new NotImplementedException();
public override Task<ResourceResponse[]> SendActivitiesAsync(ITurnContext turnContext, Activity[] activities, CancellationToken cancellationToken) => Task.FromResult(new[] { new ResourceResponse() });
public override Task<ResourceResponse> UpdateActivityAsync(ITurnContext turnContext, Activity activity, CancellationToken cancellationToken) => throw new NotImplementedException();
}
}

Просмотреть файл

@ -0,0 +1,54 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Bot.Builder.Adapters;
using Microsoft.Bot.Configuration;
using Microsoft.Bot.Schema;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using RichardSzalay.MockHttp;
namespace Microsoft.Bot.Builder.AI.LuisPreview.Tests
{
public class OverrideFillRecognizer : LuisRecognizer
{
public OverrideFillRecognizer(IBotTelemetryClient telemetryClient, LuisApplication application, LuisPredictionOptions predictionOptions = null, bool includeApiResults = false, bool logPersonalInformation = false, HttpClientHandler clientHandler = null)
: base(application, predictionOptions, includeApiResults, clientHandler)
{
LogPersonalInformation = logPersonalInformation;
}
protected override async Task OnRecognizerResultAsync(RecognizerResult recognizerResult, ITurnContext turnContext, Dictionary<string, string> telemetryProperties = null, Dictionary<string, double> telemetryMetrics = null, CancellationToken cancellationToken = default(CancellationToken))
{
var properties = await FillLuisEventPropertiesAsync(recognizerResult, turnContext, telemetryProperties, cancellationToken).ConfigureAwait(false);
properties.TryAdd("MyImportantProperty", "myImportantValue");
// Log event
TelemetryClient.TrackEvent(
LuisTelemetryConstants.LuisResult,
properties,
telemetryMetrics);
// Create second event.
var secondEventProperties = new Dictionary<string, string>();
secondEventProperties.Add(
"MyImportantProperty2",
"myImportantValue2");
TelemetryClient.TrackEvent(
"MySecondEvent",
secondEventProperties);
}
}
}

Просмотреть файл

@ -0,0 +1,41 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Bot.Builder.Adapters;
using Microsoft.Bot.Configuration;
using Microsoft.Bot.Schema;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using RichardSzalay.MockHttp;
namespace Microsoft.Bot.Builder.AI.LuisPreview.Tests
{
public class TelemetryConvertResult : IRecognizerConvert
{
private RecognizerResult _result;
public TelemetryConvertResult()
{
}
/// <summary>
/// Convert recognizer result.
/// </summary>
/// <param name="result">Result to convert.</param>
public void Convert(dynamic result)
{
_result = result as RecognizerResult;
}
}
}

Просмотреть файл

@ -0,0 +1,53 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Bot.Builder.Adapters;
using Microsoft.Bot.Configuration;
using Microsoft.Bot.Schema;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using RichardSzalay.MockHttp;
namespace Microsoft.Bot.Builder.AI.LuisPreview.Tests
{
public class TelemetryOverrideRecognizer : LuisRecognizer
{
public TelemetryOverrideRecognizer(IBotTelemetryClient telemetryClient, LuisApplication application, LuisPredictionOptions predictionOptions = null, bool includeApiResults = false, bool logPersonalInformation = false, HttpClientHandler clientHandler = null)
: base(application, predictionOptions, includeApiResults, clientHandler)
{
LogPersonalInformation = logPersonalInformation;
}
protected override Task OnRecognizerResultAsync(RecognizerResult recognizerResult, ITurnContext turnContext, Dictionary<string, string> properties = null, Dictionary<string, double> metrics = null, CancellationToken cancellationToken = default(CancellationToken))
{
properties.TryAdd("MyImportantProperty", "myImportantValue");
// Log event
TelemetryClient.TrackEvent(
LuisTelemetryConstants.LuisResult,
properties,
metrics);
// Create second event.
var secondEventProperties = new Dictionary<string, string>();
secondEventProperties.Add(
"MyImportantProperty2",
"myImportantValue2");
TelemetryClient.TrackEvent(
"MySecondEvent",
secondEventProperties);
return Task.CompletedTask;
}
}
}

Просмотреть файл

@ -115,7 +115,7 @@
<Version>1.1.6</Version>
</PackageReference>
<PackageReference Include="Newtonsoft.Json">
<Version>11.0.1</Version>
<Version>10.0.3</Version>
</PackageReference>
</ItemGroup>
<ItemGroup>