@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
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@trtc/calls-uikit-react",
3
- "version": "4.4.3",
3
+ "version": "4.4.4",
4
4
  "main": "./tuicall-uikit-react.umd.js",
5
5
  "module": "./tuicall-uikit-react.es.js",
6
6
  "types": "./types/index.d.ts",
@@ -14,7 +14,7 @@
14
14
  },
15
15
  "dependencies": {
16
16
  "@tencentcloud/tui-core-lite": "1.0.0",
17
- "@trtc/call-engine-lite-js": "~3.5.2",
17
+ "@trtc/call-engine-lite-js": "~3.5.5",
18
18
  "@tencentcloud/lite-chat": "^1.6.3",
19
19
  "@trtc/call-engine-lite-wx": "~3.4.7"
20
20
  },
@@ -0,0 +1,4 @@
1
+ <svg width="13" height="14" viewBox="0 0 13 14" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <path d="M9.06218 6.75C9.06218 8.40685 7.71903 9.75 6.06218 9.75C4.40532 9.75 3.06218 8.40685 3.06218 6.75C3.06218 5.09315 4.40532 3.75 6.06218 3.75C7.71903 3.75 9.06218 5.09315 9.06218 6.75ZM8.06218 6.75C8.06218 5.64543 7.16675 4.75 6.06218 4.75C4.95761 4.75 4.06218 5.64543 4.06218 6.75C4.06218 7.85457 4.95761 8.75 6.06218 8.75C7.16675 8.75 8.06218 7.85457 8.06218 6.75Z" fill="white" fill-opacity="0.75"/>
3
+ <path d="M6.06218 0L12.1244 3.375V10.125L6.06218 13.5L0 10.125V3.375L6.06218 0ZM1 3.9628V9.5372L6.06218 12.3555L11.1244 9.5372V3.9628L6.06218 1.14453L1 3.9628Z" fill="white" fill-opacity="0.75"/>
4
+ </svg>
@@ -0,0 +1,7 @@
1
+ <svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <path d="M19 12.1182H17.333V3.66699H2.66699V16.333H8.18945V18H1V2H19V12.1182Z" fill="white" fill-opacity="0.9"/>
3
+ <path d="M15.6667 8.02202C15.6667 8.02202 14.9677 7.72533 13.7849 7.77478C13.086 7.82422 12.5484 7.97257 12.172 8.36815C11.7419 8.81319 11.5269 9.35711 11.5269 10.0494C11.5269 10.7417 11.7419 11.2361 12.1183 11.6317C12.4946 11.9779 12.9785 12.1262 13.6237 12.1757C14.4301 12.2745 15.6667 11.9779 15.6667 11.9779V13.2635C15.6667 13.2635 14.7527 13.4613 13.5161 13.4613C12.4946 13.4613 11.6882 13.1152 11.043 12.5218C10.4516 11.879 10.129 11.0878 10.129 10.0988C10.129 9.06043 10.4516 8.17036 11.1505 7.52754C11.8495 6.88471 12.7097 6.53857 13.7849 6.53857C14.7527 6.53857 15.6667 6.73637 15.6667 6.73637V8.02202Z" fill="white" fill-opacity="0.9"/>
4
+ <path d="M9.53763 8.02202C9.53763 8.02202 8.83871 7.72533 7.65592 7.77478C6.95699 7.82422 6.41936 7.97257 6.04301 8.36815C5.6129 8.81319 5.39785 9.35711 5.39785 10.0494C5.39785 10.7417 5.6129 11.2361 5.98925 11.6317C6.36559 11.9779 6.84946 12.1262 7.49462 12.1757C8.30108 12.2745 9.53763 11.9779 9.53763 11.9779V13.2635C9.53763 13.2635 8.62366 13.4613 7.3871 13.4613C6.36559 13.4613 5.55914 13.1152 4.91398 12.5218C4.32258 11.879 4 11.0878 4 10.0988C4 9.06043 4.32258 8.17036 5.02151 7.52754C5.72043 6.88471 6.58065 6.53857 7.65592 6.53857C8.62366 6.53857 9.53763 6.73637 9.53763 6.73637V8.02202Z" fill="white" fill-opacity="0.9"/>
5
+ <rect x="10" y="14.5916" width="10" height="5" rx="2.5" fill="#676A70"/>
6
+ <rect x="10.4997" y="15.0916" width="4" height="4" rx="2" fill="white"/>
7
+ </svg>
@@ -0,0 +1,7 @@
1
+ <svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <path d="M19 12.1182H17.333V3.66699H2.66699V16.333H8.18945V18H1V2H19V12.1182Z" fill="white" fill-opacity="0.9"/>
3
+ <path d="M15.6667 8.02202C15.6667 8.02202 14.9677 7.72533 13.7849 7.77478C13.086 7.82422 12.5484 7.97257 12.172 8.36815C11.7419 8.81319 11.5269 9.35711 11.5269 10.0494C11.5269 10.7417 11.7419 11.2361 12.1183 11.6317C12.4946 11.9779 12.9785 12.1262 13.6237 12.1757C14.4301 12.2745 15.6667 11.9779 15.6667 11.9779V13.2635C15.6667 13.2635 14.7527 13.4613 13.5161 13.4613C12.4946 13.4613 11.6882 13.1152 11.043 12.5218C10.4516 11.879 10.129 11.0878 10.129 10.0988C10.129 9.06043 10.4516 8.17036 11.1505 7.52754C11.8495 6.88471 12.7097 6.53857 13.7849 6.53857C14.7527 6.53857 15.6667 6.73637 15.6667 6.73637V8.02202Z" fill="white" fill-opacity="0.9"/>
4
+ <path d="M9.53763 8.02202C9.53763 8.02202 8.83871 7.72533 7.65592 7.77478C6.95699 7.82422 6.41936 7.97257 6.04301 8.36815C5.6129 8.81319 5.39785 9.35711 5.39785 10.0494C5.39785 10.7417 5.6129 11.2361 5.98925 11.6317C6.36559 11.9779 6.84946 12.1262 7.49462 12.1757C8.30108 12.2745 9.53763 11.9779 9.53763 11.9779V13.2635C9.53763 13.2635 8.62366 13.4613 7.3871 13.4613C6.36559 13.4613 5.55914 13.1152 4.91398 12.5218C4.32258 11.879 4 11.0878 4 10.0988C4 9.06043 4.32258 8.17036 5.02151 7.52754C5.72043 6.88471 6.58065 6.53857 7.65592 6.53857C8.62366 6.53857 9.53763 6.73637 9.53763 6.73637V8.02202Z" fill="white" fill-opacity="0.9"/>
5
+ <path d="M10 17.0916C10 15.7108 11.1193 14.5916 12.5 14.5916H17.5C18.8807 14.5916 20 15.7108 20 17.0916C20 18.4723 18.8807 19.5916 17.5 19.5916H12.5C11.1193 19.5916 10 18.4723 10 17.0916Z" fill="#4588F5"/>
6
+ <rect x="15.5042" y="15.0916" width="4" height="4" rx="2" fill="white"/>
7
+ </svg>
@@ -0,0 +1,3 @@
1
+ <svg width="6" height="12" viewBox="0 0 6 12" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <path d="M1.84529 9.34448L1.15586 8.65505L3.81114 5.99977L1.15586 3.34448L1.84529 2.65505L5.19 5.99977L1.84529 9.34448Z" fill="white" fill-opacity="0.42"/>
3
+ </svg>
@@ -0,0 +1,116 @@
1
+ .custom-select-wrapper {
2
+ position: relative;
3
+ width: 100%;
4
+ }
5
+
6
+ .custom-select {
7
+ height: 36px;
8
+ padding: 0 32px 0 12px;
9
+ border: 1px solid #DCDFE6;
10
+ border-radius: 4px;
11
+ font-size: 14px;
12
+ color: #606266;
13
+ background: #FFFFFF;
14
+ cursor: pointer;
15
+ display: flex;
16
+ align-items: center;
17
+ transition: all 0.3s;
18
+
19
+ &:hover:not(.is-disabled) {
20
+ border-color: #C0C4CC;
21
+ }
22
+
23
+ &.is-open {
24
+ border-color: #409EFF;
25
+ box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.2);
26
+ }
27
+
28
+ &.is-disabled {
29
+ background: #F5F7FA;
30
+ color: #C0C4CC;
31
+ cursor: not-allowed;
32
+ border-color: #E4E7ED;
33
+ }
34
+ }
35
+
36
+ .select-text {
37
+ overflow: hidden;
38
+ text-overflow: ellipsis;
39
+ white-space: nowrap;
40
+ }
41
+
42
+ .select-arrow {
43
+ position: absolute;
44
+ right: 12px;
45
+ top: 50%;
46
+ transform: translateY(-50%);
47
+ pointer-events: none;
48
+ transition: transform 0.3s;
49
+
50
+ &.is-open {
51
+ transform: translateY(-50%) rotate(180deg);
52
+ }
53
+ }
54
+
55
+ .custom-options {
56
+ position: absolute;
57
+ top: 100%;
58
+ left: 0;
59
+ right: 0;
60
+ background: #FFFFFF;
61
+ border: 1px solid #DCDFE6;
62
+ border-radius: 4px;
63
+ box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
64
+ z-index: 1000;
65
+ margin-top: 4px;
66
+ overflow: hidden;
67
+ max-height: 200px;
68
+ overflow-y: auto;
69
+ }
70
+
71
+ .custom-option {
72
+ padding: 8px 12px;
73
+ font-size: 14px;
74
+ color: #606266;
75
+ cursor: pointer;
76
+ transition: all 0.2s;
77
+
78
+ &:hover {
79
+ background: #F5F7FA;
80
+ color: #409EFF;
81
+ }
82
+
83
+ &.is-selected {
84
+ color: #409EFF;
85
+ font-weight: 500;
86
+
87
+ &:hover {
88
+ background: #F5F7FA;
89
+ color: #409EFF;
90
+ }
91
+ }
92
+ }
93
+
94
+ // Scrollbar styling for options - more subtle and modern
95
+ .custom-options::-webkit-scrollbar {
96
+ width: 4px;
97
+ }
98
+
99
+ .custom-options::-webkit-scrollbar-track {
100
+ background: transparent;
101
+ }
102
+
103
+ .custom-options::-webkit-scrollbar-thumb {
104
+ background: rgba(0, 0, 0, 0.1);
105
+ border-radius: 2px;
106
+
107
+ &:hover {
108
+ background: rgba(0, 0, 0, 0.2);
109
+ }
110
+ }
111
+
112
+ // Hide scrollbar for Firefox
113
+ .custom-options {
114
+ scrollbar-width: thin;
115
+ scrollbar-color: rgba(0, 0, 0, 0.1) transparent;
116
+ }
@@ -0,0 +1,96 @@
1
+ import React, { useState, useRef, useEffect } from 'react';
2
+ import './CustomSelect.scss';
3
+
4
+ export interface SelectOption {
5
+ label: string;
6
+ value: string | number;
7
+ }
8
+
9
+ interface CustomSelectProps {
10
+ value: string | number;
11
+ options: SelectOption[];
12
+ placeholder?: string;
13
+ disabled?: boolean;
14
+ onChange: (value: string | number) => void;
15
+ }
16
+
17
+ const CustomSelect: React.FC<CustomSelectProps> = ({
18
+ value,
19
+ options,
20
+ placeholder = 'Please select',
21
+ disabled = false,
22
+ onChange
23
+ }) => {
24
+ const [isOpen, setIsOpen] = useState(false);
25
+ const wrapperRef = useRef<HTMLDivElement>(null);
26
+
27
+ const displayText = (() => {
28
+ const selectedOption = options.find(option => option.value === value);
29
+ return selectedOption ? selectedOption.label : placeholder;
30
+ })();
31
+
32
+ const toggleDropdown = () => {
33
+ if (disabled) return;
34
+ setIsOpen(!isOpen);
35
+ };
36
+
37
+ const selectOption = (optionValue: string | number) => {
38
+ onChange(optionValue);
39
+ setIsOpen(false);
40
+ };
41
+
42
+ // Close dropdown when clicking outside
43
+ useEffect(() => {
44
+ const handleClickOutside = (event: MouseEvent) => {
45
+ if (wrapperRef.current && !wrapperRef.current.contains(event.target as Node)) {
46
+ setIsOpen(false);
47
+ }
48
+ };
49
+
50
+ document.addEventListener('mousedown', handleClickOutside);
51
+ return () => {
52
+ document.removeEventListener('mousedown', handleClickOutside);
53
+ };
54
+ }, []);
55
+
56
+ return (
57
+ <div className="custom-select-wrapper" ref={wrapperRef}>
58
+ <div
59
+ className={`custom-select ${isOpen ? 'is-open' : ''} ${disabled ? 'is-disabled' : ''}`}
60
+ onClick={toggleDropdown}
61
+ >
62
+ <span className="select-text">{displayText}</span>
63
+ <svg
64
+ className={`select-arrow ${isOpen ? 'is-open' : ''}`}
65
+ width="12"
66
+ height="8"
67
+ viewBox="0 0 12 8"
68
+ fill="none"
69
+ >
70
+ <path
71
+ d="M1 1L6 6L11 1"
72
+ stroke="#C0C4CC"
73
+ strokeWidth="1.5"
74
+ strokeLinecap="round"
75
+ strokeLinejoin="round"
76
+ />
77
+ </svg>
78
+ </div>
79
+ {isOpen && (
80
+ <div className="custom-options">
81
+ {options.map((option) => (
82
+ <div
83
+ key={option.value}
84
+ className={`custom-option ${value === option.value ? 'is-selected' : ''}`}
85
+ onClick={() => selectOption(option.value)}
86
+ >
87
+ {option.label}
88
+ </div>
89
+ ))}
90
+ </div>
91
+ )}
92
+ </div>
93
+ );
94
+ };
95
+
96
+ export default CustomSelect;
@@ -0,0 +1,109 @@
1
+ // PC端样式
2
+ .ai-subtitle-pc {
3
+ position: absolute;
4
+ z-index: 1;
5
+ left: 50%;
6
+ transform: translateX(-50%);
7
+ width: auto;
8
+ height: auto;
9
+ bottom: 110px;
10
+
11
+ // PC端展开状态
12
+ &.ai-subtitle-pc--expanded {
13
+ position: absolute !important;
14
+ top: 0 !important;
15
+ left: 0 !important;
16
+ right: 0 !important;
17
+ bottom: 0 !important;
18
+ width: 100% !important;
19
+ height: 100% !important;
20
+ background-color: transparent;
21
+ transform: none !important;
22
+ z-index: 1000;
23
+ }
24
+
25
+ .ai-subtitle-pc__content {
26
+ // PC端内容定位
27
+ .ai-subtitle-pc:not(.ai-subtitle-pc--expanded) & {
28
+ position: relative;
29
+ width: auto;
30
+ height: auto;
31
+ }
32
+
33
+ // PC端展开时隐藏内容
34
+ .ai-subtitle-pc--expanded & {
35
+ display: none;
36
+ }
37
+ }
38
+
39
+ .ai-subtitle-pc__settings {
40
+ // PC端设置面板定位
41
+ .ai-subtitle-pc--expanded & {
42
+ position: absolute;
43
+ top: 50%;
44
+ left: 50%;
45
+ transform: translate(-50%, -50%);
46
+ z-index: 1001;
47
+ }
48
+
49
+ // PC端未展开时隐藏设置
50
+ .ai-subtitle-pc:not(.ai-subtitle-pc--expanded) & {
51
+ display: none;
52
+ }
53
+ }
54
+ }
55
+
56
+ // H5端样式
57
+ .ai-subtitle-h5 {
58
+ position: absolute;
59
+ z-index: 100;
60
+ left: 50%;
61
+ transform: translateX(-50%);
62
+ width: auto;
63
+ height: auto;
64
+ bottom: 26%;
65
+
66
+ // H5端展开状态
67
+ &.ai-subtitle-h5--expanded {
68
+ position: absolute !important;
69
+ top: 0 !important;
70
+ left: 0 !important;
71
+ right: 0 !important;
72
+ bottom: 0 !important;
73
+ width: 100% !important;
74
+ height: 100% !important;
75
+ background-color: transparent;
76
+ transform: none !important;
77
+ z-index: 1000;
78
+ }
79
+
80
+ .ai-subtitle-h5__content {
81
+ // H5端内容定位
82
+ .ai-subtitle-h5:not(.ai-subtitle-h5--expanded) & {
83
+ position: relative;
84
+ width: auto;
85
+ height: auto;
86
+ }
87
+
88
+ // H5端展开时隐藏内容
89
+ .ai-subtitle-h5--expanded & {
90
+ display: none;
91
+ }
92
+ }
93
+
94
+ .ai-subtitle-h5__settings {
95
+ // H5端设置面板定位
96
+ .ai-subtitle-h5--expanded & {
97
+ position: absolute;
98
+ top: 50%;
99
+ left: 50%;
100
+ transform: translate(-50%, -50%);
101
+ z-index: 1001;
102
+ }
103
+
104
+ // H5端未展开时隐藏设置
105
+ .ai-subtitle-h5:not(.ai-subtitle-h5--expanded) & {
106
+ display: none;
107
+ }
108
+ }
109
+ }
@@ -1,19 +1,10 @@
1
- import React, { useEffect, useState } from 'react';
2
- import { aiAssistant, ASREvent } from './index';
3
-
4
- interface TranslationContent {
5
- language: string;
6
- content: string;
7
- }
8
-
9
- interface SubtitleInfo {
10
- roundId: string;
11
- sender: string;
12
- nick?: string;
13
- text: string;
14
- end: boolean;
15
- translation: TranslationContent[];
16
- }
1
+ import React, { useState } from 'react';
2
+ import { TUIGlobal } from '../../../../TUICallService/index';
3
+ import { useAIAssistant } from '../../../hooks/useAIAssistant';
4
+ import SubtitleContent from './components/SubtitleContent';
5
+ import SubtitleSettingsPC from './components/SubtitleSettingsPC';
6
+ import SubtitleSettingsH5 from './components/SubtitleSettingsH5';
7
+ import './AISubtitle.scss';
17
8
 
18
9
  interface AISubtitleProps {
19
10
  customClass?: string;
@@ -21,67 +12,62 @@ interface AISubtitleProps {
21
12
  }
22
13
 
23
14
  const AISubtitle: React.FC<AISubtitleProps> = ({ customClass, customStyle }) => {
24
- const [subtitleInfoList, setSubtitleInfoList] = useState<SubtitleInfo[]>([]);
15
+ const isPC = TUIGlobal.isPC;
25
16
 
26
- const handleAISubtitle = (data: any) => {
27
- if (!data?.subtitleInfoList) return;
28
- setSubtitleInfoList(JSON.parse(JSON.stringify(data.subtitleInfoList)));
29
- };
17
+ // Use AI Assistant hook (now includes both status and data)
18
+ const { isAITranscriberEnabled } = useAIAssistant();
19
+
20
+ const [showSettingsModal, setShowSettingsModal] = useState(false);
30
21
 
31
- useEffect(() => {
32
- aiAssistant.on(ASREvent.TRANSCRIPTION, handleAISubtitle);
33
-
34
- return () => {
35
- aiAssistant.off(ASREvent.TRANSCRIPTION, handleAISubtitle);
36
- };
37
- }, []);
22
+ const openSettingsModal = () => {
23
+ setShowSettingsModal(true);
24
+ };
38
25
 
39
- // 内联样式定义
40
- const styles = {
41
- subtitleContainer: {
42
- position: 'absolute' as const,
43
- zIndex: 100,
44
- bottom: '120px',
45
- left: '50%',
46
- padding: '10px 12px',
47
- color: '#fff',
48
- backgroundColor: 'rgba(79, 88, 107, 0.7)',
49
- borderRadius: '8px',
50
- transform: 'translateX(-50%)',
51
- width: '260px',
52
- maxHeight: '280px',
53
- overflowY: 'auto' as const,
54
- overflowX: 'hidden' as const,
55
- },
56
- spacer: {
57
- height: '16px',
58
- },
59
- senderName: {
60
- color: 'yellow',
61
- }
26
+ const handleSettingsConfirm = () => {
27
+ // Handle settings save logic here
28
+ setShowSettingsModal(false);
62
29
  };
63
30
 
64
- if (!subtitleInfoList.length) {
31
+ // Don't render if AI transcriber is not enabled
32
+ if (!isAITranscriberEnabled) {
65
33
  return null;
66
34
  }
67
35
 
68
36
  return (
69
37
  <div
70
- className={`ai-subtitle ${customClass || ''}`}
71
- style={{ ...styles.subtitleContainer, ...customStyle }}
38
+ className={`
39
+ ${isPC ? 'ai-subtitle-pc' : 'ai-subtitle-h5'}
40
+ ${customClass || ''}
41
+ ${showSettingsModal && isPC ? 'ai-subtitle-pc--expanded' : ''}
42
+ ${showSettingsModal && !isPC ? 'ai-subtitle-h5--expanded' : ''}
43
+ `}
44
+ style={customStyle}
72
45
  >
73
- {subtitleInfoList.map((subtitleInfo, index) => (
74
- <div key={subtitleInfo.roundId}>
75
- {index !== 0 && <div style={{ height: '16px' }} />}
76
- <div style={styles.senderName}>{`${subtitleInfo?.nick || subtitleInfo?.sender}:`}</div>
77
- <div>{subtitleInfo?.text}</div>
78
- {subtitleInfo?.translation?.map((translationContent, transIndex) => (
79
- <div key={transIndex}>
80
- <span>{`[${translationContent?.language}]: ${translationContent?.content}`}</span>
81
- </div>
82
- ))}
83
- </div>
84
- ))}
46
+ {/* Subtitle Content Component */}
47
+ <div style={{ display: showSettingsModal ? 'none' : 'block' }}>
48
+ <SubtitleContent
49
+ onOpenSettings={openSettingsModal}
50
+ className={isPC ? 'ai-subtitle-pc__content' : 'ai-subtitle-h5__content'}
51
+ />
52
+ </div>
53
+
54
+ {/* Settings Modal Component (Same Level) */}
55
+ {isPC && (
56
+ <SubtitleSettingsPC
57
+ visible={showSettingsModal}
58
+ onVisibleChange={setShowSettingsModal}
59
+ onConfirm={handleSettingsConfirm}
60
+ />
61
+ )}
62
+
63
+ {/* Settings Modal Component (H5) */}
64
+ {!isPC && (
65
+ <SubtitleSettingsH5
66
+ visible={showSettingsModal}
67
+ onVisibleChange={setShowSettingsModal}
68
+ onConfirm={handleSettingsConfirm}
69
+ />
70
+ )}
85
71
  </div>
86
72
  );
87
73
  };
@@ -0,0 +1,39 @@
1
+ import React from 'react';
2
+ import { TUICallKitAPI } from '../../../../../TUICallService/index';
3
+ import { useAIAssistant } from '../../../../hooks/useAIAssistant';
4
+ import openAiAssistantIcon from '../../../../assets/aiAssistant/mobile/open-aiAssistant.svg';
5
+ import closeAiAssistantIcon from '../../../../assets/aiAssistant/mobile/close-aiAssistant.svg';
6
+
7
+ const AITranscriberSwitchH5: React.FC = () => {
8
+ // Use AI Transcriber status hook
9
+ const { isAITranscriberRunning } = useAIAssistant();
10
+
11
+ // Toggle AI transcriber
12
+ const handleToggle = async () => {
13
+ try {
14
+ if (isAITranscriberRunning) {
15
+ await TUICallKitAPI._aiAssistant.stopRealtimeTranscriber();
16
+ } else {
17
+ await TUICallKitAPI._aiAssistant.startRealtimeTranscriber({
18
+ sourceLanguage: 'zh',
19
+ translationLanguages: ['en']
20
+ });
21
+ }
22
+ } catch (error) {
23
+ console.error('Failed to toggle AI transcriber:', error);
24
+ }
25
+ };
26
+
27
+ return (
28
+ <div onClick={handleToggle}>
29
+ <img
30
+ src={isAITranscriberRunning ? openAiAssistantIcon : closeAiAssistantIcon}
31
+ width="24px"
32
+ height="24px"
33
+ alt="AI Assistant Toggle"
34
+ />
35
+ </div>
36
+ );
37
+ };
38
+
39
+ export default AITranscriberSwitchH5;
@@ -0,0 +1,46 @@
1
+ .ai-transcriber-switch {
2
+ display: flex;
3
+ align-items: center;
4
+ gap: 8px;
5
+ padding: 8px 12px;
6
+ border-radius: 20px;
7
+ color: white;
8
+ font-size: 14px;
9
+ font-weight: 400;
10
+ font-family: PingFang SC;
11
+ cursor: pointer;
12
+
13
+ &__label {
14
+ white-space: nowrap;
15
+ }
16
+
17
+ &__toggle {
18
+ position: relative;
19
+ width: 32px;
20
+ height: 20px;
21
+ background: #FFFFFF4D;
22
+ border-radius: 10px;
23
+ transition: background-color 0.3s ease;
24
+ cursor: pointer;
25
+
26
+ &--active {
27
+ background: #1C66E5;
28
+ }
29
+ }
30
+
31
+ &__slider {
32
+ position: absolute;
33
+ top: 3px;
34
+ left: 2px;
35
+ width: 14px;
36
+ height: 14px;
37
+ border-radius: 50%;
38
+ background: white;
39
+ transition: transform 0.3s ease;
40
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
41
+
42
+ .ai-transcriber-switch__toggle--active & {
43
+ transform: translateX(14px);
44
+ }
45
+ }
46
+ }
@@ -0,0 +1,42 @@
1
+ import React from 'react';
2
+ import { TUICallKitAPI } from '../../../../../TUICallService/index';
3
+ import { useAIAssistant } from '../../../../hooks/useAIAssistant';
4
+ import { useTranslate } from '../../../../hooks';
5
+ import './AITranscriberSwitchPC.scss';
6
+
7
+ const AITranscriberSwitchPC: React.FC = () => {
8
+ // Use AI Transcriber status hook
9
+ const { isAITranscriberRunning } = useAIAssistant();
10
+
11
+ // Use i18n translation
12
+ const { t } = useTranslate();
13
+
14
+ // Toggle AI transcriber
15
+ const handleToggle = async () => {
16
+ try {
17
+ if (isAITranscriberRunning) {
18
+ await TUICallKitAPI._aiAssistant.stopRealtimeTranscriber();
19
+ } else {
20
+ await TUICallKitAPI._aiAssistant.startRealtimeTranscriber({
21
+ sourceLanguage: 'zh',
22
+ translationLanguages: ['en']
23
+ });
24
+ }
25
+ } catch (error) {
26
+ console.error('Failed to toggle AI transcriber:', error);
27
+ }
28
+ };
29
+
30
+ return (
31
+ <div className="ai-transcriber-switch" onClick={handleToggle}>
32
+ <span className="ai-transcriber-switch__label">{t('ai-subtitle')}</span>
33
+ <div
34
+ className={`ai-transcriber-switch__toggle ${isAITranscriberRunning ? 'ai-transcriber-switch__toggle--active' : ''}`}
35
+ >
36
+ <div className="ai-transcriber-switch__slider"></div>
37
+ </div>
38
+ </div>
39
+ );
40
+ };
41
+
42
+ export default AITranscriberSwitchPC;