@lobehub/chat 1.31.9 → 1.31.11
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 +42 -0
- package/locales/ar/error.json +1 -0
- package/locales/ar/models.json +3 -9
- package/locales/bg-BG/error.json +1 -0
- package/locales/bg-BG/models.json +3 -9
- package/locales/de-DE/error.json +1 -0
- package/locales/de-DE/models.json +3 -9
- package/locales/en-US/error.json +1 -0
- package/locales/en-US/models.json +3 -9
- package/locales/es-ES/error.json +1 -0
- package/locales/es-ES/models.json +4 -10
- package/locales/fa-IR/error.json +1 -0
- package/locales/fa-IR/models.json +3 -9
- package/locales/fr-FR/error.json +1 -0
- package/locales/fr-FR/models.json +4 -10
- package/locales/it-IT/error.json +1 -0
- package/locales/it-IT/models.json +3 -9
- package/locales/ja-JP/error.json +1 -0
- package/locales/ja-JP/models.json +3 -9
- package/locales/ko-KR/error.json +1 -0
- package/locales/ko-KR/models.json +3 -9
- package/locales/nl-NL/error.json +1 -0
- package/locales/nl-NL/models.json +3 -9
- package/locales/pl-PL/error.json +1 -0
- package/locales/pl-PL/models.json +4 -10
- package/locales/pt-BR/error.json +1 -0
- package/locales/pt-BR/models.json +3 -9
- package/locales/ru-RU/error.json +1 -0
- package/locales/ru-RU/models.json +3 -9
- package/locales/tr-TR/error.json +1 -0
- package/locales/tr-TR/models.json +3 -9
- package/locales/vi-VN/error.json +1 -0
- package/locales/vi-VN/models.json +3 -9
- package/locales/zh-CN/error.json +2 -1
- package/locales/zh-CN/models.json +3 -9
- package/locales/zh-TW/error.json +1 -0
- package/locales/zh-TW/models.json +3 -9
- package/package.json +3 -3
- package/src/{features → app/(main)/chat/(workspace)/@conversation/features}/ChatInput/Desktop/TextArea.test.tsx +13 -13
- package/src/app/(main)/chat/(workspace)/@conversation/features/ChatInput/Desktop/TextArea.tsx +29 -0
- package/src/app/(main)/chat/(workspace)/@conversation/features/ChatInput/Desktop/index.tsx +46 -0
- package/src/app/(main)/chat/(workspace)/@conversation/features/ChatInput/index.tsx +2 -1
- package/src/app/(main)/chat/(workspace)/@conversation/features/ChatList/Content.tsx +13 -11
- package/src/app/(main)/settings/llm/components/Checker.tsx +9 -2
- package/src/const/message.ts +4 -0
- package/src/features/ChatInput/Desktop/Footer/ShortcutHint.tsx +61 -0
- package/src/features/ChatInput/Desktop/Footer/index.tsx +11 -46
- package/src/features/ChatInput/Desktop/{TextArea.tsx → InputArea/index.tsx} +11 -20
- package/src/features/ChatInput/Desktop/index.tsx +23 -32
- package/src/features/Conversation/Messages/index.ts +11 -11
- package/src/features/Conversation/components/ChatItem/index.tsx +83 -44
- package/src/features/Conversation/components/VirtualizedList/index.tsx +90 -92
- package/src/features/Conversation/index.ts +2 -0
- package/src/libs/agent-runtime/error.ts +2 -0
- package/src/locales/default/error.ts +1 -0
- package/src/types/topic/index.ts +1 -0
- /package/src/types/{topic.ts → topic/topic.ts} +0 -0
@@ -1,23 +1,20 @@
|
|
1
|
-
import {
|
2
|
-
import { Button, Skeleton, Space } from 'antd';
|
1
|
+
import { Button, Space } from 'antd';
|
3
2
|
import { createStyles } from 'antd-style';
|
4
|
-
import { ChevronUp, CornerDownLeft, LucideCommand } from 'lucide-react';
|
5
3
|
import { rgba } from 'polished';
|
6
4
|
import { memo, useEffect, useState } from 'react';
|
7
5
|
import { useTranslation } from 'react-i18next';
|
8
|
-
import {
|
6
|
+
import { Flexbox } from 'react-layout-kit';
|
9
7
|
|
10
8
|
import StopLoadingIcon from '@/components/StopLoading';
|
11
|
-
import SaveTopic from '@/features/ChatInput/Topic';
|
12
9
|
import { useSendMessage } from '@/features/ChatInput/useSend';
|
13
10
|
import { useChatStore } from '@/store/chat';
|
14
11
|
import { chatSelectors } from '@/store/chat/selectors';
|
15
|
-
import { useUserStore } from '@/store/user';
|
16
|
-
import { preferenceSelectors } from '@/store/user/selectors';
|
17
12
|
import { isMacOS } from '@/utils/platform';
|
18
13
|
|
14
|
+
import SaveTopic from '../../Topic';
|
19
15
|
import LocalFiles from '../FilePreview';
|
20
16
|
import SendMore from './SendMore';
|
17
|
+
import ShortcutHint from './ShortcutHint';
|
21
18
|
|
22
19
|
const useStyles = createStyles(({ css, prefixCls, token }) => {
|
23
20
|
return {
|
@@ -48,51 +45,29 @@ const useStyles = createStyles(({ css, prefixCls, token }) => {
|
|
48
45
|
|
49
46
|
interface FooterProps {
|
50
47
|
expand: boolean;
|
48
|
+
saveTopic?: boolean;
|
51
49
|
setExpand?: (expand: boolean) => void;
|
50
|
+
shortcutHint?: boolean;
|
52
51
|
}
|
53
52
|
|
54
|
-
const Footer = memo<FooterProps>(({ setExpand, expand }) => {
|
53
|
+
const Footer = memo<FooterProps>(({ setExpand, expand, shortcutHint = true, saveTopic = true }) => {
|
55
54
|
const { t } = useTranslation('chat');
|
56
55
|
|
57
|
-
const {
|
56
|
+
const { styles } = useStyles();
|
58
57
|
|
59
58
|
const [isAIGenerating, stopGenerateMessage] = useChatStore((s) => [
|
60
59
|
chatSelectors.isAIGenerating(s),
|
61
60
|
s.stopGenerateMessage,
|
62
61
|
]);
|
63
62
|
|
64
|
-
const [useCmdEnterToSend] = useUserStore((s) => [preferenceSelectors.useCmdEnterToSend(s)]);
|
65
|
-
|
66
63
|
const { send: sendMessage, canSend } = useSendMessage();
|
67
64
|
|
68
65
|
const [isMac, setIsMac] = useState<boolean>();
|
66
|
+
|
69
67
|
useEffect(() => {
|
70
68
|
setIsMac(isMacOS());
|
71
69
|
}, [setIsMac]);
|
72
70
|
|
73
|
-
const cmdEnter = (
|
74
|
-
<Flexbox gap={2} horizontal>
|
75
|
-
{typeof isMac === 'boolean' ? (
|
76
|
-
<Icon icon={isMac ? LucideCommand : ChevronUp} />
|
77
|
-
) : (
|
78
|
-
<Skeleton.Node active style={{ height: '100%', width: 12 }}>
|
79
|
-
{' '}
|
80
|
-
</Skeleton.Node>
|
81
|
-
)}
|
82
|
-
<Icon icon={CornerDownLeft} />
|
83
|
-
</Flexbox>
|
84
|
-
);
|
85
|
-
|
86
|
-
const enter = (
|
87
|
-
<Center>
|
88
|
-
<Icon icon={CornerDownLeft} />
|
89
|
-
</Center>
|
90
|
-
);
|
91
|
-
|
92
|
-
const sendShortcut = useCmdEnterToSend ? cmdEnter : enter;
|
93
|
-
|
94
|
-
const wrapperShortcut = useCmdEnterToSend ? enter : cmdEnter;
|
95
|
-
|
96
71
|
return (
|
97
72
|
<Flexbox
|
98
73
|
align={'end'}
|
@@ -107,18 +82,8 @@ const Footer = memo<FooterProps>(({ setExpand, expand }) => {
|
|
107
82
|
{expand && <LocalFiles />}
|
108
83
|
</Flexbox>
|
109
84
|
<Flexbox align={'center'} flex={'none'} gap={8} horizontal>
|
110
|
-
<
|
111
|
-
|
112
|
-
horizontal
|
113
|
-
style={{ color: theme.colorTextDescription, fontSize: 12, marginRight: 12 }}
|
114
|
-
>
|
115
|
-
{sendShortcut}
|
116
|
-
<span>{t('input.send')}</span>
|
117
|
-
<span>/</span>
|
118
|
-
{wrapperShortcut}
|
119
|
-
<span>{t('input.warp')}</span>
|
120
|
-
</Flexbox>
|
121
|
-
<SaveTopic />
|
85
|
+
{shortcutHint && <ShortcutHint />}
|
86
|
+
{saveTopic && <SaveTopic />}
|
122
87
|
<Flexbox style={{ minWidth: 92 }}>
|
123
88
|
{isAIGenerating ? (
|
124
89
|
<Button
|
@@ -4,14 +4,11 @@ import { TextAreaRef } from 'antd/es/input/TextArea';
|
|
4
4
|
import { memo, useEffect, useRef } from 'react';
|
5
5
|
import { useTranslation } from 'react-i18next';
|
6
6
|
|
7
|
-
import { useSendMessage } from '@/features/ChatInput/useSend';
|
8
|
-
import { useChatStore } from '@/store/chat';
|
9
|
-
import { chatSelectors } from '@/store/chat/selectors';
|
10
7
|
import { useUserStore } from '@/store/user';
|
11
8
|
import { preferenceSelectors } from '@/store/user/selectors';
|
12
9
|
import { isCommandPressed } from '@/utils/keyboard';
|
13
10
|
|
14
|
-
import { useAutoFocus } from '
|
11
|
+
import { useAutoFocus } from '../useAutoFocus';
|
15
12
|
|
16
13
|
const useStyles = createStyles(({ css }) => {
|
17
14
|
return {
|
@@ -34,25 +31,20 @@ const useStyles = createStyles(({ css }) => {
|
|
34
31
|
});
|
35
32
|
|
36
33
|
interface InputAreaProps {
|
37
|
-
|
34
|
+
loading?: boolean;
|
35
|
+
onChange: (string: string) => void;
|
36
|
+
onSend: () => void;
|
37
|
+
value: string;
|
38
38
|
}
|
39
39
|
|
40
|
-
const InputArea = memo<InputAreaProps>(({
|
40
|
+
const InputArea = memo<InputAreaProps>(({ onSend, value, loading, onChange }) => {
|
41
41
|
const { t } = useTranslation('chat');
|
42
42
|
const { styles } = useStyles();
|
43
43
|
const ref = useRef<TextAreaRef>(null);
|
44
44
|
const isChineseInput = useRef(false);
|
45
45
|
|
46
|
-
const [loading, value, updateInputMessage] = useChatStore((s) => [
|
47
|
-
chatSelectors.isAIGenerating(s),
|
48
|
-
s.inputMessage,
|
49
|
-
s.updateInputMessage,
|
50
|
-
]);
|
51
|
-
|
52
46
|
const useCmdEnterToSend = useUserStore(preferenceSelectors.useCmdEnterToSend);
|
53
47
|
|
54
|
-
const { send: sendMessage } = useSendMessage();
|
55
|
-
|
56
48
|
useAutoFocus(ref);
|
57
49
|
|
58
50
|
const hasValue = !!value;
|
@@ -78,10 +70,10 @@ const InputArea = memo<InputAreaProps>(({ setExpand }) => {
|
|
78
70
|
autoFocus
|
79
71
|
className={styles.textarea}
|
80
72
|
onBlur={(e) => {
|
81
|
-
|
73
|
+
onChange?.(e.target.value);
|
82
74
|
}}
|
83
75
|
onChange={(e) => {
|
84
|
-
|
76
|
+
onChange?.(e.target.value);
|
85
77
|
}}
|
86
78
|
onCompositionEnd={() => {
|
87
79
|
isChineseInput.current = false;
|
@@ -98,8 +90,7 @@ const InputArea = memo<InputAreaProps>(({ setExpand }) => {
|
|
98
90
|
// refs: https://github.com/lobehub/lobe-chat/pull/989
|
99
91
|
e.preventDefault();
|
100
92
|
|
101
|
-
|
102
|
-
setExpand?.(false);
|
93
|
+
onSend();
|
103
94
|
};
|
104
95
|
const commandKey = isCommandPressed(e);
|
105
96
|
|
@@ -109,7 +100,7 @@ const InputArea = memo<InputAreaProps>(({ setExpand }) => {
|
|
109
100
|
} else {
|
110
101
|
// cmd + enter to wrap
|
111
102
|
if (commandKey) {
|
112
|
-
|
103
|
+
onChange?.((e.target as any).value + '\n');
|
113
104
|
return;
|
114
105
|
}
|
115
106
|
|
@@ -125,6 +116,6 @@ const InputArea = memo<InputAreaProps>(({ setExpand }) => {
|
|
125
116
|
);
|
126
117
|
});
|
127
118
|
|
128
|
-
InputArea.displayName = '
|
119
|
+
InputArea.displayName = 'DesktopInputArea';
|
129
120
|
|
130
121
|
export default InputArea;
|
@@ -1,59 +1,50 @@
|
|
1
1
|
'use client';
|
2
2
|
|
3
3
|
import { DraggablePanel } from '@lobehub/ui';
|
4
|
-
import { memo, useState } from 'react';
|
4
|
+
import { ReactNode, memo, useCallback, useState } from 'react';
|
5
5
|
import { Flexbox } from 'react-layout-kit';
|
6
6
|
|
7
7
|
import { CHAT_TEXTAREA_HEIGHT, CHAT_TEXTAREA_MAX_HEIGHT } from '@/const/layoutTokens';
|
8
|
-
import { ActionKeys } from '@/features/ChatInput/ActionBar/config';
|
9
|
-
import { useGlobalStore } from '@/store/global';
|
10
|
-
import { systemStatusSelectors } from '@/store/global/selectors';
|
11
8
|
|
9
|
+
import { ActionKeys } from '../ActionBar/config';
|
12
10
|
import LocalFiles from './FilePreview';
|
13
11
|
import Footer from './Footer';
|
14
12
|
import Head from './Header';
|
15
|
-
import TextArea from './TextArea';
|
16
|
-
|
17
|
-
const defaultLeftActions = [
|
18
|
-
'model',
|
19
|
-
'fileUpload',
|
20
|
-
'knowledgeBase',
|
21
|
-
'temperature',
|
22
|
-
'history',
|
23
|
-
'stt',
|
24
|
-
'tools',
|
25
|
-
'token',
|
26
|
-
] as ActionKeys[];
|
27
|
-
|
28
|
-
const defaultRightActions = ['clear'] as ActionKeys[];
|
29
13
|
|
30
14
|
interface DesktopChatInputProps {
|
31
|
-
|
32
|
-
|
15
|
+
footer?: {
|
16
|
+
saveTopic?: boolean;
|
17
|
+
shortcutHint?: boolean;
|
18
|
+
};
|
19
|
+
inputHeight: number;
|
20
|
+
leftActions: ActionKeys[];
|
21
|
+
onInputHeightChange?: (height: number) => void;
|
22
|
+
renderTextArea: (onSend: () => void) => ReactNode;
|
23
|
+
rightActions: ActionKeys[];
|
33
24
|
}
|
25
|
+
|
34
26
|
const DesktopChatInput = memo<DesktopChatInputProps>(
|
35
|
-
({ leftActions
|
27
|
+
({ leftActions, rightActions, footer, renderTextArea, inputHeight, onInputHeightChange }) => {
|
36
28
|
const [expand, setExpand] = useState<boolean>(false);
|
37
29
|
|
38
|
-
const
|
39
|
-
|
40
|
-
|
41
|
-
]);
|
30
|
+
const onSend = useCallback(() => {
|
31
|
+
setExpand(false);
|
32
|
+
}, []);
|
42
33
|
|
43
34
|
return (
|
44
35
|
<>
|
45
|
-
{!expand && <LocalFiles />}
|
36
|
+
{!expand && leftActions.includes('fileUpload') && <LocalFiles />}
|
46
37
|
<DraggablePanel
|
47
38
|
fullscreen={expand}
|
48
39
|
maxHeight={CHAT_TEXTAREA_MAX_HEIGHT}
|
49
40
|
minHeight={CHAT_TEXTAREA_HEIGHT}
|
50
41
|
onSizeChange={(_, size) => {
|
51
42
|
if (!size) return;
|
43
|
+
const height =
|
44
|
+
typeof size.height === 'string' ? Number.parseInt(size.height) : size.height;
|
45
|
+
if (!height) return;
|
52
46
|
|
53
|
-
|
54
|
-
inputHeight:
|
55
|
-
typeof size.height === 'string' ? Number.parseInt(size.height) : size.height,
|
56
|
-
});
|
47
|
+
onInputHeightChange?.(height);
|
57
48
|
}}
|
58
49
|
placement="bottom"
|
59
50
|
size={{ height: inputHeight, width: '100%' }}
|
@@ -71,8 +62,8 @@ const DesktopChatInput = memo<DesktopChatInputProps>(
|
|
71
62
|
rightActions={rightActions}
|
72
63
|
setExpand={setExpand}
|
73
64
|
/>
|
74
|
-
|
75
|
-
<Footer expand={expand} setExpand={setExpand} />
|
65
|
+
{renderTextArea(onSend)}
|
66
|
+
<Footer expand={expand} setExpand={setExpand} {...footer} />
|
76
67
|
</Flexbox>
|
77
68
|
</DraggablePanel>
|
78
69
|
</>
|
@@ -1,9 +1,11 @@
|
|
1
|
+
import { useCallback } from 'react';
|
2
|
+
|
1
3
|
import { useOpenChatSettings } from '@/hooks/useInterceptingRoutes';
|
2
4
|
import { useGlobalStore } from '@/store/global';
|
3
5
|
import { useSessionStore } from '@/store/session';
|
4
6
|
import { sessionSelectors } from '@/store/session/selectors';
|
5
7
|
|
6
|
-
import { MarkdownCustomRender,
|
8
|
+
import { MarkdownCustomRender, RenderBelowMessage, RenderMessage } from '../types';
|
7
9
|
import { AssistantMessage } from './Assistant';
|
8
10
|
import { DefaultBelowMessage, DefaultMessage } from './Default';
|
9
11
|
import { ToolMessage } from './Tool';
|
@@ -26,22 +28,20 @@ export const markdownCustomRenders: Record<string, MarkdownCustomRender> = {
|
|
26
28
|
user: UserMarkdownRender,
|
27
29
|
};
|
28
30
|
|
29
|
-
export const useAvatarsClick = ()
|
31
|
+
export const useAvatarsClick = (role?: string) => {
|
30
32
|
const [isInbox] = useSessionStore((s) => [sessionSelectors.isInboxSession(s)]);
|
31
33
|
const [toggleSystemRole] = useGlobalStore((s) => [s.toggleSystemRole]);
|
32
34
|
const openChatSettings = useOpenChatSettings();
|
33
35
|
|
34
|
-
return (
|
36
|
+
return useCallback(() => {
|
35
37
|
switch (role) {
|
36
38
|
case 'assistant': {
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
}
|
43
|
-
};
|
39
|
+
if (!isInbox) {
|
40
|
+
toggleSystemRole(true);
|
41
|
+
} else {
|
42
|
+
openChatSettings();
|
43
|
+
}
|
44
44
|
}
|
45
45
|
}
|
46
|
-
};
|
46
|
+
}, [isInbox, role]);
|
47
47
|
};
|
@@ -1,7 +1,9 @@
|
|
1
|
+
'use client';
|
2
|
+
|
1
3
|
import { ChatItem } from '@lobehub/ui';
|
2
4
|
import { createStyles } from 'antd-style';
|
3
5
|
import isEqual from 'fast-deep-equal';
|
4
|
-
import { ReactNode, memo, useCallback, useMemo } from 'react';
|
6
|
+
import { MouseEventHandler, ReactNode, memo, useCallback, useMemo } from 'react';
|
5
7
|
import { useTranslation } from 'react-i18next';
|
6
8
|
|
7
9
|
import { useAgentStore } from '@/store/agent';
|
@@ -42,11 +44,13 @@ const useStyles = createStyles(({ css, prefixCls }) => ({
|
|
42
44
|
}));
|
43
45
|
|
44
46
|
export interface ChatListItemProps {
|
47
|
+
hideActionBar?: boolean;
|
45
48
|
id: string;
|
46
49
|
index: number;
|
50
|
+
showThreadDivider?: boolean;
|
47
51
|
}
|
48
52
|
|
49
|
-
const Item = memo<ChatListItemProps>(({ index, id }) => {
|
53
|
+
const Item = memo<ChatListItemProps>(({ index, id, hideActionBar }) => {
|
50
54
|
const fontSize = useUserStore(userGeneralSettingsSelectors.fontSize);
|
51
55
|
const { t } = useTranslation('common');
|
52
56
|
const { styles, cx } = useStyles();
|
@@ -61,7 +65,7 @@ const Item = memo<ChatListItemProps>(({ index, id }) => {
|
|
61
65
|
|
62
66
|
if (index >= chats.length) return;
|
63
67
|
|
64
|
-
return chats
|
68
|
+
return chats.find((s) => s.id === id);
|
65
69
|
}, isEqual);
|
66
70
|
|
67
71
|
const [
|
@@ -83,18 +87,18 @@ const Item = memo<ChatListItemProps>(({ index, id }) => {
|
|
83
87
|
// when the message is in RAG flow or the AI generating, it should be in loading state
|
84
88
|
const isProcessing = isInRAGFlow || generating;
|
85
89
|
|
86
|
-
const onAvatarsClick = useAvatarsClick();
|
90
|
+
const onAvatarsClick = useAvatarsClick(item?.role);
|
87
91
|
|
88
|
-
const
|
89
|
-
(
|
92
|
+
const renderMessage = useCallback(
|
93
|
+
(editableContent: ReactNode) => {
|
90
94
|
if (!item?.role) return;
|
91
95
|
const RenderFunction = renderMessages[item.role] ?? renderMessages['default'];
|
92
96
|
|
93
97
|
if (!RenderFunction) return;
|
94
98
|
|
95
|
-
return <RenderFunction {...
|
99
|
+
return <RenderFunction {...item} editableContent={editableContent} />;
|
96
100
|
},
|
97
|
-
[item
|
101
|
+
[item],
|
98
102
|
);
|
99
103
|
|
100
104
|
const BelowMessage = useCallback(
|
@@ -136,7 +140,7 @@ const Item = memo<ChatListItemProps>(({ index, id }) => {
|
|
136
140
|
|
137
141
|
const error = useErrorContent(item?.error);
|
138
142
|
|
139
|
-
const historyLength = useChatStore((s) => chatSelectors.currentChats(s).length);
|
143
|
+
const [historyLength] = useChatStore((s) => [chatSelectors.currentChats(s).length]);
|
140
144
|
|
141
145
|
const enableHistoryDivider = useAgentStore((s) => {
|
142
146
|
const config = agentSelectors.currentAgentChatConfig(s);
|
@@ -151,6 +155,11 @@ const Item = memo<ChatListItemProps>(({ index, id }) => {
|
|
151
155
|
const message =
|
152
156
|
!editing && item?.role === 'assistant' ? processWithArtifact(item?.content) : item?.content;
|
153
157
|
|
158
|
+
// ======================= Performance Optimization ======================= //
|
159
|
+
// these useMemo/useCallback are all for the performance optimization
|
160
|
+
// maybe we can remove it in React 19
|
161
|
+
// ======================================================================== //
|
162
|
+
|
154
163
|
const components = useMemo(
|
155
164
|
() =>
|
156
165
|
Object.fromEntries(
|
@@ -163,55 +172,83 @@ const Item = memo<ChatListItemProps>(({ index, id }) => {
|
|
163
172
|
[id],
|
164
173
|
);
|
165
174
|
|
175
|
+
const markdownProps = useMemo(
|
176
|
+
() => ({
|
177
|
+
components,
|
178
|
+
customRender: markdownCustomRender,
|
179
|
+
rehypePlugins,
|
180
|
+
}),
|
181
|
+
[components, markdownCustomRender],
|
182
|
+
);
|
183
|
+
|
184
|
+
const onChange = useCallback((value: string) => updateMessageContent(id, value), [id]);
|
185
|
+
|
186
|
+
const onDoubleClick = useCallback<MouseEventHandler<HTMLDivElement>>(
|
187
|
+
(e) => {
|
188
|
+
if (!item) return;
|
189
|
+
if (item.id === 'default' || item.error) return;
|
190
|
+
if (item.role && ['assistant', 'user'].includes(item.role) && e.altKey) {
|
191
|
+
toggleMessageEditing(id, true);
|
192
|
+
}
|
193
|
+
},
|
194
|
+
[item],
|
195
|
+
);
|
196
|
+
|
197
|
+
const text = useMemo(
|
198
|
+
() => ({
|
199
|
+
cancel: t('cancel'),
|
200
|
+
confirm: t('ok'),
|
201
|
+
edit: t('edit'),
|
202
|
+
}),
|
203
|
+
[t],
|
204
|
+
);
|
205
|
+
|
206
|
+
const onEditingChange = useCallback((edit: boolean) => {
|
207
|
+
toggleMessageEditing(id, edit);
|
208
|
+
}, []);
|
209
|
+
|
210
|
+
const actions = useMemo(
|
211
|
+
() =>
|
212
|
+
!hideActionBar && (
|
213
|
+
<ActionsBar
|
214
|
+
index={index}
|
215
|
+
setEditing={(edit) => {
|
216
|
+
toggleMessageEditing(id, edit);
|
217
|
+
}}
|
218
|
+
/>
|
219
|
+
),
|
220
|
+
[hideActionBar, index, id],
|
221
|
+
);
|
222
|
+
|
223
|
+
const belowMessage = useMemo(() => item && <BelowMessage data={item} />, [item]);
|
224
|
+
const errorMessage = useMemo(() => item && <ErrorMessageExtra data={item} />, [item]);
|
225
|
+
const messageExtra = useMemo(() => item && <MessageExtra data={item} />, [item]);
|
226
|
+
|
166
227
|
return (
|
167
228
|
item && (
|
168
229
|
<>
|
169
230
|
{enableHistoryDivider && <History />}
|
170
231
|
<ChatItem
|
171
|
-
actions={
|
172
|
-
<ActionsBar
|
173
|
-
index={index}
|
174
|
-
setEditing={(edit) => {
|
175
|
-
toggleMessageEditing(id, edit);
|
176
|
-
}}
|
177
|
-
/>
|
178
|
-
}
|
232
|
+
actions={actions}
|
179
233
|
avatar={item.meta}
|
180
|
-
belowMessage={
|
234
|
+
belowMessage={belowMessage}
|
181
235
|
className={cx(styles.message, isMessageLoading && styles.loading)}
|
182
236
|
editing={editing}
|
183
237
|
error={error}
|
184
|
-
errorMessage={
|
238
|
+
errorMessage={errorMessage}
|
185
239
|
fontSize={fontSize}
|
186
240
|
loading={isProcessing}
|
187
|
-
markdownProps={
|
188
|
-
components,
|
189
|
-
customRender: markdownCustomRender,
|
190
|
-
rehypePlugins,
|
191
|
-
}}
|
241
|
+
markdownProps={markdownProps}
|
192
242
|
message={message}
|
193
|
-
messageExtra={
|
194
|
-
onAvatarClick={onAvatarsClick
|
195
|
-
onChange={
|
196
|
-
onDoubleClick={
|
197
|
-
|
198
|
-
if (item.role && ['assistant', 'user'].includes(item.role) && e.altKey) {
|
199
|
-
toggleMessageEditing(id, true);
|
200
|
-
}
|
201
|
-
}}
|
202
|
-
onEditingChange={(edit) => {
|
203
|
-
toggleMessageEditing(id, edit);
|
204
|
-
}}
|
243
|
+
messageExtra={messageExtra}
|
244
|
+
onAvatarClick={onAvatarsClick}
|
245
|
+
onChange={onChange}
|
246
|
+
onDoubleClick={onDoubleClick}
|
247
|
+
onEditingChange={onEditingChange}
|
205
248
|
placement={type === 'chat' ? (item.role === 'user' ? 'right' : 'left') : 'left'}
|
206
249
|
primary={item.role === 'user'}
|
207
|
-
renderMessage={
|
208
|
-
|
209
|
-
)}
|
210
|
-
text={{
|
211
|
-
cancel: t('cancel'),
|
212
|
-
confirm: t('ok'),
|
213
|
-
edit: t('edit'),
|
214
|
-
}}
|
250
|
+
renderMessage={renderMessage}
|
251
|
+
text={text}
|
215
252
|
time={item.updatedAt || item.createdAt}
|
216
253
|
type={type === 'chat' ? 'block' : 'pure'}
|
217
254
|
/>
|
@@ -220,4 +257,6 @@ const Item = memo<ChatListItemProps>(({ index, id }) => {
|
|
220
257
|
);
|
221
258
|
});
|
222
259
|
|
260
|
+
Item.displayName = 'ChatItem';
|
261
|
+
|
223
262
|
export default Item;
|