import { ArrowLeftOutlined, CheckCircleOutlined, DeleteOutlined, ExclamationCircleOutlined, FileTextOutlined, InboxOutlined, LoadingOutlined, QuestionCircleOutlined, } from '@ant-design/icons'; import type { UploadFile } from 'antd'; import { Button, Card, Checkbox, Divider, Empty, Input, InputNumber, Progress, Select, Spin, Tooltip, Upload, } from 'antd'; import { useEffect, useState } from 'react'; import type { Segment } from '~/api/dify-dataset/type'; import { useDocumentUpload } from '~/hooks/dify-dataset-manager/document-upload'; import type { DocumentUploadProps, UploadedDocument } from '~/types/dify-dataset-manager/document-upload'; import { SUPPORTED_FORMATS } from '~/types/dify-dataset-manager/document-upload'; const { Dragger } = Upload; /** * 文档上传组件 * 支持多文件上传,两步流程:选择文件 → 上传并配置分段 */ export default function DocumentUpload({ datasetId, onClose, onSuccess, }: DocumentUploadProps) { const { // 状态 step, fileList, uploadedDocuments, currentSettings, previewLoading, // 方法 handleFileChange, handleRemoveFile, handleNextStep, handleDocumentChange, handleReprocess, handlePrevStep, handleGoToDocuments, updateCurrentSettings, // 计算属性方法 getCurrentDocument, getCurrentProgress, getStatusText, isCurrentDocProcessing, getCompletionStats, } = useDocumentUpload(datasetId, onClose, onSuccess); const selectedFiles = fileList.filter((f: UploadFile) => f.originFileObj).map((f: UploadFile) => f.originFileObj as File); // 平滑进度条逻辑 const [displayPercent, setDisplayPercent] = useState(0); const targetPercent = getCurrentProgress(); useEffect(() => { if (targetPercent > displayPercent) { // 如果目标进度大于当前显示进度,启动动画 const diff = targetPercent - displayPercent; // 动态步长:差距越大跑得越快,但最小步长为1 const step = Math.max(1, Math.ceil(diff / 10)); const timer = requestAnimationFrame(() => { setDisplayPercent(prev => Math.min(targetPercent, prev + step)); }); return () => cancelAnimationFrame(timer); } else if (targetPercent < displayPercent && targetPercent === 0) { // 如果目标重置为0(例如重新开始),立即重置 setDisplayPercent(0); } }, [targetPercent, displayPercent]); /** * 渲染步骤指示器(两步流程) */ const renderSteps = () => (
1 ? 'completed' : ''}`}> 1 选择数据源
1 ? 'completed' : ''}`}>
2 文本分段与清洗
); /** * 渲染第一步:选择文件(支持多文件) */ const renderStep1 = () => (

上传文本文件

文档需上传至知识智能理解法治知识库,广东烟草智能理解将按照于知识库,你可以在聊后指数文档所据案中检索它

false} multiple={true} accept=".txt,.md,.mdx,.pdf,.html,.htm,.xlsx,.xls,.docx,.csv,.vtt,.properties" showUploadList={false} >

拖拽文件或至此,或者 选择文件

已支持 {SUPPORTED_FORMATS},每个文件不超过 15MB。支持批量上传多个文件。

{/* 已选文件列表 */} {selectedFiles.length > 0 && (

嵌入已就绪 ({selectedFiles.length} 个文件)

{fileList.map((file: UploadFile) => (
{file.name} {file.originFileObj ? `${file.originFileObj.type?.split('/')[1]?.toUpperCase() || 'FILE'},${(file.originFileObj.size / 1024 / 1024).toFixed(2)}MB` : ''}
))}
)}
); /** * 渲染第二步:分段配置与预览 * 左侧始终显示配置面板,右侧预览框内显示进度或分段内容 */ const renderStep2 = () => { const currentDoc = getCurrentDocument(); const isProcessing = isCurrentDocProcessing(); const stats = getCompletionStats(); return (
{/* 分段配置与预览 */}
{/* 左侧设置区域 */}

分段设置

{/* 分段标识符 */}
updateCurrentSettings('separator', e.target.value)} placeholder="\n\n" className="setting-input" disabled={isProcessing} />
{/* 分段最大长度 */}
updateCurrentSettings('maxTokens', value || 1024)} min={100} max={4000} className="setting-input-number" disabled={isProcessing} /> characters
{/* 分段重叠长度 */}
updateCurrentSettings('chunkOverlap', value || 50)} min={0} max={500} className="setting-input-number" disabled={isProcessing} /> characters
{/* 文本预处理规则 */}

文本预处理规则

updateCurrentSettings('removeExtraSpaces', e.target.checked)} disabled={isProcessing} > 替换掉连续的空格、换行符和制表符 updateCurrentSettings('removeUrlsEmails', e.target.checked)} disabled={isProcessing} > 删除所有 URL 和电子邮件地址
{/* 索引方式 */}

索引方式

!isProcessing && updateCurrentSettings('indexingTechnique', 'high_quality')} > 高质量 推荐
!isProcessing && updateCurrentSettings('indexingTechnique', 'economy')} > 经济
{/* 操作按钮 */}
{/* 右侧预览区域 */}
预览 {uploadedDocuments.length > 0 && ( <>