@fonoster/autopilot 0.5.1 → 0.5.3
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/dist/cerebro/cerebro.d.ts +4 -2
- package/dist/cerebro/cerebro.js +29 -4
- package/dist/cerebro/effects.d.ts +1 -1
- package/dist/cerebro/effects.js +13 -3
- package/dist/cerebro/types.d.ts +1 -1
- package/dist/intents/dialogflow_cx.d.ts +30 -2
- package/dist/intents/dialogflow_cx.js +33 -18
- package/dist/intents/dialogflow_es.d.ts +2 -2
- package/dist/intents/dialogflow_es.js +12 -15
- package/dist/intents/types.d.ts +0 -1
- package/dist/pilot.js +2 -1
- package/package.json +3 -3
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
2
|
/// <reference types="node" />
|
|
3
3
|
import { EffectsManager } from "./effects";
|
|
4
|
-
import { IntentsEngine } from "../intents/types";
|
|
4
|
+
import { Intent, IntentsEngine } from "../intents/types";
|
|
5
5
|
import { SGatherStream, VoiceRequest, VoiceResponse } from "@fonoster/voice";
|
|
6
6
|
import { CerebroConfig, CerebroStatus } from "./types";
|
|
7
7
|
import Events from "events";
|
|
@@ -18,10 +18,11 @@ export declare class Cerebro {
|
|
|
18
18
|
intentsEngine: IntentsEngine;
|
|
19
19
|
stream: SGatherStream;
|
|
20
20
|
config: CerebroConfig;
|
|
21
|
-
lastIntent:
|
|
21
|
+
lastIntent: Intent;
|
|
22
22
|
effects: EffectsManager;
|
|
23
23
|
interactionsTimer: NodeJS.Timeout;
|
|
24
24
|
isCallHandover: boolean;
|
|
25
|
+
isDead: boolean;
|
|
25
26
|
constructor(config: CerebroConfig);
|
|
26
27
|
wake(): Promise<void>;
|
|
27
28
|
sleep(): Promise<void>;
|
|
@@ -37,4 +38,5 @@ export declare class Cerebro {
|
|
|
37
38
|
startInteractionTimer(): void;
|
|
38
39
|
resetInteractionTimer(): void;
|
|
39
40
|
stopPlayback(): Promise<void>;
|
|
41
|
+
cleanup(): Promise<void>;
|
|
40
42
|
}
|
package/dist/cerebro/cerebro.js
CHANGED
|
@@ -47,6 +47,7 @@ class Cerebro {
|
|
|
47
47
|
effects;
|
|
48
48
|
interactionsTimer;
|
|
49
49
|
isCallHandover = false;
|
|
50
|
+
isDead = false;
|
|
50
51
|
constructor(config) {
|
|
51
52
|
this.voiceResponse = config.voiceResponse;
|
|
52
53
|
this.voiceRequest = config.voiceRequest;
|
|
@@ -128,12 +129,17 @@ class Cerebro {
|
|
|
128
129
|
this.startActiveTimer();
|
|
129
130
|
}
|
|
130
131
|
}
|
|
132
|
+
}, () => {
|
|
133
|
+
logger.verbose("invokeEffects cleanup callback", {
|
|
134
|
+
sessionId: this.voiceRequest.sessionId
|
|
135
|
+
});
|
|
136
|
+
this.cleanup();
|
|
131
137
|
});
|
|
132
|
-
|
|
133
|
-
sessionId: this.voiceRequest.sessionId
|
|
134
|
-
});
|
|
135
|
-
if (this.isCallHandover) {
|
|
138
|
+
if (this.isDead || this.isCallHandover) {
|
|
136
139
|
try {
|
|
140
|
+
logger.verbose("the call was handover or cerebro was cleaned up", {
|
|
141
|
+
sessionId: this.voiceRequest.sessionId
|
|
142
|
+
});
|
|
137
143
|
this.voiceResponse.hangup();
|
|
138
144
|
}
|
|
139
145
|
catch (e) {
|
|
@@ -141,6 +147,9 @@ class Cerebro {
|
|
|
141
147
|
}
|
|
142
148
|
return;
|
|
143
149
|
}
|
|
150
|
+
logger.verbose("cerebro finished processing intent effects", {
|
|
151
|
+
sessionId: this.voiceRequest.sessionId
|
|
152
|
+
});
|
|
144
153
|
// Reset the interactions timer
|
|
145
154
|
if (!this.config.activationIntentId) {
|
|
146
155
|
this.resetInteractionTimer();
|
|
@@ -190,11 +199,13 @@ class Cerebro {
|
|
|
190
199
|
sessionId: this.voiceRequest.sessionId,
|
|
191
200
|
failedInteractions: this.failedInteractions
|
|
192
201
|
});
|
|
202
|
+
// Fix hard coded intent
|
|
193
203
|
let intentId = "welcome";
|
|
194
204
|
if (this.failedInteractions >= this.maxIteractionsBeforeHangup) {
|
|
195
205
|
logger.verbose("there was no interaction so for a long time so we hangup", {
|
|
196
206
|
sessionId: this.voiceRequest.sessionId
|
|
197
207
|
});
|
|
208
|
+
// Fix hard coded intent
|
|
198
209
|
intentId = "goodbye";
|
|
199
210
|
clearTimeout(this.interactionsTimer);
|
|
200
211
|
}
|
|
@@ -207,6 +218,11 @@ class Cerebro {
|
|
|
207
218
|
logger.verbose("invokeEffects callback", {
|
|
208
219
|
sessionId: this.voiceRequest.sessionId
|
|
209
220
|
});
|
|
221
|
+
}, () => {
|
|
222
|
+
logger.verbose("invokeEffects cleanup callback", {
|
|
223
|
+
sessionId: this.voiceRequest.sessionId
|
|
224
|
+
});
|
|
225
|
+
this.cleanup();
|
|
210
226
|
});
|
|
211
227
|
}, this.activationTimeout);
|
|
212
228
|
}
|
|
@@ -237,5 +253,14 @@ class Cerebro {
|
|
|
237
253
|
}
|
|
238
254
|
}
|
|
239
255
|
}
|
|
256
|
+
// Cleanup all timers and events
|
|
257
|
+
async cleanup() {
|
|
258
|
+
this.isDead = true;
|
|
259
|
+
await this.voiceResponse.closeMediaPipe();
|
|
260
|
+
this.stream.close();
|
|
261
|
+
this.cerebroEvents.removeAllListeners();
|
|
262
|
+
clearTimeout(this.activeTimer);
|
|
263
|
+
clearTimeout(this.interactionsTimer);
|
|
264
|
+
}
|
|
240
265
|
}
|
|
241
266
|
exports.Cerebro = Cerebro;
|
|
@@ -5,7 +5,7 @@ export declare class EffectsManager {
|
|
|
5
5
|
voice: VoiceResponse;
|
|
6
6
|
config: EffectsManagerConfig;
|
|
7
7
|
constructor(config: EffectsManagerConfig);
|
|
8
|
-
invokeEffects(intent: Intent, status: CerebroStatus, activateCallback: () => void): Promise<void>;
|
|
8
|
+
invokeEffects(intent: Intent, status: CerebroStatus, activateCallback: () => void, cleanupCallback: () => void): Promise<void>;
|
|
9
9
|
run(effect: Effect): Promise<void>;
|
|
10
10
|
transferEffect(effect: Effect): Promise<void>;
|
|
11
11
|
}
|
package/dist/cerebro/effects.js
CHANGED
|
@@ -15,7 +15,7 @@ class EffectsManager {
|
|
|
15
15
|
this.voice = config.voice;
|
|
16
16
|
this.config = config;
|
|
17
17
|
}
|
|
18
|
-
async invokeEffects(intent, status, activateCallback) {
|
|
18
|
+
async invokeEffects(intent, status, activateCallback, cleanupCallback) {
|
|
19
19
|
activateCallback();
|
|
20
20
|
logger.verbose("intent received", { intentRef: intent.ref });
|
|
21
21
|
if (this.config.activationIntentId === intent.ref) {
|
|
@@ -31,8 +31,18 @@ class EffectsManager {
|
|
|
31
31
|
}
|
|
32
32
|
// eslint-disable-next-line no-loops/no-loops
|
|
33
33
|
for (const e of intent.effects) {
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
try {
|
|
35
|
+
logger.verbose("effects running", { type: e.type });
|
|
36
|
+
await this.run(e);
|
|
37
|
+
}
|
|
38
|
+
catch (e) {
|
|
39
|
+
const axiosError = e;
|
|
40
|
+
if (axiosError.response?.status !== 404) {
|
|
41
|
+
logger.error("error running effect", { error: e });
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
cleanupCallback();
|
|
45
|
+
}
|
|
36
46
|
}
|
|
37
47
|
}
|
|
38
48
|
async run(effect) {
|
package/dist/cerebro/types.d.ts
CHANGED
|
@@ -13,7 +13,7 @@ export interface CerebroConfig {
|
|
|
13
13
|
activationTimeout?: number;
|
|
14
14
|
activationIntentId?: string;
|
|
15
15
|
intentsEngine: IntentsEngine;
|
|
16
|
-
voiceConfig: Record<string, string>;
|
|
16
|
+
voiceConfig: Record<string, string | string[]>;
|
|
17
17
|
eventsClient: EventsClient | null;
|
|
18
18
|
transfer?: Transfer;
|
|
19
19
|
alternativeLanguageCode?: string;
|
|
@@ -1,8 +1,24 @@
|
|
|
1
1
|
import { DialogFlowCXConfig, IntentsEngine, Intent } from "./types";
|
|
2
|
+
import { Effect } from "../cerebro/types";
|
|
2
3
|
import { SessionsClient } from "@google-cloud/dialogflow-cx";
|
|
4
|
+
type DetectItemRequest = {
|
|
5
|
+
session: string;
|
|
6
|
+
queryParams: Record<string, unknown>;
|
|
7
|
+
queryInput: {
|
|
8
|
+
text: {
|
|
9
|
+
text: string;
|
|
10
|
+
};
|
|
11
|
+
} | ({
|
|
12
|
+
event: {
|
|
13
|
+
event: string;
|
|
14
|
+
};
|
|
15
|
+
} & {
|
|
16
|
+
languageCode: string;
|
|
17
|
+
});
|
|
18
|
+
};
|
|
3
19
|
export default class DialogFlowCX implements IntentsEngine {
|
|
4
20
|
sessionClient: SessionsClient;
|
|
5
|
-
sessionPath:
|
|
21
|
+
sessionPath: string;
|
|
6
22
|
config: DialogFlowCXConfig;
|
|
7
23
|
projectId: string;
|
|
8
24
|
location: string;
|
|
@@ -10,6 +26,18 @@ export default class DialogFlowCX implements IntentsEngine {
|
|
|
10
26
|
sessionId: string;
|
|
11
27
|
constructor(config: DialogFlowCXConfig);
|
|
12
28
|
setProjectId(id: string): void;
|
|
13
|
-
findIntent(
|
|
29
|
+
findIntent(text: string, payload?: Record<string, unknown>): Promise<Intent>;
|
|
30
|
+
findIntentWithEvent(name: string, payload?: Record<string, unknown>): Promise<{
|
|
31
|
+
ref: string;
|
|
32
|
+
effects: Effect[];
|
|
33
|
+
confidence: number;
|
|
34
|
+
}>;
|
|
35
|
+
detectIntent(request: DetectItemRequest, payload?: Record<string, unknown>): Promise<{
|
|
36
|
+
ref: string;
|
|
37
|
+
effects: Effect[];
|
|
38
|
+
confidence: number;
|
|
39
|
+
}>;
|
|
40
|
+
private getSessionPath;
|
|
14
41
|
private getEffects;
|
|
15
42
|
}
|
|
43
|
+
export {};
|
|
@@ -4,6 +4,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
const df_utils_1 = require("./df_utils");
|
|
7
|
+
const pb_util_1 = require("pb-util");
|
|
7
8
|
const logger_1 = require("@fonoster/logger");
|
|
8
9
|
const dialogflow_cx_1 = __importDefault(require("@google-cloud/dialogflow-cx"));
|
|
9
10
|
const uuid = require("uuid");
|
|
@@ -36,46 +37,60 @@ class DialogFlowCX {
|
|
|
36
37
|
setProjectId(id) {
|
|
37
38
|
this.projectId = id;
|
|
38
39
|
}
|
|
39
|
-
async findIntent(
|
|
40
|
-
const sessionPath = this.sessionClient.projectLocationAgentSessionPath(this.projectId, this.location, this.agent, this.sessionId);
|
|
40
|
+
async findIntent(text, payload) {
|
|
41
41
|
const request = {
|
|
42
|
-
session:
|
|
42
|
+
session: this.getSessionPath(),
|
|
43
|
+
queryParams: {},
|
|
43
44
|
queryInput: {
|
|
44
45
|
text: {
|
|
45
|
-
text
|
|
46
|
+
text
|
|
46
47
|
},
|
|
47
48
|
languageCode: this.config.languageCode
|
|
48
49
|
}
|
|
49
50
|
};
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
51
|
+
return this.detectIntent(request, payload);
|
|
52
|
+
}
|
|
53
|
+
async findIntentWithEvent(name, payload) {
|
|
54
|
+
const request = {
|
|
55
|
+
session: this.getSessionPath(),
|
|
56
|
+
queryParams: {},
|
|
57
|
+
queryInput: {
|
|
58
|
+
languageCode: this.config.languageCode,
|
|
59
|
+
event: {
|
|
60
|
+
event: name
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
return this.detectIntent(request, payload);
|
|
65
|
+
}
|
|
66
|
+
async detectIntent(request, payload) {
|
|
67
|
+
if (payload) {
|
|
68
|
+
request.queryParams = { payload: pb_util_1.struct.encode(payload) };
|
|
56
69
|
}
|
|
57
|
-
const
|
|
58
|
-
const
|
|
59
|
-
|
|
60
|
-
|
|
70
|
+
const [response] = await this.sessionClient.detectIntent(request);
|
|
71
|
+
const effects = this.getEffects(response.queryResult.responseMessages);
|
|
72
|
+
const params = pb_util_1.struct.decode(response.queryResult.parameters);
|
|
73
|
+
const ref = params.skillCode?.toString() || "unknown";
|
|
61
74
|
return {
|
|
62
75
|
ref,
|
|
63
76
|
effects,
|
|
64
|
-
confidence:
|
|
65
|
-
allRequiredParamsPresent: responses[0].queryResult.text ? true : false
|
|
77
|
+
confidence: response.queryResult.match?.confidence || 0
|
|
66
78
|
};
|
|
67
79
|
}
|
|
80
|
+
getSessionPath() {
|
|
81
|
+
return this.sessionClient.projectLocationAgentSessionPath(this.projectId, this.location, this.agent, this.sessionId);
|
|
82
|
+
}
|
|
68
83
|
getEffects(responseMessages) {
|
|
69
84
|
const effects = [];
|
|
70
85
|
for (const r of responseMessages) {
|
|
71
86
|
if (r.message === "text") {
|
|
87
|
+
const res = r.text;
|
|
72
88
|
effects.push({
|
|
73
89
|
type: "say",
|
|
74
90
|
parameters: {
|
|
75
|
-
response:
|
|
91
|
+
response: res.text[0]
|
|
76
92
|
}
|
|
77
93
|
});
|
|
78
|
-
continue;
|
|
79
94
|
}
|
|
80
95
|
else if (r.payload) {
|
|
81
96
|
effects.push((0, df_utils_1.transformPayloadToEffect)(r.payload));
|
|
@@ -2,7 +2,7 @@ import * as dialogflow from "@google-cloud/dialogflow";
|
|
|
2
2
|
import { IntentsEngine, Intent, DialogFlowESConfig } from "./types";
|
|
3
3
|
export default class DialogFlow implements IntentsEngine {
|
|
4
4
|
sessionClient: dialogflow.v2beta1.SessionsClient;
|
|
5
|
-
sessionPath:
|
|
5
|
+
sessionPath: string;
|
|
6
6
|
config: DialogFlowESConfig;
|
|
7
7
|
sessionId: string;
|
|
8
8
|
projectId: string;
|
|
@@ -10,6 +10,6 @@ export default class DialogFlow implements IntentsEngine {
|
|
|
10
10
|
setProjectId(projectId: string): void;
|
|
11
11
|
findIntentWithEvent(name: string, payload?: Record<string, unknown>): Promise<Intent>;
|
|
12
12
|
findIntent(txt: string, payload?: Record<string, unknown>): Promise<Intent>;
|
|
13
|
-
private
|
|
13
|
+
private detectItent;
|
|
14
14
|
private getEffects;
|
|
15
15
|
}
|
|
@@ -80,7 +80,7 @@ class DialogFlow {
|
|
|
80
80
|
}
|
|
81
81
|
}
|
|
82
82
|
};
|
|
83
|
-
return this.
|
|
83
|
+
return this.detectItent(request, payload);
|
|
84
84
|
}
|
|
85
85
|
async findIntent(txt, payload) {
|
|
86
86
|
const request = {
|
|
@@ -92,9 +92,9 @@ class DialogFlow {
|
|
|
92
92
|
}
|
|
93
93
|
}
|
|
94
94
|
};
|
|
95
|
-
return this.
|
|
95
|
+
return this.detectItent(request, payload);
|
|
96
96
|
}
|
|
97
|
-
async
|
|
97
|
+
async detectItent(request, payload) {
|
|
98
98
|
const sessionPath = this.sessionClient.projectAgentSessionPath(this.projectId, this.sessionId);
|
|
99
99
|
request.session = sessionPath;
|
|
100
100
|
if (payload) {
|
|
@@ -102,33 +102,30 @@ class DialogFlow {
|
|
|
102
102
|
payload: pb_util_1.struct.encode(payload)
|
|
103
103
|
};
|
|
104
104
|
}
|
|
105
|
-
const
|
|
106
|
-
logger.silly("got speech from api", { text: JSON.stringify(
|
|
107
|
-
if (!
|
|
108
|
-
!responses[0].queryResult ||
|
|
109
|
-
!responses[0].queryResult.intent) {
|
|
105
|
+
const [response] = await this.sessionClient.detectIntent(request);
|
|
106
|
+
logger.silly("got speech from api", { text: JSON.stringify(response) });
|
|
107
|
+
if (!response.queryResult?.intent) {
|
|
110
108
|
throw new Error("got unexpect null intent");
|
|
111
109
|
}
|
|
112
110
|
let effects = [];
|
|
113
|
-
if (
|
|
114
|
-
const messages =
|
|
111
|
+
if (response.queryResult.fulfillmentMessages) {
|
|
112
|
+
const messages = response.queryResult.fulfillmentMessages.filter((f) => f.platform === this.config.platform);
|
|
115
113
|
effects = this.getEffects(messages);
|
|
116
114
|
}
|
|
117
|
-
else if (
|
|
115
|
+
else if (response.queryResult.fulfillmentText) {
|
|
118
116
|
effects = [
|
|
119
117
|
{
|
|
120
118
|
type: "say",
|
|
121
119
|
parameters: {
|
|
122
|
-
response:
|
|
120
|
+
response: response.queryResult.fulfillmentText
|
|
123
121
|
}
|
|
124
122
|
}
|
|
125
123
|
];
|
|
126
124
|
}
|
|
127
125
|
return {
|
|
128
|
-
ref:
|
|
126
|
+
ref: response.queryResult.intent.displayName || "unknown",
|
|
129
127
|
effects,
|
|
130
|
-
confidence:
|
|
131
|
-
allRequiredParamsPresent: responses[0].queryResult.allRequiredParamsPresent
|
|
128
|
+
confidence: response.queryResult.intentDetectionConfidence || 0
|
|
132
129
|
};
|
|
133
130
|
}
|
|
134
131
|
getEffects(fulfillmentMessages) {
|
package/dist/intents/types.d.ts
CHANGED
package/dist/pilot.js
CHANGED
|
@@ -66,7 +66,8 @@ function pilot(config) {
|
|
|
66
66
|
intentsEngine?.setProjectId(app.intentsEngineConfig.projectId);
|
|
67
67
|
const voiceConfig = {
|
|
68
68
|
name: app.speechConfig.voice,
|
|
69
|
-
playbackId: (0, nanoid_1.nanoid)()
|
|
69
|
+
playbackId: (0, nanoid_1.nanoid)(),
|
|
70
|
+
cachingFields: ["name"]
|
|
70
71
|
};
|
|
71
72
|
const speechSecret = await secrets.getSecret(app.speechConfig.secretName);
|
|
72
73
|
const speechCredentials = {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fonoster/autopilot",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.3",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"main": "dist/index",
|
|
6
6
|
"types": "dist/index",
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"dependencies": {
|
|
15
15
|
"@fonoster/apps": "^0.5.1",
|
|
16
16
|
"@fonoster/googleasr": "^0.5.1",
|
|
17
|
-
"@fonoster/googletts": "^0.5.
|
|
17
|
+
"@fonoster/googletts": "^0.5.3",
|
|
18
18
|
"@fonoster/logger": "^0.5.1",
|
|
19
19
|
"@fonoster/secrets": "^0.5.1",
|
|
20
20
|
"@fonoster/voice": "^0.5.1",
|
|
@@ -37,5 +37,5 @@
|
|
|
37
37
|
"publishConfig": {
|
|
38
38
|
"access": "public"
|
|
39
39
|
},
|
|
40
|
-
"gitHead": "
|
|
40
|
+
"gitHead": "a75f426e647949f536417951e0956439856d5ae9"
|
|
41
41
|
}
|