@lobehub/chat 0.122.9 → 0.123.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 (227) hide show
  1. package/.env.example +22 -2
  2. package/.eslintrc.js +1 -0
  3. package/CHANGELOG.md +25 -0
  4. package/README.md +11 -9
  5. package/README.zh-CN.md +11 -9
  6. package/docs/Deployment/Environment-Variable.md +65 -23
  7. package/docs/Deployment/Environment-Variable.zh-CN.md +64 -22
  8. package/locales/ar/chat.json +12 -1
  9. package/locales/ar/common.json +16 -0
  10. package/locales/ar/error.json +35 -6
  11. package/locales/ar/setting.json +53 -6
  12. package/locales/de-DE/chat.json +12 -1
  13. package/locales/de-DE/common.json +16 -0
  14. package/locales/de-DE/error.json +35 -6
  15. package/locales/de-DE/setting.json +53 -6
  16. package/locales/en-US/chat.json +13 -2
  17. package/locales/en-US/common.json +16 -0
  18. package/locales/en-US/error.json +35 -6
  19. package/locales/en-US/setting.json +53 -6
  20. package/locales/es-ES/chat.json +12 -1
  21. package/locales/es-ES/common.json +16 -0
  22. package/locales/es-ES/error.json +35 -6
  23. package/locales/es-ES/setting.json +53 -6
  24. package/locales/fr-FR/chat.json +13 -2
  25. package/locales/fr-FR/common.json +16 -0
  26. package/locales/fr-FR/error.json +35 -6
  27. package/locales/fr-FR/setting.json +53 -6
  28. package/locales/it-IT/chat.json +12 -1
  29. package/locales/it-IT/common.json +16 -0
  30. package/locales/it-IT/error.json +35 -6
  31. package/locales/it-IT/setting.json +53 -6
  32. package/locales/ja-JP/chat.json +12 -1
  33. package/locales/ja-JP/common.json +16 -0
  34. package/locales/ja-JP/error.json +35 -6
  35. package/locales/ja-JP/setting.json +53 -6
  36. package/locales/ko-KR/chat.json +12 -1
  37. package/locales/ko-KR/common.json +16 -0
  38. package/locales/ko-KR/error.json +35 -6
  39. package/locales/ko-KR/setting.json +53 -6
  40. package/locales/nl-NL/chat.json +12 -1
  41. package/locales/nl-NL/common.json +16 -0
  42. package/locales/nl-NL/error.json +35 -6
  43. package/locales/nl-NL/setting.json +53 -6
  44. package/locales/pl-PL/chat.json +12 -1
  45. package/locales/pl-PL/common.json +16 -0
  46. package/locales/pl-PL/error.json +35 -6
  47. package/locales/pl-PL/setting.json +53 -6
  48. package/locales/pt-BR/chat.json +12 -1
  49. package/locales/pt-BR/common.json +16 -0
  50. package/locales/pt-BR/error.json +35 -6
  51. package/locales/pt-BR/setting.json +53 -6
  52. package/locales/ru-RU/chat.json +12 -1
  53. package/locales/ru-RU/common.json +16 -0
  54. package/locales/ru-RU/error.json +35 -6
  55. package/locales/ru-RU/setting.json +53 -6
  56. package/locales/tr-TR/chat.json +12 -1
  57. package/locales/tr-TR/common.json +16 -0
  58. package/locales/tr-TR/error.json +35 -6
  59. package/locales/tr-TR/setting.json +53 -6
  60. package/locales/vi-VN/chat.json +12 -1
  61. package/locales/vi-VN/common.json +16 -0
  62. package/locales/vi-VN/error.json +35 -6
  63. package/locales/vi-VN/setting.json +53 -6
  64. package/locales/zh-CN/chat.json +12 -1
  65. package/locales/zh-CN/common.json +16 -0
  66. package/locales/zh-CN/error.json +34 -5
  67. package/locales/zh-CN/setting.json +59 -12
  68. package/locales/zh-TW/chat.json +12 -1
  69. package/locales/zh-TW/common.json +16 -0
  70. package/locales/zh-TW/error.json +35 -6
  71. package/locales/zh-TW/setting.json +53 -6
  72. package/next.config.mjs +8 -2
  73. package/package.json +8 -1
  74. package/src/app/api/chat/[provider]/agentRuntime.ts +129 -0
  75. package/src/app/api/chat/[provider]/route.ts +64 -0
  76. package/src/app/api/chat/auth.ts +42 -0
  77. package/src/app/api/chat/google/route.ts +86 -0
  78. package/src/app/api/config/route.ts +6 -1
  79. package/src/app/api/config.ts +3 -3
  80. package/src/app/api/errorResponse.test.ts +8 -8
  81. package/src/app/api/errorResponse.ts +43 -6
  82. package/src/app/api/openai/createBizOpenAI/createAzureOpenai.ts +1 -1
  83. package/src/app/api/openai/createBizOpenAI/createOpenai.ts +1 -1
  84. package/src/app/api/openai/createBizOpenAI/index.ts +2 -2
  85. package/src/app/chat/(desktop)/features/ChatHeader.tsx +6 -4
  86. package/src/app/chat/(desktop)/features/ChatInput/Footer/index.tsx +13 -3
  87. package/src/app/chat/(desktop)/features/ChatInput/Header/index.tsx +16 -24
  88. package/src/app/chat/(desktop)/features/SideBar/index.tsx +1 -0
  89. package/src/app/chat/features/ChatHeader/ShareButton/Preview.tsx +3 -3
  90. package/src/app/chat/features/SessionListContent/List/Item/index.tsx +2 -3
  91. package/src/app/settings/llm/Azure/index.tsx +145 -0
  92. package/src/app/settings/llm/Bedrock/index.tsx +109 -0
  93. package/src/app/settings/llm/{LLM/Checker.tsx → Checker.tsx} +11 -14
  94. package/src/app/settings/llm/Google/index.tsx +74 -0
  95. package/src/app/settings/llm/{LLM → OpenAI}/index.tsx +26 -44
  96. package/src/app/settings/llm/Zhipu/index.tsx +78 -0
  97. package/src/app/settings/llm/const.ts +13 -0
  98. package/src/app/settings/llm/page.tsx +42 -2
  99. package/src/app/settings/llm/useSyncSettings.ts +23 -0
  100. package/src/chains/__tests__/langDetect.test.ts +2 -2
  101. package/src/chains/__tests__/pickEmoji.test.ts +2 -2
  102. package/src/chains/langDetect.ts +2 -2
  103. package/src/chains/pickEmoji.ts +2 -2
  104. package/src/chains/summaryAgentName.ts +2 -2
  105. package/src/chains/summaryDescription.ts +2 -2
  106. package/src/chains/summaryTags.ts +2 -2
  107. package/src/chains/summaryTitle.ts +2 -2
  108. package/src/chains/translate.ts +2 -2
  109. package/src/components/ModelIcon/index.tsx +37 -0
  110. package/src/components/ModelProviderIcon/index.tsx +44 -0
  111. package/src/components/ModelSelect/index.tsx +133 -0
  112. package/src/components/ModelTag/ModelIcon.tsx +35 -0
  113. package/src/components/ModelTag/index.tsx +13 -0
  114. package/src/config/modelProviders/bedrock.ts +43 -0
  115. package/src/config/modelProviders/google.ts +20 -0
  116. package/src/config/modelProviders/index.ts +18 -0
  117. package/src/config/modelProviders/openai.ts +102 -0
  118. package/src/config/modelProviders/zhipu.ts +34 -0
  119. package/src/config/{server.ts → server/app.ts} +1 -24
  120. package/src/config/server/index.ts +13 -0
  121. package/src/config/server/provider.ts +78 -0
  122. package/src/const/auth.ts +30 -0
  123. package/src/const/fetch.ts +3 -0
  124. package/src/const/settings.ts +24 -4
  125. package/src/database/core/migrations/migrateSettingsToUser/index.test.ts +2 -1
  126. package/src/database/core/migrations/migrateSettingsToUser/index.ts +1 -18
  127. package/src/database/core/migrations/migrateSettingsToUser/type.ts +100 -0
  128. package/src/database/models/message.ts +3 -1
  129. package/src/database/schemas/message.ts +1 -0
  130. package/src/database/schemas/session.ts +1 -0
  131. package/src/features/AgentSetting/AgentConfig/ModelSelect.tsx +71 -0
  132. package/src/features/AgentSetting/AgentConfig/index.tsx +171 -161
  133. package/src/features/AgentSetting/AgentConfig/useSyncConfig.ts +23 -0
  134. package/src/features/AgentSetting/AgentPrompt/TokenTag.tsx +39 -0
  135. package/src/features/AgentSetting/AgentPrompt/index.tsx +4 -26
  136. package/src/features/AgentSetting/store/index.ts +10 -2
  137. package/src/features/ChatInput/ActionBar/FileUpload.tsx +11 -4
  138. package/src/features/ChatInput/ActionBar/ModelSwitch.tsx +56 -14
  139. package/src/features/ChatInput/ActionBar/Token/TokenTag.tsx +42 -7
  140. package/src/features/ChatInput/ActionBar/Token/index.tsx +5 -2
  141. package/src/features/ChatInput/ActionBar/Tools/index.tsx +11 -1
  142. package/src/features/ChatInput/useChatInput.ts +5 -1
  143. package/src/features/Conversation/Error/APIKeyForm/Bedrock.tsx +80 -0
  144. package/src/features/Conversation/Error/APIKeyForm/Google.tsx +61 -0
  145. package/src/features/Conversation/Error/APIKeyForm/OpenAI.tsx +63 -0
  146. package/src/features/Conversation/Error/APIKeyForm/Zhipu.tsx +62 -0
  147. package/src/features/Conversation/Error/APIKeyForm/index.tsx +72 -0
  148. package/src/features/Conversation/Error/AccessCodeForm.tsx +63 -0
  149. package/src/features/Conversation/Error/ErrorJsonViewer.tsx +26 -0
  150. package/src/features/Conversation/Error/InvalidAPIKey.tsx +16 -0
  151. package/src/features/Conversation/Error/InvalidAccessCode.tsx +50 -0
  152. package/src/features/Conversation/Error/OpenAiBizError.tsx +9 -17
  153. package/src/features/Conversation/Error/{Plugin/PluginSettings.tsx → PluginSettings.tsx} +8 -3
  154. package/src/features/Conversation/Error/index.tsx +75 -70
  155. package/src/features/Conversation/Error/style.tsx +9 -3
  156. package/src/features/Conversation/Extras/Assistant.tsx +2 -3
  157. package/src/features/Conversation/Plugins/Inspector/index.tsx +8 -2
  158. package/src/features/Conversation/components/ChatItem/index.tsx +9 -24
  159. package/src/features/Conversation/types/index.tsx +2 -5
  160. package/src/hooks/_header.ts +35 -0
  161. package/src/libs/agent-runtime/BaseAI.ts +9 -0
  162. package/src/libs/agent-runtime/azureOpenai/index.ts +72 -0
  163. package/src/libs/agent-runtime/bedrock/index.ts +134 -0
  164. package/src/libs/agent-runtime/error.ts +26 -0
  165. package/src/libs/agent-runtime/google/index.ts +160 -0
  166. package/src/libs/agent-runtime/index.ts +9 -0
  167. package/src/libs/agent-runtime/openai/index.test.ts +176 -0
  168. package/src/libs/agent-runtime/openai/index.ts +107 -0
  169. package/src/libs/agent-runtime/types/chat.ts +119 -0
  170. package/src/libs/agent-runtime/types/index.ts +2 -0
  171. package/src/libs/agent-runtime/types/type.ts +34 -0
  172. package/src/libs/agent-runtime/utils/createError.ts +10 -0
  173. package/src/libs/agent-runtime/utils/debugStream.ts +18 -0
  174. package/src/libs/agent-runtime/utils/env.ts +1 -0
  175. package/src/libs/agent-runtime/utils/handleOpenAIError.ts +39 -0
  176. package/src/libs/agent-runtime/utils/uriParser.ts +16 -0
  177. package/src/libs/agent-runtime/zhipu/authToken.ts +22 -0
  178. package/src/libs/agent-runtime/zhipu/index.ts +125 -0
  179. package/src/locales/default/chat.ts +12 -2
  180. package/src/locales/default/common.ts +16 -0
  181. package/src/locales/default/error.ts +42 -5
  182. package/src/locales/default/setting.ts +61 -12
  183. package/src/services/__tests__/chat.test.ts +8 -2
  184. package/src/services/__tests__/message.test.ts +1 -1
  185. package/src/services/_auth.ts +106 -0
  186. package/src/services/_header.ts +1 -0
  187. package/src/services/_url.ts +0 -2
  188. package/src/services/chat.ts +32 -14
  189. package/src/store/chat/slices/message/action.ts +9 -6
  190. package/src/store/global/slices/common/action.ts +8 -2
  191. package/src/store/global/slices/settings/action.test.ts +2 -2
  192. package/src/store/global/slices/settings/action.ts +11 -4
  193. package/src/store/global/slices/settings/selectors/__snapshots__/modelProvider.test.ts.snap +242 -78
  194. package/src/store/global/slices/settings/selectors/__snapshots__/selectors.test.ts.snap +2 -0
  195. package/src/store/global/slices/settings/selectors/modelProvider.test.ts +171 -47
  196. package/src/store/global/slices/settings/selectors/modelProvider.ts +136 -43
  197. package/src/store/session/slices/agent/selectors.test.ts +0 -48
  198. package/src/store/session/slices/agent/selectors.ts +7 -12
  199. package/src/types/agent/index.ts +6 -2
  200. package/src/types/fetch.ts +4 -2
  201. package/src/types/files.ts +3 -3
  202. package/src/types/llm.ts +27 -0
  203. package/src/types/message/index.ts +7 -3
  204. package/src/types/openai/chat.ts +6 -11
  205. package/src/types/settings/index.ts +1 -0
  206. package/src/types/settings/modelProvider.ts +37 -1
  207. package/src/utils/__snapshots__/parseModels.test.ts.snap +63 -0
  208. package/src/utils/parseModels.test.ts +24 -0
  209. package/src/utils/parseModels.ts +37 -0
  210. package/src/app/api/openai/chat/createChatCompletion.test.ts +0 -166
  211. package/src/app/api/openai/chat/createChatCompletion.ts +0 -76
  212. package/src/app/api/openai/chat/route.ts +0 -19
  213. package/src/app/api/openai/models/route.ts +0 -17
  214. package/src/app/settings/llm/LLM/ModelList.tsx +0 -51
  215. package/src/app/settings/llm/LLM/getModelList.ts +0 -9
  216. package/src/app/settings/llm/index.tsx +0 -36
  217. package/src/const/llm.ts +0 -32
  218. package/src/features/Conversation/Error/ApiKeyForm.tsx +0 -87
  219. package/src/features/Conversation/Error/ErrorActionContainer.tsx +0 -23
  220. package/src/features/Conversation/Error/InvalidAccess.tsx +0 -90
  221. package/src/features/Conversation/Error/OpenAPIKey.tsx +0 -13
  222. package/src/features/Conversation/Error/Plugin/PluginError.tsx +0 -30
  223. package/src/services/modelList.ts +0 -15
  224. /package/src/app/chat/(desktop)/features/ChatInput/{Header → Footer}/DragUpload.tsx +0 -0
  225. /package/src/{app/api/openai/chat → libs/agent-runtime/utils}/desensitizeUrl.test.ts +0 -0
  226. /package/src/{app/api/openai/chat → libs/agent-runtime/utils}/desensitizeUrl.ts +0 -0
  227. /package/src/types/{translate.ts → message/translate.ts} +0 -0
@@ -1,17 +1,22 @@
1
1
  import { TokenTag, Tooltip } from '@lobehub/ui';
2
+ import numeral from 'numeral';
2
3
  import { memo } from 'react';
3
4
  import { useTranslation } from 'react-i18next';
5
+ import { Flexbox } from 'react-layout-kit';
4
6
 
5
- import { ModelTokens } from '@/const/llm';
6
7
  import { useTokenCount } from '@/hooks/useTokenCount';
7
8
  import { useChatStore } from '@/store/chat';
8
9
  import { chatSelectors } from '@/store/chat/selectors';
10
+ import { useGlobalStore } from '@/store/global';
11
+ import { modelProviderSelectors } from '@/store/global/selectors';
9
12
  import { useSessionStore } from '@/store/session';
10
13
  import { agentSelectors } from '@/store/session/selectors';
11
14
  import { useToolStore } from '@/store/tool';
12
15
  import { toolSelectors } from '@/store/tool/selectors';
13
16
  import { LanguageModel } from '@/types/llm';
14
17
 
18
+ const format = (number: number) => numeral(number).format('0,0');
19
+
15
20
  const Token = memo(() => {
16
21
  const { t } = useTranslation('chat');
17
22
 
@@ -25,6 +30,8 @@ const Token = memo(() => {
25
30
  agentSelectors.currentAgentModel(s) as LanguageModel,
26
31
  ]);
27
32
 
33
+ const tokens = useGlobalStore(modelProviderSelectors.modelMaxToken(model));
34
+
28
35
  const plugins = useSessionStore(agentSelectors.currentAgentPlugins);
29
36
 
30
37
  const toolsString = useToolStore((s) => {
@@ -38,26 +45,54 @@ const Token = memo(() => {
38
45
  });
39
46
 
40
47
  const inputTokenCount = useTokenCount(input);
48
+ const chatsToken = useTokenCount(messageString) + inputTokenCount;
41
49
 
42
- const systemRoleToken = useTokenCount(systemRole);
43
- const chatsToken = useTokenCount(messageString);
44
50
  const toolsToken = useTokenCount(toolsString);
51
+ const systemRoleToken = useTokenCount(systemRole);
45
52
 
46
- const totalToken = systemRoleToken + chatsToken + toolsToken;
53
+ const totalToken = systemRoleToken + toolsToken + chatsToken;
47
54
  return (
48
55
  <Tooltip
49
56
  placement={'bottom'}
50
- title={t('tokenDetail', { chatsToken, systemRoleToken, toolsToken })}
57
+ title={
58
+ <Flexbox width={150}>
59
+ <Flexbox horizontal justify={'space-between'}>
60
+ <span>{t('tokenDetails.systemRole')}</span>
61
+ <span>{format(systemRoleToken)}</span>
62
+ </Flexbox>
63
+ <Flexbox horizontal justify={'space-between'}>
64
+ <span>{t('tokenDetails.tools')}</span>
65
+ <span>{format(toolsToken)}</span>
66
+ </Flexbox>
67
+ <Flexbox horizontal justify={'space-between'}>
68
+ <span>{t('tokenDetails.chats')}</span>
69
+ <span>{format(chatsToken)}</span>
70
+ </Flexbox>
71
+ <Flexbox horizontal justify={'space-between'}>
72
+ <span>{t('tokenDetails.used')}</span>
73
+ <span>{format(totalToken)}</span>
74
+ </Flexbox>
75
+ <Flexbox horizontal justify={'space-between'} style={{ marginTop: 8 }}>
76
+ <span>{t('tokenDetails.total')}</span>
77
+ <span>{format(tokens)}</span>
78
+ </Flexbox>
79
+ <Flexbox horizontal justify={'space-between'}>
80
+ <span>{t('tokenDetails.rest')}</span>
81
+ <span>{format(tokens - totalToken)}</span>
82
+ </Flexbox>
83
+ </Flexbox>
84
+ }
51
85
  >
52
86
  <TokenTag
53
- maxValue={ModelTokens[model]}
87
+ displayMode={'used'}
88
+ maxValue={tokens}
54
89
  style={{ marginLeft: 8 }}
55
90
  text={{
56
91
  overload: t('tokenTag.overload'),
57
92
  remained: t('tokenTag.remained'),
58
93
  used: t('tokenTag.used'),
59
94
  }}
60
- value={totalToken + inputTokenCount}
95
+ value={totalToken}
61
96
  />
62
97
  </Tooltip>
63
98
  );
@@ -1,15 +1,18 @@
1
1
  import dynamic from 'next/dynamic';
2
2
  import { memo } from 'react';
3
3
 
4
+ import { useGlobalStore } from '@/store/global';
5
+ import { modelProviderSelectors } from '@/store/global/selectors';
4
6
  import { useSessionStore } from '@/store/session';
5
7
  import { agentSelectors } from '@/store/session/selectors';
6
8
 
7
9
  const LargeTokenContent = dynamic(() => import('./TokenTag'), { ssr: false });
8
10
 
9
11
  const Token = memo(() => {
10
- const [showTokenTag] = useSessionStore((s) => [agentSelectors.showTokenTag(s)]);
12
+ const model = useSessionStore(agentSelectors.currentAgentModel);
13
+ const showTag = useGlobalStore(modelProviderSelectors.modelHasMaxToken(model));
11
14
 
12
- return showTokenTag && <LargeTokenContent />;
15
+ return showTag && <LargeTokenContent />;
13
16
  });
14
17
 
15
18
  export default Token;
@@ -8,6 +8,8 @@ import { useTranslation } from 'react-i18next';
8
8
  import { Flexbox } from 'react-layout-kit';
9
9
 
10
10
  import PluginStore from '@/features/PluginStore';
11
+ import { useGlobalStore } from '@/store/global';
12
+ import { modelProviderSelectors } from '@/store/global/selectors';
11
13
  import { useSessionStore } from '@/store/session';
12
14
  import { agentSelectors } from '@/store/session/selectors';
13
15
  import { pluginHelpers, useToolStore } from '@/store/tool';
@@ -43,6 +45,9 @@ const Tools = memo(() => {
43
45
  const [open, setOpen] = useState(false);
44
46
  const { styles } = useStyles();
45
47
 
48
+ const model = useSessionStore(agentSelectors.currentAgentModel);
49
+ const enableFC = useGlobalStore(modelProviderSelectors.modelEnabledFunctionCall(model));
50
+
46
51
  return (
47
52
  <>
48
53
  <Dropdown
@@ -118,7 +123,12 @@ const Tools = memo(() => {
118
123
  placement={'top'}
119
124
  trigger={['click']}
120
125
  >
121
- <ActionIcon icon={Blocks} placement={'bottom'} title={t('tools.title')} />
126
+ <ActionIcon
127
+ disable={!enableFC}
128
+ icon={Blocks}
129
+ placement={'bottom'}
130
+ title={t(enableFC ? 'tools.title' : 'tools.disabled')}
131
+ />
122
132
  </Dropdown>
123
133
  <PluginStore open={open} setOpen={setOpen} />
124
134
  </>
@@ -2,6 +2,8 @@ import { TextAreaRef } from 'antd/es/input/TextArea';
2
2
  import { useCallback, useRef, useState } from 'react';
3
3
 
4
4
  import { useChatStore } from '@/store/chat';
5
+ import { useGlobalStore } from '@/store/global';
6
+ import { modelProviderSelectors } from '@/store/global/selectors';
5
7
  import { useSessionStore } from '@/store/session';
6
8
  import { agentSelectors } from '@/store/session/selectors';
7
9
 
@@ -12,7 +14,9 @@ export const useChatInput = () => {
12
14
  const [expand, setExpand] = useState<boolean>(false);
13
15
  const onSend = useSendMessage();
14
16
 
15
- const canUpload = useSessionStore(agentSelectors.modelHasVisionAbility);
17
+ const model = useSessionStore(agentSelectors.currentAgentModel);
18
+ const canUpload = useGlobalStore(modelProviderSelectors.modelEnabledVision(model));
19
+
16
20
  const [loading, value, onInput, onStop] = useChatStore((s) => [
17
21
  !!s.chatLoadingId,
18
22
  s.inputMessage,
@@ -0,0 +1,80 @@
1
+ import { Aws } from '@lobehub/icons';
2
+ import { Icon } from '@lobehub/ui';
3
+ import { Button, Input, Select } from 'antd';
4
+ import { useTheme } from 'antd-style';
5
+ import { Network } from 'lucide-react';
6
+ import { memo, useState } from 'react';
7
+ import { useTranslation } from 'react-i18next';
8
+
9
+ import { ModelProvider } from '@/libs/agent-runtime';
10
+ import { useGlobalStore } from '@/store/global';
11
+ import { modelProviderSelectors } from '@/store/global/selectors';
12
+
13
+ import { FormAction } from '../style';
14
+
15
+ const BedrockForm = memo(() => {
16
+ const { t } = useTranslation('error');
17
+ const [showRegion, setShow] = useState(false);
18
+
19
+ const [accessKeyId, secretAccessKey, region, setConfig] = useGlobalStore((s) => [
20
+ modelProviderSelectors.bedrockConfig(s).accessKeyId,
21
+ modelProviderSelectors.bedrockConfig(s).secretAccessKey,
22
+ modelProviderSelectors.bedrockConfig(s).region,
23
+ s.setModelProviderConfig,
24
+ ]);
25
+
26
+ const theme = useTheme();
27
+ return (
28
+ <FormAction
29
+ avatar={<Aws.Color color={theme.colorText} size={56} />}
30
+ description={t('unlock.apikey.Bedrock.description')}
31
+ title={t('unlock.apikey.Bedrock.title')}
32
+ >
33
+ <Input.Password
34
+ autoComplete={'new-password'}
35
+ onChange={(e) => {
36
+ setConfig(ModelProvider.Bedrock, { accessKeyId: e.target.value });
37
+ }}
38
+ placeholder={'Aws Access Key Id'}
39
+ type={'block'}
40
+ value={accessKeyId}
41
+ />
42
+ <Input.Password
43
+ autoComplete={'new-password'}
44
+ onChange={(e) => {
45
+ setConfig(ModelProvider.Bedrock, { secretAccessKey: e.target.value });
46
+ }}
47
+ placeholder={'Aws Secret Access Key'}
48
+ type={'block'}
49
+ value={secretAccessKey}
50
+ />
51
+ {showRegion ? (
52
+ <Select
53
+ onChange={(region) => {
54
+ setConfig('bedrock', { region });
55
+ }}
56
+ options={['us-east-1', 'us-west-2', 'ap-southeast-1'].map((i) => ({
57
+ label: i,
58
+ value: i,
59
+ }))}
60
+ placeholder={'https://api.openai.com/v1'}
61
+ style={{ width: '100%' }}
62
+ value={region}
63
+ />
64
+ ) : (
65
+ <Button
66
+ block
67
+ icon={<Icon icon={Network} />}
68
+ onClick={() => {
69
+ setShow(true);
70
+ }}
71
+ type={'text'}
72
+ >
73
+ {t('unlock.apikey.Bedrock.customRegion')}
74
+ </Button>
75
+ )}
76
+ </FormAction>
77
+ );
78
+ });
79
+
80
+ export default BedrockForm;
@@ -0,0 +1,61 @@
1
+ import { Google } from '@lobehub/icons';
2
+ import { Input } from 'antd';
3
+ import { memo } from 'react';
4
+ import { useTranslation } from 'react-i18next';
5
+
6
+ import { ModelProvider } from '@/libs/agent-runtime';
7
+ import { useGlobalStore } from '@/store/global';
8
+ import { modelProviderSelectors } from '@/store/global/selectors';
9
+
10
+ import { FormAction } from '../style';
11
+
12
+ const GoogleForm = memo(() => {
13
+ const { t } = useTranslation('error');
14
+ // const [showProxy, setShow] = useState(false);
15
+
16
+ const [apiKey, setConfig] = useGlobalStore((s) => [
17
+ modelProviderSelectors.googleAPIKey(s),
18
+ // modelProviderSelectors.openAIProxyUrl(s),
19
+ s.setModelProviderConfig,
20
+ ]);
21
+
22
+ return (
23
+ <FormAction
24
+ avatar={<Google.Color size={56} />}
25
+ description={t('unlock.apikey.Google.description')}
26
+ title={t('unlock.apikey.Google.title')}
27
+ >
28
+ <Input.Password
29
+ autoComplete={'new-password'}
30
+ onChange={(e) => {
31
+ setConfig(ModelProvider.Google, { apiKey: e.target.value });
32
+ }}
33
+ placeholder={'*********************************'}
34
+ type={'block'}
35
+ value={apiKey}
36
+ />
37
+ {/*{showProxy ? (*/}
38
+ {/* <Input*/}
39
+ {/* onChange={(e) => {*/}
40
+ {/* setConfig({ endpoint: e.target.value });*/}
41
+ {/* }}*/}
42
+ {/* placeholder={'https://api.openai.com/v1'}*/}
43
+ {/* type={'block'}*/}
44
+ {/* value={proxyUrl}*/}
45
+ {/* />*/}
46
+ {/*) : (*/}
47
+ {/* <Button*/}
48
+ {/* icon={<Icon icon={Network} />}*/}
49
+ {/* onClick={() => {*/}
50
+ {/* setShow(true);*/}
51
+ {/* }}*/}
52
+ {/* type={'text'}*/}
53
+ {/* >*/}
54
+ {/* {t('unlock.apikey.addProxyUrl')}*/}
55
+ {/* </Button>*/}
56
+ {/*)}*/}
57
+ </FormAction>
58
+ );
59
+ });
60
+
61
+ export default GoogleForm;
@@ -0,0 +1,63 @@
1
+ import { OpenAI } from '@lobehub/icons';
2
+ import { Icon } from '@lobehub/ui';
3
+ import { Button, Input } from 'antd';
4
+ import { useTheme } from 'antd-style';
5
+ import { Network } from 'lucide-react';
6
+ import { memo, useState } from 'react';
7
+ import { useTranslation } from 'react-i18next';
8
+
9
+ import { useGlobalStore } from '@/store/global';
10
+ import { modelProviderSelectors } from '@/store/global/selectors';
11
+
12
+ import { FormAction } from '../style';
13
+
14
+ const OpenAIForm = memo(() => {
15
+ const { t } = useTranslation('error');
16
+ const [showProxy, setShow] = useState(false);
17
+
18
+ const [apiKey, proxyUrl, setConfig] = useGlobalStore((s) => [
19
+ modelProviderSelectors.openAIAPIKey(s),
20
+ modelProviderSelectors.openAIProxyUrl(s),
21
+ s.setModelProviderConfig,
22
+ ]);
23
+ const theme = useTheme();
24
+ return (
25
+ <FormAction
26
+ avatar={<OpenAI color={theme.colorText} size={64} />}
27
+ description={t('unlock.apikey.OpenAI.description')}
28
+ title={t('unlock.apikey.OpenAI.title')}
29
+ >
30
+ <Input.Password
31
+ autoComplete={'new-password'}
32
+ onChange={(e) => {
33
+ setConfig('openAI', { OPENAI_API_KEY: e.target.value });
34
+ }}
35
+ placeholder={'sk-*****************************************'}
36
+ type={'block'}
37
+ value={apiKey}
38
+ />
39
+ {showProxy ? (
40
+ <Input
41
+ onChange={(e) => {
42
+ setConfig('openAI', { endpoint: e.target.value });
43
+ }}
44
+ placeholder={'https://api.openai.com/v1'}
45
+ type={'block'}
46
+ value={proxyUrl}
47
+ />
48
+ ) : (
49
+ <Button
50
+ icon={<Icon icon={Network} />}
51
+ onClick={() => {
52
+ setShow(true);
53
+ }}
54
+ type={'text'}
55
+ >
56
+ {t('unlock.apikey.OpenAI.addProxyUrl')}
57
+ </Button>
58
+ )}
59
+ </FormAction>
60
+ );
61
+ });
62
+
63
+ export default OpenAIForm;
@@ -0,0 +1,62 @@
1
+ import { Zhipu } from '@lobehub/icons';
2
+ import { Input } from 'antd';
3
+ import { rgba } from 'polished';
4
+ import { memo } from 'react';
5
+ import { useTranslation } from 'react-i18next';
6
+
7
+ import { ModelProvider } from '@/libs/agent-runtime';
8
+ import { useGlobalStore } from '@/store/global';
9
+ import { modelProviderSelectors } from '@/store/global/selectors';
10
+
11
+ import { FormAction } from '../style';
12
+
13
+ const ZhipuForm = memo(() => {
14
+ const { t } = useTranslation('error');
15
+
16
+ const [apiKey, setConfig] = useGlobalStore((s) => [
17
+ modelProviderSelectors.zhipuAPIKey(s),
18
+ s.setModelProviderConfig,
19
+ // modelProviderSelectors.zhipuAPIKey(s),
20
+ ]);
21
+
22
+ return (
23
+ <FormAction
24
+ avatar={<Zhipu.Color size={64} />}
25
+ background={rgba(Zhipu.colorPrimary, 0.1)}
26
+ description={t('unlock.apikey.Zhipu.description')}
27
+ title={t('unlock.apikey.Zhipu.title')}
28
+ >
29
+ <Input.Password
30
+ autoComplete={'new-password'}
31
+ onChange={(e) => {
32
+ setConfig(ModelProvider.ZhiPu, { apiKey: e.target.value });
33
+ }}
34
+ placeholder={'*************************.****************'}
35
+ type={'block'}
36
+ value={apiKey}
37
+ />
38
+ {/*{showProxy ? (*/}
39
+ {/* <Input*/}
40
+ {/* onChange={(e) => {*/}
41
+ {/* setConfig({ endpoint: e.target.value });*/}
42
+ {/* }}*/}
43
+ {/* placeholder={'https://api.openai.com/v1'}*/}
44
+ {/* type={'block'}*/}
45
+ {/* value={proxyUrl}*/}
46
+ {/* />*/}
47
+ {/*) : (*/}
48
+ {/* <Button*/}
49
+ {/* icon={<Icon icon={Network} />}*/}
50
+ {/* onClick={() => {*/}
51
+ {/* setShow(true);*/}
52
+ {/* }}*/}
53
+ {/* type={'text'}*/}
54
+ {/* >*/}
55
+ {/* {t('unlock.apikey.addProxyUrl')}*/}
56
+ {/* </Button>*/}
57
+ {/*)}*/}
58
+ </FormAction>
59
+ );
60
+ });
61
+
62
+ export default ZhipuForm;
@@ -0,0 +1,72 @@
1
+ import { Button } from 'antd';
2
+ import { memo, useMemo } from 'react';
3
+ import { useTranslation } from 'react-i18next';
4
+ import { Center, Flexbox } from 'react-layout-kit';
5
+
6
+ import { ModelProvider } from '@/libs/agent-runtime';
7
+ import { useChatStore } from '@/store/chat';
8
+
9
+ import BedrockForm from './Bedrock';
10
+ import GoogleForm from './Google';
11
+ import OpenAIForm from './OpenAI';
12
+ import ZhipuForm from './Zhipu';
13
+
14
+ interface APIKeyFormProps {
15
+ id: string;
16
+ provider?: string;
17
+ }
18
+
19
+ const APIKeyForm = memo<APIKeyFormProps>(({ id, provider }) => {
20
+ const { t } = useTranslation('error');
21
+
22
+ const [resend, deleteMessage] = useChatStore((s) => [s.resendMessage, s.deleteMessage]);
23
+
24
+ const action = useMemo(() => {
25
+ switch (provider as ModelProvider) {
26
+ case ModelProvider.Bedrock: {
27
+ return <BedrockForm />;
28
+ }
29
+
30
+ case ModelProvider.Google: {
31
+ return <GoogleForm />;
32
+ }
33
+
34
+ case ModelProvider.ZhiPu: {
35
+ return <ZhipuForm />;
36
+ }
37
+
38
+ default:
39
+ case ModelProvider.OpenAI: {
40
+ return <OpenAIForm />;
41
+ }
42
+ }
43
+ }, [provider]);
44
+
45
+ return (
46
+ <Center gap={16} style={{ maxWidth: 300 }}>
47
+ {action}
48
+ <Flexbox gap={12} width={'100%'}>
49
+ <Button
50
+ block
51
+ onClick={() => {
52
+ resend(id);
53
+ deleteMessage(id);
54
+ }}
55
+ style={{ marginTop: 8 }}
56
+ type={'primary'}
57
+ >
58
+ {t('unlock.confirm')}
59
+ </Button>
60
+ <Button
61
+ onClick={() => {
62
+ deleteMessage(id);
63
+ }}
64
+ >
65
+ {t('unlock.closeMessage')}
66
+ </Button>
67
+ </Flexbox>
68
+ </Center>
69
+ );
70
+ });
71
+
72
+ export default APIKeyForm;
@@ -0,0 +1,63 @@
1
+ import { Button, Input } from 'antd';
2
+ import { memo } from 'react';
3
+ import { useTranslation } from 'react-i18next';
4
+ import { Flexbox } from 'react-layout-kit';
5
+
6
+ import { useChatStore } from '@/store/chat';
7
+ import { useGlobalStore } from '@/store/global';
8
+ import { settingsSelectors } from '@/store/global/selectors';
9
+
10
+ import { FormAction } from './style';
11
+
12
+ interface AccessCodeFormProps {
13
+ id: string;
14
+ }
15
+
16
+ const AccessCodeForm = memo<AccessCodeFormProps>(({ id }) => {
17
+ const { t } = useTranslation('error');
18
+ const [password, setSettings] = useGlobalStore((s) => [
19
+ settingsSelectors.currentSettings(s).password,
20
+ s.setSettings,
21
+ ]);
22
+ const [resend, deleteMessage] = useChatStore((s) => [s.resendMessage, s.deleteMessage]);
23
+
24
+ return (
25
+ <>
26
+ <FormAction
27
+ avatar={'🗳'}
28
+ description={t('unlock.password.description')}
29
+ title={t('unlock.password.title')}
30
+ >
31
+ <Input.Password
32
+ autoComplete={'new-password'}
33
+ onChange={(e) => {
34
+ setSettings({ password: e.target.value });
35
+ }}
36
+ placeholder={t('unlock.password.placeholder')}
37
+ type={'block'}
38
+ value={password}
39
+ />
40
+ </FormAction>
41
+ <Flexbox gap={12}>
42
+ <Button
43
+ onClick={() => {
44
+ resend(id);
45
+ deleteMessage(id);
46
+ }}
47
+ type={'primary'}
48
+ >
49
+ {t('unlock.confirm')}
50
+ </Button>
51
+ <Button
52
+ onClick={() => {
53
+ deleteMessage(id);
54
+ }}
55
+ >
56
+ {t('unlock.closeMessage')}
57
+ </Button>
58
+ </Flexbox>
59
+ </>
60
+ );
61
+ });
62
+
63
+ export default AccessCodeForm;
@@ -0,0 +1,26 @@
1
+ import { Highlighter } from '@lobehub/ui';
2
+ import { memo } from 'react';
3
+ import { Flexbox } from 'react-layout-kit';
4
+
5
+ import { ChatMessageError } from '@/types/message';
6
+
7
+ interface ErrorJSONViewerProps {
8
+ error?: ChatMessageError;
9
+ id: string;
10
+ }
11
+
12
+ const ErrorJsonViewer = memo<ErrorJSONViewerProps>(({ error, id }) => {
13
+ const errorBody = error?.body || error;
14
+
15
+ if (!errorBody) return;
16
+
17
+ return (
18
+ <Flexbox id={id} style={{ maxWidth: 600 }}>
19
+ <Highlighter copyButtonSize={'small'} language={'json'}>
20
+ {JSON.stringify(errorBody, null, 2)}
21
+ </Highlighter>
22
+ </Flexbox>
23
+ );
24
+ });
25
+
26
+ export default ErrorJsonViewer;
@@ -0,0 +1,16 @@
1
+ import { memo } from 'react';
2
+
3
+ import APIKeyForm from './APIKeyForm';
4
+ import { ErrorActionContainer } from './style';
5
+
6
+ interface InvalidAPIKeyProps {
7
+ id: string;
8
+ provider?: string;
9
+ }
10
+ const InvalidAPIKey = memo<InvalidAPIKeyProps>(({ id, provider }) => (
11
+ <ErrorActionContainer>
12
+ <APIKeyForm id={id} provider={provider} />
13
+ </ErrorActionContainer>
14
+ ));
15
+
16
+ export default InvalidAPIKey;
@@ -0,0 +1,50 @@
1
+ import { Icon } from '@lobehub/ui';
2
+ import { Segmented } from 'antd';
3
+ import { AsteriskSquare, KeySquare } from 'lucide-react';
4
+ import { memo, useState } from 'react';
5
+ import { useTranslation } from 'react-i18next';
6
+ import { Flexbox } from 'react-layout-kit';
7
+
8
+ import APIKeyForm from './APIKeyForm';
9
+ import AccessCodeForm from './AccessCodeForm';
10
+ import { ErrorActionContainer } from './style';
11
+
12
+ enum Tab {
13
+ Api = 'api',
14
+ Password = 'password',
15
+ }
16
+
17
+ interface InvalidAccessCodeProps {
18
+ id: string;
19
+ provider?: string;
20
+ }
21
+
22
+ const InvalidAccessCode = memo<InvalidAccessCodeProps>(({ id, provider }) => {
23
+ const { t } = useTranslation('error');
24
+ const [mode, setMode] = useState<Tab>(Tab.Password);
25
+
26
+ return (
27
+ <ErrorActionContainer>
28
+ <Segmented
29
+ block
30
+ onChange={(value) => setMode(value as Tab)}
31
+ options={[
32
+ {
33
+ icon: <Icon icon={AsteriskSquare} />,
34
+ label: t('unlock.tabs.password'),
35
+ value: Tab.Password,
36
+ },
37
+ { icon: <Icon icon={KeySquare} />, label: t('unlock.tabs.apiKey'), value: Tab.Api },
38
+ ]}
39
+ style={{ width: '100%' }}
40
+ value={mode}
41
+ />
42
+ <Flexbox gap={24}>
43
+ {mode === Tab.Password && <AccessCodeForm id={id} />}
44
+ {mode === Tab.Api && <APIKeyForm id={id} provider={provider} />}
45
+ </Flexbox>
46
+ </ErrorActionContainer>
47
+ );
48
+ });
49
+
50
+ export default InvalidAccessCode;