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