@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
@@ -0,0 +1,22 @@
1
+ import { SignJWT } from 'jose';
2
+
3
+ export const generateApiToken = async (apiKey?: string): Promise<string> => {
4
+ if (!apiKey) {
5
+ throw new Error('Invalid apiKey');
6
+ }
7
+
8
+ const [id, secret] = apiKey.split('.');
9
+ if (!id || !secret) {
10
+ throw new Error('Invalid apiKey');
11
+ }
12
+
13
+ const expSeconds = 60 * 60 * 24 * 30;
14
+ const nowSeconds = Math.floor(Date.now() / 1000);
15
+ const exp = nowSeconds + expSeconds;
16
+ const jwtConstructor = new SignJWT({ api_key: id })
17
+ .setProtectedHeader({ alg: 'HS256', sign_type: 'SIGN', typ: 'JWT' })
18
+ .setExpirationTime(exp)
19
+ .setIssuedAt(nowSeconds);
20
+
21
+ return jwtConstructor.sign(new TextEncoder().encode(secret));
22
+ };
@@ -0,0 +1,125 @@
1
+ import { OpenAIStream, StreamingTextResponse } from 'ai';
2
+ import OpenAI from 'openai';
3
+
4
+ import { LobeRuntimeAI } from '../BaseAI';
5
+ import { AgentRuntimeErrorType } from '../error';
6
+ import { ChatStreamPayload, ModelProvider, OpenAIChatMessage } from '../types';
7
+ import { AgentRuntimeError } from '../utils/createError';
8
+ import { debugStream } from '../utils/debugStream';
9
+ import { desensitizeUrl } from '../utils/desensitizeUrl';
10
+ import { DEBUG_CHAT_COMPLETION } from '../utils/env';
11
+ import { handleOpenAIError } from '../utils/handleOpenAIError';
12
+ import { parseDataUri } from '../utils/uriParser';
13
+ import { generateApiToken } from './authToken';
14
+
15
+ const DEFAULT_BASE_URL = 'https://open.bigmodel.cn/api/paas/v4';
16
+
17
+ export class LobeZhipuAI implements LobeRuntimeAI {
18
+ private _llm: OpenAI;
19
+
20
+ baseURL: string;
21
+
22
+ constructor(oai: OpenAI) {
23
+ this._llm = oai;
24
+ this.baseURL = this._llm.baseURL;
25
+ }
26
+
27
+ static async fromAPIKey(apiKey?: string, baseURL: string = DEFAULT_BASE_URL) {
28
+ const invalidZhipuAPIKey = AgentRuntimeError.createError(
29
+ AgentRuntimeErrorType.InvalidZhipuAPIKey,
30
+ );
31
+
32
+ let token: string;
33
+
34
+ try {
35
+ token = await generateApiToken(apiKey);
36
+ } catch {
37
+ throw invalidZhipuAPIKey;
38
+ }
39
+
40
+ const header = { Authorization: `Bearer ${token}` };
41
+
42
+ const llm = new OpenAI({ apiKey, baseURL, defaultHeaders: header });
43
+
44
+ return new LobeZhipuAI(llm);
45
+ }
46
+
47
+ async chat(payload: ChatStreamPayload) {
48
+ try {
49
+ const params = this.buildCompletionsParams(payload);
50
+
51
+ const response = await this._llm.chat.completions.create(
52
+ params as unknown as OpenAI.ChatCompletionCreateParamsStreaming,
53
+ );
54
+
55
+ const stream = OpenAIStream(response);
56
+
57
+ const [debug, returnStream] = stream.tee();
58
+
59
+ if (DEBUG_CHAT_COMPLETION) {
60
+ debugStream(debug).catch(console.error);
61
+ }
62
+
63
+ return new StreamingTextResponse(returnStream);
64
+ } catch (error) {
65
+ const { errorResult, RuntimeError } = handleOpenAIError(error);
66
+
67
+ const errorType = RuntimeError || AgentRuntimeErrorType.ZhipuBizError;
68
+
69
+ let desensitizedEndpoint = this.baseURL;
70
+
71
+ if (this.baseURL !== DEFAULT_BASE_URL) {
72
+ desensitizedEndpoint = desensitizeUrl(this.baseURL);
73
+ }
74
+ throw AgentRuntimeError.chat({
75
+ endpoint: desensitizedEndpoint,
76
+ error: errorResult,
77
+ errorType,
78
+ provider: ModelProvider.ZhiPu,
79
+ });
80
+ }
81
+ }
82
+
83
+ private buildCompletionsParams(payload: ChatStreamPayload) {
84
+ const { messages, temperature, top_p, ...params } = payload;
85
+
86
+ return {
87
+ messages: messages.map((m) => this.transformMessage(m)) as any,
88
+ ...params,
89
+ do_sample: temperature === 0,
90
+ stream: true,
91
+ // 当前的模型侧不支持 top_p=1 和 temperature 为 0
92
+ // refs: https://zhipu-ai.feishu.cn/wiki/TUo0w2LT7iswnckmfSEcqTD0ncd
93
+ temperature: temperature === 0 ? undefined : temperature,
94
+ top_p: top_p === 1 ? 0.99 : top_p,
95
+ };
96
+ }
97
+
98
+ // TODO: 临时处理,后续需要移除
99
+ private transformMessage = (message: OpenAIChatMessage): OpenAIChatMessage => {
100
+ return {
101
+ ...message,
102
+ content:
103
+ typeof message.content === 'string'
104
+ ? message.content
105
+ : message.content.map((c) => {
106
+ switch (c.type) {
107
+ default:
108
+ case 'text': {
109
+ return c;
110
+ }
111
+
112
+ case 'image_url': {
113
+ const { base64 } = parseDataUri(c.image_url.url);
114
+ return {
115
+ image_url: { ...c.image_url, url: base64 || c.image_url.url },
116
+ type: 'image_url',
117
+ };
118
+ }
119
+ }
120
+ }),
121
+ };
122
+ };
123
+ }
124
+
125
+ export default LobeZhipuAI;
@@ -1,4 +1,7 @@
1
1
  export default {
2
+ ModelSwitch: {
3
+ title: '模型',
4
+ },
2
5
  agentDefaultMessage:
3
6
  '你好,我是 **{{name}}**,你可以立即与我开始对话,也可以前往 [助手设置](/chat/settings#session={{id}}) 完善我的信息。',
4
7
  agentDefaultMessageWithSystemRole: '你好,我是 **{{name}}**,{{systemRole}},让我们开始对话吧!',
@@ -66,8 +69,14 @@ export default {
66
69
  prettifying: '润色中...',
67
70
  },
68
71
  temp: '临时',
69
- tokenDetail:
70
- '角色设定: {{systemRoleToken}} · 会话消息: {{chatsToken}} · 工具设定: {{toolsToken}}',
72
+ tokenDetails: {
73
+ chats: '会话消息',
74
+ rest: '剩余可用',
75
+ systemRole: '角色设定',
76
+ tools: '插件设定',
77
+ total: '总共可用',
78
+ used: '总计使用',
79
+ },
71
80
  tokenTag: {
72
81
  overload: '超过限制',
73
82
  remained: '剩余',
@@ -105,6 +114,7 @@ export default {
105
114
  updateAgent: '更新助理信息',
106
115
  upload: {
107
116
  actionTooltip: '上传图片',
117
+ disabled: '当前模型不支持视觉识别,请切换模型后使用',
108
118
  dragDesc: '拖拽文件到这里,支持上传多个图片。按住 Shift 直接发送图片',
109
119
  dragTitle: '上传图片',
110
120
  },
@@ -1,4 +1,12 @@
1
1
  export default {
2
+ ModelSelect: {
3
+ featureTag: {
4
+ custom: '自定义模型,默认设定同时支持函数调用与视觉识别,请根据实际情况验证上述能力的可用性',
5
+ functionCall: '该模型支持函数调用(Function Call)',
6
+ tokens: '该模型单个会话最多支持 {{tokens}} Tokens',
7
+ vision: '该模型支持视觉识别',
8
+ },
9
+ },
2
10
  about: '关于',
3
11
  advanceSettings: '高级设置',
4
12
  agentMaxToken: '会话最大长度',
@@ -89,6 +97,14 @@ export default {
89
97
  'zh-TW': '繁体中文',
90
98
  },
91
99
  layoutInitializing: '正在加载布局...',
100
+ modelProvider: {
101
+ azure: 'Azure',
102
+ bedrock: 'AWS Bedrock',
103
+ google: 'Google',
104
+ oneapi: 'One API',
105
+ openai: 'OpenAI',
106
+ zhipu: '智谱AI',
107
+ },
92
108
  noDescription: '暂无描述',
93
109
  ok: '确定',
94
110
  password: '密码',
@@ -51,9 +51,26 @@ export default {
51
51
  PluginGatewayError: '很抱歉,插件网关出现错误,请检查插件网关配置是否正确',
52
52
  PluginOpenApiInitError: '很抱歉,OpenAPI 客户端初始化失败,请检查 OpenAPI 的配置信息是否正确',
53
53
 
54
- InvalidAccessCode: '密码不正确或为空,请输入正确的访问密码,或者添加自定义 OpenAI API Key',
54
+ InvalidAccessCode: '密码不正确或为空,请输入正确的访问密码,或者添加自定义 API Key',
55
+ LocationNotSupportError:
56
+ '很抱歉,你的所在位置不支持此模型服务,可能是由于地区限制或服务未开通。请确认当前位置是否支持使用此服务,或尝试使用其他位置信息。',
57
+
55
58
  OpenAIBizError: '请求 OpenAI 服务出错,请根据以下信息排查或重试',
56
- NoAPIKey: 'OpenAI API Key 为空,请添加自定义 OpenAI API Key',
59
+ NoOpenAIAPIKey: 'OpenAI API Key 为空,请添加自定义 OpenAI API Key',
60
+
61
+ ZhipuBizError: '请求智谱服务出错,请根据以下信息排查或重试',
62
+ InvalidZhipuAPIKey: 'Zhipu API Key 不正确或为空,请检查 Zhipu API Key 后重试',
63
+
64
+ GoogleBizError: '请求 Google 服务出错,请根据以下信息排查或重试',
65
+ InvalidGoogleAPIKey: 'Google API Key 不正确或为空,请检查 Google API Key 后重试',
66
+
67
+ InvalidBedrockCredentials: 'Bedrock 鉴权未通过,请检查 AccessKeyId/SecretAccessKey 后重试',
68
+ BedrockBizError: '请求 Bedrock 服务出错,请根据以下信息排查或重试',
69
+
70
+ InvalidAzureAPIKey: 'Azure API Key 不正确或为空,请检查 Azure API Key 后重试',
71
+ AzureBizError: '请求 Azure AI 服务出错,请根据以下信息排查或重试',
72
+
73
+ AgentRuntimeError: 'Lobe 语言模型运行时执行出错,请根据以下信息排查或重试',
57
74
  /* eslint-enable */
58
75
  },
59
76
  stt: {
@@ -64,9 +81,25 @@ export default {
64
81
  },
65
82
  unlock: {
66
83
  apikey: {
67
- addProxyUrl: '添加 OpenAI 代理地址(可选)',
68
- description: '输入你的 OpenAI API Key 即可开始会话。应用不会记录你的 API Key',
69
- title: '使用自定义 API Key',
84
+ Bedrock: {
85
+ customRegion: '自定义服务区域',
86
+ description:
87
+ '输入你的 Aws AccessKeyId / SecretAccessKey 即可开始会话。应用不会记录你的鉴权配置',
88
+ title: '使用自定义 Bedrock 鉴权信息',
89
+ },
90
+ Google: {
91
+ description: '输入你的 Google API Key 即可开始会话。应用不会记录你的 API Key',
92
+ title: '使用自定义 Google API Key',
93
+ },
94
+ OpenAI: {
95
+ addProxyUrl: '添加 OpenAI 代理地址(可选)',
96
+ description: '输入你的 OpenAI API Key 即可开始会话。应用不会记录你的 API Key',
97
+ title: '使用自定义 OpenAI API Key',
98
+ },
99
+ Zhipu: {
100
+ description: '输入你的 Zhipu API Key 即可开始会话。应用不会记录你的 API Key',
101
+ title: '使用自定义 Zhipu API Key',
102
+ },
70
103
  },
71
104
  closeMessage: '关闭提示',
72
105
  confirm: '确认并重试',
@@ -75,5 +108,9 @@ export default {
75
108
  placeholder: '请输入密码',
76
109
  title: '输入密码解锁应用',
77
110
  },
111
+ tabs: {
112
+ apiKey: '自定义 API Key',
113
+ password: '密码',
114
+ },
78
115
  },
79
116
  };
@@ -22,6 +22,16 @@ export default {
22
22
  },
23
23
  llm: {
24
24
  AzureOpenAI: {
25
+ azureApiVersion: {
26
+ desc: 'Azure 的 API 版本,遵循 YYYY-MM-DD 格式,查阅[最新版本](https://learn.microsoft.com/zh-cn/azure/ai-services/openai/reference#chat-completions)',
27
+ fetch: '获取列表',
28
+ title: 'Azure Api Version',
29
+ },
30
+ deployments: {
31
+ desc: '使用 id=name 的语法填写你的部署模型(如部署名和模型同名,可以只填写模型名称),多个模型使用逗号(,) 隔开',
32
+ title: 'Azure 部署模型列表',
33
+ },
34
+
25
35
  endpoint: {
26
36
  desc: '从 Azure 门户检查资源时,可在“密钥和终结点”部分中找到此值',
27
37
  placeholder: 'https://docs-test-001.openai.azure.com',
@@ -31,25 +41,48 @@ export default {
31
41
  desc: '支持的模型',
32
42
  title: '模型列表',
33
43
  },
34
- title: 'Azure OpenAI 设置',
44
+ title: 'Azure OpenAI',
35
45
  token: {
36
46
  desc: '从 Azure 门户检查资源时,可在“密钥和终结点”部分中找到此值。 可以使用 KEY1 或 KEY2',
37
47
  placeholder: 'Azure API Key',
38
48
  title: 'API Key',
39
49
  },
40
50
  },
51
+ Bedrock: {
52
+ accessKeyId: {
53
+ desc: '填入Aws Access Key Id',
54
+ placeholder: 'Aws Access Key Id',
55
+ title: 'Aws Access Key Id',
56
+ },
57
+ checker: {
58
+ desc: '测试 AccessKeyId / SecretAccessKey 是否填写正确',
59
+ },
60
+ region: {
61
+ desc: '填入 Aws Region',
62
+ placeholder: 'Aws Region',
63
+ title: 'Aws Region',
64
+ },
65
+ secretAccessKey: {
66
+ desc: '填入 Aws Secret Access Key',
67
+ placeholder: 'Aws Secret Access Key',
68
+ title: 'Aws Secret Access Key',
69
+ },
70
+ title: 'Bedrock',
71
+ },
72
+ Google: {
73
+ title: 'Google',
74
+ token: {
75
+ desc: '填入来自 Google 的 API Key',
76
+ placeholder: 'Google API Key',
77
+ title: 'API Key',
78
+ },
79
+ },
41
80
  OpenAI: {
42
81
  azureApiVersion: {
43
82
  desc: 'Azure 的 API 版本,遵循 YYYY-MM-DD 格式,查阅[最新版本](https://learn.microsoft.com/zh-cn/azure/ai-services/openai/reference#chat-completions)',
44
83
  fetch: '获取列表',
45
84
  title: 'Azure Api Version',
46
85
  },
47
- check: {
48
- button: '检查',
49
- desc: '测试 Api Key 与代理地址是否正确填写',
50
- pass: '检查通过',
51
- title: '连通性检查',
52
- },
53
86
  customModelName: {
54
87
  desc: '增加自定义模型,多个模型使用逗号(,) 隔开',
55
88
  placeholder: 'model1,model2,model3',
@@ -69,11 +102,11 @@ export default {
69
102
  refetch: '重新获取模型列表',
70
103
  title: '模型列表',
71
104
  },
72
- title: 'OpenAI 设置',
105
+ title: 'OpenAI',
73
106
  token: {
74
107
  desc: '使用自己的 OpenAI Key',
75
108
  placeholder: 'OpenAI API Key',
76
- title: 'API Key',
109
+ title: 'OpenAI API Key',
77
110
  },
78
111
  useAzure: {
79
112
  desc: '使用 Azure 提供的 OpenAI 服务',
@@ -82,6 +115,21 @@ export default {
82
115
  title: 'Azure OpenAI',
83
116
  },
84
117
  },
118
+ Zhipu: {
119
+ title: '智谱',
120
+ token: {
121
+ desc: '填入来自智谱的 API Key',
122
+ placeholder: 'Zhipu API Key',
123
+ title: 'API Key',
124
+ },
125
+ },
126
+
127
+ checker: {
128
+ button: '检查',
129
+ desc: '测试 Api Key 与代理地址是否正确填写',
130
+ pass: '检查通过',
131
+ title: '连通性检查',
132
+ },
85
133
  waitingForMore: '更多模型正在 <1>计划接入</1> 中,敬请期待 ✨',
86
134
  },
87
135
  plugin: {
@@ -291,14 +339,15 @@ export default {
291
339
  },
292
340
  tools: {
293
341
  builtins: {
294
- groupName: '内置扩展',
342
+ groupName: '内置插件',
295
343
  },
344
+ disabled: '当前模型不支持函数调用,无法使用插件',
296
345
  plugins: {
297
346
  enabled: '已启用 {{num}}',
298
- groupName: '插件',
347
+ groupName: '三方插件',
299
348
  noEnabled: '暂无启用插件',
300
349
  store: '插件商店',
301
350
  },
302
- title: '扩展工具',
351
+ title: '扩展插件',
303
352
  },
304
353
  };
@@ -7,9 +7,10 @@ import { useFileStore } from '@/store/file';
7
7
  import { useToolStore } from '@/store/tool';
8
8
  import { DalleManifest } from '@/tools/dalle';
9
9
  import { ChatMessage } from '@/types/message';
10
- import { OpenAIChatStreamPayload } from '@/types/openai/chat';
10
+ import { ChatStreamPayload } from '@/types/openai/chat';
11
11
  import { LobeTool } from '@/types/tool';
12
12
 
13
+ // import { createHeaderWithAuth } from '../_header';
13
14
  import { chatService } from '../chat';
14
15
 
15
16
  // Mocking external dependencies
@@ -23,6 +24,11 @@ vi.mock('@/utils/fetch', () => ({
23
24
  getMessageError: vi.fn(),
24
25
  }));
25
26
 
27
+ // mock auth
28
+ vi.mock('../_auth', () => ({
29
+ createHeaderWithAuth: vi.fn().mockResolvedValue({}),
30
+ }));
31
+
26
32
  describe('ChatService', () => {
27
33
  describe('createAssistantMessage', () => {
28
34
  it('should process messages and call getChatCompletion with the right parameters', async () => {
@@ -531,7 +537,7 @@ Get data from users`,
531
537
 
532
538
  describe('getChatCompletion', () => {
533
539
  it('should make a POST request with the correct payload', async () => {
534
- const params: Partial<OpenAIChatStreamPayload> = {
540
+ const params: Partial<ChatStreamPayload> = {
535
541
  model: 'test-model',
536
542
  messages: [],
537
543
  };
@@ -217,7 +217,7 @@ describe('MessageService', () => {
217
217
  describe('updateMessageError', () => {
218
218
  it('should update the error field of a message', async () => {
219
219
  // Setup
220
- const newError = { type: 'NoAPIKey', message: 'Error occurred' } as ChatMessageError;
220
+ const newError = { type: 'NoOpenAIAPIKey', message: 'Error occurred' } as ChatMessageError;
221
221
  (MessageModel.update as Mock).mockResolvedValue({ ...mockMessage, error: newError });
222
222
 
223
223
  // Execute
@@ -0,0 +1,106 @@
1
+ import { SignJWT, importJWK } from 'jose';
2
+
3
+ import { JWTPayload, JWT_SECRET_KEY, LOBE_CHAT_AUTH_HEADER } from '@/const/auth';
4
+ import { ModelProvider } from '@/libs/agent-runtime';
5
+ import { useGlobalStore } from '@/store/global';
6
+ import { modelProviderSelectors, settingsSelectors } from '@/store/global/selectors';
7
+
8
+ const createJWT = async (payload: JWTPayload) => {
9
+ // 将AccessCode转换成适合作为密钥的格式,例如使用SHA-256进行哈希
10
+ const encoder = new TextEncoder();
11
+ const secretKey = await crypto.subtle.digest('SHA-256', encoder.encode(JWT_SECRET_KEY));
12
+
13
+ // 将密钥导入为JWK格式
14
+ const jwkSecretKey = await importJWK(
15
+ {
16
+ k: Buffer.from(secretKey).toString('base64'),
17
+ kty: 'oct',
18
+ },
19
+ 'HS256',
20
+ );
21
+
22
+ // 获取当前时间戳
23
+ const now = Math.floor(Date.now() / 1000);
24
+
25
+ // 创建JWT
26
+ return new SignJWT(payload as Record<string, any>)
27
+ .setProtectedHeader({ alg: 'HS256' })
28
+ .setIssuedAt(now) // 设置JWT的iat(签发时间)声明
29
+ .setExpirationTime(now + 100) // 设置 JWT 的 exp(过期时间)为 100 s
30
+ .sign(jwkSecretKey);
31
+ };
32
+
33
+ const getProviderAuthPayload = (provider: string) => {
34
+ switch (provider) {
35
+ case ModelProvider.ZhiPu: {
36
+ return { apiKey: modelProviderSelectors.zhipuAPIKey(useGlobalStore.getState()) };
37
+ }
38
+
39
+ case ModelProvider.Google: {
40
+ return { apiKey: modelProviderSelectors.googleAPIKey(useGlobalStore.getState()) };
41
+ }
42
+
43
+ case ModelProvider.Bedrock: {
44
+ const { accessKeyId, region, secretAccessKey } = modelProviderSelectors.bedrockConfig(
45
+ useGlobalStore.getState(),
46
+ );
47
+ const awsSecretAccessKey = secretAccessKey;
48
+ const awsAccessKeyId = accessKeyId;
49
+
50
+ const apiKey = (awsSecretAccessKey || '') + (awsAccessKeyId || '');
51
+
52
+ return { apiKey, awsAccessKeyId, awsRegion: region, awsSecretAccessKey };
53
+ }
54
+
55
+ case ModelProvider.Azure: {
56
+ const azure = modelProviderSelectors.azureConfig(useGlobalStore.getState());
57
+
58
+ return {
59
+ apiKey: azure.apiKey,
60
+ azureApiVersion: azure.apiVersion,
61
+ endpoint: azure.endpoint,
62
+ };
63
+ }
64
+
65
+ default:
66
+ case ModelProvider.OpenAI: {
67
+ const openai = modelProviderSelectors.openAIConfig(useGlobalStore.getState());
68
+ const apiKey = openai.OPENAI_API_KEY || '';
69
+ const endpoint = openai.endpoint || '';
70
+
71
+ return {
72
+ apiKey,
73
+ azureApiVersion: openai.azureApiVersion,
74
+ endpoint,
75
+ useAzure: openai.useAzure,
76
+ };
77
+ }
78
+ }
79
+ };
80
+
81
+ const createAuthTokenWithPayload = async (payload = {}) => {
82
+ const accessCode = settingsSelectors.password(useGlobalStore.getState());
83
+
84
+ return await createJWT({ accessCode, ...payload });
85
+ };
86
+
87
+ interface AuthParams {
88
+ // eslint-disable-next-line no-undef
89
+ headers?: HeadersInit;
90
+ payload?: Record<string, any>;
91
+ provider?: string;
92
+ }
93
+
94
+ // eslint-disable-next-line no-undef
95
+ export const createHeaderWithAuth = async (params?: AuthParams): Promise<HeadersInit> => {
96
+ let payload = params?.payload || {};
97
+
98
+ if (params?.provider) {
99
+ payload = { ...payload, ...getProviderAuthPayload(params?.provider) };
100
+ }
101
+
102
+ const token = await createAuthTokenWithPayload(payload);
103
+
104
+ // eslint-disable-next-line no-undef
105
+ return { ...params?.headers, [LOBE_CHAT_AUTH_HEADER]: token };
106
+ };
@@ -8,6 +8,7 @@ import {
8
8
  import { useGlobalStore } from '@/store/global';
9
9
  import { modelProviderSelectors, settingsSelectors } from '@/store/global/selectors';
10
10
 
11
+ // TODO: Need to be removed after tts refactor
11
12
  // eslint-disable-next-line no-undef
12
13
  export const createHeaderWithOpenAI = (header?: HeadersInit): HeadersInit => {
13
14
  const openai = modelProviderSelectors.openAIConfig(useGlobalStore.getState());
@@ -10,9 +10,7 @@ export const PLUGINS_URLS = {
10
10
  };
11
11
 
12
12
  export const OPENAI_URLS = {
13
- chat: '/api/openai/chat',
14
13
  images: '/api/openai/images',
15
- models: '/api/openai/models',
16
14
  stt: '/api/openai/stt',
17
15
  tts: '/api/openai/tts',
18
16
  };