@nlxai/core 1.2.3 → 1.2.4-alpha.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/README.md +155 -1
- package/docs/README.md +1922 -0
- package/lib/index.cjs +119 -82
- package/lib/index.d.ts +83 -2
- package/lib/index.esm.js +119 -82
- package/lib/index.umd.js +2 -2
- package/package.json +2 -2
package/lib/index.cjs
CHANGED
|
@@ -5,75 +5,9 @@ var ramda = require('ramda');
|
|
|
5
5
|
var ReconnectingWebSocket = require('reconnecting-websocket');
|
|
6
6
|
var uuid = require('uuid');
|
|
7
7
|
|
|
8
|
-
var
|
|
9
|
-
var version$1 = "1.2.3";
|
|
10
|
-
var description = "Low-level SDK for building NLX experiences";
|
|
11
|
-
var type = "module";
|
|
12
|
-
var main = "lib/index.cjs";
|
|
13
|
-
var module$1 = "lib/index.esm.js";
|
|
14
|
-
var browser = "lib/index.umd.js";
|
|
15
|
-
var types = "lib/index.d.ts";
|
|
16
|
-
var exports$1 = {
|
|
17
|
-
".": {
|
|
18
|
-
types: "./lib/index.d.ts",
|
|
19
|
-
"import": "./lib/index.esm.js",
|
|
20
|
-
require: "./lib/index.cjs"
|
|
21
|
-
}
|
|
22
|
-
};
|
|
23
|
-
var scripts = {
|
|
24
|
-
build: "rm -rf lib && rollup -c --configPlugin typescript --configImportAttributesKey with",
|
|
25
|
-
"lint:check": "eslint src/ --ext .ts,.tsx,.js,.jsx --max-warnings 0",
|
|
26
|
-
lint: "eslint src/ --ext .ts,.tsx,.js,.jsx --fix",
|
|
27
|
-
prepublish: "npm run build",
|
|
28
|
-
test: "typedoc --emit none",
|
|
29
|
-
tsc: "tsc",
|
|
30
|
-
"update-readme:docs": "rm -rf docs/ && typedoc",
|
|
31
|
-
"update-readme:merge": "../../scripts/transclude-markdown.js",
|
|
32
|
-
"update-readme": "npm run update-readme:docs && npm run update-readme:merge"
|
|
33
|
-
};
|
|
34
|
-
var author = "Peter Szerzo <peter@nlx.ai>";
|
|
35
|
-
var license = "MIT";
|
|
36
|
-
var devDependencies = {
|
|
37
|
-
"@types/isomorphic-fetch": "^0.0.39",
|
|
38
|
-
"@types/node": "^24.10.1",
|
|
39
|
-
"@types/ramda": "0.31.1",
|
|
40
|
-
"@types/uuid": "^9.0.7",
|
|
41
|
-
"concat-md": "^0.5.1",
|
|
42
|
-
"eslint-config-nlx": "*",
|
|
43
|
-
prettier: "^3.1.0",
|
|
44
|
-
"rollup-config-nlx": "*",
|
|
45
|
-
typedoc: "^0.28.14",
|
|
46
|
-
"typedoc-plugin-markdown": "^4.9.0",
|
|
47
|
-
typescript: "^5.5.4"
|
|
48
|
-
};
|
|
49
|
-
var dependencies = {
|
|
50
|
-
"isomorphic-fetch": "^3.0.0",
|
|
51
|
-
ramda: "^0.32.0",
|
|
52
|
-
"reconnecting-websocket": "^4.4.0",
|
|
53
|
-
uuid: "^9.0.1"
|
|
54
|
-
};
|
|
55
|
-
var publishConfig = {
|
|
56
|
-
access: "public"
|
|
57
|
-
};
|
|
58
|
-
var gitHead = "3902161e95745dd4a9cfb68bb469755a62b421f5";
|
|
8
|
+
var version$1 = "1.2.4-alpha.3";
|
|
59
9
|
var packageJson = {
|
|
60
|
-
|
|
61
|
-
version: version$1,
|
|
62
|
-
description: description,
|
|
63
|
-
type: type,
|
|
64
|
-
main: main,
|
|
65
|
-
module: module$1,
|
|
66
|
-
browser: browser,
|
|
67
|
-
types: types,
|
|
68
|
-
exports: exports$1,
|
|
69
|
-
scripts: scripts,
|
|
70
|
-
author: author,
|
|
71
|
-
license: license,
|
|
72
|
-
devDependencies: devDependencies,
|
|
73
|
-
dependencies: dependencies,
|
|
74
|
-
publishConfig: publishConfig,
|
|
75
|
-
gitHead: gitHead
|
|
76
|
-
};
|
|
10
|
+
version: version$1};
|
|
77
11
|
|
|
78
12
|
/**
|
|
79
13
|
* Package version
|
|
@@ -163,6 +97,96 @@ const normalizeToHttp = (applicationUrl) => {
|
|
|
163
97
|
const isWebsocketUrl = (url) => {
|
|
164
98
|
return url.indexOf("wss://") === 0;
|
|
165
99
|
};
|
|
100
|
+
const fetchUserMessage = async ({ fullApplicationUrl, headers, body, stream, eventListeners, }) => {
|
|
101
|
+
const streamRequest = async (body) => {
|
|
102
|
+
const response = await fetch(fullApplicationUrl, {
|
|
103
|
+
method: "POST",
|
|
104
|
+
headers: {
|
|
105
|
+
...headers,
|
|
106
|
+
"Content-Type": "application/json",
|
|
107
|
+
"nlx-sdk-version": packageJson.version,
|
|
108
|
+
},
|
|
109
|
+
body: JSON.stringify({ ...body, stream: true }),
|
|
110
|
+
});
|
|
111
|
+
if (!response.ok || response.body == null)
|
|
112
|
+
throw new Error(`HTTP Error: ${response.status}`);
|
|
113
|
+
const reader = response.body.getReader();
|
|
114
|
+
const decoder = new TextDecoder();
|
|
115
|
+
let buffer = "";
|
|
116
|
+
const messages = [];
|
|
117
|
+
let finalResponse = {};
|
|
118
|
+
while (true) {
|
|
119
|
+
const { done, value } = await reader.read();
|
|
120
|
+
if (done)
|
|
121
|
+
break;
|
|
122
|
+
buffer += decoder.decode(value, { stream: true });
|
|
123
|
+
while (true) {
|
|
124
|
+
const openBrace = buffer.indexOf("{");
|
|
125
|
+
if (openBrace === -1)
|
|
126
|
+
break;
|
|
127
|
+
let foundObject = false;
|
|
128
|
+
for (let i = 0; i < buffer.length; i++) {
|
|
129
|
+
if (buffer[i] === "}") {
|
|
130
|
+
const candidate = buffer.substring(openBrace, i + 1);
|
|
131
|
+
try {
|
|
132
|
+
const json = JSON.parse(candidate);
|
|
133
|
+
if (json.type === "interim") {
|
|
134
|
+
const text = json.text;
|
|
135
|
+
if (typeof text === "string") {
|
|
136
|
+
eventListeners.interimMessage.forEach((listener) => {
|
|
137
|
+
listener(text);
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
else if (json.type === "message") {
|
|
142
|
+
messages.push({
|
|
143
|
+
text: json.text,
|
|
144
|
+
choices: json.choices ?? [],
|
|
145
|
+
messageId: json.messageId,
|
|
146
|
+
metadata: json.metadata,
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
else if (json.type === "final_response") {
|
|
150
|
+
finalResponse = json.data;
|
|
151
|
+
}
|
|
152
|
+
buffer = buffer.substring(i + 1);
|
|
153
|
+
foundObject = true;
|
|
154
|
+
break;
|
|
155
|
+
}
|
|
156
|
+
catch (e) {
|
|
157
|
+
/* keep scanning */
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
if (!foundObject)
|
|
162
|
+
break;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
eventListeners.interimMessage.forEach((listener) => {
|
|
166
|
+
listener(undefined);
|
|
167
|
+
});
|
|
168
|
+
return { ...finalResponse, messages };
|
|
169
|
+
};
|
|
170
|
+
if (stream) {
|
|
171
|
+
return await streamRequest(body);
|
|
172
|
+
}
|
|
173
|
+
else {
|
|
174
|
+
const response = await fetch(fullApplicationUrl, {
|
|
175
|
+
method: "POST",
|
|
176
|
+
headers: {
|
|
177
|
+
...(headers ?? {}),
|
|
178
|
+
Accept: "application/json",
|
|
179
|
+
"Content-Type": "application/json",
|
|
180
|
+
"nlx-sdk-version": packageJson.version,
|
|
181
|
+
},
|
|
182
|
+
body: JSON.stringify(body),
|
|
183
|
+
});
|
|
184
|
+
if (!response.ok || response.body == null)
|
|
185
|
+
throw new Error(`HTTP Error: ${response.status}`);
|
|
186
|
+
const json = await response.json();
|
|
187
|
+
return json;
|
|
188
|
+
}
|
|
189
|
+
};
|
|
166
190
|
/**
|
|
167
191
|
* Call this to create a conversation handler.
|
|
168
192
|
* @param configuration - The necessary configuration to create the conversation.
|
|
@@ -193,7 +217,10 @@ function createConversation(configuration) {
|
|
|
193
217
|
if (/[-|_][a-z]{2,}[-|_][A-Z]{2,}$/.test(applicationUrl)) {
|
|
194
218
|
Console.warn("Since v1.0.0, the language code is no longer added at the end of the application URL. Please remove the modifier (e.g. '-en-US') from the URL, and specify it in the `languageCode` parameter instead.");
|
|
195
219
|
}
|
|
196
|
-
const eventListeners = {
|
|
220
|
+
const eventListeners = {
|
|
221
|
+
voicePlusCommand: [],
|
|
222
|
+
interimMessage: [],
|
|
223
|
+
};
|
|
197
224
|
const initialConversationId = configuration.conversationId ?? uuid.v4();
|
|
198
225
|
let state = {
|
|
199
226
|
responses: configuration.responses ?? [],
|
|
@@ -305,20 +332,13 @@ function createConversation(configuration) {
|
|
|
305
332
|
}
|
|
306
333
|
else {
|
|
307
334
|
try {
|
|
308
|
-
const
|
|
309
|
-
|
|
310
|
-
headers: {
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
"nlx-sdk-version": packageJson.version,
|
|
315
|
-
},
|
|
316
|
-
body: JSON.stringify(bodyWithContext),
|
|
335
|
+
const json = await fetchUserMessage({
|
|
336
|
+
fullApplicationUrl: fullApplicationHttpUrl(),
|
|
337
|
+
headers: configuration.headers ?? {},
|
|
338
|
+
stream: configuration.experimental?.streamHttp ?? false,
|
|
339
|
+
eventListeners,
|
|
340
|
+
body: bodyWithContext,
|
|
317
341
|
});
|
|
318
|
-
if (res.status >= 400) {
|
|
319
|
-
throw new Error(`Responded with ${res.status}`);
|
|
320
|
-
}
|
|
321
|
-
const json = await res.json();
|
|
322
342
|
messageResponseHandler(json);
|
|
323
343
|
}
|
|
324
344
|
catch (err) {
|
|
@@ -591,6 +611,23 @@ function createConversation(configuration) {
|
|
|
591
611
|
sendFlow(welcomeIntent, context);
|
|
592
612
|
},
|
|
593
613
|
sendChoice,
|
|
614
|
+
submitFeedback: async (feedbackUrl, feedback) => {
|
|
615
|
+
const res = await fetch(feedbackUrl, {
|
|
616
|
+
method: "POST",
|
|
617
|
+
headers: {
|
|
618
|
+
"Content-Type": "application/json",
|
|
619
|
+
},
|
|
620
|
+
body: JSON.stringify({
|
|
621
|
+
languageCode: state.languageCode,
|
|
622
|
+
conversationId: state.conversationId,
|
|
623
|
+
userId: state.userId,
|
|
624
|
+
...feedback,
|
|
625
|
+
}),
|
|
626
|
+
});
|
|
627
|
+
if (res.status >= 400) {
|
|
628
|
+
throw new Error(`Responded with ${res.status}`);
|
|
629
|
+
}
|
|
630
|
+
},
|
|
594
631
|
currentConversationId: () => {
|
|
595
632
|
return state.conversationId;
|
|
596
633
|
},
|
package/lib/index.d.ts
CHANGED
|
@@ -55,6 +55,10 @@ export interface Config {
|
|
|
55
55
|
* @internal
|
|
56
56
|
*/
|
|
57
57
|
experimental?: {
|
|
58
|
+
/**
|
|
59
|
+
* Check whether HTTP streaming should be enabled
|
|
60
|
+
*/
|
|
61
|
+
streamHttp?: boolean;
|
|
58
62
|
/**
|
|
59
63
|
* Simulate alternative channel types
|
|
60
64
|
*/
|
|
@@ -145,6 +149,15 @@ export interface ConversationHandler {
|
|
|
145
149
|
* @param context - [Context](https://docs.studio.nlx.ai/workspacesettings/documentation-settings/settings-context-attributes) for usage later in the intent.
|
|
146
150
|
*/
|
|
147
151
|
sendStructured: (request: StructuredRequest, context?: Context) => void;
|
|
152
|
+
/**
|
|
153
|
+
* Submit feedback about a response.
|
|
154
|
+
* @param url - The URL comming from the Application response `metadata.feedbackURL` field.
|
|
155
|
+
* @param feedback - Either a numerical rating or a textual comment.
|
|
156
|
+
*/
|
|
157
|
+
submitFeedback: (url: string, feedback: {
|
|
158
|
+
rating?: number;
|
|
159
|
+
comment?: string;
|
|
160
|
+
}) => Promise<void>;
|
|
148
161
|
/**
|
|
149
162
|
* Subscribe a callback to the conversation. On subscribe, the subscriber will receive all of the Responses that the conversation has already received.
|
|
150
163
|
* @param subscriber - The callback to subscribe
|
|
@@ -351,6 +364,16 @@ export interface ApplicationResponseMetadata {
|
|
|
351
364
|
* Knowledge base sources
|
|
352
365
|
*/
|
|
353
366
|
sources?: KnowledgeBaseResponseSource[];
|
|
367
|
+
/**
|
|
368
|
+
* URL to use for submitting feedback about this response. See `feedbackConfig` for what the expected feedback type is.
|
|
369
|
+
*
|
|
370
|
+
* You can pass this as the first argument to `submitFeedback`.
|
|
371
|
+
*/
|
|
372
|
+
feedbackUrl?: string;
|
|
373
|
+
/**
|
|
374
|
+
* If present, the application would like to collect feedback from the user.
|
|
375
|
+
*/
|
|
376
|
+
feedbackConfig?: FeedbackConfiguration;
|
|
354
377
|
}
|
|
355
378
|
/**
|
|
356
379
|
* Response for knowlege base sources
|
|
@@ -541,6 +564,52 @@ export type Response = ApplicationResponse | UserResponse | FailureMessage;
|
|
|
541
564
|
* The time value in milliseconds since midnight, January 1, 1970 UTC.
|
|
542
565
|
*/
|
|
543
566
|
export type Time = number;
|
|
567
|
+
/**
|
|
568
|
+
* Configuration for feedback collection. You can use this to render an appropriate feedback widget in your application.
|
|
569
|
+
*/
|
|
570
|
+
export interface FeedbackConfiguration {
|
|
571
|
+
/** Unique identifier for the feedback collection. */
|
|
572
|
+
feedbackId: string;
|
|
573
|
+
/** Human readable name of this feedback collection. */
|
|
574
|
+
feedbackName: string;
|
|
575
|
+
/**
|
|
576
|
+
* Type of feedback being collected.
|
|
577
|
+
* At the moment only binary feedback is supported, but we plan to introduce more types in the future.
|
|
578
|
+
* Hence your code should make sure to check the `type` attribute to make sure the expected feedback type is handled.
|
|
579
|
+
*/
|
|
580
|
+
feedbackType: FeedbackType;
|
|
581
|
+
/** Whether comments are enabled for this feedback collection. */
|
|
582
|
+
commentsEnabled: boolean;
|
|
583
|
+
/** Optional question to show to the user when collecting feedback. */
|
|
584
|
+
question?: string;
|
|
585
|
+
/** Labels for individual feedback UI elements as customised by the builder. */
|
|
586
|
+
labels: {
|
|
587
|
+
/** Label for positive feedback */
|
|
588
|
+
positive?: string;
|
|
589
|
+
/** Label for negative feedback */
|
|
590
|
+
negative?: string;
|
|
591
|
+
/** Label for comment */
|
|
592
|
+
comment?: string;
|
|
593
|
+
};
|
|
594
|
+
}
|
|
595
|
+
/**
|
|
596
|
+
* @inline @hidden
|
|
597
|
+
*/
|
|
598
|
+
export type FeedbackType = {
|
|
599
|
+
/** A binary feedback type is a thumbs up/down sort of choice. */
|
|
600
|
+
type: "binary";
|
|
601
|
+
/** Configuration specific to binary feedback. */
|
|
602
|
+
config: BinaryFeedbackConfig;
|
|
603
|
+
};
|
|
604
|
+
/**
|
|
605
|
+
* @inline @hidden
|
|
606
|
+
*/
|
|
607
|
+
export interface BinaryFeedbackConfig {
|
|
608
|
+
/** Value to send for positive feedback. Default `1`. */
|
|
609
|
+
positiveValue: number;
|
|
610
|
+
/** Value to send for negative feedback. Default `-1`. */
|
|
611
|
+
negativeValue: number;
|
|
612
|
+
}
|
|
544
613
|
/**
|
|
545
614
|
* @hidden
|
|
546
615
|
*/
|
|
@@ -709,7 +778,15 @@ export interface VoicePlusMessage {
|
|
|
709
778
|
* Handler events
|
|
710
779
|
* @event voicePlusCommand
|
|
711
780
|
*/
|
|
712
|
-
export type ConversationHandlerEvent = "voicePlusCommand";
|
|
781
|
+
export type ConversationHandlerEvent = "voicePlusCommand" | "interimMessage";
|
|
782
|
+
/**
|
|
783
|
+
* Voice+ command listener
|
|
784
|
+
*/
|
|
785
|
+
export type VoicePlusCommandListener = (payload: any) => void;
|
|
786
|
+
/**
|
|
787
|
+
* Interim message listener
|
|
788
|
+
*/
|
|
789
|
+
export type InterimMessageListener = (message?: string) => void;
|
|
713
790
|
/**
|
|
714
791
|
* Dictionary of handler methods per event
|
|
715
792
|
*/
|
|
@@ -717,7 +794,11 @@ export interface EventHandlers {
|
|
|
717
794
|
/**
|
|
718
795
|
* Voice+ command event handler
|
|
719
796
|
*/
|
|
720
|
-
voicePlusCommand:
|
|
797
|
+
voicePlusCommand: VoicePlusCommandListener;
|
|
798
|
+
/**
|
|
799
|
+
* Interim message event handler
|
|
800
|
+
*/
|
|
801
|
+
interimMessage: InterimMessageListener;
|
|
721
802
|
}
|
|
722
803
|
/**
|
|
723
804
|
* The callback function for listening to all responses.
|
package/lib/index.esm.js
CHANGED
|
@@ -3,75 +3,9 @@ import { equals, adjust } from 'ramda';
|
|
|
3
3
|
import ReconnectingWebSocket from 'reconnecting-websocket';
|
|
4
4
|
import { v4 } from 'uuid';
|
|
5
5
|
|
|
6
|
-
var
|
|
7
|
-
var version$1 = "1.2.3";
|
|
8
|
-
var description = "Low-level SDK for building NLX experiences";
|
|
9
|
-
var type = "module";
|
|
10
|
-
var main = "lib/index.cjs";
|
|
11
|
-
var module = "lib/index.esm.js";
|
|
12
|
-
var browser = "lib/index.umd.js";
|
|
13
|
-
var types = "lib/index.d.ts";
|
|
14
|
-
var exports = {
|
|
15
|
-
".": {
|
|
16
|
-
types: "./lib/index.d.ts",
|
|
17
|
-
"import": "./lib/index.esm.js",
|
|
18
|
-
require: "./lib/index.cjs"
|
|
19
|
-
}
|
|
20
|
-
};
|
|
21
|
-
var scripts = {
|
|
22
|
-
build: "rm -rf lib && rollup -c --configPlugin typescript --configImportAttributesKey with",
|
|
23
|
-
"lint:check": "eslint src/ --ext .ts,.tsx,.js,.jsx --max-warnings 0",
|
|
24
|
-
lint: "eslint src/ --ext .ts,.tsx,.js,.jsx --fix",
|
|
25
|
-
prepublish: "npm run build",
|
|
26
|
-
test: "typedoc --emit none",
|
|
27
|
-
tsc: "tsc",
|
|
28
|
-
"update-readme:docs": "rm -rf docs/ && typedoc",
|
|
29
|
-
"update-readme:merge": "../../scripts/transclude-markdown.js",
|
|
30
|
-
"update-readme": "npm run update-readme:docs && npm run update-readme:merge"
|
|
31
|
-
};
|
|
32
|
-
var author = "Peter Szerzo <peter@nlx.ai>";
|
|
33
|
-
var license = "MIT";
|
|
34
|
-
var devDependencies = {
|
|
35
|
-
"@types/isomorphic-fetch": "^0.0.39",
|
|
36
|
-
"@types/node": "^24.10.1",
|
|
37
|
-
"@types/ramda": "0.31.1",
|
|
38
|
-
"@types/uuid": "^9.0.7",
|
|
39
|
-
"concat-md": "^0.5.1",
|
|
40
|
-
"eslint-config-nlx": "*",
|
|
41
|
-
prettier: "^3.1.0",
|
|
42
|
-
"rollup-config-nlx": "*",
|
|
43
|
-
typedoc: "^0.28.14",
|
|
44
|
-
"typedoc-plugin-markdown": "^4.9.0",
|
|
45
|
-
typescript: "^5.5.4"
|
|
46
|
-
};
|
|
47
|
-
var dependencies = {
|
|
48
|
-
"isomorphic-fetch": "^3.0.0",
|
|
49
|
-
ramda: "^0.32.0",
|
|
50
|
-
"reconnecting-websocket": "^4.4.0",
|
|
51
|
-
uuid: "^9.0.1"
|
|
52
|
-
};
|
|
53
|
-
var publishConfig = {
|
|
54
|
-
access: "public"
|
|
55
|
-
};
|
|
56
|
-
var gitHead = "3902161e95745dd4a9cfb68bb469755a62b421f5";
|
|
6
|
+
var version$1 = "1.2.4-alpha.3";
|
|
57
7
|
var packageJson = {
|
|
58
|
-
|
|
59
|
-
version: version$1,
|
|
60
|
-
description: description,
|
|
61
|
-
type: type,
|
|
62
|
-
main: main,
|
|
63
|
-
module: module,
|
|
64
|
-
browser: browser,
|
|
65
|
-
types: types,
|
|
66
|
-
exports: exports,
|
|
67
|
-
scripts: scripts,
|
|
68
|
-
author: author,
|
|
69
|
-
license: license,
|
|
70
|
-
devDependencies: devDependencies,
|
|
71
|
-
dependencies: dependencies,
|
|
72
|
-
publishConfig: publishConfig,
|
|
73
|
-
gitHead: gitHead
|
|
74
|
-
};
|
|
8
|
+
version: version$1};
|
|
75
9
|
|
|
76
10
|
/**
|
|
77
11
|
* Package version
|
|
@@ -161,6 +95,96 @@ const normalizeToHttp = (applicationUrl) => {
|
|
|
161
95
|
const isWebsocketUrl = (url) => {
|
|
162
96
|
return url.indexOf("wss://") === 0;
|
|
163
97
|
};
|
|
98
|
+
const fetchUserMessage = async ({ fullApplicationUrl, headers, body, stream, eventListeners, }) => {
|
|
99
|
+
const streamRequest = async (body) => {
|
|
100
|
+
const response = await fetch(fullApplicationUrl, {
|
|
101
|
+
method: "POST",
|
|
102
|
+
headers: {
|
|
103
|
+
...headers,
|
|
104
|
+
"Content-Type": "application/json",
|
|
105
|
+
"nlx-sdk-version": packageJson.version,
|
|
106
|
+
},
|
|
107
|
+
body: JSON.stringify({ ...body, stream: true }),
|
|
108
|
+
});
|
|
109
|
+
if (!response.ok || response.body == null)
|
|
110
|
+
throw new Error(`HTTP Error: ${response.status}`);
|
|
111
|
+
const reader = response.body.getReader();
|
|
112
|
+
const decoder = new TextDecoder();
|
|
113
|
+
let buffer = "";
|
|
114
|
+
const messages = [];
|
|
115
|
+
let finalResponse = {};
|
|
116
|
+
while (true) {
|
|
117
|
+
const { done, value } = await reader.read();
|
|
118
|
+
if (done)
|
|
119
|
+
break;
|
|
120
|
+
buffer += decoder.decode(value, { stream: true });
|
|
121
|
+
while (true) {
|
|
122
|
+
const openBrace = buffer.indexOf("{");
|
|
123
|
+
if (openBrace === -1)
|
|
124
|
+
break;
|
|
125
|
+
let foundObject = false;
|
|
126
|
+
for (let i = 0; i < buffer.length; i++) {
|
|
127
|
+
if (buffer[i] === "}") {
|
|
128
|
+
const candidate = buffer.substring(openBrace, i + 1);
|
|
129
|
+
try {
|
|
130
|
+
const json = JSON.parse(candidate);
|
|
131
|
+
if (json.type === "interim") {
|
|
132
|
+
const text = json.text;
|
|
133
|
+
if (typeof text === "string") {
|
|
134
|
+
eventListeners.interimMessage.forEach((listener) => {
|
|
135
|
+
listener(text);
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
else if (json.type === "message") {
|
|
140
|
+
messages.push({
|
|
141
|
+
text: json.text,
|
|
142
|
+
choices: json.choices ?? [],
|
|
143
|
+
messageId: json.messageId,
|
|
144
|
+
metadata: json.metadata,
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
else if (json.type === "final_response") {
|
|
148
|
+
finalResponse = json.data;
|
|
149
|
+
}
|
|
150
|
+
buffer = buffer.substring(i + 1);
|
|
151
|
+
foundObject = true;
|
|
152
|
+
break;
|
|
153
|
+
}
|
|
154
|
+
catch (e) {
|
|
155
|
+
/* keep scanning */
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
if (!foundObject)
|
|
160
|
+
break;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
eventListeners.interimMessage.forEach((listener) => {
|
|
164
|
+
listener(undefined);
|
|
165
|
+
});
|
|
166
|
+
return { ...finalResponse, messages };
|
|
167
|
+
};
|
|
168
|
+
if (stream) {
|
|
169
|
+
return await streamRequest(body);
|
|
170
|
+
}
|
|
171
|
+
else {
|
|
172
|
+
const response = await fetch(fullApplicationUrl, {
|
|
173
|
+
method: "POST",
|
|
174
|
+
headers: {
|
|
175
|
+
...(headers ?? {}),
|
|
176
|
+
Accept: "application/json",
|
|
177
|
+
"Content-Type": "application/json",
|
|
178
|
+
"nlx-sdk-version": packageJson.version,
|
|
179
|
+
},
|
|
180
|
+
body: JSON.stringify(body),
|
|
181
|
+
});
|
|
182
|
+
if (!response.ok || response.body == null)
|
|
183
|
+
throw new Error(`HTTP Error: ${response.status}`);
|
|
184
|
+
const json = await response.json();
|
|
185
|
+
return json;
|
|
186
|
+
}
|
|
187
|
+
};
|
|
164
188
|
/**
|
|
165
189
|
* Call this to create a conversation handler.
|
|
166
190
|
* @param configuration - The necessary configuration to create the conversation.
|
|
@@ -191,7 +215,10 @@ function createConversation(configuration) {
|
|
|
191
215
|
if (/[-|_][a-z]{2,}[-|_][A-Z]{2,}$/.test(applicationUrl)) {
|
|
192
216
|
Console.warn("Since v1.0.0, the language code is no longer added at the end of the application URL. Please remove the modifier (e.g. '-en-US') from the URL, and specify it in the `languageCode` parameter instead.");
|
|
193
217
|
}
|
|
194
|
-
const eventListeners = {
|
|
218
|
+
const eventListeners = {
|
|
219
|
+
voicePlusCommand: [],
|
|
220
|
+
interimMessage: [],
|
|
221
|
+
};
|
|
195
222
|
const initialConversationId = configuration.conversationId ?? v4();
|
|
196
223
|
let state = {
|
|
197
224
|
responses: configuration.responses ?? [],
|
|
@@ -303,20 +330,13 @@ function createConversation(configuration) {
|
|
|
303
330
|
}
|
|
304
331
|
else {
|
|
305
332
|
try {
|
|
306
|
-
const
|
|
307
|
-
|
|
308
|
-
headers: {
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
"nlx-sdk-version": packageJson.version,
|
|
313
|
-
},
|
|
314
|
-
body: JSON.stringify(bodyWithContext),
|
|
333
|
+
const json = await fetchUserMessage({
|
|
334
|
+
fullApplicationUrl: fullApplicationHttpUrl(),
|
|
335
|
+
headers: configuration.headers ?? {},
|
|
336
|
+
stream: configuration.experimental?.streamHttp ?? false,
|
|
337
|
+
eventListeners,
|
|
338
|
+
body: bodyWithContext,
|
|
315
339
|
});
|
|
316
|
-
if (res.status >= 400) {
|
|
317
|
-
throw new Error(`Responded with ${res.status}`);
|
|
318
|
-
}
|
|
319
|
-
const json = await res.json();
|
|
320
340
|
messageResponseHandler(json);
|
|
321
341
|
}
|
|
322
342
|
catch (err) {
|
|
@@ -589,6 +609,23 @@ function createConversation(configuration) {
|
|
|
589
609
|
sendFlow(welcomeIntent, context);
|
|
590
610
|
},
|
|
591
611
|
sendChoice,
|
|
612
|
+
submitFeedback: async (feedbackUrl, feedback) => {
|
|
613
|
+
const res = await fetch(feedbackUrl, {
|
|
614
|
+
method: "POST",
|
|
615
|
+
headers: {
|
|
616
|
+
"Content-Type": "application/json",
|
|
617
|
+
},
|
|
618
|
+
body: JSON.stringify({
|
|
619
|
+
languageCode: state.languageCode,
|
|
620
|
+
conversationId: state.conversationId,
|
|
621
|
+
userId: state.userId,
|
|
622
|
+
...feedback,
|
|
623
|
+
}),
|
|
624
|
+
});
|
|
625
|
+
if (res.status >= 400) {
|
|
626
|
+
throw new Error(`Responded with ${res.status}`);
|
|
627
|
+
}
|
|
628
|
+
},
|
|
592
629
|
currentConversationId: () => {
|
|
593
630
|
return state.conversationId;
|
|
594
631
|
},
|