import { log } from "./table-system/logger.js"; import { getContext, extension_settings } from "/scripts/extensions.js"; import { eventSource, event_types } from "/script.js"; import { extensionName } from "../utils/settings.js"; function collectDataToBuffer(buffer, tableName, rowObj) { if (!buffer[tableName]) { buffer[tableName] = { headers: Object.keys(rowObj), rows: [] }; } else { const newKeys = Object.keys(rowObj); newKeys.forEach(k => { if (!buffer[tableName].headers.includes(k)) { buffer[tableName].headers.push(k); } }); } buffer[tableName].rows.push(rowObj); } function flushBufferToMarkdown(buffer) { let output = ""; const tableNames = Object.keys(buffer); if (tableNames.length === 0) return ""; for (const tableName of tableNames) { const { headers, rows } = buffer[tableName]; if (rows.length === 0) continue; const firstColKey = headers[0]; const firstColVal = rows[0] ? rows[0][firstColKey] : ''; const isIndexCol = (firstColKey && (firstColKey.includes('索引') || firstColKey.includes('Index'))) || (typeof firstColVal === 'string' && /^\s*M\d+/.test(firstColVal)); if (isIndexCol) { rows.sort((a, b) => { const valA = String(a[firstColKey] || ''); const valB = String(b[firstColKey] || ''); return valA.localeCompare(valB, undefined, { numeric: true }); }); } else { rows.reverse(); } output += `\n# ${tableName}档案\n`; output += `| ${headers.join(' | ')} |\n`; output += `|${headers.map(() => '---').join('|')}|\n`; for (const rowObj of rows) { const rowArr = headers.map(h => { const val = rowObj[h]; let safeVal = (val === undefined || val === null) ? '' : String(val); safeVal = safeVal.replace(/\|/g, '\\|').replace(/\n/g, ' '); return safeVal; }); output += `| ${rowArr.join(' | ')} |\n`; } output += `\n`; } return output; } function processText(text) { const blockRegex = /【(.*?)档案[::]\s*.*?】\s*((?:-\s*.*?[::].*?(?:\r?\n|$))+)/g; const itemRegex = /-\s*(.*?)[::]\s*(.*?)(?:\r?\n|$)/g; const buffer = {}; let found = false; const cleanText = text.replace(blockRegex, (match, tableName, content) => { found = true; const rowObj = {}; let itemMatch; itemRegex.lastIndex = 0; while ((itemMatch = itemRegex.exec(content)) !== null) { const key = itemMatch[1].trim(); const val = itemMatch[2].trim(); if (key) { rowObj[key] = val; } } if (Object.keys(rowObj).length > 0) { collectDataToBuffer(buffer, tableName, rowObj); } return ""; // 移除原始文本 }); return { cleanText, buffer, found }; } function handlePromptProcessing(data) { // 【V146.5】检查上下文优化开关 const settings = extension_settings[extensionName]; if (settings && settings.context_optimization_enabled === false) { // log('[ContextOptimizer] 上下文优化已禁用,跳过处理。', 'info'); return; } if (!data) return; if (typeof data.prompt === 'string') { const { cleanText, buffer, found } = processText(data.prompt); if (found) { const mergedTable = flushBufferToMarkdown(buffer); if (mergedTable) { data.prompt = cleanText + "\n" + mergedTable; log('[ContextOptimizer] 已优化上下文:合并了分散的世界书条目 (Text Mode)。', 'success'); } } } else if (Array.isArray(data.chat)) { console.log('[ContextOptimizer] 检测到 Chat Completion 格式...'); const newChat = []; let modifiedCount = 0; for (const msg of data.chat) { const newMsg = { ...msg }; if (typeof newMsg.content === 'string') { const { cleanText, buffer, found } = processText(newMsg.content); if (found) { const mergedTable = flushBufferToMarkdown(buffer); if (mergedTable) { newMsg.content = cleanText + "\n" + mergedTable; modifiedCount++; } } } newChat.push(newMsg); } if (modifiedCount > 0) { console.log(`[ContextOptimizer] 已原地优化 ${modifiedCount} 条消息中的表格数据。`); // 全量替换,确保生效 data.chat.splice(0, data.chat.length, ...newChat); log('[ContextOptimizer] 已优化上下文:合并了分散的世界书条目 (Chat Mode - In Place)。', 'success'); } } } /** * 注册监听器 */ export function registerContextOptimizerMacros() { console.log('[ContextOptimizer] 正在注册监听器...'); const context = getContext(); if (context) { console.log('[ContextOptimizer] Context APIs:', Object.keys(context)); } if (context && context.registerChatCompletionModifier) { context.registerChatCompletionModifier((chat) => { console.log('[ContextOptimizer] ChatCompletionModifier 触发'); const data = { chat: chat }; handlePromptProcessing(data); return data.chat; }); log('[ContextOptimizer] 已注册 Chat Completion Modifier。', 'success'); } else if (context && context.registerPromptModifier) { context.registerPromptModifier((prompt) => { console.log('[ContextOptimizer] PromptModifier 触发'); const data = { prompt: prompt }; handlePromptProcessing(data); return data.prompt; }); log('[ContextOptimizer] 已注册 Prompt Modifier (正则模式)。', 'success'); } else if (eventSource) { eventSource.on('chat_completion_prompt_ready', (...args) => { if (args[0] && typeof args[0] === 'object') { handlePromptProcessing(args[0]); } }); eventSource.on(event_types.GENERATION_STARTED, (...args) => { if (args.length > 1 && args[1] && typeof args[1].prompt === 'string') { handlePromptProcessing(args[1]); } else if (args[0] && typeof args[0].prompt === 'string') { handlePromptProcessing(args[0]); } }); log('[ContextOptimizer] 已绑定事件监听 (Text/Chat 双模式)。', 'info'); } else { console.error('[ContextOptimizer] 无法获取 eventSource。'); } } export function resetContextBuffer() { }