From 89d82ff031afdaefada3702c4b54fc2a024ac450 Mon Sep 17 00:00:00 2001 From: balibabu Date: Thu, 27 Nov 2025 17:54:27 +0800 Subject: [PATCH] Feat: Delete useless knowledge base, chat, and search files. #10427 (#11568) ### What problem does this PR solve? Feat: Delete useless knowledge base, chat, and search files. #10427 ### Type of change - [x] New Feature (non-breaking change which adds functionality) --- .../floating-chat-widget-markdown.tsx | 3 +- .../markdown-content/index.less | 0 .../markdown-content/index.tsx | 3 +- web/src/components/message-item/index.tsx | 9 +- .../next-markdown-content/index.tsx | 3 +- .../components/next-message-item/index.tsx | 7 +- web/src/components/rename-dialog/index.tsx | 2 +- .../components/rename-dialog/rename-form.tsx | 2 +- web/src/constants/knowledge.ts | 2 + web/src/hooks/chat-hooks.ts | 4 +- web/src/hooks/flow-hooks.ts | 2 +- web/src/hooks/logic-hooks.ts | 8 +- web/src/hooks/use-agent-request.ts | 2 +- web/src/hooks/use-chat-request.ts | 2 +- web/src/interfaces/database/chat.ts | 9 + .../components/chunk-card/index.less | 34 - .../components/chunk-card/index.tsx | 101 --- .../components/chunk-creating-modal/index.tsx | 140 ---- .../chunk-creating-modal/tag-feature-item.tsx | 107 --- .../components/chunk-toolbar/index.tsx | 221 ------- .../components/document-preview/hooks.ts | 55 -- .../components/document-preview/index.less | 12 - .../components/document-preview/preview.tsx | 121 ---- .../components/knowledge-chunk/constant.ts | 4 - .../components/knowledge-chunk/hooks.ts | 129 ---- .../components/knowledge-chunk/index.less | 92 --- .../components/knowledge-chunk/index.tsx | 202 ------ .../components/knowledge-chunk/utils.ts | 24 - .../components/knowledge-dataset/index.less | 0 .../components/knowledge-dataset/index.tsx | 7 - .../components/knowledge-file/constant.ts | 17 - .../knowledge-file/create-file-modal.tsx | 49 -- .../knowledge-file/document-toolbar.tsx | 240 ------- .../components/knowledge-file/hooks.ts | 364 ---------- .../components/knowledge-file/index.less | 54 -- .../components/knowledge-file/index.tsx | 275 -------- .../parsing-action-cell/index.less | 3 - .../parsing-action-cell/index.tsx | 149 ----- .../parsing-status-cell/index.less | 36 - .../parsing-status-cell/index.tsx | 143 ---- .../knowledge-file/rename-modal/index.tsx | 75 --- .../knowledge-file/set-meta-modal/index.tsx | 81 --- .../components/knowledge-file/utils.ts | 6 - .../knowledge-file/web-crawl-modal.tsx | 67 -- .../components/knowledge-graph/constant.ts | 241 ------- .../knowledge-graph/force-graph.tsx | 141 ---- .../components/knowledge-graph/index.less | 5 - .../components/knowledge-graph/index.tsx | 31 - .../knowledge-graph/use-delete-graph.ts | 21 - .../components/knowledge-graph/util.ts | 94 --- .../knowledge-setting/category-panel.tsx | 77 --- .../knowledge-setting/configuration/audio.tsx | 31 - .../knowledge-setting/configuration/book.tsx | 33 - .../configuration/common-item.tsx | 52 -- .../knowledge-setting/configuration/email.tsx | 31 - .../knowledge-setting/configuration/index.tsx | 133 ---- .../configuration/knowledge-graph.tsx | 22 - .../knowledge-setting/configuration/laws.tsx | 33 - .../configuration/manual.tsx | 33 - .../knowledge-setting/configuration/naive.tsx | 43 -- .../knowledge-setting/configuration/one.tsx | 30 - .../knowledge-setting/configuration/paper.tsx | 33 - .../configuration/picture.tsx | 24 - .../configuration/presentation.tsx | 33 - .../knowledge-setting/configuration/qa.tsx | 16 - .../configuration/resume.tsx | 16 - .../knowledge-setting/configuration/table.tsx | 13 - .../knowledge-setting/configuration/tag.tsx | 13 - .../components/knowledge-setting/hooks.ts | 121 ---- .../components/knowledge-setting/index.less | 45 -- .../components/knowledge-setting/index.tsx | 40 -- .../components/knowledge-setting/tag-item.tsx | 90 --- .../knowledge-setting/tag-table/index.tsx | 307 --------- .../tag-table/rename-dialog/index.tsx | 40 -- .../tag-table/rename-dialog/rename-form.tsx | 83 --- .../components/knowledge-setting/tag-tabs.tsx | 40 -- .../knowledge-setting/tag-word-cloud.tsx | 62 -- .../components/knowledge-setting/utils.ts | 20 - .../components/knowledge-sidebar/index.less | 63 -- .../components/knowledge-sidebar/index.tsx | 135 ---- .../components/knowledge-testing/index.less | 4 - .../components/knowledge-testing/index.tsx | 68 -- .../testing-control/index.less | 29 - .../testing-control/index.tsx | 109 --- .../testing-control/label-word-cloud.tsx | 59 -- .../testing-result/index.less | 46 -- .../testing-result/index.tsx | 147 ----- .../testing-result/select-files.tsx | 73 --- web/src/pages/add-knowledge/constant.ts | 21 - web/src/pages/add-knowledge/index.less | 19 - web/src/pages/add-knowledge/index.tsx | 74 --- web/src/pages/agent/chat/box.tsx | 2 +- .../pages/agent/chat/use-get-file-icon.tsx | 12 + web/src/pages/agent/debug-content/index.tsx | 2 +- web/src/pages/agent/hooks/use-chat-logic.ts | 3 +- web/src/pages/agent/share/index.tsx | 2 +- web/src/pages/agent/utils/chat.ts | 3 +- .../pages/agents/agent-log-detail-modal.tsx | 7 +- web/src/pages/agents/create-agent-dialog.tsx | 2 +- web/src/pages/agents/create-agent-form.tsx | 2 +- .../agents/upload-agent-dialog/index.tsx | 2 +- .../upload-agent-dialog/upload-agent-form.tsx | 2 +- .../assistant-setting.tsx | 193 ------ .../editable-cell.tsx | 101 --- .../chat/chat-configuration-modal/index.less | 57 -- .../chat/chat-configuration-modal/index.tsx | 207 ------ .../metadata-filter-conditions.tsx | 88 --- .../model-setting.tsx | 55 -- .../prompt-engine.tsx | 222 ------- web/src/pages/chat/chat-container/index.less | 7 - web/src/pages/chat/chat-container/index.tsx | 125 ---- web/src/pages/chat/chat-id-modal/index.less | 3 - web/src/pages/chat/chat-id-modal/index.tsx | 38 -- web/src/pages/chat/constants.ts | 1 - web/src/pages/chat/context.ts | 5 - web/src/pages/chat/hooks.ts | 620 ------------------ web/src/pages/chat/index.less | 82 --- web/src/pages/chat/index.tsx | 393 ----------- web/src/pages/chat/interface.ts | 33 - web/src/pages/chat/share/index.less | 13 - web/src/pages/chat/share/index.tsx | 13 - web/src/pages/chat/share/large.tsx | 124 ---- web/src/pages/chat/shared-hooks.ts | 149 ----- web/src/pages/chat/utils.ts | 53 -- .../parsed-result/add-knowledge/constant.ts | 17 - web/src/pages/data-flow/constant.tsx | 0 .../data-flow/form/parser-form/index.tsx | 0 .../form/parser-form/pdf-form-fields.tsx | 0 .../form/parser-form/ppt-form-fields.tsx | 40 -- .../parser-form/spreadsheet-form-fields.tsx | 40 -- web/src/pages/data-flow/utils.ts | 0 web/src/pages/data-flows/index.tsx | 3 - .../tag-table/rename-dialog/index.tsx | 2 +- .../tag-table/rename-dialog/rename-form.tsx | 2 +- .../pages/dataset/dataset/set-meta-dialog.tsx | 2 +- .../pages/file-manager/action-cell/index.tsx | 141 ---- .../connect-to-knowledge-modal/index.tsx | 62 -- web/src/pages/file-manager/file-toolbar.tsx | 191 ------ .../folder-create-modal/index.tsx | 53 -- web/src/pages/file-manager/hooks.ts | 294 --------- web/src/pages/file-manager/index.less | 29 - web/src/pages/file-manager/index.tsx | 216 ------ .../move-file-modal/async-tree-select.tsx | 69 -- .../file-manager/move-file-modal/index.tsx | 54 -- .../create-folder-form.tsx | 2 +- .../files/create-folder-dialog/index.tsx | 2 +- web/src/pages/knowledge/hooks.ts | 47 -- web/src/pages/knowledge/index.less | 50 -- web/src/pages/knowledge/index.tsx | 132 ---- .../pages/knowledge/knowledge-card/index.less | 133 ---- .../pages/knowledge/knowledge-card/index.tsx | 112 ---- .../knowledge-creating-modal/index.tsx | 63 -- web/src/pages/next-chats/chat/interface.ts | 10 - .../next-chats/hooks/use-send-chat-message.ts | 3 +- .../hooks/use-send-multiple-message.ts | 3 +- web/src/pages/next-chats/share/index.tsx | 2 +- web/src/pages/next-chats/utils.ts | 17 +- web/src/pages/next-search/hooks.ts | 65 +- .../next-search/markdown-content/index.tsx | 3 +- web/src/pages/next-search/mindmap-drawer.tsx | 2 +- .../mcp/import-mcp-dialog/import-mcp-form.tsx | 2 +- .../mcp/import-mcp-dialog/index.tsx | 2 +- web/src/pages/search/hooks.ts | 278 -------- web/src/pages/search/index.less | 191 ------ web/src/pages/search/index.tsx | 284 -------- web/src/pages/search/mindmap-drawer.tsx | 36 - web/src/pages/search/sidebar.tsx | 162 ----- .../mcp/import-mcp-dialog/import-mcp-form.tsx | 2 +- .../mcp/import-mcp-dialog/index.tsx | 2 +- web/src/routes.ts | 59 -- web/src/utils/chat.ts | 13 +- 171 files changed, 161 insertions(+), 11112 deletions(-) rename web/src/{pages/chat => components}/markdown-content/index.less (100%) rename web/src/{pages/chat => components}/markdown-content/index.tsx (99%) delete mode 100644 web/src/pages/add-knowledge/components/knowledge-chunk/components/chunk-card/index.less delete mode 100644 web/src/pages/add-knowledge/components/knowledge-chunk/components/chunk-card/index.tsx delete mode 100644 web/src/pages/add-knowledge/components/knowledge-chunk/components/chunk-creating-modal/index.tsx delete mode 100644 web/src/pages/add-knowledge/components/knowledge-chunk/components/chunk-creating-modal/tag-feature-item.tsx delete mode 100644 web/src/pages/add-knowledge/components/knowledge-chunk/components/chunk-toolbar/index.tsx delete mode 100644 web/src/pages/add-knowledge/components/knowledge-chunk/components/document-preview/hooks.ts delete mode 100644 web/src/pages/add-knowledge/components/knowledge-chunk/components/document-preview/index.less delete mode 100644 web/src/pages/add-knowledge/components/knowledge-chunk/components/document-preview/preview.tsx delete mode 100644 web/src/pages/add-knowledge/components/knowledge-chunk/constant.ts delete mode 100644 web/src/pages/add-knowledge/components/knowledge-chunk/hooks.ts delete mode 100644 web/src/pages/add-knowledge/components/knowledge-chunk/index.less delete mode 100644 web/src/pages/add-knowledge/components/knowledge-chunk/index.tsx delete mode 100644 web/src/pages/add-knowledge/components/knowledge-chunk/utils.ts delete mode 100644 web/src/pages/add-knowledge/components/knowledge-dataset/index.less delete mode 100644 web/src/pages/add-knowledge/components/knowledge-dataset/index.tsx delete mode 100644 web/src/pages/add-knowledge/components/knowledge-file/constant.ts delete mode 100644 web/src/pages/add-knowledge/components/knowledge-file/create-file-modal.tsx delete mode 100644 web/src/pages/add-knowledge/components/knowledge-file/document-toolbar.tsx delete mode 100644 web/src/pages/add-knowledge/components/knowledge-file/hooks.ts delete mode 100644 web/src/pages/add-knowledge/components/knowledge-file/index.less delete mode 100644 web/src/pages/add-knowledge/components/knowledge-file/index.tsx delete mode 100644 web/src/pages/add-knowledge/components/knowledge-file/parsing-action-cell/index.less delete mode 100644 web/src/pages/add-knowledge/components/knowledge-file/parsing-action-cell/index.tsx delete mode 100644 web/src/pages/add-knowledge/components/knowledge-file/parsing-status-cell/index.less delete mode 100644 web/src/pages/add-knowledge/components/knowledge-file/parsing-status-cell/index.tsx delete mode 100644 web/src/pages/add-knowledge/components/knowledge-file/rename-modal/index.tsx delete mode 100644 web/src/pages/add-knowledge/components/knowledge-file/set-meta-modal/index.tsx delete mode 100644 web/src/pages/add-knowledge/components/knowledge-file/utils.ts delete mode 100644 web/src/pages/add-knowledge/components/knowledge-file/web-crawl-modal.tsx delete mode 100644 web/src/pages/add-knowledge/components/knowledge-graph/constant.ts delete mode 100644 web/src/pages/add-knowledge/components/knowledge-graph/force-graph.tsx delete mode 100644 web/src/pages/add-knowledge/components/knowledge-graph/index.less delete mode 100644 web/src/pages/add-knowledge/components/knowledge-graph/index.tsx delete mode 100644 web/src/pages/add-knowledge/components/knowledge-graph/use-delete-graph.ts delete mode 100644 web/src/pages/add-knowledge/components/knowledge-graph/util.ts delete mode 100644 web/src/pages/add-knowledge/components/knowledge-setting/category-panel.tsx delete mode 100644 web/src/pages/add-knowledge/components/knowledge-setting/configuration/audio.tsx delete mode 100644 web/src/pages/add-knowledge/components/knowledge-setting/configuration/book.tsx delete mode 100644 web/src/pages/add-knowledge/components/knowledge-setting/configuration/common-item.tsx delete mode 100644 web/src/pages/add-knowledge/components/knowledge-setting/configuration/email.tsx delete mode 100644 web/src/pages/add-knowledge/components/knowledge-setting/configuration/index.tsx delete mode 100644 web/src/pages/add-knowledge/components/knowledge-setting/configuration/knowledge-graph.tsx delete mode 100644 web/src/pages/add-knowledge/components/knowledge-setting/configuration/laws.tsx delete mode 100644 web/src/pages/add-knowledge/components/knowledge-setting/configuration/manual.tsx delete mode 100644 web/src/pages/add-knowledge/components/knowledge-setting/configuration/naive.tsx delete mode 100644 web/src/pages/add-knowledge/components/knowledge-setting/configuration/one.tsx delete mode 100644 web/src/pages/add-knowledge/components/knowledge-setting/configuration/paper.tsx delete mode 100644 web/src/pages/add-knowledge/components/knowledge-setting/configuration/picture.tsx delete mode 100644 web/src/pages/add-knowledge/components/knowledge-setting/configuration/presentation.tsx delete mode 100644 web/src/pages/add-knowledge/components/knowledge-setting/configuration/qa.tsx delete mode 100644 web/src/pages/add-knowledge/components/knowledge-setting/configuration/resume.tsx delete mode 100644 web/src/pages/add-knowledge/components/knowledge-setting/configuration/table.tsx delete mode 100644 web/src/pages/add-knowledge/components/knowledge-setting/configuration/tag.tsx delete mode 100644 web/src/pages/add-knowledge/components/knowledge-setting/hooks.ts delete mode 100644 web/src/pages/add-knowledge/components/knowledge-setting/index.less delete mode 100644 web/src/pages/add-knowledge/components/knowledge-setting/index.tsx delete mode 100644 web/src/pages/add-knowledge/components/knowledge-setting/tag-item.tsx delete mode 100644 web/src/pages/add-knowledge/components/knowledge-setting/tag-table/index.tsx delete mode 100644 web/src/pages/add-knowledge/components/knowledge-setting/tag-table/rename-dialog/index.tsx delete mode 100644 web/src/pages/add-knowledge/components/knowledge-setting/tag-table/rename-dialog/rename-form.tsx delete mode 100644 web/src/pages/add-knowledge/components/knowledge-setting/tag-tabs.tsx delete mode 100644 web/src/pages/add-knowledge/components/knowledge-setting/tag-word-cloud.tsx delete mode 100644 web/src/pages/add-knowledge/components/knowledge-setting/utils.ts delete mode 100644 web/src/pages/add-knowledge/components/knowledge-sidebar/index.less delete mode 100644 web/src/pages/add-knowledge/components/knowledge-sidebar/index.tsx delete mode 100644 web/src/pages/add-knowledge/components/knowledge-testing/index.less delete mode 100644 web/src/pages/add-knowledge/components/knowledge-testing/index.tsx delete mode 100644 web/src/pages/add-knowledge/components/knowledge-testing/testing-control/index.less delete mode 100644 web/src/pages/add-knowledge/components/knowledge-testing/testing-control/index.tsx delete mode 100644 web/src/pages/add-knowledge/components/knowledge-testing/testing-control/label-word-cloud.tsx delete mode 100644 web/src/pages/add-knowledge/components/knowledge-testing/testing-result/index.less delete mode 100644 web/src/pages/add-knowledge/components/knowledge-testing/testing-result/index.tsx delete mode 100644 web/src/pages/add-knowledge/components/knowledge-testing/testing-result/select-files.tsx delete mode 100644 web/src/pages/add-knowledge/constant.ts delete mode 100644 web/src/pages/add-knowledge/index.less delete mode 100644 web/src/pages/add-knowledge/index.tsx create mode 100644 web/src/pages/agent/chat/use-get-file-icon.tsx delete mode 100644 web/src/pages/chat/chat-configuration-modal/assistant-setting.tsx delete mode 100644 web/src/pages/chat/chat-configuration-modal/editable-cell.tsx delete mode 100644 web/src/pages/chat/chat-configuration-modal/index.less delete mode 100644 web/src/pages/chat/chat-configuration-modal/index.tsx delete mode 100644 web/src/pages/chat/chat-configuration-modal/metadata-filter-conditions.tsx delete mode 100644 web/src/pages/chat/chat-configuration-modal/model-setting.tsx delete mode 100644 web/src/pages/chat/chat-configuration-modal/prompt-engine.tsx delete mode 100644 web/src/pages/chat/chat-container/index.less delete mode 100644 web/src/pages/chat/chat-container/index.tsx delete mode 100644 web/src/pages/chat/chat-id-modal/index.less delete mode 100644 web/src/pages/chat/chat-id-modal/index.tsx delete mode 100644 web/src/pages/chat/constants.ts delete mode 100644 web/src/pages/chat/context.ts delete mode 100644 web/src/pages/chat/hooks.ts delete mode 100644 web/src/pages/chat/index.less delete mode 100644 web/src/pages/chat/index.tsx delete mode 100644 web/src/pages/chat/interface.ts delete mode 100644 web/src/pages/chat/share/index.less delete mode 100644 web/src/pages/chat/share/index.tsx delete mode 100644 web/src/pages/chat/share/large.tsx delete mode 100644 web/src/pages/chat/shared-hooks.ts delete mode 100644 web/src/pages/chat/utils.ts delete mode 100644 web/src/pages/data-flow/constant.tsx delete mode 100644 web/src/pages/data-flow/form/parser-form/index.tsx delete mode 100644 web/src/pages/data-flow/form/parser-form/pdf-form-fields.tsx delete mode 100644 web/src/pages/data-flow/form/parser-form/ppt-form-fields.tsx delete mode 100644 web/src/pages/data-flow/form/parser-form/spreadsheet-form-fields.tsx delete mode 100644 web/src/pages/data-flow/utils.ts delete mode 100644 web/src/pages/data-flows/index.tsx delete mode 100644 web/src/pages/file-manager/action-cell/index.tsx delete mode 100644 web/src/pages/file-manager/connect-to-knowledge-modal/index.tsx delete mode 100644 web/src/pages/file-manager/file-toolbar.tsx delete mode 100644 web/src/pages/file-manager/folder-create-modal/index.tsx delete mode 100644 web/src/pages/file-manager/hooks.ts delete mode 100644 web/src/pages/file-manager/index.less delete mode 100644 web/src/pages/file-manager/index.tsx delete mode 100644 web/src/pages/file-manager/move-file-modal/async-tree-select.tsx delete mode 100644 web/src/pages/file-manager/move-file-modal/index.tsx delete mode 100644 web/src/pages/knowledge/hooks.ts delete mode 100644 web/src/pages/knowledge/index.less delete mode 100644 web/src/pages/knowledge/index.tsx delete mode 100644 web/src/pages/knowledge/knowledge-card/index.less delete mode 100644 web/src/pages/knowledge/knowledge-card/index.tsx delete mode 100644 web/src/pages/knowledge/knowledge-creating-modal/index.tsx delete mode 100644 web/src/pages/search/hooks.ts delete mode 100644 web/src/pages/search/index.less delete mode 100644 web/src/pages/search/index.tsx delete mode 100644 web/src/pages/search/mindmap-drawer.tsx delete mode 100644 web/src/pages/search/sidebar.tsx diff --git a/web/src/components/floating-chat-widget-markdown.tsx b/web/src/components/floating-chat-widget-markdown.tsx index 58e7bbd04..04e066c21 100644 --- a/web/src/components/floating-chat-widget-markdown.tsx +++ b/web/src/components/floating-chat-widget-markdown.tsx @@ -6,7 +6,9 @@ import { } from '@/hooks/document-hooks'; import { IReference, IReferenceChunk } from '@/interfaces/database/chat'; import { + currentReg, preprocessLaTeX, + replaceTextByOldReg, replaceThinkToSection, showImage, } from '@/utils/chat'; @@ -32,7 +34,6 @@ import rehypeRaw from 'rehype-raw'; import remarkGfm from 'remark-gfm'; import remarkMath from 'remark-math'; import { visitParents } from 'unist-util-visit-parents'; -import { currentReg, replaceTextByOldReg } from '../pages/next-chats/utils'; import styles from './floating-chat-widget-markdown.less'; import { useIsDarkTheme } from './theme-provider'; diff --git a/web/src/pages/chat/markdown-content/index.less b/web/src/components/markdown-content/index.less similarity index 100% rename from web/src/pages/chat/markdown-content/index.less rename to web/src/components/markdown-content/index.less diff --git a/web/src/pages/chat/markdown-content/index.tsx b/web/src/components/markdown-content/index.tsx similarity index 99% rename from web/src/pages/chat/markdown-content/index.tsx rename to web/src/components/markdown-content/index.tsx index adc4f15c8..acf5e6f29 100644 --- a/web/src/pages/chat/markdown-content/index.tsx +++ b/web/src/components/markdown-content/index.tsx @@ -21,11 +21,12 @@ import { useTranslation } from 'react-i18next'; import 'katex/dist/katex.min.css'; // `rehype-katex` does not import the CSS for you import { + currentReg, preprocessLaTeX, + replaceTextByOldReg, replaceThinkToSection, showImage, } from '@/utils/chat'; -import { currentReg, replaceTextByOldReg } from '../utils'; import classNames from 'classnames'; import { omit } from 'lodash'; diff --git a/web/src/components/message-item/index.tsx b/web/src/components/message-item/index.tsx index 6a9432465..ff5b08b7d 100644 --- a/web/src/components/message-item/index.tsx +++ b/web/src/components/message-item/index.tsx @@ -1,6 +1,10 @@ import { ReactComponent as AssistantIcon } from '@/assets/svg/assistant.svg'; import { MessageType } from '@/constants/chat'; -import { IReference, IReferenceChunk } from '@/interfaces/database/chat'; +import { + IMessage, + IReference, + IReferenceChunk, +} from '@/interfaces/database/chat'; import classNames from 'classnames'; import { memo, useCallback, useEffect, useMemo } from 'react'; @@ -10,9 +14,8 @@ import { } from '@/hooks/document-hooks'; import { IRegenerateMessage, IRemoveMessageById } from '@/hooks/logic-hooks'; import { cn } from '@/lib/utils'; -import { IMessage } from '@/pages/chat/interface'; -import MarkdownContent from '@/pages/chat/markdown-content'; import { Avatar, Flex, Space } from 'antd'; +import MarkdownContent from '../markdown-content'; import { ReferenceDocumentList } from '../next-message-item/reference-document-list'; import { InnerUploadedMessageFiles } from '../next-message-item/uploaded-message-files'; import { useTheme } from '../theme-provider'; diff --git a/web/src/components/next-markdown-content/index.tsx b/web/src/components/next-markdown-content/index.tsx index b841cd446..20466bc48 100644 --- a/web/src/components/next-markdown-content/index.tsx +++ b/web/src/components/next-markdown-content/index.tsx @@ -19,13 +19,14 @@ import { useTranslation } from 'react-i18next'; import 'katex/dist/katex.min.css'; // `rehype-katex` does not import the CSS for you import { + currentReg, preprocessLaTeX, + replaceTextByOldReg, replaceThinkToSection, showImage, } from '@/utils/chat'; import { cn } from '@/lib/utils'; -import { currentReg, replaceTextByOldReg } from '@/pages/chat/utils'; import classNames from 'classnames'; import { omit } from 'lodash'; import { pipe } from 'lodash/fp'; diff --git a/web/src/components/next-message-item/index.tsx b/web/src/components/next-message-item/index.tsx index 706553b67..3f3ce6879 100644 --- a/web/src/components/next-message-item/index.tsx +++ b/web/src/components/next-message-item/index.tsx @@ -1,6 +1,10 @@ import { ReactComponent as AssistantIcon } from '@/assets/svg/assistant.svg'; import { MessageType } from '@/constants/chat'; -import { IReferenceChunk, IReferenceObject } from '@/interfaces/database/chat'; +import { + IMessage, + IReferenceChunk, + IReferenceObject, +} from '@/interfaces/database/chat'; import classNames from 'classnames'; import { PropsWithChildren, @@ -17,7 +21,6 @@ import { INodeEvent, MessageEventType } from '@/hooks/use-send-message'; import { cn } from '@/lib/utils'; import { AgentChatContext } from '@/pages/agent/context'; import { WorkFlowTimeline } from '@/pages/agent/log-sheet/workflow-timeline'; -import { IMessage } from '@/pages/chat/interface'; import { downloadFile } from '@/services/file-manager-service'; import { downloadFileFromBlob } from '@/utils/file-util'; import { isEmpty } from 'lodash'; diff --git a/web/src/components/rename-dialog/index.tsx b/web/src/components/rename-dialog/index.tsx index 999760d00..27f50a015 100644 --- a/web/src/components/rename-dialog/index.tsx +++ b/web/src/components/rename-dialog/index.tsx @@ -5,8 +5,8 @@ import { DialogHeader, DialogTitle, } from '@/components/ui/dialog'; +import { TagRenameId } from '@/constants/knowledge'; import { IModalProps } from '@/interfaces/common'; -import { TagRenameId } from '@/pages/add-knowledge/constant'; import { ReactNode } from 'react'; import { useTranslation } from 'react-i18next'; import { ButtonLoading } from '../ui/button'; diff --git a/web/src/components/rename-dialog/rename-form.tsx b/web/src/components/rename-dialog/rename-form.tsx index e1b3c285f..3dc543d53 100644 --- a/web/src/components/rename-dialog/rename-form.tsx +++ b/web/src/components/rename-dialog/rename-form.tsx @@ -13,8 +13,8 @@ import { FormMessage, } from '@/components/ui/form'; import { Input } from '@/components/ui/input'; +import { TagRenameId } from '@/constants/knowledge'; import { IModalProps } from '@/interfaces/common'; -import { TagRenameId } from '@/pages/add-knowledge/constant'; import { useEffect } from 'react'; import { useTranslation } from 'react-i18next'; diff --git a/web/src/constants/knowledge.ts b/web/src/constants/knowledge.ts index a08aac2c5..130b7ed91 100644 --- a/web/src/constants/knowledge.ts +++ b/web/src/constants/knowledge.ts @@ -92,3 +92,5 @@ export enum DocumentParserType { Tag = 'tag', KnowledgeGraph = 'knowledge_graph', } + +export const TagRenameId = 'tagRename'; diff --git a/web/src/hooks/chat-hooks.ts b/web/src/hooks/chat-hooks.ts index 599944d27..a8e1509a3 100644 --- a/web/src/hooks/chat-hooks.ts +++ b/web/src/hooks/chat-hooks.ts @@ -1,5 +1,6 @@ import { ChatSearchParams } from '@/constants/chat'; import { + IClientConversation, IConversation, IDialog, IStats, @@ -10,8 +11,7 @@ import { IFeedbackRequestBody, } from '@/interfaces/request/chat'; import i18n from '@/locales/config'; -import { IClientConversation } from '@/pages/chat/interface'; -import { useGetSharedChatSearchParams } from '@/pages/chat/shared-hooks'; +import { useGetSharedChatSearchParams } from '@/pages/next-chats/hooks/use-send-shared-message'; import chatService from '@/services/chat-service'; import { buildMessageListWithUuid, diff --git a/web/src/hooks/flow-hooks.ts b/web/src/hooks/flow-hooks.ts index 5acfd0649..d65452181 100644 --- a/web/src/hooks/flow-hooks.ts +++ b/web/src/hooks/flow-hooks.ts @@ -1,7 +1,7 @@ import { DSL, IFlow } from '@/interfaces/database/flow'; import { IDebugSingleRequestBody } from '@/interfaces/request/flow'; import i18n from '@/locales/config'; -import { useGetSharedChatSearchParams } from '@/pages/chat/shared-hooks'; +import { useGetSharedChatSearchParams } from '@/pages/next-chats/hooks/use-send-shared-message'; import flowService from '@/services/flow-service'; import { buildMessageListWithUuid } from '@/utils/chat'; import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; diff --git a/web/src/hooks/logic-hooks.ts b/web/src/hooks/logic-hooks.ts index d7afe6347..d2fb2cd50 100644 --- a/web/src/hooks/logic-hooks.ts +++ b/web/src/hooks/logic-hooks.ts @@ -2,9 +2,13 @@ import { Authorization } from '@/constants/authorization'; import { MessageType } from '@/constants/chat'; import { LanguageTranslationMap } from '@/constants/common'; import { ResponseType } from '@/interfaces/database/base'; -import { IAnswer, Message } from '@/interfaces/database/chat'; +import { + IAnswer, + IClientConversation, + IMessage, + Message, +} from '@/interfaces/database/chat'; import { IKnowledgeFile } from '@/interfaces/database/knowledge'; -import { IClientConversation, IMessage } from '@/pages/chat/interface'; import api from '@/utils/api'; import { getAuthorization } from '@/utils/authorization-util'; import { buildMessageUuid } from '@/utils/chat'; diff --git a/web/src/hooks/use-agent-request.ts b/web/src/hooks/use-agent-request.ts index 4f8d8c538..bbddf50d7 100644 --- a/web/src/hooks/use-agent-request.ts +++ b/web/src/hooks/use-agent-request.ts @@ -14,7 +14,7 @@ import { IDebugSingleRequestBody } from '@/interfaces/request/agent'; import i18n from '@/locales/config'; import { BeginId } from '@/pages/agent/constant'; import { IInputs } from '@/pages/agent/interface'; -import { useGetSharedChatSearchParams } from '@/pages/chat/shared-hooks'; +import { useGetSharedChatSearchParams } from '@/pages/next-chats/hooks/use-send-shared-message'; import agentService, { fetchAgentLogsByCanvasId, fetchPipeLineList, diff --git a/web/src/hooks/use-chat-request.ts b/web/src/hooks/use-chat-request.ts index 127b0e54b..25155e1fc 100644 --- a/web/src/hooks/use-chat-request.ts +++ b/web/src/hooks/use-chat-request.ts @@ -2,12 +2,12 @@ import { FileUploadProps } from '@/components/file-upload'; import message from '@/components/ui/message'; import { ChatSearchParams } from '@/constants/chat'; import { + IClientConversation, IConversation, IDialog, IExternalChatInfo, } from '@/interfaces/database/chat'; import { IAskRequestBody } from '@/interfaces/request/chat'; -import { IClientConversation } from '@/pages/next-chats/chat/interface'; import { useGetSharedChatSearchParams } from '@/pages/next-chats/hooks/use-send-shared-message'; import { isConversationIdExist } from '@/pages/next-chats/utils'; import chatService from '@/services/next-chat-service'; diff --git a/web/src/interfaces/database/chat.ts b/web/src/interfaces/database/chat.ts index eb6eebe89..fb409b05e 100644 --- a/web/src/interfaces/database/chat.ts +++ b/web/src/interfaces/database/chat.ts @@ -183,3 +183,12 @@ export interface IExternalChatInfo { title: string; prologue?: string; } + +export interface IMessage extends Message { + id: string; + reference?: IReference; // the latest news has reference +} + +export interface IClientConversation extends IConversation { + message: IMessage[]; +} diff --git a/web/src/pages/add-knowledge/components/knowledge-chunk/components/chunk-card/index.less b/web/src/pages/add-knowledge/components/knowledge-chunk/components/chunk-card/index.less deleted file mode 100644 index 127a5c790..000000000 --- a/web/src/pages/add-knowledge/components/knowledge-chunk/components/chunk-card/index.less +++ /dev/null @@ -1,34 +0,0 @@ -.image { - width: 100px !important; - object-fit: contain; -} - -.imagePreview { - max-width: 50vw; - max-height: 50vh; - object-fit: contain; -} - -.content { - flex: 1; - .chunkText; -} - -.contentEllipsis { - .multipleLineEllipsis(3); -} - -.contentText { - word-break: break-all !important; -} - -.chunkCard { - width: 100%; -} - -.cardSelected { - background-color: @selectedBackgroundColor; -} -.cardSelectedDark { - background-color: #ffffff2f; -} diff --git a/web/src/pages/add-knowledge/components/knowledge-chunk/components/chunk-card/index.tsx b/web/src/pages/add-knowledge/components/knowledge-chunk/components/chunk-card/index.tsx deleted file mode 100644 index b7e61e06a..000000000 --- a/web/src/pages/add-knowledge/components/knowledge-chunk/components/chunk-card/index.tsx +++ /dev/null @@ -1,101 +0,0 @@ -import Image from '@/components/image'; -import { IChunk } from '@/interfaces/database/knowledge'; -import { Card, Checkbox, CheckboxProps, Flex, Popover, Switch } from 'antd'; -import classNames from 'classnames'; -import DOMPurify from 'dompurify'; -import { useEffect, useState } from 'react'; - -import { useTheme } from '@/components/theme-provider'; -import { ChunkTextMode } from '../../constant'; -import styles from './index.less'; - -interface IProps { - item: IChunk; - checked: boolean; - switchChunk: (available?: number, chunkIds?: string[]) => void; - editChunk: (chunkId: string) => void; - handleCheckboxClick: (chunkId: string, checked: boolean) => void; - selected: boolean; - clickChunkCard: (chunkId: string) => void; - textMode: ChunkTextMode; -} - -const ChunkCard = ({ - item, - checked, - handleCheckboxClick, - editChunk, - switchChunk, - selected, - clickChunkCard, - textMode, -}: IProps) => { - const available = Number(item.available_int); - const [enabled, setEnabled] = useState(false); - const { theme } = useTheme(); - - const onChange = (checked: boolean) => { - setEnabled(checked); - switchChunk(available === 0 ? 1 : 0, [item.chunk_id]); - }; - - const handleCheck: CheckboxProps['onChange'] = (e) => { - handleCheckboxClick(item.chunk_id, e.target.checked); - }; - - const handleContentDoubleClick = () => { - editChunk(item.chunk_id); - }; - - const handleContentClick = () => { - clickChunkCard(item.chunk_id); - }; - - useEffect(() => { - setEnabled(available === 1); - }, [available]); - - return ( - - - - {item.image_id && ( - - } - > - - - )} - -
-
-
- -
- -
-
-
- ); -}; - -export default ChunkCard; diff --git a/web/src/pages/add-knowledge/components/knowledge-chunk/components/chunk-creating-modal/index.tsx b/web/src/pages/add-knowledge/components/knowledge-chunk/components/chunk-creating-modal/index.tsx deleted file mode 100644 index abcf1742c..000000000 --- a/web/src/pages/add-knowledge/components/knowledge-chunk/components/chunk-creating-modal/index.tsx +++ /dev/null @@ -1,140 +0,0 @@ -import EditTag from '@/components/edit-tag'; -import { useFetchChunk } from '@/hooks/chunk-hooks'; -import { IModalProps } from '@/interfaces/common'; -import { IChunk } from '@/interfaces/database/knowledge'; -import { DeleteOutlined } from '@ant-design/icons'; -import { Divider, Form, Input, Modal, Space, Switch } from 'antd'; -import React, { useCallback, useEffect, useState } from 'react'; -import { useTranslation } from 'react-i18next'; -import { useDeleteChunkByIds } from '../../hooks'; -import { - transformTagFeaturesArrayToObject, - transformTagFeaturesObjectToArray, -} from '../../utils'; -import { TagFeatureItem } from './tag-feature-item'; - -type FieldType = Pick< - IChunk, - 'content_with_weight' | 'tag_kwd' | 'question_kwd' | 'important_kwd' ->; - -interface kFProps { - doc_id: string; - chunkId: string | undefined; - parserId: string; -} - -const ChunkCreatingModal: React.FC & kFProps> = ({ - doc_id, - chunkId, - hideModal, - onOk, - loading, - parserId, -}) => { - const [form] = Form.useForm(); - const [checked, setChecked] = useState(false); - const { removeChunk } = useDeleteChunkByIds(); - const { data } = useFetchChunk(chunkId); - const { t } = useTranslation(); - - const isTagParser = parserId === 'tag'; - - const handleOk = useCallback(async () => { - try { - const values = await form.validateFields(); - console.log('🚀 ~ handleOk ~ values:', values); - - onOk?.({ - ...values, - tag_feas: transformTagFeaturesArrayToObject(values.tag_feas), - available_int: checked ? 1 : 0, // available_int - }); - } catch (errorInfo) { - console.log('Failed:', errorInfo); - } - }, [checked, form, onOk]); - - const handleRemove = useCallback(() => { - if (chunkId) { - return removeChunk([chunkId], doc_id); - } - }, [chunkId, doc_id, removeChunk]); - - const handleCheck = useCallback(() => { - setChecked(!checked); - }, [checked]); - - useEffect(() => { - if (data?.code === 0) { - const { available_int, tag_feas } = data.data; - form.setFieldsValue({ - ...(data.data || {}), - tag_feas: transformTagFeaturesObjectToArray(tag_feas), - }); - - setChecked(available_int !== 0); - } - }, [data, form, chunkId]); - - return ( - -
- - label={t('chunk.chunk')} - name="content_with_weight" - rules={[{ required: true, message: t('chunk.chunkMessage') }]} - > - - - - label={t('chunk.keyword')} name="important_kwd"> - - - - label={t('chunk.question')} - name="question_kwd" - tooltip={t('chunk.questionTip')} - > - - - {isTagParser && ( - - label={t('knowledgeConfiguration.tagName')} - name="tag_kwd" - > - - - )} - - {!isTagParser && } - - - {chunkId && ( -
- - - - - - {t('common.delete')} - - -
- )} -
- ); -}; -export default ChunkCreatingModal; diff --git a/web/src/pages/add-knowledge/components/knowledge-chunk/components/chunk-creating-modal/tag-feature-item.tsx b/web/src/pages/add-knowledge/components/knowledge-chunk/components/chunk-creating-modal/tag-feature-item.tsx deleted file mode 100644 index 64c192eb7..000000000 --- a/web/src/pages/add-knowledge/components/knowledge-chunk/components/chunk-creating-modal/tag-feature-item.tsx +++ /dev/null @@ -1,107 +0,0 @@ -import { - useFetchKnowledgeBaseConfiguration, - useFetchTagListByKnowledgeIds, -} from '@/hooks/knowledge-hooks'; -import { MinusCircleOutlined, PlusOutlined } from '@ant-design/icons'; -import { Button, Form, InputNumber, Select } from 'antd'; -import { useCallback, useEffect, useMemo } from 'react'; -import { useTranslation } from 'react-i18next'; -import { FormListItem } from '../../utils'; - -const FieldKey = 'tag_feas'; - -export const TagFeatureItem = () => { - const form = Form.useFormInstance(); - const { t } = useTranslation(); - const { data: knowledgeConfiguration } = useFetchKnowledgeBaseConfiguration(); - - const { setKnowledgeIds, list } = useFetchTagListByKnowledgeIds(); - - const tagKnowledgeIds = useMemo(() => { - return knowledgeConfiguration?.parser_config?.tag_kb_ids ?? []; - }, [knowledgeConfiguration?.parser_config?.tag_kb_ids]); - - const options = useMemo(() => { - return list.map((x) => ({ - value: x[0], - label: x[0], - })); - }, [list]); - - const filterOptions = useCallback( - (index: number) => { - const tags: FormListItem[] = form.getFieldValue(FieldKey) ?? []; - - // Exclude it's own current data - const list = tags - .filter((x, idx) => x && index !== idx) - .map((x) => x.tag); - - // Exclude the selected data from other options from one's own options. - return options.filter((x) => !list.some((y) => x.value === y)); - }, - [form, options], - ); - - useEffect(() => { - setKnowledgeIds(tagKnowledgeIds); - }, [setKnowledgeIds, tagKnowledgeIds]); - - return ( - - - {(fields, { add, remove }) => ( - <> - {fields.map(({ key, name, ...restField }) => ( -
-
- - } - allowClear - onChange={handleInputChange} - onBlur={handleSearchBlur} - value={searchString} - /> - ) : ( - -
- ), - }, - { type: 'divider' }, - { - key: '3', - onClick: showCreateModal, - label: ( -
- -
- ), - }, - ]; - }, [showDocumentUploadModal, showCreateModal, t]); - - const handleDelete = useCallback(() => { - const deletedKeys = selectedRowKeys.filter( - (x) => - !documents - .filter((y) => y.run === RunningStatus.RUNNING) - .some((y) => y.id === x), - ); - if (deletedKeys.length === 0) { - toast.error(t('theDocumentBeingParsedCannotBeDeleted')); - return; - } - showDeleteConfirm({ - onOk: () => { - removeDocument(deletedKeys); - }, - }); - }, [selectedRowKeys, showDeleteConfirm, documents, t, removeDocument]); - - const runDocument = useCallback( - (run: number) => { - runDocumentByIds({ - documentIds: selectedRowKeys, - run, - shouldDelete: false, - }); - }, - [runDocumentByIds, selectedRowKeys], - ); - - const handleRunClick = useCallback(() => { - runDocument(1); - }, [runDocument]); - - const handleCancelClick = useCallback(() => { - runDocument(2); - }, [runDocument]); - - const onChangeStatus = useCallback( - (enabled: boolean) => { - selectedRowKeys.forEach((id) => { - setDocumentStatus({ status: enabled, documentId: id }); - }); - }, - [selectedRowKeys, setDocumentStatus], - ); - - const handleEnableClick = useCallback(() => { - onChangeStatus(true); - }, [onChangeStatus]); - - const handleDisableClick = useCallback(() => { - onChangeStatus(false); - }, [onChangeStatus]); - - const disabled = selectedRowKeys.length === 0; - - const items: MenuProps['items'] = useMemo(() => { - return [ - { - key: '0', - onClick: handleEnableClick, - label: ( - - - {t('enabled')} - - ), - }, - { - key: '1', - onClick: handleDisableClick, - label: ( - - - {t('disabled')} - - ), - }, - { type: 'divider' }, - { - key: '2', - onClick: handleRunClick, - label: ( - - - {t('run')} - - ), - }, - { - key: '3', - onClick: handleCancelClick, - label: ( - - - {t('cancel')} - - ), - }, - { type: 'divider' }, - { - key: '4', - onClick: handleDelete, - label: ( - - - - - {t('delete', { keyPrefix: 'common' })} - - ), - }, - ]; - }, [ - handleDelete, - handleRunClick, - handleCancelClick, - t, - handleDisableClick, - handleEnableClick, - ]); - - return ( -
- - - - - } - /> - - - - - -
- ); -}; - -export default DocumentToolbar; diff --git a/web/src/pages/add-knowledge/components/knowledge-file/hooks.ts b/web/src/pages/add-knowledge/components/knowledge-file/hooks.ts deleted file mode 100644 index 49eccb7eb..000000000 --- a/web/src/pages/add-knowledge/components/knowledge-file/hooks.ts +++ /dev/null @@ -1,364 +0,0 @@ -import { useSetModalState } from '@/hooks/common-hooks'; -import { - useCreateNextDocument, - useNextWebCrawl, - useRunNextDocument, - useSaveNextDocumentName, - useSetDocumentMeta, - useSetNextDocumentParser, - useUploadNextDocument, -} from '@/hooks/document-hooks'; -import { useGetKnowledgeSearchParams } from '@/hooks/route-hook'; -import { IDocumentInfo } from '@/interfaces/database/document'; -import { IChangeParserConfigRequestBody } from '@/interfaces/request/document'; -import { UploadFile } from 'antd'; -import { TableRowSelection } from 'antd/es/table/interface'; -import { useCallback, useState } from 'react'; -import { useNavigate } from 'umi'; -import { KnowledgeRouteKey } from './constant'; - -export const useNavigateToOtherPage = () => { - const navigate = useNavigate(); - const { knowledgeId } = useGetKnowledgeSearchParams(); - - const linkToUploadPage = useCallback(() => { - navigate(`/knowledge/dataset/upload?id=${knowledgeId}`); - }, [navigate, knowledgeId]); - - const toChunk = useCallback( - (id: string) => { - navigate( - `/knowledge/${KnowledgeRouteKey.Dataset}/chunk?id=${knowledgeId}&doc_id=${id}`, - ); - }, - [navigate, knowledgeId], - ); - - return { linkToUploadPage, toChunk }; -}; - -export const useRenameDocument = (documentId: string) => { - const { saveName, loading } = useSaveNextDocumentName(); - - const { - visible: renameVisible, - hideModal: hideRenameModal, - showModal: showRenameModal, - } = useSetModalState(); - - const onRenameOk = useCallback( - async (name: string) => { - const ret = await saveName({ documentId, name }); - if (ret === 0) { - hideRenameModal(); - } - }, - [hideRenameModal, saveName, documentId], - ); - - return { - renameLoading: loading, - onRenameOk, - renameVisible, - hideRenameModal, - showRenameModal, - }; -}; - -export const useCreateEmptyDocument = () => { - const { createDocument, loading } = useCreateNextDocument(); - - const { - visible: createVisible, - hideModal: hideCreateModal, - showModal: showCreateModal, - } = useSetModalState(); - - const onCreateOk = useCallback( - async (name: string) => { - const ret = await createDocument(name); - if (ret === 0) { - hideCreateModal(); - } - }, - [hideCreateModal, createDocument], - ); - - return { - createLoading: loading, - onCreateOk, - createVisible, - hideCreateModal, - showCreateModal, - }; -}; - -export const useChangeDocumentParser = (documentId: string) => { - const { setDocumentParser, loading } = useSetNextDocumentParser(); - - const { - visible: changeParserVisible, - hideModal: hideChangeParserModal, - showModal: showChangeParserModal, - } = useSetModalState(); - - const onChangeParserOk = useCallback( - async (parserId: string, parserConfig: IChangeParserConfigRequestBody) => { - const ret = await setDocumentParser({ - parserId, - documentId, - parserConfig, - }); - if (ret === 0) { - hideChangeParserModal(); - } - }, - [hideChangeParserModal, setDocumentParser, documentId], - ); - - return { - changeParserLoading: loading, - onChangeParserOk, - changeParserVisible, - hideChangeParserModal, - showChangeParserModal, - }; -}; - -export const useGetRowSelection = () => { - const [selectedRowKeys, setSelectedRowKeys] = useState([]); - - const rowSelection: TableRowSelection = { - selectedRowKeys, - onChange: (newSelectedRowKeys: React.Key[]) => { - setSelectedRowKeys(newSelectedRowKeys); - }, - }; - - return rowSelection; -}; - -export const useHandleUploadDocument = () => { - const { - visible: documentUploadVisible, - hideModal: hideDocumentUploadModal, - showModal: showDocumentUploadModal, - } = useSetModalState(); - const [fileList, setFileList] = useState([]); - const [uploadProgress, setUploadProgress] = useState(0); - const { uploadDocument, loading } = useUploadNextDocument(); - const { runDocumentByIds } = useRunNextDocument(); - - const onDocumentUploadOk = useCallback( - async ({ - parseOnCreation, - directoryFileList, - }: { - directoryFileList: UploadFile[]; - parseOnCreation: boolean; - }): Promise => { - const processFileGroup = async (filesPart: UploadFile[]) => { - // set status to uploading on files - setFileList( - fileList.map((file) => { - if (!filesPart.includes(file)) { - return file; - } - - let newFile = file; - newFile.status = 'uploading'; - newFile.percent = 1; - return newFile; - }), - ); - - const ret = await uploadDocument(filesPart); - - const files = ret?.data || []; - const successfulFilenames = files.map((file: any) => file.name); - - // set status to done or error on files (based on response) - setFileList( - fileList.map((file) => { - if (!filesPart.includes(file)) { - return file; - } - - let newFile = file; - newFile.status = successfulFilenames.includes(file.name) - ? 'done' - : 'error'; - newFile.percent = 100; - newFile.response = ret.message; - return newFile; - }), - ); - - return { - code: ret?.code, - fileIds: files.map((file: any) => file.id), - totalSuccess: successfulFilenames.length, - }; - }; - const totalFiles = fileList.length; - - if (directoryFileList.length > 0) { - const ret = await uploadDocument(directoryFileList); - if (ret?.code === 0) { - hideDocumentUploadModal(); - } - if (totalFiles === 0) { - return 0; - } - } - - if (totalFiles === 0) { - console.log('No files to upload'); - hideDocumentUploadModal(); - return 0; - } - - let totalSuccess = 0; - let codes = []; - let toRunFileIds: any[] = []; - for (let i = 0; i < totalFiles; i += 10) { - setUploadProgress(Math.floor((i / totalFiles) * 100)); - const files = fileList.slice(i, i + 10); - const { - code, - totalSuccess: count, - fileIds, - } = await processFileGroup(files); - codes.push(code); - totalSuccess += count; - toRunFileIds = toRunFileIds.concat(fileIds); - } - - const allSuccess = codes.every((code) => code === 0); - const any500 = codes.some((code) => code === 500); - - let code = 500; - if (allSuccess || (any500 && totalSuccess === totalFiles)) { - code = 0; - hideDocumentUploadModal(); - } - - if (parseOnCreation) { - await runDocumentByIds({ - documentIds: toRunFileIds, - run: 1, - shouldDelete: false, - }); - } - - setUploadProgress(100); - - return code; - }, - [fileList, uploadDocument, hideDocumentUploadModal, runDocumentByIds], - ); - - return { - documentUploadLoading: loading, - onDocumentUploadOk, - documentUploadVisible, - hideDocumentUploadModal, - showDocumentUploadModal, - uploadFileList: fileList, - setUploadFileList: setFileList, - uploadProgress, - setUploadProgress, - }; -}; - -export const useHandleWebCrawl = () => { - const { - visible: webCrawlUploadVisible, - hideModal: hideWebCrawlUploadModal, - showModal: showWebCrawlUploadModal, - } = useSetModalState(); - const { webCrawl, loading } = useNextWebCrawl(); - - const onWebCrawlUploadOk = useCallback( - async (name: string, url: string) => { - const ret = await webCrawl({ name, url }); - if (ret === 0) { - hideWebCrawlUploadModal(); - return 0; - } - return -1; - }, - [webCrawl, hideWebCrawlUploadModal], - ); - - return { - webCrawlUploadLoading: loading, - onWebCrawlUploadOk, - webCrawlUploadVisible, - hideWebCrawlUploadModal, - showWebCrawlUploadModal, - }; -}; - -export const useHandleRunDocumentByIds = (id: string) => { - const { runDocumentByIds, loading } = useRunNextDocument(); - const [currentId, setCurrentId] = useState(''); - const isLoading = loading && currentId !== '' && currentId === id; - - const handleRunDocumentByIds = async ( - documentId: string, - isRunning: boolean, - shouldDelete: boolean = false, - ) => { - if (isLoading) { - return; - } - setCurrentId(documentId); - try { - await runDocumentByIds({ - documentIds: [documentId], - run: isRunning ? 2 : 1, - shouldDelete, - }); - setCurrentId(''); - } catch (error) { - setCurrentId(''); - } - }; - - return { - handleRunDocumentByIds, - loading: isLoading, - }; -}; - -export const useShowMetaModal = (documentId: string) => { - const { setDocumentMeta, loading } = useSetDocumentMeta(); - - const { - visible: setMetaVisible, - hideModal: hideSetMetaModal, - showModal: showSetMetaModal, - } = useSetModalState(); - - const onSetMetaModalOk = useCallback( - async (meta: string) => { - const ret = await setDocumentMeta({ - documentId, - meta, - }); - if (ret === 0) { - hideSetMetaModal(); - } - }, - [setDocumentMeta, documentId, hideSetMetaModal], - ); - - return { - setMetaLoading: loading, - onSetMetaModalOk, - setMetaVisible, - hideSetMetaModal, - showSetMetaModal, - }; -}; diff --git a/web/src/pages/add-knowledge/components/knowledge-file/index.less b/web/src/pages/add-knowledge/components/knowledge-file/index.less deleted file mode 100644 index 6962a8929..000000000 --- a/web/src/pages/add-knowledge/components/knowledge-file/index.less +++ /dev/null @@ -1,54 +0,0 @@ -.datasetWrapper { - padding: 30px 30px 0; - height: 100%; -} - -.documentTable { - tbody { - // height: calc(100vh - 508px); - } -} - -.filter { - height: 32px; - display: flex; - margin: 10px 0; - justify-content: space-between; - padding: 24px 0; - align-items: center; -} - -.deleteIconWrapper { - width: 22px; - text-align: center; -} - -.img { - height: 24px; - width: 24px; - display: inline-block; - vertical-align: middle; -} - -.column { - min-width: 200px; -} - -.toChunks { - cursor: pointer; -} - -.pageInputNumber { - width: 220px; -} - -.questionIcon { - margin-inline-start: 4px; - color: rgba(0, 0, 0, 0.45); - cursor: help; - writing-mode: horizontal-tb; -} - -.nameText { - color: #1677ff; -} diff --git a/web/src/pages/add-knowledge/components/knowledge-file/index.tsx b/web/src/pages/add-knowledge/components/knowledge-file/index.tsx deleted file mode 100644 index 2787ce476..000000000 --- a/web/src/pages/add-knowledge/components/knowledge-file/index.tsx +++ /dev/null @@ -1,275 +0,0 @@ -import ChunkMethodModal from '@/components/chunk-method-modal'; -import SvgIcon from '@/components/svg-icon'; -import { - useFetchNextDocumentList, - useSetNextDocumentStatus, -} from '@/hooks/document-hooks'; -import { useSetSelectedRecord } from '@/hooks/logic-hooks'; -import { useSelectParserList } from '@/hooks/user-setting-hooks'; -import { getExtension } from '@/utils/document-util'; -import { Divider, Flex, Switch, Table, Tooltip, Typography } from 'antd'; -import type { ColumnsType } from 'antd/es/table'; -import { useTranslation } from 'react-i18next'; -import CreateFileModal from './create-file-modal'; -import DocumentToolbar from './document-toolbar'; -import { - useChangeDocumentParser, - useCreateEmptyDocument, - useGetRowSelection, - useHandleUploadDocument, - useHandleWebCrawl, - useNavigateToOtherPage, - useRenameDocument, - useShowMetaModal, -} from './hooks'; -import ParsingActionCell from './parsing-action-cell'; -import ParsingStatusCell from './parsing-status-cell'; -import RenameModal from './rename-modal'; -import WebCrawlModal from './web-crawl-modal'; - -import FileUploadModal from '@/components/file-upload-modal'; -import { RunningStatus } from '@/constants/knowledge'; -import { IDocumentInfo } from '@/interfaces/database/document'; -import { formatDate } from '@/utils/date'; -import { CircleHelp } from 'lucide-react'; -import styles from './index.less'; -import { SetMetaModal } from './set-meta-modal'; - -const { Text } = Typography; - -const KnowledgeFile = () => { - const { searchString, documents, pagination, handleInputChange } = - useFetchNextDocumentList(); - const parserList = useSelectParserList(); - const { setDocumentStatus } = useSetNextDocumentStatus(); - const { toChunk } = useNavigateToOtherPage(); - const { currentRecord, setRecord } = useSetSelectedRecord(); - const { - renameLoading, - onRenameOk, - renameVisible, - hideRenameModal, - showRenameModal, - } = useRenameDocument(currentRecord.id); - const { - createLoading, - onCreateOk, - createVisible, - hideCreateModal, - showCreateModal, - } = useCreateEmptyDocument(); - const { - changeParserLoading, - onChangeParserOk, - changeParserVisible, - hideChangeParserModal, - showChangeParserModal, - } = useChangeDocumentParser(currentRecord.id); - const { - documentUploadVisible, - hideDocumentUploadModal, - showDocumentUploadModal, - onDocumentUploadOk, - documentUploadLoading, - uploadFileList, - setUploadFileList, - uploadProgress, - setUploadProgress, - } = useHandleUploadDocument(); - const { - webCrawlUploadVisible, - hideWebCrawlUploadModal, - showWebCrawlUploadModal, - onWebCrawlUploadOk, - webCrawlUploadLoading, - } = useHandleWebCrawl(); - const { t } = useTranslation('translation', { - keyPrefix: 'knowledgeDetails', - }); - - const { - showSetMetaModal, - hideSetMetaModal, - setMetaVisible, - setMetaLoading, - onSetMetaModalOk, - } = useShowMetaModal(currentRecord.id); - - const rowSelection = useGetRowSelection(); - - const columns: ColumnsType = [ - { - title: t('name'), - dataIndex: 'name', - key: 'name', - fixed: 'left', - render: (text: any, { id, thumbnail, name }) => ( -
toChunk(id)}> - - {thumbnail ? ( - - ) : ( - - )} - - {text} - - -
- ), - }, - { - title: t('chunkNumber'), - dataIndex: 'chunk_num', - key: 'chunk_num', - }, - { - title: t('uploadDate'), - dataIndex: 'create_time', - key: 'create_time', - render(value) { - return formatDate(value); - }, - }, - { - title: t('chunkMethod'), - dataIndex: 'parser_id', - key: 'parser_id', - render: (text) => { - return parserList.find((x) => x.value === text)?.label; - }, - }, - { - title: t('enabled'), - key: 'status', - dataIndex: 'status', - render: (_, { status, id }) => ( - <> - { - setDocumentStatus({ status: e, documentId: id }); - }} - /> - - ), - }, - { - title: ( - - {t('parsingStatus')} - - - - - ), - dataIndex: 'run', - key: 'run', - filters: Object.values(RunningStatus).map((value) => ({ - text: t(`runningStatus${value}`), - value: value, - })), - onFilter: (value, record: IDocumentInfo) => record.run === value, - render: (text, record) => { - return ; - }, - }, - { - title: t('action'), - key: 'action', - render: (_, record) => ( - - ), - }, - ]; - - const finalColumns = columns.map((x) => ({ - ...x, - className: `${styles.column}`, - })); - - return ( -
-

{t('dataset')}

-

{t('datasetDescription')}

- - - - - - - - - {setMetaVisible && ( - - )} - - ); -}; - -export default KnowledgeFile; diff --git a/web/src/pages/add-knowledge/components/knowledge-file/parsing-action-cell/index.less b/web/src/pages/add-knowledge/components/knowledge-file/parsing-action-cell/index.less deleted file mode 100644 index 6353670fa..000000000 --- a/web/src/pages/add-knowledge/components/knowledge-file/parsing-action-cell/index.less +++ /dev/null @@ -1,3 +0,0 @@ -.iconButton { - padding: 4px 8px; -} diff --git a/web/src/pages/add-knowledge/components/knowledge-file/parsing-action-cell/index.tsx b/web/src/pages/add-knowledge/components/knowledge-file/parsing-action-cell/index.tsx deleted file mode 100644 index ac5f1eec8..000000000 --- a/web/src/pages/add-knowledge/components/knowledge-file/parsing-action-cell/index.tsx +++ /dev/null @@ -1,149 +0,0 @@ -import { useShowDeleteConfirm, useTranslate } from '@/hooks/common-hooks'; -import { useRemoveNextDocument } from '@/hooks/document-hooks'; -import { IDocumentInfo } from '@/interfaces/database/document'; -import { downloadDocument } from '@/utils/file-util'; -import { - DeleteOutlined, - DownloadOutlined, - EditOutlined, - ToolOutlined, -} from '@ant-design/icons'; -import { Button, Dropdown, MenuProps, Space, Tooltip } from 'antd'; -import { isParserRunning } from '../utils'; - -import { useCallback } from 'react'; -import { DocumentType } from '../constant'; -import styles from './index.less'; - -interface IProps { - record: IDocumentInfo; - setCurrentRecord: (record: IDocumentInfo) => void; - showRenameModal: () => void; - showChangeParserModal: () => void; - showSetMetaModal: () => void; -} - -const ParsingActionCell = ({ - record, - setCurrentRecord, - showRenameModal, - showChangeParserModal, - showSetMetaModal, -}: IProps) => { - const documentId = record.id; - const isRunning = isParserRunning(record.run); - const { t } = useTranslate('knowledgeDetails'); - const { removeDocument } = useRemoveNextDocument(); - const showDeleteConfirm = useShowDeleteConfirm(); - const isVirtualDocument = record.type === DocumentType.Virtual; - - const onRmDocument = () => { - if (!isRunning) { - showDeleteConfirm({ - onOk: () => removeDocument([documentId]), - content: record?.parser_config?.graphrag?.use_graphrag - ? t('deleteDocumentConfirmContent') - : '', - }); - } - }; - - const onDownloadDocument = () => { - downloadDocument({ - id: documentId, - filename: record.name, - }); - }; - - const setRecord = useCallback(() => { - setCurrentRecord(record); - }, [record, setCurrentRecord]); - - const onShowRenameModal = () => { - setRecord(); - showRenameModal(); - }; - const onShowChangeParserModal = () => { - setRecord(); - showChangeParserModal(); - }; - - const onShowSetMetaModal = useCallback(() => { - setRecord(); - showSetMetaModal(); - }, [setRecord, showSetMetaModal]); - - const chunkItems: MenuProps['items'] = [ - { - key: '1', - label: ( -
- -
- ), - }, - { type: 'divider' }, - { - key: '2', - label: ( -
- -
- ), - }, - ]; - - return ( - - {isVirtualDocument || ( - - - - )} - - - - - - - {isVirtualDocument || ( - - - - )} - - ); -}; - -export default ParsingActionCell; diff --git a/web/src/pages/add-knowledge/components/knowledge-file/parsing-status-cell/index.less b/web/src/pages/add-knowledge/components/knowledge-file/parsing-status-cell/index.less deleted file mode 100644 index 7ca657a6c..000000000 --- a/web/src/pages/add-knowledge/components/knowledge-file/parsing-status-cell/index.less +++ /dev/null @@ -1,36 +0,0 @@ -.popoverContent { - width: 40vw; - - .popoverContentItem { - display: flex; - gap: 10px; - } - - .popoverContentText { - white-space: pre-line; - max-height: 50vh; - overflow: auto; - .popoverContentErrorLabel { - color: red; - } - } -} - -.operationIcon { - text-align: center; - display: flex; - &:hover { - cursor: pointer; - } -} -.operationIconSpin { - animation: spin 1s linear infinite; - @keyframes spin { - 0% { - transform: rotate(0deg); - } - 100% { - transform: rotate(360deg); - } - } -} diff --git a/web/src/pages/add-knowledge/components/knowledge-file/parsing-status-cell/index.tsx b/web/src/pages/add-knowledge/components/knowledge-file/parsing-status-cell/index.tsx deleted file mode 100644 index 184ea6e2f..000000000 --- a/web/src/pages/add-knowledge/components/knowledge-file/parsing-status-cell/index.tsx +++ /dev/null @@ -1,143 +0,0 @@ -import { ReactComponent as CancelIcon } from '@/assets/svg/cancel.svg'; -import { ReactComponent as RefreshIcon } from '@/assets/svg/refresh.svg'; -import { ReactComponent as RunIcon } from '@/assets/svg/run.svg'; -import { useTranslate } from '@/hooks/common-hooks'; -import { IDocumentInfo } from '@/interfaces/database/document'; -import { - Badge, - DescriptionsProps, - Flex, - Popconfirm, - Popover, - Space, - Tag, -} from 'antd'; -import classNames from 'classnames'; -import { useTranslation } from 'react-i18next'; -import reactStringReplace from 'react-string-replace'; -import { DocumentType, RunningStatus, RunningStatusMap } from '../constant'; -import { useHandleRunDocumentByIds } from '../hooks'; -import { isParserRunning } from '../utils'; -import styles from './index.less'; - -const iconMap = { - [RunningStatus.UNSTART]: RunIcon, - [RunningStatus.RUNNING]: CancelIcon, - [RunningStatus.CANCEL]: RefreshIcon, - [RunningStatus.DONE]: RefreshIcon, - [RunningStatus.FAIL]: RefreshIcon, -}; - -interface IProps { - record: IDocumentInfo; -} - -const PopoverContent = ({ record }: IProps) => { - const { t } = useTranslate('knowledgeDetails'); - - const replaceText = (text: string) => { - // Remove duplicate \n - const nextText = text.replace(/(\n)\1+/g, '$1'); - - const replacedText = reactStringReplace( - nextText, - /(\[ERROR\].+\s)/g, - (match, i) => { - return ( - - {match} - - ); - }, - ); - - return replacedText; - }; - - const items: DescriptionsProps['items'] = [ - { - key: 'process_begin_at', - label: t('processBeginAt'), - children: record.process_begin_at, - }, - { - key: 'process_duration', - label: t('processDuration'), - children: `${record.process_duration.toFixed(2)} s`, - }, - { - key: 'progress_msg', - label: t('progressMsg'), - children: replaceText(record.progress_msg.trim()), - }, - ]; - - return ( - - {items.map((x, idx) => { - return ( -
- {x.label}: -
{x.children}
-
- ); - })} -
- ); -}; - -export const ParsingStatusCell = ({ record }: IProps) => { - const text = record.run; - const runningStatus = RunningStatusMap[text]; - const { t } = useTranslation(); - const { handleRunDocumentByIds } = useHandleRunDocumentByIds(record.id); - - const isRunning = isParserRunning(text); - - const OperationIcon = iconMap[text]; - - const label = t(`knowledgeDetails.runningStatus${text}`); - - const handleOperationIconClick = - (shouldDelete: boolean = false) => - () => { - handleRunDocumentByIds(record.id, isRunning, shouldDelete); - }; - - return record.type === DocumentType.Virtual ? null : ( - - }> - - {isRunning ? ( - - - {label} - {(record.progress * 100).toFixed(2)}% - - ) : ( - label - )} - - - -
{} - } - > - -
-
-
- ); -}; - -export default ParsingStatusCell; diff --git a/web/src/pages/add-knowledge/components/knowledge-file/rename-modal/index.tsx b/web/src/pages/add-knowledge/components/knowledge-file/rename-modal/index.tsx deleted file mode 100644 index 7ff590e61..000000000 --- a/web/src/pages/add-knowledge/components/knowledge-file/rename-modal/index.tsx +++ /dev/null @@ -1,75 +0,0 @@ -import { IModalManagerChildrenProps } from '@/components/modal-manager'; -import { useTranslate } from '@/hooks/common-hooks'; -import { Form, Input, Modal } from 'antd'; -import { useEffect } from 'react'; - -interface IProps extends Omit { - loading: boolean; - initialName: string; - onOk: (name: string) => void; - showModal?(): void; -} - -const RenameModal = ({ - visible, - onOk, - loading, - initialName, - hideModal, -}: IProps) => { - const [form] = Form.useForm(); - const { t } = useTranslate('common'); - type FieldType = { - name?: string; - }; - - const handleOk = async () => { - const ret = await form.validateFields(); - onOk(ret.name); - }; - - const onFinish = (values: any) => { - console.log('Success:', values); - }; - - const onFinishFailed = (errorInfo: any) => { - console.log('Failed:', errorInfo); - }; - - useEffect(() => { - if (visible) { - form.setFieldValue('name', initialName); - } - }, [initialName, form, visible]); - - return ( - -
- - label={t('name')} - name="name" - rules={[{ required: true, message: t('namePlaceholder') }]} - > - - - -
- ); -}; - -export default RenameModal; diff --git a/web/src/pages/add-knowledge/components/knowledge-file/set-meta-modal/index.tsx b/web/src/pages/add-knowledge/components/knowledge-file/set-meta-modal/index.tsx deleted file mode 100644 index c51ac8cb6..000000000 --- a/web/src/pages/add-knowledge/components/knowledge-file/set-meta-modal/index.tsx +++ /dev/null @@ -1,81 +0,0 @@ -import { IModalProps } from '@/interfaces/common'; -import { IDocumentInfo } from '@/interfaces/database/document'; -import Editor, { loader } from '@monaco-editor/react'; - -import { Form, Modal } from 'antd'; -import DOMPurify from 'dompurify'; -import { useCallback, useEffect } from 'react'; -import { useTranslation } from 'react-i18next'; - -loader.config({ paths: { vs: '/vs' } }); - -type FieldType = { - meta?: string; -}; - -export function SetMetaModal({ - visible, - hideModal, - onOk, - initialMetaData, -}: IModalProps & { initialMetaData?: IDocumentInfo['meta_fields'] }) { - const { t } = useTranslation(); - const [form] = Form.useForm(); - - const handleOk = useCallback(async () => { - const values = await form.validateFields(); - onOk?.(values.meta); - }, [form, onOk]); - - useEffect(() => { - form.setFieldValue('meta', JSON.stringify(initialMetaData, null, 4)); - }, [form, initialMetaData]); - - return ( - -
- - label={t('knowledgeDetails.metaData')} - name="meta" - rules={[ - { - required: true, - validator(rule, value) { - try { - JSON.parse(value); - return Promise.resolve(); - } catch (error) { - return Promise.reject( - new Error(t('knowledgeDetails.pleaseInputJson')), - ); - } - }, - }, - ]} - tooltip={ -
- } - > - - - -
- ); -} diff --git a/web/src/pages/add-knowledge/components/knowledge-file/utils.ts b/web/src/pages/add-knowledge/components/knowledge-file/utils.ts deleted file mode 100644 index 0965ffdb9..000000000 --- a/web/src/pages/add-knowledge/components/knowledge-file/utils.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { RunningStatus } from './constant'; - -export const isParserRunning = (text: RunningStatus) => { - const isRunning = text === RunningStatus.RUNNING; - return isRunning; -}; diff --git a/web/src/pages/add-knowledge/components/knowledge-file/web-crawl-modal.tsx b/web/src/pages/add-knowledge/components/knowledge-file/web-crawl-modal.tsx deleted file mode 100644 index d8617e29e..000000000 --- a/web/src/pages/add-knowledge/components/knowledge-file/web-crawl-modal.tsx +++ /dev/null @@ -1,67 +0,0 @@ -import { IModalManagerChildrenProps } from '@/components/modal-manager'; -import { useTranslate } from '@/hooks/common-hooks'; -import { Form, Input, Modal } from 'antd'; -import React from 'react'; - -interface IProps extends Omit { - loading: boolean; - onOk: (name: string, url: string) => void; - showModal?(): void; -} - -const WebCrawlModal: React.FC = ({ visible, hideModal, onOk }) => { - const [form] = Form.useForm(); - const { t } = useTranslate('knowledgeDetails'); - const handleOk = async () => { - const values = await form.validateFields(); - onOk(values.name, values.url); - }; - - return ( - -
- - - - - - - -
- ); -}; -export default WebCrawlModal; diff --git a/web/src/pages/add-knowledge/components/knowledge-graph/constant.ts b/web/src/pages/add-knowledge/components/knowledge-graph/constant.ts deleted file mode 100644 index fc7d3561f..000000000 --- a/web/src/pages/add-knowledge/components/knowledge-graph/constant.ts +++ /dev/null @@ -1,241 +0,0 @@ -const nodes = [ - { - type: '"ORGANIZATION"', - description: - '"厦门象屿是一家公司,其营业收入和市场占有率在2018年至2022年间有所变化。"', - source_id: '0', - id: '"厦门象屿"', - }, - { - type: '"EVENT"', - description: - '"2018年是一个时间点,标志着厦门象屿营业收入和市场占有率的记录开始。"', - source_id: '0', - entity_type: '"EVENT"', - id: '"2018"', - }, - { - type: '"EVENT"', - description: - '"2019年是一个时间点,厦门象屿的营业收入和市场占有率在此期间有所变化。"', - source_id: '0', - entity_type: '"EVENT"', - id: '"2019"', - }, - { - type: '"EVENT"', - description: - '"2020年是一个时间点,厦门象屿的营业收入和市场占有率在此期间有所变化。"', - source_id: '0', - entity_type: '"EVENT"', - id: '"2020"', - }, - { - type: '"EVENT"', - description: - '"2021年是一个时间点,厦门象屿的营业收入和市场占有率在此期间有所变化。"', - source_id: '0', - entity_type: '"EVENT"', - id: '"2021"', - }, - { - type: '"EVENT"', - description: - '"2022年是一个时间点,厦门象屿的营业收入和市场占有率在此期间有所变化。"', - source_id: '0', - entity_type: '"EVENT"', - id: '"2022"', - }, - { - type: '"ORGANIZATION"', - description: - '"厦门象屿股份有限公司是一家公司,中文简称为厦门象屿,外文名称为Xiamen Xiangyu Co.,Ltd.,外文名称缩写为Xiangyu,法定代表人为邓启东。"', - source_id: '1', - id: '"厦门象屿股份有限公司"', - }, - { - type: '"PERSON"', - description: '"邓启东是厦门象屿股份有限公司的法定代表人。"', - source_id: '1', - entity_type: '"PERSON"', - id: '"邓启东"', - }, - { - type: '"GEO"', - description: '"厦门是一个地理位置,与厦门象屿股份有限公司相关。"', - source_id: '1', - entity_type: '"GEO"', - id: '"厦门"', - }, - { - type: '"PERSON"', - description: - '"廖杰 is the Board Secretary, responsible for handling board-related matters and communications."', - source_id: '2', - id: '"廖杰"', - }, - { - type: '"PERSON"', - description: - '"史经洋 is the Securities Affairs Representative, responsible for handling securities-related matters and communications."', - source_id: '2', - entity_type: '"PERSON"', - id: '"史经洋"', - }, - { - type: '"GEO"', - description: - '"A geographic location in Xiamen, specifically in the Free Trade Zone, where the company\'s office is situated."', - source_id: '2', - entity_type: '"GEO"', - id: '"厦门市湖里区自由贸易试验区厦门片区"', - }, - { - type: '"GEO"', - description: - '"The building where the company\'s office is located, situated at Xiangyu Road, Xiamen."', - source_id: '2', - entity_type: '"GEO"', - id: '"象屿集团大厦"', - }, - { - type: '"EVENT"', - description: - '"Refers to the year 2021, used for comparing financial metrics with the year 2022."', - source_id: '3', - id: '"2021年"', - }, - { - type: '"EVENT"', - description: - '"Refers to the year 2022, used for presenting current financial metrics and comparing them with the year 2021."', - source_id: '3', - entity_type: '"EVENT"', - id: '"2022年"', - }, - { - type: '"EVENT"', - description: - '"Indicates the focus on key financial metrics in the table, such as weighted averages and percentages."', - source_id: '3', - entity_type: '"EVENT"', - id: '"主要财务指标"', - }, -].map(({ type, ...x }) => ({ ...x })); - -const edges = [ - { - weight: 2.0, - description: '"厦门象屿在2018年的营业收入和市场占有率被记录。"', - source_id: '0', - source: '"厦门象屿"', - target: '"2018"', - }, - { - weight: 2.0, - description: '"厦门象屿在2019年的营业收入和市场占有率有所变化。"', - source_id: '0', - source: '"厦门象屿"', - target: '"2019"', - }, - { - weight: 2.0, - description: '"厦门象屿在2020年的营业收入和市场占有率有所变化。"', - source_id: '0', - source: '"厦门象屿"', - target: '"2020"', - }, - { - weight: 2.0, - description: '"厦门象屿在2021年的营业收入和市场占有率有所变化。"', - source_id: '0', - source: '"厦门象屿"', - target: '"2021"', - }, - { - weight: 2.0, - description: '"厦门象屿在2022年的营业收入和市场占有率有所变化。"', - source_id: '0', - source: '"厦门象屿"', - target: '"2022"', - }, - { - weight: 2.0, - description: '"厦门象屿股份有限公司的法定代表人是邓启东。"', - source_id: '1', - source: '"厦门象屿股份有限公司"', - target: '"邓启东"', - }, - { - weight: 2.0, - description: '"厦门象屿股份有限公司位于厦门。"', - source_id: '1', - source: '"厦门象屿股份有限公司"', - target: '"厦门"', - }, - { - weight: 2.0, - description: - '"廖杰\'s office is located in the Xiangyu Group Building, indicating his workplace."', - source_id: '2', - source: '"廖杰"', - target: '"象屿集团大厦"', - }, - { - weight: 2.0, - description: - '"廖杰 works in the Xiamen Free Trade Zone, a specific area within Xiamen."', - source_id: '2', - source: '"廖杰"', - target: '"厦门市湖里区自由贸易试验区厦门片区"', - }, - { - weight: 2.0, - description: - '"史经洋\'s office is also located in the Xiangyu Group Building, indicating his workplace."', - source_id: '2', - source: '"史经洋"', - target: '"象屿集团大厦"', - }, - { - weight: 2.0, - description: - '"史经洋 works in the Xiamen Free Trade Zone, a specific area within Xiamen."', - source_id: '2', - source: '"史经洋"', - target: '"厦门市湖里区自由贸易试验区厦门片区"', - }, - { - weight: 2.0, - description: - '"The years 2021 and 2022 are related as they are used for comparing financial metrics, showing changes and adjustments over time."', - source_id: '3', - source: '"2021年"', - target: '"2022年"', - }, - { - weight: 2.0, - description: - '"The \'主要财务指标\' is related to the year 2021 as it provides the basis for financial comparisons and adjustments."', - source_id: '3', - source: '"2021年"', - target: '"主要财务指标"', - }, - { - weight: 2.0, - description: - '"The \'主要财务指标\' is related to the year 2022 as it presents the current financial metrics and their changes compared to 2021."', - source_id: '3', - source: '"2022年"', - target: '"主要财务指标"', - }, -]; - -export const graphData = { - directed: false, - multigraph: false, - graph: {}, - nodes, - edges, - combos: [], -}; diff --git a/web/src/pages/add-knowledge/components/knowledge-graph/force-graph.tsx b/web/src/pages/add-knowledge/components/knowledge-graph/force-graph.tsx deleted file mode 100644 index d2547e959..000000000 --- a/web/src/pages/add-knowledge/components/knowledge-graph/force-graph.tsx +++ /dev/null @@ -1,141 +0,0 @@ -import { ElementDatum, Graph, IElementEvent } from '@antv/g6'; -import isEmpty from 'lodash/isEmpty'; -import { useCallback, useEffect, useMemo, useRef } from 'react'; -import { buildNodesAndCombos } from './util'; - -import styles from './index.less'; - -const TooltipColorMap = { - combo: 'red', - node: 'black', - edge: 'blue', -}; - -interface IProps { - data: any; - show: boolean; -} - -const ForceGraph = ({ data, show }: IProps) => { - const containerRef = useRef(null); - const graphRef = useRef(null); - - const nextData = useMemo(() => { - if (!isEmpty(data)) { - const graphData = data; - const mi = buildNodesAndCombos(graphData.nodes); - return { edges: graphData.edges, ...mi }; - } - return { nodes: [], edges: [] }; - }, [data]); - - const render = useCallback(() => { - const graph = new Graph({ - container: containerRef.current!, - autoFit: 'view', - autoResize: true, - behaviors: [ - 'drag-element', - 'drag-canvas', - 'zoom-canvas', - 'collapse-expand', - { - type: 'hover-activate', - degree: 1, // 👈🏻 Activate relations. - }, - ], - plugins: [ - { - type: 'tooltip', - enterable: true, - getContent: (e: IElementEvent, items: ElementDatum) => { - if (Array.isArray(items)) { - if (items.some((x) => x?.isCombo)) { - return `

${items?.[0]?.data?.label}

`; - } - let result = ``; - items.forEach((item) => { - result += `

${item?.id}

`; - if (item?.entity_type) { - result += `
Entity type: ${item?.entity_type}
`; - } - if (item?.weight) { - result += `
Weight: ${item?.weight}
`; - } - if (item?.description) { - result += `

${item?.description}

`; - } - }); - return result + '
'; - } - return undefined; - }, - }, - ], - layout: { - type: 'combo-combined', - preventOverlap: true, - comboPadding: 1, - spacing: 100, - }, - node: { - style: { - size: 150, - labelText: (d) => d.id, - // labelPadding: 30, - labelFontSize: 40, - // labelOffsetX: 20, - labelOffsetY: 20, - labelPlacement: 'center', - labelWordWrap: true, - }, - palette: { - type: 'group', - field: (d) => { - return d?.entity_type as string; - }, - }, - }, - edge: { - style: (model) => { - const weight: number = Number(model?.weight) || 2; - const lineWeight = weight * 4; - return { - stroke: '#99ADD1', - lineWidth: lineWeight > 10 ? 10 : lineWeight, - }; - }, - }, - }); - - if (graphRef.current) { - graphRef.current.destroy(); - } - - graphRef.current = graph; - - graph.setData(nextData); - - graph.render(); - }, [nextData]); - - useEffect(() => { - if (!isEmpty(data)) { - render(); - } - }, [data, render]); - - return ( -
- ); -}; - -export default ForceGraph; diff --git a/web/src/pages/add-knowledge/components/knowledge-graph/index.less b/web/src/pages/add-knowledge/components/knowledge-graph/index.less deleted file mode 100644 index 7c5d1f5a8..000000000 --- a/web/src/pages/add-knowledge/components/knowledge-graph/index.less +++ /dev/null @@ -1,5 +0,0 @@ -.forceContainer { - :global(.tooltip) { - border-radius: 10px !important; - } -} diff --git a/web/src/pages/add-knowledge/components/knowledge-graph/index.tsx b/web/src/pages/add-knowledge/components/knowledge-graph/index.tsx deleted file mode 100644 index 1c33438e5..000000000 --- a/web/src/pages/add-knowledge/components/knowledge-graph/index.tsx +++ /dev/null @@ -1,31 +0,0 @@ -import { ConfirmDeleteDialog } from '@/components/confirm-delete-dialog'; -import { Button } from '@/components/ui/button'; -import { useFetchKnowledgeGraph } from '@/hooks/knowledge-hooks'; -import { Trash2 } from 'lucide-react'; -import React from 'react'; -import { useTranslation } from 'react-i18next'; -import ForceGraph from './force-graph'; -import { useDeleteKnowledgeGraph } from './use-delete-graph'; - -const KnowledgeGraph: React.FC = () => { - const { data } = useFetchKnowledgeGraph(); - const { t } = useTranslation(); - const { handleDeleteKnowledgeGraph } = useDeleteKnowledgeGraph(); - - return ( -
- - - - -
- ); -}; - -export default KnowledgeGraph; diff --git a/web/src/pages/add-knowledge/components/knowledge-graph/use-delete-graph.ts b/web/src/pages/add-knowledge/components/knowledge-graph/use-delete-graph.ts deleted file mode 100644 index 49c42986f..000000000 --- a/web/src/pages/add-knowledge/components/knowledge-graph/use-delete-graph.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { - useKnowledgeBaseId, - useRemoveKnowledgeGraph, -} from '@/hooks/knowledge-hooks'; -import { useCallback } from 'react'; -import { useNavigate } from 'umi'; - -export function useDeleteKnowledgeGraph() { - const { removeKnowledgeGraph, loading } = useRemoveKnowledgeGraph(); - const navigate = useNavigate(); - const knowledgeBaseId = useKnowledgeBaseId(); - - const handleDeleteKnowledgeGraph = useCallback(async () => { - const ret = await removeKnowledgeGraph(); - if (ret === 0) { - navigate(`/knowledge/dataset?id=${knowledgeBaseId}`); - } - }, [knowledgeBaseId, navigate, removeKnowledgeGraph]); - - return { handleDeleteKnowledgeGraph, loading }; -} diff --git a/web/src/pages/add-knowledge/components/knowledge-graph/util.ts b/web/src/pages/add-knowledge/components/knowledge-graph/util.ts deleted file mode 100644 index e0be797f2..000000000 --- a/web/src/pages/add-knowledge/components/knowledge-graph/util.ts +++ /dev/null @@ -1,94 +0,0 @@ -import { isEmpty } from 'lodash'; -import { v4 as uuid } from 'uuid'; - -class KeyGenerator { - idx = 0; - chars: string[] = []; - constructor() { - const chars = Array(26) - .fill(1) - .map((x, idx) => String.fromCharCode(97 + idx)); // 26 char - this.chars = chars; - } - generateKey() { - const key = this.chars[this.idx]; - this.idx++; - return key; - } -} - -// Classify nodes based on edge relationships -export class Converter { - keyGenerator; - dict: Record = {}; // key is node id, value is combo - constructor() { - this.keyGenerator = new KeyGenerator(); - } - buildDict(edges: { source: string; target: string }[]) { - edges.forEach((x) => { - if (this.dict[x.source] && !this.dict[x.target]) { - this.dict[x.target] = this.dict[x.source]; - } else if (!this.dict[x.source] && this.dict[x.target]) { - this.dict[x.source] = this.dict[x.target]; - } else if (!this.dict[x.source] && !this.dict[x.target]) { - this.dict[x.source] = this.dict[x.target] = - this.keyGenerator.generateKey(); - } - }); - return this.dict; - } - buildNodesAndCombos(nodes: any[], edges: any[]) { - this.buildDict(edges); - const nextNodes = nodes.map((x) => ({ ...x, combo: this.dict[x.id] })); - - const combos = Object.values(this.dict).reduce((pre, cur) => { - if (pre.every((x) => x.id !== cur)) { - pre.push({ - id: cur, - data: { - label: `Combo ${cur}`, - }, - }); - } - return pre; - }, []); - - return { nodes: nextNodes, combos }; - } -} - -export const isDataExist = (data: any) => { - return ( - data?.data && typeof data?.data !== 'boolean' && !isEmpty(data?.data?.graph) - ); -}; - -const findCombo = (communities: string[]) => { - const combo = Array.isArray(communities) ? communities[0] : undefined; - return combo; -}; - -export const buildNodesAndCombos = (nodes: any[]) => { - const combos: any[] = []; - nodes.forEach((x) => { - const combo = findCombo(x?.communities); - if (combo && combos.every((y) => y.data.label !== combo)) { - combos.push({ - isCombo: true, - id: uuid(), - data: { - label: combo, - }, - }); - } - }); - - const nextNodes = nodes.map((x) => { - return { - ...x, - combo: combos.find((y) => y.data.label === findCombo(x?.communities))?.id, - }; - }); - - return { nodes: nextNodes, combos }; -}; diff --git a/web/src/pages/add-knowledge/components/knowledge-setting/category-panel.tsx b/web/src/pages/add-knowledge/components/knowledge-setting/category-panel.tsx deleted file mode 100644 index 4e96fefcc..000000000 --- a/web/src/pages/add-knowledge/components/knowledge-setting/category-panel.tsx +++ /dev/null @@ -1,77 +0,0 @@ -import SvgIcon from '@/components/svg-icon'; -import { useTranslate } from '@/hooks/common-hooks'; -import { useSelectParserList } from '@/hooks/user-setting-hooks'; -import { Col, Divider, Empty, Row, Typography } from 'antd'; -import DOMPurify from 'dompurify'; -import camelCase from 'lodash/camelCase'; -import { useMemo } from 'react'; -import styles from './index.less'; -import { TagTabs } from './tag-tabs'; -import { ImageMap } from './utils'; - -const { Text } = Typography; - -const CategoryPanel = ({ chunkMethod }: { chunkMethod: string }) => { - const parserList = useSelectParserList(); - const { t } = useTranslate('knowledgeConfiguration'); - - const item = useMemo(() => { - const item = parserList.find((x) => x.value === chunkMethod); - if (item) { - return { - title: item.label, - description: t(camelCase(item.value)), - }; - } - return { title: '', description: '' }; - }, [parserList, chunkMethod, t]); - - const imageList = useMemo(() => { - if (chunkMethod in ImageMap) { - return ImageMap[chunkMethod as keyof typeof ImageMap]; - } - return []; - }, [chunkMethod]); - - return ( -
- {imageList.length > 0 ? ( - <> -
- {`"${item.title}" ${t('methodTitle')}`} -
-

-
{`"${item.title}" ${t('methodExamples')}`}
- {t('methodExamplesDescription')} - - {imageList.map((x) => ( -
- - - ))} - -
- {item.title} {t('dialogueExamplesTitle')} -
- - - ) : ( - -

{t('methodEmpty')}

- -
- )} - {chunkMethod === 'tag' && } - - ); -}; - -export default CategoryPanel; diff --git a/web/src/pages/add-knowledge/components/knowledge-setting/configuration/audio.tsx b/web/src/pages/add-knowledge/components/knowledge-setting/configuration/audio.tsx deleted file mode 100644 index ff1e33223..000000000 --- a/web/src/pages/add-knowledge/components/knowledge-setting/configuration/audio.tsx +++ /dev/null @@ -1,31 +0,0 @@ -import { - AutoKeywordsItem, - AutoQuestionsItem, -} from '@/components/auto-keywords-item'; -import PageRank from '@/components/page-rank'; -import ParseConfiguration from '@/components/parse-configuration'; -import GraphRagItems from '@/components/parse-configuration/graph-rag-items'; -import { TagItems } from '../tag-item'; -import { ChunkMethodItem, EmbeddingModelItem } from './common-item'; - -export function AudioConfiguration() { - return ( - <> - - - - - - <> - - - - - - - - - - - ); -} diff --git a/web/src/pages/add-knowledge/components/knowledge-setting/configuration/book.tsx b/web/src/pages/add-knowledge/components/knowledge-setting/configuration/book.tsx deleted file mode 100644 index c1ff2b30b..000000000 --- a/web/src/pages/add-knowledge/components/knowledge-setting/configuration/book.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import { - AutoKeywordsItem, - AutoQuestionsItem, -} from '@/components/auto-keywords-item'; -import LayoutRecognize from '@/components/layout-recognize'; -import PageRank from '@/components/page-rank'; -import ParseConfiguration from '@/components/parse-configuration'; -import GraphRagItems from '@/components/parse-configuration/graph-rag-items'; -import { TagItems } from '../tag-item'; -import { ChunkMethodItem, EmbeddingModelItem } from './common-item'; - -export function BookConfiguration() { - return ( - <> - - - - - - - <> - - - - - - - - - - - ); -} diff --git a/web/src/pages/add-knowledge/components/knowledge-setting/configuration/common-item.tsx b/web/src/pages/add-knowledge/components/knowledge-setting/configuration/common-item.tsx deleted file mode 100644 index 62670e8a9..000000000 --- a/web/src/pages/add-knowledge/components/knowledge-setting/configuration/common-item.tsx +++ /dev/null @@ -1,52 +0,0 @@ -import { useTranslate } from '@/hooks/common-hooks'; -import { useHandleChunkMethodSelectChange } from '@/hooks/logic-hooks'; -import { Form, Select } from 'antd'; -import { memo } from 'react'; -import { - useHasParsedDocument, - useSelectChunkMethodList, - useSelectEmbeddingModelOptions, -} from '../hooks'; - -export const EmbeddingModelItem = memo(function EmbeddingModelItem() { - const { t } = useTranslate('knowledgeConfiguration'); - const embeddingModelOptions = useSelectEmbeddingModelOptions(); - const disabled = useHasParsedDocument(); - - return ( - - - - ); -}); - -export const ChunkMethodItem = memo(function ChunkMethodItem() { - const { t } = useTranslate('knowledgeConfiguration'); - const form = Form.useFormInstance(); - const handleChunkMethodSelectChange = useHandleChunkMethodSelectChange(form); - const parserList = useSelectChunkMethodList(); - - return ( - - - - ); -}); diff --git a/web/src/pages/add-knowledge/components/knowledge-setting/configuration/email.tsx b/web/src/pages/add-knowledge/components/knowledge-setting/configuration/email.tsx deleted file mode 100644 index c39015464..000000000 --- a/web/src/pages/add-knowledge/components/knowledge-setting/configuration/email.tsx +++ /dev/null @@ -1,31 +0,0 @@ -import { - AutoKeywordsItem, - AutoQuestionsItem, -} from '@/components/auto-keywords-item'; -import PageRank from '@/components/page-rank'; -import ParseConfiguration from '@/components/parse-configuration'; -import GraphRagItems from '@/components/parse-configuration/graph-rag-items'; -import { TagItems } from '../tag-item'; -import { ChunkMethodItem, EmbeddingModelItem } from './common-item'; - -export function EmailConfiguration() { - return ( - <> - - - - - - <> - - - - - - - - - - - ); -} diff --git a/web/src/pages/add-knowledge/components/knowledge-setting/configuration/index.tsx b/web/src/pages/add-knowledge/components/knowledge-setting/configuration/index.tsx deleted file mode 100644 index 4d142cdb4..000000000 --- a/web/src/pages/add-knowledge/components/knowledge-setting/configuration/index.tsx +++ /dev/null @@ -1,133 +0,0 @@ -import { DocumentParserType } from '@/constants/knowledge'; -import { useTranslate } from '@/hooks/common-hooks'; -import { normFile } from '@/utils/file-util'; -import { PlusOutlined } from '@ant-design/icons'; -import { Button, Form, Input, Radio, Space, Upload } from 'antd'; -import { FormInstance } from 'antd/lib'; -import { useEffect, useMemo, useState } from 'react'; -import { - useFetchKnowledgeConfigurationOnMount, - useSubmitKnowledgeConfiguration, -} from '../hooks'; -import { AudioConfiguration } from './audio'; -import { BookConfiguration } from './book'; -import { EmailConfiguration } from './email'; -import { KnowledgeGraphConfiguration } from './knowledge-graph'; -import { LawsConfiguration } from './laws'; -import { ManualConfiguration } from './manual'; -import { NaiveConfiguration } from './naive'; -import { OneConfiguration } from './one'; -import { PaperConfiguration } from './paper'; -import { PictureConfiguration } from './picture'; -import { PresentationConfiguration } from './presentation'; -import { QAConfiguration } from './qa'; -import { ResumeConfiguration } from './resume'; -import { TableConfiguration } from './table'; -import { TagConfiguration } from './tag'; - -import styles from '../index.less'; - -const ConfigurationComponentMap = { - [DocumentParserType.Naive]: NaiveConfiguration, - [DocumentParserType.Qa]: QAConfiguration, - [DocumentParserType.Resume]: ResumeConfiguration, - [DocumentParserType.Manual]: ManualConfiguration, - [DocumentParserType.Table]: TableConfiguration, - [DocumentParserType.Paper]: PaperConfiguration, - [DocumentParserType.Book]: BookConfiguration, - [DocumentParserType.Laws]: LawsConfiguration, - [DocumentParserType.Presentation]: PresentationConfiguration, - [DocumentParserType.Picture]: PictureConfiguration, - [DocumentParserType.One]: OneConfiguration, - [DocumentParserType.Audio]: AudioConfiguration, - [DocumentParserType.Email]: EmailConfiguration, - [DocumentParserType.Tag]: TagConfiguration, - [DocumentParserType.KnowledgeGraph]: KnowledgeGraphConfiguration, -}; - -function EmptyComponent() { - return
; -} - -export const ConfigurationForm = ({ form }: { form: FormInstance }) => { - const { submitKnowledgeConfiguration, submitLoading, navigateToDataset } = - useSubmitKnowledgeConfiguration(form); - const { t } = useTranslate('knowledgeConfiguration'); - - const [finalParserId, setFinalParserId] = useState(); - const knowledgeDetails = useFetchKnowledgeConfigurationOnMount(form); - const parserId: DocumentParserType = Form.useWatch('parser_id', form); - const ConfigurationComponent = useMemo(() => { - return finalParserId - ? ConfigurationComponentMap[finalParserId] - : EmptyComponent; - }, [finalParserId]); - - useEffect(() => { - setFinalParserId(parserId); - }, [parserId]); - - useEffect(() => { - setFinalParserId(knowledgeDetails.parser_id as DocumentParserType); - }, [knowledgeDetails.parser_id]); - - return ( -
- - - - - false} - showUploadList={{ showPreviewIcon: false, showRemoveIcon: false }} - > - - - - - - - - - {t('me')} - {t('team')} - - - - - - -
- - - - -
-
- - ); -}; diff --git a/web/src/pages/add-knowledge/components/knowledge-setting/configuration/knowledge-graph.tsx b/web/src/pages/add-knowledge/components/knowledge-setting/configuration/knowledge-graph.tsx deleted file mode 100644 index 8a7e3062f..000000000 --- a/web/src/pages/add-knowledge/components/knowledge-setting/configuration/knowledge-graph.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import Delimiter from '@/components/delimiter'; -import EntityTypesItem from '@/components/entity-types-item'; -import MaxTokenNumber from '@/components/max-token-number'; -import PageRank from '@/components/page-rank'; -import { ChunkMethodItem, EmbeddingModelItem } from './common-item'; - -export function KnowledgeGraphConfiguration() { - return ( - <> - - - - - - <> - - - - - - ); -} diff --git a/web/src/pages/add-knowledge/components/knowledge-setting/configuration/laws.tsx b/web/src/pages/add-knowledge/components/knowledge-setting/configuration/laws.tsx deleted file mode 100644 index c103884ec..000000000 --- a/web/src/pages/add-knowledge/components/knowledge-setting/configuration/laws.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import { - AutoKeywordsItem, - AutoQuestionsItem, -} from '@/components/auto-keywords-item'; -import LayoutRecognize from '@/components/layout-recognize'; -import PageRank from '@/components/page-rank'; -import ParseConfiguration from '@/components/parse-configuration'; -import GraphRagItems from '@/components/parse-configuration/graph-rag-items'; -import { TagItems } from '../tag-item'; -import { ChunkMethodItem, EmbeddingModelItem } from './common-item'; - -export function LawsConfiguration() { - return ( - <> - - - - - - - <> - - - - - - - - - - - ); -} diff --git a/web/src/pages/add-knowledge/components/knowledge-setting/configuration/manual.tsx b/web/src/pages/add-knowledge/components/knowledge-setting/configuration/manual.tsx deleted file mode 100644 index 71837a280..000000000 --- a/web/src/pages/add-knowledge/components/knowledge-setting/configuration/manual.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import { - AutoKeywordsItem, - AutoQuestionsItem, -} from '@/components/auto-keywords-item'; -import LayoutRecognize from '@/components/layout-recognize'; -import PageRank from '@/components/page-rank'; -import ParseConfiguration from '@/components/parse-configuration'; -import GraphRagItems from '@/components/parse-configuration/graph-rag-items'; -import { TagItems } from '../tag-item'; -import { ChunkMethodItem, EmbeddingModelItem } from './common-item'; - -export function ManualConfiguration() { - return ( - <> - - - - - - - <> - - - - - - - - - - - ); -} diff --git a/web/src/pages/add-knowledge/components/knowledge-setting/configuration/naive.tsx b/web/src/pages/add-knowledge/components/knowledge-setting/configuration/naive.tsx deleted file mode 100644 index 956f83b0f..000000000 --- a/web/src/pages/add-knowledge/components/knowledge-setting/configuration/naive.tsx +++ /dev/null @@ -1,43 +0,0 @@ -import { - AutoKeywordsItem, - AutoQuestionsItem, -} from '@/components/auto-keywords-item'; -import { DatasetConfigurationContainer } from '@/components/dataset-configuration-container'; -import Delimiter from '@/components/delimiter'; -import ExcelToHtml from '@/components/excel-to-html'; -import LayoutRecognize from '@/components/layout-recognize'; -import MaxTokenNumber from '@/components/max-token-number'; -import PageRank from '@/components/page-rank'; -import ParseConfiguration from '@/components/parse-configuration'; -import GraphRagItems from '@/components/parse-configuration/graph-rag-items'; -import { Divider } from 'antd'; -import { TagItems } from '../tag-item'; -import { ChunkMethodItem, EmbeddingModelItem } from './common-item'; - -export function NaiveConfiguration() { - return ( -
- - - - - - - - - - - - - - - - - - - - - -
- ); -} diff --git a/web/src/pages/add-knowledge/components/knowledge-setting/configuration/one.tsx b/web/src/pages/add-knowledge/components/knowledge-setting/configuration/one.tsx deleted file mode 100644 index b488ec0ff..000000000 --- a/web/src/pages/add-knowledge/components/knowledge-setting/configuration/one.tsx +++ /dev/null @@ -1,30 +0,0 @@ -import { - AutoKeywordsItem, - AutoQuestionsItem, -} from '@/components/auto-keywords-item'; -import LayoutRecognize from '@/components/layout-recognize'; -import PageRank from '@/components/page-rank'; -import GraphRagItems from '@/components/parse-configuration/graph-rag-items'; -import { TagItems } from '../tag-item'; -import { ChunkMethodItem, EmbeddingModelItem } from './common-item'; - -export function OneConfiguration() { - return ( - <> - - - - - - - <> - - - - - - - - - ); -} diff --git a/web/src/pages/add-knowledge/components/knowledge-setting/configuration/paper.tsx b/web/src/pages/add-knowledge/components/knowledge-setting/configuration/paper.tsx deleted file mode 100644 index db61b01a2..000000000 --- a/web/src/pages/add-knowledge/components/knowledge-setting/configuration/paper.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import { - AutoKeywordsItem, - AutoQuestionsItem, -} from '@/components/auto-keywords-item'; -import LayoutRecognize from '@/components/layout-recognize'; -import PageRank from '@/components/page-rank'; -import ParseConfiguration from '@/components/parse-configuration'; -import GraphRagItems from '@/components/parse-configuration/graph-rag-items'; -import { TagItems } from '../tag-item'; -import { ChunkMethodItem, EmbeddingModelItem } from './common-item'; - -export function PaperConfiguration() { - return ( - <> - - - - - - - <> - - - - - - - - - - - ); -} diff --git a/web/src/pages/add-knowledge/components/knowledge-setting/configuration/picture.tsx b/web/src/pages/add-knowledge/components/knowledge-setting/configuration/picture.tsx deleted file mode 100644 index f10b0892b..000000000 --- a/web/src/pages/add-knowledge/components/knowledge-setting/configuration/picture.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import { - AutoKeywordsItem, - AutoQuestionsItem, -} from '@/components/auto-keywords-item'; -import PageRank from '@/components/page-rank'; -import { TagItems } from '../tag-item'; -import { ChunkMethodItem, EmbeddingModelItem } from './common-item'; - -export function PictureConfiguration() { - return ( - <> - - - - - - <> - - - - - - ); -} diff --git a/web/src/pages/add-knowledge/components/knowledge-setting/configuration/presentation.tsx b/web/src/pages/add-knowledge/components/knowledge-setting/configuration/presentation.tsx deleted file mode 100644 index 84d17a5fb..000000000 --- a/web/src/pages/add-knowledge/components/knowledge-setting/configuration/presentation.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import { - AutoKeywordsItem, - AutoQuestionsItem, -} from '@/components/auto-keywords-item'; -import LayoutRecognize from '@/components/layout-recognize'; -import PageRank from '@/components/page-rank'; -import ParseConfiguration from '@/components/parse-configuration'; -import GraphRagItems from '@/components/parse-configuration/graph-rag-items'; -import { TagItems } from '../tag-item'; -import { ChunkMethodItem, EmbeddingModelItem } from './common-item'; - -export function PresentationConfiguration() { - return ( - <> - - - - - - - <> - - - - - - - - - - - ); -} diff --git a/web/src/pages/add-knowledge/components/knowledge-setting/configuration/qa.tsx b/web/src/pages/add-knowledge/components/knowledge-setting/configuration/qa.tsx deleted file mode 100644 index 1d25dff4e..000000000 --- a/web/src/pages/add-knowledge/components/knowledge-setting/configuration/qa.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import PageRank from '@/components/page-rank'; -import { TagItems } from '../tag-item'; -import { ChunkMethodItem, EmbeddingModelItem } from './common-item'; - -export function QAConfiguration() { - return ( - <> - - - - - - - - ); -} diff --git a/web/src/pages/add-knowledge/components/knowledge-setting/configuration/resume.tsx b/web/src/pages/add-knowledge/components/knowledge-setting/configuration/resume.tsx deleted file mode 100644 index 89d535d9c..000000000 --- a/web/src/pages/add-knowledge/components/knowledge-setting/configuration/resume.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import PageRank from '@/components/page-rank'; -import { TagItems } from '../tag-item'; -import { ChunkMethodItem, EmbeddingModelItem } from './common-item'; - -export function ResumeConfiguration() { - return ( - <> - - - - - - - - ); -} diff --git a/web/src/pages/add-knowledge/components/knowledge-setting/configuration/table.tsx b/web/src/pages/add-knowledge/components/knowledge-setting/configuration/table.tsx deleted file mode 100644 index 5611812fa..000000000 --- a/web/src/pages/add-knowledge/components/knowledge-setting/configuration/table.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import PageRank from '@/components/page-rank'; -import { ChunkMethodItem, EmbeddingModelItem } from './common-item'; - -export function TableConfiguration() { - return ( - <> - - - - - - ); -} diff --git a/web/src/pages/add-knowledge/components/knowledge-setting/configuration/tag.tsx b/web/src/pages/add-knowledge/components/knowledge-setting/configuration/tag.tsx deleted file mode 100644 index d2a22b228..000000000 --- a/web/src/pages/add-knowledge/components/knowledge-setting/configuration/tag.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import PageRank from '@/components/page-rank'; -import { ChunkMethodItem, EmbeddingModelItem } from './common-item'; - -export function TagConfiguration() { - return ( - <> - - - - - - ); -} diff --git a/web/src/pages/add-knowledge/components/knowledge-setting/hooks.ts b/web/src/pages/add-knowledge/components/knowledge-setting/hooks.ts deleted file mode 100644 index a065515df..000000000 --- a/web/src/pages/add-knowledge/components/knowledge-setting/hooks.ts +++ /dev/null @@ -1,121 +0,0 @@ -import { LlmModelType } from '@/constants/knowledge'; -import { useSetModalState } from '@/hooks/common-hooks'; -import { - useFetchKnowledgeBaseConfiguration, - useUpdateKnowledge, -} from '@/hooks/knowledge-hooks'; -import { useSelectLlmOptionsByModelType } from '@/hooks/llm-hooks'; -import { useNavigateToDataset } from '@/hooks/route-hook'; -import { useSelectParserList } from '@/hooks/user-setting-hooks'; -import { - getBase64FromUploadFileList, - getUploadFileListFromBase64, -} from '@/utils/file-util'; -import { useIsFetching } from '@tanstack/react-query'; -import { Form, UploadFile } from 'antd'; -import { FormInstance } from 'antd/lib'; -import pick from 'lodash/pick'; -import { useCallback, useEffect, useState } from 'react'; - -export const useSubmitKnowledgeConfiguration = (form: FormInstance) => { - const { saveKnowledgeConfiguration, loading } = useUpdateKnowledge(); - const navigateToDataset = useNavigateToDataset(); - - const submitKnowledgeConfiguration = useCallback(async () => { - const values = await form.validateFields(); - const avatar = await getBase64FromUploadFileList(values.avatar); - saveKnowledgeConfiguration({ - ...values, - avatar, - }); - navigateToDataset(); - }, [saveKnowledgeConfiguration, form, navigateToDataset]); - - return { - submitKnowledgeConfiguration, - submitLoading: loading, - navigateToDataset, - }; -}; - -// The value that does not need to be displayed in the analysis method Select -const HiddenFields = ['email', 'picture', 'audio']; - -export function useSelectChunkMethodList() { - const parserList = useSelectParserList(); - - return parserList.filter((x) => !HiddenFields.some((y) => y === x.value)); -} - -export function useSelectEmbeddingModelOptions() { - const allOptions = useSelectLlmOptionsByModelType(); - return allOptions[LlmModelType.Embedding]; -} - -export function useHasParsedDocument() { - const { data: knowledgeDetails } = useFetchKnowledgeBaseConfiguration(); - return knowledgeDetails.chunk_num > 0; -} - -export const useFetchKnowledgeConfigurationOnMount = (form: FormInstance) => { - const { data: knowledgeDetails } = useFetchKnowledgeBaseConfiguration(); - - useEffect(() => { - const fileList: UploadFile[] = getUploadFileListFromBase64( - knowledgeDetails.avatar, - ); - form.setFieldsValue({ - ...pick(knowledgeDetails, [ - 'description', - 'name', - 'permission', - 'embd_id', - 'parser_id', - 'language', - 'parser_config', - 'pagerank', - ]), - avatar: fileList, - }); - }, [form, knowledgeDetails]); - - return knowledgeDetails; -}; - -export const useSelectKnowledgeDetailsLoading = () => - useIsFetching({ queryKey: ['fetchKnowledgeDetail'] }) > 0; - -export const useHandleChunkMethodChange = () => { - const [form] = Form.useForm(); - const chunkMethod = Form.useWatch('parser_id', form); - - useEffect(() => { - console.log('🚀 ~ useHandleChunkMethodChange ~ chunkMethod:', chunkMethod); - }, [chunkMethod]); - - return { form, chunkMethod }; -}; - -export const useRenameKnowledgeTag = () => { - const [tag, setTag] = useState(''); - const { - visible: tagRenameVisible, - hideModal: hideTagRenameModal, - showModal: showFileRenameModal, - } = useSetModalState(); - - const handleShowTagRenameModal = useCallback( - (record: string) => { - setTag(record); - showFileRenameModal(); - }, - [showFileRenameModal], - ); - - return { - initialName: tag, - tagRenameVisible, - hideTagRenameModal, - showTagRenameModal: handleShowTagRenameModal, - }; -}; diff --git a/web/src/pages/add-knowledge/components/knowledge-setting/index.less b/web/src/pages/add-knowledge/components/knowledge-setting/index.less deleted file mode 100644 index 4889e3776..000000000 --- a/web/src/pages/add-knowledge/components/knowledge-setting/index.less +++ /dev/null @@ -1,45 +0,0 @@ -.tags { - margin-bottom: 24px; -} - -.preset { - display: flex; - height: 80px; - background-color: rgba(0, 0, 0, 0.1); - border-radius: 5px; - padding: 5px; - margin-bottom: 24px; - - .left { - flex: 1; - } - - .right { - width: 100px; - border-left: 1px solid rgba(0, 0, 0, 0.4); - margin: 10px 0px; - padding: 5px; - } -} - -.configurationWrapper { - padding: 0 52px; - .buttonWrapper { - text-align: right; - } - .variableSlider { - width: 100%; - } -} - -.categoryPanelWrapper { - .topTitle { - margin-top: 0; - } - .imageRow { - margin-top: 16px; - } - .image { - width: 100%; - } -} diff --git a/web/src/pages/add-knowledge/components/knowledge-setting/index.tsx b/web/src/pages/add-knowledge/components/knowledge-setting/index.tsx deleted file mode 100644 index 8acc45de5..000000000 --- a/web/src/pages/add-knowledge/components/knowledge-setting/index.tsx +++ /dev/null @@ -1,40 +0,0 @@ -import { Col, Divider, Row, Spin, Typography } from 'antd'; -import CategoryPanel from './category-panel'; -import { ConfigurationForm } from './configuration'; -import { - useHandleChunkMethodChange, - useSelectKnowledgeDetailsLoading, -} from './hooks'; - -import { useTranslate } from '@/hooks/common-hooks'; -import styles from './index.less'; - -const { Title } = Typography; - -const Configuration = () => { - const loading = useSelectKnowledgeDetailsLoading(); - const { form, chunkMethod } = useHandleChunkMethodChange(); - const { t } = useTranslate('knowledgeConfiguration'); - - return ( -
- - {t('configuration', { keyPrefix: 'knowledgeDetails' })} - -

{t('titleDescription')}

- - - -
- - - - - - - - - ); -}; - -export default Configuration; diff --git a/web/src/pages/add-knowledge/components/knowledge-setting/tag-item.tsx b/web/src/pages/add-knowledge/components/knowledge-setting/tag-item.tsx deleted file mode 100644 index 4d3e2a9e0..000000000 --- a/web/src/pages/add-knowledge/components/knowledge-setting/tag-item.tsx +++ /dev/null @@ -1,90 +0,0 @@ -import { useFetchKnowledgeList } from '@/hooks/knowledge-hooks'; -import { UserOutlined } from '@ant-design/icons'; -import { Avatar, Flex, Form, InputNumber, Select, Slider, Space } from 'antd'; -import DOMPurify from 'dompurify'; -import { useTranslation } from 'react-i18next'; - -export const TagSetItem = () => { - const { t } = useTranslation(); - - const { list: knowledgeList } = useFetchKnowledgeList(true); - - const knowledgeOptions = knowledgeList - .filter((x) => x.parser_id === 'tag') - .map((x) => ({ - label: ( - - } src={x.avatar} /> - {x.name} - - ), - value: x.id, - })); - - return ( - - } - rules={[ - { - message: t('chat.knowledgeBasesMessage'), - type: 'array', - }, - ]} - > - - - ); -}; - -export const TopNTagsItem = () => { - const { t } = useTranslation(); - - return ( - - - - - - - - - - - - - ); -}; - -export function TagItems() { - return ( - <> - - - {({ getFieldValue }) => { - const ids: string[] = getFieldValue(['parser_config', 'tag_kb_ids']); - - return ( - Array.isArray(ids) && - ids.length > 0 && - ); - }} - - - ); -} diff --git a/web/src/pages/add-knowledge/components/knowledge-setting/tag-table/index.tsx b/web/src/pages/add-knowledge/components/knowledge-setting/tag-table/index.tsx deleted file mode 100644 index 0ab25a86e..000000000 --- a/web/src/pages/add-knowledge/components/knowledge-setting/tag-table/index.tsx +++ /dev/null @@ -1,307 +0,0 @@ -'use client'; - -import { - ColumnDef, - ColumnFiltersState, - SortingState, - VisibilityState, - flexRender, - getCoreRowModel, - getFilteredRowModel, - getPaginationRowModel, - getSortedRowModel, - useReactTable, -} from '@tanstack/react-table'; -import { ArrowUpDown, Pencil, Trash2 } from 'lucide-react'; -import * as React from 'react'; - -import { ConfirmDeleteDialog } from '@/components/confirm-delete-dialog'; -import { Button } from '@/components/ui/button'; -import { Checkbox } from '@/components/ui/checkbox'; -import { Input } from '@/components/ui/input'; -import { - Table, - TableBody, - TableCell, - TableHead, - TableHeader, - TableRow, -} from '@/components/ui/table'; -import { - Tooltip, - TooltipContent, - TooltipProvider, - TooltipTrigger, -} from '@/components/ui/tooltip'; -import { useDeleteTag, useFetchTagList } from '@/hooks/knowledge-hooks'; -import { useCallback, useEffect, useState } from 'react'; -import { useTranslation } from 'react-i18next'; -import { useRenameKnowledgeTag } from '../hooks'; -import { RenameDialog } from './rename-dialog'; - -export type ITag = { - tag: string; - frequency: number; -}; - -export function TagTable() { - const { t } = useTranslation(); - const { list } = useFetchTagList(); - const [tagList, setTagList] = useState([]); - - const [sorting, setSorting] = React.useState([]); - const [columnFilters, setColumnFilters] = React.useState( - [], - ); - const [columnVisibility, setColumnVisibility] = - React.useState({}); - const [rowSelection, setRowSelection] = useState({}); - - const { deleteTag } = useDeleteTag(); - - useEffect(() => { - setTagList(list.map((x) => ({ tag: x[0], frequency: x[1] }))); - }, [list]); - - const handleDeleteTag = useCallback( - (tags: string[]) => () => { - deleteTag(tags); - }, - [deleteTag], - ); - - const { - showTagRenameModal, - hideTagRenameModal, - tagRenameVisible, - initialName, - } = useRenameKnowledgeTag(); - - const columns: ColumnDef[] = [ - { - id: 'select', - header: ({ table }) => ( - table.toggleAllPageRowsSelected(!!value)} - aria-label="Select all" - /> - ), - cell: ({ row }) => ( - row.toggleSelected(!!value)} - aria-label="Select row" - /> - ), - enableSorting: false, - enableHiding: false, - }, - { - accessorKey: 'tag', - header: ({ column }) => { - return ( - - ); - }, - cell: ({ row }) => { - const value: string = row.getValue('tag'); - return
{value}
; - }, - }, - { - accessorKey: 'frequency', - header: ({ column }) => { - return ( - - ); - }, - cell: ({ row }) => ( -
{row.getValue('frequency')}
- ), - }, - { - id: 'actions', - enableHiding: false, - header: t('common.action'), - cell: ({ row }) => { - return ( -
- - - - - - - -

{t('common.delete')}

-
-
- - - - - -

{t('common.rename')}

-
-
-
- ); - }, - }, - ]; - - const table = useReactTable({ - data: tagList, - columns, - onSortingChange: setSorting, - onColumnFiltersChange: setColumnFilters, - getCoreRowModel: getCoreRowModel(), - getPaginationRowModel: getPaginationRowModel(), - getSortedRowModel: getSortedRowModel(), - getFilteredRowModel: getFilteredRowModel(), - onColumnVisibilityChange: setColumnVisibility, - onRowSelectionChange: setRowSelection, - state: { - sorting, - columnFilters, - columnVisibility, - rowSelection, - }, - }); - - const selectedRowLength = table.getFilteredSelectedRowModel().rows.length; - - return ( - -
-
- - table.getColumn('tag')?.setFilterValue(event.target.value) - } - className="w-1/2" - /> - {selectedRowLength > 0 && ( - x.original.tag), - )} - > - - - )} -
-
-
- - {table.getHeaderGroups().map((headerGroup) => ( - - {headerGroup.headers.map((header) => { - return ( - - {header.isPlaceholder - ? null - : flexRender( - header.column.columnDef.header, - header.getContext(), - )} - - ); - })} - - ))} - - - {table.getRowModel().rows?.length ? ( - table.getRowModel().rows.map((row) => ( - - {row.getVisibleCells().map((cell) => ( - - {flexRender( - cell.column.columnDef.cell, - cell.getContext(), - )} - - ))} - - )) - ) : ( - - - No results. - - - )} - -
-
-
-
- {selectedRowLength} of {table.getFilteredRowModel().rows.length}{' '} - row(s) selected. -
-
- - -
-
-
- {tagRenameVisible && ( - - )} - - ); -} diff --git a/web/src/pages/add-knowledge/components/knowledge-setting/tag-table/rename-dialog/index.tsx b/web/src/pages/add-knowledge/components/knowledge-setting/tag-table/rename-dialog/index.tsx deleted file mode 100644 index b95907f92..000000000 --- a/web/src/pages/add-knowledge/components/knowledge-setting/tag-table/rename-dialog/index.tsx +++ /dev/null @@ -1,40 +0,0 @@ -import { - Dialog, - DialogContent, - DialogFooter, - DialogHeader, - DialogTitle, -} from '@/components/ui/dialog'; -import { LoadingButton } from '@/components/ui/loading-button'; -import { useTagIsRenaming } from '@/hooks/knowledge-hooks'; -import { IModalProps } from '@/interfaces/common'; -import { TagRenameId } from '@/pages/add-knowledge/constant'; -import { useTranslation } from 'react-i18next'; -import { RenameForm } from './rename-form'; - -export function RenameDialog({ - hideModal, - initialName, -}: IModalProps & { initialName: string }) { - const { t } = useTranslation(); - const loading = useTagIsRenaming(); - - return ( - - - - {t('common.rename')} - - - - - {t('common.save')} - - - - - ); -} diff --git a/web/src/pages/add-knowledge/components/knowledge-setting/tag-table/rename-dialog/rename-form.tsx b/web/src/pages/add-knowledge/components/knowledge-setting/tag-table/rename-dialog/rename-form.tsx deleted file mode 100644 index 9c8f1cf7e..000000000 --- a/web/src/pages/add-knowledge/components/knowledge-setting/tag-table/rename-dialog/rename-form.tsx +++ /dev/null @@ -1,83 +0,0 @@ -'use client'; - -import { zodResolver } from '@hookform/resolvers/zod'; -import { useForm } from 'react-hook-form'; -import { z } from 'zod'; - -import { - Form, - FormControl, - FormField, - FormItem, - FormLabel, - FormMessage, -} from '@/components/ui/form'; -import { Input } from '@/components/ui/input'; -import { useRenameTag } from '@/hooks/knowledge-hooks'; -import { IModalProps } from '@/interfaces/common'; -import { TagRenameId } from '@/pages/add-knowledge/constant'; -import { useEffect } from 'react'; -import { useTranslation } from 'react-i18next'; - -export function RenameForm({ - initialName, - hideModal, -}: IModalProps & { initialName: string }) { - const { t } = useTranslation(); - const FormSchema = z.object({ - name: z - .string() - .min(1, { - message: t('common.namePlaceholder'), - }) - .trim(), - }); - - const form = useForm>({ - resolver: zodResolver(FormSchema), - defaultValues: { - name: '', - }, - }); - - const { renameTag } = useRenameTag(); - - async function onSubmit(data: z.infer) { - const ret = await renameTag({ fromTag: initialName, toTag: data.name }); - if (ret) { - hideModal?.(); - } - } - - useEffect(() => { - form.setValue('name', initialName); - }, [form, initialName]); - - return ( -
- - ( - - {t('common.name')} - - - - - - )} - /> - - - ); -} diff --git a/web/src/pages/add-knowledge/components/knowledge-setting/tag-tabs.tsx b/web/src/pages/add-knowledge/components/knowledge-setting/tag-tabs.tsx deleted file mode 100644 index abcd3f673..000000000 --- a/web/src/pages/add-knowledge/components/knowledge-setting/tag-tabs.tsx +++ /dev/null @@ -1,40 +0,0 @@ -import { Segmented } from 'antd'; -import { SegmentedLabeledOption } from 'antd/es/segmented'; -import { upperFirst } from 'lodash'; -import { useState } from 'react'; -import { useTranslation } from 'react-i18next'; -import { TagTable } from './tag-table'; -import { TagWordCloud } from './tag-word-cloud'; - -enum TagType { - Cloud = 'cloud', - Table = 'table', -} - -const TagContentMap = { - [TagType.Cloud]: , - [TagType.Table]: , -}; - -export function TagTabs() { - const [value, setValue] = useState(TagType.Cloud); - const { t } = useTranslation(); - - const options: SegmentedLabeledOption[] = [TagType.Cloud, TagType.Table].map( - (x) => ({ - label: t(`knowledgeConfiguration.tag${upperFirst(x)}`), - value: x, - }), - ); - - return ( -
- setValue(val as TagType)} - /> - {TagContentMap[value]} -
- ); -} diff --git a/web/src/pages/add-knowledge/components/knowledge-setting/tag-word-cloud.tsx b/web/src/pages/add-knowledge/components/knowledge-setting/tag-word-cloud.tsx deleted file mode 100644 index b71ed69af..000000000 --- a/web/src/pages/add-knowledge/components/knowledge-setting/tag-word-cloud.tsx +++ /dev/null @@ -1,62 +0,0 @@ -import { useFetchTagList } from '@/hooks/knowledge-hooks'; -import { Chart } from '@antv/g2'; -import { sumBy } from 'lodash'; -import { useCallback, useEffect, useMemo, useRef } from 'react'; - -export function TagWordCloud() { - const domRef = useRef(null); - let chartRef = useRef(); - const { list } = useFetchTagList(); - - const { list: tagList } = useMemo(() => { - const nextList = list.sort((a, b) => b[1] - a[1]).slice(0, 256); - - return { - list: nextList.map((x) => ({ text: x[0], value: x[1], name: x[0] })), - sumValue: sumBy(nextList, (x: [string, number]) => x[1]), - length: nextList.length, - }; - }, [list]); - - const renderWordCloud = useCallback(() => { - if (domRef.current) { - chartRef.current = new Chart({ container: domRef.current }); - - chartRef.current.options({ - type: 'wordCloud', - autoFit: true, - layout: { - fontSize: [10, 50], - // fontSize: (d: any) => { - // if (d.value) { - // return (d.value / sumValue) * 100 * (length / 10); - // } - // return 0; - // }, - }, - data: { - type: 'inline', - value: tagList, - }, - encode: { color: 'text' }, - legend: false, - tooltip: { - title: 'name', // title - items: ['value'], // data item - }, - }); - - chartRef.current.render(); - } - }, [tagList]); - - useEffect(() => { - renderWordCloud(); - - return () => { - chartRef.current?.destroy(); - }; - }, [renderWordCloud]); - - return
; -} diff --git a/web/src/pages/add-knowledge/components/knowledge-setting/utils.ts b/web/src/pages/add-knowledge/components/knowledge-setting/utils.ts deleted file mode 100644 index 4c5666467..000000000 --- a/web/src/pages/add-knowledge/components/knowledge-setting/utils.ts +++ /dev/null @@ -1,20 +0,0 @@ -const getImageName = (prefix: string, length: number) => - new Array(length) - .fill(0) - .map((x, idx) => `chunk-method/${prefix}-0${idx + 1}`); - -export const ImageMap = { - book: getImageName('book', 4), - laws: getImageName('law', 2), - manual: getImageName('manual', 4), - picture: getImageName('media', 2), - naive: getImageName('naive', 2), - paper: getImageName('paper', 2), - presentation: getImageName('presentation', 2), - qa: getImageName('qa', 2), - resume: getImageName('resume', 2), - table: getImageName('table', 2), - one: getImageName('one', 2), - knowledge_graph: getImageName('knowledge-graph', 2), - tag: getImageName('tag', 2), -}; diff --git a/web/src/pages/add-knowledge/components/knowledge-sidebar/index.less b/web/src/pages/add-knowledge/components/knowledge-sidebar/index.less deleted file mode 100644 index 1080b0629..000000000 --- a/web/src/pages/add-knowledge/components/knowledge-sidebar/index.less +++ /dev/null @@ -1,63 +0,0 @@ -.sidebarWrapper { - max-width: 288px; - padding: 32px 24px 24px 24px; - flex-direction: column; - - .sidebarTop { - text-align: center; - .knowledgeLogo { - } - .knowledgeTitle { - font-size: 16px; - line-height: 24px; - font-weight: @fontWeight700; - margin-bottom: 6px; - } - .knowledgeDescription { - font-size: 12px; - font-weight: @fontWeight600; - color: @gray8; - margin: 0; - } - padding-bottom: 20px; - } - .divider { - height: 2px; - background-image: linear-gradient( - to right, - @gray11 0%, - @gray11 50%, - transparent 50% - ); - background-size: 10px 2px; - background-repeat: repeat-x; - } - - .menuWrapper { - padding-top: 10px; - - .menu { - border: none; - font-size: @fontSize16; - font-weight: @fontWeight600; - :global(.ant-menu-item) { - display: flex; - align-items: center; - } - } - - .defaultWidth { - width: 240px; - } - - .minWidth { - width: 50px; - } - - .menuText { - color: @gray3; - font-size: @fontSize14; - font-weight: @fontWeight700; - } - } -} diff --git a/web/src/pages/add-knowledge/components/knowledge-sidebar/index.tsx b/web/src/pages/add-knowledge/components/knowledge-sidebar/index.tsx deleted file mode 100644 index 421a28653..000000000 --- a/web/src/pages/add-knowledge/components/knowledge-sidebar/index.tsx +++ /dev/null @@ -1,135 +0,0 @@ -import { ReactComponent as ConfigurationIcon } from '@/assets/svg/knowledge-configration.svg'; -import { ReactComponent as DatasetIcon } from '@/assets/svg/knowledge-dataset.svg'; -import { ReactComponent as TestingIcon } from '@/assets/svg/knowledge-testing.svg'; -import { - useFetchKnowledgeBaseConfiguration, - useFetchKnowledgeGraph, -} from '@/hooks/knowledge-hooks'; -import { - useGetKnowledgeSearchParams, - useSecondPathName, -} from '@/hooks/route-hook'; -import { getWidth } from '@/utils'; -import { Avatar, Menu, MenuProps, Space } from 'antd'; -import classNames from 'classnames'; -import { useCallback, useEffect, useMemo, useState } from 'react'; -import { useTranslation } from 'react-i18next'; -import { useNavigate } from 'umi'; -import { KnowledgeRouteKey } from '../../constant'; - -import { isEmpty } from 'lodash'; -import { GitGraph } from 'lucide-react'; -import styles from './index.less'; - -const KnowledgeSidebar = () => { - let navigate = useNavigate(); - const activeKey = useSecondPathName(); - const { knowledgeId } = useGetKnowledgeSearchParams(); - - const [windowWidth, setWindowWidth] = useState(getWidth()); - const { t } = useTranslation(); - const { data: knowledgeDetails } = useFetchKnowledgeBaseConfiguration(); - - const handleSelect: MenuProps['onSelect'] = (e) => { - navigate(`/knowledge/${e.key}?id=${knowledgeId}`); - }; - - const { data } = useFetchKnowledgeGraph(); - - type MenuItem = Required['items'][number]; - - const getItem = useCallback( - ( - label: string, - key: React.Key, - icon?: React.ReactNode, - disabled?: boolean, - children?: MenuItem[], - type?: 'group', - ): MenuItem => { - return { - key, - icon, - children, - label: t(`knowledgeDetails.${label}`), - type, - disabled, - } as MenuItem; - }, - [t], - ); - - const items: MenuItem[] = useMemo(() => { - const list = [ - getItem( - KnowledgeRouteKey.Dataset, // TODO: Change icon color when selected - KnowledgeRouteKey.Dataset, - , - ), - getItem( - KnowledgeRouteKey.Testing, - KnowledgeRouteKey.Testing, - , - ), - getItem( - KnowledgeRouteKey.Configuration, - KnowledgeRouteKey.Configuration, - , - ), - ]; - - if (!isEmpty(data?.graph)) { - list.push( - getItem( - KnowledgeRouteKey.KnowledgeGraph, - KnowledgeRouteKey.KnowledgeGraph, - , - ), - ); - } - - return list; - }, [data, getItem]); - - useEffect(() => { - const widthSize = () => { - const width = getWidth(); - - setWindowWidth(width); - }; - window.addEventListener('resize', widthSize); - return () => { - window.removeEventListener('resize', widthSize); - }; - }, []); - - return ( -
-
- - -
{knowledgeDetails.name}
-
-

- {knowledgeDetails.description} -

-
-
-
- 957, - [styles.minWidth]: windowWidth.width <= 957, - })} - // inlineCollapsed={collapsed} - items={items} - onSelect={handleSelect} - /> -
-
- ); -}; - -export default KnowledgeSidebar; diff --git a/web/src/pages/add-knowledge/components/knowledge-testing/index.less b/web/src/pages/add-knowledge/components/knowledge-testing/index.less deleted file mode 100644 index c7d005dc6..000000000 --- a/web/src/pages/add-knowledge/components/knowledge-testing/index.less +++ /dev/null @@ -1,4 +0,0 @@ -.testingWrapper { - flex: 1; - height: 100%; -} diff --git a/web/src/pages/add-knowledge/components/knowledge-testing/index.tsx b/web/src/pages/add-knowledge/components/knowledge-testing/index.tsx deleted file mode 100644 index 531941d30..000000000 --- a/web/src/pages/add-knowledge/components/knowledge-testing/index.tsx +++ /dev/null @@ -1,68 +0,0 @@ -import { - useTestChunkAllRetrieval, - useTestChunkRetrieval, -} from '@/hooks/knowledge-hooks'; -import { Flex, Form } from 'antd'; -import { useMemo, useState } from 'react'; -import TestingControl from './testing-control'; -import TestingResult from './testing-result'; - -import styles from './index.less'; - -const KnowledgeTesting = () => { - const [form] = Form.useForm(); - const { - data: retrievalData, - testChunk, - loading: retrievalLoading, - } = useTestChunkRetrieval(); - const { - data: allRetrievalData, - testChunkAll, - loading: allRetrievalLoading, - } = useTestChunkAllRetrieval(); - const [selectedDocumentIds, setSelectedDocumentIds] = useState([]); - - const handleTesting = async (documentIds: string[] = []) => { - const values = await form.validateFields(); - const params = { - ...values, - vector_similarity_weight: 1 - values.vector_similarity_weight, - }; - - if (Array.isArray(documentIds) && documentIds.length > 0) { - testChunk({ - ...params, - doc_ids: documentIds, - }); - } else { - testChunkAll({ - ...params, - doc_ids: [], - }); - } - }; - - const testingResult = useMemo(() => { - return selectedDocumentIds.length > 0 ? retrievalData : allRetrievalData; - }, [allRetrievalData, retrievalData, selectedDocumentIds.length]); - - return ( - - - - - ); -}; - -export default KnowledgeTesting; diff --git a/web/src/pages/add-knowledge/components/knowledge-testing/testing-control/index.less b/web/src/pages/add-knowledge/components/knowledge-testing/testing-control/index.less deleted file mode 100644 index 7b0db52db..000000000 --- a/web/src/pages/add-knowledge/components/knowledge-testing/testing-control/index.less +++ /dev/null @@ -1,29 +0,0 @@ -.testingControlWrapper { - width: 350px; - background-color: rgba(255, 255, 255, 0.1); - padding: 30px 20px; - overflow: auto; - height: calc(100vh - 160px); - - .historyTitle { - padding: 30px 0 20px; - } - .historyIcon { - vertical-align: middle; - } - .historyCardWrapper { - width: 100%; - } - .historyCard { - width: 100%; - :global(.ant-card-body) { - padding: 10px; - } - } - .historyText { - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - flex: 1; - } -} diff --git a/web/src/pages/add-knowledge/components/knowledge-testing/testing-control/index.tsx b/web/src/pages/add-knowledge/components/knowledge-testing/testing-control/index.tsx deleted file mode 100644 index 8efb4c195..000000000 --- a/web/src/pages/add-knowledge/components/knowledge-testing/testing-control/index.tsx +++ /dev/null @@ -1,109 +0,0 @@ -import Rerank from '@/components/rerank'; -import SimilaritySlider from '@/components/similarity-slider'; -import { useTranslate } from '@/hooks/common-hooks'; -import { useChunkIsTesting } from '@/hooks/knowledge-hooks'; -import { Button, Card, Divider, Flex, Form, Input } from 'antd'; -import { FormInstance } from 'antd/lib'; -import { LabelWordCloud } from './label-word-cloud'; - -import { CrossLanguageItem } from '@/components/cross-language-item'; -import { UseKnowledgeGraphItem } from '@/components/use-knowledge-graph-item'; -import styles from './index.less'; - -type FieldType = { - similarity_threshold?: number; - vector_similarity_weight?: number; - question: string; -}; - -interface IProps { - form: FormInstance; - handleTesting: (documentIds?: string[]) => Promise; - selectedDocumentIds: string[]; -} - -const TestingControl = ({ - form, - handleTesting, - selectedDocumentIds, -}: IProps) => { - const question = Form.useWatch('question', { form, preserve: true }); - const loading = useChunkIsTesting(); - const { t } = useTranslate('knowledgeDetails'); - - const buttonDisabled = - !question || (typeof question === 'string' && question.trim() === ''); - - const onClick = () => { - handleTesting(selectedDocumentIds); - }; - - return ( -
-
- {t('testing')} -
-

{t('testingDescription')}

- -
-
- - - - - - - name={'question'} - rules={[{ required: true, message: t('testTextPlaceholder') }]} - > - - - - - - -
-
- - {/*
-
- - - Test history - -
- - {list.map((x) => ( - - - {x} -
- content dcjsjl snldsh svnodvn svnodrfn svjdoghdtbnhdo - sdvhodhbuid sldghdrlh -
- - time - - -
-
- ))} -
-
*/} -
- ); -}; - -export default TestingControl; diff --git a/web/src/pages/add-knowledge/components/knowledge-testing/testing-control/label-word-cloud.tsx b/web/src/pages/add-knowledge/components/knowledge-testing/testing-control/label-word-cloud.tsx deleted file mode 100644 index b1dbc05ba..000000000 --- a/web/src/pages/add-knowledge/components/knowledge-testing/testing-control/label-word-cloud.tsx +++ /dev/null @@ -1,59 +0,0 @@ -import { useSelectTestingResult } from '@/hooks/knowledge-hooks'; -import { Chart } from '@antv/g2'; -import { useCallback, useEffect, useMemo, useRef } from 'react'; - -export function LabelWordCloud() { - const domRef = useRef(null); - let chartRef = useRef(); - const { labels } = useSelectTestingResult(); - - const list = useMemo(() => { - if (!labels) { - return []; - } - - return Object.keys(labels).reduce< - Array<{ text: string; name: string; value: number }> - >((pre, cur) => { - pre.push({ name: cur, text: cur, value: labels[cur] }); - - return pre; - }, []); - }, [labels]); - - const renderWordCloud = useCallback(() => { - if (domRef.current && list.length) { - chartRef.current = new Chart({ container: domRef.current }); - - chartRef.current.options({ - type: 'wordCloud', - autoFit: true, - layout: { - fontSize: [6, 15], - }, - data: { - type: 'inline', - value: list, - }, - encode: { color: 'text' }, - legend: false, - tooltip: { - title: 'name', // title - items: ['value'], // data item - }, - }); - - chartRef.current.render(); - } - }, [list]); - - useEffect(() => { - renderWordCloud(); - - return () => { - chartRef.current?.destroy(); - }; - }, [renderWordCloud]); - - return
; -} diff --git a/web/src/pages/add-knowledge/components/knowledge-testing/testing-result/index.less b/web/src/pages/add-knowledge/components/knowledge-testing/testing-result/index.less deleted file mode 100644 index 44a886798..000000000 --- a/web/src/pages/add-knowledge/components/knowledge-testing/testing-result/index.less +++ /dev/null @@ -1,46 +0,0 @@ -.testingResultWrapper { - flex: 1; - background-color: rgba(255, 255, 255, 0.1); - padding: 30px 20px; - overflow: auto; - height: calc(100vh - 160px); - display: flex; - flex-direction: column; - justify-content: space-between; - - .selectFilesCollapse { - :global(.ant-collapse-header) { - padding-left: 22px; - } - margin-bottom: 32px; - overflow-y: auto; - } - - .selectFilesTitle { - padding-right: 10px; - } - - .similarityCircle { - width: 24px; - height: 24px; - border-radius: 50%; - background-color: rgba(255, 255, 255, 0.1); - font-size: 10px; - font-weight: normal; - } - - .similarityText { - font-size: 12px; - font-weight: 500; - } - .image { - width: 100%; - max-height: 30vh; - object-fit: contain; - } -} -.imagePreview { - display: block; - max-width: 45vw; - max-height: 40vh; -} diff --git a/web/src/pages/add-knowledge/components/knowledge-testing/testing-result/index.tsx b/web/src/pages/add-knowledge/components/knowledge-testing/testing-result/index.tsx deleted file mode 100644 index 02481cc9e..000000000 --- a/web/src/pages/add-knowledge/components/knowledge-testing/testing-result/index.tsx +++ /dev/null @@ -1,147 +0,0 @@ -import { ReactComponent as SelectedFilesCollapseIcon } from '@/assets/svg/selected-files-collapse.svg'; -import { useTranslate } from '@/hooks/common-hooks'; -import { ITestingChunk, ITestingResult } from '@/interfaces/database/knowledge'; -import { - Card, - Collapse, - Empty, - Flex, - Image, - Pagination, - PaginationProps, - Space, -} from 'antd'; -import camelCase from 'lodash/camelCase'; -import SelectFiles from './select-files'; - -import { useGetPaginationWithRouter } from '@/hooks/logic-hooks'; -import { api_host } from '@/utils/api'; -import { showImage } from '@/utils/chat'; -import { useCallback } from 'react'; -import styles from './index.less'; - -const similarityList: Array<{ field: keyof ITestingChunk; label: string }> = [ - { field: 'similarity', label: 'Hybrid Similarity' }, - { field: 'term_similarity', label: 'Term Similarity' }, - { field: 'vector_similarity', label: 'Vector Similarity' }, -]; - -const ChunkTitle = ({ item }: { item: ITestingChunk }) => { - const { t } = useTranslate('knowledgeDetails'); - return ( - - {similarityList.map((x) => ( - - - {((item[x.field] as number) * 100).toFixed(2)} - - {t(camelCase(x.field))} - - ))} - - ); -}; - -interface IProps { - handleTesting: (documentIds?: string[]) => Promise; - selectedDocumentIds: string[]; - setSelectedDocumentIds: (ids: string[]) => void; - data?: ITestingResult; - loading?: boolean; -} - -const TestingResult = ({ - handleTesting, - selectedDocumentIds, - setSelectedDocumentIds, - data, - loading, -}: IProps) => { - const { documents, chunks, total } = data || {}; - const { t } = useTranslate('knowledgeDetails'); - const { pagination, setPagination } = useGetPaginationWithRouter(); - - const onChange: PaginationProps['onChange'] = (pageNumber, pageSize) => { - pagination.onChange?.(pageNumber, pageSize); - handleTesting(selectedDocumentIds); - }; - - const onTesting = useCallback( - (ids: string[]) => { - setPagination({ page: 1 }); - handleTesting(ids); - }, - [setPagination, handleTesting], - ); - - return ( -
- ( - - )} - className={styles.selectFilesCollapse} - items={[ - { - key: '1', - label: ( - - - - {selectedDocumentIds?.length ?? 0}/{documents?.length ?? 0} - - {t('filesSelected')} - - - ), - children: ( -
- -
- ), - }, - ]} - /> - - {loading === false && chunks && chunks.length > 0 ? ( - chunks?.map((x) => ( - }> -
- {showImage(x.doc_type_kwd) && ( - - )} -
-
{x.content_with_weight}
-
- )) - ) : loading === false && chunks && chunks.length === 0 ? ( - - ) : null} -
- -
- ); -}; - -export default TestingResult; diff --git a/web/src/pages/add-knowledge/components/knowledge-testing/testing-result/select-files.tsx b/web/src/pages/add-knowledge/components/knowledge-testing/testing-result/select-files.tsx deleted file mode 100644 index 93545e09e..000000000 --- a/web/src/pages/add-knowledge/components/knowledge-testing/testing-result/select-files.tsx +++ /dev/null @@ -1,73 +0,0 @@ -import NewDocumentLink from '@/components/new-document-link'; -import { useTranslate } from '@/hooks/common-hooks'; -import { useAllTestingResult } from '@/hooks/knowledge-hooks'; -import { ITestingDocument } from '@/interfaces/database/knowledge'; -import { EyeOutlined } from '@ant-design/icons'; -import { Button, Table, TableProps, Tooltip } from 'antd'; - -interface IProps { - handleTesting: (ids: string[]) => void; - setSelectedDocumentIds: (ids: string[]) => void; -} - -const SelectFiles = ({ setSelectedDocumentIds, handleTesting }: IProps) => { - const { documents } = useAllTestingResult(); - const { t } = useTranslate('fileManager'); - - const columns: TableProps['columns'] = [ - { - title: 'Name', - dataIndex: 'doc_name', - key: 'doc_name', - render: (text) =>

{text}

, - }, - - { - title: 'Hits', - dataIndex: 'count', - key: 'count', - width: 80, - }, - { - title: 'View', - key: 'view', - width: 50, - render: (_, { doc_id, doc_name }) => ( - - - - - - ), - }, - ]; - - const rowSelection = { - onChange: (selectedRowKeys: React.Key[]) => { - setSelectedDocumentIds(selectedRowKeys as string[]); - handleTesting(selectedRowKeys as string[]); - }, - getCheckboxProps: (record: ITestingDocument) => ({ - disabled: record.doc_name === 'Disabled User', // Column configuration not to be checked - name: record.doc_name, - }), - }; - - return ( - - ); -}; - -export default SelectFiles; diff --git a/web/src/pages/add-knowledge/constant.ts b/web/src/pages/add-knowledge/constant.ts deleted file mode 100644 index 71df266c8..000000000 --- a/web/src/pages/add-knowledge/constant.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { KnowledgeRouteKey } from '@/constants/knowledge'; - -export const routeMap = { - [KnowledgeRouteKey.Dataset]: 'Dataset', - [KnowledgeRouteKey.Testing]: 'Retrieval testing', - [KnowledgeRouteKey.Configuration]: 'Configuration', -}; - -export enum KnowledgeDatasetRouteKey { - Chunk = 'chunk', - File = 'file', -} - -export const datasetRouteMap = { - [KnowledgeDatasetRouteKey.Chunk]: 'Chunk', - [KnowledgeDatasetRouteKey.File]: 'File Upload', -}; - -export * from '@/constants/knowledge'; - -export const TagRenameId = 'tagRename'; diff --git a/web/src/pages/add-knowledge/index.less b/web/src/pages/add-knowledge/index.less deleted file mode 100644 index dc934280c..000000000 --- a/web/src/pages/add-knowledge/index.less +++ /dev/null @@ -1,19 +0,0 @@ -.container { - display: flex; - height: 100%; - width: 100%; - .contentWrapper { - flex: 1; - overflow-x: auto; - height: 100%; - background-color: rgba(255, 255, 255, 0.1); - padding: 16px 20px 28px 40px; - display: flex; - flex-direction: column; - } - .content { - background-color: rgba(255, 255, 255, 0.1); - margin-top: 16px; - flex: 1; - } -} diff --git a/web/src/pages/add-knowledge/index.tsx b/web/src/pages/add-knowledge/index.tsx deleted file mode 100644 index 18187cf4e..000000000 --- a/web/src/pages/add-knowledge/index.tsx +++ /dev/null @@ -1,74 +0,0 @@ -import { useKnowledgeBaseId } from '@/hooks/knowledge-hooks'; -import { - useNavigateWithFromState, - useSecondPathName, - useThirdPathName, -} from '@/hooks/route-hook'; -import { Breadcrumb } from 'antd'; -import { ItemType } from 'antd/es/breadcrumb/Breadcrumb'; -import { useMemo } from 'react'; -import { useTranslation } from 'react-i18next'; -import { Link, Outlet } from 'umi'; -import Siderbar from './components/knowledge-sidebar'; -import { KnowledgeDatasetRouteKey, KnowledgeRouteKey } from './constant'; -import styles from './index.less'; - -const KnowledgeAdding = () => { - const knowledgeBaseId = useKnowledgeBaseId(); - - const { t } = useTranslation(); - const activeKey: KnowledgeRouteKey = - (useSecondPathName() as KnowledgeRouteKey) || KnowledgeRouteKey.Dataset; - - const datasetActiveKey: KnowledgeDatasetRouteKey = - useThirdPathName() as KnowledgeDatasetRouteKey; - - const gotoList = useNavigateWithFromState(); - - const breadcrumbItems: ItemType[] = useMemo(() => { - const items: ItemType[] = [ - { - title: ( - gotoList('/knowledge')}> - {t('header.knowledgeBase')} - - ), - }, - { - title: datasetActiveKey ? ( - - {t(`knowledgeDetails.${activeKey}`)} - - ) : ( - t(`knowledgeDetails.${activeKey}`) - ), - }, - ]; - - if (datasetActiveKey) { - items.push({ - title: t(`knowledgeDetails.${datasetActiveKey}`), - }); - } - - return items; - }, [activeKey, datasetActiveKey, gotoList, knowledgeBaseId, t]); - - return ( - <> -
- -
- -
- -
-
-
- - ); -}; - -export default KnowledgeAdding; diff --git a/web/src/pages/agent/chat/box.tsx b/web/src/pages/agent/chat/box.tsx index f57ed4282..f44e219fc 100644 --- a/web/src/pages/agent/chat/box.tsx +++ b/web/src/pages/agent/chat/box.tsx @@ -1,5 +1,4 @@ import { MessageType } from '@/constants/chat'; -import { useGetFileIcon } from '@/pages/chat/hooks'; import { useSendAgentMessage } from './use-send-agent-message'; @@ -19,6 +18,7 @@ import { useParams } from 'umi'; import DebugContent from '../debug-content'; import { useAwaitCompentData } from '../hooks/use-chat-logic'; import { useIsTaskMode } from '../hooks/use-get-begin-query'; +import { useGetFileIcon } from './use-get-file-icon'; function AgentChatBox() { const { data: canvasInfo, refetch } = useFetchAgent(); diff --git a/web/src/pages/agent/chat/use-get-file-icon.tsx b/web/src/pages/agent/chat/use-get-file-icon.tsx new file mode 100644 index 000000000..f86c5524e --- /dev/null +++ b/web/src/pages/agent/chat/use-get-file-icon.tsx @@ -0,0 +1,12 @@ +import { fileIconMap } from '@/constants/common'; +import { getFileExtension } from '@/utils'; + +export const useGetFileIcon = () => { + const getFileIcon = (filename: string) => { + const ext: string = getFileExtension(filename); + const iconPath = fileIconMap[ext as keyof typeof fileIconMap]; + return `@/assets/svg/file-icon/${iconPath}`; + }; + + return getFileIcon; +}; diff --git a/web/src/pages/agent/debug-content/index.tsx b/web/src/pages/agent/debug-content/index.tsx index eadcefe58..22e20dc78 100644 --- a/web/src/pages/agent/debug-content/index.tsx +++ b/web/src/pages/agent/debug-content/index.tsx @@ -11,7 +11,7 @@ import { Input } from '@/components/ui/input'; import { RAGFlowSelect } from '@/components/ui/select'; import { Switch } from '@/components/ui/switch'; import { Textarea } from '@/components/ui/textarea'; -import { IMessage } from '@/pages/chat/interface'; +import { IMessage } from '@/interfaces/database/chat'; import { zodResolver } from '@hookform/resolvers/zod'; import React, { ReactNode, useCallback, useMemo } from 'react'; import { useForm } from 'react-hook-form'; diff --git a/web/src/pages/agent/hooks/use-chat-logic.ts b/web/src/pages/agent/hooks/use-chat-logic.ts index 42b0533cb..3c62ae4d1 100644 --- a/web/src/pages/agent/hooks/use-chat-logic.ts +++ b/web/src/pages/agent/hooks/use-chat-logic.ts @@ -1,6 +1,5 @@ import { MessageType } from '@/constants/chat'; -import { Message } from '@/interfaces/database/chat'; -import { IMessage } from '@/pages/chat/interface'; +import { IMessage, Message } from '@/interfaces/database/chat'; import { get } from 'lodash'; import { useCallback, useMemo } from 'react'; import { BeginQuery } from '../interface'; diff --git a/web/src/pages/agent/share/index.tsx b/web/src/pages/agent/share/index.tsx index b33c1b3ce..24308ea66 100644 --- a/web/src/pages/agent/share/index.tsx +++ b/web/src/pages/agent/share/index.tsx @@ -11,12 +11,12 @@ import i18n from '@/locales/config'; import DebugContent from '@/pages/agent/debug-content'; import { useCacheChatLog } from '@/pages/agent/hooks/use-cache-chat-log'; import { useAwaitCompentData } from '@/pages/agent/hooks/use-chat-logic'; -import { useSendButtonDisabled } from '@/pages/chat/hooks'; import { buildMessageUuidWithRole } from '@/utils/chat'; import { isEmpty } from 'lodash'; import React, { forwardRef, useCallback } from 'react'; import { useGetSharedChatSearchParams, + useSendButtonDisabled, useSendNextSharedMessage, } from '../hooks/use-send-shared-message'; import { ParameterDialog } from './parameter-dialog'; diff --git a/web/src/pages/agent/utils/chat.ts b/web/src/pages/agent/utils/chat.ts index 15c8ff850..a2859b6dc 100644 --- a/web/src/pages/agent/utils/chat.ts +++ b/web/src/pages/agent/utils/chat.ts @@ -1,6 +1,5 @@ import { MessageType } from '@/constants/chat'; -import { IReference } from '@/interfaces/database/chat'; -import { IMessage } from '@/pages/chat/interface'; +import { IMessage, IReference } from '@/interfaces/database/chat'; import { isEmpty } from 'lodash'; export const buildAgentMessageItemReference = ( diff --git a/web/src/pages/agents/agent-log-detail-modal.tsx b/web/src/pages/agents/agent-log-detail-modal.tsx index beabe8c5f..88c1327b8 100644 --- a/web/src/pages/agents/agent-log-detail-modal.tsx +++ b/web/src/pages/agents/agent-log-detail-modal.tsx @@ -3,10 +3,13 @@ import { Modal } from '@/components/ui/modal/modal'; import { useFetchAgent } from '@/hooks/use-agent-request'; import { useFetchUserInfo } from '@/hooks/user-setting-hooks'; import { IAgentLogMessage } from '@/interfaces/database/agent'; -import { IReferenceObject, Message } from '@/interfaces/database/chat'; +import { + IMessage, + IReferenceObject, + Message, +} from '@/interfaces/database/chat'; import { buildMessageUuidWithRole } from '@/utils/chat'; import React, { useMemo } from 'react'; -import { IMessage } from '../chat/interface'; interface CustomModalProps { isOpen: boolean; diff --git a/web/src/pages/agents/create-agent-dialog.tsx b/web/src/pages/agents/create-agent-dialog.tsx index 5c8f99320..ae998e6c5 100644 --- a/web/src/pages/agents/create-agent-dialog.tsx +++ b/web/src/pages/agents/create-agent-dialog.tsx @@ -6,7 +6,7 @@ import { DialogHeader, DialogTitle, } from '@/components/ui/dialog'; -import { TagRenameId } from '@/pages/add-knowledge/constant'; +import { TagRenameId } from '@/constants/knowledge'; import { useTranslation } from 'react-i18next'; import { CreateAgentForm, CreateAgentFormProps } from './create-agent-form'; diff --git a/web/src/pages/agents/create-agent-form.tsx b/web/src/pages/agents/create-agent-form.tsx index f89031d17..ec36086d8 100644 --- a/web/src/pages/agents/create-agent-form.tsx +++ b/web/src/pages/agents/create-agent-form.tsx @@ -7,9 +7,9 @@ import { z } from 'zod'; import { RAGFlowFormItem } from '@/components/ragflow-form'; import { Card, CardContent } from '@/components/ui/card'; import { Form } from '@/components/ui/form'; +import { TagRenameId } from '@/constants/knowledge'; import { IModalProps } from '@/interfaces/common'; import { cn } from '@/lib/utils'; -import { TagRenameId } from '@/pages/add-knowledge/constant'; import { BrainCircuit, Check, Route } from 'lucide-react'; import { useCallback } from 'react'; import { useTranslation } from 'react-i18next'; diff --git a/web/src/pages/agents/upload-agent-dialog/index.tsx b/web/src/pages/agents/upload-agent-dialog/index.tsx index b2084bc0f..83a51dbdf 100644 --- a/web/src/pages/agents/upload-agent-dialog/index.tsx +++ b/web/src/pages/agents/upload-agent-dialog/index.tsx @@ -6,8 +6,8 @@ import { DialogHeader, DialogTitle, } from '@/components/ui/dialog'; +import { TagRenameId } from '@/constants/knowledge'; import { IModalProps } from '@/interfaces/common'; -import { TagRenameId } from '@/pages/add-knowledge/constant'; import { useTranslation } from 'react-i18next'; import { UploadAgentForm } from './upload-agent-form'; diff --git a/web/src/pages/agents/upload-agent-dialog/upload-agent-form.tsx b/web/src/pages/agents/upload-agent-dialog/upload-agent-form.tsx index f7711b70d..1cabecd93 100644 --- a/web/src/pages/agents/upload-agent-dialog/upload-agent-form.tsx +++ b/web/src/pages/agents/upload-agent-dialog/upload-agent-form.tsx @@ -14,8 +14,8 @@ import { FormMessage, } from '@/components/ui/form'; import { FileMimeType } from '@/constants/common'; +import { TagRenameId } from '@/constants/knowledge'; import { IModalProps } from '@/interfaces/common'; -import { TagRenameId } from '@/pages/add-knowledge/constant'; import { NameFormField, NameFormSchema } from '../name-form-field'; export const FormSchema = z.object({ diff --git a/web/src/pages/chat/chat-configuration-modal/assistant-setting.tsx b/web/src/pages/chat/chat-configuration-modal/assistant-setting.tsx deleted file mode 100644 index 1e955c100..000000000 --- a/web/src/pages/chat/chat-configuration-modal/assistant-setting.tsx +++ /dev/null @@ -1,193 +0,0 @@ -import KnowledgeBaseItem from '@/components/knowledge-base-item'; -import { TavilyItem } from '@/components/tavily-item'; -import { useTranslate } from '@/hooks/common-hooks'; -import { useFetchTenantInfo } from '@/hooks/user-setting-hooks'; -import { PlusOutlined } from '@ant-design/icons'; -import { Form, Input, message, Select, Switch, Upload } from 'antd'; -import classNames from 'classnames'; -import { useCallback } from 'react'; -import { ISegmentedContentProps } from '../interface'; - -import { DatasetMetadata } from '@/constants/chat'; -import styles from './index.less'; -import { MetadataFilterConditions } from './metadata-filter-conditions'; - -const emptyResponseField = ['prompt_config', 'empty_response']; - -const AssistantSetting = ({ - show, - form, - setHasError, -}: ISegmentedContentProps) => { - const { t } = useTranslate('chat'); - const { data } = useFetchTenantInfo(true); - - const MetadataOptions = Object.values(DatasetMetadata).map((x) => { - return { - value: x, - label: t(`meta.${x}`), - }; - }); - - const metadata = Form.useWatch(['meta_data_filter', 'method'], form); - const kbIds = Form.useWatch(['kb_ids'], form); - - const hasKnowledge = Array.isArray(kbIds) && kbIds.length > 0; - - const handleChange = useCallback(() => { - const kbIds = form.getFieldValue('kb_ids'); - const emptyResponse = form.getFieldValue(emptyResponseField); - - const required = - emptyResponse && ((Array.isArray(kbIds) && kbIds.length === 0) || !kbIds); - - setHasError(required); - form.setFields([ - { - name: emptyResponseField, - errors: required ? [t('emptyResponseMessage')] : [], - }, - ]); - }, [form, setHasError, t]); - - const normFile = (e: any) => { - if (Array.isArray(e)) { - return e; - } - return e?.fileList; - }; - - const handleTtsChange = useCallback( - (checked: boolean) => { - if (checked && !data.tts_id) { - message.error(`Please set TTS model firstly. - Setting >> Model providers >> System model settings`); - form.setFieldValue(['prompt_config', 'tts'], false); - } - }, - [data, form], - ); - - const uploadButton = ( - - ); - - return ( -
- - - - - - - - false} - showUploadList={{ showPreviewIcon: false, showRemoveIcon: false }} - > - {show ? uploadButton : null} - - - - - - - - - - - - - - - - - - - - {hasKnowledge && ( - -
- - - ); -}; - -interface EditableCellProps { - title: React.ReactNode; - editable: boolean; - children: React.ReactNode; - dataIndex: keyof Item; - record: Item; - handleSave: (record: Item) => void; -} - -export const EditableCell: React.FC = ({ - title, - editable, - children, - dataIndex, - record, - handleSave, - ...restProps -}) => { - const [editing, setEditing] = useState(false); - const inputRef = useRef(null); - const form = useContext(EditableContext)!; - - useEffect(() => { - if (editing) { - inputRef.current!.focus(); - } - }, [editing]); - - const toggleEdit = () => { - setEditing(!editing); - form.setFieldsValue({ [dataIndex]: record[dataIndex] }); - }; - - const save = async () => { - try { - const values = await form.validateFields(); - - toggleEdit(); - handleSave({ ...record, ...values }); - } catch (errInfo) { - console.log('Save failed:', errInfo); - } - }; - - let childNode = children; - - if (editable) { - childNode = editing ? ( - - - - ) : ( -
- {children} -
- ); - } - - return
; -}; diff --git a/web/src/pages/chat/chat-configuration-modal/index.less b/web/src/pages/chat/chat-configuration-modal/index.less deleted file mode 100644 index 706725ccf..000000000 --- a/web/src/pages/chat/chat-configuration-modal/index.less +++ /dev/null @@ -1,57 +0,0 @@ -.chatConfigurationDescription { - font-size: 14px; -} - -.variableContainer { - padding-bottom: 20px; - .variableAlign { - text-align: end; - } - - .variableLabel { - margin-right: 14px; - } - - .variableIcon { - margin-inline-start: 4px; - color: rgba(0, 0, 0, 0.45); - cursor: help; - writing-mode: horizontal-tb; - } - - .variableTable { - margin-top: 14px; - } - .editableRow { - :global(.editable-cell) { - position: relative; - } - - :global(.editable-cell-value-wrap) { - padding: 5px 12px; - cursor: pointer; - height: 22px !important; - } - &:hover { - :global(.editable-cell-value-wrap) { - padding: 4px 11px; - border: 1px solid #d9d9d9; - border-radius: 2px; - } - } - } -} - -.segmentedHidden { - opacity: 0; - height: 0; - width: 0; - margin: 0; -} - -.sliderInputNumber { - width: 80px; -} -.variableSlider { - width: 100%; -} diff --git a/web/src/pages/chat/chat-configuration-modal/index.tsx b/web/src/pages/chat/chat-configuration-modal/index.tsx deleted file mode 100644 index be87cd13e..000000000 --- a/web/src/pages/chat/chat-configuration-modal/index.tsx +++ /dev/null @@ -1,207 +0,0 @@ -import { ReactComponent as ChatConfigurationAtom } from '@/assets/svg/chat-configuration-atom.svg'; -import { IModalManagerChildrenProps } from '@/components/modal-manager'; -import { - ModelVariableType, - settledModelVariableMap, -} from '@/constants/knowledge'; -import { useTranslate } from '@/hooks/common-hooks'; -import { useFetchModelId } from '@/hooks/logic-hooks'; -import { IDialog } from '@/interfaces/database/chat'; -import { getBase64FromUploadFileList } from '@/utils/file-util'; -import { removeUselessFieldsFromValues } from '@/utils/form'; -import { Divider, Flex, Form, Modal, Segmented, UploadFile } from 'antd'; -import { SegmentedValue } from 'antd/es/segmented'; -import camelCase from 'lodash/camelCase'; -import { useEffect, useRef, useState } from 'react'; -import { IPromptConfigParameters } from '../interface'; -import AssistantSetting from './assistant-setting'; -import ModelSetting from './model-setting'; -import PromptEngine from './prompt-engine'; - -import styles from './index.less'; - -const layout = { - labelCol: { span: 9 }, - wrapperCol: { span: 15 }, -}; - -const validateMessages = { - required: '${label} is required!', - types: { - email: '${label} is not a valid email!', - number: '${label} is not a valid number!', - }, - number: { - range: '${label} must be between ${min} and ${max}', - }, -}; - -enum ConfigurationSegmented { - AssistantSetting = 'Assistant Setting', - PromptEngine = 'Prompt Engine', - ModelSetting = 'Model Setting', -} - -const segmentedMap = { - [ConfigurationSegmented.AssistantSetting]: AssistantSetting, - [ConfigurationSegmented.ModelSetting]: ModelSetting, - [ConfigurationSegmented.PromptEngine]: PromptEngine, -}; - -interface IProps extends IModalManagerChildrenProps { - initialDialog: IDialog; - loading: boolean; - onOk: (dialog: IDialog) => void; - clearDialog: () => void; -} - -const ChatConfigurationModal = ({ - visible, - hideModal, - initialDialog, - loading, - onOk, - clearDialog, -}: IProps) => { - const [form] = Form.useForm(); - const [hasError, setHasError] = useState(false); - - const [value, setValue] = useState( - ConfigurationSegmented.AssistantSetting, - ); - const promptEngineRef = useRef>([]); - const modelId = useFetchModelId(); - const { t } = useTranslate('chat'); - - const handleOk = async () => { - const values = await form.validateFields(); - if (hasError) { - return; - } - const nextValues: any = removeUselessFieldsFromValues( - values, - 'llm_setting.', - ); - const emptyResponse = nextValues.prompt_config?.empty_response ?? ''; - - const icon = await getBase64FromUploadFileList(values.icon); - - const finalValues = { - dialog_id: initialDialog.id, - ...nextValues, - vector_similarity_weight: 1 - nextValues.vector_similarity_weight, - prompt_config: { - ...nextValues.prompt_config, - parameters: promptEngineRef.current, - empty_response: emptyResponse, - }, - icon, - }; - onOk(finalValues); - }; - - const handleSegmentedChange = (val: SegmentedValue) => { - setValue(val as ConfigurationSegmented); - }; - - const handleModalAfterClose = () => { - clearDialog(); - form.resetFields(); - }; - - const title = ( - - -
- {t('chatConfiguration')} -
- {t('chatConfigurationDescription')} -
-
-
- ); - - useEffect(() => { - if (visible) { - const icon = initialDialog.icon; - let fileList: UploadFile[] = []; - - if (icon) { - fileList = [{ uid: '1', name: 'file', thumbUrl: icon, status: 'done' }]; - } - form.setFieldsValue({ - ...initialDialog, - llm_setting: - initialDialog.llm_setting ?? - settledModelVariableMap[ModelVariableType.Precise], - icon: fileList, - llm_id: initialDialog.llm_id ?? modelId, - vector_similarity_weight: - 1 - (initialDialog.vector_similarity_weight ?? 0.3), - }); - } - }, [initialDialog, form, visible, modelId]); - - const handleKeyDown = (e: React.KeyboardEvent) => { - // Allow Enter in textareas - if (e.target instanceof HTMLTextAreaElement) { - return; - } - - if (e.key === 'Enter' && !e.shiftKey) { - e.preventDefault(); - handleOk(); - } - }; - - return ( - - ({ - label: t(camelCase(x)), - value: x, - }))} - block - /> - -
- {Object.entries(segmentedMap).map(([key, Element]) => ( - - ))} - -
- ); -}; - -export default ChatConfigurationModal; diff --git a/web/src/pages/chat/chat-configuration-modal/metadata-filter-conditions.tsx b/web/src/pages/chat/chat-configuration-modal/metadata-filter-conditions.tsx deleted file mode 100644 index ce2a0b59a..000000000 --- a/web/src/pages/chat/chat-configuration-modal/metadata-filter-conditions.tsx +++ /dev/null @@ -1,88 +0,0 @@ -import { SwitchOperatorOptions } from '@/constants/agent'; -import { useBuildSwitchOperatorOptions } from '@/hooks/logic-hooks/use-build-operator-options'; -import { useFetchKnowledgeMetadata } from '@/hooks/use-knowledge-request'; -import { MinusCircleOutlined, PlusOutlined } from '@ant-design/icons'; -import { - Button, - Dropdown, - Empty, - Form, - FormListOperation, - Input, - Select, - Space, -} from 'antd'; -import { useCallback } from 'react'; -import { useTranslation } from 'react-i18next'; - -export function MetadataFilterConditions({ kbIds }: { kbIds: string[] }) { - const metadata = useFetchKnowledgeMetadata(kbIds); - const { t } = useTranslation(); - const switchOperatorOptions = useBuildSwitchOperatorOptions(); - - const renderItems = useCallback( - (add: FormListOperation['add']) => { - if (Object.keys(metadata.data).length === 0) { - return [{ key: 'noData', label: }]; - } - return Object.keys(metadata.data).map((key) => { - return { - key, - onClick: () => { - add({ - key, - value: '', - op: SwitchOperatorOptions[0].value, - }); - }, - label: key, - }; - }); - }, - [metadata], - ); - return ( - - {(fields, { add, remove }) => ( - <> - {fields.map(({ key, name, ...restField }) => ( - - - - - - - - remove(name)} /> - - ))} - - - - - - - )} - - ); -} diff --git a/web/src/pages/chat/chat-configuration-modal/model-setting.tsx b/web/src/pages/chat/chat-configuration-modal/model-setting.tsx deleted file mode 100644 index a890bbbbe..000000000 --- a/web/src/pages/chat/chat-configuration-modal/model-setting.tsx +++ /dev/null @@ -1,55 +0,0 @@ -import classNames from 'classnames'; -import { useEffect } from 'react'; -import { ISegmentedContentProps } from '../interface'; - -import LlmSettingItems from '@/components/llm-setting-items'; -import { - ChatVariableEnabledField, - variableEnabledFieldMap, -} from '@/constants/chat'; -import { Variable } from '@/interfaces/database/chat'; -import { setInitialChatVariableEnabledFieldValue } from '@/utils/chat'; -import styles from './index.less'; - -const ModelSetting = ({ - show, - form, - initialLlmSetting, - visible, -}: ISegmentedContentProps & { - initialLlmSetting?: Variable; - visible?: boolean; -}) => { - useEffect(() => { - if (visible) { - const values = Object.keys(variableEnabledFieldMap).reduce< - Record - >((pre, field) => { - pre[field] = - initialLlmSetting === undefined - ? setInitialChatVariableEnabledFieldValue( - field as ChatVariableEnabledField, - ) - : !!initialLlmSetting[ - variableEnabledFieldMap[ - field as keyof typeof variableEnabledFieldMap - ] as keyof Variable - ]; - return pre; - }, {}); - form.setFieldsValue(values); - } - }, [form, initialLlmSetting, visible]); - - return ( -
- {visible && } -
- ); -}; - -export default ModelSetting; diff --git a/web/src/pages/chat/chat-configuration-modal/prompt-engine.tsx b/web/src/pages/chat/chat-configuration-modal/prompt-engine.tsx deleted file mode 100644 index 71bfb2cfe..000000000 --- a/web/src/pages/chat/chat-configuration-modal/prompt-engine.tsx +++ /dev/null @@ -1,222 +0,0 @@ -import SimilaritySlider from '@/components/similarity-slider'; -import { DeleteOutlined, QuestionCircleOutlined } from '@ant-design/icons'; -import { - Button, - Col, - Divider, - Form, - Input, - Row, - Switch, - Table, - TableProps, - Tooltip, -} from 'antd'; -import classNames from 'classnames'; -import { - ForwardedRef, - forwardRef, - useEffect, - useImperativeHandle, - useState, -} from 'react'; -import { v4 as uuid } from 'uuid'; -import { - VariableTableDataType as DataType, - IPromptConfigParameters, - ISegmentedContentProps, -} from '../interface'; -import { EditableCell, EditableRow } from './editable-cell'; - -import { CrossLanguageItem } from '@/components/cross-language-item'; -import Rerank from '@/components/rerank'; -import TopNItem from '@/components/top-n-item'; -import { UseKnowledgeGraphItem } from '@/components/use-knowledge-graph-item'; -import { useTranslate } from '@/hooks/common-hooks'; -import { useSelectPromptConfigParameters } from '../hooks'; -import styles from './index.less'; - -const PromptEngine = ( - { show }: ISegmentedContentProps, - ref: ForwardedRef>, -) => { - const [dataSource, setDataSource] = useState([]); - const parameters = useSelectPromptConfigParameters(); - const { t } = useTranslate('chat'); - - const components = { - body: { - row: EditableRow, - cell: EditableCell, - }, - }; - - const handleRemove = (key: string) => () => { - const newData = dataSource.filter((item) => item.key !== key); - setDataSource(newData); - }; - - const handleSave = (row: DataType) => { - const newData = [...dataSource]; - const index = newData.findIndex((item) => row.key === item.key); - const item = newData[index]; - newData.splice(index, 1, { - ...item, - ...row, - }); - setDataSource(newData); - }; - - const handleAdd = () => { - setDataSource((state) => [ - ...state, - { - key: uuid(), - variable: '', - optional: true, - }, - ]); - }; - - const handleOptionalChange = (row: DataType) => (checked: boolean) => { - const newData = [...dataSource]; - const index = newData.findIndex((item) => row.key === item.key); - const item = newData[index]; - newData.splice(index, 1, { - ...item, - optional: checked, - }); - setDataSource(newData); - }; - - useImperativeHandle( - ref, - () => { - return dataSource - .filter((x) => x.variable.trim() !== '') - .map((x) => ({ key: x.variable, optional: x.optional })); - }, - [dataSource], - ); - - const columns: TableProps['columns'] = [ - { - title: t('key'), - dataIndex: 'variable', - key: 'variable', - onCell: (record: DataType) => ({ - record, - editable: true, - dataIndex: 'variable', - title: 'key', - handleSave, - }), - }, - { - title: t('optional'), - dataIndex: 'optional', - key: 'optional', - width: 40, - align: 'center', - render(text, record) { - return ( - - ); - }, - }, - { - title: t('operation'), - dataIndex: 'operation', - width: 30, - key: 'operation', - align: 'center', - render(_, record) { - return ; - }, - }, - ]; - - useEffect(() => { - setDataSource(parameters); - }, [parameters]); - - return ( -
- - - - - - - - - - - - - - - -
- -
- - - - - - - {dataSource.length > 0 && ( - - - -
{childNode}
styles.editableRow} - /> - - - )} - - - ); -}; - -export default forwardRef(PromptEngine); diff --git a/web/src/pages/chat/chat-container/index.less b/web/src/pages/chat/chat-container/index.less deleted file mode 100644 index 8430b1ef6..000000000 --- a/web/src/pages/chat/chat-container/index.less +++ /dev/null @@ -1,7 +0,0 @@ -.chatContainer { - padding: 0 0 24px 24px; - .messageContainer { - overflow-y: auto; - padding-right: 24px; - } -} diff --git a/web/src/pages/chat/chat-container/index.tsx b/web/src/pages/chat/chat-container/index.tsx deleted file mode 100644 index de5b41faf..000000000 --- a/web/src/pages/chat/chat-container/index.tsx +++ /dev/null @@ -1,125 +0,0 @@ -import MessageItem from '@/components/message-item'; -import { MessageType } from '@/constants/chat'; -import { Flex, Spin } from 'antd'; -import { - useCreateConversationBeforeUploadDocument, - useGetFileIcon, - useGetSendButtonDisabled, - useSendButtonDisabled, - useSendNextMessage, -} from '../hooks'; -import { buildMessageItemReference } from '../utils'; - -import MessageInput from '@/components/message-input'; -import PdfDrawer from '@/components/pdf-drawer'; -import { useClickDrawer } from '@/components/pdf-drawer/hooks'; -import { - useFetchNextConversation, - useFetchNextDialog, - useGetChatSearchParams, -} from '@/hooks/chat-hooks'; -import { useFetchUserInfo } from '@/hooks/user-setting-hooks'; -import { buildMessageUuidWithRole } from '@/utils/chat'; -import { memo } from 'react'; -import styles from './index.less'; - -interface IProps { - controller: AbortController; -} - -const ChatContainer = ({ controller }: IProps) => { - const { conversationId } = useGetChatSearchParams(); - const { data: conversation } = useFetchNextConversation(); - const { data: currentDialog } = useFetchNextDialog(); - - const { - value, - scrollRef, - messageContainerRef, - loading, - sendLoading, - derivedMessages, - handleInputChange, - handlePressEnter, - regenerateMessage, - removeMessageById, - stopOutputMessage, - } = useSendNextMessage(controller); - - const { visible, hideModal, documentId, selectedChunk, clickDocumentButton } = - useClickDrawer(); - const disabled = useGetSendButtonDisabled(); - const sendDisabled = useSendButtonDisabled(value); - useGetFileIcon(); - const { data: userInfo } = useFetchUserInfo(); - const { createConversationBeforeUploadDocument } = - useCreateConversationBeforeUploadDocument(); - - return ( - <> - - -
- - {derivedMessages?.map((message, i) => { - return ( - - ); - })} - -
-
- - - - - - ); -}; - -export default memo(ChatContainer); diff --git a/web/src/pages/chat/chat-id-modal/index.less b/web/src/pages/chat/chat-id-modal/index.less deleted file mode 100644 index c95b34c95..000000000 --- a/web/src/pages/chat/chat-id-modal/index.less +++ /dev/null @@ -1,3 +0,0 @@ -.id { - .linkText(); -} diff --git a/web/src/pages/chat/chat-id-modal/index.tsx b/web/src/pages/chat/chat-id-modal/index.tsx deleted file mode 100644 index d640be055..000000000 --- a/web/src/pages/chat/chat-id-modal/index.tsx +++ /dev/null @@ -1,38 +0,0 @@ -import { useTranslate } from '@/hooks/common-hooks'; -import { IModalProps } from '@/interfaces/common'; -import { Modal, Typography } from 'antd'; - -import styles from './index.less'; - -const { Paragraph, Link } = Typography; - -const ChatIdModal = ({ - visible, - hideModal, - id, -}: IModalProps & { id: string; name?: string; idKey: string }) => { - const { t } = useTranslate('chat'); - - return ( - - - {id} - - - {t('howUseId')} - - - ); -}; - -export default ChatIdModal; diff --git a/web/src/pages/chat/constants.ts b/web/src/pages/chat/constants.ts deleted file mode 100644 index 8c9a965f4..000000000 --- a/web/src/pages/chat/constants.ts +++ /dev/null @@ -1 +0,0 @@ -export const EmptyConversationId = 'empty'; diff --git a/web/src/pages/chat/context.ts b/web/src/pages/chat/context.ts deleted file mode 100644 index 117641da5..000000000 --- a/web/src/pages/chat/context.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { createContext } from 'react'; - -export const ConversationContext = createContext< - null | ((isPlaying: boolean) => void) ->(null); diff --git a/web/src/pages/chat/hooks.ts b/web/src/pages/chat/hooks.ts deleted file mode 100644 index ce0d657cd..000000000 --- a/web/src/pages/chat/hooks.ts +++ /dev/null @@ -1,620 +0,0 @@ -import { ChatSearchParams, MessageType } from '@/constants/chat'; -import { fileIconMap } from '@/constants/common'; -import { - useFetchManualConversation, - useFetchManualDialog, - useFetchNextConversation, - useFetchNextConversationList, - useFetchNextDialog, - useFetchNextDialogList, - useGetChatSearchParams, - useRemoveNextConversation, - useRemoveNextDialog, - useSetNextDialog, - useUpdateNextConversation, -} from '@/hooks/chat-hooks'; -import { - useSetModalState, - useShowDeleteConfirm, - useTranslate, -} from '@/hooks/common-hooks'; -import { - useRegenerateMessage, - useSelectDerivedMessages, - useSendMessageWithSse, -} from '@/hooks/logic-hooks'; -import { IConversation, IDialog, Message } from '@/interfaces/database/chat'; -import { getFileExtension } from '@/utils'; -import api from '@/utils/api'; -import { getConversationId } from '@/utils/chat'; -import { useMutationState } from '@tanstack/react-query'; -import { get } from 'lodash'; -import trim from 'lodash/trim'; -import { - ChangeEventHandler, - useCallback, - useEffect, - useMemo, - useState, -} from 'react'; -import { useSearchParams } from 'umi'; -import { v4 as uuid } from 'uuid'; -import { - IClientConversation, - IMessage, - VariableTableDataType, -} from './interface'; - -export const useSetChatRouteParams = () => { - const [currentQueryParameters, setSearchParams] = useSearchParams(); - const newQueryParameters: URLSearchParams = useMemo( - () => new URLSearchParams(currentQueryParameters.toString()), - [currentQueryParameters], - ); - - const setConversationIsNew = useCallback( - (value: string) => { - newQueryParameters.set(ChatSearchParams.isNew, value); - setSearchParams(newQueryParameters); - }, - [newQueryParameters, setSearchParams], - ); - - const getConversationIsNew = useCallback(() => { - return newQueryParameters.get(ChatSearchParams.isNew); - }, [newQueryParameters]); - - return { setConversationIsNew, getConversationIsNew }; -}; - -export const useSetNewConversationRouteParams = () => { - const [currentQueryParameters, setSearchParams] = useSearchParams(); - const newQueryParameters: URLSearchParams = useMemo( - () => new URLSearchParams(currentQueryParameters.toString()), - [currentQueryParameters], - ); - - const setNewConversationRouteParams = useCallback( - (conversationId: string, isNew: string) => { - newQueryParameters.set(ChatSearchParams.ConversationId, conversationId); - newQueryParameters.set(ChatSearchParams.isNew, isNew); - setSearchParams(newQueryParameters); - }, - [newQueryParameters, setSearchParams], - ); - - return { setNewConversationRouteParams }; -}; - -export const useSelectCurrentDialog = () => { - const data = useMutationState({ - filters: { mutationKey: ['fetchDialog'] }, - select: (mutation) => { - return get(mutation, 'state.data.data', {}); - }, - }); - - return (data.at(-1) ?? {}) as IDialog; -}; - -export const useSelectPromptConfigParameters = (): VariableTableDataType[] => { - const { data: currentDialog } = useFetchNextDialog(); - - const finalParameters: VariableTableDataType[] = useMemo(() => { - const parameters = currentDialog?.prompt_config?.parameters ?? []; - if (!currentDialog.id) { - // The newly created chat has a default parameter - return [{ key: uuid(), variable: 'knowledge', optional: false }]; - } - return parameters.map((x) => ({ - key: uuid(), - variable: x.key, - optional: x.optional, - })); - }, [currentDialog]); - - return finalParameters; -}; - -export const useDeleteDialog = () => { - const showDeleteConfirm = useShowDeleteConfirm(); - - const { removeDialog } = useRemoveNextDialog(); - - const onRemoveDialog = (dialogIds: Array) => { - showDeleteConfirm({ onOk: () => removeDialog(dialogIds) }); - }; - - return { onRemoveDialog }; -}; - -export const useHandleItemHover = () => { - const [activated, setActivated] = useState(''); - - const handleItemEnter = (id: string) => { - setActivated(id); - }; - - const handleItemLeave = () => { - setActivated(''); - }; - - return { - activated, - handleItemEnter, - handleItemLeave, - }; -}; - -export const useEditDialog = () => { - const [dialog, setDialog] = useState({} as IDialog); - const { fetchDialog } = useFetchManualDialog(); - const { setDialog: submitDialog, loading } = useSetNextDialog(); - - const { - visible: dialogEditVisible, - hideModal: hideDialogEditModal, - showModal: showDialogEditModal, - } = useSetModalState(); - - const hideModal = useCallback(() => { - setDialog({} as IDialog); - hideDialogEditModal(); - }, [hideDialogEditModal]); - - const onDialogEditOk = useCallback( - async (dialog: IDialog) => { - const ret = await submitDialog(dialog); - - if (ret === 0) { - hideModal(); - } - }, - [submitDialog, hideModal], - ); - - const handleShowDialogEditModal = useCallback( - async (dialogId?: string) => { - if (dialogId) { - const ret = await fetchDialog(dialogId); - if (ret.code === 0) { - setDialog(ret.data); - } - } - showDialogEditModal(); - }, - [showDialogEditModal, fetchDialog], - ); - - const clearDialog = useCallback(() => { - setDialog({} as IDialog); - }, []); - - return { - dialogSettingLoading: loading, - initialDialog: dialog, - onDialogEditOk, - dialogEditVisible, - hideDialogEditModal: hideModal, - showDialogEditModal: handleShowDialogEditModal, - clearDialog, - }; -}; - -//#region conversation - -const useFindPrologueFromDialogList = () => { - const { dialogId } = useGetChatSearchParams(); - const { data: dialogList } = useFetchNextDialogList(true); - const prologue = useMemo(() => { - return dialogList.find((x) => x.id === dialogId)?.prompt_config.prologue; - }, [dialogId, dialogList]); - - return prologue; -}; - -export const useSelectDerivedConversationList = () => { - const { t } = useTranslate('chat'); - - const [list, setList] = useState>([]); - const { data: conversationList, loading } = useFetchNextConversationList(); - const { dialogId } = useGetChatSearchParams(); - const { setNewConversationRouteParams } = useSetNewConversationRouteParams(); - const prologue = useFindPrologueFromDialogList(); - - const addTemporaryConversation = useCallback(() => { - const conversationId = getConversationId(); - setList((pre) => { - if (dialogId) { - setNewConversationRouteParams(conversationId, 'true'); - const nextList = [ - { - id: conversationId, - name: t('newConversation'), - dialog_id: dialogId, - is_new: true, - message: [ - { - content: prologue, - role: MessageType.Assistant, - }, - ], - } as any, - ...conversationList, - ]; - return nextList; - } - - return pre; - }); - }, [conversationList, dialogId, prologue, t, setNewConversationRouteParams]); - - // When you first enter the page, select the top conversation card - - useEffect(() => { - setList([...conversationList]); - }, [conversationList]); - - return { list, addTemporaryConversation, loading }; -}; - -export const useSetConversation = () => { - const { dialogId } = useGetChatSearchParams(); - const { updateConversation } = useUpdateNextConversation(); - - const setConversation = useCallback( - async ( - message: string, - isNew: boolean = false, - conversationId?: string, - ) => { - const data = await updateConversation({ - dialog_id: dialogId, - name: message, - is_new: isNew, - conversation_id: conversationId, - message: [ - { - role: MessageType.Assistant, - content: message, - }, - ], - }); - - return data; - }, - [updateConversation, dialogId], - ); - - return { setConversation }; -}; - -export const useSelectNextMessages = () => { - const { - scrollRef, - messageContainerRef, - setDerivedMessages, - derivedMessages, - addNewestAnswer, - addNewestQuestion, - removeLatestMessage, - removeMessageById, - removeMessagesAfterCurrentMessage, - } = useSelectDerivedMessages(); - const { data: conversation, loading } = useFetchNextConversation(); - const { conversationId, dialogId, isNew } = useGetChatSearchParams(); - const prologue = useFindPrologueFromDialogList(); - - const addPrologue = useCallback(() => { - if (dialogId !== '' && isNew === 'true') { - const nextMessage = { - role: MessageType.Assistant, - content: prologue, - id: uuid(), - } as IMessage; - - setDerivedMessages([nextMessage]); - } - }, [dialogId, isNew, prologue, setDerivedMessages]); - - useEffect(() => { - addPrologue(); - }, [addPrologue]); - - useEffect(() => { - if ( - conversationId && - isNew !== 'true' && - conversation.message?.length > 0 - ) { - setDerivedMessages(conversation.message); - } - - if (!conversationId) { - setDerivedMessages([]); - } - }, [conversation.message, conversationId, setDerivedMessages, isNew]); - - return { - scrollRef, - messageContainerRef, - derivedMessages, - loading, - addNewestAnswer, - addNewestQuestion, - removeLatestMessage, - removeMessageById, - removeMessagesAfterCurrentMessage, - }; -}; - -export const useHandleMessageInputChange = () => { - const [value, setValue] = useState(''); - - const handleInputChange: ChangeEventHandler = (e) => { - const value = e.target.value; - // const nextValue = value.replaceAll('\\n', '\n').replaceAll('\\t', '\t'); - setValue(value); - }; - - return { - handleInputChange, - value, - setValue, - }; -}; - -export const useSendNextMessage = (controller: AbortController) => { - const { setConversation } = useSetConversation(); - const { conversationId, isNew } = useGetChatSearchParams(); - const { handleInputChange, value, setValue } = useHandleMessageInputChange(); - - const { send, answer, done } = useSendMessageWithSse( - api.completeConversation, - ); - const { - scrollRef, - messageContainerRef, - derivedMessages, - loading, - addNewestAnswer, - addNewestQuestion, - removeLatestMessage, - removeMessageById, - removeMessagesAfterCurrentMessage, - } = useSelectNextMessages(); - const { setConversationIsNew, getConversationIsNew } = - useSetChatRouteParams(); - - const stopOutputMessage = useCallback(() => { - controller.abort(); - }, [controller]); - - const sendMessage = useCallback( - async ({ - message, - currentConversationId, - messages, - }: { - message: Message; - currentConversationId?: string; - messages?: Message[]; - }) => { - const res = await send( - { - conversation_id: currentConversationId ?? conversationId, - messages: [...(messages ?? derivedMessages ?? []), message], - }, - controller, - ); - - if (res && (res?.response.status !== 200 || res?.data?.code !== 0)) { - // cancel loading - setValue(message.content); - console.info('removeLatestMessage111'); - removeLatestMessage(); - } - }, - [ - derivedMessages, - conversationId, - removeLatestMessage, - setValue, - send, - controller, - ], - ); - - const handleSendMessage = useCallback( - async (message: Message) => { - const isNew = getConversationIsNew(); - if (isNew !== 'true') { - sendMessage({ message }); - } else { - const data = await setConversation( - message.content, - true, - conversationId, - ); - if (data.code === 0) { - setConversationIsNew(''); - const id = data.data.id; - // currentConversationIdRef.current = id; - sendMessage({ - message, - currentConversationId: id, - messages: data.data.message, - }); - } - } - }, - [ - setConversation, - sendMessage, - setConversationIsNew, - getConversationIsNew, - conversationId, - ], - ); - - const { regenerateMessage } = useRegenerateMessage({ - removeMessagesAfterCurrentMessage, - sendMessage, - messages: derivedMessages, - }); - - useEffect(() => { - // #1289 - if (answer.answer && conversationId && isNew !== 'true') { - addNewestAnswer(answer); - } - }, [answer, addNewestAnswer, conversationId, isNew]); - - const handlePressEnter = useCallback( - (documentIds: string[]) => { - if (trim(value) === '') return; - const id = uuid(); - - addNewestQuestion({ - content: value, - doc_ids: documentIds, - id, - role: MessageType.User, - }); - if (done) { - setValue(''); - handleSendMessage({ - id, - content: value.trim(), - role: MessageType.User, - doc_ids: documentIds, - }); - } - }, - [addNewestQuestion, handleSendMessage, done, setValue, value], - ); - - return { - handlePressEnter, - handleInputChange, - value, - setValue, - regenerateMessage, - sendLoading: !done, - loading, - scrollRef, - messageContainerRef, - derivedMessages, - removeMessageById, - stopOutputMessage, - }; -}; - -export const useGetFileIcon = () => { - const getFileIcon = (filename: string) => { - const ext: string = getFileExtension(filename); - const iconPath = fileIconMap[ext as keyof typeof fileIconMap]; - return `@/assets/svg/file-icon/${iconPath}`; - }; - - return getFileIcon; -}; - -export const useDeleteConversation = () => { - const showDeleteConfirm = useShowDeleteConfirm(); - const { removeConversation } = useRemoveNextConversation(); - - const deleteConversation = (conversationIds: Array) => async () => { - const ret = await removeConversation(conversationIds); - - return ret; - }; - - const onRemoveConversation = (conversationIds: Array) => { - showDeleteConfirm({ onOk: deleteConversation(conversationIds) }); - }; - - return { onRemoveConversation }; -}; - -export const useRenameConversation = () => { - const [conversation, setConversation] = useState( - {} as IClientConversation, - ); - const { fetchConversation } = useFetchManualConversation(); - const { - visible: conversationRenameVisible, - hideModal: hideConversationRenameModal, - showModal: showConversationRenameModal, - } = useSetModalState(); - const { updateConversation, loading } = useUpdateNextConversation(); - - const onConversationRenameOk = useCallback( - async (name: string) => { - const ret = await updateConversation({ - conversation_id: conversation.id, - name, - is_new: false, - }); - - if (ret.code === 0) { - hideConversationRenameModal(); - } - }, - [updateConversation, conversation, hideConversationRenameModal], - ); - - const handleShowConversationRenameModal = useCallback( - async (conversationId: string) => { - const ret = await fetchConversation(conversationId); - if (ret.code === 0) { - setConversation(ret.data); - } - showConversationRenameModal(); - }, - [showConversationRenameModal, fetchConversation], - ); - - return { - conversationRenameLoading: loading, - initialConversationName: conversation.name, - onConversationRenameOk, - conversationRenameVisible, - hideConversationRenameModal, - showConversationRenameModal: handleShowConversationRenameModal, - }; -}; - -export const useGetSendButtonDisabled = () => { - const { dialogId, conversationId } = useGetChatSearchParams(); - - return dialogId === '' || conversationId === ''; -}; - -export const useSendButtonDisabled = (value: string) => { - return trim(value) === ''; -}; - -export const useCreateConversationBeforeUploadDocument = () => { - const { setConversation } = useSetConversation(); - const { dialogId } = useGetChatSearchParams(); - const { getConversationIsNew } = useSetChatRouteParams(); - - const createConversationBeforeUploadDocument = useCallback( - async (message: string) => { - const isNew = getConversationIsNew(); - if (isNew === 'true') { - const data = await setConversation(message, true); - - return data; - } - }, - [setConversation, getConversationIsNew], - ); - - return { - createConversationBeforeUploadDocument, - dialogId, - }; -}; -//#endregion diff --git a/web/src/pages/chat/index.less b/web/src/pages/chat/index.less deleted file mode 100644 index 58bcb26dc..000000000 --- a/web/src/pages/chat/index.less +++ /dev/null @@ -1,82 +0,0 @@ -.chatWrapper { - height: 100%; - width: 100%; - - .chatAppWrapper { - width: 288px; - padding: 26px; - - .chatAppContent { - overflow-y: auto; - width: 100%; - } - - .chatAppCard { - :global(.ant-card-body) { - padding: 10px; - } - .cubeIcon { - &:hover { - cursor: pointer; - } - } - } - .chatAppCardSelected { - :global(.ant-card-body) { - background-color: @gray11; - border-radius: 8px; - } - } - .chatAppCardSelectedDark { - :global(.ant-card-body) { - background-color: rgba(255, 255, 255, 0.1); - border-radius: 8px; - } - } - } - .chatTitleWrapper { - width: 220px; - padding: 26px 0; - } - - .chatTitle { - padding: 5px 15px; - } - - .chatTitleContent { - padding: 5px 10px; - overflow: auto; - } - - .chatSpin { - :global(.ant-spin-container) { - display: flex; - flex-direction: column; - gap: 10px; - } - } - - .chatTitleCard { - :global(.ant-card-body) { - padding: 8px; - } - } - - .chatTitleCardSelected { - :global(.ant-card-body) { - background-color: @gray11; - border-radius: 8px; - } - } - .chatTitleCardSelectedDark { - :global(.ant-card-body) { - background-color: rgba(255, 255, 255, 0.1); - border-radius: 8px; - } - } - - .divider { - margin: 0; - height: 100%; - } -} diff --git a/web/src/pages/chat/index.tsx b/web/src/pages/chat/index.tsx deleted file mode 100644 index 9c7d67e92..000000000 --- a/web/src/pages/chat/index.tsx +++ /dev/null @@ -1,393 +0,0 @@ -import { ReactComponent as ChatAppCube } from '@/assets/svg/chat-app-cube.svg'; -import RenameModal from '@/components/rename-modal'; -import { DeleteOutlined, EditOutlined } from '@ant-design/icons'; -import { - Avatar, - Button, - Card, - Divider, - Dropdown, - Flex, - MenuProps, - Space, - Spin, - Tag, - Tooltip, - Typography, -} from 'antd'; -import { MenuItemProps } from 'antd/lib/menu/MenuItem'; -import classNames from 'classnames'; -import { useCallback, useState } from 'react'; -import ChatConfigurationModal from './chat-configuration-modal'; -import ChatContainer from './chat-container'; -import { - useDeleteConversation, - useDeleteDialog, - useEditDialog, - useHandleItemHover, - useRenameConversation, - useSelectDerivedConversationList, -} from './hooks'; - -import EmbedModal from '@/components/api-service/embed-modal'; -import { useShowEmbedModal } from '@/components/api-service/hooks'; -import SvgIcon from '@/components/svg-icon'; -import { useTheme } from '@/components/theme-provider'; -import { SharedFrom } from '@/constants/chat'; -import { - useClickConversationCard, - useClickDialogCard, - useFetchNextDialogList, - useGetChatSearchParams, -} from '@/hooks/chat-hooks'; -import { useTranslate } from '@/hooks/common-hooks'; -import { useSetSelectedRecord } from '@/hooks/logic-hooks'; -import { IDialog } from '@/interfaces/database/chat'; -import { PictureInPicture2 } from 'lucide-react'; -import styles from './index.less'; - -const { Text } = Typography; - -const Chat = () => { - const { data: dialogList, loading: dialogLoading } = useFetchNextDialogList(); - const { onRemoveDialog } = useDeleteDialog(); - const { onRemoveConversation } = useDeleteConversation(); - const { handleClickDialog } = useClickDialogCard(); - const { handleClickConversation } = useClickConversationCard(); - const { dialogId, conversationId } = useGetChatSearchParams(); - const { theme } = useTheme(); - const { - list: conversationList, - addTemporaryConversation, - loading: conversationLoading, - } = useSelectDerivedConversationList(); - const { activated, handleItemEnter, handleItemLeave } = useHandleItemHover(); - const { - activated: conversationActivated, - handleItemEnter: handleConversationItemEnter, - handleItemLeave: handleConversationItemLeave, - } = useHandleItemHover(); - const { - conversationRenameLoading, - initialConversationName, - onConversationRenameOk, - conversationRenameVisible, - hideConversationRenameModal, - showConversationRenameModal, - } = useRenameConversation(); - const { - dialogSettingLoading, - initialDialog, - onDialogEditOk, - dialogEditVisible, - clearDialog, - hideDialogEditModal, - showDialogEditModal, - } = useEditDialog(); - const { t } = useTranslate('chat'); - const { currentRecord, setRecord } = useSetSelectedRecord(); - const [controller, setController] = useState(new AbortController()); - const { showEmbedModal, hideEmbedModal, embedVisible, beta } = - useShowEmbedModal(); - - const handleAppCardEnter = (id: string) => () => { - handleItemEnter(id); - }; - - const handleConversationCardEnter = (id: string) => () => { - handleConversationItemEnter(id); - }; - - const handleShowChatConfigurationModal = - (dialogId?: string): any => - (info: any) => { - info?.domEvent?.preventDefault(); - info?.domEvent?.stopPropagation(); - showDialogEditModal(dialogId); - }; - - const handleRemoveDialog = - (dialogId: string): MenuItemProps['onClick'] => - ({ domEvent }) => { - domEvent.preventDefault(); - domEvent.stopPropagation(); - onRemoveDialog([dialogId]); - }; - - const handleShowOverviewModal = - (dialog: IDialog): any => - (info: any) => { - info?.domEvent?.preventDefault(); - info?.domEvent?.stopPropagation(); - setRecord(dialog); - showEmbedModal(); - }; - - const handleRemoveConversation = - (conversationId: string): MenuItemProps['onClick'] => - ({ domEvent }) => { - domEvent.preventDefault(); - domEvent.stopPropagation(); - onRemoveConversation([conversationId]); - }; - - const handleShowConversationRenameModal = - (conversationId: string): MenuItemProps['onClick'] => - ({ domEvent }) => { - domEvent.preventDefault(); - domEvent.stopPropagation(); - showConversationRenameModal(conversationId); - }; - - const handleDialogCardClick = useCallback( - (dialogId: string) => () => { - handleClickDialog(dialogId); - }, - [handleClickDialog], - ); - - const handleConversationCardClick = useCallback( - (conversationId: string, isNew: boolean) => () => { - handleClickConversation(conversationId, isNew ? 'true' : ''); - setController((pre) => { - pre.abort(); - return new AbortController(); - }); - }, - [handleClickConversation], - ); - - const handleCreateTemporaryConversation = useCallback(() => { - addTemporaryConversation(); - }, [addTemporaryConversation]); - - const buildAppItems = (dialog: IDialog) => { - const dialogId = dialog.id; - - const appItems: MenuProps['items'] = [ - { - key: '1', - onClick: handleShowChatConfigurationModal(dialogId), - label: ( - - - {t('edit', { keyPrefix: 'common' })} - - ), - }, - { type: 'divider' }, - { - key: '2', - onClick: handleRemoveDialog(dialogId), - label: ( - - - {t('delete', { keyPrefix: 'common' })} - - ), - }, - { type: 'divider' }, - { - key: '3', - onClick: handleShowOverviewModal(dialog), - label: ( - - {/* */} - - {t('embedIntoSite', { keyPrefix: 'common' })} - - ), - }, - ]; - - return appItems; - }; - - const buildConversationItems = (conversationId: string) => { - const appItems: MenuProps['items'] = [ - { - key: '1', - onClick: handleShowConversationRenameModal(conversationId), - label: ( - - - {t('rename', { keyPrefix: 'common' })} - - ), - }, - { type: 'divider' }, - { - key: '2', - onClick: handleRemoveConversation(conversationId), - label: ( - - - {t('delete', { keyPrefix: 'common' })} - - ), - }, - ]; - - return appItems; - }; - - return ( - - - - - - - - {dialogList.map((x) => ( - - - - -
- - - {x.name} - - -
{x.description}
-
-
- {activated === x.id && ( -
- - - -
- )} -
-
- ))} -
-
-
-
- - - - - - {t('chat')} - {conversationList.length} - - -
- -
-
-
- - - - {conversationList.map((x) => ( - - -
- - {x.name} - -
- {conversationActivated === x.id && - x.id !== '' && - !x.is_new && ( -
- - - -
- )} -
-
- ))} -
-
-
-
- - - {dialogEditVisible && ( - - )} - - - {embedVisible && ( - - )} -
- ); -}; - -export default Chat; diff --git a/web/src/pages/chat/interface.ts b/web/src/pages/chat/interface.ts deleted file mode 100644 index 570c6da21..000000000 --- a/web/src/pages/chat/interface.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { IConversation, IReference, Message } from '@/interfaces/database/chat'; -import { FormInstance } from 'antd'; - -export interface ISegmentedContentProps { - show: boolean; - form: FormInstance; - setHasError: (hasError: boolean) => void; -} - -export interface IVariable { - temperature: number; - top_p: number; - frequency_penalty: number; - presence_penalty: number; - max_tokens: number; -} - -export interface VariableTableDataType { - key: string; - variable: string; - optional: boolean; -} - -export type IPromptConfigParameters = Omit; - -export interface IMessage extends Message { - id: string; - reference?: IReference; // the latest news has reference -} - -export interface IClientConversation extends IConversation { - message: IMessage[]; -} diff --git a/web/src/pages/chat/share/index.less b/web/src/pages/chat/share/index.less deleted file mode 100644 index 01e090061..000000000 --- a/web/src/pages/chat/share/index.less +++ /dev/null @@ -1,13 +0,0 @@ -.chatWrapper { - height: 100vh; -} - -.chatContainer { - padding: 10px; - box-sizing: border-box; - height: 100%; - .messageContainer { - overflow-y: auto; - padding-right: 6px; - } -} diff --git a/web/src/pages/chat/share/index.tsx b/web/src/pages/chat/share/index.tsx deleted file mode 100644 index acaadcbf9..000000000 --- a/web/src/pages/chat/share/index.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import ChatContainer from './large'; - -import styles from './index.less'; - -const SharedChat = () => { - return ( -
- -
- ); -}; - -export default SharedChat; diff --git a/web/src/pages/chat/share/large.tsx b/web/src/pages/chat/share/large.tsx deleted file mode 100644 index dfdd8c5a7..000000000 --- a/web/src/pages/chat/share/large.tsx +++ /dev/null @@ -1,124 +0,0 @@ -import MessageInput from '@/components/message-input'; -import MessageItem from '@/components/message-item'; -import { useClickDrawer } from '@/components/pdf-drawer/hooks'; -import { MessageType, SharedFrom } from '@/constants/chat'; -import { useSendButtonDisabled } from '@/pages/chat/hooks'; -import { Flex, Spin } from 'antd'; -import React, { forwardRef, useMemo } from 'react'; -import { - useGetSharedChatSearchParams, - useSendSharedMessage, -} from '../shared-hooks'; -import { buildMessageItemReference } from '../utils'; - -import PdfDrawer from '@/components/pdf-drawer'; -import { useFetchNextConversationSSE } from '@/hooks/chat-hooks'; -import { useFetchFlowSSE } from '@/hooks/flow-hooks'; -import i18n from '@/locales/config'; -import { buildMessageUuidWithRole } from '@/utils/chat'; -import styles from './index.less'; - -const ChatContainer = () => { - const { - sharedId: conversationId, - from, - locale, - visibleAvatar, - } = useGetSharedChatSearchParams(); - const { visible, hideModal, documentId, selectedChunk, clickDocumentButton } = - useClickDrawer(); - - const { - handlePressEnter, - handleInputChange, - value, - sendLoading, - loading, - ref, - derivedMessages, - hasError, - stopOutputMessage, - } = useSendSharedMessage(); - const sendDisabled = useSendButtonDisabled(value); - - const useFetchAvatar = useMemo(() => { - return from === SharedFrom.Agent - ? useFetchFlowSSE - : useFetchNextConversationSSE; - }, [from]); - React.useEffect(() => { - if (locale && i18n.language !== locale) { - i18n.changeLanguage(locale); - } - }, [locale, visibleAvatar]); - const { data: avatarData } = useFetchAvatar(); - - if (!conversationId) { - return
empty
; - } - - return ( - <> - - -
- - {derivedMessages?.map((message, i) => { - return ( - - ); - })} - -
-
- - - - - {visible && ( - - )} - - ); -}; - -export default forwardRef(ChatContainer); diff --git a/web/src/pages/chat/shared-hooks.ts b/web/src/pages/chat/shared-hooks.ts deleted file mode 100644 index be5d49ffe..000000000 --- a/web/src/pages/chat/shared-hooks.ts +++ /dev/null @@ -1,149 +0,0 @@ -import { MessageType, SharedFrom } from '@/constants/chat'; -import { useCreateNextSharedConversation } from '@/hooks/chat-hooks'; -import { - useSelectDerivedMessages, - useSendMessageWithSse, -} from '@/hooks/logic-hooks'; -import { Message } from '@/interfaces/database/chat'; -import { message } from 'antd'; -import { get } from 'lodash'; -import trim from 'lodash/trim'; -import { useCallback, useEffect, useState } from 'react'; -import { useSearchParams } from 'umi'; -import { v4 as uuid } from 'uuid'; -import { useHandleMessageInputChange } from './hooks'; - -const isCompletionError = (res: any) => - res && (res?.response.status !== 200 || res?.data?.code !== 0); - -export const useSendButtonDisabled = (value: string) => { - return trim(value) === ''; -}; - -export const useGetSharedChatSearchParams = () => { - const [searchParams] = useSearchParams(); - const data_prefix = 'data_'; - const data = Object.fromEntries( - searchParams - .entries() - .filter(([key]) => key.startsWith(data_prefix)) - .map(([key, value]) => [key.replace(data_prefix, ''), value]), - ); - return { - from: searchParams.get('from') as SharedFrom, - sharedId: searchParams.get('shared_id'), - locale: searchParams.get('locale'), - data: data, - visibleAvatar: searchParams.get('visible_avatar') - ? searchParams.get('visible_avatar') !== '1' - : true, - }; -}; - -export const useSendSharedMessage = () => { - const { - from, - sharedId: conversationId, - data: data, - } = useGetSharedChatSearchParams(); - const { createSharedConversation: setConversation } = - useCreateNextSharedConversation(); - const { handleInputChange, value, setValue } = useHandleMessageInputChange(); - const { send, answer, done, stopOutputMessage } = useSendMessageWithSse( - `/api/v1/${from === SharedFrom.Agent ? 'agentbots' : 'chatbots'}/${conversationId}/completions`, - ); - const { - derivedMessages, - ref, - removeLatestMessage, - addNewestAnswer, - addNewestQuestion, - } = useSelectDerivedMessages(); - const [hasError, setHasError] = useState(false); - - const sendMessage = useCallback( - async (message: Message, id?: string) => { - const res = await send({ - conversation_id: id ?? conversationId, - quote: true, - question: message.content, - session_id: get(derivedMessages, '0.session_id'), - }); - - if (isCompletionError(res)) { - // cancel loading - setValue(message.content); - removeLatestMessage(); - } - }, - [send, conversationId, derivedMessages, setValue, removeLatestMessage], - ); - - const handleSendMessage = useCallback( - async (message: Message) => { - if (conversationId !== '') { - sendMessage(message); - } else { - const data = await setConversation('user id'); - if (data.code === 0) { - const id = data.data.id; - sendMessage(message, id); - } - } - }, - [conversationId, setConversation, sendMessage], - ); - - const fetchSessionId = useCallback(async () => { - const payload = { question: '' }; - const ret = await send({ ...payload, ...data }); - if (isCompletionError(ret)) { - message.error(ret?.data.message); - setHasError(true); - } - }, [send]); - - useEffect(() => { - fetchSessionId(); - }, [fetchSessionId, send]); - - useEffect(() => { - if (answer.answer) { - addNewestAnswer(answer); - } - }, [answer, addNewestAnswer]); - - const handlePressEnter = useCallback( - (documentIds: string[]) => { - if (trim(value) === '') return; - const id = uuid(); - if (done) { - setValue(''); - addNewestQuestion({ - content: value, - doc_ids: documentIds, - id, - role: MessageType.User, - }); - handleSendMessage({ - content: value.trim(), - id, - role: MessageType.User, - }); - } - }, - [addNewestQuestion, done, handleSendMessage, setValue, value], - ); - - return { - handlePressEnter, - handleInputChange, - value, - sendLoading: !done, - ref, - loading: false, - derivedMessages, - hasError, - stopOutputMessage, - }; -}; diff --git a/web/src/pages/chat/utils.ts b/web/src/pages/chat/utils.ts deleted file mode 100644 index e3e4f5ff2..000000000 --- a/web/src/pages/chat/utils.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { MessageType } from '@/constants/chat'; -import { IConversation, IReference } from '@/interfaces/database/chat'; -import { isEmpty } from 'lodash'; -import { EmptyConversationId } from './constants'; -import { IMessage } from './interface'; - -export const isConversationIdExist = (conversationId: string) => { - return conversationId !== EmptyConversationId && conversationId !== ''; -}; - -export const getDocumentIdsFromConversionReference = (data: IConversation) => { - const documentIds = data.reference.reduce( - (pre: Array, cur: IReference) => { - cur.doc_aggs - ?.map((x) => x.doc_id) - .forEach((x) => { - if (pre.every((y) => y !== x)) { - pre.push(x); - } - }); - return pre; - }, - [], - ); - return documentIds.join(','); -}; - -export const buildMessageItemReference = ( - conversation: { message: IMessage[]; reference: IReference[] }, - message: IMessage, -) => { - const assistantMessages = conversation.message - ?.filter((x) => x.role === MessageType.Assistant) - .slice(1); - const referenceIndex = assistantMessages.findIndex( - (x) => x.id === message.id, - ); - const reference = !isEmpty(message?.reference) - ? message?.reference - : (conversation?.reference ?? [])[referenceIndex]; - - return reference ?? { doc_aggs: [], chunks: [], total: 0 }; -}; - -const oldReg = /(#{2}\d+\${2})/g; -export const currentReg = /\[ID:(\d+)\]/g; - -// To be compatible with the old index matching mode -export const replaceTextByOldReg = (text: string) => { - return text?.replace(oldReg, (substring: string) => { - return `[ID:${substring.slice(2, -2)}]`; - }); -}; diff --git a/web/src/pages/chunk/parsed-result/add-knowledge/constant.ts b/web/src/pages/chunk/parsed-result/add-knowledge/constant.ts index 71df266c8..fb4eecc3f 100644 --- a/web/src/pages/chunk/parsed-result/add-knowledge/constant.ts +++ b/web/src/pages/chunk/parsed-result/add-knowledge/constant.ts @@ -1,21 +1,4 @@ -import { KnowledgeRouteKey } from '@/constants/knowledge'; - -export const routeMap = { - [KnowledgeRouteKey.Dataset]: 'Dataset', - [KnowledgeRouteKey.Testing]: 'Retrieval testing', - [KnowledgeRouteKey.Configuration]: 'Configuration', -}; - export enum KnowledgeDatasetRouteKey { Chunk = 'chunk', File = 'file', } - -export const datasetRouteMap = { - [KnowledgeDatasetRouteKey.Chunk]: 'Chunk', - [KnowledgeDatasetRouteKey.File]: 'File Upload', -}; - -export * from '@/constants/knowledge'; - -export const TagRenameId = 'tagRename'; diff --git a/web/src/pages/data-flow/constant.tsx b/web/src/pages/data-flow/constant.tsx deleted file mode 100644 index e69de29bb..000000000 diff --git a/web/src/pages/data-flow/form/parser-form/index.tsx b/web/src/pages/data-flow/form/parser-form/index.tsx deleted file mode 100644 index e69de29bb..000000000 diff --git a/web/src/pages/data-flow/form/parser-form/pdf-form-fields.tsx b/web/src/pages/data-flow/form/parser-form/pdf-form-fields.tsx deleted file mode 100644 index e69de29bb..000000000 diff --git a/web/src/pages/data-flow/form/parser-form/ppt-form-fields.tsx b/web/src/pages/data-flow/form/parser-form/ppt-form-fields.tsx deleted file mode 100644 index 59b179498..000000000 --- a/web/src/pages/data-flow/form/parser-form/ppt-form-fields.tsx +++ /dev/null @@ -1,40 +0,0 @@ -import { ParseDocumentType } from '@/components/layout-recognize-form-field'; -import { isEmpty } from 'lodash'; -import { useEffect } from 'react'; -import { useFormContext } from 'react-hook-form'; -import { ParserMethodFormField } from './common-form-fields'; -import { CommonProps } from './interface'; -import { buildFieldNameWithPrefix } from './utils'; - -export function PptFormFields({ prefix }: CommonProps) { - const form = useFormContext(); - - const parseMethodName = buildFieldNameWithPrefix('parse_method', prefix); - - // PPT only supports DeepDOC and TCADPParser - const optionsWithoutLLM = [ - { label: ParseDocumentType.DeepDOC, value: ParseDocumentType.DeepDOC }, - { - label: ParseDocumentType.TCADPParser, - value: ParseDocumentType.TCADPParser, - }, - ]; - - useEffect(() => { - if (isEmpty(form.getValues(parseMethodName))) { - form.setValue(parseMethodName, ParseDocumentType.DeepDOC, { - shouldValidate: true, - shouldDirty: true, - }); - } - }, [form, parseMethodName]); - - return ( - <> - - - ); -} diff --git a/web/src/pages/data-flow/form/parser-form/spreadsheet-form-fields.tsx b/web/src/pages/data-flow/form/parser-form/spreadsheet-form-fields.tsx deleted file mode 100644 index 443ff6e18..000000000 --- a/web/src/pages/data-flow/form/parser-form/spreadsheet-form-fields.tsx +++ /dev/null @@ -1,40 +0,0 @@ -import { ParseDocumentType } from '@/components/layout-recognize-form-field'; -import { isEmpty } from 'lodash'; -import { useEffect } from 'react'; -import { useFormContext } from 'react-hook-form'; -import { ParserMethodFormField } from './common-form-fields'; -import { CommonProps } from './interface'; -import { buildFieldNameWithPrefix } from './utils'; - -export function SpreadsheetFormFields({ prefix }: CommonProps) { - const form = useFormContext(); - - const parseMethodName = buildFieldNameWithPrefix('parse_method', prefix); - - // Spreadsheet only supports DeepDOC and TCADPParser - const optionsWithoutLLM = [ - { label: ParseDocumentType.DeepDOC, value: ParseDocumentType.DeepDOC }, - { - label: ParseDocumentType.TCADPParser, - value: ParseDocumentType.TCADPParser, - }, - ]; - - useEffect(() => { - if (isEmpty(form.getValues(parseMethodName))) { - form.setValue(parseMethodName, ParseDocumentType.DeepDOC, { - shouldValidate: true, - shouldDirty: true, - }); - } - }, [form, parseMethodName]); - - return ( - <> - - - ); -} diff --git a/web/src/pages/data-flow/utils.ts b/web/src/pages/data-flow/utils.ts deleted file mode 100644 index e69de29bb..000000000 diff --git a/web/src/pages/data-flows/index.tsx b/web/src/pages/data-flows/index.tsx deleted file mode 100644 index 13ee9742c..000000000 --- a/web/src/pages/data-flows/index.tsx +++ /dev/null @@ -1,3 +0,0 @@ -export default function DataFlows() { - return
xx
; -} diff --git a/web/src/pages/dataset/dataset-setting/tag-table/rename-dialog/index.tsx b/web/src/pages/dataset/dataset-setting/tag-table/rename-dialog/index.tsx index b95907f92..86b8780e8 100644 --- a/web/src/pages/dataset/dataset-setting/tag-table/rename-dialog/index.tsx +++ b/web/src/pages/dataset/dataset-setting/tag-table/rename-dialog/index.tsx @@ -6,9 +6,9 @@ import { DialogTitle, } from '@/components/ui/dialog'; import { LoadingButton } from '@/components/ui/loading-button'; +import { TagRenameId } from '@/constants/knowledge'; import { useTagIsRenaming } from '@/hooks/knowledge-hooks'; import { IModalProps } from '@/interfaces/common'; -import { TagRenameId } from '@/pages/add-knowledge/constant'; import { useTranslation } from 'react-i18next'; import { RenameForm } from './rename-form'; diff --git a/web/src/pages/dataset/dataset-setting/tag-table/rename-dialog/rename-form.tsx b/web/src/pages/dataset/dataset-setting/tag-table/rename-dialog/rename-form.tsx index 9c8f1cf7e..9ba2407ab 100644 --- a/web/src/pages/dataset/dataset-setting/tag-table/rename-dialog/rename-form.tsx +++ b/web/src/pages/dataset/dataset-setting/tag-table/rename-dialog/rename-form.tsx @@ -13,9 +13,9 @@ import { FormMessage, } from '@/components/ui/form'; import { Input } from '@/components/ui/input'; +import { TagRenameId } from '@/constants/knowledge'; import { useRenameTag } from '@/hooks/knowledge-hooks'; import { IModalProps } from '@/interfaces/common'; -import { TagRenameId } from '@/pages/add-knowledge/constant'; import { useEffect } from 'react'; import { useTranslation } from 'react-i18next'; diff --git a/web/src/pages/dataset/dataset/set-meta-dialog.tsx b/web/src/pages/dataset/dataset/set-meta-dialog.tsx index 8636ddda6..ff5aeabc2 100644 --- a/web/src/pages/dataset/dataset/set-meta-dialog.tsx +++ b/web/src/pages/dataset/dataset/set-meta-dialog.tsx @@ -5,8 +5,8 @@ import { DialogHeader, DialogTitle, } from '@/components/ui/dialog'; +import { TagRenameId } from '@/constants/knowledge'; import { IModalProps } from '@/interfaces/common'; -import { TagRenameId } from '@/pages/add-knowledge/constant'; import { useTranslation } from 'react-i18next'; import { zodResolver } from '@hookform/resolvers/zod'; diff --git a/web/src/pages/file-manager/action-cell/index.tsx b/web/src/pages/file-manager/action-cell/index.tsx deleted file mode 100644 index 7280b5918..000000000 --- a/web/src/pages/file-manager/action-cell/index.tsx +++ /dev/null @@ -1,141 +0,0 @@ -import NewDocumentLink from '@/components/new-document-link'; -import { useTranslate } from '@/hooks/common-hooks'; -import { useDownloadFile } from '@/hooks/file-manager-hooks'; -import { IFile } from '@/interfaces/database/file-manager'; -import { - getExtension, - isSupportedPreviewDocumentType, -} from '@/utils/document-util'; -import { - DownloadOutlined, - EditOutlined, - EyeOutlined, - LinkOutlined, -} from '@ant-design/icons'; -import { Button, Space, Tooltip } from 'antd'; -import { FolderInput, Trash2 } from 'lucide-react'; -import { useHandleDeleteFile } from '../hooks'; - -interface IProps { - record: IFile; - setCurrentRecord: (record: any) => void; - showRenameModal: (record: IFile) => void; - showMoveFileModal: (ids: string[]) => void; - showConnectToKnowledgeModal: (record: IFile) => void; - setSelectedRowKeys(keys: string[]): void; -} - -const ActionCell = ({ - record, - setCurrentRecord, - showRenameModal, - showConnectToKnowledgeModal, - setSelectedRowKeys, - showMoveFileModal, -}: IProps) => { - const documentId = record.id; - const beingUsed = false; - const { t } = useTranslate('fileManager'); - const { handleRemoveFile } = useHandleDeleteFile( - [documentId], - setSelectedRowKeys, - ); - const { downloadFile, loading } = useDownloadFile(); - const extension = getExtension(record.name); - const isKnowledgeBase = record.source_type === 'knowledgebase'; - - const onDownloadDocument = () => { - downloadFile({ - id: documentId, - filename: record.name, - }); - }; - - const setRecord = () => { - setCurrentRecord(record); - }; - - const onShowRenameModal = () => { - setRecord(); - showRenameModal(record); - }; - - const onShowConnectToKnowledgeModal = () => { - showConnectToKnowledgeModal(record); - }; - - const onShowMoveFileModal = () => { - showMoveFileModal([documentId]); - }; - - return ( - - {isKnowledgeBase || ( - - - - )} - - {isKnowledgeBase || ( - - - - )} - {isKnowledgeBase || ( - - - - )} - {isKnowledgeBase || ( - - - - )} - {record.type !== 'folder' && ( - - - - )} - {isSupportedPreviewDocumentType(extension) && ( - - - - - - )} - - ); -}; - -export default ActionCell; diff --git a/web/src/pages/file-manager/connect-to-knowledge-modal/index.tsx b/web/src/pages/file-manager/connect-to-knowledge-modal/index.tsx deleted file mode 100644 index d32df3596..000000000 --- a/web/src/pages/file-manager/connect-to-knowledge-modal/index.tsx +++ /dev/null @@ -1,62 +0,0 @@ -import { useTranslate } from '@/hooks/common-hooks'; -import { useFetchKnowledgeList } from '@/hooks/knowledge-hooks'; -import { IModalProps } from '@/interfaces/common'; -import { filterOptionsByInput } from '@/utils/common-util'; -import { Form, Modal, Select } from 'antd'; -import { useEffect } from 'react'; - -const ConnectToKnowledgeModal = ({ - visible, - hideModal, - onOk, - initialValue, - loading, -}: IModalProps & { initialValue: string[] }) => { - const [form] = Form.useForm(); - const { list } = useFetchKnowledgeList(); - const { t } = useTranslate('fileManager'); - - const options = list?.map((item) => ({ - label: item.name, - value: item.id, - })); - - const handleOk = async () => { - const values = await form.getFieldsValue(); - const knowledgeIds = values.knowledgeIds ?? []; - return onOk?.(knowledgeIds); - }; - - useEffect(() => { - if (visible) { - form.setFieldValue('knowledgeIds', initialValue); - } - }, [visible, initialValue, form]); - - return ( - -
- - } - /> - - {isKnowledgeBase || ( - - - - )} - -
- ); -}; - -export default FileToolbar; diff --git a/web/src/pages/file-manager/folder-create-modal/index.tsx b/web/src/pages/file-manager/folder-create-modal/index.tsx deleted file mode 100644 index d336a01b4..000000000 --- a/web/src/pages/file-manager/folder-create-modal/index.tsx +++ /dev/null @@ -1,53 +0,0 @@ -import { IModalManagerChildrenProps } from '@/components/modal-manager'; -import { useTranslate } from '@/hooks/common-hooks'; -import { Form, Input, Modal } from 'antd'; - -interface IProps extends Omit { - loading: boolean; - onOk: (name: string) => void; -} - -const FolderCreateModal = ({ visible, hideModal, loading, onOk }: IProps) => { - const [form] = Form.useForm(); - const { t } = useTranslate('common'); - - type FieldType = { - name?: string; - }; - - const handleOk = async () => { - const ret = await form.validateFields(); - - return onOk(ret.name); - }; - - return ( - - - - label={t('name')} - name="name" - rules={[{ required: true, message: t('namePlaceholder') }]} - > - - - - - ); -}; - -export default FolderCreateModal; diff --git a/web/src/pages/file-manager/hooks.ts b/web/src/pages/file-manager/hooks.ts deleted file mode 100644 index d1145e572..000000000 --- a/web/src/pages/file-manager/hooks.ts +++ /dev/null @@ -1,294 +0,0 @@ -import { useSetModalState, useShowDeleteConfirm } from '@/hooks/common-hooks'; -import { - useConnectToKnowledge, - useCreateFolder, - useDeleteFile, - useFetchParentFolderList, - useMoveFile, - useRenameFile, - useUploadFile, -} from '@/hooks/file-manager-hooks'; -import { IFile } from '@/interfaces/database/file-manager'; -import { TableRowSelection } from 'antd/es/table/interface'; -import { UploadFile } from 'antd/lib'; -import { useCallback, useMemo, useState } from 'react'; -import { useNavigate, useSearchParams } from 'umi'; - -export const useGetFolderId = () => { - const [searchParams] = useSearchParams(); - const id = searchParams.get('folderId') as string; - - return id ?? ''; -}; - -export const useGetRowSelection = () => { - const [selectedRowKeys, setSelectedRowKeys] = useState([]); - - const rowSelection: TableRowSelection = { - selectedRowKeys, - getCheckboxProps: (record) => { - return { disabled: record.source_type === 'knowledgebase' }; - }, - onChange: (newSelectedRowKeys: React.Key[]) => { - setSelectedRowKeys(newSelectedRowKeys); - }, - }; - - return { rowSelection, setSelectedRowKeys }; -}; - -export const useNavigateToOtherFolder = () => { - const navigate = useNavigate(); - const navigateToOtherFolder = useCallback( - (folderId: string) => { - navigate(`/file?folderId=${folderId}`); - }, - [navigate], - ); - - return navigateToOtherFolder; -}; - -export const useRenameCurrentFile = () => { - const [file, setFile] = useState({} as IFile); - const { - visible: fileRenameVisible, - hideModal: hideFileRenameModal, - showModal: showFileRenameModal, - } = useSetModalState(); - const { renameFile, loading } = useRenameFile(); - - const onFileRenameOk = useCallback( - async (name: string) => { - const ret = await renameFile({ - fileId: file.id, - name, - }); - - if (ret === 0) { - hideFileRenameModal(); - } - }, - [renameFile, file, hideFileRenameModal], - ); - - const handleShowFileRenameModal = useCallback( - async (record: IFile) => { - setFile(record); - showFileRenameModal(); - }, - [showFileRenameModal], - ); - - return { - fileRenameLoading: loading, - initialFileName: file.name, - onFileRenameOk, - fileRenameVisible, - hideFileRenameModal, - showFileRenameModal: handleShowFileRenameModal, - }; -}; - -export const useSelectBreadcrumbItems = () => { - const parentFolderList = useFetchParentFolderList(); - - return parentFolderList.length === 1 - ? [] - : parentFolderList.map((x) => ({ - title: x.name === '/' ? 'root' : x.name, - path: `/file?folderId=${x.id}`, - })); -}; - -export const useHandleCreateFolder = () => { - const { - visible: folderCreateModalVisible, - hideModal: hideFolderCreateModal, - showModal: showFolderCreateModal, - } = useSetModalState(); - const { createFolder, loading } = useCreateFolder(); - const id = useGetFolderId(); - - const onFolderCreateOk = useCallback( - async (name: string) => { - const ret = await createFolder({ parentId: id, name }); - - if (ret === 0) { - hideFolderCreateModal(); - } - }, - [createFolder, hideFolderCreateModal, id], - ); - - return { - folderCreateLoading: loading, - onFolderCreateOk, - folderCreateModalVisible, - hideFolderCreateModal, - showFolderCreateModal, - }; -}; - -export const useHandleDeleteFile = ( - fileIds: string[], - setSelectedRowKeys: (keys: string[]) => void, -) => { - const { deleteFile: removeDocument } = useDeleteFile(); - const showDeleteConfirm = useShowDeleteConfirm(); - const parentId = useGetFolderId(); - - const handleRemoveFile = () => { - showDeleteConfirm({ - onOk: async () => { - const code = await removeDocument({ fileIds, parentId }); - if (code === 0) { - setSelectedRowKeys([]); - } - return; - }, - }); - }; - - return { handleRemoveFile }; -}; - -export const useHandleUploadFile = () => { - const { - visible: fileUploadVisible, - hideModal: hideFileUploadModal, - showModal: showFileUploadModal, - } = useSetModalState(); - const { uploadFile, loading } = useUploadFile(); - const id = useGetFolderId(); - - const onFileUploadOk = useCallback( - async (fileList: UploadFile[]): Promise => { - if (fileList.length > 0) { - const ret: number = await uploadFile({ fileList, parentId: id }); - if (ret === 0) { - hideFileUploadModal(); - } - return ret; - } - }, - [uploadFile, hideFileUploadModal, id], - ); - - return { - fileUploadLoading: loading, - onFileUploadOk, - fileUploadVisible, - hideFileUploadModal, - showFileUploadModal, - }; -}; - -export const useHandleConnectToKnowledge = () => { - const { - visible: connectToKnowledgeVisible, - hideModal: hideConnectToKnowledgeModal, - showModal: showConnectToKnowledgeModal, - } = useSetModalState(); - const { connectFileToKnowledge: connectToKnowledge, loading } = - useConnectToKnowledge(); - const [record, setRecord] = useState({} as IFile); - - const initialValue = useMemo(() => { - return Array.isArray(record?.kbs_info) - ? record?.kbs_info?.map((x) => x.kb_id) - : []; - }, [record?.kbs_info]); - - const onConnectToKnowledgeOk = useCallback( - async (knowledgeIds: string[]) => { - const ret = await connectToKnowledge({ - fileIds: [record.id], - kbIds: knowledgeIds, - }); - - if (ret === 0) { - hideConnectToKnowledgeModal(); - } - return ret; - }, - [connectToKnowledge, hideConnectToKnowledgeModal, record.id], - ); - - const handleShowConnectToKnowledgeModal = useCallback( - (record: IFile) => { - setRecord(record); - showConnectToKnowledgeModal(); - }, - [showConnectToKnowledgeModal], - ); - - return { - initialValue, - connectToKnowledgeLoading: loading, - onConnectToKnowledgeOk, - connectToKnowledgeVisible, - hideConnectToKnowledgeModal, - showConnectToKnowledgeModal: handleShowConnectToKnowledgeModal, - }; -}; - -export const useHandleBreadcrumbClick = () => { - const navigate = useNavigate(); - - const handleBreadcrumbClick = useCallback( - (path?: string) => { - if (path) { - navigate(path); - } - }, - [navigate], - ); - - return { handleBreadcrumbClick }; -}; - -export const useHandleMoveFile = ( - setSelectedRowKeys: (keys: string[]) => void, -) => { - const { - visible: moveFileVisible, - hideModal: hideMoveFileModal, - showModal: showMoveFileModal, - } = useSetModalState(); - const { moveFile, loading } = useMoveFile(); - const [sourceFileIds, setSourceFileIds] = useState([]); - - const onMoveFileOk = useCallback( - async (targetFolderId: string) => { - const ret = await moveFile({ - src_file_ids: sourceFileIds, - dest_file_id: targetFolderId, - }); - - if (ret === 0) { - setSelectedRowKeys([]); - hideMoveFileModal(); - } - return ret; - }, - [moveFile, hideMoveFileModal, sourceFileIds, setSelectedRowKeys], - ); - - const handleShowMoveFileModal = useCallback( - (ids: string[]) => { - setSourceFileIds(ids); - showMoveFileModal(); - }, - [showMoveFileModal], - ); - - return { - initialValue: '', - moveFileLoading: loading, - onMoveFileOk, - moveFileVisible, - hideMoveFileModal, - showMoveFileModal: handleShowMoveFileModal, - }; -}; diff --git a/web/src/pages/file-manager/index.less b/web/src/pages/file-manager/index.less deleted file mode 100644 index 8f3d2f34d..000000000 --- a/web/src/pages/file-manager/index.less +++ /dev/null @@ -1,29 +0,0 @@ -.fileManagerWrapper { - width: 100%; - padding: 32px; -} - -.filter { - height: 32px; - display: flex; - margin: 10px 0; - justify-content: space-between; - padding: 24px 0; - align-items: center; -} - -.deleteIconWrapper { - width: 22px; - text-align: center; -} - -.linkButton { - padding: 0; -} - -.breadcrumbItemButton { - cursor: pointer; - color: #1677ff; - padding: 0; - height: auto; -} diff --git a/web/src/pages/file-manager/index.tsx b/web/src/pages/file-manager/index.tsx deleted file mode 100644 index 4683b9538..000000000 --- a/web/src/pages/file-manager/index.tsx +++ /dev/null @@ -1,216 +0,0 @@ -import { useFetchFileList } from '@/hooks/file-manager-hooks'; -import { IFile } from '@/interfaces/database/file-manager'; -import { formatDate } from '@/utils/date'; -import { Button, Flex, Space, Table, Tag, Typography } from 'antd'; -import { ColumnsType } from 'antd/es/table'; -import ActionCell from './action-cell'; -import FileToolbar from './file-toolbar'; -import { - useGetRowSelection, - useHandleConnectToKnowledge, - useHandleCreateFolder, - useHandleMoveFile, - useHandleUploadFile, - useNavigateToOtherFolder, - useRenameCurrentFile, -} from './hooks'; - -import FileUploadModal from '@/components/file-upload-modal'; -import RenameModal from '@/components/rename-modal'; -import SvgIcon from '@/components/svg-icon'; -import { useTranslate } from '@/hooks/common-hooks'; -import { formatNumberWithThousandsSeparator } from '@/utils/common-util'; -import { getExtension } from '@/utils/document-util'; -import ConnectToKnowledgeModal from './connect-to-knowledge-modal'; -import FolderCreateModal from './folder-create-modal'; -import styles from './index.less'; -import FileMovingModal from './move-file-modal'; - -const { Text } = Typography; - -const FileManager = () => { - const { t } = useTranslate('fileManager'); - // const fileList = useSelectFileList(); - const { rowSelection, setSelectedRowKeys } = useGetRowSelection(); - const navigateToOtherFolder = useNavigateToOtherFolder(); - const { - fileRenameVisible, - fileRenameLoading, - hideFileRenameModal, - showFileRenameModal, - initialFileName, - onFileRenameOk, - } = useRenameCurrentFile(); - const { - folderCreateModalVisible, - showFolderCreateModal, - hideFolderCreateModal, - folderCreateLoading, - onFolderCreateOk, - } = useHandleCreateFolder(); - const { - fileUploadVisible, - hideFileUploadModal, - showFileUploadModal, - fileUploadLoading, - onFileUploadOk, - } = useHandleUploadFile(); - const { - connectToKnowledgeVisible, - hideConnectToKnowledgeModal, - showConnectToKnowledgeModal, - onConnectToKnowledgeOk, - initialValue, - connectToKnowledgeLoading, - } = useHandleConnectToKnowledge(); - const { - showMoveFileModal, - moveFileVisible, - onMoveFileOk, - hideMoveFileModal, - moveFileLoading, - } = useHandleMoveFile(setSelectedRowKeys); - const { pagination, data, searchString, handleInputChange, loading } = - useFetchFileList(); - const columns: ColumnsType = [ - { - title: t('name'), - dataIndex: 'name', - key: 'name', - fixed: 'left', - render(value, record) { - return ( - - - {record.type === 'folder' ? ( - - ) : ( - {value} - )} - - ); - }, - }, - { - title: t('uploadDate'), - dataIndex: 'create_time', - key: 'create_time', - render(text) { - return formatDate(text); - }, - }, - { - title: t('size'), - dataIndex: 'size', - key: 'size', - render(value) { - return ( - formatNumberWithThousandsSeparator((value / 1024).toFixed(2)) + ' KB' - ); - }, - }, - { - title: t('knowledgeBase'), - dataIndex: 'kbs_info', - key: 'kbs_info', - render(value) { - return Array.isArray(value) ? ( - - {value?.map((x) => ( - - {x.kb_name} - - ))} - - ) : ( - '' - ); - }, - }, - { - title: t('action'), - dataIndex: 'action', - key: 'action', - render: (text, record) => ( - { - console.info(record); - }} - showRenameModal={showFileRenameModal} - showMoveFileModal={showMoveFileModal} - showConnectToKnowledgeModal={showConnectToKnowledgeModal} - setSelectedRowKeys={setSelectedRowKeys} - > - ), - }, - ]; - - return ( -
- -
- - - - - {moveFileVisible && ( - - )} - - ); -}; - -export default FileManager; diff --git a/web/src/pages/file-manager/move-file-modal/async-tree-select.tsx b/web/src/pages/file-manager/move-file-modal/async-tree-select.tsx deleted file mode 100644 index 2ed1c80d6..000000000 --- a/web/src/pages/file-manager/move-file-modal/async-tree-select.tsx +++ /dev/null @@ -1,69 +0,0 @@ -import { useFetchPureFileList } from '@/hooks/file-manager-hooks'; -import { IFile } from '@/interfaces/database/file-manager'; -import type { GetProp, TreeSelectProps } from 'antd'; -import { TreeSelect } from 'antd'; -import { useCallback, useEffect, useState } from 'react'; -import { useTranslation } from 'react-i18next'; - -type DefaultOptionType = GetProp[number]; - -interface IProps { - value?: string; - onChange?: (value: string) => void; -} - -const AsyncTreeSelect = ({ value, onChange }: IProps) => { - const { t } = useTranslation(); - const { fetchList } = useFetchPureFileList(); - const [treeData, setTreeData] = useState[]>( - [], - ); - - const onLoadData: TreeSelectProps['loadData'] = useCallback( - async ({ id }) => { - const ret = await fetchList(id); - if (ret.code === 0) { - setTreeData((tree) => { - return tree.concat( - ret.data.files - .filter((x: IFile) => x.type === 'folder') - .map((x: IFile) => ({ - id: x.id, - pId: x.parent_id, - value: x.id, - title: x.name, - isLeaf: - typeof x.has_child_folder === 'boolean' - ? !x.has_child_folder - : false, - })), - ); - }); - } - }, - [fetchList], - ); - - const handleChange = (newValue: string) => { - onChange?.(newValue); - }; - - useEffect(() => { - onLoadData?.({ id: '', props: '' }); - }, [onLoadData]); - - return ( - - ); -}; - -export default AsyncTreeSelect; diff --git a/web/src/pages/file-manager/move-file-modal/index.tsx b/web/src/pages/file-manager/move-file-modal/index.tsx deleted file mode 100644 index c7b13c48b..000000000 --- a/web/src/pages/file-manager/move-file-modal/index.tsx +++ /dev/null @@ -1,54 +0,0 @@ -import { IModalManagerChildrenProps } from '@/components/modal-manager'; -import { useTranslate } from '@/hooks/common-hooks'; -import { Form, Modal } from 'antd'; -import AsyncTreeSelect from './async-tree-select'; - -interface IProps extends Omit { - loading: boolean; - onOk: (id: string) => void; -} - -const FileMovingModal = ({ visible, hideModal, loading, onOk }: IProps) => { - const [form] = Form.useForm(); - const { t } = useTranslate('fileManager'); - - type FieldType = { - name?: string; - }; - - const handleOk = async () => { - const ret = await form.validateFields(); - - return onOk(ret.name); - }; - - return ( - -
- - label={t('destinationFolder')} - name="name" - rules={[{ required: true, message: t('pleaseSelect') }]} - > - - - -
- ); -}; - -export default FileMovingModal; diff --git a/web/src/pages/files/create-folder-dialog/create-folder-form.tsx b/web/src/pages/files/create-folder-dialog/create-folder-form.tsx index 15ab47643..a575d42c5 100644 --- a/web/src/pages/files/create-folder-dialog/create-folder-form.tsx +++ b/web/src/pages/files/create-folder-dialog/create-folder-form.tsx @@ -13,8 +13,8 @@ import { FormMessage, } from '@/components/ui/form'; import { Input } from '@/components/ui/input'; +import { TagRenameId } from '@/constants/knowledge'; import { IModalProps } from '@/interfaces/common'; -import { TagRenameId } from '@/pages/add-knowledge/constant'; import { useTranslation } from 'react-i18next'; export function CreateFolderForm({ hideModal, onOk }: IModalProps) { diff --git a/web/src/pages/files/create-folder-dialog/index.tsx b/web/src/pages/files/create-folder-dialog/index.tsx index 3ac2dc1ee..1fb98dbc2 100644 --- a/web/src/pages/files/create-folder-dialog/index.tsx +++ b/web/src/pages/files/create-folder-dialog/index.tsx @@ -6,8 +6,8 @@ import { DialogTitle, } from '@/components/ui/dialog'; import { LoadingButton } from '@/components/ui/loading-button'; +import { TagRenameId } from '@/constants/knowledge'; import { IModalProps } from '@/interfaces/common'; -import { TagRenameId } from '@/pages/add-knowledge/constant'; import { useTranslation } from 'react-i18next'; import { CreateFolderForm } from './create-folder-form'; diff --git a/web/src/pages/knowledge/hooks.ts b/web/src/pages/knowledge/hooks.ts deleted file mode 100644 index e978a6243..000000000 --- a/web/src/pages/knowledge/hooks.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { KnowledgeRouteKey } from '@/constants/knowledge'; -import { useSetModalState } from '@/hooks/common-hooks'; -import { useCreateKnowledge } from '@/hooks/knowledge-hooks'; -import { useCallback, useState } from 'react'; -import { useNavigate } from 'umi'; - -export const useSearchKnowledge = () => { - const [searchString, setSearchString] = useState(''); - - const handleInputChange = (e: React.ChangeEvent) => { - setSearchString(e.target.value); - }; - return { - searchString, - handleInputChange, - }; -}; - -export const useSaveKnowledge = () => { - const { visible: visible, hideModal, showModal } = useSetModalState(); - const { loading, createKnowledge } = useCreateKnowledge(); - const navigate = useNavigate(); - - const onCreateOk = useCallback( - async (name: string) => { - const ret = await createKnowledge({ - name, - }); - - if (ret?.code === 0) { - hideModal(); - navigate( - `/knowledge/${KnowledgeRouteKey.Configuration}?id=${ret.data.kb_id}`, - ); - } - }, - [createKnowledge, hideModal, navigate], - ); - - return { - loading, - onCreateOk, - visible, - hideModal, - showModal, - }; -}; diff --git a/web/src/pages/knowledge/index.less b/web/src/pages/knowledge/index.less deleted file mode 100644 index e40efb0f6..000000000 --- a/web/src/pages/knowledge/index.less +++ /dev/null @@ -1,50 +0,0 @@ -// @import '~@/less/variable.less'; - -.knowledge { - padding: 48px 0; - overflow: auto; -} - -.topWrapper { - display: flex; - justify-content: space-between; - align-items: flex-start; - padding: 0 60px 72px; - - .title { - font-family: Inter; - font-size: 30px; - font-style: normal; - font-weight: @fontWeight600; - line-height: 38px; - color: var(--ant-color-info); - } - .description { - font-family: Inter; - font-size: 16px; - font-style: normal; - font-weight: 400; - line-height: 24px; - } - - .topButton { - font-family: Inter; - font-size: 14px; - font-style: normal; - font-weight: @fontWeight600; - line-height: 20px; - } - - .filterButton { - display: flex; - align-items: center; - .topButton(); - } -} -.knowledgeCardContainer { - padding: 0 60px; - overflow: auto; - .knowledgeEmpty { - width: 100%; - } -} diff --git a/web/src/pages/knowledge/index.tsx b/web/src/pages/knowledge/index.tsx deleted file mode 100644 index df9ddb23d..000000000 --- a/web/src/pages/knowledge/index.tsx +++ /dev/null @@ -1,132 +0,0 @@ -import { useInfiniteFetchKnowledgeList } from '@/hooks/knowledge-hooks'; -import { useFetchUserInfo } from '@/hooks/user-setting-hooks'; -import { PlusOutlined, SearchOutlined } from '@ant-design/icons'; -import { - Button, - Divider, - Empty, - Flex, - Input, - Skeleton, - Space, - Spin, -} from 'antd'; -import { useTranslation } from 'react-i18next'; -import InfiniteScroll from 'react-infinite-scroll-component'; -import { useSaveKnowledge } from './hooks'; -import KnowledgeCard from './knowledge-card'; -import KnowledgeCreatingModal from './knowledge-creating-modal'; - -import { useMemo } from 'react'; -import styles from './index.less'; - -const KnowledgeList = () => { - const { data: userInfo } = useFetchUserInfo(); - const { t } = useTranslation('translation', { keyPrefix: 'knowledgeList' }); - const { - visible, - hideModal, - showModal, - onCreateOk, - loading: creatingLoading, - } = useSaveKnowledge(); - const { - fetchNextPage, - data, - hasNextPage, - searchString, - handleInputChange, - loading, - } = useInfiniteFetchKnowledgeList(); - - const nextList = useMemo(() => { - const list = - data?.pages?.flatMap((x) => (Array.isArray(x.kbs) ? x.kbs : [])) ?? []; - return list; - }, [data?.pages]); - - const total = useMemo(() => { - return data?.pages.at(-1).total ?? 0; - }, [data?.pages]); - - return ( - -
-
- - {t('welcome')}, {userInfo.nickname} - -

{t('description')}

-
- - } - /> - - - -
- -
- } - endMessage={ - !!total && {t('noMoreData')} 🤐 - } - scrollableTarget="scrollableDiv" - scrollThreshold="200px" - > - - {nextList?.length > 0 ? ( - nextList.map((item: any, index: number) => { - return ( - - ); - }) - ) : ( - - )} - - -
-
- -
- ); -}; - -export default KnowledgeList; diff --git a/web/src/pages/knowledge/knowledge-card/index.less b/web/src/pages/knowledge/knowledge-card/index.less deleted file mode 100644 index 6791a5d38..000000000 --- a/web/src/pages/knowledge/knowledge-card/index.less +++ /dev/null @@ -1,133 +0,0 @@ -.container { - height: 251px; - display: flex; - flex-direction: column; - justify-content: space-between; - - .delete { - height: 24px; - } - - .content { - display: flex; - justify-content: space-between; - - .context { - flex: 1; - } - } - - .footer { - // text-align: left; - } - .footerTop { - padding-bottom: 2px; - } - - .titleWrapper { - margin: 16px 0; - overflow: hidden; - - .title { - display: -webkit-box; - -webkit-line-clamp: 2; - -webkit-box-orient: vertical; - overflow: hidden; - font-size: 24px; - line-height: 32px; - font-weight: 600; - color: rgba(0, 0, 0, 0.88); - word-break: break-all; - } - - .description { - margin-top: 4px; - display: -webkit-box; - -webkit-line-clamp: 3; - -webkit-box-orient: vertical; - overflow: hidden; - font-size: 12px; - font-weight: 600; - line-height: 20px; - color: rgba(0, 0, 0, 0.45); - } - .titledark { - display: -webkit-box; - -webkit-line-clamp: 2; - -webkit-box-orient: vertical; - overflow: hidden; - font-size: 24px; - line-height: 32px; - font-weight: 600; - word-break: break-all; - } - - .descriptiondark { - margin-top: 4px; - display: -webkit-box; - -webkit-line-clamp: 3; - -webkit-box-orient: vertical; - overflow: hidden; - font-size: 12px; - font-weight: 600; - line-height: 20px; - } - } -} - -.card { - border-radius: 12px; - border: 1px solid rgba(0, 0, 0, 0.3); - background-color: rgba(255, 255, 255, 0.1); - box-shadow: 0px 1px 2px 0px rgba(16, 24, 40, 0.05); - padding: 24px; - width: 300px; - cursor: pointer; - - .titleWrapper { - .title { - font-size: 24px; - line-height: 32px; - font-weight: 600; - word-break: break-all; - } - .description { - font-size: 12px; - font-weight: 600; - line-height: 20px; - } - } - - :global { - .ant-card-body { - padding: 0; - margin: 0; - } - } - .bottom { - display: flex; - align-items: center; - justify-content: space-between; - } - .bottomLeft { - vertical-align: middle; - } - .leftIcon { - margin-right: 10px; - font-size: 18px; - vertical-align: middle; - } - .rightText { - font-size: 12px; - font-weight: 600; - vertical-align: middle; - } -} - -.hideRibbon { - display: none !important; -} - -.ribbon { - top: 4px; -} diff --git a/web/src/pages/knowledge/knowledge-card/index.tsx b/web/src/pages/knowledge/knowledge-card/index.tsx deleted file mode 100644 index 2265b19da..000000000 --- a/web/src/pages/knowledge/knowledge-card/index.tsx +++ /dev/null @@ -1,112 +0,0 @@ -import { KnowledgeRouteKey } from '@/constants/knowledge'; -import { IKnowledge } from '@/interfaces/database/knowledge'; -import { formatDate } from '@/utils/date'; -import { - CalendarOutlined, - FileTextOutlined, - UserOutlined, -} from '@ant-design/icons'; -import { Avatar, Badge, Card, Space } from 'antd'; -import classNames from 'classnames'; -import { useTranslation } from 'react-i18next'; -import { useNavigate } from 'umi'; - -import OperateDropdown from '@/components/operate-dropdown'; -import { useTheme } from '@/components/theme-provider'; -import { useDeleteKnowledge } from '@/hooks/knowledge-hooks'; -import { useFetchUserInfo } from '@/hooks/user-setting-hooks'; -import styles from './index.less'; - -interface IProps { - item: IKnowledge; -} - -const KnowledgeCard = ({ item }: IProps) => { - const navigate = useNavigate(); - const { t } = useTranslation(); - const { data: userInfo } = useFetchUserInfo(); - const { theme } = useTheme(); - const { deleteKnowledge } = useDeleteKnowledge(); - - const removeKnowledge = async () => { - return deleteKnowledge(item.id); - }; - - const handleCardClick = () => { - navigate(`/knowledge/${KnowledgeRouteKey.Dataset}?id=${item.id}`, { - state: { from: 'list' }, - }); - }; - - return ( - - -
-
- } src={item.avatar} /> - -
-
- - {item.name} - -

- {item.description} -

-
-
-
-
- - - - {item.doc_num} - {t('knowledgeList.doc')} - - -
-
-
-
- - - {formatDate(item.update_time)} - -
- {/* - - - K - - - } - /> - - } - /> - */} -
-
-
-
-
- ); -}; - -export default KnowledgeCard; diff --git a/web/src/pages/knowledge/knowledge-creating-modal/index.tsx b/web/src/pages/knowledge/knowledge-creating-modal/index.tsx deleted file mode 100644 index 1025cd21c..000000000 --- a/web/src/pages/knowledge/knowledge-creating-modal/index.tsx +++ /dev/null @@ -1,63 +0,0 @@ -import { IModalManagerChildrenProps } from '@/components/modal-manager'; -import { Form, Input, Modal } from 'antd'; -import { useTranslation } from 'react-i18next'; - -type FieldType = { - name?: string; -}; - -interface IProps extends Omit { - loading: boolean; - onOk: (name: string) => void; -} - -const KnowledgeCreatingModal = ({ - visible, - hideModal, - loading, - onOk, -}: IProps) => { - const [form] = Form.useForm(); - - const { t } = useTranslation('translation', { keyPrefix: 'knowledgeList' }); - - const handleOk = async () => { - const ret = await form.validateFields(); - onOk(ret.name); - }; - - const handleKeyDown = async (e) => { - if (e.key === 'Enter') { - await handleOk(); - } - }; - - return ( - -
- - label={t('name')} - name="name" - rules={[{ required: true, message: t('namePlaceholder') }]} - > - - - -
- ); -}; - -export default KnowledgeCreatingModal; diff --git a/web/src/pages/next-chats/chat/interface.ts b/web/src/pages/next-chats/chat/interface.ts index 570c6da21..cf5c25814 100644 --- a/web/src/pages/next-chats/chat/interface.ts +++ b/web/src/pages/next-chats/chat/interface.ts @@ -1,4 +1,3 @@ -import { IConversation, IReference, Message } from '@/interfaces/database/chat'; import { FormInstance } from 'antd'; export interface ISegmentedContentProps { @@ -22,12 +21,3 @@ export interface VariableTableDataType { } export type IPromptConfigParameters = Omit; - -export interface IMessage extends Message { - id: string; - reference?: IReference; // the latest news has reference -} - -export interface IClientConversation extends IConversation { - message: IMessage[]; -} diff --git a/web/src/pages/next-chats/hooks/use-send-chat-message.ts b/web/src/pages/next-chats/hooks/use-send-chat-message.ts index ad589a041..6263f6c23 100644 --- a/web/src/pages/next-chats/hooks/use-send-chat-message.ts +++ b/web/src/pages/next-chats/hooks/use-send-chat-message.ts @@ -10,13 +10,12 @@ import { useFetchConversation, useGetChatSearchParams, } from '@/hooks/use-chat-request'; -import { Message } from '@/interfaces/database/chat'; +import { IMessage, Message } from '@/interfaces/database/chat'; import api from '@/utils/api'; import { trim } from 'lodash'; import { useCallback, useEffect } from 'react'; import { useParams } from 'umi'; import { v4 as uuid } from 'uuid'; -import { IMessage } from '../chat/interface'; import { useFindPrologueFromDialogList } from './use-select-conversation-list'; import { useSetChatRouteParams } from './use-set-chat-route'; import { useSetConversation } from './use-set-conversation'; diff --git a/web/src/pages/next-chats/hooks/use-send-multiple-message.ts b/web/src/pages/next-chats/hooks/use-send-multiple-message.ts index bd0bc8c38..34a2c099d 100644 --- a/web/src/pages/next-chats/hooks/use-send-multiple-message.ts +++ b/web/src/pages/next-chats/hooks/use-send-multiple-message.ts @@ -5,13 +5,12 @@ import { useSendMessageWithSse, } from '@/hooks/logic-hooks'; import { useGetChatSearchParams } from '@/hooks/use-chat-request'; -import { IAnswer, Message } from '@/interfaces/database/chat'; +import { IAnswer, IMessage, Message } from '@/interfaces/database/chat'; import api from '@/utils/api'; import { buildMessageUuid } from '@/utils/chat'; import { trim } from 'lodash'; import { useCallback, useEffect, useState } from 'react'; import { v4 as uuid } from 'uuid'; -import { IMessage } from '../chat/interface'; import { useBuildFormRefs } from './use-build-form-refs'; import { useUploadFile } from './use-upload-file'; diff --git a/web/src/pages/next-chats/share/index.tsx b/web/src/pages/next-chats/share/index.tsx index 1b7e53dca..648b22f72 100644 --- a/web/src/pages/next-chats/share/index.tsx +++ b/web/src/pages/next-chats/share/index.tsx @@ -8,9 +8,9 @@ import { useFetchNextConversationSSE } from '@/hooks/chat-hooks'; import { useFetchFlowSSE } from '@/hooks/flow-hooks'; import { useFetchExternalChatInfo } from '@/hooks/use-chat-request'; import i18n from '@/locales/config'; -import { useSendButtonDisabled } from '@/pages/chat/hooks'; import { buildMessageUuidWithRole } from '@/utils/chat'; import React, { forwardRef, useMemo } from 'react'; +import { useSendButtonDisabled } from '../hooks/use-button-disabled'; import { useGetSharedChatSearchParams, useSendSharedMessage, diff --git a/web/src/pages/next-chats/utils.ts b/web/src/pages/next-chats/utils.ts index a31f40097..ab640b7ac 100644 --- a/web/src/pages/next-chats/utils.ts +++ b/web/src/pages/next-chats/utils.ts @@ -1,7 +1,10 @@ import { EmptyConversationId, MessageType } from '@/constants/chat'; -import { IConversation, IReference } from '@/interfaces/database/chat'; +import { + IConversation, + IMessage, + IReference, +} from '@/interfaces/database/chat'; import { isEmpty } from 'lodash'; -import { IMessage } from '../chat/interface'; export const isConversationIdExist = (conversationId: string) => { return conversationId !== EmptyConversationId && conversationId !== ''; @@ -40,13 +43,3 @@ export const buildMessageItemReference = ( return reference ?? { doc_aggs: [], chunks: [], total: 0 }; }; - -const oldReg = /(#{2}\d+\${2})/g; -export const currentReg = /\[ID:(\d+)\]/g; - -// To be compatible with the old index matching mode -export const replaceTextByOldReg = (text: string) => { - return text?.replace(oldReg, (substring: string) => { - return `[ID:${substring.slice(2, -2)}]`; - }); -}; diff --git a/web/src/pages/next-search/hooks.ts b/web/src/pages/next-search/hooks.ts index 568705582..34a810ad1 100644 --- a/web/src/pages/next-search/hooks.ts +++ b/web/src/pages/next-search/hooks.ts @@ -1,5 +1,6 @@ import message from '@/components/ui/message'; import { SharedFrom } from '@/constants/chat'; +import { useSetModalState } from '@/hooks/common-hooks'; import { useSelectTestingResult } from '@/hooks/knowledge-hooks'; import { useGetPaginationWithRouter, @@ -16,18 +17,18 @@ import kbService from '@/services/knowledge-service'; import searchService from '@/services/search-service'; import api from '@/utils/api'; import { useMutation } from '@tanstack/react-query'; -import { has, isEmpty, trim } from 'lodash'; +import { has, isEmpty, isEqual, trim } from 'lodash'; import { ChangeEventHandler, Dispatch, SetStateAction, useCallback, useEffect, + useRef, useState, } from 'react'; import { useSearchParams } from 'umi'; import { ISearchAppDetailProps } from '../next-searches/hooks'; -import { useShowMindMapDrawer } from '../search/hooks'; import { useClickDrawer } from './document-preview-modal/hooks'; export interface ISearchingProps { @@ -90,6 +91,41 @@ export const useSearchFetchMindMap = () => { return { data, loading, fetchMindMap: mutateAsync }; }; +export const useShowMindMapDrawer = ( + kbIds: string[], + question: string, + searchId = '', +) => { + const { visible, showModal, hideModal } = useSetModalState(); + const ref = useRef(); + + const { + fetchMindMap, + data: mindMap, + loading: mindMapLoading, + } = useSearchFetchMindMap(); + + const handleShowModal = useCallback(() => { + const searchParams = { question: trim(question), kb_ids: kbIds, searchId }; + if ( + !isEmpty(searchParams.question) && + !isEqual(searchParams, ref.current) + ) { + ref.current = searchParams; + fetchMindMap(searchParams); + } + showModal(); + }, [fetchMindMap, showModal, question, kbIds, searchId]); + + return { + mindMap, + mindMapVisible: visible, + mindMapLoading, + showMindMapModal: handleShowModal, + hideMindMapModal: hideModal, + }; +}; + export const useTestChunkRetrieval = ( tenantId?: string, ): ResponsePostType & { @@ -539,3 +575,28 @@ export const useCheckSettings = (data: ISearchAppDetailProps) => { openSetting: kb_ids && kb_ids.length > 0 && name ? false : true, }; }; + +export const usePendingMindMap = () => { + const [count, setCount] = useState(0); + const ref = useRef(); + + const setCountInterval = useCallback(() => { + ref.current = setInterval(() => { + setCount((pre) => { + if (pre > 40) { + clearInterval(ref?.current); + } + return pre + 1; + }); + }, 1000); + }, []); + + useEffect(() => { + setCountInterval(); + return () => { + clearInterval(ref?.current); + }; + }, [setCountInterval]); + + return Number(((count / 43) * 100).toFixed(0)); +}; diff --git a/web/src/pages/next-search/markdown-content/index.tsx b/web/src/pages/next-search/markdown-content/index.tsx index fe23900b6..88107536c 100644 --- a/web/src/pages/next-search/markdown-content/index.tsx +++ b/web/src/pages/next-search/markdown-content/index.tsx @@ -20,7 +20,9 @@ import { useTranslation } from 'react-i18next'; import 'katex/dist/katex.min.css'; // `rehype-katex` does not import the CSS for you import { + currentReg, preprocessLaTeX, + replaceTextByOldReg, replaceThinkToSection, showImage, } from '@/utils/chat'; @@ -31,7 +33,6 @@ import { PopoverContent, PopoverTrigger, } from '@/components/ui/popover'; -import { currentReg, replaceTextByOldReg } from '@/pages/next-chats/utils'; import classNames from 'classnames'; import { omit } from 'lodash'; import { pipe } from 'lodash/fp'; diff --git a/web/src/pages/next-search/mindmap-drawer.tsx b/web/src/pages/next-search/mindmap-drawer.tsx index 1d3084de5..cf5853d5e 100644 --- a/web/src/pages/next-search/mindmap-drawer.tsx +++ b/web/src/pages/next-search/mindmap-drawer.tsx @@ -3,7 +3,7 @@ import { Progress } from '@/components/ui/progress'; import { IModalProps } from '@/interfaces/common'; import { X } from 'lucide-react'; import { useTranslation } from 'react-i18next'; -import { usePendingMindMap } from '../search/hooks'; +import { usePendingMindMap } from './hooks'; interface IProps extends IModalProps { data: any; diff --git a/web/src/pages/profile-setting/mcp/import-mcp-dialog/import-mcp-form.tsx b/web/src/pages/profile-setting/mcp/import-mcp-dialog/import-mcp-form.tsx index d34507308..6408b9e18 100644 --- a/web/src/pages/profile-setting/mcp/import-mcp-dialog/import-mcp-form.tsx +++ b/web/src/pages/profile-setting/mcp/import-mcp-dialog/import-mcp-form.tsx @@ -14,8 +14,8 @@ import { FormMessage, } from '@/components/ui/form'; import { FileMimeType, Platform } from '@/constants/common'; +import { TagRenameId } from '@/constants/knowledge'; import { IModalProps } from '@/interfaces/common'; -import { TagRenameId } from '@/pages/add-knowledge/constant'; import { useTranslation } from 'react-i18next'; export function ImportMcpForm({ hideModal, onOk }: IModalProps) { diff --git a/web/src/pages/profile-setting/mcp/import-mcp-dialog/index.tsx b/web/src/pages/profile-setting/mcp/import-mcp-dialog/index.tsx index 76b35387b..1946523eb 100644 --- a/web/src/pages/profile-setting/mcp/import-mcp-dialog/index.tsx +++ b/web/src/pages/profile-setting/mcp/import-mcp-dialog/index.tsx @@ -6,8 +6,8 @@ import { DialogTitle, } from '@/components/ui/dialog'; import { LoadingButton } from '@/components/ui/loading-button'; +import { TagRenameId } from '@/constants/knowledge'; import { IModalProps } from '@/interfaces/common'; -import { TagRenameId } from '@/pages/add-knowledge/constant'; import { useTranslation } from 'react-i18next'; import { ImportMcpForm } from './import-mcp-form'; diff --git a/web/src/pages/search/hooks.ts b/web/src/pages/search/hooks.ts deleted file mode 100644 index abfecd698..000000000 --- a/web/src/pages/search/hooks.ts +++ /dev/null @@ -1,278 +0,0 @@ -import { useFetchRelatedQuestions } from '@/hooks/chat-hooks'; -import { useSetModalState } from '@/hooks/common-hooks'; -import { - useTestChunkAllRetrieval, - useTestChunkRetrieval, -} from '@/hooks/knowledge-hooks'; -import { - useGetPaginationWithRouter, - useSendMessageWithSse, -} from '@/hooks/logic-hooks'; -import { IAnswer } from '@/interfaces/database/chat'; -import api from '@/utils/api'; -import { get, isEmpty, isEqual, trim } from 'lodash'; -import { - ChangeEventHandler, - useCallback, - useEffect, - useRef, - useState, -} from 'react'; -import { - useGetSharedSearchParams, - useSearchFetchMindMap, -} from '../next-search/hooks'; - -export const useSendQuestion = (kbIds: string[], tenantId?: string) => { - const { sharedId } = useGetSharedSearchParams(); - const { send, answer, done, stopOutputMessage } = useSendMessageWithSse( - sharedId ? api.askShare : api.ask, - ); - - const { testChunk, loading } = useTestChunkRetrieval(tenantId); - const { testChunkAll } = useTestChunkAllRetrieval(tenantId); - const [sendingLoading, setSendingLoading] = useState(false); - const [currentAnswer, setCurrentAnswer] = useState({} as IAnswer); - const { fetchRelatedQuestions, data: relatedQuestions } = - useFetchRelatedQuestions(tenantId); - const [searchStr, setSearchStr] = useState(''); - const [isFirstRender, setIsFirstRender] = useState(true); - const [selectedDocumentIds, setSelectedDocumentIds] = useState([]); - - const { pagination, setPagination } = useGetPaginationWithRouter(); - - const sendQuestion = useCallback( - (question: string) => { - const q = trim(question); - if (isEmpty(q)) return; - setPagination({ page: 1 }); - setIsFirstRender(false); - setCurrentAnswer({} as IAnswer); - setSendingLoading(true); - send({ kb_ids: kbIds, question: q, tenantId }); - testChunk({ - kb_id: kbIds, - highlight: true, - question: q, - page: 1, - size: pagination.pageSize, - }); - - fetchRelatedQuestions(q); - }, - [ - send, - testChunk, - kbIds, - fetchRelatedQuestions, - setPagination, - pagination.pageSize, - tenantId, - ], - ); - - const handleSearchStrChange: ChangeEventHandler = - useCallback((e) => { - setSearchStr(e.target.value); - }, []); - - const handleClickRelatedQuestion = useCallback( - (question: string) => () => { - if (sendingLoading) return; - - setSearchStr(question); - sendQuestion(question); - }, - [sendQuestion, sendingLoading], - ); - - const handleTestChunk = useCallback( - (documentIds: string[], page: number = 1, size: number = 10) => { - const q = trim(searchStr); - if (sendingLoading || isEmpty(q)) return; - - testChunk({ - kb_id: kbIds, - highlight: true, - question: q, - doc_ids: documentIds ?? selectedDocumentIds, - page, - size, - }); - - testChunkAll({ - kb_id: kbIds, - highlight: true, - question: q, - doc_ids: [], - page, - size, - }); - }, - [ - searchStr, - sendingLoading, - testChunk, - kbIds, - selectedDocumentIds, - testChunkAll, - ], - ); - - useEffect(() => { - if (!isEmpty(answer)) { - setCurrentAnswer(answer); - } - }, [answer]); - - useEffect(() => { - if (done) { - setSendingLoading(false); - } - }, [done]); - - return { - sendQuestion, - handleSearchStrChange, - handleClickRelatedQuestion, - handleTestChunk, - setSelectedDocumentIds, - loading, - sendingLoading, - answer: currentAnswer, - relatedQuestions: relatedQuestions?.slice(0, 5) ?? [], - searchStr, - setSearchStr, - isFirstRender, - selectedDocumentIds, - isSearchStrEmpty: isEmpty(trim(searchStr)), - stopOutputMessage, - }; -}; - -export const useFetchBackgroundImage = () => { - const [imgUrl, setImgUrl] = useState(''); - - const fetchImage = useCallback(async () => { - try { - const res = await fetch( - '/HPImageArchive.aspx?format=js&idx=0&n=1&mkt=zh-CN', - ); - const ret = await res.json(); - const url = get(ret, 'images.0.url'); - if (url) { - setImgUrl(url); - } - } catch (error) { - console.log('🚀 ~ fetchImage ~ error:', error); - } - }, []); - - useEffect(() => { - fetchImage(); - }, [fetchImage]); - - return `https://cn.bing.com${imgUrl}`; -}; - -export const useTestRetrieval = ( - kbIds: string[], - searchStr: string, - sendingLoading: boolean, -) => { - const { testChunk, loading } = useTestChunkRetrieval(); - const { pagination } = useGetPaginationWithRouter(); - - const [selectedDocumentIds, setSelectedDocumentIds] = useState([]); - - const handleTestChunk = useCallback(() => { - const q = trim(searchStr); - if (sendingLoading || isEmpty(q)) return; - - testChunk({ - kb_id: kbIds, - highlight: true, - question: q, - doc_ids: Array.isArray(selectedDocumentIds) ? selectedDocumentIds : [], - page: pagination.current, - size: pagination.pageSize, - }); - }, [ - sendingLoading, - searchStr, - kbIds, - testChunk, - selectedDocumentIds, - pagination, - ]); - - useEffect(() => { - handleTestChunk(); - }, [handleTestChunk]); - - return { - loading, - selectedDocumentIds, - setSelectedDocumentIds, - }; -}; - -export const useShowMindMapDrawer = ( - kbIds: string[], - question: string, - searchId = '', -) => { - const { visible, showModal, hideModal } = useSetModalState(); - const ref = useRef(); - - const { - fetchMindMap, - data: mindMap, - loading: mindMapLoading, - } = useSearchFetchMindMap(); - - const handleShowModal = useCallback(() => { - const searchParams = { question: trim(question), kb_ids: kbIds, searchId }; - if ( - !isEmpty(searchParams.question) && - !isEqual(searchParams, ref.current) - ) { - ref.current = searchParams; - fetchMindMap(searchParams); - } - showModal(); - }, [fetchMindMap, showModal, question, kbIds, searchId]); - - return { - mindMap, - mindMapVisible: visible, - mindMapLoading, - showMindMapModal: handleShowModal, - hideMindMapModal: hideModal, - }; -}; - -export const usePendingMindMap = () => { - const [count, setCount] = useState(0); - const ref = useRef(); - - const setCountInterval = useCallback(() => { - ref.current = setInterval(() => { - setCount((pre) => { - if (pre > 40) { - clearInterval(ref?.current); - } - return pre + 1; - }); - }, 1000); - }, []); - - useEffect(() => { - setCountInterval(); - return () => { - clearInterval(ref?.current); - }; - }, [setCountInterval]); - - return Number(((count / 43) * 100).toFixed(0)); -}; diff --git a/web/src/pages/search/index.less b/web/src/pages/search/index.less deleted file mode 100644 index 1958fd116..000000000 --- a/web/src/pages/search/index.less +++ /dev/null @@ -1,191 +0,0 @@ -.searchPage { - background-position: center; - background-size: cover; - .card { - width: 100%; - :global(.ant-card-body) { - padding: 14px; - } - p { - margin: 0; - } - } - .tag { - padding: 4px 8px; - font-size: 14px; - cursor: pointer; - } -} - -.searchSide { - position: relative; - max-width: 400px !important; - min-width: auto !important; - - :global(.ant-layout-sider-children) { - height: auto; - } - inset-inline-start: 0; - - .modelForm { - display: flex; - padding: 24px; - } - - .checkGroup { - width: 100%; - height: 100%; - } - .list { - padding-top: 10px; - width: 100%; - height: calc(100vh - 76px); - overflow: auto; - // background-color: transparent; - // &::-webkit-scrollbar-track { - // background: transparent; - // } - } - .checkbox { - width: 100%; - } - .knowledgeName { - width: 116px; - max-width: 270px; - } - .embeddingId { - width: 170px; - } -} - -.firstRenderContent { - height: 100%; -} - -.content { - height: 100%; - overflow: auto; - width: 100%; - padding: 20px 16% 10px; - .hide { - display: none; - } - - .main { - margin: 0 auto; - width: 100%; - max-width: 1200px; - } - - .highlightContent { - .multipleLineEllipsis(2); - em { - color: red; - font-style: normal; - } - } - .documentReference { - cursor: pointer; - } - .pagination { - padding-bottom: 16px; - } -} -.answerWrapper { - margin-top: 16px; - background: rgba(232 242 251, 1); - box-shadow: 0 2px 8px 0 rgba(0, 0, 0, 0.08); - :global(.ant-card-head) { - background-color: #e6f4ff23; - } - & p { - margin: 0; - } -} - -.input() { - :global(.ant-input-affix-wrapper) { - padding: 4px 12px; - border-start-start-radius: 30px !important; - border-end-start-radius: 30px !important; - } - // :global(.ant-input-group-addon) { - // background-color: transparent; - // } - input { - height: 40px; - } - button { - height: 50px !important; - border-start-end-radius: 30px !important; - border-end-end-radius: 30px !important; - } -} - -.globalInput { - width: 600px; - position: sticky; - top: 30%; - z-index: 1; - .input(); -} -.partialInput { - width: 100%; - position: sticky; - top: 0; - z-index: 1; - .input(); -} - -.searchInput { - :global(.ant-input-search-button) { - display: none; - } -} - -.appIcon { - display: inline-block; - vertical-align: middle; - width: 60px; -} - -.appName { - vertical-align: middle; - font-family: Inter; - font-size: 40px; - font-style: normal; - font-weight: 600; - line-height: 20px; - - background: linear-gradient(to right, #095fab 10%, #25abe8 50%, #55c8dd 60%); - background-size: auto auto; - background-clip: border-box; - background-size: 200% auto; - color: #fff; - background-clip: text; - text-fill-color: transparent; - -webkit-background-clip: text; - -webkit-text-fill-color: transparent; - animation: textclip 1.5s linear infinite; -} - -@keyframes textclip { - to { - background-position: 200% center; - } -} - -.popupMarkdown { - width: 60vw; - max-height: 40vh; - overflow: auto; -} - -.mindMapFloatButton { - top: 20%; - width: 60px; - height: 60px; - :global(.ant-float-btn-content, .ant-float-btn-icon) { - width: auto !important; - } -} diff --git a/web/src/pages/search/index.tsx b/web/src/pages/search/index.tsx deleted file mode 100644 index db19e82aa..000000000 --- a/web/src/pages/search/index.tsx +++ /dev/null @@ -1,284 +0,0 @@ -import FileIcon from '@/components/file-icon'; -import HightLightMarkdown from '@/components/highlight-markdown'; -import { ImageWithPopover } from '@/components/image'; -import PdfDrawer from '@/components/pdf-drawer'; -import { useClickDrawer } from '@/components/pdf-drawer/hooks'; -import RetrievalDocuments from '@/components/retrieval-documents'; -import SvgIcon from '@/components/svg-icon'; -import { - useFetchKnowledgeList, - useSelectTestingResult, -} from '@/hooks/knowledge-hooks'; -import { useGetPaginationWithRouter } from '@/hooks/logic-hooks'; -import { IReference } from '@/interfaces/database/chat'; -import { - Button, - Card, - Divider, - Flex, - FloatButton, - Input, - Layout, - List, - Pagination, - PaginationProps, - Popover, - Skeleton, - Space, - Spin, - Tag, - Tooltip, -} from 'antd'; -import classNames from 'classnames'; -import DOMPurify from 'dompurify'; -import { isEmpty } from 'lodash'; -import { CircleStop, SendHorizontal } from 'lucide-react'; -import { useCallback, useMemo, useState } from 'react'; -import { useTranslation } from 'react-i18next'; -import MarkdownContent from '../chat/markdown-content'; -import { useSendQuestion, useShowMindMapDrawer } from './hooks'; -import styles from './index.less'; -import MindMapDrawer from './mindmap-drawer'; -import SearchSidebar from './sidebar'; - -const { Content } = Layout; -const { Search } = Input; - -const SearchPage = () => { - const { t } = useTranslation(); - const [checkedList, setCheckedList] = useState([]); - const { chunks, total } = useSelectTestingResult(); - const { list: knowledgeList } = useFetchKnowledgeList(); - const checkedWithoutEmbeddingIdList = useMemo(() => { - return checkedList.filter((x) => knowledgeList.some((y) => y.id === x)); - }, [checkedList, knowledgeList]); - - const { - sendQuestion, - handleClickRelatedQuestion, - handleSearchStrChange, - handleTestChunk, - setSelectedDocumentIds, - answer, - sendingLoading, - relatedQuestions, - searchStr, - loading, - isFirstRender, - selectedDocumentIds, - isSearchStrEmpty, - stopOutputMessage, - } = useSendQuestion(checkedWithoutEmbeddingIdList); - const { visible, hideModal, documentId, selectedChunk, clickDocumentButton } = - useClickDrawer(); - const { pagination } = useGetPaginationWithRouter(); - const { - mindMapVisible, - hideMindMapModal, - showMindMapModal, - mindMapLoading, - mindMap, - } = useShowMindMapDrawer(checkedWithoutEmbeddingIdList, searchStr); - - const onChange: PaginationProps['onChange'] = (pageNumber, pageSize) => { - pagination.onChange?.(pageNumber, pageSize); - handleTestChunk(selectedDocumentIds, pageNumber, pageSize); - }; - - const handleSearch = useCallback(() => { - sendQuestion(searchStr); - }, [searchStr, sendQuestion]); - - const InputSearch = ( - - - - ) : ( - - ) - } - onSearch={sendQuestion} - size="large" - loading={sendingLoading} - disabled={checkedWithoutEmbeddingIdList.length === 0} - className={classNames( - styles.searchInput, - isFirstRender ? styles.globalInput : styles.partialInput, - )} - /> - ); - - return ( - <> - - - - - {isFirstRender ? ( - - - {InputSearch} - - - ) : ( - -
- {InputSearch} - - - {t('chat.answerTitle')} - - } - className={styles.answerWrapper} - > - {isEmpty(answer) && sendingLoading ? ( - - ) : ( - answer.answer && ( - - ) - )} - - - - - - {chunks?.length > 0 && ( - ( - - - - - - - - {item.content_with_weight} - - - } - > -
-
- - clickDocumentButton( - item.doc_id, - item as any, - ) - } - > - - {item.docnm_kwd} - -
-
-
-
- )} - /> - )} -
- {relatedQuestions?.length > 0 && ( - - - {relatedQuestions?.map((x, idx) => ( - - {x} - - ))} - - - )} - - -
-
- )} -
-
-
- {!isFirstRender && - !isSearchStrEmpty && - !isEmpty(checkedWithoutEmbeddingIdList) && ( - - - } - /> - - )} - {visible && ( - - )} - {mindMapVisible && ( - - )} - - ); -}; - -export default SearchPage; diff --git a/web/src/pages/search/mindmap-drawer.tsx b/web/src/pages/search/mindmap-drawer.tsx deleted file mode 100644 index 43ac8eb1d..000000000 --- a/web/src/pages/search/mindmap-drawer.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import IndentedTree from '@/components/indented-tree/indented-tree'; -import { IModalProps } from '@/interfaces/common'; -import { Drawer, Flex, Progress } from 'antd'; -import { useTranslation } from 'react-i18next'; -import { usePendingMindMap } from './hooks'; - -interface IProps extends IModalProps { - data: any; -} - -const MindMapDrawer = ({ data, hideModal, visible, loading }: IProps) => { - const { t } = useTranslation(); - const percent = usePendingMindMap(); - return ( - - {loading ? ( - - - - ) : ( - - )} - - ); -}; - -export default MindMapDrawer; diff --git a/web/src/pages/search/sidebar.tsx b/web/src/pages/search/sidebar.tsx deleted file mode 100644 index 052f48443..000000000 --- a/web/src/pages/search/sidebar.tsx +++ /dev/null @@ -1,162 +0,0 @@ -import { useFetchKnowledgeList } from '@/hooks/knowledge-hooks'; -import { UserOutlined } from '@ant-design/icons'; -import type { TreeDataNode, TreeProps } from 'antd'; -import { Avatar, Layout, Space, Spin, Tree, Typography } from 'antd'; -import classNames from 'classnames'; -import { - Dispatch, - SetStateAction, - useCallback, - useEffect, - useMemo, - useState, -} from 'react'; - -import styles from './index.less'; - -const { Sider } = Layout; - -interface IProps { - isFirstRender: boolean; - checkedList: string[]; - setCheckedList: Dispatch>; -} - -const SearchSidebar = ({ - isFirstRender, - checkedList, - setCheckedList, -}: IProps) => { - const { list, loading } = useFetchKnowledgeList(); - - const groupedList = useMemo(() => { - return list.reduce((pre: TreeDataNode[], cur) => { - const parentItem = pre.find((x) => x.key === cur.embd_id); - const childItem: TreeDataNode = { - title: cur.name, - key: cur.id, - isLeaf: true, - }; - if (parentItem) { - parentItem.children?.push(childItem); - } else { - pre.push({ - title: cur.embd_id, - key: cur.embd_id, - isLeaf: false, - children: [childItem], - }); - } - - return pre; - }, []); - }, [list]); - - const [expandedKeys, setExpandedKeys] = useState([]); - const [selectedKeys, setSelectedKeys] = useState([]); - const [autoExpandParent, setAutoExpandParent] = useState(true); - - const onExpand: TreeProps['onExpand'] = (expandedKeysValue) => { - // if not set autoExpandParent to false, if children expanded, parent can not collapse. - // or, you can remove all expanded children keys. - setExpandedKeys(expandedKeysValue); - setAutoExpandParent(false); - }; - - const onCheck: TreeProps['onCheck'] = (checkedKeysValue, info) => { - console.log('onCheck', checkedKeysValue, info); - const currentCheckedKeysValue = checkedKeysValue as string[]; - - let nextSelectedKeysValue: string[] = []; - const { isLeaf, checked, key, children } = info.node; - if (isLeaf) { - const item = list.find((x) => x.id === key); - if (!checked) { - const embeddingIds = currentCheckedKeysValue - .filter((x) => list.some((y) => y.id === x)) - .map((x) => list.find((y) => y.id === x)?.embd_id); - - if (embeddingIds.some((x) => x !== item?.embd_id)) { - nextSelectedKeysValue = [key as string]; - } else { - nextSelectedKeysValue = currentCheckedKeysValue; - } - } else { - nextSelectedKeysValue = currentCheckedKeysValue; - } - } else { - if (!checked) { - nextSelectedKeysValue = [ - key as string, - ...(children?.map((x) => x.key as string) ?? []), - ]; - } else { - nextSelectedKeysValue = []; - } - } - - setCheckedList(nextSelectedKeysValue); - }; - - const onSelect: TreeProps['onSelect'] = (selectedKeysValue, info) => { - console.log('onSelect', info); - - setSelectedKeys(selectedKeysValue); - }; - - const renderTitle = useCallback( - (node: TreeDataNode) => { - const item = list.find((x) => x.id === node.key); - return ( - - {node.isLeaf && ( - } src={item?.avatar} /> - )} - - {node.title as string} - - - ); - }, - [list], - ); - - useEffect(() => { - const firstGroup = groupedList[0]?.children?.map((x) => x.key as string); - if (firstGroup) { - setCheckedList(firstGroup); - } - setExpandedKeys(groupedList.map((x) => x.key)); - }, [groupedList, setExpandedKeys, setCheckedList]); - - return ( - - - - - - ); -}; - -export default SearchSidebar; diff --git a/web/src/pages/user-setting/mcp/import-mcp-dialog/import-mcp-form.tsx b/web/src/pages/user-setting/mcp/import-mcp-dialog/import-mcp-form.tsx index d34507308..6408b9e18 100644 --- a/web/src/pages/user-setting/mcp/import-mcp-dialog/import-mcp-form.tsx +++ b/web/src/pages/user-setting/mcp/import-mcp-dialog/import-mcp-form.tsx @@ -14,8 +14,8 @@ import { FormMessage, } from '@/components/ui/form'; import { FileMimeType, Platform } from '@/constants/common'; +import { TagRenameId } from '@/constants/knowledge'; import { IModalProps } from '@/interfaces/common'; -import { TagRenameId } from '@/pages/add-knowledge/constant'; import { useTranslation } from 'react-i18next'; export function ImportMcpForm({ hideModal, onOk }: IModalProps) { diff --git a/web/src/pages/user-setting/mcp/import-mcp-dialog/index.tsx b/web/src/pages/user-setting/mcp/import-mcp-dialog/index.tsx index 76b35387b..1946523eb 100644 --- a/web/src/pages/user-setting/mcp/import-mcp-dialog/index.tsx +++ b/web/src/pages/user-setting/mcp/import-mcp-dialog/index.tsx @@ -6,8 +6,8 @@ import { DialogTitle, } from '@/components/ui/dialog'; import { LoadingButton } from '@/components/ui/loading-button'; +import { TagRenameId } from '@/constants/knowledge'; import { IModalProps } from '@/interfaces/common'; -import { TagRenameId } from '@/pages/add-knowledge/constant'; import { useTranslation } from 'react-i18next'; import { ImportMcpForm } from './import-mcp-form'; diff --git a/web/src/routes.ts b/web/src/routes.ts index 56dd84077..306a5225f 100644 --- a/web/src/routes.ts +++ b/web/src/routes.ts @@ -69,11 +69,6 @@ const routes = [ component: '@/pages/login-next', layout: false, }, - { - path: '/chat/share', - component: '@/pages/chat/share', - layout: false, - }, { path: Routes.ChatShare, component: `@/pages${Routes.ChatShare}`, @@ -89,65 +84,11 @@ const routes = [ component: `@/pages${Routes.ChatWidget}`, layout: false, }, - { - path: Routes.Home, - component: '@/layouts', - layout: false, - redirect: '/knowledge', - }, - { - path: '/knowledge', - component: '@/pages/knowledge', - }, - { - path: '/knowledge', - component: '@/pages/add-knowledge', - routes: [ - { - path: 'dataset', - component: '@/pages/add-knowledge/components/knowledge-dataset', - routes: [ - { - path: '', - component: '@/pages/add-knowledge/components/knowledge-file', - }, - { - path: 'chunk', - component: '@/pages/add-knowledge/components/knowledge-chunk', - }, - ], - }, - { - path: 'configuration', - component: '@/pages/add-knowledge/components/knowledge-setting', - }, - { - path: 'testing', - component: '@/pages/add-knowledge/components/knowledge-testing', - }, - { - path: 'knowledgeGraph', - component: '@/pages/add-knowledge/components/knowledge-graph', - }, - ], - }, - { - path: '/chat', - component: '@/pages/chat', - }, - { - path: '/file', - component: '@/pages/file-manager', - }, { path: Routes.AgentList, component: `@/pages/${Routes.Agents}`, }, - { - path: '/search', - component: '@/pages/search', - }, { path: '/document/:id', component: '@/pages/document-viewer', diff --git a/web/src/utils/chat.ts b/web/src/utils/chat.ts index b66559372..08ef3c820 100644 --- a/web/src/utils/chat.ts +++ b/web/src/utils/chat.ts @@ -2,8 +2,7 @@ import { ChatVariableEnabledField, EmptyConversationId, } from '@/constants/chat'; -import { Message } from '@/interfaces/database/chat'; -import { IMessage } from '@/pages/chat/interface'; +import { IMessage, Message } from '@/interfaces/database/chat'; import { omit } from 'lodash'; import { v4 as uuid } from 'uuid'; @@ -84,3 +83,13 @@ export function setChatVariableEnabledFieldValuePage() { return variableCheckBoxFieldMap; } + +const oldReg = /(#{2}\d+\${2})/g; +export const currentReg = /\[ID:(\d+)\]/g; + +// To be compatible with the old index matching mode +export const replaceTextByOldReg = (text: string) => { + return text?.replace(oldReg, (substring: string) => { + return `[ID:${substring.slice(2, -2)}]`; + }); +};