diff --git a/modules/ena-planner/ena-planner.html b/modules/ena-planner/ena-planner.html index ce397c0..e803a0b 100644 --- a/modules/ena-planner/ena-planner.html +++ b/modules/ena-planner/ena-planner.html @@ -256,6 +256,11 @@
聊天与历史
+
+ + +

仅支持英文标签(如 plot, note, memory)。留空表示不按标签过滤(仅去除 think)。无效标签会自动忽略。

+
x.trim()).filter(Boolean); } + function normalizeKeepTagsInput(text) { + const src = csvToArr(text); + const out = []; + src.forEach(item => { + const tag = String(item || '').replace(/^<+|>+$/g, '').toLowerCase(); + if (!/^[a-z][a-z0-9_-]*$/.test(tag)) return; + if (!out.includes(tag)) out.push(tag); + }); + return out; + } function escapeHtml(str) { return String(str || '').replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"'); @@ -669,6 +684,7 @@ $('ep_wb_pos4').value = String(toBool(cfg.excludeWorldbookPosition4, true)); $('ep_wb_exclude_names').value = arrToCsv(cfg.worldbookExcludeNames); $('ep_plot_n').value = String(toNum(cfg.plotCount, 2)); + $('ep_keep_tags').value = arrToCsv(cfg.responseKeepTags || ['plot', 'note']); $('ep_exclude_tags').value = arrToCsv(cfg.chatExcludeTags); $('ep_logs_persist').value = String(toBool(cfg.logsPersist, true)); @@ -708,6 +724,7 @@ p.excludeWorldbookPosition4 = toBool($('ep_wb_pos4').value, true); p.worldbookExcludeNames = csvToArr($('ep_wb_exclude_names').value); p.plotCount = Math.max(0, Math.floor(toNum($('ep_plot_n').value, 2))); + p.responseKeepTags = normalizeKeepTagsInput($('ep_keep_tags').value); p.chatExcludeTags = csvToArr($('ep_exclude_tags').value); p.logsPersist = toBool($('ep_logs_persist').value, true); @@ -761,6 +778,10 @@ const val = $('ep_model_select').value; if (val) { $('ep_model').value = val; scheduleSave(); } }); + $('ep_keep_tags').addEventListener('change', () => { + const normalized = normalizeKeepTagsInput($('ep_keep_tags').value); + $('ep_keep_tags').value = normalized.join(', '); + }); $('ep_add_prompt').addEventListener('click', () => { cfg.promptBlocks = cfg.promptBlocks || []; diff --git a/modules/ena-planner/ena-planner.js b/modules/ena-planner/ena-planner.js index 6d8562d..2b2886c 100644 --- a/modules/ena-planner/ena-planner.js +++ b/modules/ena-planner/ena-planner.js @@ -32,6 +32,8 @@ function getDefaultSettings() { // Plot extraction plotCount: 2, + // Planner response tags to keep, in source order (empty = keep full response) + responseKeepTags: ['plot', 'note'], // Planner prompts (designer) promptBlocks: structuredClone(DEFAULT_PROMPT_BLOCKS), @@ -100,6 +102,8 @@ function ensureSettings() { } } deepMerge(s, d); + if (!Array.isArray(s.responseKeepTags)) s.responseKeepTags = structuredClone(d.responseKeepTags); + else s.responseKeepTags = normalizeResponseKeepTags(s.responseKeepTags); // Migration: remove old keys that are no longer needed delete s.includeCharacterLorebooks; @@ -114,6 +118,20 @@ function ensureSettings() { return s; } +function normalizeResponseKeepTags(tags) { + const src = Array.isArray(tags) ? tags : []; + const cleaned = []; + for (const raw of src) { + const t = String(raw || '') + .trim() + .replace(/^<+|>+$/g, '') + .toLowerCase(); + if (!/^[a-z][a-z0-9_-]*$/.test(t)) continue; + if (!cleaned.includes(t)) cleaned.push(t); + } + return cleaned; +} + async function loadConfig() { const loaded = await EnaPlannerStorage.get('config', null); config = (loaded && typeof loaded === 'object') ? loaded : getDefaultSettings(); @@ -878,10 +896,13 @@ function stripThinkBlocks(text) { return out.trim(); } -function extractPlotAndNoteInOrder(text) { +function extractSelectedBlocksInOrder(text, tagNames) { + const names = normalizeResponseKeepTags(tagNames); + if (!Array.isArray(names) || names.length === 0) return ''; const src = String(text ?? ''); const blocks = []; - const re = /<(plot|note)\b[^>]*>[\s\S]*?<\/\1>/gi; + const escapedNames = names.map(n => n.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')); + const re = new RegExp(`<(${escapedNames.join('|')})\\b[^>]*>[\\s\\S]*?<\\/\\1>`, 'gi'); let m; while ((m = re.exec(src)) !== null) { blocks.push(m[0]); @@ -891,8 +912,9 @@ function extractPlotAndNoteInOrder(text) { function filterPlannerForInput(rawFull) { const noThink = stripThinkBlocks(rawFull); - const onlyPN = extractPlotAndNoteInOrder(noThink); - if (onlyPN) return onlyPN; + const tags = ensureSettings().responseKeepTags; + const selected = extractSelectedBlocksInOrder(noThink, tags); + if (selected) return selected; return noThink; }