@lobehub/chat 1.14.5 → 1.14.7
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/docker-compose/local/.env.example +35 -0
- package/docker-compose/local/.env.zh-CN.example +35 -0
- package/docker-compose/local/docker-compose.yml +64 -0
- package/docker-compose/{.env.example → production/.env.example} +4 -4
- package/docker-compose/{.env.zh-CN.example → production/.env.zh-CN.example} +5 -5
- package/docs/self-hosting/server-database/docker-compose.mdx +136 -10
- package/docs/self-hosting/server-database/docker-compose.zh-CN.mdx +135 -10
- package/locales/ar/portal.json +7 -0
- package/locales/bg-BG/portal.json +7 -0
- package/locales/de-DE/portal.json +7 -0
- package/locales/en-US/components.json +10 -10
- package/locales/en-US/file.json +5 -5
- package/locales/en-US/portal.json +7 -0
- package/locales/en-US/tool.json +1 -1
- package/locales/es-ES/portal.json +7 -0
- package/locales/fr-FR/portal.json +7 -0
- package/locales/it-IT/portal.json +7 -0
- package/locales/ja-JP/portal.json +7 -0
- package/locales/ko-KR/portal.json +7 -0
- package/locales/nl-NL/portal.json +7 -0
- package/locales/pl-PL/portal.json +7 -0
- package/locales/pt-BR/portal.json +7 -0
- package/locales/ru-RU/portal.json +7 -0
- package/locales/tr-TR/portal.json +7 -0
- package/locales/vi-VN/portal.json +7 -0
- package/locales/zh-CN/portal.json +7 -0
- package/locales/zh-TW/portal.json +7 -0
- package/package.json +1 -1
- package/src/app/(main)/chat/(workspace)/@portal/Artifacts/{index.tsx → Body/index.tsx} +1 -1
- package/src/app/(main)/chat/(workspace)/@portal/Artifacts/Header.tsx +35 -0
- package/src/app/(main)/chat/(workspace)/@portal/Artifacts/index.ts +9 -0
- package/src/app/(main)/chat/(workspace)/@portal/Artifacts/useEnable.ts +6 -0
- package/src/app/(main)/chat/(workspace)/@portal/FilePreview/Body/index.tsx +57 -0
- package/src/app/(main)/chat/(workspace)/@portal/FilePreview/Header.tsx +36 -0
- package/src/app/(main)/chat/(workspace)/@portal/FilePreview/index.ts +9 -0
- package/src/app/(main)/chat/(workspace)/@portal/FilePreview/useEnable.ts +6 -0
- package/src/app/(main)/chat/(workspace)/@portal/Home/{Files → Body/Files}/FileList/Item.tsx +7 -7
- package/src/app/(main)/chat/(workspace)/@portal/Home/{Files → Body/Files}/FileList/index.tsx +2 -2
- package/src/app/(main)/chat/(workspace)/@portal/Home/Header.tsx +17 -0
- package/src/app/(main)/chat/(workspace)/@portal/Home/index.ts +2 -0
- package/src/app/(main)/chat/(workspace)/@portal/_layout/Desktop.tsx +1 -1
- package/src/app/(main)/chat/(workspace)/@portal/default.tsx +2 -2
- package/src/app/(main)/chat/(workspace)/@portal/features/Header.tsx +6 -35
- package/src/app/(main)/chat/(workspace)/@portal/router.tsx +36 -12
- package/src/app/(main)/chat/(workspace)/_layout/Desktop/ChatHeader/KnowledgeTag.tsx +5 -3
- package/src/app/(main)/settings/llm/components/ProviderConfig/index.tsx +3 -1
- package/src/components/FileParsingStatus/EmbeddingStatus.tsx +117 -0
- package/src/components/FileParsingStatus/index.tsx +54 -112
- package/src/config/modelProviders/google.ts +29 -1
- package/src/config/modelProviders/openai.ts +0 -1
- package/src/database/server/models/message.ts +8 -2
- package/src/features/Conversation/Messages/Assistant/FileChunks/Item/index.tsx +10 -7
- package/src/features/Conversation/Messages/Assistant/FileChunks/Item/style.ts +13 -0
- package/src/features/Conversation/Messages/User/FileListViewer/Item.tsx +1 -1
- package/src/features/FileManager/FileList/FileListItem/ChunkTag.tsx +14 -7
- package/src/layout/GlobalProvider/Locale.tsx +19 -17
- package/src/locales/default/portal.ts +7 -0
- package/src/server/routers/lambda/agent.ts +3 -1
- package/src/server/routers/lambda/file.ts +19 -0
- package/src/services/file/server.ts +4 -0
- package/src/services/rag.ts +1 -0
- package/src/store/chat/slices/portal/action.ts +9 -4
- package/src/store/chat/slices/portal/initialState.ts +7 -3
- package/src/store/chat/slices/portal/selectors.ts +2 -0
- package/src/store/file/slices/fileManager/action.ts +18 -0
- package/src/styles/index.ts +2 -0
- package/src/styles/text.ts +10 -0
- package/src/types/message/index.ts +2 -0
- package/src/app/(main)/chat/(workspace)/@portal/FilePreview/index.tsx +0 -26
- /package/docker-compose/{docker-compose.yml → production/docker-compose.yml} +0 -0
- /package/src/app/(main)/chat/(workspace)/@portal/Artifacts/{ToolRender.tsx → Body/ToolRender.tsx} +0 -0
- /package/src/app/(main)/chat/(workspace)/@portal/Home/{Artifacts → Body/Artifacts}/ArtifactList/Item/index.tsx +0 -0
- /package/src/app/(main)/chat/(workspace)/@portal/Home/{Artifacts → Body/Artifacts}/ArtifactList/Item/style.ts +0 -0
- /package/src/app/(main)/chat/(workspace)/@portal/Home/{Artifacts → Body/Artifacts}/ArtifactList/index.tsx +0 -0
- /package/src/app/(main)/chat/(workspace)/@portal/Home/{Artifacts → Body/Artifacts}/index.tsx +0 -0
- /package/src/app/(main)/chat/(workspace)/@portal/Home/{Files → Body/Files}/index.tsx +0 -0
- /package/src/app/(main)/chat/(workspace)/@portal/Home/{index.tsx → Body/index.tsx} +0 -0
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { Typography } from 'antd';
|
|
4
|
+
import { memo } from 'react';
|
|
5
|
+
import { useTranslation } from 'react-i18next';
|
|
6
|
+
|
|
7
|
+
const Header = memo(() => {
|
|
8
|
+
const { t } = useTranslation('portal');
|
|
9
|
+
|
|
10
|
+
return (
|
|
11
|
+
<Typography.Text style={{ fontSize: 16 }} type={'secondary'}>
|
|
12
|
+
{t('title')}
|
|
13
|
+
</Typography.Text>
|
|
14
|
+
);
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
export default Header;
|
|
@@ -7,7 +7,7 @@ const Layout = ({ children }: PropsWithChildren) => {
|
|
|
7
7
|
return (
|
|
8
8
|
<>
|
|
9
9
|
<Header />
|
|
10
|
-
<Flexbox height={'100%'} style={{
|
|
10
|
+
<Flexbox height={'100%'} style={{ position: 'relative' }} width={'100%'}>
|
|
11
11
|
{children}
|
|
12
12
|
</Flexbox>
|
|
13
13
|
</>
|
|
@@ -6,7 +6,7 @@ import { isMobileDevice } from '@/utils/responsive';
|
|
|
6
6
|
import Desktop from './_layout/Desktop';
|
|
7
7
|
import Mobile from './_layout/Mobile';
|
|
8
8
|
|
|
9
|
-
const
|
|
9
|
+
const PortalBody = lazy(() => import('./router'));
|
|
10
10
|
|
|
11
11
|
const Inspector = () => {
|
|
12
12
|
const mobile = isMobileDevice();
|
|
@@ -16,7 +16,7 @@ const Inspector = () => {
|
|
|
16
16
|
return (
|
|
17
17
|
<Suspense fallback={<Loading />}>
|
|
18
18
|
<Layout>
|
|
19
|
-
<
|
|
19
|
+
<PortalBody />
|
|
20
20
|
</Layout>
|
|
21
21
|
</Suspense>
|
|
22
22
|
);
|
|
@@ -1,51 +1,22 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
import { ActionIcon } from '@lobehub/ui';
|
|
4
|
-
import {
|
|
5
|
-
import isEqual from 'fast-deep-equal';
|
|
6
|
-
import { ArrowLeft, XIcon } from 'lucide-react';
|
|
4
|
+
import { XIcon } from 'lucide-react';
|
|
7
5
|
import { memo } from 'react';
|
|
8
|
-
import { useTranslation } from 'react-i18next';
|
|
9
|
-
import { Flexbox } from 'react-layout-kit';
|
|
10
6
|
|
|
11
7
|
import SidebarHeader from '@/components/SidebarHeader';
|
|
12
|
-
import PluginAvatar from '@/features/PluginAvatar';
|
|
13
8
|
import { useChatStore } from '@/store/chat';
|
|
14
|
-
import { chatPortalSelectors } from '@/store/chat/selectors';
|
|
15
|
-
import { pluginHelpers, useToolStore } from '@/store/tool';
|
|
16
|
-
import { toolSelectors } from '@/store/tool/selectors';
|
|
17
9
|
|
|
18
|
-
|
|
19
|
-
const [showToolUI, toggleInspector, closeToolUI, toolUIIdentifier = ''] = useChatStore((s) => [
|
|
20
|
-
chatPortalSelectors.showArtifactUI(s),
|
|
21
|
-
s.togglePortal,
|
|
22
|
-
s.closeToolUI,
|
|
23
|
-
chatPortalSelectors.toolUIIdentifier(s),
|
|
24
|
-
]);
|
|
10
|
+
import { PortalHeader } from '../router';
|
|
25
11
|
|
|
26
|
-
|
|
27
|
-
const
|
|
28
|
-
const pluginTitle = pluginHelpers.getPluginTitle(pluginMeta) ?? t('unknownPlugin');
|
|
12
|
+
const Header = memo(() => {
|
|
13
|
+
const [toggleInspector] = useChatStore((s) => [s.togglePortal]);
|
|
29
14
|
|
|
30
15
|
return (
|
|
31
16
|
<SidebarHeader
|
|
32
17
|
actions={<ActionIcon icon={XIcon} onClick={() => toggleInspector(false)} />}
|
|
33
|
-
style={{ paddingBlock: 8 }}
|
|
34
|
-
title={
|
|
35
|
-
showToolUI ? (
|
|
36
|
-
<Flexbox align={'center'} gap={4} horizontal>
|
|
37
|
-
<ActionIcon icon={ArrowLeft} onClick={() => closeToolUI()} />
|
|
38
|
-
<PluginAvatar identifier={toolUIIdentifier} size={28} />
|
|
39
|
-
<Typography.Text style={{ fontSize: 16 }} type={'secondary'}>
|
|
40
|
-
{pluginTitle}
|
|
41
|
-
</Typography.Text>
|
|
42
|
-
</Flexbox>
|
|
43
|
-
) : (
|
|
44
|
-
<Typography.Text style={{ fontSize: 16 }} type={'secondary'}>
|
|
45
|
-
{t('portal:title')}
|
|
46
|
-
</Typography.Text>
|
|
47
|
-
)
|
|
48
|
-
}
|
|
18
|
+
style={{ paddingBlock: 8, paddingInline: 8 }}
|
|
19
|
+
title={<PortalHeader />}
|
|
49
20
|
/>
|
|
50
21
|
);
|
|
51
22
|
});
|
|
@@ -2,22 +2,46 @@
|
|
|
2
2
|
|
|
3
3
|
import { memo } from 'react';
|
|
4
4
|
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
5
|
+
import { Artifacts } from './Artifacts';
|
|
6
|
+
import { FilePreview } from './FilePreview';
|
|
7
|
+
import { HomeBody, HomeHeader } from './Home';
|
|
7
8
|
|
|
8
|
-
|
|
9
|
-
import FilePreview from './FilePreview';
|
|
10
|
-
import Home from './Home';
|
|
9
|
+
const items = [Artifacts, FilePreview];
|
|
11
10
|
|
|
12
|
-
const
|
|
13
|
-
const
|
|
14
|
-
const showFilePreview = useChatStore(chatPortalSelectors.showFilePreview);
|
|
11
|
+
export const PortalHeader = memo(() => {
|
|
12
|
+
const enabledList: boolean[] = [];
|
|
15
13
|
|
|
16
|
-
|
|
14
|
+
for (const item of items) {
|
|
15
|
+
const enabled = item.useEnable();
|
|
16
|
+
enabledList.push(enabled);
|
|
17
|
+
}
|
|
17
18
|
|
|
18
|
-
|
|
19
|
+
for (const [i, element] of enabledList.entries()) {
|
|
20
|
+
const Header = items[i].Header;
|
|
21
|
+
if (element) {
|
|
22
|
+
return <Header />;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
19
25
|
|
|
20
|
-
return <
|
|
26
|
+
return <HomeHeader />;
|
|
21
27
|
});
|
|
22
28
|
|
|
23
|
-
|
|
29
|
+
const PortalBody = memo(() => {
|
|
30
|
+
const enabledList: boolean[] = [];
|
|
31
|
+
|
|
32
|
+
for (const item of items) {
|
|
33
|
+
const enabled = item.useEnable();
|
|
34
|
+
enabledList.push(enabled);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
for (const [i, element] of enabledList.entries()) {
|
|
38
|
+
const Body = items[i].Body;
|
|
39
|
+
if (element) {
|
|
40
|
+
return <Body />;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return <HomeBody />;
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
export default PortalBody;
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
import { Icon, Tag } from '@lobehub/ui';
|
|
4
|
-
import
|
|
5
|
-
import { Dropdown } from 'antd';
|
|
4
|
+
import { Dropdown, MenuProps } from 'antd';
|
|
6
5
|
import { LibraryBig } from 'lucide-react';
|
|
7
6
|
import { memo } from 'react';
|
|
8
7
|
import { Flexbox } from 'react-layout-kit';
|
|
9
8
|
|
|
10
9
|
import KnowledgeIcon from '@/components/KnowledgeIcon';
|
|
10
|
+
import { oneLineEllipsis } from '@/styles';
|
|
11
11
|
import { KnowledgeItem } from '@/types/knowledgeBase';
|
|
12
12
|
|
|
13
13
|
export interface PluginTagProps {
|
|
@@ -30,7 +30,9 @@ const PluginTag = memo<PluginTagProps>(({ data }) => {
|
|
|
30
30
|
<div>
|
|
31
31
|
<Tag>
|
|
32
32
|
{<Icon icon={LibraryBig} />}
|
|
33
|
-
{
|
|
33
|
+
<div className={oneLineEllipsis} style={{ maxWidth: 140 }}>
|
|
34
|
+
{data[0].name}
|
|
35
|
+
</div>
|
|
34
36
|
{count > 1 && <div>({data.length - 1}+)</div>}
|
|
35
37
|
</Tag>
|
|
36
38
|
</div>
|
|
@@ -102,6 +102,7 @@ export interface ProviderConfigProps extends Omit<ModelProviderCard, 'id' | 'cha
|
|
|
102
102
|
showModelFetcher?: boolean;
|
|
103
103
|
};
|
|
104
104
|
showAceGcm?: boolean;
|
|
105
|
+
title?: ReactNode;
|
|
105
106
|
}
|
|
106
107
|
|
|
107
108
|
const ProviderConfig = memo<ProviderConfigProps>(
|
|
@@ -114,6 +115,7 @@ const ProviderConfig = memo<ProviderConfigProps>(
|
|
|
114
115
|
canDeactivate = true,
|
|
115
116
|
checkerItem,
|
|
116
117
|
modelList,
|
|
118
|
+
title,
|
|
117
119
|
defaultShowBrowserRequest,
|
|
118
120
|
disableBrowserRequest,
|
|
119
121
|
className,
|
|
@@ -264,7 +266,7 @@ const ProviderConfig = memo<ProviderConfigProps>(
|
|
|
264
266
|
) : undefined}
|
|
265
267
|
</Flexbox>
|
|
266
268
|
),
|
|
267
|
-
title: (
|
|
269
|
+
title: title ?? (
|
|
268
270
|
<Flexbox
|
|
269
271
|
align={'center'}
|
|
270
272
|
className={styles.safariIconWidthFix}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { Icon, Tooltip } from '@lobehub/ui';
|
|
2
|
+
import { Tag } from 'antd';
|
|
3
|
+
import { createStyles } from 'antd-style';
|
|
4
|
+
import { BoltIcon, RotateCwIcon } from 'lucide-react';
|
|
5
|
+
import { darken, lighten } from 'polished';
|
|
6
|
+
import { memo } from 'react';
|
|
7
|
+
import { useTranslation } from 'react-i18next';
|
|
8
|
+
import { Flexbox } from 'react-layout-kit';
|
|
9
|
+
|
|
10
|
+
import { AsyncTaskStatus, FileParsingTask } from '@/types/asyncTask';
|
|
11
|
+
|
|
12
|
+
const useStyles = createStyles(({ css, token, isDarkMode }) => ({
|
|
13
|
+
errorReason: css`
|
|
14
|
+
padding: 4px;
|
|
15
|
+
|
|
16
|
+
font-family: monospace;
|
|
17
|
+
font-size: 12px;
|
|
18
|
+
|
|
19
|
+
background: ${isDarkMode ? darken(0.1, token.colorText) : lighten(0.1, token.colorText)};
|
|
20
|
+
border-radius: 4px;
|
|
21
|
+
`,
|
|
22
|
+
}));
|
|
23
|
+
|
|
24
|
+
interface EmbeddingStatusProps extends FileParsingTask {
|
|
25
|
+
className?: string;
|
|
26
|
+
onClick?: (status: AsyncTaskStatus) => void;
|
|
27
|
+
onErrorClick?: (task: 'chunking' | 'embedding') => void;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const EmbeddingStatus = memo<EmbeddingStatusProps>(
|
|
31
|
+
({ chunkCount, embeddingStatus, embeddingError, onClick, onErrorClick, className }) => {
|
|
32
|
+
const { t } = useTranslation(['components', 'common']);
|
|
33
|
+
const { styles, cx } = useStyles();
|
|
34
|
+
|
|
35
|
+
switch (embeddingStatus) {
|
|
36
|
+
case AsyncTaskStatus.Processing: {
|
|
37
|
+
return (
|
|
38
|
+
<Flexbox horizontal>
|
|
39
|
+
<Tooltip
|
|
40
|
+
overlayStyle={{ pointerEvents: 'none' }}
|
|
41
|
+
title={t('FileParsingStatus.chunks.embeddingStatus.processing')}
|
|
42
|
+
>
|
|
43
|
+
<Tag
|
|
44
|
+
bordered={false}
|
|
45
|
+
className={cx('chunk-tag', className)}
|
|
46
|
+
color={'processing'}
|
|
47
|
+
icon={<Icon icon={BoltIcon} spin />}
|
|
48
|
+
style={{ cursor: 'pointer' }}
|
|
49
|
+
>
|
|
50
|
+
{chunkCount}
|
|
51
|
+
</Tag>
|
|
52
|
+
</Tooltip>
|
|
53
|
+
</Flexbox>
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
case AsyncTaskStatus.Error: {
|
|
58
|
+
return (
|
|
59
|
+
<Tooltip
|
|
60
|
+
overlayStyle={{ maxWidth: 340, pointerEvents: 'none' }}
|
|
61
|
+
title={
|
|
62
|
+
<Flexbox gap={4}>
|
|
63
|
+
{t('FileParsingStatus.chunks.embeddingStatus.errorResult')}
|
|
64
|
+
{embeddingError && (
|
|
65
|
+
<Flexbox className={styles.errorReason}>
|
|
66
|
+
[{embeddingError.name}]:{' '}
|
|
67
|
+
{embeddingError.body && typeof embeddingError.body !== 'string'
|
|
68
|
+
? embeddingError.body.detail
|
|
69
|
+
: embeddingError.body}
|
|
70
|
+
</Flexbox>
|
|
71
|
+
)}
|
|
72
|
+
</Flexbox>
|
|
73
|
+
}
|
|
74
|
+
>
|
|
75
|
+
<Tag bordered={false} className={className} color={'error'}>
|
|
76
|
+
{t('FileParsingStatus.chunks.embeddingStatus.error')}{' '}
|
|
77
|
+
<Icon
|
|
78
|
+
icon={RotateCwIcon}
|
|
79
|
+
onClick={() => {
|
|
80
|
+
onErrorClick?.('embedding');
|
|
81
|
+
}}
|
|
82
|
+
style={{ cursor: 'pointer' }}
|
|
83
|
+
title={t('retry', { ns: 'common' })}
|
|
84
|
+
/>
|
|
85
|
+
</Tag>
|
|
86
|
+
</Tooltip>
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
case AsyncTaskStatus.Success: {
|
|
91
|
+
return (
|
|
92
|
+
<Flexbox horizontal>
|
|
93
|
+
<Tooltip
|
|
94
|
+
overlayStyle={{ pointerEvents: 'none' }}
|
|
95
|
+
title={t('FileParsingStatus.chunks.embeddingStatus.success')}
|
|
96
|
+
>
|
|
97
|
+
<Tag
|
|
98
|
+
bordered={false}
|
|
99
|
+
className={cx('chunk-tag', className)}
|
|
100
|
+
color={'purple'}
|
|
101
|
+
icon={<Icon icon={BoltIcon} />}
|
|
102
|
+
onClick={() => {
|
|
103
|
+
onClick?.(AsyncTaskStatus.Success);
|
|
104
|
+
}}
|
|
105
|
+
style={{ cursor: 'pointer' }}
|
|
106
|
+
>
|
|
107
|
+
{chunkCount}
|
|
108
|
+
</Tag>
|
|
109
|
+
</Tooltip>
|
|
110
|
+
</Flexbox>
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
},
|
|
115
|
+
);
|
|
116
|
+
|
|
117
|
+
export default EmbeddingStatus;
|
|
@@ -9,6 +9,8 @@ import { Flexbox } from 'react-layout-kit';
|
|
|
9
9
|
|
|
10
10
|
import { AsyncTaskStatus, FileParsingTask } from '@/types/asyncTask';
|
|
11
11
|
|
|
12
|
+
import EmbeddingStatus from './EmbeddingStatus';
|
|
13
|
+
|
|
12
14
|
const useStyles = createStyles(({ css, token, isDarkMode }) => ({
|
|
13
15
|
errorReason: css`
|
|
14
16
|
padding: 4px;
|
|
@@ -72,7 +74,6 @@ const FileParsingStatus = memo<FileParsingStatusProps>(
|
|
|
72
74
|
return (
|
|
73
75
|
<Tooltip
|
|
74
76
|
overlayStyle={{ maxWidth: 340, pointerEvents: 'none' }}
|
|
75
|
-
// style={{}}
|
|
76
77
|
title={
|
|
77
78
|
<Flexbox gap={4}>
|
|
78
79
|
{t('FileParsingStatus.chunks.status.errorResult')}
|
|
@@ -103,124 +104,65 @@ const FileParsingStatus = memo<FileParsingStatusProps>(
|
|
|
103
104
|
}
|
|
104
105
|
|
|
105
106
|
case AsyncTaskStatus.Success: {
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
switch (embeddingStatus) {
|
|
109
|
-
case AsyncTaskStatus.Processing: {
|
|
110
|
-
return (
|
|
111
|
-
<Flexbox horizontal>
|
|
112
|
-
<Tooltip
|
|
113
|
-
overlayStyle={{ pointerEvents: 'none' }}
|
|
114
|
-
title={t('FileParsingStatus.chunks.embeddingStatus.processing')}
|
|
115
|
-
>
|
|
116
|
-
<Tag
|
|
117
|
-
bordered={false}
|
|
118
|
-
className={cx('chunk-tag', className)}
|
|
119
|
-
color={'processing'}
|
|
120
|
-
icon={
|
|
121
|
-
preparingEmbedding ? (
|
|
122
|
-
<Icon icon={Loader2Icon} spin />
|
|
123
|
-
) : (
|
|
124
|
-
<Icon icon={BoltIcon} spin={isEmbeddingProcessing} />
|
|
125
|
-
)
|
|
126
|
-
}
|
|
127
|
-
style={{ cursor: 'pointer' }}
|
|
128
|
-
>
|
|
129
|
-
{chunkCount}
|
|
130
|
-
</Tag>
|
|
131
|
-
</Tooltip>
|
|
132
|
-
</Flexbox>
|
|
133
|
-
);
|
|
134
|
-
}
|
|
107
|
+
console.log(embeddingStatus);
|
|
135
108
|
|
|
136
|
-
|
|
137
|
-
|
|
109
|
+
// if no embedding status, it means that the embedding is not started
|
|
110
|
+
if (!embeddingStatus || preparingEmbedding)
|
|
111
|
+
return (
|
|
112
|
+
<Flexbox horizontal>
|
|
138
113
|
<Tooltip
|
|
139
|
-
overlayStyle={{
|
|
140
|
-
title={
|
|
141
|
-
<Flexbox gap={4}>
|
|
142
|
-
{t('FileParsingStatus.chunks.embeddingStatus.errorResult')}
|
|
143
|
-
{embeddingError && (
|
|
144
|
-
<Flexbox className={styles.errorReason}>
|
|
145
|
-
[{embeddingError.name}]:{' '}
|
|
146
|
-
{embeddingError.body && typeof embeddingError.body !== 'string'
|
|
147
|
-
? embeddingError.body.detail
|
|
148
|
-
: embeddingError.body}
|
|
149
|
-
</Flexbox>
|
|
150
|
-
)}
|
|
151
|
-
</Flexbox>
|
|
152
|
-
}
|
|
114
|
+
overlayStyle={{ pointerEvents: 'none' }}
|
|
115
|
+
title={t('FileParsingStatus.chunks.embeddingStatus.empty')}
|
|
153
116
|
>
|
|
154
|
-
<Tag
|
|
155
|
-
{
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
117
|
+
<Tag
|
|
118
|
+
bordered={false}
|
|
119
|
+
className={cx('chunk-tag', className)}
|
|
120
|
+
icon={
|
|
121
|
+
preparingEmbedding ? <Icon icon={Loader2Icon} spin /> : <Icon icon={BoltIcon} />
|
|
122
|
+
}
|
|
123
|
+
onClick={() => {
|
|
124
|
+
onClick?.(AsyncTaskStatus.Success);
|
|
125
|
+
}}
|
|
126
|
+
style={{ cursor: 'pointer' }}
|
|
127
|
+
>
|
|
128
|
+
{chunkCount}
|
|
129
|
+
{
|
|
130
|
+
// if want to hide button
|
|
131
|
+
hideEmbeddingButton ||
|
|
132
|
+
// or if preparing the embedding
|
|
133
|
+
preparingEmbedding ? null : (
|
|
134
|
+
<Button
|
|
135
|
+
onClick={(e) => {
|
|
136
|
+
e.stopPropagation();
|
|
137
|
+
onEmbeddingClick?.();
|
|
138
|
+
}}
|
|
139
|
+
style={{
|
|
140
|
+
fontSize: 12,
|
|
141
|
+
height: 'auto',
|
|
142
|
+
paddingBlock: 0,
|
|
143
|
+
paddingInline: '8px 0',
|
|
144
|
+
}}
|
|
145
|
+
type={'link'}
|
|
146
|
+
>
|
|
147
|
+
{t('FileParsingStatus.chunks.embeddings')}
|
|
148
|
+
</Button>
|
|
149
|
+
)
|
|
150
|
+
}
|
|
164
151
|
</Tag>
|
|
165
152
|
</Tooltip>
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
}
|
|
153
|
+
</Flexbox>
|
|
154
|
+
);
|
|
169
155
|
|
|
170
156
|
return (
|
|
171
|
-
<
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
<Tag
|
|
181
|
-
bordered={false}
|
|
182
|
-
className={cx('chunk-tag', className)}
|
|
183
|
-
color={finishEmbedding ? 'purple' : undefined}
|
|
184
|
-
icon={
|
|
185
|
-
preparingEmbedding ? (
|
|
186
|
-
<Icon icon={Loader2Icon} spin />
|
|
187
|
-
) : (
|
|
188
|
-
<Icon icon={BoltIcon} spin={isEmbeddingProcessing} />
|
|
189
|
-
)
|
|
190
|
-
}
|
|
191
|
-
onClick={() => {
|
|
192
|
-
onClick?.(AsyncTaskStatus.Success);
|
|
193
|
-
}}
|
|
194
|
-
style={{ cursor: 'pointer' }}
|
|
195
|
-
>
|
|
196
|
-
{chunkCount}
|
|
197
|
-
{
|
|
198
|
-
// if want to hide button
|
|
199
|
-
hideEmbeddingButton ||
|
|
200
|
-
// or if finished the embedding
|
|
201
|
-
finishEmbedding ||
|
|
202
|
-
// or if preparing the embedding
|
|
203
|
-
preparingEmbedding ? null : (
|
|
204
|
-
<Button
|
|
205
|
-
onClick={(e) => {
|
|
206
|
-
e.stopPropagation();
|
|
207
|
-
onEmbeddingClick?.();
|
|
208
|
-
}}
|
|
209
|
-
style={{
|
|
210
|
-
fontSize: 12,
|
|
211
|
-
height: 'auto',
|
|
212
|
-
paddingBlock: 0,
|
|
213
|
-
paddingInline: '8px 0',
|
|
214
|
-
}}
|
|
215
|
-
type={'link'}
|
|
216
|
-
>
|
|
217
|
-
{t('FileParsingStatus.chunks.embeddings')}
|
|
218
|
-
</Button>
|
|
219
|
-
)
|
|
220
|
-
}
|
|
221
|
-
</Tag>
|
|
222
|
-
</Tooltip>
|
|
223
|
-
</Flexbox>
|
|
157
|
+
<EmbeddingStatus
|
|
158
|
+
chunkCount={chunkCount}
|
|
159
|
+
className={className}
|
|
160
|
+
embeddingError={embeddingError}
|
|
161
|
+
embeddingStatus={embeddingStatus}
|
|
162
|
+
finishEmbedding={finishEmbedding}
|
|
163
|
+
onClick={onClick}
|
|
164
|
+
onErrorClick={onErrorClick}
|
|
165
|
+
/>
|
|
224
166
|
);
|
|
225
167
|
}
|
|
226
168
|
}
|
|
@@ -23,6 +23,25 @@ const Google: ModelProviderCard = {
|
|
|
23
23
|
tokens: 1_048_576 + 8192,
|
|
24
24
|
vision: true,
|
|
25
25
|
},
|
|
26
|
+
{
|
|
27
|
+
description: 'Fast and versatile multimodal model for scaling across diverse tasks',
|
|
28
|
+
displayName: 'Gemini 1.5 Flash Experimental 0827',
|
|
29
|
+
enabled: true,
|
|
30
|
+
functionCall: true,
|
|
31
|
+
id: 'gemini-1.5-flash-exp-0827',
|
|
32
|
+
maxOutput: 8192,
|
|
33
|
+
tokens: 1_048_576 + 8192,
|
|
34
|
+
vision: true,
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
description: 'Fast and versatile multimodal model for scaling across diverse tasks',
|
|
38
|
+
displayName: 'Gemini 1.5 Flash 8B Experimental 0827',
|
|
39
|
+
functionCall: true,
|
|
40
|
+
id: 'gemini-1.5-flash-8b-exp-0827',
|
|
41
|
+
maxOutput: 8192,
|
|
42
|
+
tokens: 1_048_576 + 8192,
|
|
43
|
+
vision: true,
|
|
44
|
+
},
|
|
26
45
|
{
|
|
27
46
|
description: 'Mid-size multimodal model that supports up to 2 million tokens',
|
|
28
47
|
displayName: 'Gemini 1.5 Pro',
|
|
@@ -45,13 +64,22 @@ const Google: ModelProviderCard = {
|
|
|
45
64
|
{
|
|
46
65
|
description: 'Mid-size multimodal model that supports up to 2 million tokens',
|
|
47
66
|
displayName: 'Gemini 1.5 Pro Experimental 0801',
|
|
48
|
-
enabled: true,
|
|
49
67
|
functionCall: true,
|
|
50
68
|
id: 'gemini-1.5-pro-exp-0801',
|
|
51
69
|
maxOutput: 8192,
|
|
52
70
|
tokens: 2_097_152 + 8192,
|
|
53
71
|
vision: true,
|
|
54
72
|
},
|
|
73
|
+
{
|
|
74
|
+
description: 'Mid-size multimodal model that supports up to 2 million tokens',
|
|
75
|
+
displayName: 'Gemini 1.5 Pro Experimental 0827',
|
|
76
|
+
enabled: true,
|
|
77
|
+
functionCall: true,
|
|
78
|
+
id: 'gemini-1.5-pro-exp-0827',
|
|
79
|
+
maxOutput: 8192,
|
|
80
|
+
tokens: 2_097_152 + 8192,
|
|
81
|
+
vision: true,
|
|
82
|
+
},
|
|
55
83
|
{
|
|
56
84
|
description:
|
|
57
85
|
'The best model for scaling across a wide range of tasks. This is the latest model.',
|
|
@@ -37,7 +37,6 @@ const OpenAI: ModelProviderCard = {
|
|
|
37
37
|
description: 'Dynamic model continuously updated to the current version of GPT-4o in ChatGPT',
|
|
38
38
|
displayName: 'ChatGPT-4o',
|
|
39
39
|
enabled: true,
|
|
40
|
-
functionCall: true,
|
|
41
40
|
id: 'chatgpt-4o-latest',
|
|
42
41
|
tokens: 128_000,
|
|
43
42
|
vision: true,
|
|
@@ -144,6 +144,7 @@ export class MessageModel {
|
|
|
144
144
|
filename: files.name,
|
|
145
145
|
id: chunks.id,
|
|
146
146
|
messageId: messageQueryChunks.messageId,
|
|
147
|
+
similarity: messageQueryChunks.similarity,
|
|
147
148
|
text: chunks.text,
|
|
148
149
|
})
|
|
149
150
|
.from(messageQueryChunks)
|
|
@@ -168,7 +169,12 @@ export class MessageModel {
|
|
|
168
169
|
const messageQuery = messageQueriesList.find((relation) => relation.messageId === item.id);
|
|
169
170
|
return {
|
|
170
171
|
...item,
|
|
171
|
-
chunksList: chunksList
|
|
172
|
+
chunksList: chunksList
|
|
173
|
+
.filter((relation) => relation.messageId === item.id)
|
|
174
|
+
.map((c) => ({
|
|
175
|
+
...c,
|
|
176
|
+
similarity: Number(c.similarity) ?? undefined,
|
|
177
|
+
})),
|
|
172
178
|
|
|
173
179
|
extra: {
|
|
174
180
|
fromModel: model,
|
|
@@ -343,7 +349,7 @@ export class MessageModel {
|
|
|
343
349
|
chunkId: chunk.id,
|
|
344
350
|
messageId: id,
|
|
345
351
|
queryId: ragQueryId,
|
|
346
|
-
similarity: chunk.similarity
|
|
352
|
+
similarity: chunk.similarity?.toString(),
|
|
347
353
|
})),
|
|
348
354
|
);
|
|
349
355
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Tooltip } from '@lobehub/ui';
|
|
2
2
|
import { Typography } from 'antd';
|
|
3
3
|
import { memo } from 'react';
|
|
4
|
-
import { Flexbox } from 'react-layout-kit';
|
|
4
|
+
import { Center, Flexbox } from 'react-layout-kit';
|
|
5
5
|
|
|
6
6
|
import FileIcon from '@/components/FileIcon';
|
|
7
7
|
import { useIsMobile } from '@/hooks/useIsMobile';
|
|
@@ -14,7 +14,7 @@ export interface ChunkItemProps extends ChatFileChunk {
|
|
|
14
14
|
index: number;
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
const ChunkItem = memo<ChunkItemProps>(({ id, fileId, text, filename, fileType }) => {
|
|
17
|
+
const ChunkItem = memo<ChunkItemProps>(({ id, fileId, similarity, text, filename, fileType }) => {
|
|
18
18
|
const { styles, cx } = useStyles();
|
|
19
19
|
const openFilePreview = useChatStore((s) => s.openFilePreview);
|
|
20
20
|
|
|
@@ -28,14 +28,12 @@ const ChunkItem = memo<ChunkItemProps>(({ id, fileId, text, filename, fileType }
|
|
|
28
28
|
key={id}
|
|
29
29
|
onClick={(e) => {
|
|
30
30
|
e.stopPropagation();
|
|
31
|
-
openFilePreview(fileId);
|
|
31
|
+
openFilePreview({ chunkId: id, chunkText: text, fileId });
|
|
32
32
|
}}
|
|
33
33
|
>
|
|
34
34
|
<FileIcon fileName={filename} fileType={fileType} size={20} variant={'pure'} />
|
|
35
|
-
<Flexbox style={{ maxWidth: 200 }}>
|
|
36
|
-
<
|
|
37
|
-
<Typography.Text ellipsis={{ tooltip: false }}>{filename}</Typography.Text>
|
|
38
|
-
</Tooltip>
|
|
35
|
+
<Flexbox gap={12} horizontal justify={'space-between'} style={{ maxWidth: 200 }}>
|
|
36
|
+
<Typography.Text ellipsis={{ tooltip: false }}>{filename}</Typography.Text>
|
|
39
37
|
{/*<Typography.Text*/}
|
|
40
38
|
{/* ellipsis={{ suffix: '...' }}*/}
|
|
41
39
|
{/* style={{ fontSize: 12, lineHeight: 1 }}*/}
|
|
@@ -43,6 +41,11 @@ const ChunkItem = memo<ChunkItemProps>(({ id, fileId, text, filename, fileType }
|
|
|
43
41
|
{/*>*/}
|
|
44
42
|
{/* {text}*/}
|
|
45
43
|
{/*</Typography.Text>*/}
|
|
44
|
+
{similarity && (
|
|
45
|
+
<Tooltip title={similarity}>
|
|
46
|
+
<Center className={styles.badge}>{similarity.toFixed(1)}</Center>
|
|
47
|
+
</Tooltip>
|
|
48
|
+
)}
|
|
46
49
|
</Flexbox>
|
|
47
50
|
</Flexbox>
|
|
48
51
|
);
|