@lobehub/chat 0.42.3 → 0.44.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/release.yml +1 -1
- package/CHANGELOG.md +74 -0
- package/package.json +5 -2
- package/src/const/meta.ts +3 -0
- package/src/const/session.ts +1 -0
- package/src/helpers/export.ts +15 -9
- package/src/locales/default/common.ts +8 -1
- package/src/pages/chat/SessionList/Inbox.tsx +23 -0
- package/src/pages/chat/SessionList/List/SessionItem.tsx +15 -4
- package/src/pages/chat/SessionList/List/index.tsx +3 -2
- package/src/pages/chat/SessionList/index.tsx +13 -1
- package/src/pages/chat/[id]/index.page.tsx +7 -9
- package/src/pages/chat/[id]/layout.tsx +7 -23
- package/src/pages/chat/[id]/setting/index.page.tsx +3 -3
- package/src/pages/chat/features/Conversation/ChatList/SkeletonList.tsx +43 -0
- package/src/pages/chat/{[id] → features}/Conversation/ChatList/index.tsx +35 -5
- package/src/pages/chat/{[id] → features}/Conversation/Input/index.tsx +1 -1
- package/src/pages/chat/{[id] → features}/Header/index.tsx +32 -34
- package/src/pages/chat/features/Sidebar/Inner.tsx +42 -0
- package/src/pages/chat/{[id]/Sidebar/Inner.tsx → features/Sidebar/SystemRole.tsx} +7 -37
- package/src/pages/chat/{[id] → features}/Sidebar/index.tsx +8 -4
- package/src/pages/chat/index.page.tsx +39 -1
- package/src/pages/chat/layout.tsx +27 -0
- package/src/pages/settings/Settings/Common.tsx +11 -2
- package/src/pages/welcome/Footer/index.tsx +1 -0
- package/src/services/chatModel.ts +1 -1
- package/src/store/global/hooks/useOnFinishHydrationGlobal.ts +18 -0
- package/src/store/global/hooks/useSwitchSideBarOnInit.ts +4 -8
- package/src/store/global/slices/settings.ts +2 -2
- package/src/store/session/hooks/index.ts +2 -0
- package/src/store/session/hooks/useOnFinishHydrationSession.ts +18 -0
- package/src/store/session/hooks/useSessionHydrated.ts +1 -1
- package/src/store/session/index.ts +1 -3
- package/src/store/session/initialState.ts +6 -3
- package/src/store/session/selectors.ts +3 -3
- package/src/store/session/slices/agentConfig/action.ts +2 -1
- package/src/store/session/slices/agentConfig/selectors.ts +11 -11
- package/src/store/session/slices/chat/actions/message.ts +13 -20
- package/src/store/session/slices/chat/actions/topic.ts +3 -1
- package/src/store/session/slices/chat/selectors/chat.ts +1 -1
- package/src/store/session/slices/chat/selectors/token.ts +1 -1
- package/src/store/session/slices/chat/selectors/topic.ts +4 -2
- package/src/store/session/slices/session/action.ts +29 -15
- package/src/store/session/slices/session/initialState.ts +18 -4
- package/src/store/session/slices/session/selectors/export.ts +13 -8
- package/src/store/session/slices/session/selectors/list.test.ts +303 -0
- package/src/store/session/slices/session/selectors/list.ts +8 -3
- package/src/store/session/store.ts +5 -5
- package/src/types/exportConfig.ts +93 -31
- package/src/utils/config.ts +9 -0
- package/src/pages/chat/SessionList/List/style.ts +0 -36
- package/src/store/session/slices/chat/index.ts +0 -3
- package/src/store/session/slices/session/index.ts +0 -3
- package/src/pages/chat/{[id] → features}/Conversation/ChatList/Error/ApiKeyForm.tsx +0 -0
- package/src/pages/chat/{[id] → features}/Conversation/ChatList/Error/ErrorActionContainer.tsx +0 -0
- package/src/pages/chat/{[id] → features}/Conversation/ChatList/Error/InvalidAccess.tsx +1 -1
- /package/src/pages/chat/{[id] → features}/Conversation/ChatList/Error/OpenAiBizError.tsx +0 -0
- /package/src/pages/chat/{[id] → features}/Conversation/ChatList/Error/style.tsx +0 -0
- /package/src/pages/chat/{[id] → features}/Conversation/ChatList/MessageExtra.tsx +0 -0
- /package/src/pages/chat/{[id] → features}/Conversation/ChatList/OTPInput.tsx +0 -0
- /package/src/pages/chat/{[id] → features}/Conversation/ChatList/Plugins/FunctionCall.tsx +0 -0
- /package/src/pages/chat/{[id] → features}/Conversation/ChatList/Plugins/PluginMessage.tsx +0 -0
- /package/src/pages/chat/{[id] → features}/Conversation/ChatList/Plugins/PluginResultRender.tsx +0 -0
- /package/src/pages/chat/{[id] → features}/Conversation/ChatList/Plugins/style.ts +0 -0
- /package/src/pages/chat/{[id] → features}/Conversation/Input/Action.tsx +0 -0
- /package/src/pages/chat/{[id] → features}/Conversation/Input/ActionRight.tsx +0 -0
- /package/src/pages/chat/{[id] → features}/Conversation/Input/Token.tsx +0 -0
- /package/src/pages/chat/{[id] → features}/Conversation/index.tsx +0 -0
- /package/src/pages/chat/{[id] → features}/Header/PluginTag.tsx +0 -0
- /package/src/pages/chat/{[id] → features}/Sidebar/Header.tsx +0 -0
- /package/src/pages/chat/{[id] → features}/Sidebar/Topic/DefaultContent.tsx +0 -0
- /package/src/pages/chat/{[id] → features}/Sidebar/Topic/TopicContent.tsx +0 -0
- /package/src/pages/chat/{[id] → features}/Sidebar/Topic/TopicItem.tsx +0 -0
- /package/src/pages/chat/{[id] → features}/Sidebar/Topic/index.tsx +0 -0
|
@@ -9,30 +9,37 @@ import { Flexbox } from 'react-layout-kit';
|
|
|
9
9
|
|
|
10
10
|
import HeaderTitle from '@/components/HeaderTitle';
|
|
11
11
|
import Tag from '@/components/Tag';
|
|
12
|
+
import { INBOX_SESSION_ID } from '@/const/session';
|
|
12
13
|
import { useGlobalStore } from '@/store/global';
|
|
13
14
|
import { agentSelectors, useSessionHydrated, useSessionStore } from '@/store/session';
|
|
14
15
|
|
|
15
16
|
import PluginTag from './PluginTag';
|
|
16
17
|
|
|
17
|
-
const Header = memo(() => {
|
|
18
|
+
const Header = memo<{ settings?: boolean }>(({ settings = true }) => {
|
|
18
19
|
const init = useSessionHydrated();
|
|
20
|
+
|
|
19
21
|
const { t } = useTranslation('common');
|
|
20
22
|
|
|
21
|
-
const [title, description, avatar, backgroundColor,
|
|
23
|
+
const [id, title, description, avatar, backgroundColor, model, plugins] = useSessionStore((s) => [
|
|
24
|
+
s.activeId,
|
|
25
|
+
|
|
22
26
|
agentSelectors.currentAgentTitle(s),
|
|
23
27
|
agentSelectors.currentAgentDescription(s),
|
|
24
28
|
agentSelectors.currentAgentAvatar(s),
|
|
25
29
|
agentSelectors.currentAgentBackgroundColor(s),
|
|
26
|
-
s.activeId,
|
|
27
30
|
agentSelectors.currentAgentModel(s),
|
|
28
31
|
agentSelectors.currentAgentPlugins(s),
|
|
29
32
|
]);
|
|
30
33
|
|
|
34
|
+
const isInbox = id === INBOX_SESSION_ID;
|
|
31
35
|
const [showAgentSettings, toggleConfig] = useGlobalStore((s) => [
|
|
32
36
|
s.preference.showChatSideBar,
|
|
33
37
|
s.toggleChatSideBar,
|
|
34
38
|
]);
|
|
35
39
|
|
|
40
|
+
const displayTitle = isInbox ? t('inbox.title') : title;
|
|
41
|
+
const displayDesc = isInbox ? t('inbox.desc') : description;
|
|
42
|
+
|
|
36
43
|
return (
|
|
37
44
|
<ChatHeader
|
|
38
45
|
left={
|
|
@@ -48,49 +55,40 @@ const Header = memo(() => {
|
|
|
48
55
|
</Flexbox>
|
|
49
56
|
) : (
|
|
50
57
|
<Flexbox align={'flex-start'} gap={12} horizontal>
|
|
51
|
-
<Avatar
|
|
52
|
-
avatar={avatar}
|
|
53
|
-
background={backgroundColor}
|
|
54
|
-
onClick={() => {
|
|
55
|
-
Router.push(`/chat/${id}/setting`);
|
|
56
|
-
}}
|
|
57
|
-
size={40}
|
|
58
|
-
style={{ cursor: 'pointer', flex: 'none' }}
|
|
59
|
-
title={title}
|
|
60
|
-
/>
|
|
58
|
+
<Avatar avatar={avatar} background={backgroundColor} size={40} title={title} />
|
|
61
59
|
<HeaderTitle
|
|
62
|
-
desc={
|
|
60
|
+
desc={displayDesc}
|
|
63
61
|
tag={
|
|
64
62
|
<>
|
|
65
63
|
<Tag>
|
|
66
|
-
<SiOpenai size={'11px'} style={{ marginTop:
|
|
64
|
+
<SiOpenai size={'11px'} style={{ marginTop: 2 }} />
|
|
67
65
|
{model}
|
|
68
66
|
</Tag>
|
|
69
67
|
{plugins?.length > 0 && <PluginTag plugins={plugins} />}
|
|
70
68
|
</>
|
|
71
69
|
}
|
|
72
|
-
title={
|
|
70
|
+
title={displayTitle}
|
|
73
71
|
/>
|
|
74
72
|
</Flexbox>
|
|
75
73
|
)
|
|
76
74
|
}
|
|
77
75
|
right={
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
76
|
+
<>
|
|
77
|
+
{/*<ActionIcon*/}
|
|
78
|
+
{/* icon={Share2}*/}
|
|
79
|
+
{/* onClick={() => {*/}
|
|
80
|
+
{/* // genShareUrl();*/}
|
|
81
|
+
{/* }}*/}
|
|
82
|
+
{/* size={{ fontSize: 24 }}*/}
|
|
83
|
+
{/* title={t('share')}*/}
|
|
84
|
+
{/*/>*/}
|
|
85
|
+
<ActionIcon
|
|
86
|
+
icon={showAgentSettings ? PanelRightClose : PanelRightOpen}
|
|
87
|
+
onClick={() => toggleConfig()}
|
|
88
|
+
size={{ fontSize: 24 }}
|
|
89
|
+
title={t('roleAndArchive')}
|
|
90
|
+
/>
|
|
91
|
+
{settings && (
|
|
94
92
|
<ActionIcon
|
|
95
93
|
icon={Settings}
|
|
96
94
|
onClick={() => {
|
|
@@ -99,8 +97,8 @@ const Header = memo(() => {
|
|
|
99
97
|
size={{ fontSize: 24 }}
|
|
100
98
|
title={t('header.session', { ns: 'setting' })}
|
|
101
99
|
/>
|
|
102
|
-
|
|
103
|
-
|
|
100
|
+
)}
|
|
101
|
+
</>
|
|
104
102
|
}
|
|
105
103
|
/>
|
|
106
104
|
);
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { DraggablePanelBody, SearchBar } from '@lobehub/ui';
|
|
2
|
+
import { Skeleton } from 'antd';
|
|
3
|
+
import { memo } from 'react';
|
|
4
|
+
import { useTranslation } from 'react-i18next';
|
|
5
|
+
import { Flexbox } from 'react-layout-kit';
|
|
6
|
+
|
|
7
|
+
import { useSessionHydrated } from '@/store/session';
|
|
8
|
+
|
|
9
|
+
import SystemRole from './SystemRole';
|
|
10
|
+
import { Topic } from './Topic';
|
|
11
|
+
|
|
12
|
+
const Inner = memo<{ systemRole: boolean }>(({ systemRole }) => {
|
|
13
|
+
const hydrated = useSessionHydrated();
|
|
14
|
+
const { t } = useTranslation('common');
|
|
15
|
+
|
|
16
|
+
return (
|
|
17
|
+
<DraggablePanelBody style={{ padding: 0 }}>
|
|
18
|
+
{systemRole && <SystemRole />}
|
|
19
|
+
<Flexbox gap={16} padding={16}>
|
|
20
|
+
<SearchBar placeholder={t('topic.searchPlaceholder')} spotlight type={'ghost'} />
|
|
21
|
+
{!hydrated ? (
|
|
22
|
+
<Flexbox gap={8} style={{ marginTop: 8 }}>
|
|
23
|
+
{Array.from({ length: 8 }).map((_, i) => (
|
|
24
|
+
<Skeleton
|
|
25
|
+
active
|
|
26
|
+
avatar={false}
|
|
27
|
+
key={i}
|
|
28
|
+
paragraph={{ rows: 1, width: '100%' }}
|
|
29
|
+
round
|
|
30
|
+
title={false}
|
|
31
|
+
/>
|
|
32
|
+
))}
|
|
33
|
+
</Flexbox>
|
|
34
|
+
) : (
|
|
35
|
+
<Topic />
|
|
36
|
+
)}
|
|
37
|
+
</Flexbox>
|
|
38
|
+
</DraggablePanelBody>
|
|
39
|
+
);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
export default Inner;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ActionIcon,
|
|
1
|
+
import { ActionIcon, EditableMessage } from '@lobehub/ui';
|
|
2
2
|
import { Skeleton } from 'antd';
|
|
3
3
|
import { createStyles } from 'antd-style';
|
|
4
4
|
import { Maximize2Icon } from 'lucide-react';
|
|
@@ -6,18 +6,10 @@ import { memo, useState } from 'react';
|
|
|
6
6
|
import { useTranslation } from 'react-i18next';
|
|
7
7
|
import { Flexbox } from 'react-layout-kit';
|
|
8
8
|
|
|
9
|
+
import Header from '@/pages/chat/features/Sidebar/Header';
|
|
9
10
|
import { agentSelectors, useSessionHydrated, useSessionStore } from '@/store/session';
|
|
10
11
|
|
|
11
|
-
import Header from './Header';
|
|
12
|
-
import { Topic } from './Topic';
|
|
13
|
-
|
|
14
12
|
const useStyles = createStyles(({ css, token }) => ({
|
|
15
|
-
desc: css`
|
|
16
|
-
color: ${token.colorText};
|
|
17
|
-
`,
|
|
18
|
-
model: css`
|
|
19
|
-
color: ${token.colorTextTertiary};
|
|
20
|
-
`,
|
|
21
13
|
prompt: css`
|
|
22
14
|
overflow-x: hidden;
|
|
23
15
|
overflow-y: auto;
|
|
@@ -46,14 +38,11 @@ const useStyles = createStyles(({ css, token }) => ({
|
|
|
46
38
|
|
|
47
39
|
background: linear-gradient(to bottom, transparent, ${token.colorBgLayout});
|
|
48
40
|
`,
|
|
49
|
-
title: css`
|
|
50
|
-
font-size: ${token.fontSizeHeading4}px;
|
|
51
|
-
font-weight: bold;
|
|
52
|
-
`,
|
|
53
41
|
}));
|
|
54
42
|
|
|
55
|
-
const
|
|
43
|
+
const SystemRole = memo(() => {
|
|
56
44
|
const [openModal, setOpenModal] = useState(false);
|
|
45
|
+
|
|
57
46
|
const { styles } = useStyles();
|
|
58
47
|
const [systemRole, updateAgentConfig] = useSessionStore((s) => [
|
|
59
48
|
agentSelectors.currentAgentSystemRole(s),
|
|
@@ -63,7 +52,7 @@ const Inner = memo(() => {
|
|
|
63
52
|
const hydrated = useSessionHydrated();
|
|
64
53
|
const { t } = useTranslation('common');
|
|
65
54
|
return (
|
|
66
|
-
|
|
55
|
+
<>
|
|
67
56
|
<Header
|
|
68
57
|
actions={
|
|
69
58
|
<ActionIcon
|
|
@@ -101,27 +90,8 @@ const Inner = memo(() => {
|
|
|
101
90
|
<Skeleton active avatar={false} style={{ marginTop: 12 }} title={false} />
|
|
102
91
|
)}
|
|
103
92
|
</Flexbox>
|
|
104
|
-
|
|
105
|
-
<SearchBar placeholder={t('topic.searchPlaceholder')} spotlight type={'ghost'} />
|
|
106
|
-
{!hydrated ? (
|
|
107
|
-
<Flexbox gap={8} style={{ marginTop: 8 }}>
|
|
108
|
-
{Array.from({ length: 8 }).map((_, i) => (
|
|
109
|
-
<Skeleton
|
|
110
|
-
active
|
|
111
|
-
avatar={false}
|
|
112
|
-
key={i}
|
|
113
|
-
paragraph={{ rows: 1, width: '100%' }}
|
|
114
|
-
round
|
|
115
|
-
title={false}
|
|
116
|
-
/>
|
|
117
|
-
))}
|
|
118
|
-
</Flexbox>
|
|
119
|
-
) : (
|
|
120
|
-
<Topic />
|
|
121
|
-
)}
|
|
122
|
-
</Flexbox>
|
|
123
|
-
</DraggablePanelBody>
|
|
93
|
+
</>
|
|
124
94
|
);
|
|
125
95
|
});
|
|
126
96
|
|
|
127
|
-
export default
|
|
97
|
+
export default SystemRole;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { DraggablePanel, DraggablePanelContainer } from '@lobehub/ui';
|
|
2
2
|
import { createStyles } from 'antd-style';
|
|
3
3
|
import { rgba } from 'polished';
|
|
4
|
+
import { memo } from 'react';
|
|
4
5
|
|
|
5
6
|
import HeaderSpacing from '@/components/HeaderSpacing';
|
|
6
7
|
import { CHAT_SIDEBAR_WIDTH } from '@/const/layoutTokens';
|
|
@@ -20,7 +21,10 @@ const useStyles = createStyles(({ cx, css, token, stylish }) => ({
|
|
|
20
21
|
`,
|
|
21
22
|
}));
|
|
22
23
|
|
|
23
|
-
|
|
24
|
+
interface SideBarProps {
|
|
25
|
+
systemRole?: boolean;
|
|
26
|
+
}
|
|
27
|
+
const SideBar = memo<SideBarProps>(({ systemRole = true }) => {
|
|
24
28
|
const { styles } = useStyles();
|
|
25
29
|
const [showAgentSettings, toggleConfig] = useGlobalStore((s) => [
|
|
26
30
|
s.preference.showChatSideBar,
|
|
@@ -37,10 +41,10 @@ const Config = () => {
|
|
|
37
41
|
>
|
|
38
42
|
<HeaderSpacing />
|
|
39
43
|
<DraggablePanelContainer style={{ flex: 'none', minWidth: CHAT_SIDEBAR_WIDTH }}>
|
|
40
|
-
<Inner />
|
|
44
|
+
<Inner systemRole={systemRole} />
|
|
41
45
|
</DraggablePanelContainer>
|
|
42
46
|
</DraggablePanel>
|
|
43
47
|
);
|
|
44
|
-
};
|
|
48
|
+
});
|
|
45
49
|
|
|
46
|
-
export default
|
|
50
|
+
export default SideBar;
|
|
@@ -1 +1,39 @@
|
|
|
1
|
-
|
|
1
|
+
import Head from 'next/head';
|
|
2
|
+
import { memo } from 'react';
|
|
3
|
+
import { useTranslation } from 'react-i18next';
|
|
4
|
+
import { Flexbox } from 'react-layout-kit';
|
|
5
|
+
|
|
6
|
+
import { INBOX_SESSION_ID } from '@/const/session';
|
|
7
|
+
import { useOnFinishHydrationSession, useSessionStore } from '@/store/session';
|
|
8
|
+
import { genSiteHeadTitle } from '@/utils/genSiteHeadTitle';
|
|
9
|
+
|
|
10
|
+
import Conversation from './features/Conversation';
|
|
11
|
+
import Header from './features/Header';
|
|
12
|
+
import SideBar from './features/Sidebar';
|
|
13
|
+
import Layout from './layout';
|
|
14
|
+
|
|
15
|
+
const Chat = memo(() => {
|
|
16
|
+
const { t } = useTranslation('common');
|
|
17
|
+
|
|
18
|
+
const pageTitle = genSiteHeadTitle(t('inbox.title'));
|
|
19
|
+
|
|
20
|
+
useOnFinishHydrationSession(() => {
|
|
21
|
+
useSessionStore.getState().activeSession(INBOX_SESSION_ID);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
return (
|
|
25
|
+
<>
|
|
26
|
+
<Head>
|
|
27
|
+
<title>{pageTitle}</title>
|
|
28
|
+
</Head>
|
|
29
|
+
<Layout>
|
|
30
|
+
<Header settings={false} />
|
|
31
|
+
<Flexbox flex={1} height={'calc(100vh - 64px)'} horizontal>
|
|
32
|
+
<Conversation />
|
|
33
|
+
<SideBar systemRole={false} />
|
|
34
|
+
</Flexbox>
|
|
35
|
+
</Layout>
|
|
36
|
+
</>
|
|
37
|
+
);
|
|
38
|
+
});
|
|
39
|
+
export default Chat;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { PropsWithChildren, memo } from 'react';
|
|
2
|
+
import { Flexbox } from 'react-layout-kit';
|
|
3
|
+
|
|
4
|
+
import AppLayout from '@/layout/AppLayout';
|
|
5
|
+
import { useSwitchSideBarOnInit } from '@/store/global';
|
|
6
|
+
|
|
7
|
+
import { Sessions } from './SessionList';
|
|
8
|
+
|
|
9
|
+
const ChatLayout = memo<PropsWithChildren>(({ children }) => {
|
|
10
|
+
useSwitchSideBarOnInit('chat');
|
|
11
|
+
|
|
12
|
+
return (
|
|
13
|
+
<AppLayout>
|
|
14
|
+
<Sessions />
|
|
15
|
+
<Flexbox
|
|
16
|
+
flex={1}
|
|
17
|
+
height={'100vh'}
|
|
18
|
+
id={'lobe-conversion-container'}
|
|
19
|
+
style={{ position: 'relative' }}
|
|
20
|
+
>
|
|
21
|
+
{children}
|
|
22
|
+
</Flexbox>
|
|
23
|
+
</AppLayout>
|
|
24
|
+
);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
export default ChatLayout;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Form, type ItemGroup, ThemeSwitch } from '@lobehub/ui';
|
|
2
2
|
import { Form as AntForm, App, Button, Input, Select } from 'antd';
|
|
3
3
|
import isEqual from 'fast-deep-equal';
|
|
4
|
+
import { changeLanguage } from 'i18next';
|
|
4
5
|
import { debounce } from 'lodash-es';
|
|
5
6
|
import { AppWindow, Palette, Webhook } from 'lucide-react';
|
|
6
7
|
import { memo, useCallback, useMemo } from 'react';
|
|
@@ -27,9 +28,10 @@ const Common = memo(() => {
|
|
|
27
28
|
const { t } = useTranslation('setting');
|
|
28
29
|
const [form] = AntForm.useForm();
|
|
29
30
|
const clearSessions = useSessionStore((s) => s.clearSessions);
|
|
31
|
+
|
|
30
32
|
const settings = useGlobalStore(settingsSelectors.currentSettings, isEqual);
|
|
31
33
|
const [setThemeMode, setSettings, resetSettings] = useGlobalStore((s) => [
|
|
32
|
-
s.
|
|
34
|
+
s.switchThemeMode,
|
|
33
35
|
s.setSettings,
|
|
34
36
|
s.resetSettings,
|
|
35
37
|
]);
|
|
@@ -89,7 +91,14 @@ const Common = memo(() => {
|
|
|
89
91
|
label: t('settingTheme.themeMode.title'),
|
|
90
92
|
},
|
|
91
93
|
{
|
|
92
|
-
children:
|
|
94
|
+
children: (
|
|
95
|
+
<Select
|
|
96
|
+
onChange={(e) => {
|
|
97
|
+
changeLanguage(e);
|
|
98
|
+
}}
|
|
99
|
+
options={options}
|
|
100
|
+
/>
|
|
101
|
+
),
|
|
93
102
|
label: t('settingTheme.lang.title'),
|
|
94
103
|
name: 'language',
|
|
95
104
|
},
|
|
@@ -9,6 +9,7 @@ import { CHANGELOG, DISCORD, GITHUB } from '@/const/url';
|
|
|
9
9
|
|
|
10
10
|
const Footer = memo(() => {
|
|
11
11
|
const theme = useTheme();
|
|
12
|
+
|
|
12
13
|
return (
|
|
13
14
|
<Flexbox align={'center'} horizontal justify={'space-between'} style={{ padding: 16 }}>
|
|
14
15
|
<span style={{ color: theme.colorTextDescription }}>©{new Date().getFullYear()} LobeHub</span>
|
|
@@ -2,7 +2,7 @@ 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
4
|
import { useGlobalStore } from '@/store/global';
|
|
5
|
-
import { initialLobeAgentConfig } from '@/store/session';
|
|
5
|
+
import { initialLobeAgentConfig } from '@/store/session/initialState';
|
|
6
6
|
import type { OpenAIStreamPayload } from '@/types/openai';
|
|
7
7
|
|
|
8
8
|
import { URLS } from './url';
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { useEffect } from 'react';
|
|
2
|
+
|
|
3
|
+
import { useGlobalStore } from '../store';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* 当 Session 水合完毕后才会执行的 useEffect
|
|
7
|
+
* @param fn
|
|
8
|
+
* @param deps
|
|
9
|
+
*/
|
|
10
|
+
export const useOnFinishHydrationGlobal = (fn: () => void, deps: any[] = []) => {
|
|
11
|
+
useEffect(() => {
|
|
12
|
+
const hasRehydrated = useGlobalStore.persist.hasHydrated();
|
|
13
|
+
// 只有当水合完毕后再开始做操作
|
|
14
|
+
if (!hasRehydrated) return;
|
|
15
|
+
|
|
16
|
+
fn();
|
|
17
|
+
}, deps);
|
|
18
|
+
};
|
|
@@ -1,17 +1,13 @@
|
|
|
1
|
-
import { useEffect } from 'react';
|
|
2
|
-
|
|
3
1
|
import { SidebarTabKey } from '../initialState';
|
|
4
2
|
import { useGlobalStore } from '../store';
|
|
3
|
+
import { useOnFinishHydrationGlobal } from './useOnFinishHydrationGlobal';
|
|
5
4
|
|
|
6
5
|
/**
|
|
7
6
|
* 切换侧边栏选项
|
|
8
7
|
* @desc 只会在应用初始化时(且水合后)执行一次
|
|
9
8
|
*/
|
|
10
9
|
export const useSwitchSideBarOnInit = (key: SidebarTabKey) => {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
useGlobalStore.getState().switchSideBar(key);
|
|
15
|
-
}
|
|
16
|
-
}, []);
|
|
10
|
+
useOnFinishHydrationGlobal(() => {
|
|
11
|
+
useGlobalStore.getState().switchSideBar(key);
|
|
12
|
+
});
|
|
17
13
|
};
|
|
@@ -29,7 +29,7 @@ export interface SettingsAction {
|
|
|
29
29
|
* 设置主题模式
|
|
30
30
|
* @param themeMode - 主题模式
|
|
31
31
|
*/
|
|
32
|
-
|
|
32
|
+
switchThemeMode: (themeMode: ThemeMode) => void;
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
export const createSettingsSlice: StateCreator<
|
|
@@ -63,7 +63,7 @@ export const createSettingsSlice: StateCreator<
|
|
|
63
63
|
const oldSetting = get().settings;
|
|
64
64
|
set({ settings: merge(oldSetting, settings) }, false, t('setSettings', settings));
|
|
65
65
|
},
|
|
66
|
-
|
|
66
|
+
switchThemeMode: (themeMode) => {
|
|
67
67
|
get().setSettings({ themeMode });
|
|
68
68
|
},
|
|
69
69
|
});
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { useEffect } from 'react';
|
|
2
|
+
|
|
3
|
+
import { useSessionStore } from '../store';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* 当 Session 水合完毕后才会执行的 useEffect
|
|
7
|
+
* @param fn
|
|
8
|
+
* @param deps
|
|
9
|
+
*/
|
|
10
|
+
export const useOnFinishHydrationSession = (fn: () => void, deps: any[] = []) => {
|
|
11
|
+
useEffect(() => {
|
|
12
|
+
const hasRehydrated = useSessionStore.persist.hasHydrated();
|
|
13
|
+
// 只有当水合完毕后再开始做操作
|
|
14
|
+
if (!hasRehydrated) return;
|
|
15
|
+
|
|
16
|
+
fn();
|
|
17
|
+
}, deps);
|
|
18
|
+
};
|
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
export * from './hooks
|
|
1
|
+
export * from './hooks';
|
|
2
2
|
export * from './selectors';
|
|
3
|
-
export { initialLobeAgentConfig } from './slices/agentConfig';
|
|
4
|
-
export { initLobeSession } from './slices/session';
|
|
5
3
|
export type { SessionStore } from './store';
|
|
6
4
|
export { useSessionStore } from './store';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { AgentConfigState, initialAgentConfigState } from './slices/agentConfig';
|
|
2
|
-
import { ChatState, initialChatState } from './slices/chat';
|
|
3
|
-
import { SessionState, initialSessionState } from './slices/session';
|
|
1
|
+
import { AgentConfigState, initialAgentConfigState } from './slices/agentConfig/initialState';
|
|
2
|
+
import { ChatState, initialChatState } from './slices/chat/initialState';
|
|
3
|
+
import { SessionState, initialSessionState } from './slices/session/initialState';
|
|
4
4
|
|
|
5
5
|
export type SessionStoreState = SessionState & ChatState & AgentConfigState;
|
|
6
6
|
|
|
@@ -9,3 +9,6 @@ export const initialState: SessionStoreState = {
|
|
|
9
9
|
...initialChatState,
|
|
10
10
|
...initialAgentConfigState,
|
|
11
11
|
};
|
|
12
|
+
|
|
13
|
+
export { initialLobeAgentConfig } from './slices/agentConfig';
|
|
14
|
+
export { initLobeSession } from './slices/session/initialState';
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { agentSelectors } from './slices/agentConfig';
|
|
2
|
-
export { chatSelectors, topicSelectors } from './slices/chat';
|
|
3
|
-
export { sessionSelectors } from './slices/session';
|
|
1
|
+
export { agentSelectors } from './slices/agentConfig/selectors';
|
|
2
|
+
export { chatSelectors, topicSelectors } from './slices/chat/selectors';
|
|
3
|
+
export { sessionSelectors } from './slices/session/selectors';
|
|
@@ -2,12 +2,13 @@ import { produce } from 'immer';
|
|
|
2
2
|
import { StateCreator } from 'zustand/vanilla';
|
|
3
3
|
|
|
4
4
|
import { promptPickEmoji, promptSummaryAgentName, promptSummaryDescription } from '@/prompts/agent';
|
|
5
|
-
import { SessionStore, sessionSelectors } from '@/store/session';
|
|
6
5
|
import { MetaData } from '@/types/meta';
|
|
7
6
|
import { LobeAgentConfig } from '@/types/session';
|
|
8
7
|
import { fetchPresetTaskResult } from '@/utils/fetch';
|
|
9
8
|
import { setNamespace } from '@/utils/storeDebug';
|
|
10
9
|
|
|
10
|
+
import { SessionStore } from '../../store';
|
|
11
|
+
import { sessionSelectors } from '../session/selectors';
|
|
11
12
|
import { SessionLoadingState } from './initialState';
|
|
12
13
|
|
|
13
14
|
const t = setNamespace('agentConfig');
|
|
@@ -7,7 +7,7 @@ import { SessionStore } from '@/store/session';
|
|
|
7
7
|
import { LanguageModel } from '@/types/llm';
|
|
8
8
|
import { MetaData } from '@/types/meta';
|
|
9
9
|
|
|
10
|
-
import { sessionSelectors } from '../session';
|
|
10
|
+
import { sessionSelectors } from '../session/selectors';
|
|
11
11
|
import { initialLobeAgentConfig } from './initialState';
|
|
12
12
|
|
|
13
13
|
const currentAgentMeta = (s: SessionStore): MetaData => {
|
|
@@ -25,8 +25,17 @@ const currentAutocomplete = (s: SessionStore): Autocomplete => ({
|
|
|
25
25
|
|
|
26
26
|
const currentAgentTitle = (s: SessionStore) => currentAgentMeta(s)?.title || t('defaultSession');
|
|
27
27
|
|
|
28
|
+
const currentAgentConfig = (s: SessionStore) => {
|
|
29
|
+
const session = sessionSelectors.currentSession(s);
|
|
30
|
+
return merge({}, initialLobeAgentConfig, session?.config);
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const currentAgentSystemRole = (s: SessionStore) => {
|
|
34
|
+
return currentAgentConfig(s).systemRole;
|
|
35
|
+
};
|
|
36
|
+
|
|
28
37
|
const currentAgentDescription = (s: SessionStore) =>
|
|
29
|
-
currentAgentMeta(s)?.description || t('noDescription');
|
|
38
|
+
currentAgentMeta(s)?.description || currentAgentSystemRole(s) || t('noDescription');
|
|
30
39
|
|
|
31
40
|
const currentAgentBackgroundColor = (s: SessionStore) => {
|
|
32
41
|
const session = sessionSelectors.currentSession(s);
|
|
@@ -41,15 +50,6 @@ const currentAgentAvatar = (s: SessionStore) => {
|
|
|
41
50
|
return session.meta.avatar || DEFAULT_AVATAR;
|
|
42
51
|
};
|
|
43
52
|
|
|
44
|
-
const currentAgentConfig = (s: SessionStore) => {
|
|
45
|
-
const session = sessionSelectors.currentSession(s);
|
|
46
|
-
return merge({}, initialLobeAgentConfig, session?.config);
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
const currentAgentSystemRole = (s: SessionStore) => {
|
|
50
|
-
return currentAgentConfig(s).systemRole;
|
|
51
|
-
};
|
|
52
|
-
|
|
53
53
|
const currentAgentModel = (s: SessionStore): LanguageModel => {
|
|
54
54
|
const config = currentAgentConfig(s);
|
|
55
55
|
|
|
@@ -4,15 +4,18 @@ import { StateCreator } from 'zustand/vanilla';
|
|
|
4
4
|
import { LOADING_FLAT } from '@/const/message';
|
|
5
5
|
import { fetchChatModel } from '@/services/chatModel';
|
|
6
6
|
import { fetchPlugin } from '@/services/plugin';
|
|
7
|
-
import { SessionStore
|
|
8
|
-
import { getSlicedMessagesWithConfig } from '@/store/session/slices/chat/utils';
|
|
7
|
+
import { SessionStore } from '@/store/session';
|
|
9
8
|
import { ChatMessage, OpenAIFunctionCall } from '@/types/chatMessage';
|
|
10
9
|
import { fetchSSE } from '@/utils/fetch';
|
|
11
10
|
import { isFunctionMessage } from '@/utils/message';
|
|
12
11
|
import { setNamespace } from '@/utils/storeDebug';
|
|
13
12
|
import { nanoid } from '@/utils/uuid';
|
|
14
13
|
|
|
14
|
+
import { agentSelectors } from '../../agentConfig/selectors';
|
|
15
|
+
import { sessionSelectors } from '../../session/selectors';
|
|
15
16
|
import { MessageDispatch, messagesReducer } from '../reducers/message';
|
|
17
|
+
import { chatSelectors } from '../selectors';
|
|
18
|
+
import { getSlicedMessagesWithConfig } from '../utils';
|
|
16
19
|
|
|
17
20
|
const t = setNamespace('chat/message');
|
|
18
21
|
|
|
@@ -24,11 +27,6 @@ export interface ChatMessageAction {
|
|
|
24
27
|
* 清除消息
|
|
25
28
|
*/
|
|
26
29
|
clearMessage: () => void;
|
|
27
|
-
/**
|
|
28
|
-
* 创建或发送消息
|
|
29
|
-
* @param text - 消息文本
|
|
30
|
-
*/
|
|
31
|
-
createOrSendMsg: (text: string) => Promise<void>;
|
|
32
30
|
/**
|
|
33
31
|
* 删除消息
|
|
34
32
|
* @param id - 消息 ID
|
|
@@ -86,19 +84,6 @@ export const chatMessage: StateCreator<
|
|
|
86
84
|
}
|
|
87
85
|
},
|
|
88
86
|
|
|
89
|
-
createOrSendMsg: async (message) => {
|
|
90
|
-
if (!message) return;
|
|
91
|
-
|
|
92
|
-
const { sendMessage, createSession } = get();
|
|
93
|
-
const session = sessionSelectors.currentSession(get());
|
|
94
|
-
|
|
95
|
-
if (!session) {
|
|
96
|
-
await createSession();
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
sendMessage(message);
|
|
100
|
-
},
|
|
101
|
-
|
|
102
87
|
deleteMessage: (id) => {
|
|
103
88
|
get().dispatchMessage({ id, type: 'deleteMessage' });
|
|
104
89
|
},
|
|
@@ -325,4 +310,12 @@ export const chatMessage: StateCreator<
|
|
|
325
310
|
|
|
326
311
|
await realFetchAIResponse(chats, message.id);
|
|
327
312
|
},
|
|
313
|
+
|
|
314
|
+
// genShareUrl: () => {
|
|
315
|
+
// const session = sessionSelectors.currentSession(get());
|
|
316
|
+
// if (!session) return '';
|
|
317
|
+
//
|
|
318
|
+
// const agent = session.config;
|
|
319
|
+
// return genShareMessagesUrl(session.chats, agent.systemRole);
|
|
320
|
+
// },
|
|
328
321
|
});
|