@ray-js/t-agent-ui-ray 0.2.0-beta-2 → 0.2.0-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.
@@ -12,6 +12,13 @@ import { defaultRenderOptions } from '../renderOption';
12
12
  import logger from '../logger';
13
13
  export default function ChatContainer(props) {
14
14
  const [keyboardHeight, setKeyboardHeight] = useState(0);
15
+ const [windowSize, setWindowSize] = useState(() => {
16
+ const info = ty.getSystemInfoSync();
17
+ return {
18
+ width: info.windowWidth,
19
+ height: info.windowHeight
20
+ };
21
+ });
15
22
  const {
16
23
  createAgent,
17
24
  renderOptions = defaultRenderOptions,
@@ -135,6 +142,17 @@ export default function ChatContainer(props) {
135
142
  const hide = () => {
136
143
  setKeyboardHeight(0);
137
144
  };
145
+ const resize = _ref4 => {
146
+ let {
147
+ size
148
+ } = _ref4;
149
+ setWindowSize({
150
+ width: size.windowWidth,
151
+ height: size.windowHeight
152
+ });
153
+ };
154
+ // @ts-ignore
155
+ ty.onWindowResize(resize);
138
156
  ty.onKeyboardWillShow(show);
139
157
  ty.onKeyboardWillHide(hide);
140
158
  ty.onKeyboardHeightChange(show);
@@ -142,12 +160,16 @@ export default function ChatContainer(props) {
142
160
  ty.offKeyboardWillShow(show);
143
161
  ty.offKeyboardWillHide(hide);
144
162
  ty.offKeyboardHeightChange(show);
163
+ // @ts-ignore
164
+ ty.offWindowResize(resize);
145
165
  };
146
166
  }, []);
147
167
  return /*#__PURE__*/React.createElement(View, {
148
168
  style: _objectSpread({
149
169
  // @ts-ignore
150
- '--t-agent-chat-container-keyboard-height': "".concat(keyboardHeight, "px")
170
+ '--t-agent-chat-container-keyboard-height': "".concat(keyboardHeight, "px"),
171
+ '--t-agent-chat-container-window-height': "".concat(windowSize.height, "px"),
172
+ '--t-agent-chat-container-window-width': "".concat(windowSize.width, "px")
151
173
  }, style),
152
174
  className: cx('t-agent-chat-container', className, {
153
175
  't-agent-chat-container-keyboard-show': keyboardHeight > 0
@@ -1,8 +1,5 @@
1
1
  import React from 'react';
2
- export declare const WaveformVisualizer: ({ amplitudeCount }: {
3
- amplitudeCount: number;
4
- }) => React.JSX.Element;
5
- interface IProps {
2
+ interface Props {
6
3
  amplitudeCount: number;
7
4
  recording: boolean;
8
5
  disabled?: boolean;
@@ -11,5 +8,5 @@ interface IProps {
11
8
  onCancel: () => void;
12
9
  onBack: () => void;
13
10
  }
14
- declare const AsrInput: (props: IProps) => React.JSX.Element;
11
+ declare const AsrInput: (props: Props) => React.JSX.Element;
15
12
  export default AsrInput;
@@ -1,109 +1,79 @@
1
- import "core-js/modules/es.regexp.exec.js";
2
- import "core-js/modules/esnext.iterator.constructor.js";
3
- import "core-js/modules/esnext.iterator.map.js";
4
1
  import "core-js/modules/web.dom-collections.iterator.js";
5
- import React, { useState } from 'react';
2
+ import React, { useRef, useState } from 'react';
6
3
  import { Button, View } from '@ray-js/ray';
7
4
  import cx from 'clsx';
8
- import { useOnEvent, useTranslate } from '../../hooks';
9
- export const WaveformVisualizer = _ref => {
10
- let {
11
- amplitudeCount
12
- } = _ref;
13
- const [bars, setBars] = useState(() => Array.from({
14
- length: amplitudeCount
15
- }, (_, index) => /*#__PURE__*/React.createElement(View
16
- // eslint-disable-next-line react/no-array-index-key
17
- , {
18
- key: "asr_wave_".concat(index),
19
- className: "t-agent-message-input-waveform-bar",
20
- style: {
21
- height: 0,
22
- // 添加渐变色偏移效果
23
- animationDelay: "".concat(index * 10, "ms")
24
- }
25
- })));
26
- useOnEvent('amplitudes', val => {
27
- const waveBase = val.body.amplitudes || [];
28
- const bars = waveBase.map((item, index) => {
29
- const value = item > 1 ? 1 : item * 100;
30
- // 将数值映射到高度范围(0-100 → 2px-20px)
31
- // const height = 2 + (value / 100) * 18;
32
- return /*#__PURE__*/React.createElement(View
33
- // eslint-disable-next-line react/no-array-index-key
34
- , {
35
- key: "asr_wave_".concat(index),
36
- className: "t-agent-message-input-waveform-bar t-agent-item",
37
- style: {
38
- height: "".concat(value, "%"),
39
- // 添加渐变色偏移效果
40
- animationDelay: "".concat(index * 10, "ms")
41
- }
42
- });
43
- });
44
- setBars(bars);
45
- });
46
- return /*#__PURE__*/React.createElement(View, {
47
- className: "t-agent-message-input-waveform-container"
48
- }, bars);
49
- };
5
+ import { useTranslate } from '../../hooks';
6
+ import { WaveformVisualizer } from './WaveformVisualizer';
7
+ import { useSleep } from '../../hooks/useSleep';
50
8
  const AsrInput = props => {
51
- const [asrElementBounds, setAsrElementBounds] = useState(null);
9
+ const touchRef = useRef({
10
+ startAt: 0,
11
+ y: 0
12
+ });
13
+ useSleep();
52
14
  const t = useTranslate();
53
- const [ptt, setPtt] = useState(false);
54
- const onVoiceTouchEnd = e => {
55
- const touch = e.origin.changedTouches[0];
56
- const touchY = touch.clientY;
57
- setPtt(false);
58
- // 误触状态
59
- if (!asrElementBounds) {
60
- setTimeout(() => {
61
- props.onCancel();
62
- }, 200);
63
- setAsrElementBounds(null);
15
+ const [active, setActive] = useState(false);
16
+ const [cancel, setCancel] = useState(false);
17
+ const onVoiceTouchEnd = event => {
18
+ const touchY = event.changedTouches[0].pageY;
19
+ setCancel(false);
20
+ setActive(false);
21
+ if (touchRef.current.y - touchY > 100) {
22
+ touchRef.current = {
23
+ startAt: 0,
24
+ y: 0
25
+ };
26
+ props.onCancel();
64
27
  return;
65
28
  }
66
- // 上滑取消
67
- if (touchY < asrElementBounds.top - 100) {
68
- setTimeout(() => {
69
- props.onCancel();
70
- }, 200);
71
- setAsrElementBounds(null);
29
+ if (Date.now() - touchRef.current.startAt < 500) {
30
+ // 这种情况是误触
31
+ touchRef.current = {
32
+ startAt: 0,
33
+ y: 0
34
+ };
35
+ props.onCancel();
72
36
  return;
73
37
  }
74
- setTimeout(() => {
75
- props.onConfirm();
76
- }, 200);
77
- setAsrElementBounds(null);
38
+ props.onConfirm();
78
39
  };
79
- return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(View, {
40
+ return /*#__PURE__*/React.createElement(View, {
41
+ className: "t-agent-message-input-ptt-bar"
42
+ }, /*#__PURE__*/React.createElement(View, {
80
43
  className: cx('t-agent-message-input-ptt', {
81
- 't-agent-message-input-ptt-handle': ptt
44
+ 't-agent-message-input-ptt-active': active,
45
+ 't-agent-message-input-ptt-cancel': cancel
82
46
  }),
83
- onTouchStart: () => {
84
- const query = ty.createSelectorQuery();
85
- query.select('.t-agent-message-input-ptt').boundingClientRect(rect => {
86
- if (!rect) return;
87
- setAsrElementBounds(rect);
88
- }).exec();
89
- setPtt(true);
90
- setTimeout(() => {
91
- props.onRecord();
92
- }, 200);
47
+ onTouchStart: async event => {
48
+ var _event$touches$;
49
+ touchRef.current = {
50
+ startAt: Date.now(),
51
+ y: (_event$touches$ = event.touches[0]) === null || _event$touches$ === void 0 ? void 0 : _event$touches$.pageY
52
+ };
53
+ setActive(true);
54
+ props.onRecord();
55
+ },
56
+ onTouchMove: event => {
57
+ const touch = event.touches[0];
58
+ const touchY = touch.pageY;
59
+ setCancel(touchRef.current.y - touchY > 100);
93
60
  },
94
61
  onTouchCancel: onVoiceTouchEnd,
95
62
  onTouchEnd: onVoiceTouchEnd
96
- }, props.recording ? /*#__PURE__*/React.createElement(View, {
97
- className: "t-agent-message-input-oninput"
98
63
  }, /*#__PURE__*/React.createElement(View, {
99
- className: "t-agent-message-input-oninput-text-top"
64
+ className: "t-agent-message-input-ptt-text"
65
+ }, " ", t('t-agent.input.asr.ptt')), /*#__PURE__*/React.createElement(View, {
66
+ className: cx('t-agent-message-input-ptt-overlay', {
67
+ 't-agent-message-input-ptt-overlay-active': active,
68
+ 't-agent-message-input-ptt-overlay-cancel': cancel
69
+ })
70
+ }, /*#__PURE__*/React.createElement(View, {
71
+ className: "t-agent-message-input-ptt-active-text-top"
100
72
  }, t('t-agent.input.asr.oninput.text.top')), /*#__PURE__*/React.createElement(View, {
101
- className: "t-agent-message-input-oninput-text-center"
73
+ className: "t-agent-message-input-ptt-active-text-center"
102
74
  }, t('t-agent.input.asr.oninput.text.center')), /*#__PURE__*/React.createElement(WaveformVisualizer, {
103
75
  amplitudeCount: props.amplitudeCount
104
- })) : /*#__PURE__*/React.createElement(View, {
105
- className: "t-agent-message-input-ptt-text"
106
- }, " ", t('t-agent.input.asr.ptt'))), !props.recording && /*#__PURE__*/React.createElement(Button, {
76
+ }))), !props.recording && /*#__PURE__*/React.createElement(Button, {
107
77
  className: "t-agent-message-input-button t-agent-message-input-button-keyboard",
108
78
  "data-testid": "t-agent-message-input-button-asr",
109
79
  onClick: props.onBack
@@ -0,0 +1,4 @@
1
+ import React from 'react';
2
+ export declare const WaveformVisualizer: ({ amplitudeCount }: {
3
+ amplitudeCount: number;
4
+ }) => React.JSX.Element;
@@ -0,0 +1,47 @@
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 React, { useState } from 'react';
5
+ import { View } from '@ray-js/ray';
6
+ import { useOnEvent } from '../../hooks';
7
+ export const WaveformVisualizer = _ref => {
8
+ let {
9
+ amplitudeCount
10
+ } = _ref;
11
+ const [bars, setBars] = useState(() => Array.from({
12
+ length: amplitudeCount
13
+ }, (_, index) => /*#__PURE__*/React.createElement(View
14
+ // eslint-disable-next-line react/no-array-index-key
15
+ , {
16
+ key: "asr_wave_".concat(index),
17
+ className: "t-agent-message-input-waveform-bar",
18
+ style: {
19
+ height: 0,
20
+ // 添加渐变色偏移效果
21
+ animationDelay: "".concat(index * 10, "ms")
22
+ }
23
+ })));
24
+ useOnEvent('amplitudes', val => {
25
+ const waveBase = val.body.amplitudes || [];
26
+ const bars = waveBase.map((item, index) => {
27
+ const value = item > 1 ? 1 : item * 100;
28
+ // 将数值映射到高度范围(0-100 → 2px-20px)
29
+ // const height = 2 + (value / 100) * 18;
30
+ return /*#__PURE__*/React.createElement(View
31
+ // eslint-disable-next-line react/no-array-index-key
32
+ , {
33
+ key: "asr_wave_".concat(index),
34
+ className: "t-agent-message-input-waveform-bar",
35
+ style: {
36
+ height: "".concat(value, "%"),
37
+ // 添加渐变色偏移效果
38
+ animationDelay: "".concat(index * 10, "ms")
39
+ }
40
+ });
41
+ });
42
+ setBars(bars);
43
+ });
44
+ return /*#__PURE__*/React.createElement(View, {
45
+ className: "t-agent-message-input-waveform-container"
46
+ }, bars);
47
+ };
@@ -14,8 +14,9 @@ import imageSvg from '../icons/image.svg';
14
14
  import videoSvg from '../icons/video.svg';
15
15
  import loadingSvg from '../icons/loading.svg';
16
16
  import closeCircleSvg from '../icons/close-circle.svg';
17
- import { useAttachmentInput, useChatAgent, useEmitEvent, useIsUnmounted, useOnEvent, useTranslate } from '../../hooks';
17
+ import { useAgentSessionValue, useAttachmentInput, useChatAgent, useEmitEvent, useIsUnmounted, useOnEvent, useTranslate } from '../../hooks';
18
18
  import AsrInput from './AsrInput';
19
+ import { useSleep } from '../../hooks/useSleep';
19
20
  const AMPLITUDE_COUNT = 60;
20
21
  export default function MessageInputAIStream(props) {
21
22
  const [moreOpen, setMoreOpen] = useState(false);
@@ -50,9 +51,10 @@ export default function MessageInputAIStream(props) {
50
51
  setResponding(false);
51
52
  }
52
53
  });
53
- const isMore = !text.trim().length && true;
54
+ const [hasMore] = useAgentSessionValue('multiModal');
55
+ const isMore = !text.trim().length && hasMore;
54
56
  const send = async inputBlocks => {
55
- if (!(inputBlocks !== null && inputBlocks !== void 0 && inputBlocks.length) || attachmentInput.uploading || responding) {
57
+ if (!(inputBlocks !== null && inputBlocks !== void 0 && inputBlocks.length)) {
56
58
  return;
57
59
  }
58
60
  setUploaded([]);
@@ -63,8 +65,8 @@ export default function MessageInputAIStream(props) {
63
65
  ac.signal.addEventListener('abort', () => {
64
66
  if (acRef.current === ac) {
65
67
  acRef.current = null;
68
+ setResponding(false);
66
69
  }
67
- setResponding(false);
68
70
  });
69
71
  try {
70
72
  await agent.pushInputBlocks(inputBlocks, ac.signal);
@@ -131,7 +133,9 @@ export default function MessageInputAIStream(props) {
131
133
  });
132
134
  }
133
135
  };
136
+ const sleep = useSleep();
134
137
  let container;
138
+ const canSend = text.trim().length && !responding && !attachmentInput.uploading;
135
139
  if (mode === 'text') {
136
140
  container = /*#__PURE__*/React.createElement(View, {
137
141
  className: "t-agent-message-input-text-bar"
@@ -145,7 +149,7 @@ export default function MessageInputAIStream(props) {
145
149
  "data-testid": "t-agent-message-input-text-inner",
146
150
  className: "t-agent-message-input-text-inner",
147
151
  onConfirm: () => {
148
- if (text.trim().length) {
152
+ if (canSend) {
149
153
  send([...attachmentInput.blocks, {
150
154
  type: 'text',
151
155
  text
@@ -193,7 +197,7 @@ export default function MessageInputAIStream(props) {
193
197
  }
194
198
  } else if (isMore) {
195
199
  openMoreClick();
196
- } else if (text.trim().length) {
200
+ } else if (canSend) {
197
201
  await send([...attachmentInput.blocks, {
198
202
  type: 'text',
199
203
  text
@@ -202,21 +206,24 @@ export default function MessageInputAIStream(props) {
202
206
  }
203
207
  }));
204
208
  } else {
205
- container = /*#__PURE__*/React.createElement(View, {
206
- className: "t-agent-message-input-text-bar"
207
- }, /*#__PURE__*/React.createElement(View, {
208
- className: "t-agent-message-input-text-group"
209
- }, /*#__PURE__*/React.createElement(AsrInput, {
209
+ container = /*#__PURE__*/React.createElement(AsrInput, {
210
210
  disabled: responding,
211
211
  amplitudeCount: AMPLITUDE_COUNT,
212
212
  recording: record.recording,
213
213
  onRecord: async () => {
214
+ if (attachmentInput.uploading) {
215
+ return;
216
+ }
217
+ if (responding && acRef.current) {
218
+ acRef.current.abort('User abort');
219
+ // 中断后等待一会再开始
220
+ await sleep(50);
221
+ }
214
222
  const emitter = new Emitter();
215
223
  setRecord({
216
224
  startAt: Date.now(),
217
225
  recording: true,
218
226
  confirm: () => {
219
- console.log('setRecord confirm');
220
227
  emitter.dispatchEvent(new EmitterEvent('confirm'));
221
228
  setRecord({
222
229
  startAt: 0,
@@ -226,7 +233,6 @@ export default function MessageInputAIStream(props) {
226
233
  });
227
234
  },
228
235
  cancel: () => {
229
- console.log('setRecord cancel');
230
236
  emitter.dispatchEvent(new EmitterEvent('cancel'));
231
237
  setRecord({
232
238
  startAt: 0,
@@ -237,7 +243,6 @@ export default function MessageInputAIStream(props) {
237
243
  }
238
244
  });
239
245
  emitter.addEventListener('error', event => {
240
- console.log('setRecord error');
241
246
  ty.showToast({
242
247
  icon: 'error',
243
248
  title: t('t-agent.input.voice.recording-failed')
@@ -250,7 +255,6 @@ export default function MessageInputAIStream(props) {
250
255
  cancel: null
251
256
  });
252
257
  });
253
- console.log('setRecord send');
254
258
  await send([...attachmentInput.blocks, {
255
259
  type: 'audio',
256
260
  audio_emitter: emitter,
@@ -259,16 +263,14 @@ export default function MessageInputAIStream(props) {
259
263
  },
260
264
  onConfirm: () => {
261
265
  var _record$confirm;
262
- console.log('test onConfirm');
263
266
  (_record$confirm = record.confirm) === null || _record$confirm === void 0 || _record$confirm.call(record);
264
267
  },
265
268
  onCancel: () => {
266
269
  var _record$cancel;
267
- console.log('test onCancel');
268
270
  (_record$cancel = record.cancel) === null || _record$cancel === void 0 || _record$cancel.call(record);
269
271
  },
270
272
  onBack: () => setMode('text')
271
- })));
273
+ });
272
274
  }
273
275
  return /*#__PURE__*/React.createElement(View, {
274
276
  className: "".concat(props.className || '', " t-agent-message-input"),
@@ -147,11 +147,12 @@
147
147
  }
148
148
 
149
149
  .t-agent-message-input-button-keyboard {
150
- background: transparent url('icons/keyboard.svg') no-repeat center;
150
+ border: 2rpx solid var(--t-agent-input-border-color);
151
+ background: transparent url('icons/text.svg') no-repeat center;
151
152
  position: absolute;
152
153
  top: 50%;
153
154
  transform: translateY(-50%);
154
- right: 10rpx;
155
+ right: 32rpx;
155
156
  }
156
157
 
157
158
  .t-agent-message-input-button-stop {
@@ -314,37 +315,64 @@
314
315
  min-height: 56rpx;
315
316
  }
316
317
 
317
- @transition-duration: 0.3s;
318
+ .t-agent-message-input-ptt-bar {
319
+ padding: 16rpx 32rpx;
320
+ position: relative;
321
+ }
318
322
 
319
323
  .t-agent-message-input-ptt {
320
324
  background: transparent;
321
325
  padding: 0;
322
326
  border: none;
323
- height: 56rpx;
327
+ height: 72rpx;
324
328
  display: flex;
325
329
  justify-content: center;
326
330
  align-items: center;
327
- transition: height @transition-duration ease-in-out; // 定义高度变化的过渡效果
328
- }
329
-
330
- .t-agent-message-input-ptt-handle {
331
- height: 224rpx;
331
+ transition: height 0.3s ease-in-out; // 定义高度变化的过渡效果
332
332
  }
333
333
 
334
334
  .t-agent-message-input-ptt-text {
335
335
  font-size: 32rpx;
336
336
  line-height: 56rpx;
337
- color: var(--app-M1-B1);
337
+ color: var(--app-B1-N1);
338
338
  text-align: center;
339
339
  }
340
340
 
341
- .t-agent-message-input-oninput-text-top {
341
+ .t-agent-message-input-ptt-overlay-cancel {
342
+
343
+ }
344
+
345
+ .t-agent-message-input-ptt-overlay {
346
+ position: absolute;
347
+ height: 100%;
348
+ left: 0;
349
+ right: 0;
350
+ bottom: 0;
351
+ background-color: var(--app-B1);
352
+ pointer-events: none;
353
+ opacity: 0;
354
+ display: flex;
355
+ flex-direction: column;
356
+ justify-content: center;
357
+ border-top: 2rpx solid var(--t-agent-input-border-color);
358
+ z-index: 2;
359
+ transition: opacity 0s ease 0.1s, height 0.3s ease;
360
+
361
+ &.t-agent-message-input-ptt-overlay-active {
362
+ transition: opacity 0s ease 0s, height 0.3s ease;
363
+ opacity: 1;
364
+ height: calc(100% + 150rpx);
365
+ }
366
+ }
367
+
368
+ .t-agent-message-input-ptt-active-text-top {
342
369
  font-size: 32rpx;
343
370
  line-height: 56rpx;
344
371
  color: var(--app-M1-B1);
345
372
  text-align: center;
346
373
  }
347
- .t-agent-message-input-oninput-text-center {
374
+
375
+ .t-agent-message-input-ptt-active-text-center {
348
376
  font-size: 20rpx;
349
377
  color: var(--app-M1-B1);
350
378
  text-align: center;
@@ -365,7 +393,7 @@
365
393
  background-color: var(--app-M4);
366
394
  border-radius: 2rpx;
367
395
  transition: height 0.3s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.3s ease;
368
- animation: colorPulse 2s infinite;
396
+ animation: t-agent-message-input-waveform-bar-color-pulse 2s infinite;
369
397
  margin-right: 4rpx;
370
398
  opacity: 1;
371
399
 
@@ -374,7 +402,7 @@
374
402
  }
375
403
  }
376
404
 
377
- @keyframes colorPulse {
405
+ @keyframes t-agent-message-input-waveform-bar-color-pulse {
378
406
  0% {
379
407
  opacity: 1;
380
408
  }
@@ -10,7 +10,7 @@ interface Props {
10
10
  assistant?: 'start' | 'end' | string;
11
11
  [key: string]: 'start' | 'end' | string;
12
12
  };
13
- multSelect?: {
13
+ multiSelect?: {
14
14
  show: boolean;
15
15
  select: string[];
16
16
  onSelect: (msgs: string[]) => void;
@@ -21,7 +21,7 @@ export default function MessageList(props) {
21
21
  wrapperClassName,
22
22
  wrapperStyle,
23
23
  historyLimit,
24
- multSelect
24
+ multiSelect
25
25
  } = props;
26
26
  const {
27
27
  messages
@@ -104,7 +104,7 @@ export default function MessageList(props) {
104
104
  side = msg.role === 'user' ? 'end' : 'start';
105
105
  }
106
106
  return /*#__PURE__*/React.createElement(MessageRender, {
107
- multSelect: multSelect,
107
+ multiSelect: multiSelect,
108
108
  key: msg.id,
109
109
  message: msg,
110
110
  isLatestMessage: index === 0,
@@ -5,11 +5,11 @@ interface Props {
5
5
  message: ChatMessageObject;
6
6
  isLatestMessage: boolean;
7
7
  side: 'start' | 'end' | string;
8
- multSelect?: {
8
+ multiSelect?: {
9
9
  show: boolean;
10
10
  select: string[];
11
11
  onSelect: (msgs: string[]) => void;
12
12
  };
13
13
  }
14
- export default function MessageRender({ message, isLatestMessage, side, multSelect }: Props): React.JSX.Element;
14
+ export default function MessageRender({ message, isLatestMessage, side, multiSelect }: Props): React.JSX.Element;
15
15
  export {};
@@ -11,7 +11,7 @@ export default function MessageRender(_ref) {
11
11
  message,
12
12
  isLatestMessage,
13
13
  side,
14
- multSelect
14
+ multiSelect
15
15
  } = _ref;
16
16
  const {
17
17
  id,
@@ -20,8 +20,8 @@ export default function MessageRender(_ref) {
20
20
  const {
21
21
  select = [],
22
22
  onSelect = () => {},
23
- show: showMultSelect = false
24
- } = multSelect || {};
23
+ show: showMultiSelect = false
24
+ } = multiSelect || {};
25
25
  if (tiles.length === 0) {
26
26
  return /*#__PURE__*/React.createElement(View, {
27
27
  key: id,
@@ -31,7 +31,7 @@ export default function MessageRender(_ref) {
31
31
  return /*#__PURE__*/React.createElement(View, {
32
32
  key: id,
33
33
  className: "t-agent-message-list-row-container "
34
- }, showMultSelect && /*#__PURE__*/React.createElement(View, {
34
+ }, showMultiSelect && /*#__PURE__*/React.createElement(View, {
35
35
  className: "t-agent-message-list-row-check"
36
36
  }, /*#__PURE__*/React.createElement(View, {
37
37
  className: "checkbox-container ".concat(select.includes(id) ? 'selected' : ''),
@@ -1,3 +1,4 @@
1
+ import { Dispatch, SetStateAction } from 'react';
1
2
  import { TTTAction } from '../types';
2
3
  export declare const useChatAgent: () => import("../contexts").UIChatAgent;
3
4
  export declare const useAgentMessage: () => {
@@ -9,3 +10,4 @@ export declare const useOnEvent: (eventName: string, callback: (details: any) =>
9
10
  export declare const useEmitEvent: () => <T extends keyof import("@ray-js/t-agent").UIEventMap>(eventName: T, detail: import("@ray-js/t-agent").UIEventMap[T]) => void;
10
11
  export declare const useTileProps: () => import("../types").TileProps<any, any>;
11
12
  export declare const useSendAction: () => (action: TTTAction) => void;
13
+ export declare const useAgentSessionValue: <S = any>(key: string) => readonly [S, Dispatch<SetStateAction<S>>];
@@ -1,4 +1,5 @@
1
- import { useEffect, useContext, useCallback, useRef } from 'react';
1
+ import "core-js/modules/web.dom-collections.iterator.js";
2
+ import { useEffect, useContext, useCallback, useRef, useState } from 'react';
2
3
  import { TilePropsContext, ChatAgentContext, MessageContext, RenderContext } from '../contexts';
3
4
  export const useChatAgent = () => {
4
5
  return useContext(ChatAgentContext);
@@ -42,4 +43,26 @@ export const useSendAction = () => {
42
43
  agent.plugins.ui.emitEvent('runTTTAction', action);
43
44
  }, [agent]);
44
45
  return emitTileEvent ? tileSendAction : uiSendAction;
46
+ };
47
+ export const useAgentSessionValue = key => {
48
+ const agent = useChatAgent();
49
+ const [value, setValue] = useState(() => agent.session.get(key));
50
+ const set = useCallback(value => {
51
+ if (typeof value === 'function') {
52
+ const prev = agent.session.get(key);
53
+ value = value(prev);
54
+ }
55
+ agent.session.set(key, value);
56
+ setValue(value);
57
+ }, []);
58
+ useOnEvent('sessionChange', _ref => {
59
+ let {
60
+ key: k,
61
+ value
62
+ } = _ref;
63
+ if (k === key) {
64
+ setValue(value);
65
+ }
66
+ });
67
+ return [value, set];
45
68
  };
@@ -3,4 +3,4 @@ export * from './useAttachmentInput';
3
3
  export * from './useIsUnmounted';
4
4
  export * from './useLongPress';
5
5
  export * from './useTranslate';
6
- export * from './useMultSelect';
6
+ export * from './useMultiSelect';
@@ -3,4 +3,4 @@ export * from './useAttachmentInput';
3
3
  export * from './useIsUnmounted';
4
4
  export * from './useLongPress';
5
5
  export * from './useTranslate';
6
- export * from './useMultSelect';
6
+ export * from './useMultiSelect';
@@ -2,7 +2,7 @@ import { ChatMessageObject } from '@ray-js/t-agent';
2
2
  /**
3
3
  * 预定义动作类型
4
4
  */
5
- export type ActionType = 'copy' | 'delete' | 'like' | 'unlike' | 'deleteByChannel' | 'multSelect';
5
+ export type ActionType = 'copy' | 'delete' | 'like' | 'unlike' | 'deleteByChannel' | 'multiSelect';
6
6
  export interface ActionMenuItem {
7
7
  key: string;
8
8
  label: string;
@@ -23,7 +23,7 @@ export interface LongPressActionMenuProps {
23
23
  }
24
24
  export interface UseLongPressOptions {
25
25
  message?: ChatMessageObject;
26
- actions?: ActionType | ActionType[];
26
+ actions?: ActionType | ActionType[] | string[];
27
27
  getMessageContent?: () => string;
28
28
  customActions?: ActionMenuItem[];
29
29
  disabled?: boolean;
@@ -20,7 +20,7 @@ export function useLongPress() {
20
20
  let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
21
21
  const {
22
22
  message,
23
- actions = ['copy', 'multSelect', 'delete'],
23
+ actions = ['copy', 'multiSelect', 'delete'],
24
24
  getMessageContent = () => '',
25
25
  customActions = [],
26
26
  disabled = false
@@ -79,12 +79,12 @@ export function useLongPress() {
79
79
  });
80
80
  }
81
81
  break;
82
- case 'multSelect':
82
+ case 'multiSelect':
83
83
  menuItems.push({
84
- key: 'multSelect',
85
- label: t('t-agent.message.action.multSelect'),
84
+ key: 'multiSelect',
85
+ label: t('t-agent.message.action.multiSelect'),
86
86
  action: () => {
87
- emitEvent('multSelect', {});
87
+ emitEvent('multiSelect', {});
88
88
  }
89
89
  });
90
90
  break;
@@ -115,32 +115,33 @@ export function useLongPress() {
115
115
  });
116
116
  }
117
117
  break;
118
- case 'deleteByChannel':
119
- menuItems.push({
120
- key: 'deleteByChannel',
121
- label: t('t-agent.message.action.deleteByChannel'),
122
- action: () => {
123
- // const channel = agent.session.get('AIAssistant.channel');
124
- // const { removeMessageByChannel } = agent.plugins.assistant;
125
- // if (typeof removeMessageByChannel === 'function') {
126
- // removeMessageByChannel(channel);
127
- // }
128
- }
129
- });
130
- break;
131
118
  case 'like':
132
119
  menuItems.push({
133
120
  key: 'like',
134
121
  label: t('t-agent.message.action.like'),
135
122
  action: async () => {
136
- // const { feedback } = agent.plugins.assistant;
137
- // if (typeof feedback === 'function') {
138
- // await feedback({ requestId: message.id, type: 'like' });
139
- // ty.showToast({
140
- // title: t('t-agent.message.like.success'),
141
- // icon: 'none',
142
- // });
143
- // }
123
+ try {
124
+ const result = await agent.plugins.ui.callHook('onMessageFeedback', {
125
+ messageId: message.id,
126
+ rate: 'like'
127
+ });
128
+ if (result !== null && result !== void 0 && result.success) {
129
+ ty.showToast({
130
+ title: t('t-agent.message.like.success'),
131
+ icon: 'none'
132
+ });
133
+ } else {
134
+ ty.showToast({
135
+ title: t('t-agent.unknown-error'),
136
+ icon: 'none'
137
+ });
138
+ }
139
+ } catch (error) {
140
+ ty.showToast({
141
+ title: (error === null || error === void 0 ? void 0 : error.message) || t('t-agent.unknown-error'),
142
+ icon: 'none'
143
+ });
144
+ }
144
145
  }
145
146
  });
146
147
  break;
@@ -149,14 +150,28 @@ export function useLongPress() {
149
150
  key: 'unlike',
150
151
  label: t('t-agent.message.action.unlike'),
151
152
  action: async () => {
152
- // const { feedback } = agent.plugins.assistant;
153
- // if (typeof feedback === 'function') {
154
- // await feedback({ requestId: message.id, type: 'unlike' });
155
- // ty.showToast({
156
- // title: t('t-agent.message.unlike.success'),
157
- // icon: 'none',
158
- // });
159
- // }
153
+ try {
154
+ const result = await agent.plugins.ui.callHook('onMessageFeedback', {
155
+ messageId: message.id,
156
+ rate: 'unlike'
157
+ });
158
+ if (result !== null && result !== void 0 && result.success) {
159
+ ty.showToast({
160
+ title: t('t-agent.message.unlike.success'),
161
+ icon: 'none'
162
+ });
163
+ } else {
164
+ ty.showToast({
165
+ title: t('t-agent.unknown-error'),
166
+ icon: 'none'
167
+ });
168
+ }
169
+ } catch (error) {
170
+ ty.showToast({
171
+ title: (error === null || error === void 0 ? void 0 : error.message) || t('t-agent.unknown-error'),
172
+ icon: 'none'
173
+ });
174
+ }
160
175
  }
161
176
  });
162
177
  break;
@@ -217,9 +232,11 @@ export function useLongPress() {
217
232
  isClosing: false,
218
233
  menuPosition: adjustedPosition
219
234
  });
220
- ty.vibrateShort({
221
- type: 'light'
222
- });
235
+ if (ty.getSystemInfoSync().brand !== 'devtools') {
236
+ ty.vibrateShort({
237
+ type: 'light'
238
+ });
239
+ }
223
240
  if (e.origin && e.origin.stopPropagation) {
224
241
  e.origin.stopPropagation();
225
242
  }
@@ -1,5 +1,5 @@
1
1
  /// <reference types="react" />
2
- export declare const useMultSelectMessage: () => {
2
+ export declare const useMultiSelectMessage: () => {
3
3
  show: boolean;
4
4
  select: string[];
5
5
  onSelect: import("react").Dispatch<import("react").SetStateAction<string[]>>;
@@ -1,6 +1,6 @@
1
1
  import "core-js/modules/web.dom-collections.iterator.js";
2
2
  import { useState } from 'react';
3
- export const useMultSelectMessage = () => {
3
+ export const useMultiSelectMessage = () => {
4
4
  const [select, setSelect] = useState([]);
5
5
  const [show, setShow] = useState(false);
6
6
  return {
@@ -25,7 +25,7 @@ declare const _default: {
25
25
  't-agent.message.action.copy': string;
26
26
  't-agent.message.action.delete': string;
27
27
  't-agent.message.action.deleteByChannel': string;
28
- 't-agent.message.action.multSelect': string;
28
+ 't-agent.message.action.multiSelect': string;
29
29
  't-agent.message.like.success': string;
30
30
  't-agent.message.unlike.success': string;
31
31
  't-agent.message.action.like': string;
@@ -66,6 +66,7 @@ declare const _default: {
66
66
  't-agent.expand.scene.one-click': string;
67
67
  't-agent.expand.scene.auto': string;
68
68
  't-agent.expand.no.details': string;
69
+ 't-agent.unknown-error': string;
69
70
  };
70
71
  'zh-Hant': {
71
72
  't-agent.build-in.button.create_scene_manually': string;
@@ -157,7 +158,7 @@ declare const _default: {
157
158
  't-agent.message.action.copy': string;
158
159
  't-agent.message.action.delete': string;
159
160
  't-agent.message.action.deleteByChannel': string;
160
- 't-agent.message.action.multSelect': string;
161
+ 't-agent.message.action.multiSelect': string;
161
162
  't-agent.message.like.success': string;
162
163
  't-agent.message.unlike.success': string;
163
164
  't-agent.message.action.like': string;
@@ -198,6 +199,7 @@ declare const _default: {
198
199
  't-agent.expand.scene.one-click': string;
199
200
  't-agent.expand.scene.auto': string;
200
201
  't-agent.expand.no.details': string;
202
+ 't-agent.unknown-error': string;
201
203
  };
202
204
  ja: {
203
205
  't-agent.build-in.button.create_scene_manually': string;
@@ -25,7 +25,7 @@ export default {
25
25
  't-agent.message.action.copy': '复制消息',
26
26
  't-agent.message.action.delete': '删除消息',
27
27
  't-agent.message.action.deleteByChannel': '删除所有渠道消息',
28
- 't-agent.message.action.multSelect': '多选',
28
+ 't-agent.message.action.multiSelect': '多选',
29
29
  't-agent.message.like.success': '点赞成功',
30
30
  't-agent.message.unlike.success': '取消点赞成功',
31
31
  't-agent.message.action.like': '喜欢消息',
@@ -65,7 +65,8 @@ export default {
65
65
  't-agent.expand.scene.rename': '{oldName}改名成{newName}',
66
66
  't-agent.expand.scene.one-click': '一键执行',
67
67
  't-agent.expand.scene.auto': '自动执行',
68
- 't-agent.expand.no.details': '没有可显示的详情内容'
68
+ 't-agent.expand.no.details': '没有可显示的详情内容',
69
+ 't-agent.unknown-error': '未知错误'
69
70
  },
70
71
  'zh-Hant': {
71
72
  't-agent.build-in.button.create_scene_manually': '手動創建場景',
@@ -160,7 +161,7 @@ export default {
160
161
  't-agent.message.action.copy': 'Copy Message',
161
162
  't-agent.message.action.delete': 'Delete Message',
162
163
  't-agent.message.action.deleteByChannel': 'Delete All Channel Messages',
163
- 't-agent.message.action.multSelect': 'Multiple Selection',
164
+ 't-agent.message.action.multiSelect': 'Multiple Selection',
164
165
  't-agent.message.like.success': 'Like Successful',
165
166
  't-agent.message.unlike.success': 'Unlike Successful',
166
167
  't-agent.message.action.like': 'Like Message',
@@ -200,7 +201,8 @@ export default {
200
201
  't-agent.expand.scene.rename': '{oldName} renamed to {newName}',
201
202
  't-agent.expand.scene.one-click': 'One-click Execution',
202
203
  't-agent.expand.scene.auto': 'Automatic Execution',
203
- 't-agent.expand.no.details': 'No details available'
204
+ 't-agent.expand.no.details': 'No details available',
205
+ 't-agent.unknown-error': 'Unknown Error'
204
206
  },
205
207
  ja: {
206
208
  't-agent.build-in.button.create_scene_manually': 'シーンを手動で作成',
@@ -1,23 +1,21 @@
1
1
  import _extends from "@babel/runtime/helpers/esm/extends";
2
- import "core-js/modules/es.json.stringify.js";
3
2
  import "core-js/modules/esnext.iterator.constructor.js";
4
3
  import "core-js/modules/esnext.iterator.find.js";
5
4
  import "core-js/modules/esnext.iterator.map.js";
6
5
  import "core-js/modules/esnext.iterator.some.js";
7
- import "core-js/modules/web.dom-collections.iterator.js";
8
6
  import './index.less';
9
7
  import { View } from '@ray-js/components';
10
- import React, { useEffect, useState, useCallback, memo } from 'react';
8
+ import React, { useCallback, memo } from 'react';
11
9
  import { Image } from '@ray-js/ray';
12
- import { BubbleTileStatus, ChatMessageStatus, safeParseJSON } from '@ray-js/t-agent';
10
+ import { BubbleTileStatus, ChatMessageStatus } from '@ray-js/t-agent';
13
11
  import TileRender from '../../TileRender';
14
12
  import noticeSvg from './notice.svg';
15
13
  import noticeWarnSvg from './notice-warn.svg';
16
14
  import { useChatAgent, useTranslate, useLongPress, useRenderOptions } from '../../hooks';
17
15
  import RollBack from '../WorkflowTile/RollBack';
18
16
  const BubbleTile = props => {
19
- var _message$meta$request, _workflowTile$data;
20
- const agent = useChatAgent();
17
+ var _workflowTile$data;
18
+ useChatAgent();
21
19
  const {
22
20
  renderLongPressAs
23
21
  } = useRenderOptions();
@@ -38,30 +36,6 @@ const BubbleTile = props => {
38
36
  const bubbleStatus = data.status || BubbleTileStatus.NORMAL;
39
37
  const t = useTranslate();
40
38
  const loading = status === ChatMessageStatus.START || status === ChatMessageStatus.UPDATING;
41
- isLatestMessage && status === ChatMessageStatus.FINISH && role === 'assistant' && ((_message$meta$request = message.meta.requestId) === null || _message$meta$request === void 0 ? void 0 : _message$meta$request.startsWith('AIAssistant')) && bubbleStatus === BubbleTileStatus.NORMAL;
42
- const [feedbackLoaded, setFeedbackLoaded] = useState(false);
43
- const [feedbackValue, setFeedbackValue] = useState(null);
44
- useEffect(() => {
45
- ty.getStorage({
46
- key: 'latestMessageFeedbackValue',
47
- success: res => {
48
- if (res.data) {
49
- try {
50
- const {
51
- requestId,
52
- value
53
- } = safeParseJSON(res.data);
54
- if (requestId === message.meta.requestId) {
55
- setFeedbackValue(value);
56
- }
57
- } catch (e) {
58
- // noop
59
- }
60
- }
61
- setFeedbackLoaded(true);
62
- }
63
- });
64
- }, []);
65
39
  const showInfo = () => {
66
40
  if (data.info) {
67
41
  ty.showToast({
@@ -90,12 +64,7 @@ const BubbleTile = props => {
90
64
  }, [tile]);
91
65
  const longPressRes = useLongPress({
92
66
  message,
93
- // actions: [
94
- // 'copy',
95
- // 'delete',
96
- // ...(isAssistantMessage ? ['like', 'unlike', 'deleteByChannel'] : []),
97
- // ] as ActionType[],
98
- actions: ['copy', 'multSelect', 'delete'],
67
+ actions: ['copy', 'multiSelect', 'delete', 'like', 'unlike'],
99
68
  getMessageContent,
100
69
  disabled: loading
101
70
  });
@@ -1,5 +1,5 @@
1
- import React from 'react';
2
1
  import './index.less';
2
+ import React from 'react';
3
3
  export default function RollBack(props: {
4
4
  nodeId: string;
5
5
  }): React.JSX.Element;
@@ -1,28 +1,22 @@
1
+ import './index.less';
1
2
  import { Image, View } from '@ray-js/ray';
2
3
  import React from 'react';
3
4
  import rollback from './workflow-rollback.png';
4
- import { useChatAgent } from '../../../hooks';
5
- import './index.less';
5
+ import { useTileProps } from '../../../hooks';
6
6
  export default function RollBack(props) {
7
7
  const {
8
8
  nodeId
9
9
  } = props;
10
- const agent = useChatAgent();
10
+ const {
11
+ emitTileEvent
12
+ } = useTileProps();
11
13
  return /*#__PURE__*/React.createElement(View, {
12
14
  className: "t-agent-workflow-rollback-tile",
13
15
  onClick: async () => {
14
- agent.session.get('AIAssistant.channel');
15
- const systemInfo = ty.getSystemInfoSync();
16
- systemInfo.language; // await agent.plugins.assistant.runSkill('hi', 'assistant', {
17
- // channel,
18
- // domain: 'control',
19
- // intent: 'backNode',
20
- // lang,
21
- // 'back.node.id': nodeId,
22
- // device_id: undefined,
23
- // 'text.stream': 'true',
24
- // 'tts.disable': 'true',
25
- // });
16
+ emitTileEvent({
17
+ type: 'rollback',
18
+ nodeId
19
+ });
26
20
  }
27
21
  }, /*#__PURE__*/React.createElement(Image, {
28
22
  src: rollback,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ray-js/t-agent-ui-ray",
3
- "version": "0.2.0-beta-2",
3
+ "version": "0.2.0-beta-3",
4
4
  "author": "Tuya.inc",
5
5
  "license": "MIT",
6
6
  "private": false,
@@ -40,5 +40,5 @@
40
40
  "@types/echarts": "^4.9.22",
41
41
  "@types/markdown-it": "^14.1.1"
42
42
  },
43
- "gitHead": "0784a0f440b67cc1f766a440dbad5350f633dfb1"
43
+ "gitHead": "03c4af7fe4cfe27069db83d99a61042c8053399e"
44
44
  }