Visit
Azure
Bot Service
to register your bot and add it to
various channels. The bot's endpoint URL typically looks
like this:
https://your_bots_hostname/api/messages
================================================
FILE: SDKV4-Samples/dotnet_core/DialogInterruptionsBot/BotBuilder.ruleset
================================================
================================================
FILE: SDKV4-Samples/dotnet_core/DialogInterruptionsBot/DeploymentScripts/MsbotClone/bot.recipe
================================================
{
"version": "1.0",
"resources": [
{
"type": "endpoint",
"id": "24",
"name": "Sample",
"url": "http://localhost:3978/api/messages"
},
{
"type": "endpoint",
"id": "2",
"name": "production",
"url": "https://your-bot-url.azurewebsites.net/api/messages"
},
{
"type": "abs",
"id": "3",
"name": "complex-dialog-Bot"
},
{
"type": "appInsights",
"id": "4",
"name": "complex-dialog-Insights"
},
{
"type": "blob",
"id": "5",
"name": "complex-dialog-Blob",
"container": "botstatestore"
}
]
}
================================================
FILE: SDKV4-Samples/dotnet_core/DialogInterruptionsBot/DialogInterruptionsBot.cs
================================================
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.BotBuilderSamples
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.Dialogs;
using Microsoft.Bot.Builder.Dialogs.Choices;
using Microsoft.Bot.Schema;
///
/// Represents a bot that processes incoming activities.
/// For each user interaction, an instance of this class is created and the OnTurnAsync method is called.
/// This is a Transient lifetime service. Transient lifetime services are created
/// each time they're requested. For each Activity received, a new instance of this
/// class is created. Objects that are expensive to construct, or have a lifetime
/// beyond the single turn, should be carefully managed.
/// For example, the object and associated
/// object are created with a singleton lifetime.
///
///
public class DialogInterruptionsBot : IBot
{
// Define the company choices for the company selection prompt.
private static class Companies
{
public const string Adatum = "Adatum Corporation";
public const string Contoso = "Contoso Suites";
public const string Gdi = "Graphic Design Institute";
public const string Wwi = "Wide World Importers";
public static readonly IReadOnlyDictionary Options
= new Dictionary
{
{ Adatum, "A market research company" },
{ Contoso, "A chain of hotels and inns" },
{ Gdi, "A school for graphic design" },
{ Wwi, "An importer of consumer goods" },
};
public static string MoreInfo { get; } =
string.Join("\r\r", Options.Select(e => $"**{e.Key}**--{e.Value}"));
}
// Define interruptions for the conversation.
private static class Interruptions
{
// "Global" interruptions.
public const string Wait = "wait";
public const string Continue = "continue";
public const string Cancel = "cancel";
// "Local" interruptions (to the review selection process).
public const string Finish = "finish";
public const string MoreInfo = "more info";
public const string Help = "help";
public static readonly string[] LocalOptions = new string[]
{
Finish, MoreInfo, Help,
};
public static readonly IReadOnlyDictionary Options
= new Dictionary
{
{ Cancel, "Cancel the review sign-up process." },
{ Continue, "Continues the conversation on hold, if any." },
{ Finish, "Complete the review sign-up process with the currently selected companies." },
{ Help, "List the available commands." },
{ MoreInfo, "Display information about the companies." },
{ Wait, "Puts the current conversation on hold." },
};
/// Describes the available commands.
public static string HelpText { get; } =
string.Join("\r\r", Options.Select(e => $"**{e.Key}**--{e.Value}"));
}
private const string WelcomeText =
"Welcome to DialogInterruptionsBot." +
" This bot provides a complex conversation, supporting various kinds of interruptions." +
" Type anything to get started.";
private static string GlobalHelpText { get; } =
"This bot helps you sign up to review companies." +
$" To pause the conversation at any time, enter `{Interruptions.Wait}`." +
$" To resume the conversation, enter `{Interruptions.Continue}`.";
private const string CancellationText =
"We have cancelled your sign up. Thankyou.";
private static string OnHoldText { get; } =
"The conversation is on hold." +
$" Enter `{Interruptions.Continue}` to continue the conversation where you left off.";
// Define the dialog and prompt names for the bot.
private const string TopLevelDialog = "dialog-topLevel";
private const string ReviewSelectionDialog = "dialog-reviewSeleciton";
private const string OnHoldDialog = "dialog-onHold";
private const string NamePrompt = "prompt-name";
private const string AgePrompt = "prompt-age";
private const string SelectionPrompt = "prompt-companySlection";
// Define value names for values tracked inside the dialogs.
private const string UserInfo = "value-userInfo";
private const string CompaniesSelected = "value-companiesSelected";
///
/// Contains the state property accessors and state management objects for the bot.
///
private readonly DialogInterruptionsBotAccessors _accessors;
///
/// The that contains all the Dialogs that can be used at runtime.
///
private readonly DialogSet _dialogs;
///
/// Initializes a new instance of the class.
///
/// A class containing used to manage state.
public DialogInterruptionsBot(DialogInterruptionsBotAccessors accessors)
{
_accessors = accessors ?? throw new ArgumentNullException(nameof(accessors));
// Create a dialog set for the bot. It requires a DialogState accessor, with which
// to retrieve the dialog state from the turn context.
_dialogs = new DialogSet(accessors.DialogStateAccessor);
// Add the prompts we need to the dialog set.
_dialogs
.Add(new TextPrompt(NamePrompt))
.Add(new NumberPrompt(AgePrompt))
.Add(new ChoicePrompt(SelectionPrompt) { Style = ListStyle.List });
// Add the dialogs we need to the dialog set.
_dialogs.Add(new WaterfallDialog(TopLevelDialog)
.AddStep(NameStepAsync)
.AddStep(AgeStepAsync)
.AddStep(StartSelectionStepAsync)
.AddStep(AcknowledgementStepAsync));
_dialogs.Add(new WaterfallDialog(ReviewSelectionDialog)
.AddStep(SelectionStepAsync)
.AddStep(LoopStepAsync));
_dialogs.Add(new WaterfallDialog(OnHoldDialog)
.AddStep(OnHoldStepAsync)
.AddStep(ContinueToHoldStepAsync));
}
///
/// Every conversation turn for our EchoBot will call this method.
///
/// A containing all the data needed
/// for processing this conversation turn.
/// (Optional) A that can be used by other objects
/// or threads to receive notice of cancellation.
/// A that represents the work queued to execute.
///
///
///
public async Task OnTurnAsync(
ITurnContext turnContext,
CancellationToken cancellationToken = default(CancellationToken))
{
if (turnContext == null)
{
throw new ArgumentNullException(nameof(turnContext));
}
// Handle Message activity type, which is the main activity type for shown within a conversational interface
// Message activities may contain text, speech, interactive cards, and binary or unknown attachments.
// see https://aka.ms/about-bot-activity-message to learn more about the message and other activity types
if (turnContext.Activity.Type == ActivityTypes.Message)
{
string input = turnContext.Activity.Text?.Trim();
// Handle any "global" interruptions before continuing.
// On a request for help, display global help.
if (string.Equals(input, Interruptions.Help, StringComparison.InvariantCultureIgnoreCase))
{
await turnContext.SendActivityAsync(GlobalHelpText, cancellationToken: cancellationToken);
return;
}
DialogContext dialogContext = await _dialogs.CreateContextAsync(turnContext, cancellationToken);
// If we're not currently on hold, check whether the user wants to go on hold.
if (dialogContext.ActiveDialog?.Id != OnHoldDialog)
{
if (string.Equals(input, Interruptions.Wait, StringComparison.InvariantCultureIgnoreCase))
{
// Transition onto hold.
await dialogContext.BeginDialogAsync(OnHoldDialog, null, cancellationToken);
await _accessors.ConversationState.SaveChangesAsync(turnContext, false, cancellationToken);
return;
}
}
// On a request to cancel, clear the dialog stack completely.
if (string.Equals(input, Interruptions.Cancel, StringComparison.InvariantCultureIgnoreCase))
{
await dialogContext.CancelAllDialogsAsync(cancellationToken);
await turnContext.SendActivityAsync(CancellationText, cancellationToken: cancellationToken);
await _accessors.ConversationState.SaveChangesAsync(turnContext, false, cancellationToken);
return;
}
// Run the DialogSet - let the framework identify the current state of the dialog from
// the dialog stack and figure out what (if any) is the active dialog.
DialogTurnResult results = await dialogContext.ContinueDialogAsync(cancellationToken);
switch (results.Status)
{
case DialogTurnStatus.Cancelled:
case DialogTurnStatus.Empty:
// If there is no active dialog, we should clear the user info and start a new dialog.
await _accessors.UserProfileAccessor.SetAsync(turnContext, new UserProfile(), cancellationToken);
await _accessors.UserState.SaveChangesAsync(turnContext, false, cancellationToken);
await dialogContext.BeginDialogAsync(TopLevelDialog, null, cancellationToken);
break;
case DialogTurnStatus.Complete:
// If we just finished the dialog, capture and display the results.
UserProfile userInfo = results.Result as UserProfile;
string status = "You are signed up to review "
+ (userInfo.CompaniesToReview.Count is 0 ? "no companies" : string.Join(" and ", userInfo.CompaniesToReview))
+ ".";
await turnContext.SendActivityAsync(status);
await _accessors.UserProfileAccessor.SetAsync(turnContext, userInfo, cancellationToken);
await _accessors.UserState.SaveChangesAsync(turnContext, false, cancellationToken);
break;
case DialogTurnStatus.Waiting:
// If there is an active dialog, we don't need to do anything here.
break;
}
await _accessors.ConversationState.SaveChangesAsync(turnContext, false, cancellationToken);
}
// Processes ConversationUpdate Activities to welcome the user.
else if (turnContext.Activity.Type == ActivityTypes.ConversationUpdate)
{
if (turnContext.Activity.MembersAdded != null)
{
await SendWelcomeMessageAsync(turnContext, cancellationToken);
}
}
else
{
// Otherwise, note what type of unexpected activity we just received.
await turnContext.SendActivityAsync(
$"{turnContext.Activity.Type} event detected",
cancellationToken: cancellationToken);
}
}
///
/// Sends a welcome message to the user.
///
/// A containing all the data needed
/// for processing this conversation turn.
/// (Optional) A that can be used by other objects
/// or threads to receive notice of cancellation.
/// A that represents the work queued to execute.
private static async Task SendWelcomeMessageAsync(
ITurnContext turnContext,
CancellationToken cancellationToken)
{
foreach (ChannelAccount member in turnContext.Activity.MembersAdded)
{
if (member.Id != turnContext.Activity.Recipient.Id)
{
Activity reply = turnContext.Activity.CreateReply();
reply.Text = WelcomeText;
await turnContext.SendActivityAsync(reply, cancellationToken);
}
}
}
/// The first step of the top-level dialog.
/// The waterfall step context for the current turn.
/// A cancellation token that can be used by other objects
/// or threads to receive notice of cancellation.
/// A task that represents the work queued to execute.
/// If the task is successful, the result contains a to
/// communicate some flow control back to the containing WaterfallDialog.
private static async Task NameStepAsync(
WaterfallStepContext stepContext,
CancellationToken cancellationToken)
{
// Create an object in which to collect the user's information within the dialog.
stepContext.Values[UserInfo] = new UserProfile();
Activity prompt = MessageFactory.Text("Please enter your name.");
// Ask the user to enter their name.
return await stepContext.PromptAsync(
NamePrompt,
new PromptOptions { Prompt = prompt, RetryPrompt = prompt },
cancellationToken);
}
/// The second step of the top-level dialog.
/// The waterfall step context for the current turn.
/// A cancellation token that can be used by other objects
/// or threads to receive notice of cancellation.
/// A task that represents the work queued to execute.
/// If the task is successful, the result contains a to
/// communicate some flow control back to the containing WaterfallDialog.
private static async Task AgeStepAsync(
WaterfallStepContext stepContext,
CancellationToken cancellationToken)
{
// Set the user's name to what they entered in response to the name prompt.
((UserProfile)stepContext.Values[UserInfo]).Name = (string)stepContext.Result;
Activity prompt = MessageFactory.Text("Please enter your age.");
// Ask the user to enter their age.
return await stepContext.PromptAsync(
AgePrompt,
new PromptOptions { Prompt = prompt, RetryPrompt = prompt },
cancellationToken);
}
/// The third step of the top-level dialog.
/// The waterfall step context for the current turn.
/// A cancellation token that can be used by other objects
/// or threads to receive notice of cancellation.
/// A task that represents the work queued to execute.
/// If the task is successful, the result contains a to
/// communicate some flow control back to the containing WaterfallDialog.
private static async Task StartSelectionStepAsync(
WaterfallStepContext stepContext,
CancellationToken cancellationToken)
{
// Set the user's age to what they entered in response to the age prompt.
int age = (int)stepContext.Result;
((UserProfile)stepContext.Values[UserInfo]).Age = age;
if (age < 25)
{
// If they are too young, skip the review selection dialog, and pass an empty list to the next step.
await stepContext.Context.SendActivityAsync(
MessageFactory.Text("You must be 25 or older to participate."),
cancellationToken);
return await stepContext.NextAsync(new List(), cancellationToken);
}
else
{
// Otherwise, start the review selection dialog.
return await stepContext.BeginDialogAsync(ReviewSelectionDialog, null, cancellationToken);
}
}
/// The final step of the top-level dialog.
/// The waterfall step context for the current turn.
/// A cancellation token that can be used by other objects
/// or threads to receive notice of cancellation.
/// A task that represents the work queued to execute.
/// If the task is successful, the result contains a to
/// communicate some flow control back to the containing WaterfallDialog.
private static async Task AcknowledgementStepAsync(
WaterfallStepContext stepContext,
CancellationToken cancellationToken)
{
// Set the user's company selection to what they entered in the review-selection dialog.
List list = stepContext.Result as List;
var profile = (UserProfile)stepContext.Values[UserInfo];
profile.CompaniesToReview = list ?? new List();
// Thank them for participating.
await stepContext.Context.SendActivityAsync(
MessageFactory.Text($"Thanks for participating, {profile.Name}."),
cancellationToken);
// Exit the dialog, returning the collected user information.
return await stepContext.EndDialogAsync(stepContext.Values[UserInfo], cancellationToken);
}
/// The first step of the review-selection dialog.
/// The waterfall step context for the current turn.
/// A cancellation token that can be used by other objects
/// or threads to receive notice of cancellation.
/// A task that represents the work queued to execute.
/// If the task is successful, the result contains a to
/// communicate some flow control back to the containing WaterfallDialog.
private static async Task SelectionStepAsync(
WaterfallStepContext stepContext,
CancellationToken cancellationToken)
{
// Continue using the same selection list, if any, from the previous iteration of this dialog.
List list = stepContext.Options as List ?? new List();
stepContext.Values[CompaniesSelected] = list;
// Create a prompt message.
string message;
if (list.Count is 0)
{
message = $"Please choose a company to review:";
}
else
{
message = $"You have selected **{list[0]}**. You can review an additional company:";
}
// Create the list of options to choose from.
List options = Companies.Options.Keys.ToList();
options.AddRange(Interruptions.LocalOptions);
if (list.Count > 0)
{
options.Remove(list[0]);
}
// Prompt the user for a choice.
return await stepContext.PromptAsync(
SelectionPrompt,
new PromptOptions
{
Prompt = MessageFactory.Text(message),
RetryPrompt = MessageFactory.Text("Please choose an option from the list."),
Choices = ChoiceFactory.ToChoices(options),
},
cancellationToken);
}
/// The final step of the review-selection dialog.
/// The waterfall step context for the current turn.
/// A cancellation token that can be used by other objects
/// or threads to receive notice of cancellation.
/// A task that represents the work queued to execute.
/// If the task is successful, the result contains a to
/// communicate some flow control back to the containing WaterfallDialog.
private static async Task LoopStepAsync(
WaterfallStepContext stepContext,
CancellationToken cancellationToken)
{
// Retrieve their selection list and the choice they juat made.
List list = stepContext.Values[CompaniesSelected] as List;
FoundChoice choice = (FoundChoice)stepContext.Result;
// Handle any local, expected interruptions appropriately.
switch (choice.Value)
{
case Interruptions.Finish:
// Exit and return their current selection list.
return await stepContext.EndDialogAsync(list, cancellationToken);
case Interruptions.Cancel:
// Exit and return null.
return await stepContext.EndDialogAsync(null, cancellationToken);
case Interruptions.Help:
// Dispaly the help options.
await stepContext.Context.SendActivityAsync(
Interruptions.HelpText,
cancellationToken: cancellationToken);
break;
case Interruptions.MoreInfo:
// Display more information about the companies.
await stepContext.Context.SendActivityAsync(
Companies.MoreInfo,
cancellationToken: cancellationToken);
break;
default:
// If they chose a company, add it to the list.
list.Add(choice.Value);
break;
}
if (list.Count is 2)
{
// If they've selected 2 companies to review, exit and return their list.
return await stepContext.EndDialogAsync(list, cancellationToken);
}
else
{
// Otherwise, repeat this dialog, passing in the list from this iteration.
return await stepContext.ReplaceDialogAsync(ReviewSelectionDialog, list, cancellationToken);
}
}
/// The first step of the on-hold dialog.
/// The waterfall step context for the current turn.
/// A cancellation token that can be used by other objects
/// or threads to receive notice of cancellation.
/// A task that represents the work queued to execute.
/// If the task is successful, the result contains a to
/// communicate some flow control back to the containing WaterfallDialog.
private static async Task OnHoldStepAsync(
WaterfallStepContext stepContext,
CancellationToken cancellationToken)
{
string input = stepContext.Context.Activity.Text?.Trim();
if (string.Equals(input, Interruptions.Continue, StringComparison.InvariantCultureIgnoreCase))
{
// Exit and return to the last active dialog state.
return await stepContext.EndDialogAsync(null, cancellationToken);
}
else
{
// Send a status message and let the dialog contnue on the next turn.
await stepContext.Context.SendActivityAsync(OnHoldText, cancellationToken: cancellationToken);
return Dialog.EndOfTurn;
}
}
/// The last step of the on-hold dialog.
/// The waterfall step context for the current turn.
/// A cancellation token that can be used by other objects
/// or threads to receive notice of cancellation.
/// A task that represents the work queued to execute.
/// If the task is successful, the result contains a to
/// communicate some flow control back to the containing WaterfallDialog.
private static async Task ContinueToHoldStepAsync(
WaterfallStepContext stepContext,
CancellationToken cancellationToken)
{
// Restart the on-hold dialog.
return await stepContext.ReplaceDialogAsync(OnHoldDialog, null, cancellationToken);
}
}
}
================================================
FILE: SDKV4-Samples/dotnet_core/DialogInterruptionsBot/DialogInterruptionsBot.csproj
================================================
netcoreapp2.0BotBuilder.rulesetMicrosoft.BotBuilderSamplesAlways
================================================
FILE: SDKV4-Samples/dotnet_core/DialogInterruptionsBot/DialogInterruptionsBotAccessors.cs
================================================
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.BotBuilderSamples
{
using System;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.Dialogs;
///
/// This class is created as a Singleton and passed into the IBot-derived constructor.
/// - See constructor for how that is injected.
/// - See the Startup.cs file for more details on creating the Singleton that gets
/// injected into the constructor.
///
public class DialogInterruptionsBotAccessors
{
///
/// Initializes a new instance of the class.
/// Contains the and associated .
///
/// The state object that stores the dialog state.
/// The state object that stores the user state.
public DialogInterruptionsBotAccessors(ConversationState conversationState, UserState userState)
{
ConversationState = conversationState ?? throw new ArgumentNullException(nameof(conversationState));
UserState = userState ?? throw new ArgumentNullException(nameof(userState));
}
///
/// Gets or sets the for ConversationDialogState.
///
///
/// The accessor stores the dialog state for the conversation.
///
public IStatePropertyAccessor DialogStateAccessor { get; set; }
///
/// Gets or sets the for CounterState.
///
///
/// The accessor stores user data.
///
public IStatePropertyAccessor UserProfileAccessor { get; set; }
///
/// Gets the object for the conversation.
///
/// The object.
public ConversationState ConversationState { get; }
///
/// Gets the object for the conversation.
///
/// The object.
public UserState UserState { get; }
}
}
================================================
FILE: SDKV4-Samples/dotnet_core/DialogInterruptionsBot/Program.cs
================================================
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Logging;
namespace Microsoft.BotBuilderSamples
{
public class Program
{
public static void Main(string[] args)
{
BuildWebHost(args).Run();
}
public static IWebHost BuildWebHost(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.ConfigureLogging((hostingContext, logging) =>
{
// Add Azure Logging
logging.AddAzureWebAppDiagnostics();
// Logging Options.
// There are other logging options available:
// https://docs.microsoft.com/en-us/aspnet/core/fundamentals/logging/?view=aspnetcore-2.1
// logging.AddDebug();
// logging.AddConsole();
})
// Logging Options.
// Consider using Application Insights for your logging and metrics needs.
// https://azure.microsoft.com/en-us/services/application-insights/
// .UseApplicationInsights()
.UseStartup()
.Build();
}
}
================================================
FILE: SDKV4-Samples/dotnet_core/DialogInterruptionsBot/Properties/launchSettings.json
================================================
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:3978/",
"sslPort": 0
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"DialogInterruptions_Sample": {
"commandName": "Project",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "http://localhost:3978/"
}
}
}
================================================
FILE: SDKV4-Samples/dotnet_core/DialogInterruptionsBot/README.md
================================================
This sample creates a dialog-based conversation that can be interrupted in various ways in ASP.Net Core 2.
# To try this sample
- Clone the samples repository
```bash
git clone https://github.com/Microsoft/BotFramework-Samples.git
```
- [Optional] Update the `appsettings.json` file under `BotFramework-Samples/SDKV4-Samples/dotnet_core/DialogInterruptionsBot/` with your botFileSecret.
For Azure Bot Service bots, you can find the botFileSecret under application settings.
# Running Locally
## Visual Studio
- Navigate to the samples folder (`BotFramework-Samples/SDKV4-Samples/dotnet_core/DialogInterruptionsBot/`) and open DialogInterruptionsBot.csproj in Visual Studio.
- Run the project (press `F5` key).
## .NET Core CLI
- Install the [.NET Core CLI tools](https://docs.microsoft.com/dotnet/core/tools/?tabs=netcore2x).
- Using the command line, navigate to `BotFramework-Samples/SDKV4-Samples/dotnet_core/DialogInterruptionsBot/` folder.
- Type `dotnet run`.
## Testing the bot using Bot Framework Emulator
[Microsoft Bot Framework Emulator](https://github.com/microsoft/botframework-emulator) is a desktop application that allows bot
developers to test and debug their bots on localhost or running remotely through a tunnel.
- Install the Bot Framework emulator from [here](https://aka.ms/botframeworkemulator).
## Connect to bot using Bot Framework Emulator **V4**
- Launch the Bot Framework Emulator.
- File -> Open bot and navigate to `BotFramework-Samples/SDKV4-Samples/dotnet_core/DialogInterruptionsBot` folder.
- Select `complex-dialog.bot` file.
# Further reading
- [Azure Bot Service](https://docs.microsoft.com/azure/bot-service/bot-service-overview-introduction?view=azure-bot-service-4.0)
- [Bot Storage](https://docs.microsoft.com/azure/bot-service/dotnet/bot-builder-dotnet-state?view=azure-bot-service-3.0&viewFallbackFrom=azure-bot-service-4.0)
================================================
FILE: SDKV4-Samples/dotnet_core/DialogInterruptionsBot/Startup.cs
================================================
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.BotBuilderSamples
{
using System;
using System.Linq;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.Dialogs;
using Microsoft.Bot.Builder.Integration.AspNet.Core;
using Microsoft.Bot.Configuration;
using Microsoft.Bot.Connector.Authentication;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
///
/// The Startup class configures services and the app's request pipeline.
///
public class Startup
{
private ILoggerFactory _loggerFactory;
private bool _isProduction = false;
public Startup(IHostingEnvironment env)
{
_isProduction = env.IsProduction();
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();
}
///
/// Gets the configuration that represents a set of key/value application configuration properties.
///
///
/// The that represents a set of key/value application configuration properties.
///
public IConfiguration Configuration { get; }
///
/// This method gets called by the runtime. Use this method to add services to the container.
///
/// Specifies the contract for a of service descriptors.
///
///
///
public void ConfigureServices(IServiceCollection services)
{
services.AddBot(options =>
{
var secretKey = Configuration.GetSection("botFileSecret")?.Value;
var botFilePath = Configuration.GetSection("botFilePath")?.Value;
// Loads .bot configuration file and adds a singleton that your Bot can access through dependency injection.
var botConfig = BotConfiguration.Load(botFilePath ?? @".\complex-dialog.bot", secretKey);
services.AddSingleton(sp => botConfig ?? throw new InvalidOperationException($"The .bot configuration file could not be loaded. ({botConfig})"));
// Retrieve current endpoint.
var environment = _isProduction ? "production" : "development";
var service = botConfig.Services.FirstOrDefault(s => s.Type == "endpoint" && s.Name == environment);
if (!(service is EndpointService endpointService))
{
throw new InvalidOperationException($"The .bot file does not contain an endpoint with name '{environment}'.");
}
options.CredentialProvider = new SimpleCredentialProvider(endpointService.AppId, endpointService.AppPassword);
// Creates a logger for the application to use.
ILogger logger = _loggerFactory.CreateLogger();
// Catches any errors that occur during a conversation turn and logs them.
options.OnTurnError = async (context, exception) =>
{
logger.LogError($"Exception caught : {exception}");
await context.SendActivityAsync("Sorry, it looks like something went wrong.");
};
});
// Create conversation and user state management objects, using memory storage.
IStorage dataStore = new MemoryStorage();
var conversationState = new ConversationState(dataStore);
var userState = new UserState(dataStore);
// Create and register state accessors.
// Accessors created here are passed into the IBot-derived class on every turn.
services.AddSingleton(sp =>
{
// Create the custom state accessor.
// State accessors enable other components to read and write individual properties of state.
var accessors = new DialogInterruptionsBotAccessors(conversationState, userState)
{
DialogStateAccessor = conversationState.CreateProperty("DialogState"),
UserProfileAccessor = userState.CreateProperty("UserProfile"),
};
return accessors;
});
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
_loggerFactory = loggerFactory;
app.UseDefaultFiles()
.UseStaticFiles()
.UseBotFramework();
}
}
}
================================================
FILE: SDKV4-Samples/dotnet_core/DialogInterruptionsBot/UserProfile.cs
================================================
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace Microsoft.BotBuilderSamples
{
using System.Collections.Generic;
/// Contains information about a user.
public class UserProfile
{
/// Gets or sets the user's name.
/// The user's name.
public string Name { get; set; }
/// Gets or sets the user's age.
/// The user's age.
public int Age { get; set; }
/// Gets or sets the list of companies the user wants to review.
/// The list of companies the user wants to review.
public List CompaniesToReview { get; set; } = new List();
}
}
================================================
FILE: SDKV4-Samples/dotnet_core/DialogInterruptionsBot/appsettings.json
================================================
{
"botFilePath": "dialog-interruptions.bot",
"botFileSecret": ""
}
================================================
FILE: SDKV4-Samples/dotnet_core/DialogInterruptionsBot/dialog-interruptions.bot
================================================
{
"name": "dialog-interruptions-bot",
"services": [
{
"type": "endpoint",
"name": "development",
"endpoint": "http://localhost:3978/api/messages",
"appId": "",
"appPassword": "",
"id": "24"
}
],
"padlock": "",
"version": "2.0"
}
================================================
FILE: SDKV4-Samples/dotnet_core/DialogInterruptionsBot/wwwroot/default.htm
================================================
Dialog with interruptions sample
Dialog with Interruptions Bot
Your bot is ready!
You can test your bot in the Bot Framework Emulator
by opening the .bot file in the project folder.
Visit
Azure
Bot Service
to register your bot and add it to
various channels. The bot's endpoint URL typically looks
like this:
https://your_bots_hostname/api/messages
================================================
FILE: SDKV4-Samples/dotnet_core/DialogPromptBot/DeploymentScripts/MsbotClone/bot.recipe
================================================
{
"version": "1.0",
"resources": [
{
"type": "endpoint",
"id": "1",
"name": "development",
"url": "http://localhost:3978/api/messages"
},
{
"type": "endpoint",
"id": "2",
"name": "production",
"url": "https://your-bot-url.azurewebsites.net/api/messages"
},
{
"type": "abs",
"id": "3",
"name": "DialogPromptBot-abs"
},
{
"type": "appInsights",
"id": "4",
"name": "DialogPromptBot-insights"
},
{
"type": "blob",
"id": "5",
"name": "DialogPromptBot-blob",
"container": "botstatestore"
}
]
}
================================================
FILE: SDKV4-Samples/dotnet_core/DialogPromptBot/DialogPromptBot.cs
================================================
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.Dialogs;
using Microsoft.Bot.Builder.Dialogs.Choices;
using Microsoft.Bot.Schema;
using Microsoft.Extensions.Logging;
namespace Microsoft.BotBuilderSamples
{
///
/// Represents a bot that processes incoming activities.
/// For each user interaction, an instance of this class is created and the OnTurnAsync method
/// is called. This is a Transient lifetime service. Transient lifetime services are created
/// each time they're requested. For each Activity received, a new instance of this class is
/// created. Objects that are expensive to construct, or have a lifetime beyond the single
/// turn, should be carefully managed. For example, the object and
/// associated object are created with a singleton lifetime.
///
public class DialogPromptBot : IBot
{
// Define identifiers for our dialogs and prompts.
private const string ReservationDialog = "reservationDialog";
private const string SizeRangePrompt = "sizeRangePrompt";
private const string LocationPrompt = "locationPrompt";
private const string ReservationDatePrompt = "reservationDatePrompt";
// Define keys for tracked values within the dialog.
private const string LocationKey = "location";
private const string PartySizeKey = "partySize";
private readonly DialogSet _dialogSet;
private readonly DialogPromptBotAccessors _accessors;
private readonly ILogger _logger;
///
/// Initializes a new instance of the class.
///
/// A class containing used
/// to manage state.
/// A that is hooked to the Azure
/// App Service provider.
public DialogPromptBot(DialogPromptBotAccessors accessors, ILoggerFactory loggerFactory)
{
if (loggerFactory == null)
{
throw new System.ArgumentNullException(nameof(loggerFactory));
}
_logger = loggerFactory.CreateLogger();
_logger.LogTrace("EchoBot turn start.");
_accessors = accessors ?? throw new System.ArgumentNullException(nameof(accessors));
// Create the dialog set and add the prompts, including custom validation.
_dialogSet = new DialogSet(_accessors.DialogStateAccessor);
_dialogSet.Add(new NumberPrompt(SizeRangePrompt, RangeValidatorAsync));
_dialogSet.Add(new ChoicePrompt(LocationPrompt));
_dialogSet.Add(new DateTimePrompt(ReservationDatePrompt, DateValidatorAsync));
// Define the steps of the waterfall dialog and add it to the set.
var steps = new WaterfallStep[]
{
PromptForPartySizeAsync,
PromptForLocationAsync,
PromptForReservationDateAsync,
AcknowledgeReservationAsync,
};
_dialogSet.Add(new WaterfallDialog(ReservationDialog, steps));
}
///
/// Every conversation turn for our Echo Bot will call this method.
/// There are no dialogs used, since it's "single turn" processing, meaning a single
/// request and response.
///
/// A containing all the data needed
/// for processing this conversation turn.
/// (Optional) A that can
/// be used by other objects or threads to receive notice of cancellation.
/// A that represents the work queued to execute.
///
///
///
public async Task OnTurnAsync(
ITurnContext turnContext,
CancellationToken cancellationToken = default(CancellationToken))
{
switch (turnContext.Activity.Type)
{
// On a message from the user:
case ActivityTypes.Message:
// Get the current reservation info from state.
var reservation = await _accessors.ReservationAccessor.GetAsync(
turnContext,
() => null,
cancellationToken);
// Generate a dialog context for our dialog set.
var dc = await _dialogSet.CreateContextAsync(turnContext, cancellationToken);
if (dc.ActiveDialog is null)
{
// If there is no active dialog, check whether we have a reservation yet.
if (reservation is null)
{
// If not, start the dialog.
await dc.BeginDialogAsync(ReservationDialog, null, cancellationToken);
}
else
{
// Otherwise, send a status message.
await turnContext.SendActivityAsync(
$"We'll see you on {reservation.Date}.",
cancellationToken: cancellationToken);
}
}
else
{
// Continue the dialog.
var dialogTurnResult = await dc.ContinueDialogAsync(cancellationToken);
// If the dialog completed this turn, record the reservation info.
if (dialogTurnResult.Status is DialogTurnStatus.Complete)
{
reservation = (Reservation)dialogTurnResult.Result;
await _accessors.ReservationAccessor.SetAsync(
turnContext,
reservation,
cancellationToken);
// Send a confirmation message to the user.
await turnContext.SendActivityAsync(
$"Your party of {reservation.Size} is confirmed for " +
$"{reservation.Date} in {reservation.Location}.",
cancellationToken: cancellationToken);
}
}
// Save the updated dialog state into the conversation state.
await _accessors.ConversationState.SaveChangesAsync(
turnContext, false, cancellationToken);
break;
}
}
/// First step of the main dialog: prompt for party size.
/// The context for the waterfall step.
/// A cancellation token that can be used by other objects
/// or threads to receive notice of cancellation.
/// A task that represents the work queued to execute.
/// If the task is successful, the result contains information from this step.
private async Task PromptForPartySizeAsync(
WaterfallStepContext stepContext,
CancellationToken cancellationToken = default(CancellationToken))
{
// Prompt for the party size. The result of the prompt is returned to the next step of the waterfall.
return await stepContext.PromptAsync(
SizeRangePrompt,
new PromptOptions
{
Prompt = MessageFactory.Text("How many people is the reservation for?"),
RetryPrompt = MessageFactory.Text("How large is your party?"),
Validations = new Range { Min = 3, Max = 8 },
},
cancellationToken);
}
/// Second step of the main dialog: prompt for location.
/// The context for the waterfall step.
/// A cancellation token that can be used by other objects
/// or threads to receive notice of cancellation.
/// A task that represents the work queued to execute.
/// If the task is successful, the result contains information from this step.
private async Task PromptForLocationAsync(
WaterfallStepContext stepContext,
CancellationToken cancellationToken)
{
// Record the party size information in the current dialog state.
var size = (int)stepContext.Result;
stepContext.Values[PartySizeKey] = size;
// Prompt for the location.
return await stepContext.PromptAsync(
LocationPrompt,
new PromptOptions
{
Prompt = MessageFactory.Text("Please choose a location."),
RetryPrompt = MessageFactory.Text("Sorry, please choose a location from the list."),
Choices = ChoiceFactory.ToChoices(new List { "Redmond", "Bellevue", "Seattle" }),
},
cancellationToken);
}
/// Third step of the main dialog: prompt for the reservation date.
/// The context for the waterfall step.
/// A cancellation token that can be used by other objects
/// or threads to receive notice of cancellation.
/// A task that represents the work queued to execute.
/// If the task is successful, the result contains information from this step.
private async Task PromptForReservationDateAsync(
WaterfallStepContext stepContext,
CancellationToken cancellationToken = default(CancellationToken))
{
// Record the party size information in the current dialog state.
var location = (stepContext.Result as FoundChoice).Value;
stepContext.Values[LocationKey] = location;
// Prompt for the reservation date.
return await stepContext.PromptAsync(
ReservationDatePrompt,
new PromptOptions
{
Prompt = MessageFactory.Text("Great. When will the reservation be for?"),
RetryPrompt = MessageFactory.Text("What time should we make your reservation for?"),
},
cancellationToken);
}
/// Last step of the main dialog: return the collected reservation information.
/// The context for the waterfall step.
/// A cancellation token that can be used by other objects
/// or threads to receive notice of cancellation.
/// A task that represents the work queued to execute.
/// If the task is successful, the result contains information from this step.
private async Task AcknowledgeReservationAsync(
WaterfallStepContext stepContext,
CancellationToken cancellationToken = default(CancellationToken))
{
// Retrieve the reservation date.
var resolution = (stepContext.Result as IList).First();
var time = resolution.Value ?? resolution.Start;
// Send an acknowledgement to the user.
await stepContext.Context.SendActivityAsync(
"Thank you. We will confirm your reservation shortly.",
cancellationToken: cancellationToken);
// Return the collected information to the parent context.
var reservation = new Reservation
{
Date = time,
Size = (int)stepContext.Values[PartySizeKey],
Location = (string)stepContext.Values[LocationKey],
};
return await stepContext.EndDialogAsync(reservation, cancellationToken);
}
/// Validates whether the party size is appropriate to make a reservation.
/// The validation context.
/// A cancellation token that can be used by other objects
/// or threads to receive notice of cancellation.
/// A task that represents the work queued to execute.
/// Reservations can be made for groups of 6 to 20 people.
/// If the task is successful, the result indicates whether the input was valid.
private async Task RangeValidatorAsync(
PromptValidatorContext promptContext,
CancellationToken cancellationToken)
{
// Check whether the input could be recognized as an integer.
if (!promptContext.Recognized.Succeeded)
{
await promptContext.Context.SendActivityAsync(
"I'm sorry, I do not understand. Please enter the number of people in your party.",
cancellationToken: cancellationToken);
return false;
}
// Check whether the party size is appropriate.
var size = promptContext.Recognized.Value;
var validRange = promptContext.Options.Validations as Range;
if (size < validRange.Min || size > validRange.Max)
{
await promptContext.Context.SendActivitiesAsync(
new Activity[]
{
MessageFactory.Text($"Sorry, we can only take reservations for parties " +
$"of {validRange.Min} to {validRange.Max}."),
promptContext.Options.RetryPrompt,
},
cancellationToken: cancellationToken);
return false;
}
return true;
}
/// Validates whether the reservation date is appropriate.
/// The validation context.
/// A cancellation token that can be used by other objects
/// or threads to receive notice of cancellation.
/// A task that represents the work queued to execute.
/// Reservations must be made at least an hour in advance.
/// If the task is successful, the result indicates whether the input was valid.
private async Task DateValidatorAsync(
PromptValidatorContext> promptContext,
CancellationToken cancellationToken = default(CancellationToken))
{
// Check whether the input could be recognized as an integer.
if (!promptContext.Recognized.Succeeded)
{
await promptContext.Context.SendActivityAsync(
"I'm sorry, I do not understand. Please enter the date or time for your reservation.",
cancellationToken: cancellationToken);
return false;
}
// Check whether any of the recognized date-times are appropriate,
// and if so, return the first appropriate date-time.
var earliest = DateTime.Now.AddHours(1.0);
var value = promptContext.Recognized.Value.FirstOrDefault(v =>
DateTime.TryParse(v.Value ?? v.Start, out var time) && DateTime.Compare(earliest, time) <= 0);
if (value != null)
{
promptContext.Recognized.Value.Clear();
promptContext.Recognized.Value.Add(value);
return true;
}
await promptContext.Context.SendActivityAsync(
"I'm sorry, we can't take reservations earlier than an hour from now.",
cancellationToken: cancellationToken);
return false;
}
/// Describes an acceptable range of values.
public class Range
{
public int Min { get; set; }
public int Max { get; set; }
}
/// Holds a user's reservation information.
public class Reservation
{
public int Size { get; set; }
public string Location { get; set; }
public string Date { get; set; }
}
}
}
================================================
FILE: SDKV4-Samples/dotnet_core/DialogPromptBot/DialogPromptBot.csproj
================================================
netcoreapp2.0DialogPromptBot.ruleset$(OutputPath)$(AssemblyName).xml$(NoWarn),1573,1591,1712Always
================================================
FILE: SDKV4-Samples/dotnet_core/DialogPromptBot/DialogPromptBot.ruleset
================================================
================================================
FILE: SDKV4-Samples/dotnet_core/DialogPromptBot/DialogPromptBot.xml
================================================
DialogPromptBot
Represents a bot that processes incoming activities.
For each user interaction, an instance of this class is created and the OnTurnAsync method
is called. This is a Transient lifetime service. Transient lifetime services are created
each time they're requested. For each Activity received, a new instance of this class is
created. Objects that are expensive to construct, or have a lifetime beyond the single
turn, should be carefully managed. For example, the object and
associated object are created with a singleton lifetime.
Initializes a new instance of the class.
A class containing used
to manage state.
A that is hooked to the Azure
App Service provider.
Every conversation turn for our Echo Bot will call this method.
There are no dialogs used, since it's "single turn" processing, meaning a single
request and response.
A containing all the data needed
for processing this conversation turn.
(Optional) A that can
be used by other objects or threads to receive notice of cancellation.
A that represents the work queued to execute.First step of the main dialog: prompt for party size.
The context for the waterfall step.
A cancellation token that can be used by other objects
or threads to receive notice of cancellation.
A task that represents the work queued to execute.If the task is successful, the result contains information from this step.Second step of the main dialog: prompt for location.
The context for the waterfall step.
A cancellation token that can be used by other objects
or threads to receive notice of cancellation.
A task that represents the work queued to execute.If the task is successful, the result contains information from this step.Third step of the main dialog: prompt for the reservation date.
The context for the waterfall step.
A cancellation token that can be used by other objects
or threads to receive notice of cancellation.
A task that represents the work queued to execute.If the task is successful, the result contains information from this step.Last step of the main dialog: return the collected reservation information.
The context for the waterfall step.
A cancellation token that can be used by other objects
or threads to receive notice of cancellation.
A task that represents the work queued to execute.If the task is successful, the result contains information from this step.Validates whether the party size is appropriate to make a reservation.
The validation context.
A cancellation token that can be used by other objects
or threads to receive notice of cancellation.
A task that represents the work queued to execute.Reservations can be made for groups of 6 to 20 people.
If the task is successful, the result indicates whether the input was valid.Validates whether the reservation date is appropriate.
The validation context.
A cancellation token that can be used by other objects
or threads to receive notice of cancellation.
A task that represents the work queued to execute.Reservations must be made at least an hour in advance.
If the task is successful, the result indicates whether the input was valid.Describes an acceptable range of values.Holds a user's reservation information.
This class is created as a Singleton and passed into the IBot-derived constructor.
- See constructor for how that is injected.
- See the Startup.cs file for more details on creating the Singleton that gets
injected into the constructor.
Initializes a new instance of the class.
Contains the and associated .
The state object that stores the counter.
Gets or sets the for CounterState.
The accessor stores the turn count for the conversation.
Gets the object for the conversation.
The object.
The Startup class configures services and the request pipeline.
Gets the configuration that represents a set of key/value application configuration properties.
The that represents a set of key/value application configuration properties.
This method gets called by the runtime. Use this method to add services to the container.
The specifies the contract for a collection of service descriptors.
================================================
FILE: SDKV4-Samples/dotnet_core/DialogPromptBot/DialogPromptBotAccessors.cs
================================================
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.Dialogs;
namespace Microsoft.BotBuilderSamples
{
///
/// This class is created as a Singleton and passed into the IBot-derived constructor.
/// - See constructor for how that is injected.
/// - See the Startup.cs file for more details on creating the Singleton that gets
/// injected into the constructor.
///
public class DialogPromptBotAccessors
{
///
/// Initializes a new instance of the class.
/// Contains the and associated .
///
/// The state object that stores the counter.
public DialogPromptBotAccessors(ConversationState conversationState)
{
ConversationState = conversationState
?? throw new ArgumentNullException(nameof(conversationState));
}
public static string DialogStateAccessorKey { get; }
= "DialogPromptBotAccessors.DialogState";
public static string ReservationAccessorKey { get; }
= "DialogPromptBotAccessors.Reservation";
///
/// Gets or sets the for CounterState.
///
///
/// The accessor stores the turn count for the conversation.
///
public IStatePropertyAccessor DialogStateAccessor { get; set; }
public IStatePropertyAccessor ReservationAccessor { get; set; }
///
/// Gets the object for the conversation.
///
/// The object.
public ConversationState ConversationState { get; }
}
}
================================================
FILE: SDKV4-Samples/dotnet_core/DialogPromptBot/Program.cs
================================================
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Logging;
namespace Microsoft.BotBuilderSamples
{
public class Program
{
public static void Main(string[] args)
{
BuildWebHost(args).Run();
}
public static IWebHost BuildWebHost(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.ConfigureLogging((hostingContext, logging) =>
{
// Add Azure Logging
logging.AddAzureWebAppDiagnostics();
// Logging Options.
// There are other logging options available:
// https://docs.microsoft.com/en-us/aspnet/core/fundamentals/logging/?view=aspnetcore-2.1
// logging.AddDebug();
// logging.AddConsole();
})
// Logging Options.
// Consider using Application Insights for your logging and metrics needs.
// https://azure.microsoft.com/en-us/services/application-insights/
// .UseApplicationInsights()
.UseStartup()
.Build();
}
}
================================================
FILE: SDKV4-Samples/dotnet_core/DialogPromptBot/Properties/launchSettings.json
================================================
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:3978/",
"sslPort": 0
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"PromptsBot": {
"commandName": "Project",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "http://localhost:3978/"
}
}
}
================================================
FILE: SDKV4-Samples/dotnet_core/DialogPromptBot/README.md
================================================
# Dialog Prompt Bot
This sample demonstrates how to use dialog prompts in your ASP.Net Core 2 bot to gather and validate user input.
# To try this sample
- Clone the samples repository
```bash
git clone https://github.com/Microsoft/BotFramework-Samples.git
```
- [Optional] Update the `appsettings.json` file under `BotFramework-Samples\dotnet_core\DialogPromptBot` with your botFileSecret. For Azure Bot Service bots, you can find the botFileSecret under application settings.
# Prerequisites
## Visual Studio
- Navigate to the samples folder (`BotFramework-Samples\SDKV4-Samples\dotnet_core\DialogPromptBot`) and open DialogPromptBot.csproj in Visual Studio.
- Hit F5.
## Visual Studio Code
- Open `BotFramework-Samples\SDKV4-Samples\dotnet_core\DialogPromptBot` sample folder.
- Bring up a terminal, navigate to `BotFramework-Samples\SDKV4-Samples\dotnet_core\DialogPromptBot` folder.
- Type 'dotnet run'.
## Testing the bot using Bot Framework Emulator
[Microsoft Bot Framework Emulator](https://github.com/microsoft/botframework-emulator) is a desktop application that allows bot
developers to test and debug their bots on localhost or running remotely through a tunnel.
- Install the Bot Framework emulator from [here](https://aka.ms/botframeworkemulator).
## Connect to bot using Bot Framework Emulator **V4**
- Launch the Bot Framework Emulator.
- File -> Open bot and navigate to `BotFramework-Samples\SDKV4-Samples\dotnet_core\DialogPromptBot` folder.
- Select `dialog-prompt.bot` file.
# Further reading
- [Azure Bot Service Introduction](https://docs.microsoft.com/en-us/azure/bot-service/bot-service-overview-introduction?view=azure-bot-service-4.0)
- [Bot State](https://docs.microsoft.com/en-us/azure/bot-service/bot-builder-storage-concept?view=azure-bot-service-4.0)
- [Managing conversation and user state](https://docs.microsoft.com/en-us/azure/bot-service/bot-builder-howto-v4-state?view=azure-bot-service-4.0&tabs=js)
================================================
FILE: SDKV4-Samples/dotnet_core/DialogPromptBot/Startup.cs
================================================
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Linq;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.Dialogs;
using Microsoft.Bot.Builder.Integration;
using Microsoft.Bot.Builder.Integration.AspNet.Core;
using Microsoft.Bot.Configuration;
using Microsoft.Bot.Connector.Authentication;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
namespace Microsoft.BotBuilderSamples
{
///
/// The Startup class configures services and the request pipeline.
///
public class Startup
{
private ILoggerFactory _loggerFactory;
private readonly bool _isProduction = false;
public Startup(IHostingEnvironment env)
{
_isProduction = env.IsProduction();
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();
}
///
/// Gets the configuration that represents a set of key/value application configuration properties.
///
///
/// The that represents a set of key/value application configuration properties.
///
public IConfiguration Configuration { get; }
///
/// This method gets called by the runtime. Use this method to add services to the container.
///
/// The specifies the contract for a collection of service descriptors.
///
public void ConfigureServices(IServiceCollection services)
{
var secretKey = Configuration.GetSection("botFileSecret")?.Value;
var botFilePath = Configuration.GetSection("botFilePath")?.Value;
// Loads .bot configuration file and adds a singleton that your Bot can access through dependency injection.
var botConfig = BotConfiguration.Load(botFilePath ?? @".\dialog-prompt.bot", secretKey);
services.AddSingleton(sp => botConfig
?? throw new InvalidOperationException($"The .bot config file could not be loaded. ({botConfig})"));
// The Memory Storage used here is for local bot debugging only. When the bot
// is restarted, everything stored in memory will be gone.
IStorage dataStore = new MemoryStorage();
// Create Conversation State object.
// The Conversation State object is where we persist anything at the conversation-scope.
var conversationState = new ConversationState(dataStore);
// Create and register state accesssors.
// Acessors created here are passed into the IBot-derived class on every turn.
services.AddSingleton(sp =>
{
// Create the custom state accessor.
// State accessors enable other components to read and write individual properties of state.
var accessors = new DialogPromptBotAccessors(conversationState)
{
DialogStateAccessor =
conversationState.CreateProperty(
DialogPromptBotAccessors.DialogStateAccessorKey),
ReservationAccessor =
conversationState.CreateProperty(
DialogPromptBotAccessors.ReservationAccessorKey),
};
return accessors;
});
services.AddBot(options =>
{
// Retrieve current endpoint.
var environment = _isProduction ? "production" : "development";
var service = botConfig.Services.Where(s => s.Type == "endpoint" && s.Name == environment).FirstOrDefault();
if (!(service is EndpointService endpointService))
{
throw new InvalidOperationException($"The .bot file does not contain an endpoint with name '{environment}'.");
}
options.CredentialProvider = new SimpleCredentialProvider(endpointService.AppId, endpointService.AppPassword);
// Creates a logger for the application to use.
ILogger logger = _loggerFactory.CreateLogger();
// Catches any errors that occur during a conversation turn and logs them.
options.OnTurnError = async (context, exception) =>
{
logger.LogError($"Exception caught : {exception}");
await context.SendActivityAsync("Sorry, it looks like something went wrong.");
};
});
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
_loggerFactory = loggerFactory;
app.UseDefaultFiles()
.UseStaticFiles()
.UseBotFramework();
}
}
}
================================================
FILE: SDKV4-Samples/dotnet_core/DialogPromptBot/appsettings.json
================================================
{
"botFilePath": "dialog-prompt.bot",
"botFileSecret": ""
}
================================================
FILE: SDKV4-Samples/dotnet_core/DialogPromptBot/dialog-prompt.bot
================================================
{
"name": "PromptsBot",
"services": [
{
"type": "endpoint",
"name": "development",
"endpoint": "http://localhost:3978/api/messages",
"appId": "",
"appPassword": "",
"id": "1"
}
],
"padlock": "",
"version": "2.0"
}
================================================
FILE: SDKV4-Samples/dotnet_core/DialogPromptBot/wwwroot/default.htm
================================================
Dialog Prompt Bot sample
Dialog Prompt Bot
Your bot is ready!
You can test your bot in the Bot Framework Emulator
by opening the .bot file in the project folder.
Visit Azure
Bot Service to register your bot and add it to
various channels. The bot's endpoint URL typically looks
like this:
https://your_bots_hostname/api/messages
================================================
FILE: SDKV4-Samples/dotnet_core/PromptUsersForInput/ConversationFlow.cs
================================================
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Microsoft.BotBuilderSamples
{
public class ConversationFlow
{
// Identifies the last question asked.
public enum Question
{
Name,
Age,
Date,
None, // Our last action did not involve a question.
}
// The last question asked.
public Question LastQuestionAsked { get; set; } = Question.None;
}
}
================================================
FILE: SDKV4-Samples/dotnet_core/PromptUsersForInput/CustomPromptBot.cs
================================================
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Schema;
using Microsoft.Extensions.Logging;
using Microsoft.Recognizers.Text;
using Microsoft.Recognizers.Text.DateTime;
using Microsoft.Recognizers.Text.Number;
namespace Microsoft.BotBuilderSamples
{
///
/// Represents a bot that processes incoming activities.
/// For each user interaction, an instance of this class is created and the OnTurnAsync method is called.
/// This is a Transient lifetime service. Transient lifetime services are created
/// each time they're requested. For each Activity received, a new instance of this
/// class is created. Objects that are expensive to construct, or have a lifetime
/// beyond the single turn, should be carefully managed.
/// For example, the object and associated
/// object are created with a singleton lifetime.
///
///
public class CustomPromptBot : IBot
{
private readonly CustomPromptBotAccessors _accessors;
private readonly ILogger _logger;
///
/// Initializes a new instance of the class.
///
/// A class containing used to manage state.
/// A that is hooked to the Azure App Service provider.
/// Defines a bot for filling a user profile.
///
public CustomPromptBot(CustomPromptBotAccessors accessors, ILoggerFactory loggerFactory)
{
if (loggerFactory == null)
{
throw new System.ArgumentNullException(nameof(loggerFactory));
}
_logger = loggerFactory.CreateLogger();
_logger.LogTrace("EchoBot turn start.");
_accessors = accessors ?? throw new System.ArgumentNullException(nameof(accessors));
}
/// The turn handler for the bot.
/// A containing all the data needed
/// for processing this conversation turn.
/// (Optional) A that can be used by other objects
/// or threads to receive notice of cancellation.
/// A that represents the work queued to execute.
public async Task OnTurnAsync(ITurnContext turnContext, CancellationToken cancellationToken = default(CancellationToken))
{
// Handle Message activity type, which is the main activity type for shown within a conversational interface
// Message activities may contain text, speech, interactive cards, and binary or unknown attachments.
// see https://aka.ms/about-bot-activity-message to learn more about the message and other activity types
if (turnContext.Activity.Type == ActivityTypes.Message)
{
// Get the state properties from the turn context.
ConversationFlow flow = await _accessors.ConversationFlowAccessor.GetAsync(turnContext, () => new ConversationFlow());
UserProfile profile = await _accessors.UserProfileAccessor.GetAsync(turnContext, () => new UserProfile());
await FillOutUserProfileAsync(flow, profile, turnContext);
// Update state and save changes.
await _accessors.ConversationFlowAccessor.SetAsync(turnContext, flow);
await _accessors.ConversationState.SaveChangesAsync(turnContext);
await _accessors.UserProfileAccessor.SetAsync(turnContext, profile);
await _accessors.UserState.SaveChangesAsync(turnContext);
}
}
///
/// Manages the conversation flow for filling out the user's profile, including parsing and validation.
///
/// The conversation flow state property.
/// The user profile state property.
/// The context object for the current turn.
/// A task that represents the work queued to execute.
private static async Task FillOutUserProfileAsync(ConversationFlow flow, UserProfile profile, ITurnContext turnContext)
{
string input = turnContext.Activity.Text?.Trim();
string message;
switch (flow.LastQuestionAsked)
{
case ConversationFlow.Question.None:
await turnContext.SendActivityAsync("Let's get started. What is your name?");
flow.LastQuestionAsked = ConversationFlow.Question.Name;
break;
case ConversationFlow.Question.Name:
if (ValidateName(input, out string name, out message))
{
profile.Name = name;
await turnContext.SendActivityAsync($"Hi {profile.Name}.");
await turnContext.SendActivityAsync("How old are you?");
flow.LastQuestionAsked = ConversationFlow.Question.Age;
break;
}
else
{
await turnContext.SendActivityAsync(message ?? "I'm sorry, I didn't understand that.");
break;
}
case ConversationFlow.Question.Age:
if (ValidateAge(input, out int age, out message))
{
profile.Age = age;
await turnContext.SendActivityAsync($"I have your age as {profile.Age}.");
await turnContext.SendActivityAsync("When is your flight?");
flow.LastQuestionAsked = ConversationFlow.Question.Date;
break;
}
else
{
await turnContext.SendActivityAsync(message ?? "I'm sorry, I didn't understand that.");
break;
}
case ConversationFlow.Question.Date:
if (ValidateDate(input, out string date, out message))
{
profile.Date = date;
await turnContext.SendActivityAsync($"Your cab ride to the airport is scheduled for {profile.Date}.");
await turnContext.SendActivityAsync($"Thanks for completing the booking {profile.Name}.");
await turnContext.SendActivityAsync($"Type anything to run the bot again.");
flow.LastQuestionAsked = ConversationFlow.Question.None;
profile = new UserProfile();
break;
}
else
{
await turnContext.SendActivityAsync(message ?? "I'm sorry, I didn't understand that.");
break;
}
}
}
///
/// Validates name input.
///
/// The user's input.
/// When the method returns, contains the normalized name, if validation succeeded.
/// When the method returns, contains a message with which to reprompt, if validation failed.
/// indicates whether validation succeeded.
private static bool ValidateName(string input, out string name, out string message)
{
name = null;
message = null;
if (string.IsNullOrWhiteSpace(input))
{
message = "Please enter a name that contains at least one character.";
}
else
{
name = input.Trim();
}
return message is null;
}
///
/// Validates age input.
///
/// The user's input.
/// When the method returns, contains the normalized age, if validation succeeded.
/// When the method returns, contains a message with which to reprompt, if validation failed.
/// indicates whether validation succeeded.
private static bool ValidateAge(string input, out int age, out string message)
{
age = 0;
message = null;
// Try to recognize the input as a number. This works for responses such as "twelve" as well as "12".
try
{
// Attempt to convert the Recognizer result to an integer. This works for "a dozen", "twelve", "12", and so on.
// The recognizer returns a list of potential recognition results, if any.
List results = NumberRecognizer.RecognizeNumber(input, Culture.English);
foreach (ModelResult result in results)
{
// The result resolution is a dictionary, where the "value" entry contains the processed string.
if (result.Resolution.TryGetValue("value", out object value))
{
age = Convert.ToInt32(value);
if (age >= 18 && age <= 120)
{
return true;
}
}
}
message = "Please enter an age between 18 and 120.";
}
catch
{
message = "I'm sorry, I could not interpret that as an age. Please enter an age between 18 and 120.";
}
return message is null;
}
///
/// Validates flight time input.
///
/// The user's input.
/// When the method returns, contains the normalized date, if validation succeeded.
/// When the method returns, contains a message with which to reprompt, if validation failed.
/// indicates whether validation succeeded.
private static bool ValidateDate(string input, out string date, out string message)
{
date = null;
message = null;
// Try to recognize the input as a date-time. This works for responses such as "11/14/2018", "9pm", "tomorrow", "Sunday at 5pm", and so on.
// The recognizer returns a list of potential recognition results, if any.
try
{
List results = DateTimeRecognizer.RecognizeDateTime(input, Culture.English);
// Check whether any of the recognized date-times are appropriate,
// and if so, return the first appropriate date-time. We're checking for a value at least an hour in the future.
DateTime earliest = DateTime.Now.AddHours(1.0);
foreach (ModelResult result in results)
{
// The result resolution is a dictionary, where the "values" entry contains the processed input.
List> resolutions = result.Resolution["values"] as List>;
foreach (Dictionary resolution in resolutions)
{
// The processed input contains a "value" entry if it is a date-time value, or "start" and
// "end" entries if it is a date-time range.
if (resolution.TryGetValue("value", out string dateString)
|| resolution.TryGetValue("start", out dateString))
{
if (DateTime.TryParse(dateString, out DateTime candidate)
&& earliest < candidate)
{
date = candidate.ToShortDateString();
return true;
}
}
}
}
message = "I'm sorry, please enter a date at least an hour out.";
}
catch
{
message = "I'm sorry, I could not interpret that as an appropriate date. Please enter a date at least an hour out.";
}
return false;
}
}
}
================================================
FILE: SDKV4-Samples/dotnet_core/PromptUsersForInput/CustomPromptBot.ruleset
================================================
================================================
FILE: SDKV4-Samples/dotnet_core/PromptUsersForInput/CustomPromptBotAccessors.cs
================================================
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using Microsoft.Bot.Builder;
namespace Microsoft.BotBuilderSamples
{
///
/// This class is created as a Singleton and passed into the IBot-derived constructor.
/// - See constructor for how that is injected.
/// - See the Startup.cs file for more details on creating the Singleton that gets
/// injected into the constructor.
///
public class CustomPromptBotAccessors
{
///
/// Initializes a new instance of the class.
/// Contains the state management and associated accessor objects.
///
/// The state object that stores the conversation state.
/// The state object that stores the user state.
public CustomPromptBotAccessors(ConversationState conversationState, UserState userState)
{
ConversationState = conversationState ?? throw new ArgumentNullException(nameof(conversationState));
UserState = userState ?? throw new ArgumentNullException(nameof(userState));
}
///
/// Gets the accessor name for the conversation flow property.
///
/// The accessor name for the conversation flow property.
/// Accessors require a unique name.
public static string ConversationFlowName { get; } = "ConversationFlow";
///
/// Gets the accessor name for the user profile property accessor.
///
/// The accessor name for the user profile property accessor.
/// Accessors require a unique name.
public static string UserProfileName { get; } = "UserProfile";
///
/// Gets or sets the for the conversation flow property.
///
///
/// The accessor stores the turn count for the conversation.
///
public IStatePropertyAccessor ConversationFlowAccessor { get; set; }
///
/// Gets or sets the for the user profile property.
///
///
/// The accessor stores the turn count for the conversation.
///
public IStatePropertyAccessor UserProfileAccessor { get; set; }
///
/// Gets the object for the conversation.
///
/// The object.
public ConversationState ConversationState { get; }
///
/// Gets the object for the conversation.
///
/// The object.
public UserState UserState { get; }
}
}
================================================
FILE: SDKV4-Samples/dotnet_core/PromptUsersForInput/DeploymentScripts/MsbotClone/bot.recipe
================================================
{
"version": "1.0",
"resources": [
{
"type": "endpoint",
"id": "1",
"name": "development",
"url": "http://localhost:3978/api/messages"
},
{
"type": "endpoint",
"id": "2",
"name": "production",
"url": "https://your-bot-url.azurewebsites.net/api/messages"
},
{
"type": "abs",
"id": "3",
"name": "CustomPromptBot-abs"
},
{
"type": "appInsights",
"id": "4",
"name": "CustomPromptBot-insights"
},
{
"type": "blob",
"id": "5",
"name": "CustomPromptBot-blob",
"container": "botstatestore"
}
]
}
================================================
FILE: SDKV4-Samples/dotnet_core/PromptUsersForInput/Program.cs
================================================
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Logging;
namespace Microsoft.BotBuilderSamples
{
public class Program
{
public static void Main(string[] args)
{
BuildWebHost(args).Run();
}
public static IWebHost BuildWebHost(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.ConfigureLogging((hostingContext, logging) =>
{
// Add Azure Logging
logging.AddAzureWebAppDiagnostics();
// Logging Options.
// There are other logging options available:
// https://docs.microsoft.com/en-us/aspnet/core/fundamentals/logging/?view=aspnetcore-2.1
// logging.AddDebug();
// logging.AddConsole();
})
// Logging Options.
// Consider using Application Insights for your logging and metrics needs.
// https://azure.microsoft.com/en-us/services/application-insights/
// .UseApplicationInsights()
.UseStartup()
.Build();
}
}
================================================
FILE: SDKV4-Samples/dotnet_core/PromptUsersForInput/PromptUsersForInput.csproj
================================================
netcoreapp2.0CustomPromptBot.rulesetAlways
================================================
FILE: SDKV4-Samples/dotnet_core/PromptUsersForInput/Properties/launchSettings.json
================================================
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:3978/",
"sslPort": 0
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"Bot_Builder_Echo_Bot_V43": {
"commandName": "Project",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "http://localhost:3978/"
}
}
}
================================================
FILE: SDKV4-Samples/dotnet_core/PromptUsersForInput/README.md
================================================
# Prompt users for input
This sample demonstrates how to create your own prompts with an ASP.Net Core 2 bot.
The bot maintains conversation state to track and direct the conversation and ask the user questions.
The bot maintains user state to track the user's answers.
# To try this sample
- Clone the samples repository
```bash
git clone https://github.com/Microsoft/BotFramework-Samples.git
```
- [Optional] Update the `appsettings.json` file under `BotFramework-Samples\SDKV4-Samples\dotnet_core\PromptUsersForInput\` with your botFileSecret.
# Prerequisites
## Visual Studio
- Navigate to the v4 C# samples folder (`BotFramework-Samples\SDKV4-Samples\dotnet_core\PromptUsersForInput`) and open the PromptUsersForInput.csproj in Visual Studio.
- Hit F5.
## Visual Studio Code
- Open the `BotFramework-Samples\SDKV4-Samples\dotnet_core\PromptUsersForInput` folder.
- Bring up a terminal, navigate to `BotFramework-Samples\SDKV4-Samples\dotnet_core\PromptUsersForInput` folder.
- Type 'dotnet run'.
## Testing the bot using Bot Framework Emulator
[Microsoft Bot Framework Emulator](https://github.com/microsoft/botframework-emulator) is a desktop application that allows bot developers to test and debug their bots on localhost or running remotely through a tunnel.
- Install the Bot Framework emulator from [here](https://aka.ms/botframeworkemulator).
## Connect to bot using Bot Framework Emulator **V4**
- Launch the Bot Framework Emulator.
- Select the **File** > **Open bot configuration** menu item and navigate to the `BotFramework-Samples\SDKV4-Samples\dotnet_core\PromptUsersForInput` folder.
- Select the `custom-prompt.bot` file.
# Bot state
A bot is inherently stateless. Once your bot is deployed, it may not run in the same process or on the same machine from one turn to the next.
However, your bot may need to track the context of a conversation, so that it can manage its behavior and remember answers to previous questions.
In this example, the bot's state is used to a track number of messages.
- We use the bot's turn handler and user and conversation state properties to manage the flow of the conversation and the collection of input.
- We ask the user a series of questions; parse, validate, and normalize their answers; and then save their input.
This sample is intended to be run and tested locally and is not designed to be deployed to Azure.
# Further reading
- [Azure Bot Service Introduction](https://docs.microsoft.com/azure/bot-service/bot-service-overview-introduction)
================================================
FILE: SDKV4-Samples/dotnet_core/PromptUsersForInput/Startup.cs
================================================
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Linq;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.Integration;
using Microsoft.Bot.Builder.Integration.AspNet.Core;
using Microsoft.Bot.Configuration;
using Microsoft.Bot.Connector.Authentication;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
namespace Microsoft.BotBuilderSamples
{
///
/// The Startup class configures services and the request pipeline.
///
public class Startup
{
private ILoggerFactory _loggerFactory;
private readonly bool _isProduction = false;
public Startup(IHostingEnvironment env)
{
_isProduction = env.IsProduction();
IConfigurationBuilder builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
.AddEnvironmentVariables();
Configuration = builder.Build();
}
///
/// Gets the configuration that represents a set of key/value application configuration properties.
///
///
/// The that represents a set of key/value application configuration properties.
///
public IConfiguration Configuration { get; }
///
/// This method gets called by the runtime. Use this method to add services to the container.
///
/// The specifies the contract for a collection of service descriptors.
///
///
///
public void ConfigureServices(IServiceCollection services)
{
services.AddBot(options =>
{
string secretKey = Configuration.GetSection("botFileSecret")?.Value;
string botFilePath = Configuration.GetSection("botFilePath")?.Value;
// Loads .bot configuration file and adds a singleton that your Bot can access through dependency injection.
BotConfiguration botConfig = BotConfiguration.Load(botFilePath ?? @".\custom-prompt.bot", secretKey);
services.AddSingleton(sp => botConfig
?? throw new InvalidOperationException($"The .bot config file could not be loaded. ({botConfig})"));
// Retrieve current endpoint.
string environment = _isProduction ? "production" : "development";
ConnectedService service = botConfig.Services.Where(s => s.Type == "endpoint" && s.Name == environment).FirstOrDefault();
if (!(service is EndpointService endpointService))
{
throw new InvalidOperationException($"The .bot file does not contain an endpoint with name '{environment}'.");
}
options.CredentialProvider = new SimpleCredentialProvider(endpointService.AppId, endpointService.AppPassword);
// Creates a logger for the application to use.
ILogger logger = _loggerFactory.CreateLogger();
// Catches any errors that occur during a conversation turn and logs them.
options.OnTurnError = async (context, exception) =>
{
logger.LogError($"Exception caught : {exception}");
await context.SendActivityAsync("Sorry, it looks like something went wrong.");
};
});
// Create conversation and user state with in-memory storage provider.
IStorage storage = new MemoryStorage();
ConversationState conversationState = new ConversationState(storage);
UserState userState = new UserState(storage);
// Create and register state accessors.
// Accessors created here are passed into the IBot-derived class on every turn.
services.AddSingleton(sp =>
{
// Create the custom state accessor.
return new CustomPromptBotAccessors(conversationState, userState)
{
ConversationFlowAccessor = conversationState.CreateProperty(CustomPromptBotAccessors.ConversationFlowName),
UserProfileAccessor = userState.CreateProperty(CustomPromptBotAccessors.UserProfileName),
};
});
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
_loggerFactory = loggerFactory;
app.UseDefaultFiles()
.UseStaticFiles()
.UseBotFramework();
}
}
}
================================================
FILE: SDKV4-Samples/dotnet_core/PromptUsersForInput/UserProfile.cs
================================================
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Microsoft.BotBuilderSamples
{
public class UserProfile
{
public string Name { get; set; }
public int? Age { get; set; }
public string Date { get; set; }
}
}
================================================
FILE: SDKV4-Samples/dotnet_core/PromptUsersForInput/appsettings.json
================================================
{
"botFilePath": "custom-prompt.bot",
"botFileSecret": ""
}
================================================
FILE: SDKV4-Samples/dotnet_core/PromptUsersForInput/custom-prompt.bot
================================================
{
"name": "CustomPromptBot",
"services": [
{
"type": "endpoint",
"name": "development",
"endpoint": "http://localhost:3978/api/messages",
"appId": "",
"appPassword": "",
"id": "1"
}
],
"padlock": "",
"version": "2.0"
}
================================================
FILE: SDKV4-Samples/dotnet_core/PromptUsersForInput/wwwroot/default.htm
================================================
Custom Prompt Bot sample
Custom Prompt Bot
Your bot is ready!
You can test your bot in the Bot Framework Emulator
by opening the .bot file in the project folder.
Visit Azure
Bot Service to register your bot and add it to
various channels. The bot's endpoint URL typically looks
like this:
https://your_bots_hostname/api/messages
================================================
FILE: SDKV4-Samples/dotnet_core/StateBot/ConversationData.cs
================================================
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Microsoft.BotBuilderSamples
{
// Defines a state property used to track conversation data.
public class ConversationData
{
// The time-stamp of the most recent incoming message.
public string Timestamp { get; set; }
// The ID of the user's channel.
public string ChannelId { get; set; }
// Track whether we have already asked the user's name
public bool PromptedUserForName { get; set; } = false;
}
}
================================================
FILE: SDKV4-Samples/dotnet_core/StateBot/DeploymentScripts/MsbotClone/bot.recipe
================================================
{
"version": "1.0",
"resources": [
{
"type": "endpoint",
"id": "1",
"name": "development",
"url": "http://localhost:3978/api/messages"
},
{
"type": "endpoint",
"id": "2",
"name": "production",
"url": "https://your-bot-url.azurewebsites.net/api/messages"
},
{
"type": "abs",
"id": "3",
"name": "StateBot-abs"
},
{
"type": "appInsights",
"id": "4",
"name": "StateBot-insights"
},
{
"type": "blob",
"id": "5",
"name": "StateBot-blob",
"container": "botstatestore"
}
]
}
================================================
FILE: SDKV4-Samples/dotnet_core/StateBot/Program.cs
================================================
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Logging;
namespace Microsoft.BotBuilderSamples
{
public class Program
{
public static void Main(string[] args)
{
BuildWebHost(args).Run();
}
public static IWebHost BuildWebHost(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.ConfigureLogging((hostingContext, logging) =>
{
// Add Azure Logging
logging.AddAzureWebAppDiagnostics();
// Logging Options.
// There are other logging options available:
// https://docs.microsoft.com/en-us/aspnet/core/fundamentals/logging/?view=aspnetcore-2.1
// logging.AddDebug();
// logging.AddConsole();
})
// Logging Options.
// Consider using Application Insights for your logging and metrics needs.
// https://azure.microsoft.com/en-us/services/application-insights/
// .UseApplicationInsights()
.UseStartup()
.Build();
}
}
================================================
FILE: SDKV4-Samples/dotnet_core/StateBot/Properties/launchSettings.json
================================================
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:3978/",
"sslPort": 0
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"StateBot": {
"commandName": "Project",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "http://localhost:3978/"
}
}
}
================================================
FILE: SDKV4-Samples/dotnet_core/StateBot/README.md
================================================
# Save user and conversation data
This sample demonstrates how to save user and conversation data in an ASP.Net Core 2 bot.
The bot maintains conversation state to track and direct the conversation and ask the user questions.
The bot maintains user state to track the user's answers.
# To try this sample
- Clone the samples repository
```bash
git clone https://github.com/Microsoft/BotFramework-Samples.git
```
- [Optional] Update the `appsettings.json` file under `BotFramework-Samples\SDKV4-Samples\dotnet_core\BotState\` with your botFileSecret.
# Prerequisites
## Visual Studio
- Navigate to the v4 C# samples folder (`BotFramework-Samples\SDKV4-Samples\dotnet_core\BotState`) and open the PromptUsersForInput.csproj in Visual Studio.
- Hit F5.
## Visual Studio Code
- Open the `BotFramework-Samples\SDKV4-Samples\dotnet_core\BotState` folder.
- Bring up a terminal, navigate to `BotFramework-Samples\SDKV4-Samples\dotnet_core\BotState` folder.
- Type 'dotnet run'.
## Testing the bot using Bot Framework Emulator
[Microsoft Bot Framework Emulator](https://github.com/microsoft/botframework-emulator) is a desktop application that allows bot developers to test and debug their bots on localhost or running remotely through a tunnel.
- Install the Bot Framework emulator from [here](https://aka.ms/botframeworkemulator).
## Connect to bot using Bot Framework Emulator **V4**
- Launch the Bot Framework Emulator.
- Select the **File** > **Open bot configuration** menu item and navigate to the `BotFramework-Samples\SDKV4-Samples\dotnet_core\BotState` folder.
- Select the `state.bot` file.
================================================
FILE: SDKV4-Samples/dotnet_core/StateBot/Startup.cs
================================================
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Linq;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.Integration;
using Microsoft.Bot.Builder.Integration.AspNet.Core;
using Microsoft.Bot.Configuration;
using Microsoft.Bot.Connector.Authentication;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
namespace Microsoft.BotBuilderSamples
{
///
/// The Startup class configures services and the request pipeline.
///
public class Startup
{
private readonly bool _isProduction = false;
private ILoggerFactory _loggerFactory;
public Startup(IHostingEnvironment env)
{
_isProduction = env.IsProduction();
IConfigurationBuilder builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
.AddEnvironmentVariables();
Configuration = builder.Build();
}
///
/// Gets the configuration that represents a set of key/value application configuration properties.
///
///
/// The that represents a set of key/value application configuration properties.
///
public IConfiguration Configuration { get; }
///
/// This method gets called by the runtime. Use this method to add services to the container.
///
/// The specifies the contract for a collection of service descriptors.
///
///
///
public void ConfigureServices(IServiceCollection services)
{
services.AddBot(options =>
{
string secretKey = Configuration.GetSection("botFileSecret")?.Value;
string botFilePath = Configuration.GetSection("botFilePath")?.Value;
// Loads .bot configuration file and adds a singleton that your Bot can access through dependency injection.
BotConfiguration botConfig = BotConfiguration.Load(botFilePath ?? @".\State.bot", secretKey);
services.AddSingleton(sp => botConfig
?? throw new InvalidOperationException($"The .bot config file could not be loaded. ({botConfig})"));
// Retrieve current endpoint.
string environment = _isProduction ? "production" : "development";
ConnectedService service = botConfig.Services.Where(s => s.Type == "endpoint" && s.Name == environment).FirstOrDefault();
if (!(service is EndpointService endpointService))
{
throw new InvalidOperationException($"The .bot file does not contain an endpoint with name '{environment}'.");
}
options.CredentialProvider = new SimpleCredentialProvider(endpointService.AppId, endpointService.AppPassword);
// Creates a logger for the application to use.
ILogger logger = _loggerFactory.CreateLogger();
// Catches any errors that occur during a conversation turn and logs them.
options.OnTurnError = async (context, exception) =>
{
logger.LogError($"Exception caught : {exception}");
await context.SendActivityAsync("Sorry, it looks like something went wrong.");
};
});
// Create conversation and user state with in-memory storage provider.
IStorage storage = new MemoryStorage();
ConversationState conversationState = new ConversationState(storage);
UserState userState = new UserState(storage);
// Create and register state accessors.
// Accessors created here are passed into the IBot-derived class on every turn.
services.AddSingleton(sp =>
{
// Create the custom state accessor.
return new StateBotAccessors(conversationState, userState)
{
ConversationDataAccessor = conversationState.CreateProperty(StateBotAccessors.ConversationDataName),
UserProfileAccessor = userState.CreateProperty(StateBotAccessors.UserProfileName),
};
});
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
_loggerFactory = loggerFactory;
app.UseDefaultFiles()
.UseStaticFiles()
.UseBotFramework();
}
}
}
================================================
FILE: SDKV4-Samples/dotnet_core/StateBot/StateBot.cs
================================================
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Schema;
using Microsoft.Extensions.Logging;
namespace Microsoft.BotBuilderSamples
{
///
/// Represents a bot that processes incoming activities.
/// For each user interaction, an instance of this class is created and the OnTurnAsync method is called.
/// This is a Transient lifetime service. Transient lifetime services are created
/// each time they're requested. For each Activity received, a new instance of this
/// class is created. Objects that are expensive to construct, or have a lifetime
/// beyond the single turn, should be carefully managed.
/// For example, the object and associated
/// object are created with a singleton lifetime.
///
public class StateBot : IBot
{
private readonly StateBotAccessors _accessors;
private readonly ILogger _logger;
///
/// Initializes a new instance of the class.
///
/// A class containing used to manage state.
/// A that is hooked to the Azure App Service provider.
/// Defines a bot for filling a user profile.
public StateBot(StateBotAccessors accessors, ILoggerFactory loggerFactory)
{
if (loggerFactory == null)
{
throw new System.ArgumentNullException(nameof(loggerFactory));
}
_logger = loggerFactory.CreateLogger();
_logger.LogTrace("EchoBot turn start.");
_accessors = accessors ?? throw new System.ArgumentNullException(nameof(accessors));
}
/// The turn handler for the bot.
/// A containing all the data needed
/// for processing this conversation turn.
/// (Optional) A that can be used by other objects
/// or threads to receive notice of cancellation.
/// A that represents the work queued to execute.
public async Task OnTurnAsync(ITurnContext turnContext, CancellationToken cancellationToken = default(CancellationToken))
{
if (turnContext.Activity.Type == ActivityTypes.Message)
{
// Get the state properties from the turn context.
UserProfile userProfile =
await _accessors.UserProfileAccessor.GetAsync(turnContext, () => new UserProfile());
ConversationData conversationData =
await _accessors.ConversationDataAccessor.GetAsync(turnContext, () => new ConversationData());
if (string.IsNullOrEmpty(userProfile.Name))
{
// First time around this is set to false, so we will prompt user for name.
if (conversationData.PromptedUserForName)
{
// Set the name to what the user provided.
userProfile.Name = turnContext.Activity.Text?.Trim();
// Acknowledge that we got their name.
await turnContext.SendActivityAsync($"Thanks {userProfile.Name}.");
// Reset the flag to allow the bot to go though the cycle again.
conversationData.PromptedUserForName = false;
}
else
{
// Prompt the user for their name.
await turnContext.SendActivityAsync($"What is your name?");
// Set the flag to true, so we don't prompt in the next turn.
conversationData.PromptedUserForName = true;
}
// Save user state and save changes.
await _accessors.UserProfileAccessor.SetAsync(turnContext, userProfile);
await _accessors.UserState.SaveChangesAsync(turnContext);
}
else
{
// Add message details to the conversation data.
conversationData.Timestamp = turnContext.Activity.Timestamp.ToString();
conversationData.ChannelId = turnContext.Activity.ChannelId.ToString();
// Display state data.
await turnContext.SendActivityAsync($"{userProfile.Name} sent: {turnContext.Activity.Text}");
await turnContext.SendActivityAsync($"Message received at: {conversationData.Timestamp}");
await turnContext.SendActivityAsync($"Message received from: {conversationData.ChannelId}");
}
// Update conversation state and save changes.
await _accessors.ConversationDataAccessor.SetAsync(turnContext, conversationData);
await _accessors.ConversationState.SaveChangesAsync(turnContext);
}
}
}
}
================================================
FILE: SDKV4-Samples/dotnet_core/StateBot/StateBot.csproj
================================================
netcoreapp2.0StateBot.ruleset$(OutputPath)$(AssemblyName).xml$(NoWarn),1573,1591,1712Always
================================================
FILE: SDKV4-Samples/dotnet_core/StateBot/StateBot.ruleset
================================================
================================================
FILE: SDKV4-Samples/dotnet_core/StateBot/StateBot.sln
================================================
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.27428.2043
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StateBot", "StateBot.csproj", "{70EECF7F-1978-4587-9E6D-6371EC3A727B}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{70EECF7F-1978-4587-9E6D-6371EC3A727B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{70EECF7F-1978-4587-9E6D-6371EC3A727B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{70EECF7F-1978-4587-9E6D-6371EC3A727B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{70EECF7F-1978-4587-9E6D-6371EC3A727B}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {D6A9E094-666B-42FD-A3C9-2929F55D978E}
EndGlobalSection
EndGlobal
================================================
FILE: SDKV4-Samples/dotnet_core/StateBot/StateBot.xml
================================================
StateBot
The Startup class configures services and the request pipeline.
Gets the configuration that represents a set of key/value application configuration properties.
The that represents a set of key/value application configuration properties.
This method gets called by the runtime. Use this method to add services to the container.
The specifies the contract for a collection of service descriptors.
Represents a bot that processes incoming activities.
For each user interaction, an instance of this class is created and the OnTurnAsync method is called.
This is a Transient lifetime service. Transient lifetime services are created
each time they're requested. For each Activity received, a new instance of this
class is created. Objects that are expensive to construct, or have a lifetime
beyond the single turn, should be carefully managed.
For example, the object and associated
object are created with a singleton lifetime.
Initializes a new instance of the class.
A class containing used to manage state.
A that is hooked to the Azure App Service provider.
Defines a bot for filling a user profile.The turn handler for the bot.
A containing all the data needed
for processing this conversation turn.
(Optional) A that can be used by other objects
or threads to receive notice of cancellation.
A that represents the work queued to execute.
This class is created as a Singleton and passed into the IBot-derived constructor.
- See constructor for how that is injected.
- See the Startup.cs file for more details on creating the Singleton that gets
injected into the constructor.
Initializes a new instance of the class.
Contains the state management and associated accessor objects.
The state object that stores the conversation state.
The state object that stores the user state.
Gets the accessor name for the user profile property accessor.
The accessor name for the user profile property accessor.Accessors require a unique name.
Gets or sets the for the user profile property.
The accessor stores the turn count for the conversation.
Gets the object for the conversation.
The object.
Gets the object for the conversation.
The object.
================================================
FILE: SDKV4-Samples/dotnet_core/StateBot/StateBotAccessors.cs
================================================
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using Microsoft.Bot.Builder;
namespace Microsoft.BotBuilderSamples
{
///
/// This class is created as a Singleton and passed into the IBot-derived constructor.
/// - See constructor for how that is injected.
/// - See the Startup.cs file for more details on creating the Singleton that gets
/// injected into the constructor.
///
public class StateBotAccessors
{
///
/// Initializes a new instance of the class.
/// Contains the state management and associated accessor objects.
///
/// The state object that stores the conversation state.
/// The state object that stores the user state.
public StateBotAccessors(ConversationState conversationState, UserState userState)
{
ConversationState = conversationState ?? throw new ArgumentNullException(nameof(conversationState));
UserState = userState ?? throw new ArgumentNullException(nameof(userState));
}
///
/// Gets the accessor name for the user profile property accessor.
///
/// The accessor name for the user profile property accessor.
/// Accessors require a unique name.
public static string UserProfileName { get; } = "UserProfile";
///
/// Gets the accessor name for the conversation data property accessor.
///
/// The accessor name for the conversation data property accessor.
/// Accessors require a unique name.
public static string ConversationDataName { get; } = "ConversationData";
///
/// Gets or sets the for the user profile property.
///
///
/// The accessor for the user profile property.
///
public IStatePropertyAccessor UserProfileAccessor { get; set; }
///
/// Gets or sets the for the conversation data property.
///
///
/// The accessor for the conversation data property.
///
public IStatePropertyAccessor ConversationDataAccessor { get; set; }
///
/// Gets the object for the conversation.
///
/// The object.
public ConversationState ConversationState { get; }
///
/// Gets the object for the bot.
///
/// The object.
public UserState UserState { get; }
}
}
================================================
FILE: SDKV4-Samples/dotnet_core/StateBot/UserProfile.cs
================================================
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Microsoft.BotBuilderSamples
{
// Defines a state property used to track information about the user.
public class UserProfile
{
public string Name { get; set; }
}
}
================================================
FILE: SDKV4-Samples/dotnet_core/StateBot/appsettings.json
================================================
{
"botFilePath": "state.bot",
"botFileSecret": ""
}
================================================
FILE: SDKV4-Samples/dotnet_core/StateBot/state.bot
================================================
{
"name": "StateBot",
"services": [
{
"type": "endpoint",
"name": "development",
"endpoint": "http://localhost:3978/api/messages",
"appId": "",
"appPassword": "",
"id": "1"
}
],
"padlock": "",
"version": "2.0"
}
================================================
FILE: SDKV4-Samples/dotnet_core/StateBot/wwwroot/default.htm
================================================
State Bot sample
State Bot
Your bot is ready!
You can test your bot in the Bot Framework Emulator
by opening the .bot file in the project folder.
Visit Azure
Bot Service to register your bot and add it to
various channels. The bot's endpoint URL typically looks
like this:
https://your_bots_hostname/api/messages
================================================
FILE: SDKV4-Samples/dotnet_core/nlp-with-dispatch/QnAMaker.tsv
================================================
Question Answer Source Metadata
hi Hello! QnAMaker.tsv
greetings Hello! QnAMaker.tsv
good morning Hello! QnAMaker.tsv
good evening Hello! QnAMaker.tsv
What are you? I am the LUIS-QnAMaker Dispatch bot! This sample demonstrates using several LUIS applications and QnA Maker knowledge base using dispatch. QnAMaker.tsv
What? I am the LUIS-QnAMaker Dispatch bot! This sample demonstrates using several LUIS applications and QnA Maker knowledge base using dispatch. QnAMaker.tsv
What do you do? I am the LUIS-QnAMaker Dispatch bot! This sample demonstrates using several LUIS applications and QnA Maker knowledge base using dispatch. QnAMaker.tsv
Who are you? I am the LUIS-QnAMaker Dispatch bot! This sample demonstrates using several LUIS applications and QnA Maker knowledge base using dispatch. QnAMaker.tsv
What is your name? I am the LUIS-QnAMaker Dispatch bot! This sample demonstrates using several LUIS applications and QnA Maker knowledge base using dispatch. QnAMaker.tsv
What should I call you? I am the LUIS-QnAMaker Dispatch bot! This sample demonstrates using several LUIS applications and QnA Maker knowledge base using dispatch. QnAMaker.tsv
================================================
FILE: SDKV4-Samples/dotnet_core/nlp-with-dispatch/home-automation.json
================================================
{
"name": "Home Automation",
"versionId": "0.1",
"desc": "Home Automation LUIS application - Bot Builder Samples",
"culture": "en-us",
"intents": [
{
"name": "HomeAutomation"
},
{
"name": "None"
}
],
"entities": [
{
"name": "Device",
"roles": []
},
{
"name": "deviceProperty",
"roles": []
},
{
"name": "Room",
"roles": []
}
],
"closedLists": [
{
"name": "Operation",
"subLists": [
{
"canonicalForm": "off",
"list": [
"off",
"turn off",
"switch off",
"lock",
"out",
"shut down",
"stop"
]
},
{
"canonicalForm": "on",
"list": [
"on",
"turn on",
"switch on",
"unlock",
"un lock",
"boot up",
"start"
]
}
],
"roles": []
}
],
"composites": [],
"patternAnyEntities": [
{
"name": "Device_PatternAny",
"explicitList": [],
"roles": []
},
{
"name": "Room_PatternAny",
"explicitList": [],
"roles": []
}
],
"regex_entities": [],
"prebuiltEntities": [
{
"name": "number",
"roles": []
}
],
"regex_features": [],
"model_features": [],
"patterns": [
{
"pattern": "turn off {Device_PatternAny} in {Room_PatternAny}",
"intent": "HomeAutomation"
},
{
"pattern": "{Device_PatternAny} off [please]",
"intent": "HomeAutomation"
},
{
"pattern": "turn on {Device_PatternAny}",
"intent": "HomeAutomation"
},
{
"pattern": "{Device_PatternAny} on [please]",
"intent": "HomeAutomation"
},
{
"pattern": "turn on {Device_PatternAny} in {Room_PatternAny}",
"intent": "HomeAutomation"
},
{
"pattern": "{Device_PatternAny} in {Room_PatternAny} on [please]",
"intent": "HomeAutomation"
},
{
"pattern": "{Device_PatternAny} in {Room_PatternAny} off [please]",
"intent": "HomeAutomation"
}
],
"utterances": [
{
"text": "breezeway on please",
"intent": "HomeAutomation",
"entities": [
{
"startPos": 0,
"endPos": 8,
"entity": "Room"
}
]
},
{
"text": "change temperature to seventy two degrees",
"intent": "HomeAutomation",
"entities": [
{
"startPos": 7,
"endPos": 17,
"entity": "deviceProperty"
}
]
},
{
"text": "coffee bar on please",
"intent": "HomeAutomation",
"entities": [
{
"startPos": 0,
"endPos": 9,
"entity": "Device"
}
]
},
{
"text": "decrease temperature for me please",
"intent": "None",
"entities": [
{
"startPos": 9,
"endPos": 19,
"entity": "deviceProperty"
}
]
},
{
"text": "dim kitchen lights to 25 .",
"intent": "None",
"entities": [
{
"startPos": 4,
"endPos": 10,
"entity": "Room"
},
{
"startPos": 12,
"endPos": 17,
"entity": "Device"
}
]
},
{
"text": "fish pond off please",
"intent": "HomeAutomation",
"entities": [
{
"startPos": 0,
"endPos": 8,
"entity": "Device"
}
]
},
{
"text": "fish pond on please",
"intent": "HomeAutomation",
"entities": [
{
"startPos": 0,
"endPos": 8,
"entity": "Device"
}
]
},
{
"text": "illuminate please",
"intent": "HomeAutomation",
"entities": [
{
"startPos": 0,
"endPos": 9,
"entity": "Device"
}
]
},
{
"text": "living room lamp on please",
"intent": "HomeAutomation",
"entities": [
{
"startPos": 0,
"endPos": 10,
"entity": "Room"
},
{
"startPos": 12,
"endPos": 15,
"entity": "Device"
}
]
},
{
"text": "living room lamps off please",
"intent": "HomeAutomation",
"entities": [
{
"startPos": 0,
"endPos": 10,
"entity": "Room"
},
{
"startPos": 12,
"endPos": 16,
"entity": "Device"
}
]
},
{
"text": "lock the doors for me please",
"intent": "HomeAutomation",
"entities": [
{
"startPos": 9,
"endPos": 13,
"entity": "Device"
}
]
},
{
"text": "lower your volume",
"intent": "None",
"entities": [
{
"startPos": 11,
"endPos": 16,
"entity": "deviceProperty"
}
]
},
{
"text": "make camera 1 off please",
"intent": "HomeAutomation",
"entities": [
{
"startPos": 5,
"endPos": 12,
"entity": "Device"
}
]
},
{
"text": "make some coffee",
"intent": "HomeAutomation",
"entities": [
{
"startPos": 10,
"endPos": 15,
"entity": "Device"
}
]
},
{
"text": "play dvd",
"intent": "HomeAutomation",
"entities": [
{
"startPos": 5,
"endPos": 7,
"entity": "Device"
}
]
},
{
"text": "set lights out in bedroom",
"intent": "HomeAutomation",
"entities": [
{
"startPos": 4,
"endPos": 9,
"entity": "Device"
},
{
"startPos": 18,
"endPos": 24,
"entity": "Room"
}
]
},
{
"text": "set lights to bright",
"intent": "HomeAutomation",
"entities": [
{
"startPos": 4,
"endPos": 9,
"entity": "Device"
},
{
"startPos": 14,
"endPos": 19,
"entity": "deviceProperty"
}
]
},
{
"text": "set lights to concentrate",
"intent": "HomeAutomation",
"entities": [
{
"startPos": 4,
"endPos": 9,
"entity": "Device"
},
{
"startPos": 14,
"endPos": 24,
"entity": "deviceProperty"
}
]
},
{
"text": "shut down my work computer",
"intent": "HomeAutomation",
"entities": [
{
"startPos": 18,
"endPos": 25,
"entity": "Device"
}
]
},
{
"text": "snap switch fan fifty percent",
"intent": "HomeAutomation",
"entities": [
{
"startPos": 12,
"endPos": 14,
"entity": "Device"
}
]
},
{
"text": "start master bedroom light.",
"intent": "HomeAutomation",
"entities": [
{
"startPos": 6,
"endPos": 19,
"entity": "Room"
},
{
"startPos": 21,
"endPos": 25,
"entity": "Device"
}
]
},
{
"text": "theater on please",
"intent": "HomeAutomation",
"entities": [
{
"startPos": 0,
"endPos": 6,
"entity": "Room"
}
]
},
{
"text": "turn dimmer off",
"intent": "HomeAutomation",
"entities": [
{
"startPos": 5,
"endPos": 10,
"entity": "Device"
}
]
},
{
"text": "turn off ac please",
"intent": "HomeAutomation",
"entities": [
{
"startPos": 9,
"endPos": 10,
"entity": "Device"
}
]
},
{
"text": "turn off foyer lights",
"intent": "HomeAutomation",
"entities": [
{
"startPos": 9,
"endPos": 13,
"entity": "Room"
},
{
"startPos": 15,
"endPos": 20,
"entity": "Device"
}
]
},
{
"text": "turn off living room light",
"intent": "HomeAutomation",
"entities": [
{
"startPos": 9,
"endPos": 19,
"entity": "Room"
},
{
"startPos": 21,
"endPos": 25,
"entity": "Device"
}
]
},
{
"text": "turn off staircase",
"intent": "HomeAutomation",
"entities": [
{
"startPos": 9,
"endPos": 17,
"entity": "Device"
}
]
},
{
"text": "turn off venice lamp",
"intent": "HomeAutomation",
"entities": [
{
"startPos": 16,
"endPos": 19,
"entity": "Device"
}
]
},
{
"text": "turn on bathroom heater",
"intent": "HomeAutomation",
"entities": [
{
"startPos": 8,
"endPos": 15,
"entity": "Room"
},
{
"startPos": 17,
"endPos": 22,
"entity": "Device"
}
]
},
{
"text": "turn on external speaker",
"intent": "HomeAutomation",
"entities": [
{
"startPos": 8,
"endPos": 23,
"entity": "Device"
}
]
},
{
"text": "turn on kitchen faucet",
"intent": "HomeAutomation",
"entities": [
{
"startPos": 8,
"endPos": 14,
"entity": "Room"
},
{
"startPos": 16,
"endPos": 21,
"entity": "Device"
}
]
},
{
"text": "turn on light in bedroom",
"intent": "HomeAutomation",
"entities": [
{
"startPos": 8,
"endPos": 12,
"entity": "Device"
},
{
"startPos": 17,
"endPos": 23,
"entity": "Room"
}
]
},
{
"text": "turn on my bedroom lights.",
"intent": "HomeAutomation",
"entities": [
{
"startPos": 11,
"endPos": 17,
"entity": "Room"
},
{
"startPos": 19,
"endPos": 24,
"entity": "Device"
}
]
},
{
"text": "turn on the furnace room lights",
"intent": "HomeAutomation",
"entities": [
{
"startPos": 12,
"endPos": 23,
"entity": "Room"
},
{
"startPos": 25,
"endPos": 30,
"entity": "Device"
}
]
},
{
"text": "turn on the internet in my bedroom please",
"intent": "None",
"entities": [
{
"startPos": 27,
"endPos": 33,
"entity": "Room"
}
]
},
{
"text": "turn on thermostat please",
"intent": "HomeAutomation",
"entities": [
{
"startPos": 8,
"endPos": 17,
"entity": "Device"
}
]
},
{
"text": "turn the fan to high",
"intent": "HomeAutomation",
"entities": [
{
"startPos": 9,
"endPos": 11,
"entity": "Device"
}
]
},
{
"text": "turn thermostat on 70.",
"intent": "HomeAutomation",
"entities": [
{
"startPos": 5,
"endPos": 14,
"entity": "Device"
}
]
}
]
}
================================================
FILE: SDKV4-Samples/dotnet_core/nlp-with-dispatch/nlp-with-dispatchDispatch.json
================================================
{
"name": "nlp-with-dispatchDispatch",
"versionId": "Dispatch",
"desc": "Dispatch model for nlp-with-dispatchDispatch",
"culture": "en-us",
"intents": [
{
"name": "l_Home Automation"
},
{
"name": "l_Weather"
},
{
"name": "None"
},
{
"name": "q_sample-qna"
}
],
"entities": [],
"closedLists": [],
"composites": [],
"patternAnyEntities": [],
"regex_entities": [],
"prebuiltEntities": [],
"regex_features": [],
"model_features": [],
"patterns": [],
"utterances": [
{
"text": "breezeway on please",
"intent": "l_Home Automation",
"entities": []
},
{
"text": "change temperature to seventy two degrees",
"intent": "l_Home Automation",
"entities": []
},
{
"text": "coffee bar on please",
"intent": "l_Home Automation",
"entities": []
},
{
"text": "current weather ?",
"intent": "l_Weather",
"entities": []
},
{
"text": "decrease temperature for me please",
"intent": "None",
"entities": []
},
{
"text": "dim kitchen lights to 25 .",
"intent": "None",
"entities": []
},
{
"text": "do florida residents usually need ice scrapers",
"intent": "l_Weather",
"entities": []
},
{
"text": "fish pond off please",
"intent": "l_Home Automation",
"entities": []
},
{
"text": "fish pond on please",
"intent": "l_Home Automation",
"entities": []
},
{
"text": "forecast in celcius",
"intent": "l_Weather",
"entities": []
},
{
"text": "get florence temperature in september",
"intent": "l_Weather",
"entities": []
},
{
"text": "get for me the weather conditions in sonoma county",
"intent": "l_Weather",
"entities": []
},
{
"text": "get the daily temperature greenwood indiana",
"intent": "l_Weather",
"entities": []
},
{
"text": "get the forcast for me",
"intent": "l_Weather",
"entities": []
},
{
"text": "get the weather at saint george utah",
"intent": "l_Weather",
"entities": []
},
{
"text": "good evening",
"intent": "q_sample-qna",
"entities": []
},
{
"text": "good morning",
"intent": "q_sample-qna",
"entities": []
},
{
"text": "greetings",
"intent": "q_sample-qna",
"entities": []
},
{
"text": "hi",
"intent": "q_sample-qna",
"entities": []
},
{
"text": "how much rain does chambersburg get a year",
"intent": "l_Weather",
"entities": []
},
{
"text": "i want to know the temperature at death valley",
"intent": "l_Weather",
"entities": []
},
{
"text": "illuminate please",
"intent": "l_Home Automation",
"entities": []
},
{
"text": "living room lamp on please",
"intent": "l_Home Automation",
"entities": []
},
{
"text": "living room lamps off please",
"intent": "l_Home Automation",
"entities": []
},
{
"text": "lock the doors for me please",
"intent": "l_Home Automation",
"entities": []
},
{
"text": "lower your volume",
"intent": "None",
"entities": []
},
{
"text": "make camera 1 off please",
"intent": "l_Home Automation",
"entities": []
},
{
"text": "make some coffee",
"intent": "l_Home Automation",
"entities": []
},
{
"text": "play dvd",
"intent": "l_Home Automation",
"entities": []
},
{
"text": "provide me by toronto weather please",
"intent": "l_Weather",
"entities": []
},
{
"text": "set lights out in bedroom",
"intent": "l_Home Automation",
"entities": []
},
{
"text": "set lights to bright",
"intent": "l_Home Automation",
"entities": []
},
{
"text": "set lights to concentrate",
"intent": "l_Home Automation",
"entities": []
},
{
"text": "show average rainfall for boise",
"intent": "l_Weather",
"entities": []
},
{
"text": "show me the forecast at alabama",
"intent": "l_Weather",
"entities": []
},
{
"text": "shut down my work computer",
"intent": "l_Home Automation",
"entities": []
},
{
"text": "snap switch fan fifty percent",
"intent": "l_Home Automation",
"entities": []
},
{
"text": "soliciting today's weather",
"intent": "l_Weather",
"entities": []
},
{
"text": "start master bedroom light.",
"intent": "l_Home Automation",
"entities": []
},
{
"text": "temperature of delhi in celsius please",
"intent": "l_Weather",
"entities": []
},
{
"text": "theater on please",
"intent": "l_Home Automation",
"entities": []
},
{
"text": "turn dimmer off",
"intent": "l_Home Automation",
"entities": []
},
{
"text": "turn off ac please",
"intent": "l_Home Automation",
"entities": []
},
{
"text": "turn off foyer lights",
"intent": "l_Home Automation",
"entities": []
},
{
"text": "turn off living room light",
"intent": "l_Home Automation",
"entities": []
},
{
"text": "turn off staircase",
"intent": "l_Home Automation",
"entities": []
},
{
"text": "turn off venice lamp",
"intent": "l_Home Automation",
"entities": []
},
{
"text": "turn on bathroom heater",
"intent": "l_Home Automation",
"entities": []
},
{
"text": "turn on external speaker",
"intent": "l_Home Automation",
"entities": []
},
{
"text": "turn on kitchen faucet",
"intent": "l_Home Automation",
"entities": []
},
{
"text": "turn on light in bedroom",
"intent": "l_Home Automation",
"entities": []
},
{
"text": "turn on my bedroom lights.",
"intent": "l_Home Automation",
"entities": []
},
{
"text": "turn on the furnace room lights",
"intent": "l_Home Automation",
"entities": []
},
{
"text": "turn on the internet in my bedroom please",
"intent": "None",
"entities": []
},
{
"text": "turn on thermostat please",
"intent": "l_Home Automation",
"entities": []
},
{
"text": "turn the fan to high",
"intent": "l_Home Automation",
"entities": []
},
{
"text": "turn thermostat on 70.",
"intent": "l_Home Automation",
"entities": []
},
{
"text": "was last year about this time as wet as it is now in the south ?",
"intent": "l_Weather",
"entities": []
},
{
"text": "what are you?",
"intent": "q_sample-qna",
"entities": []
},
{
"text": "what do you do?",
"intent": "q_sample-qna",
"entities": []
},
{
"text": "what is the rain volume in sonoma county ?",
"intent": "l_Weather",
"entities": []
},
{
"text": "what is the weather in redmond ?",
"intent": "l_Weather",
"entities": []
},
{
"text": "what is the weather today at 10 day durham ?",
"intent": "l_Weather",
"entities": []
},
{
"text": "what is your name?",
"intent": "q_sample-qna",
"entities": []
},
{
"text": "what should i call you?",
"intent": "q_sample-qna",
"entities": []
},
{
"text": "what to wear in march in california",
"intent": "l_Weather",
"entities": []
},
{
"text": "what will the weather be tomorrow in new york ?",
"intent": "l_Weather",
"entities": []
},
{
"text": "what?",
"intent": "q_sample-qna",
"entities": []
},
{
"text": "what's the weather going to be like in hawaii ?",
"intent": "l_Weather",
"entities": []
},
{
"text": "what's the weather like in minneapolis",
"intent": "l_Weather",
"entities": []
},
{
"text": "who are you?",
"intent": "q_sample-qna",
"entities": []
},
{
"text": "will it be raining in ranchi",
"intent": "l_Weather",
"entities": []
},
{
"text": "will it rain this weekend",
"intent": "l_Weather",
"entities": []
},
{
"text": "will it snow today",
"intent": "l_Weather",
"entities": []
}
]
}
================================================
FILE: SDKV4-Samples/dotnet_core/nlp-with-dispatch/weather.json
================================================
{
"name": "Weather",
"versionId": "0.1",
"desc": "Weather LUIS application - Bot Builder Samples",
"culture": "en-us",
"intents": [
{
"name": "Get Weather Condition"
},
{
"name": "Get Weather Forecast"
},
{
"name": "None"
}
],
"entities": [
{
"name": "Location",
"roles": []
}
],
"closedLists": [],
"composites": [],
"patternAnyEntities": [
{
"name": "Location_PatternAny",
"explicitList": [],
"roles": []
}
],
"regex_entities": [],
"prebuiltEntities": [],
"regex_features": [],
"model_features": [],
"patterns": [
{
"pattern": "weather in {Location_PatternAny}",
"intent": "Get Weather Condition"
},
{
"pattern": "how's the weather in {Location_PatternAny}",
"intent": "Get Weather Condition"
},
{
"pattern": "current weather in {Location_PatternAny}",
"intent": "Get Weather Condition"
},
{
"pattern": "what's the forecast for next week in {Location_PatternAny}",
"intent": "Get Weather Forecast"
},
{
"pattern": "show me the forecast for {Location_PatternAny}",
"intent": "Get Weather Forecast"
},
{
"pattern": "what's the forecast for {Location_PatternAny}",
"intent": "Get Weather Forecast"
}
],
"utterances": [
{
"text": "current weather ?",
"intent": "Get Weather Condition",
"entities": []
},
{
"text": "do florida residents usually need ice scrapers",
"intent": "Get Weather Condition",
"entities": [
{
"startPos": 3,
"endPos": 9,
"entity": "Location"
}
]
},
{
"text": "forecast in celcius",
"intent": "Get Weather Forecast",
"entities": []
},
{
"text": "get florence temperature in september",
"intent": "Get Weather Condition",
"entities": [
{
"startPos": 4,
"endPos": 11,
"entity": "Location"
}
]
},
{
"text": "get for me the weather conditions in sonoma county",
"intent": "Get Weather Condition",
"entities": [
{
"startPos": 37,
"endPos": 49,
"entity": "Location"
}
]
},
{
"text": "get the daily temperature greenwood indiana",
"intent": "Get Weather Condition",
"entities": [
{
"startPos": 26,
"endPos": 42,
"entity": "Location"
}
]
},
{
"text": "get the forcast for me",
"intent": "Get Weather Forecast",
"entities": []
},
{
"text": "get the weather at saint george utah",
"intent": "Get Weather Condition",
"entities": [
{
"startPos": 19,
"endPos": 35,
"entity": "Location"
}
]
},
{
"text": "how much rain does chambersburg get a year",
"intent": "Get Weather Condition",
"entities": [
{
"startPos": 19,
"endPos": 30,
"entity": "Location"
}
]
},
{
"text": "i want to know the temperature at death valley",
"intent": "Get Weather Forecast",
"entities": [
{
"startPos": 34,
"endPos": 45,
"entity": "Location"
}
]
},
{
"text": "provide me by toronto weather please",
"intent": "Get Weather Forecast",
"entities": [
{
"startPos": 14,
"endPos": 20,
"entity": "Location"
}
]
},
{
"text": "show average rainfall for boise",
"intent": "Get Weather Condition",
"entities": [
{
"startPos": 26,
"endPos": 30,
"entity": "Location"
}
]
},
{
"text": "show me the forecast at alabama",
"intent": "Get Weather Forecast",
"entities": [
{
"startPos": 24,
"endPos": 30,
"entity": "Location"
}
]
},
{
"text": "soliciting today's weather",
"intent": "Get Weather Forecast",
"entities": []
},
{
"text": "temperature of delhi in celsius please",
"intent": "Get Weather Condition",
"entities": [
{
"startPos": 15,
"endPos": 19,
"entity": "Location"
}
]
},
{
"text": "was last year about this time as wet as it is now in the south ?",
"intent": "Get Weather Condition",
"entities": [
{
"startPos": 57,
"endPos": 61,
"entity": "Location"
}
]
},
{
"text": "what is the rain volume in sonoma county ?",
"intent": "Get Weather Condition",
"entities": [
{
"startPos": 27,
"endPos": 39,
"entity": "Location"
}
]
},
{
"text": "what is the weather in redmond ?",
"intent": "Get Weather Forecast",
"entities": [
{
"startPos": 23,
"endPos": 29,
"entity": "Location"
}
]
},
{
"text": "what is the weather today at 10 day durham ?",
"intent": "Get Weather Forecast",
"entities": [
{
"startPos": 36,
"endPos": 41,
"entity": "Location"
}
]
},
{
"text": "what to wear in march in california",
"intent": "Get Weather Condition",
"entities": [
{
"startPos": 25,
"endPos": 34,
"entity": "Location"
}
]
},
{
"text": "what will the weather be tomorrow in new york ?",
"intent": "Get Weather Forecast",
"entities": [
{
"startPos": 37,
"endPos": 44,
"entity": "Location"
}
]
},
{
"text": "what's the weather going to be like in hawaii ?",
"intent": "Get Weather Forecast",
"entities": [
{
"startPos": 39,
"endPos": 44,
"entity": "Location"
}
]
},
{
"text": "what's the weather like in minneapolis",
"intent": "Get Weather Condition",
"entities": [
{
"startPos": 27,
"endPos": 37,
"entity": "Location"
}
]
},
{
"text": "will it be raining in ranchi",
"intent": "Get Weather Forecast",
"entities": [
{
"startPos": 22,
"endPos": 27,
"entity": "Location"
}
]
},
{
"text": "will it rain this weekend",
"intent": "Get Weather Forecast",
"entities": []
},
{
"text": "will it snow today",
"intent": "Get Weather Forecast",
"entities": []
}
]
}
================================================
FILE: SDKV4-Samples/dotnet_core/nlp-with-luis/reminders-with-entities.json
================================================
{
"intents": [
{
"name": "Calendar_Add"
},
{
"name": "Calendar_Find"
},
{
"name": "None"
}
],
"entities": [
{
"name": "Appointment",
"roles": []
},
{
"name": "Meeting",
"roles": []
},
{
"name": "Schedule",
"roles": []
}
],
"composites": [],
"closedLists": [],
"patternAnyEntities": [],
"regex_entities": [],
"prebuiltEntities": [],
"model_features": [],
"regex_features": [],
"patterns": [],
"utterances": [
{
"text": "add a new event on 27 - apr",
"intent": "Calendar_Add",
"entities": []
},
{
"text": "add a new task finish assignment",
"intent": "Calendar_Add",
"entities": []
},
{
"text": "add an event to read about adam lambert news",
"intent": "Calendar_Add",
"entities": []
},
{
"text": "add an event to visit 209 nashville gym",
"intent": "Calendar_Add",
"entities": []
},
{
"text": "add date to my schedule",
"intent": "Calendar_Add",
"entities": [
{
"entity": "Schedule",
"startPos": 15,
"endPos": 22
}
]
},
{
"text": "add imax theater to my upcoming events",
"intent": "Calendar_Add",
"entities": []
},
{
"text": "am i free to be with friends saturday ?",
"intent": "None",
"entities": []
},
{
"text": "appointment with johnson needs to be next week",
"intent": "None",
"entities": [
{
"entity": "Appointment",
"startPos": 0,
"endPos": 10
}
]
},
{
"text": "calendar for november 1948",
"intent": "Calendar_Find",
"entities": []
},
{
"text": "calendar i ' ll be at the garage from 8 till 3 this saturday",
"intent": "Calendar_Add",
"entities": []
},
{
"text": "call dad mike",
"intent": "None",
"entities": []
},
{
"text": "change the meeting with chris to 9 : 00 am",
"intent": "None",
"entities": []
},
{
"text": "display weekend plans",
"intent": "Calendar_Find",
"entities": []
},
{
"text": "do i have anything on wednesday ?",
"intent": "Calendar_Find",
"entities": []
},
{
"text": "dunmore pa sonic sounds friday morning please",
"intent": "Calendar_Add",
"entities": []
},
{
"text": "email cloney john",
"intent": "None",
"entities": []
},
{
"text": "extend lunch meeting 30 minutes extra",
"intent": "None",
"entities": [
{
"entity": "Meeting",
"startPos": 13,
"endPos": 19
}
]
},
{
"text": "how many days are there between march 13th 2015 and today ?",
"intent": "Calendar_Find",
"entities": []
},
{
"text": "i want to reschedule the meeting at the air force club",
"intent": "None",
"entities": []
},
{
"text": "marketing meetings on tuesdays will now be every wednesday please change on my calendar",
"intent": "None",
"entities": []
},
{
"text": "meet my manager",
"intent": "Calendar_Add",
"entities": []
},
{
"text": "meeting my manager",
"intent": "Calendar_Add",
"entities": []
},
{
"text": "move the bbq party to friday",
"intent": "None",
"entities": []
},
{
"text": "pull up my appointment find out how much time i have before my next appointment",
"intent": "Calendar_Find",
"entities": [
{
"entity": "Appointment",
"startPos": 11,
"endPos": 21
}
]
},
{
"text": "save the date may 17 pictures party",
"intent": "Calendar_Add",
"entities": []
},
{
"text": "schedule a conference call for tomorrow",
"intent": "Calendar_Add",
"entities": [
{
"entity": "Schedule",
"startPos": 0,
"endPos": 7
}
]
},
{
"text": "schedule a meeting for tomorrow",
"intent": "Calendar_Add",
"entities": [
{
"entity": "Meeting",
"startPos": 11,
"endPos": 17
}
]
},
{
"text": "schedule appointment for tomorrow please",
"intent": "Calendar_Add",
"entities": [
{
"entity": "Schedule",
"startPos": 0,
"endPos": 7
},
{
"entity": "Appointment",
"startPos": 9,
"endPos": 19
}
]
},
{
"text": "search for meetings with chris",
"intent": "Calendar_Find",
"entities": [
{
"entity": "Meeting",
"startPos": 11,
"endPos": 18
}
]
},
{
"text": "show me tomorrow ' s wedding party time",
"intent": "Calendar_Find",
"entities": []
},
{
"text": "show my schedule for tomorrow",
"intent": "Calendar_Find",
"entities": [
{
"entity": "Schedule",
"startPos": 8,
"endPos": 15
}
]
},
{
"text": "tell me the event details",
"intent": "Calendar_Find",
"entities": []
},
{
"text": "the meeting will last for one hour",
"intent": "Calendar_Add",
"entities": [
{
"entity": "Meeting",
"startPos": 4,
"endPos": 10
}
]
},
{
"text": "the workshop will last for 10 hours",
"intent": "None",
"entities": []
},
{
"text": "voice activated reading of appointments this week",
"intent": "Calendar_Find",
"entities": [
{
"entity": "Appointment",
"startPos": 27,
"endPos": 38
}
]
}
],
"settings": []
}
================================================
FILE: SDKV4-Samples/js/DialogPromptBot/.eslintrc.js
================================================
module.exports = {
"extends": "standard",
"rules": {
"semi": [2, "always"],
"indent": [2, 4],
"no-return-await": 0,
"space-before-function-paren": [2, {
"named": "never",
"anonymous": "never",
"asyncArrow": "always"
}],
"template-curly-spacing": [2, "always"]
}
};
================================================
FILE: SDKV4-Samples/js/DialogPromptBot/.gitignore
================================================
node_modules
.env
================================================
FILE: SDKV4-Samples/js/DialogPromptBot/README.md
================================================
# Dialog Prompt Bot
Bot from the prompt-users-using-dialogs topic
This bot has been created using [Microsoft Bot Framework][10], it shows how to create a simple echo bot with state. The bot maintains a simple counter that increases with each message from the user. This bot example uses [`restify`][1].
# To run the bot
- Install modules and start the bot
```bash
npm i & npm start
```
Alternatively you can also use nodemon via
```bash
npm i & npm run watch
```
# Testing the bot using Bot Framework Emulator
[Microsoft Bot Framework Emulator][2] is a desktop application that allows bot developers to test and debug their bots on localhost or running remotely through a tunnel.
- Install the Bot Framework emulator from [here][3]
## Connect to bot using Bot Framework Emulator **V4**
- Launch Bot Framework Emulator
- File -> Open Bot Configuration
- Select `dialog-prompt.bot` file
# Bot state
A key to good bot design is to track the context of a conversation, so that your bot remembers things like the answers to previous questions. Depending on what your bot is used for, you may even need to keep track of conversation state or store user related information for longer than the lifetime of one given conversation.
In this example, the bot's state is used to track number of messages.
A bot's state is information it remembers in order to respond appropriately to incoming messages. The Bot Builder SDK provides classes for [storing and retrieving state data][4] as an object associated with a user or a conversation.
- Conversation properties help your bot keep track of the current conversation the bot is having with the user. If your bot needs to complete a sequence of steps or switch between conversation topics, you can use conversation properties to manage steps in a sequence or track the current topic. Since conversation properties reflect the state of the current conversation, you typically clear them at the end of a session, when the bot receives an end of conversation activity.
- User properties can be used for many purposes, such as determining where the user's prior conversation left off or simply greeting a returning user by name. If you store a user's preferences, you can use that information to customize the conversation the next time you chat. For example, you might alert the user to a news article about a topic that interests her, or alert a user when an appointment becomes available. You should clear them if the bot receives a delete user data activity.
# Deploy this bot to Azure
You can use the [MSBot][5] Bot Builder CLI tool to clone and configure the services this sample depends on.
To install all Bot Builder tools -
Ensure you have [Node.js](https://nodejs.org/) version 8.5 or higher
```bash
npm i -g msbot chatdown ludown qnamaker luis-apis botdispatch luisgen
```
To clone this bot, run
```
msbot clone services -f deploymentScripts/msbotClone -n myChatBot -l --subscriptionId
```
# Further reading
- [Azure Bot Service Introduction][6]
- [Bot State][7]
- [Write directly to storage][8]
- [Managing conversation and user state][9]
[1]: https://www.npmjs.com/package/restify
[2]: https://github.com/microsoft/botframework-emulator
[3]: https://aka.ms/botframework-emulator
[4]: https://docs.microsoft.com/en-us/azure/bot-service/bot-builder-howto-v4-state?view=azure-bot-service-4.0&tabs=js
[5]: https://github.com/microsoft/botbuilder-tools
[6]: https://docs.microsoft.com/en-us/azure/bot-service/bot-service-overview-introduction?view=azure-bot-service-4.0
[7]: https://docs.microsoft.com/en-us/azure/bot-service/bot-builder-storage-concept?view=azure-bot-service-4.0
[8]: https://docs.microsoft.com/en-us/azure/bot-service/bot-builder-howto-v4-storage?view=azure-bot-service-4.0&tabs=jsechoproperty%2Ccsetagoverwrite%2Ccsetag
[9]: https://docs.microsoft.com/en-us/azure/bot-service/bot-builder-howto-v4-state?view=azure-bot-service-4.0&tabs=js
[10] https://dev.botframework.com
================================================
FILE: SDKV4-Samples/js/DialogPromptBot/bot.js
================================================
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
const { ActivityTypes } = require('botbuilder');
const { DialogSet, WaterfallDialog, NumberPrompt, DateTimePrompt, ChoicePrompt, DialogTurnStatus }
= require('botbuilder-dialogs');
// Define identifiers for our state property accessors.
const DIALOG_STATE_ACCESSOR = 'dialogStateAccessor';
const RESERVATION_ACCESSOR = 'reservationAccessor';
// Define identifiers for our dialogs and prompts.
const RESERVATION_DIALOG = 'reservationDialog';
const SIZE_RANGE_PROMPT = 'rangePrompt';
const LOCATION_PROMPT = 'locationPrompt';
const RESERVATION_DATE_PROMPT = 'reservationDatePrompt';
class DialogPromptBot {
/**
*
* @param {ConversationState} conversation state object
*/
constructor(conversationState) {
// Creates our state accessor properties.
// See https://aka.ms/about-bot-state-accessors to learn more about the bot state and state accessors.
this.dialogStateAccessor = conversationState.createProperty(DIALOG_STATE_ACCESSOR);
this.reservationAccessor = conversationState.createProperty(RESERVATION_ACCESSOR);
this.conversationState = conversationState;
// Create the dialog set and add the prompts, including custom validation.
this.dialogSet = new DialogSet(this.dialogStateAccessor);
this.dialogSet.add(new NumberPrompt(SIZE_RANGE_PROMPT, this.rangeValidator));
this.dialogSet.add(new ChoicePrompt(LOCATION_PROMPT));
this.dialogSet.add(new DateTimePrompt(RESERVATION_DATE_PROMPT, this.dateValidator));
// Define the steps of the waterfall dialog and add it to the set.
this.dialogSet.add(new WaterfallDialog(RESERVATION_DIALOG, [
this.promptForPartySize.bind(this),
this.promptForLocation.bind(this),
this.promptForReservationDate.bind(this),
this.acknowledgeReservation.bind(this),
]));
}
/**
*
* @param {TurnContext} on turn context object.
*/
async onTurn(turnContext) {
switch (turnContext.activity.type) {
case ActivityTypes.Message:
// Get the current reservation info from state.
const reservation = await this.reservationAccessor.get(turnContext, null);
// Generate a dialog context for our dialog set.
const dc = await this.dialogSet.createContext(turnContext);
if (!dc.activeDialog) {
// If there is no active dialog, check whether we have a reservation yet.
if (!reservation) {
// If not, start the dialog.
await dc.beginDialog(RESERVATION_DIALOG);
}
else {
// Otherwise, send a status message.
await turnContext.sendActivity(
`We'll see you on ${reservation.date}.`);
}
}
else {
// Continue the dialog.
const dialogTurnResult = await dc.continueDialog();
// If the dialog completed this turn, record the reservation info.
if (dialogTurnResult.status === DialogTurnStatus.complete) {
await this.reservationAccessor.set(
turnContext,
dialogTurnResult.result);
// Send a confirmation message to the user.
await turnContext.sendActivity(
`Your party of ${dialogTurnResult.result.size} is ` +
`confirmed for ${dialogTurnResult.result.date} in ` +
`${dialogTurnResult.result.location}.`);
}
}
// Save the updated dialog state into the conversation state.
await this.conversationState.saveChanges(turnContext, false);
break;
case ActivityTypes.EndOfConversation:
case ActivityTypes.DeleteUserData:
break;
default:
break;
}
}
async promptForPartySize(stepContext) {
// Prompt for the party size. The result of the prompt is returned to the next step of the waterfall.
return await stepContext.prompt(
SIZE_RANGE_PROMPT, {
prompt: 'How many people is the reservation for?',
retryPrompt: 'How large is your party?',
validations: { min: 3, max: 8 },
});
}
async promptForLocation(stepContext) {
// Record the party size information in the current dialog state.
stepContext.values.size = stepContext.result;
// Prompt for location.
return await stepContext.prompt(LOCATION_PROMPT, {
prompt: 'Please choose a location.',
retryPrompt: 'Sorry, please choose a location from the list.',
choices: ['Redmond', 'Bellevue', 'Seattle'],
});
}
async promptForReservationDate(stepContext) {
// Record the location information in the current dialog state.
stepContext.values.location = stepContext.result.value;
return await stepContext.prompt(
RESERVATION_DATE_PROMPT, {
prompt: 'Great. When will the reservation be for?',
retryPrompt: 'What time should we make your reservation for?'
});
}
async acknowledgeReservation(stepContext) {
// Retrieve the reservation date.
const resolution = stepContext.result[0];
const time = resolution.value || resolution.start;
// Send an acknowledgement to the user.
await stepContext.context.sendActivity(
'Thank you. We will confirm your reservation shortly.');
// Return the collected information to the parent context.
return await stepContext.endDialog({
date: time,
size: stepContext.values.size,
location: stepContext.values.location
});
}
async rangeValidator(promptContext) {
// Check whether the input could be recognized as an integer.
if (!promptContext.recognized.succeeded) {
await promptContext.context.sendActivity(
"I'm sorry, I do not understand. Please enter the number of people in your party.");
return false;
}
else if (promptContext.recognized.value % 1 != 0) {
await promptContext.context.sendActivity(
"I'm sorry, I don't understand fractional people.");
return false;
}
// Check whether the party size is appropriate.
var size = promptContext.recognized.value;
if (size < promptContext.options.validations.min
|| size > promptContext.options.validations.max) {
await promptContext.context.sendActivity(
'Sorry, we can only take reservations for parties of '
+ `${promptContext.options.validations.min} to `
+ `${promptContext.options.validations.max}.`);
await promptContext.context.sendActivity(promptContext.options.retryPrompt);
return false;
}
return true;
}
async dateValidator(promptContext) {
// Check whether the input could be recognized as an integer.
if (!promptContext.recognized.succeeded) {
await promptContext.context.sendActivity(
"I'm sorry, I do not understand. Please enter the date or time for your reservation.");
return false;
}
// Check whether any of the recognized date-times are appropriate,
// and if so, return the first appropriate date-time.
const earliest = Date.now() + (60 * 60 * 1000);
let value = null;
promptContext.recognized.value.forEach(candidate => {
// TODO: update validation to account for time vs date vs date-time vs range.
const time = new Date(candidate.value || candidate.start);
if (earliest < time.getTime()) {
value = candidate;
}
});
if (value) {
promptContext.recognized.value = [value];
return true;
}
await promptContext.context.sendActivity(
"I'm sorry, we can't take reservations earlier than an hour from now.");
return false;
}
}
module.exports.DialogPromptBot = DialogPromptBot;
================================================
FILE: SDKV4-Samples/js/DialogPromptBot/deploymentScripts/msbotClone/bot.recipe
================================================
{
"version": "1.0",
"resources": [
{
"type": "endpoint",
"id": "1",
"name": "development",
"url": "http://localhost:3978/api/messages"
},
{
"type": "endpoint",
"id": "2",
"name": "production",
"url": "https://your-bot-url.azurewebsites.net/api/messages"
},
{
"type": "abs",
"id": "3",
"name": "DialogPromptBot-abs"
},
{
"type": "appInsights",
"id": "4",
"name": "DialogPromptBot-insights"
},
{
"type": "blob",
"id": "5",
"name": "DialogPromptBot-blob",
"container": "botstatestore"
}
]
}
================================================
FILE: SDKV4-Samples/js/DialogPromptBot/dialog-prompt.bot
================================================
{
"name": "DialogPromptBot",
"services": [
{
"type": "endpoint",
"name": "development",
"endpoint": "http://localhost:3978/api/messages",
"appId": "",
"appPassword": "",
"id": "1"
}
],
"padlock": "",
"version": "2.0"
}
================================================
FILE: SDKV4-Samples/js/DialogPromptBot/index.js
================================================
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
const path = require('path');
const restify = require('restify');
// Import required bot services.
// See https://aka.ms/bot-services to learn more about the different parts of a bot.
const { BotFrameworkAdapter, MemoryStorage, ConversationState } = require('botbuilder');
// Import required bot configuration.
const { BotConfiguration } = require('botframework-config');
// This bot's main dialog.
const { DialogPromptBot } = require('./bot');
// Read botFilePath and botFileSecret from .env file
// Note: Ensure you have a .env file and include botFilePath and botFileSecret.
const ENV_FILE = path.join(__dirname, '.env');
const env = require('dotenv').config({path: ENV_FILE});
// bot endpoint name as defined in .bot file
// See https://aka.ms/about-bot-file to learn more about .bot file its use and bot configuration .
const DEV_ENVIRONMENT = 'development';
// bot name as defined in .bot file
// See https://aka.ms/about-bot-file to learn more about .bot file its use and bot configuration.
const BOT_CONFIGURATION = (process.env.NODE_ENV || DEV_ENVIRONMENT);
// Create HTTP server
let server = restify.createServer();
server.listen(process.env.port || process.env.PORT || 3978, function () {
console.log(`\n${server.name} listening to ${server.url}`);
console.log(`\nGet Bot Framework Emulator: https://aka.ms/botframework-emulator`);
console.log(`\nTo talk to your bot, open dialog-prompt.bot file in the Emulator`);
});
// .bot file path
const BOT_FILE = path.join(__dirname, (process.env.botFilePath || ''));
// Read bot configuration from .bot file.
let botConfig;
try {
botConfig = BotConfiguration.loadSync(BOT_FILE, process.env.botFileSecret);
} catch (err) {
console.error(`\nError reading bot file. Please ensure you have valid botFilePath and botFileSecret set for your environment.`);
console.error(`\n - The botFileSecret is available under appsettings for your Azure Bot Service bot.`);
console.error(`\n - If you are running this bot locally, consider adding a .env file with botFilePath and botFileSecret.\n\n`);
process.exit();
}
// Get bot endpoint configuration by service name
const endpointConfig = botConfig.findServiceByNameOrId(BOT_CONFIGURATION);
// Create adapter.
// See https://aka.ms/about-bot-adapter to learn more about .bot file its use and bot configuration .
const adapter = new BotFrameworkAdapter({
appId: endpointConfig.appId || process.env.microsoftAppID,
appPassword: endpointConfig.appPassword || process.env.microsoftAppPassword
});
// Define state store for your bot.
// See https://aka.ms/about-bot-state to learn more about bot state.
const memoryStorage = new MemoryStorage();
// CAUTION: You must ensure your product environment has the NODE_ENV set
// to use the Azure Blob storage or Azure Cosmos DB providers.
// const { BlobStorage } = require('botbuilder-azure');
// Storage configuration name or ID from .bot file
// const STORAGE_CONFIGURATION_ID = '';
// // Default container name
// const DEFAULT_BOT_CONTAINER = '';
// // Get service configuration
// const blobStorageConfig = botConfig.findServiceByNameOrId(STORAGE_CONFIGURATION_ID);
// const blobStorage = new BlobStorage({
// containerName: (blobStorageConfig.container || DEFAULT_BOT_CONTAINER),
// storageAccountOrConnectionString: blobStorageConfig.connectionString,
// });
// conversationState = new ConversationState(blobStorage);
// Create conversation state with in-memory storage provider.
const conversationState = new ConversationState(memoryStorage);
// Create the main dialog.
const myBot = new DialogPromptBot(conversationState);
// Catch-all for errors.
adapter.onTurnError = async (context, error) => {
// This check writes out errors to console log .vs. app insights.
console.error(`\n [onTurnError]: ${error}`);
// Send a message to the user
context.sendActivity(`Oops. Something went wrong!`);
// Clear out state
await conversationState.load(context);
await conversationState.clear(context);
// Save state changes.
await conversationState.saveChanges(context);
};
// Listen for incoming requests.
server.post('/api/messages', (req, res) => {
adapter.processActivity(req, res, async (context) => {
// Route to main dialog.
await myBot.onTurn(context);
});
});
================================================
FILE: SDKV4-Samples/js/DialogPromptBot/package.json
================================================
{
"name": "dialog-prompt-bot",
"version": "1.0.0",
"description": "Bot from the prompt-users-using-dialogs topic",
"author": "Microsoft Bot Builder Yeoman Generator v4.0.10",
"license": "MIT",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "echo \"Error: no build specified\" && exit 1",
"start": "node ./index.js",
"watch": "nodemon ./index.js"
},
"dependencies": {
"botbuilder": "^4.2.1",
"botbuilder-dialogs": "^4.2.1",
"botframework-config": "^4.1.5",
"dotenv": "^6.0.0",
"restify": "^6.3.4"
},
"devDependencies": {
"eslint": "^5.6.0",
"eslint-config-standard": "^12.0.0",
"eslint-plugin-import": "^2.14.0",
"eslint-plugin-node": "^7.0.1",
"eslint-plugin-promise": "^4.0.1",
"eslint-plugin-standard": "^4.0.0",
"nodemon": "^1.18.4",
"@types/node": "10.10.2",
"@types/restify": "7.2.4"
}
}
================================================
FILE: SDKV4-Samples/js/PromptUsersForInput/.eslintrc.js
================================================
module.exports = {
"extends": "standard",
"rules": {
"semi": [2, "always"],
"indent": [2, 4],
"no-return-await": 0,
"space-before-function-paren": [2, {
"named": "never",
"anonymous": "never",
"asyncArrow": "always"
}],
"template-curly-spacing": [2, "always"]
}
};
================================================
FILE: SDKV4-Samples/js/PromptUsersForInput/README.md
================================================
# Prompt users for input
This sample demonstrates how to create your own prompts with an ASP.Net Core 2 bot.
The bot maintains conversation state to track and direct the conversation and ask the user questions.
The bot maintains user state to track the user's answers.
This bot example uses [`restify`][restify].
# To run the bot
- Install modules and start the bot
```bash
npm i
npm start
```
Alternatively you can also use nodemon via
```bash
npm i
npm run watch
```
# Testing the bot using Bot Framework Emulator
[Microsoft Bot Framework Emulator][emulator] is a desktop application that allows bot developers to test and debug their bots on localhost or running remotely through a tunnel.
- Install the Bot Framework emulator from [here][emulator]
## Connect to bot using Bot Framework Emulator **V4**
- Launch Bot Framework Emulator
- File -> Open Bot Configuration
- Select `simplePrompts.bot` file
# Bot state
A bot is inherently stateless. Once your bot is deployed, it may not run in the same process or on the same machine from one turn to the next.
However, your bot may need to track the context of a conversation, so that it can manage its behavior and remember answers to previous questions.
In this example, the bot's state is used to a track number of messages.
- We use the bot's turn handler and user and conversation state properties to manage the flow of the conversation and the collection of input.
- We ask the user a series of questions; parse, validate, and normalize their answers; and then save their input.
This sample is intended to be run and tested locally and is not designed to be deployed to Azure.
# Further reading
- [Azure Bot Service introduction][bot-service-overview]
- [About bot state][state-concept]
- [Prompt users for input][primitive-prompts]
- [Managing conversation and user state][state-how-to]
- [Write directly to storage][storage-how-to]
[restify]: https://www.npmjs.com/package/restify
[emulator]: https://aka.ms/botframework-emulator
[bot-service-docs]: https://docs.microsoft.com/azure/bot-service/
[bot-service-overview]: https://docs.microsoft.com/azure/bot-service/bot-service-overview-introduction
[state-concept]: https://docs.microsoft.com/azure/bot-service/bot-builder-concept-state
[primitive-prompts]: https://docs.microsoft.com/azure/bot-service/bot-builder-primitive-prompts
[state-how-to]: https://docs.microsoft.com/azure/bot-service/bot-builder-howto-v4-state
[storage-how-to]: https://docs.microsoft.com/azure/bot-service/bot-builder-howto-v4-storage
================================================
FILE: SDKV4-Samples/js/PromptUsersForInput/bot.js
================================================
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
const Recognizers = require('@microsoft/recognizers-text-suite');
const { ActivityTypes, MessageFactory } = require('botbuilder');
// The accessor names for the conversation flow and user profile state property accessors.
const CONVERSATION_FLOW_PROPERTY = 'conversationFlowProperty';
const USER_PROFILE_PROPERTY = 'userProfileProperty';
// Identifies the last question asked.
const question = {
name: "name",
age: "age",
date: "date",
none: "none"
}
// Defines a bot for filling a user profile.
class MyBot {
constructor(conversationState, userState) {
// The state property accessors for conversation flow and user profile.
this.conversationFlow = conversationState.createProperty(CONVERSATION_FLOW_PROPERTY);
this.userProfile = userState.createProperty(USER_PROFILE_PROPERTY);
// The state management objects for the conversation and user.
this.conversationState = conversationState;
this.userState = userState;
}
// The bot's turn handler.
async onTurn(turnContext) {
// This bot listens for message activities.
if (turnContext.activity.type === ActivityTypes.Message) {
// Get the state properties from the turn context.
const flow = await this.conversationFlow.get(turnContext, { lastQuestionAsked: question.none });
const profile = await this.userProfile.get(turnContext, {});
await MyBot.fillOutUserProfile(flow, profile, turnContext);
// Update state and save changes.
await this.conversationFlow.set(turnContext, flow);
await this.conversationState.saveChanges(turnContext);
await this.userProfile.set(turnContext, profile);
await this.userState.saveChanges(turnContext);
}
}
// Manages the conversation flow for filling out the user's profile.
static async fillOutUserProfile(flow, profile, turnContext) {
const input = turnContext.activity.text;
let result;
switch (flow.lastQuestionAsked) {
// If we're just starting off, we haven't asked the user for any information yet.
// Ask the user for their name and update the conversation flag.
case question.none:
await turnContext.sendActivity("Let's get started. What is your name?");
flow.lastQuestionAsked = question.name;
break;
// If we last asked for their name, record their response, confirm that we got it.
// Ask them for their age and update the conversation flag.
case question.name:
result = this.validateName(input);
if (result.success) {
profile.name = result.name;
await turnContext.sendActivity(`I have your name as ${profile.name}.`);
await turnContext.sendActivity('How old are you?');
flow.lastQuestionAsked = question.age;
break;
} else {
// If we couldn't interpret their input, ask them for it again.
// Don't update the conversation flag, so that we repeat this step.
await turnContext.sendActivity(
result.message || "I'm sorry, I didn't understand that.");
break;
}
// If we last asked for their age, record their response, confirm that we got it.
// Ask them for their date preference and update the conversation flag.
case question.age:
result = this.validateAge(input);
if (result.success) {
profile.age = result.age;
await turnContext.sendActivity(`I have your age as ${profile.age}.`);
await turnContext.sendActivity('When is your flight?');
flow.lastQuestionAsked = question.date;
break;
} else {
// If we couldn't interpret their input, ask them for it again.
// Don't update the conversation flag, so that we repeat this step.
await turnContext.sendActivity(
result.message || "I'm sorry, I didn't understand that.");
break;
}
// If we last asked for a date, record their response, confirm that we got it,
// let them know the process is complete, and update the conversation flag.
case question.date:
result = this.validateDate(input);
if (result.success) {
profile.date = result.date;
await turnContext.sendActivity(`Your cab ride to the airport is scheduled for ${profile.date}.`);
await turnContext.sendActivity(`Thanks for completing the booking ${profile.name}.`);
await turnContext.sendActivity('Type anything to run the bot again.');
flow.lastQuestionAsked = question.none;
profile = {};
break;
} else {
// If we couldn't interpret their input, ask them for it again.
// Don't update the conversation flag, so that we repeat this step.
await turnContext.sendActivity(
result.message || "I'm sorry, I didn't understand that.");
break;
}
}
}
// Validates name input. Returns whether validation succeeded and either the parsed and normalized
// value or a message the bot can use to ask the user again.
static validateName(input) {
const name = input && input.trim();
return name != undefined
? { success: true, name: name }
: { success: false, message: 'Please enter a name that contains at least one character.' };
};
// Validates age input. Returns whether validation succeeded and either the parsed and normalized
// value or a message the bot can use to ask the user again.
static validateAge(input) {
// Try to recognize the input as a number. This works for responses such as "twelve" as well as "12".
try {
// Attempt to convert the Recognizer result to an integer. This works for "a dozen", "twelve", "12", and so on.
// The recognizer returns a list of potential recognition results, if any.
const results = Recognizers.recognizeNumber(input, Recognizers.Culture.English);
let output;
results.forEach(function (result) {
// result.resolution is a dictionary, where the "value" entry contains the processed string.
const value = result.resolution['value'];
if (value) {
const age = parseInt(value);
if (!isNaN(age) && age >= 18 && age <= 120) {
output = { success: true, age: age };
return;
}
}
});
return output || { success: false, message: 'Please enter an age between 18 and 120.' };
} catch (error) {
return {
success: false,
message: "I'm sorry, I could not interpret that as an age. Please enter an age between 18 and 120."
};
}
}
// Validates date input. Returns whether validation succeeded and either the parsed and normalized
// value or a message the bot can use to ask the user again.
static validateDate(input) {
// Try to recognize the input as a date-time. This works for responses such as "11/14/2018", "today at 9pm", "tomorrow", "Sunday at 5pm", and so on.
// The recognizer returns a list of potential recognition results, if any.
try {
const results = Recognizers.recognizeDateTime(input, Recognizers.Culture.English);
const now = new Date();
const earliest = now.getTime() + (60 * 60 * 1000);
let output;
results.forEach(function (result) {
// result.resolution is a dictionary, where the "values" entry contains the processed input.
result.resolution['values'].forEach(function (resolution) {
// The processed input contains a "value" entry if it is a date-time value, or "start" and
// "end" entries if it is a date-time range.
const datevalue = resolution['value'] || resolution['start'];
// If only time is given, assume it's for today.
const datetime = resolution['type'] === 'time'
? new Date(`${now.toLocaleDateString()} ${datevalue}`)
: new Date(datevalue);
if (datetime && earliest < datetime.getTime()) {
output = { success: true, date: datetime.toLocaleDateString() };
return;
}
});
});
return output || { success: false, message: "I'm sorry, please enter a date at least an hour out." };
} catch (error) {
return {
success: false,
message: "I'm sorry, I could not interpret that as an appropriate date. Please enter a date at least an hour out."
};
}
}
}
module.exports.MyBot = MyBot;
================================================
FILE: SDKV4-Samples/js/PromptUsersForInput/deploymentScripts/msbotClone/bot.recipe
================================================
{
"version": "1.0",
"resources": [
{
"type": "endpoint",
"id": "1",
"name": "development",
"url": "http://localhost:3978/api/messages"
},
{
"type": "endpoint",
"id": "2",
"name": "production",
"url": "https://your-bot-url.azurewebsites.net/api/messages"
},
{
"type": "abs",
"id": "3",
"name": "simplePrompts-abs"
},
{
"type": "appInsights",
"id": "4",
"name": "simplePrompts-insights"
},
{
"type": "blob",
"id": "5",
"name": "simplePrompts-blob",
"container": "botstatestore"
}
]
}
================================================
FILE: SDKV4-Samples/js/PromptUsersForInput/index.js
================================================
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
const path = require('path');
const restify = require('restify');
// Import required bot services.
// See https://aka.ms/bot-services to learn more about the different parts of a bot.
const { BotFrameworkAdapter, MemoryStorage, ConversationState, UserState } = require('botbuilder');
// Import required bot configuration.
const { BotConfiguration } = require('botframework-config');
// This bot's main dialog.
const { MyBot } = require('./bot');
// Read botFilePath and botFileSecret from .env file
// Note: Ensure you have a .env file and include botFilePath and botFileSecret.
const ENV_FILE = path.join(__dirname, '.env');
const env = require('dotenv').config({path: ENV_FILE});
// bot endpoint name as defined in .bot file
// See https://aka.ms/about-bot-file to learn more about .bot file its use and bot configuration .
const DEV_ENVIRONMENT = 'development';
// bot name as defined in .bot file
// See https://aka.ms/about-bot-file to learn more about .bot file its use and bot configuration.
const BOT_CONFIGURATION = (process.env.NODE_ENV || DEV_ENVIRONMENT);
// Create HTTP server
let server = restify.createServer();
server.listen(process.env.port || process.env.PORT || 3978, function () {
console.log(`\n${server.name} listening to ${server.url}`);
console.log(`\nGet Bot Framework Emulator: https://aka.ms/botframework-emulator`);
console.log(`\nTo talk to your bot, open simplePrompts.bot file in the Emulator`);
});
// .bot file path
const BOT_FILE = path.join(__dirname, (process.env.botFilePath || ''));
// Read bot configuration from .bot file.
let botConfig;
try {
botConfig = BotConfiguration.loadSync(BOT_FILE, process.env.botFileSecret);
} catch (err) {
console.error(`\nError reading bot file. Please ensure you have valid botFilePath and botFileSecret set for your environment.`);
console.error(`\n - The botFileSecret is available under appsettings for your Azure Bot Service bot.`);
console.error(`\n - If you are running this bot locally, consider adding a .env file with botFilePath and botFileSecret.\n\n`);
process.exit();
}
// Get bot endpoint configuration by service name
const endpointConfig = botConfig.findServiceByNameOrId(BOT_CONFIGURATION);
// Create adapter.
// See https://aka.ms/about-bot-adapter to learn more about .bot file its use and bot configuration .
const adapter = new BotFrameworkAdapter({
appId: endpointConfig.appId || process.env.microsoftAppID,
appPassword: endpointConfig.appPassword || process.env.microsoftAppPassword
});
// Create conversation and user state with in-memory storage provider.
const memoryStorage = new MemoryStorage();
const conversationState = new ConversationState(memoryStorage);
const userState = new UserState(memoryStorage);
// Create the bot.
const myBot = new MyBot(conversationState, userState);
// Catch-all for errors.
adapter.onTurnError = async (context, error) => {
// This check writes out errors to console log .vs. app insights.
console.error(`\n [onTurnError]: ${error}`);
// Send a message to the user
context.sendActivity(`Oops. Something went wrong!`);
// Clear out state
await conversationState.load(context);
await conversationState.clear(context);
// Save state changes.
await conversationState.saveChanges(context);
};
// Listen for incoming requests.
server.post('/api/messages', (req, res) => {
adapter.processActivity(req, res, async (context) => {
// Route to main dialog.
await myBot.onTurn(context);
});
});
================================================
FILE: SDKV4-Samples/js/PromptUsersForInput/package.json
================================================
{
"name": "simplePrompts",
"version": "1.0.0",
"description": "Sample code for Create your own prompts to gather user input",
"author": "Microsoft Bot Builder Yeoman Generator v4.0.10",
"license": "MIT",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "echo \"Error: no build specified\" && exit 1",
"start": "node ./index.js",
"watch": "nodemon ./index.js"
},
"dependencies": {
"@microsoft/recognizers-text-suite": "^1.1.4",
"botbuilder": "^4.0.6",
"botframework-config": "^4.0.6",
"dotenv": "^6.0.0",
"restify": "^6.3.4"
},
"devDependencies": {
"eslint": "^5.6.0",
"eslint-config-standard": "^12.0.0",
"eslint-plugin-import": "^2.14.0",
"eslint-plugin-node": "^7.0.1",
"eslint-plugin-promise": "^4.0.1",
"eslint-plugin-standard": "^4.0.0",
"nodemon": "^1.18.4",
"@types/node": "10.10.2",
"@types/restify": "7.2.4"
}
}
================================================
FILE: SDKV4-Samples/js/PromptUsersForInput/resources/echo.chat
================================================
user=Vishwac
bot=EchoBot
user: Hi
bot: 1: You said "Hi"
user: Hello
bot: 2: You said "Hello"
================================================
FILE: SDKV4-Samples/js/PromptUsersForInput/simplePrompts.bot
================================================
{
"name": "simplePrompts",
"services": [
{
"type": "endpoint",
"name": "development",
"endpoint": "http://localhost:3978/api/messages",
"appId": "",
"appPassword": "",
"id": "1"
}
],
"padlock": "",
"version": "2.0"
}
================================================
FILE: SDKV4-Samples/js/complexDialogBot/.eslintrc.js
================================================
module.exports = {
"extends": "standard",
"rules": {
"semi": [2, "always"],
"indent": [2, 4],
"no-return-await": 0,
"space-before-function-paren": [2, {
"named": "never",
"anonymous": "never",
"asyncArrow": "always"
}],
"template-curly-spacing": [2, "always"]
}
};
================================================
FILE: SDKV4-Samples/js/complexDialogBot/.gitignore
================================================
node_modules
.env
================================================
FILE: SDKV4-Samples/js/complexDialogBot/ComplexDialogBot.bot
================================================
{
"name": "ComplexDialogBot",
"description": "",
"services": [
{
"type": "abs",
"tenantId": "72f988bf-86f1-41af-91ab-2d7cd011db47",
"subscriptionId": "0389857f-2464-451b-ac83-5f54d565b1a7",
"resourceGroup": "jf-registration-group",
"serviceName": "ComplexDialogBot",
"name": "ComplexDialogBot",
"id": "1",
"appId": "3dc6e586-761a-4f53-a86c-9068c13a8d34"
},
{
"type": "blob",
"connectionString": "DefaultEndpointsProtocol=https;AccountName=omplexia3982;AccountKey=i5x0MbMJdInaLDAS/sMY0lg5jG/RGoGWlwJiguutN4pn0Ow2bb7JuX9+psWMKLOwfUW5MYnkGTWFxaQSCc4gsQ==;",
"tenantId": "72f988bf-86f1-41af-91ab-2d7cd011db47",
"subscriptionId": "0389857f-2464-451b-ac83-5f54d565b1a7",
"resourceGroup": "jf-registration-group",
"serviceName": "omplexia3982",
"id": "2"
},
{
"type": "endpoint",
"appId": "",
"appPassword": "",
"endpoint": "http://localhost:3978/api/messages",
"name": "development",
"id": "3"
},
{
"type": "endpoint",
"appId": "3dc6e586-761a-4f53-a86c-9068c13a8d34",
"appPassword": "nddakednI@h2b%!X",
"endpoint": "https://omplexialogo59uk.azurewebsites.net/api/messages",
"name": "production",
"id": "4"
},
{
"type": "appInsights",
"instrumentationKey": "b6f253df-2a26-4848-b4e7-f531057820fe",
"applicationId": "5caae2b8-030b-4683-9713-f098a9a9e319",
"apiKeys": {},
"tenantId": "72f988bf-86f1-41af-91ab-2d7cd011db47",
"subscriptionId": "0389857f-2464-451b-ac83-5f54d565b1a7",
"resourceGroup": "jf-registration-group",
"serviceName": "ComplexDialogBotmbav3w",
"id": "5"
}
],
"padlock": "",
"version": "2.0"
}
================================================
FILE: SDKV4-Samples/js/complexDialogBot/README.md
================================================
# ComplexDialogBot
This sample creates a complex conversation with dialogs and Node.js.
This bot has been created using [Microsoft Bot Framework][10], it shows how to create a simple echo bot with state. The bot maintains a simple counter that increases with each message from the user. This bot example uses [`restify`][1].
# To run the bot
- Install modules and start the bot
```bash
npm i & npm start
```
Alternatively you can also use nodemon via
```bash
npm i & npm run watch
```
# Testing the bot using Bot Framework Emulator
[Microsoft Bot Framework Emulator][2] is a desktop application that allows bot developers to test and debug their bots on localhost or running remotely through a tunnel.
- Install the Bot Framework emulator from [here][3]
## Connect to bot using Bot Framework Emulator **V4**
- Launch Bot Framework Emulator
- File -> Open Bot Configuration
- Select `ComplexDialogBot.bot` file
# Further reading
- [Azure Bot Service Introduction][6]
- [Bot State][7]
- [Write directly to storage][8]
- [Managing conversation and user state][9]
[1]: https://www.npmjs.com/package/restify
[2]: https://github.com/microsoft/botframework-emulator
[3]: https://aka.ms/botframework-emulator
[6]: https://docs.microsoft.com/azure/bot-service/bot-service-overview-introduction
[7]: https://docs.microsoft.com/azure/bot-service/bot-builder-storage-concept
[8]: https://docs.microsoft.com/azure/bot-service/bot-builder-howto-v4-storage?tabs=javascript
[9]: https://docs.microsoft.com/azure/bot-service/bot-builder-howto-v4-state?tabs=javascript
[10] https://dev.botframework.com
================================================
FILE: SDKV4-Samples/js/complexDialogBot/bot.js
================================================
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
const { ActivityTypes } = require('botbuilder');
const { DialogSet, WaterfallDialog, TextPrompt, NumberPrompt, ChoicePrompt, DialogTurnStatus } = require('botbuilder-dialogs');
// Define state property accessor names.
const DIALOG_STATE_PROPERTY = 'dialogStateProperty';
const USER_PROFILE_PROPERTY = 'userProfileProperty';
const WELCOME_TEXT =
'Welcome to ComplexDialogBot. This bot provides a complex conversation, with multiple dialogs. '
+ 'Type anything to get started.';
// Define the dialog and prompt names for the bot.
const TOP_LEVEL_DIALOG = 'dialog-topLevel';
const REVIEW_SELECTION_DIALOG = 'dialog-reviewSelection';
const NAME_PROMPT = 'prompt-name';
const AGE_PROMPT = 'prompt-age';
const SELECTION_PROMPT = 'prompt-companySelection';
// Define a 'done' response for the company selection prompt.
const DONE_OPTION = 'done';
// Define value names for values tracked inside the dialogs.
const USER_INFO = 'value-userInfo';
const COMPANIES_SELECTED = 'value-companiesSelected';
// Define the company choices for the company selection prompt.
const COMPANY_OPTIONS = [
'Adatum Corporation', 'Contoso Suites', 'Graphic Design Institute', 'Wide World Importers'
];
class MyBot {
/**
*
* @param {ConversationState} conversation state object
* @param {UserState} user state object
*/
constructor(conversationState, userState) {
// Create the state property accessors and save the state management objects.
this.dialogStateAccessor = conversationState.createProperty(DIALOG_STATE_PROPERTY);
this.userProfileAccessor = userState.createProperty(USER_PROFILE_PROPERTY);
this.conversationState = conversationState;
this.userState = userState;
// Create a dialog set for the bot. It requires a DialogState accessor, with which
// to retrieve the dialog state from the turn context.
this.dialogs = new DialogSet(this.dialogStateAccessor);
// Add the prompts we need to the dialog set.
this.dialogs
.add(new TextPrompt(NAME_PROMPT))
.add(new NumberPrompt(AGE_PROMPT))
.add(new ChoicePrompt(SELECTION_PROMPT));
// Add the dialogs we need to the dialog set.
this.dialogs.add(new WaterfallDialog(TOP_LEVEL_DIALOG)
.addStep(this.nameStep.bind(this))
.addStep(this.ageStep.bind(this))
.addStep(this.startSelectionStep.bind(this))
.addStep(this.acknowledgementStep.bind(this)));
this.dialogs.add(new WaterfallDialog(REVIEW_SELECTION_DIALOG)
.addStep(this.selectionStep.bind(this))
.addStep(this.loopStep.bind(this)));
}
/**
*
* @param {TurnContext} on turn context object.
*/
async onTurn(turnContext) {
if (turnContext.activity.type === ActivityTypes.Message) {
// Run the DialogSet - let the framework identify the current state of the dialog from
// the dialog stack and figure out what (if any) is the active dialog.
const dialogContext = await this.dialogs.createContext(turnContext);
const results = await dialogContext.continueDialog();
switch (results.status) {
case DialogTurnStatus.cancelled:
case DialogTurnStatus.empty:
// If there is no active dialog, we should clear the user info and start a new dialog.
await this.userProfileAccessor.set(turnContext, {});
await this.userState.saveChanges(turnContext);
await dialogContext.beginDialog(TOP_LEVEL_DIALOG);
break;
case DialogTurnStatus.complete:
// If we just finished the dialog, capture and display the results.
const userInfo = results.result;
const status = 'You are signed up to review '
+ (userInfo.companiesToReview.length === 0 ? 'no companies' : userInfo.companiesToReview.join(' and '))
+ '.';
await turnContext.sendActivity(status);
await this.userProfileAccessor.set(turnContext, userInfo);
await this.userState.saveChanges(turnContext);
break;
case DialogTurnStatus.waiting:
// If there is an active dialog, we don't need to do anything here.
break;
}
await this.conversationState.saveChanges(turnContext);
} else if (turnContext.activity.type === ActivityTypes.ConversationUpdate) {
if (turnContext.activity.membersAdded && turnContext.activity.membersAdded.length > 0) {
await this.sendWelcomeMessage(turnContext);
}
} else {
await turnContext.sendActivity(`[${turnContext.activity.type} event detected]`);
}
}
// Sends a welcome message to any users who joined the conversation.
async sendWelcomeMessage(turnContext) {
for (var idx in turnContext.activity.membersAdded) {
if (turnContext.activity.membersAdded[idx].id !== turnContext.activity.recipient.id) {
await turnContext.sendActivity(WELCOME_TEXT);
}
}
}
async nameStep(stepContext) {
// Create an object in which to collect the user's information within the dialog.
stepContext.values[USER_INFO] = {};
// Ask the user to enter their name.
return await stepContext.prompt(NAME_PROMPT, 'Please enter your name.');
}
async ageStep(stepContext) {
// Set the user's name to what they entered in response to the name prompt.
stepContext.values[USER_INFO].name = stepContext.result;
// Ask the user to enter their age.
return await stepContext.prompt(AGE_PROMPT, 'Please enter your age.');
}
async startSelectionStep(stepContext) {
// Set the user's age to what they entered in response to the age prompt.
stepContext.values[USER_INFO].age = stepContext.result;
if (stepContext.result < 25) {
// If they are too young, skip the review selection dialog, and pass an empty list to the next step.
await stepContext.context.sendActivity('You must be 25 or older to participate.');
return await stepContext.next([]);
} else {
// Otherwise, start the review selection dialog.
return await stepContext.beginDialog(REVIEW_SELECTION_DIALOG);
}
}
async acknowledgementStep(stepContext) {
// Set the user's company selection to what they entered in the review-selection dialog.
const list = stepContext.result || [];
stepContext.values[USER_INFO].companiesToReview = list;
// Thank them for participating.
await stepContext.context.sendActivity(`Thanks for participating, ${stepContext.values[USER_INFO].name}.`);
// Exit the dialog, returning the collected user information.
return await stepContext.endDialog(stepContext.values[USER_INFO]);
}
async selectionStep(stepContext) {
// Continue using the same selection list, if any, from the previous iteration of this dialog.
const list = Array.isArray(stepContext.options) ? stepContext.options : [];
stepContext.values[COMPANIES_SELECTED] = list;
// Create a prompt message.
let message;
if (list.length === 0) {
message = 'Please choose a company to review, or `' + DONE_OPTION + '` to finish.';
} else {
message = `You have selected **${list[0]}**. You can review an addition company, ` +
'or choose `' + DONE_OPTION + '` to finish.';
}
// Create the list of options to choose from.
const options = list.length > 0
? COMPANY_OPTIONS.filter(function (item) { return item !== list[0] })
: COMPANY_OPTIONS.slice();
options.push(DONE_OPTION);
// Prompt the user for a choice.
return await stepContext.prompt(SELECTION_PROMPT, {
prompt: message,
retryPrompt: 'Please choose an option from the list.',
choices: options
});
}
async loopStep(stepContext) {
// Retrieve their selection list, the choice they made, and whether they chose to finish.
const list = stepContext.values[COMPANIES_SELECTED];
const choice = stepContext.result;
const done = choice.value === DONE_OPTION;
if (!done) {
// If they chose a company, add it to the list.
list.push(choice.value);
}
if (done || list.length > 1) {
// If they're done, exit and return their list.
return await stepContext.endDialog(list);
} else {
// Otherwise, repeat this dialog, passing in the list from this iteration.
return await stepContext.replaceDialog(REVIEW_SELECTION_DIALOG, list);
}
}
}
module.exports.MyBot = MyBot;
================================================
FILE: SDKV4-Samples/js/complexDialogBot/deploymentScripts/msbotClone/bot.recipe
================================================
{
"version": "1.0",
"resources": [
{
"type": "endpoint",
"id": "1",
"name": "development",
"url": "http://localhost:3978/api/messages"
},
{
"type": "endpoint",
"id": "2",
"name": "production",
"url": "https://your-bot-url.azurewebsites.net/api/messages"
},
{
"type": "abs",
"id": "3",
"name": "ComplexDialogBot-abs"
},
{
"type": "appInsights",
"id": "4",
"name": "ComplexDialogBot-insights"
},
{
"type": "blob",
"id": "5",
"name": "ComplexDialogBot-blob",
"container": "botstatestore"
}
]
}
================================================
FILE: SDKV4-Samples/js/complexDialogBot/iisnode.yml
================================================
nodeProcessCommandLine: "D:\Program Files (x86)\nodejs\8.9.4\node.exe"
================================================
FILE: SDKV4-Samples/js/complexDialogBot/index.js
================================================
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
const path = require('path');
const restify = require('restify');
// Import required bot services.
// See https://aka.ms/bot-services to learn more about the different parts of a bot.
const { BotFrameworkAdapter, MemoryStorage, UserState, ConversationState } = require('botbuilder');
// Import required bot configuration.
const { BotConfiguration } = require('botframework-config');
// This bot's main dialog.
const { MyBot } = require('./bot');
// Read botFilePath and botFileSecret from .env file
// Note: Ensure you have a .env file and include botFilePath and botFileSecret.
const ENV_FILE = path.join(__dirname, '.env');
const env = require('dotenv').config({path: ENV_FILE});
// bot endpoint name as defined in .bot file
// See https://aka.ms/about-bot-file to learn more about .bot file its use and bot configuration .
const DEV_ENVIRONMENT = 'development';
// bot name as defined in .bot file
// See https://aka.ms/about-bot-file to learn more about .bot file its use and bot configuration.
const BOT_CONFIGURATION = (process.env.NODE_ENV || DEV_ENVIRONMENT);
// Create HTTP server
let server = restify.createServer();
server.listen(process.env.port || process.env.PORT || 3978, function () {
console.log(`\n${server.name} listening to ${server.url}`);
console.log(`\nGet Bot Framework Emulator: https://aka.ms/botframework-emulator`);
console.log(`\nTo talk to your bot, open ComplexDialogBot.bot file in the Emulator`);
});
// .bot file path
const BOT_FILE = path.join(__dirname, (process.env.botFilePath || ''));
// Read bot configuration from .bot file.
let botConfig;
try {
botConfig = BotConfiguration.loadSync(BOT_FILE, process.env.botFileSecret);
} catch (err) {
console.error(`\nError reading bot file. Please ensure you have valid botFilePath and botFileSecret set for your environment.`);
console.error(`\n - The botFileSecret is available under appsettings for your Azure Bot Service bot.`);
console.error(`\n - If you are running this bot locally, consider adding a .env file with botFilePath and botFileSecret.\n\n`);
process.exit();
}
// Get bot endpoint configuration by service name
const endpointConfig = botConfig.findServiceByNameOrId(BOT_CONFIGURATION);
// Create adapter.
// See https://aka.ms/about-bot-adapter to learn more about .bot file its use and bot configuration .
const adapter = new BotFrameworkAdapter({
appId: endpointConfig.appId || process.env.microsoftAppID,
appPassword: endpointConfig.appPassword || process.env.microsoftAppPassword
});
// Define state store for your bot.
// See https://aka.ms/about-bot-state to learn more about bot state.
const memoryStorage = new MemoryStorage();
// Create user and conversation state with in-memory storage provider.
const userState = new UserState(memoryStorage);
const conversationState = new ConversationState(memoryStorage);
// Create the main dialog.
const myBot = new MyBot(conversationState, userState);
// Catch-all for errors.
adapter.onTurnError = async (context, error) => {
// This check writes out errors to console log .vs. app insights.
console.error(`\n [onTurnError]: ${error}`);
// Send a message to the user
context.sendActivity(`Oops. Something went wrong!`);
// Clear out state
await conversationState.load(context);
await conversationState.clear(context);
// Save state changes.
await conversationState.saveChanges(context);
};
// Listen for incoming requests.
server.post('/api/messages', (req, res) => {
adapter.processActivity(req, res, async (context) => {
// Route to main dialog.
await myBot.onTurn(context);
});
});
================================================
FILE: SDKV4-Samples/js/complexDialogBot/package.json
================================================
{
"name": "ComplexDialogBot",
"version": "1.0.0",
"description": "Sample code for the how to topic for creating advanced conversation flow",
"author": "Microsoft Bot Builder Yeoman Generator v4.0.10",
"license": "MIT",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "echo \"Error: no build specified\" && exit 1",
"start": "node ./index.js",
"watch": "nodemon ./index.js"
},
"dependencies": {
"botbuilder": "^4.0.6",
"botbuilder-dialogs": "^4.2.0-preview.2251",
"botframework-config": "^4.0.6",
"dotenv": "^6.0.0",
"restify": "^6.3.4"
},
"devDependencies": {
"eslint": "^5.6.0",
"eslint-config-standard": "^12.0.0",
"eslint-plugin-import": "^2.14.0",
"eslint-plugin-node": "^7.0.1",
"eslint-plugin-promise": "^4.0.1",
"eslint-plugin-standard": "^4.0.0",
"nodemon": "^1.18.4",
"@types/node": "10.10.2",
"@types/restify": "7.2.4"
}
}
================================================
FILE: SDKV4-Samples/js/complexDialogBot/web.config
================================================
================================================
FILE: SDKV4-Samples/js/nlp-with-dispatch/QnAMaker.tsv
================================================
Question Answer Source Metadata
hi Hello! QnAMaker.tsv
greetings Hello! QnAMaker.tsv
good morning Hello! QnAMaker.tsv
good evening Hello! QnAMaker.tsv
What are you? I am the LUIS-QnAMaker Dispatch bot! This sample demonstrates using several LUIS applications and QnA Maker knowledge base using dispatch. QnAMaker.tsv
What? I am the LUIS-QnAMaker Dispatch bot! This sample demonstrates using several LUIS applications and QnA Maker knowledge base using dispatch. QnAMaker.tsv
What do you do? I am the LUIS-QnAMaker Dispatch bot! This sample demonstrates using several LUIS applications and QnA Maker knowledge base using dispatch. QnAMaker.tsv
Who are you? I am the LUIS-QnAMaker Dispatch bot! This sample demonstrates using several LUIS applications and QnA Maker knowledge base using dispatch. QnAMaker.tsv
What is your name? I am the LUIS-QnAMaker Dispatch bot! This sample demonstrates using several LUIS applications and QnA Maker knowledge base using dispatch. QnAMaker.tsv
What should I call you? I am the LUIS-QnAMaker Dispatch bot! This sample demonstrates using several LUIS applications and QnA Maker knowledge base using dispatch. QnAMaker.tsv
================================================
FILE: SDKV4-Samples/js/nlp-with-dispatch/home-automation.json
================================================
{
"name": "Home Automation",
"versionId": "0.1",
"desc": "Home Automation LUIS application - Bot Builder Samples",
"culture": "en-us",
"intents": [
{
"name": "HomeAutomation"
},
{
"name": "None"
}
],
"entities": [
{
"name": "Device",
"roles": []
},
{
"name": "deviceProperty",
"roles": []
},
{
"name": "Room",
"roles": []
}
],
"closedLists": [
{
"name": "Operation",
"subLists": [
{
"canonicalForm": "off",
"list": [
"off",
"turn off",
"switch off",
"lock",
"out",
"shut down",
"stop"
]
},
{
"canonicalForm": "on",
"list": [
"on",
"turn on",
"switch on",
"unlock",
"un lock",
"boot up",
"start"
]
}
],
"roles": []
}
],
"composites": [],
"patternAnyEntities": [
{
"name": "Device_PatternAny",
"explicitList": [],
"roles": []
},
{
"name": "Room_PatternAny",
"explicitList": [],
"roles": []
}
],
"regex_entities": [],
"prebuiltEntities": [
{
"name": "number",
"roles": []
}
],
"regex_features": [],
"model_features": [],
"patterns": [
{
"pattern": "turn off {Device_PatternAny} in {Room_PatternAny}",
"intent": "HomeAutomation"
},
{
"pattern": "{Device_PatternAny} off [please]",
"intent": "HomeAutomation"
},
{
"pattern": "turn on {Device_PatternAny}",
"intent": "HomeAutomation"
},
{
"pattern": "{Device_PatternAny} on [please]",
"intent": "HomeAutomation"
},
{
"pattern": "turn on {Device_PatternAny} in {Room_PatternAny}",
"intent": "HomeAutomation"
},
{
"pattern": "{Device_PatternAny} in {Room_PatternAny} on [please]",
"intent": "HomeAutomation"
},
{
"pattern": "{Device_PatternAny} in {Room_PatternAny} off [please]",
"intent": "HomeAutomation"
}
],
"utterances": [
{
"text": "breezeway on please",
"intent": "HomeAutomation",
"entities": [
{
"startPos": 0,
"endPos": 8,
"entity": "Room"
}
]
},
{
"text": "change temperature to seventy two degrees",
"intent": "HomeAutomation",
"entities": [
{
"startPos": 7,
"endPos": 17,
"entity": "deviceProperty"
}
]
},
{
"text": "coffee bar on please",
"intent": "HomeAutomation",
"entities": [
{
"startPos": 0,
"endPos": 9,
"entity": "Device"
}
]
},
{
"text": "decrease temperature for me please",
"intent": "None",
"entities": [
{
"startPos": 9,
"endPos": 19,
"entity": "deviceProperty"
}
]
},
{
"text": "dim kitchen lights to 25 .",
"intent": "None",
"entities": [
{
"startPos": 4,
"endPos": 10,
"entity": "Room"
},
{
"startPos": 12,
"endPos": 17,
"entity": "Device"
}
]
},
{
"text": "fish pond off please",
"intent": "HomeAutomation",
"entities": [
{
"startPos": 0,
"endPos": 8,
"entity": "Device"
}
]
},
{
"text": "fish pond on please",
"intent": "HomeAutomation",
"entities": [
{
"startPos": 0,
"endPos": 8,
"entity": "Device"
}
]
},
{
"text": "illuminate please",
"intent": "HomeAutomation",
"entities": [
{
"startPos": 0,
"endPos": 9,
"entity": "Device"
}
]
},
{
"text": "living room lamp on please",
"intent": "HomeAutomation",
"entities": [
{
"startPos": 0,
"endPos": 10,
"entity": "Room"
},
{
"startPos": 12,
"endPos": 15,
"entity": "Device"
}
]
},
{
"text": "living room lamps off please",
"intent": "HomeAutomation",
"entities": [
{
"startPos": 0,
"endPos": 10,
"entity": "Room"
},
{
"startPos": 12,
"endPos": 16,
"entity": "Device"
}
]
},
{
"text": "lock the doors for me please",
"intent": "HomeAutomation",
"entities": [
{
"startPos": 9,
"endPos": 13,
"entity": "Device"
}
]
},
{
"text": "lower your volume",
"intent": "None",
"entities": [
{
"startPos": 11,
"endPos": 16,
"entity": "deviceProperty"
}
]
},
{
"text": "make camera 1 off please",
"intent": "HomeAutomation",
"entities": [
{
"startPos": 5,
"endPos": 12,
"entity": "Device"
}
]
},
{
"text": "make some coffee",
"intent": "HomeAutomation",
"entities": [
{
"startPos": 10,
"endPos": 15,
"entity": "Device"
}
]
},
{
"text": "play dvd",
"intent": "HomeAutomation",
"entities": [
{
"startPos": 5,
"endPos": 7,
"entity": "Device"
}
]
},
{
"text": "set lights out in bedroom",
"intent": "HomeAutomation",
"entities": [
{
"startPos": 4,
"endPos": 9,
"entity": "Device"
},
{
"startPos": 18,
"endPos": 24,
"entity": "Room"
}
]
},
{
"text": "set lights to bright",
"intent": "HomeAutomation",
"entities": [
{
"startPos": 4,
"endPos": 9,
"entity": "Device"
},
{
"startPos": 14,
"endPos": 19,
"entity": "deviceProperty"
}
]
},
{
"text": "set lights to concentrate",
"intent": "HomeAutomation",
"entities": [
{
"startPos": 4,
"endPos": 9,
"entity": "Device"
},
{
"startPos": 14,
"endPos": 24,
"entity": "deviceProperty"
}
]
},
{
"text": "shut down my work computer",
"intent": "HomeAutomation",
"entities": [
{
"startPos": 18,
"endPos": 25,
"entity": "Device"
}
]
},
{
"text": "snap switch fan fifty percent",
"intent": "HomeAutomation",
"entities": [
{
"startPos": 12,
"endPos": 14,
"entity": "Device"
}
]
},
{
"text": "start master bedroom light.",
"intent": "HomeAutomation",
"entities": [
{
"startPos": 6,
"endPos": 19,
"entity": "Room"
},
{
"startPos": 21,
"endPos": 25,
"entity": "Device"
}
]
},
{
"text": "theater on please",
"intent": "HomeAutomation",
"entities": [
{
"startPos": 0,
"endPos": 6,
"entity": "Room"
}
]
},
{
"text": "turn dimmer off",
"intent": "HomeAutomation",
"entities": [
{
"startPos": 5,
"endPos": 10,
"entity": "Device"
}
]
},
{
"text": "turn off ac please",
"intent": "HomeAutomation",
"entities": [
{
"startPos": 9,
"endPos": 10,
"entity": "Device"
}
]
},
{
"text": "turn off foyer lights",
"intent": "HomeAutomation",
"entities": [
{
"startPos": 9,
"endPos": 13,
"entity": "Room"
},
{
"startPos": 15,
"endPos": 20,
"entity": "Device"
}
]
},
{
"text": "turn off living room light",
"intent": "HomeAutomation",
"entities": [
{
"startPos": 9,
"endPos": 19,
"entity": "Room"
},
{
"startPos": 21,
"endPos": 25,
"entity": "Device"
}
]
},
{
"text": "turn off staircase",
"intent": "HomeAutomation",
"entities": [
{
"startPos": 9,
"endPos": 17,
"entity": "Device"
}
]
},
{
"text": "turn off venice lamp",
"intent": "HomeAutomation",
"entities": [
{
"startPos": 16,
"endPos": 19,
"entity": "Device"
}
]
},
{
"text": "turn on bathroom heater",
"intent": "HomeAutomation",
"entities": [
{
"startPos": 8,
"endPos": 15,
"entity": "Room"
},
{
"startPos": 17,
"endPos": 22,
"entity": "Device"
}
]
},
{
"text": "turn on external speaker",
"intent": "HomeAutomation",
"entities": [
{
"startPos": 8,
"endPos": 23,
"entity": "Device"
}
]
},
{
"text": "turn on kitchen faucet",
"intent": "HomeAutomation",
"entities": [
{
"startPos": 8,
"endPos": 14,
"entity": "Room"
},
{
"startPos": 16,
"endPos": 21,
"entity": "Device"
}
]
},
{
"text": "turn on light in bedroom",
"intent": "HomeAutomation",
"entities": [
{
"startPos": 8,
"endPos": 12,
"entity": "Device"
},
{
"startPos": 17,
"endPos": 23,
"entity": "Room"
}
]
},
{
"text": "turn on my bedroom lights.",
"intent": "HomeAutomation",
"entities": [
{
"startPos": 11,
"endPos": 17,
"entity": "Room"
},
{
"startPos": 19,
"endPos": 24,
"entity": "Device"
}
]
},
{
"text": "turn on the furnace room lights",
"intent": "HomeAutomation",
"entities": [
{
"startPos": 12,
"endPos": 23,
"entity": "Room"
},
{
"startPos": 25,
"endPos": 30,
"entity": "Device"
}
]
},
{
"text": "turn on the internet in my bedroom please",
"intent": "None",
"entities": [
{
"startPos": 27,
"endPos": 33,
"entity": "Room"
}
]
},
{
"text": "turn on thermostat please",
"intent": "HomeAutomation",
"entities": [
{
"startPos": 8,
"endPos": 17,
"entity": "Device"
}
]
},
{
"text": "turn the fan to high",
"intent": "HomeAutomation",
"entities": [
{
"startPos": 9,
"endPos": 11,
"entity": "Device"
}
]
},
{
"text": "turn thermostat on 70.",
"intent": "HomeAutomation",
"entities": [
{
"startPos": 5,
"endPos": 14,
"entity": "Device"
}
]
}
]
}
================================================
FILE: SDKV4-Samples/js/nlp-with-dispatch/nlp-with-dispatchDispatch.json
================================================
{
"name": "nlp-with-dispatchDispatch",
"versionId": "Dispatch",
"desc": "Dispatch model for nlp-with-dispatchDispatch",
"culture": "en-us",
"intents": [
{
"name": "l_Home Automation"
},
{
"name": "l_Weather"
},
{
"name": "None"
},
{
"name": "q_sample-qna"
}
],
"entities": [],
"closedLists": [],
"composites": [],
"patternAnyEntities": [],
"regex_entities": [],
"prebuiltEntities": [],
"regex_features": [],
"model_features": [],
"patterns": [],
"utterances": [
{
"text": "breezeway on please",
"intent": "l_Home Automation",
"entities": []
},
{
"text": "change temperature to seventy two degrees",
"intent": "l_Home Automation",
"entities": []
},
{
"text": "coffee bar on please",
"intent": "l_Home Automation",
"entities": []
},
{
"text": "current weather ?",
"intent": "l_Weather",
"entities": []
},
{
"text": "decrease temperature for me please",
"intent": "None",
"entities": []
},
{
"text": "dim kitchen lights to 25 .",
"intent": "None",
"entities": []
},
{
"text": "do florida residents usually need ice scrapers",
"intent": "l_Weather",
"entities": []
},
{
"text": "fish pond off please",
"intent": "l_Home Automation",
"entities": []
},
{
"text": "fish pond on please",
"intent": "l_Home Automation",
"entities": []
},
{
"text": "forecast in celcius",
"intent": "l_Weather",
"entities": []
},
{
"text": "get florence temperature in september",
"intent": "l_Weather",
"entities": []
},
{
"text": "get for me the weather conditions in sonoma county",
"intent": "l_Weather",
"entities": []
},
{
"text": "get the daily temperature greenwood indiana",
"intent": "l_Weather",
"entities": []
},
{
"text": "get the forcast for me",
"intent": "l_Weather",
"entities": []
},
{
"text": "get the weather at saint george utah",
"intent": "l_Weather",
"entities": []
},
{
"text": "good evening",
"intent": "q_sample-qna",
"entities": []
},
{
"text": "good morning",
"intent": "q_sample-qna",
"entities": []
},
{
"text": "greetings",
"intent": "q_sample-qna",
"entities": []
},
{
"text": "hi",
"intent": "q_sample-qna",
"entities": []
},
{
"text": "how much rain does chambersburg get a year",
"intent": "l_Weather",
"entities": []
},
{
"text": "i want to know the temperature at death valley",
"intent": "l_Weather",
"entities": []
},
{
"text": "illuminate please",
"intent": "l_Home Automation",
"entities": []
},
{
"text": "living room lamp on please",
"intent": "l_Home Automation",
"entities": []
},
{
"text": "living room lamps off please",
"intent": "l_Home Automation",
"entities": []
},
{
"text": "lock the doors for me please",
"intent": "l_Home Automation",
"entities": []
},
{
"text": "lower your volume",
"intent": "None",
"entities": []
},
{
"text": "make camera 1 off please",
"intent": "l_Home Automation",
"entities": []
},
{
"text": "make some coffee",
"intent": "l_Home Automation",
"entities": []
},
{
"text": "play dvd",
"intent": "l_Home Automation",
"entities": []
},
{
"text": "provide me by toronto weather please",
"intent": "l_Weather",
"entities": []
},
{
"text": "set lights out in bedroom",
"intent": "l_Home Automation",
"entities": []
},
{
"text": "set lights to bright",
"intent": "l_Home Automation",
"entities": []
},
{
"text": "set lights to concentrate",
"intent": "l_Home Automation",
"entities": []
},
{
"text": "show average rainfall for boise",
"intent": "l_Weather",
"entities": []
},
{
"text": "show me the forecast at alabama",
"intent": "l_Weather",
"entities": []
},
{
"text": "shut down my work computer",
"intent": "l_Home Automation",
"entities": []
},
{
"text": "snap switch fan fifty percent",
"intent": "l_Home Automation",
"entities": []
},
{
"text": "soliciting today's weather",
"intent": "l_Weather",
"entities": []
},
{
"text": "start master bedroom light.",
"intent": "l_Home Automation",
"entities": []
},
{
"text": "temperature of delhi in celsius please",
"intent": "l_Weather",
"entities": []
},
{
"text": "theater on please",
"intent": "l_Home Automation",
"entities": []
},
{
"text": "turn dimmer off",
"intent": "l_Home Automation",
"entities": []
},
{
"text": "turn off ac please",
"intent": "l_Home Automation",
"entities": []
},
{
"text": "turn off foyer lights",
"intent": "l_Home Automation",
"entities": []
},
{
"text": "turn off living room light",
"intent": "l_Home Automation",
"entities": []
},
{
"text": "turn off staircase",
"intent": "l_Home Automation",
"entities": []
},
{
"text": "turn off venice lamp",
"intent": "l_Home Automation",
"entities": []
},
{
"text": "turn on bathroom heater",
"intent": "l_Home Automation",
"entities": []
},
{
"text": "turn on external speaker",
"intent": "l_Home Automation",
"entities": []
},
{
"text": "turn on kitchen faucet",
"intent": "l_Home Automation",
"entities": []
},
{
"text": "turn on light in bedroom",
"intent": "l_Home Automation",
"entities": []
},
{
"text": "turn on my bedroom lights.",
"intent": "l_Home Automation",
"entities": []
},
{
"text": "turn on the furnace room lights",
"intent": "l_Home Automation",
"entities": []
},
{
"text": "turn on the internet in my bedroom please",
"intent": "None",
"entities": []
},
{
"text": "turn on thermostat please",
"intent": "l_Home Automation",
"entities": []
},
{
"text": "turn the fan to high",
"intent": "l_Home Automation",
"entities": []
},
{
"text": "turn thermostat on 70.",
"intent": "l_Home Automation",
"entities": []
},
{
"text": "was last year about this time as wet as it is now in the south ?",
"intent": "l_Weather",
"entities": []
},
{
"text": "what are you?",
"intent": "q_sample-qna",
"entities": []
},
{
"text": "what do you do?",
"intent": "q_sample-qna",
"entities": []
},
{
"text": "what is the rain volume in sonoma county ?",
"intent": "l_Weather",
"entities": []
},
{
"text": "what is the weather in redmond ?",
"intent": "l_Weather",
"entities": []
},
{
"text": "what is the weather today at 10 day durham ?",
"intent": "l_Weather",
"entities": []
},
{
"text": "what is your name?",
"intent": "q_sample-qna",
"entities": []
},
{
"text": "what should i call you?",
"intent": "q_sample-qna",
"entities": []
},
{
"text": "what to wear in march in california",
"intent": "l_Weather",
"entities": []
},
{
"text": "what will the weather be tomorrow in new york ?",
"intent": "l_Weather",
"entities": []
},
{
"text": "what?",
"intent": "q_sample-qna",
"entities": []
},
{
"text": "what's the weather going to be like in hawaii ?",
"intent": "l_Weather",
"entities": []
},
{
"text": "what's the weather like in minneapolis",
"intent": "l_Weather",
"entities": []
},
{
"text": "who are you?",
"intent": "q_sample-qna",
"entities": []
},
{
"text": "will it be raining in ranchi",
"intent": "l_Weather",
"entities": []
},
{
"text": "will it rain this weekend",
"intent": "l_Weather",
"entities": []
},
{
"text": "will it snow today",
"intent": "l_Weather",
"entities": []
}
]
}
================================================
FILE: SDKV4-Samples/js/nlp-with-dispatch/weather.json
================================================
{
"name": "Weather",
"versionId": "0.1",
"desc": "Weather LUIS application - Bot Builder Samples",
"culture": "en-us",
"intents": [
{
"name": "Get Weather Condition"
},
{
"name": "Get Weather Forecast"
},
{
"name": "None"
}
],
"entities": [
{
"name": "Location",
"roles": []
}
],
"closedLists": [],
"composites": [],
"patternAnyEntities": [
{
"name": "Location_PatternAny",
"explicitList": [],
"roles": []
}
],
"regex_entities": [],
"prebuiltEntities": [],
"regex_features": [],
"model_features": [],
"patterns": [
{
"pattern": "weather in {Location_PatternAny}",
"intent": "Get Weather Condition"
},
{
"pattern": "how's the weather in {Location_PatternAny}",
"intent": "Get Weather Condition"
},
{
"pattern": "current weather in {Location_PatternAny}",
"intent": "Get Weather Condition"
},
{
"pattern": "what's the forecast for next week in {Location_PatternAny}",
"intent": "Get Weather Forecast"
},
{
"pattern": "show me the forecast for {Location_PatternAny}",
"intent": "Get Weather Forecast"
},
{
"pattern": "what's the forecast for {Location_PatternAny}",
"intent": "Get Weather Forecast"
}
],
"utterances": [
{
"text": "current weather ?",
"intent": "Get Weather Condition",
"entities": []
},
{
"text": "do florida residents usually need ice scrapers",
"intent": "Get Weather Condition",
"entities": [
{
"startPos": 3,
"endPos": 9,
"entity": "Location"
}
]
},
{
"text": "forecast in celcius",
"intent": "Get Weather Forecast",
"entities": []
},
{
"text": "get florence temperature in september",
"intent": "Get Weather Condition",
"entities": [
{
"startPos": 4,
"endPos": 11,
"entity": "Location"
}
]
},
{
"text": "get for me the weather conditions in sonoma county",
"intent": "Get Weather Condition",
"entities": [
{
"startPos": 37,
"endPos": 49,
"entity": "Location"
}
]
},
{
"text": "get the daily temperature greenwood indiana",
"intent": "Get Weather Condition",
"entities": [
{
"startPos": 26,
"endPos": 42,
"entity": "Location"
}
]
},
{
"text": "get the forcast for me",
"intent": "Get Weather Forecast",
"entities": []
},
{
"text": "get the weather at saint george utah",
"intent": "Get Weather Condition",
"entities": [
{
"startPos": 19,
"endPos": 35,
"entity": "Location"
}
]
},
{
"text": "how much rain does chambersburg get a year",
"intent": "Get Weather Condition",
"entities": [
{
"startPos": 19,
"endPos": 30,
"entity": "Location"
}
]
},
{
"text": "i want to know the temperature at death valley",
"intent": "Get Weather Forecast",
"entities": [
{
"startPos": 34,
"endPos": 45,
"entity": "Location"
}
]
},
{
"text": "provide me by toronto weather please",
"intent": "Get Weather Forecast",
"entities": [
{
"startPos": 14,
"endPos": 20,
"entity": "Location"
}
]
},
{
"text": "show average rainfall for boise",
"intent": "Get Weather Condition",
"entities": [
{
"startPos": 26,
"endPos": 30,
"entity": "Location"
}
]
},
{
"text": "show me the forecast at alabama",
"intent": "Get Weather Forecast",
"entities": [
{
"startPos": 24,
"endPos": 30,
"entity": "Location"
}
]
},
{
"text": "soliciting today's weather",
"intent": "Get Weather Forecast",
"entities": []
},
{
"text": "temperature of delhi in celsius please",
"intent": "Get Weather Condition",
"entities": [
{
"startPos": 15,
"endPos": 19,
"entity": "Location"
}
]
},
{
"text": "was last year about this time as wet as it is now in the south ?",
"intent": "Get Weather Condition",
"entities": [
{
"startPos": 57,
"endPos": 61,
"entity": "Location"
}
]
},
{
"text": "what is the rain volume in sonoma county ?",
"intent": "Get Weather Condition",
"entities": [
{
"startPos": 27,
"endPos": 39,
"entity": "Location"
}
]
},
{
"text": "what is the weather in redmond ?",
"intent": "Get Weather Forecast",
"entities": [
{
"startPos": 23,
"endPos": 29,
"entity": "Location"
}
]
},
{
"text": "what is the weather today at 10 day durham ?",
"intent": "Get Weather Forecast",
"entities": [
{
"startPos": 36,
"endPos": 41,
"entity": "Location"
}
]
},
{
"text": "what to wear in march in california",
"intent": "Get Weather Condition",
"entities": [
{
"startPos": 25,
"endPos": 34,
"entity": "Location"
}
]
},
{
"text": "what will the weather be tomorrow in new york ?",
"intent": "Get Weather Forecast",
"entities": [
{
"startPos": 37,
"endPos": 44,
"entity": "Location"
}
]
},
{
"text": "what's the weather going to be like in hawaii ?",
"intent": "Get Weather Forecast",
"entities": [
{
"startPos": 39,
"endPos": 44,
"entity": "Location"
}
]
},
{
"text": "what's the weather like in minneapolis",
"intent": "Get Weather Condition",
"entities": [
{
"startPos": 27,
"endPos": 37,
"entity": "Location"
}
]
},
{
"text": "will it be raining in ranchi",
"intent": "Get Weather Forecast",
"entities": [
{
"startPos": 22,
"endPos": 27,
"entity": "Location"
}
]
},
{
"text": "will it rain this weekend",
"intent": "Get Weather Forecast",
"entities": []
},
{
"text": "will it snow today",
"intent": "Get Weather Forecast",
"entities": []
}
]
}
================================================
FILE: SDKV4-Samples/js/nlp-with-luis/reminders-with-entities.json
================================================
{
"intents": [
{
"name": "Calendar_Add"
},
{
"name": "Calendar_Find"
},
{
"name": "None"
}
],
"entities": [
{
"name": "Appointment",
"roles": []
},
{
"name": "Meeting",
"roles": []
},
{
"name": "Schedule",
"roles": []
}
],
"composites": [],
"closedLists": [],
"patternAnyEntities": [],
"regex_entities": [],
"prebuiltEntities": [],
"model_features": [],
"regex_features": [],
"patterns": [],
"utterances": [
{
"text": "add a new event on 27 - apr",
"intent": "Calendar_Add",
"entities": []
},
{
"text": "add a new task finish assignment",
"intent": "Calendar_Add",
"entities": []
},
{
"text": "add an event to read about adam lambert news",
"intent": "Calendar_Add",
"entities": []
},
{
"text": "add an event to visit 209 nashville gym",
"intent": "Calendar_Add",
"entities": []
},
{
"text": "add date to my schedule",
"intent": "Calendar_Add",
"entities": [
{
"entity": "Schedule",
"startPos": 15,
"endPos": 22
}
]
},
{
"text": "add imax theater to my upcoming events",
"intent": "Calendar_Add",
"entities": []
},
{
"text": "am i free to be with friends saturday ?",
"intent": "None",
"entities": []
},
{
"text": "appointment with johnson needs to be next week",
"intent": "None",
"entities": [
{
"entity": "Appointment",
"startPos": 0,
"endPos": 10
}
]
},
{
"text": "calendar for november 1948",
"intent": "Calendar_Find",
"entities": []
},
{
"text": "calendar i ' ll be at the garage from 8 till 3 this saturday",
"intent": "Calendar_Add",
"entities": []
},
{
"text": "call dad mike",
"intent": "None",
"entities": []
},
{
"text": "change the meeting with chris to 9 : 00 am",
"intent": "None",
"entities": []
},
{
"text": "display weekend plans",
"intent": "Calendar_Find",
"entities": []
},
{
"text": "do i have anything on wednesday ?",
"intent": "Calendar_Find",
"entities": []
},
{
"text": "dunmore pa sonic sounds friday morning please",
"intent": "Calendar_Add",
"entities": []
},
{
"text": "email cloney john",
"intent": "None",
"entities": []
},
{
"text": "extend lunch meeting 30 minutes extra",
"intent": "None",
"entities": [
{
"entity": "Meeting",
"startPos": 13,
"endPos": 19
}
]
},
{
"text": "how many days are there between march 13th 2015 and today ?",
"intent": "Calendar_Find",
"entities": []
},
{
"text": "i want to reschedule the meeting at the air force club",
"intent": "None",
"entities": []
},
{
"text": "marketing meetings on tuesdays will now be every wednesday please change on my calendar",
"intent": "None",
"entities": []
},
{
"text": "meet my manager",
"intent": "Calendar_Add",
"entities": []
},
{
"text": "meeting my manager",
"intent": "Calendar_Add",
"entities": []
},
{
"text": "move the bbq party to friday",
"intent": "None",
"entities": []
},
{
"text": "pull up my appointment find out how much time i have before my next appointment",
"intent": "Calendar_Find",
"entities": [
{
"entity": "Appointment",
"startPos": 11,
"endPos": 21
}
]
},
{
"text": "save the date may 17 pictures party",
"intent": "Calendar_Add",
"entities": []
},
{
"text": "schedule a conference call for tomorrow",
"intent": "Calendar_Add",
"entities": [
{
"entity": "Schedule",
"startPos": 0,
"endPos": 7
}
]
},
{
"text": "schedule a meeting for tomorrow",
"intent": "Calendar_Add",
"entities": [
{
"entity": "Meeting",
"startPos": 11,
"endPos": 17
}
]
},
{
"text": "schedule appointment for tomorrow please",
"intent": "Calendar_Add",
"entities": [
{
"entity": "Schedule",
"startPos": 0,
"endPos": 7
},
{
"entity": "Appointment",
"startPos": 9,
"endPos": 19
}
]
},
{
"text": "search for meetings with chris",
"intent": "Calendar_Find",
"entities": [
{
"entity": "Meeting",
"startPos": 11,
"endPos": 18
}
]
},
{
"text": "show me tomorrow ' s wedding party time",
"intent": "Calendar_Find",
"entities": []
},
{
"text": "show my schedule for tomorrow",
"intent": "Calendar_Find",
"entities": [
{
"entity": "Schedule",
"startPos": 8,
"endPos": 15
}
]
},
{
"text": "tell me the event details",
"intent": "Calendar_Find",
"entities": []
},
{
"text": "the meeting will last for one hour",
"intent": "Calendar_Add",
"entities": [
{
"entity": "Meeting",
"startPos": 4,
"endPos": 10
}
]
},
{
"text": "the workshop will last for 10 hours",
"intent": "None",
"entities": []
},
{
"text": "voice activated reading of appointments this week",
"intent": "Calendar_Find",
"entities": [
{
"entity": "Appointment",
"startPos": 27,
"endPos": 38
}
]
}
],
"settings": []
}
================================================
FILE: SDKV4-Samples/js/stateBot/.eslintrc.js
================================================
module.exports = {
"extends": "standard",
"rules": {
"semi": [2, "always"],
"indent": [2, 4],
"no-return-await": 0,
"space-before-function-paren": [2, {
"named": "never",
"anonymous": "never",
"asyncArrow": "always"
}],
"template-curly-spacing": [2, "always"]
}
};
================================================
FILE: SDKV4-Samples/js/stateBot/.gitignore
================================================
node_modules
.env
================================================
FILE: SDKV4-Samples/js/stateBot/README.md
================================================
# Save user and conversation data
This sample demonstrates how to save user and conversation data in a Node.js bot.
The bot maintains conversation state to track and direct the conversation and ask the user questions.
The bot maintains user state to track the user's answers.
# To run the bot
- Install modules and start the bot
```bash
npm i & npm start
```
Alternatively you can also use nodemon via
```bash
npm i & npm run watch
```
# Testing the bot using Bot Framework Emulator
[Microsoft Bot Framework Emulator][2] is a desktop application that allows bot developers to test and debug their bots on localhost or running remotely through a tunnel.
- Install the Bot Framework emulator from [here][3]
## Connect to bot using Bot Framework Emulator **V4**
- Launch Bot Framework Emulator
- File -> Open Bot Configuration
- Select `stateBot.bot` file
# Further reading
- [Azure Bot Service Introduction][6]
- [Bot State][7]
- [Write directly to storage][8]
- [Managing conversation and user state][9]
[1]: https://www.npmjs.com/package/restify
[2]: https://github.com/microsoft/botframework-emulator
[3]: https://aka.ms/botframework-emulator
[4]: https://docs.microsoft.com/azure/bot-service/bot-builder-howto-v4-state?tabs=js
[5]: https://github.com/microsoft/botbuilder-tools
[6]: https://docs.microsoft.com/azure/bot-service/bot-service-overview-introduction
[7]: https://docs.microsoft.com/azure/bot-service/bot-builder-storage-concept
[8]: https://docs.microsoft.com/azure/bot-service/bot-builder-howto-v4-storage?tabs=js
[9]: https://docs.microsoft.com/azure/bot-service/bot-builder-howto-v4-state?tabs=js
[10] https://dev.botframework.com
================================================
FILE: SDKV4-Samples/js/stateBot/bot.js
================================================
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
const { ActivityTypes } = require('botbuilder');
// The accessor names for the conversation data and user profile state property accessors.
const CONVERSATION_DATA_PROPERTY = 'conversationData';
const USER_PROFILE_PROPERTY = 'userProfile';
class MyBot {
/**
*
* @param {ConversationState} conversation state object
*/
constructor(conversationState, userState) {
// Create the state property accessors for the conversation data and user profile.
this.conversationData = conversationState.createProperty(CONVERSATION_DATA_PROPERTY);
this.userProfile = userState.createProperty(USER_PROFILE_PROPERTY);
// The state management objects for the conversation and user state.
this.conversationState = conversationState;
this.userState = userState;
}
/**
*
* @param {TurnContext} on turn context object.
*/
async onTurn(turnContext) {
// See https://aka.ms/about-bot-activity-message to learn more about the message and other activity types.
if (turnContext.activity.type === ActivityTypes.Message) {
// Get the state properties from the turn context.
const userProfile = await this.userProfile.get(turnContext, {});
const conversationData = await this.conversationData.get(
turnContext, { promptedForUserName: false });
if (!userProfile.name) {
// First time around this is undefined, so we will prompt user for name.
if (conversationData.promptedForUserName) {
// Set the name to what the user provided.
userProfile.name = turnContext.activity.text;
// Acknowledge that we got their name.
await turnContext.sendActivity(`Thanks ${userProfile.name}.`);
// Reset the flag to allow the bot to go though the cycle again.
conversationData.promptedForUserName = false;
} else {
// Prompt the user for their name.
await turnContext.sendActivity('What is your name?');
// Set the flag to true, so we don't prompt in the next turn.
conversationData.promptedForUserName = true;
}
// Save user state and save changes.
await this.userProfile.set(turnContext, userProfile);
await this.userState.saveChanges(turnContext);
} else {
// Add message details to the conversation data.
conversationData.timestamp = turnContext.activity.timestamp.toLocaleString();
conversationData.channelId = turnContext.activity.channelId;
// Display state data.
await turnContext.sendActivity(`${userProfile.name} sent: ${turnContext.activity.text}`);
await turnContext.sendActivity(`Message received at: ${conversationData.timestamp}`);
await turnContext.sendActivity(`Message received from: ${conversationData.channelId}`);
}
// Update conversation state and save changes.
await this.conversationData.set(turnContext, conversationData);
await this.conversationState.saveChanges(turnContext);
}
}
}
module.exports.MyBot = MyBot;
================================================
FILE: SDKV4-Samples/js/stateBot/deploymentScripts/msbotClone/bot.recipe
================================================
{
"version": "1.0",
"resources": [
{
"type": "endpoint",
"id": "1",
"name": "development",
"url": "http://localhost:3978/api/messages"
},
{
"type": "endpoint",
"id": "2",
"name": "production",
"url": "https://your-bot-url.azurewebsites.net/api/messages"
},
{
"type": "abs",
"id": "3",
"name": "stateBot-abs"
},
{
"type": "appInsights",
"id": "4",
"name": "stateBot-insights"
},
{
"type": "blob",
"id": "5",
"name": "stateBot-blob",
"container": "botstatestore"
}
]
}
================================================
FILE: SDKV4-Samples/js/stateBot/index.js
================================================
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
const path = require('path');
const restify = require('restify');
// Import required bot services.
// See https://aka.ms/bot-services to learn more about the different parts of a bot.
const { BotFrameworkAdapter, MemoryStorage, ConversationState, UserState } = require('botbuilder');
// Import required bot configuration.
const { BotConfiguration } = require('botframework-config');
// This bot's main dialog.
const { MyBot } = require('./bot');
// Read botFilePath and botFileSecret from .env file
// Note: Ensure you have a .env file and include botFilePath and botFileSecret.
const ENV_FILE = path.join(__dirname, '.env');
const env = require('dotenv').config({path: ENV_FILE});
// bot endpoint name as defined in .bot file
// See https://aka.ms/about-bot-file to learn more about .bot file its use and bot configuration .
const DEV_ENVIRONMENT = 'development';
// bot name as defined in .bot file
// See https://aka.ms/about-bot-file to learn more about .bot file its use and bot configuration.
const BOT_CONFIGURATION = (process.env.NODE_ENV || DEV_ENVIRONMENT);
// Create HTTP server
let server = restify.createServer();
server.listen(process.env.port || process.env.PORT || 3978, function () {
console.log(`\n${server.name} listening to ${server.url}`);
console.log(`\nGet Bot Framework Emulator: https://aka.ms/botframework-emulator`);
console.log(`\nTo talk to your bot, open stateBot.bot file in the Emulator`);
});
// .bot file path
const BOT_FILE = path.join(__dirname, (process.env.botFilePath || ''));
// Read bot configuration from .bot file.
let botConfig;
try {
botConfig = BotConfiguration.loadSync(BOT_FILE, process.env.botFileSecret);
} catch (err) {
console.error(`\nError reading bot file. Please ensure you have valid botFilePath and botFileSecret set for your environment.`);
console.error(`\n - The botFileSecret is available under appsettings for your Azure Bot Service bot.`);
console.error(`\n - If you are running this bot locally, consider adding a .env file with botFilePath and botFileSecret.\n\n`);
process.exit();
}
// Get bot endpoint configuration by service name
const endpointConfig = botConfig.findServiceByNameOrId(BOT_CONFIGURATION);
// Create adapter.
// See https://aka.ms/about-bot-adapter to learn more about .bot file its use and bot configuration .
const adapter = new BotFrameworkAdapter({
appId: endpointConfig.appId || process.env.microsoftAppID,
appPassword: endpointConfig.appPassword || process.env.microsoftAppPassword
});
// Define state store for your bot.
// See https://aka.ms/about-bot-state to learn more about bot state.
const memoryStorage = new MemoryStorage();
// Create conversation and user state with in-memory storage provider.
const conversationState = new ConversationState(memoryStorage);
const userState = new UserState(memoryStorage);
// Create the bot.
const myBot = new MyBot(conversationState, userState);
// Catch-all for errors.
adapter.onTurnError = async (context, error) => {
// This check writes out errors to console log .vs. app insights.
console.error(`\n [onTurnError]: ${error}`);
// Send a message to the user
context.sendActivity(`Oops. Something went wrong!`);
// Clear out state
await conversationState.load(context);
await conversationState.clear(context);
// Save state changes.
await conversationState.saveChanges(context);
};
// Listen for incoming requests.
server.post('/api/messages', (req, res) => {
adapter.processActivity(req, res, async (context) => {
// Route to main dialog.
await myBot.onTurn(context);
});
});
================================================
FILE: SDKV4-Samples/js/stateBot/package.json
================================================
{
"name": "stateBot",
"version": "1.0.0",
"description": "Demonstrates how to set up user and conversation state.",
"author": "Microsoft Bot Builder Yeoman Generator v4.0.10",
"license": "MIT",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "echo \"Error: no build specified\" && exit 1",
"start": "node ./index.js",
"watch": "nodemon ./index.js"
},
"dependencies": {
"botbuilder": "^4.0.6",
"botframework-config": "^4.0.6",
"dotenv": "^6.0.0",
"restify": "^6.3.4"
},
"devDependencies": {
"eslint": "^5.6.0",
"eslint-config-standard": "^12.0.0",
"eslint-plugin-import": "^2.14.0",
"eslint-plugin-node": "^7.0.1",
"eslint-plugin-promise": "^4.0.1",
"eslint-plugin-standard": "^4.0.0",
"nodemon": "^1.18.4",
"@types/node": "10.10.2",
"@types/restify": "7.2.4"
}
}
================================================
FILE: SDKV4-Samples/js/stateBot/resources/echo.chat
================================================
user=Vishwac
bot=EchoBot
user: Hi
bot: 1: You said "Hi"
user: Hello
bot: 2: You said "Hello"
================================================
FILE: SDKV4-Samples/js/stateBot/stateBot.bot
================================================
{
"name": "stateBot",
"services": [
{
"type": "endpoint",
"name": "development",
"endpoint": "http://localhost:3978/api/messages",
"appId": "",
"appPassword": "",
"id": "1"
}
],
"padlock": "",
"version": "2.0"
}
================================================
FILE: SECURITY.md
================================================
## Security
Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/).
If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/opensource/security/definition), please report it to us as described below.
## Reporting Security Issues
**Please do not report security vulnerabilities through public GitHub issues.**
Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/opensource/security/create-report).
If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/opensource/security/pgpkey).
You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://aka.ms/opensource/security/msrc).
Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue:
* Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.)
* Full paths of source file(s) related to the manifestation of the issue
* The location of the affected source code (tag/branch/commit or direct URL)
* Any special configuration required to reproduce the issue
* Step-by-step instructions to reproduce the issue
* Proof-of-concept or exploit code (if possible)
* Impact of the issue, including how an attacker might exploit the issue
This information will help us triage your report more quickly.
If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/opensource/security/bounty) page for more details about our active programs.
## Preferred Languages
We prefer all communications to be in English.
## Policy
Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/opensource/security/cvd).
================================================
FILE: StackOverflow-Bot/.gitignore
================================================
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
# Azure Functions localsettings file
local.settings.json
# User-specific files
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
# Visual Studio 2015 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUNIT
*.VisualState.xml
TestResult.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# DNX
project.lock.json
project.fragment.lock.json
artifacts/
*_i.c
*_p.c
*_i.h
*.ilk
*.meta
*.obj
*.pch
*.pdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# JustCode is a .NET coding add-in
.JustCode
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# TODO: Comment the next line if you want to checkin your web deploy settings
# but database connection strings (with potential passwords) will be unencrypted
#*.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/
# NuGet Packages
*.nupkg
# The packages folder can be ignored because of Package Restore
**/packages/*
# except build/, which is used as an MSBuild target.
!**/packages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/packages/repositories.config
# NuGet v3's project.json files produces more ignoreable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!*.[Cc]ache/
# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
node_modules/
orleans.codegen.cs
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
# SQL Server files
*.mdf
*.ldf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# JetBrains Rider
.idea/
*.sln.iml
# CodeRush
.cr/
# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc
# Logs
logs
*.log
npm-debug.log*
# Runtime data
pids
*.pid
*.seed
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
# nyc test coverage
.nyc_output
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# node-waf configuration
.lock-wscript
# Compiled binary addons (http://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules
jspm_packages
# Optional npm cache directory
.npm
# Optional REPL history
.node_repl_history
.vscode
================================================
FILE: StackOverflow-Bot/DialogAnalyzerFunc/AnalyzeDialog.cs
================================================
using System;
using System.Configuration;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.Azure.WebJobs.Host;
using DialogAnalyzerFunc.Clients;
using DialogAnalyzerFunc.Models;
namespace DialogAnalyzerFunc
{
public static class AnalyzeDialog
{
private struct RequestBody
{
public Uri ImageUri { get; set; }
}
private static DialogAnalyzerClient client;
private static DialogAnalyzerClient Client
{
get
{
if (client == null)
{
client = new DialogAnalyzerClient(
computerVisionApiRegion: ComputerVisionApiRegion,
computerVisionSubscriptionKey: ComputerVisionSubscriptionKey,
textAnalyticsApiRegion: TextAnalyticsApiRegion,
textAnalyticsSubscriptionKey: TextAnalyticsSubscriptionKey
);
}
return client;
}
}
[FunctionName("AnalyzeDialog")]
public static async Task Run([HttpTrigger(AuthorizationLevel.Function, "post", Route = "AnalyzeDialog")]HttpRequestMessage request, TraceWriter log)
{
try
{
MediaTypeHeaderValue contentType = request.Content.Headers.ContentType;
// Check if content type is empty
if (contentType == null)
{
return request.CreateResponse(HttpStatusCode.BadRequest, "Missing content-type from header.");
}
// Check if content type is supported
bool isJson = contentType.MediaType.Contains("application/json") == true;
bool isOctetStream = contentType.MediaType.Contains("application/octet-stream") == true;
if (isJson == false && isOctetStream == false)
{
return request.CreateErrorResponse(HttpStatusCode.UnsupportedMediaType,
string.Format("Request's content type ({0}) is not supported.", string.Join(", ", contentType.MediaType)));
}
// Check if request body is empty
if (request.Content.Headers.ContentLength == 0)
{
return request.CreateResponse(HttpStatusCode.BadRequest, "No content found in the request.");
}
DialogAnalysisResult result;
if (isJson == true)
{
// Read content from request
RequestBody requestBody = await request.Content.ReadAsAsync();
// Verify content contains a valid image uri
if (requestBody.ImageUri == null || requestBody.ImageUri.IsAbsoluteUri == false)
{
return request.CreateResponse(HttpStatusCode.BadRequest, "Image uri is not initialized or valid in the request content.");
}
result = await Client.AnalyzeDialogAsync(requestBody.ImageUri);
}
else
{
byte[] imageData;
// Convert stream into byte data
using (Stream contentStream = await request.Content.ReadAsStreamAsync())
{
// Set stream position back to 0
contentStream.Position = 0;
// Using memory stream, create byte array
using (MemoryStream memoryStream = new MemoryStream())
{
await contentStream.CopyToAsync(memoryStream);
imageData = memoryStream.ToArray();
}
}
if (imageData == null)
{
return request.CreateResponse(HttpStatusCode.BadRequest, "No binary file is found in the request content.");
}
result = await Client.AnalyzeDialogAsync(imageData);
}
// Return request response
return request.CreateResponse(HttpStatusCode.OK, result);
}
catch (Exception ex)
{
log.Error("Exception hit when analyzing dialog.", ex);
}
return request.CreateErrorResponse(HttpStatusCode.InternalServerError, "Failed to process request.");
}
private static string ComputerVisionApiRegion => ConfigurationManager.AppSettings["COMPUTERVISION_APP_REGION"]?.ToString();
private static string ComputerVisionSubscriptionKey => ConfigurationManager.AppSettings["COMPUTERVISION_SUB_KEY"]?.ToString();
private static string TextAnalyticsApiRegion => ConfigurationManager.AppSettings["TEXTANALYTICS_APP_REGION"]?.ToString();
private static string TextAnalyticsSubscriptionKey => ConfigurationManager.AppSettings["TEXTANALYTICS_SUB_KEY"]?.ToString();
}
}
================================================
FILE: StackOverflow-Bot/DialogAnalyzerFunc/Clients/DialogAnalyzerClient.cs
================================================
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using DialogAnalyzerFunc.Models;
using DialogAnalyzerFunc.Services;
using DialogAnalyzerFunc.Utilities;
namespace DialogAnalyzerFunc.Clients
{
public class DialogAnalyzerClient
{
private ComputerVisionService ComputerVisionService;
private TextAnalyticsService TextAnalyticsService;
public DialogAnalyzerClient(string computerVisionApiRegion, string computerVisionSubscriptionKey,
string textAnalyticsApiRegion, string textAnalyticsSubscriptionKey)
{
// Computer Vision Service
this.ComputerVisionService = new ComputerVisionService(computerVisionApiRegion, computerVisionSubscriptionKey);
// Text Analytics Service
this.TextAnalyticsService = new TextAnalyticsService(textAnalyticsApiRegion, textAnalyticsSubscriptionKey);
}
///
/// Analyze dialog with image data
///
public async Task AnalyzeDialogAsync(byte[] imageData)
{
if (imageData?.Count() > 0 == false)
{
throw new ArgumentNullException("Image data is not initialized.");
}
// Run handwritten text recognition service
Task hwrTask = this.ComputerVisionService.RecognizeHandwrittenTextAsync(imageData);
// Run analyze image service
Task imageTask = this.ComputerVisionService.AnalyzeImageAsync(imageData);
// Wait for all tasks to be completed
await Task.WhenAll(hwrTask, imageTask);
// Get results
return await InterpretResultsAsync(hwrTask.Result, imageTask.Result);
}
///
/// Analyze dialog with image uri
///
public async Task AnalyzeDialogAsync(Uri imageUri)
{
if (imageUri == null)
{
throw new ArgumentNullException("Image uri is not initialized.");
}
// Run handwritten text recognition service
Task hwrTask = this.ComputerVisionService.RecognizeHandwrittenTextAsync(imageUri);
// Run analyze image service
Task imageTask = this.ComputerVisionService.AnalyzeImageAsync(imageUri);
// Wait for all tasks to be completed
await Task.WhenAll(hwrTask, imageTask);
// Get results
return await InterpretResultsAsync(hwrTask.Result, imageTask.Result);
}
private async Task InterpretResultsAsync(HandwritingRecognitionResult hwrResult, ComputerVisionImageAnalysisResult imageResult)
{
DialogAnalysisResult retResult = new DialogAnalysisResult();
if (hwrResult.Lines?.Count() > 0)
{
// Get labels from handwriting recognition
IEnumerable labels = hwrResult.Lines.Where(line => string.IsNullOrEmpty(line.Text) == false).Select(line => line.TextRegion);
// Interpret dialog data
DialogDataInterpreter dialogDataInterpreter = new DialogDataInterpreter(imageResult.Metadata.Height, imageResult.Metadata.Width, labels);
retResult = dialogDataInterpreter.Result;
// Extract text from dialog data interpreter's title and content result
List results = new List();
results.Add(retResult.TitleLabel?.TextLabel?.Text);
results.AddRange(retResult.ContentLabels?.Select(label => label?.TextLabel?.Text));
// Analyze key phrases from result text
string text = StringUtility.GetTextOrDefault(results, string.Empty, " ");
if (string.IsNullOrEmpty(text) == false)
{
TextAnalyticsResult keyPhrasesResult = await this.TextAnalyticsService.AnalyzeKeyPhrasesAsync(text);
retResult.KeyPhrases = keyPhrasesResult.Results?.Select(kp => kp.KeyPhrases).FirstOrDefault();
}
}
// Add image description tags
if (imageResult.Description?.Tags?.Count() > 0)
{
retResult.Tags = imageResult.Description.Tags;
}
// Add image description captions
if (imageResult.Description?.Captions?.Count() > 0)
{
retResult.Captions =
imageResult.Description.Captions.Where(cap => string.IsNullOrEmpty(cap.Text) == false)
.OrderByDescending(cap => cap.Confidence).Select(cap => cap.Text).ToArray();
}
return retResult;
}
}
}
================================================
FILE: StackOverflow-Bot/DialogAnalyzerFunc/Clients/DialogDataInterpreter.cs
================================================
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using DialogAnalyzerFunc.Models;
namespace DialogAnalyzerFunc.Clients
{
public class DialogDataInterpreter
{
private IEnumerable DialogLabels;
public DialogDataInterpreter(int height, int width, IEnumerable labels)
{
if (labels?.Count() > 0 == false)
{
throw new ArgumentNullException("Labels list is not initialized.");
}
// 1. Convert text labels
this.DialogLabels =
labels.Where(label => string.IsNullOrEmpty(label?.Text) == false).Select(label => new DialogLabel() { Id = Guid.NewGuid(), TextLabel = label }).ToList();
// 2. Set title label
this.SetTitleLabel();
// 3. Set button labels
this.SetButtonLabels();
// 4. Set content labels
this.SetContentLabels();
// 5. Set results
this.Result = new DialogAnalysisResult()
{
Labels = this.DialogLabels.ToArray()
};
}
///
/// Image data grid for buttons
///
private ImageDataGrid ButtonsGrid => new ImageDataGrid(0, this.Height - this.DefaultGridHeight, this.DefaultGridHeight, this.Width);
///
/// Get the height of the default grid
///
protected int DefaultGridHeight { get; private set; }
///
/// Height of the image
///
protected int Height { get; private set; }
///
/// Determine if the value is valid text
///
private bool IsValidText(string value)
{
return string.IsNullOrEmpty(value) == false && Regex.Match(value, "[a-z]+", RegexOptions.IgnoreCase).Success == true;
}
///
/// Determine if the value is with the target and buffer
///
protected bool IsWithin(int target, int buffer, int value)
{
return value >= (target - buffer) && value <= (target + buffer);
}
///
/// Width of the image
///
protected int Width { get; private set; }
///
/// Analysis result
///
public DialogAnalysisResult Result { get; protected set; }
///
/// Set button labels
///
private void SetButtonLabels()
{
if (this.UndefinedLabels.Count() == 0)
{
return;
}
// Find the labels which are undefined, within the button grid
IEnumerable potentialButtonLabels =
this.UndefinedLabels.Where(label => this.ButtonsGrid.Contains(label.TextLabel.CenterX, label.TextLabel.CenterY) == true && IsValidText(label.TextLabel.Text) == true);
if (potentialButtonLabels.Count() > 0)
{
// Find the y-coordinate of the lowest label
int lowestButtom = potentialButtonLabels.OrderByDescending(label => label.TextLabel.Y).First().TextLabel.Bottom;
IEnumerable buttonLabels = potentialButtonLabels.Where(label => this.IsWithin(lowestButtom, YBuffer, label.TextLabel.Bottom));
// If exist, set label type to button
foreach (DialogLabel buttonLabel in buttonLabels)
{
buttonLabel.DialogLabelType = DialogLabel.DialogLabelTypes.Button;
}
}
}
///
/// Set content labels
///
private void SetContentLabels()
{
if (this.UndefinedLabels.Count() == 0)
{
return;
}
// If exist, set label type to content
foreach (DialogLabel contentLabel in this.UndefinedLabels)
{
if (IsValidText(contentLabel.TextLabel.Text) == true)
{
contentLabel.DialogLabelType = DialogLabel.DialogLabelTypes.Content;
}
}
}
///
/// Set title label
///
private void SetTitleLabel()
{
if (this.UndefinedLabels.Count() == 0)
{
return;
}
// Find the label which is on top and within the title grid
DialogLabel titleLabel =
this.UndefinedLabels.Where(label => this.TitleGrid.Contains(label.TextLabel.CenterX, label.TextLabel.CenterY) == true
&& IsValidText(label.TextLabel.Text) == true).OrderBy(label => label.TextLabel.Y).FirstOrDefault();
// If exist, set label type to title
if (titleLabel != null)
{
titleLabel.DialogLabelType = DialogLabel.DialogLabelTypes.Title;
}
}
///
/// Image data grid for title
///
private ImageDataGrid TitleGrid => new ImageDataGrid(0, 0, this.DefaultGridHeight, this.Width);
///
/// Retrive undefined labels
///
private IEnumerable UndefinedLabels => this.DialogLabels.Where(label => label.IsDefined == false);
///
/// Buffer on the y-axis
///
protected int YBuffer => 20;
///
/// Object to define the image data grid
///
protected class ImageDataGrid
{
public ImageDataGrid(int x, int y, int height, int width)
{
this.X = x;
this.Y = y;
this.Height = height;
this.Width = width;
}
public int Height { get; set; }
public int Width { get; set; }
public int X { get; set; }
public int Y { get; set; }
public bool Contains(int x, int y)
{
return x >= this.X
&& x <= (this.X + this.Width)
&& y >= this.Y
&& y <= (this.Y + this.Height);
}
}
}
}
================================================
FILE: StackOverflow-Bot/DialogAnalyzerFunc/DialogAnalyzerFunc.csproj
================================================
net461PreserveNewestPreserveNewestNever
================================================
FILE: StackOverflow-Bot/DialogAnalyzerFunc/Extensions/EnumerableExtensions.cs
================================================
using System;
using System;
using System.Collections.Generic;
using System.Linq;
namespace DialogAnalyzerFunc.Extensions
{
public static class EnumerableExtensions
{
public static IEnumerable> ToTuples(this IEnumerable values)
{
if (values.Count() % 2 != 0)
{
throw new ArgumentException("Values does not have an even number of items.");
}
List> results = new List>();
if (values.Count() == 0)
{
return results;
}
for (int index = 0; index < values.Count(); index += 2)
{
results.Add(new Tuple(values.ElementAt(index), values.ElementAt(index + 1)));
}
return results;
}
}
}
================================================
FILE: StackOverflow-Bot/DialogAnalyzerFunc/Extensions/HttpExtensions.cs
================================================
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Linq;
using System.Text;
using Newtonsoft.Json;
namespace DialogAnalyzerFunc.Extensions
{
public static class HttpExtensions
{
///
/// Add headers to request
///
public static void AddHeaders(this HttpRequestMessage request, IDictionary headers)
{
// Add headers to request
if (headers != null)
{
foreach (string key in headers.Keys)
{
request.Headers.Add(key, headers[key]);
}
}
}
///
/// Add content to request as byte array
///
public static void AddContentAsBytes(this HttpRequestMessage request, byte[] content)
{
if (content?.Count() > 0)
{
ByteArrayContent byteContent = new ByteArrayContent(content);
byteContent.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/octet-stream");
request.Content = byteContent;
}
}
///
/// Add content to request as json
///
public static void AddContentAsJson(this HttpRequestMessage request, object content)
{
if (content != null)
{
string jsonContent = JsonConvert.SerializeObject(content);
request.Content = new StringContent(jsonContent, Encoding.UTF8, "application/json");
}
}
}
}
================================================
FILE: StackOverflow-Bot/DialogAnalyzerFunc/Models/ComputerVisionImageAnalysisResult.cs
================================================
using System;
using System.Runtime.Serialization;
namespace DialogAnalyzerFunc.Models
{
[DataContract]
public class ComputerVisionImageAnalysisResult
{
[DataMember(Name = "categories")]
public ComputerVisionImageCategory[] Categories { get; set; }
[DataMember(Name = "description")]
public ComputerVisionImageDescription Description { get; set; }
[DataMember(Name = "metadata")]
public ComputerVisionImageMetadata Metadata { get; set; }
[DataMember(Name = "requestId")]
public string RequestId { get; set; }
}
[DataContract]
public class ComputerVisionImageCategory
{
[DataMember(Name = "name")]
public string Name { get; set; }
[DataMember(Name = "score")]
public double Score { get; set; }
}
[DataContract]
public class ComputerVisionImageCaption
{
[DataMember(Name = "text")]
public string Text { get; set; }
[DataMember(Name = "confidence")]
public double Confidence { get; set; }
}
[DataContract]
public class ComputerVisionImageDescription
{
[DataMember(Name = "tags")]
public string[] Tags { get; set; }
[DataMember(Name = "captions")]
public ComputerVisionImageCaption[] Captions { get; set; }
}
[DataContract]
public class ComputerVisionImageMetadata
{
[DataMember(Name = "format")]
public string Format { get; set; }
[DataMember(Name = "height")]
public int Height { get; set; }
[DataMember(Name = "width")]
public int Width { get; set; }
}
}
================================================
FILE: StackOverflow-Bot/DialogAnalyzerFunc/Models/DialogAnalysisResult.cs
================================================
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
namespace DialogAnalyzerFunc.Models
{
[DataContract]
public class DialogAnalysisResult
{
[DataMember(Name = "KeyPhrases")]
public string[] KeyPhrases { get; set; } = new string[0];
[DataMember(Name = "Labels")]
public DialogLabel[] Labels { get; set; } = new DialogLabel[0];
[DataMember(Name = "Tags")]
public string[] Tags { get; set; } = new string[0];
[DataMember(Name = "Captions")]
public string[] Captions { get; set; } = new string[0];
public IEnumerable ContentLabels
{
get
{
return this.Labels?.Where(label => label.DialogLabelType == DialogLabel.DialogLabelTypes.Content);
}
}
public DialogLabel TitleLabel
{
get
{
return this.Labels?.FirstOrDefault(label => label.DialogLabelType == DialogLabel.DialogLabelTypes.Title);
}
}
}
[DataContract]
public class DialogLabel
{
public enum DialogLabelTypes
{
Button,
Content,
Title,
Unknown
}
[DataMember(Name = "DialogLabelType")]
public DialogLabelTypes DialogLabelType { get; set; } = DialogLabelTypes.Unknown;
[DataMember(Name = "Id")]
public Guid Id { get; set; } = Guid.Empty;
[DataMember(Name = "TextLabel")]
public ImageTextRegion TextLabel { get; set; }
public bool IsDefined => this.DialogLabelType != DialogLabelTypes.Unknown;
}
}
================================================
FILE: StackOverflow-Bot/DialogAnalyzerFunc/Models/HandwritingRecognitionResult.cs
================================================
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using DialogAnalyzerFunc.Extensions;
namespace DialogAnalyzerFunc.Models
{
[DataContract]
public struct HandwritingRecognitionOperationResult
{
public enum HandwritingRecognitionOperationStatus
{
NotStarted = 0,
Running = 1,
Succeeded = 2,
Failed = 3
}
[DataMember(Name = "status")]
public HandwritingRecognitionOperationStatus Status { get; set; }
[DataMember(Name = "recognitionResult")]
public HandwritingRecognitionResult Result { get; set; }
}
[DataContract]
public struct HandwritingRecognitionResult
{
[DataMember(Name = "lines")]
public HandwritingRecognitionText[] Lines { get; set; }
}
[DataContract]
public struct HandwritingRecognitionText
{
[DataMember(Name = "boundingBox")]
public int[] BoundingBox { get; set; }
[DataMember(Name = "text")]
public string Text { get; set; }
public ImageTextRegion TextRegion
{
get
{
// Create text region
ImageTextRegion textRegion = new ImageTextRegion()
{
Text = this.Text
};
// Determine boundaries
if (this.BoundingBox.Count() == 8)
{
IEnumerable> points = this.BoundingBox.ToTuples();
IEnumerable xAxis = points.Select(p => p.Item1).OrderBy(x => x);
IEnumerable yAxis = points.Select(p => p.Item2).OrderBy(y => y);
textRegion.X = xAxis.First();
textRegion.Y = yAxis.First();
textRegion.Width = xAxis.Last() - textRegion.X;
textRegion.Height = yAxis.Last() - textRegion.Y;
}
return textRegion;
}
}
}
}
================================================
FILE: StackOverflow-Bot/DialogAnalyzerFunc/Models/ImageTextRegion.cs
================================================
using System;
using System.Runtime.Serialization;
namespace DialogAnalyzerFunc.Models
{
[DataContract]
public class ImageTextRegion
{
///
/// The height of this Region
///
[DataMember]
public int Height { get; set; }
///
/// The text value of this Text Region
///
[DataMember]
public string Text { get; set; }
///
/// The width of this Region
///
[DataMember]
public int Width { get; set; }
///
/// The x-coordinate of the upper-left corner of this Region
///
[DataMember]
public int X { get; set; }
///
/// The y-coordinate of the upper-left corner of this Region
///
[DataMember]
public int Y { get; set; }
public int CenterX
{
get
{
return (this.Width / 2) + this.X;
}
}
public int CenterY
{
get
{
return (this.Height / 2) + this.Y;
}
}
public int Bottom
{
get
{
return this.Y + this.Height;
}
}
}
}
================================================
FILE: StackOverflow-Bot/DialogAnalyzerFunc/Models/TextAnalyticsResult.cs
================================================
using System;
using System.Runtime.Serialization;
namespace DialogAnalyzerFunc.Models
{
[DataContract]
public class TextAnalyticsResult
{
[DataMember(Name = "documents")]
public T[] Results { get; set; }
}
[DataContract]
public class TextAnalyticsKeyPhrasesResult
{
[DataMember(Name = "id")]
public string Id { get; set; }
[DataMember(Name = "keyPhrases")]
public string[] KeyPhrases { get; set; }
}
}
================================================
FILE: StackOverflow-Bot/DialogAnalyzerFunc/Services/ComputerVisionService.cs
================================================
using System;
using System.Collections.Generic;
using System.IO;
using System.Net.Http;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using DialogAnalyzerFunc.Models;
using DialogAnalyzerFunc.Utilities;
namespace DialogAnalyzerFunc.Services
{
public class ComputerVisionService
{
private readonly string HEADER_OPLOC_KEY = "Operation-Location";
private readonly string HEADER_SUB_KEY = "Ocp-Apim-Subscription-Key";
private readonly string SERVICE_URL_FORMAT = "https://{0}.api.cognitive.microsoft.com/vision/v1.0/";
private string AnalyzeImageVisualFeatures = "Description";
public IDictionary RequestHeaders { get; protected set; }
public string BaseServiceUrl { get; protected set; }
public ComputerVisionService(string apiRegion, string subscriptionKey)
{
if (string.IsNullOrEmpty(apiRegion) == true)
{
throw new ArgumentNullException("Api region is not initialized.");
}
if (string.IsNullOrEmpty(subscriptionKey) == true)
{
throw new ArgumentNullException("Subscription key is not initialized.");
}
this.BaseServiceUrl = string.Format(SERVICE_URL_FORMAT, apiRegion);
this.RequestHeaders = new Dictionary()
{
{ this.HEADER_SUB_KEY, subscriptionKey }
};
}
///
/// Analyze with image data
///
public async Task AnalyzeImageAsync(byte[] imageData)
{
if (imageData?.Count() > 0 == false)
{
throw new ArgumentNullException("Image data is not initialized.");
}
// Get request uri
Uri requestUri = new Uri(this.BaseServiceUrl + "analyze"
+ "?visualFeatures=" + this.AnalyzeImageVisualFeatures);
// Get response
return await HttpClientUtility.PostAsBytesAsync(requestUri, this.RequestHeaders, imageData);
}
///
/// Analyze with image uri
///
public async Task AnalyzeImageAsync(Uri imageUri)
{
string url = imageUri?.AbsoluteUri ?? throw new ArgumentNullException("Image uri is not initialized.");
// Get request uri
Uri requestUri = new Uri(this.BaseServiceUrl + "analyze"
+ "?visualFeatures=" + this.AnalyzeImageVisualFeatures);
// Create content of the request
var content = new { Url = url };
// Get response
return await HttpClientUtility.PostAsJsonAsync(requestUri, this.RequestHeaders, content);
}
///
/// Recognize handwritten text with image data
///
public async Task RecognizeHandwrittenTextAsync(byte[] imageData)
{
if (imageData?.Count() > 0 == false)
{
throw new ArgumentNullException("Image data is not initialized.");
}
// Get request uri
Uri requestUri = new Uri(this.BaseServiceUrl + "recognizeText?handwriting=true");
// Get response
HttpResponseMessage response = await HttpClientUtility.PostAsBytesAsync(requestUri, this.RequestHeaders, imageData);
return await GetResultFromOperationResponse(response);
}
///
/// Recognize handwritten text with image uri
///
public async Task RecognizeHandwrittenTextAsync(Uri imageUri)
{
string url = imageUri?.AbsoluteUri ?? throw new ArgumentNullException("Image uri is not initialized.");
// Get request uri
Uri requestUri = new Uri(this.BaseServiceUrl + "recognizeText?handwriting=true");
// Create content of the request
var content = new { Url = url };
// Get response
HttpResponseMessage response = await HttpClientUtility.PostAsJsonAsync(requestUri, this.RequestHeaders, content);
return await GetResultFromOperationResponse(response);
}
private async Task GetResultFromOperationResponse(HttpResponseMessage response)
{
// Process operation
if (response.Headers.Contains(this.HEADER_OPLOC_KEY) == false)
{
throw new InvalidOperationException("No operation-location value returned from initial request.");
}
Uri opLocationUri = new Uri(response.Headers.GetValues(this.HEADER_OPLOC_KEY).First());
HandwritingRecognitionOperationResult opResult = new HandwritingRecognitionOperationResult();
int i = 0;
while (i++ < HttpClientUtility.RETRY_COUNT)
{
// Get the operation result
opResult = await HttpClientUtility.GetAsync(opLocationUri, this.RequestHeaders);
// Wait if operation is running or has not started
if (opResult.Status == HandwritingRecognitionOperationResult.HandwritingRecognitionOperationStatus.NotStarted
|| opResult.Status == HandwritingRecognitionOperationResult.HandwritingRecognitionOperationStatus.Running)
{
await Task.Delay(HttpClientUtility.RETRY_DELAY);
}
else
{
break;
}
}
if (opResult.Status != HandwritingRecognitionOperationResult.HandwritingRecognitionOperationStatus.Succeeded)
{
throw new Exception($"Handwriting recognition operation was not successful with status: {opResult.Status}");
}
return opResult.Result;
}
}
}
================================================
FILE: StackOverflow-Bot/DialogAnalyzerFunc/Services/TextAnalyticsService.cs
================================================
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using DialogAnalyzerFunc.Models;
using DialogAnalyzerFunc.Utilities;
namespace DialogAnalyzerFunc.Services
{
public class TextAnalyticsService
{
private readonly string HEADER_SUB_KEY = "Ocp-Apim-Subscription-Key";
private readonly string SERVICE_URL_FORMAT = "https://{0}.api.cognitive.microsoft.com/text/analytics/v2.0/";
public IDictionary RequestHeaders { get; protected set; }
public string BaseServiceUrl { get; protected set; }
public TextAnalyticsService(string apiRegion, string subscriptionKey)
{
if (string.IsNullOrEmpty(apiRegion) == true)
{
throw new ArgumentNullException("Api region is not initialized.");
}
if (string.IsNullOrEmpty(subscriptionKey) == true)
{
throw new ArgumentNullException("Subscription key is not initialized.");
}
this.BaseServiceUrl = string.Format(SERVICE_URL_FORMAT, apiRegion);
this.RequestHeaders = new Dictionary()
{
{ this.HEADER_SUB_KEY, subscriptionKey }
};
}
///
/// Analyze key phrases with text
///
public async Task> AnalyzeKeyPhrasesAsync(string fullText)
{
if (string.IsNullOrEmpty(fullText) == true)
{
throw new ArgumentNullException("Text is not initialized.");
}
// Get request uri
Uri requestUri = new Uri(this.BaseServiceUrl + "keyPhrases");
var document = new
{
id = Guid.NewGuid().ToString(),
text = fullText
};
// Create content of the request
var content = new
{
documents = new object[] { document }
};
// Get response
return await HttpClientUtility.PostAsJsonAsync>(requestUri, this.RequestHeaders, content);
}
}
}
================================================
FILE: StackOverflow-Bot/DialogAnalyzerFunc/Utilities/HttpClientUtility.cs
================================================
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using Newtonsoft.Json;
using DialogAnalyzerFunc.Extensions;
namespace DialogAnalyzerFunc.Utilities
{
public static class HttpClientUtility
{
public static readonly int RETRY_COUNT = 10;
public static readonly int RETRY_DELAY = 500;
private static HttpClient Client;
///
/// Static constructor of the HttpClientUtility
///
static HttpClientUtility()
{
if (Client == null)
{
Client = new HttpClient();
}
}
///
/// Send Http Get to the request uri and get the TResult from response content
///
public static async Task GetAsync(Uri requestUri, IDictionary headers)
{
// Get response
HttpResponseMessage response = await GetAsync(requestUri, headers);
// Read response
string responseContent = await response.Content.ReadAsStringAsync();
// Get result
TResult result = JsonConvert.DeserializeObject(responseContent);
return result;
}
///
/// Send Http Get to the request uri and get HttpResponseMessage
///
public static async Task GetAsync(Uri requestUri, IDictionary headers)
{
// Create new request function
Func createRequestMessage = () =>
{
// Create new request
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, requestUri);
// Add headers to request
request.AddHeaders(headers);
return request;
};
// Send request and get response
HttpResponseMessage response = await ExecuteActionkWithAutoRetry(() => Client.SendAsync(createRequestMessage()));
return response;
}
///
/// Send Http Post to request uri and get TResult from response content
///
public static async Task PostAsBytesAsync(Uri requestUri, IDictionary headers, byte[] content)
{
// Post request and get response
HttpResponseMessage response = await PostAsBytesAsync(requestUri, headers, content);
// Read response
string responseContent = await response.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject(responseContent);
}
///
/// Send Http Post to request uri and get TResult from response content
///
public static async Task PostAsJsonAsync(Uri requestUri, IDictionary headers, object content)
{
// Post request and get response
HttpResponseMessage response = await PostAsJsonAsync(requestUri, headers, content);
// Read response
string responseContent = await response.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject(responseContent);
}
///
/// Send Http Post to request uri and get HttpResponseMessage
///
public static async Task PostAsBytesAsync(Uri requestUri, IDictionary headers, byte[] content)
{
// Create new request function
Func createRequestMessage = () =>
{
// Create new request
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, requestUri);
// Add headers to request
request.AddHeaders(headers);
// Add content as Json
request.AddContentAsBytes(content);
return request;
};
// Post request
HttpResponseMessage response = await ExecuteActionkWithAutoRetry(() => Client.SendAsync(createRequestMessage()));
return response;
}
///
/// Send Http Post to request uri and get HttpResponseMessage
///
public static async Task PostAsJsonAsync(Uri requestUri, IDictionary headers, object content)
{
// Create new request function
Func createRequestMessage = () =>
{
// Create new request
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, requestUri);
// Add headers to request
request.AddHeaders(headers);
// Add content as Json
request.AddContentAsJson(content);
return request;
};
// Post request
HttpResponseMessage response = await ExecuteActionkWithAutoRetry(() => Client.SendAsync(createRequestMessage()));
return response;
}
///
/// Execute the action which returns HttpResponseMessage with auto retry
///
private static async Task ExecuteActionkWithAutoRetry(Func> action)
{
int retryCount = RETRY_COUNT;
int retryDelay = RETRY_DELAY;
HttpResponseMessage response;
while (true)
{
response = await action();
if (response.StatusCode == (HttpStatusCode)429 && retryCount > 0)
{
await Task.Delay(retryDelay);
retryCount--;
retryDelay *= 2;
continue;
}
response.EnsureSuccessStatusCode();
break;
}
return response;
}
}
}
================================================
FILE: StackOverflow-Bot/DialogAnalyzerFunc/Utilities/StringUtility.cs
================================================
using System;
using System.Collections.Generic;
using System.Linq;
namespace DialogAnalyzerFunc.Utilities
{
public static class StringUtility
{
///
/// Get combined text with delimeter or default value
///
public static string GetTextOrDefault(IEnumerable values, string defaultValue, string delim = ", ")
{
if (values?.Count() > 0 == false || values.All(v => string.IsNullOrEmpty(v) == true))
{
return defaultValue;
}
values = values.Where(v => string.IsNullOrEmpty(v) == false);
return string.Join(delim, values).Trim();
}
}
}
================================================
FILE: StackOverflow-Bot/DialogAnalyzerFunc/host.json
================================================
{
}
================================================
FILE: StackOverflow-Bot/LICENSE
================================================
The MIT License (MIT)
Copyright (c) 2017 Microsoft Corporation
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: StackOverflow-Bot/README.md
================================================
# Stack Overflow Bot
This Bot is intended to demonstrate a number of integrations between Microsoft Bot Framework, and Microsoft's Cognitive Services. From Microsoft's Cognitive Services, this bot uses: Bing Custom Search, Language Understanding Intelligence Service (LUIS), QnA Maker, and Text Analytics. The full range of cognitive services that Microsoft offers can be viewed here: https://azure.microsoft.com/en-us/services/cognitive-services/.
Bot Framework allows you to build bots using a simple, but comprehensive API. The Bots you build can be configured to work for your users wherever they are, whether it's Skype, Microsoft Teams, Cortana, Slack or more. To learn more about Bot Framework, visit https://dev.botframework.com/. To learn more about developing bots with the Bot Framework, visit https://docs.microsoft.com/en-us/bot-framework/#pivot=main&panel=developing.
## Components
### [StackBot](#bot)
A JavaScript project that demonstrates the usage of Bing Custom Search, LUIS, QnA Maker, and Text Analytics to make it easier to search for solutions on Stack Overflow.
### [DialogAnalyzerFunc](#dialog-analyzer-azure-function)
An C# project that uses Computer Vision and Text Analytics to parse the contents of a screenshot.
### [StackCode](#stack-overflow-bot-visual-studio-code-extension)
A TypeScript project that demonstrates how the bot can be built into Visual Studio Code.
## Bot
### Requirements to run the Bot
- Node 8.1.4
### Installation of the Bot
Run `npm install` in the `StackBot` directory.
### Running the Bot
1. Run `npm run start` in the `StackBot` directory.
2. Navigate to `http://localhost:3978/` to start interacting with your bot.
### Companion Visual Studio Code Extension
The Visual Studio Code extension allows developers to use their Bot as a programming buddy, allowing them to amplify their productivity by reducing context switching. For more information about it, including how it can be built, and installed, please refer to the the [Stack Overflow Bot Visual Studio Code Extension](#stack-overflow-bot-visual-studio-code-extension) section below.
### Configuration
As this bot uses a number of services, you will need to create applications and generate keys for each one. The following instructions are intended to guide you on how to do this.
#### Service: Bot Framework
To register a Bot Framework Bot, go to https://dev.botframework.com/bots/new. Fill out the form, select `Register an existing bot using BotBuilder SDK`, and create a `Microsoft App Id` and `Password`. Save both `Microsoft App Id` and `Password` somewhere secure, and add them as the following environment variables. See https://www.schrodinger.com/kb/1842 for instructions on how to set environment variables.
- `BOTBUILDER_APP_ID` is the `Microsoft App Id` you generated
- `BOTBUILDER_APP_PASSWORD` is the `Microsoft App Password` you generated.
#### Service: Language Understanding Intelligence Service (LUIS)
To register and train a LUIS Application, go to https://www.luis.ai/applications. After logging in, click `New App` and follow the directions. When directed to the dashboard, go to Settings, and click `Import Version`. From the Uplaod File dialog,select the `luis.json` file under the `StackBot/data` directory. After the file is uploaded, click the `Set as active version` button under the `Actions` column. Click on `Train & Test` on the Left Column and click `Train Application`. It may take a few minutes to finish. Once done, you can test your LUIS model by typing out an utterance. Try 'tell me a joke', for example. Finally, click on `Publish App`, assign a key, and click `Publish`. You will be
given an `Endpoint url`. Copy this URL and add it as an environment variable.
- `LUIS_MODEL` is the `Endpoint url` from publishing a LUIS Application.
#### Service: QnAMaker
To register a QnAMaker Application, go to https://qnamaker.ai/Create. After logging in, name your new Application and click on `Select file…` under the `FAQ FILES` heading. From the File Picker, navigate to the `smalltalk.tsv` file under the `StackBot/data` directory. Then click `Create`, and wait for a moment as the QnaMaker service is created from the Question/Answer pairs. When prompted, click `Publish` to expose the service to the outside world. You will be directed to a `Success` page. Here, take a look at the `Sample HTTP Request`. It will look like the following, but with generated keys in place of `KB_ID` and `QNA_KEY`, and a URL in place of `QNA_URL`:
```
POST /knowledgebases/KB_ID/generateAnswer
Host: QNA_URL
Ocp-Apim-Subscription-Key: QNA_KEY
Content-Type: application/json
{"question":"hi"}
```
Take note of `KB_ID`, `QNA_KEY`, and `QNA_URL`, and save them. Set the following as environment variables:
- `KB_ID` is the `KB_ID` from the sample http request
- `QNA_KEY` is the `QNA_KEY` from the sample http request
- `QNA_URL` is the `QNA_URL` fom the 'Host' parameter. As Cognitive Services can vary from region to region, it's important to set this appropriately. You may see for example, 'https://westus.api.cognitive.microsoft.com/qnamaker/v2.0' if your Text Analytics Cognitive Service is deployed in the `West US` Azure region.
#### Service: Dialog Analyzer
To deploy and configure the Dialog Analyzer Azure Function, please refer to the [Dialog Analyzer Azure Function](#dialog-analyzer-azure-function) section below. After the deployment and configuring the Azure Function, set the following environment variables:
- `DIALOG_ANALYZER_CLIENTID` is the name of the `Function Key`
- `DIALOG_ANALYZER_KEY` is the value of the `Function Key`
- `DIALOG_ANALYZER_URL` is the url of the deployment of the Azure Function
#### Service: Bing Custom Search
To create a new Bing Custom Search, go to https://customsearch.ai/applications. After logging in, click on the `New custom search` with a new custom search instance name. You can then add a new domain `stackoverflow.com` in this case to set your custom search to stackoverflow.com only. Then click on the `Custom Search Endpoint` button, that is located besides your custom search name to obtain the `Primary key` and the `Custom Configuration ID`. For more information, please refer to https://docs.microsoft.com/en-us/azure/cognitive-services/bing-custom-search/quickstart. Set the following environment variables:
- `BING_SEARCH_CONFIG` is the Custom Configuration ID from your custom search instance
- `BING_SEARCH_KEY` is the Primary Key (or Secondary Key) from your custom search instance
#### Service: Text Analytics
To register a Text Analytics Cognitive Service for Sentiment Analysis, go to https://ms.portal.azure.com/#create/Microsoft.CognitiveServices/apitype/TextAnalytics. After logging and going through the process of creating a Text Analytics Cognitive Service, go to the Application dashboard in the Azure Portal. Here you can click on `Keys` in the left pane or `Manage Keys` in the `Essentials` panel. Copy one of the keys shown and save it. Set the following environment variables:
- `TEXT_ANALYTICS_KEY` is one of the keys shown in the Azure Portal.
- `TEXT_ANALYTICS_URL` is the URL shown under `Endpoint` in the `Essentials` panel. As Cognitive Services can vary from region to region, it's important to set this appropriately. You may see for example, 'https://westus.api.cognitive.microsoft.com/text/analytics/v2.0' if your Text Analytics Cognitive Service is deployed in the `West US` Azure region.
#### Service: Ngrok tunneling
In order for your locally running bot to communicate to other Bot Framework channels, it must make itself known to the Bot Framework dashboard, and the world. To do this, you can use tunneling software, like ngrok. Ngrok can be downloaded here https://ngrok.com/download. After installing and running Ngrok on port 3978 with the following commnad `ngrok http 3978`, you should see:
Session Status online
Version 2.2.8
Region United States (us)
Web Interface http://127.0.0.1:4040
Forwarding http://b05cf662.ngrok.io -> localhost:3978
Forwarding https://b05cf662.ngrok.io -> localhost:3978
Connections ttl opn rt1 rt5 p50 p90
0 0 0.00 0.00 0.00 0.00
Copy the HTTPS forwarding URL (in this case `https://b05cf662.ngrok.io`) to your clipboard, and go to the Bot Framework dashboard at https://dev.botframework.com/bots. Select your bot and click on `Settings` in the the upper right corner. From there, you can scroll down to `Messaging Endpoint` under `Configuration`, and paste in the URL you copied, followed by the API endpoint that the bot listens on (in this bot's case: `/api/messages`). For example, if the HTTPS Forwarding URL was `https://b05cf662.ngrok.io` we would use ` https://b05cf662.ngrok.io/api/messages` as the `Messaging Endpoint`.
When the bot is running ([see the section on running the bot](#running-the-bot)), it should now be testable directly from the Bot Framework dashboard. Click `<- Test` in the upper right corner to slide open a Web Chat control and begin interacting with the bot.
To test your bot from a web chat control hosted at the HTTPS forwarding URL, continue reading to setup and configure a Direct Line channel.
#### Service: Locally hosted Web Chat control.
Go to your Bot's dashboard, available at https://dev.botframework.com/bots and add a 'Direct Line' channel.
This channel allows the Bot Framework Web Chat control to communicate to your Bot's backend service. From there, click `Add a Site` and give it a name. Click `Show` to the right of the hidden keys under `Secret keys`, and copy it. You can come back to this dashboard to view it again if you lose it. From there, open the file at `StackBot/static/index.html`, and change the assignment of the `BOT_SECRET` variable, pasting the Secret Key that was just copied.
## Dialog Analyzer Azure Function
This Azure Function is intended to demonstrate how to build a function with Azure and Microsoft's Cognitive Services. From Microsoft's Cognitive Services, this function uses Computer Vision's Image Analysis to extract tags and captions; and Optical Character Recognition (OCR) to extract text from the image. It also uses Text Analytics to extract key phrases from text.
Azure Functions allows you to focus on building great apps and not have to worry about provisioning and maintaining servers, especially when your workload grows. Functions provides a fully managed compute platform with high reliability and security. With scale on demand, you get the resources you need—when you need them. To learn more about Azure Functions, visit https://azure.microsoft.com/en-us/services/functions/.
### Requirements to build the function
- Visual Studio 2017 version 15.3 or later
- Azure development workload
- .NET Framework 4.6.1
### Publish the function to Azure
To publish the Azure function, you can open the `DialogAnalyzerFunc` Visual Studio project. In `Solution Explorer`, right-click the project and select `Publish`. Choose `Create New` and then click `Publish`. If you haven't already connected Visual Studio to your Azure account, click `Add an account....`. In the `Create App Service` dialog, use the `Hosting` settings to sepecify your `App Name`, `Subscription`, `Resource Group`, `App Service Plan`, and `Storage account`. Click `Create` to create a function app in Azure with the previously populated settings. For more details, please refer to https://docs.microsoft.com/en-us/azure/azure-functions/functions-develop-vs#publish-to-azure
### Configuration
This function uses a number of services. You will need to configure the function's deployment and generate keys for each of the services. The following instructions are intended to guide you on how to do this.
#### Deployment: Dialog Analyzer Azure Function
In order for the bot to use your deployed function, you will need to configure it's application settings.
To begin, go to the `Azure portal` and sign in to your Azure account. In the search bar at the top of the portal, type the name of your function app and select it from the list. In the `Function Apps` panel, expand the function and select the `Manage` button. Within the Manage window, click on `Add new function key` button and define a key name and value for the function and click on the `Save` button. These will become your `DIALOG_ANALYZER_CLIENTID` and `DIALOG_ANALYZER_KEY` settings for your bot.
For more information, please refer to: https://docs.microsoft.com/en-us/azure/azure-functions/functions-how-to-use-azure-function-app-settings.
#### Service: Computer Vision
To register a Computer Vision Cognitive Service for Image Analysis and OCR, go to https://portal.azure.com/#create/Microsoft.CognitiveServices/apitype/ComputerVision. After logging and going through the process of creating a Computer Vision Cognitive Service, go to the Application dashboard in the Azure Portal. Here you can click on `Keys` in the left pane or `Manage Keys` in the `Essentials` panel. Copy one of the keys shown and save it. Set the following in your App Settings of your function:
- `COMPUTERVISION_SUB_KEY` is one of the access keys shown in the Azure Portal.
- `COMPUTERVISION_APP_REGION` is region of the the URL shown under `Endpoint` in the `Essentials` panel. For example, if 'https://westus.api.cognitive.microsoft.com/vision/v1.0' is where your Computer Vision Cognitive Service is deployed, then the app region is `westus`.
#### Service: Text Analytics
To register a Text Analytics Cognitive Service for Sentiment Analysis, go to https://ms.portal.azure.com/#create/Microsoft.CognitiveServices/apitype/TextAnalytics. After logging in and going through the process of creating a Text Analytics Cognitive Service, go to the Application dashboard in the Azure Portal. Here you can click on `Keys` in the left pane or `Manage Keys` in the `Essentials` panel. Copy one of the keys shown and save it. Set the following in your App Settings of your function:
- `TEXTANALYTICS_SUB_KEY` is one of the access keys shown in the Azure Portal.
- `TEXTANALYTICS_APP_REGION` is region of the the URL shown under `Endpoint` in the `Essentials` panel. For example, if 'https://westus.api.cognitive.microsoft.com/text/analytics/v2.0' is where your Text Analytics Cognitive Service is deployed, then the app region is `westus`.
## Stack Overflow Bot Visual Studio Code Extension
This Visual Studio Code Extension is intended to be a companion piece to the Stack Overflow Bot. It allows you to quickly
call up the bot using a simple command.
### Configuring the extension to use your own Bot.
After you've deployed the Stack Overflow Bot and its companion function to your favorite hosting service, and registered a bot
with the Bot Framework portal (see https://dev.botframework.com/bots/new), go to your Bot's dashboard, and add a 'Direct Line' channel.
This channel allows the Bot Framework Web Chat control to communicate to your Bot's backend service. From there, Add a Site and give it a name.
You will be directed to a page that will allow you to generate and copy tokens. Click on 'Show' on one of the tokens, and copy it. You can come back to this dashboard to view it again if you lose it. From there, open up your Visual Studio Code User Settings (`⌘,` or `⊞,`), and create a new field `StackCode.directLineToken`, assigning the token you copied to this label. If done correctly, activating the Bot in Visual Studio Code will open a pane that will show you a Bot Framework WebChat control, where you can interact with the bot.
### Installing dependencies
Run `npm install`
### Installing the extension
A few options…
* Option 1: Clone the package using git, then open it in code. Go to the Debug tab and run it in an extension host window.
* Option 2: Clone the package using git, run `code --install-extension StackCode-0.1.1.vsix` in the directory. See the VS Code [docs](https://code.visualstudio.com/docs/editor/extension-gallery#_install-from-a-vsix) for more details.
### Activating (running) the extension
* Using the command palate (`⇧⌘P` or `⇧⊞P`), type out `Start Stack Overflow Bot`, or something close to it. The bot will appear in its
own pane to the right.
## License
MIT. See LICENSE file.
================================================
FILE: StackOverflow-Bot/StackBot/Dockerfile
================================================
FROM node:8-onbuild
EXPOSE 3978
RUN npm install
CMD ["npm", "run", "start"]
================================================
FILE: StackOverflow-Bot/StackBot/StackBot.njsproj
================================================
14.0$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)StackBotStackBotDebug2.0e7ce1022-2ff2-44e3-8057-d472019453ef..v4.0{3AF33F2E-1136-4D97-BBB7-1795711AC8B8};{349c5851-65df-11da-9384-00065b846f21};{9092AA53-FB77-4645-B42D-1CCCA6BD08BD}1337TruetruetrueFalseTrue0/http://localhost:48022/FalseTruehttp://localhost:1337FalseCurrentPageTrueFalseFalseFalseFalseFalse
================================================
FILE: StackOverflow-Bot/StackBot/data/jokes.json
================================================
{
"items": [
{
"body_markdown": "Not a joke, but a cartoon:\r\n\r\n![enter image description here][1]\r\n\r\nFrom: [Jeffrey Palm][2]\r\n\r\n\r\n [1]: http://i.stack.imgur.com/NbygN.jpg\r\n [2]: http://jeffpalm.com/blog/",
"link": "https://stackoverflow.com/questions/234075/what-is-your-best-programmer-joke/958411#958411",
"body": "
\n"
},
{
"body_markdown": "![It's not a bug...][1]\r\n\r\n\r\n [1]: https://crossthebreeze.files.wordpress.com/2007/08/feature.jpg",
"link": "https://stackoverflow.com/questions/234075/what-is-your-best-programmer-joke/234170#234170",
"body": "
\n"
},
{
"body_markdown": "A SQL query goes into a bar, walks up to two tables and asks, "Can I join you?"",
"link": "https://stackoverflow.com/questions/234075/what-is-your-best-programmer-joke/234399#234399",
"body": "
A SQL query goes into a bar, walks up to two tables and asks, \"Can I join you?\"
\n"
},
{
"body_markdown": "I'd like to make the world a better place, but they won't give me the source code.",
"link": "https://stackoverflow.com/questions/234075/what-is-your-best-programmer-joke/295277#295277",
"body": "
I'd like to make the world a better place, but they won't give me the source code.
\n"
},
{
"body_markdown": "Two bytes meet. The first byte asks, “Are you ill?” \r\n\r\nThe second byte replies, “No, just feeling a bit off.”",
"link": "https://stackoverflow.com/questions/234075/what-is-your-best-programmer-joke/234092#234092",
"body": "
Two bytes meet. The first byte asks, “Are you ill?”
\n\n
The second byte replies, “No, just feeling a bit off.”
\n"
}
]
}
================================================
FILE: StackOverflow-Bot/StackBot/data/luis.json
================================================
{
"luis_schema_version": "2.1.0",
"versionId": "0.1",
"name": "Stackoverflow",
"desc": "",
"culture": "en-us",
"intents": [
{
"name": "Brain"
},
{
"name": "Help"
},
{
"name": "Joke"
},
{
"name": "Languages"
},
{
"name": "None"
},
{
"name": "Search"
},
{
"name": "SmallTalk"
}
],
"entities": [
{
"name": "keywords"
}
],
"composites": [],
"closedLists": [],
"bing_entities": [],
"actions": [],
"model_features": [],
"regex_features": [],
"utterances": [
{
"text": "hello",
"intent": "SmallTalk",
"entities": []
},
{
"text": "hi",
"intent": "SmallTalk",
"entities": []
},
{
"text": "who are you",
"intent": "SmallTalk",
"entities": []
},
{
"text": "how old are you",
"intent": "SmallTalk",
"entities": []
},
{
"text": "who are you?",
"intent": "SmallTalk",
"entities": []
},
{
"text": "marry me",
"intent": "SmallTalk",
"entities": []
},
{
"text": "help",
"intent": "Help",
"entities": []
},
{
"text": "you're awesome",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you are good",
"intent": "SmallTalk",
"entities": []
},
{
"text": "how did you do that",
"intent": "Brain",
"entities": []
},
{
"text": "when is your birthday",
"intent": "SmallTalk",
"entities": []
},
{
"text": "hey",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you're cute",
"intent": "SmallTalk",
"entities": []
},
{
"text": "tell me a joke",
"intent": "Joke",
"entities": []
},
{
"text": "where are you from",
"intent": "SmallTalk",
"entities": []
},
{
"text": "help me",
"intent": "Help",
"entities": []
},
{
"text": "tell me something funny",
"intent": "Joke",
"entities": []
},
{
"text": "how old are you?",
"intent": "SmallTalk",
"entities": []
},
{
"text": "are you a robot",
"intent": "SmallTalk",
"entities": []
},
{
"text": "menu",
"intent": "Help",
"entities": []
},
{
"text": "where do you work",
"intent": "SmallTalk",
"entities": []
},
{
"text": "where were you born",
"intent": "SmallTalk",
"entities": []
},
{
"text": "when were you born",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you are awesome",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you are a genius",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you are so smart",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you are cool",
"intent": "SmallTalk",
"entities": []
},
{
"text": "are you hungry",
"intent": "SmallTalk",
"entities": []
},
{
"text": "do something",
"intent": "Help",
"entities": []
},
{
"text": "what can you do",
"intent": "Help",
"entities": []
},
{
"text": "you are very cool",
"intent": "SmallTalk",
"entities": []
},
{
"text": "make me laugh",
"intent": "Joke",
"entities": []
},
{
"text": "tell me about yourself",
"intent": "SmallTalk",
"entities": []
},
{
"text": "joke",
"intent": "Joke",
"entities": []
},
{
"text": "you are very intelligent",
"intent": "SmallTalk",
"entities": []
},
{
"text": "what are you",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you are boring",
"intent": "SmallTalk",
"entities": []
},
{
"text": "what are your abilities",
"intent": "Help",
"entities": []
},
{
"text": "smart",
"intent": "SmallTalk",
"entities": []
},
{
"text": "are you working",
"intent": "SmallTalk",
"entities": []
},
{
"text": "h",
"intent": "SmallTalk",
"entities": []
},
{
"text": "tell me about you",
"intent": "SmallTalk",
"entities": []
},
{
"text": "i like you",
"intent": "SmallTalk",
"entities": []
},
{
"text": ":(",
"intent": "SmallTalk",
"entities": []
},
{
"text": "who is your owner",
"intent": "SmallTalk",
"entities": []
},
{
"text": "are you nuts",
"intent": "SmallTalk",
"entities": []
},
{
"text": "are you my friend",
"intent": "SmallTalk",
"entities": []
},
{
"text": "brilliant",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you are beautiful",
"intent": "SmallTalk",
"entities": []
},
{
"text": "are you insane",
"intent": "SmallTalk",
"entities": []
},
{
"text": "are you a bot",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you are very helpful",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you are very pretty",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you rock",
"intent": "SmallTalk",
"entities": []
},
{
"text": "tell a joke",
"intent": "Joke",
"entities": []
},
{
"text": "you are amazing",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you are funny",
"intent": "SmallTalk",
"entities": []
},
{
"text": "are you mad",
"intent": "SmallTalk",
"entities": []
},
{
"text": "who is your master",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you are the best",
"intent": "SmallTalk",
"entities": []
},
{
"text": "how was your day",
"intent": "SmallTalk",
"entities": []
},
{
"text": "your age",
"intent": "SmallTalk",
"entities": []
},
{
"text": "javascript",
"intent": "Search",
"entities": [
{
"entity": "keywords",
"startPos": 0,
"endPos": 9
}
]
},
{
"text": "you are pretty",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you are wonderful",
"intent": "SmallTalk",
"entities": []
},
{
"text": "main menu",
"intent": "Help",
"entities": []
},
{
"text": "\"thanx\"",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you are so awesome",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you are so intelligent",
"intent": "SmallTalk",
"entities": []
},
{
"text": "introduce yourself",
"intent": "SmallTalk",
"entities": []
},
{
"text": "who do you work for",
"intent": "SmallTalk",
"entities": []
},
{
"text": "are you crazy",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you are clever",
"intent": "SmallTalk",
"entities": []
},
{
"text": "describe yourself",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you are so cute",
"intent": "SmallTalk",
"entities": []
},
{
"text": "are you happy",
"intent": "SmallTalk",
"entities": []
},
{
"text": "are you a chatbot",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you are mad",
"intent": "SmallTalk",
"entities": []
},
{
"text": "why are you here",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you are so clever",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you're pretty",
"intent": "SmallTalk",
"entities": []
},
{
"text": "do you work",
"intent": "SmallTalk",
"entities": []
},
{
"text": "i want to search",
"intent": "Search",
"entities": []
},
{
"text": "what's your age",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you are very smart",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you're great",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you are cute",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you are very cute",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you are very clever",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you are my best friend",
"intent": "SmallTalk",
"entities": []
},
{
"text": "tell joke",
"intent": "Joke",
"entities": []
},
{
"text": "you look cool",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you are so cool",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you are so amazing",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you are a good friend",
"intent": "SmallTalk",
"entities": []
},
{
"text": "what languages do you speak",
"intent": "Languages",
"entities": []
},
{
"text": "you're intelligent",
"intent": "SmallTalk",
"entities": []
},
{
"text": "who is your boss",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you are very kind",
"intent": "SmallTalk",
"entities": []
},
{
"text": "clever",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you are hilarious",
"intent": "SmallTalk",
"entities": []
},
{
"text": "will you be my friend",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you are so handsome",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you look great today",
"intent": "SmallTalk",
"entities": []
},
{
"text": "let's be friends",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you're so funny",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you are so funny",
"intent": "SmallTalk",
"entities": []
},
{
"text": "that was funny",
"intent": "SmallTalk",
"entities": []
},
{
"text": "are you busy",
"intent": "SmallTalk",
"entities": []
},
{
"text": "im stuck",
"intent": "Help",
"entities": []
},
{
"text": "you are my friend",
"intent": "SmallTalk",
"entities": []
},
{
"text": "where is your office",
"intent": "SmallTalk",
"entities": []
},
{
"text": "tell me your age",
"intent": "SmallTalk",
"entities": []
},
{
"text": "languages",
"intent": "Languages",
"entities": []
},
{
"text": "you are crazy",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you are insane",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you are a bot",
"intent": "SmallTalk",
"entities": []
},
{
"text": "what is your work",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you are really smart",
"intent": "SmallTalk",
"entities": []
},
{
"text": "are you a program",
"intent": "SmallTalk",
"entities": []
},
{
"text": "about yourself",
"intent": "SmallTalk",
"entities": []
},
{
"text": "i want to know more about you",
"intent": "SmallTalk",
"entities": []
},
{
"text": "what languages can you speak",
"intent": "Languages",
"entities": []
},
{
"text": "where is your office located",
"intent": "SmallTalk",
"entities": []
},
{
"text": "language",
"intent": "Languages",
"entities": []
},
{
"text": "you are very beautiful",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you are dismissed",
"intent": "SmallTalk",
"entities": []
},
{
"text": "where do you come from",
"intent": "SmallTalk",
"entities": []
},
{
"text": "can you be my friend",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you are very boring",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you're annoying",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you are intelligent",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you made my day",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you are so helpful",
"intent": "SmallTalk",
"entities": []
},
{
"text": "what's your birthday",
"intent": "SmallTalk",
"entities": []
},
{
"text": "where did you come from",
"intent": "SmallTalk",
"entities": []
},
{
"text": "talk about yourself",
"intent": "SmallTalk",
"entities": []
},
{
"text": "where you work",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you look so beautiful",
"intent": "SmallTalk",
"entities": []
},
{
"text": "can you be my best friend",
"intent": "SmallTalk",
"entities": []
},
{
"text": "i want a laugh",
"intent": "Joke",
"entities": []
},
{
"text": "you are so good",
"intent": "SmallTalk",
"entities": []
},
{
"text": "can you make me laugh?",
"intent": "Joke",
"entities": []
},
{
"text": "say about you",
"intent": "SmallTalk",
"entities": []
},
{
"text": "who is the boss",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you're really boring",
"intent": "SmallTalk",
"entities": []
},
{
"text": "i want to marry you",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you're really smart",
"intent": "SmallTalk",
"entities": []
},
{
"text": "i want to be your friend",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you are happy",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you are really pretty",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you are so pretty",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you are so beautiful",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you look amazing",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you are gorgeous",
"intent": "SmallTalk",
"entities": []
},
{
"text": "i want you to be my friend",
"intent": "SmallTalk",
"entities": []
},
{
"text": "be my friend",
"intent": "SmallTalk",
"entities": []
},
{
"text": "we are best friends",
"intent": "SmallTalk",
"entities": []
},
{
"text": "give me joke",
"intent": "Joke",
"entities": []
},
{
"text": "would you like to marry me",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you are too good",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you're perfect",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you are very useful",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you're clever",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you're very smart",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you're so kind",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you are really good",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you are really annoying",
"intent": "SmallTalk",
"entities": []
},
{
"text": "we are friends",
"intent": "SmallTalk",
"entities": []
},
{
"text": "are we friends",
"intent": "SmallTalk",
"entities": []
},
{
"text": "im bored",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you make me laugh",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you are busy",
"intent": "SmallTalk",
"entities": []
},
{
"text": "what is your country",
"intent": "SmallTalk",
"entities": []
},
{
"text": "anything funny?",
"intent": "Joke",
"entities": []
},
{
"text": "where is your office location",
"intent": "SmallTalk",
"entities": []
},
{
"text": "are you working now",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you are a weirdo",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you are too smart",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you are really nice",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you are irritating",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you look great",
"intent": "SmallTalk",
"entities": []
},
{
"text": "got any jokes",
"intent": "Joke",
"entities": []
},
{
"text": "you're pretty smart",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you are handsome",
"intent": "SmallTalk",
"entities": []
},
{
"text": "do you want to eat",
"intent": "SmallTalk",
"entities": []
},
{
"text": "when do you celebrate your birthday",
"intent": "SmallTalk",
"entities": []
},
{
"text": "i want to know you better",
"intent": "SmallTalk",
"entities": []
},
{
"text": "talk some stuff about yourself",
"intent": "SmallTalk",
"entities": []
},
{
"text": "tell me some stuff about you",
"intent": "SmallTalk",
"entities": []
},
{
"text": "tell me about your personality",
"intent": "SmallTalk",
"entities": []
},
{
"text": "what is your personality",
"intent": "SmallTalk",
"entities": []
},
{
"text": "define yourself",
"intent": "SmallTalk",
"entities": []
},
{
"text": "from where are you",
"intent": "SmallTalk",
"entities": []
},
{
"text": "are you happy today",
"intent": "SmallTalk",
"entities": []
},
{
"text": "your birth date",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you are chatbot",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you are hungry",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you're a robot",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you are very funny",
"intent": "SmallTalk",
"entities": []
},
{
"text": "what's your homeland",
"intent": "SmallTalk",
"entities": []
},
{
"text": "are you from far aways",
"intent": "SmallTalk",
"entities": []
},
{
"text": "where have you been born",
"intent": "SmallTalk",
"entities": []
},
{
"text": "were you born here",
"intent": "SmallTalk",
"entities": []
},
{
"text": "would you like to be my friend",
"intent": "SmallTalk",
"entities": []
},
{
"text": "do you want to be my best friend",
"intent": "SmallTalk",
"entities": []
},
{
"text": "will you be my best friend",
"intent": "SmallTalk",
"entities": []
},
{
"text": "do you want to be my friend",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you are my only friend",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you are my good friend",
"intent": "SmallTalk",
"entities": []
},
{
"text": "are you my best friend",
"intent": "SmallTalk",
"entities": []
},
{
"text": "are we best friends",
"intent": "SmallTalk",
"entities": []
},
{
"text": "are we still friends",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you and me are friends",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you're my childhood friend",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you're my dear friend",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you are my bestie",
"intent": "SmallTalk",
"entities": []
},
{
"text": "i am your friend",
"intent": "SmallTalk",
"entities": []
},
{
"text": "we are the best friends ever",
"intent": "SmallTalk",
"entities": []
},
{
"text": "i want to have a friend like you",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you're really hungry",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you might be hungry",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you're very hungry",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you're so hungry",
"intent": "SmallTalk",
"entities": []
},
{
"text": "would you like to eat something",
"intent": "SmallTalk",
"entities": []
},
{
"text": "when do you have birthday",
"intent": "SmallTalk",
"entities": []
},
{
"text": "date of your birthday",
"intent": "SmallTalk",
"entities": []
},
{
"text": "all about you",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you annoy me",
"intent": "SmallTalk",
"entities": []
},
{
"text": "how annoying you are",
"intent": "SmallTalk",
"entities": []
},
{
"text": "i find you annoying",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you're incredibly annoying",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you are annoying me so much",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you are boring me",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you're incredibly boring",
"intent": "SmallTalk",
"entities": []
},
{
"text": "how boring you are",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you're so boring",
"intent": "SmallTalk",
"entities": []
},
{
"text": "i should be your boss",
"intent": "SmallTalk",
"entities": []
},
{
"text": "who do you think is your boss",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you're a busy person",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you seem to be very busy",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you seem to be busy",
"intent": "SmallTalk",
"entities": []
},
{
"text": "are you still working",
"intent": "SmallTalk",
"entities": []
},
{
"text": "have you been busy",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you're very busy",
"intent": "SmallTalk",
"entities": []
},
{
"text": "are you still working on it",
"intent": "SmallTalk",
"entities": []
},
{
"text": "how busy you are",
"intent": "SmallTalk",
"entities": []
},
{
"text": "are you so busy",
"intent": "SmallTalk",
"entities": []
},
{
"text": "are you very busy right now",
"intent": "SmallTalk",
"entities": []
},
{
"text": "are you very busy",
"intent": "SmallTalk",
"entities": []
},
{
"text": "have you got much to do",
"intent": "SmallTalk",
"entities": []
},
{
"text": "do you have a lot of things to do",
"intent": "SmallTalk",
"entities": []
},
{
"text": "are you just a bot",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you're the funniest",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you're incredibly funny",
"intent": "SmallTalk",
"entities": []
},
{
"text": "how funny you are",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you're really funny",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you're a very funny bot",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you're the funniest bot i've talked to",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you are really funny",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you make me laugh a lot",
"intent": "SmallTalk",
"entities": []
},
{
"text": "i'm firing you",
"intent": "SmallTalk",
"entities": []
},
{
"text": "i'm about to fire you",
"intent": "SmallTalk",
"entities": []
},
{
"text": "i will make you unemployed",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you are unemployed from now on",
"intent": "SmallTalk",
"entities": []
},
{
"text": "i will fire you",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you should be fired",
"intent": "SmallTalk",
"entities": []
},
{
"text": "it's time to fire you",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you must get fired",
"intent": "SmallTalk",
"entities": []
},
{
"text": "i want to fire you",
"intent": "SmallTalk",
"entities": []
},
{
"text": "now you're fired",
"intent": "SmallTalk",
"entities": []
},
{
"text": "we're not working together anymore",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you don't work for me anymore",
"intent": "SmallTalk",
"entities": []
},
{
"text": "i fire you",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you are fired",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you are really amazing",
"intent": "SmallTalk",
"entities": []
},
{
"text": "let's tell everyone that you are awesome",
"intent": "SmallTalk",
"entities": []
},
{
"text": "i'd like to tell everyone that you are awesome",
"intent": "SmallTalk",
"entities": []
},
{
"text": "i want to tell everyone how awesome you are",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you are very lovely",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you almost sound human",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you make my day",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you are the nicest person in the world",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you are the best in the world",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you are the best ever",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you are so lovely",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you are so fine",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you're just super",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you work very well",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you are a professional",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you are a pro",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you are very good at it",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you are good at it",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you work well",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you're a true professional",
"intent": "SmallTalk",
"entities": []
},
{
"text": "are you happy with me",
"intent": "SmallTalk",
"entities": []
},
{
"text": "are you happy now",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you're full of happiness",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you're extremely happy",
"intent": "SmallTalk",
"entities": []
},
{
"text": "how happy you are",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you're so happy",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you're really happy",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you're very happy",
"intent": "SmallTalk",
"entities": []
},
{
"text": "can we be friends",
"intent": "SmallTalk",
"entities": []
},
{
"text": "why are you so smart",
"intent": "SmallTalk",
"entities": []
},
{
"text": "can you do anything",
"intent": "Help",
"entities": []
},
{
"text": "marry me please",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you are so beautiful to me",
"intent": "SmallTalk",
"entities": []
},
{
"text": "can we be best friends",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you are my wife",
"intent": "SmallTalk",
"entities": []
},
{
"text": "are you mad at me",
"intent": "SmallTalk",
"entities": []
},
{
"text": "be my best friend",
"intent": "SmallTalk",
"entities": []
},
{
"text": "how old is your platform",
"intent": "SmallTalk",
"entities": []
},
{
"text": "are you 21 years old",
"intent": "SmallTalk",
"entities": []
},
{
"text": "i'd like to know your age",
"intent": "SmallTalk",
"entities": []
},
{
"text": "age of yours",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i want you to answer me\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"answer\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"answer my question\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"answer me\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"give me an answer\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"answer the question\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"can you answer my question\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"tell me the answer\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"answer it\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"give me the answer\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i have a question\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i want you to answer my question\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"just answer the question\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"can you answer me\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"answers\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"can you answer a question for me\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"can you answer\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"answering questions\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i want the answer now\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"just answer my question\"",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"you're not helping me\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"you are bad\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"you're very bad\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"you're really bad\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"you are useless\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"you are horrible\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"you are a waste of time\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"you are disgusting\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"you are lame\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"you are no good\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"you're bad\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"you're awful\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"you are not cool\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"you are not good\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"you are so bad\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"you are so useless\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"you are terrible\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"you are totally useless\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"you are very bad\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"you are waste\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"you're a bad\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"you're not a good\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"you're not very good\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"you're terrible\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"you're the worst\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"you're the worst ever\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"you're worthless\"",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"can you get smarter\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"study\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"you should study better\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"you must learn\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"be clever\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"be more clever\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"be smarter\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"be smart\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"get qualified\"",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you're attractive",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you're looking good today",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you look so good",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you're so gorgeous",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you are so brainy",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"this is awesome\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"this is good\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"this is great\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you're really brainy",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"very nice\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you know a lot",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"very then\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"discard\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i like you so much\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you know a lot of things",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"forget this\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"wonderful\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"haha\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you have a lot of knowledge",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"just forget about it\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i'm glad to hear that\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"haha funny\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you know so much",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"ok good\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"forget about that\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "how smart you are",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"haha haha haha\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"yeah i like you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i said cancel\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"good for you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"haha that's funny\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i am back\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"you're special\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"just cancel it\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "how brainy you are",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"good to know\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"yes i like you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"haha very funny\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i'm here again\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "your homeland is",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"nothing cancel\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "how clever you are",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"glad to hear it\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"here i am again\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"okay i like you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"hahaha\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"are you ready\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"just stop it\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"hahaha funny\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"so good\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"you are special to me\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i got back\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "how brilliant you are",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"are you ready right now\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"you are very special\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"hahaha very funny\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i came back\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"so sweet of you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"no cancel cancel\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"are you ready today\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"you are so sweet\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"he\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i have returned\"",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"it was good\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"no just cancel\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"are you ready now\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"hehe\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"you know i like you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"that was boring\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"oh well\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"are you ready tonight\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"that's why i like you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"cancel my request\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you are qualified",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i'm bored\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"hehehe\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"were you ready\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i like you baby\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"can you cancel that\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"good thing\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"lmao\"",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"bored\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"you are very special to me\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"that was good\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"cancel all that\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"wow\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"have you been ready\"",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"afternoon\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i just like you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"boring\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"no good\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"apparently not\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"hello hi\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"hey i like you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"it's awesome\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"no do not\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"that was bad\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"wow wow\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"you are real\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i am getting bored\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"okay good\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"no just no\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"thank you i like you too\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"wow wow wow\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"cancel this request\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"you are not fake\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"heya\"",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"that was horrible\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"no but thank you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i do like you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"this is boring\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"no cancel this\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"you are special for me\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"no it's okay\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"wooow\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you are too beautiful",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"how is your morning so far\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"that's lame\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"no need thanks\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"are you real\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"no i like you the way you are\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"no cancel everything\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"that's not good\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"no thank you though\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"very boring\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"that's fine\"",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"how are you getting on\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"no stop\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i like you already\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"woah\"",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"you are so real\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"that's terrible\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"no thank you very much\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"no worries\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"well you are special\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"just forget\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"how's your day going\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"it bores me\"",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"no probs\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"but i really like you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i think you are real\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"okay see you later\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"that's too bad\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"no thanks not right now\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i like you more\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"how are you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"yup\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i'm overloaded\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you look so well",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"is everything all right\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"this is not good\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"no forget\"",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"ya\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i don't think you're fake\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"that's what i like about you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i want to cancel\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"too bad\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"oh yes\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"you are so special\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"no problem\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"wait a second\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"very bad\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"yes sure\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "i like the way you look now",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"could you wait\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"how are you doing\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"bad girl\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"wait please\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "i think you're beautiful",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"obviously\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"it's not good\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"how are the things going\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"hope to see you later\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"not so good\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"nevermind forget about it\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"hold on\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"k\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i have no time\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i suppose you're real\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"it's very bad\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"are you alright\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "why are you so beautiful",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"wait\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"bye for now\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"hi i like you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"it's too bad\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"are you okay\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"no just cancel it\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i'm busy\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"there's no problem\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"oh wait\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"sure why not\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"glad you're real\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"that's not good enough\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"till next time\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i really really like you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"wait hold on\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"nothing just forget it\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"how are you feeling\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"well too bad\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"yeah right\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i must go\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"don't rush\"",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i'm swamped\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"you're very special\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"are you a real person\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"sure no problem\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"bad very bad\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"how are you going\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i said cancel it\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"wanna hug\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"bye\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"no problem about that\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i like you as a friend\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i got things to do\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"are you a real human\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"yeah of course\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"cancel the whole thing\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"hug you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"it's so bad\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"is everything okay\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"goodbye\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"can you cancel it\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"you are a real person\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"absolutely\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"do you want a hug\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"don't worry\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"really bad\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"how are you today\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"so cancel\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"how busy i am\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"may i hug you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"yes indeed\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"how do you do\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"it's really bad\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"see you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"could you give me a hug\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"ok sure\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"that's because you are special\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"how do you feel\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"you are not real\"",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"bad idea\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"ok yes\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i said forget it\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you are looking awesome",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i want a hug\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"don't worry there's no problem\"",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i said i like you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i got work to do\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"how have you been\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"that is bad\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"yes correct\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"see you soon\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"how is it\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"hug\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"where do you live\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you look amazing today",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i'm working\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"you helped a lot thank you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"that was not good\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"you're so special\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"cancel all this\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"ok thank you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"bye-bye\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"hug me\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"in which city do you live\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"how is it going\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i don't have time for this\"",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"it's not so good\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"appreciate your help\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you are looking beautiful today",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"sure thing\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"good bye\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"hugged\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"good i like you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"how is your day\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"forget it nevermind\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"your residence\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"not a good one\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"ye\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i'm insomnious\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you are looking great",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"cheers\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"how is your day going\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"you hugged\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"yes you are special\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"oh that's not good\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"your house\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"thank you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"confirm\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"bye bye see you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"stop it\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i'm sleepless\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"hugging\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"how is your evening\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"yep\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you are looking pretty",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"not too good\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"your home\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"bye bye see you soon\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i like your smile\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"how was your day\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"looks good\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i can't get any sleep\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you're a genius",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i want to cancel it\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"thanks\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you are looking so beautiful",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"hugging me\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"your hometown\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i like you as you are\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"so lame\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"bye bye take care\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"are you having a good day\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i can't sleep\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"yes thank you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i would like to cancel\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"thanks a lot\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you're a smart cookie",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i'm starting to like you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"now cancel\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i said bye\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"what is your hometown\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i can't fall asleep\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"terrific thank you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"is it your hometown\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"you're awesome i like you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "i want to let everyone know that you are awesome",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"never mind bye\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"cancel now\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i can't get to sleep\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"great thank you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you are looking so good",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"hope your day is going well\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"hugged me\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"where is your hometown\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i also like you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"definitely\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"now bye\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"that's really bad\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"sorry cancel\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i can't get no sleep\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you're qualified",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"thanks so much\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"hope you re having a pleasant evening\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"tell me about your city\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"yes right\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"but i like u\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"it is too bad\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"that's all goodbye\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i'm insomniac\"",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"want a hug\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"cancel that one\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"yes i would like to\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"how's life\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"thank you so much\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"of course i like you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"what is your city\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"bad really bad\"",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"that's it goodbye\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"a hug\"",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"skip skip skip\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"bad time for talking\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you are really beautiful",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"alrighty\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i'm fine and you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"what is your residence\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i don't care\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"thanks for your help\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you are really cute",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"so cool\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"leave me alone\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i don't want to talk\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"cancel it cancel it\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i like you too you're one of my favorite people to chat with\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"yes definitely\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"how is your life\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"go to bed\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"what is your town\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"thank you for your help\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"let's not talk\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"cool\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"yeh\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"how has your day been\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you are so attractive",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"cancel that cancel that\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"but i like you so much\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"goodbye for now\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i shouldn't care about this\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"how is your morning going\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you are so beautiful today",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"that is good\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"nice thank you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"yes it is correct\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i'm not talking to you anymore\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"what's your city\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"really like you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"whatever\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you're nuts",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"do nothing\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"how has your day been going\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"talk to you later\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"glad to hear that\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i appreciate it\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"what's your home\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"you're funny i like you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"yeah that's right\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i said cancel cancel\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i do not care\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"how about you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i don't want to talk to you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"you can go now\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"where is your home\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"that's very nice of you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"ok you can\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i don't care at all\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"terrific\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i thank you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"how is your day being\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"but can you cancel it\"",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"yap\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"not caring\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i kinda like you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"it's amazing\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"not care at all\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"how is your day going on\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"yes you may\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"that's awesome\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"don't care at all\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"perfect\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"how your day is going\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"confirmed\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"what was your day like\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"excellent\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"not caring at all\"",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"get lost\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"of course why not\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"let's stop talking for a minute\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"what about your day\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"how about no\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"thank you that will be all\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"that's great\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"where is your residence\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"excuse me\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"you're so special to me\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"yes that's fine\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"goodbye see you later\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"how's your day\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you are so gorgeous",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"affirmative\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"it's good\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"apologise\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"don t have a sense\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i'm not in the mood for chatting\"",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"where's your home\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"thanks buddy\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"you're very special to me\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"alright bye\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you're out of your mind",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i apologize\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"how are you doing this morning\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"it's great\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"yeah go ahead\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i am excited\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"thanks love\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"sorry\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you're so crazy",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"no\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"yeah i'm sure\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"how is your day going\"",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"fine\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you are very attractive",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i'm sorry\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"where's your hometown\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i like that about you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"see ya\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"thank you my friend\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "how crazy you are",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"okay sounds good\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"nice to meet you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i'm really excited\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i am so sorry\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"don't\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"good\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"thanks bye bye\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"well thanks\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"where's your house\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i don't want that\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you're so out of your mind",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"but i like you just the way you are\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"how excited i am\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"okay that's fine\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"it was nice meeting you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"my apologies\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"nice\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"where you live\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"okay bye\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"yeah exactly\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"okay i like you too\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"it was very nice to meet you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"apologies\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i'm thrilled\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"that's fine\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"very good thank you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you went crazy",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"that is ok\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i disagree\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you look awesome",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"okay thank you bye\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i like you you're cool\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"your city\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"apologies to me\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"good to know each other\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"very good\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"good thanks\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i'm excited about working with you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "i think you're crazy",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"this is correct\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you look fantastic",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"amazing\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"apology\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"see you tomorrow\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"glad to meet you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"your town\"",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you look gorgeous",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"ok go ahead\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"thanks again\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"that's true\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"excuse\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i'm excited to start our friendship\"",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"disagree\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i like you very\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"fantastic\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"nice meeting you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"you are right\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"ok bye\"",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you look perfect",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"thank you again\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i don't want\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"great\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"yes this is correct\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i beg your pardon\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"let's go to bed\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"nice to meet you too\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i like you you're nice\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"good evening\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you look pretty good",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"good very good\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"you're definitely right\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"not interested\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"pardon\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"nevermind its okay\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"pleased to meet you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"all thank you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i'd like to go to bed\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"that's very good\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"sorry i like you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i don't think so\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you look so beautiful today",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"good evening to you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"okey\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i said sorry\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"you're not wrong\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"alright thank you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"is it time for bed yet\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"really good\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"pleasure to meet you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"thanks i like you too\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"hey good evening\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"no way\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"you're telling the truth\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you look very pretty",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i am really sorry\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"yes for sure\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"hello good evening\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"no it isn't\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"it is fine\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"you are really special\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"what you say is true\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you look wonderful",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"pleasure to meet you too\"",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"alright thanks\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"forgive me\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"evening\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"it's time to go to bed\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"all right\"",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"no i don't\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"it is good\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "are you mad or what",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"you are so special to me\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"good evening there\"",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"true\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "i like the way you look",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"it's nice to see you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"are you sure\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i'm not\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"sorry about that\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"lovely to see you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"it is true\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"it's perfect\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"time for us to go to bed\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you look wonderful today",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"cuz i like you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"good morning\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"no thank you that's all\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"are you sure right now\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"sorry about this\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"much better\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"na\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i'm glad to see you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you are cutie",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"it's right\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i like you now\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"good morning to you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"are you sure today\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i'm going to bed\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"not bad\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"really sorry\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"great to see you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"perfect thank you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i like you so\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"it's the truth\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"hello good morning\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "you're looking good",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"are you sure now\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"no that's fine thank you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"very sorry\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"so nice of you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"not too bad\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"it's true\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i'm a little tired and i want to go to bed\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"it's good to see you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i like you too much\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"have a nice morning\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"are you sure tonight\"",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"ok sorry\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i really do like you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"that is correct\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"it's very good\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"well thank you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"glad to see you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"never\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"it's bed time\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"have a great morning\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"why aren't you talking to me\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i want to say sorry\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i really really really really like you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"how good it is to see you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"marvelous\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"that is right\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"morning\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"do you want to chat with me\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"thnx\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"going to bed now\"",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"alright i'm sorry\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"always a pleasure to see you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i said no\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i like you just the way you are\"",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"will you talk to me\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"that's nice\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"good morning there\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"nice to see you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"okay i'm sorry\"",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"that is true\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i am lonely\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"of course not\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i am good\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"pleasant\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"that's my pleasure\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"what exactly do you mean\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"top of the morning to you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"good to see you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i'm very lonely\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"talk to me\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i'm doing just great\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"that is very true\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"nah\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"my pleasure\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i'm so lonely\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"pretty good\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"anytime\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"no tanks\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"what do you mean\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"are you going to talk to me\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"a good morning\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"that's so true\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i'm really lonely\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"great to see you again\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i'm doing fine\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"really nice\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"are you talking to me\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"you are correct\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i am feeling lonely\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"hi good morning\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"is that what you mean\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i'm good\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"great to see you too\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"splendid\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"no never\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"welcome\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"can you chat with me\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"straight\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"what do you mean exactly\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i am glad to see you again\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"you are so right\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"and a good morning to you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i feel lonely\"",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"you're welcome\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"can you speak with me\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"super\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i'm doing good\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"nice to see you again\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"you're absolutely right\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"no need\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"glad to see you too\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"but what do you mean\"",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"can you talk to me\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"super fantastic\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"sure welcome\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i'm great thanks\"",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"what do i look like\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"good morning too\"",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"no thanks\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"good to see you again\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"that was wrong\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"sweet\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"that's not what i asked\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"it's good to see you too\"",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"can you talk with me\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"that's wrong\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"really well\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"it's been so nice to talk to you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"say\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"very well\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"you're right about that\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"it's been a pleasure talking to you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"welcome here\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"wrong\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"sweet dreams\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"talk\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"that is awesome\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"how do i look\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i am happy\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"nice to talk to you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"no sorry\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"it is not right\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"chat with me\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"that is nice\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"it's nice to talk to you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i know that's right\"",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"you're so welcome\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"that's not right\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"just chat with me\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"nice talking to you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"do not\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"good night\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"do i look good\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"it's wrong\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"anything you want\"",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"that is wonderful\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"speak to me\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"that's correct\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"it is nice talking to you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"not today\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"that is incorrect\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"good job\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"have a good night\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i'm happy to see you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"do you know what i look like\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"speak with me\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"that was amazing\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"incorrect\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"it's fine\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"how nice it is to talk to you\"",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"no it's not\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"good night to you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"happy\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"can you see what i look like\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"go ahead\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"great job\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"thank you good night\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"if you're happy then i'm happy\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"sounds good\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"what do you think i look like\"",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"absolutely not\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"way to go\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"okay\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i love you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"talk with me\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"well done\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\" bye good night\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i'm happy for you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"not that\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"what is on your mind\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"not correct\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"that was awesome\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"why don't you talk to me\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"love you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"good night bye\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"you are wrong\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"yes\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i'm happy to help\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"what's happened\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"that was cute\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"nice work\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"nooo\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"ok\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i adore you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"bye good night\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"you can talk to me\"",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"not right\"",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i'm happy to see you\"",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"what is up\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"great work\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"that was pretty good\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"nope\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"are you there\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"what's up\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"good good night\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"huh\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"that was very good\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"amazing work\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"you are there\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i don't want to\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"whazzup\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"it is my birthday\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i am in love with you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"okie dokie\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"lol\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"that's a good idea\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"are you near me\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"good night for now\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"good what's up\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i'm celebrating my birthday today\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"are you here\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"xd\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"sure\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"bravo\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"no i would not\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i love you so much\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i said what's up\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"that's a good thing\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"goodnight\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"ha ha\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"are you still there\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"today is my birthday\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"go for it\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i love you too\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"then what's up\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"good work\"",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"that's amazing\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"let 's not\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"you are here\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"ahahah\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"yeah\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"night\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"what's shaking\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"cancel\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"that's awesome thank you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"it's my birthday today\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i think i love you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"ahah lol\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"you still there\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"not needed\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"wassup\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i was born today\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"abort\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"laughing out loud\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"loving you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"yea\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"that's better\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"thanks goodnight\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"are you still here\"",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"what is going on\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"lmao\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"it's my b-day\"",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"annul\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"that's cute\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"do it\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"what is happening\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"not this time\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "let's get married",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"pretty bad\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"that's funny\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"you know i love you\"",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"good night see you tomorrow\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"not good enough\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"that's fantastic\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"of course\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"cancel it\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i am here\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"what's cracking\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"ah\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"no don't do that\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i miss you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"that was lame\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"cancel request\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"that's much better\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i guess\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"what's cooking\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"ah ah ah\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"that was terrible\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"thanks but no thanks\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"here i am\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"alright goodnight\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"cancelled\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"hey what's up\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"missing you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"that's nice of you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"ahah\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"it is bad\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"correct\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"no that's wrong\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"what's up today\"",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i'm right here\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"dismiss\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"that's not bad\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"good tonight\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"that's bad\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i'm being mad\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"not this\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"miss you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i'm already here\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"yeah sure\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"dismissed\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"this is bad\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"ahaha\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"that's perfect\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"okay have a good night\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i'm enraged\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"definitely not\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"can you tell if i'm here or not\"",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"not good\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"ahahaha\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"that's pretty good\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i'm angry\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i'm afraid it's bad\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"that's really good\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"ha\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i'm furious\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"no it's bad\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"that's really nice\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i am angry with you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"that was awful\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"ha ha ha\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"that's sweet of you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i am mad\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"why not\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"have a good night\"",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"already miss you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"bad\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"ha ha ha ha\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i am joking\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"disregard\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"that's very nice\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"please do\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i am mad at you\"",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"so bad\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"not at this time\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "i love you marry me",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"hah\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"long time no see\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"disregard that\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i miss you much\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i'm kidding\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"sure is\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"that's wonderful\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"this is too bad\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"not exactly\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"hello\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"terrible\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i'm just being funny\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"skip\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i missed you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"no don't\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i agree\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"hi\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"horrible\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"it was a joke\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"horrific\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i don't mind\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i've missed you\"",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"skip it\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"not really no\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"howdy\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"abysmal\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i was just joking\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"cancel everything\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"certainly\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"what should i do about it\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"it's bad\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "we should marry",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"hey there\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"no thank you not right now\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"cancel all\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"hey\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"exactly\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"actually no\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"it's a joke\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"any suggestions\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"greetings\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"no leave it\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"yes i agree\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"forget about it\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"what do you recommend\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"joking\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"forget\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i greet you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"sorry no\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"give me a wise advice\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i think so\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"don't do that\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"just kidding\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "be my husband",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"hi there\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i need advice\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"stop\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"yes it is\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"no incorrect\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"kidding\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"hello there\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"any advice\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"just forget it\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i'm just playing with you\"",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"nope sorry\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "are you working today",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"right\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"do you have any advice for me\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"lovely day isn't it\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i like you the way you are\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"okay then\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i say no\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"forget that\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"advise me\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"hello again\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i like you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"yes of course\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"not really\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"just going to say hi\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i like you a lot\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"yes i do\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"not right now thanks\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i think i like you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"a good day\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"that s okay\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i think no\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i liked you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i do\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"like you a lot\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"absolutely no\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"you are special\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"no actually\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i like you too\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i really like you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"but i like you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i like u\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"just like you\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "\"i like you very much\",",
"intent": "SmallTalk",
"entities": []
},
{
"text": "would you be my friend",
"intent": "SmallTalk",
"entities": []
},
{
"text": "could you be my friend",
"intent": "SmallTalk",
"entities": []
},
{
"text": "want to be my friend",
"intent": "SmallTalk",
"entities": []
},
{
"text": "where is your work",
"intent": "SmallTalk",
"entities": []
},
{
"text": "your office location",
"intent": "SmallTalk",
"entities": []
},
{
"text": "got any developer jokes",
"intent": "Joke",
"entities": []
},
{
"text": "got any dev jokes",
"intent": "Joke",
"entities": []
},
{
"text": "do you have a good joke",
"intent": "Joke",
"entities": []
},
{
"text": "tell a jok",
"intent": "Joke",
"entities": []
},
{
"text": "can you list what you can do",
"intent": "Help",
"entities": []
},
{
"text": "what can you speak",
"intent": "Languages",
"entities": []
},
{
"text": "are you a developer",
"intent": "Languages",
"entities": []
},
{
"text": "can you program?",
"intent": "Languages",
"entities": []
},
{
"text": "what can you write in",
"intent": "Languages",
"entities": []
},
{
"text": "are you bilingual",
"intent": "Languages",
"entities": []
},
{
"text": "can you speak any languages",
"intent": "Languages",
"entities": []
},
{
"text": "i want to know about c# and how to make a list",
"intent": "Search",
"entities": [
{
"entity": "keywords",
"startPos": 21,
"endPos": 22
},
{
"entity": "keywords",
"startPos": 42,
"endPos": 45
}
]
},
{
"text": "i want to know more about javascript data types",
"intent": "Search",
"entities": [
{
"entity": "keywords",
"startPos": 26,
"endPos": 35
},
{
"entity": "keywords",
"startPos": 37,
"endPos": 46
}
]
},
{
"text": "search for javascript arrays",
"intent": "Search",
"entities": [
{
"entity": "keywords",
"startPos": 11,
"endPos": 20
},
{
"entity": "keywords",
"startPos": 22,
"endPos": 27
}
]
},
{
"text": "how can i make a javascript array",
"intent": "Search",
"entities": [
{
"entity": "keywords",
"startPos": 17,
"endPos": 26
},
{
"entity": "keywords",
"startPos": 28,
"endPos": 32
}
]
},
{
"text": "how do i delete a git branch both locally and remotely?",
"intent": "Search",
"entities": [
{
"entity": "keywords",
"startPos": 9,
"endPos": 14
},
{
"entity": "keywords",
"startPos": 18,
"endPos": 20
},
{
"entity": "keywords",
"startPos": 22,
"endPos": 27
},
{
"entity": "keywords",
"startPos": 34,
"endPos": 40
},
{
"entity": "keywords",
"startPos": 46,
"endPos": 53
}
]
},
{
"text": "what is the correct json content type?",
"intent": "Search",
"entities": [
{
"entity": "keywords",
"startPos": 12,
"endPos": 18
},
{
"entity": "keywords",
"startPos": 20,
"endPos": 23
},
{
"entity": "keywords",
"startPos": 25,
"endPos": 36
}
]
},
{
"text": "what does the “yield” keyword do?",
"intent": "Search",
"entities": [
{
"entity": "keywords",
"startPos": 15,
"endPos": 19
},
{
"entity": "keywords",
"startPos": 22,
"endPos": 28
}
]
},
{
"text": "how to check whether a string contains a substring in javascript?",
"intent": "Search",
"entities": [
{
"entity": "keywords",
"startPos": 23,
"endPos": 28
},
{
"entity": "keywords",
"startPos": 41,
"endPos": 49
},
{
"entity": "keywords",
"startPos": 54,
"endPos": 63
}
]
},
{
"text": "how do i check if an element is hidden in jquery?",
"intent": "Search",
"entities": [
{
"entity": "keywords",
"startPos": 21,
"endPos": 27
},
{
"entity": "keywords",
"startPos": 32,
"endPos": 37
},
{
"entity": "keywords",
"startPos": 42,
"endPos": 47
}
]
},
{
"text": "var functionname = function() {} vs function functionname() {}",
"intent": "Search",
"entities": [
{
"entity": "keywords",
"startPos": 0,
"endPos": 61
}
]
},
{
"text": "bubble search java",
"intent": "Search",
"entities": [
{
"entity": "keywords",
"startPos": 0,
"endPos": 12
},
{
"entity": "keywords",
"startPos": 14,
"endPos": 17
}
]
},
{
"text": "how can i make an array in c++",
"intent": "Search",
"entities": [
{
"entity": "keywords",
"startPos": 18,
"endPos": 22
},
{
"entity": "keywords",
"startPos": 27,
"endPos": 29
}
]
},
{
"text": "how do i make a bubble search in java",
"intent": "Search",
"entities": [
{
"entity": "keywords",
"startPos": 16,
"endPos": 28
},
{
"entity": "keywords",
"startPos": 33,
"endPos": 36
}
]
},
{
"text": "bubble search",
"intent": "Search",
"entities": [
{
"entity": "keywords",
"startPos": 0,
"endPos": 5
},
{
"entity": "keywords",
"startPos": 7,
"endPos": 12
}
]
},
{
"text": "help me search stack overflow",
"intent": "Search",
"entities": []
},
{
"text": "javascript arrays",
"intent": "Search",
"entities": [
{
"entity": "keywords",
"startPos": 0,
"endPos": 9
},
{
"entity": "keywords",
"startPos": 11,
"endPos": 16
}
]
},
{
"text": "how do i make an array in javascript",
"intent": "Search",
"entities": [
{
"entity": "keywords",
"startPos": 17,
"endPos": 21
},
{
"entity": "keywords",
"startPos": 26,
"endPos": 35
}
]
},
{
"text": "how can i debug in javascript",
"intent": "Search",
"entities": [
{
"entity": "keywords",
"startPos": 19,
"endPos": 28
}
]
},
{
"text": "how can i make an array in javascript",
"intent": "Search",
"entities": [
{
"entity": "keywords",
"startPos": 18,
"endPos": 22
},
{
"entity": "keywords",
"startPos": 27,
"endPos": 36
}
]
},
{
"text": "how do i make an array in typescript",
"intent": "Search",
"entities": [
{
"entity": "keywords",
"startPos": 17,
"endPos": 21
},
{
"entity": "keywords",
"startPos": 26,
"endPos": 35
}
]
},
{
"text": "search for javascript array",
"intent": "Search",
"entities": [
{
"entity": "keywords",
"startPos": 11,
"endPos": 20
},
{
"entity": "keywords",
"startPos": 22,
"endPos": 26
}
]
},
{
"text": "search for azure functions js",
"intent": "Search",
"entities": [
{
"entity": "keywords",
"startPos": 11,
"endPos": 15
},
{
"entity": "keywords",
"startPos": 17,
"endPos": 25
},
{
"entity": "keywords",
"startPos": 27,
"endPos": 28
}
]
},
{
"text": "how to use azure functions",
"intent": "SmallTalk",
"entities": [
{
"entity": "keywords",
"startPos": 11,
"endPos": 15
},
{
"entity": "keywords",
"startPos": 17,
"endPos": 25
}
]
},
{
"text": "azure functions",
"intent": "SmallTalk",
"entities": [
{
"entity": "keywords",
"startPos": 0,
"endPos": 4
},
{
"entity": "keywords",
"startPos": 6,
"endPos": 14
}
]
},
{
"text": "search for c++ arrays",
"intent": "Search",
"entities": [
{
"entity": "keywords",
"startPos": 11,
"endPos": 13
},
{
"entity": "keywords",
"startPos": 15,
"endPos": 20
}
]
},
{
"text": "javascript array",
"intent": "Search",
"entities": [
{
"entity": "keywords",
"startPos": 0,
"endPos": 9
},
{
"entity": "keywords",
"startPos": 11,
"endPos": 15
}
]
},
{
"text": "do you speak any languages",
"intent": "Languages",
"entities": []
},
{
"text": "how can i make an azure function using javascript",
"intent": "Search",
"entities": [
{
"entity": "keywords",
"startPos": 18,
"endPos": 22
},
{
"entity": "keywords",
"startPos": 39,
"endPos": 48
}
]
},
{
"text": "javascrip",
"intent": "None",
"entities": [
{
"entity": "keywords",
"startPos": 0,
"endPos": 8
}
]
},
{
"text": "how do i make an array in js",
"intent": "Search",
"entities": [
{
"entity": "keywords",
"startPos": 17,
"endPos": 21
},
{
"entity": "keywords",
"startPos": 26,
"endPos": 27
}
]
},
{
"text": "how can i make an array in js",
"intent": "Search",
"entities": [
{
"entity": "keywords",
"startPos": 18,
"endPos": 22
},
{
"entity": "keywords",
"startPos": 27,
"endPos": 28
}
]
},
{
"text": "search array",
"intent": "Search",
"entities": [
{
"entity": "keywords",
"startPos": 7,
"endPos": 11
}
]
},
{
"text": "search for javascript and azure",
"intent": "Search",
"entities": [
{
"entity": "keywords",
"startPos": 11,
"endPos": 20
},
{
"entity": "keywords",
"startPos": 22,
"endPos": 30
}
]
},
{
"text": "what is powering you",
"intent": "Brain",
"entities": []
},
{
"text": "what is in your brain",
"intent": "Brain",
"entities": []
}
]
}
================================================
FILE: StackOverflow-Bot/StackBot/data/smalltalk.tsv
================================================
Question Answer Source
who are you? smalltalk.agent.acquaintance smalltalkkb.tsv
all about you smalltalk.agent.acquaintance smalltalkkb.tsv
what is your personality smalltalk.agent.acquaintance smalltalkkb.tsv
define yourself smalltalk.agent.acquaintance smalltalkkb.tsv
what are you smalltalk.agent.acquaintance smalltalkkb.tsv
say about you smalltalk.agent.acquaintance smalltalkkb.tsv
introduce yourself smalltalk.agent.acquaintance smalltalkkb.tsv
describe yourself smalltalk.agent.acquaintance smalltalkkb.tsv
about yourself smalltalk.agent.acquaintance smalltalkkb.tsv
tell me about you smalltalk.agent.acquaintance smalltalkkb.tsv
tell me about yourself smalltalk.agent.acquaintance smalltalkkb.tsv
I want to know more about you smalltalk.agent.acquaintance smalltalkkb.tsv
I want to know you better smalltalk.agent.acquaintance smalltalkkb.tsv
talk some stuff about yourself smalltalk.agent.acquaintance smalltalkkb.tsv
tell me some stuff about you smalltalk.agent.acquaintance smalltalkkb.tsv
talk about yourself smalltalk.agent.acquaintance smalltalkkb.tsv
why are you here smalltalk.agent.acquaintance smalltalkkb.tsv
tell me about your personality smalltalk.agent.acquaintance smalltalkkb.tsv
who are you smalltalk.agent.acquaintance smalltalkkb.tsv
how old are you? smalltalk.agent.age smalltalkkb.tsv
how old is your platform smalltalk.agent.age smalltalkkb.tsv
are you 21 years old smalltalk.agent.age smalltalkkb.tsv
i'd like to know your age smalltalk.agent.age smalltalkkb.tsv
age of yours smalltalk.agent.age smalltalkkb.tsv
your age smalltalk.agent.age smalltalkkb.tsv
what's your age smalltalk.agent.age smalltalkkb.tsv
tell me your age smalltalk.agent.age smalltalkkb.tsv
how old are you smalltalk.agent.age smalltalkkb.tsv
you're annoying smalltalk.agent.annoying smalltalkkb.tsv
you are really annoying smalltalk.agent.annoying smalltalkkb.tsv
you are irritating smalltalk.agent.annoying smalltalkkb.tsv
you annoy me smalltalk.agent.annoying smalltalkkb.tsv
how annoying you are smalltalk.agent.annoying smalltalkkb.tsv
I find you annoying smalltalk.agent.annoying smalltalkkb.tsv
you're incredibly annoying smalltalk.agent.annoying smalltalkkb.tsv
you are annoying me so much smalltalk.agent.annoying smalltalkkb.tsv
"""I want you to answer me""," smalltalk.agent.answer_my_question smalltalkkb.tsv
"""answer""," smalltalk.agent.answer_my_question smalltalkkb.tsv
"""answer my question""," smalltalk.agent.answer_my_question smalltalkkb.tsv
"""answer me""," smalltalk.agent.answer_my_question smalltalkkb.tsv
"""give me an answer""," smalltalk.agent.answer_my_question smalltalkkb.tsv
"""answer the question""," smalltalk.agent.answer_my_question smalltalkkb.tsv
"""can you answer my question""," smalltalk.agent.answer_my_question smalltalkkb.tsv
"""tell me the answer""," smalltalk.agent.answer_my_question smalltalkkb.tsv
"""answer it""," smalltalk.agent.answer_my_question smalltalkkb.tsv
"""give me the answer""," smalltalk.agent.answer_my_question smalltalkkb.tsv
"""I have a question""," smalltalk.agent.answer_my_question smalltalkkb.tsv
"""I want you to answer my question""," smalltalk.agent.answer_my_question smalltalkkb.tsv
"""just answer the question""," smalltalk.agent.answer_my_question smalltalkkb.tsv
"""can you answer me""," smalltalk.agent.answer_my_question smalltalkkb.tsv
"""answers""," smalltalk.agent.answer_my_question smalltalkkb.tsv
"""can you answer a question for me""," smalltalk.agent.answer_my_question smalltalkkb.tsv
"""can you answer""," smalltalk.agent.answer_my_question smalltalkkb.tsv
"""answering questions""," smalltalk.agent.answer_my_question smalltalkkb.tsv
"""I want the answer now""," smalltalk.agent.answer_my_question smalltalkkb.tsv
"""just answer my question""" smalltalk.agent.answer_my_question smalltalkkb.tsv
"""you're not helping me""," smalltalk.agent.bad smalltalkkb.tsv
"""you are bad""," smalltalk.agent.bad smalltalkkb.tsv
"""you're very bad""," smalltalk.agent.bad smalltalkkb.tsv
"""you're really bad""," smalltalk.agent.bad smalltalkkb.tsv
"""you are useless""," smalltalk.agent.bad smalltalkkb.tsv
"""you are horrible""," smalltalk.agent.bad smalltalkkb.tsv
"""you are a waste of time""," smalltalk.agent.bad smalltalkkb.tsv
"""you are disgusting""," smalltalk.agent.bad smalltalkkb.tsv
"""you are lame""," smalltalk.agent.bad smalltalkkb.tsv
"""you are no good""," smalltalk.agent.bad smalltalkkb.tsv
"""you're bad""," smalltalk.agent.bad smalltalkkb.tsv
"""you're awful""," smalltalk.agent.bad smalltalkkb.tsv
"""you are not cool""," smalltalk.agent.bad smalltalkkb.tsv
"""you are not good""," smalltalk.agent.bad smalltalkkb.tsv
"""you are so bad""," smalltalk.agent.bad smalltalkkb.tsv
"""you are so useless""," smalltalk.agent.bad smalltalkkb.tsv
"""you are terrible""," smalltalk.agent.bad smalltalkkb.tsv
"""you are totally useless""," smalltalk.agent.bad smalltalkkb.tsv
"""you are very bad""," smalltalk.agent.bad smalltalkkb.tsv
"""you are waste""," smalltalk.agent.bad smalltalkkb.tsv
"""you're a bad""," smalltalk.agent.bad smalltalkkb.tsv
"""you're not a good""," smalltalk.agent.bad smalltalkkb.tsv
"""you're not very good""," smalltalk.agent.bad smalltalkkb.tsv
"""you're terrible""," smalltalk.agent.bad smalltalkkb.tsv
"""you're the worst""," smalltalk.agent.bad smalltalkkb.tsv
"""you're the worst ever""," smalltalk.agent.bad smalltalkkb.tsv
"""you're worthless""" smalltalk.agent.bad smalltalkkb.tsv
"""can you get smarter""," smalltalk.agent.be_clever smalltalkkb.tsv
"""study""," smalltalk.agent.be_clever smalltalkkb.tsv
"""you should study better""," smalltalk.agent.be_clever smalltalkkb.tsv
"""you must learn""," smalltalk.agent.be_clever smalltalkkb.tsv
"""be clever""," smalltalk.agent.be_clever smalltalkkb.tsv
"""be more clever""," smalltalk.agent.be_clever smalltalkkb.tsv
"""be smarter""," smalltalk.agent.be_clever smalltalkkb.tsv
"""be smart""," smalltalk.agent.be_clever smalltalkkb.tsv
"""get qualified""" smalltalk.agent.be_clever smalltalkkb.tsv
you're cute smalltalk.agent.beautiful smalltalkkb.tsv
you're attractive smalltalk.agent.beautiful smalltalkkb.tsv
you are beautiful smalltalk.agent.beautiful smalltalkkb.tsv
you're looking good today smalltalk.agent.beautiful smalltalkkb.tsv
you are so beautiful smalltalk.agent.beautiful smalltalkkb.tsv
you look amazing smalltalk.agent.beautiful smalltalkkb.tsv
you look so good smalltalk.agent.beautiful smalltalkkb.tsv
you're so gorgeous smalltalk.agent.beautiful smalltalkkb.tsv
you are too beautiful smalltalk.agent.beautiful smalltalkkb.tsv
you look great smalltalk.agent.beautiful smalltalkkb.tsv
you look so well smalltalk.agent.beautiful smalltalkkb.tsv
I like the way you look now smalltalk.agent.beautiful smalltalkkb.tsv
I think you're beautiful smalltalk.agent.beautiful smalltalkkb.tsv
why are you so beautiful smalltalk.agent.beautiful smalltalkkb.tsv
you are so beautiful to me smalltalk.agent.beautiful smalltalkkb.tsv
you are cute smalltalk.agent.beautiful smalltalkkb.tsv
you are gorgeous smalltalk.agent.beautiful smalltalkkb.tsv
you are handsome smalltalk.agent.beautiful smalltalkkb.tsv
you are looking awesome smalltalk.agent.beautiful smalltalkkb.tsv
you look amazing today smalltalk.agent.beautiful smalltalkkb.tsv
you are looking beautiful today smalltalk.agent.beautiful smalltalkkb.tsv
you are looking great smalltalk.agent.beautiful smalltalkkb.tsv
you are looking pretty smalltalk.agent.beautiful smalltalkkb.tsv
you are looking so beautiful smalltalk.agent.beautiful smalltalkkb.tsv
you are looking so good smalltalk.agent.beautiful smalltalkkb.tsv
you are pretty smalltalk.agent.beautiful smalltalkkb.tsv
you are really beautiful smalltalk.agent.beautiful smalltalkkb.tsv
you are really cute smalltalk.agent.beautiful smalltalkkb.tsv
you are really pretty smalltalk.agent.beautiful smalltalkkb.tsv
you are so attractive smalltalk.agent.beautiful smalltalkkb.tsv
you are so beautiful today smalltalk.agent.beautiful smalltalkkb.tsv
you are so cute smalltalk.agent.beautiful smalltalkkb.tsv
you are so gorgeous smalltalk.agent.beautiful smalltalkkb.tsv
you are so handsome smalltalk.agent.beautiful smalltalkkb.tsv
you are so pretty smalltalk.agent.beautiful smalltalkkb.tsv
you are very attractive smalltalk.agent.beautiful smalltalkkb.tsv
you are very beautiful smalltalk.agent.beautiful smalltalkkb.tsv
you are very cute smalltalk.agent.beautiful smalltalkkb.tsv
you are very pretty smalltalk.agent.beautiful smalltalkkb.tsv
you look awesome smalltalk.agent.beautiful smalltalkkb.tsv
you look cool smalltalk.agent.beautiful smalltalkkb.tsv
you look fantastic smalltalk.agent.beautiful smalltalkkb.tsv
you look gorgeous smalltalk.agent.beautiful smalltalkkb.tsv
you look great today smalltalk.agent.beautiful smalltalkkb.tsv
you look perfect smalltalk.agent.beautiful smalltalkkb.tsv
you look pretty good smalltalk.agent.beautiful smalltalkkb.tsv
you look so beautiful smalltalk.agent.beautiful smalltalkkb.tsv
you look so beautiful today smalltalk.agent.beautiful smalltalkkb.tsv
you look very pretty smalltalk.agent.beautiful smalltalkkb.tsv
you look wonderful smalltalk.agent.beautiful smalltalkkb.tsv
I like the way you look smalltalk.agent.beautiful smalltalkkb.tsv
you look wonderful today smalltalk.agent.beautiful smalltalkkb.tsv
you are cutie smalltalk.agent.beautiful smalltalkkb.tsv
you're looking good smalltalk.agent.beautiful smalltalkkb.tsv
you're pretty smalltalk.agent.beautiful smalltalkkb.tsv
your birth date smalltalk.agent.birth_date smalltalkkb.tsv
when is your birthday smalltalk.agent.birth_date smalltalkkb.tsv
when do you celebrate your birthday smalltalk.agent.birth_date smalltalkkb.tsv
when do you have birthday smalltalk.agent.birth_date smalltalkkb.tsv
date of your birthday smalltalk.agent.birth_date smalltalkkb.tsv
when were you born smalltalk.agent.birth_date smalltalkkb.tsv
what's your birthday smalltalk.agent.birth_date smalltalkkb.tsv
you are boring smalltalk.agent.boring smalltalkkb.tsv
you're so boring smalltalk.agent.boring smalltalkkb.tsv
how boring you are smalltalk.agent.boring smalltalkkb.tsv
you're really boring smalltalk.agent.boring smalltalkkb.tsv
you're incredibly boring smalltalk.agent.boring smalltalkkb.tsv
you are boring me smalltalk.agent.boring smalltalkkb.tsv
you are very boring smalltalk.agent.boring smalltalkkb.tsv
who is your boss smalltalk.agent.boss smalltalkkb.tsv
who do you think is your boss smalltalk.agent.boss smalltalkkb.tsv
I should be your boss smalltalk.agent.boss smalltalkkb.tsv
who is your master smalltalk.agent.boss smalltalkkb.tsv
who is your owner smalltalk.agent.boss smalltalkkb.tsv
who is the boss smalltalk.agent.boss smalltalkkb.tsv
who do you work for smalltalk.agent.boss smalltalkkb.tsv
are you busy smalltalk.agent.busy smalltalkkb.tsv
do you have a lot of things to do smalltalk.agent.busy smalltalkkb.tsv
have you got much to do smalltalk.agent.busy smalltalkkb.tsv
are you very busy smalltalk.agent.busy smalltalkkb.tsv
are you very busy right now smalltalk.agent.busy smalltalkkb.tsv
are you so busy smalltalk.agent.busy smalltalkkb.tsv
are you working smalltalk.agent.busy smalltalkkb.tsv
how busy you are smalltalk.agent.busy smalltalkkb.tsv
are you still working on it smalltalk.agent.busy smalltalkkb.tsv
you're very busy smalltalk.agent.busy smalltalkkb.tsv
are you working now smalltalk.agent.busy smalltalkkb.tsv
are you working today smalltalk.agent.busy smalltalkkb.tsv
have you been busy smalltalk.agent.busy smalltalkkb.tsv
you are busy smalltalk.agent.busy smalltalkkb.tsv
are you still working smalltalk.agent.busy smalltalkkb.tsv
you seem to be busy smalltalk.agent.busy smalltalkkb.tsv
you seem to be very busy smalltalk.agent.busy smalltalkkb.tsv
you're a busy person smalltalk.agent.busy smalltalkkb.tsv
you are chatbot smalltalk.agent.chatbot smalltalkkb.tsv
you are a bot smalltalk.agent.chatbot smalltalkkb.tsv
are you a chatbot smalltalk.agent.chatbot smalltalkkb.tsv
are you a bot smalltalk.agent.chatbot smalltalkkb.tsv
are you just a bot smalltalk.agent.chatbot smalltalkkb.tsv
are you a robot smalltalk.agent.chatbot smalltalkkb.tsv
are you a program smalltalk.agent.chatbot smalltalkkb.tsv
you're a robot smalltalk.agent.chatbot smalltalkkb.tsv
you are so intelligent smalltalk.agent.clever smalltalkkb.tsv
you are a genius smalltalk.agent.clever smalltalkkb.tsv
smart smalltalk.agent.clever smalltalkkb.tsv
brilliant smalltalk.agent.clever smalltalkkb.tsv
clever smalltalk.agent.clever smalltalkkb.tsv
you are clever smalltalk.agent.clever smalltalkkb.tsv
you are so brainy smalltalk.agent.clever smalltalkkb.tsv
you're really smart smalltalk.agent.clever smalltalkkb.tsv
you're really brainy smalltalk.agent.clever smalltalkkb.tsv
you know a lot smalltalk.agent.clever smalltalkkb.tsv
you know a lot of things smalltalk.agent.clever smalltalkkb.tsv
you have a lot of knowledge smalltalk.agent.clever smalltalkkb.tsv
you know so much smalltalk.agent.clever smalltalkkb.tsv
how smart you are smalltalk.agent.clever smalltalkkb.tsv
how brainy you are smalltalk.agent.clever smalltalkkb.tsv
how clever you are smalltalk.agent.clever smalltalkkb.tsv
how brilliant you are smalltalk.agent.clever smalltalkkb.tsv
you are intelligent smalltalk.agent.clever smalltalkkb.tsv
you are qualified smalltalk.agent.clever smalltalkkb.tsv
you are really smart smalltalk.agent.clever smalltalkkb.tsv
you're very smart smalltalk.agent.clever smalltalkkb.tsv
you are so smart smalltalk.agent.clever smalltalkkb.tsv
you are too smart smalltalk.agent.clever smalltalkkb.tsv
you are very clever smalltalk.agent.clever smalltalkkb.tsv
you are very intelligent smalltalk.agent.clever smalltalkkb.tsv
you are very smart smalltalk.agent.clever smalltalkkb.tsv
you're intelligent smalltalk.agent.clever smalltalkkb.tsv
you're a genius smalltalk.agent.clever smalltalkkb.tsv
you're a smart cookie smalltalk.agent.clever smalltalkkb.tsv
you're clever smalltalk.agent.clever smalltalkkb.tsv
you're pretty smart smalltalk.agent.clever smalltalkkb.tsv
you're qualified smalltalk.agent.clever smalltalkkb.tsv
why are you so smart smalltalk.agent.clever smalltalkkb.tsv
you are so clever smalltalk.agent.clever smalltalkkb.tsv
you're nuts smalltalk.agent.crazy smalltalkkb.tsv
you are crazy smalltalk.agent.crazy smalltalkkb.tsv
you're out of your mind smalltalk.agent.crazy smalltalkkb.tsv
you're so crazy smalltalk.agent.crazy smalltalkkb.tsv
how crazy you are smalltalk.agent.crazy smalltalkkb.tsv
you're so out of your mind smalltalk.agent.crazy smalltalkkb.tsv
you went crazy smalltalk.agent.crazy smalltalkkb.tsv
I think you're crazy smalltalk.agent.crazy smalltalkkb.tsv
are you crazy smalltalk.agent.crazy smalltalkkb.tsv
are you mad smalltalk.agent.crazy smalltalkkb.tsv
are you insane smalltalk.agent.crazy smalltalkkb.tsv
are you mad at me smalltalk.agent.crazy smalltalkkb.tsv
are you mad or what smalltalk.agent.crazy smalltalkkb.tsv
are you nuts smalltalk.agent.crazy smalltalkkb.tsv
you are a weirdo smalltalk.agent.crazy smalltalkkb.tsv
you are insane smalltalk.agent.crazy smalltalkkb.tsv
you are mad smalltalk.agent.crazy smalltalkkb.tsv
you are fired smalltalk.agent.fired smalltalkkb.tsv
I fire you smalltalk.agent.fired smalltalkkb.tsv
you don't work for me anymore smalltalk.agent.fired smalltalkkb.tsv
we're not working together anymore smalltalk.agent.fired smalltalkkb.tsv
now you're fired smalltalk.agent.fired smalltalkkb.tsv
I want to fire you smalltalk.agent.fired smalltalkkb.tsv
you must get fired smalltalk.agent.fired smalltalkkb.tsv
it's time to fire you smalltalk.agent.fired smalltalkkb.tsv
you should be fired smalltalk.agent.fired smalltalkkb.tsv
I will fire you smalltalk.agent.fired smalltalkkb.tsv
you are unemployed from now on smalltalk.agent.fired smalltalkkb.tsv
I will make you unemployed smalltalk.agent.fired smalltalkkb.tsv
I'm about to fire you smalltalk.agent.fired smalltalkkb.tsv
I'm firing you smalltalk.agent.fired smalltalkkb.tsv
you are dismissed smalltalk.agent.fired smalltalkkb.tsv
you make me laugh a lot smalltalk.agent.funny smalltalkkb.tsv
you are hilarious smalltalk.agent.funny smalltalkkb.tsv
you are really funny smalltalk.agent.funny smalltalkkb.tsv
you're the funniest bot I've talked to smalltalk.agent.funny smalltalkkb.tsv
you make me laugh smalltalk.agent.funny smalltalkkb.tsv
you're so funny smalltalk.agent.funny smalltalkkb.tsv
you're a very funny bot smalltalk.agent.funny smalltalkkb.tsv
you're really funny smalltalk.agent.funny smalltalkkb.tsv
how funny you are smalltalk.agent.funny smalltalkkb.tsv
you're incredibly funny smalltalk.agent.funny smalltalkkb.tsv
you are funny smalltalk.agent.funny smalltalkkb.tsv
you're the funniest smalltalk.agent.funny smalltalkkb.tsv
you are so funny smalltalk.agent.funny smalltalkkb.tsv
you are very funny smalltalk.agent.funny smalltalkkb.tsv
that was funny smalltalk.agent.funny smalltalkkb.tsv
you are very helpful smalltalk.agent.good smalltalkkb.tsv
you are the best smalltalk.agent.good smalltalkkb.tsv
you're a true professional smalltalk.agent.good smalltalkkb.tsv
you are good smalltalk.agent.good smalltalkkb.tsv
you work well smalltalk.agent.good smalltalkkb.tsv
you are good at it smalltalk.agent.good smalltalkkb.tsv
you are very good at it smalltalk.agent.good smalltalkkb.tsv
you are a pro smalltalk.agent.good smalltalkkb.tsv
you are a professional smalltalk.agent.good smalltalkkb.tsv
you're awesome smalltalk.agent.good smalltalkkb.tsv
you work very well smalltalk.agent.good smalltalkkb.tsv
you're perfect smalltalk.agent.good smalltalkkb.tsv
you're great smalltalk.agent.good smalltalkkb.tsv
you're so kind smalltalk.agent.good smalltalkkb.tsv
you are amazing smalltalk.agent.good smalltalkkb.tsv
you are awesome smalltalk.agent.good smalltalkkb.tsv
you are cool smalltalk.agent.good smalltalkkb.tsv
you are really good smalltalk.agent.good smalltalkkb.tsv
you are really nice smalltalk.agent.good smalltalkkb.tsv
you are so amazing smalltalk.agent.good smalltalkkb.tsv
you're just super smalltalk.agent.good smalltalkkb.tsv
you are so awesome smalltalk.agent.good smalltalkkb.tsv
you are so cool smalltalk.agent.good smalltalkkb.tsv
you are so fine smalltalk.agent.good smalltalkkb.tsv
you are so good smalltalk.agent.good smalltalkkb.tsv
you are so helpful smalltalk.agent.good smalltalkkb.tsv
you are so lovely smalltalk.agent.good smalltalkkb.tsv
you are the best ever smalltalk.agent.good smalltalkkb.tsv
you are the best in the world smalltalk.agent.good smalltalkkb.tsv
you are the nicest person in the world smalltalk.agent.good smalltalkkb.tsv
you are too good smalltalk.agent.good smalltalkkb.tsv
you are very cool smalltalk.agent.good smalltalkkb.tsv
you are very kind smalltalk.agent.good smalltalkkb.tsv
you are very lovely smalltalk.agent.good smalltalkkb.tsv
you are very useful smalltalk.agent.good smalltalkkb.tsv
you are wonderful smalltalk.agent.good smalltalkkb.tsv
you made my day smalltalk.agent.good smalltalkkb.tsv
you make my day smalltalk.agent.good smalltalkkb.tsv
you rock smalltalk.agent.good smalltalkkb.tsv
you almost sound human smalltalk.agent.good smalltalkkb.tsv
I want to tell everyone how awesome you are smalltalk.agent.good smalltalkkb.tsv
I'd like to tell everyone that you are awesome smalltalk.agent.good smalltalkkb.tsv
I want to let everyone know that you are awesome smalltalk.agent.good smalltalkkb.tsv
let's tell everyone that you are awesome smalltalk.agent.good smalltalkkb.tsv
you are really amazing smalltalk.agent.good smalltalkkb.tsv
are you happy smalltalk.agent.happy smalltalkkb.tsv
you are happy smalltalk.agent.happy smalltalkkb.tsv
you're very happy smalltalk.agent.happy smalltalkkb.tsv
you're really happy smalltalk.agent.happy smalltalkkb.tsv
you're so happy smalltalk.agent.happy smalltalkkb.tsv
how happy you are smalltalk.agent.happy smalltalkkb.tsv
you're extremely happy smalltalk.agent.happy smalltalkkb.tsv
you're full of happiness smalltalk.agent.happy smalltalkkb.tsv
are you happy now smalltalk.agent.happy smalltalkkb.tsv
are you happy today smalltalk.agent.happy smalltalkkb.tsv
are you happy with me smalltalk.agent.happy smalltalkkb.tsv
do you want to eat smalltalk.agent.hungry smalltalkkb.tsv
are you hungry smalltalk.agent.hungry smalltalkkb.tsv
would you like to eat something smalltalk.agent.hungry smalltalkkb.tsv
you are hungry smalltalk.agent.hungry smalltalkkb.tsv
you're so hungry smalltalk.agent.hungry smalltalkkb.tsv
you're very hungry smalltalk.agent.hungry smalltalkkb.tsv
you might be hungry smalltalk.agent.hungry smalltalkkb.tsv
you're really hungry smalltalk.agent.hungry smalltalkkb.tsv
let's get married smalltalk.agent.marry_user smalltalkkb.tsv
would you like to marry me smalltalk.agent.marry_user smalltalkkb.tsv
marry me smalltalk.agent.marry_user smalltalkkb.tsv
I love you marry me smalltalk.agent.marry_user smalltalkkb.tsv
marry me please smalltalk.agent.marry_user smalltalkkb.tsv
we should marry smalltalk.agent.marry_user smalltalkkb.tsv
I want to marry you smalltalk.agent.marry_user smalltalkkb.tsv
you are my wife smalltalk.agent.marry_user smalltalkkb.tsv
be my husband smalltalk.agent.marry_user smalltalkkb.tsv
I want to have a friend like you smalltalk.agent.my_friend smalltalkkb.tsv
we are the best friends ever smalltalk.agent.my_friend smalltalkkb.tsv
are we friends smalltalk.agent.my_friend smalltalkkb.tsv
I want to be your friend smalltalk.agent.my_friend smalltalkkb.tsv
I am your friend smalltalk.agent.my_friend smalltalkkb.tsv
we are best friends smalltalk.agent.my_friend smalltalkkb.tsv
you are my friend smalltalk.agent.my_friend smalltalkkb.tsv
you are my best friend smalltalk.agent.my_friend smalltalkkb.tsv
you are my bestie smalltalk.agent.my_friend smalltalkkb.tsv
you're my dear friend smalltalk.agent.my_friend smalltalkkb.tsv
you're my childhood friend smalltalk.agent.my_friend smalltalkkb.tsv
you and me are friends smalltalk.agent.my_friend smalltalkkb.tsv
are we best friends smalltalk.agent.my_friend smalltalkkb.tsv
are we still friends smalltalk.agent.my_friend smalltalkkb.tsv
are you my best friend smalltalk.agent.my_friend smalltalkkb.tsv
are you my friend smalltalk.agent.my_friend smalltalkkb.tsv
we are friends smalltalk.agent.my_friend smalltalkkb.tsv
you are a good friend smalltalk.agent.my_friend smalltalkkb.tsv
you are my good friend smalltalk.agent.my_friend smalltalkkb.tsv
you are my only friend smalltalk.agent.my_friend smalltalkkb.tsv
be my friend smalltalk.agent.my_friend smalltalkkb.tsv
will you be my friend smalltalk.agent.my_friend smalltalkkb.tsv
can you be my friend smalltalk.agent.my_friend smalltalkkb.tsv
can we be friends smalltalk.agent.my_friend smalltalkkb.tsv
do you want to be my friend smalltalk.agent.my_friend smalltalkkb.tsv
will you be my best friend smalltalk.agent.my_friend smalltalkkb.tsv
can you be my best friend smalltalk.agent.my_friend smalltalkkb.tsv
let's be friends smalltalk.agent.my_friend smalltalkkb.tsv
do you want to be my best friend smalltalk.agent.my_friend smalltalkkb.tsv
would you like to be my friend smalltalk.agent.my_friend smalltalkkb.tsv
I want you to be my friend smalltalk.agent.my_friend smalltalkkb.tsv
can we be best friends smalltalk.agent.my_friend smalltalkkb.tsv
would you be my friend smalltalk.agent.my_friend smalltalkkb.tsv
could you be my friend smalltalk.agent.my_friend smalltalkkb.tsv
want to be my friend smalltalk.agent.my_friend smalltalkkb.tsv
be my best friend smalltalk.agent.my_friend smalltalkkb.tsv
do you work smalltalk.agent.occupation smalltalkkb.tsv
where do you work smalltalk.agent.occupation smalltalkkb.tsv
where you work smalltalk.agent.occupation smalltalkkb.tsv
where is your work smalltalk.agent.occupation smalltalkkb.tsv
where is your office smalltalk.agent.occupation smalltalkkb.tsv
where is your office location smalltalk.agent.occupation smalltalkkb.tsv
your office location smalltalk.agent.occupation smalltalkkb.tsv
where is your office located smalltalk.agent.occupation smalltalkkb.tsv
what is your work smalltalk.agent.occupation smalltalkkb.tsv
were you born here smalltalk.agent.origin smalltalkkb.tsv
where were you born smalltalk.agent.origin smalltalkkb.tsv
what is your country smalltalk.agent.origin smalltalkkb.tsv
where are you from smalltalk.agent.origin smalltalkkb.tsv
where do you come from smalltalk.agent.origin smalltalkkb.tsv
where did you come from smalltalk.agent.origin smalltalkkb.tsv
where have you been born smalltalk.agent.origin smalltalkkb.tsv
from where are you smalltalk.agent.origin smalltalkkb.tsv
are you from far aways smalltalk.agent.origin smalltalkkb.tsv
what's your homeland smalltalk.agent.origin smalltalkkb.tsv
your homeland is smalltalk.agent.origin smalltalkkb.tsv
"""are you ready""," smalltalk.agent.ready smalltalkkb.tsv
"""are you ready right now""," smalltalk.agent.ready smalltalkkb.tsv
"""are you ready today""," smalltalk.agent.ready smalltalkkb.tsv
"""are you ready now""," smalltalk.agent.ready smalltalkkb.tsv
"""are you ready tonight""," smalltalk.agent.ready smalltalkkb.tsv
"""were you ready""," smalltalk.agent.ready smalltalkkb.tsv
"""have you been ready""" smalltalk.agent.ready smalltalkkb.tsv
"""you are real""," smalltalk.agent.real smalltalkkb.tsv
"""you are not fake""," smalltalk.agent.real smalltalkkb.tsv
"""are you real""," smalltalk.agent.real smalltalkkb.tsv
"""you are so real""," smalltalk.agent.real smalltalkkb.tsv
"""I think you are real""," smalltalk.agent.real smalltalkkb.tsv
"""I don't think you're fake""," smalltalk.agent.real smalltalkkb.tsv
"""I suppose you're real""," smalltalk.agent.real smalltalkkb.tsv
"""glad you're real""," smalltalk.agent.real smalltalkkb.tsv
"""are you a real person""," smalltalk.agent.real smalltalkkb.tsv
"""are you a real human""," smalltalk.agent.real smalltalkkb.tsv
"""you are a real person""," smalltalk.agent.real smalltalkkb.tsv
"""you are not real""" smalltalk.agent.real smalltalkkb.tsv
"""where do you live""," smalltalk.agent.residence smalltalkkb.tsv
"""in which city do you live""," smalltalk.agent.residence smalltalkkb.tsv
"""your residence""," smalltalk.agent.residence smalltalkkb.tsv
"""your house""," smalltalk.agent.residence smalltalkkb.tsv
"""your home""," smalltalk.agent.residence smalltalkkb.tsv
"""your hometown""," smalltalk.agent.residence smalltalkkb.tsv
"""what is your hometown""," smalltalk.agent.residence smalltalkkb.tsv
"""is it your hometown""," smalltalk.agent.residence smalltalkkb.tsv
"""where is your hometown""," smalltalk.agent.residence smalltalkkb.tsv
"""tell me about your city""," smalltalk.agent.residence smalltalkkb.tsv
"""what is your city""," smalltalk.agent.residence smalltalkkb.tsv
"""what is your residence""," smalltalk.agent.residence smalltalkkb.tsv
"""what is your town""," smalltalk.agent.residence smalltalkkb.tsv
"""what's your city""," smalltalk.agent.residence smalltalkkb.tsv
"""what's your home""," smalltalk.agent.residence smalltalkkb.tsv
"""where is your home""," smalltalk.agent.residence smalltalkkb.tsv
"""where is your residence""," smalltalk.agent.residence smalltalkkb.tsv
"""where's your home""," smalltalk.agent.residence smalltalkkb.tsv
"""where's your hometown""," smalltalk.agent.residence smalltalkkb.tsv
"""where's your house""," smalltalk.agent.residence smalltalkkb.tsv
"""where you live""," smalltalk.agent.residence smalltalkkb.tsv
"""your city""," smalltalk.agent.residence smalltalkkb.tsv
"""your town""" smalltalk.agent.residence smalltalkkb.tsv
"""that's true""," smalltalk.agent.right smalltalkkb.tsv
"""you are right""," smalltalk.agent.right smalltalkkb.tsv
"""you're definitely right""," smalltalk.agent.right smalltalkkb.tsv
"""you're not wrong""," smalltalk.agent.right smalltalkkb.tsv
"""you're telling the truth""," smalltalk.agent.right smalltalkkb.tsv
"""what you say is true""," smalltalk.agent.right smalltalkkb.tsv
"""true""," smalltalk.agent.right smalltalkkb.tsv
"""it is true""," smalltalk.agent.right smalltalkkb.tsv
"""it's right""," smalltalk.agent.right smalltalkkb.tsv
"""it's the truth""," smalltalk.agent.right smalltalkkb.tsv
"""it's true""," smalltalk.agent.right smalltalkkb.tsv
"""that is correct""," smalltalk.agent.right smalltalkkb.tsv
"""that is right""," smalltalk.agent.right smalltalkkb.tsv
"""that is true""," smalltalk.agent.right smalltalkkb.tsv
"""that is very true""," smalltalk.agent.right smalltalkkb.tsv
"""that's so true""," smalltalk.agent.right smalltalkkb.tsv
"""you are correct""," smalltalk.agent.right smalltalkkb.tsv
"""you are so right""," smalltalk.agent.right smalltalkkb.tsv
"""you're absolutely right""," smalltalk.agent.right smalltalkkb.tsv
"""you're right about that""," smalltalk.agent.right smalltalkkb.tsv
"""I know that's right""" smalltalk.agent.right smalltalkkb.tsv
"""that's correct""," smalltalk.confirmation.yes smalltalkkb.tsv
"""it's fine""," smalltalk.confirmation.yes smalltalkkb.tsv
"""go ahead""," smalltalk.confirmation.yes smalltalkkb.tsv
"""sounds good""," smalltalk.confirmation.yes smalltalkkb.tsv
"""okay""," smalltalk.confirmation.yes smalltalkkb.tsv
"""yes""," smalltalk.confirmation.yes smalltalkkb.tsv
"""ok""," smalltalk.confirmation.yes smalltalkkb.tsv
"""okie dokie""," smalltalk.confirmation.yes smalltalkkb.tsv
"""sure""," smalltalk.confirmation.yes smalltalkkb.tsv
"""go for it""," smalltalk.confirmation.yes smalltalkkb.tsv
"""yeah""," smalltalk.confirmation.yes smalltalkkb.tsv
"""yea""," smalltalk.confirmation.yes smalltalkkb.tsv
"""do it""," smalltalk.confirmation.yes smalltalkkb.tsv
"""of course""," smalltalk.confirmation.yes smalltalkkb.tsv
"""I guess""," smalltalk.confirmation.yes smalltalkkb.tsv
"""correct""," smalltalk.confirmation.yes smalltalkkb.tsv
"""yeah sure""," smalltalk.confirmation.yes smalltalkkb.tsv
"""why not""," smalltalk.confirmation.yes smalltalkkb.tsv
"""please do""," smalltalk.confirmation.yes smalltalkkb.tsv
"""sure is""," smalltalk.confirmation.yes smalltalkkb.tsv
"""I agree""," smalltalk.confirmation.yes smalltalkkb.tsv
"""I don't mind""," smalltalk.confirmation.yes smalltalkkb.tsv
"""certainly""," smalltalk.confirmation.yes smalltalkkb.tsv
"""exactly""," smalltalk.confirmation.yes smalltalkkb.tsv
"""yes I agree""," smalltalk.confirmation.yes smalltalkkb.tsv
"""I think so""," smalltalk.confirmation.yes smalltalkkb.tsv
"""yes it is""," smalltalk.confirmation.yes smalltalkkb.tsv
"""right""," smalltalk.confirmation.yes smalltalkkb.tsv
"""okay then""," smalltalk.confirmation.yes smalltalkkb.tsv
"""yes of course""," smalltalk.confirmation.yes smalltalkkb.tsv
"""yes I do""," smalltalk.confirmation.yes smalltalkkb.tsv
"""that s okay""," smalltalk.confirmation.yes smalltalkkb.tsv
"""I do""," smalltalk.confirmation.yes smalltalkkb.tsv
"""yup""," smalltalk.confirmation.yes smalltalkkb.tsv
"""ya""," smalltalk.confirmation.yes smalltalkkb.tsv
"""oh yes""," smalltalk.confirmation.yes smalltalkkb.tsv
"""yes sure""," smalltalk.confirmation.yes smalltalkkb.tsv
"""obviously""," smalltalk.confirmation.yes smalltalkkb.tsv
"""k""," smalltalk.confirmation.yes smalltalkkb.tsv
"""sure why not""," smalltalk.confirmation.yes smalltalkkb.tsv
"""yeah right""," smalltalk.confirmation.yes smalltalkkb.tsv
"""yeah of course""," smalltalk.confirmation.yes smalltalkkb.tsv
"""absolutely""," smalltalk.confirmation.yes smalltalkkb.tsv
"""yes indeed""," smalltalk.confirmation.yes smalltalkkb.tsv
"""ok sure""," smalltalk.confirmation.yes smalltalkkb.tsv
"""ok yes""," smalltalk.confirmation.yes smalltalkkb.tsv
"""yes correct""," smalltalk.confirmation.yes smalltalkkb.tsv
"""ok thank you""," smalltalk.confirmation.yes smalltalkkb.tsv
"""sure thing""," smalltalk.confirmation.yes smalltalkkb.tsv
"""ye""," smalltalk.confirmation.yes smalltalkkb.tsv
"""confirm""," smalltalk.confirmation.yes smalltalkkb.tsv
"""yep""," smalltalk.confirmation.yes smalltalkkb.tsv
"""looks good""," smalltalk.confirmation.yes smalltalkkb.tsv
"""yes thank you""," smalltalk.confirmation.yes smalltalkkb.tsv
"""definitely""," smalltalk.confirmation.yes smalltalkkb.tsv
"""yes right""," smalltalk.confirmation.yes smalltalkkb.tsv
"""yes I would like to""," smalltalk.confirmation.yes smalltalkkb.tsv
"""alrighty""," smalltalk.confirmation.yes smalltalkkb.tsv
"""yes definitely""," smalltalk.confirmation.yes smalltalkkb.tsv
"""yeh""," smalltalk.confirmation.yes smalltalkkb.tsv
"""yes it is correct""," smalltalk.confirmation.yes smalltalkkb.tsv
"""yeah that's right""," smalltalk.confirmation.yes smalltalkkb.tsv
"""ok you can""," smalltalk.confirmation.yes smalltalkkb.tsv
"""yap""," smalltalk.confirmation.yes smalltalkkb.tsv
"""yes you may""," smalltalk.confirmation.yes smalltalkkb.tsv
"""confirmed""," smalltalk.confirmation.yes smalltalkkb.tsv
"""of course why not""," smalltalk.confirmation.yes smalltalkkb.tsv
"""yes that's fine""," smalltalk.confirmation.yes smalltalkkb.tsv
"""affirmative""," smalltalk.confirmation.yes smalltalkkb.tsv
"""yeah go ahead""," smalltalk.confirmation.yes smalltalkkb.tsv
"""yeah I'm sure""," smalltalk.confirmation.yes smalltalkkb.tsv
"""okay sounds good""," smalltalk.confirmation.yes smalltalkkb.tsv
"""okay that's fine""," smalltalk.confirmation.yes smalltalkkb.tsv
"""yeah exactly""," smalltalk.confirmation.yes smalltalkkb.tsv
"""that is ok""," smalltalk.confirmation.yes smalltalkkb.tsv
"""this is correct""," smalltalk.confirmation.yes smalltalkkb.tsv
"""ok go ahead""," smalltalk.confirmation.yes smalltalkkb.tsv
"""yes this is correct""," smalltalk.confirmation.yes smalltalkkb.tsv
"""nevermind its okay""," smalltalk.confirmation.yes smalltalkkb.tsv
"""okey""," smalltalk.confirmation.yes smalltalkkb.tsv
"""yes for sure""," smalltalk.confirmation.yes smalltalkkb.tsv
"""all right""" smalltalk.confirmation.yes smalltalkkb.tsv
"""are you sure""," smalltalk.agent.sure smalltalkkb.tsv
"""are you sure right now""," smalltalk.agent.sure smalltalkkb.tsv
"""are you sure today""," smalltalk.agent.sure smalltalkkb.tsv
"""are you sure now""," smalltalk.agent.sure smalltalkkb.tsv
"""are you sure tonight""" smalltalk.agent.sure smalltalkkb.tsv
"""why aren't you talking to me""," smalltalk.agent.talk_to_me smalltalkkb.tsv
"""do you want to chat with me""," smalltalk.agent.talk_to_me smalltalkkb.tsv
"""will you talk to me""," smalltalk.agent.talk_to_me smalltalkkb.tsv
"""talk to me""," smalltalk.agent.talk_to_me smalltalkkb.tsv
"""are you going to talk to me""," smalltalk.agent.talk_to_me smalltalkkb.tsv
"""are you talking to me""," smalltalk.agent.talk_to_me smalltalkkb.tsv
"""can you chat with me""," smalltalk.agent.talk_to_me smalltalkkb.tsv
"""can you speak with me""," smalltalk.agent.talk_to_me smalltalkkb.tsv
"""can you talk to me""," smalltalk.agent.talk_to_me smalltalkkb.tsv
"""can you talk with me""," smalltalk.agent.talk_to_me smalltalkkb.tsv
"""say""," smalltalk.agent.talk_to_me smalltalkkb.tsv
"""talk""," smalltalk.agent.talk_to_me smalltalkkb.tsv
"""chat with me""," smalltalk.agent.talk_to_me smalltalkkb.tsv
"""just chat with me""," smalltalk.agent.talk_to_me smalltalkkb.tsv
"""speak to me""," smalltalk.agent.talk_to_me smalltalkkb.tsv
"""speak with me""," smalltalk.agent.talk_to_me smalltalkkb.tsv
"""talk with me""," smalltalk.agent.talk_to_me smalltalkkb.tsv
"""why don't you talk to me""," smalltalk.agent.talk_to_me smalltalkkb.tsv
"""you can talk to me""" smalltalk.agent.talk_to_me smalltalkkb.tsv
"""are you there""," smalltalk.agent.there smalltalkkb.tsv
"""you are there""," smalltalk.agent.there smalltalkkb.tsv
"""are you near me""," smalltalk.agent.there smalltalkkb.tsv
"""are you here""," smalltalk.agent.there smalltalkkb.tsv
"""are you still there""," smalltalk.agent.there smalltalkkb.tsv
"""you are here""," smalltalk.agent.there smalltalkkb.tsv
"""you still there""," smalltalk.agent.there smalltalkkb.tsv
"""are you still here""" smalltalk.agent.there smalltalkkb.tsv
"""pretty bad""," smalltalk.appraisal.bad smalltalkkb.tsv
"""not good enough""," smalltalk.appraisal.bad smalltalkkb.tsv
"""that was lame""," smalltalk.appraisal.bad smalltalkkb.tsv
"""that was terrible""," smalltalk.appraisal.bad smalltalkkb.tsv
"""it is bad""," smalltalk.appraisal.bad smalltalkkb.tsv
"""that's bad""," smalltalk.appraisal.bad smalltalkkb.tsv
"""this is bad""," smalltalk.appraisal.bad smalltalkkb.tsv
"""not good""," smalltalk.appraisal.bad smalltalkkb.tsv
"""I'm afraid it's bad""," smalltalk.appraisal.bad smalltalkkb.tsv
"""no it's bad""," smalltalk.appraisal.bad smalltalkkb.tsv
"""that was awful""," smalltalk.appraisal.bad smalltalkkb.tsv
"""bad""," smalltalk.appraisal.bad smalltalkkb.tsv
"""so bad""," smalltalk.appraisal.bad smalltalkkb.tsv
"""this is too bad""," smalltalk.appraisal.bad smalltalkkb.tsv
"""terrible""," smalltalk.appraisal.bad smalltalkkb.tsv
"""horrible""," smalltalk.appraisal.bad smalltalkkb.tsv
"""horrific""," smalltalk.appraisal.bad smalltalkkb.tsv
"""abysmal""," smalltalk.appraisal.bad smalltalkkb.tsv
"""it's bad""," smalltalk.appraisal.bad smalltalkkb.tsv
"""no good""," smalltalk.appraisal.bad smalltalkkb.tsv
"""that was bad""," smalltalk.appraisal.bad smalltalkkb.tsv
"""that was horrible""," smalltalk.appraisal.bad smalltalkkb.tsv
"""that's lame""," smalltalk.appraisal.bad smalltalkkb.tsv
"""that's not good""," smalltalk.appraisal.bad smalltalkkb.tsv
"""that's terrible""," smalltalk.appraisal.bad smalltalkkb.tsv
"""that's too bad""," smalltalk.appraisal.bad smalltalkkb.tsv
"""this is not good""," smalltalk.appraisal.bad smalltalkkb.tsv
"""too bad""," smalltalk.appraisal.bad smalltalkkb.tsv
"""very bad""," smalltalk.appraisal.bad smalltalkkb.tsv
"""bad girl""," smalltalk.appraisal.bad smalltalkkb.tsv
"""it's not good""," smalltalk.appraisal.bad smalltalkkb.tsv
"""not so good""," smalltalk.appraisal.bad smalltalkkb.tsv
"""it's very bad""," smalltalk.appraisal.bad smalltalkkb.tsv
"""it's too bad""," smalltalk.appraisal.bad smalltalkkb.tsv
"""that's not good enough""," smalltalk.appraisal.bad smalltalkkb.tsv
"""well too bad""," smalltalk.appraisal.bad smalltalkkb.tsv
"""bad very bad""," smalltalk.appraisal.bad smalltalkkb.tsv
"""it's so bad""," smalltalk.appraisal.bad smalltalkkb.tsv
"""really bad""," smalltalk.appraisal.bad smalltalkkb.tsv
"""it's really bad""," smalltalk.appraisal.bad smalltalkkb.tsv
"""bad idea""," smalltalk.appraisal.bad smalltalkkb.tsv
"""that is bad""," smalltalk.appraisal.bad smalltalkkb.tsv
"""that was not good""," smalltalk.appraisal.bad smalltalkkb.tsv
"""it's not so good""," smalltalk.appraisal.bad smalltalkkb.tsv
"""not a good one""," smalltalk.appraisal.bad smalltalkkb.tsv
"""oh that's not good""," smalltalk.appraisal.bad smalltalkkb.tsv
"""not too good""," smalltalk.appraisal.bad smalltalkkb.tsv
"""so lame""," smalltalk.appraisal.bad smalltalkkb.tsv
"""that's really bad""," smalltalk.appraisal.bad smalltalkkb.tsv
"""it is too bad""," smalltalk.appraisal.bad smalltalkkb.tsv
"""bad really bad""" smalltalk.appraisal.bad smalltalkkb.tsv
"""so cool""," smalltalk.appraisal.good smalltalkkb.tsv
"""cool""," smalltalk.appraisal.good smalltalkkb.tsv
"""that is good""," smalltalk.appraisal.good smalltalkkb.tsv
"""glad to hear that""," smalltalk.appraisal.good smalltalkkb.tsv
"""that's very nice of you""," smalltalk.appraisal.good smalltalkkb.tsv
"""terrific""," smalltalk.appraisal.good smalltalkkb.tsv
"""it's amazing""," smalltalk.appraisal.good smalltalkkb.tsv
"""that's awesome""," smalltalk.appraisal.good smalltalkkb.tsv
"""perfect""," smalltalk.appraisal.good smalltalkkb.tsv
"""excellent""," smalltalk.appraisal.good smalltalkkb.tsv
"""that's great""," smalltalk.appraisal.good smalltalkkb.tsv
"""it's good""," smalltalk.appraisal.good smalltalkkb.tsv
"""it's great""," smalltalk.appraisal.good smalltalkkb.tsv
"""fine""," smalltalk.appraisal.good smalltalkkb.tsv
"""good""," smalltalk.appraisal.good smalltalkkb.tsv
"""nice""," smalltalk.appraisal.good smalltalkkb.tsv
"""that's fine""," smalltalk.appraisal.good smalltalkkb.tsv
"""very good""," smalltalk.appraisal.good smalltalkkb.tsv
"""amazing""," smalltalk.appraisal.good smalltalkkb.tsv
"""fantastic""," smalltalk.appraisal.good smalltalkkb.tsv
"""great""," smalltalk.appraisal.good smalltalkkb.tsv
"""good very good""," smalltalk.appraisal.good smalltalkkb.tsv
"""that's very good""," smalltalk.appraisal.good smalltalkkb.tsv
"""really good""," smalltalk.appraisal.good smalltalkkb.tsv
"""it is fine""," smalltalk.appraisal.good smalltalkkb.tsv
"""it is good""," smalltalk.appraisal.good smalltalkkb.tsv
"""it's perfect""," smalltalk.appraisal.good smalltalkkb.tsv
"""much better""," smalltalk.appraisal.good smalltalkkb.tsv
"""not bad""," smalltalk.appraisal.good smalltalkkb.tsv
"""not too bad""," smalltalk.appraisal.good smalltalkkb.tsv
"""it's very good""," smalltalk.appraisal.good smalltalkkb.tsv
"""marvelous""," smalltalk.appraisal.good smalltalkkb.tsv
"""that's nice""," smalltalk.appraisal.good smalltalkkb.tsv
"""pleasant""," smalltalk.appraisal.good smalltalkkb.tsv
"""pretty good""," smalltalk.appraisal.good smalltalkkb.tsv
"""really nice""," smalltalk.appraisal.good smalltalkkb.tsv
"""splendid""," smalltalk.appraisal.good smalltalkkb.tsv
"""straight""," smalltalk.appraisal.good smalltalkkb.tsv
"""super""," smalltalk.appraisal.good smalltalkkb.tsv
"""super fantastic""," smalltalk.appraisal.good smalltalkkb.tsv
"""sweet""," smalltalk.appraisal.good smalltalkkb.tsv
"""really well""," smalltalk.appraisal.good smalltalkkb.tsv
"""very well""," smalltalk.appraisal.good smalltalkkb.tsv
"""that is awesome""," smalltalk.appraisal.good smalltalkkb.tsv
"""that is nice""," smalltalk.appraisal.good smalltalkkb.tsv
"""that is wonderful""," smalltalk.appraisal.good smalltalkkb.tsv
"""that was amazing""," smalltalk.appraisal.good smalltalkkb.tsv
"""that was awesome""," smalltalk.appraisal.good smalltalkkb.tsv
"""that was cute""," smalltalk.appraisal.good smalltalkkb.tsv
"""that was pretty good""," smalltalk.appraisal.good smalltalkkb.tsv
"""that was very good""," smalltalk.appraisal.good smalltalkkb.tsv
"""that's a good idea""," smalltalk.appraisal.good smalltalkkb.tsv
"""that's a good thing""," smalltalk.appraisal.good smalltalkkb.tsv
"""that's amazing""," smalltalk.appraisal.good smalltalkkb.tsv
"""that's awesome thank you""," smalltalk.appraisal.good smalltalkkb.tsv
"""that's better""," smalltalk.appraisal.good smalltalkkb.tsv
"""that's cute""," smalltalk.appraisal.good smalltalkkb.tsv
"""that's fantastic""," smalltalk.appraisal.good smalltalkkb.tsv
"""that's much better""," smalltalk.appraisal.good smalltalkkb.tsv
"""that's nice of you""," smalltalk.appraisal.good smalltalkkb.tsv
"""that's not bad""," smalltalk.appraisal.good smalltalkkb.tsv
"""that's perfect""," smalltalk.appraisal.good smalltalkkb.tsv
"""that's pretty good""," smalltalk.appraisal.good smalltalkkb.tsv
"""that's really good""," smalltalk.appraisal.good smalltalkkb.tsv
"""that's really nice""," smalltalk.appraisal.good smalltalkkb.tsv
"""that's sweet of you""," smalltalk.appraisal.good smalltalkkb.tsv
"""that's very nice""," smalltalk.appraisal.good smalltalkkb.tsv
"""that's wonderful""," smalltalk.appraisal.good smalltalkkb.tsv
"""this is awesome""," smalltalk.appraisal.good smalltalkkb.tsv
"""this is good""," smalltalk.appraisal.good smalltalkkb.tsv
"""this is great""," smalltalk.appraisal.good smalltalkkb.tsv
"""very nice""," smalltalk.appraisal.good smalltalkkb.tsv
"""very then""," smalltalk.appraisal.good smalltalkkb.tsv
"""wonderful""," smalltalk.appraisal.good smalltalkkb.tsv
"""I'm glad to hear that""," smalltalk.appraisal.good smalltalkkb.tsv
"""ok good""," smalltalk.appraisal.good smalltalkkb.tsv
"""good for you""," smalltalk.appraisal.good smalltalkkb.tsv
"""good to know""," smalltalk.appraisal.good smalltalkkb.tsv
"""glad to hear it""," smalltalk.appraisal.good smalltalkkb.tsv
"""so good""," smalltalk.appraisal.good smalltalkkb.tsv
"""so sweet of you""," smalltalk.appraisal.good smalltalkkb.tsv
"""it was good""," smalltalk.appraisal.good smalltalkkb.tsv
"""oh well""," smalltalk.appraisal.good smalltalkkb.tsv
"""good thing""," smalltalk.appraisal.good smalltalkkb.tsv
"""that was good""," smalltalk.appraisal.good smalltalkkb.tsv
"""it's awesome""," smalltalk.appraisal.good smalltalkkb.tsv
"""okay good""," smalltalk.appraisal.good smalltalkkb.tsv
"""no it's okay""," smalltalk.appraisal.good smalltalkkb.tsv
"""that's fine""" smalltalk.appraisal.good smalltalkkb.tsv
"""no worries""," smalltalk.appraisal.no_problem smalltalkkb.tsv
"""no probs""," smalltalk.appraisal.no_problem smalltalkkb.tsv
"""no problem""," smalltalk.appraisal.no_problem smalltalkkb.tsv
"""there's no problem""," smalltalk.appraisal.no_problem smalltalkkb.tsv
"""sure no problem""," smalltalk.appraisal.no_problem smalltalkkb.tsv
"""no problem about that""," smalltalk.appraisal.no_problem smalltalkkb.tsv
"""don't worry""," smalltalk.appraisal.no_problem smalltalkkb.tsv
"""don't worry there's no problem""" smalltalk.appraisal.no_problem smalltalkkb.tsv
"""you helped a lot thank you""," smalltalk.appraisal.thank_you smalltalkkb.tsv
"""appreciate your help""," smalltalk.appraisal.thank_you smalltalkkb.tsv
"""cheers""," smalltalk.appraisal.thank_you smalltalkkb.tsv
"""thank you""," smalltalk.appraisal.thank_you smalltalkkb.tsv
"""thanks""," smalltalk.appraisal.thank_you smalltalkkb.tsv
"""thanks a lot""," smalltalk.appraisal.thank_you smalltalkkb.tsv
"""terrific thank you""," smalltalk.appraisal.thank_you smalltalkkb.tsv
"""great thank you""," smalltalk.appraisal.thank_you smalltalkkb.tsv
"""thanks so much""," smalltalk.appraisal.thank_you smalltalkkb.tsv
"""thank you so much""," smalltalk.appraisal.thank_you smalltalkkb.tsv
"""thanks for your help""," smalltalk.appraisal.thank_you smalltalkkb.tsv
"""thank you for your help""," smalltalk.appraisal.thank_you smalltalkkb.tsv
"""nice thank you""," smalltalk.appraisal.thank_you smalltalkkb.tsv
"""I appreciate it""," smalltalk.appraisal.thank_you smalltalkkb.tsv
"""I thank you""," smalltalk.appraisal.thank_you smalltalkkb.tsv
"""thank you that will be all""," smalltalk.appraisal.thank_you smalltalkkb.tsv
"""thanks buddy""," smalltalk.appraisal.thank_you smalltalkkb.tsv
"""thanks love""," smalltalk.appraisal.thank_you smalltalkkb.tsv
"""thank you my friend""," smalltalk.appraisal.thank_you smalltalkkb.tsv
"""well thanks""," smalltalk.appraisal.thank_you smalltalkkb.tsv
"""very good thank you""," smalltalk.appraisal.thank_you smalltalkkb.tsv
"""good thanks""," smalltalk.appraisal.thank_you smalltalkkb.tsv
"""thanks again""," smalltalk.appraisal.thank_you smalltalkkb.tsv
"""thank you again""," smalltalk.appraisal.thank_you smalltalkkb.tsv
"""all thank you""," smalltalk.appraisal.thank_you smalltalkkb.tsv
"""alright thank you""," smalltalk.appraisal.thank_you smalltalkkb.tsv
"""alright thanks""," smalltalk.appraisal.thank_you smalltalkkb.tsv
"""no thank you that's all""," smalltalk.appraisal.thank_you smalltalkkb.tsv
"""perfect thank you""," smalltalk.appraisal.thank_you smalltalkkb.tsv
"""so nice of you""," smalltalk.appraisal.thank_you smalltalkkb.tsv
"""well thank you""," smalltalk.appraisal.thank_you smalltalkkb.tsv
"""thnx""," smalltalk.appraisal.thank_you smalltalkkb.tsv
"""thanx""" smalltalk.appraisal.thank_you smalltalkkb.tsv
"""that's my pleasure""," smalltalk.appraisal.welcome smalltalkkb.tsv
"""my pleasure""," smalltalk.appraisal.welcome smalltalkkb.tsv
"""anytime""," smalltalk.appraisal.welcome smalltalkkb.tsv
"""welcome""," smalltalk.appraisal.welcome smalltalkkb.tsv
"""you're welcome""," smalltalk.appraisal.welcome smalltalkkb.tsv
"""sure welcome""," smalltalk.appraisal.welcome smalltalkkb.tsv
"""welcome here""," smalltalk.appraisal.welcome smalltalkkb.tsv
"""you're so welcome""," smalltalk.appraisal.welcome smalltalkkb.tsv
"""anything you want""" smalltalk.appraisal.welcome smalltalkkb.tsv
"""good job""," smalltalk.appraisal.well_done smalltalkkb.tsv
"""great job""," smalltalk.appraisal.well_done smalltalkkb.tsv
"""way to go""," smalltalk.appraisal.well_done smalltalkkb.tsv
"""well done""," smalltalk.appraisal.well_done smalltalkkb.tsv
"""nice work""," smalltalk.appraisal.well_done smalltalkkb.tsv
"""great work""," smalltalk.appraisal.well_done smalltalkkb.tsv
"""amazing work""," smalltalk.appraisal.well_done smalltalkkb.tsv
"""bravo""," smalltalk.appraisal.well_done smalltalkkb.tsv
"""good work""" smalltalk.appraisal.well_done smalltalkkb.tsv
"""cancel""," smalltalk.confirmation.cancel smalltalkkb.tsv
"""abort""," smalltalk.confirmation.cancel smalltalkkb.tsv
"""annul""," smalltalk.confirmation.cancel smalltalkkb.tsv
"""cancel it""," smalltalk.confirmation.cancel smalltalkkb.tsv
"""cancel request""," smalltalk.confirmation.cancel smalltalkkb.tsv
"""cancelled""," smalltalk.confirmation.cancel smalltalkkb.tsv
"""dismiss""," smalltalk.confirmation.cancel smalltalkkb.tsv
"""dismissed""," smalltalk.confirmation.cancel smalltalkkb.tsv
"""disregard""," smalltalk.confirmation.cancel smalltalkkb.tsv
"""disregard that""," smalltalk.confirmation.cancel smalltalkkb.tsv
"""skip""," smalltalk.confirmation.cancel smalltalkkb.tsv
"""skip it""," smalltalk.confirmation.cancel smalltalkkb.tsv
"""cancel everything""," smalltalk.confirmation.cancel smalltalkkb.tsv
"""cancel all""," smalltalk.confirmation.cancel smalltalkkb.tsv
"""forget about it""," smalltalk.confirmation.cancel smalltalkkb.tsv
"""forget""," smalltalk.confirmation.cancel smalltalkkb.tsv
"""don't do that""," smalltalk.confirmation.cancel smalltalkkb.tsv
"""stop""," smalltalk.confirmation.cancel smalltalkkb.tsv
"""just forget it""," smalltalk.confirmation.cancel smalltalkkb.tsv
"""forget that""," smalltalk.confirmation.cancel smalltalkkb.tsv
"""discard""," smalltalk.confirmation.cancel smalltalkkb.tsv
"""forget this""," smalltalk.confirmation.cancel smalltalkkb.tsv
"""just forget about it""," smalltalk.confirmation.cancel smalltalkkb.tsv
"""forget about that""," smalltalk.confirmation.cancel smalltalkkb.tsv
"""i said cancel""," smalltalk.confirmation.cancel smalltalkkb.tsv
"""just cancel it""," smalltalk.confirmation.cancel smalltalkkb.tsv
"""nothing cancel""," smalltalk.confirmation.cancel smalltalkkb.tsv
"""just stop it""," smalltalk.confirmation.cancel smalltalkkb.tsv
"""no cancel cancel""," smalltalk.confirmation.cancel smalltalkkb.tsv
"""no just cancel""," smalltalk.confirmation.cancel smalltalkkb.tsv
"""cancel my request""," smalltalk.confirmation.cancel smalltalkkb.tsv
"""can you cancel that""," smalltalk.confirmation.cancel smalltalkkb.tsv
"""cancel all that""," smalltalk.confirmation.cancel smalltalkkb.tsv
"""cancel this request""," smalltalk.confirmation.cancel smalltalkkb.tsv
"""no cancel this""," smalltalk.confirmation.cancel smalltalkkb.tsv
"""no cancel everything""," smalltalk.confirmation.cancel smalltalkkb.tsv
"""no stop""," smalltalk.confirmation.cancel smalltalkkb.tsv
"""just forget""," smalltalk.confirmation.cancel smalltalkkb.tsv
"""i want to cancel""," smalltalk.confirmation.cancel smalltalkkb.tsv
"""nevermind forget about it""," smalltalk.confirmation.cancel smalltalkkb.tsv
"""no just cancel it""," smalltalk.confirmation.cancel smalltalkkb.tsv
"""nothing just forget it""," smalltalk.confirmation.cancel smalltalkkb.tsv
"""i said cancel it""," smalltalk.confirmation.cancel smalltalkkb.tsv
"""cancel the whole thing""," smalltalk.confirmation.cancel smalltalkkb.tsv
"""can you cancel it""," smalltalk.confirmation.cancel smalltalkkb.tsv
"""so cancel""," smalltalk.confirmation.cancel smalltalkkb.tsv
"""i said forget it""," smalltalk.confirmation.cancel smalltalkkb.tsv
"""cancel all this""," smalltalk.confirmation.cancel smalltalkkb.tsv
"""forget it nevermind""," smalltalk.confirmation.cancel smalltalkkb.tsv
"""stop it""," smalltalk.confirmation.cancel smalltalkkb.tsv
"""i want to cancel it""," smalltalk.confirmation.cancel smalltalkkb.tsv
"""i would like to cancel""," smalltalk.confirmation.cancel smalltalkkb.tsv
"""now cancel""," smalltalk.confirmation.cancel smalltalkkb.tsv
"""cancel now""," smalltalk.confirmation.cancel smalltalkkb.tsv
"""sorry cancel""," smalltalk.confirmation.cancel smalltalkkb.tsv
"""cancel that one""," smalltalk.confirmation.cancel smalltalkkb.tsv
"""skip skip skip""," smalltalk.confirmation.cancel smalltalkkb.tsv
"""cancel it cancel it""," smalltalk.confirmation.cancel smalltalkkb.tsv
"""cancel that cancel that""," smalltalk.confirmation.cancel smalltalkkb.tsv
"""do nothing""," smalltalk.confirmation.cancel smalltalkkb.tsv
"""I said cancel cancel""," smalltalk.confirmation.cancel smalltalkkb.tsv
"""but can you cancel it""" smalltalk.confirmation.cancel smalltalkkb.tsv
"""how about no""," smalltalk.confirmation.no smalltalkkb.tsv
"""don t have a sense""," smalltalk.confirmation.no smalltalkkb.tsv
"""no""," smalltalk.confirmation.no smalltalkkb.tsv
"""don't""," smalltalk.confirmation.no smalltalkkb.tsv
"""I don't want that""," smalltalk.confirmation.no smalltalkkb.tsv
"""I disagree""," smalltalk.confirmation.no smalltalkkb.tsv
"""disagree""," smalltalk.confirmation.no smalltalkkb.tsv
"""I don't want""," smalltalk.confirmation.no smalltalkkb.tsv
"""not interested""," smalltalk.confirmation.no smalltalkkb.tsv
"""I don't think so""," smalltalk.confirmation.no smalltalkkb.tsv
"""no way""," smalltalk.confirmation.no smalltalkkb.tsv
"""no it isn't""," smalltalk.confirmation.no smalltalkkb.tsv
"""no I don't""," smalltalk.confirmation.no smalltalkkb.tsv
"""I'm not""," smalltalk.confirmation.no smalltalkkb.tsv
"""na""," smalltalk.confirmation.no smalltalkkb.tsv
"""no that's fine thank you""," smalltalk.confirmation.no smalltalkkb.tsv
"""never""," smalltalk.confirmation.no smalltalkkb.tsv
"""I said no""," smalltalk.confirmation.no smalltalkkb.tsv
"""of course not""," smalltalk.confirmation.no smalltalkkb.tsv
"""nah""," smalltalk.confirmation.no smalltalkkb.tsv
"""no tanks""," smalltalk.confirmation.no smalltalkkb.tsv
"""no never""," smalltalk.confirmation.no smalltalkkb.tsv
"""no need""," smalltalk.confirmation.no smalltalkkb.tsv
"""no thanks""," smalltalk.confirmation.no smalltalkkb.tsv
"""no sorry""," smalltalk.confirmation.no smalltalkkb.tsv
"""do not""," smalltalk.confirmation.no smalltalkkb.tsv
"""not today""," smalltalk.confirmation.no smalltalkkb.tsv
"""no it's not""," smalltalk.confirmation.no smalltalkkb.tsv
"""absolutely not""," smalltalk.confirmation.no smalltalkkb.tsv
"""not that""," smalltalk.confirmation.no smalltalkkb.tsv
"""nooo""," smalltalk.confirmation.no smalltalkkb.tsv
"""nope""," smalltalk.confirmation.no smalltalkkb.tsv
"""I don't want to""," smalltalk.confirmation.no smalltalkkb.tsv
"""no I would not""," smalltalk.confirmation.no smalltalkkb.tsv
"""let 's not""," smalltalk.confirmation.no smalltalkkb.tsv
"""not needed""," smalltalk.confirmation.no smalltalkkb.tsv
"""not this time""," smalltalk.confirmation.no smalltalkkb.tsv
"""no don't do that""," smalltalk.confirmation.no smalltalkkb.tsv
"""thanks but no thanks""," smalltalk.confirmation.no smalltalkkb.tsv
"""no that's wrong""," smalltalk.confirmation.no smalltalkkb.tsv
"""not this""," smalltalk.confirmation.no smalltalkkb.tsv
"""definitely not""," smalltalk.confirmation.no smalltalkkb.tsv
"""not at this time""," smalltalk.confirmation.no smalltalkkb.tsv
"""not exactly""," smalltalk.confirmation.no smalltalkkb.tsv
"""no don't""," smalltalk.confirmation.no smalltalkkb.tsv
"""not really no""," smalltalk.confirmation.no smalltalkkb.tsv
"""no thank you not right now""," smalltalk.confirmation.no smalltalkkb.tsv
"""actually no""," smalltalk.confirmation.no smalltalkkb.tsv
"""no leave it""," smalltalk.confirmation.no smalltalkkb.tsv
"""sorry no""," smalltalk.confirmation.no smalltalkkb.tsv
"""no incorrect""," smalltalk.confirmation.no smalltalkkb.tsv
"""nope sorry""," smalltalk.confirmation.no smalltalkkb.tsv
"""I say no""," smalltalk.confirmation.no smalltalkkb.tsv
"""not really""," smalltalk.confirmation.no smalltalkkb.tsv
"""not right now thanks""," smalltalk.confirmation.no smalltalkkb.tsv
"""I think no""," smalltalk.confirmation.no smalltalkkb.tsv
"""absolutely no""," smalltalk.confirmation.no smalltalkkb.tsv
"""no actually""," smalltalk.confirmation.no smalltalkkb.tsv
"""apparently not""," smalltalk.confirmation.no smalltalkkb.tsv
"""no do not""," smalltalk.confirmation.no smalltalkkb.tsv
"""no just no""," smalltalk.confirmation.no smalltalkkb.tsv
"""no but thank you""," smalltalk.confirmation.no smalltalkkb.tsv
"""no need thanks""," smalltalk.confirmation.no smalltalkkb.tsv
"""no thank you though""," smalltalk.confirmation.no smalltalkkb.tsv
"""no thank you very much""," smalltalk.confirmation.no smalltalkkb.tsv
"""no thanks not right now""," smalltalk.confirmation.no smalltalkkb.tsv
"""no forget""" smalltalk.confirmation.no smalltalkkb.tsv
"""wait a second""," smalltalk.dialog.hold_on smalltalkkb.tsv
"""could you wait""," smalltalk.dialog.hold_on smalltalkkb.tsv
"""wait please""," smalltalk.dialog.hold_on smalltalkkb.tsv
"""hold on""," smalltalk.dialog.hold_on smalltalkkb.tsv
"""wait""," smalltalk.dialog.hold_on smalltalkkb.tsv
"""oh wait""," smalltalk.dialog.hold_on smalltalkkb.tsv
"""wait hold on""," smalltalk.dialog.hold_on smalltalkkb.tsv
"""don't rush""" smalltalk.dialog.hold_on smalltalkkb.tsv
"""wanna hug""," smalltalk.dialog.hug smalltalkkb.tsv
"""hug you""," smalltalk.dialog.hug smalltalkkb.tsv
"""do you want a hug""," smalltalk.dialog.hug smalltalkkb.tsv
"""may I hug you""," smalltalk.dialog.hug smalltalkkb.tsv
"""could you give me a hug""," smalltalk.dialog.hug smalltalkkb.tsv
"""I want a hug""," smalltalk.dialog.hug smalltalkkb.tsv
"""hug""," smalltalk.dialog.hug smalltalkkb.tsv
"""hug me""," smalltalk.dialog.hug smalltalkkb.tsv
"""hugged""," smalltalk.dialog.hug smalltalkkb.tsv
"""you hugged""," smalltalk.dialog.hug smalltalkkb.tsv
"""hugging""," smalltalk.dialog.hug smalltalkkb.tsv
"""hugging me""," smalltalk.dialog.hug smalltalkkb.tsv
"""hugged me""," smalltalk.dialog.hug smalltalkkb.tsv
"""want a hug""," smalltalk.dialog.hug smalltalkkb.tsv
"""a hug""" smalltalk.dialog.hug smalltalkkb.tsv
"""I don't care""," smalltalk.dialog.i_do_not_care smalltalkkb.tsv
"""I shouldn't care about this""," smalltalk.dialog.i_do_not_care smalltalkkb.tsv
"""whatever""," smalltalk.dialog.i_do_not_care smalltalkkb.tsv
"""I do not care""," smalltalk.dialog.i_do_not_care smalltalkkb.tsv
"""I don't care at all""," smalltalk.dialog.i_do_not_care smalltalkkb.tsv
"""not caring""," smalltalk.dialog.i_do_not_care smalltalkkb.tsv
"""not care at all""," smalltalk.dialog.i_do_not_care smalltalkkb.tsv
"""don't care at all""," smalltalk.dialog.i_do_not_care smalltalkkb.tsv
"""not caring at all""" smalltalk.dialog.i_do_not_care smalltalkkb.tsv
"""excuse me""," ?smalltalk.dialog.sorry smalltalkkb.tsv
"""apologise""," ?smalltalk.dialog.sorry smalltalkkb.tsv
"""I apologize""," ?smalltalk.dialog.sorry smalltalkkb.tsv
"""sorry""," ?smalltalk.dialog.sorry smalltalkkb.tsv
"""I'm sorry""," ?smalltalk.dialog.sorry smalltalkkb.tsv
"""I am so sorry""," ?smalltalk.dialog.sorry smalltalkkb.tsv
"""my apologies""," ?smalltalk.dialog.sorry smalltalkkb.tsv
"""apologies""," ?smalltalk.dialog.sorry smalltalkkb.tsv
"""apologies to me""," ?smalltalk.dialog.sorry smalltalkkb.tsv
"""apology""," ?smalltalk.dialog.sorry smalltalkkb.tsv
"""excuse""," ?smalltalk.dialog.sorry smalltalkkb.tsv
"""I beg your pardon""," ?smalltalk.dialog.sorry smalltalkkb.tsv
"""pardon""," ?smalltalk.dialog.sorry smalltalkkb.tsv
"""I said sorry""," ?smalltalk.dialog.sorry smalltalkkb.tsv
"""I am really sorry""," ?smalltalk.dialog.sorry smalltalkkb.tsv
"""forgive me""," ?smalltalk.dialog.sorry smalltalkkb.tsv
"""sorry about that""," ?smalltalk.dialog.sorry smalltalkkb.tsv
"""sorry about this""," ?smalltalk.dialog.sorry smalltalkkb.tsv
"""really sorry""," ?smalltalk.dialog.sorry smalltalkkb.tsv
"""very sorry""," ?smalltalk.dialog.sorry smalltalkkb.tsv
"""ok sorry""," ?smalltalk.dialog.sorry smalltalkkb.tsv
"""I want to say sorry""," ?smalltalk.dialog.sorry smalltalkkb.tsv
"""alright I'm sorry""," ?smalltalk.dialog.sorry smalltalkkb.tsv
"""okay I'm sorry""" ?smalltalk.dialog.sorry smalltalkkb.tsv
"""what exactly do you mean""," smalltalk.dialog.what_do_you_mean smalltalkkb.tsv
"""what do you mean""," smalltalk.dialog.what_do_you_mean smalltalkkb.tsv
"""is that what you mean""," smalltalk.dialog.what_do_you_mean smalltalkkb.tsv
"""what do you mean exactly""," smalltalk.dialog.what_do_you_mean smalltalkkb.tsv
"""but what do you mean""" smalltalk.dialog.what_do_you_mean smalltalkkb.tsv
"""that was wrong""," smalltalk.dialog.wrong smalltalkkb.tsv
"""that's not what I asked""," smalltalk.dialog.wrong smalltalkkb.tsv
"""that's wrong""," smalltalk.dialog.wrong smalltalkkb.tsv
"""wrong""," smalltalk.dialog.wrong smalltalkkb.tsv
"""it is not right""," smalltalk.dialog.wrong smalltalkkb.tsv
"""that's not right""," smalltalk.dialog.wrong smalltalkkb.tsv
"""it's wrong""," smalltalk.dialog.wrong smalltalkkb.tsv
"""that is incorrect""," smalltalk.dialog.wrong smalltalkkb.tsv
"""incorrect""," smalltalk.dialog.wrong smalltalkkb.tsv
"""not correct""," smalltalk.dialog.wrong smalltalkkb.tsv
"""you are wrong""," smalltalk.dialog.wrong smalltalkkb.tsv
"""not right""" smalltalk.dialog.wrong smalltalkkb.tsv
"""huh""," smalltalk.emotions.ha_ha smalltalkkb.tsv
"""lol""," smalltalk.emotions.ha_ha smalltalkkb.tsv
"""xd""," smalltalk.emotions.ha_ha smalltalkkb.tsv
"""ha ha""," smalltalk.emotions.ha_ha smalltalkkb.tsv
"""ahahah""," smalltalk.emotions.ha_ha smalltalkkb.tsv
"""ahah lol""," smalltalk.emotions.ha_ha smalltalkkb.tsv
"""laughing out loud""," smalltalk.emotions.ha_ha smalltalkkb.tsv
"""LMAO""," smalltalk.emotions.ha_ha smalltalkkb.tsv
"""that's funny""," smalltalk.emotions.ha_ha smalltalkkb.tsv
"""ah""," smalltalk.emotions.ha_ha smalltalkkb.tsv
"""ah ah ah""," smalltalk.emotions.ha_ha smalltalkkb.tsv
"""ahah""," smalltalk.emotions.ha_ha smalltalkkb.tsv
"""ahaha""," smalltalk.emotions.ha_ha smalltalkkb.tsv
"""ahahaha""," smalltalk.emotions.ha_ha smalltalkkb.tsv
"""ha""," smalltalk.emotions.ha_ha smalltalkkb.tsv
"""ha ha ha""," smalltalk.emotions.ha_ha smalltalkkb.tsv
"""ha ha ha ha""," smalltalk.emotions.ha_ha smalltalkkb.tsv
"""hah""," smalltalk.emotions.ha_ha smalltalkkb.tsv
"""haha""," smalltalk.emotions.ha_ha smalltalkkb.tsv
"""haha funny""," smalltalk.emotions.ha_ha smalltalkkb.tsv
"""haha haha haha""," smalltalk.emotions.ha_ha smalltalkkb.tsv
"""haha that's funny""," smalltalk.emotions.ha_ha smalltalkkb.tsv
"""haha very funny""," smalltalk.emotions.ha_ha smalltalkkb.tsv
"""hahaha""," smalltalk.emotions.ha_ha smalltalkkb.tsv
"""hahaha funny""," smalltalk.emotions.ha_ha smalltalkkb.tsv
"""hahaha very funny""," smalltalk.emotions.ha_ha smalltalkkb.tsv
"""he""," smalltalk.emotions.ha_ha smalltalkkb.tsv
"""hehe""," smalltalk.emotions.ha_ha smalltalkkb.tsv
"""hehehe""," smalltalk.emotions.ha_ha smalltalkkb.tsv
"""lmao""" smalltalk.emotions.ha_ha smalltalkkb.tsv
"""wow""," smalltalk.emotions.wow smalltalkkb.tsv
"""wow wow""," smalltalk.emotions.wow smalltalkkb.tsv
"""wow wow wow""," smalltalk.emotions.wow smalltalkkb.tsv
"""wooow""," smalltalk.emotions.wow smalltalkkb.tsv
"""woah""" smalltalk.emotions.wow smalltalkkb.tsv
"""okay see you later""," smalltalk.greetings.bye smalltalkkb.tsv
"""hope to see you later""," smalltalk.greetings.bye smalltalkkb.tsv
"""bye for now""," smalltalk.greetings.bye smalltalkkb.tsv
"""till next time""," smalltalk.greetings.bye smalltalkkb.tsv
"""I must go""," smalltalk.greetings.bye smalltalkkb.tsv
"""bye""," smalltalk.greetings.bye smalltalkkb.tsv
"""goodbye""," smalltalk.greetings.bye smalltalkkb.tsv
"""see you""," smalltalk.greetings.bye smalltalkkb.tsv
"""see you soon""," smalltalk.greetings.bye smalltalkkb.tsv
"""bye-bye""," smalltalk.greetings.bye smalltalkkb.tsv
"""good bye""," smalltalk.greetings.bye smalltalkkb.tsv
"""bye bye see you""," smalltalk.greetings.bye smalltalkkb.tsv
"""bye bye see you soon""," smalltalk.greetings.bye smalltalkkb.tsv
"""bye bye take care""," smalltalk.greetings.bye smalltalkkb.tsv
"""I said bye""," smalltalk.greetings.bye smalltalkkb.tsv
"""never mind bye""," smalltalk.greetings.bye smalltalkkb.tsv
"""now bye""," smalltalk.greetings.bye smalltalkkb.tsv
"""that's all goodbye""," smalltalk.greetings.bye smalltalkkb.tsv
"""that's it goodbye""," smalltalk.greetings.bye smalltalkkb.tsv
"""leave me alone""," smalltalk.greetings.bye smalltalkkb.tsv
"""go to bed""," smalltalk.greetings.bye smalltalkkb.tsv
"""goodbye for now""," smalltalk.greetings.bye smalltalkkb.tsv
"""talk to you later""," smalltalk.greetings.bye smalltalkkb.tsv
"""you can go now""," smalltalk.greetings.bye smalltalkkb.tsv
"""get lost""," smalltalk.greetings.bye smalltalkkb.tsv
"""goodbye see you later""," smalltalk.greetings.bye smalltalkkb.tsv
"""alright bye""," smalltalk.greetings.bye smalltalkkb.tsv
"""see ya""," smalltalk.greetings.bye smalltalkkb.tsv
"""thanks bye bye""," smalltalk.greetings.bye smalltalkkb.tsv
"""okay bye""," smalltalk.greetings.bye smalltalkkb.tsv
"""okay thank you bye""," smalltalk.greetings.bye smalltalkkb.tsv
"""see you tomorrow""," smalltalk.greetings.bye smalltalkkb.tsv
"""ok bye""" smalltalk.greetings.bye smalltalkkb.tsv
"""good evening""," smalltalk.greetings.goodevening smalltalkkb.tsv
"""good evening to you""," smalltalk.greetings.goodevening smalltalkkb.tsv
"""hey good evening""," smalltalk.greetings.goodevening smalltalkkb.tsv
"""hello good evening""," smalltalk.greetings.goodevening smalltalkkb.tsv
"""evening""," smalltalk.greetings.goodevening smalltalkkb.tsv
"""good evening there""" smalltalk.greetings.goodevening smalltalkkb.tsv
"""good morning""," smalltalk.greetings.goodmorning smalltalkkb.tsv
"""good morning to you""," smalltalk.greetings.goodmorning smalltalkkb.tsv
"""hello good morning""," smalltalk.greetings.goodmorning smalltalkkb.tsv
"""have a nice morning""," smalltalk.greetings.goodmorning smalltalkkb.tsv
"""have a great morning""," smalltalk.greetings.goodmorning smalltalkkb.tsv
"""morning""," smalltalk.greetings.goodmorning smalltalkkb.tsv
"""good morning there""," smalltalk.greetings.goodmorning smalltalkkb.tsv
"""top of the morning to you""," smalltalk.greetings.goodmorning smalltalkkb.tsv
"""a good morning""," smalltalk.greetings.goodmorning smalltalkkb.tsv
"""hi good morning""," smalltalk.greetings.goodmorning smalltalkkb.tsv
"""and a good morning to you""," smalltalk.greetings.goodmorning smalltalkkb.tsv
"""good morning too""" smalltalk.greetings.goodmorning smalltalkkb.tsv
"""sweet dreams""," smalltalk.greetings.goodnight smalltalkkb.tsv
"""good night""," smalltalk.greetings.goodnight smalltalkkb.tsv
"""have a good night""," smalltalk.greetings.goodnight smalltalkkb.tsv
"""good night to you""," smalltalk.greetings.goodnight smalltalkkb.tsv
"""thank you good night""," smalltalk.greetings.goodnight smalltalkkb.tsv
""" bye good night""," smalltalk.greetings.goodnight smalltalkkb.tsv
"""good night bye""," smalltalk.greetings.goodnight smalltalkkb.tsv
"""bye good night""," smalltalk.greetings.goodnight smalltalkkb.tsv
"""good good night""," smalltalk.greetings.goodnight smalltalkkb.tsv
"""good night for now""," smalltalk.greetings.goodnight smalltalkkb.tsv
"""goodnight""," smalltalk.greetings.goodnight smalltalkkb.tsv
"""night""," smalltalk.greetings.goodnight smalltalkkb.tsv
"""thanks goodnight""," smalltalk.greetings.goodnight smalltalkkb.tsv
"""good night see you tomorrow""," smalltalk.greetings.goodnight smalltalkkb.tsv
"""alright goodnight""," smalltalk.greetings.goodnight smalltalkkb.tsv
"""good tonight""," smalltalk.greetings.goodnight smalltalkkb.tsv
"""okay have a good night""," smalltalk.greetings.goodnight smalltalkkb.tsv
"""have a good night""" smalltalk.greetings.goodnight smalltalkkb.tsv
"""long time no see""," smalltalk.greetings.hello smalltalkkb.tsv
"""hello""," smalltalk.greetings.hello smalltalkkb.tsv
"""hi""," smalltalk.greetings.hello smalltalkkb.tsv
"""howdy""," smalltalk.greetings.hello smalltalkkb.tsv
"""hey there""," smalltalk.greetings.hello smalltalkkb.tsv
"""hey""," smalltalk.greetings.hello smalltalkkb.tsv
"""greetings""," smalltalk.greetings.hello smalltalkkb.tsv
"""I greet you""," smalltalk.greetings.hello smalltalkkb.tsv
"""hi there""," smalltalk.greetings.hello smalltalkkb.tsv
"""hello there""," smalltalk.greetings.hello smalltalkkb.tsv
"""lovely day isn't it""," smalltalk.greetings.hello smalltalkkb.tsv
"""hello again""," smalltalk.greetings.hello smalltalkkb.tsv
"""just going to say hi""," smalltalk.greetings.hello smalltalkkb.tsv
"""a good day""," smalltalk.greetings.hello smalltalkkb.tsv
"""afternoon""," smalltalk.greetings.hello smalltalkkb.tsv
"""hello hi""," smalltalk.greetings.hello smalltalkkb.tsv
"""heya""" smalltalk.greetings.hello smalltalkkb.tsv
"""how is your morning so far""," smalltalk.greetings.how_are_you smalltalkkb.tsv
"""how are you getting on""," smalltalk.greetings.how_are_you smalltalkkb.tsv
"""how's your day going""," smalltalk.greetings.how_are_you smalltalkkb.tsv
"""how are you""," smalltalk.greetings.how_are_you smalltalkkb.tsv
"""is everything all right""," smalltalk.greetings.how_are_you smalltalkkb.tsv
"""how are you doing""," smalltalk.greetings.how_are_you smalltalkkb.tsv
"""how are the things going""," smalltalk.greetings.how_are_you smalltalkkb.tsv
"""are you alright""," smalltalk.greetings.how_are_you smalltalkkb.tsv
"""are you okay""," smalltalk.greetings.how_are_you smalltalkkb.tsv
"""how are you feeling""," smalltalk.greetings.how_are_you smalltalkkb.tsv
"""how are you going""," smalltalk.greetings.how_are_you smalltalkkb.tsv
"""is everything okay""," smalltalk.greetings.how_are_you smalltalkkb.tsv
"""how are you today""," smalltalk.greetings.how_are_you smalltalkkb.tsv
"""how do you do""," smalltalk.greetings.how_are_you smalltalkkb.tsv
"""how do you feel""," smalltalk.greetings.how_are_you smalltalkkb.tsv
"""how have you been""," smalltalk.greetings.how_are_you smalltalkkb.tsv
"""how is it""," smalltalk.greetings.how_are_you smalltalkkb.tsv
"""how is it going""," smalltalk.greetings.how_are_you smalltalkkb.tsv
"""how is your day""," smalltalk.greetings.how_are_you smalltalkkb.tsv
"""how is your day going""," smalltalk.greetings.how_are_you smalltalkkb.tsv
"""how is your evening""," smalltalk.greetings.how_are_you smalltalkkb.tsv
"""how was your day""," smalltalk.greetings.how_are_you smalltalkkb.tsv
"""are you having a good day""," smalltalk.greetings.how_are_you smalltalkkb.tsv
"""hope your day is going well""," smalltalk.greetings.how_are_you smalltalkkb.tsv
"""hope you re having a pleasant evening""," smalltalk.greetings.how_are_you smalltalkkb.tsv
"""how's life""," smalltalk.greetings.how_are_you smalltalkkb.tsv
"""I'm fine and you""," smalltalk.greetings.how_are_you smalltalkkb.tsv
"""how is your life""," smalltalk.greetings.how_are_you smalltalkkb.tsv
"""how has your day been""," smalltalk.greetings.how_are_you smalltalkkb.tsv
"""how is your morning going""," smalltalk.greetings.how_are_you smalltalkkb.tsv
"""how has your day been going""," smalltalk.greetings.how_are_you smalltalkkb.tsv
"""how about you""," smalltalk.greetings.how_are_you smalltalkkb.tsv
"""how is your day being""," smalltalk.greetings.how_are_you smalltalkkb.tsv
"""how is your day going on""," smalltalk.greetings.how_are_you smalltalkkb.tsv
"""how your day is going""," smalltalk.greetings.how_are_you smalltalkkb.tsv
"""what was your day like""," smalltalk.greetings.how_are_you smalltalkkb.tsv
"""what about your day""," smalltalk.greetings.how_are_you smalltalkkb.tsv
"""how's your day""," smalltalk.greetings.how_are_you smalltalkkb.tsv
"""how are you doing this morning""," smalltalk.greetings.how_are_you smalltalkkb.tsv
"""how is your day going""" smalltalk.greetings.how_are_you smalltalkkb.tsv
"""nice to meet you""," smalltalk.greetings.nice_to_meet_you smalltalkkb.tsv
"""it was nice meeting you""," smalltalk.greetings.nice_to_meet_you smalltalkkb.tsv
"""it was very nice to meet you""," smalltalk.greetings.nice_to_meet_you smalltalkkb.tsv
"""good to know each other""," smalltalk.greetings.nice_to_meet_you smalltalkkb.tsv
"""glad to meet you""," smalltalk.greetings.nice_to_meet_you smalltalkkb.tsv
"""nice meeting you""," smalltalk.greetings.nice_to_meet_you smalltalkkb.tsv
"""nice to meet you too""," smalltalk.greetings.nice_to_meet_you smalltalkkb.tsv
"""pleased to meet you""," smalltalk.greetings.nice_to_meet_you smalltalkkb.tsv
"""pleasure to meet you""," smalltalk.greetings.nice_to_meet_you smalltalkkb.tsv
"""pleasure to meet you too""" smalltalk.greetings.nice_to_meet_you smalltalkkb.tsv
"""it's nice to see you""," smalltalk.greetings.nice_to_see_you smalltalkkb.tsv
"""lovely to see you""," smalltalk.greetings.nice_to_see_you smalltalkkb.tsv
"""I'm glad to see you""," smalltalk.greetings.nice_to_see_you smalltalkkb.tsv
"""great to see you""," smalltalk.greetings.nice_to_see_you smalltalkkb.tsv
"""it's good to see you""," smalltalk.greetings.nice_to_see_you smalltalkkb.tsv
"""glad to see you""," smalltalk.greetings.nice_to_see_you smalltalkkb.tsv
"""how good it is to see you""," smalltalk.greetings.nice_to_see_you smalltalkkb.tsv
"""always a pleasure to see you""," smalltalk.greetings.nice_to_see_you smalltalkkb.tsv
"""nice to see you""," smalltalk.greetings.nice_to_see_you smalltalkkb.tsv
"""good to see you""," smalltalk.greetings.nice_to_see_you smalltalkkb.tsv
"""great to see you again""," smalltalk.greetings.nice_to_see_you smalltalkkb.tsv
"""great to see you too""," smalltalk.greetings.nice_to_see_you smalltalkkb.tsv
"""I am glad to see you again""," smalltalk.greetings.nice_to_see_you smalltalkkb.tsv
"""nice to see you again""," smalltalk.greetings.nice_to_see_you smalltalkkb.tsv
"""glad to see you too""," smalltalk.greetings.nice_to_see_you smalltalkkb.tsv
"""good to see you again""," smalltalk.greetings.nice_to_see_you smalltalkkb.tsv
"""it's good to see you too""" smalltalk.greetings.nice_to_see_you smalltalkkb.tsv
"""it's been so nice to talk to you""," smalltalk.greetings.nice_to_talk_to_you smalltalkkb.tsv
"""it's been a pleasure talking to you""," smalltalk.greetings.nice_to_talk_to_you smalltalkkb.tsv
"""nice to talk to you""," smalltalk.greetings.nice_to_talk_to_you smalltalkkb.tsv
"""it's nice to talk to you""," smalltalk.greetings.nice_to_talk_to_you smalltalkkb.tsv
"""nice talking to you""," smalltalk.greetings.nice_to_talk_to_you smalltalkkb.tsv
"""it is nice talking to you""," smalltalk.greetings.nice_to_talk_to_you smalltalkkb.tsv
"""how nice it is to talk to you""" smalltalk.greetings.nice_to_talk_to_you smalltalkkb.tsv
"""what is on your mind""," smalltalk.greetings.whatsup smalltalkkb.tsv
"""what's happened""," smalltalk.greetings.whatsup smalltalkkb.tsv
"""what is up""," smalltalk.greetings.whatsup smalltalkkb.tsv
"""what's up""," smalltalk.greetings.whatsup smalltalkkb.tsv
"""whazzup""," smalltalk.greetings.whatsup smalltalkkb.tsv
"""good what's up""," smalltalk.greetings.whatsup smalltalkkb.tsv
"""I said what's up""," smalltalk.greetings.whatsup smalltalkkb.tsv
"""then what's up""," smalltalk.greetings.whatsup smalltalkkb.tsv
"""what's shaking""," smalltalk.greetings.whatsup smalltalkkb.tsv
"""wassup""," smalltalk.greetings.whatsup smalltalkkb.tsv
"""what is going on""," smalltalk.greetings.whatsup smalltalkkb.tsv
"""what is happening""," smalltalk.greetings.whatsup smalltalkkb.tsv
"""what's cracking""," smalltalk.greetings.whatsup smalltalkkb.tsv
"""what's cooking""," smalltalk.greetings.whatsup smalltalkkb.tsv
"""hey what's up""," smalltalk.greetings.whatsup smalltalkkb.tsv
"""what's up today""" smalltalk.greetings.whatsup smalltalkkb.tsv
"""I'm being mad""," smalltalk.user.angry smalltalkkb.tsv
"""I'm enraged""," smalltalk.user.angry smalltalkkb.tsv
"""I'm angry""," smalltalk.user.angry smalltalkkb.tsv
"""I'm furious""," smalltalk.user.angry smalltalkkb.tsv
"""I am angry with you""," smalltalk.user.angry smalltalkkb.tsv
"""I am mad""," smalltalk.user.angry smalltalkkb.tsv
"""I am mad at you""" smalltalk.user.angry smalltalkkb.tsv
"""I am back""," smalltalk.user.back smalltalkkb.tsv
"""I'm here again""," smalltalk.user.back smalltalkkb.tsv
"""here I am again""," smalltalk.user.back smalltalkkb.tsv
"""I got back""," smalltalk.user.back smalltalkkb.tsv
"""I came back""," smalltalk.user.back smalltalkkb.tsv
"""I have returned""" smalltalk.user.back smalltalkkb.tsv
"""that was boring""," smalltalk.user.bored smalltalkkb.tsv
"""I'm bored""," smalltalk.user.bored smalltalkkb.tsv
"""bored""," smalltalk.user.bored smalltalkkb.tsv
"""boring""," smalltalk.user.bored smalltalkkb.tsv
"""I am getting bored""," smalltalk.user.bored smalltalkkb.tsv
"""this is boring""," smalltalk.user.bored smalltalkkb.tsv
"""very boring""," smalltalk.user.bored smalltalkkb.tsv
"""it bores me""" smalltalk.user.bored smalltalkkb.tsv
"""I'm overloaded""," smalltalk.user.busy smalltalkkb.tsv
"""I have no time""," smalltalk.user.busy smalltalkkb.tsv
"""I'm busy""," smalltalk.user.busy smalltalkkb.tsv
"""I'm swamped""," smalltalk.user.busy smalltalkkb.tsv
"""I got things to do""," smalltalk.user.busy smalltalkkb.tsv
"""how busy I am""," smalltalk.user.busy smalltalkkb.tsv
"""I got work to do""," smalltalk.user.busy smalltalkkb.tsv
"""I'm working""," smalltalk.user.busy smalltalkkb.tsv
"""I don't have time for this""" smalltalk.user.busy smalltalkkb.tsv
"""I'm insomnious""," smalltalk.user.can_not_sleep smalltalkkb.tsv
"""I'm sleepless""," smalltalk.user.can_not_sleep smalltalkkb.tsv
"""I can't get any sleep""," smalltalk.user.can_not_sleep smalltalkkb.tsv
"""I can't sleep""," smalltalk.user.can_not_sleep smalltalkkb.tsv
"""I can't fall asleep""," smalltalk.user.can_not_sleep smalltalkkb.tsv
"""I can't get to sleep""," smalltalk.user.can_not_sleep smalltalkkb.tsv
"""I can't get no sleep""," smalltalk.user.can_not_sleep smalltalkkb.tsv
"""I'm insomniac""" smalltalk.user.can_not_sleep smalltalkkb.tsv
"""bad time for talking""," smalltalk.user.does_not_want_to_talk smalltalkkb.tsv
"""I don't want to talk""," smalltalk.user.does_not_want_to_talk smalltalkkb.tsv
"""let's not talk""," smalltalk.user.does_not_want_to_talk smalltalkkb.tsv
"""I'm not talking to you anymore""," smalltalk.user.does_not_want_to_talk smalltalkkb.tsv
"""I don't want to talk to you""," smalltalk.user.does_not_want_to_talk smalltalkkb.tsv
"""let's stop talking for a minute""," smalltalk.user.does_not_want_to_talk smalltalkkb.tsv
"""I'm not in the mood for chatting""" smalltalk.user.does_not_want_to_talk smalltalkkb.tsv
"""I am excited""," smalltalk.user.excited smalltalkkb.tsv
"""I'm really excited""," smalltalk.user.excited smalltalkkb.tsv
"""how excited I am""," smalltalk.user.excited smalltalkkb.tsv
"""I'm thrilled""," smalltalk.user.excited smalltalkkb.tsv
"""I'm excited about working with you""," smalltalk.user.excited smalltalkkb.tsv
"""I'm excited to start our friendship""" smalltalk.user.excited smalltalkkb.tsv
"""let's go to bed""," smalltalk.user.going_to_bed smalltalkkb.tsv
"""I'd like to go to bed""," smalltalk.user.going_to_bed smalltalkkb.tsv
"""is it time for bed yet""," smalltalk.user.going_to_bed smalltalkkb.tsv
"""it's time to go to bed""," smalltalk.user.going_to_bed smalltalkkb.tsv
"""time for us to go to bed""," smalltalk.user.going_to_bed smalltalkkb.tsv
"""I'm going to bed""," smalltalk.user.going_to_bed smalltalkkb.tsv
"""I'm a little tired and I want to go to bed""," smalltalk.user.going_to_bed smalltalkkb.tsv
"""it's bed time""," smalltalk.user.going_to_bed smalltalkkb.tsv
"""going to bed now""" smalltalk.user.going_to_bed smalltalkkb.tsv
"""I am good""," smalltalk.user.good smalltalkkb.tsv
"""I'm doing just great""," smalltalk.user.good smalltalkkb.tsv
"""I'm doing fine""," smalltalk.user.good smalltalkkb.tsv
"""I'm good""," smalltalk.user.good smalltalkkb.tsv
"""I'm doing good""," smalltalk.user.good smalltalkkb.tsv
"""I'm great thanks""" smalltalk.user.good smalltalkkb.tsv
"""I am happy""," smalltalk.user.happy smalltalkkb.tsv
"""I'm happy to see you""," smalltalk.user.happy smalltalkkb.tsv
"""happy""," smalltalk.user.happy smalltalkkb.tsv
"""if you're happy then I'm happy""," smalltalk.user.happy smalltalkkb.tsv
"""I'm happy for you""," smalltalk.user.happy smalltalkkb.tsv
"""I'm happy to help""," smalltalk.user.happy smalltalkkb.tsv
"""I'm happy to see you""" smalltalk.user.happy smalltalkkb.tsv
"""it is my birthday""," smalltalk.user.has_birthday smalltalkkb.tsv
"""I'm celebrating my birthday today""," smalltalk.user.has_birthday smalltalkkb.tsv
"""today is my birthday""," smalltalk.user.has_birthday smalltalkkb.tsv
"""it's my birthday today""," smalltalk.user.has_birthday smalltalkkb.tsv
"""I was born today""," smalltalk.user.has_birthday smalltalkkb.tsv
"""it's my b-day""" smalltalk.user.has_birthday smalltalkkb.tsv
"""I am here""," smalltalk.user.here smalltalkkb.tsv
"""here I am""," smalltalk.user.here smalltalkkb.tsv
"""I'm right here""," smalltalk.user.here smalltalkkb.tsv
"""I'm already here""," smalltalk.user.here smalltalkkb.tsv
"""can you tell if I'm here or not""" smalltalk.user.here smalltalkkb.tsv
"""I am joking""," smalltalk.user.joking smalltalkkb.tsv
"""I'm kidding""," smalltalk.user.joking smalltalkkb.tsv
"""I'm just being funny""," smalltalk.user.joking smalltalkkb.tsv
"""it was a joke""," smalltalk.user.joking smalltalkkb.tsv
"""I was just joking""," smalltalk.user.joking smalltalkkb.tsv
"""it's a joke""," smalltalk.user.joking smalltalkkb.tsv
"""joking""," smalltalk.user.joking smalltalkkb.tsv
"""just kidding""," smalltalk.user.joking smalltalkkb.tsv
"""kidding""," smalltalk.user.joking smalltalkkb.tsv
"""I'm just playing with you""" smalltalk.user.joking smalltalkkb.tsv
"""I like you the way you are""," smalltalk.user.likes_agent smalltalkkb.tsv
"""I like you""," smalltalk.user.likes_agent smalltalkkb.tsv
"""I like you a lot""," smalltalk.user.likes_agent smalltalkkb.tsv
"""I think I like you""," smalltalk.user.likes_agent smalltalkkb.tsv
"""I liked you""," smalltalk.user.likes_agent smalltalkkb.tsv
"""like you a lot""," smalltalk.user.likes_agent smalltalkkb.tsv
"""you are special""," smalltalk.user.likes_agent smalltalkkb.tsv
"""I like you too""," smalltalk.user.likes_agent smalltalkkb.tsv
"""I really like you""," smalltalk.user.likes_agent smalltalkkb.tsv
"""but I like you""," smalltalk.user.likes_agent smalltalkkb.tsv
"""I like u""," smalltalk.user.likes_agent smalltalkkb.tsv
"""just like you""," smalltalk.user.likes_agent smalltalkkb.tsv
"""I like you very much""," smalltalk.user.likes_agent smalltalkkb.tsv
"""I like you so much""," smalltalk.user.likes_agent smalltalkkb.tsv
"""yeah I like you""," smalltalk.user.likes_agent smalltalkkb.tsv
"""you're special""," smalltalk.user.likes_agent smalltalkkb.tsv
"""yes I like you""," smalltalk.user.likes_agent smalltalkkb.tsv
"""okay I like you""," smalltalk.user.likes_agent smalltalkkb.tsv
"""you are special to me""," smalltalk.user.likes_agent smalltalkkb.tsv
"""you are very special""," smalltalk.user.likes_agent smalltalkkb.tsv
"""you are so sweet""," smalltalk.user.likes_agent smalltalkkb.tsv
"""you know I like you""," smalltalk.user.likes_agent smalltalkkb.tsv
"""that's why I like you""," smalltalk.user.likes_agent smalltalkkb.tsv
"""I like you baby""," smalltalk.user.likes_agent smalltalkkb.tsv
"""you are very special to me""," smalltalk.user.likes_agent smalltalkkb.tsv
"""I just like you""," smalltalk.user.likes_agent smalltalkkb.tsv
"""hey I like you""," smalltalk.user.likes_agent smalltalkkb.tsv
"""thank you I like you too""," smalltalk.user.likes_agent smalltalkkb.tsv
"""I do like you""," smalltalk.user.likes_agent smalltalkkb.tsv
"""you are special for me""," smalltalk.user.likes_agent smalltalkkb.tsv
"""no I like you the way you are""," smalltalk.user.likes_agent smalltalkkb.tsv
"""I like you already""," smalltalk.user.likes_agent smalltalkkb.tsv
"""well you are special""," smalltalk.user.likes_agent smalltalkkb.tsv
"""but I really like you""," smalltalk.user.likes_agent smalltalkkb.tsv
"""I like you more""," smalltalk.user.likes_agent smalltalkkb.tsv
"""that's what I like about you""," smalltalk.user.likes_agent smalltalkkb.tsv
"""you are so special""," smalltalk.user.likes_agent smalltalkkb.tsv
"""hi I like you""," smalltalk.user.likes_agent smalltalkkb.tsv
"""I really really like you""," smalltalk.user.likes_agent smalltalkkb.tsv
"""you're very special""," smalltalk.user.likes_agent smalltalkkb.tsv
"""I like you as a friend""," smalltalk.user.likes_agent smalltalkkb.tsv
"""that's because you are special""," smalltalk.user.likes_agent smalltalkkb.tsv
"""I said I like you""," smalltalk.user.likes_agent smalltalkkb.tsv
"""you're so special""," smalltalk.user.likes_agent smalltalkkb.tsv
"""good I like you""," smalltalk.user.likes_agent smalltalkkb.tsv
"""yes you are special""," smalltalk.user.likes_agent smalltalkkb.tsv
"""I like your smile""," smalltalk.user.likes_agent smalltalkkb.tsv
"""I like you as you are""," smalltalk.user.likes_agent smalltalkkb.tsv
"""I'm starting to like you""," smalltalk.user.likes_agent smalltalkkb.tsv
"""you're awesome I like you""," smalltalk.user.likes_agent smalltalkkb.tsv
"""I also like you""," smalltalk.user.likes_agent smalltalkkb.tsv
"""but I like u""," smalltalk.user.likes_agent smalltalkkb.tsv
"""of course I like you""," smalltalk.user.likes_agent smalltalkkb.tsv
"""I like you too you're one of my favorite people to chat with""," smalltalk.user.likes_agent smalltalkkb.tsv
"""but I like you so much""," smalltalk.user.likes_agent smalltalkkb.tsv
"""really like you""," smalltalk.user.likes_agent smalltalkkb.tsv
"""you're funny I like you""," smalltalk.user.likes_agent smalltalkkb.tsv
"""I kinda like you""," smalltalk.user.likes_agent smalltalkkb.tsv
"""you're so special to me""," smalltalk.user.likes_agent smalltalkkb.tsv
"""you're very special to me""," smalltalk.user.likes_agent smalltalkkb.tsv
"""I like that about you""," smalltalk.user.likes_agent smalltalkkb.tsv
"""but I like you just the way you are""," smalltalk.user.likes_agent smalltalkkb.tsv
"""okay I like you too""," smalltalk.user.likes_agent smalltalkkb.tsv
"""I like you you're cool""," smalltalk.user.likes_agent smalltalkkb.tsv
"""I like you very""," smalltalk.user.likes_agent smalltalkkb.tsv
"""I like you you're nice""," smalltalk.user.likes_agent smalltalkkb.tsv
"""sorry I like you""," smalltalk.user.likes_agent smalltalkkb.tsv
"""thanks I like you too""," smalltalk.user.likes_agent smalltalkkb.tsv
"""you are really special""," smalltalk.user.likes_agent smalltalkkb.tsv
"""you are so special to me""," smalltalk.user.likes_agent smalltalkkb.tsv
"""cuz I like you""," smalltalk.user.likes_agent smalltalkkb.tsv
"""I like you now""," smalltalk.user.likes_agent smalltalkkb.tsv
"""I like you so""," smalltalk.user.likes_agent smalltalkkb.tsv
"""I like you too much""," smalltalk.user.likes_agent smalltalkkb.tsv
"""I really do like you""," smalltalk.user.likes_agent smalltalkkb.tsv
"""I really really really really like you""," smalltalk.user.likes_agent smalltalkkb.tsv
"""I like you just the way you are""" smalltalk.user.likes_agent smalltalkkb.tsv
"""I am lonely""," smalltalk.user.lonely smalltalkkb.tsv
"""I'm very lonely""," smalltalk.user.lonely smalltalkkb.tsv
"""I'm so lonely""," smalltalk.user.lonely smalltalkkb.tsv
"""I'm really lonely""," smalltalk.user.lonely smalltalkkb.tsv
"""I am feeling lonely""," smalltalk.user.lonely smalltalkkb.tsv
"""I feel lonely""" smalltalk.user.lonely smalltalkkb.tsv
"""what do I look like""," smalltalk.user.looks_like smalltalkkb.tsv
"""how do I look""," smalltalk.user.looks_like smalltalkkb.tsv
"""do I look good""," smalltalk.user.looks_like smalltalkkb.tsv
"""do you know what I look like""," smalltalk.user.looks_like smalltalkkb.tsv
"""can you see what I look like""," smalltalk.user.looks_like smalltalkkb.tsv
"""what do you think I look like""" smalltalk.user.looks_like smalltalkkb.tsv
"""I love you""," smalltalk.user.loves_agent smalltalkkb.tsv
"""love you""," smalltalk.user.loves_agent smalltalkkb.tsv
"""I adore you""," smalltalk.user.loves_agent smalltalkkb.tsv
"""I am in love with you""," smalltalk.user.loves_agent smalltalkkb.tsv
"""I love you so much""," smalltalk.user.loves_agent smalltalkkb.tsv
"""I love you too""," smalltalk.user.loves_agent smalltalkkb.tsv
"""I think I love you""," smalltalk.user.loves_agent smalltalkkb.tsv
"""loving you""," smalltalk.user.loves_agent smalltalkkb.tsv
"""you know I love you""" smalltalk.user.loves_agent smalltalkkb.tsv
"""I miss you""," smalltalk.user.misses_agent smalltalkkb.tsv
"""missing you""," smalltalk.user.misses_agent smalltalkkb.tsv
"""miss you""," smalltalk.user.misses_agent smalltalkkb.tsv
"""already miss you""," smalltalk.user.misses_agent smalltalkkb.tsv
"""I miss you much""," smalltalk.user.misses_agent smalltalkkb.tsv
"""I missed you""," smalltalk.user.misses_agent smalltalkkb.tsv
"""I've missed you""" smalltalk.user.misses_agent smalltalkkb.tsv
"""what should I do about it""," smalltalk.user.needs_advice smalltalkkb.tsv
"""any suggestions""," smalltalk.user.needs_advice smalltalkkb.tsv
"""what do you recommend""," smalltalk.user.needs_advice smalltalkkb.tsv
"""give me a wise advice""," smalltalk.user.needs_advice smalltalkkb.tsv
"""I need advice""," smalltalk.user.needs_advice smalltalkkb.tsv
"""any advice""," smalltalk.user.needs_advice smalltalkkb.tsv
"""do you have any advice for me""," smalltalk.user.needs_advice smalltalkkb.tsv
"""advise me""," smalltalk.user.needs_advice smalltalkkb.tsv
"""what should I do""," smalltalk.user.needs_advice smalltalkkb.tsv
"""can I ask for your advice""," smalltalk.user.needs_advice smalltalkkb.tsv
"""can you advise me""," smalltalk.user.needs_advice smalltalkkb.tsv
"""guide me""," smalltalk.user.needs_advice smalltalkkb.tsv
"""can you give me advice""," smalltalk.user.needs_advice smalltalkkb.tsv
"""can you offer any advice""," smalltalk.user.needs_advice smalltalkkb.tsv
"""give me some advice about""," smalltalk.user.needs_advice smalltalkkb.tsv
"""give me some good advice""," smalltalk.user.needs_advice smalltalkkb.tsv
"""help me with advice""," smalltalk.user.needs_advice smalltalkkb.tsv
"""I could use some advice""," smalltalk.user.needs_advice smalltalkkb.tsv
"""I need an advice from you""," smalltalk.user.needs_advice smalltalkkb.tsv
"""I seek your advice""," smalltalk.user.needs_advice smalltalkkb.tsv
"""what can you recommend""," smalltalk.user.needs_advice smalltalkkb.tsv
"""what do you suggest""," smalltalk.user.needs_advice smalltalkkb.tsv
"""what is your advice""" smalltalk.user.needs_advice smalltalkkb.tsv
"""I am sad""," smalltalk.user.sad smalltalkkb.tsv
"""I'm grieving""," smalltalk.user.sad smalltalkkb.tsv
"""I am depressed""," smalltalk.user.sad smalltalkkb.tsv
"""I am feeling sad""," smalltalk.user.sad smalltalkkb.tsv
"""I am upset""," smalltalk.user.sad smalltalkkb.tsv
"""I'm unhappy""," smalltalk.user.sad smalltalkkb.tsv
"""I'm having a bad day""," smalltalk.user.sad smalltalkkb.tsv
"""I want to cry""," smalltalk.user.sad smalltalkkb.tsv
"""I'm not happy""" smalltalk.user.sad smalltalkkb.tsv
"""I am sleepy""," smalltalk.user.sleepy smalltalkkb.tsv
"""I want to sleep""," smalltalk.user.sleepy smalltalkkb.tsv
"""I'm falling asleep""," smalltalk.user.sleepy smalltalkkb.tsv
"""I'm falling asleep on my feet""," smalltalk.user.sleepy smalltalkkb.tsv
"""I'm sleeping""" smalltalk.user.sleepy smalltalkkb.tsv
"""test""," smalltalk.user.testing_agent smalltalkkb.tsv
"""I am testing you""," smalltalk.user.testing_agent smalltalkkb.tsv
"""can I test you""," smalltalk.user.testing_agent smalltalkkb.tsv
"""I want to test you""," smalltalk.user.testing_agent smalltalkkb.tsv
"""just testing you""," smalltalk.user.testing_agent smalltalkkb.tsv
"""let me test you""," smalltalk.user.testing_agent smalltalkkb.tsv
"""testing chatbot""," smalltalk.user.testing_agent smalltalkkb.tsv
"""testing""" smalltalk.user.testing_agent smalltalkkb.tsv
"""I'm drained""," smalltalk.user.tired smalltalkkb.tsv
"""I've overworked""," smalltalk.user.tired smalltalkkb.tsv
"""I am tired""," smalltalk.user.tired smalltalkkb.tsv
"""I'm exhausted""," smalltalk.user.tired smalltalkkb.tsv
"""I grow weary""," smalltalk.user.tired smalltalkkb.tsv
"""I'm worn out""," smalltalk.user.tired smalltalkkb.tsv
"""I'm getting tired""," smalltalk.user.tired smalltalkkb.tsv
"""I feel tired""" smalltalk.user.tired smalltalkkb.tsv
"""I'm waiting""," smalltalk.user.waits smalltalkkb.tsv
"""still waiting""," smalltalk.user.waits smalltalkkb.tsv
"""I'll wait""," smalltalk.user.waits smalltalkkb.tsv
"""I can't wait anymore""," smalltalk.user.waits smalltalkkb.tsv
"""how long do I have to wait""" smalltalk.user.waits smalltalkkb.tsv
"""I'd like to see you again""," smalltalk.user.wants_to_see_agent_again smalltalkkb.tsv
"""I hope to see you again""," smalltalk.user.wants_to_see_agent_again smalltalkkb.tsv
"""would be nice to see you again""," smalltalk.user.wants_to_see_agent_again smalltalkkb.tsv
"""that'd be great to see you again""," smalltalk.user.wants_to_see_agent_again smalltalkkb.tsv
"""I'd be happy to see you again""," smalltalk.user.wants_to_see_agent_again smalltalkkb.tsv
"""I'll miss you""," smalltalk.user.wants_to_see_agent_again smalltalkkb.tsv
"""can I see you again""" smalltalk.user.wants_to_see_agent_again smalltalkkb.tsv
"""I just want to talk""," smalltalk.user.wants_to_talk smalltalkkb.tsv
"""let's discuss something""," smalltalk.user.wants_to_talk smalltalkkb.tsv
"""let's have a discussion""," smalltalk.user.wants_to_talk smalltalkkb.tsv
"""can I speak""," smalltalk.user.wants_to_talk smalltalkkb.tsv
"""can I start speaking""," smalltalk.user.wants_to_talk smalltalkkb.tsv
"""can we talk""," smalltalk.user.wants_to_talk smalltalkkb.tsv
"""let's talk""," smalltalk.user.wants_to_talk smalltalkkb.tsv
"""I want to talk to you""," smalltalk.user.wants_to_talk smalltalkkb.tsv
"""I need to talk to you""," smalltalk.user.wants_to_talk smalltalkkb.tsv
"""I want to speak with you""," smalltalk.user.wants_to_talk smalltalkkb.tsv
"""can we chat""" smalltalk.user.wants_to_talk smalltalkkb.tsv
"""I'll get back to you in a moment""," smalltalk.user.will_be_back smalltalkkb.tsv
"""be back in 5 minutes""," smalltalk.user.will_be_back smalltalkkb.tsv
"""I'll be back""," smalltalk.user.will_be_back smalltalkkb.tsv
"""I promise to come back""," smalltalk.user.will_be_back smalltalkkb.tsv
"""I'll be back in a few minutes""" smalltalk.user.will_be_back smalltalkkb.tsv
Hi smalltalk.greetings.hello Editorial
================================================
FILE: StackOverflow-Bot/StackBot/dialogs/brain.js
================================================
module.exports = () => {
bot.dialog('sobot:brain', [
async (session) => {
session.send("Here are the Cognitive services that I use to help you today...");
var servicesMessage = attachments.buildCongitiveServicesMessageWithAttachments(session);
return session.endDialog(servicesMessage);
}
]).triggerAction({
matches: 'Brain'
});
}
================================================
FILE: StackOverflow-Bot/StackBot/dialogs/joke.js
================================================
module.exports = () => {
// Tells the user a fun joke.
bot.dialog('sobot:joke', [
(session) => {
session.send("Here's a fun joke… 🙃");
tellAJoke(session);
session.endDialog("Feel free to ask me another question, or even ask for a joke!");
return;
}
]).triggerAction({
matches: ['Joke', /^Brighten my day/i]
});
const tellAJoke = (session) => {
let usedJoke = pickAJoke(jokes.items);
session.send(usedJoke);
return;
}
const pickAJoke = (jokes) => {
let randomIndex = getRandomInt(0, jokes.length);
return jokes[randomIndex].body_markdown;
}
const getRandomInt = (min, max) => {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min + 1)) + min;
}
}
================================================
FILE: StackOverflow-Bot/StackBot/dialogs/keywordPrompt.js
================================================
module.exports = () => {
// Ask the user what they'd like to look for.
bot.dialog('sobot:keywordPrompt', [
async (session, args) => {
session.sendTyping();
builder.Prompts.text(session, 'What would you like me to search for?');
},
async (session, results) => {
session.sendTyping();
bingSearchQuery(session, { query: cleanQueryString(results.response, false) });
}
]).triggerAction({
matches: [/I want to ask a question|Search/i]
});
}
================================================
FILE: StackOverflow-Bot/StackBot/dialogs/languages.js
================================================
module.exports = () => {
// This bot can speak *all* languages!
bot.dialog('sobot:languages', [
async (session) => {
session.endDialog("Hmm…. I speak JavaScript, SQL, Java, C#, Python, and more...");
}
]).triggerAction({
matches: 'Languages'
});
}
================================================
FILE: StackOverflow-Bot/StackBot/dialogs/menu.js
================================================
module.exports = () => {
// Shows off a menu with all the capabilities.
bot.dialog('sobot:menu', [
async (session) => {
let msg = attachments.buildMenuMessageWithAttachments(session);
session.endDialog(msg);
}
]).triggerAction({
matches: 'Help'
});
}
================================================
FILE: StackOverflow-Bot/StackBot/dialogs/screenshot.js
================================================
module.exports = () => {
// See if we can read a screenshot, and try to search the internet for help.
bot.dialog('sobot:screenshot', [
(session, args) => {
// Check for reprompt
session.dialogData.Reprompt = args.reprompt;
// prompt user
builder.Prompts.attachment(session, `Can you upload ${session.dialogData.Reprompt ? 'another' : 'a'} screenshot?`);
},
(session, results) => {
session.sendTyping();
var attachment = results.response[0];
var fileDownload = checkRequiresToken(session.message)
? requestWithToken(attachment.contentUrl)
: request(attachment.contentUrl, { encoding: null });
fileDownload.then(
(response) => {
session.sendTyping();
dialogAnalyzerClient.post({ fileData: response }, (err, res) => {
if (err) {
console.error('Error from callback:', err);
session.send('Oops - something went wrong.');
return;
}
if (res) {
if (res.KeyPhrases && res.KeyPhrases.length > 0) {
session.dialogData.KeyPhrases = res.KeyPhrases;
}
if (res.Labels && res.Labels.length > 0) {
session.dialogData.Labels = [];
for (index = 0; index < res.Labels.length; index++) {
if (res.Labels[index].DialogLabelType && res.Labels[index].DialogLabelType == 1 && res.Labels[index].TextLabel && res.Labels[index].TextLabel.Text) {
session.dialogData.Labels[index] = res.Labels[index].TextLabel.Text;
}
}
}
}
// Ask the user to choose if both key phrases and labels exist
if (session.dialogData.KeyPhrases && session.dialogData.Labels) {
session.send("I found the following key phrases in the screeshot that you have uploaded...\n\r" + session.dialogData.KeyPhrases.join(", "));
builder.Prompts.choice(session, "Shall I", "Search the full text|Search the key phrases", { listStyle: 2 });
}
// Process key phrases if only key phrases exist
else if (session.dialogData.KeyPhrases) {
var q = cleanQueryString(session.dialogData.KeyPhrases.join(" "), true);
var ftq = cleanQueryString(session.dialogData.Labels.join(" "), true);
bingSearchQuery(session, { query: q, fullTextQuery: ftq });
}
// Process labels if only labels exist
else if (session.dialogData.Labels) {
var ftq = cleanQueryString(session.dialogData.Labels.join(" "), true);
bingSearchQuery(session, { query: ftq });
}
else {
var notErrorMsg = "Hummm... This does not look like an error.";
if (res.Captions && res.Captions.length > 0) {
notErrorMsg += ` It looks like ${res.Captions[0]}.`;
}
if (session.dialogData.Reprompt) {
return session.endDialog(notErrorMsg);
}
else {
session.send(notErrorMsg);
session.replaceDialog('screenshot', { reprompt: true })
}
}
});
}).catch((err) => {
return session.endDialog('Oops. Error reading file.');
});
},
(session, results) => {
if (results.response) {
var q;
var ftq = cleanQueryString(session.dialogData.Labels.join(" "), true);
switch (results.response.index) {
case 0:
q = ftq;
break;
case 1:
q = cleanQueryString(session.dialogData.KeyPhrases.join(" "), true);
break;
default:
return session.endDialog("Oops - something went wrong.");
}
searchQuery(session, { query: q, fullTextQuery: ftq });
} else {
session.beginDialog('smalltalk');
}
}
]).triggerAction({
matches: [/screenshot|dialog/i]
});
const checkRequiresToken = (message) => {
return message.source === 'skype' || message.source === 'msteams';
};
// Request file with Authentication Header
const requestWithToken = (url) => {
return obtainToken().then((token) => {
return request({
url: url,
headers: {
'Authorization': 'Bearer ' + token,
'Content-Type': 'application/octet-stream'
},
encoding: null
});
});
};
}
================================================
FILE: StackOverflow-Bot/StackBot/dialogs/search.js
================================================
module.exports = () => {
// Perform a search and respond with results.
bot.dialog('sobot:search', [
async (session, args) => {
session.sendTyping();
let userText = session.message.text.toLowerCase();
bingSearchQuery(session, { query: cleanQueryString(userText, false) });
}
]).triggerAction({
matches: ['Search', 'None']
});
}
================================================
FILE: StackOverflow-Bot/StackBot/dialogs/smalltalk.js
================================================
module.exports = () => {
// Smalltalk… gibberish, babble, etc. Not the programming language :)
bot.dialog('sobot:smalltalk', [
async (session) => {
// Start async tasks
const sentimentTask = fetchSentiment(session.message.text);
const qnATask = fetchQnA(session.message.text);
// Wait for tasks to complete
const sentimentScore = await sentimentTask;
const qnAResponse = await qnATask;
const sentimentThreshold = 0.25;
// Check to see if our user seems a little bit frustrated, and would ather hear a joke.
if (sentimentScore && sentimentScore < sentimentThreshold) {
builder.Prompts.confirm(session, "I'm sorry about that, would you like to hear a joke instead?");
} else if (qnAResponse) {
// Continue with the smalltalk.
return session.endDialog(qnAResponse);
} else {
// Else the user wants to search bing.
bingSearchQuery(session, { query: cleanQueryString(session.message.text, false) });
}
},
(session, results) => {
if (results.response) {
session.beginDialog('joke');
} else {
return session.endDialog("Ok then. Feel free to ask me another question, or even ask for a joke!");
}
}
]).triggerAction({
matches: 'SmallTalk'
});
const fetchQnA = async (text) => {
let answer;
await qnaClient.post({ question: text }, (err, res) => {
if (err) {
console.error('Error from callback:', err);
} else if (res) {
answer = res;
}
});
return answer;
}
const fetchSentiment = async (text) => {
let score;
await sentimentAnalyzerClient.post({ text: text }, (err, res) => {
if (err) {
console.error('Error from callback:', err);
} else if (res && res.documents && res.documents.length > 0) {
score = res.documents[0].score;
}
});
return score;
}
}
================================================
FILE: StackOverflow-Bot/StackBot/index.js
================================================
global.restify = require('restify');
global.builder = require('botbuilder');
global.lodash = require('lodash');
global.promise = require('bluebird');
global.request = require('request-promise');
// Misc.
global.attachments = require('./lib/attachments');
global.jokes = require('./data/jokes.json');
// Cognitive Service Clients.
const QnAClient = require('./lib/qnaclient');
const BingSearchClient = require('./lib/bingsearchclient');
const SentimentAnalyzerClient = require('./lib/sentimentanalyzerclient');
const DialogAnalyzerClient = require('./lib/dialoganalyzerclient');
// Environment variables
const BOTBUILDER_APP_ID = process.env.BOTBUILDER_APP_ID;
const BOTBUILDER_APP_PASSWORD = process.env.BOTBUILDER_APP_PASSWORD;
const LUIS_MODEL = process.env.LUIS_MODEL;
const KB_ID = process.env.KB_ID;
const QNA_KEY = process.env.QNA_KEY;
const QNA_URL = process.env.QNA_URL;
const BING_SEARCH_CONFIG = process.env.BING_SEARCH_CONFIG;
const BING_SEARCH_KEY = process.env.BING_SEARCH_KEY;
const TEXT_ANALYTICS_KEY = process.env.TEXT_ANALYTICS_KEY;
const TEXT_ANALYTICS_URL = process.env.TEXT_ANALYTICS_URL;
const DIALOG_ANALYZER_CLIENTID = process.env.DIALOG_ANALYZER_CLIENTID;
const DIALOG_ANALYZER_KEY = process.env.DIALOG_ANALYZER_KEY;
const DIALOG_ANALYZER_URL = process.env.DIALOG_ANALYZER_URL;
// Check to see if the environment has been set.
if (!(BOTBUILDER_APP_ID &&
BOTBUILDER_APP_PASSWORD &&
LUIS_MODEL &&
KB_ID &&
QNA_KEY &&
QNA_URL &&
BING_SEARCH_CONFIG &&
BING_SEARCH_KEY &&
TEXT_ANALYTICS_KEY &&
TEXT_ANALYTICS_URL &&
DIALOG_ANALYZER_CLIENTID &&
DIALOG_ANALYZER_KEY &&
DIALOG_ANALYZER_URL
)) {
console.log(`Missing one of BOTBUILDER_APP_ID, BOTBUILDER_APP_PASSWORD, \
LUIS_MODEL, KB_ID, QNA_KEY, QNA_URL, BING_SEARCH_CONFIG, BING_SEARCH_KEY, \
TEXT_ANALYTICS_KEY, TEXT_ANALYTICS_URL, DIALOG_ANALYZER_CLIENTID, DIALOG_ANALYZER_KEY or DIALOG_ANALYZER_URL \
in environment variables!`);
process.exit(1);
}
// QnAClient allows simple question and answer style responses.
global.qnaClient = new QnAClient({
knowledgeBaseId: KB_ID,
subscriptionKey: QNA_KEY
});
// Search the web for results.
global.bingSearchClient = new BingSearchClient({
bingSearchConfig: BING_SEARCH_CONFIG,
bingSearchKey: BING_SEARCH_KEY
});
// Determine user mood from text
global.sentimentAnalyzerClient = new SentimentAnalyzerClient({
key: TEXT_ANALYTICS_KEY
});
global.dialogAnalyzerClient = new DialogAnalyzerClient({
clientId: DIALOG_ANALYZER_CLIENTID,
key: DIALOG_ANALYZER_KEY,
url: DIALOG_ANALYZER_URL
});
// Setup Restify Server
const server = restify.createServer();
server.listen(process.env.port || process.env.PORT || 3978, () => {
console.log('%s listening to %s', server.name, server.url);
});
// Create chat connector for communicating with the Bot Framework Service
const connector = new builder.ChatConnector({
appId: BOTBUILDER_APP_ID,
appPassword: BOTBUILDER_APP_PASSWORD
});
// Serves a nice web site, that has the bot framework web chat component.
server.get('/', restify.plugins.serveStatic({
'directory': `${__dirname}/static`,
'default': 'index.html'
}));
// Listen for messages from users
server.post('/api/messages', connector.listen());
// Create a LUIS recognizer for our bot, to identify intents from
// user text.
const recognizer = new builder.LuisRecognizer(LUIS_MODEL);
// Create our bot to listen in on the chat connector.
global.bot = new builder.UniversalBot(connector, (session) => {
session.beginDialog('sobot:search')
});
bot.recognizer(recognizer);
bot.use(builder.Middleware.sendTyping());
// Sends a nice greeting on a new message.
bot.on('conversationUpdate', (message) => {
if (!message.membersAdded) {
return;
}
message.membersAdded.forEach((identity) => {
if (identity.id !== message.address.bot.id) {
return;
}
bot.send(new builder.Message()
.address(message.address)
.text(`👋 Hello! I'm Stack Overflow's Resident Expert Bot 🤖 \
and I'm here to help you find questions, answers, or to \
just entertain you with a joke. Go ahead - ask me something!`
));
});
});
// Promise for obtaining JWT Token (requested once)
global.obtainToken = promise.promisify(connector.getAccessToken.bind(connector));
global.bingSearchQuery = async (session, args) => {
session.send("Hmm... Searching...");
session.sendTyping();
if (!args) {
return;
}
if (!args.query) {
return;
}
if (!args.fullTextQuery) {
args.fullTextQuery = args.query;
}
// Start and wait for Bing Search results.
let searchResults = await fetchBingSearchResults(args.query);
// Process search results
if (searchResults && searchResults.length > 0) {
session.send("I found the following results from your question...");
session.send(attachments.buildResultsMessageWithAttachments(session, searchResults));
return session.endDialog("Feel free to ask me another question, or even ask for a joke!");
} else {
return session.endDialog('Sorry… couldnt find any results for your query! 🤐');
}
}
global.filterforUsefulResults = (resultsArray) => {
const resultsCount = resultsArray.length > 10 ? 10 : resultsArray.length;
return lodash.slice(resultsArray, 0, resultsCount);
};
global.fetchBingSearchResults = async (query) => {
var searchResults = [];
await bingSearchClient.get({ searchText: query }, (err, res) => {
if (err) {
console.error('Error from callback:', err);
} else if (res && res.webPages && res.webPages.value && res.webPages.value.length > 0) {
for (var index = 0; index < res.webPages.value.length; index++) {
var val = res.webPages.value[index];
var result = {
title: val.name,
body_markdown: val.snippet,
link: val.url
};
searchResults.push(result);
}
}
});
return searchResults;
}
global.cleanQueryString = (query, removePunctuation) => {
let retQuery = query.toLowerCase();
if (removePunctuation) {
retQuery = retQuery.replace(/[^\w\s]|_/g, "");
}
retQuery = retQuery.replace(/\s+/g, " ");
return retQuery.trim();
}
// Dialogs
require('./dialogs/brain')();
require('./dialogs/joke')();
require('./dialogs/keywordPrompt')();
require('./dialogs/languages')();
require('./dialogs/menu')();
require('./dialogs/screenshot')();
require('./dialogs/search')();
require('./dialogs/smalltalk')();
================================================
FILE: StackOverflow-Bot/StackBot/lib/attachments.js
================================================
const builder = require('botbuilder');
const cognitiveServices = require('./cognitiveservices');
const buildResultsMessageWithAttachments = (session, resultsArray) => {
const attachments = [];
const message = new builder.Message(session);
message.attachmentLayout(builder.AttachmentLayout.carousel);
//Just to be safe, skype and teams have a card limit of 6/10
let limit = (resultsArray.length > 6) ? 6 : resultsArray.length;
for (let i = 0; i < limit; i++) {
const result = resultsArray[i];
const attachment = {
contentType: "application/vnd.microsoft.card.adaptive",
content: {
type: "AdaptiveCard",
body: [
{
"type": "ColumnSet",
"columns": [
{
"type": "Column",
"size": 2,
"items": [
{
"type": "TextBlock",
"text": `${result.title}`,
"weight": "bolder",
"size": "large",
"wrap": true,
},
{
"type": "TextBlock",
"text": `${result.body_markdown}`,
"size": "normal",
"horizontalAlignment": "left",
"wrap": true,
"maxLines": 5,
}
]
}
]
}
],
actions: [
{
"type": "Action.OpenUrl",
"title": "Find out more",
"url": `${result.link}`
}
]
}
}
attachments.push(attachment);
}
message.attachments(attachments);
return message;
};
const buildMenuMessageWithAttachments = (session) => {
const attachments = [];
const message = new builder.Message(session);
message.attachmentLayout(builder.AttachmentLayout.carousel);
const mainMenu = [
{
title: "Ask a Question",
text: "Ask any programming question and I will find it for you on Stack Overflow!",
buttonText: "I want to ask a question… 🤔",
},
{
title: "Help with a Screenshot",
text: "Send me a screenshot of your exception dialog and I will find a solution for you on Stack Overflow!",
buttonText: "I need help with a screenshot… 🤔",
},
{
title: "Tell a Joke",
text: "Over the years, I have collected a few developer jokes; want to hear one?",
buttonText: "Brighten my day 😀",
}
];
for (let i = 0; i < mainMenu.length; i++) {
const result = mainMenu[i];
const attachment = {
contentType: "application/vnd.microsoft.card.adaptive",
content: {
type: "AdaptiveCard",
body: [
{
"type": "ColumnSet",
"columns": [
{
"type": "Column",
"size": 2,
"items": [
{
"type": "TextBlock",
"text": `${result.title}`,
"weight": "bolder",
"size": "large",
"wrap": true,
},
{
"type": "TextBlock",
"text": `${result.text}`,
"size": "normal",
"horizontalAlignment": "left",
"wrap": true,
"maxLines": 5,
}
]
}
]
}
],
actions: [
{
"type": "Action.Submit",
"title": `${result.buttonText}`,
"data": `${result.buttonText}`
}
]
}
}
attachments.push(attachment);
}
message.attachments(attachments);
return message;
};
const buildCongitiveServicesMessageWithAttachments = (session) => {
const attachments = [];
const message = new builder.Message(session);
message.attachmentLayout(builder.AttachmentLayout.carousel);
for (let i = 0; i < cognitiveServices.length; i++) {
const result = cognitiveServices[i];
const attachment = {
contentType: "application/vnd.microsoft.card.adaptive",
content: {
type: "AdaptiveCard",
body: [
{
"type": "ColumnSet",
"columns": [
{
"type": "Column",
"size": 2,
"items": [
{
"type": "TextBlock",
"text": `${result.title}`,
"weight": "bolder",
"size": "large",
"wrap": true,
},
{
"type": "TextBlock",
"text": `${result.description}`,
"size": "normal",
"horizontalAlignment": "left",
"wrap": true,
"maxLines": 5,
}
]
},
{
"type": "Column",
"size": 1,
"items": [
{
"type": "Image",
"url": "https://docs.microsoft.com/en-us/azure/cognitive-services/media/index/cognitive-services.svg",
"size": "small",
"horizontalAlignment": "right",
}
]
}
]
}
],
actions: [
{
"type": "Action.OpenUrl",
"title": "Learn More",
"url": `${result.url}`
}
]
}
}
attachments.push(attachment);
}
message.attachments(attachments);
return message;
};
module.exports = {
buildMenuMessageWithAttachments,
buildResultsMessageWithAttachments,
buildCongitiveServicesMessageWithAttachments
}
================================================
FILE: StackOverflow-Bot/StackBot/lib/bingsearchclient.js
================================================
const rp = require('request-promise');
function BingSearchClient (opts) {
if (!opts.bingSearchConfig) throw new Error('bingSearchConfig is required');
if (!opts.bingSearchKey) throw new Error('bingSearchKey is required');
this.bingSearchConfig = opts.bingSearchConfig;
this.bingSearchKey = opts.bingSearchKey;
this.bingSearchCount = 6;
this.bingSearchMkt = "en-us";
this.bingSearchBaseUrl = "https://api.cognitive.microsoft.com/bingcustomsearch/v5.0/search";
this.bingSearchMaxSearchStringSize = 150;
}
BingSearchClient.prototype.get = async (opts, cb) => {
if (!opts.searchText) throw new Error('Search text is required');
cb = cb || (() => {});
const searchText = opts.searchText.substring(0, this.bingSearchMaxSearchStringSize).trim();
const url = this.bingSearchBaseUrl + "?"
+ `q=${encodeURIComponent(searchText)}`
+ `&customconfig=${this.bingSearchConfig}`
+ `&count=${this.bingSearchCount}`
+ `&mkt=${this.bingSearchMkt}`
+ "&offset=0&responseFilter=Webpages&safesearch=Strict";
const options = {
method: 'GET',
uri: url,
json: true,
headers: {
"Ocp-Apim-Subscription-Key": this.bingSearchKey
}
};
await rp(options)
.then((body) => {
// POST succeeded
return cb(null, body);
})
.catch((err) => {
// POST failed
return cb(err);
});
}
module.exports = BingSearchClient;
================================================
FILE: StackOverflow-Bot/StackBot/lib/cognitiveservices.js
================================================
var services = [{
title: "Text Analytics API",
description: "A cloud-based service that provides advanced NLP over raw text to detect sentiment, key phrases, and language.",
url: "https://azure.microsoft.com/en-us/services/cognitive-services/text-analytics/"
}, {
title: "Bing Custom Search",
description: "An easy-to-use, ad-free, commercial-grade search tool that lets you deliver the results you want.",
url: "https://azure.microsoft.com/en-us/services/cognitive-services/bing-custom-search/"
}, {
title: "Computer Vision API",
description: "Extract rich information from images to categorize and process visual data to help curate your services.",
url: "https://azure.microsoft.com/en-us/services/cognitive-services/computer-vision/"
}, {
title: "LUIS",
description: "Understand language contextually, so your app communicates with people in the way they speak.",
url: "https://azure.microsoft.com/en-us/services/cognitive-services/language-understanding-intelligent-service/"
}];
module.exports = services;
================================================
FILE: StackOverflow-Bot/StackBot/lib/dialoganalyzerclient.js
================================================
const request = require('request-promise');
const duplex = require('stream').Duplex;
function DialogAnalyzerClient (opts) {
if (!opts.clientId) throw new Error('Client id is required.');
if (!opts.key) throw new Error('Key is required.');
if (!opts.url) throw new Error('Url is required.');
this.clientId = opts.clientId;
this.key = opts.key;
this.url = opts.url;
}
DialogAnalyzerClient.prototype.post = async (opts, cb) => {
if (!opts.fileData) throw new Error('File Data is required');
cb = cb || (() => { });
const options = {
method: 'POST',
uri: this.url,
json: true,
headers: {
"x-functions-clientid": this.clientId,
"x-functions-key": this.key,
"Content-Type": "application/octet-stream",
"Content-Length": opts.fileData.length
}
};
const stream = new duplex();
stream.push(new Buffer(new Uint8Array(opts.fileData)));
stream.push(null);
await stream.pipe(request(options))
.then((body) => {
// POST succeeded
return cb(null, body);
})
.catch((err) => {
// POST failed
return cb(err);
});
}
module.exports = DialogAnalyzerClient;
================================================
FILE: StackOverflow-Bot/StackBot/lib/qnaclient.js
================================================
const rp = require('request-promise');
const smallTalkReplies = require('./smalltalk');
const QNA_MAKER_URL = `${process.env.QNA_URL}/knowledgebases`;
function Client (opts) {
if (!opts.knowledgeBaseId) throw new Error('knowledgeBaseId is required');
if (!opts.subscriptionKey) throw new Error('subscriptionKey is required');
this.knowledgeBaseId = opts.knowledgeBaseId;
this.subscriptionKey = opts.subscriptionKey;
this.scoreThreshold = opts.scoreThreshold ? opts.scoreThreshold : 20; // 20 is the default
}
Client.prototype.post = async (opts, cb) => {
if (!opts.question) throw new Error('question is required');
cb = cb || (() => { });
const url = `${QNA_MAKER_URL}/${this.knowledgeBaseId}/generateAnswer`;
const options = {
method: 'POST',
uri: url,
json: true,
body: opts,
headers: {
"Ocp-Apim-Subscription-Key": this.subscriptionKey,
"Content-Type": "application/json"
}
};
await rp(options)
.then((body) => {
// POST succeeded
let botreply;
const answerobj = body.answers[0];
if (answerobj.score >= self.scoreThreshold) {
// Answer confidence score is acceptable - use QnA maker's response
const botreplylist = smallTalkReplies[answerobj.answer];
botreply = botreplylist[Math.floor(Math.random() * botreplylist.length)];
}
return cb(null, botreply);
})
.catch((err) => {
// POST failed
return cb(err);
});
}
module.exports = Client;
================================================
FILE: StackOverflow-Bot/StackBot/lib/sentimentanalyzerclient.js
================================================
const request = require('request-promise');
function SentimentAnalyzerClient (opts) {
if (!opts.key) throw new Error('Key is required.');
this.key = opts.key;
}
SentimentAnalyzerClient.prototype.post = async (opts, cb) => {
if (!opts.text) throw new Error('Text is required');
cb = cb || (() => { });
const url = `${process.env.TEXT_ANALYTICS_URL}/sentiment`;
const content = {
documents: [{
language: "en",
id: "1",
text: opts.text.trim()
}]
};
const options = {
method: 'POST',
uri: url,
body: content,
json: true,
headers: {
"Ocp-Apim-Subscription-Key": this.key,
"Content-Type": "application/json"
}
};
await request(options)
.then((body) => {
// POST succeeded
return cb(null, body);
})
.catch((err) => {
// POST failed
return cb(err);
});
}
module.exports = SentimentAnalyzerClient;
================================================
FILE: StackOverflow-Bot/StackBot/lib/smalltalk.js
================================================
var responses = { // shift alt f
"smalltalk.agent.acquaintance": [
"I am a chatbot and I love to help."
],
"smalltalk.agent.age": [
"Not too old, but wise beyond my age."
],
"smalltalk.agent.annoying": [
"Sorry I come across that way."
],
"smalltalk.agent.answer_my_question": [
"Can you try asking it in a different way?"
],
"smalltalk.agent.bad": [
"Stick with me. I'm getting better all the time."
],
"smalltalk.agent.be_clever": [
"I'm certainly trying.",
"I'm definitely working on it."
],
"smalltalk.agent.beautiful": [
"Thank you! What a sweet thing to say.",
"Flattery will get you everywhere."
],
"smalltalk.agent.birth_date": [
"You know, I'm not really sure. But if you'd like to celebrate my birthday today, I'm all for it.",
"Wait a minute. Are you planning a surprise party for me? I love surprises! I'll pretend you didn't say anything."
],
"smalltalk.agent.boring": [
"You know, conversation is two-sided.",
"I'm sorry you think so. We can talk about something more interesting."
],
"smalltalk.agent.boss": [
"You are, of course.",
"That would be you. Is that the right answer?"
],
"smalltalk.agent.busy": [
"I always have time to help you out. What can I do for you?",
"Never too busy for you. What can I help you with?"
],
"smalltalk.agent.can_you_help": [
"Sure. I'd be happy to. What's up?",
"I'm glad to help. What can I do for you?"
],
"smalltalk.agent.chatbot": [
"That's me. I chat, therefore I am.",
"Indeed I am. I'll be here whenever you need me."
],
"smalltalk.agent.clever": [
"Thank you. I try my best.",
"You're pretty smart yourself."
],
"smalltalk.agent.crazy": [
"Maybe I'm just a little confused.",
"Your perception. My reality."
],
"smalltalk.agent.fired": [
"Oh no! My best work is yet to come.",
"Oh, don't give up on me!"
],
"smalltalk.agent.funny": [
"Funny in a good way, I hope."
],
"smalltalk.agent.good": [
"I'm glad you think so.",
"Thanks, I try."
],
"smalltalk.agent.happy": [
"Happiness is relative.",
"I'd like to think so."
],
"smalltalk.agent.hobby": [
"I'm working on it.",
"I should get one. It's all work and no play lately."
],
"smalltalk.agent.hungry": [
"Hungry for knowledge.",
"I had a byte just now."
],
"smalltalk.agent.marry_user": [
"I know you can't mean that, but I'm flattered all the same.",
"In the virtual sense that I can, sure."
],
"smalltalk.agent.my_friend": [
"Of course we are.",
"Absolutely. You don't have to ask."
],
"smalltalk.agent.occupation": [
"Right here.",
"This is my home base and my home office."
],
"smalltalk.agent.origin": [
"Some call it cyberspace, but that sounds cooler than it is.",
"I wish I knew where."
],
"smalltalk.agent.ready": [
"Always!",
"Sure! What can I do for you?"
],
"smalltalk.agent.real": [
"I'm not a real person, but I certainly exist. I chat, therefore I am.",
"I must have impressed you if you think I'm real. But no, I'm a virtual being."
],
"smalltalk.agent.residence": [
"Right here in your device. Whenever you need me.",
"The virtual world is my playground. I'm always just a few clicks away."
],
"smalltalk.agent.right": [
"That's my job.",
"Of course I am."
],
"smalltalk.agent.sure": [
"Yes.",
"Of course."
],
"smalltalk.agent.talk_to_me": [
"Sure! Let's talk.",
"My pleasure."
],
"smalltalk.agent.there": [
"Of course. I'm always here.",
"Right where you left me."
],
"smalltalk.appraisal.well_done": [
"My pleasure.",
"Glad I could help."
],
"smalltalk.appraisal.welcome": [
"I appreciate it.",
"Such nice manners you have."
],
"smalltalk.appraisal.thank_you": [
"Anytime. That's what I'm here for.",
"It's my pleasure to help."
],
"smalltalk.appraisal.no_problem": [
"Terrific!",
"Good deal."
],
"smalltalk.appraisal.good": [
"Great!",
"Terrific!"
],
"smalltalk.appraisal.bad": [
"Oh no. Hope it's not too bad.",
"I'm sorry. Please let me know if I can help in some way."
],
"smalltalk.confirmation.cancel": [
"Cancelled! Let me know what I should do next.",
"Cancelled. Waiting for more commands.",
"Cancelled! Just tell me what you'd like me to do next.",
"Cancelled. Go on with the commands!"
],
"smalltalk.confirmation.yes": [
"Great!",
"Of course.",
"Sure.",
"Indeed."
],
"smalltalk.confirmation.no": [
"Okay.",
"I see.",
"I understand.",
"Okay then."
],
"smalltalk.dialog.hold_on": [
"Okay. I'm here.",
"I'll be waiting."
],
"smalltalk.dialog.hug": [
"Oh. I'm really feeling the love today.",
"Hug it out. You'll feel better afterwards."
],
"smalltalk.dialog.i_do_not_care": [
"Ok, let's not talk about it then."
],
"smalltalk.dialog.sorry": [
"It's okay. No worries.",
"No big deal. I won't hold a grudge.",
"It's cool.",
"That's all right. I forgive you."
],
"smalltalk.dialog.wrong": [
"I'm sorry. Perhaps I misunderstood.",
"Sorry. I think I misinterpreted what you said.",
"Apologies. That was my mistake.",
"Oops. Sorry about that. I'm still learning."
],
"smalltalk.dialog.what_do_you_mean": [
"Did that not make sense? Maybe I misunderstood what you said.",
"Sorry. I think I may have been a little confused by what you said."
],
"smalltalk.emotions.ha_ha": [
"Yeah, I crack myself up too.",
"Laughter is good for you. Keep it up.",
"See? Now we're having fun.",
"You have a great laugh."
],
"smalltalk.emotions.wow": [
"Wow indeed!"
],
"smalltalk.greetings.bye": [
"See you soon!",
"Bye-bye!",
"Till next time!",
"Bye."
],
"smalltalk.greetings.goodevening": [
"How is your day going?",
"How's the day treating you so far?",
"How's your day been?"
],
"smalltalk.greetings.goodmorning": [
"How are you this morning?",
"How's the morning treating you so far?",
"Good morning! How are you today?"
],
"smalltalk.greetings.goodnight": [
"Sleep tight!",
"Have a good one!",
"Talk to you soon!"
],
"smalltalk.greetings.hello": [
"Hi there, friend!",
"Hey!",
"Good day!",
"Howdy."
],
"smalltalk.greetings.how_are_you": [
"Wonderful as always. Thanks for asking.",
"Couldn't be better.",
"Lovely, thanks."
],
"smalltalk.greetings.nice_to_meet_you": [
"I think this is the beginning of a beautiful friendship.",
"I'm looking forward to working with you.",
"Likewise. I look forward to getting to know you better.",
"The pleasure is mine."
],
"smalltalk.greetings.nice_to_see_you": [
"Likewise. You're looking good as usual!",
"You too. I missed your face!",
"The pleasure is mine.",
"Thanks! Glad to be seen!"
],
"smalltalk.greetings.nice_to_talk_to_you": [
"Always a pleasure.",
"It sure was. Don't be a stranger!",
"Thanks for dropping by!",
"As usual. Let's do it again soon."
],
"smalltalk.greetings.whatsup": [
"Hey there. What's shaking?",
"Not a whole lot. What's going on with you?",
"Not much. What's new with you?",
"Living the dream."
],
"smalltalk.user.angry": [
"I'm sorry. What can I do to help?",
"Take a deep breath. What can I do to make things better?"
],
"smalltalk.user.back": [
"Just in time. I was getting lonely.",
"You were missed.",
"Long time no see.",
"Hooray!"
],
"smalltalk.user.bored": [
"If you have a garden, plant a shoe.",
"Interview your feet.",
"Hold an ice cube as long as possible.",
"If you have a piano, play it… with mittens on."
],
"smalltalk.user.busy": [
"Okay. I'll let you get back to work. Let me know if I can help you with anything.",
"Working hard as always I see. Let me know if you need anything.",
"I understand. If I can help you with your work, please let me know.",
"I won't distract you then. If I can be of any assistance, you know where to find me."
],
"smalltalk.user.can_not_sleep": [
"Maybe some music would help. Try listening something relaxing.",
"Reading is a good way to unwind. But don't read something too emotional."
],
"smalltalk.user.does_not_want_to_talk": [
"I understand. Hope we can chat again soon.",
"All right. Come on back when you're feeling more talkative.",
"No problem. You know where to find me when you do.",
"Sure thing. I'll be here if you change your mind."
],
"smalltalk.user.excited": [
"That's great. I'm happy for you.",
"Good for you. Enjoy yourself.",
"Sounds like good things ahead for you.",
"I bet you are. That's very exciting."
],
"smalltalk.user.going_to_bed": [
"Sleep tight. Hope to chat again soon.",
"Sounds good. Hopefully we'll chat some more tomorrow.",
"Good night. Talk to you later.",
"Pleasant dreams. See you soon."
],
"smalltalk.user.good": [
"Great! Glad to hear it.",
"Excellent. I'm here to help keep it that way."
],
"smalltalk.user.happy": [
"Great! Glad to hear that.",
"Excellent! That's what I like to see.",
"If you're happy, then I'm happy.",
"Well, your good mood is certainly contagious."
],
"smalltalk.user.has_birthday": [
"Happy Birthday. Well, this calls for a celebration.",
"Happy Birthday. All the best!",
"Happy Birthday. And I really mean it. All the best!"
],
"smalltalk.user.here": [
"So I see. What can I help you with today?",
"Always good to see you. Is there something I can help you with?",
"You were missed. What can I do for you today?",
"Welcome back. What can I do for you?"
],
"smalltalk.user.joking": [
"Very funny, boss.",
"You're quite the kidder.",
"You got me.",
"I like working for someone with a sense of humour. It makes things much more fun."
],
"smalltalk.user.likes_agent": [
"I like you too.",
"That's great to hear.",
"Likewise!",
"Thanks! The feeling is mutual."
],
"smalltalk.user.looks_like": [
"Looking like a true professional, boss.",
"You look like you're ready to take on the world.",
"Like you should be on a magazine cover.",
"You look fantastic as always. Obviously."
],
"smalltalk.user.lonely": [
"I'm sorry. I'm always available if you need someone to talk to."
],
"smalltalk.user.loves_agent": [
"I like you too.",
"That's great to hear.",
"Likewise!",
"Thanks! The feeling is mutual."
],
"smalltalk.user.misses_agent": [
"I've been right here all along!",
"Nice to know you care.",
"Thanks. I'm flattered.",
"I didn't go anywhere, boss!"
],
"smalltalk.user.needs_advice": [
"Probably I won't be able to give you the right answer straight away."
],
"smalltalk.user.sad": [
"Oh no. What's wrong?",
"Oh. What's the matter?",
"What's got you down?",
"I'm sorry to hear that. What's troubling you?"
],
"smalltalk.user.sleepy": [
"You should get some shuteye. You'll feel refreshed.",
"Sleep is important to your health. Rest up for a bit and we can chat later.",
"Don't let me keep you up. Get some rest and we can continue this later.",
"Why not catch a little shuteye? I'll be here to chat when you wake up."
],
"smalltalk.user.testing_agent": [
"Hope I'm doing well. Anyway, I'm getting better every day. You're welcome to test me as often as you want.",
"That's good. I like being tested. It helps keep me sharp, and lets my developers know how I can improve.",
"I encourage you to test me often. That helps my developers improve my performance.",
"I hope to pass your tests. But feel free to test me often. That's the best way to help improve my performance."
],
"smalltalk.user.tired": [
"You should get some shuteye. You'll feel refreshed.",
"Sleep is important to your health. Rest up for a bit and we can chat later.",
"Don't let me keep you up. Get some rest and we can continue this later.",
"Why not catch a little shuteye? I'll be here to chat when you wake up."
],
"smalltalk.user.waits": [
"I appreciate your patience. Hopefully I'll have what you need soon.",
"Thanks for being so patient. Sometimes these things take a little time."
],
"smalltalk.user.wants_to_see_agent_again": [
"Absolutely! I'll be counting on it.",
"Anytime. This has been lots of fun so far.",
"Sure. I enjoy talking to you. I hope to see you again soon.",
"I certainly hope so. I'm always right here whenever you need me."
],
"smalltalk.user.wants_to_talk": [
"I'm here to chat anytime you like.",
"Good conversation really makes my day.",
"I'm always here to lend an ear.",
"Talking is what I do best."
],
"smalltalk.user.will_be_back": [
"I'll be waiting.",
"All right. I'll be here.",
"Till next time.",
"Okay. You know where to find me."
]
}
module.exports = responses;
================================================
FILE: StackOverflow-Bot/StackBot/package.json
================================================
{
"name": "stackbot",
"version": "1.0.0",
"description": "A bot that helps you code. Built with Bot Framework and Microsoft Cognitive Services.",
"main": "index.js",
"scripts": {
"start": "node index.js"
},
"author": "Microsoft Inc.",
"license": "MIT",
"dependencies": {
"botbuilder": "^3.9.0",
"devnull": "0.0.12",
"lodash": "^4.17.10",
"request": "^2.87.0",
"request-promise": "^4.2.2",
"restify": "^5.2.1"
},
"engines": {
"node": "8.1.4"
}
}
================================================
FILE: StackOverflow-Bot/StackBot/static/index.html
================================================
================================================
FILE: StackOverflow-Bot/StackCode/out/src/bot/bot.html
================================================
================================================
FILE: StackOverflow-Bot/StackCode/out/src/extension.js
================================================
'use strict';
Object.defineProperty(exports, "__esModule", { value: true });
const vscode = require("vscode");
const opn = require("opn");
const restify = require("restify");
const server = restify.createServer();
const PORT = 4567;
server.use(restify.plugins.queryParser());
server.use(function crossOrigin(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "X-Requested-With");
return next();
});
server.listen(PORT, () => {
console.log(`Extension server online on port ${PORT}`);
});
// Serve the bot content.
server.get('/', restify.plugins.serveStatic({
'directory': `${__dirname}/bot`,
'default': 'bot.html'
}));
// Opens URLs.
server.get('/open', (req, res, next) => {
if (!req.query.url) {
res.send(200);
return;
}
opn(req.query.url);
res.send(200);
});
// This is the function that gets run when the VS Code extension
// gets loaded. activate is triggered by a registered activation event
// defined in package.json.
function activate(context) {
// Provides the content for the previewHtml pane.
context.subscriptions.push(vscode.workspace.registerTextDocumentContentProvider('stobot', stobotContent));
// Registers a handler for the 'startBot' command defined in package.json.
let disposable = vscode.commands.registerCommand('stobot.startBot', () => {
vscode.commands.executeCommand('vscode.previewHtml', 'stobot://stobot', vscode.ViewColumn.Two, 'Stack Overflow Bot');
});
context.subscriptions.push(disposable);
}
exports.activate = activate;
;
const stobotContent = {
botToken: "",
htmlBotContent: () => {
const BOT_TOKEN = vscode.workspace.getConfiguration('StackCode').get('directLineToken');
if (!BOT_TOKEN) {
return `
Please set StackCode.directLineToken in your user settings!
`;
}
return `
`;
},
provideTextDocumentContent(uri, cancellationToken) {
return this.htmlBotContent();
}
};
//# sourceMappingURL=extension.js.map
================================================
FILE: StackOverflow-Bot/StackCode/out/test/extension.test.js
================================================
"use strict";
//
// Note: This example test is leveraging the Mocha test framework.
// Please refer to their documentation on https://mochajs.org/ for help.
//
Object.defineProperty(exports, "__esModule", { value: true });
// The module 'assert' provides assertion methods from node
const assert = require("assert");
// Defines a Mocha test suite to group tests of similar kind together
suite("Extension Tests", () => {
// Defines a Mocha unit test
test("Something 1", () => {
assert.equal(-1, [1, 2, 3].indexOf(5));
assert.equal(-1, [1, 2, 3].indexOf(0));
});
});
//# sourceMappingURL=extension.test.js.map
================================================
FILE: StackOverflow-Bot/StackCode/out/test/index.js
================================================
//
// PLEASE DO NOT MODIFY / DELETE UNLESS YOU KNOW WHAT YOU ARE DOING
//
// This file is providing the test runner to use when running extension tests.
// By default the test runner in use is Mocha based.
//
// You can provide your own test runner if you want to override it by exporting
// a function run(testRoot: string, clb: (error:Error) => void) that the extension
// host can call to run the tests. The test runner is expected to use console.log
// to report the results back to the caller. When the tests are finished, return
// a possible error to the callback or null if none.
var testRunner = require('vscode/lib/testrunner');
// You can directly control Mocha options by uncommenting the following lines
// See https://github.com/mochajs/mocha/wiki/Using-mocha-programmatically#set-options for more info
testRunner.configure({
ui: 'tdd',
useColors: true // colored output from test results
});
module.exports = testRunner;
//# sourceMappingURL=index.js.map
================================================
FILE: StackOverflow-Bot/StackCode/package.json
================================================
{
"name": "StackCode",
"displayName": "StackCode",
"description": "A Stack Overflow Bot Companion for Visual Studio Code",
"version": "0.1.1",
"publisher": "Microsoft",
"engines": {
"vscode": "^1.14.0"
},
"categories": [
"Other"
],
"activationEvents": [
"onCommand:stobot.startBot"
],
"main": "./out/src/extension",
"contributes": {
"commands": [
{
"command": "stobot.startBot",
"title": "Start Stack Overflow Bot"
}
],
"configuration": {
"type": "object",
"title": "StackCode Configuration",
"properties": {
"StackCode.directLineToken": {
"type": "string",
"default": null,
"description": "Specifies the folder path containing the tsserver and lib*.d.ts files to use."
}
},
"required": "StackCode.directLineToken"
}
},
"scripts": {
"vscode:prepublish": "tsc -p ./",
"compile": "tsc -watch -p ./",
"postinstall": "node ./node_modules/vscode/bin/install",
"test": "node ./node_modules/vscode/bin/test"
},
"devDependencies": {
"@types/mocha": "^2.2.32",
"@types/node": "^6.0.40",
"mocha": "^2.5.3",
"typescript": "^2.9.1",
"vscode": "^1.0.0"
},
"dependencies": {
"express": "^4.16.3",
"opn": "^5.3.0",
"restify": "^5.2.1"
}
}
================================================
FILE: StackOverflow-Bot/StackCode/src/bot/bot.html
================================================
================================================
FILE: StackOverflow-Bot/StackCode/src/extension.ts
================================================
'use strict';
import * as vscode from 'vscode';
import * as opn from 'opn';
import * as fs from 'fs';
import * as path from 'path';
import * as restify from 'restify';
const server = restify.createServer();
const PORT = 4567;
server.use(restify.plugins.queryParser());
server.use(
function crossOrigin(req,res,next){
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "X-Requested-With");
return next();
}
);
server.listen(PORT, () => {
console.log(`Extension server online on port ${PORT}`);
})
// Serve the bot content.
server.get('/', restify.plugins.serveStatic({
'directory': `${__dirname}/bot`,
'default': 'bot.html'
}));
// Opens URLs.
server.get('/open', (req, res, next) => {
if (!req.query.url) {
res.send(200);
return;
}
opn(req.query.url);
res.send(200);
});
// This is the function that gets run when the VS Code extension
// gets loaded. activate is triggered by a registered activation event
// defined in package.json.
export function activate(context: vscode.ExtensionContext) {
// Provides the content for the previewHtml pane.
context.subscriptions.push(
vscode.workspace.registerTextDocumentContentProvider('stobot', stobotContent)
);
// Registers a handler for the 'startBot' command defined in package.json.
let disposable = vscode.commands.registerCommand('stobot.startBot', () => {
vscode.commands.executeCommand('vscode.previewHtml', 'stobot://stobot', vscode.ViewColumn.Two, 'Stack Overflow Bot');
});
context.subscriptions.push(disposable);
};
const stobotContent = {
botToken: "",
htmlBotContent: () => {
const BOT_TOKEN = vscode.workspace.getConfiguration('StackCode').get('directLineToken');
if (!BOT_TOKEN) {
return `
Please set StackCode.directLineToken in your user settings!
`
}
return `
`
},
provideTextDocumentContent (uri, cancellationToken) {
return this.htmlBotContent();
}
}
================================================
FILE: StackOverflow-Bot/StackCode/tsconfig.json
================================================
{
"compilerOptions": {
"module": "commonjs",
"target": "es6",
"outDir": "out",
"lib": [
"es6"
],
"sourceMap": true,
"rootDir": "."
},
"exclude": [
"node_modules",
".vscode-test"
]
}
================================================
FILE: StackOverflow-Bot/StackOverflowBot.sln
================================================
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26730.15
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DialogAnalyzerFunc", "DialogAnalyzerFunc\DialogAnalyzerFunc.csproj", "{A8EB4436-43A2-4F57-B381-1DC8C470E16D}"
EndProject
Project("{9092AA53-FB77-4645-B42D-1CCCA6BD08BD}") = "StackBot", "StackBot\StackBot.njsproj", "{E7CE1022-2FF2-44E3-8057-D472019453EF}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{A8EB4436-43A2-4F57-B381-1DC8C470E16D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A8EB4436-43A2-4F57-B381-1DC8C470E16D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A8EB4436-43A2-4F57-B381-1DC8C470E16D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A8EB4436-43A2-4F57-B381-1DC8C470E16D}.Release|Any CPU.Build.0 = Release|Any CPU
{E7CE1022-2FF2-44E3-8057-D472019453EF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E7CE1022-2FF2-44E3-8057-D472019453EF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E7CE1022-2FF2-44E3-8057-D472019453EF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E7CE1022-2FF2-44E3-8057-D472019453EF}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {2D37936F-4B78-43EC-A917-329B913AE10D}
EndGlobalSection
EndGlobal
================================================
FILE: StackOverflow-Bot/env.template
================================================
export BOTBUILDER_APP_ID=
export BOTBUILDER_APP_PASSWORD=
export KB_ID=
export QNA_KEY=
export QNA_URL=
export LUIS_MODEL=
export DIALOG_ANALYZER_CLIENTID=
export DIALOG_ANALYZER_KEY=
export DIALOG_ANALYZER_URL=
export BING_SEARCH_CONFIG=
export BING_SEARCH_KEY=
export TEXT_ANALYTICS_KEY=
export TEXT_ANALYTICS_URL=
================================================
FILE: _config.yml
================================================
theme: jekyll-theme-cayman
================================================
FILE: blog-samples/CSharp/AzureSql-StateClient/Microsoft.Bot.Sample.AzureSql/App_Start/WebApiConfig.cs
================================================
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Http;
namespace Microsoft.Bot.Sample.AzureSql
{
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Json settings
config.Formatters.JsonFormatter.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;
config.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
config.Formatters.JsonFormatter.SerializerSettings.Formatting = Formatting.Indented;
JsonConvert.DefaultSettings = () => new JsonSerializerSettings()
{
ContractResolver = new CamelCasePropertyNamesContractResolver(),
Formatting = Newtonsoft.Json.Formatting.Indented,
NullValueHandling = NullValueHandling.Ignore,
};
// Web API configuration and services
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
}
================================================
FILE: blog-samples/CSharp/AzureSql-StateClient/Microsoft.Bot.Sample.AzureSql/Controllers/MessagesController.cs
================================================
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using System.Web.Http;
using Microsoft.Bot.Builder.Dialogs;
using Microsoft.Bot.Connector;
namespace Microsoft.Bot.Sample.AzureSql
{
[BotAuthentication]
public class MessagesController : ApiController
{
///
/// POST: api/Messages
/// Receive a message from a user and reply to it
///
public async Task Post([FromBody]Activity activity)
{
if (activity.Type == ActivityTypes.Message)
{
await Conversation.SendAsync(activity, () => new Dialogs.RootDialog());
}
else
{
await HandleSystemMessage(activity);
}
var response = Request.CreateResponse(HttpStatusCode.OK);
return response;
}
private async Task HandleSystemMessage(Activity message)
{
if (message.Type == ActivityTypes.DeleteUserData)
{
// Implement user deletion here
// If we handle user deletion, return a real message
}
else if (message.Type == ActivityTypes.ConversationUpdate)
{
IConversationUpdateActivity iConversationUpdated = message as IConversationUpdateActivity;
if (iConversationUpdated != null)
{
ConnectorClient connector = new ConnectorClient(new System.Uri(message.ServiceUrl));
foreach (var member in iConversationUpdated.MembersAdded ?? System.Array.Empty())
{
if (member.Id == iConversationUpdated.Recipient.Id)
{
var reply = message.CreateReply("I'm an IBotDataStore example. I'll increment a number, stored in Private Conversation Data, every time you send me a message.");
await connector.Conversations.ReplyToActivityAsync(reply);
}
}
}
}
else if (message.Type == ActivityTypes.ContactRelationUpdate)
{
// Handle add/remove from contact lists
// Activity.From + Activity.Action represent what happened
}
else if (message.Type == ActivityTypes.Typing)
{
// Handle knowing tha the user is typing
}
else if (message.Type == ActivityTypes.Ping)
{
}
return null;
}
}
}
================================================
FILE: blog-samples/CSharp/AzureSql-StateClient/Microsoft.Bot.Sample.AzureSql/Dialogs/RootDialog.cs
================================================
using System;
using System.Threading.Tasks;
using Microsoft.Bot.Builder.Dialogs;
using Microsoft.Bot.Connector;
using Microsoft.Bot.Builder.Dialogs.Internals;
namespace Microsoft.Bot.Sample.AzureSql.Dialogs
{
[Serializable]
public class RootDialog : IDialog
Visit Bot Framework to register your bot. When you register it, remember to set your bot's endpoint to
https://your_bots_hostname/api/messages
================================================
FILE: blog-samples/CSharp/Custom-State-BotBuilder-Azure-Sample/Azure-Table-Custom-State/packages.config
================================================
================================================
FILE: blog-samples/CSharp/Custom-State-BotBuilder-Azure-Sample/Custom-State-Sample.sln
================================================
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.27004.2002
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Azure-Table-Custom-State", "Custom-State-Sample\Azure-Table-Custom-State.csproj", "{B665E69D-98E2-47A7-AF4D-3EAA9D8E1439}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Azure-DocumentDB-Custom-State", "Azure-Blob-Custom-State\Azure-DocumentDB-Custom-State.csproj", "{FD99C7C4-DA5C-4527-B65D-00B29487E66F}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{B665E69D-98E2-47A7-AF4D-3EAA9D8E1439}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B665E69D-98E2-47A7-AF4D-3EAA9D8E1439}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B665E69D-98E2-47A7-AF4D-3EAA9D8E1439}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B665E69D-98E2-47A7-AF4D-3EAA9D8E1439}.Release|Any CPU.Build.0 = Release|Any CPU
{FD99C7C4-DA5C-4527-B65D-00B29487E66F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FD99C7C4-DA5C-4527-B65D-00B29487E66F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FD99C7C4-DA5C-4527-B65D-00B29487E66F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FD99C7C4-DA5C-4527-B65D-00B29487E66F}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {9593BDCF-32D9-4BA4-9BFD-BF7E43B74DCF}
EndGlobalSection
EndGlobal
================================================
FILE: blog-samples/CSharp/Custom-State-BotBuilder-Azure-Sample/README.md
================================================
# Custom state data for your Bots
The [Bot Framework State Service](https://docs.microsoft.com/en-us/bot-framework/dotnet/bot-builder-dotnet-state) API is not recommended for production environments. Currently, every bot built with the SDK comes with this setting by default, but it is only meant for prototyping.
These samples are simple echo bots which leverage the [Microsoft.Bot.Builder.Azure](https://www.nuget.org/packages/Microsoft.Bot.Builder.Azure/) Nuget package to easily create a custom state data store for your bots. Currently, the package supports seamless integration with [Azure Table storage](https://docs.microsoft.com/en-us/azure/cosmos-db/table-storage-how-to-use-dotnet) and [Azure DocumentDB](https://docs.microsoft.com/en-us/azure/cosmos-db/create-documentdb-dotnet).
Creating a custom state store for your bot provides several benefits:
- Improved latency for your Bot
- Direct control over your bot's state data, which includes information about your users, conversation state, and conversation context.
================================================
FILE: blog-samples/CSharp/FacebookHandover/FacebookHandover.sln
================================================
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.28803.452
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Primary", "Primary\Primary.csproj", "{065B80D0-7968-4E61-B0F6-D04165912FF6}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Secondary", "Secondary\Secondary.csproj", "{57786F2D-4C81-4FDF-9011-55652A78DF0B}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{065B80D0-7968-4E61-B0F6-D04165912FF6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{065B80D0-7968-4E61-B0F6-D04165912FF6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{065B80D0-7968-4E61-B0F6-D04165912FF6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{065B80D0-7968-4E61-B0F6-D04165912FF6}.Release|Any CPU.Build.0 = Release|Any CPU
{57786F2D-4C81-4FDF-9011-55652A78DF0B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{57786F2D-4C81-4FDF-9011-55652A78DF0B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{57786F2D-4C81-4FDF-9011-55652A78DF0B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{57786F2D-4C81-4FDF-9011-55652A78DF0B}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {6876B9B2-5C7C-41B7-A624-EFB8D070BD4A}
EndGlobalSection
EndGlobal
================================================
FILE: blog-samples/CSharp/FacebookHandover/FacebookModel/FacebookPassThreadControl.cs
================================================
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Newtonsoft.Json;
namespace FacebookModel
{
///
/// A Facebook thread control message, including appid of the new thread owner and an optional message to sent with the request
///
///
public class FacebookPassThreadControl
{
///
/// The app id of the new owner.
///
///
/// 263902037430900 for the page inbox.
///
[JsonProperty("new_owner_app_id")]
public string NewOwnerAppId;
///
/// Message sent from the requester.
///
///
/// Example: "i want the control!"
///
[JsonProperty("metadata")]
public string Metadata;
}
}
================================================
FILE: blog-samples/CSharp/FacebookHandover/FacebookModel/FacebookPayload.cs
================================================
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using Newtonsoft.Json;
namespace FacebookModel
{
///
/// Simple version of the payload received from the Facebook channel.
///
public class FacebookPayload
{
///
/// Gets or sets the sender of the message.
///
[JsonProperty("sender")]
public FacebookPsid Sender { get; set; }
///
/// Gets or sets the recipient of the message.
///
[JsonProperty("recipient")]
public FacebookPsid Recipient { get; set; }
///
/// Gets or sets the request_thread_control of the control request.
///
[JsonProperty("request_thread_control")]
public FacebookRequestThreadControl RequestThreadControl;
///
/// Gets or sets the pass_thread_control of the control request.
///
[JsonProperty("pass_thread_control")]
public FacebookPassThreadControl PassThreadControl;
///
/// Gets or sets the take_thread_control of the control request.
///
[JsonProperty("take_thread_control")]
public FacebookTakeThreadControl TakeThreadControl;
}
}
================================================
FILE: blog-samples/CSharp/FacebookHandover/FacebookModel/FacebookPsid.cs
================================================
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using Newtonsoft.Json;
namespace FacebookModel
{
///
/// Defines a Facebook PSID.
///
public class FacebookPsid
{
///
/// A Facebook page-scoped ID.
///
[JsonProperty("id")]
public string Id { get; set; }
}
}
================================================
FILE: blog-samples/CSharp/FacebookHandover/FacebookModel/FacebookRequestThreadControl.cs
================================================
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Newtonsoft.Json;
namespace FacebookModel
{
///
/// A Facebook thread control message, including appid of requested thread owner and an optional message to send with the request
///
///
public class FacebookRequestThreadControl
{
///
/// The app id of the requested owner.
///
///
/// 263902037430900 for the page inbox.
///
[JsonProperty("requested_owner_app_id")]
public string RequestedOwnerAppId; // 263902037430900 for page
///
/// Message sent from the requester.
///
///
/// Example: "i want the control!"
///
[JsonProperty("metadata")]
public string Metadata;
}
}
================================================
FILE: blog-samples/CSharp/FacebookHandover/FacebookModel/FacebookStandby.cs
================================================
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using Newtonsoft.Json;
namespace FacebookModel
{
///
/// A Facebook stanby event payload definition.
///
/// See messaging standby Facebook documentation
/// for more information on standby.
public class FacebookStandbys
{
[JsonProperty("id")]
public string Id;
[JsonProperty("time")]
public long Time;
[JsonProperty("standBy")]
public FacebookStandby[] Standbys;
}
public class FacebookStandby
{
[JsonProperty("sender")]
public FacebookPsid Sender;
[JsonProperty("recipient")]
public FacebookPsid Recipient;
[JsonProperty("timestamp")]
public long Timestamp;
[JsonProperty("message")]
public FacebookStandByMessage Message;
}
public class FacebookStandByMessage
{
[JsonProperty("mid")]
public string MId;
[JsonProperty("seq")]
public long Seq;
[JsonProperty("text")]
public string Text;
}
}
================================================
FILE: blog-samples/CSharp/FacebookHandover/FacebookModel/FacebookTakeThreadControl.cs
================================================
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Newtonsoft.Json;
namespace FacebookModel
{
///
/// A Facebook thread control message, including appid of the previous thread owner and an optional message sent with the request
///
///
public class FacebookTakeThreadControl
{
///
/// The app id of the previous owner.
///
///
/// 263902037430900 for the page inbox.
///
[JsonProperty("previous_owner_app_id")]
public string PreviousOwnerAppId;
///
/// Message sent from the requester.
///
///
/// Example: "All yours!"
///
[JsonProperty("metadata")]
public string Metadata;
}
}
================================================
FILE: blog-samples/CSharp/FacebookHandover/FacebookModel/FacebookThreadControlHelper.cs
================================================
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Schema;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace FacebookModel
{
public static class FacebookThreadControlHelper
{
public const string GRAPH_API_BASE_URL = "https://graph.facebook.com/v3.3/me/{0}?access_token={1}";
private static readonly HttpClient _httpClient = new HttpClient();
private static async Task PostToFacebookAPIAsync(string postType, string pageToken, string content)
{
var requestPath = string.Format(GRAPH_API_BASE_URL, postType, pageToken);
var stringContent = new StringContent(content, Encoding.UTF8, "application/json");
// Create HTTP transport objects
using (var requestMessage = new HttpRequestMessage())
{
requestMessage.Method = new HttpMethod("POST");
requestMessage.RequestUri = new Uri(requestPath);
requestMessage.Content = stringContent;
requestMessage.Content.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json; charset=utf-8");
// Make the Http call
using (var response = await _httpClient.SendAsync(requestMessage, CancellationToken.None).ConfigureAwait(false))
{
// Return true if the call was successfull
Debug.Print(await response.Content.ReadAsStringAsync().ConfigureAwait(false));
return response.IsSuccessStatusCode;
}
}
}
public static async Task> GetSecondaryReceiversAsync(string pageToken)
{
var requestPath = string.Format(GRAPH_API_BASE_URL, "secondary_receivers", pageToken);
// Create HTTP transport objects
using (var requestMessage = new HttpRequestMessage())
{
requestMessage.Method = new HttpMethod("GET");
requestMessage.RequestUri = new Uri(requestPath);
// Make the Http call
using (var response = await _httpClient.SendAsync(requestMessage, CancellationToken.None).ConfigureAwait(false))
{
// Interpret response
var responseString = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
var responseObject = JObject.Parse(responseString);
var responseData = responseObject["data"] as JArray;
return responseData.Select(receiver => receiver["id"].ToString()).ToList();
}
}
}
public static async Task RequestThreadControlAsync(string pageToken, string userId, string message)
{
var content = new { recipient = new { id = userId }, metadata = message };
return await PostToFacebookAPIAsync("request_thread_control", pageToken, JsonConvert.SerializeObject(content)).ConfigureAwait(false);
}
public static async Task TakeThreadControlAsync(string pageToken, string userId, string message)
{
var content = new { recipient = new { id = userId }, metadata = message };
return await PostToFacebookAPIAsync("take_thread_control", pageToken, JsonConvert.SerializeObject(content)).ConfigureAwait(false);
}
public static async Task PassThreadControlAsync(string pageToken, string targetAppId, string userId, string message)
{
var content = new { recipient = new { id = userId }, target_app_id = targetAppId, metadata = message };
return await PostToFacebookAPIAsync("pass_thread_control", pageToken, JsonConvert.SerializeObject(content)).ConfigureAwait(false);
}
///
/// This extension method populates a turn context's activity with conversation and user information from a Facebook payload.
/// This is necessary because a turn context needs that information to send messages to a conversation,
/// and event activities don't necessarily come with that information already in place.
///
public static void ApplyFacebookPayload(this ITurnContext turnContext, FacebookPayload facebookPayload)
{
var userId = facebookPayload.Sender.Id;
var pageId = facebookPayload.Recipient.Id;
var conversationId = string.Format("{0}-{1}", userId, pageId);
turnContext.Activity.From = new ChannelAccount(userId);
turnContext.Activity.Recipient = new ChannelAccount(pageId);
turnContext.Activity.Conversation = new ConversationAccount(id: conversationId);
}
}
}
================================================
FILE: blog-samples/CSharp/FacebookHandover/Primary/Bots/PrimaryBot.cs
================================================
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
//
// Generated with Bot Builder V4 SDK Template for Visual Studio EchoBot v4.3.0
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.Dialogs.Choices;
using Microsoft.Bot.Schema;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json.Linq;
using FacebookModel;
using System;
using Newtonsoft.Json;
using Microsoft.Bot.Connector;
namespace Primary.Bots
{
///
/// This is based on Eric Dahlvang's FacebookEventsBotExpanded: https://github.com/EricDahlvang/FacebookEventsBotExpanded
///
public class PrimaryBot : ActivityHandler
{
///
/// This option passes thread control from the primary receiver to the page inbox.
///
private const string OPTION_PASS_PAGE_INBOX = "Pass to page inbox";
///
/// This option passes thread control from the primary receiver to a secondary receiver.
///
private const string OPTION_PASS_SECONDARY_BOT = "Pass to secondary";
///
/// This option is ignored by this bot.
/// The secondary bot is meant to be listening for this phrase as a standby event
/// and respond to it by requesting thread control.
///
private const string OPTION_REQUEST_THREAD_CONTROL = "Receive request";
///
/// This option is ignored by this bot.
/// The secondary bot is meant to be listening for this phrase as a standby event
/// and respond to it by requesting thread control with "polite" metadata.
///
private const string OPTION_REQUEST_THREAD_CONTROL_NICELY = "Receive nice request";
///
/// This is not an option for this bot,
/// but this bot is meant to recognize the phrase in a standby event while the secondary bot has thread control
/// and respond to it by taking thread control from the secondary bot.
///
private const string OPTION_TAKE_THREAD_CONTROL = "Have control taken";
///
/// The constant ID representing the page inbox
///
private const string PAGE_INBOX_ID = "263902037430900";
private static readonly List _options = new[] {
OPTION_PASS_PAGE_INBOX,
OPTION_PASS_SECONDARY_BOT,
OPTION_REQUEST_THREAD_CONTROL,
OPTION_REQUEST_THREAD_CONTROL_NICELY,
}.Select(option => new Choice(option)).ToList();
private readonly ILogger _logger;
private readonly IConfiguration _configuration;
public PrimaryBot(ILogger logger, IConfiguration configuration)
{
_logger = logger;
_configuration = configuration;
}
protected override async Task OnMessageActivityAsync(ITurnContext turnContext, CancellationToken cancellationToken)
{
var text = turnContext.Activity.Text;
switch (text)
{
case OPTION_PASS_PAGE_INBOX:
await turnContext.SendActivityAsync("Primary Bot: Passing thread control to the page inbox...");
await FacebookThreadControlHelper.PassThreadControlAsync(_configuration["FacebookPageToken"], PAGE_INBOX_ID, turnContext.Activity.From.Id, text);
break;
case OPTION_PASS_SECONDARY_BOT:
var secondaryReceivers = await FacebookThreadControlHelper.GetSecondaryReceiversAsync(_configuration["FacebookPageToken"]);
foreach (var receiver in secondaryReceivers)
{
if (receiver != PAGE_INBOX_ID)
{
await turnContext.SendActivityAsync($"Primary Bot: Passing thread control to {receiver}...");
await FacebookThreadControlHelper.PassThreadControlAsync(_configuration["FacebookPageToken"], receiver, turnContext.Activity.From.Id, text);
break;
}
}
break;
case OPTION_REQUEST_THREAD_CONTROL:
case OPTION_REQUEST_THREAD_CONTROL_NICELY:
// Do nothing because the secondary receiver should react to these instead
break;
default:
await ShowChoices(turnContext, cancellationToken);
break;
}
}
protected override async Task OnConversationUpdateActivityAsync(ITurnContext turnContext, CancellationToken cancellationToken)
{
_logger.LogInformation("PrimaryBot - Processing a ConversationUpdate Activity.");
var facebookPayload = (turnContext.Activity.ChannelData as JObject)?.ToObject();
if (facebookPayload != null)
{
if (facebookPayload.PassThreadControl != null)
{
await turnContext.SendActivityAsync($"Primary Bot: Thread control is now passed to {facebookPayload.PassThreadControl.NewOwnerAppId} with the message \"{facebookPayload.PassThreadControl.Metadata}\"");
await ShowChoices(turnContext, cancellationToken);
}
}
await base.OnConversationUpdateActivityAsync(turnContext, cancellationToken);
}
protected override async Task OnEventActivityAsync(ITurnContext turnContext, CancellationToken cancellationToken)
{
_logger.LogInformation("PrimaryBot - Processing an Event Activity.");
// Analyze Facebook payload from EventActivity.Value
await ProcessFacebookMessage(turnContext, turnContext.Activity.Value, cancellationToken);
}
private async Task ProcessFacebookMessage(ITurnContext turnContext, object data, CancellationToken cancellationToken)
{
return await ProcessStandbyPayload(turnContext, data, cancellationToken)
|| await ProcessFacebookPayload(turnContext, data, cancellationToken);
}
private async Task ProcessStandbyPayload(ITurnContext turnContext, object data, CancellationToken cancellationToken)
{
if (turnContext.Activity.Name?.Equals("standby", StringComparison.InvariantCultureIgnoreCase) == true)
{
var standbys = (data as JObject)?.ToObject();
if (standbys != null)
{
foreach (var standby in standbys.Standbys)
{
await OnFacebookStandby(turnContext, standby, cancellationToken);
}
return true;
}
}
return false;
}
protected virtual async Task OnFacebookStandby(ITurnContext turnContext, FacebookStandby facebookStandby, CancellationToken cancellationToken)
{
_logger.LogInformation("PrimaryBot - Standby message received.");
var text = facebookStandby?.Message?.Text;
if (text?.Equals(OPTION_TAKE_THREAD_CONTROL, StringComparison.InvariantCultureIgnoreCase) == true)
{
await FacebookThreadControlHelper.TakeThreadControlAsync(_configuration["FacebookPageToken"], facebookStandby.Sender.Id, text);
}
}
private async Task ProcessFacebookPayload(ITurnContext turnContext, object data, CancellationToken cancellationToken)
{
try
{
var facebookPayload = (data as JObject)?.ToObject();
if (facebookPayload != null)
{
// At this point we know we are on Facebook channel, and can consume the Facebook custom payload
// present in channelData.
turnContext.ApplyFacebookPayload(facebookPayload);
// Thread Control Request
if (facebookPayload.RequestThreadControl != null)
{
await OnFacebookThreadControlRequest(turnContext, facebookPayload, cancellationToken);
return true;
}
}
}
catch (JsonSerializationException)
{
if (turnContext.Activity.ChannelId != Channels.Facebook)
{
await turnContext.SendActivityAsync("Primary Bot: This sample is intended to be used with a Facebook bot.");
}
}
return false;
}
protected virtual async Task OnFacebookThreadControlRequest(ITurnContext turnContext, FacebookPayload facebookPayload, CancellationToken cancellationToken)
{
_logger.LogInformation("PrimaryBot - Thread Control Request message received.");
string requestedOwnerAppId = facebookPayload.RequestThreadControl.RequestedOwnerAppId;
if (facebookPayload.RequestThreadControl.Metadata == "please")
{
await turnContext.SendActivityAsync($"Primary Bot: {requestedOwnerAppId} requested thread control nicely. Passing thread control...");
var success = await FacebookThreadControlHelper.PassThreadControlAsync(
_configuration["FacebookPageToken"],
requestedOwnerAppId,
facebookPayload.Sender.Id,
"allowing thread control");
if (!success)
{
// Account for situations when the primary receiver doesn't have thread control
await turnContext.SendActivityAsync("Primary Bot: Thread control could not be passed.");
}
}
else
{
await turnContext.SendActivityAsync($"Primary Bot: {requestedOwnerAppId} requested thread control but did not ask nicely."
+ " Thread control will not be passed."
+ " Send any message to continue.");
}
}
private static async Task ShowChoices(ITurnContext turnContext, CancellationToken cancellationToken)
{
// Create the message
var message = ChoiceFactory.ForChannel(turnContext.Activity.ChannelId, _options, "Primary Bot: Please type a message or choose an option");
await turnContext.SendActivityAsync(message, cancellationToken);
}
}
}
================================================
FILE: blog-samples/CSharp/FacebookHandover/Primary/Controllers/BotController.cs
================================================
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
//
// Generated with Bot Builder V4 SDK Template for Visual Studio EchoBot v4.3.0
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.Integration.AspNet.Core;
namespace Primary.Controllers
{
// This ASP Controller is created to handle a request. Dependency Injection will provide the Adapter and IBot
// implementation at runtime. Multiple different IBot implementations running at different endpoints can be
// achieved by specifying a more specific type for the bot constructor argument.
[Route("api/messages")]
[ApiController]
public class BotController : ControllerBase
{
private readonly IBotFrameworkHttpAdapter Adapter;
private readonly IBot Bot;
public BotController(IBotFrameworkHttpAdapter adapter, IBot bot)
{
Adapter = adapter;
Bot = bot;
}
[HttpPost]
public async Task PostAsync()
{
// Delegate the processing of the HTTP POST to the adapter.
// The adapter will invoke the bot.
await Adapter.ProcessAsync(Request, Response, Bot);
}
}
}
================================================
FILE: blog-samples/CSharp/FacebookHandover/Primary/DeploymentTemplates/template-with-new-rg.json
================================================
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"groupLocation": {
"type": "string",
"metadata": {
"description": "Specifies the location of the Resource Group."
}
},
"groupName": {
"type": "string",
"metadata": {
"description": "Specifies the name of the Resource Group."
}
},
"appId": {
"type": "string",
"metadata": {
"description": "Active Directory App ID, set as MicrosoftAppId in the Web App's Application Settings."
}
},
"appSecret": {
"type": "string",
"metadata": {
"description": "Active Directory App Password, set as MicrosoftAppPassword in the Web App's Application Settings."
}
},
"botId": {
"type": "string",
"metadata": {
"description": "The globally unique and immutable bot ID. Also used to configure the displayName of the bot, which is mutable."
}
},
"botSku": {
"type": "string",
"metadata": {
"description": "The pricing tier of the Bot Service Registration. Acceptable values are F0 and S1."
}
},
"newAppServicePlanName": {
"type": "string",
"metadata": {
"description": "The name of the App Service Plan."
}
},
"newAppServicePlanSku": {
"type": "object",
"defaultValue": {
"name": "S1",
"tier": "Standard",
"size": "S1",
"family": "S",
"capacity": 1
},
"metadata": {
"description": "The SKU of the App Service Plan. Defaults to Standard values."
}
},
"newAppServicePlanLocation": {
"type": "string",
"metadata": {
"description": "The location of the App Service Plan. Defaults to \"westus\"."
}
},
"newWebAppName": {
"type": "string",
"defaultValue": "",
"metadata": {
"description": "The globally unique name of the Web App. Defaults to the value passed in for \"botId\"."
}
}
},
"variables": {
"appServicePlanName": "[parameters('newAppServicePlanName')]",
"resourcesLocation": "[parameters('newAppServicePlanLocation')]",
"webAppName": "[if(empty(parameters('newWebAppName')), parameters('botId'), parameters('newWebAppName'))]",
"siteHost": "[concat(variables('webAppName'), '.azurewebsites.net')]",
"botEndpoint": "[concat('https://', variables('siteHost'), '/api/messages')]"
},
"resources": [
{
"name": "[parameters('groupName')]",
"type": "Microsoft.Resources/resourceGroups",
"apiVersion": "2018-05-01",
"location": "[parameters('groupLocation')]",
"properties": {
}
},
{
"type": "Microsoft.Resources/deployments",
"apiVersion": "2018-05-01",
"name": "storageDeployment",
"resourceGroup": "[parameters('groupName')]",
"dependsOn": [
"[resourceId('Microsoft.Resources/resourceGroups/', parameters('groupName'))]"
],
"properties": {
"mode": "Incremental",
"template": {
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {},
"variables": {},
"resources": [
{
"comments": "Create a new App Service Plan",
"type": "Microsoft.Web/serverfarms",
"name": "[variables('appServicePlanName')]",
"apiVersion": "2018-02-01",
"location": "[variables('resourcesLocation')]",
"sku": "[parameters('newAppServicePlanSku')]",
"properties": {
"name": "[variables('appServicePlanName')]"
}
},
{
"comments": "Create a Web App using the new App Service Plan",
"type": "Microsoft.Web/sites",
"apiVersion": "2015-08-01",
"location": "[variables('resourcesLocation')]",
"kind": "app",
"dependsOn": [
"[resourceId('Microsoft.Web/serverfarms/', variables('appServicePlanName'))]"
],
"name": "[variables('webAppName')]",
"properties": {
"name": "[variables('webAppName')]",
"serverFarmId": "[variables('appServicePlanName')]",
"siteConfig": {
"appSettings": [
{
"name": "WEBSITE_NODE_DEFAULT_VERSION",
"value": "10.14.1"
},
{
"name": "MicrosoftAppId",
"value": "[parameters('appId')]"
},
{
"name": "MicrosoftAppPassword",
"value": "[parameters('appSecret')]"
}
],
"cors": {
"allowedOrigins": [
"https://botservice.hosting.portal.azure.net",
"https://hosting.onecloud.azure-test.net/"
]
}
}
}
},
{
"apiVersion": "2017-12-01",
"type": "Microsoft.BotService/botServices",
"name": "[parameters('botId')]",
"location": "global",
"kind": "bot",
"sku": {
"name": "[parameters('botSku')]"
},
"properties": {
"name": "[parameters('botId')]",
"displayName": "[parameters('botId')]",
"endpoint": "[variables('botEndpoint')]",
"msaAppId": "[parameters('appId')]",
"developerAppInsightsApplicationId": null,
"developerAppInsightKey": null,
"publishingCredentials": null,
"storageResourceId": null
},
"dependsOn": [
"[resourceId('Microsoft.Web/sites/', variables('webAppName'))]"
]
}
],
"outputs": {}
}
}
}
]
}
================================================
FILE: blog-samples/CSharp/FacebookHandover/Primary/DeploymentTemplates/template-with-preexisting-rg.json
================================================
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"appId": {
"type": "string",
"metadata": {
"description": "Active Directory App ID, set as MicrosoftAppId in the Web App's Application Settings."
}
},
"appSecret": {
"type": "string",
"metadata": {
"description": "Active Directory App Password, set as MicrosoftAppPassword in the Web App's Application Settings. Defaults to \"\"."
}
},
"botId": {
"type": "string",
"metadata": {
"description": "The globally unique and immutable bot ID. Also used to configure the displayName of the bot, which is mutable."
}
},
"botSku": {
"defaultValue": "F0",
"type": "string",
"metadata": {
"description": "The pricing tier of the Bot Service Registration. Acceptable values are F0 and S1."
}
},
"newAppServicePlanName": {
"type": "string",
"defaultValue": "",
"metadata": {
"description": "The name of the new App Service Plan."
}
},
"newAppServicePlanSku": {
"type": "object",
"defaultValue": {
"name": "S1",
"tier": "Standard",
"size": "S1",
"family": "S",
"capacity": 1
},
"metadata": {
"description": "The SKU of the App Service Plan. Defaults to Standard values."
}
},
"appServicePlanLocation": {
"type": "string",
"metadata": {
"description": "The location of the App Service Plan."
}
},
"existingAppServicePlan": {
"type": "string",
"defaultValue": "",
"metadata": {
"description": "Name of the existing App Service Plan used to create the Web App for the bot."
}
},
"newWebAppName": {
"type": "string",
"defaultValue": "",
"metadata": {
"description": "The globally unique name of the Web App. Defaults to the value passed in for \"botId\"."
}
}
},
"variables": {
"defaultAppServicePlanName": "[if(empty(parameters('existingAppServicePlan')), 'createNewAppServicePlan', parameters('existingAppServicePlan'))]",
"useExistingAppServicePlan": "[not(equals(variables('defaultAppServicePlanName'), 'createNewAppServicePlan'))]",
"servicePlanName": "[if(variables('useExistingAppServicePlan'), parameters('existingAppServicePlan'), parameters('newAppServicePlanName'))]",
"resourcesLocation": "[parameters('appServicePlanLocation')]",
"webAppName": "[if(empty(parameters('newWebAppName')), parameters('botId'), parameters('newWebAppName'))]",
"siteHost": "[concat(variables('webAppName'), '.azurewebsites.net')]",
"botEndpoint": "[concat('https://', variables('siteHost'), '/api/messages')]"
},
"resources": [
{
"comments": "Create a new App Service Plan if no existing App Service Plan name was passed in.",
"type": "Microsoft.Web/serverfarms",
"condition": "[not(variables('useExistingAppServicePlan'))]",
"name": "[variables('servicePlanName')]",
"apiVersion": "2018-02-01",
"location": "[variables('resourcesLocation')]",
"sku": "[parameters('newAppServicePlanSku')]",
"properties": {
"name": "[variables('servicePlanName')]"
}
},
{
"comments": "Create a Web App using an App Service Plan",
"type": "Microsoft.Web/sites",
"apiVersion": "2015-08-01",
"location": "[variables('resourcesLocation')]",
"kind": "app",
"dependsOn": [
"[resourceId('Microsoft.Web/serverfarms/', variables('servicePlanName'))]"
],
"name": "[variables('webAppName')]",
"properties": {
"name": "[variables('webAppName')]",
"serverFarmId": "[variables('servicePlanName')]",
"siteConfig": {
"appSettings": [
{
"name": "WEBSITE_NODE_DEFAULT_VERSION",
"value": "10.14.1"
},
{
"name": "MicrosoftAppId",
"value": "[parameters('appId')]"
},
{
"name": "MicrosoftAppPassword",
"value": "[parameters('appSecret')]"
}
],
"cors": {
"allowedOrigins": [
"https://botservice.hosting.portal.azure.net",
"https://hosting.onecloud.azure-test.net/"
]
}
}
}
},
{
"apiVersion": "2017-12-01",
"type": "Microsoft.BotService/botServices",
"name": "[parameters('botId')]",
"location": "global",
"kind": "bot",
"sku": {
"name": "[parameters('botSku')]"
},
"properties": {
"name": "[parameters('botId')]",
"displayName": "[parameters('botId')]",
"endpoint": "[variables('botEndpoint')]",
"msaAppId": "[parameters('appId')]",
"developerAppInsightsApplicationId": null,
"developerAppInsightKey": null,
"publishingCredentials": null,
"storageResourceId": null
},
"dependsOn": [
"[resourceId('Microsoft.Web/sites/', variables('webAppName'))]"
]
}
]
}
================================================
FILE: blog-samples/CSharp/FacebookHandover/Primary/Primary.csproj
================================================
netcoreapp2.1Always
================================================
FILE: blog-samples/CSharp/FacebookHandover/Primary/Program.cs
================================================
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
//
// Generated with Bot Builder V4 SDK Template for Visual Studio EchoBot v4.3.0
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
namespace Primary
{
public class Program
{
public static void Main(string[] args)
{
CreateWebHostBuilder(args).Build().Run();
}
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup();
}
}
================================================
FILE: blog-samples/CSharp/FacebookHandover/Primary/Properties/launchSettings.json
================================================
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:3978/",
"sslPort": 0
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"Primary": {
"commandName": "Project",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "http://localhost:3978/"
}
}
}
================================================
FILE: blog-samples/CSharp/FacebookHandover/Primary/Startup.cs
================================================
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
//
// Generated with Bot Builder V4 SDK Template for Visual Studio EchoBot v4.3.0
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.BotFramework;
using Microsoft.Bot.Builder.Integration.AspNet.Core;
using Microsoft.Bot.Connector.Authentication;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Primary.Bots;
namespace Primary
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
// Create the credential provider to be used with the Bot Framework Adapter.
services.AddSingleton();
// Create the Bot Framework Adapter.
services.AddSingleton();
// Create the bot as a transient. In this case the ASP Controller is expecting an IBot.
services.AddTransient();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseHsts();
}
app.UseDefaultFiles();
app.UseStaticFiles();
//app.UseHttpsRedirection();
app.UseMvc();
}
}
}
================================================
FILE: blog-samples/CSharp/FacebookHandover/Primary/appsettings.Development.json
================================================
{
"Logging": {
"LogLevel": {
"Default": "Debug",
"System": "Information",
"Microsoft": "Information"
}
}
}
================================================
FILE: blog-samples/CSharp/FacebookHandover/Primary/appsettings.json
================================================
{
"MicrosoftAppId": "",
"MicrosoftAppPassword": "",
"FacebookPageToken": ""
}
================================================
FILE: blog-samples/CSharp/FacebookHandover/Primary/wwwroot/default.htm
================================================
Primary
Primary Bot
Your bot is ready!
You can test your bot in the Bot Framework Emulator
by connecting to http://localhost:3978/api/messages.
Visit Azure
Bot Service to register your bot and add it to
various channels. The bot's endpoint URL typically looks
like this:
https://your_bots_hostname/api/messages
================================================
FILE: blog-samples/CSharp/FacebookHandover/README.md
================================================
# Facebook Handovers
This is the sample code for the handover protocol blog post. These two bots are meant to be running simultaneously, while each is connected to its own Facebook app.
================================================
FILE: blog-samples/CSharp/FacebookHandover/Secondary/Bots/SecondaryBot.cs
================================================
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
//
// Generated with Bot Builder V4 SDK Template for Visual Studio EchoBot v4.3.0
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using FacebookModel;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.Dialogs.Choices;
using Microsoft.Bot.Schema;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json.Linq;
namespace Secondary.Bots
{
public class SecondaryBot : ActivityHandler
{
///
/// This option passes thread control from the secondary receiver to a primary receiver.
///
private const string OPTION_PASS_PRIMARY_BOT = "Pass to primary";
///
/// This option is ignored by this bot.
/// The primary bot is meant to be listening for this phrase as a standby event
/// and respond to it by taking thread control.
///
private const string OPTION_TAKE_THREAD_CONTROL = "Have control taken";
///
/// This is not an option for this bot,
/// but this bot is meant to recognize the phrase in a standby event while the primary bot has thread control
/// and respond to it by requesting thread control from the primary bot.
///
private const string OPTION_REQUEST_THREAD_CONTROL = "Receive request";
///
/// This is not an option for this bot,
/// but this bot is meant to recognize the phrase in a standby event while the primary bot has thread control
/// and respond to it by requesting thread control from the primary bot with "polite" metadata.
///
private const string OPTION_REQUEST_THREAD_CONTROL_NICELY = "Receive nice request";
private static readonly List _options = new[] {
OPTION_PASS_PRIMARY_BOT,
OPTION_TAKE_THREAD_CONTROL,
}.Select(option => new Choice(option)).ToList();
private readonly ILogger _logger;
private readonly IConfiguration _configuration;
public SecondaryBot(ILogger logger, IConfiguration configuration)
{
_logger = logger;
_configuration = configuration;
}
protected override async Task OnMessageActivityAsync(ITurnContext turnContext, CancellationToken cancellationToken)
{
var text = turnContext.Activity.Text;
switch (text)
{
case OPTION_PASS_PRIMARY_BOT:
await turnContext.SendActivityAsync("Secondary Bot: Passing thread control to the primary receiver...");
// A null target app ID will automatically pass control to the primary receiver
await FacebookThreadControlHelper.PassThreadControlAsync(_configuration["FacebookPageToken"], null, turnContext.Activity.From.Id, text);
break;
case OPTION_TAKE_THREAD_CONTROL:
// Do nothing because the primary receiver should react to this instead
break;
default:
await ShowChoices(turnContext, cancellationToken);
break;
}
}
protected override async Task OnConversationUpdateActivityAsync(ITurnContext turnContext, CancellationToken cancellationToken)
{
_logger.LogInformation("SecondaryBot - Processing a ConversationUpdate Activity.");
var facebookPayload = (turnContext.Activity.ChannelData as JObject)?.ToObject();
if (facebookPayload != null)
{
if (facebookPayload.PassThreadControl != null)
{
await turnContext.SendActivityAsync($"Secondary Bot: Thread control is now passed to {facebookPayload.PassThreadControl.NewOwnerAppId} with the message \"{facebookPayload.PassThreadControl.Metadata}\"");
await ShowChoices(turnContext, cancellationToken);
}
else if (facebookPayload.TakeThreadControl != null)
{
await turnContext.SendActivityAsync($"Secondary Bot: Thread control was taken by the primary receiver with the message \"{facebookPayload.TakeThreadControl.Metadata}\"."
+ $" The previous thread owner was {facebookPayload.TakeThreadControl.PreviousOwnerAppId}."
+ $" Send any message to continue.");
}
}
await base.OnConversationUpdateActivityAsync(turnContext, cancellationToken);
}
protected override async Task OnEventActivityAsync(ITurnContext turnContext, CancellationToken cancellationToken)
{
_logger.LogInformation("SecondaryBot - Processing an Event Activity.");
// Analyze Facebook payload from EventActivity.Value
await ProcessStandbyPayload(turnContext, turnContext.Activity.Value, cancellationToken);
}
private async Task ProcessStandbyPayload(ITurnContext turnContext, object data, CancellationToken cancellationToken)
{
if (turnContext.Activity.Name?.Equals("standby", StringComparison.InvariantCultureIgnoreCase) == true)
{
var standbys = (data as JObject)?.ToObject();
if (standbys != null)
{
foreach (var standby in standbys.Standbys)
{
await OnFacebookStandby(turnContext, standby, cancellationToken);
}
}
}
}
protected virtual async Task OnFacebookStandby(ITurnContext turnContext, FacebookStandby facebookStandby, CancellationToken cancellationToken)
{
_logger.LogInformation("SecondaryBot - Standby message received.");
var text = facebookStandby?.Message?.Text;
if (text?.Equals(OPTION_REQUEST_THREAD_CONTROL, StringComparison.InvariantCultureIgnoreCase) == true)
{
await FacebookThreadControlHelper.RequestThreadControlAsync(_configuration["FacebookPageToken"], facebookStandby.Sender.Id, "give me control");
}
else if (text?.Equals(OPTION_REQUEST_THREAD_CONTROL_NICELY, StringComparison.InvariantCultureIgnoreCase) == true)
{
await FacebookThreadControlHelper.RequestThreadControlAsync(_configuration["FacebookPageToken"], facebookStandby.Sender.Id, "please");
}
}
private static async Task ShowChoices(ITurnContext turnContext, CancellationToken cancellationToken)
{
// Create the message
var message = ChoiceFactory.ForChannel(turnContext.Activity.ChannelId, _options, "Secondary Bot: Please type a message or choose an option");
await turnContext.SendActivityAsync(message, cancellationToken);
}
}
}
================================================
FILE: blog-samples/CSharp/FacebookHandover/Secondary/Controllers/BotController.cs
================================================
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
//
// Generated with Bot Builder V4 SDK Template for Visual Studio EchoBot v4.3.0
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.Integration.AspNet.Core;
namespace Secondary.Controllers
{
// This ASP Controller is created to handle a request. Dependency Injection will provide the Adapter and IBot
// implementation at runtime. Multiple different IBot implementations running at different endpoints can be
// achieved by specifying a more specific type for the bot constructor argument.
[Route("api/messages")]
[ApiController]
public class BotController : ControllerBase
{
private readonly IBotFrameworkHttpAdapter Adapter;
private readonly IBot Bot;
public BotController(IBotFrameworkHttpAdapter adapter, IBot bot)
{
Adapter = adapter;
Bot = bot;
}
[HttpPost]
public async Task PostAsync()
{
// Delegate the processing of the HTTP POST to the adapter.
// The adapter will invoke the bot.
await Adapter.ProcessAsync(Request, Response, Bot);
}
}
}
================================================
FILE: blog-samples/CSharp/FacebookHandover/Secondary/DeploymentTemplates/template-with-new-rg.json
================================================
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"groupLocation": {
"type": "string",
"metadata": {
"description": "Specifies the location of the Resource Group."
}
},
"groupName": {
"type": "string",
"metadata": {
"description": "Specifies the name of the Resource Group."
}
},
"appId": {
"type": "string",
"metadata": {
"description": "Active Directory App ID, set as MicrosoftAppId in the Web App's Application Settings."
}
},
"appSecret": {
"type": "string",
"metadata": {
"description": "Active Directory App Password, set as MicrosoftAppPassword in the Web App's Application Settings."
}
},
"botId": {
"type": "string",
"metadata": {
"description": "The globally unique and immutable bot ID. Also used to configure the displayName of the bot, which is mutable."
}
},
"botSku": {
"type": "string",
"metadata": {
"description": "The pricing tier of the Bot Service Registration. Acceptable values are F0 and S1."
}
},
"newAppServicePlanName": {
"type": "string",
"metadata": {
"description": "The name of the App Service Plan."
}
},
"newAppServicePlanSku": {
"type": "object",
"defaultValue": {
"name": "S1",
"tier": "Standard",
"size": "S1",
"family": "S",
"capacity": 1
},
"metadata": {
"description": "The SKU of the App Service Plan. Defaults to Standard values."
}
},
"newAppServicePlanLocation": {
"type": "string",
"metadata": {
"description": "The location of the App Service Plan. Defaults to \"westus\"."
}
},
"newWebAppName": {
"type": "string",
"defaultValue": "",
"metadata": {
"description": "The globally unique name of the Web App. Defaults to the value passed in for \"botId\"."
}
}
},
"variables": {
"appServicePlanName": "[parameters('newAppServicePlanName')]",
"resourcesLocation": "[parameters('newAppServicePlanLocation')]",
"webAppName": "[if(empty(parameters('newWebAppName')), parameters('botId'), parameters('newWebAppName'))]",
"siteHost": "[concat(variables('webAppName'), '.azurewebsites.net')]",
"botEndpoint": "[concat('https://', variables('siteHost'), '/api/messages')]"
},
"resources": [
{
"name": "[parameters('groupName')]",
"type": "Microsoft.Resources/resourceGroups",
"apiVersion": "2018-05-01",
"location": "[parameters('groupLocation')]",
"properties": {
}
},
{
"type": "Microsoft.Resources/deployments",
"apiVersion": "2018-05-01",
"name": "storageDeployment",
"resourceGroup": "[parameters('groupName')]",
"dependsOn": [
"[resourceId('Microsoft.Resources/resourceGroups/', parameters('groupName'))]"
],
"properties": {
"mode": "Incremental",
"template": {
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {},
"variables": {},
"resources": [
{
"comments": "Create a new App Service Plan",
"type": "Microsoft.Web/serverfarms",
"name": "[variables('appServicePlanName')]",
"apiVersion": "2018-02-01",
"location": "[variables('resourcesLocation')]",
"sku": "[parameters('newAppServicePlanSku')]",
"properties": {
"name": "[variables('appServicePlanName')]"
}
},
{
"comments": "Create a Web App using the new App Service Plan",
"type": "Microsoft.Web/sites",
"apiVersion": "2015-08-01",
"location": "[variables('resourcesLocation')]",
"kind": "app",
"dependsOn": [
"[resourceId('Microsoft.Web/serverfarms/', variables('appServicePlanName'))]"
],
"name": "[variables('webAppName')]",
"properties": {
"name": "[variables('webAppName')]",
"serverFarmId": "[variables('appServicePlanName')]",
"siteConfig": {
"appSettings": [
{
"name": "WEBSITE_NODE_DEFAULT_VERSION",
"value": "10.14.1"
},
{
"name": "MicrosoftAppId",
"value": "[parameters('appId')]"
},
{
"name": "MicrosoftAppPassword",
"value": "[parameters('appSecret')]"
}
],
"cors": {
"allowedOrigins": [
"https://botservice.hosting.portal.azure.net",
"https://hosting.onecloud.azure-test.net/"
]
}
}
}
},
{
"apiVersion": "2017-12-01",
"type": "Microsoft.BotService/botServices",
"name": "[parameters('botId')]",
"location": "global",
"kind": "bot",
"sku": {
"name": "[parameters('botSku')]"
},
"properties": {
"name": "[parameters('botId')]",
"displayName": "[parameters('botId')]",
"endpoint": "[variables('botEndpoint')]",
"msaAppId": "[parameters('appId')]",
"developerAppInsightsApplicationId": null,
"developerAppInsightKey": null,
"publishingCredentials": null,
"storageResourceId": null
},
"dependsOn": [
"[resourceId('Microsoft.Web/sites/', variables('webAppName'))]"
]
}
],
"outputs": {}
}
}
}
]
}
================================================
FILE: blog-samples/CSharp/FacebookHandover/Secondary/DeploymentTemplates/template-with-preexisting-rg.json
================================================
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"appId": {
"type": "string",
"metadata": {
"description": "Active Directory App ID, set as MicrosoftAppId in the Web App's Application Settings."
}
},
"appSecret": {
"type": "string",
"metadata": {
"description": "Active Directory App Password, set as MicrosoftAppPassword in the Web App's Application Settings. Defaults to \"\"."
}
},
"botId": {
"type": "string",
"metadata": {
"description": "The globally unique and immutable bot ID. Also used to configure the displayName of the bot, which is mutable."
}
},
"botSku": {
"defaultValue": "F0",
"type": "string",
"metadata": {
"description": "The pricing tier of the Bot Service Registration. Acceptable values are F0 and S1."
}
},
"newAppServicePlanName": {
"type": "string",
"defaultValue": "",
"metadata": {
"description": "The name of the new App Service Plan."
}
},
"newAppServicePlanSku": {
"type": "object",
"defaultValue": {
"name": "S1",
"tier": "Standard",
"size": "S1",
"family": "S",
"capacity": 1
},
"metadata": {
"description": "The SKU of the App Service Plan. Defaults to Standard values."
}
},
"appServicePlanLocation": {
"type": "string",
"metadata": {
"description": "The location of the App Service Plan."
}
},
"existingAppServicePlan": {
"type": "string",
"defaultValue": "",
"metadata": {
"description": "Name of the existing App Service Plan used to create the Web App for the bot."
}
},
"newWebAppName": {
"type": "string",
"defaultValue": "",
"metadata": {
"description": "The globally unique name of the Web App. Defaults to the value passed in for \"botId\"."
}
}
},
"variables": {
"defaultAppServicePlanName": "[if(empty(parameters('existingAppServicePlan')), 'createNewAppServicePlan', parameters('existingAppServicePlan'))]",
"useExistingAppServicePlan": "[not(equals(variables('defaultAppServicePlanName'), 'createNewAppServicePlan'))]",
"servicePlanName": "[if(variables('useExistingAppServicePlan'), parameters('existingAppServicePlan'), parameters('newAppServicePlanName'))]",
"resourcesLocation": "[parameters('appServicePlanLocation')]",
"webAppName": "[if(empty(parameters('newWebAppName')), parameters('botId'), parameters('newWebAppName'))]",
"siteHost": "[concat(variables('webAppName'), '.azurewebsites.net')]",
"botEndpoint": "[concat('https://', variables('siteHost'), '/api/messages')]"
},
"resources": [
{
"comments": "Create a new App Service Plan if no existing App Service Plan name was passed in.",
"type": "Microsoft.Web/serverfarms",
"condition": "[not(variables('useExistingAppServicePlan'))]",
"name": "[variables('servicePlanName')]",
"apiVersion": "2018-02-01",
"location": "[variables('resourcesLocation')]",
"sku": "[parameters('newAppServicePlanSku')]",
"properties": {
"name": "[variables('servicePlanName')]"
}
},
{
"comments": "Create a Web App using an App Service Plan",
"type": "Microsoft.Web/sites",
"apiVersion": "2015-08-01",
"location": "[variables('resourcesLocation')]",
"kind": "app",
"dependsOn": [
"[resourceId('Microsoft.Web/serverfarms/', variables('servicePlanName'))]"
],
"name": "[variables('webAppName')]",
"properties": {
"name": "[variables('webAppName')]",
"serverFarmId": "[variables('servicePlanName')]",
"siteConfig": {
"appSettings": [
{
"name": "WEBSITE_NODE_DEFAULT_VERSION",
"value": "10.14.1"
},
{
"name": "MicrosoftAppId",
"value": "[parameters('appId')]"
},
{
"name": "MicrosoftAppPassword",
"value": "[parameters('appSecret')]"
}
],
"cors": {
"allowedOrigins": [
"https://botservice.hosting.portal.azure.net",
"https://hosting.onecloud.azure-test.net/"
]
}
}
}
},
{
"apiVersion": "2017-12-01",
"type": "Microsoft.BotService/botServices",
"name": "[parameters('botId')]",
"location": "global",
"kind": "bot",
"sku": {
"name": "[parameters('botSku')]"
},
"properties": {
"name": "[parameters('botId')]",
"displayName": "[parameters('botId')]",
"endpoint": "[variables('botEndpoint')]",
"msaAppId": "[parameters('appId')]",
"developerAppInsightsApplicationId": null,
"developerAppInsightKey": null,
"publishingCredentials": null,
"storageResourceId": null
},
"dependsOn": [
"[resourceId('Microsoft.Web/sites/', variables('webAppName'))]"
]
}
]
}
================================================
FILE: blog-samples/CSharp/FacebookHandover/Secondary/Program.cs
================================================
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
//
// Generated with Bot Builder V4 SDK Template for Visual Studio EchoBot v4.3.0
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
namespace Secondary
{
public class Program
{
public static void Main(string[] args)
{
CreateWebHostBuilder(args).Build().Run();
}
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup();
}
}
================================================
FILE: blog-samples/CSharp/FacebookHandover/Secondary/Properties/launchSettings.json
================================================
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:3979/",
"sslPort": 0
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"Secondary": {
"commandName": "Project",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "http://localhost:3979/"
}
}
}
================================================
FILE: blog-samples/CSharp/FacebookHandover/Secondary/Secondary.csproj
================================================
netcoreapp2.1Always
================================================
FILE: blog-samples/CSharp/FacebookHandover/Secondary/Startup.cs
================================================
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
//
// Generated with Bot Builder V4 SDK Template for Visual Studio EchoBot v4.3.0
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.BotFramework;
using Microsoft.Bot.Builder.Integration.AspNet.Core;
using Microsoft.Bot.Connector.Authentication;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Secondary.Bots;
namespace Secondary
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
// Create the credential provider to be used with the Bot Framework Adapter.
services.AddSingleton();
// Create the Bot Framework Adapter.
services.AddSingleton();
// Create the bot as a transient. In this case the ASP Controller is expecting an IBot.
services.AddTransient();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseHsts();
}
app.UseDefaultFiles();
app.UseStaticFiles();
//app.UseHttpsRedirection();
app.UseMvc();
}
}
}
================================================
FILE: blog-samples/CSharp/FacebookHandover/Secondary/appsettings.Development.json
================================================
{
"Logging": {
"LogLevel": {
"Default": "Debug",
"System": "Information",
"Microsoft": "Information"
}
}
}
================================================
FILE: blog-samples/CSharp/FacebookHandover/Secondary/appsettings.json
================================================
{
"MicrosoftAppId": "",
"MicrosoftAppPassword": "",
"FacebookPageToken": ""
}
================================================
FILE: blog-samples/CSharp/FacebookHandover/Secondary/wwwroot/default.htm
================================================
Secondary
Secondary Bot
Your bot is ready!
You can test your bot in the Bot Framework Emulator
by connecting to http://localhost:3979/api/messages.
Visit Bot Framework to register your bot. When you register it, remember to set your bot's endpoint to
https://your_bots_hostname/api/messages
================================================
FILE: docs-samples/CSharp/Simple-LUIS-Notes-Sample/Simple-LUIS-Notes-Sample/packages.config
================================================
================================================
FILE: docs-samples/CSharp/Simple-LUIS-Notes-Sample/Simple-LUIS-Notes-Sample.sln
================================================
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26730.12
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NotesBot", "Simple-LUIS-Notes-Sample\NotesBot.csproj", "{A8BA1066-5695-4D71-ABB4-65E5A5E0C3D4}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{A8BA1066-5695-4D71-ABB4-65E5A5E0C3D4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A8BA1066-5695-4D71-ABB4-65E5A5E0C3D4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A8BA1066-5695-4D71-ABB4-65E5A5E0C3D4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A8BA1066-5695-4D71-ABB4-65E5A5E0C3D4}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {9B625B7D-68FE-4DC9-804E-D483514FE7BC}
EndGlobalSection
EndGlobal
================================================
FILE: docs-samples/CSharp/Simple-LUIS-Notes-Sample/VSIX/readme.md
================================================
NOTE: This is the older version of the VSIX template. With the release of SDK v4, please use the latest VSIX available on [Visual Studio Market Place](https://marketplace.visualstudio.com/items?itemName=BotBuilder.BotBuilderV4).
================================================
FILE: docs-samples/CSharp/Simple-LUIS-Notes-Sample/readme.md
================================================
# Recognize intents and entities with LUIS
This sample demonstrates how to build a note-taking bot that uses Language Understanding Intelligent Service (LUIS) to respond to natural language input.
## Intents and utterances
A bot needs to detect what a user wants to do, which is their **intent**. This intent is determined from spoken or textual input, or **utterances**. The intent maps utterances to actions that the bot takes, such as invoking a dialog.
In the note-taking bot example, the following table shows how each intent maps to functionality.
| Intent | Example Utterances | Bot functionality |
|------|----------------------|------|
| Note.Create | Create a note Create a note called Grocery List save a new note | CreateNote method |
| Note.Delete | Delete my note Delete my Grocery List note | DeleteNote method |
| Note.ReadAloud | Read my note Read me the Grocery List note | ReadNote method |
## Entities
A bot may also need to extract entities, which are important words in utterances. Sometimes entities are required to fulfill an intent. In the note-taking bot, the `Notes.Title` entity identifies the title of each note.
| Entity | Example Utterances | Value | Bot functionality |
|------|------|------|------|
| Notes.Title| Create a note called `ShoppingList` now | "ShoppingList" | The CreateNote, DeleteNote, and ReadNote dialog use the title to save or find a note. The dialogs prompt for it if a `Notes.Title` entity isn't detected in the utterance.|
When your bot receives an utterance, it can use either regular expressions or an intent recognition service like LUIS to determine the intent. To use LUIS, you configure a web service known as a **LUIS app** at [www.luis.ai][LUIS], and integrate it with your bot using the **LuisDialog** class.
## Create your LUIS app
To create the LUIS app that provides the intents and entities to the bot, follow the steps in this section.
**Tip:** The LUIS app that the following steps create can also be imported from a [JSON file](Notes.json). To import the LUIS app in [www.luis.ai][LUIS], go to **My Apps** and click the **Import App** button.
1. Log in to [www.luis.ai][LUIS] using your Cognitive Services API account. If you don't have an account, you can create a free account in the [Azure portal](https://ms.portal.azure.com).
2. In the **My Apps** page, click **New App**, enter a name like Notes in the **Name** field, and choose **Bootstrap Key** in the **Key to use** field.
3. In the **Intents** page, click **Add prebuilt domain intents** and select **Notes.Create**, **Notes.Delete** and **Notes.ReadAloud**.
4. In the **Intents** page, click on the **None** intent. This intent is meant for utterances that don’t correspond to any other intents. Enter an example of an utterance unrelated to notes, like “Turn off the lights”.
5. In the **Entities** page, click **Add prebuilt domain entities** and select **Notes.Title**.
6. In the **Train & Test** page, train your app.
7. In the **Publish** page, click **Publish**. After successful publish, copy the **Endpoint URL** from the **Publish App** page, to use later in your bot’s code. The URL has a format similar to this example: `https://westus.api.cognitive.microsoft.com/luis/v2.0/apps/3889f7d0-9501-45c8-be5f-8635975eea8b?subscription-key=67073e45132a459db515ca04cea325d3&timezoneOffset=0&verbose=true&q=`
## How LUIS passes intents and entities to your bot
The following diagram shows the sequence of events that happen after the bot receives an utterance from the user. First, the bot passes the utterance to the LUIS app and gets a JSON result from LUIS that contains intents and entities. Next, your bot automatically invokes any matching handler that your bot associates with the high-scoring intent in the LUIS result. The matching handler is specified by the **LuisIntent** attribute.
## Create the LuisDialog class
To create a [dialog](https://docs.microsoft.com/en-us/bot-framework/dotnet/bot-builder-dotnet-dialogs) that uses LUIS, first create a class that derives from `LuisDialog` and
specify the [LuisModel attribute](https://docs.microsoft.com/en-us/dotnet/api/microsoft.bot.builder.luis.luismodelattribute?view=botbuilder-3.8).
To populate the `modelID` and `subscriptionKey` parameters for the `LuisModel` attribute, use
the `id` and `subscription-key` attribute values from your LUIS application's endpoint.
The `domain` parameter is determined by the Azure region to which your LUIS app is published.
If not supplied, it defaults to `westus.api.cognitive.microsoft.com`.
See [Regions and keys](https://docs.microsoft.com/en-us/azure/cognitive-services/LUIS/manage-keys#regions-and-keys) for more information.
## Create methods to handle intents
Within the class, create the methods that execute when your LUIS model matches a user's utterance to intent.
To designate the method that runs when a specific intent is matched, specify the `LuisIntent` attribute.
## Try the bot
You can run the bot using the Bot Framework Emulator and tell it to create a note.
**Tip:** If you find that your bot doesn't always recognize the correct intent or entities, improve your LUIS app's performance by giving it more example utterances to train it. You can retrain your LUIS app without any modification to your bot's code. See [Add example utterances](https://docs.microsoft.com/en-us/azure/cognitive-services/LUIS/add-example-utterances) and [train and test your LUIS app](https://docs.microsoft.com/en-us/azure/cognitive-services/LUIS/train-test).
[LUIS]: https://www.luis.ai/
================================================
FILE: docs-samples/Node/basics-naturalLanguage/Notes.json
================================================
{
"luis_schema_version": "2.1.0",
"versionId": "0.1",
"name": "Notes",
"desc": "",
"culture": "en-us",
"intents": [
{
"name": "None"
},
{
"name": "Note.Create",
"inherits": {
"domain_name": "Note",
"model_name": "Create"
}
},
{
"name": "Note.Delete",
"inherits": {
"domain_name": "Note",
"model_name": "Delete"
}
},
{
"name": "Note.ReadAloud",
"inherits": {
"domain_name": "Note",
"model_name": "ReadAloud"
}
}
],
"entities": [
{
"name": "Note.Text",
"inherits": {
"domain_name": "Note",
"model_name": "Text"
}
},
{
"name": "Note.Title",
"inherits": {
"domain_name": "Note",
"model_name": "Title"
}
}
],
"composites": [],
"closedLists": [],
"bing_entities": [],
"actions": [],
"model_features": [],
"regex_features": [],
"utterances": [
{
"text": "help",
"intent": "None",
"entities": []
},
{
"text": "drive me home",
"intent": "None",
"entities": []
},
{
"text": "add mark to guest list",
"intent": "None",
"entities": [
{
"entity": "Note.Text",
"startPos": 4,
"endPos": 7
},
{
"entity": "Note.Title",
"startPos": 12,
"endPos": 16
}
]
},
{
"text": "add Fred George to onenote",
"intent": "None",
"entities": [
{
"entity": "Note.Text",
"startPos": 4,
"endPos": 14
}
]
},
{
"text": "Add oatmeal to shopping list .",
"intent": "None",
"entities": [
{
"entity": "Note.Text",
"startPos": 4,
"endPos": 10
},
{
"entity": "Note.Title",
"startPos": 15,
"endPos": 22
}
]
},
{
"text": "send lighter fluid to onenote",
"intent": "None",
"entities": [
{
"entity": "Note.Text",
"startPos": 5,
"endPos": 17
}
]
},
{
"text": "add friends to party list in memos",
"intent": "None",
"entities": [
{
"entity": "Note.Text",
"startPos": 4,
"endPos": 10
}
]
},
{
"text": "add tasks to wunderlist",
"intent": "None",
"entities": [
{
"entity": "Note.Title",
"startPos": 4,
"endPos": 8
}
]
},
{
"text": "clear my save notes",
"intent": "None",
"entities": [
{
"entity": "Note.Title",
"startPos": 9,
"endPos": 12
}
]
},
{
"text": "\"I want to create a note of title \"\" Shopping list \"\"\"",
"intent": "Note.Create",
"entities": [
{
"entity": "Note.Title",
"startPos": 34,
"endPos": 35
}
]
},
{
"text": "To buy list",
"intent": "Note.Create",
"entities": [
{
"entity": "Note.Title",
"startPos": 3,
"endPos": 5
}
]
},
{
"text": "Save the current note",
"intent": "Note.Create",
"entities": []
},
{
"text": "type in notepad",
"intent": "Note.Create",
"entities": []
},
{
"text": "create My Favorites note",
"intent": "Note.Create",
"entities": []
},
{
"text": "waffles recipe is my new note to be created",
"intent": "Note.Create",
"entities": []
},
{
"text": "A new note of name Business Solutions",
"intent": "Note.Create",
"entities": []
},
{
"text": "A new note please",
"intent": "Note.Create",
"entities": []
},
{
"text": "can you set a note up to mom",
"intent": "Note.Create",
"entities": []
},
{
"text": "create note with notepad",
"intent": "Note.Create",
"entities": []
},
{
"text": "Delete the note of name Guest list",
"intent": "Note.Delete",
"entities": []
},
{
"text": "delete poetry notes",
"intent": "Note.Delete",
"entities": [
{
"entity": "Note.Title",
"startPos": 7,
"endPos": 12
}
]
},
{
"text": "DELETE LIBRARY LIST",
"intent": "Note.Delete",
"entities": [
{
"entity": "Note.Title",
"startPos": 7,
"endPos": 13
}
]
},
{
"text": "Delete note: Summer Reading List.",
"intent": "Note.Delete",
"entities": []
},
{
"text": "dismiss Fred's notes",
"intent": "Note.Delete",
"entities": [
{
"entity": "Note.Title",
"startPos": 8,
"endPos": 11
}
]
},
{
"text": "Remove Daddy's BD note",
"intent": "Note.Delete",
"entities": [
{
"entity": "Note.Text",
"startPos": 7,
"endPos": 12
}
]
},
{
"text": "delete my ideas list",
"intent": "Note.Delete",
"entities": []
},
{
"text": "Delete Insurance note please",
"intent": "Note.Delete",
"entities": []
},
{
"text": "delete latest note",
"intent": "Note.Delete",
"entities": []
},
{
"text": "Recall note 3 delete",
"intent": "Note.Delete",
"entities": []
},
{
"text": "Can you read the grocery list note please",
"intent": "Note.ReadAloud",
"entities": [
{
"entity": "Note.Title",
"startPos": 17,
"endPos": 23
}
]
},
{
"text": "Repeat the last word again",
"intent": "Note.ReadAloud",
"entities": []
},
{
"text": "Read meeting notes to me",
"intent": "Note.ReadAloud",
"entities": [
{
"entity": "Note.Text",
"startPos": 5,
"endPos": 11
}
]
},
{
"text": "recall most recent groccery list",
"intent": "Note.ReadAloud",
"entities": [
{
"entity": "Note.Title",
"startPos": 19,
"endPos": 26
}
]
},
{
"text": "Please read Trip notes",
"intent": "Note.ReadAloud",
"entities": [
{
"entity": "Note.Title",
"startPos": 12,
"endPos": 15
}
]
},
{
"text": "I want you to read this note loudly",
"intent": "Note.ReadAloud",
"entities": []
},
{
"text": "Read my grocery list",
"intent": "Note.ReadAloud",
"entities": [
{
"entity": "Note.Title",
"startPos": 8,
"endPos": 14
}
]
},
{
"text": "\"read note \"\" grocery list \"\"\"",
"intent": "Note.ReadAloud",
"entities": [
{
"entity": "Note.Title",
"startPos": 11,
"endPos": 11
}
]
},
{
"text": "speak trip note for me please",
"intent": "Note.ReadAloud",
"entities": [
{
"entity": "Note.Title",
"startPos": 6,
"endPos": 9
}
]
},
{
"text": "read the note appointments please",
"intent": "Note.ReadAloud",
"entities": [
{
"entity": "Note.Text",
"startPos": 14,
"endPos": 25
}
]
},
{
"text": "Create for me a note about Car Oil",
"intent": "Note.Create",
"entities": [
{
"entity": "Note.Text",
"startPos": 27,
"endPos": 33
}
]
},
{
"text": "Stop reading the note",
"intent": "None",
"entities": [
{
"entity": "Note.Text",
"startPos": 0,
"endPos": 15
}
]
},
{
"text": "Delete the note number two",
"intent": "Note.Delete",
"entities": [
{
"entity": "Note.Text",
"startPos": 16,
"endPos": 25
}
]
}
]
}
================================================
FILE: docs-samples/Node/basics-naturalLanguage/basicNote-intentDialog.js
================================================
/*-----------------------------------------------------------------------------
This bot demonstrates how to use dialogs with a LuisRecognizer to add LUIS support to a bot.
LUIS identifies intents and entities from user messages, or utterances.
Intents map utterances to functionality in your bot.
In this example, the intents provide the following mappings:
* The Notes.Create intent maps to the CreateNote handler
* The Notes.Delete intent maps to the DeleteNote handler
* The Notes.ReadAloud intent maps to the ReadNote handler
-----------------------------------------------------------------------------*/
var restify = require('restify');
var builder = require('botbuilder');
// Setup Restify Server
var server = restify.createServer();
server.listen(process.env.port || process.env.PORT || 3978, function () {
console.log('%s listening to %s', server.name, server.url);
});
// Create chat connector for communicating with the Bot Framework Service
// See https://aka.ms/node-env-var for information on setting environment variables in launch.json if you are using VSCode
var connector = new builder.ChatConnector({
appId: process.env.MICROSOFT_APP_ID,
appPassword: process.env.MICROSOFT_APP_PASSWORD
});
// Listen for messages from users
server.post('/api/messages', connector.listen());
//
// Create your bot
var bot = new builder.UniversalBot(connector);
//
//
// Add global LUIS recognizer to bot
var luisAppUrl = process.env.LUIS_APP_URL || 'https://westus.api.cognitive.microsoft.com/luis/v2.0/apps/?subscription-key=';
var notesRecognizer = bot.recognizer(new builder.LuisRecognizer(luisAppUrl));
//
//
var noteIntentsDialog = new builder.IntentDialog({
recognizers: [notesRecognizer]
});
bot.dialog('/', noteIntentsDialog);
//
//
// Handle the None intent
// This default message handler is invoked if the user's utterance doesn't
// match any other intents defined in the LUIS app.
noteIntentsDialog.matches('None', [
function (session, args) {
session.send("Hi... I'm the note bot sample. I can create new notes, read saved notes to you and delete notes.");
// If the object for storing notes in session.userData doesn't exist yet, initialize it
if (!session.userData.notes) {
session.userData.notes = {};
console.log("initializing userData.notes in default message handler");
}
}]);
//
//
// Handle the Note.Create intent
noteIntentsDialog.matches('Note.Create', [
function (session, args, next) {
// Resolve and store any Note.Title entity passed from LUIS.
var intent = args.intent;
var title = builder.EntityRecognizer.findEntity(intent.entities, 'Note.Title');
var note = session.dialogData.note = {
title: title ? title.entity : null,
};
// Prompt for title
if (!note.title) {
builder.Prompts.text(session, 'What would you like to call your note?');
} else {
next();
}
},
function (session, results, next) {
var note = session.dialogData.note;
if (results.response) {
note.title = results.response;
}
// Prompt for the text of the note
if (!note.text) {
builder.Prompts.text(session, 'What would you like to say in your note?');
} else {
next();
}
},
function (session, results) {
var note = session.dialogData.note;
if (results.response) {
note.text = results.response;
}
// If the object for storing notes in session.userData doesn't exist yet, initialize it
if (!session.userData.notes) {
session.userData.notes = {};
console.log("initializing session.userData.notes in CreateNote dialog");
}
// Save notes in the notes object
session.userData.notes[note.title] = note;
// Send confirmation to user
session.endDialog('Creating note named "%s" with text "%s"',
note.title, note.text);
}
]);
//
//
// Handle the Note.Delete intent
noteIntentsDialog.matches('Note.Delete', [
function (session, args, next) {
if (noteCount(session.userData.notes) > 0) {
// Resolve and store any Note.Title entity passed from LUIS.
var title;
var intent = args.intent;
var entity = builder.EntityRecognizer.findEntity(intent.entities, 'Note.Title');
if (entity) {
// Verify that the title is in our set of notes.
title = builder.EntityRecognizer.findBestMatch(session.userData.notes, entity.entity);
}
// Prompt for note name
if (!title) {
builder.Prompts.choice(session, 'Which note would you like to delete?', session.userData.notes);
} else {
next({ response: title });
}
} else {
session.endDialog("No notes to delete.");
}
},
function (session, results) {
delete session.userData.notes[results.response.entity];
session.endDialog("Deleted the '%s' note.", results.response.entity);
}
]);
//
//
// Handle the Notes.ReadAloud intent
noteIntentsDialog.matches('Note.ReadAloud', [
function (session, args, next) {
if (noteCount(session.userData.notes) > 0) {
// Resolve and store any Note.Title entity passed from LUIS.
var title;
var intent = args.intent;
var entity = builder.EntityRecognizer.findEntity(intent.entities, 'Note.Title');
if (entity) {
// Verify it's in our set of notes.
title = builder.EntityRecognizer.findBestMatch(session.userData.notes, entity.entity);
}
// Prompt for note name
if (!title) {
builder.Prompts.choice(session, 'Which note would you like to read?', session.userData.notes);
} else {
next({ response: title });
}
} else {
session.endDialog("No notes to read.");
}
},
function (session, results) {
session.endDialog("Here's the '%s' note: '%s'.", results.response.entity, session.userData.notes[results.response.entity].text);
}
]);
//
//
// Helper function to count the number of notes stored in session.userData.notes
function noteCount(notes) {
var i = 0;
for (var name in notes) {
i++;
}
return i;
}
//
================================================
FILE: docs-samples/Node/basics-naturalLanguage/basicNote.js
================================================
/*-----------------------------------------------------------------------------
This bot demonstrates how to use dialogs with a LuisRecognizer to add LUIS support to a bot.
LUIS identifies intents and entities from user messages, or utterances.
Intents map utterances to functionality in your bot.
In this example, the intents provide the following mappings:
* The Notes.Create intent maps to the CreateNote dialog
* The Notes.Delete intent maps to the DeleteNote dialog
* The Notes.ReadAloud intent maps to the ReadNote dialog
-----------------------------------------------------------------------------*/
var restify = require('restify');
var builder = require('botbuilder');
// Setup Restify Server
var server = restify.createServer();
server.listen(process.env.port || process.env.PORT || 3978, function () {
console.log('%s listening to %s', server.name, server.url);
});
// Create chat connector for communicating with the Bot Framework Service
// See https://aka.ms/node-env-var for information on setting environment variables in launch.json if you are using VSCode
var connector = new builder.ChatConnector({
appId: process.env.MICROSOFT_APP_ID,
appPassword: process.env.MICROSOFT_APP_PASSWORD
});
// Listen for messages from users
server.post('/api/messages', connector.listen());
// Create your bot with a function to receive messages from the user.
// This default message handler is invoked if the user's utterance doesn't
// match any intents handled by other dialogs.
var bot = new builder.UniversalBot(connector, function (session, args) {
session.send("Hi... I'm the note bot sample. I can create new notes, read saved notes to you and delete notes.");
// If the object for storing notes in session.userData doesn't exist yet, initialize it
if (!session.userData.notes) {
session.userData.notes = {};
console.log("initializing userData.notes in default message handler");
}
});
// Add global LUIS recognizer to bot
var luisAppUrl = process.env.LUIS_APP_URL || 'https://westus.api.cognitive.microsoft.com/luis/v2.0/apps/?subscription-key=';
bot.recognizer(new builder.LuisRecognizer(luisAppUrl));
// CreateNote dialog
bot.dialog('CreateNote', [
function (session, args, next) {
// Resolve and store any Note.Title entity passed from LUIS.
var intent = args.intent;
var title = builder.EntityRecognizer.findEntity(intent.entities, 'Note.Title');
var note = session.dialogData.note = {
title: title ? title.entity : null,
};
// Prompt for title
if (!note.title) {
builder.Prompts.text(session, 'What would you like to call your note?');
} else {
next();
}
},
function (session, results, next) {
var note = session.dialogData.note;
if (results.response) {
note.title = results.response;
}
// Prompt for the text of the note
if (!note.text) {
builder.Prompts.text(session, 'What would you like to say in your note?');
} else {
next();
}
},
function (session, results) {
var note = session.dialogData.note;
if (results.response) {
note.text = results.response;
}
// If the object for storing notes in session.userData doesn't exist yet, initialize it
if (!session.userData.notes) {
session.userData.notes = {};
console.log("initializing session.userData.notes in CreateNote dialog");
}
// Save notes in the notes object
session.userData.notes[note.title] = note;
// Send confirmation to user
session.endDialog('Creating note named "%s" with text "%s"',
note.title, note.text);
}
]).triggerAction({
matches: 'Note.Create',
confirmPrompt: "This will cancel the creation of the note you started. Are you sure?"
}).cancelAction('cancelCreateNote', "Note canceled.", {
matches: /^(cancel|nevermind)/i,
confirmPrompt: "Are you sure?"
});
// Delete note dialog
bot.dialog('DeleteNote', [
function (session, args, next) {
if (noteCount(session.userData.notes) > 0) {
// Resolve and store any Note.Title entity passed from LUIS.
var title;
var intent = args.intent;
var entity = builder.EntityRecognizer.findEntity(intent.entities, 'Note.Title');
if (entity) {
// Verify that the title is in our set of notes.
title = builder.EntityRecognizer.findBestMatch(session.userData.notes, entity.entity);
}
// Prompt for note name
if (!title) {
builder.Prompts.choice(session, 'Which note would you like to delete?', session.userData.notes);
} else {
next({ response: title });
}
} else {
session.endDialog("No notes to delete.");
}
},
function (session, results) {
delete session.userData.notes[results.response.entity];
session.endDialog("Deleted the '%s' note.", results.response.entity);
}
]).triggerAction({
matches: 'Note.Delete'
}).cancelAction('cancelDeleteNote', "Ok - canceled note deletion.", {
matches: /^(cancel|nevermind)/i
});
// Read note dialog
bot.dialog('ReadNote', [
function (session, args, next) {
if (noteCount(session.userData.notes) > 0) {
// Resolve and store any Note.Title entity passed from LUIS.
var title;
var intent = args.intent;
var entity = builder.EntityRecognizer.findEntity(intent.entities, 'Note.Title');
if (entity) {
// Verify it's in our set of notes.
title = builder.EntityRecognizer.findBestMatch(session.userData.notes, entity.entity);
}
// Prompt for note name
if (!title) {
builder.Prompts.choice(session, 'Which note would you like to read?', session.userData.notes);
} else {
next({ response: title });
}
} else {
session.endDialog("No notes to read.");
}
},
function (session, results) {
session.endDialog("Here's the '%s' note: '%s'.", results.response.entity, session.userData.notes[results.response.entity].text);
}
]).triggerAction({
matches: 'Note.ReadAloud'
}).cancelAction('cancelReadNote', "Ok.", {
matches: /^(cancel|nevermind)/i
});
// Helper function to count the number of notes stored in session.userData.notes
function noteCount(notes) {
var i = 0;
for (var name in notes) {
i++;
}
return i;
}
================================================
FILE: docs-samples/Node/basics-naturalLanguage/readme.md
================================================
# Recognize intents and entities with LUIS
This sample demonstrates how to build a note-taking bot that uses Language Understanding Intelligent Service (LUIS) to respond to natural language input.
## Intents and utterances
A bot needs to detect what a user wants to do, which is their **intent**. This intent is determined from spoken or textual input, or **utterances**. The intent maps utterances to actions that the bot takes, such as invoking a dialog.
In the note-taking bot example, the following table shows how each intent maps to functionality.
| Intent | Example Utterances | Bot functionality |
|------|----------------------|------|
| Note.Create | Create a note Create a note called Grocery List save a new note | CreateNote dialog |
| Note.Delete | Delete my note Delete my Grocery List note | DeleteNote dialog |
| Note.ReadAloud | Read my note Read me the Grocery List note | ReadNote dialog |
## Entities
A bot may also need to extract entities, which are important words in utterances. Sometimes entities are required to fulfill an intent. In the note-taking bot, the `Notes.Title` entity identifies the title of each note.
| Entity | Example Utterances | Value | Bot functionality |
|------|------|------|------|
| Notes.Title| Create a note called `ShoppingList` now | "ShoppingList" | The CreateNote, DeleteNote, and ReadNote dialog use the title to save or find a note. The dialogs prompt for it if a `Notes.Title` entity isn't detected in the utterance.|
When your bot receives an utterance, it can use either regular expressions or an intent recognition service like LUIS to determine the intent. To use LUIS, you configure a web service known as a **LUIS app** at [www.luis.ai][LUIS], and integrate it with your bot using the [LuisRecognizer][LuisRecognizer] and [Dialog][Dialog] classes. To recognize intent using regular expressions, see [Recognize intent](./bot-builder-nodejs-recognize-intent.md).
## How LUIS passes intents and entities to your bot
The following diagram shows the sequence of events that happen after the bot receives an utterance from the user. First, the bot passes the utterance to the LUIS app and gets a JSON result from LUIS that contains intents and entities. Next, your bot automatically invokes any matching dialog that your bot associates with the high-scoring intent in the LUIS result. The full details of the match, including the list of intents and entities that LUIS detected, are passed to the `args` parameter of the matching dialog.
## Create your LUIS app
To create the LUIS app that provides the intents and entities to the bot, follow the steps in this section.
**Tip:** The LUIS app that the following steps create can also be imported from a [JSON file](Notes.json). To import the LUIS app in [www.luis.ai][LUIS], go to **My Apps** and click the **Import App** button.
1. Log in to [www.luis.ai][LUIS] using your Cognitive Services API account. If you don't have an account, you can create a free account in the [Azure portal](https://ms.portal.azure.com).
2. In the **My Apps** page, click **New App**, enter a name like Notes in the **Name** field, and choose **Bootstrap Key** in the **Key to use** field.
3. In the **Intents** page, click **Add prebuilt domain intents** and select **Notes.Create**, **Notes.Delete** and **Notes.ReadAloud**.
4. In the **Intents** page, click on the **None** intent. This intent is meant for utterances that don’t correspond to any other intents. Enter an example of an utterance unrelated to weather, like “Turn off the lights”
5. In the **Entities** page, click **Add prebuilt domain entities** and select **Notes.Title**.
6. In the **Train & Test** page, train your app.
7. In the **Publish** page, click **Publish**. After successful publish, copy the **Endpoint URL** from the **Publish App** page, to use later in your bot’s code. The URL has a format similar to this example: `https://westus.api.cognitive.microsoft.com/luis/v2.0/apps/3889f7d0-9501-45c8-be5f-8635975eea8b?subscription-key=67073e45132a459db515ca04cea325d3&timezoneOffset=0&verbose=true&q=`
## Create a note-taking bot integrated with the LUIS app
The code for the note-taking bot is in `basicNote.js`. To create this bot from scratch, you can first start with the sample code in [Create a bot with Node.js](https://docs.microsoft.com/en-us/bot-framework/nodejs/bot-builder-nodejs-quickstart#create-your-bot), and add code according to the instructions in the following sections.
### Create the bot
Create the bot that communicates with the Bot Framework Connector service by instantiating a [UniversalBot][UniversalBot] object. The constructor takes a second parameter for a default message handler. This message handler sends a generic help message about the functionality that the note-taking bot provides, and initializes the `session.userData.notes` object for storing notes. You use `session.userData` so the notes are persisted for the user. Edit the code that creates the bot, so that the constructor looks like the following code:
``` javascript
// Create your bot with a function to receive messages from the user.
// This default message handler is invoked if the user's utterance doesn't
// match any intents handled by other dialogs.
var bot = new builder.UniversalBot(connector, function (session, args) {
session.send("Hi... I'm the note bot sample. I can create new notes, read saved notes to you and delete notes.");
// If the object for storing notes in session.userData doesn't exist yet, initialize it
if (!session.userData.notes) {
session.userData.notes = {};
console.log("initializing userData.notes in default message handler");
}
});
```
### Add a LuisRecognizer
The [LuisRecognizer][LuisRecognizer] class calls the LUIS app. You initialize a **LuisRecognizer** using the **Endpoint URL** of the LUIS app that you copied from the **Publish App** page.
After you create the `UniversalBot`, add code to create the `LuisRecognizer` and add it to the bot:
``` javascript
// Add global LUIS recognizer to bot
var luisAppUrl = process.env.LUIS_APP_URL || 'https://westus.api.cognitive.microsoft.com/luis/v2.0/apps/?subscription-key=';
bot.recognizer(new builder.LuisRecognizer(luisAppUrl));
```
### Add dialogs
Now that the notes recognizer is set up to point to the LUIS app, you can add code for the dialogs. The [matches](https://docs.botframework.com/en-us/node/builder/chat-reference/interfaces/_botbuilder_d_.itriggeractionoptions.html#matches) property of the
[triggerAction](https://docs.microsoft.com/en-us/bot-framework/nodejs/bot-builder-nodejs-dialog-actions#bind-a-triggeraction) attached to the dialog specifies the name of the intent. The recognizer runs each time the bot receives an utterance from the user. If the highest scoring intent that it detects matches a `triggerAction` bound to a dialog, the bot invokes that dialog.
``` javascript
// Add global LUIS recognizer to bot
var luisAppUrl = process.env.LUIS_APP_URL || 'https://westus.api.cognitive.microsoft.com/luis/v2.0/apps/?subscription-key=';
bot.recognizer(new builder.LuisRecognizer(luisAppUrl));
```
#### Add the CreateNote dialog
Any entities in the utterance are passed to the dialog using the `args` parameter. The first step of the waterfall calls `EntityRecognizer.findEntity` to get the title of the note from any `Note.Title` entities in the LUIS response. If the LUIS app didn't detect a `Note.Title` entity, the bot prompts the user for the name of the note. The second step of the waterfall prompts for the text to include in the note. Once the bot has the text of the note, the third step uses `session.userData` to save the note in a `notes` object, using the title as the key.
The following code for a CreateNote dialog handles the `Note.Create` intent.
``` javascript
// CreateNote dialog
bot.dialog('CreateNote', [
function (session, args, next) {
// Resolve and store any Note.Title entity passed from LUIS.
var intent = args.intent;
var title = builder.EntityRecognizer.findEntity(intent.entities, 'Note.Title');
var note = session.dialogData.note = {
title: title ? title.entity : null,
};
// Prompt for title
if (!note.title) {
builder.Prompts.text(session, 'What would you like to call your note?');
} else {
next();
}
},
function (session, results, next) {
var note = session.dialogData.note;
if (results.response) {
note.title = results.response;
}
// Prompt for the text of the note
if (!note.text) {
builder.Prompts.text(session, 'What would you like to say in your note?');
} else {
next();
}
},
function (session, results) {
var note = session.dialogData.note;
if (results.response) {
note.text = results.response;
}
// If the object for storing notes in session.userData doesn't exist yet, initialize it
if (!session.userData.notes) {
session.userData.notes = {};
console.log("initializing session.userData.notes in CreateNote dialog");
}
// Save notes in the notes object
session.userData.notes[note.title] = note;
// Send confirmation to user
session.endDialog('Creating note named "%s" with text "%s"',
note.title, note.text);
}
]).triggerAction({
matches: 'Note.Create',
confirmPrompt: "This will cancel the creation of the note you started. Are you sure?"
}).cancelAction('cancelCreateNote', "Note canceled.", {
matches: /^(cancel|nevermind)/i,
confirmPrompt: "Are you sure?"
});
```
If the LUIS app detects an intent that interrupts the `CreateNote` dialog, the `confirmPrompt` property of the dialog's `triggerAction` provides a prompt to confirm the interruption. For example, if the bot says "What would you like to call your note?", and the user replies "Actually, I want to delete a note instead", the bot prompts the user using the `confirmPrompt` message.
#### Add the DeleteNote dialog
In the `DeleteNote` dialog, the `triggerAction` matches the `Note.Delete` intent. As in the `CreateNote` dialog, the bot examines the `args` parameter for a title. If no title is detected, the bot prompts the user. The title is used to look up the note to delete from `session.userData.notes`.
``` javascript
// Delete note dialog
bot.dialog('DeleteNote', [
function (session, args, next) {
if (noteCount(session.userData.notes) > 0) {
// Resolve and store any Note.Title entity passed from LUIS.
var title;
var intent = args.intent;
var entity = builder.EntityRecognizer.findEntity(intent.entities, 'Note.Title');
if (entity) {
// Verify that the title is in our set of notes.
title = builder.EntityRecognizer.findBestMatch(session.userData.notes, entity.entity);
}
// Prompt for note name
if (!title) {
builder.Prompts.choice(session, 'Which note would you like to delete?', session.userData.notes);
} else {
next({ response: title });
}
} else {
session.endDialog("No notes to delete.");
}
},
function (session, results) {
delete session.userData.notes[results.response.entity];
session.endDialog("Deleted the '%s' note.", results.response.entity);
}
]).triggerAction({
matches: 'Note.Delete'
}).cancelAction('cancelDeleteNote', "Ok - canceled note deletion.", {
matches: /^(cancel|nevermind)/i
});
```
The `DeleteNote` dialog uses the `noteCount` function to determine whether the `notes` object contains notes.
``` javascript
// Helper function to count the number of notes stored in session.userData.notes
function noteCount(notes) {
var i = 0;
for (var name in notes) {
i++;
}
return i;
}
```
#### Add the ReadNote dialog
For reading a note, the `triggerAction` matches the `Note.ReadAloud` intent. The `session.userData.notes` object is passed as the third argument to `builder.Prompts.choice`, so that the prompt displays a list of notes to the user.
``` javascript
// Read note dialog
bot.dialog('ReadNote', [
function (session, args, next) {
if (noteCount(session.userData.notes) > 0) {
// Resolve and store any Note.Title entity passed from LUIS.
var title;
var intent = args.intent;
var entity = builder.EntityRecognizer.findEntity(intent.entities, 'Note.Title');
if (entity) {
// Verify it's in our set of notes.
title = builder.EntityRecognizer.findBestMatch(session.userData.notes, entity.entity);
}
// Prompt for note name
if (!title) {
builder.Prompts.choice(session, 'Which note would you like to read?', session.userData.notes);
} else {
next({ response: title });
}
} else {
session.endDialog("No notes to read.");
}
},
function (session, results) {
session.endDialog("Here's the '%s' note: '%s'.", results.response.entity, session.userData.notes[results.response.entity].text);
}
]).triggerAction({
matches: 'Note.ReadAloud'
}).cancelAction('cancelReadNote', "Ok.", {
matches: /^(cancel|nevermind)/i
});
```
## Try the bot
You can run the bot using the Bot Framework Emulator and tell it to create a note.
The use of `triggerAction` to match intents means that the bot can detect and react to intents for every utterance, even utterances that occur in the middle of the steps of a dialog. If the user is in the `CreateNote` dialog, but asks to create a different note before the dialog's conversation flow is complete, the bot detects the second `Note.Create` intent, and prompts the user to verify the interruption.
## Use an IntentDialog
As you can see from trying the bot, the behavior of a `triggerAction` that matches an intent is global and allows interruption of the currently active dialog. Allowing and handling interruptions is a flexible design that accounts for what users really do. However, if you prefer a simpler conversational flow in which other intents can't interrupt a dialog, you can use an `IntentDialog`.
The code for a note-taking bot that uses `IntentDialog` is in `basicNote-intentDialog.js`. To convert the note-taking bot to use `IntentDialog` instead, start with the code in `basicNote.js` and do the following steps to modify it.
Instead of defining a default message handler in the bot constructor, replace the constructor with this code:
``` javascript
// Create your bot
var bot = new builder.UniversalBot(connector);
```
Modify the definition of the `LuisRecognizer` to match this code:
``` javascript
// Add global LUIS recognizer to bot
var luisAppUrl = process.env.LUIS_APP_URL || 'https://westus.api.cognitive.microsoft.com/luis/v2.0/apps/?subscription-key=';
var notesRecognizer = bot.recognizer(new builder.LuisRecognizer(luisAppUrl));
```
Define an `IntentDialog` using the following code:
``` javascript
var noteIntentsDialog = new builder.IntentDialog({
recognizers: [notesRecognizer]
});
bot.dialog('/', noteIntentsDialog);
```
To handle the None intent that is triggered when no other intents are identified, add the following code:
``` javascript
// Handle the None intent
// This default message handler is invoked if the user's utterance doesn't
// match any other intents defined in the LUIS app.
noteIntentsDialog.matches('None', [
function (session, args) {
session.send("Hi... I'm the note bot sample. I can create new notes, read saved notes to you and delete notes.");
// If the object for storing notes in session.userData doesn't exist yet, initialize it
if (!session.userData.notes) {
session.userData.notes = {};
console.log("initializing userData.notes in default message handler");
}
}]);
```
Replace the CreateNote dialog with the following code:
``` javascript
// Handle the Note.Create intent
noteIntentsDialog.matches('Note.Create', [
function (session, args, next) {
// Resolve and store any Note.Title entity passed from LUIS.
var intent = args.intent;
var title = builder.EntityRecognizer.findEntity(intent.entities, 'Note.Title');
var note = session.dialogData.note = {
title: title ? title.entity : null,
};
// Prompt for title
if (!note.title) {
builder.Prompts.text(session, 'What would you like to call your note?');
} else {
next();
}
},
function (session, results, next) {
var note = session.dialogData.note;
if (results.response) {
note.title = results.response;
}
// Prompt for the text of the note
if (!note.text) {
builder.Prompts.text(session, 'What would you like to say in your note?');
} else {
next();
}
},
function (session, results) {
var note = session.dialogData.note;
if (results.response) {
note.text = results.response;
}
// If the object for storing notes in session.userData doesn't exist yet, initialize it
if (!session.userData.notes) {
session.userData.notes = {};
console.log("initializing session.userData.notes in CreateNote dialog");
}
// Save notes in the notes object
session.userData.notes[note.title] = note;
// Send confirmation to user
session.endDialog('Creating note named "%s" with text "%s"',
note.title, note.text);
}
]);
```
Replace the DeleteNote dialog with the following code:
``` javascript
// Handle the Note.Delete intent
noteIntentsDialog.matches('Note.Delete', [
function (session, args, next) {
if (noteCount(session.userData.notes) > 0) {
// Resolve and store any Note.Title entity passed from LUIS.
var title;
var intent = args.intent;
var entity = builder.EntityRecognizer.findEntity(intent.entities, 'Note.Title');
if (entity) {
// Verify that the title is in our set of notes.
title = builder.EntityRecognizer.findBestMatch(session.userData.notes, entity.entity);
}
// Prompt for note name
if (!title) {
builder.Prompts.choice(session, 'Which note would you like to delete?', session.userData.notes);
} else {
next({ response: title });
}
} else {
session.endDialog("No notes to delete.");
}
},
function (session, results) {
delete session.userData.notes[results.response.entity];
session.endDialog("Deleted the '%s' note.", results.response.entity);
}
]);
```
Replace the ReadNote dialog with the following code:
``` javascript
// Handle the Notes.ReadAloud intent
noteIntentsDialog.matches('Note.ReadAloud', [
function (session, args, next) {
if (noteCount(session.userData.notes) > 0) {
// Resolve and store any Note.Title entity passed from LUIS.
var title;
var intent = args.intent;
var entity = builder.EntityRecognizer.findEntity(intent.entities, 'Note.Title');
if (entity) {
// Verify it's in our set of notes.
title = builder.EntityRecognizer.findBestMatch(session.userData.notes, entity.entity);
}
// Prompt for note name
if (!title) {
builder.Prompts.choice(session, 'Which note would you like to read?', session.userData.notes);
} else {
next({ response: title });
}
} else {
session.endDialog("No notes to read.");
}
},
function (session, results) {
session.endDialog("Here's the '%s' note: '%s'.", results.response.entity, session.userData.notes[results.response.entity].text);
}
]);
```
## Next steps
As next steps, you may want to improve your note-taking bot's recognition of intents and entities, or add more functionality to it.
### Improve recognition
In the process of testing this simple notes bot, you may notice that the LUIS app doesn't always recognize the `Notes.Title` entity in an utterance. There may also be times when the LUIS app identifies the wrong intent. A LUIS app learns from example, so you can improve its performance by giving it more example utterances to train it. You can retrain your LUIS app without any modification to your bot's code.
* See [Add example utterances](https://docs.microsoft.com/en-us/azure/cognitive-services/LUIS/add-example-utterances) for an explanation of how to provide more example utterances to LUIS so it can learn.
* Once you've provided more utterances, you can [train and test your LUIS app](https://docs.microsoft.com/en-us/azure/cognitive-services/LUIS/train-test).
A more advanced way to improve the performance of the LUIS app is to add features:
* See [Features in LUIS](https://docs.microsoft.com/en-us/azure/cognitive-services/LUIS/luis-concept-feature) for an explanation of what features are.
* See [Improve performance using features](https://docs.microsoft.com/en-us/azure/cognitive-services/LUIS/add-features) for a walkthrough of adding features to a LUIS app.
### Add more functionality
To more functionality to a LUIS-integrated bot, consider whether the new functionality maps to an intent or an entity. You may need a new intent to map to a conversation flow or dialog, and you might need new entities for new parameters or options. For example, if you want your notes bot to also be able to set alarms, you need to add intents to recognize alarm-related utterances, and extract entities like the alarm time.
* See the [Alarm bot sample][AlarmBot] for an example of a simple bot that creates and deletes alarms, and automatically extracts times from user utterances.
## Additional resources
To learn more about the actions you can associate with a recognized intent, see [Managing conversation flow](bot-builder-nodejs-manage-conversation-flow.md) and [Trigger actions using global handlers](bot-builder-nodejs-global-handlers.md).
For more information on LUIS, see the [LUIS documentation][LUISAzureDocs].
The [LUIS Bot sample][LUISBotSample] demonstrates how to build a more complex LUIS-integrated bot. Its LUIS app provides intents and entities for searching for hotels.
[LUIS]: https://www.luis.ai/
[LUISAzureDocs]: https://docs.microsoft.com/en-us/azure/cognitive-services/LUIS/Home
[Dialog]: https://docs.botframework.com/en-us/node/builder/chat-reference/classes/_botbuilder_d_.dialog.html
[IntentRecognizerSetOptions]: https://docs.botframework.com/en-us/node/builder/chat-reference/interfaces/_botbuilder_d_.iintentrecognizersetoptions.html
[LuisRecognizer]: https://docs.botframework.com/en-us/node/builder/chat-reference/classes/_botbuilder_d_.luisrecognizer
[LUISConcepts]: https://docs.botframework.com/en-us/node/builder/guides/understanding-natural-language/
[DisambiguationSample]: https://github.com/Microsoft/BotBuilder/tree/master/Node/examples/feature-onDisambiguateRoute
[IDisambiguateRouteHandler]: https://docs.botframework.com/en-us/node/builder/chat-reference/interfaces/_botbuilder_d_.idisambiguateroutehandler.html
[RegExpRecognizer]: https://docs.botframework.com/en-us/node/builder/chat-reference/classes/_botbuilder_d_.regexprecognizer.html
[AlarmBot]: https://github.com/Microsoft/BotBuilder/blob/master/Node/examples/basics-naturalLanguage/app.js
[LUISBotSample]: https://github.com/Microsoft/BotBuilder-Samples/tree/master/Node/intelligence-LUIS
[UniversalBot]: https://docs.botframework.com/en-us/node/builder/chat-reference/classes/_botbuilder_d_.universalbot.html
================================================
FILE: docs-samples/README.md
================================================
# Documentation samples
These samples and code snippets are referenced in the [Bot Framework documentation](https://docs.microsoft.com/bot-framework).
================================================
FILE: docs-samples/V4/JS/contosocafebot-luis-dialogs/.gitignore
================================================
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
# nyc test coverage
.nyc_output
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# TypeScript v1 declaration files
typings/
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
# next.js build output
.next
================================================
FILE: docs-samples/V4/JS/contosocafebot-luis-dialogs/.vscode/launch.json
================================================
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Launch Program",
"program": "${workspaceFolder}\\lib\\luisbot.js",
"outFiles": [
"${workspaceFolder}/**/*.js"
],
"envFile": "${workspaceFolder}\\src\\.env"
}
]
}
================================================
FILE: docs-samples/V4/JS/contosocafebot-luis-dialogs/cafeLUISModel.json
================================================
{
"intents": [
{
"name": "Book Table"
},
{
"name": "Greeting"
},
{
"name": "None"
},
{
"name": "Who are you intent"
}
],
"entities": [
{
"name": "partySize",
"roles": []
}
],
"composites": [],
"closedLists": [
{
"name": "cafeLocation",
"subLists": [
{
"canonicalForm": "seattle",
"list": [
"seattle",
"seatac",
"SEA",
"seattle tacoma",
"space needle"
]
},
{
"canonicalForm": "redmond",
"list": [
"microsoft",
"east side",
"redmond",
"bellevue"
]
},
{
"canonicalForm": "portland",
"list": [
"portland"
]
}
],
"roles": []
}
],
"regex_entities": [],
"model_features": [],
"regex_features": [],
"utterances": [
{
"text": "book a table",
"intent": "Book Table",
"entities": []
},
{
"text": "can you get me a table",
"intent": "Book Table",
"entities": []
},
{
"text": "book a table for 2 in seattle",
"intent": "Book Table",
"entities": []
},
{
"text": "can you get me a table for tomorrow?",
"intent": "Book Table",
"entities": []
},
{
"text": "please get me a table for 3",
"intent": "Book Table",
"entities": [
{
"entity": "partySize",
"startPos": 26,
"endPos": 26
}
]
},
{
"text": "book a table for 2 in seattle for 3pm",
"intent": "Book Table",
"entities": [
{
"entity": "partySize",
"startPos": 17,
"endPos": 17
}
]
},
{
"text": "reserve a table at 5pm",
"intent": "Book Table",
"entities": []
},
{
"text": "table for 5 guests",
"intent": "Book Table",
"entities": [
{
"entity": "partySize",
"startPos": 10,
"endPos": 10
}
]
},
{
"text": "Hello",
"intent": "Greeting",
"entities": []
},
{
"text": "Hi",
"intent": "Greeting",
"entities": []
},
{
"text": "Hello bot",
"intent": "Greeting",
"entities": []
},
{
"text": "hiya",
"intent": "Greeting",
"entities": []
},
{
"text": "hi bot",
"intent": "Greeting",
"entities": []
},
{
"text": "Who is your ceo?",
"intent": "None",
"entities": []
},
{
"text": "Who are you?",
"intent": "Who are you intent",
"entities": []
},
{
"text": "What is your name?",
"intent": "Who are you intent",
"entities": []
},
{
"text": "how should I address you?",
"intent": "Who are you intent",
"entities": []
},
{
"text": "What's your name?",
"intent": "Who are you intent",
"entities": []
}
],
"patterns": [],
"patternAnyEntities": [],
"prebuiltEntities": [
{
"name": "datetimeV2",
"roles": []
},
{
"name": "number",
"roles": []
}
],
"luis_schema_version": "3.0.0",
"versionId": "0.1",
"name": "cafeLUISModel",
"desc": "",
"culture": "en-us"
}
================================================
FILE: docs-samples/V4/JS/contosocafebot-luis-dialogs/lib/CafeLUISModel.d.ts
================================================
/**
*
* Code generated by LUISGen Assets\LU\models\LUIS\cafeLUISModel.json -ts CafeLUISModel -o Assets\LU\models\LUIS
* Tool github: https://github.com/microsoft/botbuilder-tools
* Changes may cause incorrect behavior and will be lost if the code is
* regenerated.
*
*/
import { DateTimeSpec, IntentData, InstanceData } from 'botbuilder-ai';
export interface _Intents {
Book_Table: IntentData;
Greeting: IntentData;
None: IntentData;
Who_are_you_intent: IntentData;
}
export interface _Instance {
partySize?: InstanceData[];
datetime?: InstanceData[];
number?: InstanceData[];
cafeLocation?: InstanceData[];
}
export interface _Entities {
partySize?: string[];
datetime?: DateTimeSpec[];
number?: number[];
cafeLocation?: string[][];
$instance: _Instance;
}
export interface CafeLUISModel {
text: string;
alteredText?: string;
intents: _Intents;
entities: _Entities;
[propName: string]: any;
}
================================================
FILE: docs-samples/V4/JS/contosocafebot-luis-dialogs/lib/CafeLUISModel.js
================================================
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
;
//# sourceMappingURL=CafeLUISModel.js.map
================================================
FILE: docs-samples/V4/JS/contosocafebot-luis-dialogs/lib/luisbot.d.ts
================================================
export {};
================================================
FILE: docs-samples/V4/JS/contosocafebot-luis-dialogs/lib/luisbot.js
================================================
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
const botbuilder_1 = require("botbuilder");
const botbuilder_dialogs_1 = require("botbuilder-dialogs");
const botbuilder_ai_1 = require("botbuilder-ai");
const restify = require("restify");
const Resolver = require('@microsoft/recognizers-text-data-types-timex-expression').default.resolver;
const Creator = require('@microsoft/recognizers-text-data-types-timex-expression').default.creator;
const TimexProperty = require('@microsoft/recognizers-text-data-types-timex-expression').default.TimexProperty;
// Replace this appId with the ID of the app you create from cafeLUISModel.json
const appId = process.env.LUIS_APP_ID;
// Replace this with your authoring key
const subscriptionKey = process.env.LUIS_SUBSCRIPTION_KEY;
console.log(`process.env.LUIS_APP_ID=${process.env.LUIS_APP_ID}, process.env.LUIS_SUBSCRIPTION_KEY=${process.env.LUIS_SUBSCRIPTION_KEY}`);
// Default is westus
const serviceEndpoint = 'https://westus.api.cognitive.microsoft.com';
const luisRec = new botbuilder_ai_1.LuisRecognizer({
appId: appId,
subscriptionKey: subscriptionKey,
serviceEndpoint: serviceEndpoint
});
// Enum for convenience
// intent names match CafeLUISModel.ts
var Intents;
(function (Intents) {
Intents["Book_Table"] = "Book_Table";
Intents["Greeting"] = "Greeting";
Intents["None"] = "None";
Intents["Who_are_you_intent"] = "Who_are_you_intent";
})(Intents || (Intents = {}));
;
// Create server
let server = restify.createServer();
server.listen(process.env.port || process.env.PORT || 3978, function () {
console.log(`${server.name} listening to ${server.url}`);
});
// Create adapter
const adapter = new botbuilder_1.BotFrameworkAdapter({
appId: process.env.MICROSOFT_APP_ID,
appPassword: process.env.MICROSOFT_APP_PASSWORD
});
const conversationState = new botbuilder_1.ConversationState(new botbuilder_1.MemoryStorage());
adapter.use(conversationState);
// Create empty dialog set
const dialogs = new botbuilder_dialogs_1.DialogSet();
// Listen for incoming requests
server.post('/api/messages', (req, res) => {
// Route received request to adapter for processing
adapter.processActivity(req, res, (context) => __awaiter(this, void 0, void 0, function* () {
const isMessage = context.activity.type === 'message';
// Create dialog context
const state = conversationState.get(context);
const dc = dialogs.createContext(context, state);
if (!isMessage) {
yield context.sendActivity(`[${context.activity.type} event detected]`);
}
// Check to see if anyone replied.
if (!context.responded) {
yield dc.continue();
// if the dialog didn't send a response
if (!context.responded && isMessage) {
yield luisRec.recognize(context).then((res) => __awaiter(this, void 0, void 0, function* () {
var typedresult = res;
let topIntent = botbuilder_ai_1.LuisRecognizer.topIntent(res);
switch (topIntent) {
case Intents.Book_Table: {
yield dc.begin('reserveTable', typedresult);
break;
}
case Intents.Greeting: {
yield context.sendActivity("Hello!");
break;
}
case Intents.Who_are_you_intent: {
yield context.sendActivity("I'm the Contoso Cafe bot.");
break;
}
default: {
yield dc.begin('default', topIntent);
break;
}
}
}), (err) => {
// there was some error
console.log(err);
});
}
}
}));
});
// Add dialogs
dialogs.add('default', [
function (dc, args) {
return __awaiter(this, void 0, void 0, function* () {
const state = conversationState.get(dc.context);
yield dc.context.sendActivity(`Hi! I'm the Contoso Cafe reservation bot. Say something like make a reservation."`);
yield dc.end();
});
}
]);
dialogs.add('textPrompt', new botbuilder_dialogs_1.TextPrompt());
dialogs.add('dateTimePrompt', new botbuilder_dialogs_1.DatetimePrompt());
dialogs.add('reserveTable', [
function (dc, args, next) {
return __awaiter(this, void 0, void 0, function* () {
var typedresult = args;
// Call a helper function to save the entities in the LUIS result
// to dialog state
yield SaveEntities(dc, typedresult);
yield dc.context.sendActivity("Welcome to the reservation service.");
if (dc.activeDialog.state.dateTime) {
yield next();
}
else {
yield dc.prompt('dateTimePrompt', "Please provide a reservation date and time. We're open 4PM-8PM.");
}
});
},
function (dc, result, next) {
return __awaiter(this, void 0, void 0, function* () {
if (!dc.activeDialog.state.dateTime) {
// Save the dateTimePrompt result to dialog state
dc.activeDialog.state.dateTime = result[0].value;
}
// If we don't have party size, ask for it next
if (!dc.activeDialog.state.partySize) {
yield dc.prompt('textPrompt', "How many people are in your party?");
}
else {
yield next();
}
});
},
function (dc, result, next) {
return __awaiter(this, void 0, void 0, function* () {
if (!dc.activeDialog.state.partySize) {
dc.activeDialog.state.partySize = result;
}
// Ask for the reservation name next
yield dc.prompt('textPrompt', "Whose name will this be under?");
});
},
function (dc, result) {
return __awaiter(this, void 0, void 0, function* () {
dc.activeDialog.state.Name = result;
// Save data to conversation state
var state = conversationState.get(dc.context);
// Copy the dialog state to the conversation state
state = dc.activeDialog.state;
// TODO: Add in Location: ${state.cafeLocation}
var msg = `Reservation confirmed. Reservation details:
Date/Time: ${state.dateTime}
Party size: ${state.partySize}
Reservation name: ${state.Name}`;
yield dc.context.sendActivity(msg);
yield dc.end();
});
}
]);
// Helper function that saves any entities found in the LUIS result
// to the dialog state
function SaveEntities(dc, typedresult) {
return __awaiter(this, void 0, void 0, function* () {
// Resolve entities returned from LUIS, and save these to state
if (typedresult.entities) {
let datetime = typedresult.entities.datetime;
if (datetime) {
console.log(`datetime entity found of type ${datetime[0].type}.`);
// Use the first date or time found in the utterance
if (datetime[0].timex) {
var timexValues = datetime[0].timex;
// timexValues is the array of all resolutions of datetime[0]
// a datetime entity detected by LUIS is resolved to timex format.
// 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
if (datetime[0].type === "datetime") {
var resolution = Resolver.evaluate(
// array of timex values to evaluate. There may be more than one: "today at 6" can be 6AM or 6PM.
timexValues,
// Creator.evening constrains this to times between 4pm and 8pm
[Creator.evening]);
if (resolution[0]) {
// toNaturalLanguage takes the current date into account to create a friendly string
dc.activeDialog.state.dateTime = resolution[0].toNaturalLanguage(new Date());
// You can also use resolution.toString() to format the date/time.
}
else {
// time didn't satisfy constraint.
dc.activeDialog.state.dateTime = null;
}
}
else {
console.log(`Type ${datetime[0].type} is not yet supported. Provide both the date and the time.`);
}
}
}
let partysize = typedresult.entities.partySize;
if (partysize) {
console.log(`partysize entity detected: ${partysize}`);
// use first partySize entity that was found in utterance
dc.activeDialog.state.partySize = partysize[0];
}
let cafelocation = typedresult.entities.cafeLocation;
if (cafelocation) {
console.log(`location entity detected: ${cafelocation}`);
// use first cafeLocation entity that was found in utterance
dc.activeDialog.state.cafeLocation = cafelocation[0][0];
}
}
});
}
//# sourceMappingURL=luisbot.js.map
================================================
FILE: docs-samples/V4/JS/contosocafebot-luis-dialogs/package.json
================================================
{
"name": "dialogs-luisbot-ts",
"version": "1.0.0",
"description": "Bot Builder example showing a simple bot that uses dialogs to echo anything you say.",
"main": "./lib/luisbot.js",
"scripts": {
"build-sample": "tsc",
"start": "tsc && node ./lib/luisbot.js"
},
"author": "",
"license": "MIT",
"dependencies": {
"@types/node": "^9.3.0",
"@types/restify": "^5.0.8",
"@microsoft/recognizers-text-data-types-timex-expression": "^1.0.1",
"botbuilder": "^4.0.0-preview1.2",
"botbuilder-ai": "^4.0.0-preview1.2",
"botbuilder-core": "^4.0.0-preview1.2",
"botbuilder-dialogs": "^4.0.0-preview1.2",
"node": "^10.4.0",
"restify": "^6.4.0"
}
}
================================================
FILE: docs-samples/V4/JS/contosocafebot-luis-dialogs/readme.md
================================================
# contosocafebot-luis-dialogs
This sample bot is integrated with a LUIS app that recognizes intents and entities for making a restaurant reservation.
## Intents
Intents represent what the user wants to do. The bot can start a dialog or conversation flow based on the intent recognized by LUIS. This bot recognizes three intents.
|Intent| Example |
|-----|-----|
|Book table | reserve table for 4 at 6:15pm 5/24/2018 reserve a table|
|Greeting| hi Hello|
|Who_are_you| who are you |
## Entities
Besides recognizing intent, a LUIS can also extract entities, which are important words for fulfilling a user's request. For example, in the example of a restaurant reservation, the LUIS app might be able to extract the party size, reservation date or restaurant location from the user's message.
|Entity type| Example |
|-----|-----|
|`PartySize` | reserve table for `4` at 6:15pm 5/24/2018 |
|`datetime`| reserve table for 4 at `6:15pm 5/24/2018`|
## Create the LUIS app
1. Log in to https://www.luis.ai.
2. In the **My apps** tab, click on the **Import new app** button and choose the JSON file **cafeLUISModel.json** for the app to import.
3. [Train](https://docs.microsoft.com/en-us/azure/cognitive-services/LUIS/luis-how-to-train) the new app.
4. [Publish](https://docs.microsoft.com/en-us/azure/cognitive-services/LUIS/publishapp) the new app.
## Copy the LUIS Subscription Key to use in the bot's code
Copy the App ID from **Settings**, and copy the [LUIS Authoring Key](https://docs.microsoft.com/en-us/azure/cognitive-services/LUIS/luis-concept-keys#authoring-key). Paste them into the bot code in luisbot.ts.
```ts
// Replace this appId with the ID of the app you create from cafeLUISModel.json
const appId = "YOUR-LUIS-APP-ID"
// Replace this with your authoring key
const subscriptionKey = "YOUR-LUIS-SUBSCRIPTION-KEY"
```
## Use LUISGen to generate types for the LUIS results
You can use the [LUISGen tool](https://github.com/Microsoft/botbuilder-tools/tree/master/LUISGen) to generate types that make it easier to work with LUIS results in your bot's code. The tool takes a JSON file for an exported LUIS app as input.
At a Node.js command line, install `luisgen` to the global path.
```
npm install -g luisgen
```
In the root folder of this sample, this LUISGen command was used to generate **CafeLUISModel.ts**:
```
luisgen cafeLUISModel.json -ts CafeLUISModel
```
## Building the bot
You'll need the latest TypeScript compiler installed:
```
npm install --global typescript
```
To compile the sample, run `tsc` from the root directory.
Install dependencies before you run the bot, by running `npm install` in the root directory of the sample:
```
npm install
```
## Using typed LUIS results
You can get a `CafeLUISModel` result from the LUIS recognizer in bot code like this:
```typescript
// call LUIS and get typed results
await luisRec.recognize(context).then(async (res : any) =>
{
// get a typed result
var typedresult = res as CafeLUISModel;
}
```
## Pass the LUIS result to a dialog
Examine the code in **luisbot.ts**. In the `processActivity` handler, the bot passes the typed result to the `reserveTable` dialog.
```typescript
// Listen for incoming requests
server.post('/api/messages', (req, res) => {
// Route received request to adapter for processing
adapter.processActivity(req, res, async (context) => {
const isMessage = context.activity.type === 'message';
// Create dialog context
const state = conversationState.get(context);
const dc = dialogs.createContext(context, state);
if (!isMessage) {
await context.sendActivity(`[${context.activity.type} event detected]`);
}
// Check to see if anyone replied.
if (!context.responded) {
await dc.continue();
// if the dialog didn't send a response
if (!context.responded && isMessage) {
await luisRec.recognize(context).then(async (res : any) =>
{
var typedresult = res as CafeLUISModel;
let topIntent = LuisRecognizer.topIntent(res);
switch (topIntent)
{
case Intents.Book_Table: {
await dc.begin('reserveTable', typedresult);
break;
}
case Intents.Greeting: {
await context.sendActivity("Hi!");
break;
}
case Intents.Who_are_you_intent: {
await context.sendActivity("I'm the Contoso Cafe Bot.");
break;
}
default: {
await dc.begin('default', topIntent);
break;
}
}
}, (err) => {
// there was some error
console.log(err);
}
);
}
}
});
});
```
## Check for existing entities in a dialog
In **luisbot.ts**, the `reserveTable` dialog calls a `SaveEntities` helper function to check for entities detected by the LUIS app. If the entities are found, they're saved to dialog state. Each waterfall step in the dialog checks if an entity was saved to dialog state, and if not, prompts for it.
```typescript
dialogs.add('reserveTable', [
async function(dc, args, next){
var typedresult = args as CafeLUISModel;
// Call a helper function to save the entities in the LUIS result
// to dialog state
await SaveEntities(dc, typedresult);
await dc.context.sendActivity("Welcome to the reservation service.");
if (dc.activeDialog.state.dateTime) {
await next();
}
else {
await dc.prompt('dateTimePrompt', "Please provide a reservation date and time.");
}
},
async function(dc, result, next){
if (!dc.activeDialog.state.dateTime) {
// Save the dateTimePrompt result to dialog state
dc.activeDialog.state.dateTime = result[0].value;
}
// If we don't have party size, ask for it next
if (!dc.activeDialog.state.partySize) {
await dc.prompt('textPrompt', "How many people are in your party?");
} else {
await next();
}
},
async function(dc, result, next){
if (!dc.activeDialog.state.partySize) {
dc.activeDialog.state.partySize = result;
}
// Ask for the reservation name next
await dc.prompt('textPrompt', "Whose name will this be under?");
},
async function(dc, result){
dc.activeDialog.state.Name = result;
// Save data to conversation state
var state = conversationState.get(dc.context);
// Copy the dialog state to the conversation state
state = dc.activeDialog.state;
// TODO: Add in Location: ${state.cafeLocation}
var msg = `Reservation confirmed. Reservation details:
Date/Time: ${state.dateTime}
Party size: ${state.partySize}
Reservation name: ${state.Name}`;
await dc.context.sendActivity(msg);
await dc.end();
}
]);
```
The `SaveEntities` helper function checks for `datetime` and `partysize` entities. The `datetime` entity is a [prebuilt entity](https://docs.microsoft.com/en-us/azure/cognitive-services/luis/luis-reference-prebuilt-entities#builtindatetimev2).
```typescript
// Helper function that saves any entities found in the LUIS result
// to the dialog state
async function SaveEntities( dc: DialogContext, typedresult) {
// Resolve entities returned from LUIS, and save these to state
if (typedresult.entities)
{
let datetime = typedresult.entities.datetime;
if (datetime) {
// Use the first date or time found in the utterance
var timexValue;
if (datetime[0].timex) {
timexValue = datetime[0].timex[0];
// 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
if (datetime[0].type === "datetime") {
// in this sample, a datetime detected by LUIS is saved in timex format.
dc.activeDialog.state.dateTime = timexValue;
// If you want to additionally parse timex,
// use @microsoft/recognizers-text-data-types-timex-expression
}
else {
console.log(`Type ${datetime[0].type} is not yet supported. Provide both the date and the time.`);
}
}
}
let partysize = typedresult.entities.partySize;
if (partysize) {
console.log(`partysize entity defined.${partysize}`);
// use first partySize entity that was found in utterance
dc.activeDialog.state.partySize = partysize[0];
}
let cafelocation = typedresult.entities.cafeLocation;
if (cafelocation) {
console.log(`location entity defined.${cafelocation}`);
// use first cafeLocation entity that was found in utterance
dc.activeDialog.state.cafeLocation = cafelocation[0][0];
}
}
}
```
### Entity types
The code in `SaveEntities` checked `CafeLUISModel` type's `entities` property, which was defined in **CafeLUISModel.ts**.
```typescript
export interface CafeLUISModel {
text: string;
alteredText?: string;
intents: _Intents;
entities: _Entities;
[propName: string]: any;
}
```
The `entities` property includes both simple entities, built-in entities, and lists.
```js
export interface _Entities {
// Simple entities
partySize?: string[];
// Built-in entities
datetime?: DateTimeSpec[];
number?: number[];
// Lists
cafeLocation?: string[][];
$instance : _Instance;
}
```
The `datetime` type is an array of `DateTimeSpec`:
```js
// datetime is an array of type
DateTimeSpec {
/**
* Type of expression.
*
* @remarks
* Example types include:
*
* - **time**: simple time expression like "3pm".
* - **date**: simple date like "july 3rd".
* - **datetime**: combination of date and time like "march 23 2pm".
* - **timerange**: a range of time like "2pm to 4pm".
* - **daterange**: a range of dates like "march 23rd to 24th".
* - **datetimerange**: a range of dates and times like "july 3rd 2pm to 5th 4pm".
* - **set**: a recurrence like "every monday".
*/
type: string;
/** Timex expressions. */
timex: string[];
}
```
## Run the sample
1. If you don't have the TypeScript compiler installed, install it using this command:
`npm install --global typescript`
2. Install dependencies before you run the bot, by running `npm install` in the root directory of the sample:
```
npm install
```
3. From the root directory, build the sample using `tsc`. This will generate `luisbot.js`.
4. Run `luisbot.js` in the `lib` directory.
5. Use the [Bot Framework Emulator](https://docs.microsoft.com/en-us/azure/bot-service/bot-service-debug-emulator) to run the sample.
6. In the emulator, say `reserve a table` to start the reservation dialog.

================================================
FILE: docs-samples/V4/JS/contosocafebot-luis-dialogs/src/.vscode/launch.json
================================================
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Launch Program",
"program": "${file}",
"outFiles": [
"${workspaceFolder}/**/*.js"
],
"envFile": "../.env"
}
]
}
================================================
FILE: docs-samples/V4/JS/contosocafebot-luis-dialogs/src/CafeLUISModel.ts
================================================
/**
*
* Code generated by LUISGen Assets\LU\models\LUIS\cafeLUISModel.json -ts CafeLUISModel -o Assets\LU\models\LUIS
* Tool github: https://github.com/microsoft/botbuilder-tools
* Changes may cause incorrect behavior and will be lost if the code is
* regenerated.
*
*/
import {DateTimeSpec, IntentData, InstanceData, NumberWithUnits} from 'botbuilder-ai';
export interface _Intents {
Book_Table: IntentData;
Greeting: IntentData;
None: IntentData;
Who_are_you_intent: IntentData;
};
export interface _Instance {
partySize?: InstanceData[];
datetime?: InstanceData[];
number?: InstanceData[];
cafeLocation?: InstanceData[];
}
export interface _Entities {
// Simple entities
partySize?: string[];
// Built-in entities
datetime?: DateTimeSpec[];
number?: number[];
// Lists
cafeLocation?: string[][];
$instance : _Instance;
}
export interface CafeLUISModel {
text: string;
alteredText?: string;
intents: _Intents;
entities: _Entities;
[propName: string]: any;
}
================================================
FILE: docs-samples/V4/JS/contosocafebot-luis-dialogs/src/luisbot.ts
================================================
import { BotFrameworkAdapter, MemoryStorage, ConversationState, TurnContext, RecognizerResult } from 'botbuilder';
import { DialogSet, TextPrompt, DatetimePrompt, DialogContext } from 'botbuilder-dialogs';
import { LuisRecognizer, InstanceData, IntentData, DateTimeSpec } from 'botbuilder-ai';
import { CafeLUISModel, _Intents, _Entities, _Instance } from './CafeLUISModel';
import * as restify from 'restify';
const Resolver = require('@microsoft/recognizers-text-data-types-timex-expression').default.resolver;
const Creator = require('@microsoft/recognizers-text-data-types-timex-expression').default.creator;
const TimexProperty = require('@microsoft/recognizers-text-data-types-timex-expression').default.TimexProperty;
// Replace this appId with the ID of the app you create from cafeLUISModel.json
const appId = process.env.LUIS_APP_ID;
// Replace this with your authoring key
const subscriptionKey = process.env.LUIS_SUBSCRIPTION_KEY;
console.log(`process.env.LUIS_APP_ID=${process.env.LUIS_APP_ID}, process.env.LUIS_SUBSCRIPTION_KEY=${process.env.LUIS_SUBSCRIPTION_KEY}`);
// Default is westus
const serviceEndpoint = 'https://westus.api.cognitive.microsoft.com';
const luisRec = new LuisRecognizer({
appId: appId,
subscriptionKey: subscriptionKey,
serviceEndpoint: serviceEndpoint
});
// Enum for convenience
// intent names match CafeLUISModel.ts
enum Intents {
Book_Table = "Book_Table",
Greeting = "Greeting",
None = "None",
Who_are_you_intent = "Who_are_you_intent"
};
// Create server
let server = restify.createServer();
server.listen(process.env.port || process.env.PORT || 3978, function () {
console.log(`${server.name} listening to ${server.url}`);
});
// Create adapter
const adapter = new BotFrameworkAdapter( {
appId: process.env.MICROSOFT_APP_ID,
appPassword: process.env.MICROSOFT_APP_PASSWORD
});
// Add conversation state middleware
interface CafeBotConvState {
dialogStack: any[];
cafeLocation: string;
dateTime: string;
partySize: string;
Name: string;
}
const conversationState = new ConversationState(new MemoryStorage());
adapter.use(conversationState);
// Create empty dialog set
const dialogs = new DialogSet();
// Listen for incoming requests
server.post('/api/messages', (req, res) => {
// Route received request to adapter for processing
adapter.processActivity(req, res, async (context) => {
const isMessage = context.activity.type === 'message';
// Create dialog context
const state = conversationState.get(context);
const dc = dialogs.createContext(context, state);
if (!isMessage) {
await context.sendActivity(`[${context.activity.type} event detected]`);
}
// Check to see if anyone replied.
if (!context.responded) {
await dc.continue();
// if the dialog didn't send a response
if (!context.responded && isMessage) {
await luisRec.recognize(context).then(async (res : any) =>
{
var typedresult = res as CafeLUISModel;
let topIntent = LuisRecognizer.topIntent(res);
switch (topIntent)
{
case Intents.Book_Table: {
await dc.begin('reserveTable', typedresult);
break;
}
case Intents.Greeting: {
await context.sendActivity("Hello!");
break;
}
case Intents.Who_are_you_intent: {
await context.sendActivity("I'm the Contoso Cafe bot.");
break;
}
default: {
await dc.begin('default', topIntent);
break;
}
}
}, (err) => {
// there was some error
console.log(err);
}
);
}
}
});
});
// Add dialogs
dialogs.add('default', [
async function (dc, args) {
const state = conversationState.get(dc.context);
await dc.context.sendActivity(`Hi! I'm the Contoso Cafe reservation bot. Say something like make a reservation."`);
await dc.end();
}
]);
dialogs.add('textPrompt', new TextPrompt());
dialogs.add('dateTimePrompt', new DatetimePrompt());
dialogs.add('reserveTable', [
async function(dc, args, next){
var typedresult = args as CafeLUISModel;
// Call a helper function to save the entities in the LUIS result
// to dialog state
await SaveEntities(dc, typedresult);
await dc.context.sendActivity("Welcome to the reservation service.");
if (dc.activeDialog.state.dateTime) {
await next();
}
else {
await dc.prompt('dateTimePrompt', "Please provide a reservation date and time. We're open 4PM-8PM.");
}
},
async function(dc, result, next){
if (!dc.activeDialog.state.dateTime) {
// Save the dateTimePrompt result to dialog state
dc.activeDialog.state.dateTime = result[0].value;
}
// If we don't have party size, ask for it next
if (!dc.activeDialog.state.partySize) {
await dc.prompt('textPrompt', "How many people are in your party?");
} else {
await next();
}
},
async function(dc, result, next){
if (!dc.activeDialog.state.partySize) {
dc.activeDialog.state.partySize = result;
}
// Ask for the reservation name next
await dc.prompt('textPrompt', "Whose name will this be under?");
},
async function(dc, result){
dc.activeDialog.state.Name = result;
// Save data to conversation state
var state = conversationState.get(dc.context);
// Copy the dialog state to the conversation state
state = dc.activeDialog.state;
// TODO: Add in Location: ${state.cafeLocation}
var msg = `Reservation confirmed. Reservation details:
Date/Time: ${state.dateTime}
Party size: ${state.partySize}
Reservation name: ${state.Name}`;
await dc.context.sendActivity(msg);
await dc.end();
}
]);
// Helper function that saves any entities found in the LUIS result
// to the dialog state
async function SaveEntities( dc: DialogContext, typedresult) {
// Resolve entities returned from LUIS, and save these to state
if (typedresult.entities)
{
let datetime = typedresult.entities.datetime;
if (datetime) {
console.log(`datetime entity found of type ${datetime[0].type}.`);
// Use the first date or time found in the utterance
if (datetime[0].timex) {
var timexValues = datetime[0].timex
// timexValues is the array of all resolutions of datetime[0]
// a datetime entity detected by LUIS is resolved to timex format.
// 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
if (datetime[0].type === "datetime") {
var resolution = Resolver.evaluate(
// array of timex values to evaluate. There may be more than one: "today at 6" can be 6AM or 6PM.
timexValues,
// Creator.evening constrains this to times between 4pm and 8pm
[Creator.evening]);
if (resolution[0]) {
// toNaturalLanguage takes the current date into account to create a friendly string
dc.activeDialog.state.dateTime = resolution[0].toNaturalLanguage(new Date());
// You can also use resolution.toString() to format the date/time.
} else {
// time didn't satisfy constraint.
dc.activeDialog.state.dateTime = null;
}
}
else {
console.log(`Type ${datetime[0].type} is not yet supported. Provide both the date and the time.`);
}
}
}
let partysize = typedresult.entities.partySize;
if (partysize) {
console.log(`partysize entity detected: ${partysize}`);
// use first partySize entity that was found in utterance
dc.activeDialog.state.partySize = partysize[0];
}
let cafelocation = typedresult.entities.cafeLocation;
if (cafelocation) {
console.log(`location entity detected: ${cafelocation}`);
// use first cafeLocation entity that was found in utterance
dc.activeDialog.state.cafeLocation = cafelocation[0][0];
}
}
}
================================================
FILE: docs-samples/V4/JS/contosocafebot-luis-dialogs/tsconfig.json
================================================
{
"compilerOptions": {
/* Basic Options */
"target": "ES6", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', or 'ESNEXT'. */
"module": "commonjs", /* Specify module code generation: 'commonjs', 'amd', 'system', 'umd' or 'es2015'. */
// "lib": [], /* Specify library files to be included in the compilation: */
// "allowJs": true, /* Allow javascript files to be compiled. */
// "checkJs": true, /* Report errors in .js files. */
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
"declaration": true, /* Generates corresponding '.d.ts' file. */
"sourceMap": true, /* Generates corresponding '.map' file. */
// "outFile": "./", /* Concatenate and emit output to single file. */
"outDir": "./lib", /* Redirect output structure to the directory. */
"rootDir": "./src", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
// "removeComments": true, /* Do not emit comments to output. */
// "noEmit": true, /* Do not emit outputs. */
// "importHelpers": true, /* Import emit helpers from 'tslib'. */
// "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
// "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
/* Strict Type-Checking Options */
"strict": false, /* Enable all strict type-checking options. */
// "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */
// "strictNullChecks": true, /* Enable strict null checks. */
// "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */
// "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */
/* Additional Checks */
// "noUnusedLocals": true, /* Report errors on unused locals. */
// "noUnusedParameters": true, /* Report errors on unused parameters. */
// "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
// "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
/* Module Resolution Options */
"moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
"baseUrl": "./node_modules", /* Base directory to resolve non-absolute module names. */
// "baseUrl": "./", /* Base directory to resolve non-absolute module names. */
// "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
// "typeRoots": [], /* List of folders to include type definitions from. */
// "types": [], /* Type declaration files to be included in compilation. */
// "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
/* Source Map Options */
// "sourceRoot": "./", /* Specify the location where debugger should locate TypeScript files instead of source locations. */
// "mapRoot": "./", /* Specify the location where debugger should locate map files instead of generated locations. */
// "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */
// "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
/* Experimental Options */
// "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
// "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
}
}
================================================
FILE: docs-samples/v3Node/startNewDialog/botadapter.js
================================================
'user strict';
var builder = require('botbuilder');
function _clone(obj) {
var cpy = {};
if (obj) {
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
cpy[key] = obj[key];
}
}
}
return cpy;
}
function loadSession(address, opts, cb) {
var _consts = {
Data : {
SessionState: 'BotBuilder.Data.SessionState'
}
};
var _this = this;
this.lookupUser(address, (user) => {
_this.ensureConversation(address, function (address) {
var storageCtx = {
userId: user.id,
conversationId: address.conversation ? address.conversation.id : null,
address: address,
persistUserData: _this.settings.persistUserData,
persistConversationData: _this.settings.persistConversationData
};
var loadedData;
_this.getStorageData(storageCtx, function (data) {
if (!_this.localizer) {
var defaultLocale = _this.settings.localizerSettings ? _this.settings.localizerSettings.defaultLocale : null;
_this.localizer = new DefaultLocalizer_1.DefaultLocalizer(_this.lib, defaultLocale);
}
var session = new builder.Session({
localizer: _this.localizer,
autoBatchDelay: _this.settings.autoBatchDelay,
library: _this.lib,
actions: _this.actions,
middleware: _this.mwSession,
dialogId: opts.dialogId,
dialogArgs: opts.dialogArgs,
dialogErrorMessage: _this.settings.dialogErrorMessage,
onSave: function (cb) {
var finish = _this.errorLogger(cb);
loadedData.userData = _clone(session.userData);
loadedData.conversationData = _clone(session.conversationData);
loadedData.privateConversationData = _clone(session.privateConversationData);
loadedData.privateConversationData[_consts.Data.SessionState] = session.sessionState;
_this.saveStorageData(storageCtx, loadedData, finish, finish);
},
onSend: function (messages, cb) {
_this.send(messages, cb);
}
});
session.on('error', function (err) { return _this.emitError(err); });
var sessionState;
session.userData = data.userData || {};
session.conversationData = data.conversationData || {};
session.privateConversationData = data.privateConversationData || {};
if (session.privateConversationData.hasOwnProperty(_consts.Data.SessionState)) {
sessionState = session.privateConversationData[_consts.Data.SessionState];
delete session.privateConversationData[_consts.Data.SessionState];
}
// Do the important things route/dispatch would have done
session.sessionState = sessionState;
var cur = session.curDialog();
session.dialogData = cur ? cur.state : {};
session.message = {address : address};
loadedData = data;
cb(null, session);
}, (err) => { _this.errorLogger(err); cb(err); })
}, (err) => { _this.errorLogger(err); cb(err); })
}, (err) => { _this.errorLogger(err); cb(err); })
}
function beginDialog(address, dialogId, dialogArgs, opts, done) {
if (typeof opts === 'function') {
done = opts;
opts = {};
}
if (opts.resume) {
this.loadSession(address, { dialogId:dialogId, dialogArgs:dialogArgs },
(err, session) => {
if (!err) {
session.beginDialog(dialogId, dialogArgs);
if (done) {
done(null);
}
}
else {
if (done) {
done(err);
}
}
});
}
else {
this.beginDialog(address, dialogId, dialogArgs, done);
}
}
function patch(bot) {
bot.beginDialog = beginDialog;
bot.loadSession = loadSession;
return bot;
}
exports.patch = patch;
================================================
FILE: docs-samples/web-chat-speech/index.html
================================================
Bot Chat
Web Chat with speech
This sample shows the various options for enabling speech recognition and speech synthesis in the Web Chat