@lobehub/chat 0.26.0 → 0.26.1
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 +25 -0
- package/package.json +1 -1
- package/src/const/message.ts +2 -0
- package/src/locales/default/common.ts +3 -0
- package/src/locales/default/plugin.ts +19 -1
- package/src/pages/api/openai.ts +7 -4
- package/src/pages/api/plugins.api.ts +16 -38
- package/src/pages/chat/[id]/Conversation/ChatList/MessageExtra.tsx +28 -26
- package/src/pages/chat/[id]/Conversation/ChatList/Plugins/FunctionCall.tsx +60 -0
- package/src/pages/chat/[id]/Conversation/ChatList/Plugins/PluginMessage.tsx +45 -0
- package/src/pages/chat/[id]/Conversation/ChatList/Plugins/PluginResultRender.tsx +51 -0
- package/src/pages/chat/[id]/Conversation/ChatList/Plugins/style.ts +25 -0
- package/src/pages/chat/[id]/Conversation/ChatList/index.tsx +34 -9
- package/src/pages/chat/[id]/edit/AgentPlugin/index.tsx +2 -2
- package/src/pages/setting/index.page.tsx +11 -28
- package/src/pages/setting/layout.tsx +35 -0
- package/src/plugins/Render.ts +8 -0
- package/src/plugins/index.ts +7 -3
- package/src/plugins/searchEngine/index.ts +4 -1
- package/src/plugins/searchEngine/runner.ts +5 -73
- package/src/plugins/searchEngine/type.ts +80 -0
- package/src/plugins/type.ts +17 -0
- package/src/plugins/weather/Render.tsx +53 -0
- package/src/plugins/weather/index.ts +9 -1
- package/src/plugins/weather/runner.ts +12 -7
- package/src/plugins/weather/type.ts +36 -0
- package/src/plugins/webCrawler/index.ts +4 -1
- package/src/plugins/webCrawler/runner.ts +3 -27
- package/src/plugins/webCrawler/type.ts +32 -0
- package/src/services/chatModel.ts +1 -2
- package/src/services/plugin.ts +30 -0
- package/src/store/session/slices/chat/actions/message.ts +59 -40
- package/src/store/session/slices/chat/selectors/utils.test.ts +3 -2
- package/src/store/session/slices/chat/selectors/utils.ts +4 -3
- package/src/types/chatMessage.ts +5 -1
- package/src/types/openai.ts +3 -0
- package/src/types/plugin.ts +4 -0
- package/src/utils/message.ts +16 -0
- package/src/pages/chat/[id]/Conversation/ChatList/FunctionMessage.tsx +0 -31
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,31 @@
|
|
|
2
2
|
|
|
3
3
|
# Changelog
|
|
4
4
|
|
|
5
|
+
### [Version 0.26.1](https://github.com/lobehub/lobe-chat/compare/v0.26.0...v0.26.1)
|
|
6
|
+
|
|
7
|
+
<sup>Released on **2023-07-29**</sup>
|
|
8
|
+
|
|
9
|
+
#### ♻ Code Refactoring
|
|
10
|
+
|
|
11
|
+
- **misc**: 优化 setting Layout 实现.
|
|
12
|
+
|
|
13
|
+
<br/>
|
|
14
|
+
|
|
15
|
+
<details>
|
|
16
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
|
17
|
+
|
|
18
|
+
#### Code refactoring
|
|
19
|
+
|
|
20
|
+
- **misc**: 优化 setting Layout 实现 ([f789935](https://github.com/lobehub/lobe-chat/commit/f789935))
|
|
21
|
+
|
|
22
|
+
</details>
|
|
23
|
+
|
|
24
|
+
<div align="right">
|
|
25
|
+
|
|
26
|
+
[](#readme-top)
|
|
27
|
+
|
|
28
|
+
</div>
|
|
29
|
+
|
|
5
30
|
## [Version 0.26.0](https://github.com/lobehub/lobe-chat/compare/v0.25.0...v0.26.0)
|
|
6
31
|
|
|
7
32
|
<sup>Released on **2023-07-28**</sup>
|
package/package.json
CHANGED
package/src/const/message.ts
CHANGED
|
@@ -1,10 +1,28 @@
|
|
|
1
1
|
export default {
|
|
2
|
+
loading: {
|
|
3
|
+
content: '数据获取中...',
|
|
4
|
+
plugin: '插件运行中...',
|
|
5
|
+
},
|
|
2
6
|
pluginList: '插件列表',
|
|
3
|
-
pluginLoading: '插件运行中...',
|
|
4
7
|
plugins: {
|
|
5
8
|
realtimeWeather: '实时天气预报',
|
|
6
9
|
searchEngine: '搜索引擎',
|
|
7
10
|
undefined: '插件检测中...',
|
|
8
11
|
websiteCrawler: '网页内容提取',
|
|
9
12
|
},
|
|
13
|
+
realtimeWeather: {
|
|
14
|
+
data: {
|
|
15
|
+
date: '日期',
|
|
16
|
+
daytemp_float: '日间温度',
|
|
17
|
+
dayweather: '日间天气',
|
|
18
|
+
daywind: '日间风速',
|
|
19
|
+
nighttemp_float: '夜间温度',
|
|
20
|
+
nightweather: '夜间天气',
|
|
21
|
+
nightwind: '夜间风速',
|
|
22
|
+
week: '星期',
|
|
23
|
+
},
|
|
24
|
+
title: '近7日天气数据({{city}})',
|
|
25
|
+
updateAt: '更新时间',
|
|
26
|
+
},
|
|
27
|
+
responseData: '返回数据',
|
|
10
28
|
};
|
package/src/pages/api/openai.ts
CHANGED
|
@@ -4,11 +4,10 @@ import { ChatCompletionFunctions } from 'openai-edge/types/api';
|
|
|
4
4
|
|
|
5
5
|
import { getServerConfig } from '@/config/server';
|
|
6
6
|
import { createErrorResponse } from '@/pages/api/error';
|
|
7
|
+
import { PluginsMap } from '@/plugins';
|
|
7
8
|
import { ErrorType } from '@/types/fetch';
|
|
8
9
|
import { OpenAIStreamPayload } from '@/types/openai';
|
|
9
10
|
|
|
10
|
-
import pluginList from '../../plugins';
|
|
11
|
-
|
|
12
11
|
const isDev = process.env.NODE_ENV === 'development';
|
|
13
12
|
|
|
14
13
|
// 创建 OpenAI 实例
|
|
@@ -41,7 +40,7 @@ export const createChatCompletion = async ({
|
|
|
41
40
|
|
|
42
41
|
// ============ 1. 前置处理 functions ============ //
|
|
43
42
|
|
|
44
|
-
const filterFunctions: ChatCompletionFunctions[] =
|
|
43
|
+
const filterFunctions: ChatCompletionFunctions[] = Object.values(PluginsMap)
|
|
45
44
|
.filter((p) => {
|
|
46
45
|
// 如果不存在 enabledPlugins,那么全部不启用
|
|
47
46
|
if (!enabledPlugins) return false;
|
|
@@ -54,7 +53,11 @@ export const createChatCompletion = async ({
|
|
|
54
53
|
const functions = filterFunctions.length === 0 ? undefined : filterFunctions;
|
|
55
54
|
|
|
56
55
|
// ============ 2. 前置处理 messages ============ //
|
|
57
|
-
const formatMessages = messages.map((m) => ({
|
|
56
|
+
const formatMessages = messages.map((m) => ({
|
|
57
|
+
content: m.content,
|
|
58
|
+
name: m.name,
|
|
59
|
+
role: m.role,
|
|
60
|
+
}));
|
|
58
61
|
|
|
59
62
|
// ============ 3. 发送请求 ============ //
|
|
60
63
|
|
|
@@ -1,44 +1,22 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { OpenAIPluginPayload } from '@/types/plugin';
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
import { OpenAIStreamPayload } from '@/types/openai';
|
|
5
|
-
|
|
6
|
-
import pluginList from '../../plugins';
|
|
7
|
-
import { createChatCompletion, createOpenAI } from './openai';
|
|
3
|
+
import { PluginsMap } from '../../plugins';
|
|
8
4
|
|
|
9
5
|
export const runtime = 'edge';
|
|
10
6
|
|
|
11
7
|
export default async function handler(req: Request) {
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
const func = pluginList.find((f) => f.name === name);
|
|
27
|
-
|
|
28
|
-
if (func) {
|
|
29
|
-
const result = await func.runner(args as any);
|
|
30
|
-
|
|
31
|
-
console.log(`[${name}]`, args, `result:`, JSON.stringify(result, null, 2));
|
|
32
|
-
|
|
33
|
-
const newMessages = createFunctionCallMessages(result) as ChatCompletionRequestMessage[];
|
|
34
|
-
|
|
35
|
-
return openai.createChatCompletion({
|
|
36
|
-
...payload,
|
|
37
|
-
messages: [...payload.messages, ...newMessages],
|
|
38
|
-
});
|
|
39
|
-
}
|
|
40
|
-
},
|
|
41
|
-
}),
|
|
42
|
-
payload,
|
|
43
|
-
});
|
|
8
|
+
const { name, arguments: args } = (await req.json()) as OpenAIPluginPayload;
|
|
9
|
+
|
|
10
|
+
console.log(`检测到 functionCall: ${name}`);
|
|
11
|
+
|
|
12
|
+
const func = PluginsMap[name];
|
|
13
|
+
|
|
14
|
+
if (func) {
|
|
15
|
+
const data = JSON.parse(args);
|
|
16
|
+
const result = await func.runner(data);
|
|
17
|
+
|
|
18
|
+
console.log(`[${name}]`, args, `result:`, JSON.stringify(result, null, 2));
|
|
19
|
+
|
|
20
|
+
return new Response(JSON.stringify(result));
|
|
21
|
+
}
|
|
44
22
|
}
|
|
@@ -1,13 +1,9 @@
|
|
|
1
|
-
import { Avatar, Icon, Tooltip } from '@lobehub/ui';
|
|
2
1
|
import { Tag } from 'antd';
|
|
3
2
|
import { createStyles } from 'antd-style';
|
|
4
|
-
import { LucideToyBrick } from 'lucide-react';
|
|
5
3
|
import { ReactNode } from 'react';
|
|
6
|
-
import { useTranslation } from 'react-i18next';
|
|
7
4
|
import { Flexbox } from 'react-layout-kit';
|
|
8
5
|
import { shallow } from 'zustand/shallow';
|
|
9
6
|
|
|
10
|
-
import pluginList from '@/plugins';
|
|
11
7
|
import { agentSelectors, useSessionStore } from '@/store/session';
|
|
12
8
|
import { ChatMessage } from '@/types/chatMessage';
|
|
13
9
|
|
|
@@ -23,25 +19,29 @@ const useStyles = createStyles(({ css }) => ({
|
|
|
23
19
|
`,
|
|
24
20
|
}));
|
|
25
21
|
|
|
26
|
-
const MessageExtra = ({
|
|
22
|
+
const MessageExtra = ({
|
|
23
|
+
role,
|
|
24
|
+
extra,
|
|
25
|
+
// name,
|
|
26
|
+
function_call,
|
|
27
|
+
}: ChatMessage): ReactNode => {
|
|
27
28
|
const { styles } = useStyles();
|
|
28
29
|
|
|
29
|
-
const { t } = useTranslation();
|
|
30
|
+
// const { t } = useTranslation();
|
|
30
31
|
const [model] = useSessionStore((s) => [agentSelectors.currentAgentModel(s)], shallow);
|
|
31
32
|
|
|
32
|
-
const plugin =
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
);
|
|
33
|
+
// const plugin = PluginsMap[name || ''];
|
|
34
|
+
|
|
35
|
+
// const funcTag = (
|
|
36
|
+
// <Tag bordered={false} className={styles.plugin} style={{ borderRadius: 6 }}>
|
|
37
|
+
// {plugin?.avatar ? (
|
|
38
|
+
// <Avatar avatar={plugin?.avatar} size={18} />
|
|
39
|
+
// ) : (
|
|
40
|
+
// <Icon icon={LucideToyBrick} />
|
|
41
|
+
// )}
|
|
42
|
+
// {t(`plugins.${name}` as any, { ns: 'plugin' })}
|
|
43
|
+
// </Tag>
|
|
44
|
+
// );
|
|
45
45
|
|
|
46
46
|
const modelTag = (
|
|
47
47
|
<div>
|
|
@@ -59,6 +59,7 @@ const MessageExtra = ({ role, extra, function_call }: ChatMessage): ReactNode =>
|
|
|
59
59
|
|
|
60
60
|
switch (role) {
|
|
61
61
|
case 'user':
|
|
62
|
+
case 'function':
|
|
62
63
|
case 'system': {
|
|
63
64
|
return;
|
|
64
65
|
}
|
|
@@ -69,15 +70,16 @@ const MessageExtra = ({ role, extra, function_call }: ChatMessage): ReactNode =>
|
|
|
69
70
|
if (!(hasModelTag || hasFuncTag)) return;
|
|
70
71
|
|
|
71
72
|
return (
|
|
72
|
-
|
|
73
|
-
{
|
|
74
|
-
|
|
75
|
-
|
|
73
|
+
hasModelTag && (
|
|
74
|
+
<Flexbox className={styles.container} horizontal>
|
|
75
|
+
{modelTag}
|
|
76
|
+
</Flexbox>
|
|
77
|
+
)
|
|
76
78
|
);
|
|
77
79
|
}
|
|
78
|
-
case 'function': {
|
|
79
|
-
|
|
80
|
-
}
|
|
80
|
+
// case 'function': {
|
|
81
|
+
// return <Flexbox className={styles.container}>{funcTag}</Flexbox>;
|
|
82
|
+
// }
|
|
81
83
|
}
|
|
82
84
|
};
|
|
83
85
|
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { LoadingOutlined } from '@ant-design/icons';
|
|
2
|
+
import { Avatar, Highlighter, Icon } from '@lobehub/ui';
|
|
3
|
+
import { LucideChevronDown, LucideChevronUp, LucideToyBrick } from 'lucide-react';
|
|
4
|
+
import { memo, useState } from 'react';
|
|
5
|
+
import { useTranslation } from 'react-i18next';
|
|
6
|
+
import { Flexbox } from 'react-layout-kit';
|
|
7
|
+
|
|
8
|
+
import { PluginsMap } from '@/plugins';
|
|
9
|
+
import { OpenAIFunctionCall } from '@/types/chatMessage';
|
|
10
|
+
|
|
11
|
+
import { useStyles } from './style';
|
|
12
|
+
|
|
13
|
+
export interface FunctionCallProps {
|
|
14
|
+
function_call?: OpenAIFunctionCall;
|
|
15
|
+
loading?: boolean;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const FunctionCall = memo<FunctionCallProps>(({ function_call, loading }) => {
|
|
19
|
+
const { t } = useTranslation('plugin');
|
|
20
|
+
const { styles } = useStyles();
|
|
21
|
+
const [open, setOpen] = useState(false);
|
|
22
|
+
|
|
23
|
+
const plugin = PluginsMap[function_call?.name || ''];
|
|
24
|
+
|
|
25
|
+
const avatar = plugin?.avatar ? (
|
|
26
|
+
<Avatar avatar={plugin?.avatar} size={32} />
|
|
27
|
+
) : (
|
|
28
|
+
<Icon icon={LucideToyBrick} />
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
const args = JSON.stringify(JSON.parse(function_call?.arguments || '{}'), null, 2);
|
|
32
|
+
|
|
33
|
+
return (
|
|
34
|
+
<Flexbox gap={8}>
|
|
35
|
+
<Flexbox
|
|
36
|
+
align={'center'}
|
|
37
|
+
className={styles.container}
|
|
38
|
+
gap={8}
|
|
39
|
+
horizontal
|
|
40
|
+
onClick={() => {
|
|
41
|
+
setOpen(!open);
|
|
42
|
+
}}
|
|
43
|
+
>
|
|
44
|
+
{loading ? (
|
|
45
|
+
<div>
|
|
46
|
+
<LoadingOutlined />
|
|
47
|
+
</div>
|
|
48
|
+
) : (
|
|
49
|
+
avatar
|
|
50
|
+
)}
|
|
51
|
+
{t(`plugins.${function_call?.name}` as any, { ns: 'plugin' })}
|
|
52
|
+
{loading ? `(${t('loading.plugin')})` : null}
|
|
53
|
+
<Icon icon={open ? LucideChevronUp : LucideChevronDown} />
|
|
54
|
+
</Flexbox>
|
|
55
|
+
{open && <Highlighter language={'json'}>{args}</Highlighter>}
|
|
56
|
+
</Flexbox>
|
|
57
|
+
);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
export default FunctionCall;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { Loading3QuartersOutlined } from '@ant-design/icons';
|
|
2
|
+
import { memo } from 'react';
|
|
3
|
+
import { useTranslation } from 'react-i18next';
|
|
4
|
+
import { Flexbox } from 'react-layout-kit';
|
|
5
|
+
|
|
6
|
+
import { PluginsRender } from '@/plugins/Render';
|
|
7
|
+
import { ChatMessage } from '@/types/chatMessage';
|
|
8
|
+
|
|
9
|
+
import PluginResult from './PluginResultRender';
|
|
10
|
+
|
|
11
|
+
export interface FunctionMessageProps extends ChatMessage {
|
|
12
|
+
loading?: boolean;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const PluginMessage = memo<FunctionMessageProps>(({ content, name }) => {
|
|
16
|
+
const { t } = useTranslation('plugin');
|
|
17
|
+
|
|
18
|
+
const Render = PluginsRender[name || ''];
|
|
19
|
+
|
|
20
|
+
let isJSON = true;
|
|
21
|
+
try {
|
|
22
|
+
JSON.parse(content);
|
|
23
|
+
} catch {
|
|
24
|
+
isJSON = false;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (!isJSON) {
|
|
28
|
+
return (
|
|
29
|
+
<Flexbox gap={8} horizontal>
|
|
30
|
+
<div>
|
|
31
|
+
<Loading3QuartersOutlined spin />
|
|
32
|
+
</div>
|
|
33
|
+
{t('loading.content')}
|
|
34
|
+
</Flexbox>
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (Render) {
|
|
39
|
+
return <Render content={JSON.parse(content)} name={name || 'unknown'} />;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return <PluginResult content={content} />;
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
export default PluginMessage;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { Avatar, Highlighter, Icon } from '@lobehub/ui';
|
|
2
|
+
import { LucideChevronDown, LucideChevronUp } from 'lucide-react';
|
|
3
|
+
import { memo, useState } from 'react';
|
|
4
|
+
import { useTranslation } from 'react-i18next';
|
|
5
|
+
import { Flexbox } from 'react-layout-kit';
|
|
6
|
+
|
|
7
|
+
import { useStyles } from './style';
|
|
8
|
+
|
|
9
|
+
export interface FunctionMessageProps {
|
|
10
|
+
content: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const PluginResult = memo<FunctionMessageProps>(({ content }) => {
|
|
14
|
+
const { t } = useTranslation('plugin');
|
|
15
|
+
const { styles } = useStyles();
|
|
16
|
+
|
|
17
|
+
const [open, setOpen] = useState(false);
|
|
18
|
+
|
|
19
|
+
let data;
|
|
20
|
+
|
|
21
|
+
try {
|
|
22
|
+
data = JSON.stringify(JSON.parse(content), null, 2);
|
|
23
|
+
} catch {
|
|
24
|
+
data = content;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return (
|
|
28
|
+
<Flexbox gap={8}>
|
|
29
|
+
<Flexbox
|
|
30
|
+
align={'center'}
|
|
31
|
+
className={styles.container}
|
|
32
|
+
gap={8}
|
|
33
|
+
horizontal
|
|
34
|
+
onClick={() => {
|
|
35
|
+
setOpen(!open);
|
|
36
|
+
}}
|
|
37
|
+
>
|
|
38
|
+
<Avatar avatar={'💾'} size={24} />
|
|
39
|
+
{t('responseData')}
|
|
40
|
+
<Icon icon={open ? LucideChevronUp : LucideChevronDown} />
|
|
41
|
+
</Flexbox>
|
|
42
|
+
{open && (
|
|
43
|
+
<Highlighter language={'json'} style={{ maxHeight: 200 }}>
|
|
44
|
+
{data}
|
|
45
|
+
</Highlighter>
|
|
46
|
+
)}
|
|
47
|
+
</Flexbox>
|
|
48
|
+
);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
export default PluginResult;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { createStyles } from 'antd-style';
|
|
2
|
+
|
|
3
|
+
export const useStyles = createStyles(({ css, token }) => ({
|
|
4
|
+
container: css`
|
|
5
|
+
cursor: pointer;
|
|
6
|
+
|
|
7
|
+
width: fit-content;
|
|
8
|
+
padding: 6px 8px;
|
|
9
|
+
|
|
10
|
+
color: ${token.colorText};
|
|
11
|
+
|
|
12
|
+
border: 1px solid ${token.colorBorder};
|
|
13
|
+
border-radius: 8px;
|
|
14
|
+
|
|
15
|
+
&:hover {
|
|
16
|
+
background: ${token.colorFillTertiary};
|
|
17
|
+
}
|
|
18
|
+
`,
|
|
19
|
+
plugin: css`
|
|
20
|
+
display: flex;
|
|
21
|
+
gap: 4px;
|
|
22
|
+
align-items: center;
|
|
23
|
+
width: fit-content;
|
|
24
|
+
`,
|
|
25
|
+
}));
|
|
@@ -1,24 +1,20 @@
|
|
|
1
1
|
import { ChatList, RenderErrorMessage, RenderMessage } from '@lobehub/ui';
|
|
2
2
|
import isEqual from 'fast-deep-equal';
|
|
3
|
-
import { memo } from 'react';
|
|
3
|
+
import { memo, useCallback } from 'react';
|
|
4
4
|
import { useTranslation } from 'react-i18next';
|
|
5
|
+
import { Flexbox } from 'react-layout-kit';
|
|
5
6
|
import { shallow } from 'zustand/shallow';
|
|
6
7
|
|
|
7
8
|
import { agentSelectors, chatSelectors, useSessionStore } from '@/store/session';
|
|
9
|
+
import { ChatMessage } from '@/types/chatMessage';
|
|
8
10
|
import { ErrorType } from '@/types/fetch';
|
|
9
11
|
import { isFunctionMessage } from '@/utils/message';
|
|
10
12
|
|
|
11
13
|
import InvalidAccess from './Error/InvalidAccess';
|
|
12
14
|
import OpenAiBizError from './Error/OpenAiBizError';
|
|
13
|
-
import FunctionMessage from './FunctionMessage';
|
|
14
15
|
import MessageExtra from './MessageExtra';
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
if (message.role === 'function')
|
|
18
|
-
return isFunctionMessage(message.content) ? <FunctionMessage /> : content;
|
|
19
|
-
|
|
20
|
-
return content;
|
|
21
|
-
};
|
|
16
|
+
import FunctionCall from './Plugins/FunctionCall';
|
|
17
|
+
import PluginMessage from './Plugins/PluginMessage';
|
|
22
18
|
|
|
23
19
|
const renderErrorMessage: RenderErrorMessage = (error, message) => {
|
|
24
20
|
switch (error.type as ErrorType) {
|
|
@@ -46,6 +42,35 @@ const List = () => {
|
|
|
46
42
|
shallow,
|
|
47
43
|
);
|
|
48
44
|
|
|
45
|
+
const renderMessage: RenderMessage = useCallback(
|
|
46
|
+
(content, message: ChatMessage) => {
|
|
47
|
+
if (message.role === 'function')
|
|
48
|
+
return (
|
|
49
|
+
<Flexbox gap={12}>
|
|
50
|
+
<FunctionCall
|
|
51
|
+
function_call={message.function_call}
|
|
52
|
+
loading={message.id === chatLoadingId}
|
|
53
|
+
/>
|
|
54
|
+
<PluginMessage loading={message.id === chatLoadingId} {...message} />
|
|
55
|
+
</Flexbox>
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
if (message.role === 'assistant') {
|
|
59
|
+
return isFunctionMessage(message.content) || !!message.function_call ? (
|
|
60
|
+
<FunctionCall
|
|
61
|
+
function_call={message.function_call}
|
|
62
|
+
loading={message.id === chatLoadingId}
|
|
63
|
+
/>
|
|
64
|
+
) : (
|
|
65
|
+
content
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return content;
|
|
70
|
+
},
|
|
71
|
+
[chatLoadingId],
|
|
72
|
+
);
|
|
73
|
+
|
|
49
74
|
return (
|
|
50
75
|
<ChatList
|
|
51
76
|
data={data}
|
|
@@ -7,7 +7,7 @@ import { useTranslation } from 'react-i18next';
|
|
|
7
7
|
import { shallow } from 'zustand/shallow';
|
|
8
8
|
|
|
9
9
|
import { FORM_STYLE } from '@/const/layoutTokens';
|
|
10
|
-
import
|
|
10
|
+
import { PluginsMap } from '@/plugins';
|
|
11
11
|
import { agentSelectors, useSessionStore } from '@/store/session';
|
|
12
12
|
|
|
13
13
|
const PluginList = () => {
|
|
@@ -19,7 +19,7 @@ const PluginList = () => {
|
|
|
19
19
|
|
|
20
20
|
const plugin: ItemGroup = useMemo(
|
|
21
21
|
() => ({
|
|
22
|
-
children:
|
|
22
|
+
children: Object.values(PluginsMap).map((item) => ({
|
|
23
23
|
avatar: <Avatar avatar={item.avatar} />,
|
|
24
24
|
children: (
|
|
25
25
|
<Switch
|
|
@@ -1,39 +1,22 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { memo, useEffect } from 'react';
|
|
3
|
-
import { useTranslation } from 'react-i18next';
|
|
1
|
+
import { memo } from 'react';
|
|
4
2
|
import { Flexbox } from 'react-layout-kit';
|
|
5
3
|
|
|
6
4
|
import HeaderSpacing from '@/components/HeaderSpacing';
|
|
7
|
-
import { createI18nNext } from '@/locales/create';
|
|
8
|
-
import ChatLayout from '@/pages/chat/layout';
|
|
9
|
-
import { genSiteHeadTitle } from '@/utils/genSiteHeadTitle';
|
|
10
5
|
|
|
11
6
|
import Header from './Header';
|
|
12
7
|
import SettingForm from './SettingForm';
|
|
8
|
+
import SettingLayout from './layout';
|
|
13
9
|
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
const SettingLayout = memo(() => {
|
|
17
|
-
const { t } = useTranslation('setting');
|
|
18
|
-
const pageTitle = genSiteHeadTitle(t('header.global'));
|
|
19
|
-
|
|
20
|
-
useEffect(() => {
|
|
21
|
-
initI18n.finally();
|
|
22
|
-
}, []);
|
|
10
|
+
const Setting = memo(() => {
|
|
23
11
|
return (
|
|
24
|
-
|
|
25
|
-
<
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
<HeaderSpacing />
|
|
32
|
-
<SettingForm />
|
|
33
|
-
</Flexbox>
|
|
34
|
-
</ChatLayout>
|
|
35
|
-
</>
|
|
12
|
+
<SettingLayout>
|
|
13
|
+
<Header />
|
|
14
|
+
<Flexbox align={'center'} flex={1} padding={24} style={{ overflow: 'auto' }}>
|
|
15
|
+
<HeaderSpacing />
|
|
16
|
+
<SettingForm />
|
|
17
|
+
</Flexbox>
|
|
18
|
+
</SettingLayout>
|
|
36
19
|
);
|
|
37
20
|
});
|
|
38
21
|
|
|
39
|
-
export default
|
|
22
|
+
export default Setting;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import Head from 'next/head';
|
|
2
|
+
import { ReactNode, memo, useEffect } from 'react';
|
|
3
|
+
import { useTranslation } from 'react-i18next';
|
|
4
|
+
import { Flexbox } from 'react-layout-kit';
|
|
5
|
+
|
|
6
|
+
import SideBar from '@/features/SideBar';
|
|
7
|
+
import { createI18nNext } from '@/locales/create';
|
|
8
|
+
import { genSiteHeadTitle } from '@/utils/genSiteHeadTitle';
|
|
9
|
+
|
|
10
|
+
const initI18n = createI18nNext('setting');
|
|
11
|
+
|
|
12
|
+
const SettingLayout = memo<{ children: ReactNode }>(({ children }) => {
|
|
13
|
+
const { t } = useTranslation('setting');
|
|
14
|
+
const pageTitle = genSiteHeadTitle(t('header.global'));
|
|
15
|
+
|
|
16
|
+
useEffect(() => {
|
|
17
|
+
initI18n.finally();
|
|
18
|
+
}, []);
|
|
19
|
+
|
|
20
|
+
return (
|
|
21
|
+
<>
|
|
22
|
+
<Head>
|
|
23
|
+
<title>{pageTitle}</title>
|
|
24
|
+
</Head>
|
|
25
|
+
<Flexbox horizontal width={'100%'}>
|
|
26
|
+
<SideBar />
|
|
27
|
+
<Flexbox flex={1} height={'100vh'} style={{ position: 'relative' }}>
|
|
28
|
+
{children}
|
|
29
|
+
</Flexbox>
|
|
30
|
+
</Flexbox>
|
|
31
|
+
</>
|
|
32
|
+
);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
export default SettingLayout;
|
package/src/plugins/index.ts
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
|
+
import type { PluginItem } from '@/plugins/type';
|
|
2
|
+
|
|
1
3
|
import searchEngine from './searchEngine';
|
|
2
4
|
import getWeather from './weather';
|
|
3
5
|
import webCrawler from './webCrawler';
|
|
4
6
|
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
-
|
|
7
|
+
export const PluginsMap: Record<string, PluginItem> = {
|
|
8
|
+
[getWeather.name]: getWeather,
|
|
9
|
+
[searchEngine.name]: searchEngine,
|
|
10
|
+
[webCrawler.name]: webCrawler,
|
|
11
|
+
};
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { ChatCompletionFunctions } from 'openai-edge/types/api';
|
|
2
2
|
|
|
3
|
+
import { PluginItem } from '@/plugins/type';
|
|
4
|
+
|
|
3
5
|
import runner from './runner';
|
|
6
|
+
import { Result } from './type';
|
|
4
7
|
|
|
5
8
|
const schema: ChatCompletionFunctions = {
|
|
6
9
|
description: '查询搜索引擎获取信息',
|
|
@@ -17,7 +20,7 @@ const schema: ChatCompletionFunctions = {
|
|
|
17
20
|
},
|
|
18
21
|
};
|
|
19
22
|
|
|
20
|
-
const searchEngine = {
|
|
23
|
+
const searchEngine: PluginItem<Result> = {
|
|
21
24
|
avatar: '🔍',
|
|
22
25
|
name: 'searchEngine',
|
|
23
26
|
runner,
|