@fe-free/ai 4.1.37 → 4.1.38
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/CHANGELOG.md +10 -0
- package/package.json +4 -4
- package/src/helper/index.tsx +1 -21
- package/src/messages/messages.tsx +13 -31
- package/src/store/index.ts +37 -8
package/CHANGELOG.md
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fe-free/ai",
|
|
3
|
-
"version": "4.1.
|
|
3
|
+
"version": "4.1.38",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "./src/index.ts",
|
|
6
6
|
"author": "",
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"lodash-es": "^4.17.21",
|
|
20
20
|
"uuid": "^13.0.0",
|
|
21
21
|
"zustand": "^4.5.7",
|
|
22
|
-
"@fe-free/core": "4.1.
|
|
22
|
+
"@fe-free/core": "4.1.38"
|
|
23
23
|
},
|
|
24
24
|
"peerDependencies": {
|
|
25
25
|
"antd": "^5.27.1",
|
|
@@ -29,8 +29,8 @@
|
|
|
29
29
|
"i18next-icu": "^2.4.1",
|
|
30
30
|
"react": "^19.2.0",
|
|
31
31
|
"react-i18next": "^16.4.0",
|
|
32
|
-
"@fe-free/icons": "4.1.
|
|
33
|
-
"@fe-free/tool": "4.1.
|
|
32
|
+
"@fe-free/icons": "4.1.38",
|
|
33
|
+
"@fe-free/tool": "4.1.38"
|
|
34
34
|
},
|
|
35
35
|
"scripts": {
|
|
36
36
|
"test": "echo \"Error: no test specified\" && exit 1",
|
package/src/helper/index.tsx
CHANGED
|
@@ -42,24 +42,4 @@ function generateUUID() {
|
|
|
42
42
|
return uuidv4();
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
-
|
|
46
|
-
// 创建一个不可见的 div 元素
|
|
47
|
-
const outer = document.createElement('div');
|
|
48
|
-
outer.style.visibility = 'hidden';
|
|
49
|
-
outer.style.overflow = 'scroll'; // 强制显示滚动条
|
|
50
|
-
document.body.appendChild(outer);
|
|
51
|
-
|
|
52
|
-
// 创建一个内部 div,宽度为 100%
|
|
53
|
-
const inner = document.createElement('div');
|
|
54
|
-
outer.appendChild(inner);
|
|
55
|
-
|
|
56
|
-
// 滚动条宽度 = 外部容器的宽度 - 内部内容的宽度
|
|
57
|
-
const scrollbarWidth = outer.offsetWidth - inner.offsetWidth;
|
|
58
|
-
|
|
59
|
-
// 清理 DOM
|
|
60
|
-
document.body.removeChild(outer);
|
|
61
|
-
|
|
62
|
-
return scrollbarWidth;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
export { generateUUID, getScrollbarWidth, RecordLoading };
|
|
45
|
+
export { generateUUID, RecordLoading };
|
|
@@ -1,30 +1,21 @@
|
|
|
1
|
-
import { PageLayout } from '@fe-free/core';
|
|
1
|
+
import { PageLayout, ScrollFixed } from '@fe-free/core';
|
|
2
2
|
import { ArrowDownOutlined } from '@fe-free/icons';
|
|
3
3
|
import { useMemoizedFn } from 'ahooks';
|
|
4
4
|
import { Button } from 'antd';
|
|
5
5
|
import { useEffect, useMemo, useRef, useState } from 'react';
|
|
6
|
-
import { getScrollbarWidth } from '../helper';
|
|
7
6
|
import { EnumChatMessageType, type ChatMessage } from '../store/types';
|
|
8
7
|
|
|
9
|
-
interface MessagesProps<AIData> {
|
|
8
|
+
interface MessagesProps<UserData, AIData> {
|
|
10
9
|
refList?: React.RefObject<HTMLDivElement | null>;
|
|
11
|
-
messages?: ChatMessage<AIData>[];
|
|
10
|
+
messages?: ChatMessage<UserData, AIData>[];
|
|
12
11
|
/** 含所有 */
|
|
13
|
-
renderMessage?: (props: { message: ChatMessage<AIData> }) => React.ReactNode;
|
|
12
|
+
renderMessage?: (props: { message: ChatMessage<UserData, AIData> }) => React.ReactNode;
|
|
14
13
|
/** 系统消息 */
|
|
15
|
-
renderMessageOfSystem?: (props: { message: ChatMessage<AIData> }) => React.ReactNode;
|
|
14
|
+
renderMessageOfSystem?: (props: { message: ChatMessage<UserData, AIData> }) => React.ReactNode;
|
|
16
15
|
/** 用户消息 */
|
|
17
|
-
renderMessageOfUser?: (props: { message: ChatMessage<AIData> }) => React.ReactNode;
|
|
16
|
+
renderMessageOfUser?: (props: { message: ChatMessage<UserData, AIData> }) => React.ReactNode;
|
|
18
17
|
/** AI消息 */
|
|
19
|
-
renderMessageOfAI?: (props: { message: ChatMessage<AIData> }) => React.ReactNode;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
function useScrollWidth() {
|
|
23
|
-
const width = useMemo(() => {
|
|
24
|
-
return getScrollbarWidth();
|
|
25
|
-
}, []);
|
|
26
|
-
|
|
27
|
-
return width;
|
|
18
|
+
renderMessageOfAI?: (props: { message: ChatMessage<UserData, AIData> }) => React.ReactNode;
|
|
28
19
|
}
|
|
29
20
|
|
|
30
21
|
function useScrollToBottom({ ref }) {
|
|
@@ -58,7 +49,7 @@ function useScrollToBottom({ ref }) {
|
|
|
58
49
|
return showScrollBottom;
|
|
59
50
|
}
|
|
60
51
|
|
|
61
|
-
function Messages<AIData>(props: MessagesProps<AIData>) {
|
|
52
|
+
function Messages<UserData, AIData>(props: MessagesProps<UserData, AIData>) {
|
|
62
53
|
const {
|
|
63
54
|
refList,
|
|
64
55
|
messages,
|
|
@@ -120,14 +111,12 @@ function Messages<AIData>(props: MessagesProps<AIData>) {
|
|
|
120
111
|
}, 100);
|
|
121
112
|
}, [lastMessage?.updatedAt, lastMessage?.uuid, ref, scrollToBottom]);
|
|
122
113
|
|
|
123
|
-
const scrollWidth = useScrollWidth();
|
|
124
|
-
|
|
125
114
|
const showScrollBottom = useScrollToBottom({ ref });
|
|
126
115
|
|
|
127
116
|
return (
|
|
128
117
|
<PageLayout>
|
|
129
|
-
<
|
|
130
|
-
|
|
118
|
+
<ScrollFixed
|
|
119
|
+
refScroll={ref}
|
|
131
120
|
className="fea-messages-scroll relative flex h-full flex-col overflow-y-auto overflow-x-hidden"
|
|
132
121
|
style={{
|
|
133
122
|
transform: `translateZ(0)`,
|
|
@@ -135,14 +124,7 @@ function Messages<AIData>(props: MessagesProps<AIData>) {
|
|
|
135
124
|
>
|
|
136
125
|
{messages?.map((message) => {
|
|
137
126
|
return (
|
|
138
|
-
<div
|
|
139
|
-
key={message.uuid}
|
|
140
|
-
data-uuid={message.uuid}
|
|
141
|
-
className="flex flex-col"
|
|
142
|
-
style={{
|
|
143
|
-
marginRight: `-${scrollWidth}px`,
|
|
144
|
-
}}
|
|
145
|
-
>
|
|
127
|
+
<div key={message.uuid} data-uuid={message.uuid} className="flex flex-col">
|
|
146
128
|
{renderMessage ? (
|
|
147
129
|
renderMessage?.({ message })
|
|
148
130
|
) : (
|
|
@@ -172,13 +154,13 @@ function Messages<AIData>(props: MessagesProps<AIData>) {
|
|
|
172
154
|
}}
|
|
173
155
|
className="bg-white text-2xl shadow-[0px_1px_12px_0px_#2921391F]"
|
|
174
156
|
style={{
|
|
175
|
-
transform: `translateY(${showScrollBottom ? 0 : 30}px) scale(${showScrollBottom ? 1 : 0
|
|
157
|
+
transform: `translateY(${showScrollBottom ? 0 : 30}px) scale(${showScrollBottom ? 1 : 0})`,
|
|
176
158
|
width: 44,
|
|
177
159
|
height: 44,
|
|
178
160
|
}}
|
|
179
161
|
/>
|
|
180
162
|
</div>
|
|
181
|
-
</
|
|
163
|
+
</ScrollFixed>
|
|
182
164
|
</PageLayout>
|
|
183
165
|
);
|
|
184
166
|
}
|
package/src/store/index.ts
CHANGED
|
@@ -11,6 +11,14 @@ interface ChatStore<
|
|
|
11
11
|
AIData,
|
|
12
12
|
ContextData extends Record<string, any>,
|
|
13
13
|
> {
|
|
14
|
+
/** 存放Chat的上下文数据 */
|
|
15
|
+
contextData?: ContextData;
|
|
16
|
+
setContextData: (contextData?: ContextData) => void;
|
|
17
|
+
setContextDataWithField: (
|
|
18
|
+
field: keyof ContextData,
|
|
19
|
+
contextDataValue: ContextData[keyof ContextData],
|
|
20
|
+
) => void;
|
|
21
|
+
|
|
14
22
|
senderValue?: UserData;
|
|
15
23
|
setSenderValue: (senderValue?: UserData) => void;
|
|
16
24
|
|
|
@@ -18,10 +26,7 @@ interface ChatStore<
|
|
|
18
26
|
setMessages: (messages: ChatMessage<UserData, AIData>[]) => void;
|
|
19
27
|
addMessage: (message: ChatMessage<UserData, AIData>) => void;
|
|
20
28
|
updateMessage: (message: ChatMessage<UserData, AIData>) => void;
|
|
21
|
-
|
|
22
|
-
/** 存放Chat的上下文数据 */
|
|
23
|
-
contextData?: ContextData;
|
|
24
|
-
setContextData: (contextData?: ContextData) => void;
|
|
29
|
+
setMessagesBefore: (messages: ChatMessage<UserData, AIData>[]) => void;
|
|
25
30
|
|
|
26
31
|
reset: () => void;
|
|
27
32
|
}
|
|
@@ -29,13 +34,27 @@ interface ChatStore<
|
|
|
29
34
|
function createChatStore<
|
|
30
35
|
UserData extends BaseSenderValue,
|
|
31
36
|
AIData,
|
|
32
|
-
ContextData extends Record<string, any
|
|
37
|
+
ContextData extends Record<string, any> = any,
|
|
33
38
|
>() {
|
|
34
39
|
const useChatStore = create<ChatStore<UserData, AIData, ContextData>>((set, get, store) => ({
|
|
40
|
+
contextData: undefined,
|
|
41
|
+
setContextData: (contextData) => {
|
|
42
|
+
set({ contextData });
|
|
43
|
+
},
|
|
44
|
+
setContextDataWithField: (field, contextDataValue) => {
|
|
45
|
+
const preContextData = get().contextData;
|
|
46
|
+
set({
|
|
47
|
+
contextData: {
|
|
48
|
+
...preContextData,
|
|
49
|
+
[field]: contextDataValue,
|
|
50
|
+
} as ContextData,
|
|
51
|
+
});
|
|
52
|
+
},
|
|
35
53
|
senderValue: undefined,
|
|
36
54
|
setSenderValue: (senderValue) => {
|
|
37
55
|
set(() => ({ senderValue }));
|
|
38
56
|
},
|
|
57
|
+
|
|
39
58
|
messages: [],
|
|
40
59
|
setMessages: (messages) => {
|
|
41
60
|
set(() => ({
|
|
@@ -74,9 +93,19 @@ function createChatStore<
|
|
|
74
93
|
}),
|
|
75
94
|
}));
|
|
76
95
|
},
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
96
|
+
setMessagesBefore: (messagesBefore) => {
|
|
97
|
+
const messages = get().messages;
|
|
98
|
+
|
|
99
|
+
const lastMessageBefore = messagesBefore[messagesBefore.length - 1];
|
|
100
|
+
const index = messages.findIndex((message) => message.uuid === lastMessageBefore.uuid);
|
|
101
|
+
|
|
102
|
+
// 如果 index 非 -1,则合并
|
|
103
|
+
// 如果 index -1,-1 + 1 为 0,即全取 message,也适用
|
|
104
|
+
const newMessages = [...messagesBefore, ...messages.slice(index + 1)];
|
|
105
|
+
|
|
106
|
+
set({
|
|
107
|
+
messages: newMessages,
|
|
108
|
+
});
|
|
80
109
|
},
|
|
81
110
|
reset: () => {
|
|
82
111
|
set(store.getInitialState());
|