@lobehub/chat 1.0.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/.changelogrc.js +1 -0
- package/.commitlintrc.js +1 -0
- package/.editorconfig +16 -0
- package/.eslintignore +32 -0
- package/.eslintrc.js +6 -0
- package/.github/ISSUE_TEMPLATE/1_bug_report.yml +45 -0
- package/.github/ISSUE_TEMPLATE/2_feature_request.yml +21 -0
- package/.github/ISSUE_TEMPLATE/3_question.yml +15 -0
- package/.github/ISSUE_TEMPLATE/4_other.md +7 -0
- package/.github/PULL_REQUEST_TEMPLATE.md +17 -0
- package/.github/dependabot.yml +17 -0
- package/.github/workflows/auto-merge.yml +32 -0
- package/.github/workflows/contributor-help.yml +29 -0
- package/.github/workflows/issue-check-inactive.yml +22 -0
- package/.github/workflows/issue-close-require.yml +46 -0
- package/.github/workflows/issue-remove-inactive.yml +25 -0
- package/.github/workflows/release.yml +34 -0
- package/.github/workflows/test.yml +30 -0
- package/.gitpod.yml +3 -0
- package/.husky/commit-msg +4 -0
- package/.husky/pre-commit +5 -0
- package/.i18nrc.js +13 -0
- package/.prettierignore +63 -0
- package/.prettierrc.js +1 -0
- package/.releaserc.js +1 -0
- package/.remarkrc.js +1 -0
- package/.stylelintrc.js +8 -0
- package/CHANGELOG.md +80 -0
- package/README.md +147 -0
- package/locales/en_US/common.json +40 -0
- package/locales/en_US/setting.json +97 -0
- package/locales/zh_CN/common.json +40 -0
- package/locales/zh_CN/setting.json +98 -0
- package/next.config.mjs +32 -0
- package/package.json +138 -0
- package/public/next.svg +1 -0
- package/public/vercel.svg +1 -0
- package/scripts/genDefaultLocale.mjs +12 -0
- package/scripts/toc.mjs +40 -0
- package/src/const/fetch.ts +1 -0
- package/src/const/modelTokens.ts +8 -0
- package/src/features/FolderPanel/index.tsx +55 -0
- package/src/helpers/prompt.test.ts +36 -0
- package/src/helpers/prompt.ts +36 -0
- package/src/helpers/url.ts +17 -0
- package/src/layout/index.tsx +42 -0
- package/src/layout/style.ts +18 -0
- package/src/locales/create.ts +48 -0
- package/src/locales/default/common.ts +41 -0
- package/src/locales/default/setting.ts +97 -0
- package/src/locales/index.ts +5 -0
- package/src/locales/resources/en_US.ts +9 -0
- package/src/locales/resources/index.ts +7 -0
- package/src/locales/resources/zh_CN.ts +9 -0
- package/src/migrations/FromV0ToV1.ts +12 -0
- package/src/migrations/index.ts +13 -0
- package/src/pages/Sidebar.tsx +36 -0
- package/src/pages/_app.page.tsx +13 -0
- package/src/pages/_document.page.tsx +70 -0
- package/src/pages/api/LangChainStream.ts +95 -0
- package/src/pages/api/chain.api.ts +17 -0
- package/src/pages/api/openai.api.ts +31 -0
- package/src/pages/chat/SessionList/Header.tsx +56 -0
- package/src/pages/chat/SessionList/List/SessionItem.tsx +90 -0
- package/src/pages/chat/SessionList/List/index.tsx +31 -0
- package/src/pages/chat/SessionList/List/style.ts +77 -0
- package/src/pages/chat/SessionList/index.tsx +18 -0
- package/src/pages/chat/[id]/Config/ConfigCell.tsx +68 -0
- package/src/pages/chat/[id]/Config/ReadMode.tsx +63 -0
- package/src/pages/chat/[id]/Config/index.tsx +79 -0
- package/src/pages/chat/[id]/Conversation/ChatList.tsx +36 -0
- package/src/pages/chat/[id]/Conversation/Input.tsx +61 -0
- package/src/pages/chat/[id]/Conversation/index.tsx +32 -0
- package/src/pages/chat/[id]/Header.tsx +86 -0
- package/src/pages/chat/[id]/edit/AgentConfig.tsx +95 -0
- package/src/pages/chat/[id]/edit/AgentMeta.tsx +117 -0
- package/src/pages/chat/[id]/edit/FormItem.tsx +26 -0
- package/src/pages/chat/[id]/edit/Prompt.tsx +68 -0
- package/src/pages/chat/[id]/edit/index.page.tsx +62 -0
- package/src/pages/chat/[id]/edit/style.ts +42 -0
- package/src/pages/chat/[id]/index.page.tsx +40 -0
- package/src/pages/chat/index.page.tsx +1 -0
- package/src/pages/chat/layout.tsx +51 -0
- package/src/pages/index.page.tsx +1 -0
- package/src/pages/setting/Header.tsx +27 -0
- package/src/pages/setting/SettingForm.tsx +42 -0
- package/src/pages/setting/index.page.tsx +41 -0
- package/src/prompts/agent.ts +65 -0
- package/src/services/chatModel.ts +34 -0
- package/src/services/langChain.ts +18 -0
- package/src/services/url.ts +8 -0
- package/src/store/middleware/createHashStorage.ts +49 -0
- package/src/store/session/index.ts +33 -0
- package/src/store/session/initialState.ts +11 -0
- package/src/store/session/selectors.ts +3 -0
- package/src/store/session/slices/agentConfig/action.ts +226 -0
- package/src/store/session/slices/agentConfig/index.ts +3 -0
- package/src/store/session/slices/agentConfig/initialState.ts +34 -0
- package/src/store/session/slices/agentConfig/selectors.ts +54 -0
- package/src/store/session/slices/chat/action.ts +210 -0
- package/src/store/session/slices/chat/index.ts +3 -0
- package/src/store/session/slices/chat/initialState.ts +12 -0
- package/src/store/session/slices/chat/messageReducer.test.ts +70 -0
- package/src/store/session/slices/chat/messageReducer.ts +84 -0
- package/src/store/session/slices/chat/selectors.ts +83 -0
- package/src/store/session/slices/session/action.ts +118 -0
- package/src/store/session/slices/session/index.ts +3 -0
- package/src/store/session/slices/session/initialState.ts +31 -0
- package/src/store/session/slices/session/reducers/session.test.ts +456 -0
- package/src/store/session/slices/session/reducers/session.ts +113 -0
- package/src/store/session/slices/session/selectors/chat.ts +4 -0
- package/src/store/session/slices/session/selectors/index.ts +20 -0
- package/src/store/session/slices/session/selectors/list.ts +65 -0
- package/src/store/session/store.ts +17 -0
- package/src/store/settings/action.ts +31 -0
- package/src/store/settings/index.ts +23 -0
- package/src/store/settings/initialState.ts +25 -0
- package/src/store/settings/selectors.ts +9 -0
- package/src/store/settings/store.ts +13 -0
- package/src/styles/antdOverride.ts +29 -0
- package/src/styles/global.ts +23 -0
- package/src/styles/index.ts +6 -0
- package/src/types/chatMessage.ts +46 -0
- package/src/types/exportConfig.ts +23 -0
- package/src/types/global.d.ts +14 -0
- package/src/types/i18next.d.ts +8 -0
- package/src/types/langchain.ts +34 -0
- package/src/types/llm.ts +49 -0
- package/src/types/locale.ts +7 -0
- package/src/types/meta.ts +26 -0
- package/src/types/openai.ts +62 -0
- package/src/types/session.ts +59 -0
- package/src/utils/VersionController.test.ts +90 -0
- package/src/utils/VersionController.ts +64 -0
- package/src/utils/compass.ts +94 -0
- package/src/utils/fetch.ts +132 -0
- package/src/utils/filter.test.ts +120 -0
- package/src/utils/filter.ts +29 -0
- package/src/utils/uploadFIle.ts +8 -0
- package/src/utils/uuid.ts +9 -0
- package/tsconfig.json +26 -0
- package/vitest.config.ts +11 -0
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { ActionIcon, Avatar, ChatHeader } from '@lobehub/ui';
|
|
2
|
+
import { createStyles } from 'antd-style';
|
|
3
|
+
import { ArchiveIcon, LucideEdit, MoreVerticalIcon, Share2Icon } from 'lucide-react';
|
|
4
|
+
import Router from 'next/router';
|
|
5
|
+
import { memo } from 'react';
|
|
6
|
+
import { useTranslation } from 'react-i18next';
|
|
7
|
+
import { Flexbox } from 'react-layout-kit';
|
|
8
|
+
import { shallow } from 'zustand/shallow';
|
|
9
|
+
|
|
10
|
+
import { sessionSelectors, useSessionStore } from '@/store/session';
|
|
11
|
+
|
|
12
|
+
const useStyles = createStyles(({ css, token }) => ({
|
|
13
|
+
desc: css`
|
|
14
|
+
font-size: 12px;
|
|
15
|
+
color: ${token.colorTextTertiary};
|
|
16
|
+
`,
|
|
17
|
+
title: css`
|
|
18
|
+
font-weight: bold;
|
|
19
|
+
color: ${token.colorText};
|
|
20
|
+
`,
|
|
21
|
+
}));
|
|
22
|
+
const Header = memo(() => {
|
|
23
|
+
const { t } = useTranslation('common');
|
|
24
|
+
const [meta, id] = useSessionStore((s) => {
|
|
25
|
+
const chat = sessionSelectors.currentSession(s);
|
|
26
|
+
return [chat?.meta, s.activeId];
|
|
27
|
+
}, shallow);
|
|
28
|
+
|
|
29
|
+
const [
|
|
30
|
+
// genShareUrl,
|
|
31
|
+
|
|
32
|
+
toggleConfig,
|
|
33
|
+
] = useSessionStore(
|
|
34
|
+
(s) => [
|
|
35
|
+
// s.genShareUrl,
|
|
36
|
+
s.toggleConfig,
|
|
37
|
+
],
|
|
38
|
+
shallow,
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
const { styles } = useStyles();
|
|
42
|
+
return (
|
|
43
|
+
<ChatHeader
|
|
44
|
+
left={
|
|
45
|
+
<>
|
|
46
|
+
<Avatar avatar={meta && sessionSelectors.getAgentAvatar(meta)} size={40} title={'123'} />
|
|
47
|
+
<Flexbox>
|
|
48
|
+
<Flexbox className={styles.title}>{meta?.title || t('defaultAgent')}</Flexbox>
|
|
49
|
+
<Flexbox className={styles.desc}>{meta?.description || t('noDescription')}</Flexbox>
|
|
50
|
+
</Flexbox>
|
|
51
|
+
</>
|
|
52
|
+
}
|
|
53
|
+
right={
|
|
54
|
+
id && (
|
|
55
|
+
<>
|
|
56
|
+
<ActionIcon
|
|
57
|
+
icon={Share2Icon}
|
|
58
|
+
onClick={() => {
|
|
59
|
+
// genShareUrl();
|
|
60
|
+
}}
|
|
61
|
+
size={{ fontSize: 24 }}
|
|
62
|
+
title={t('share')}
|
|
63
|
+
/>
|
|
64
|
+
<ActionIcon icon={ArchiveIcon} size={{ fontSize: 24 }} title={t('archive')} />
|
|
65
|
+
<ActionIcon
|
|
66
|
+
icon={LucideEdit}
|
|
67
|
+
onClick={() => {
|
|
68
|
+
Router.push(`/chat/${id}/edit`);
|
|
69
|
+
}}
|
|
70
|
+
size={{ blockSize: 32, fontSize: 20 }}
|
|
71
|
+
title={t('edit')}
|
|
72
|
+
/>
|
|
73
|
+
<ActionIcon
|
|
74
|
+
icon={MoreVerticalIcon}
|
|
75
|
+
onClick={() => toggleConfig()}
|
|
76
|
+
size={{ fontSize: 24 }}
|
|
77
|
+
title={t('sessionSetting')}
|
|
78
|
+
/>
|
|
79
|
+
</>
|
|
80
|
+
)
|
|
81
|
+
}
|
|
82
|
+
/>
|
|
83
|
+
);
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
export default Header;
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { Collapse, InputNumber, Segmented, Slider } from 'antd';
|
|
2
|
+
import isEqual from 'fast-deep-equal';
|
|
3
|
+
import { useTranslation } from 'react-i18next';
|
|
4
|
+
import { Flexbox } from 'react-layout-kit';
|
|
5
|
+
import { shallow } from 'zustand/shallow';
|
|
6
|
+
|
|
7
|
+
import { agentSelectors, useSessionStore } from '@/store/session';
|
|
8
|
+
import { LanguageModel } from '@/types/llm';
|
|
9
|
+
|
|
10
|
+
import { FormItem } from './FormItem';
|
|
11
|
+
import Prompt from './Prompt';
|
|
12
|
+
import { useStyles } from './style';
|
|
13
|
+
|
|
14
|
+
const AgentConfig = () => {
|
|
15
|
+
const { t } = useTranslation('common');
|
|
16
|
+
|
|
17
|
+
const { styles, theme } = useStyles();
|
|
18
|
+
|
|
19
|
+
const config = useSessionStore(agentSelectors.currentAgentConfigSafe, isEqual);
|
|
20
|
+
|
|
21
|
+
const [updateAgentConfig] = useSessionStore((s) => [s.updateAgentConfig], shallow);
|
|
22
|
+
|
|
23
|
+
return (
|
|
24
|
+
<>
|
|
25
|
+
<Flexbox
|
|
26
|
+
align={'center'}
|
|
27
|
+
distribution={'space-between'}
|
|
28
|
+
horizontal
|
|
29
|
+
paddingBlock={12}
|
|
30
|
+
style={{
|
|
31
|
+
borderBottom: `1px solid ${theme.colorBorder}`,
|
|
32
|
+
}}
|
|
33
|
+
>
|
|
34
|
+
<Flexbox className={styles.profile}> {t('modelConfig')}</Flexbox>
|
|
35
|
+
</Flexbox>
|
|
36
|
+
<Flexbox gap={24}>
|
|
37
|
+
<FormItem label={t('agentModel')}>
|
|
38
|
+
<Segmented
|
|
39
|
+
block
|
|
40
|
+
onChange={(value) => {
|
|
41
|
+
updateAgentConfig({ model: value as LanguageModel });
|
|
42
|
+
}}
|
|
43
|
+
options={Object.values(LanguageModel).map((value) => ({
|
|
44
|
+
label: t(value),
|
|
45
|
+
value,
|
|
46
|
+
}))}
|
|
47
|
+
size={'large'}
|
|
48
|
+
value={config.model}
|
|
49
|
+
/>
|
|
50
|
+
</FormItem>
|
|
51
|
+
<Prompt />
|
|
52
|
+
<Collapse
|
|
53
|
+
activeKey={['advanceSettings']}
|
|
54
|
+
bordered={false}
|
|
55
|
+
className={styles.title}
|
|
56
|
+
expandIconPosition={'end'}
|
|
57
|
+
items={[
|
|
58
|
+
{
|
|
59
|
+
children: (
|
|
60
|
+
<Flexbox paddingBlock={16}>
|
|
61
|
+
<FormItem label={t('modelTemperature')}>
|
|
62
|
+
<Flexbox gap={16} horizontal>
|
|
63
|
+
<Slider
|
|
64
|
+
max={1}
|
|
65
|
+
min={0}
|
|
66
|
+
onChange={(value) => {
|
|
67
|
+
updateAgentConfig({ params: { temperature: value } });
|
|
68
|
+
}}
|
|
69
|
+
step={0.1}
|
|
70
|
+
style={{ flex: 1 }}
|
|
71
|
+
value={Number(config.params.temperature)}
|
|
72
|
+
/>
|
|
73
|
+
<InputNumber
|
|
74
|
+
max={1}
|
|
75
|
+
min={0}
|
|
76
|
+
onChange={(value) => {
|
|
77
|
+
if (value) updateAgentConfig({ params: { temperature: value } });
|
|
78
|
+
}}
|
|
79
|
+
value={config.params.temperature}
|
|
80
|
+
/>
|
|
81
|
+
</Flexbox>
|
|
82
|
+
</FormItem>
|
|
83
|
+
</Flexbox>
|
|
84
|
+
),
|
|
85
|
+
key: 'advanceSettings',
|
|
86
|
+
label: t('advanceSettings'),
|
|
87
|
+
},
|
|
88
|
+
]}
|
|
89
|
+
/>
|
|
90
|
+
</Flexbox>
|
|
91
|
+
</>
|
|
92
|
+
);
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
export default AgentConfig;
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { ActionIcon, Avatar, Input, Tooltip } from '@lobehub/ui';
|
|
2
|
+
import { Button, Collapse } from 'antd';
|
|
3
|
+
import isEqual from 'fast-deep-equal';
|
|
4
|
+
import { LucideSparkles } from 'lucide-react';
|
|
5
|
+
import { useTranslation } from 'react-i18next';
|
|
6
|
+
import { Flexbox } from 'react-layout-kit';
|
|
7
|
+
import { shallow } from 'zustand/shallow';
|
|
8
|
+
|
|
9
|
+
import { agentSelectors, useSessionStore } from '@/store/session';
|
|
10
|
+
|
|
11
|
+
import { FormItem } from './FormItem';
|
|
12
|
+
import { useStyles } from './style';
|
|
13
|
+
|
|
14
|
+
const AgentMeta = () => {
|
|
15
|
+
const { t } = useTranslation('common');
|
|
16
|
+
|
|
17
|
+
const { styles, theme } = useStyles();
|
|
18
|
+
|
|
19
|
+
const metaData = useSessionStore(agentSelectors.currentAgentMeta, isEqual);
|
|
20
|
+
|
|
21
|
+
const [
|
|
22
|
+
autocompleteMeta,
|
|
23
|
+
autocompleteSessionAgentMeta,
|
|
24
|
+
loading,
|
|
25
|
+
updateAgentMeta,
|
|
26
|
+
id,
|
|
27
|
+
hasSystemRole,
|
|
28
|
+
] = useSessionStore(
|
|
29
|
+
(s) => [
|
|
30
|
+
s.autocompleteMeta,
|
|
31
|
+
s.autocompleteSessionAgentMeta,
|
|
32
|
+
s.autocompleteLoading,
|
|
33
|
+
s.updateAgentMeta,
|
|
34
|
+
s.activeId,
|
|
35
|
+
agentSelectors.hasSystemRole(s),
|
|
36
|
+
],
|
|
37
|
+
shallow,
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
const basic = [
|
|
41
|
+
{ key: 'title', label: t('agentName'), placeholder: t('agentNamePlaceholder') },
|
|
42
|
+
{
|
|
43
|
+
key: 'description',
|
|
44
|
+
label: t('agentDescription'),
|
|
45
|
+
placeholder: t('agentDescriptionPlaceholder'),
|
|
46
|
+
},
|
|
47
|
+
// { key: 'tag', label: t('agentTag'), placeholder: t('agentTagPlaceholder') },
|
|
48
|
+
];
|
|
49
|
+
|
|
50
|
+
return (
|
|
51
|
+
<Collapse
|
|
52
|
+
defaultActiveKey={hasSystemRole ? ['meta'] : []}
|
|
53
|
+
items={[
|
|
54
|
+
{
|
|
55
|
+
children: (
|
|
56
|
+
<Flexbox gap={80} horizontal style={{ marginTop: 16 }}>
|
|
57
|
+
<Flexbox flex={1} gap={24}>
|
|
58
|
+
{basic.map((item) => (
|
|
59
|
+
<FormItem key={item.key} label={item.label}>
|
|
60
|
+
<Input
|
|
61
|
+
onChange={(e) => {
|
|
62
|
+
updateAgentMeta({ [item.key]: e.target.value });
|
|
63
|
+
}}
|
|
64
|
+
placeholder={item.placeholder}
|
|
65
|
+
suffix={
|
|
66
|
+
<ActionIcon
|
|
67
|
+
icon={LucideSparkles}
|
|
68
|
+
loading={loading[item.key as keyof typeof loading]}
|
|
69
|
+
onClick={() => {
|
|
70
|
+
autocompleteMeta(item.key as keyof typeof metaData);
|
|
71
|
+
}}
|
|
72
|
+
size={'small'}
|
|
73
|
+
style={{
|
|
74
|
+
color: theme.purple,
|
|
75
|
+
}}
|
|
76
|
+
title={t('autoGenerate')}
|
|
77
|
+
/>
|
|
78
|
+
}
|
|
79
|
+
type={'block'}
|
|
80
|
+
value={metaData[item.key as keyof typeof metaData]}
|
|
81
|
+
/>
|
|
82
|
+
</FormItem>
|
|
83
|
+
))}
|
|
84
|
+
</Flexbox>
|
|
85
|
+
<FormItem label={t('agentAvatar')}>
|
|
86
|
+
<Avatar avatar={metaData.avatar} size={200} />
|
|
87
|
+
</FormItem>
|
|
88
|
+
</Flexbox>
|
|
89
|
+
),
|
|
90
|
+
className: styles.collapseHeader,
|
|
91
|
+
extra: (
|
|
92
|
+
<Tooltip title={t('autoGenerateTooltip')}>
|
|
93
|
+
<Button
|
|
94
|
+
disabled={!hasSystemRole}
|
|
95
|
+
loading={Object.values(loading).some((i) => !!i)}
|
|
96
|
+
onClick={(e) => {
|
|
97
|
+
e.stopPropagation();
|
|
98
|
+
console.log(id);
|
|
99
|
+
if (!id) return;
|
|
100
|
+
|
|
101
|
+
autocompleteSessionAgentMeta(id, true);
|
|
102
|
+
}}
|
|
103
|
+
size={'large'}
|
|
104
|
+
>
|
|
105
|
+
{t('autoGenerate')}
|
|
106
|
+
</Button>
|
|
107
|
+
</Tooltip>
|
|
108
|
+
),
|
|
109
|
+
key: 'meta',
|
|
110
|
+
label: <Flexbox className={styles.profile}>{t('profile')}</Flexbox>,
|
|
111
|
+
},
|
|
112
|
+
]}
|
|
113
|
+
/>
|
|
114
|
+
);
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
export default AgentMeta;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { createStyles } from 'antd-style';
|
|
2
|
+
import { ReactNode, memo } from 'react';
|
|
3
|
+
import { Flexbox } from 'react-layout-kit';
|
|
4
|
+
|
|
5
|
+
const useStyles = createStyles(({ css, token }) => ({
|
|
6
|
+
header: css``,
|
|
7
|
+
title: css`
|
|
8
|
+
color: ${token.colorTextSecondary};
|
|
9
|
+
`,
|
|
10
|
+
}));
|
|
11
|
+
|
|
12
|
+
interface FormItemProps {
|
|
13
|
+
children: ReactNode;
|
|
14
|
+
label: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export const FormItem = memo<FormItemProps>(({ label, children }) => {
|
|
18
|
+
const { styles } = useStyles();
|
|
19
|
+
|
|
20
|
+
return (
|
|
21
|
+
<Flexbox className={styles.header} gap={12}>
|
|
22
|
+
<Flexbox className={styles.title}>{label}</Flexbox>
|
|
23
|
+
<Flexbox>{children}</Flexbox>
|
|
24
|
+
</Flexbox>
|
|
25
|
+
);
|
|
26
|
+
});
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { EditableMessage } from '@lobehub/ui';
|
|
2
|
+
import { Button } from 'antd';
|
|
3
|
+
import { createStyles } from 'antd-style';
|
|
4
|
+
import { useState } from 'react';
|
|
5
|
+
import { useTranslation } from 'react-i18next';
|
|
6
|
+
import { Flexbox } from 'react-layout-kit';
|
|
7
|
+
import { shallow } from 'zustand/shallow';
|
|
8
|
+
|
|
9
|
+
import { agentSelectors, useSessionStore } from '@/store/session';
|
|
10
|
+
|
|
11
|
+
import { FormItem } from './FormItem';
|
|
12
|
+
|
|
13
|
+
export const useStyles = createStyles(({ css, token }) => ({
|
|
14
|
+
input: css`
|
|
15
|
+
padding: 12px;
|
|
16
|
+
background: ${token.colorFillTertiary};
|
|
17
|
+
border: 1px solid ${token.colorPrimaryBorder};
|
|
18
|
+
border-radius: 8px;
|
|
19
|
+
`,
|
|
20
|
+
markdown: css`
|
|
21
|
+
padding: 12px;
|
|
22
|
+
background: ${token.colorFillTertiary};
|
|
23
|
+
`,
|
|
24
|
+
}));
|
|
25
|
+
|
|
26
|
+
const Prompt = () => {
|
|
27
|
+
const { t } = useTranslation('common');
|
|
28
|
+
|
|
29
|
+
const [editing, setEditing] = useState(false);
|
|
30
|
+
const { styles } = useStyles();
|
|
31
|
+
|
|
32
|
+
const systemRole = useSessionStore((s) => {
|
|
33
|
+
const config = agentSelectors.currentAgentConfigSafe(s);
|
|
34
|
+
return config.systemRole;
|
|
35
|
+
}, shallow);
|
|
36
|
+
|
|
37
|
+
const [updateAgentConfig] = useSessionStore((s) => [s.updateAgentConfig], shallow);
|
|
38
|
+
|
|
39
|
+
return (
|
|
40
|
+
<FormItem label={t('agentPrompt')}>
|
|
41
|
+
<Flexbox gap={16}>
|
|
42
|
+
<EditableMessage
|
|
43
|
+
classNames={styles}
|
|
44
|
+
editing={editing}
|
|
45
|
+
onChange={(e) => {
|
|
46
|
+
updateAgentConfig({ systemRole: e });
|
|
47
|
+
}}
|
|
48
|
+
onEditingChange={setEditing}
|
|
49
|
+
value={systemRole}
|
|
50
|
+
/>
|
|
51
|
+
{!editing && (
|
|
52
|
+
<Flexbox direction={'horizontal-reverse'}>
|
|
53
|
+
<Button
|
|
54
|
+
onClick={() => {
|
|
55
|
+
setEditing(true);
|
|
56
|
+
}}
|
|
57
|
+
type={'primary'}
|
|
58
|
+
>
|
|
59
|
+
{t('edit')}
|
|
60
|
+
</Button>
|
|
61
|
+
</Flexbox>
|
|
62
|
+
)}
|
|
63
|
+
</Flexbox>
|
|
64
|
+
</FormItem>
|
|
65
|
+
);
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
export default Prompt;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { ChatHeader } from '@lobehub/ui';
|
|
2
|
+
import { Button } from 'antd';
|
|
3
|
+
import { createStyles } from 'antd-style';
|
|
4
|
+
import Router from 'next/router';
|
|
5
|
+
import { memo } from 'react';
|
|
6
|
+
import { useTranslation } from 'react-i18next';
|
|
7
|
+
import { Flexbox } from 'react-layout-kit';
|
|
8
|
+
|
|
9
|
+
import ChatLayout from '../../layout';
|
|
10
|
+
import AgentConfig from './AgentConfig';
|
|
11
|
+
import AgentMeta from './AgentMeta';
|
|
12
|
+
|
|
13
|
+
const useStyles = createStyles(({ css, token }) => ({
|
|
14
|
+
footer: css`
|
|
15
|
+
position: sticky;
|
|
16
|
+
bottom: 0;
|
|
17
|
+
border-top: 1px solid ${token.colorBorder};
|
|
18
|
+
`,
|
|
19
|
+
form: css`
|
|
20
|
+
overflow-y: auto;
|
|
21
|
+
`,
|
|
22
|
+
header: css`
|
|
23
|
+
background: ${token.colorBgContainer};
|
|
24
|
+
border-bottom: 1px solid ${token.colorSplit};
|
|
25
|
+
`,
|
|
26
|
+
title: css`
|
|
27
|
+
font-size: 16px;
|
|
28
|
+
font-weight: 500;
|
|
29
|
+
`,
|
|
30
|
+
}));
|
|
31
|
+
|
|
32
|
+
const EditPage = memo(() => {
|
|
33
|
+
const { t } = useTranslation('common');
|
|
34
|
+
|
|
35
|
+
const { styles } = useStyles();
|
|
36
|
+
|
|
37
|
+
return (
|
|
38
|
+
<ChatLayout>
|
|
39
|
+
<Flexbox height={'100vh'} style={{ position: 'relative' }} width={'100%'}>
|
|
40
|
+
{/*header*/}
|
|
41
|
+
<ChatHeader
|
|
42
|
+
left={<div className={styles.title}>{t('editAgentProfile')}</div>}
|
|
43
|
+
onBackClick={() => Router.back()}
|
|
44
|
+
right={
|
|
45
|
+
<>
|
|
46
|
+
<Button>{t('share')}</Button>
|
|
47
|
+
<Button type={'primary'}>{t('export')}</Button>
|
|
48
|
+
</>
|
|
49
|
+
}
|
|
50
|
+
showBackButton
|
|
51
|
+
/>
|
|
52
|
+
{/*form*/}
|
|
53
|
+
<Flexbox className={styles.form} flex={1} gap={10} padding={24}>
|
|
54
|
+
<AgentMeta />
|
|
55
|
+
<AgentConfig />
|
|
56
|
+
</Flexbox>
|
|
57
|
+
</Flexbox>
|
|
58
|
+
</ChatLayout>
|
|
59
|
+
);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
export default EditPage;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { createStyles } from 'antd-style';
|
|
2
|
+
|
|
3
|
+
export const useStyles = createStyles(({ css, token }) => ({
|
|
4
|
+
collapseHeader: css`
|
|
5
|
+
.ant-collapse-header {
|
|
6
|
+
align-items: center !important;
|
|
7
|
+
}
|
|
8
|
+
`,
|
|
9
|
+
footer: css`
|
|
10
|
+
position: sticky;
|
|
11
|
+
bottom: 0;
|
|
12
|
+
border-top: 1px solid ${token.colorBorder};
|
|
13
|
+
`,
|
|
14
|
+
form: css`
|
|
15
|
+
overflow-y: auto;
|
|
16
|
+
`,
|
|
17
|
+
header: css`
|
|
18
|
+
background: ${token.colorBgContainer};
|
|
19
|
+
border-bottom: 1px solid ${token.colorSplit};
|
|
20
|
+
`,
|
|
21
|
+
profile: css`
|
|
22
|
+
font-size: 20px;
|
|
23
|
+
font-weight: bold;
|
|
24
|
+
color: ${token.colorText};
|
|
25
|
+
`,
|
|
26
|
+
prompt: css`
|
|
27
|
+
padding: 12px;
|
|
28
|
+
background: ${token.colorFillTertiary};
|
|
29
|
+
`,
|
|
30
|
+
title: css`
|
|
31
|
+
font-size: 16px;
|
|
32
|
+
font-weight: 500;
|
|
33
|
+
|
|
34
|
+
.ant-collapse-header {
|
|
35
|
+
padding: 0 !important;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.ant-collapse-content-box {
|
|
39
|
+
padding: 0 !important;
|
|
40
|
+
}
|
|
41
|
+
`,
|
|
42
|
+
}));
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import isEqual from 'fast-deep-equal';
|
|
2
|
+
import Head from 'next/head';
|
|
3
|
+
import { memo } from 'react';
|
|
4
|
+
import { Flexbox } from 'react-layout-kit';
|
|
5
|
+
|
|
6
|
+
import { sessionSelectors, useSessionStore } from '@/store/session';
|
|
7
|
+
|
|
8
|
+
import Layout from '../layout';
|
|
9
|
+
import Config from './Config';
|
|
10
|
+
import Conversation from './Conversation';
|
|
11
|
+
import Header from './Header';
|
|
12
|
+
|
|
13
|
+
const Chat = memo(() => {
|
|
14
|
+
const [title] = useSessionStore((s) => {
|
|
15
|
+
const context = sessionSelectors.currentSession(s);
|
|
16
|
+
return [context?.meta.title];
|
|
17
|
+
}, isEqual);
|
|
18
|
+
|
|
19
|
+
const pageTitle = title ? `${title} - LobeChat` : 'LobeChat';
|
|
20
|
+
|
|
21
|
+
return (
|
|
22
|
+
<Layout>
|
|
23
|
+
<Head>
|
|
24
|
+
<title>{pageTitle}</title>
|
|
25
|
+
</Head>
|
|
26
|
+
|
|
27
|
+
<Flexbox flex={1}>
|
|
28
|
+
<Header />
|
|
29
|
+
<Flexbox
|
|
30
|
+
id={'lobe-conversion-container'}
|
|
31
|
+
style={{ height: 'calc(100vh - 64px)', position: 'relative' }}
|
|
32
|
+
>
|
|
33
|
+
<Conversation />
|
|
34
|
+
<Config />
|
|
35
|
+
</Flexbox>
|
|
36
|
+
</Flexbox>
|
|
37
|
+
</Layout>
|
|
38
|
+
);
|
|
39
|
+
});
|
|
40
|
+
export default Chat;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from './[id]/index.page';
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { useRouter } from 'next/router';
|
|
2
|
+
import { PropsWithChildren, memo, useEffect } from 'react';
|
|
3
|
+
import { Flexbox } from 'react-layout-kit';
|
|
4
|
+
import { shallow } from 'zustand/shallow';
|
|
5
|
+
|
|
6
|
+
import { createI18nNext } from '@/locales/create';
|
|
7
|
+
import { useSessionStore } from '@/store/session';
|
|
8
|
+
import { useSettings } from '@/store/settings';
|
|
9
|
+
|
|
10
|
+
import Sidebar from '../Sidebar';
|
|
11
|
+
import { Sessions } from './SessionList';
|
|
12
|
+
|
|
13
|
+
const initI18n = createI18nNext();
|
|
14
|
+
|
|
15
|
+
const ChatLayout = memo<PropsWithChildren>(({ children }) => {
|
|
16
|
+
useEffect(() => {
|
|
17
|
+
initI18n.finally();
|
|
18
|
+
}, []);
|
|
19
|
+
|
|
20
|
+
const [activeSession] = useSessionStore((s) => {
|
|
21
|
+
return [s.activeSession];
|
|
22
|
+
}, shallow);
|
|
23
|
+
|
|
24
|
+
const router = useRouter();
|
|
25
|
+
const { id } = router.query;
|
|
26
|
+
|
|
27
|
+
useEffect(() => {
|
|
28
|
+
const hasRehydrated = useSessionStore.persist.hasHydrated();
|
|
29
|
+
// 只有当水合完毕后,才能正常去激活会话
|
|
30
|
+
if (typeof id === 'string' && hasRehydrated) {
|
|
31
|
+
activeSession(id);
|
|
32
|
+
}
|
|
33
|
+
}, [id]);
|
|
34
|
+
|
|
35
|
+
useEffect(() => {
|
|
36
|
+
const hasRehydrated = useSettings.persist.hasHydrated();
|
|
37
|
+
if (hasRehydrated) {
|
|
38
|
+
useSettings.setState({ sidebarKey: 'chat' });
|
|
39
|
+
}
|
|
40
|
+
}, []);
|
|
41
|
+
|
|
42
|
+
return (
|
|
43
|
+
<Flexbox horizontal width={'100%'}>
|
|
44
|
+
<Sidebar />
|
|
45
|
+
<Sessions />
|
|
46
|
+
{children}
|
|
47
|
+
</Flexbox>
|
|
48
|
+
);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
export default ChatLayout;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from './chat/index.page';
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { ChatHeader } from '@lobehub/ui';
|
|
2
|
+
import { createStyles } from 'antd-style';
|
|
3
|
+
import { useTranslation } from 'react-i18next';
|
|
4
|
+
import Router from 'next/router';
|
|
5
|
+
import { memo } from 'react';
|
|
6
|
+
|
|
7
|
+
const useStyles = createStyles(({ css, token }) => ({
|
|
8
|
+
title: css`
|
|
9
|
+
font-size: 16px;
|
|
10
|
+
font-weight: bold;
|
|
11
|
+
color: ${token.colorText};
|
|
12
|
+
`,
|
|
13
|
+
}));
|
|
14
|
+
const Header = memo(() => {
|
|
15
|
+
const { t } = useTranslation('setting');
|
|
16
|
+
|
|
17
|
+
const { styles } = useStyles();
|
|
18
|
+
return (
|
|
19
|
+
<ChatHeader
|
|
20
|
+
left={<div className={styles.title}>{t('header')}</div>}
|
|
21
|
+
onBackClick={() => Router.back()}
|
|
22
|
+
showBackButton
|
|
23
|
+
/>
|
|
24
|
+
);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
export default Header;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { Form, Input, type ItemGroup } from '@lobehub/ui';
|
|
2
|
+
import isEqual from 'fast-deep-equal';
|
|
3
|
+
import { Palette } from 'lucide-react';
|
|
4
|
+
import { memo, useMemo } from 'react';
|
|
5
|
+
import { useTranslation } from 'react-i18next';
|
|
6
|
+
|
|
7
|
+
import { settingsSelectors, useSettings } from '@/store/settings';
|
|
8
|
+
import { ConfigKeys } from '@/types/exportConfig';
|
|
9
|
+
|
|
10
|
+
type SettingItemGroup = ItemGroup & {
|
|
11
|
+
children: {
|
|
12
|
+
name: ConfigKeys;
|
|
13
|
+
}[];
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const SettingForm = memo(() => {
|
|
17
|
+
const settings = useSettings(settingsSelectors.currentSettings, isEqual);
|
|
18
|
+
|
|
19
|
+
const { t } = useTranslation('setting');
|
|
20
|
+
|
|
21
|
+
const theme: SettingItemGroup = useMemo(
|
|
22
|
+
() => ({
|
|
23
|
+
children: [
|
|
24
|
+
{
|
|
25
|
+
children: <Input />,
|
|
26
|
+
desc: t('settingTheme.avatar.desc'),
|
|
27
|
+
label: t('settingTheme.avatar.title'),
|
|
28
|
+
name: 'avatar',
|
|
29
|
+
},
|
|
30
|
+
],
|
|
31
|
+
icon: Palette,
|
|
32
|
+
title: t('settingTheme.title'),
|
|
33
|
+
}),
|
|
34
|
+
[settings],
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
return (
|
|
38
|
+
<Form initialValues={settings} items={[theme]} style={{ maxWidth: 1024, width: '100%' }} />
|
|
39
|
+
);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
export default SettingForm;
|