@lobehub/chat 0.42.0 → 0.42.2
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 +61 -0
- package/package.json +1 -1
- package/src/features/AvatarWithUpload/index.tsx +2 -2
- package/src/features/FolderPanel/index.tsx +8 -7
- package/src/features/SideBar/BottomActions.tsx +3 -3
- package/src/features/SideBar/TopActions.tsx +3 -3
- package/src/features/SideBar/index.tsx +2 -2
- package/src/helpers/export.ts +2 -2
- package/src/hooks/useImportConfig.ts +2 -2
- package/src/layout/index.tsx +4 -4
- package/src/pages/chat/SessionList/List/SessionItem.tsx +2 -2
- package/src/pages/chat/[id]/Conversation/ChatList/Error/ApiKeyForm.tsx +2 -2
- package/src/pages/chat/[id]/Conversation/ChatList/Error/InvalidAccess.tsx +2 -2
- package/src/pages/chat/[id]/Conversation/Input/index.tsx +7 -3
- package/src/pages/chat/[id]/Header/index.tsx +4 -4
- package/src/pages/chat/[id]/Sidebar/Topic/index.tsx +5 -2
- package/src/pages/chat/[id]/Sidebar/index.tsx +4 -4
- package/src/pages/chat/[id]/layout.tsx +2 -7
- package/src/pages/index/Loading.tsx +35 -0
- package/src/pages/index.page.tsx +4 -19
- package/src/pages/settings/Settings/Agent.tsx +4 -4
- package/src/pages/settings/Settings/Common.tsx +3 -3
- package/src/pages/settings/ThemeSwatches/ThemeSwatchesNeutral.tsx +5 -2
- package/src/pages/settings/ThemeSwatches/ThemeSwatchesPrimary.tsx +5 -2
- package/src/pages/settings/layout.tsx +2 -7
- package/src/services/chatModel.ts +4 -4
- package/src/services/plugin.ts +2 -2
- package/src/store/global/hooks/index.ts +2 -0
- package/src/store/{settings → global}/hooks/useHydrated.ts +3 -3
- package/src/store/global/hooks/useSwitchSideBarOnInit.ts +17 -0
- package/src/store/global/index.ts +3 -0
- package/src/store/global/initialState.ts +43 -0
- package/src/store/global/selectors.ts +32 -0
- package/src/store/{settings → global}/slices/agent.ts +2 -7
- package/src/store/global/slices/common.ts +56 -0
- package/src/store/{settings/slices/common.ts → global/slices/settings.ts} +7 -34
- package/src/store/{settings → global}/store.ts +15 -12
- package/src/store/session/slices/chat/selectors/chat.ts +2 -2
- package/src/store/session/slices/session/action.ts +3 -3
- package/src/store/settings/index.ts +0 -3
- package/src/store/settings/initialState.ts +0 -29
- package/src/store/settings/selectors.ts +0 -32
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,67 @@
|
|
|
2
2
|
|
|
3
3
|
# Changelog
|
|
4
4
|
|
|
5
|
+
### [Version 0.42.2](https://github.com/lobehub/lobe-chat/compare/v0.42.1...v0.42.2)
|
|
6
|
+
|
|
7
|
+
<sup>Released on **2023-08-12**</sup>
|
|
8
|
+
|
|
9
|
+
#### ♻ Code Refactoring
|
|
10
|
+
|
|
11
|
+
- **misc**: 将 useSettings 更名为 useGlobalStore, 将原本的 settings 更名为 global, 收敛切换 SideBar 方法为 useSwitchSideBarOnInit, 重构需本地缓存的状态为 preference.
|
|
12
|
+
|
|
13
|
+
#### 🐛 Bug Fixes
|
|
14
|
+
|
|
15
|
+
- **misc**: 修正移除 session 时的路由跳转逻辑.
|
|
16
|
+
|
|
17
|
+
<br/>
|
|
18
|
+
|
|
19
|
+
<details>
|
|
20
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
|
21
|
+
|
|
22
|
+
#### Code refactoring
|
|
23
|
+
|
|
24
|
+
- **misc**: 将 useSettings 更名为 useGlobalStore ([bdde7df](https://github.com/lobehub/lobe-chat/commit/bdde7df))
|
|
25
|
+
- **misc**: 将原本的 settings 更名为 global ([e42d34c](https://github.com/lobehub/lobe-chat/commit/e42d34c))
|
|
26
|
+
- **misc**: 收敛切换 SideBar 方法为 useSwitchSideBarOnInit ([bbad38f](https://github.com/lobehub/lobe-chat/commit/bbad38f))
|
|
27
|
+
- **misc**: 重构需本地缓存的状态为 preference ([8359b62](https://github.com/lobehub/lobe-chat/commit/8359b62))
|
|
28
|
+
|
|
29
|
+
#### What's fixed
|
|
30
|
+
|
|
31
|
+
- **misc**: 修正移除 session 时的路由跳转逻辑 ([8b7838d](https://github.com/lobehub/lobe-chat/commit/8b7838d))
|
|
32
|
+
|
|
33
|
+
</details>
|
|
34
|
+
|
|
35
|
+
<div align="right">
|
|
36
|
+
|
|
37
|
+
[](#readme-top)
|
|
38
|
+
|
|
39
|
+
</div>
|
|
40
|
+
|
|
41
|
+
### [Version 0.42.1](https://github.com/lobehub/lobe-chat/compare/v0.42.0...v0.42.1)
|
|
42
|
+
|
|
43
|
+
<sup>Released on **2023-08-12**</sup>
|
|
44
|
+
|
|
45
|
+
#### 💄 Styles
|
|
46
|
+
|
|
47
|
+
- **misc**: 优化 App 首页 Loading 态.
|
|
48
|
+
|
|
49
|
+
<br/>
|
|
50
|
+
|
|
51
|
+
<details>
|
|
52
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
|
53
|
+
|
|
54
|
+
#### Styles
|
|
55
|
+
|
|
56
|
+
- **misc**: 优化 App 首页 Loading 态 ([72104e8](https://github.com/lobehub/lobe-chat/commit/72104e8))
|
|
57
|
+
|
|
58
|
+
</details>
|
|
59
|
+
|
|
60
|
+
<div align="right">
|
|
61
|
+
|
|
62
|
+
[](#readme-top)
|
|
63
|
+
|
|
64
|
+
</div>
|
|
65
|
+
|
|
5
66
|
## [Version 0.42.0](https://github.com/lobehub/lobe-chat/compare/v0.41.2...v0.42.0)
|
|
6
67
|
|
|
7
68
|
<sup>Released on **2023-08-11**</sup>
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@ import { Upload } from 'antd';
|
|
|
3
3
|
import { createStyles } from 'antd-style';
|
|
4
4
|
import { memo } from 'react';
|
|
5
5
|
|
|
6
|
-
import {
|
|
6
|
+
import { useGlobalStore } from '@/store/global';
|
|
7
7
|
import { createUploadImageHandler } from '@/utils/uploadFIle';
|
|
8
8
|
|
|
9
9
|
const useStyle = createStyles(
|
|
@@ -27,7 +27,7 @@ interface AvatarWithUploadProps {
|
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
const AvatarWithUpload = memo<AvatarWithUploadProps>(({ size = 40 }) => {
|
|
30
|
-
const [avatar, setSettings] =
|
|
30
|
+
const [avatar, setSettings] = useGlobalStore((st) => [st.settings.avatar, st.setSettings]);
|
|
31
31
|
const { styles } = useStyle();
|
|
32
32
|
|
|
33
33
|
const handleUploadAvatar = createUploadImageHandler((avatar) => {
|
|
@@ -4,7 +4,7 @@ import isEqual from 'fast-deep-equal';
|
|
|
4
4
|
import { PropsWithChildren, memo, useState } from 'react';
|
|
5
5
|
|
|
6
6
|
import { FOLDER_WIDTH } from '@/const/layoutTokens';
|
|
7
|
-
import {
|
|
7
|
+
import { useGlobalStore } from '@/store/global';
|
|
8
8
|
|
|
9
9
|
export const useStyles = createStyles(({ css, token }) => ({
|
|
10
10
|
panel: css`
|
|
@@ -16,9 +16,10 @@ export const useStyles = createStyles(({ css, token }) => ({
|
|
|
16
16
|
|
|
17
17
|
const FolderPanel = memo<PropsWithChildren>(({ children }) => {
|
|
18
18
|
const { styles } = useStyles();
|
|
19
|
-
const [sessionsWidth, sessionExpandable] =
|
|
20
|
-
s.sessionsWidth,
|
|
21
|
-
s.
|
|
19
|
+
const [sessionsWidth, sessionExpandable, updatePreference] = useGlobalStore((s) => [
|
|
20
|
+
s.preference.sessionsWidth,
|
|
21
|
+
s.preference.showSessionPanel,
|
|
22
|
+
s.updatePreference,
|
|
22
23
|
]);
|
|
23
24
|
const [tmpWidth, setWidth] = useState(sessionsWidth);
|
|
24
25
|
if (tmpWidth !== sessionsWidth) setWidth(sessionsWidth);
|
|
@@ -31,9 +32,9 @@ const FolderPanel = memo<PropsWithChildren>(({ children }) => {
|
|
|
31
32
|
maxWidth={400}
|
|
32
33
|
minWidth={FOLDER_WIDTH}
|
|
33
34
|
onExpandChange={(expand) => {
|
|
34
|
-
|
|
35
|
-
sessionExpandable: expand,
|
|
35
|
+
updatePreference({
|
|
36
36
|
sessionsWidth: expand ? 320 : 0,
|
|
37
|
+
showSessionPanel: expand,
|
|
37
38
|
});
|
|
38
39
|
}}
|
|
39
40
|
onSizeChange={(_, size) => {
|
|
@@ -44,7 +45,7 @@ const FolderPanel = memo<PropsWithChildren>(({ children }) => {
|
|
|
44
45
|
if (isEqual(nextWidth, sessionsWidth)) return;
|
|
45
46
|
|
|
46
47
|
setWidth(nextWidth);
|
|
47
|
-
|
|
48
|
+
updatePreference({ sessionsWidth: nextWidth });
|
|
48
49
|
}}
|
|
49
50
|
placement="left"
|
|
50
51
|
size={{ height: '100vh', width: sessionsWidth }}
|
|
@@ -18,11 +18,11 @@ import DiscordIcon from '@/components/DiscordIcon';
|
|
|
18
18
|
import { ABOUT, CHANGELOG, DISCORD, FEEDBACK, GITHUB } from '@/const/url';
|
|
19
19
|
import { useExportConfig } from '@/hooks/useExportConfig';
|
|
20
20
|
import { useImportConfig } from '@/hooks/useImportConfig';
|
|
21
|
-
import {
|
|
21
|
+
import { GlobalStore } from '@/store/global';
|
|
22
22
|
|
|
23
23
|
export interface BottomActionProps {
|
|
24
|
-
setTab:
|
|
25
|
-
tab:
|
|
24
|
+
setTab: GlobalStore['switchSideBar'];
|
|
25
|
+
tab: GlobalStore['sidebarKey'];
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
const BottomActions = memo<BottomActionProps>(({ tab, setTab }) => {
|
|
@@ -4,11 +4,11 @@ import Router from 'next/router';
|
|
|
4
4
|
import { memo } from 'react';
|
|
5
5
|
import { useTranslation } from 'react-i18next';
|
|
6
6
|
|
|
7
|
-
import {
|
|
7
|
+
import { GlobalStore } from '@/store/global';
|
|
8
8
|
|
|
9
9
|
export interface TopActionProps {
|
|
10
|
-
setTab:
|
|
11
|
-
tab:
|
|
10
|
+
setTab: GlobalStore['switchSideBar'];
|
|
11
|
+
tab: GlobalStore['sidebarKey'];
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
const TopActions = memo<TopActionProps>(({ tab, setTab }) => {
|
|
@@ -2,13 +2,13 @@ import { SideNav } from '@lobehub/ui';
|
|
|
2
2
|
import { memo } from 'react';
|
|
3
3
|
|
|
4
4
|
import AvatarWithUpload from '@/features/AvatarWithUpload';
|
|
5
|
-
import {
|
|
5
|
+
import { useGlobalStore } from '@/store/global';
|
|
6
6
|
|
|
7
7
|
import BottomActions from './BottomActions';
|
|
8
8
|
import TopActions from './TopActions';
|
|
9
9
|
|
|
10
10
|
export default memo(() => {
|
|
11
|
-
const [tab, setTab] =
|
|
11
|
+
const [tab, setTab] = useGlobalStore((s) => [s.sidebarKey, s.switchSideBar]);
|
|
12
12
|
|
|
13
13
|
return (
|
|
14
14
|
<SideNav
|
package/src/helpers/export.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
import { settingsSelectors, useGlobalStore } from '@/store/global';
|
|
1
2
|
import { sessionSelectors, useSessionStore } from '@/store/session';
|
|
2
|
-
import { settingsSelectors, useSettings } from '@/store/settings';
|
|
3
3
|
import { createConfigFile, exportConfigFile } from '@/utils/config';
|
|
4
4
|
|
|
5
5
|
const getAgents = () => sessionSelectors.exportAgents(useSessionStore.getState());
|
|
@@ -8,7 +8,7 @@ const getAgent = (id: string) => sessionSelectors.getExportAgent(id)(useSessionS
|
|
|
8
8
|
const getSessions = () => sessionSelectors.exportSessions(useSessionStore.getState());
|
|
9
9
|
const getSession = (id: string) => sessionSelectors.getSessionById(id)(useSessionStore.getState());
|
|
10
10
|
|
|
11
|
-
const getSettings = () => settingsSelectors.exportSettings(
|
|
11
|
+
const getSettings = () => settingsSelectors.exportSettings(useGlobalStore.getState());
|
|
12
12
|
|
|
13
13
|
export const exportAgents = () => {
|
|
14
14
|
const sessions = getAgents();
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { useMemo } from 'react';
|
|
2
2
|
|
|
3
|
+
import { useGlobalStore } from '@/store/global';
|
|
3
4
|
import { useSessionStore } from '@/store/session';
|
|
4
|
-
import { useSettings } from '@/store/settings';
|
|
5
5
|
import { importConfigFile } from '@/utils/config';
|
|
6
6
|
|
|
7
7
|
export const useImportConfig = () => {
|
|
8
8
|
const importSessions = useSessionStore((s) => s.importSessions);
|
|
9
|
-
const importAppSettings =
|
|
9
|
+
const importAppSettings = useGlobalStore((s) => s.importAppSettings);
|
|
10
10
|
|
|
11
11
|
const importConfig = (info: any) => {
|
|
12
12
|
importConfigFile(info, (config) => {
|
package/src/layout/index.tsx
CHANGED
|
@@ -5,8 +5,8 @@ import 'antd/dist/reset.css';
|
|
|
5
5
|
import Zh_CN from 'antd/locale/zh_CN';
|
|
6
6
|
import { PropsWithChildren, useCallback, useEffect } from 'react';
|
|
7
7
|
|
|
8
|
+
import { useGlobalStore } from '@/store/global';
|
|
8
9
|
import { useSessionStore } from '@/store/session';
|
|
9
|
-
import { useSettings } from '@/store/settings';
|
|
10
10
|
import { GlobalStyle } from '@/styles';
|
|
11
11
|
|
|
12
12
|
import i18n from '../locales';
|
|
@@ -28,8 +28,8 @@ const Layout = ({ children }: PropsWithChildren) => {
|
|
|
28
28
|
};
|
|
29
29
|
|
|
30
30
|
export default ({ children }: PropsWithChildren) => {
|
|
31
|
-
const themeMode =
|
|
32
|
-
const [primaryColor, neutralColor] =
|
|
31
|
+
const themeMode = useGlobalStore((s) => s.settings.themeMode);
|
|
32
|
+
const [primaryColor, neutralColor] = useGlobalStore((s) => [
|
|
33
33
|
s.settings.primaryColor,
|
|
34
34
|
s.settings.neutralColor,
|
|
35
35
|
]);
|
|
@@ -40,7 +40,7 @@ export default ({ children }: PropsWithChildren) => {
|
|
|
40
40
|
useEffect(() => {
|
|
41
41
|
// refs: https://github.com/pmndrs/zustand/blob/main/docs/integrations/persisting-store-data.md#hashydrated
|
|
42
42
|
useSessionStore.persist.rehydrate();
|
|
43
|
-
|
|
43
|
+
useGlobalStore.persist.rehydrate();
|
|
44
44
|
}, []);
|
|
45
45
|
|
|
46
46
|
const genCustomToken: any = useCallback(
|
|
@@ -8,8 +8,8 @@ import { Flexbox } from 'react-layout-kit';
|
|
|
8
8
|
import { shallow } from 'zustand/shallow';
|
|
9
9
|
|
|
10
10
|
import { exportSingleAgent, exportSingleSession } from '@/helpers/export';
|
|
11
|
+
import { useGlobalStore } from '@/store/global';
|
|
11
12
|
import { agentSelectors, chatSelectors, sessionSelectors, useSessionStore } from '@/store/session';
|
|
12
|
-
import { useSettings } from '@/store/settings';
|
|
13
13
|
|
|
14
14
|
import { useStyles } from './style';
|
|
15
15
|
|
|
@@ -29,7 +29,7 @@ const SessionItem: FC<SessionItemProps> = memo(({ id, active = true, loading })
|
|
|
29
29
|
const { t } = useTranslation('common');
|
|
30
30
|
|
|
31
31
|
const { styles } = useStyles();
|
|
32
|
-
const [defaultModel] =
|
|
32
|
+
const [defaultModel] = useGlobalStore((s) => [s.settings.defaultAgent.config?.model]);
|
|
33
33
|
|
|
34
34
|
const [
|
|
35
35
|
pin,
|
|
@@ -4,14 +4,14 @@ import { memo } from 'react';
|
|
|
4
4
|
import { useTranslation } from 'react-i18next';
|
|
5
5
|
import { Center, Flexbox } from 'react-layout-kit';
|
|
6
6
|
|
|
7
|
-
import {
|
|
7
|
+
import { useGlobalStore } from '@/store/global';
|
|
8
8
|
|
|
9
9
|
import { useStyles } from './style';
|
|
10
10
|
|
|
11
11
|
const APIKeyForm = memo<{ onConfirm?: () => void }>(({ onConfirm }) => {
|
|
12
12
|
const { t } = useTranslation('error');
|
|
13
13
|
const { styles, theme } = useStyles();
|
|
14
|
-
const [apiKey, setSettings] =
|
|
14
|
+
const [apiKey, setSettings] = useGlobalStore((s) => [s.settings.OPENAI_API_KEY, s.setSettings]);
|
|
15
15
|
|
|
16
16
|
return (
|
|
17
17
|
<Center gap={16} style={{ maxWidth: 300 }}>
|
|
@@ -5,8 +5,8 @@ import { memo, useState } from 'react';
|
|
|
5
5
|
import { useTranslation } from 'react-i18next';
|
|
6
6
|
import { Flexbox } from 'react-layout-kit';
|
|
7
7
|
|
|
8
|
+
import { useGlobalStore } from '@/store/global';
|
|
8
9
|
import { useSessionStore } from '@/store/session';
|
|
9
|
-
import { useSettings } from '@/store/settings';
|
|
10
10
|
|
|
11
11
|
import OtpInput from '../OTPInput';
|
|
12
12
|
import APIKeyForm from './ApiKeyForm';
|
|
@@ -15,7 +15,7 @@ import { ErrorActionContainer, FormAction } from './style';
|
|
|
15
15
|
const InvalidAccess = memo<{ id: string }>(({ id }) => {
|
|
16
16
|
const { t } = useTranslation('error');
|
|
17
17
|
const [mode, setMode] = useState('password');
|
|
18
|
-
const [password, setSettings] =
|
|
18
|
+
const [password, setSettings] = useGlobalStore((s) => [s.settings.password, s.setSettings]);
|
|
19
19
|
const [resend, deleteMessage] = useSessionStore((s) => [s.resendMessage, s.deleteMessage]);
|
|
20
20
|
|
|
21
21
|
return (
|
|
@@ -5,8 +5,8 @@ import { memo, useState } from 'react';
|
|
|
5
5
|
import { useTranslation } from 'react-i18next';
|
|
6
6
|
|
|
7
7
|
import { CHAT_TEXTAREA_HEIGHT, HEADER_HEIGHT } from '@/const/layoutTokens';
|
|
8
|
+
import { useGlobalStore } from '@/store/global';
|
|
8
9
|
import { useSessionStore } from '@/store/session';
|
|
9
|
-
import { useSettings } from '@/store/settings';
|
|
10
10
|
|
|
11
11
|
import InputActions from './Action';
|
|
12
12
|
import ActionsRight from './ActionRight';
|
|
@@ -17,7 +17,10 @@ const ChatInput = () => {
|
|
|
17
17
|
const [expand, setExpand] = useState<boolean>(false);
|
|
18
18
|
const [text, setText] = useState('');
|
|
19
19
|
|
|
20
|
-
const [inputHeight] =
|
|
20
|
+
const [inputHeight, updatePreference] = useGlobalStore((s) => [
|
|
21
|
+
s.preference.inputHeight,
|
|
22
|
+
s.updatePreference,
|
|
23
|
+
]);
|
|
21
24
|
const [sendMessage, hasTopic, saveToTopic] = useSessionStore((s) => [
|
|
22
25
|
s.createOrSendMsg,
|
|
23
26
|
!!s.activeTopicId,
|
|
@@ -38,7 +41,8 @@ const ChatInput = () => {
|
|
|
38
41
|
minHeight={CHAT_TEXTAREA_HEIGHT}
|
|
39
42
|
onSizeChange={(_, size) => {
|
|
40
43
|
if (!size) return;
|
|
41
|
-
|
|
44
|
+
|
|
45
|
+
updatePreference({
|
|
42
46
|
inputHeight: typeof size.height === 'string' ? Number.parseInt(size.height) : size.height,
|
|
43
47
|
});
|
|
44
48
|
}}
|
|
@@ -9,8 +9,8 @@ import { Flexbox } from 'react-layout-kit';
|
|
|
9
9
|
|
|
10
10
|
import HeaderTitle from '@/components/HeaderTitle';
|
|
11
11
|
import Tag from '@/components/Tag';
|
|
12
|
+
import { useGlobalStore } from '@/store/global';
|
|
12
13
|
import { agentSelectors, useSessionHydrated, useSessionStore } from '@/store/session';
|
|
13
|
-
import { useSettings } from '@/store/settings';
|
|
14
14
|
|
|
15
15
|
import PluginTag from './PluginTag';
|
|
16
16
|
|
|
@@ -28,9 +28,9 @@ const Header = memo(() => {
|
|
|
28
28
|
agentSelectors.currentAgentPlugins(s),
|
|
29
29
|
]);
|
|
30
30
|
|
|
31
|
-
const [showAgentSettings, toggleConfig] =
|
|
32
|
-
s.
|
|
33
|
-
s.
|
|
31
|
+
const [showAgentSettings, toggleConfig] = useGlobalStore((s) => [
|
|
32
|
+
s.preference.showChatSideBar,
|
|
33
|
+
s.toggleChatSideBar,
|
|
34
34
|
]);
|
|
35
35
|
|
|
36
36
|
return (
|
|
@@ -4,8 +4,8 @@ import { useTranslation } from 'react-i18next';
|
|
|
4
4
|
import { Flexbox } from 'react-layout-kit';
|
|
5
5
|
|
|
6
6
|
import Empty from '@/components/Empty';
|
|
7
|
+
import { useGlobalStore } from '@/store/global';
|
|
7
8
|
import { topicSelectors, useSessionStore } from '@/store/session';
|
|
8
|
-
import { useSettings } from '@/store/settings';
|
|
9
9
|
|
|
10
10
|
import TopicItem from './TopicItem';
|
|
11
11
|
|
|
@@ -15,7 +15,10 @@ export const Topic = () => {
|
|
|
15
15
|
const [activeTopicId] = useSessionStore((s) => [s.activeTopicId]);
|
|
16
16
|
const { t } = useTranslation('empty');
|
|
17
17
|
|
|
18
|
-
const [visible, updateGuideState] =
|
|
18
|
+
const [visible, updateGuideState] = useGlobalStore((s) => [
|
|
19
|
+
s.preference.guide?.topic,
|
|
20
|
+
s.updateGuideState,
|
|
21
|
+
]);
|
|
19
22
|
|
|
20
23
|
return (
|
|
21
24
|
<Flexbox gap={2}>
|
|
@@ -4,7 +4,7 @@ import { rgba } from 'polished';
|
|
|
4
4
|
|
|
5
5
|
import HeaderSpacing from '@/components/HeaderSpacing';
|
|
6
6
|
import { CHAT_SIDEBAR_WIDTH } from '@/const/layoutTokens';
|
|
7
|
-
import {
|
|
7
|
+
import { useGlobalStore } from '@/store/global';
|
|
8
8
|
|
|
9
9
|
import Inner from './Inner';
|
|
10
10
|
|
|
@@ -22,9 +22,9 @@ const useStyles = createStyles(({ cx, css, token, stylish }) => ({
|
|
|
22
22
|
|
|
23
23
|
const Config = () => {
|
|
24
24
|
const { styles } = useStyles();
|
|
25
|
-
const [showAgentSettings, toggleConfig] =
|
|
26
|
-
s.
|
|
27
|
-
s.
|
|
25
|
+
const [showAgentSettings, toggleConfig] = useGlobalStore((s) => [
|
|
26
|
+
s.preference.showChatSideBar,
|
|
27
|
+
s.toggleChatSideBar,
|
|
28
28
|
]);
|
|
29
29
|
|
|
30
30
|
return (
|
|
@@ -4,8 +4,8 @@ import { Flexbox } from 'react-layout-kit';
|
|
|
4
4
|
import { shallow } from 'zustand/shallow';
|
|
5
5
|
|
|
6
6
|
import AppLayout from '@/layout/AppLayout';
|
|
7
|
+
import { useSwitchSideBarOnInit } from '@/store/global';
|
|
7
8
|
import { useSessionStore } from '@/store/session';
|
|
8
|
-
import { useSettings } from '@/store/settings';
|
|
9
9
|
|
|
10
10
|
import { Sessions } from '../SessionList';
|
|
11
11
|
|
|
@@ -31,12 +31,7 @@ const ChatLayout = memo<PropsWithChildren>(({ children }) => {
|
|
|
31
31
|
toggleTopic();
|
|
32
32
|
}, [id]);
|
|
33
33
|
|
|
34
|
-
|
|
35
|
-
const hasRehydrated = useSettings.persist.hasHydrated();
|
|
36
|
-
if (hasRehydrated) {
|
|
37
|
-
useSettings.setState({ sidebarKey: 'chat' });
|
|
38
|
-
}
|
|
39
|
-
}, []);
|
|
34
|
+
useSwitchSideBarOnInit('chat');
|
|
40
35
|
|
|
41
36
|
return (
|
|
42
37
|
<AppLayout>
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { GridBackground, Icon } from '@lobehub/ui';
|
|
2
|
+
import { useTheme } from 'antd-style';
|
|
3
|
+
import { Loader2 } from 'lucide-react';
|
|
4
|
+
import { rgba } from 'polished';
|
|
5
|
+
import { memo } from 'react';
|
|
6
|
+
import { useTranslation } from 'react-i18next';
|
|
7
|
+
import { Center, Flexbox } from 'react-layout-kit';
|
|
8
|
+
|
|
9
|
+
const Loading = memo(() => {
|
|
10
|
+
const { t } = useTranslation('common');
|
|
11
|
+
|
|
12
|
+
const theme = useTheme();
|
|
13
|
+
|
|
14
|
+
return (
|
|
15
|
+
<Flexbox height={'100vh'} width={'100%'}>
|
|
16
|
+
<GridBackground
|
|
17
|
+
animation
|
|
18
|
+
colorBack={rgba(theme.colorText, 0.12)}
|
|
19
|
+
colorFront={rgba(theme.colorText, 0.4)}
|
|
20
|
+
flip
|
|
21
|
+
/>
|
|
22
|
+
<Center flex={1} gap={12} width={'100%'}>
|
|
23
|
+
<Icon icon={Loader2} size={{ fontSize: 64 }} spin />
|
|
24
|
+
{t('appInitializing')}
|
|
25
|
+
</Center>
|
|
26
|
+
<GridBackground
|
|
27
|
+
animation
|
|
28
|
+
colorBack={rgba(theme.colorText, 0.12)}
|
|
29
|
+
colorFront={rgba(theme.colorText, 0.4)}
|
|
30
|
+
/>
|
|
31
|
+
</Flexbox>
|
|
32
|
+
);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
export default Loading;
|
package/src/pages/index.page.tsx
CHANGED
|
@@ -1,33 +1,18 @@
|
|
|
1
|
-
import { Icon } from '@lobehub/ui';
|
|
2
|
-
import { useWhyDidYouUpdate } from 'ahooks';
|
|
3
|
-
import { Loader2 } from 'lucide-react';
|
|
4
1
|
import { memo } from 'react';
|
|
5
|
-
import { useTranslation } from 'react-i18next';
|
|
6
|
-
import { Center } from 'react-layout-kit';
|
|
7
2
|
|
|
8
3
|
import { sessionSelectors, useSessionHydrated, useSessionStore } from '@/store/session';
|
|
9
4
|
|
|
10
5
|
import Chat from './chat/index.page';
|
|
6
|
+
import Loading from './index/Loading';
|
|
11
7
|
import Welcome from './welcome/index.page';
|
|
12
8
|
|
|
13
|
-
const
|
|
14
|
-
const { t } = useTranslation('common');
|
|
15
|
-
|
|
16
|
-
return (
|
|
17
|
-
<Center gap={12} height={'100vh'} width={'100%'}>
|
|
18
|
-
<Icon icon={Loader2} size={{ fontSize: 64 }} spin />
|
|
19
|
-
{t('appInitializing')}
|
|
20
|
-
</Center>
|
|
21
|
-
);
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
export default memo(() => {
|
|
9
|
+
const Home = memo(() => {
|
|
25
10
|
const hydrated = useSessionHydrated();
|
|
26
11
|
const hasSession = useSessionStore(sessionSelectors.hasSessionList);
|
|
27
12
|
|
|
28
|
-
useWhyDidYouUpdate('index.page', { hasSession, hydrated });
|
|
29
|
-
|
|
30
13
|
if (!hydrated) return <Loading />;
|
|
31
14
|
|
|
32
15
|
return !hasSession ? <Welcome /> : <Chat />;
|
|
33
16
|
});
|
|
17
|
+
|
|
18
|
+
export default Home;
|
|
@@ -2,12 +2,12 @@ import isEqual from 'fast-deep-equal';
|
|
|
2
2
|
import { memo } from 'react';
|
|
3
3
|
|
|
4
4
|
import { AgentConfig, AgentMeta, AgentPlugin, AgentPrompt } from '@/features/AgentSetting';
|
|
5
|
-
import { settingsSelectors,
|
|
5
|
+
import { settingsSelectors, useGlobalStore } from '@/store/global';
|
|
6
6
|
|
|
7
7
|
const Agent = memo(() => {
|
|
8
|
-
const config =
|
|
9
|
-
const meta =
|
|
10
|
-
const [setAgentConfig, setAgentMeta, toggleAgentPlugin] =
|
|
8
|
+
const config = useGlobalStore(settingsSelectors.currentAgentConfig, isEqual);
|
|
9
|
+
const meta = useGlobalStore(settingsSelectors.currentAgentMeta, isEqual);
|
|
10
|
+
const [setAgentConfig, setAgentMeta, toggleAgentPlugin] = useGlobalStore((s) => [
|
|
11
11
|
s.setAgentConfig,
|
|
12
12
|
s.setAgentMeta,
|
|
13
13
|
s.toggleAgentPlugin,
|
|
@@ -11,8 +11,8 @@ import { FORM_STYLE } from '@/const/layoutTokens';
|
|
|
11
11
|
import { DEFAULT_SETTINGS } from '@/const/settings';
|
|
12
12
|
import AvatarWithUpload from '@/features/AvatarWithUpload';
|
|
13
13
|
import { options } from '@/locales/options';
|
|
14
|
+
import { settingsSelectors, useGlobalStore } from '@/store/global';
|
|
14
15
|
import { useSessionStore } from '@/store/session';
|
|
15
|
-
import { settingsSelectors, useSettings } from '@/store/settings';
|
|
16
16
|
import { ConfigKeys } from '@/types/settings';
|
|
17
17
|
|
|
18
18
|
import { ThemeSwatchesNeutral, ThemeSwatchesPrimary } from '../ThemeSwatches';
|
|
@@ -27,8 +27,8 @@ const Common = memo(() => {
|
|
|
27
27
|
const { t } = useTranslation('setting');
|
|
28
28
|
const [form] = AntForm.useForm();
|
|
29
29
|
const clearSessions = useSessionStore((s) => s.clearSessions);
|
|
30
|
-
const settings =
|
|
31
|
-
const [setThemeMode, setSettings, resetSettings] =
|
|
30
|
+
const settings = useGlobalStore(settingsSelectors.currentSettings, isEqual);
|
|
31
|
+
const [setThemeMode, setSettings, resetSettings] = useGlobalStore((s) => [
|
|
32
32
|
s.setThemeMode,
|
|
33
33
|
s.setSettings,
|
|
34
34
|
s.resetSettings,
|
|
@@ -7,10 +7,13 @@ import {
|
|
|
7
7
|
} from '@lobehub/ui';
|
|
8
8
|
import { memo } from 'react';
|
|
9
9
|
|
|
10
|
-
import {
|
|
10
|
+
import { useGlobalStore } from '@/store/global';
|
|
11
11
|
|
|
12
12
|
const ThemeSwatchesNeutral = memo(() => {
|
|
13
|
-
const [neutralColor, setSettings] =
|
|
13
|
+
const [neutralColor, setSettings] = useGlobalStore((s) => [
|
|
14
|
+
s.settings.neutralColor,
|
|
15
|
+
s.setSettings,
|
|
16
|
+
]);
|
|
14
17
|
|
|
15
18
|
const handleSelect = (v: any) => {
|
|
16
19
|
const name = findCustomThemeName('neutral', v) as NeutralColors;
|
|
@@ -7,10 +7,13 @@ import {
|
|
|
7
7
|
} from '@lobehub/ui';
|
|
8
8
|
import { memo } from 'react';
|
|
9
9
|
|
|
10
|
-
import {
|
|
10
|
+
import { useGlobalStore } from '@/store/global';
|
|
11
11
|
|
|
12
12
|
const ThemeSwatchesPrimary = memo(() => {
|
|
13
|
-
const [primaryColor, setSettings] =
|
|
13
|
+
const [primaryColor, setSettings] = useGlobalStore((s) => [
|
|
14
|
+
s.settings.primaryColor,
|
|
15
|
+
s.setSettings,
|
|
16
|
+
]);
|
|
14
17
|
|
|
15
18
|
const handleSelect = (v: any) => {
|
|
16
19
|
const name = findCustomThemeName('primary', v) as PrimaryColors;
|
|
@@ -5,7 +5,7 @@ import { Flexbox } from 'react-layout-kit';
|
|
|
5
5
|
|
|
6
6
|
import SideBar from '@/features/SideBar';
|
|
7
7
|
import { createI18nNext } from '@/locales/create';
|
|
8
|
-
import {
|
|
8
|
+
import { useSwitchSideBarOnInit } from '@/store/global';
|
|
9
9
|
import { genSiteHeadTitle } from '@/utils/genSiteHeadTitle';
|
|
10
10
|
|
|
11
11
|
const initI18n = createI18nNext('setting');
|
|
@@ -18,12 +18,7 @@ const SettingLayout = memo<{ children: ReactNode }>(({ children }) => {
|
|
|
18
18
|
initI18n.finally();
|
|
19
19
|
}, []);
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
const hasRehydrated = useSettings.persist.hasHydrated();
|
|
23
|
-
if (hasRehydrated) {
|
|
24
|
-
useSettings.setState({ sidebarKey: 'settings' });
|
|
25
|
-
}
|
|
26
|
-
}, []);
|
|
21
|
+
useSwitchSideBarOnInit('settings');
|
|
27
22
|
|
|
28
23
|
return (
|
|
29
24
|
<>
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { merge } from 'lodash-es';
|
|
2
2
|
|
|
3
3
|
import { LOBE_CHAT_ACCESS_CODE, OPENAI_API_KEY_HEADER_KEY, OPENAI_END_POINT } from '@/const/fetch';
|
|
4
|
+
import { useGlobalStore } from '@/store/global';
|
|
4
5
|
import { initialLobeAgentConfig } from '@/store/session';
|
|
5
|
-
import { useSettings } from '@/store/settings';
|
|
6
6
|
import type { OpenAIStreamPayload } from '@/types/openai';
|
|
7
7
|
|
|
8
8
|
import { URLS } from './url';
|
|
@@ -31,9 +31,9 @@ export const fetchChatModel = (
|
|
|
31
31
|
body: JSON.stringify(payload),
|
|
32
32
|
headers: {
|
|
33
33
|
'Content-Type': 'application/json',
|
|
34
|
-
[LOBE_CHAT_ACCESS_CODE]:
|
|
35
|
-
[OPENAI_API_KEY_HEADER_KEY]:
|
|
36
|
-
[OPENAI_END_POINT]:
|
|
34
|
+
[LOBE_CHAT_ACCESS_CODE]: useGlobalStore.getState().settings.password || '',
|
|
35
|
+
[OPENAI_API_KEY_HEADER_KEY]: useGlobalStore.getState().settings.OPENAI_API_KEY || '',
|
|
36
|
+
[OPENAI_END_POINT]: useGlobalStore.getState().settings.endpoint || '',
|
|
37
37
|
},
|
|
38
38
|
method: 'POST',
|
|
39
39
|
signal: options?.signal,
|
package/src/services/plugin.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { LOBE_CHAT_ACCESS_CODE } from '@/const/fetch';
|
|
2
|
-
import {
|
|
2
|
+
import { useGlobalStore } from '@/store/global';
|
|
3
3
|
import { OpenAIPluginPayload } from '@/types/plugin';
|
|
4
4
|
|
|
5
5
|
import { URLS } from './url';
|
|
@@ -20,7 +20,7 @@ export const fetchPlugin = async (
|
|
|
20
20
|
body: JSON.stringify(params),
|
|
21
21
|
headers: {
|
|
22
22
|
'Content-Type': 'application/json',
|
|
23
|
-
[LOBE_CHAT_ACCESS_CODE]:
|
|
23
|
+
[LOBE_CHAT_ACCESS_CODE]: useGlobalStore.getState().settings.password || '',
|
|
24
24
|
},
|
|
25
25
|
method: 'POST',
|
|
26
26
|
signal: options?.signal,
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import { useEffect, useState } from 'react';
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { useGlobalStore } from '../store';
|
|
4
4
|
|
|
5
5
|
export const useSettingsHydrated = () => {
|
|
6
6
|
// 根据 sessions 是否有值来判断是否已经初始化
|
|
7
|
-
const hasInited = !!Object.values(
|
|
7
|
+
const hasInited = !!Object.values(useGlobalStore.getState().settings).length;
|
|
8
8
|
|
|
9
9
|
const [isInit, setInit] = useState(hasInited);
|
|
10
10
|
|
|
11
11
|
useEffect(() => {
|
|
12
|
-
const hasRehydrated =
|
|
12
|
+
const hasRehydrated = useGlobalStore.persist.hasHydrated();
|
|
13
13
|
|
|
14
14
|
if (hasRehydrated && !isInit) {
|
|
15
15
|
setInit(true);
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { useEffect } from 'react';
|
|
2
|
+
|
|
3
|
+
import { SidebarTabKey } from '../initialState';
|
|
4
|
+
import { useGlobalStore } from '../store';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* 切换侧边栏选项
|
|
8
|
+
* @desc 只会在应用初始化时(且水合后)执行一次
|
|
9
|
+
*/
|
|
10
|
+
export const useSwitchSideBarOnInit = (key: SidebarTabKey) => {
|
|
11
|
+
useEffect(() => {
|
|
12
|
+
const hasRehydrated = useGlobalStore.persist.hasHydrated();
|
|
13
|
+
if (hasRehydrated) {
|
|
14
|
+
useGlobalStore.getState().switchSideBar(key);
|
|
15
|
+
}
|
|
16
|
+
}, []);
|
|
17
|
+
};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { DEFAULT_SETTINGS } from '@/const/settings';
|
|
2
|
+
import type { GlobalSettings } from '@/types/settings';
|
|
3
|
+
|
|
4
|
+
export type SidebarTabKey = 'chat' | 'market' | 'settings';
|
|
5
|
+
|
|
6
|
+
export interface Guide {
|
|
7
|
+
// Topic 引导
|
|
8
|
+
topic?: boolean;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface GlobalState {
|
|
12
|
+
/**
|
|
13
|
+
* 用户偏好的 UI 状态
|
|
14
|
+
* @localStorage
|
|
15
|
+
*/
|
|
16
|
+
preference: GlobalPreference;
|
|
17
|
+
/**
|
|
18
|
+
* @localStorage
|
|
19
|
+
* 用户设置
|
|
20
|
+
*/
|
|
21
|
+
settings: GlobalSettings;
|
|
22
|
+
sidebarKey: SidebarTabKey;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface GlobalPreference {
|
|
26
|
+
guide?: Guide;
|
|
27
|
+
inputHeight: number;
|
|
28
|
+
sessionsWidth: number;
|
|
29
|
+
showChatSideBar?: boolean;
|
|
30
|
+
showSessionPanel?: boolean;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export const initialState: GlobalState = {
|
|
34
|
+
preference: {
|
|
35
|
+
guide: {},
|
|
36
|
+
inputHeight: 200,
|
|
37
|
+
sessionsWidth: 320,
|
|
38
|
+
showChatSideBar: true,
|
|
39
|
+
showSessionPanel: true,
|
|
40
|
+
},
|
|
41
|
+
settings: DEFAULT_SETTINGS,
|
|
42
|
+
sidebarKey: 'chat',
|
|
43
|
+
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { merge } from 'lodash-es';
|
|
2
|
+
|
|
3
|
+
import { DEFAULT_AGENT_META } from '@/const/meta';
|
|
4
|
+
import { DEFAULT_AGENT, DEFAULT_AGENT_CONFIG, DEFAULT_SETTINGS } from '@/const/settings';
|
|
5
|
+
import { GlobalSettings } from '@/types/settings';
|
|
6
|
+
|
|
7
|
+
import { GlobalStore } from './store';
|
|
8
|
+
|
|
9
|
+
const currentSettings = (s: GlobalStore) => merge({}, DEFAULT_SETTINGS, s.settings);
|
|
10
|
+
|
|
11
|
+
const currentDefaultAgent = (s: GlobalStore) => merge({}, DEFAULT_AGENT, s.settings.defaultAgent);
|
|
12
|
+
|
|
13
|
+
const currentAgentConfig = (s: GlobalStore) =>
|
|
14
|
+
merge({}, DEFAULT_AGENT_CONFIG, s.settings.defaultAgent.config);
|
|
15
|
+
|
|
16
|
+
const currentAgentMeta = (s: GlobalStore) =>
|
|
17
|
+
merge({}, DEFAULT_AGENT_META, s.settings.defaultAgent.meta);
|
|
18
|
+
|
|
19
|
+
export const exportSettings = (s: GlobalStore) => {
|
|
20
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
21
|
+
const { OPENAI_API_KEY: _, password: __, ...settings } = s.settings;
|
|
22
|
+
|
|
23
|
+
return settings as GlobalSettings;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export const settingsSelectors = {
|
|
27
|
+
currentAgentConfig,
|
|
28
|
+
currentAgentMeta,
|
|
29
|
+
currentDefaultAgent,
|
|
30
|
+
currentSettings,
|
|
31
|
+
exportSettings,
|
|
32
|
+
};
|
|
@@ -9,7 +9,7 @@ import { LobeAgentConfig } from '@/types/session';
|
|
|
9
9
|
import type { GlobalSettings } from '@/types/settings';
|
|
10
10
|
import { setNamespace } from '@/utils/storeDebug';
|
|
11
11
|
|
|
12
|
-
import type {
|
|
12
|
+
import type { GlobalStore } from '../store';
|
|
13
13
|
|
|
14
14
|
const t = setNamespace('settings');
|
|
15
15
|
|
|
@@ -22,12 +22,11 @@ export interface AgentAction {
|
|
|
22
22
|
resetDefaultAgent: () => void;
|
|
23
23
|
setAgentConfig: (config: Partial<LobeAgentSession['config']>) => void;
|
|
24
24
|
setAgentMeta: (meta: Partial<LobeAgentSession['meta']>) => void;
|
|
25
|
-
toggleAgentPanel: (visible?: boolean) => void;
|
|
26
25
|
toggleAgentPlugin: (pluginId: string) => void;
|
|
27
26
|
}
|
|
28
27
|
|
|
29
28
|
export const createAgentSlice: StateCreator<
|
|
30
|
-
|
|
29
|
+
GlobalStore,
|
|
31
30
|
[['zustand/devtools', never]],
|
|
32
31
|
[],
|
|
33
32
|
AgentAction
|
|
@@ -66,11 +65,7 @@ export const createAgentSlice: StateCreator<
|
|
|
66
65
|
|
|
67
66
|
set({ settings }, false, t('setAgentMeta', meta));
|
|
68
67
|
},
|
|
69
|
-
toggleAgentPanel: (newValue) => {
|
|
70
|
-
const showAgentConfig = typeof newValue === 'boolean' ? newValue : !get().showAgentConfig;
|
|
71
68
|
|
|
72
|
-
set({ showAgentConfig }, false, t('toggleAgentPanel', newValue));
|
|
73
|
-
},
|
|
74
69
|
toggleAgentPlugin: (id: string) => {
|
|
75
70
|
const settings = produce(get().settings, (draft: GlobalSettings) => {
|
|
76
71
|
const oldConfig = draft.defaultAgent.config as LobeAgentConfig;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { produce } from 'immer';
|
|
2
|
+
import { merge } from 'lodash-es';
|
|
3
|
+
import type { StateCreator } from 'zustand/vanilla';
|
|
4
|
+
|
|
5
|
+
import { setNamespace } from '@/utils/storeDebug';
|
|
6
|
+
|
|
7
|
+
import type { GlobalPreference, GlobalState, Guide, SidebarTabKey } from '../initialState';
|
|
8
|
+
import type { GlobalStore } from '../store';
|
|
9
|
+
|
|
10
|
+
const t = setNamespace('settings');
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* 设置操作
|
|
14
|
+
*/
|
|
15
|
+
export interface CommonAction {
|
|
16
|
+
/**
|
|
17
|
+
* 切换侧边栏选项
|
|
18
|
+
* @param key - 选中的侧边栏选项
|
|
19
|
+
*/
|
|
20
|
+
switchSideBar: (key: SidebarTabKey) => void;
|
|
21
|
+
toggleChatSideBar: (visible?: boolean) => void;
|
|
22
|
+
updateGuideState: (guide: Partial<Guide>) => void;
|
|
23
|
+
updatePreference: (preference: Partial<GlobalPreference>, action?: string) => void;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export const createCommonSlice: StateCreator<
|
|
27
|
+
GlobalStore,
|
|
28
|
+
[['zustand/devtools', never]],
|
|
29
|
+
[],
|
|
30
|
+
CommonAction
|
|
31
|
+
> = (set, get) => ({
|
|
32
|
+
switchSideBar: (key) => {
|
|
33
|
+
set({ sidebarKey: key }, false, t('switchSideBar', key));
|
|
34
|
+
},
|
|
35
|
+
toggleChatSideBar: (newValue) => {
|
|
36
|
+
const showChatSideBar =
|
|
37
|
+
typeof newValue === 'boolean' ? newValue : !get().preference.showChatSideBar;
|
|
38
|
+
|
|
39
|
+
get().updatePreference({ showChatSideBar }, t('toggleAgentPanel', newValue) as string);
|
|
40
|
+
},
|
|
41
|
+
updateGuideState: (guide) => {
|
|
42
|
+
const { updatePreference } = get();
|
|
43
|
+
const nextGuide = merge({}, get().preference.guide, guide);
|
|
44
|
+
updatePreference({ guide: nextGuide });
|
|
45
|
+
},
|
|
46
|
+
|
|
47
|
+
updatePreference: (preference, action) => {
|
|
48
|
+
set(
|
|
49
|
+
produce((draft: GlobalState) => {
|
|
50
|
+
draft.preference = merge({}, draft.preference, preference);
|
|
51
|
+
}),
|
|
52
|
+
false,
|
|
53
|
+
action,
|
|
54
|
+
);
|
|
55
|
+
},
|
|
56
|
+
});
|
|
@@ -3,31 +3,23 @@ import { produce } from 'immer';
|
|
|
3
3
|
import { merge } from 'lodash-es';
|
|
4
4
|
import type { StateCreator } from 'zustand/vanilla';
|
|
5
5
|
|
|
6
|
-
import { DEFAULT_AGENT,
|
|
6
|
+
import { DEFAULT_AGENT, DEFAULT_SETTINGS } from '@/const/settings';
|
|
7
7
|
import type { GlobalSettings } from '@/types/settings';
|
|
8
8
|
import { setNamespace } from '@/utils/storeDebug';
|
|
9
9
|
|
|
10
|
-
import type {
|
|
11
|
-
import { AppSettingsState } from '../initialState';
|
|
12
|
-
import type { SettingsStore } from '../store';
|
|
10
|
+
import type { GlobalStore } from '../store';
|
|
13
11
|
|
|
14
12
|
const t = setNamespace('settings');
|
|
15
13
|
|
|
16
14
|
/**
|
|
17
15
|
* 设置操作
|
|
18
16
|
*/
|
|
19
|
-
export interface
|
|
17
|
+
export interface SettingsAction {
|
|
20
18
|
importAppSettings: (settings: GlobalSettings) => void;
|
|
21
|
-
resetBaseSettings: () => void;
|
|
22
19
|
/**
|
|
23
20
|
* 重置设置
|
|
24
21
|
*/
|
|
25
22
|
resetSettings: () => void;
|
|
26
|
-
/**
|
|
27
|
-
* 设置全局设置
|
|
28
|
-
* @param settings - 全局设置
|
|
29
|
-
*/
|
|
30
|
-
setAppSettings: (settings: AppSettingsState) => void;
|
|
31
23
|
/**
|
|
32
24
|
* 设置部分配置设置
|
|
33
25
|
* @param settings - 部分配置设置
|
|
@@ -38,19 +30,13 @@ export interface CommonAction {
|
|
|
38
30
|
* @param themeMode - 主题模式
|
|
39
31
|
*/
|
|
40
32
|
setThemeMode: (themeMode: ThemeMode) => void;
|
|
41
|
-
/**
|
|
42
|
-
* 切换侧边栏选项
|
|
43
|
-
* @param key - 选中的侧边栏选项
|
|
44
|
-
*/
|
|
45
|
-
switchSideBar: (key: SidebarTabKey) => void;
|
|
46
|
-
updateGuideState: (guide: Partial<Guide>) => void;
|
|
47
33
|
}
|
|
48
34
|
|
|
49
|
-
export const
|
|
50
|
-
|
|
35
|
+
export const createSettingsSlice: StateCreator<
|
|
36
|
+
GlobalStore,
|
|
51
37
|
[['zustand/devtools', never]],
|
|
52
38
|
[],
|
|
53
|
-
|
|
39
|
+
SettingsAction
|
|
54
40
|
> = (set, get) => ({
|
|
55
41
|
importAppSettings: (importAppSettings) => {
|
|
56
42
|
const { setSettings } = get();
|
|
@@ -63,11 +49,6 @@ export const createCommonSlice: StateCreator<
|
|
|
63
49
|
avatar: !get().settings.avatar ? settings.avatar : get().settings.avatar,
|
|
64
50
|
});
|
|
65
51
|
},
|
|
66
|
-
resetBaseSettings: () => {
|
|
67
|
-
const settings = get().settings;
|
|
68
|
-
|
|
69
|
-
set({ settings: { ...settings, ...DEFAULT_BASE_SETTINGS } }, false, t('resetBaseSettings'));
|
|
70
|
-
},
|
|
71
52
|
resetDefaultAgent: () => {
|
|
72
53
|
const settings = produce(get().settings, (draft: GlobalSettings) => {
|
|
73
54
|
draft.defaultAgent = DEFAULT_AGENT;
|
|
@@ -77,9 +58,7 @@ export const createCommonSlice: StateCreator<
|
|
|
77
58
|
resetSettings: () => {
|
|
78
59
|
set({ settings: DEFAULT_SETTINGS }, false, t('resetSettings'));
|
|
79
60
|
},
|
|
80
|
-
|
|
81
|
-
set({ ...settings }, false, t('setAppSettings', settings));
|
|
82
|
-
},
|
|
61
|
+
|
|
83
62
|
setSettings: (settings) => {
|
|
84
63
|
const oldSetting = get().settings;
|
|
85
64
|
set({ settings: merge(oldSetting, settings) }, false, t('setSettings', settings));
|
|
@@ -87,10 +66,4 @@ export const createCommonSlice: StateCreator<
|
|
|
87
66
|
setThemeMode: (themeMode) => {
|
|
88
67
|
get().setSettings({ themeMode });
|
|
89
68
|
},
|
|
90
|
-
switchSideBar: (key) => {
|
|
91
|
-
set({ sidebarKey: key }, false, t('switchSideBar', key));
|
|
92
|
-
},
|
|
93
|
-
updateGuideState: (guide) => {
|
|
94
|
-
set({ guide: { ...get().guide, ...guide } });
|
|
95
|
-
},
|
|
96
69
|
});
|
|
@@ -5,37 +5,40 @@ import { StateCreator } from 'zustand/vanilla';
|
|
|
5
5
|
|
|
6
6
|
import { isDev } from '@/utils/env';
|
|
7
7
|
|
|
8
|
-
import { type
|
|
8
|
+
import { type GlobalState, initialState } from './initialState';
|
|
9
9
|
import { type AgentAction, createAgentSlice } from './slices/agent';
|
|
10
10
|
import { type CommonAction, createCommonSlice } from './slices/common';
|
|
11
|
+
import { type SettingsAction, createSettingsSlice } from './slices/settings';
|
|
11
12
|
|
|
12
13
|
// =============== 聚合 createStoreFn ============ //
|
|
13
14
|
|
|
14
|
-
export type
|
|
15
|
+
export type GlobalStore = CommonAction & GlobalState & AgentAction & SettingsAction;
|
|
15
16
|
|
|
16
|
-
const createStore: StateCreator<
|
|
17
|
-
...parameters
|
|
18
|
-
) => ({
|
|
17
|
+
const createStore: StateCreator<GlobalStore, [['zustand/devtools', never]]> = (...parameters) => ({
|
|
19
18
|
...initialState,
|
|
20
19
|
...createCommonSlice(...parameters),
|
|
21
20
|
...createAgentSlice(...parameters),
|
|
21
|
+
...createSettingsSlice(...parameters),
|
|
22
22
|
});
|
|
23
23
|
|
|
24
24
|
// =============== persist 本地缓存中间件配置 ============ //
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
25
|
+
type GlobalPersist = Pick<GlobalStore, 'preference' | 'settings'>;
|
|
26
|
+
|
|
27
|
+
const persistOptions: PersistOptions<GlobalStore, GlobalPersist> = {
|
|
28
|
+
name: 'LOBE_SETTINGS',
|
|
29
|
+
partialize: (s) => ({
|
|
30
|
+
preference: s.preference,
|
|
31
|
+
settings: s.settings,
|
|
32
|
+
}),
|
|
30
33
|
skipHydration: true,
|
|
31
34
|
};
|
|
32
35
|
|
|
33
36
|
// =============== 实装 useStore ============ //
|
|
34
37
|
|
|
35
|
-
export const
|
|
38
|
+
export const useGlobalStore = createWithEqualityFn<GlobalStore>()(
|
|
36
39
|
persist(
|
|
37
40
|
devtools(createStore, {
|
|
38
|
-
name:
|
|
41
|
+
name: 'LOBE_GLOBAL' + (isDev ? '_DEV' : ''),
|
|
39
42
|
}),
|
|
40
43
|
persistOptions,
|
|
41
44
|
),
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { DEFAULT_USER_AVATAR } from '@/const/meta';
|
|
2
|
-
import {
|
|
2
|
+
import { useGlobalStore } from '@/store/global';
|
|
3
3
|
import { ChatMessage } from '@/types/chatMessage';
|
|
4
4
|
|
|
5
5
|
import type { SessionStore } from '../../../store';
|
|
@@ -20,7 +20,7 @@ export const getChatsById =
|
|
|
20
20
|
{
|
|
21
21
|
assistant: agentSelectors.currentAgentAvatar(s),
|
|
22
22
|
assistantBackground: agentSelectors.currentAgentBackgroundColor(s),
|
|
23
|
-
user:
|
|
23
|
+
user: useGlobalStore.getState().settings.avatar || DEFAULT_USER_AVATAR,
|
|
24
24
|
},
|
|
25
25
|
s.activeTopicId,
|
|
26
26
|
);
|
|
@@ -3,8 +3,8 @@ import { merge } from 'lodash-es';
|
|
|
3
3
|
import Router from 'next/router';
|
|
4
4
|
import { StateCreator } from 'zustand/vanilla';
|
|
5
5
|
|
|
6
|
+
import { useGlobalStore } from '@/store/global';
|
|
6
7
|
import { SessionStore, initLobeSession } from '@/store/session';
|
|
7
|
-
import { useSettings } from '@/store/settings';
|
|
8
8
|
import { LobeAgentSession, LobeSessions } from '@/types/session';
|
|
9
9
|
import { setNamespace } from '@/utils/storeDebug';
|
|
10
10
|
import { uuid } from '@/utils/uuid';
|
|
@@ -79,7 +79,7 @@ export const createSessionSlice: StateCreator<
|
|
|
79
79
|
const timestamp = Date.now();
|
|
80
80
|
|
|
81
81
|
// 合并 settings 里的 defaultAgent
|
|
82
|
-
const globalDefaultAgent =
|
|
82
|
+
const globalDefaultAgent = useGlobalStore.getState().settings.defaultAgent;
|
|
83
83
|
const newSession: LobeAgentSession = merge({}, initLobeSession, globalDefaultAgent, {
|
|
84
84
|
createAt: timestamp,
|
|
85
85
|
id: uuid(),
|
|
@@ -136,7 +136,7 @@ export const createSessionSlice: StateCreator<
|
|
|
136
136
|
get().dispatchSession({ id: sessionId, type: 'removeSession' });
|
|
137
137
|
|
|
138
138
|
if (sessionId === get().activeId) {
|
|
139
|
-
Router.push('/');
|
|
139
|
+
Router.push('/chat');
|
|
140
140
|
}
|
|
141
141
|
},
|
|
142
142
|
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import { DEFAULT_SETTINGS } from '@/const/settings';
|
|
2
|
-
import type { GlobalSettings } from '@/types/settings';
|
|
3
|
-
|
|
4
|
-
export type SidebarTabKey = 'chat' | 'market' | 'settings';
|
|
5
|
-
|
|
6
|
-
export interface Guide {
|
|
7
|
-
// Topic 引导
|
|
8
|
-
topic?: boolean;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export interface AppSettingsState {
|
|
12
|
-
guide?: Guide;
|
|
13
|
-
inputHeight: number;
|
|
14
|
-
sessionExpandable?: boolean;
|
|
15
|
-
sessionsWidth: number;
|
|
16
|
-
settings: GlobalSettings;
|
|
17
|
-
showAgentConfig?: boolean;
|
|
18
|
-
sidebarKey: SidebarTabKey;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export const initialState: AppSettingsState = {
|
|
22
|
-
guide: {},
|
|
23
|
-
inputHeight: 200,
|
|
24
|
-
sessionExpandable: true,
|
|
25
|
-
sessionsWidth: 320,
|
|
26
|
-
settings: DEFAULT_SETTINGS,
|
|
27
|
-
showAgentConfig: true,
|
|
28
|
-
sidebarKey: 'chat',
|
|
29
|
-
};
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import { defaults } from 'lodash-es';
|
|
2
|
-
|
|
3
|
-
import { DEFAULT_AGENT_META } from '@/const/meta';
|
|
4
|
-
import { DEFAULT_AGENT, DEFAULT_AGENT_CONFIG, DEFAULT_SETTINGS } from '@/const/settings';
|
|
5
|
-
import { GlobalSettings } from '@/types/settings';
|
|
6
|
-
|
|
7
|
-
import { SettingsStore } from './store';
|
|
8
|
-
|
|
9
|
-
const currentSettings = (s: SettingsStore) => defaults(s.settings, DEFAULT_SETTINGS);
|
|
10
|
-
|
|
11
|
-
const currentDefaultAgent = (s: SettingsStore) => defaults(s.settings.defaultAgent, DEFAULT_AGENT);
|
|
12
|
-
|
|
13
|
-
const currentAgentConfig = (s: SettingsStore) =>
|
|
14
|
-
defaults(s.settings.defaultAgent.config, DEFAULT_AGENT_CONFIG);
|
|
15
|
-
|
|
16
|
-
const currentAgentMeta = (s: SettingsStore) =>
|
|
17
|
-
defaults(s.settings.defaultAgent.meta, DEFAULT_AGENT_META);
|
|
18
|
-
|
|
19
|
-
export const exportSettings = (s: SettingsStore) => {
|
|
20
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
21
|
-
const { OPENAI_API_KEY: _, password: __, ...settings } = s.settings;
|
|
22
|
-
|
|
23
|
-
return settings as GlobalSettings;
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
export const settingsSelectors = {
|
|
27
|
-
currentAgentConfig,
|
|
28
|
-
currentAgentMeta,
|
|
29
|
-
currentDefaultAgent,
|
|
30
|
-
currentSettings,
|
|
31
|
-
exportSettings,
|
|
32
|
-
};
|