mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2026-01-01 17:59:09 +08:00
* refactor(main): 使用枚举管理 IPC 通道 - 新增 IpcChannel 枚举,用于统一管理所有的 IPC 通道 - 修改相关代码,使用 IpcChannel 枚举替代硬编码的字符串通道名称 - 此改动有助于提高代码的可维护性和可读性,避免因通道名称变更导致的错误 * refactor(ipc): 将字符串通道名称替换为 IpcChannel 枚举 - 在多个文件中将硬编码的字符串通道名称替换为 IpcChannel 枚举值 - 更新了相关文件的导入,增加了对 IpcChannel 的引用 - 通过使用枚举来管理 IPC 通道名称,提高了代码的可维护性和可读性 * refactor(ipc): 调整 IPC 通道枚举和预加载脚本 - 移除了 IpcChannel 枚举中的未使用注释 - 更新了预加载脚本中 IpcChannel 的导入路径 * refactor(ipc): 更新 IpcChannel导入路径 - 将 IpcChannel 的导入路径从 @main/enum/IpcChannel 修改为 @shared/IpcChannel - 此修改涉及多个文件,包括 AppUpdater、BackupManager、EditMcpJsonPopup 等 - 同时移除了 tsconfig.web.json 中对 src/main/**/* 的引用 * refactor(ipc): 添加 ReduxStoreReady 事件并更新事件监听 - 在 IpcChannel 枚举中添加 ReduxStoreReady 事件 - 更新 ReduxService 中的事件监听,使用新的枚举值 * refactor(main): 重构 ReduxService 中的状态变化事件处理 - 将状态变化事件名称定义为常量 STATUS_CHANGE_EVENT - 更新事件监听和触发使用新的常量 - 优化了代码结构,提高了可维护性 * refactor(i18n): 优化国际化配置和语言选择逻辑 - 在多个文件中引入 defaultLanguage 常量,统一默认语言设置 - 调整 i18n 初始化和语言变更逻辑,使用新配置 - 更新相关组件和 Hook 中的语言选择逻辑 * refactor(ConfigManager): 重构配置管理器 - 添加 ConfigKeys 枚举,用于统一配置项的键名 - 引入 defaultLanguage,作为默认语言设置 - 重构 get 和 set 方法,使用 ConfigKeys 枚举作为键名 - 优化类型定义和方法签名,提高代码可读性和可维护性 * refactor(ConfigManager): 重命名配置键 ZoomFactor 将配置键 zoomFactor 重命名为 ZoomFactor,以符合命名规范。 更新了相关方法和属性以反映这一变更。 * refactor(shared): 重构常量定义并优化文件大小格式化逻辑 - 在 constant.ts 中添加 KB、MB、GB 常量定义 - 将 defaultLanguage 移至 constant.ts - 更新 ConfigManager、useAppInit、i18n、GeneralSettings 等文件中的导入路径 - 优化 formatFileSize 函数,使用新定义的常量 * refactor(FileSize): 使用 GB/MB/KB 等常量处理文件大小计算 * refactor(ipc): 将字符串通道名称替换为 IpcChannel 枚举 - 在多个文件中将硬编码的字符串通道名称替换为 IpcChannel 枚举值 - 更新了相关文件的导入,增加了对 IpcChannel 的引用 - 通过使用枚举来管理 IPC 通道名称,提高了代码的可维护性和可读性 * refactor(ipc): 更新 IpcChannel导入路径 - 将 IpcChannel 的导入路径从 @main/enum/IpcChannel 修改为 @shared/IpcChannel - 此修改涉及多个文件,包括 AppUpdater、BackupManager、EditMcpJsonPopup 等 - 同时移除了 tsconfig.web.json 中对 src/main/**/* 的引用 * refactor(i18n): 优化国际化配置和语言选择逻辑 - 在多个文件中引入 defaultLanguage 常量,统一默认语言设置 - 调整 i18n 初始化和语言变更逻辑,使用新配置 - 更新相关组件和 Hook 中的语言选择逻辑 * refactor(shared): 重构常量定义并优化文件大小格式化逻辑 - 在 constant.ts 中添加 KB、MB、GB 常量定义 - 将 defaultLanguage 移至 constant.ts - 更新 ConfigManager、useAppInit、i18n、GeneralSettings 等文件中的导入路径 - 优化 formatFileSize 函数,使用新定义的常量 * refactor: 移除重复的导入语句 - 在 HomeWindow.tsx 和 useAppInit.ts 文件中移除了重复的 defaultLanguage导入语句 - 这个改动简化了代码结构,提高了代码的可读性和维护性
373 lines
10 KiB
TypeScript
373 lines
10 KiB
TypeScript
/* eslint-disable react-hooks/rules-of-hooks */
|
|
import { db } from '@renderer/databases/index'
|
|
import KnowledgeQueue from '@renderer/queue/KnowledgeQueue'
|
|
import FileManager from '@renderer/services/FileManager'
|
|
import { getKnowledgeBaseParams } from '@renderer/services/KnowledgeService'
|
|
import { RootState } from '@renderer/store'
|
|
import {
|
|
addBase,
|
|
addFiles as addFilesAction,
|
|
addItem,
|
|
clearAllProcessing,
|
|
clearCompletedProcessing,
|
|
deleteBase,
|
|
removeItem as removeItemAction,
|
|
renameBase,
|
|
updateBase,
|
|
updateBases,
|
|
updateItem as updateItemAction,
|
|
updateItemProcessingStatus,
|
|
updateNotes
|
|
} from '@renderer/store/knowledge'
|
|
import { FileType, KnowledgeBase, KnowledgeItem, ProcessingStatus } from '@renderer/types'
|
|
import { runAsyncFunction } from '@renderer/utils'
|
|
import { useEffect, useState } from 'react'
|
|
import { useDispatch, useSelector } from 'react-redux'
|
|
import { v4 as uuidv4 } from 'uuid'
|
|
|
|
import { useAgents } from './useAgents'
|
|
import { useAssistants } from './useAssistant'
|
|
import { IpcChannel } from '@shared/IpcChannel'
|
|
|
|
export const useKnowledge = (baseId: string) => {
|
|
const dispatch = useDispatch()
|
|
const base = useSelector((state: RootState) => state.knowledge.bases.find((b) => b.id === baseId))
|
|
|
|
// 重命名知识库
|
|
const renameKnowledgeBase = (name: string) => {
|
|
dispatch(renameBase({ baseId, name }))
|
|
}
|
|
|
|
// 更新知识库
|
|
const updateKnowledgeBase = (base: KnowledgeBase) => {
|
|
dispatch(updateBase(base))
|
|
}
|
|
|
|
// 批量添加文件
|
|
const addFiles = (files: FileType[]) => {
|
|
const filesItems: KnowledgeItem[] = files.map((file) => ({
|
|
id: uuidv4(),
|
|
type: 'file' as const,
|
|
content: file,
|
|
created_at: Date.now(),
|
|
updated_at: Date.now(),
|
|
processingStatus: 'pending',
|
|
processingProgress: 0,
|
|
processingError: '',
|
|
retryCount: 0
|
|
}))
|
|
dispatch(addFilesAction({ baseId, items: filesItems }))
|
|
setTimeout(() => KnowledgeQueue.checkAllBases(), 0)
|
|
}
|
|
|
|
// 添加URL
|
|
const addUrl = (url: string) => {
|
|
const newUrlItem: KnowledgeItem = {
|
|
id: uuidv4(),
|
|
type: 'url' as const,
|
|
content: url,
|
|
created_at: Date.now(),
|
|
updated_at: Date.now(),
|
|
processingStatus: 'pending',
|
|
processingProgress: 0,
|
|
processingError: '',
|
|
retryCount: 0
|
|
}
|
|
dispatch(addItem({ baseId, item: newUrlItem }))
|
|
setTimeout(() => KnowledgeQueue.checkAllBases(), 0)
|
|
}
|
|
|
|
// 添加笔记
|
|
const addNote = async (content: string) => {
|
|
const noteId = uuidv4()
|
|
const note: KnowledgeItem = {
|
|
id: noteId,
|
|
type: 'note',
|
|
content,
|
|
created_at: Date.now(),
|
|
updated_at: Date.now()
|
|
}
|
|
|
|
// 存储完整笔记到数据库
|
|
await db.knowledge_notes.add(note)
|
|
|
|
// 在 store 中只存储引用
|
|
const noteRef: KnowledgeItem = {
|
|
id: noteId,
|
|
baseId,
|
|
type: 'note',
|
|
content: '', // store中不需要存储实际内容
|
|
created_at: Date.now(),
|
|
updated_at: Date.now(),
|
|
processingStatus: 'pending',
|
|
processingProgress: 0,
|
|
processingError: '',
|
|
retryCount: 0
|
|
}
|
|
|
|
dispatch(updateNotes({ baseId, item: noteRef }))
|
|
setTimeout(() => KnowledgeQueue.checkAllBases(), 0)
|
|
}
|
|
|
|
// 更新笔记内容
|
|
const updateNoteContent = async (noteId: string, content: string) => {
|
|
const note = await db.knowledge_notes.get(noteId)
|
|
if (note) {
|
|
const updatedNote = {
|
|
...note,
|
|
content,
|
|
updated_at: Date.now()
|
|
}
|
|
await db.knowledge_notes.put(updatedNote)
|
|
dispatch(updateNotes({ baseId, item: updatedNote }))
|
|
}
|
|
const noteItem = base?.items.find((item) => item.id === noteId)
|
|
noteItem && refreshItem(noteItem)
|
|
}
|
|
|
|
// 获取笔记内容
|
|
const getNoteContent = async (noteId: string) => {
|
|
return await db.knowledge_notes.get(noteId)
|
|
}
|
|
|
|
const updateItem = (item: KnowledgeItem) => {
|
|
dispatch(updateItemAction({ baseId, item }))
|
|
}
|
|
|
|
// 移除项目
|
|
const removeItem = async (item: KnowledgeItem) => {
|
|
dispatch(removeItemAction({ baseId, item }))
|
|
if (base) {
|
|
if (item?.uniqueId && item?.uniqueIds) {
|
|
await window.api.knowledgeBase.remove({
|
|
uniqueId: item.uniqueId,
|
|
uniqueIds: item.uniqueIds,
|
|
base: getKnowledgeBaseParams(base)
|
|
})
|
|
}
|
|
}
|
|
if (item.type === 'file' && typeof item.content === 'object') {
|
|
await FileManager.deleteFile(item.content.id)
|
|
}
|
|
}
|
|
// 刷新项目
|
|
const refreshItem = async (item: KnowledgeItem) => {
|
|
const status = getProcessingStatus(item.id)
|
|
|
|
if (status === 'pending' || status === 'processing') {
|
|
return
|
|
}
|
|
|
|
if (base && item.uniqueId && item.uniqueIds) {
|
|
await window.api.knowledgeBase.remove({
|
|
uniqueId: item.uniqueId,
|
|
uniqueIds: item.uniqueIds,
|
|
base: getKnowledgeBaseParams(base)
|
|
})
|
|
updateItem({
|
|
...item,
|
|
processingStatus: 'pending',
|
|
processingProgress: 0,
|
|
processingError: '',
|
|
uniqueId: undefined
|
|
})
|
|
setTimeout(() => KnowledgeQueue.checkAllBases(), 0)
|
|
}
|
|
}
|
|
|
|
// 更新处理状态
|
|
const updateItemStatus = (itemId: string, status: ProcessingStatus, progress?: number, error?: string) => {
|
|
dispatch(
|
|
updateItemProcessingStatus({
|
|
baseId,
|
|
itemId,
|
|
status,
|
|
progress,
|
|
error
|
|
})
|
|
)
|
|
}
|
|
|
|
// 获取特定项目的处理状态
|
|
const getProcessingStatus = (itemId: string) => {
|
|
return base?.items.find((item) => item.id === itemId)?.processingStatus
|
|
}
|
|
|
|
// 获取特定类型的所有处理项
|
|
const getProcessingItemsByType = (type: 'file' | 'url' | 'note') => {
|
|
return base?.items.filter((item) => item.type === type && item.processingStatus !== undefined) || []
|
|
}
|
|
|
|
// 获取目录处理进度
|
|
const getDirectoryProcessingPercent = (itemId?: string) => {
|
|
const [percent, setPercent] = useState<number>(0)
|
|
|
|
useEffect(() => {
|
|
if (!itemId) {
|
|
return
|
|
}
|
|
|
|
const cleanup = window.electron.ipcRenderer.on(
|
|
IpcChannel.DirectoryProcessingPercent,
|
|
(_, { itemId: id, percent }: { itemId: string; percent: number }) => {
|
|
if (itemId === id) {
|
|
setPercent(percent)
|
|
}
|
|
}
|
|
)
|
|
|
|
return () => {
|
|
cleanup()
|
|
}
|
|
}, [itemId])
|
|
|
|
return percent
|
|
}
|
|
|
|
// 清除已完成的项目
|
|
const clearCompleted = () => {
|
|
dispatch(clearCompletedProcessing({ baseId }))
|
|
}
|
|
|
|
// 清除所有处理状态
|
|
const clearAll = () => {
|
|
dispatch(clearAllProcessing({ baseId }))
|
|
}
|
|
|
|
// 添加 Sitemap
|
|
const addSitemap = (url: string) => {
|
|
const newSitemapItem: KnowledgeItem = {
|
|
id: uuidv4(),
|
|
type: 'sitemap' as const,
|
|
content: url,
|
|
created_at: Date.now(),
|
|
updated_at: Date.now(),
|
|
processingStatus: 'pending',
|
|
processingProgress: 0,
|
|
processingError: '',
|
|
retryCount: 0
|
|
}
|
|
dispatch(addItem({ baseId, item: newSitemapItem }))
|
|
setTimeout(() => KnowledgeQueue.checkAllBases(), 0)
|
|
}
|
|
|
|
// Add directory support
|
|
const addDirectory = (path: string) => {
|
|
const newDirectoryItem: KnowledgeItem = {
|
|
id: uuidv4(),
|
|
type: 'directory',
|
|
content: path,
|
|
created_at: Date.now(),
|
|
updated_at: Date.now(),
|
|
processingStatus: 'pending',
|
|
processingProgress: 0,
|
|
processingError: '',
|
|
retryCount: 0
|
|
}
|
|
dispatch(addItem({ baseId, item: newDirectoryItem }))
|
|
setTimeout(() => KnowledgeQueue.checkAllBases(), 0)
|
|
}
|
|
|
|
const fileItems = base?.items.filter((item) => item.type === 'file') || []
|
|
const directoryItems = base?.items.filter((item) => item.type === 'directory') || []
|
|
const urlItems = base?.items.filter((item) => item.type === 'url') || []
|
|
const sitemapItems = base?.items.filter((item) => item.type === 'sitemap') || []
|
|
const [noteItems, setNoteItems] = useState<KnowledgeItem[]>([])
|
|
|
|
useEffect(() => {
|
|
const notes = base?.items.filter((item) => item.type === 'note') || []
|
|
runAsyncFunction(async () => {
|
|
const newNoteItems = await Promise.all(
|
|
notes.map(async (item) => {
|
|
const note = await db.knowledge_notes.get(item.id)
|
|
return { ...item, content: note?.content || '' }
|
|
})
|
|
)
|
|
setNoteItems(newNoteItems.filter((note) => note !== undefined) as KnowledgeItem[])
|
|
})
|
|
}, [base?.items])
|
|
|
|
return {
|
|
base,
|
|
fileItems,
|
|
urlItems,
|
|
sitemapItems,
|
|
noteItems,
|
|
renameKnowledgeBase,
|
|
updateKnowledgeBase,
|
|
addFiles,
|
|
addUrl,
|
|
addSitemap,
|
|
addNote,
|
|
updateNoteContent,
|
|
getNoteContent,
|
|
updateItem,
|
|
updateItemStatus,
|
|
refreshItem,
|
|
getProcessingStatus,
|
|
getProcessingItemsByType,
|
|
getDirectoryProcessingPercent,
|
|
clearCompleted,
|
|
clearAll,
|
|
removeItem,
|
|
directoryItems,
|
|
addDirectory
|
|
}
|
|
}
|
|
|
|
export const useKnowledgeBases = () => {
|
|
const dispatch = useDispatch()
|
|
const bases = useSelector((state: RootState) => state.knowledge.bases)
|
|
const { assistants, updateAssistants } = useAssistants()
|
|
const { agents, updateAgents } = useAgents()
|
|
|
|
const addKnowledgeBase = (base: KnowledgeBase) => {
|
|
dispatch(addBase(base))
|
|
}
|
|
|
|
const renameKnowledgeBase = (baseId: string, name: string) => {
|
|
dispatch(renameBase({ baseId, name }))
|
|
}
|
|
|
|
const deleteKnowledgeBase = (baseId: string) => {
|
|
dispatch(deleteBase({ baseId }))
|
|
|
|
// remove assistant knowledge_base
|
|
const _assistants = assistants.map((assistant) => {
|
|
if (assistant.knowledge_bases?.find((kb) => kb.id === baseId)) {
|
|
return {
|
|
...assistant,
|
|
knowledge_bases: assistant.knowledge_bases.filter((kb) => kb.id !== baseId)
|
|
}
|
|
}
|
|
return assistant
|
|
})
|
|
|
|
// remove agent knowledge_base
|
|
const _agents = agents.map((agent) => {
|
|
if (agent.knowledge_bases?.find((kb) => kb.id === baseId)) {
|
|
return {
|
|
...agent,
|
|
knowledge_bases: agent.knowledge_bases.filter((kb) => kb.id !== baseId)
|
|
}
|
|
}
|
|
return agent
|
|
})
|
|
|
|
updateAssistants(_assistants)
|
|
updateAgents(_agents)
|
|
}
|
|
|
|
const updateKnowledgeBases = (bases: KnowledgeBase[]) => {
|
|
dispatch(updateBases(bases))
|
|
}
|
|
|
|
return {
|
|
bases,
|
|
addKnowledgeBase,
|
|
renameKnowledgeBase,
|
|
deleteKnowledgeBase,
|
|
updateKnowledgeBases
|
|
}
|
|
}
|