@unboundcx/sdk 4.0.11 → 4.0.13

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@unboundcx/sdk",
3
- "version": "4.0.11",
3
+ "version": "4.0.13",
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
@@ -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
 
@@ -224,6 +257,27 @@ export class GenerativeService {
224
257
  return result;
225
258
  }
226
259
 
260
+ /**
261
+ * Summarize chat/transcript content (running summary, chapters, title)
262
+ * @param {Object} payload
263
+ * @param {string} [payload.domain] - Summary domain (e.g. 'meeting')
264
+ * @param {string} [payload.mode] - Summary mode
265
+ * @param {Array} [payload.lines] - Transcript/chat lines to summarize
266
+ * @param {Array} [payload.chatMessages] - Chat messages to summarize
267
+ * @param {string} [payload.runningSummary] - Existing running summary to extend
268
+ * @param {boolean} [payload.includeChapters] - Include chapter breakdown
269
+ * @param {boolean} [payload.includeTitle] - Include a generated title
270
+ * @returns {Promise<Object>} Summary result
271
+ */
272
+ async summarize(payload = {}) {
273
+ const params = {
274
+ body: payload,
275
+ };
276
+
277
+ const result = await this.sdk._fetch('/ai/summarize', 'POST', params);
278
+ return result;
279
+ }
280
+
227
281
  /**
228
282
  * List available chat tools and their metadata
229
283
  * @returns {Promise<Object>} { tools: Array<{ name, label, description, configRequirements }>, count: number }
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);
@@ -1030,4 +1042,355 @@ export class VideoService {
1030
1042
  const result = await this.sdk._fetch('/video/settings/user', 'GET', params);
1031
1043
  return result;
1032
1044
  }
1045
+
1046
+ /**
1047
+ * Get the AI-generated summary for a video room's transcript
1048
+ * @param {string} roomId - The video room ID
1049
+ * @returns {Promise} Meeting summary
1050
+ */
1051
+ async getSummary(roomId) {
1052
+ this.sdk.validateParams(
1053
+ { roomId },
1054
+ {
1055
+ roomId: { type: 'string', required: true },
1056
+ },
1057
+ );
1058
+
1059
+ const result = await this.sdk._fetch(`/video/${roomId}/summary`, 'GET');
1060
+ return result;
1061
+ }
1062
+
1063
+ /**
1064
+ * Host-only edit of a video room's post-meeting AI summary
1065
+ * @param {string} roomId - The video room ID
1066
+ * @param {Object} update
1067
+ * @param {Object} update.summaryJson - {title, summary, actionItems, chapters}
1068
+ * @returns {Promise} Update result
1069
+ */
1070
+ async updateSummary(roomId, { summaryJson }) {
1071
+ this.sdk.validateParams(
1072
+ { roomId, summaryJson },
1073
+ {
1074
+ roomId: { type: 'string', required: true },
1075
+ summaryJson: { type: 'object', required: true },
1076
+ },
1077
+ );
1078
+
1079
+ const params = {
1080
+ body: { summaryJson },
1081
+ };
1082
+
1083
+ const result = await this.sdk._fetch(
1084
+ `/video/${roomId}/summary`,
1085
+ 'PATCH',
1086
+ params,
1087
+ );
1088
+ return result;
1089
+ }
1090
+
1091
+ /**
1092
+ * Generate a "catch me up" recap of a video room's transcript so far
1093
+ * @param {string} roomId - The video room ID
1094
+ * @returns {Promise} Catch-up summary
1095
+ */
1096
+ async catchMeUp(roomId) {
1097
+ this.sdk.validateParams(
1098
+ { roomId },
1099
+ {
1100
+ roomId: { type: 'string', required: true },
1101
+ },
1102
+ );
1103
+
1104
+ const result = await this.sdk._fetch(
1105
+ `/video/${roomId}/catch-me-up`,
1106
+ 'POST',
1107
+ {},
1108
+ );
1109
+ return result;
1110
+ }
1111
+
1112
+ /**
1113
+ * Ask the room-scoped AI assistant a question, grounded in the meeting
1114
+ * transcript so far
1115
+ * @param {string} roomId - The video room ID
1116
+ * @param {Object} params
1117
+ * @param {string} params.question - The question to ask
1118
+ * @param {Array<{role: 'user'|'assistant', content: string}>} [params.history] - Prior turns
1119
+ * @returns {Promise} Assistant answer
1120
+ */
1121
+ async assistantChat(roomId, { question, history } = {}) {
1122
+ this.sdk.validateParams(
1123
+ { roomId, question },
1124
+ {
1125
+ roomId: { type: 'string', required: true },
1126
+ question: { type: 'string', required: true },
1127
+ },
1128
+ );
1129
+
1130
+ const body = { question };
1131
+ if (history !== undefined) {
1132
+ body.history = history;
1133
+ }
1134
+
1135
+ const result = await this.sdk._fetch(`/video/${roomId}/assistant`, 'POST', {
1136
+ body,
1137
+ });
1138
+ return result;
1139
+ }
1140
+
1141
+ /**
1142
+ * Update the text of a transcript message
1143
+ * @param {string} roomId - The video room ID
1144
+ * @param {string} messageId - The transcript message ID
1145
+ * @param {Object} update
1146
+ * @param {string} update.text - New transcript text
1147
+ * @returns {Promise} Updated transcript message
1148
+ */
1149
+ async updateTranscriptMessage(roomId, messageId, { text }) {
1150
+ this.sdk.validateParams(
1151
+ { roomId, messageId, text },
1152
+ {
1153
+ roomId: { type: 'string', required: true },
1154
+ messageId: { type: 'string', required: true },
1155
+ text: { type: 'string', required: true },
1156
+ },
1157
+ );
1158
+
1159
+ const params = {
1160
+ body: { text },
1161
+ };
1162
+
1163
+ const result = await this.sdk._fetch(
1164
+ `/video/${roomId}/transcript/${messageId}`,
1165
+ 'PATCH',
1166
+ params,
1167
+ );
1168
+ return result;
1169
+ }
1170
+
1171
+ /**
1172
+ * Redact a transcript message
1173
+ * @param {string} roomId - The video room ID
1174
+ * @param {string} messageId - The transcript message ID
1175
+ * @returns {Promise} Redaction result
1176
+ */
1177
+ async redactTranscriptMessage(roomId, messageId) {
1178
+ this.sdk.validateParams(
1179
+ { roomId, messageId },
1180
+ {
1181
+ roomId: { type: 'string', required: true },
1182
+ messageId: { type: 'string', required: true },
1183
+ },
1184
+ );
1185
+
1186
+ const result = await this.sdk._fetch(
1187
+ `/video/${roomId}/transcript/${messageId}/redact`,
1188
+ 'POST',
1189
+ {},
1190
+ );
1191
+ return result;
1192
+ }
1193
+
1194
+ /**
1195
+ * Rename a speaker in the transcript for a video room
1196
+ * @param {string} roomId - The video room ID
1197
+ * @param {Object} update
1198
+ * @param {string} update.participantId - Participant ID whose transcript speaker name to update
1199
+ * @param {string} update.displayName - New display name
1200
+ * @returns {Promise} Update result
1201
+ */
1202
+ async renameTranscriptSpeaker(roomId, { participantId, displayName }) {
1203
+ this.sdk.validateParams(
1204
+ { roomId, participantId, displayName },
1205
+ {
1206
+ roomId: { type: 'string', required: true },
1207
+ participantId: { type: 'string', required: true },
1208
+ displayName: { type: 'string', required: true },
1209
+ },
1210
+ );
1211
+
1212
+ const params = {
1213
+ body: { participantId, displayName },
1214
+ };
1215
+
1216
+ const result = await this.sdk._fetch(
1217
+ `/video/${roomId}/transcript-speakers`,
1218
+ 'PATCH',
1219
+ params,
1220
+ );
1221
+ return result;
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
+ }
1033
1396
  }