react-native-chatbot-ai 0.0.6 → 0.1.1
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/assets/icons/icon_thinking_step.gif +0 -0
- package/lib/module/assets/icons/index.js +6 -0
- package/lib/module/assets/icons/index.js.map +1 -0
- package/lib/module/assets/svgIcon/IconChatArrow.js.map +1 -1
- package/lib/module/assets/svgIcon/IconThinkingStep.js.map +1 -1
- package/lib/module/components/chat/ChatEmpty.js +7 -2
- package/lib/module/components/chat/ChatEmpty.js.map +1 -1
- package/lib/module/components/chat/ChatFooter.js +4 -2
- package/lib/module/components/chat/ChatFooter.js.map +1 -1
- package/lib/module/components/chat/ChatHeader.js +5 -1
- package/lib/module/components/chat/ChatHeader.js.map +1 -1
- package/lib/module/components/chat/ChatMessageList.js +33 -6
- package/lib/module/components/chat/ChatMessageList.js.map +1 -1
- package/lib/module/components/chat/SuggestionItem.js.map +1 -1
- package/lib/module/components/chat/item/ChatAIAnswerMessageItem.js +67 -29
- package/lib/module/components/chat/item/ChatAIAnswerMessageItem.js.map +1 -1
- package/lib/module/components/chat/item/ChatAIThinkingMessageItem.js +84 -41
- package/lib/module/components/chat/item/ChatAIThinkingMessageItem.js.map +1 -1
- package/lib/module/components/chat/item/ChatUserMessageItem.js +1 -1
- package/lib/module/components/chat/item/ChatUserMessageItem.js.map +1 -1
- package/lib/module/components/chat/item/index.js +2 -1
- package/lib/module/components/chat/item/index.js.map +1 -1
- package/lib/module/constants/events.js +2 -1
- package/lib/module/constants/events.js.map +1 -1
- package/lib/module/context/ChatContext.js +6 -3
- package/lib/module/context/ChatContext.js.map +1 -1
- package/lib/module/hooks/message/useMessage.js +2 -2
- 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 +4 -4
- package/lib/module/hooks/message/useStreamMessage.js.map +1 -1
- package/lib/module/services/endpoints.js.map +1 -1
- package/lib/module/store/session.js.map +1 -1
- package/lib/module/store/streamMessage.js.map +1 -1
- package/lib/typescript/src/assets/icons/index.d.ts +5 -0
- package/lib/typescript/src/assets/icons/index.d.ts.map +1 -0
- package/lib/typescript/src/assets/svgIcon/IconChatArrow.d.ts.map +1 -1
- package/lib/typescript/src/assets/svgIcon/IconThinkingStep.d.ts.map +1 -1
- package/lib/typescript/src/components/chat/ChatEmpty.d.ts.map +1 -1
- package/lib/typescript/src/components/chat/ChatFooter.d.ts.map +1 -1
- package/lib/typescript/src/components/chat/ChatHeader.d.ts.map +1 -1
- package/lib/typescript/src/components/chat/ChatMessageList.d.ts.map +1 -1
- package/lib/typescript/src/components/chat/SuggestionItem.d.ts.map +1 -1
- package/lib/typescript/src/components/chat/item/ChatAIAnswerMessageItem.d.ts +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 +2 -1
- package/lib/typescript/src/components/chat/item/ChatAIThinkingMessageItem.d.ts.map +1 -1
- package/lib/typescript/src/constants/events.d.ts +1 -0
- package/lib/typescript/src/constants/events.d.ts.map +1 -1
- package/lib/typescript/src/context/ChatContext.d.ts.map +1 -1
- package/lib/typescript/src/hooks/message/useMessage.d.ts.map +1 -1
- package/lib/typescript/src/hooks/message/useStreamMessage.d.ts.map +1 -1
- package/lib/typescript/src/services/endpoints.d.ts.map +1 -1
- package/lib/typescript/src/types/chat.d.ts +3 -0
- package/lib/typescript/src/types/chat.d.ts.map +1 -1
- package/lib/typescript/src/types/dto.d.ts.map +1 -1
- package/package.json +11 -4
- package/src/assets/icons/icon_thinking_step.gif +0 -0
- package/src/assets/icons/index.ts +3 -0
- package/src/assets/svgIcon/IconChatArrow.tsx +7 -1
- package/src/assets/svgIcon/IconThinkingStep.tsx +15 -2
- package/src/components/chat/ChatEmpty.tsx +16 -5
- package/src/components/chat/ChatFooter.tsx +22 -5
- package/src/components/chat/ChatHeader.tsx +21 -4
- package/src/components/chat/ChatMessageList.tsx +45 -6
- package/src/components/chat/SuggestionItem.tsx +50 -8
- package/src/components/chat/item/ChatAIAnswerMessageItem.tsx +106 -31
- package/src/components/chat/item/ChatAIThinkingMessageItem.tsx +124 -43
- package/src/components/chat/item/ChatUserMessageItem.tsx +1 -1
- package/src/components/chat/item/index.tsx +1 -1
- package/src/constants/events.ts +1 -0
- package/src/context/ChatContext.tsx +3 -2
- package/src/hooks/message/useMessage.ts +19 -15
- package/src/hooks/message/useSendMessage.ts +1 -1
- package/src/hooks/message/useStreamMessage.ts +25 -13
- package/src/services/endpoints.ts +2 -1
- package/src/store/session.ts +2 -2
- package/src/store/streamMessage.ts +3 -3
- package/src/types/chat.ts +3 -0
- package/src/types/dto.ts +6 -1
|
@@ -5,14 +5,15 @@ import ChatBotAI from '../components/chat';
|
|
|
5
5
|
export const ChatContext = createContext<ChatContextType>({
|
|
6
6
|
apiAddress: '',
|
|
7
7
|
userId: '',
|
|
8
|
+
cartButton: undefined,
|
|
8
9
|
});
|
|
9
10
|
|
|
10
11
|
export const useChatContext = () => useContext(ChatContext);
|
|
11
12
|
|
|
12
13
|
export const ChatProvider = (props: ChatProviderProps) => {
|
|
13
|
-
const { apiAddress, userId } = props;
|
|
14
|
+
const { apiAddress, userId, cartButton } = props;
|
|
14
15
|
return (
|
|
15
|
-
<ChatContext.Provider value={{ apiAddress, userId }}>
|
|
16
|
+
<ChatContext.Provider value={{ apiAddress, userId, cartButton }}>
|
|
16
17
|
<ChatBotAI />
|
|
17
18
|
</ChatContext.Provider>
|
|
18
19
|
);
|
|
@@ -17,19 +17,21 @@ const initialState = {
|
|
|
17
17
|
messages: [],
|
|
18
18
|
};
|
|
19
19
|
export const useMessage = () => {
|
|
20
|
-
const sessionId = useSessionStore(state => state.sessionId);
|
|
20
|
+
const sessionId = useSessionStore((state) => state.sessionId);
|
|
21
21
|
const { mutateAsync: getSessionById } = useFetchSessionById();
|
|
22
|
-
const [loadState, setLoadState] =
|
|
22
|
+
const [loadState, setLoadState] =
|
|
23
|
+
useState<SessionDetailResponse>(initialState);
|
|
23
24
|
|
|
24
25
|
const onGetSessionById = useCallback(async () => {
|
|
25
26
|
if (!sessionId) return;
|
|
26
27
|
const res = await getSessionById(sessionId);
|
|
27
28
|
if (!res) return;
|
|
28
|
-
setLoadState(prev => ({
|
|
29
|
+
setLoadState((prev) => ({
|
|
29
30
|
...res,
|
|
30
|
-
messages:
|
|
31
|
+
messages:
|
|
32
|
+
res?.messages?.length > 0 ? res.messages.reverse() : prev.messages,
|
|
31
33
|
}));
|
|
32
|
-
}, [sessionId]);
|
|
34
|
+
}, [sessionId, getSessionById]);
|
|
33
35
|
|
|
34
36
|
useEffect(() => {
|
|
35
37
|
if (!sessionId) {
|
|
@@ -37,13 +39,13 @@ export const useMessage = () => {
|
|
|
37
39
|
return;
|
|
38
40
|
}
|
|
39
41
|
onGetSessionById();
|
|
40
|
-
}, [sessionId]);
|
|
42
|
+
}, [sessionId, onGetSessionById]);
|
|
41
43
|
|
|
42
44
|
useEffect(() => {
|
|
43
45
|
const subOneMessage = DeviceEventEmitter.addListener(
|
|
44
46
|
events.updateOneMessage,
|
|
45
47
|
(messageItem: IMessageItem) => {
|
|
46
|
-
setLoadState(prev => ({
|
|
48
|
+
setLoadState((prev) => ({
|
|
47
49
|
...prev,
|
|
48
50
|
messages: [messageItem, ...prev.messages],
|
|
49
51
|
}));
|
|
@@ -52,9 +54,11 @@ export const useMessage = () => {
|
|
|
52
54
|
const subMultipleMessage = DeviceEventEmitter.addListener(
|
|
53
55
|
events.updateMultipleMessage,
|
|
54
56
|
(messageItems: IMessageItem[]) => {
|
|
55
|
-
setLoadState(prev => {
|
|
56
|
-
const existingIds = new Set(prev.messages.map(m => m?.id));
|
|
57
|
-
const filtered = messageItems
|
|
57
|
+
setLoadState((prev) => {
|
|
58
|
+
const existingIds = new Set(prev.messages.map((m) => m?.id));
|
|
59
|
+
const filtered = messageItems
|
|
60
|
+
.filter((m) => !existingIds.has(m?.id))
|
|
61
|
+
.reverse();
|
|
58
62
|
console.log('🚀 ~ useEffect ~ filtered:', prev.messages);
|
|
59
63
|
return {
|
|
60
64
|
...prev,
|
|
@@ -66,14 +70,14 @@ export const useMessage = () => {
|
|
|
66
70
|
const subForceUpdateMessages = DeviceEventEmitter.addListener(
|
|
67
71
|
events.forceUpdateMessages,
|
|
68
72
|
(messages: IMessageItem[]) => {
|
|
69
|
-
setLoadState(prev => {
|
|
70
|
-
const merged = prev.messages.map(msg => {
|
|
71
|
-
const update = messages.find(u => u.id === msg.id);
|
|
73
|
+
setLoadState((prev) => {
|
|
74
|
+
const merged = prev.messages.map((msg) => {
|
|
75
|
+
const update = messages.find((u) => u.id === msg.id);
|
|
72
76
|
return update ? { ...msg, ...update } : msg;
|
|
73
77
|
});
|
|
74
78
|
|
|
75
|
-
const existingIds = new Set(prev.messages.map(m => m.id));
|
|
76
|
-
const newItems = messages.filter(u => !existingIds.has(u.id));
|
|
79
|
+
const existingIds = new Set(prev.messages.map((m) => m.id));
|
|
80
|
+
const newItems = messages.filter((u) => !existingIds.has(u.id));
|
|
77
81
|
return {
|
|
78
82
|
...prev,
|
|
79
83
|
messages: [...newItems, ...merged],
|
|
@@ -10,12 +10,14 @@ import { events } from '../../constants/events';
|
|
|
10
10
|
import useSessionStore from '../../store/session';
|
|
11
11
|
|
|
12
12
|
export const useStreamMessage = () => {
|
|
13
|
-
const sessionId = useSessionStore(state => state.sessionId);
|
|
13
|
+
const sessionId = useSessionStore((state) => state.sessionId);
|
|
14
14
|
const esRef = useRef<EventSource | null>(null);
|
|
15
15
|
const sessionIdRef = useRef<string | undefined>(sessionId);
|
|
16
16
|
const { apiAddress } = useChatContext();
|
|
17
|
-
const setStreamMessage = useStreamMessageStore(
|
|
18
|
-
|
|
17
|
+
const setStreamMessage = useStreamMessageStore(
|
|
18
|
+
(state) => state.setStreamMessage
|
|
19
|
+
);
|
|
20
|
+
const setIsStreaming = useStreamMessageStore((state) => state.setIsStreaming);
|
|
19
21
|
|
|
20
22
|
useEffect(() => {
|
|
21
23
|
sessionIdRef.current = sessionId;
|
|
@@ -39,7 +41,7 @@ export const useStreamMessage = () => {
|
|
|
39
41
|
method: 'POST',
|
|
40
42
|
headers: {
|
|
41
43
|
'Content-Type': 'application/json',
|
|
42
|
-
Authorization: `Bearer ${token}`,
|
|
44
|
+
'Authorization': `Bearer ${token}`,
|
|
43
45
|
},
|
|
44
46
|
body: JSON.stringify(payload),
|
|
45
47
|
});
|
|
@@ -56,7 +58,7 @@ export const useStreamMessage = () => {
|
|
|
56
58
|
() => {
|
|
57
59
|
DeviceEventEmitter.emit(
|
|
58
60
|
events.updateMultipleMessage,
|
|
59
|
-
Object.values(buffers).map(m => ({ ...m, content: '' }))
|
|
61
|
+
Object.values(buffers).map((m) => ({ ...m, content: '' }))
|
|
60
62
|
);
|
|
61
63
|
setStreamMessage(buffers);
|
|
62
64
|
},
|
|
@@ -64,11 +66,15 @@ export const useStreamMessage = () => {
|
|
|
64
66
|
{ leading: true, trailing: true }
|
|
65
67
|
);
|
|
66
68
|
|
|
67
|
-
es.addEventListener('message', event => {
|
|
68
|
-
console.log(
|
|
69
|
+
es.addEventListener('message', (event) => {
|
|
70
|
+
console.log(
|
|
71
|
+
'📩 Stream message:',
|
|
72
|
+
typeof event.data,
|
|
73
|
+
JSON?.parse?.(event?.data || '{}')
|
|
74
|
+
);
|
|
69
75
|
try {
|
|
70
76
|
const data = JSON?.parse?.(event?.data || '{}');
|
|
71
|
-
if (
|
|
77
|
+
if (data?.is_done) {
|
|
72
78
|
console.log('✅ Stream done');
|
|
73
79
|
es.close();
|
|
74
80
|
setIsStreaming(false);
|
|
@@ -78,7 +84,10 @@ export const useStreamMessage = () => {
|
|
|
78
84
|
if (buffers?.[message?.id]) {
|
|
79
85
|
buffers[message?.id] = {
|
|
80
86
|
...message,
|
|
81
|
-
content: [
|
|
87
|
+
content: [
|
|
88
|
+
buffers?.[message?.id]?.content || '',
|
|
89
|
+
message?.content || '',
|
|
90
|
+
].join(''),
|
|
82
91
|
};
|
|
83
92
|
} else {
|
|
84
93
|
buffers[message?.id] = message;
|
|
@@ -91,21 +100,24 @@ export const useStreamMessage = () => {
|
|
|
91
100
|
}
|
|
92
101
|
});
|
|
93
102
|
|
|
94
|
-
es.addEventListener('error', err => {
|
|
103
|
+
es.addEventListener('error', (err) => {
|
|
95
104
|
console.log('❌ Stream error:', err);
|
|
96
105
|
setIsStreaming(false);
|
|
97
106
|
});
|
|
98
107
|
|
|
99
108
|
es.addEventListener('close', () => {
|
|
100
109
|
console.log('🔴 Stream closed');
|
|
101
|
-
DeviceEventEmitter.emit(
|
|
110
|
+
DeviceEventEmitter.emit(
|
|
111
|
+
events.forceUpdateMessages,
|
|
112
|
+
Object.values(buffers)
|
|
113
|
+
);
|
|
102
114
|
buffers = {};
|
|
103
115
|
setIsStreaming(false);
|
|
104
116
|
});
|
|
105
117
|
|
|
106
118
|
esRef.current = es;
|
|
107
119
|
},
|
|
108
|
-
[apiAddress]
|
|
120
|
+
[apiAddress, setIsStreaming, setStreamMessage]
|
|
109
121
|
);
|
|
110
122
|
|
|
111
123
|
const stopStream = useCallback(() => {
|
|
@@ -115,7 +127,7 @@ export const useStreamMessage = () => {
|
|
|
115
127
|
esRef.current = null;
|
|
116
128
|
setIsStreaming(false);
|
|
117
129
|
}
|
|
118
|
-
}, []);
|
|
130
|
+
}, [setIsStreaming]);
|
|
119
131
|
|
|
120
132
|
useEffect(() => {
|
|
121
133
|
return () => {
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
export const ENDPOINTS = {
|
|
2
2
|
assistantService: {
|
|
3
3
|
getSuggestions: '/assistant-service/v1/app/chat/prompt-suggestions',
|
|
4
|
-
getSessionById: (sessionId: string) =>
|
|
4
|
+
getSessionById: (sessionId: string) =>
|
|
5
|
+
`/assistant-service/v1/app/chat/sessions/${sessionId}`,
|
|
5
6
|
getStreamMessage: (sessionId: string) =>
|
|
6
7
|
`/assistant-service/v1/app/chat/sessions/${sessionId}/stream`,
|
|
7
8
|
createSession: '/assistant-service/v1/app/chat/sessions',
|
package/src/store/session.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { create } from 'zustand';
|
|
2
2
|
import { SessionStore } from '../types/chat';
|
|
3
3
|
|
|
4
|
-
const useSessionStore = create<SessionStore>(set => ({
|
|
4
|
+
const useSessionStore = create<SessionStore>((set) => ({
|
|
5
5
|
sessionId: undefined,
|
|
6
|
-
setSessionId: sessionId => set({ sessionId }),
|
|
6
|
+
setSessionId: (sessionId) => set({ sessionId }),
|
|
7
7
|
}));
|
|
8
8
|
|
|
9
9
|
export default useSessionStore;
|
|
@@ -2,14 +2,14 @@ import { create } from 'zustand';
|
|
|
2
2
|
import { StreamMessageStore } from '../types/chat';
|
|
3
3
|
import { IMessageItem } from '../types';
|
|
4
4
|
|
|
5
|
-
const useStreamMessageStore = create<StreamMessageStore>(set => ({
|
|
5
|
+
const useStreamMessageStore = create<StreamMessageStore>((set) => ({
|
|
6
6
|
isStreaming: false,
|
|
7
|
-
setIsStreaming: isStreaming => set({ isStreaming }),
|
|
7
|
+
setIsStreaming: (isStreaming) => set({ isStreaming }),
|
|
8
8
|
streamMessage: {},
|
|
9
9
|
setStreamMessage: (streamMessage: Record<string, IMessageItem>) => {
|
|
10
10
|
if (!streamMessage || Object.keys(streamMessage).length === 0) return;
|
|
11
11
|
|
|
12
|
-
set(state => {
|
|
12
|
+
set((state) => {
|
|
13
13
|
const updated = { ...state.streamMessage };
|
|
14
14
|
|
|
15
15
|
for (const [id, msg] of Object.entries(streamMessage)) {
|
package/src/types/chat.ts
CHANGED
|
@@ -1,13 +1,16 @@
|
|
|
1
|
+
import { JSX } from 'react';
|
|
1
2
|
import { IMessageItem } from './dto';
|
|
2
3
|
|
|
3
4
|
export interface ChatContextType {
|
|
4
5
|
apiAddress: string;
|
|
5
6
|
userId: string;
|
|
7
|
+
cartButton?: JSX.Element;
|
|
6
8
|
}
|
|
7
9
|
|
|
8
10
|
export interface ChatProviderProps {
|
|
9
11
|
apiAddress: string;
|
|
10
12
|
userId: string;
|
|
13
|
+
cartButton?: JSX.Element;
|
|
11
14
|
}
|
|
12
15
|
|
|
13
16
|
export interface SessionStore {
|
package/src/types/dto.ts
CHANGED
|
@@ -44,7 +44,12 @@ export interface IAttachment {
|
|
|
44
44
|
name?: string;
|
|
45
45
|
size?: number;
|
|
46
46
|
loading?: boolean;
|
|
47
|
-
mime_type:
|
|
47
|
+
mime_type:
|
|
48
|
+
| 'image/jpeg'
|
|
49
|
+
| 'image/png'
|
|
50
|
+
| 'image/webp'
|
|
51
|
+
| 'image/jpg'
|
|
52
|
+
| 'application/pdf';
|
|
48
53
|
}
|
|
49
54
|
|
|
50
55
|
export interface StreamMessageRequest {
|