@unboundcx/sdk 2.8.6 → 2.8.8
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 +48 -1
- package/base.js +43 -12
- package/index.js +27 -3
- package/package.json +5 -2
- package/proto/transcription.proto +207 -0
- package/services/ai/SttStream.js +311 -0
- package/services/ai/playbooks.js +958 -0
- package/services/ai.js +1006 -45
- package/services/engagementMetrics.js +6 -2
- package/services/externalOAuth.js +45 -0
- package/services/fax.js +249 -0
- package/services/knowledgeBase.js +229 -0
- package/services/messaging/EmailTemplatesService.js +31 -11
- package/services/messaging/TenDlcCampaignManagementService.js +187 -105
- package/services/messaging/TollFreeCampaignsService.js +263 -110
- package/services/notes.js +27 -2
- package/services/objects.js +92 -3
- package/services/phoneNumbers.js +88 -3
- package/services/portals.js +89 -0
- package/services/sipEndpoints.js +105 -33
- package/services/storage.js +310 -6
- package/services/taskRouter/MetricsService.js +111 -0
- package/services/taskRouter/TaskRouterService.js +12 -0
- package/services/taskRouter/TaskService.js +846 -0
- package/services/taskRouter/WorkerService.js +394 -0
- package/services/taskRouter.js +6 -0
- package/services/video.js +145 -5
- package/services/voice.js +124 -67
- package/services/workflows.js +167 -7
package/services/ai.js
CHANGED
|
@@ -1,8 +1,13 @@
|
|
|
1
|
+
import { PlaybooksService } from './ai/playbooks.js';
|
|
2
|
+
|
|
1
3
|
export class AIService {
|
|
2
4
|
constructor(sdk) {
|
|
3
5
|
this.sdk = sdk;
|
|
4
6
|
this.generative = new GenerativeService(sdk);
|
|
5
7
|
this.tts = new TextToSpeechService(sdk);
|
|
8
|
+
this.stt = new SpeechToTextService(sdk);
|
|
9
|
+
this.extract = new ExtractService(sdk);
|
|
10
|
+
this.playbooks = new PlaybooksService(sdk);
|
|
6
11
|
}
|
|
7
12
|
}
|
|
8
13
|
|
|
@@ -14,43 +19,129 @@ export class GenerativeService {
|
|
|
14
19
|
async chat({
|
|
15
20
|
prompt,
|
|
16
21
|
messages,
|
|
22
|
+
systemPrompt,
|
|
23
|
+
appendSystemPrompt,
|
|
17
24
|
relatedId,
|
|
25
|
+
peopleId,
|
|
26
|
+
companyId,
|
|
27
|
+
provider,
|
|
18
28
|
model,
|
|
19
29
|
temperature,
|
|
30
|
+
maxTokens,
|
|
20
31
|
subscriptionId,
|
|
21
32
|
stream,
|
|
22
|
-
|
|
33
|
+
isPlayground = false,
|
|
34
|
+
responseFormat,
|
|
35
|
+
sessionId,
|
|
36
|
+
scope,
|
|
37
|
+
manageSession,
|
|
38
|
+
tools,
|
|
39
|
+
toolConfig,
|
|
40
|
+
maxToolRounds,
|
|
41
|
+
recordTypeId,
|
|
42
|
+
meta,
|
|
43
|
+
qualityCheck,
|
|
44
|
+
isPublic,
|
|
23
45
|
}) {
|
|
24
46
|
this.sdk.validateParams(
|
|
25
|
-
{
|
|
47
|
+
{
|
|
48
|
+
stream,
|
|
49
|
+
temperature,
|
|
50
|
+
maxTokens,
|
|
51
|
+
subscriptionId,
|
|
52
|
+
provider,
|
|
53
|
+
model,
|
|
54
|
+
prompt,
|
|
55
|
+
messages,
|
|
56
|
+
systemPrompt,
|
|
57
|
+
appendSystemPrompt,
|
|
58
|
+
isPlayground,
|
|
59
|
+
responseFormat,
|
|
60
|
+
sessionId,
|
|
61
|
+
scope,
|
|
62
|
+
manageSession,
|
|
63
|
+
tools,
|
|
64
|
+
toolConfig,
|
|
65
|
+
maxToolRounds,
|
|
66
|
+
recordTypeId,
|
|
67
|
+
peopleId,
|
|
68
|
+
companyId,
|
|
69
|
+
meta,
|
|
70
|
+
qualityCheck,
|
|
71
|
+
isPublic,
|
|
72
|
+
},
|
|
26
73
|
{
|
|
27
74
|
prompt: { type: 'string', required: false },
|
|
28
75
|
messages: { type: 'array', required: false },
|
|
76
|
+
systemPrompt: { type: 'string', required: false },
|
|
77
|
+
appendSystemPrompt: { type: 'string', required: false },
|
|
78
|
+
provider: { type: 'string', required: false },
|
|
29
79
|
model: { type: 'string', required: false },
|
|
30
80
|
temperature: { type: 'number', required: false },
|
|
81
|
+
maxTokens: { type: 'number', required: false },
|
|
31
82
|
subscriptionId: { type: 'string', required: false },
|
|
32
83
|
stream: { type: 'boolean', required: false },
|
|
33
|
-
|
|
84
|
+
isPlayground: { type: 'boolean', required: false },
|
|
85
|
+
responseFormat: { type: 'object', required: false },
|
|
86
|
+
sessionId: { type: 'string', required: false },
|
|
87
|
+
scope: { type: 'string', required: false },
|
|
88
|
+
manageSession: { type: 'boolean', required: false },
|
|
89
|
+
tools: { type: 'array', required: false },
|
|
90
|
+
toolConfig: { type: 'object', required: false },
|
|
91
|
+
maxToolRounds: { type: 'number', required: false },
|
|
92
|
+
recordTypeId: { type: 'string', required: false },
|
|
93
|
+
peopleId: { type: 'string', required: false },
|
|
94
|
+
companyId: { type: 'string', required: false },
|
|
95
|
+
meta: { type: 'object', required: false },
|
|
96
|
+
qualityCheck: { type: 'boolean', required: false },
|
|
97
|
+
isPublic: { type: 'boolean', required: false },
|
|
34
98
|
},
|
|
35
99
|
);
|
|
36
100
|
|
|
37
101
|
const params = {
|
|
38
102
|
body: {
|
|
103
|
+
isPlayground,
|
|
39
104
|
prompt,
|
|
40
105
|
messages,
|
|
106
|
+
systemPrompt,
|
|
107
|
+
appendSystemPrompt,
|
|
41
108
|
relatedId,
|
|
109
|
+
peopleId,
|
|
110
|
+
companyId,
|
|
111
|
+
provider,
|
|
42
112
|
model,
|
|
43
113
|
temperature,
|
|
114
|
+
maxTokens,
|
|
44
115
|
subscriptionId,
|
|
45
116
|
stream,
|
|
46
|
-
|
|
117
|
+
responseFormat,
|
|
118
|
+
sessionId,
|
|
119
|
+
scope,
|
|
120
|
+
manageSession,
|
|
121
|
+
tools,
|
|
122
|
+
toolConfig,
|
|
123
|
+
maxToolRounds,
|
|
124
|
+
recordTypeId,
|
|
125
|
+
meta,
|
|
126
|
+
qualityCheck,
|
|
127
|
+
isPublic,
|
|
47
128
|
},
|
|
48
129
|
// Return raw response for streaming to allow client-side stream handling
|
|
49
130
|
returnRawResponse: stream === true,
|
|
50
131
|
};
|
|
51
132
|
|
|
52
|
-
// Force HTTP transport when streaming
|
|
53
|
-
const
|
|
133
|
+
// Force HTTP transport when streaming or when messages contain large content (too large for NATS)
|
|
134
|
+
const hasLargeContent = messages?.some(
|
|
135
|
+
(m) =>
|
|
136
|
+
Array.isArray(m.content) &&
|
|
137
|
+
m.content.some(
|
|
138
|
+
(c) =>
|
|
139
|
+
c.type === 'image' ||
|
|
140
|
+
c.type === 'image_url' ||
|
|
141
|
+
c.type === 'document',
|
|
142
|
+
),
|
|
143
|
+
);
|
|
144
|
+
const forceFetch = stream === true || hasLargeContent;
|
|
54
145
|
const result = await this.sdk._fetch(
|
|
55
146
|
'/ai/generative/chat',
|
|
56
147
|
'POST',
|
|
@@ -60,55 +151,181 @@ export class GenerativeService {
|
|
|
60
151
|
return result;
|
|
61
152
|
}
|
|
62
153
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
154
|
+
/**
|
|
155
|
+
* Clone an existing chat session into a new one, importing conversation context.
|
|
156
|
+
* Filters out system prompts and tool calls, keeps user/assistant turns.
|
|
157
|
+
* If the transcript exceeds ~50k tokens it is summarized automatically.
|
|
158
|
+
*
|
|
159
|
+
* @param {Object} options
|
|
160
|
+
* @param {string} options.sourceSessionId - Session to clone from (required)
|
|
161
|
+
* @param {string} [options.systemPrompt] - New system prompt (appended after conversation context)
|
|
162
|
+
* @param {string} [options.provider] - LLM provider (falls back to source session)
|
|
163
|
+
* @param {string} [options.model] - Model ID (falls back to source session)
|
|
164
|
+
* @param {Array} [options.tools] - Tool names (falls back to source session)
|
|
165
|
+
* @param {Object} [options.toolConfig] - Tool config (falls back to source session)
|
|
166
|
+
* @param {string} [options.scope] - 'user' or 'account'
|
|
167
|
+
* @param {string} [options.userId] - Owner user ID
|
|
168
|
+
* @param {string} [options.peopleId] - Linked people record
|
|
169
|
+
* @param {string} [options.companyId] - Linked company record
|
|
170
|
+
* @param {string} [options.relatedId] - Linked related record
|
|
171
|
+
* @returns {Promise<Object>} { id, sourceSessionId, wasSummarized }
|
|
172
|
+
*/
|
|
173
|
+
async cloneSession({
|
|
174
|
+
sourceSessionId,
|
|
175
|
+
systemPrompt,
|
|
176
|
+
provider,
|
|
67
177
|
model,
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
178
|
+
tools,
|
|
179
|
+
toolConfig,
|
|
180
|
+
scope,
|
|
181
|
+
userId,
|
|
182
|
+
peopleId,
|
|
183
|
+
companyId,
|
|
184
|
+
relatedId,
|
|
73
185
|
}) {
|
|
74
186
|
this.sdk.validateParams(
|
|
75
|
-
{
|
|
187
|
+
{ sourceSessionId },
|
|
76
188
|
{
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
189
|
+
sourceSessionId: { type: 'string', required: true },
|
|
190
|
+
systemPrompt: { type: 'string', required: false },
|
|
191
|
+
provider: { type: 'string', required: false },
|
|
80
192
|
model: { type: 'string', required: false },
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
193
|
+
tools: { type: 'array', required: false },
|
|
194
|
+
toolConfig: { type: 'object', required: false },
|
|
195
|
+
scope: { type: 'string', required: false },
|
|
196
|
+
userId: { type: 'string', required: false },
|
|
197
|
+
peopleId: { type: 'string', required: false },
|
|
198
|
+
companyId: { type: 'string', required: false },
|
|
199
|
+
relatedId: { type: 'string', required: false },
|
|
86
200
|
},
|
|
87
201
|
);
|
|
88
202
|
|
|
89
203
|
const params = {
|
|
90
204
|
body: {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
205
|
+
sourceSessionId,
|
|
206
|
+
systemPrompt,
|
|
207
|
+
provider,
|
|
94
208
|
model,
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
209
|
+
tools,
|
|
210
|
+
toolConfig,
|
|
211
|
+
scope,
|
|
212
|
+
userId,
|
|
213
|
+
peopleId,
|
|
214
|
+
companyId,
|
|
215
|
+
relatedId,
|
|
100
216
|
},
|
|
101
217
|
};
|
|
102
218
|
|
|
103
219
|
const result = await this.sdk._fetch(
|
|
104
|
-
'/ai/generative/
|
|
220
|
+
'/ai/generative/chat/clone',
|
|
105
221
|
'POST',
|
|
106
222
|
params,
|
|
107
223
|
);
|
|
108
224
|
return result;
|
|
109
225
|
}
|
|
110
226
|
|
|
111
|
-
|
|
227
|
+
/**
|
|
228
|
+
* List available chat tools and their metadata
|
|
229
|
+
* @returns {Promise<Object>} { tools: Array<{ name, label, description, configRequirements }>, count: number }
|
|
230
|
+
*/
|
|
231
|
+
async listTools() {
|
|
232
|
+
return await this.sdk._fetch('/ai/generative/tools', 'GET');
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* List chat sessions visible to the current user
|
|
237
|
+
* @param {Object} [options] - Filter options
|
|
238
|
+
* @param {string} [options.relatedId] - Filter by related object ID
|
|
239
|
+
* @param {string} [options.scope] - Filter by scope ('user' or 'account')
|
|
240
|
+
* @param {number} [options.limit=25] - Results limit
|
|
241
|
+
* @param {number} [options.offset=0] - Pagination offset
|
|
242
|
+
* @returns {Promise<Object>} { sessions: Array }
|
|
243
|
+
*/
|
|
244
|
+
async listSessions({ relatedId, scope, limit, offset } = {}) {
|
|
245
|
+
this.sdk.validateParams(
|
|
246
|
+
{ relatedId, scope, limit, offset },
|
|
247
|
+
{
|
|
248
|
+
relatedId: { type: 'string', required: false },
|
|
249
|
+
scope: { type: 'string', required: false },
|
|
250
|
+
limit: { type: 'number', required: false },
|
|
251
|
+
offset: { type: 'number', required: false },
|
|
252
|
+
},
|
|
253
|
+
);
|
|
254
|
+
|
|
255
|
+
const params = { query: { relatedId, scope, limit, offset } };
|
|
256
|
+
const result = await this.sdk._fetch(
|
|
257
|
+
'/ai/generative/sessions',
|
|
258
|
+
'GET',
|
|
259
|
+
params,
|
|
260
|
+
);
|
|
261
|
+
return result;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* Get a chat session with its message history
|
|
266
|
+
* @param {Object} options
|
|
267
|
+
* @param {string} options.sessionId - Session ID to retrieve
|
|
268
|
+
* @returns {Promise<Object>} { session: { id, name, scope, relatedId, provider, model, messages, messageCount, lastMessageAt, createdAt } }
|
|
269
|
+
*/
|
|
270
|
+
async getSession({ sessionId }) {
|
|
271
|
+
this.sdk.validateParams(
|
|
272
|
+
{ sessionId },
|
|
273
|
+
{ sessionId: { type: 'string', required: true } },
|
|
274
|
+
);
|
|
275
|
+
|
|
276
|
+
const result = await this.sdk._fetch(
|
|
277
|
+
`/ai/generative/sessions/${sessionId}`,
|
|
278
|
+
'GET',
|
|
279
|
+
);
|
|
280
|
+
return result;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Update a chat session (name, scope)
|
|
285
|
+
* @param {Object} options
|
|
286
|
+
* @param {string} options.sessionId - Session ID to update
|
|
287
|
+
* @param {string} [options.name] - New session name
|
|
288
|
+
* @param {string} [options.scope] - New scope ('user' or 'account')
|
|
289
|
+
* @returns {Promise<Object>} { success: true }
|
|
290
|
+
*/
|
|
291
|
+
async updateSession({ sessionId, name, scope }) {
|
|
292
|
+
this.sdk.validateParams(
|
|
293
|
+
{ sessionId, name, scope },
|
|
294
|
+
{
|
|
295
|
+
sessionId: { type: 'string', required: true },
|
|
296
|
+
name: { type: 'string', required: false },
|
|
297
|
+
scope: { type: 'string', required: false },
|
|
298
|
+
},
|
|
299
|
+
);
|
|
300
|
+
|
|
301
|
+
const result = await this.sdk._fetch(
|
|
302
|
+
`/ai/generative/sessions/${sessionId}`,
|
|
303
|
+
'PUT',
|
|
304
|
+
{ body: { name, scope } },
|
|
305
|
+
);
|
|
306
|
+
return result;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* Delete a chat session
|
|
311
|
+
* @param {Object} options
|
|
312
|
+
* @param {string} options.sessionId - Session ID to delete
|
|
313
|
+
* @returns {Promise<Object>} { success: true }
|
|
314
|
+
*/
|
|
315
|
+
async deleteSession({ sessionId }) {
|
|
316
|
+
this.sdk.validateParams(
|
|
317
|
+
{ sessionId },
|
|
318
|
+
{ sessionId: { type: 'string', required: true } },
|
|
319
|
+
);
|
|
320
|
+
|
|
321
|
+
const result = await this.sdk._fetch(
|
|
322
|
+
`/ai/generative/sessions/${sessionId}`,
|
|
323
|
+
'DELETE',
|
|
324
|
+
);
|
|
325
|
+
return result;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
async playbook({
|
|
112
329
|
prompt,
|
|
113
330
|
messages,
|
|
114
331
|
relatedId,
|
|
@@ -116,10 +333,11 @@ export class GenerativeService {
|
|
|
116
333
|
temperature,
|
|
117
334
|
subscriptionId,
|
|
118
335
|
stream,
|
|
119
|
-
|
|
336
|
+
playbookId,
|
|
337
|
+
sessionId,
|
|
120
338
|
}) {
|
|
121
339
|
this.sdk.validateParams(
|
|
122
|
-
{
|
|
340
|
+
{ playbookId },
|
|
123
341
|
{
|
|
124
342
|
prompt: { type: 'string', required: false },
|
|
125
343
|
messages: { type: 'array', required: false },
|
|
@@ -128,7 +346,8 @@ export class GenerativeService {
|
|
|
128
346
|
temperature: { type: 'number', required: false },
|
|
129
347
|
subscriptionId: { type: 'string', required: false },
|
|
130
348
|
stream: { type: 'boolean', required: false },
|
|
131
|
-
|
|
349
|
+
playbookId: { type: 'string', required: true },
|
|
350
|
+
sessionId: { type: 'string', required: false },
|
|
132
351
|
},
|
|
133
352
|
);
|
|
134
353
|
|
|
@@ -141,22 +360,68 @@ export class GenerativeService {
|
|
|
141
360
|
temperature,
|
|
142
361
|
subscriptionId,
|
|
143
362
|
stream,
|
|
144
|
-
|
|
363
|
+
playbookId,
|
|
364
|
+
sessionId,
|
|
145
365
|
},
|
|
146
|
-
// Return raw response for streaming to allow client-side stream handling
|
|
147
|
-
returnRawResponse: stream === true,
|
|
148
366
|
};
|
|
149
367
|
|
|
150
|
-
// Force HTTP transport when streaming is enabled since NATS doesn't support streaming responses
|
|
151
|
-
const forceFetch = stream === true;
|
|
152
368
|
const result = await this.sdk._fetch(
|
|
153
|
-
'/ai/generative/
|
|
369
|
+
'/ai/generative/playbook',
|
|
154
370
|
'POST',
|
|
155
371
|
params,
|
|
156
|
-
forceFetch,
|
|
157
372
|
);
|
|
158
373
|
return result;
|
|
159
374
|
}
|
|
375
|
+
|
|
376
|
+
// async chatOllama({
|
|
377
|
+
// prompt,
|
|
378
|
+
// messages,
|
|
379
|
+
// relatedId,
|
|
380
|
+
// model,
|
|
381
|
+
// temperature,
|
|
382
|
+
// subscriptionId,
|
|
383
|
+
// stream,
|
|
384
|
+
// method,
|
|
385
|
+
// }) {
|
|
386
|
+
// this.sdk.validateParams(
|
|
387
|
+
// { method },
|
|
388
|
+
// {
|
|
389
|
+
// prompt: { type: 'string', required: false },
|
|
390
|
+
// messages: { type: 'array', required: false },
|
|
391
|
+
// relatedId: { type: 'string', required: false },
|
|
392
|
+
// model: { type: 'string', required: false },
|
|
393
|
+
// temperature: { type: 'number', required: false },
|
|
394
|
+
// subscriptionId: { type: 'string', required: false },
|
|
395
|
+
// stream: { type: 'boolean', required: false },
|
|
396
|
+
// method: { type: 'string', required: true },
|
|
397
|
+
// },
|
|
398
|
+
// );
|
|
399
|
+
|
|
400
|
+
// const params = {
|
|
401
|
+
// body: {
|
|
402
|
+
// prompt,
|
|
403
|
+
// messages,
|
|
404
|
+
// relatedId,
|
|
405
|
+
// model,
|
|
406
|
+
// temperature,
|
|
407
|
+
// subscriptionId,
|
|
408
|
+
// stream,
|
|
409
|
+
// method,
|
|
410
|
+
// },
|
|
411
|
+
// // Return raw response for streaming to allow client-side stream handling
|
|
412
|
+
// returnRawResponse: stream === true,
|
|
413
|
+
// };
|
|
414
|
+
|
|
415
|
+
// // Force HTTP transport when streaming is enabled since NATS doesn't support streaming responses
|
|
416
|
+
// const forceFetch = stream === true;
|
|
417
|
+
// const result = await this.sdk._fetch(
|
|
418
|
+
// '/ai/generative/ollama',
|
|
419
|
+
// 'POST',
|
|
420
|
+
// params,
|
|
421
|
+
// forceFetch,
|
|
422
|
+
// );
|
|
423
|
+
// return result;
|
|
424
|
+
// }
|
|
160
425
|
}
|
|
161
426
|
|
|
162
427
|
export class TextToSpeechService {
|
|
@@ -174,9 +439,21 @@ export class TextToSpeechService {
|
|
|
174
439
|
pitch,
|
|
175
440
|
volumeGainDb,
|
|
176
441
|
effectsProfileIds,
|
|
442
|
+
createAccessKey,
|
|
177
443
|
}) {
|
|
178
444
|
this.sdk.validateParams(
|
|
179
|
-
{
|
|
445
|
+
{
|
|
446
|
+
text,
|
|
447
|
+
voice,
|
|
448
|
+
languageCode,
|
|
449
|
+
ssmlGender,
|
|
450
|
+
audioEncoding,
|
|
451
|
+
speakingRate,
|
|
452
|
+
pitch,
|
|
453
|
+
volumeGainDb,
|
|
454
|
+
effectsProfileIds,
|
|
455
|
+
createAccessKey,
|
|
456
|
+
},
|
|
180
457
|
{
|
|
181
458
|
text: { type: 'string', required: true },
|
|
182
459
|
voice: { type: 'string', required: false },
|
|
@@ -187,6 +464,7 @@ export class TextToSpeechService {
|
|
|
187
464
|
pitch: { type: 'number', required: false },
|
|
188
465
|
volumeGainDb: { type: 'number', required: false },
|
|
189
466
|
effectsProfileIds: { type: 'array', required: false },
|
|
467
|
+
createAccessKey: { type: 'boolean', required: false },
|
|
190
468
|
},
|
|
191
469
|
);
|
|
192
470
|
|
|
@@ -199,6 +477,7 @@ export class TextToSpeechService {
|
|
|
199
477
|
if (pitch) ttsData.pitch = pitch;
|
|
200
478
|
if (volumeGainDb) ttsData.volumeGainDb = volumeGainDb;
|
|
201
479
|
if (effectsProfileIds) ttsData.effectsProfileIds = effectsProfileIds;
|
|
480
|
+
if (createAccessKey) ttsData.createAccessKey = createAccessKey;
|
|
202
481
|
|
|
203
482
|
const params = {
|
|
204
483
|
body: ttsData,
|
|
@@ -207,4 +486,686 @@ export class TextToSpeechService {
|
|
|
207
486
|
const result = await this.sdk._fetch('/ai/tts', 'POST', params);
|
|
208
487
|
return result;
|
|
209
488
|
}
|
|
489
|
+
|
|
490
|
+
/**
|
|
491
|
+
* List available TTS voices
|
|
492
|
+
* @returns {Promise<Object>} { voices: Array, count: number, supportedEncodings: Array, supportedLanguages: Array }
|
|
493
|
+
*/
|
|
494
|
+
async list() {
|
|
495
|
+
const result = await this.sdk._fetch('/ai/tts', 'GET');
|
|
496
|
+
return result;
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
export class SpeechToTextService {
|
|
501
|
+
constructor(sdk) {
|
|
502
|
+
this.sdk = sdk;
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
/**
|
|
506
|
+
* Create a transcription from file or storage
|
|
507
|
+
* @param {Object} options - Transcription options
|
|
508
|
+
* @param {string} options.sourceType - 'file', 'storage', 'stream', or 'url'
|
|
509
|
+
* @param {string} [options.sourceId] - Source identifier
|
|
510
|
+
* @param {string} [options.storageId] - Storage ID if using storage
|
|
511
|
+
* @param {string} [options.engine='google'] - STT engine ('google', 'deepgram', 'whisper')
|
|
512
|
+
* @param {string} [options.languageCode='en-US'] - BCP-47 language code
|
|
513
|
+
* @param {Object} [options.metadata] - Engine-specific configuration
|
|
514
|
+
* @param {string} [options.engagementSessionId] - Engagement session ID
|
|
515
|
+
* @param {string} [options.playbookId] - Playbook ID
|
|
516
|
+
* @param {string} [options.name] - Transcription name
|
|
517
|
+
* @param {string} [options.role] - Speaker role
|
|
518
|
+
* @param {string} [options.direction] - Call direction
|
|
519
|
+
* @returns {Promise<Object>} Transcription result
|
|
520
|
+
*/
|
|
521
|
+
async create({
|
|
522
|
+
sourceType,
|
|
523
|
+
sourceId,
|
|
524
|
+
sipCallId,
|
|
525
|
+
cdrId,
|
|
526
|
+
storageId,
|
|
527
|
+
engine,
|
|
528
|
+
languageCode,
|
|
529
|
+
metadata,
|
|
530
|
+
engagementSessionId,
|
|
531
|
+
playbookId,
|
|
532
|
+
name,
|
|
533
|
+
role,
|
|
534
|
+
direction,
|
|
535
|
+
}) {
|
|
536
|
+
this.sdk.validateParams(
|
|
537
|
+
{
|
|
538
|
+
sourceType,
|
|
539
|
+
sourceId,
|
|
540
|
+
sipCallId,
|
|
541
|
+
cdrId,
|
|
542
|
+
storageId,
|
|
543
|
+
engine,
|
|
544
|
+
languageCode,
|
|
545
|
+
metadata,
|
|
546
|
+
engagementSessionId,
|
|
547
|
+
playbookId,
|
|
548
|
+
name,
|
|
549
|
+
role,
|
|
550
|
+
direction,
|
|
551
|
+
},
|
|
552
|
+
{
|
|
553
|
+
sourceType: { type: 'string', required: true },
|
|
554
|
+
sourceId: { type: 'string', required: false },
|
|
555
|
+
sipCallId: { type: 'string', required: false },
|
|
556
|
+
cdrId: { type: 'string', required: false },
|
|
557
|
+
storageId: { type: 'string', required: false },
|
|
558
|
+
engine: { type: 'string', required: false },
|
|
559
|
+
languageCode: { type: 'string', required: false },
|
|
560
|
+
metadata: { type: 'object', required: false },
|
|
561
|
+
engagementSessionId: { type: 'string', required: false },
|
|
562
|
+
playbookId: { type: 'string', required: false },
|
|
563
|
+
name: { type: 'string', required: false },
|
|
564
|
+
role: { type: 'string', required: false },
|
|
565
|
+
direction: { type: 'string', required: false },
|
|
566
|
+
},
|
|
567
|
+
);
|
|
568
|
+
|
|
569
|
+
const params = {
|
|
570
|
+
body: {
|
|
571
|
+
sourceType,
|
|
572
|
+
sourceId,
|
|
573
|
+
sipCallId,
|
|
574
|
+
cdrId,
|
|
575
|
+
storageId,
|
|
576
|
+
engine,
|
|
577
|
+
languageCode,
|
|
578
|
+
metadata,
|
|
579
|
+
engagementSessionId,
|
|
580
|
+
playbookId,
|
|
581
|
+
name,
|
|
582
|
+
role,
|
|
583
|
+
direction,
|
|
584
|
+
},
|
|
585
|
+
};
|
|
586
|
+
|
|
587
|
+
const result = await this.sdk._fetch('/ai/stt', 'POST', params);
|
|
588
|
+
return result;
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
/**
|
|
592
|
+
* Create a real-time streaming transcription session
|
|
593
|
+
* Returns an EventEmitter-based stream for sending audio and receiving transcripts
|
|
594
|
+
*
|
|
595
|
+
* @param {Object} options - Stream options
|
|
596
|
+
* @param {string} [options.engine='google'] - STT engine ('google' or 'whisper')
|
|
597
|
+
* @param {string} [options.model] - STT model (e.g., 'phone_call' for Google)
|
|
598
|
+
* @param {string} [options.languageCode='en-US'] - BCP-47 language code
|
|
599
|
+
* @param {string} [options.encoding='LINEAR16'] - Audio encoding format
|
|
600
|
+
* @param {number} [options.sampleRateHertz=16000] - Sample rate in Hertz
|
|
601
|
+
* @param {number} [options.audioChannelCount=1] - Number of audio channels (1=mono, 2=stereo)
|
|
602
|
+
* @param {boolean} [options.singleUtterance=false] - Stop after first utterance
|
|
603
|
+
* @param {boolean} [options.interimResults=true] - Return interim results
|
|
604
|
+
* @param {boolean} [options.enableAutomaticPunctuation=true] - Enable automatic punctuation
|
|
605
|
+
* @param {boolean} [options.diarizationEnabled=false] - Enable speaker diarization
|
|
606
|
+
* @param {number} [options.speakerCount] - Number of speakers (if diarization enabled)
|
|
607
|
+
* @param {boolean} [options.vadEnabled=false] - Enable Voice Activity Detection
|
|
608
|
+
* @param {number} [options.minSilenceDuration=500] - Min silence duration in ms (for VAD)
|
|
609
|
+
* @param {number} [options.speechPadMs=400] - Speech padding in ms (for VAD)
|
|
610
|
+
* @param {string} [options.engagementSessionId] - Engagement session ID
|
|
611
|
+
* @param {string} [options.playbookId] - Playbook ID
|
|
612
|
+
* @param {string} [options.name] - Session name
|
|
613
|
+
* @param {Object} [options.metadata] - Additional metadata
|
|
614
|
+
* @returns {Promise<SttStream>} Stream object with write() method and transcript events
|
|
615
|
+
*
|
|
616
|
+
* @example
|
|
617
|
+
* const stream = await sdk.ai.stt.stream({ engine: 'google', languageCode: 'en-US' });
|
|
618
|
+
* stream.on('transcript', (result) => console.log(result.text, result.isFinal));
|
|
619
|
+
* stream.on('error', (error) => console.error(error));
|
|
620
|
+
* stream.on('close', () => console.log('Stream closed'));
|
|
621
|
+
* stream.write(audioChunk);
|
|
622
|
+
* stream.end();
|
|
623
|
+
*/
|
|
624
|
+
async stream(options = {}) {
|
|
625
|
+
// Environment check - STT streaming only works in Node.js
|
|
626
|
+
if (this.sdk.environment !== 'node') {
|
|
627
|
+
throw new Error(
|
|
628
|
+
'STT streaming requires Node.js environment. ' +
|
|
629
|
+
'This feature is only available in backend services. ' +
|
|
630
|
+
'Browser-based streaming is not supported.',
|
|
631
|
+
);
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
const {
|
|
635
|
+
engine = 'google',
|
|
636
|
+
model,
|
|
637
|
+
languageCode = 'en-US',
|
|
638
|
+
encoding = 'LINEAR16',
|
|
639
|
+
sampleRateHertz = 16000,
|
|
640
|
+
audioChannelCount = 1,
|
|
641
|
+
singleUtterance = false,
|
|
642
|
+
interimResults = true,
|
|
643
|
+
enableAutomaticPunctuation = true,
|
|
644
|
+
diarizationEnabled = false,
|
|
645
|
+
speakerCount,
|
|
646
|
+
vadEnabled = false,
|
|
647
|
+
minSilenceDuration = 500,
|
|
648
|
+
speechPadMs = 400,
|
|
649
|
+
engagementSessionId,
|
|
650
|
+
playbookId,
|
|
651
|
+
taskId,
|
|
652
|
+
workerId,
|
|
653
|
+
generateSubject,
|
|
654
|
+
generateTranscriptSummary,
|
|
655
|
+
generateSentiment,
|
|
656
|
+
bridgeId,
|
|
657
|
+
name,
|
|
658
|
+
metadata,
|
|
659
|
+
sipCallId,
|
|
660
|
+
cdrId,
|
|
661
|
+
} = options;
|
|
662
|
+
|
|
663
|
+
// Validate parameters
|
|
664
|
+
this.sdk.validateParams(
|
|
665
|
+
{
|
|
666
|
+
engine,
|
|
667
|
+
model,
|
|
668
|
+
languageCode,
|
|
669
|
+
encoding,
|
|
670
|
+
sampleRateHertz,
|
|
671
|
+
audioChannelCount,
|
|
672
|
+
singleUtterance,
|
|
673
|
+
interimResults,
|
|
674
|
+
enableAutomaticPunctuation,
|
|
675
|
+
diarizationEnabled,
|
|
676
|
+
speakerCount,
|
|
677
|
+
vadEnabled,
|
|
678
|
+
minSilenceDuration,
|
|
679
|
+
speechPadMs,
|
|
680
|
+
engagementSessionId,
|
|
681
|
+
playbookId,
|
|
682
|
+
taskId,
|
|
683
|
+
workerId,
|
|
684
|
+
generateSubject,
|
|
685
|
+
generateTranscriptSummary,
|
|
686
|
+
generateSentiment,
|
|
687
|
+
bridgeId,
|
|
688
|
+
name,
|
|
689
|
+
metadata,
|
|
690
|
+
sipCallId,
|
|
691
|
+
cdrId,
|
|
692
|
+
},
|
|
693
|
+
{
|
|
694
|
+
engine: { type: 'string', required: false },
|
|
695
|
+
model: { type: 'string', required: false },
|
|
696
|
+
languageCode: { type: 'string', required: false },
|
|
697
|
+
encoding: { type: 'string', required: false },
|
|
698
|
+
sampleRateHertz: { type: 'number', required: false },
|
|
699
|
+
audioChannelCount: { type: 'number', required: false },
|
|
700
|
+
singleUtterance: { type: 'boolean', required: false },
|
|
701
|
+
interimResults: { type: 'boolean', required: false },
|
|
702
|
+
enableAutomaticPunctuation: { type: 'boolean', required: false },
|
|
703
|
+
diarizationEnabled: { type: 'boolean', required: false },
|
|
704
|
+
speakerCount: { type: 'number', required: false },
|
|
705
|
+
vadEnabled: { type: 'boolean', required: false },
|
|
706
|
+
minSilenceDuration: { type: 'number', required: false },
|
|
707
|
+
speechPadMs: { type: 'number', required: false },
|
|
708
|
+
engagementSessionId: { type: 'string', required: false },
|
|
709
|
+
playbookId: { type: 'string', required: false },
|
|
710
|
+
taskId: { type: 'string', required: false },
|
|
711
|
+
workerId: { type: 'string', required: false },
|
|
712
|
+
generateSubject: { type: 'boolean', required: false },
|
|
713
|
+
generateTranscriptSummary: { type: 'boolean', required: false },
|
|
714
|
+
generateSentiment: { type: 'boolean', required: false },
|
|
715
|
+
bridgeId: { type: 'string', required: false },
|
|
716
|
+
name: { type: 'string', required: false },
|
|
717
|
+
metadata: { type: 'object', required: false },
|
|
718
|
+
sipCallId: { type: 'string', required: false },
|
|
719
|
+
cdrId: { type: 'string', required: false },
|
|
720
|
+
},
|
|
721
|
+
);
|
|
722
|
+
|
|
723
|
+
// Create session via API
|
|
724
|
+
const sessionParams = {
|
|
725
|
+
body: {
|
|
726
|
+
engine,
|
|
727
|
+
model,
|
|
728
|
+
engagementSessionId,
|
|
729
|
+
playbookId,
|
|
730
|
+
taskId,
|
|
731
|
+
workerId,
|
|
732
|
+
generateSubject,
|
|
733
|
+
generateTranscriptSummary,
|
|
734
|
+
generateSentiment,
|
|
735
|
+
bridgeId,
|
|
736
|
+
sipCallId,
|
|
737
|
+
cdrId,
|
|
738
|
+
name,
|
|
739
|
+
metadata: {
|
|
740
|
+
...metadata,
|
|
741
|
+
languageCode,
|
|
742
|
+
encoding,
|
|
743
|
+
sampleRateHertz,
|
|
744
|
+
audioChannelCount,
|
|
745
|
+
singleUtterance,
|
|
746
|
+
interimResults,
|
|
747
|
+
enableAutomaticPunctuation,
|
|
748
|
+
diarizationEnabled,
|
|
749
|
+
speakerCount,
|
|
750
|
+
vadEnabled,
|
|
751
|
+
minSilenceDuration,
|
|
752
|
+
speechPadMs,
|
|
753
|
+
},
|
|
754
|
+
},
|
|
755
|
+
};
|
|
756
|
+
|
|
757
|
+
const session = await this.sdk._fetch(
|
|
758
|
+
'/ai/stt/stream',
|
|
759
|
+
'POST',
|
|
760
|
+
sessionParams,
|
|
761
|
+
);
|
|
762
|
+
|
|
763
|
+
// Dynamic import of SttStream (only loads when needed)
|
|
764
|
+
const { SttStream } = await import('./ai/SttStream.js');
|
|
765
|
+
|
|
766
|
+
// Create and return stream instance
|
|
767
|
+
const streamOptions = {
|
|
768
|
+
...options,
|
|
769
|
+
languageCode,
|
|
770
|
+
encoding,
|
|
771
|
+
sampleRateHertz,
|
|
772
|
+
audioChannelCount,
|
|
773
|
+
vadEnabled,
|
|
774
|
+
minSilenceDuration,
|
|
775
|
+
speechPadMs,
|
|
776
|
+
};
|
|
777
|
+
|
|
778
|
+
return new SttStream(this.sdk, session, streamOptions);
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
/**
|
|
782
|
+
* Get a transcription by ID
|
|
783
|
+
* @param {string} id - Transcription ID
|
|
784
|
+
* @param {Object} [options] - Retrieval options
|
|
785
|
+
* @param {boolean} [options.includeMessages=true] - Include transcription messages
|
|
786
|
+
* @returns {Promise<Object>} Transcription data
|
|
787
|
+
*/
|
|
788
|
+
async get(id, { includeMessages = true } = {}) {
|
|
789
|
+
this.sdk.validateParams(
|
|
790
|
+
{ id },
|
|
791
|
+
{
|
|
792
|
+
id: { type: 'string', required: true },
|
|
793
|
+
includeMessages: { type: 'boolean', required: false },
|
|
794
|
+
},
|
|
795
|
+
);
|
|
796
|
+
|
|
797
|
+
const params = {
|
|
798
|
+
query: { includeMessages: includeMessages.toString() },
|
|
799
|
+
};
|
|
800
|
+
|
|
801
|
+
const result = await this.sdk._fetch(`/ai/stt/${id}`, 'GET', params);
|
|
802
|
+
return result;
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
/**
|
|
806
|
+
* List transcriptions with filters
|
|
807
|
+
* @param {Object} [filters] - Filter options
|
|
808
|
+
* @param {string} [filters.engagementSessionId] - Filter by engagement session
|
|
809
|
+
* @param {string} [filters.userId] - Filter by user
|
|
810
|
+
* @param {string} [filters.status] - Filter by status
|
|
811
|
+
* @param {string} [filters.engine] - Filter by engine
|
|
812
|
+
* @param {string} [filters.sourceType] - Filter by source type
|
|
813
|
+
* @param {string} [filters.playbookId] - Filter by playbook
|
|
814
|
+
* @param {string} [filters.startDate] - Filter by start date
|
|
815
|
+
* @param {string} [filters.endDate] - Filter by end date
|
|
816
|
+
* @param {number} [filters.limit=50] - Limit results
|
|
817
|
+
* @param {number} [filters.offset=0] - Offset for pagination
|
|
818
|
+
* @returns {Promise<Object>} List of transcriptions
|
|
819
|
+
*/
|
|
820
|
+
async list(filters = {}) {
|
|
821
|
+
this.sdk.validateParams(filters, {
|
|
822
|
+
engagementSessionId: { type: 'string', required: false },
|
|
823
|
+
userId: { type: 'string', required: false },
|
|
824
|
+
status: { type: 'string', required: false },
|
|
825
|
+
engine: { type: 'string', required: false },
|
|
826
|
+
sourceType: { type: 'string', required: false },
|
|
827
|
+
playbookId: { type: 'string', required: false },
|
|
828
|
+
startDate: { type: 'string', required: false },
|
|
829
|
+
endDate: { type: 'string', required: false },
|
|
830
|
+
limit: { type: 'number', required: false },
|
|
831
|
+
offset: { type: 'number', required: false },
|
|
832
|
+
});
|
|
833
|
+
|
|
834
|
+
const params = {
|
|
835
|
+
query: filters,
|
|
836
|
+
};
|
|
837
|
+
|
|
838
|
+
const result = await this.sdk._fetch('/ai/stt', 'GET', params);
|
|
839
|
+
return result;
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
/**
|
|
843
|
+
* Log a transcription message for a streaming session
|
|
844
|
+
* @param {string} sessionId - Transcription session ID
|
|
845
|
+
* @param {string} messageId - message id for the transcription
|
|
846
|
+
* @param {number} timestamp - message timestamp (unix)
|
|
847
|
+
* @param {Object} message - Message data
|
|
848
|
+
* @param {string} message.text - Transcribed text
|
|
849
|
+
* @param {Object} [message.transcriptionJson] - Full transcription metadata
|
|
850
|
+
* @param {number} [message.duration] - Duration of this segment in seconds
|
|
851
|
+
* @param {number} [message.confidence] - Confidence score (0-1)
|
|
852
|
+
* @param {string} [message.languageCode] - Language code for this segment
|
|
853
|
+
* @param {string} [message.userId] - User associated with this message
|
|
854
|
+
* @param {string} [message.role] - Speaker role
|
|
855
|
+
* @param {string} [message.sipCallId] - SIP call identifier
|
|
856
|
+
* @param {string} [message.side] - Stream side ('send' or 'recv')
|
|
857
|
+
* @param {string} [message.bridgeId] - bridge id
|
|
858
|
+
* @param {Object} [message.sentiment] - Sentiment analysis data
|
|
859
|
+
* @param {number} [message.sentiment.score] - Overall sentiment score (-100 to +100)
|
|
860
|
+
* @param {number} [message.sentiment.previousScore] - Previous sentiment score (-100 to +100)
|
|
861
|
+
* @param {number} [message.sentiment.delta] - Score change (score - previousScore)
|
|
862
|
+
* @param {number} [message.sentiment.customerScore] - Customer sentiment score (-100 to +100)
|
|
863
|
+
* @param {number} [message.sentiment.agentScore] - Agent sentiment score (-100 to +100)
|
|
864
|
+
* @param {number} [message.sentiment.intensity] - Sentiment intensity (0 to 1)
|
|
865
|
+
* @param {string[]} [message.sentiment.emotions] - Detected emotions (up to 3)
|
|
866
|
+
* @param {string} [message.sentiment.trend] - Sentiment trend ('improving' | 'stable' | 'declining')
|
|
867
|
+
* @param {string} [message.sentiment.source] - Analysis source ('llm+acoustic' | 'acoustic_only' | 'carry_forward')
|
|
868
|
+
* @returns {Promise<Object>} Created message result
|
|
869
|
+
*/
|
|
870
|
+
async logMessage(
|
|
871
|
+
sessionId,
|
|
872
|
+
{
|
|
873
|
+
messageId,
|
|
874
|
+
timestamp,
|
|
875
|
+
text,
|
|
876
|
+
transcriptionJson,
|
|
877
|
+
duration,
|
|
878
|
+
confidence,
|
|
879
|
+
languageCode,
|
|
880
|
+
userId,
|
|
881
|
+
role,
|
|
882
|
+
sipCallId,
|
|
883
|
+
side,
|
|
884
|
+
bridgeId,
|
|
885
|
+
sentiment,
|
|
886
|
+
},
|
|
887
|
+
) {
|
|
888
|
+
this.sdk.validateParams(
|
|
889
|
+
{ messageId, sessionId, text, bridgeId },
|
|
890
|
+
{
|
|
891
|
+
sessionId: { type: 'string', required: true },
|
|
892
|
+
messageId: { type: 'string', required: false },
|
|
893
|
+
timestamp: { type: 'number', required: false },
|
|
894
|
+
text: { type: 'string', required: true },
|
|
895
|
+
transcriptionJson: { type: 'object', required: false },
|
|
896
|
+
duration: { type: 'number', required: false },
|
|
897
|
+
confidence: { type: 'number', required: false },
|
|
898
|
+
languageCode: { type: 'string', required: false },
|
|
899
|
+
userId: { type: 'string', required: false },
|
|
900
|
+
role: { type: 'string', required: false },
|
|
901
|
+
sipCallId: { type: 'string', required: false },
|
|
902
|
+
side: { type: 'string', required: false },
|
|
903
|
+
bridgeId: { type: 'string', required: false },
|
|
904
|
+
sentiment: { type: 'object', required: false },
|
|
905
|
+
},
|
|
906
|
+
);
|
|
907
|
+
|
|
908
|
+
const params = {
|
|
909
|
+
body: {
|
|
910
|
+
messageId,
|
|
911
|
+
timestamp,
|
|
912
|
+
text,
|
|
913
|
+
transcriptionJson,
|
|
914
|
+
duration,
|
|
915
|
+
confidence,
|
|
916
|
+
languageCode,
|
|
917
|
+
userId,
|
|
918
|
+
role,
|
|
919
|
+
sipCallId,
|
|
920
|
+
side,
|
|
921
|
+
bridgeId,
|
|
922
|
+
sentiment,
|
|
923
|
+
},
|
|
924
|
+
};
|
|
925
|
+
|
|
926
|
+
const result = await this.sdk._fetch(
|
|
927
|
+
`/ai/stt/stream/${sessionId}/messages`,
|
|
928
|
+
'POST',
|
|
929
|
+
params,
|
|
930
|
+
);
|
|
931
|
+
return result;
|
|
932
|
+
}
|
|
933
|
+
|
|
934
|
+
/**
|
|
935
|
+
* Complete a streaming transcription session
|
|
936
|
+
* @param {string} sessionId - Transcription session ID
|
|
937
|
+
* @param {Object} [options] - Completion options
|
|
938
|
+
* @param {string} [options.status='completed'] - Final status ('completed' or 'failed')
|
|
939
|
+
* @param {string} [options.error] - Error message if status is 'failed'
|
|
940
|
+
* @returns {Promise<Object>} Completion result
|
|
941
|
+
*/
|
|
942
|
+
async complete(sessionId, { status = 'completed', error } = {}) {
|
|
943
|
+
this.sdk.validateParams(
|
|
944
|
+
{ sessionId },
|
|
945
|
+
{
|
|
946
|
+
sessionId: { type: 'string', required: true },
|
|
947
|
+
status: { type: 'string', required: false },
|
|
948
|
+
error: { type: 'string', required: false },
|
|
949
|
+
},
|
|
950
|
+
);
|
|
951
|
+
|
|
952
|
+
const params = {
|
|
953
|
+
body: { status, error },
|
|
954
|
+
};
|
|
955
|
+
|
|
956
|
+
const result = await this.sdk._fetch(
|
|
957
|
+
`/ai/stt/stream/${sessionId}/complete`,
|
|
958
|
+
'PUT',
|
|
959
|
+
params,
|
|
960
|
+
);
|
|
961
|
+
return result;
|
|
962
|
+
}
|
|
963
|
+
}
|
|
964
|
+
|
|
965
|
+
// STT Constants
|
|
966
|
+
export const STT = {
|
|
967
|
+
ENGINES: {
|
|
968
|
+
GOOGLE: 'google',
|
|
969
|
+
DEEPGRAM: 'deepgram',
|
|
970
|
+
WHISPER: 'whisper',
|
|
971
|
+
},
|
|
972
|
+
SOURCE_TYPES: {
|
|
973
|
+
FILE: 'file',
|
|
974
|
+
STORAGE: 'storage',
|
|
975
|
+
STREAM: 'stream',
|
|
976
|
+
URL: 'url',
|
|
977
|
+
},
|
|
978
|
+
STATUS: {
|
|
979
|
+
PENDING: 'pending',
|
|
980
|
+
PROCESSING: 'processing',
|
|
981
|
+
COMPLETED: 'completed',
|
|
982
|
+
FAILED: 'failed',
|
|
983
|
+
},
|
|
984
|
+
LANGUAGES: {
|
|
985
|
+
EN_US: 'en-US',
|
|
986
|
+
EN_GB: 'en-GB',
|
|
987
|
+
EN_AU: 'en-AU',
|
|
988
|
+
ES_ES: 'es-ES',
|
|
989
|
+
ES_MX: 'es-MX',
|
|
990
|
+
ES_US: 'es-US',
|
|
991
|
+
FR_FR: 'fr-FR',
|
|
992
|
+
FR_CA: 'fr-CA',
|
|
993
|
+
DE_DE: 'de-DE',
|
|
994
|
+
IT_IT: 'it-IT',
|
|
995
|
+
PT_BR: 'pt-BR',
|
|
996
|
+
PT_PT: 'pt-PT',
|
|
997
|
+
ZH_CN: 'zh-CN',
|
|
998
|
+
JA_JP: 'ja-JP',
|
|
999
|
+
KO_KR: 'ko-KR',
|
|
1000
|
+
},
|
|
1001
|
+
};
|
|
1002
|
+
|
|
1003
|
+
export class ExtractService {
|
|
1004
|
+
constructor(sdk) {
|
|
1005
|
+
this.sdk = sdk;
|
|
1006
|
+
}
|
|
1007
|
+
|
|
1008
|
+
/**
|
|
1009
|
+
* Extract phone number from text
|
|
1010
|
+
* @param {Object} options - Extraction options
|
|
1011
|
+
* @param {string} options.value - Text containing phone number
|
|
1012
|
+
* @param {string} [options.country='US'] - Country code for validation
|
|
1013
|
+
* @param {string} [options.format='E164'] - Output format: 'E164', 'national', 'international'
|
|
1014
|
+
* @returns {Promise<Object>} { isValid, parsedValue, confidence, metadata: { country, type, nationalNumber, ... } }
|
|
1015
|
+
*/
|
|
1016
|
+
async phone({ value, country = 'US', format = 'E164' }) {
|
|
1017
|
+
return this._extract('phone', value, { country, format });
|
|
1018
|
+
}
|
|
1019
|
+
|
|
1020
|
+
/**
|
|
1021
|
+
* Extract email address from text
|
|
1022
|
+
* @param {Object} options - Extraction options
|
|
1023
|
+
* @param {string} options.value - Text containing email
|
|
1024
|
+
* @returns {Promise<Object>} { isValid, parsedValue, confidence, metadata: { domain } }
|
|
1025
|
+
*/
|
|
1026
|
+
async email({ value }) {
|
|
1027
|
+
return this._extract('email', value);
|
|
1028
|
+
}
|
|
1029
|
+
|
|
1030
|
+
/**
|
|
1031
|
+
* Extract physical address from text
|
|
1032
|
+
* @param {Object} options - Extraction options
|
|
1033
|
+
* @param {string} options.value - Text containing address
|
|
1034
|
+
* @param {boolean} [options.useAI=false] - Use AI for better extraction from conversational text
|
|
1035
|
+
* @returns {Promise<Object>} { isValid, parsedValue, confidence, metadata: { components } }
|
|
1036
|
+
*/
|
|
1037
|
+
async address({ value, useAI = false }) {
|
|
1038
|
+
return this._extract('address', value, { useAI });
|
|
1039
|
+
}
|
|
1040
|
+
|
|
1041
|
+
/**
|
|
1042
|
+
* Extract person's name from text
|
|
1043
|
+
* @param {Object} options - Extraction options
|
|
1044
|
+
* @param {string} options.value - Text containing name
|
|
1045
|
+
* @param {boolean} [options.useAI=true] - Use AI for extraction from conversational text
|
|
1046
|
+
* @returns {Promise<Object>} { isValid, parsedValue, firstName, lastName, title }
|
|
1047
|
+
*/
|
|
1048
|
+
async personName({ value, useAI = true }) {
|
|
1049
|
+
return this._extract('personName', value, { useAI });
|
|
1050
|
+
}
|
|
1051
|
+
|
|
1052
|
+
/**
|
|
1053
|
+
* Extract and validate credit card number (masked for security)
|
|
1054
|
+
* @param {Object} options - Extraction options
|
|
1055
|
+
* @param {string} options.value - Text containing credit card
|
|
1056
|
+
* @param {boolean} [options.maskOutput=true] - Mask all but last 4 digits
|
|
1057
|
+
* @returns {Promise<Object>} { isValid, parsedValue (masked), confidence, metadata: { cardType, length } }
|
|
1058
|
+
*/
|
|
1059
|
+
async creditCard({ value, maskOutput = true }) {
|
|
1060
|
+
return this._extract('creditCard', value, { maskOutput });
|
|
1061
|
+
}
|
|
1062
|
+
|
|
1063
|
+
/**
|
|
1064
|
+
* Extract and validate SSN (masked for security)
|
|
1065
|
+
* @param {Object} options - Extraction options
|
|
1066
|
+
* @param {string} options.value - Text containing SSN
|
|
1067
|
+
* @param {boolean} [options.maskOutput=true] - Mask all but last 4 digits
|
|
1068
|
+
* @returns {Promise<Object>} { isValid, parsedValue (masked), confidence, metadata }
|
|
1069
|
+
*/
|
|
1070
|
+
async ssn({ value, maskOutput = true }) {
|
|
1071
|
+
return this._extract('ssn', value, { maskOutput });
|
|
1072
|
+
}
|
|
1073
|
+
|
|
1074
|
+
/**
|
|
1075
|
+
* Extract phone extension
|
|
1076
|
+
* @param {Object} options - Extraction options
|
|
1077
|
+
* @param {string} options.value - Text containing extension
|
|
1078
|
+
* @param {number} [options.minLength=1] - Minimum digits
|
|
1079
|
+
* @param {number} [options.maxLength=10] - Maximum digits
|
|
1080
|
+
* @returns {Promise<Object>} { isValid, parsedValue, confidence }
|
|
1081
|
+
*/
|
|
1082
|
+
async extension({ value, minLength = 1, maxLength = 10 }) {
|
|
1083
|
+
return this._extract('extension', value, { minLength, maxLength });
|
|
1084
|
+
}
|
|
1085
|
+
|
|
1086
|
+
/**
|
|
1087
|
+
* Detect correct/incorrect response from natural language
|
|
1088
|
+
* @param {Object} options - Extraction options
|
|
1089
|
+
* @param {string} options.value - User's response (e.g., "yes", "no", "correct", "nope")
|
|
1090
|
+
* @returns {Promise<Object>} { isValid, parsedValue: 'correct'|'incorrect', booleanValue: true|false }
|
|
1091
|
+
*/
|
|
1092
|
+
async correctIncorrect({ value }) {
|
|
1093
|
+
return this._extract('correctIncorrect', value);
|
|
1094
|
+
}
|
|
1095
|
+
|
|
1096
|
+
/**
|
|
1097
|
+
* Extract using custom regex pattern
|
|
1098
|
+
* @param {Object} options - Extraction options
|
|
1099
|
+
* @param {string} options.value - Text to match against
|
|
1100
|
+
* @param {string} options.pattern - Regex pattern
|
|
1101
|
+
* @param {number} [options.maxLength] - Maximum length of extracted value
|
|
1102
|
+
* @param {string} [options.flags='g'] - Regex flags
|
|
1103
|
+
* @param {boolean} [options.replaceNumbers=true] - Convert number words to digits first
|
|
1104
|
+
* @returns {Promise<Object>} { isValid, parsedValue, originalValue, processedValue }
|
|
1105
|
+
*/
|
|
1106
|
+
async regex({
|
|
1107
|
+
value,
|
|
1108
|
+
pattern,
|
|
1109
|
+
maxLength,
|
|
1110
|
+
flags = 'g',
|
|
1111
|
+
replaceNumbers = true,
|
|
1112
|
+
}) {
|
|
1113
|
+
return this._extract('regex', value, {
|
|
1114
|
+
pattern,
|
|
1115
|
+
maxLength,
|
|
1116
|
+
flags,
|
|
1117
|
+
replaceNumbers,
|
|
1118
|
+
});
|
|
1119
|
+
}
|
|
1120
|
+
|
|
1121
|
+
/**
|
|
1122
|
+
* Detect intent response from natural language
|
|
1123
|
+
* @param {Object} options - Extraction options
|
|
1124
|
+
* @param {string} options.value - User's response (e.g., "I need help with my invoice")
|
|
1125
|
+
* @param {Object} options.params.question - The Question posed to the user to answer
|
|
1126
|
+
* @param {Object} options.params.validOptions - An array of objects with the valid intents
|
|
1127
|
+
*
|
|
1128
|
+
* @returns {Promise<Object>} { isValid, value: 'Billing', }
|
|
1129
|
+
*/
|
|
1130
|
+
async intent({ value, params }) {
|
|
1131
|
+
return this._extract('intent', value, params);
|
|
1132
|
+
}
|
|
1133
|
+
|
|
1134
|
+
/**
|
|
1135
|
+
* Extract ALL entities from text (phone, email, address, name, etc.)
|
|
1136
|
+
* @param {Object} options - Extraction options
|
|
1137
|
+
* @param {string} options.value - Text to extract from
|
|
1138
|
+
* @param {array} [options.types] - Array of strings of the types you want to find ('correctIncorrect', 'phone', 'email', 'address', 'personName', 'extension', 'creditCard', 'ssn'). If not provided, all types will be extracted.
|
|
1139
|
+
* @param {string} [options.question] - The original question that was asked to the user. Providing this context significantly improves extraction accuracy by helping the AI understand what data entities to look for.
|
|
1140
|
+
* @returns {Promise<Object>} { isValid, extractions: [{ type, value, ...metadata }], metadata }
|
|
1141
|
+
*/
|
|
1142
|
+
async all({ value, types = [], question }) {
|
|
1143
|
+
const params = {
|
|
1144
|
+
types,
|
|
1145
|
+
question,
|
|
1146
|
+
};
|
|
1147
|
+
return this._extract('all', value, params);
|
|
1148
|
+
}
|
|
1149
|
+
|
|
1150
|
+
// Internal method
|
|
1151
|
+
async _extract(type, value, params = {}) {
|
|
1152
|
+
this.sdk.validateParams(
|
|
1153
|
+
{ type, value },
|
|
1154
|
+
{
|
|
1155
|
+
type: { type: 'string', required: true },
|
|
1156
|
+
value: { type: 'string', required: true },
|
|
1157
|
+
},
|
|
1158
|
+
);
|
|
1159
|
+
|
|
1160
|
+
const requestParams = {
|
|
1161
|
+
body: {
|
|
1162
|
+
type,
|
|
1163
|
+
value,
|
|
1164
|
+
params,
|
|
1165
|
+
},
|
|
1166
|
+
};
|
|
1167
|
+
|
|
1168
|
+
const result = await this.sdk._fetch('/ai/extract', 'POST', requestParams);
|
|
1169
|
+
return result;
|
|
1170
|
+
}
|
|
210
1171
|
}
|