mirror of
https://github.com/Wx-2025/ST-Amily2-Chat-Optimisation.git
synced 2026-06-06 16:15:50 +00:00
ci: auto build & obfuscate [2026-04-19 03:01:12] (Jenkins #16)
This commit is contained in:
@@ -10,6 +10,7 @@ import { generateRandomSeed } from '../../core/api.js';
|
|||||||
import { getChatIdentifier } from '../../core/lore.js';
|
import { getChatIdentifier } from '../../core/lore.js';
|
||||||
import { safeLorebookEntries } from '../../core/tavernhelper-compatibility.js';
|
import { safeLorebookEntries } from '../../core/tavernhelper-compatibility.js';
|
||||||
import { amilyHelper } from '../../core/tavern-helper/main.js';
|
import { amilyHelper } from '../../core/tavern-helper/main.js';
|
||||||
|
import { resolveHistoriographyRuleConfig } from '../../utils/config/RuleProfileManager.js';
|
||||||
|
|
||||||
const { SillyTavern, jQuery, characters } = window;
|
const { SillyTavern, jQuery, characters } = window;
|
||||||
|
|
||||||
@@ -127,9 +128,10 @@ function processChatMessages(messages) {
|
|||||||
return messages.map(msg => `${msg.is_user ? SillyTavern?.name1 || '用户' : msg.name || '角色'}: ${msg.message}`).join('\n\n');
|
return messages.map(msg => `${msg.is_user ? SillyTavern?.name1 || '用户' : msg.name || '角色'}: ${msg.message}`).join('\n\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
const useTagExtraction = mainSettings.historiographyTagExtractionEnabled ?? false;
|
const historiographyRuleConfig = resolveHistoriographyRuleConfig(mainSettings);
|
||||||
const tagsToExtract = useTagExtraction ? (mainSettings.historiographyTags || '').split(',').map(t => t.trim()).filter(Boolean) : [];
|
const useTagExtraction = historiographyRuleConfig.tagExtractionEnabled ?? false;
|
||||||
const exclusionRules = mainSettings.historiographyExclusionRules || [];
|
const tagsToExtract = useTagExtraction ? (historiographyRuleConfig.tags || '').split(',').map(t => t.trim()).filter(Boolean) : [];
|
||||||
|
const exclusionRules = historiographyRuleConfig.exclusionRules || [];
|
||||||
|
|
||||||
logDebug(`[CWB] 标签提取: ${useTagExtraction}, 标签: ${tagsToExtract.join(', ')}, 排除规则: ${exclusionRules.length}`);
|
logDebug(`[CWB] 标签提取: ${useTagExtraction}, 标签: ${tagsToExtract.join(', ')}, 排除规则: ${exclusionRules.length}`);
|
||||||
|
|
||||||
|
|||||||
22
SL/module/RuleConfigModule.js
Normal file
22
SL/module/RuleConfigModule.js
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
import { Module, ModuleBuilder } from './Module.js';
|
||||||
|
import { bindRuleConfigPanel } from '../../ui/rule-config-bindings.js';
|
||||||
|
|
||||||
|
const builder = new ModuleBuilder()
|
||||||
|
.name('RuleConfig')
|
||||||
|
.view('assets/rule-config-panel.html')
|
||||||
|
.strict(true)
|
||||||
|
.required(['mount']);
|
||||||
|
|
||||||
|
export default class RuleConfigModule extends Module {
|
||||||
|
constructor() {
|
||||||
|
super(builder);
|
||||||
|
}
|
||||||
|
|
||||||
|
async mount() {
|
||||||
|
if (this.el) {
|
||||||
|
this.el.id = 'amily2_rule_config_panel';
|
||||||
|
this.el.style.display = 'none';
|
||||||
|
}
|
||||||
|
bindRuleConfigPanel($(this.el));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -20,6 +20,7 @@ import GlossaryModule from './GlossaryModule.js';
|
|||||||
import RendererModule from './RendererModule.js';
|
import RendererModule from './RendererModule.js';
|
||||||
import SuperMemoryModule from './SuperMemoryModule.js';
|
import SuperMemoryModule from './SuperMemoryModule.js';
|
||||||
import ApiConfigModule from './ApiConfigModule.js';
|
import ApiConfigModule from './ApiConfigModule.js';
|
||||||
|
import RuleConfigModule from './RuleConfigModule.js';
|
||||||
import SfiGenModule from './SfiGenModule.js';
|
import SfiGenModule from './SfiGenModule.js';
|
||||||
|
|
||||||
export function registerAllModules() {
|
export function registerAllModules() {
|
||||||
@@ -34,5 +35,6 @@ export function registerAllModules() {
|
|||||||
registry.register('Renderer', () => new RendererModule());
|
registry.register('Renderer', () => new RendererModule());
|
||||||
registry.register('SuperMemory', () => new SuperMemoryModule());
|
registry.register('SuperMemory', () => new SuperMemoryModule());
|
||||||
registry.register('ApiConfig', () => new ApiConfigModule());
|
registry.register('ApiConfig', () => new ApiConfigModule());
|
||||||
|
registry.register('RuleConfig', () => new RuleConfigModule());
|
||||||
registry.register('SfiGen', () => new SfiGenModule());
|
registry.register('SfiGen', () => new SfiGenModule());
|
||||||
}
|
}
|
||||||
|
|||||||
21
TODO.md
21
TODO.md
@@ -80,4 +80,23 @@
|
|||||||
- **史官系统 (Historiographer) 优化**:
|
- **史官系统 (Historiographer) 优化**:
|
||||||
- **Ngms API 强制参数**:在 `core/api/Ngms_api.js` 中,移除了旧版 UI 中的温度和最大 Token 设置,强制将默认温度设为 `1.0`,最大 Token 设为 `30000`,以确保总结任务的稳定性和完整性。
|
- **Ngms API 强制参数**:在 `core/api/Ngms_api.js` 中,移除了旧版 UI 中的温度和最大 Token 设置,强制将默认温度设为 `1.0`,最大 Token 设为 `30000`,以确保总结任务的稳定性和完整性。
|
||||||
- **总结失败自动重试**:在 `core/historiographer.js` 中为“微言录”和“宏史卷”的生成过程添加了自定义重试逻辑。用户可在 UI 中设置重试次数,当 AI 返回空内容时,系统会自动等待并重试,降低了因 API 波动导致的总结失败率。
|
- **总结失败自动重试**:在 `core/historiographer.js` 中为“微言录”和“宏史卷”的生成过程添加了自定义重试逻辑。用户可在 UI 中设置重试次数,当 AI 返回空内容时,系统会自动等待并重试,降低了因 API 波动导致的总结失败率。
|
||||||
- **时间跨度标识优化**:修改了 `utils/settings.js` 中的“微言录”和“宏史卷”提示词,强制要求 AI 在提取时间时加入相对时间跨度标识 `(Xd)`(如 `2023-09-15(2d)-星期五-15:00`),以解决长篇剧情中因缺乏具体日期导致的时间线混乱问题。
|
- **时间跨度标识优化**:修改了 `utils/settings.js` 中的”微言录”和”宏史卷”提示词,强制要求 AI 在提取时间时加入相对时间跨度标识 `(Xd)`(如 `2023-09-15(2d)-星期五-15:00`),以解决长篇剧情中因缺乏具体日期导致的时间线混乱问题。
|
||||||
|
|
||||||
|
### 2.1.0 (2026/04/18)
|
||||||
|
|
||||||
|
以下为更新内容:
|
||||||
|
- **提取规则配置通用化重构**:
|
||||||
|
- `RuleProfileManager` 新增功能槽(SLOTS)+ 统一分配(assignments)机制,参照 `ApiProfileManager` 的架构模式,将提取规则预设存储在 `extension_settings`(settings.json)中实现云同步。
|
||||||
|
- 定义四个功能槽:`table`(表格提取)、`historiography`(史官/总结提取)、`condensation`(翰林院·浓缩)、`queryPreprocessing`(翰林院·查询预处理)。
|
||||||
|
- 新增 `resolveSlotRuleConfig(slot)` 统一解析接口,优先读取 assignments 分配,回退兼容旧字段。
|
||||||
|
- 新增一次性迁移逻辑:自动将旧版分散的 `table_rule_profile_id`、`historiographyRuleProfileId`、`condensation.ruleProfileId`、`queryPreprocessing.ruleProfileId` 迁移到统一的 `ruleProfileAssignments`。
|
||||||
|
- **消费方 UI 统一改为下拉选单**:
|
||||||
|
- **表格系统**:移除”启用独立提取规则”开关和”配置规则”弹窗,替换为规则配置下拉选单,onChange 即时生效。
|
||||||
|
- **史官系统**:移除标签提取开关、标签输入框和”内容排除”弹窗按钮,替换为规则配置下拉选单。
|
||||||
|
- **翰林院(浓缩 + 查询预处理)**:移除各自的规则配置弹窗按钮,分别替换为独立的规则配置下拉选单;修复了翰林院旧弹窗存在的 HTML 注入隐患。
|
||||||
|
- 新建/编辑规则统一通过「规则配置中心」面板完成。
|
||||||
|
- **遗留代码清理**:
|
||||||
|
- 删除 `openTableRuleEditor`(table-bindings.js)、`showHistoriographyExclusionRulesModal`(historiography-bindings.js)、`showRulesModal` / `saveHanlinRuleProfile` / `syncHanlinLinkedRuleProfile`(hanlinyuan-bindings.js)等旧弹窗函数。
|
||||||
|
- 删除 `saveHistoriographyRuleProfile` / `syncHistoriographyLinkedRuleProfile` 等旧同步函数。
|
||||||
|
- 移除 `table_independent_rules_enabled` 开关判断,批量填表和分步填表改为检查 resolved config 是否有实际内容。
|
||||||
|
- 修复 `previewCondensation` 引用已移除 DOM 元素(`hly-tag-extraction-toggle` / `hly-tag-input`)的问题,改为从 resolved config 读取。
|
||||||
|
|||||||
@@ -241,20 +241,12 @@
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="hly-control-block" style="flex-direction: row; justify-content: space-between; align-items: center; margin-top: 10px;">
|
<div class="hly-control-block" style="margin-top: 10px;">
|
||||||
<label for="historiography-tag-extraction-toggle">标签提取</label>
|
<label style="font-weight: bold;">提取规则配置</label>
|
||||||
<label class="hly-toggle-switch">
|
<select id="historiography-rule-profile-select" class="hly-imperial-brush" style="width: 100%;"></select>
|
||||||
<input type="checkbox" id="historiography-tag-extraction-toggle" data-setting-key="condensation.tagExtractionEnabled" data-type="boolean">
|
<small class="hly-notes">选择在「规则配置中心」里创建的提取规则,应用于微言录和宏史卷总结。</small>
|
||||||
<span class="slider"></span>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
<div id="historiography-tag-input-container" class="hly-control-block" style="display: none;">
|
|
||||||
<label for="historiography-tag-input">输入标签 (以逗号分隔):</label>
|
|
||||||
<textarea id="historiography-tag-input" class="hly-imperial-brush" rows="2" placeholder="例如: content,details" data-setting-key="condensation.tags" data-type="string"></textarea>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="hly-button-group" style="justify-content: flex-start; margin-top: 10px; display: flex; align-items: center; gap: 20px;">
|
<div class="hly-button-group" style="justify-content: flex-start; margin-top: 10px; display: flex; align-items: center; gap: 20px;">
|
||||||
<button id="historiography-exclusion-rules-btn" class="hly-action-button">内容排除</button>
|
|
||||||
|
|
||||||
<div class="auto-control-pair" style="margin-bottom: 0;">
|
<div class="auto-control-pair" style="margin-bottom: 0;">
|
||||||
<label for="historiography_auto_summary_interactive" title="开启后,“自动巡录”将弹出交互窗口确认,而不是在后台静默运行。">交互式巡录:</label>
|
<label for="historiography_auto_summary_interactive" title="开启后,“自动巡录”将弹出交互窗口确认,而不是在后台静默运行。">交互式巡录:</label>
|
||||||
<label class="toggle-switch">
|
<label class="toggle-switch">
|
||||||
|
|||||||
@@ -252,16 +252,10 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="table-independent-rules-container" class="control-block-with-switch" style="margin-bottom: 10px; display: none; flex-direction: column; align-items: flex-start; gap: 8px;">
|
<div class="control-block-with-switch" style="margin-bottom: 10px; display: flex; flex-direction: column; align-items: flex-start; gap: 8px;">
|
||||||
<div style="display: flex; justify-content: space-between; align-items: center; width: 100%;">
|
<label style="font-weight: bold;">提取规则配置</label>
|
||||||
<label for="table-independent-rules-enabled">启用独立提取规则</label>
|
<select id="table-rule-profile-select" class="text_pole" style="width: 100%;"></select>
|
||||||
<label class="toggle-switch">
|
<small class="notes">选择在「规则配置中心」里创建的提取规则,应用于分步填表和批量填表。未选择时使用默认行为。</small>
|
||||||
<input type="checkbox" id="table-independent-rules-enabled">
|
|
||||||
<span class="slider"></span>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
<button id="table-configure-rules-btn" class="menu_button small_button" style="display: none;"><i class="fas fa-cog"></i> 配置规则</button>
|
|
||||||
<small class="notes">启用后,分步填表和批量填表将使用下方配置的专属规则,而非微言录的规则。</small>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="action-center-buttons" style="gap: 8px;">
|
<div class="action-center-buttons" style="gap: 8px;">
|
||||||
<button id="amily2-open-relationship-graph-btn" class="menu_button accent small_button interactable"><i class="fas fa-project-diagram"></i> 关系图谱</button>
|
<button id="amily2-open-relationship-graph-btn" class="menu_button accent small_button interactable"><i class="fas fa-project-diagram"></i> 关系图谱</button>
|
||||||
|
|||||||
@@ -251,19 +251,10 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="hly-control-block" style="flex-direction: row; justify-content: space-between; align-items: center;">
|
<div class="hly-control-block" style="margin-top: 8px;">
|
||||||
<label for="hly-tag-extraction-toggle">标签提取</label>
|
<label style="font-weight: bold;">提取规则配置</label>
|
||||||
<label class="hly-toggle-switch">
|
<select id="hly-condensation-rule-profile-select" class="hly-imperial-brush" style="width: 100%;"></select>
|
||||||
<input type="checkbox" id="hly-tag-extraction-toggle" data-setting-key="condensation.tagExtractionEnabled" data-type="boolean">
|
<small class="hly-notes">选择在「规则配置中心」里创建的提取规则,应用于浓缩处理。</small>
|
||||||
<span class="slider"></span>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
<div id="hly-tag-input-container" class="hly-control-block" style="display: none;">
|
|
||||||
<label for="hly-tag-input">输入标签 (以逗号分隔):</label>
|
|
||||||
<textarea id="hly-tag-input" class="hly-imperial-brush" rows="2" placeholder="例如: content,details,摘要" data-setting-key="condensation.tags" data-type="string"></textarea>
|
|
||||||
</div>
|
|
||||||
<div class="hly-button-group" style="justify-content: flex-start;">
|
|
||||||
<button id="hly-exclusion-rules-btn" class="hly-action-button">内容排除</button>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="hly-button-group">
|
<div class="hly-button-group">
|
||||||
<button class="hly-action-button success" onclick="startHLYCondensation()"> 开始凝识</button>
|
<button class="hly-action-button success" onclick="startHLYCondensation()"> 开始凝识</button>
|
||||||
@@ -405,7 +396,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="hly-kb-list-local" class="hly-kb-list">
|
<div id="hly-kb-list-local" class="hly-kb-list">
|
||||||
<p id="hly-kb-list-local-placeholder" style="color: #888;">当前角色没有知识库。通过“书库编纂”中的功能可自动创建。</p>
|
<p id="hly-kb-list-local-placeholder" style="color: #888;">当前角色没有知识库。通过“书库编纂"中的功能可自动创建。</p>
|
||||||
<!-- Local KBs will be populated here -->
|
<!-- Local KBs will be populated here -->
|
||||||
</div>
|
</div>
|
||||||
<div class="hly-button-group" style="margin-top: 15px;">
|
<div class="hly-button-group" style="margin-top: 15px;">
|
||||||
@@ -456,10 +447,11 @@
|
|||||||
<span class="slider"></span>
|
<span class="slider"></span>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="hly-button-group" style="justify-content: flex-start;">
|
<div class="hly-control-block" style="margin-top: 8px;">
|
||||||
<button id="hly-query-preprocessing-rules-btn" class="hly-action-button">配置处理规则</button>
|
<label style="font-weight: bold;">处理规则配置</label>
|
||||||
|
<select id="hly-query-preprocessing-rule-profile-select" class="hly-imperial-brush" style="width: 100%;"></select>
|
||||||
|
<small class="hly-notes">选择在「规则配置中心」里创建的提取规则,应用于查询预处理(标签提取 + 内容排除)。</small>
|
||||||
</div>
|
</div>
|
||||||
<small class="hly-notes">此功能类似于“凝识法则”,可对您最近的几条聊天记录(即用于检索的文本)进行标签提取和内容排除,以生成更纯净、更高效的检索查询。</small>
|
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
<fieldset class="hly-settings-group">
|
<fieldset class="hly-settings-group">
|
||||||
|
|||||||
@@ -2,8 +2,8 @@
|
|||||||
<div class="additional-features-title">
|
<div class="additional-features-title">
|
||||||
<i class="fas fa-key"></i> API 连接配置
|
<i class="fas fa-key"></i> API 连接配置
|
||||||
</div>
|
</div>
|
||||||
<button id="amily2_back_to_main_from_api_config" class="menu_button secondary small_button interactable">
|
<button id="amily2_back_to_main_from_api_config" class="menu_button secondary small_button interactable amily2-vbtn">
|
||||||
返回主殿 <i class="fas fa-arrow-right"></i>
|
<span class="vbtn-icon"><i class="fas fa-arrow-right"></i></span><span class="vbtn-label">返回主殿</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<hr class="header-divider" style="margin-top: 5px; margin-bottom: 10px;">
|
<hr class="header-divider" style="margin-top: 5px; margin-bottom: 10px;">
|
||||||
@@ -26,16 +26,16 @@
|
|||||||
<label>当前密钥对指纹</label>
|
<label>当前密钥对指纹</label>
|
||||||
<div style="display:flex; gap:6px; align-items:center;">
|
<div style="display:flex; gap:6px; align-items:center;">
|
||||||
<code id="amily2_keypair_fingerprint" style="flex:1; padding:4px 8px; background:var(--black30a); border-radius:4px; font-size:0.85em;">(未生成)</code>
|
<code id="amily2_keypair_fingerprint" style="flex:1; padding:4px 8px; background:var(--black30a); border-radius:4px; font-size:0.85em;">(未生成)</code>
|
||||||
<button id="amily2_generate_keypair" class="menu_button interactable small_button" title="生成新密钥对(会清除所有已加密的 Key)">
|
<button id="amily2_generate_keypair" class="menu_button interactable small_button amily2-vbtn" title="生成新密钥对(会清除所有已加密的 Key)">
|
||||||
<i class="fas fa-sync-alt"></i> 重新生成
|
<span class="vbtn-icon"><i class="fas fa-sync-alt"></i></span><span class="vbtn-label">重新生成</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div style="display:flex; gap:6px; margin-top:6px; flex-wrap:wrap;">
|
<div style="display:flex; gap:6px; margin-top:6px; flex-wrap:wrap;">
|
||||||
<button id="amily2_export_key_bundle" class="menu_button interactable small_button" title="导出当前设备的私钥包,用于新设备恢复解密权限">
|
<button id="amily2_export_key_bundle" class="menu_button interactable small_button amily2-vbtn" title="导出当前设备的私钥包,用于新设备恢复解密权限">
|
||||||
<i class="fas fa-download"></i> 导出私钥
|
<span class="vbtn-icon"><i class="fas fa-download"></i></span><span class="vbtn-label">导出私钥</span>
|
||||||
</button>
|
</button>
|
||||||
<button id="amily2_import_key_bundle" class="menu_button interactable small_button" title="导入先前导出的私钥包,恢复云同步密钥的解密能力">
|
<button id="amily2_import_key_bundle" class="menu_button interactable small_button amily2-vbtn" title="导入先前导出的私钥包,恢复云同步密钥的解密能力">
|
||||||
<i class="fas fa-upload"></i> 导入私钥
|
<span class="vbtn-icon"><i class="fas fa-upload"></i></span><span class="vbtn-label">导入私钥</span>
|
||||||
</button>
|
</button>
|
||||||
<input id="amily2_import_key_bundle_input" type="file" accept=".json,application/json" style="display:none;" />
|
<input id="amily2_import_key_bundle_input" type="file" accept=".json,application/json" style="display:none;" />
|
||||||
</div>
|
</div>
|
||||||
@@ -52,17 +52,17 @@
|
|||||||
|
|
||||||
<div style="display:flex; gap:6px; margin-bottom:10px; flex-wrap:wrap;">
|
<div style="display:flex; gap:6px; margin-bottom:10px; flex-wrap:wrap;">
|
||||||
<button class="menu_button small_button amily2_profile_type_filter active" data-type="all">全部</button>
|
<button class="menu_button small_button amily2_profile_type_filter active" data-type="all">全部</button>
|
||||||
<button class="menu_button small_button amily2_profile_type_filter" data-type="chat">
|
<button class="menu_button small_button amily2_profile_type_filter amily2-vbtn" data-type="chat">
|
||||||
<i class="fas fa-comments"></i> 对话模型
|
<span class="vbtn-icon"><i class="fas fa-comments"></i></span><span class="vbtn-label">对话模型</span>
|
||||||
</button>
|
</button>
|
||||||
<button class="menu_button small_button amily2_profile_type_filter" data-type="embedding">
|
<button class="menu_button small_button amily2_profile_type_filter amily2-vbtn" data-type="embedding">
|
||||||
<i class="fas fa-project-diagram"></i> 向量嵌入
|
<span class="vbtn-icon"><i class="fas fa-project-diagram"></i></span><span class="vbtn-label">向量嵌入</span>
|
||||||
</button>
|
</button>
|
||||||
<button class="menu_button small_button amily2_profile_type_filter" data-type="rerank">
|
<button class="menu_button small_button amily2_profile_type_filter amily2-vbtn" data-type="rerank">
|
||||||
<i class="fas fa-sort-amount-down"></i> 重排序
|
<span class="vbtn-icon"><i class="fas fa-sort-amount-down"></i></span><span class="vbtn-label">重排序</span>
|
||||||
</button>
|
</button>
|
||||||
<button id="amily2_add_profile" class="menu_button small_button interactable" style="margin-left:auto;">
|
<button id="amily2_add_profile" class="menu_button small_button interactable amily2-vbtn" style="margin-left:auto;">
|
||||||
<i class="fas fa-plus"></i> 新建配置
|
<span class="vbtn-icon"><i class="fas fa-plus"></i></span><span class="vbtn-label">新建配置</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -139,16 +139,16 @@
|
|||||||
<div style="display:flex; gap:6px; align-items:stretch;">
|
<div style="display:flex; gap:6px; align-items:stretch;">
|
||||||
<input id="amily2_pf_model" type="text" class="text_pole" placeholder="手动填写或点击「获取」" style="flex:1;" />
|
<input id="amily2_pf_model" type="text" class="text_pole" placeholder="手动填写或点击「获取」" style="flex:1;" />
|
||||||
<select id="amily2_pf_model_select" class="text_pole" style="flex:1; display:none;"></select>
|
<select id="amily2_pf_model_select" class="text_pole" style="flex:1; display:none;"></select>
|
||||||
<button id="amily2_pf_fetch_models" class="menu_button small_button interactable" type="button" title="从 API 获取可用模型列表(需先填写地址和 Key)">
|
<button id="amily2_pf_fetch_models" class="menu_button small_button interactable amily2-vbtn" type="button" title="从 API 获取可用模型列表(需先填写地址和 Key)">
|
||||||
<i class="fas fa-list"></i> 获取
|
<span class="vbtn-icon"><i class="fas fa-list"></i></span><span class="vbtn-label">获取</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 测试连接 -->
|
<!-- 测试连接 -->
|
||||||
<div style="display:flex; align-items:center; gap:10px; margin-bottom:10px;">
|
<div style="display:flex; align-items:center; gap:10px; margin-bottom:10px;">
|
||||||
<button id="amily2_pf_test_conn" class="menu_button small_button interactable" type="button">
|
<button id="amily2_pf_test_conn" class="menu_button small_button interactable amily2-vbtn" type="button">
|
||||||
<i class="fas fa-plug"></i> 测试连接
|
<span class="vbtn-icon"><i class="fas fa-plug"></i></span><span class="vbtn-label">测试连接</span>
|
||||||
</button>
|
</button>
|
||||||
<span id="amily2_pf_test_result" style="font-size:0.85em;"></span>
|
<span id="amily2_pf_test_result" style="font-size:0.85em;"></span>
|
||||||
</div>
|
</div>
|
||||||
@@ -222,11 +222,11 @@
|
|||||||
|
|
||||||
<!-- 操作按钮 -->
|
<!-- 操作按钮 -->
|
||||||
<div style="display:flex; gap:8px; margin-top:16px;">
|
<div style="display:flex; gap:8px; margin-top:16px;">
|
||||||
<button id="amily2_profile_modal_cancel" class="menu_button secondary interactable">
|
<button id="amily2_profile_modal_cancel" class="menu_button secondary interactable amily2-vbtn">
|
||||||
<i class="fas fa-times"></i> 取消
|
<span class="vbtn-icon"><i class="fas fa-times"></i></span><span class="vbtn-label">取消</span>
|
||||||
</button>
|
</button>
|
||||||
<button id="amily2_profile_modal_save" class="menu_button interactable">
|
<button id="amily2_profile_modal_save" class="menu_button interactable amily2-vbtn">
|
||||||
<i class="fas fa-save"></i> 保存
|
<span class="vbtn-icon"><i class="fas fa-save"></i></span><span class="vbtn-label">保存</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
45
assets/rule-config-panel.html
Normal file
45
assets/rule-config-panel.html
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
<div class="settings-group" id="amily2_rule_config_panel_root">
|
||||||
|
<fieldset class="settings-group">
|
||||||
|
<legend><i class="fas fa-list-check"></i> 规则配置中心</legend>
|
||||||
|
<div style="display:flex; gap:16px; align-items:flex-start;">
|
||||||
|
<div style="width: 260px; flex-shrink:0;">
|
||||||
|
<div style="display:flex; gap:8px; margin-bottom:10px;">
|
||||||
|
<button id="amily2_rule_profile_new" class="menu_button small_button amily2-vbtn"><span class="vbtn-icon"><i class="fas fa-plus"></i></span><span class="vbtn-label">新建</span></button>
|
||||||
|
</div>
|
||||||
|
<div id="amily2_rule_profile_list" style="display:flex; flex-direction:column; gap:8px;"></div>
|
||||||
|
</div>
|
||||||
|
<div style="flex:1; min-width:0;">
|
||||||
|
<div class="amily2_settings_block">
|
||||||
|
<label for="amily2_rule_profile_name">配置名称</label>
|
||||||
|
<input id="amily2_rule_profile_name" class="text_pole" type="text" placeholder="例如:通用提取规则">
|
||||||
|
</div>
|
||||||
|
<div class="amily2_settings_block" style="margin-top:10px;">
|
||||||
|
<label><input id="amily2_rule_profile_tag_toggle" type="checkbox"> 启用标签提取</label>
|
||||||
|
</div>
|
||||||
|
<div id="amily2_rule_profile_tags_wrap" class="amily2_settings_block" style="display:none; margin-top:10px;">
|
||||||
|
<label for="amily2_rule_profile_tags">标签列表</label>
|
||||||
|
<textarea id="amily2_rule_profile_tags" class="text_pole" rows="3" placeholder="例如:content,details,summary"></textarea>
|
||||||
|
</div>
|
||||||
|
<div class="amily2_settings_block" style="margin-top:10px;">
|
||||||
|
<label>排除规则</label>
|
||||||
|
<div id="amily2_rule_profile_rules" style="display:flex; flex-direction:column; gap:8px; margin:8px 0;"></div>
|
||||||
|
<button id="amily2_rule_profile_add_rule" class="menu_button small_button amily2-vbtn"><span class="vbtn-icon"><i class="fas fa-plus"></i></span><span class="vbtn-label">添加规则</span></button>
|
||||||
|
</div>
|
||||||
|
<div style="display:flex; gap:8px; margin-top:16px;">
|
||||||
|
<button id="amily2_rule_profile_save" class="menu_button menu_button_primary amily2-vbtn"><span class="vbtn-icon"><i class="fas fa-save"></i></span><span class="vbtn-label">保存</span></button>
|
||||||
|
<button id="amily2_rule_profile_delete" class="menu_button danger amily2-vbtn"><span class="vbtn-icon"><i class="fas fa-trash-alt"></i></span><span class="vbtn-label">删除</span></button>
|
||||||
|
<button id="amily2_back_to_main_from_rule_config" class="menu_button amily2-vbtn"><span class="vbtn-icon"><i class="fas fa-arrow-left"></i></span><span class="vbtn-label">返回</span></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
</div>
|
||||||
|
<style>
|
||||||
|
#amily2_rule_config_panel .amily2-rule-row,
|
||||||
|
#amily2_rule_config_panel_root .amily2-rule-row {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr auto;
|
||||||
|
gap: 8px;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -772,3 +772,18 @@ hr.header-divider {
|
|||||||
padding-bottom: 8px;
|
padding-bottom: 8px;
|
||||||
border-bottom: 1px solid var(--SmartThemeBorderColor);
|
border-bottom: 1px solid var(--SmartThemeBorderColor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 图标在上、文字在下的垂直按钮 */
|
||||||
|
.amily2-vbtn {
|
||||||
|
display: inline-flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 3px;
|
||||||
|
padding: 8px 12px;
|
||||||
|
min-width: 56px;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
.amily2-vbtn .vbtn-icon { font-size: 1.15em; }
|
||||||
|
.amily2-vbtn .vbtn-label { font-size: 0.82em; white-space: nowrap; }
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import { getPresetPrompts, getMixedOrder } from '../PresetSettings/index.js';
|
|||||||
import { callAI, generateRandomSeed } from "./api.js";
|
import { callAI, generateRandomSeed } from "./api.js";
|
||||||
import { callNgmsAI } from "./api/Ngms_api.js";
|
import { callNgmsAI } from "./api/Ngms_api.js";
|
||||||
import { executeAutoHide } from "./autoHideManager.js";
|
import { executeAutoHide } from "./autoHideManager.js";
|
||||||
|
import { resolveHistoriographyRuleConfig } from "../utils/config/RuleProfileManager.js";
|
||||||
|
|
||||||
let reloadEditor = () => {
|
let reloadEditor = () => {
|
||||||
console.warn("[大史官] reloadEditor 函数不可用,可能是旧版本。已使用空函数代替。");
|
console.warn("[大史官] reloadEditor 函数不可用,可能是旧版本。已使用空函数代替。");
|
||||||
@@ -302,9 +303,10 @@ function getRawMessagesForSummary(startFloor, endFloor) {
|
|||||||
const userName = context.name1 || '用户';
|
const userName = context.name1 || '用户';
|
||||||
const characterName = context.name2 || '角色';
|
const characterName = context.name2 || '角色';
|
||||||
|
|
||||||
const useTagExtraction = settings.historiographyTagExtractionEnabled ?? false;
|
const historiographyRuleConfig = resolveHistoriographyRuleConfig(settings);
|
||||||
const tagsToExtract = useTagExtraction ? (settings.historiographyTags || '').split(',').map(t => t.trim()).filter(Boolean) : [];
|
const useTagExtraction = historiographyRuleConfig.tagExtractionEnabled ?? false;
|
||||||
const exclusionRules = settings.historiographyExclusionRules || [];
|
const tagsToExtract = useTagExtraction ? (historiographyRuleConfig.tags || '').split(',').map(t => t.trim()).filter(Boolean) : [];
|
||||||
|
const exclusionRules = historiographyRuleConfig.exclusionRules || [];
|
||||||
|
|
||||||
const messages = historySlice.map((msg, index) => {
|
const messages = historySlice.map((msg, index) => {
|
||||||
let content = msg.mes;
|
let content = msg.mes;
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import * as ContextUtils from './utils/context-utils.js';
|
|||||||
import { getCollectionIdInfo, getCharacterId, getCharacterStableId } from './utils/context-utils.js';
|
import { getCollectionIdInfo, getCharacterId, getCharacterStableId } from './utils/context-utils.js';
|
||||||
import { defaultSettings as ragDefaultSettings } from './rag-settings.js';
|
import { defaultSettings as ragDefaultSettings } from './rag-settings.js';
|
||||||
import { extractBlocksByTags, applyExclusionRules } from './utils/rag-tag-extractor.js';
|
import { extractBlocksByTags, applyExclusionRules } from './utils/rag-tag-extractor.js';
|
||||||
|
import { resolveQueryPreprocessingRuleConfig } from '../utils/config/RuleProfileManager.js';
|
||||||
import * as IngestionManager from './ingestion-manager.js';
|
import * as IngestionManager from './ingestion-manager.js';
|
||||||
import {
|
import {
|
||||||
getEmbeddings,
|
getEmbeddings,
|
||||||
@@ -1324,7 +1325,7 @@ function preprocessQueryText(queryText) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let processedText = queryText;
|
let processedText = queryText;
|
||||||
const { tagExtractionEnabled, tags, exclusionRules } = settings.queryPreprocessing;
|
const { tagExtractionEnabled, tags, exclusionRules } = resolveQueryPreprocessingRuleConfig(settings);
|
||||||
|
|
||||||
if (tagExtractionEnabled && tags) {
|
if (tagExtractionEnabled && tags) {
|
||||||
const tagsToExtract = tags.split(',').map(t => t.trim()).filter(Boolean);
|
const tagsToExtract = tags.split(',').map(t => t.trim()).filter(Boolean);
|
||||||
@@ -1438,7 +1439,7 @@ async function rearrangeChat(chat, contextSize, abort, type) {
|
|||||||
const queryMessages = chat.slice(-settings.advanced.queryMessageCount);
|
const queryMessages = chat.slice(-settings.advanced.queryMessageCount);
|
||||||
if (queryMessages.length === 0) return;
|
if (queryMessages.length === 0) return;
|
||||||
|
|
||||||
const queryPreprocessingSettings = settings.queryPreprocessing;
|
const queryPreprocessingSettings = resolveQueryPreprocessingRuleConfig(settings);
|
||||||
let queryText = '';
|
let queryText = '';
|
||||||
const relevantTexts = [];
|
const relevantTexts = [];
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import {
|
|||||||
import { getBatchFillerFlowTemplate, convertTablesToCsvString, updateTableFromText, saveStateToMessage, getMemoryState } from './table-system/manager.js';
|
import { getBatchFillerFlowTemplate, convertTablesToCsvString, updateTableFromText, saveStateToMessage, getMemoryState } from './table-system/manager.js';
|
||||||
import { saveChat } from "/script.js";
|
import { saveChat } from "/script.js";
|
||||||
import { renderTables } from '../ui/table-bindings.js';
|
import { renderTables } from '../ui/table-bindings.js';
|
||||||
|
import { resolveHistoriographyRuleConfig } from "../utils/config/RuleProfileManager.js";
|
||||||
|
|
||||||
import { getPresetPrompts, getMixedOrder } from '../PresetSettings/index.js';
|
import { getPresetPrompts, getMixedOrder } from '../PresetSettings/index.js';
|
||||||
import { callAI, generateRandomSeed } from './api.js';
|
import { callAI, generateRandomSeed } from './api.js';
|
||||||
@@ -428,9 +429,10 @@ export async function processPlotOptimization(currentUserMessage, contextMessage
|
|||||||
const historyMessages = contextMessages.slice(-contextLimit);
|
const historyMessages = contextMessages.slice(-contextLimit);
|
||||||
|
|
||||||
// 复刻 Historiographer 的标签提取与内容排除逻辑
|
// 复刻 Historiographer 的标签提取与内容排除逻辑
|
||||||
const useTagExtraction = settings.historiographyTagExtractionEnabled ?? false;
|
const historiographyRuleConfig = resolveHistoriographyRuleConfig(settings);
|
||||||
const tagsToExtract = useTagExtraction ? (settings.historiographyTags || '').split(',').map(t => t.trim()).filter(Boolean) : [];
|
const useTagExtraction = historiographyRuleConfig.tagExtractionEnabled ?? false;
|
||||||
const exclusionRules = settings.historiographyExclusionRules || [];
|
const tagsToExtract = useTagExtraction ? (historiographyRuleConfig.tags || '').split(',').map(t => t.trim()).filter(Boolean) : [];
|
||||||
|
const exclusionRules = historiographyRuleConfig.exclusionRules || [];
|
||||||
|
|
||||||
history = historyMessages
|
history = historyMessages
|
||||||
.map(msg => {
|
.map(msg => {
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import { getPresetPrompts, getMixedOrder } from '../../PresetSettings/index.js';
|
|||||||
import { callAI, generateRandomSeed } from '../api.js';
|
import { callAI, generateRandomSeed } from '../api.js';
|
||||||
import { callNccsAI } from '../api/NccsApi.js';
|
import { callNccsAI } from '../api/NccsApi.js';
|
||||||
import { extractBlocksByTags, applyExclusionRules } from '../utils/rag-tag-extractor.js';
|
import { extractBlocksByTags, applyExclusionRules } from '../utils/rag-tag-extractor.js';
|
||||||
|
import { resolveTableRuleConfig } from '../../utils/config/RuleProfileManager.js';
|
||||||
|
|
||||||
import { getBatchFillerRuleTemplate, getBatchFillerFlowTemplate, convertTablesToCsvString } from './manager.js';
|
import { getBatchFillerRuleTemplate, getBatchFillerFlowTemplate, convertTablesToCsvString } from './manager.js';
|
||||||
|
|
||||||
@@ -152,10 +153,11 @@ function getRawMessagesForSummary(startFloor, endFloor) {
|
|||||||
let tagsToExtract = [];
|
let tagsToExtract = [];
|
||||||
let exclusionRules = [];
|
let exclusionRules = [];
|
||||||
|
|
||||||
if (settings.table_independent_rules_enabled) {
|
const tableRuleConfig = resolveTableRuleConfig(settings);
|
||||||
log('批量填表:使用独立提取规则。', 'info');
|
if (tableRuleConfig.tags || (tableRuleConfig.exclusionRules && tableRuleConfig.exclusionRules.length)) {
|
||||||
tagsToExtract = (settings.table_tags_to_extract || '').split(',').map(t => t.trim()).filter(Boolean);
|
log('批量填表:使用提取规则配置。', 'info');
|
||||||
exclusionRules = settings.table_exclusion_rules || [];
|
tagsToExtract = (tableRuleConfig.tags || '').split(',').map(t => t.trim()).filter(Boolean);
|
||||||
|
exclusionRules = tableRuleConfig.exclusionRules || [];
|
||||||
}
|
}
|
||||||
|
|
||||||
const messages = historySlice.map((msg, index) => {
|
const messages = historySlice.map((msg, index) => {
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import { getPresetPrompts, getMixedOrder } from '../../PresetSettings/index.js';
|
|||||||
import { callAI, generateRandomSeed } from '../api.js';
|
import { callAI, generateRandomSeed } from '../api.js';
|
||||||
import { callNccsAI } from '../api/NccsApi.js';
|
import { callNccsAI } from '../api/NccsApi.js';
|
||||||
import { extractBlocksByTags, applyExclusionRules } from '../utils/rag-tag-extractor.js';
|
import { extractBlocksByTags, applyExclusionRules } from '../utils/rag-tag-extractor.js';
|
||||||
|
import { resolveTableRuleConfig } from '../../utils/config/RuleProfileManager.js';
|
||||||
import { safeLorebookEntries } from '../tavernhelper-compatibility.js';
|
import { safeLorebookEntries } from '../tavernhelper-compatibility.js';
|
||||||
|
|
||||||
|
|
||||||
@@ -171,9 +172,10 @@ export async function fillWithSecondaryApi(latestMessage, forceRun = false) {
|
|||||||
|
|
||||||
let tagsToExtract = [];
|
let tagsToExtract = [];
|
||||||
let exclusionRules = [];
|
let exclusionRules = [];
|
||||||
if (settings.table_independent_rules_enabled) {
|
const tableRuleConfig = resolveTableRuleConfig(settings);
|
||||||
tagsToExtract = (settings.table_tags_to_extract || '').split(',').map(t => t.trim()).filter(Boolean);
|
if (tableRuleConfig.tags || (tableRuleConfig.exclusionRules && tableRuleConfig.exclusionRules.length)) {
|
||||||
exclusionRules = settings.table_exclusion_rules || [];
|
tagsToExtract = (tableRuleConfig.tags || '').split(',').map(t => t.trim()).filter(Boolean);
|
||||||
|
exclusionRules = tableRuleConfig.exclusionRules || [];
|
||||||
}
|
}
|
||||||
|
|
||||||
let coreContentText = "";
|
let coreContentText = "";
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import './SL/bus/Amily2Bus.js'
|
|||||||
import './utils/config/ConfigManager.js'
|
import './utils/config/ConfigManager.js'
|
||||||
import './utils/config/api-key-store/ApiKeyStore.js'
|
import './utils/config/api-key-store/ApiKeyStore.js'
|
||||||
import './utils/config/ApiProfileManager.js'
|
import './utils/config/ApiProfileManager.js'
|
||||||
|
import './utils/config/RuleProfileManager.js'
|
||||||
import './core/table-system/TableSystemService.js'
|
import './core/table-system/TableSystemService.js'
|
||||||
|
|
||||||
// Re-exports (重新导出供 index.js 使用)
|
// Re-exports (重新导出供 index.js 使用)
|
||||||
@@ -33,7 +34,9 @@ export { pluginVersion, extensionName, defaultSettings } from './utils/settings.
|
|||||||
export { configManager } from './utils/config/ConfigManager.js';
|
export { configManager } from './utils/config/ConfigManager.js';
|
||||||
export { apiKeyStore } from './utils/config/api-key-store/ApiKeyStore.js';
|
export { apiKeyStore } from './utils/config/api-key-store/ApiKeyStore.js';
|
||||||
export { apiProfileManager, PROFILE_TYPES, SLOTS } from './utils/config/ApiProfileManager.js';
|
export { apiProfileManager, PROFILE_TYPES, SLOTS } from './utils/config/ApiProfileManager.js';
|
||||||
|
export { ruleProfileManager, RULE_SLOTS, resolveSlotRuleConfig, resolveCondensationRuleConfig, resolveQueryPreprocessingRuleConfig, resolveTableRuleConfig, resolveHistoriographyRuleConfig, resolveRuleConfig } from './utils/config/RuleProfileManager.js';
|
||||||
export { bindApiConfigPanel } from './ui/api-config-bindings.js';
|
export { bindApiConfigPanel } from './ui/api-config-bindings.js';
|
||||||
|
export { bindRuleConfigPanel } from './ui/rule-config-bindings.js';
|
||||||
export { checkAuthorization, refreshUserInfo } from './utils/auth.js';
|
export { checkAuthorization, refreshUserInfo } from './utils/auth.js';
|
||||||
export { tableSystemDefaultSettings } from './core/table-system/settings.js';
|
export { tableSystemDefaultSettings } from './core/table-system/settings.js';
|
||||||
export { manageLorebookEntriesForChat } from './core/lore.js';
|
export { manageLorebookEntriesForChat } from './core/lore.js';
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "Amily2号聊天优化助手",
|
"name": "Amily2号聊天优化助手",
|
||||||
"display_name": "Amily2号助手",
|
"display_name": "Amily2号助手",
|
||||||
"version": "2.0.3",
|
"version": "2.1.0",
|
||||||
"author": "Wx-2025",
|
"author": "Wx-2025",
|
||||||
"description": "一个拥有独立UI的智能引擎,正文优化、自动总结、记忆表格、rag向量、隐藏楼层、剧情推进等多功能整合。",
|
"description": "一个拥有独立UI的智能引擎,正文优化、自动总结、记忆表格、rag向量、隐藏楼层、剧情推进等多功能整合。",
|
||||||
"minSillyTavernVersion": "1.10.0",
|
"minSillyTavernVersion": "1.10.0",
|
||||||
|
|||||||
@@ -435,6 +435,10 @@ export function bindModalEvents() {
|
|||||||
bindAmily2ModalWorldBookSettings();
|
bindAmily2ModalWorldBookSettings();
|
||||||
|
|
||||||
const container = $("#amily2_drawer_content").length ? $("#amily2_drawer_content") : $("#amily2_chat_optimiser");
|
const container = $("#amily2_drawer_content").length ? $("#amily2_drawer_content") : $("#amily2_chat_optimiser");
|
||||||
|
const apiConfigButton = container.find('#amily2_open_api_config');
|
||||||
|
if (apiConfigButton.length && !container.find('#amily2_open_rule_config').length) {
|
||||||
|
apiConfigButton.after(' <button id="amily2_open_rule_config" class="menu_button wide_button"><i class="fas fa-list-check"></i> 规则配置</button>');
|
||||||
|
}
|
||||||
|
|
||||||
// Collapsible sections logic
|
// Collapsible sections logic
|
||||||
container.find('.collapsible-legend').each(function() {
|
container.find('.collapsible-legend').each(function() {
|
||||||
@@ -802,7 +806,7 @@ export function bindModalEvents() {
|
|||||||
container
|
container
|
||||||
.off("click.amily2.chamber_nav")
|
.off("click.amily2.chamber_nav")
|
||||||
.on("click.amily2.chamber_nav",
|
.on("click.amily2.chamber_nav",
|
||||||
"#amily2_open_text_optimization, #amily2_open_plot_optimization, #amily2_open_additional_features, #amily2_open_rag_palace, #amily2_open_memorisation_forms, #amily2_open_character_world_book, #amily2_open_world_editor, #amily2_open_glossary, #amily2_open_renderer, #amily2_open_super_memory, #amily2_open_auto_char_card, #amily2_open_api_config, #amily2_open_sfigen, #amily2_back_to_main_settings, #amily2_back_to_main_from_hanlinyuan, #amily2_back_to_main_from_forms, #amily2_back_to_main_from_optimization, #amily2_back_to_main_from_text_optimization, #amily2_back_to_main_from_cwb, #amily2_back_to_main_from_world_editor, #amily2_back_to_main_from_glossary, #amily2_renderer_back_button, #amily2_back_to_main_from_super_memory, #amily2_back_to_main_from_api_config, #amily2_sfigen_back_to_main", function () {
|
"#amily2_open_text_optimization, #amily2_open_plot_optimization, #amily2_open_additional_features, #amily2_open_rag_palace, #amily2_open_memorisation_forms, #amily2_open_character_world_book, #amily2_open_world_editor, #amily2_open_glossary, #amily2_open_renderer, #amily2_open_super_memory, #amily2_open_auto_char_card, #amily2_open_api_config, #amily2_open_rule_config, #amily2_open_sfigen, #amily2_back_to_main_settings, #amily2_back_to_main_from_hanlinyuan, #amily2_back_to_main_from_forms, #amily2_back_to_main_from_optimization, #amily2_back_to_main_from_text_optimization, #amily2_back_to_main_from_cwb, #amily2_back_to_main_from_world_editor, #amily2_back_to_main_from_glossary, #amily2_renderer_back_button, #amily2_back_to_main_from_super_memory, #amily2_back_to_main_from_api_config, #amily2_back_to_main_from_rule_config, #amily2_sfigen_back_to_main", function () {
|
||||||
if (!pluginAuthStatus.authorized) return;
|
if (!pluginAuthStatus.authorized) return;
|
||||||
|
|
||||||
const mainPanel = container.find('.plugin-features');
|
const mainPanel = container.find('.plugin-features');
|
||||||
@@ -817,6 +821,7 @@ export function bindModalEvents() {
|
|||||||
const rendererPanel = container.find('#amily2_renderer_panel');
|
const rendererPanel = container.find('#amily2_renderer_panel');
|
||||||
const superMemoryPanel = container.find('#amily2_super_memory_panel');
|
const superMemoryPanel = container.find('#amily2_super_memory_panel');
|
||||||
const apiConfigPanel = container.find('#amily2_api_config_panel');
|
const apiConfigPanel = container.find('#amily2_api_config_panel');
|
||||||
|
const ruleConfigPanel = container.find('#amily2_rule_config_panel');
|
||||||
const sfigenPanel = container.find('#amily2_sfigen_panel');
|
const sfigenPanel = container.find('#amily2_sfigen_panel');
|
||||||
|
|
||||||
mainPanel.hide();
|
mainPanel.hide();
|
||||||
@@ -831,6 +836,7 @@ export function bindModalEvents() {
|
|||||||
rendererPanel.hide();
|
rendererPanel.hide();
|
||||||
superMemoryPanel.hide();
|
superMemoryPanel.hide();
|
||||||
apiConfigPanel.hide();
|
apiConfigPanel.hide();
|
||||||
|
ruleConfigPanel.hide();
|
||||||
sfigenPanel.hide();
|
sfigenPanel.hide();
|
||||||
|
|
||||||
switch (this.id) {
|
switch (this.id) {
|
||||||
@@ -879,6 +885,9 @@ export function bindModalEvents() {
|
|||||||
case 'amily2_open_api_config':
|
case 'amily2_open_api_config':
|
||||||
apiConfigPanel.show();
|
apiConfigPanel.show();
|
||||||
break;
|
break;
|
||||||
|
case 'amily2_open_rule_config':
|
||||||
|
ruleConfigPanel.show();
|
||||||
|
break;
|
||||||
case 'amily2_open_sfigen':
|
case 'amily2_open_sfigen':
|
||||||
sfigenPanel.show();
|
sfigenPanel.show();
|
||||||
break;
|
break;
|
||||||
@@ -893,6 +902,7 @@ export function bindModalEvents() {
|
|||||||
case 'amily2_renderer_back_button':
|
case 'amily2_renderer_back_button':
|
||||||
case 'amily2_back_to_main_from_super_memory':
|
case 'amily2_back_to_main_from_super_memory':
|
||||||
case 'amily2_back_to_main_from_api_config':
|
case 'amily2_back_to_main_from_api_config':
|
||||||
|
case 'amily2_back_to_main_from_rule_config':
|
||||||
case 'amily2_sfigen_back_to_main':
|
case 'amily2_sfigen_back_to_main':
|
||||||
mainPanel.show();
|
mainPanel.show();
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import * as ContextUtils from '../core/utils/context-utils.js';
|
|||||||
import * as IngestionManager from '../core/ingestion-manager.js';
|
import * as IngestionManager from '../core/ingestion-manager.js';
|
||||||
import { showContentModal, showHtmlModal } from './page-window.js';
|
import { showContentModal, showHtmlModal } from './page-window.js';
|
||||||
import { extractBlocksByTags, applyExclusionRules } from '../core/utils/rag-tag-extractor.js';
|
import { extractBlocksByTags, applyExclusionRules } from '../core/utils/rag-tag-extractor.js';
|
||||||
|
import { ruleProfileManager, resolveCondensationRuleConfig } from '../utils/config/RuleProfileManager.js';
|
||||||
import {
|
import {
|
||||||
filterWorldbooks,
|
filterWorldbooks,
|
||||||
filterWorldbookEntries,
|
filterWorldbookEntries,
|
||||||
@@ -23,6 +24,27 @@ function escapeTextareaContent(text) {
|
|||||||
.replace(/>/g, '>');
|
.replace(/>/g, '>');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function escapeAttribute(text) {
|
||||||
|
return String(text ?? '')
|
||||||
|
.replace(/&/g, '&')
|
||||||
|
.replace(/"/g, '"')
|
||||||
|
.replace(/</g, '<')
|
||||||
|
.replace(/>/g, '>');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function _populateHlyRuleProfileSelect(select, slot) {
|
||||||
|
const profiles = ruleProfileManager.listProfiles();
|
||||||
|
const assigned = ruleProfileManager.getAssignment(slot) || '';
|
||||||
|
select.innerHTML = [
|
||||||
|
'<option value="">— 未分配 —</option>',
|
||||||
|
...profiles.map(p =>
|
||||||
|
`<option value="${p.id}" ${p.id === assigned ? 'selected' : ''}>${escapeTextareaContent(p.name || p.id)}</option>`
|
||||||
|
),
|
||||||
|
].join('');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
function setupGlobalEventHandlers() {
|
function setupGlobalEventHandlers() {
|
||||||
|
|
||||||
window.saveHLYSettings = () => saveSettingsFromUI(false); // false表示非自动保存
|
window.saveHLYSettings = () => saveSettingsFromUI(false); // false表示非自动保存
|
||||||
@@ -53,6 +75,17 @@ function updateAndSaveSetting(key, value) {
|
|||||||
current[keys[keys.length - 1]] = value;
|
current[keys[keys.length - 1]] = value;
|
||||||
|
|
||||||
HanlinyuanCore.saveSettings();
|
HanlinyuanCore.saveSettings();
|
||||||
|
|
||||||
|
if (key === 'condensation.tagExtractionEnabled') {
|
||||||
|
syncHanlinLinkedRuleProfile('condensation', { tagExtractionEnabled: value });
|
||||||
|
} else if (key === 'condensation.tags') {
|
||||||
|
syncHanlinLinkedRuleProfile('condensation', { tags: value });
|
||||||
|
} else if (key === 'queryPreprocessing.tagExtractionEnabled') {
|
||||||
|
syncHanlinLinkedRuleProfile('queryPreprocessing', { tagExtractionEnabled: value });
|
||||||
|
} else if (key === 'queryPreprocessing.tags') {
|
||||||
|
syncHanlinLinkedRuleProfile('queryPreprocessing', { tags: value });
|
||||||
|
}
|
||||||
|
|
||||||
log(`[自动保存] 设置项 '${key}' 已更新为: ${JSON.stringify(value)}`, 'success');
|
log(`[自动保存] 设置项 '${key}' 已更新为: ${JSON.stringify(value)}`, 'success');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -358,18 +391,34 @@ function bindInternalUIEvents() {
|
|||||||
librarySelect.addEventListener('change', handleWorldbookSelectionChange);
|
librarySelect.addEventListener('change', handleWorldbookSelectionChange);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 为规则配置按钮绑定通用弹窗事件
|
// 浓缩 — 提取规则下拉选单
|
||||||
const condensationRulesBtn = document.getElementById('hly-exclusion-rules-btn');
|
const condensationRuleSelect = document.getElementById('hly-condensation-rule-profile-select');
|
||||||
if (condensationRulesBtn) {
|
if (condensationRuleSelect) {
|
||||||
condensationRulesBtn.addEventListener('click', () => showRulesModal('condensation'));
|
_populateHlyRuleProfileSelect(condensationRuleSelect, 'condensation');
|
||||||
|
condensationRuleSelect.addEventListener('change', () => {
|
||||||
|
ruleProfileManager.setAssignment('condensation', condensationRuleSelect.value || null);
|
||||||
|
const name = condensationRuleSelect.selectedOptions[0]?.textContent || '';
|
||||||
|
toastr.info(condensationRuleSelect.value ? `浓缩提取规则已切换为「${name}」` : '浓缩提取规则已取消分配');
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// 为“检索预处理”的配置按钮绑定事件
|
// 查询预处理 — 提取规则下拉选单
|
||||||
const queryPreprocessingBtn = document.getElementById('hly-query-preprocessing-rules-btn');
|
const queryPrepRuleSelect = document.getElementById('hly-query-preprocessing-rule-profile-select');
|
||||||
if (queryPreprocessingBtn) {
|
if (queryPrepRuleSelect) {
|
||||||
queryPreprocessingBtn.addEventListener('click', () => showRulesModal('queryPreprocessing'));
|
_populateHlyRuleProfileSelect(queryPrepRuleSelect, 'queryPreprocessing');
|
||||||
|
queryPrepRuleSelect.addEventListener('change', () => {
|
||||||
|
ruleProfileManager.setAssignment('queryPreprocessing', queryPrepRuleSelect.value || null);
|
||||||
|
const name = queryPrepRuleSelect.selectedOptions[0]?.textContent || '';
|
||||||
|
toastr.info(queryPrepRuleSelect.value ? `查询预处理规则已切换为「${name}」` : '查询预处理规则已取消分配');
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 规则配置中心保存/删除后自动刷新翰林院下拉选单
|
||||||
|
document.addEventListener('amily2:ruleProfilesChanged', () => {
|
||||||
|
if (condensationRuleSelect) _populateHlyRuleProfileSelect(condensationRuleSelect, 'condensation');
|
||||||
|
if (queryPrepRuleSelect) _populateHlyRuleProfileSelect(queryPrepRuleSelect, 'queryPreprocessing');
|
||||||
|
});
|
||||||
|
|
||||||
// 为自定义多选下拉框绑定事件
|
// 为自定义多选下拉框绑定事件
|
||||||
const multiSelectBtn = document.getElementById('hly-hist-entry-multiselect-btn');
|
const multiSelectBtn = document.getElementById('hly-hist-entry-multiselect-btn');
|
||||||
const optionsContainer = document.getElementById('hly-hist-entry-multiselect-options');
|
const optionsContainer = document.getElementById('hly-hist-entry-multiselect-options');
|
||||||
@@ -1570,134 +1619,20 @@ API端点: ${settings.retrieval.apiEndpoint}
|
|||||||
log(`查询宝库状态失败: ${error.message}`, 'error');
|
log(`查询宝库状态失败: ${error.message}`, 'error');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function showRulesModal(type) {
|
|
||||||
const settings = HanlinyuanCore.getSettings();
|
|
||||||
const config = settings[type];
|
|
||||||
if (!config) {
|
|
||||||
console.error(`[翰林院-枢纽] 未找到类型为 "${type}" 的配置项。`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const title = type === 'condensation' ? '编辑凝识内容排除规则' : '编辑检索内容排除规则';
|
|
||||||
const rules = config.exclusionRules || [];
|
|
||||||
|
|
||||||
const createRuleRowHtml = (rule = { start: '', end: '' }, index) => `
|
|
||||||
<div class="hly-exclusion-rule-row" data-index="${index}">
|
|
||||||
<input type="text" class="hly-imperial-brush" value="${(rule.start || '').replace(/"/g, '"')}" placeholder="开始字符串, 如 <!--">
|
|
||||||
<span style="margin: 0 5px;">到</span>
|
|
||||||
<input type="text" class="hly-imperial-brush" value="${(rule.end || '').replace(/"/g, '"')}" placeholder="结束字符串, 如 -->">
|
|
||||||
<button class="hly-delete-rule-btn" title="删除此规则">×</button>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
|
|
||||||
const rulesHtml = rules.map(createRuleRowHtml).join('');
|
|
||||||
|
|
||||||
// 标签提取部分只在“检索预处理”设置中显示
|
|
||||||
const tagExtractionFieldset = type === 'queryPreprocessing' ? `
|
|
||||||
<fieldset class="hly-settings-group">
|
|
||||||
<legend><i class="fas fa-tags"></i> 标签提取</legend>
|
|
||||||
<div class="hly-control-block" style="flex-direction: row; justify-content: space-between; align-items: center;">
|
|
||||||
<label for="hly-modal-tag-extraction-enabled">启用标签提取</label>
|
|
||||||
<label class="hly-toggle-switch">
|
|
||||||
<input type="checkbox" id="hly-modal-tag-extraction-enabled" ${config.tagExtractionEnabled ? 'checked' : ''}>
|
|
||||||
<span class="slider"></span>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
<div id="hly-modal-tag-input-container" class="hly-control-block" style="display: ${config.tagExtractionEnabled ? 'block' : 'none'};">
|
|
||||||
<label for="hly-modal-tag-input">输入标签 (以逗号分隔):</label>
|
|
||||||
<textarea id="hly-modal-tag-input" class="hly-imperial-brush" rows="2" placeholder="例如: content,details,摘要">${config.tags || ''}</textarea>
|
|
||||||
</div>
|
|
||||||
</fieldset>
|
|
||||||
` : '';
|
|
||||||
|
|
||||||
const modalHtml = `
|
|
||||||
<div id="hly-rules-modal-container">
|
|
||||||
${tagExtractionFieldset}
|
|
||||||
<fieldset class="hly-settings-group">
|
|
||||||
<legend><i class="fas fa-ban"></i> 内容排除规则</legend>
|
|
||||||
<p class="hly-notes">在这里定义需要从提取内容中排除的文本片段。例如,排除HTML注释,可以设置开始字符串为 \`<!--\`,结束字符串为 \`-->\`。</p>
|
|
||||||
<div id="hly-rules-list">${rulesHtml.length > 0 ? rulesHtml : '<p class="hly-notes" style="text-align:center;">暂无规则</p>'}</div>
|
|
||||||
<button id="hly-add-rule-btn" class="hly-action-button" style="margin-top: 10px;">
|
|
||||||
<i class="fas fa-plus"></i> 添加新规则
|
|
||||||
</button>
|
|
||||||
</fieldset>
|
|
||||||
</div>
|
|
||||||
<style>
|
|
||||||
.hly-exclusion-rule-row { display: flex; align-items: center; gap: 10px; margin-bottom: 10px; }
|
|
||||||
.hly-exclusion-rule-row input { flex-grow: 1; }
|
|
||||||
.hly-delete-rule-btn { background: #c0392b; color: white; border: none; border-radius: 50%; width: 24px; height: 24px; cursor: pointer; font-size: 16px; line-height: 24px; text-align: center; padding: 0; flex-shrink: 0; }
|
|
||||||
</style>
|
|
||||||
`;
|
|
||||||
|
|
||||||
showHtmlModal(title, modalHtml, {
|
|
||||||
okText: '保存规则',
|
|
||||||
onOk: (dialogElement) => {
|
|
||||||
const newRules = [];
|
|
||||||
dialogElement.find('.hly-exclusion-rule-row').each(function () {
|
|
||||||
const start = $(this).find('input').eq(0).val().trim();
|
|
||||||
const end = $(this).find('input').eq(1).val().trim();
|
|
||||||
// 规则必须至少有一个开始字符串
|
|
||||||
if (start) {
|
|
||||||
newRules.push({ start, end });
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const newConfig = { ...config, exclusionRules: newRules };
|
|
||||||
|
|
||||||
// 如果是检索预处理设置,则同时保存标签提取的设置
|
|
||||||
if (type === 'queryPreprocessing') {
|
|
||||||
newConfig.tagExtractionEnabled = dialogElement.find('#hly-modal-tag-extraction-enabled').is(':checked');
|
|
||||||
newConfig.tags = dialogElement.find('#hly-modal-tag-input').val();
|
|
||||||
}
|
|
||||||
|
|
||||||
updateAndSaveSetting(type, newConfig);
|
|
||||||
toastr.success('规则已保存。', '圣旨已达');
|
|
||||||
},
|
|
||||||
onShow: (dialogElement) => {
|
|
||||||
const rulesList = dialogElement.find('#hly-rules-list');
|
|
||||||
|
|
||||||
dialogElement.find('#hly-add-rule-btn').on('click', () => {
|
|
||||||
const newIndex = rulesList.children('.hly-exclusion-rule-row').length;
|
|
||||||
const newRowHtml = createRuleRowHtml(undefined, newIndex);
|
|
||||||
if (rulesList.find('p').length > 0) {
|
|
||||||
rulesList.html(newRowHtml);
|
|
||||||
} else {
|
|
||||||
rulesList.append(newRowHtml);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
rulesList.on('click', '.hly-delete-rule-btn', function () {
|
|
||||||
$(this).closest('.hly-exclusion-rule-row').remove();
|
|
||||||
if (rulesList.children().length === 0) {
|
|
||||||
rulesList.html('<p class="hly-notes" style="text-align:center;">暂无规则</p>');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// 如果是检索预处理设置,则绑定标签提取的UI事件
|
|
||||||
if (type === 'queryPreprocessing') {
|
|
||||||
const tagToggle = dialogElement.find('#hly-modal-tag-extraction-enabled');
|
|
||||||
const tagInputContainer = dialogElement.find('#hly-modal-tag-input-container');
|
|
||||||
tagToggle.on('change', () => {
|
|
||||||
tagInputContainer.css('display', tagToggle.is(':checked') ? 'block' : 'none');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function previewCondensation() {
|
function previewCondensation() {
|
||||||
const resultsEl = document.getElementById('hly-condensation-results');
|
const resultsEl = document.getElementById('hly-condensation-results');
|
||||||
try {
|
try {
|
||||||
// 1. 获取UI设置和新规则
|
// 1. 获取UI设置和新规则
|
||||||
const settings = HanlinyuanCore.getSettings();
|
const settings = HanlinyuanCore.getSettings();
|
||||||
const exclusionRules = settings.condensation.exclusionRules || [];
|
const condensationRuleConfig = resolveCondensationRuleConfig(settings);
|
||||||
|
const exclusionRules = condensationRuleConfig.exclusionRules || [];
|
||||||
const overrideMessageTypes = {
|
const overrideMessageTypes = {
|
||||||
user: document.getElementById('hly-include-user').checked,
|
user: document.getElementById('hly-include-user').checked,
|
||||||
ai: document.getElementById('hly-include-ai').checked,
|
ai: document.getElementById('hly-include-ai').checked,
|
||||||
};
|
};
|
||||||
const useTagExtraction = document.getElementById('hly-tag-extraction-toggle').checked;
|
const useTagExtraction = condensationRuleConfig.tagExtractionEnabled;
|
||||||
const tagsToExtract = useTagExtraction
|
const tagsToExtract = useTagExtraction
|
||||||
? document.getElementById('hly-tag-input').value.split(',').map(t => t.trim()).filter(Boolean)
|
? (condensationRuleConfig.tags || '').split(',').map(t => t.trim()).filter(Boolean)
|
||||||
: [];
|
: [];
|
||||||
|
|
||||||
// 2. 获取原始消息
|
// 2. 获取原始消息
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ import {
|
|||||||
saveSettings,
|
saveSettings,
|
||||||
} from "../utils/settings.js";
|
} from "../utils/settings.js";
|
||||||
import { showHtmlModal } from './page-window.js';
|
import { showHtmlModal } from './page-window.js';
|
||||||
import { applyExclusionRules, extractBlocksByTags } from '../core/utils/rag-tag-extractor.js';
|
|
||||||
import { configManager } from '../utils/config/ConfigManager.js';
|
import { configManager } from '../utils/config/ConfigManager.js';
|
||||||
|
import { ruleProfileManager, resolveHistoriographyRuleConfig } from '../utils/config/RuleProfileManager.js';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
getAvailableWorldbooks, getLoresForWorldbook,
|
getAvailableWorldbooks, getLoresForWorldbook,
|
||||||
@@ -17,6 +17,25 @@ import {
|
|||||||
|
|
||||||
import { getNgmsApiSettings, testNgmsApiConnection, fetchNgmsModels } from "../core/api/Ngms_api.js";
|
import { getNgmsApiSettings, testNgmsApiConnection, fetchNgmsModels } from "../core/api/Ngms_api.js";
|
||||||
|
|
||||||
|
function getHistoriographyRuleConfig() {
|
||||||
|
return resolveHistoriographyRuleConfig(extension_settings[extensionName] || {});
|
||||||
|
}
|
||||||
|
|
||||||
|
function _escapeHtml(text) {
|
||||||
|
return String(text ?? '').replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"');
|
||||||
|
}
|
||||||
|
|
||||||
|
function _populateHistRuleProfileSelect(select) {
|
||||||
|
const profiles = ruleProfileManager.listProfiles();
|
||||||
|
const assigned = ruleProfileManager.getAssignment('historiography') || '';
|
||||||
|
select.innerHTML = [
|
||||||
|
'<option value="">— 未分配 —</option>',
|
||||||
|
...profiles.map(p =>
|
||||||
|
`<option value="${p.id}" ${p.id === assigned ? 'selected' : ''}>${_escapeHtml(p.name || p.id)}</option>`
|
||||||
|
),
|
||||||
|
].join('');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
function setupPromptEditor(type) {
|
function setupPromptEditor(type) {
|
||||||
const selector = document.getElementById(
|
const selector = document.getElementById(
|
||||||
@@ -199,29 +218,19 @@ export function bindHistoriographyEvents() {
|
|||||||
saveSettings();
|
saveSettings();
|
||||||
});
|
});
|
||||||
|
|
||||||
// ========== 🏷️ 标签与排除规则绑定 (新增) ==========
|
// ========== 提取规则下拉选单 ==========
|
||||||
const tagExtractionToggle = document.getElementById("historiography-tag-extraction-toggle");
|
const histRuleSelect = document.getElementById("historiography-rule-profile-select");
|
||||||
const tagInputContainer = document.getElementById("historiography-tag-input-container");
|
if (histRuleSelect) {
|
||||||
const tagInput = document.getElementById("historiography-tag-input");
|
_populateHistRuleProfileSelect(histRuleSelect);
|
||||||
const exclusionRulesBtn = document.getElementById("historiography-exclusion-rules-btn");
|
histRuleSelect.addEventListener("change", () => {
|
||||||
|
ruleProfileManager.setAssignment('historiography', histRuleSelect.value || null);
|
||||||
tagExtractionToggle.checked = extension_settings[extensionName].historiographyTagExtractionEnabled ?? false;
|
const name = histRuleSelect.selectedOptions[0]?.textContent || '';
|
||||||
tagInput.value = extension_settings[extensionName].historiographyTags ?? '';
|
toastr.info(histRuleSelect.value ? `史官提取规则已切换为「${name}」` : '史官提取规则已取消分配');
|
||||||
tagInputContainer.style.display = tagExtractionToggle.checked ? 'block' : 'none';
|
});
|
||||||
|
document.addEventListener('amily2:ruleProfilesChanged', () => {
|
||||||
tagExtractionToggle.addEventListener("change", (event) => {
|
_populateHistRuleProfileSelect(histRuleSelect);
|
||||||
const isEnabled = event.target.checked;
|
});
|
||||||
extension_settings[extensionName].historiographyTagExtractionEnabled = isEnabled;
|
}
|
||||||
tagInputContainer.style.display = isEnabled ? 'block' : 'none';
|
|
||||||
saveSettings();
|
|
||||||
});
|
|
||||||
|
|
||||||
tagInput.addEventListener("change", (event) => {
|
|
||||||
extension_settings[extensionName].historiographyTags = event.target.value;
|
|
||||||
saveSettings();
|
|
||||||
});
|
|
||||||
|
|
||||||
exclusionRulesBtn.addEventListener("click", showHistoriographyExclusionRulesModal);
|
|
||||||
|
|
||||||
|
|
||||||
const expeditionExecuteBtn = document.getElementById("amily2_mhb_small_expedition_execute");
|
const expeditionExecuteBtn = document.getElementById("amily2_mhb_small_expedition_execute");
|
||||||
@@ -616,62 +625,3 @@ async function loadNgmsTavernPresets() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function showHistoriographyExclusionRulesModal() {
|
|
||||||
const rules = extension_settings[extensionName].historiographyExclusionRules || [];
|
|
||||||
|
|
||||||
const createRuleRowHtml = (rule = { start: '', end: '' }, index) => `
|
|
||||||
<div class="hly-exclusion-rule-row" data-index="${index}">
|
|
||||||
<input type="text" class="hly-imperial-brush" value="${rule.start}" placeholder="开始字符, 如 <!--">
|
|
||||||
<span>到</span>
|
|
||||||
<input type="text" class="hly-imperial-brush" value="${rule.end}" placeholder="结束字符, 如 -->">
|
|
||||||
<button class="hly-delete-rule-btn" title="删除此规则">×</button>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
|
|
||||||
const rulesHtml = rules.map(createRuleRowHtml).join('');
|
|
||||||
|
|
||||||
const modalHtml = `
|
|
||||||
<div id="historiography-exclusion-rules-container">
|
|
||||||
<p class="hly-notes">在这里定义需要从提取内容中排除的文本片段。例如,排除HTML注释,可以设置开始字符为 \`<!--\`,结束字符为 \`-->\`。</p>
|
|
||||||
<div id="historiography-rules-list">${rulesHtml}</div>
|
|
||||||
<button id="historiography-add-rule-btn" class="hly-action-button" style="margin-top: 10px;">
|
|
||||||
<i class="fas fa-plus"></i> 添加新规则
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<style>
|
|
||||||
.hly-exclusion-rule-row { display: flex; align-items: center; gap: 10px; margin-bottom: 10px; }
|
|
||||||
.hly-exclusion-rule-row input { flex-grow: 1; }
|
|
||||||
.hly-delete-rule-btn { background: #c0392b; color: white; border: none; border-radius: 50%; width: 24px; height: 24px; cursor: pointer; font-size: 16px; line-height: 24px; text-align: center; padding: 0; }
|
|
||||||
</style>
|
|
||||||
`;
|
|
||||||
|
|
||||||
showHtmlModal('编辑内容排除规则', modalHtml, {
|
|
||||||
okText: '保存规则',
|
|
||||||
onOk: (dialogElement) => {
|
|
||||||
const newRules = [];
|
|
||||||
dialogElement.find('.hly-exclusion-rule-row').each(function() {
|
|
||||||
const start = $(this).find('input').eq(0).val().trim();
|
|
||||||
const end = $(this).find('input').eq(1).val().trim();
|
|
||||||
if (start && end) {
|
|
||||||
newRules.push({ start, end });
|
|
||||||
}
|
|
||||||
});
|
|
||||||
extension_settings[extensionName].historiographyExclusionRules = newRules;
|
|
||||||
saveSettings();
|
|
||||||
toastr.success('内容排除规则已保存。', '圣旨已达');
|
|
||||||
},
|
|
||||||
onShow: (dialogElement) => {
|
|
||||||
const rulesList = dialogElement.find('#historiography-rules-list');
|
|
||||||
|
|
||||||
dialogElement.find('#historiography-add-rule-btn').on('click', () => {
|
|
||||||
const newIndex = rulesList.children().length;
|
|
||||||
const newRowHtml = createRuleRowHtml({ start: '', end: '' }, newIndex);
|
|
||||||
rulesList.append(newRowHtml);
|
|
||||||
});
|
|
||||||
|
|
||||||
rulesList.on('click', '.hly-delete-rule-btn', function() {
|
|
||||||
$(this).closest('.hly-exclusion-rule-row').remove();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|||||||
151
ui/rule-config-bindings.js
Normal file
151
ui/rule-config-bindings.js
Normal file
@@ -0,0 +1,151 @@
|
|||||||
|
import { ruleProfileManager } from '../utils/config/RuleProfileManager.js';
|
||||||
|
|
||||||
|
let currentEditingId = null;
|
||||||
|
|
||||||
|
function createEmptyProfile() {
|
||||||
|
return {
|
||||||
|
id: '',
|
||||||
|
name: '',
|
||||||
|
tagExtractionEnabled: false,
|
||||||
|
tags: '',
|
||||||
|
exclusionRules: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function createRuleRow(rule = { start: '', end: '' }, index = 0) {
|
||||||
|
return `
|
||||||
|
<div class="amily2-rule-row" data-index="${index}">
|
||||||
|
<input type="text" class="text_pole amily2-rule-start" value="${escapeHtml(rule.start || '')}" placeholder="起始标记">
|
||||||
|
<input type="text" class="text_pole amily2-rule-end" value="${escapeHtml(rule.end || '')}" placeholder="结束标记">
|
||||||
|
<button type="button" class="menu_button danger small_button amily2-rule-remove">
|
||||||
|
<i class="fas fa-trash-alt"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function escapeHtml(text) {
|
||||||
|
return String(text ?? '')
|
||||||
|
.replace(/&/g, '&')
|
||||||
|
.replace(/</g, '<')
|
||||||
|
.replace(/>/g, '>')
|
||||||
|
.replace(/"/g, '"');
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderRules(container, exclusionRules = []) {
|
||||||
|
const list = container.find('#amily2_rule_profile_rules');
|
||||||
|
if (!exclusionRules.length) {
|
||||||
|
list.html('<p class="notes">当前没有排除规则。</p>');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
list.html(exclusionRules.map((rule, index) => createRuleRow(rule, index)).join(''));
|
||||||
|
}
|
||||||
|
|
||||||
|
function collectProfile(container) {
|
||||||
|
const exclusionRules = [];
|
||||||
|
container.find('.amily2-rule-row').each(function () {
|
||||||
|
const start = $(this).find('.amily2-rule-start').val().trim();
|
||||||
|
const end = $(this).find('.amily2-rule-end').val().trim();
|
||||||
|
if (start) {
|
||||||
|
exclusionRules.push({ start, end });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: currentEditingId || '',
|
||||||
|
name: container.find('#amily2_rule_profile_name').val().trim(),
|
||||||
|
tagExtractionEnabled: container.find('#amily2_rule_profile_tag_toggle').is(':checked'),
|
||||||
|
tags: container.find('#amily2_rule_profile_tags').val(),
|
||||||
|
exclusionRules,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderProfileList(container) {
|
||||||
|
const list = container.find('#amily2_rule_profile_list');
|
||||||
|
const profiles = ruleProfileManager.listProfiles();
|
||||||
|
|
||||||
|
if (!profiles.length) {
|
||||||
|
list.html('<p class="notes">还没有规则配置。</p>');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
list.html(profiles.map(profile => `
|
||||||
|
<button type="button" class="menu_button wide_button amily2-rule-profile-item" data-id="${profile.id}">
|
||||||
|
<span>${escapeHtml(profile.name || profile.id)}</span>
|
||||||
|
</button>
|
||||||
|
`).join(''));
|
||||||
|
}
|
||||||
|
|
||||||
|
function fillEditor(container, profile) {
|
||||||
|
const current = profile || createEmptyProfile();
|
||||||
|
currentEditingId = current.id || null;
|
||||||
|
container.find('#amily2_rule_profile_name').val(current.name || '');
|
||||||
|
container.find('#amily2_rule_profile_tag_toggle').prop('checked', !!current.tagExtractionEnabled);
|
||||||
|
container.find('#amily2_rule_profile_tags').val(current.tags || '');
|
||||||
|
container.find('#amily2_rule_profile_tags_wrap').toggle(!!current.tagExtractionEnabled);
|
||||||
|
renderRules(container, current.exclusionRules || []);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function bindRuleConfigPanel(container) {
|
||||||
|
const $c = $(container);
|
||||||
|
|
||||||
|
renderProfileList($c);
|
||||||
|
fillEditor($c, createEmptyProfile());
|
||||||
|
|
||||||
|
$c.off('.ruleConfig');
|
||||||
|
|
||||||
|
$c.on('click.ruleConfig', '#amily2_rule_profile_new', () => {
|
||||||
|
fillEditor($c, createEmptyProfile());
|
||||||
|
});
|
||||||
|
|
||||||
|
$c.on('click.ruleConfig', '.amily2-rule-profile-item', function () {
|
||||||
|
const profile = ruleProfileManager.getProfile($(this).data('id'));
|
||||||
|
if (profile) {
|
||||||
|
fillEditor($c, profile);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$c.on('change.ruleConfig', '#amily2_rule_profile_tag_toggle', function () {
|
||||||
|
$c.find('#amily2_rule_profile_tags_wrap').toggle(this.checked);
|
||||||
|
});
|
||||||
|
|
||||||
|
$c.on('click.ruleConfig', '#amily2_rule_profile_add_rule', () => {
|
||||||
|
const rules = collectProfile($c).exclusionRules;
|
||||||
|
rules.push({ start: '', end: '' });
|
||||||
|
renderRules($c, rules);
|
||||||
|
});
|
||||||
|
|
||||||
|
$c.on('click.ruleConfig', '.amily2-rule-remove', function () {
|
||||||
|
$(this).closest('.amily2-rule-row').remove();
|
||||||
|
if ($c.find('.amily2-rule-row').length === 0) {
|
||||||
|
renderRules($c, []);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$c.on('click.ruleConfig', '#amily2_rule_profile_save', () => {
|
||||||
|
const profile = collectProfile($c);
|
||||||
|
if (!profile.name) {
|
||||||
|
toastr.warning('请先填写规则配置名称。');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const saved = ruleProfileManager.saveProfile(profile);
|
||||||
|
fillEditor($c, saved);
|
||||||
|
renderProfileList($c);
|
||||||
|
document.dispatchEvent(new CustomEvent('amily2:ruleProfilesChanged'));
|
||||||
|
toastr.success('规则配置已保存。');
|
||||||
|
});
|
||||||
|
|
||||||
|
$c.on('click.ruleConfig', '#amily2_rule_profile_delete', () => {
|
||||||
|
if (!currentEditingId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!confirm('删除当前规则配置?引用它的位置会回退到旧配置。')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ruleProfileManager.deleteProfile(currentEditingId);
|
||||||
|
fillEditor($c, createEmptyProfile());
|
||||||
|
renderProfileList($c);
|
||||||
|
document.dispatchEvent(new CustomEvent('amily2:ruleProfilesChanged'));
|
||||||
|
toastr.success('规则配置已删除。');
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -14,6 +14,7 @@ import { fetchNccsModels, testNccsApiConnection } from '../core/api/NccsApi.js';
|
|||||||
import { showGraphVisualization } from '../core/relationship-graph/visualizer.js';
|
import { showGraphVisualization } from '../core/relationship-graph/visualizer.js';
|
||||||
import { escapeHTML } from '../utils/utils.js';
|
import { escapeHTML } from '../utils/utils.js';
|
||||||
import { configManager } from '../utils/config/ConfigManager.js';
|
import { configManager } from '../utils/config/ConfigManager.js';
|
||||||
|
import { ruleProfileManager } from '../utils/config/RuleProfileManager.js';
|
||||||
import { bindTableTemplateEditors } from './table/template-bindings.js';
|
import { bindTableTemplateEditors } from './table/template-bindings.js';
|
||||||
import { bindNccsApiEvents as bindNccsApiSettingsEvents } from './table/nccs-bindings.js';
|
import { bindNccsApiEvents as bindNccsApiSettingsEvents } from './table/nccs-bindings.js';
|
||||||
import { bindChatTableDisplaySetting as bindChatTableDisplaySettings } from './table/chat-display-bindings.js';
|
import { bindChatTableDisplaySetting as bindChatTableDisplaySettings } from './table/chat-display-bindings.js';
|
||||||
@@ -21,6 +22,23 @@ import { bindChatTableDisplaySetting as bindChatTableDisplaySettings } from './t
|
|||||||
const isTouchDevice = () => window.matchMedia('(pointer: coarse)').matches;
|
const isTouchDevice = () => window.matchMedia('(pointer: coarse)').matches;
|
||||||
const getAllTablesContainer = () => document.getElementById('all-tables-container');
|
const getAllTablesContainer = () => document.getElementById('all-tables-container');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通用:填充规则配置下拉选单
|
||||||
|
* @param {HTMLSelectElement} select
|
||||||
|
* @param {string} slot — RULE_SLOTS 中的功能槽名
|
||||||
|
*/
|
||||||
|
function _populateRuleProfileSelect(select, slot) {
|
||||||
|
const profiles = ruleProfileManager.listProfiles();
|
||||||
|
const assigned = ruleProfileManager.getAssignment(slot) || '';
|
||||||
|
const options = [
|
||||||
|
'<option value="">— 未分配 —</option>',
|
||||||
|
...profiles.map(p =>
|
||||||
|
`<option value="${p.id}" ${p.id === assigned ? 'selected' : ''}>${escapeHTML(p.name || p.id)}</option>`
|
||||||
|
),
|
||||||
|
];
|
||||||
|
select.innerHTML = options.join('');
|
||||||
|
}
|
||||||
|
|
||||||
function getLiveExtensionSettings() {
|
function getLiveExtensionSettings() {
|
||||||
if (!extension_settings[extensionName]) {
|
if (!extension_settings[extensionName]) {
|
||||||
extension_settings[extensionName] = {};
|
extension_settings[extensionName] = {};
|
||||||
@@ -782,73 +800,6 @@ export function renderTables() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function openTableRuleEditor() {
|
|
||||||
const settings = getLiveExtensionSettings();
|
|
||||||
const tags = settings.table_tags_to_extract || '';
|
|
||||||
const exclusionRules = settings.table_exclusion_rules || [];
|
|
||||||
|
|
||||||
const rulesHtml = exclusionRules.map((rule, index) => `
|
|
||||||
<div class="exclusion-rule-item" data-index="${index}">
|
|
||||||
<input type="text" class="text_pole rule-start" value="${rule.start}" placeholder="起始标记">
|
|
||||||
<span>-</span>
|
|
||||||
<input type="text" class="text_pole rule-end" value="${rule.end}" placeholder="结束标记">
|
|
||||||
<button class="menu_button danger small_button remove-rule-btn"><i class="fas fa-trash-alt"></i></button>
|
|
||||||
</div>
|
|
||||||
`).join('');
|
|
||||||
|
|
||||||
const modalHtml = `
|
|
||||||
<div id="table-rules-editor" style="display: flex; flex-direction: column; gap: 20px;">
|
|
||||||
<div>
|
|
||||||
<label for="table-tags-input"><b>标签提取 (半角逗号分隔)</b></label>
|
|
||||||
<input type="text" id="table-tags-input" class="text_pole" value="${tags}" placeholder="例如: content,game,time">
|
|
||||||
<small class="notes">仅提取指定XML标签的内容,例如填“content”,即提取<content>...</content>中的内容。</small>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label><b>内容排除规则</b></label>
|
|
||||||
<div id="exclusion-rules-list" style="display: flex; flex-direction: column; gap: 8px; margin-top: 8px;">${rulesHtml}</div>
|
|
||||||
<button id="add-exclusion-rule-btn" class="menu_button small_button" style="margin-top: 10px;"><i class="fas fa-plus"></i> 添加规则</button>
|
|
||||||
<small class="notes">移除所有被起始和结束标记包裹的内容(例如 OOC 部分)。</small>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
|
|
||||||
const dialog = showHtmlModal('配置独立提取规则', modalHtml, {
|
|
||||||
onOk: () => {
|
|
||||||
const newTags = document.getElementById('table-tags-input').value;
|
|
||||||
updateAndSaveTableSetting('table_tags_to_extract', newTags);
|
|
||||||
|
|
||||||
const newExclusionRules = [];
|
|
||||||
document.querySelectorAll('#exclusion-rules-list .exclusion-rule-item').forEach(item => {
|
|
||||||
const start = item.querySelector('.rule-start').value.trim();
|
|
||||||
const end = item.querySelector('.rule-end').value.trim();
|
|
||||||
if (start && end) {
|
|
||||||
newExclusionRules.push({ start, end });
|
|
||||||
}
|
|
||||||
});
|
|
||||||
updateAndSaveTableSetting('table_exclusion_rules', newExclusionRules);
|
|
||||||
toastr.success('独立提取规则已保存。');
|
|
||||||
},
|
|
||||||
onShow: (dialogElement) => {
|
|
||||||
const rulesList = dialogElement.find('#exclusion-rules-list');
|
|
||||||
|
|
||||||
dialogElement.find('#add-exclusion-rule-btn').on('click', () => {
|
|
||||||
const newIndex = rulesList.children().length;
|
|
||||||
const newItemHtml = `
|
|
||||||
<div class="exclusion-rule-item" data-index="${newIndex}">
|
|
||||||
<input type="text" class="text_pole rule-start" value="" placeholder="起始标记">
|
|
||||||
<span>-</span>
|
|
||||||
<input type="text" class="text_pole rule-end" value="" placeholder="结束标记">
|
|
||||||
<button class="menu_button danger small_button remove-rule-btn"><i class="fas fa-trash-alt"></i></button>
|
|
||||||
</div>`;
|
|
||||||
rulesList.append(newItemHtml);
|
|
||||||
});
|
|
||||||
|
|
||||||
rulesList.on('click', '.remove-rule-btn', function() {
|
|
||||||
$(this).closest('.exclusion-rule-item').remove();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function openRuleEditor(tableIndex) {
|
function openRuleEditor(tableIndex) {
|
||||||
const tables = TableManager.getMemoryState();
|
const tables = TableManager.getMemoryState();
|
||||||
@@ -1421,9 +1372,7 @@ export function bindTableEvents(panelElement = null) {
|
|||||||
const bufferSlider = document.getElementById('secondary-filler-buffer');
|
const bufferSlider = document.getElementById('secondary-filler-buffer');
|
||||||
const maxRetriesSlider = document.getElementById('secondary-filler-max-retries'); // 【新增】
|
const maxRetriesSlider = document.getElementById('secondary-filler-max-retries'); // 【新增】
|
||||||
|
|
||||||
const independentRulesContainer = document.getElementById('table-independent-rules-container');
|
const tableRuleProfileSelect = document.getElementById('table-rule-profile-select');
|
||||||
const independentRulesToggle = document.getElementById('table-independent-rules-enabled');
|
|
||||||
const configureRulesBtn = document.getElementById('table-configure-rules-btn');
|
|
||||||
|
|
||||||
const updateFillingModeUI = () => {
|
const updateFillingModeUI = () => {
|
||||||
const currentMode = extension_settings[extensionName]?.filling_mode || 'main-api';
|
const currentMode = extension_settings[extensionName]?.filling_mode || 'main-api';
|
||||||
@@ -1437,12 +1386,8 @@ export function bindTableEvents(panelElement = null) {
|
|||||||
secondaryFillerControls.style.display = isSecondaryMode ? 'block' : 'none';
|
secondaryFillerControls.style.display = isSecondaryMode ? 'block' : 'none';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (independentRulesContainer) {
|
if (tableRuleProfileSelect) {
|
||||||
independentRulesContainer.style.display = 'flex';
|
_populateRuleProfileSelect(tableRuleProfileSelect, 'table');
|
||||||
}
|
|
||||||
|
|
||||||
if (independentRulesToggle && configureRulesBtn) {
|
|
||||||
configureRulesBtn.style.display = independentRulesToggle.checked ? 'block' : 'none';
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1500,18 +1445,18 @@ export function bindTableEvents(panelElement = null) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (independentRulesToggle) {
|
|
||||||
independentRulesToggle.checked = extension_settings[extensionName]?.table_independent_rules_enabled ?? false;
|
|
||||||
independentRulesToggle.addEventListener('change', () => {
|
|
||||||
updateAndSaveTableSetting('table_independent_rules_enabled', independentRulesToggle.checked);
|
|
||||||
updateFillingModeUI();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
updateFillingModeUI();
|
updateFillingModeUI();
|
||||||
|
|
||||||
if (configureRulesBtn) {
|
if (tableRuleProfileSelect) {
|
||||||
configureRulesBtn.addEventListener('click', openTableRuleEditor);
|
_populateRuleProfileSelect(tableRuleProfileSelect, 'table');
|
||||||
|
tableRuleProfileSelect.addEventListener('change', () => {
|
||||||
|
ruleProfileManager.setAssignment('table', tableRuleProfileSelect.value || null);
|
||||||
|
const name = tableRuleProfileSelect.selectedOptions[0]?.textContent || '';
|
||||||
|
toastr.info(tableRuleProfileSelect.value ? `表格提取规则已切换为「${name}」` : '表格提取规则已取消分配');
|
||||||
|
});
|
||||||
|
document.addEventListener('amily2:ruleProfilesChanged', () => {
|
||||||
|
_populateRuleProfileSelect(tableRuleProfileSelect, 'table');
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const renderAll = () => {
|
const renderAll = () => {
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
291
utils/config/RuleProfileManager.js
Normal file
291
utils/config/RuleProfileManager.js
Normal file
@@ -0,0 +1,291 @@
|
|||||||
|
import { extension_settings } from "/scripts/extensions.js";
|
||||||
|
import { saveSettingsDebounced } from "/script.js";
|
||||||
|
import { extensionName } from "../settings.js";
|
||||||
|
|
||||||
|
const RULE_PROFILE_KEY = 'ruleProfiles';
|
||||||
|
const RULE_ASSIGNMENTS_KEY = 'ruleProfileAssignments';
|
||||||
|
|
||||||
|
// ── 功能槽定义 ──────────────────────────────────────────────────────────────────
|
||||||
|
export const RULE_SLOTS = {
|
||||||
|
table: { label: '表格提取规则' },
|
||||||
|
historiography: { label: '史官/总结提取规则' },
|
||||||
|
condensation: { label: '翰林院·浓缩规则' },
|
||||||
|
queryPreprocessing:{ label: '翰林院·查询预处理规则' },
|
||||||
|
};
|
||||||
|
|
||||||
|
function sanitizeRuleProfile(profile = {}) {
|
||||||
|
const exclusionRules = Array.isArray(profile.exclusionRules)
|
||||||
|
? profile.exclusionRules
|
||||||
|
.map(rule => ({
|
||||||
|
start: String(rule?.start ?? '').trim(),
|
||||||
|
end: String(rule?.end ?? '').trim(),
|
||||||
|
}))
|
||||||
|
.filter(rule => rule.start)
|
||||||
|
: [];
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: String(profile.id ?? '').trim(),
|
||||||
|
name: String(profile.name ?? '').trim(),
|
||||||
|
tagExtractionEnabled: Boolean(profile.tagExtractionEnabled),
|
||||||
|
tags: String(profile.tags ?? ''),
|
||||||
|
exclusionRules,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function cloneRuleProfile(profile = {}) {
|
||||||
|
return {
|
||||||
|
id: profile.id || '',
|
||||||
|
name: profile.name || '',
|
||||||
|
tagExtractionEnabled: Boolean(profile.tagExtractionEnabled),
|
||||||
|
tags: profile.tags || '',
|
||||||
|
exclusionRules: Array.isArray(profile.exclusionRules)
|
||||||
|
? profile.exclusionRules.map(rule => ({
|
||||||
|
start: rule.start || '',
|
||||||
|
end: rule.end || '',
|
||||||
|
}))
|
||||||
|
: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function createRuleProfileId(name = 'rule-profile') {
|
||||||
|
const base = String(name || 'rule-profile')
|
||||||
|
.toLowerCase()
|
||||||
|
.replace(/[^a-z0-9]+/g, '-')
|
||||||
|
.replace(/^-+|-+$/g, '') || 'rule-profile';
|
||||||
|
return `${base}-${Date.now().toString(36)}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function ensureSettingsRoot() {
|
||||||
|
if (!extension_settings[extensionName]) {
|
||||||
|
extension_settings[extensionName] = {};
|
||||||
|
}
|
||||||
|
return extension_settings[extensionName];
|
||||||
|
}
|
||||||
|
|
||||||
|
function ensureProfileMap() {
|
||||||
|
const settings = ensureSettingsRoot();
|
||||||
|
if (!settings[RULE_PROFILE_KEY] || typeof settings[RULE_PROFILE_KEY] !== 'object' || Array.isArray(settings[RULE_PROFILE_KEY])) {
|
||||||
|
settings[RULE_PROFILE_KEY] = {};
|
||||||
|
}
|
||||||
|
return settings[RULE_PROFILE_KEY];
|
||||||
|
}
|
||||||
|
|
||||||
|
function ensureAssignments() {
|
||||||
|
const settings = ensureSettingsRoot();
|
||||||
|
if (!settings[RULE_ASSIGNMENTS_KEY] || typeof settings[RULE_ASSIGNMENTS_KEY] !== 'object' || Array.isArray(settings[RULE_ASSIGNMENTS_KEY])) {
|
||||||
|
settings[RULE_ASSIGNMENTS_KEY] = {};
|
||||||
|
}
|
||||||
|
return settings[RULE_ASSIGNMENTS_KEY];
|
||||||
|
}
|
||||||
|
|
||||||
|
function mergeRuleConfig(profile, fallback = {}) {
|
||||||
|
const safeFallback = sanitizeRuleProfile({
|
||||||
|
id: fallback.id,
|
||||||
|
name: fallback.name,
|
||||||
|
tagExtractionEnabled: fallback.tagExtractionEnabled,
|
||||||
|
tags: fallback.tags,
|
||||||
|
exclusionRules: fallback.exclusionRules,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!profile) {
|
||||||
|
return safeFallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: profile.id,
|
||||||
|
name: profile.name,
|
||||||
|
tagExtractionEnabled: profile.tagExtractionEnabled,
|
||||||
|
tags: profile.tags,
|
||||||
|
exclusionRules: cloneRuleProfile(profile).exclusionRules.length > 0
|
||||||
|
? cloneRuleProfile(profile).exclusionRules
|
||||||
|
: safeFallback.exclusionRules,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export class RuleProfileManager {
|
||||||
|
listProfiles() {
|
||||||
|
const profiles = Object.values(ensureProfileMap())
|
||||||
|
.map(profile => cloneRuleProfile(profile))
|
||||||
|
.sort((left, right) => {
|
||||||
|
const leftName = left.name || left.id;
|
||||||
|
const rightName = right.name || right.id;
|
||||||
|
return leftName.localeCompare(rightName, 'zh-Hans-CN');
|
||||||
|
});
|
||||||
|
return profiles;
|
||||||
|
}
|
||||||
|
|
||||||
|
getProfile(id) {
|
||||||
|
if (!id) return null;
|
||||||
|
const profile = ensureProfileMap()[id];
|
||||||
|
return profile ? cloneRuleProfile(profile) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
saveProfile(profile) {
|
||||||
|
const normalized = sanitizeRuleProfile(profile);
|
||||||
|
const profileId = normalized.id || createRuleProfileId(normalized.name);
|
||||||
|
const nextProfile = {
|
||||||
|
...normalized,
|
||||||
|
id: profileId,
|
||||||
|
name: normalized.name || profileId,
|
||||||
|
};
|
||||||
|
|
||||||
|
ensureProfileMap()[profileId] = nextProfile;
|
||||||
|
saveSettingsDebounced();
|
||||||
|
return cloneRuleProfile(nextProfile);
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteProfile(id) {
|
||||||
|
if (!id) return false;
|
||||||
|
const profiles = ensureProfileMap();
|
||||||
|
if (!profiles[id]) return false;
|
||||||
|
delete profiles[id];
|
||||||
|
saveSettingsDebounced();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
resolveProfile(id, fallback = {}) {
|
||||||
|
return mergeRuleConfig(this.getProfile(id), fallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── 功能槽分配 ──────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
getAssignment(slot) {
|
||||||
|
if (!RULE_SLOTS[slot]) return null;
|
||||||
|
return ensureAssignments()[slot] || null;
|
||||||
|
}
|
||||||
|
|
||||||
|
setAssignment(slot, profileId) {
|
||||||
|
if (!RULE_SLOTS[slot]) return false;
|
||||||
|
const assignments = ensureAssignments();
|
||||||
|
if (profileId) {
|
||||||
|
assignments[slot] = profileId;
|
||||||
|
} else {
|
||||||
|
delete assignments[slot];
|
||||||
|
}
|
||||||
|
saveSettingsDebounced();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
getAssignedProfile(slot) {
|
||||||
|
const id = this.getAssignment(slot);
|
||||||
|
if (!id) return null;
|
||||||
|
const profile = ensureProfileMap()[id];
|
||||||
|
return profile ? cloneRuleProfile(profile) : null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ruleProfileManager = new RuleProfileManager();
|
||||||
|
|
||||||
|
export function resolveRuleConfig(ruleProfileId, fallback = {}) {
|
||||||
|
return ruleProfileManager.resolveProfile(ruleProfileId, fallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过功能槽名解析规则配置(推荐方式)
|
||||||
|
* 先查 assignments,再回退到旧字段
|
||||||
|
*/
|
||||||
|
export function resolveSlotRuleConfig(slot, legacyFallback = {}) {
|
||||||
|
const assignedId = ruleProfileManager.getAssignment(slot);
|
||||||
|
if (assignedId) {
|
||||||
|
const profile = ruleProfileManager.getProfile(assignedId);
|
||||||
|
if (profile) return profile;
|
||||||
|
}
|
||||||
|
// 回退到旧的 resolve 路径
|
||||||
|
return sanitizeRuleProfile(legacyFallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function resolveCondensationRuleConfig(settings = {}) {
|
||||||
|
const condensation = settings.condensation || {};
|
||||||
|
return resolveSlotRuleConfig('condensation', {
|
||||||
|
...condensation,
|
||||||
|
ruleProfileId: condensation.ruleProfileId,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function resolveQueryPreprocessingRuleConfig(settings = {}) {
|
||||||
|
const queryPreprocessing = settings.queryPreprocessing || {};
|
||||||
|
return resolveSlotRuleConfig('queryPreprocessing', {
|
||||||
|
...queryPreprocessing,
|
||||||
|
ruleProfileId: queryPreprocessing.ruleProfileId,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function resolveTableRuleConfig(settings = {}) {
|
||||||
|
return resolveSlotRuleConfig('table', {
|
||||||
|
id: settings.table_rule_profile_id,
|
||||||
|
tagExtractionEnabled: Boolean(settings.table_tags_to_extract),
|
||||||
|
tags: settings.table_tags_to_extract || '',
|
||||||
|
exclusionRules: settings.table_exclusion_rules || [],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function resolveHistoriographyRuleConfig(settings = {}) {
|
||||||
|
return resolveSlotRuleConfig('historiography', {
|
||||||
|
id: settings.historiographyRuleProfileId,
|
||||||
|
tagExtractionEnabled: settings.historiographyTagExtractionEnabled ?? false,
|
||||||
|
tags: settings.historiographyTags || '',
|
||||||
|
exclusionRules: settings.historiographyExclusionRules || [],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── 一次性迁移:旧分散 profileId 字段 → 统一 assignments ─────────────────────
|
||||||
|
;(() => {
|
||||||
|
const settings = ensureSettingsRoot();
|
||||||
|
const assignments = ensureAssignments();
|
||||||
|
let changed = false;
|
||||||
|
|
||||||
|
// table: table_rule_profile_id → assignments.table
|
||||||
|
if (settings.table_rule_profile_id && !assignments.table) {
|
||||||
|
assignments.table = settings.table_rule_profile_id;
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// historiography: historiographyRuleProfileId → assignments.historiography
|
||||||
|
if (settings.historiographyRuleProfileId && !assignments.historiography) {
|
||||||
|
assignments.historiography = settings.historiographyRuleProfileId;
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// condensation: condensation.ruleProfileId → assignments.condensation
|
||||||
|
const condensation = settings.condensation || {};
|
||||||
|
if (condensation.ruleProfileId && !assignments.condensation) {
|
||||||
|
assignments.condensation = condensation.ruleProfileId;
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// queryPreprocessing: queryPreprocessing.ruleProfileId → assignments.queryPreprocessing
|
||||||
|
const queryPreprocessing = settings.queryPreprocessing || {};
|
||||||
|
if (queryPreprocessing.ruleProfileId && !assignments.queryPreprocessing) {
|
||||||
|
assignments.queryPreprocessing = queryPreprocessing.ruleProfileId;
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (changed) {
|
||||||
|
saveSettingsDebounced();
|
||||||
|
console.log('[RuleProfiles] 已迁移旧规则配置分配到统一 assignments。', assignments);
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
try {
|
||||||
|
const ctx = window.Amily2Bus?.register('RuleProfiles');
|
||||||
|
if (!ctx) {
|
||||||
|
console.warn('[RuleProfiles] Amily2Bus 尚未就绪,注册跳过。');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ctx.expose({
|
||||||
|
listProfiles: () => ruleProfileManager.listProfiles(),
|
||||||
|
getProfile: (id) => ruleProfileManager.getProfile(id),
|
||||||
|
saveProfile: (profile) => ruleProfileManager.saveProfile(profile),
|
||||||
|
deleteProfile: (id) => ruleProfileManager.deleteProfile(id),
|
||||||
|
resolveProfile: (id, fallback) => ruleProfileManager.resolveProfile(id, fallback),
|
||||||
|
getAssignment: (slot) => ruleProfileManager.getAssignment(slot),
|
||||||
|
setAssignment: (slot, id) => ruleProfileManager.setAssignment(slot, id),
|
||||||
|
getAssignedProfile: (slot) => ruleProfileManager.getAssignedProfile(slot),
|
||||||
|
RULE_SLOTS,
|
||||||
|
});
|
||||||
|
ctx.log('RuleProfiles', 'info', 'RuleProfiles 服务已注册到 Bus。');
|
||||||
|
} catch (error) {
|
||||||
|
console.error('[RuleProfiles] Bus 注册失败:', error);
|
||||||
|
}
|
||||||
|
}, 0);
|
||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
|
|||||||
function a0_0x3df7(_0x2d6ff7,_0x66f04c){_0x2d6ff7=_0x2d6ff7-0x142;const _0x37dbf3=a0_0x37db();let _0x3df7d1=_0x37dbf3[_0x2d6ff7];if(a0_0x3df7['SRsBUW']===undefined){var _0x177cea=function(_0x263285){const _0x23b824='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0x5dc9bb='',_0x4f00bc='';for(let _0x3a945f=0x0,_0x467661,_0x2c1afd,_0x361ba3=0x0;_0x2c1afd=_0x263285['charAt'](_0x361ba3++);~_0x2c1afd&&(_0x467661=_0x3a945f%0x4?_0x467661*0x40+_0x2c1afd:_0x2c1afd,_0x3a945f++%0x4)?_0x5dc9bb+=String['fromCharCode'](0xff&_0x467661>>(-0x2*_0x3a945f&0x6)):0x0){_0x2c1afd=_0x23b824['indexOf'](_0x2c1afd);}for(let _0x134167=0x0,_0x59c18c=_0x5dc9bb['length'];_0x134167<_0x59c18c;_0x134167++){_0x4f00bc+='%'+('00'+_0x5dc9bb['charCodeAt'](_0x134167)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(_0x4f00bc);};const _0x2742fa=function(_0x225e04,_0x57e87c){let _0x196891=[],_0x5287e0=0x0,_0x4e6f16,_0x4e9137='';_0x225e04=_0x177cea(_0x225e04);let _0x3b2355;for(_0x3b2355=0x0;_0x3b2355<0x100;_0x3b2355++){_0x196891[_0x3b2355]=_0x3b2355;}for(_0x3b2355=0x0;_0x3b2355<0x100;_0x3b2355++){_0x5287e0=(_0x5287e0+_0x196891[_0x3b2355]+_0x57e87c['charCodeAt'](_0x3b2355%_0x57e87c['length']))%0x100,_0x4e6f16=_0x196891[_0x3b2355],_0x196891[_0x3b2355]=_0x196891[_0x5287e0],_0x196891[_0x5287e0]=_0x4e6f16;}_0x3b2355=0x0,_0x5287e0=0x0;for(let _0x14e882=0x0;_0x14e882<_0x225e04['length'];_0x14e882++){_0x3b2355=(_0x3b2355+0x1)%0x100,_0x5287e0=(_0x5287e0+_0x196891[_0x3b2355])%0x100,_0x4e6f16=_0x196891[_0x3b2355],_0x196891[_0x3b2355]=_0x196891[_0x5287e0],_0x196891[_0x5287e0]=_0x4e6f16,_0x4e9137+=String['fromCharCode'](_0x225e04['charCodeAt'](_0x14e882)^_0x196891[(_0x196891[_0x3b2355]+_0x196891[_0x5287e0])%0x100]);}return _0x4e9137;};a0_0x3df7['gGFzDR']=_0x2742fa,a0_0x3df7['xOxaTR']={},a0_0x3df7['SRsBUW']=!![];}const _0x2e2977=_0x37dbf3[0x0],_0x46cf12=_0x2d6ff7+_0x2e2977,_0x2e4631=a0_0x3df7['xOxaTR'][_0x46cf12];return!_0x2e4631?(a0_0x3df7['ObVLbg']===undefined&&(a0_0x3df7['ObVLbg']=!![]),_0x3df7d1=a0_0x3df7['gGFzDR'](_0x3df7d1,_0x66f04c),a0_0x3df7['xOxaTR'][_0x46cf12]=_0x3df7d1):_0x3df7d1=_0x2e4631,_0x3df7d1;}const a0_0x2af32d=a0_0x3df7;(function(_0xd2618c,_0x4148c8){const _0x3e9b8c=a0_0x3df7,_0x44ff83=_0xd2618c();while(!![]){try{const _0x3bd772=parseInt(_0x3e9b8c(0x149,'cURR'))/0x1+-parseInt(_0x3e9b8c(0x152,'Ipuz'))/0x2*(-parseInt(_0x3e9b8c(0x159,'r74E'))/0x3)+-parseInt(_0x3e9b8c(0x147,'DYEA'))/0x4*(-parseInt(_0x3e9b8c(0x14c,'r74E'))/0x5)+parseInt(_0x3e9b8c(0x142,'UpGh'))/0x6*(parseInt(_0x3e9b8c(0x14e,'8hxs'))/0x7)+parseInt(_0x3e9b8c(0x14a,'hAFE'))/0x8*(-parseInt(_0x3e9b8c(0x146,'OG5z'))/0x9)+parseInt(_0x3e9b8c(0x15d,'Z46V'))/0xa+-parseInt(_0x3e9b8c(0x157,'SE&p'))/0xb;if(_0x3bd772===_0x4148c8)break;else _0x44ff83['push'](_0x44ff83['shift']());}catch(_0x52e370){_0x44ff83['push'](_0x44ff83['shift']());}}}(a0_0x37db,0x6ab29));function a0_0x37db(){const _0x2331d0=['pSkZW5ZdVZC3xIi','z8o6W7ddLduovrhdGCoC','arfnxCoaBmoCD8kXymoU','tNDZBSoedXbjsxLmW4C','WQq3tSoIWRXfW508W7pcPCknW6xcJ28','lCo1f8ksWRFcJsClwmoTucTYka','W6DJDmovWRb8W4SB','WPmbW5/dGSoauXFdRcm/wa','WPWsWQjrW6xcGSocW6hdOCoRDa','o8olWRzxWPxdHMe','WQ4MWRpdHJPzWRryqrPveSkuW5S','ESoctmoDWQ/cHmkBuSkAWOBcR1pcQa','BSkgW7xcSSkXiW','er9nzSoGBmoCy8k/Fa','iWuRF8kjaWmAWOm0W4K','u1CynmkzkmkfrSkQvmo/W5Cv','WPSyW5TwoCkxuHvIpYVdNa','vmkXF8kKkGL6uCoOcWG','WP/dOSowW6GmWOLgW5JcQGNcV8kM','fSkEg1ddHCkgWRJcRa','t3HmWQhcRCk1hxRcUWOVaa','n8ocWQNdImoLAabgWPGhcSoL','WPzoWQGuASoiDW','e07dU8kcW7VdImodW69oWOC','WPKcW5VdGCoecapdJb45rSkh','WPqtWQjCWRNcPSo7W53dSCo1','nSocW5tdU8o5FwhdLSoiFG','m8oVW6eooSk7W5yy','jsBdK8oxWQ1yWQX8W5FcIq','yLX0o8o2ndqRWQqlW75WW4pdPSoBmCkJkXuvWPddTeWv'];a0_0x37db=function(){return _0x2331d0;};return a0_0x37db();}export const SENSITIVE_KEYS=new Set([a0_0x2af32d(0x15e,'cURR'),a0_0x2af32d(0x156,'(nn@'),a0_0x2af32d(0x151,'UpGh'),a0_0x2af32d(0x14b,'7yS&'),a0_0x2af32d(0x150,'v814'),a0_0x2af32d(0x153,'Ipuz'),a0_0x2af32d(0x154,'V0W['),a0_0x2af32d(0x15f,'V0W[')]);
|
function a0_0x14a8(){const _0x1fb0fe=['t8oghcK4WPuBW5xdImo7ba','WRFcMYFcOCkfW5JdQstcHCopWQuB','WQNdVvzhoHL6WQRcI8kmhCoGWPC','dMugW7tdR0tcUmkNudBcOSonFSo9','W43dH8oIWQlcG1moeI/dQa','ghm2W5j3lmo/WOj+','bXFcTdTYpSkUWRW','uCo/DSkWWR/cNmkbdCkflwP6tq','vxlcTb/dLstdKmkXW7PAyXJdQG','ASoMW7q7z3anWQ1+W6iHD8o+','cmkTvc4SW4rDmCkcWOu6WPGH','WPeVkcSeWRZcIHnWF0/dNq','WRFcKcBcPmkkW53cRXlcSCo+WRuOpq','dWbxWRydWPZcGKWx','q8onW7ddOmoXuCoZWRi','d8kOvc8PW40FhmkdWPytWR0','WPuPWR7dJ8kKBq','cmkTuYSQW4vAAmk+WReiWQCgWRO','qZD/W4TCbCoEWQzcia','lSk5WQX+gdjnWP9qW6ulzSoXm8kqW6tdHxWChLBcLbTV','baWVWPddRCoFW7ens8kfg8om','uhpcUH3dKYtdLmk4W4v5yZNdIa','W6OOW5ddUxy0gSo8xGS','mmk2WQb5fJjqWOTwW7m','WOTOW4hcOCkymmoyjWP8hGZcG8k8','W6CXWPTDdbfcWQ/dOSkJW6xcJfm'];a0_0x14a8=function(){return _0x1fb0fe;};return a0_0x14a8();}function a0_0x2f02(_0xfc7e50,_0x3dbb02){_0xfc7e50=_0xfc7e50-0x132;const _0x14a89c=a0_0x14a8();let _0x2f0242=_0x14a89c[_0xfc7e50];if(a0_0x2f02['haRsYa']===undefined){var _0x5df497=function(_0x10bb1d){const _0x5e6cb0='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0x109289='',_0x9c7442='';for(let _0x403cc5=0x0,_0x465206,_0x20ab31,_0x2b7eb2=0x0;_0x20ab31=_0x10bb1d['charAt'](_0x2b7eb2++);~_0x20ab31&&(_0x465206=_0x403cc5%0x4?_0x465206*0x40+_0x20ab31:_0x20ab31,_0x403cc5++%0x4)?_0x109289+=String['fromCharCode'](0xff&_0x465206>>(-0x2*_0x403cc5&0x6)):0x0){_0x20ab31=_0x5e6cb0['indexOf'](_0x20ab31);}for(let _0x245772=0x0,_0x37e017=_0x109289['length'];_0x245772<_0x37e017;_0x245772++){_0x9c7442+='%'+('00'+_0x109289['charCodeAt'](_0x245772)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(_0x9c7442);};const _0x4fc336=function(_0xbbd1d9,_0x87c073){let _0x5aae06=[],_0xc59be1=0x0,_0x1677a3,_0x18267d='';_0xbbd1d9=_0x5df497(_0xbbd1d9);let _0x2fdfd9;for(_0x2fdfd9=0x0;_0x2fdfd9<0x100;_0x2fdfd9++){_0x5aae06[_0x2fdfd9]=_0x2fdfd9;}for(_0x2fdfd9=0x0;_0x2fdfd9<0x100;_0x2fdfd9++){_0xc59be1=(_0xc59be1+_0x5aae06[_0x2fdfd9]+_0x87c073['charCodeAt'](_0x2fdfd9%_0x87c073['length']))%0x100,_0x1677a3=_0x5aae06[_0x2fdfd9],_0x5aae06[_0x2fdfd9]=_0x5aae06[_0xc59be1],_0x5aae06[_0xc59be1]=_0x1677a3;}_0x2fdfd9=0x0,_0xc59be1=0x0;for(let _0x60400c=0x0;_0x60400c<_0xbbd1d9['length'];_0x60400c++){_0x2fdfd9=(_0x2fdfd9+0x1)%0x100,_0xc59be1=(_0xc59be1+_0x5aae06[_0x2fdfd9])%0x100,_0x1677a3=_0x5aae06[_0x2fdfd9],_0x5aae06[_0x2fdfd9]=_0x5aae06[_0xc59be1],_0x5aae06[_0xc59be1]=_0x1677a3,_0x18267d+=String['fromCharCode'](_0xbbd1d9['charCodeAt'](_0x60400c)^_0x5aae06[(_0x5aae06[_0x2fdfd9]+_0x5aae06[_0xc59be1])%0x100]);}return _0x18267d;};a0_0x2f02['FifVqZ']=_0x4fc336,a0_0x2f02['BzwYNH']={},a0_0x2f02['haRsYa']=!![];}const _0x577f3d=_0x14a89c[0x0],_0x53c179=_0xfc7e50+_0x577f3d,_0x522de8=a0_0x2f02['BzwYNH'][_0x53c179];return!_0x522de8?(a0_0x2f02['YRLvop']===undefined&&(a0_0x2f02['YRLvop']=!![]),_0x2f0242=a0_0x2f02['FifVqZ'](_0x2f0242,_0x3dbb02),a0_0x2f02['BzwYNH'][_0x53c179]=_0x2f0242):_0x2f0242=_0x522de8,_0x2f0242;}const a0_0xbb9b93=a0_0x2f02;(function(_0x1bb79c,_0x24a1c8){const _0x3d02d0=a0_0x2f02,_0x1c7173=_0x1bb79c();while(!![]){try{const _0x254b63=-parseInt(_0x3d02d0(0x13d,'5rsN'))/0x1+-parseInt(_0x3d02d0(0x149,'Y#Z2'))/0x2*(parseInt(_0x3d02d0(0x13b,'MW1l'))/0x3)+parseInt(_0x3d02d0(0x134,'y6wl'))/0x4+-parseInt(_0x3d02d0(0x136,'ldKT'))/0x5*(-parseInt(_0x3d02d0(0x13a,'7dR0'))/0x6)+-parseInt(_0x3d02d0(0x14a,'5rsN'))/0x7+-parseInt(_0x3d02d0(0x137,'xK2z'))/0x8+parseInt(_0x3d02d0(0x138,']MRa'))/0x9;if(_0x254b63===_0x24a1c8)break;else _0x1c7173['push'](_0x1c7173['shift']());}catch(_0x3d34d4){_0x1c7173['push'](_0x1c7173['shift']());}}}(a0_0x14a8,0xf1f7e));export const SENSITIVE_KEYS=new Set([a0_0xbb9b93(0x145,'ld^v'),a0_0xbb9b93(0x133,'dUc%'),a0_0xbb9b93(0x148,'cU[V'),a0_0xbb9b93(0x139,'v^N$'),a0_0xbb9b93(0x132,'cU[V'),a0_0xbb9b93(0x147,'7dR0'),a0_0xbb9b93(0x135,'Ge@A'),a0_0xbb9b93(0x14b,'BVyW')]);
|
||||||
@@ -2,7 +2,7 @@ import { extension_settings } from "/scripts/extensions.js";
|
|||||||
import { saveSettingsDebounced } from "/script.js";
|
import { saveSettingsDebounced } from "/script.js";
|
||||||
import { pluginAuthStatus } from "./auth.js";
|
import { pluginAuthStatus } from "./auth.js";
|
||||||
|
|
||||||
export const pluginVersion = "1.4.5";
|
export const pluginVersion = "2.1.0";
|
||||||
|
|
||||||
// 从当前文件 URL 动态推导插件文件夹名和根路径,兼容任意文件夹名(Dev / 正式版均适用)
|
// 从当前文件 URL 动态推导插件文件夹名和根路径,兼容任意文件夹名(Dev / 正式版均适用)
|
||||||
// URL 结构:.../scripts/extensions/third-party/<folderName>/utils/settings.js
|
// URL 结构:.../scripts/extensions/third-party/<folderName>/utils/settings.js
|
||||||
|
|||||||
Reference in New Issue
Block a user