You've already forked DataMate
feat(rag): 添加相对路径搜索功能并优化文件显示
- 在RagFileRepositoryImpl中新增relativePath字段和路径模式构建方法 - 实现buildRelativePathPattern方法用于构建相对路径搜索模式 - 修改page方法添加相对路径模糊查询支持 - 在RagFileReq DTO中添加relativePath参数字段 - 优化KnowledgeBaseDetail页面中的文件名显示逻辑 - 添加normalizePath函数处理文件路径规范化显示
This commit is contained in:
@@ -20,6 +20,8 @@ import java.util.List;
|
|||||||
*/
|
*/
|
||||||
@Repository
|
@Repository
|
||||||
public class RagFileRepositoryImpl extends CrudRepository<RagFileMapper, RagFile> implements RagFileRepository {
|
public class RagFileRepositoryImpl extends CrudRepository<RagFileMapper, RagFile> implements RagFileRepository {
|
||||||
|
private static final String RELATIVE_PATH_KEY = "\"relativePath\":\"";
|
||||||
|
private static final String PATH_SEPARATOR = "/";
|
||||||
@Override
|
@Override
|
||||||
public void removeByKnowledgeBaseId(String knowledgeBaseId) {
|
public void removeByKnowledgeBaseId(String knowledgeBaseId) {
|
||||||
lambdaUpdate().eq(RagFile::getKnowledgeBaseId, knowledgeBaseId).remove();
|
lambdaUpdate().eq(RagFile::getKnowledgeBaseId, knowledgeBaseId).remove();
|
||||||
@@ -42,9 +44,25 @@ public class RagFileRepositoryImpl extends CrudRepository<RagFileMapper, RagFile
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IPage<RagFile> page(IPage<RagFile> page, RagFileReq request) {
|
public IPage<RagFile> page(IPage<RagFile> page, RagFileReq request) {
|
||||||
|
String relativePathPattern = buildRelativePathPattern(request.getRelativePath());
|
||||||
return lambdaQuery()
|
return lambdaQuery()
|
||||||
.eq(RagFile::getKnowledgeBaseId, request.getKnowledgeBaseId())
|
.eq(RagFile::getKnowledgeBaseId, request.getKnowledgeBaseId())
|
||||||
.like(StringUtils.hasText(request.getFileName()), RagFile::getFileName, request.getFileName())
|
.like(StringUtils.hasText(request.getFileName()), RagFile::getFileName, request.getFileName())
|
||||||
|
.like(StringUtils.hasText(relativePathPattern), RagFile::getMetadata, relativePathPattern)
|
||||||
.page(page);
|
.page(page);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String buildRelativePathPattern(String relativePath) {
|
||||||
|
if (!StringUtils.hasText(relativePath)) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
String normalized = relativePath.replace("\\", PATH_SEPARATOR).trim();
|
||||||
|
while (normalized.startsWith(PATH_SEPARATOR)) {
|
||||||
|
normalized = normalized.substring(1);
|
||||||
|
}
|
||||||
|
if (!StringUtils.hasText(normalized)) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return RELATIVE_PATH_KEY + normalized;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,5 +14,6 @@ import lombok.Setter;
|
|||||||
@Getter
|
@Getter
|
||||||
public class RagFileReq extends PagingQuery {
|
public class RagFileReq extends PagingQuery {
|
||||||
private String fileName;
|
private String fileName;
|
||||||
|
private String relativePath;
|
||||||
private String knowledgeBaseId;
|
private String knowledgeBaseId;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -124,10 +124,14 @@ const KnowledgeBaseDetailPage: React.FC = () => {
|
|||||||
const pageSize = 200;
|
const pageSize = 200;
|
||||||
let page = 0;
|
let page = 0;
|
||||||
let combined: KBFile[] = [];
|
let combined: KBFile[] = [];
|
||||||
|
const currentPrefix = normalizePrefix(filePrefix);
|
||||||
|
const keyword = fileKeyword.trim();
|
||||||
while (true) {
|
while (true) {
|
||||||
const { data } = await queryKnowledgeBaseFilesUsingGet(id, {
|
const { data } = await queryKnowledgeBaseFilesUsingGet(id, {
|
||||||
page,
|
page,
|
||||||
size: pageSize,
|
size: pageSize,
|
||||||
|
...(currentPrefix ? { relativePath: currentPrefix } : {}),
|
||||||
|
...(keyword ? { fileName: keyword } : {}),
|
||||||
});
|
});
|
||||||
const content = Array.isArray(data?.content) ? data.content : [];
|
const content = Array.isArray(data?.content) ? data.content : [];
|
||||||
combined = combined.concat(content.map(mapFileData));
|
combined = combined.concat(content.map(mapFileData));
|
||||||
@@ -146,14 +150,19 @@ const KnowledgeBaseDetailPage: React.FC = () => {
|
|||||||
} finally {
|
} finally {
|
||||||
setFilesLoading(false);
|
setFilesLoading(false);
|
||||||
}
|
}
|
||||||
}, [id, message]);
|
}, [id, filePrefix, fileKeyword, message]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (id) {
|
if (id) {
|
||||||
fetchKnowledgeBaseDetails(id);
|
fetchKnowledgeBaseDetails(id);
|
||||||
|
}
|
||||||
|
}, [id, fetchKnowledgeBaseDetails]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (id) {
|
||||||
fetchFiles();
|
fetchFiles();
|
||||||
}
|
}
|
||||||
}, [id, fetchKnowledgeBaseDetails, fetchFiles]);
|
}, [id, fetchFiles]);
|
||||||
|
|
||||||
// File table logic
|
// File table logic
|
||||||
const handleDeleteFile = async (file: KBFileRow) => {
|
const handleDeleteFile = async (file: KBFileRow) => {
|
||||||
@@ -257,8 +266,7 @@ const KnowledgeBaseDetailPage: React.FC = () => {
|
|||||||
const normalizedPrefix = useMemo(() => normalizePrefix(filePrefix), [filePrefix]);
|
const normalizedPrefix = useMemo(() => normalizePrefix(filePrefix), [filePrefix]);
|
||||||
|
|
||||||
const { rows: fileRows, total: fileTotal } = useMemo(() => {
|
const { rows: fileRows, total: fileTotal } = useMemo(() => {
|
||||||
const keyword = fileKeyword.trim().toLowerCase();
|
const folderMap = new Map<string, { name: string; fileCount: number }>();
|
||||||
const folderMap = new Map<string, { name: string; fileCount: number; hasMatch: boolean }>();
|
|
||||||
const fileItems: KBFileRow[] = [];
|
const fileItems: KBFileRow[] = [];
|
||||||
|
|
||||||
allFiles.forEach((file) => {
|
allFiles.forEach((file) => {
|
||||||
@@ -271,31 +279,22 @@ const KnowledgeBaseDetailPage: React.FC = () => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const leafName = segments[0];
|
const leafName = segments[0];
|
||||||
const fileMatches =
|
|
||||||
!keyword ||
|
|
||||||
leafName.toLowerCase().includes(keyword) ||
|
|
||||||
fullPath.toLowerCase().includes(keyword);
|
|
||||||
|
|
||||||
if (segments.length > 1) {
|
if (segments.length > 1) {
|
||||||
const folderName = leafName;
|
const folderName = leafName;
|
||||||
const entry = folderMap.get(folderName) || {
|
const entry = folderMap.get(folderName) || {
|
||||||
name: folderName,
|
name: folderName,
|
||||||
fileCount: 0,
|
fileCount: 0,
|
||||||
hasMatch: false,
|
|
||||||
};
|
};
|
||||||
entry.fileCount += 1;
|
entry.fileCount += 1;
|
||||||
if (fileMatches) {
|
|
||||||
entry.hasMatch = true;
|
|
||||||
}
|
|
||||||
folderMap.set(folderName, entry);
|
folderMap.set(folderName, entry);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!fileMatches) {
|
const normalizedFileName = normalizePath(file.fileName);
|
||||||
return;
|
const displayName = normalizedFileName.includes(PATH_SEPARATOR)
|
||||||
}
|
? leafName
|
||||||
|
: file.fileName || leafName;
|
||||||
const displayName = file.fileName || leafName;
|
|
||||||
fileItems.push({
|
fileItems.push({
|
||||||
...file,
|
...file,
|
||||||
name: displayName,
|
name: displayName,
|
||||||
@@ -304,17 +303,8 @@ const KnowledgeBaseDetailPage: React.FC = () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
const folderItems: KBFileRow[] = Array.from(folderMap.values())
|
const folderItems: KBFileRow[] = Array.from(folderMap.values()).map(
|
||||||
.filter((entry) => {
|
(entry) =>
|
||||||
if (!keyword) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
entry.hasMatch ||
|
|
||||||
entry.name.toLowerCase().includes(keyword)
|
|
||||||
);
|
|
||||||
})
|
|
||||||
.map((entry) =>
|
|
||||||
({
|
({
|
||||||
id: `directory-${normalizedPrefix}${entry.name}`,
|
id: `directory-${normalizedPrefix}${entry.name}`,
|
||||||
fileName: entry.name,
|
fileName: entry.name,
|
||||||
@@ -346,7 +336,7 @@ const KnowledgeBaseDetailPage: React.FC = () => {
|
|||||||
|
|
||||||
const combined = [...folderItems, ...fileItems];
|
const combined = [...folderItems, ...fileItems];
|
||||||
return { rows: combined, total: combined.length };
|
return { rows: combined, total: combined.length };
|
||||||
}, [allFiles, fileKeyword, knowledgeBase?.id, normalizedPrefix]);
|
}, [allFiles, knowledgeBase?.id, normalizedPrefix]);
|
||||||
|
|
||||||
const filePageCurrent = filePagination.current;
|
const filePageCurrent = filePagination.current;
|
||||||
const filePageSize = filePagination.pageSize;
|
const filePageSize = filePagination.pageSize;
|
||||||
|
|||||||
Reference in New Issue
Block a user