diff --git a/web/src/i18n/en.ts b/web/src/i18n/en.ts index f8ce9a2a..3843a760 100644 --- a/web/src/i18n/en.ts +++ b/web/src/i18n/en.ts @@ -505,6 +505,7 @@ export const en = { createImport: 'Create/Import', textDataSet: 'Text Dataset', imageDataSet: 'Image Dataset', + mediaDataSet: 'Media Dataset', blankDataset: 'Blank Dataset', customTextDataset: 'Custom Text Dataset', text: 'Text', @@ -581,6 +582,7 @@ export const en = { datasetName: 'Dataset Name', pleaseEnterDatasetName: 'Please enter dataset name', uploadImages: 'Upload Images', + uploadMedia: 'Upload Media files', pleaseUploadImages: 'Please upload images', embedding_id: 'Embedding', llm_id: 'LLM', diff --git a/web/src/i18n/zh.ts b/web/src/i18n/zh.ts index f1721a2f..d83607f3 100644 --- a/web/src/i18n/zh.ts +++ b/web/src/i18n/zh.ts @@ -128,6 +128,7 @@ export const zh = { createImport: '新建/导入', textDataSet: '文本数据集', imageDataSet: '图片数据集', + mediaDataSet: '媒体数据集', blankDataset: '空白数据集', emptyDataSet: '空白数据集', customTextDataset: '自定义文本数据集', @@ -204,6 +205,7 @@ export const zh = { datasetName: '数据集名称', pleaseEnterDatasetName: '请输入数据集名称', uploadImages: '上传图片', + uploadMedia: '上传媒体文件', pleaseUploadImages: '请上传图片', embedding_id: '嵌入模型', llm_id: '大语言模型', diff --git a/web/src/views/KnowledgeBase/[knowledgeBaseId]/CreateDataset.tsx b/web/src/views/KnowledgeBase/[knowledgeBaseId]/CreateDataset.tsx index 34a91850..0f273d7f 100644 --- a/web/src/views/KnowledgeBase/[knowledgeBaseId]/CreateDataset.tsx +++ b/web/src/views/KnowledgeBase/[knowledgeBaseId]/CreateDataset.tsx @@ -53,8 +53,8 @@ interface CreateDatasetLocationState { knowledgeBaseId?: string; parentId?: string; startStep?: StepKey; - fileId?: string; - fileIds?: string[]; + fileId?: string | string[]; + fileIds?: string | string[]; } const CreateDataset = () => { @@ -67,7 +67,11 @@ const CreateDataset = () => { const knowledgeBaseId = locationState.knowledgeBaseId || routeKnowledgeBaseId; const parentId = locationState.parentId; const initialStepKey = locationState.startStep ?? 'selectFile'; - const initialFileIds = locationState.fileIds ?? (locationState.fileId ? [locationState.fileId] : []); + const initialFileIds = (() => { + const fileIds = locationState.fileIds || locationState.fileId; + if (!fileIds) return []; + return Array.isArray(fileIds) ? fileIds : [fileIds]; + })(); const [current, setCurrent] = useState(stepIndexMap[initialStepKey]); const tableRef = useRef(null); diff --git a/web/src/views/KnowledgeBase/[knowledgeBaseId]/Private.tsx b/web/src/views/KnowledgeBase/[knowledgeBaseId]/Private.tsx index c6500b3c..5a4492d9 100644 --- a/web/src/views/KnowledgeBase/[knowledgeBaseId]/Private.tsx +++ b/web/src/views/KnowledgeBase/[knowledgeBaseId]/Private.tsx @@ -13,6 +13,7 @@ import folderIcon from '@/assets/images/knowledgeBase/folder.png'; import textIcon from '@/assets/images/knowledgeBase/text.png'; import editIcon from '@/assets/images/knowledgeBase/edit.png'; import blankIcon from '@/assets/images/knowledgeBase/blankDocument.png'; +import imageIcon from '@/assets/images/knowledgeBase/image.png' import { getKnowledgeBaseDetail, deleteDocument, downloadFile, updateKnowledgeBase } from '@/api/knowledgeBase'; import { type CreateModalRef, @@ -327,15 +328,15 @@ const Private: FC = () => { // handleCreate('folder'); // 传入 type: 'folder' }, }, - // 暂时未实现 - // { - // key: '3', - // icon: image, - // label: t('knowledgeBase.imageDataSet'), - // onClick: () => { - // createImageDataset?.current?.handleOpen(knowledgeBaseId || '', parentId || '') - // }, - // }, + { + key: '3', + icon: image, + label: t('knowledgeBase.mediaDataSet'), + onClick: () => { + createImageDataset?.current?.handleOpen(knowledgeBaseId || '', parentId || '') + }, + }, + // 暂时未实现 // { // key: '4', // icon: blank, diff --git a/web/src/views/KnowledgeBase/components/CreateImageDataset.tsx b/web/src/views/KnowledgeBase/components/CreateImageDataset.tsx index 8f57b009..0c5aff4d 100644 --- a/web/src/views/KnowledgeBase/components/CreateImageDataset.tsx +++ b/web/src/views/KnowledgeBase/components/CreateImageDataset.tsx @@ -1,5 +1,7 @@ import { forwardRef, useImperativeHandle, useState, useRef } from 'react'; -import { Form, Input } from 'antd'; +import { useNavigate } from 'react-router-dom'; + +import { Form, Input, message } from 'antd'; import { useTranslation } from 'react-i18next'; import type { UploadFile } from 'antd'; import type { CreateSetModalRef, CreateSetMoealRefProps, UploadFileResponse } from '@/views/KnowledgeBase/types'; @@ -16,12 +18,16 @@ interface ImageDatasetFormData { const CreateImageDataset = forwardRef( ({ refreshTable }, ref) => { const { t } = useTranslation(); + const navigate = useNavigate(); const [visible, setVisible] = useState(false); + const [messageApi, contextHolder] = message.useMessage(); + const [form] = Form.useForm(); const [loading, setLoading] = useState(false); const [kbId, setKbId] = useState(''); const [parentId, setParentId] = useState(''); const uploadRef = useRef<{ fileList: UploadFile[]; clearFiles: () => void }>(null); + // const fileIds = []; const handleClose = () => { form.resetFields(); @@ -50,22 +56,23 @@ const CreateImageDataset = forwardRef if (fileList.length === 0) { throw new Error(t('knowledgeBase.pleaseUploadImages')); } - - // 上传所有图片 - const uploadPromises = fileList.map(async (file) => { - if (file.originFileObj) { - const formData = new FormData(); - formData.append('file', file.originFileObj); + const ids = fileList.map((file) => file.response?.id); + handleChunking(kbId, parentId, ids) + // // 上传所有图片 + // const uploadPromises = fileList.map(async (file) => { + // if (file.originFileObj) { + // const formData = new FormData(); + // formData.append('file', file.originFileObj); - return uploadFile(formData, { - kb_id: kbId, - parent_id: parentId, - }); - } - return null; - }); + // return uploadFile(formData, { + // kb_id: kbId, + // parent_id: parentId, + // }); + // } + // return null; + // }); - await Promise.all(uploadPromises); + // await Promise.all(uploadPromises); if (refreshTable) { await refreshTable(); @@ -78,13 +85,73 @@ const CreateImageDataset = forwardRef setLoading(false); } }; - + const handleChunking = (kb_id: string, parent_id: string, file_id: Array) => { + if (!kb_id) return; + const targetFileId = file_id + navigate(`/knowledge-base/${kb_id}/create-dataset`, { + state: { + source: 'local', + knowledgeBaseId: kb_id, + parentId: parent_id ?? kb_id, + startStep: 'parameterSettings', + fileId: targetFileId, + }, + }); + } useImperativeHandle(ref, () => ({ handleOpen, })); + // 检查媒体文件时长的辅助函数 + const checkMediaDuration = (file: File): Promise => { + return new Promise((resolve, reject) => { + const url = URL.createObjectURL(file); + const media = document.createElement(file.type.startsWith('video/') ? 'video' : 'audio'); + + media.onloadedmetadata = () => { + URL.revokeObjectURL(url); + resolve(media.duration); + }; + + media.onerror = () => { + URL.revokeObjectURL(url); + reject(new Error('无法读取媒体文件')); + }; + + media.src = url; + }); + }; // 上传文件 - const handleUpload = (options: UploadRequestOption) => { + const handleUpload = async (options: UploadRequestOption) => { const { file, onSuccess, onError, onProgress, filename = 'file' } = options; + // 获取文件扩展名 + const fileExtension = (file as File).name.split('.').pop()?.toLowerCase(); + const mediaExtensions = ['mp3', 'mp4', 'mov', 'wav']; + + // 如果是媒体文件,进行大小和时长检查 + if (fileExtension && mediaExtensions.includes(fileExtension)) { + const fileSizeInMB = (file as File).size / (1024 * 1024); + + // 检查文件大小(256MB限制) + if (fileSizeInMB > 256) { + messageApi.error(`${t('knowledgeBase.sizeLimitError')}:${fileSizeInMB.toFixed(2)}MB`); + onError?.(new Error(`${t('knowledgeBase.fileSizeExceeds')}`)); + return; + } + + try { + // 检查媒体时长(150秒限制) + const duration = await checkMediaDuration(file as File); + if (duration > 150) { + messageApi.error(`${t('knowledgeBase.fileDurationLimitError')}:${Math.round(duration)}秒`); + onError?.(new Error(`${t('knowledgeBase.fileDurationExceeds')}`)); + return; + } + } catch (error) { + messageApi.error(`${t('knowledgeBase.unableReadFile')}`); + onError?.(error as Error); + return; + } + } const formData = new FormData(); formData.append(filename, file as File); @@ -108,6 +175,7 @@ const CreateImageDataset = forwardRef onSuccess?.(res, new XMLHttpRequest()); if (res?.id) { // 上传成功 + // fileIds.push(res.id) } }) .catch((error) => { @@ -115,6 +183,8 @@ const CreateImageDataset = forwardRef }); }; return ( + <> + {contextHolder} confirmLoading={loading} >
- - + */} - +
- ); + ); } );