@ray-js/t-agent-ui-ray 0.2.3-beta-1 → 0.2.3-beta-3
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/dist/LazyScrollView/LazyItem/index.d.ts +0 -1
- package/dist/LazyScrollView/LazyItem/index.js +6 -12
- package/dist/LazyScrollView/LazyItem/index.tyml +7 -7
- package/dist/LazyScrollView/get-visible-items.sjs +53 -0
- package/dist/LazyScrollView/index.d.ts +1 -0
- package/dist/LazyScrollView/index.js +18 -1
- package/dist/LazyScrollView/index.tyml +2 -0
- package/dist/LazyScrollView/lazy-item-context.sjs +90 -0
- package/dist/LazyScrollView/lazy-scroll-view.sjs +20 -256
- package/dist/LazyScrollView/ordered-list.sjs +57 -0
- package/dist/LazyScrollView/scroll-view-context.sjs +237 -0
- package/dist/MessageActionBar/back.svg +1 -0
- package/dist/MessageActionBar/delete.svg +1 -0
- package/dist/MessageActionBar/index.d.ts +4 -0
- package/dist/MessageActionBar/index.js +79 -0
- package/dist/MessageActionBar/index.less +68 -0
- package/dist/MessageInput/MessageInputAIStream/index.js +4 -3
- package/dist/MessageInput/MessageInputAssistant/asr.d.ts +30 -0
- package/dist/MessageInput/MessageInputAssistant/asr.js +126 -0
- package/dist/MessageInput/MessageInputAssistant/index.js +5 -2
- package/dist/MessageInput/MessageInputAssistant/useAsrInput.js +1 -1
- package/dist/MessageList/PartRender.d.ts +15 -0
- package/dist/MessageList/PartRender.js +25 -0
- package/dist/MessageList/ScrollBottomView.d.ts +1 -0
- package/dist/MessageList/ScrollBottomView.js +4 -0
- package/dist/MessageList/index.d.ts +3 -5
- package/dist/MessageList/index.js +30 -47
- package/dist/MessageList/index.less +2 -22
- package/dist/MessageRender/index.d.ts +1 -2
- package/dist/MessageRender/index.js +0 -4
- package/dist/hooks/context.js +0 -1
- package/dist/hooks/useLongPress.js +1 -1
- package/dist/i18n/strings.d.ts +48 -16
- package/dist/i18n/strings.js +48 -16
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/utils/abort.d.ts +38 -0
- package/dist/utils/abort.js +177 -0
- package/dist/utils/ttt.d.ts +98 -0
- package/dist/utils/ttt.js +54 -0
- package/package.json +2 -2
- package/dist/LazyScrollView/weak-ref.sjs +0 -45
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
const { OrderedList } = require('./ordered-list.sjs');
|
|
2
|
+
const { getVisibleItems } = require('./get-visible-items.sjs');
|
|
3
|
+
|
|
4
|
+
// 为了尽可能防止内存泄漏,LazyItemContext 不引用 ownerInstance、instance
|
|
5
|
+
|
|
6
|
+
export class ScrollViewContext {
|
|
7
|
+
constructor(prefix, overscanCount) {
|
|
8
|
+
this.prefix = prefix;
|
|
9
|
+
|
|
10
|
+
this.scrollViewId = null;
|
|
11
|
+
this.height = 0;
|
|
12
|
+
this.width = 0;
|
|
13
|
+
this.overscanCount = overscanCount;
|
|
14
|
+
this.items = new OrderedList(); // ItemContext[]
|
|
15
|
+
this.initDone = false;
|
|
16
|
+
this.updateVisibleItemsPending = false;
|
|
17
|
+
this.offset = 0;
|
|
18
|
+
this.lastScrollEventDetail = null;
|
|
19
|
+
this.lastScrollIntoView = null;
|
|
20
|
+
this.lastChanges = null;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
refresh(ownerInstance, instance) {
|
|
24
|
+
const rect = instance.getBoundingClientRect();
|
|
25
|
+
this.height = rect.height;
|
|
26
|
+
this.width = rect.width;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
init(ownerInstance, instance) {
|
|
30
|
+
const { scrollViewId } = instance.getDataset();
|
|
31
|
+
|
|
32
|
+
const rect = instance.getBoundingClientRect();
|
|
33
|
+
|
|
34
|
+
this.scrollViewId = scrollViewId;
|
|
35
|
+
this.height = rect.height;
|
|
36
|
+
this.width = rect.width
|
|
37
|
+
|
|
38
|
+
const onEvent = (event) => {
|
|
39
|
+
switch (event.type) {
|
|
40
|
+
case 'itemUpdate': {
|
|
41
|
+
this.updateVisibleItems(ownerInstance, instance);
|
|
42
|
+
break;
|
|
43
|
+
}
|
|
44
|
+
case 'itemIndexChange':
|
|
45
|
+
case 'itemAdd': {
|
|
46
|
+
this.items.upsert(event.itemContext);
|
|
47
|
+
this.updateVisibleItems(ownerInstance, instance);
|
|
48
|
+
break;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
ownerInstance.eventChannel.on(`${this.prefix}${this.scrollViewId}`, onEvent);
|
|
54
|
+
ownerInstance.setTimeout(() => {
|
|
55
|
+
this.initDone = true;
|
|
56
|
+
this.updateVisibleItems(ownerInstance, instance);
|
|
57
|
+
}, 3000);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
updateVisibleItems(ownerInstance, instance) {
|
|
61
|
+
if (this.updateVisibleItemsPending || !this.initDone) {
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
this.updateVisibleItemsPending = true;
|
|
65
|
+
requestAnimationFrame(async () => {
|
|
66
|
+
const items = this.items.getAll();
|
|
67
|
+
const map = getVisibleItems({
|
|
68
|
+
sizes: items,
|
|
69
|
+
containerSize: this.height,
|
|
70
|
+
offset: this.offset,
|
|
71
|
+
overscanCount: this.overscanCount,
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
if (!map) {
|
|
75
|
+
this.updateVisibleItemsPending = false;
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const changes = {}
|
|
80
|
+
const toRefresh = [];
|
|
81
|
+
for (let i = 0; i < items.length; i++) {
|
|
82
|
+
const itemContext = items[i];
|
|
83
|
+
const prevShow = itemContext.show;
|
|
84
|
+
const itemId = itemContext.itemId
|
|
85
|
+
const show = !!map[itemId];
|
|
86
|
+
itemContext.show = show;
|
|
87
|
+
|
|
88
|
+
if (!itemContext.ready) {
|
|
89
|
+
// 未准备好,不隐藏
|
|
90
|
+
changes[itemContext.itemId] = true;
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// 不展示,则跳过
|
|
95
|
+
if (!show) {
|
|
96
|
+
continue
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
changes[itemContext.itemId] = true;
|
|
100
|
+
|
|
101
|
+
if (prevShow !== show) {
|
|
102
|
+
toRefresh.push(itemContext);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (!this.isChangesDifferent(changes)) {
|
|
107
|
+
this.updateVisibleItemsPending = false;
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
this.lastChanges = changes;
|
|
112
|
+
|
|
113
|
+
if (toRefresh.length) {
|
|
114
|
+
await Promise.all(toRefresh.map((itemContext) => itemContext.refreshSize(ownerInstance)))
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
ownerInstance.triggerEvent('changed', {
|
|
118
|
+
changes,
|
|
119
|
+
})
|
|
120
|
+
this.updateVisibleItemsPending = false;
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
onScroll(event, ownerInstance, instance) {
|
|
125
|
+
const last = this.lastScrollEventDetail;
|
|
126
|
+
|
|
127
|
+
if (last) {
|
|
128
|
+
if (
|
|
129
|
+
last.scrollTop === event.detail.scrollTop &&
|
|
130
|
+
last.scrollHeight === event.detail.scrollHeight
|
|
131
|
+
) {
|
|
132
|
+
// 如果滚动位置没有变化,则不处理
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
this.offset = event.detail.scrollTop;
|
|
137
|
+
// 触发父组件的滚动事件
|
|
138
|
+
ownerInstance.triggerEvent('scroll', {
|
|
139
|
+
...event.detail,
|
|
140
|
+
clientHeight: this.height,
|
|
141
|
+
clientWidth: this.width,
|
|
142
|
+
});
|
|
143
|
+
this.lastScrollEventDetail = event.detail;
|
|
144
|
+
this.updateVisibleItems(ownerInstance, instance);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
onScrollBottom(newValue, oldValue, ownerInstance, instance) {
|
|
148
|
+
if (newValue === oldValue) {
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
requestAnimationFrame(() => {
|
|
153
|
+
ownerInstance.triggerEvent('done', {
|
|
154
|
+
scrollIntoView: newValue,
|
|
155
|
+
})
|
|
156
|
+
})
|
|
157
|
+
|
|
158
|
+
if (!newValue) {
|
|
159
|
+
return
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const last = this.lastScrollIntoView;
|
|
163
|
+
|
|
164
|
+
if (last && last === newValue) {
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
this.lastScrollIntoView = newValue
|
|
169
|
+
|
|
170
|
+
const rect = instance.getBoundingClientRect()
|
|
171
|
+
if (this.lastScrollEventDetail == null) {
|
|
172
|
+
return
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// 这个就是用来滚动到底部的,所以直接计算底部 offset 就行
|
|
176
|
+
|
|
177
|
+
const lastOffset = this.offset
|
|
178
|
+
this.offset = this.lastScrollEventDetail.scrollHeight - rect.height;
|
|
179
|
+
this.refresh(ownerInstance, instance)
|
|
180
|
+
this.updateVisibleItems(ownerInstance, instance);
|
|
181
|
+
|
|
182
|
+
ownerInstance.triggerEvent('scroll', {
|
|
183
|
+
scrollTop: this.offset,
|
|
184
|
+
deltaX: 0,
|
|
185
|
+
deltaY: this.offset - lastOffset,
|
|
186
|
+
scrollLeft: this.lastScrollEventDetail.scrollLeft,
|
|
187
|
+
scrollHeight: this.lastScrollEventDetail.scrollHeight,
|
|
188
|
+
scrollWidth: this.lastScrollEventDetail.scrollWidth,
|
|
189
|
+
clientHeight: this.height,
|
|
190
|
+
clientWidth: this.width,
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
doOp(opJson, old, ownerInstance, instance) {
|
|
195
|
+
this.refresh(ownerInstance, instance);
|
|
196
|
+
if (!opJson || opJson === old) {
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
let op = null;
|
|
201
|
+
try {
|
|
202
|
+
op = JSON.parse(opJson);
|
|
203
|
+
} catch (error) {
|
|
204
|
+
// nothing
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
if (!op || !op.type) {
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
switch (op.type) {
|
|
212
|
+
case 'detachItem': {
|
|
213
|
+
const { itemId } = op;
|
|
214
|
+
this.items.remove(itemId);
|
|
215
|
+
this.updateVisibleItems(ownerInstance, instance);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
isChangesDifferent(newMap) {
|
|
221
|
+
if (!this.lastChanges) {
|
|
222
|
+
return true
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
let count = 0
|
|
226
|
+
for (const key in newMap) {
|
|
227
|
+
if (!(key in this.lastChanges)) return true
|
|
228
|
+
count++
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// 再检查 b 有没有多余 key
|
|
232
|
+
let countB = 0
|
|
233
|
+
for (const _ in this.lastChanges) countB++
|
|
234
|
+
|
|
235
|
+
return count !== countB
|
|
236
|
+
}
|
|
237
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1750676277859" class="icon" viewBox="0 0 1052 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="15883" xmlns:xlink="http://www.w3.org/1999/xlink" width="16" height="16"><path d="M142.989806 468.094235L514.938748 59.038122 450.02313 0l-438.619035 482.480939a43.861904 43.861904 0 0 0 0 59.038122l438.619035 482.480939 64.915618-59.038122-371.948942-409.143836H1052.685685v-87.723807H142.989806z" fill="#7b7c7e" p-id="15884"></path></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1750676141470" class="icon" viewBox="0 0 1049 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="9977" xmlns:xlink="http://www.w3.org/1999/xlink" width="16" height="16"><path d="M818.93731 882.886003a64.030784 64.030784 0 0 1-63.948694 63.948693H294.295334a64.030784 64.030784 0 0 1-63.948693-63.948693V204.159692h588.590669v678.726311zM358.572391 89.396825a12.888248 12.888248 0 0 1 13.134519-13.134519h307.019401a12.888248 12.888248 0 0 1 13.13452 13.134519v38.500562h-333.28844z m652.539361 38.500562h-242.988616v-38.500562A89.643098 89.643098 0 0 0 678.726311 0H371.378547a89.643098 89.643098 0 0 0-89.396825 89.396825v38.500562H38.41847a38.582652 38.582652 0 1 0 0 77.083213h114.927049v677.987494a141.031906 141.031906 0 0 0 141.031906 141.031906h460.611191a141.031906 141.031906 0 0 0 141.031907-141.031906V204.159692h114.927048a38.500561 38.500561 0 0 0 38.500561-38.582652 37.761744 37.761744 0 0 0-38.500561-37.679653z m-486.469777 703.353535a38.500561 38.500561 0 0 0 38.582652-38.500561V382.871252a38.582652 38.582652 0 1 0-77.083213 0v409.879109a38.41847 38.41847 0 0 0 38.500561 38.500561z m-179.450376 0a38.500561 38.500561 0 0 0 38.500561-38.500561V382.871252a38.582652 38.582652 0 1 0-77.083213 0v409.879109a39.567741 39.567741 0 0 0 38.500561 38.500561z m359.064935 0a38.500561 38.500561 0 0 0 38.500561-38.500561V382.871252a38.582652 38.582652 0 1 0-77.083213 0v409.879109a38.500561 38.500561 0 0 0 38.500561 38.500561z" fill="#748393" p-id="9978"></path></svg>
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import "core-js/modules/esnext.iterator.constructor.js";
|
|
2
|
+
import "core-js/modules/esnext.iterator.map.js";
|
|
3
|
+
import "core-js/modules/web.dom-collections.iterator.js";
|
|
4
|
+
import './index.less';
|
|
5
|
+
import { Button, View } from '@ray-js/components';
|
|
6
|
+
import React from 'react';
|
|
7
|
+
import { useAgentSessionValue, useChatAgent, useTranslate } from '../hooks';
|
|
8
|
+
const MessageActionBar = () => {
|
|
9
|
+
const [showSelect, setShowSelect] = useAgentSessionValue('UIRay.multiSelect.show');
|
|
10
|
+
const [selected] = useAgentSessionValue('UIRay.multiSelect.selected');
|
|
11
|
+
const t = useTranslate();
|
|
12
|
+
const agent = useChatAgent();
|
|
13
|
+
if (!showSelect) {
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
return /*#__PURE__*/React.createElement(View, {
|
|
17
|
+
className: "t-agent-message-action-bar"
|
|
18
|
+
}, /*#__PURE__*/React.createElement(Button, {
|
|
19
|
+
className: "t-agent-message-action-bar-button t-agent-message-action-bar-button-back",
|
|
20
|
+
onClick: () => {
|
|
21
|
+
setShowSelect(false);
|
|
22
|
+
}
|
|
23
|
+
}), /*#__PURE__*/React.createElement(Button, {
|
|
24
|
+
className: "t-agent-message-action-bar-button t-agent-message-action-bar-button-clean-all",
|
|
25
|
+
onClick: () => {
|
|
26
|
+
ty.showModal({
|
|
27
|
+
title: t('t-agent.message.clear-history.title'),
|
|
28
|
+
content: t('t-agent.message.clear-history.content'),
|
|
29
|
+
confirmText: t('t-agent.message.delete.confirm'),
|
|
30
|
+
cancelText: t('t-agent.message.delete.cancel'),
|
|
31
|
+
success: async res => {
|
|
32
|
+
if (res.confirm) {
|
|
33
|
+
ty.showLoading({
|
|
34
|
+
title: ''
|
|
35
|
+
});
|
|
36
|
+
const {
|
|
37
|
+
success
|
|
38
|
+
} = await agent.plugins.ui.callHook('onClearHistory', {});
|
|
39
|
+
ty.hideLoading();
|
|
40
|
+
if (success) {
|
|
41
|
+
setShowSelect(false);
|
|
42
|
+
ty.showToast({
|
|
43
|
+
title: t('t-agent.message.delete.success'),
|
|
44
|
+
icon: 'none'
|
|
45
|
+
});
|
|
46
|
+
} else {
|
|
47
|
+
ty.showToast({
|
|
48
|
+
title: t('t-agent.error.unknown-error'),
|
|
49
|
+
icon: 'error'
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
}, t('t-agent.message.clear-history.button')), /*#__PURE__*/React.createElement(Button, {
|
|
57
|
+
className: "t-agent-message-action-bar-button t-agent-message-action-bar-button-delete",
|
|
58
|
+
disabled: !selected.length,
|
|
59
|
+
onClick: () => {
|
|
60
|
+
ty.showModal({
|
|
61
|
+
title: t('t-agent.message.multi-select-delete.title'),
|
|
62
|
+
content: t('t-agent.message.multi-select-delete.content'),
|
|
63
|
+
confirmText: t('t-agent.message.delete.confirm'),
|
|
64
|
+
cancelText: t('t-agent.message.delete.cancel'),
|
|
65
|
+
success: async res => {
|
|
66
|
+
if (res.confirm) {
|
|
67
|
+
await Promise.all(selected.map(id => agent.removeMessage(id)));
|
|
68
|
+
setShowSelect(false);
|
|
69
|
+
ty.showToast({
|
|
70
|
+
title: t('t-agent.message.delete.success'),
|
|
71
|
+
icon: 'none'
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
}));
|
|
78
|
+
};
|
|
79
|
+
export default MessageActionBar;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
|
|
2
|
+
.t-agent-message-action-bar {
|
|
3
|
+
position: absolute;
|
|
4
|
+
display: flex;
|
|
5
|
+
bottom: 0;
|
|
6
|
+
left: 0;
|
|
7
|
+
right: 0;
|
|
8
|
+
z-index: 10;
|
|
9
|
+
height: calc(106rpx + var(--t-agent-safe-bottom));
|
|
10
|
+
|
|
11
|
+
--t-agent-action-bar-border-color: var(--app-B1-N7);
|
|
12
|
+
border-top: 2rpx solid var(--t-agent-action-bar-border-color);
|
|
13
|
+
background: var(--app-B1);
|
|
14
|
+
|
|
15
|
+
padding: 16rpx 32rpx calc(16rpx + var(--t-agent-safe-bottom));
|
|
16
|
+
align-items: center;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.t-agent-chat-container-keyboard-show .t-agent-message-action-bar {
|
|
20
|
+
height: 106rpx;
|
|
21
|
+
padding-bottom: 16rpx;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.t-agent-message-action-bar-button {
|
|
25
|
+
--button-size: 68rpx;
|
|
26
|
+
background: transparent;
|
|
27
|
+
|
|
28
|
+
border-radius: var(--button-size);
|
|
29
|
+
|
|
30
|
+
width: var(--button-size);
|
|
31
|
+
height: var(--button-size);
|
|
32
|
+
flex-basis: var(--button-size);
|
|
33
|
+
line-height: var(--button-size);
|
|
34
|
+
|
|
35
|
+
padding: 0;
|
|
36
|
+
margin: 0;
|
|
37
|
+
text-align: center;
|
|
38
|
+
color: transparent;
|
|
39
|
+
display: flex;
|
|
40
|
+
align-items: center;
|
|
41
|
+
justify-content: center;
|
|
42
|
+
|
|
43
|
+
background-size: contain;
|
|
44
|
+
background-origin: content-box;
|
|
45
|
+
|
|
46
|
+
&[disabled] {
|
|
47
|
+
opacity: 0.6;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.t-agent-message-action-bar-button-back {
|
|
52
|
+
background: url('./back.svg') no-repeat center;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.t-agent-message-action-bar-button-delete {
|
|
56
|
+
background: url('./delete.svg') no-repeat center;
|
|
57
|
+
&[disabled] {
|
|
58
|
+
background: transparent;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.t-agent-message-action-bar-button-clean-all {
|
|
63
|
+
flex: 1;
|
|
64
|
+
color: var(--app-M2-N1);
|
|
65
|
+
background: var(--app-M2);
|
|
66
|
+
margin: 0 32rpx;
|
|
67
|
+
font-weight: normal;
|
|
68
|
+
}
|
|
@@ -7,7 +7,7 @@ import '../index.less';
|
|
|
7
7
|
import { Button, View } from '@ray-js/components';
|
|
8
8
|
import React, { useRef, useState, useMemo } from 'react';
|
|
9
9
|
import { Image, Input, ScrollView } from '@ray-js/ray';
|
|
10
|
-
import { AbortController
|
|
10
|
+
import { AbortController } from '../../utils/abort';
|
|
11
11
|
import { Emitter, EmitterEvent, isAbortError } from '@ray-js/t-agent';
|
|
12
12
|
import cx from 'clsx';
|
|
13
13
|
import imageSvg from '../icons/image.svg';
|
|
@@ -19,6 +19,7 @@ import logger from '../../logger';
|
|
|
19
19
|
import { systemInfo } from '../../utils';
|
|
20
20
|
import { useSleep } from '../../hooks/useSleep';
|
|
21
21
|
import { useStableCallback } from '../../hooks/useStableCallback';
|
|
22
|
+
import { authorize } from '../../utils/ttt';
|
|
22
23
|
export let MessageInputState = /*#__PURE__*/function (MessageInputState) {
|
|
23
24
|
MessageInputState["PENDING"] = "pending";
|
|
24
25
|
MessageInputState["RECORDING"] = "recording";
|
|
@@ -239,7 +240,7 @@ export default function MessageInputAIStream(props) {
|
|
|
239
240
|
onClick: async () => {
|
|
240
241
|
const auth = await authorize({
|
|
241
242
|
scope: 'scope.record'
|
|
242
|
-
})
|
|
243
|
+
});
|
|
243
244
|
if (!auth) {
|
|
244
245
|
ty.showToast({
|
|
245
246
|
icon: 'none',
|
|
@@ -350,7 +351,7 @@ export default function MessageInputAIStream(props) {
|
|
|
350
351
|
}
|
|
351
352
|
if (dispatch(InputAction.ASR_ERROR, {})) {
|
|
352
353
|
var _error$detail;
|
|
353
|
-
if (((_error$detail = error.detail) === null || _error$detail === void 0 ? void 0 : _error$detail.code) === '
|
|
354
|
+
if (((_error$detail = error.detail) === null || _error$detail === void 0 ? void 0 : _error$detail.code) === 'asr-empty') {
|
|
354
355
|
ty.showToast({
|
|
355
356
|
icon: 'error',
|
|
356
357
|
title: t('t-agent.input.asr.error.empty')
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { Emitter } from '@ray-js/t-agent';
|
|
2
|
+
import { AsrListenerManager } from '../../utils/ttt';
|
|
3
|
+
export interface DetectResult {
|
|
4
|
+
/** managerId */
|
|
5
|
+
managerId: number;
|
|
6
|
+
/** 拾音状态 0. 未开启 1.进行中 2.结束 3.发送错误 */
|
|
7
|
+
state: number;
|
|
8
|
+
/** 语言转换内容 */
|
|
9
|
+
text: string;
|
|
10
|
+
/** 错误码 0. 录音时间太短 */
|
|
11
|
+
errorCode: number;
|
|
12
|
+
}
|
|
13
|
+
export declare enum AsrDetectResultState {
|
|
14
|
+
WAIT = 0,
|
|
15
|
+
MID = 1,
|
|
16
|
+
END = 2,
|
|
17
|
+
ERROR = 3
|
|
18
|
+
}
|
|
19
|
+
export declare class Asr {
|
|
20
|
+
static manager: AsrListenerManager | null;
|
|
21
|
+
static emitter: Emitter;
|
|
22
|
+
static authorize(): Promise<boolean>;
|
|
23
|
+
static createManager(): Promise<AsrListenerManager>;
|
|
24
|
+
static listener: (detail: DetectResult) => void;
|
|
25
|
+
static dispose: () => void;
|
|
26
|
+
static detect(callback: (params: DetectResult) => void): {
|
|
27
|
+
start(): Promise<void>;
|
|
28
|
+
stop(): Promise<void>;
|
|
29
|
+
};
|
|
30
|
+
}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import _defineProperty from "@babel/runtime/helpers/esm/defineProperty";
|
|
2
|
+
var _Asr;
|
|
3
|
+
import "core-js/modules/es.json.stringify.js";
|
|
4
|
+
import { Emitter, EmitterEvent } from '@ray-js/t-agent';
|
|
5
|
+
import logger from '../../logger';
|
|
6
|
+
import { authorize, getAppInfo, getAsrListenerManager, getCurrentHomeInfo } from '../../utils/ttt';
|
|
7
|
+
export let AsrDetectResultState = /*#__PURE__*/function (AsrDetectResultState) {
|
|
8
|
+
AsrDetectResultState[AsrDetectResultState["WAIT"] = 0] = "WAIT";
|
|
9
|
+
AsrDetectResultState[AsrDetectResultState["MID"] = 1] = "MID";
|
|
10
|
+
AsrDetectResultState[AsrDetectResultState["END"] = 2] = "END";
|
|
11
|
+
AsrDetectResultState[AsrDetectResultState["ERROR"] = 3] = "ERROR";
|
|
12
|
+
return AsrDetectResultState;
|
|
13
|
+
}({});
|
|
14
|
+
export class Asr {
|
|
15
|
+
// 录音权限
|
|
16
|
+
static authorize() {
|
|
17
|
+
return authorize({
|
|
18
|
+
scope: 'scope.record'
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
static async createManager() {
|
|
22
|
+
if (Asr.manager) {
|
|
23
|
+
return Asr.manager;
|
|
24
|
+
}
|
|
25
|
+
const {
|
|
26
|
+
homeId
|
|
27
|
+
} = await getCurrentHomeInfo();
|
|
28
|
+
const systemInfo = ty.getSystemInfoSync();
|
|
29
|
+
const appInfo = await getAppInfo();
|
|
30
|
+
const isCnApp = appInfo.regionCode === 'AY';
|
|
31
|
+
const lang = systemInfo.language;
|
|
32
|
+
const params = {
|
|
33
|
+
homeId,
|
|
34
|
+
sampleRate: isCnApp ? 16000 : 8000,
|
|
35
|
+
channels: 1,
|
|
36
|
+
codec: isCnApp ? 0 : 1,
|
|
37
|
+
options: JSON.stringify({
|
|
38
|
+
format: isCnApp ? 'wav' : 'mulaw',
|
|
39
|
+
lang,
|
|
40
|
+
channel: '1',
|
|
41
|
+
sampleRate: isCnApp ? '16000' : '8000',
|
|
42
|
+
realTimeAsr: 'true',
|
|
43
|
+
'asr.only': 'true'
|
|
44
|
+
})
|
|
45
|
+
};
|
|
46
|
+
logger.debug('Asr createManager', params);
|
|
47
|
+
Asr.manager = await getAsrListenerManager(params);
|
|
48
|
+
Asr.manager.onDetect(Asr.listener);
|
|
49
|
+
return Asr.manager;
|
|
50
|
+
}
|
|
51
|
+
static detect(callback) {
|
|
52
|
+
const listener = event => {
|
|
53
|
+
var _event$detail;
|
|
54
|
+
callback(event.detail);
|
|
55
|
+
if (((_event$detail = event.detail) === null || _event$detail === void 0 ? void 0 : _event$detail.state) === AsrDetectResultState.END) {
|
|
56
|
+
Asr.emitter.removeEventListener('result', listener);
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
const promise = Asr.createManager();
|
|
60
|
+
Asr.emitter.addEventListener('result', listener);
|
|
61
|
+
return {
|
|
62
|
+
start() {
|
|
63
|
+
logger.debug('Asr detect start');
|
|
64
|
+
return new Promise((resolve, reject) => {
|
|
65
|
+
promise.then(manager => {
|
|
66
|
+
manager.getAsrActive({
|
|
67
|
+
success: _ref => {
|
|
68
|
+
let {
|
|
69
|
+
isActive
|
|
70
|
+
} = _ref;
|
|
71
|
+
logger.debug('Asr manager.getAsrActive', isActive);
|
|
72
|
+
if (!isActive) {
|
|
73
|
+
manager.startDetect({
|
|
74
|
+
success: function (res) {
|
|
75
|
+
logger.debug('Asr startDetect success', res);
|
|
76
|
+
resolve();
|
|
77
|
+
},
|
|
78
|
+
fail: function (err) {
|
|
79
|
+
logger.error('Asr startDetect fail', err);
|
|
80
|
+
reject(err);
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
} else {
|
|
84
|
+
resolve();
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
failure: params => {
|
|
88
|
+
logger.error('Asr manager.getAsrActive failure', params);
|
|
89
|
+
reject(params);
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
},
|
|
95
|
+
async stop() {
|
|
96
|
+
const manager = await promise;
|
|
97
|
+
logger.debug('Asr detect stop');
|
|
98
|
+
await new Promise((resolve, reject) => {
|
|
99
|
+
manager.stopDetect({
|
|
100
|
+
success: resolve,
|
|
101
|
+
fail: reject
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
_Asr = Asr;
|
|
109
|
+
_defineProperty(Asr, "manager", null);
|
|
110
|
+
_defineProperty(Asr, "emitter", new Emitter());
|
|
111
|
+
_defineProperty(Asr, "listener", detail => {
|
|
112
|
+
const {
|
|
113
|
+
text,
|
|
114
|
+
state
|
|
115
|
+
} = detail;
|
|
116
|
+
logger.debug('Asr listener', detail);
|
|
117
|
+
_Asr.emitter.dispatchEvent(new EmitterEvent('result', {
|
|
118
|
+
detail
|
|
119
|
+
}));
|
|
120
|
+
});
|
|
121
|
+
_defineProperty(Asr, "dispose", () => {
|
|
122
|
+
if (_Asr.manager) {
|
|
123
|
+
_Asr.manager.offDetect(_Asr.listener);
|
|
124
|
+
_Asr.manager = null;
|
|
125
|
+
}
|
|
126
|
+
});
|
|
@@ -7,15 +7,16 @@ import '../index.less';
|
|
|
7
7
|
import { Button, View } from '@ray-js/components';
|
|
8
8
|
import React, { useRef, useState } from 'react';
|
|
9
9
|
import { Image, Input, ScrollView } from '@ray-js/ray';
|
|
10
|
-
import { Asr, AbortController } from '@ray-js/t-agent-plugin-assistant';
|
|
11
10
|
import cx from 'clsx';
|
|
12
11
|
import PrivateImage from '../../PrivateImage';
|
|
13
12
|
import imageSvg from '../icons/image.svg';
|
|
14
13
|
import videoSvg from '../icons/video.svg';
|
|
15
14
|
import loadingSvg from '../icons/loading.svg';
|
|
16
15
|
import closeCircleSvg from '../icons/close-circle.svg';
|
|
16
|
+
import { AbortController } from '../../utils/abort';
|
|
17
17
|
import { useAttachmentInput, useChatAgent, useEmitEvent, useIsUnmounted, useOnEvent, useRenderOptions, useTranslate } from '../../hooks';
|
|
18
18
|
import AsrInput from './AsrInput';
|
|
19
|
+
import { authorize } from '../../utils/ttt';
|
|
19
20
|
export default function MessageInputAssistant(props) {
|
|
20
21
|
const [moreOpen, setMoreOpen] = useState(false);
|
|
21
22
|
const t = useTranslate();
|
|
@@ -159,7 +160,9 @@ export default function MessageInputAssistant(props) {
|
|
|
159
160
|
}), /*#__PURE__*/React.createElement(Button, {
|
|
160
161
|
"data-testid": "t-agent-message-input-button-asr",
|
|
161
162
|
onClick: async () => {
|
|
162
|
-
const auth = await
|
|
163
|
+
const auth = await authorize({
|
|
164
|
+
scope: 'scope.record'
|
|
165
|
+
});
|
|
163
166
|
if (!auth) {
|
|
164
167
|
ty.showToast({
|
|
165
168
|
icon: 'none',
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import "core-js/modules/web.dom-collections.iterator.js";
|
|
2
2
|
import { useEffect, useRef, useState } from 'react';
|
|
3
|
-
import { Asr, AsrDetectResultState } from '
|
|
3
|
+
import { Asr, AsrDetectResultState } from './asr';
|
|
4
4
|
import { useIsUnmounted } from '../../hooks';
|
|
5
5
|
export let AsrErrorCode = /*#__PURE__*/function (AsrErrorCode) {
|
|
6
6
|
AsrErrorCode[AsrErrorCode["SHORT_TIME"] = 0] = "SHORT_TIME";
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import React, { ReactNode } from 'react';
|
|
2
|
+
interface PartOptions {
|
|
3
|
+
notifyHeightChanged: () => void;
|
|
4
|
+
}
|
|
5
|
+
export type RenderPart = ReactNode | ((options: PartOptions) => React.ReactNode);
|
|
6
|
+
interface Props {
|
|
7
|
+
scrollViewId: string;
|
|
8
|
+
notifyHeightChanged: () => void;
|
|
9
|
+
itemId: string;
|
|
10
|
+
children: RenderPart;
|
|
11
|
+
index: number;
|
|
12
|
+
show: boolean;
|
|
13
|
+
}
|
|
14
|
+
export declare function PartRender(props: Props): React.JSX.Element;
|
|
15
|
+
export {};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import "core-js/modules/web.dom-collections.iterator.js";
|
|
2
|
+
import LazyItem from '../LazyScrollView/LazyItem';
|
|
3
|
+
import React, { useState } from 'react';
|
|
4
|
+
export function PartRender(props) {
|
|
5
|
+
const {
|
|
6
|
+
scrollViewId,
|
|
7
|
+
children,
|
|
8
|
+
itemId,
|
|
9
|
+
index
|
|
10
|
+
} = props;
|
|
11
|
+
const [tick, setTick] = useState(() => "".concat(Math.random()));
|
|
12
|
+
const content = typeof children === 'function' ? children({
|
|
13
|
+
notifyHeightChanged: () => {
|
|
14
|
+
props.notifyHeightChanged();
|
|
15
|
+
setTick("".concat(Math.random()));
|
|
16
|
+
}
|
|
17
|
+
}) : children;
|
|
18
|
+
return /*#__PURE__*/React.createElement(LazyItem, {
|
|
19
|
+
scrollViewId: scrollViewId,
|
|
20
|
+
itemId: itemId,
|
|
21
|
+
update: tick,
|
|
22
|
+
ready: true,
|
|
23
|
+
index: index
|
|
24
|
+
}, content);
|
|
25
|
+
}
|
|
@@ -36,6 +36,7 @@ interface Props extends ScrollBottomViewOptions {
|
|
|
36
36
|
children: React.ReactNode;
|
|
37
37
|
style?: React.CSSProperties;
|
|
38
38
|
hideScrollbar?: boolean;
|
|
39
|
+
onChanged?: (changes: Record<string, boolean>) => void;
|
|
39
40
|
}
|
|
40
41
|
export interface ScrollBottomViewRef {
|
|
41
42
|
scrollToBottom: (options?: {
|