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
This commit is contained in:
parent
37cf7427f9
commit
886a7ec1e9
43
src/renderer/src/hooks/useKnowledgeFiles.tsx
Normal file
43
src/renderer/src/hooks/useKnowledgeFiles.tsx
Normal file
@ -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<FileType[]>([])
|
||||||
|
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 }
|
||||||
|
}
|
||||||
@ -595,6 +595,10 @@
|
|||||||
"data": {
|
"data": {
|
||||||
"app_data": "App Data",
|
"app_data": "App Data",
|
||||||
"app_logs": "App Logs",
|
"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": {
|
"clear_cache": {
|
||||||
"button": "Clear Cache",
|
"button": "Clear Cache",
|
||||||
"confirm": "Clearing the cache will delete application cache data, including minapp data. This action is irreversible, continue?",
|
"confirm": "Clearing the cache will delete application cache data, including minapp data. This action is irreversible, continue?",
|
||||||
|
|||||||
@ -595,6 +595,10 @@
|
|||||||
"data": {
|
"data": {
|
||||||
"app_data": "アプリデータ",
|
"app_data": "アプリデータ",
|
||||||
"app_logs": "アプリログ",
|
"app_logs": "アプリログ",
|
||||||
|
"app_knowledge": "ナレッジベースファイル",
|
||||||
|
"app_knowledge.remove_all": "ファイルを削除",
|
||||||
|
"app_knowledge.remove_all_confirm": "ナレッジベースファイルを削除してもナレッジベース自体は削除されません。これにより、ストレージ容量を節約できます。続行しますか?",
|
||||||
|
"app_knowledge.remove_all_success": "ファイル削除成功",
|
||||||
"clear_cache": {
|
"clear_cache": {
|
||||||
"button": "キャッシュをクリア",
|
"button": "キャッシュをクリア",
|
||||||
"confirm": "キャッシュをクリアすると、アプリのキャッシュデータ(ミニアプリデータを含む)が削除されます。この操作は元に戻せません。続行しますか?",
|
"confirm": "キャッシュをクリアすると、アプリのキャッシュデータ(ミニアプリデータを含む)が削除されます。この操作は元に戻せません。続行しますか?",
|
||||||
|
|||||||
@ -595,6 +595,10 @@
|
|||||||
"data": {
|
"data": {
|
||||||
"app_data": "Данные приложения",
|
"app_data": "Данные приложения",
|
||||||
"app_logs": "Логи приложения",
|
"app_logs": "Логи приложения",
|
||||||
|
"app_knowledge": "База знаний",
|
||||||
|
"app_knowledge.remove_all": "Удалить файлы",
|
||||||
|
"app_knowledge.remove_all_confirm": "Удаление файлов базы знаний не удалит саму базу знаний, что позволит уменьшить занимаемый объем памяти, продолжить?",
|
||||||
|
"app_knowledge.remove_all_success": "Файлы удалены успешно",
|
||||||
"clear_cache": {
|
"clear_cache": {
|
||||||
"button": "Очистка кэша",
|
"button": "Очистка кэша",
|
||||||
"confirm": "Очистка кэша удалит данные приложения. Это действие необратимо, продолжить?",
|
"confirm": "Очистка кэша удалит данные приложения. Это действие необратимо, продолжить?",
|
||||||
|
|||||||
@ -595,6 +595,10 @@
|
|||||||
"data": {
|
"data": {
|
||||||
"app_data": "应用数据",
|
"app_data": "应用数据",
|
||||||
"app_logs": "应用日志",
|
"app_logs": "应用日志",
|
||||||
|
"app_knowledge": "知识库文件",
|
||||||
|
"app_knowledge.remove_all": "删除文件",
|
||||||
|
"app_knowledge.remove_all_confirm": "删除知识库文件不会删除知识库本身,可以减少存储空间占用,删除之后文件无法再打开,是否继续?",
|
||||||
|
"app_knowledge.remove_all_success": "文件删除成功",
|
||||||
"clear_cache": {
|
"clear_cache": {
|
||||||
"button": "清除缓存",
|
"button": "清除缓存",
|
||||||
"confirm": "清除缓存将删除应用缓存的数据,包括小程序数据。此操作不可恢复,是否继续?",
|
"confirm": "清除缓存将删除应用缓存的数据,包括小程序数据。此操作不可恢复,是否继续?",
|
||||||
|
|||||||
@ -595,6 +595,10 @@
|
|||||||
"data": {
|
"data": {
|
||||||
"app_data": "應用數據",
|
"app_data": "應用數據",
|
||||||
"app_logs": "應用日誌",
|
"app_logs": "應用日誌",
|
||||||
|
"app_knowledge": "知識庫文件",
|
||||||
|
"app_knowledge.remove_all": "刪除文件",
|
||||||
|
"app_knowledge.remove_all_confirm": "刪除知識庫文件不會刪除知識庫本身,可以減少存儲空間占用,刪除之後文件無法再打開,是否繼續?",
|
||||||
|
"app_knowledge.remove_all_success": "文件刪除成功",
|
||||||
"clear_cache": {
|
"clear_cache": {
|
||||||
"button": "清除緩存",
|
"button": "清除緩存",
|
||||||
"confirm": "清除緩存將刪除應用緩存數據,包括小程序數據。此操作不可恢復,是否繼續?",
|
"confirm": "清除緩存將刪除應用緩存數據,包括小程序數據。此操作不可恢復,是否繼續?",
|
||||||
|
|||||||
@ -35,7 +35,7 @@ const ContentView: React.FC<ContentViewProps> = ({ id, files, dataSource, column
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<ImageInfo>
|
<ImageInfo>
|
||||||
<div>{formatFileSize(file)}</div>
|
<div>{formatFileSize(file.size)}</div>
|
||||||
</ImageInfo>
|
</ImageInfo>
|
||||||
</ImageWrapper>
|
</ImageWrapper>
|
||||||
</Col>
|
</Col>
|
||||||
|
|||||||
@ -111,7 +111,7 @@ const FilesPage: FC = () => {
|
|||||||
{file.origin_name}
|
{file.origin_name}
|
||||||
</FileNameText>
|
</FileNameText>
|
||||||
),
|
),
|
||||||
size: formatFileSize(file),
|
size: formatFileSize(file.size),
|
||||||
size_bytes: file.size,
|
size_bytes: file.size,
|
||||||
count: file.count,
|
count: file.count,
|
||||||
created_at: dayjs(file.created_at).format('MM-DD HH:mm'),
|
created_at: dayjs(file.created_at).format('MM-DD HH:mm'),
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import MinApp from '@renderer/components/MinApp'
|
|||||||
import BackupPopup from '@renderer/components/Popups/BackupPopup'
|
import BackupPopup from '@renderer/components/Popups/BackupPopup'
|
||||||
import RestorePopup from '@renderer/components/Popups/RestorePopup'
|
import RestorePopup from '@renderer/components/Popups/RestorePopup'
|
||||||
import { useTheme } from '@renderer/context/ThemeProvider'
|
import { useTheme } from '@renderer/context/ThemeProvider'
|
||||||
|
import { useKnowledgeFiles } from '@renderer/hooks/useKnowledgeFiles'
|
||||||
import { reset } from '@renderer/services/BackupService'
|
import { reset } from '@renderer/services/BackupService'
|
||||||
import { RootState, useAppDispatch } from '@renderer/store'
|
import { RootState, useAppDispatch } from '@renderer/store'
|
||||||
import {
|
import {
|
||||||
@ -18,6 +19,7 @@ import {
|
|||||||
setYuqueUrl
|
setYuqueUrl
|
||||||
} from '@renderer/store/settings'
|
} from '@renderer/store/settings'
|
||||||
import { AppInfo } from '@renderer/types'
|
import { AppInfo } from '@renderer/types'
|
||||||
|
import { formatFileSize } from '@renderer/utils'
|
||||||
import { Button, InputNumber, Modal, Switch, Tooltip, Typography } from 'antd'
|
import { Button, InputNumber, Modal, Switch, Tooltip, Typography } from 'antd'
|
||||||
import Input from 'antd/es/input/Input'
|
import Input from 'antd/es/input/Input'
|
||||||
import { FC, useEffect, useState } from 'react'
|
import { FC, useEffect, useState } from 'react'
|
||||||
@ -298,6 +300,7 @@ const YuqueSettings: FC = () => {
|
|||||||
const DataSettings: FC = () => {
|
const DataSettings: FC = () => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const [appInfo, setAppInfo] = useState<AppInfo>()
|
const [appInfo, setAppInfo] = useState<AppInfo>()
|
||||||
|
const { size, removeAllFiles } = useKnowledgeFiles()
|
||||||
const { theme } = useTheme()
|
const { theme } = useTheme()
|
||||||
|
|
||||||
useEffect(() => {
|
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 (
|
return (
|
||||||
<SettingContainer theme={theme}>
|
<SettingContainer theme={theme}>
|
||||||
<SettingGroup theme={theme}>
|
<SettingGroup theme={theme}>
|
||||||
@ -384,6 +403,15 @@ const DataSettings: FC = () => {
|
|||||||
</HStack>
|
</HStack>
|
||||||
</SettingRow>
|
</SettingRow>
|
||||||
<SettingDivider />
|
<SettingDivider />
|
||||||
|
<SettingRow>
|
||||||
|
<SettingRowTitle>{t('settings.data.app_knowledge')}</SettingRowTitle>
|
||||||
|
<HStack alignItems="center" gap="5px">
|
||||||
|
<Button onClick={handleRemoveAllFiles} danger>
|
||||||
|
{t('settings.data.app_knowledge.remove_all')}
|
||||||
|
</Button>
|
||||||
|
</HStack>
|
||||||
|
</SettingRow>
|
||||||
|
<SettingDivider />
|
||||||
<SettingRow>
|
<SettingRow>
|
||||||
<SettingRowTitle>{t('settings.data.clear_cache.title')}</SettingRowTitle>
|
<SettingRowTitle>{t('settings.data.clear_cache.title')}</SettingRowTitle>
|
||||||
<HStack gap="5px">
|
<HStack gap="5px">
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { FileType, Model } from '@renderer/types'
|
import { Model } from '@renderer/types'
|
||||||
import { ModalFuncProps } from 'antd/es/modal/interface'
|
import { ModalFuncProps } from 'antd/es/modal/interface'
|
||||||
import imageCompression from 'browser-image-compression'
|
import imageCompression from 'browser-image-compression'
|
||||||
import html2canvas from 'html2canvas'
|
import html2canvas from 'html2canvas'
|
||||||
@ -394,9 +394,7 @@ export function hasPath(url: string): boolean {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function formatFileSize(file: FileType) {
|
export function formatFileSize(size: number) {
|
||||||
const size = file.size
|
|
||||||
|
|
||||||
if (size > 1024 * 1024) {
|
if (size > 1024 * 1024) {
|
||||||
return (size / 1024 / 1024).toFixed(1) + ' MB'
|
return (size / 1024 / 1024).toFixed(1) + ' MB'
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user