@tencentcloud/roomkit-electron-vue3 2.7.0 → 2.7.2
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/es/components/AITools/AISubtitles.vue.mjs +1 -1
- package/es/components/AITools/AISubtitles.vue2.mjs +18 -19
- package/es/components/AITools/AITranscription.vue.mjs +1 -1
- package/es/components/AITools/AITranscription.vue2.mjs +65 -76
- package/es/components/Chat/ChatEditor/index.vue2.mjs +1 -1
- package/es/components/Chat/ChatKit/components/TUIChat/chat-header/index.vue2.mjs +1 -1
- package/es/components/Chat/ChatKit/components/TUIChat/emoji-config/default-emoji.mjs +4 -4
- package/es/components/Chat/ChatKit/components/TUIChat/emoji-config/index.mjs +1 -1
- package/es/components/Chat/ChatKit/components/TUIChat/index.vue2.mjs +1 -1
- package/es/components/Chat/ChatKit/components/TUIChat/message-input/message-input-quote/index.vue2.mjs +1 -1
- package/es/components/Chat/ChatKit/components/TUIChat/message-input-toolbar/emoji-picker/emoji-picker-dialog.vue2.mjs +1 -1
- package/es/components/Chat/ChatKit/components/TUIChat/message-input-toolbar/image-upload/index.vue2.mjs +1 -1
- package/es/components/Chat/ChatKit/components/TUIChat/message-input-toolbar/video-upload/index.vue2.mjs +1 -1
- package/es/components/Chat/ChatKit/components/TUIChat/message-list/index.vue2.mjs +2 -2
- package/es/components/Chat/ChatKit/components/TUIChat/message-list/message-elements/message-audio.vue2.mjs +1 -1
- package/es/components/Chat/ChatKit/components/TUIChat/message-list/message-elements/message-record/index.vue2.mjs +1 -1
- package/es/components/Chat/ChatKit/components/TUIChat/message-list/message-group-application/index.vue2.mjs +2 -2
- package/es/components/Chat/ChatKit/components/TUIChat/offlinePushInfoManager/offlinePushInfoManager.mjs +1 -1
- package/es/components/Chat/ChatKit/components/TUIChat/utils/sendMessage.mjs +1 -1
- package/es/components/Chat/ChatKit/components/common/BottomPopup/index.vue2.mjs +1 -1
- package/es/components/Chat/ChatKit/components/common/Dialog/index.vue2.mjs +1 -1
- package/es/components/Chat/ChatKit/components/common/Drawer/index.vue2.mjs +1 -1
- package/es/components/Chat/ChatKit/components/common/Icon.vue2.mjs +1 -1
- package/es/components/Chat/ChatKit/components/common/Overlay/index.vue2.mjs +1 -1
- package/es/components/Chat/ChatKit/components/common/Toast/index.mjs +1 -1
- package/es/components/Chat/ChatKit/components/common/Toast/index.vue2.mjs +1 -1
- package/es/components/Chat/ChatKit/components/common/Transfer/index.vue2.mjs +1 -1
- package/es/components/Chat/ChatKit/locales/index.mjs +4 -4
- package/es/components/Chat/ChatKit/plugins/plugin-components/message-plugin.vue2.mjs +1 -1
- package/es/components/ManageMember/MemberControl/index.vue.mjs +1 -1
- package/es/components/ManageMember/MemberControl/index.vue2.mjs +6 -4
- package/es/components/ManageMember/MemberControl/useMemberControlHooks.mjs +1 -1
- package/es/components/ManageMember/MemberItemCommon/MemberInfo.vue.mjs +1 -1
- package/es/components/ManageMember/index.vue2.mjs +1 -1
- package/es/components/PreRoom/PasswordDialog.vue2.mjs +1 -1
- package/es/components/RoomContent/StreamRegion/StreamPlay/index.vue2.mjs +1 -1
- package/es/components/RoomFooter/ApplyControl/MasterApplyControl/index.vue2.mjs +1 -1
- package/es/components/RoomFooter/ApplyControl/MemberApplyControl.vue2.mjs +1 -1
- package/es/components/RoomFooter/AudioControl.vue2.mjs +1 -1
- package/es/components/RoomFooter/BasicBeauty.vue.mjs +1 -1
- package/es/components/RoomFooter/BasicBeauty.vue2.mjs +5 -3
- package/es/components/RoomFooter/ChatControl.vue.mjs +2 -0
- package/es/components/RoomFooter/EndControl/index.vue2.mjs +1 -1
- package/es/components/RoomFooter/ScreenShareControl/Index.vue2.mjs +1 -1
- package/es/components/RoomFooter/ScreenShareControl/ScreenWindowSelectDialog.vue2.mjs +1 -1
- package/es/components/RoomFooter/VideoControl.vue2.mjs +2 -2
- package/es/components/RoomFooter/VirtualBackground.vue2.mjs +1 -1
- package/es/components/RoomFooter/WhiteboardControl.vue.mjs +1 -1
- package/es/components/RoomHeader/UserInfo/index.vue.mjs +1 -1
- package/es/components/RoomHeader/UserInfo/index.vue2.mjs +2 -1
- package/es/components/RoomHeader/index/LayoutControl.vue2.mjs +1 -1
- package/es/components/RoomHome/RoomControl/index.vue2.mjs +2 -2
- package/es/components/RoomInvite/InvitationNotification.vue2.mjs +1 -1
- package/es/components/RoomInvite/index.vue2.mjs +1 -1
- package/es/components/RoomSetting/index.vue2.mjs +1 -1
- package/es/components/ScheduleConference/Contacts.vue2.mjs +1 -1
- package/es/components/ScheduleConference/ScheduleConferencePanel/index.vue2.mjs +2 -2
- package/es/components/ScheduleConference/ScheduleRoomControl.vue2.mjs +2 -2
- package/es/components/ScheduleConference/ScheduleRoomList.vue2.mjs +1 -1
- package/es/components/ScheduleConference/ShareLink.vue2.mjs +1 -1
- package/es/components/common/VideoProfile.vue2.mjs +1 -1
- package/es/components/common/VideoSettingTab.vue2.mjs +2 -2
- package/es/components/common/base/Button.vue2.mjs +1 -1
- package/es/components/common/base/Dialog/index.vue2.mjs +1 -1
- package/es/components/common/base/Input/index.vue2.mjs +1 -1
- package/es/components/common/base/Message/Message.vue2.mjs +1 -1
- package/es/components/common/base/MessageBox/index.vue2.mjs +1 -1
- package/es/components/common/base/SvgIcon.vue2.mjs +1 -1
- package/es/constants/room.mjs +1 -3
- package/es/extension/RoomMessageCard/RoomMessageCard.vue2.mjs +1 -1
- package/es/extension/chatExtension.mjs +3 -6
- package/es/hooks/useDeviceManager.mjs +1 -1
- package/es/index.mjs +134 -126
- package/es/services/function/aiTask.d.ts +13 -17
- package/es/services/function/aiTask.mjs +63 -100
- package/es/services/manager/MediaManager.mjs +1 -1
- package/es/services/manager/dataReportManager.d.ts +4 -1
- package/es/services/manager/dataReportManager.mjs +3 -0
- package/es/services/manager/roomActionManager.mjs +1 -1
- package/es/services/roomService.mjs +1 -1
- package/es/stores/basic.mjs +1 -1
- package/es/stores/room.mjs +1 -4
- package/es/utils/common/logger/index.mjs +1 -1
- package/es/utils/utils.d.ts +2 -0
- package/es/utils/utils.mjs +33 -0
- package/lib/components/AITools/AISubtitles.vue.js +1 -1
- package/lib/components/AITools/AISubtitles.vue2.js +17 -18
- package/lib/components/AITools/AITranscription.vue.js +1 -1
- package/lib/components/AITools/AITranscription.vue2.js +64 -75
- package/lib/components/Chat/ChatKit/components/TUIChat/message-input/index.vue2.js +6 -6
- package/lib/components/Chat/ChatKit/components/TUIChat/message-list/index.vue2.js +8 -8
- package/lib/components/Chat/ChatKit/components/TUIChat/message-list/message-elements/message-quote/index.vue2.js +4 -4
- package/lib/components/Chat/ChatKit/components/TUIChat/message-list/message-tool/index.vue2.js +10 -10
- package/lib/components/Chat/ChatKit/locales/index.js +4 -4
- package/lib/components/ManageMember/MemberControl/index.vue.js +1 -1
- package/lib/components/ManageMember/MemberControl/index.vue2.js +5 -3
- package/lib/components/ManageMember/MemberItemCommon/MemberInfo.vue.js +1 -1
- package/lib/components/RoomContent/StreamContainer/index.vue2.js +6 -6
- package/lib/components/RoomFooter/AudioControl.vue2.js +4 -4
- package/lib/components/RoomFooter/BasicBeauty.vue.js +1 -1
- package/lib/components/RoomFooter/BasicBeauty.vue2.js +3 -1
- package/lib/components/RoomFooter/ChatControl.vue.js +2 -0
- package/lib/components/RoomFooter/ScreenShareControl/Index.vue2.js +5 -5
- package/lib/components/RoomFooter/VideoControl.vue2.js +4 -4
- package/lib/components/RoomHeader/UserInfo/index.vue.js +1 -1
- package/lib/components/RoomHeader/UserInfo/index.vue2.js +2 -1
- package/lib/components/ScheduleConference/ScheduleConferencePanel/index.vue2.js +1 -1
- package/lib/components/ScheduleConference/ScheduleRoomControl.vue2.js +1 -1
- package/lib/components/ScheduleConference/ScheduleRoomList.vue2.js +1 -1
- package/lib/conference.vue2.js +12 -12
- package/lib/constants/room.js +1 -3
- package/lib/extension/chatExtension.js +1 -4
- package/lib/hooks/useMasterApplyControl.js +9 -9
- package/lib/index.js +134 -126
- package/lib/preConference.vue2.js +7 -7
- package/lib/services/function/aiTask.d.ts +13 -17
- package/lib/services/function/aiTask.js +63 -100
- package/lib/services/manager/dataReportManager.d.ts +4 -1
- package/lib/services/manager/dataReportManager.js +3 -0
- package/lib/stores/room.js +0 -3
- package/lib/utils/utils.d.ts +2 -0
- package/lib/utils/utils.js +33 -0
- package/package.json +2 -2
- package/src/TUIRoom/components/AITools/AISubtitles.vue +26 -23
- package/src/TUIRoom/components/AITools/AITranscription.vue +106 -101
- package/src/TUIRoom/components/ManageMember/MemberControl/index.vue +8 -3
- package/src/TUIRoom/components/ManageMember/MemberItemCommon/MemberInfo.vue +1 -1
- package/src/TUIRoom/components/RoomFooter/BasicBeauty.vue +2 -1
- package/src/TUIRoom/components/RoomFooter/ChatControl.vue +2 -1
- package/src/TUIRoom/components/RoomHeader/UserInfo/index.vue +2 -5
- package/src/TUIRoom/services/function/aiTask.ts +79 -113
- package/src/TUIRoom/services/manager/dataReportManager.ts +3 -0
- package/src/TUIRoom/stores/room.ts +0 -3
- package/src/TUIRoom/utils/utils.ts +47 -0
|
@@ -1,141 +1,138 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div
|
|
2
|
+
<div
|
|
3
|
+
class="conversation"
|
|
4
|
+
ref="conversationContainerRef"
|
|
5
|
+
@scroll="handleScroll"
|
|
6
|
+
>
|
|
3
7
|
<div
|
|
4
|
-
v-for="
|
|
5
|
-
:key="
|
|
6
|
-
class="conversation-
|
|
8
|
+
v-for="group in transcribedMessageList"
|
|
9
|
+
:key="group.startMsTs"
|
|
10
|
+
class="conversation-group"
|
|
7
11
|
>
|
|
8
12
|
<div class="title">
|
|
9
|
-
<span class="speaker">{{
|
|
10
|
-
|
|
13
|
+
<span class="speaker">{{
|
|
14
|
+
roomService.roomStore.getDisplayName(group.sender)
|
|
15
|
+
}}</span>
|
|
16
|
+
<span class="timestamp">
|
|
17
|
+
{{ formatTimestampToTime(group.startMsTs) }}
|
|
18
|
+
</span>
|
|
11
19
|
</div>
|
|
12
|
-
<div
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
20
|
+
<div
|
|
21
|
+
v-for="(message, messageIndex) in group.messages"
|
|
22
|
+
:key="messageIndex"
|
|
23
|
+
class="content"
|
|
24
|
+
>
|
|
25
|
+
{{ message.text }}
|
|
16
26
|
</div>
|
|
17
27
|
</div>
|
|
18
28
|
</div>
|
|
19
29
|
</template>
|
|
20
30
|
|
|
21
31
|
<script setup lang="ts">
|
|
22
|
-
import { ref,
|
|
23
|
-
import {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
32
|
+
import { ref, onMounted, computed, nextTick, watch, onUnmounted } from 'vue';
|
|
33
|
+
import {
|
|
34
|
+
roomService,
|
|
35
|
+
AI_TASK,
|
|
36
|
+
SubtitleMessage,
|
|
37
|
+
MetricsKey,
|
|
38
|
+
} from '../../services';
|
|
39
|
+
import { formatTimestampToTime } from '../../utils/utils.ts';
|
|
40
|
+
|
|
41
|
+
const conversationContainerRef = ref<HTMLElement>();
|
|
42
|
+
const isUserScrolling = ref(false);
|
|
43
|
+
const timeInterval = 60 * 1000;
|
|
44
|
+
const rawTranscribedMessageList = ref<SubtitleMessage[]>(
|
|
45
|
+
roomService.aiTask.transcribedMessageList
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
onMounted(() => {
|
|
49
|
+
scrollToBottom();
|
|
50
|
+
});
|
|
36
51
|
|
|
37
52
|
const scrollToBottom = async () => {
|
|
38
|
-
if (
|
|
53
|
+
if (conversationContainerRef.value && !isUserScrolling.value) {
|
|
39
54
|
await nextTick();
|
|
40
|
-
|
|
55
|
+
conversationContainerRef.value.scrollTop =
|
|
56
|
+
conversationContainerRef.value.scrollHeight;
|
|
41
57
|
}
|
|
42
58
|
};
|
|
43
59
|
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
60
|
+
const handleScroll = () => {
|
|
61
|
+
if (conversationContainerRef.value) {
|
|
62
|
+
const isAtBottom =
|
|
63
|
+
conversationContainerRef.value.scrollTop +
|
|
64
|
+
conversationContainerRef.value.clientHeight >=
|
|
65
|
+
conversationContainerRef.value.scrollHeight - 5;
|
|
66
|
+
if (isAtBottom) {
|
|
67
|
+
isUserScrolling.value = false;
|
|
68
|
+
scrollToBottom();
|
|
69
|
+
} else {
|
|
70
|
+
isUserScrolling.value = true;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
};
|
|
49
74
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
75
|
+
const transcribedMessageList = computed(() => {
|
|
76
|
+
const aggregatedMessageList: {
|
|
77
|
+
sender: string;
|
|
78
|
+
startMsTs: number;
|
|
79
|
+
messages: SubtitleMessage[];
|
|
80
|
+
}[] = [];
|
|
81
|
+
let currentAggregatedMessage: {
|
|
82
|
+
sender: string;
|
|
83
|
+
startMsTs: number;
|
|
84
|
+
messages: SubtitleMessage[];
|
|
85
|
+
} | null = null;
|
|
53
86
|
|
|
87
|
+
for (const message of rawTranscribedMessageList.value) {
|
|
54
88
|
if (
|
|
55
|
-
|
|
56
|
-
|
|
89
|
+
!currentAggregatedMessage ||
|
|
90
|
+
message.sender !== currentAggregatedMessage.sender ||
|
|
91
|
+
message.startMsTs - currentAggregatedMessage.startMsTs > timeInterval
|
|
57
92
|
) {
|
|
58
|
-
|
|
59
|
-
|
|
93
|
+
currentAggregatedMessage = {
|
|
94
|
+
messages: [message],
|
|
95
|
+
sender: message.sender,
|
|
96
|
+
startMsTs: message.startMsTs,
|
|
97
|
+
};
|
|
98
|
+
aggregatedMessageList.push(currentAggregatedMessage);
|
|
60
99
|
} else {
|
|
61
|
-
|
|
62
|
-
if (currentSpeaker !== null) {
|
|
63
|
-
result.push({
|
|
64
|
-
timestamp: currentTimestamp,
|
|
65
|
-
speaker: currentSpeaker,
|
|
66
|
-
messages: currentMessages,
|
|
67
|
-
});
|
|
68
|
-
}
|
|
69
|
-
// Update active speaker, timestamp, and message
|
|
70
|
-
currentSpeaker = item.speaker;
|
|
71
|
-
currentTimestamp = timestampMinute;
|
|
72
|
-
currentMessages = [item.content];
|
|
100
|
+
currentAggregatedMessage.messages.push(message);
|
|
73
101
|
}
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
// Save the last set of aggregation results
|
|
77
|
-
if (currentSpeaker !== null) {
|
|
78
|
-
result.push({
|
|
79
|
-
timestamp: currentTimestamp,
|
|
80
|
-
speaker: currentSpeaker,
|
|
81
|
-
messages: currentMessages,
|
|
82
|
-
});
|
|
83
102
|
}
|
|
84
103
|
|
|
85
|
-
return
|
|
104
|
+
return aggregatedMessageList;
|
|
86
105
|
});
|
|
87
106
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
processedConversations.value = processConversation(
|
|
91
|
-
data.transcriptionText.value
|
|
92
|
-
);
|
|
107
|
+
watch(rawTranscribedMessageList, () => {
|
|
108
|
+
scrollToBottom();
|
|
93
109
|
});
|
|
94
110
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
if (match) {
|
|
110
|
-
const timestamp = match[1];
|
|
111
|
-
const speaker = match[2];
|
|
112
|
-
const content = match[3];
|
|
113
|
-
conversations.push({
|
|
114
|
-
timestamp,
|
|
115
|
-
speaker,
|
|
116
|
-
content,
|
|
117
|
-
});
|
|
118
|
-
}
|
|
119
|
-
});
|
|
120
|
-
|
|
121
|
-
conversations.sort((a, b) => {
|
|
122
|
-
const timeA = a.timestamp.split('->')[0];
|
|
123
|
-
const timeB = b.timestamp.split('->')[0];
|
|
124
|
-
return timeA.localeCompare(timeB);
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
return conversations;
|
|
128
|
-
}
|
|
111
|
+
const handleAITranscriptionTask = async (data?: {
|
|
112
|
+
subtitleMessages: { [key: string]: SubtitleMessage };
|
|
113
|
+
transcribedMessageList: SubtitleMessage[];
|
|
114
|
+
}) => {
|
|
115
|
+
if (!data) return;
|
|
116
|
+
rawTranscribedMessageList.value = [...data.transcribedMessageList];
|
|
117
|
+
};
|
|
118
|
+
onMounted(() => {
|
|
119
|
+
roomService.dataReportManager.reportCount(MetricsKey.aiTask);
|
|
120
|
+
roomService.aiTask.on(AI_TASK.TRANSCRIPTION_TASK, handleAITranscriptionTask);
|
|
121
|
+
});
|
|
122
|
+
onUnmounted(() => {
|
|
123
|
+
roomService.aiTask.off(AI_TASK.TRANSCRIPTION_TASK, handleAITranscriptionTask);
|
|
124
|
+
});
|
|
129
125
|
</script>
|
|
130
126
|
|
|
131
127
|
<style scoped lang="scss">
|
|
132
128
|
.conversation {
|
|
129
|
+
height: 100%;
|
|
133
130
|
padding: 20px;
|
|
134
131
|
overflow-y: auto;
|
|
135
132
|
}
|
|
136
133
|
|
|
137
|
-
.conversation-
|
|
138
|
-
margin-bottom:
|
|
134
|
+
.conversation-group {
|
|
135
|
+
margin-bottom: 20px;
|
|
139
136
|
}
|
|
140
137
|
|
|
141
138
|
.title {
|
|
@@ -147,10 +144,18 @@ function processConversation(data: string) {
|
|
|
147
144
|
line-height: 22px;
|
|
148
145
|
color: var(--font-color-4);
|
|
149
146
|
text-align: left;
|
|
147
|
+
|
|
148
|
+
.speaker {
|
|
149
|
+
max-width: 150px;
|
|
150
|
+
overflow: hidden;
|
|
151
|
+
text-overflow: ellipsis;
|
|
152
|
+
white-space: nowrap;
|
|
153
|
+
}
|
|
150
154
|
}
|
|
151
155
|
|
|
152
156
|
.content {
|
|
153
157
|
padding: 8px;
|
|
158
|
+
margin-top: 5px;
|
|
154
159
|
font-size: 14px;
|
|
155
160
|
font-weight: 400;
|
|
156
161
|
line-height: 22px;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div class="member-control-container">
|
|
3
3
|
<tui-button
|
|
4
|
+
v-if="singleControl"
|
|
4
5
|
class="button"
|
|
5
6
|
size="default"
|
|
6
7
|
@click="singleControl.func(props.userInfo)"
|
|
7
|
-
v-if="!isCanOperateMySelf"
|
|
8
8
|
>
|
|
9
9
|
{{ singleControl?.title }}
|
|
10
10
|
</tui-button>
|
|
@@ -105,9 +105,14 @@ const {
|
|
|
105
105
|
|
|
106
106
|
const { isCanOperateMySelf } = useMemberItemHooks(props.userInfo);
|
|
107
107
|
|
|
108
|
-
const singleControl = computed(() =>
|
|
108
|
+
const singleControl = computed(() => {
|
|
109
|
+
return isCanOperateMySelf.value ? null : controlList.value[0];
|
|
110
|
+
});
|
|
111
|
+
|
|
109
112
|
const moreControlList = computed(() => {
|
|
110
|
-
return isCanOperateMySelf
|
|
113
|
+
return isCanOperateMySelf.value
|
|
114
|
+
? controlList.value
|
|
115
|
+
: controlList.value.slice(1);
|
|
111
116
|
});
|
|
112
117
|
const dropdownClass = ref('down');
|
|
113
118
|
const moreBtnRef = ref();
|
|
@@ -108,7 +108,7 @@ import IconButton from '../common/base/IconButton.vue';
|
|
|
108
108
|
import SvgIcon from '../common/base/SvgIcon.vue';
|
|
109
109
|
import BasicBeautyIcon from '../common/icons/BasicBeautyIcon.vue';
|
|
110
110
|
import { useI18n } from '../../locales';
|
|
111
|
-
import { roomService } from '../../services';
|
|
111
|
+
import { roomService, MetricsKey } from '../../services';
|
|
112
112
|
import Dialog from '../common/base/Dialog/index.vue';
|
|
113
113
|
import TuiButton from '../common/base/Button.vue';
|
|
114
114
|
import Slider from '../common/base/Slider.vue';
|
|
@@ -197,6 +197,7 @@ const openBeautySettingPanel = async () => {
|
|
|
197
197
|
view: 'test-preview',
|
|
198
198
|
});
|
|
199
199
|
isLoading.value = false;
|
|
200
|
+
roomService.dataReportManager.reportCount(MetricsKey.setBasicBeauty);
|
|
200
201
|
};
|
|
201
202
|
|
|
202
203
|
const closeBeautySettingPanel = async () => {
|
|
@@ -23,7 +23,7 @@ import { useChatStore } from '../../stores/chat';
|
|
|
23
23
|
import { storeToRefs } from 'pinia';
|
|
24
24
|
import { useI18n } from '../../locales';
|
|
25
25
|
import TuiBadge from '../common/base/Badge.vue';
|
|
26
|
-
import { roomService } from '../../services';
|
|
26
|
+
import { roomService, MetricsKey } from '../../services';
|
|
27
27
|
const { t } = useI18n();
|
|
28
28
|
const chatControlConfig = roomService.getComponentConfig('ChatControl');
|
|
29
29
|
const basicStore = useBasicStore();
|
|
@@ -39,5 +39,6 @@ async function toggleChatSidebar() {
|
|
|
39
39
|
basicStore.setSidebarOpenStatus(true);
|
|
40
40
|
basicStore.setSidebarName('chat');
|
|
41
41
|
chatStore.updateUnReadCount(0);
|
|
42
|
+
roomService.dataReportManager.reportCount(MetricsKey.openChat);
|
|
42
43
|
}
|
|
43
44
|
</script>
|
|
@@ -97,11 +97,8 @@ const props = defineProps<{
|
|
|
97
97
|
isShowEditName?: boolean;
|
|
98
98
|
}>();
|
|
99
99
|
|
|
100
|
-
/**
|
|
101
|
-
* Save the new userName
|
|
102
|
-
*
|
|
103
|
-
**/
|
|
104
100
|
async function saveUserName(userName: string) {
|
|
101
|
+
const { userId } = props;
|
|
105
102
|
if (userName.length === 0) {
|
|
106
103
|
TUIMessage({
|
|
107
104
|
type: 'warning',
|
|
@@ -115,7 +112,7 @@ async function saveUserName(userName: string) {
|
|
|
115
112
|
avatarUrl: roomStore.localUser.avatarUrl || '',
|
|
116
113
|
});
|
|
117
114
|
basicStore.setUserName(userName);
|
|
118
|
-
roomStore.
|
|
115
|
+
roomStore.updateUserInfo({ userId, userName });
|
|
119
116
|
emits('update-user-name', userName);
|
|
120
117
|
closeUserNameEditor();
|
|
121
118
|
}
|
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
import { IRoomService } from '../';
|
|
2
2
|
import mitt from 'mitt';
|
|
3
3
|
import { isElectron, isMobile } from '../../utils/environment';
|
|
4
|
+
import { findLastIndex } from '../../utils/utils';
|
|
4
5
|
|
|
5
|
-
interface SubtitleMessage {
|
|
6
|
-
|
|
6
|
+
export interface SubtitleMessage {
|
|
7
|
+
sender: string;
|
|
7
8
|
text: string;
|
|
8
|
-
|
|
9
|
+
translationText: string;
|
|
10
|
+
end?: boolean;
|
|
11
|
+
startMsTs: number;
|
|
9
12
|
}
|
|
13
|
+
|
|
10
14
|
interface DataPayload {
|
|
11
15
|
end: boolean;
|
|
12
16
|
text: string;
|
|
@@ -34,22 +38,23 @@ export enum AI_TASK {
|
|
|
34
38
|
|
|
35
39
|
export interface AITaskEvent {
|
|
36
40
|
[AI_TASK.TRANSCRIPTION_TASK]: {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
transcriptionText: { value: string };
|
|
41
|
+
subtitleMessages: { [key: string]: SubtitleMessage };
|
|
42
|
+
transcribedMessageList: SubtitleMessage[];
|
|
40
43
|
};
|
|
41
44
|
[key: string]: unknown;
|
|
42
45
|
[key: symbol]: unknown;
|
|
43
46
|
}
|
|
44
47
|
|
|
48
|
+
const ASR_EVENT_CODE = 10000;
|
|
49
|
+
|
|
45
50
|
export class AITask {
|
|
46
51
|
private emitter = mitt<AITaskEvent>();
|
|
47
|
-
|
|
48
52
|
private trtc: any;
|
|
49
53
|
private service: IRoomService;
|
|
50
|
-
public
|
|
51
|
-
public
|
|
52
|
-
|
|
54
|
+
public subtitleMessages: { [key: string]: SubtitleMessage } = {};
|
|
55
|
+
public transcribedMessageList: SubtitleMessage[] = [];
|
|
56
|
+
private subtitleTimeout: { [key: string]: ReturnType<typeof setTimeout> } =
|
|
57
|
+
{};
|
|
53
58
|
|
|
54
59
|
constructor(service: IRoomService) {
|
|
55
60
|
this.service = service;
|
|
@@ -95,14 +100,13 @@ export class AITask {
|
|
|
95
100
|
) {
|
|
96
101
|
return;
|
|
97
102
|
}
|
|
98
|
-
|
|
99
|
-
this.trtc
|
|
100
|
-
trtc.on('custom-message', this.handleAIMessage);
|
|
103
|
+
this.trtc = this.service.roomEngine.instance?.getTRTCCloud()._trtc;
|
|
104
|
+
this.trtc.on('custom-message', this.handleAIMessage);
|
|
101
105
|
}
|
|
106
|
+
|
|
102
107
|
private handleUnmount() {
|
|
103
|
-
this.
|
|
104
|
-
this.
|
|
105
|
-
this.transcriptionText.value = '';
|
|
108
|
+
this.subtitleMessages = {};
|
|
109
|
+
this.transcribedMessageList = [];
|
|
106
110
|
this.trtc?.off('custom-message', this.handleAIMessage);
|
|
107
111
|
}
|
|
108
112
|
|
|
@@ -111,122 +115,84 @@ export class AITask {
|
|
|
111
115
|
this.service.lifeCycleManager.on('unmount', this.handleUnmount);
|
|
112
116
|
}
|
|
113
117
|
|
|
114
|
-
|
|
118
|
+
private resetSubtitleTimeout(id: string, fn: () => void) {
|
|
119
|
+
if (this.subtitleTimeout[id]) {
|
|
120
|
+
clearTimeout(this.subtitleTimeout[id]);
|
|
121
|
+
}
|
|
122
|
+
this.subtitleTimeout[id] = setTimeout(fn, 3000);
|
|
123
|
+
}
|
|
124
|
+
|
|
115
125
|
private handleAIMessage(event: any) {
|
|
116
126
|
if (event.cmdId !== 1) return;
|
|
117
127
|
const data = new TextDecoder().decode(event.data);
|
|
118
128
|
const jsonData = JSON.parse(data);
|
|
119
129
|
this.handleMessage(jsonData);
|
|
120
130
|
this.emit(AI_TASK.TRANSCRIPTION_TASK, {
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
subtitleMsg: this.subtitleMsg,
|
|
131
|
+
subtitleMessages: this.subtitleMessages,
|
|
132
|
+
transcribedMessageList: this.transcribedMessageList,
|
|
124
133
|
});
|
|
125
134
|
}
|
|
126
135
|
|
|
127
136
|
private handleMessage(data: MessageData): void {
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
+
if (data.type !== ASR_EVENT_CODE) return;
|
|
138
|
+
const { sender, payload } = data;
|
|
139
|
+
const { end } = payload;
|
|
140
|
+
|
|
141
|
+
const createSubtitleMsg = () => {
|
|
142
|
+
return {
|
|
143
|
+
sender,
|
|
144
|
+
text: payload.text,
|
|
145
|
+
translationText: payload.translation_text,
|
|
146
|
+
startMsTs: data.start_ms_ts,
|
|
147
|
+
end,
|
|
148
|
+
};
|
|
137
149
|
};
|
|
138
150
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
this.subtitleMsg[i].text = data.payload.text;
|
|
145
|
-
this.subtitleMsg[i].translation_text = data.payload.translation_text;
|
|
146
|
-
exist = true;
|
|
147
|
-
break;
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
if (!exist) {
|
|
151
|
-
this.subtitleMsg.push({
|
|
152
|
-
userid: data.sender,
|
|
153
|
-
text: data.payload.text,
|
|
154
|
-
translation_text: data.payload.translation_text,
|
|
155
|
-
});
|
|
156
|
-
}
|
|
151
|
+
const updateMsg = (msg: SubtitleMessage) => {
|
|
152
|
+
msg.text = payload.text;
|
|
153
|
+
msg.translationText = payload.translation_text;
|
|
154
|
+
msg.end = end;
|
|
155
|
+
};
|
|
157
156
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
157
|
+
const appendMsg = <T extends SubtitleMessage>(
|
|
158
|
+
msg: T,
|
|
159
|
+
target: T[] | Record<string, T>
|
|
160
|
+
) => {
|
|
161
|
+
if (Array.isArray(target)) {
|
|
162
|
+
target.push(msg);
|
|
163
|
+
} else if (typeof target === 'object') {
|
|
164
|
+
const recordTarget = target as Record<string, T>;
|
|
165
|
+
recordTarget[msg.sender] = msg;
|
|
166
|
+
} else {
|
|
167
|
+
throw new Error('Invalid target type');
|
|
169
168
|
}
|
|
170
|
-
|
|
171
|
-
// todo start_ms_ts end_ms_ts
|
|
169
|
+
};
|
|
172
170
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
this.
|
|
171
|
+
const existingSubtitle = this.subtitleMessages[sender];
|
|
172
|
+
if (existingSubtitle) {
|
|
173
|
+
updateMsg(existingSubtitle);
|
|
174
|
+
} else {
|
|
175
|
+
appendMsg(createSubtitleMsg(), this.subtitleMessages);
|
|
178
176
|
}
|
|
179
177
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
if (data.userid === this.subtitleMsg[i].userid) {
|
|
185
|
-
this.subtitleMsg[i].text = data.text;
|
|
186
|
-
this.subtitleMsg[i].translation_text = data.translation_text;
|
|
187
|
-
exist = true;
|
|
188
|
-
break;
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
if (!exist) {
|
|
192
|
-
this.subtitleMsg.push({
|
|
193
|
-
userid: data.userid,
|
|
194
|
-
text: data.text,
|
|
195
|
-
translation_text: data.translation_text,
|
|
196
|
-
});
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
refreshSubtitle();
|
|
200
|
-
} else if (data.type === 'transcription') {
|
|
201
|
-
let index = 0;
|
|
202
|
-
for (let i = 0; i < this.subtitleMsg.length; i++) {
|
|
203
|
-
if (data.userid === this.subtitleMsg[i].userid) {
|
|
204
|
-
this.subtitleMsg[i].text = data.text;
|
|
205
|
-
this.subtitleMsg[i].translation_text = data.translation_text;
|
|
206
|
-
index = i;
|
|
207
|
-
break;
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
refreshSubtitle();
|
|
178
|
+
const transcriptionIndex = findLastIndex(
|
|
179
|
+
this.transcribedMessageList,
|
|
180
|
+
msg => msg.sender === sender && !msg.end
|
|
181
|
+
);
|
|
211
182
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
this.transcriptionText.value += content;
|
|
183
|
+
if (transcriptionIndex !== -1) {
|
|
184
|
+
updateMsg(this.transcribedMessageList[transcriptionIndex]);
|
|
185
|
+
} else {
|
|
186
|
+
appendMsg(createSubtitleMsg(), this.transcribedMessageList);
|
|
217
187
|
}
|
|
218
|
-
}
|
|
219
188
|
|
|
220
|
-
|
|
221
|
-
|
|
189
|
+
this.resetSubtitleTimeout(sender, () => {
|
|
190
|
+
if (!end) return;
|
|
191
|
+
delete this.subtitleMessages[sender];
|
|
192
|
+
this.emit(AI_TASK.TRANSCRIPTION_TASK, {
|
|
193
|
+
subtitleMessages: this.subtitleMessages,
|
|
194
|
+
transcribedMessageList: this.transcribedMessageList,
|
|
195
|
+
});
|
|
196
|
+
});
|
|
222
197
|
}
|
|
223
198
|
}
|
|
224
|
-
|
|
225
|
-
// utils
|
|
226
|
-
function formatTimestampToTime(timestamp: number): string {
|
|
227
|
-
const date = new Date(timestamp);
|
|
228
|
-
const hours = date.getHours().toString().padStart(2, '0');
|
|
229
|
-
const minutes = date.getMinutes().toString().padStart(2, '0');
|
|
230
|
-
const seconds = date.getSeconds().toString().padStart(2, '0');
|
|
231
|
-
return `${hours}:${minutes}:${seconds}`;
|
|
232
|
-
}
|
|
@@ -530,9 +530,6 @@ export const useRoomStore = defineStore('room', {
|
|
|
530
530
|
updateVideoQuality(quality: TUIVideoQuality) {
|
|
531
531
|
this.localVideoQuality = quality;
|
|
532
532
|
},
|
|
533
|
-
setLocalUser(obj: Record<string, any>) {
|
|
534
|
-
Object.assign(this.localUser, obj);
|
|
535
|
-
},
|
|
536
533
|
setDeviceList(
|
|
537
534
|
type: TUIMediaDeviceType,
|
|
538
535
|
deviceList: { deviceId: string; deviceName: string }[]
|