@lobehub/chat 1.14.6 → 1.14.8

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.
Files changed (70) hide show
  1. package/CHANGELOG.md +58 -0
  2. package/locales/ar/portal.json +7 -0
  3. package/locales/bg-BG/portal.json +7 -0
  4. package/locales/de-DE/portal.json +7 -0
  5. package/locales/en-US/components.json +10 -10
  6. package/locales/en-US/file.json +5 -5
  7. package/locales/en-US/portal.json +7 -0
  8. package/locales/en-US/tool.json +1 -1
  9. package/locales/es-ES/portal.json +7 -0
  10. package/locales/fr-FR/portal.json +7 -0
  11. package/locales/it-IT/portal.json +7 -0
  12. package/locales/ja-JP/portal.json +7 -0
  13. package/locales/ko-KR/portal.json +7 -0
  14. package/locales/nl-NL/portal.json +7 -0
  15. package/locales/pl-PL/portal.json +7 -0
  16. package/locales/pt-BR/portal.json +7 -0
  17. package/locales/ru-RU/portal.json +7 -0
  18. package/locales/tr-TR/portal.json +7 -0
  19. package/locales/vi-VN/portal.json +7 -0
  20. package/locales/zh-CN/portal.json +7 -0
  21. package/locales/zh-TW/portal.json +7 -0
  22. package/package.json +1 -1
  23. package/src/app/(main)/chat/(workspace)/@portal/Artifacts/{index.tsx → Body/index.tsx} +1 -1
  24. package/src/app/(main)/chat/(workspace)/@portal/Artifacts/Header.tsx +35 -0
  25. package/src/app/(main)/chat/(workspace)/@portal/Artifacts/index.ts +9 -0
  26. package/src/app/(main)/chat/(workspace)/@portal/Artifacts/useEnable.ts +6 -0
  27. package/src/app/(main)/chat/(workspace)/@portal/FilePreview/Body/index.tsx +57 -0
  28. package/src/app/(main)/chat/(workspace)/@portal/FilePreview/Header.tsx +36 -0
  29. package/src/app/(main)/chat/(workspace)/@portal/FilePreview/index.ts +9 -0
  30. package/src/app/(main)/chat/(workspace)/@portal/FilePreview/useEnable.ts +6 -0
  31. package/src/app/(main)/chat/(workspace)/@portal/Home/{Files → Body/Files}/FileList/Item.tsx +7 -7
  32. package/src/app/(main)/chat/(workspace)/@portal/Home/{Files → Body/Files}/FileList/index.tsx +2 -2
  33. package/src/app/(main)/chat/(workspace)/@portal/Home/Header.tsx +17 -0
  34. package/src/app/(main)/chat/(workspace)/@portal/Home/index.ts +2 -0
  35. package/src/app/(main)/chat/(workspace)/@portal/_layout/Desktop.tsx +1 -1
  36. package/src/app/(main)/chat/(workspace)/@portal/default.tsx +2 -2
  37. package/src/app/(main)/chat/(workspace)/@portal/features/Header.tsx +6 -35
  38. package/src/app/(main)/chat/(workspace)/@portal/router.tsx +36 -12
  39. package/src/app/(main)/chat/(workspace)/_layout/Desktop/ChatHeader/KnowledgeTag.tsx +5 -3
  40. package/src/app/(main)/settings/llm/components/ProviderConfig/index.tsx +3 -1
  41. package/src/app/(main)/settings/tts/features/const.tsx +1 -1
  42. package/src/components/FileParsingStatus/EmbeddingStatus.tsx +117 -0
  43. package/src/components/FileParsingStatus/index.tsx +54 -112
  44. package/src/config/modelProviders/openai.ts +0 -1
  45. package/src/database/server/models/message.ts +8 -2
  46. package/src/features/Conversation/Messages/Assistant/FileChunks/Item/index.tsx +10 -7
  47. package/src/features/Conversation/Messages/Assistant/FileChunks/Item/style.ts +13 -0
  48. package/src/features/Conversation/Messages/User/FileListViewer/Item.tsx +1 -1
  49. package/src/features/FileManager/FileList/FileListItem/ChunkTag.tsx +14 -7
  50. package/src/layout/GlobalProvider/Locale.tsx +19 -17
  51. package/src/locales/default/portal.ts +7 -0
  52. package/src/server/routers/lambda/agent.ts +3 -1
  53. package/src/server/routers/lambda/file.ts +19 -0
  54. package/src/services/file/server.ts +4 -0
  55. package/src/services/rag.ts +1 -0
  56. package/src/store/chat/slices/portal/action.ts +9 -4
  57. package/src/store/chat/slices/portal/initialState.ts +7 -3
  58. package/src/store/chat/slices/portal/selectors.ts +2 -0
  59. package/src/store/file/slices/fileManager/action.ts +18 -0
  60. package/src/styles/index.ts +2 -0
  61. package/src/styles/text.ts +10 -0
  62. package/src/types/message/index.ts +2 -0
  63. package/src/app/(main)/chat/(workspace)/@portal/FilePreview/index.tsx +0 -26
  64. /package/src/app/(main)/chat/(workspace)/@portal/Artifacts/{ToolRender.tsx → Body/ToolRender.tsx} +0 -0
  65. /package/src/app/(main)/chat/(workspace)/@portal/Home/{Artifacts → Body/Artifacts}/ArtifactList/Item/index.tsx +0 -0
  66. /package/src/app/(main)/chat/(workspace)/@portal/Home/{Artifacts → Body/Artifacts}/ArtifactList/Item/style.ts +0 -0
  67. /package/src/app/(main)/chat/(workspace)/@portal/Home/{Artifacts → Body/Artifacts}/ArtifactList/index.tsx +0 -0
  68. /package/src/app/(main)/chat/(workspace)/@portal/Home/{Artifacts → Body/Artifacts}/index.tsx +0 -0
  69. /package/src/app/(main)/chat/(workspace)/@portal/Home/{Files → Body/Files}/index.tsx +0 -0
  70. /package/src/app/(main)/chat/(workspace)/@portal/Home/{index.tsx → Body/index.tsx} +0 -0
@@ -0,0 +1,36 @@
1
+ import { ActionIcon } from '@lobehub/ui';
2
+ import { Skeleton, Typography } from 'antd';
3
+ import { ArrowLeft } from 'lucide-react';
4
+ import { Flexbox } from 'react-layout-kit';
5
+
6
+ import { useChatStore } from '@/store/chat';
7
+ import { chatPortalSelectors } from '@/store/chat/selectors';
8
+ import { useFileStore } from '@/store/file';
9
+ import { oneLineEllipsis } from '@/styles';
10
+
11
+ const Header = () => {
12
+ const [closeFilePreview, previewFileId] = useChatStore((s) => [
13
+ s.closeFilePreview,
14
+ chatPortalSelectors.previewFileId(s),
15
+ ]);
16
+
17
+ const useFetchFileItem = useFileStore((s) => s.useFetchFileItem);
18
+
19
+ const { data, isLoading } = useFetchFileItem(previewFileId);
20
+
21
+ return (
22
+ <Flexbox align={'center'} gap={4} horizontal>
23
+ <ActionIcon icon={ArrowLeft} onClick={() => closeFilePreview()} />
24
+
25
+ {isLoading ? (
26
+ <Skeleton.Button active style={{ height: 28 }} />
27
+ ) : (
28
+ <Typography.Text className={oneLineEllipsis} style={{ fontSize: 16 }} type={'secondary'}>
29
+ {data?.name}
30
+ </Typography.Text>
31
+ )}
32
+ </Flexbox>
33
+ );
34
+ };
35
+
36
+ export default Header;
@@ -0,0 +1,9 @@
1
+ import Body from './Body';
2
+ import Header from './Header';
3
+ import { useEnable } from './useEnable';
4
+
5
+ export const FilePreview = {
6
+ Body,
7
+ Header,
8
+ useEnable,
9
+ };
@@ -0,0 +1,6 @@
1
+ import { useChatStore } from '@/store/chat';
2
+ import { chatPortalSelectors } from '@/store/chat/selectors';
3
+
4
+ export const useEnable = () => {
5
+ return useChatStore(chatPortalSelectors.showFilePreview);
6
+ };
@@ -4,6 +4,7 @@ import { memo } from 'react';
4
4
  import { Flexbox } from 'react-layout-kit';
5
5
 
6
6
  import FileIcon from '@/components/FileIcon';
7
+ import { useChatStore } from '@/store/chat';
7
8
  import { ChatFileItem } from '@/types/message';
8
9
  import { formatSize } from '@/utils/format';
9
10
 
@@ -26,8 +27,9 @@ const useStyles = createStyles(({ css, token }) => ({
26
27
  `,
27
28
  }));
28
29
 
29
- const ArtifactItem = memo<ChatFileItem>(({ name, fileType, size }) => {
30
+ const FileItem = memo<ChatFileItem>(({ name, fileType, size, id }) => {
30
31
  const { styles } = useStyles();
32
+ const openFilePreview = useChatStore((s) => s.openFilePreview);
31
33
 
32
34
  return (
33
35
  <Flexbox
@@ -35,11 +37,9 @@ const ArtifactItem = memo<ChatFileItem>(({ name, fileType, size }) => {
35
37
  className={styles.container}
36
38
  gap={8}
37
39
  horizontal
38
- // onClick={() => {
39
- // if (!isToolHasUI || !identifier) return;
40
- //
41
- // openToolUI(messageId, identifier);
42
- // }}
40
+ onClick={() => {
41
+ openFilePreview({ fileId: id });
42
+ }}
43
43
  >
44
44
  <FileIcon fileName={name} fileType={fileType} />
45
45
  <Flexbox>
@@ -50,4 +50,4 @@ const ArtifactItem = memo<ChatFileItem>(({ name, fileType, size }) => {
50
50
  );
51
51
  });
52
52
 
53
- export default ArtifactItem;
53
+ export default FileItem;
@@ -7,10 +7,10 @@ import { useTranslation } from 'react-i18next';
7
7
  import { Center, Flexbox } from 'react-layout-kit';
8
8
  import Balancer from 'react-wrap-balancer';
9
9
 
10
+ import SkeletonLoading from '@/components/SkeletonLoading';
10
11
  import { useChatStore } from '@/store/chat';
11
12
  import { chatSelectors } from '@/store/chat/selectors';
12
13
 
13
- import SkeletonLoading from '../../../components/SkeletonLoading';
14
14
  import FileItem from './Item';
15
15
 
16
16
  const FileList = () => {
@@ -35,7 +35,7 @@ const FileList = () => {
35
35
  size={48}
36
36
  />
37
37
  <Balancer>
38
- <Typography.Text type={'secondary'}>{t('emptyArtifactList')}</Typography.Text>
38
+ <Typography.Text type={'secondary'}>{t('emptyKnowledgeList')}</Typography.Text>
39
39
  </Balancer>
40
40
  </Center>
41
41
  ) : (
@@ -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;
@@ -0,0 +1,2 @@
1
+ export { default as HomeBody } from './Body';
2
+ export { default as HomeHeader } from './Header';
@@ -7,7 +7,7 @@ const Layout = ({ children }: PropsWithChildren) => {
7
7
  return (
8
8
  <>
9
9
  <Header />
10
- <Flexbox height={'100%'} style={{ overflow: 'auto', position: 'relative' }} width={'100%'}>
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 PortalView = lazy(() => import('./router'));
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
- <PortalView />
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 { Typography } from 'antd';
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
- const Header = memo(() => {
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
- const { t } = useTranslation(['plugin', 'portal']);
27
- const pluginMeta = useToolStore(toolSelectors.getMetaById(toolUIIdentifier), isEqual);
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 { useChatStore } from '@/store/chat';
6
- import { chatPortalSelectors } from '@/store/chat/selectors';
5
+ import { Artifacts } from './Artifacts';
6
+ import { FilePreview } from './FilePreview';
7
+ import { HomeBody, HomeHeader } from './Home';
7
8
 
8
- import Artifacts from './Artifacts';
9
- import FilePreview from './FilePreview';
10
- import Home from './Home';
9
+ const items = [Artifacts, FilePreview];
11
10
 
12
- const PortalView = memo(() => {
13
- const showArtifactUI = useChatStore(chatPortalSelectors.showArtifactUI);
14
- const showFilePreview = useChatStore(chatPortalSelectors.showFilePreview);
11
+ export const PortalHeader = memo(() => {
12
+ const enabledList: boolean[] = [];
15
13
 
16
- if (showArtifactUI) return <Artifacts />;
14
+ for (const item of items) {
15
+ const enabled = item.useEnable();
16
+ enabledList.push(enabled);
17
+ }
17
18
 
18
- if (showFilePreview) return <FilePreview />;
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 <Home />;
26
+ return <HomeHeader />;
21
27
  });
22
28
 
23
- export default PortalView;
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 type { MenuProps } from 'antd';
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
- {data[0].name}
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}
@@ -16,7 +16,7 @@ export const opeanaiTTSOptions: SelectProps['options'] = [
16
16
 
17
17
  export const opeanaiSTTOptions: SelectProps['options'] = [
18
18
  {
19
- label: <LabelRenderer Icon={OpenAI.Avatar} label={'stt-1'} />,
19
+ label: <LabelRenderer Icon={OpenAI.Avatar} label={'whisper-1'} />,
20
20
  value: 'whisper-1',
21
21
  },
22
22
  ];
@@ -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
- const isEmbeddingProcessing = embeddingStatus === AsyncTaskStatus.Processing;
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
- case AsyncTaskStatus.Error: {
137
- return (
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={{ maxWidth: 340, pointerEvents: 'none' }}
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 bordered={false} className={className} color={'error'}>
155
- {t('FileParsingStatus.chunks.embeddingStatus.error')}{' '}
156
- <Icon
157
- icon={RotateCwIcon}
158
- onClick={() => {
159
- onErrorClick?.('embedding');
160
- }}
161
- style={{ cursor: 'pointer' }}
162
- title={t('retry', { ns: 'common' })}
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
- <Flexbox horizontal>
172
- <Tooltip
173
- overlayStyle={{ pointerEvents: 'none' }}
174
- title={
175
- finishEmbedding
176
- ? t('FileParsingStatus.chunks.embeddingStatus.success')
177
- : t('FileParsingStatus.chunks.embeddingStatus.empty')
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
  }
@@ -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,