chatgpt-plugin/models/memory/prompt.js
ikechan8370 8bfce5402f
试验性的记忆功能 (#812)
* feat: memory basic

* fix: chaite ver

* fix: update prompt

* fix: memory cursor and extract prompt

* fix: memory retrieval bug

* fix: memory retrieval bug

* fix: one more attempt by codex

* fix: messages prompt error

* fix: one more time by codex

* fix: metrics by codex

* fix: memory forward

* fix: memory show update time
2025-11-07 16:40:26 +08:00

128 lines
4.1 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import ChatGPTConfig from '../../config/config.js'
import { memoryService } from './service.js'
function renderTemplate (template, context = {}) {
if (!template) {
return ''
}
return template.replace(/\$\{(\w+)\}/g, (_, key) => {
const value = context[key]
return value === undefined || value === null ? '' : String(value)
})
}
function formatUserMemories (memories, config) {
if (!memories.length) {
return ''
}
const headerTemplate = config.promptHeader ?? '# 用户画像'
const itemTemplate = config.promptItemTemplate ?? '- ${value}'
const footerTemplate = config.promptFooter ?? ''
const segments = []
const header = renderTemplate(headerTemplate, { count: memories.length })
if (header) {
segments.push(header)
}
memories.forEach((item, index) => {
const timestamp = item.updated_at || item.created_at || ''
const timeSuffix = timestamp ? `(记录时间:${timestamp}` : ''
const context = {
index,
order: index + 1,
value: item.value || '',
importance: item.importance ?? '',
sourceMessageId: item.source_message_id || '',
sourceId: item.source_message_id || '',
groupId: item.group_id || '',
createdAt: item.created_at || '',
updatedAt: item.updated_at || '',
timestamp,
time: timestamp,
timeSuffix
}
const line = renderTemplate(itemTemplate, context)
if (line) {
segments.push(line)
}
})
const footer = renderTemplate(footerTemplate, { count: memories.length })
if (footer) {
segments.push(footer)
}
return segments.join('\n')
}
function formatGroupFacts (facts, config) {
if (!facts.length) {
return ''
}
const headerTemplate = config.promptHeader ?? '# 群聊长期记忆'
const itemTemplate = config.promptItemTemplate ?? '- ${fact}${topicSuffix}'
const footerTemplate = config.promptFooter ?? ''
const segments = []
const header = renderTemplate(headerTemplate, { count: facts.length })
if (header) {
segments.push(header)
}
facts.forEach((item, index) => {
const topicSuffix = item.topic ? `${item.topic}` : ''
const timestamp = item.updated_at || item.created_at || ''
const timeSuffix = timestamp ? `(记录时间:${timestamp}` : ''
const context = {
index,
order: index + 1,
fact: item.fact || '',
topic: item.topic || '',
topicSuffix,
importance: item.importance ?? '',
createdAt: item.created_at || '',
updatedAt: item.updated_at || '',
timestamp,
time: timestamp,
timeSuffix,
distance: item.distance ?? '',
bm25: item.bm25_score ?? '',
sourceMessages: item.source_messages || '',
sourceMessageIds: item.source_message_ids || ''
}
const line = renderTemplate(itemTemplate, context)
if (line) {
segments.push(line)
}
})
const footer = renderTemplate(footerTemplate, { count: facts.length })
if (footer) {
segments.push(footer)
}
return segments.join('\n')
}
export async function buildMemoryPrompt ({ userId, groupId, queryText }) {
const segments = []
const userConfig = ChatGPTConfig.memory?.user || {}
const groupConfig = ChatGPTConfig.memory?.group || {}
if (memoryService.isUserMemoryEnabled(userId)) {
const totalLimit = userConfig.maxItemsPerInjection || 5
const searchLimit = Math.min(userConfig.maxRelevantItemsPerQuery || totalLimit, totalLimit)
const userMemories = memoryService.queryUserMemories(userId, groupId, queryText, {
totalLimit,
searchLimit,
minImportance: userConfig.minImportanceForInjection ?? 0
})
const userSegment = formatUserMemories(userMemories, userConfig)
if (userSegment) {
segments.push(userSegment)
}
}
if (groupId && memoryService.isGroupMemoryEnabled(groupId)) {
const facts = await memoryService.queryGroupFacts(groupId, queryText, {
limit: groupConfig.maxFactsPerInjection || 5,
minImportance: groupConfig.minImportanceForInjection || 0
})
const groupSegment = formatGroupFacts(facts, groupConfig)
if (groupSegment) {
segments.push(groupSegment)
}
}
return segments.join('\n\n').trim()
}