Merge pull request #470 from DeniseMak/master
LUIS dispatch hierarchical sample
This commit is contained in:
Коммит
3ff1a6fe94
|
@ -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>
|
Загрузка…
Ссылка в новой задаче