-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.ts
349 lines (312 loc) · 8.56 KB
/
index.ts
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
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
import { Directive, IntentRequest } from "ask-sdk-model";
import {
AgentBuilder,
CompoundBlock,
CompoundBlockBuilder,
DoBlock,
DoBlockBuilder,
GotoStateBlock,
GotoStateBlockBuilder,
RemoveGlobalStateBlockBuilder,
SetGlobalStateBlockBuilder,
StateBuilder,
WhenBlock,
WhenBlockBuilder,
} from "@chitchatjs/core";
import { AlexaDialogManager } from "../";
import { RuleBasedDialogEngine } from "../engine";
import {
AlexaBuilderContext,
AlexaDialogContext,
AlexaEvent,
AlexaBlock,
INITIAL_STATE_NAME,
Locale,
Skill,
Slot,
SSMLSpeechBlock,
} from "../models";
import { intent_utils } from "../util/IntentUtils";
import { AskSpeechBlockBuilder } from "./builders/AskSpeechBlockBuilder";
import { CustomBlockBuilder } from "./builders/CustomBlockBuilder";
import { DirectiveBlockBuilder } from "./builders/DirectiveBlockBuilder";
import { EmptyBlockBuilder } from "./builders/EndBlockBuilder";
import { IntentBlockBuilder } from "./builders/IntentBlockBuilder";
import { LocalizedBlockBuilder } from "./builders/LocalizedBlockBuilder";
import { SkillInfoBlockBuilder } from "./builders/SkillInfoBlockBuilder";
import { SlotTypeBlockBuilder } from "./builders/SlotTypeBlockBuilder";
import { SSMLSpeechBlockBuilder } from "./builders/SSMLSpeechBlockBuilder";
import { TellSpeechBlockBuilder } from "./builders/TellSpeechBlockBuilder";
import { WhenSlotNotFilledBlockBuilder } from "./builders/WhenSlotNotFilledBlockBuilder";
import { WhenUserSaysBlockBuilder } from "./builders/WhenUserSaysBuilder";
/**
* A collection of core Alexa building blocks
* that allows skill builders generate artifacts as well as
* handle runtime requests.
*/
export namespace alexa {
/**
* Instantiates AlexaDialogManager with RuleBasedDialogEngine.
*
* Usage:
* ax.dialogManager(<skill>)
* ax.dialogManager(<skill>).exports()
*
* @param s Skill
*/
export function dialogManager(s: Skill) {
return new AlexaDialogManager(s, new RuleBasedDialogEngine());
}
/**
* A building block to build an Alexa Skill.
*
* Usage:
* ax.skill().addState(..).build()
*/
export function skill() {
return new AgentBuilder<AlexaBuilderContext, AlexaDialogContext, AlexaEvent>();
}
/**
* The initial/root state of the skill.
*
* Usage:
* ax
* .start()
* .block(ax.say("hello!"))
* .build()
*/
export function start() {
return alexa.state(INITIAL_STATE_NAME);
}
/**
* Builds a new state with a specified name.
*
* Usage:
* ax
* .state("WelcomeUser")
* .block(..)
* .build()
*
* @param name State name
*/
export function state(name: string) {
return new StateBuilder<AlexaBuilderContext, AlexaDialogContext, AlexaEvent>(name);
}
/**
* Localizes the associated block.
*
* Usage:
* ax
* .localize([Locale.en_US])
* .block(..)
* .build()
*
* @param locales Locale[]
*/
export function localize(locales: Locale[]) {
return new LocalizedBlockBuilder(locales);
}
export function compound() {
return new CompoundBlockBuilder<
AlexaBuilderContext,
AlexaDialogContext,
AlexaEvent
>();
}
export function when() {
return new WhenBlockBuilder<AlexaBuilderContext, AlexaDialogContext, AlexaEvent>();
}
export function whenLaunch() {
return new WhenBlockBuilder<
AlexaBuilderContext,
AlexaDialogContext,
AlexaEvent
>().true((c: AlexaDialogContext, e: AlexaEvent) => {
return e.currentRequest.request.type === "LaunchRequest";
});
}
export function whenUserSays(sampleUtterances: string[]) {
return new WhenUserSaysBlockBuilder().userSays(sampleUtterances);
}
export function whenIntentName(intentName: string) {
return alexa.when().true((c: AlexaDialogContext, e: AlexaEvent) => {
let isIntentRequest = false;
if (e.currentRequest.request.type === "IntentRequest") {
const req: IntentRequest = e.currentRequest.request;
if ((isIntentRequest = req.intent.name === intentName)) {
// update state to capture slots
const _state = c.platformState.globalState;
const flattenSlots = intent_utils.flattenSlotValues(req);
c.platformState.globalState = Object.assign(_state, flattenSlots);
return true;
}
}
return false;
});
}
export function setStateVar(
f:
| string
| ((
ctx: AlexaDialogContext,
event: AlexaEvent
) => Promise<{ [name: string]: any }> | { [name: string]: any }),
value?: any
) {
let func: (
ctx: AlexaDialogContext,
event: AlexaEvent
) => Promise<{ [name: string]: any }> | { [name: string]: any };
if (typeof f === "string") {
func = () => {
return { [f]: value };
};
} else {
// tslint:disable-next-line:no-angle-bracket-type-assertion
func = <typeof func>f;
}
return new SetGlobalStateBlockBuilder<
AlexaBuilderContext,
AlexaDialogContext,
AlexaEvent
>()
.set(func)
.build();
}
export function removeStateVar(
f:
| string
| string[]
| ((ctx: AlexaDialogContext, event: AlexaEvent) => Promise<string[]> | string[])
) {
let func: (
ctx: AlexaDialogContext,
event: AlexaEvent
) => Promise<string[]> | string[];
if (typeof f === "string") {
const varName = f;
func = () => {
return [varName];
};
} else if (Array.isArray(f)) {
const varNames = f;
func = () => {
return varNames;
};
} else {
// tslint:disable-next-line:no-angle-bracket-type-assertion
func = <typeof func>f;
}
return new RemoveGlobalStateBlockBuilder<
AlexaBuilderContext,
AlexaDialogContext,
AlexaEvent
>()
.remove(func)
.build();
}
export function goto(stateName: string) {
return new GotoStateBlockBuilder<
AlexaBuilderContext,
AlexaDialogContext,
AlexaEvent
>()
.stateName(stateName)
.build();
}
export function ask(msg: string | SSMLSpeechBlock) {
return new AskSpeechBlockBuilder().say(msg);
}
export function say(msg: string | SSMLSpeechBlock) {
return new TellSpeechBlockBuilder(msg).build();
}
export function empty() {
return new EmptyBlockBuilder().build();
}
export function end() {
return alexa
.when()
.true((ctx: AlexaDialogContext, event: AlexaEvent) => {
return event.currentRequest.request.type === "SessionEndedRequest";
})
.then(empty())
.build();
}
export function info() {
return new SkillInfoBlockBuilder();
}
/**
* Custom block allows your to manually generate artifacts or response.
*/
export function custom() {
return new CustomBlockBuilder();
}
/**
* Run block allows you to dynamically return a block to execute or build.
*
* Usage:
* ax
* .run()
* .builder(<builder to run>)
* .executor(<executor to run>)
* .build()
*/
export function run() {
return new DoBlockBuilder<AlexaBuilderContext, AlexaDialogContext, AlexaEvent>();
}
export function slotType(typeName?: string) {
return new SlotTypeBlockBuilder(typeName);
}
export function intent(name: string, samples?: string[], slots?: Slot[]) {
return new IntentBlockBuilder(name, samples, slots);
}
/**
* Use this block when you're expecting an intent request
* and want to check if slot value is present.
* You can then wire the .then() to a prompt.
* And optionally use .otherwise().
*
* @param slotName Slot name
*/
export function whenMissingSlot(slotName: string) {
return new WhenSlotNotFilledBlockBuilder(slotName);
}
/**
* Builds a SSML speech.
*
* @param speech text to speak or SSMLSpeechBlock
*/
export function ssml(speech: string | SSMLSpeechBlock) {
return new SSMLSpeechBlockBuilder(speech);
}
/**
* Adds the specified directive to the response.
* @param _directive Directive
*/
export function directive(_directive: Directive) {
return new DirectiveBlockBuilder(_directive).build();
}
}
/**
* A short hand of alexa
*/
export const ax = alexa;
/**
* Helper type aliases
*/
export type AlexaCompoundBlock = CompoundBlock<
AlexaBuilderContext,
AlexaDialogContext,
AlexaEvent
>;
export type AlexaWhenBlock = WhenBlock<
AlexaBuilderContext,
AlexaDialogContext,
AlexaEvent
>;
export type AlexaGotoStateBlock = GotoStateBlock<
AlexaBuilderContext,
AlexaDialogContext,
AlexaEvent
>;
export type AlexaDoBlock = DoBlock<AlexaBuilderContext, AlexaDialogContext, AlexaEvent>;