react-native-chatbot-ai 0.1.38 → 0.1.40
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/lib/module/components/Drawer/RenameSessionPopup.js +2 -1
- package/lib/module/components/Drawer/RenameSessionPopup.js.map +1 -1
- package/lib/module/components/Drawer/SessionOptionsBottomSheet.js +1 -1
- package/lib/module/components/Drawer/SessionOptionsBottomSheet.js.map +1 -1
- package/lib/module/components/chat/ChatEmpty.js +2 -6
- package/lib/module/components/chat/ChatEmpty.js.map +1 -1
- package/lib/module/components/chat/ChatMessageList.js +21 -30
- package/lib/module/components/chat/ChatMessageList.js.map +1 -1
- package/lib/module/components/chat/footer/index.js +17 -11
- package/lib/module/components/chat/footer/index.js.map +1 -1
- package/lib/module/components/chat/item/ChatAIAnswerMessageItem.js +7 -1
- package/lib/module/components/chat/item/ChatAIAnswerMessageItem.js.map +1 -1
- package/lib/module/components/chat/item/ChatAIThinkingMessageItem.js +1 -6
- package/lib/module/components/chat/item/ChatAIThinkingMessageItem.js.map +1 -1
- package/lib/module/components/chat/item/index.js +5 -5
- package/lib/module/components/chat/item/index.js.map +1 -1
- package/lib/module/components/portal/Popup.js +6 -0
- package/lib/module/components/portal/Popup.js.map +1 -1
- package/lib/module/components/product/CardHorizontal.js +1 -1
- package/lib/module/components/product/CardHorizontal.js.map +1 -1
- package/lib/module/constants/events.js +0 -1
- package/lib/module/constants/events.js.map +1 -1
- package/lib/module/hooks/message/useMessage.js +22 -10
- package/lib/module/hooks/message/useMessage.js.map +1 -1
- package/lib/module/hooks/message/useSendMessage.js +1 -1
- package/lib/module/hooks/message/useSendMessage.js.map +1 -1
- package/lib/module/hooks/message/useStreamMessage.js +10 -12
- package/lib/module/hooks/message/useStreamMessage.js.map +1 -1
- package/lib/typescript/src/components/chat/ChatMessageList.d.ts.map +1 -1
- package/lib/typescript/src/components/chat/footer/index.d.ts.map +1 -1
- package/lib/typescript/src/components/chat/item/ChatAIAnswerMessageItem.d.ts.map +1 -1
- package/lib/typescript/src/components/chat/item/ChatAIThinkingMessageItem.d.ts.map +1 -1
- package/lib/typescript/src/components/chat/item/index.d.ts +2 -2
- package/lib/typescript/src/components/chat/item/index.d.ts.map +1 -1
- package/lib/typescript/src/components/portal/Popup.d.ts.map +1 -1
- package/lib/typescript/src/constants/events.d.ts +0 -1
- package/lib/typescript/src/constants/events.d.ts.map +1 -1
- package/lib/typescript/src/hooks/message/useMessage.d.ts.map +1 -1
- package/lib/typescript/src/hooks/message/useSendMessage.d.ts.map +1 -1
- package/lib/typescript/src/hooks/message/useStreamMessage.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/components/Drawer/RenameSessionPopup.tsx +1 -0
- package/src/components/Drawer/SessionOptionsBottomSheet.tsx +1 -1
- package/src/components/chat/ChatEmpty.tsx +2 -2
- package/src/components/chat/ChatMessageList.tsx +21 -32
- package/src/components/chat/footer/index.tsx +16 -12
- package/src/components/chat/item/ChatAIAnswerMessageItem.tsx +12 -2
- package/src/components/chat/item/ChatAIThinkingMessageItem.tsx +1 -7
- package/src/components/chat/item/index.tsx +6 -6
- package/src/components/portal/Popup.tsx +4 -1
- package/src/components/product/CardHorizontal.tsx +1 -1
- package/src/constants/events.ts +0 -1
- package/src/hooks/message/useMessage.ts +27 -14
- package/src/hooks/message/useSendMessage.ts +5 -1
- package/src/hooks/message/useStreamMessage.ts +25 -15
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { KColors, KContainer, KLabel, KSpacingValue } from '@droppii/libs';
|
|
2
|
-
import { StyleSheet
|
|
2
|
+
import { StyleSheet } from 'react-native';
|
|
3
3
|
import { useFetchSuggestions } from '../../hooks/suggestions/useFetchSuggestions';
|
|
4
4
|
import SuggestionItem from './SuggestionItem';
|
|
5
5
|
import { useSendMessage } from '../../hooks/message/useSendMessage';
|
|
@@ -72,7 +72,7 @@ const styles = StyleSheet.create({
|
|
|
72
72
|
gap: KSpacingValue['0.5rem'],
|
|
73
73
|
},
|
|
74
74
|
transformStyle: {
|
|
75
|
-
transform: [Platform.OS === 'android' ? { scale: -1 } : { scaleY: -1 }],
|
|
75
|
+
// transform: [Platform.OS === 'android' ? { scale: -1 } : { scaleY: -1 }],
|
|
76
76
|
},
|
|
77
77
|
disclaimer: {
|
|
78
78
|
fontSize: 11,
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { FlatList, StyleSheet,
|
|
1
|
+
import { FlatList, StyleSheet, View } from 'react-native';
|
|
2
2
|
import type { ComponentType } from 'react';
|
|
3
3
|
import { useCallback, useRef, useEffect, useState } from 'react';
|
|
4
4
|
import ChatEmpty from './ChatEmpty';
|
|
5
5
|
import ChatItem from './item';
|
|
6
6
|
import { KSpacingValue, KColors, KImage, KContainer } from '@droppii/libs';
|
|
7
7
|
import type { IMessageItem } from '../../types';
|
|
8
|
-
import {
|
|
8
|
+
import { GAEvents } from '../../constants/events';
|
|
9
9
|
import { useChatContext } from '../../context/ChatContext';
|
|
10
10
|
import useSessionStore from '../../store/session';
|
|
11
11
|
|
|
@@ -25,37 +25,18 @@ const ChatMessageList = ({ messageList = [] }: IChatMessageListProps) => {
|
|
|
25
25
|
|
|
26
26
|
const onScroll = useCallback((event: any) => {
|
|
27
27
|
const offsetY = event?.nativeEvent?.contentOffset?.y ?? 0;
|
|
28
|
+
const layoutHeight = event?.nativeEvent?.layoutMeasurement?.height ?? 0;
|
|
29
|
+
const contentHeight = event?.nativeEvent?.contentSize?.height ?? 0;
|
|
28
30
|
scrollOffsetRef.current = offsetY;
|
|
29
31
|
|
|
30
|
-
const threshold =
|
|
31
|
-
|
|
32
|
+
const threshold = 20;
|
|
33
|
+
const atBottom = layoutHeight + offsetY >= contentHeight - threshold;
|
|
34
|
+
setShowScrollToBottom(!atBottom);
|
|
32
35
|
}, []);
|
|
33
36
|
|
|
34
|
-
const scrollToBottom = useCallback(() => {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
useEffect(() => {
|
|
39
|
-
const subExpandThinkingStep = DeviceEventEmitter.addListener(
|
|
40
|
-
events.expandThinkingStep,
|
|
41
|
-
(isExpand: boolean) => {
|
|
42
|
-
try {
|
|
43
|
-
const scrollToOffset = flatListRef.current?.scrollToOffset({
|
|
44
|
-
offset: scrollOffsetRef.current + (isExpand ? 60 : -60),
|
|
45
|
-
animated: true,
|
|
46
|
-
});
|
|
47
|
-
setTimeout(() => {
|
|
48
|
-
scrollToOffset?.();
|
|
49
|
-
}, 100);
|
|
50
|
-
} catch (error) {
|
|
51
|
-
console.error(error);
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
);
|
|
55
|
-
|
|
56
|
-
return () => {
|
|
57
|
-
subExpandThinkingStep.remove();
|
|
58
|
-
};
|
|
37
|
+
const scrollToBottom = useCallback(async () => {
|
|
38
|
+
await new Promise((resolve) => setTimeout(resolve, 300));
|
|
39
|
+
flatListRef.current?.scrollToEnd({ animated: true });
|
|
59
40
|
}, []);
|
|
60
41
|
|
|
61
42
|
useEffect(() => {
|
|
@@ -68,6 +49,12 @@ const ChatMessageList = ({ messageList = [] }: IChatMessageListProps) => {
|
|
|
68
49
|
}
|
|
69
50
|
}, [sessionId, logGA]);
|
|
70
51
|
|
|
52
|
+
useEffect(() => {
|
|
53
|
+
if (messageList.length > 0) {
|
|
54
|
+
scrollToBottom();
|
|
55
|
+
}
|
|
56
|
+
}, [messageList, scrollToBottom]);
|
|
57
|
+
|
|
71
58
|
return (
|
|
72
59
|
<View style={{ flex: 1 }}>
|
|
73
60
|
<FlatListComponent
|
|
@@ -79,10 +66,12 @@ const ChatMessageList = ({ messageList = [] }: IChatMessageListProps) => {
|
|
|
79
66
|
}: {
|
|
80
67
|
item: IMessageItem;
|
|
81
68
|
index: number;
|
|
82
|
-
}) =>
|
|
69
|
+
}) => (
|
|
70
|
+
<ChatItem item={item} isLastItem={index === messageList.length - 1} />
|
|
71
|
+
)}
|
|
83
72
|
keyExtractor={(item: IMessageItem) => item.id}
|
|
84
73
|
contentContainerStyle={styles.container}
|
|
85
|
-
inverted
|
|
74
|
+
// inverted
|
|
86
75
|
ListEmptyComponent={<ChatEmpty />}
|
|
87
76
|
onScroll={onScroll}
|
|
88
77
|
scrollEventThrottle={16}
|
|
@@ -111,7 +100,7 @@ const styles = StyleSheet.create({
|
|
|
111
100
|
flexGrow: 1,
|
|
112
101
|
gap: KSpacingValue['0.5rem'],
|
|
113
102
|
paddingVertical: KSpacingValue['1rem'],
|
|
114
|
-
justifyContent: 'flex-end',
|
|
103
|
+
// justifyContent: 'flex-end',
|
|
115
104
|
},
|
|
116
105
|
scrollButton: {
|
|
117
106
|
position: 'absolute',
|
|
@@ -54,6 +54,7 @@ const ChatFooter = ({ lastMessage }: IChatFooterProps) => {
|
|
|
54
54
|
const logGA = useChatContext().logGA;
|
|
55
55
|
const { onSendMessage } = useSendMessage();
|
|
56
56
|
const [message, setMessage] = useState('');
|
|
57
|
+
const sessionId = useSessionStore((state) => state.sessionId);
|
|
57
58
|
const isStreaming = useStreamMessageStore((state) => state.isStreaming);
|
|
58
59
|
const stopStream = useStreamMessageStore((state) => state.stopStream);
|
|
59
60
|
|
|
@@ -103,6 +104,7 @@ const ChatFooter = ({ lastMessage }: IChatFooterProps) => {
|
|
|
103
104
|
}, [onPressImagePicker, onPressCameraPicker]);
|
|
104
105
|
|
|
105
106
|
const onPressSend = useCallback(() => {
|
|
107
|
+
if (isDisabledSend) return;
|
|
106
108
|
if (isStreaming) {
|
|
107
109
|
stopStream();
|
|
108
110
|
logGA(GAEvents.chatDetailStopChatBtnTap, {
|
|
@@ -132,6 +134,7 @@ const ChatFooter = ({ lastMessage }: IChatFooterProps) => {
|
|
|
132
134
|
fileUpload,
|
|
133
135
|
logGA,
|
|
134
136
|
clearFileUpload,
|
|
137
|
+
isDisabledSend,
|
|
135
138
|
]);
|
|
136
139
|
|
|
137
140
|
const renderUploadItem = useCallback(
|
|
@@ -164,7 +167,7 @@ const ChatFooter = ({ lastMessage }: IChatFooterProps) => {
|
|
|
164
167
|
return () => {
|
|
165
168
|
stopStream();
|
|
166
169
|
};
|
|
167
|
-
}, [stopStream]);
|
|
170
|
+
}, [stopStream, sessionId]);
|
|
168
171
|
|
|
169
172
|
return (
|
|
170
173
|
<KContainer.View style={styles.container}>
|
|
@@ -239,17 +242,18 @@ const ChatFooter = ({ lastMessage }: IChatFooterProps) => {
|
|
|
239
242
|
/>
|
|
240
243
|
</KContainer.Touchable>
|
|
241
244
|
<KContainer.View flex />
|
|
242
|
-
<
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
245
|
+
<KContainer.View style={{ opacity: isDisabledSend ? 0.5 : 1 }}>
|
|
246
|
+
<KButton.Solid
|
|
247
|
+
kind="primary"
|
|
248
|
+
icon={{
|
|
249
|
+
vectorName: isStreaming ? 'square-b' : 'send-b',
|
|
250
|
+
size: 20,
|
|
251
|
+
tintColor: KColors.white,
|
|
252
|
+
}}
|
|
253
|
+
onPress={onPressSend}
|
|
254
|
+
br="round"
|
|
255
|
+
/>
|
|
256
|
+
</KContainer.View>
|
|
253
257
|
</KContainer.View>
|
|
254
258
|
</KContainer.View>
|
|
255
259
|
</KContainer.View>
|
|
@@ -199,7 +199,11 @@ class CustomRenderer extends Renderer implements RendererInterface {
|
|
|
199
199
|
);
|
|
200
200
|
default:
|
|
201
201
|
return (
|
|
202
|
-
<KLabel.Text
|
|
202
|
+
<KLabel.Text
|
|
203
|
+
typo="TextMdNormal"
|
|
204
|
+
key={this.getKey()}
|
|
205
|
+
selectable={true}
|
|
206
|
+
>
|
|
203
207
|
{match?.[2] || ''}
|
|
204
208
|
</KLabel.Text>
|
|
205
209
|
);
|
|
@@ -225,6 +229,7 @@ class CustomRenderer extends Renderer implements RendererInterface {
|
|
|
225
229
|
key={this.getKey()}
|
|
226
230
|
typo="TextMdNormal"
|
|
227
231
|
color={KColors.black}
|
|
232
|
+
selectable={true}
|
|
228
233
|
>
|
|
229
234
|
{text}
|
|
230
235
|
</KLabel.Text>
|
|
@@ -237,6 +242,7 @@ class CustomRenderer extends Renderer implements RendererInterface {
|
|
|
237
242
|
key={this.getKey()}
|
|
238
243
|
typo="TextMdNormal"
|
|
239
244
|
color={KColors.black}
|
|
245
|
+
selectable={true}
|
|
240
246
|
>
|
|
241
247
|
{text}
|
|
242
248
|
</KLabel.Text>
|
|
@@ -250,6 +256,7 @@ class CustomRenderer extends Renderer implements RendererInterface {
|
|
|
250
256
|
typo="TextMdBold"
|
|
251
257
|
style={styles.mdStrong}
|
|
252
258
|
color={KColors.black}
|
|
259
|
+
selectable={true}
|
|
253
260
|
>
|
|
254
261
|
{children}
|
|
255
262
|
</KLabel.Text>
|
|
@@ -262,6 +269,7 @@ class CustomRenderer extends Renderer implements RendererInterface {
|
|
|
262
269
|
typo="TextMdNormal"
|
|
263
270
|
style={styles.mdEm}
|
|
264
271
|
color={KColors.black}
|
|
272
|
+
selectable={true}
|
|
265
273
|
>
|
|
266
274
|
{children}
|
|
267
275
|
</KLabel.Text>
|
|
@@ -286,6 +294,7 @@ class CustomRenderer extends Renderer implements RendererInterface {
|
|
|
286
294
|
typo="TextMdNormal"
|
|
287
295
|
style={textStyle}
|
|
288
296
|
color={KColors.gray.dark}
|
|
297
|
+
selectable={true}
|
|
289
298
|
>
|
|
290
299
|
{text}
|
|
291
300
|
</KLabel.Text>
|
|
@@ -500,10 +509,11 @@ const ChatAIAnswerMessageItem = ({
|
|
|
500
509
|
))}
|
|
501
510
|
|
|
502
511
|
{/* Message Actions Bar */}
|
|
512
|
+
|
|
503
513
|
<MessageActionsBar
|
|
504
514
|
messageId={item.id}
|
|
505
515
|
messageContent={item.content}
|
|
506
|
-
isVisible={!isStreaming}
|
|
516
|
+
isVisible={!isStreaming || (isStreaming && !isLast)}
|
|
507
517
|
productImages={productImages}
|
|
508
518
|
message={item}
|
|
509
519
|
/>
|
|
@@ -8,14 +8,13 @@ import {
|
|
|
8
8
|
} from '@droppii/libs';
|
|
9
9
|
import FastImage from '@d11/react-native-fast-image';
|
|
10
10
|
import type { IMessageItem } from '../../../types';
|
|
11
|
-
import { StyleSheet
|
|
11
|
+
import { StyleSheet } from 'react-native';
|
|
12
12
|
import { ReactNode, useCallback, useEffect, useRef, useState } from 'react';
|
|
13
13
|
import { IconThinkingStep } from '../../../assets/svgIcon/IconThinkingStep';
|
|
14
14
|
import { IconChatArrow } from '../../../assets/svgIcon/IconChatArrow';
|
|
15
15
|
import useStreamMessageStore from '../../../store/streamMessage';
|
|
16
16
|
import Markdown, { Renderer, RendererInterface } from 'react-native-marked';
|
|
17
17
|
import icons from '../../../assets/icons';
|
|
18
|
-
import { events } from '../../../constants/events';
|
|
19
18
|
import { trans } from '../../../translation';
|
|
20
19
|
|
|
21
20
|
interface ChatAIThinkingMessageItemProps {
|
|
@@ -91,10 +90,6 @@ const ChatAIThinkingMessageItem = ({
|
|
|
91
90
|
const [display, setDisplay] = useState('');
|
|
92
91
|
const indexRef = useRef(0);
|
|
93
92
|
|
|
94
|
-
const onPressExpandThinkingStep = useCallback((expand: boolean) => {
|
|
95
|
-
DeviceEventEmitter.emit(events.expandThinkingStep, expand);
|
|
96
|
-
}, []);
|
|
97
|
-
|
|
98
93
|
const renderHeader = useCallback(() => {
|
|
99
94
|
return (
|
|
100
95
|
<KContainer.View style={styles.header}>
|
|
@@ -158,7 +153,6 @@ const ChatAIThinkingMessageItem = ({
|
|
|
158
153
|
containerStyle={styles.container}
|
|
159
154
|
headerStyle={styles.mHeader}
|
|
160
155
|
defaultValue={true}
|
|
161
|
-
onChangeValue={onPressExpandThinkingStep}
|
|
162
156
|
>
|
|
163
157
|
{renderThinkingContent()}
|
|
164
158
|
</KListItem.Accordion>
|
|
@@ -5,18 +5,18 @@ import ChatUserMessageItem from './ChatUserMessageItem';
|
|
|
5
5
|
|
|
6
6
|
interface ChatItemProps {
|
|
7
7
|
item: IMessageItem;
|
|
8
|
-
|
|
8
|
+
isLastItem: boolean;
|
|
9
9
|
}
|
|
10
|
-
const ChatItem = ({ item,
|
|
10
|
+
const ChatItem = ({ item, isLastItem = false }: ChatItemProps) => {
|
|
11
11
|
switch (item.type) {
|
|
12
12
|
case MessageType.user_message:
|
|
13
|
-
return <ChatUserMessageItem item={item} isLast={
|
|
13
|
+
return <ChatUserMessageItem item={item} isLast={isLastItem} />;
|
|
14
14
|
case MessageType.ai_answer:
|
|
15
|
-
return <ChatAIAnswerMessageItem item={item} isLast={
|
|
15
|
+
return <ChatAIAnswerMessageItem item={item} isLast={isLastItem} />;
|
|
16
16
|
case MessageType.ai_thinking:
|
|
17
|
-
return <ChatAIThinkingMessageItem item={item} isLast={
|
|
17
|
+
return <ChatAIThinkingMessageItem item={item} isLast={isLastItem} />;
|
|
18
18
|
default:
|
|
19
|
-
return <ChatUserMessageItem item={item} isLast={
|
|
19
|
+
return <ChatUserMessageItem item={item} isLast={isLastItem} />;
|
|
20
20
|
}
|
|
21
21
|
};
|
|
22
22
|
|
|
@@ -45,6 +45,7 @@ import {
|
|
|
45
45
|
import { Z_INDEX_PRIORITY } from '../../constants';
|
|
46
46
|
import { ScrollView } from 'react-native-gesture-handler';
|
|
47
47
|
import { WithPopupProps } from '../../types';
|
|
48
|
+
import { useReanimatedKeyboardAnimation } from 'react-native-keyboard-controller';
|
|
48
49
|
|
|
49
50
|
const UNIT = KSpacingValue['1rem'];
|
|
50
51
|
const STATUS_BAR_HEIGHT = KDims.os === 'ios' ? 0 : StatusBar.currentHeight || 0;
|
|
@@ -248,8 +249,10 @@ const Popup = forwardRef<WithPopupProps>((_, ref) => {
|
|
|
248
249
|
e.stopPropagation();
|
|
249
250
|
}, []);
|
|
250
251
|
|
|
252
|
+
const { height } = useReanimatedKeyboardAnimation();
|
|
253
|
+
|
|
251
254
|
const rStyle = useAnimatedStyle(() => ({
|
|
252
|
-
transform: [{ scale: scale.value }],
|
|
255
|
+
transform: [{ scale: scale.value }, { translateY: height.value / 2 }],
|
|
253
256
|
}));
|
|
254
257
|
|
|
255
258
|
if (!data) {
|
package/src/constants/events.ts
CHANGED
|
@@ -28,8 +28,7 @@ export const useMessage = () => {
|
|
|
28
28
|
if (!res) return;
|
|
29
29
|
setLoadState((prev) => ({
|
|
30
30
|
...res,
|
|
31
|
-
messages:
|
|
32
|
-
res?.messages?.length > 0 ? res.messages.reverse() : prev.messages,
|
|
31
|
+
messages: res?.messages?.length > 0 ? res.messages : prev.messages,
|
|
33
32
|
}));
|
|
34
33
|
}, [sessionId, getSessionById]);
|
|
35
34
|
|
|
@@ -44,8 +43,12 @@ export const useMessage = () => {
|
|
|
44
43
|
useEffect(() => {
|
|
45
44
|
const subOneMessage = DeviceEventEmitter.addListener(
|
|
46
45
|
events.updateOneMessage,
|
|
47
|
-
(messageItem: IMessageItem) => {
|
|
46
|
+
(messageItem: IMessageItem, sID?: string) => {
|
|
48
47
|
setLoadState((prev) => {
|
|
48
|
+
if (sID !== prev.id) {
|
|
49
|
+
return prev;
|
|
50
|
+
}
|
|
51
|
+
|
|
49
52
|
const messageIndex = prev.messages.findIndex(
|
|
50
53
|
(m) => m.id === messageItem.id
|
|
51
54
|
);
|
|
@@ -65,7 +68,7 @@ export const useMessage = () => {
|
|
|
65
68
|
|
|
66
69
|
return {
|
|
67
70
|
...prev,
|
|
68
|
-
messages: [
|
|
71
|
+
messages: [...prev.messages, messageItem],
|
|
69
72
|
};
|
|
70
73
|
});
|
|
71
74
|
}
|
|
@@ -73,23 +76,29 @@ export const useMessage = () => {
|
|
|
73
76
|
|
|
74
77
|
const subMultipleMessage = DeviceEventEmitter.addListener(
|
|
75
78
|
events.updateMultipleMessage,
|
|
76
|
-
(messageItems: IMessageItem[]) => {
|
|
79
|
+
(messageItems: IMessageItem[], sID?: string) => {
|
|
77
80
|
setLoadState((prev) => {
|
|
81
|
+
if (sID !== prev.id) {
|
|
82
|
+
return prev;
|
|
83
|
+
}
|
|
84
|
+
|
|
78
85
|
const existingIds = new Set(prev.messages.map((m) => m?.id));
|
|
79
|
-
const filtered = messageItems
|
|
80
|
-
.filter((m) => !existingIds.has(m?.id))
|
|
81
|
-
.reverse();
|
|
86
|
+
const filtered = messageItems.filter((m) => !existingIds.has(m?.id));
|
|
82
87
|
return {
|
|
83
88
|
...prev,
|
|
84
|
-
messages: [...
|
|
89
|
+
messages: [...prev.messages, ...filtered],
|
|
85
90
|
};
|
|
86
91
|
});
|
|
87
92
|
}
|
|
88
93
|
);
|
|
89
94
|
const subForceUpdateMessages = DeviceEventEmitter.addListener(
|
|
90
95
|
events.forceUpdateMessages,
|
|
91
|
-
(messages: IMessageItem[]) => {
|
|
96
|
+
(messages: IMessageItem[], sID?: string) => {
|
|
92
97
|
setLoadState((prev) => {
|
|
98
|
+
if (sID !== prev.id) {
|
|
99
|
+
return prev;
|
|
100
|
+
}
|
|
101
|
+
|
|
93
102
|
const merged = prev.messages.map((msg) => {
|
|
94
103
|
const update = messages.find((u) => u.id === msg.id);
|
|
95
104
|
return update ? { ...msg, ...update } : msg;
|
|
@@ -99,23 +108,27 @@ export const useMessage = () => {
|
|
|
99
108
|
const newItems = messages.filter((u) => !existingIds.has(u.id));
|
|
100
109
|
return {
|
|
101
110
|
...prev,
|
|
102
|
-
messages: [...
|
|
111
|
+
messages: [...merged, ...newItems],
|
|
103
112
|
};
|
|
104
113
|
});
|
|
105
114
|
}
|
|
106
115
|
);
|
|
107
116
|
const subUpdateMessageError = DeviceEventEmitter.addListener(
|
|
108
117
|
events.updateMessageError,
|
|
109
|
-
(messageId: string, metadata: Record<string, any
|
|
118
|
+
(messageId: string, metadata: Record<string, any>, sID?: string) => {
|
|
110
119
|
setLoadState((prev) => {
|
|
120
|
+
if (sID !== prev.id) {
|
|
121
|
+
return prev;
|
|
122
|
+
}
|
|
123
|
+
|
|
111
124
|
const messageIndex = prev.messages.findIndex(
|
|
112
125
|
(m) => m.id === messageId
|
|
113
126
|
);
|
|
114
127
|
if (messageIndex === -1) return prev;
|
|
115
|
-
const updatedMessages = prev.messages
|
|
128
|
+
const updatedMessages: IMessageItem[] = prev.messages
|
|
116
129
|
.slice(messageIndex)
|
|
117
130
|
.map((m, i) =>
|
|
118
|
-
i ===
|
|
131
|
+
i === updatedMessages?.length - 1
|
|
119
132
|
? {
|
|
120
133
|
...m,
|
|
121
134
|
metadata: {
|
|
@@ -46,7 +46,11 @@ export const useSendMessage = () => {
|
|
|
46
46
|
manual_retry_attempts: 0,
|
|
47
47
|
group_suggestion_id: null,
|
|
48
48
|
};
|
|
49
|
-
DeviceEventEmitter.emit(
|
|
49
|
+
DeviceEventEmitter.emit(
|
|
50
|
+
events.updateOneMessage,
|
|
51
|
+
messageItem,
|
|
52
|
+
useSessionStore.getState().sessionId
|
|
53
|
+
);
|
|
50
54
|
|
|
51
55
|
let latestSessionId;
|
|
52
56
|
if (!useSessionStore.getState().sessionId) {
|
|
@@ -69,11 +69,12 @@ export const useStreamMessage = () => {
|
|
|
69
69
|
() => {
|
|
70
70
|
DeviceEventEmitter.emit(
|
|
71
71
|
events.updateMultipleMessage,
|
|
72
|
-
Object.values(buffers).map((m) => ({ ...m, content: '' }))
|
|
72
|
+
Object.values(buffers).map((m) => ({ ...m, content: '' })),
|
|
73
|
+
useSessionStore.getState().sessionId
|
|
73
74
|
);
|
|
74
75
|
setStreamMessage(buffers);
|
|
75
76
|
},
|
|
76
|
-
|
|
77
|
+
250,
|
|
77
78
|
{ leading: true, trailing: true }
|
|
78
79
|
);
|
|
79
80
|
|
|
@@ -83,19 +84,23 @@ export const useStreamMessage = () => {
|
|
|
83
84
|
) => {
|
|
84
85
|
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
85
86
|
if (isError) {
|
|
86
|
-
DeviceEventEmitter.emit(
|
|
87
|
+
DeviceEventEmitter.emit(
|
|
88
|
+
events.updateMessageError,
|
|
89
|
+
messageId,
|
|
87
90
|
{
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
original_message_id: localMessageId || messageId,
|
|
92
|
-
status: 'error',
|
|
93
|
-
},
|
|
91
|
+
needs_retry: true,
|
|
92
|
+
original_message_id: localMessageId || messageId,
|
|
93
|
+
status: 'error',
|
|
94
94
|
},
|
|
95
|
-
|
|
95
|
+
useSessionStore.getState().sessionId
|
|
96
|
+
);
|
|
96
97
|
} else {
|
|
97
98
|
const arrMessages = Object.values(buffers);
|
|
98
|
-
DeviceEventEmitter.emit(
|
|
99
|
+
DeviceEventEmitter.emit(
|
|
100
|
+
events.forceUpdateMessages,
|
|
101
|
+
arrMessages,
|
|
102
|
+
useSessionStore.getState().sessionId
|
|
103
|
+
);
|
|
99
104
|
arrMessages.forEach((m: any) => {
|
|
100
105
|
if (m?.suggestions?.length > 0) {
|
|
101
106
|
logGA?.(GAEvents.chatDetailInConvPrmSuggReturn, {
|
|
@@ -149,6 +154,7 @@ export const useStreamMessage = () => {
|
|
|
149
154
|
});
|
|
150
155
|
|
|
151
156
|
es.addEventListener('close', async () => {
|
|
157
|
+
throttledFlush.cancel();
|
|
152
158
|
console.log('✅ Stream closed');
|
|
153
159
|
});
|
|
154
160
|
},
|
|
@@ -157,10 +163,14 @@ export const useStreamMessage = () => {
|
|
|
157
163
|
|
|
158
164
|
const retryStream = useCallback(
|
|
159
165
|
(messageItem: IMessageItem) => {
|
|
160
|
-
DeviceEventEmitter.emit(
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
166
|
+
DeviceEventEmitter.emit(
|
|
167
|
+
events.updateOneMessage,
|
|
168
|
+
{
|
|
169
|
+
...messageItem,
|
|
170
|
+
metadata: {},
|
|
171
|
+
},
|
|
172
|
+
sessionId
|
|
173
|
+
);
|
|
164
174
|
|
|
165
175
|
logGA(GAEvents.chatDetailSendBtnTap, {
|
|
166
176
|
chat_type: useSessionStore.getState().sessionLogType,
|