@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
|
@@ -22,20 +22,20 @@ import TuiGlobal from '../TUIGlobal/tuiGlobal';
|
|
|
22
22
|
import TuiStore from '../TUIStore/tuiStore';
|
|
23
23
|
import { UIDesign } from './UIDesign';
|
|
24
24
|
import ChatCombine from './chatCombine';
|
|
25
|
-
import { AIAssistant } from './AIAssistant';
|
|
26
25
|
import EngineEventHandler from './engineEventHandler';
|
|
27
26
|
const TUIGlobal: ITUIGlobal = TuiGlobal.getInstance();
|
|
28
27
|
const TUIStore: ITUIStore = TuiStore.getInstance();
|
|
29
28
|
const uiDesign = UIDesign.getInstance();
|
|
30
29
|
uiDesign.setTUIStore(TUIStore);
|
|
31
|
-
const
|
|
32
|
-
|
|
30
|
+
const version = '4.4.5';
|
|
31
|
+
import AIAssistant from './AIAssistant'; // 仅 web 支持 AI 实时字幕
|
|
33
32
|
const frameWork = 'vue3';
|
|
34
33
|
export { TUIGlobal, TUIStore, uiDesign };
|
|
35
34
|
|
|
36
35
|
export default class TUICallService {
|
|
37
36
|
static instance: TUICallService;
|
|
38
37
|
public _tuiCallEngine: any;
|
|
38
|
+
public _aiAssistant: any = null;
|
|
39
39
|
private _tim: any = null;
|
|
40
40
|
private _TUICore: any = null;
|
|
41
41
|
private _timerId: number = -1;
|
|
@@ -62,6 +62,7 @@ export default class TUICallService {
|
|
|
62
62
|
this._engineEventHandler = EngineEventHandler.getInstance({ callService: this });
|
|
63
63
|
|
|
64
64
|
this._chatCombine = ChatCombine.getInstance({ callService: this });
|
|
65
|
+
this._aiAssistant = AIAssistant.getInstance({ callService: this });
|
|
65
66
|
initBrowserCloseDetection(this.handleExceptionExit.bind(this));
|
|
66
67
|
}
|
|
67
68
|
static getInstance() {
|
|
@@ -115,15 +116,15 @@ export default class TUICallService {
|
|
|
115
116
|
});
|
|
116
117
|
uiDesign.setEngineInstance(this._tuiCallEngine);
|
|
117
118
|
this._addListenTuiCallEngineEvent();
|
|
118
|
-
this._bellContext
|
|
119
|
+
if (this._bellContext) {
|
|
120
|
+
this._bellContext?.destroy();
|
|
121
|
+
}
|
|
122
|
+
this._bellContext = new BellContext();
|
|
119
123
|
TUIStore.update(StoreName.CALL, NAME.LOCAL_USER_INFO, { userId: userID });
|
|
120
124
|
TUIStore.update(StoreName.CALL, NAME.LOCAL_USER_INFO_EXCLUDE_VOLUMN, { userId: userID });
|
|
121
125
|
uiDesign.updateViewBackgroundUserId('local');
|
|
122
|
-
|
|
123
|
-
aiAssistant.setEngineInstance(this._tuiCallEngine);
|
|
124
|
-
aiAssistant.setImInstance(this.getTim());
|
|
126
|
+
this._aiAssistant?.bindEvent();
|
|
125
127
|
|
|
126
|
-
this.enableAISubtitle(true);
|
|
127
128
|
await this._tuiCallEngine.login({ userID, userSig, assetsPath: '' }); // web && mini
|
|
128
129
|
const uiConfig = TUIStore.getData(StoreName.CALL, NAME.CUSTOM_UI_CONFIG);
|
|
129
130
|
// close auto play dialog
|
|
@@ -155,6 +156,8 @@ export default class TUICallService {
|
|
|
155
156
|
await this._tuiCallEngine.destroyInstance();
|
|
156
157
|
this._tuiCallEngine = null;
|
|
157
158
|
}
|
|
159
|
+
this._aiAssistant?.unbindEvent();
|
|
160
|
+
this._aiAssistant?.reset();
|
|
158
161
|
this._bellContext?.destroy();
|
|
159
162
|
this._bellContext = null;
|
|
160
163
|
} catch (error) {
|
|
@@ -187,6 +190,7 @@ export default class TUICallService {
|
|
|
187
190
|
public async calls(callsParams: ICallsParams) {
|
|
188
191
|
if (TUIStore.getData(StoreName.CALL, NAME.CALL_STATUS) !== CallStatus.IDLE) return; // avoid double click when application stuck
|
|
189
192
|
try {
|
|
193
|
+
TUIStore.update(StoreName.CALL, NAME.PUSHER_ID, NAME.NEW_PUSHER);
|
|
190
194
|
const { userIDList, type, chatGroupID, offlinePushInfo } = callsParams;
|
|
191
195
|
if (TUIStore.getData(StoreName.CALL, NAME.CALL_STATUS) !== CallStatus.IDLE) return;
|
|
192
196
|
const remoteUserInfoList = userIDList.map(userId => ({ userId }));
|
|
@@ -204,10 +208,7 @@ export default class TUICallService {
|
|
|
204
208
|
public async join(params) {
|
|
205
209
|
if (TUIStore.getData(StoreName.CALL, NAME.CALL_STATUS) === CallStatus.CONNECTED) return; // avoid double click when application stuck
|
|
206
210
|
try {
|
|
207
|
-
|
|
208
|
-
TUIStore.update(StoreName.CALL, NAME.IS_CLICKABLE, true);
|
|
209
|
-
this.startTimer();
|
|
210
|
-
|
|
211
|
+
TUIStore.update(StoreName.CALL, NAME.PUSHER_ID, NAME.NEW_PUSHER);
|
|
211
212
|
const updateStoreParams = {
|
|
212
213
|
[NAME.CALL_ROLE]: CallRole.CALLEE,
|
|
213
214
|
[NAME.IS_GROUP]: true,
|
|
@@ -216,6 +217,10 @@ export default class TUICallService {
|
|
|
216
217
|
};
|
|
217
218
|
TUIStore.updateStore(updateStoreParams, StoreName.CALL);
|
|
218
219
|
|
|
220
|
+
const response = await this._tuiCallEngine.join(params);
|
|
221
|
+
TUIStore.update(StoreName.CALL, NAME.IS_CLICKABLE, true);
|
|
222
|
+
this.startTimer();
|
|
223
|
+
|
|
219
224
|
updateDeviceList(this._tuiCallEngine);;
|
|
220
225
|
await this._tuiCallEngine.setVideoQuality(TUIStore.getData(StoreName.CALL, NAME.VIDEO_RESOLUTION));
|
|
221
226
|
const localUserInfo = TUIStore.getData(StoreName.CALL, NAME.LOCAL_USER_INFO);
|
|
@@ -271,6 +276,16 @@ export default class TUICallService {
|
|
|
271
276
|
throw error;
|
|
272
277
|
}
|
|
273
278
|
}
|
|
279
|
+
public async enableAITranscriber(enable: boolean) {
|
|
280
|
+
try {
|
|
281
|
+
// Update store to control UI translation switch and translation area visibility
|
|
282
|
+
TUIStore.update(StoreName.CALL, NAME.IS_AI_TRANSCRIBER_ENABLED, enable);
|
|
283
|
+
console.log(`${NAME.PREFIX}enableAITranscriber: ${enable}.`);
|
|
284
|
+
} catch (error: any) {
|
|
285
|
+
console.error(`${NAME.PREFIX}enableAITranscriber failed, error: ${error}.`);
|
|
286
|
+
throw error;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
274
289
|
// 修改默认铃声:只支持本地铃声文件,不支持在线铃声文件;修改铃声修改的是被叫的铃声
|
|
275
290
|
public async setCallingBell(filePath?: string) {
|
|
276
291
|
let isCheckFileExist: boolean = true;
|
|
@@ -306,9 +321,7 @@ export default class TUICallService {
|
|
|
306
321
|
public setCameraDefaultState(isOpen: boolean) {
|
|
307
322
|
uiDesign.setCameraDefaultState(isOpen);
|
|
308
323
|
}
|
|
309
|
-
|
|
310
|
-
aiAssistant.enableAISubtitle(enable);
|
|
311
|
-
}
|
|
324
|
+
// AI Subtitle functionality removed, focusing on real-time transcriber
|
|
312
325
|
// =============================【实验性接口】=============================
|
|
313
326
|
public callExperimentalAPI(jsonStr: string) {
|
|
314
327
|
const jsonObj = JSON.parse(jsonStr);
|
|
@@ -343,19 +356,7 @@ export default class TUICallService {
|
|
|
343
356
|
TUIStore.update(StoreName.CALL, NAME.CALL_STATUS, CallStatus.CONNECTED);
|
|
344
357
|
updateDeviceList(this._tuiCallEngine);;
|
|
345
358
|
const response = await this._tuiCallEngine.accept();
|
|
346
|
-
|
|
347
|
-
this._chatCombine?.callTUIService({ message: response?.data?.message });
|
|
348
|
-
TUIStore.update(StoreName.CALL, NAME.IS_CLICKABLE, true);
|
|
349
|
-
this.startTimer();
|
|
350
|
-
const callMediaType = TUIStore.getData(StoreName.CALL, NAME.CALL_MEDIA_TYPE);
|
|
351
|
-
const isCameraDefaultStateClose = this._getFeatureButtonDefaultState(FeatureButton.Camera) === ButtonState.Close;
|
|
352
|
-
(callMediaType === CallMediaType.VIDEO) && !isCameraDefaultStateClose && await this.openCamera(NAME.LOCAL_VIDEO);
|
|
353
|
-
await this._tuiCallEngine.setVideoQuality(TUIStore.getData(StoreName.CALL, NAME.VIDEO_RESOLUTION));
|
|
354
|
-
const localUserInfo = TUIStore.getData(StoreName.CALL, NAME.LOCAL_USER_INFO);
|
|
355
|
-
TUIStore.update(StoreName.CALL, NAME.LOCAL_USER_INFO, { ...localUserInfo, isEnter: true });
|
|
356
|
-
TUIStore.update(StoreName.CALL, NAME.LOCAL_USER_INFO_EXCLUDE_VOLUMN, { ...localUserInfo, isEnter: true });
|
|
357
|
-
setLocalUserInfoAudioVideoAvailable(true, NAME.AUDIO); // web && mini default open audio
|
|
358
|
-
}
|
|
359
|
+
await this._handleAcceptResponse(response);
|
|
359
360
|
} catch (error) {
|
|
360
361
|
this._tuiCallEngine?.reportLog?.({
|
|
361
362
|
name: 'TUICallKit.accept.fail',
|
|
@@ -368,6 +369,21 @@ export default class TUICallService {
|
|
|
368
369
|
this._resetCallStore();
|
|
369
370
|
}
|
|
370
371
|
}
|
|
372
|
+
private async _handleAcceptResponse(response) {
|
|
373
|
+
if (response) {
|
|
374
|
+
this._chatCombine?.callTUIService({ message: response?.data?.message });
|
|
375
|
+
TUIStore.update(StoreName.CALL, NAME.IS_CLICKABLE, true);
|
|
376
|
+
this.startTimer();
|
|
377
|
+
const callMediaType = TUIStore.getData(StoreName.CALL, NAME.CALL_MEDIA_TYPE);
|
|
378
|
+
const isCameraDefaultStateClose = this._getFeatureButtonDefaultState(FeatureButton.Camera) === ButtonState.Close;
|
|
379
|
+
(callMediaType === CallMediaType.VIDEO) && !isCameraDefaultStateClose && await this.openCamera(NAME.LOCAL_VIDEO);
|
|
380
|
+
await this._tuiCallEngine.setVideoQuality(TUIStore.getData(StoreName.CALL, NAME.VIDEO_RESOLUTION));
|
|
381
|
+
const localUserInfo = TUIStore.getData(StoreName.CALL, NAME.LOCAL_USER_INFO);
|
|
382
|
+
TUIStore.update(StoreName.CALL, NAME.LOCAL_USER_INFO, { ...localUserInfo, isEnter: true });
|
|
383
|
+
TUIStore.update(StoreName.CALL, NAME.LOCAL_USER_INFO_EXCLUDE_VOLUMN, { ...localUserInfo, isEnter: true });
|
|
384
|
+
setLocalUserInfoAudioVideoAvailable(true, NAME.AUDIO); // web && mini default open audio
|
|
385
|
+
}
|
|
386
|
+
}
|
|
371
387
|
@avoidRepeatedCall()
|
|
372
388
|
public async hangup() {
|
|
373
389
|
if (TUIStore.getData(StoreName.CALL, NAME.CALL_STATUS) === CallStatus.IDLE) return; // avoid double click when application stuck
|
|
@@ -696,21 +712,29 @@ export default class TUICallService {
|
|
|
696
712
|
}
|
|
697
713
|
}
|
|
698
714
|
// clear all use avoidRepeatCall decorator state
|
|
699
|
-
private
|
|
700
|
-
this._tuiCallEngine?.reportLog?.({ name: 'TUICallkit.
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
(this as any)
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
715
|
+
private _cleanupAvoidRepeatCallState(methodName?: string) {
|
|
716
|
+
this._tuiCallEngine?.reportLog?.({ name: 'TUICallkit._cleanupAvoidRepeatCallState', data: { methodName } });
|
|
717
|
+
let methodsToClean = [];
|
|
718
|
+
if (methodName) {
|
|
719
|
+
methodsToClean = [(this as any)[methodName]];
|
|
720
|
+
} else {
|
|
721
|
+
methodsToClean = [
|
|
722
|
+
(this as any).calls,
|
|
723
|
+
(this as any).accept,
|
|
724
|
+
(this as any).hangup,
|
|
725
|
+
(this as any).reject,
|
|
726
|
+
(this as any).join,
|
|
727
|
+
(this as any).inviteUser,
|
|
728
|
+
];
|
|
729
|
+
}
|
|
707
730
|
|
|
708
|
-
methodsToClean
|
|
731
|
+
methodsToClean?.forEach(method => {
|
|
709
732
|
method?.clearCallState?.(this);
|
|
710
733
|
});
|
|
711
734
|
}
|
|
712
735
|
private _resetCallStore() {
|
|
713
|
-
this.
|
|
736
|
+
this._cleanupAvoidRepeatCallState();
|
|
737
|
+
this._bellContext?.stop();
|
|
714
738
|
|
|
715
739
|
const oldStatusStr = generateStatusChangeText();
|
|
716
740
|
this._stopTimer();
|
|
@@ -729,6 +753,7 @@ export default class TUICallService {
|
|
|
729
753
|
case NAME.ENABLE_FLOAT_WINDOW:
|
|
730
754
|
case NAME.LOCAL_USER_INFO:
|
|
731
755
|
case NAME.IS_SHOW_ENABLE_VIRTUAL_BACKGROUND:
|
|
756
|
+
case NAME.IS_AI_TRANSCRIBER_ENABLED:
|
|
732
757
|
case NAME.IS_FORCE_USE_V2_API:
|
|
733
758
|
case NAME.LOCAL_USER_INFO_EXCLUDE_VOLUMN: {
|
|
734
759
|
return false;
|
|
@@ -744,6 +769,7 @@ export default class TUICallService {
|
|
|
744
769
|
callStatus !== CallStatus.IDLE && TUIStore.reset(StoreName.CALL, [NAME.CALL_STATUS], true); // callStatus reset need notify
|
|
745
770
|
TUIStore.reset(StoreName.CALL, [NAME.IS_MINIMIZED], true); // isMinimized reset need notify
|
|
746
771
|
TUIStore.reset(StoreName.CALL, [NAME.IS_EAR_PHONE], true); // isEarPhone reset need notify
|
|
772
|
+
TUIStore.reset(StoreName.CALL, [NAME.PUSHER_ID], true); // pusher unload reset need notify
|
|
747
773
|
TUIStore.reset(StoreName.CALL, [NAME.ENABLE_VIRTUAL_BACKGROUND], true); // ENABLE_VIRTUAL_BACKGROUND reset need notify
|
|
748
774
|
TUIStore.reset(StoreName.CALL, [NAME.IS_MUTE_SPEAKER], true); // IS_MUTE_SPEAKER reset need notify
|
|
749
775
|
TUIStore.update(StoreName.CALL, NAME.LOCAL_USER_INFO, {
|
|
@@ -784,10 +810,17 @@ export default class TUICallService {
|
|
|
784
810
|
callRole: TUIStore.getData(StoreName.CALL, NAME.CALL_ROLE),
|
|
785
811
|
callStatus: TUIStore.getData(StoreName.CALL, NAME.CALL_STATUS),
|
|
786
812
|
};
|
|
813
|
+
this._tuiCallEngine?.reportLog?.({
|
|
814
|
+
name: 'TUICallkit._handleCallStatusChange.start',
|
|
815
|
+
data: { bellParams }
|
|
816
|
+
});
|
|
787
817
|
this._bellContext.setBellProperties(bellParams);
|
|
788
818
|
if (value === CallStatus.CALLING) {
|
|
789
|
-
|
|
819
|
+
this?._bellContext?.play();
|
|
790
820
|
} else {
|
|
821
|
+
this._tuiCallEngine?.reportLog?.({
|
|
822
|
+
name: 'TUICallkit._bellContext.stop',
|
|
823
|
+
});
|
|
791
824
|
// 状态变更通知
|
|
792
825
|
if (value === CallStatus.CONNECTED) {
|
|
793
826
|
const isGroup = TUIStore.getData(StoreName.CALL, NAME.IS_GROUP);
|
|
@@ -41,18 +41,6 @@ export async function beforeCall(type: CallMediaType, that: any) {
|
|
|
41
41
|
return CallStatus.IDLE;
|
|
42
42
|
}
|
|
43
43
|
}
|
|
44
|
-
// 套餐问题提示, 小程序最低需要群组通话版, 1v1 通话版本使用 TRTC 就会报错
|
|
45
|
-
export function handlePackageError(error) {
|
|
46
|
-
if (error?.code === -1002) {
|
|
47
|
-
// @ts-ignore
|
|
48
|
-
wx.showModal({
|
|
49
|
-
icon: 'none',
|
|
50
|
-
title: 'error',
|
|
51
|
-
content: error?.message || '',
|
|
52
|
-
showCancel: false,
|
|
53
|
-
});
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
44
|
|
|
57
45
|
export function handleNoPusherCapabilityError(){
|
|
58
46
|
// @ts-ignore
|
|
@@ -41,7 +41,7 @@ export default class CallStore {
|
|
|
41
41
|
pusher: {},
|
|
42
42
|
player: [],
|
|
43
43
|
isEarPhone: false, // 是否是听筒, 默认: false
|
|
44
|
-
pusherId:
|
|
44
|
+
pusherId: '', // 重新渲染 live-Pusher 的标识位
|
|
45
45
|
// 是否开启虚拟背景, 目前仅 web 支持
|
|
46
46
|
isShowEnableVirtualBackground: false, // 是否显示虚拟背景图标, 默认: false
|
|
47
47
|
enableVirtualBackground: false, // 是否开启虚拟背景, 默认: false
|
|
@@ -54,6 +54,11 @@ export default class CallStore {
|
|
|
54
54
|
// translate function
|
|
55
55
|
translate: t,
|
|
56
56
|
isForceUseV2API: false,
|
|
57
|
+
// AI Transcriber related fields
|
|
58
|
+
transcriberRobotId: null,
|
|
59
|
+
realtimeMessageList: [],
|
|
60
|
+
isAITranscriberEnabled: false,
|
|
61
|
+
isAITranscriberRunning: false,
|
|
57
62
|
};
|
|
58
63
|
public store: ICallStore = deepClone(this.defaultStore);
|
|
59
64
|
public prevStore: ICallStore = deepClone(this.defaultStore);
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
import type { UIKitModalOptions, UIKitModalResult } from './type';
|
|
3
|
+
import TUICallKitServer from '../CallService';
|
|
4
|
+
|
|
5
|
+
const URL_REGEX = /^(https?:\/\/)?([\da-z.-]+)\.([a-z.]{2,6})([/\w .-]*)*\/?$/i;
|
|
6
|
+
const FULL_URL_REGEX = /(https?:\/\/[^\s]+)/g;
|
|
7
|
+
|
|
8
|
+
function isDevEnvironment(): boolean {
|
|
9
|
+
const accountInfo = uni.getAccountInfoSync?.();
|
|
10
|
+
const envVersion = accountInfo?.miniProgram?.envVersion;
|
|
11
|
+
return envVersion === 'develop' || envVersion === 'trial';
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function extractUrlFromContent(content: string): string | null {
|
|
15
|
+
if (!content || typeof content !== 'string') {
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
if (content.includes('<a ') || content.includes('<a>')) {
|
|
20
|
+
const hrefMatch = content.match(/href=["']([^"']+)["']/);
|
|
21
|
+
return hrefMatch ? hrefMatch[1] : null;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if (URL_REGEX.test(content.trim())) {
|
|
25
|
+
return content.trim();
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const urlMatch = content.match(FULL_URL_REGEX);
|
|
29
|
+
return urlMatch ? urlMatch[0] : null;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function processContent(content: string): string {
|
|
33
|
+
if (!content || typeof content !== 'string') {
|
|
34
|
+
return '';
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
let text = content.replace(/<[^>]+>/g, '');
|
|
38
|
+
text = text
|
|
39
|
+
.replace(/ /g, ' ')
|
|
40
|
+
.replace(/</g, '<')
|
|
41
|
+
.replace(/>/g, '>')
|
|
42
|
+
.replace(/&/g, '&')
|
|
43
|
+
.replace(/"/g, '"');
|
|
44
|
+
text = text.replace(/\s+/g, ' ').trim();
|
|
45
|
+
|
|
46
|
+
const url = extractUrlFromContent(content);
|
|
47
|
+
if (url && !text.includes(url)) {
|
|
48
|
+
return text ? `${text}\n${url}` : url;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return text;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function reportModalView(options: UIKitModalOptions): void {
|
|
55
|
+
try {
|
|
56
|
+
const tim = TUICallKitServer?.getTim?.();
|
|
57
|
+
if (tim && typeof tim.callExperimentalAPI === 'function') {
|
|
58
|
+
const reportData = {
|
|
59
|
+
id: options.id,
|
|
60
|
+
title: options.title,
|
|
61
|
+
type: options.type,
|
|
62
|
+
content: options.content,
|
|
63
|
+
platform: 'miniprogram',
|
|
64
|
+
};
|
|
65
|
+
tim.callExperimentalAPI('reportModalView', JSON.stringify(reportData));
|
|
66
|
+
}
|
|
67
|
+
} catch (error) {
|
|
68
|
+
console.warn('[UIKitModal] reportModalView failed:', error);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const createUIKitModal = (options: UIKitModalOptions): Promise<UIKitModalResult> => {
|
|
73
|
+
return new Promise((resolve) => {
|
|
74
|
+
reportModalView(options);
|
|
75
|
+
|
|
76
|
+
if (!isDevEnvironment()) {
|
|
77
|
+
resolve({ action: 'confirm' });
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const url = extractUrlFromContent(options.content);
|
|
82
|
+
const processedContent = processContent(options.content);
|
|
83
|
+
const hasLink = !!url;
|
|
84
|
+
|
|
85
|
+
uni.showModal({
|
|
86
|
+
title: options.title || '',
|
|
87
|
+
content: processedContent,
|
|
88
|
+
cancelText: '取消',
|
|
89
|
+
confirmText: hasLink ? '复制链接' : '确认',
|
|
90
|
+
success: (res) => {
|
|
91
|
+
const action = res.confirm ? 'confirm' : 'cancel';
|
|
92
|
+
if (res.confirm) {
|
|
93
|
+
if (hasLink && url) {
|
|
94
|
+
uni.setClipboardData({
|
|
95
|
+
data: url,
|
|
96
|
+
success: () => {
|
|
97
|
+
uni.showToast({ title: '链接已复制', icon: 'success' });
|
|
98
|
+
},
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
options.onConfirm?.();
|
|
102
|
+
} else {
|
|
103
|
+
options.onCancel?.();
|
|
104
|
+
}
|
|
105
|
+
resolve({ action, raw: res });
|
|
106
|
+
},
|
|
107
|
+
fail: () => {
|
|
108
|
+
options.onCancel?.();
|
|
109
|
+
resolve({ action: 'cancel' });
|
|
110
|
+
},
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
export const UIKitModal = {
|
|
116
|
+
openModal: (config: UIKitModalOptions) => createUIKitModal(config),
|
|
117
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export type ModalType = 'info' | 'warning' | 'error' | 'success';
|
|
2
|
+
|
|
3
|
+
export interface UIKitModalOptions {
|
|
4
|
+
id: number;
|
|
5
|
+
title: string;
|
|
6
|
+
content: string;
|
|
7
|
+
type: ModalType;
|
|
8
|
+
onConfirm?: () => void;
|
|
9
|
+
onCancel?: () => void;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface UIKitModalResult {
|
|
13
|
+
action: 'confirm' | 'cancel';
|
|
14
|
+
raw?: any;
|
|
15
|
+
}
|
|
@@ -39,6 +39,10 @@ export const CALL_DATA_KEY: any = {
|
|
|
39
39
|
PUSHER_ID: 'pusherId',
|
|
40
40
|
IS_FORCE_USE_V2_API: 'isForceUseV2API',
|
|
41
41
|
MODAL_ERROR: 'modalError',
|
|
42
|
+
TRANSCRIBER_ROBOT_ID: 'transcriberRobotId',
|
|
43
|
+
REALTIME_MESSAGE_LIST: 'realtimeMessageList',
|
|
44
|
+
IS_AI_TRANSCRIBER_ENABLED: 'isAITranscriberEnabled', // Controls UI visibility
|
|
45
|
+
IS_AI_TRANSCRIBER_RUNNING: 'isAITranscriberRunning', // Controls AI transcriber running state
|
|
42
46
|
};
|
|
43
47
|
|
|
44
48
|
export const CHAT_DATA_KEY: any = {
|
|
@@ -52,4 +52,9 @@ export interface ICallStore {
|
|
|
52
52
|
// translate function
|
|
53
53
|
translate: Function,
|
|
54
54
|
isForceUseV2API: boolean, // 是否使用 call/groupCall 接口, 默认: false
|
|
55
|
+
// AI Transcriber related fields
|
|
56
|
+
transcriberRobotId: string | null, // AI 转写机器人 ID
|
|
57
|
+
realtimeMessageList: [], // 实时转写消息列表
|
|
58
|
+
isAITranscriberEnabled: boolean, // AI 转写UI是否显示
|
|
59
|
+
isAITranscriberRunning: boolean, // AI transcriber running state
|
|
55
60
|
}
|
|
@@ -146,4 +146,19 @@ export const en = {
|
|
|
146
146
|
'error.10013': "Call failed: You have been blocked by the other party or you have blocked the other party",
|
|
147
147
|
'error.10014': "Call initiation failed. User ID is invalid. Please confirm that the user is registered.",
|
|
148
148
|
'error': 'Error',
|
|
149
|
+
// AI Subtitle Settings
|
|
150
|
+
'ai-subtitle': 'AI Subtitle',
|
|
151
|
+
'ai-subtitle-settings': 'AI Subtitle Settings',
|
|
152
|
+
'recognition-language': 'Recognition Language',
|
|
153
|
+
'translation-language': 'Translation Language',
|
|
154
|
+
'subtitle-display-settings': 'Subtitle Display Settings',
|
|
155
|
+
'subtitle-display-bilingual': 'Show Bilingual Subtitles',
|
|
156
|
+
'no-translation': 'No Translation',
|
|
157
|
+
'show-bilingual': 'Show Bilingual',
|
|
158
|
+
'show-original-only': 'Show Original Only',
|
|
159
|
+
'save': 'Save',
|
|
160
|
+
'select-recognition-language': 'Please select recognition language',
|
|
161
|
+
'select-translation-language': 'Please select translation language',
|
|
162
|
+
'confirm': 'Confirm',
|
|
163
|
+
'recognition-and-translation-settings': 'Recognition & Translation Settings',
|
|
149
164
|
};
|
|
@@ -145,4 +145,19 @@ export const ja_JP = {
|
|
|
145
145
|
'error.10013': "通話失敗:相手にブロックされているか、または相手をブロックしています",
|
|
146
146
|
'error.10014': "通話の開始に失敗しました。ユーザーIDが無効です。ユーザーが登録されていることを確認してください。",
|
|
147
147
|
'error': 'エラー',
|
|
148
|
+
// AI Subtitle Settings
|
|
149
|
+
'ai-subtitle': 'AI字幕',
|
|
150
|
+
'ai-subtitle-settings': 'AI字幕設定',
|
|
151
|
+
'recognition-language': '認識言語',
|
|
152
|
+
'translation-language': '翻訳言語',
|
|
153
|
+
'subtitle-display-settings': '字幕表示設定',
|
|
154
|
+
'subtitle-display-bilingual': 'バイリンガル字幕を表示',
|
|
155
|
+
'no-translation': '翻訳しない',
|
|
156
|
+
'show-bilingual': 'バイリンガル表示',
|
|
157
|
+
'show-original-only': '原文のみ表示',
|
|
158
|
+
'save': '保存',
|
|
159
|
+
'select-recognition-language': '認識言語を選択してください',
|
|
160
|
+
'select-translation-language': '翻訳言語を選択してください',
|
|
161
|
+
'confirm': '確認',
|
|
162
|
+
'recognition-and-translation-settings': '認識と翻訳の設定',
|
|
148
163
|
};
|
|
@@ -141,4 +141,19 @@ export const zh = {
|
|
|
141
141
|
'error.10013': "呼叫失败:您已被对方拉黑或您拉黑了对方",
|
|
142
142
|
'error.10014': "发起通话失败,用户 ID 无效,请确认该用户已注册。",
|
|
143
143
|
'error': '错误',
|
|
144
|
+
// AI Subtitle Settings
|
|
145
|
+
'ai-subtitle': 'AI 字幕',
|
|
146
|
+
'ai-subtitle-settings': 'AI 字幕设置',
|
|
147
|
+
'recognition-language': '识别语言',
|
|
148
|
+
'translation-language': '翻译语言',
|
|
149
|
+
'subtitle-display-settings': '字幕显示设置',
|
|
150
|
+
'subtitle-display-bilingual': '字幕显示双语',
|
|
151
|
+
'no-translation': '不翻译',
|
|
152
|
+
'show-bilingual': '显示双语',
|
|
153
|
+
'show-original-only': '仅显示原文',
|
|
154
|
+
'save': '保存',
|
|
155
|
+
'select-recognition-language': '请选择识别语言',
|
|
156
|
+
'select-translation-language': '请选择翻译语言',
|
|
157
|
+
'confirm': '确定',
|
|
158
|
+
'recognition-and-translation-settings': '识别与翻译设置',
|
|
144
159
|
};
|
|
@@ -155,7 +155,7 @@ export function handleRepeatedCallError(error: any) {
|
|
|
155
155
|
*/
|
|
156
156
|
export function handleNoDevicePermissionError(error: any) {
|
|
157
157
|
const { message } = error;
|
|
158
|
-
if (message
|
|
158
|
+
if (message?.indexOf('NotAllowedError: Permission denied') !== -1) {
|
|
159
159
|
return true;
|
|
160
160
|
}
|
|
161
161
|
return false;
|