diff --git a/web/src/views/KnowledgeBase/[knowledgeBaseId]/CreateDataset.tsx b/web/src/views/KnowledgeBase/[knowledgeBaseId]/CreateDataset.tsx index f876c51b..d2b1536f 100644 --- a/web/src/views/KnowledgeBase/[knowledgeBaseId]/CreateDataset.tsx +++ b/web/src/views/KnowledgeBase/[knowledgeBaseId]/CreateDataset.tsx @@ -24,7 +24,7 @@ const { TextArea } = Input; const radioWrapperBaseStyle: React.CSSProperties = { display: 'flex', alignItems: 'flex-start', - columnGap: 14, // 点与文字更宽的间距 + columnGap: 14, // Wider gap between dot and text width: '100%', border: '1px solid #E5E5E5', borderRadius: 8, @@ -97,7 +97,7 @@ const CreateDataset = () => { () => [ { title: t('knowledgeBase.selectFile') }, { title: t('knowledgeBase.parameterSettings') }, - // { title: t('knowledgeBase.dataPreview') }, // 暂时隐藏第三步 + // { title: t('knowledgeBase.dataPreview') }, // Temporarily hide step 3 { title: t('knowledgeBase.confirmUpload') }, ], [t], @@ -105,27 +105,27 @@ const CreateDataset = () => { // 存储每个文件的 AbortController,用于取消上传 const abortControllersRef = useRef>(new Map()); const uploadRef = useRef<{ fileList: UploadFile[]; clearFiles: () => void }>(null); - console.log('上传文件',uploadRef.current?.fileList.length) + console.log('Upload files', uploadRef.current?.fileList.length) const handleNext = async () => { - // 暂时隐藏第三步:调整步骤索引(0->1->2 对应 选择文件->参数设置->确认上传) + // Temporarily hide step 3: adjust step index (0->1->2 corresponds to select file->parameter settings->confirm upload) let nextStep = current + 1; if(nextStep === 1 && source === 'local') { - // 检查是否有文件已上传 + // Check if files have been uploaded if (rechunkFileIds.length === 0) { - // 如果没有文件,提示用户先上传文件 + // If no files, prompt user to upload first Modal.warning({ - title: t('common.warning') || '提示', - content: t('knowledgeBase.pleaseUploadFileFirst') || '请先上传文件', + title: t('common.warning') || 'Warning', + content: t('knowledgeBase.pleaseUploadFileFirst') || 'Please upload files first', }); - return; // 不进入下一步 + return; // Don't proceed to next step } }else if(nextStep === 1 && source === 'text'){ try { const values = await form.validateFields(); // setLoading(true); - // TODO: 这里需要调用相应的API来保存内容 + // TODO: Need to call corresponding API to save content here const params = { // ...values, kb_id: knowledgeBaseId, @@ -162,41 +162,41 @@ const CreateDataset = () => { }) } - // 立即执行一次,加载文档列表用于预览(不自动返回) + // Execute once immediately to load document list for preview (don't auto-return) pollDocumentStatus(false); } - // 限制最大步骤为 2(确认上传) + // Limit max step to 2 (confirm upload) setCurrent(Math.min(nextStep, 2)); }; const handlePrev = () => setCurrent((c) => Math.max(c - 1, 0)); - // 开始上传:触发文档解析并启动轮询 + // Start upload: trigger document parsing and start polling const handleStartUpload = () => { if (rechunkFileIds.length === 0) { Modal.warning({ - title: t('common.warning') || '提示', - content: t('knowledgeBase.pleaseUploadFileFirst') || '请先上传文件', + title: t('common.warning') || 'Warning', + content: t('knowledgeBase.pleaseUploadFileFirst') || 'Please upload files first', }); return; } // 显示确认弹框 confirm({ - title: t('knowledgeBase.startUploadConfirmTitle') || '开始处理文档', - content: t('knowledgeBase.startUploadConfirmContent') || '文档处理将在后台进行,您可以选择立即返回列表页或停留在此页面查看处理进度。', - okText: t('knowledgeBase.returnToList') || '返回列表页', - cancelText: t('knowledgeBase.stayOnPage') || '停留在此页', + title: t('knowledgeBase.startUploadConfirmTitle') || 'Start processing documents', + content: t('knowledgeBase.startUploadConfirmContent') || 'Document processing will proceed in the background. You can choose to return to the list page immediately or stay on this page to view processing progress.', + okText: t('knowledgeBase.returnToList') || 'Return to list', + cancelText: t('knowledgeBase.stayOnPage') || 'Stay on this page', onOk: () => { - // 用户选择返回列表页 - 不显示 loading,直接跳转 + // User chose to return to list - don't show loading, navigate directly startProcessing(true); }, onCancel: () => { - // 用户选择停留在当前页 - 显示 loading 并开始轮询 - console.log('用户选择停留,开始显示 loading'); + // User chose to stay on current page - show loading and start polling + console.log('User chose to stay, starting to show loading'); setPollingLoading(true); - // 延迟一点时间让用户看到 loading 效果,然后开始处理 + // Delay a bit to let user see loading effect, then start processing setTimeout(() => { startProcessing(false); }, 100); @@ -204,25 +204,25 @@ const CreateDataset = () => { }); }; - // 实际开始处理的函数 + // Function to actually start processing const startProcessing = (autoReturnToList: boolean) => { - // 触发文档解析 + // Trigger document parsing rechunkFileIds.map((id) => { parseDocument(id, {}); }); if (autoReturnToList) { - // 用户选择立即返回,直接跳转(不显示 loading) - console.log('用户选择立即返回列表页'); + // User chose to return immediately, navigate directly (no loading shown) + console.log('User chose to return to list page immediately'); handleBack(); } else { - // 用户选择停留,启动轮询查看进度(loading 已在 onCancel 中设置) - console.log('用户选择停留查看进度'); + // User chose to stay, start polling to view progress (loading already set in onCancel) + console.log('User chose to stay and view progress'); - // 立即执行一次轮询(启用自动返回) + // Execute polling once immediately (enable auto-return) pollDocumentStatus(true); - // 然后每3秒执行一次(启用自动返回) + // Then execute every 3 seconds (enable auto-return) pollingTimerRef.current = setInterval(() => { pollDocumentStatus(true); }, 3000); @@ -244,11 +244,11 @@ const CreateDataset = () => { }, onCancel: () => { - console.log('取消删除'); + console.log('Delete cancelled'); }, }); } - // 表格列配置 + // Table column configuration const columns: ColumnsType = [ { title: t('knowledgeBase.name'), @@ -261,7 +261,7 @@ const CreateDataset = () => { dataIndex: 'progress', key: 'progress', render: (value: number, record: any) => { - // value >= 1 时完成,0~1 时显示进度条 + // When value >= 1 it's complete, when 0~1 show progress bar if (value >= 1) { return ( @@ -270,7 +270,7 @@ const CreateDataset = () => { ); } else if (value >= 0 && value < 1) { - // 处理中,显示进度条 + // Processing, show progress bar return (
{
); } else { - // value = 0 或其他情况,显示待处理 + // value = 0 or other cases, show pending return ( @@ -304,7 +304,7 @@ const CreateDataset = () => { ), }, ]; - // 检查媒体文件时长的辅助函数 + // Helper function to check media file duration const checkMediaDuration = (file: File): Promise => { return new Promise((resolve, reject) => { const url = URL.createObjectURL(file); @@ -324,36 +324,36 @@ const CreateDataset = () => { }); }; - // 上传文件 + // Upload file const handleUpload = async (options: UploadRequestOption) => { const { file, onSuccess, onError, onProgress, filename = 'file' } = options; - // 创建 AbortController 用于取消上传 + // Create AbortController for cancelling upload const abortController = new AbortController(); const fileUid = (file as any).uid; abortControllersRef.current.set(fileUid, abortController); - // 获取文件扩展名 + // Get file extension const fileExtension = (file as File).name.split('.').pop()?.toLowerCase(); const mediaExtensions = ['mp3', 'mp4', 'mov', 'wav']; - // 如果是媒体文件,进行大小和时长检查 + // If media file, check size and duration if (fileExtension && mediaExtensions.includes(fileExtension)) { const fileSizeInMB = (file as File).size / (1024 * 1024); // 检查文件大小(50MB限制) if (fileSizeInMB > 100) { - messageApi.error(`${t('knowledgeBase.sizeLimitError')}:${fileSizeInMB.toFixed(2)}MB`); + messageApi.error(`${t('knowledgeBase.sizeLimitError')}: ${fileSizeInMB.toFixed(2)}MB`); onError?.(new Error(`${t('knowledgeBase.fileSizeExceeds')}`)); abortControllersRef.current.delete(fileUid); return; } try { - // 检查媒体时长(150秒限制) + // Check media duration (150 second limit) const duration = await checkMediaDuration(file as File); if (duration > 150) { - messageApi.error(`${t('knowledgeBase.fileDurationLimitError')}:${Math.round(duration)}秒`); + messageApi.error(`${t('knowledgeBase.fileDurationLimitError')}: ${Math.round(duration)}s`); onError?.(new Error(`${t('knowledgeBase.fileDurationExceeds')}`)); abortControllersRef.current.delete(fileUid); return; @@ -386,7 +386,7 @@ const CreateDataset = () => { }, }) .then((res: UploadFileResponse) => { - // 上传成功,移除 AbortController + // Upload successful, remove AbortController abortControllersRef.current.delete(fileUid); onSuccess?.(res, new XMLHttpRequest()); @@ -399,12 +399,12 @@ const CreateDataset = () => { } }) .catch((error) => { - // 移除 AbortController + // Remove AbortController abortControllersRef.current.delete(fileUid); - // 如果是用户主动取消,不显示错误信息 + // If user actively cancelled, don't show error message if (error.name === 'AbortError' || error.code === 'ERR_CANCELED') { - console.log('上传已取消:', (file as File).name); + console.log('Upload cancelled:', (file as File).name); return; } onError?.(error as Error); @@ -413,12 +413,12 @@ const CreateDataset = () => { // 轮询检查文档处理状态 - // autoReturn: 是否在所有文档完成时自动返回列表页 + // autoReturn: whether to automatically return to list page when all documents are completed const pollDocumentStatus = (autoReturn: boolean = false) => { - console.log('开始轮询文档状态,当前 pollingLoading:', pollingLoading); + console.log('Start polling document status, current pollingLoading:', pollingLoading); if (!knowledgeBaseId || !parentId || rechunkFileIds.length === 0) { - console.log('轮询条件不满足,退出'); + console.log('Polling conditions not met, exiting'); return; } @@ -436,10 +436,10 @@ const CreateDataset = () => { } console.log('documents', documents); - // 检查是否所有文档的 progress 都为 1 + // Check if all documents have progress of 1 const allCompleted = documents.every((doc: KnowledgeBaseDocumentData) => doc.progress === 1); - console.log('轮询状态:', allCompleted); + console.log('Polling status:', allCompleted); // 检查是否所有文档都完成了 // debugger @@ -455,23 +455,23 @@ const CreateDataset = () => { setPollingLoading(false); }, 1000); - // 只有在 autoReturn 为 true 时才自动返回 + // Only auto-return when autoReturn is true if (autoReturn) { - // 延迟 2 秒后跳转,让用户看到完成状态 - console.log('所有文档处理完成,2秒后返回列表页'); + // Delay 2 seconds before navigating to let user see completion status + console.log('All documents processed, returning to list page in 2 seconds'); setTimeout(() => { handleBack(); }, 2000); } else { - console.log('所有文档处理完成,用户可手动操作'); + console.log('All documents processed, user can operate manually'); } } else { - // 如果还有文档在处理中,确保 loading 状态保持 - console.log('还有文档在处理中,保持 loading 状态'); + // If documents are still processing, keep loading state + console.log('Documents still processing, maintaining loading state'); } }) .catch((error) => { - console.error('轮询文档状态失败:', error); + console.error('Failed to poll document status:', error); setPollingLoading(false); }); }; @@ -486,7 +486,7 @@ const CreateDataset = () => { }, }); } else { - console.warn('缺少路由参数,无法返回'); + console.warn('Missing route parameters, unable to return'); } }; const handleChange = (value: number | null) =>{ @@ -498,17 +498,17 @@ const CreateDataset = () => { const handleDeleteFile = async (fileId: string) => { try { await deleteDocument(fileId); - // 删除成功,从 rechunkFileIds 中移除该 id + // Delete successful, remove the id from rechunkFileIds setRechunkFileIds((prev) => prev.filter((id) => id !== fileId)); console.log(`${t('common.deleteSuccess')}`); } catch (error) { messageApi.error(`${t('common.deleteFailed')}`); } }; - // 当从其他页面跳转过来且带有 fileIds 时,加载对应的文档数据 + // When navigating from other pages with fileIds, load corresponding document data // useEffect(() => { // if (initialFileIds.length > 0 && initialStepKey !== 'selectFile' && knowledgeBaseId && parentId) { - // // 加载文档列表数据 + // // Load document list data // getDocumentList(knowledgeBaseId,{ // document_ids: initialFileIds.join(','), // }) @@ -517,12 +517,12 @@ const CreateDataset = () => { // setData(documents); // }) // .catch((error) => { - // console.error('加载文档列表失败:', error); + // console.error('Failed to load document list:', error); // }); // } // }, []); - // 清理函数:组件卸载时清除定时器和 loading 状态 + // Cleanup function: clear timer and loading state when component unmounts useEffect(() => { return () => { if (pollingTimerRef.current) { @@ -533,10 +533,10 @@ const CreateDataset = () => { }; }, []); - // 监听路由变化,确保在页面切换时清理状态 + // Watch for route changes, ensure state is cleaned up when page switches useEffect(() => { return () => { - // 页面卸载时清理状态 + // Clean up state when page unmounts if (pollingTimerRef.current) { clearInterval(pollingTimerRef.current); pollingTimerRef.current = null; @@ -574,7 +574,7 @@ const CreateDataset = () => { fileType={fileType} customRequest={handleUpload} onChange={(fileList) => { - console.log('文件列表变化:', fileList); + console.log('File list changed:', fileList); }} onRemove={async (file) => { // 如果文件正在上传,取消上传 @@ -583,26 +583,26 @@ const CreateDataset = () => { if (abortController) { abortController.abort(); abortControllersRef.current.delete(fileUid); - console.log('已取消上传:', (file as any).name); + console.log('Upload cancelled:', (file as any).name); // 取消上传后直接返回 true,允许移除文件 return true; } - // 只有当文件已经上传成功(有response.id)时,才删除服务器上的文件 + // Only delete server file when file upload was successful (has response.id) if (file.response?.id) { try { await deleteDocument(file.response.id); setRechunkFileIds(prev => prev.filter(id => id !== file.response.id)); - console.log('已删除服务器文件:', file.response.id); + console.log('Server file deleted:', file.response.id); return true; } catch (error) { - console.error('删除文件失败:', error); - messageApi.error(t('common.deleteFailed') || '删除文件失败'); - return false; // 删除失败时不移除文件 + console.error('Failed to delete file:', error); + messageApi.error(t('common.deleteFailed') || 'Failed to delete file'); + return false; // Don't remove file when deletion fails } } - // 其他情况(如上传失败的文件)也允许移除 + // Also allow removal in other cases (such as failed uploads) return true; }} /> )} diff --git a/web/src/views/KnowledgeBase/[knowledgeBaseId]/DocumentDetails.tsx b/web/src/views/KnowledgeBase/[knowledgeBaseId]/DocumentDetails.tsx index 2127bec4..ffe4a3e2 100644 --- a/web/src/views/KnowledgeBase/[knowledgeBaseId]/DocumentDetails.tsx +++ b/web/src/views/KnowledgeBase/[knowledgeBaseId]/DocumentDetails.tsx @@ -1,5 +1,5 @@ -/* - * @Description: 文档详情 +/** + * @Description: Document Details * @Version: 0.0.1 * @Author: yujiangping * @Date: 2025-11-15 16:13:47 @@ -57,28 +57,28 @@ const DocumentDetails: FC = () => { } }, [documentId]); - // 更新面包屑 + // Update breadcrumbs useEffect(() => { if (breadcrumbPath) { updateBreadcrumbs(breadcrumbPath); } }, [breadcrumbPath, updateBreadcrumbs]); - // 当文档加载完成且 progress === 1 时,加载分块列表 + // Load chunk list when document is loaded and progress === 1 useEffect(() => { if (document && document.progress === 1 && !isManualRefreshRef.current) { ChunkList(); } - // 重置标志 + // Reset flag isManualRefreshRef.current = false; }, [document]); - // 监听 keywords 变化,重新搜索 + // Listen to keywords changes and re-search useEffect(() => { if (documentId && keywords && document?.progress === 1) { - setPage(1); // 重置页码 - setChunkList([]); // 清空列表 - ChunkList(1, false); // 重新加载第一页 + setPage(1); // Reset page number + setChunkList([]); // Clear list + ChunkList(1, false); // Reload first page } }, [keywords]); @@ -129,9 +129,9 @@ const DocumentDetails: FC = () => { const url = `${imagePath}/api/files/${response.file_id}` setFileUrl(url); setParserMode(response?.parser_config?.auto_questions || 0) - // ChunkList 会在 useEffect 中根据 document.progress 自动调用 + // ChunkList will be called automatically in useEffect based on document.progress } catch (error) { - console.error('获取文档详情失败:', error); + console.error('Failed to fetch document details:', error); message.error(t('common.loadFailed') || '加载失败'); } finally { setLoading(false); @@ -140,12 +140,12 @@ const DocumentDetails: FC = () => { const ChunkList = async (pageNum: number = 1, append: boolean = false, force: boolean = false) => { if (!documentId) return; - // 如果不是强制刷新,且正在加载中,则跳过 + // Skip if not force refresh and already loading if (!force && chunkLoading) { return; } - // 只有当文档处理完成时才获取分块列表 + // Only fetch chunk list when document processing is complete if (document && document.progress !== 1) { return; } @@ -157,10 +157,10 @@ const DocumentDetails: FC = () => { keywords: keywords || undefined, page: pageNum, pagesize: 20, - _t: force ? Date.now() : undefined, // 强制刷新时添加时间戳破坏缓存 + _t: force ? Date.now() : undefined, // Add timestamp to break cache when force refresh }); - // 转换数据格式以匹配 RecallTestData + // Convert data format to match RecallTestData const formattedChunks: RecallTestData[] = response.items.map((item: any) => ({ page_content: item.page_content || item.content || '', vector: null, @@ -172,7 +172,7 @@ const DocumentDetails: FC = () => { document_id: item.metadata.document_id || documentId || '', knowledge_id: item.metadata.knowledge_id || knowledgeBaseId || '', sort_id: item.metadata.sort_id || item.id || 0, - score: item.metadata.score || null, // chunk 列表没有相似度分数 + score: item.metadata.score || null, // Chunk list has no similarity score status: item.metadata.status, }, children: null, @@ -186,7 +186,7 @@ const DocumentDetails: FC = () => { setHasMore(response.page?.has_next ?? false); } catch (error) { - console.error('获取文档详情失败:', error); + console.error('Failed to fetch document details:', error); message.error(t('common.loadFailed') || '加载失败'); } finally { setChunkLoading(false); @@ -201,17 +201,17 @@ const DocumentDetails: FC = () => { const handleBack = () => { if (knowledgeBaseId && breadcrumbPath) { - // 返回到知识库详情页,并传递面包屑信息以恢复状态 + // Return to knowledge base detail page and pass breadcrumb info to restore state const navigationState = { fromKnowledgeBaseList: true, knowledgeBaseFolderPath: breadcrumbPath.knowledgeBaseFolderPath, navigateToDocumentFolder: locationParentId, documentFolderPath: breadcrumbPath.documentFolderPath, - timestamp: Date.now(), // 添加时间戳确保状态变化 + timestamp: Date.now(), // Add timestamp to ensure state change }; navigate(`/knowledge-base/${knowledgeBaseId}/private`, { state: navigationState }); } else if (knowledgeBaseId) { - // 降级处理:直接跳转到知识库详情页 + // Fallback: Navigate directly to knowledge base detail page navigate(`/knowledge-base/${knowledgeBaseId}/private`); } }; @@ -226,61 +226,61 @@ const DocumentDetails: FC = () => { insertModalRef.current?.handleOpen(documentId); }; - // 处理插入/编辑内容 + // Handle insert/edit content const handleInsertContent = async (_docId: string, content: string, chunkId?: string): Promise => { try { if (chunkId) { - // 编辑模式:更新现有块 + // Edit mode: Update existing chunk const response = await updateDocumentChunk(knowledgeBaseId || '', documentId, chunkId, { content }); - // 直接更新前端列表,不等待后端缓存刷新 + // Update frontend list directly without waiting for backend cache refresh setChunkList(prev => prev.map(item => item.metadata?.doc_id === chunkId ? { ...item, page_content: response.page_content || content } : item )); - // 编辑模式返回特殊标记,告诉 InsertModal 不要调用 onSuccess + // Edit mode returns special flag to tell InsertModal not to call onSuccess return true; } else { - // 插入模式:创建新块 + // Insert mode: Create new chunk await createDocumentChunk(knowledgeBaseId || '', documentId, { content }); return true; } } catch (error) { - console.error('操作失败:', error); + console.error('Operation failed:', error); return false; } }; - // 处理点击文本块 + // Handle click on text chunk const handleChunkClick = (item: RecallTestData, index: number) => { if (!documentId) return; const chunkId = String(item.metadata?.doc_id || index); insertModalRef.current?.handleOpen(documentId, item.page_content, chunkId); }; - // 插入成功后的回调(仅用于插入新块,编辑操作已在 handleInsertContent 中同步更新) + // Callback after successful insert (only for inserting new chunks, edit operations are already updated synchronously in handleInsertContent) const handleInsertSuccess = () => { - // 设置手动刷新标志,防止 useEffect 重复调用 + // Set manual refresh flag to prevent useEffect from calling repeatedly isManualRefreshRef.current = true; - // 重置页码 + // Reset page number setPage(1); - // 等待后端处理完成,然后重新加载数据(仅用于插入新块的情况) + // Wait for backend processing to complete, then reload data (only for inserting new chunks) setTimeout(() => { ChunkList(1, false, true).then(() => { return fetchDocumentDetail(); }).catch(err => { - console.error('刷新失败:', err); + console.error('Refresh failed:', err); }); }, 1000); }; const handleAdjustmentParameter = () =>{ if (!knowledgeBaseId || !document) return; const targetFileId = document.id; - // 优先使用从 location 传递的 parentId,其次使用 document.parent_id,最后使用 knowledgeBaseId + // Prioritize parentId from location, then document.parent_id, finally knowledgeBaseId const parentId = locationParentId ?? document.parent_id ?? document.kb_id ?? knowledgeBaseId; navigate(`/knowledge-base/${knowledgeBaseId}/create-dataset`, { @@ -317,7 +317,7 @@ const DocumentDetails: FC = () => { exit {t('common.exit')} - {/* 文档预览 */} + {/* Document preview */} {fileUrl && (

@@ -339,7 +339,7 @@ const DocumentDetails: FC = () => { return (<>
- {/* 头部 */} + {/* Header */}
@@ -366,9 +366,9 @@ const DocumentDetails: FC = () => {
- {/* 内容区域 */} + {/* Content area */}
- {/* 左侧:文档信息 */} + {/* Left: Document info */}
{
- {/* 右侧:分块列表 */} + {/* Right: Chunk list */}
{
- {/* 插入内容弹窗 */} + {/* Insert content modal */} { const { t } = useTranslation(); @@ -73,9 +73,9 @@ const Private: FC = () => { const [isGraph, setIsGraph] = useState(false); const { updateBreadcrumbs } = useBreadcrumbManager({ breadcrumbType: 'detail', - // 不提供 onKnowledgeBaseMenuClick,让它使用默认的导航行为(返回列表页面) + // Don't provide onKnowledgeBaseMenuClick, let it use default navigation behavior (return to list page) onKnowledgeBaseFolderClick: useCallback((folderId: string, folderPath: Array<{ id: string; name: string }>) => { - // 点击文件夹面包屑时,导航到对应文件夹 + // Navigate to corresponding folder when clicking folder breadcrumb setParentId(folderId); setFolderPath(folderPath); setSelectedKeys([folderId]); @@ -84,7 +84,7 @@ const Private: FC = () => { parent_id: folderId }); - // 确保query对象发生变化,触发表格刷新 + // Ensure query object changes to trigger table refresh setQuery({ orderby: 'created_at', desc: true, @@ -92,10 +92,10 @@ const Private: FC = () => { _timestamp: Date.now() }); - // 确保API URL正确设置 + // Ensure API URL is set correctly setTableApi(`/documents/${knowledgeBaseId}/documents`); - // 手动触发表格刷新,确保数据更新 + // Manually trigger table refresh to ensure data update setTimeout(() => { tableRef.current?.loadData(); }, 100); @@ -108,7 +108,7 @@ const Private: FC = () => { setLoading(true); try { const res = await getKnowledgeBaseDetail(id); - // 将 KnowledgeBase 转换为 KnowledgeBaseListItem + // Convert KnowledgeBase to KnowledgeBaseListItem const listItem = res as unknown as KnowledgeBaseListItem; setKnowledgeBase(listItem); } finally { @@ -122,7 +122,7 @@ const Private: FC = () => { setTableApi(url); fetchKnowledgeBaseDetail(knowledgeBaseId); - // 立即设置基础面包屑,确保不会显示其他页面的面包屑 + // Immediately set base breadcrumbs to ensure other page breadcrumbs are not displayed updateBreadcrumbs({ knowledgeBaseFolderPath, knowledgeBase: { @@ -135,7 +135,7 @@ const Private: FC = () => { } }, [knowledgeBaseId]); - // 更新面包屑 + // Update breadcrumbs useEffect(() => { if (knowledgeBase) { updateBreadcrumbs({ @@ -150,22 +150,22 @@ const Private: FC = () => { } }, [knowledgeBase, knowledgeBaseFolderPath, folderPath, updateBreadcrumbs]); - // 监听 tableApi 变化,自动刷新表格数据 + // Listen to tableApi changes and auto refresh table data useEffect(() => { if (tableApi) { tableRef.current?.loadData(); } }, [tableApi]); - // 监听 query 变化,确保表格数据更新 + // Listen to query changes and ensure table data update useEffect(() => { if (tableApi && query._timestamp) { - // 当 query 中有 _timestamp 时,说明是通过面包屑或其他方式触发的更新 + // When query has _timestamp, it means the update is triggered by breadcrumb or other means tableRef.current?.loadData(); } }, [query._timestamp, tableApi]); - // 监听 location state 变化 + // Listen to location state changes useEffect(() => { const state = location.state as { refresh?: boolean; @@ -180,18 +180,18 @@ const Private: FC = () => { if (state?.refresh) { tableRef.current?.loadData(); - // 清除 state,避免重复刷新 + // Clear state to avoid repeated refresh navigate(location.pathname, { replace: true, state: {} }); } - // 如果是从知识库列表页跳转过来的,设置知识库文件夹路径 + // If navigated from knowledge base list page, set knowledge base folder path if (state?.fromKnowledgeBaseList && state?.knowledgeBaseFolderPath) { setKnowledgeBaseFolderPath(state.knowledgeBaseFolderPath); } - // 如果需要重置到根目录(回到初始状态) + // If need to reset to root directory (return to initial state) if (state?.resetToRoot) { - // 重置所有状态到初始状态,和页面初始化保持一致 + // Reset all states to initial state, consistent with page initialization setParentId(knowledgeBaseId); setFolderPath([]); setSelectedKeys([]); @@ -202,31 +202,31 @@ const Private: FC = () => { setQuery({ orderby: 'created_at', desc: true, - _timestamp: Date.now() // 添加时间戳确保query对象发生变化,触发API调用 + _timestamp: Date.now() // Add timestamp to ensure query object changes and trigger API call }); - // 重新设置API URL + // Reset API URL const rootUrl = `/documents/${knowledgeBaseId}/documents`; setTableApi(rootUrl); - // 清除自动展开路径 + // Clear auto expand path setAutoExpandPath([]); - // 刷新文件夹树 - 使用延迟确保状态重置完成后再刷新 + // Refresh folder tree - use delay to ensure state reset is complete before refresh setTimeout(() => { setFolderTreeRefreshKey((prev) => prev + 1); }, 100); - // 手动触发表格刷新,确保数据更新 + // Manually trigger table refresh to ensure data update setTimeout(() => { tableRef.current?.loadData(); }, 200); - // 清除 state,避免重复处理 + // Clear state to avoid repeated processing navigate(location.pathname, { replace: true, state: {} }); } - // 如果是从文档详情页返回,恢复文档文件夹路径 + // If returning from document details page, restore document folder path if (state?.navigateToDocumentFolder && state?.documentFolderPath) { setFolderPath(state.documentFolderPath); setParentId(state.navigateToDocumentFolder); @@ -242,25 +242,25 @@ const Private: FC = () => { setTableApi(`/documents/${knowledgeBaseId}/documents`); setSelectedKeys([state.navigateToDocumentFolder]); - // 设置自动展开路径,让FolderTree自动展开到对应位置 + // Set auto expand path to let FolderTree auto expand to corresponding position setAutoExpandPath(state.documentFolderPath); - // 手动触发表格刷新 + // Manually trigger table refresh setTimeout(() => { tableRef.current?.loadData(); }, 100); - // 清除自动展开路径,避免重复触发(延迟清除,确保FolderTree处理完成) + // Clear auto expand path to avoid repeated trigger (delayed clear to ensure FolderTree processing is complete) setTimeout(() => { setAutoExpandPath([]); }, 2000); } }, [location.state, knowledgeBaseId, navigate, location.pathname]); - // 处理树节点选择 + // Handle tree node selection const onSelect = (keys: React.Key[]) => { if (!keys.length) { - // 如果没有选中任何节点,回到根目录(初始状态) + // If no node is selected, return to root directory (initial state) setParentId(knowledgeBaseId); setFolder({ kb_id: knowledgeBaseId ?? '', @@ -269,7 +269,7 @@ const Private: FC = () => { setQuery({ orderby: 'created_at', desc: true, - _timestamp: Date.now() // 添加时间戳确保query对象发生变化 + _timestamp: Date.now() // Add timestamp to ensure query object changes }); setSelectedKeys([]); return; @@ -284,7 +284,7 @@ const Private: FC = () => { setQuery({ ...query, parent_id: String(keys[0]), - _timestamp: Date.now() // 添加时间戳确保query对象发生变化 + _timestamp: Date.now() // Add timestamp to ensure query object changes }) let url = `/documents/${knowledgeBaseId}/documents`; @@ -294,14 +294,14 @@ const Private: FC = () => { setSelectedKeys(keys) }; - // 处理文件夹路径变化 + // Handle folder path change const handleFolderPathChange = (path: Array<{ id: string; name: string }>) => { setFolderPath(path); }; - // 处理树节点展开 + // Handle tree node expand const onExpand = (_expandedKeys: React.Key[], _info: any) => { - // 展开节点时不需要特殊处理 + // No special handling needed when expanding nodes }; // create / import list const createItems: MenuProps['items'] = [ @@ -344,13 +344,13 @@ const Private: FC = () => { // createImageDataset?.current?.handleOpen(knowledgeBaseId || '', parentId || '') // }, // }, - // 暂时未实现 + // Not implemented yet // { // key: '4', // icon: blank, // label: t('knowledgeBase.blankDataset'), // onClick: () => { - // handleCreate('folder'); // 传入 type: 'folder' + // handleCreate('folder'); // Pass type: 'folder' // }, // }, // { @@ -362,7 +362,7 @@ const Private: FC = () => { // icon: import, // label: t('knowledgeBase.importTemplate'), // onClick: () => { - // handleCreate('folder'); // 传入 type: 'folder' + // handleCreate('folder'); // Pass type: 'folder' // }, // }, // { @@ -370,17 +370,17 @@ const Private: FC = () => { // icon: import, // label: t('knowledgeBase.importBackup'), // onClick: () => { - // handleCreate('folder'); // 传入 type: 'folder' + // handleCreate('folder'); // Pass type: 'folder' // }, // }, ]; - // 处理开关 + // Handle switch const onChange = (checked: boolean) => { if (!knowledgeBase) return; - // 构造完整的更新数据,保留现有配置 + // Construct complete update data, keeping existing configuration const updateData: KnowledgeBaseFormData = { name: knowledgeBase.name, description: knowledgeBase.description, @@ -411,30 +411,30 @@ const Private: FC = () => { updateKnowledgeBase(knowledgeBaseId || '', updateData); console.log(`switch to ${checked}`); }; - // 处理搜索 + // Handle search const handleSearch = (value?: string) => { setQuery({ ...query, keywords: value }) } - // 处理分享 + // Handle share const handleShare = () => { shareModalRef?.current?.handleOpen(knowledgeBaseId,knowledgeBase); } - // 处理分享回调,接收选中的数据 + // Handle share callback, receive selected data const handleShareCallback = (selectedData: { checkedItems: any[], selectedItem: any | null }) => { - console.log('选中的数据:', selectedData); - // checkedItems: 所有 checked 为 true 的数据 - // selectedItem: 当前选中的项(curIndex 对应的数据) - // 在这里处理分享逻辑 + console.log('Selected data:', selectedData); + // checkedItems: All data with checked = true + // selectedItem: Currently selected item (corresponding to curIndex) + // Handle share logic here } const handleCreateDatasetCallback = (payload: { value: number; title: string; description: string }) => { - console.log('创建数据集:', payload); + console.log('Create dataset:', payload); } - // 处理设置 + // Handle settings const handleSetting = () => { modalRef?.current?.handleOpen(knowledgeBase, ''); } - // 处理召回测试 + // Handle recall test const handleRecallTest = () => { recallTestDrawerRef?.current?.handleOpen(knowledgeBaseId); } @@ -443,7 +443,7 @@ const Private: FC = () => { const handelCreateOrImport = () => { } - // 生成下拉菜单项(根据当前 row) + // Generate dropdown menu items (based on current row) const getOptMenuItems = (row: KnowledgeBaseListItem): MenuProps['items'] => [ { key: '1', @@ -495,19 +495,19 @@ const Private: FC = () => { deleteDocument(item.id) .then(() => { messageApi.success(t('common.deleteSuccess')); - // 刷新表格数据 + // Refresh table data tableRef.current?.loadData(); }) .catch((err: any) => { - console.log('删除失败', err); + console.log('Delete failed', err); }); }, onCancel: () => { - console.log('取消删除'); + console.log('Cancel delete'); }, }); } - // 表格列配置 + // Table column configuration const columns: ColumnsType = [ { title: t('knowledgeBase.name'), @@ -524,7 +524,7 @@ const Private: FC = () => { state: { documentId: document.id, parentId: parentId ?? knowledgeBaseId, - // 传递面包屑信息 + // Pass breadcrumb information breadcrumbPath: { knowledgeBaseFolderPath, knowledgeBase: { @@ -572,7 +572,7 @@ const Private: FC = () => { render: (value: string) => { if (!value) return '-'; - // 解析日志格式,将 \n 转换为换行 + // Parse log format, convert \n to newline const formattedText = value.replace(/\\n/g, '\n'); return ( @@ -634,25 +634,25 @@ const Private: FC = () => { ), }, ]; - // 刷新列表数据 + // Refresh list data if (loading) { - return
加载中...
; + return
Loading...
; } if (!knowledgeBase) { return
知识库不存在
; } const refreshDirectoryTree = async () => { - // 先刷新知识库详情,确保数据是最新的 + // First refresh knowledge base details to ensure data is up-to-date if (knowledgeBase?.id) { await fetchKnowledgeBaseDetail(knowledgeBase.id); } - // 添加短暂延迟,确保后端数据已经完全更新 + // Add short delay to ensure backend data is fully updated await new Promise(resolve => setTimeout(resolve, 300)); - // 然后刷新文件夹树 + // Then refresh folder tree setFolderTreeRefreshKey((prev) => prev + 1); - // 确保 folder 状态正确设置 + // Ensure folder state is set correctly if (!folder) { setFolder({ kb_id: knowledgeBaseId ?? '', @@ -663,10 +663,10 @@ const Private: FC = () => { } const handleRootTreeLoad = (nodes: TreeNodeData[] | null) => { if (!nodes || nodes.length === 0) { - // 如果没有节点,设置folder为null(这会隐藏FolderTree) + // If no nodes, set folder to null (this will hide FolderTree) setFolder(null); } else { - // 如果有节点且 folder 为 null,重新设置 folder + // If there are nodes and folder is null, reset folder if (!folder) { setFolder({ kb_id: knowledgeBaseId ?? '', @@ -687,7 +687,7 @@ const Private: FC = () => { } const handleRefreshTable = () => { - // 刷新表格数据 + // Refresh table data fetchKnowledgeBaseDetail(knowledgeBase.id) tableRef.current?.loadData(); } diff --git a/web/src/views/KnowledgeBase/[knowledgeBaseId]/Share.tsx b/web/src/views/KnowledgeBase/[knowledgeBaseId]/Share.tsx index aa4baf0b..e9aa0aa9 100644 --- a/web/src/views/KnowledgeBase/[knowledgeBaseId]/Share.tsx +++ b/web/src/views/KnowledgeBase/[knowledgeBaseId]/Share.tsx @@ -38,7 +38,7 @@ const Share: FC = () => { if (knowledgeBaseId) { fetchKnowledgeBaseDetail(knowledgeBaseId); - // 打开召回测试组件 + // Open recall test component setTimeout(() => { console.log('Share.tsx - calling handleOpen with:', knowledgeBaseId); recallTestRef.current?.handleOpen(knowledgeBaseId); @@ -48,7 +48,7 @@ const Share: FC = () => { } }, [knowledgeBaseId]); - // 更新面包屑 + // Update breadcrumbs useEffect(() => { if (knowledgeBase) { updateBreadcrumbs({ @@ -63,14 +63,14 @@ const Share: FC = () => { } }, [knowledgeBase, knowledgeBaseFolderPath, updateBreadcrumbs]); - // 监听 location state 变化 + // Listen to location state changes useEffect(() => { const state = location.state as { fromKnowledgeBaseList?: boolean; knowledgeBaseFolderPath?: BreadcrumbItem[]; } | null; - // 如果是从知识库列表页跳转过来的,设置知识库文件夹路径 + // If navigated from knowledge base list page, set knowledge base folder path if (state?.fromKnowledgeBaseList && state?.knowledgeBaseFolderPath) { setKnowledgeBaseFolderPath(state.knowledgeBaseFolderPath); } diff --git a/web/src/views/KnowledgeBase/components/CreateContentModal.tsx b/web/src/views/KnowledgeBase/components/CreateContentModal.tsx index 63292dec..0849f593 100644 --- a/web/src/views/KnowledgeBase/components/CreateContentModal.tsx +++ b/web/src/views/KnowledgeBase/components/CreateContentModal.tsx @@ -41,7 +41,7 @@ const CreateContentModal = forwardRef const values = await form.validateFields(); setLoading(true); - // TODO: 这里需要调用相应的API来保存内容 + // TODO: Call appropriate API to save content const params = { // ...values, kb_id: kbId, @@ -55,7 +55,7 @@ const CreateContentModal = forwardRef } handleClose(); } catch (err) { - console.error('创建内容失败:', err); + console.error('Failed to create content:', err); } finally { setLoading(false); } diff --git a/web/src/views/KnowledgeBase/components/CreateContentModalExample.tsx b/web/src/views/KnowledgeBase/components/CreateContentModalExample.tsx index 7434e559..e93ad63d 100644 --- a/web/src/views/KnowledgeBase/components/CreateContentModalExample.tsx +++ b/web/src/views/KnowledgeBase/components/CreateContentModalExample.tsx @@ -3,18 +3,18 @@ import { Button } from 'antd'; import CreateContentModal from './CreateContentModal'; import type { CreateContentModalRef } from '../types'; -// 使用示例组件 +// Example usage component const CreateContentModalExample = () => { const createContentModalRef = useRef(null); const handleOpenModal = () => { - // 打开弹窗,传入知识库ID和父级ID + // Open modal, pass knowledge base ID and parent ID createContentModalRef.current?.handleOpen('kb_123', 'parent_456'); }; const handleRefreshTable = () => { - console.log('刷新表格数据'); - // 这里可以添加刷新表格的逻辑 + console.log('Refresh table data'); + // Add table refresh logic here }; return ( diff --git a/web/src/views/KnowledgeBase/components/CreateDatasetModal.tsx b/web/src/views/KnowledgeBase/components/CreateDatasetModal.tsx index 37e41375..d9e265e4 100644 --- a/web/src/views/KnowledgeBase/components/CreateDatasetModal.tsx +++ b/web/src/views/KnowledgeBase/components/CreateDatasetModal.tsx @@ -1,5 +1,5 @@ -/* - * @Description: +/** + * @Description: Create Dataset Modal * @Version: 0.0.1 * @Author: yujiangping * @Date: 2025-11-10 18:52:55 diff --git a/web/src/views/KnowledgeBase/components/CreateFolderModal.tsx b/web/src/views/KnowledgeBase/components/CreateFolderModal.tsx index 578288d9..044f47ee 100644 --- a/web/src/views/KnowledgeBase/components/CreateFolderModal.tsx +++ b/web/src/views/KnowledgeBase/components/CreateFolderModal.tsx @@ -13,7 +13,7 @@ const CreateFolderModal = forwardRef(); const [loading, setLoading] = useState(false) - // 封装取消方法,添加关闭弹窗逻辑 + // Close modal and reset state const handleClose = () => { setFolder({} as FolderFormData); form.resetFields(); @@ -22,17 +22,16 @@ const CreateFolderModal = forwardRef { - debugger if (folder) { setFolder(folder); - // 设置表单值 + // Set form values form.setFieldsValue({ folder_name: folder.folder_name, parent_id: folder.parent_id ?? '', kb_id: folder.kb_id ?? '', }); } else { - // 新建时,重置表单并设置默认值 + // Reset form and set default values for new folder form.resetFields(); form.setFieldsValue({ parent_id: '', @@ -41,7 +40,7 @@ const CreateFolderModal = forwardRef { form .validateFields({ validateOnly: true }) @@ -74,13 +73,13 @@ const CreateFolderModal = forwardRef ({ handleOpen, handleClose })); - // 根据 type 获取标题 + // Get modal title based on folder state const getTitle = () => { if (folder.id) { return t('common.edit') + ' ' + (folder.folder_name || ''); diff --git a/web/src/views/KnowledgeBase/components/CreateImageDataset.tsx b/web/src/views/KnowledgeBase/components/CreateImageDataset.tsx index 83f7020c..e6b9b386 100644 --- a/web/src/views/KnowledgeBase/components/CreateImageDataset.tsx +++ b/web/src/views/KnowledgeBase/components/CreateImageDataset.tsx @@ -28,12 +28,12 @@ const CreateImageDataset = forwardRef const [parentId, setParentId] = useState(''); const [hasFiles, setHasFiles] = useState(false); const uploadRef = useRef<{ fileList: UploadFile[]; clearFiles: () => void }>(null); - // 存储每个文件的 AbortController,用于取消上传 + // Store AbortController for each file to cancel upload const abortControllersRef = useRef>(new Map()); // const fileIds = []; const handleClose = () => { - // 取消所有正在进行的上传 + // Cancel all ongoing uploads abortControllersRef.current.forEach((controller) => { controller.abort(); }); @@ -69,7 +69,7 @@ const CreateImageDataset = forwardRef } const ids = fileList.map((file) => file.response?.id); handleChunking(kbId, parentId, ids) - // // 上传所有图片 + // // Upload all images // const uploadPromises = fileList.map(async (file) => { // if (file.originFileObj) { // const formData = new FormData(); @@ -91,7 +91,7 @@ const CreateImageDataset = forwardRef handleClose(); } catch (err) { - console.error('创建图片数据集失败:', err); + console.error('Failed to create image dataset:', err); } finally { setLoading(false); } @@ -112,7 +112,7 @@ const CreateImageDataset = forwardRef useImperativeHandle(ref, () => ({ handleOpen, })); - // 检查媒体文件时长的辅助函数 + // Helper function to check media file duration const checkMediaDuration = (file: File): Promise => { return new Promise((resolve, reject) => { const url = URL.createObjectURL(file); @@ -131,7 +131,7 @@ const CreateImageDataset = forwardRef media.src = url; }); }; - // 删除已上传的文件 + // Delete uploaded file const handleDeleteFile = async (fileId: string) => { try { await deleteDocument(fileId); @@ -141,24 +141,24 @@ const CreateImageDataset = forwardRef } }; - // 上传文件 + // Upload file const handleUpload = async (options: UploadRequestOption) => { const { file, onSuccess, onError, onProgress, filename = 'file' } = options; - // 创建 AbortController 用于取消上传 + // Create AbortController to cancel upload const abortController = new AbortController(); const fileUid = (file as any).uid; abortControllersRef.current.set(fileUid, abortController); - // 获取文件扩展名 + // Get file extension const fileExtension = (file as File).name.split('.').pop()?.toLowerCase(); const mediaExtensions = ['mp3', 'mp4', 'mov', 'wav']; - // 如果是媒体文件,进行大小和时长检查 + // If it's a media file, check size and duration if (fileExtension && mediaExtensions.includes(fileExtension)) { const fileSizeInMB = (file as File).size / (50 * 1024); - // 检查文件大小(50MB限制) + // Check file size (50MB limit) if (fileSizeInMB > 50) { messageApi.error(`${t('knowledgeBase.sizeLimitError')}:${fileSizeInMB.toFixed(2)}MB`); onError?.(new Error(`${t('knowledgeBase.fileSizeExceeds')}`)); @@ -167,7 +167,7 @@ const CreateImageDataset = forwardRef } try { - // 检查媒体时长(150秒限制) + // Check media duration (150 seconds limit) const duration = await checkMediaDuration(file as File); if (duration > 150) { messageApi.error(`${t('knowledgeBase.fileDurationLimitError')}:${Math.round(duration)}秒`); @@ -204,21 +204,21 @@ const CreateImageDataset = forwardRef }, }); - // 上传成功,移除 AbortController + // Upload successful, remove AbortController abortControllersRef.current.delete(fileUid); onSuccess?.(res, new XMLHttpRequest()); if (res?.id) { - // 上传成功 + // Upload successful // fileIds.push(res.id) } } catch (error: any) { - // 移除 AbortController + // Remove AbortController abortControllersRef.current.delete(fileUid); - // 如果是用户主动取消,不显示错误信息 + // If user actively cancelled, don't show error message if (error.name === 'AbortError' || error.code === 'ERR_CANCELED') { - console.log('上传已取消:', (file as File).name); + console.log('Upload cancelled:', (file as File).name); return; } @@ -259,11 +259,11 @@ const CreateImageDataset = forwardRef fileType={['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'mp3', 'mp4', 'mov', 'wav']} customRequest={handleUpload} onChange={(fileList) => { - // 实时更新文件状态 + // Update file status in real-time setHasFiles(fileList.length > 0); }} onRemove={async (file) => { - // 如果文件正在上传,取消上传 + // If file is uploading, cancel upload const fileUid = file.uid; const abortController = abortControllersRef.current.get(fileUid); if (abortController) { @@ -271,12 +271,12 @@ const CreateImageDataset = forwardRef abortControllersRef.current.delete(fileUid); } - // 如果文件已经上传成功,删除服务器上的文件 + // If file is already uploaded successfully, delete file on server if (file.response?.id) { await handleDeleteFile(file.response.id); } - return true; // 允许移除文件 + return true; // Allow file removal }} /> diff --git a/web/src/views/KnowledgeBase/components/CreateModal.tsx b/web/src/views/KnowledgeBase/components/CreateModal.tsx index f0a0b50c..6d709a1b 100644 --- a/web/src/views/KnowledgeBase/components/CreateModal.tsx +++ b/web/src/views/KnowledgeBase/components/CreateModal.tsx @@ -15,7 +15,7 @@ import RbModal from '@/components/RbModal' const { TextArea } = Input; const { confirm } = Modal -// 全局模型数据常量 +// Global model data constant let models: any = null; const CreateModal = forwardRef(({ @@ -33,9 +33,9 @@ const CreateModal = forwardRef(({ const [activeTab, setActiveTab] = useState('basic'); const [generatingEntityTypes, setGeneratingEntityTypes] = useState(false); const [isRebuildMode, setIsRebuildMode] = useState(false); - const [originalType, setOriginalType] = useState(''); // 保存原始的 type 参数 + const [originalType, setOriginalType] = useState(''); // Save original type parameter - // 监听 parser_config.graphrag 相关字段的变化 + // Watch for changes to parser_config.graphrag related fields const parserConfig = Form.useWatch('parser_config', form); const graphragConfig = parserConfig?.graphrag; const enableKnowledgeGraph = graphragConfig?.use_graphrag || false; @@ -43,30 +43,30 @@ const CreateModal = forwardRef(({ const entityNormalization = graphragConfig?.resolution || false; const communityReportGeneration = graphragConfig?.community || false; - // 封装取消方法,添加关闭弹窗逻辑 + // Encapsulate cancel method, add close modal logic const handleClose = () => { setDatasets(null); form.resetFields(); setLoading(false); setActiveTab('basic'); - setIsRebuildMode(false); // 重置重建模式标识 - setOriginalType(''); // 重置原始 type + setIsRebuildMode(false); // Reset rebuild mode flag + setOriginalType(''); // Reset original type setVisible(false); }; - // 生成实体类型的函数 + // Generate entity types function const generateEntityTypes = async () => { const sceneName = form.getFieldValue(['parser_config', 'graphrag', 'scene_name']); if (!sceneName) { - // 可以添加提示用户输入场景名称 + // Can add prompt for user to enter scenario name messageApi.error(t('knowledgeBase.enterScenarioName')); return; } - // 检查是否选择了 LLM 模型 + // Check if LLM model is selected const llmId = form.getFieldValue('llm_id'); if (!llmId) { - // 跳转到基础配置页 + // Navigate to basic configuration page setActiveTab('basic'); messageApi.error(t('knowledgeBase.pleaseSelectLLMModel')); return; @@ -74,7 +74,7 @@ const CreateModal = forwardRef(({ setGeneratingEntityTypes(true); try { - // 这里应该调用实际的API接口 + // Call the actual API interface here // const user = JSON.parse(localStorage.getItem('user') as any); //datasets?.id || datasets?.parent_id || user?.current_workspace_id, const params = { @@ -82,17 +82,17 @@ const CreateModal = forwardRef(({ llm_id: llmId }; const response = await getKnowledgeGraphEntityTypes(params); - // 模拟API调用 + // Simulate API call // await new Promise(resolve => setTimeout(resolve, 1000)); - // 处理API响应数据 - console.log('API Response:', response); // 调试日志 + // Process API response data + console.log('API Response:', response); // Debug log - // 检查响应结构 - API直接返回字符串 + // Check response structure - API returns string directly if (response && typeof response === 'string' && response.trim()) { - // 将逗号分隔的字符串转换为换行分隔的格式以便在TextArea中显示 + // Convert comma-separated string to newline-separated format for TextArea display const entityTypesString = response.replace(/,\s*/g, '\n'); - console.log('Converted entity types:', entityTypesString); // 调试日志 + console.log('Converted entity types:', entityTypesString); // Debug log const currentGraphrag = form.getFieldValue(['parser_config', 'graphrag']) || {}; const updatedGraphrag = { @@ -100,22 +100,22 @@ const CreateModal = forwardRef(({ entity_types: entityTypesString }; - console.log('Updating form with:', updatedGraphrag); // 调试日志 + console.log('Updating form with:', updatedGraphrag); // Debug log - // 使用更直接的方式更新表单字段 + // Use more direct way to update form field form.setFieldValue(['parser_config', 'graphrag', 'entity_types'], entityTypesString); - // 强制触发表单重新渲染 + // Force trigger form re-render form.validateFields([['parser_config', 'graphrag', 'entity_types']]); - // 额外的强制更新机制 + // Additional forced update mechanism setTimeout(() => { form.setFieldValue(['parser_config', 'graphrag', 'entity_types'], entityTypesString); }, 100); messageApi.success(t('knowledgeBase.generateEntityTypesSuccess')); } else { - messageApi.error(t('knowledgeBase.generateEntityTypesFailed') + ':' + t('knowledgeBase.unknownError')); + messageApi.error(t('knowledgeBase.generateEntityTypesFailed') + ': ' + t('knowledgeBase.unknownError')); } } catch (error) { console.error(t('knowledgeBase.generateEntityTypesFailed') + ':', error); @@ -143,7 +143,7 @@ const CreateModal = forwardRef(({ }; const fetchModelLists = async (types: string[]) => { - // 如果还没有获取过全部模型数据,则获取一次 + // If model data hasn't been fetched yet, fetch it once if (!models) { try { models = await getModelList({ page: 1, pagesize: 100 }); @@ -153,7 +153,7 @@ const CreateModal = forwardRef(({ } } - // 从全部模型数据中过滤出需要的类型 + // Filter out the required types from all model data const typesToFetch = types.includes('llm') ? [...types, 'chat'] : types; const next: Record = {}; @@ -165,7 +165,7 @@ const CreateModal = forwardRef(({ setModelOptionsByType(next); - // 如果不是编辑模式,为每个类型的下拉框设置默认值为第一条数据 + // If not in edit mode, set default value to first item for each type dropdown if (!datasets?.id) { const defaultValues: Record = {}; types.forEach((tp) => { @@ -174,7 +174,7 @@ const CreateModal = forwardRef(({ ? [...(next['llm'] || []), ...(next['chat'] || [])] : next[tp] || []; - // 如果有选项且当前字段没有值,设置第一个选项为默认值 + // If there are options and current field has no value, set first option as default if (options.length > 0 && !form.getFieldValue(fieldKey)) { defaultValues[fieldKey] = options[0].value; } @@ -204,7 +204,7 @@ const CreateModal = forwardRef(({ status: record.status, }; - // 处理 parser_config 配置数据,如果没有则设置默认值 + // Process parser_config data, set default values if not present baseValues.parser_config = record.parser_config || { graphrag: { use_graphrag: false, @@ -216,13 +216,13 @@ const CreateModal = forwardRef(({ } }; - // 如果存在 entity_types,转换为换行分隔格式用于 TextArea 显示 + // If entity_types exists, convert to newline-separated format for TextArea display if (baseValues.parser_config.graphrag.entity_types) { if (Array.isArray(baseValues.parser_config.graphrag.entity_types)) { - // 如果是数组格式,转换为换行分隔字符串 + // If array format, convert to newline-separated string (baseValues.parser_config.graphrag as any).entity_types = baseValues.parser_config.graphrag.entity_types.join('\n'); } else if (typeof baseValues.parser_config.graphrag.entity_types === 'string') { - // 如果是逗号分隔字符串格式,转换为换行分隔字符串(兼容旧数据) + // If comma-separated string format, convert to newline-separated string (compatible with old data) (baseValues.parser_config.graphrag as any).entity_types = (baseValues.parser_config.graphrag.entity_types as string).replace(/,\s*/g, '\n'); } } @@ -249,13 +249,13 @@ const CreateModal = forwardRef(({ const handleOpen = (record?: KnowledgeBaseListItem | null, type?: string) => { setDatasets(record || null); - // 如果是重建模式,使用记录的实际类型,否则使用传入的类型 + // If rebuild mode, use record's actual type, otherwise use passed type const actualType = type === 'rebuild' ? (record?.type || 'General') : (type || currentType); setCurrentType(actualType as any); - setIsRebuildMode(type === 'rebuild'); // 设置重建模式标识 - setOriginalType(type || ''); // 保存原始的 type 参数 + setIsRebuildMode(type === 'rebuild'); // Set rebuild mode flag + setOriginalType(type || ''); // Save original type parameter - // 如果是重建模式,默认切换到知识图谱标签页 + // If rebuild mode, default to knowledge graph tab if (type === 'rebuild') { setActiveTab('knowledgeGraph'); } else { @@ -285,13 +285,13 @@ const CreateModal = forwardRef(({ setDynamicModelFields(datasets, modelTypeList); }, [visible, datasets, currentType, modelTypeList]); - // 封装保存方法,添加提交逻辑 + // Encapsulate save method, add submit logic const handleSave = () => { - // 获取当前表单中的知识图谱开启状态 + // Get current knowledge graph enabled status from form const currentFormValues = form.getFieldsValue(); const isGraphragEnabled = currentFormValues?.parser_config?.graphrag?.use_graphrag || false; - // 如果原始 type 是 'rebuild' 并且知识图谱开启为true,显示确认弹框 + // If original type is 'rebuild' and knowledge graph is enabled, show confirmation dialog if (originalType === 'rebuild' && isGraphragEnabled) { confirm({ title: t('knowledgeBase.rebuildConfirmTitle'), @@ -302,11 +302,11 @@ const CreateModal = forwardRef(({ await rebuildKnowledgeGraph(datasets?.id || '') }, onCancel: () => { - // 用户取消,不执行任何操作 + // User cancelled, no action taken }, }); } else { - // 非重建模式或知识图谱未开启,直接保存 + // Non-rebuild mode or knowledge graph not enabled, save directly performSave(); } }; @@ -318,7 +318,7 @@ const CreateModal = forwardRef(({ messageApi.error(t('knowledgeBase.deleteGraphFailed')) } }; - // 实际的保存逻辑 + // Actual save logic const performSave = () => { form .validateFields() @@ -326,7 +326,7 @@ const CreateModal = forwardRef(({ setLoading(true) const formValues = form.getFieldsValue(); - // 处理 entity_types 格式转换:从换行分隔字符串转换为字符串数组 + // Process entity_types format conversion: from newline-separated string to string array if (formValues.parser_config && formValues.parser_config.graphrag && formValues.parser_config.graphrag.entity_types) { const entityTypesString = formValues.parser_config.graphrag.entity_types as any as string; const entityTypesArray = entityTypesString @@ -336,7 +336,7 @@ const CreateModal = forwardRef(({ formValues.parser_config.graphrag.entity_types = entityTypesArray; } - // 确保保存时使用正确的类型(不是 'rebuild') + // Ensure correct type is used when saving (not 'rebuild') const saveType = originalType === 'rebuild' ? currentType : (formValues.type || currentType); const payload: KnowledgeBaseFormData = { @@ -346,7 +346,7 @@ const CreateModal = forwardRef(({ parent_id: datasets?.parent_id || undefined, }; - console.log('Saving payload:', payload); // 调试日志 + console.log('Saving payload:', payload); // Debug log const submit = datasets?.id ? updateKnowledgeBase(datasets.id, payload) @@ -367,32 +367,32 @@ const CreateModal = forwardRef(({ }); } const handleChange = (_value: string, tp: string) => { - // 只在编辑模式且类型为 embedding 时触发提示 + // Only trigger prompt in edit mode and when type is embedding if (datasets?.id && tp.toLowerCase() === 'embedding') { const fieldKey = typeToFieldKey(tp); - // 从原始 datasets 对象中获取之前的值 + // Get previous value from original datasets object const previousValue = (datasets as any)[fieldKey]; confirm({ title: t('common.updateWarning'), content: t('knowledgeBase.updateEmbeddingContent'), onOk: () => { - // 确定时什么也不做,保持新值 + // Do nothing on confirm, keep new value }, onCancel: () => { - // 取消时恢复之前的值 + // Restore previous value on cancel form.setFieldsValue({ [fieldKey]: previousValue } as any); }, }); } } - // 暴露给父组件的方法 + // Methods exposed to parent component useImperativeHandle(ref, () => ({ handleOpen, handleClose })); - // 根据 type 获取标题 + // Get title based on type const getTitle = () => { if (isRebuildMode) { return t('knowledgeBase.rebuildGraph') + ' - ' + (datasets?.name || ''); @@ -408,7 +408,7 @@ const CreateModal = forwardRef(({ const dynamicTypeList = useMemo(() => modelTypeList.filter((tp) => (modelOptionsByType[tp] || []).length), [modelTypeList, modelOptionsByType]); - // 基础配置表单内容 + // Basic configuration form content const renderBasicConfig = () => ( <> {!datasets?.id && ( @@ -426,7 +426,7 @@ const CreateModal = forwardRef(({ {currentType !== 'Folder' && dynamicTypeList.map((tp) => { const fieldKey = typeToFieldKey(tp); - // 当 tp 为 'llm' 时,合并 llm 和 chat 的选项 + // When tp is 'llm', merge llm and chat options const options = tp.toLowerCase() === 'llm' ? [...(modelOptionsByType['llm'] || []), ...(modelOptionsByType['chat'] || [])] : modelOptionsByType[tp] || []; @@ -451,7 +451,7 @@ const CreateModal = forwardRef(({ ); - // 知识图谱配置表单内容 + // Knowledge graph configuration form content const renderKnowledgeGraphConfig = () => ( <>
(({
{t('knowledgeBase.graphConfig')}
- {/* 场景名称 */} + {/* Scene name */}
(({
- {/* 实体类型 */} + {/* Entity types */} (({ /> - {/* 实体归一化 */} + {/* Entity normalization */}
(({
- {/* 实体方法 */} + {/* Entity method */} (({ - {/* 社区报告生成 */} + {/* Community report generation */}
(({ ); - // Tabs 配置 + // Tabs configuration const tabItems = [ { key: 'basic', @@ -607,16 +607,16 @@ const CreateModal = forwardRef(({ form={form} layout="vertical" initialValues={{ - permission_id: 'Private', // 设置 permission_id 的默认值 + permission_id: 'Private', // Set default value for permission_id type: currentType, parser_config: { graphrag: { - use_graphrag: false, // 默认不启用知识图谱 - scene_name: '', // 场景名称 - entity_types: '' as any, // 实体类型(界面上显示为字符串,保存时转为数组) - method: 'general', // 默认使用通用方法 - resolution: false, // 默认不启用实体归一化 - community: false, // 默认不生成社区报告 + use_graphrag: false, // Default not to enable knowledge graph + scene_name: '', // Scene name + entity_types: '' as any, // Entity types (displayed as string in UI, converted to array when saving) + method: 'general', // Default to use general method + resolution: false, // Default not to enable entity normalization + community: false, // Default not to generate community reports } } }} diff --git a/web/src/views/KnowledgeBase/components/DelimiterSelector.tsx b/web/src/views/KnowledgeBase/components/DelimiterSelector.tsx index ea05bdbb..24cd79ee 100644 --- a/web/src/views/KnowledgeBase/components/DelimiterSelector.tsx +++ b/web/src/views/KnowledgeBase/components/DelimiterSelector.tsx @@ -17,13 +17,13 @@ const DelimiterSelector: FC = ({ className = '', }) => { const { t } = useTranslation(); - // 默认值为空字符串(不设置) + // Default value is empty string (not set) const [selectedValue, setSelectedValue] = useState(value || ''); const [customValue, setCustomValue] = useState(''); const [showCustomInput, setShowCustomInput] = useState(false); useEffect(() => { - // 检查当前值是否为自定义值 + // Check if current value is a custom delimiter if (value && isCustomDelimiter(value) && value !== 'custom') { setSelectedValue('custom'); setCustomValue(value); @@ -39,15 +39,15 @@ const DelimiterSelector: FC = ({ if (val === 'custom') { setShowCustomInput(true); - // 如果已有自定义值,使用它;否则等待用户输入 + // If custom value exists, use it; otherwise wait for user input if (customValue) { onChange?.(customValue); } else { - // 自定义但还没输入值,暂不触发 onChange + // Custom selected but no value entered yet, don't trigger onChange onChange?.(undefined); } } else if (val === '') { - // 选择"不设置"时,返回 undefined(不传递该参数) + // When "Not set" is selected, return undefined (don't pass this parameter) setShowCustomInput(false); onChange?.(undefined); } else { @@ -59,7 +59,7 @@ const DelimiterSelector: FC = ({ const handleCustomInputChange = (e: React.ChangeEvent) => { const val = e.target.value; setCustomValue(val); - // 只有当输入不为空时才触发 onChange + // Only trigger onChange when input is not empty onChange?.(val || undefined); }; diff --git a/web/src/views/KnowledgeBase/components/FolderTree.tsx b/web/src/views/KnowledgeBase/components/FolderTree.tsx index 8455f8b9..86e1d172 100644 --- a/web/src/views/KnowledgeBase/components/FolderTree.tsx +++ b/web/src/views/KnowledgeBase/components/FolderTree.tsx @@ -60,7 +60,7 @@ interface FolderTreeProps { onRootLoad?: (nodes: TreeNodeData[] | null) => void; onFolderPathChange?: (path: Array<{ id: string; name: string }>) => void; selectedKeys?: React.Key[]; - // 新增:自动展开到指定路径 + // New: Auto expand to specified path autoExpandPath?: Array<{ id: string; name: string }>; } @@ -221,7 +221,7 @@ const extractItems = (resp: any): any[] => { return []; }; -// 只加载当前层级的节点,不递归加载子节点 +// Only load nodes at current level, don't recursively load child nodes const buildTreeNodes = async ( kbId: string, parentId: string, @@ -229,7 +229,7 @@ const buildTreeNodes = async ( const currentParent = String(parentId ?? ''); if (!currentParent) return []; - // 只请求一次当前层级的数据,不分页 + // Only request current level data once, no pagination const response = await getFolderList({ kb_id: kbId, parent_id: currentParent, @@ -246,20 +246,20 @@ const buildTreeNodes = async ( const nodeKey = String(keySource); const isFolder = isFolderLike(raw); - // 只显示文件夹 + // Only show folders if (!isFolder) { continue; } - // 文件夹节点初始不加载子节点,isLeaf设为false表示可能有子节点 + // Folder node initially doesn't load child nodes, isLeaf set to false indicates possible child nodes nodes.push({ key: nodeKey, title: getNodeTitle(raw), icon: getNodeIcon(raw, isFolder), switcherIcon: isFolder ? switcherIcon : undefined, type: isFolder ? 'folder' : (typeof raw?.type === 'string' ? raw.type : normalizeExt(raw?.file_ext) || 'file'), - isLeaf: false, // 文件夹节点初始设为false,表示可能有子节点,需要展开时加载 - children: undefined, // 初始不加载子节点 + isLeaf: false, // Folder node initially set to false, indicating possible child nodes, load when expanded + children: undefined, // Initially don't load child nodes }); } @@ -283,7 +283,7 @@ const FolderTree: FC = ({ const [expandedKeys, setExpandedKeys] = useState([]); const [autoExpandInProgress, setAutoExpandInProgress] = useState(false); - // 更新树节点数据的辅助函数 + // Helper function to update tree node data const updateTreeData = (nodes: TreeNodeData[], key: Key, children: TreeNodeData[]): TreeNodeData[] => { return nodes.map((node) => { if (node.key === key) { @@ -303,17 +303,17 @@ const FolderTree: FC = ({ }); }; - // 加载根节点 + // Load root nodes useEffect(() => { let cancelled = false; const load = async () => { if (!knowledgeBaseId) { setTreeData([]); - setExpandedKeys([]); // 重置展开状态 + setExpandedKeys([]); // Reset expand state return; } try { - // 重置展开状态,确保从根目录开始 + // Reset expand state, ensure starting from root directory setExpandedKeys([]); const nodes = await buildTreeNodes(knowledgeBaseId, knowledgeBaseId); @@ -324,7 +324,7 @@ const FolderTree: FC = ({ } } } catch (e) { - console.error('加载文件夹树失败:', e); + console.error('Failed to load folder tree:', e); if (!cancelled) { const fallback = buildMockTreeData(); setTreeData(fallback); @@ -340,27 +340,27 @@ const FolderTree: FC = ({ }; }, [knowledgeBaseId, refreshKey]); - // 懒加载子节点 - 只在展开时加载 + // Lazy load child nodes - only load when expanded const onLoadData = async (node: any) => { const { key } = node; - // 如果已经加载过子节点,不再重复加载 + // If child nodes already loaded, don't reload if (node.children !== undefined) { return Promise.resolve(); } try { - // 使用节点的 key 作为 parent_id 加载子文件夹 + // Use node's key as parent_id to load child folders const children = await buildTreeNodes(knowledgeBaseId, String(key)); setTreeData((prevData) => updateTreeData(prevData, key, children)); } catch (e) { - console.error('加载子节点失败:', e); - // 加载失败时,将该节点标记为叶子节点(没有子节点) + console.error('Failed to load child nodes:', e); + // On load failure, mark this node as leaf node (no child nodes) setTreeData((prevData) => updateTreeData(prevData, key, [])); } }; - // 查找节点路径的辅助函数 + // Helper function to find node path const findNodePath = (nodes: TreeNodeData[], targetKey: Key, currentPath: Array<{ id: string; name: string }> = []): Array<{ id: string; name: string }> | null => { for (const node of nodes) { const newPath = [...currentPath, { id: String(node.key), name: String(node.title) }]; @@ -379,7 +379,7 @@ const FolderTree: FC = ({ return null; }; - // 查找节点的辅助函数 + // Helper function to find node const findNodeInTree = (nodes: TreeNodeData[], key: string): TreeNodeData | null => { for (const node of nodes) { if (String(node.key) === key) { @@ -393,7 +393,7 @@ const FolderTree: FC = ({ return null; }; - // 渐进式自动展开到指定路径 + // Progressive auto expand to specified path useEffect(() => { if (!autoExpandPath || autoExpandPath.length === 0 || autoExpandInProgress || treeData.length === 0) { return; @@ -406,46 +406,46 @@ const FolderTree: FC = ({ const keysToExpand: React.Key[] = []; let currentTreeData = treeData; - // 逐级展开,从第一级开始(跳过根节点,因为根节点已经加载) + // Expand level by level, starting from first level (skip root node as it's already loaded) for (let i = 0; i < autoExpandPath.length - 1; i++) { const nodeKey = autoExpandPath[i].id; keysToExpand.push(nodeKey); - // 查找当前节点 + // Find current node const targetNode = findNodeInTree(currentTreeData, nodeKey); if (targetNode && targetNode.children === undefined) { - // 如果子节点未加载,先加载 + // If child nodes not loaded, load first try { - console.log(`自动展开:加载节点 ${nodeKey} 的子节点`); + console.log(`Auto expand: Loading child nodes of ${nodeKey}`); const children = await buildTreeNodes(knowledgeBaseId, nodeKey); - // 更新树数据 + // Update tree data setTreeData((prevData) => { const newData = updateTreeData(prevData, nodeKey, children); - currentTreeData = newData; // 更新当前引用 + currentTreeData = newData; // Update current reference return newData; }); - // 等待状态更新完成 + // Wait for state update to complete await new Promise(resolve => setTimeout(resolve, 150)); } catch (error) { - console.error(`自动展开时加载节点 ${nodeKey} 失败:`, error); - // 加载失败时停止展开 + console.error(`Failed to load node ${nodeKey} during auto expand:`, error); + // Stop expanding on load failure break; } } } - // 设置展开的节点 + // Set expanded nodes setExpandedKeys(keysToExpand); - // 选中最后一个节点(目标文件夹) + // Select last node (target folder) const targetKey = autoExpandPath[autoExpandPath.length - 1]?.id; if (targetKey) { - console.log(`自动展开:选中目标节点 ${targetKey}`); - // 延迟选中,确保展开动画完成 + console.log(`Auto expand: Select target node ${targetKey}`); + // Delay selection to ensure expand animation completes setTimeout(() => { if (onSelect) { onSelect([targetKey], { @@ -460,21 +460,21 @@ const FolderTree: FC = ({ } } catch (error) { - console.error('自动展开路径失败:', error); + console.error('Auto expand path failed:', error); } finally { - // 延迟重置标志,确保展开过程完全完成 + // Delay reset flag to ensure expand process is fully complete setTimeout(() => { setAutoExpandInProgress(false); }, 500); } }; - // 延迟执行,确保树数据已经加载完成 + // Delay execution to ensure tree data is loaded const timer = setTimeout(expandToPath, 300); return () => clearTimeout(timer); }, [autoExpandPath, treeData.length, knowledgeBaseId, onSelect, autoExpandInProgress]); - // 处理展开事件 + // Handle expand event const handleExpand: TreeProps['onExpand'] = (expandedKeys, info) => { setExpandedKeys(expandedKeys); if (onExpand) { @@ -482,7 +482,7 @@ const FolderTree: FC = ({ } }; - // 处理选择事件,计算并传递路径 + // Handle select event, calculate and pass path const handleSelect: TreeProps['onSelect'] = (selectedKeys, info) => { if (selectedKeys.length > 0) { const path = findNodePath(treeData, selectedKeys[0]); @@ -493,7 +493,7 @@ const FolderTree: FC = ({ onFolderPathChange([]); } - // 调用原始的 onSelect 回调 + // Call original onSelect callback if (onSelect) { onSelect(selectedKeys, info); } @@ -503,7 +503,7 @@ const FolderTree: FC = ({ return ( (({ onInsert, on } } } catch (error) { - console.error('操作失败:', error); + console.error('Operation failed:', error); const errorMsg = isEditMode ? (t('knowledgeBase.updateFailed') || '更新失败') : (t('knowledgeBase.insertFailed') || '插入失败'); diff --git a/web/src/views/KnowledgeBase/components/KnowledgeGraph.tsx b/web/src/views/KnowledgeBase/components/KnowledgeGraph.tsx index 55f8fcfc..ea6b8f7e 100644 --- a/web/src/views/KnowledgeBase/components/KnowledgeGraph.tsx +++ b/web/src/views/KnowledgeBase/components/KnowledgeGraph.tsx @@ -9,7 +9,7 @@ import pointer from '@/assets/images/userMemory/pointer.svg' import empty from '@/assets/images/userMemory/empty.svg' import Empty from '@/components/Empty' -// 知识图谱数据类型定义 +// Knowledge graph data type definitions export interface KnowledgeNode { id: string entity_name: string @@ -17,7 +17,7 @@ export interface KnowledgeNode { description: string pagerank: number source_id: string[] - // ECharts 需要的属性 + // Properties required by ECharts name: string category: number symbolSize: number @@ -35,7 +35,7 @@ export interface KnowledgeEdge { source_id: string[] source: string target: string - // ECharts 需要的属性 + // Properties required by ECharts value: number } @@ -65,7 +65,7 @@ const operations = [ { name: 'zoom', icon: zoom }, ] -// 预定义的颜色调色板 +// Predefined color palette const colorPalette = [ '#155EEF', '#4DA8FF', '#9C6FFF', '#8BAEF7', '#369F21', '#FF5D34', '#FF8A4C', '#FFB048', '#E74C3C', '#9B59B6', @@ -73,7 +73,7 @@ const colorPalette = [ '#8E44AD', '#2980B9', '#16A085', '#F1C40F', '#E67E22' ] -// 动态生成实体类型颜色映射 +// Dynamically generate entity type color mapping const generateEntityTypeColors = (entityTypes: string[]): Record => { const colorMap: Record = {} entityTypes.forEach((type, index) => { @@ -93,12 +93,12 @@ const KnowledgeGraph: FC = ({ data, loading = false }) => { const [selectedNode, setSelectedNode] = useState(null) const [entityTypeColors, setEntityTypeColors] = useState>({}) - // 弹框拖动相关状态 + // Modal drag-related state const [modalPosition, setModalPosition] = useState({ x: 20, y: 20 }) const [isDragging, setIsDragging] = useState(false) const [dragStart, setDragStart] = useState({ x: 0, y: 0 }) - // 拖动处理函数 + // Drag handling functions const handleMouseDown = useCallback((e: React.MouseEvent) => { setIsDragging(true) setDragStart({ @@ -113,7 +113,7 @@ const KnowledgeGraph: FC = ({ data, loading = false }) => { const newX = e.clientX - dragStart.x const newY = e.clientY - dragStart.y - // 限制拖动范围,确保弹框不会超出容器 + // Limit drag range to ensure modal doesn't exceed container bounds const container = chartRef.current?.getEchartsInstance().getDom().parentElement if (container && modalRef.current) { const containerRect = container.getBoundingClientRect() @@ -133,7 +133,7 @@ const KnowledgeGraph: FC = ({ data, loading = false }) => { setIsDragging(false) }, []) - // 添加全局鼠标事件监听 + // Add global mouse event listeners useEffect(() => { if (isDragging) { document.addEventListener('mousemove', handleMouseMove) @@ -145,12 +145,12 @@ const KnowledgeGraph: FC = ({ data, loading = false }) => { } }, [isDragging, handleMouseMove, handleMouseUp]) - // 关闭弹框 + // Close modal const handleCloseModal = useCallback(() => { setSelectedNode(null) }, []) - // 处理知识图谱数据 + // Process knowledge graph data const processGraphData = useCallback(() => { if (!data?.graph) { setNodes([]) @@ -164,31 +164,31 @@ const KnowledgeGraph: FC = ({ data, loading = false }) => { const processedNodes: KnowledgeNode[] = [] const processedEdges: KnowledgeEdge[] = [] - // 获取所有实体类型 + // Get all entity types const entityTypes = [...new Set(rawNodes.map(node => node.entity_type))] const categoryMap = entityTypes.reduce((acc, type, index) => { acc[type] = index return acc }, {} as Record) - // 动态生成实体类型颜色映射 + // Dynamically generate entity type color mapping const dynamicEntityTypeColors = generateEntityTypeColors(entityTypes) setEntityTypeColors(dynamicEntityTypeColors) - // 计算每个节点的连接数 + // Calculate connection count for each node const connectionCount: Record = {} rawEdges.forEach(edge => { - // 使用 src_id 和 tgt_id 计算连接数 + // Use src_id and tgt_id to calculate connection count connectionCount[edge.src_id] = (connectionCount[edge.src_id] || 0) + 1 connectionCount[edge.tgt_id] = (connectionCount[edge.tgt_id] || 0) + 1 }) - // 处理节点数据 + // Process node data rawNodes.forEach(node => { const connections = connectionCount[node.id] || 0 const categoryIndex = categoryMap[node.entity_type] || 0 - // 根据 pagerank 和连接数计算节点大小 + // Calculate node size based on pagerank and connection count let symbolSize = Math.max(10, Math.min(50, node.pagerank * 200 + connections * 2)) processedNodes.push({ @@ -202,19 +202,19 @@ const KnowledgeGraph: FC = ({ data, loading = false }) => { }) }) - // 处理边数据 + // Process edge data rawEdges.forEach(edge => { - // 注意:根据数据结构,source 和 target 字段可能与 src_id 和 tgt_id 相反 - // 我们使用 src_id 和 tgt_id 作为正确的连接关系 + // Note: Based on data structure, source and target fields may be opposite to src_id and tgt_id + // We use src_id and tgt_id as the correct connection relationship processedEdges.push({ - ...edge, // 保留所有原始字段 - source: edge.src_id, // 使用 src_id 作为源节点 - target: edge.tgt_id, // 使用 tgt_id 作为目标节点 + ...edge, // Keep all original fields + source: edge.src_id, // Use src_id as source node + target: edge.tgt_id, // Use tgt_id as target node value: edge.weight || 1 }) }) - // 验证节点ID和边的连接 + // Verify node IDs and edge connections const nodeIds = new Set(processedNodes.map(n => n.id)) const validEdges = processedEdges.filter(edge => { const sourceExists = nodeIds.has(edge.source) @@ -225,18 +225,18 @@ const KnowledgeGraph: FC = ({ data, loading = false }) => { return sourceExists && targetExists }) - // 调试信息 + // Debug information console.log('Total nodes:', processedNodes.length) console.log('Total edges:', processedEdges.length) console.log('Valid edges:', validEdges.length) console.log('Node IDs:', Array.from(nodeIds).slice(0, 5)) console.log('Edge sample:', validEdges.slice(0, 3)) - // 设置分类 + // Set categories const processedCategories = entityTypes.map(type => ({ name: type })) setNodes(processedNodes) - setLinks(validEdges) // 只使用有效的边 + setLinks(validEdges) // Only use valid edges setCategories(processedCategories) }, [data]) @@ -334,7 +334,7 @@ const KnowledgeGraph: FC = ({ data, loading = false }) => { lineStyle: { color: '#5B6167', curveness: 0.3, - width: 2, // 固定线宽,避免函数问题 + width: 2, // Fixed line width to avoid function issues opacity: 0.8 }, force: { @@ -376,7 +376,7 @@ const KnowledgeGraph: FC = ({ data, loading = false }) => { }} /> - {/* 实体详情弹框 */} + {/* Entity details modal */} {selectedNode && (
= ({ data, loading = false }) => { cursor: isDragging ? 'grabbing' : 'grab' }} > - {/* 弹框头部 - 可拖动区域 */} + {/* Modal header - draggable area */}
= ({ data, loading = false }) => {
- {/* 弹框内容 */} + {/* Modal content */}
{selectedNode.entity_name}
diff --git a/web/src/views/KnowledgeBase/components/KnowledgeGraphCard.tsx b/web/src/views/KnowledgeBase/components/KnowledgeGraphCard.tsx index 3dd7ab22..f2978b61 100644 --- a/web/src/views/KnowledgeBase/components/KnowledgeGraphCard.tsx +++ b/web/src/views/KnowledgeBase/components/KnowledgeGraphCard.tsx @@ -15,7 +15,7 @@ import { type KnowledgeBase } from '../types'; import Empty from '@/components/Empty'; interface KnowledgeGraphCardProps { knowledgeBase?: KnowledgeBase; - onRebuildGraph?: () => void; // 添加重建图谱的回调函数 + onRebuildGraph?: () => void; // Callback function to rebuild graph } const KnowledgeGraphCard: React.FC = ({ knowledgeBase, onRebuildGraph }) => { @@ -23,7 +23,7 @@ const KnowledgeGraphCard: React.FC = ({ knowledgeBase, const [data, setData] = useState() const [loading, setLoading] = useState(true) const handleRebuildGraph = () => { - // 调用父组件传递的回调函数来打开CreateModal并传递重建标识 + // Call parent component's callback to open CreateModal with rebuild flag if (onRebuildGraph) { onRebuildGraph(); } @@ -38,15 +38,15 @@ const KnowledgeGraphCard: React.FC = ({ knowledgeBase, setLoading(true) try { const res = await getKnowledgeGraph(knowledgeBase?.id) - // 判断 res.graph 是否为空对象或不存在 + // Check if res.graph is empty object or doesn't exist const graphResponse = res as KnowledgeGraphResponse; if (!graphResponse || !graphResponse.graph || Object.keys(graphResponse.graph).length === 0) { - setData(undefined) // 设置为 undefined 以显示 empty 状态 + setData(undefined) // Set to undefined to show empty state } else { setData(graphResponse) } } catch (error) { - console.error('获取知识图谱数据失败:', error) + console.error('Failed to fetch knowledge graph data:', error) } finally { setLoading(false) } diff --git a/web/src/views/KnowledgeBase/components/RecallTest.tsx b/web/src/views/KnowledgeBase/components/RecallTest.tsx index 81332a11..9c0c9261 100644 --- a/web/src/views/KnowledgeBase/components/RecallTest.tsx +++ b/web/src/views/KnowledgeBase/components/RecallTest.tsx @@ -27,7 +27,7 @@ const RecallTest = forwardRef(({},ref) => { { label: t('knowledgeBase.vector'), value: false }, ]); - // 获取检索模式选项 + // Get retrieval mode options useEffect(() => { fetchRetrievalModeOptions(); }, []); @@ -36,9 +36,9 @@ const RecallTest = forwardRef(({},ref) => { try { const response = await getRetrievalModeType(); if (response && Array.isArray(response)) { - // 将 API 返回的数据转换为选项格式 + // Convert API response to option format const options = response.map((item: any) => { - // 支持多种数据格式 + // Support multiple data formats let label = t(`knowledgeBase.${item}`) + ' ' + t(`knowledgeBase.retrieve`); let value = item; @@ -50,8 +50,8 @@ const RecallTest = forwardRef(({},ref) => { } } } catch (error) { - console.error('获取检索模式选项失败:', error); - // 保持默认选项 + console.error('Failed to fetch retrieval mode options:', error); + // Keep default options } }; @@ -60,8 +60,8 @@ const RecallTest = forwardRef(({},ref) => { setKnowledgeBaseId(kbId || ''); form.resetFields(); setData([]); - setRetrieveType('hybrid'); // 重置为默认值 - // 确保表单字段也设置为默认值 + setRetrieveType('hybrid'); // Reset to default value + // Ensure form field is also set to default value form.setFieldsValue({ retrieve_type: 'hybrid' }); } const fetchData = (params: RecallTestParams) => { @@ -91,10 +91,10 @@ const RecallTest = forwardRef(({},ref) => { console.log('RecallTest - params:', params); fetchData(params); }).catch((error) => { - console.error('表单验证失败:', error); + console.error('Form validation failed:', error); }); } - // 暴露给父组件的方法 + // Expose methods to parent component useImperativeHandle(ref, () => ({ handleOpen, })); @@ -134,7 +134,7 @@ const RecallTest = forwardRef(({},ref) => { /> - {/* 当 retrieve_type = semantic 或 hybrid 时显示 */} + {/* Show when retrieve_type = semantic or hybrid */} {(retrieveType === 'semantic' || retrieveType === 'hybrid') && ( (({},ref) => { const pendingKbIdRef = useRef(undefined); const shouldCallHandleOpenRef = useRef(false); - // 调用 RecallTest 的 handleOpen 方法 + // Call RecallTest's handleOpen method const callRecallTestHandleOpen = useCallback(() => { if (recallTestRef.current && shouldCallHandleOpenRef.current) { recallTestRef.current.handleOpen(pendingKbIdRef.current); @@ -26,14 +26,14 @@ const RecallTestDrawer = forwardRef(({},ref) => { setOpen(true); } - // 当 Drawer 打开时,尝试调用 handleOpen + // When Drawer opens, try to call handleOpen useLayoutEffect(() => { if (open) { callRecallTestHandleOpen(); } }, [open, callRecallTestHandleOpen]); - // 使用回调 ref 确保在组件挂载后立即调用 + // Use callback ref to ensure immediate call after component mount const setRecallTestRef = useCallback((node: any) => { recallTestRef.current = node; if (open && shouldCallHandleOpenRef.current) { @@ -41,7 +41,7 @@ const RecallTestDrawer = forwardRef(({},ref) => { } }, [open, callRecallTestHandleOpen]); - // 暴露给父组件的方法 + // Expose methods to parent component useImperativeHandle(ref, () => ({ handleOpen, })); diff --git a/web/src/views/KnowledgeBase/components/RecallTestResult.tsx b/web/src/views/KnowledgeBase/components/RecallTestResult.tsx index c8acbe03..f9a9bb6e 100644 --- a/web/src/views/KnowledgeBase/components/RecallTestResult.tsx +++ b/web/src/views/KnowledgeBase/components/RecallTestResult.tsx @@ -1,5 +1,5 @@ -/* - * @Description: 滚动列表 +/** + * @Description: Scroll List * @Version: 0.0.1 * @Author: yujiangping * @Date: 2025-11-18 16:19:58 @@ -22,9 +22,9 @@ interface RecallTestResultProps { loadMore?: () => void; loading?: boolean; scrollableTarget?: string; - editable?: boolean; // 是否可编辑 - onItemClick?: (item: RecallTestData, index: number) => void; // 点击项的回调 - parserMode?: number; // 解析模式,1 表示 QA 格式 + editable?: boolean; // Whether editable + onItemClick?: (item: RecallTestData, index: number) => void; // Click item callback + parserMode?: number; // Parser mode, 1 means QA format } const RecallTestResult = ({ @@ -40,7 +40,7 @@ const RecallTestResult = ({ }: RecallTestResultProps) => { const { t } = useTranslation(); - // 解析 QA 格式内容 + // Parse QA format content const parseQAContent = (content: string) => { if (!content || parserMode !== 1) return null; @@ -56,25 +56,25 @@ const RecallTestResult = ({ return null; }; - // 格式化 QA 内容为显示格式 + // Format QA content for display const formatQAContent = (question: string, answer: string) => { return `**${t('knowledgeBase.question')}:** ${question}\n**${t('knowledgeBase.answer')}:** ${answer}`; }; const handleItemClick = (e: React.MouseEvent, item: RecallTestData, index: number) => { - // 检查点击的是否是图片或图片相关元素 + // Check if the click is on an image or image-related element const target = e.target as HTMLElement; - // 检查是否点击了图片本身、图片的容器、预览层、关闭按钮或 SVG 图标 + // Check if clicked on image itself, image container, preview layer, close button or SVG icon if ( target.tagName === 'IMG' || - target.tagName === 'SVG' || // SVG 图标 - target.tagName === 'PATH' || // SVG 路径 + target.tagName === 'SVG' || // SVG icon + target.tagName === 'PATH' || // SVG path target.closest('.ant-image') || target.closest('.ant-image-preview') || target.closest('.ant-image-preview-wrap') || target.closest('.ant-image-preview-operations') || - target.closest('.anticon') || // Ant Design 图标 + target.closest('.anticon') || // Ant Design icon target.classList.contains('ant-image-img') || target.classList.contains('ant-image-mask') || target.classList.contains('ant-image-preview-close') || @@ -88,7 +88,7 @@ const RecallTestResult = ({ } }; - // 根据分数获取颜色类名 + // Get color class based on score const getScoreColorClass = (score: number): string => { const percentage = score * 100; if (percentage >= 90) { @@ -177,7 +177,7 @@ const RecallTestResult = ({
); - // 如果提供了 loadMore 和 hasMore,使用 InfiniteScroll + // If loadMore and hasMore are provided, use InfiniteScroll if (loadMore && hasMore !== undefined) { return (
@@ -200,7 +200,7 @@ const RecallTestResult = ({ ); } - // 否则使用普通渲染 + // Otherwise use normal rendering return (
diff --git a/web/src/views/KnowledgeBase/components/ShareModal.tsx b/web/src/views/KnowledgeBase/components/ShareModal.tsx index f37d669b..5336d227 100644 --- a/web/src/views/KnowledgeBase/components/ShareModal.tsx +++ b/web/src/views/KnowledgeBase/components/ShareModal.tsx @@ -4,13 +4,13 @@ * @Author: yujiangping * @Date: 2025-11-10 18:52:55 * @LastEditors: yujiangping - * @LastEditTime: 2025-11-29 12:29:31 + * @LastEditTime: 2026-02-03 17:08:00 */ import { forwardRef, useImperativeHandle, useState, useRef } from 'react'; import { Switch } from 'antd'; import { useTranslation } from 'react-i18next'; import { message } from 'antd'; -import type { ShareModalRef, ShareModalRefProps, KnowledgeBase} from '@/views/KnowledgeBase/types'; +import type { ShareModalRef, ShareModalRefProps, KnowledgeBase, SpaceItem} from '@/views/KnowledgeBase/types'; import RbModal from '@/components/RbModal' // import betchControlIcon from '@/assets/images/knowledgeBase/betch-control.png'; import kbIcon from '@/assets/images/knowledgeBase/knowledge-management.png'; @@ -33,7 +33,7 @@ const ShareModal = forwardRef(({ handleShare: const [knowledgeBase, setKnowledgeBase] = useState(null); const [spaceList, setSpaceList] = useState([]); - // 封装取消方法,添加关闭弹窗逻辑 + // Close modal and reset state const handleClose = () => { setCurIndex(9999); setLoading(false) @@ -66,11 +66,11 @@ const ShareModal = forwardRef(({ handleShare: console.log('Workspace IDs:', workspaceIds); shareSpaceModalRef?.current?.handleOpen(kbId,knowledgeBase,workspaceIds); - // 分享后关闭弹窗 + // Close modal after sharing handleClose(); } const handleChange = (checked: boolean, item: any) => { - // 打开/关闭分享出去的数据库 + // Toggle shared knowledge base status console.log('Switch changed:', checked, item); updateKnowledgeBase(item.target_kb?.id, { status: checked ? 1 : 2 @@ -82,7 +82,7 @@ const ShareModal = forwardRef(({ handleShare: }) } - // 暴露给父组件的方法 + // Expose methods to parent component useImperativeHandle(ref, () => ({ handleOpen, handleClose, diff --git a/web/src/views/KnowledgeBase/components/ShareSpaceModal.tsx b/web/src/views/KnowledgeBase/components/ShareSpaceModal.tsx index 60cfd81d..db26fd93 100644 --- a/web/src/views/KnowledgeBase/components/ShareSpaceModal.tsx +++ b/web/src/views/KnowledgeBase/components/ShareSpaceModal.tsx @@ -30,7 +30,7 @@ const ShareModal = forwardRef(({ handleShare: const [knowledgeBase, setKnowledgeBase] = useState(null); const [spaceList, setSpaceList] = useState([]); - // 封装取消方法,添加关闭弹窗逻辑 + // Close modal and reset state const handleClose = () => { setCurIndex(-1); setLoading(false) @@ -51,10 +51,10 @@ const ShareModal = forwardRef(({ handleShare: } const handleShare = async() => { - // 获取所有 checked 为 true 的数据 + // Get all data with checked = true const checkedItems = spaceList.filter(item => item.is_active); debugger - // 获取当前选中的项(curIndex 对应的数据) + // Get currently selected item (corresponding to curIndex) const selectedItem = curIndex !== -1 ? spaceList[curIndex] : null; if(!selectedItem){ messageApi.error(t('knowledgeBase.selectSpace')); @@ -70,13 +70,13 @@ const ShareModal = forwardRef(({ handleShare: }else{ messageApi.error(t('knowledgeBase.shareFailed')); } - // 调用父组件传递的回调函数,传递选中的数据 + // Call parent component's callback function with selected data onShare?.({ checkedItems, selectedItem }); - // 分享后关闭弹窗 + // Close modal after sharing handleClose(); } const handleClick = (index: number, checked: boolean) => { @@ -84,7 +84,7 @@ const ShareModal = forwardRef(({ handleShare: setCurIndex(index); } - // 暴露给父组件的方法 + // Expose methods to parent component useImperativeHandle(ref, () => ({ handleOpen, handleClose, diff --git a/web/src/views/KnowledgeBase/datasets.tsx b/web/src/views/KnowledgeBase/datasets.tsx index e5e6d79e..238d9857 100644 --- a/web/src/views/KnowledgeBase/datasets.tsx +++ b/web/src/views/KnowledgeBase/datasets.tsx @@ -36,11 +36,11 @@ const Datasets: FC = () => { }; if (loading) { - return
加载中...
; + return
Loading...
; } if (!knowledgeBase) { - return
知识库不存在
; + return
Knowledge base not found
; } return ( @@ -50,7 +50,7 @@ const Datasets: FC = () => { icon={} onClick={handleBack} > - 返回 + {t('common.back')}
@@ -61,7 +61,7 @@ const Datasets: FC = () => {

{t('knowledgeBase.datasets')}

- {/* TODO: 添加数据集列表 */} + {/* TODO: Add dataset list */}
{t('knowledgeBase.noDataSets')}
diff --git a/web/src/views/KnowledgeBase/index.tsx b/web/src/views/KnowledgeBase/index.tsx index 58889581..01df5218 100644 --- a/web/src/views/KnowledgeBase/index.tsx +++ b/web/src/views/KnowledgeBase/index.tsx @@ -388,7 +388,7 @@ const KnowledgeBaseManagement: FC = () => { }); }, onCancel: () => { - console.log('取消删除'); + console.log('Cancel delete'); }, }); };