@trtc/calls-uikit-vue 4.4.2 → 4.4.5

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.
Files changed (57) hide show
  1. package/package.json +2 -2
  2. package/src/Components/TUICallKit.vue +1 -1
  3. package/src/Components/assets/aiAssistant/desktop/subtitleSettings.svg +4 -0
  4. package/src/Components/assets/aiAssistant/mobile/close-aiAssistant.svg +7 -0
  5. package/src/Components/assets/aiAssistant/mobile/open-aiAssistant.svg +7 -0
  6. package/src/Components/assets/aiAssistant/mobile/subtitleSettings.svg +3 -0
  7. package/src/Components/components/base/CustomSelect/CustomSelect.ts +45 -0
  8. package/src/Components/components/base/CustomSelect/CustomSelect.vue +199 -0
  9. package/src/Components/components/common/AIAssistant/AISubtitle.vue +155 -37
  10. package/src/Components/components/common/AIAssistant/components/AITranscriberSwitchH5.vue +35 -0
  11. package/src/Components/components/common/AIAssistant/components/AITranscriberSwitchPC.vue +89 -0
  12. package/src/Components/components/common/AIAssistant/components/SubtitleContent.vue +234 -0
  13. package/src/Components/components/common/AIAssistant/components/SubtitleSettingsH5.vue +534 -0
  14. package/src/Components/components/common/AIAssistant/components/SubtitleSettingsPC.vue +294 -0
  15. package/src/Components/components/common/TopBar/TopBar.vue +41 -15
  16. package/src/Components/hooks/index.ts +1 -0
  17. package/src/Components/hooks/useAIAssistant.ts +142 -0
  18. package/src/Components/hooks/useGetVolumeMap.ts +2 -2
  19. package/src/TUICallService/CallService/AIAssistant.ts +285 -39
  20. package/src/TUICallService/CallService/UIKitModal.ts +14 -6
  21. package/src/TUICallService/CallService/bellContext.ts +25 -2
  22. package/src/TUICallService/CallService/engineEventHandler.ts +6 -1
  23. package/src/TUICallService/CallService/index.ts +72 -39
  24. package/src/TUICallService/CallService/miniProgram.ts +0 -12
  25. package/src/TUICallService/TUIStore/callStore.ts +6 -1
  26. package/src/TUICallService/UIKitModal/UIKitModal.ts +117 -0
  27. package/src/TUICallService/UIKitModal/index.ts +2 -0
  28. package/src/TUICallService/UIKitModal/type.ts +15 -0
  29. package/src/TUICallService/const/index.ts +4 -0
  30. package/src/TUICallService/interface/ICallStore.ts +5 -0
  31. package/src/TUICallService/locales/en.ts +15 -0
  32. package/src/TUICallService/locales/ja_JP.ts +15 -0
  33. package/src/TUICallService/locales/zh-cn.ts +15 -0
  34. package/src/TUICallService/utils/common-utils.ts +1 -1
  35. package/src/index.ts +1 -1
  36. package/stats.html +1 -1
  37. package/tuicall-uikit-vue.es.js +4199 -3474
  38. package/tuicall-uikit-vue.umd.js +2 -2
  39. package/types/Components/components/base/CustomSelect/CustomSelect.d.ts +41 -0
  40. package/types/Components/hooks/index.d.ts +1 -0
  41. package/types/Components/hooks/useAIAssistant.d.ts +19 -0
  42. package/types/TUICallService/CallService/AIAssistant.d.ts +72 -15
  43. package/types/TUICallService/CallService/bellContext.d.ts +3 -0
  44. package/types/TUICallService/CallService/index.d.ts +4 -3
  45. package/types/TUICallService/CallService/miniProgram.d.ts +0 -1
  46. package/types/TUICallService/UIKitModal/UIKitModal.d.ts +4 -0
  47. package/types/TUICallService/UIKitModal/index.d.ts +2 -0
  48. package/types/TUICallService/UIKitModal/type.d.ts +13 -0
  49. package/types/TUICallService/interface/ICallStore.d.ts +4 -0
  50. package/types/TUICallService/locales/en.d.ts +14 -0
  51. package/types/TUICallService/locales/ja_JP.d.ts +14 -0
  52. package/types/TUICallService/locales/zh-cn.d.ts +14 -0
  53. package/types/tsconfig.tsbuildinfo +1 -1
  54. package/src/Components/components/common/AIAssistant/AIAssistant.ts +0 -130
  55. package/src/Components/components/common/AIAssistant/index.ts +0 -11
  56. package/types/Components/components/common/AIAssistant/AIAssistant.d.ts +0 -40
  57. package/types/Components/components/common/AIAssistant/index.d.ts +0 -4
@@ -0,0 +1,294 @@
1
+ <template>
2
+ <div v-if="visible" class="subtitle-settings-overlay" @click="handleOverlayClick">
3
+ <div class="subtitle-settings-modal" @click.stop>
4
+ <div class="modal-header">
5
+ <h3 class="modal-title">{{ t('ai-subtitle-settings') }}</h3>
6
+ <button class="close-btn" @click="closeModal">
7
+ <svg width="16" height="16" viewBox="0 0 16 16" fill="none">
8
+ <path d="M12 4L4 12M4 4L12 12" stroke="#666" stroke-width="2" stroke-linecap="round"/>
9
+ </svg>
10
+ </button>
11
+ </div>
12
+
13
+ <div class="modal-content">
14
+ <!-- Recognition Language -->
15
+ <div class="setting-item">
16
+ <label class="setting-label">{{ t('recognition-language') }}</label>
17
+ <CustomSelect
18
+ :value="recognitionLanguage"
19
+ @input="handleLanguageChange"
20
+ :options="languageOptions"
21
+ @change="handleLanguageChange"
22
+ />
23
+ </div>
24
+
25
+ <!-- Translation Language -->
26
+ <div class="setting-item">
27
+ <label class="setting-label">{{ t('translation-language') }}</label>
28
+ <CustomSelect
29
+ :value="translationLanguage"
30
+ @input="handleTranslationChange"
31
+ :options="translationOptions"
32
+ @change="handleTranslationChange"
33
+ />
34
+ </div>
35
+
36
+ <!-- Subtitle Display Settings -->
37
+ <div class="setting-item">
38
+ <label class="setting-label">{{ t('subtitle-display-settings') }}</label>
39
+ <CustomSelect
40
+ :value="subtitleDisplay"
41
+ @input="handleSubtitleDisplayChange"
42
+ :options="subtitleDisplayOptions"
43
+ @change="handleSubtitleDisplayChange"
44
+ />
45
+ </div>
46
+ </div>
47
+
48
+ <div class="modal-footer">
49
+ <button class="btn btn-cancel" @click="closeModal">{{ t('Cancel') }}</button>
50
+ <button class="btn btn-confirm" @click="confirmSettings">{{ t('save') }}</button>
51
+ </div>
52
+ </div>
53
+ </div>
54
+ </template>
55
+
56
+ <script lang="ts" setup>
57
+ import { ref, computed, watch } from '../../../../../adapter-vue';
58
+ import { TUICallKitAPI } from '../../../../../TUICallService/index';
59
+ import CustomSelect from '../../../base/CustomSelect/CustomSelect.vue';
60
+ import { useTranslate } from '../../../../hooks/useTranslate';
61
+
62
+ interface Props {
63
+ visible: boolean;
64
+ }
65
+
66
+ interface Emits {
67
+ (e: 'update:visible', value: boolean): void;
68
+ (e: 'confirm', settings: {
69
+ recognitionLanguage: string;
70
+ translationLanguage: string;
71
+ subtitleDisplay: string;
72
+ }): void;
73
+ }
74
+
75
+ const props = withDefaults(defineProps<Props>(), {
76
+ visible: false
77
+ });
78
+ const emit = defineEmits<Emits>();
79
+
80
+ // Use i18n translation
81
+ const t = useTranslate();
82
+
83
+ // Settings state
84
+ const recognitionLanguage = ref('zh');
85
+ const translationLanguage = ref('en');
86
+ const subtitleDisplay = ref('both');
87
+
88
+ // Saved settings to restore on cancel
89
+ const savedSettings = ref({
90
+ recognitionLanguage: 'zh',
91
+ translationLanguage: 'en',
92
+ subtitleDisplay: 'both'
93
+ });
94
+
95
+ // Language options for CustomSelect - supported recognition languages
96
+ // Use native language names for better UX (users can always recognize their own language)
97
+ const languageOptions = computed(() => [
98
+ { value: 'zh', label: '中文' },
99
+ { value: 'en', label: 'English' }
100
+ ]);
101
+
102
+ // Translation options for CustomSelect - translation target languages (base list)
103
+ // Use native language names for better UX (users can always recognize their own language)
104
+ const baseTranslationOptions = computed(() => [
105
+ { value: '', label: t.value('no-translation') },
106
+ { value: 'zh', label: 'Chinese (中文)' },
107
+ { value: 'en', label: 'English (英语)' },
108
+ { value: 'vi', label: 'Vietnamese (越南语)' },
109
+ { value: 'ja', label: 'Japanese (日语)' },
110
+ { value: 'ko', label: 'Korean (韩语)' },
111
+ { value: 'id', label: 'Indonesian (印尼语)' },
112
+ { value: 'th', label: 'Thai (泰语)' },
113
+ { value: 'pt', label: 'Portuguese (葡萄牙语)' },
114
+ { value: 'ar', label: 'Arabic (阿拉伯语)' },
115
+ { value: 'es', label: 'Spanish (西班牙语)' },
116
+ { value: 'fr', label: 'French (法语)' },
117
+ { value: 'ms', label: 'Malay (马来语)' },
118
+ { value: 'de', label: 'German (德语)' },
119
+ { value: 'it', label: 'Italian (意大利语)' },
120
+ { value: 'ru', label: 'Russian (俄语)' }
121
+ ]);
122
+
123
+ // Computed property to filter translation options based on selected recognition language
124
+ const translationOptions = computed(() => {
125
+ return baseTranslationOptions.value.filter(option =>
126
+ option.value === '' || option.value !== recognitionLanguage.value
127
+ );
128
+ });
129
+
130
+ // Subtitle display options for CustomSelect
131
+ const subtitleDisplayOptions = computed(() => [
132
+ { value: 'both', label: t.value('show-bilingual') },
133
+ { value: 'original', label: t.value('show-original-only') },
134
+ ]);
135
+
136
+ const handleLanguageChange = (value: string | number) => {
137
+ recognitionLanguage.value = value as string;
138
+ };
139
+
140
+ const handleTranslationChange = (value: string | number) => {
141
+ translationLanguage.value = value as string;
142
+ };
143
+
144
+ const handleSubtitleDisplayChange = (value: string | number) => {
145
+ subtitleDisplay.value = value as string;
146
+ };
147
+
148
+ const closeModal = () => {
149
+ // Restore saved settings when closing without confirming
150
+ recognitionLanguage.value = savedSettings.value.recognitionLanguage;
151
+ translationLanguage.value = savedSettings.value.translationLanguage;
152
+ subtitleDisplay.value = savedSettings.value.subtitleDisplay;
153
+
154
+ emit('update:visible', false);
155
+ };
156
+
157
+ const handleOverlayClick = () => {
158
+ closeModal();
159
+ };
160
+
161
+ const confirmSettings = async () => {
162
+ try {
163
+ // Call updateRealTimeTranscriber when settings are confirmed
164
+ const translationLanguages = translationLanguage.value ? [translationLanguage.value] : [];
165
+
166
+ await TUICallKitAPI._aiAssistant.updateRealTimeTranscriber({
167
+ sourceLanguage: recognitionLanguage.value,
168
+ translationLanguages: translationLanguages,
169
+ });
170
+
171
+ // Save the confirmed settings
172
+ savedSettings.value = {
173
+ recognitionLanguage: recognitionLanguage.value,
174
+ translationLanguage: translationLanguage.value,
175
+ subtitleDisplay: subtitleDisplay.value
176
+ };
177
+
178
+ emit('confirm', {
179
+ recognitionLanguage: recognitionLanguage.value,
180
+ translationLanguage: translationLanguage.value,
181
+ subtitleDisplay: subtitleDisplay.value,
182
+ });
183
+ } catch (error) {
184
+ console.error('Failed to update AI transcriber settings:', error);
185
+ }
186
+
187
+ closeModal();
188
+ };
189
+
190
+ // Watch for recognition language changes and reset translation language if it conflicts
191
+ watch(recognitionLanguage, (newRecognitionLang) => {
192
+ // If the current translation language is the same as the new recognition language, reset it
193
+ if (translationLanguage.value === newRecognitionLang) {
194
+ translationLanguage.value = '';
195
+ }
196
+ });
197
+ </script>
198
+
199
+ <style lang="scss" scoped>
200
+ .subtitle-settings-overlay {
201
+ position: absolute;
202
+ top: 50%;
203
+ left: 50%;
204
+ display: flex;
205
+ align-items: center;
206
+ justify-content: center;
207
+ z-index: 1000;
208
+ font-family: PingFang SC;
209
+ box-shadow: 0px 2px 6px 0px var(--Black-8);
210
+ }
211
+
212
+ .subtitle-settings-modal {
213
+ background: white;
214
+ border-radius: 12px;
215
+ width: 480px;
216
+ overflow: hidden;
217
+ }
218
+
219
+ .modal-header {
220
+ display: flex;
221
+ align-items: center;
222
+ justify-content: space-between;
223
+ padding: 24px 24px 10px 24px;
224
+ }
225
+
226
+ .modal-title {
227
+ font-size: 16px;
228
+ font-weight: 600;
229
+ color: #000000E5;
230
+ }
231
+
232
+ .close-btn {
233
+ background: none;
234
+ border: none;
235
+ cursor: pointer;
236
+ padding: 4px;
237
+ border-radius: 4px;
238
+ transition: background-color 0.2s;
239
+
240
+ &:hover {
241
+ background-color: #f5f5f5;
242
+ }
243
+ }
244
+
245
+ .modal-content {
246
+ padding: 24px;
247
+ }
248
+
249
+ .setting-item {
250
+ margin-bottom: 24px;
251
+
252
+ &:last-child {
253
+ margin-bottom: 0;
254
+ }
255
+ }
256
+
257
+ .setting-label {
258
+ display: block;
259
+ font-size: 14px;
260
+ font-weight: 400;
261
+ color: #4F586B;
262
+ margin-bottom: 8px;
263
+ }
264
+
265
+ .modal-footer {
266
+ display: flex;
267
+ justify-content: flex-end;
268
+ gap: 20px;
269
+ padding: 16px 24px 24px;
270
+ }
271
+
272
+ .btn {
273
+ width: 72px;
274
+ height: 32px;
275
+ border-radius: 6px;
276
+ font-size: 14px;
277
+ font-weight: 500;
278
+ cursor: pointer;
279
+ border-radius: 26px;
280
+ transition: all 0.2s;
281
+ border: 1px solid transparent;
282
+
283
+ &.btn-cancel {
284
+ color: #1C66E5;
285
+ border-color: #1C66E5;
286
+ background-color: white;
287
+ }
288
+
289
+ &.btn-confirm {
290
+ background: #1C66E5;
291
+ color: white;
292
+ }
293
+ }
294
+ </style>
@@ -6,25 +6,23 @@
6
6
  <Timer v-if="showTimer" :call-duration="callDuration" />
7
7
  </Col>
8
8
  <Col :span="8" justify="end" align="center">
9
- <Row>
10
- <Col :span="18" />
11
- <Col :span="3" justify="center">
12
- <Minimize v-if="showMinimize" />
13
- </Col>
14
- <Col :span="3" justify="center">
15
- <FullScreen v-if="allowedFullScreen" />
16
- </Col>
17
- </Row>
9
+ <div class="topbar-right-controls">
10
+ <AITranscriberSwitch v-if="showAITranscriberSwitch" />
11
+ <Minimize v-if="showMinimize" />
12
+ <FullScreen v-if="allowedFullScreen" />
13
+ </div>
18
14
  </Col>
19
15
  </Row>
20
16
  <Row v-if="!isPC">
21
17
  <Col :span="8" align="center">
22
- <Row>
23
- <Col :span="8" justify="center">
18
+ <div class="top-bar-left-controls">
19
+ <div class="control-item">
24
20
  <Minimize v-if="!isPC && showMinimize" />
25
- </Col>
26
- <Col :span="16" />
27
- </Row>
21
+ </div>
22
+ <div class="control-item">
23
+ <AITranscriberSwitchH5 v-if="showAITranscriberSwitch" />
24
+ </div>
25
+ </div>
28
26
  </Col>
29
27
  <Col :span="8" justify="center" align="center">
30
28
  <Timer v-if="showTimer" :call-duration="callDuration" />
@@ -51,7 +49,7 @@ export default {
51
49
 
52
50
  <script setup lang="ts">
53
51
  import { toRefs, computed, ref, onMounted, onUnmounted } from '../../../../adapter-vue';
54
- import { useCallInfoContext, useCallDuration, useCustomUI } from '../../../hooks';
52
+ import { useCallInfoContext, useCallDuration, useCustomUI, useAIAssistant } from '../../../hooks';
55
53
  import { CallRole, CallStatus, FeatureButton, NAME, StoreName, TUIGlobal, TUIStore } from '../../../../TUICallService';
56
54
  import { TopBarProps } from './TopBar';
57
55
  import Row from '../../base/Layout/Row/Row.vue';
@@ -60,14 +58,21 @@ import Minimize from '../Button/Minimize.vue';
60
58
  import FullScreen from '../Button/FullScreen.vue';
61
59
  import InviteUser from '../Button/InviteUser.vue';
62
60
  import Timer from '../Timer/Timer.vue';
61
+ import AITranscriberSwitch from '../AIAssistant/components/AITranscriberSwitchPC.vue';
62
+ import AITranscriberSwitchH5 from '../AIAssistant/components/AITranscriberSwitchH5.vue';
63
63
 
64
64
  defineProps(TopBarProps);
65
65
  const isPC = TUIGlobal.isPC;
66
66
  const { callStatus, isGroupCall, callRole, allowedFullScreen } = toRefs(useCallInfoContext());
67
67
  const { callDuration } = useCallDuration();
68
+ const { isAITranscriberEnabled } = useAIAssistant();
68
69
  const customUIConfig = useCustomUI();
69
70
  const showTimer = computed(() => (callStatus.value === CallStatus.CONNECTED));
70
71
  const showMinimize = ref(TUIStore.getData(StoreName.CALL, NAME.ENABLE_FLOAT_WINDOW));
72
+ const showAITranscriberSwitch = computed(() => {
73
+ // Show AI transcriber switch when call is connected AND AI transcriber UI is enabled
74
+ return callStatus.value === CallStatus.CONNECTED && isAITranscriberEnabled.value;
75
+ });
71
76
  const showInviteUser = computed(() => {
72
77
  if (
73
78
  !isGroupCall.value
@@ -113,4 +118,25 @@ onUnmounted(() => {
113
118
  display: flex;
114
119
  align-items: center;
115
120
  }
121
+
122
+ .topbar-right-controls {
123
+ margin-right: 10px;
124
+ display: flex;
125
+ align-items: center;
126
+ gap: 16px; // Adjust this value to match design spacing
127
+ }
128
+
129
+ .top-bar-left-controls {
130
+ display: flex;
131
+ align-items: center;
132
+ justify-content: flex-start;
133
+ gap: 16px;
134
+ margin-left: 10px;
135
+ }
136
+
137
+ .control-item {
138
+ display: flex;
139
+ align-items: center;
140
+ justify-content: center;
141
+ }
116
142
  </style>
@@ -18,3 +18,4 @@ export * from './useCustomUI';
18
18
  export * from './useViewBackgroundConfig';
19
19
  export * from './useJoinGroupCall';
20
20
  export * from './useTranslate';
21
+ export * from './useAIAssistant';
@@ -0,0 +1,142 @@
1
+ /**
2
+ * AI Assistant Hook
3
+ * @description Vue 3 composable for AI Transcriber functionality
4
+ */
5
+ import { ref, onMounted, onUnmounted } from '../../adapter-vue';
6
+ import { TUIStore, StoreName, NAME } from '../../TUICallService/index';
7
+ import { TranscriberMessage } from '../../TUICallService/CallService/AIAssistant';
8
+
9
+ // Translation content interface
10
+ interface ITranslationContent {
11
+ language: string;
12
+ text: string;
13
+ }
14
+
15
+ // Converted message interface
16
+ interface ITranslationInfo {
17
+ roundId: string;
18
+ sender: string;
19
+ nick?: string;
20
+ text: string;
21
+ end: boolean;
22
+ translation: ITranslationContent[];
23
+ }
24
+
25
+ /**
26
+ * AI Assistant composable hook
27
+ * Provides reactive state management for AI transcription functionality
28
+ */
29
+ export function useAIAssistant() {
30
+ // AI Transcriber Status State
31
+ const isAITranscriberEnabled = ref(TUIStore.getData(StoreName.CALL, NAME.IS_AI_TRANSCRIBER_ENABLED));
32
+ const isAITranscriberRunning = ref(TUIStore.getData(StoreName.CALL, NAME.IS_AI_TRANSCRIBER_RUNNING));
33
+
34
+ // Converted message list
35
+ const subtitleInfoList = ref<ITranslationInfo[]>([]);
36
+
37
+ // Helper functions for message conversion
38
+ const parseTranslationTexts = (translationTexts: any): ITranslationContent[] => {
39
+ if (!translationTexts) {
40
+ return [];
41
+ }
42
+
43
+ // Handle Map type
44
+ if (translationTexts instanceof Map) {
45
+ return Array.from(translationTexts.entries()).map(([language, content]) => ({
46
+ language: String(language),
47
+ text: ensureStringContent(content)
48
+ }));
49
+ }
50
+
51
+ // Handle plain object type
52
+ if (typeof translationTexts === 'object') {
53
+ return Object.entries(translationTexts).map(([language, content]) => ({
54
+ language: String(language),
55
+ text: ensureStringContent(content)
56
+ }));
57
+ }
58
+
59
+ return [];
60
+ };
61
+
62
+ const ensureStringContent = (content: any): string => {
63
+ if (content === null || content === undefined) {
64
+ return '';
65
+ }
66
+
67
+ if (typeof content === 'string') {
68
+ return content;
69
+ }
70
+
71
+ if (typeof content === 'object') {
72
+ try {
73
+ return JSON.stringify(content);
74
+ } catch (error) {
75
+ console.warn('Failed to stringify translation content:', error);
76
+ return '[Invalid Object]';
77
+ }
78
+ }
79
+
80
+ return String(content);
81
+ };
82
+
83
+ const convertToLegacyFormat = (messages: TranscriberMessage[]): ITranslationInfo[] => {
84
+ return messages.map(msg => ({
85
+ roundId: msg.segmentId,
86
+ sender: msg.speakerUserId,
87
+ nick: '',
88
+ text: msg.sourceText,
89
+ end: msg.isCompleted,
90
+ translation: parseTranslationTexts(msg.translationTexts)
91
+ }));
92
+ };
93
+
94
+ // Store watcher callbacks
95
+ const handleAITranscriberEnabledChange = (value: boolean) => {
96
+ isAITranscriberEnabled.value = value || false;
97
+ };
98
+
99
+ const handleAITranscriberRunningChange = (value: boolean) => {
100
+ isAITranscriberRunning.value = value || false;
101
+ };
102
+
103
+ const handleRealtimeMessageListChange = (messageList: TranscriberMessage[]) => {
104
+ if (messageList && messageList.length > 0) {
105
+ const convertedMessages = convertToLegacyFormat(messageList);
106
+ subtitleInfoList.value = convertedMessages;
107
+ } else {
108
+ subtitleInfoList.value = [];
109
+ }
110
+ };
111
+
112
+ // Lifecycle management
113
+ onMounted(() => {
114
+ // Subscribe to TUIStore changes
115
+ TUIStore.watch(StoreName.CALL, {
116
+ [NAME.IS_AI_TRANSCRIBER_ENABLED]: handleAITranscriberEnabledChange,
117
+ [NAME.IS_AI_TRANSCRIBER_RUNNING]: handleAITranscriberRunningChange,
118
+ [NAME.REALTIME_MESSAGE_LIST]: handleRealtimeMessageListChange,
119
+ });
120
+
121
+ // Get initial message data
122
+ const currentMessages = TUIStore.getData(StoreName.CALL, NAME.REALTIME_MESSAGE_LIST);
123
+ if (currentMessages) {
124
+ handleRealtimeMessageListChange(currentMessages);
125
+ }
126
+ });
127
+
128
+ onUnmounted(() => {
129
+ // Unsubscribe from TUIStore changes
130
+ TUIStore.unwatch(StoreName.CALL, {
131
+ [NAME.IS_AI_TRANSCRIBER_ENABLED]: handleAITranscriberEnabledChange,
132
+ [NAME.IS_AI_TRANSCRIBER_RUNNING]: handleAITranscriberRunningChange,
133
+ [NAME.REALTIME_MESSAGE_LIST]: handleRealtimeMessageListChange,
134
+ });
135
+ });
136
+
137
+ return {
138
+ isAITranscriberEnabled,
139
+ isAITranscriberRunning,
140
+ subtitleInfoList,
141
+ };
142
+ }
@@ -8,9 +8,9 @@ export function useGetVolumeMap() {
8
8
  const remoteUserInfoList = ref(TUIStore.getData(StoreName.CALL, NAME.REMOTE_USER_INFO_LIST));
9
9
 
10
10
  const handleLocalUserInfoChange = (value) => {
11
- const isAudioAvailable = TUIGlobal.isWeChat ? value.enableMic : value.isAudioAvailable;
11
+ const isAudioAvailable = TUIGlobal.isWeChat ? value?.enableMic : value?.isAudioAvailable;
12
12
  if (isAudioAvailable) {
13
- volumeMap.value = { ...volumeMap.value, localVideo: value.volume };
13
+ volumeMap.value = { ...volumeMap.value, localVideo: value?.volume };
14
14
  }
15
15
  };
16
16
  const handleRemoteUserInfoListChange = (value) => {