diff --git a/src/frontend/platform/src/pages/KnowledgePage/components/FileUploadStep2.tsx b/src/frontend/platform/src/pages/KnowledgePage/components/FileUploadStep2.tsx index afd3fd8f0..ff2870eba 100644 --- a/src/frontend/platform/src/pages/KnowledgePage/components/FileUploadStep2.tsx +++ b/src/frontend/platform/src/pages/KnowledgePage/components/FileUploadStep2.tsx @@ -295,7 +295,7 @@ const useFileProcessingRules = (initialStrategies, resultFiles, kid, splitRule) separator: splitRule?.separator || ['\\n\\n', '\\n'], separatorRule: splitRule?.separator_rule || ['after', 'after'], chunkSize: splitRule?.chunk_size?.toString() || "1000", - chunkOverlap: splitRule?.chunk_overlap?.toString() || "100", + chunkOverlap: splitRule?.chunk_overlap?.toString() || "10", retainImages: splitRule?.retain_images ?? true, enableFormula: splitRule?.enable_formula ?? true, forceOcr: splitRule?.force_ocr ?? true, diff --git a/src/frontend/platform/src/pages/KnowledgePage/components/Paragraphs.tsx b/src/frontend/platform/src/pages/KnowledgePage/components/Paragraphs.tsx index 60ad7b462..4fe698e72 100644 --- a/src/frontend/platform/src/pages/KnowledgePage/components/Paragraphs.tsx +++ b/src/frontend/platform/src/pages/KnowledgePage/components/Paragraphs.tsx @@ -4,7 +4,7 @@ import { Dialog, DialogContent, DialogHeader } from '@/components/bs-ui/dialog'; import { SearchInput } from '@/components/bs-ui/input'; import AutoPagination from '@/components/bs-ui/pagination/autoPagination'; import ShadTooltip from "@/components/ShadTooltipComponent"; -import { delChunkApi, getFilePathApi, getKnowledgeChunkApi, getFileBboxApi, readFileByLibDatabase, updateChunkApi } from '@/controllers/API'; +import { delChunkApi, getFileBboxApi, getFilePathApi, getKnowledgeChunkApi, readFileByLibDatabase, updateChunkApi } from '@/controllers/API'; import { captureAndAlertRequestErrorHoc } from '@/controllers/request'; import { useTable } from '@/util/hook'; import { truncateString } from "@/util/utils"; @@ -60,7 +60,13 @@ export default function Paragraphs({ fileId, onBack }) { const [previewUrl, setPreviewUrl] = useState() const [hasChunkBboxes, setHasChunkBboxes] = useState(false); const latestFileUrlRef = useRef(''); -const latestPreviewUrlRef = useRef(''); + const latestPreviewUrlRef = useRef(''); + + const [selectedChunkIndex, setSelectedBbox] = useKnowledgeStore((state) => [state.selectedChunkIndex, state.setSelectedBbox]); + useEffect(() => { + // 切换chunk清空选中的高亮标注bbox + setSelectedBbox([]) + }, [selectedChunkIndex]) // 表格配置(完全保留原始逻辑) const tableConfig = useMemo(() => ({ @@ -89,19 +95,19 @@ const latestPreviewUrlRef = useRef(''); let chunkBboxes = []; try { const firstChunk = response.data?.[0]; - if (firstChunk?.metadata?.bbox) { - console.log(JSON.parse(firstChunk?.metadata?.bbox).chunk_bboxes,6666666666666); - - // 先判断bbox是否为空字符串 - if (typeof firstChunk.metadata.bbox === 'string' && JSON.parse(firstChunk?.metadata?.bbox).chunk_bboxes === '') { - console.log('bbox为空字符串'); - chunkBboxes = []; - } else { - // 解析JSON - const bboxObj = JSON.parse(firstChunk.metadata.bbox); - chunkBboxes = bboxObj.chunk_bboxes || []; + if (firstChunk?.metadata?.bbox) { + console.log(JSON.parse(firstChunk?.metadata?.bbox).chunk_bboxes, 6666666666666); + + // 先判断bbox是否为空字符串 + if (typeof firstChunk.metadata.bbox === 'string' && JSON.parse(firstChunk?.metadata?.bbox).chunk_bboxes === '') { + console.log('bbox为空字符串'); + chunkBboxes = []; + } else { + // 解析JSON + const bboxObj = JSON.parse(firstChunk.metadata.bbox); + chunkBboxes = bboxObj.chunk_bboxes || []; + } } - } } catch (e) { console.error('解析 chunk_bboxes 失败:', e); chunkBboxes = []; @@ -115,95 +121,95 @@ const latestPreviewUrlRef = useRef(''); return response; } ); -const fetchFileUrl = useCallback(async (fileId) => { - console.log('获取文件URL:', fileId); - if (!fileId) return ''; + const fetchFileUrl = useCallback(async (fileId) => { + console.log('获取文件URL:', fileId); + if (!fileId) return ''; - try { - setIsFetchingUrl(true); - const res = await getFilePathApi(fileId); - const pares = await getFileBboxApi(fileId); - setPartitions(pares || []); + try { + setIsFetchingUrl(true); + const res = await getFilePathApi(fileId); + const pares = await getFileBboxApi(fileId); + setPartitions(pares || []); - // 获取当前选中的文件信息 - const currentFile = rawFiles.find(f => String(f.id) === String(fileId)); - let finalUrl = ''; - let finalPreviewUrl = ''; + // 获取当前选中的文件信息 + const currentFile = rawFiles.find(f => String(f.id) === String(fileId)); + let finalUrl = ''; + let finalPreviewUrl = ''; - // 检查是否有有效的preview_url和original_url - const hasPreviewUrl = typeof res.preview_url === 'string' && res.preview_url.trim() !== ''; - const hasOriginalUrl = typeof res.original_url === 'string' && res.original_url.trim() !== ''; + // 检查是否有有效的preview_url和original_url + const hasPreviewUrl = typeof res.preview_url === 'string' && res.preview_url.trim() !== ''; + const hasOriginalUrl = typeof res.original_url === 'string' && res.original_url.trim() !== ''; - if (currentFile) { - console.log(currentFile,3); - - // 判断是否为UNS或LOCAL类型 - const isUnsOrLocal = currentFile.parse_type === "uns" || currentFile.parse_type === "local"; - console.log(isUnsOrLocal,currentFile,4444444); - - - if (isUnsOrLocal) { - // UNS或LOCAL类型:根据bbox是否有效选择URL - const isBboxesValid = hasChunkBboxes; - const isBboxesEmpty = !hasChunkBboxes || chunkBboxes.length === 0; - if (!isBboxesEmpty && hasPreviewUrl) { - // 有有效bbox且有preview_url → 使用preview_url - console.log(1111); - - finalUrl = res.preview_url.trim(); - finalPreviewUrl = res.preview_url.trim(); - console.log('UNS/LOCAL类型(有有效bbox):使用preview_url'); - } else { - // 无有效bbox(为空数组/字符串)或无preview_url → 强制使用original_url - console.log(2222); - - finalUrl = hasOriginalUrl ? res.original_url.trim() : ''; - finalPreviewUrl = finalUrl; - console.log('UNS/LOCAL类型(无有效bbox或无preview_url):使用original_url'); + if (currentFile) { + console.log(currentFile, 3); + + // 判断是否为UNS或LOCAL类型 + const isUnsOrLocal = currentFile.parse_type === "uns" || currentFile.parse_type === "local"; + console.log(isUnsOrLocal, currentFile, 4444444); + + + if (isUnsOrLocal) { + // UNS或LOCAL类型:根据bbox是否有效选择URL + const isBboxesValid = hasChunkBboxes; + const isBboxesEmpty = !hasChunkBboxes || chunkBboxes.length === 0; + if (!isBboxesEmpty && hasPreviewUrl) { + // 有有效bbox且有preview_url → 使用preview_url + console.log(1111); + + finalUrl = res.preview_url.trim(); + finalPreviewUrl = res.preview_url.trim(); + console.log('UNS/LOCAL类型(有有效bbox):使用preview_url'); + } else { + // 无有效bbox(为空数组/字符串)或无preview_url → 强制使用original_url + console.log(2222); + + finalUrl = hasOriginalUrl ? res.original_url.trim() : ''; + finalPreviewUrl = finalUrl; + console.log('UNS/LOCAL类型(无有效bbox或无preview_url):使用original_url'); + } + } else { + // 其他类型:优先使用preview_url,无则使用original_url + if (hasPreviewUrl) { + // 有preview_url → 优先使用 + finalUrl = res.preview_url.trim(); + finalPreviewUrl = res.preview_url.trim(); + console.log('其他类型:使用preview_url'); + } else { + // 无preview_url → 使用original_url或备选URL + finalUrl = hasOriginalUrl ? res.original_url.trim() : ''; + finalPreviewUrl = finalUrl; + console.log('其他类型(无preview_url):使用original_url'); + } + } + } else { + // 如果没有找到当前文件,使用默认策略 + finalUrl = hasPreviewUrl ? res.preview_url.trim() : (hasOriginalUrl ? res.original_url.trim() : ''); + finalPreviewUrl = finalUrl; + console.log('未找到文件信息,使用默认URL策略'); + } + + if (finalUrl) { + finalUrl = decodeURIComponent(finalUrl); + finalPreviewUrl = decodeURIComponent(finalPreviewUrl); + // 同时更新状态和ref(ref会同步生效) + setFileUrl(finalUrl); + setPreviewUrl(finalPreviewUrl); + return finalUrl; + } else { + setFileUrl(''); + setPreviewUrl(''); + return ''; + } + } catch (err) { + console.error('获取文件URL失败:', err); + setFileUrl(''); + setPreviewUrl(''); + setPartitions([]); + return ''; + } finally { + setIsFetchingUrl(false); } - } else { - // 其他类型:优先使用preview_url,无则使用original_url - if (hasPreviewUrl) { - // 有preview_url → 优先使用 - finalUrl = res.preview_url.trim(); - finalPreviewUrl = res.preview_url.trim(); - console.log('其他类型:使用preview_url'); - } else { - // 无preview_url → 使用original_url或备选URL - finalUrl = hasOriginalUrl ? res.original_url.trim() : ''; - finalPreviewUrl = finalUrl; - console.log('其他类型(无preview_url):使用original_url'); - } - } - } else { - // 如果没有找到当前文件,使用默认策略 - finalUrl = hasPreviewUrl ? res.preview_url.trim() : (hasOriginalUrl ? res.original_url.trim() : ''); - finalPreviewUrl = finalUrl; - console.log('未找到文件信息,使用默认URL策略'); - } - - if (finalUrl) { - finalUrl = decodeURIComponent(finalUrl); - finalPreviewUrl = decodeURIComponent(finalPreviewUrl); - // 同时更新状态和ref(ref会同步生效) - setFileUrl(finalUrl); - setPreviewUrl(finalPreviewUrl); - return finalUrl; - } else { - setFileUrl(''); - setPreviewUrl(''); - return ''; - } - } catch (err) { - console.error('获取文件URL失败:', err); - setFileUrl(''); - setPreviewUrl(''); - setPartitions([]); - return ''; - } finally { - setIsFetchingUrl(false); - } -}, [rawFiles, hasChunkBboxes]); + }, [rawFiles, hasChunkBboxes]); @@ -286,7 +292,7 @@ const fetchFileUrl = useCallback(async (fileId) => { if (filterData) filterData({ file_ids: [newFileId] }); await fetchFileUrl(newFileId); await reload(); - setChunkSwitchTrigger(prev => prev + 1); + setChunkSwitchTrigger(prev => prev + 1); } catch (err) { console.error('文件切换失败:', err); setSelectError(err.message || '文件切换失败'); @@ -347,7 +353,8 @@ const fetchFileUrl = useCallback(async (fileId) => { // 处理分段修改(完全保留原始逻辑) const handleChunkChange = useCallback((chunkIndex, text) => { const bbox = { chunk_bboxes: selectedBbox }; - const bboxStr = JSON.stringify(bbox); + // selectedBbox空数组时,使用safeChunks的bbox + const bboxStr = selectedBbox.length ? JSON.stringify(bbox) : safeChunks[chunkIndex].bbox; captureAndAlertRequestErrorHoc(updateChunkApi({ knowledge_id: Number(id), @@ -392,7 +399,7 @@ const fetchFileUrl = useCallback(async (fileId) => { chunkIndex: item?.metadata?.chunk_index || index, bbox: item?.metadata?.bbox })); - }, [datalist, selectedFileId,chunkSwitchTrigger]); + }, [datalist, selectedFileId, chunkSwitchTrigger]); // 打开元数据弹窗(完全保留原始逻辑) const handleMetadataClick = useCallback(() => { @@ -407,8 +414,8 @@ const fetchFileUrl = useCallback(async (fileId) => { // 调整分段策略(完全保留原始逻辑) const handleAdjustSegmentation = useCallback(() => { console.log(currentFile, fileUrl, previewUrl, 789); - const currentFileUrl = latestFileUrlRef.current; - const currentPreviewUrl = latestPreviewUrlRef.current; + const currentFileUrl = latestFileUrlRef.current; + const currentPreviewUrl = latestPreviewUrlRef.current; navigate(`/filelib/adjust/${id}`, { state: { @@ -430,46 +437,46 @@ const fetchFileUrl = useCallback(async (fileId) => { }, [id, selectedFileId, currentFile, navigate]); // 解析切分策略描述(完全保留原始逻辑) - const splitRuleDesc = useCallback((file) => { - if (!file.split_rule) return ''; - const suffix = file.file_name?.split('.').pop()?.toUpperCase() || ''; - try { - const rule = JSON.parse(file.split_rule); - const { excel_rule } = rule; - - // 处理Excel文件规则 - if (excel_rule && ['XLSX', 'XLS', 'CSV'].includes(suffix)) { - return `每 ${excel_rule.slice_length} 行作为一个分段`; + const splitRuleDesc = useCallback((file) => { + if (!file.split_rule) return ''; + const suffix = file.file_name?.split('.').pop()?.toUpperCase() || ''; + try { + const rule = JSON.parse(file.split_rule); + const { excel_rule } = rule; + + // 处理Excel文件规则 + if (excel_rule && ['XLSX', 'XLS', 'CSV'].includes(suffix)) { + return `每 ${excel_rule.slice_length} 行作为一个分段`; + } + + // 处理分隔符规则 + const { separator, separator_rule } = rule; + if (separator && separator_rule && separator.length === separator_rule.length) { + const displayItems = separator.map((sep, index) => { + // 核心修复:将实际换行符转换为可见的 \n 字符串 + const displaySep = sep + .replace(/\n/g, '\\n') // 替换换行符 + .replace(/\r/g, '\\r') // 替换回车符(可选) + .replace(/\t/g, '\\t'); // 替换制表符(可选) + + // 根据规则添加切割符号 + const prefix = separator_rule[index] === 'before' ? '✂️' : ''; + const suffix = separator_rule[index] === 'after' ? '✂️' : ''; + + return `${prefix}${displaySep}${suffix}`; + }); + return displayItems.join(', '); + } + } catch (e) { + console.error('解析切分策略失败:', e); } - // 处理分隔符规则 - const { separator, separator_rule } = rule; - if (separator && separator_rule && separator.length === separator_rule.length) { - const displayItems = separator.map((sep, index) => { - // 核心修复:将实际换行符转换为可见的 \n 字符串 - const displaySep = sep - .replace(/\n/g, '\\n') // 替换换行符 - .replace(/\r/g, '\\r') // 替换回车符(可选) - .replace(/\t/g, '\\t'); // 替换制表符(可选) - - // 根据规则添加切割符号 - const prefix = separator_rule[index] === 'before' ? '✂️' : ''; - const suffix = separator_rule[index] === 'after' ? '✂️' : ''; - - return `${prefix}${displaySep}${suffix}`; - }); - return displayItems.join(', '); - } - } catch (e) { - console.error('解析切分策略失败:', e); - } - - // 解析失败时的兜底处理 - return file.split_rule - .replace(/\n/g, '\\n') - .replace(/\r/g, '\\r') - .replace(/\t/g, '\\t'); -}, []); + // 解析失败时的兜底处理 + return file.split_rule + .replace(/\n/g, '\\n') + .replace(/\r/g, '\\r') + .replace(/\t/g, '\\t'); + }, []); // 删除分段(完全保留原始逻辑) @@ -544,20 +551,17 @@ const fetchFileUrl = useCallback(async (fileId) => { const contentLayoutClass = useMemo(() => { const isSingleVisible = isPreviewVisible !== isParagraphVisible; if (isSingleVisible) { - return "flex justify-center bg-background-main"; + return "flex justify-center bg-background-main min-h-0"; } - if (isPreviewVisible && isParagraphVisible && !isExcelFile) { - return "flex bg-background-main"; - } - return "flex bg-background-main"; + return "flex bg-background-main min-h-0"; }, [isPreviewVisible, isParagraphVisible, isExcelFile]); -useEffect(() => { - latestFileUrlRef.current = fileUrl; - latestPreviewUrlRef.current = previewUrl; -}, [fileUrl, previewUrl]); + useEffect(() => { + latestFileUrlRef.current = fileUrl; + latestPreviewUrlRef.current = previewUrl; + }, [fileUrl, previewUrl]); // 渲染部分(完全保留原始样式,无任何修改) return ( -
+
{/* 顶部导航栏 */}
@@ -709,12 +713,13 @@ useEffect(() => { {/* 分段组件 */} {isParagraphVisible ? (
-
+
{

{t('文档元数据')}

- {console.log(metadataDialog.file,67678)} + {console.log(metadataDialog.file, 67678)}
{[ diff --git a/src/frontend/platform/src/pages/KnowledgePage/components/PreviewFile.tsx b/src/frontend/platform/src/pages/KnowledgePage/components/PreviewFile.tsx index 10a7235c2..6cc9cc820 100644 --- a/src/frontend/platform/src/pages/KnowledgePage/components/PreviewFile.tsx +++ b/src/frontend/platform/src/pages/KnowledgePage/components/PreviewFile.tsx @@ -28,8 +28,8 @@ export default function PreviewFile({ setChunks: any; edit?: boolean; }) { - console.log(urlState,file,rawFiles,previewUrl,67); - + console.log(urlState, file, rawFiles, previewUrl, 67); + const { t } = useTranslation('knowledge') const MemoizedFileView = React.memo(FileView); const selectedChunkIndex = useKnowledgeStore((state) => state.selectedChunkIndex); @@ -67,6 +67,7 @@ export default function PreviewFile({ // 4. 初始化标签数据(完全对齐ParagraphEdit的initData逻辑) useEffect(() => { + if (selectedChunkIndex === -1) return setLabelChange(false); // 仅对非uns类型的非PDF文件清空标签 if (suffix !== 'pdf' && !isUnsType) { @@ -232,7 +233,7 @@ export default function PreviewFile({ case 'md': return ; case 'html': return ; case 'doc': - case 'docx': return ; + case 'docx': return ; case 'png': case 'jpg': case 'jpeg': diff --git a/src/frontend/platform/src/pages/KnowledgePage/components/PreviewParagraph.tsx b/src/frontend/platform/src/pages/KnowledgePage/components/PreviewParagraph.tsx index 46d1576ad..e622f0147 100644 --- a/src/frontend/platform/src/pages/KnowledgePage/components/PreviewParagraph.tsx +++ b/src/frontend/platform/src/pages/KnowledgePage/components/PreviewParagraph.tsx @@ -226,7 +226,7 @@ const EditMarkdown = ({ data, active, fileSuffix, onClick, onDel, onChange, onPo } // 分段结果列表 -export default function PreviewParagraph({ fileId, previewCount, edit, fileSuffix, loading, chunks, onDel, onChange }) { +export default function PreviewParagraph({ fileId, previewCount, edit, fileSuffix, loading, chunks, className, onDel, onChange }) { const containerRef = useRef(null); const [visibleItems, setVisibleItems] = useState(10); // 初始加载数量 const loadingRef = useRef(false); @@ -269,13 +269,13 @@ export default function PreviewParagraph({ fileId, previewCount, edit, fileSuffi return () => container.removeEventListener('scroll', handleScroll); }, [chunks.length]); - return
+ return
{loading && (
)} -
diff --git a/src/frontend/platform/src/pages/KnowledgePage/components/PreviewResult.tsx b/src/frontend/platform/src/pages/KnowledgePage/components/PreviewResult.tsx index c1ab4c2e9..8f3a82363 100644 --- a/src/frontend/platform/src/pages/KnowledgePage/components/PreviewResult.tsx +++ b/src/frontend/platform/src/pages/KnowledgePage/components/PreviewResult.tsx @@ -189,6 +189,7 @@ export default function PreviewResult({ showPreview, previewCount, rules, step, fileSuffix={currentFile?.suffix} previewCount={previewCount} edit={step === 3} + className="h-[calc(100vh-284px)]" loading={loading} chunks={chunks} onDel={handleDelete} diff --git a/src/frontend/platform/src/pages/KnowledgePage/filesUpload.tsx b/src/frontend/platform/src/pages/KnowledgePage/filesUpload.tsx index 7d35802a3..56e84b8bb 100644 --- a/src/frontend/platform/src/pages/KnowledgePage/filesUpload.tsx +++ b/src/frontend/platform/src/pages/KnowledgePage/filesUpload.tsx @@ -60,10 +60,10 @@ export default function FilesUpload() { // 步骤3:原文对比回调,控制下一步按钮禁用状态 const handlePreviewResult = (isSuccess) => { - if (currentStep === 3) { - console.log("更新按钮状态:", { isSuccess, currentStep }); - setIsNextDisabled(!isSuccess); - } + if (currentStep === 3) { + console.log("更新按钮状态:", { isSuccess, currentStep }); + setIsNextDisabled(!isSuccess); + } }; // 下一步:按当前步骤跳转 @@ -183,9 +183,6 @@ export default function FilesUpload() { repeatCallBackRef.current(); })); }; -useEffect(() => { - console.log("父组件文件数据:", resultFiles); -}, [resultFiles]); return (
{/* 顶部返回栏 */} @@ -195,7 +192,7 @@ useEffect(() => { variant="outline" size="icon" className="bg-[#fff] size-8" - onClick={() => navigate(-1)} + onClick={() => navigate(-1)} > @@ -213,7 +210,7 @@ useEffect(() => { {/* 步骤内容区域(正常模式专属步骤) */}
-
+
{/* 步骤1:文件上传(正常模式独有) */} {currentStep === 1 && ( { { setCurrentStep(4); diff --git a/src/frontend/platform/src/pages/LogPage/useAppLog/appChatDetail.tsx b/src/frontend/platform/src/pages/LogPage/useAppLog/appChatDetail.tsx index b3f736ae2..6e68fa5a0 100644 --- a/src/frontend/platform/src/pages/LogPage/useAppLog/appChatDetail.tsx +++ b/src/frontend/platform/src/pages/LogPage/useAppLog/appChatDetail.tsx @@ -22,7 +22,7 @@ export default function AppChatDetail() { const loading = false; const title = t('log.detailedSession'); - const { loadAssistantState, destroy } = useAssistantStore() + const { assistantState, loadAssistantState, destroy } = useAssistantStore() const { loadHistoryMsg, loadMoreHistoryMsg, changeChatId, clearMsgs } = useMessageStore() const { loadHistoryMsg: loadFlowHistoryMsg, @@ -49,7 +49,7 @@ export default function AppChatDetail() { } }, []) - const logo = useAppAvatar(cid, type) + const logo = useAppAvatar(cid, type, assistantState) return
{loading &&
@@ -81,7 +81,7 @@ export default function AppChatDetail() { }; -const useAppAvatar = (cid, flowType) => { +const useAppAvatar = (cid, flowType, assistantState) => { const [logo, setLogo] = useState('') const [title, setTitle] = useState('') const loadAppDetail = async () => { @@ -89,9 +89,14 @@ const useAppAvatar = (cid, flowType) => { setLogo(lostflow.flow_logo) setTitle(lostflow.flow_name) } + useEffect(() => { - loadAppDetail() + if (flowType !== AppNumType.ASSISTANT) { + loadAppDetail() + } }, []) - return + return flowType === AppNumType.ASSISTANT ? + : + } \ No newline at end of file