@onereach/step-voice 5.0.5 → 5.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dst/Custom Voice Input.js +1 -1
- package/dst/Global Command.js +15 -6
- package/dst/Initiate Call.d.ts +2 -0
- package/dst/Initiate Call.js +34 -41
- package/dst/Transfer.d.ts +2 -4
- package/dst/Transfer.js +2 -2
- package/dst/step.d.ts +2 -2
- package/dst/step.js +24 -23
- package/dst/voice.d.ts +9 -7
- package/dst/voice.js +15 -3
- package/package.json +9 -7
|
@@ -53,7 +53,7 @@ const alterRecognitionPhrases = (phrases, interpretation) => {
|
|
|
53
53
|
class CustomVoiceInput extends voice_1.default {
|
|
54
54
|
async runStep() {
|
|
55
55
|
const call = await this.fetchData();
|
|
56
|
-
const { textType,
|
|
56
|
+
const { textType, tts, sensitiveData, noReplyDelay, usePromptsTriggers, recognitionModel } = this.data;
|
|
57
57
|
const exitExists = (exitId) => {
|
|
58
58
|
return lodash_1.default.some(choices, (choice) => choice.exitId === exitId);
|
|
59
59
|
};
|
package/dst/Global Command.js
CHANGED
|
@@ -7,21 +7,26 @@ const nanoid_1 = require("nanoid");
|
|
|
7
7
|
const voice_1 = tslib_1.__importDefault(require("./voice"));
|
|
8
8
|
class GlobalCommand extends voice_1.default {
|
|
9
9
|
get isGlobal() {
|
|
10
|
-
return this.thread.id ===
|
|
10
|
+
return this.thread.id === this.globalThreadId;
|
|
11
11
|
}
|
|
12
12
|
get useQueue() {
|
|
13
13
|
return this.isGlobal;
|
|
14
14
|
}
|
|
15
15
|
async runStep() {
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
id: gcThreadId,
|
|
19
|
-
state: {
|
|
16
|
+
const globThread = this.process.newThread(this.globalThreadId, thread => {
|
|
17
|
+
thread.state = {
|
|
20
18
|
name: 'globThread',
|
|
21
19
|
step: this.step.id,
|
|
22
20
|
thread: this.dataThreadId
|
|
23
|
-
}
|
|
21
|
+
};
|
|
24
22
|
});
|
|
23
|
+
if (globThread.isNewThread) {
|
|
24
|
+
globThread.activate();
|
|
25
|
+
await globThread.run();
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
globThread.state.step = this.step.id;
|
|
29
|
+
}
|
|
25
30
|
// refresh cache after global thread was started
|
|
26
31
|
this._clearCache();
|
|
27
32
|
await this.initGrammar();
|
|
@@ -71,6 +76,10 @@ class GlobalCommand extends voice_1.default {
|
|
|
71
76
|
}
|
|
72
77
|
this.end();
|
|
73
78
|
});
|
|
79
|
+
// TODO remove this hack that prevents this.triggers.once execution below
|
|
80
|
+
// currently it skips logic to override triggers (is there better way to do it?)
|
|
81
|
+
if (this.event.name.startsWith('@end'))
|
|
82
|
+
return;
|
|
74
83
|
}
|
|
75
84
|
this.triggers.once(`in/voice/${call.id}/event`, async (event) => {
|
|
76
85
|
event.processed = undefined;
|
package/dst/Initiate Call.d.ts
CHANGED
package/dst/Initiate Call.js
CHANGED
|
@@ -47,7 +47,7 @@ class InitiateCall extends voice_1.default {
|
|
|
47
47
|
this.exitStep('cancel');
|
|
48
48
|
}
|
|
49
49
|
async waitForCall() {
|
|
50
|
-
const { asr, tts, from: botNumber, endUserNumber, sipHost, sipUser, sipPassword, timeout, headers, enableSpoofCallerId, spoofCallerId, isAMD } = this.data;
|
|
50
|
+
const { asr, tts, from: botNumber, endUserNumber, sipHost, sipUser, sipPassword, timeout, headers, enableSpoofCallerId, spoofCallerId, isAMD, otherCallRef, otherCallRefThread } = this.data;
|
|
51
51
|
const call = await this.fetchData();
|
|
52
52
|
this.triggers.once(`in/voice/${call.id}/event`, async (event) => {
|
|
53
53
|
switch (event.params.type) {
|
|
@@ -140,55 +140,48 @@ class InitiateCall extends voice_1.default {
|
|
|
140
140
|
memo[header.name] = `${header.value}`;
|
|
141
141
|
return memo;
|
|
142
142
|
}, {});
|
|
143
|
-
|
|
143
|
+
const params = {
|
|
144
|
+
id: call.id,
|
|
145
|
+
from: botNumber,
|
|
146
|
+
to: endUserNumber,
|
|
147
|
+
headers: customHeaders,
|
|
148
|
+
spoofCallerId: {
|
|
149
|
+
enableSpoofCallerId,
|
|
150
|
+
spoofCallerId
|
|
151
|
+
},
|
|
152
|
+
gateway: sipHost
|
|
153
|
+
? {
|
|
154
|
+
host: sipHost,
|
|
155
|
+
username: sipUser,
|
|
156
|
+
password: sipPassword
|
|
157
|
+
}
|
|
158
|
+
: undefined,
|
|
159
|
+
timeout: originateTimeout,
|
|
160
|
+
version: 2,
|
|
161
|
+
sessionExpireTime: this.session.expireTime
|
|
162
|
+
};
|
|
163
|
+
if (otherCallRef) {
|
|
164
|
+
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
|
|
165
|
+
const otherThread = this.process.getSafeThread(otherCallRefThread || this.thread.id);
|
|
166
|
+
const otherCall = await otherThread.get(otherCallRef);
|
|
167
|
+
if (otherCall == null)
|
|
168
|
+
throw new Error(`otherCall not found: ${otherCallRef}`);
|
|
169
|
+
await this.sendCommands(otherCall, [
|
|
170
|
+
{ name: 'originate', params }
|
|
171
|
+
]);
|
|
172
|
+
}
|
|
173
|
+
else if (endUserNumber.startsWith('user:')) {
|
|
144
174
|
await this.thread.emitAsync({
|
|
145
175
|
target: 'provider',
|
|
146
176
|
name: 'out/voice/originate',
|
|
147
|
-
params
|
|
148
|
-
id: call.id,
|
|
149
|
-
from: botNumber,
|
|
150
|
-
to: endUserNumber,
|
|
151
|
-
headers: customHeaders,
|
|
152
|
-
spoofCallerId: {
|
|
153
|
-
enableSpoofCallerId,
|
|
154
|
-
spoofCallerId
|
|
155
|
-
},
|
|
156
|
-
gateway: sipHost
|
|
157
|
-
? {
|
|
158
|
-
host: sipHost,
|
|
159
|
-
username: sipUser,
|
|
160
|
-
password: sipPassword
|
|
161
|
-
}
|
|
162
|
-
: undefined,
|
|
163
|
-
timeout: originateTimeout,
|
|
164
|
-
version: 2
|
|
165
|
-
}
|
|
177
|
+
params
|
|
166
178
|
});
|
|
167
179
|
}
|
|
168
180
|
else {
|
|
169
181
|
await this.thread.emitAsync({
|
|
170
182
|
target: 'provider',
|
|
171
183
|
name: 'out/voice/originate/v2',
|
|
172
|
-
params
|
|
173
|
-
id: call.id,
|
|
174
|
-
from: botNumber,
|
|
175
|
-
to: endUserNumber,
|
|
176
|
-
headers: customHeaders,
|
|
177
|
-
spoofCallerId: {
|
|
178
|
-
enableSpoofCallerId,
|
|
179
|
-
spoofCallerId
|
|
180
|
-
},
|
|
181
|
-
gateway: sipHost
|
|
182
|
-
? {
|
|
183
|
-
host: sipHost,
|
|
184
|
-
username: sipUser,
|
|
185
|
-
password: sipPassword
|
|
186
|
-
}
|
|
187
|
-
: undefined,
|
|
188
|
-
timeout: originateTimeout,
|
|
189
|
-
version: 2,
|
|
190
|
-
sessionExpireTime: this.session.expireTime
|
|
191
|
-
}
|
|
184
|
+
params
|
|
192
185
|
});
|
|
193
186
|
}
|
|
194
187
|
});
|
package/dst/Transfer.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import VoiceStep, {
|
|
1
|
+
import VoiceStep, { VoiceEvent } from './voice';
|
|
2
2
|
interface INPUT {
|
|
3
3
|
destination: string;
|
|
4
4
|
phoneNumber: string;
|
|
@@ -14,9 +14,7 @@ interface INPUT {
|
|
|
14
14
|
sipUser?: string;
|
|
15
15
|
sipPassword?: string;
|
|
16
16
|
}
|
|
17
|
-
interface EVENT {
|
|
18
|
-
type: EventType;
|
|
19
|
-
error?: string | Error;
|
|
17
|
+
interface EVENT extends VoiceEvent {
|
|
20
18
|
originateDisposition?: string;
|
|
21
19
|
}
|
|
22
20
|
export default class Transfer extends VoiceStep<INPUT, {}, EVENT> {
|
package/dst/Transfer.js
CHANGED
|
@@ -23,8 +23,8 @@ class Transfer extends voice_1.default {
|
|
|
23
23
|
}
|
|
24
24
|
case 'bridge/ended': {
|
|
25
25
|
const { error, originateDisposition } = event.params;
|
|
26
|
-
const isSuccess = error === 'NORMAL_CLEARING'
|
|
27
|
-
|
|
26
|
+
const isSuccess = error === 'NORMAL_CLEARING' &&
|
|
27
|
+
(lodash_1.default.isUndefined(originateDisposition) || originateDisposition === 'SUCCESS');
|
|
28
28
|
if (isSuccess) {
|
|
29
29
|
await this.transcript(call, {
|
|
30
30
|
action: 'Transfer Ended - Answered',
|
package/dst/step.d.ts
CHANGED
|
@@ -16,7 +16,8 @@ export default class ConvStep<TData = unknown, TIn = unknown, TOut = unknown, TP
|
|
|
16
16
|
private convDataCache?;
|
|
17
17
|
get cache(): TData & IConversationData | undefined;
|
|
18
18
|
get conversation(): string | IMergeField;
|
|
19
|
-
get
|
|
19
|
+
get conversationId(): string;
|
|
20
|
+
get globalThreadId(): string;
|
|
20
21
|
/** id of the thread where conversation data is stored */
|
|
21
22
|
get dataThreadId(): IThreadId;
|
|
22
23
|
get isGlobal(): boolean;
|
|
@@ -28,7 +29,6 @@ export default class ConvStep<TData = unknown, TIn = unknown, TOut = unknown, TP
|
|
|
28
29
|
runBefore(): Promise<void>;
|
|
29
30
|
runAfter(): Promise<void>;
|
|
30
31
|
hasActiveGlobal(): Promise<boolean>;
|
|
31
|
-
setLocalTriggers(): Promise<void>;
|
|
32
32
|
waitForConversation(): Promise<void>;
|
|
33
33
|
protected onSkipEvent(): Promise<void>;
|
|
34
34
|
cancel(): Promise<void>;
|
package/dst/step.js
CHANGED
|
@@ -12,7 +12,7 @@ class ConvStep extends step_1.default {
|
|
|
12
12
|
throw new Error('missing data.conversation');
|
|
13
13
|
return this.data.conversation;
|
|
14
14
|
}
|
|
15
|
-
get
|
|
15
|
+
get conversationId() {
|
|
16
16
|
const convOrName = this.conversation;
|
|
17
17
|
const conv = (typeof convOrName === 'string')
|
|
18
18
|
? this.config.mergeFields[convOrName] ?? convOrName
|
|
@@ -25,6 +25,9 @@ class ConvStep extends step_1.default {
|
|
|
25
25
|
return convOrName;
|
|
26
26
|
throw new Error(`invalid conversation ${JSON.stringify(conv)}`);
|
|
27
27
|
}
|
|
28
|
+
get globalThreadId() {
|
|
29
|
+
return `G:${this.conversationId}`;
|
|
30
|
+
}
|
|
28
31
|
/** id of the thread where conversation data is stored */
|
|
29
32
|
get dataThreadId() {
|
|
30
33
|
const dataThreadId = this.state.thread ?? this.data.conversationThread;
|
|
@@ -76,21 +79,19 @@ class ConvStep extends step_1.default {
|
|
|
76
79
|
if (this.useQueue && !await this.pushConvStep()) {
|
|
77
80
|
return await this.waitForConversation();
|
|
78
81
|
}
|
|
79
|
-
if (this.event.action == null && !this.event.processed) {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
}
|
|
93
|
-
await this.setLocalTriggers();
|
|
82
|
+
// if (this.event.action == null && !this.event.processed) {
|
|
83
|
+
// if (this.isGlobal) return
|
|
84
|
+
// const hasGlobal = await this.sendEventToStep({ event: { ...this.event, action: 'global' }, toGlobal: true }) // redirect to global (1)
|
|
85
|
+
// if (hasGlobal != null) {
|
|
86
|
+
// this.log.debug('conv.sendEventToStep toGlobal', { hasGlobal })
|
|
87
|
+
// this.state.prevSkipName = this.state.name
|
|
88
|
+
// this.state.name = 'onSkipEvent'
|
|
89
|
+
// }
|
|
90
|
+
// }
|
|
91
|
+
// if (this.isGlobal && this.event.action === 'global') {
|
|
92
|
+
// // it was redirected from (1)
|
|
93
|
+
// }
|
|
94
|
+
// await this.setLocalTriggers()
|
|
94
95
|
}
|
|
95
96
|
async runAfter() {
|
|
96
97
|
if (this.thread.ending)
|
|
@@ -112,11 +113,11 @@ class ConvStep extends step_1.default {
|
|
|
112
113
|
const globalLength = (await this.getConversation())?.glb?.length ?? 0;
|
|
113
114
|
return globalLength > 0;
|
|
114
115
|
}
|
|
115
|
-
async setLocalTriggers() {
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
}
|
|
116
|
+
// public async setLocalTriggers (): Promise<void> {
|
|
117
|
+
// if (!this.isGlobal && await this.hasActiveGlobal()) {
|
|
118
|
+
// this.triggers.config({ target: 'session' })
|
|
119
|
+
// }
|
|
120
|
+
// }
|
|
120
121
|
async waitForConversation() {
|
|
121
122
|
if (this.state.name !== 'waitForConversation') {
|
|
122
123
|
this.log.debug(this.state, 'conv.begin waitForConversation');
|
|
@@ -200,9 +201,9 @@ class ConvStep extends step_1.default {
|
|
|
200
201
|
}
|
|
201
202
|
}
|
|
202
203
|
async waitGlobEnd() {
|
|
203
|
-
const gcThreadId =
|
|
204
|
+
const gcThreadId = this.globalThreadId;
|
|
204
205
|
// wait for glob thread end (if exists)
|
|
205
|
-
this.triggers.
|
|
206
|
+
this.triggers.hook({ name: 'end', thread: gcThreadId }, async () => await this.onConvEnd());
|
|
206
207
|
if (!this.process.getThread(gcThreadId))
|
|
207
208
|
await this.onConvEnd();
|
|
208
209
|
}
|
package/dst/voice.d.ts
CHANGED
|
@@ -28,19 +28,24 @@ export interface IVoiceCall {
|
|
|
28
28
|
export type EventType = 'hangup' | 'error' | 'cancel' | 'avm-detected' | 'recognition' | 'digit' | 'digits' | 'conference-start' | 'conference-end' | 'playback' | 'timeout' | 'record' | 'bridge' | 'bridge/ended' | 'is_flow_ready' | 'call' | 'dtmf-sent';
|
|
29
29
|
export declare class VoiceStepError extends BasicError {
|
|
30
30
|
}
|
|
31
|
+
export type VoicerError = Error | string & {
|
|
32
|
+
message?: never;
|
|
33
|
+
name?: never;
|
|
34
|
+
};
|
|
31
35
|
export interface VoiceEvent {
|
|
32
36
|
type: EventType;
|
|
33
|
-
|
|
37
|
+
global?: boolean;
|
|
38
|
+
error?: VoicerError;
|
|
34
39
|
}
|
|
35
40
|
export interface CallStartEvent extends VoiceEvent {
|
|
36
41
|
channel: IVoiceCall;
|
|
37
42
|
headers?: Record<string, string>;
|
|
38
43
|
}
|
|
39
|
-
export default class VoiceStep<TIn = unknown, TOut = unknown, TParams = VoiceEvent> extends ConvStep<IVoiceCall, TIn & {
|
|
44
|
+
export default class VoiceStep<TIn = unknown, TOut = unknown, TParams extends VoiceEvent = VoiceEvent> extends ConvStep<IVoiceCall, TIn & {
|
|
40
45
|
handleCancel?: boolean;
|
|
41
46
|
}, TOut, TParams> {
|
|
42
47
|
runBefore(): Promise<void>;
|
|
43
|
-
sendCommands({ id, type, callback }: IVoiceCall, commands: TODO[]): Promise<
|
|
48
|
+
sendCommands({ id, type, callback }: IVoiceCall, commands: TODO[]): Promise<void>;
|
|
44
49
|
handleHeartbeat(call: IVoiceCall): Promise<void>;
|
|
45
50
|
extractSectionMessages(sections: IPromtpSection[]): string;
|
|
46
51
|
extractSectionFiles(sections: IPromtpSection[]): Array<{
|
|
@@ -50,10 +55,7 @@ export default class VoiceStep<TIn = unknown, TOut = unknown, TParams = VoiceEve
|
|
|
50
55
|
pauseRecording(call: IVoiceCall, command: any, sensitiveData?: SensitiveData): Promise<void>;
|
|
51
56
|
resumeRecording(call: IVoiceCall, sensitiveData?: SensitiveData): Promise<void>;
|
|
52
57
|
transcript(call: IVoiceCall, data?: Partial<IVoiceReporterTranscriptEventArgs>): Promise<string>;
|
|
53
|
-
throwError(error?:
|
|
54
|
-
name: string;
|
|
55
|
-
message: string;
|
|
56
|
-
}): never;
|
|
58
|
+
throwError(error?: VoicerError): never;
|
|
57
59
|
handleHangup(call: IVoiceCall): Promise<void>;
|
|
58
60
|
buildSections({ sections, textType, ttsSettings, allowKeypadBargeIn }: TODO): TODO;
|
|
59
61
|
buildReprompts({ prompts, allowKeypadBargeIn }: TODO): TODO;
|
package/dst/voice.js
CHANGED
|
@@ -15,13 +15,22 @@ class VoiceStep extends step_1.default {
|
|
|
15
15
|
// static Error = VoiceStepError
|
|
16
16
|
async runBefore() {
|
|
17
17
|
await super.runBefore();
|
|
18
|
-
if (this.cache != null)
|
|
18
|
+
if (this.cache != null) {
|
|
19
|
+
if (!this.isGlobal && this.event.params.global && this.event.action == null) {
|
|
20
|
+
const hasGlobal = await this.sendEventToStep({ event: { ...this.event, action: 'global' }, toGlobal: true }); // redirect to global (1)
|
|
21
|
+
if (hasGlobal != null) {
|
|
22
|
+
this.log.debug('conv.sendEventToStep toGlobal', { hasGlobal });
|
|
23
|
+
this.state.prevSkipName = this.state.name;
|
|
24
|
+
this.state.name = 'onSkipEvent';
|
|
25
|
+
}
|
|
26
|
+
}
|
|
19
27
|
await this.handleHeartbeat(this.cache);
|
|
28
|
+
}
|
|
20
29
|
}
|
|
21
30
|
async sendCommands({ id, type, callback }, commands) {
|
|
22
31
|
if (lodash_1.default.isEmpty(commands))
|
|
23
32
|
return;
|
|
24
|
-
|
|
33
|
+
const result = await this.thread.eventManager.emit({
|
|
25
34
|
target: 'provider',
|
|
26
35
|
name: `out/voice/${type}`,
|
|
27
36
|
params: {
|
|
@@ -37,6 +46,8 @@ class VoiceStep extends step_1.default {
|
|
|
37
46
|
invocationType: 'async',
|
|
38
47
|
timeout: 5000
|
|
39
48
|
});
|
|
49
|
+
if (result == null)
|
|
50
|
+
throw new Error(`failed to send command to call: ${id}`);
|
|
40
51
|
}
|
|
41
52
|
async handleHeartbeat(call) {
|
|
42
53
|
if (call.vv >= 1) {
|
|
@@ -146,7 +157,7 @@ class VoiceStep extends step_1.default {
|
|
|
146
157
|
return eventId;
|
|
147
158
|
}
|
|
148
159
|
throwError(error = new Error('unknown')) {
|
|
149
|
-
throw new VoiceStepError(error.message, null, { name: error
|
|
160
|
+
throw new VoiceStepError(error.message ?? error, null, { name: error?.name });
|
|
150
161
|
}
|
|
151
162
|
async handleHangup(call) {
|
|
152
163
|
if (call.ended)
|
|
@@ -166,6 +177,7 @@ class VoiceStep extends step_1.default {
|
|
|
166
177
|
textType,
|
|
167
178
|
bargeInVoice: section.allowVoiceBargeIn,
|
|
168
179
|
bargeInKeypad: section.allowKeypadBargeIn ?? allowKeypadBargeIn,
|
|
180
|
+
bargeInBeforeSpeechEndTime: section.bargeInBeforeSpeechEndTime,
|
|
169
181
|
...ttsSettings
|
|
170
182
|
}));
|
|
171
183
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@onereach/step-voice",
|
|
3
|
-
"version": "5.0.
|
|
3
|
+
"version": "5.0.6",
|
|
4
4
|
"author": "Roman Zolotarov <roman.zolotarov@onereach.com>",
|
|
5
5
|
"contributors": [
|
|
6
6
|
"Roman Zolotarov",
|
|
@@ -19,20 +19,22 @@
|
|
|
19
19
|
"uuid": "^9.0.0"
|
|
20
20
|
},
|
|
21
21
|
"devDependencies": {
|
|
22
|
-
"@onereach/flow-sdk": "^3.1.
|
|
23
|
-
"@swc/cli": "^0.1.
|
|
24
|
-
"@swc/core": "^1.3.
|
|
22
|
+
"@onereach/flow-sdk": "^3.1.114",
|
|
23
|
+
"@swc/cli": "^0.1.62",
|
|
24
|
+
"@swc/core": "^1.3.36",
|
|
25
|
+
"@swc/helpers": "^0.4.14",
|
|
25
26
|
"@swc/jest": "^0.2.24",
|
|
26
27
|
"@types/jest": "^29.4.0",
|
|
27
28
|
"@types/lodash": "^4.14.191",
|
|
28
29
|
"@types/timestring": "^6.0.2",
|
|
29
|
-
"@types/uuid": "^9.0.
|
|
30
|
-
"aws-sdk": "^2.
|
|
30
|
+
"@types/uuid": "^9.0.1",
|
|
31
|
+
"aws-sdk": "^2.1320.0",
|
|
31
32
|
"babel-runtime": "^6.26.0",
|
|
32
33
|
"docdash": "^2.0.1",
|
|
33
34
|
"husky": "^8.0.3",
|
|
34
|
-
"jest": "^29.4.
|
|
35
|
+
"jest": "^29.4.3",
|
|
35
36
|
"pinst": "^3.0.0",
|
|
37
|
+
"source-map-support": "^0.5.21",
|
|
36
38
|
"ts-standard": "^12.0.2",
|
|
37
39
|
"typescript": "^4.9.5"
|
|
38
40
|
},
|