@webex/internal-plugin-voicea 3.0.0-beta.4 → 3.0.0-beta.400
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +24 -21
- package/dist/constants.js +13 -3
- package/dist/constants.js.map +1 -1
- package/dist/index.js +13 -11
- package/dist/index.js.map +1 -1
- package/dist/utils.js +0 -4
- package/dist/utils.js.map +1 -1
- package/dist/voicea.js +136 -148
- package/dist/voicea.js.map +1 -1
- package/dist/voicea.types.js +0 -1
- package/dist/voicea.types.js.map +1 -1
- package/package.json +8 -9
- package/src/constants.ts +15 -3
- package/src/index.ts +1 -0
- package/src/utils.ts +1 -2
- package/src/voicea.ts +149 -50
- package/src/voicea.types.ts +3 -3
- package/test/unit/spec/voicea.js +156 -44
package/src/constants.ts
CHANGED
|
@@ -8,7 +8,7 @@ export const EVENT_TRIGGERS = {
|
|
|
8
8
|
|
|
9
9
|
NEW_CAPTION: 'voicea:newCaption',
|
|
10
10
|
EVA_COMMAND: 'voicea:wxa',
|
|
11
|
-
HIGHLIGHT_CREATED: 'voicea:highlightCreated'
|
|
11
|
+
HIGHLIGHT_CREATED: 'voicea:highlightCreated',
|
|
12
12
|
};
|
|
13
13
|
|
|
14
14
|
export const VOICEA_RELAY_TYPES = {
|
|
@@ -16,7 +16,7 @@ export const VOICEA_RELAY_TYPES = {
|
|
|
16
16
|
CLIENT_ANNOUNCEMENT: 'client.annc',
|
|
17
17
|
TRANSLATION_REQUEST: 'voicea.transl.req',
|
|
18
18
|
TRANSLATION_RESPONSE: 'voicea.transl.rsp',
|
|
19
|
-
TRANSCRIPTION: 'voicea.transcription'
|
|
19
|
+
TRANSCRIPTION: 'voicea.transcription',
|
|
20
20
|
};
|
|
21
21
|
|
|
22
22
|
export const TRANSCRIPTION_TYPE = {
|
|
@@ -26,7 +26,19 @@ export const TRANSCRIPTION_TYPE = {
|
|
|
26
26
|
EVA_CANCEL: 'eva_cancel',
|
|
27
27
|
HIGHLIGHT_CREATED: 'highlight_created',
|
|
28
28
|
TRANSCRIPT_INTERIM_RESULTS: 'transcript_interim_results',
|
|
29
|
-
TRANSCRIPT_FINAL_RESULT: 'transcript_final_result'
|
|
29
|
+
TRANSCRIPT_FINAL_RESULT: 'transcript_final_result',
|
|
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/index.ts
CHANGED
package/src/utils.ts
CHANGED
|
@@ -3,6 +3,5 @@ export const millisToMinutesAndSeconds = (millis: number) => {
|
|
|
3
3
|
const minutes = Math.floor(millis / 60000);
|
|
4
4
|
const seconds = ((millis % 60000) / 1000).toFixed(0);
|
|
5
5
|
|
|
6
|
-
return `${minutes}:${+
|
|
6
|
+
return `${minutes}:${+seconds < 10 ? '0' : ''}${seconds}`;
|
|
7
7
|
};
|
|
8
|
-
|
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,
|
|
@@ -13,30 +20,36 @@ import {
|
|
|
13
20
|
import {millisToMinutesAndSeconds} from './utils';
|
|
14
21
|
|
|
15
22
|
/**
|
|
16
|
-
* VoiceaChannel to hold single instance of LLM
|
|
23
|
+
* @description VoiceaChannel to hold single instance of LLM
|
|
24
|
+
* @export
|
|
25
|
+
* @class VoiceaChannel
|
|
17
26
|
*/
|
|
18
27
|
export class VoiceaChannel extends WebexPlugin implements IVoiceaChannel {
|
|
19
28
|
namespace = VOICEA;
|
|
20
29
|
|
|
21
30
|
private seqNum: number;
|
|
22
31
|
|
|
23
|
-
private hasVoiceaJoined: boolean;
|
|
24
|
-
|
|
25
32
|
private areCaptionsEnabled: boolean;
|
|
26
33
|
|
|
27
|
-
private
|
|
28
|
-
|
|
29
|
-
private hasSubscribedToEvents: boolean = false;
|
|
34
|
+
private hasSubscribedToEvents = false;
|
|
30
35
|
|
|
31
36
|
private vmcDeviceId?: string;
|
|
32
37
|
|
|
38
|
+
private announceStatus: string;
|
|
39
|
+
|
|
40
|
+
private captionStatus: string;
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* @param {Object} e
|
|
44
|
+
* @returns {undefined}
|
|
45
|
+
*/
|
|
46
|
+
|
|
33
47
|
private eventProcessor = (e) => {
|
|
34
|
-
e;
|
|
35
48
|
this.seqNum = e.sequenceNumber + 1;
|
|
36
49
|
switch (e.data.relayType) {
|
|
37
50
|
case VOICEA_RELAY_TYPES.ANNOUNCEMENT:
|
|
38
51
|
this.vmcDeviceId = e.headers.from;
|
|
39
|
-
this.
|
|
52
|
+
this.announceStatus = ANNOUNCE_STATUS.JOINED;
|
|
40
53
|
this.processAnnouncementMessage(e.data.voiceaPayload);
|
|
41
54
|
break;
|
|
42
55
|
case VOICEA_RELAY_TYPES.TRANSLATION_RESPONSE:
|
|
@@ -49,23 +62,31 @@ export class VoiceaChannel extends WebexPlugin implements IVoiceaChannel {
|
|
|
49
62
|
break;
|
|
50
63
|
}
|
|
51
64
|
};
|
|
65
|
+
|
|
52
66
|
/**
|
|
53
67
|
* Listen to websocket messages
|
|
68
|
+
* @returns {undefined}
|
|
54
69
|
*/
|
|
55
70
|
private listenToEvents() {
|
|
56
71
|
if (!this.hasSubscribedToEvents) {
|
|
72
|
+
// @ts-ignore
|
|
57
73
|
this.webex.internal.llm.on('event:relay.event', this.eventProcessor);
|
|
58
74
|
this.hasSubscribedToEvents = true;
|
|
59
75
|
}
|
|
60
76
|
}
|
|
61
77
|
|
|
78
|
+
/**
|
|
79
|
+
* Listen to websocket messages
|
|
80
|
+
* @returns {void}
|
|
81
|
+
*/
|
|
62
82
|
public deregisterEvents() {
|
|
63
|
-
this.hasVoiceaJoined = false;
|
|
64
83
|
this.areCaptionsEnabled = false;
|
|
65
|
-
this.isTranscribingEnabled = false;
|
|
66
84
|
this.vmcDeviceId = undefined;
|
|
85
|
+
// @ts-ignore
|
|
67
86
|
this.webex.internal.llm.off('event:relay.event', this.eventProcessor);
|
|
68
87
|
this.hasSubscribedToEvents = false;
|
|
88
|
+
this.announceStatus = ANNOUNCE_STATUS.IDLE;
|
|
89
|
+
this.captionStatus = TURN_ON_CAPTION_STATUS.IDLE;
|
|
69
90
|
}
|
|
70
91
|
|
|
71
92
|
/**
|
|
@@ -75,10 +96,10 @@ export class VoiceaChannel extends WebexPlugin implements IVoiceaChannel {
|
|
|
75
96
|
constructor(...args) {
|
|
76
97
|
super(...args);
|
|
77
98
|
this.seqNum = 1;
|
|
78
|
-
this.hasVoiceaJoined = false;
|
|
79
99
|
this.areCaptionsEnabled = false;
|
|
80
|
-
this.isTranscribingEnabled = false;
|
|
81
100
|
this.vmcDeviceId = undefined;
|
|
101
|
+
this.announceStatus = ANNOUNCE_STATUS.IDLE;
|
|
102
|
+
this.captionStatus = TURN_ON_CAPTION_STATUS.IDLE;
|
|
82
103
|
}
|
|
83
104
|
|
|
84
105
|
/**
|
|
@@ -115,6 +136,7 @@ export class VoiceaChannel extends WebexPlugin implements IVoiceaChannel {
|
|
|
115
136
|
{
|
|
116
137
|
isFinal: true,
|
|
117
138
|
transcriptId: voiceaPayload.transcript_id,
|
|
139
|
+
translations: voiceaPayload.translations,
|
|
118
140
|
transcript: {
|
|
119
141
|
csis: voiceaPayload.csis,
|
|
120
142
|
text: voiceaPayload.transcript.text,
|
|
@@ -236,14 +258,14 @@ export class VoiceaChannel extends WebexPlugin implements IVoiceaChannel {
|
|
|
236
258
|
* @returns {void}
|
|
237
259
|
*/
|
|
238
260
|
private sendAnnouncement = (): void => {
|
|
239
|
-
|
|
240
|
-
|
|
261
|
+
this.announceStatus = ANNOUNCE_STATUS.JOINING;
|
|
241
262
|
this.listenToEvents();
|
|
242
|
-
|
|
263
|
+
// @ts-ignore
|
|
243
264
|
this.webex.internal.llm.socket.send({
|
|
244
265
|
id: `${this.seqNum}`,
|
|
245
266
|
type: 'publishRequest',
|
|
246
267
|
recipients: {
|
|
268
|
+
// @ts-ignore
|
|
247
269
|
route: this.webex.internal.llm.getBinding(),
|
|
248
270
|
},
|
|
249
271
|
headers: {},
|
|
@@ -265,11 +287,15 @@ export class VoiceaChannel extends WebexPlugin implements IVoiceaChannel {
|
|
|
265
287
|
* @returns {Promise}
|
|
266
288
|
*/
|
|
267
289
|
public setSpokenLanguage = (languageCode: string): Promise<void> =>
|
|
290
|
+
// @ts-ignore
|
|
268
291
|
this.request({
|
|
269
292
|
method: 'PUT',
|
|
293
|
+
// @ts-ignore
|
|
270
294
|
url: `${this.webex.internal.llm.getLocusUrl()}/controls/`,
|
|
271
295
|
body: {
|
|
272
|
-
|
|
296
|
+
transcribe: {
|
|
297
|
+
spokenLanguage: languageCode,
|
|
298
|
+
},
|
|
273
299
|
},
|
|
274
300
|
}).then(() => {
|
|
275
301
|
Trigger.trigger(
|
|
@@ -289,11 +315,14 @@ export class VoiceaChannel extends WebexPlugin implements IVoiceaChannel {
|
|
|
289
315
|
* @returns {void}
|
|
290
316
|
*/
|
|
291
317
|
public requestLanguage = (languageCode: string): void => {
|
|
318
|
+
// @ts-ignore
|
|
292
319
|
if (!this.webex.internal.llm.isConnected()) return;
|
|
320
|
+
// @ts-ignore
|
|
293
321
|
this.webex.internal.llm.socket.send({
|
|
294
322
|
id: `${this.seqNum}`,
|
|
295
323
|
type: 'publishRequest',
|
|
296
324
|
recipients: {
|
|
325
|
+
// @ts-ignore
|
|
297
326
|
route: this.webex.internal.llm.getBinding(),
|
|
298
327
|
},
|
|
299
328
|
headers: {
|
|
@@ -313,59 +342,129 @@ export class VoiceaChannel extends WebexPlugin implements IVoiceaChannel {
|
|
|
313
342
|
};
|
|
314
343
|
|
|
315
344
|
/**
|
|
316
|
-
*
|
|
345
|
+
* request turn on Captions
|
|
346
|
+
* @param {string} [languageCode] - Optional Parameter for spoken language code. Defaults to English
|
|
317
347
|
* @returns {Promise}
|
|
318
348
|
*/
|
|
319
|
-
|
|
320
|
-
|
|
349
|
+
private requestTurnOnCaptions = (languageCode?): undefined | Promise<void> => {
|
|
350
|
+
this.captionStatus = TURN_ON_CAPTION_STATUS.SENDING;
|
|
351
|
+
|
|
352
|
+
// only set the spoken language if it is provided
|
|
353
|
+
const body = {
|
|
354
|
+
transcribe: {caption: true},
|
|
355
|
+
languageCode,
|
|
356
|
+
};
|
|
321
357
|
|
|
358
|
+
// @ts-ignore
|
|
359
|
+
// eslint-disable-next-line newline-before-return
|
|
322
360
|
return this.request({
|
|
323
361
|
method: 'PUT',
|
|
362
|
+
// @ts-ignore
|
|
324
363
|
url: `${this.webex.internal.llm.getLocusUrl()}/controls/`,
|
|
325
|
-
body
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
364
|
+
body,
|
|
365
|
+
})
|
|
366
|
+
.then(() => {
|
|
367
|
+
Trigger.trigger(
|
|
368
|
+
this,
|
|
369
|
+
{
|
|
370
|
+
file: 'voicea',
|
|
371
|
+
function: 'turnOnCaptions',
|
|
372
|
+
},
|
|
373
|
+
EVENT_TRIGGERS.CAPTIONS_TURNED_ON
|
|
374
|
+
);
|
|
375
|
+
this.areCaptionsEnabled = true;
|
|
376
|
+
this.captionStatus = TURN_ON_CAPTION_STATUS.ENABLED;
|
|
377
|
+
this.announce();
|
|
378
|
+
})
|
|
379
|
+
.catch(() => {
|
|
380
|
+
this.captionStatus = TURN_ON_CAPTION_STATUS.IDLE;
|
|
381
|
+
throw new Error('turn on captions fail');
|
|
382
|
+
});
|
|
383
|
+
};
|
|
384
|
+
|
|
385
|
+
/**
|
|
386
|
+
* is announce processing
|
|
387
|
+
* @returns {boolean}
|
|
388
|
+
*/
|
|
389
|
+
private isAnnounceProcessing = () =>
|
|
390
|
+
[ANNOUNCE_STATUS.JOINING, ANNOUNCE_STATUS.JOINED].includes(this.announceStatus);
|
|
391
|
+
|
|
392
|
+
/**
|
|
393
|
+
* announce to voicea data chanel
|
|
394
|
+
* @returns {void}
|
|
395
|
+
*/
|
|
396
|
+
public announce = () => {
|
|
397
|
+
if (this.isAnnounceProcessing()) return;
|
|
398
|
+
// @ts-ignore
|
|
399
|
+
if (!this.webex.internal.llm.isConnected()) {
|
|
400
|
+
throw new Error('voicea can not announce before llm connected');
|
|
401
|
+
}
|
|
402
|
+
this.sendAnnouncement();
|
|
403
|
+
};
|
|
404
|
+
|
|
405
|
+
/**
|
|
406
|
+
* is turn on caption processing
|
|
407
|
+
* @returns {boolean}
|
|
408
|
+
*/
|
|
409
|
+
private isCaptionProcessing = () =>
|
|
410
|
+
[TURN_ON_CAPTION_STATUS.SENDING, TURN_ON_CAPTION_STATUS.ENABLED].includes(this.captionStatus);
|
|
411
|
+
|
|
412
|
+
/**
|
|
413
|
+
* Turn on Captions
|
|
414
|
+
* @param {string} [spokenLanguage] - Optional Spoken language code
|
|
415
|
+
* @returns {Promise}
|
|
416
|
+
*/
|
|
417
|
+
public turnOnCaptions = async (spokenLanguage?): undefined | Promise<void> => {
|
|
418
|
+
if (this.isCaptionProcessing()) return undefined;
|
|
419
|
+
// @ts-ignore
|
|
420
|
+
if (!this.webex.internal.llm.isConnected()) {
|
|
421
|
+
throw new Error('can not turn on captions before llm connected');
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
return this.requestTurnOnCaptions(spokenLanguage);
|
|
340
425
|
};
|
|
341
426
|
|
|
342
427
|
/**
|
|
343
428
|
* Toggle transcribing for highlights
|
|
344
429
|
* @param {bool} activate if true transcribing is turned on
|
|
430
|
+
* @param {string} spokenLanguage language code for spoken language
|
|
345
431
|
* @returns {Promise}
|
|
346
432
|
*/
|
|
347
|
-
public toggleTranscribing =
|
|
348
|
-
|
|
349
|
-
|
|
433
|
+
public toggleTranscribing = (
|
|
434
|
+
activate: boolean,
|
|
435
|
+
spokenLanguage?: string
|
|
436
|
+
): undefined | Promise<void> => {
|
|
437
|
+
// @ts-ignore
|
|
350
438
|
return this.request({
|
|
351
439
|
method: 'PUT',
|
|
440
|
+
// @ts-ignore
|
|
352
441
|
url: `${this.webex.internal.llm.getLocusUrl()}/controls/`,
|
|
353
442
|
body: {
|
|
354
|
-
transcribe: {
|
|
355
|
-
|
|
356
|
-
}).then(() => {
|
|
357
|
-
Trigger.trigger(
|
|
358
|
-
this,
|
|
359
|
-
{
|
|
360
|
-
file: 'voicea',
|
|
361
|
-
function: 'toggleTranscribing',
|
|
443
|
+
transcribe: {
|
|
444
|
+
transcribing: activate,
|
|
362
445
|
},
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
if (activate && !this.areCaptionsEnabled
|
|
446
|
+
spokenLanguage,
|
|
447
|
+
},
|
|
448
|
+
}).then((): undefined | Promise<void> => {
|
|
449
|
+
if (activate && !this.areCaptionsEnabled) {
|
|
450
|
+
return this.turnOnCaptions(spokenLanguage);
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
return undefined;
|
|
367
454
|
});
|
|
368
455
|
};
|
|
456
|
+
|
|
457
|
+
/**
|
|
458
|
+
* get caption status
|
|
459
|
+
* @returns {string}
|
|
460
|
+
*/
|
|
461
|
+
public getCaptionStatus = () => this.captionStatus;
|
|
462
|
+
|
|
463
|
+
/**
|
|
464
|
+
* get announce status
|
|
465
|
+
* @returns {string}
|
|
466
|
+
*/
|
|
467
|
+
public getAnnounceStatus = () => this.announceStatus;
|
|
369
468
|
}
|
|
370
469
|
|
|
371
470
|
export default VoiceaChannel;
|
package/src/voicea.types.ts
CHANGED
|
@@ -78,11 +78,11 @@ interface IVoiceaChannel {
|
|
|
78
78
|
setSpokenLanguage: (languageCode: string) => Promise<void>;
|
|
79
79
|
requestLanguage: (languageCode: string) => void;
|
|
80
80
|
turnOnCaptions: () => undefined | Promise<void>;
|
|
81
|
-
toggleTranscribing: (activate: boolean) => undefined | Promise<void>;
|
|
82
|
-
deregisterEvents: () =>
|
|
81
|
+
toggleTranscribing: (activate: boolean, spokenLanguage: string) => undefined | Promise<void>;
|
|
82
|
+
deregisterEvents: () => void;
|
|
83
83
|
}
|
|
84
84
|
|
|
85
|
-
export {
|
|
85
|
+
export type {
|
|
86
86
|
AnnouncementPayload,
|
|
87
87
|
CaptionLanguageResponse,
|
|
88
88
|
TranscriptionResponse,
|