diff --git a/README.md b/README.md
index b53597e2c..1af322b1d 100644
--- a/README.md
+++ b/README.md
@@ -57,7 +57,7 @@ https://github.com/labring/FastGPT/assets/15308462/7d3a38df-eb0e-4388-9250-2409b
- [x] 知识库单点搜索测试
- [x] 对话时反馈引用并可修改与删除
- [x] 完整调用链路日志
- - [ ] 应用评测
+ - [x] 应用评测
- [ ] 高级编排 DeBug 调试模式
- [ ] 应用节点日志
diff --git a/document/content/docs/upgrading/4-14/4142.mdx b/document/content/docs/upgrading/4-14/4142.mdx
index 9910f251e..8fef2e21d 100644
--- a/document/content/docs/upgrading/4-14/4142.mdx
+++ b/document/content/docs/upgrading/4-14/4142.mdx
@@ -9,6 +9,7 @@ description: 'FastGPT V4.14.2 更新说明'
1. 封装底层 Agent Call 方式,支持工具连续调用时上下文的压缩,以及单个工具长响应的压缩。
2. 模板市场新 UI。
+3. 支持 Agent 编辑页快速创建知识库。
## ⚙️ 优化
@@ -19,3 +20,16 @@ description: 'FastGPT V4.14.2 更新说明'
1. 简易应用模板未正常转化。
2. 工具调用中,包含两个以上连续用户选择时候,第二个用户选择异常。
+3. 门户中,团队应用类型错误。
+
+## 插件
+
+1. 修复:子工具头像丢失。
+2. 修复:模型头像丢失。
+3. 修复:Worker 中错误引用 mongoose 依赖,导致超过 10s 的工具运行报错。
+4. 优化:开发环境热更新时,不重复上传静态文件。
+5. 新增:5118 SEO 关键词挖掘工具。
+6. 新增:Tavity 内容提取高级配置。网页站点地图工具。
+7. 新增:微信公众号工具集。
+8. 新增:文档对比工具。
+9. 新增:kimiV2 和 GPT5.1 模型预设。
\ No newline at end of file
diff --git a/document/data/doc-last-modified.json b/document/data/doc-last-modified.json
index 66d2ef55c..3e756af53 100644
--- a/document/data/doc-last-modified.json
+++ b/document/data/doc-last-modified.json
@@ -116,7 +116,7 @@
"document/content/docs/upgrading/4-13/4132.mdx": "2025-10-21T11:46:53+08:00",
"document/content/docs/upgrading/4-14/4140.mdx": "2025-11-06T15:43:00+08:00",
"document/content/docs/upgrading/4-14/4141.mdx": "2025-11-12T12:19:02+08:00",
- "document/content/docs/upgrading/4-14/4142.mdx": "2025-11-14T13:21:17+08:00",
+ "document/content/docs/upgrading/4-14/4142.mdx": "2025-11-17T19:34:52+08:00",
"document/content/docs/upgrading/4-8/40.mdx": "2025-08-02T19:38:37+08:00",
"document/content/docs/upgrading/4-8/41.mdx": "2025-08-02T19:38:37+08:00",
"document/content/docs/upgrading/4-8/42.mdx": "2025-08-02T19:38:37+08:00",
diff --git a/packages/global/core/app/type.d.ts b/packages/global/core/app/type.d.ts
index c099c3c53..7f7b897a1 100644
--- a/packages/global/core/app/type.d.ts
+++ b/packages/global/core/app/type.d.ts
@@ -112,7 +112,7 @@ export type AppSimpleEditFormType = {
[NodeInputKeyEnum.aiChatJsonSchema]?: string;
};
dataset: {
- datasets: SelectedDatasetType;
+ datasets: SelectedDatasetType[];
} & AppDatasetSearchParamsType;
selectedTools: FlowNodeTemplateType[];
chatConfig: AppChatConfigType;
diff --git a/packages/global/core/dataset/type.d.ts b/packages/global/core/dataset/type.d.ts
index 26df8a530..d854bd274 100644
--- a/packages/global/core/dataset/type.d.ts
+++ b/packages/global/core/dataset/type.d.ts
@@ -10,7 +10,8 @@ import type {
SearchScoreTypeEnum,
TrainingModeEnum,
ChunkSettingModeEnum,
- ChunkTriggerConfigTypeEnum
+ ChunkTriggerConfigTypeEnum,
+ ParagraphChunkAIModeEnum
} from './constants';
import type { DatasetPermission } from '../../support/permission/dataset/controller';
import type {
diff --git a/packages/global/core/workflow/type/io.d.ts b/packages/global/core/workflow/type/io.d.ts
index d2fdbdf0e..1957cb627 100644
--- a/packages/global/core/workflow/type/io.d.ts
+++ b/packages/global/core/workflow/type/io.d.ts
@@ -128,7 +128,7 @@ export type SelectedDatasetType = {
avatar: string;
name: string;
vectorModel: EmbeddingModelItemType;
-}[];
+};
/* http node */
export type HttpParamAndHeaderItemType = {
diff --git a/packages/service/core/workflow/dispatch/dataset/search.ts b/packages/service/core/workflow/dispatch/dataset/search.ts
index 384efceb6..749ce620b 100644
--- a/packages/service/core/workflow/dispatch/dataset/search.ts
+++ b/packages/service/core/workflow/dispatch/dataset/search.ts
@@ -19,7 +19,7 @@ import { getDatasetSearchToolResponsePrompt } from '../../../../../global/core/a
import { getNodeErrResponse } from '../utils';
type DatasetSearchProps = ModuleDispatchProps<{
- [NodeInputKeyEnum.datasetSelectList]: SelectedDatasetType;
+ [NodeInputKeyEnum.datasetSelectList]: SelectedDatasetType[];
[NodeInputKeyEnum.datasetSimilarity]: number;
[NodeInputKeyEnum.datasetMaxTokens]: number;
[NodeInputKeyEnum.userChatInput]?: string;
diff --git a/packages/web/components/common/MyModal/index.tsx b/packages/web/components/common/MyModal/index.tsx
index 3f1a33ab0..59f289497 100644
--- a/packages/web/components/common/MyModal/index.tsx
+++ b/packages/web/components/common/MyModal/index.tsx
@@ -95,7 +95,7 @@ const MyModal = ({
/>
>
)}
-
+
{title}
diff --git a/packages/web/i18n/en/app.json b/packages/web/i18n/en/app.json
index 6f8c09397..7b59368a1 100644
--- a/packages/web/i18n/en/app.json
+++ b/packages/web/i18n/en/app.json
@@ -2,6 +2,7 @@
"Add_tool": "Add tool",
"AutoOptimize": "Automatic optimization",
"Click_to_delete_this_field": "Click to delete this field",
+ "Create_dataset": "Create a knowledge base",
"Custom_params": "input parameters",
"Edit_tool": "Edit tool",
"Filed_is_deprecated": "This field is deprecated",
@@ -126,6 +127,10 @@
"custom_plugin_user_guide_label": "User Guide",
"custom_plugin_user_guide_placeholder": "Use markdown syntax",
"dataset": "dataset",
+ "dataset.Select_dataset_model_tip": "Only knowledge bases with the same index model can be selected",
+ "dataset.create_dataset_tips": "For more advanced operations, please go to",
+ "dataset_create_success": "The knowledge base was created successfully and files are being indexed in the background.",
+ "dataset_empty_tips": "You don’t have a knowledge base yet, create one first.",
"dataset_search_tool_description": "Call the \"Semantic Search\" and \"Full-text Search\" capabilities to find reference content that may be related to the problem from the \"Knowledge Base\". \nPrioritize calling this tool to assist in answering user questions.",
"dataset_select": "Optional knowledge base",
"day": "Day",
diff --git a/packages/web/i18n/en/common.json b/packages/web/i18n/en/common.json
index 6061b08a3..56c25c801 100644
--- a/packages/web/i18n/en/common.json
+++ b/packages/web/i18n/en/common.json
@@ -783,7 +783,6 @@
"dataset.Manual collection Tip": "Manual datasets allow you to create an empty container to hold data",
"dataset.Move Failed": "Move Error",
"dataset.Select Dataset": "Select This Dataset",
- "dataset.Select Dataset Tips": "Only Datasets with the same index model can be selected",
"dataset.Select Folder": "Enter Folder",
"dataset.Training Name": "Data Training",
"dataset.collections.Collection Embedding": "{{total}} Indexes",
diff --git a/packages/web/i18n/zh-CN/app.json b/packages/web/i18n/zh-CN/app.json
index f8f34e8f2..65b90e90e 100644
--- a/packages/web/i18n/zh-CN/app.json
+++ b/packages/web/i18n/zh-CN/app.json
@@ -2,6 +2,7 @@
"Add_tool": "添加工具",
"AutoOptimize": "自动优化",
"Click_to_delete_this_field": "点击删除该字段",
+ "Create_dataset": "创建知识库",
"Custom_params": "输入参数",
"Edit_tool": "编辑工具",
"Filed_is_deprecated": "该字段已弃用",
@@ -129,6 +130,10 @@
"custom_plugin_user_guide_label": "使用说明",
"custom_plugin_user_guide_placeholder": "使用 markdown 语法",
"dataset": "知识库",
+ "dataset.Select_dataset_model_tip": "仅能选择同一个索引模型的知识库",
+ "dataset.create_dataset_tips": "更多高级操作请前往",
+ "dataset_create_success": "知识库创建成功,正在后台索引文件",
+ "dataset_empty_tips": "你还没有知识库,先创建一个吧",
"dataset_search_tool_description": "调用“语义检索”和“全文检索”能力,从“知识库”中查找可能与问题相关的参考内容。优先调用该工具来辅助回答用户的问题。",
"dataset_select": "可选知识库",
"day": "日",
diff --git a/packages/web/i18n/zh-CN/common.json b/packages/web/i18n/zh-CN/common.json
index bfed3a4a3..28b2b9e93 100644
--- a/packages/web/i18n/zh-CN/common.json
+++ b/packages/web/i18n/zh-CN/common.json
@@ -786,7 +786,6 @@
"dataset.Manual collection Tip": "手动数据集允许创建一个空的容器装入数据",
"dataset.Move Failed": "移动出现错误~",
"dataset.Select Dataset": "选择该知识库",
- "dataset.Select Dataset Tips": "仅能选择同一个索引模型的知识库",
"dataset.Select Folder": "进入文件夹",
"dataset.Training Name": "数据训练",
"dataset.collections.Collection Embedding": "{{total}} 组索引中",
diff --git a/packages/web/i18n/zh-Hant/app.json b/packages/web/i18n/zh-Hant/app.json
index 43614ca6d..fb3666358 100644
--- a/packages/web/i18n/zh-Hant/app.json
+++ b/packages/web/i18n/zh-Hant/app.json
@@ -2,6 +2,7 @@
"Add_tool": "添加工具",
"AutoOptimize": "自動優化",
"Click_to_delete_this_field": "點擊刪除該字段",
+ "Create_dataset": "創建知識庫",
"Custom_params": "輸入參數",
"Filed_is_deprecated": "該字段已棄用",
"HTTPTools_Create_Type": "創建方式",
@@ -125,6 +126,10 @@
"custom_plugin_user_guide_label": "使用說明",
"custom_plugin_user_guide_placeholder": "使用 markdown 語法",
"dataset": "知識庫",
+ "dataset.Select_dataset_model_tip": "僅能選擇同一個索引模型的知識庫",
+ "dataset.create_dataset_tips": "更多高級操作請前往",
+ "dataset_create_success": "知識庫創建成功,正在後台索引文件",
+ "dataset_empty_tips": "你還沒有知識庫,先創建一個吧",
"dataset_search_tool_description": "呼叫「語意搜尋」和「全文搜尋」功能,從「知識庫」中尋找可能與問題相關的參考內容。優先呼叫這個工具來協助回答使用者的問題。",
"dataset_select": "可選知識庫",
"day": "日",
diff --git a/packages/web/i18n/zh-Hant/common.json b/packages/web/i18n/zh-Hant/common.json
index 7b96ecea5..281ae8aaf 100644
--- a/packages/web/i18n/zh-Hant/common.json
+++ b/packages/web/i18n/zh-Hant/common.json
@@ -782,7 +782,6 @@
"dataset.Manual collection Tip": "手動資料集允許建立一個空的容器來存放資料",
"dataset.Move Failed": "移動錯誤",
"dataset.Select Dataset": "選擇此知識庫",
- "dataset.Select Dataset Tips": "僅能選擇相同索引模型的知識庫",
"dataset.Select Folder": "進入資料夾",
"dataset.Training Name": "資料訓練",
"dataset.collections.Collection Embedding": "{{total}} 個索引",
diff --git a/projects/app/src/components/core/app/DatasetSelectModal.tsx b/projects/app/src/components/core/app/DatasetSelectModal.tsx
index 377ef7b15..82fc95a4b 100644
--- a/projects/app/src/components/core/app/DatasetSelectModal.tsx
+++ b/projects/app/src/components/core/app/DatasetSelectModal.tsx
@@ -10,9 +10,10 @@ import {
VStack,
HStack,
IconButton,
- Spacer
+ Spacer,
+ useDisclosure
} from '@chakra-ui/react';
-import { ChevronRightIcon, CloseIcon, InfoIcon } from '@chakra-ui/icons';
+import { ChevronRightIcon, CloseIcon } from '@chakra-ui/icons';
import Avatar from '@fastgpt/web/components/common/Avatar';
import type { SelectedDatasetType } from '@fastgpt/global/core/workflow/type/io';
import type { DatasetListItemType } from '@fastgpt/global/core/dataset/type';
@@ -26,6 +27,7 @@ import SearchInput from '@fastgpt/web/components/common/Input/SearchInput';
import { useDatasetSelect } from '@/components/core/dataset/SelectModal';
import FolderPath from '@/components/common/folder/Path';
import EmptyTip from '@fastgpt/web/components/common/EmptyTip';
+import QuickCreateDatasetModal from '@/pageComponents/app/detail/components/QuickCreateModal';
// Dataset selection modal component
export const DatasetSelectModal = ({
@@ -35,19 +37,28 @@ export const DatasetSelectModal = ({
onClose
}: {
isOpen: boolean;
- defaultSelectedDatasets: SelectedDatasetType;
- onChange: (e: SelectedDatasetType) => void;
+ defaultSelectedDatasets: SelectedDatasetType[];
+ onChange: (e: SelectedDatasetType[]) => void;
onClose: () => void;
}) => {
// Translation function
const { t } = useTranslation();
// Current selected datasets, initialized with defaultSelectedDatasets
const [selectedDatasets, setSelectedDatasets] =
- useState(defaultSelectedDatasets);
+ useState(defaultSelectedDatasets);
const { toast } = useToast();
// Use server-side search, following the logic of the dataset list page
- const { paths, setParentId, searchKey, setSearchKey, datasets, isFetching } = useDatasetSelect();
+ const {
+ paths,
+ parentId,
+ setParentId,
+ searchKey,
+ setSearchKey,
+ datasets,
+ isFetching,
+ loadDatasets
+ } = useDatasetSelect();
// The vector model of the first selected dataset
const activeVectorModel = selectedDatasets[0]?.vectorModel?.model;
@@ -98,7 +109,7 @@ export const DatasetSelectModal = ({
if (isDatasetDisabled(item)) {
return toast({
status: 'warning',
- title: t('common:dataset.Select Dataset Tips')
+ title: t('app:dataset.Select_dataset_model_tip')
});
}
setSelectedDatasets((prev) => [
@@ -115,6 +126,15 @@ export const DatasetSelectModal = ({
}
};
+ const {
+ isOpen: isQuickCreateOpen,
+ onOpen: onOpenQuickCreate,
+ onClose: onCloseQuickCreate
+ } = useDisclosure();
+ const isRootEmpty = useMemo(() => {
+ return datasets.length === 0 && paths.length === 0 && !searchKey && !isFetching;
+ }, [datasets.length, isFetching, paths.length, searchKey]);
+
// Render component
return (
{/* Main vertical layout */}
-
- {/* Two-column layout */}
-
- {/* Left: search and dataset list */}
-
- {/* Search box */}
-
- setSearchKey(e.target.value?.trim())}
- size="md"
- />
-
-
- {/* Path display area - always occupies space, content changes based on search state */}
-
- {searchKey && (
+
+ {isRootEmpty ? (
+
+
+
+
+ ) : (
+ <>
+ {/* Two-column layout */}
+
+ {/* Left: search and dataset list */}
+
+ {/* Search box */}
+
+ setSearchKey(e.target.value?.trim())}
+ size="md"
+ />
+
+ {/* Path display area - always occupies space, content changes based on search state */}
- {t('chat:search_results')}
-
- )}
- {!searchKey && paths.length === 0 && (
- // Root directory path
-
- setParentId('')}
- >
- {t('common:root_folder')}
-
-
-
- )}
- {!searchKey && paths.length > 0 && (
- // Subdirectory path
- ({
- parentId: path.parentId,
- parentName: path.parentName
- }))}
- FirstPathDom={t('common:root_folder')}
- onClick={(e) => setParentId(e)}
- />
- )}
-
-
- {/* Dataset list */}
-
- {datasets.length === 0 && !isFetching && (
-
- )}
- {datasets.map((item: DatasetListItemType) => (
-
- {
- if (item.type === DatasetTypeEnum.folder) {
- if (searchKey) {
- setSearchKey('');
- }
- setParentId(item._id);
- } else {
- onSelect(item, !isDatasetSelected(item._id));
- }
- }}
- >
+ {searchKey && (
e.stopPropagation()} // Prevent parent click when clicking checkbox
+ w="100%"
+ minH={6}
+ display="flex"
+ alignItems="center"
+ fontSize="sm"
+ color="myGray.500"
>
- {item.type !== DatasetTypeEnum.folder && (
- {
- const checked = e.target.checked;
- onSelect(item, checked);
- }}
- colorScheme="blue"
- size="sm"
- />
- )}
+ {t('chat:search_results')}
-
- {/* Avatar */}
-
-
- {/* Name and type */}
-
-
- {item.name}
+ )}
+ {!searchKey && paths.length === 0 && datasets.length > 0 && (
+ // Root directory path
+
+ setParentId('')}
+ >
+ {t('common:root_folder')}
-
- {item.type === DatasetTypeEnum.folder ? (
- <>{t('common:Folder')}>
- ) : (
- <>
- {t('app:Index')}: {item.vectorModel.name}
- >
- )}
-
-
-
- {/* Folder expand arrow */}
- {item.type === DatasetTypeEnum.folder && (
-
-
-
- )}
-
+
+
+ )}
+ {!searchKey && paths.length > 0 && (
+ // Subdirectory path
+ ({
+ parentId: path.parentId,
+ parentName: path.parentName
+ }))}
+ FirstPathDom={t('common:root_folder')}
+ onClick={(e) => setParentId(e)}
+ />
+ )}
- ))}
-
-
- {/* Select all / Deselect all */}
- {datasets.length > 0 && (
-
- {
- if (e.target.checked) {
- const compatibleDatasets = compatibleDatasetsByModel.filter((dataset) => {
- return !isDatasetSelected(dataset._id);
- });
- const newSelections = compatibleDatasets.map(
- (item: DatasetListItemType) => ({
- datasetId: item._id,
- avatar: item.avatar,
- name: item.name,
- vectorModel: item.vectorModel
- })
- );
- setSelectedDatasets((prev) => [...prev, ...newSelections]);
- } else {
- const datasetIdsToRemove = compatibleDatasetsByModel.map(
- (item: DatasetListItemType) => item._id
- );
- setSelectedDatasets((prev) =>
- prev.filter((dataset) => !datasetIdsToRemove.includes(dataset.datasetId))
- );
- }
- }}
- colorScheme="blue"
- size="sm"
+ {/* Dataset list */}
+
- {t('common:Select_all')}
-
+ {datasets.length === 0 && !isFetching && (
+
+ )}
+ {datasets.map((item: DatasetListItemType) => (
+
+ {
+ if (item.type === DatasetTypeEnum.folder) {
+ if (searchKey) {
+ setSearchKey('');
+ }
+ setParentId(item._id);
+ } else {
+ onSelect(item, !isDatasetSelected(item._id));
+ }
+ }}
+ >
+ e.stopPropagation()} // Prevent parent click when clicking checkbox
+ >
+ {item.type !== DatasetTypeEnum.folder && (
+ {
+ const checked = e.target.checked;
+ onSelect(item, checked);
+ }}
+ colorScheme="blue"
+ size="sm"
+ />
+ )}
+
+
+ {/* Avatar */}
+
+
+ {/* Name and type */}
+
+
+ {item.name}
+
+
+ {item.type === DatasetTypeEnum.folder ? (
+ <>{t('common:Folder')}>
+ ) : (
+ <>
+ {t('app:Index')}: {item.vectorModel.name}
+ >
+ )}
+
+
+
+ {/* Folder expand arrow */}
+ {item.type === DatasetTypeEnum.folder && (
+
+
+
+ )}
+
+
+ ))}
+
+
+ {/* Select all / Deselect all */}
+ {datasets.length > 0 && (
+
+ {
+ if (e.target.checked) {
+ const compatibleDatasets = compatibleDatasetsByModel.filter(
+ (dataset) => {
+ return !isDatasetSelected(dataset._id);
+ }
+ );
+ const newSelections = compatibleDatasets.map(
+ (item: DatasetListItemType) => ({
+ datasetId: item._id,
+ avatar: item.avatar,
+ name: item.name,
+ vectorModel: item.vectorModel
+ })
+ );
+ setSelectedDatasets((prev) => [...prev, ...newSelections]);
+ } else {
+ const datasetIdsToRemove = compatibleDatasetsByModel.map(
+ (item: DatasetListItemType) => item._id
+ );
+ setSelectedDatasets((prev) =>
+ prev.filter(
+ (dataset) => !datasetIdsToRemove.includes(dataset.datasetId)
+ )
+ );
+ }
+ }}
+ colorScheme="blue"
+ size="sm"
+ >
+ {t('common:Select_all')}
+
+
+ )}
- )}
-
- {/* Right: selected datasets display */}
-
- {/* Selected count display */}
-
- {t('app:Selected')}: {selectedDatasets.length} {t('app:dataset')}
-
- {/* Selected dataset list */}
-
- {selectedDatasets.length === 0 && !isFetching && (
-
- )}
- {selectedDatasets.map((item) => (
-
-
-
- {item.name}
-
- }
- size="xs"
- variant="ghost"
- color="black"
- _hover={{ bg: 'myGray.200' }}
- onClick={() =>
- setSelectedDatasets((prev) =>
- prev.filter((dataset) => dataset.datasetId !== item.datasetId)
- )
- }
- />
-
- ))}
-
-
-
+ {/* Right: selected datasets display */}
+
+ {!isRootEmpty && (
+ <>
+ {/* Selected count display */}
+
+ {t('app:Selected')}: {selectedDatasets.length} {t('app:dataset')}
+
+ {/* Selected dataset list */}
+
+ {selectedDatasets.length === 0 && !isFetching && (
+
+ )}
+ {selectedDatasets.map((item) => (
+
+
+
+ {item.name}
+
+ }
+ size="xs"
+ variant="ghost"
+ color="black"
+ _hover={{ bg: 'myGray.200' }}
+ onClick={() =>
+ setSelectedDatasets((prev) =>
+ prev.filter((dataset) => dataset.datasetId !== item.datasetId)
+ )
+ }
+ />
+
+ ))}
+
+ >
+ )}
+
+
+ >
+ )}
{/* Modal footer button area */}
-
-
-
-
- {t('common:dataset.Select Dataset Tips')}
-
+ {!isRootEmpty && (
}
+ variant={'transparentBase'}
+ color={'primary.700'}
+ fontSize={'mini'}
+ onClick={onOpenQuickCreate}
+ >
+ {t('common:new_create')}
+
+ )}
+
+ {isRootEmpty ? (
+
-
+ ) : (
+
+
+
+ {t('app:dataset.Select_dataset_model_tip')}
+
+
+
+ )}
+
+ {isQuickCreateOpen && (
+ {
+ setSelectedDatasets((prev) => [...prev, newDataset]);
+ loadDatasets();
+ }}
+ />
+ )}
);
};
diff --git a/projects/app/src/components/core/dataset/SelectModal.tsx b/projects/app/src/components/core/dataset/SelectModal.tsx
index d83a60ddb..21c7abdcd 100644
--- a/projects/app/src/components/core/dataset/SelectModal.tsx
+++ b/projects/app/src/components/core/dataset/SelectModal.tsx
@@ -77,7 +77,8 @@ export function useDatasetSelect() {
datasets: [],
paths: []
},
- loading: isFetching
+ loading: isFetching,
+ runAsync: loadDatasets
} = useRequest2(
async () => {
const result = await Promise.all([
@@ -105,7 +106,8 @@ export function useDatasetSelect() {
setSearchKey,
datasets: data.datasets,
paths: data.paths,
- isFetching
+ isFetching,
+ loadDatasets
};
}
diff --git a/projects/app/src/pageComponents/app/detail/WorkflowComponents/Flow/nodes/render/RenderInput/templates/SelectDataset.tsx b/projects/app/src/pageComponents/app/detail/WorkflowComponents/Flow/nodes/render/RenderInput/templates/SelectDataset.tsx
index 526a55603..32819022d 100644
--- a/projects/app/src/pageComponents/app/detail/WorkflowComponents/Flow/nodes/render/RenderInput/templates/SelectDataset.tsx
+++ b/projects/app/src/pageComponents/app/detail/WorkflowComponents/Flow/nodes/render/RenderInput/templates/SelectDataset.tsx
@@ -36,8 +36,8 @@ export const SelectDatasetRender = React.memo(function SelectDatasetRender({
} = useDisclosure();
const selectedDatasets = useMemo(() => {
- if (Array.isArray(item.value)) return item.value as SelectedDatasetType;
- return [] as SelectedDatasetType;
+ if (Array.isArray(item.value)) return item.value as SelectedDatasetType[];
+ return [] as SelectedDatasetType[];
}, [item.value]);
useEffect(() => {
diff --git a/projects/app/src/pageComponents/app/detail/components/QuickCreateModal.tsx b/projects/app/src/pageComponents/app/detail/components/QuickCreateModal.tsx
new file mode 100644
index 000000000..24a9fd894
--- /dev/null
+++ b/projects/app/src/pageComponents/app/detail/components/QuickCreateModal.tsx
@@ -0,0 +1,347 @@
+import React, { useState } from 'react';
+import { useTranslation } from 'next-i18next';
+import { useForm } from 'react-hook-form';
+import {
+ Box,
+ Flex,
+ ModalBody,
+ ModalFooter,
+ Button,
+ FormControl,
+ Input,
+ Progress
+} from '@chakra-ui/react';
+import MyModal from '@fastgpt/web/components/common/MyModal';
+import Avatar from '@fastgpt/web/components/common/Avatar';
+import FormLabel from '@fastgpt/web/components/common/MyBox/FormLabel';
+import MyTooltip from '@fastgpt/web/components/common/MyTooltip';
+import MyIcon from '@fastgpt/web/components/common/Icon';
+import { useUploadAvatar } from '@fastgpt/web/common/file/hooks/useUploadAvatar';
+import { useRequest2 } from '@fastgpt/web/hooks/useRequest';
+import {
+ postCreateDataset,
+ getDatasetById,
+ postCreateDatasetFileCollection
+} from '@/web/core/dataset/api';
+import { getUploadAvatarPresignedUrl } from '@/web/common/file/api';
+import { uploadFile2DB } from '@/web/common/file/controller';
+import { useSystemStore } from '@/web/common/system/useSystemStore';
+import {
+ ChunkSettingModeEnum,
+ ChunkTriggerConfigTypeEnum,
+ DataChunkSplitModeEnum,
+ DatasetCollectionDataProcessModeEnum,
+ DatasetTypeEnum
+} from '@fastgpt/global/core/dataset/constants';
+import { getWebDefaultEmbeddingModel, getWebDefaultLLMModel } from '@/web/common/system/utils';
+import { BucketNameEnum } from '@fastgpt/global/common/file/constants';
+import { getErrText } from '@fastgpt/global/common/error/utils';
+import { formatFileSize } from '@fastgpt/global/common/file/tools';
+import { getFileIcon } from '@fastgpt/global/common/file/icon';
+import type { SelectedDatasetType } from '@fastgpt/global/core/workflow/type/io';
+import type { ImportSourceItemType } from '@/web/core/dataset/type';
+import FileSelector, {
+ type SelectFileItemType
+} from '@/pageComponents/dataset/detail/Import/components/FileSelector';
+import { useRouter } from 'next/router';
+
+const QuickCreateDatasetModal = ({
+ onClose,
+ onSuccess,
+ parentId
+}: {
+ onClose: () => void;
+ onSuccess: (dataset: SelectedDatasetType) => void;
+ parentId: string;
+}) => {
+ const { t } = useTranslation();
+ const router = useRouter();
+ const { defaultModels, embeddingModelList, datasetModelList } = useSystemStore();
+
+ const defaultVectorModel =
+ defaultModels.embedding?.model || getWebDefaultEmbeddingModel(embeddingModelList)?.model;
+ const defaultAgentModel =
+ defaultModels.datasetTextLLM?.model || getWebDefaultLLMModel(datasetModelList)?.model;
+ const defaultVLLM = defaultModels.datasetImageLLM?.model;
+
+ const [selectFiles, setSelectFiles] = useState([]);
+
+ const { register, handleSubmit, watch, setValue } = useForm({
+ defaultValues: {
+ parentId,
+ name: '',
+ avatar: 'core/dataset/commonDatasetColor'
+ }
+ });
+
+ const avatar = watch('avatar');
+
+ const { Component: AvatarUploader, handleFileSelectorOpen: handleAvatarSelectorOpen } =
+ useUploadAvatar(getUploadAvatarPresignedUrl, {
+ onSuccess: (avatarUrl: string) => {
+ setValue('avatar', avatarUrl);
+ }
+ });
+
+ const handleSelectFiles = (files: SelectFileItemType[]) => {
+ setSelectFiles((state) => [
+ ...state,
+ ...files.map((selectFile) => {
+ const { fileId, file } = selectFile;
+
+ return {
+ id: fileId,
+ createStatus: 'waiting',
+ file,
+ sourceName: file.name,
+ sourceSize: formatFileSize(file.size),
+ icon: getFileIcon(file.name),
+ uploadedFileRate: 0
+ };
+ })
+ ]);
+ };
+
+ const uploadSingleFile = async (fileItem: ImportSourceItemType, datasetId: string) => {
+ try {
+ if (!fileItem.file) return;
+ setSelectFiles((prev) =>
+ prev.map((item) => (item.id === fileItem.id ? { ...item, uploadedFileRate: 0 } : item))
+ );
+
+ const { fileId } = await uploadFile2DB({
+ file: fileItem.file,
+ bucketName: BucketNameEnum.dataset,
+ data: { datasetId },
+ percentListen: (percent) => {
+ setSelectFiles((prev) =>
+ prev.map((item) =>
+ item.id === fileItem.id
+ ? { ...item, uploadedFileRate: Math.max(percent, item.uploadedFileRate || 0) }
+ : item
+ )
+ );
+ }
+ });
+
+ await postCreateDatasetFileCollection({
+ datasetId,
+ fileId,
+ trainingType: DatasetCollectionDataProcessModeEnum.chunk,
+ chunkTriggerType: ChunkTriggerConfigTypeEnum.minSize,
+ chunkTriggerMinSize: 1000,
+ chunkSettingMode: ChunkSettingModeEnum.auto,
+ chunkSplitMode: DataChunkSplitModeEnum.paragraph,
+ chunkSize: 1024,
+ indexSize: 512,
+ customPdfParse: false
+ });
+
+ setSelectFiles((prev) =>
+ prev.map((item) =>
+ item.id === fileItem.id ? { ...item, dbFileId: fileId, uploadedFileRate: 100 } : item
+ )
+ );
+ } catch (error) {
+ setSelectFiles((prev) =>
+ prev.map((item) =>
+ item.id === fileItem.id ? { ...item, errorMsg: getErrText(error) } : item
+ )
+ );
+ }
+ };
+
+ const { runAsync: onCreate, loading: isCreating } = useRequest2(
+ async (data) => {
+ const datasetId = await postCreateDataset({
+ name: data.name.trim(),
+ avatar: data.avatar,
+ intro: '',
+ parentId,
+ type: DatasetTypeEnum.dataset,
+ vectorModel: defaultVectorModel,
+ agentModel: defaultAgentModel,
+ vlmModel: defaultVLLM
+ });
+
+ if (selectFiles.length > 0) {
+ await Promise.all(selectFiles.map((file) => uploadSingleFile(file, datasetId)));
+ }
+
+ const datasetDetail = await getDatasetById(datasetId);
+
+ return {
+ datasetId,
+ name: datasetDetail.name,
+ avatar: datasetDetail.avatar,
+ vectorModel: datasetDetail.vectorModel
+ };
+ },
+ {
+ manual: true,
+ successToast: t('app:dataset_create_success'),
+ onSuccess: (result) => {
+ onSuccess(result);
+ onClose();
+ setSelectFiles([]);
+ }
+ }
+ );
+
+ return (
+
+
+
+ {t('common:app_icon_and_name')}
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {selectFiles.length > 0 && (
+
+ {selectFiles.map((item) => (
+
+
+
+ {item.sourceName}
+
+
+ {item.errorMsg ? (
+
+
+
+ {t('common:Error')}
+
+
+
+
+ ) : !!item.uploadedFileRate ? (
+
+
+ {`${item.uploadedFileRate}%`}
+
+ ) : null}
+
+
+ {!item.uploadedFileRate && (
+
+
+ setSelectFiles((prev) =>
+ prev.filter((prevItem) => prevItem.id !== item.id)
+ )
+ }
+ />
+
+ )}
+
+
+ ))}
+
+ )}
+
+
+
+
+
+ {t('app:dataset.create_dataset_tips')}
+ {
+ router.push('/dataset/list');
+ }}
+ >
+ {t('common:core.dataset.Dataset')}
+
+
+
+
+
+
+
+
+
+
+ );
+};
+
+export default QuickCreateDatasetModal;
diff --git a/projects/app/src/pageComponents/dataset/detail/Import/commonProgress/Upload.tsx b/projects/app/src/pageComponents/dataset/detail/Import/commonProgress/Upload.tsx
index ea96fc073..36c94bb17 100644
--- a/projects/app/src/pageComponents/dataset/detail/Import/commonProgress/Upload.tsx
+++ b/projects/app/src/pageComponents/dataset/detail/Import/commonProgress/Upload.tsx
@@ -20,7 +20,6 @@ import MyIcon from '@fastgpt/web/components/common/Icon';
import { useRequest2 } from '@fastgpt/web/hooks/useRequest';
import { useToast } from '@fastgpt/web/hooks/useToast';
import { useRouter } from 'next/router';
-import { TabEnum } from '../../../../../pages/dataset/detail/index';
import {
postCreateDatasetApiDatasetCollection,
postCreateDatasetExternalFileCollection,
diff --git a/projects/app/src/service/core/dataset/queues/datasetParse.ts b/projects/app/src/service/core/dataset/queues/datasetParse.ts
index 7afc73b5b..5017377d9 100644
--- a/projects/app/src/service/core/dataset/queues/datasetParse.ts
+++ b/projects/app/src/service/core/dataset/queues/datasetParse.ts
@@ -42,7 +42,7 @@ const requestLLMPargraph = async ({
rawText: string;
model: string;
billId: string;
- paragraphChunkAIMode: ParagraphChunkAIModeEnum;
+ paragraphChunkAIMode?: ParagraphChunkAIModeEnum;
}) => {
if (
!global.feConfigs?.isPlus ||