Merge pull request #470 from DeniseMak/master

LUIS dispatch hierarchical sample
This commit is contained in:
Cezary Marcjan 2018-04-24 12:31:05 -07:00 коммит произвёл GitHub
Родитель dc4698009a 6915a83e65
Коммит 3ff1a6fe94
7 изменённых файлов: 326 добавлений и 0 удалений

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

@ -96,6 +96,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Bot.Samples.Dialo
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Bot.Builder.Dialogs.Tests", "tests\Microsoft.Bot.Builder.Dialogs.Tests\Microsoft.Bot.Builder.Dialogs.Tests.csproj", "{2F77CA1D-E6F0-4DEA-96BB-8A039F4D0FF8}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Bot.Samples.Ai.Luis.Dispatch", "samples\Microsoft.Bot.Samples.Ai.Luis.Dispatch\Microsoft.Bot.Samples.Ai.Luis.Dispatch.csproj", "{91178F5C-303C-43B8-9284-84125FB07FFF}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug - NuGet Packages|Any CPU = Debug - NuGet Packages|Any CPU
@ -408,6 +410,14 @@ Global
{2F77CA1D-E6F0-4DEA-96BB-8A039F4D0FF8}.Documentation|Any CPU.ActiveCfg = Debug|Any CPU
{2F77CA1D-E6F0-4DEA-96BB-8A039F4D0FF8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2F77CA1D-E6F0-4DEA-96BB-8A039F4D0FF8}.Release|Any CPU.Build.0 = Release|Any CPU
{91178F5C-303C-43B8-9284-84125FB07FFF}.Debug - NuGet Packages|Any CPU.ActiveCfg = Debug|Any CPU
{91178F5C-303C-43B8-9284-84125FB07FFF}.Debug - NuGet Packages|Any CPU.Build.0 = Debug|Any CPU
{91178F5C-303C-43B8-9284-84125FB07FFF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{91178F5C-303C-43B8-9284-84125FB07FFF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{91178F5C-303C-43B8-9284-84125FB07FFF}.Documentation|Any CPU.ActiveCfg = Debug|Any CPU
{91178F5C-303C-43B8-9284-84125FB07FFF}.Documentation|Any CPU.Build.0 = Debug|Any CPU
{91178F5C-303C-43B8-9284-84125FB07FFF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{91178F5C-303C-43B8-9284-84125FB07FFF}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -457,6 +467,7 @@ Global
{0F639EB4-FB64-4909-8A10-FB93E7BE3AFB} = {4269F3C3-6B42-419B-B64A-3E6DC0F1574A}
{B71A123F-09FE-45D7-9644-4EE3E1E221AE} = {3ADFB27A-95FA-4330-B211-1D66A29A17AB}
{2F77CA1D-E6F0-4DEA-96BB-8A039F4D0FF8} = {AD743B78-D61F-4FBF-B620-FA83CE599A50}
{91178F5C-303C-43B8-9284-84125FB07FFF} = {3ADFB27A-95FA-4330-B211-1D66A29A17AB}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {7173C9F3-A7F9-496E-9078-9156E35D6E16}

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

@ -0,0 +1,177 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.Ai.LUIS;
using Microsoft.Bot.Builder.Ai.QnA;
using Microsoft.Bot.Schema;
namespace Microsoft.Bot.Samples.Ai.Luis.Dispatch
{
/// <summary>
/// This bot demonstrates how to use a LUIS model generated by the Dispatch tool.
///
/// See https://aka.ms/bot-dispatch for more information on the Dispatch tool.
///
/// This example assumes the LUIS app from Dispatch is generated from two LUIS apps and one QnAMaker service:
/// * A LUIS app named "homeautomation", for handling messages about turning lights and appliances on and off
/// * A LUIS app named "weather", for handling requests for weather forecasts and conditions
/// * A QnA Maker service named "faq", for answering questions about using the hypothetical home automation system.
///
/// Generate the LUIS app using Dispatch tool. The tool creates a LUIS app with one intent
/// for each of the constituent LUIS apps and QnAMaker services: "l_homeautomation", "l_weather", "q_faq".
/// The bot can use the intents to route the user messages to the appropriate LUIS app or QnA Maker.
///
/// Dispatching the messages to the original LUIS apps allows the bot to get entities from the these apps.
/// The LUIS app generated by the Dispatch tool doesn't contain entity information.
/// </summary>
public class LuisDispatchBot : IBot
{
public LuisDispatchBot() { }
private static QnAMakerOptions qnaOptions = new QnAMakerOptions
{
// add subscription key for QnA and knowledge base ID
SubscriptionKey = "<QNAMAKER-KB-ID>",
KnowledgeBaseId = "<YOUR-QNAMAKER-SUBSCRIPTION-KEY>"
};
// App ID for a LUIS model named "homeautomation"
private static LuisModel luisModel1 =
new LuisModel("<YOUR-LUIS-APP-ID>", "<YOUR-LUIS-SUBSCRIPTION-KEY>", new System.Uri("https://westus.api.cognitive.microsoft.com/luis/v2.0/apps/"));
// App ID for a LUIS model named "weather"
private static LuisModel luisModel2 =
new LuisModel("YOUR-LUIS-APP-ID", "<YOUR-LUIS-SUBSCRIPTION-KEY>", new System.Uri("https://westus.api.cognitive.microsoft.com/luis/v2.0/apps/"));
public async Task OnTurn(ITurnContext context)
{
if (context.Activity.Type is ActivityTypes.Message)
{
var message = context.Activity.AsMessageActivity();
// Get the intent recognition result from the context object.
var dispatchResult = context.Services.Get<RecognizerResult>(LuisRecognizerMiddleware.LuisRecognizerResultKey) as RecognizerResult;
var topIntent = dispatchResult?.GetTopScoringIntent();
LuisRecognizer luisRecognizer1, luisRecognizer2;
RecognizerResult recognizerResult;
var intentsList = new List<string>();
var entitiesList = new List<string>();
if (topIntent == null)
{
await context.SendActivity("Unable to get the top intent.");
}
else
{
if (topIntent.Value.score < 0.3)
{
await context.SendActivity("I'm not very sure what you want but will try to send your request.");
}
switch (topIntent.Value.key.ToLowerInvariant())
{
case "l_homeautomation":
await context.SendActivity("Sending your request to the home automation system ...");
luisRecognizer1 = new LuisRecognizer(luisModel1);
var luisResults = await luisRecognizer1.CallAndRecognize(message.Text, System.Threading.CancellationToken.None);
recognizerResult = luisResults.recognizerResult;
// list the intents
foreach (var intent in recognizerResult.Intents)
{
intentsList.Add($"'{intent.Key}', score {intent.Value}");
}
await context.SendActivity($"Intents detected by the home automation app:\n\n{string.Join("\n\n", intentsList)}");
// list the entities
entitiesList = new List<string>();
foreach (var entity in recognizerResult.Entities)
{
if (!entity.Key.ToString().Equals("$instance"))
{
entitiesList.Add($"{entity.Key}: {entity.Value.First}");
}
}
if (entitiesList.Count > 0)
{
await context.SendActivity($"The following entities were found the message:\n\n{string.Join("\n\n", entitiesList)}");
}
// Here, you can add code for calling the hypothetical home automation service, passing in any entity information that you need
break;
case "l_weather":
await context.SendActivity("Sending your request to the weather system ...");
luisRecognizer2 = new LuisRecognizer(luisModel2);
luisResults = await luisRecognizer2.CallAndRecognize(message.Text, System.Threading.CancellationToken.None);
recognizerResult = luisResults.recognizerResult;
// list the intents
var intentsResult2 = new List<string>();
foreach (var intent in recognizerResult.Intents)
{
intentsResult2.Add($"'{intent.Key}', score {intent.Value}");
}
await context.SendActivity($"Intents detected by the weather app: \n\n{string.Join("\n\n", intentsResult2)}");
// list the entities
entitiesList = new List<string>();
foreach (var entity in recognizerResult.Entities)
{
if (!entity.Key.ToString().Equals("$instance"))
{
entitiesList.Add($"{entity.Key}: {entity.Value.First}");
}
}
if (entitiesList.Count > 0)
{
await context.SendActivity($"The following entities were found in the message:\n\n{string.Join("\n\n", entitiesList)}");
}
// Here, you can add code for calling the hypothetical weather service, passing in any entity information that you need
break;
case "none":
// You can provide logic here to handle the known None intent (none of the above).
// In this example we fall through to the QnA intent.
case "q_faq":
QnAMaker qnaMaker = new QnAMaker(qnaOptions);
var messageActivity = context.Activity.AsMessageActivity();
if (!string.IsNullOrEmpty(messageActivity.Text))
{
var results = await qnaMaker.GetAnswers(messageActivity.Text.Trim()).ConfigureAwait(false);
if (results.Any())
{
await context.SendActivity(results.First().Answer);
}
else
{
await context.SendActivity("Couldn't find an answer in the FAQ.");
}
}
break;
default:
// The intent didn't match any case, so just display the recognition results.
await context.SendActivity($"Dispatch intent: {topIntent.Value.key} ({topIntent.Value.score}).");
break;
}
}
}
else if (context.Activity.Type is ActivityTypes.ConversationUpdate)
{
foreach (var newMember in context.Activity.MembersAdded)
{
if (newMember.Id != context.Activity.Recipient.Id)
{
await context.SendActivity("Hello and welcome to the LUIS Dispatch sample bot. This bot dispatches messages to LUIS apps and QnA, using a LUIS model generated by the Dispatch tool in hierarchical mode.");
}
}
}
}
}
}

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

@ -0,0 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netcoreapp2.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.3" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\libraries\integration\Microsoft.Bot.Builder.Integration.AspNet.Core\Microsoft.Bot.Builder.Integration.AspNet.Core.csproj" />
<ProjectReference Include="..\..\libraries\Microsoft.Bot.Builder.Ai.LUIS\Microsoft.Bot.Builder.Ai.LUIS.csproj" />
<ProjectReference Include="..\..\libraries\Microsoft.Bot.Builder.Ai.QnA\Microsoft.Bot.Builder.Ai.QnA.csproj" />
<ProjectReference Include="..\..\libraries\Microsoft.Bot.Builder.Core\Microsoft.Bot.Builder.Core.csproj" />
<ProjectReference Include="..\..\libraries\Microsoft.Bot.Builder\Microsoft.Bot.Builder.csproj" />
<ProjectReference Include="..\..\libraries\Microsoft.Bot.Connector\Microsoft.Bot.Connector.csproj" />
<ProjectReference Include="..\..\libraries\Microsoft.Bot.Schema\Microsoft.Bot.Schema.csproj" />
</ItemGroup>
</Project>

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

@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
namespace Microsoft.Bot.Samples.Ai.Luis.Dispatch
{
public class Program
{
public static void Main(string[] args)
{
BuildWebHost(args).Run();
}
public static IWebHost BuildWebHost(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.Build();
}
}

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

@ -0,0 +1,62 @@
using System;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Bot.Builder.BotFramework;
using Microsoft.Bot.Builder.Integration.AspNet.Core;
using Microsoft.Bot.Builder.Ai.LUIS;
using Microsoft.Cognitive.LUIS;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
namespace Microsoft.Bot.Samples.Ai.Luis.Dispatch
{
public class Startup
{
public Startup(IHostingEnvironment env)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
.AddEnvironmentVariables();
Configuration = builder.Build();
}
public IConfigurationRoot Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddBot<LuisDispatchBot>(options =>
{
options.CredentialProvider = new ConfigurationCredentialProvider(Configuration);
string luisModelId = "<Your LUIS app ID from cDispatch here>";
string luisSubscriptionKey = "<Your LUIS Subscription Key here>";
Uri luisUri = new Uri("https://westus.api.cognitive.microsoft.com/luis/v2.0/apps/");
var luisModel = new LuisModel(luisModelId, luisSubscriptionKey, luisUri);
// If you want to get all intents scorings, add verbose in luisOptions
var luisOptions = new LuisRequest { Verbose = true };
var middleware = options.Middleware;
middleware.Add(new LuisRecognizerMiddleware(luisModel, luisOptions: luisOptions));
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseDefaultFiles()
.UseStaticFiles()
.UseBotFramework();
}
}
}

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

@ -0,0 +1,21 @@
# LuisDispatchBot hosted in ASP.NET Core
This bot demonstrates how to use a LUIS app generated by the Dispatch tool.
See https://aka.ms/bot-dispatch for more information on the Dispatch tool.
This example assumes the LUIS app from Dispatch is generated from two LUIS apps and one QnAMaker service:
* A LUIS app named "homeautomation", for handling messages about turning lights and appliances on and off
* A LUIS app named "weather", for handling requests for weather forecasts and conditions
* A QnA Maker service named "faq", for answering questions about using the hypothetical home automation system.
First create the LUIS apps and QnAMaker, then generate a LUIS app from them using the Dispatch tool.
The tool creates a LUIS app with one intent for each of the constituent LUIS apps and QnAMaker services:
"l_homeautomation", "l_weather", "q_faq".
The bot uses the intents to route the user messages to the appropriate LUIS app or QnA Maker.
Dispatching the messages to the original LUIS apps allows the bot to get entities from the these apps.
The LUIS app generated by the Dispatch tool doesn't contain entity information.
To use the sample, update Startup.cs with the LUIS App ID and Subscription Key for the LUIS app that the Dispatch tool generates.
Update the subscription keys and app IDs in LuisDispatchBot.cs with the ones for the constituent LUIS apps and QnAMaker service.

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

@ -0,0 +1,10 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
</head>
<body>
Hi, I'm an example bot showing you how a LUIS app that is generated by the Dispatch tool can combine multiple LUIS apps and services.
</body>
</html>