@lobehub/chat 0.26.0 → 0.27.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 +58 -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 +11 -0
- package/src/plugins/index.ts +7 -3
- package/src/plugins/searchEngine/Render.tsx +85 -0
- package/src/plugins/searchEngine/index.ts +4 -1
- package/src/plugins/searchEngine/runner.ts +7 -73
- package/src/plugins/searchEngine/type.ts +82 -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/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
|
+
};
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { createStyles } from 'antd-style';
|
|
2
|
+
import Link from 'next/link';
|
|
3
|
+
import { memo } from 'react';
|
|
4
|
+
import { Flexbox } from 'react-layout-kit';
|
|
5
|
+
|
|
6
|
+
import { PluginRenderProps } from '@/plugins/type';
|
|
7
|
+
|
|
8
|
+
import { Result } from './type';
|
|
9
|
+
|
|
10
|
+
const useStyles = createStyles(({ css, token, cx }) => {
|
|
11
|
+
const title = css`
|
|
12
|
+
margin-top: 4px;
|
|
13
|
+
font-size: 16px;
|
|
14
|
+
`;
|
|
15
|
+
return {
|
|
16
|
+
container: css`
|
|
17
|
+
:not(:last-child) {
|
|
18
|
+
border-bottom: 1px solid ${token.colorBorder};
|
|
19
|
+
}
|
|
20
|
+
`,
|
|
21
|
+
desc: css`
|
|
22
|
+
color: ${token.colorTextTertiary};
|
|
23
|
+
`,
|
|
24
|
+
displayLink: css`
|
|
25
|
+
color: ${token.colorTextQuaternary};
|
|
26
|
+
`,
|
|
27
|
+
favicon: css`
|
|
28
|
+
border-radius: 50%;
|
|
29
|
+
`,
|
|
30
|
+
link: css`
|
|
31
|
+
&:hover {
|
|
32
|
+
.${cx(title)} {
|
|
33
|
+
text-decoration: underline;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
`,
|
|
37
|
+
title,
|
|
38
|
+
};
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
const Render = memo<PluginRenderProps<Result>>(({ content }) => {
|
|
42
|
+
const { styles } = useStyles();
|
|
43
|
+
return (
|
|
44
|
+
<Flexbox gap={8}>
|
|
45
|
+
<Flexbox>
|
|
46
|
+
{content.map((item) => (
|
|
47
|
+
<Flexbox
|
|
48
|
+
className={styles.container}
|
|
49
|
+
distribution={'space-between'}
|
|
50
|
+
horizontal
|
|
51
|
+
key={item.link}
|
|
52
|
+
padding={12}
|
|
53
|
+
>
|
|
54
|
+
<Flexbox>
|
|
55
|
+
<Link className={styles.link} href={item.link!} target={'_blank'}>
|
|
56
|
+
<Flexbox>
|
|
57
|
+
<Flexbox align={'center'} gap={12} horizontal>
|
|
58
|
+
{item.favicon && (
|
|
59
|
+
<img
|
|
60
|
+
alt={item.title || item.link}
|
|
61
|
+
className={styles.favicon}
|
|
62
|
+
height={24}
|
|
63
|
+
src={item.favicon}
|
|
64
|
+
width={24}
|
|
65
|
+
/>
|
|
66
|
+
)}
|
|
67
|
+
<Flexbox>
|
|
68
|
+
<Flexbox className={styles.desc}>{item.source}</Flexbox>
|
|
69
|
+
<Flexbox className={styles.displayLink}>{item.displayed_link}</Flexbox>
|
|
70
|
+
</Flexbox>
|
|
71
|
+
</Flexbox>
|
|
72
|
+
<Flexbox className={styles.title}>{item.title}</Flexbox>
|
|
73
|
+
</Flexbox>
|
|
74
|
+
</Link>
|
|
75
|
+
<Flexbox className={styles.desc}>
|
|
76
|
+
{item.date ? `${item.date} - ${item.content}` : item.content}
|
|
77
|
+
</Flexbox>
|
|
78
|
+
</Flexbox>
|
|
79
|
+
</Flexbox>
|
|
80
|
+
))}
|
|
81
|
+
</Flexbox>
|
|
82
|
+
</Flexbox>
|
|
83
|
+
);
|
|
84
|
+
});
|
|
85
|
+
export default Render;
|
|
@@ -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,
|
|
@@ -1,82 +1,14 @@
|
|
|
1
1
|
import querystring from 'query-string';
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
const API_KEY = process.env.SERPAI_API_KEY;
|
|
6
|
-
|
|
7
|
-
export type OrganicResults = OrganicResult[];
|
|
8
|
-
|
|
9
|
-
export interface OrganicResult {
|
|
10
|
-
about_page_link: string;
|
|
11
|
-
about_page_serpapi_link: string;
|
|
12
|
-
about_this_result: AboutThisResult;
|
|
13
|
-
cached_page_link?: string;
|
|
14
|
-
date?: string;
|
|
15
|
-
displayed_link: string;
|
|
16
|
-
favicon?: string;
|
|
17
|
-
link: string;
|
|
18
|
-
position: number;
|
|
19
|
-
related_results?: RelatedResult[];
|
|
20
|
-
rich_snippet?: RichSnippet;
|
|
21
|
-
snippet: string;
|
|
22
|
-
snippet_highlighted_words?: string[];
|
|
23
|
-
source: string;
|
|
24
|
-
thumbnail?: string;
|
|
25
|
-
title: string;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export interface AboutThisResult {
|
|
29
|
-
languages: string[];
|
|
30
|
-
regions: string[];
|
|
31
|
-
source: Source;
|
|
32
|
-
}
|
|
3
|
+
import { PluginRunner } from '@/plugins/type';
|
|
33
4
|
|
|
34
|
-
|
|
35
|
-
description: string;
|
|
36
|
-
icon: string;
|
|
37
|
-
security?: string;
|
|
38
|
-
source_info_link?: string;
|
|
39
|
-
}
|
|
5
|
+
import { OrganicResults, Result } from './type';
|
|
40
6
|
|
|
41
|
-
|
|
42
|
-
about_page_link: string;
|
|
43
|
-
about_page_serpapi_link: string;
|
|
44
|
-
about_this_result: AboutThisResult2;
|
|
45
|
-
cached_page_link: string;
|
|
46
|
-
date: string;
|
|
47
|
-
displayed_link: string;
|
|
48
|
-
link: string;
|
|
49
|
-
position: number;
|
|
50
|
-
snippet: string;
|
|
51
|
-
snippet_highlighted_words: string[];
|
|
52
|
-
title: string;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
export interface AboutThisResult2 {
|
|
56
|
-
languages: string[];
|
|
57
|
-
regions: string[];
|
|
58
|
-
source: Source2;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
export interface Source2 {
|
|
62
|
-
description: string;
|
|
63
|
-
icon: string;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
export interface RichSnippet {
|
|
67
|
-
top: Top;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
export interface Top {
|
|
71
|
-
detected_extensions: DetectedExtensions;
|
|
72
|
-
extensions: string[];
|
|
73
|
-
}
|
|
7
|
+
const BASE_URL = 'https://serpapi.com/search';
|
|
74
8
|
|
|
75
|
-
|
|
76
|
-
month_ago: number;
|
|
77
|
-
}
|
|
9
|
+
const API_KEY = process.env.SERPAI_API_KEY;
|
|
78
10
|
|
|
79
|
-
const fetchResult
|
|
11
|
+
const fetchResult: PluginRunner<{ keywords: string }, Result> = async ({ keywords }) => {
|
|
80
12
|
const params = {
|
|
81
13
|
api_key: API_KEY,
|
|
82
14
|
engine: 'google',
|
|
@@ -98,6 +30,8 @@ const fetchResult = async ({ keywords }: { keywords: string }) => {
|
|
|
98
30
|
return results.map((r) => ({
|
|
99
31
|
content: r.snippet,
|
|
100
32
|
date: r.date,
|
|
33
|
+
displayed_link: r.displayed_link,
|
|
34
|
+
favicon: r.favicon,
|
|
101
35
|
link: r.link,
|
|
102
36
|
source: r.source,
|
|
103
37
|
title: r.title,
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
export type OrganicResults = OrganicResult[];
|
|
2
|
+
|
|
3
|
+
export interface SearchItem {
|
|
4
|
+
content: string;
|
|
5
|
+
date?: string;
|
|
6
|
+
displayed_link?: string;
|
|
7
|
+
favicon?: string;
|
|
8
|
+
link: string;
|
|
9
|
+
source?: string;
|
|
10
|
+
title: string;
|
|
11
|
+
}
|
|
12
|
+
export type Result = SearchItem[];
|
|
13
|
+
|
|
14
|
+
interface OrganicResult {
|
|
15
|
+
about_page_link: string;
|
|
16
|
+
about_page_serpapi_link: string;
|
|
17
|
+
about_this_result: AboutThisResult;
|
|
18
|
+
cached_page_link?: string;
|
|
19
|
+
date?: string;
|
|
20
|
+
displayed_link: string;
|
|
21
|
+
favicon?: string;
|
|
22
|
+
link: string;
|
|
23
|
+
position: number;
|
|
24
|
+
related_results?: RelatedResult[];
|
|
25
|
+
rich_snippet?: RichSnippet;
|
|
26
|
+
snippet: string;
|
|
27
|
+
snippet_highlighted_words?: string[];
|
|
28
|
+
source: string;
|
|
29
|
+
thumbnail?: string;
|
|
30
|
+
title: string;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
interface AboutThisResult {
|
|
34
|
+
languages: string[];
|
|
35
|
+
regions: string[];
|
|
36
|
+
source: Source;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
interface Source {
|
|
40
|
+
description: string;
|
|
41
|
+
icon: string;
|
|
42
|
+
security?: string;
|
|
43
|
+
source_info_link?: string;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
interface RelatedResult {
|
|
47
|
+
about_page_link: string;
|
|
48
|
+
about_page_serpapi_link: string;
|
|
49
|
+
about_this_result: AboutThisResult2;
|
|
50
|
+
cached_page_link: string;
|
|
51
|
+
date: string;
|
|
52
|
+
displayed_link: string;
|
|
53
|
+
link: string;
|
|
54
|
+
position: number;
|
|
55
|
+
snippet: string;
|
|
56
|
+
snippet_highlighted_words: string[];
|
|
57
|
+
title: string;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
interface AboutThisResult2 {
|
|
61
|
+
languages: string[];
|
|
62
|
+
regions: string[];
|
|
63
|
+
source: Source2;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
interface Source2 {
|
|
67
|
+
description: string;
|
|
68
|
+
icon: string;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
interface RichSnippet {
|
|
72
|
+
top: Top;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
interface Top {
|
|
76
|
+
detected_extensions: DetectedExtensions;
|
|
77
|
+
extensions: string[];
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
interface DetectedExtensions {
|
|
81
|
+
month_ago: number;
|
|
82
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { ChatCompletionFunctions } from 'openai-edge/types/api';
|
|
2
|
+
import { ReactNode } from 'react';
|
|
3
|
+
|
|
4
|
+
export interface PluginItem<Result = any, RunnerParams = any> {
|
|
5
|
+
avatar: string;
|
|
6
|
+
name: string;
|
|
7
|
+
runner: PluginRunner<RunnerParams, Result>;
|
|
8
|
+
schema: ChatCompletionFunctions;
|
|
9
|
+
}
|
|
10
|
+
export type PluginRender = (props: PluginRenderProps) => ReactNode;
|
|
11
|
+
|
|
12
|
+
export type PluginRunner<Params = object, Result = any> = (params: Params) => Promise<Result>;
|
|
13
|
+
|
|
14
|
+
export interface PluginRenderProps<Result = any> {
|
|
15
|
+
content: Result;
|
|
16
|
+
name: string;
|
|
17
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { Table } from 'antd';
|
|
2
|
+
import { createStyles } from 'antd-style';
|
|
3
|
+
import { memo } from 'react';
|
|
4
|
+
import { useTranslation } from 'react-i18next';
|
|
5
|
+
import { Flexbox } from 'react-layout-kit';
|
|
6
|
+
|
|
7
|
+
import { PluginRenderProps } from '@/plugins/type';
|
|
8
|
+
|
|
9
|
+
import { WeatherResult } from './type';
|
|
10
|
+
|
|
11
|
+
const useStyles = createStyles(({ css, token }) => ({
|
|
12
|
+
time: css`
|
|
13
|
+
color: ${token.colorTextQuaternary};
|
|
14
|
+
`,
|
|
15
|
+
title: css`
|
|
16
|
+
font-weight: bold;
|
|
17
|
+
`,
|
|
18
|
+
}));
|
|
19
|
+
|
|
20
|
+
const Render = memo<PluginRenderProps<WeatherResult>>(({ content }) => {
|
|
21
|
+
const { t } = useTranslation('plugin');
|
|
22
|
+
|
|
23
|
+
const { styles } = useStyles();
|
|
24
|
+
return (
|
|
25
|
+
<div>
|
|
26
|
+
{content.map((item, index) => (
|
|
27
|
+
<Flexbox gap={8} key={`${item.city}-${index}`}>
|
|
28
|
+
<Flexbox align={'center'} distribution={'space-between'} horizontal>
|
|
29
|
+
<div className={styles.title}>{t('realtimeWeather.title', { city: item.city })}</div>
|
|
30
|
+
<div className={styles.time}>
|
|
31
|
+
{t('realtimeWeather.updateAt')}: {item.reporttime}
|
|
32
|
+
</div>
|
|
33
|
+
</Flexbox>
|
|
34
|
+
<Table
|
|
35
|
+
bordered
|
|
36
|
+
columns={[
|
|
37
|
+
{ dataIndex: 'date', title: t('realtimeWeather.data.date') },
|
|
38
|
+
{ dataIndex: 'week', title: t('realtimeWeather.data.week') },
|
|
39
|
+
{ dataIndex: 'dayweather', title: t('realtimeWeather.data.dayweather') },
|
|
40
|
+
{ dataIndex: 'daytemp_float', title: t('realtimeWeather.data.daytemp_float') },
|
|
41
|
+
{ dataIndex: 'daywind', title: t('realtimeWeather.data.daywind') },
|
|
42
|
+
{ dataIndex: 'nightweather', title: t('realtimeWeather.data.nightweather') },
|
|
43
|
+
{ dataIndex: 'nighttemp_float', title: t('realtimeWeather.data.nighttemp_float') },
|
|
44
|
+
]}
|
|
45
|
+
dataSource={item.casts}
|
|
46
|
+
pagination={false}
|
|
47
|
+
/>
|
|
48
|
+
</Flexbox>
|
|
49
|
+
))}
|
|
50
|
+
</div>
|
|
51
|
+
);
|
|
52
|
+
});
|
|
53
|
+
export default Render;
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { PluginItem } from '@/plugins/type';
|
|
2
|
+
import { WeatherResult } from '@/plugins/weather/type';
|
|
3
|
+
|
|
1
4
|
import runner from './runner';
|
|
2
5
|
|
|
3
6
|
const schema = {
|
|
@@ -15,6 +18,11 @@ const schema = {
|
|
|
15
18
|
},
|
|
16
19
|
};
|
|
17
20
|
|
|
18
|
-
const getWeather = {
|
|
21
|
+
const getWeather: PluginItem<WeatherResult> = {
|
|
22
|
+
avatar: '☂️',
|
|
23
|
+
name: 'realtimeWeather',
|
|
24
|
+
runner,
|
|
25
|
+
schema,
|
|
26
|
+
};
|
|
19
27
|
|
|
20
28
|
export default getWeather;
|
|
@@ -1,30 +1,35 @@
|
|
|
1
|
+
import { PluginRunner } from '@/plugins/type';
|
|
2
|
+
|
|
3
|
+
import { Response, WeatherParams, WeatherResult } from './type';
|
|
4
|
+
|
|
1
5
|
const weatherBaseURL = 'https://restapi.amap.com/v3/weather/weatherInfo';
|
|
2
6
|
|
|
3
7
|
const citySearchURL = 'https://restapi.amap.com/v3/config/district';
|
|
4
8
|
|
|
5
9
|
const KEY = process.env.GAODE_WEATHER_KEY;
|
|
6
10
|
|
|
7
|
-
interface WeatherParams {
|
|
8
|
-
city: string;
|
|
9
|
-
extensions?: 'base' | 'all';
|
|
10
|
-
}
|
|
11
|
-
|
|
12
11
|
const fetchCityCode = async (keywords: string): Promise<string> => {
|
|
13
12
|
const URL = `${citySearchURL}?keywords=${keywords}&subdistrict=0&extensions=base&key=${KEY}`;
|
|
14
13
|
const res = await fetch(URL);
|
|
15
14
|
|
|
16
15
|
const data = await res.json();
|
|
16
|
+
console.log(data);
|
|
17
17
|
|
|
18
18
|
return data.districts[0].adcode;
|
|
19
19
|
};
|
|
20
20
|
|
|
21
|
-
const fetchWeather
|
|
21
|
+
const fetchWeather: PluginRunner<WeatherParams, WeatherResult> = async ({
|
|
22
|
+
city,
|
|
23
|
+
extensions = 'all',
|
|
24
|
+
}) => {
|
|
22
25
|
const cityCode = await fetchCityCode(city);
|
|
23
26
|
|
|
24
27
|
const URL = `${weatherBaseURL}?city=${cityCode}&extensions=${extensions}&key=${KEY}`;
|
|
25
28
|
const res = await fetch(URL);
|
|
26
29
|
|
|
27
|
-
|
|
30
|
+
const data: Response = await res.json();
|
|
31
|
+
|
|
32
|
+
return data.forecasts;
|
|
28
33
|
};
|
|
29
34
|
|
|
30
35
|
export default fetchWeather;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export interface WeatherParams {
|
|
2
|
+
city: string;
|
|
3
|
+
extensions?: 'base' | 'all';
|
|
4
|
+
}
|
|
5
|
+
export type WeatherResult = Forecast[];
|
|
6
|
+
|
|
7
|
+
export interface Response {
|
|
8
|
+
count: string;
|
|
9
|
+
forecasts: Forecast[];
|
|
10
|
+
info: string;
|
|
11
|
+
infocode: string;
|
|
12
|
+
status: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface Forecast {
|
|
16
|
+
adcode: string;
|
|
17
|
+
casts: Cast[];
|
|
18
|
+
city: string;
|
|
19
|
+
province: string;
|
|
20
|
+
reporttime: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface Cast {
|
|
24
|
+
date: string;
|
|
25
|
+
daypower: string;
|
|
26
|
+
daytemp: string;
|
|
27
|
+
daytemp_float: string;
|
|
28
|
+
dayweather: string;
|
|
29
|
+
daywind: string;
|
|
30
|
+
nightpower: string;
|
|
31
|
+
nighttemp: string;
|
|
32
|
+
nighttemp_float: string;
|
|
33
|
+
nightweather: string;
|
|
34
|
+
nightwind: string;
|
|
35
|
+
week: string;
|
|
36
|
+
}
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
+
import { PluginItem } from '@/plugins/type';
|
|
2
|
+
|
|
1
3
|
import runner from './runner';
|
|
4
|
+
import { Result } from './type';
|
|
2
5
|
|
|
3
6
|
const schema = {
|
|
4
7
|
description: '提取网页内容并总结',
|
|
@@ -15,6 +18,6 @@ const schema = {
|
|
|
15
18
|
},
|
|
16
19
|
};
|
|
17
20
|
|
|
18
|
-
const getWeather = { avatar: '🕸', name: 'websiteCrawler', runner, schema };
|
|
21
|
+
const getWeather: PluginItem<Result> = { avatar: '🕸', name: 'websiteCrawler', runner, schema };
|
|
19
22
|
|
|
20
23
|
export default getWeather;
|
|
@@ -1,36 +1,12 @@
|
|
|
1
|
-
|
|
1
|
+
import { PluginRunner } from '@/plugins/type';
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
crawl: Crawl;
|
|
5
|
-
markdown: string;
|
|
6
|
-
metadata: Metadata;
|
|
7
|
-
screenshotUrl: any;
|
|
8
|
-
text: string;
|
|
9
|
-
url: string;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export interface Crawl {
|
|
13
|
-
depth: number;
|
|
14
|
-
httpStatusCode: number;
|
|
15
|
-
loadedTime: string;
|
|
16
|
-
loadedUrl: string;
|
|
17
|
-
referrerUrl: string;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export interface Metadata {
|
|
21
|
-
author: any;
|
|
22
|
-
canonicalUrl: string;
|
|
23
|
-
description: string;
|
|
24
|
-
keywords: string;
|
|
25
|
-
languageCode: string;
|
|
26
|
-
title: string;
|
|
27
|
-
}
|
|
3
|
+
import { DataResults, Result } from './type';
|
|
28
4
|
|
|
29
5
|
const BASE_URL =
|
|
30
6
|
'https://api.apify.com/v2/acts/apify~website-content-crawler/run-sync-get-dataset-items';
|
|
31
7
|
const token = process.env.APIFY_API_KEY;
|
|
32
8
|
|
|
33
|
-
const runner
|
|
9
|
+
const runner: PluginRunner<{ url: string }, Result> = async ({ url }) => {
|
|
34
10
|
// Prepare Actor input
|
|
35
11
|
const input = {
|
|
36
12
|
aggressivePrune: false,
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export type DataResults = DataItem[];
|
|
2
|
+
|
|
3
|
+
export type Result = {
|
|
4
|
+
content?: string;
|
|
5
|
+
title?: string;
|
|
6
|
+
url?: string;
|
|
7
|
+
};
|
|
8
|
+
export interface DataItem {
|
|
9
|
+
crawl: Crawl;
|
|
10
|
+
markdown: string;
|
|
11
|
+
metadata: Metadata;
|
|
12
|
+
screenshotUrl: any;
|
|
13
|
+
text: string;
|
|
14
|
+
url: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface Crawl {
|
|
18
|
+
depth: number;
|
|
19
|
+
httpStatusCode: number;
|
|
20
|
+
loadedTime: string;
|
|
21
|
+
loadedUrl: string;
|
|
22
|
+
referrerUrl: string;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface Metadata {
|
|
26
|
+
author: any;
|
|
27
|
+
canonicalUrl: string;
|
|
28
|
+
description: string;
|
|
29
|
+
keywords: string;
|
|
30
|
+
languageCode: string;
|
|
31
|
+
title: string;
|
|
32
|
+
}
|
|
@@ -9,7 +9,6 @@ import { URLS } from './url';
|
|
|
9
9
|
|
|
10
10
|
interface FetchChatModelOptions {
|
|
11
11
|
signal?: AbortSignal | undefined;
|
|
12
|
-
withPlugin?: boolean;
|
|
13
12
|
}
|
|
14
13
|
|
|
15
14
|
/**
|
|
@@ -28,7 +27,7 @@ export const fetchChatModel = (
|
|
|
28
27
|
params,
|
|
29
28
|
);
|
|
30
29
|
|
|
31
|
-
return fetch(
|
|
30
|
+
return fetch(URLS.openai, {
|
|
32
31
|
body: JSON.stringify(payload),
|
|
33
32
|
headers: {
|
|
34
33
|
'Content-Type': 'application/json',
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { LOBE_CHAT_ACCESS_CODE } from '@/const/fetch';
|
|
2
|
+
import { useSettings } from '@/store/settings';
|
|
3
|
+
import { OpenAIPluginPayload } from '@/types/plugin';
|
|
4
|
+
|
|
5
|
+
import { URLS } from './url';
|
|
6
|
+
|
|
7
|
+
interface FetchChatModelOptions {
|
|
8
|
+
signal?: AbortSignal | undefined;
|
|
9
|
+
withPlugin?: boolean;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* 专门用于对话的 fetch
|
|
14
|
+
*/
|
|
15
|
+
export const fetchPlugin = async (
|
|
16
|
+
params: Partial<OpenAIPluginPayload>,
|
|
17
|
+
options?: FetchChatModelOptions,
|
|
18
|
+
) => {
|
|
19
|
+
const res = await fetch(URLS.plugins, {
|
|
20
|
+
body: JSON.stringify(params),
|
|
21
|
+
headers: {
|
|
22
|
+
'Content-Type': 'application/json',
|
|
23
|
+
[LOBE_CHAT_ACCESS_CODE]: useSettings.getState().settings.password || '',
|
|
24
|
+
},
|
|
25
|
+
method: 'POST',
|
|
26
|
+
signal: options?.signal,
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
return await res.text();
|
|
30
|
+
};
|