@lobehub/chat 0.122.9 → 0.123.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +22 -2
- package/.eslintrc.js +1 -0
- package/CHANGELOG.md +59 -0
- package/Dockerfile +7 -1
- package/README.md +12 -10
- package/README.zh-CN.md +12 -10
- package/docs/Deployment/Docker-Deployment.md +1 -1
- package/docs/Deployment/Docker-Deployment.zh-CN.md +1 -1
- package/docs/Deployment/Environment-Variable.md +65 -23
- package/docs/Deployment/Environment-Variable.zh-CN.md +64 -22
- package/locales/ar/chat.json +12 -1
- package/locales/ar/common.json +16 -0
- package/locales/ar/error.json +35 -6
- package/locales/ar/setting.json +53 -6
- package/locales/de-DE/chat.json +12 -1
- package/locales/de-DE/common.json +16 -0
- package/locales/de-DE/error.json +35 -6
- package/locales/de-DE/setting.json +53 -6
- package/locales/en-US/chat.json +13 -2
- package/locales/en-US/common.json +16 -0
- package/locales/en-US/error.json +35 -6
- package/locales/en-US/setting.json +53 -6
- package/locales/es-ES/chat.json +12 -1
- package/locales/es-ES/common.json +16 -0
- package/locales/es-ES/error.json +35 -6
- package/locales/es-ES/setting.json +53 -6
- package/locales/fr-FR/chat.json +13 -2
- package/locales/fr-FR/common.json +16 -0
- package/locales/fr-FR/error.json +35 -6
- package/locales/fr-FR/setting.json +53 -6
- package/locales/it-IT/chat.json +12 -1
- package/locales/it-IT/common.json +16 -0
- package/locales/it-IT/error.json +35 -6
- package/locales/it-IT/setting.json +53 -6
- package/locales/ja-JP/chat.json +12 -1
- package/locales/ja-JP/common.json +16 -0
- package/locales/ja-JP/error.json +35 -6
- package/locales/ja-JP/setting.json +53 -6
- package/locales/ko-KR/chat.json +12 -1
- package/locales/ko-KR/common.json +16 -0
- package/locales/ko-KR/error.json +35 -6
- package/locales/ko-KR/setting.json +53 -6
- package/locales/nl-NL/chat.json +12 -1
- package/locales/nl-NL/common.json +16 -0
- package/locales/nl-NL/error.json +35 -6
- package/locales/nl-NL/setting.json +53 -6
- package/locales/pl-PL/chat.json +12 -1
- package/locales/pl-PL/common.json +16 -0
- package/locales/pl-PL/error.json +35 -6
- package/locales/pl-PL/setting.json +53 -6
- package/locales/pt-BR/chat.json +12 -1
- package/locales/pt-BR/common.json +16 -0
- package/locales/pt-BR/error.json +35 -6
- package/locales/pt-BR/setting.json +53 -6
- package/locales/ru-RU/chat.json +12 -1
- package/locales/ru-RU/common.json +16 -0
- package/locales/ru-RU/error.json +35 -6
- package/locales/ru-RU/setting.json +53 -6
- package/locales/tr-TR/chat.json +12 -1
- package/locales/tr-TR/common.json +16 -0
- package/locales/tr-TR/error.json +35 -6
- package/locales/tr-TR/setting.json +53 -6
- package/locales/vi-VN/chat.json +12 -1
- package/locales/vi-VN/common.json +16 -0
- package/locales/vi-VN/error.json +35 -6
- package/locales/vi-VN/setting.json +53 -6
- package/locales/zh-CN/chat.json +12 -1
- package/locales/zh-CN/common.json +16 -0
- package/locales/zh-CN/error.json +34 -5
- package/locales/zh-CN/setting.json +59 -12
- package/locales/zh-TW/chat.json +12 -1
- package/locales/zh-TW/common.json +16 -0
- package/locales/zh-TW/error.json +35 -6
- package/locales/zh-TW/setting.json +53 -6
- package/next.config.mjs +8 -2
- package/package.json +8 -2
- package/src/app/api/chat/[provider]/agentRuntime.ts +129 -0
- package/src/app/api/chat/[provider]/route.ts +64 -0
- package/src/app/api/chat/auth.ts +42 -0
- package/src/app/api/chat/google/route.ts +86 -0
- package/src/app/api/config/route.ts +6 -1
- package/src/app/api/config.ts +3 -3
- package/src/app/api/errorResponse.test.ts +8 -8
- package/src/app/api/errorResponse.ts +43 -6
- package/src/app/api/openai/createBizOpenAI/createAzureOpenai.ts +1 -1
- package/src/app/api/openai/createBizOpenAI/createOpenai.ts +1 -1
- package/src/app/api/openai/createBizOpenAI/index.ts +2 -2
- package/src/app/api/plugin/gateway/route.ts +4 -1
- package/src/app/chat/(desktop)/features/ChatHeader.tsx +6 -4
- package/src/app/chat/(desktop)/features/ChatInput/Footer/index.tsx +13 -3
- package/src/app/chat/(desktop)/features/ChatInput/Header/index.tsx +16 -24
- package/src/app/chat/(desktop)/features/SideBar/index.tsx +1 -0
- package/src/app/chat/features/ChatHeader/ShareButton/Preview.tsx +3 -3
- package/src/app/chat/features/SessionListContent/List/Item/index.tsx +2 -3
- package/src/app/settings/llm/Azure/index.tsx +145 -0
- package/src/app/settings/llm/Bedrock/index.tsx +109 -0
- package/src/app/settings/llm/{LLM/Checker.tsx → Checker.tsx} +11 -14
- package/src/app/settings/llm/Google/index.tsx +74 -0
- package/src/app/settings/llm/{LLM → OpenAI}/index.tsx +26 -44
- package/src/app/settings/llm/Zhipu/index.tsx +78 -0
- package/src/app/settings/llm/const.ts +13 -0
- package/src/app/settings/llm/page.tsx +42 -2
- package/src/app/settings/llm/useSyncSettings.ts +23 -0
- package/src/chains/__tests__/langDetect.test.ts +2 -2
- package/src/chains/__tests__/pickEmoji.test.ts +2 -2
- package/src/chains/langDetect.ts +2 -2
- package/src/chains/pickEmoji.ts +2 -2
- package/src/chains/summaryAgentName.ts +2 -2
- package/src/chains/summaryDescription.ts +2 -2
- package/src/chains/summaryTags.ts +2 -2
- package/src/chains/summaryTitle.ts +2 -2
- package/src/chains/translate.ts +2 -2
- package/src/components/ModelIcon/index.tsx +37 -0
- package/src/components/ModelProviderIcon/index.tsx +44 -0
- package/src/components/ModelSelect/index.tsx +133 -0
- package/src/components/ModelTag/ModelIcon.tsx +35 -0
- package/src/components/ModelTag/index.tsx +13 -0
- package/src/config/modelProviders/bedrock.ts +43 -0
- package/src/config/modelProviders/google.ts +20 -0
- package/src/config/modelProviders/index.ts +18 -0
- package/src/config/modelProviders/openai.ts +110 -0
- package/src/config/modelProviders/zhipu.ts +34 -0
- package/src/config/{server.ts → server/app.ts} +1 -24
- package/src/config/server/index.ts +13 -0
- package/src/config/server/provider.ts +78 -0
- package/src/const/auth.ts +30 -0
- package/src/const/fetch.ts +3 -0
- package/src/const/settings.ts +24 -4
- package/src/database/core/migrations/migrateSettingsToUser/index.test.ts +2 -1
- package/src/database/core/migrations/migrateSettingsToUser/index.ts +1 -18
- package/src/database/core/migrations/migrateSettingsToUser/type.ts +100 -0
- package/src/database/models/message.ts +3 -1
- package/src/database/schemas/message.ts +1 -0
- package/src/database/schemas/session.ts +1 -0
- package/src/features/AgentSetting/AgentConfig/ModelSelect.tsx +71 -0
- package/src/features/AgentSetting/AgentConfig/index.tsx +171 -161
- package/src/features/AgentSetting/AgentConfig/useSyncConfig.ts +23 -0
- package/src/features/AgentSetting/AgentPrompt/TokenTag.tsx +39 -0
- package/src/features/AgentSetting/AgentPrompt/index.tsx +4 -26
- package/src/features/AgentSetting/store/index.ts +10 -2
- package/src/features/ChatInput/ActionBar/FileUpload.tsx +15 -5
- package/src/features/ChatInput/ActionBar/ModelSwitch.tsx +56 -14
- package/src/features/ChatInput/ActionBar/Token/TokenTag.tsx +42 -7
- package/src/features/ChatInput/ActionBar/Token/index.tsx +5 -2
- package/src/features/ChatInput/ActionBar/Tools/index.tsx +11 -1
- package/src/features/ChatInput/useChatInput.ts +5 -1
- package/src/features/Conversation/Error/APIKeyForm/Bedrock.tsx +80 -0
- package/src/features/Conversation/Error/APIKeyForm/Google.tsx +61 -0
- package/src/features/Conversation/Error/APIKeyForm/OpenAI.tsx +63 -0
- package/src/features/Conversation/Error/APIKeyForm/Zhipu.tsx +62 -0
- package/src/features/Conversation/Error/APIKeyForm/index.tsx +72 -0
- package/src/features/Conversation/Error/AccessCodeForm.tsx +63 -0
- package/src/features/Conversation/Error/ErrorJsonViewer.tsx +26 -0
- package/src/features/Conversation/Error/InvalidAPIKey.tsx +16 -0
- package/src/features/Conversation/Error/InvalidAccessCode.tsx +50 -0
- package/src/features/Conversation/Error/OpenAiBizError.tsx +9 -17
- package/src/features/Conversation/Error/{Plugin/PluginSettings.tsx → PluginSettings.tsx} +8 -3
- package/src/features/Conversation/Error/index.tsx +75 -70
- package/src/features/Conversation/Error/style.tsx +9 -3
- package/src/features/Conversation/Extras/Assistant.tsx +2 -3
- package/src/features/Conversation/Plugins/Inspector/index.tsx +8 -2
- package/src/features/Conversation/components/ChatItem/index.tsx +9 -24
- package/src/features/Conversation/types/index.tsx +2 -5
- package/src/hooks/_header.ts +35 -0
- package/src/libs/agent-runtime/BaseAI.ts +9 -0
- package/src/libs/agent-runtime/azureOpenai/index.ts +72 -0
- package/src/libs/agent-runtime/bedrock/index.ts +134 -0
- package/src/libs/agent-runtime/error.ts +26 -0
- package/src/libs/agent-runtime/google/index.ts +160 -0
- package/src/libs/agent-runtime/index.ts +9 -0
- package/src/libs/agent-runtime/openai/index.test.ts +176 -0
- package/src/libs/agent-runtime/openai/index.ts +107 -0
- package/src/libs/agent-runtime/types/chat.ts +119 -0
- package/src/libs/agent-runtime/types/index.ts +2 -0
- package/src/libs/agent-runtime/types/type.ts +34 -0
- package/src/libs/agent-runtime/utils/createError.ts +10 -0
- package/src/libs/agent-runtime/utils/debugStream.ts +18 -0
- package/src/libs/agent-runtime/utils/env.ts +1 -0
- package/src/libs/agent-runtime/utils/handleOpenAIError.ts +39 -0
- package/src/libs/agent-runtime/utils/uriParser.ts +16 -0
- package/src/libs/agent-runtime/zhipu/authToken.ts +22 -0
- package/src/libs/agent-runtime/zhipu/index.ts +125 -0
- package/src/locales/default/chat.ts +12 -2
- package/src/locales/default/common.ts +16 -0
- package/src/locales/default/error.ts +42 -5
- package/src/locales/default/setting.ts +61 -12
- package/src/services/__tests__/chat.test.ts +8 -2
- package/src/services/__tests__/message.test.ts +1 -1
- package/src/services/_auth.ts +106 -0
- package/src/services/_header.ts +1 -0
- package/src/services/_url.ts +0 -2
- package/src/services/chat.ts +34 -14
- package/src/store/chat/slices/message/action.ts +9 -6
- package/src/store/global/slices/common/action.ts +8 -2
- package/src/store/global/slices/settings/action.test.ts +2 -2
- package/src/store/global/slices/settings/action.ts +11 -4
- package/src/store/global/slices/settings/selectors/__snapshots__/modelProvider.test.ts.snap +24 -92
- package/src/store/global/slices/settings/selectors/__snapshots__/selectors.test.ts.snap +2 -0
- package/src/store/global/slices/settings/selectors/modelProvider.test.ts +127 -50
- package/src/store/global/slices/settings/selectors/modelProvider.ts +145 -43
- package/src/store/session/slices/agent/selectors.test.ts +0 -48
- package/src/store/session/slices/agent/selectors.ts +7 -12
- package/src/types/agent/index.ts +6 -2
- package/src/types/fetch.ts +4 -2
- package/src/types/files.ts +3 -3
- package/src/types/llm.ts +34 -0
- package/src/types/message/index.ts +7 -3
- package/src/types/openai/chat.ts +6 -11
- package/src/types/settings/index.ts +1 -0
- package/src/types/settings/modelProvider.ts +37 -1
- package/src/utils/__snapshots__/parseModels.test.ts.snap +63 -0
- package/src/utils/parseModels.test.ts +24 -0
- package/src/utils/parseModels.ts +37 -0
- package/src/app/api/openai/chat/createChatCompletion.test.ts +0 -166
- package/src/app/api/openai/chat/createChatCompletion.ts +0 -76
- package/src/app/api/openai/chat/route.ts +0 -19
- package/src/app/api/openai/models/route.ts +0 -17
- package/src/app/settings/llm/LLM/ModelList.tsx +0 -51
- package/src/app/settings/llm/LLM/getModelList.ts +0 -9
- package/src/app/settings/llm/index.tsx +0 -36
- package/src/const/llm.ts +0 -32
- package/src/features/Conversation/Error/ApiKeyForm.tsx +0 -87
- package/src/features/Conversation/Error/ErrorActionContainer.tsx +0 -23
- package/src/features/Conversation/Error/InvalidAccess.tsx +0 -90
- package/src/features/Conversation/Error/OpenAPIKey.tsx +0 -13
- package/src/features/Conversation/Error/Plugin/PluginError.tsx +0 -30
- package/src/services/modelList.ts +0 -15
- /package/src/app/chat/(desktop)/features/ChatInput/{Header → Footer}/DragUpload.tsx +0 -0
- /package/src/{app/api/openai/chat → libs/agent-runtime/utils}/desensitizeUrl.test.ts +0 -0
- /package/src/{app/api/openai/chat → libs/agent-runtime/utils}/desensitizeUrl.ts +0 -0
- /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
|
-
|
|
70
|
-
|
|
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: '密码不正确或为空,请输入正确的访问密码,或者添加自定义
|
|
54
|
+
InvalidAccessCode: '密码不正确或为空,请输入正确的访问密码,或者添加自定义 API Key',
|
|
55
|
+
LocationNotSupportError:
|
|
56
|
+
'很抱歉,你的所在位置不支持此模型服务,可能是由于地区限制或服务未开通。请确认当前位置是否支持使用此服务,或尝试使用其他位置信息。',
|
|
57
|
+
|
|
55
58
|
OpenAIBizError: '请求 OpenAI 服务出错,请根据以下信息排查或重试',
|
|
56
|
-
|
|
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
|
-
|
|
68
|
-
|
|
69
|
-
|
|
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 {
|
|
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<
|
|
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: '
|
|
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
|
+
};
|
package/src/services/_header.ts
CHANGED
|
@@ -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());
|
package/src/services/_url.ts
CHANGED