react-native-chatbot-ai 0.0.4 → 0.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (157) hide show
  1. package/lib/module/assets/images/bg_header.png +0 -0
  2. package/lib/module/assets/images/index.js +6 -0
  3. package/lib/module/assets/images/index.js.map +1 -0
  4. package/lib/module/assets/svgIcon/IconChatArrow.js +25 -0
  5. package/lib/module/assets/svgIcon/IconChatArrow.js.map +1 -0
  6. package/lib/module/assets/svgIcon/IconThinkingStep.js +45 -0
  7. package/lib/module/assets/svgIcon/IconThinkingStep.js.map +1 -0
  8. package/lib/module/components/chat/ChatEmpty.js +60 -0
  9. package/lib/module/components/chat/ChatEmpty.js.map +1 -0
  10. package/lib/module/components/chat/ChatFooter.js +89 -0
  11. package/lib/module/components/chat/ChatFooter.js.map +1 -0
  12. package/lib/module/components/chat/ChatHeader.js +70 -0
  13. package/lib/module/components/chat/ChatHeader.js.map +1 -0
  14. package/lib/module/components/chat/ChatMessageList.js +38 -0
  15. package/lib/module/components/chat/ChatMessageList.js.map +1 -0
  16. package/lib/module/components/chat/SuggestionItem.js +80 -0
  17. package/lib/module/components/chat/SuggestionItem.js.map +1 -0
  18. package/lib/module/components/chat/index.js +17 -5
  19. package/lib/module/components/chat/index.js.map +1 -1
  20. package/lib/module/components/chat/item/ChatAIAnswerMessageItem.js +82 -0
  21. package/lib/module/components/chat/item/ChatAIAnswerMessageItem.js.map +1 -0
  22. package/lib/module/components/chat/item/ChatAIThinkingMessageItem.js +126 -0
  23. package/lib/module/components/chat/item/ChatAIThinkingMessageItem.js.map +1 -0
  24. package/lib/module/components/chat/item/ChatUserMessageItem.js +41 -0
  25. package/lib/module/components/chat/item/ChatUserMessageItem.js.map +1 -0
  26. package/lib/module/components/chat/item/index.js +33 -0
  27. package/lib/module/components/chat/item/index.js.map +1 -0
  28. package/lib/module/constants/events.js +8 -0
  29. package/lib/module/constants/events.js.map +1 -0
  30. package/lib/module/constants/query.js +8 -0
  31. package/lib/module/constants/query.js.map +1 -0
  32. package/lib/module/context/ChatContext.js +19 -10
  33. package/lib/module/context/ChatContext.js.map +1 -1
  34. package/lib/module/hooks/message/useMessage.js +86 -0
  35. package/lib/module/hooks/message/useMessage.js.map +1 -0
  36. package/lib/module/hooks/message/useSendMessage.js +58 -0
  37. package/lib/module/hooks/message/useSendMessage.js.map +1 -0
  38. package/lib/module/hooks/message/useStreamMessage.js +113 -0
  39. package/lib/module/hooks/message/useStreamMessage.js.map +1 -0
  40. package/lib/module/hooks/session/useCreateSession.js +18 -0
  41. package/lib/module/hooks/session/useCreateSession.js.map +1 -0
  42. package/lib/module/hooks/session/useFetchSessionById.js +14 -0
  43. package/lib/module/hooks/session/useFetchSessionById.js.map +1 -0
  44. package/lib/module/hooks/suggestions/useFetchSuggestions.js +15 -0
  45. package/lib/module/hooks/suggestions/useFetchSuggestions.js.map +1 -0
  46. package/lib/module/index.js +2 -1
  47. package/lib/module/index.js.map +1 -1
  48. package/lib/module/services/endpoints.js +11 -0
  49. package/lib/module/services/endpoints.js.map +1 -0
  50. package/lib/module/store/session.js +11 -0
  51. package/lib/module/store/session.js.map +1 -0
  52. package/lib/module/store/streamMessage.js +26 -0
  53. package/lib/module/store/streamMessage.js.map +1 -0
  54. package/lib/module/types/common.js +23 -0
  55. package/lib/module/types/common.js.map +1 -0
  56. package/lib/module/types/dto.js +2 -0
  57. package/lib/module/types/index.js +6 -0
  58. package/lib/module/types/index.js.map +1 -0
  59. package/lib/typescript/src/assets/images/index.d.ts +5 -0
  60. package/lib/typescript/src/assets/images/index.d.ts.map +1 -0
  61. package/lib/typescript/src/assets/svgIcon/IconChatArrow.d.ts +9 -0
  62. package/lib/typescript/src/assets/svgIcon/IconChatArrow.d.ts.map +1 -0
  63. package/lib/typescript/src/assets/svgIcon/IconThinkingStep.d.ts +7 -0
  64. package/lib/typescript/src/assets/svgIcon/IconThinkingStep.d.ts.map +1 -0
  65. package/lib/typescript/src/components/chat/ChatEmpty.d.ts +3 -0
  66. package/lib/typescript/src/components/chat/ChatEmpty.d.ts.map +1 -0
  67. package/lib/typescript/src/components/chat/ChatFooter.d.ts +3 -0
  68. package/lib/typescript/src/components/chat/ChatFooter.d.ts.map +1 -0
  69. package/lib/typescript/src/components/chat/ChatHeader.d.ts +3 -0
  70. package/lib/typescript/src/components/chat/ChatHeader.d.ts.map +1 -0
  71. package/lib/typescript/src/components/chat/ChatMessageList.d.ts +3 -0
  72. package/lib/typescript/src/components/chat/ChatMessageList.d.ts.map +1 -0
  73. package/lib/typescript/src/components/chat/SuggestionItem.d.ts +8 -0
  74. package/lib/typescript/src/components/chat/SuggestionItem.d.ts.map +1 -0
  75. package/lib/typescript/src/components/chat/index.d.ts +2 -1
  76. package/lib/typescript/src/components/chat/index.d.ts.map +1 -1
  77. package/lib/typescript/src/components/chat/item/ChatAIAnswerMessageItem.d.ts +8 -0
  78. package/lib/typescript/src/components/chat/item/ChatAIAnswerMessageItem.d.ts.map +1 -0
  79. package/lib/typescript/src/components/chat/item/ChatAIThinkingMessageItem.d.ts +7 -0
  80. package/lib/typescript/src/components/chat/item/ChatAIThinkingMessageItem.d.ts.map +1 -0
  81. package/lib/typescript/src/components/chat/item/ChatUserMessageItem.d.ts +7 -0
  82. package/lib/typescript/src/components/chat/item/ChatUserMessageItem.d.ts.map +1 -0
  83. package/lib/typescript/src/components/chat/item/index.d.ts +8 -0
  84. package/lib/typescript/src/components/chat/item/index.d.ts.map +1 -0
  85. package/lib/typescript/src/constants/events.d.ts +6 -0
  86. package/lib/typescript/src/constants/events.d.ts.map +1 -0
  87. package/lib/typescript/src/constants/query.d.ts +6 -0
  88. package/lib/typescript/src/constants/query.d.ts.map +1 -0
  89. package/lib/typescript/src/context/ChatContext.d.ts +2 -1
  90. package/lib/typescript/src/context/ChatContext.d.ts.map +1 -1
  91. package/lib/typescript/src/hooks/message/useMessage.d.ts +5 -0
  92. package/lib/typescript/src/hooks/message/useMessage.d.ts.map +1 -0
  93. package/lib/typescript/src/hooks/message/useSendMessage.d.ts +5 -0
  94. package/lib/typescript/src/hooks/message/useSendMessage.d.ts.map +1 -0
  95. package/lib/typescript/src/hooks/message/useStreamMessage.d.ts +6 -0
  96. package/lib/typescript/src/hooks/message/useStreamMessage.d.ts.map +1 -0
  97. package/lib/typescript/src/hooks/session/useCreateSession.d.ts +2 -0
  98. package/lib/typescript/src/hooks/session/useCreateSession.d.ts.map +1 -0
  99. package/lib/typescript/src/hooks/session/useFetchSessionById.d.ts +2 -0
  100. package/lib/typescript/src/hooks/session/useFetchSessionById.d.ts.map +1 -0
  101. package/lib/typescript/src/hooks/suggestions/useFetchSuggestions.d.ts +2 -0
  102. package/lib/typescript/src/hooks/suggestions/useFetchSuggestions.d.ts.map +1 -0
  103. package/lib/typescript/src/index.d.ts +2 -1
  104. package/lib/typescript/src/index.d.ts.map +1 -1
  105. package/lib/typescript/src/services/endpoints.d.ts +9 -0
  106. package/lib/typescript/src/services/endpoints.d.ts.map +1 -0
  107. package/lib/typescript/src/store/session.d.ts +4 -0
  108. package/lib/typescript/src/store/session.d.ts.map +1 -0
  109. package/lib/typescript/src/store/streamMessage.d.ts +4 -0
  110. package/lib/typescript/src/store/streamMessage.d.ts.map +1 -0
  111. package/lib/typescript/src/types/chat.d.ts +16 -2
  112. package/lib/typescript/src/types/chat.d.ts.map +1 -1
  113. package/lib/typescript/src/types/common.d.ts +29 -0
  114. package/lib/typescript/src/types/common.d.ts.map +1 -0
  115. package/lib/typescript/src/types/dto.d.ts +66 -0
  116. package/lib/typescript/src/types/dto.d.ts.map +1 -1
  117. package/lib/typescript/src/types/index.d.ts +4 -0
  118. package/lib/typescript/src/types/index.d.ts.map +1 -0
  119. package/package.json +8 -5
  120. package/src/assets/images/bg_header.png +0 -0
  121. package/src/assets/images/index.ts +3 -0
  122. package/src/assets/svgIcon/IconChatArrow.tsx +21 -0
  123. package/src/assets/svgIcon/IconThinkingStep.tsx +35 -0
  124. package/src/components/chat/ChatEmpty.tsx +52 -0
  125. package/src/components/chat/ChatFooter.tsx +82 -0
  126. package/src/components/chat/ChatHeader.tsx +57 -0
  127. package/src/components/chat/ChatMessageList.tsx +33 -0
  128. package/src/components/chat/SuggestionItem.tsx +64 -0
  129. package/src/components/chat/index.tsx +20 -5
  130. package/src/components/chat/item/ChatAIAnswerMessageItem.tsx +84 -0
  131. package/src/components/chat/item/ChatAIThinkingMessageItem.tsx +130 -0
  132. package/src/components/chat/item/ChatUserMessageItem.tsx +39 -0
  133. package/src/components/chat/item/index.tsx +23 -0
  134. package/src/constants/events.ts +5 -0
  135. package/src/constants/query.ts +5 -0
  136. package/src/context/ChatContext.tsx +11 -6
  137. package/src/hooks/message/useMessage.ts +94 -0
  138. package/src/hooks/message/useSendMessage.ts +58 -0
  139. package/src/hooks/message/useStreamMessage.ts +130 -0
  140. package/src/hooks/session/useCreateSession.ts +23 -0
  141. package/src/hooks/session/useFetchSessionById.ts +17 -0
  142. package/src/hooks/suggestions/useFetchSuggestions.ts +18 -0
  143. package/src/ignore.d.ts +2 -1
  144. package/src/index.ts +4 -0
  145. package/src/services/endpoints.ts +9 -0
  146. package/src/store/session.ts +9 -0
  147. package/src/store/streamMessage.ts +24 -0
  148. package/src/types/chat.ts +21 -3
  149. package/src/types/common.ts +32 -0
  150. package/src/types/dto.ts +74 -0
  151. package/src/types/index.ts +3 -0
  152. package/lib/module/utils/index.js +0 -2
  153. package/lib/module/utils/index.js.map +0 -1
  154. package/lib/typescript/src/utils/index.d.ts +0 -1
  155. package/lib/typescript/src/utils/index.d.ts.map +0 -1
  156. package/src/index.tsx +0 -2
  157. package/src/utils/index.ts +0 -0
@@ -0,0 +1,39 @@
1
+ import { StyleSheet } from 'react-native';
2
+ import { KColors, KContainer, KLabel, KSpacingValue } from '@droppii/libs';
3
+ import { IMessageItem } from '../../../types';
4
+ import { IconChatArrow } from '../../../assets/svgIcon/IconChatArrow';
5
+
6
+ interface ChatUserMessageItemProps {
7
+ item: IMessageItem;
8
+ }
9
+ const ChatUserMessageItem = ({ item }: ChatUserMessageItemProps) => {
10
+ return (
11
+ <KContainer.View style={styles.container}>
12
+ <KContainer.View style={styles.content}>
13
+ <KLabel.Text typo="TextMdNormal" color={KColors.black}>
14
+ {item.content}
15
+ </KLabel.Text>
16
+ </KContainer.View>
17
+ <IconChatArrow fill={'#0077FF'} />
18
+ </KContainer.View>
19
+ );
20
+ };
21
+
22
+ export default ChatUserMessageItem;
23
+
24
+ const styles = StyleSheet.create({
25
+ container: {
26
+ flexDirection: 'row',
27
+ justifyContent: 'flex-end',
28
+ paddingHorizontal: KSpacingValue['1rem'],
29
+ marginVertical: KSpacingValue['0.5rem'],
30
+ },
31
+ content: {
32
+ maxWidth: '70%',
33
+ paddingHorizontal: KSpacingValue['1rem'],
34
+ paddingVertical: KSpacingValue['0.5rem'],
35
+ backgroundColor: KColors.hexToRgba('#0077FF', 0.1),
36
+ borderRadius: KSpacingValue['1rem'],
37
+ borderTopRightRadius: 0,
38
+ },
39
+ });
@@ -0,0 +1,23 @@
1
+ import { IMessageItem, MessageType } from '../../../types';
2
+ import ChatAIAnswerMessageItem from './ChatAIAnswerMessageItem';
3
+ import ChatAIThinkingMessageItem from './ChatAIThinkingMessageItem';
4
+ import ChatUserMessageItem from './ChatUserMessageItem';
5
+
6
+ interface ChatItemProps {
7
+ item: IMessageItem;
8
+ index: number;
9
+ }
10
+ const ChatItem = ({ item, index }: ChatItemProps) => {
11
+ switch (item.type) {
12
+ case MessageType.user_message:
13
+ return <ChatUserMessageItem item={item} />;
14
+ case MessageType.ai_answer:
15
+ return <ChatAIAnswerMessageItem item={item} isLast={index === 0} />;
16
+ case MessageType.ai_thinking:
17
+ return <ChatAIThinkingMessageItem item={item} />;
18
+ default:
19
+ return <ChatUserMessageItem item={item} />;
20
+ }
21
+ };
22
+
23
+ export default ChatItem;
@@ -0,0 +1,5 @@
1
+ export const events = {
2
+ updateOneMessage: 'update_one_message',
3
+ updateMultipleMessage: 'update_multiple_message',
4
+ forceUpdateMessages: 'force_update_messages',
5
+ };
@@ -0,0 +1,5 @@
1
+ export const QUERY_KEYS = {
2
+ GET_SUGGESTIONS: 'GET_SUGGESTIONS',
3
+ GET_SESSION_BY_ID: 'GET_SESSION_BY_ID',
4
+ CREATE_SESSION: 'CREATE_SESSION',
5
+ };
@@ -1,13 +1,18 @@
1
- import { createContext } from 'react';
1
+ import { createContext, useContext } from 'react';
2
2
  import type { ChatContextType, ChatProviderProps } from '../types/chat';
3
- import { ChatBotAI } from '../components/chat';
3
+ import ChatBotAI from '../components/chat';
4
4
 
5
- export const ChatContext = createContext<ChatContextType>({});
5
+ export const ChatContext = createContext<ChatContextType>({
6
+ apiAddress: '',
7
+ userId: '',
8
+ });
6
9
 
7
- export const ChatProvider = ({ children }: ChatProviderProps) => {
10
+ export const useChatContext = () => useContext(ChatContext);
11
+
12
+ export const ChatProvider = (props: ChatProviderProps) => {
13
+ const { apiAddress, userId } = props;
8
14
  return (
9
- <ChatContext.Provider value={{}}>
10
- {children}
15
+ <ChatContext.Provider value={{ apiAddress, userId }}>
11
16
  <ChatBotAI />
12
17
  </ChatContext.Provider>
13
18
  );
@@ -0,0 +1,94 @@
1
+ import { useCallback, useEffect, useState } from 'react';
2
+ import useSessionStore from '../../store/session';
3
+ import { useFetchSessionById } from '../session/useFetchSessionById';
4
+ import { IMessageItem, SessionDetailResponse } from '../../types/dto';
5
+ import { DeviceEventEmitter } from 'react-native';
6
+ import { events } from '../../constants/events';
7
+
8
+ const initialState = {
9
+ id: '',
10
+ title: '',
11
+ created_at: '',
12
+ updated_at: '',
13
+ metadata: {
14
+ source: '',
15
+ },
16
+ shared: false,
17
+ messages: [],
18
+ };
19
+ export const useMessage = () => {
20
+ const sessionId = useSessionStore(state => state.sessionId);
21
+ const { mutateAsync: getSessionById } = useFetchSessionById();
22
+ const [loadState, setLoadState] = useState<SessionDetailResponse>(initialState);
23
+
24
+ const onGetSessionById = useCallback(async () => {
25
+ if (!sessionId) return;
26
+ const res = await getSessionById(sessionId);
27
+ if (!res) return;
28
+ setLoadState(prev => ({
29
+ ...res,
30
+ messages: res?.messages?.length > 0 ? res.messages.reverse() : prev.messages,
31
+ }));
32
+ }, [sessionId]);
33
+
34
+ useEffect(() => {
35
+ if (!sessionId) {
36
+ setLoadState(initialState);
37
+ return;
38
+ }
39
+ onGetSessionById();
40
+ }, [sessionId]);
41
+
42
+ useEffect(() => {
43
+ const subOneMessage = DeviceEventEmitter.addListener(
44
+ events.updateOneMessage,
45
+ (messageItem: IMessageItem) => {
46
+ setLoadState(prev => ({
47
+ ...prev,
48
+ messages: [messageItem, ...prev.messages],
49
+ }));
50
+ }
51
+ );
52
+ const subMultipleMessage = DeviceEventEmitter.addListener(
53
+ events.updateMultipleMessage,
54
+ (messageItems: IMessageItem[]) => {
55
+ setLoadState(prev => {
56
+ const existingIds = new Set(prev.messages.map(m => m?.id));
57
+ const filtered = messageItems.filter(m => !existingIds.has(m?.id)).reverse();
58
+ console.log('🚀 ~ useEffect ~ filtered:', prev.messages);
59
+ return {
60
+ ...prev,
61
+ messages: [...filtered, ...prev.messages],
62
+ };
63
+ });
64
+ }
65
+ );
66
+ const subForceUpdateMessages = DeviceEventEmitter.addListener(
67
+ events.forceUpdateMessages,
68
+ (messages: IMessageItem[]) => {
69
+ setLoadState(prev => {
70
+ const merged = prev.messages.map(msg => {
71
+ const update = messages.find(u => u.id === msg.id);
72
+ return update ? { ...msg, ...update } : msg;
73
+ });
74
+
75
+ const existingIds = new Set(prev.messages.map(m => m.id));
76
+ const newItems = messages.filter(u => !existingIds.has(u.id));
77
+ return {
78
+ ...prev,
79
+ messages: [...newItems, ...merged],
80
+ };
81
+ });
82
+ }
83
+ );
84
+ return () => {
85
+ subOneMessage.remove();
86
+ subMultipleMessage.remove();
87
+ subForceUpdateMessages.remove();
88
+ };
89
+ }, []);
90
+
91
+ return {
92
+ messageState: loadState,
93
+ };
94
+ };
@@ -0,0 +1,58 @@
1
+ import { useCallback } from 'react';
2
+ import useSessionStore from '../../store/session';
3
+ import { useStreamMessage } from './useStreamMessage';
4
+ import { events } from '../../constants/events';
5
+ import { DeviceEventEmitter } from 'react-native';
6
+ import { IMessageItem, MessageType, RoleType } from '../../types';
7
+ import dayjs from 'dayjs';
8
+ import { useCreateSession } from '../session/useCreateSession';
9
+
10
+ export const useSendMessage = () => {
11
+ const { startStream, stopStream } = useStreamMessage();
12
+ const { mutateAsync: createSession } = useCreateSession();
13
+
14
+ const onSendMessage = useCallback(
15
+ async (message: string) => {
16
+ const messageItem: IMessageItem = {
17
+ id: dayjs().valueOf().toString(),
18
+ attachments: [],
19
+ type: MessageType.user_message,
20
+ created_at: dayjs().toISOString(),
21
+ modified_at: dayjs().toISOString(),
22
+ content: message,
23
+ additional_kwargs: {},
24
+ response_metadata: {},
25
+ name: null,
26
+ role: RoleType.user,
27
+ metadata: {},
28
+ };
29
+ DeviceEventEmitter.emit(events.updateOneMessage, messageItem);
30
+
31
+ let latestSessionId;
32
+ if (!useSessionStore.getState().sessionId) {
33
+ const resSession = await createSession({ title: message });
34
+ if (!resSession) return;
35
+ useSessionStore.getState().setSessionId(resSession.id);
36
+ latestSessionId = resSession.id;
37
+ }
38
+ startStream(
39
+ {
40
+ content: message,
41
+ stream: true,
42
+ attachments: [],
43
+ metadata: {
44
+ source: 'user',
45
+ },
46
+ manual_retry_attempts: 0,
47
+ },
48
+ latestSessionId
49
+ );
50
+ },
51
+ [startStream]
52
+ );
53
+
54
+ return {
55
+ onSendMessage,
56
+ stopStream,
57
+ };
58
+ };
@@ -0,0 +1,130 @@
1
+ import { useEffect, useRef, useCallback } from 'react';
2
+ import { useChatContext } from '../../context/ChatContext';
3
+ import { ENDPOINTS } from '../../services/endpoints';
4
+ import { type IMessageItem, type StreamMessageRequest } from '../../types';
5
+ import EventSource from 'react-native-sse';
6
+ import useStreamMessageStore from '../../store/streamMessage';
7
+ import throttle from 'lodash/throttle';
8
+ import { DeviceEventEmitter } from 'react-native';
9
+ import { events } from '../../constants/events';
10
+ import useSessionStore from '../../store/session';
11
+
12
+ export const useStreamMessage = () => {
13
+ const sessionId = useSessionStore(state => state.sessionId);
14
+ const esRef = useRef<EventSource | null>(null);
15
+ const sessionIdRef = useRef<string | undefined>(sessionId);
16
+ const { apiAddress } = useChatContext();
17
+ const setStreamMessage = useStreamMessageStore(state => state.setStreamMessage);
18
+ const setIsStreaming = useStreamMessageStore(state => state.setIsStreaming);
19
+
20
+ useEffect(() => {
21
+ sessionIdRef.current = sessionId;
22
+ }, [sessionId]);
23
+
24
+ const startStream = useCallback(
25
+ (payload: StreamMessageRequest, latestSessionId?: string) => {
26
+ const token = (global as any)?.accessToken;
27
+ const currentSessionId = latestSessionId || sessionIdRef.current;
28
+
29
+ if (!currentSessionId || !token) return;
30
+
31
+ if (esRef.current) {
32
+ esRef.current.close();
33
+ esRef.current = null;
34
+ }
35
+
36
+ const url = `${apiAddress}${ENDPOINTS.assistantService.getStreamMessage(currentSessionId)}`;
37
+
38
+ const es = new EventSource(url, {
39
+ method: 'POST',
40
+ headers: {
41
+ 'Content-Type': 'application/json',
42
+ Authorization: `Bearer ${token}`,
43
+ },
44
+ body: JSON.stringify(payload),
45
+ });
46
+
47
+ es.addEventListener('open', () => {
48
+ console.log('🔵 Stream opened');
49
+ setIsStreaming(true);
50
+ setStreamMessage({});
51
+ });
52
+
53
+ let buffers: Record<string, IMessageItem> = {};
54
+
55
+ const throttledFlush = throttle(
56
+ () => {
57
+ DeviceEventEmitter.emit(
58
+ events.updateMultipleMessage,
59
+ Object.values(buffers).map(m => ({ ...m, content: '' }))
60
+ );
61
+ setStreamMessage(buffers);
62
+ },
63
+ 300,
64
+ { leading: true, trailing: true }
65
+ );
66
+
67
+ es.addEventListener('message', event => {
68
+ console.log('📩 Stream message:', typeof event.data, JSON?.parse?.(event?.data || '{}'));
69
+ try {
70
+ const data = JSON?.parse?.(event?.data || '{}');
71
+ if (!!data?.is_done) {
72
+ console.log('✅ Stream done');
73
+ es.close();
74
+ setIsStreaming(false);
75
+ } else {
76
+ const message = data?.messages as IMessageItem;
77
+ if (!message?.id) return;
78
+ if (buffers?.[message?.id]) {
79
+ buffers[message?.id] = {
80
+ ...message,
81
+ content: [buffers?.[message?.id]?.content || '', message?.content || ''].join(''),
82
+ };
83
+ } else {
84
+ buffers[message?.id] = message;
85
+ }
86
+ throttledFlush();
87
+ }
88
+ } catch (error) {
89
+ es.close();
90
+ setIsStreaming(false);
91
+ }
92
+ });
93
+
94
+ es.addEventListener('error', err => {
95
+ console.log('❌ Stream error:', err);
96
+ setIsStreaming(false);
97
+ });
98
+
99
+ es.addEventListener('close', () => {
100
+ console.log('🔴 Stream closed');
101
+ DeviceEventEmitter.emit(events.forceUpdateMessages, Object.values(buffers));
102
+ buffers = {};
103
+ setIsStreaming(false);
104
+ });
105
+
106
+ esRef.current = es;
107
+ },
108
+ [apiAddress]
109
+ );
110
+
111
+ const stopStream = useCallback(() => {
112
+ if (esRef.current) {
113
+ console.log('🛑 Closing stream');
114
+ esRef.current.close();
115
+ esRef.current = null;
116
+ setIsStreaming(false);
117
+ }
118
+ }, []);
119
+
120
+ useEffect(() => {
121
+ return () => {
122
+ stopStream();
123
+ };
124
+ }, [stopStream]);
125
+
126
+ return {
127
+ startStream,
128
+ stopStream,
129
+ };
130
+ };
@@ -0,0 +1,23 @@
1
+ import { useMutation } from '@tanstack/react-query';
2
+ import { QUERY_KEYS } from '../../constants/query';
3
+ import { apiInstance } from '../../services/apis';
4
+ import { ENDPOINTS } from '../../services/endpoints';
5
+ import { BaseResponse } from '../../types/common';
6
+ import { CreateSessionRequest, CreateSessionResponse } from '../../types/dto';
7
+
8
+ const MAX_TITLE_LENGTH = 300;
9
+
10
+ export const useCreateSession = () =>
11
+ useMutation({
12
+ mutationKey: [QUERY_KEYS.CREATE_SESSION],
13
+ mutationFn: async (payload: CreateSessionRequest) => {
14
+ const res = await apiInstance?.post<BaseResponse<CreateSessionResponse>>(
15
+ ENDPOINTS.assistantService.createSession,
16
+ {
17
+ ...payload,
18
+ title: payload.title.slice(0, MAX_TITLE_LENGTH),
19
+ }
20
+ );
21
+ return res?.data?.data;
22
+ },
23
+ });
@@ -0,0 +1,17 @@
1
+ import { useMutation } from '@tanstack/react-query';
2
+ import { QUERY_KEYS } from '../../constants/query';
3
+ import { apiInstance } from '../../services';
4
+ import { BaseResponse } from '../../types/common';
5
+ import { SessionDetailResponse } from '../../types/dto';
6
+ import { ENDPOINTS } from '../../services/endpoints';
7
+
8
+ export const useFetchSessionById = () =>
9
+ useMutation({
10
+ mutationKey: [QUERY_KEYS.GET_SESSION_BY_ID],
11
+ mutationFn: async (sessionId: string) => {
12
+ const res = await apiInstance?.get<BaseResponse<SessionDetailResponse>>(
13
+ ENDPOINTS.assistantService.getSessionById(sessionId)
14
+ );
15
+ return res?.data?.data;
16
+ },
17
+ });
@@ -0,0 +1,18 @@
1
+ import { useQuery } from '@tanstack/react-query';
2
+ import { QUERY_KEYS } from '../../constants/query';
3
+ import { apiInstance } from '../../services/apis';
4
+ import { ENDPOINTS } from '../../services/endpoints';
5
+ import { BaseResponse } from '../../types/common';
6
+ import { SuggetionResponse } from '../../types/dto';
7
+
8
+ export const useFetchSuggestions = () =>
9
+ useQuery({
10
+ queryKey: [QUERY_KEYS.GET_SUGGESTIONS],
11
+ queryFn: async () => {
12
+ const res = await apiInstance?.get<BaseResponse<SuggetionResponse>>(
13
+ ENDPOINTS.assistantService.getSuggestions
14
+ );
15
+ return res?.data?.data;
16
+ },
17
+ enabled: !!apiInstance,
18
+ });
package/src/ignore.d.ts CHANGED
@@ -1,2 +1,3 @@
1
1
  declare module '@droppii/libs/*';
2
- declare module '@droppii/libs';
2
+ declare module '@droppii/libs';
3
+ declare module '*';
package/src/index.ts ADDED
@@ -0,0 +1,4 @@
1
+ import { ChatProvider } from './context/ChatContext';
2
+
3
+ export * from './services';
4
+ export { ChatProvider as ChatBotAI };
@@ -0,0 +1,9 @@
1
+ export const ENDPOINTS = {
2
+ assistantService: {
3
+ getSuggestions: '/assistant-service/v1/app/chat/prompt-suggestions',
4
+ getSessionById: (sessionId: string) => `/assistant-service/v1/app/chat/sessions/${sessionId}`,
5
+ getStreamMessage: (sessionId: string) =>
6
+ `/assistant-service/v1/app/chat/sessions/${sessionId}/stream`,
7
+ createSession: '/assistant-service/v1/app/chat/sessions',
8
+ },
9
+ };
@@ -0,0 +1,9 @@
1
+ import { create } from 'zustand';
2
+ import { SessionStore } from '../types/chat';
3
+
4
+ const useSessionStore = create<SessionStore>(set => ({
5
+ sessionId: undefined,
6
+ setSessionId: sessionId => set({ sessionId }),
7
+ }));
8
+
9
+ export default useSessionStore;
@@ -0,0 +1,24 @@
1
+ import { create } from 'zustand';
2
+ import { StreamMessageStore } from '../types/chat';
3
+ import { IMessageItem } from '../types';
4
+
5
+ const useStreamMessageStore = create<StreamMessageStore>(set => ({
6
+ isStreaming: false,
7
+ setIsStreaming: isStreaming => set({ isStreaming }),
8
+ streamMessage: {},
9
+ setStreamMessage: (streamMessage: Record<string, IMessageItem>) => {
10
+ if (!streamMessage || Object.keys(streamMessage).length === 0) return;
11
+
12
+ set(state => {
13
+ const updated = { ...state.streamMessage };
14
+
15
+ for (const [id, msg] of Object.entries(streamMessage)) {
16
+ updated[id] = msg;
17
+ }
18
+
19
+ return { streamMessage: updated };
20
+ });
21
+ },
22
+ }));
23
+
24
+ export default useStreamMessageStore;
package/src/types/chat.ts CHANGED
@@ -1,5 +1,23 @@
1
- import type { PropsWithChildren } from 'react';
1
+ import { IMessageItem } from './dto';
2
2
 
3
- export interface ChatContextType {}
3
+ export interface ChatContextType {
4
+ apiAddress: string;
5
+ userId: string;
6
+ }
4
7
 
5
- export interface ChatProviderProps extends PropsWithChildren {}
8
+ export interface ChatProviderProps {
9
+ apiAddress: string;
10
+ userId: string;
11
+ }
12
+
13
+ export interface SessionStore {
14
+ sessionId?: string;
15
+ setSessionId: (sessionId: string | undefined) => void;
16
+ }
17
+
18
+ export interface StreamMessageStore {
19
+ isStreaming: boolean;
20
+ setIsStreaming: (isStreaming: boolean) => void;
21
+ streamMessage: Record<string, IMessageItem>;
22
+ setStreamMessage: (streamMessage: Record<string, IMessageItem>) => void;
23
+ }
@@ -0,0 +1,32 @@
1
+ export interface BaseResponse<T> {
2
+ statusCode: number;
3
+ message: any;
4
+ data: T;
5
+ }
6
+
7
+ export interface Pageable {
8
+ pageNumber: number;
9
+ totalPages: number;
10
+ pageSize: number;
11
+ totalElements: number;
12
+ }
13
+
14
+ export enum SuggestionCategory {
15
+ product = 'product',
16
+ discount = 'discount',
17
+ gift = 'gift',
18
+ health_advice = 'health_advice',
19
+ content = 'content',
20
+ guide = 'guide',
21
+ }
22
+
23
+ export enum MessageType {
24
+ user_message = 'user-message',
25
+ ai_thinking = 'ai-thinking',
26
+ ai_answer = 'ai-answer',
27
+ }
28
+
29
+ export enum RoleType {
30
+ user = 'user',
31
+ ai = 'ai',
32
+ }
package/src/types/dto.ts CHANGED
@@ -0,0 +1,74 @@
1
+ import { MessageType, RoleType, SuggestionCategory } from './common';
2
+
3
+ export interface ISuggestionItem {
4
+ content: string;
5
+ category: SuggestionCategory;
6
+ suggestion_id: string;
7
+ }
8
+
9
+ export interface SuggetionResponse {
10
+ group_suggestion_id: string;
11
+ suggestions: ISuggestionItem[];
12
+ }
13
+
14
+ export interface IMessageItem {
15
+ id: string;
16
+ content: string;
17
+ additional_kwargs: Record<string, any>;
18
+ response_metadata: Record<string, any>;
19
+ type: MessageType;
20
+ name: string | null;
21
+ role: RoleType;
22
+ metadata: Record<string, any>;
23
+ created_at: string;
24
+ modified_at: string;
25
+ attachments: any[];
26
+ }
27
+
28
+ export interface SessionDetailResponse {
29
+ id: string;
30
+ title: string;
31
+ created_at: string;
32
+ updated_at: string;
33
+ metadata: {
34
+ source: string;
35
+ };
36
+ shared: boolean;
37
+ messages: IMessageItem[];
38
+ }
39
+
40
+ export interface IAttachment {
41
+ type: 'image' | 'file';
42
+ source_type: 'url';
43
+ data: string;
44
+ name?: string;
45
+ size?: number;
46
+ loading?: boolean;
47
+ mime_type: 'image/jpeg' | 'image/png' | 'image/webp' | 'image/jpg' | 'application/pdf';
48
+ }
49
+
50
+ export interface StreamMessageRequest {
51
+ content: string;
52
+ stream: boolean;
53
+ attachments: IAttachment[];
54
+ clicked_suggestion_id?: string;
55
+ metadata: {
56
+ source: 'user';
57
+ };
58
+ manual_retry_attempts: number;
59
+ retried_message_id?: string;
60
+ }
61
+
62
+ export interface CreateSessionRequest {
63
+ title: string;
64
+ }
65
+
66
+ export interface CreateSessionResponse {
67
+ id: string;
68
+ title: string;
69
+ created_at: string;
70
+ updated_at: string;
71
+ metadata: {
72
+ source: string;
73
+ };
74
+ }
@@ -0,0 +1,3 @@
1
+ export * from './common';
2
+ export * from './dto';
3
+ export * from './chat';
@@ -1,2 +0,0 @@
1
- "use strict";
2
- //# sourceMappingURL=index.js.map
@@ -1 +0,0 @@
1
- {"version":3,"names":[],"sourceRoot":"../../../src","sources":["utils/index.ts"],"mappings":"","ignoreList":[]}
@@ -1 +0,0 @@
1
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/utils/index.ts"],"names":[],"mappings":""}
package/src/index.tsx DELETED
@@ -1,2 +0,0 @@
1
- export { ChatBotAI } from './components/chat';
2
- export * from './services';
File without changes