@unboundcx/sdk 4.0.12 → 4.0.14
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/package.json +1 -1
- package/proto/transcription.proto +4 -0
- package/services/ai/SttStream.js +3 -0
- package/services/ai/settings.js +37 -0
- package/services/ai/translate.js +38 -0
- package/services/ai/vocabulary.js +55 -0
- package/services/ai.js +33 -0
- package/services/video.js +185 -0
- package/services/voice.js +7 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@unboundcx/sdk",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.14",
|
|
4
4
|
"description": "Official JavaScript SDK for the Unbound API - A comprehensive toolkit for integrating with Unbound's communication, AI, and data management services",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -108,6 +108,10 @@ message AudioRequest {
|
|
|
108
108
|
// SilenceDetector), instead of relying on client-sent vad_event fields.
|
|
109
109
|
// Defaults to false/unset: existing (non-Meet) callers are unaffected.
|
|
110
110
|
bool server_vad = 26;
|
|
111
|
+
|
|
112
|
+
// Optional custom vocabulary terms to bias transcription toward
|
|
113
|
+
// (e.g. product names, jargon). Merged account + room terms, capped.
|
|
114
|
+
repeated string vocabulary = 27;
|
|
111
115
|
}
|
|
112
116
|
|
|
113
117
|
// Audio configuration
|
package/services/ai/SttStream.js
CHANGED
|
@@ -167,6 +167,8 @@ export class SttStream extends EventEmitter {
|
|
|
167
167
|
* Meet (video-room) session metadata is not per-chunk — it is sent once in the
|
|
168
168
|
* first-chunk session config, read from stream options: options.videoRoomId,
|
|
169
169
|
* options.participantId, options.displayName, options.serverVad. See constructor.
|
|
170
|
+
* @param {string[]} [options.vocabulary] - Custom vocabulary terms to bias
|
|
171
|
+
* transcription toward (sent once in the first-chunk session config).
|
|
170
172
|
*/
|
|
171
173
|
write(audioChunk, streamMetadata = {}) {
|
|
172
174
|
if (this.isClosed) {
|
|
@@ -223,6 +225,7 @@ export class SttStream extends EventEmitter {
|
|
|
223
225
|
participant_id: this.options.participantId || '',
|
|
224
226
|
display_name: this.options.displayName || '',
|
|
225
227
|
server_vad: this.options.serverVad || false,
|
|
228
|
+
vocabulary: this.options.vocabulary || [],
|
|
226
229
|
};
|
|
227
230
|
|
|
228
231
|
this.grpcCall.write(request);
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AI Settings helpers - Manage account-level AI feature settings
|
|
3
|
+
* Exposed directly on AIService as getSettings()/updateSettings()
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Get account AI settings
|
|
8
|
+
* @param {Object} sdk
|
|
9
|
+
* @returns {Promise<Object>} { settings: { shareOcrEnabled } }
|
|
10
|
+
*/
|
|
11
|
+
export async function getSettings(sdk) {
|
|
12
|
+
const result = await sdk._fetch('/ai/settings', 'GET');
|
|
13
|
+
return result;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Update account AI settings
|
|
18
|
+
* @param {Object} sdk
|
|
19
|
+
* @param {Object} options
|
|
20
|
+
* @param {boolean} options.shareOcrEnabled - Whether shared-content OCR is enabled
|
|
21
|
+
* @returns {Promise<Object>} { settings }
|
|
22
|
+
*/
|
|
23
|
+
export async function updateSettings(sdk, { shareOcrEnabled }) {
|
|
24
|
+
sdk.validateParams(
|
|
25
|
+
{ shareOcrEnabled },
|
|
26
|
+
{
|
|
27
|
+
shareOcrEnabled: { type: 'boolean', required: true },
|
|
28
|
+
},
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
const params = {
|
|
32
|
+
body: { shareOcrEnabled },
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const result = await sdk._fetch('/ai/settings', 'PUT', params);
|
|
36
|
+
return result;
|
|
37
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AI Translate helper - Batch-translate arbitrary text items
|
|
3
|
+
* Exposed directly on AIService as translate()
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Translate a batch of text items
|
|
8
|
+
* @param {Object} sdk
|
|
9
|
+
* @param {Object} options
|
|
10
|
+
* @param {Array<{id: string, text: string}>} options.items - Items to translate
|
|
11
|
+
* @param {string} options.targetLanguage - Target language code
|
|
12
|
+
* @param {string} [options.sourceLanguage] - Source language code (auto-detect if omitted)
|
|
13
|
+
* @param {string} [options.domain] - Optional domain hint for translation quality
|
|
14
|
+
* @param {string} [options.context] - Optional additional context
|
|
15
|
+
* @returns {Promise<Object>} { items: [{id, text}] }
|
|
16
|
+
*/
|
|
17
|
+
export async function translate(
|
|
18
|
+
sdk,
|
|
19
|
+
{ items, targetLanguage, sourceLanguage, domain, context },
|
|
20
|
+
) {
|
|
21
|
+
sdk.validateParams(
|
|
22
|
+
{ items, targetLanguage, sourceLanguage, domain, context },
|
|
23
|
+
{
|
|
24
|
+
items: { type: 'array', required: true },
|
|
25
|
+
targetLanguage: { type: 'string', required: true },
|
|
26
|
+
sourceLanguage: { type: 'string', required: false },
|
|
27
|
+
domain: { type: 'string', required: false },
|
|
28
|
+
context: { type: 'string', required: false },
|
|
29
|
+
},
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
const params = {
|
|
33
|
+
body: { items, targetLanguage, sourceLanguage, domain, context },
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const result = await sdk._fetch('/ai/translate', 'POST', params);
|
|
37
|
+
return result;
|
|
38
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vocabulary Service - Manage account-level custom transcription vocabulary
|
|
3
|
+
*/
|
|
4
|
+
export class VocabularyService {
|
|
5
|
+
constructor(sdk) {
|
|
6
|
+
this.sdk = sdk;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* List account custom vocabulary terms
|
|
11
|
+
* @returns {Promise<Object>} { terms: [{id, term, createdBy, createdAt}] }
|
|
12
|
+
*/
|
|
13
|
+
async list() {
|
|
14
|
+
const result = await this.sdk._fetch('/ai/vocabulary', 'GET');
|
|
15
|
+
return result;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Add a custom vocabulary term (deduped case-insensitive, max 120 chars)
|
|
20
|
+
* @param {string} term - The vocabulary term to add
|
|
21
|
+
* @returns {Promise<Object>} { term: {id, term, createdBy, createdAt} }
|
|
22
|
+
*/
|
|
23
|
+
async add(term) {
|
|
24
|
+
this.sdk.validateParams(
|
|
25
|
+
{ term },
|
|
26
|
+
{
|
|
27
|
+
term: { type: 'string', required: true },
|
|
28
|
+
},
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
const params = {
|
|
32
|
+
body: { term },
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const result = await this.sdk._fetch('/ai/vocabulary', 'POST', params);
|
|
36
|
+
return result;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Remove a custom vocabulary term
|
|
41
|
+
* @param {string} id - The vocabulary term ID
|
|
42
|
+
* @returns {Promise} 204-style response
|
|
43
|
+
*/
|
|
44
|
+
async remove(id) {
|
|
45
|
+
this.sdk.validateParams(
|
|
46
|
+
{ id },
|
|
47
|
+
{
|
|
48
|
+
id: { type: 'string', required: true },
|
|
49
|
+
},
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
const result = await this.sdk._fetch(`/ai/vocabulary/${id}`, 'DELETE');
|
|
53
|
+
return result;
|
|
54
|
+
}
|
|
55
|
+
}
|
package/services/ai.js
CHANGED
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
import { PlaybooksService } from './ai/playbooks.js';
|
|
2
|
+
import { VocabularyService } from './ai/vocabulary.js';
|
|
3
|
+
import { translate as translateItems } from './ai/translate.js';
|
|
4
|
+
import {
|
|
5
|
+
getSettings as getAiSettings,
|
|
6
|
+
updateSettings as updateAiSettings,
|
|
7
|
+
} from './ai/settings.js';
|
|
2
8
|
|
|
3
9
|
export class AIService {
|
|
4
10
|
constructor(sdk) {
|
|
@@ -8,6 +14,33 @@ export class AIService {
|
|
|
8
14
|
this.stt = new SpeechToTextService(sdk);
|
|
9
15
|
this.extract = new ExtractService(sdk);
|
|
10
16
|
this.playbooks = new PlaybooksService(sdk);
|
|
17
|
+
this.vocabulary = new VocabularyService(sdk);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Translate a batch of text items
|
|
22
|
+
* @param {Object} params - { items, targetLanguage, sourceLanguage?, domain?, context? }
|
|
23
|
+
* @returns {Promise<Object>} { items: [{id, text}] }
|
|
24
|
+
*/
|
|
25
|
+
async translate(params) {
|
|
26
|
+
return translateItems(this.sdk, params);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Get account AI settings
|
|
31
|
+
* @returns {Promise<Object>} { settings: { shareOcrEnabled } }
|
|
32
|
+
*/
|
|
33
|
+
async getSettings() {
|
|
34
|
+
return getAiSettings(this.sdk);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Update account AI settings
|
|
39
|
+
* @param {Object} options - { shareOcrEnabled }
|
|
40
|
+
* @returns {Promise<Object>} { settings }
|
|
41
|
+
*/
|
|
42
|
+
async updateSettings(options) {
|
|
43
|
+
return updateAiSettings(this.sdk, options);
|
|
11
44
|
}
|
|
12
45
|
}
|
|
13
46
|
|
package/services/video.js
CHANGED
|
@@ -228,6 +228,8 @@ export class VideoService {
|
|
|
228
228
|
calendarId,
|
|
229
229
|
eventId,
|
|
230
230
|
calendarProvider,
|
|
231
|
+
vocabularyTerms,
|
|
232
|
+
shareOcrEnabled,
|
|
231
233
|
}) {
|
|
232
234
|
this.sdk.validateParams(
|
|
233
235
|
{
|
|
@@ -255,6 +257,8 @@ export class VideoService {
|
|
|
255
257
|
calendarId,
|
|
256
258
|
eventId,
|
|
257
259
|
calendarProvider,
|
|
260
|
+
vocabularyTerms,
|
|
261
|
+
shareOcrEnabled,
|
|
258
262
|
},
|
|
259
263
|
{
|
|
260
264
|
name: { type: 'string', required: false },
|
|
@@ -281,6 +285,8 @@ export class VideoService {
|
|
|
281
285
|
calendarId: { type: 'string', required: false },
|
|
282
286
|
eventId: { type: 'string', required: false },
|
|
283
287
|
calendarProvider: { type: 'string', required: false },
|
|
288
|
+
vocabularyTerms: { type: 'array', required: false },
|
|
289
|
+
shareOcrEnabled: { type: 'boolean', required: false },
|
|
284
290
|
},
|
|
285
291
|
);
|
|
286
292
|
const params = {
|
|
@@ -309,6 +315,8 @@ export class VideoService {
|
|
|
309
315
|
calendarId,
|
|
310
316
|
eventId,
|
|
311
317
|
calendarProvider,
|
|
318
|
+
vocabularyTerms,
|
|
319
|
+
shareOcrEnabled,
|
|
312
320
|
},
|
|
313
321
|
};
|
|
314
322
|
const result = await this.sdk._fetch(`/video`, 'POST', params);
|
|
@@ -350,6 +358,10 @@ export class VideoService {
|
|
|
350
358
|
validationSchema.startTranscribingOn = { type: 'boolean' };
|
|
351
359
|
if ('enableChat' in update)
|
|
352
360
|
validationSchema.enableChat = { type: 'boolean' };
|
|
361
|
+
if ('vocabularyTerms' in update)
|
|
362
|
+
validationSchema.vocabularyTerms = { type: 'array' };
|
|
363
|
+
if ('shareOcrEnabled' in update)
|
|
364
|
+
validationSchema.shareOcrEnabled = { type: 'boolean' };
|
|
353
365
|
|
|
354
366
|
if (Object.keys(validationSchema).length > 0) {
|
|
355
367
|
this.sdk.validateParams(update, validationSchema);
|
|
@@ -1208,4 +1220,177 @@ export class VideoService {
|
|
|
1208
1220
|
);
|
|
1209
1221
|
return result;
|
|
1210
1222
|
}
|
|
1223
|
+
|
|
1224
|
+
/**
|
|
1225
|
+
* Host-only manual retry for a stuck/failed webm->mp4 recording conversion
|
|
1226
|
+
* @param {string} roomId - The video room ID
|
|
1227
|
+
* @returns {Promise} { launched: true } on success
|
|
1228
|
+
*/
|
|
1229
|
+
async retryRecordingConvert(roomId) {
|
|
1230
|
+
this.sdk.validateParams(
|
|
1231
|
+
{ roomId },
|
|
1232
|
+
{
|
|
1233
|
+
roomId: { type: 'string', required: true },
|
|
1234
|
+
},
|
|
1235
|
+
);
|
|
1236
|
+
|
|
1237
|
+
const result = await this.sdk._fetch(
|
|
1238
|
+
`/video/${roomId}/recording-convert-retry`,
|
|
1239
|
+
'POST',
|
|
1240
|
+
{},
|
|
1241
|
+
);
|
|
1242
|
+
return result;
|
|
1243
|
+
}
|
|
1244
|
+
|
|
1245
|
+
/**
|
|
1246
|
+
* Host-triggered "generate meeting name from transcript" action. Always
|
|
1247
|
+
* force-regenerates the room name.
|
|
1248
|
+
* @param {string} roomId - The video room ID
|
|
1249
|
+
* @returns {Promise} { ok: true, name: string } on success
|
|
1250
|
+
*/
|
|
1251
|
+
async autoNameMeeting(roomId) {
|
|
1252
|
+
this.sdk.validateParams(
|
|
1253
|
+
{ roomId },
|
|
1254
|
+
{
|
|
1255
|
+
roomId: { type: 'string', required: true },
|
|
1256
|
+
},
|
|
1257
|
+
);
|
|
1258
|
+
|
|
1259
|
+
const result = await this.sdk._fetch(`/video/${roomId}/auto-name`, 'POST', {});
|
|
1260
|
+
return result;
|
|
1261
|
+
}
|
|
1262
|
+
|
|
1263
|
+
/**
|
|
1264
|
+
* Host-authorized live-transcription toggle, mirrors the recording control
|
|
1265
|
+
* @param {string} roomId - The video room ID
|
|
1266
|
+
* @param {'start'|'stop'} action - Whether to start or stop transcription
|
|
1267
|
+
* @returns {Promise} { action, ok: true } on success
|
|
1268
|
+
*/
|
|
1269
|
+
async controlTranscription(roomId, action) {
|
|
1270
|
+
this.sdk.validateParams(
|
|
1271
|
+
{ roomId, action },
|
|
1272
|
+
{
|
|
1273
|
+
roomId: { type: 'string', required: true },
|
|
1274
|
+
action: { type: 'string', required: true },
|
|
1275
|
+
},
|
|
1276
|
+
);
|
|
1277
|
+
|
|
1278
|
+
const params = {
|
|
1279
|
+
body: { action },
|
|
1280
|
+
};
|
|
1281
|
+
|
|
1282
|
+
const result = await this.sdk._fetch(
|
|
1283
|
+
`/video/${roomId}/transcription`,
|
|
1284
|
+
'POST',
|
|
1285
|
+
params,
|
|
1286
|
+
);
|
|
1287
|
+
return result;
|
|
1288
|
+
}
|
|
1289
|
+
|
|
1290
|
+
/**
|
|
1291
|
+
* Set the caption language for the calling participant in a video room
|
|
1292
|
+
* @param {string} roomId - The video room ID
|
|
1293
|
+
* @param {Object} options
|
|
1294
|
+
* @param {string} options.language - Language code, or 'original' for no translation
|
|
1295
|
+
* @returns {Promise} { ok: true } on success
|
|
1296
|
+
*/
|
|
1297
|
+
async setCaptionLanguage(roomId, { language }) {
|
|
1298
|
+
this.sdk.validateParams(
|
|
1299
|
+
{ roomId, language },
|
|
1300
|
+
{
|
|
1301
|
+
roomId: { type: 'string', required: true },
|
|
1302
|
+
language: { type: 'string', required: true },
|
|
1303
|
+
},
|
|
1304
|
+
);
|
|
1305
|
+
|
|
1306
|
+
const params = {
|
|
1307
|
+
body: { language },
|
|
1308
|
+
};
|
|
1309
|
+
|
|
1310
|
+
const result = await this.sdk._fetch(
|
|
1311
|
+
`/video/${roomId}/caption-language`,
|
|
1312
|
+
'POST',
|
|
1313
|
+
params,
|
|
1314
|
+
);
|
|
1315
|
+
return result;
|
|
1316
|
+
}
|
|
1317
|
+
|
|
1318
|
+
/**
|
|
1319
|
+
* Translate a video room's full transcript into a target language (account users).
|
|
1320
|
+
* Batches the full transcript and caches translations server-side.
|
|
1321
|
+
* @param {string} roomId - The video room ID
|
|
1322
|
+
* @param {Object} options
|
|
1323
|
+
* @param {string} options.targetLanguage - Target language code
|
|
1324
|
+
* @returns {Promise} { items: [{messageId, text}] }
|
|
1325
|
+
*/
|
|
1326
|
+
async translateTranscript(roomId, { targetLanguage }) {
|
|
1327
|
+
this.sdk.validateParams(
|
|
1328
|
+
{ roomId, targetLanguage },
|
|
1329
|
+
{
|
|
1330
|
+
roomId: { type: 'string', required: true },
|
|
1331
|
+
targetLanguage: { type: 'string', required: true },
|
|
1332
|
+
},
|
|
1333
|
+
);
|
|
1334
|
+
|
|
1335
|
+
const params = {
|
|
1336
|
+
body: { targetLanguage },
|
|
1337
|
+
};
|
|
1338
|
+
|
|
1339
|
+
const result = await this.sdk._fetch(
|
|
1340
|
+
`/video/${roomId}/transcript/translate`,
|
|
1341
|
+
'POST',
|
|
1342
|
+
params,
|
|
1343
|
+
);
|
|
1344
|
+
return result;
|
|
1345
|
+
}
|
|
1346
|
+
|
|
1347
|
+
/**
|
|
1348
|
+
* Submit a captured content-share keyframe for OCR/indexing
|
|
1349
|
+
* @param {string} roomId - The video room ID
|
|
1350
|
+
* @param {Object} options
|
|
1351
|
+
* @param {string} options.image - Base64 jpeg image data (no data: prefix)
|
|
1352
|
+
* @param {string} [options.title] - Optional title for the content frame
|
|
1353
|
+
* @returns {Promise} { event }
|
|
1354
|
+
*/
|
|
1355
|
+
async submitContentFrame(roomId, { image, title }) {
|
|
1356
|
+
this.sdk.validateParams(
|
|
1357
|
+
{ roomId, image, title },
|
|
1358
|
+
{
|
|
1359
|
+
roomId: { type: 'string', required: true },
|
|
1360
|
+
image: { type: 'string', required: true },
|
|
1361
|
+
title: { type: 'string', required: false },
|
|
1362
|
+
},
|
|
1363
|
+
);
|
|
1364
|
+
|
|
1365
|
+
const params = {
|
|
1366
|
+
body: { image, title },
|
|
1367
|
+
};
|
|
1368
|
+
|
|
1369
|
+
const result = await this.sdk._fetch(
|
|
1370
|
+
`/video/${roomId}/content-frame`,
|
|
1371
|
+
'POST',
|
|
1372
|
+
params,
|
|
1373
|
+
);
|
|
1374
|
+
return result;
|
|
1375
|
+
}
|
|
1376
|
+
|
|
1377
|
+
/**
|
|
1378
|
+
* Get captured content-share events for a video room
|
|
1379
|
+
* @param {string} roomId - The video room ID
|
|
1380
|
+
* @returns {Promise} { events: [{id, participantId, displayName, timestamp, title, text, fileId}] }
|
|
1381
|
+
*/
|
|
1382
|
+
async getContentEvents(roomId) {
|
|
1383
|
+
this.sdk.validateParams(
|
|
1384
|
+
{ roomId },
|
|
1385
|
+
{
|
|
1386
|
+
roomId: { type: 'string', required: true },
|
|
1387
|
+
},
|
|
1388
|
+
);
|
|
1389
|
+
|
|
1390
|
+
const result = await this.sdk._fetch(
|
|
1391
|
+
`/video/${roomId}/content-events`,
|
|
1392
|
+
'GET',
|
|
1393
|
+
);
|
|
1394
|
+
return result;
|
|
1395
|
+
}
|
|
1211
1396
|
}
|
package/services/voice.js
CHANGED
|
@@ -22,9 +22,9 @@ export class VoiceService {
|
|
|
22
22
|
return result;
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
async call({ to, from, destination, app, timeout, customHeaders }) {
|
|
25
|
+
async call({ to, from, destination, app, timeout, customHeaders, statusWebhook }) {
|
|
26
26
|
this.sdk.validateParams(
|
|
27
|
-
{ to, from, destination, app, timeout, customHeaders },
|
|
27
|
+
{ to, from, destination, app, timeout, customHeaders, statusWebhook },
|
|
28
28
|
{
|
|
29
29
|
to: { type: 'string', required: true },
|
|
30
30
|
from: { type: 'string', required: true },
|
|
@@ -32,6 +32,10 @@ export class VoiceService {
|
|
|
32
32
|
app: { type: 'object', required: false },
|
|
33
33
|
timeout: { type: 'number', required: false },
|
|
34
34
|
customHeaders: { type: 'object', required: false },
|
|
35
|
+
// { url, static } — internal endpoint that receives call progress
|
|
36
|
+
// events (trying/ringing/answered/failed) with `static` fields
|
|
37
|
+
// merged into each POST body
|
|
38
|
+
statusWebhook: { type: 'object', required: false },
|
|
35
39
|
},
|
|
36
40
|
);
|
|
37
41
|
|
|
@@ -43,6 +47,7 @@ export class VoiceService {
|
|
|
43
47
|
app,
|
|
44
48
|
timeout,
|
|
45
49
|
customHeaders,
|
|
50
|
+
statusWebhook,
|
|
46
51
|
},
|
|
47
52
|
};
|
|
48
53
|
|