diff --git a/src/main/services/MemoryFileService.ts b/src/main/services/MemoryFileService.ts index 258f7a3366..5c01294c31 100644 --- a/src/main/services/MemoryFileService.ts +++ b/src/main/services/MemoryFileService.ts @@ -81,8 +81,34 @@ export class MemoryFileService { // 如果文件不存在或读取失败,使用空对象 } - // 合并数据,优先使用新数据 - const mergedData = { ...existingData, ...data } + // 合并数据,注意数组的处理 + const mergedData = { ...existingData } + + // 处理每个属性 + Object.entries(data).forEach(([key, value]) => { + // 如果是数组属性,需要特殊处理 + if (Array.isArray(value) && Array.isArray(mergedData[key])) { + // 对于 memories 和 shortMemories,需要合并而不是覆盖 + if (key === 'memories' || key === 'shortMemories') { + // 创建一个集合来跟踪已存在的记忆ID + const existingIds = new Set(mergedData[key].map(item => item.id)) + + // 将新记忆添加到现有记忆中,避免重复 + value.forEach(item => { + if (item.id && !existingIds.has(item.id)) { + mergedData[key].push(item) + existingIds.add(item.id) + } + }) + } else { + // 其他数组属性,使用新值 + mergedData[key] = value + } + } else { + // 非数组属性,直接使用新值 + mergedData[key] = value + } + }) // 保存合并后的数据 await fs.writeFile(memoryDataPath, JSON.stringify(mergedData, null, 2)) diff --git a/src/renderer/src/i18n/locales/zh-cn.json b/src/renderer/src/i18n/locales/zh-cn.json index 60801b6a47..c49627a549 100644 --- a/src/renderer/src/i18n/locales/zh-cn.json +++ b/src/renderer/src/i18n/locales/zh-cn.json @@ -1070,6 +1070,26 @@ "enable": "启用智能优先级管理", "enableTip": "启用后,系统将根据重要性、访问频率和时间因素自动排序记忆", "decay": "记忆衰减", + "decayRate": "衰减速率", + "decayRateTip": "值越大,记忆衰减越快。0.05表示每天衰减5%", + "freshness": "记忆鲜度", + "freshnessTip": "考虑记忆的创建时间和最后访问时间,优先显示较新的记忆", + "updateNow": "立即更新", + "updateNowTip": "立即更新所有记忆的优先级排序", + "update": "更新" + }, + "contextualRecommendation": { + "title": "上下文感知记忆推荐", + "description": "根据当前对话上下文,智能推荐相关的记忆内容。", + "enable": "启用上下文感知记忆推荐", + "enableTip": "启用后,系统将根据当前对话上下文自动推荐相关记忆", + "autoRecommend": "自动推荐记忆", + "autoRecommendTip": "启用后,系统将定期自动分析当前对话并推荐相关记忆", + "threshold": "推荐阈值", + "thresholdTip": "设置记忆推荐的相似度阈值,值越高要求越严格", + "clearRecommendations": "清除当前推荐", + "clearRecommendationsTip": "清除当前的记忆推荐列表", + "clear": "清除", "decayTip": "随着时间推移,未访问的记忆重要性会逐渐降低", "decayRate": "衰减速率", "decayRateTip": "值越大,记忆衰减越快。0.05表示每天衰减5%", diff --git a/src/renderer/src/pages/settings/MemorySettings/index.tsx b/src/renderer/src/pages/settings/MemorySettings/index.tsx index cebea3d924..e072b54fae 100644 --- a/src/renderer/src/pages/settings/MemorySettings/index.tsx +++ b/src/renderer/src/pages/settings/MemorySettings/index.tsx @@ -9,7 +9,7 @@ import { import { useTheme } from '@renderer/context/ThemeProvider' import { TopicManager } from '@renderer/hooks/useTopic' import { analyzeAndAddShortMemories, useMemoryService } from '@renderer/services/MemoryService' -import store, { useAppDispatch, useAppSelector } from '@renderer/store' +import { useAppDispatch, useAppSelector } from '@renderer/store' import { addMemory, clearMemories, @@ -19,7 +19,8 @@ import { setAnalyzing, setAutoAnalyze, setMemoryActive, - setShortMemoryAnalyzeModel + setShortMemoryAnalyzeModel, + saveMemoryData } from '@renderer/store/memory' import { Topic } from '@renderer/types' import { Button, Empty, Input, List, message, Modal, Radio, Select, Switch, Tabs, Tag, Tooltip } from 'antd' @@ -260,18 +261,9 @@ const MemorySettings: FC = () => { dispatch(setAnalyzeModel(modelId)) console.log('[Memory Settings] Analyze model set:', modelId) - // 手动保存到JSON文件 + // 使用Redux Thunk保存到JSON文件 try { - const state = store.getState().memory - await window.api.memory.saveData({ - analyzeModel: modelId, - shortMemoryAnalyzeModel: state.shortMemoryAnalyzeModel, - vectorizeModel: state.vectorizeModel, - // 确保其他必要的数据也被保存 - memoryLists: state.memoryLists || [], - memories: state.memories || [], - shortMemories: state.shortMemories || [] - }) + await dispatch(saveMemoryData({ analyzeModel: modelId })).unwrap() console.log('[Memory Settings] Analyze model saved to file successfully:', modelId) } catch (error) { console.error('[Memory Settings] Failed to save analyze model to file:', error) @@ -283,18 +275,9 @@ const MemorySettings: FC = () => { dispatch(setShortMemoryAnalyzeModel(modelId)) console.log('[Memory Settings] Short memory analyze model set:', modelId) - // 手动保存到JSON文件 + // 使用Redux Thunk保存到JSON文件 try { - const state = store.getState().memory - await window.api.memory.saveData({ - analyzeModel: state.analyzeModel, - shortMemoryAnalyzeModel: modelId, - vectorizeModel: state.vectorizeModel, - // 确保其他必要的数据也被保存 - memoryLists: state.memoryLists || [], - memories: state.memories || [], - shortMemories: state.shortMemories || [] - }) + await dispatch(saveMemoryData({ shortMemoryAnalyzeModel: modelId })).unwrap() console.log('[Memory Settings] Short memory analyze model saved to file successfully:', modelId) } catch (error) { console.error('[Memory Settings] Failed to save short memory analyze model to file:', error) diff --git a/src/renderer/src/services/MemoryService.ts b/src/renderer/src/services/MemoryService.ts index bec80e933d..da39f38cf9 100644 --- a/src/renderer/src/services/MemoryService.ts +++ b/src/renderer/src/services/MemoryService.ts @@ -899,33 +899,42 @@ export const analyzeAndAddShortMemories = async (topicId: string) => { // 构建短期记忆分析提示词,包含已有记忆和新对话 const prompt = ` -请对以下对话内容进行详细分析和总结,提取对当前对话至关重要的上下文信息。 +请对以下对话内容进行非常详细的分析和总结,提取对当前对话至关重要的上下文信息。请注意,这个分析将用于生成短期记忆,帮助AI理解当前对话的完整上下文。 分析要求: -1. 详细总结用户的每一句话中表达的关键信息、需求和意图 -2. 分析AI回复中的重要内容和对用户问题的解决方案 -3. 识别对话中的重要事实、数据和具体细节 -4. 捕捉对话的逻辑发展和转折点 +1. 非常详细地总结用户的每一句话中表达的关键信息、需求和意图 +2. 全面分析AI回复中的重要内容和对用户问题的解决方案 +3. 详细记录对话中的重要事实、数据、代码示例和具体细节 +4. 清晰捕捉对话的逻辑发展、转折点和关键决策 5. 提取对理解当前对话上下文必不可少的信息 +6. 记录用户提出的具体问题和关注点 +7. 捕捉用户在对话中表达的偏好、困惑和反馈 +8. 记录对话中提到的文件、路径、变量名等具体技术细节 -与长期记忆不同,短期记忆应该关注当前对话的具体细节和上下文,而不是用户的长期偏好。每条短期记忆应该是对对话片段的精准总结,确保不遗漏任何重要信息。 +与长期记忆不同,短期记忆应该非常详细地关注当前对话的具体细节和上下文。每条短期记忆应该是对对话片段的精准总结,确保不遗漏任何重要信息。 + +请注意,对于长对话(超过5万字),您应该生成至少15-20条详细的记忆条目,确保完整捕捉对话的所有重要方面。对于超长对话(超过8万字),应生成至少20-30条记忆条目。 ${ existingMemoriesContent ? `以下是已经提取的重要信息: ${existingMemoriesContent} -请分析新的对话内容,提取出新的重要信息,避免重复已有信息。确保新提取的信息与已有信息形成连贯的上下文理解。` - : '请对对话进行全面分析,确保不遗漏任何重要细节。每条总结应该是完整的句子,清晰表达一个重要的上下文信息。' +请分析新的对话内容,提取出新的重要信息,避免重复已有信息。确保新提取的信息与已有信息形成连贯的上下文理解。对于新的对话内容,请提供非常详细的分析。` + : '请对对话进行非常全面和详细的分析,确保不遗漏任何重要细节。每条总结应该是完整的句子,清晰表达一个重要的上下文信息。请确保总结足够详细,以便在没有原始对话的情况下也能理解完整的上下文。' } 输出格式: -- 提供完整的上下文总结,数量不限,确保覆盖所有重要信息 -- 每条总结应该是一个完整的句子 +- 提供非常详细的上下文总结,数量不限,确保覆盖所有重要信息 +- 每条总结应该是一个完整的句子,包含充分的上下文信息 - 确保总结内容精准、具体且与当前对话直接相关 - 按重要性排序,最重要的信息放在前面 -- 对于复杂的对话,应提供足够多的条目(至少5-10条)以确保上下文的完整性 -- 如果对话内容简单,可以少于5条,但必须确保完整捕捉所有重要信息 +- 对于复杂的对话,必须提供足够多的条目(至少15-20条)以确保上下文的完整性 +- 对于技术内容,请包含具体的文件名、路径、变量名、函数名等技术细节 +- 对于代码相关的对话,请记录关键的代码片段和实现细节 +- 如果对话内容简单,可以少于15条,但必须确保完整捕捉所有重要信息 + +请记住,您的分析应该非常详细,不要过于简化或概括。对于8万字的对话,100字的总结是远远不够的,应该提供至少500-1000字的详细总结,分成多个条目。 如果没有找到新的重要信息,请返回空字符串。 diff --git a/src/renderer/src/store/memory.ts b/src/renderer/src/store/memory.ts index 1a5c46266c..18e3394f86 100644 --- a/src/renderer/src/store/memory.ts +++ b/src/renderer/src/store/memory.ts @@ -1,6 +1,7 @@ import { createSlice, createAsyncThunk, PayloadAction } from '@reduxjs/toolkit' import { nanoid } from 'nanoid' import log from 'electron-log' +import store from '@renderer/store' // 记忆列表接口 export interface MemoryList { @@ -851,12 +852,26 @@ export const saveMemoryData = createAsyncThunk( 'memory/saveData', async (data: Partial) => { try { - // log.info('Saving memory data to file...') // Removed direct log call from renderer - const result = await window.api.memory.saveData(data) - // log.info('Memory data saved successfully') // Removed direct log call from renderer + console.log('[Memory] Saving memory data to file...', Object.keys(data)) + + // 确保数据完整性 + const state = store.getState().memory + const completeData = { + ...data, + // 如果没有提供这些字段,则使用当前状态中的值 + memoryLists: data.memoryLists || state.memoryLists, + memories: data.memories || state.memories, + shortMemories: data.shortMemories || state.shortMemories, + analyzeModel: data.analyzeModel || state.analyzeModel, + shortMemoryAnalyzeModel: data.shortMemoryAnalyzeModel || state.shortMemoryAnalyzeModel, + vectorizeModel: data.vectorizeModel || state.vectorizeModel + } + + const result = await window.api.memory.saveData(completeData) + console.log('[Memory] Memory data saved successfully') return result } catch (error) { - console.error('Failed to save memory data:', error) // Use console.error instead of log.error + console.error('[Memory] Failed to save memory data:', error) return false } }