@lobehub/chat 0.74.0 → 0.76.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/CHANGELOG.md +86 -0
- package/README.md +26 -5
- package/README.zh-CN.md +25 -4
- package/docs/deploy-with-azure-openai.zh-CN.md +45 -0
- package/locales/en_US/market.json +12 -0
- package/locales/en_US/plugin.json +11 -2
- package/locales/en_US/setting.json +3 -1
- package/locales/ru_RU/market.json +12 -0
- package/locales/ru_RU/plugin.json +44 -49
- package/locales/ru_RU/setting.json +3 -1
- package/locales/zh_CN/common.json +1 -1
- package/locales/zh_CN/market.json +12 -0
- package/locales/zh_CN/plugin.json +19 -5
- package/locales/zh_CN/setting.json +62 -14
- package/next.config.mjs +3 -1
- package/package.json +5 -5
- package/scripts/i18nWorkflow/const.ts +19 -0
- package/scripts/i18nWorkflow/genDefaultLocale.ts +19 -0
- package/scripts/i18nWorkflow/genDiff.ts +50 -0
- package/scripts/i18nWorkflow/genResources.ts +26 -0
- package/scripts/i18nWorkflow/index.ts +15 -0
- package/scripts/i18nWorkflow/utils.ts +85 -0
- package/src/config/client.ts +14 -0
- package/src/config/server.ts +5 -0
- package/src/const/layoutTokens.ts +3 -1
- package/src/const/market.ts +15 -0
- package/src/const/settings.ts +2 -1
- package/src/const/url.ts +29 -4
- package/src/features/AgentSetting/AgentConfig/index.tsx +1 -2
- package/src/features/AgentSetting/AgentPlugin/MarketSettingModal.tsx +1 -1
- package/src/features/AgentSetting/store/initialState.ts +1 -1
- package/src/features/MobileTabBar/index.tsx +2 -2
- package/src/features/SideBar/TopActions.tsx +2 -2
- package/src/locales/default/market.ts +12 -0
- package/src/locales/default/setting.ts +1 -0
- package/src/locales/resources/en_US.ts +2 -0
- package/src/locales/resources/ru_RU.ts +2 -0
- package/src/locales/resources/zh_CN.ts +2 -0
- package/src/pages/api/openai/chat.api.ts +6 -10
- package/src/pages/api/openai/createAzureOpenai.ts +13 -9
- package/src/pages/chat/features/Conversation/Input/{Action.tsx → ActionBar/ActionLeft.tsx} +2 -2
- package/src/pages/chat/features/Conversation/Input/ActionBar/ActionRight.tsx +36 -0
- package/src/pages/chat/features/Conversation/Input/Desktop.tsx +40 -0
- package/src/pages/chat/features/Conversation/Input/Footer/SaveTopic.tsx +27 -0
- package/src/pages/chat/features/Conversation/Input/Footer/index.tsx +35 -0
- package/src/pages/chat/features/Conversation/Input/Mobile.tsx +12 -0
- package/src/pages/chat/features/Conversation/Input/index.tsx +20 -38
- package/src/pages/chat/features/SessionList/Header/Desktop.tsx +6 -13
- package/src/pages/chat/features/SessionList/Header/Mobile.tsx +1 -1
- package/src/pages/chat/features/SessionList/List/AddButton.tsx +1 -1
- package/src/pages/chat/features/SessionList/List/Item/index.tsx +4 -3
- package/src/pages/chat/features/SessionList/List/index.tsx +1 -3
- package/src/pages/chat/features/SessionList/Mobile.tsx +2 -12
- package/src/pages/chat/features/SessionSearchBar/index.tsx +26 -0
- package/src/pages/chat/features/Sidebar/Topic/index.tsx +18 -6
- package/src/pages/chat/features/Sidebar/TopicSearchBar/index.tsx +24 -0
- package/src/pages/chat/features/Sidebar/index.tsx +2 -9
- package/src/pages/market/features/AgentCard/AgentCardBanner.tsx +64 -0
- package/src/pages/market/features/AgentCard/AgentCardItem.tsx +57 -0
- package/src/pages/market/features/AgentCard/Loading.tsx +13 -0
- package/src/pages/market/features/AgentCard/index.tsx +37 -0
- package/src/pages/market/features/AgentCard/style.ts +22 -0
- package/src/pages/market/features/AgentSearchBar/index.tsx +26 -0
- package/src/pages/market/features/Header/Desktop.tsx +15 -4
- package/src/pages/market/features/Header/Mobile.tsx +7 -24
- package/src/pages/market/features/SideBar/AgentInfo/Comment.tsx +16 -0
- package/src/pages/market/features/SideBar/AgentInfo/Header.tsx +68 -0
- package/src/pages/market/features/SideBar/AgentInfo/Loading.tsx +61 -0
- package/src/pages/market/features/SideBar/AgentInfo/TokenTag.tsx +25 -0
- package/src/pages/market/features/SideBar/AgentInfo/index.tsx +68 -0
- package/src/pages/market/features/SideBar/AgentInfo/style.ts +46 -0
- package/src/pages/market/features/SideBar/Desktop.tsx +70 -0
- package/src/pages/market/features/SideBar/Mobile.tsx +36 -0
- package/src/pages/market/features/SideBar/index.tsx +23 -0
- package/src/pages/market/features/TagList/index.tsx +29 -0
- package/src/pages/market/index.page.tsx +11 -2
- package/src/pages/market/layout.mobile.tsx +8 -7
- package/src/pages/market/layout.tsx +39 -1
- package/src/pages/settings/features/Header/Desktop.tsx +2 -4
- package/src/pages/settings/features/Header/Mobile.tsx +1 -1
- package/src/pages/settings/features/Settings/Common.tsx +1 -2
- package/src/pages/settings/features/Settings/LLM/index.tsx +12 -1
- package/src/pages/settings/features/Settings/index.tsx +17 -4
- package/src/services/_header.ts +1 -1
- package/src/services/agentMarket.ts +21 -0
- package/src/store/global/initialState.ts +1 -2
- package/src/store/global/selectors.test.ts +0 -1
- package/src/store/market/action.ts +57 -0
- package/src/store/market/index.ts +3 -0
- package/src/store/market/initialState.ts +17 -0
- package/src/store/market/selectors.ts +36 -0
- package/src/store/market/store.ts +51 -0
- package/src/store/session/slices/session/action.ts +5 -3
- package/src/store/session/slices/session/initialState.ts +2 -0
- package/src/store/session/slices/session/reducers/session.test.ts +4 -4
- package/src/types/market.ts +19 -0
- package/src/types/meta.ts +1 -1
- package/src/utils/filter.ts +1 -1
- package/src/utils/findDuplicates.ts +22 -0
- package/scripts/genDefaultLocale.ts +0 -18
- package/scripts/genResources.ts +0 -51
- package/scripts/toc.ts +0 -7
- package/src/components/Empty/index.tsx +0 -63
- package/src/components/Empty/style.ts +0 -31
- package/src/components/SelectWithImg/index.tsx +0 -97
- package/src/components/SelectWithImg/styles.ts +0 -43
- package/src/pages/chat/features/Conversation/Input/ActionRight.tsx +0 -31
- package/src/pages/chat/features/Conversation/Input/Footer.tsx +0 -49
- /package/src/components/{ManifestPreviewer.tsx → ManifestPreviewer/index.tsx} +0 -0
- /package/src/pages/chat/features/Conversation/Input/{Token.tsx → ActionBar/Token.tsx} +0 -0
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { ActionIcon } from '@lobehub/ui';
|
|
2
|
+
import { Drawer } from 'antd';
|
|
3
|
+
import { useTheme } from 'antd-style';
|
|
4
|
+
import { X } from 'lucide-react';
|
|
5
|
+
import { PropsWithChildren, memo } from 'react';
|
|
6
|
+
import { useTranslation } from 'react-i18next';
|
|
7
|
+
|
|
8
|
+
import { agentMarketSelectors, useMarketStore } from '@/store/market';
|
|
9
|
+
|
|
10
|
+
const Mobile = memo<PropsWithChildren>(({ children }) => {
|
|
11
|
+
const theme = useTheme();
|
|
12
|
+
const [showAgentSidebar, deactivateAgent] = useMarketStore((s) => [
|
|
13
|
+
agentMarketSelectors.showSideBar(s),
|
|
14
|
+
s.deactivateAgent,
|
|
15
|
+
]);
|
|
16
|
+
|
|
17
|
+
const { t } = useTranslation('market');
|
|
18
|
+
|
|
19
|
+
return (
|
|
20
|
+
<Drawer
|
|
21
|
+
bodyStyle={{ padding: 0 }}
|
|
22
|
+
closeIcon={<ActionIcon icon={X} size={{ blockSize: 32, fontSize: 20 }} />}
|
|
23
|
+
drawerStyle={{ background: theme.colorBgContainer }}
|
|
24
|
+
headerStyle={{ padding: '8px 4px' }}
|
|
25
|
+
height={'75vh'}
|
|
26
|
+
onClose={deactivateAgent}
|
|
27
|
+
open={showAgentSidebar}
|
|
28
|
+
placement={'bottom'}
|
|
29
|
+
title={t('sidebar.title')}
|
|
30
|
+
>
|
|
31
|
+
{children}
|
|
32
|
+
</Drawer>
|
|
33
|
+
);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
export default Mobile;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { useResponsive } from 'antd-style';
|
|
2
|
+
import { memo } from 'react';
|
|
3
|
+
import { Flexbox } from 'react-layout-kit';
|
|
4
|
+
|
|
5
|
+
import AgentInfo from './AgentInfo';
|
|
6
|
+
import Desktop from './Desktop';
|
|
7
|
+
import Mobile from './Mobile';
|
|
8
|
+
|
|
9
|
+
const SideBar = memo(() => {
|
|
10
|
+
const { mobile } = useResponsive();
|
|
11
|
+
|
|
12
|
+
const Render = mobile ? Mobile : Desktop;
|
|
13
|
+
|
|
14
|
+
return (
|
|
15
|
+
<Render>
|
|
16
|
+
<Flexbox>
|
|
17
|
+
<AgentInfo />
|
|
18
|
+
</Flexbox>
|
|
19
|
+
</Render>
|
|
20
|
+
);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
export default SideBar;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { Button } from 'antd';
|
|
2
|
+
import isEqual from 'fast-deep-equal';
|
|
3
|
+
import { startCase } from 'lodash-es';
|
|
4
|
+
import { memo } from 'react';
|
|
5
|
+
import { Flexbox } from 'react-layout-kit';
|
|
6
|
+
|
|
7
|
+
import { agentMarketSelectors, useMarketStore } from '@/store/market';
|
|
8
|
+
|
|
9
|
+
const TagList = memo(() => {
|
|
10
|
+
const agentTagList = useMarketStore(agentMarketSelectors.getAgentTagList, isEqual);
|
|
11
|
+
const keywords = useMarketStore((s) => s.searchKeywords);
|
|
12
|
+
|
|
13
|
+
return (
|
|
14
|
+
<Flexbox gap={8} horizontal style={{ flexWrap: 'wrap' }}>
|
|
15
|
+
{agentTagList.map((item) => (
|
|
16
|
+
<Button
|
|
17
|
+
key={item}
|
|
18
|
+
onClick={() => useMarketStore.setState({ searchKeywords: item })}
|
|
19
|
+
size={'small'}
|
|
20
|
+
type={keywords === item ? 'primary' : 'default'}
|
|
21
|
+
>
|
|
22
|
+
{startCase(item)}
|
|
23
|
+
</Button>
|
|
24
|
+
))}
|
|
25
|
+
</Flexbox>
|
|
26
|
+
);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
export default TagList;
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import { useResponsive } from 'antd-style';
|
|
2
2
|
import Head from 'next/head';
|
|
3
|
-
import { memo } from 'react';
|
|
3
|
+
import { memo, useEffect } from 'react';
|
|
4
4
|
import { useTranslation } from 'react-i18next';
|
|
5
5
|
|
|
6
|
+
import { useMarketStore } from '@/store/market';
|
|
6
7
|
import { genSiteHeadTitle } from '@/utils/genSiteHeadTitle';
|
|
7
8
|
|
|
9
|
+
import AgentCard from './features/AgentCard';
|
|
10
|
+
import AgentSearchBar from './features/AgentSearchBar';
|
|
8
11
|
import DesktopLayout from './layout';
|
|
9
12
|
import MobileLayout from './layout.mobile';
|
|
10
13
|
|
|
@@ -13,6 +16,11 @@ const Market = memo(() => {
|
|
|
13
16
|
const pageTitle = genSiteHeadTitle(t('tab.market'));
|
|
14
17
|
const { mobile } = useResponsive();
|
|
15
18
|
|
|
19
|
+
useEffect(() => {
|
|
20
|
+
// refs: https://github.com/pmndrs/zustand/blob/main/docs/integrations/persisting-store-data.md#hashydrated
|
|
21
|
+
useMarketStore.persist.rehydrate();
|
|
22
|
+
}, []);
|
|
23
|
+
|
|
16
24
|
const RenderLayout = mobile ? MobileLayout : DesktopLayout;
|
|
17
25
|
|
|
18
26
|
return (
|
|
@@ -21,7 +29,8 @@ const Market = memo(() => {
|
|
|
21
29
|
<title>{pageTitle}</title>
|
|
22
30
|
</Head>
|
|
23
31
|
<RenderLayout>
|
|
24
|
-
<
|
|
32
|
+
<AgentSearchBar />
|
|
33
|
+
<AgentCard />
|
|
25
34
|
</RenderLayout>
|
|
26
35
|
</>
|
|
27
36
|
);
|
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
import { ReactNode, memo } from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { Flexbox } from 'react-layout-kit';
|
|
3
3
|
|
|
4
4
|
import AppMobileLayout from '@/layout/AppMobileLayout';
|
|
5
|
-
import
|
|
5
|
+
import SideBar from '@/pages/market/features/SideBar';
|
|
6
6
|
|
|
7
7
|
import Header from './features/Header';
|
|
8
8
|
|
|
9
|
-
const
|
|
10
|
-
useSwitchSideBarOnInit('chat');
|
|
11
|
-
|
|
9
|
+
const MarketLayout = memo<{ children: ReactNode }>(({ children }) => {
|
|
12
10
|
return (
|
|
13
11
|
<AppMobileLayout navBar={<Header />} showTabBar>
|
|
14
|
-
<
|
|
12
|
+
<Flexbox flex={1} gap={16} style={{ padding: 16 }}>
|
|
13
|
+
{children}
|
|
14
|
+
</Flexbox>
|
|
15
|
+
<SideBar />
|
|
15
16
|
</AppMobileLayout>
|
|
16
17
|
);
|
|
17
18
|
});
|
|
18
19
|
|
|
19
|
-
export default
|
|
20
|
+
export default MarketLayout;
|
|
@@ -1,10 +1,30 @@
|
|
|
1
|
+
import { GridBackground } from '@lobehub/ui';
|
|
2
|
+
import { createStyles } from 'antd-style';
|
|
1
3
|
import { PropsWithChildren, memo } from 'react';
|
|
2
4
|
import { Center, Flexbox } from 'react-layout-kit';
|
|
3
5
|
|
|
6
|
+
import SafeSpacing from '@/components/SafeSpacing';
|
|
7
|
+
import { MAX_WIDTH } from '@/const/layoutTokens';
|
|
8
|
+
|
|
4
9
|
import AppLayout from '../../layout/AppLayout';
|
|
5
10
|
import Header from './features/Header';
|
|
11
|
+
import SideBar from './features/SideBar';
|
|
12
|
+
|
|
13
|
+
const useStyles = createStyles(({ css }) => ({
|
|
14
|
+
background: css`
|
|
15
|
+
width: 80%;
|
|
16
|
+
margin: -60px 0 -20px;
|
|
17
|
+
`,
|
|
18
|
+
title: css`
|
|
19
|
+
z-index: 2;
|
|
20
|
+
margin-top: 24px;
|
|
21
|
+
font-size: 56px;
|
|
22
|
+
font-weight: 800;
|
|
23
|
+
`,
|
|
24
|
+
}));
|
|
6
25
|
|
|
7
26
|
const MarketLayout = memo<PropsWithChildren>(({ children }) => {
|
|
27
|
+
const { theme, styles } = useStyles();
|
|
8
28
|
return (
|
|
9
29
|
<AppLayout>
|
|
10
30
|
<Flexbox
|
|
@@ -14,7 +34,25 @@ const MarketLayout = memo<PropsWithChildren>(({ children }) => {
|
|
|
14
34
|
style={{ position: 'relative' }}
|
|
15
35
|
>
|
|
16
36
|
<Header />
|
|
17
|
-
<
|
|
37
|
+
<Flexbox flex={1} height={'calc(100vh - 64px)'} horizontal>
|
|
38
|
+
<Flexbox align={'center'} flex={1} style={{ overflow: 'auto', padding: 16 }}>
|
|
39
|
+
<SafeSpacing />
|
|
40
|
+
|
|
41
|
+
<Flexbox gap={16} style={{ maxWidth: MAX_WIDTH, position: 'relative', width: '100%' }}>
|
|
42
|
+
<Center>
|
|
43
|
+
<h1 className={styles.title}>Find & Use The Best Agents</h1>
|
|
44
|
+
<GridBackground
|
|
45
|
+
animation
|
|
46
|
+
className={styles.background}
|
|
47
|
+
colorFront={theme.colorText}
|
|
48
|
+
random
|
|
49
|
+
/>
|
|
50
|
+
</Center>
|
|
51
|
+
{children}
|
|
52
|
+
</Flexbox>
|
|
53
|
+
</Flexbox>
|
|
54
|
+
<SideBar />
|
|
55
|
+
</Flexbox>
|
|
18
56
|
</Flexbox>
|
|
19
57
|
</AppLayout>
|
|
20
58
|
);
|
|
@@ -1,17 +1,15 @@
|
|
|
1
1
|
import { ChatHeader, ChatHeaderTitle } from '@lobehub/ui';
|
|
2
|
+
import Router from 'next/router';
|
|
2
3
|
import { memo } from 'react';
|
|
3
4
|
import { useTranslation } from 'react-i18next';
|
|
4
5
|
|
|
5
|
-
import { useSessionStore } from '@/store/session';
|
|
6
|
-
|
|
7
6
|
const Index = memo(() => {
|
|
8
7
|
const { t } = useTranslation('setting');
|
|
9
|
-
const [switchBackToChat] = useSessionStore((s) => [s.switchBackToChat]);
|
|
10
8
|
|
|
11
9
|
return (
|
|
12
10
|
<ChatHeader
|
|
13
11
|
left={<ChatHeaderTitle title={t('header.global')} />}
|
|
14
|
-
onBackClick={
|
|
12
|
+
onBackClick={() => Router.back()}
|
|
15
13
|
showBackButton
|
|
16
14
|
/>
|
|
17
15
|
);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Form, type ItemGroup, SliderWithInput } from '@lobehub/ui';
|
|
1
|
+
import { Form, type ItemGroup, SelectWithImg, SliderWithInput } from '@lobehub/ui';
|
|
2
2
|
import { Form as AntForm, App, Button, Input, Select } from 'antd';
|
|
3
3
|
import isEqual from 'fast-deep-equal';
|
|
4
4
|
import { changeLanguage } from 'i18next';
|
|
@@ -7,7 +7,6 @@ import { AppWindow, Monitor, Moon, Palette, Sun } from 'lucide-react';
|
|
|
7
7
|
import { memo, useCallback, useMemo } from 'react';
|
|
8
8
|
import { useTranslation } from 'react-i18next';
|
|
9
9
|
|
|
10
|
-
import SelectWithImg from '@/components/SelectWithImg';
|
|
11
10
|
import { FORM_STYLE } from '@/const/layoutTokens';
|
|
12
11
|
import { DEFAULT_SETTINGS } from '@/const/settings';
|
|
13
12
|
import AvatarWithUpload from '@/features/AvatarWithUpload';
|
|
@@ -8,6 +8,7 @@ import { memo } from 'react';
|
|
|
8
8
|
import { Trans, useTranslation } from 'react-i18next';
|
|
9
9
|
import { Flexbox } from 'react-layout-kit';
|
|
10
10
|
|
|
11
|
+
import { getClientConfig } from '@/config/client';
|
|
11
12
|
import { FORM_STYLE } from '@/const/layoutTokens';
|
|
12
13
|
import { globalSelectors, useEffectAfterGlobalHydrated, useGlobalStore } from '@/store/global';
|
|
13
14
|
|
|
@@ -81,7 +82,17 @@ const LLM = memo(() => {
|
|
|
81
82
|
name: [configKey, 'openAI', 'endpoint'],
|
|
82
83
|
},
|
|
83
84
|
{
|
|
84
|
-
children:
|
|
85
|
+
children: (
|
|
86
|
+
<Switch disabled={getClientConfig().USE_AZURE_OPENAI} />
|
|
87
|
+
// <Flexbox gap={4}>
|
|
88
|
+
// <div>
|
|
89
|
+
//
|
|
90
|
+
// </div>
|
|
91
|
+
// {getClientConfig().USE_AZURE_OPENAI && (
|
|
92
|
+
// <div className={styles.tip}>{t('llm.OpenAI.useAzure.serverConfig')}</div>
|
|
93
|
+
// )}
|
|
94
|
+
// </Flexbox>
|
|
95
|
+
),
|
|
85
96
|
desc: t('llm.OpenAI.useAzure.desc'),
|
|
86
97
|
label: t('llm.OpenAI.useAzure.title'),
|
|
87
98
|
name: [configKey, 'openAI', 'useAzure'],
|
|
@@ -2,7 +2,7 @@ import { GridBackground, Icon, Logo, TabsNav } from '@lobehub/ui';
|
|
|
2
2
|
import { createStyles } from 'antd-style';
|
|
3
3
|
import { PackageCheck } from 'lucide-react';
|
|
4
4
|
import { rgba } from 'polished';
|
|
5
|
-
import { memo } from 'react';
|
|
5
|
+
import { memo, useMemo } from 'react';
|
|
6
6
|
import { useTranslation } from 'react-i18next';
|
|
7
7
|
import { Center, Flexbox } from 'react-layout-kit';
|
|
8
8
|
|
|
@@ -64,6 +64,21 @@ const Settings = memo(() => {
|
|
|
64
64
|
|
|
65
65
|
const [tab, setTab] = useGlobalStore((s) => [s.settingsTab, s.switchSettingTabs]);
|
|
66
66
|
|
|
67
|
+
const content = useMemo(() => {
|
|
68
|
+
switch (tab) {
|
|
69
|
+
case 'llm': {
|
|
70
|
+
return <LLM />;
|
|
71
|
+
}
|
|
72
|
+
case 'agent': {
|
|
73
|
+
return <Agent />;
|
|
74
|
+
}
|
|
75
|
+
default:
|
|
76
|
+
case 'common': {
|
|
77
|
+
return <Common />;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}, [tab]);
|
|
81
|
+
|
|
67
82
|
return (
|
|
68
83
|
<Center gap={16} width={'100%'}>
|
|
69
84
|
<Flexbox align={'flex-end'} className={styles.tabs} horizontal justify={'center'}>
|
|
@@ -91,9 +106,7 @@ const Settings = memo(() => {
|
|
|
91
106
|
<div>{`${pkg.version}`}</div>
|
|
92
107
|
</Flexbox>
|
|
93
108
|
</Flexbox>
|
|
94
|
-
{
|
|
95
|
-
{tab === 'llm' && <LLM />}
|
|
96
|
-
{tab === 'agent' && <Agent />}
|
|
109
|
+
{content}
|
|
97
110
|
</Center>
|
|
98
111
|
);
|
|
99
112
|
});
|
package/src/services/_header.ts
CHANGED
|
@@ -24,7 +24,7 @@ export const createHeaderWithOpenAI = (header?: HeadersInit): HeadersInit => {
|
|
|
24
24
|
|
|
25
25
|
if (openai.useAzure) {
|
|
26
26
|
Object.assign(result, {
|
|
27
|
-
[AZURE_OPENAI_API_VERSION]: openai.azureApiVersion,
|
|
27
|
+
[AZURE_OPENAI_API_VERSION]: openai.azureApiVersion || '',
|
|
28
28
|
[USE_AZURE_OPENAI]: '1',
|
|
29
29
|
});
|
|
30
30
|
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { getAgentIndexJSON, getAgentJSON } from '@/const/url';
|
|
2
|
+
import { useGlobalStore } from '@/store/global';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* 请求助手列表
|
|
6
|
+
*/
|
|
7
|
+
export const getAgentList = async () => {
|
|
8
|
+
const res = await fetch(getAgentIndexJSON(useGlobalStore.getState().settings.language));
|
|
9
|
+
|
|
10
|
+
return res.json();
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* 请求助手 manifest
|
|
15
|
+
*/
|
|
16
|
+
export const getAgentManifest = async (identifier?: string) => {
|
|
17
|
+
if (!identifier) return;
|
|
18
|
+
const res = await fetch(getAgentJSON(identifier, useGlobalStore.getState().settings.language));
|
|
19
|
+
|
|
20
|
+
return res.json();
|
|
21
|
+
};
|
|
@@ -21,7 +21,7 @@ export interface GlobalState {
|
|
|
21
21
|
* 用户设置
|
|
22
22
|
*/
|
|
23
23
|
settings: GlobalSettings;
|
|
24
|
-
settingsTab
|
|
24
|
+
settingsTab?: SettingsTabs;
|
|
25
25
|
sidebarKey: SidebarTabKey;
|
|
26
26
|
}
|
|
27
27
|
|
|
@@ -44,6 +44,5 @@ export const initialState: GlobalState = {
|
|
|
44
44
|
showSessionPanel: true,
|
|
45
45
|
},
|
|
46
46
|
settings: DEFAULT_SETTINGS,
|
|
47
|
-
settingsTab: 'common',
|
|
48
47
|
sidebarKey: 'chat',
|
|
49
48
|
};
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import isEqual from 'fast-deep-equal';
|
|
2
|
+
import { produce } from 'immer';
|
|
3
|
+
import useSWR, { SWRResponse } from 'swr';
|
|
4
|
+
import type { StateCreator } from 'zustand/vanilla';
|
|
5
|
+
|
|
6
|
+
import { getAgentList, getAgentManifest } from '@/services/agentMarket';
|
|
7
|
+
import { AgentsMarketItem, LobeChatAgentsMarketIndex } from '@/types/market';
|
|
8
|
+
|
|
9
|
+
import type { Store } from './store';
|
|
10
|
+
|
|
11
|
+
export interface StoreAction {
|
|
12
|
+
activateAgent: (identifier: string) => void;
|
|
13
|
+
deactivateAgent: () => void;
|
|
14
|
+
updateAgentMap: (key: string, value: AgentsMarketItem) => void;
|
|
15
|
+
useFetchAgent: (identifier: string) => SWRResponse<AgentsMarketItem>;
|
|
16
|
+
useFetchAgentList: () => SWRResponse<LobeChatAgentsMarketIndex>;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export const createMarketAction: StateCreator<
|
|
20
|
+
Store,
|
|
21
|
+
[['zustand/devtools', never]],
|
|
22
|
+
[],
|
|
23
|
+
StoreAction
|
|
24
|
+
> = (set, get) => ({
|
|
25
|
+
activateAgent: (identifier) => {
|
|
26
|
+
set({ currentIdentifier: identifier });
|
|
27
|
+
},
|
|
28
|
+
deactivateAgent: () => {
|
|
29
|
+
set({ currentIdentifier: undefined }, false, 'deactivateAgent');
|
|
30
|
+
},
|
|
31
|
+
updateAgentMap: (key, value) => {
|
|
32
|
+
const { agentMap } = get();
|
|
33
|
+
|
|
34
|
+
const nextAgentMap = produce(agentMap, (draft) => {
|
|
35
|
+
draft[key] = value;
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
if (isEqual(nextAgentMap, agentMap)) return;
|
|
39
|
+
|
|
40
|
+
set({ agentMap: nextAgentMap }, false, `setAgentMap/${key}`);
|
|
41
|
+
},
|
|
42
|
+
useFetchAgent: (identifier) =>
|
|
43
|
+
useSWR<AgentsMarketItem>(identifier, getAgentManifest, {
|
|
44
|
+
onError: () => {
|
|
45
|
+
get().deactivateAgent();
|
|
46
|
+
},
|
|
47
|
+
onSuccess: (data, key) => {
|
|
48
|
+
get().updateAgentMap(key, data);
|
|
49
|
+
},
|
|
50
|
+
}),
|
|
51
|
+
useFetchAgentList: () =>
|
|
52
|
+
useSWR<LobeChatAgentsMarketIndex>('fetchAgentList', getAgentList, {
|
|
53
|
+
onSuccess: (agentMarketIndex) => {
|
|
54
|
+
set({ agentList: agentMarketIndex.agents }, false, 'useFetchAgentList');
|
|
55
|
+
},
|
|
56
|
+
}),
|
|
57
|
+
});
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { AgentsMarketIndexItem, AgentsMarketItem } from '@/types/market';
|
|
2
|
+
|
|
3
|
+
export type MarketAgentMap = Record<string, AgentsMarketItem>;
|
|
4
|
+
|
|
5
|
+
export interface StoreState {
|
|
6
|
+
agentList: AgentsMarketIndexItem[];
|
|
7
|
+
agentMap: MarketAgentMap;
|
|
8
|
+
currentIdentifier: string;
|
|
9
|
+
searchKeywords: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export const initialState: StoreState = {
|
|
13
|
+
agentList: [],
|
|
14
|
+
agentMap: {},
|
|
15
|
+
currentIdentifier: '',
|
|
16
|
+
searchKeywords: '',
|
|
17
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { flatten } from 'lodash-es';
|
|
2
|
+
|
|
3
|
+
import { DEFAULT_AGENTS_MARKET_ITEM } from '@/const/market';
|
|
4
|
+
import { AgentsMarketItem } from '@/types/market';
|
|
5
|
+
import { findDuplicates } from '@/utils/findDuplicates';
|
|
6
|
+
|
|
7
|
+
import type { Store } from './store';
|
|
8
|
+
|
|
9
|
+
const getAgentList = (s: Store) => s.agentList;
|
|
10
|
+
const getAgentTagList = (s: Store) => {
|
|
11
|
+
const agentList = s.agentList;
|
|
12
|
+
const rawAgentTagList = flatten(agentList.map((item) => item.meta.tags)) as string[];
|
|
13
|
+
return findDuplicates(rawAgentTagList);
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const getAgentItemById = (d: string) => (s: Store) => s.agentMap[d];
|
|
17
|
+
|
|
18
|
+
const currentAgentItem = (s: Store) => getAgentItemById(s.currentIdentifier)(s);
|
|
19
|
+
|
|
20
|
+
const currentAgentItemSafe = (s: Store): AgentsMarketItem => {
|
|
21
|
+
const item = getAgentItemById(s.currentIdentifier)(s);
|
|
22
|
+
if (!item) return DEFAULT_AGENTS_MARKET_ITEM;
|
|
23
|
+
|
|
24
|
+
return item;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const showSideBar = (s: Store) => !!s.currentIdentifier;
|
|
28
|
+
|
|
29
|
+
export const agentMarketSelectors = {
|
|
30
|
+
currentAgentItem,
|
|
31
|
+
currentAgentItemSafe,
|
|
32
|
+
getAgentItemById,
|
|
33
|
+
getAgentList,
|
|
34
|
+
getAgentTagList,
|
|
35
|
+
showSideBar,
|
|
36
|
+
};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { PersistOptions, devtools, persist } from 'zustand/middleware';
|
|
2
|
+
import { shallow } from 'zustand/shallow';
|
|
3
|
+
import { createWithEqualityFn } from 'zustand/traditional';
|
|
4
|
+
import type { StateCreator } from 'zustand/vanilla';
|
|
5
|
+
|
|
6
|
+
import { createHyperStorage } from '@/store/middleware/createHyperStorage';
|
|
7
|
+
import { isDev } from '@/utils/env';
|
|
8
|
+
|
|
9
|
+
import { type StoreAction, createMarketAction } from './action';
|
|
10
|
+
import { type StoreState, initialState } from './initialState';
|
|
11
|
+
|
|
12
|
+
export type Store = StoreAction & StoreState;
|
|
13
|
+
|
|
14
|
+
const LOBE_AGENT_MARKET = 'LOBE_AGENT_MARKET';
|
|
15
|
+
|
|
16
|
+
const persistOptions: PersistOptions<Store> = {
|
|
17
|
+
name: LOBE_AGENT_MARKET,
|
|
18
|
+
|
|
19
|
+
skipHydration: true,
|
|
20
|
+
|
|
21
|
+
storage: createHyperStorage({
|
|
22
|
+
localStorage: {
|
|
23
|
+
dbName: 'LobeHub',
|
|
24
|
+
selectors: ['agentMap'],
|
|
25
|
+
},
|
|
26
|
+
url: {
|
|
27
|
+
mode: 'hash',
|
|
28
|
+
selectors: [
|
|
29
|
+
// map state key to storage key
|
|
30
|
+
{ currentIdentifier: 'agent' },
|
|
31
|
+
],
|
|
32
|
+
},
|
|
33
|
+
}),
|
|
34
|
+
|
|
35
|
+
version: 0,
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
const createStore: StateCreator<Store, [['zustand/devtools', never]]> = (...parameters) => ({
|
|
39
|
+
...initialState,
|
|
40
|
+
...createMarketAction(...parameters),
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
export const useMarketStore = createWithEqualityFn<Store>()(
|
|
44
|
+
persist(
|
|
45
|
+
devtools(createStore, {
|
|
46
|
+
name: LOBE_AGENT_MARKET + (isDev ? '_DEV' : ''),
|
|
47
|
+
}),
|
|
48
|
+
persistOptions,
|
|
49
|
+
),
|
|
50
|
+
shallow,
|
|
51
|
+
);
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { produce } from 'immer';
|
|
2
2
|
import { merge } from 'lodash-es';
|
|
3
3
|
import Router from 'next/router';
|
|
4
|
+
import { DeepPartial } from 'utility-types';
|
|
4
5
|
import { StateCreator } from 'zustand/vanilla';
|
|
5
6
|
|
|
6
7
|
import { INBOX_SESSION_ID } from '@/const/session';
|
|
7
8
|
import { SESSION_CHAT_URL } from '@/const/url';
|
|
8
9
|
import { useGlobalStore } from '@/store/global';
|
|
9
10
|
import { SessionStore } from '@/store/session';
|
|
10
|
-
import { LobeAgentSession, LobeSessions } from '@/types/session';
|
|
11
|
+
import { LobeAgentSession, LobeAgentSettings, LobeSessions } from '@/types/session';
|
|
11
12
|
import { setNamespace } from '@/utils/storeDebug';
|
|
12
13
|
import { uuid } from '@/utils/uuid';
|
|
13
14
|
|
|
@@ -24,7 +25,7 @@ export interface SessionAction {
|
|
|
24
25
|
* @param session - 会话信息
|
|
25
26
|
* @returns void
|
|
26
27
|
*/
|
|
27
|
-
createSession: () => Promise<string>;
|
|
28
|
+
createSession: (agent?: DeepPartial<LobeAgentSettings>) => Promise<string>;
|
|
28
29
|
/**
|
|
29
30
|
* 变更session
|
|
30
31
|
* @param payload - 聊天记录
|
|
@@ -79,7 +80,7 @@ export const createSessionSlice: StateCreator<
|
|
|
79
80
|
set({ sessions: {} }, false, t('clearSessions'));
|
|
80
81
|
},
|
|
81
82
|
|
|
82
|
-
createSession: async () => {
|
|
83
|
+
createSession: async (agent) => {
|
|
83
84
|
const { dispatchSession, switchSession } = get();
|
|
84
85
|
|
|
85
86
|
const timestamp = Date.now();
|
|
@@ -87,6 +88,7 @@ export const createSessionSlice: StateCreator<
|
|
|
87
88
|
// 合并 settings 里的 defaultAgent
|
|
88
89
|
const globalDefaultAgent = useGlobalStore.getState().settings.defaultAgent;
|
|
89
90
|
const newSession: LobeAgentSession = merge({}, initLobeSession, globalDefaultAgent, {
|
|
91
|
+
...agent,
|
|
90
92
|
createAt: timestamp,
|
|
91
93
|
id: uuid(),
|
|
92
94
|
updateAt: timestamp,
|
|
@@ -16,6 +16,7 @@ export interface SessionState {
|
|
|
16
16
|
isMobile?: boolean;
|
|
17
17
|
searchKeywords: string;
|
|
18
18
|
sessions: Record<string, LobeAgentSession>;
|
|
19
|
+
topicSearchKeywords: string;
|
|
19
20
|
}
|
|
20
21
|
|
|
21
22
|
export const initLobeSession: LobeAgentSession = {
|
|
@@ -44,4 +45,5 @@ export const initialSessionState: SessionState = {
|
|
|
44
45
|
isMobile: false,
|
|
45
46
|
searchKeywords: '',
|
|
46
47
|
sessions: {},
|
|
48
|
+
topicSearchKeywords: '',
|
|
47
49
|
};
|
|
@@ -109,7 +109,7 @@ describe('sessionsReducer', () => {
|
|
|
109
109
|
avatar: 'avatar-url',
|
|
110
110
|
backgroundColor: 'background-color',
|
|
111
111
|
description: 'description',
|
|
112
|
-
|
|
112
|
+
tags: ['tag1', 'tag2'],
|
|
113
113
|
title: 'title',
|
|
114
114
|
},
|
|
115
115
|
} as LobeAgentSession,
|
|
@@ -151,7 +151,7 @@ describe('sessionsReducer', () => {
|
|
|
151
151
|
avatar: 'avatar-url',
|
|
152
152
|
backgroundColor: 'background-color',
|
|
153
153
|
description: 'description',
|
|
154
|
-
|
|
154
|
+
tags: ['tag1', 'tag2'],
|
|
155
155
|
title: 'title',
|
|
156
156
|
},
|
|
157
157
|
} as LobeAgentSession,
|
|
@@ -185,7 +185,7 @@ describe('sessionsReducer', () => {
|
|
|
185
185
|
avatar: 'avatar-url',
|
|
186
186
|
backgroundColor: 'background-color',
|
|
187
187
|
description: 'description',
|
|
188
|
-
|
|
188
|
+
tags: ['tag1', 'tag2'],
|
|
189
189
|
title: 'title',
|
|
190
190
|
},
|
|
191
191
|
} as LobeAgentSession,
|
|
@@ -221,7 +221,7 @@ describe('sessionsReducer', () => {
|
|
|
221
221
|
avatar: 'avatar-url',
|
|
222
222
|
backgroundColor: 'background-color',
|
|
223
223
|
description: 'description',
|
|
224
|
-
|
|
224
|
+
tags: ['tag1', 'tag2'],
|
|
225
225
|
title: 'title',
|
|
226
226
|
},
|
|
227
227
|
} as LobeAgentSession,
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { MetaData } from '@/types/meta';
|
|
2
|
+
import { LobeAgentSettings } from '@/types/session';
|
|
3
|
+
|
|
4
|
+
export interface AgentsMarketIndexItem {
|
|
5
|
+
author: string;
|
|
6
|
+
createAt: string;
|
|
7
|
+
homepage: string;
|
|
8
|
+
identifier: string;
|
|
9
|
+
manifest: string;
|
|
10
|
+
meta: MetaData;
|
|
11
|
+
schemaVersion: 1;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export type AgentsMarketItem = AgentsMarketIndexItem & LobeAgentSettings;
|
|
15
|
+
|
|
16
|
+
export interface LobeChatAgentsMarketIndex {
|
|
17
|
+
agents: AgentsMarketIndexItem[];
|
|
18
|
+
schemaVersion: 1;
|
|
19
|
+
}
|