agora-appbuilder-core 4.1.24-beta.3 → 4.1.25-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/template/customization-api/index.ts +0 -1
- package/template/defaultConfig.js +2 -2
- package/template/src/auth/AuthProvider.tsx +0 -9
- package/template/src/logger/AppBuilderLogger.tsx +4 -3
- package/template/src/subComponents/caption/Transcript.tsx +0 -36
- package/template/src/subComponents/caption/__tests__/transcriptStreamListener.test.ts +47 -0
- package/template/src/subComponents/caption/transcriptStreamListener.ts +50 -0
- package/template/src/subComponents/caption/useCaption.tsx +120 -190
- package/template/src/subComponents/caption/useSTTAPI.tsx +12 -13
- package/template/src/subComponents/caption/useStreamMessageUtils.ts +8 -109
- package/template/customization-api/logger.ts +0 -33
- package/template/src/subComponents/caption/__tests__/transcriptJourney.test.ts +0 -7
package/package.json
CHANGED
|
@@ -21,7 +21,6 @@ export {customize, $config};
|
|
|
21
21
|
export * from './action-library';
|
|
22
22
|
export * from './app-state';
|
|
23
23
|
export * from './customEvents';
|
|
24
|
-
export * from './logger';
|
|
25
24
|
export * from './sub-components';
|
|
26
25
|
export * from './typeDefinition';
|
|
27
26
|
export * from './utils';
|
|
@@ -77,8 +77,8 @@ const DefaultConfig = {
|
|
|
77
77
|
CHAT_ORG_NAME: "",
|
|
78
78
|
CHAT_APP_NAME: "",
|
|
79
79
|
CHAT_URL: "",
|
|
80
|
-
CLI_VERSION: "3.1.
|
|
81
|
-
CORE_VERSION: "4.1.
|
|
80
|
+
CLI_VERSION: "3.1.25-beta.1",
|
|
81
|
+
CORE_VERSION: "4.1.25-beta.1",
|
|
82
82
|
DISABLE_LANDSCAPE_MODE: false,
|
|
83
83
|
STT_AUTO_START: false,
|
|
84
84
|
CLOUD_RECORDING_AUTO_START: false,
|
|
@@ -137,15 +137,6 @@ const AuthProvider = (props: AuthProviderProps) => {
|
|
|
137
137
|
}
|
|
138
138
|
}, [store?.token]);
|
|
139
139
|
|
|
140
|
-
// A running native app is already authenticated when it receives a URL
|
|
141
|
-
// event, so there may be no later token change to consume returnTo.
|
|
142
|
-
useEffect(() => {
|
|
143
|
-
if (authenticated && returnTo && (isAndroid() || isIOS())) {
|
|
144
|
-
history.push(returnTo);
|
|
145
|
-
setReturnTo('');
|
|
146
|
-
}
|
|
147
|
-
}, [authenticated, history, returnTo]);
|
|
148
|
-
|
|
149
140
|
const deepLinkUrl = (link: string | null) => {
|
|
150
141
|
if (link !== null) {
|
|
151
142
|
if (lifecycle?.onDeepLink?.(link)) {
|
|
@@ -38,8 +38,6 @@ export declare const StatusTypes: {
|
|
|
38
38
|
|
|
39
39
|
export type StatusType = (typeof StatusTypes)[keyof typeof StatusTypes];
|
|
40
40
|
|
|
41
|
-
export type CustomizationLogType = string;
|
|
42
|
-
|
|
43
41
|
export enum LogSource {
|
|
44
42
|
AgoraSDK = 'Agora-SDK',
|
|
45
43
|
/** Logs related to all features */
|
|
@@ -109,7 +107,10 @@ type LogType = {
|
|
|
109
107
|
| 'recording_delete'
|
|
110
108
|
| 'ban_user';
|
|
111
109
|
[LogSource.Events]: 'CUSTOM_EVENTS' | 'RTM_EVENTS';
|
|
112
|
-
[LogSource.CustomizationAPI]:
|
|
110
|
+
[LogSource.CustomizationAPI]:
|
|
111
|
+
| 'Log'
|
|
112
|
+
| 'AI_AGENT_CUSTOMIZATION'
|
|
113
|
+
| 'EXTERNAL_CUSTOMIZATION';
|
|
113
114
|
[LogSource.SDK]: 'Log' | 'Event';
|
|
114
115
|
};
|
|
115
116
|
|
|
@@ -40,8 +40,6 @@ import {
|
|
|
40
40
|
sttTranscriptPanelSearchText,
|
|
41
41
|
sttTranscriptPanelViewLatestText,
|
|
42
42
|
} from '../../../src/language/default-labels/videoCallScreenLabels';
|
|
43
|
-
import {logger, LogSource} from '../../logger/AppBuilderLogger';
|
|
44
|
-
import {TRANSCRIPT_JOURNEY} from './transcriptJourney';
|
|
45
43
|
|
|
46
44
|
export interface TranscriptProps {
|
|
47
45
|
showHeader?: boolean;
|
|
@@ -58,7 +56,6 @@ const Transcript = (props: TranscriptProps) => {
|
|
|
58
56
|
isSTTActive,
|
|
59
57
|
selectedTranslationLanguage,
|
|
60
58
|
transcriptViewMode,
|
|
61
|
-
isSTTListenerAdded,
|
|
62
59
|
} = useCaption();
|
|
63
60
|
|
|
64
61
|
const settingSpokenLanguageLabel = useString(sttSettingSpokenLanguageText)();
|
|
@@ -71,39 +68,6 @@ const Transcript = (props: TranscriptProps) => {
|
|
|
71
68
|
|
|
72
69
|
const data = meetingTranscript; // Object.entries(transcript);
|
|
73
70
|
console.log('[STT_GLOBAL] meetingTranscript data: ', data);
|
|
74
|
-
const hasLoggedFirstEntryRef = React.useRef(false);
|
|
75
|
-
const transcriptEntryCountRef = React.useRef(data.length);
|
|
76
|
-
transcriptEntryCountRef.current = data.length;
|
|
77
|
-
|
|
78
|
-
React.useEffect(() => {
|
|
79
|
-
logger.log(
|
|
80
|
-
LogSource.Internals,
|
|
81
|
-
'TRANSCRIPT',
|
|
82
|
-
`${TRANSCRIPT_JOURNEY} transcript panel state`,
|
|
83
|
-
{
|
|
84
|
-
stage: 'transcript_panel',
|
|
85
|
-
isSTTActive,
|
|
86
|
-
listenerRegistered: isSTTListenerAdded,
|
|
87
|
-
transcriptEntryCount: transcriptEntryCountRef.current,
|
|
88
|
-
},
|
|
89
|
-
);
|
|
90
|
-
}, [isSTTActive, isSTTListenerAdded]);
|
|
91
|
-
|
|
92
|
-
React.useEffect(() => {
|
|
93
|
-
if (data.length > 0 && !hasLoggedFirstEntryRef.current) {
|
|
94
|
-
hasLoggedFirstEntryRef.current = true;
|
|
95
|
-
logger.log(
|
|
96
|
-
LogSource.Internals,
|
|
97
|
-
'TRANSCRIPT',
|
|
98
|
-
`${TRANSCRIPT_JOURNEY} first transcript entry available to panel`,
|
|
99
|
-
{
|
|
100
|
-
stage: 'transcript_panel_data',
|
|
101
|
-
outcome: 'success',
|
|
102
|
-
transcriptEntryCount: data.length,
|
|
103
|
-
},
|
|
104
|
-
);
|
|
105
|
-
}
|
|
106
|
-
}, [data.length]);
|
|
107
71
|
|
|
108
72
|
const [showButton, setShowButton] = React.useState(false);
|
|
109
73
|
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import {
|
|
2
|
+
registerTranscriptStreamListener,
|
|
3
|
+
removeTranscriptStreamListener,
|
|
4
|
+
TranscriptStreamEngine,
|
|
5
|
+
} from '../transcriptStreamListener';
|
|
6
|
+
|
|
7
|
+
describe('transcript stream listener lifecycle', () => {
|
|
8
|
+
it('tracks and removes a native listener when addListener returns void', () => {
|
|
9
|
+
const listener = jest.fn();
|
|
10
|
+
const engine: TranscriptStreamEngine = {
|
|
11
|
+
addListener: jest.fn(),
|
|
12
|
+
removeListener: jest.fn(),
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const registration = registerTranscriptStreamListener(engine, listener);
|
|
16
|
+
|
|
17
|
+
expect(registration).toEqual({subscription: null});
|
|
18
|
+
expect(engine.addListener).toHaveBeenCalledTimes(1);
|
|
19
|
+
expect(engine.addListener).toHaveBeenCalledWith(
|
|
20
|
+
'onStreamMessage',
|
|
21
|
+
listener,
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
removeTranscriptStreamListener(engine, listener, registration, false);
|
|
25
|
+
|
|
26
|
+
expect(engine.removeListener).toHaveBeenCalledTimes(1);
|
|
27
|
+
expect(engine.removeListener).toHaveBeenCalledWith(
|
|
28
|
+
'onStreamMessage',
|
|
29
|
+
listener,
|
|
30
|
+
);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it('uses the subscription returned by the web bridge', () => {
|
|
34
|
+
const listener = jest.fn();
|
|
35
|
+
const remove = jest.fn();
|
|
36
|
+
const engine: TranscriptStreamEngine = {
|
|
37
|
+
addListener: jest.fn(() => ({remove})),
|
|
38
|
+
removeListener: jest.fn(),
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const registration = registerTranscriptStreamListener(engine, listener);
|
|
42
|
+
removeTranscriptStreamListener(engine, listener, registration, true);
|
|
43
|
+
|
|
44
|
+
expect(remove).toHaveBeenCalledTimes(1);
|
|
45
|
+
expect(engine.removeListener).not.toHaveBeenCalled();
|
|
46
|
+
});
|
|
47
|
+
});
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
export type TranscriptStreamListener = (...args: any[]) => void;
|
|
2
|
+
|
|
3
|
+
type TranscriptStreamSubscription = {
|
|
4
|
+
remove: () => void;
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
export type TranscriptStreamEngine = {
|
|
8
|
+
addListener: (
|
|
9
|
+
event: 'onStreamMessage',
|
|
10
|
+
listener: TranscriptStreamListener,
|
|
11
|
+
) => unknown;
|
|
12
|
+
removeListener: (
|
|
13
|
+
event: 'onStreamMessage',
|
|
14
|
+
listener: TranscriptStreamListener,
|
|
15
|
+
) => void;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export type TranscriptStreamListenerRegistration = {
|
|
19
|
+
subscription: TranscriptStreamSubscription | null;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export const registerTranscriptStreamListener = (
|
|
23
|
+
engine: TranscriptStreamEngine,
|
|
24
|
+
listener: TranscriptStreamListener,
|
|
25
|
+
): TranscriptStreamListenerRegistration => {
|
|
26
|
+
const result = engine.addListener('onStreamMessage', listener);
|
|
27
|
+
const subscription =
|
|
28
|
+
result &&
|
|
29
|
+
typeof (result as TranscriptStreamSubscription).remove === 'function'
|
|
30
|
+
? (result as TranscriptStreamSubscription)
|
|
31
|
+
: null;
|
|
32
|
+
|
|
33
|
+
// Native Agora returns void from addListener. The registration object is our
|
|
34
|
+
// platform-independent proof that registration completed successfully.
|
|
35
|
+
return {subscription};
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export const removeTranscriptStreamListener = (
|
|
39
|
+
engine: TranscriptStreamEngine,
|
|
40
|
+
listener: TranscriptStreamListener,
|
|
41
|
+
registration: TranscriptStreamListenerRegistration,
|
|
42
|
+
web: boolean,
|
|
43
|
+
) => {
|
|
44
|
+
if (web) {
|
|
45
|
+
registration.subscription?.remove();
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
engine.removeListener('onStreamMessage', listener);
|
|
50
|
+
};
|
|
@@ -22,6 +22,12 @@ import {useContent, useRtc} from 'customization-api';
|
|
|
22
22
|
import useStreamMessageUtils from './useStreamMessageUtils';
|
|
23
23
|
import {isWebInternal} from '../../utils/common';
|
|
24
24
|
import {TRANSCRIPT_JOURNEY} from './transcriptJourney';
|
|
25
|
+
import {
|
|
26
|
+
registerTranscriptStreamListener,
|
|
27
|
+
removeTranscriptStreamListener,
|
|
28
|
+
TranscriptStreamEngine,
|
|
29
|
+
TranscriptStreamListenerRegistration,
|
|
30
|
+
} from './transcriptStreamListener';
|
|
25
31
|
|
|
26
32
|
// Types
|
|
27
33
|
type GlobalSttState = {
|
|
@@ -321,22 +327,20 @@ const CaptionProvider: React.FC<CaptionProviderProps> = ({
|
|
|
321
327
|
prevSpeakerRef,
|
|
322
328
|
selectedTranslationLanguageRef,
|
|
323
329
|
});
|
|
324
|
-
const
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
[streamMessageCallback],
|
|
339
|
-
);
|
|
330
|
+
const streamMessageCallbackRef = React.useRef(streamMessageCallback);
|
|
331
|
+
streamMessageCallbackRef.current = streamMessageCallback;
|
|
332
|
+
const transcriptListenerRegistrationRef =
|
|
333
|
+
React.useRef<TranscriptStreamListenerRegistration | null>(null);
|
|
334
|
+
|
|
335
|
+
const handleStreamMessageCallback = React.useCallback((...args: any[]) => {
|
|
336
|
+
if (isWebInternal()) {
|
|
337
|
+
const [uid, data] = args;
|
|
338
|
+
streamMessageCallbackRef.current([uid, data]);
|
|
339
|
+
} else {
|
|
340
|
+
const [, uid, , data] = args;
|
|
341
|
+
streamMessageCallbackRef.current([uid, data]);
|
|
342
|
+
}
|
|
343
|
+
}, []);
|
|
340
344
|
|
|
341
345
|
// Register once for the lifetime of the active call. Keeping collection in
|
|
342
346
|
// the provider makes it independent of whether caption/transcript UI is open.
|
|
@@ -344,7 +348,7 @@ const CaptionProvider: React.FC<CaptionProviderProps> = ({
|
|
|
344
348
|
if (
|
|
345
349
|
!$config.ENABLE_STT ||
|
|
346
350
|
!callActive ||
|
|
347
|
-
|
|
351
|
+
transcriptListenerRegistrationRef.current
|
|
348
352
|
) {
|
|
349
353
|
return;
|
|
350
354
|
}
|
|
@@ -356,10 +360,11 @@ const CaptionProvider: React.FC<CaptionProviderProps> = ({
|
|
|
356
360
|
{stage: 'listener_registration', outcome: 'started'},
|
|
357
361
|
);
|
|
358
362
|
try {
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
+
transcriptListenerRegistrationRef.current =
|
|
364
|
+
registerTranscriptStreamListener(
|
|
365
|
+
RtcEngineUnsafe as unknown as TranscriptStreamEngine,
|
|
366
|
+
handleStreamMessageCallback,
|
|
367
|
+
);
|
|
363
368
|
setIsSTTListenerAdded(true);
|
|
364
369
|
logger.log(
|
|
365
370
|
LogSource.Internals,
|
|
@@ -378,10 +383,9 @@ const CaptionProvider: React.FC<CaptionProviderProps> = ({
|
|
|
378
383
|
error: error ?? null,
|
|
379
384
|
},
|
|
380
385
|
);
|
|
386
|
+
return;
|
|
381
387
|
}
|
|
382
|
-
}, [RtcEngineUnsafe, callActive, handleStreamMessageCallback]);
|
|
383
388
|
|
|
384
|
-
React.useEffect(() => {
|
|
385
389
|
return () => {
|
|
386
390
|
logger.log(
|
|
387
391
|
LogSource.Internals,
|
|
@@ -390,19 +394,27 @@ const CaptionProvider: React.FC<CaptionProviderProps> = ({
|
|
|
390
394
|
{
|
|
391
395
|
stage: 'listener_cleanup',
|
|
392
396
|
outcome: 'started',
|
|
393
|
-
|
|
397
|
+
listenerRegistered: !!transcriptListenerRegistrationRef.current,
|
|
394
398
|
},
|
|
395
399
|
);
|
|
396
|
-
|
|
397
|
-
|
|
400
|
+
if (transcriptListenerRegistrationRef.current) {
|
|
401
|
+
removeTranscriptStreamListener(
|
|
402
|
+
RtcEngineUnsafe as unknown as TranscriptStreamEngine,
|
|
403
|
+
handleStreamMessageCallback,
|
|
404
|
+
transcriptListenerRegistrationRef.current,
|
|
405
|
+
isWebInternal(),
|
|
406
|
+
);
|
|
407
|
+
}
|
|
408
|
+
transcriptListenerRegistrationRef.current = null;
|
|
409
|
+
setIsSTTListenerAdded(false);
|
|
398
410
|
logger.log(
|
|
399
411
|
LogSource.Internals,
|
|
400
412
|
'TRANSCRIPT',
|
|
401
|
-
`${TRANSCRIPT_JOURNEY} stream listener
|
|
413
|
+
`${TRANSCRIPT_JOURNEY} stream listener removed and local references cleared`,
|
|
402
414
|
{stage: 'listener_cleanup', outcome: 'completed'},
|
|
403
415
|
);
|
|
404
416
|
};
|
|
405
|
-
}, []);
|
|
417
|
+
}, [RtcEngineUnsafe, callActive, handleStreamMessageCallback]);
|
|
406
418
|
|
|
407
419
|
const flushPendingTranscript = React.useCallback(async () => {
|
|
408
420
|
await flushStreamMessageQueue();
|
|
@@ -435,12 +447,17 @@ const CaptionProvider: React.FC<CaptionProviderProps> = ({
|
|
|
435
447
|
const updateErrorLabel = useString(sttUpdateError)();
|
|
436
448
|
|
|
437
449
|
// --- Derived readiness flag for STT ---
|
|
450
|
+
const localUidReady = !!localUid;
|
|
451
|
+
const localBotUidReady = !!localBotUid;
|
|
452
|
+
const rtmJoined = !!hasUserJoinedRTM;
|
|
453
|
+
const activeCallReady = !!callActive;
|
|
454
|
+
const roomInfoReady = !!(roomId?.host || roomId?.attendee);
|
|
438
455
|
const sttDepsReady =
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
456
|
+
localUidReady &&
|
|
457
|
+
localBotUidReady &&
|
|
458
|
+
rtmJoined &&
|
|
459
|
+
activeCallReady &&
|
|
460
|
+
roomInfoReady;
|
|
444
461
|
|
|
445
462
|
const sttStartGuardRef = React.useRef(false);
|
|
446
463
|
const sttAutoStartGuardRef = React.useRef(false);
|
|
@@ -452,27 +469,42 @@ const CaptionProvider: React.FC<CaptionProviderProps> = ({
|
|
|
452
469
|
}, [sttDepsReady]);
|
|
453
470
|
|
|
454
471
|
React.useEffect(() => {
|
|
472
|
+
const missingDependencies = [
|
|
473
|
+
!localUidReady && 'localUid',
|
|
474
|
+
!localBotUidReady && 'localBotUid',
|
|
475
|
+
!rtmJoined && 'RTM',
|
|
476
|
+
!activeCallReady && 'activeCall',
|
|
477
|
+
!roomInfoReady && 'roomInfo',
|
|
478
|
+
!isSTTListenerAdded && 'streamListener',
|
|
479
|
+
].filter(Boolean);
|
|
480
|
+
const transcriptReady = sttDepsReady && isSTTListenerAdded;
|
|
481
|
+
|
|
455
482
|
logger.log(
|
|
456
483
|
LogSource.Internals,
|
|
457
484
|
'TRANSCRIPT',
|
|
458
|
-
`${TRANSCRIPT_JOURNEY} STT readiness
|
|
485
|
+
`${TRANSCRIPT_JOURNEY} STT readiness: ${
|
|
486
|
+
transcriptReady
|
|
487
|
+
? 'READY'
|
|
488
|
+
: `WAITING (missing: ${missingDependencies.join(', ')})`
|
|
489
|
+
}`,
|
|
459
490
|
{
|
|
460
491
|
stage: 'stt_readiness',
|
|
461
|
-
outcome:
|
|
462
|
-
localUidReady
|
|
463
|
-
localBotUidReady
|
|
464
|
-
rtmJoined
|
|
465
|
-
callActive:
|
|
466
|
-
roomInfoReady
|
|
467
|
-
listenerRegistered:
|
|
492
|
+
outcome: transcriptReady ? 'ready' : 'waiting',
|
|
493
|
+
localUidReady,
|
|
494
|
+
localBotUidReady,
|
|
495
|
+
rtmJoined,
|
|
496
|
+
callActive: activeCallReady,
|
|
497
|
+
roomInfoReady,
|
|
498
|
+
listenerRegistered: isSTTListenerAdded,
|
|
468
499
|
},
|
|
469
500
|
);
|
|
470
501
|
}, [
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
502
|
+
activeCallReady,
|
|
503
|
+
isSTTListenerAdded,
|
|
504
|
+
localBotUidReady,
|
|
505
|
+
localUidReady,
|
|
506
|
+
roomInfoReady,
|
|
507
|
+
rtmJoined,
|
|
476
508
|
sttDepsReady,
|
|
477
509
|
]);
|
|
478
510
|
|
|
@@ -593,21 +625,22 @@ const CaptionProvider: React.FC<CaptionProviderProps> = ({
|
|
|
593
625
|
try {
|
|
594
626
|
setIsLangChangeInProgress(true);
|
|
595
627
|
const result = await start(localBotUidRef.current, newConfig);
|
|
628
|
+
console.log('[STT] start result: ', result);
|
|
596
629
|
if (result.success) {
|
|
597
630
|
setIsSTTError(false);
|
|
598
631
|
logger.log(
|
|
599
632
|
LogSource.NetworkRest,
|
|
600
633
|
'stt',
|
|
601
|
-
|
|
602
|
-
result.data
|
|
634
|
+
'STT started successfully',
|
|
635
|
+
result.data,
|
|
603
636
|
);
|
|
604
637
|
} else {
|
|
605
638
|
setIsSTTError(true);
|
|
606
639
|
logger.error(
|
|
607
640
|
LogSource.NetworkRest,
|
|
608
641
|
'stt',
|
|
609
|
-
|
|
610
|
-
result.error
|
|
642
|
+
'Failed to start STT',
|
|
643
|
+
result.error,
|
|
611
644
|
);
|
|
612
645
|
Toast.show({
|
|
613
646
|
leadingIconName: 'alert',
|
|
@@ -624,12 +657,7 @@ const CaptionProvider: React.FC<CaptionProviderProps> = ({
|
|
|
624
657
|
} catch (error: any) {
|
|
625
658
|
setIsLangChangeInProgress(false);
|
|
626
659
|
setIsSTTError(true);
|
|
627
|
-
logger.error(
|
|
628
|
-
LogSource.NetworkRest,
|
|
629
|
-
'stt',
|
|
630
|
-
`${TRANSCRIPT_JOURNEY} STT start error`,
|
|
631
|
-
error ?? null,
|
|
632
|
-
);
|
|
660
|
+
logger.error(LogSource.NetworkRest, 'stt', 'STT start error', error);
|
|
633
661
|
// Show error toast: text1 = translated label, text2 = exception error
|
|
634
662
|
Toast.show({
|
|
635
663
|
leadingIconName: 'alert',
|
|
@@ -674,16 +702,16 @@ const CaptionProvider: React.FC<CaptionProviderProps> = ({
|
|
|
674
702
|
logger.log(
|
|
675
703
|
LogSource.NetworkRest,
|
|
676
704
|
'stt',
|
|
677
|
-
|
|
678
|
-
result.data
|
|
705
|
+
'STT updated successfully',
|
|
706
|
+
result.data,
|
|
679
707
|
);
|
|
680
708
|
} else {
|
|
681
709
|
setIsSTTError(true);
|
|
682
710
|
logger.error(
|
|
683
711
|
LogSource.NetworkRest,
|
|
684
712
|
'stt',
|
|
685
|
-
|
|
686
|
-
result.error
|
|
713
|
+
'Failed to update STT',
|
|
714
|
+
result.error,
|
|
687
715
|
);
|
|
688
716
|
// Show error toast: text1 = translated label, text2 = API error
|
|
689
717
|
Toast.show({
|
|
@@ -701,12 +729,7 @@ const CaptionProvider: React.FC<CaptionProviderProps> = ({
|
|
|
701
729
|
} catch (error: any) {
|
|
702
730
|
setIsLangChangeInProgress(false);
|
|
703
731
|
setIsSTTError(true);
|
|
704
|
-
logger.error(
|
|
705
|
-
LogSource.NetworkRest,
|
|
706
|
-
'stt',
|
|
707
|
-
`${TRANSCRIPT_JOURNEY} STT update error`,
|
|
708
|
-
error ?? null,
|
|
709
|
-
);
|
|
732
|
+
logger.error(LogSource.NetworkRest, 'stt', 'STT update error', error);
|
|
710
733
|
// Show error toast: text1 = translated label, text2 = exception error
|
|
711
734
|
Toast.show({
|
|
712
735
|
leadingIconName: 'alert',
|
|
@@ -725,20 +748,10 @@ const CaptionProvider: React.FC<CaptionProviderProps> = ({
|
|
|
725
748
|
};
|
|
726
749
|
|
|
727
750
|
const stopSTTBotSession = React.useCallback(async () => {
|
|
728
|
-
|
|
729
|
-
LogSource.Internals,
|
|
730
|
-
'TRANSCRIPT',
|
|
731
|
-
`${TRANSCRIPT_JOURNEY} STT stop requested`,
|
|
732
|
-
{stage: 'stt_stop', localBotUid: localBotUidRef.current ?? null},
|
|
733
|
-
);
|
|
751
|
+
console.log('[STT] stopSTTBotSession called');
|
|
734
752
|
|
|
735
753
|
if (!localBotUidRef.current) {
|
|
736
|
-
|
|
737
|
-
LogSource.Internals,
|
|
738
|
-
'TRANSCRIPT',
|
|
739
|
-
`${TRANSCRIPT_JOURNEY} STT stop skipped because bot UID is missing`,
|
|
740
|
-
{stage: 'stt_stop', outcome: 'skipped'},
|
|
741
|
-
);
|
|
754
|
+
console.warn('[STT] Missing botUid for stop');
|
|
742
755
|
return;
|
|
743
756
|
}
|
|
744
757
|
|
|
@@ -754,16 +767,16 @@ const CaptionProvider: React.FC<CaptionProviderProps> = ({
|
|
|
754
767
|
logger.log(
|
|
755
768
|
LogSource.NetworkRest,
|
|
756
769
|
'stt',
|
|
757
|
-
|
|
758
|
-
result.data
|
|
770
|
+
'STT stopped successfully',
|
|
771
|
+
result.data,
|
|
759
772
|
);
|
|
760
773
|
} else {
|
|
761
774
|
setIsSTTError(true);
|
|
762
775
|
logger.error(
|
|
763
776
|
LogSource.NetworkRest,
|
|
764
777
|
'stt',
|
|
765
|
-
|
|
766
|
-
result.error
|
|
778
|
+
'Failed to stop STT',
|
|
779
|
+
result.error,
|
|
767
780
|
);
|
|
768
781
|
}
|
|
769
782
|
} catch (error) {
|
|
@@ -771,8 +784,8 @@ const CaptionProvider: React.FC<CaptionProviderProps> = ({
|
|
|
771
784
|
logger.error(
|
|
772
785
|
LogSource.NetworkRest,
|
|
773
786
|
'stt',
|
|
774
|
-
|
|
775
|
-
error
|
|
787
|
+
'Error in stopSTTBotSession',
|
|
788
|
+
error,
|
|
776
789
|
);
|
|
777
790
|
}
|
|
778
791
|
}, [stop]);
|
|
@@ -843,29 +856,12 @@ const CaptionProvider: React.FC<CaptionProviderProps> = ({
|
|
|
843
856
|
// Queue
|
|
844
857
|
enqueueSttEvent(updatedState, true, targetChange);
|
|
845
858
|
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
`${TRANSCRIPT_JOURNEY} local spoken-language state queued`,
|
|
850
|
-
{
|
|
851
|
-
stage: 'global_state_queue',
|
|
852
|
-
outcome: 'queued',
|
|
853
|
-
spokenLanguage: updatedState.globalSpokenLanguage ?? null,
|
|
854
|
-
translationTargetCount:
|
|
855
|
-
updatedState.globalTranslationTargets.length,
|
|
856
|
-
},
|
|
859
|
+
console.log(
|
|
860
|
+
'[STT_GLOBAL] confirmSpokenLanguageChange sent STT_GLOBAL_STATE: ',
|
|
861
|
+
updatedState,
|
|
857
862
|
);
|
|
858
863
|
} catch (error) {
|
|
859
|
-
|
|
860
|
-
LogSource.Internals,
|
|
861
|
-
'TRANSCRIPT',
|
|
862
|
-
`${TRANSCRIPT_JOURNEY} local spoken-language state failed`,
|
|
863
|
-
{
|
|
864
|
-
stage: 'global_state_queue',
|
|
865
|
-
outcome: 'failure',
|
|
866
|
-
error: error ?? null,
|
|
867
|
-
},
|
|
868
|
-
);
|
|
864
|
+
console.log('[STT_GLOBAL] confirmSpokenLanguageChange error: ', error);
|
|
869
865
|
}
|
|
870
866
|
},
|
|
871
867
|
[localUid], // only real dependency
|
|
@@ -920,24 +916,15 @@ const CaptionProvider: React.FC<CaptionProviderProps> = ({
|
|
|
920
916
|
// Queues all local + remote stt events
|
|
921
917
|
const enqueueSttEvent = React.useCallback(
|
|
922
918
|
(state: GlobalSttState, isLocal: boolean, targetChange?: TargetChange) => {
|
|
919
|
+
console.log(
|
|
920
|
+
'[STT_GLOBAL] inside enqueueSttEvent - sttDepsReadyRef flag',
|
|
921
|
+
sttDepsReadyRef.current,
|
|
922
|
+
);
|
|
923
923
|
sttEventQueueRef.current.push({
|
|
924
924
|
state,
|
|
925
925
|
isLocal,
|
|
926
926
|
targetChange,
|
|
927
927
|
});
|
|
928
|
-
logger.log(
|
|
929
|
-
LogSource.Internals,
|
|
930
|
-
'TRANSCRIPT',
|
|
931
|
-
`${TRANSCRIPT_JOURNEY} STT global state queued`,
|
|
932
|
-
{
|
|
933
|
-
stage: 'global_state_queue',
|
|
934
|
-
outcome: 'queued',
|
|
935
|
-
stateOrigin: isLocal ? 'local' : 'remote',
|
|
936
|
-
sttEnabled: state.globalSttEnabled,
|
|
937
|
-
sttDepsReady: sttDepsReadyRef.current,
|
|
938
|
-
queueSize: sttEventQueueRef.current.length,
|
|
939
|
-
},
|
|
940
|
-
);
|
|
941
928
|
if (sttDepsReadyRef.current) {
|
|
942
929
|
processSttEventQueue();
|
|
943
930
|
}
|
|
@@ -964,12 +951,7 @@ const CaptionProvider: React.FC<CaptionProviderProps> = ({
|
|
|
964
951
|
!globalSttStateRef.current.globalSttEnabled &&
|
|
965
952
|
sttEventQueueRef.current.length === 0
|
|
966
953
|
) {
|
|
967
|
-
|
|
968
|
-
LogSource.Internals,
|
|
969
|
-
'TRANSCRIPT',
|
|
970
|
-
`${TRANSCRIPT_JOURNEY} STT auto-start state injected`,
|
|
971
|
-
{stage: 'global_state_queue', outcome: 'queued'},
|
|
972
|
-
);
|
|
954
|
+
console.log('[STT] AUTO_START injecting auto start state');
|
|
973
955
|
|
|
974
956
|
sttAutoStartGuardRef.current = true;
|
|
975
957
|
|
|
@@ -996,12 +978,7 @@ const CaptionProvider: React.FC<CaptionProviderProps> = ({
|
|
|
996
978
|
const {state: newState, isLocal, targetChange} = item;
|
|
997
979
|
const prevState = globalSttStateRef.current;
|
|
998
980
|
if (isSameState(prevState, newState)) {
|
|
999
|
-
|
|
1000
|
-
LogSource.Internals,
|
|
1001
|
-
'TRANSCRIPT',
|
|
1002
|
-
`${TRANSCRIPT_JOURNEY} duplicate STT global state skipped`,
|
|
1003
|
-
{stage: 'global_state_queue', outcome: 'skipped'},
|
|
1004
|
-
);
|
|
981
|
+
console.log('[STT] Skipped duplicate STT_GLOBAL_STATE');
|
|
1005
982
|
continue; // no call to processGlobalSttSingleEvent
|
|
1006
983
|
}
|
|
1007
984
|
const ok = await processGlobalSttSingleEvent(
|
|
@@ -1011,22 +988,16 @@ const CaptionProvider: React.FC<CaptionProviderProps> = ({
|
|
|
1011
988
|
);
|
|
1012
989
|
if (!ok) {
|
|
1013
990
|
if (isLocal) {
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
'TRANSCRIPT',
|
|
1017
|
-
`${TRANSCRIPT_JOURNEY} local global state update skipped because API failed`,
|
|
1018
|
-
{stage: 'global_state_apply', outcome: 'skipped'},
|
|
991
|
+
console.warn(
|
|
992
|
+
'[STT] Skipping local global state update because API failed.',
|
|
1019
993
|
);
|
|
1020
994
|
continue;
|
|
1021
995
|
}
|
|
1022
996
|
// A received RTM event is authoritative for the meeting-level state.
|
|
1023
997
|
// Failure to provision this participant's bot must not make the UI
|
|
1024
998
|
// report that meeting STT is disabled while captions are arriving.
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
'TRANSCRIPT',
|
|
1028
|
-
`${TRANSCRIPT_JOURNEY} remote global state applied after local STT API failure`,
|
|
1029
|
-
{stage: 'global_state_apply', outcome: 'applied_with_api_failure'},
|
|
999
|
+
console.warn(
|
|
1000
|
+
'[STT] Applying remote global state after local STT API failure.',
|
|
1030
1001
|
);
|
|
1031
1002
|
}
|
|
1032
1003
|
// update global state AFTER processing
|
|
@@ -1051,24 +1022,10 @@ const CaptionProvider: React.FC<CaptionProviderProps> = ({
|
|
|
1051
1022
|
const isStopOperation = wasEnabledBefore && !isEnabledNow;
|
|
1052
1023
|
try {
|
|
1053
1024
|
if (isStartOperation) {
|
|
1054
|
-
|
|
1055
|
-
LogSource.Internals,
|
|
1056
|
-
'TRANSCRIPT',
|
|
1057
|
-
`${TRANSCRIPT_JOURNEY} STT global state selected start operation`,
|
|
1058
|
-
{
|
|
1059
|
-
stage: 'global_state_operation',
|
|
1060
|
-
outcome: 'started',
|
|
1061
|
-
stateOrigin: isLocal ? 'local' : 'remote',
|
|
1062
|
-
},
|
|
1063
|
-
);
|
|
1025
|
+
console.log('[STT] Remote global STT -> starting session', newState);
|
|
1064
1026
|
// Start guard starts
|
|
1065
1027
|
if (sttStartGuardRef.current) {
|
|
1066
|
-
|
|
1067
|
-
LogSource.Internals,
|
|
1068
|
-
'TRANSCRIPT',
|
|
1069
|
-
`${TRANSCRIPT_JOURNEY} STT start skipped by start guard`,
|
|
1070
|
-
{stage: 'global_state_operation', outcome: 'skipped'},
|
|
1071
|
-
);
|
|
1028
|
+
console.log('[STT] Start skipped (already started)');
|
|
1072
1029
|
return;
|
|
1073
1030
|
}
|
|
1074
1031
|
sttStartGuardRef.current = true;
|
|
@@ -1139,16 +1096,7 @@ const CaptionProvider: React.FC<CaptionProviderProps> = ({
|
|
|
1139
1096
|
}
|
|
1140
1097
|
return true;
|
|
1141
1098
|
} else if (isUpdateOperation) {
|
|
1142
|
-
|
|
1143
|
-
LogSource.Internals,
|
|
1144
|
-
'TRANSCRIPT',
|
|
1145
|
-
`${TRANSCRIPT_JOURNEY} STT global state selected update operation`,
|
|
1146
|
-
{
|
|
1147
|
-
stage: 'global_state_operation',
|
|
1148
|
-
outcome: 'started',
|
|
1149
|
-
stateOrigin: isLocal ? 'local' : 'remote',
|
|
1150
|
-
},
|
|
1151
|
-
);
|
|
1099
|
+
console.log('[STT] Global STT -> updating session', newState);
|
|
1152
1100
|
const result = await updateSTTBotSession(
|
|
1153
1101
|
{
|
|
1154
1102
|
source: [newState.globalSpokenLanguage],
|
|
@@ -1212,16 +1160,7 @@ const CaptionProvider: React.FC<CaptionProviderProps> = ({
|
|
|
1212
1160
|
}
|
|
1213
1161
|
return true;
|
|
1214
1162
|
} else if (isStopOperation) {
|
|
1215
|
-
|
|
1216
|
-
LogSource.Internals,
|
|
1217
|
-
'TRANSCRIPT',
|
|
1218
|
-
`${TRANSCRIPT_JOURNEY} STT global state selected stop operation`,
|
|
1219
|
-
{
|
|
1220
|
-
stage: 'global_state_operation',
|
|
1221
|
-
outcome: 'started',
|
|
1222
|
-
stateOrigin: isLocal ? 'local' : 'remote',
|
|
1223
|
-
},
|
|
1224
|
-
);
|
|
1163
|
+
console.log('[STT] Global STT -> stopping session', newState);
|
|
1225
1164
|
await stopSTTBotSession();
|
|
1226
1165
|
sttStartGuardRef.current = false;
|
|
1227
1166
|
return true;
|
|
@@ -1234,8 +1173,8 @@ const CaptionProvider: React.FC<CaptionProviderProps> = ({
|
|
|
1234
1173
|
logger.error(
|
|
1235
1174
|
LogSource.Internals,
|
|
1236
1175
|
'STT',
|
|
1237
|
-
|
|
1238
|
-
error
|
|
1176
|
+
'Error handling STT_GLOBAL_STATE event',
|
|
1177
|
+
error,
|
|
1239
1178
|
);
|
|
1240
1179
|
return false;
|
|
1241
1180
|
}
|
|
@@ -1247,16 +1186,7 @@ const CaptionProvider: React.FC<CaptionProviderProps> = ({
|
|
|
1247
1186
|
React.useEffect(() => {
|
|
1248
1187
|
const handleGlobalSTTChange = async (evt: any) => {
|
|
1249
1188
|
const {payload} = evt || {};
|
|
1250
|
-
|
|
1251
|
-
LogSource.Internals,
|
|
1252
|
-
'TRANSCRIPT',
|
|
1253
|
-
`${TRANSCRIPT_JOURNEY} STT_GLOBAL_STATE event received`,
|
|
1254
|
-
{
|
|
1255
|
-
stage: 'global_state_event',
|
|
1256
|
-
outcome: 'received',
|
|
1257
|
-
payloadPresent: typeof payload === 'string' && payload.length > 0,
|
|
1258
|
-
},
|
|
1259
|
-
);
|
|
1189
|
+
console.log('[STT] STT_GLOBAL_STATE event received: ', evt);
|
|
1260
1190
|
let newState: GlobalSttState;
|
|
1261
1191
|
try {
|
|
1262
1192
|
newState = JSON.parse(payload);
|
|
@@ -1264,8 +1194,8 @@ const CaptionProvider: React.FC<CaptionProviderProps> = ({
|
|
|
1264
1194
|
logger.error(
|
|
1265
1195
|
LogSource.Internals,
|
|
1266
1196
|
'STT',
|
|
1267
|
-
|
|
1268
|
-
error
|
|
1197
|
+
'Failed to parse STT_GLOBAL_STATE event payload',
|
|
1198
|
+
error,
|
|
1269
1199
|
);
|
|
1270
1200
|
return;
|
|
1271
1201
|
}
|
|
@@ -7,7 +7,6 @@ import {logger, LogSource} from '../../logger/AppBuilderLogger';
|
|
|
7
7
|
import getUniqueID from '../../utils/getUniqueID';
|
|
8
8
|
import {buildSTTRequestBody, type STTMethod} from './sttRequestBody';
|
|
9
9
|
import {ensureSTTSessionId} from './sttSessionId';
|
|
10
|
-
import {TRANSCRIPT_JOURNEY} from './transcriptJourney';
|
|
11
10
|
|
|
12
11
|
export interface STTAPIResponse {
|
|
13
12
|
success: boolean;
|
|
@@ -100,12 +99,12 @@ const useSTTAPI = (): IuseSTTAPI => {
|
|
|
100
99
|
});
|
|
101
100
|
|
|
102
101
|
console.log(
|
|
103
|
-
|
|
102
|
+
`[STT_BOT_SUBSCRIPTION] ${method.toUpperCase()} - Bot UID: ${botUid} will subscribe to User UID: ${ownerUid}`,
|
|
104
103
|
{
|
|
105
104
|
method,
|
|
106
105
|
botUid,
|
|
107
106
|
ownerUid,
|
|
108
|
-
translationConfig
|
|
107
|
+
translationConfig,
|
|
109
108
|
},
|
|
110
109
|
);
|
|
111
110
|
const response = await fetch(`${STT_API_URL}/${method}`, {
|
|
@@ -147,10 +146,10 @@ const useSTTAPI = (): IuseSTTAPI => {
|
|
|
147
146
|
logger.error(
|
|
148
147
|
LogSource.NetworkRest,
|
|
149
148
|
'stt',
|
|
150
|
-
|
|
151
|
-
errorPayload
|
|
149
|
+
`STT API Failure - Called ${method}`,
|
|
150
|
+
errorPayload,
|
|
152
151
|
{
|
|
153
|
-
responseData: res
|
|
152
|
+
responseData: res,
|
|
154
153
|
httpStatus,
|
|
155
154
|
requestId,
|
|
156
155
|
startReqTs,
|
|
@@ -173,9 +172,9 @@ const useSTTAPI = (): IuseSTTAPI => {
|
|
|
173
172
|
logger.log(
|
|
174
173
|
LogSource.NetworkRest,
|
|
175
174
|
'stt',
|
|
176
|
-
|
|
175
|
+
`STT API Success - Called ${method}`,
|
|
177
176
|
{
|
|
178
|
-
responseData: res
|
|
177
|
+
responseData: res,
|
|
179
178
|
httpStatus,
|
|
180
179
|
requestId,
|
|
181
180
|
startReqTs,
|
|
@@ -195,8 +194,8 @@ const useSTTAPI = (): IuseSTTAPI => {
|
|
|
195
194
|
logger.error(
|
|
196
195
|
LogSource.NetworkRest,
|
|
197
196
|
'stt',
|
|
198
|
-
|
|
199
|
-
error
|
|
197
|
+
`STT API Failure - Called ${method}`,
|
|
198
|
+
error,
|
|
200
199
|
{
|
|
201
200
|
requestId,
|
|
202
201
|
startReqTs,
|
|
@@ -236,14 +235,14 @@ const useSTTAPI = (): IuseSTTAPI => {
|
|
|
236
235
|
logger.log(
|
|
237
236
|
LogSource.NetworkRest,
|
|
238
237
|
'stt',
|
|
239
|
-
|
|
238
|
+
'Retrying STT start after transient failure',
|
|
240
239
|
{
|
|
241
240
|
attempt,
|
|
242
241
|
maxAttempts: STT_START_MAX_ATTEMPTS,
|
|
243
242
|
retryDelayMs,
|
|
244
243
|
botUid,
|
|
245
|
-
httpStatus: result.httpStatus
|
|
246
|
-
errorCode: result.error?.code
|
|
244
|
+
httpStatus: result.httpStatus,
|
|
245
|
+
errorCode: result.error?.code,
|
|
247
246
|
},
|
|
248
247
|
);
|
|
249
248
|
await wait(retryDelayMs);
|
|
@@ -3,8 +3,6 @@ import protoRoot from './proto/ptoto';
|
|
|
3
3
|
import PQueue from 'p-queue';
|
|
4
4
|
import type {CaptionObj, TranscriptItem} from './useCaption';
|
|
5
5
|
import type {LanguageType} from './utils';
|
|
6
|
-
import {logger, LogSource} from '../../logger/AppBuilderLogger';
|
|
7
|
-
import {TRANSCRIPT_JOURNEY} from './transcriptJourney';
|
|
8
6
|
|
|
9
7
|
type StreamMessageCallback = (args: [number, Uint8Array]) => void;
|
|
10
8
|
type FinalListType = {
|
|
@@ -44,29 +42,8 @@ const useStreamMessageUtils = ({
|
|
|
44
42
|
const finalTranscriptListRef = React.useRef<FinalListType>({});
|
|
45
43
|
const finalTranslationListRef = React.useRef<FinalTranslationListType>({});
|
|
46
44
|
const queue = React.useMemo(() => new PQueue({concurrency: 1}), []);
|
|
47
|
-
const messagesReceivedRef = React.useRef(0);
|
|
48
|
-
const messagesProcessedRef = React.useRef(0);
|
|
49
|
-
const finalizedSegmentsRef = React.useRef(0);
|
|
50
|
-
const speakersWithFinalizedSegmentsRef = React.useRef(new Set<string>());
|
|
51
45
|
|
|
52
46
|
const streamMessageCallback: StreamMessageCallback = args => {
|
|
53
|
-
const [receivedBotUid, receivedPayload] = args;
|
|
54
|
-
const messageNumber = ++messagesReceivedRef.current;
|
|
55
|
-
if (messageNumber === 1 || messageNumber % 50 === 0) {
|
|
56
|
-
logger.log(
|
|
57
|
-
LogSource.Internals,
|
|
58
|
-
'TRANSCRIPT',
|
|
59
|
-
`${TRANSCRIPT_JOURNEY} stream message received`,
|
|
60
|
-
{
|
|
61
|
-
stage: 'stream_message_received',
|
|
62
|
-
outcome: 'success',
|
|
63
|
-
botUid: receivedBotUid ?? null,
|
|
64
|
-
payloadByteLength: receivedPayload?.byteLength || 0,
|
|
65
|
-
messagesReceived: messageNumber,
|
|
66
|
-
messagesProcessed: messagesProcessedRef.current,
|
|
67
|
-
},
|
|
68
|
-
);
|
|
69
|
-
}
|
|
70
47
|
const queueCallback = (args1: [number, Uint8Array]) => {
|
|
71
48
|
const finalList = finalListRef.current;
|
|
72
49
|
const finalTranscriptList = finalTranscriptListRef.current;
|
|
@@ -244,29 +221,11 @@ const useStreamMessageUtils = ({
|
|
|
244
221
|
finalList[textstream.uid].push(finalText);
|
|
245
222
|
finalTranscriptList[textstream.uid].push(finalText);
|
|
246
223
|
currentFinalText = finalText;
|
|
247
|
-
|
|
248
|
-
const speakerKey = String(speakerUid ?? 'unknown');
|
|
249
|
-
const isFirstFinalizedSegmentForSpeaker =
|
|
250
|
-
!speakersWithFinalizedSegmentsRef.current.has(speakerKey);
|
|
251
|
-
finalizedSegmentsRef.current += 1;
|
|
224
|
+
// log info to show measure the duration of passes in which a sentence gets finalized
|
|
252
225
|
const duration = performance.now() - captionStartTimeRef.current;
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
LogSource.Internals,
|
|
257
|
-
'TRANSCRIPT',
|
|
258
|
-
`${TRANSCRIPT_JOURNEY} first transcript segment finalized for speaker`,
|
|
259
|
-
{
|
|
260
|
-
stage: 'segment_finalized',
|
|
261
|
-
outcome: 'success',
|
|
262
|
-
botUid: botUid ?? null,
|
|
263
|
-
speakerUid,
|
|
264
|
-
finalCharacterCount: currentFinalText.length,
|
|
265
|
-
finalizeDurationMs: duration,
|
|
266
|
-
finalizedSegments: finalizedSegmentsRef.current,
|
|
267
|
-
},
|
|
268
|
-
);
|
|
269
|
-
}
|
|
226
|
+
console.log(
|
|
227
|
+
`stt-Time taken to finalize caption ${currentFinalText}: ${duration}ms`,
|
|
228
|
+
);
|
|
270
229
|
captionStartTimeRef.current = 0; // Reset start time
|
|
271
230
|
}
|
|
272
231
|
|
|
@@ -405,74 +364,14 @@ const useStreamMessageUtils = ({
|
|
|
405
364
|
};
|
|
406
365
|
void queue
|
|
407
366
|
.add(() => queueCallback(args))
|
|
408
|
-
.then(() =>
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
LogSource.Internals,
|
|
413
|
-
'TRANSCRIPT',
|
|
414
|
-
`${TRANSCRIPT_JOURNEY} stream message processed`,
|
|
415
|
-
{
|
|
416
|
-
stage: 'stream_message_processed',
|
|
417
|
-
outcome: 'success',
|
|
418
|
-
botUid: receivedBotUid ?? null,
|
|
419
|
-
messagesReceived: messagesReceivedRef.current,
|
|
420
|
-
messagesProcessed: processedCount,
|
|
421
|
-
queueSize: queue.size,
|
|
422
|
-
},
|
|
423
|
-
);
|
|
424
|
-
}
|
|
425
|
-
})
|
|
426
|
-
.catch(error => {
|
|
427
|
-
logger.error(
|
|
428
|
-
LogSource.Internals,
|
|
429
|
-
'TRANSCRIPT',
|
|
430
|
-
`${TRANSCRIPT_JOURNEY} failed to process stream message`,
|
|
431
|
-
{
|
|
432
|
-
stage: 'stream_message_processing',
|
|
433
|
-
outcome: 'failure',
|
|
434
|
-
botUid: receivedBotUid ?? null,
|
|
435
|
-
messageNumber,
|
|
436
|
-
messagesReceived: messagesReceivedRef.current,
|
|
437
|
-
messagesProcessed: messagesProcessedRef.current,
|
|
438
|
-
error: error ?? null,
|
|
439
|
-
},
|
|
440
|
-
);
|
|
441
|
-
});
|
|
367
|
+
.then(() => console.log('stt- using pq queue'))
|
|
368
|
+
.catch(error =>
|
|
369
|
+
console.error('Failed to process STT stream message', error),
|
|
370
|
+
);
|
|
442
371
|
};
|
|
443
372
|
|
|
444
373
|
const flushStreamMessageQueue = React.useCallback(async () => {
|
|
445
|
-
logger.log(
|
|
446
|
-
LogSource.Internals,
|
|
447
|
-
'TRANSCRIPT',
|
|
448
|
-
`${TRANSCRIPT_JOURNEY} stream queue flush requested`,
|
|
449
|
-
{
|
|
450
|
-
stage: 'stream_queue_flush',
|
|
451
|
-
outcome: 'started',
|
|
452
|
-
messagesReceived: messagesReceivedRef.current,
|
|
453
|
-
messagesProcessed: messagesProcessedRef.current,
|
|
454
|
-
finalizedSegments: finalizedSegmentsRef.current,
|
|
455
|
-
speakersWithFinalizedSegments:
|
|
456
|
-
speakersWithFinalizedSegmentsRef.current.size,
|
|
457
|
-
queueSize: queue.size,
|
|
458
|
-
},
|
|
459
|
-
);
|
|
460
374
|
await queue.onIdle();
|
|
461
|
-
logger.log(
|
|
462
|
-
LogSource.Internals,
|
|
463
|
-
'TRANSCRIPT',
|
|
464
|
-
`${TRANSCRIPT_JOURNEY} stream queue flush completed`,
|
|
465
|
-
{
|
|
466
|
-
stage: 'stream_queue_flush',
|
|
467
|
-
outcome: 'success',
|
|
468
|
-
messagesReceived: messagesReceivedRef.current,
|
|
469
|
-
messagesProcessed: messagesProcessedRef.current,
|
|
470
|
-
finalizedSegments: finalizedSegmentsRef.current,
|
|
471
|
-
speakersWithFinalizedSegments:
|
|
472
|
-
speakersWithFinalizedSegmentsRef.current.size,
|
|
473
|
-
queueSize: queue.size,
|
|
474
|
-
},
|
|
475
|
-
);
|
|
476
375
|
}, [queue]);
|
|
477
376
|
|
|
478
377
|
return {
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
CustomizationLogType,
|
|
3
|
-
LogSource,
|
|
4
|
-
logger,
|
|
5
|
-
} from '../src/logger/AppBuilderLogger';
|
|
6
|
-
|
|
7
|
-
export type CustomizationLogLevel = 'debug' | 'info' | 'warn' | 'error';
|
|
8
|
-
export type CustomizationLogData = Record<string, unknown>;
|
|
9
|
-
export type CustomizationLogEvent = {
|
|
10
|
-
type: CustomizationLogType;
|
|
11
|
-
event: string;
|
|
12
|
-
data?: CustomizationLogData;
|
|
13
|
-
level?: CustomizationLogLevel;
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Sends a customization event through the active App Builder log transport.
|
|
18
|
-
* The logger adds the current session, room, user, platform, and SDK context.
|
|
19
|
-
* Callers must redact credentials and other sensitive values before logging.
|
|
20
|
-
*/
|
|
21
|
-
export const logCustomizationEvent = ({
|
|
22
|
-
type,
|
|
23
|
-
event,
|
|
24
|
-
data,
|
|
25
|
-
level = 'info',
|
|
26
|
-
}: CustomizationLogEvent) => {
|
|
27
|
-
if (data) {
|
|
28
|
-
logger[level](LogSource.CustomizationAPI, type, event, data);
|
|
29
|
-
return;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
logger[level](LogSource.CustomizationAPI, type, event);
|
|
33
|
-
};
|