mirror of
https://github.com/Wx-2025/ST-Amily2-Chat-Optimisation.git
synced 2026-06-06 20:55:51 +00:00
230 lines
6.4 KiB
JavaScript
230 lines
6.4 KiB
JavaScript
import { getContext, extension_settings } from "/scripts/extensions.js";
|
|
import { setExtensionPrompt, eventSource, event_types } from "/script.js";
|
|
import { callAI } from "./api.js";
|
|
import { callNgmsAI } from "./api/Ngms_api.js";
|
|
import { extensionName } from "../utils/settings.js";
|
|
import { getMemoryState, updateRow, insertRow, deleteRow, clearAllTables } from "./table-system/manager.js";
|
|
|
|
const FRACTAL_INJECTION_KEY = 'HANLINYUAN_FRACTAL_MEMORY';
|
|
const BUFFER_SIZE = 5;
|
|
const UPDATE_INTERVAL = 5;
|
|
|
|
|
|
|
|
export async function initializeFractalMemory() {
|
|
eventSource.on(event_types.MESSAGE_RECEIVED, handleMessageReceived);
|
|
console.log('[分形记忆] 系统已启动,正在构建多维记忆...');
|
|
}
|
|
|
|
let messageCounter = 0;
|
|
|
|
async function handleMessageReceived() {
|
|
messageCounter++;
|
|
if (messageCounter >= UPDATE_INTERVAL) {
|
|
messageCounter = 0;
|
|
await updateSceneLayer();
|
|
}
|
|
}
|
|
|
|
async function updateSceneLayer() {
|
|
const context = getContext();
|
|
const settings = extension_settings[extensionName];
|
|
|
|
if (!settings.fractalMemory) {
|
|
settings.fractalMemory = {
|
|
saga: "故事刚刚开始...",
|
|
arc: [],
|
|
scene: []
|
|
};
|
|
}
|
|
const memory = settings.fractalMemory;
|
|
|
|
console.log('[分形记忆] 正在提取近期事态...');
|
|
|
|
const recentChat = context.chat.slice(-UPDATE_INTERVAL).map(m => `${m.name}: ${m.mes}`).join('\n');
|
|
|
|
const prompt = `
|
|
请将以下对话总结为一句话的“场景事件”,描述发生了什么。
|
|
要求:简洁、客观、包含关键动作。
|
|
|
|
【对话内容】
|
|
${recentChat}
|
|
|
|
【输出】
|
|
(仅输出一句话总结)
|
|
`;
|
|
|
|
const newEvent = await _callLLM(prompt);
|
|
if (!newEvent) return;
|
|
|
|
console.log(`[分形记忆] 新增场景事件: ${newEvent}`);
|
|
memory.scene.push(newEvent);
|
|
|
|
if (memory.scene.length >= BUFFER_SIZE) {
|
|
await compressSceneToArc();
|
|
}
|
|
|
|
context.saveSettingsDebounced();
|
|
injectFractalMemory();
|
|
syncToTables();
|
|
}
|
|
|
|
async function compressSceneToArc() {
|
|
const context = getContext();
|
|
const settings = extension_settings[extensionName];
|
|
const memory = settings.fractalMemory;
|
|
|
|
console.log('[分形记忆] 场景层已满,正在压缩至篇章层...');
|
|
|
|
const sceneEvents = memory.scene.join('\n');
|
|
const prompt = `
|
|
请将以下 5 个连续的“场景事件”合并总结为一条“篇章节点”。
|
|
这条节点应该概括这一系列事件对剧情的推动作用。
|
|
|
|
【场景事件列表】
|
|
${sceneEvents}
|
|
|
|
【输出】
|
|
(仅输出一句话总结)
|
|
`;
|
|
|
|
const newArcEvent = await _callLLM(prompt);
|
|
if (!newArcEvent) return;
|
|
|
|
console.log(`[分形记忆] 新增篇章节点: ${newArcEvent}`);
|
|
|
|
memory.arc.push(newArcEvent);
|
|
memory.scene = [];
|
|
|
|
if (memory.arc.length >= BUFFER_SIZE) {
|
|
await compressArcToSaga();
|
|
}
|
|
}
|
|
|
|
async function compressArcToSaga() {
|
|
const context = getContext();
|
|
const settings = extension_settings[extensionName];
|
|
const memory = settings.fractalMemory;
|
|
|
|
console.log('[分形记忆] 篇章层已满,正在重写宏观史诗...');
|
|
|
|
const arcEvents = memory.arc.join('\n');
|
|
const oldSaga = memory.saga;
|
|
|
|
const prompt = `
|
|
请根据“旧的宏观史诗”和新发生的“篇章事件”,重写并更新整个故事的“宏观史诗”。
|
|
宏观史诗应该是一个高度概括的段落,描述故事的起因、经过和当前状态。
|
|
|
|
【旧史诗】
|
|
${oldSaga}
|
|
|
|
【新篇章事件】
|
|
${arcEvents}
|
|
|
|
【输出】
|
|
(输出一段更新后的宏观史诗,约 100-200 字)
|
|
`;
|
|
|
|
const newSaga = await _callLLM(prompt);
|
|
if (!newSaga) return;
|
|
|
|
console.log(`[分形记忆] 宏观史诗已更新。`);
|
|
|
|
memory.saga = newSaga;
|
|
memory.arc = [];
|
|
}
|
|
|
|
function syncToTables() {
|
|
const settings = extension_settings[extensionName];
|
|
if (!settings || !settings.fractalMemory) return;
|
|
const memory = settings.fractalMemory;
|
|
const tables = getMemoryState();
|
|
if (!tables) return;
|
|
|
|
const targetTableName = '【系统】分形记忆';
|
|
const tableIndex = tables.findIndex(t => t.name === targetTableName);
|
|
|
|
if (tableIndex !== -1) {
|
|
const table = tables[tableIndex];
|
|
const targetRows = [];
|
|
|
|
targetRows.push({
|
|
0: '宏观史诗',
|
|
1: memory.saga
|
|
});
|
|
|
|
memory.arc.forEach((event, i) => {
|
|
targetRows.push({
|
|
0: `篇章-${i+1}`,
|
|
1: event
|
|
});
|
|
});
|
|
|
|
memory.scene.forEach((event, i) => {
|
|
targetRows.push({
|
|
0: `场景-${i+1}`,
|
|
1: event
|
|
});
|
|
});
|
|
|
|
while (table.rows.length > targetRows.length) {
|
|
deleteRow(tableIndex, table.rows.length - 1);
|
|
}
|
|
|
|
targetRows.forEach((rowData, i) => {
|
|
if (i < table.rows.length) {
|
|
updateRow(tableIndex, i, rowData);
|
|
} else {
|
|
insertRow(tableIndex, rowData);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
export function injectFractalMemory() {
|
|
const settings = extension_settings[extensionName];
|
|
if (!settings || !settings.fractalMemory) return;
|
|
|
|
const memory = settings.fractalMemory;
|
|
|
|
let content = `【分形记忆系统】\n`;
|
|
|
|
content += `[宏观史诗]\n${memory.saga}\n\n`;
|
|
|
|
if (memory.arc.length > 0) {
|
|
content += `[当前篇章]\n${memory.arc.map(e => `- ${e}`).join('\n')}\n\n`;
|
|
}
|
|
|
|
if (memory.scene.length > 0) {
|
|
content += `[近期事态]\n${memory.scene.map(e => `- ${e}`).join('\n')}`;
|
|
}
|
|
|
|
setExtensionPrompt(
|
|
FRACTAL_INJECTION_KEY,
|
|
content,
|
|
0,
|
|
4,
|
|
false,
|
|
0
|
|
);
|
|
}
|
|
|
|
|
|
async function _callLLM(prompt) {
|
|
const settings = extension_settings[extensionName];
|
|
const messages = [{ role: 'user', content: prompt }];
|
|
|
|
try {
|
|
let responseText = '';
|
|
if (settings.ngmsEnabled) {
|
|
responseText = await callNgmsAI(messages);
|
|
} else {
|
|
responseText = await callAI(messages);
|
|
}
|
|
return responseText.trim();
|
|
} catch (error) {
|
|
console.error('[分形记忆] AI 调用失败:', error);
|
|
return null;
|
|
}
|
|
}
|