@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.
- package/package.json +2 -2
- package/src/Components/TUICallKit.vue +1 -1
- package/src/Components/assets/aiAssistant/desktop/subtitleSettings.svg +4 -0
- package/src/Components/assets/aiAssistant/mobile/close-aiAssistant.svg +7 -0
- package/src/Components/assets/aiAssistant/mobile/open-aiAssistant.svg +7 -0
- package/src/Components/assets/aiAssistant/mobile/subtitleSettings.svg +3 -0
- package/src/Components/components/base/CustomSelect/CustomSelect.ts +45 -0
- package/src/Components/components/base/CustomSelect/CustomSelect.vue +199 -0
- package/src/Components/components/common/AIAssistant/AISubtitle.vue +155 -37
- package/src/Components/components/common/AIAssistant/components/AITranscriberSwitchH5.vue +35 -0
- package/src/Components/components/common/AIAssistant/components/AITranscriberSwitchPC.vue +89 -0
- package/src/Components/components/common/AIAssistant/components/SubtitleContent.vue +234 -0
- package/src/Components/components/common/AIAssistant/components/SubtitleSettingsH5.vue +534 -0
- package/src/Components/components/common/AIAssistant/components/SubtitleSettingsPC.vue +294 -0
- package/src/Components/components/common/TopBar/TopBar.vue +41 -15
- package/src/Components/hooks/index.ts +1 -0
- package/src/Components/hooks/useAIAssistant.ts +142 -0
- package/src/Components/hooks/useGetVolumeMap.ts +2 -2
- package/src/TUICallService/CallService/AIAssistant.ts +285 -39
- package/src/TUICallService/CallService/UIKitModal.ts +14 -6
- package/src/TUICallService/CallService/bellContext.ts +25 -2
- package/src/TUICallService/CallService/engineEventHandler.ts +6 -1
- package/src/TUICallService/CallService/index.ts +72 -39
- package/src/TUICallService/CallService/miniProgram.ts +0 -12
- package/src/TUICallService/TUIStore/callStore.ts +6 -1
- package/src/TUICallService/UIKitModal/UIKitModal.ts +117 -0
- package/src/TUICallService/UIKitModal/index.ts +2 -0
- package/src/TUICallService/UIKitModal/type.ts +15 -0
- package/src/TUICallService/const/index.ts +4 -0
- package/src/TUICallService/interface/ICallStore.ts +5 -0
- package/src/TUICallService/locales/en.ts +15 -0
- package/src/TUICallService/locales/ja_JP.ts +15 -0
- package/src/TUICallService/locales/zh-cn.ts +15 -0
- package/src/TUICallService/utils/common-utils.ts +1 -1
- package/src/index.ts +1 -1
- package/stats.html +1 -1
- package/tuicall-uikit-vue.es.js +4199 -3474
- package/tuicall-uikit-vue.umd.js +2 -2
- package/types/Components/components/base/CustomSelect/CustomSelect.d.ts +41 -0
- package/types/Components/hooks/index.d.ts +1 -0
- package/types/Components/hooks/useAIAssistant.d.ts +19 -0
- package/types/TUICallService/CallService/AIAssistant.d.ts +72 -15
- package/types/TUICallService/CallService/bellContext.d.ts +3 -0
- package/types/TUICallService/CallService/index.d.ts +4 -3
- package/types/TUICallService/CallService/miniProgram.d.ts +0 -1
- package/types/TUICallService/UIKitModal/UIKitModal.d.ts +4 -0
- package/types/TUICallService/UIKitModal/index.d.ts +2 -0
- package/types/TUICallService/UIKitModal/type.d.ts +13 -0
- package/types/TUICallService/interface/ICallStore.d.ts +4 -0
- package/types/TUICallService/locales/en.d.ts +14 -0
- package/types/TUICallService/locales/ja_JP.d.ts +14 -0
- package/types/TUICallService/locales/zh-cn.d.ts +14 -0
- package/types/tsconfig.tsbuildinfo +1 -1
- package/src/Components/components/common/AIAssistant/AIAssistant.ts +0 -130
- package/src/Components/components/common/AIAssistant/index.ts +0 -11
- package/types/Components/components/common/AIAssistant/AIAssistant.d.ts +0 -40
- package/types/Components/components/common/AIAssistant/index.d.ts +0 -4
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div
|
|
3
|
+
v-if="isAITranscriberRunning && subtitleInfoList.length > 0"
|
|
4
|
+
ref="subtitleContainer"
|
|
5
|
+
:class="['subtitle-content', { 'subtitle-content--h5': isH5 }]"
|
|
6
|
+
@mouseenter="!isH5 && (showSettingsIcon = true)"
|
|
7
|
+
@mouseleave="!isH5 && (showSettingsIcon = false)"
|
|
8
|
+
>
|
|
9
|
+
<div
|
|
10
|
+
v-show="isH5 || showSettingsIcon"
|
|
11
|
+
:class="['subtitle-content__settings-btn', { 'subtitle-content__settings-btn--h5': isH5 }]"
|
|
12
|
+
@click="handleSettingsClick"
|
|
13
|
+
>
|
|
14
|
+
<TKImage
|
|
15
|
+
:src="settingsIcon"
|
|
16
|
+
:width="iconSize"
|
|
17
|
+
:height="iconSize"
|
|
18
|
+
/>
|
|
19
|
+
</div>
|
|
20
|
+
|
|
21
|
+
<div v-for="(subtitleInfo, index) in (Array.isArray(subtitleInfoList) ? subtitleInfoList : [])" :key="subtitleInfo.roundId">
|
|
22
|
+
<div v-if="index !== 0" style="height: 16px;"> </div>
|
|
23
|
+
<div class="sender-name">{{ `${subtitleInfo?.nick || subtitleInfo?.sender}:` }}</div>
|
|
24
|
+
<div>{{ subtitleInfo?.text }}</div>
|
|
25
|
+
<div v-for="tranlationContent in (Array.isArray(subtitleInfo?.translation) ? subtitleInfo.translation : [])" :key="tranlationContent?.language">
|
|
26
|
+
<span>{{ formatTranslationContent(tranlationContent?.text) }}</span>
|
|
27
|
+
</div>
|
|
28
|
+
</div>
|
|
29
|
+
</div>
|
|
30
|
+
</template>
|
|
31
|
+
|
|
32
|
+
<script lang="ts" setup>
|
|
33
|
+
import { ref, computed, watch, nextTick } from '../../../../../adapter-vue';
|
|
34
|
+
import { TUIGlobal } from '../../../../../TUICallService/index';
|
|
35
|
+
import { useAIAssistant } from '../../../../hooks/useAIAssistant';
|
|
36
|
+
import TKImage from '../../../base/TKImage/TKImage.vue';
|
|
37
|
+
import subtitleSettingsDeskTopIcon from '../../../../assets/aiAssistant/desktop/subtitleSettings.svg';
|
|
38
|
+
import subtitleSettingsH5Icon from '../../../../assets/aiAssistant/mobile/subtitleSettings.svg';
|
|
39
|
+
|
|
40
|
+
// Internal state management
|
|
41
|
+
const showSettingsIcon = ref(false);
|
|
42
|
+
const subtitleContainer = ref<HTMLElement | null>(null);
|
|
43
|
+
|
|
44
|
+
// Use AI Assistant hook (combines both status and subtitle data)
|
|
45
|
+
const { subtitleInfoList, isAITranscriberRunning } = useAIAssistant();
|
|
46
|
+
|
|
47
|
+
// Device type detection
|
|
48
|
+
const isH5 = TUIGlobal.isH5;
|
|
49
|
+
|
|
50
|
+
// Dynamic icon selection based on device type
|
|
51
|
+
const settingsIcon = computed(() => {
|
|
52
|
+
return isH5 ? subtitleSettingsH5Icon : subtitleSettingsDeskTopIcon;
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
// Icon size is consistent across all devices
|
|
56
|
+
const iconSize = '16px';
|
|
57
|
+
|
|
58
|
+
// Events
|
|
59
|
+
const emit = defineEmits(['open-settings']);
|
|
60
|
+
|
|
61
|
+
// Handle settings button click
|
|
62
|
+
const handleSettingsClick = () => {
|
|
63
|
+
emit('open-settings');
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
// Auto scroll to bottom when new messages arrive
|
|
67
|
+
const scrollToBottom = () => {
|
|
68
|
+
if (subtitleContainer.value) {
|
|
69
|
+
nextTick(() => {
|
|
70
|
+
subtitleContainer.value!.scrollTop = subtitleContainer.value!.scrollHeight;
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
// Watch for changes in subtitle list and auto scroll
|
|
76
|
+
watch(
|
|
77
|
+
() => subtitleInfoList.value,
|
|
78
|
+
(newList, oldList) => {
|
|
79
|
+
// Only scroll if new messages are added
|
|
80
|
+
if (newList && oldList && newList.length > oldList.length) {
|
|
81
|
+
scrollToBottom();
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
{ deep: true }
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
// Also scroll when the component first shows subtitles
|
|
88
|
+
watch(
|
|
89
|
+
() => isAITranscriberRunning.value && subtitleInfoList.value.length > 0,
|
|
90
|
+
(shouldShow) => {
|
|
91
|
+
if (shouldShow) {
|
|
92
|
+
scrollToBottom();
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
);
|
|
96
|
+
|
|
97
|
+
// Parse translation data to extract language and text
|
|
98
|
+
const parseTranslationData = (content: any) => {
|
|
99
|
+
if (content === null || content === undefined) {
|
|
100
|
+
return { language: 'Unknown', text: '' };
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// If content is already a string, check if it's a JSON string
|
|
104
|
+
if (typeof content === 'string') {
|
|
105
|
+
try {
|
|
106
|
+
// Try to parse as JSON in case it's a nested JSON string
|
|
107
|
+
const parsed = JSON.parse(content);
|
|
108
|
+
if (parsed && typeof parsed === 'object') {
|
|
109
|
+
return {
|
|
110
|
+
language: parsed.language || 'Unknown',
|
|
111
|
+
text: parsed.text || content
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
return { language: 'Unknown', text: content };
|
|
115
|
+
} catch {
|
|
116
|
+
// If parsing fails, return the original string
|
|
117
|
+
return { language: 'Unknown', text: content };
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return { language: 'Unknown', text: String(content) };
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
// Format translation content to prevent [object Object] display
|
|
125
|
+
const formatTranslationContent = (content: any): string => {
|
|
126
|
+
return parseTranslationData(content).text;
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
// Get language display name from translation content
|
|
130
|
+
const getLanguageDisplayFromContent = (content: any): string => {
|
|
131
|
+
const { language } = parseTranslationData(content);
|
|
132
|
+
return getLanguageDisplay(language);
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
// Get language display name
|
|
136
|
+
const getLanguageDisplay = (languageCode: string): string => {
|
|
137
|
+
if (!languageCode || languageCode === 'Unknown') return 'Translation';
|
|
138
|
+
|
|
139
|
+
// Handle numeric language codes
|
|
140
|
+
if (languageCode === '0' || languageCode === '1' || languageCode === '2') {
|
|
141
|
+
return 'Translation';
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Map common language codes with bilingual format: English (中文)
|
|
145
|
+
const languageMap: Record<string, string> = {
|
|
146
|
+
'en': 'English (英语)',
|
|
147
|
+
'zh': 'Chinese (中文)',
|
|
148
|
+
'ja': 'Japanese (日语)',
|
|
149
|
+
'ko': 'Korean (韩语)',
|
|
150
|
+
'es': 'Spanish (西班牙语)',
|
|
151
|
+
'fr': 'French (法语)',
|
|
152
|
+
'de': 'German (德语)',
|
|
153
|
+
'vi': 'Vietnamese (越南语)',
|
|
154
|
+
'id': 'Indonesian (印尼语)',
|
|
155
|
+
'th': 'Thai (泰语)',
|
|
156
|
+
'pt': 'Portuguese (葡萄牙语)',
|
|
157
|
+
'ar': 'Arabic (阿拉伯语)',
|
|
158
|
+
'ms': 'Malay (马来语)',
|
|
159
|
+
'it': 'Italian (意大利语)',
|
|
160
|
+
'ru': 'Russian (俄语)'
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
return languageMap[languageCode] || languageCode;
|
|
164
|
+
};
|
|
165
|
+
</script>
|
|
166
|
+
|
|
167
|
+
<style lang="scss" scoped>
|
|
168
|
+
// Common styles for both PC and H5
|
|
169
|
+
.subtitle-content {
|
|
170
|
+
position: relative;
|
|
171
|
+
padding: 10px 12px;
|
|
172
|
+
color: #fff;
|
|
173
|
+
background-color: #000000B8;
|
|
174
|
+
opacity: 0.72;
|
|
175
|
+
border-radius: 8px;
|
|
176
|
+
overflow-y: auto;
|
|
177
|
+
overflow-x: hidden;
|
|
178
|
+
font-size: 12px;
|
|
179
|
+
|
|
180
|
+
/* Hide scrollbar for webkit browsers */
|
|
181
|
+
&::-webkit-scrollbar {
|
|
182
|
+
width: 0;
|
|
183
|
+
background: transparent;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/* Hide scrollbar for Firefox */
|
|
187
|
+
scrollbar-width: none;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// PC specific styles
|
|
191
|
+
.subtitle-content:not(.subtitle-content--h5) {
|
|
192
|
+
width: 640px;
|
|
193
|
+
min-width: 640px;
|
|
194
|
+
height: 180px;
|
|
195
|
+
max-height: 180px;
|
|
196
|
+
|
|
197
|
+
.subtitle-content__settings-btn {
|
|
198
|
+
position: fixed;
|
|
199
|
+
top: 8px;
|
|
200
|
+
right: 8px;
|
|
201
|
+
cursor: pointer;
|
|
202
|
+
z-index: 999;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// H5 specific styles
|
|
207
|
+
.subtitle-content--h5 {
|
|
208
|
+
position: relative;
|
|
209
|
+
width: 350px;
|
|
210
|
+
min-width: 350px;
|
|
211
|
+
height: 116px;
|
|
212
|
+
max-height: 116px;
|
|
213
|
+
|
|
214
|
+
.subtitle-content__settings-btn {
|
|
215
|
+
position: fixed;
|
|
216
|
+
top: 50%;
|
|
217
|
+
right: 4px;
|
|
218
|
+
cursor: pointer;
|
|
219
|
+
z-index: 999;
|
|
220
|
+
transform: translateY(-50%);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
.sender-name {
|
|
225
|
+
font-family: PingFang SC;
|
|
226
|
+
font-weight: 400;
|
|
227
|
+
font-style: Regular;
|
|
228
|
+
font-size: 12px;
|
|
229
|
+
leading-trim: NONE;
|
|
230
|
+
line-height: 16px;
|
|
231
|
+
letter-spacing: 0px;
|
|
232
|
+
color: #FFFFFFBF;
|
|
233
|
+
}
|
|
234
|
+
</style>
|