@webex/internal-plugin-voicea 3.0.0-beta.38 → 3.0.0-beta.381
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/constants.js +13 -1
- package/dist/constants.js.map +1 -1
- package/dist/voicea.js +68 -27
- package/dist/voicea.js.map +1 -1
- package/dist/voicea.types.js.map +1 -1
- package/package.json +9 -9
- package/src/constants.ts +12 -0
- package/src/voicea.ts +97 -26
- package/src/voicea.types.ts +1 -1
- package/test/unit/spec/voicea.js +145 -14
package/dist/constants.js
CHANGED
|
@@ -4,7 +4,7 @@ var _Object$defineProperty = require("@babel/runtime-corejs2/core-js/object/defi
|
|
|
4
4
|
_Object$defineProperty(exports, "__esModule", {
|
|
5
5
|
value: true
|
|
6
6
|
});
|
|
7
|
-
exports.VOICEA_RELAY_TYPES = exports.VOICEA = exports.TRANSCRIPTION_TYPE = exports.EVENT_TRIGGERS = void 0;
|
|
7
|
+
exports.VOICEA_RELAY_TYPES = exports.VOICEA = exports.TURN_ON_CAPTION_STATUS = exports.TRANSCRIPTION_TYPE = exports.EVENT_TRIGGERS = exports.ANNOUNCE_STATUS = void 0;
|
|
8
8
|
var EVENT_TRIGGERS = {
|
|
9
9
|
VOICEA_ANNOUNCEMENT: 'voicea:announcement',
|
|
10
10
|
CAPTION_LANGUAGE_UPDATE: 'voicea:captionLanguageUpdate',
|
|
@@ -37,4 +37,16 @@ var TRANSCRIPTION_TYPE = {
|
|
|
37
37
|
exports.TRANSCRIPTION_TYPE = TRANSCRIPTION_TYPE;
|
|
38
38
|
var VOICEA = 'voicea';
|
|
39
39
|
exports.VOICEA = VOICEA;
|
|
40
|
+
var ANNOUNCE_STATUS = {
|
|
41
|
+
IDLE: 'idle',
|
|
42
|
+
JOINED: 'joined',
|
|
43
|
+
JOINING: 'joining'
|
|
44
|
+
};
|
|
45
|
+
exports.ANNOUNCE_STATUS = ANNOUNCE_STATUS;
|
|
46
|
+
var TURN_ON_CAPTION_STATUS = {
|
|
47
|
+
IDLE: 'idle',
|
|
48
|
+
ENABLED: 'enabled',
|
|
49
|
+
SENDING: 'sending'
|
|
50
|
+
};
|
|
51
|
+
exports.TURN_ON_CAPTION_STATUS = TURN_ON_CAPTION_STATUS;
|
|
40
52
|
//# sourceMappingURL=constants.js.map
|
package/dist/constants.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["EVENT_TRIGGERS","VOICEA_ANNOUNCEMENT","CAPTION_LANGUAGE_UPDATE","SPOKEN_LANGUAGE_UPDATE","CAPTIONS_TURNED_ON","TRANSCRIBING_ON","TRANSCRIBING_OFF","NEW_CAPTION","EVA_COMMAND","HIGHLIGHT_CREATED","VOICEA_RELAY_TYPES","ANNOUNCEMENT","CLIENT_ANNOUNCEMENT","TRANSLATION_REQUEST","TRANSLATION_RESPONSE","TRANSCRIPTION","TRANSCRIPTION_TYPE","UNKNOWN","EVA_WAKE","EVA_THANKS","EVA_CANCEL","TRANSCRIPT_INTERIM_RESULTS","TRANSCRIPT_FINAL_RESULT","VOICEA"],"sources":["constants.ts"],"sourcesContent":["export const EVENT_TRIGGERS = {\n VOICEA_ANNOUNCEMENT: 'voicea:announcement',\n CAPTION_LANGUAGE_UPDATE: 'voicea:captionLanguageUpdate',\n SPOKEN_LANGUAGE_UPDATE: 'voicea:spokenLanguageUpdate',\n CAPTIONS_TURNED_ON: 'voicea:captionOn',\n TRANSCRIBING_ON: 'voicea:transcribingOn',\n TRANSCRIBING_OFF: 'voicea:transcribingOff',\n\n NEW_CAPTION: 'voicea:newCaption',\n EVA_COMMAND: 'voicea:wxa',\n HIGHLIGHT_CREATED: 'voicea:highlightCreated',\n};\n\nexport const VOICEA_RELAY_TYPES = {\n ANNOUNCEMENT: 'voicea.annc',\n CLIENT_ANNOUNCEMENT: 'client.annc',\n TRANSLATION_REQUEST: 'voicea.transl.req',\n TRANSLATION_RESPONSE: 'voicea.transl.rsp',\n TRANSCRIPTION: 'voicea.transcription',\n};\n\nexport const TRANSCRIPTION_TYPE = {\n UNKNOWN: 'unknown',\n EVA_WAKE: 'eva_wake',\n EVA_THANKS: 'eva_thanks',\n EVA_CANCEL: 'eva_cancel',\n HIGHLIGHT_CREATED: 'highlight_created',\n TRANSCRIPT_INTERIM_RESULTS: 'transcript_interim_results',\n TRANSCRIPT_FINAL_RESULT: 'transcript_final_result',\n};\n\nexport const VOICEA = 'voicea';\n"],"mappings":";;;;;;;AAAO,IAAMA,cAAc,GAAG;EAC5BC,mBAAmB,EAAE,qBAAqB;EAC1CC,uBAAuB,EAAE,8BAA8B;EACvDC,sBAAsB,EAAE,6BAA6B;EACrDC,kBAAkB,EAAE,kBAAkB;EACtCC,eAAe,EAAE,uBAAuB;EACxCC,gBAAgB,EAAE,wBAAwB;EAE1CC,WAAW,EAAE,mBAAmB;EAChCC,WAAW,EAAE,YAAY;EACzBC,iBAAiB,EAAE;AACrB,CAAC;AAAC;AAEK,IAAMC,kBAAkB,GAAG;EAChCC,YAAY,EAAE,aAAa;EAC3BC,mBAAmB,EAAE,aAAa;EAClCC,mBAAmB,EAAE,mBAAmB;EACxCC,oBAAoB,EAAE,mBAAmB;EACzCC,aAAa,EAAE;AACjB,CAAC;AAAC;AAEK,IAAMC,kBAAkB,GAAG;EAChCC,OAAO,EAAE,SAAS;EAClBC,QAAQ,EAAE,UAAU;EACpBC,UAAU,EAAE,YAAY;EACxBC,UAAU,EAAE,YAAY;EACxBX,iBAAiB,EAAE,mBAAmB;EACtCY,0BAA0B,EAAE,4BAA4B;EACxDC,uBAAuB,EAAE;AAC3B,CAAC;AAAC;AAEK,IAAMC,MAAM,GAAG,QAAQ;AAAC"}
|
|
1
|
+
{"version":3,"names":["EVENT_TRIGGERS","VOICEA_ANNOUNCEMENT","CAPTION_LANGUAGE_UPDATE","SPOKEN_LANGUAGE_UPDATE","CAPTIONS_TURNED_ON","TRANSCRIBING_ON","TRANSCRIBING_OFF","NEW_CAPTION","EVA_COMMAND","HIGHLIGHT_CREATED","VOICEA_RELAY_TYPES","ANNOUNCEMENT","CLIENT_ANNOUNCEMENT","TRANSLATION_REQUEST","TRANSLATION_RESPONSE","TRANSCRIPTION","TRANSCRIPTION_TYPE","UNKNOWN","EVA_WAKE","EVA_THANKS","EVA_CANCEL","TRANSCRIPT_INTERIM_RESULTS","TRANSCRIPT_FINAL_RESULT","VOICEA","ANNOUNCE_STATUS","IDLE","JOINED","JOINING","TURN_ON_CAPTION_STATUS","ENABLED","SENDING"],"sources":["constants.ts"],"sourcesContent":["export const EVENT_TRIGGERS = {\n VOICEA_ANNOUNCEMENT: 'voicea:announcement',\n CAPTION_LANGUAGE_UPDATE: 'voicea:captionLanguageUpdate',\n SPOKEN_LANGUAGE_UPDATE: 'voicea:spokenLanguageUpdate',\n CAPTIONS_TURNED_ON: 'voicea:captionOn',\n TRANSCRIBING_ON: 'voicea:transcribingOn',\n TRANSCRIBING_OFF: 'voicea:transcribingOff',\n\n NEW_CAPTION: 'voicea:newCaption',\n EVA_COMMAND: 'voicea:wxa',\n HIGHLIGHT_CREATED: 'voicea:highlightCreated',\n};\n\nexport const VOICEA_RELAY_TYPES = {\n ANNOUNCEMENT: 'voicea.annc',\n CLIENT_ANNOUNCEMENT: 'client.annc',\n TRANSLATION_REQUEST: 'voicea.transl.req',\n TRANSLATION_RESPONSE: 'voicea.transl.rsp',\n TRANSCRIPTION: 'voicea.transcription',\n};\n\nexport const TRANSCRIPTION_TYPE = {\n UNKNOWN: 'unknown',\n EVA_WAKE: 'eva_wake',\n EVA_THANKS: 'eva_thanks',\n EVA_CANCEL: 'eva_cancel',\n HIGHLIGHT_CREATED: 'highlight_created',\n TRANSCRIPT_INTERIM_RESULTS: 'transcript_interim_results',\n TRANSCRIPT_FINAL_RESULT: 'transcript_final_result',\n};\n\nexport const VOICEA = 'voicea';\n\nexport const ANNOUNCE_STATUS = {\n IDLE: 'idle',\n JOINED: 'joined',\n JOINING: 'joining',\n};\n\nexport const TURN_ON_CAPTION_STATUS = {\n IDLE: 'idle',\n ENABLED: 'enabled',\n SENDING: 'sending',\n};\n"],"mappings":";;;;;;;AAAO,IAAMA,cAAc,GAAG;EAC5BC,mBAAmB,EAAE,qBAAqB;EAC1CC,uBAAuB,EAAE,8BAA8B;EACvDC,sBAAsB,EAAE,6BAA6B;EACrDC,kBAAkB,EAAE,kBAAkB;EACtCC,eAAe,EAAE,uBAAuB;EACxCC,gBAAgB,EAAE,wBAAwB;EAE1CC,WAAW,EAAE,mBAAmB;EAChCC,WAAW,EAAE,YAAY;EACzBC,iBAAiB,EAAE;AACrB,CAAC;AAAC;AAEK,IAAMC,kBAAkB,GAAG;EAChCC,YAAY,EAAE,aAAa;EAC3BC,mBAAmB,EAAE,aAAa;EAClCC,mBAAmB,EAAE,mBAAmB;EACxCC,oBAAoB,EAAE,mBAAmB;EACzCC,aAAa,EAAE;AACjB,CAAC;AAAC;AAEK,IAAMC,kBAAkB,GAAG;EAChCC,OAAO,EAAE,SAAS;EAClBC,QAAQ,EAAE,UAAU;EACpBC,UAAU,EAAE,YAAY;EACxBC,UAAU,EAAE,YAAY;EACxBX,iBAAiB,EAAE,mBAAmB;EACtCY,0BAA0B,EAAE,4BAA4B;EACxDC,uBAAuB,EAAE;AAC3B,CAAC;AAAC;AAEK,IAAMC,MAAM,GAAG,QAAQ;AAAC;AAExB,IAAMC,eAAe,GAAG;EAC7BC,IAAI,EAAE,MAAM;EACZC,MAAM,EAAE,QAAQ;EAChBC,OAAO,EAAE;AACX,CAAC;AAAC;AAEK,IAAMC,sBAAsB,GAAG;EACpCH,IAAI,EAAE,MAAM;EACZI,OAAO,EAAE,SAAS;EAClBC,OAAO,EAAE;AACX,CAAC;AAAC"}
|
package/dist/voicea.js
CHANGED
|
@@ -44,16 +44,17 @@ var VoiceaChannel = /*#__PURE__*/function (_WebexPlugin) {
|
|
|
44
44
|
_this = _super.call.apply(_super, [this].concat(args));
|
|
45
45
|
(0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "namespace", _constants.VOICEA);
|
|
46
46
|
(0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "seqNum", void 0);
|
|
47
|
-
(0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "hasVoiceaJoined", void 0);
|
|
48
47
|
(0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "areCaptionsEnabled", void 0);
|
|
49
48
|
(0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "hasSubscribedToEvents", false);
|
|
50
49
|
(0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "vmcDeviceId", void 0);
|
|
50
|
+
(0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "announceStatus", void 0);
|
|
51
|
+
(0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "captionStatus", void 0);
|
|
51
52
|
(0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "eventProcessor", function (e) {
|
|
52
53
|
_this.seqNum = e.sequenceNumber + 1;
|
|
53
54
|
switch (e.data.relayType) {
|
|
54
55
|
case _constants.VOICEA_RELAY_TYPES.ANNOUNCEMENT:
|
|
55
56
|
_this.vmcDeviceId = e.headers.from;
|
|
56
|
-
_this.
|
|
57
|
+
_this.announceStatus = _constants.ANNOUNCE_STATUS.JOINED;
|
|
57
58
|
_this.processAnnouncementMessage(e.data.voiceaPayload);
|
|
58
59
|
break;
|
|
59
60
|
case _constants.VOICEA_RELAY_TYPES.TRANSLATION_RESPONSE:
|
|
@@ -159,8 +160,7 @@ var VoiceaChannel = /*#__PURE__*/function (_WebexPlugin) {
|
|
|
159
160
|
}, _constants.EVENT_TRIGGERS.VOICEA_ANNOUNCEMENT, voiceaLanguageOptions);
|
|
160
161
|
});
|
|
161
162
|
(0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "sendAnnouncement", function () {
|
|
162
|
-
|
|
163
|
-
if (_this.hasVoiceaJoined || !_this.webex.internal.llm.isConnected()) return;
|
|
163
|
+
_this.announceStatus = _constants.ANNOUNCE_STATUS.JOINING;
|
|
164
164
|
_this.listenToEvents();
|
|
165
165
|
// @ts-ignore
|
|
166
166
|
_this.webex.internal.llm.socket.send({
|
|
@@ -228,34 +228,64 @@ var VoiceaChannel = /*#__PURE__*/function (_WebexPlugin) {
|
|
|
228
228
|
});
|
|
229
229
|
_this.seqNum += 1;
|
|
230
230
|
});
|
|
231
|
+
(0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "requestTurnOnCaptions", function () {
|
|
232
|
+
_this.captionStatus = _constants.TURN_ON_CAPTION_STATUS.SENDING;
|
|
233
|
+
// @ts-ignore
|
|
234
|
+
// eslint-disable-next-line newline-before-return
|
|
235
|
+
return _this.request({
|
|
236
|
+
method: 'PUT',
|
|
237
|
+
// @ts-ignore
|
|
238
|
+
url: "".concat(_this.webex.internal.llm.getLocusUrl(), "/controls/"),
|
|
239
|
+
body: {
|
|
240
|
+
transcribe: {
|
|
241
|
+
caption: true
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
}).then(function () {
|
|
245
|
+
_pluginMeetings.TriggerProxy.trigger((0, _assertThisInitialized2.default)(_this), {
|
|
246
|
+
file: 'voicea',
|
|
247
|
+
function: 'turnOnCaptions'
|
|
248
|
+
}, _constants.EVENT_TRIGGERS.CAPTIONS_TURNED_ON);
|
|
249
|
+
_this.areCaptionsEnabled = true;
|
|
250
|
+
_this.captionStatus = _constants.TURN_ON_CAPTION_STATUS.ENABLED;
|
|
251
|
+
_this.announce();
|
|
252
|
+
}).catch(function () {
|
|
253
|
+
_this.captionStatus = _constants.TURN_ON_CAPTION_STATUS.IDLE;
|
|
254
|
+
throw new Error('turn on captions fail');
|
|
255
|
+
});
|
|
256
|
+
});
|
|
257
|
+
(0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "isAnnounceProcessing", function () {
|
|
258
|
+
return [_constants.ANNOUNCE_STATUS.JOINING, _constants.ANNOUNCE_STATUS.JOINED].includes(_this.announceStatus);
|
|
259
|
+
});
|
|
260
|
+
(0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "announce", function () {
|
|
261
|
+
if (_this.isAnnounceProcessing()) return;
|
|
262
|
+
// @ts-ignore
|
|
263
|
+
if (!_this.webex.internal.llm.isConnected()) {
|
|
264
|
+
throw new Error('voicea can not announce before llm connected');
|
|
265
|
+
}
|
|
266
|
+
_this.sendAnnouncement();
|
|
267
|
+
});
|
|
268
|
+
(0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "isCaptionProcessing", function () {
|
|
269
|
+
return [_constants.TURN_ON_CAPTION_STATUS.SENDING, _constants.TURN_ON_CAPTION_STATUS.ENABLED].includes(_this.captionStatus);
|
|
270
|
+
});
|
|
231
271
|
(0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "turnOnCaptions", /*#__PURE__*/(0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee() {
|
|
232
272
|
return _regenerator.default.wrap(function _callee$(_context) {
|
|
233
273
|
while (1) switch (_context.prev = _context.next) {
|
|
234
274
|
case 0:
|
|
235
|
-
if (!
|
|
275
|
+
if (!_this.isCaptionProcessing()) {
|
|
236
276
|
_context.next = 2;
|
|
237
277
|
break;
|
|
238
278
|
}
|
|
239
279
|
return _context.abrupt("return", undefined);
|
|
240
280
|
case 2:
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
}
|
|
250
|
-
}).then(function () {
|
|
251
|
-
_pluginMeetings.TriggerProxy.trigger((0, _assertThisInitialized2.default)(_this), {
|
|
252
|
-
file: 'voicea',
|
|
253
|
-
function: 'turnOnCaptions'
|
|
254
|
-
}, _constants.EVENT_TRIGGERS.CAPTIONS_TURNED_ON);
|
|
255
|
-
_this.areCaptionsEnabled = true;
|
|
256
|
-
_this.sendAnnouncement();
|
|
257
|
-
}));
|
|
258
|
-
case 3:
|
|
281
|
+
if (_this.webex.internal.llm.isConnected()) {
|
|
282
|
+
_context.next = 4;
|
|
283
|
+
break;
|
|
284
|
+
}
|
|
285
|
+
throw new Error('can not turn on captions before llm connected');
|
|
286
|
+
case 4:
|
|
287
|
+
return _context.abrupt("return", _this.requestTurnOnCaptions());
|
|
288
|
+
case 5:
|
|
259
289
|
case "end":
|
|
260
290
|
return _context.stop();
|
|
261
291
|
}
|
|
@@ -276,7 +306,7 @@ var VoiceaChannel = /*#__PURE__*/function (_WebexPlugin) {
|
|
|
276
306
|
}
|
|
277
307
|
}
|
|
278
308
|
}).then(function () {
|
|
279
|
-
if (activate && !_this.areCaptionsEnabled
|
|
309
|
+
if (activate && !_this.areCaptionsEnabled) _this.turnOnCaptions();
|
|
280
310
|
}));
|
|
281
311
|
case 1:
|
|
282
312
|
case "end":
|
|
@@ -288,10 +318,17 @@ var VoiceaChannel = /*#__PURE__*/function (_WebexPlugin) {
|
|
|
288
318
|
return _ref2.apply(this, arguments);
|
|
289
319
|
};
|
|
290
320
|
}());
|
|
321
|
+
(0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "getCaptionStatus", function () {
|
|
322
|
+
return _this.captionStatus;
|
|
323
|
+
});
|
|
324
|
+
(0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "getAnnounceStatus", function () {
|
|
325
|
+
return _this.announceStatus;
|
|
326
|
+
});
|
|
291
327
|
_this.seqNum = 1;
|
|
292
|
-
_this.hasVoiceaJoined = false;
|
|
293
328
|
_this.areCaptionsEnabled = false;
|
|
294
329
|
_this.vmcDeviceId = undefined;
|
|
330
|
+
_this.announceStatus = _constants.ANNOUNCE_STATUS.IDLE;
|
|
331
|
+
_this.captionStatus = _constants.TURN_ON_CAPTION_STATUS.IDLE;
|
|
295
332
|
return _this;
|
|
296
333
|
}
|
|
297
334
|
|
|
@@ -320,16 +357,20 @@ var VoiceaChannel = /*#__PURE__*/function (_WebexPlugin) {
|
|
|
320
357
|
}
|
|
321
358
|
}
|
|
322
359
|
|
|
323
|
-
|
|
360
|
+
/**
|
|
361
|
+
* Listen to websocket messages
|
|
362
|
+
* @returns {void}
|
|
363
|
+
*/
|
|
324
364
|
}, {
|
|
325
365
|
key: "deregisterEvents",
|
|
326
366
|
value: function deregisterEvents() {
|
|
327
|
-
this.hasVoiceaJoined = false;
|
|
328
367
|
this.areCaptionsEnabled = false;
|
|
329
368
|
this.vmcDeviceId = undefined;
|
|
330
369
|
// @ts-ignore
|
|
331
370
|
this.webex.internal.llm.off('event:relay.event', this.eventProcessor);
|
|
332
371
|
this.hasSubscribedToEvents = false;
|
|
372
|
+
this.announceStatus = _constants.ANNOUNCE_STATUS.IDLE;
|
|
373
|
+
this.captionStatus = _constants.TURN_ON_CAPTION_STATUS.IDLE;
|
|
333
374
|
}
|
|
334
375
|
}]);
|
|
335
376
|
return VoiceaChannel;
|
package/dist/voicea.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["VoiceaChannel","args","VOICEA","e","seqNum","sequenceNumber","data","relayType","VOICEA_RELAY_TYPES","ANNOUNCEMENT","vmcDeviceId","headers","from","hasVoiceaJoined","processAnnouncementMessage","voiceaPayload","TRANSLATION_RESPONSE","processCaptionLanguageResponse","TRANSCRIPTION","processTranscription","type","TRANSCRIPTION_TYPE","TRANSCRIPT_INTERIM_RESULTS","Trigger","trigger","file","function","EVENT_TRIGGERS","NEW_CAPTION","isFinal","transcriptId","transcript_id","transcripts","TRANSCRIPT_FINAL_RESULT","transcript","csis","text","transcriptLanguageCode","transcript_language_code","timestamp","millisToMinutesAndSeconds","end_millis","HIGHLIGHT_CREATED","highlight","highlightId","highlight_id","highlightLabel","highlight_label","highlightSource","highlight_source","EVA_THANKS","EVA_COMMAND","isListening","command_response","EVA_WAKE","EVA_CANCEL","statusCode","CAPTION_LANGUAGE_UPDATE","errorCode","errorMessage","message","voiceaLanguageOptions","captionLanguages","translation","allowed_languages","maxLanguages","max_languages","spokenLanguages","ASR","spoken_languages","VOICEA_ANNOUNCEMENT","webex","internal","llm","isConnected","listenToEvents","socket","send","id","recipients","route","getBinding","clientPayload","version","eventType","CLIENT_ANNOUNCEMENT","trackingId","config","trackingIdPrefix","uuid","v4","toString","languageCode","request","method","url","getLocusUrl","body","then","SPOKEN_LANGUAGE_UPDATE","to","translationLanguage","TRANSLATION_REQUEST","areCaptionsEnabled","undefined","transcribe","caption","CAPTIONS_TURNED_ON","sendAnnouncement","activate","transcribing","turnOnCaptions","hasSubscribedToEvents","on","eventProcessor","off","WebexPlugin"],"sources":["voicea.ts"],"sourcesContent":["import uuid from 'uuid';\nimport {TriggerProxy as Trigger} from '@webex/plugin-meetings';\nimport {WebexPlugin, config} from '@webex/webex-core';\n\nimport {EVENT_TRIGGERS, VOICEA_RELAY_TYPES, TRANSCRIPTION_TYPE, VOICEA} from './constants';\n// eslint-disable-next-line no-unused-vars\nimport {\n AnnouncementPayload,\n CaptionLanguageResponse,\n TranscriptionResponse,\n IVoiceaChannel,\n} from './voicea.types';\nimport {millisToMinutesAndSeconds} from './utils';\n\n/**\n * @description VoiceaChannel to hold single instance of LLM\n * @export\n * @class VoiceaChannel\n */\nexport class VoiceaChannel extends WebexPlugin implements IVoiceaChannel {\n namespace = VOICEA;\n\n private seqNum: number;\n\n private hasVoiceaJoined: boolean;\n\n private areCaptionsEnabled: boolean;\n\n private hasSubscribedToEvents = false;\n\n private vmcDeviceId?: string;\n\n /**\n * @param {Object} e\n * @returns {undefined}\n */\n\n private eventProcessor = (e) => {\n this.seqNum = e.sequenceNumber + 1;\n switch (e.data.relayType) {\n case VOICEA_RELAY_TYPES.ANNOUNCEMENT:\n this.vmcDeviceId = e.headers.from;\n this.hasVoiceaJoined = true;\n this.processAnnouncementMessage(e.data.voiceaPayload);\n break;\n case VOICEA_RELAY_TYPES.TRANSLATION_RESPONSE:\n this.processCaptionLanguageResponse(e.data.voiceaPayload);\n break;\n case VOICEA_RELAY_TYPES.TRANSCRIPTION:\n this.processTranscription(e.data.voiceaPayload);\n break;\n default:\n break;\n }\n };\n\n /**\n * Listen to websocket messages\n * @returns {undefined}\n */\n private listenToEvents() {\n if (!this.hasSubscribedToEvents) {\n // @ts-ignore\n this.webex.internal.llm.on('event:relay.event', this.eventProcessor);\n this.hasSubscribedToEvents = true;\n }\n }\n\n // @ts-ignore\n public deregisterEvents() {\n this.hasVoiceaJoined = false;\n this.areCaptionsEnabled = false;\n this.vmcDeviceId = undefined;\n // @ts-ignore\n this.webex.internal.llm.off('event:relay.event', this.eventProcessor);\n this.hasSubscribedToEvents = false;\n }\n\n /**\n * Initializes Voicea plugin\n * @param {any} args\n */\n constructor(...args) {\n super(...args);\n this.seqNum = 1;\n this.hasVoiceaJoined = false;\n this.areCaptionsEnabled = false;\n this.vmcDeviceId = undefined;\n }\n\n /**\n * Process Transcript and send alert\n * @param {TranscriptionResponse} voiceaPayload\n * @returns {void}\n */\n private processTranscription = (voiceaPayload: TranscriptionResponse): void => {\n switch (voiceaPayload.type) {\n case TRANSCRIPTION_TYPE.TRANSCRIPT_INTERIM_RESULTS:\n Trigger.trigger(\n this,\n {\n file: 'voicea',\n function: 'processTranscription',\n },\n EVENT_TRIGGERS.NEW_CAPTION,\n {\n isFinal: false,\n transcriptId: voiceaPayload.transcript_id,\n transcripts: voiceaPayload.transcripts,\n }\n );\n break;\n\n case TRANSCRIPTION_TYPE.TRANSCRIPT_FINAL_RESULT:\n Trigger.trigger(\n this,\n {\n file: 'voicea',\n function: 'processTranscription',\n },\n EVENT_TRIGGERS.NEW_CAPTION,\n {\n isFinal: true,\n transcriptId: voiceaPayload.transcript_id,\n transcript: {\n csis: voiceaPayload.csis,\n text: voiceaPayload.transcript.text,\n transcriptLanguageCode: voiceaPayload.transcript.transcript_language_code,\n },\n timestamp: millisToMinutesAndSeconds(voiceaPayload.transcript.end_millis),\n }\n );\n break;\n\n case TRANSCRIPTION_TYPE.HIGHLIGHT_CREATED:\n Trigger.trigger(\n this,\n {\n file: 'voicea',\n function: 'processTranscription',\n },\n EVENT_TRIGGERS.HIGHLIGHT_CREATED,\n {\n csis: voiceaPayload.highlight.csis,\n highlightId: voiceaPayload.highlight.highlight_id,\n text: voiceaPayload.highlight.transcript,\n highlightLabel: voiceaPayload.highlight.highlight_label,\n highlightSource: voiceaPayload.highlight.highlight_source,\n timestamp: millisToMinutesAndSeconds(voiceaPayload.highlight.end_millis),\n }\n );\n break;\n\n case TRANSCRIPTION_TYPE.EVA_THANKS:\n Trigger.trigger(\n this,\n {\n file: 'voicea',\n function: 'processTranscription',\n },\n EVENT_TRIGGERS.EVA_COMMAND,\n {\n isListening: false,\n text: voiceaPayload.command_response,\n }\n );\n break;\n\n case TRANSCRIPTION_TYPE.EVA_WAKE:\n case TRANSCRIPTION_TYPE.EVA_CANCEL:\n Trigger.trigger(\n this,\n {\n file: 'voicea',\n function: 'processTranscription',\n },\n EVENT_TRIGGERS.EVA_COMMAND,\n {\n isListening: voiceaPayload.type === TRANSCRIPTION_TYPE.EVA_WAKE,\n }\n );\n break;\n\n default:\n break;\n }\n };\n\n /**\n * Processes Caption Language Response\n * @param {CaptionLanguageResponse} voiceaPayload\n * @returns {void}\n */\n private processCaptionLanguageResponse = (voiceaPayload: CaptionLanguageResponse): void => {\n if (voiceaPayload.statusCode === 200) {\n Trigger.trigger(\n this,\n {\n file: 'voicea',\n function: 'processCaptionLanguageResponse',\n },\n EVENT_TRIGGERS.CAPTION_LANGUAGE_UPDATE,\n {statusCode: 200}\n );\n } else {\n Trigger.trigger(\n this,\n {\n file: 'voicea',\n function: 'processCaptionLanguageResponse',\n },\n EVENT_TRIGGERS.CAPTION_LANGUAGE_UPDATE,\n {statusCode: voiceaPayload.errorCode, errorMessage: voiceaPayload.message}\n );\n }\n };\n\n /**\n * processes voicea announcement response and triggers event\n * @param {Object} voiceaPayload\n * @returns {void}\n */\n private processAnnouncementMessage = (voiceaPayload: AnnouncementPayload): void => {\n const voiceaLanguageOptions = {\n captionLanguages: voiceaPayload?.translation?.allowed_languages ?? [],\n maxLanguages: voiceaPayload?.translation?.max_languages ?? 0,\n spokenLanguages: voiceaPayload?.ASR?.spoken_languages ?? [],\n };\n\n Trigger.trigger(\n this,\n {\n file: 'voicea',\n function: 'processAnnouncementMessage',\n },\n EVENT_TRIGGERS.VOICEA_ANNOUNCEMENT,\n voiceaLanguageOptions\n );\n };\n\n /**\n * Sends Announcement to add voicea to the meeting\n * @returns {void}\n */\n private sendAnnouncement = (): void => {\n // @ts-ignore\n if (this.hasVoiceaJoined || !this.webex.internal.llm.isConnected()) return;\n\n this.listenToEvents();\n // @ts-ignore\n this.webex.internal.llm.socket.send({\n id: `${this.seqNum}`,\n type: 'publishRequest',\n recipients: {\n // @ts-ignore\n route: this.webex.internal.llm.getBinding(),\n },\n headers: {},\n data: {\n clientPayload: {\n version: 'v2',\n },\n eventType: 'relay.event',\n relayType: VOICEA_RELAY_TYPES.CLIENT_ANNOUNCEMENT,\n },\n trackingId: `${config.trackingIdPrefix}_${uuid.v4().toString()}`,\n });\n this.seqNum += 1;\n };\n\n /**\n * Set Spoken Language for the meeting\n * @param {string} languageCode\n * @returns {Promise}\n */\n public setSpokenLanguage = (languageCode: string): Promise<void> =>\n // @ts-ignore\n this.request({\n method: 'PUT',\n // @ts-ignore\n url: `${this.webex.internal.llm.getLocusUrl()}/controls/`,\n body: {\n languageCode,\n },\n }).then(() => {\n Trigger.trigger(\n this,\n {\n file: 'voicea',\n function: 'setSpokenLanguage',\n },\n EVENT_TRIGGERS.SPOKEN_LANGUAGE_UPDATE,\n {languageCode}\n );\n });\n\n /**\n * Request Language translation\n * @param {string} languageCode\n * @returns {void}\n */\n public requestLanguage = (languageCode: string): void => {\n // @ts-ignore\n if (!this.webex.internal.llm.isConnected()) return;\n // @ts-ignore\n this.webex.internal.llm.socket.send({\n id: `${this.seqNum}`,\n type: 'publishRequest',\n recipients: {\n // @ts-ignore\n route: this.webex.internal.llm.getBinding(),\n },\n headers: {\n to: this.vmcDeviceId,\n },\n data: {\n clientPayload: {\n translationLanguage: languageCode,\n id: uuid.v4(),\n },\n eventType: 'relay.event',\n relayType: VOICEA_RELAY_TYPES.TRANSLATION_REQUEST,\n },\n trackingId: `${config.trackingIdPrefix}_${uuid.v4().toString()}`,\n });\n this.seqNum += 1;\n };\n\n /**\n * Turn on Captions\n * @returns {Promise}\n */\n public turnOnCaptions = async (): undefined | Promise<void> => {\n if (this.hasVoiceaJoined && this.areCaptionsEnabled) return undefined;\n // @ts-ignore\n // eslint-disable-next-line newline-before-return\n return this.request({\n method: 'PUT',\n // @ts-ignore\n url: `${this.webex.internal.llm.getLocusUrl()}/controls/`,\n body: {\n transcribe: {caption: true},\n },\n }).then(() => {\n Trigger.trigger(\n this,\n {\n file: 'voicea',\n function: 'turnOnCaptions',\n },\n EVENT_TRIGGERS.CAPTIONS_TURNED_ON\n );\n this.areCaptionsEnabled = true;\n this.sendAnnouncement();\n });\n };\n\n /**\n * Toggle transcribing for highlights\n * @param {bool} activate if true transcribing is turned on\n * @returns {Promise}\n */\n public toggleTranscribing = async (activate: boolean): undefined | Promise<void> => {\n // @ts-ignore\n return this.request({\n method: 'PUT',\n // @ts-ignore\n url: `${this.webex.internal.llm.getLocusUrl()}/controls/`,\n body: {\n transcribe: {transcribing: activate},\n },\n }).then(() => {\n if (activate && !this.areCaptionsEnabled && !this.hasVoiceaJoined) this.turnOnCaptions();\n });\n };\n}\n\nexport default VoiceaChannel;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"names":["VoiceaChannel","args","VOICEA","e","seqNum","sequenceNumber","data","relayType","VOICEA_RELAY_TYPES","ANNOUNCEMENT","vmcDeviceId","headers","from","announceStatus","ANNOUNCE_STATUS","JOINED","processAnnouncementMessage","voiceaPayload","TRANSLATION_RESPONSE","processCaptionLanguageResponse","TRANSCRIPTION","processTranscription","type","TRANSCRIPTION_TYPE","TRANSCRIPT_INTERIM_RESULTS","Trigger","trigger","file","function","EVENT_TRIGGERS","NEW_CAPTION","isFinal","transcriptId","transcript_id","transcripts","TRANSCRIPT_FINAL_RESULT","transcript","csis","text","transcriptLanguageCode","transcript_language_code","timestamp","millisToMinutesAndSeconds","end_millis","HIGHLIGHT_CREATED","highlight","highlightId","highlight_id","highlightLabel","highlight_label","highlightSource","highlight_source","EVA_THANKS","EVA_COMMAND","isListening","command_response","EVA_WAKE","EVA_CANCEL","statusCode","CAPTION_LANGUAGE_UPDATE","errorCode","errorMessage","message","voiceaLanguageOptions","captionLanguages","translation","allowed_languages","maxLanguages","max_languages","spokenLanguages","ASR","spoken_languages","VOICEA_ANNOUNCEMENT","JOINING","listenToEvents","webex","internal","llm","socket","send","id","recipients","route","getBinding","clientPayload","version","eventType","CLIENT_ANNOUNCEMENT","trackingId","config","trackingIdPrefix","uuid","v4","toString","languageCode","request","method","url","getLocusUrl","body","then","SPOKEN_LANGUAGE_UPDATE","isConnected","to","translationLanguage","TRANSLATION_REQUEST","captionStatus","TURN_ON_CAPTION_STATUS","SENDING","transcribe","caption","CAPTIONS_TURNED_ON","areCaptionsEnabled","ENABLED","announce","catch","IDLE","Error","includes","isAnnounceProcessing","sendAnnouncement","isCaptionProcessing","undefined","requestTurnOnCaptions","activate","transcribing","turnOnCaptions","hasSubscribedToEvents","on","eventProcessor","off","WebexPlugin"],"sources":["voicea.ts"],"sourcesContent":["import uuid from 'uuid';\nimport {TriggerProxy as Trigger} from '@webex/plugin-meetings';\nimport {WebexPlugin, config} from '@webex/webex-core';\n\nimport {\n EVENT_TRIGGERS,\n VOICEA_RELAY_TYPES,\n TRANSCRIPTION_TYPE,\n VOICEA,\n ANNOUNCE_STATUS,\n TURN_ON_CAPTION_STATUS,\n} from './constants';\n// eslint-disable-next-line no-unused-vars\nimport {\n AnnouncementPayload,\n CaptionLanguageResponse,\n TranscriptionResponse,\n IVoiceaChannel,\n} from './voicea.types';\nimport {millisToMinutesAndSeconds} from './utils';\n\n/**\n * @description VoiceaChannel to hold single instance of LLM\n * @export\n * @class VoiceaChannel\n */\nexport class VoiceaChannel extends WebexPlugin implements IVoiceaChannel {\n namespace = VOICEA;\n\n private seqNum: number;\n\n private areCaptionsEnabled: boolean;\n\n private hasSubscribedToEvents = false;\n\n private vmcDeviceId?: string;\n\n private announceStatus: string;\n\n private captionStatus: string;\n\n /**\n * @param {Object} e\n * @returns {undefined}\n */\n\n private eventProcessor = (e) => {\n this.seqNum = e.sequenceNumber + 1;\n switch (e.data.relayType) {\n case VOICEA_RELAY_TYPES.ANNOUNCEMENT:\n this.vmcDeviceId = e.headers.from;\n this.announceStatus = ANNOUNCE_STATUS.JOINED;\n this.processAnnouncementMessage(e.data.voiceaPayload);\n break;\n case VOICEA_RELAY_TYPES.TRANSLATION_RESPONSE:\n this.processCaptionLanguageResponse(e.data.voiceaPayload);\n break;\n case VOICEA_RELAY_TYPES.TRANSCRIPTION:\n this.processTranscription(e.data.voiceaPayload);\n break;\n default:\n break;\n }\n };\n\n /**\n * Listen to websocket messages\n * @returns {undefined}\n */\n private listenToEvents() {\n if (!this.hasSubscribedToEvents) {\n // @ts-ignore\n this.webex.internal.llm.on('event:relay.event', this.eventProcessor);\n this.hasSubscribedToEvents = true;\n }\n }\n\n /**\n * Listen to websocket messages\n * @returns {void}\n */\n public deregisterEvents() {\n this.areCaptionsEnabled = false;\n this.vmcDeviceId = undefined;\n // @ts-ignore\n this.webex.internal.llm.off('event:relay.event', this.eventProcessor);\n this.hasSubscribedToEvents = false;\n this.announceStatus = ANNOUNCE_STATUS.IDLE;\n this.captionStatus = TURN_ON_CAPTION_STATUS.IDLE;\n }\n\n /**\n * Initializes Voicea plugin\n * @param {any} args\n */\n constructor(...args) {\n super(...args);\n this.seqNum = 1;\n this.areCaptionsEnabled = false;\n this.vmcDeviceId = undefined;\n this.announceStatus = ANNOUNCE_STATUS.IDLE;\n this.captionStatus = TURN_ON_CAPTION_STATUS.IDLE;\n }\n\n /**\n * Process Transcript and send alert\n * @param {TranscriptionResponse} voiceaPayload\n * @returns {void}\n */\n private processTranscription = (voiceaPayload: TranscriptionResponse): void => {\n switch (voiceaPayload.type) {\n case TRANSCRIPTION_TYPE.TRANSCRIPT_INTERIM_RESULTS:\n Trigger.trigger(\n this,\n {\n file: 'voicea',\n function: 'processTranscription',\n },\n EVENT_TRIGGERS.NEW_CAPTION,\n {\n isFinal: false,\n transcriptId: voiceaPayload.transcript_id,\n transcripts: voiceaPayload.transcripts,\n }\n );\n break;\n\n case TRANSCRIPTION_TYPE.TRANSCRIPT_FINAL_RESULT:\n Trigger.trigger(\n this,\n {\n file: 'voicea',\n function: 'processTranscription',\n },\n EVENT_TRIGGERS.NEW_CAPTION,\n {\n isFinal: true,\n transcriptId: voiceaPayload.transcript_id,\n transcript: {\n csis: voiceaPayload.csis,\n text: voiceaPayload.transcript.text,\n transcriptLanguageCode: voiceaPayload.transcript.transcript_language_code,\n },\n timestamp: millisToMinutesAndSeconds(voiceaPayload.transcript.end_millis),\n }\n );\n break;\n\n case TRANSCRIPTION_TYPE.HIGHLIGHT_CREATED:\n Trigger.trigger(\n this,\n {\n file: 'voicea',\n function: 'processTranscription',\n },\n EVENT_TRIGGERS.HIGHLIGHT_CREATED,\n {\n csis: voiceaPayload.highlight.csis,\n highlightId: voiceaPayload.highlight.highlight_id,\n text: voiceaPayload.highlight.transcript,\n highlightLabel: voiceaPayload.highlight.highlight_label,\n highlightSource: voiceaPayload.highlight.highlight_source,\n timestamp: millisToMinutesAndSeconds(voiceaPayload.highlight.end_millis),\n }\n );\n break;\n\n case TRANSCRIPTION_TYPE.EVA_THANKS:\n Trigger.trigger(\n this,\n {\n file: 'voicea',\n function: 'processTranscription',\n },\n EVENT_TRIGGERS.EVA_COMMAND,\n {\n isListening: false,\n text: voiceaPayload.command_response,\n }\n );\n break;\n\n case TRANSCRIPTION_TYPE.EVA_WAKE:\n case TRANSCRIPTION_TYPE.EVA_CANCEL:\n Trigger.trigger(\n this,\n {\n file: 'voicea',\n function: 'processTranscription',\n },\n EVENT_TRIGGERS.EVA_COMMAND,\n {\n isListening: voiceaPayload.type === TRANSCRIPTION_TYPE.EVA_WAKE,\n }\n );\n break;\n\n default:\n break;\n }\n };\n\n /**\n * Processes Caption Language Response\n * @param {CaptionLanguageResponse} voiceaPayload\n * @returns {void}\n */\n private processCaptionLanguageResponse = (voiceaPayload: CaptionLanguageResponse): void => {\n if (voiceaPayload.statusCode === 200) {\n Trigger.trigger(\n this,\n {\n file: 'voicea',\n function: 'processCaptionLanguageResponse',\n },\n EVENT_TRIGGERS.CAPTION_LANGUAGE_UPDATE,\n {statusCode: 200}\n );\n } else {\n Trigger.trigger(\n this,\n {\n file: 'voicea',\n function: 'processCaptionLanguageResponse',\n },\n EVENT_TRIGGERS.CAPTION_LANGUAGE_UPDATE,\n {statusCode: voiceaPayload.errorCode, errorMessage: voiceaPayload.message}\n );\n }\n };\n\n /**\n * processes voicea announcement response and triggers event\n * @param {Object} voiceaPayload\n * @returns {void}\n */\n private processAnnouncementMessage = (voiceaPayload: AnnouncementPayload): void => {\n const voiceaLanguageOptions = {\n captionLanguages: voiceaPayload?.translation?.allowed_languages ?? [],\n maxLanguages: voiceaPayload?.translation?.max_languages ?? 0,\n spokenLanguages: voiceaPayload?.ASR?.spoken_languages ?? [],\n };\n\n Trigger.trigger(\n this,\n {\n file: 'voicea',\n function: 'processAnnouncementMessage',\n },\n EVENT_TRIGGERS.VOICEA_ANNOUNCEMENT,\n voiceaLanguageOptions\n );\n };\n\n /**\n * Sends Announcement to add voicea to the meeting\n * @returns {void}\n */\n private sendAnnouncement = (): void => {\n this.announceStatus = ANNOUNCE_STATUS.JOINING;\n this.listenToEvents();\n // @ts-ignore\n this.webex.internal.llm.socket.send({\n id: `${this.seqNum}`,\n type: 'publishRequest',\n recipients: {\n // @ts-ignore\n route: this.webex.internal.llm.getBinding(),\n },\n headers: {},\n data: {\n clientPayload: {\n version: 'v2',\n },\n eventType: 'relay.event',\n relayType: VOICEA_RELAY_TYPES.CLIENT_ANNOUNCEMENT,\n },\n trackingId: `${config.trackingIdPrefix}_${uuid.v4().toString()}`,\n });\n this.seqNum += 1;\n };\n\n /**\n * Set Spoken Language for the meeting\n * @param {string} languageCode\n * @returns {Promise}\n */\n public setSpokenLanguage = (languageCode: string): Promise<void> =>\n // @ts-ignore\n this.request({\n method: 'PUT',\n // @ts-ignore\n url: `${this.webex.internal.llm.getLocusUrl()}/controls/`,\n body: {\n languageCode,\n },\n }).then(() => {\n Trigger.trigger(\n this,\n {\n file: 'voicea',\n function: 'setSpokenLanguage',\n },\n EVENT_TRIGGERS.SPOKEN_LANGUAGE_UPDATE,\n {languageCode}\n );\n });\n\n /**\n * Request Language translation\n * @param {string} languageCode\n * @returns {void}\n */\n public requestLanguage = (languageCode: string): void => {\n // @ts-ignore\n if (!this.webex.internal.llm.isConnected()) return;\n // @ts-ignore\n this.webex.internal.llm.socket.send({\n id: `${this.seqNum}`,\n type: 'publishRequest',\n recipients: {\n // @ts-ignore\n route: this.webex.internal.llm.getBinding(),\n },\n headers: {\n to: this.vmcDeviceId,\n },\n data: {\n clientPayload: {\n translationLanguage: languageCode,\n id: uuid.v4(),\n },\n eventType: 'relay.event',\n relayType: VOICEA_RELAY_TYPES.TRANSLATION_REQUEST,\n },\n trackingId: `${config.trackingIdPrefix}_${uuid.v4().toString()}`,\n });\n this.seqNum += 1;\n };\n\n /**\n * request turn on Captions\n * @returns {Promise}\n */\n private requestTurnOnCaptions = (): undefined | Promise<void> => {\n this.captionStatus = TURN_ON_CAPTION_STATUS.SENDING;\n // @ts-ignore\n // eslint-disable-next-line newline-before-return\n return this.request({\n method: 'PUT',\n // @ts-ignore\n url: `${this.webex.internal.llm.getLocusUrl()}/controls/`,\n body: {\n transcribe: {caption: true},\n },\n })\n .then(() => {\n Trigger.trigger(\n this,\n {\n file: 'voicea',\n function: 'turnOnCaptions',\n },\n EVENT_TRIGGERS.CAPTIONS_TURNED_ON\n );\n this.areCaptionsEnabled = true;\n this.captionStatus = TURN_ON_CAPTION_STATUS.ENABLED;\n this.announce();\n })\n .catch(() => {\n this.captionStatus = TURN_ON_CAPTION_STATUS.IDLE;\n throw new Error('turn on captions fail');\n });\n };\n\n /**\n * is announce processing\n * @returns {boolean}\n */\n private isAnnounceProcessing = () =>\n [ANNOUNCE_STATUS.JOINING, ANNOUNCE_STATUS.JOINED].includes(this.announceStatus);\n\n /**\n * announce to voicea data chanel\n * @returns {void}\n */\n public announce = () => {\n if (this.isAnnounceProcessing()) return;\n // @ts-ignore\n if (!this.webex.internal.llm.isConnected()) {\n throw new Error('voicea can not announce before llm connected');\n }\n this.sendAnnouncement();\n };\n\n /**\n * is turn on caption processing\n * @returns {boolean}\n */\n private isCaptionProcessing = () =>\n [TURN_ON_CAPTION_STATUS.SENDING, TURN_ON_CAPTION_STATUS.ENABLED].includes(this.captionStatus);\n\n /**\n * Turn on Captions\n * @returns {Promise}\n */\n public turnOnCaptions = async (): undefined | Promise<void> => {\n if (this.isCaptionProcessing()) return undefined;\n // @ts-ignore\n if (!this.webex.internal.llm.isConnected()) {\n throw new Error('can not turn on captions before llm connected');\n }\n\n return this.requestTurnOnCaptions();\n };\n\n /**\n * Toggle transcribing for highlights\n * @param {bool} activate if true transcribing is turned on\n * @returns {Promise}\n */\n public toggleTranscribing = async (activate: boolean): undefined | Promise<void> => {\n // @ts-ignore\n return this.request({\n method: 'PUT',\n // @ts-ignore\n url: `${this.webex.internal.llm.getLocusUrl()}/controls/`,\n body: {\n transcribe: {transcribing: activate},\n },\n }).then(() => {\n if (activate && !this.areCaptionsEnabled) this.turnOnCaptions();\n });\n };\n\n /**\n * get caption status\n * @returns {string}\n */\n public getCaptionStatus = () => this.captionStatus;\n\n /**\n * get announce status\n * @returns {string}\n */\n public getAnnounceStatus = () => this.announceStatus;\n}\n\nexport default VoiceaChannel;\n"],"mappings":"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"}
|
package/dist/voicea.types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":[],"sources":["voicea.types.ts"],"sourcesContent":["/* eslint-disable camelcase */\n/* eslint-disable no-undef */\n\n/**\n * Type for payload\n */\ninterface AnnouncementPayload {\n translation: {\n max_languages: number;\n allowed_languages: string[];\n };\n\n ASR: {\n spoken_languages: string[];\n };\n}\n\n// eslint-disable-next-line no-undef\ntype TRANSCRIPTION_TYPES =\n | 'unknown'\n | 'eva_wake'\n | 'eva_thanks'\n | 'eva_cancel'\n | 'highlight_created'\n | 'transcript_interim_results'\n | 'transcript_final_result';\n\n/**\n * Class for an Transcription Object\n */\ninterface Transcription {\n start_millis: number;\n end_millis: number;\n text: string;\n transcript_language_code: string;\n translations: {[x: string]: string};\n csis: number[];\n last_packet_timestamp_ms: number;\n}\n\n/**\n * Highlights\n */\ninterface Highlight {\n highlight_id: string;\n transcript: string;\n highlight_label: string;\n highlight_source: string;\n start_millis: number;\n end_millis: number;\n csis: number[];\n}\n/**\n * Type for Transcription message\n */\ninterface TranscriptionResponse {\n type: TRANSCRIPTION_TYPES;\n transcript_id: string;\n translations?: {[x: string]: string};\n transcripts?: Transcription[];\n transcript?: Transcription;\n highlight?: Highlight;\n csis: number[];\n data: string;\n command_response: string;\n}\n/**\n * Type for CaptionLanguageResponse\n */\ninterface CaptionLanguageResponse {\n requestId: string;\n statusCode: number;\n errorCode: number;\n message: string;\n}\n\ninterface IVoiceaChannel {\n setSpokenLanguage: (languageCode: string) => Promise<void>;\n requestLanguage: (languageCode: string) => void;\n turnOnCaptions: () => undefined | Promise<void>;\n toggleTranscribing: (activate: boolean) => undefined | Promise<void>;\n deregisterEvents: () =>
|
|
1
|
+
{"version":3,"names":[],"sources":["voicea.types.ts"],"sourcesContent":["/* eslint-disable camelcase */\n/* eslint-disable no-undef */\n\n/**\n * Type for payload\n */\ninterface AnnouncementPayload {\n translation: {\n max_languages: number;\n allowed_languages: string[];\n };\n\n ASR: {\n spoken_languages: string[];\n };\n}\n\n// eslint-disable-next-line no-undef\ntype TRANSCRIPTION_TYPES =\n | 'unknown'\n | 'eva_wake'\n | 'eva_thanks'\n | 'eva_cancel'\n | 'highlight_created'\n | 'transcript_interim_results'\n | 'transcript_final_result';\n\n/**\n * Class for an Transcription Object\n */\ninterface Transcription {\n start_millis: number;\n end_millis: number;\n text: string;\n transcript_language_code: string;\n translations: {[x: string]: string};\n csis: number[];\n last_packet_timestamp_ms: number;\n}\n\n/**\n * Highlights\n */\ninterface Highlight {\n highlight_id: string;\n transcript: string;\n highlight_label: string;\n highlight_source: string;\n start_millis: number;\n end_millis: number;\n csis: number[];\n}\n/**\n * Type for Transcription message\n */\ninterface TranscriptionResponse {\n type: TRANSCRIPTION_TYPES;\n transcript_id: string;\n translations?: {[x: string]: string};\n transcripts?: Transcription[];\n transcript?: Transcription;\n highlight?: Highlight;\n csis: number[];\n data: string;\n command_response: string;\n}\n/**\n * Type for CaptionLanguageResponse\n */\ninterface CaptionLanguageResponse {\n requestId: string;\n statusCode: number;\n errorCode: number;\n message: string;\n}\n\ninterface IVoiceaChannel {\n setSpokenLanguage: (languageCode: string) => Promise<void>;\n requestLanguage: (languageCode: string) => void;\n turnOnCaptions: () => undefined | Promise<void>;\n toggleTranscribing: (activate: boolean) => undefined | Promise<void>;\n deregisterEvents: () => void;\n}\n\nexport type {\n AnnouncementPayload,\n CaptionLanguageResponse,\n TranscriptionResponse,\n Transcription,\n Highlight,\n IVoiceaChannel,\n};\n"],"mappings":""}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@webex/internal-plugin-voicea",
|
|
3
|
-
"version": "3.0.0-beta.
|
|
3
|
+
"version": "3.0.0-beta.381",
|
|
4
4
|
"description": "",
|
|
5
5
|
"license": "Cisco EULA (https://www.cisco.com/c/en/us/products/end-user-license-agreement.html)",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -14,11 +14,11 @@
|
|
|
14
14
|
"node": ">=16"
|
|
15
15
|
},
|
|
16
16
|
"dependencies": {
|
|
17
|
-
"@webex/internal-plugin-llm": "3.0.0-beta.
|
|
18
|
-
"@webex/internal-plugin-mercury": "3.0.0-beta.
|
|
19
|
-
"@webex/internal-plugin-voicea": "3.0.0-beta.
|
|
20
|
-
"@webex/plugin-meetings": "3.0.0-beta.
|
|
21
|
-
"@webex/webex-core": "3.0.0-beta.
|
|
17
|
+
"@webex/internal-plugin-llm": "3.0.0-beta.381",
|
|
18
|
+
"@webex/internal-plugin-mercury": "3.0.0-beta.381",
|
|
19
|
+
"@webex/internal-plugin-voicea": "3.0.0-beta.381",
|
|
20
|
+
"@webex/plugin-meetings": "3.0.0-beta.381",
|
|
21
|
+
"@webex/webex-core": "3.0.0-beta.381",
|
|
22
22
|
"uuid": "^3.3.2"
|
|
23
23
|
},
|
|
24
24
|
"browserify": {
|
|
@@ -28,9 +28,9 @@
|
|
|
28
28
|
]
|
|
29
29
|
},
|
|
30
30
|
"devDependencies": {
|
|
31
|
-
"@webex/test-helper-chai": "3.0.0-beta.
|
|
32
|
-
"@webex/test-helper-mock-web-socket": "3.0.0-beta.
|
|
33
|
-
"@webex/test-helper-mock-webex": "3.0.0-beta.
|
|
31
|
+
"@webex/test-helper-chai": "3.0.0-beta.381",
|
|
32
|
+
"@webex/test-helper-mock-web-socket": "3.0.0-beta.381",
|
|
33
|
+
"@webex/test-helper-mock-webex": "3.0.0-beta.381",
|
|
34
34
|
"sinon": "^9.2.4"
|
|
35
35
|
}
|
|
36
36
|
}
|
package/src/constants.ts
CHANGED
|
@@ -30,3 +30,15 @@ export const TRANSCRIPTION_TYPE = {
|
|
|
30
30
|
};
|
|
31
31
|
|
|
32
32
|
export const VOICEA = 'voicea';
|
|
33
|
+
|
|
34
|
+
export const ANNOUNCE_STATUS = {
|
|
35
|
+
IDLE: 'idle',
|
|
36
|
+
JOINED: 'joined',
|
|
37
|
+
JOINING: 'joining',
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export const TURN_ON_CAPTION_STATUS = {
|
|
41
|
+
IDLE: 'idle',
|
|
42
|
+
ENABLED: 'enabled',
|
|
43
|
+
SENDING: 'sending',
|
|
44
|
+
};
|
package/src/voicea.ts
CHANGED
|
@@ -2,7 +2,14 @@ import uuid from 'uuid';
|
|
|
2
2
|
import {TriggerProxy as Trigger} from '@webex/plugin-meetings';
|
|
3
3
|
import {WebexPlugin, config} from '@webex/webex-core';
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
EVENT_TRIGGERS,
|
|
7
|
+
VOICEA_RELAY_TYPES,
|
|
8
|
+
TRANSCRIPTION_TYPE,
|
|
9
|
+
VOICEA,
|
|
10
|
+
ANNOUNCE_STATUS,
|
|
11
|
+
TURN_ON_CAPTION_STATUS,
|
|
12
|
+
} from './constants';
|
|
6
13
|
// eslint-disable-next-line no-unused-vars
|
|
7
14
|
import {
|
|
8
15
|
AnnouncementPayload,
|
|
@@ -22,14 +29,16 @@ export class VoiceaChannel extends WebexPlugin implements IVoiceaChannel {
|
|
|
22
29
|
|
|
23
30
|
private seqNum: number;
|
|
24
31
|
|
|
25
|
-
private hasVoiceaJoined: boolean;
|
|
26
|
-
|
|
27
32
|
private areCaptionsEnabled: boolean;
|
|
28
33
|
|
|
29
34
|
private hasSubscribedToEvents = false;
|
|
30
35
|
|
|
31
36
|
private vmcDeviceId?: string;
|
|
32
37
|
|
|
38
|
+
private announceStatus: string;
|
|
39
|
+
|
|
40
|
+
private captionStatus: string;
|
|
41
|
+
|
|
33
42
|
/**
|
|
34
43
|
* @param {Object} e
|
|
35
44
|
* @returns {undefined}
|
|
@@ -40,7 +49,7 @@ export class VoiceaChannel extends WebexPlugin implements IVoiceaChannel {
|
|
|
40
49
|
switch (e.data.relayType) {
|
|
41
50
|
case VOICEA_RELAY_TYPES.ANNOUNCEMENT:
|
|
42
51
|
this.vmcDeviceId = e.headers.from;
|
|
43
|
-
this.
|
|
52
|
+
this.announceStatus = ANNOUNCE_STATUS.JOINED;
|
|
44
53
|
this.processAnnouncementMessage(e.data.voiceaPayload);
|
|
45
54
|
break;
|
|
46
55
|
case VOICEA_RELAY_TYPES.TRANSLATION_RESPONSE:
|
|
@@ -66,14 +75,18 @@ export class VoiceaChannel extends WebexPlugin implements IVoiceaChannel {
|
|
|
66
75
|
}
|
|
67
76
|
}
|
|
68
77
|
|
|
69
|
-
|
|
78
|
+
/**
|
|
79
|
+
* Listen to websocket messages
|
|
80
|
+
* @returns {void}
|
|
81
|
+
*/
|
|
70
82
|
public deregisterEvents() {
|
|
71
|
-
this.hasVoiceaJoined = false;
|
|
72
83
|
this.areCaptionsEnabled = false;
|
|
73
84
|
this.vmcDeviceId = undefined;
|
|
74
85
|
// @ts-ignore
|
|
75
86
|
this.webex.internal.llm.off('event:relay.event', this.eventProcessor);
|
|
76
87
|
this.hasSubscribedToEvents = false;
|
|
88
|
+
this.announceStatus = ANNOUNCE_STATUS.IDLE;
|
|
89
|
+
this.captionStatus = TURN_ON_CAPTION_STATUS.IDLE;
|
|
77
90
|
}
|
|
78
91
|
|
|
79
92
|
/**
|
|
@@ -83,9 +96,10 @@ export class VoiceaChannel extends WebexPlugin implements IVoiceaChannel {
|
|
|
83
96
|
constructor(...args) {
|
|
84
97
|
super(...args);
|
|
85
98
|
this.seqNum = 1;
|
|
86
|
-
this.hasVoiceaJoined = false;
|
|
87
99
|
this.areCaptionsEnabled = false;
|
|
88
100
|
this.vmcDeviceId = undefined;
|
|
101
|
+
this.announceStatus = ANNOUNCE_STATUS.IDLE;
|
|
102
|
+
this.captionStatus = TURN_ON_CAPTION_STATUS.IDLE;
|
|
89
103
|
}
|
|
90
104
|
|
|
91
105
|
/**
|
|
@@ -243,9 +257,7 @@ export class VoiceaChannel extends WebexPlugin implements IVoiceaChannel {
|
|
|
243
257
|
* @returns {void}
|
|
244
258
|
*/
|
|
245
259
|
private sendAnnouncement = (): void => {
|
|
246
|
-
|
|
247
|
-
if (this.hasVoiceaJoined || !this.webex.internal.llm.isConnected()) return;
|
|
248
|
-
|
|
260
|
+
this.announceStatus = ANNOUNCE_STATUS.JOINING;
|
|
249
261
|
this.listenToEvents();
|
|
250
262
|
// @ts-ignore
|
|
251
263
|
this.webex.internal.llm.socket.send({
|
|
@@ -327,11 +339,11 @@ export class VoiceaChannel extends WebexPlugin implements IVoiceaChannel {
|
|
|
327
339
|
};
|
|
328
340
|
|
|
329
341
|
/**
|
|
330
|
-
*
|
|
342
|
+
* request turn on Captions
|
|
331
343
|
* @returns {Promise}
|
|
332
344
|
*/
|
|
333
|
-
|
|
334
|
-
|
|
345
|
+
private requestTurnOnCaptions = (): undefined | Promise<void> => {
|
|
346
|
+
this.captionStatus = TURN_ON_CAPTION_STATUS.SENDING;
|
|
335
347
|
// @ts-ignore
|
|
336
348
|
// eslint-disable-next-line newline-before-return
|
|
337
349
|
return this.request({
|
|
@@ -341,18 +353,65 @@ export class VoiceaChannel extends WebexPlugin implements IVoiceaChannel {
|
|
|
341
353
|
body: {
|
|
342
354
|
transcribe: {caption: true},
|
|
343
355
|
},
|
|
344
|
-
})
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
+
})
|
|
357
|
+
.then(() => {
|
|
358
|
+
Trigger.trigger(
|
|
359
|
+
this,
|
|
360
|
+
{
|
|
361
|
+
file: 'voicea',
|
|
362
|
+
function: 'turnOnCaptions',
|
|
363
|
+
},
|
|
364
|
+
EVENT_TRIGGERS.CAPTIONS_TURNED_ON
|
|
365
|
+
);
|
|
366
|
+
this.areCaptionsEnabled = true;
|
|
367
|
+
this.captionStatus = TURN_ON_CAPTION_STATUS.ENABLED;
|
|
368
|
+
this.announce();
|
|
369
|
+
})
|
|
370
|
+
.catch(() => {
|
|
371
|
+
this.captionStatus = TURN_ON_CAPTION_STATUS.IDLE;
|
|
372
|
+
throw new Error('turn on captions fail');
|
|
373
|
+
});
|
|
374
|
+
};
|
|
375
|
+
|
|
376
|
+
/**
|
|
377
|
+
* is announce processing
|
|
378
|
+
* @returns {boolean}
|
|
379
|
+
*/
|
|
380
|
+
private isAnnounceProcessing = () =>
|
|
381
|
+
[ANNOUNCE_STATUS.JOINING, ANNOUNCE_STATUS.JOINED].includes(this.announceStatus);
|
|
382
|
+
|
|
383
|
+
/**
|
|
384
|
+
* announce to voicea data chanel
|
|
385
|
+
* @returns {void}
|
|
386
|
+
*/
|
|
387
|
+
public announce = () => {
|
|
388
|
+
if (this.isAnnounceProcessing()) return;
|
|
389
|
+
// @ts-ignore
|
|
390
|
+
if (!this.webex.internal.llm.isConnected()) {
|
|
391
|
+
throw new Error('voicea can not announce before llm connected');
|
|
392
|
+
}
|
|
393
|
+
this.sendAnnouncement();
|
|
394
|
+
};
|
|
395
|
+
|
|
396
|
+
/**
|
|
397
|
+
* is turn on caption processing
|
|
398
|
+
* @returns {boolean}
|
|
399
|
+
*/
|
|
400
|
+
private isCaptionProcessing = () =>
|
|
401
|
+
[TURN_ON_CAPTION_STATUS.SENDING, TURN_ON_CAPTION_STATUS.ENABLED].includes(this.captionStatus);
|
|
402
|
+
|
|
403
|
+
/**
|
|
404
|
+
* Turn on Captions
|
|
405
|
+
* @returns {Promise}
|
|
406
|
+
*/
|
|
407
|
+
public turnOnCaptions = async (): undefined | Promise<void> => {
|
|
408
|
+
if (this.isCaptionProcessing()) return undefined;
|
|
409
|
+
// @ts-ignore
|
|
410
|
+
if (!this.webex.internal.llm.isConnected()) {
|
|
411
|
+
throw new Error('can not turn on captions before llm connected');
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
return this.requestTurnOnCaptions();
|
|
356
415
|
};
|
|
357
416
|
|
|
358
417
|
/**
|
|
@@ -370,9 +429,21 @@ export class VoiceaChannel extends WebexPlugin implements IVoiceaChannel {
|
|
|
370
429
|
transcribe: {transcribing: activate},
|
|
371
430
|
},
|
|
372
431
|
}).then(() => {
|
|
373
|
-
if (activate && !this.areCaptionsEnabled
|
|
432
|
+
if (activate && !this.areCaptionsEnabled) this.turnOnCaptions();
|
|
374
433
|
});
|
|
375
434
|
};
|
|
435
|
+
|
|
436
|
+
/**
|
|
437
|
+
* get caption status
|
|
438
|
+
* @returns {string}
|
|
439
|
+
*/
|
|
440
|
+
public getCaptionStatus = () => this.captionStatus;
|
|
441
|
+
|
|
442
|
+
/**
|
|
443
|
+
* get announce status
|
|
444
|
+
* @returns {string}
|
|
445
|
+
*/
|
|
446
|
+
public getAnnounceStatus = () => this.announceStatus;
|
|
376
447
|
}
|
|
377
448
|
|
|
378
449
|
export default VoiceaChannel;
|
package/src/voicea.types.ts
CHANGED
|
@@ -79,7 +79,7 @@ interface IVoiceaChannel {
|
|
|
79
79
|
requestLanguage: (languageCode: string) => void;
|
|
80
80
|
turnOnCaptions: () => undefined | Promise<void>;
|
|
81
81
|
toggleTranscribing: (activate: boolean) => undefined | Promise<void>;
|
|
82
|
-
deregisterEvents: () =>
|
|
82
|
+
deregisterEvents: () => void;
|
|
83
83
|
}
|
|
84
84
|
|
|
85
85
|
export type {
|
package/test/unit/spec/voicea.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import 'jsdom-global/register';
|
|
1
2
|
import MockWebex from '@webex/test-helper-mock-webex';
|
|
2
3
|
import MockWebSocket from '@webex/test-helper-mock-web-socket';
|
|
3
|
-
import {assert} from '@webex/test-helper-chai';
|
|
4
|
+
import {assert, expect} from '@webex/test-helper-chai';
|
|
4
5
|
import sinon from 'sinon';
|
|
5
6
|
import Mercury from '@webex/internal-plugin-mercury';
|
|
6
7
|
import LLMChannel from '@webex/internal-plugin-llm';
|
|
@@ -41,17 +42,26 @@ describe('plugin-voicea', () => {
|
|
|
41
42
|
});
|
|
42
43
|
});
|
|
43
44
|
|
|
45
|
+
describe("#constructor", () => {
|
|
46
|
+
it('should init status', () => {
|
|
47
|
+
assert.equal(voiceaService.announceStatus, 'idle');
|
|
48
|
+
assert.equal(voiceaService.captionStatus, 'idle');
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
|
|
44
52
|
describe('#sendAnnouncement', () => {
|
|
45
53
|
beforeEach(async () => {
|
|
46
54
|
const mockWebSocket = new MockWebSocket();
|
|
47
55
|
|
|
48
56
|
voiceaService.webex.internal.llm.socket = mockWebSocket;
|
|
57
|
+
voiceaService.announceStatus = "idle";
|
|
49
58
|
});
|
|
50
59
|
|
|
51
60
|
it("sends announcement if voicea hasn't joined", () => {
|
|
52
61
|
const spy = sinon.spy(voiceaService, 'listenToEvents');
|
|
53
62
|
|
|
54
63
|
voiceaService.sendAnnouncement();
|
|
64
|
+
assert.equal(voiceaService.announceStatus, 'joining');
|
|
55
65
|
assert.calledOnce(spy);
|
|
56
66
|
|
|
57
67
|
assert.calledOnceWithExactly(voiceaService.webex.internal.llm.socket.send, {
|
|
@@ -98,14 +108,14 @@ describe('plugin-voicea', () => {
|
|
|
98
108
|
data: {relayType: 'voicea.annc', voiceaPayload: {}},
|
|
99
109
|
});
|
|
100
110
|
|
|
101
|
-
assert.equal(voiceaService.hasVoiceaJoined, true);
|
|
102
111
|
assert.equal(voiceaService.areCaptionsEnabled, true);
|
|
103
112
|
assert.equal(voiceaService.vmcDeviceId, 'ws');
|
|
104
113
|
|
|
105
114
|
voiceaService.deregisterEvents();
|
|
106
|
-
assert.equal(voiceaService.hasVoiceaJoined, false);
|
|
107
115
|
assert.equal(voiceaService.areCaptionsEnabled, false);
|
|
108
116
|
assert.equal(voiceaService.vmcDeviceId, undefined);
|
|
117
|
+
assert.equal(voiceaService.announceStatus, 'idle');
|
|
118
|
+
assert.equal(voiceaService.captionStatus, 'idle');
|
|
109
119
|
});
|
|
110
120
|
});
|
|
111
121
|
describe('#processAnnouncementMessage', () => {
|
|
@@ -198,22 +208,28 @@ describe('plugin-voicea', () => {
|
|
|
198
208
|
});
|
|
199
209
|
});
|
|
200
210
|
|
|
201
|
-
describe('#
|
|
211
|
+
describe('#requestTurnOnCaptions', () => {
|
|
202
212
|
beforeEach(async () => {
|
|
203
213
|
const mockWebSocket = new MockWebSocket();
|
|
204
214
|
|
|
205
215
|
voiceaService.webex.internal.llm.socket = mockWebSocket;
|
|
216
|
+
voiceaService.captionStatus = 'idle';
|
|
206
217
|
});
|
|
207
218
|
|
|
219
|
+
afterEach( () => {
|
|
220
|
+
voiceaService.captionStatus = 'idle';
|
|
221
|
+
})
|
|
222
|
+
|
|
208
223
|
it('turns on captions', async () => {
|
|
209
|
-
const announcementSpy = sinon.spy(voiceaService, '
|
|
224
|
+
const announcementSpy = sinon.spy(voiceaService, 'announce');
|
|
210
225
|
|
|
211
226
|
const triggerSpy = sinon.spy();
|
|
212
227
|
|
|
213
228
|
voiceaService.on(EVENT_TRIGGERS.CAPTIONS_TURNED_ON, triggerSpy);
|
|
214
229
|
voiceaService.listenToEvents();
|
|
215
230
|
|
|
216
|
-
await voiceaService.
|
|
231
|
+
await voiceaService.requestTurnOnCaptions();
|
|
232
|
+
assert.equal(voiceaService.captionStatus, 'enabled');
|
|
217
233
|
sinon.assert.calledWith(
|
|
218
234
|
voiceaService.request,
|
|
219
235
|
sinon.match({
|
|
@@ -228,18 +244,119 @@ describe('plugin-voicea', () => {
|
|
|
228
244
|
assert.calledOnce(announcementSpy);
|
|
229
245
|
});
|
|
230
246
|
|
|
231
|
-
it("
|
|
232
|
-
|
|
247
|
+
it("should handle request fail", async () => {
|
|
248
|
+
voiceaService.captionStatus = 'sending';
|
|
249
|
+
voiceaService.request = sinon.stub().rejects();
|
|
250
|
+
|
|
251
|
+
try {
|
|
252
|
+
await voiceaService.requestTurnOnCaptions();
|
|
253
|
+
} catch (error) {
|
|
254
|
+
expect(error.message).to.include('turn on captions fail');
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
assert.equal(voiceaService.captionStatus, 'idle');
|
|
258
|
+
});
|
|
259
|
+
});
|
|
233
260
|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
261
|
+
describe("#isAnnounceProcessing", () => {
|
|
262
|
+
afterEach(() => {
|
|
263
|
+
voiceaService.announceStatus = 'idle';
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
['joining', 'joined'].forEach((status) => {
|
|
267
|
+
it(`should return true when status is ${status}`, () => {
|
|
268
|
+
voiceaService.announceStatus = status;
|
|
269
|
+
assert.equal(voiceaService.isAnnounceProcessing(), true);
|
|
270
|
+
});
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
it('should return false when status is not processing status', () => {
|
|
274
|
+
voiceaService.announceStatus = 'idle';
|
|
275
|
+
assert.equal(voiceaService.isAnnounceProcessing(), false);
|
|
276
|
+
});
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
describe("#announce", () => {
|
|
280
|
+
let isAnnounceProcessing, sendAnnouncement;
|
|
281
|
+
beforeEach(() => {
|
|
282
|
+
voiceaService.webex.internal.llm.isConnected.returns(true);
|
|
283
|
+
sendAnnouncement = sinon.stub(voiceaService, 'sendAnnouncement');
|
|
284
|
+
isAnnounceProcessing = sinon.stub(voiceaService, 'isAnnounceProcessing').returns(false)
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
afterEach(() => {
|
|
288
|
+
voiceaService.webex.internal.llm.isConnected.returns(true);
|
|
289
|
+
isAnnounceProcessing.restore();
|
|
290
|
+
sendAnnouncement.restore();
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
it('announce to llm data channel', ()=> {
|
|
294
|
+
voiceaService.announce();
|
|
295
|
+
assert.calledOnce(sendAnnouncement);
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
it('announce to llm data channel before llm connected', ()=> {
|
|
299
|
+
voiceaService.webex.internal.llm.isConnected.returns(false);
|
|
300
|
+
assert.throws(() => voiceaService.announce(), "voicea can not announce before llm connected");
|
|
301
|
+
assert.notCalled(sendAnnouncement);
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
it('should not announce duplicate', () => {
|
|
305
|
+
isAnnounceProcessing.returns(true);
|
|
306
|
+
voiceaService.announce();
|
|
307
|
+
assert.notCalled(sendAnnouncement);
|
|
308
|
+
})
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
describe("#isCaptionProcessing", () => {
|
|
312
|
+
afterEach(() => {
|
|
313
|
+
voiceaService.captionStatus = 'idle';
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
['sending', 'enabled'].forEach((status) => {
|
|
317
|
+
it(`should return true when status is ${status}`, () => {
|
|
318
|
+
voiceaService.captionStatus = status;
|
|
319
|
+
assert.equal(voiceaService.isCaptionProcessing(), true);
|
|
238
320
|
});
|
|
321
|
+
});
|
|
239
322
|
|
|
240
|
-
|
|
323
|
+
it('should return false when status is not processing status', () => {
|
|
324
|
+
voiceaService.captionStatus = 'idle';
|
|
325
|
+
assert.equal(voiceaService.isCaptionProcessing(), false);
|
|
326
|
+
});
|
|
327
|
+
});
|
|
241
328
|
|
|
242
|
-
|
|
329
|
+
describe('#turnOnCaptions', () => {
|
|
330
|
+
let requestTurnOnCaptions, isCaptionProcessing;
|
|
331
|
+
beforeEach(() => {
|
|
332
|
+
requestTurnOnCaptions = sinon.stub(voiceaService, 'requestTurnOnCaptions');
|
|
333
|
+
isCaptionProcessing = sinon.stub(voiceaService, 'isCaptionProcessing').returns(false);
|
|
334
|
+
voiceaService.webex.internal.llm.isConnected.returns(true);
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
afterEach(() => {
|
|
338
|
+
requestTurnOnCaptions.restore();
|
|
339
|
+
isCaptionProcessing.restore();
|
|
340
|
+
voiceaService.webex.internal.llm.isConnected.returns(true);
|
|
341
|
+
});
|
|
342
|
+
|
|
343
|
+
it('call request turn on captions', () => {
|
|
344
|
+
isCaptionProcessing.returns(false);
|
|
345
|
+
voiceaService.turnOnCaptions();
|
|
346
|
+
assert.calledOnce(requestTurnOnCaptions);
|
|
347
|
+
});
|
|
348
|
+
|
|
349
|
+
it("turns on captions before llm connected", () => {
|
|
350
|
+
isCaptionProcessing.returns(false);
|
|
351
|
+
voiceaService.webex.internal.llm.isConnected.returns(true);
|
|
352
|
+
// assert.throws(() => voiceaService.turnOnCaptions(), "can not turn on captions before llm connected");
|
|
353
|
+
assert.notCalled(requestTurnOnCaptions);
|
|
354
|
+
});
|
|
355
|
+
|
|
356
|
+
it('should not turn on duplicate when processing', () => {
|
|
357
|
+
isCaptionProcessing.returns(true);
|
|
358
|
+
voiceaService.turnOnCaptions();
|
|
359
|
+
assert.notCalled(voiceaService.requestTurnOnCaptions);
|
|
243
360
|
});
|
|
244
361
|
});
|
|
245
362
|
|
|
@@ -613,5 +730,19 @@ describe('plugin-voicea', () => {
|
|
|
613
730
|
});
|
|
614
731
|
});
|
|
615
732
|
});
|
|
733
|
+
|
|
734
|
+
describe("#getCaptionStatus", () => {
|
|
735
|
+
it('works correctly', () => {
|
|
736
|
+
voiceaService.captionStatus = "enabled"
|
|
737
|
+
assert.equal(voiceaService.getCaptionStatus(), "enabled");
|
|
738
|
+
});
|
|
739
|
+
});
|
|
740
|
+
|
|
741
|
+
describe("#getAnnounceStatus", () => {
|
|
742
|
+
it('works correctly', () => {
|
|
743
|
+
voiceaService.announceStatus = "joined"
|
|
744
|
+
assert.equal(voiceaService.getAnnounceStatus(), "joined");
|
|
745
|
+
});
|
|
746
|
+
});
|
|
616
747
|
});
|
|
617
748
|
});
|