forked from microsoft/BotBuilder-Samples
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbot.js
179 lines (155 loc) · 7.41 KB
/
bot.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
const { ActivityTypes } = require('botbuilder');
const { ChoicePrompt, DialogSet, NumberPrompt, TextPrompt, WaterfallDialog } = require('botbuilder-dialogs');
const DIALOG_STATE_PROPERTY = 'dialogState';
const USER_PROFILE_PROPERTY = 'user';
const WHO_ARE_YOU = 'who_are_you';
const HELLO_USER = 'hello_user';
const NAME_PROMPT = 'name_prompt';
const CONFIRM_PROMPT = 'confirm_prompt';
const AGE_PROMPT = 'age_prompt';
class MultiTurnBot {
/**
*
* @param {ConversationState} conversationState A ConversationState object used to store the dialog state.
* @param {UserState} userState A UserState object used to store values specific to the user.
*/
constructor(conversationState, userState) {
// Create a new state accessor property. See https://aka.ms/about-bot-state-accessors to learn more about bot state and state accessors.
this.conversationState = conversationState;
this.userState = userState;
this.dialogState = this.conversationState.createProperty(DIALOG_STATE_PROPERTY);
this.userProfile = this.userState.createProperty(USER_PROFILE_PROPERTY);
this.dialogs = new DialogSet(this.dialogState);
// Add prompts that will be used by the main dialogs.
this.dialogs.add(new TextPrompt(NAME_PROMPT));
this.dialogs.add(new ChoicePrompt(CONFIRM_PROMPT));
this.dialogs.add(new NumberPrompt(AGE_PROMPT, async (prompt) => {
if (prompt.recognized.succeeded) {
if (prompt.recognized.value <= 0) {
await prompt.context.sendActivity(`Your age can't be less than zero.`);
return false;
} else {
return true;
}
}
return false;
}));
// Create a dialog that asks the user for their name.
this.dialogs.add(new WaterfallDialog(WHO_ARE_YOU, [
this.promptForName.bind(this),
this.confirmAgePrompt.bind(this),
this.promptForAge.bind(this),
this.captureAge.bind(this)
]));
// Create a dialog that displays a user name after it has been collected.
this.dialogs.add(new WaterfallDialog(HELLO_USER, [
this.displayProfile.bind(this)
]));
}
// This step in the dialog prompts the user for their name.
async promptForName(step) {
return await step.prompt(NAME_PROMPT, `What is your name, human?`);
}
// This step captures the user's name, then prompts whether or not to collect an age.
async confirmAgePrompt(step) {
const user = await this.userProfile.get(step.context, {});
user.name = step.result;
await this.userProfile.set(step.context, user);
await step.prompt(CONFIRM_PROMPT, 'Do you want to give your age?', ['yes', 'no']);
}
// This step checks the user's response - if yes, the bot will proceed to prompt for age.
// Otherwise, the bot will skip the age step.
async promptForAge(step) {
if (step.result && step.result.value === 'yes') {
return await step.prompt(AGE_PROMPT, `What is your age?`,
{
retryPrompt: 'Sorry, please specify your age as a positive number or say cancel.'
}
);
} else {
return await step.next(-1);
}
}
// This step captures the user's age.
async captureAge(step) {
const user = await this.userProfile.get(step.context, {});
if (step.result !== -1) {
user.age = step.result;
await this.userProfile.set(step.context, user);
await step.context.sendActivity(`I will remember that you are ${ step.result } years old.`);
} else {
await step.context.sendActivity(`No age given.`);
}
return await step.endDialog();
}
// This step displays the captured information back to the user.
async displayProfile(step) {
const user = await this.userProfile.get(step.context, {});
if (user.age) {
await step.context.sendActivity(`Your name is ${ user.name } and you are ${ user.age } years old.`);
} else {
await step.context.sendActivity(`Your name is ${ user.name } and you did not share your age.`);
}
return await step.endDialog();
}
/**
*
* @param {TurnContext} turnContext A TurnContext object that will be interpreted and acted upon by the bot.
*/
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) {
// Create a dialog context object.
const dc = await this.dialogs.createContext(turnContext);
const utterance = (turnContext.activity.text || '').trim().toLowerCase();
if (utterance === 'cancel') {
if (dc.activeDialog) {
await dc.cancelAllDialogs();
await dc.context.sendActivity(`Ok... canceled.`);
} else {
await dc.context.sendActivity(`Nothing to cancel.`);
}
}
// If the bot has not yet responded, continue processing the current dialog.
await dc.continueDialog();
// Start the sample dialog in response to any other input.
if (!turnContext.responded) {
const user = await this.userProfile.get(dc.context, {});
if (user.name) {
await dc.beginDialog(HELLO_USER);
} else {
await dc.beginDialog(WHO_ARE_YOU);
}
}
} else if (
turnContext.activity.type === ActivityTypes.ConversationUpdate
) {
// Do we have any new members added to the conversation?
if (turnContext.activity.membersAdded.length !== 0) {
// Iterate over all new members added to the conversation
for (var idx in turnContext.activity.membersAdded) {
// Greet anyone that was not the target (recipient) of this message.
// Since the bot is the recipient for events from the channel,
// context.activity.membersAdded === context.activity.recipient.Id indicates the
// bot was added to the conversation, and the opposite indicates this is a user.
if (turnContext.activity.membersAdded[idx].id !== turnContext.activity.recipient.id) {
// Send a "this is what the bot does" message.
const description = [
'I am a bot that demonstrates the TextPrompt and NumberPrompt classes',
'to collect your name and age, then store those values in UserState for later use.',
'Say anything to continue.'
];
await turnContext.sendActivity(description.join(' '));
}
}
}
}
// Save changes to the user state.
await this.userState.saveChanges(turnContext);
// End this turn by saving changes to the conversation state.
await this.conversationState.saveChanges(turnContext);
}
}
module.exports.MultiTurnBot = MultiTurnBot;