@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.
Files changed (137) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/changelog/v1.json +18 -0
  3. package/locales/ar/chat.json +6 -2
  4. package/locales/ar/editor.json +47 -0
  5. package/locales/bg-BG/chat.json +6 -2
  6. package/locales/bg-BG/editor.json +47 -0
  7. package/locales/de-DE/chat.json +6 -2
  8. package/locales/de-DE/editor.json +47 -0
  9. package/locales/en-US/chat.json +6 -2
  10. package/locales/en-US/editor.json +47 -0
  11. package/locales/es-ES/chat.json +6 -2
  12. package/locales/es-ES/editor.json +47 -0
  13. package/locales/es-ES/models.json +3 -1
  14. package/locales/fa-IR/chat.json +6 -2
  15. package/locales/fa-IR/editor.json +47 -0
  16. package/locales/fr-FR/chat.json +6 -2
  17. package/locales/fr-FR/editor.json +47 -0
  18. package/locales/it-IT/chat.json +6 -2
  19. package/locales/it-IT/editor.json +47 -0
  20. package/locales/ja-JP/chat.json +6 -2
  21. package/locales/ja-JP/editor.json +47 -0
  22. package/locales/ko-KR/chat.json +6 -2
  23. package/locales/ko-KR/editor.json +47 -0
  24. package/locales/ko-KR/models.json +3 -1
  25. package/locales/nl-NL/chat.json +6 -2
  26. package/locales/nl-NL/editor.json +47 -0
  27. package/locales/nl-NL/models.json +3 -1
  28. package/locales/pl-PL/chat.json +6 -2
  29. package/locales/pl-PL/editor.json +47 -0
  30. package/locales/pt-BR/chat.json +6 -2
  31. package/locales/pt-BR/editor.json +47 -0
  32. package/locales/ru-RU/chat.json +6 -2
  33. package/locales/ru-RU/editor.json +47 -0
  34. package/locales/tr-TR/chat.json +6 -2
  35. package/locales/tr-TR/editor.json +47 -0
  36. package/locales/vi-VN/chat.json +6 -2
  37. package/locales/vi-VN/editor.json +47 -0
  38. package/locales/zh-CN/chat.json +6 -2
  39. package/locales/zh-CN/editor.json +47 -0
  40. package/locales/zh-TW/chat.json +6 -2
  41. package/locales/zh-TW/editor.json +47 -0
  42. package/locales/zh-TW/models.json +3 -1
  43. package/next.config.ts +4 -0
  44. package/package.json +4 -2
  45. package/packages/const/src/layoutTokens.ts +1 -0
  46. package/packages/types/src/index.ts +1 -0
  47. package/packages/utils/src/index.ts +1 -0
  48. package/src/app/(backend)/webapi/chat/[provider]/route.ts +1 -1
  49. package/src/app/(backend)/webapi/chat/vertexai/route.ts +1 -0
  50. package/src/app/[variants]/(main)/chat/(workspace)/@conversation/features/ChatInput/Desktop/{Footer/MessageFromUrl.tsx → MessageFromUrl.tsx} +3 -2
  51. package/src/app/[variants]/(main)/chat/(workspace)/@conversation/features/ChatInput/Desktop/index.tsx +129 -28
  52. package/src/app/[variants]/(main)/chat/(workspace)/@conversation/features/ChatInput/Mobile/index.tsx +44 -66
  53. package/src/app/[variants]/(main)/chat/(workspace)/@conversation/features/ChatInput/useSend.ts +141 -0
  54. package/src/app/[variants]/(main)/chat/(workspace)/@conversation/features/ChatList/Content.tsx +7 -1
  55. package/src/app/[variants]/(main)/chat/(workspace)/@conversation/features/ChatList/WelcomeChatItem/InboxWelcome/QuestionSuggest.tsx +3 -2
  56. package/src/app/[variants]/(main)/chat/(workspace)/@conversation/features/ChatList/WelcomeChatItem/OpeningQuestions.tsx +3 -2
  57. package/src/app/[variants]/(main)/chat/(workspace)/_layout/Desktop/ChatHeader/HeaderAction.tsx +18 -2
  58. package/src/features/ChatInput/ActionBar/STT/common.tsx +41 -47
  59. package/src/features/ChatInput/{Topic → ActionBar/SaveTopic}/index.tsx +15 -4
  60. package/src/features/ChatInput/ActionBar/Typo/index.tsx +22 -0
  61. package/src/features/ChatInput/ActionBar/components/Action.tsx +4 -0
  62. package/src/features/ChatInput/ActionBar/config.ts +7 -1
  63. package/src/features/ChatInput/ActionBar/index.tsx +40 -51
  64. package/src/features/ChatInput/ChatInputProvider.tsx +54 -0
  65. package/src/features/ChatInput/Desktop/FilePreview/FileItem/index.tsx +20 -11
  66. package/src/features/ChatInput/Desktop/FilePreview/FileList.tsx +16 -15
  67. package/src/features/ChatInput/Desktop/index.tsx +81 -68
  68. package/src/features/ChatInput/InputEditor/index.tsx +134 -0
  69. package/src/{app/[variants]/(main)/chat/(workspace)/@conversation/features/ChatInput/Mobile/Files → features/ChatInput/Mobile/FilePreview}/FileItem/File.tsx +1 -2
  70. package/src/features/ChatInput/Mobile/FilePreview/index.tsx +44 -0
  71. package/src/features/ChatInput/Mobile/index.tsx +72 -0
  72. package/src/features/ChatInput/SendArea/ExpandButton.tsx +30 -0
  73. package/src/features/ChatInput/SendArea/SendButton.tsx +29 -0
  74. package/src/features/ChatInput/SendArea/ShortcutHint.tsx +52 -0
  75. package/src/features/ChatInput/SendArea/index.tsx +36 -0
  76. package/src/features/ChatInput/StoreUpdater.tsx +41 -0
  77. package/src/features/ChatInput/TypoBar/index.tsx +139 -0
  78. package/src/features/ChatInput/hooks/useChatInputEditor.ts +36 -0
  79. package/src/features/ChatInput/index.ts +7 -0
  80. package/src/features/ChatInput/store/action.ts +75 -0
  81. package/src/features/ChatInput/store/index.ts +23 -0
  82. package/src/features/ChatInput/store/initialState.ts +54 -0
  83. package/src/features/ChatInput/store/selectors.ts +5 -0
  84. package/src/features/Conversation/components/BackBottom/style.ts +1 -1
  85. package/src/features/Conversation/components/SkeletonList.tsx +10 -3
  86. package/src/features/Conversation/components/VirtualizedList/index.tsx +53 -44
  87. package/src/features/Conversation/components/WideScreenContainer/index.tsx +43 -0
  88. package/src/features/Portal/Thread/Chat/ChatInput/index.tsx +49 -42
  89. package/src/features/Portal/Thread/Chat/ChatInput/useSend.ts +48 -22
  90. package/src/features/Portal/Thread/Chat/index.tsx +2 -2
  91. package/src/features/Portal/Thread/Header/index.tsx +1 -1
  92. package/src/hooks/useHotkeys/chatScope.ts +5 -3
  93. package/src/layout/GlobalProvider/Editor.tsx +27 -0
  94. package/src/layout/GlobalProvider/Locale.tsx +3 -23
  95. package/src/libs/trpc/client/lambda.ts +76 -63
  96. package/src/locales/default/chat.ts +7 -2
  97. package/src/locales/default/editor.ts +47 -0
  98. package/src/locales/default/index.ts +2 -0
  99. package/src/services/aiChat.ts +8 -2
  100. package/src/store/chat/slices/aiChat/actions/__tests__/generateAIChatV2.test.ts +42 -33
  101. package/src/store/chat/slices/aiChat/actions/generateAIChatV2.ts +174 -35
  102. package/src/store/chat/slices/aiChat/initialState.ts +19 -0
  103. package/src/store/chat/slices/aiChat/selectors.ts +18 -0
  104. package/src/store/global/action.test.ts +6 -5
  105. package/src/store/global/actions/__tests__/general.test.ts +6 -6
  106. package/src/store/global/actions/workspacePane.ts +6 -0
  107. package/src/store/global/initialState.ts +2 -4
  108. package/src/store/global/selectors/systemStatus.test.ts +1 -2
  109. package/src/store/global/selectors/systemStatus.ts +2 -5
  110. package/src/app/(backend)/webapi/chat/anthropic/route.test.ts +0 -30
  111. package/src/app/(backend)/webapi/chat/anthropic/route.ts +0 -21
  112. package/src/app/(backend)/webapi/chat/google/route.test.ts +0 -35
  113. package/src/app/(backend)/webapi/chat/google/route.ts +0 -25
  114. package/src/app/(backend)/webapi/chat/groq/route.test.ts +0 -29
  115. package/src/app/(backend)/webapi/chat/groq/route.ts +0 -21
  116. package/src/app/(backend)/webapi/chat/openai/route.test.ts +0 -30
  117. package/src/app/(backend)/webapi/chat/openai/route.ts +0 -26
  118. package/src/app/[variants]/(main)/chat/(workspace)/@conversation/features/ChatInput/Desktop/Footer/SendMore.tsx +0 -104
  119. package/src/app/[variants]/(main)/chat/(workspace)/@conversation/features/ChatInput/Desktop/Footer/ShortcutHint.tsx +0 -40
  120. package/src/app/[variants]/(main)/chat/(workspace)/@conversation/features/ChatInput/Desktop/Footer/index.tsx +0 -125
  121. package/src/app/[variants]/(main)/chat/(workspace)/@conversation/features/ChatInput/Desktop/TextArea.test.tsx +0 -332
  122. package/src/app/[variants]/(main)/chat/(workspace)/@conversation/features/ChatInput/Desktop/TextArea.tsx +0 -29
  123. package/src/app/[variants]/(main)/chat/(workspace)/@conversation/features/ChatInput/Mobile/Files/index.tsx +0 -33
  124. package/src/app/[variants]/(main)/chat/(workspace)/@conversation/features/ChatInput/Mobile/InputArea/Container.tsx +0 -41
  125. package/src/app/[variants]/(main)/chat/(workspace)/@conversation/features/ChatInput/Mobile/InputArea/index.tsx +0 -156
  126. package/src/app/[variants]/(main)/chat/(workspace)/@conversation/features/ChatInput/Mobile/Send.tsx +0 -33
  127. package/src/features/ChatInput/Desktop/Header/index.tsx +0 -30
  128. package/src/features/ChatInput/Desktop/InputArea/index.tsx +0 -143
  129. package/src/features/ChatInput/Desktop/__tests__/useAutoFocus.test.ts +0 -45
  130. package/src/features/ChatInput/Desktop/useAutoFocus.ts +0 -13
  131. package/src/features/ChatInput/useSend.ts +0 -102
  132. package/src/features/Portal/Thread/Chat/ChatInput/Footer.tsx +0 -90
  133. package/src/features/Portal/Thread/Chat/ChatInput/TextArea.tsx +0 -30
  134. package/src/libs/trpc/client/types.ts +0 -18
  135. /package/src/{app/[variants]/(main)/chat/(workspace)/@conversation/features/ChatInput/Mobile/Files → features/ChatInput/Mobile/FilePreview}/FileItem/Image.tsx +0 -0
  136. /package/src/{app/[variants]/(main)/chat/(workspace)/@conversation/features/ChatInput/Mobile/Files → features/ChatInput/Mobile/FilePreview}/FileItem/index.tsx +0 -0
  137. /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
- }