@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
@@ -0,0 +1,47 @@
1
+ {
2
+ "actions": {
3
+ "expand": {
4
+ "off": "收起",
5
+ "on": "展开"
6
+ },
7
+ "typobar": {
8
+ "off": "隐藏格式工具栏",
9
+ "on": "显示格式工具栏"
10
+ }
11
+ },
12
+ "file": {
13
+ "error": "错误:{{message}}",
14
+ "uploading": "正在上传文件..."
15
+ },
16
+ "image": {
17
+ "broken": "图片损坏"
18
+ },
19
+ "link": {
20
+ "edit": "编辑链接",
21
+ "open": "打开链接",
22
+ "placeholder": "输入链接 URL",
23
+ "unlink": "取消链接"
24
+ },
25
+ "table": {
26
+ "delete": "删除表格",
27
+ "deleteColumn": "删除列",
28
+ "deleteRow": "删除行",
29
+ "insertColumnLeft": "在左侧插入 {{count}} 列",
30
+ "insertColumnRight": "在右侧插入 {{count}} 列",
31
+ "insertRowAbove": "在上方插入 {{count}} 行",
32
+ "insertRowBelow": "在下方插入 {{count}} 行"
33
+ },
34
+ "typobar": {
35
+ "blockquote": "引用",
36
+ "bold": "加粗",
37
+ "bulletList": "无序列表",
38
+ "code": "行内代码",
39
+ "codeblock": "代码块",
40
+ "italic": "斜体",
41
+ "link": "链接",
42
+ "numberList": "有序列表",
43
+ "strikethrough": "删除线",
44
+ "table": "插入表格",
45
+ "underline": "下划线"
46
+ }
47
+ }
@@ -72,8 +72,8 @@
72
72
  "addUser": "新增一條使用者訊息",
73
73
  "more": "更多",
74
74
  "send": "發送",
75
- "sendWithCmdEnter": "按 {{meta}} + Enter 鍵發送",
76
- "sendWithEnter": "按 Enter 鍵發送",
75
+ "sendWithCmdEnter": "按 <key/> 鍵發送",
76
+ "sendWithEnter": "按 <key/> 鍵發送",
77
77
  "stop": "停止",
78
78
  "warp": "換行"
79
79
  },
@@ -232,6 +232,10 @@
232
232
  "threadMessageCount": "{{messageCount}} 條消息",
233
233
  "title": "子話題"
234
234
  },
235
+ "toggleWideScreen": {
236
+ "off": "關閉寬螢幕模式",
237
+ "on": "開啟寬螢幕模式"
238
+ },
235
239
  "tokenDetails": {
236
240
  "chats": "聊天訊息",
237
241
  "historySummary": "歷史總結",
@@ -0,0 +1,47 @@
1
+ {
2
+ "actions": {
3
+ "expand": {
4
+ "off": "收合",
5
+ "on": "展開"
6
+ },
7
+ "typobar": {
8
+ "off": "隱藏格式工具列",
9
+ "on": "顯示格式工具列"
10
+ }
11
+ },
12
+ "file": {
13
+ "error": "錯誤:{{message}}",
14
+ "uploading": "正在上傳檔案..."
15
+ },
16
+ "image": {
17
+ "broken": "圖片損毀"
18
+ },
19
+ "link": {
20
+ "edit": "編輯連結",
21
+ "open": "開啟連結",
22
+ "placeholder": "輸入連結 URL",
23
+ "unlink": "取消連結"
24
+ },
25
+ "table": {
26
+ "delete": "刪除表格",
27
+ "deleteColumn": "刪除列",
28
+ "deleteRow": "刪除行",
29
+ "insertColumnLeft": "在左側插入 {{count}} 列",
30
+ "insertColumnRight": "在右側插入 {{count}} 列",
31
+ "insertRowAbove": "在上方插入 {{count}} 行",
32
+ "insertRowBelow": "在下方插入 {{count}} 行"
33
+ },
34
+ "typobar": {
35
+ "blockquote": "引用",
36
+ "bold": "粗體",
37
+ "bulletList": "無序清單",
38
+ "code": "行內程式碼",
39
+ "codeblock": "程式碼區塊",
40
+ "italic": "斜體",
41
+ "link": "連結",
42
+ "numberList": "有序清單",
43
+ "strikethrough": "刪除線",
44
+ "table": "插入表格",
45
+ "underline": "底線"
46
+ }
47
+ }
@@ -1505,7 +1505,9 @@
1505
1505
  "gpt-4.1-nano": {
1506
1506
  "description": "GPT-4.1 mini 提供了智能、速度和成本之間的平衡,使其成為許多用例中具吸引力的模型。"
1507
1507
  },
1508
- "gpt-4.5-preview": "GPT-4.5-preview 是最新的通用模型,具備深厚的世界知識並能更好地理解使用者意圖,擅長創意任務與代理規劃。此模型的知識截至 2023 年 10 月。",
1508
+ "gpt-4.5-preview": {
1509
+ "description": "GPT-4.5-preview 是最新的通用模型,擁有深厚的世界知識和對使用者意圖的更佳理解,擅長創意任務與代理規劃。該模型的知識截止至2023年10月。"
1510
+ },
1509
1511
  "gpt-4o": {
1510
1512
  "description": "ChatGPT-4o是一款動態模型,實時更新以保持當前最新版本。它結合了強大的語言理解與生成能力,適合於大規模應用場景,包括客戶服務、教育和技術支持。"
1511
1513
  },
package/next.config.ts CHANGED
@@ -22,6 +22,9 @@ const standaloneConfig: NextConfig = {
22
22
 
23
23
  const nextConfig: NextConfig = {
24
24
  ...(isStandaloneMode ? standaloneConfig : {}),
25
+ compiler: {
26
+ emotion: true,
27
+ },
25
28
  compress: isProd,
26
29
  experimental: {
27
30
  optimizePackageImports: [
@@ -30,6 +33,7 @@ const nextConfig: NextConfig = {
30
33
  '@emoji-mart/data',
31
34
  '@icons-pack/react-simple-icons',
32
35
  '@lobehub/ui',
36
+ '@lobehub/icons',
33
37
  'gpt-tokenizer',
34
38
  ],
35
39
  // oidc provider depend on constructor.name
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lobehub/chat",
3
- "version": "1.123.3",
3
+ "version": "1.124.0",
4
4
  "description": "Lobe Chat - an open-source, high-performance chatbot framework that supports speech synthesis, multimodal, and extensible Function Call plugin system. Supports one-click free deployment of your private ChatGPT/LLM web application.",
5
5
  "keywords": [
6
6
  "framework",
@@ -134,6 +134,7 @@
134
134
  "@codesandbox/sandpack-react": "^2.20.0",
135
135
  "@cyntler/react-doc-viewer": "^1.17.0",
136
136
  "@electric-sql/pglite": "0.2.17",
137
+ "@emotion/react": "^11.14.0",
137
138
  "@fal-ai/client": "^1.6.1",
138
139
  "@formkit/auto-animate": "^0.8.2",
139
140
  "@google/genai": "^1.13.0",
@@ -154,10 +155,11 @@
154
155
  "@lobehub/charts": "^2.0.0",
155
156
  "@lobehub/chat-plugin-sdk": "^1.32.4",
156
157
  "@lobehub/chat-plugins-gateway": "^1.9.0",
158
+ "@lobehub/editor": "^1.4.4",
157
159
  "@lobehub/icons": "^2.31.0",
158
160
  "@lobehub/market-sdk": "^0.22.7",
159
161
  "@lobehub/tts": "^2.0.1",
160
- "@lobehub/ui": "^2.8.3",
162
+ "@lobehub/ui": "^2.11.9",
161
163
  "@modelcontextprotocol/sdk": "^1.17.1",
162
164
  "@neondatabase/serverless": "^1.0.1",
163
165
  "@next/third-parties": "^15.4.6",
@@ -7,6 +7,7 @@ export const CHAT_TEXTAREA_MAX_HEIGHT = 800;
7
7
  export const CHAT_TEXTAREA_HEIGHT = 160;
8
8
  export const CHAT_TEXTAREA_HEIGHT_MOBILE = 108;
9
9
  export const CHAT_SIDEBAR_WIDTH = 280;
10
+ export const CONVERSATION_MIN_WIDTH = 850;
10
11
 
11
12
  export const CHAT_PORTAL_WIDTH = 400;
12
13
  export const CHAT_PORTAL_MAX_WIDTH = 1280;
@@ -8,6 +8,7 @@ export * from './chunk';
8
8
  export * from './clientDB';
9
9
  export * from './eval';
10
10
  export * from './fetch';
11
+ export * from './hotkey';
11
12
  export * from './knowledgeBase';
12
13
  export * from './llm';
13
14
  export * from './message';
@@ -2,6 +2,7 @@ export * from './client/cookie';
2
2
  export * from './detectChinese';
3
3
  export * from './format';
4
4
  export * from './imageToBase64';
5
+ export * from './keyboard';
5
6
  export * from './object';
6
7
  export * from './parseModels';
7
8
  export * from './pricing';
@@ -11,7 +11,7 @@ import { ChatStreamPayload } from '@/types/openai/chat';
11
11
  import { createErrorResponse } from '@/utils/errorResponse';
12
12
  import { getTracePayload } from '@/utils/trace';
13
13
 
14
- export const runtime = 'edge';
14
+ export const maxDuration = 300;
15
15
 
16
16
  export const POST = checkAuth(async (req: Request, { params, jwtPayload, createRuntime }) => {
17
17
  const { provider } = await params;
@@ -6,6 +6,7 @@ import { safeParseJSON } from '@/utils/safeParseJSON';
6
6
 
7
7
  import { POST as UniverseRoute } from '../[provider]/route';
8
8
 
9
+ export const maxDuration = 300;
9
10
  // due to the Chinese region does not support accessing Google
10
11
  // we need to use proxy to access it
11
12
  // refs: https://github.com/google/generative-ai-js/issues/29#issuecomment-1866246513
@@ -3,12 +3,13 @@
3
3
  import { useSearchParams } from 'next/navigation';
4
4
  import { useEffect } from 'react';
5
5
 
6
- import { useSendMessage } from '@/features/ChatInput/useSend';
7
6
  import { useChatStore } from '@/store/chat';
8
7
 
8
+ import { useSend } from '../useSend';
9
+
9
10
  const MessageFromUrl = () => {
10
11
  const updateInputMessage = useChatStore((s) => s.updateInputMessage);
11
- const { send: sendMessage } = useSendMessage();
12
+ const { send: sendMessage } = useSend();
12
13
  const searchParams = useSearchParams();
13
14
 
14
15
  useEffect(() => {
@@ -1,51 +1,152 @@
1
1
  'use client';
2
2
 
3
- import { memo } from 'react';
3
+ import { Alert, Hotkey, Icon } from '@lobehub/ui';
4
+ import { BotMessageSquare, LucideCheck, MessageSquarePlus } from 'lucide-react';
5
+ import { Suspense, memo } from 'react';
6
+ import { Trans, useTranslation } from 'react-i18next';
7
+ import { Flexbox } from 'react-layout-kit';
4
8
 
5
- import { ActionKeys } from '@/features/ChatInput/ActionBar/config';
6
- import DesktopChatInput, { FooterRender } from '@/features/ChatInput/Desktop';
7
- import { useGlobalStore } from '@/store/global';
8
- import { systemStatusSelectors } from '@/store/global/selectors';
9
+ import { type ActionKeys, ChatInputProvider, DesktopChatInput } from '@/features/ChatInput';
10
+ import WideScreenContainer from '@/features/Conversation/components/WideScreenContainer';
11
+ import { useChatStore } from '@/store/chat';
12
+ import { aiChatSelectors } from '@/store/chat/selectors';
13
+ import { useUserStore } from '@/store/user';
14
+ import { preferenceSelectors, settingsSelectors } from '@/store/user/selectors';
15
+ import { HotkeyEnum, KeyEnum } from '@/types/hotkey';
9
16
 
10
- import Footer from './Footer';
11
- import TextArea from './TextArea';
17
+ import { useSend } from '../useSend';
18
+ import MessageFromUrl from './MessageFromUrl';
12
19
 
13
- const leftActions = [
20
+ const leftActions: ActionKeys[] = [
14
21
  'model',
15
22
  'search',
23
+ 'typo',
16
24
  'fileUpload',
17
25
  'knowledgeBase',
18
- 'params',
19
- 'history',
20
- 'stt',
21
26
  'tools',
27
+ '---',
28
+ ['params', 'history', 'stt', 'clear'],
22
29
  'mainToken',
23
- ] as ActionKeys[];
30
+ ];
24
31
 
25
- const rightActions = ['clear'] as ActionKeys[];
26
-
27
- const renderTextArea = (onSend: () => void) => <TextArea onSend={onSend} />;
28
- const renderFooter: FooterRender = ({ expand, onExpandChange }) => (
29
- <Footer expand={expand} onExpandChange={onExpandChange} />
30
- );
32
+ const rightActions: ActionKeys[] = ['saveTopic'];
31
33
 
32
34
  const Desktop = memo(() => {
33
- const [inputHeight, updatePreference] = useGlobalStore((s) => [
34
- systemStatusSelectors.inputHeight(s),
35
- s.updateSystemStatus,
35
+ const { t } = useTranslation('chat');
36
+ const { send, generating, disabled, stop } = useSend();
37
+ const [useCmdEnterToSend, updatePreference] = useUserStore((s) => [
38
+ preferenceSelectors.useCmdEnterToSend(s),
39
+ s.updatePreference,
40
+ ]);
41
+
42
+ const [mainInputSendErrorMsg, clearSendMessageError] = useChatStore((s) => [
43
+ aiChatSelectors.isCurrentSendMessageError(s),
44
+ s.clearSendMessageError,
36
45
  ]);
46
+ const hotkey = useUserStore(settingsSelectors.getHotkeyById(HotkeyEnum.AddUserMessage));
37
47
 
38
48
  return (
39
- <DesktopChatInput
40
- inputHeight={inputHeight}
49
+ <ChatInputProvider
50
+ chatInputEditorRef={(instance) => {
51
+ if (!instance) return;
52
+ useChatStore.setState({ mainInputEditor: instance });
53
+ }}
41
54
  leftActions={leftActions}
42
- onInputHeightChange={(height) => {
43
- updatePreference({ inputHeight: height });
55
+ onMarkdownContentChange={(content) => {
56
+ useChatStore.setState({ inputMessage: content });
57
+ }}
58
+ onSend={() => {
59
+ send();
44
60
  }}
45
- renderFooter={renderFooter}
46
- renderTextArea={renderTextArea}
47
61
  rightActions={rightActions}
48
- />
62
+ sendButtonProps={{ disabled, generating, onStop: stop }}
63
+ sendMenu={{
64
+ items: [
65
+ {
66
+ icon: !useCmdEnterToSend ? <Icon icon={LucideCheck} /> : <div />,
67
+ key: 'sendWithEnter',
68
+ label: (
69
+ <Flexbox align={'center'} gap={4} horizontal>
70
+ <Trans
71
+ components={{
72
+ key: <Hotkey keys={KeyEnum.Enter} variant={'borderless'} />,
73
+ }}
74
+ i18nKey={'input.sendWithEnter'}
75
+ ns={'chat'}
76
+ />
77
+ </Flexbox>
78
+ ),
79
+ onClick: () => {
80
+ updatePreference({ useCmdEnterToSend: false });
81
+ },
82
+ },
83
+ {
84
+ icon: useCmdEnterToSend ? <Icon icon={LucideCheck} /> : <div />,
85
+ key: 'sendWithCmdEnter',
86
+ label: (
87
+ <Flexbox align={'center'} gap={4} horizontal>
88
+ <Trans
89
+ components={{
90
+ key: (
91
+ <Hotkey
92
+ keys={[KeyEnum.Mod, KeyEnum.Enter].join('+')}
93
+ variant={'borderless'}
94
+ />
95
+ ),
96
+ }}
97
+ i18nKey={'input.sendWithCmdEnter'}
98
+ ns={'chat'}
99
+ />
100
+ </Flexbox>
101
+ ),
102
+ onClick: () => {
103
+ updatePreference({ useCmdEnterToSend: true });
104
+ },
105
+ },
106
+ { type: 'divider' },
107
+ {
108
+ // disabled,
109
+ icon: <Icon icon={BotMessageSquare} />,
110
+ key: 'addAi',
111
+ label: t('input.addAi'),
112
+ onClick: () => {
113
+ send({ onlyAddAIMessage: true });
114
+ },
115
+ },
116
+ {
117
+ // disabled,
118
+ icon: <Icon icon={MessageSquarePlus} />,
119
+ key: 'addUser',
120
+ label: (
121
+ <Flexbox align={'center'} gap={24} horizontal>
122
+ {t('input.addUser')}
123
+ <Hotkey keys={hotkey} />
124
+ </Flexbox>
125
+ ),
126
+ onClick: () => {
127
+ send({ onlyAddUserMessage: true });
128
+ },
129
+ },
130
+ ],
131
+ }}
132
+ >
133
+ <WideScreenContainer>
134
+ {mainInputSendErrorMsg && (
135
+ <Flexbox paddingBlock={'0 6px'} paddingInline={12}>
136
+ <Alert
137
+ closable
138
+ message={t('input.errorMsg', { errorMsg: mainInputSendErrorMsg })}
139
+ onClose={clearSendMessageError}
140
+ type={'warning'}
141
+ />
142
+ </Flexbox>
143
+ )}
144
+ <DesktopChatInput />
145
+ </WideScreenContainer>
146
+ <Suspense>
147
+ <MessageFromUrl />
148
+ </Suspense>
149
+ </ChatInputProvider>
49
150
  );
50
151
  });
51
152
 
@@ -1,91 +1,69 @@
1
1
  'use client';
2
2
 
3
- import { Skeleton } from 'antd';
4
- import { useTheme } from 'antd-style';
5
- import { TextAreaRef } from 'antd/es/input/TextArea';
6
- import { memo, useRef, useState } from 'react';
3
+ import { Alert } from '@lobehub/ui';
4
+ import { memo } from 'react';
5
+ import { useTranslation } from 'react-i18next';
7
6
  import { Flexbox } from 'react-layout-kit';
8
7
 
9
- import ActionBar from '@/features/ChatInput/ActionBar';
10
- import STT from '@/features/ChatInput/ActionBar/STT';
11
- import { ActionKeys } from '@/features/ChatInput/ActionBar/config';
12
- import SaveTopic from '@/features/ChatInput/Topic';
13
- import { useSendMessage } from '@/features/ChatInput/useSend';
14
- import { useInitAgentConfig } from '@/hooks/useInitAgentConfig';
8
+ import {
9
+ type ActionKey,
10
+ type ActionKeys,
11
+ MobileChatInput as ChatInput,
12
+ ChatInputProvider,
13
+ } from '@/features/ChatInput';
15
14
  import { useChatStore } from '@/store/chat';
16
- import { chatSelectors } from '@/store/chat/selectors';
15
+ import { aiChatSelectors } from '@/store/chat/slices/aiChat/selectors';
17
16
 
18
- import Files from './Files';
19
- import InputArea from './InputArea';
20
- import SendButton from './Send';
17
+ import { useSend } from '../useSend';
21
18
 
22
- const defaultLeftActions: ActionKeys[] = [
19
+ const leftActions: ActionKeys[] = [
23
20
  'model',
24
21
  'search',
25
22
  'fileUpload',
26
23
  'knowledgeBase',
27
- 'history',
28
24
  'tools',
29
- 'params',
25
+ '---',
26
+ ['params', 'history', 'stt', 'clear'],
30
27
  'mainToken',
31
28
  ];
32
29
 
33
- const defaultRightActions: ActionKeys[] = ['clear'];
30
+ const rightActions: ActionKey[] = ['saveTopic'];
34
31
 
35
32
  const MobileChatInput = memo(() => {
36
- const theme = useTheme();
37
- const ref = useRef<TextAreaRef>(null);
38
- const [expand, setExpand] = useState<boolean>(false);
39
- const { send: sendMessage, canSend } = useSendMessage();
40
- const { isLoading } = useInitAgentConfig();
33
+ const { t } = useTranslation('chat');
34
+ const { send, disabled, generating, stop } = useSend();
41
35
 
42
- const [loading, value, onInput, onStop] = useChatStore((s) => [
43
- chatSelectors.isAIGenerating(s),
44
- s.inputMessage,
45
- s.updateInputMessage,
46
- s.stopGenerateMessage,
36
+ const [mainInputSendErrorMsg, clearSendMessageError] = useChatStore((s) => [
37
+ aiChatSelectors.isCurrentSendMessageError(s),
38
+ s.clearSendMessageError,
47
39
  ]);
48
-
49
40
  return (
50
- <InputArea
51
- expand={expand}
52
- onInput={onInput}
53
- onSend={() => {
54
- setExpand(false);
55
-
56
- sendMessage();
41
+ <ChatInputProvider
42
+ chatInputEditorRef={(instance) => {
43
+ if (!instance) return;
44
+ useChatStore.setState({ mainInputEditor: instance });
57
45
  }}
58
- ref={ref}
59
- setExpand={setExpand}
60
- style={{
61
- background: theme.colorBgLayout,
62
- top: expand ? 0 : undefined,
63
- width: '100%',
64
- zIndex: 101,
46
+ leftActions={leftActions}
47
+ mobile
48
+ onMarkdownContentChange={(content) => {
49
+ useChatStore.setState({ inputMessage: content });
65
50
  }}
66
- textAreaLeftAddons={<STT mobile />}
67
- textAreaRightAddons={
68
- <SendButton disabled={!canSend} loading={loading} onSend={sendMessage} onStop={onStop} />
69
- }
70
- topAddons={
71
- isLoading ? (
72
- <Flexbox paddingInline={8}>
73
- <Skeleton.Button active block size={'small'} />
74
- </Flexbox>
75
- ) : (
76
- <>
77
- <Files />
78
- <ActionBar
79
- leftActions={defaultLeftActions}
80
- padding={'0 8px'}
81
- rightActions={defaultRightActions}
82
- rightAreaStartRender={<SaveTopic mobile />}
83
- />
84
- </>
85
- )
86
- }
87
- value={value}
88
- />
51
+ onSend={() => send()}
52
+ rightActions={rightActions}
53
+ sendButtonProps={{ disabled, generating, onStop: stop }}
54
+ >
55
+ {mainInputSendErrorMsg && (
56
+ <Flexbox paddingBlock={'0 6px'} paddingInline={12}>
57
+ <Alert
58
+ closable
59
+ message={t('input.errorMsg', { errorMsg: mainInputSendErrorMsg })}
60
+ onClose={clearSendMessageError}
61
+ type={'warning'}
62
+ />
63
+ </Flexbox>
64
+ )}
65
+ <ChatInput />
66
+ </ChatInputProvider>
89
67
  );
90
68
  });
91
69