From 886a7ec1e9cad4520c87c49fe69022658aed5776 Mon Sep 17 00:00:00 2001 From: kangfenmao Date: Mon, 3 Mar 2025 23:20:31 +0800 Subject: [PATCH] feat: Add knowledge base file management functionality - Implemented `useKnowledgeFiles` hook for managing knowledge base files - Added localization support for knowledge base file management in multiple languages - Created UI option to remove all knowledge base files in DataSettings - Updated file size formatting utility function - Modified ContentView and FilesPage to use file size correctly --- src/renderer/src/hooks/useKnowledgeFiles.tsx | 43 +++++++++++++++++++ src/renderer/src/i18n/locales/en-us.json | 4 ++ src/renderer/src/i18n/locales/ja-jp.json | 4 ++ src/renderer/src/i18n/locales/ru-ru.json | 4 ++ src/renderer/src/i18n/locales/zh-cn.json | 4 ++ src/renderer/src/i18n/locales/zh-tw.json | 4 ++ src/renderer/src/pages/files/ContentView.tsx | 2 +- src/renderer/src/pages/files/FilesPage.tsx | 2 +- .../settings/DataSettings/DataSettings.tsx | 28 ++++++++++++ src/renderer/src/utils/index.ts | 6 +-- 10 files changed, 95 insertions(+), 6 deletions(-) create mode 100644 src/renderer/src/hooks/useKnowledgeFiles.tsx diff --git a/src/renderer/src/hooks/useKnowledgeFiles.tsx b/src/renderer/src/hooks/useKnowledgeFiles.tsx new file mode 100644 index 00000000..cdb4e40c --- /dev/null +++ b/src/renderer/src/hooks/useKnowledgeFiles.tsx @@ -0,0 +1,43 @@ +import FileManager from '@renderer/services/FileManager' +import { FileType } from '@renderer/types' +import { isEmpty } from 'lodash' +import { useEffect, useState } from 'react' + +import { useKnowledgeBases } from './useKnowledge' + +export const useKnowledgeFiles = () => { + const [knowledgeFiles, setKnowledgeFiles] = useState([]) + const { bases, updateKnowledgeBases } = useKnowledgeBases() + + useEffect(() => { + const items = bases.map((kb) => kb.items).flat() + const fileItems = items.filter((item) => item.type === 'file') + const files = fileItems.map((item) => item.content as FileType) + !isEmpty(files) && setKnowledgeFiles(files) + }, [bases]) + + const removeAllFiles = async () => { + console.debug('removeAllFiles', knowledgeFiles) + await FileManager.deleteFiles(knowledgeFiles) + + const newBases = bases.map((kb) => ({ + ...kb, + items: kb.items.map((item) => + item.type === 'file' + ? { + ...item, + content: { + ...(item.content as FileType), + size: 0 + } + } + : item + ) + })) + updateKnowledgeBases(newBases) + } + + const size = knowledgeFiles.reduce((acc, file) => acc + file.size, 0) + + return { knowledgeFiles, size, removeAllFiles } +} diff --git a/src/renderer/src/i18n/locales/en-us.json b/src/renderer/src/i18n/locales/en-us.json index 33ebd744..2dd60164 100644 --- a/src/renderer/src/i18n/locales/en-us.json +++ b/src/renderer/src/i18n/locales/en-us.json @@ -595,6 +595,10 @@ "data": { "app_data": "App Data", "app_logs": "App Logs", + "app_knowledge": "Knowledge Base Files", + "app_knowledge.remove_all": "Remove Files", + "app_knowledge.remove_all_confirm": "Removing knowledge base files will not delete the knowledge base itself, which will reduce the storage space occupied. Continue?", + "app_knowledge.remove_all_success": "Files removed successfully", "clear_cache": { "button": "Clear Cache", "confirm": "Clearing the cache will delete application cache data, including minapp data. This action is irreversible, continue?", diff --git a/src/renderer/src/i18n/locales/ja-jp.json b/src/renderer/src/i18n/locales/ja-jp.json index f69aad3e..627a6932 100644 --- a/src/renderer/src/i18n/locales/ja-jp.json +++ b/src/renderer/src/i18n/locales/ja-jp.json @@ -595,6 +595,10 @@ "data": { "app_data": "アプリデータ", "app_logs": "アプリログ", + "app_knowledge": "ナレッジベースファイル", + "app_knowledge.remove_all": "ファイルを削除", + "app_knowledge.remove_all_confirm": "ナレッジベースファイルを削除してもナレッジベース自体は削除されません。これにより、ストレージ容量を節約できます。続行しますか?", + "app_knowledge.remove_all_success": "ファイル削除成功", "clear_cache": { "button": "キャッシュをクリア", "confirm": "キャッシュをクリアすると、アプリのキャッシュデータ(ミニアプリデータを含む)が削除されます。この操作は元に戻せません。続行しますか?", diff --git a/src/renderer/src/i18n/locales/ru-ru.json b/src/renderer/src/i18n/locales/ru-ru.json index 0f574484..5219d3e9 100644 --- a/src/renderer/src/i18n/locales/ru-ru.json +++ b/src/renderer/src/i18n/locales/ru-ru.json @@ -595,6 +595,10 @@ "data": { "app_data": "Данные приложения", "app_logs": "Логи приложения", + "app_knowledge": "База знаний", + "app_knowledge.remove_all": "Удалить файлы", + "app_knowledge.remove_all_confirm": "Удаление файлов базы знаний не удалит саму базу знаний, что позволит уменьшить занимаемый объем памяти, продолжить?", + "app_knowledge.remove_all_success": "Файлы удалены успешно", "clear_cache": { "button": "Очистка кэша", "confirm": "Очистка кэша удалит данные приложения. Это действие необратимо, продолжить?", diff --git a/src/renderer/src/i18n/locales/zh-cn.json b/src/renderer/src/i18n/locales/zh-cn.json index 58fa3df1..b444438e 100644 --- a/src/renderer/src/i18n/locales/zh-cn.json +++ b/src/renderer/src/i18n/locales/zh-cn.json @@ -595,6 +595,10 @@ "data": { "app_data": "应用数据", "app_logs": "应用日志", + "app_knowledge": "知识库文件", + "app_knowledge.remove_all": "删除文件", + "app_knowledge.remove_all_confirm": "删除知识库文件不会删除知识库本身,可以减少存储空间占用,删除之后文件无法再打开,是否继续?", + "app_knowledge.remove_all_success": "文件删除成功", "clear_cache": { "button": "清除缓存", "confirm": "清除缓存将删除应用缓存的数据,包括小程序数据。此操作不可恢复,是否继续?", diff --git a/src/renderer/src/i18n/locales/zh-tw.json b/src/renderer/src/i18n/locales/zh-tw.json index 3dbb667c..0e8f8425 100644 --- a/src/renderer/src/i18n/locales/zh-tw.json +++ b/src/renderer/src/i18n/locales/zh-tw.json @@ -595,6 +595,10 @@ "data": { "app_data": "應用數據", "app_logs": "應用日誌", + "app_knowledge": "知識庫文件", + "app_knowledge.remove_all": "刪除文件", + "app_knowledge.remove_all_confirm": "刪除知識庫文件不會刪除知識庫本身,可以減少存儲空間占用,刪除之後文件無法再打開,是否繼續?", + "app_knowledge.remove_all_success": "文件刪除成功", "clear_cache": { "button": "清除緩存", "confirm": "清除緩存將刪除應用緩存數據,包括小程序數據。此操作不可恢復,是否繼續?", diff --git a/src/renderer/src/pages/files/ContentView.tsx b/src/renderer/src/pages/files/ContentView.tsx index 1e75990c..6e3d3428 100644 --- a/src/renderer/src/pages/files/ContentView.tsx +++ b/src/renderer/src/pages/files/ContentView.tsx @@ -35,7 +35,7 @@ const ContentView: React.FC = ({ id, files, dataSource, column }} /> -
{formatFileSize(file)}
+
{formatFileSize(file.size)}
diff --git a/src/renderer/src/pages/files/FilesPage.tsx b/src/renderer/src/pages/files/FilesPage.tsx index a248ef64..596c083f 100644 --- a/src/renderer/src/pages/files/FilesPage.tsx +++ b/src/renderer/src/pages/files/FilesPage.tsx @@ -111,7 +111,7 @@ const FilesPage: FC = () => { {file.origin_name} ), - size: formatFileSize(file), + size: formatFileSize(file.size), size_bytes: file.size, count: file.count, created_at: dayjs(file.created_at).format('MM-DD HH:mm'), diff --git a/src/renderer/src/pages/settings/DataSettings/DataSettings.tsx b/src/renderer/src/pages/settings/DataSettings/DataSettings.tsx index ee083837..6955d1e7 100644 --- a/src/renderer/src/pages/settings/DataSettings/DataSettings.tsx +++ b/src/renderer/src/pages/settings/DataSettings/DataSettings.tsx @@ -5,6 +5,7 @@ import MinApp from '@renderer/components/MinApp' import BackupPopup from '@renderer/components/Popups/BackupPopup' import RestorePopup from '@renderer/components/Popups/RestorePopup' import { useTheme } from '@renderer/context/ThemeProvider' +import { useKnowledgeFiles } from '@renderer/hooks/useKnowledgeFiles' import { reset } from '@renderer/services/BackupService' import { RootState, useAppDispatch } from '@renderer/store' import { @@ -18,6 +19,7 @@ import { setYuqueUrl } from '@renderer/store/settings' import { AppInfo } from '@renderer/types' +import { formatFileSize } from '@renderer/utils' import { Button, InputNumber, Modal, Switch, Tooltip, Typography } from 'antd' import Input from 'antd/es/input/Input' import { FC, useEffect, useState } from 'react' @@ -298,6 +300,7 @@ const YuqueSettings: FC = () => { const DataSettings: FC = () => { const { t } = useTranslation() const [appInfo, setAppInfo] = useState() + const { size, removeAllFiles } = useKnowledgeFiles() const { theme } = useTheme() useEffect(() => { @@ -334,6 +337,22 @@ const DataSettings: FC = () => { }) } + const handleRemoveAllFiles = () => { + Modal.confirm({ + centered: true, + title: t('settings.data.app_knowledge.remove_all') + ` (${formatFileSize(size)}) `, + content: t('settings.data.app_knowledge.remove_all_confirm'), + onOk: async () => { + await removeAllFiles() + window.message.success(t('settings.data.app_knowledge.remove_all_success')) + }, + okText: t('common.delete'), + okButtonProps: { + danger: true + } + }) + } + return ( @@ -384,6 +403,15 @@ const DataSettings: FC = () => { + + {t('settings.data.app_knowledge')} + + + + + {t('settings.data.clear_cache.title')} diff --git a/src/renderer/src/utils/index.ts b/src/renderer/src/utils/index.ts index 7ce1ee03..21a4e5ba 100644 --- a/src/renderer/src/utils/index.ts +++ b/src/renderer/src/utils/index.ts @@ -1,4 +1,4 @@ -import { FileType, Model } from '@renderer/types' +import { Model } from '@renderer/types' import { ModalFuncProps } from 'antd/es/modal/interface' import imageCompression from 'browser-image-compression' import html2canvas from 'html2canvas' @@ -394,9 +394,7 @@ export function hasPath(url: string): boolean { } } -export function formatFileSize(file: FileType) { - const size = file.size - +export function formatFileSize(size: number) { if (size > 1024 * 1024) { return (size / 1024 / 1024).toFixed(1) + ' MB' }