From 6ed63767079a429399d2a2ba1a7b3104c25312c9 Mon Sep 17 00:00:00 2001 From: beyondkmp Date: Mon, 19 May 2025 21:58:44 +0800 Subject: [PATCH] feat: add resolveFilePath functionality to resolve restoring from different computer (#5980) * feat: add resolveFilePath functionality to file management * Added new IPC channel for resolving file paths. * Implemented resolveFilePath method in FileStorage service. * Updated FileManager to utilize the new resolveFilePath method. * Enhanced preload API to expose resolveFilePath to the renderer. * Updated KnowledgeService to ensure file paths are correctly resolved in knowledge bases. * refactor: remove unused path import from preload index * Removed the unused 'resolve' import to clean up the codebase. * Improved code readability by eliminating unnecessary dependencies. --------- Co-authored-by: beyondkmp --- packages/shared/IpcChannel.ts | 2 +- src/main/ipc.ts | 1 + src/main/services/FileStorage.ts | 4 ++++ src/preload/index.ts | 1 + src/renderer/src/services/BackupService.ts | 3 +++ src/renderer/src/services/FileManager.ts | 4 ++++ src/renderer/src/services/KnowledgeService.ts | 24 +++++++++++++++++++ 7 files changed, 38 insertions(+), 1 deletion(-) diff --git a/packages/shared/IpcChannel.ts b/packages/shared/IpcChannel.ts index b4c4c571d6..7c536015a9 100644 --- a/packages/shared/IpcChannel.ts +++ b/packages/shared/IpcChannel.ts @@ -112,7 +112,7 @@ export enum IpcChannel { File_BinaryImage = 'file:binaryImage', File_Base64File = 'file:base64File', Fs_Read = 'fs:read', - + File_ResolveFilePath = 'file:resolveFilePath', Export_Word = 'export:word', Shortcuts_Update = 'shortcuts:update', diff --git a/src/main/ipc.ts b/src/main/ipc.ts index 439ed63e3d..e40b19aca1 100644 --- a/src/main/ipc.ts +++ b/src/main/ipc.ts @@ -242,6 +242,7 @@ export function registerIpc(mainWindow: BrowserWindow, app: Electron.App) { ipcMain.handle(IpcChannel.File_Download, fileManager.downloadFile) ipcMain.handle(IpcChannel.File_Copy, fileManager.copyFile) ipcMain.handle(IpcChannel.File_BinaryImage, fileManager.binaryImage) + ipcMain.handle(IpcChannel.File_ResolveFilePath, (_, name) => fileManager.resolveFilePath(name)) // fs ipcMain.handle(IpcChannel.Fs_Read, FileService.readFile) diff --git a/src/main/services/FileStorage.ts b/src/main/services/FileStorage.ts index 697eb6dd7c..ee8d21a3a6 100644 --- a/src/main/services/FileStorage.ts +++ b/src/main/services/FileStorage.ts @@ -27,6 +27,10 @@ class FileStorage { this.initStorageDir() } + public resolveFilePath = (name: string): string => { + return path.join(this.storageDir, name) + } + private initStorageDir = (): void => { try { if (!fs.existsSync(this.storageDir)) { diff --git a/src/preload/index.ts b/src/preload/index.ts index 3679dd0802..f70ca04d20 100644 --- a/src/preload/index.ts +++ b/src/preload/index.ts @@ -55,6 +55,7 @@ const api = { }, file: { select: (options?: OpenDialogOptions) => ipcRenderer.invoke(IpcChannel.File_Select, options), + resolveFilePath: (name: string) => ipcRenderer.invoke(IpcChannel.File_ResolveFilePath, name), upload: (file: FileType) => ipcRenderer.invoke(IpcChannel.File_Upload, file), delete: (fileId: string) => ipcRenderer.invoke(IpcChannel.File_Delete, fileId), read: (fileId: string) => ipcRenderer.invoke(IpcChannel.File_Read, fileId), diff --git a/src/renderer/src/services/BackupService.ts b/src/renderer/src/services/BackupService.ts index e0720e36d3..3d3bbf1e38 100644 --- a/src/renderer/src/services/BackupService.ts +++ b/src/renderer/src/services/BackupService.ts @@ -3,6 +3,7 @@ import db from '@renderer/databases' import { upgradeToV7 } from '@renderer/databases/upgrades' import i18n from '@renderer/i18n' import store from '@renderer/store' +import { updateKnowledgeBaseFilePath } from '@renderer/services/KnowledgeService' import { setWebDAVSyncState } from '@renderer/store/backup' import dayjs from 'dayjs' @@ -32,6 +33,7 @@ export async function restore() { } await handleData(data) + await updateKnowledgeBaseFilePath() } catch (error) { Logger.error('[Backup] restore: Error restoring backup file:', error) window.message.error({ content: i18n.t('error.backup.file_format'), key: 'restore' }) @@ -211,6 +213,7 @@ export async function restoreFromWebdav(fileName?: string) { try { await handleData(JSON.parse(data)) + await updateKnowledgeBaseFilePath() } catch (error) { console.error('[Backup] Error downloading file from WebDAV:', error) window.message.error({ content: i18n.t('error.backup.file_format'), key: 'restore' }) diff --git a/src/renderer/src/services/FileManager.ts b/src/renderer/src/services/FileManager.ts index 94849a8ebb..ab40c5bb35 100644 --- a/src/renderer/src/services/FileManager.ts +++ b/src/renderer/src/services/FileManager.ts @@ -12,6 +12,10 @@ class FileManager { return files } + static async resolveFilePath(name: string): Promise { + return window.api.file.resolveFilePath(name) + } + static async addFile(file: FileType): Promise { const fileRecord = await db.files.get(file.id) diff --git a/src/renderer/src/services/KnowledgeService.ts b/src/renderer/src/services/KnowledgeService.ts index 4200085b36..9318c3739e 100644 --- a/src/renderer/src/services/KnowledgeService.ts +++ b/src/renderer/src/services/KnowledgeService.ts @@ -4,6 +4,7 @@ import { getEmbeddingMaxContext } from '@renderer/config/embedings' import Logger from '@renderer/config/logger' import AiProvider from '@renderer/providers/AiProvider' import store from '@renderer/store' +import { updateBases } from '@renderer/store/knowledge' import { FileType, KnowledgeBase, KnowledgeBaseParams, KnowledgeReference } from '@renderer/types' import { ExtractResults } from '@renderer/utils/extract' import { isEmpty } from 'lodash' @@ -11,6 +12,29 @@ import { isEmpty } from 'lodash' import { getProviderByModel } from './AssistantService' import FileManager from './FileManager' +export const updateKnowledgeBaseFilePath = async () => { + const bases = store.getState().knowledge.bases + const updatedBases = await Promise.all( + bases.map(async (base) => { + const updatedBase = { ...base } + updatedBase.items = await Promise.all( + base.items.map(async (item) => { + const updatedItem = { ...item } + if (item.type === 'file' || item.type === 'directory') { + updatedItem.content = { ...(item.content as FileType) } + updatedItem.content.path = await FileManager.resolveFilePath(updatedItem.content.name) + } + return updatedItem + }) + ) + return updatedBase + }) + ) + + // 使用 dispatch 更新状态 + store.dispatch(updateBases(updatedBases)) +} + export const getKnowledgeBaseParams = (base: KnowledgeBase): KnowledgeBaseParams => { const provider = getProviderByModel(base.model) const rerankProvider = getProviderByModel(base.rerankModel)