@webex/internal-plugin-voicea 3.11.0 → 3.12.0-llmrefactor.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/voicea.js CHANGED
@@ -20,6 +20,7 @@ var _possibleConstructorReturn2 = _interopRequireDefault(require("@babel/runtime
20
20
  var _getPrototypeOf2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/getPrototypeOf"));
21
21
  var _inherits2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/inherits"));
22
22
  var _defineProperty2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/defineProperty"));
23
+ var _events = _interopRequireDefault(require("events"));
23
24
  var _uuid = _interopRequireDefault(require("uuid"));
24
25
  var _webexCore = require("@webex/webex-core");
25
26
  var _constants = require("./constants");
@@ -27,38 +28,42 @@ var _utils = require("./utils");
27
28
  function ownKeys(e, r) { var t = _Object$keys(e); if (_Object$getOwnPropertySymbols) { var o = _Object$getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return _Object$getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
28
29
  function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : _Object$getOwnPropertyDescriptors ? _Object$defineProperties(e, _Object$getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { _Object$defineProperty(e, r, _Object$getOwnPropertyDescriptor(t, r)); }); } return e; }
29
30
  function _callSuper(t, o, e) { return o = (0, _getPrototypeOf2.default)(o), (0, _possibleConstructorReturn2.default)(t, _isNativeReflectConstruct() ? _Reflect$construct(o, e || [], (0, _getPrototypeOf2.default)(t).constructor) : o.apply(t, e)); }
30
- function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.call(_Reflect$construct(Boolean, [], function () {})); } catch (t) {} return (_isNativeReflectConstruct = function _isNativeReflectConstruct() { return !!t; })(); } // eslint-disable-next-line no-unused-vars
31
+ function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.call(_Reflect$construct(Boolean, [], function () {})); } catch (t) {} return (_isNativeReflectConstruct = function _isNativeReflectConstruct() { return !!t; })(); } // @ts-ignore - webex-core types
32
+ // @ts-ignore - internal-plugin-llm types
31
33
  /**
32
- * @description VoiceaChannel to hold single instance of LLM
34
+ * @description VoiceaChannel handles voicea/transcription functionality for a single LLM connection.
35
+ * Created via `webex.internal.voicea.createChannel(llmChannel)`. The caller owns the
36
+ * channel and is responsible for its lifecycle.
33
37
  * @export
34
38
  * @class VoiceaChannel
35
39
  */
36
- var VoiceaChannel = exports.VoiceaChannel = /*#__PURE__*/function (_WebexPlugin) {
40
+ var VoiceaChannel = exports.VoiceaChannel = /*#__PURE__*/function (_EventEmitter) {
37
41
  /**
38
- * Initializes Voicea plugin
39
- * @param {any} args
42
+ * Creates a VoiceaChannel bound to the given LLMChannel
43
+ * @param {LLMChannel} llmChannel - The LLM channel to use
44
+ * @param {Function} request - The request function for making API calls (typically webex.request bound to webex)
40
45
  */
41
- function VoiceaChannel() {
46
+ function VoiceaChannel(llmChannel, request) {
42
47
  var _this;
43
48
  (0, _classCallCheck2.default)(this, VoiceaChannel);
44
- for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
45
- args[_key] = arguments[_key];
46
- }
47
- _this = _callSuper(this, VoiceaChannel, [].concat(args));
48
- (0, _defineProperty2.default)(_this, "namespace", _constants.VOICEA);
49
+ _this = _callSuper(this, VoiceaChannel);
50
+ (0, _defineProperty2.default)(_this, "request", void 0);
51
+ (0, _defineProperty2.default)(_this, "llmChannel", void 0);
49
52
  (0, _defineProperty2.default)(_this, "seqNum", void 0);
50
53
  (0, _defineProperty2.default)(_this, "areCaptionsEnabled", void 0);
51
54
  (0, _defineProperty2.default)(_this, "hasSubscribedToEvents", false);
52
55
  (0, _defineProperty2.default)(_this, "captionServiceId", void 0);
53
56
  (0, _defineProperty2.default)(_this, "announceStatus", void 0);
54
57
  (0, _defineProperty2.default)(_this, "captionStatus", void 0);
58
+ (0, _defineProperty2.default)(_this, "keepTranscriptionSubscribed", void 0);
55
59
  (0, _defineProperty2.default)(_this, "toggleManualCaptionStatus", void 0);
56
60
  (0, _defineProperty2.default)(_this, "currentSpokenLanguage", void 0);
57
61
  (0, _defineProperty2.default)(_this, "spokenLanguages", []);
58
62
  (0, _defineProperty2.default)(_this, "currentCaptionLanguage", void 0);
59
63
  /**
60
- * @param {Object} e
61
- * @returns {undefined}
64
+ * Process events from LLM channel
65
+ * @param {Object} e - Event data
66
+ * @returns {void}
62
67
  */
63
68
  (0, _defineProperty2.default)(_this, "eventProcessor", function (e) {
64
69
  var _e$headers;
@@ -93,8 +98,7 @@ var VoiceaChannel = exports.VoiceaChannel = /*#__PURE__*/function (_WebexPlugin)
93
98
  */
94
99
  (0, _defineProperty2.default)(_this, "processManualTranscription", function (transcriptPayload) {
95
100
  if (transcriptPayload.type === _constants.TRANSCRIPTION_TYPE.MANUAL_CAPTION_FINAL_RESULT || transcriptPayload.type === _constants.TRANSCRIPTION_TYPE.MANUAL_CAPTION_INTERIM_RESULT) {
96
- // @ts-ignore
97
- _this.trigger(_constants.EVENT_TRIGGERS.NEW_MANUAL_CAPTION, {
101
+ _this.emit(_constants.EVENT_TRIGGERS.NEW_MANUAL_CAPTION, {
98
102
  isFinal: transcriptPayload.type === _constants.TRANSCRIPTION_TYPE.MANUAL_CAPTION_FINAL_RESULT,
99
103
  transcriptId: transcriptPayload.id,
100
104
  transcripts: transcriptPayload.transcripts,
@@ -109,48 +113,44 @@ var VoiceaChannel = exports.VoiceaChannel = /*#__PURE__*/function (_WebexPlugin)
109
113
  * @returns {void}
110
114
  */
111
115
  (0, _defineProperty2.default)(_this, "processTranscription", function (voiceaPayload) {
116
+ var _voiceaPayload$transc, _voiceaPayload$highli, _voiceaPayload$highli2, _voiceaPayload$highli3, _voiceaPayload$highli4, _voiceaPayload$highli5, _voiceaPayload$highli6, _voiceaPayload$highli7;
112
117
  switch (voiceaPayload.type) {
113
118
  case _constants.TRANSCRIPTION_TYPE.TRANSCRIPT_INTERIM_RESULTS:
114
- // @ts-ignore
115
- _this.trigger(_constants.EVENT_TRIGGERS.NEW_CAPTION, {
119
+ _this.emit(_constants.EVENT_TRIGGERS.NEW_CAPTION, {
116
120
  isFinal: false,
117
121
  transcriptId: voiceaPayload.transcript_id,
118
122
  transcripts: voiceaPayload.transcripts
119
123
  });
120
124
  break;
121
125
  case _constants.TRANSCRIPTION_TYPE.TRANSCRIPT_FINAL_RESULT:
122
- // @ts-ignore
123
- _this.trigger(_constants.EVENT_TRIGGERS.NEW_CAPTION, {
126
+ _this.emit(_constants.EVENT_TRIGGERS.NEW_CAPTION, {
124
127
  isFinal: true,
125
128
  transcriptId: voiceaPayload.transcript_id,
126
- transcripts: voiceaPayload.transcripts.map(function (transcript) {
129
+ transcripts: (_voiceaPayload$transc = voiceaPayload.transcripts) === null || _voiceaPayload$transc === void 0 ? void 0 : _voiceaPayload$transc.map(function (transcript) {
127
130
  transcript.timestamp = (0, _utils.millisToMinutesAndSeconds)(transcript.end_millis);
128
131
  return transcript;
129
132
  })
130
133
  });
131
134
  break;
132
135
  case _constants.TRANSCRIPTION_TYPE.HIGHLIGHT_CREATED:
133
- // @ts-ignore
134
- _this.trigger(_constants.EVENT_TRIGGERS.HIGHLIGHT_CREATED, {
135
- csis: voiceaPayload.highlight.csis,
136
- highlightId: voiceaPayload.highlight.highlight_id,
137
- text: voiceaPayload.highlight.transcript,
138
- highlightLabel: voiceaPayload.highlight.highlight_label,
139
- highlightSource: voiceaPayload.highlight.highlight_source,
140
- timestamp: (0, _utils.millisToMinutesAndSeconds)(voiceaPayload.highlight.end_millis)
136
+ _this.emit(_constants.EVENT_TRIGGERS.HIGHLIGHT_CREATED, {
137
+ csis: (_voiceaPayload$highli = voiceaPayload.highlight) === null || _voiceaPayload$highli === void 0 ? void 0 : _voiceaPayload$highli.csis,
138
+ highlightId: (_voiceaPayload$highli2 = voiceaPayload.highlight) === null || _voiceaPayload$highli2 === void 0 ? void 0 : _voiceaPayload$highli2.highlight_id,
139
+ text: (_voiceaPayload$highli3 = voiceaPayload.highlight) === null || _voiceaPayload$highli3 === void 0 ? void 0 : _voiceaPayload$highli3.transcript,
140
+ highlightLabel: (_voiceaPayload$highli4 = voiceaPayload.highlight) === null || _voiceaPayload$highli4 === void 0 ? void 0 : _voiceaPayload$highli4.highlight_label,
141
+ highlightSource: (_voiceaPayload$highli5 = voiceaPayload.highlight) === null || _voiceaPayload$highli5 === void 0 ? void 0 : _voiceaPayload$highli5.highlight_source,
142
+ timestamp: (0, _utils.millisToMinutesAndSeconds)((_voiceaPayload$highli6 = (_voiceaPayload$highli7 = voiceaPayload.highlight) === null || _voiceaPayload$highli7 === void 0 ? void 0 : _voiceaPayload$highli7.end_millis) !== null && _voiceaPayload$highli6 !== void 0 ? _voiceaPayload$highli6 : 0)
141
143
  });
142
144
  break;
143
145
  case _constants.TRANSCRIPTION_TYPE.EVA_THANKS:
144
- // @ts-ignore
145
- _this.trigger(_constants.EVENT_TRIGGERS.EVA_COMMAND, {
146
+ _this.emit(_constants.EVENT_TRIGGERS.EVA_COMMAND, {
146
147
  isListening: false,
147
148
  text: voiceaPayload.command_response
148
149
  });
149
150
  break;
150
151
  case _constants.TRANSCRIPTION_TYPE.EVA_WAKE:
151
152
  case _constants.TRANSCRIPTION_TYPE.EVA_CANCEL:
152
- // @ts-ignore
153
- _this.trigger(_constants.EVENT_TRIGGERS.EVA_COMMAND, {
153
+ _this.emit(_constants.EVENT_TRIGGERS.EVA_COMMAND, {
154
154
  isListening: voiceaPayload.type === _constants.TRANSCRIPTION_TYPE.EVA_WAKE
155
155
  });
156
156
  break;
@@ -158,8 +158,7 @@ var VoiceaChannel = exports.VoiceaChannel = /*#__PURE__*/function (_WebexPlugin)
158
158
  {
159
159
  var isInSpokenLanguages = _this.spokenLanguages.includes(voiceaPayload.language);
160
160
  if (isInSpokenLanguages) {
161
- // @ts-ignore
162
- _this.trigger(_constants.EVENT_TRIGGERS.LANGUAGE_DETECTED, {
161
+ _this.emit(_constants.EVENT_TRIGGERS.LANGUAGE_DETECTED, {
163
162
  languageCode: voiceaPayload.language
164
163
  });
165
164
  }
@@ -176,13 +175,11 @@ var VoiceaChannel = exports.VoiceaChannel = /*#__PURE__*/function (_WebexPlugin)
176
175
  */
177
176
  (0, _defineProperty2.default)(_this, "processCaptionLanguageResponse", function (voiceaPayload) {
178
177
  if (voiceaPayload.statusCode === 200) {
179
- // @ts-ignore
180
- _this.trigger(_constants.EVENT_TRIGGERS.CAPTION_LANGUAGE_UPDATE, {
178
+ _this.emit(_constants.EVENT_TRIGGERS.CAPTION_LANGUAGE_UPDATE, {
181
179
  statusCode: 200
182
180
  });
183
181
  } else {
184
- // @ts-ignore
185
- _this.trigger(_constants.EVENT_TRIGGERS.CAPTION_LANGUAGE_UPDATE, {
182
+ _this.emit(_constants.EVENT_TRIGGERS.CAPTION_LANGUAGE_UPDATE, {
186
183
  statusCode: voiceaPayload.errorCode,
187
184
  errorMessage: voiceaPayload.message
188
185
  });
@@ -202,8 +199,17 @@ var VoiceaChannel = exports.VoiceaChannel = /*#__PURE__*/function (_WebexPlugin)
202
199
  currentSpokenLanguage: _this.currentSpokenLanguage
203
200
  };
204
201
  _this.spokenLanguages = (_voiceaPayload$ASR$sp2 = voiceaPayload === null || voiceaPayload === void 0 ? void 0 : (_voiceaPayload$ASR2 = voiceaPayload.ASR) === null || _voiceaPayload$ASR2 === void 0 ? void 0 : _voiceaPayload$ASR2.spoken_languages) !== null && _voiceaPayload$ASR$sp2 !== void 0 ? _voiceaPayload$ASR$sp2 : [];
205
- // @ts-ignore
206
- _this.trigger(_constants.EVENT_TRIGGERS.VOICEA_ANNOUNCEMENT, voiceaLanguageOptions);
202
+ _this.emit(_constants.EVENT_TRIGGERS.VOICEA_ANNOUNCEMENT, voiceaLanguageOptions);
203
+ });
204
+ /**
205
+ * Indicates whether the LLM channel is connected.
206
+ * @returns {boolean}
207
+ */
208
+ (0, _defineProperty2.default)(_this, "isLLMConnected", function () {
209
+ return _this.llmChannel.isConnected();
210
+ });
211
+ (0, _defineProperty2.default)(_this, "getKeepTranscriptionSubscribed", function () {
212
+ return _this.keepTranscriptionSubscribed;
207
213
  });
208
214
  /**
209
215
  * Sends Announcement to add voicea to the meeting
@@ -211,15 +217,14 @@ var VoiceaChannel = exports.VoiceaChannel = /*#__PURE__*/function (_WebexPlugin)
211
217
  */
212
218
  (0, _defineProperty2.default)(_this, "sendAnnouncement", function () {
213
219
  _this.announceStatus = _constants.ANNOUNCE_STATUS.JOINING;
214
- _this.listenToEvents();
215
- // @ts-ignore
216
- _this.webex.internal.llm.socket.send({
220
+ var socket = _this.llmChannel.getSocket();
221
+ var binding = _this.llmChannel.getBinding();
222
+ var payload = {
217
223
  id: "".concat(_this.seqNum),
218
224
  type: 'publishRequest',
219
- recipients: {
220
- // @ts-ignore
221
- route: _this.webex.internal.llm.getBinding()
222
- },
225
+ recipients: [{
226
+ route: binding
227
+ }],
223
228
  // If captionServiceId exists, send it as the 'to' header; otherwise keep headers empty.
224
229
  headers: _this.captionServiceId ? {
225
230
  to: _this.captionServiceId
@@ -232,7 +237,8 @@ var VoiceaChannel = exports.VoiceaChannel = /*#__PURE__*/function (_WebexPlugin)
232
237
  relayType: _constants.AIBRIDGE_RELAY_TYPES.VOICEA.CLIENT_ANNOUNCEMENT
233
238
  },
234
239
  trackingId: "".concat(_webexCore.config.trackingIdPrefix, "_").concat(_uuid.default.v4().toString())
235
- });
240
+ };
241
+ socket.send(payload);
236
242
  _this.seqNum += 1;
237
243
  });
238
244
  /**
@@ -242,26 +248,21 @@ var VoiceaChannel = exports.VoiceaChannel = /*#__PURE__*/function (_WebexPlugin)
242
248
  * @returns {Promise}
243
249
  */
244
250
  (0, _defineProperty2.default)(_this, "setSpokenLanguage", function (languageCode, languageAssignment) {
245
- return (
246
- // @ts-ignore
247
- _this.request({
248
- method: 'PUT',
249
- // @ts-ignore
250
- url: "".concat(_this.webex.internal.llm.getLocusUrl(), "/controls/"),
251
- body: {
252
- transcribe: _objectSpread({
253
- spokenLanguage: languageCode
254
- }, languageAssignment && {
255
- languageAssignment: languageAssignment
256
- })
257
- }
258
- }).then(function () {
259
- // @ts-ignore
260
- _this.trigger(_constants.EVENT_TRIGGERS.SPOKEN_LANGUAGE_UPDATE, {
261
- languageCode: languageCode
262
- });
263
- })
264
- );
251
+ return _this.request({
252
+ method: 'PUT',
253
+ url: "".concat(_this.llmChannel.getLocusUrl(), "/controls/"),
254
+ body: {
255
+ transcribe: _objectSpread({
256
+ spokenLanguage: languageCode
257
+ }, languageAssignment && {
258
+ languageAssignment: languageAssignment
259
+ })
260
+ }
261
+ }).then(function () {
262
+ _this.emit(_constants.EVENT_TRIGGERS.SPOKEN_LANGUAGE_UPDATE, {
263
+ languageCode: languageCode
264
+ });
265
+ });
265
266
  });
266
267
  /**
267
268
  * Request Language translation
@@ -269,16 +270,17 @@ var VoiceaChannel = exports.VoiceaChannel = /*#__PURE__*/function (_WebexPlugin)
269
270
  * @returns {void}
270
271
  */
271
272
  (0, _defineProperty2.default)(_this, "requestLanguage", function (languageCode) {
272
- // @ts-ignore
273
- if (!_this.webex.internal.llm.isConnected()) return;
274
- // @ts-ignore
275
- _this.webex.internal.llm.socket.send({
273
+ if (!_this.isLLMConnected()) {
274
+ return;
275
+ }
276
+ var socket = _this.llmChannel.getSocket();
277
+ var binding = _this.llmChannel.getBinding();
278
+ socket.send({
276
279
  id: "".concat(_this.seqNum),
277
280
  type: 'publishRequest',
278
- recipients: {
279
- // @ts-ignore
280
- route: _this.webex.internal.llm.getBinding()
281
- },
281
+ recipients: [{
282
+ route: binding
283
+ }],
282
284
  headers: {
283
285
  to: _this.captionServiceId
284
286
  },
@@ -304,17 +306,17 @@ var VoiceaChannel = exports.VoiceaChannel = /*#__PURE__*/function (_WebexPlugin)
304
306
  * @returns {void}
305
307
  */
306
308
  (0, _defineProperty2.default)(_this, "sendManualClosedCaption", function (text, timeStamp, csis, isFinal) {
307
- // @ts-ignore
308
- if (!_this.webex.internal.llm.isConnected()) return;
309
-
310
- // @ts-ignore
311
- _this.webex.internal.llm.socket.send({
309
+ if (!_this.isLLMConnected()) {
310
+ return;
311
+ }
312
+ var socket = _this.llmChannel.getSocket();
313
+ var binding = _this.llmChannel.getBinding();
314
+ socket === null || socket === void 0 ? void 0 : socket.send({
312
315
  id: "".concat(_this.seqNum),
313
316
  type: 'publishRequest',
314
- recipients: {
315
- // @ts-ignore
316
- route: _this.webex.internal.llm.getBinding()
317
- },
317
+ recipients: [{
318
+ route: binding
319
+ }],
318
320
  headers: {},
319
321
  data: {
320
322
  eventType: 'relay.event',
@@ -337,34 +339,31 @@ var VoiceaChannel = exports.VoiceaChannel = /*#__PURE__*/function (_WebexPlugin)
337
339
  });
338
340
  /**
339
341
  * request turn on Captions
340
- * @param {string} [languageCode] - Optional Parameter for spoken language code. Defaults to English
342
+ * @param {string} [languageCode] - Optional Parameter for spoken language code
341
343
  * @returns {Promise}
342
344
  */
343
345
  (0, _defineProperty2.default)(_this, "requestTurnOnCaptions", function (languageCode) {
344
346
  _this.captionStatus = _constants.TURN_ON_CAPTION_STATUS.SENDING;
345
-
346
- // only set the spoken language if it is provided
347
+ var locusUrl = _this.llmChannel.getLocusUrl();
347
348
  var body = {
348
349
  transcribe: {
349
350
  caption: true
350
351
  },
351
352
  languageCode: languageCode
352
353
  };
353
-
354
- // @ts-ignore
355
- // eslint-disable-next-line newline-before-return
356
354
  return _this.request({
357
355
  method: 'PUT',
358
- // @ts-ignore
359
- url: "".concat(_this.webex.internal.llm.getLocusUrl(), "/controls/"),
356
+ url: "".concat(locusUrl, "/controls/"),
360
357
  body: body
361
358
  }).then(function () {
362
- // @ts-ignore
363
- _this.trigger(_constants.EVENT_TRIGGERS.CAPTIONS_TURNED_ON);
359
+ _this.emit(_constants.EVENT_TRIGGERS.CAPTIONS_TURNED_ON);
364
360
  _this.areCaptionsEnabled = true;
365
361
  _this.captionStatus = _constants.TURN_ON_CAPTION_STATUS.ENABLED;
366
362
  _this.announce();
367
- }).catch(function () {
363
+ _this.updateSubchannelSubscriptionsAndSyncCaptionState({
364
+ subscribe: ['transcription']
365
+ }, true);
366
+ }).catch(function (error) {
368
367
  _this.captionStatus = _constants.TURN_ON_CAPTION_STATUS.IDLE;
369
368
  throw new Error('turn on captions fail');
370
369
  });
@@ -377,13 +376,21 @@ var VoiceaChannel = exports.VoiceaChannel = /*#__PURE__*/function (_WebexPlugin)
377
376
  return [_constants.ANNOUNCE_STATUS.JOINING, _constants.ANNOUNCE_STATUS.JOINED].includes(_this.announceStatus);
378
377
  });
379
378
  /**
380
- * announce to voicea data chanel
379
+ * is announce processed
380
+ * @returns {boolean}
381
+ */
382
+ (0, _defineProperty2.default)(_this, "isAnnounceProcessed", function () {
383
+ return _this.announceStatus === _constants.ANNOUNCE_STATUS.JOINED;
384
+ });
385
+ /**
386
+ * announce to voicea data channel
381
387
  * @returns {void}
382
388
  */
383
389
  (0, _defineProperty2.default)(_this, "announce", function () {
384
- if (_this.isAnnounceProcessing()) return;
385
- // @ts-ignore
386
- if (!_this.webex.internal.llm.isConnected()) {
390
+ if (_this.isAnnounceProcessed()) {
391
+ return;
392
+ }
393
+ if (!_this.isLLMConnected()) {
387
394
  throw new Error('voicea can not announce before llm connected');
388
395
  }
389
396
  _this.sendAnnouncement();
@@ -411,7 +418,7 @@ var VoiceaChannel = exports.VoiceaChannel = /*#__PURE__*/function (_WebexPlugin)
411
418
  }
412
419
  return _context.abrupt("return", undefined);
413
420
  case 1:
414
- if (_this.webex.internal.llm.isConnected()) {
421
+ if (_this.isLLMConnected()) {
415
422
  _context.next = 2;
416
423
  break;
417
424
  }
@@ -435,11 +442,9 @@ var VoiceaChannel = exports.VoiceaChannel = /*#__PURE__*/function (_WebexPlugin)
435
442
  * @returns {Promise}
436
443
  */
437
444
  (0, _defineProperty2.default)(_this, "toggleTranscribing", function (activate, spokenLanguage) {
438
- // @ts-ignore
439
445
  return _this.request({
440
446
  method: 'PUT',
441
- // @ts-ignore
442
- url: "".concat(_this.webex.internal.llm.getLocusUrl(), "/controls/"),
447
+ url: "".concat(_this.llmChannel.getLocusUrl(), "/controls/"),
443
448
  body: {
444
449
  transcribe: {
445
450
  transcribing: activate
@@ -461,12 +466,9 @@ var VoiceaChannel = exports.VoiceaChannel = /*#__PURE__*/function (_WebexPlugin)
461
466
  (0, _defineProperty2.default)(_this, "toggleManualCaption", function (enable) {
462
467
  if (_this.toggleManualCaptionStatus === _constants.TOGGLE_MANUAL_CAPTION_STATUS.SENDING) return undefined;
463
468
  _this.toggleManualCaptionStatus = _constants.TOGGLE_MANUAL_CAPTION_STATUS.SENDING;
464
-
465
- // @ts-ignore
466
469
  return _this.request({
467
470
  method: 'PUT',
468
- // @ts-ignore
469
- url: "".concat(_this.webex.internal.llm.getLocusUrl(), "/controls/"),
471
+ url: "".concat(_this.llmChannel.getLocusUrl(), "/controls/"),
470
472
  body: {
471
473
  manualCaption: {
472
474
  enable: enable
@@ -487,8 +489,7 @@ var VoiceaChannel = exports.VoiceaChannel = /*#__PURE__*/function (_WebexPlugin)
487
489
  * @returns {void}
488
490
  */
489
491
  (0, _defineProperty2.default)(_this, "onSpokenLanguageUpdate", function (languageCode, meetingId) {
490
- // @ts-ignore
491
- _this.trigger(_constants.EVENT_TRIGGERS.SPOKEN_LANGUAGE_UPDATE, {
492
+ _this.emit(_constants.EVENT_TRIGGERS.SPOKEN_LANGUAGE_UPDATE, {
492
493
  languageCode: languageCode,
493
494
  meetingId: meetingId
494
495
  });
@@ -505,7 +506,6 @@ var VoiceaChannel = exports.VoiceaChannel = /*#__PURE__*/function (_WebexPlugin)
505
506
  }
506
507
  if (_this.captionServiceId !== serviceId) {
507
508
  _this.captionServiceId = serviceId;
508
- // if service id value has changed and the translation language has been set, client needs to resend the translator language message to the LLM.
509
509
  if (_this.currentCaptionLanguage) {
510
510
  _this.requestLanguage(_this.currentCaptionLanguage);
511
511
  }
@@ -525,6 +525,82 @@ var VoiceaChannel = exports.VoiceaChannel = /*#__PURE__*/function (_WebexPlugin)
525
525
  (0, _defineProperty2.default)(_this, "getAnnounceStatus", function () {
526
526
  return _this.announceStatus;
527
527
  });
528
+ /**
529
+ * update LLM sub‑channel subscriptions.
530
+ *
531
+ * @param {string[]} options.subscribe Sub‑channels to subscribe to.
532
+ * @param {string[]} options.unsubscribe Sub‑channels to unsubscribe from.
533
+ * @returns {Promise}
534
+ */
535
+ (0, _defineProperty2.default)(_this, "updateSubchannelSubscriptions", /*#__PURE__*/(0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee2() {
536
+ var _ref3,
537
+ _ref3$subscribe,
538
+ subscribe,
539
+ _ref3$unsubscribe,
540
+ unsubscribe,
541
+ isDataChannelTokenEnabled,
542
+ socket,
543
+ datachannelUrl,
544
+ _args2 = arguments;
545
+ return _regenerator.default.wrap(function (_context2) {
546
+ while (1) switch (_context2.prev = _context2.next) {
547
+ case 0:
548
+ _ref3 = _args2.length > 0 && _args2[0] !== undefined ? _args2[0] : {}, _ref3$subscribe = _ref3.subscribe, subscribe = _ref3$subscribe === void 0 ? [] : _ref3$subscribe, _ref3$unsubscribe = _ref3.unsubscribe, unsubscribe = _ref3$unsubscribe === void 0 ? [] : _ref3$unsubscribe;
549
+ if (_this.isLLMConnected()) {
550
+ _context2.next = 1;
551
+ break;
552
+ }
553
+ return _context2.abrupt("return");
554
+ case 1:
555
+ _context2.next = 2;
556
+ return _this.llmChannel.isDataChannelTokenEnabled();
557
+ case 2:
558
+ isDataChannelTokenEnabled = _context2.sent;
559
+ if (isDataChannelTokenEnabled) {
560
+ _context2.next = 3;
561
+ break;
562
+ }
563
+ return _context2.abrupt("return");
564
+ case 3:
565
+ socket = _this.llmChannel.getSocket();
566
+ datachannelUrl = _this.llmChannel.getDatachannelUrl();
567
+ socket.send({
568
+ id: "".concat(_this.seqNum),
569
+ type: 'subchannelSubscriptionRequest',
570
+ data: {
571
+ datachannelUri: datachannelUrl,
572
+ subscribe: subscribe,
573
+ unsubscribe: unsubscribe
574
+ },
575
+ trackingId: "".concat(_webexCore.config.trackingIdPrefix, "_").concat(_uuid.default.v4().toString())
576
+ });
577
+ _this.seqNum += 1;
578
+ case 4:
579
+ case "end":
580
+ return _context2.stop();
581
+ }
582
+ }, _callee2);
583
+ })));
584
+ /**
585
+ * Updates transcription subchannel subscriptions and records whether the
586
+ * transcription subscription should be kept (and restored on reconnect).
587
+ *
588
+ * @param {Object} [options] - Subscription options.
589
+ * @param {string[]} [options.subscribe] - Subchannels to subscribe to.
590
+ * @param {string[]} [options.unsubscribe] - Subchannels to unsubscribe from.
591
+ * @param {boolean} [keepSubscribed=false] - Whether the transcription
592
+ * subscription should be kept and restored on reconnect.
593
+ *
594
+ * @returns {Promise<void>}
595
+ */
596
+ (0, _defineProperty2.default)(_this, "updateSubchannelSubscriptionsAndSyncCaptionState", function () {
597
+ var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
598
+ var keepSubscribed = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
599
+ _this.keepTranscriptionSubscribed = keepSubscribed;
600
+ return _this.updateSubchannelSubscriptions(options);
601
+ });
602
+ _this.llmChannel = llmChannel;
603
+ _this.request = request;
528
604
  _this.seqNum = 1;
529
605
  _this.areCaptionsEnabled = false;
530
606
  _this.captionServiceId = undefined;
@@ -533,43 +609,93 @@ var VoiceaChannel = exports.VoiceaChannel = /*#__PURE__*/function (_WebexPlugin)
533
609
  _this.toggleManualCaptionStatus = _constants.TOGGLE_MANUAL_CAPTION_STATUS.IDLE;
534
610
  _this.currentSpokenLanguage = _constants.DEFAULT_SPOKEN_LANGUAGE;
535
611
  _this.currentCaptionLanguage = undefined;
612
+ _this.keepTranscriptionSubscribed = false;
613
+
614
+ // Subscribe to relay events from the LLM channel
615
+ _this.llmChannel.on('event:relay.event', _this.eventProcessor);
616
+ _this.hasSubscribedToEvents = true;
536
617
  return _this;
537
618
  }
538
- (0, _inherits2.default)(VoiceaChannel, _WebexPlugin);
619
+ (0, _inherits2.default)(VoiceaChannel, _EventEmitter);
539
620
  return (0, _createClass2.default)(VoiceaChannel, [{
540
- key: "listenToEvents",
621
+ key: "deregisterEvents",
541
622
  value:
542
623
  /**
543
- * Listen to websocket messages
544
- * @returns {undefined}
545
- */
546
- function listenToEvents() {
547
- if (!this.hasSubscribedToEvents) {
548
- // @ts-ignore
549
- this.webex.internal.llm.on('event:relay.event', this.eventProcessor);
550
- this.hasSubscribedToEvents = true;
551
- }
552
- }
553
-
554
- /**
555
- * Listen to websocket messages
624
+ * Deregister events and clean up
556
625
  * @returns {void}
557
626
  */
558
- }, {
559
- key: "deregisterEvents",
560
- value: function deregisterEvents() {
627
+ function deregisterEvents() {
561
628
  this.areCaptionsEnabled = false;
629
+ this.keepTranscriptionSubscribed = false;
562
630
  this.captionServiceId = undefined;
563
- // @ts-ignore
564
- this.webex.internal.llm.off('event:relay.event', this.eventProcessor);
565
- this.hasSubscribedToEvents = false;
631
+ if (this.hasSubscribedToEvents) {
632
+ this.llmChannel.off('event:relay.event', this.eventProcessor);
633
+ this.hasSubscribedToEvents = false;
634
+ }
566
635
  this.announceStatus = _constants.ANNOUNCE_STATUS.IDLE;
567
636
  this.captionStatus = _constants.TURN_ON_CAPTION_STATUS.IDLE;
568
637
  this.toggleManualCaptionStatus = _constants.TOGGLE_MANUAL_CAPTION_STATUS.IDLE;
569
638
  this.currentSpokenLanguage = undefined;
570
639
  this.currentCaptionLanguage = undefined;
571
640
  }
641
+
642
+ /**
643
+ * Switch to a different LLM channel while preserving caption state.
644
+ * Used when transitioning between main meeting and practice session.
645
+ * - Preserves keepTranscriptionSubscribed and spokenLanguage state
646
+ * - Unsubscribes from old channel, subscribes to new channel
647
+ * - Re-announces and re-enables captions if they were on
648
+ * @param {LLMChannel} newLLMChannel - The new LLM channel to switch to
649
+ * @returns {Promise<void>}
650
+ */
651
+ }, {
652
+ key: "switchLLMChannel",
653
+ value: (function () {
654
+ var _switchLLMChannel = (0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee3(newLLMChannel) {
655
+ var captionsWereOn, spokenLanguage;
656
+ return _regenerator.default.wrap(function (_context3) {
657
+ while (1) switch (_context3.prev = _context3.next) {
658
+ case 0:
659
+ // Save current state
660
+ captionsWereOn = this.keepTranscriptionSubscribed;
661
+ spokenLanguage = this.currentSpokenLanguage; // Unsubscribe from old channel
662
+ if (this.hasSubscribedToEvents && this.llmChannel) {
663
+ this.llmChannel.off('event:relay.event', this.eventProcessor);
664
+ this.hasSubscribedToEvents = false;
665
+ }
666
+
667
+ // Switch to new channel
668
+ this.llmChannel = newLLMChannel;
669
+
670
+ // Subscribe to new channel
671
+ this.llmChannel.on('event:relay.event', this.eventProcessor);
672
+ this.hasSubscribedToEvents = true;
673
+
674
+ // Reset announcement state for new connection
675
+ this.announceStatus = _constants.ANNOUNCE_STATUS.IDLE;
676
+ this.captionStatus = _constants.TURN_ON_CAPTION_STATUS.IDLE;
677
+ this.captionServiceId = undefined;
678
+ this.areCaptionsEnabled = false;
679
+
680
+ // Re-announce and re-enable captions if they were on
681
+ if (!captionsWereOn) {
682
+ _context3.next = 1;
683
+ break;
684
+ }
685
+ _context3.next = 1;
686
+ return this.turnOnCaptions(spokenLanguage);
687
+ case 1:
688
+ case "end":
689
+ return _context3.stop();
690
+ }
691
+ }, _callee3, this);
692
+ }));
693
+ function switchLLMChannel(_x2) {
694
+ return _switchLLMChannel.apply(this, arguments);
695
+ }
696
+ return switchLLMChannel;
697
+ }())
572
698
  }]);
573
- }(_webexCore.WebexPlugin);
699
+ }(_events.default);
574
700
  var _default = exports.default = VoiceaChannel;
575
701
  //# sourceMappingURL=voicea.js.map