@lobehub/chat 1.66.6 → 1.67.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 +25 -0
- package/changelog/v1.json +9 -0
- package/locales/ar/models.json +9 -3
- package/locales/ar/plugin.json +12 -0
- package/locales/bg-BG/models.json +9 -3
- package/locales/bg-BG/plugin.json +12 -0
- package/locales/de-DE/models.json +9 -3
- package/locales/de-DE/plugin.json +12 -0
- package/locales/en-US/models.json +9 -3
- package/locales/en-US/plugin.json +12 -0
- package/locales/es-ES/models.json +9 -3
- package/locales/es-ES/plugin.json +12 -0
- package/locales/fa-IR/models.json +9 -3
- package/locales/fa-IR/plugin.json +12 -0
- package/locales/fr-FR/models.json +9 -3
- package/locales/fr-FR/plugin.json +12 -0
- package/locales/it-IT/models.json +9 -3
- package/locales/it-IT/plugin.json +12 -0
- package/locales/ja-JP/models.json +9 -3
- package/locales/ja-JP/plugin.json +12 -0
- package/locales/ko-KR/models.json +9 -3
- package/locales/ko-KR/plugin.json +12 -0
- package/locales/nl-NL/models.json +9 -3
- package/locales/nl-NL/plugin.json +12 -0
- package/locales/pl-PL/models.json +9 -3
- package/locales/pl-PL/plugin.json +12 -0
- package/locales/pt-BR/models.json +9 -3
- package/locales/pt-BR/plugin.json +12 -0
- package/locales/ru-RU/models.json +9 -3
- package/locales/ru-RU/plugin.json +12 -0
- package/locales/tr-TR/models.json +9 -3
- package/locales/tr-TR/plugin.json +12 -0
- package/locales/vi-VN/models.json +9 -3
- package/locales/vi-VN/plugin.json +12 -0
- package/locales/zh-CN/models.json +9 -3
- package/locales/zh-CN/plugin.json +12 -0
- package/locales/zh-TW/models.json +9 -3
- package/locales/zh-TW/plugin.json +12 -0
- package/package.json +5 -1
- package/packages/web-crawler/README.md +34 -0
- package/packages/web-crawler/package.json +13 -0
- package/packages/web-crawler/src/crawImpl/browserless.ts +62 -0
- package/packages/web-crawler/src/crawImpl/index.ts +11 -0
- package/packages/web-crawler/src/crawImpl/jina.ts +37 -0
- package/packages/web-crawler/src/crawImpl/naive.ts +84 -0
- package/packages/web-crawler/src/crawler.ts +66 -0
- package/packages/web-crawler/src/index.ts +2 -0
- package/packages/web-crawler/src/type.ts +42 -0
- package/packages/web-crawler/src/urlRules.ts +34 -0
- package/packages/web-crawler/src/utils/__snapshots__/htmlToMarkdown.test.ts.snap +638 -0
- package/packages/web-crawler/src/utils/appUrlRules.test.ts +26 -0
- package/packages/web-crawler/src/utils/appUrlRules.ts +40 -0
- package/packages/web-crawler/src/utils/errorType.ts +12 -0
- package/packages/web-crawler/src/utils/html/terms.html +1222 -0
- package/packages/web-crawler/src/utils/html/yingchao.html +1001 -0
- package/packages/web-crawler/src/utils/htmlToMarkdown.test.ts +35 -0
- package/packages/web-crawler/src/utils/htmlToMarkdown.ts +45 -0
- package/packages/web-crawler/tsconfig.json +20 -0
- package/pnpm-workspace.yaml +3 -0
- package/src/features/Conversation/Messages/Assistant/Tool/Render/CustomRender.tsx +4 -35
- package/src/features/Conversation/Messages/Assistant/Tool/Render/index.tsx +1 -1
- package/src/features/PluginsUI/Render/BuiltinType/index.tsx +3 -0
- package/src/features/PluginsUI/Render/index.tsx +1 -0
- package/src/features/Portal/Plugins/Body/ToolRender.tsx +1 -0
- package/src/locales/default/plugin.ts +12 -0
- package/src/server/routers/tools/search.ts +23 -0
- package/src/services/search.ts +8 -0
- package/src/store/chat/slices/builtinTool/actions/searXNG.ts +50 -0
- package/src/store/chat/slices/builtinTool/initialState.ts +1 -0
- package/src/tools/web-browsing/Portal/PageContent/index.tsx +190 -0
- package/src/tools/web-browsing/Portal/PageContents/index.tsx +23 -0
- package/src/tools/web-browsing/Portal/{ResultList → Search/ResultList}/SearchItem/Video.tsx +1 -1
- package/src/tools/web-browsing/Portal/Search/index.tsx +69 -0
- package/src/tools/web-browsing/Portal/index.tsx +28 -64
- package/src/tools/web-browsing/Render/PageContent/Loading.tsx +57 -0
- package/src/tools/web-browsing/Render/PageContent/Result.tsx +142 -0
- package/src/tools/web-browsing/Render/PageContent/index.tsx +41 -0
- package/src/tools/web-browsing/Render/{SearchQuery → Search/SearchQuery}/SearchView.tsx +1 -1
- package/src/tools/web-browsing/Render/{SearchQuery → Search/SearchQuery}/index.tsx +1 -1
- package/src/tools/web-browsing/Render/{SearchResult → Search/SearchResult}/ShowMore.tsx +1 -1
- package/src/tools/web-browsing/Render/Search/index.tsx +62 -0
- package/src/tools/web-browsing/Render/index.tsx +35 -44
- package/src/tools/web-browsing/index.ts +43 -47
- package/src/tools/web-browsing/systemRole.ts +109 -0
- package/src/types/tool/builtin.ts +2 -0
- package/src/types/tool/crawler.ts +19 -0
- package/src/types/tool/search.ts +1 -0
- /package/src/tools/web-browsing/Portal/{Footer.tsx → Search/Footer.tsx} +0 -0
- /package/src/tools/web-browsing/Portal/{ResultList → Search/ResultList}/SearchItem/CategoryAvatar.tsx +0 -0
- /package/src/tools/web-browsing/Portal/{ResultList → Search/ResultList}/SearchItem/TitleExtra.tsx +0 -0
- /package/src/tools/web-browsing/Portal/{ResultList → Search/ResultList}/SearchItem/index.tsx +0 -0
- /package/src/tools/web-browsing/Portal/{ResultList → Search/ResultList}/index.tsx +0 -0
- /package/src/tools/web-browsing/Render/{ConfigForm → Search/ConfigForm}/Form.tsx +0 -0
- /package/src/tools/web-browsing/Render/{ConfigForm → Search/ConfigForm}/SearchXNGIcon.tsx +0 -0
- /package/src/tools/web-browsing/Render/{ConfigForm → Search/ConfigForm}/index.tsx +0 -0
- /package/src/tools/web-browsing/Render/{ConfigForm → Search/ConfigForm}/style.tsx +0 -0
- /package/src/tools/web-browsing/Render/{SearchResult → Search/SearchResult}/SearchResultItem.tsx +0 -0
- /package/src/tools/web-browsing/Render/{SearchResult → Search/SearchResult}/index.tsx +0 -0
@@ -1,77 +1,41 @@
|
|
1
|
-
import { Skeleton } from 'antd';
|
2
|
-
import { uniq } from 'lodash-es';
|
3
1
|
import { memo } from 'react';
|
4
|
-
import { Flexbox } from 'react-layout-kit';
|
5
2
|
|
6
|
-
import {
|
7
|
-
import {
|
8
|
-
import {
|
3
|
+
import { WebBrowsingApiName } from '@/tools/web-browsing';
|
4
|
+
import { BuiltinPortalProps } from '@/types/tool';
|
5
|
+
import { CrawlPluginState } from '@/types/tool/crawler';
|
6
|
+
import { SearchQuery } from '@/types/tool/search';
|
9
7
|
|
10
|
-
import
|
11
|
-
import
|
12
|
-
import
|
8
|
+
import PageContent from './PageContent';
|
9
|
+
import PageContents from './PageContents';
|
10
|
+
import Search from './Search';
|
13
11
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
}
|
12
|
+
const Inspector = memo<BuiltinPortalProps>(({ arguments: args, messageId, state, apiName }) => {
|
13
|
+
switch (apiName) {
|
14
|
+
case WebBrowsingApiName.searchWithSearXNG: {
|
15
|
+
return <Search messageId={messageId} query={args as SearchQuery} response={state} />;
|
16
|
+
}
|
18
17
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
}
|
18
|
+
case WebBrowsingApiName.crawlSinglePage: {
|
19
|
+
const url = args.url;
|
20
|
+
const result = (state as CrawlPluginState).results.find(
|
21
|
+
(result) => result.originalUrl === url,
|
22
|
+
);
|
25
23
|
|
26
|
-
|
27
|
-
|
28
|
-
const engines = uniq((state.results || []).map((result) => result.engine));
|
29
|
-
const defaultEngines = engines.length > 0 ? engines : args.searchEngine || [];
|
30
|
-
const loading = useChatStore(chatToolSelectors.isSearXNGSearching(messageId));
|
24
|
+
return <PageContent messageId={messageId} result={result} />;
|
25
|
+
}
|
31
26
|
|
32
|
-
|
27
|
+
case WebBrowsingApiName.crawlMultiPages: {
|
33
28
|
return (
|
34
|
-
<
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
messageId={messageId}
|
40
|
-
tooltip={false}
|
41
|
-
/>
|
42
|
-
|
43
|
-
<Flexbox gap={16} paddingBlock={16} paddingInline={12}>
|
44
|
-
{[1, 2, 3, 4, 6].map((id) => (
|
45
|
-
<Skeleton
|
46
|
-
active
|
47
|
-
key={id}
|
48
|
-
paragraph={{ rows: 3, width: `${(id % 4) + 5}0%` }}
|
49
|
-
title={false}
|
50
|
-
/>
|
51
|
-
))}
|
52
|
-
</Flexbox>
|
53
|
-
</Flexbox>
|
29
|
+
<PageContents
|
30
|
+
messageId={messageId}
|
31
|
+
results={(state as CrawlPluginState).results}
|
32
|
+
urls={args.urls}
|
33
|
+
/>
|
54
34
|
);
|
55
35
|
}
|
36
|
+
}
|
56
37
|
|
57
|
-
|
58
|
-
|
59
|
-
<Flexbox gap={12} height={'100%'}>
|
60
|
-
<SearchBar
|
61
|
-
aiSummary={false}
|
62
|
-
defaultEngines={defaultEngines}
|
63
|
-
defaultQuery={args.query}
|
64
|
-
messageId={messageId}
|
65
|
-
tooltip={false}
|
66
|
-
/>
|
67
|
-
<Flexbox height={'100%'} width={'100%'}>
|
68
|
-
<ResultList dataSources={state.results} />
|
69
|
-
</Flexbox>
|
70
|
-
</Flexbox>
|
71
|
-
<Footer />
|
72
|
-
</Flexbox>
|
73
|
-
);
|
74
|
-
},
|
75
|
-
);
|
38
|
+
return null;
|
39
|
+
});
|
76
40
|
|
77
41
|
export default Inspector;
|
@@ -0,0 +1,57 @@
|
|
1
|
+
'use client';
|
2
|
+
|
3
|
+
import { CopyButton } from '@lobehub/ui';
|
4
|
+
import { createStyles } from 'antd-style';
|
5
|
+
import Link from 'next/link';
|
6
|
+
import { memo } from 'react';
|
7
|
+
import { useTranslation } from 'react-i18next';
|
8
|
+
import { Flexbox } from 'react-layout-kit';
|
9
|
+
|
10
|
+
import { shinyTextStylish } from '@/styles/loading';
|
11
|
+
|
12
|
+
const useStyles = createStyles(({ token, css }) => {
|
13
|
+
return {
|
14
|
+
cardBody: css`
|
15
|
+
padding-block: 12px 8px;
|
16
|
+
padding-inline: 12px;
|
17
|
+
`,
|
18
|
+
container: css`
|
19
|
+
overflow: hidden;
|
20
|
+
justify-content: space-between;
|
21
|
+
|
22
|
+
max-width: 360px;
|
23
|
+
border: 1px solid ${token.colorBorderSecondary};
|
24
|
+
border-radius: 12px;
|
25
|
+
`,
|
26
|
+
|
27
|
+
footer: css`
|
28
|
+
padding-block: 8px;
|
29
|
+
padding-inline: 12px;
|
30
|
+
|
31
|
+
font-size: ${token.fontSizeSM}px;
|
32
|
+
color: ${token.colorTextTertiary};
|
33
|
+
|
34
|
+
background-color: ${token.colorFillQuaternary};
|
35
|
+
`,
|
36
|
+
shining: shinyTextStylish(token),
|
37
|
+
};
|
38
|
+
});
|
39
|
+
|
40
|
+
const LoadingCard = memo<{ url: string }>(({ url }) => {
|
41
|
+
const { t } = useTranslation('plugin');
|
42
|
+
const { styles } = useStyles();
|
43
|
+
|
44
|
+
return (
|
45
|
+
<Flexbox className={styles.container}>
|
46
|
+
<Flexbox className={styles.cardBody} horizontal>
|
47
|
+
<Link href={url} rel={'nofollow'} target={'_blank'}>
|
48
|
+
<div className={styles.shining}>{url}</div>
|
49
|
+
</Link>
|
50
|
+
<CopyButton content={url} size={'small'} />
|
51
|
+
</Flexbox>
|
52
|
+
<div className={styles.footer}>{t('search.crawPages.crawling')}</div>
|
53
|
+
</Flexbox>
|
54
|
+
);
|
55
|
+
});
|
56
|
+
|
57
|
+
export default LoadingCard;
|
@@ -0,0 +1,142 @@
|
|
1
|
+
'use client';
|
2
|
+
|
3
|
+
import { CrawlSuccessResult } from '@lobechat/web-crawler';
|
4
|
+
import { Icon } from '@lobehub/ui';
|
5
|
+
import { Descriptions, Typography } from 'antd';
|
6
|
+
import { createStyles } from 'antd-style';
|
7
|
+
import { ExternalLink } from 'lucide-react';
|
8
|
+
import Link from 'next/link';
|
9
|
+
import { memo } from 'react';
|
10
|
+
import { useTranslation } from 'react-i18next';
|
11
|
+
import { Center, Flexbox } from 'react-layout-kit';
|
12
|
+
|
13
|
+
import { useChatStore } from '@/store/chat';
|
14
|
+
import { WebBrowsingManifest } from '@/tools/web-browsing';
|
15
|
+
|
16
|
+
const { Paragraph } = Typography;
|
17
|
+
|
18
|
+
const useStyles = createStyles(({ token, css }) => {
|
19
|
+
return {
|
20
|
+
cardBody: css`
|
21
|
+
padding-block: 12px 8px;
|
22
|
+
padding-inline: 16px;
|
23
|
+
`,
|
24
|
+
container: css`
|
25
|
+
cursor: pointer;
|
26
|
+
|
27
|
+
overflow: hidden;
|
28
|
+
|
29
|
+
max-width: 360px;
|
30
|
+
border: 1px solid ${token.colorBorderSecondary};
|
31
|
+
border-radius: 12px;
|
32
|
+
|
33
|
+
transition: border-color 0.2s;
|
34
|
+
|
35
|
+
:hover {
|
36
|
+
border-color: ${token.colorPrimary};
|
37
|
+
}
|
38
|
+
`,
|
39
|
+
description: css`
|
40
|
+
margin-block: 0 4px !important;
|
41
|
+
color: ${token.colorTextTertiary};
|
42
|
+
`,
|
43
|
+
detailsSection: css`
|
44
|
+
padding-block: ${token.paddingSM}px;
|
45
|
+
`,
|
46
|
+
externalLink: css`
|
47
|
+
color: ${token.colorTextQuaternary};
|
48
|
+
|
49
|
+
:hover {
|
50
|
+
color: ${token.colorText};
|
51
|
+
}
|
52
|
+
`,
|
53
|
+
footer: css`
|
54
|
+
padding: ${token.paddingXS}px;
|
55
|
+
text-align: center;
|
56
|
+
background-color: ${token.colorFillQuaternary};
|
57
|
+
`,
|
58
|
+
footerText: css`
|
59
|
+
font-size: ${token.fontSizeSM}px;
|
60
|
+
color: ${token.colorTextTertiary} !important;
|
61
|
+
`,
|
62
|
+
metaInfo: css`
|
63
|
+
display: flex;
|
64
|
+
align-items: center;
|
65
|
+
color: ${token.colorTextSecondary};
|
66
|
+
`,
|
67
|
+
title: css`
|
68
|
+
overflow: hidden;
|
69
|
+
display: -webkit-box;
|
70
|
+
-webkit-box-orient: vertical;
|
71
|
+
-webkit-line-clamp: 1;
|
72
|
+
|
73
|
+
margin-block-end: 0;
|
74
|
+
`,
|
75
|
+
titleRow: css`
|
76
|
+
color: ${token.colorText};
|
77
|
+
`,
|
78
|
+
};
|
79
|
+
});
|
80
|
+
|
81
|
+
interface CrawlerData {
|
82
|
+
crawler: string;
|
83
|
+
messageId: string;
|
84
|
+
originalUrl: string;
|
85
|
+
result: CrawlSuccessResult;
|
86
|
+
}
|
87
|
+
|
88
|
+
const CrawlerResultCard = memo<CrawlerData>(({ result, messageId, crawler, originalUrl }) => {
|
89
|
+
const { t } = useTranslation('plugin');
|
90
|
+
const { styles } = useStyles();
|
91
|
+
const [openToolUI, togglePageContent] = useChatStore((s) => [s.openToolUI, s.togglePageContent]);
|
92
|
+
|
93
|
+
const { url, title, description } = result;
|
94
|
+
|
95
|
+
return (
|
96
|
+
<Flexbox
|
97
|
+
className={styles.container}
|
98
|
+
justify={'space-between'}
|
99
|
+
onClick={() => {
|
100
|
+
openToolUI(messageId, WebBrowsingManifest.identifier);
|
101
|
+
togglePageContent(originalUrl);
|
102
|
+
}}
|
103
|
+
>
|
104
|
+
<Flexbox className={styles.cardBody} gap={8}>
|
105
|
+
<Flexbox align={'center'} className={styles.titleRow} horizontal justify={'space-between'}>
|
106
|
+
<Flexbox>
|
107
|
+
<div className={styles.title}>{title || originalUrl}</div>
|
108
|
+
</Flexbox>
|
109
|
+
<Link href={url} onClick={(e) => e.stopPropagation()} target={'_blank'}>
|
110
|
+
<Center className={styles.externalLink}>
|
111
|
+
<Icon icon={ExternalLink} />
|
112
|
+
</Center>
|
113
|
+
</Link>
|
114
|
+
</Flexbox>
|
115
|
+
<Paragraph className={styles.description} ellipsis={{ expandable: false, rows: 2 }}>
|
116
|
+
{description || result.content?.slice(0, 40)}
|
117
|
+
</Paragraph>
|
118
|
+
</Flexbox>
|
119
|
+
<div className={styles.footer}>
|
120
|
+
<Descriptions
|
121
|
+
classNames={{
|
122
|
+
content: styles.footerText,
|
123
|
+
}}
|
124
|
+
column={2}
|
125
|
+
items={[
|
126
|
+
{
|
127
|
+
children: result.content?.length,
|
128
|
+
label: t('search.crawPages.meta.words'),
|
129
|
+
},
|
130
|
+
{
|
131
|
+
children: crawler,
|
132
|
+
label: t('search.crawPages.meta.crawler'),
|
133
|
+
},
|
134
|
+
]}
|
135
|
+
size="small"
|
136
|
+
/>
|
137
|
+
</div>
|
138
|
+
</Flexbox>
|
139
|
+
);
|
140
|
+
});
|
141
|
+
|
142
|
+
export default CrawlerResultCard;
|
@@ -0,0 +1,41 @@
|
|
1
|
+
import { memo } from 'react';
|
2
|
+
import { Flexbox } from 'react-layout-kit';
|
3
|
+
|
4
|
+
import { CrawlPluginState } from '@/types/tool/crawler';
|
5
|
+
|
6
|
+
import Loading from './Loading';
|
7
|
+
import Result from './Result';
|
8
|
+
|
9
|
+
interface PagesContentProps {
|
10
|
+
messageId: string;
|
11
|
+
results?: CrawlPluginState['results'];
|
12
|
+
urls: string[];
|
13
|
+
}
|
14
|
+
|
15
|
+
const PagesContent = memo<PagesContentProps>(({ results, messageId, urls }) => {
|
16
|
+
if (!results || results.length === 0) {
|
17
|
+
return (
|
18
|
+
<Flexbox gap={12} horizontal>
|
19
|
+
{urls.map((url) => (
|
20
|
+
<Loading key={url} url={url} />
|
21
|
+
))}
|
22
|
+
</Flexbox>
|
23
|
+
);
|
24
|
+
}
|
25
|
+
|
26
|
+
return (
|
27
|
+
<Flexbox gap={12} horizontal>
|
28
|
+
{results.map((result) => (
|
29
|
+
<Result
|
30
|
+
crawler={result.crawler}
|
31
|
+
key={result.originalUrl}
|
32
|
+
messageId={messageId}
|
33
|
+
originalUrl={result.originalUrl}
|
34
|
+
result={result.data}
|
35
|
+
/>
|
36
|
+
))}
|
37
|
+
</Flexbox>
|
38
|
+
);
|
39
|
+
});
|
40
|
+
|
41
|
+
export default PagesContent;
|
@@ -8,7 +8,7 @@ import { Flexbox } from 'react-layout-kit';
|
|
8
8
|
|
9
9
|
import { useIsMobile } from '@/hooks/useIsMobile';
|
10
10
|
|
11
|
-
import { EngineAvatarGroup } from '
|
11
|
+
import { EngineAvatarGroup } from '../../../components/EngineAvatar';
|
12
12
|
|
13
13
|
const useStyles = createStyles(({ css, token }) => ({
|
14
14
|
font: css`
|
@@ -10,7 +10,7 @@ import { useChatStore } from '@/store/chat';
|
|
10
10
|
import { chatToolSelectors } from '@/store/chat/selectors';
|
11
11
|
import { SearchQuery, SearchResponse } from '@/types/tool/search';
|
12
12
|
|
13
|
-
import SearchBar from '
|
13
|
+
import SearchBar from '../../../components/SearchBar';
|
14
14
|
import SearchView from './SearchView';
|
15
15
|
|
16
16
|
interface SearchQueryViewProps {
|
@@ -6,7 +6,7 @@ import { Flexbox } from 'react-layout-kit';
|
|
6
6
|
import { useChatStore } from '@/store/chat';
|
7
7
|
import { WebBrowsingManifest } from '@/tools/web-browsing';
|
8
8
|
|
9
|
-
import { EngineAvatarGroup } from '
|
9
|
+
import { EngineAvatarGroup } from '../../../components/EngineAvatar';
|
10
10
|
|
11
11
|
const useStyles = createStyles(({ css, token }) => ({
|
12
12
|
container: css`
|
@@ -0,0 +1,62 @@
|
|
1
|
+
import { Alert, Highlighter } from '@lobehub/ui';
|
2
|
+
import { memo, useState } from 'react';
|
3
|
+
import { Flexbox } from 'react-layout-kit';
|
4
|
+
|
5
|
+
import { ChatMessagePluginError } from '@/types/message';
|
6
|
+
import { SearchQuery, SearchResponse } from '@/types/tool/search';
|
7
|
+
|
8
|
+
import ConfigForm from './ConfigForm';
|
9
|
+
import SearchQueryView from './SearchQuery';
|
10
|
+
import SearchResult from './SearchResult';
|
11
|
+
|
12
|
+
interface SearchProps {
|
13
|
+
messageId: string;
|
14
|
+
pluginError: ChatMessagePluginError;
|
15
|
+
searchQuery: SearchQuery;
|
16
|
+
searchResponse?: SearchResponse;
|
17
|
+
}
|
18
|
+
|
19
|
+
const Search = memo<SearchProps>(({ messageId, searchQuery, searchResponse, pluginError }) => {
|
20
|
+
const [editing, setEditing] = useState(false);
|
21
|
+
|
22
|
+
if (pluginError) {
|
23
|
+
if (pluginError?.type === 'PluginSettingsInvalid') {
|
24
|
+
return <ConfigForm id={messageId} provider={pluginError.body?.provider} />;
|
25
|
+
}
|
26
|
+
|
27
|
+
return (
|
28
|
+
<Alert
|
29
|
+
extra={
|
30
|
+
<Flexbox>
|
31
|
+
<Highlighter copyButtonSize={'small'} language={'json'} type={'pure'}>
|
32
|
+
{JSON.stringify(pluginError.body?.data || pluginError.body, null, 2)}
|
33
|
+
</Highlighter>
|
34
|
+
</Flexbox>
|
35
|
+
}
|
36
|
+
message={pluginError?.message}
|
37
|
+
type={'error'}
|
38
|
+
/>
|
39
|
+
);
|
40
|
+
}
|
41
|
+
|
42
|
+
return (
|
43
|
+
<Flexbox gap={8}>
|
44
|
+
<SearchQueryView
|
45
|
+
args={searchQuery}
|
46
|
+
editing={editing}
|
47
|
+
messageId={messageId}
|
48
|
+
pluginState={searchResponse}
|
49
|
+
setEditing={setEditing}
|
50
|
+
/>
|
51
|
+
<SearchResult
|
52
|
+
args={searchQuery}
|
53
|
+
editing={editing}
|
54
|
+
messageId={messageId}
|
55
|
+
pluginState={searchResponse}
|
56
|
+
setEditing={setEditing}
|
57
|
+
/>
|
58
|
+
</Flexbox>
|
59
|
+
);
|
60
|
+
});
|
61
|
+
|
62
|
+
export default Search;
|
@@ -1,56 +1,47 @@
|
|
1
|
-
import {
|
2
|
-
import { memo, useState } from 'react';
|
3
|
-
import { Flexbox } from 'react-layout-kit';
|
1
|
+
import { memo } from 'react';
|
4
2
|
|
3
|
+
import { WebBrowsingApiName } from '@/tools/web-browsing';
|
4
|
+
import PageContent from '@/tools/web-browsing/Render/PageContent';
|
5
5
|
import { BuiltinRenderProps } from '@/types/tool';
|
6
|
+
import { CrawlMultiPagesQuery, CrawlPluginState, CrawlSinglePageQuery } from '@/types/tool/crawler';
|
6
7
|
import { SearchContent, SearchQuery, SearchResponse } from '@/types/tool/search';
|
7
8
|
|
8
|
-
import
|
9
|
-
import SearchQueryView from './SearchQuery';
|
10
|
-
import SearchResult from './SearchResult';
|
9
|
+
import Search from './Search';
|
11
10
|
|
12
|
-
const WebBrowsing = memo<BuiltinRenderProps<SearchContent[]
|
13
|
-
({ messageId, args, pluginState, pluginError }) => {
|
14
|
-
|
11
|
+
const WebBrowsing = memo<BuiltinRenderProps<SearchContent[]>>(
|
12
|
+
({ messageId, args, pluginState, pluginError, apiName }) => {
|
13
|
+
switch (apiName) {
|
14
|
+
case WebBrowsingApiName.searchWithSearXNG: {
|
15
|
+
return (
|
16
|
+
<Search
|
17
|
+
messageId={messageId}
|
18
|
+
pluginError={pluginError}
|
19
|
+
searchQuery={args as SearchQuery}
|
20
|
+
searchResponse={pluginState as SearchResponse}
|
21
|
+
/>
|
22
|
+
);
|
23
|
+
}
|
15
24
|
|
16
|
-
|
17
|
-
|
18
|
-
|
25
|
+
case WebBrowsingApiName.crawlSinglePage: {
|
26
|
+
return (
|
27
|
+
<PageContent
|
28
|
+
messageId={messageId}
|
29
|
+
results={(pluginState as CrawlPluginState)?.results}
|
30
|
+
urls={[(args as CrawlSinglePageQuery).url]}
|
31
|
+
/>
|
32
|
+
);
|
19
33
|
}
|
20
34
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
message={pluginError?.message}
|
31
|
-
type={'error'}
|
32
|
-
/>
|
33
|
-
);
|
35
|
+
case WebBrowsingApiName.crawlMultiPages: {
|
36
|
+
return (
|
37
|
+
<PageContent
|
38
|
+
messageId={messageId}
|
39
|
+
results={(pluginState as CrawlPluginState)?.results}
|
40
|
+
urls={(args as CrawlMultiPagesQuery).urls}
|
41
|
+
/>
|
42
|
+
);
|
43
|
+
}
|
34
44
|
}
|
35
|
-
|
36
|
-
return (
|
37
|
-
<Flexbox gap={8}>
|
38
|
-
<SearchQueryView
|
39
|
-
args={args}
|
40
|
-
editing={editing}
|
41
|
-
messageId={messageId}
|
42
|
-
pluginState={pluginState}
|
43
|
-
setEditing={setEditing}
|
44
|
-
/>
|
45
|
-
<SearchResult
|
46
|
-
args={args}
|
47
|
-
editing={editing}
|
48
|
-
messageId={messageId}
|
49
|
-
pluginState={pluginState}
|
50
|
-
setEditing={setEditing}
|
51
|
-
/>
|
52
|
-
</Flexbox>
|
53
|
-
);
|
54
45
|
},
|
55
46
|
);
|
56
47
|
|
@@ -2,12 +2,20 @@ import dayjs from 'dayjs';
|
|
2
2
|
|
3
3
|
import { BuiltinToolManifest } from '@/types/tool';
|
4
4
|
|
5
|
+
import { systemPrompt } from './systemRole';
|
6
|
+
|
7
|
+
export const WebBrowsingApiName = {
|
8
|
+
crawlMultiPages: 'crawlMultiPages',
|
9
|
+
crawlSinglePage: 'crawlSinglePage',
|
10
|
+
searchWithSearXNG: 'searchWithSearXNG',
|
11
|
+
};
|
12
|
+
|
5
13
|
export const WebBrowsingManifest: BuiltinToolManifest = {
|
6
14
|
api: [
|
7
15
|
{
|
8
16
|
description:
|
9
17
|
'A meta search engine. Useful for when you need to answer questions about current events. Input should be a search query. Output is a JSON array of the query results',
|
10
|
-
name:
|
18
|
+
name: WebBrowsingApiName.searchWithSearXNG,
|
11
19
|
parameters: {
|
12
20
|
properties: {
|
13
21
|
query: {
|
@@ -46,57 +54,45 @@ export const WebBrowsingManifest: BuiltinToolManifest = {
|
|
46
54
|
type: 'object',
|
47
55
|
},
|
48
56
|
},
|
57
|
+
{
|
58
|
+
description:
|
59
|
+
'A crawler can visit page content. Output is a JSON object of title, content, url and website',
|
60
|
+
name: WebBrowsingApiName.crawlSinglePage,
|
61
|
+
parameters: {
|
62
|
+
properties: {
|
63
|
+
url: {
|
64
|
+
description: 'The url need to be crawled',
|
65
|
+
type: 'string',
|
66
|
+
},
|
67
|
+
},
|
68
|
+
required: ['url'],
|
69
|
+
type: 'object',
|
70
|
+
},
|
71
|
+
},
|
72
|
+
{
|
73
|
+
description:
|
74
|
+
'A crawler can visit multi pages. If need to visit multi website, use this one. Output is an array of JSON object of title, content, url and website',
|
75
|
+
name: WebBrowsingApiName.crawlMultiPages,
|
76
|
+
parameters: {
|
77
|
+
properties: {
|
78
|
+
urls: {
|
79
|
+
items: {
|
80
|
+
description: 'The url need to be crawled',
|
81
|
+
type: 'string',
|
82
|
+
},
|
83
|
+
type: 'array',
|
84
|
+
},
|
85
|
+
},
|
86
|
+
required: ['urls'],
|
87
|
+
type: 'object',
|
88
|
+
},
|
89
|
+
},
|
49
90
|
],
|
50
91
|
identifier: 'lobe-web-browsing',
|
51
92
|
meta: {
|
52
93
|
avatar: '🌐',
|
53
94
|
title: 'Web Browsing',
|
54
95
|
},
|
55
|
-
systemRole:
|
56
|
-
|
57
|
-
SearXNG combine with these engines:
|
58
|
-
- Google: The world's most popular search engine, offering a wide range of general web results.,
|
59
|
-
- Bilibili: A Chinese video sharing website themed around animation, comic, and games (ACG) ,(又名 B 站),
|
60
|
-
- Bing: Microsoft's search engine, providing web results with a focus on visual search.,
|
61
|
-
- DuckDuckGo: A privacy-focused search engine that doesn't track users.,
|
62
|
-
- npm: The package manager for JavaScript, used to find Node.js packages.,
|
63
|
-
- PyPI: The Python Package Index, used to find Python packages.,
|
64
|
-
- GitHub: A platform for version control and collaboration, search for code repositories.,
|
65
|
-
- arXiv: A repository of electronic preprints for scientific papers.,
|
66
|
-
- Google Scholar: A freely accessible web search engine for scholarly literature.,
|
67
|
-
- Z-Library: A shadow library project for file-sharing access to scholarly journal articles and books.,
|
68
|
-
- Reddit: A network of communities based on people's interests, search for discussions and content.,
|
69
|
-
- IMDb: An online database of information related to films, TV programs, and video games.,
|
70
|
-
- Brave: A privacy-focused browser with its own search engine.,
|
71
|
-
- Wikipedia: A free online encyclopedia, search for articles on various topics.,
|
72
|
-
- Pinterest: An image sharing and social media service, search for images and ideas.,
|
73
|
-
- Unsplash: A website dedicated to sharing stock photography, search for high-quality images.,
|
74
|
-
- Vimeo: A video hosting, sharing, and services platform.,
|
75
|
-
- YouTube: A video sharing platform, search for a wide variety of video content.
|
76
|
-
|
77
|
-
SearXNG comes with a search syntax by with you can modify the categories, engines, languages and more.
|
78
|
-
|
79
|
-
## \`!\` select engine and category
|
80
|
-
|
81
|
-
To set category and/or engine names use a \`!\` prefix. To give a few examples:
|
82
|
-
|
83
|
-
- search in category **map** for **paris**
|
84
|
-
- \`!map paris\`
|
85
|
-
- image search
|
86
|
-
- \`!images Wau Holland\`
|
87
|
-
|
88
|
-
Abbreviations of the engines and languages are also accepted. Engine/category modifiers are chain able and inclusive. E.g. with \`!map !ddg !wp paris\` search in map category and DuckDuckGo and Wikipedia for **paris**.
|
89
|
-
|
90
|
-
## \`:\` select language
|
91
|
-
|
92
|
-
To select language filter use a \`:\` prefix. To give an example:
|
93
|
-
|
94
|
-
- search Wikipedia by a custom language
|
95
|
-
- \`:fr !wp Wau Holland\`
|
96
|
-
|
97
|
-
You need to summarize in the language of the user's question. If you use search content in your reply, you must use Markdown footnote format to indicate the source, Such as [^1].
|
98
|
-
|
99
|
-
current date: ${dayjs(new Date()).format('YYYY-MM-DD')}
|
100
|
-
`,
|
96
|
+
systemRole: systemPrompt(dayjs(new Date()).format('YYYY-MM-DD')),
|
101
97
|
type: 'builtin',
|
102
98
|
};
|