mirror of
https://github.com/SilenceLurker/ST-Amily2-Chat-Optimisation.git
synced 2026-06-06 08:55:50 +00:00
Merge branch 'Wx-2025:main' into main
This commit is contained in:
@@ -324,6 +324,10 @@ async function proceedWithCardUpdate($panel, messagesToUse) {
|
||||
|
||||
async function triggerAutomaticUpdate($panel) {
|
||||
logDebug(`检查是否需要更新。总消息数: ${state.allChatMessages.length}, 自动更新启用: ${state.autoUpdateEnabled}`);
|
||||
if (!isCwbEnabled()) {
|
||||
logDebug('更新检查已跳过 - CharacterWorldBook总开关已关闭。');
|
||||
return;
|
||||
}
|
||||
if (!state.autoUpdateEnabled || isUpdatingCard || !state.customApiConfig.url || !state.customApiConfig.model || state.allChatMessages.length === 0) {
|
||||
logDebug('更新检查已跳过(未启用、正在更新、未配置或无消息)。');
|
||||
return;
|
||||
@@ -544,6 +548,10 @@ async function processNextBatch($panel) {
|
||||
}
|
||||
|
||||
export async function startBatchUpdate($panel) {
|
||||
if (!isCwbEnabled()) {
|
||||
showToastr('warning', 'CharacterWorldBook总开关已关闭,无法执行批量更新。');
|
||||
return;
|
||||
}
|
||||
await loadAllChatMessages($panel);
|
||||
if (!state.customApiConfig.url || !state.customApiConfig.model) {
|
||||
showToastr('warning', '请先配置API信息。');
|
||||
@@ -581,6 +589,10 @@ export async function startBatchUpdate($panel) {
|
||||
}
|
||||
|
||||
export async function handleFloorRangeUpdate($panel) {
|
||||
if (!isCwbEnabled()) {
|
||||
showToastr('warning', 'CharacterWorldBook总开关已关闭,无法执行楼层范围更新。');
|
||||
return;
|
||||
}
|
||||
await loadAllChatMessages($panel);
|
||||
if (isUpdatingCard || isBatchUpdating) {
|
||||
showToastr('info', '已有更新任务在进行中。');
|
||||
@@ -639,6 +651,10 @@ export async function handleFloorRangeUpdate($panel) {
|
||||
}
|
||||
|
||||
export async function manualUpdateLogic($panel = null) {
|
||||
if (!isCwbEnabled()) {
|
||||
logDebug('手动更新已跳过 - CharacterWorldBook总开关已关闭。');
|
||||
return;
|
||||
}
|
||||
if (isUpdatingCard) {
|
||||
showToastr('info', '已有更新任务在进行中。');
|
||||
return;
|
||||
|
||||
@@ -78,6 +78,7 @@
|
||||
<button class="world-editor-btn world-editor-btn-warning" id="world-editor-disable-selected-btn">批量禁用</button>
|
||||
<button class="world-editor-btn world-editor-btn-primary" id="world-editor-set-blue-btn">批量蓝灯</button>
|
||||
<button class="world-editor-btn world-editor-btn-success" id="world-editor-set-green-btn">批量绿灯</button>
|
||||
<button class="world-editor-btn world-editor-btn-info" id="world-editor-copy-entries-btn">复制条目</button>
|
||||
<button class="world-editor-btn world-editor-btn-danger" id="world-editor-delete-selected-btn">批量删除</button>
|
||||
<button class="world-editor-btn world-editor-btn-primary" id="world-editor-set-disable-recursion-btn">不可递归</button>
|
||||
<button class="world-editor-btn world-editor-btn-primary" id="world-editor-set-prevent-recursion-btn">防止递归</button>
|
||||
|
||||
@@ -37,6 +37,14 @@
|
||||
cursor: pointer;
|
||||
font-size: 12px;
|
||||
transition: background-color 0.3s;
|
||||
color: white;
|
||||
font-weight: 500;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
#world-editor-container .world-editor-btn:disabled {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
#world-editor-container .world-editor-btn-primary {
|
||||
@@ -75,6 +83,15 @@
|
||||
background-color: #e68900;
|
||||
}
|
||||
|
||||
#world-editor-container .world-editor-btn-info {
|
||||
background-color: #17a2b8;
|
||||
color: white;
|
||||
}
|
||||
|
||||
#world-editor-container .world-editor-btn-info:hover {
|
||||
background-color: #138496;
|
||||
}
|
||||
|
||||
#world-editor-container .world-editor-content {
|
||||
flex: 1;
|
||||
padding: 20px;
|
||||
@@ -400,6 +417,12 @@
|
||||
.world-editor-btn.small-btn {
|
||||
padding: 4px 8px;
|
||||
font-size: 11px;
|
||||
color: white;
|
||||
background-color: #4a90e2;
|
||||
}
|
||||
|
||||
.world-editor-btn.small-btn:hover {
|
||||
background-color: #357abd;
|
||||
}
|
||||
|
||||
#world-editor-container .world-editor-selector h3 {
|
||||
@@ -414,6 +437,26 @@
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
#world-editor-container .world-editor-selector button {
|
||||
color: white;
|
||||
font-weight: 500;
|
||||
background-color: #4a90e2;
|
||||
}
|
||||
|
||||
#world-editor-container .world-editor-selector button:hover {
|
||||
background-color: #357abd;
|
||||
}
|
||||
|
||||
/* 确保返回列表按钮有颜色 */
|
||||
#world-editor-back-to-list-btn {
|
||||
color: white !important;
|
||||
background-color: #4a90e2 !important;
|
||||
}
|
||||
|
||||
#world-editor-back-to-list-btn:hover {
|
||||
background-color: #357abd !important;
|
||||
}
|
||||
|
||||
/* ====== 布局修正 v2:针对 fieldset ====== */
|
||||
|
||||
/* 1. 重置 fieldset 的默认样式,使其表现为标准的 flex 容器 */
|
||||
|
||||
@@ -51,7 +51,7 @@ class WorldEditor {
|
||||
'world-editor-select-all', 'world-editor-selected-count', 'world-editor-batch-actions',
|
||||
'world-editor-entries-container',
|
||||
'world-editor-enable-selected-btn', 'world-editor-disable-selected-btn',
|
||||
'world-editor-set-blue-btn', 'world-editor-set-green-btn', 'world-editor-delete-selected-btn',
|
||||
'world-editor-set-blue-btn', 'world-editor-set-green-btn', 'world-editor-copy-entries-btn', 'world-editor-delete-selected-btn',
|
||||
'world-editor-set-disable-recursion-btn', 'world-editor-set-prevent-recursion-btn'
|
||||
];
|
||||
this.elements = {};
|
||||
@@ -95,6 +95,7 @@ class WorldEditor {
|
||||
this.elements.worldEditorDisableSelectedBtn.addEventListener('click', () => this.batchUpdateEntries({ enabled: false }));
|
||||
this.elements.worldEditorSetBlueBtn.addEventListener('click', () => this.batchUpdateEntries({ type: 'constant' }));
|
||||
this.elements.worldEditorSetGreenBtn.addEventListener('click', () => this.batchUpdateEntries({ type: 'selective' }));
|
||||
this.elements.worldEditorCopyEntriesBtn.addEventListener('click', () => this.copySelectedEntries());
|
||||
this.elements.worldEditorDeleteSelectedBtn.addEventListener('click', () => this.batchDeleteEntries());
|
||||
this.elements.worldEditorSetDisableRecursionBtn.addEventListener('click', () => this.toggleBatchRecursion('exclude_recursion', '不可递归'));
|
||||
this.elements.worldEditorSetPreventRecursionBtn.addEventListener('click', () => this.toggleBatchRecursion('prevent_recursion', '防止递归'));
|
||||
@@ -298,13 +299,37 @@ class WorldEditor {
|
||||
this.setLoading(true);
|
||||
this.currentWorldBook = worldBookName;
|
||||
try {
|
||||
const rawEntries = await safeLorebookEntries(worldBookName);
|
||||
this.entries = (rawEntries || []).map(e => ({
|
||||
uid: e.uid, enabled: e.enabled, type: e.type || (e.constant ? 'constant' : 'selective'),
|
||||
keys: e.keys || [], content: e.content || '', position: e.position || 'before_character_definition',
|
||||
depth: (String(e.position)?.startsWith('at_depth')) ? e.depth : null, order: e.order || 100, comment: e.comment || '',
|
||||
exclude_recursion: e.exclude_recursion, prevent_recursion: e.prevent_recursion
|
||||
const bookData = await loadWorldInfo(worldBookName);
|
||||
if (!bookData || !bookData.entries) {
|
||||
this.entries = [];
|
||||
this.filteredEntries = [];
|
||||
this.renderEntries();
|
||||
this.updateEntryCount();
|
||||
return;
|
||||
}
|
||||
|
||||
const positionMap = {
|
||||
0: 'before_character_definition',
|
||||
1: 'after_character_definition',
|
||||
2: 'before_author_note',
|
||||
3: 'after_author_note',
|
||||
4: 'at_depth'
|
||||
};
|
||||
|
||||
this.entries = Object.entries(bookData.entries).map(([uid, e]) => ({
|
||||
uid: parseInt(uid),
|
||||
enabled: !e.disable,
|
||||
type: e.constant ? 'constant' : 'selective',
|
||||
keys: e.key || [],
|
||||
content: e.content || '',
|
||||
position: positionMap[e.position] || 'at_depth',
|
||||
depth: e.depth != null ? e.depth : 4,
|
||||
order: e.order != null ? e.order : 100,
|
||||
comment: e.comment || '',
|
||||
exclude_recursion: e.excludeRecursion || false,
|
||||
prevent_recursion: e.preventRecursion || false
|
||||
}));
|
||||
|
||||
this.filteredEntries = [...this.entries];
|
||||
this.renderEntries();
|
||||
this.updateEntryCount();
|
||||
@@ -488,6 +513,114 @@ class WorldEditor {
|
||||
this.batchUpdateEntries({ [field]: shouldEnable }, confirmation);
|
||||
}
|
||||
|
||||
async copySelectedEntries() {
|
||||
if (this.selectedEntries.size === 0) {
|
||||
this.showError('请先选择要复制的条目');
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取所有世界书列表(包括当前世界书,允许在同一世界书内复制)
|
||||
const availableBooks = this.allWorldBooks.map(book => book.name);
|
||||
|
||||
if (availableBooks.length === 0) {
|
||||
this.showError('没有可用的世界书');
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('[世界书编辑器] 准备复制条目,已选择:', this.selectedEntries.size, '个条目');
|
||||
console.log('[世界书编辑器] 选中的UID:', Array.from(this.selectedEntries));
|
||||
|
||||
// 创建选择对话框
|
||||
const selectHtml = `
|
||||
<style>
|
||||
.copy-dialog { padding: 20px; }
|
||||
.copy-dialog label { display: block; margin-bottom: 10px; color: #ccc; font-weight: bold; }
|
||||
.copy-dialog select { width: 100%; padding: 10px; background-color: #404040; color: white; border: 1px solid #555; border-radius: 4px; font-size: 14px; }
|
||||
.copy-dialog .info { margin-top: 15px; padding: 10px; background-color: #2a2a2a; border-left: 3px solid #4a9eff; color: #ccc; }
|
||||
</style>
|
||||
<div class="copy-dialog">
|
||||
<label for="target-worldbook">选择目标世界书:</label>
|
||||
<select id="target-worldbook" class="form-control">
|
||||
${availableBooks.map(name => `<option value="${name}" ${name === this.currentWorldBook ? 'selected' : ''}>${name}${name === this.currentWorldBook ? ' (当前)' : ''}</option>`).join('')}
|
||||
</select>
|
||||
<div class="info">
|
||||
将复制 ${this.selectedEntries.size} 个条目到目标世界书
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
showHtmlModal('复制条目', selectHtml, {
|
||||
onOk: async (dialog) => {
|
||||
const targetBook = dialog.find('#target-worldbook').val();
|
||||
|
||||
if (!targetBook) {
|
||||
this.showError('请选择目标世界书');
|
||||
return false;
|
||||
}
|
||||
|
||||
await this.performCopy(targetBook);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async performCopy(targetBookName) {
|
||||
this.setLoading(true);
|
||||
try {
|
||||
// 获取要复制的条目
|
||||
const entriesToCopy = this.entries.filter(e => this.selectedEntries.has(e.uid));
|
||||
|
||||
console.log('[世界书编辑器] 过滤后的条目数量:', entriesToCopy.length);
|
||||
console.log('[世界书编辑器] 条目详情:', entriesToCopy);
|
||||
|
||||
if (entriesToCopy.length === 0) {
|
||||
this.showError('没有选中的条目');
|
||||
return;
|
||||
}
|
||||
|
||||
// 加载目标世界书
|
||||
const targetBookData = await loadWorldInfo(targetBookName);
|
||||
if (!targetBookData) {
|
||||
this.showError(`目标世界书 "${targetBookName}" 不存在`);
|
||||
return;
|
||||
}
|
||||
|
||||
// 准备要创建的条目数据
|
||||
const newEntries = entriesToCopy.map(entry => ({
|
||||
enabled: entry.enabled,
|
||||
type: entry.type,
|
||||
keys: Array.isArray(entry.keys) ? entry.keys : [],
|
||||
content: entry.content || '',
|
||||
position: entry.position,
|
||||
depth: entry.depth != null ? entry.depth : 4,
|
||||
order: entry.order != null ? entry.order : 100,
|
||||
comment: entry.comment || '',
|
||||
exclude_recursion: entry.exclude_recursion || false,
|
||||
prevent_recursion: entry.prevent_recursion || false
|
||||
}));
|
||||
|
||||
console.log('[世界书编辑器] 准备创建的条目:', newEntries);
|
||||
|
||||
// 在目标世界书中创建条目
|
||||
await amilyHelper.createLorebookEntries(targetBookName, newEntries);
|
||||
|
||||
if (window.toastr) {
|
||||
window.toastr.success(`成功复制 ${entriesToCopy.length} 个条目到 "${targetBookName}"`);
|
||||
}
|
||||
|
||||
// 如果复制到当前世界书,刷新视图
|
||||
if (targetBookName === this.currentWorldBook) {
|
||||
await this.loadWorldBookEntries(this.currentWorldBook);
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('[世界书编辑器] 复制失败:', error);
|
||||
this.showError(`复制失败: ${error.message}`);
|
||||
} finally {
|
||||
this.setLoading(false);
|
||||
}
|
||||
}
|
||||
|
||||
async batchDeleteEntries() {
|
||||
if (this.selectedEntries.size === 0 || !confirm(`删除 ${this.selectedEntries.size} 个条目?`)) return;
|
||||
try {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"message": "插件群:1060183271,更新了多个版本了,现在是v1.5.7,术语表上线。个人原因,降低更新频率以及无暇看帖子,有问题最好加群。"
|
||||
"message": "插件群:1060183271,有问题最好加群。"
|
||||
}
|
||||
|
||||
|
||||
@@ -43,5 +43,6 @@
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -15,13 +15,21 @@
|
||||
|
||||
<div class="control-pair-container">
|
||||
<div class="amily2_settings_block">
|
||||
<label for="amily2_auto_hide_enabled">启用自动隐藏</label>
|
||||
<label for="amily2_auto_hide_enabled">按阈值自动隐藏</label>
|
||||
<label class="toggle-switch">
|
||||
<input id="amily2_auto_hide_enabled" type="checkbox" />
|
||||
<span class="slider"></span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="amily2_settings_block">
|
||||
<label for="amily2_auto_hide_summarized_enabled">隐藏已总结楼层</label>
|
||||
<label class="toggle-switch">
|
||||
<input id="amily2_auto_hide_summarized_enabled" type="checkbox" />
|
||||
<span class="slider"></span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="amily2_settings_block">
|
||||
<button id="amily2_unhide_all_button" class="menu_button secondary small_button interactable" title="一键取消所有已隐藏的楼层">
|
||||
|
||||
@@ -1 +1,129 @@
|
||||
(function(_0x4ee988,_0x4037de){const _0x37bb46=_0x58cf,_0x4f5812=_0x4ee988();while(!![]){try{const _0x1c6d7c=-parseInt(_0x37bb46(0x1c9))/0x1*(parseInt(_0x37bb46(0x1df))/0x2)+parseInt(_0x37bb46(0x1da))/0x3*(-parseInt(_0x37bb46(0x1d0))/0x4)+-parseInt(_0x37bb46(0x1d2))/0x5+-parseInt(_0x37bb46(0x1ea))/0x6+parseInt(_0x37bb46(0x1dd))/0x7*(-parseInt(_0x37bb46(0x1d6))/0x8)+-parseInt(_0x37bb46(0x1d1))/0x9+parseInt(_0x37bb46(0x1d7))/0xa;if(_0x1c6d7c===_0x4037de)break;else _0x4f5812['push'](_0x4f5812['shift']());}catch(_0xa818b5){_0x4f5812['push'](_0x4f5812['shift']());}}}(_0x5992,0xc4f22));function _0x58cf(_0x18e475,_0x4450b0){const _0x599238=_0x5992();return _0x58cf=function(_0x58cf6f,_0x5e2dd5){_0x58cf6f=_0x58cf6f-0x1c0;let _0x33b306=_0x599238[_0x58cf6f];return _0x33b306;},_0x58cf(_0x18e475,_0x4450b0);}import{getContext,extension_settings}from'/scripts/extensions.js';import{SlashCommandParser}from'/scripts/slash-commands/SlashCommandParser.js';import{extensionName}from'../utils/settings.js';async function executeSlashCommand(_0x28ecae){const _0x4e2c65=_0x58cf;if(!_0x28ecae)return;try{console['log']('[Amily-敕令执行官]\x20准备执行圣谕:\x20'+_0x28ecae);const _0x54b194=new SlashCommandParser(),_0x2ebd11=_0x54b194[_0x4e2c65(0x1e8)](_0x28ecae,![]);if(_0x2ebd11&&typeof _0x2ebd11[_0x4e2c65(0x1c7)]===_0x4e2c65(0x1e4))await _0x2ebd11[_0x4e2c65(0x1c7)](),console[_0x4e2c65(0x1d3)]('[Amily-敕令执行官]\x20圣谕:\x20\x22'+_0x28ecae+_0x4e2c65(0x1cd)),toastr[_0x4e2c65(0x1e5)](_0x4e2c65(0x1c1)+_0x28ecae+'\x22\x20已成功颁布','敕令司回报');else{const _0x4902df=_0x4e2c65(0x1db)+_0x28ecae;console[_0x4e2c65(0x1e6)](_0x4e2c65(0x1d8)+_0x4902df),toastr[_0x4e2c65(0x1e6)](_0x4902df,_0x4e2c65(0x1e2));}}catch(_0x3fb9f0){console[_0x4e2c65(0x1e6)](_0x4e2c65(0x1cb)+_0x28ecae+_0x4e2c65(0x1c5),_0x3fb9f0),toastr[_0x4e2c65(0x1e6)](_0x4e2c65(0x1e0)+_0x3fb9f0[_0x4e2c65(0x1c6)],_0x4e2c65(0x1e2));}}export async function executeAutoHide(){const _0x5f18de=_0x58cf;try{const _0x5185f0=extension_settings[extensionName];if(!_0x5185f0[_0x5f18de(0x1c8)])return;const _0x1bd89b=_0x5185f0['autoHideThreshold']||0x1e,_0x4cdc8a=getContext(),_0x22e5ff=_0x4cdc8a['chat']['length'],_0x430d62=_0x22e5ff-_0x1bd89b-0x1;if(_0x430d62<0x0){;return;}const _0x4768bf=_0x5f18de(0x1c3)+_0x430d62;console[_0x5f18de(0x1d3)](_0x5f18de(0x1ca)+_0x4768bf);const _0x1b6e36=new SlashCommandParser(),_0x31a7eb=_0x1b6e36[_0x5f18de(0x1e8)](_0x4768bf,![]);_0x31a7eb&&typeof _0x31a7eb[_0x5f18de(0x1c7)]===_0x5f18de(0x1e4)?(await _0x31a7eb[_0x5f18de(0x1c7)](),console[_0x5f18de(0x1d3)]('[Amily-史册管理员]\x20圣谕颁布成功。')):console[_0x5f18de(0x1e6)](_0x5f18de(0x1e3));}catch(_0x170bc5){console[_0x5f18de(0x1e6)](_0x5f18de(0x1e7),_0x170bc5);}}export async function executeManualCommand(_0xaf2ae3,_0x15bb0a={}){const _0x567b75=_0x58cf,{from:_0x1666d9,to:_0x3462b1}=_0x15bb0a;let _0x5cc3b1='';switch(_0xaf2ae3){case _0x567b75(0x1de):{const _0x6bd434=getContext()[_0x567b75(0x1e1)][_0x567b75(0x1c4)];if(_0x6bd434>0x0){const _0x4dbd57=_0x6bd434-0x1;_0x5cc3b1=_0x567b75(0x1cf)+_0x4dbd57;}else{toastr[_0x567b75(0x1c0)](_0x567b75(0x1ce),'敕令司回报');return;}break;}case _0x567b75(0x1c2):case _0x567b75(0x1d5):{const _0x582643=_0xaf2ae3===_0x567b75(0x1c2)?'/hide':_0x567b75(0x1cc);if(_0x1666d9===''&&_0x3462b1!=='')_0x5cc3b1=_0x582643+'\x20'+_0x3462b1;else{if(_0x1666d9!==''&&_0x3462b1!==''){if(parseInt(_0x1666d9)>parseInt(_0x3462b1)){toastr[_0x567b75(0x1e9)](_0x567b75(0x1d9),_0x567b75(0x1dc));return;}_0x5cc3b1=_0x582643+'\x20'+_0x1666d9+'-'+_0x3462b1;}else{toastr[_0x567b75(0x1e9)]('请输入有效的楼层范围',_0x567b75(0x1dc));return;}}break;}default:console[_0x567b75(0x1e6)](_0x567b75(0x1d4)+_0xaf2ae3);return;}await executeSlashCommand(_0x5cc3b1);}function _0x5992(){const _0x133664=['success','error','[Amily-史册管理员]\x20执行自动隐藏律法时发生意外错误:','parse','warning','8803272zKOyks','info','圣谕\x20\x22','manual_hide','/hide\x200-','length','\x22\x20时发生意外:','message','execute','autoHideEnabled','17XaePWh','[Amily-史册管理员]\x20颁布圣谕:\x20','[Amily-敕令执行官]\x20执行圣谕\x20\x22','/unhide','\x22\x20已成功颁布。','史册为空,无需解除隐藏。','/unhide\x200-','3241588UWNBsl','2333502whztNt','6368380RiIATK','log','[Amily-手动敕令司]\x20未知的命令类型:\x20','manual_unhide','12590440mhbLFH','65756490EvHMoU','[Amily-敕令执行官]\x20','起始层不能大于结束层','3MrmhsI','铸造出的圣谕法印无法执行!指令:\x20','敕令司提示','7TQjRrw','unhide_all','45246UriBuS','执行圣谕时发生意外:\x20','chat','敕令司紧急报告','[Amily-史册管理员]\x20致命错误:铸造出的圣谕法印无法执行!','function'];_0x5992=function(){return _0x133664;};return _0x5992();}
|
||||
import { getContext, extension_settings } from "/scripts/extensions.js";
|
||||
import { SlashCommandParser } from "/scripts/slash-commands/SlashCommandParser.js";
|
||||
import { extensionName } from "../utils/settings.js";
|
||||
import { readGoldenLedgerProgress } from "./historiographer.js";
|
||||
import { characters } from "/script.js";
|
||||
import { getChatIdentifier } from "./lore.js";
|
||||
|
||||
|
||||
async function executeSlashCommand(commandString) {
|
||||
if (!commandString) return;
|
||||
try {
|
||||
console.log(`[Amily-敕令执行官] 准备执行圣谕: ${commandString}`);
|
||||
const parser = new SlashCommandParser();
|
||||
const closure = parser.parse(commandString, false);
|
||||
|
||||
if (closure && typeof closure.execute === 'function') {
|
||||
await closure.execute();
|
||||
console.log(`[Amily-敕令执行官] 圣谕: "${commandString}" 已成功颁布。`);
|
||||
toastr.success(`圣谕 "${commandString}" 已成功颁布`, "敕令司回报");
|
||||
} else {
|
||||
const errorMsg = `铸造出的圣谕法印无法执行!指令: ${commandString}`;
|
||||
console.error(`[Amily-敕令执行官] ${errorMsg}`);
|
||||
toastr.error(errorMsg, "敕令司紧急报告");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`[Amily-敕令执行官] 执行圣谕 "${commandString}" 时发生意外:`, error);
|
||||
toastr.error(`执行圣谕时发生意外: ${error.message}`, "敕令司紧急报告");
|
||||
}
|
||||
}
|
||||
|
||||
export async function executeAutoHide() {
|
||||
try {
|
||||
const settings = extension_settings[extensionName];
|
||||
const context = getContext();
|
||||
const chatLength = context.chat.length;
|
||||
let hideUntilIndex = -1;
|
||||
|
||||
if (settings.autoHideSummarizedEnabled) {
|
||||
let targetLorebookName;
|
||||
switch (settings.lorebookTarget) {
|
||||
case "character_main":
|
||||
targetLorebookName = characters[context.characterId]?.data?.extensions?.world;
|
||||
break;
|
||||
case "dedicated":
|
||||
const chatIdentifier = await getChatIdentifier();
|
||||
targetLorebookName = `Amily2-Lore-${chatIdentifier}`;
|
||||
break;
|
||||
}
|
||||
|
||||
if (targetLorebookName) {
|
||||
const summarizedCount = await readGoldenLedgerProgress(targetLorebookName);
|
||||
if (summarizedCount > 0) {
|
||||
hideUntilIndex = summarizedCount - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (settings.autoHideEnabled) {
|
||||
const threshold = settings.autoHideThreshold || 30;
|
||||
const thresholdHideIndex = chatLength - threshold - 1;
|
||||
if (thresholdHideIndex > hideUntilIndex) {
|
||||
hideUntilIndex = thresholdHideIndex;
|
||||
}
|
||||
}
|
||||
|
||||
if (hideUntilIndex < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const commandString = `/hide 0-${hideUntilIndex}`;
|
||||
console.log(`[Amily-史册管理员] 颁布圣谕: ${commandString}`);
|
||||
const parser = new SlashCommandParser();
|
||||
const closure = parser.parse(commandString, false);
|
||||
|
||||
if (closure && typeof closure.execute === 'function') {
|
||||
await closure.execute();
|
||||
console.log(`[Amily-史册管理员] 圣谕颁布成功。`);
|
||||
} else {
|
||||
console.error('[Amily-史册管理员] 致命错误:铸造出的圣谕法印无法执行!');
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('[Amily-史册管理员] 执行自动隐藏律法时发生意外错误:', error);
|
||||
}
|
||||
}
|
||||
|
||||
export async function executeManualCommand(commandType, params = {}) {
|
||||
const { from, to } = params;
|
||||
|
||||
let commandString = '';
|
||||
|
||||
switch (commandType) {
|
||||
case 'unhide_all': {
|
||||
const chatLength = getContext().chat.length;
|
||||
if (chatLength > 0) {
|
||||
const lastIndex = chatLength - 1;
|
||||
commandString = `/unhide 0-${lastIndex}`;
|
||||
} else {
|
||||
toastr.info("史册为空,无需解除隐藏。", "敕令司回报");
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 'manual_hide':
|
||||
case 'manual_unhide': {
|
||||
const command = commandType === 'manual_hide' ? '/hide' : '/unhide';
|
||||
if (from === '' && to !== '') {
|
||||
commandString = `${command} ${to}`;
|
||||
} else if (from !== '' && to !== '') {
|
||||
if (parseInt(from) > parseInt(to)) {
|
||||
toastr.warning("起始层不能大于结束层", "敕令司提示");
|
||||
return;
|
||||
}
|
||||
commandString = `${command} ${from}-${to}`;
|
||||
} else {
|
||||
toastr.warning("请输入有效的楼层范围", "敕令司提示");
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
console.error(`[Amily-手动敕令司] 未知的命令类型: ${commandType}`);
|
||||
return;
|
||||
}
|
||||
|
||||
await executeSlashCommand(commandString);
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ import { showSummaryModal, showHtmlModal } from "../ui/page-window.js";
|
||||
import { getPresetPrompts, getMixedOrder } from '../PresetSettings/index.js';
|
||||
import { callAI, generateRandomSeed } from "./api.js";
|
||||
import { callNgmsAI } from "./api/Ngms_api.js";
|
||||
import { executeAutoHide } from "./autoHideManager.js";
|
||||
|
||||
let isExpeditionRunning = false;
|
||||
let manualStopRequested = false;
|
||||
@@ -24,7 +25,7 @@ const RUNNING_LOG_COMMENT = "【敕史局】对话流水总帐";
|
||||
const PROGRESS_SEAL_REGEX =
|
||||
/本条勿动【前(\d+)楼总结已完成】否则后续总结无法进行。$/;
|
||||
|
||||
async function readGoldenLedgerProgress(targetLorebookName) {
|
||||
export async function readGoldenLedgerProgress(targetLorebookName) {
|
||||
if (!targetLorebookName) return 0;
|
||||
try {
|
||||
const bookData = await loadWorldInfo(targetLorebookName);
|
||||
@@ -127,10 +128,9 @@ export async function executeManualSummary(startFloor, endFloor, isAuto = false)
|
||||
onRegenerate: async (summaryDialog) => {
|
||||
summaryDialog.find('textarea').prop('disabled', true).val('正在重新生成,请稍候...');
|
||||
const newSummary = await getSummary(textToSummarize, toastTitle);
|
||||
if (newSummary) {
|
||||
summaryDialog.find('textarea').prop('disabled', false).val(newSummary);
|
||||
} else {
|
||||
summaryDialog.find('textarea').prop('disabled', false).val(summary);
|
||||
summaryDialog.find('textarea').prop('disabled', false).val(newSummary || summary);
|
||||
summaryDialog[0].showModal(); // 重新显示弹窗
|
||||
if (!newSummary) {
|
||||
toastr.error("重新生成失败,已恢复原始内容。", "模型召唤失败");
|
||||
}
|
||||
},
|
||||
@@ -242,10 +242,9 @@ export async function executeManualSummary(startFloor, endFloor, isAuto = false)
|
||||
onRegenerate: async (summaryDialog) => {
|
||||
summaryDialog.find('textarea').prop('disabled', true).val('正在重新生成,请稍候...');
|
||||
const newSummary = await getSummary(textToSummarize, toastTitle);
|
||||
if (newSummary) {
|
||||
summaryDialog.find('textarea').prop('disabled', false).val(newSummary);
|
||||
} else {
|
||||
summaryDialog.find('textarea').prop('disabled', false).val(summary);
|
||||
summaryDialog.find('textarea').prop('disabled', false).val(newSummary || summary);
|
||||
summaryDialog[0].showModal(); // 重新显示弹窗
|
||||
if (!newSummary) {
|
||||
toastr.error("重新生成失败,已恢复原始内容。", "模型召唤失败");
|
||||
}
|
||||
},
|
||||
@@ -454,6 +453,7 @@ async function writeSummary(summary, startFloor, endFloor, toastTitle) {
|
||||
|
||||
if (success) {
|
||||
toastr.success(`编年史已成功更新!`, `${toastTitle} - 国史馆`);
|
||||
executeAutoHide(); // 总结成功后立即触发自动隐藏
|
||||
return true;
|
||||
} else {
|
||||
// 错误已在 compatibleWriteToLorebook 内部处理和记录
|
||||
@@ -618,10 +618,9 @@ export async function executeRefinement(worldbook, loreKey) {
|
||||
onRegenerate: async (dialog) => {
|
||||
dialog.find('textarea').prop('disabled', true).val('正在重新生成,请稍候...');
|
||||
const newContent = await getRefinedContent();
|
||||
if (newContent) {
|
||||
dialog.find('textarea').prop('disabled', false).val(newContent);
|
||||
} else {
|
||||
dialog.find('textarea').prop('disabled', false).val(currentRefinedContent);
|
||||
dialog.find('textarea').prop('disabled', false).val(newContent || currentRefinedContent);
|
||||
dialog[0].showModal(); // 重新显示弹窗
|
||||
if (!newContent) {
|
||||
toastr.error("重新生成失败,已恢复原始内容。", "模型召唤失败");
|
||||
}
|
||||
},
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -33,8 +33,9 @@ const DEFAULT_AI_FLOW_TEMPLATE = `# dataTable 说明
|
||||
【说明】:
|
||||
· [表格用途和规则的说明]
|
||||
<[tableName]内容>
|
||||
rowIndex,[colIndex]:[colName],[colIndex]:[colName],...
|
||||
[rowIndex],[单元格数据],[单元格数据],...
|
||||
| rowIndex | [colIndex]:[colName] | [colIndex]:[colName] | ... |
|
||||
|---|---|---|---|
|
||||
| [rowIndex] | [单元格数据] | [单元格数据] | ... |
|
||||
...
|
||||
</[tableName]内容>
|
||||
【增加】: · [插入新行的触发条件]
|
||||
@@ -46,9 +47,9 @@ rowIndex,[colIndex]:[colName],[colIndex]:[colName],...
|
||||
### 格式解析:
|
||||
- \`* [tableIndex]:[tableName]\`: 表格的标题行,包含表格的索引(\`tableIndex\`)和名称(\`tableName\`)。
|
||||
- \`【说明】\`: 提供了表格的详细用途和填写规则。
|
||||
- \`<[tableName]内容>\`: 包含了表格的实际数据。
|
||||
- 第一行是表头,定义了每一列的索引 (\`colIndex\`) 和名称 (\`colName\`)。
|
||||
- 后续每一行都是一条数据记录,以行索引 (\`rowIndex\`) 开头,后面跟着对应列的单元格数据。
|
||||
- \`<[tableName]内容>\`: 包含了使用 Markdown 格式的实际数据表格。
|
||||
- 表头行定义了每一列的索引 (\`colIndex\`) 和名称 (\`colName\`)。第一列始终是 \`rowIndex\`。
|
||||
- 后续每一行都是一条数据记录,第一列是该行的索引 (\`rowIndex\`),后面跟着对应列的单元格数据。
|
||||
- \`【增加】\`, \`【删除】\`, \`【修改】\`: 分别描述了你应该在何种剧情下对表格进行增、删、改操作。
|
||||
|
||||
### 示例:
|
||||
@@ -57,8 +58,9 @@ rowIndex,[colIndex]:[colName],[colIndex]:[colName],...
|
||||
【说明】:
|
||||
(内容省略...)
|
||||
<时空栏内容>
|
||||
rowIndex,0:日期,1:时段,2:时间,3:地点,4:此地角色
|
||||
0,2025-09-04,下午,18:40,办公室,艾克/克莱因
|
||||
| rowIndex | 0:日期 | 1:时段 | 2:时间 | 3:地点 | 4:此地角色 |
|
||||
|---|---|---|---|---|---|
|
||||
| 0 | 2025-09-04 | 下午 | 18:40 | 办公室 | 艾克/克莱因 |
|
||||
</时空栏内容>
|
||||
【增加】: · 此表不存在任何一行时
|
||||
【删除】: · 此表大于一行时应删除多余行
|
||||
|
||||
@@ -416,6 +416,9 @@ class AmilyHelper {
|
||||
existingEntry.position = positionMap[entryUpdate.position] ?? 4;
|
||||
}
|
||||
if (entryUpdate.depth !== undefined) existingEntry.depth = entryUpdate.depth;
|
||||
if (entryUpdate.order !== undefined) existingEntry.order = entryUpdate.order;
|
||||
if (entryUpdate.exclude_recursion !== undefined) existingEntry.excludeRecursion = entryUpdate.exclude_recursion;
|
||||
if (entryUpdate.prevent_recursion !== undefined) existingEntry.preventRecursion = entryUpdate.prevent_recursion;
|
||||
}
|
||||
}
|
||||
await saveWorldInfo(bookName, bookData, true);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "Amily2号聊天优化助手",
|
||||
"display_name": "Amily2号助手",
|
||||
"version": "1.6.2",
|
||||
"version": "1.6.3",
|
||||
"author": "Wx-2025",
|
||||
"description": "一个拥有独立UI的智能引擎,正文优化、自动总结、记忆表格、rag向量、隐藏楼层、剧情推进六大功能整合。",
|
||||
"minSillyTavernVersion": "1.10.0",
|
||||
@@ -33,5 +33,6 @@
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -150,6 +150,7 @@ export function showSummaryModal(summaryText, callbacks) {
|
||||
const regenerateButton = $('<button class="menu_button secondary interactable" style="margin-right: auto;">重新生成</button>');
|
||||
regenerateButton.on('click', () => {
|
||||
if (onRegenerate) {
|
||||
dialogElement[0].close();
|
||||
onRegenerate(dialogElement);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -132,6 +132,7 @@ export function updateUI() {
|
||||
|
||||
$(`input[name="amily2_icon_location"][value="${settings.iconLocation}"]`).prop("checked", true);
|
||||
$("#amily2_auto_hide_enabled").prop("checked", settings.autoHideEnabled);
|
||||
$("#amily2_auto_hide_summarized_enabled").prop("checked", settings.autoHideSummarizedEnabled);
|
||||
$("#amily2_auto_hide_threshold").val(settings.autoHideThreshold);
|
||||
$("#amily2_auto_hide_threshold_value").text(settings.autoHideThreshold);
|
||||
$('#amily2_lore_activation_mode').val(settings.loreActivationMode);
|
||||
|
||||
Reference in New Issue
Block a user