@lobehub/chat 0.150.7 → 0.150.9
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/CHANGELOG.md +50 -0
- package/docs/self-hosting/advanced/upstream-sync.mdx +74 -0
- package/docs/self-hosting/advanced/upstream-sync.zh-CN.mdx +71 -0
- package/docs/usage/providers/ollama.mdx +1 -1
- package/docs/usage/providers/ollama.zh-CN.mdx +1 -1
- package/package.json +1 -1
- package/src/app/chat/(desktop)/features/ChatHeader/HeaderAction.tsx +2 -2
- package/src/app/chat/(desktop)/features/SideBar/index.tsx +2 -2
- package/src/app/chat/(mobile)/features/SessionHeader.tsx +2 -2
- package/src/app/chat/(mobile)/mobile/ChatHeader/index.tsx +2 -2
- package/src/app/chat/_layout/Desktop/SessionHeader.tsx +2 -2
- package/src/app/chat/features/PluginTag/index.tsx +2 -2
- package/src/app/chat/features/SessionListContent/List/index.tsx +2 -2
- package/src/app/chat/features/TelemetryNotification/index.tsx +5 -3
- package/src/app/settings/about/page.tsx +3 -3
- package/src/app/settings/features/SettingList/index.tsx +2 -2
- package/src/app/settings/llm/OpenAI/index.tsx +2 -2
- package/src/components/ModelIcon/index.tsx +1 -0
- package/src/components/ModelTag/ModelIcon.tsx +1 -0
- package/src/config/modelProviders/ollama.ts +6 -0
- package/src/features/AgentSetting/AgentPlugin/index.tsx +2 -2
- package/src/features/ChatInput/ActionBar/Tools/index.tsx +2 -2
- package/src/features/Conversation/Error/InvalidAccessCode.tsx +3 -3
- package/src/layout/GlobalProvider/index.tsx +5 -3
- package/src/server/globalConfig/index.ts +119 -0
- package/src/server/routers/config/index.ts +3 -112
- package/src/store/global/slices/common/selectors.ts +0 -2
- package/src/store/serverConfig/Provider.tsx +22 -0
- package/src/store/serverConfig/index.ts +3 -0
- package/src/store/serverConfig/selectors.test.ts +72 -0
- package/src/store/serverConfig/selectors.ts +11 -0
- package/src/store/serverConfig/store.test.ts +53 -0
- package/src/store/serverConfig/store.ts +61 -0
- package/src/store/featureFlags/Provider.tsx +0 -18
- package/src/store/featureFlags/index.ts +0 -3
- package/src/store/featureFlags/selectors.ts +0 -5
- package/src/store/featureFlags/store.ts +0 -42
- /package/src/server/{routers/config → globalConfig}/parseDefaultAgent.test.ts +0 -0
- /package/src/server/{routers/config → globalConfig}/parseDefaultAgent.ts +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,56 @@
|
|
|
2
2
|
|
|
3
3
|
# Changelog
|
|
4
4
|
|
|
5
|
+
### [Version 0.150.9](https://github.com/lobehub/lobe-chat/compare/v0.150.8...v0.150.9)
|
|
6
|
+
|
|
7
|
+
<sup>Released on **2024-04-28**</sup>
|
|
8
|
+
|
|
9
|
+
#### ♻ Code Refactoring
|
|
10
|
+
|
|
11
|
+
- **misc**: Refactor feature flags store to server config store.
|
|
12
|
+
|
|
13
|
+
<br/>
|
|
14
|
+
|
|
15
|
+
<details>
|
|
16
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
|
17
|
+
|
|
18
|
+
#### Code refactoring
|
|
19
|
+
|
|
20
|
+
- **misc**: Refactor feature flags store to server config store, closes [#2263](https://github.com/lobehub/lobe-chat/issues/2263) ([2e991d7](https://github.com/lobehub/lobe-chat/commit/2e991d7))
|
|
21
|
+
|
|
22
|
+
</details>
|
|
23
|
+
|
|
24
|
+
<div align="right">
|
|
25
|
+
|
|
26
|
+
[](#readme-top)
|
|
27
|
+
|
|
28
|
+
</div>
|
|
29
|
+
|
|
30
|
+
### [Version 0.150.8](https://github.com/lobehub/lobe-chat/compare/v0.150.7...v0.150.8)
|
|
31
|
+
|
|
32
|
+
<sup>Released on **2024-04-28**</sup>
|
|
33
|
+
|
|
34
|
+
#### 💄 Styles
|
|
35
|
+
|
|
36
|
+
- **ollama**: Phi3 Instruct models and its model icons.
|
|
37
|
+
|
|
38
|
+
<br/>
|
|
39
|
+
|
|
40
|
+
<details>
|
|
41
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
|
42
|
+
|
|
43
|
+
#### Styles
|
|
44
|
+
|
|
45
|
+
- **ollama**: Phi3 Instruct models and its model icons, closes [#2254](https://github.com/lobehub/lobe-chat/issues/2254) ([c9b55cc](https://github.com/lobehub/lobe-chat/commit/c9b55cc))
|
|
46
|
+
|
|
47
|
+
</details>
|
|
48
|
+
|
|
49
|
+
<div align="right">
|
|
50
|
+
|
|
51
|
+
[](#readme-top)
|
|
52
|
+
|
|
53
|
+
</div>
|
|
54
|
+
|
|
5
55
|
### [Version 0.150.7](https://github.com/lobehub/lobe-chat/compare/v0.150.6...v0.150.7)
|
|
6
56
|
|
|
7
57
|
<sup>Released on **2024-04-28**</sup>
|
|
@@ -85,3 +85,77 @@ Ensure that you have sufficient permissions to stop and remove the container bef
|
|
|
85
85
|
No need to worry, you won't. All of LobeChat's chat records are stored in your local browser. Therefore, when redeploying LobeChat using Docker, your chat records will not be lost.
|
|
86
86
|
|
|
87
87
|
</Callout>
|
|
88
|
+
|
|
89
|
+
If you wish to automate the above steps, you can follow the method below and use Crontab scheduling to complete it. The specific steps are as follows.
|
|
90
|
+
|
|
91
|
+
<Steps>
|
|
92
|
+
|
|
93
|
+
### Write automatic update scripts and configuration files
|
|
94
|
+
|
|
95
|
+
First, create a `lobe.env` configuration file with various environment variables, for example:
|
|
96
|
+
|
|
97
|
+
```env
|
|
98
|
+
OPENAI_API_KEY=sk-xxxx
|
|
99
|
+
OPENAI_PROXY_URL=https://api-proxy.com/v1
|
|
100
|
+
ACCESS_CODE=arthals2333
|
|
101
|
+
OPENAI_MODEL_LIST=-gpt-4,-gpt-4-32k,-gpt-3.5-turbo-16k,gpt-3.5-turbo-1106=gpt-3.5-turbo-16k,gpt-4-0125-preview=gpt-4-turbo,gpt-4-vision-preview=gpt-4-vision
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Then, you can use the following script to automate the update:
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
#!/bin/bash
|
|
108
|
+
# auto-update-lobe-chat.sh
|
|
109
|
+
|
|
110
|
+
# Set up proxy (optional)
|
|
111
|
+
export https_proxy=http://127.0.0.1:7890 http_proxy=http://127.0.0.1:7890 all_proxy=socks5://127.0.0.1:7890
|
|
112
|
+
|
|
113
|
+
# Pull the latest image and store the output in a variable
|
|
114
|
+
output=$(docker pull lobehub/lobe-chat:latest 2>&1)
|
|
115
|
+
|
|
116
|
+
# Check if the pull command was executed successfully
|
|
117
|
+
if [ $? -ne 0 ]; then
|
|
118
|
+
exit 1
|
|
119
|
+
fi
|
|
120
|
+
|
|
121
|
+
# Check if the output contains a specific string
|
|
122
|
+
echo "$output" | grep -q "Image is up to date for lobehub/lobe-chat:latest"
|
|
123
|
+
|
|
124
|
+
# If the image is already up to date, do nothing
|
|
125
|
+
if [ $? -eq 0 ]; then
|
|
126
|
+
exit 0
|
|
127
|
+
fi
|
|
128
|
+
|
|
129
|
+
echo "Detected Lobe-Chat update"
|
|
130
|
+
|
|
131
|
+
# Remove the old container
|
|
132
|
+
echo "Removed: $(docker rm -f Lobe-Chat)"
|
|
133
|
+
|
|
134
|
+
# Run the new container
|
|
135
|
+
echo "Started: $(docker run -d --network=host --env-file /path/to/lobe.env --name=Lobe-Chat --restart=always lobehub/lobe-chat)"
|
|
136
|
+
|
|
137
|
+
# Print the update time and version
|
|
138
|
+
echo "Update time: $(date)"
|
|
139
|
+
echo "Version: $(docker inspect lobehub/lobe-chat:latest | grep 'org.opencontainers.image.version' | awk -F'"' '{print $4}')"
|
|
140
|
+
|
|
141
|
+
# Clean up unused images
|
|
142
|
+
docker images | grep 'lobehub/lobe-chat' | grep -v 'latest' | awk '{print $3}' | xargs -r docker rmi > /dev/null 2>&1
|
|
143
|
+
echo "Removed old images."
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
<Callout type={'warning'}>
|
|
147
|
+
This script can be used in Crontab, but please ensure that your Crontab can find the correct
|
|
148
|
+
Docker command. It is recommended to use absolute paths.
|
|
149
|
+
</Callout>
|
|
150
|
+
|
|
151
|
+
Configure Crontab to execute the script every 5 minutes:
|
|
152
|
+
|
|
153
|
+
### Configure Crontab to automatically execute scripts
|
|
154
|
+
|
|
155
|
+
The following command configures Crontab to execute scripts every 5 minutes, or as often as you like:
|
|
156
|
+
|
|
157
|
+
```bash
|
|
158
|
+
*/5 * * * * /path/to/auto-update-lobe-chat.sh >> /path/to/auto-update-lobe-chat.log 2>&1
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
</Steps>
|
|
@@ -80,3 +80,74 @@ docker run -d -p 3210:3210 \
|
|
|
80
80
|
放心,不会的。LobeChat 的聊天记录全部都存储在你的本地浏览器中。因此使用 Docker 重新部署 LobeChat 时,你的聊天记录并不会丢失。
|
|
81
81
|
|
|
82
82
|
</Callout>
|
|
83
|
+
|
|
84
|
+
如果你希望自动化执行以上步骤,你可以参照下面的方法,利用 Crontab 定时来完成。具体步骤如下。
|
|
85
|
+
|
|
86
|
+
<Steps>
|
|
87
|
+
|
|
88
|
+
### 撰写自动更新脚本、配置文件
|
|
89
|
+
|
|
90
|
+
首先,新建一个 `lobe.env` 配置文件,内容为各种环境变量,例如:
|
|
91
|
+
|
|
92
|
+
```env
|
|
93
|
+
OPENAI_API_KEY=sk-xxxx
|
|
94
|
+
OPENAI_PROXY_URL=https://api-proxy.com/v1
|
|
95
|
+
ACCESS_CODE=arthals2333
|
|
96
|
+
OPENAI_MODEL_LIST=-gpt-4,-gpt-4-32k,-gpt-3.5-turbo-16k,gpt-3.5-turbo-1106=gpt-3.5-turbo-16k,gpt-4-0125-preview=gpt-4-turbo,gpt-4-vision-preview=gpt-4-vision
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
然后,你可以使用以下脚本来自动更新:
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
#!/bin/bash
|
|
103
|
+
# auto-update-lobe-chat.sh
|
|
104
|
+
|
|
105
|
+
# 设置代理(可选)
|
|
106
|
+
export https_proxy=http://127.0.0.1:7890 http_proxy=http://127.0.0.1:7890 all_proxy=socks5://127.0.0.1:7890
|
|
107
|
+
|
|
108
|
+
# 拉取最新的镜像并将输出存储在变量中
|
|
109
|
+
output=$(docker pull lobehub/lobe-chat:latest 2>&1)
|
|
110
|
+
|
|
111
|
+
# 检查拉取命令是否成功执行
|
|
112
|
+
if [ $? -ne 0 ]; then
|
|
113
|
+
exit 1
|
|
114
|
+
fi
|
|
115
|
+
|
|
116
|
+
# 检查输出中是否包含特定的字符串
|
|
117
|
+
echo "$output" | grep -q "Image is up to date for lobehub/lobe-chat:latest"
|
|
118
|
+
|
|
119
|
+
# 如果镜像已经是最新的,则不执行任何操作
|
|
120
|
+
if [ $? -eq 0 ]; then
|
|
121
|
+
exit 0
|
|
122
|
+
fi
|
|
123
|
+
|
|
124
|
+
echo "Detected Lobe-Chat update"
|
|
125
|
+
|
|
126
|
+
# 删除旧的容器
|
|
127
|
+
echo "Removed: $(docker rm -f Lobe-Chat)"
|
|
128
|
+
|
|
129
|
+
# 运行新的容器
|
|
130
|
+
echo "Started: $(docker run -d --network=host --env-file /path/to/lobe.env --name=Lobe-Chat --restart=always lobehub/lobe-chat)"
|
|
131
|
+
|
|
132
|
+
# 打印更新的时间和版本
|
|
133
|
+
echo "Update time: $(date)"
|
|
134
|
+
echo "Version: $(docker inspect lobehub/lobe-chat:latest | grep 'org.opencontainers.image.version' | awk -F'"' '{print $4}')"
|
|
135
|
+
|
|
136
|
+
# 清理不再使用的镜像
|
|
137
|
+
docker images | grep 'lobehub/lobe-chat' | grep -v 'latest' | awk '{print $3}' | xargs -r docker rmi > /dev/null 2>&1
|
|
138
|
+
echo "Removed old images."
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
<Callout type={'warning'}>
|
|
142
|
+
此脚本可以在 Crontab 中使用,但请确认你的 Crontab 可以找到正确的 Docker 命令。建议使用绝对路径。
|
|
143
|
+
</Callout>
|
|
144
|
+
|
|
145
|
+
### 配置 Crontab 自动执行脚本
|
|
146
|
+
|
|
147
|
+
以下命令可以配置 Crontab 每 5 分钟执行一次脚本,你也可以根据需要调整执行频率:
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
*/5 * * * * /path/to/auto-update-lobe-chat.sh >> /path/to/auto-update-lobe-chat.log 2>&1
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
</Steps>
|
|
@@ -25,7 +25,7 @@ This document will guide you on how to use Ollama in LobeChat:
|
|
|
25
25
|
|
|
26
26
|
<Video
|
|
27
27
|
alt="demonstration of using Ollama in LobeChat"
|
|
28
|
-
height={
|
|
28
|
+
height={580}
|
|
29
29
|
src="https://github.com/lobehub/lobe-chat/assets/28616219/c32b56db-c6a1-4876-9bc3-acbd37ec0c0c"
|
|
30
30
|
/>
|
|
31
31
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lobehub/chat",
|
|
3
|
-
"version": "0.150.
|
|
3
|
+
"version": "0.150.9",
|
|
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",
|
|
@@ -4,8 +4,8 @@ import { memo } from 'react';
|
|
|
4
4
|
import { useTranslation } from 'react-i18next';
|
|
5
5
|
|
|
6
6
|
import { DESKTOP_HEADER_ICON_SIZE } from '@/const/layoutTokens';
|
|
7
|
-
import { featureFlagsSelectors, useFeatureFlagStore } from '@/store/featureFlags';
|
|
8
7
|
import { useGlobalStore } from '@/store/global';
|
|
8
|
+
import { featureFlagsSelectors, useServerConfigStore } from '@/store/serverConfig';
|
|
9
9
|
|
|
10
10
|
import SettingButton from '../../../features/SettingButton';
|
|
11
11
|
import ShareButton from '../../../features/ShareButton';
|
|
@@ -18,7 +18,7 @@ const HeaderAction = memo(() => {
|
|
|
18
18
|
s.toggleChatSideBar,
|
|
19
19
|
]);
|
|
20
20
|
|
|
21
|
-
const { isAgentEditable } =
|
|
21
|
+
const { isAgentEditable } = useServerConfigStore(featureFlagsSelectors);
|
|
22
22
|
|
|
23
23
|
return (
|
|
24
24
|
<>
|
|
@@ -6,8 +6,8 @@ import { memo } from 'react';
|
|
|
6
6
|
import TopicListContent from '@/app/chat/features/TopicListContent';
|
|
7
7
|
import SafeSpacing from '@/components/SafeSpacing';
|
|
8
8
|
import { CHAT_SIDEBAR_WIDTH } from '@/const/layoutTokens';
|
|
9
|
-
import { featureFlagsSelectors, useFeatureFlagStore } from '@/store/featureFlags';
|
|
10
9
|
import { useGlobalStore } from '@/store/global';
|
|
10
|
+
import { featureFlagsSelectors, useServerConfigStore } from '@/store/serverConfig';
|
|
11
11
|
import { useSessionStore } from '@/store/session';
|
|
12
12
|
import { sessionSelectors } from '@/store/session/selectors';
|
|
13
13
|
|
|
@@ -35,7 +35,7 @@ const Desktop = memo(() => {
|
|
|
35
35
|
s.toggleChatSideBar,
|
|
36
36
|
]);
|
|
37
37
|
|
|
38
|
-
const { isAgentEditable: showSystemRole } =
|
|
38
|
+
const { isAgentEditable: showSystemRole } = useServerConfigStore(featureFlagsSelectors);
|
|
39
39
|
const isInbox = useSessionStore(sessionSelectors.isInboxSession);
|
|
40
40
|
|
|
41
41
|
return (
|
|
@@ -7,9 +7,9 @@ import { Flexbox } from 'react-layout-kit';
|
|
|
7
7
|
|
|
8
8
|
import { MOBILE_HEADER_ICON_SIZE } from '@/const/layoutTokens';
|
|
9
9
|
import SyncStatusInspector from '@/features/SyncStatusInspector';
|
|
10
|
-
import { featureFlagsSelectors, useFeatureFlagStore } from '@/store/featureFlags';
|
|
11
10
|
import { useGlobalStore } from '@/store/global';
|
|
12
11
|
import { commonSelectors } from '@/store/global/selectors';
|
|
12
|
+
import { featureFlagsSelectors, useServerConfigStore } from '@/store/serverConfig';
|
|
13
13
|
import { useSessionStore } from '@/store/session';
|
|
14
14
|
import { mobileHeaderSticky } from '@/styles/mobileHeader';
|
|
15
15
|
|
|
@@ -27,7 +27,7 @@ const Header = memo(() => {
|
|
|
27
27
|
const [createSession] = useSessionStore((s) => [s.createSession]);
|
|
28
28
|
const router = useRouter();
|
|
29
29
|
const avatar = useGlobalStore(commonSelectors.userAvatar);
|
|
30
|
-
const { showCreateSession } =
|
|
30
|
+
const { showCreateSession } = useServerConfigStore(featureFlagsSelectors);
|
|
31
31
|
|
|
32
32
|
return (
|
|
33
33
|
<MobileNavBar
|
|
@@ -2,7 +2,7 @@ import { MobileNavBar } from '@lobehub/ui';
|
|
|
2
2
|
import { useRouter } from 'next/navigation';
|
|
3
3
|
import { memo, useState } from 'react';
|
|
4
4
|
|
|
5
|
-
import { featureFlagsSelectors,
|
|
5
|
+
import { featureFlagsSelectors, useServerConfigStore } from '@/store/serverConfig';
|
|
6
6
|
|
|
7
7
|
import SettingButton from '../../../features/SettingButton';
|
|
8
8
|
import ShareButton from '../../../features/ShareButton';
|
|
@@ -12,7 +12,7 @@ const MobileHeader = memo(() => {
|
|
|
12
12
|
const router = useRouter();
|
|
13
13
|
const [open, setOpen] = useState(false);
|
|
14
14
|
|
|
15
|
-
const { isAgentEditable } =
|
|
15
|
+
const { isAgentEditable } = useServerConfigStore(featureFlagsSelectors);
|
|
16
16
|
|
|
17
17
|
// const items: MenuProps['items'] = [
|
|
18
18
|
// {
|
|
@@ -8,7 +8,7 @@ import { Flexbox } from 'react-layout-kit';
|
|
|
8
8
|
import { DESKTOP_HEADER_ICON_SIZE } from '@/const/layoutTokens';
|
|
9
9
|
import SyncStatusTag from '@/features/SyncStatusInspector';
|
|
10
10
|
import { useActionSWR } from '@/libs/swr';
|
|
11
|
-
import { featureFlagsSelectors,
|
|
11
|
+
import { featureFlagsSelectors, useServerConfigStore } from '@/store/serverConfig';
|
|
12
12
|
import { useSessionStore } from '@/store/session';
|
|
13
13
|
|
|
14
14
|
import SessionSearchBar from '../../features/SessionSearchBar';
|
|
@@ -27,7 +27,7 @@ const Header = memo(() => {
|
|
|
27
27
|
const { styles } = useStyles();
|
|
28
28
|
const { t } = useTranslation('chat');
|
|
29
29
|
const [createSession] = useSessionStore((s) => [s.createSession]);
|
|
30
|
-
const { enableWebrtc, showCreateSession } =
|
|
30
|
+
const { enableWebrtc, showCreateSession } = useServerConfigStore(featureFlagsSelectors);
|
|
31
31
|
|
|
32
32
|
const { mutate, isValidating } = useActionSWR('session.createSession', () => createSession());
|
|
33
33
|
|
|
@@ -5,7 +5,7 @@ import isEqual from 'fast-deep-equal';
|
|
|
5
5
|
import { LucideToyBrick } from 'lucide-react';
|
|
6
6
|
import { memo } from 'react';
|
|
7
7
|
|
|
8
|
-
import { featureFlagsSelectors,
|
|
8
|
+
import { featureFlagsSelectors, useServerConfigStore } from '@/store/serverConfig';
|
|
9
9
|
import { pluginHelpers, useToolStore } from '@/store/tool';
|
|
10
10
|
import { toolSelectors } from '@/store/tool/selectors';
|
|
11
11
|
|
|
@@ -16,7 +16,7 @@ export interface PluginTagProps {
|
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
const PluginTag = memo<PluginTagProps>(({ plugins }) => {
|
|
19
|
-
const { showDalle } =
|
|
19
|
+
const { showDalle } = useServerConfigStore(featureFlagsSelectors);
|
|
20
20
|
const list = useToolStore(toolSelectors.metaList(showDalle), isEqual);
|
|
21
21
|
const displayPlugin = useToolStore(toolSelectors.getMetaById(plugins[0]), isEqual);
|
|
22
22
|
|
|
@@ -7,7 +7,7 @@ import { Center } from 'react-layout-kit';
|
|
|
7
7
|
import LazyLoad from 'react-lazy-load';
|
|
8
8
|
|
|
9
9
|
import { SESSION_CHAT_URL } from '@/const/url';
|
|
10
|
-
import { featureFlagsSelectors,
|
|
10
|
+
import { featureFlagsSelectors, useServerConfigStore } from '@/store/serverConfig';
|
|
11
11
|
import { useSessionStore } from '@/store/session';
|
|
12
12
|
import { sessionSelectors } from '@/store/session/selectors';
|
|
13
13
|
import { LobeAgentSession } from '@/types/session';
|
|
@@ -30,7 +30,7 @@ interface SessionListProps {
|
|
|
30
30
|
const SessionList = memo<SessionListProps>(({ dataSource, groupId, showAddButton = true }) => {
|
|
31
31
|
const { t } = useTranslation('chat');
|
|
32
32
|
const isInit = useSessionStore((s) => sessionSelectors.isSessionListInit(s));
|
|
33
|
-
const { showCreateSession } =
|
|
33
|
+
const { showCreateSession } = useServerConfigStore(featureFlagsSelectors);
|
|
34
34
|
const { styles } = useStyles();
|
|
35
35
|
|
|
36
36
|
const { mobile } = useResponsive();
|
|
@@ -10,7 +10,8 @@ import { Flexbox } from 'react-layout-kit';
|
|
|
10
10
|
|
|
11
11
|
import { PRIVACY_URL } from '@/const/url';
|
|
12
12
|
import { useGlobalStore } from '@/store/global';
|
|
13
|
-
import {
|
|
13
|
+
import { useServerConfigStore } from '@/store/serverConfig';
|
|
14
|
+
import { serverConfigSelectors } from '@/store/serverConfig/selectors';
|
|
14
15
|
|
|
15
16
|
const useStyles = createStyles(({ css, token, isDarkMode }) => ({
|
|
16
17
|
container: css`
|
|
@@ -55,8 +56,9 @@ const TelemetryNotification = memo<{ mobile?: boolean }>(({ mobile }) => {
|
|
|
55
56
|
const { styles, theme, cx } = useStyles();
|
|
56
57
|
|
|
57
58
|
const { t } = useTranslation('common');
|
|
58
|
-
const
|
|
59
|
-
|
|
59
|
+
const shouldCheck = useServerConfigStore(serverConfigSelectors.enabledTelemetryChat);
|
|
60
|
+
|
|
61
|
+
const [useCheckTrace, updatePreference] = useGlobalStore((s) => [
|
|
60
62
|
s.useCheckTrace,
|
|
61
63
|
s.updatePreference,
|
|
62
64
|
]);
|
|
@@ -6,8 +6,8 @@ import { useTranslation } from 'react-i18next';
|
|
|
6
6
|
import { Flexbox } from 'react-layout-kit';
|
|
7
7
|
|
|
8
8
|
import PageTitle from '@/components/PageTitle';
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
9
|
+
import { useServerConfigStore } from '@/store/serverConfig';
|
|
10
|
+
import { serverConfigSelectors } from '@/store/serverConfig/selectors';
|
|
11
11
|
|
|
12
12
|
import AboutList from './AboutList';
|
|
13
13
|
import Analytics from './Analytics';
|
|
@@ -23,7 +23,7 @@ export default memo(() => {
|
|
|
23
23
|
const { t } = useTranslation('setting');
|
|
24
24
|
|
|
25
25
|
const { styles } = useStyles();
|
|
26
|
-
const enabledTelemetryChat =
|
|
26
|
+
const enabledTelemetryChat = useServerConfigStore(serverConfigSelectors.enabledTelemetryChat);
|
|
27
27
|
|
|
28
28
|
return (
|
|
29
29
|
<>
|
|
@@ -3,8 +3,8 @@ import Link from 'next/link';
|
|
|
3
3
|
import { memo } from 'react';
|
|
4
4
|
import { useTranslation } from 'react-i18next';
|
|
5
5
|
|
|
6
|
-
import { featureFlagsSelectors, useFeatureFlagStore } from '@/store/featureFlags';
|
|
7
6
|
import { SettingsTabs } from '@/store/global/initialState';
|
|
7
|
+
import { featureFlagsSelectors, useServerConfigStore } from '@/store/serverConfig';
|
|
8
8
|
|
|
9
9
|
import Item from './Item';
|
|
10
10
|
|
|
@@ -21,7 +21,7 @@ export interface SettingListProps {
|
|
|
21
21
|
|
|
22
22
|
const SettingList = memo<SettingListProps>(({ activeTab, mobile }) => {
|
|
23
23
|
const { t } = useTranslation('setting');
|
|
24
|
-
const { enableWebrtc, showLLM } =
|
|
24
|
+
const { enableWebrtc, showLLM } = useServerConfigStore(featureFlagsSelectors);
|
|
25
25
|
|
|
26
26
|
const items = [
|
|
27
27
|
{ icon: Settings2, label: t('tab.common'), value: SettingsTabs.Common },
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { OpenAI } from '@lobehub/icons';
|
|
2
2
|
import { memo } from 'react';
|
|
3
3
|
|
|
4
|
-
import { featureFlagsSelectors,
|
|
4
|
+
import { featureFlagsSelectors, useServerConfigStore } from '@/store/serverConfig';
|
|
5
5
|
|
|
6
6
|
import ProviderConfig from '../components/ProviderConfig';
|
|
7
7
|
|
|
8
8
|
const OpenAIProvider = memo(() => {
|
|
9
|
-
const { showOpenAIProxyUrl, showOpenAIApiKey } =
|
|
9
|
+
const { showOpenAIProxyUrl, showOpenAIApiKey } = useServerConfigStore(featureFlagsSelectors);
|
|
10
10
|
|
|
11
11
|
return (
|
|
12
12
|
<ProviderConfig
|
|
@@ -95,6 +95,7 @@ const ModelIcon = memo<ModelProviderIconProps>(({ model: originModel, size = 12
|
|
|
95
95
|
return <Stability.Avatar size={size} />;
|
|
96
96
|
|
|
97
97
|
if (model.includes('wizardlm')) return <Azure.Avatar size={size} />;
|
|
98
|
+
if (model.includes('phi3')) return <Azure.Avatar size={size} />;
|
|
98
99
|
if (model.includes('firefly')) return <Adobe.Avatar size={size} />;
|
|
99
100
|
if (model.includes('jamba') ||
|
|
100
101
|
model.includes('j2-'))
|
|
@@ -82,6 +82,7 @@ const ModelIcon = memo<ModelIconProps>(({ model, size = 12 }) => {
|
|
|
82
82
|
return <Stability size={size} />;
|
|
83
83
|
|
|
84
84
|
if (model.includes('wizardlm')) return <Azure size={size} />;
|
|
85
|
+
if (model.includes('phi3')) return <Azure size={size} />;
|
|
85
86
|
if (model.includes('firefly')) return <AdobeFirefly size={size} />;
|
|
86
87
|
if (model.includes('jamba') || model.includes('j2-')) return <Ai21 size={size} />;
|
|
87
88
|
});
|
|
@@ -91,6 +91,12 @@ const Ollama: ModelProviderCard = {
|
|
|
91
91
|
id: 'codellama:python',
|
|
92
92
|
tokens: 16_000,
|
|
93
93
|
},
|
|
94
|
+
{
|
|
95
|
+
displayName: 'Phi3-Instruct 3.8B',
|
|
96
|
+
enabled: true,
|
|
97
|
+
id: 'phi3:instruct',
|
|
98
|
+
tokens: 128_000,
|
|
99
|
+
},
|
|
94
100
|
{
|
|
95
101
|
displayName: 'Mistral',
|
|
96
102
|
enabled: true,
|
|
@@ -9,7 +9,7 @@ import { Center, Flexbox } from 'react-layout-kit';
|
|
|
9
9
|
import { FORM_STYLE } from '@/const/layoutTokens';
|
|
10
10
|
import PluginStore from '@/features/PluginStore';
|
|
11
11
|
import PluginTag from '@/features/PluginStore/PluginItem/PluginTag';
|
|
12
|
-
import { featureFlagsSelectors,
|
|
12
|
+
import { featureFlagsSelectors, useServerConfigStore } from '@/store/serverConfig';
|
|
13
13
|
import { pluginHelpers, useToolStore } from '@/store/tool';
|
|
14
14
|
import { toolSelectors } from '@/store/tool/selectors';
|
|
15
15
|
|
|
@@ -29,7 +29,7 @@ const AgentPlugin = memo(() => {
|
|
|
29
29
|
s.toggleAgentPlugin,
|
|
30
30
|
]);
|
|
31
31
|
|
|
32
|
-
const { showDalle } =
|
|
32
|
+
const { showDalle } = useServerConfigStore(featureFlagsSelectors);
|
|
33
33
|
const installedPlugins = useToolStore(toolSelectors.metaList(showDalle), isEqual);
|
|
34
34
|
const useFetchInstalledPlugins = useToolStore((s) => s.useFetchInstalledPlugins);
|
|
35
35
|
|
|
@@ -11,9 +11,9 @@ import { Flexbox } from 'react-layout-kit';
|
|
|
11
11
|
import PluginStore from '@/features/PluginStore';
|
|
12
12
|
import { useAgentStore } from '@/store/agent';
|
|
13
13
|
import { agentSelectors } from '@/store/agent/selectors';
|
|
14
|
-
import { featureFlagsSelectors, useFeatureFlagStore } from '@/store/featureFlags';
|
|
15
14
|
import { useGlobalStore } from '@/store/global';
|
|
16
15
|
import { modelProviderSelectors } from '@/store/global/selectors';
|
|
16
|
+
import { featureFlagsSelectors, useServerConfigStore } from '@/store/serverConfig';
|
|
17
17
|
import { pluginHelpers, useToolStore } from '@/store/tool';
|
|
18
18
|
import { builtinToolSelectors, pluginSelectors } from '@/store/tool/selectors';
|
|
19
19
|
|
|
@@ -35,7 +35,7 @@ const useStyles = createStyles(({ css, prefixCls }) => ({
|
|
|
35
35
|
const Tools = memo(() => {
|
|
36
36
|
const { t } = useTranslation('setting');
|
|
37
37
|
const list = useToolStore(pluginSelectors.installedPluginMetaList, isEqual);
|
|
38
|
-
const { showDalle } =
|
|
38
|
+
const { showDalle } = useServerConfigStore(featureFlagsSelectors);
|
|
39
39
|
const builtinList = useToolStore(builtinToolSelectors.metaList(showDalle), isEqual);
|
|
40
40
|
|
|
41
41
|
const enablePluginCount = useAgentStore(
|
|
@@ -6,8 +6,8 @@ import { memo, useState } from 'react';
|
|
|
6
6
|
import { useTranslation } from 'react-i18next';
|
|
7
7
|
import { Flexbox } from 'react-layout-kit';
|
|
8
8
|
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
9
|
+
import { useServerConfigStore } from '@/store/serverConfig';
|
|
10
|
+
import { serverConfigSelectors } from '@/store/serverConfig/selectors';
|
|
11
11
|
|
|
12
12
|
import APIKeyForm from './APIKeyForm';
|
|
13
13
|
import AccessCodeForm from './AccessCodeForm';
|
|
@@ -27,7 +27,7 @@ interface InvalidAccessCodeProps {
|
|
|
27
27
|
|
|
28
28
|
const InvalidAccessCode = memo<InvalidAccessCodeProps>(({ id, provider }) => {
|
|
29
29
|
const { t } = useTranslation('error');
|
|
30
|
-
const isEnabledOAuth =
|
|
30
|
+
const isEnabledOAuth = useServerConfigStore(serverConfigSelectors.enabledOAuthSSO);
|
|
31
31
|
const defaultTab = isEnabledOAuth ? Tab.Oauth : Tab.Password;
|
|
32
32
|
const [mode, setMode] = useState<Tab>(defaultTab);
|
|
33
33
|
|
|
@@ -10,7 +10,8 @@ import {
|
|
|
10
10
|
LOBE_THEME_NEUTRAL_COLOR,
|
|
11
11
|
LOBE_THEME_PRIMARY_COLOR,
|
|
12
12
|
} from '@/const/theme';
|
|
13
|
-
import {
|
|
13
|
+
import { getServerGlobalConfig } from '@/server/globalConfig';
|
|
14
|
+
import { ServerConfigStoreProvider } from '@/store/serverConfig';
|
|
14
15
|
import { getAntdLocale } from '@/utils/locale';
|
|
15
16
|
|
|
16
17
|
import AppTheme from './AppTheme';
|
|
@@ -46,6 +47,7 @@ const GlobalLayout = async ({ children }: GlobalLayoutProps) => {
|
|
|
46
47
|
|
|
47
48
|
// get default feature flags to use with ssr
|
|
48
49
|
const serverFeatureFlags = getServerFeatureFlagsValue();
|
|
50
|
+
const serverConfig = getServerGlobalConfig();
|
|
49
51
|
return (
|
|
50
52
|
<StyleRegistry>
|
|
51
53
|
<Locale antdLocale={antdLocale} defaultLang={defaultLang?.value}>
|
|
@@ -55,9 +57,9 @@ const GlobalLayout = async ({ children }: GlobalLayoutProps) => {
|
|
|
55
57
|
defaultPrimaryColor={primaryColor?.value as any}
|
|
56
58
|
>
|
|
57
59
|
<StoreInitialization />
|
|
58
|
-
<
|
|
60
|
+
<ServerConfigStoreProvider featureFlags={serverFeatureFlags} serverConfig={serverConfig}>
|
|
59
61
|
{children}
|
|
60
|
-
</
|
|
62
|
+
</ServerConfigStoreProvider>
|
|
61
63
|
<DebugUI />
|
|
62
64
|
</AppTheme>
|
|
63
65
|
</Locale>
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import {
|
|
2
|
+
OllamaProviderCard,
|
|
3
|
+
OpenAIProviderCard,
|
|
4
|
+
OpenRouterProviderCard,
|
|
5
|
+
TogetherAIProviderCard,
|
|
6
|
+
} from '@/config/modelProviders';
|
|
7
|
+
import { getServerConfig } from '@/config/server';
|
|
8
|
+
import { GlobalServerConfig } from '@/types/serverConfig';
|
|
9
|
+
import { extractEnabledModels, transformToChatModelCards } from '@/utils/parseModels';
|
|
10
|
+
|
|
11
|
+
import { parseAgentConfig } from './parseDefaultAgent';
|
|
12
|
+
|
|
13
|
+
export const getServerGlobalConfig = () => {
|
|
14
|
+
const {
|
|
15
|
+
ENABLE_LANGFUSE,
|
|
16
|
+
ENABLE_OAUTH_SSO,
|
|
17
|
+
|
|
18
|
+
DEFAULT_AGENT_CONFIG,
|
|
19
|
+
OPENAI_MODEL_LIST,
|
|
20
|
+
|
|
21
|
+
ENABLED_MOONSHOT,
|
|
22
|
+
ENABLED_ZHIPU,
|
|
23
|
+
ENABLED_AWS_BEDROCK,
|
|
24
|
+
ENABLED_GOOGLE,
|
|
25
|
+
ENABLED_GROQ,
|
|
26
|
+
ENABLED_PERPLEXITY,
|
|
27
|
+
ENABLED_ANTHROPIC,
|
|
28
|
+
ENABLED_MISTRAL,
|
|
29
|
+
|
|
30
|
+
ENABLED_AZURE_OPENAI,
|
|
31
|
+
AZURE_MODEL_LIST,
|
|
32
|
+
|
|
33
|
+
ENABLE_OLLAMA,
|
|
34
|
+
OLLAMA_MODEL_LIST,
|
|
35
|
+
OLLAMA_PROXY_URL,
|
|
36
|
+
|
|
37
|
+
ENABLED_OPENROUTER,
|
|
38
|
+
OPENROUTER_MODEL_LIST,
|
|
39
|
+
|
|
40
|
+
ENABLED_ZEROONE,
|
|
41
|
+
ENABLED_TOGETHERAI,
|
|
42
|
+
TOGETHERAI_MODEL_LIST,
|
|
43
|
+
} = getServerConfig();
|
|
44
|
+
|
|
45
|
+
const config: GlobalServerConfig = {
|
|
46
|
+
defaultAgent: {
|
|
47
|
+
config: parseAgentConfig(DEFAULT_AGENT_CONFIG),
|
|
48
|
+
},
|
|
49
|
+
|
|
50
|
+
enabledOAuthSSO: ENABLE_OAUTH_SSO,
|
|
51
|
+
languageModel: {
|
|
52
|
+
anthropic: {
|
|
53
|
+
enabled: ENABLED_ANTHROPIC,
|
|
54
|
+
},
|
|
55
|
+
azure: {
|
|
56
|
+
enabled: ENABLED_AZURE_OPENAI,
|
|
57
|
+
enabledModels: extractEnabledModels(AZURE_MODEL_LIST, true),
|
|
58
|
+
serverModelCards: transformToChatModelCards({
|
|
59
|
+
defaultChatModels: [],
|
|
60
|
+
modelString: AZURE_MODEL_LIST,
|
|
61
|
+
withDeploymentName: true,
|
|
62
|
+
}),
|
|
63
|
+
},
|
|
64
|
+
bedrock: { enabled: ENABLED_AWS_BEDROCK },
|
|
65
|
+
google: { enabled: ENABLED_GOOGLE },
|
|
66
|
+
groq: { enabled: ENABLED_GROQ },
|
|
67
|
+
mistral: { enabled: ENABLED_MISTRAL },
|
|
68
|
+
moonshot: { enabled: ENABLED_MOONSHOT },
|
|
69
|
+
ollama: {
|
|
70
|
+
enabled: ENABLE_OLLAMA,
|
|
71
|
+
fetchOnClient: !OLLAMA_PROXY_URL,
|
|
72
|
+
serverModelCards: transformToChatModelCards({
|
|
73
|
+
defaultChatModels: OllamaProviderCard.chatModels,
|
|
74
|
+
modelString: OLLAMA_MODEL_LIST,
|
|
75
|
+
}),
|
|
76
|
+
},
|
|
77
|
+
openai: {
|
|
78
|
+
enabledModels: extractEnabledModels(OPENAI_MODEL_LIST),
|
|
79
|
+
serverModelCards: transformToChatModelCards({
|
|
80
|
+
defaultChatModels: OpenAIProviderCard.chatModels,
|
|
81
|
+
modelString: OPENAI_MODEL_LIST,
|
|
82
|
+
}),
|
|
83
|
+
},
|
|
84
|
+
|
|
85
|
+
openrouter: {
|
|
86
|
+
enabled: ENABLED_OPENROUTER,
|
|
87
|
+
enabledModels: extractEnabledModels(OPENROUTER_MODEL_LIST),
|
|
88
|
+
serverModelCards: transformToChatModelCards({
|
|
89
|
+
defaultChatModels: OpenRouterProviderCard.chatModels,
|
|
90
|
+
modelString: OPENROUTER_MODEL_LIST,
|
|
91
|
+
}),
|
|
92
|
+
},
|
|
93
|
+
perplexity: { enabled: ENABLED_PERPLEXITY },
|
|
94
|
+
|
|
95
|
+
togetherai: {
|
|
96
|
+
enabled: ENABLED_TOGETHERAI,
|
|
97
|
+
enabledModels: extractEnabledModels(TOGETHERAI_MODEL_LIST),
|
|
98
|
+
serverModelCards: transformToChatModelCards({
|
|
99
|
+
defaultChatModels: TogetherAIProviderCard.chatModels,
|
|
100
|
+
modelString: TOGETHERAI_MODEL_LIST,
|
|
101
|
+
}),
|
|
102
|
+
},
|
|
103
|
+
|
|
104
|
+
zeroone: { enabled: ENABLED_ZEROONE },
|
|
105
|
+
zhipu: { enabled: ENABLED_ZHIPU },
|
|
106
|
+
},
|
|
107
|
+
telemetry: {
|
|
108
|
+
langfuse: ENABLE_LANGFUSE,
|
|
109
|
+
},
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
return config;
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
export const getServerDefaultAgentConfig = () => {
|
|
116
|
+
const { DEFAULT_AGENT_CONFIG } = getServerConfig();
|
|
117
|
+
|
|
118
|
+
return parseAgentConfig(DEFAULT_AGENT_CONFIG) || {};
|
|
119
|
+
};
|
|
@@ -1,121 +1,12 @@
|
|
|
1
|
-
import {
|
|
2
|
-
OllamaProviderCard,
|
|
3
|
-
OpenAIProviderCard,
|
|
4
|
-
OpenRouterProviderCard,
|
|
5
|
-
TogetherAIProviderCard,
|
|
6
|
-
} from '@/config/modelProviders';
|
|
7
|
-
import { getServerConfig } from '@/config/server';
|
|
8
1
|
import { publicProcedure, router } from '@/libs/trpc';
|
|
9
|
-
import {
|
|
10
|
-
import { GlobalServerConfig } from '@/types/serverConfig';
|
|
11
|
-
import { extractEnabledModels, transformToChatModelCards } from '@/utils/parseModels';
|
|
2
|
+
import { getServerDefaultAgentConfig, getServerGlobalConfig } from '@/server/globalConfig';
|
|
12
3
|
|
|
13
4
|
export const configRouter = router({
|
|
14
5
|
getDefaultAgentConfig: publicProcedure.query(async () => {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
return parseAgentConfig(DEFAULT_AGENT_CONFIG) || {};
|
|
6
|
+
return getServerDefaultAgentConfig();
|
|
18
7
|
}),
|
|
19
8
|
|
|
20
9
|
getGlobalConfig: publicProcedure.query(async () => {
|
|
21
|
-
|
|
22
|
-
ENABLE_LANGFUSE,
|
|
23
|
-
ENABLE_OAUTH_SSO,
|
|
24
|
-
|
|
25
|
-
DEFAULT_AGENT_CONFIG,
|
|
26
|
-
OPENAI_MODEL_LIST,
|
|
27
|
-
|
|
28
|
-
ENABLED_MOONSHOT,
|
|
29
|
-
ENABLED_ZHIPU,
|
|
30
|
-
ENABLED_AWS_BEDROCK,
|
|
31
|
-
ENABLED_GOOGLE,
|
|
32
|
-
ENABLED_GROQ,
|
|
33
|
-
ENABLED_PERPLEXITY,
|
|
34
|
-
ENABLED_ANTHROPIC,
|
|
35
|
-
ENABLED_MISTRAL,
|
|
36
|
-
|
|
37
|
-
ENABLED_AZURE_OPENAI,
|
|
38
|
-
AZURE_MODEL_LIST,
|
|
39
|
-
|
|
40
|
-
ENABLE_OLLAMA,
|
|
41
|
-
OLLAMA_MODEL_LIST,
|
|
42
|
-
OLLAMA_PROXY_URL,
|
|
43
|
-
|
|
44
|
-
ENABLED_OPENROUTER,
|
|
45
|
-
OPENROUTER_MODEL_LIST,
|
|
46
|
-
|
|
47
|
-
ENABLED_ZEROONE,
|
|
48
|
-
ENABLED_TOGETHERAI,
|
|
49
|
-
TOGETHERAI_MODEL_LIST,
|
|
50
|
-
} = getServerConfig();
|
|
51
|
-
|
|
52
|
-
const config: GlobalServerConfig = {
|
|
53
|
-
defaultAgent: {
|
|
54
|
-
config: parseAgentConfig(DEFAULT_AGENT_CONFIG),
|
|
55
|
-
},
|
|
56
|
-
|
|
57
|
-
enabledOAuthSSO: ENABLE_OAUTH_SSO,
|
|
58
|
-
languageModel: {
|
|
59
|
-
anthropic: {
|
|
60
|
-
enabled: ENABLED_ANTHROPIC,
|
|
61
|
-
},
|
|
62
|
-
azure: {
|
|
63
|
-
enabled: ENABLED_AZURE_OPENAI,
|
|
64
|
-
enabledModels: extractEnabledModels(AZURE_MODEL_LIST, true),
|
|
65
|
-
serverModelCards: transformToChatModelCards({
|
|
66
|
-
defaultChatModels: [],
|
|
67
|
-
modelString: AZURE_MODEL_LIST,
|
|
68
|
-
withDeploymentName: true,
|
|
69
|
-
}),
|
|
70
|
-
},
|
|
71
|
-
bedrock: { enabled: ENABLED_AWS_BEDROCK },
|
|
72
|
-
google: { enabled: ENABLED_GOOGLE },
|
|
73
|
-
groq: { enabled: ENABLED_GROQ },
|
|
74
|
-
mistral: { enabled: ENABLED_MISTRAL },
|
|
75
|
-
moonshot: { enabled: ENABLED_MOONSHOT },
|
|
76
|
-
ollama: {
|
|
77
|
-
enabled: ENABLE_OLLAMA,
|
|
78
|
-
fetchOnClient: !OLLAMA_PROXY_URL,
|
|
79
|
-
serverModelCards: transformToChatModelCards({
|
|
80
|
-
defaultChatModels: OllamaProviderCard.chatModels,
|
|
81
|
-
modelString: OLLAMA_MODEL_LIST,
|
|
82
|
-
}),
|
|
83
|
-
},
|
|
84
|
-
openai: {
|
|
85
|
-
enabledModels: extractEnabledModels(OPENAI_MODEL_LIST),
|
|
86
|
-
serverModelCards: transformToChatModelCards({
|
|
87
|
-
defaultChatModels: OpenAIProviderCard.chatModels,
|
|
88
|
-
modelString: OPENAI_MODEL_LIST,
|
|
89
|
-
}),
|
|
90
|
-
},
|
|
91
|
-
|
|
92
|
-
openrouter: {
|
|
93
|
-
enabled: ENABLED_OPENROUTER,
|
|
94
|
-
enabledModels: extractEnabledModels(OPENROUTER_MODEL_LIST),
|
|
95
|
-
serverModelCards: transformToChatModelCards({
|
|
96
|
-
defaultChatModels: OpenRouterProviderCard.chatModels,
|
|
97
|
-
modelString: OPENROUTER_MODEL_LIST,
|
|
98
|
-
}),
|
|
99
|
-
},
|
|
100
|
-
perplexity: { enabled: ENABLED_PERPLEXITY },
|
|
101
|
-
|
|
102
|
-
togetherai: {
|
|
103
|
-
enabled: ENABLED_TOGETHERAI,
|
|
104
|
-
enabledModels: extractEnabledModels(TOGETHERAI_MODEL_LIST),
|
|
105
|
-
serverModelCards: transformToChatModelCards({
|
|
106
|
-
defaultChatModels: TogetherAIProviderCard.chatModels,
|
|
107
|
-
modelString: TOGETHERAI_MODEL_LIST,
|
|
108
|
-
}),
|
|
109
|
-
},
|
|
110
|
-
|
|
111
|
-
zeroone: { enabled: ENABLED_ZEROONE },
|
|
112
|
-
zhipu: { enabled: ENABLED_ZHIPU },
|
|
113
|
-
},
|
|
114
|
-
telemetry: {
|
|
115
|
-
langfuse: ENABLE_LANGFUSE,
|
|
116
|
-
},
|
|
117
|
-
};
|
|
118
|
-
|
|
119
|
-
return config;
|
|
10
|
+
return getServerGlobalConfig();
|
|
120
11
|
}),
|
|
121
12
|
});
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import { GlobalStore } from '@/store/global';
|
|
2
2
|
|
|
3
3
|
export const commonSelectors = {
|
|
4
|
-
enabledOAuthSSO: (s: GlobalStore) => s.serverConfig.enabledOAuthSSO,
|
|
5
|
-
enabledTelemetryChat: (s: GlobalStore) => s.serverConfig.telemetry.langfuse || false,
|
|
6
4
|
userAvatar: (s: GlobalStore) => s.avatar || '',
|
|
7
5
|
userId: (s: GlobalStore) => s.userId,
|
|
8
6
|
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { ReactNode, memo } from 'react';
|
|
4
|
+
|
|
5
|
+
import { IFeatureFlags } from '@/config/featureFlags';
|
|
6
|
+
import { GlobalServerConfig } from '@/types/serverConfig';
|
|
7
|
+
|
|
8
|
+
import { Provider, createServerConfigStore } from './store';
|
|
9
|
+
|
|
10
|
+
interface GlobalStoreProviderProps {
|
|
11
|
+
children: ReactNode;
|
|
12
|
+
featureFlags?: Partial<IFeatureFlags>;
|
|
13
|
+
serverConfig?: GlobalServerConfig;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export const ServerConfigStoreProvider = memo<GlobalStoreProviderProps>(
|
|
17
|
+
({ children, featureFlags, serverConfig }) => (
|
|
18
|
+
<Provider createStore={() => createServerConfigStore({ featureFlags, serverConfig })}>
|
|
19
|
+
{children}
|
|
20
|
+
</Provider>
|
|
21
|
+
),
|
|
22
|
+
);
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import { featureFlagsSelectors, serverConfigSelectors } from './selectors';
|
|
4
|
+
import { initServerConfigStore } from './store';
|
|
5
|
+
|
|
6
|
+
vi.mock('zustand/traditional');
|
|
7
|
+
|
|
8
|
+
describe('featureFlagsSelectors', () => {
|
|
9
|
+
it('should return mapped feature flags from store', () => {
|
|
10
|
+
const store = initServerConfigStore({
|
|
11
|
+
featureFlags: {
|
|
12
|
+
language_model_settings: false,
|
|
13
|
+
edit_agent: false,
|
|
14
|
+
},
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
const result = featureFlagsSelectors(store.getState());
|
|
18
|
+
|
|
19
|
+
expect(result).toEqual({
|
|
20
|
+
enableWebrtc: true,
|
|
21
|
+
isAgentEditable: false,
|
|
22
|
+
showCreateSession: true,
|
|
23
|
+
showDalle: true,
|
|
24
|
+
showLLM: false,
|
|
25
|
+
showOpenAIApiKey: true,
|
|
26
|
+
showOpenAIProxyUrl: true,
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
describe('serverConfigSelectors', () => {
|
|
32
|
+
describe('enabledOAuthSSO', () => {
|
|
33
|
+
it('should return enabledOAuthSSO value from store', () => {
|
|
34
|
+
const store = initServerConfigStore({
|
|
35
|
+
serverConfig: {
|
|
36
|
+
enabledOAuthSSO: true,
|
|
37
|
+
telemetry: {},
|
|
38
|
+
},
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
const result = serverConfigSelectors.enabledOAuthSSO(store.getState());
|
|
42
|
+
|
|
43
|
+
expect(result).toBe(true);
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
describe('enabledTelemetryChat', () => {
|
|
48
|
+
it('should return langfuse value from store when defined', () => {
|
|
49
|
+
const store = initServerConfigStore({
|
|
50
|
+
serverConfig: {
|
|
51
|
+
telemetry: { langfuse: true },
|
|
52
|
+
},
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
const result = serverConfigSelectors.enabledTelemetryChat(store.getState());
|
|
56
|
+
|
|
57
|
+
expect(result).toBe(true);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it('should return false when langfuse is not defined', () => {
|
|
61
|
+
const store = initServerConfigStore({
|
|
62
|
+
serverConfig: {
|
|
63
|
+
telemetry: {},
|
|
64
|
+
},
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
const result = serverConfigSelectors.enabledTelemetryChat(store.getState());
|
|
68
|
+
|
|
69
|
+
expect(result).toBe(false);
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
});
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { mapFeatureFlagsEnvToState } from '@/config/featureFlags';
|
|
2
|
+
|
|
3
|
+
import { ServerConfigStore } from './store';
|
|
4
|
+
|
|
5
|
+
export const featureFlagsSelectors = (s: ServerConfigStore) =>
|
|
6
|
+
mapFeatureFlagsEnvToState(s.featureFlags);
|
|
7
|
+
|
|
8
|
+
export const serverConfigSelectors = {
|
|
9
|
+
enabledOAuthSSO: (s: ServerConfigStore) => s.serverConfig.enabledOAuthSSO,
|
|
10
|
+
enabledTelemetryChat: (s: ServerConfigStore) => s.serverConfig.telemetry.langfuse || false,
|
|
11
|
+
};
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { act } from '@testing-library/react';
|
|
2
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
3
|
+
|
|
4
|
+
import { DEFAULT_FEATURE_FLAGS } from '@/config/featureFlags';
|
|
5
|
+
|
|
6
|
+
import { ServerConfigStore, createServerConfigStore, initServerConfigStore } from './store';
|
|
7
|
+
|
|
8
|
+
describe('createServerConfigStore', () => {
|
|
9
|
+
beforeEach(() => {
|
|
10
|
+
// 每个测试用例前重置模块状态
|
|
11
|
+
vi.resetModules();
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it('should create a singleton store', () => {
|
|
15
|
+
const store1 = createServerConfigStore();
|
|
16
|
+
const store2 = createServerConfigStore();
|
|
17
|
+
|
|
18
|
+
expect(store1).toBe(store2);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('should initialize store with default state', () => {
|
|
22
|
+
const store = createServerConfigStore();
|
|
23
|
+
|
|
24
|
+
expect(store.getState()).toEqual({
|
|
25
|
+
featureFlags: DEFAULT_FEATURE_FLAGS,
|
|
26
|
+
serverConfig: { telemetry: {} },
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it('should initialize store with custom initial state', () => {
|
|
31
|
+
const initialState: Partial<ServerConfigStore> = {
|
|
32
|
+
featureFlags: { edit_agent: false },
|
|
33
|
+
serverConfig: { telemetry: { langfuse: true } },
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const store = initServerConfigStore(initialState);
|
|
37
|
+
|
|
38
|
+
expect(store.getState().featureFlags.edit_agent).toBeFalsy();
|
|
39
|
+
expect(store.getState().serverConfig).toEqual({
|
|
40
|
+
telemetry: { langfuse: true },
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it('should update store state correctly', () => {
|
|
45
|
+
const store = createServerConfigStore();
|
|
46
|
+
|
|
47
|
+
act(() => {
|
|
48
|
+
store.setState({ featureFlags: { dalle: false } });
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
expect(store.getState().featureFlags.dalle).toBeFalsy();
|
|
52
|
+
});
|
|
53
|
+
});
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { StoreApi } from 'zustand';
|
|
2
|
+
import { createContext } from 'zustand-utils';
|
|
3
|
+
import { devtools } from 'zustand/middleware';
|
|
4
|
+
import { shallow } from 'zustand/shallow';
|
|
5
|
+
import { createWithEqualityFn } from 'zustand/traditional';
|
|
6
|
+
import { StateCreator } from 'zustand/vanilla';
|
|
7
|
+
|
|
8
|
+
import { DEFAULT_FEATURE_FLAGS, IFeatureFlags } from '@/config/featureFlags';
|
|
9
|
+
import { GlobalServerConfig } from '@/types/serverConfig';
|
|
10
|
+
import { isDev } from '@/utils/env';
|
|
11
|
+
import { merge } from '@/utils/merge';
|
|
12
|
+
import { StoreApiWithSelector } from '@/utils/zustand';
|
|
13
|
+
|
|
14
|
+
const initialState: ServerConfigStore = {
|
|
15
|
+
featureFlags: DEFAULT_FEATURE_FLAGS,
|
|
16
|
+
serverConfig: { telemetry: {} },
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
// =============== 聚合 createStoreFn ============ //
|
|
20
|
+
|
|
21
|
+
export interface ServerConfigStore {
|
|
22
|
+
featureFlags: IFeatureFlags;
|
|
23
|
+
serverConfig: GlobalServerConfig;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
type CreateStore = (
|
|
27
|
+
initState: Partial<ServerConfigStore>,
|
|
28
|
+
) => StateCreator<ServerConfigStore, [['zustand/devtools', never]]>;
|
|
29
|
+
|
|
30
|
+
const createStore: CreateStore = (runtimeState) => () => ({
|
|
31
|
+
...merge(initialState, runtimeState),
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
// =============== 实装 useStore ============ //
|
|
35
|
+
|
|
36
|
+
let store: StoreApi<ServerConfigStore>;
|
|
37
|
+
|
|
38
|
+
export const initServerConfigStore = (initState: Partial<ServerConfigStore>) =>
|
|
39
|
+
createWithEqualityFn<ServerConfigStore>()(
|
|
40
|
+
devtools(createStore(initState || {}), {
|
|
41
|
+
name: 'LobeChat_ServerConfig' + (isDev ? '_DEV' : ''),
|
|
42
|
+
}),
|
|
43
|
+
shallow,
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
export const createServerConfigStore = (initState?: Partial<ServerConfigStore>) => {
|
|
47
|
+
// make sure there is only one store
|
|
48
|
+
if (!store) {
|
|
49
|
+
store = createWithEqualityFn<ServerConfigStore>()(
|
|
50
|
+
devtools(createStore(initState || {}), {
|
|
51
|
+
name: 'LobeChat_ServerConfig' + (isDev ? '_DEV' : ''),
|
|
52
|
+
}),
|
|
53
|
+
shallow,
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return store;
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
export const { useStore: useServerConfigStore, Provider } =
|
|
61
|
+
createContext<StoreApiWithSelector<ServerConfigStore>>();
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
|
-
import { ReactNode, memo } from 'react';
|
|
4
|
-
|
|
5
|
-
import { IFeatureFlags } from '@/config/featureFlags';
|
|
6
|
-
|
|
7
|
-
import { Provider, createFeatureFlagsStore } from './store';
|
|
8
|
-
|
|
9
|
-
interface GlobalStoreProviderProps {
|
|
10
|
-
children: ReactNode;
|
|
11
|
-
featureFlags?: Partial<IFeatureFlags>;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export const FeatureFlagStoreProvider = memo<GlobalStoreProviderProps>(
|
|
15
|
-
({ children, featureFlags }) => (
|
|
16
|
-
<Provider createStore={() => createFeatureFlagsStore(featureFlags)}>{children}</Provider>
|
|
17
|
-
),
|
|
18
|
-
);
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import { StoreApi } from 'zustand';
|
|
2
|
-
import { createContext } from 'zustand-utils';
|
|
3
|
-
import { devtools } from 'zustand/middleware';
|
|
4
|
-
import { shallow } from 'zustand/shallow';
|
|
5
|
-
import { createWithEqualityFn } from 'zustand/traditional';
|
|
6
|
-
import { StateCreator } from 'zustand/vanilla';
|
|
7
|
-
|
|
8
|
-
import { DEFAULT_FEATURE_FLAGS, IFeatureFlags } from '@/config/featureFlags';
|
|
9
|
-
import { isDev } from '@/utils/env';
|
|
10
|
-
import { StoreApiWithSelector } from '@/utils/zustand';
|
|
11
|
-
|
|
12
|
-
// =============== 聚合 createStoreFn ============ //
|
|
13
|
-
|
|
14
|
-
export type FeatureFlagStore = IFeatureFlags;
|
|
15
|
-
|
|
16
|
-
const createStore: (
|
|
17
|
-
initState: Partial<FeatureFlagStore>,
|
|
18
|
-
) => StateCreator<FeatureFlagStore, [['zustand/devtools', never]]> = (runtimeState) => () => ({
|
|
19
|
-
...DEFAULT_FEATURE_FLAGS,
|
|
20
|
-
...runtimeState,
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
// =============== 实装 useStore ============ //
|
|
24
|
-
|
|
25
|
-
let store: StoreApi<FeatureFlagStore>;
|
|
26
|
-
|
|
27
|
-
export const createFeatureFlagsStore = (initState?: Partial<FeatureFlagStore>) => {
|
|
28
|
-
// make sure there is only one store
|
|
29
|
-
if (!store) {
|
|
30
|
-
store = createWithEqualityFn<FeatureFlagStore>()(
|
|
31
|
-
devtools(createStore(initState || {}), {
|
|
32
|
-
name: 'LobeChat_FeatureFlags' + (isDev ? '_DEV' : ''),
|
|
33
|
-
}),
|
|
34
|
-
shallow,
|
|
35
|
-
);
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
return store;
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
export const { useStore: useFeatureFlagStore, Provider } =
|
|
42
|
-
createContext<StoreApiWithSelector<FeatureFlagStore>>();
|
|
File without changes
|
|
File without changes
|