mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2025-12-29 23:12:38 +08:00
修复
This commit is contained in:
parent
bbdcd85014
commit
994ab7362f
@ -10,35 +10,48 @@ const memoryDataPath = path.join(getConfigDir(), 'memory-data.json')
|
||||
|
||||
export class MemoryFileService {
|
||||
constructor() {
|
||||
this.ensureMemoryFileExists()
|
||||
this.registerIpcHandlers()
|
||||
}
|
||||
|
||||
private async ensureMemoryFileExists() {
|
||||
try {
|
||||
const directory = path.dirname(memoryDataPath)
|
||||
await fs.mkdir(directory, { recursive: true })
|
||||
try {
|
||||
await fs.access(memoryDataPath)
|
||||
} catch (error) {
|
||||
// 文件不存在,创建一个空文件
|
||||
await fs.writeFile(memoryDataPath, JSON.stringify({
|
||||
memoryLists: [],
|
||||
memories: [],
|
||||
shortMemories: []
|
||||
}, null, 2))
|
||||
}
|
||||
} catch (error) {
|
||||
log.error('Failed to ensure memory file exists:', error)
|
||||
}
|
||||
}
|
||||
|
||||
private registerIpcHandlers() {
|
||||
// 读取记忆数据
|
||||
ipcMain.handle(IpcChannel.Memory_LoadData, async () => {
|
||||
try {
|
||||
// 确保配置目录存在
|
||||
const configDir = path.dirname(memoryDataPath)
|
||||
try {
|
||||
await fs.mkdir(configDir, { recursive: true })
|
||||
} catch (mkdirError) {
|
||||
log.warn('Failed to create config directory, it may already exist:', mkdirError)
|
||||
}
|
||||
|
||||
// 检查文件是否存在
|
||||
try {
|
||||
await fs.access(memoryDataPath)
|
||||
} catch (accessError) {
|
||||
// 文件不存在,创建默认文件
|
||||
log.info('Memory data file does not exist, creating default file')
|
||||
const defaultData = {
|
||||
memoryLists: [{
|
||||
id: 'default',
|
||||
name: '默认列表',
|
||||
isActive: true
|
||||
}],
|
||||
memories: [],
|
||||
shortMemories: [],
|
||||
analyzeModel: 'gpt-3.5-turbo',
|
||||
shortMemoryAnalyzeModel: 'gpt-3.5-turbo',
|
||||
vectorizeModel: 'gpt-3.5-turbo'
|
||||
}
|
||||
await fs.writeFile(memoryDataPath, JSON.stringify(defaultData, null, 2))
|
||||
return defaultData
|
||||
}
|
||||
|
||||
// 读取文件
|
||||
const data = await fs.readFile(memoryDataPath, 'utf-8')
|
||||
return JSON.parse(data)
|
||||
const parsedData = JSON.parse(data)
|
||||
log.info('Memory data loaded successfully')
|
||||
return parsedData
|
||||
} catch (error) {
|
||||
log.error('Failed to load memory data:', error)
|
||||
return null
|
||||
@ -48,7 +61,32 @@ export class MemoryFileService {
|
||||
// 保存记忆数据
|
||||
ipcMain.handle(IpcChannel.Memory_SaveData, async (_, data) => {
|
||||
try {
|
||||
await fs.writeFile(memoryDataPath, JSON.stringify(data, null, 2))
|
||||
// 确保配置目录存在
|
||||
const configDir = path.dirname(memoryDataPath)
|
||||
try {
|
||||
await fs.mkdir(configDir, { recursive: true })
|
||||
} catch (mkdirError) {
|
||||
log.warn('Failed to create config directory, it may already exist:', mkdirError)
|
||||
}
|
||||
|
||||
// 尝试读取现有数据并合并
|
||||
let existingData = {}
|
||||
try {
|
||||
await fs.access(memoryDataPath)
|
||||
const fileContent = await fs.readFile(memoryDataPath, 'utf-8')
|
||||
existingData = JSON.parse(fileContent)
|
||||
log.info('Existing memory data loaded for merging')
|
||||
} catch (readError) {
|
||||
log.warn('No existing memory data found or failed to read:', readError)
|
||||
// 如果文件不存在或读取失败,使用空对象
|
||||
}
|
||||
|
||||
// 合并数据,优先使用新数据
|
||||
const mergedData = { ...existingData, ...data }
|
||||
|
||||
// 保存合并后的数据
|
||||
await fs.writeFile(memoryDataPath, JSON.stringify(mergedData, null, 2))
|
||||
log.info('Memory data saved successfully')
|
||||
return true
|
||||
} catch (error) {
|
||||
log.error('Failed to save memory data:', error)
|
||||
|
||||
@ -41,8 +41,19 @@ const MemoryProvider: FC<MemoryProviderProps> = ({ children }) => {
|
||||
// 在组件挂载时加载记忆数据
|
||||
useEffect(() => {
|
||||
console.log('[MemoryProvider] Loading memory data from file')
|
||||
// 使用Redux Thunk加载记忆数据
|
||||
dispatch(loadMemoryData())
|
||||
}, [])
|
||||
.then((result) => {
|
||||
if (result.payload) {
|
||||
console.log('[MemoryProvider] Memory data loaded successfully via Redux Thunk')
|
||||
} else {
|
||||
console.log('[MemoryProvider] No memory data loaded or loading failed')
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('[MemoryProvider] Error loading memory data:', error)
|
||||
})
|
||||
}, [dispatch])
|
||||
|
||||
// 当对话更新时,触发记忆分析
|
||||
useEffect(() => {
|
||||
|
||||
@ -0,0 +1,141 @@
|
||||
import { InfoCircleOutlined } from '@ant-design/icons'
|
||||
import { useAppDispatch, useAppSelector } from '@renderer/store'
|
||||
import {
|
||||
setContextualRecommendationEnabled,
|
||||
setAutoRecommendMemories,
|
||||
setRecommendationThreshold,
|
||||
clearCurrentRecommendations
|
||||
} from '@renderer/store/memory'
|
||||
import { Button, InputNumber, Slider, Switch, Tooltip } from 'antd'
|
||||
import { FC } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import styled from 'styled-components'
|
||||
|
||||
import { SettingDivider, SettingGroup, SettingHelpText, SettingRow, SettingRowTitle, SettingTitle } from '..'
|
||||
|
||||
const SliderContainer = styled.div`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
max-width: 300px;
|
||||
margin-right: 16px;
|
||||
`
|
||||
|
||||
const ContextualRecommendationSettings: FC = () => {
|
||||
const { t } = useTranslation()
|
||||
const dispatch = useAppDispatch()
|
||||
|
||||
// 获取相关状态
|
||||
const contextualRecommendationEnabled = useAppSelector((state) => state.memory.contextualRecommendationEnabled)
|
||||
const autoRecommendMemories = useAppSelector((state) => state.memory.autoRecommendMemories)
|
||||
const recommendationThreshold = useAppSelector((state) => state.memory.recommendationThreshold)
|
||||
|
||||
// 处理开关状态变化
|
||||
const handleContextualRecommendationToggle = (checked: boolean) => {
|
||||
dispatch(setContextualRecommendationEnabled(checked))
|
||||
}
|
||||
|
||||
const handleAutoRecommendToggle = (checked: boolean) => {
|
||||
dispatch(setAutoRecommendMemories(checked))
|
||||
}
|
||||
|
||||
// 处理推荐阈值变化
|
||||
const handleThresholdChange = (value: number | null) => {
|
||||
if (value !== null) {
|
||||
dispatch(setRecommendationThreshold(value))
|
||||
}
|
||||
}
|
||||
|
||||
// 清除当前推荐
|
||||
const handleClearRecommendations = () => {
|
||||
dispatch(clearCurrentRecommendations())
|
||||
}
|
||||
|
||||
return (
|
||||
<SettingGroup>
|
||||
<SettingTitle>{t('settings.memory.contextualRecommendation.title') || '上下文感知记忆推荐'}</SettingTitle>
|
||||
<SettingHelpText>
|
||||
{t('settings.memory.contextualRecommendation.description') ||
|
||||
'根据当前对话上下文智能推荐相关记忆,提高AI回复的相关性和连贯性。'}
|
||||
</SettingHelpText>
|
||||
|
||||
<SettingRow>
|
||||
<SettingRowTitle>
|
||||
{t('settings.memory.contextualRecommendation.enable') || '启用上下文感知记忆推荐'}
|
||||
<Tooltip title={t('settings.memory.contextualRecommendation.enableTip') ||
|
||||
'启用后,系统将根据当前对话上下文自动推荐相关记忆'}>
|
||||
<InfoCircleOutlined style={{ marginLeft: 8 }} />
|
||||
</Tooltip>
|
||||
</SettingRowTitle>
|
||||
<Switch checked={contextualRecommendationEnabled} onChange={handleContextualRecommendationToggle} />
|
||||
</SettingRow>
|
||||
|
||||
<SettingDivider />
|
||||
|
||||
<SettingRow>
|
||||
<SettingRowTitle>
|
||||
{t('settings.memory.contextualRecommendation.autoRecommend') || '自动推荐记忆'}
|
||||
<Tooltip title={t('settings.memory.contextualRecommendation.autoRecommendTip') ||
|
||||
'启用后,系统将定期自动分析当前对话并推荐相关记忆'}>
|
||||
<InfoCircleOutlined style={{ marginLeft: 8 }} />
|
||||
</Tooltip>
|
||||
</SettingRowTitle>
|
||||
<Switch
|
||||
checked={autoRecommendMemories}
|
||||
onChange={handleAutoRecommendToggle}
|
||||
disabled={!contextualRecommendationEnabled}
|
||||
/>
|
||||
</SettingRow>
|
||||
|
||||
<SettingRow>
|
||||
<SettingRowTitle>
|
||||
{t('settings.memory.contextualRecommendation.threshold') || '推荐阈值'}
|
||||
<Tooltip title={t('settings.memory.contextualRecommendation.thresholdTip') ||
|
||||
'设置记忆推荐的相似度阈值,值越高要求越严格'}>
|
||||
<InfoCircleOutlined style={{ marginLeft: 8 }} />
|
||||
</Tooltip>
|
||||
</SettingRowTitle>
|
||||
<div style={{ display: 'flex', alignItems: 'center' }}>
|
||||
<SliderContainer>
|
||||
<Slider
|
||||
min={0.1}
|
||||
max={0.9}
|
||||
step={0.05}
|
||||
value={recommendationThreshold}
|
||||
onChange={handleThresholdChange}
|
||||
disabled={!contextualRecommendationEnabled}
|
||||
style={{ flex: 1 }}
|
||||
/>
|
||||
</SliderContainer>
|
||||
<InputNumber
|
||||
min={0.1}
|
||||
max={0.9}
|
||||
step={0.05}
|
||||
value={recommendationThreshold}
|
||||
onChange={handleThresholdChange}
|
||||
disabled={!contextualRecommendationEnabled}
|
||||
style={{ width: 70 }}
|
||||
/>
|
||||
</div>
|
||||
</SettingRow>
|
||||
|
||||
<SettingRow>
|
||||
<SettingRowTitle>
|
||||
{t('settings.memory.contextualRecommendation.clearRecommendations') || '清除当前推荐'}
|
||||
<Tooltip title={t('settings.memory.contextualRecommendation.clearRecommendationsTip') ||
|
||||
'清除当前的记忆推荐列表'}>
|
||||
<InfoCircleOutlined style={{ marginLeft: 8 }} />
|
||||
</Tooltip>
|
||||
</SettingRowTitle>
|
||||
<Button
|
||||
onClick={handleClearRecommendations}
|
||||
disabled={!contextualRecommendationEnabled}
|
||||
>
|
||||
{t('settings.memory.contextualRecommendation.clear') || '清除'}
|
||||
</Button>
|
||||
</SettingRow>
|
||||
</SettingGroup>
|
||||
)
|
||||
}
|
||||
|
||||
export default ContextualRecommendationSettings
|
||||
@ -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 { useAppDispatch, useAppSelector } from '@renderer/store'
|
||||
import store, { useAppDispatch, useAppSelector } from '@renderer/store'
|
||||
import {
|
||||
addMemory,
|
||||
clearMemories,
|
||||
@ -41,6 +41,7 @@ import MemoryDeduplicationPanel from './MemoryDeduplicationPanel'
|
||||
import MemoryListManager from './MemoryListManager'
|
||||
import MemoryMindMap from './MemoryMindMap'
|
||||
import PriorityManagementSettings from './PriorityManagementSettings'
|
||||
import ContextualRecommendationSettings from './ContextualRecommendationSettings'
|
||||
|
||||
const MemorySettings: FC = () => {
|
||||
const { t } = useTranslation()
|
||||
@ -255,13 +256,49 @@ const MemorySettings: FC = () => {
|
||||
}
|
||||
|
||||
// 处理选择长期记忆分析模型
|
||||
const handleSelectModel = (modelId: string) => {
|
||||
const handleSelectModel = async (modelId: string) => {
|
||||
dispatch(setAnalyzeModel(modelId))
|
||||
console.log('[Memory Settings] Analyze model set:', modelId)
|
||||
|
||||
// 手动保存到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 || []
|
||||
})
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
// 处理选择短期记忆分析模型
|
||||
const handleSelectShortMemoryModel = (modelId: string) => {
|
||||
const handleSelectShortMemoryModel = async (modelId: string) => {
|
||||
dispatch(setShortMemoryAnalyzeModel(modelId))
|
||||
console.log('[Memory Settings] Short memory analyze model set:', modelId)
|
||||
|
||||
// 手动保存到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 || []
|
||||
})
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
// 手动触发分析
|
||||
@ -571,6 +608,8 @@ const MemorySettings: FC = () => {
|
||||
children: (
|
||||
<TabPaneSettingGroup theme={theme}>
|
||||
<PriorityManagementSettings />
|
||||
<SettingDivider />
|
||||
<ContextualRecommendationSettings />
|
||||
</TabPaneSettingGroup>
|
||||
)
|
||||
},
|
||||
|
||||
530
src/renderer/src/services/ContextualMemoryService.ts
Normal file
530
src/renderer/src/services/ContextualMemoryService.ts
Normal file
@ -0,0 +1,530 @@
|
||||
// src/renderer/src/services/ContextualMemoryService.ts
|
||||
|
||||
import store from '@renderer/store'
|
||||
import { vectorService } from './VectorService'
|
||||
import { addMemoryRetrievalLatency } from '@renderer/store/memory'
|
||||
import { fetchGenerate } from '@renderer/services/ApiService'
|
||||
import { Message } from '@renderer/types'
|
||||
import { TopicManager } from '@renderer/hooks/useTopic'
|
||||
|
||||
// 记忆项接口(从store/memory.ts导入)
|
||||
interface Memory {
|
||||
id: string
|
||||
content: string
|
||||
createdAt: string
|
||||
source?: string
|
||||
category?: string
|
||||
listId: string
|
||||
analyzedMessageIds?: string[]
|
||||
lastMessageId?: string
|
||||
topicId?: string
|
||||
vector?: number[]
|
||||
entities?: string[]
|
||||
keywords?: string[]
|
||||
importance?: number
|
||||
accessCount?: number
|
||||
lastAccessedAt?: string
|
||||
decayFactor?: number
|
||||
freshness?: number
|
||||
}
|
||||
|
||||
interface ShortMemory {
|
||||
id: string
|
||||
content: string
|
||||
createdAt: string
|
||||
topicId: string
|
||||
analyzedMessageIds?: string[]
|
||||
lastMessageId?: string
|
||||
vector?: number[]
|
||||
entities?: string[]
|
||||
keywords?: string[]
|
||||
importance?: number
|
||||
accessCount?: number
|
||||
lastAccessedAt?: string
|
||||
decayFactor?: number
|
||||
freshness?: number
|
||||
}
|
||||
|
||||
// 记忆推荐结果接口
|
||||
export interface MemoryRecommendation {
|
||||
memory: Memory | ShortMemory
|
||||
relevanceScore: number
|
||||
source: 'long-term' | 'short-term'
|
||||
matchReason?: string
|
||||
}
|
||||
|
||||
/**
|
||||
* ContextualMemoryService 类负责实现上下文感知的记忆推荐和检索功能
|
||||
*/
|
||||
class ContextualMemoryService {
|
||||
/**
|
||||
* 基于当前对话上下文推荐相关记忆
|
||||
* @param messages - 当前对话的消息列表
|
||||
* @param topicId - 当前对话的话题ID
|
||||
* @param limit - 返回的最大记忆数量
|
||||
* @returns 推荐的记忆列表,按相关性排序
|
||||
*/
|
||||
async getContextualMemoryRecommendations(
|
||||
messages: Message[],
|
||||
topicId: string,
|
||||
limit: number = 5
|
||||
): Promise<MemoryRecommendation[]> {
|
||||
console.log(`[ContextualMemory] Getting contextual memory recommendations for topic ${topicId}`)
|
||||
|
||||
const startTime = performance.now()
|
||||
|
||||
try {
|
||||
// 获取当前状态
|
||||
const state = store.getState()
|
||||
const memoryState = state.memory
|
||||
|
||||
if (!memoryState) {
|
||||
console.log('[ContextualMemory] Memory state not available')
|
||||
return []
|
||||
}
|
||||
|
||||
// 检查记忆功能是否激活
|
||||
if (!memoryState.isActive && !memoryState.shortMemoryActive) {
|
||||
console.log('[ContextualMemory] Memory features are not active')
|
||||
return []
|
||||
}
|
||||
|
||||
// 获取最近的消息作为上下文
|
||||
const recentMessages = messages.slice(-5)
|
||||
if (recentMessages.length === 0) {
|
||||
console.log('[ContextualMemory] No recent messages available')
|
||||
return []
|
||||
}
|
||||
|
||||
// 构建上下文查询文本
|
||||
const contextQuery = this._buildContextQuery(recentMessages)
|
||||
console.log(`[ContextualMemory] Context query: ${contextQuery}`)
|
||||
|
||||
// 并行获取长期记忆和短期记忆的推荐
|
||||
const [longTermRecommendations, shortTermRecommendations] = await Promise.all([
|
||||
this._getLongTermMemoryRecommendations(contextQuery, topicId),
|
||||
this._getShortTermMemoryRecommendations(contextQuery, topicId)
|
||||
])
|
||||
|
||||
// 合并并排序推荐结果
|
||||
let allRecommendations = [...longTermRecommendations, ...shortTermRecommendations]
|
||||
|
||||
// 按相关性分数排序
|
||||
allRecommendations.sort((a, b) => b.relevanceScore - a.relevanceScore)
|
||||
|
||||
// 限制返回数量
|
||||
const limitedRecommendations = allRecommendations.slice(0, limit)
|
||||
|
||||
// 记录性能指标
|
||||
const endTime = performance.now()
|
||||
const latency = endTime - startTime
|
||||
store.dispatch(addMemoryRetrievalLatency(latency))
|
||||
|
||||
console.log(`[ContextualMemory] Found ${limitedRecommendations.length} recommendations in ${latency.toFixed(2)}ms`)
|
||||
|
||||
return limitedRecommendations
|
||||
} catch (error) {
|
||||
console.error('[ContextualMemory] Error getting contextual memory recommendations:', error)
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 基于当前对话主题自动提取相关记忆
|
||||
* @param topicId - 当前对话的话题ID
|
||||
* @param limit - 返回的最大记忆数量
|
||||
* @returns 与当前主题相关的记忆列表
|
||||
*/
|
||||
async getTopicRelatedMemories(topicId: string, limit: number = 10): Promise<MemoryRecommendation[]> {
|
||||
console.log(`[ContextualMemory] Getting topic-related memories for topic ${topicId}`)
|
||||
|
||||
try {
|
||||
// 获取当前状态
|
||||
const state = store.getState()
|
||||
const memoryState = state.memory
|
||||
const messagesState = state.messages
|
||||
|
||||
if (!memoryState || !messagesState) {
|
||||
console.log('[ContextualMemory] Required state not available')
|
||||
return []
|
||||
}
|
||||
|
||||
// 获取话题信息
|
||||
// 使用TopicManager获取话题
|
||||
let topicQuery = ''
|
||||
try {
|
||||
const topic = await TopicManager.getTopic(topicId)
|
||||
if (!topic) {
|
||||
console.log(`[ContextualMemory] Topic ${topicId} not found`)
|
||||
return []
|
||||
}
|
||||
|
||||
// 使用话题ID作为查询
|
||||
// 注意:TopicManager.getTopic返回的类型只有id和messages属性
|
||||
topicQuery = `Topic ${topicId}`
|
||||
if (!topicQuery.trim()) {
|
||||
console.log('[ContextualMemory] No topic information available for query')
|
||||
return []
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`[ContextualMemory] Error getting topic ${topicId}:`, error)
|
||||
return []
|
||||
}
|
||||
|
||||
console.log(`[ContextualMemory] Topic query: ${topicQuery}`)
|
||||
|
||||
// 并行获取长期记忆和短期记忆的推荐
|
||||
const [longTermRecommendations, shortTermRecommendations] = await Promise.all([
|
||||
this._getLongTermMemoryRecommendations(topicQuery, topicId),
|
||||
this._getShortTermMemoryRecommendations(topicQuery, topicId)
|
||||
])
|
||||
|
||||
// 合并并排序推荐结果
|
||||
let allRecommendations = [...longTermRecommendations, ...shortTermRecommendations]
|
||||
|
||||
// 按相关性分数排序
|
||||
allRecommendations.sort((a, b) => b.relevanceScore - a.relevanceScore)
|
||||
|
||||
// 限制返回数量
|
||||
const limitedRecommendations = allRecommendations.slice(0, limit)
|
||||
|
||||
console.log(`[ContextualMemory] Found ${limitedRecommendations.length} topic-related memories`)
|
||||
|
||||
return limitedRecommendations
|
||||
} catch (error) {
|
||||
console.error('[ContextualMemory] Error getting topic-related memories:', error)
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用语义搜索查找与查询相关的记忆
|
||||
* @param query - 搜索查询
|
||||
* @param limit - 返回的最大记忆数量
|
||||
* @returns 与查询相关的记忆列表
|
||||
*/
|
||||
async searchMemoriesBySemantics(query: string, limit: number = 10): Promise<MemoryRecommendation[]> {
|
||||
console.log(`[ContextualMemory] Semantic search for: ${query}`)
|
||||
|
||||
try {
|
||||
// 获取当前状态
|
||||
const state = store.getState()
|
||||
const memoryState = state.memory
|
||||
|
||||
if (!memoryState) {
|
||||
console.log('[ContextualMemory] Memory state not available')
|
||||
return []
|
||||
}
|
||||
|
||||
// 并行获取长期记忆和短期记忆的推荐
|
||||
const [longTermRecommendations, shortTermRecommendations] = await Promise.all([
|
||||
this._getLongTermMemoryRecommendations(query),
|
||||
this._getShortTermMemoryRecommendations(query)
|
||||
])
|
||||
|
||||
// 合并并排序推荐结果
|
||||
let allRecommendations = [...longTermRecommendations, ...shortTermRecommendations]
|
||||
|
||||
// 按相关性分数排序
|
||||
allRecommendations.sort((a, b) => b.relevanceScore - a.relevanceScore)
|
||||
|
||||
// 限制返回数量
|
||||
const limitedRecommendations = allRecommendations.slice(0, limit)
|
||||
|
||||
console.log(`[ContextualMemory] Found ${limitedRecommendations.length} memories matching query`)
|
||||
|
||||
return limitedRecommendations
|
||||
} catch (error) {
|
||||
console.error('[ContextualMemory] Error searching memories by semantics:', error)
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用AI分析当前对话上下文,提取关键信息并推荐相关记忆
|
||||
* @param messages - 当前对话的消息列表
|
||||
* @param limit - 返回的最大记忆数量
|
||||
* @returns 基于AI分析的相关记忆推荐
|
||||
*/
|
||||
async getAIEnhancedMemoryRecommendations(messages: Message[], limit: number = 5): Promise<MemoryRecommendation[]> {
|
||||
console.log('[ContextualMemory] Getting AI-enhanced memory recommendations')
|
||||
|
||||
try {
|
||||
// 获取当前状态
|
||||
const state = store.getState()
|
||||
const memoryState = state.memory
|
||||
|
||||
if (!memoryState) {
|
||||
console.log('[ContextualMemory] Memory state not available')
|
||||
return []
|
||||
}
|
||||
|
||||
// 获取分析模型
|
||||
const analyzeModel = memoryState.analyzeModel
|
||||
if (!analyzeModel) {
|
||||
console.log('[ContextualMemory] No analyze model set')
|
||||
return []
|
||||
}
|
||||
|
||||
// 获取最近的消息作为上下文
|
||||
const recentMessages = messages.slice(-10)
|
||||
if (recentMessages.length === 0) {
|
||||
console.log('[ContextualMemory] No recent messages available')
|
||||
return []
|
||||
}
|
||||
|
||||
// 构建对话内容
|
||||
const conversation = recentMessages.map(msg => `${msg.role || 'user'}: ${msg.content || ''}`).join('\n')
|
||||
|
||||
// 构建提示词
|
||||
const prompt = `
|
||||
请分析以下对话内容,提取出关键信息和主题,以便我可以找到相关的记忆。
|
||||
|
||||
请提供:
|
||||
1. 对话的主要主题
|
||||
2. 用户可能关心的关键信息点
|
||||
3. 可能与此对话相关的背景知识或上下文
|
||||
|
||||
请以简洁的关键词和短语形式回答,每行一个要点,不要使用编号或项目符号。
|
||||
|
||||
对话内容:
|
||||
${conversation}
|
||||
`
|
||||
|
||||
// 调用AI生成文本
|
||||
console.log('[ContextualMemory] Calling AI for context analysis...')
|
||||
const result = await fetchGenerate({
|
||||
prompt: prompt,
|
||||
content: conversation,
|
||||
modelId: analyzeModel
|
||||
})
|
||||
|
||||
if (!result || typeof result !== 'string' || result.trim() === '') {
|
||||
console.log('[ContextualMemory] No valid result from AI analysis')
|
||||
return []
|
||||
}
|
||||
|
||||
// 提取关键信息
|
||||
const keyPoints = result
|
||||
.split('\n')
|
||||
.map(line => line.trim())
|
||||
.filter(line => line && !line.startsWith('#') && !line.startsWith('-'))
|
||||
|
||||
console.log('[ContextualMemory] Extracted key points:', keyPoints)
|
||||
|
||||
// 使用提取的关键信息作为查询
|
||||
const enhancedQuery = keyPoints.join(' ')
|
||||
|
||||
// 获取相关记忆
|
||||
return await this.searchMemoriesBySemantics(enhancedQuery, limit)
|
||||
} catch (error) {
|
||||
console.error('[ContextualMemory] Error getting AI-enhanced memory recommendations:', error)
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建上下文查询文本
|
||||
* @param messages - 消息列表
|
||||
* @returns 构建的查询文本
|
||||
* @private
|
||||
*/
|
||||
private _buildContextQuery(messages: Message[]): string {
|
||||
// 提取最近消息的内容
|
||||
const messageContents = messages.map(msg => msg.content || '').filter(content => content.trim() !== '')
|
||||
|
||||
// 如果没有有效内容,返回空字符串
|
||||
if (messageContents.length === 0) {
|
||||
return ''
|
||||
}
|
||||
|
||||
// 合并消息内容,最多使用最近的3条消息
|
||||
return messageContents.slice(-3).join(' ')
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取与查询相关的长期记忆推荐
|
||||
* @param query - 查询文本
|
||||
* @param topicId - 可选的话题ID,用于过滤记忆
|
||||
* @returns 长期记忆推荐列表
|
||||
* @private
|
||||
*/
|
||||
private async _getLongTermMemoryRecommendations(
|
||||
query: string,
|
||||
topicId?: string
|
||||
): Promise<MemoryRecommendation[]> {
|
||||
// 获取当前状态
|
||||
const state = store.getState()
|
||||
const memoryState = state.memory
|
||||
|
||||
// 检查长期记忆功能是否激活
|
||||
if (!memoryState || !memoryState.isActive) {
|
||||
return []
|
||||
}
|
||||
|
||||
// 获取所有激活的记忆列表
|
||||
const activeListIds = memoryState.memoryLists
|
||||
.filter(list => list.isActive)
|
||||
.map(list => list.id)
|
||||
|
||||
if (activeListIds.length === 0) {
|
||||
return []
|
||||
}
|
||||
|
||||
// 获取激活列表中的记忆
|
||||
const memories = memoryState.memories.filter(memory => activeListIds.includes(memory.listId))
|
||||
|
||||
if (memories.length === 0) {
|
||||
return []
|
||||
}
|
||||
|
||||
// 使用向量服务查找相似记忆
|
||||
const results = await vectorService.findSimilarMemoriesToQuery(
|
||||
query,
|
||||
memories,
|
||||
20, // 获取更多结果,后续会进一步优化排序
|
||||
0.5 // 降低阈值以获取更多潜在相关记忆
|
||||
)
|
||||
|
||||
// 转换为推荐格式
|
||||
const recommendations: MemoryRecommendation[] = results.map(result => ({
|
||||
memory: result.memory as Memory,
|
||||
relevanceScore: result.similarity,
|
||||
source: 'long-term',
|
||||
matchReason: '语义相似'
|
||||
}))
|
||||
|
||||
// 应用高级排序优化
|
||||
return this._optimizeRelevanceRanking(recommendations, query, topicId)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取与查询相关的短期记忆推荐
|
||||
* @param query - 查询文本
|
||||
* @param topicId - 可选的话题ID,用于过滤记忆
|
||||
* @returns 短期记忆推荐列表
|
||||
* @private
|
||||
*/
|
||||
private async _getShortTermMemoryRecommendations(
|
||||
query: string,
|
||||
topicId?: string
|
||||
): Promise<MemoryRecommendation[]> {
|
||||
// 获取当前状态
|
||||
const state = store.getState()
|
||||
const memoryState = state.memory
|
||||
|
||||
// 检查短期记忆功能是否激活
|
||||
if (!memoryState || !memoryState.shortMemoryActive) {
|
||||
return []
|
||||
}
|
||||
|
||||
// 获取短期记忆
|
||||
let shortMemories = memoryState.shortMemories
|
||||
|
||||
// 如果指定了话题ID,只获取该话题的短期记忆
|
||||
if (topicId) {
|
||||
shortMemories = shortMemories.filter(memory => memory.topicId === topicId)
|
||||
}
|
||||
|
||||
if (shortMemories.length === 0) {
|
||||
return []
|
||||
}
|
||||
|
||||
// 使用向量服务查找相似记忆
|
||||
const results = await vectorService.findSimilarMemoriesToQuery(
|
||||
query,
|
||||
shortMemories,
|
||||
20, // 获取更多结果,后续会进一步优化排序
|
||||
0.5 // 降低阈值以获取更多潜在相关记忆
|
||||
)
|
||||
|
||||
// 转换为推荐格式
|
||||
const recommendations: MemoryRecommendation[] = results.map(result => ({
|
||||
memory: result.memory as ShortMemory,
|
||||
relevanceScore: result.similarity,
|
||||
source: 'short-term',
|
||||
matchReason: '与当前对话相关'
|
||||
}))
|
||||
|
||||
// 应用高级排序优化
|
||||
return this._optimizeRelevanceRanking(recommendations, query, topicId)
|
||||
}
|
||||
|
||||
/**
|
||||
* 优化记忆推荐的相关性排序
|
||||
* @param recommendations - 初始推荐列表
|
||||
* @param query - 查询文本
|
||||
* @param topicId - 可选的话题ID
|
||||
* @returns 优化排序后的推荐列表
|
||||
* @private
|
||||
*/
|
||||
private _optimizeRelevanceRanking(
|
||||
recommendations: MemoryRecommendation[],
|
||||
query: string,
|
||||
topicId?: string
|
||||
): MemoryRecommendation[] {
|
||||
if (recommendations.length === 0) {
|
||||
return []
|
||||
}
|
||||
|
||||
// 获取当前状态
|
||||
const state = store.getState()
|
||||
const memoryState = state.memory
|
||||
|
||||
// 应用多因素排序优化
|
||||
return recommendations.map(rec => {
|
||||
const memory = rec.memory
|
||||
let adjustedScore = rec.relevanceScore
|
||||
|
||||
// 1. 考虑记忆的重要性
|
||||
if (memory.importance && memoryState.priorityManagementEnabled) {
|
||||
adjustedScore *= (1 + memory.importance * 0.5) // 重要性最多提升50%的分数
|
||||
}
|
||||
|
||||
// 2. 考虑记忆的鲜度
|
||||
if (memory.freshness && memoryState.freshnessEnabled) {
|
||||
adjustedScore *= (1 + memory.freshness * 0.3) // 鲜度最多提升30%的分数
|
||||
}
|
||||
|
||||
// 3. 考虑记忆的衰减因子
|
||||
if (memory.decayFactor && memoryState.decayEnabled) {
|
||||
adjustedScore *= memory.decayFactor // 直接应用衰减因子
|
||||
}
|
||||
|
||||
// 4. 如果记忆与当前话题相关,提高分数
|
||||
if (topicId && memory.topicId === topicId) {
|
||||
adjustedScore *= 1.2 // 提高20%的分数
|
||||
}
|
||||
|
||||
// 5. 考虑访问频率,常用的记忆可能更相关
|
||||
if (memory.accessCount && memory.accessCount > 0) {
|
||||
// 访问次数越多,提升越大,但有上限
|
||||
const accessBoost = Math.min(memory.accessCount / 10, 0.2) // 最多提升20%
|
||||
adjustedScore *= (1 + accessBoost)
|
||||
}
|
||||
|
||||
// 6. 考虑关键词匹配
|
||||
if (memory.keywords && memory.keywords.length > 0) {
|
||||
const queryLower = query.toLowerCase()
|
||||
const keywordMatches = memory.keywords.filter(keyword =>
|
||||
queryLower.includes(keyword.toLowerCase())
|
||||
).length
|
||||
|
||||
if (keywordMatches > 0) {
|
||||
// 关键词匹配越多,提升越大
|
||||
const keywordBoost = Math.min(keywordMatches * 0.1, 0.3) // 最多提升30%
|
||||
adjustedScore *= (1 + keywordBoost)
|
||||
}
|
||||
}
|
||||
|
||||
// 返回调整后的推荐
|
||||
return {
|
||||
...rec,
|
||||
relevanceScore: adjustedScore
|
||||
}
|
||||
}).sort((a, b) => b.relevanceScore - a.relevanceScore) // 按调整后的分数重新排序
|
||||
}
|
||||
}
|
||||
|
||||
// 导出 ContextualMemoryService 的单例
|
||||
export const contextualMemoryService = new ContextualMemoryService()
|
||||
@ -16,9 +16,15 @@ import {
|
||||
updateMemoryPriorities,
|
||||
accessMemory,
|
||||
Memory,
|
||||
saveMemoryData // <-- 添加 saveMemoryData
|
||||
saveMemoryData,
|
||||
updateCurrentRecommendations,
|
||||
setRecommending,
|
||||
clearCurrentRecommendations,
|
||||
MemoryRecommendation
|
||||
} from '@renderer/store/memory'
|
||||
import { useCallback, useEffect, useRef } from 'react' // Add useRef back
|
||||
import { contextualMemoryService } from './ContextualMemoryService' // Import contextual memory service
|
||||
import { Message } from '@renderer/types' // Import Message type
|
||||
|
||||
// 计算对话复杂度,用于调整分析深度
|
||||
const calculateConversationComplexity = (conversation: string): 'low' | 'medium' | 'high' => {
|
||||
@ -167,6 +173,162 @@ ${conversation}
|
||||
|
||||
// This function definition is a duplicate, removing it.
|
||||
|
||||
/**
|
||||
* 获取上下文感知的记忆推荐
|
||||
* @param messages - 当前对话的消息列表
|
||||
* @param topicId - 当前对话的话题ID
|
||||
* @param limit - 返回的最大记忆数量
|
||||
* @returns 推荐的记忆列表,按相关性排序
|
||||
*/
|
||||
export const getContextualMemoryRecommendations = async (
|
||||
messages: Message[],
|
||||
topicId: string,
|
||||
limit: number = 5
|
||||
): Promise<MemoryRecommendation[]> => {
|
||||
try {
|
||||
// 获取当前状态
|
||||
const state = store.getState().memory
|
||||
|
||||
// 检查上下文感知记忆推荐是否启用
|
||||
if (!state?.contextualRecommendationEnabled) {
|
||||
console.log('[ContextualMemory] Contextual recommendation is not enabled')
|
||||
return []
|
||||
}
|
||||
|
||||
// 设置推荐状态
|
||||
store.dispatch(setRecommending(true))
|
||||
|
||||
// 调用上下文感知记忆服务获取推荐
|
||||
const recommendations = await contextualMemoryService.getContextualMemoryRecommendations(
|
||||
messages,
|
||||
topicId,
|
||||
limit
|
||||
)
|
||||
|
||||
// 转换为Redux状态中的推荐格式
|
||||
const memoryRecommendations: MemoryRecommendation[] = recommendations.map(rec => ({
|
||||
memoryId: rec.memory.id,
|
||||
relevanceScore: rec.relevanceScore,
|
||||
source: rec.source,
|
||||
matchReason: rec.matchReason
|
||||
}))
|
||||
|
||||
// 更新Redux状态
|
||||
store.dispatch(updateCurrentRecommendations(memoryRecommendations))
|
||||
|
||||
// 重置推荐状态
|
||||
store.dispatch(setRecommending(false))
|
||||
|
||||
return memoryRecommendations
|
||||
} catch (error) {
|
||||
console.error('[ContextualMemory] Error getting contextual memory recommendations:', error)
|
||||
store.dispatch(setRecommending(false))
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 基于当前对话主题自动提取相关记忆
|
||||
* @param topicId - 当前对话的话题ID
|
||||
* @param limit - 返回的最大记忆数量
|
||||
* @returns 与当前主题相关的记忆列表
|
||||
*/
|
||||
export const getTopicRelatedMemories = async (
|
||||
topicId: string,
|
||||
limit: number = 10
|
||||
): Promise<MemoryRecommendation[]> => {
|
||||
try {
|
||||
// 获取当前状态
|
||||
const state = store.getState().memory
|
||||
|
||||
// 检查上下文感知记忆推荐是否启用
|
||||
if (!state?.contextualRecommendationEnabled) {
|
||||
console.log('[ContextualMemory] Contextual recommendation is not enabled')
|
||||
return []
|
||||
}
|
||||
|
||||
// 设置推荐状态
|
||||
store.dispatch(setRecommending(true))
|
||||
|
||||
// 调用上下文感知记忆服务获取推荐
|
||||
const recommendations = await contextualMemoryService.getTopicRelatedMemories(
|
||||
topicId,
|
||||
limit
|
||||
)
|
||||
|
||||
// 转换为Redux状态中的推荐格式
|
||||
const memoryRecommendations: MemoryRecommendation[] = recommendations.map(rec => ({
|
||||
memoryId: rec.memory.id,
|
||||
relevanceScore: rec.relevanceScore,
|
||||
source: rec.source,
|
||||
matchReason: rec.matchReason
|
||||
}))
|
||||
|
||||
// 更新Redux状态
|
||||
store.dispatch(updateCurrentRecommendations(memoryRecommendations))
|
||||
|
||||
// 重置推荐状态
|
||||
store.dispatch(setRecommending(false))
|
||||
|
||||
return memoryRecommendations
|
||||
} catch (error) {
|
||||
console.error('[ContextualMemory] Error getting topic-related memories:', error)
|
||||
store.dispatch(setRecommending(false))
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用AI分析当前对话上下文,提取关键信息并推荐相关记忆
|
||||
* @param messages - 当前对话的消息列表
|
||||
* @param limit - 返回的最大记忆数量
|
||||
* @returns 基于AI分析的相关记忆推荐
|
||||
*/
|
||||
export const getAIEnhancedMemoryRecommendations = async (
|
||||
messages: Message[],
|
||||
limit: number = 5
|
||||
): Promise<MemoryRecommendation[]> => {
|
||||
try {
|
||||
// 获取当前状态
|
||||
const state = store.getState().memory
|
||||
|
||||
// 检查上下文感知记忆推荐是否启用
|
||||
if (!state?.contextualRecommendationEnabled) {
|
||||
console.log('[ContextualMemory] Contextual recommendation is not enabled')
|
||||
return []
|
||||
}
|
||||
|
||||
// 设置推荐状态
|
||||
store.dispatch(setRecommending(true))
|
||||
|
||||
// 调用上下文感知记忆服务获取推荐
|
||||
const recommendations = await contextualMemoryService.getAIEnhancedMemoryRecommendations(
|
||||
messages,
|
||||
limit
|
||||
)
|
||||
|
||||
// 转换为Redux状态中的推荐格式
|
||||
const memoryRecommendations: MemoryRecommendation[] = recommendations.map(rec => ({
|
||||
memoryId: rec.memory.id,
|
||||
relevanceScore: rec.relevanceScore,
|
||||
source: rec.source,
|
||||
matchReason: rec.matchReason
|
||||
}))
|
||||
|
||||
// 更新Redux状态
|
||||
store.dispatch(updateCurrentRecommendations(memoryRecommendations))
|
||||
|
||||
// 重置推荐状态
|
||||
store.dispatch(setRecommending(false))
|
||||
|
||||
return memoryRecommendations
|
||||
} catch (error) {
|
||||
console.error('[ContextualMemory] Error getting AI-enhanced memory recommendations:', error)
|
||||
store.dispatch(setRecommending(false))
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
// 记忆服务钩子 - 重构版
|
||||
export const useMemoryService = () => {
|
||||
const dispatch = useAppDispatch()
|
||||
@ -174,6 +336,8 @@ export const useMemoryService = () => {
|
||||
const isActive = useAppSelector((state) => state.memory?.isActive || false)
|
||||
const autoAnalyze = useAppSelector((state) => state.memory?.autoAnalyze || false)
|
||||
const analyzeModel = useAppSelector((state) => state.memory?.analyzeModel || null)
|
||||
const contextualRecommendationEnabled = useAppSelector((state) => state.memory?.contextualRecommendationEnabled || false)
|
||||
const autoRecommendMemories = useAppSelector((state) => state.memory?.autoRecommendMemories || false)
|
||||
|
||||
// 使用 useCallback 定义分析函数,但减少依赖项
|
||||
// 增加可选的 topicId 参数,允许分析指定的话题
|
||||
@ -559,8 +723,85 @@ ${newConversation}
|
||||
// 依赖项只包含决定是否启动定时器的设置
|
||||
}, [isActive, autoAnalyze, analyzeModel])
|
||||
|
||||
// 返回分析函数和记忆访问函数,以便在其他组件中使用
|
||||
return { analyzeAndAddMemories, recordMemoryAccess }
|
||||
// 获取上下文感知记忆推荐
|
||||
const getContextualRecommendations = useCallback(
|
||||
async (messages: Message[], topicId: string, limit: number = 5) => {
|
||||
if (!contextualRecommendationEnabled) {
|
||||
console.log('[ContextualMemory] Contextual recommendation is not enabled')
|
||||
return []
|
||||
}
|
||||
|
||||
return await getContextualMemoryRecommendations(messages, topicId, limit)
|
||||
},
|
||||
[contextualRecommendationEnabled]
|
||||
)
|
||||
|
||||
// 获取主题相关记忆
|
||||
const getTopicRecommendations = useCallback(
|
||||
async (topicId: string, limit: number = 10) => {
|
||||
if (!contextualRecommendationEnabled) {
|
||||
console.log('[ContextualMemory] Contextual recommendation is not enabled')
|
||||
return []
|
||||
}
|
||||
|
||||
return await getTopicRelatedMemories(topicId, limit)
|
||||
},
|
||||
[contextualRecommendationEnabled]
|
||||
)
|
||||
|
||||
// 获取AI增强记忆推荐
|
||||
const getAIRecommendations = useCallback(
|
||||
async (messages: Message[], limit: number = 5) => {
|
||||
if (!contextualRecommendationEnabled) {
|
||||
console.log('[ContextualMemory] Contextual recommendation is not enabled')
|
||||
return []
|
||||
}
|
||||
|
||||
return await getAIEnhancedMemoryRecommendations(messages, limit)
|
||||
},
|
||||
[contextualRecommendationEnabled]
|
||||
)
|
||||
|
||||
// 清除当前记忆推荐
|
||||
const clearRecommendations = useCallback(() => {
|
||||
dispatch(clearCurrentRecommendations())
|
||||
}, [dispatch])
|
||||
|
||||
// 自动记忆推荐定时器
|
||||
useEffect(() => {
|
||||
if (!contextualRecommendationEnabled || !autoRecommendMemories) {
|
||||
return
|
||||
}
|
||||
|
||||
console.log('[ContextualMemory] Setting up auto recommendation timer...')
|
||||
|
||||
// 每5分钟自动推荐一次记忆
|
||||
const intervalId = setInterval(() => {
|
||||
const state = store.getState()
|
||||
const currentTopicId = state.messages.currentTopic?.id
|
||||
const messages = currentTopicId ? state.messages.messagesByTopic?.[currentTopicId] || [] : []
|
||||
|
||||
if (currentTopicId && messages.length > 0) {
|
||||
console.log('[ContextualMemory] Auto recommendation triggered')
|
||||
getContextualRecommendations(messages, currentTopicId)
|
||||
}
|
||||
}, 5 * 60 * 1000) // 5分钟
|
||||
|
||||
return () => {
|
||||
console.log('[ContextualMemory] Clearing auto recommendation timer')
|
||||
clearInterval(intervalId)
|
||||
}
|
||||
}, [contextualRecommendationEnabled, autoRecommendMemories, getContextualRecommendations])
|
||||
|
||||
// 返回分析函数、记忆访问函数和记忆推荐函数,以便在其他组件中使用
|
||||
return {
|
||||
analyzeAndAddMemories,
|
||||
recordMemoryAccess,
|
||||
getContextualRecommendations,
|
||||
getTopicRecommendations,
|
||||
getAIRecommendations,
|
||||
clearRecommendations
|
||||
}
|
||||
}
|
||||
|
||||
// 手动添加短记忆
|
||||
@ -722,7 +963,7 @@ ${newConversation}
|
||||
|
||||
// 首先尝试匹配带有数字或短横线的列表项
|
||||
const listItemRegex = /(?:^|\n)(?:\d+\.\s*|\-\s*)(.+?)(?=\n\d+\.\s*|\n\-\s*|\n\n|$)/gs
|
||||
let match
|
||||
let match: RegExpExecArray | null
|
||||
while ((match = listItemRegex.exec(result)) !== null) {
|
||||
if (match[1] && match[1].trim()) {
|
||||
extractedLines.push(match[1].trim())
|
||||
@ -832,13 +1073,24 @@ export const applyMemoriesToPrompt = (systemPrompt: string): string => {
|
||||
|
||||
const state = store.getState() // Use imported store
|
||||
// 确保 state.memory 存在,如果不存在则提供默认值
|
||||
const { isActive, memories, memoryLists, shortMemoryActive, shortMemories, priorityManagementEnabled } = state.memory || {
|
||||
const {
|
||||
isActive,
|
||||
memories,
|
||||
memoryLists,
|
||||
shortMemoryActive,
|
||||
shortMemories,
|
||||
priorityManagementEnabled,
|
||||
contextualRecommendationEnabled,
|
||||
currentRecommendations
|
||||
} = state.memory || {
|
||||
isActive: false,
|
||||
memories: [],
|
||||
memoryLists: [],
|
||||
shortMemoryActive: false,
|
||||
shortMemories: [],
|
||||
priorityManagementEnabled: false
|
||||
priorityManagementEnabled: false,
|
||||
contextualRecommendationEnabled: false,
|
||||
currentRecommendations: []
|
||||
}
|
||||
|
||||
// 获取当前话题ID
|
||||
@ -857,6 +1109,50 @@ export const applyMemoriesToPrompt = (systemPrompt: string): string => {
|
||||
let result = systemPrompt
|
||||
let hasContent = false
|
||||
|
||||
// 处理上下文感知记忆推荐
|
||||
if (contextualRecommendationEnabled && currentRecommendations && currentRecommendations.length > 0) {
|
||||
// 获取推荐记忆的详细信息
|
||||
const recommendedMemories: Array<{content: string, source: string, reason: string}> = []
|
||||
|
||||
// 处理每个推荐记忆
|
||||
for (const recommendation of currentRecommendations) {
|
||||
// 根据来源查找记忆
|
||||
let memory: any = null
|
||||
if (recommendation.source === 'long-term') {
|
||||
memory = memories.find(m => m.id === recommendation.memoryId)
|
||||
} else if (recommendation.source === 'short-term') {
|
||||
memory = shortMemories.find(m => m.id === recommendation.memoryId)
|
||||
}
|
||||
|
||||
if (memory) {
|
||||
recommendedMemories.push({
|
||||
content: memory.content,
|
||||
source: recommendation.source === 'long-term' ? '长期记忆' : '短期记忆',
|
||||
reason: recommendation.matchReason || '与当前对话相关'
|
||||
})
|
||||
|
||||
// 记录访问
|
||||
store.dispatch(accessMemory({
|
||||
id: memory.id,
|
||||
isShortMemory: recommendation.source === 'short-term'
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
if (recommendedMemories.length > 0) {
|
||||
// 构建推荐记忆提示词
|
||||
const recommendedMemoryPrompt = recommendedMemories
|
||||
.map((memory, index) => `${index + 1}. ${memory.content} (来源: ${memory.source}, 原因: ${memory.reason})`)
|
||||
.join('\n')
|
||||
|
||||
console.log('[Memory] Contextual memory recommendations:', recommendedMemoryPrompt)
|
||||
|
||||
// 添加推荐记忆到提示词
|
||||
result = `${result}\n\n当前对话的相关记忆(按相关性排序):\n${recommendedMemoryPrompt}`
|
||||
hasContent = true
|
||||
}
|
||||
}
|
||||
|
||||
// 处理短记忆
|
||||
if (shortMemoryActive && shortMemories && shortMemories.length > 0 && currentTopicId) {
|
||||
// 获取当前话题的短记忆
|
||||
|
||||
@ -76,6 +76,14 @@ export interface UserInterest {
|
||||
lastUpdated: string // 上次更新时间
|
||||
}
|
||||
|
||||
// 记忆推荐结果接口
|
||||
export interface MemoryRecommendation {
|
||||
memoryId: string
|
||||
relevanceScore: number
|
||||
source: 'long-term' | 'short-term'
|
||||
matchReason?: string
|
||||
}
|
||||
|
||||
export interface MemoryState {
|
||||
memoryLists: MemoryList[] // 记忆列表
|
||||
memories: Memory[] // 所有记忆项
|
||||
@ -110,6 +118,14 @@ export interface MemoryState {
|
||||
freshnessEnabled: boolean // 是否启用记忆鲜度评估
|
||||
decayRate: number // 记忆衰减速率(0-1)
|
||||
lastPriorityUpdate: number // 上次优先级更新时间
|
||||
|
||||
// 上下文感知记忆推荐相关
|
||||
contextualRecommendationEnabled: boolean // 是否启用上下文感知记忆推荐
|
||||
autoRecommendMemories: boolean // 是否自动推荐记忆
|
||||
recommendationThreshold: number // 推荐阈值(0-1)
|
||||
currentRecommendations: MemoryRecommendation[] // 当前的记忆推荐
|
||||
isRecommending: boolean // 是否正在推荐记忆
|
||||
lastRecommendTime: number | null // 上次推荐时间
|
||||
}
|
||||
|
||||
// 创建默认记忆列表
|
||||
@ -167,7 +183,15 @@ const initialState: MemoryState = {
|
||||
decayEnabled: true, // 默认启用记忆衰减功能
|
||||
freshnessEnabled: true, // 默认启用记忆鲜度评估
|
||||
decayRate: 0.05, // 默认衰减速率,每天减少5%
|
||||
lastPriorityUpdate: Date.now() // 初始化为当前时间
|
||||
lastPriorityUpdate: Date.now(), // 初始化为当前时间
|
||||
|
||||
// 上下文感知记忆推荐相关
|
||||
contextualRecommendationEnabled: true, // 默认启用上下文感知记忆推荐
|
||||
autoRecommendMemories: true, // 默认自动推荐记忆
|
||||
recommendationThreshold: 0.7, // 默认推荐阈值
|
||||
currentRecommendations: [], // 初始化空的推荐列表
|
||||
isRecommending: false, // 初始化为非推荐状态
|
||||
lastRecommendTime: null // 初始化为空
|
||||
}
|
||||
|
||||
const memorySlice = createSlice({
|
||||
@ -685,6 +709,37 @@ const memorySlice = createSlice({
|
||||
memory.lastAccessedAt = now
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// 设置上下文感知记忆推荐是否启用
|
||||
setContextualRecommendationEnabled: (state, action: PayloadAction<boolean>) => {
|
||||
state.contextualRecommendationEnabled = action.payload
|
||||
},
|
||||
|
||||
// 设置是否自动推荐记忆
|
||||
setAutoRecommendMemories: (state, action: PayloadAction<boolean>) => {
|
||||
state.autoRecommendMemories = action.payload
|
||||
},
|
||||
|
||||
// 设置推荐阈值
|
||||
setRecommendationThreshold: (state, action: PayloadAction<number>) => {
|
||||
state.recommendationThreshold = action.payload
|
||||
},
|
||||
|
||||
// 更新当前的记忆推荐
|
||||
updateCurrentRecommendations: (state, action: PayloadAction<MemoryRecommendation[]>) => {
|
||||
state.currentRecommendations = action.payload
|
||||
state.lastRecommendTime = Date.now()
|
||||
},
|
||||
|
||||
// 设置是否正在推荐记忆
|
||||
setRecommending: (state, action: PayloadAction<boolean>) => {
|
||||
state.isRecommending = action.payload
|
||||
},
|
||||
|
||||
// 清除当前的记忆推荐
|
||||
clearCurrentRecommendations: (state) => {
|
||||
state.currentRecommendations = []
|
||||
}
|
||||
},
|
||||
extraReducers: (builder) => {
|
||||
@ -695,6 +750,23 @@ const memorySlice = createSlice({
|
||||
state.memoryLists = action.payload.memoryLists || state.memoryLists
|
||||
state.memories = action.payload.memories || state.memories
|
||||
state.shortMemories = action.payload.shortMemories || state.shortMemories
|
||||
|
||||
// 更新模型选择
|
||||
if (action.payload.analyzeModel) {
|
||||
state.analyzeModel = action.payload.analyzeModel
|
||||
console.log('[Memory Reducer] Loaded analyze model:', action.payload.analyzeModel)
|
||||
}
|
||||
|
||||
if (action.payload.shortMemoryAnalyzeModel) {
|
||||
state.shortMemoryAnalyzeModel = action.payload.shortMemoryAnalyzeModel
|
||||
console.log('[Memory Reducer] Loaded short memory analyze model:', action.payload.shortMemoryAnalyzeModel)
|
||||
}
|
||||
|
||||
if (action.payload.vectorizeModel) {
|
||||
state.vectorizeModel = action.payload.vectorizeModel
|
||||
console.log('[Memory Reducer] Loaded vectorize model:', action.payload.vectorizeModel)
|
||||
}
|
||||
|
||||
log.info('Memory data loaded into state')
|
||||
}
|
||||
})
|
||||
@ -747,7 +819,15 @@ export const {
|
||||
setDecayRate,
|
||||
updateMemoryPriorities,
|
||||
updateMemoryFreshness,
|
||||
accessMemory
|
||||
accessMemory,
|
||||
|
||||
// 上下文感知记忆推荐相关的action
|
||||
setContextualRecommendationEnabled,
|
||||
setAutoRecommendMemories,
|
||||
setRecommendationThreshold,
|
||||
updateCurrentRecommendations,
|
||||
setRecommending,
|
||||
clearCurrentRecommendations
|
||||
} = memorySlice.actions
|
||||
|
||||
// 加载记忆数据的异步 thunk
|
||||
|
||||
Loading…
Reference in New Issue
Block a user