-
Notifications
You must be signed in to change notification settings - Fork 4.9k
/
index.js
150 lines (127 loc) · 6.14 KB
/
index.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
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
const dotenv = require('dotenv');
const path = require('path');
const restify = require('restify');
const { ResourceExplorer } = require('botbuilder-dialogs-declarative');
const { TemplateEngineLanguageGenerator, ActivityTemplate, AdaptiveDialog, AdaptiveDialogComponentRegistration, LanguageGeneratorMiddleWare, ChoiceInput, SendActivity, SwitchCondition, RepeatDialog, OnBeginDialog } = require('botbuilder-dialogs-adaptive');
const { DialogManager, ListStyle } = require('botbuilder-dialogs');
const { MemoryStorage, UserState, ConversationState } = require('botbuilder');
const { Case } = require('botbuilder-dialogs-adaptive/lib/actions/case');
const { StringExpression, ArrayExpression, BoolExpression, EnumExpression } = require('adaptive-expressions');
// Import required bot services.
// See https://aka.ms/bot-services to learn more about the different parts of a bot.
const { BotFrameworkAdapter } = require('botbuilder');
// Import required bot configuration.
const ENV_FILE = path.join(__dirname, '.env');
dotenv.config({ path: ENV_FILE });
// Set up resource explorer
const resourceExplorer = new ResourceExplorer().addFolder(path.join(__dirname, './dialogs'), true, true);
resourceExplorer.addComponent(new AdaptiveDialogComponentRegistration(resourceExplorer));
// Create HTTP server
const server = restify.createServer();
server.listen(process.env.port || process.env.PORT || 3978, () => {
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 the emulator select "Open Bot"');
});
// Create adapter.
// See https://aka.ms/about-bot-adapter to learn more about how bots work.
const adapter = new BotFrameworkAdapter({
appId: process.env.MicrosoftAppId,
appPassword: process.env.MicrosoftAppPassword
});
// Catch-all for errors.
const onTurnErrorHandler = async (context, error) => {
// This check writes out errors to console log .vs. app insights.
// NOTE: In production environment, you should consider logging this to Azure
// application insights.
console.error(`\n [onTurnError] unhandled error: ${ error }`);
// Send a trace activity, which will be displayed in Bot Framework Emulator
await context.sendTraceActivity(
'OnTurnError Trace',
`${ error }`,
'https://www.botframework.com/schemas/error',
'TurnError'
);
// Send a message to the user
await context.sendActivity('The bot encountered an error or bug.');
await context.sendActivity('To continue to run this bot, please fix the bot source code.');
};
// Set the onTurnError for the singleton BotFrameworkAdapter.
adapter.onTurnError = onTurnErrorHandler;
adapter.use(new LanguageGeneratorMiddleWare(resourceExplorer));
// Define the state store for your bot.
// See https://aka.ms/about-bot-state to learn more about using MemoryStorage.
// A bot requires a state storage system to persist the dialog and user state between messages.
const memoryStorage = new MemoryStorage();
// Create conversation state with in-memory storage provider.
const conversationState = new ConversationState(memoryStorage);
const userState = new UserState(memoryStorage);
let myBot;
function createChoiceInputForAllAdaptiveDialogs() {
const rootDialog = new AdaptiveDialog(AdaptiveDialog.name);
const choices = [];
const switchCases = [];
(resourceExplorer.getResources('.dialog') || []).forEach(resource => {
if (resource.resourceId !== undefined && resource.resourceId.endsWith('.main.dialog')) {
let dialogName = path.basename(resource.resourceId, '.main.dialog');
const subDialog = resourceExplorer.loadType(resource);
choices.push({value : dialogName});
switchCases.push(new Case(dialogName, [subDialog]));
}
});
rootDialog.generator = new TemplateEngineLanguageGenerator();
rootDialog.triggers.push(new OnBeginDialog([
new ChoiceInput().configure({
property: new StringExpression('turn.userChoice'),
prompt: new ActivityTemplate(`Choose a declarative sample to run..`),
style: new EnumExpression(ListStyle.list),
choices: new ArrayExpression(choices),
alwaysPrompt: new BoolExpression(true)
}),
new SendActivity("# Running ${turn.userChoice}.main.dialog"),
new SwitchCondition('turn.userChoice', switchCases),
new RepeatDialog()
]));
return rootDialog;
}
function loadRootDialog() {
// Load root dialog
myBot = new DialogManager();
myBot.userState = userState;
myBot.conversationState = conversationState;
myBot.rootDialog = createChoiceInputForAllAdaptiveDialogs();
}
loadRootDialog();
// Listen for incoming requests.
server.post('/api/messages', (req, res) => {
adapter.processActivity(req, res, async (context) => {
// Route to main dialog.
await myBot.onTurn(context);
});
});
// Listen for Upgrade requests for Streaming.
server.on('upgrade', (req, socket, head) => {
// Create an adapter scoped to this WebSocket connection to allow storing session data.
const streamingAdapter = new BotFrameworkAdapter({
appId: process.env.MicrosoftAppId,
appPassword: process.env.MicrosoftAppPassword
});
// Set onTurnError for the BotFrameworkAdapter created for each connection.
streamingAdapter.onTurnError = onTurnErrorHandler;
streamingAdapter.useWebSocket(req, socket, head, async (context) => {
// After connecting via WebSocket, run this logic for every request sent over
// the WebSocket connection.
await myBot.onTurn(context);
});
});
const handleResourceChange = (resources) => {
if (Array.isArray(resources)) {
if((resources || []).find(r => r.resourceId.endsWith('.dialog')) !== undefined) loadRootDialog();
} else {
if (resources.resourceId && resources.resourceId.endsWith('.dialog')) loadRootDialog()
}
};
// Add a resource change handler to resource explorer.
resourceExplorer.emitter.on('changed', handleResourceChange);