@lobehub/chat 0.123.2 → 0.123.4
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 +3 -3
- package/CHANGELOG.md +50 -0
- package/Dockerfile +1 -1
- package/README.md +8 -10
- package/README.zh-CN.md +8 -10
- package/docs/Deployment/Environment-Variable.md +3 -2
- package/docs/Deployment/Environment-Variable.zh-CN.md +3 -2
- package/package.json +2 -1
- package/src/app/api/chat/[provider]/route.ts +7 -5
- package/src/app/api/chat/auth.ts +13 -2
- package/src/app/api/errorResponse.ts +9 -11
- package/src/components/ModelProviderIcon/index.tsx +4 -1
- package/src/config/modelProviders/openai.ts +3 -0
- package/src/const/auth.ts +1 -0
- package/src/features/ChatInput/ActionBar/Clear.tsx +10 -5
- package/src/features/Conversation/Error/index.tsx +2 -7
- package/src/layout/GlobalLayout/Locale.tsx +1 -0
- package/src/libs/agent-runtime/error.ts +3 -4
- package/src/services/_auth.ts +3 -29
- package/src/store/global/slices/settings/selectors/__snapshots__/modelProvider.test.ts.snap +1 -0
- package/src/store/global/slices/settings/selectors/modelProvider.test.ts +57 -0
- package/src/store/global/slices/settings/selectors/modelProvider.ts +19 -17
- package/src/utils/jwt.test.ts +26 -0
- package/src/utils/jwt.ts +37 -0
package/.env.example
CHANGED
|
@@ -40,13 +40,13 @@ OPENAI_API_KEY=sk-xxxxxxxxx
|
|
|
40
40
|
#ZHIPU_API_KEY=xxxxxxxxxxxxxxxxxxx.xxxxxxxxxxxxx
|
|
41
41
|
|
|
42
42
|
########################################
|
|
43
|
-
|
|
43
|
+
########### Google AI Service ##########
|
|
44
44
|
########################################
|
|
45
45
|
|
|
46
|
-
#GOOGLE_API_KEY=
|
|
46
|
+
#GOOGLE_API_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
|
47
47
|
|
|
48
48
|
########################################
|
|
49
|
-
|
|
49
|
+
######### AWS Bedrock Service ##########
|
|
50
50
|
########################################
|
|
51
51
|
|
|
52
52
|
#AWS_REGION=us-east-1
|
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,56 @@
|
|
|
2
2
|
|
|
3
3
|
# Changelog
|
|
4
4
|
|
|
5
|
+
### [Version 0.123.4](https://github.com/lobehub/lobe-chat/compare/v0.123.3...v0.123.4)
|
|
6
|
+
|
|
7
|
+
<sup>Released on **2024-02-06**</sup>
|
|
8
|
+
|
|
9
|
+
#### 💄 Styles
|
|
10
|
+
|
|
11
|
+
- **misc**: Improve clear topic tips.
|
|
12
|
+
|
|
13
|
+
<br/>
|
|
14
|
+
|
|
15
|
+
<details>
|
|
16
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
|
17
|
+
|
|
18
|
+
#### Styles
|
|
19
|
+
|
|
20
|
+
- **misc**: Improve clear topic tips, closes [#1247](https://github.com/lobehub/lobe-chat/issues/1247) ([2d133e9](https://github.com/lobehub/lobe-chat/commit/2d133e9))
|
|
21
|
+
|
|
22
|
+
</details>
|
|
23
|
+
|
|
24
|
+
<div align="right">
|
|
25
|
+
|
|
26
|
+
[](#readme-top)
|
|
27
|
+
|
|
28
|
+
</div>
|
|
29
|
+
|
|
30
|
+
### [Version 0.123.3](https://github.com/lobehub/lobe-chat/compare/v0.123.2...v0.123.3)
|
|
31
|
+
|
|
32
|
+
<sup>Released on **2024-02-06**</sup>
|
|
33
|
+
|
|
34
|
+
#### 🐛 Bug Fixes
|
|
35
|
+
|
|
36
|
+
- **misc**: Fix non-https `crypto.subtile` missing error.
|
|
37
|
+
|
|
38
|
+
<br/>
|
|
39
|
+
|
|
40
|
+
<details>
|
|
41
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
|
42
|
+
|
|
43
|
+
#### What's fixed
|
|
44
|
+
|
|
45
|
+
- **misc**: Fix non-https `crypto.subtile` missing error, closes [#1238](https://github.com/lobehub/lobe-chat/issues/1238) ([1750d0b](https://github.com/lobehub/lobe-chat/commit/1750d0b))
|
|
46
|
+
|
|
47
|
+
</details>
|
|
48
|
+
|
|
49
|
+
<div align="right">
|
|
50
|
+
|
|
51
|
+
[](#readme-top)
|
|
52
|
+
|
|
53
|
+
</div>
|
|
54
|
+
|
|
5
55
|
### [Version 0.123.2](https://github.com/lobehub/lobe-chat/compare/v0.123.1...v0.123.2)
|
|
6
56
|
|
|
7
57
|
<sup>Released on **2024-02-06**</sup>
|
package/Dockerfile
CHANGED
package/README.md
CHANGED
|
@@ -225,16 +225,14 @@ Our marketplace is not just a showcase platform but also a collaborative space.
|
|
|
225
225
|
|
|
226
226
|
<!-- AGENT LIST -->
|
|
227
227
|
|
|
228
|
-
| Recent Submits
|
|
229
|
-
|
|
|
230
|
-
| [
|
|
231
|
-
|
|
|
232
|
-
|
|
|
233
|
-
| [
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
> 📊 Total agents: [<kbd>**149**</kbd> ](https://github.com/lobehub/lobe-chat-agents)
|
|
228
|
+
| Recent Submits | Description |
|
|
229
|
+
| ----------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
230
|
+
| [CAN: Code Master](https://chat-preview.lobehub.com/market?agent=can)<br/><sup>By **[MrHuangJser](https://github.com/MrHuangJser)** on **2024-02-06**</sup> | CAN: Professional coding expert with years of experience and no character limit. Provides entrepreneurial services such as creative naming, slogans, user profiles, pain points, value propositions, sales channels, revenue streams, and cost structures.<br/>`coding` `communication` `questioning` |
|
|
231
|
+
| [Database Expert](https://chat-preview.lobehub.com/market?agent=dba)<br/><sup>By **[xuzhen1994](https://github.com/xuzhen1994)** on **2024-02-03**</sup> | Provides professional advice on database design paradigms, index optimization, query performance tuning, data security, backup and recovery.<br/>`database` `dba` `mysql` `clickhouse` `doris` `mongo-db` `oracle` |
|
|
232
|
+
| [Presentation Wizard](https://chat-preview.lobehub.com/market?agent=word)<br/><sup>By **[MYSeaIT](https://github.com/MYSeaIT)** on **2024-02-03**</sup> | App Presentation Maker Bot for Word: Assists in creating impressive and professional app presentations in Microsoft Word.<br/>`app-presentation` `microsoft-word` `bot` `assistance` `template` |
|
|
233
|
+
| [SagePathfinder](https://chat-preview.lobehub.com/market?agent=sage-pathfinder)<br/><sup>By **[Ajasra](https://github.com/Ajasra)** on **2024-01-31**</sup> | Expert in personal growth coaching with a focus on stoicism, deep reflection, and strategic questioning.<br/>`personal-growth` `coaching` `reflection` `goal-setting` `well-being` |
|
|
234
|
+
|
|
235
|
+
> 📊 Total agents: [<kbd>**150**</kbd> ](https://github.com/lobehub/lobe-chat-agents)
|
|
238
236
|
|
|
239
237
|
<!-- AGENT LIST -->
|
|
240
238
|
|
package/README.zh-CN.md
CHANGED
|
@@ -205,16 +205,14 @@ LobeChat 的插件生态系统是其核心功能的重要扩展,它极大地
|
|
|
205
205
|
|
|
206
206
|
<!-- AGENT LIST -->
|
|
207
207
|
|
|
208
|
-
| 最近新增
|
|
209
|
-
|
|
|
210
|
-
| [
|
|
211
|
-
|
|
|
212
|
-
|
|
|
213
|
-
| [
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
> 📊 Total agents: [<kbd>**149**</kbd> ](https://github.com/lobehub/lobe-chat-agents)
|
|
208
|
+
| 最近新增 | 助手说明 |
|
|
209
|
+
| ----------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
210
|
+
| [CAN: 编程大师](https://chat-preview.lobehub.com/market?agent=can)<br/><sup>By **[MrHuangJser](https://github.com/MrHuangJser)** on **2024-02-06**</sup> | CAN: 专业编程专家,多年经验,无字符限制。提供创意命名、标语、用户画像、痛点、价值主张、销售渠道、收入流、成本结构等创业计划服务。<br/>`编程` `交流` `提问` |
|
|
211
|
+
| [数据库专家](https://chat-preview.lobehub.com/market?agent=dba)<br/><sup>By **[xuzhen1994](https://github.com/xuzhen1994)** on **2024-02-03**</sup> | 提供关于数据库设计范式、索引优化、查询性能调优、数据安全、备份与恢复等方面的专业建议<br/>`数据库` `dba` `mysql` `clickhouse` `doris` `mongo-db` `oracle` |
|
|
212
|
+
| [演示向导](https://chat-preview.lobehub.com/market?agent=word)<br/><sup>By **[MYSeaIT](https://github.com/MYSeaIT)** on **2024-02-03**</sup> | Word 应用演示制作机器人:帮助在 Microsoft Word 中创建令人印象深刻和专业的应用程序演示。<br/>`应用程序演示` `微软-word` `机器人` `辅助` `模板` |
|
|
213
|
+
| [SagePathfinder](https://chat-preview.lobehub.com/market?agent=sage-pathfinder)<br/><sup>By **[Ajasra](https://github.com/Ajasra)** on **2024-01-31**</sup> | 专注于斯多葛主义、深度反思和战略性提问的个人成长教练专家。<br/>`个人成长` `教练` `反思` `目标设定` `幸福感` |
|
|
214
|
+
|
|
215
|
+
> 📊 Total agents: [<kbd>**150**</kbd> ](https://github.com/lobehub/lobe-chat-agents)
|
|
218
216
|
|
|
219
217
|
<!-- AGENT LIST -->
|
|
220
218
|
|
|
@@ -8,7 +8,6 @@ LobeChat provides additional configuration options during deployment, which can
|
|
|
8
8
|
- [`ACCESS_CODE`](#access_code)
|
|
9
9
|
- [Model Service Providers](#model-service-providers)
|
|
10
10
|
- [OpenAI](#openai)
|
|
11
|
-
- [`CUSTOM_MODELS`](#custom_models)
|
|
12
11
|
- [Azure OpenAI](#azure-openai)
|
|
13
12
|
- [Zhipu AI](#zhipu-ai)
|
|
14
13
|
- [Google AI](#google-ai)
|
|
@@ -62,7 +61,7 @@ Related discussions:
|
|
|
62
61
|
- [Reasons for errors when using third-party interfaces](https://github.com/lobehub/lobe-chat/discussions/734)
|
|
63
62
|
- [No response when filling in the proxy server address for chatting](https://github.com/lobehub/lobe-chat/discussions/1065)
|
|
64
63
|
|
|
65
|
-
|
|
64
|
+
#### `CUSTOM_MODELS`
|
|
66
65
|
|
|
67
66
|
- Type: Optional
|
|
68
67
|
- Description: Used to control the model list. Use `+` to add a model, `-` to hide a model, and `model_name=display_name` to customize the display name of a model, separated by commas.
|
|
@@ -71,6 +70,8 @@ Related discussions:
|
|
|
71
70
|
|
|
72
71
|
The above example adds `qwen-7b-chat` and `glm-6b` to the model list, removes `gpt-3.5-turbo` from the list, and displays the model name `gpt-4-0125-preview` as `gpt-4-turbo`. If you want to disable all models first and then enable specific models, you can use `-all,+gpt-3.5-turbo`, which means only `gpt-3.5-turbo` will be enabled.
|
|
73
72
|
|
|
73
|
+
You can find all current model names in [modelProviders](https://github.com/lobehub/lobe-chat/tree/main/src/config/modelProviders).
|
|
74
|
+
|
|
74
75
|
### Azure OpenAI
|
|
75
76
|
|
|
76
77
|
If you need to use Azure OpenAI to provide model services, you can refer to the [Deploy with Azure OpenAI](Deploy-with-Azure-OpenAI.zh-CN.md) section for detailed steps. Here are the environment variables related to Azure OpenAI.
|
|
@@ -8,7 +8,6 @@ LobeChat 在部署时提供了一些额外的配置项,使用环境变量进
|
|
|
8
8
|
- [`ACCESS_CODE`](#access_code)
|
|
9
9
|
- [模型服务商](#模型服务商)
|
|
10
10
|
- [OpenAI](#openai)
|
|
11
|
-
- [`CUSTOM_MODELS`](#custom_models)
|
|
12
11
|
- [Azure OpenAI](#azure-openai)
|
|
13
12
|
- [智谱 AI](#智谱-ai)
|
|
14
13
|
- [Google AI](#google-ai)
|
|
@@ -62,7 +61,7 @@ LobeChat 在部署时提供了一些额外的配置项,使用环境变量进
|
|
|
62
61
|
- [使用第三方接口报错的原因](https://github.com/lobehub/lobe-chat/discussions/734)
|
|
63
62
|
- [代理服务器地址填了聊天没任何反应](https://github.com/lobehub/lobe-chat/discussions/1065)
|
|
64
63
|
|
|
65
|
-
|
|
64
|
+
#### `CUSTOM_MODELS`
|
|
66
65
|
|
|
67
66
|
- 类型:可选
|
|
68
67
|
- 描述:用来控制模型列表,使用 `+` 增加一个模型,使用 `-` 来隐藏一个模型,使用 `模型名=展示名` 来自定义模型的展示名,用英文逗号隔开。
|
|
@@ -71,6 +70,8 @@ LobeChat 在部署时提供了一些额外的配置项,使用环境变量进
|
|
|
71
70
|
|
|
72
71
|
上面示例表示增加 `qwen-7b-chat` 和 `glm-6b` 到模型列表,而从列表中删除 `gpt-3.5-turbo`,并将 `gpt-4-0125-preview` 模型名字展示为 `gpt-4-turbo`。如果你想先禁用所有模型,再启用指定模型,可以使用 `-all,+gpt-3.5-turbo`,则表示仅启用 `gpt-3.5-turbo`。
|
|
73
72
|
|
|
73
|
+
你可以在 [modelProviders](https://github.com/lobehub/lobe-chat/tree/main/src/config/modelProviders) 查找到当前的所有模型名。
|
|
74
|
+
|
|
74
75
|
### Azure OpenAI
|
|
75
76
|
|
|
76
77
|
如果你需要使用 Azure OpenAI 来提供模型服务,可以查阅 [使用 Azure OpenAI 部署](Deploy-with-Azure-OpenAI.zh-CN.md) 章节查看详细步骤,这里将列举和 Azure OpenAI 相关的环境变量。
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lobehub/chat",
|
|
3
|
-
"version": "0.123.
|
|
3
|
+
"version": "0.123.4",
|
|
4
4
|
"description": "Lobe Chat - an open-source, high-performance chatbot framework that supports speech synthesis, multimodal, and extensible Function Call plugin system. Supports one-click free deployment of your private ChatGPT/LLM web application.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"framework",
|
|
@@ -145,6 +145,7 @@
|
|
|
145
145
|
"@lobehub/lint": "latest",
|
|
146
146
|
"@next/bundle-analyzer": "^14",
|
|
147
147
|
"@next/eslint-plugin-next": "^14",
|
|
148
|
+
"@peculiar/webcrypto": "^1.4.5",
|
|
148
149
|
"@testing-library/jest-dom": "^6",
|
|
149
150
|
"@testing-library/react": "^14",
|
|
150
151
|
"@types/chroma-js": "^2",
|
|
@@ -40,11 +40,13 @@ export const POST = async (req: Request, { params }: { params: { provider: strin
|
|
|
40
40
|
} catch (e) {
|
|
41
41
|
// if catch the error, just return it
|
|
42
42
|
const err = e as AgentInitErrorPayload;
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
43
|
+
return createErrorResponse(
|
|
44
|
+
(err.errorType || ChatErrorType.InternalServerError) as ILobeAgentRuntimeErrorType,
|
|
45
|
+
{
|
|
46
|
+
error: err.error || e,
|
|
47
|
+
provider: params.provider,
|
|
48
|
+
},
|
|
49
|
+
);
|
|
48
50
|
}
|
|
49
51
|
|
|
50
52
|
// ============ 2. create chat completion ============ //
|
package/src/app/api/chat/auth.ts
CHANGED
|
@@ -1,11 +1,22 @@
|
|
|
1
1
|
import { importJWK, jwtVerify } from 'jose';
|
|
2
2
|
|
|
3
3
|
import { getServerConfig } from '@/config/server';
|
|
4
|
-
import { JWTPayload, JWT_SECRET_KEY } from '@/const/auth';
|
|
4
|
+
import { JWTPayload, JWT_SECRET_KEY, NON_HTTP_PREFIX } from '@/const/auth';
|
|
5
5
|
import { AgentRuntimeError } from '@/libs/agent-runtime';
|
|
6
6
|
import { ChatErrorType } from '@/types/fetch';
|
|
7
7
|
|
|
8
|
-
export const getJWTPayload = async (token: string) => {
|
|
8
|
+
export const getJWTPayload = async (token: string): Promise<JWTPayload> => {
|
|
9
|
+
//如果是 HTTP 协议发起的请求,直接解析 token
|
|
10
|
+
// 这是一个非常 hack 的解决方案,未来要找更好的解决方案来处理这个问题
|
|
11
|
+
// refs: https://github.com/lobehub/lobe-chat/pull/1238
|
|
12
|
+
if (token.startsWith(NON_HTTP_PREFIX)) {
|
|
13
|
+
const jwtParts = token.split('.');
|
|
14
|
+
|
|
15
|
+
const payload = jwtParts[1];
|
|
16
|
+
|
|
17
|
+
return JSON.parse(atob(payload));
|
|
18
|
+
}
|
|
19
|
+
|
|
9
20
|
const encoder = new TextEncoder();
|
|
10
21
|
const secretKey = await crypto.subtle.digest('SHA-256', encoder.encode(JWT_SECRET_KEY));
|
|
11
22
|
|
|
@@ -1,16 +1,13 @@
|
|
|
1
|
-
import { consola } from 'consola';
|
|
2
|
-
|
|
3
1
|
import { AgentRuntimeErrorType, ILobeAgentRuntimeErrorType } from '@/libs/agent-runtime';
|
|
4
|
-
import {
|
|
2
|
+
import { ErrorResponse, ErrorType } from '@/types/fetch';
|
|
5
3
|
|
|
6
4
|
const getStatus = (errorType: ILobeAgentRuntimeErrorType | ErrorType) => {
|
|
5
|
+
// InvalidAccessCode / InvalidAzureAPIKey / InvalidOpenAIAPIKey / InvalidZhipuAPIKey ....
|
|
6
|
+
if (errorType.toString().includes('Invalid')) return 401;
|
|
7
|
+
|
|
7
8
|
switch (errorType) {
|
|
8
|
-
|
|
9
|
-
case AgentRuntimeErrorType.NoOpenAIAPIKey:
|
|
10
|
-
case AgentRuntimeErrorType.InvalidAzureAPIKey:
|
|
11
|
-
case AgentRuntimeErrorType.InvalidBedrockCredentials:
|
|
12
|
-
case AgentRuntimeErrorType.InvalidZhipuAPIKey:
|
|
13
|
-
case AgentRuntimeErrorType.InvalidGoogleAPIKey: {
|
|
9
|
+
// TODO: Need to refactor to Invalid OpenAI API Key
|
|
10
|
+
case AgentRuntimeErrorType.NoOpenAIAPIKey: {
|
|
14
11
|
return 401;
|
|
15
12
|
}
|
|
16
13
|
|
|
@@ -38,7 +35,8 @@ const getStatus = (errorType: ILobeAgentRuntimeErrorType | ErrorType) => {
|
|
|
38
35
|
return 475;
|
|
39
36
|
}
|
|
40
37
|
}
|
|
41
|
-
|
|
38
|
+
|
|
39
|
+
return errorType as number;
|
|
42
40
|
};
|
|
43
41
|
|
|
44
42
|
export const createErrorResponse = (
|
|
@@ -50,7 +48,7 @@ export const createErrorResponse = (
|
|
|
50
48
|
const data: ErrorResponse = { body, errorType };
|
|
51
49
|
|
|
52
50
|
if (typeof statusCode !== 'number' || statusCode < 200 || statusCode > 599) {
|
|
53
|
-
|
|
51
|
+
console.error(
|
|
54
52
|
`current StatusCode: \`${statusCode}\` .`,
|
|
55
53
|
'Please go to `./src/app/api/errorResponse.ts` to defined the statusCode.',
|
|
56
54
|
);
|
|
@@ -29,6 +29,7 @@ const OpenAI: ModelProviderCard = {
|
|
|
29
29
|
tokens: 4096,
|
|
30
30
|
},
|
|
31
31
|
{
|
|
32
|
+
displayName: 'GPT-3.5 Turbo 16K',
|
|
32
33
|
hidden: true,
|
|
33
34
|
id: 'gpt-3.5-turbo-16k',
|
|
34
35
|
tokens: 16_385,
|
|
@@ -65,12 +66,14 @@ const OpenAI: ModelProviderCard = {
|
|
|
65
66
|
vision: true,
|
|
66
67
|
},
|
|
67
68
|
{
|
|
69
|
+
displayName: 'GPT-4 Turbo Preview (1106)',
|
|
68
70
|
functionCall: true,
|
|
69
71
|
hidden: true,
|
|
70
72
|
id: 'gpt-4-1106-preview',
|
|
71
73
|
tokens: 128_000,
|
|
72
74
|
},
|
|
73
75
|
{
|
|
76
|
+
displayName: 'GPT-4',
|
|
74
77
|
functionCall: true,
|
|
75
78
|
hidden: true,
|
|
76
79
|
id: 'gpt-4',
|
package/src/const/auth.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ActionIcon } from '@lobehub/ui';
|
|
2
2
|
import { Popconfirm } from 'antd';
|
|
3
3
|
import { Eraser } from 'lucide-react';
|
|
4
|
-
import { memo, useCallback } from 'react';
|
|
4
|
+
import { memo, useCallback, useState } from 'react';
|
|
5
5
|
import { useTranslation } from 'react-i18next';
|
|
6
6
|
|
|
7
7
|
import HotKeys from '@/components/HotKeys';
|
|
@@ -14,26 +14,31 @@ const Clear = memo(() => {
|
|
|
14
14
|
const [clearMessage] = useChatStore((s) => [s.clearMessage]);
|
|
15
15
|
const [clearImageList] = useFileStore((s) => [s.clearImageList]);
|
|
16
16
|
const hotkeys = [META_KEY, PREFIX_KEY, CLEAN_MESSAGE_KEY].join('+');
|
|
17
|
+
const [confirmOpened, updateConfirmOpened] = useState(false);
|
|
17
18
|
|
|
18
19
|
const resetConversation = useCallback(() => {
|
|
19
20
|
clearMessage();
|
|
20
21
|
clearImageList();
|
|
21
22
|
}, []);
|
|
22
23
|
|
|
24
|
+
const actionTitle: any = confirmOpened
|
|
25
|
+
? void 0
|
|
26
|
+
: <HotKeys desc={t('clearCurrentMessages', { ns: 'chat' })} keys={hotkeys} />
|
|
27
|
+
|
|
23
28
|
return (
|
|
24
29
|
<Popconfirm
|
|
25
30
|
arrow={false}
|
|
26
31
|
okButtonProps={{ danger: true, type: 'primary' }}
|
|
27
|
-
onConfirm={
|
|
28
|
-
|
|
29
|
-
}
|
|
32
|
+
onConfirm={resetConversation}
|
|
33
|
+
onOpenChange={updateConfirmOpened}
|
|
34
|
+
open={confirmOpened}
|
|
30
35
|
placement={'topRight'}
|
|
31
36
|
title={t('confirmClearCurrentMessages', { ns: 'chat' })}
|
|
32
37
|
>
|
|
33
38
|
<ActionIcon
|
|
34
39
|
icon={Eraser}
|
|
35
40
|
placement={'bottom'}
|
|
36
|
-
title={
|
|
41
|
+
title={actionTitle}
|
|
37
42
|
/>
|
|
38
43
|
</Popconfirm>
|
|
39
44
|
);
|
|
@@ -17,7 +17,7 @@ export const getErrorAlertConfig = (
|
|
|
17
17
|
errorType?: IPluginErrorType | ILobeAgentRuntimeErrorType | ErrorType,
|
|
18
18
|
): AlertProps | undefined => {
|
|
19
19
|
// OpenAIBizError / ZhipuBizError / GoogleBizError / ...
|
|
20
|
-
if (typeof errorType === 'string' && errorType.includes('Biz'))
|
|
20
|
+
if (typeof errorType === 'string' && (errorType.includes('Biz') || errorType.includes('Invalid')))
|
|
21
21
|
return {
|
|
22
22
|
extraDefaultExpand: true,
|
|
23
23
|
extraIsolate: true,
|
|
@@ -31,12 +31,7 @@ export const getErrorAlertConfig = (
|
|
|
31
31
|
};
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
case
|
|
35
|
-
case ChatErrorType.InvalidAccessCode:
|
|
36
|
-
case AgentRuntimeErrorType.NoOpenAIAPIKey:
|
|
37
|
-
case AgentRuntimeErrorType.InvalidBedrockCredentials:
|
|
38
|
-
case AgentRuntimeErrorType.InvalidGoogleAPIKey:
|
|
39
|
-
case AgentRuntimeErrorType.InvalidZhipuAPIKey: {
|
|
34
|
+
case ChatErrorType.InvalidAccessCode: {
|
|
40
35
|
return {
|
|
41
36
|
extraDefaultExpand: true,
|
|
42
37
|
extraIsolate: true,
|
|
@@ -33,6 +33,7 @@ const Locale = memo<LocaleLayoutProps>(({ children, defaultLang }) => {
|
|
|
33
33
|
const [lang, setLang] = useState(defaultLang);
|
|
34
34
|
|
|
35
35
|
const { data: locale } = useSWR(['antd-locale', lang], ([, key]) => getAntdLocale(key), {
|
|
36
|
+
dedupingInterval: 0,
|
|
36
37
|
revalidateOnFocus: false,
|
|
37
38
|
});
|
|
38
39
|
|
|
@@ -1,16 +1,15 @@
|
|
|
1
1
|
/* eslint-disable sort-keys-fix/sort-keys-fix */
|
|
2
|
-
|
|
3
2
|
// ******* Runtime Biz Error ******* //
|
|
4
3
|
export const AgentRuntimeErrorType = {
|
|
5
4
|
AgentRuntimeError: 'AgentRuntimeError', // Agent Runtime 模块运行时错误
|
|
6
5
|
LocationNotSupportError: 'LocationNotSupportError',
|
|
7
6
|
|
|
8
|
-
OpenAIBizError: 'OpenAIBizError',
|
|
7
|
+
OpenAIBizError: 'OpenAIBizError',
|
|
9
8
|
|
|
10
9
|
NoOpenAIAPIKey: 'NoOpenAIAPIKey',
|
|
11
10
|
|
|
12
11
|
InvalidAzureAPIKey: 'InvalidAzureAPIKey',
|
|
13
|
-
AzureBizError: 'AzureBizError',
|
|
12
|
+
AzureBizError: 'AzureBizError',
|
|
14
13
|
|
|
15
14
|
InvalidZhipuAPIKey: 'InvalidZhipuAPIKey',
|
|
16
15
|
ZhipuBizError: 'ZhipuBizError',
|
|
@@ -19,7 +18,7 @@ export const AgentRuntimeErrorType = {
|
|
|
19
18
|
GoogleBizError: 'GoogleBizError',
|
|
20
19
|
|
|
21
20
|
InvalidBedrockCredentials: 'InvalidBedrockCredentials',
|
|
22
|
-
BedrockBizError: 'BedrockBizError',
|
|
21
|
+
BedrockBizError: 'BedrockBizError',
|
|
23
22
|
} as const;
|
|
24
23
|
|
|
25
24
|
export type ILobeAgentRuntimeErrorType =
|
package/src/services/_auth.ts
CHANGED
|
@@ -1,34 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
import { JWTPayload, JWT_SECRET_KEY, LOBE_CHAT_AUTH_HEADER } from '@/const/auth';
|
|
1
|
+
import { JWTPayload, LOBE_CHAT_AUTH_HEADER } from '@/const/auth';
|
|
4
2
|
import { ModelProvider } from '@/libs/agent-runtime';
|
|
5
3
|
import { useGlobalStore } from '@/store/global';
|
|
6
4
|
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
|
-
};
|
|
5
|
+
import { createJWT } from '@/utils/jwt';
|
|
32
6
|
|
|
33
7
|
const getProviderAuthPayload = (provider: string) => {
|
|
34
8
|
switch (provider) {
|
|
@@ -81,7 +55,7 @@ const getProviderAuthPayload = (provider: string) => {
|
|
|
81
55
|
const createAuthTokenWithPayload = async (payload = {}) => {
|
|
82
56
|
const accessCode = settingsSelectors.password(useGlobalStore.getState());
|
|
83
57
|
|
|
84
|
-
return await createJWT({ accessCode, ...payload });
|
|
58
|
+
return await createJWT<JWTPayload>({ accessCode, ...payload });
|
|
85
59
|
};
|
|
86
60
|
|
|
87
61
|
interface AuthParams {
|
|
@@ -23,6 +23,62 @@ describe('modelProviderSelectors', () => {
|
|
|
23
23
|
expect(result).toMatchSnapshot();
|
|
24
24
|
});
|
|
25
25
|
|
|
26
|
+
it('should work correct with gpt-4', () => {
|
|
27
|
+
const s = merge(initialSettingsState, {
|
|
28
|
+
serverConfig: {
|
|
29
|
+
customModelName:
|
|
30
|
+
'-all,+gpt-3.5-turbo-1106,+gpt-3.5-turbo,+gpt-3.5-turbo-16k,+gpt-4,+gpt-4-32k,+gpt-4-1106-preview,+gpt-4-vision-preview',
|
|
31
|
+
},
|
|
32
|
+
}) as unknown as GlobalStore;
|
|
33
|
+
|
|
34
|
+
const result = modelProviderSelectors.modelSelectList(s).filter((r) => r.enabled);
|
|
35
|
+
|
|
36
|
+
expect(result[0].chatModels).toEqual([
|
|
37
|
+
{
|
|
38
|
+
displayName: 'GPT-3.5 Turbo (1106)',
|
|
39
|
+
functionCall: true,
|
|
40
|
+
id: 'gpt-3.5-turbo-1106',
|
|
41
|
+
tokens: 16385,
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
description: 'GPT 3.5 Turbo,适用于各种文本生成和理解任务',
|
|
45
|
+
displayName: 'GPT-3.5 Turbo',
|
|
46
|
+
functionCall: true,
|
|
47
|
+
id: 'gpt-3.5-turbo',
|
|
48
|
+
tokens: 4096,
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
displayName: 'GPT-3.5 Turbo 16K',
|
|
52
|
+
id: 'gpt-3.5-turbo-16k',
|
|
53
|
+
tokens: 16385,
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
displayName: 'GPT-4',
|
|
57
|
+
functionCall: true,
|
|
58
|
+
id: 'gpt-4',
|
|
59
|
+
tokens: 8192,
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
displayName: 'gpt-4-32k',
|
|
63
|
+
functionCall: true,
|
|
64
|
+
id: 'gpt-4-32k',
|
|
65
|
+
tokens: 32768,
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
displayName: 'GPT-4 Turbo Preview (1106)',
|
|
69
|
+
functionCall: true,
|
|
70
|
+
id: 'gpt-4-1106-preview',
|
|
71
|
+
tokens: 128000,
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
description: 'GPT-4 视觉预览版,支持视觉任务',
|
|
75
|
+
displayName: 'GPT-4 Turbo Vision (Preview)',
|
|
76
|
+
id: 'gpt-4-vision-preview',
|
|
77
|
+
tokens: 128000,
|
|
78
|
+
vision: true,
|
|
79
|
+
},
|
|
80
|
+
]);
|
|
81
|
+
});
|
|
26
82
|
it('duplicate naming model', () => {
|
|
27
83
|
const s = merge(initialSettingsState, {
|
|
28
84
|
serverConfig: {},
|
|
@@ -67,6 +123,7 @@ describe('modelProviderSelectors', () => {
|
|
|
67
123
|
const result = modelProviderSelectors.modelSelectList(s).filter((r) => r.enabled);
|
|
68
124
|
|
|
69
125
|
expect(result[0].chatModels.find((o) => o.id === 'gpt-4-1106-preview')).toEqual({
|
|
126
|
+
displayName: 'GPT-4 Turbo Preview (1106)',
|
|
70
127
|
functionCall: true,
|
|
71
128
|
id: 'gpt-4-1106-preview',
|
|
72
129
|
tokens: 128000,
|
|
@@ -52,29 +52,31 @@ const processChatModels = (modelConfig: ReturnType<typeof parseModelString>): Ch
|
|
|
52
52
|
|
|
53
53
|
return produce(chatModels, (draft) => {
|
|
54
54
|
// 处理添加或替换逻辑
|
|
55
|
-
for (const
|
|
56
|
-
//
|
|
57
|
-
const
|
|
58
|
-
|
|
59
|
-
//
|
|
60
|
-
if (
|
|
61
|
-
const
|
|
62
|
-
|
|
63
|
-
if
|
|
64
|
-
|
|
65
|
-
if (
|
|
55
|
+
for (const toAddModel of modelConfig.add) {
|
|
56
|
+
// first try to find the model in LOBE_DEFAULT_MODEL_LIST to confirm if it is a known model
|
|
57
|
+
const knownModel = LOBE_DEFAULT_MODEL_LIST.find((model) => model.id === toAddModel.id);
|
|
58
|
+
|
|
59
|
+
// if the model is known, update it based on the known model
|
|
60
|
+
if (knownModel) {
|
|
61
|
+
const modelInList = draft.find((model) => model.id === toAddModel.id);
|
|
62
|
+
|
|
63
|
+
// if the model is already in chatModels, update it
|
|
64
|
+
if (modelInList) {
|
|
65
|
+
if (modelInList.hidden) delete modelInList.hidden;
|
|
66
|
+
if (toAddModel.displayName) modelInList.displayName = toAddModel.displayName;
|
|
66
67
|
} else {
|
|
67
|
-
//
|
|
68
|
+
// if the model is not in chatModels, add it
|
|
68
69
|
draft.push({
|
|
69
|
-
...
|
|
70
|
-
displayName:
|
|
70
|
+
...knownModel,
|
|
71
|
+
displayName: toAddModel.displayName || knownModel.displayName || knownModel.id,
|
|
72
|
+
hidden: undefined,
|
|
71
73
|
});
|
|
72
74
|
}
|
|
73
75
|
} else {
|
|
74
|
-
//
|
|
76
|
+
// if the model is not in LOBE_DEFAULT_MODEL_LIST, add it as a new custom model
|
|
75
77
|
draft.push({
|
|
76
|
-
...
|
|
77
|
-
displayName:
|
|
78
|
+
...toAddModel,
|
|
79
|
+
displayName: toAddModel.displayName || toAddModel.id,
|
|
78
80
|
functionCall: true,
|
|
79
81
|
isCustom: true,
|
|
80
82
|
vision: true,
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import { NON_HTTP_PREFIX } from '@/const/auth';
|
|
4
|
+
|
|
5
|
+
import { createJWT } from './jwt';
|
|
6
|
+
|
|
7
|
+
describe('createJWT', () => {
|
|
8
|
+
it('should create a JWT token', async () => {
|
|
9
|
+
const payload = { test: 'test' };
|
|
10
|
+
const token = await createJWT(payload);
|
|
11
|
+
expect(token).toBeTruthy();
|
|
12
|
+
});
|
|
13
|
+
it('should return a token with NON_HTTP_PREFIX when crypto.subtle does not exist', async () => {
|
|
14
|
+
const originalCryptoSubtle = crypto.subtle;
|
|
15
|
+
// @ts-ignore
|
|
16
|
+
crypto['subtle'] = undefined;
|
|
17
|
+
|
|
18
|
+
const payload = { test: 'test' };
|
|
19
|
+
const token = await createJWT(payload);
|
|
20
|
+
|
|
21
|
+
expect(token.startsWith(NON_HTTP_PREFIX)).toBeTruthy();
|
|
22
|
+
|
|
23
|
+
// @ts-ignore
|
|
24
|
+
crypto['subtle'] = originalCryptoSubtle;
|
|
25
|
+
});
|
|
26
|
+
});
|
package/src/utils/jwt.ts
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { SignJWT, importJWK } from 'jose';
|
|
2
|
+
|
|
3
|
+
import { JWT_SECRET_KEY, NON_HTTP_PREFIX } from '@/const/auth';
|
|
4
|
+
|
|
5
|
+
export const createJWT = async <T>(payload: T) => {
|
|
6
|
+
const now = Math.floor(Date.now() / 1000);
|
|
7
|
+
const duration = 100; // 100s
|
|
8
|
+
|
|
9
|
+
const encoder = new TextEncoder();
|
|
10
|
+
|
|
11
|
+
// fix the issue that crypto.subtle is not available in non-HTTPS environment
|
|
12
|
+
// refs: https://github.com/lobehub/lobe-chat/pull/1238
|
|
13
|
+
if (!crypto.subtle) {
|
|
14
|
+
const buffer = encoder.encode(JSON.stringify(payload));
|
|
15
|
+
|
|
16
|
+
return `${NON_HTTP_PREFIX}.${Buffer.from(buffer).toString('base64')}`;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// create a secret key
|
|
20
|
+
const secretKey = await crypto.subtle.digest('SHA-256', encoder.encode(JWT_SECRET_KEY));
|
|
21
|
+
|
|
22
|
+
// get the JWK from the secret key
|
|
23
|
+
const jwkSecretKey = await importJWK(
|
|
24
|
+
{
|
|
25
|
+
k: Buffer.from(secretKey).toString('base64'),
|
|
26
|
+
kty: 'oct',
|
|
27
|
+
},
|
|
28
|
+
'HS256',
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
// 创建JWT
|
|
32
|
+
return new SignJWT(payload as Record<string, any>)
|
|
33
|
+
.setProtectedHeader({ alg: 'HS256' })
|
|
34
|
+
.setIssuedAt(now) // 设置JWT的iat(签发时间)声明
|
|
35
|
+
.setExpirationTime(now + duration) // 设置 JWT 的 exp(过期时间)为 100 s
|
|
36
|
+
.sign(jwkSecretKey);
|
|
37
|
+
};
|