@trtc/calls-uikit-react 4.4.3 → 4.4.4

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 (53) hide show
  1. package/package.json +2 -2
  2. package/src/Components/assets/aiAssistant/desktop/subtitleSettings.svg +4 -0
  3. package/src/Components/assets/aiAssistant/mobile/close-aiAssistant.svg +7 -0
  4. package/src/Components/assets/aiAssistant/mobile/open-aiAssistant.svg +7 -0
  5. package/src/Components/assets/aiAssistant/mobile/subtitleSettings.svg +3 -0
  6. package/src/Components/components/base/CustomSelect/CustomSelect.scss +116 -0
  7. package/src/Components/components/base/CustomSelect/CustomSelect.tsx +96 -0
  8. package/src/Components/components/common/AIAssistant/AISubtitle.scss +109 -0
  9. package/src/Components/components/common/AIAssistant/AISubtitle.tsx +52 -66
  10. package/src/Components/components/common/AIAssistant/components/AITranscriberSwitchH5.tsx +39 -0
  11. package/src/Components/components/common/AIAssistant/components/AITranscriberSwitchPC.scss +46 -0
  12. package/src/Components/components/common/AIAssistant/components/AITranscriberSwitchPC.tsx +42 -0
  13. package/src/Components/components/common/AIAssistant/components/SubtitleContent.scss +67 -0
  14. package/src/Components/components/common/AIAssistant/components/SubtitleContent.tsx +134 -0
  15. package/src/Components/components/common/AIAssistant/components/SubtitleSettingsH5.scss +275 -0
  16. package/src/Components/components/common/AIAssistant/components/SubtitleSettingsH5.tsx +265 -0
  17. package/src/Components/components/common/AIAssistant/components/SubtitleSettingsPC.scss +98 -0
  18. package/src/Components/components/common/AIAssistant/components/SubtitleSettingsPC.tsx +198 -0
  19. package/src/Components/components/common/AIAssistant/components/index.ts +5 -0
  20. package/src/Components/components/common/AIAssistant/index.ts +3 -1
  21. package/src/Components/components/common/TopBar/h5/TopBarH5.tsx +11 -1
  22. package/src/Components/components/common/TopBar/pc/TopBarPC.module.scss +20 -0
  23. package/src/Components/components/common/TopBar/pc/TopBarPC.tsx +14 -9
  24. package/src/Components/hooks/index.ts +2 -0
  25. package/src/Components/hooks/useAIAssistant.ts +174 -0
  26. package/src/TUICallService/CallService/AIAssistant.ts +285 -39
  27. package/src/TUICallService/CallService/index.ts +19 -9
  28. package/src/TUICallService/TUIStore/callStore.ts +5 -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/index.ts +1 -1
  35. package/tuicall-uikit-react.es.js +4265 -3703
  36. package/tuicall-uikit-react.umd.js +8 -3
  37. package/types/Components/components/base/CustomSelect/CustomSelect.d.ts +15 -0
  38. package/types/Components/components/common/AIAssistant/AISubtitle.d.ts +1 -0
  39. package/types/Components/components/common/AIAssistant/components/AITranscriberSwitchH5.d.ts +3 -0
  40. package/types/Components/components/common/AIAssistant/components/AITranscriberSwitchPC.d.ts +4 -0
  41. package/types/Components/components/common/AIAssistant/components/SubtitleContent.d.ts +8 -0
  42. package/types/Components/components/common/AIAssistant/components/SubtitleSettingsH5.d.ts +13 -0
  43. package/types/Components/components/common/AIAssistant/components/SubtitleSettingsPC.d.ts +13 -0
  44. package/types/Components/components/common/AIAssistant/components/index.d.ts +5 -0
  45. package/types/Components/components/common/AIAssistant/index.d.ts +1 -0
  46. package/types/Components/hooks/index.d.ts +2 -1
  47. package/types/Components/hooks/useAIAssistant.d.ts +22 -0
  48. package/types/TUICallService/CallService/AIAssistant.d.ts +72 -15
  49. package/types/TUICallService/CallService/index.d.ts +2 -1
  50. package/types/TUICallService/interface/ICallStore.d.ts +4 -0
  51. package/types/TUICallService/locales/en.d.ts +14 -0
  52. package/types/TUICallService/locales/ja_JP.d.ts +14 -0
  53. package/types/TUICallService/locales/zh-cn.d.ts +14 -0
@@ -0,0 +1,265 @@
1
+ import React, { useState, useEffect, useRef } from 'react';
2
+ import { TUICallKitAPI } from '../../../../../TUICallService/index';
3
+ import { useTranslate } from '../../../../hooks';
4
+ import './SubtitleSettingsH5.scss';
5
+
6
+ interface SubtitleSettingsH5Props {
7
+ visible: boolean;
8
+ onVisibleChange: (visible: boolean) => void;
9
+ onConfirm: (settings: {
10
+ recognitionLanguage: string;
11
+ translationLanguage: string;
12
+ subtitleEnabled: boolean;
13
+ }) => void;
14
+ }
15
+
16
+ interface LanguageOption {
17
+ value: string;
18
+ label: string;
19
+ }
20
+
21
+ const SubtitleSettingsH5: React.FC<SubtitleSettingsH5Props> = ({
22
+ visible,
23
+ onVisibleChange,
24
+ onConfirm
25
+ }) => {
26
+ // Use i18n translation
27
+ const { t } = useTranslate();
28
+
29
+ // Confirmed settings (saved on confirm button click)
30
+ const confirmedSettingsRef = useRef({
31
+ recognitionLanguage: 'zh',
32
+ translationLanguage: '',
33
+ subtitleEnabled: true
34
+ });
35
+
36
+ // Temporary editing state (current user selections)
37
+ const [recognitionLanguage, setRecognitionLanguage] = useState('zh');
38
+ const [translationLanguage, setTranslationLanguage] = useState('');
39
+ const [subtitleEnabled, setSubtitleEnabled] = useState(true);
40
+
41
+ // UI state for language selectors
42
+ const [showRecognitionLanguageSelector, setShowRecognitionLanguageSelector] = useState(false);
43
+ const [showTranslationLanguageSelector, setShowTranslationLanguageSelector] = useState(false);
44
+
45
+ // Reset to last confirmed settings when modal opens
46
+ useEffect(() => {
47
+ if (visible) {
48
+ setRecognitionLanguage(confirmedSettingsRef.current.recognitionLanguage);
49
+ setTranslationLanguage(confirmedSettingsRef.current.translationLanguage);
50
+ setSubtitleEnabled(confirmedSettingsRef.current.subtitleEnabled);
51
+ setShowRecognitionLanguageSelector(false);
52
+ setShowTranslationLanguageSelector(false);
53
+ }
54
+ }, [visible]);
55
+
56
+ // Language options - Supported recognition languages
57
+ const recognitionLanguageOptions: LanguageOption[] = [
58
+ { value: 'zh', label: '中文' },
59
+ { value: 'en', label: 'English' }
60
+ ];
61
+
62
+ // Translation options - Target translation languages (base list)
63
+ // Use native language names for better UX, but keep "no translation" internationalized
64
+ const baseTranslationLanguageOptions: LanguageOption[] = [
65
+ { value: '', label: t('no-translation') },
66
+ { value: 'zh', label: 'Chinese (中文)' },
67
+ { value: 'en', label: 'English (英语)' },
68
+ { value: 'vi', label: 'Vietnamese (越南语)' },
69
+ { value: 'ja', label: 'Japanese (日语)' },
70
+ { value: 'ko', label: 'Korean (韩语)' },
71
+ { value: 'id', label: 'Indonesian (印尼语)' },
72
+ { value: 'th', label: 'Thai (泰语)' },
73
+ { value: 'pt', label: 'Portuguese (葡萄牙语)' },
74
+ { value: 'ar', label: 'Arabic (阿拉伯语)' },
75
+ { value: 'es', label: 'Spanish (西班牙语)' },
76
+ { value: 'fr', label: 'French (法语)' },
77
+ { value: 'ms', label: 'Malay (马来语)' },
78
+ { value: 'de', label: 'German (德语)' },
79
+ { value: 'it', label: 'Italian (意大利语)' },
80
+ { value: 'ru', label: 'Russian (俄语)' }
81
+ ];
82
+
83
+ // Dynamically calculate translation options - exclude current recognition language
84
+ const translationLanguageOptions = baseTranslationLanguageOptions.filter(
85
+ option => option.value === '' || option.value !== recognitionLanguage
86
+ );
87
+
88
+ const getLanguageDisplayName = (value: string) => {
89
+ const allOptions = [...recognitionLanguageOptions, ...translationLanguageOptions];
90
+ const option = allOptions.find(opt => opt.value === value);
91
+ return option?.label || '';
92
+ };
93
+
94
+ const closeModal = () => {
95
+ onVisibleChange(false);
96
+ };
97
+
98
+ const selectRecognitionLanguage = (value: string) => {
99
+ setRecognitionLanguage(value);
100
+ setShowRecognitionLanguageSelector(false);
101
+
102
+ // 如果翻译语言与新的识别语言相同,重置翻译语言
103
+ if (translationLanguage === value) {
104
+ setTranslationLanguage('');
105
+ }
106
+ };
107
+
108
+ const selectTranslationLanguage = (value: string) => {
109
+ setTranslationLanguage(value);
110
+ setShowTranslationLanguageSelector(false);
111
+ };
112
+
113
+ const toggleSubtitle = () => {
114
+ setSubtitleEnabled(!subtitleEnabled);
115
+ };
116
+
117
+ const confirmSettings = async () => {
118
+ try {
119
+ // Save current settings as confirmed settings
120
+ confirmedSettingsRef.current = {
121
+ recognitionLanguage,
122
+ translationLanguage,
123
+ subtitleEnabled
124
+ };
125
+
126
+ // Call updateRealTimeTranscriber when settings are confirmed
127
+ const translationLanguages = translationLanguage ? [translationLanguage] : [];
128
+
129
+ await TUICallKitAPI._aiAssistant.updateRealTimeTranscriber({
130
+ sourceLanguage: recognitionLanguage,
131
+ translationLanguages: translationLanguages,
132
+ });
133
+
134
+ // Emit confirm event
135
+ onConfirm({
136
+ recognitionLanguage,
137
+ translationLanguage,
138
+ subtitleEnabled
139
+ });
140
+
141
+ closeModal();
142
+ } catch (error) {
143
+ console.error('Failed to update AI transcriber settings:', error);
144
+ }
145
+ };
146
+
147
+ // Don't render if not visible
148
+ if (!visible) {
149
+ return null;
150
+ }
151
+
152
+ return (
153
+ <div className="subtitle-settings-overlay">
154
+ <div className="subtitle-settings-modal" onClick={(e) => e.stopPropagation()}>
155
+ {/* Header */}
156
+ <div className="modal-header">
157
+ <h3 className="modal-title">{t('ai-subtitle-settings')}</h3>
158
+ </div>
159
+
160
+ {/* Content */}
161
+ <div className="modal-content">
162
+ {/* Recognition and translation settings group */}
163
+ <div className="setting-group">
164
+ <div className="group-title">{t('recognition-and-translation-settings')}</div>
165
+ <div className="group-content">
166
+ {/* Recognition language */}
167
+ <div className="setting-section">
168
+ <div className="section-header" onClick={() => setShowRecognitionLanguageSelector(true)}>
169
+ <span className="section-title">{t('recognition-language')}</span>
170
+ <span className="section-value">
171
+ {getLanguageDisplayName(recognitionLanguage)}
172
+ <svg className="arrow-icon" width="16" height="16" viewBox="0 0 16 16" fill="none">
173
+ <path d="M6 4L10 8L6 12" stroke="#999" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
174
+ </svg>
175
+ </span>
176
+ </div>
177
+ </div>
178
+
179
+ {/* Translation language */}
180
+ <div className="setting-section">
181
+ <div className="section-header" onClick={() => setShowTranslationLanguageSelector(true)}>
182
+ <span className="section-title">{t('translation-language')}</span>
183
+ <span className="section-value">
184
+ {getLanguageDisplayName(translationLanguage) || t('no-translation')}
185
+ <svg className="arrow-icon" width="16" height="16" viewBox="0 0 16 16" fill="none">
186
+ <path d="M6 4L10 8L6 12" stroke="#999" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
187
+ </svg>
188
+ </span>
189
+ </div>
190
+ </div>
191
+
192
+ {/* Subtitle display bilingual */}
193
+ <div className="setting-section">
194
+ <div className="section-header">
195
+ <span className="section-title">{t('subtitle-display-bilingual')}</span>
196
+ <div
197
+ className={`toggle-switch ${subtitleEnabled ? 'active' : ''}`}
198
+ onClick={toggleSubtitle}
199
+ >
200
+ <div className="toggle-slider"></div>
201
+ </div>
202
+ </div>
203
+ </div>
204
+ </div>
205
+ </div>
206
+ </div>
207
+
208
+ {/* Footer with buttons */}
209
+ <div className="modal-footer">
210
+ <button className="btn btn-cancel" onClick={closeModal}>{t('Cancel')}</button>
211
+ <button className="btn btn-confirm" onClick={confirmSettings}>{t('confirm')}</button>
212
+ </div>
213
+ </div>
214
+
215
+ {/* Language Selector Modals */}
216
+ {/* Recognition Language Selector */}
217
+ {showRecognitionLanguageSelector && (
218
+ <div className="language-selector-overlay" onClick={() => setShowRecognitionLanguageSelector(false)}>
219
+ <div className="language-selector" onClick={(e) => e.stopPropagation()}>
220
+ <div className="selector-header">
221
+ <h3 className="selector-title">{t('select-recognition-language')}</h3>
222
+ <div className="header-placeholder"></div>
223
+ </div>
224
+ <div className="language-list">
225
+ {recognitionLanguageOptions.map((lang) => (
226
+ <div
227
+ key={lang.value}
228
+ className={`language-item ${recognitionLanguage === lang.value ? 'selected' : ''}`}
229
+ onClick={() => selectRecognitionLanguage(lang.value)}
230
+ >
231
+ <span>{lang.label}</span>
232
+ </div>
233
+ ))}
234
+ </div>
235
+ </div>
236
+ </div>
237
+ )}
238
+
239
+ {/* Translation Language Selector */}
240
+ {showTranslationLanguageSelector && (
241
+ <div className="language-selector-overlay" onClick={() => setShowTranslationLanguageSelector(false)}>
242
+ <div className="language-selector" onClick={(e) => e.stopPropagation()}>
243
+ <div className="selector-header">
244
+ <h3 className="selector-title">{t('select-translation-language')}</h3>
245
+ <div className="header-placeholder"></div>
246
+ </div>
247
+ <div className="language-list">
248
+ {translationLanguageOptions.map((lang) => (
249
+ <div
250
+ key={lang.value}
251
+ className={`language-item ${translationLanguage === lang.value ? 'selected' : ''}`}
252
+ onClick={() => selectTranslationLanguage(lang.value)}
253
+ >
254
+ <span>{lang.label}</span>
255
+ </div>
256
+ ))}
257
+ </div>
258
+ </div>
259
+ </div>
260
+ )}
261
+ </div>
262
+ );
263
+ };
264
+
265
+ export default SubtitleSettingsH5;
@@ -0,0 +1,98 @@
1
+ .subtitle-settings-overlay-pc {
2
+ position: absolute;
3
+ top: 50%;
4
+ left: 50%;
5
+ width: 489px;
6
+ height: 430px;
7
+ transform: translate(-50%, -50%);
8
+ display: flex;
9
+ align-items: center;
10
+ justify-content: center;
11
+ z-index: 1000;
12
+ font-family: PingFang SC;
13
+ box-shadow: 0px 2px 6px 0px var(--Black-8);
14
+ }
15
+
16
+ .subtitle-settings-modal-pc {
17
+ background: white;
18
+ border-radius: 12px;
19
+ width: 480px;
20
+ height: 430px;
21
+ overflow: hidden;
22
+ }
23
+
24
+ .modal-header-pc {
25
+ display: flex;
26
+ align-items: center;
27
+ justify-content: space-between;
28
+ padding: 24px 24px 10px 24px;
29
+ }
30
+
31
+ .modal-title-pc {
32
+ font-size: 16px;
33
+ font-weight: 600;
34
+ color: #000000E5;
35
+ }
36
+
37
+ .close-btn-pc {
38
+ background: none;
39
+ border: none;
40
+ cursor: pointer;
41
+ padding: 4px;
42
+ border-radius: 4px;
43
+ transition: background-color 0.2s;
44
+
45
+ &:hover {
46
+ background-color: #f5f5f5;
47
+ }
48
+ }
49
+
50
+ .modal-content-pc {
51
+ padding: 24px;
52
+ }
53
+
54
+ .setting-item-pc {
55
+ margin-bottom: 24px;
56
+
57
+ &:last-child {
58
+ margin-bottom: 0;
59
+ }
60
+ }
61
+
62
+ .setting-label-pc {
63
+ display: block;
64
+ font-size: 14px;
65
+ font-weight: 400;
66
+ color: #4F586B;
67
+ margin-bottom: 8px;
68
+ }
69
+
70
+ .modal-footer-pc {
71
+ display: flex;
72
+ justify-content: flex-end;
73
+ gap: 20px;
74
+ padding: 16px 24px 24px;
75
+ }
76
+
77
+ .btn-pc {
78
+ width: 72px;
79
+ height: 32px;
80
+ border-radius: 6px;
81
+ font-size: 14px;
82
+ font-weight: 500;
83
+ cursor: pointer;
84
+ border-radius: 26px;
85
+ transition: all 0.2s;
86
+ border: 1px solid transparent;
87
+
88
+ &.btn-cancel-pc {
89
+ color: #1C66E5;
90
+ border-color: #1C66E5;
91
+ background-color: white;
92
+ }
93
+
94
+ &.btn-confirm-pc {
95
+ background: #1C66E5;
96
+ color: white;
97
+ }
98
+ }
@@ -0,0 +1,198 @@
1
+ import React, { useState, useEffect, useRef } from 'react';
2
+ import { TUICallKitAPI } from '../../../../../TUICallService/index';
3
+ import { useTranslate } from '../../../../hooks';
4
+ import CustomSelect, { SelectOption } from '../../../base/CustomSelect/CustomSelect';
5
+ import './SubtitleSettingsPC.scss';
6
+
7
+ interface SubtitleSettingsPCProps {
8
+ visible: boolean;
9
+ onVisibleChange: (visible: boolean) => void;
10
+ onConfirm: (settings: {
11
+ recognitionLanguage: string;
12
+ translationLanguage: string;
13
+ subtitleDisplay: string;
14
+ }) => void;
15
+ }
16
+
17
+ const SubtitleSettingsPC: React.FC<SubtitleSettingsPCProps> = ({
18
+ visible,
19
+ onVisibleChange,
20
+ onConfirm
21
+ }) => {
22
+ // Use i18n translation
23
+ const { t } = useTranslate();
24
+
25
+ // Confirmed settings (saved on confirm button click)
26
+ const confirmedSettingsRef = useRef({
27
+ recognitionLanguage: 'zh',
28
+ translationLanguage: '',
29
+ subtitleDisplay: 'both'
30
+ });
31
+
32
+ // Temporary editing state (current user selections)
33
+ const [recognitionLanguage, setRecognitionLanguage] = useState('zh');
34
+ const [translationLanguage, setTranslationLanguage] = useState('');
35
+ const [subtitleDisplay, setSubtitleDisplay] = useState('both');
36
+
37
+ // Reset to last confirmed settings when modal opens
38
+ useEffect(() => {
39
+ if (visible) {
40
+ setRecognitionLanguage(confirmedSettingsRef.current.recognitionLanguage);
41
+ setTranslationLanguage(confirmedSettingsRef.current.translationLanguage);
42
+ setSubtitleDisplay(confirmedSettingsRef.current.subtitleDisplay);
43
+ }
44
+ }, [visible]);
45
+
46
+ // Language options for CustomSelect - Supported recognition languages
47
+ const languageOptions: SelectOption[] = [
48
+ { value: 'zh', label: '中文' },
49
+ { value: 'en', label: 'English' }
50
+ ];
51
+
52
+ // Translation options for CustomSelect - Target translation languages (base list)
53
+ // Use native language names for better UX, but keep "no translation" internationalized
54
+ const baseTranslationOptions: SelectOption[] = [
55
+ { value: '', label: t('no-translation') },
56
+ { value: 'zh', label: 'Chinese (中文)' },
57
+ { value: 'en', label: 'English (英语)' },
58
+ { value: 'vi', label: 'Vietnamese (越南语)' },
59
+ { value: 'ja', label: 'Japanese (日语)' },
60
+ { value: 'ko', label: 'Korean (韩语)' },
61
+ { value: 'id', label: 'Indonesian (印尼语)' },
62
+ { value: 'th', label: 'Thai (泰语)' },
63
+ { value: 'pt', label: 'Portuguese (葡萄牙语)' },
64
+ { value: 'ar', label: 'Arabic (阿拉伯语)' },
65
+ { value: 'es', label: 'Spanish (西班牙语)' },
66
+ { value: 'fr', label: 'French (法语)' },
67
+ { value: 'ms', label: 'Malay (马来语)' },
68
+ { value: 'de', label: 'German (德语)' },
69
+ { value: 'it', label: 'Italian (意大利语)' },
70
+ { value: 'ru', label: 'Russian (俄语)' }
71
+ ];
72
+
73
+ // Dynamically calculate translation options - exclude current recognition language
74
+ const translationOptions = baseTranslationOptions.filter(
75
+ option => option.value === '' || option.value !== recognitionLanguage
76
+ );
77
+
78
+ // Subtitle display options
79
+ const subtitleDisplayOptions: SelectOption[] = [
80
+ { value: 'both', label: t('show-bilingual') },
81
+ { value: 'original', label: t('show-original-only') }
82
+ ];
83
+
84
+ const handleOverlayClick = () => {
85
+ closeModal();
86
+ };
87
+
88
+ const closeModal = () => {
89
+ onVisibleChange(false);
90
+ };
91
+
92
+ const handleLanguageChange = (value: string | number) => {
93
+ const newLanguage = String(value);
94
+ setRecognitionLanguage(newLanguage);
95
+
96
+ // 如果翻译语言与新的识别语言相同,重置翻译语言
97
+ if (translationLanguage === newLanguage) {
98
+ setTranslationLanguage('');
99
+ }
100
+ };
101
+
102
+ const handleTranslationChange = (value: string | number) => {
103
+ setTranslationLanguage(String(value));
104
+ };
105
+
106
+ const handleSubtitleDisplayChange = (value: string | number) => {
107
+ setSubtitleDisplay(String(value));
108
+ };
109
+
110
+ const confirmSettings = async () => {
111
+ try {
112
+ // Save current settings as confirmed settings
113
+ confirmedSettingsRef.current = {
114
+ recognitionLanguage,
115
+ translationLanguage,
116
+ subtitleDisplay
117
+ };
118
+
119
+ // Call updateRealTimeTranscriber when settings are confirmed
120
+ const translationLanguages = translationLanguage ? [translationLanguage] : [];
121
+
122
+ await TUICallKitAPI._aiAssistant.updateRealTimeTranscriber({
123
+ sourceLanguage: recognitionLanguage,
124
+ translationLanguages: translationLanguages,
125
+ });
126
+
127
+ // Emit confirm event
128
+ onConfirm({
129
+ recognitionLanguage,
130
+ translationLanguage,
131
+ subtitleDisplay
132
+ });
133
+
134
+ closeModal();
135
+ } catch (error) {
136
+ console.error('Failed to update AI transcriber settings:', error);
137
+ }
138
+ };
139
+
140
+ // Don't render if not visible
141
+ if (!visible) {
142
+ return null;
143
+ }
144
+
145
+ return (
146
+ <div className="subtitle-settings-overlay-pc" onClick={handleOverlayClick}>
147
+ <div className="subtitle-settings-modal-pc" onClick={(e) => e.stopPropagation()}>
148
+ <div className="modal-header-pc">
149
+ <h3 className="modal-title-pc">{t('ai-subtitle-settings')}</h3>
150
+ <button className="close-btn-pc" onClick={closeModal}>
151
+ <svg width="16" height="16" viewBox="0 0 16 16" fill="none">
152
+ <path d="M12 4L4 12M4 4L12 12" stroke="#666" strokeWidth="2" strokeLinecap="round"/>
153
+ </svg>
154
+ </button>
155
+ </div>
156
+
157
+ <div className="modal-content-pc">
158
+ {/* Recognition language */}
159
+ <div className="setting-item-pc">
160
+ <label className="setting-label-pc">{t('recognition-language')}</label>
161
+ <CustomSelect
162
+ value={recognitionLanguage}
163
+ options={languageOptions}
164
+ onChange={handleLanguageChange}
165
+ />
166
+ </div>
167
+
168
+ {/* Translation language */}
169
+ <div className="setting-item-pc">
170
+ <label className="setting-label-pc">{t('translation-language')}</label>
171
+ <CustomSelect
172
+ value={translationLanguage}
173
+ options={translationOptions}
174
+ onChange={handleTranslationChange}
175
+ />
176
+ </div>
177
+
178
+ {/* Subtitle display settings */}
179
+ <div className="setting-item-pc">
180
+ <label className="setting-label-pc">{t('subtitle-display-settings')}</label>
181
+ <CustomSelect
182
+ value={subtitleDisplay}
183
+ options={subtitleDisplayOptions}
184
+ onChange={handleSubtitleDisplayChange}
185
+ />
186
+ </div>
187
+ </div>
188
+
189
+ <div className="modal-footer-pc">
190
+ <button className="btn-pc btn-cancel-pc" onClick={closeModal}>{t('Cancel')}</button>
191
+ <button className="btn-pc btn-confirm-pc" onClick={confirmSettings}>{t('save')}</button>
192
+ </div>
193
+ </div>
194
+ </div>
195
+ );
196
+ };
197
+
198
+ export default SubtitleSettingsPC;
@@ -0,0 +1,5 @@
1
+ export { default as SubtitleContent } from './SubtitleContent';
2
+ export { default as SubtitleSettingsPC } from './SubtitleSettingsPC';
3
+ export { default as SubtitleSettingsH5 } from './SubtitleSettingsH5';
4
+ export { default as AITranscriberSwitchPC } from './AITranscriberSwitchPC';
5
+ export { default as AITranscriberSwitchH5 } from './AITranscriberSwitchH5';
@@ -7,4 +7,6 @@ export {
7
7
  aiAssistant,
8
8
  ASREvent,
9
9
  AISubtitle,
10
- }
10
+ };
11
+
12
+ export * from './components';
@@ -3,9 +3,11 @@ import Time from '../../../base/Time/Time';
3
3
  import Col from '../../../base/Grid/Col';
4
4
  import Row from '../../../base/Grid/Row';
5
5
  import Minimize from '../../ButtonPanel/button/Minimize';
6
+ import { AITranscriberSwitchH5 } from '../../AIAssistant/components';
6
7
  import { CallRole, CallStatus } from '../../../../../TUICallService';
7
8
  import Tip from '../../Tip/Tip';
8
9
  import { CallInfoContext } from '../../../../context';
10
+ import { useAIAssistant } from '../../../../hooks/useAIAssistant';
9
11
  import topBarH5Style from './TopBarH5.module.scss';
10
12
 
11
13
  interface ITopBarH5Props {
@@ -17,13 +19,21 @@ export default function TopBarH5(props: ITopBarH5Props) {
17
19
  const {
18
20
  isGroupCall, callStatus, callRole, allowedMinimized,
19
21
  } = useContext(CallInfoContext);
22
+
23
+ const { isAITranscriberEnabled } = useAIAssistant();
24
+
20
25
  const showTip = (isGroupCall
21
26
  && (callStatus === CallStatus.CONNECTED || callRole === CallRole.CALLER));
27
+ const showAITranscriberSwitch = callStatus === CallStatus.CONNECTED && isAITranscriberEnabled;
28
+
22
29
  return (
23
30
  <div className={topBarH5Style['top-bar-container']}>
24
31
  <Row className={topBarH5Style['top-bar']}>
25
32
  <Col justify='start' span={4}>
26
- {allowedMinimized && <Minimize />}
33
+ <div style={{ display: 'flex', alignItems: 'center', gap: '12px' }}>
34
+ {allowedMinimized && <Minimize />}
35
+ {showAITranscriberSwitch && <AITranscriberSwitchH5 />}
36
+ </div>
27
37
  </Col>
28
38
  <Col align='center' span={4}>
29
39
  {callStatus === CallStatus.CONNECTED
@@ -5,4 +5,24 @@
5
5
  line-height: 20px;
6
6
  margin-top: 20px;
7
7
  z-index: 2;
8
+ display: flex;
9
+ align-items: center;
10
+ justify-content: flex-end;
11
+ }
12
+
13
+ .topbar-center {
14
+ position: absolute;
15
+ left: 50%;
16
+ transform: translateX(-50%);
17
+ display: flex;
18
+ align-items: center;
19
+ justify-content: center;
20
+ }
21
+
22
+ .topbar-right-controls {
23
+ margin-right: 10px;
24
+ display: flex;
25
+ align-items: center;
26
+ gap: 16px;
27
+ z-index: 3;
8
28
  }
@@ -1,11 +1,11 @@
1
1
  import React, { useContext } from 'react';
2
2
  import Time from '../../../base/Time/Time';
3
- import Col from '../../../base/Grid/Col';
4
- import Row from '../../../base/Grid/Row';
5
3
  import Minimize from '../../ButtonPanel/button/Minimize/Minimize';
6
4
  import FullScreen from '../../ButtonPanel/button/FullScreen';
5
+ import { AITranscriberSwitchPC } from '../../AIAssistant/components';
7
6
  import { CallStatus } from '../../../../../TUICallService';
8
7
  import { CallInfoContext } from '../../../../context';
8
+ import { useAIAssistant } from '../../../../hooks/useAIAssistant';
9
9
  import topBarPCStyle from './TopBarPC.module.scss';
10
10
 
11
11
  interface ITopBarPCProps {
@@ -20,17 +20,22 @@ export default function TopBarPC(props: ITopBarPCProps) {
20
20
  allowedMinimized,
21
21
  allowedFullScreen,
22
22
  } = useContext(CallInfoContext);
23
+
24
+ const { isAITranscriberEnabled } = useAIAssistant();
25
+
23
26
  const showTime = callStatus === CallStatus.CONNECTED && !isGroupCall;
27
+ const showAITranscriberSwitch = callStatus === CallStatus.CONNECTED && isAITranscriberEnabled;
28
+
24
29
  return (
25
- <Row className={topBarPCStyle['single-top-bar']}>
26
- <Col span={4} />
27
- <Col span={4}>
30
+ <div className={topBarPCStyle['single-top-bar']}>
31
+ <div className={topBarPCStyle['topbar-center']}>
28
32
  {showTime && <Time callDuration={callDuration} />}
29
- </Col>
30
- <Col span={4} justify='end'>
33
+ </div>
34
+ <div className={topBarPCStyle['topbar-right-controls']}>
35
+ {showAITranscriberSwitch && <AITranscriberSwitchPC />}
31
36
  {allowedMinimized && <Minimize />}
32
37
  {allowedFullScreen && <FullScreen domID='tuicallkit-id' />}
33
- </Col>
34
- </Row>
38
+ </div>
39
+ </div>
35
40
  );
36
41
  }