From 76f70a68475584004b7e89971865c64170e850b4 Mon Sep 17 00:00:00 2001 From: Jerry Yan <792602257@qq.com> Date: Fri, 30 Jan 2026 22:23:52 +0800 Subject: [PATCH] =?UTF-8?q?feat(knowledge-base):=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E7=9F=A5=E8=AF=86=E5=BA=93=E6=96=87=E4=BB=B6=E5=85=A8=E5=BA=93?= =?UTF-8?q?=E6=A3=80=E7=B4=A2=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增相对路径字段替代原有的metadata存储方式 - 实现跨知识库文件检索接口searchFiles - 添加前端全库检索页面和相关API调用 - 优化文件路径处理和数据库索引配置 - 统一请求参数类型定义为RequestPayload和RequestParams - 简化RagFile模型中的元数据结构设计 --- .../application/KnowledgeBaseService.java | 45 +++- .../rag/indexer/domain/model/RagFile.java | 4 + .../domain/repository/RagFileRepository.java | 3 + .../impl/RagFileRepositoryImpl.java | 21 +- .../interfaces/KnowledgeBaseController.java | 13 +- .../dto/KnowledgeBaseFileSearchReq.java | 19 ++ .../dto/KnowledgeBaseFileSearchResp.java | 27 +++ .../Detail/KnowledgeBaseDetail.tsx | 21 +- .../KnowledgeBase/Home/KnowledgeBasePage.tsx | 43 ++-- .../Search/KnowledgeBaseSearch.tsx | 217 ++++++++++++++++++ .../pages/KnowledgeBase/knowledge-base.api.ts | 20 +- .../KnowledgeBase/knowledge-base.model.ts | 44 +--- frontend/src/routes/routes.ts | 5 + scripts/db/rag-management-init.sql | 4 + 14 files changed, 403 insertions(+), 83 deletions(-) create mode 100644 backend/services/rag-indexer-service/src/main/java/com/datamate/rag/indexer/interfaces/dto/KnowledgeBaseFileSearchReq.java create mode 100644 backend/services/rag-indexer-service/src/main/java/com/datamate/rag/indexer/interfaces/dto/KnowledgeBaseFileSearchResp.java create mode 100644 frontend/src/pages/KnowledgeBase/Search/KnowledgeBaseSearch.tsx diff --git a/backend/services/rag-indexer-service/src/main/java/com/datamate/rag/indexer/application/KnowledgeBaseService.java b/backend/services/rag-indexer-service/src/main/java/com/datamate/rag/indexer/application/KnowledgeBaseService.java index 4ffbbc2..6f24f1b 100644 --- a/backend/services/rag-indexer-service/src/main/java/com/datamate/rag/indexer/application/KnowledgeBaseService.java +++ b/backend/services/rag-indexer-service/src/main/java/com/datamate/rag/indexer/application/KnowledgeBaseService.java @@ -35,10 +35,10 @@ import org.springframework.transaction.annotation.Transactional; import org.springframework.util.StringUtils; import java.util.Collections; -import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.stream.Collectors; /** * 知识库服务类 @@ -49,7 +49,6 @@ import java.util.Optional; @Service @RequiredArgsConstructor public class KnowledgeBaseService { - private static final String RELATIVE_PATH_KEY = "relativePath"; private static final String PATH_SEPARATOR = "/"; private final KnowledgeBaseRepository knowledgeBaseRepository; private final RagFileRepository ragFileRepository; @@ -150,12 +149,7 @@ public class KnowledgeBaseService { ragFile.setKnowledgeBaseId(knowledgeBase.getId()); ragFile.setFileId(fileInfo.id()); ragFile.setFileName(fileInfo.fileName()); - String relativePath = normalizeRelativePath(fileInfo.relativePath()); - if (StringUtils.hasText(relativePath)) { - Map metadata = new HashMap<>(); - metadata.put(RELATIVE_PATH_KEY, relativePath); - ragFile.setMetadata(metadata); - } + ragFile.setRelativePath(normalizeRelativePath(fileInfo.relativePath())); ragFile.setStatus(FileStatus.UNPROCESSED); return ragFile; }).toList(); @@ -181,6 +175,41 @@ public class KnowledgeBaseService { return PagedResponse.of(page.getRecords(), page.getCurrent(), page.getTotal(), page.getPages()); } + public PagedResponse searchFiles(KnowledgeBaseFileSearchReq request) { + IPage page = new Page<>(request.getPage(), request.getSize()); + page = ragFileRepository.searchPage(page, request); + List records = page.getRecords(); + if (records.isEmpty()) { + return PagedResponse.of(Collections.emptyList(), page.getCurrent(), page.getTotal(), page.getPages()); + } + + List knowledgeBaseIds = records.stream() + .map(RagFile::getKnowledgeBaseId) + .filter(StringUtils::hasText) + .distinct() + .toList(); + Map knowledgeBaseNameMap = knowledgeBaseRepository.listByIds(knowledgeBaseIds).stream() + .collect(Collectors.toMap(KnowledgeBase::getId, KnowledgeBase::getName)); + + List responses = records.stream() + .map(file -> { + KnowledgeBaseFileSearchResp resp = new KnowledgeBaseFileSearchResp(); + resp.setId(file.getId()); + resp.setKnowledgeBaseId(file.getKnowledgeBaseId()); + resp.setKnowledgeBaseName(knowledgeBaseNameMap.getOrDefault(file.getKnowledgeBaseId(), "")); + resp.setFileName(file.getFileName()); + resp.setRelativePath(file.getRelativePath()); + resp.setChunkCount(file.getChunkCount()); + resp.setStatus(file.getStatus()); + resp.setCreatedAt(file.getCreatedAt()); + resp.setUpdatedAt(file.getUpdatedAt()); + return resp; + }) + .toList(); + + return PagedResponse.of(responses, page.getCurrent(), page.getTotal(), page.getPages()); + } + @Transactional(rollbackFor = Exception.class) public void deleteFiles(String knowledgeBaseId, DeleteFilesReq request) { KnowledgeBase knowledgeBase = Optional.ofNullable(knowledgeBaseRepository.getById(knowledgeBaseId)) diff --git a/backend/services/rag-indexer-service/src/main/java/com/datamate/rag/indexer/domain/model/RagFile.java b/backend/services/rag-indexer-service/src/main/java/com/datamate/rag/indexer/domain/model/RagFile.java index 64a3d78..e90c3b4 100644 --- a/backend/services/rag-indexer-service/src/main/java/com/datamate/rag/indexer/domain/model/RagFile.java +++ b/backend/services/rag-indexer-service/src/main/java/com/datamate/rag/indexer/domain/model/RagFile.java @@ -28,6 +28,10 @@ public class RagFile extends BaseEntity { * 文件名 */ private String fileName; + /** + * 相对路径 + */ + private String relativePath; /** * 文件ID */ diff --git a/backend/services/rag-indexer-service/src/main/java/com/datamate/rag/indexer/domain/repository/RagFileRepository.java b/backend/services/rag-indexer-service/src/main/java/com/datamate/rag/indexer/domain/repository/RagFileRepository.java index 217f206..61b86dd 100644 --- a/backend/services/rag-indexer-service/src/main/java/com/datamate/rag/indexer/domain/repository/RagFileRepository.java +++ b/backend/services/rag-indexer-service/src/main/java/com/datamate/rag/indexer/domain/repository/RagFileRepository.java @@ -3,6 +3,7 @@ package com.datamate.rag.indexer.domain.repository; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.repository.IRepository; import com.datamate.rag.indexer.domain.model.RagFile; +import com.datamate.rag.indexer.interfaces.dto.KnowledgeBaseFileSearchReq; import com.datamate.rag.indexer.interfaces.dto.RagFileReq; import java.util.List; @@ -21,4 +22,6 @@ public interface RagFileRepository extends IRepository { List findAllByKnowledgeBaseId(String knowledgeBaseId); IPage page(IPage page, RagFileReq request); + + IPage searchPage(IPage page, KnowledgeBaseFileSearchReq request); } diff --git a/backend/services/rag-indexer-service/src/main/java/com/datamate/rag/indexer/infrastructure/persistence/impl/RagFileRepositoryImpl.java b/backend/services/rag-indexer-service/src/main/java/com/datamate/rag/indexer/infrastructure/persistence/impl/RagFileRepositoryImpl.java index 1724ba7..14b4dd8 100644 --- a/backend/services/rag-indexer-service/src/main/java/com/datamate/rag/indexer/infrastructure/persistence/impl/RagFileRepositoryImpl.java +++ b/backend/services/rag-indexer-service/src/main/java/com/datamate/rag/indexer/infrastructure/persistence/impl/RagFileRepositoryImpl.java @@ -6,6 +6,7 @@ import com.datamate.rag.indexer.domain.model.FileStatus; import com.datamate.rag.indexer.domain.model.RagFile; import com.datamate.rag.indexer.domain.repository.RagFileRepository; import com.datamate.rag.indexer.infrastructure.persistence.mapper.RagFileMapper; +import com.datamate.rag.indexer.interfaces.dto.KnowledgeBaseFileSearchReq; import com.datamate.rag.indexer.interfaces.dto.RagFileReq; import org.springframework.stereotype.Repository; import org.springframework.util.StringUtils; @@ -20,7 +21,6 @@ import java.util.List; */ @Repository public class RagFileRepositoryImpl extends CrudRepository implements RagFileRepository { - private static final String RELATIVE_PATH_KEY = "\"relativePath\":\""; private static final String PATH_SEPARATOR = "/"; @Override public void removeByKnowledgeBaseId(String knowledgeBaseId) { @@ -44,15 +44,23 @@ public class RagFileRepositoryImpl extends CrudRepository page(IPage page, RagFileReq request) { - String relativePathPattern = buildRelativePathPattern(request.getRelativePath()); return lambdaQuery() .eq(RagFile::getKnowledgeBaseId, request.getKnowledgeBaseId()) .like(StringUtils.hasText(request.getFileName()), RagFile::getFileName, request.getFileName()) - .like(StringUtils.hasText(relativePathPattern), RagFile::getMetadata, relativePathPattern) + .likeRight(StringUtils.hasText(request.getRelativePath()), RagFile::getRelativePath, normalizeRelativePath(request.getRelativePath())) .page(page); } - private String buildRelativePathPattern(String relativePath) { + @Override + public IPage searchPage(IPage page, KnowledgeBaseFileSearchReq request) { + return lambdaQuery() + .eq(StringUtils.hasText(request.getKnowledgeBaseId()), RagFile::getKnowledgeBaseId, request.getKnowledgeBaseId()) + .like(StringUtils.hasText(request.getFileName()), RagFile::getFileName, request.getFileName()) + .likeRight(StringUtils.hasText(request.getRelativePath()), RagFile::getRelativePath, normalizeRelativePath(request.getRelativePath())) + .page(page); + } + + private String normalizeRelativePath(String relativePath) { if (!StringUtils.hasText(relativePath)) { return ""; } @@ -60,9 +68,6 @@ public class RagFileRepositoryImpl extends CrudRepository searchFiles(KnowledgeBaseFileSearchReq request) { + return knowledgeBaseService.searchFiles(request); + } + /** * 删除知识库文件 * @@ -141,4 +152,4 @@ public class KnowledgeBaseController { public List retrieve(@RequestBody @Valid RetrieveReq request) { return knowledgeBaseService.retrieve(request); } -} \ No newline at end of file +} diff --git a/backend/services/rag-indexer-service/src/main/java/com/datamate/rag/indexer/interfaces/dto/KnowledgeBaseFileSearchReq.java b/backend/services/rag-indexer-service/src/main/java/com/datamate/rag/indexer/interfaces/dto/KnowledgeBaseFileSearchReq.java new file mode 100644 index 0000000..1def85d --- /dev/null +++ b/backend/services/rag-indexer-service/src/main/java/com/datamate/rag/indexer/interfaces/dto/KnowledgeBaseFileSearchReq.java @@ -0,0 +1,19 @@ +package com.datamate.rag.indexer.interfaces.dto; + +import com.datamate.common.interfaces.PagingQuery; +import lombok.Getter; +import lombok.Setter; + +/** + * 知识库文件全库检索请求 + * + * @author dallas + * @since 2026-01-30 + */ +@Getter +@Setter +public class KnowledgeBaseFileSearchReq extends PagingQuery { + private String fileName; + private String relativePath; + private String knowledgeBaseId; +} diff --git a/backend/services/rag-indexer-service/src/main/java/com/datamate/rag/indexer/interfaces/dto/KnowledgeBaseFileSearchResp.java b/backend/services/rag-indexer-service/src/main/java/com/datamate/rag/indexer/interfaces/dto/KnowledgeBaseFileSearchResp.java new file mode 100644 index 0000000..dfff3a9 --- /dev/null +++ b/backend/services/rag-indexer-service/src/main/java/com/datamate/rag/indexer/interfaces/dto/KnowledgeBaseFileSearchResp.java @@ -0,0 +1,27 @@ +package com.datamate.rag.indexer.interfaces.dto; + +import com.datamate.rag.indexer.domain.model.FileStatus; +import lombok.Getter; +import lombok.Setter; + +import java.time.LocalDateTime; + +/** + * 知识库文件全库检索响应 + * + * @author dallas + * @since 2026-01-30 + */ +@Getter +@Setter +public class KnowledgeBaseFileSearchResp { + private String id; + private String knowledgeBaseId; + private String knowledgeBaseName; + private String fileName; + private String relativePath; + private Integer chunkCount; + private FileStatus status; + private LocalDateTime createdAt; + private LocalDateTime updatedAt; +} diff --git a/frontend/src/pages/KnowledgeBase/Detail/KnowledgeBaseDetail.tsx b/frontend/src/pages/KnowledgeBase/Detail/KnowledgeBaseDetail.tsx index 880b9bb..4de58da 100644 --- a/frontend/src/pages/KnowledgeBase/Detail/KnowledgeBaseDetail.tsx +++ b/frontend/src/pages/KnowledgeBase/Detail/KnowledgeBaseDetail.tsx @@ -17,7 +17,7 @@ import { EditOutlined, ReloadOutlined, } from "@ant-design/icons"; -import { useNavigate, useParams } from "react-router"; +import { useNavigate, useParams, useSearchParams } from "react-router"; import DetailHeader from "@/components/DetailHeader"; import { SearchControls } from "@/components/SearchControls"; import { KBFile, KnowledgeBaseItem } from "../knowledge-base.model"; @@ -58,7 +58,6 @@ type KBFileRow = KBFile & { }; const PATH_SEPARATOR = "/"; -const RELATIVE_PATH_KEY = "relativePath"; const normalizePath = (value?: string) => (value ?? "").replace(/\\/g, PATH_SEPARATOR); @@ -81,17 +80,13 @@ const splitRelativePath = (fullPath: string, prefix: string) => { }; const resolveFileRelativePath = (file: KBFile) => { - const metadata = file?.metadata as Record | undefined; - const metadataPath = - metadata && typeof metadata[RELATIVE_PATH_KEY] === "string" - ? String(metadata[RELATIVE_PATH_KEY]) - : ""; - const rawPath = metadataPath || file.fileName || file.name || ""; + const rawPath = file.relativePath || file.fileName || file.name || ""; return normalizePath(rawPath).replace(/^\/+/, ""); }; const KnowledgeBaseDetailPage: React.FC = () => { const navigate = useNavigate(); + const [searchParams] = useSearchParams(); const { message } = App.useApp(); const { id } = useParams<{ id: string }>(); const [knowledgeBase, setKnowledgeBase] = useState(undefined); @@ -158,6 +153,16 @@ const KnowledgeBaseDetailPage: React.FC = () => { } }, [id, fetchKnowledgeBaseDetails]); + useEffect(() => { + if (!id) { + return; + } + const prefixParam = searchParams.get("prefix"); + const fileNameParam = searchParams.get("fileName"); + setFilePrefix(prefixParam ? normalizePrefix(prefixParam) : ""); + setFileKeyword(fileNameParam ? fileNameParam : ""); + }, [id, searchParams]); + useEffect(() => { if (id) { fetchFiles(); diff --git a/frontend/src/pages/KnowledgeBase/Home/KnowledgeBasePage.tsx b/frontend/src/pages/KnowledgeBase/Home/KnowledgeBasePage.tsx index eb1c92c..55ddb53 100644 --- a/frontend/src/pages/KnowledgeBase/Home/KnowledgeBasePage.tsx +++ b/frontend/src/pages/KnowledgeBase/Home/KnowledgeBasePage.tsx @@ -37,7 +37,7 @@ export default function KnowledgeBasePage() { await deleteKnowledgeBaseByIdUsingDelete(kb.id); message.success("知识库删除成功"); fetchData(); - } catch (error) { + } catch { message.error("知识库删除失败"); } }; @@ -47,7 +47,7 @@ export default function KnowledgeBasePage() { key: "edit", label: "编辑", icon: , - onClick: (item) => { + onClick: (item: KnowledgeBaseItem) => { setIsEdit(true); setCurrentKB(item); }, @@ -64,7 +64,7 @@ export default function KnowledgeBasePage() { okType: "danger", cancelText: "取消", }, - onClick: (item) => handleDeleteKB(item), + onClick: (item: KnowledgeBaseItem) => handleDeleteKB(item), }, ]; @@ -76,7 +76,7 @@ export default function KnowledgeBasePage() { fixed: "left" as const, width: 200, ellipsis: true, - render: (_: any, kb: KnowledgeBaseItem) => ( + render: (_: unknown, kb: KnowledgeBaseItem) => ( + { + fetchData(); + }} + onClose={() => { + setIsEdit(false); + setCurrentKB(null); + }} + /> + navigate(`/data/knowledge-base/detail/${item.id}`)} + onView={(item: KnowledgeBaseItem) => + navigate(`/data/knowledge-base/detail/${item.id}`) + } pagination={pagination} /> ) : ( @@ -177,4 +184,4 @@ export default function KnowledgeBasePage() { )} ); -} \ No newline at end of file +} diff --git a/frontend/src/pages/KnowledgeBase/Search/KnowledgeBaseSearch.tsx b/frontend/src/pages/KnowledgeBase/Search/KnowledgeBaseSearch.tsx new file mode 100644 index 0000000..dc7ff4a --- /dev/null +++ b/frontend/src/pages/KnowledgeBase/Search/KnowledgeBaseSearch.tsx @@ -0,0 +1,217 @@ +import { useCallback, useMemo, useState } from "react"; +import { App, Badge, Breadcrumb, Button, Input, Table } from "antd"; +import { useNavigate } from "react-router"; +import { + KBFileStatus, + KnowledgeBaseFileSearchResult, +} from "../knowledge-base.model"; +import { KBFileStatusMap } from "../knowledge-base.const"; +import { queryKnowledgeBaseFilesSearchUsingGet } from "../knowledge-base.api"; +import { formatDateTime } from "@/utils/unit"; + +const PATH_SEPARATOR = "/"; + +const normalizePath = (value?: string) => + (value ?? "").replace(/\\/g, PATH_SEPARATOR); + +const resolvePrefix = (relativePath?: string) => { + const normalized = normalizePath(relativePath); + const parts = normalized.split(PATH_SEPARATOR).filter(Boolean); + if (parts.length <= 1) { + return ""; + } + parts.pop(); + return `${parts.join(PATH_SEPARATOR)}${PATH_SEPARATOR}`; +}; + +export default function KnowledgeBaseSearch() { + const navigate = useNavigate(); + const { message } = App.useApp(); + const [searchTerm, setSearchTerm] = useState(""); + const [activeKeyword, setActiveKeyword] = useState(""); + const [loading, setLoading] = useState(false); + const [searched, setSearched] = useState(false); + const [results, setResults] = useState([]); + const [pagination, setPagination] = useState({ + current: 1, + pageSize: 10, + total: 0, + }); + + const fetchResults = useCallback( + async (keyword: string, page?: number, pageSize?: number) => { + const resolvedPage = page ?? pagination.current; + const resolvedPageSize = pageSize ?? pagination.pageSize; + if (!keyword) { + setResults([]); + setPagination((prev) => ({ ...prev, total: 0, current: resolvedPage })); + setSearched(false); + return; + } + setLoading(true); + try { + const { data } = await queryKnowledgeBaseFilesSearchUsingGet({ + fileName: keyword, + page: Math.max(resolvedPage - 1, 0), + size: resolvedPageSize, + }); + const content = Array.isArray(data?.content) ? data.content : []; + setResults(content); + setPagination({ + current: resolvedPage, + pageSize: resolvedPageSize, + total: data?.totalElements ?? 0, + }); + setSearched(true); + } catch (error) { + console.error("Failed to search knowledge base files:", error); + message.error("检索失败,请稍后重试"); + } finally { + setLoading(false); + } + }, + [message, pagination] + ); + + const handleSearch = (value?: string) => { + const keyword = (value ?? searchTerm).trim(); + if (!keyword) { + message.warning("请输入文件名"); + return; + } + setActiveKeyword(keyword); + fetchResults(keyword, 1, pagination.pageSize); + }; + + const columns = useMemo( + () => [ + { + title: "知识库", + dataIndex: "knowledgeBaseName", + key: "knowledgeBaseName", + width: 220, + ellipsis: true, + render: (text: string) => text || "-", + }, + { + title: "文件名", + dataIndex: "fileName", + key: "fileName", + width: 220, + ellipsis: true, + }, + { + title: "相对路径", + dataIndex: "relativePath", + key: "relativePath", + ellipsis: true, + render: (value: string) => value || "-", + }, + { + title: "状态", + dataIndex: "status", + key: "status", + width: 120, + render: (status?: KBFileStatus) => { + const config = status ? KBFileStatusMap[status] : undefined; + if (!config) { + return ; + } + return ; + }, + }, + { + title: "更新时间", + dataIndex: "updatedAt", + key: "updatedAt", + width: 180, + ellipsis: true, + render: (value: string) => formatDateTime(value) || "-", + }, + { + title: "操作", + key: "action", + width: 120, + align: "right" as const, + render: (_: unknown, record: KnowledgeBaseFileSearchResult) => ( + + ), + }, + ], + [navigate] + ); + + return ( +
+ + + navigate("/data/knowledge-base")}>知识库 + + 全库搜索 + +
+

知识库全库检索

+
+
+ setSearchTerm(event.target.value)} + onSearch={handleSearch} + placeholder="输入文件名,回车或点击搜索" + enterButton="搜索" + loading={loading} + /> +
+ `共 ${total} 条`, + onChange: (page, pageSize) => { + const nextKeyword = activeKeyword.trim(); + if (!nextKeyword) { + message.warning("请输入文件名"); + return; + } + fetchResults(nextKeyword, page, pageSize || pagination.pageSize); + }, + }} + locale={{ + emptyText: searched ? "暂无匹配文件" : "请输入文件名开始检索", + }} + onRow={(record) => ({ + onClick: () => { + const prefix = resolvePrefix(record.relativePath); + const searchParams = new URLSearchParams(); + if (prefix) { + searchParams.set("prefix", prefix); + } + navigate( + `/data/knowledge-base/detail/${record.knowledgeBaseId}?${searchParams.toString()}` + ); + }, + })} + /> + + ); +} diff --git a/frontend/src/pages/KnowledgeBase/knowledge-base.api.ts b/frontend/src/pages/KnowledgeBase/knowledge-base.api.ts index b7992da..013039a 100644 --- a/frontend/src/pages/KnowledgeBase/knowledge-base.api.ts +++ b/frontend/src/pages/KnowledgeBase/knowledge-base.api.ts @@ -1,12 +1,15 @@ import { get, post, put, del } from "@/utils/request"; +type RequestPayload = Record; +type RequestParams = Record; + // 获取知识库列表 -export function queryKnowledgeBasesUsingPost(params: any) { +export function queryKnowledgeBasesUsingPost(params: RequestPayload) { return post("/api/knowledge-base/list", params); } // 创建知识库 -export function createKnowledgeBaseUsingPost(data: any) { +export function createKnowledgeBaseUsingPost(data: RequestPayload) { return post("/api/knowledge-base/create", data); } @@ -16,7 +19,7 @@ export function queryKnowledgeBaseByIdUsingGet(baseId: string) { } // 更新知识库 -export function updateKnowledgeBaseByIdUsingPut(baseId: string, data: any) { +export function updateKnowledgeBaseByIdUsingPut(baseId: string, data: RequestPayload) { return put(`/api/knowledge-base/${baseId}`, data); } @@ -26,17 +29,22 @@ export function deleteKnowledgeBaseByIdUsingDelete(baseId: string) { } // 获取知识生成文件列表 -export function queryKnowledgeBaseFilesUsingGet(baseId: string, data) { +export function queryKnowledgeBaseFilesUsingGet(baseId: string, data: RequestParams) { return get(`/api/knowledge-base/${baseId}/files`, data); } +// 全库检索知识库文件 +export function queryKnowledgeBaseFilesSearchUsingGet(params: RequestParams) { + return get("/api/knowledge-base/files/search", params); +} + // 添加文件到知识库 -export function addKnowledgeBaseFilesUsingPost(baseId: string, data: any) { +export function addKnowledgeBaseFilesUsingPost(baseId: string, data: RequestPayload) { return post(`/api/knowledge-base/${baseId}/files`, data); } // 删除知识生成文件 -export function deleteKnowledgeBaseFileByIdUsingDelete(baseId: string, data: any) { +export function deleteKnowledgeBaseFileByIdUsingDelete(baseId: string, data: RequestPayload) { return del(`/api/knowledge-base/${baseId}/files`, data); } diff --git a/frontend/src/pages/KnowledgeBase/knowledge-base.model.ts b/frontend/src/pages/KnowledgeBase/knowledge-base.model.ts index 4e0c3a3..acfc91c 100644 --- a/frontend/src/pages/KnowledgeBase/knowledge-base.model.ts +++ b/frontend/src/pages/KnowledgeBase/knowledge-base.model.ts @@ -29,50 +29,26 @@ export interface KBFile { id: string; fileName: string; name?: string; + relativePath?: string; createdAt: string; updatedAt: string; status: KBFileStatus; chunkCount: number; - metadata: Record; + metadata: Record; knowledgeBaseId: string; fileId: string; updatedBy: string; createdBy: string; } -interface Chunk { - id: number; - content: string; - position: number; - tokens: number; - embedding?: number[]; - similarity?: string; +export interface KnowledgeBaseFileSearchResult { + id: string; + knowledgeBaseId: string; + knowledgeBaseName: string; + fileName: string; + relativePath?: string; + status?: KBFileStatus; + chunkCount?: number; createdAt?: string; updatedAt?: string; - vectorId?: string; - sliceOperator?: string; - parentChunkId?: number; - metadata?: { - source: string; - page?: number; - section?: string; - }; -} - -interface VectorizationRecord { - id: number; - timestamp: string; - operation: "create" | "update" | "delete" | "reprocess"; - fileId: number; - fileName: string; - chunksProcessed: number; - vectorsGenerated: number; - status: "success" | "failed" | "partial"; - duration: string; - config: { - embeddingModel: string; - chunkSize: number; - sliceMethod: string; - }; - error?: string; } diff --git a/frontend/src/routes/routes.ts b/frontend/src/routes/routes.ts index 16f71c3..221192d 100644 --- a/frontend/src/routes/routes.ts +++ b/frontend/src/routes/routes.ts @@ -30,6 +30,7 @@ import ManualEvaluatePage from "@/pages/DataEvaluation/Evaluate/ManualEvaluate"; import KnowledgeBasePage from "@/pages/KnowledgeBase/Home/KnowledgeBasePage"; import KnowledgeBaseDetailPage from "@/pages/KnowledgeBase/Detail/KnowledgeBaseDetail"; import KnowledgeBaseFileDetailPage from "@/pages/KnowledgeBase/FileDetail/KnowledgeBaseFileDetail"; +import KnowledgeBaseSearch from "@/pages/KnowledgeBase/Search/KnowledgeBaseSearch"; import OperatorMarketPage from "@/pages/OperatorMarket/Home/OperatorMarket"; import OperatorPluginCreate from "@/pages/OperatorMarket/Create/OperatorPluginCreate"; @@ -246,6 +247,10 @@ const router = createBrowserRouter([ index: true, Component: KnowledgeBasePage, }, + { + path: "search", + Component: KnowledgeBaseSearch, + }, { path: "detail/:id", Component: KnowledgeBaseDetailPage, diff --git a/scripts/db/rag-management-init.sql b/scripts/db/rag-management-init.sql index ebf0aac..825360c 100644 --- a/scripts/db/rag-management-init.sql +++ b/scripts/db/rag-management-init.sql @@ -18,6 +18,7 @@ create table if not exists t_rag_file id VARCHAR(36) PRIMARY KEY COMMENT 'UUID', knowledge_base_id VARCHAR(36) NOT NULL COMMENT '知识库ID', file_name VARCHAR(255) NOT NULL COMMENT '文件名', + relative_path VARCHAR(512) NULL COMMENT '相对路径', file_id VARCHAR(255) NOT NULL COMMENT '文件ID', chunk_count INT COMMENT '切片数', metadata JSON COMMENT '元数据', @@ -28,3 +29,6 @@ create table if not exists t_rag_file created_by VARCHAR(255) COMMENT '创建者', updated_by VARCHAR(255) COMMENT '更新者' ) comment '知识库切片表'; + +create index idx_rag_file_kb_name on t_rag_file (knowledge_base_id, file_name); +create index idx_rag_file_kb_path on t_rag_file (knowledge_base_id, relative_path);