mirror of
https://github.com/lobehub/lobehub.git
synced 2026-03-26 13:19:34 +07:00
🐛 fix(kb): wire vector cleanup in TRPC router, OpenAPI service, and client
- TRPC removeKnowledgeBase: use deleteWithFiles when removeFiles=true + S3 cleanup - TRPC removeAllKnowledgeBases: use deleteAllWithFiles + S3 cleanup - OpenAPI deleteKnowledgeBase: use deleteWithFiles + S3 cleanup - Client service: default removeFiles=true when deleting knowledge base
This commit is contained in:
@@ -4,6 +4,7 @@ import { KnowledgeBaseModel } from '@/database/models/knowledgeBase';
|
||||
import type { KnowledgeBaseItem } from '@/database/schemas';
|
||||
import { knowledgeBases } from '@/database/schemas';
|
||||
import type { LobeChatDatabase } from '@/database/type';
|
||||
import { FileService as CoreFileService } from '@/server/services/file';
|
||||
|
||||
import { BaseService } from '../common/base.service';
|
||||
import { processPaginationConditions } from '../helpers/pagination';
|
||||
@@ -237,8 +238,19 @@ export class KnowledgeBaseService extends BaseService {
|
||||
throw this.createNotFoundError('Knowledge base not found or access denied');
|
||||
}
|
||||
|
||||
// Delete knowledge base
|
||||
await this.knowledgeBaseModel.delete(id);
|
||||
// Delete knowledge base and its exclusive files
|
||||
const result = await this.knowledgeBaseModel.deleteWithFiles(id);
|
||||
|
||||
// Clean up physical storage for deleted files
|
||||
if (result.deletedFiles.length > 0) {
|
||||
const fileService = new CoreFileService(this.db, this.userId);
|
||||
const urls = result.deletedFiles
|
||||
.map((f: { url: string | null }) => f.url)
|
||||
.filter(Boolean) as string[];
|
||||
if (urls.length > 0) {
|
||||
await fileService.deleteFiles(urls);
|
||||
}
|
||||
}
|
||||
|
||||
this.log('info', 'Knowledge base deleted successfully', { id });
|
||||
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
import { TRPCError } from '@trpc/server';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { serverDBEnv } from '@/config/db';
|
||||
import { KnowledgeBaseModel } from '@/database/models/knowledgeBase';
|
||||
import { insertKnowledgeBasesSchema } from '@/database/schemas';
|
||||
import { authedProcedure, router } from '@/libs/trpc/lambda';
|
||||
import { serverDatabase } from '@/libs/trpc/lambda/middleware';
|
||||
import { FileService } from '@/server/services/file';
|
||||
import { type KnowledgeBaseItem } from '@/types/knowledgeBase';
|
||||
|
||||
const knowledgeBaseProcedure = authedProcedure.use(serverDatabase).use(async (opts) => {
|
||||
@@ -68,7 +70,15 @@ export const knowledgeBaseRouter = router({
|
||||
}),
|
||||
|
||||
removeAllKnowledgeBases: knowledgeBaseProcedure.mutation(async ({ ctx }) => {
|
||||
return ctx.knowledgeBaseModel.deleteAll();
|
||||
const result = await ctx.knowledgeBaseModel.deleteAllWithFiles(serverDBEnv.REMOVE_GLOBAL_FILE);
|
||||
|
||||
if (result.deletedFiles.length > 0) {
|
||||
const fileService = new FileService(ctx.serverDB, ctx.userId);
|
||||
const urls = result.deletedFiles.map((f) => f.url).filter(Boolean) as string[];
|
||||
if (urls.length > 0) {
|
||||
await fileService.deleteFiles(urls);
|
||||
}
|
||||
}
|
||||
}),
|
||||
|
||||
removeFilesFromKnowledgeBase: knowledgeBaseProcedure
|
||||
@@ -80,6 +90,23 @@ export const knowledgeBaseRouter = router({
|
||||
removeKnowledgeBase: knowledgeBaseProcedure
|
||||
.input(z.object({ id: z.string(), removeFiles: z.boolean().optional() }))
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
if (input.removeFiles) {
|
||||
const result = await ctx.knowledgeBaseModel.deleteWithFiles(
|
||||
input.id,
|
||||
serverDBEnv.REMOVE_GLOBAL_FILE,
|
||||
);
|
||||
|
||||
if (result.deletedFiles.length > 0) {
|
||||
const fileService = new FileService(ctx.serverDB, ctx.userId);
|
||||
const urls = result.deletedFiles.map((f) => f.url).filter(Boolean) as string[];
|
||||
if (urls.length > 0) {
|
||||
await fileService.deleteFiles(urls);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
return ctx.knowledgeBaseModel.delete(input.id);
|
||||
}),
|
||||
|
||||
|
||||
@@ -18,8 +18,8 @@ class KnowledgeBaseService {
|
||||
return lambdaClient.knowledgeBase.updateKnowledgeBase.mutate({ id, value });
|
||||
};
|
||||
|
||||
deleteKnowledgeBase = async (id: string) => {
|
||||
return lambdaClient.knowledgeBase.removeKnowledgeBase.mutate({ id });
|
||||
deleteKnowledgeBase = async (id: string, removeFiles: boolean = true) => {
|
||||
return lambdaClient.knowledgeBase.removeKnowledgeBase.mutate({ id, removeFiles });
|
||||
};
|
||||
|
||||
addFilesToKnowledgeBase = async (knowledgeBaseId: string, ids: string[]) => {
|
||||
|
||||
@@ -147,7 +147,7 @@ describe('KnowledgeBaseCrudAction', () => {
|
||||
await result.current.removeKnowledgeBase('kb-to-delete');
|
||||
});
|
||||
|
||||
expect(knowledgeBaseService.deleteKnowledgeBase).toHaveBeenCalledWith('kb-to-delete');
|
||||
expect(knowledgeBaseService.deleteKnowledgeBase).toHaveBeenCalledWith('kb-to-delete', true);
|
||||
expect(refreshSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
|
||||
@@ -47,8 +47,8 @@ export class KnowledgeBaseCrudActionImpl {
|
||||
await mutate(FETCH_KNOWLEDGE_BASE_LIST_KEY);
|
||||
};
|
||||
|
||||
removeKnowledgeBase = async (id: string): Promise<void> => {
|
||||
await knowledgeBaseService.deleteKnowledgeBase(id);
|
||||
removeKnowledgeBase = async (id: string, removeFiles: boolean = true): Promise<void> => {
|
||||
await knowledgeBaseService.deleteKnowledgeBase(id, removeFiles);
|
||||
await this.#get().refreshKnowledgeBaseList();
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user