@lobehub/chat 1.123.3 → 1.124.0
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 +50 -0
- package/changelog/v1.json +18 -0
- package/locales/ar/chat.json +6 -2
- package/locales/ar/editor.json +47 -0
- package/locales/bg-BG/chat.json +6 -2
- package/locales/bg-BG/editor.json +47 -0
- package/locales/de-DE/chat.json +6 -2
- package/locales/de-DE/editor.json +47 -0
- package/locales/en-US/chat.json +6 -2
- package/locales/en-US/editor.json +47 -0
- package/locales/es-ES/chat.json +6 -2
- package/locales/es-ES/editor.json +47 -0
- package/locales/es-ES/models.json +3 -1
- package/locales/fa-IR/chat.json +6 -2
- package/locales/fa-IR/editor.json +47 -0
- package/locales/fr-FR/chat.json +6 -2
- package/locales/fr-FR/editor.json +47 -0
- package/locales/it-IT/chat.json +6 -2
- package/locales/it-IT/editor.json +47 -0
- package/locales/ja-JP/chat.json +6 -2
- package/locales/ja-JP/editor.json +47 -0
- package/locales/ko-KR/chat.json +6 -2
- package/locales/ko-KR/editor.json +47 -0
- package/locales/ko-KR/models.json +3 -1
- package/locales/nl-NL/chat.json +6 -2
- package/locales/nl-NL/editor.json +47 -0
- package/locales/nl-NL/models.json +3 -1
- package/locales/pl-PL/chat.json +6 -2
- package/locales/pl-PL/editor.json +47 -0
- package/locales/pt-BR/chat.json +6 -2
- package/locales/pt-BR/editor.json +47 -0
- package/locales/ru-RU/chat.json +6 -2
- package/locales/ru-RU/editor.json +47 -0
- package/locales/tr-TR/chat.json +6 -2
- package/locales/tr-TR/editor.json +47 -0
- package/locales/vi-VN/chat.json +6 -2
- package/locales/vi-VN/editor.json +47 -0
- package/locales/zh-CN/chat.json +6 -2
- package/locales/zh-CN/editor.json +47 -0
- package/locales/zh-TW/chat.json +6 -2
- package/locales/zh-TW/editor.json +47 -0
- package/locales/zh-TW/models.json +3 -1
- package/next.config.ts +4 -0
- package/package.json +4 -2
- package/packages/const/src/layoutTokens.ts +1 -0
- package/packages/types/src/index.ts +1 -0
- package/packages/utils/src/index.ts +1 -0
- package/src/app/(backend)/webapi/chat/[provider]/route.ts +1 -1
- package/src/app/(backend)/webapi/chat/vertexai/route.ts +1 -0
- package/src/app/[variants]/(main)/chat/(workspace)/@conversation/features/ChatInput/Desktop/{Footer/MessageFromUrl.tsx → MessageFromUrl.tsx} +3 -2
- package/src/app/[variants]/(main)/chat/(workspace)/@conversation/features/ChatInput/Desktop/index.tsx +129 -28
- package/src/app/[variants]/(main)/chat/(workspace)/@conversation/features/ChatInput/Mobile/index.tsx +44 -66
- package/src/app/[variants]/(main)/chat/(workspace)/@conversation/features/ChatInput/useSend.ts +141 -0
- package/src/app/[variants]/(main)/chat/(workspace)/@conversation/features/ChatList/Content.tsx +7 -1
- package/src/app/[variants]/(main)/chat/(workspace)/@conversation/features/ChatList/WelcomeChatItem/InboxWelcome/QuestionSuggest.tsx +3 -2
- package/src/app/[variants]/(main)/chat/(workspace)/@conversation/features/ChatList/WelcomeChatItem/OpeningQuestions.tsx +3 -2
- package/src/app/[variants]/(main)/chat/(workspace)/_layout/Desktop/ChatHeader/HeaderAction.tsx +18 -2
- package/src/features/ChatInput/ActionBar/STT/common.tsx +41 -47
- package/src/features/ChatInput/{Topic → ActionBar/SaveTopic}/index.tsx +15 -4
- package/src/features/ChatInput/ActionBar/Typo/index.tsx +22 -0
- package/src/features/ChatInput/ActionBar/components/Action.tsx +4 -0
- package/src/features/ChatInput/ActionBar/config.ts +7 -1
- package/src/features/ChatInput/ActionBar/index.tsx +40 -51
- package/src/features/ChatInput/ChatInputProvider.tsx +54 -0
- package/src/features/ChatInput/Desktop/FilePreview/FileItem/index.tsx +20 -11
- package/src/features/ChatInput/Desktop/FilePreview/FileList.tsx +16 -15
- package/src/features/ChatInput/Desktop/index.tsx +81 -68
- package/src/features/ChatInput/InputEditor/index.tsx +134 -0
- package/src/{app/[variants]/(main)/chat/(workspace)/@conversation/features/ChatInput/Mobile/Files → features/ChatInput/Mobile/FilePreview}/FileItem/File.tsx +1 -2
- package/src/features/ChatInput/Mobile/FilePreview/index.tsx +44 -0
- package/src/features/ChatInput/Mobile/index.tsx +72 -0
- package/src/features/ChatInput/SendArea/ExpandButton.tsx +30 -0
- package/src/features/ChatInput/SendArea/SendButton.tsx +29 -0
- package/src/features/ChatInput/SendArea/ShortcutHint.tsx +52 -0
- package/src/features/ChatInput/SendArea/index.tsx +36 -0
- package/src/features/ChatInput/StoreUpdater.tsx +41 -0
- package/src/features/ChatInput/TypoBar/index.tsx +139 -0
- package/src/features/ChatInput/hooks/useChatInputEditor.ts +36 -0
- package/src/features/ChatInput/index.ts +7 -0
- package/src/features/ChatInput/store/action.ts +75 -0
- package/src/features/ChatInput/store/index.ts +23 -0
- package/src/features/ChatInput/store/initialState.ts +54 -0
- package/src/features/ChatInput/store/selectors.ts +5 -0
- package/src/features/Conversation/components/BackBottom/style.ts +1 -1
- package/src/features/Conversation/components/SkeletonList.tsx +10 -3
- package/src/features/Conversation/components/VirtualizedList/index.tsx +53 -44
- package/src/features/Conversation/components/WideScreenContainer/index.tsx +43 -0
- package/src/features/Portal/Thread/Chat/ChatInput/index.tsx +49 -42
- package/src/features/Portal/Thread/Chat/ChatInput/useSend.ts +48 -22
- package/src/features/Portal/Thread/Chat/index.tsx +2 -2
- package/src/features/Portal/Thread/Header/index.tsx +1 -1
- package/src/hooks/useHotkeys/chatScope.ts +5 -3
- package/src/layout/GlobalProvider/Editor.tsx +27 -0
- package/src/layout/GlobalProvider/Locale.tsx +3 -23
- package/src/libs/trpc/client/lambda.ts +76 -63
- package/src/locales/default/chat.ts +7 -2
- package/src/locales/default/editor.ts +47 -0
- package/src/locales/default/index.ts +2 -0
- package/src/services/aiChat.ts +8 -2
- package/src/store/chat/slices/aiChat/actions/__tests__/generateAIChatV2.test.ts +42 -33
- package/src/store/chat/slices/aiChat/actions/generateAIChatV2.ts +174 -35
- package/src/store/chat/slices/aiChat/initialState.ts +19 -0
- package/src/store/chat/slices/aiChat/selectors.ts +18 -0
- package/src/store/global/action.test.ts +6 -5
- package/src/store/global/actions/__tests__/general.test.ts +6 -6
- package/src/store/global/actions/workspacePane.ts +6 -0
- package/src/store/global/initialState.ts +2 -4
- package/src/store/global/selectors/systemStatus.test.ts +1 -2
- package/src/store/global/selectors/systemStatus.ts +2 -5
- package/src/app/(backend)/webapi/chat/anthropic/route.test.ts +0 -30
- package/src/app/(backend)/webapi/chat/anthropic/route.ts +0 -21
- package/src/app/(backend)/webapi/chat/google/route.test.ts +0 -35
- package/src/app/(backend)/webapi/chat/google/route.ts +0 -25
- package/src/app/(backend)/webapi/chat/groq/route.test.ts +0 -29
- package/src/app/(backend)/webapi/chat/groq/route.ts +0 -21
- package/src/app/(backend)/webapi/chat/openai/route.test.ts +0 -30
- package/src/app/(backend)/webapi/chat/openai/route.ts +0 -26
- package/src/app/[variants]/(main)/chat/(workspace)/@conversation/features/ChatInput/Desktop/Footer/SendMore.tsx +0 -104
- package/src/app/[variants]/(main)/chat/(workspace)/@conversation/features/ChatInput/Desktop/Footer/ShortcutHint.tsx +0 -40
- package/src/app/[variants]/(main)/chat/(workspace)/@conversation/features/ChatInput/Desktop/Footer/index.tsx +0 -125
- package/src/app/[variants]/(main)/chat/(workspace)/@conversation/features/ChatInput/Desktop/TextArea.test.tsx +0 -332
- package/src/app/[variants]/(main)/chat/(workspace)/@conversation/features/ChatInput/Desktop/TextArea.tsx +0 -29
- package/src/app/[variants]/(main)/chat/(workspace)/@conversation/features/ChatInput/Mobile/Files/index.tsx +0 -33
- package/src/app/[variants]/(main)/chat/(workspace)/@conversation/features/ChatInput/Mobile/InputArea/Container.tsx +0 -41
- package/src/app/[variants]/(main)/chat/(workspace)/@conversation/features/ChatInput/Mobile/InputArea/index.tsx +0 -156
- package/src/app/[variants]/(main)/chat/(workspace)/@conversation/features/ChatInput/Mobile/Send.tsx +0 -33
- package/src/features/ChatInput/Desktop/Header/index.tsx +0 -30
- package/src/features/ChatInput/Desktop/InputArea/index.tsx +0 -143
- package/src/features/ChatInput/Desktop/__tests__/useAutoFocus.test.ts +0 -45
- package/src/features/ChatInput/Desktop/useAutoFocus.ts +0 -13
- package/src/features/ChatInput/useSend.ts +0 -102
- package/src/features/Portal/Thread/Chat/ChatInput/Footer.tsx +0 -90
- package/src/features/Portal/Thread/Chat/ChatInput/TextArea.tsx +0 -30
- package/src/libs/trpc/client/types.ts +0 -18
- /package/src/{app/[variants]/(main)/chat/(workspace)/@conversation/features/ChatInput/Mobile/Files → features/ChatInput/Mobile/FilePreview}/FileItem/Image.tsx +0 -0
- /package/src/{app/[variants]/(main)/chat/(workspace)/@conversation/features/ChatInput/Mobile/Files → features/ChatInput/Mobile/FilePreview}/FileItem/index.tsx +0 -0
- /package/src/{app/[variants]/(main)/chat/(workspace)/@conversation/features/ChatInput/Mobile/Files → features/ChatInput/Mobile/FilePreview}/FileItem/style.ts +0 -0
@@ -1,143 +0,0 @@
|
|
1
|
-
import { TextArea } from '@lobehub/ui';
|
2
|
-
import { createStyles } from 'antd-style';
|
3
|
-
import { TextAreaRef } from 'antd/es/input/TextArea';
|
4
|
-
import { RefObject, memo, useEffect, useRef } from 'react';
|
5
|
-
import { useHotkeysContext } from 'react-hotkeys-hook';
|
6
|
-
import { useTranslation } from 'react-i18next';
|
7
|
-
|
8
|
-
import { isDesktop } from '@/const/version';
|
9
|
-
import { useUserStore } from '@/store/user';
|
10
|
-
import { preferenceSelectors } from '@/store/user/selectors';
|
11
|
-
import { HotkeyEnum } from '@/types/hotkey';
|
12
|
-
import { isCommandPressed } from '@/utils/keyboard';
|
13
|
-
|
14
|
-
import { useAutoFocus } from '../useAutoFocus';
|
15
|
-
|
16
|
-
const useStyles = createStyles(({ css }) => {
|
17
|
-
return {
|
18
|
-
textarea: css`
|
19
|
-
resize: none !important;
|
20
|
-
|
21
|
-
height: 100% !important;
|
22
|
-
padding-block: 0;
|
23
|
-
padding-inline: 16px;
|
24
|
-
|
25
|
-
line-height: 1.5;
|
26
|
-
|
27
|
-
box-shadow: none !important;
|
28
|
-
`,
|
29
|
-
textareaContainer: css`
|
30
|
-
position: relative;
|
31
|
-
flex: 1;
|
32
|
-
`,
|
33
|
-
};
|
34
|
-
});
|
35
|
-
|
36
|
-
interface InputAreaProps {
|
37
|
-
loading?: boolean;
|
38
|
-
onChange: (string: string) => void;
|
39
|
-
onSend: () => void;
|
40
|
-
value: string;
|
41
|
-
}
|
42
|
-
|
43
|
-
const InputArea = memo<InputAreaProps>(({ onSend, value, loading, onChange }) => {
|
44
|
-
const { enableScope, disableScope } = useHotkeysContext();
|
45
|
-
const { t } = useTranslation('chat');
|
46
|
-
const { styles } = useStyles();
|
47
|
-
|
48
|
-
const ref = useRef<TextAreaRef>(null);
|
49
|
-
const isChineseInput = useRef(false);
|
50
|
-
|
51
|
-
const useCmdEnterToSend = useUserStore(preferenceSelectors.useCmdEnterToSend);
|
52
|
-
|
53
|
-
useAutoFocus(ref as RefObject<TextAreaRef>);
|
54
|
-
|
55
|
-
const hasValue = !!value;
|
56
|
-
|
57
|
-
useEffect(() => {
|
58
|
-
const fn = (e: BeforeUnloadEvent) => {
|
59
|
-
if (hasValue) {
|
60
|
-
// set returnValue to trigger alert modal
|
61
|
-
// Note: No matter what value is set, the browser will display the standard text
|
62
|
-
e.returnValue = '你有正在输入中的内容,确定要离开吗?';
|
63
|
-
}
|
64
|
-
};
|
65
|
-
|
66
|
-
window.addEventListener('beforeunload', fn);
|
67
|
-
return () => {
|
68
|
-
window.removeEventListener('beforeunload', fn);
|
69
|
-
};
|
70
|
-
}, [hasValue]);
|
71
|
-
|
72
|
-
return (
|
73
|
-
<div className={styles.textareaContainer}>
|
74
|
-
<TextArea
|
75
|
-
autoFocus
|
76
|
-
className={styles.textarea}
|
77
|
-
onBlur={(e) => {
|
78
|
-
onChange?.(e.target.value);
|
79
|
-
disableScope(HotkeyEnum.AddUserMessage);
|
80
|
-
}}
|
81
|
-
onChange={(e) => {
|
82
|
-
onChange?.(e.target.value);
|
83
|
-
}}
|
84
|
-
onCompositionEnd={() => {
|
85
|
-
isChineseInput.current = false;
|
86
|
-
}}
|
87
|
-
onCompositionStart={() => {
|
88
|
-
isChineseInput.current = true;
|
89
|
-
}}
|
90
|
-
onContextMenu={async (e) => {
|
91
|
-
if (isDesktop) {
|
92
|
-
e.preventDefault();
|
93
|
-
const textArea = ref.current?.resizableTextArea?.textArea;
|
94
|
-
const hasSelection = textArea && textArea.selectionStart !== textArea.selectionEnd;
|
95
|
-
const { electronSystemService } = await import('@/services/electron/system');
|
96
|
-
|
97
|
-
electronSystemService.showContextMenu('editor', {
|
98
|
-
hasSelection: !!hasSelection,
|
99
|
-
value: value,
|
100
|
-
});
|
101
|
-
}
|
102
|
-
}}
|
103
|
-
onFocus={() => {
|
104
|
-
enableScope(HotkeyEnum.AddUserMessage);
|
105
|
-
}}
|
106
|
-
onPressEnter={(e) => {
|
107
|
-
if (loading || e.altKey || e.shiftKey || isChineseInput.current) return;
|
108
|
-
|
109
|
-
// eslint-disable-next-line unicorn/consistent-function-scoping
|
110
|
-
const send = () => {
|
111
|
-
// avoid inserting newline when sending message.
|
112
|
-
// refs: https://github.com/lobehub/lobe-chat/pull/989
|
113
|
-
e.preventDefault();
|
114
|
-
|
115
|
-
onSend();
|
116
|
-
};
|
117
|
-
const commandKey = isCommandPressed(e);
|
118
|
-
|
119
|
-
// when user like cmd + enter to send message
|
120
|
-
if (useCmdEnterToSend) {
|
121
|
-
if (commandKey) send();
|
122
|
-
} else {
|
123
|
-
// cmd + enter to wrap
|
124
|
-
if (commandKey) {
|
125
|
-
onChange?.((e.target as any).value + '\n');
|
126
|
-
return;
|
127
|
-
}
|
128
|
-
|
129
|
-
send();
|
130
|
-
}
|
131
|
-
}}
|
132
|
-
placeholder={t('sendPlaceholder')}
|
133
|
-
ref={ref}
|
134
|
-
value={value}
|
135
|
-
variant={'borderless'}
|
136
|
-
/>
|
137
|
-
</div>
|
138
|
-
);
|
139
|
-
});
|
140
|
-
|
141
|
-
InputArea.displayName = 'DesktopInputArea';
|
142
|
-
|
143
|
-
export default InputArea;
|
@@ -1,45 +0,0 @@
|
|
1
|
-
import { act, renderHook } from '@testing-library/react';
|
2
|
-
import { describe, expect, it, vi } from 'vitest';
|
3
|
-
|
4
|
-
import { useChatStore } from '@/store/chat';
|
5
|
-
import { chatSelectors } from '@/store/chat/selectors';
|
6
|
-
|
7
|
-
import { useAutoFocus } from '../useAutoFocus';
|
8
|
-
|
9
|
-
vi.mock('zustand/traditional');
|
10
|
-
|
11
|
-
describe('useAutoFocus', () => {
|
12
|
-
it('should focus the input when chatKey changes', () => {
|
13
|
-
const focusMock = vi.fn();
|
14
|
-
const inputRef = { current: { focus: focusMock } };
|
15
|
-
|
16
|
-
act(() => {
|
17
|
-
useChatStore.setState({ activeId: '1', activeTopicId: '2' });
|
18
|
-
});
|
19
|
-
|
20
|
-
renderHook(() => useAutoFocus(inputRef as any));
|
21
|
-
|
22
|
-
expect(focusMock).toHaveBeenCalledTimes(1);
|
23
|
-
|
24
|
-
act(() => {
|
25
|
-
useChatStore.setState({ activeId: '1', activeTopicId: '3' });
|
26
|
-
});
|
27
|
-
|
28
|
-
renderHook(() => useAutoFocus(inputRef as any));
|
29
|
-
|
30
|
-
// I don't know why its 3, but is large than 2 is fine
|
31
|
-
expect(focusMock).toHaveBeenCalledTimes(3);
|
32
|
-
});
|
33
|
-
|
34
|
-
it('should not focus the input if inputRef is not available', () => {
|
35
|
-
const inputRef = { current: null };
|
36
|
-
|
37
|
-
act(() => {
|
38
|
-
useChatStore.setState({ activeId: '1', activeTopicId: '2' });
|
39
|
-
});
|
40
|
-
|
41
|
-
renderHook(() => useAutoFocus(inputRef as any));
|
42
|
-
|
43
|
-
expect(inputRef.current).toBeNull();
|
44
|
-
});
|
45
|
-
});
|
@@ -1,13 +0,0 @@
|
|
1
|
-
import { TextAreaRef } from 'antd/es/input/TextArea';
|
2
|
-
import { RefObject, useEffect } from 'react';
|
3
|
-
|
4
|
-
import { useChatStore } from '@/store/chat';
|
5
|
-
import { chatSelectors } from '@/store/chat/selectors';
|
6
|
-
|
7
|
-
export const useAutoFocus = (inputRef: RefObject<TextAreaRef>) => {
|
8
|
-
const chatKey = useChatStore(chatSelectors.currentChatKey);
|
9
|
-
|
10
|
-
useEffect(() => {
|
11
|
-
inputRef.current?.focus();
|
12
|
-
}, [chatKey]);
|
13
|
-
};
|
@@ -1,102 +0,0 @@
|
|
1
|
-
import { useAnalytics } from '@lobehub/analytics/react';
|
2
|
-
import { useCallback, useMemo } from 'react';
|
3
|
-
|
4
|
-
import { useGeminiChineseWarning } from '@/hooks/useGeminiChineseWarning';
|
5
|
-
import { getAgentStoreState } from '@/store/agent';
|
6
|
-
import { agentSelectors } from '@/store/agent/selectors';
|
7
|
-
import { useChatStore } from '@/store/chat';
|
8
|
-
import { chatSelectors, topicSelectors } from '@/store/chat/selectors';
|
9
|
-
import { fileChatSelectors, useFileStore } from '@/store/file';
|
10
|
-
import { getUserStoreState } from '@/store/user';
|
11
|
-
import { SendMessageParams } from '@/types/message';
|
12
|
-
|
13
|
-
export type UseSendMessageParams = Pick<
|
14
|
-
SendMessageParams,
|
15
|
-
'onlyAddUserMessage' | 'isWelcomeQuestion'
|
16
|
-
>;
|
17
|
-
|
18
|
-
export const useSendMessage = () => {
|
19
|
-
const [sendMessage, updateInputMessage] = useChatStore((s) => [
|
20
|
-
s.sendMessage,
|
21
|
-
s.updateInputMessage,
|
22
|
-
]);
|
23
|
-
const { analytics } = useAnalytics();
|
24
|
-
const checkGeminiChineseWarning = useGeminiChineseWarning();
|
25
|
-
|
26
|
-
const clearChatUploadFileList = useFileStore((s) => s.clearChatUploadFileList);
|
27
|
-
|
28
|
-
const isUploadingFiles = useFileStore(fileChatSelectors.isUploadingFiles);
|
29
|
-
const isSendButtonDisabledByMessage = useChatStore(chatSelectors.isSendButtonDisabledByMessage);
|
30
|
-
|
31
|
-
const canSend = !isUploadingFiles && !isSendButtonDisabledByMessage;
|
32
|
-
|
33
|
-
const send = useCallback(async (params: UseSendMessageParams = {}) => {
|
34
|
-
const store = useChatStore.getState();
|
35
|
-
if (chatSelectors.isAIGenerating(store)) return;
|
36
|
-
|
37
|
-
// if uploading file or send button is disabled by message, then we should not send the message
|
38
|
-
const isUploadingFiles = fileChatSelectors.isUploadingFiles(useFileStore.getState());
|
39
|
-
const isSendButtonDisabledByMessage = chatSelectors.isSendButtonDisabledByMessage(
|
40
|
-
useChatStore.getState(),
|
41
|
-
);
|
42
|
-
|
43
|
-
const canSend = !isUploadingFiles && !isSendButtonDisabledByMessage;
|
44
|
-
if (!canSend) return;
|
45
|
-
|
46
|
-
const fileList = fileChatSelectors.chatUploadFileList(useFileStore.getState());
|
47
|
-
// if there is no message and no image, then we should not send the message
|
48
|
-
if (!store.inputMessage && fileList.length === 0) return;
|
49
|
-
|
50
|
-
// Check for Chinese text warning with Gemini model
|
51
|
-
const agentStore = getAgentStoreState();
|
52
|
-
const currentModel = agentSelectors.currentAgentModel(agentStore);
|
53
|
-
const shouldContinue = await checkGeminiChineseWarning({
|
54
|
-
model: currentModel,
|
55
|
-
prompt: store.inputMessage,
|
56
|
-
scenario: 'chat',
|
57
|
-
});
|
58
|
-
|
59
|
-
if (!shouldContinue) return;
|
60
|
-
|
61
|
-
sendMessage({
|
62
|
-
files: fileList,
|
63
|
-
message: store.inputMessage,
|
64
|
-
...params,
|
65
|
-
});
|
66
|
-
|
67
|
-
updateInputMessage('');
|
68
|
-
clearChatUploadFileList();
|
69
|
-
|
70
|
-
// 获取分析数据
|
71
|
-
const userStore = getUserStoreState();
|
72
|
-
|
73
|
-
// 直接使用现有数据结构判断消息类型
|
74
|
-
const hasImages = fileList.some((file) => file.file?.type?.startsWith('image'));
|
75
|
-
const messageType = fileList.length === 0 ? 'text' : hasImages ? 'image' : 'file';
|
76
|
-
|
77
|
-
analytics?.track({
|
78
|
-
name: 'send_message',
|
79
|
-
properties: {
|
80
|
-
chat_id: store.activeId || 'unknown',
|
81
|
-
current_topic: topicSelectors.currentActiveTopic(store)?.title || null,
|
82
|
-
has_attachments: fileList.length > 0,
|
83
|
-
history_message_count: chatSelectors.activeBaseChats(store).length,
|
84
|
-
message: store.inputMessage,
|
85
|
-
message_length: store.inputMessage.length,
|
86
|
-
message_type: messageType,
|
87
|
-
selected_model: agentSelectors.currentAgentModel(agentStore),
|
88
|
-
session_id: store.activeId || 'inbox', // 当前活跃的会话ID
|
89
|
-
user_id: userStore.user?.id || 'anonymous',
|
90
|
-
},
|
91
|
-
});
|
92
|
-
// const hasSystemRole = agentSelectors.hasSystemRole(useAgentStore.getState());
|
93
|
-
// const agentSetting = useAgentStore.getState().agentSettingInstance;
|
94
|
-
|
95
|
-
// // if there is a system role, then we need to use agent setting instance to autocomplete agent meta
|
96
|
-
// if (hasSystemRole && !!agentSetting) {
|
97
|
-
// agentSetting.autocompleteAllMeta();
|
98
|
-
// }
|
99
|
-
}, []);
|
100
|
-
|
101
|
-
return useMemo(() => ({ canSend, send }), [canSend]);
|
102
|
-
};
|
@@ -1,90 +0,0 @@
|
|
1
|
-
import { Button } from '@lobehub/ui';
|
2
|
-
import { createStyles } from 'antd-style';
|
3
|
-
import { rgba } from 'polished';
|
4
|
-
import { memo } from 'react';
|
5
|
-
import { useTranslation } from 'react-i18next';
|
6
|
-
import { Flexbox } from 'react-layout-kit';
|
7
|
-
|
8
|
-
import StopLoadingIcon from '@/components/StopLoading';
|
9
|
-
import { useChatStore } from '@/store/chat';
|
10
|
-
import { threadSelectors } from '@/store/chat/selectors';
|
11
|
-
|
12
|
-
import { useSendThreadMessage } from './useSend';
|
13
|
-
|
14
|
-
const useStyles = createStyles(({ css, prefixCls, token }) => {
|
15
|
-
return {
|
16
|
-
loadingButton: css`
|
17
|
-
display: flex;
|
18
|
-
align-items: center;
|
19
|
-
`,
|
20
|
-
overrideAntdIcon: css`
|
21
|
-
.${prefixCls}-btn.${prefixCls}-btn-icon-only {
|
22
|
-
display: flex;
|
23
|
-
align-items: center;
|
24
|
-
justify-content: center;
|
25
|
-
}
|
26
|
-
|
27
|
-
.${prefixCls}-btn.${prefixCls}-dropdown-trigger {
|
28
|
-
&::before {
|
29
|
-
background-color: ${rgba(token.colorBgLayout, 0.1)} !important;
|
30
|
-
}
|
31
|
-
}
|
32
|
-
`,
|
33
|
-
};
|
34
|
-
});
|
35
|
-
|
36
|
-
interface FooterProps {
|
37
|
-
onExpandChange: (expand: boolean) => void;
|
38
|
-
}
|
39
|
-
|
40
|
-
const Footer = memo<FooterProps>(({ onExpandChange }) => {
|
41
|
-
const { t } = useTranslation('chat');
|
42
|
-
|
43
|
-
const { styles } = useStyles();
|
44
|
-
|
45
|
-
const [isAIGenerating, stopGenerateMessage] = useChatStore((s) => [
|
46
|
-
threadSelectors.isThreadAIGenerating(s),
|
47
|
-
s.stopGenerateMessage,
|
48
|
-
]);
|
49
|
-
|
50
|
-
const { send: sendMessage, canSend } = useSendThreadMessage();
|
51
|
-
|
52
|
-
return (
|
53
|
-
<Flexbox
|
54
|
-
align={'end'}
|
55
|
-
className={styles.overrideAntdIcon}
|
56
|
-
distribution={'space-between'}
|
57
|
-
flex={'none'}
|
58
|
-
gap={8}
|
59
|
-
horizontal
|
60
|
-
paddingInline={16}
|
61
|
-
>
|
62
|
-
<div />
|
63
|
-
{isAIGenerating ? (
|
64
|
-
<Button
|
65
|
-
className={styles.loadingButton}
|
66
|
-
icon={<StopLoadingIcon />}
|
67
|
-
onClick={stopGenerateMessage}
|
68
|
-
>
|
69
|
-
{t('input.stop')}
|
70
|
-
</Button>
|
71
|
-
) : (
|
72
|
-
<Button
|
73
|
-
disabled={!canSend}
|
74
|
-
loading={!canSend}
|
75
|
-
onClick={() => {
|
76
|
-
sendMessage();
|
77
|
-
onExpandChange?.(false);
|
78
|
-
}}
|
79
|
-
type={'primary'}
|
80
|
-
>
|
81
|
-
{t('input.send')}
|
82
|
-
</Button>
|
83
|
-
)}
|
84
|
-
</Flexbox>
|
85
|
-
);
|
86
|
-
});
|
87
|
-
|
88
|
-
Footer.displayName = 'Footer';
|
89
|
-
|
90
|
-
export default Footer;
|
@@ -1,30 +0,0 @@
|
|
1
|
-
import { memo } from 'react';
|
2
|
-
|
3
|
-
import InputArea from '@/features/ChatInput/Desktop/InputArea';
|
4
|
-
import { useChatStore } from '@/store/chat';
|
5
|
-
import { chatSelectors } from '@/store/chat/selectors';
|
6
|
-
|
7
|
-
import { useSendThreadMessage } from './useSend';
|
8
|
-
|
9
|
-
const TextArea = memo<{ onSend?: () => void }>(({ onSend }) => {
|
10
|
-
const [loading, value, updateInputMessage] = useChatStore((s) => [
|
11
|
-
chatSelectors.isAIGenerating(s),
|
12
|
-
s.threadInputMessage,
|
13
|
-
s.updateThreadInputMessage,
|
14
|
-
]);
|
15
|
-
const { send: sendMessage } = useSendThreadMessage();
|
16
|
-
|
17
|
-
return (
|
18
|
-
<InputArea
|
19
|
-
loading={loading}
|
20
|
-
onChange={updateInputMessage}
|
21
|
-
onSend={() => {
|
22
|
-
sendMessage();
|
23
|
-
onSend?.();
|
24
|
-
}}
|
25
|
-
value={value}
|
26
|
-
/>
|
27
|
-
);
|
28
|
-
});
|
29
|
-
|
30
|
-
export default TextArea;
|
@@ -1,18 +0,0 @@
|
|
1
|
-
export type ErrorResponse = ErrorItem[];
|
2
|
-
|
3
|
-
export interface ErrorItem {
|
4
|
-
error: {
|
5
|
-
json: {
|
6
|
-
code: number;
|
7
|
-
data: Data;
|
8
|
-
message: string;
|
9
|
-
};
|
10
|
-
};
|
11
|
-
}
|
12
|
-
|
13
|
-
export interface Data {
|
14
|
-
code: string;
|
15
|
-
httpStatus: number;
|
16
|
-
path: string;
|
17
|
-
stack: string;
|
18
|
-
}
|
File without changes
|
File without changes
|