mirror of
https://github.com/Wx-2025/ST-Amily2-Chat-Optimisation.git
synced 2026-06-06 12:45:51 +00:00
Compare commits
7 Commits
2.2.2
...
d6b3b00c86
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d6b3b00c86 | ||
|
|
a8c3ad9027 | ||
|
|
0e11f85031 | ||
|
|
9bc2f694b0 | ||
|
|
08e1dbde85 | ||
|
|
42e0bdec19 | ||
|
|
3e217e8ed8 |
@@ -26,3 +26,45 @@
|
||||
- NGMS / NCCS API 配置槽位标签修正(NGMS→总结,NCCS→填表)
|
||||
- API Profile 面板选择逻辑统一重构,修复多处旧字段覆盖新配置的问题
|
||||
- 世界书控制参数兼容性修复(排除递归、插入位置、扫描深度等,适配 ST 1.17.0+)
|
||||
|
||||
---
|
||||
|
||||
## v2.2.3
|
||||
|
||||
### 新功能
|
||||
|
||||
- Function Call 填表开关下方新增公益站风险提示横幅:部分公益站会屏蔽 tools 参数,请确认支持情况避免被意外封禁
|
||||
|
||||
### 修复
|
||||
|
||||
- **Function Call 填表**:
|
||||
- 修复 ST 代理以 HTTP 200 + error body 形式返回错误、导致降级重试机制从未触发的问题
|
||||
- 修复思考模式模型(如 DeepSeek v4-flash)因 tool_choice 不兼容返回 Bad Request 后正确降级并重试
|
||||
- 重试时自动追加强制调用指令,防止思考模型绕过工具直接输出文本造成无效二次开销
|
||||
- **超级记忆 / 翰林院**:
|
||||
- 修复 `getRagSettings()` 读写顶层路径而非嵌套路径,导致打开超级记忆面板后向量化、归档等开关在重载时被全默认值覆盖的问题
|
||||
- 修复自动归档失效问题
|
||||
- 修复归档管理器在同一事件中被三次触发的回归问题
|
||||
- 修复翰林院设置旧版迁移逻辑异常
|
||||
|
||||
---
|
||||
|
||||
## v2.2.4
|
||||
|
||||
### 新功能
|
||||
|
||||
- **Function Call 填表**:
|
||||
- FC 首次请求时对 DeepSeek 系模型自动附加 `thinking: { type: "disabled" }`,避免思考模式与 tool_choice 冲突
|
||||
- 操作列表为空时在日志面板输出原始响应 JSON,便于区分"AI 判断无需变更"、"格式校验全部不通过"和"JSON 解析失败"三种情况
|
||||
|
||||
### 修复
|
||||
|
||||
- **剧情优化**:移除剧情优化页面遗留的 Jqyh 直连配置字段(URL / Key / Model),统一走 API 连接配置功能分配槽位
|
||||
- **表格**:
|
||||
- 补全 `batch-filling-threshold` 批处理阈值的持久化绑定(页面刷新后不再还原为默认值 30)
|
||||
- 修复分步填表并发锁与 async/await 时序问题
|
||||
- 修复外层多余 `try...finally` 导致的插件加载报错
|
||||
- **Rerank**:
|
||||
- 修复选择连接配置后报"API Key 未配置"的问题(`apiMode` 现从设置读取而非硬编码 `custom`)
|
||||
- 补全 `hly-rerank-api-mode` 加载绑定及默认值
|
||||
- **翰林院 RAG**:补全 `priorityRetrieval.sources` 各来源条目的缺失键,修复设置面板回填 TypeError
|
||||
|
||||
@@ -36,47 +36,12 @@
|
||||
<!-- API Settings Tab -->
|
||||
<div id="sinan-api-settings-tab" class="sinan-tab-pane active">
|
||||
<fieldset class="settings-group">
|
||||
<legend>Jqyh API</legend>
|
||||
<div class="control-block-with-switch">
|
||||
<label for="amily2_jqyh_enabled"><strong>启用 Jqyh API</strong></label>
|
||||
<label class="toggle-switch">
|
||||
<input id="amily2_jqyh_enabled" type="checkbox" />
|
||||
<span class="slider"></span>
|
||||
</label>
|
||||
</div>
|
||||
<div id="amily2_jqyh_content" style="display: none;" class="inline-settings-grid">
|
||||
<label for="amily2_jqyh_api_mode">API 模式</label>
|
||||
<select id="amily2_jqyh_api_mode" class="text_pole">
|
||||
<option value="openai_test">全兼容模式</option>
|
||||
<option value="sillytavern_preset">SillyTavern 预设</option>
|
||||
</select>
|
||||
|
||||
<div id="amily2_jqyh_compatible_config" class="inline-settings-grid" style="grid-column: 1 / -1;">
|
||||
<label for="amily2_jqyh_api_url">API URL</label>
|
||||
<input type="text" id="amily2_jqyh_api_url" class="text_pole" placeholder="例如: https://api.openai.com/v1">
|
||||
<label for="amily2_jqyh_api_key">API Key</label>
|
||||
<input type="password" id="amily2_jqyh_api_key" class="text_pole" placeholder="请输入您的 API Key">
|
||||
<label for="amily2_jqyh_model">模型</label>
|
||||
<div class="amily2_opt_preset_selector_wrapper">
|
||||
<input type="text" id="amily2_jqyh_model" class="text_pole" placeholder="请先获取模型列表或手动输入">
|
||||
<select id="amily2_jqyh_model_select" class="text_pole" style="display: none;"></select>
|
||||
</div>
|
||||
<div class="jqyh-button-row" style="grid-column: 1 / -1;">
|
||||
<button id="amily2_jqyh_fetch_models" class="menu_button secondary" title="获取模型列表"><i class="fas fa-sync-alt"></i> 获取模型</button>
|
||||
<button id="amily2_jqyh_test_connection" class="menu_button primary"><i class="fas fa-plug"></i> 测试连接</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="amily2_jqyh_preset_config" class="inline-settings-grid" style="display: none; grid-column: 1 / -1;">
|
||||
<label for="amily2_jqyh_tavern_profile">选择酒馆预设</label>
|
||||
<select id="amily2_jqyh_tavern_profile" class="text_pole"></select>
|
||||
</div>
|
||||
|
||||
<label for="amily2_jqyh_max_tokens">最大 Tokens: <span id="amily2_jqyh_max_tokens_value">4000</span></label>
|
||||
<input type="number" class="text_pole" id="amily2_jqyh_max_tokens" min="100" max="100000" value="4000">
|
||||
<label for="amily2_jqyh_temperature">温度: <span id="amily2_jqyh_temperature_value">0.7</span></label>
|
||||
<input type="number" class="text_pole" id="amily2_jqyh_temperature" min="0" max="2" value="0.7">
|
||||
</div>
|
||||
<legend>剧情优化 API</legend>
|
||||
<p class="notes" style="margin: 0;">
|
||||
剧情优化所用的连接配置统一在
|
||||
<strong>API 连接配置 → 功能分配 → 剧情优化 / JQYH</strong>
|
||||
中指定,无需在此单独填写。
|
||||
</p>
|
||||
</fieldset>
|
||||
|
||||
<fieldset class="settings-group">
|
||||
|
||||
@@ -304,7 +304,10 @@
|
||||
<span class="slider"></span>
|
||||
</label>
|
||||
</div>
|
||||
<p class="notes" style="margin-bottom: 10px;">仅支持 openai 直连接口(tableFilling 槽位)。启用后跳过 <Amily2Edit> 文本解析,由模型直接返回操作列表。</p>
|
||||
<p class="notes" style="margin-bottom: 6px;">仅支持 openai 直连接口(tableFilling 槽位)。启用后跳过 <Amily2Edit> 文本解析,由模型直接返回操作列表。</p>
|
||||
<div style="background: rgba(255, 160, 0, 0.12); border-left: 3px solid #ffa000; border-radius: 3px; padding: 6px 10px; margin-bottom: 10px; font-size: 0.85em; color: #ffcc80;">
|
||||
⚠️ 部分公益站因禁止用于跑代码会屏蔽 tools 参数,请确认公益站是否支持 tools 调用,避免被意外封禁。
|
||||
</div>
|
||||
|
||||
<hr class="section-divider" style="margin: 10px 0;">
|
||||
|
||||
|
||||
19
core/api.js
19
core/api.js
@@ -485,8 +485,7 @@ export async function getApiSettings(slot = 'main') {
|
||||
apiProvider: apiMode,
|
||||
apiUrl: settings.plotOpt_apiUrl?.trim() || '',
|
||||
apiKey: configManager.get('plotOpt_apiKey') || '',
|
||||
model: document.getElementById('amily2_opt_model')?.value?.trim()
|
||||
|| settings.plotOpt_model || '',
|
||||
model: settings.plotOpt_model || '',
|
||||
maxTokens: settings.plotOpt_max_tokens ?? 65500,
|
||||
temperature: settings.plotOpt_temperature ?? 1.0,
|
||||
tavernProfile: '',
|
||||
@@ -986,7 +985,11 @@ export async function callAIForTools(messages, tool, options = {}) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const buildFCBody = (withToolChoice, overrideMessages) => ({
|
||||
// deepseek.com 域名或模型名含 deepseek 时,第一次调用主动关闭思考模式,
|
||||
// 让 tool_choice 强制走 Function Call(思考模式下 tool_choice 会报错/失败)
|
||||
const isDeepSeek = /deepseek/i.test(finalOptions.apiUrl || '') || /deepseek/i.test(finalOptions.model || '');
|
||||
|
||||
const buildFCBody = (withToolChoice, overrideMessages, extraParams = {}) => ({
|
||||
chat_completion_source: 'openai',
|
||||
reverse_proxy: finalOptions.apiUrl,
|
||||
proxy_password: finalOptions.apiKey,
|
||||
@@ -996,15 +999,16 @@ export async function callAIForTools(messages, tool, options = {}) {
|
||||
temperature: finalOptions.temperature ?? 1,
|
||||
stream: false,
|
||||
...(finalOptions.customParams || {}),
|
||||
...extraParams,
|
||||
tools: [tool],
|
||||
...(withToolChoice ? { tool_choice: { type: 'function', function: { name: tool.function.name } } } : {}),
|
||||
});
|
||||
|
||||
const doFCRequest = async (withToolChoice, overrideMessages) => {
|
||||
const doFCRequest = async (withToolChoice, overrideMessages, extraParams) => {
|
||||
const response = await fetch('/api/backends/chat-completions/generate', {
|
||||
method: 'POST',
|
||||
headers: { ...getRequestHeaders(), 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(buildFCBody(withToolChoice, overrideMessages)),
|
||||
body: JSON.stringify(buildFCBody(withToolChoice, overrideMessages, extraParams)),
|
||||
});
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text();
|
||||
@@ -1027,7 +1031,10 @@ export async function callAIForTools(messages, tool, options = {}) {
|
||||
let data;
|
||||
try {
|
||||
// 走 ST 后端代理,避免浏览器 CSP 拦截直连外部 URL
|
||||
data = await doFCRequest(true);
|
||||
// DeepSeek 思考模式与 tool_choice 不兼容,第一次请求时主动关闭思考模式
|
||||
const firstAttemptExtra = isDeepSeek ? { thinking: { type: 'disabled' } } : {};
|
||||
if (isDeepSeek) console.log('[Amily2-外交部] 检测到 DeepSeek 端点,首次 FC 请求附加 thinking:disabled');
|
||||
data = await doFCRequest(true, undefined, firstAttemptExtra);
|
||||
} catch (firstError) {
|
||||
// 首次失败(含 ST 代理吞掉错误码场景)无条件去掉 tool_choice 重试一次
|
||||
// 思考模式模型支持 tools 但不支持强制 tool_choice,追加强制指令防止模型直接输出文本
|
||||
|
||||
@@ -10,8 +10,16 @@ export function initializeArchiveManager() {
|
||||
console.log('[归档管理器] 已启动,正在监控表格状态...');
|
||||
}
|
||||
|
||||
/** Bus 直调路径:由 super-memory/manager.js 的 pushUpdate 调用,接受纯 payload 对象。 */
|
||||
export function handleArchiveUpdate(payload) {
|
||||
return handleArchivePayload(payload);
|
||||
}
|
||||
|
||||
async function handleTableUpdate(event) {
|
||||
const { tableName, data, role } = event.detail;
|
||||
return handleArchivePayload(event.detail);
|
||||
}
|
||||
|
||||
async function handleArchivePayload({ tableName, data, role }) {
|
||||
const settings = getSettings();
|
||||
|
||||
if (!settings.archive || !settings.archive.enabled) return;
|
||||
@@ -24,6 +32,7 @@ async function handleTableUpdate(event) {
|
||||
if (isArchiving) return;
|
||||
|
||||
let hasNotice = false;
|
||||
let realRows = data;
|
||||
|
||||
if (data.length > 0 && data[0][2] && data[0][2].includes('已自动归档')) {
|
||||
hasNotice = true;
|
||||
|
||||
@@ -49,12 +49,13 @@ export async function getEmbedRetrievalSettings() {
|
||||
export async function getRerankSettings() {
|
||||
const profile = await getSlotProfile('ragRerank');
|
||||
if (profile) {
|
||||
const manualSettings = getSettings().rerank || {};
|
||||
return {
|
||||
url: profile.apiUrl,
|
||||
apiKey: profile.apiKey ?? '',
|
||||
model: profile.model,
|
||||
top_n: getSettings().rerank?.top_n ?? 10,
|
||||
apiMode: 'custom',
|
||||
top_n: manualSettings.top_n ?? 10,
|
||||
apiMode: manualSettings.apiMode ?? 'custom',
|
||||
};
|
||||
}
|
||||
return getSettings().rerank || {};
|
||||
|
||||
@@ -342,6 +342,25 @@ function getSettings() {
|
||||
}
|
||||
}
|
||||
|
||||
// 旧版设置 rerank.priorityRetrieval 可能只有 enabled 字段而缺少 sources,补全
|
||||
if (s.rerank?.priorityRetrieval && !s.rerank.priorityRetrieval.sources) {
|
||||
s.rerank.priorityRetrieval.sources = structuredClone(ragDefaultSettings.rerank.priorityRetrieval.sources);
|
||||
}
|
||||
// 确保 sources 中每个来源条目完整(新增来源 / 新增字段时旧用户不会缺失)
|
||||
if (s.rerank?.priorityRetrieval?.sources) {
|
||||
const defaultSources = ragDefaultSettings.rerank.priorityRetrieval.sources;
|
||||
for (const sourceName in defaultSources) {
|
||||
if (!s.rerank.priorityRetrieval.sources[sourceName]) {
|
||||
s.rerank.priorityRetrieval.sources[sourceName] = structuredClone(defaultSources[sourceName]);
|
||||
} else {
|
||||
const existing = s.rerank.priorityRetrieval.sources[sourceName];
|
||||
for (const key in defaultSources[sourceName]) {
|
||||
if (existing[key] === undefined) existing[key] = defaultSources[sourceName][key];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
@@ -65,6 +65,7 @@ export const defaultSettings = {
|
||||
},
|
||||
rerank: {
|
||||
enabled: false,
|
||||
apiMode: 'custom',
|
||||
url: 'https://api.siliconflow.cn/v1',
|
||||
apiKey: '',
|
||||
model: 'Pro/BAAI/bge-reranker-v2-m3',
|
||||
|
||||
@@ -15,7 +15,6 @@ import { resolveHistoriographyRuleConfig } from "../utils/config/RuleProfileMana
|
||||
|
||||
import { getPresetPrompts, getMixedOrder } from '../PresetSettings/index.js';
|
||||
import { callAI, generateRandomSeed } from './api.js';
|
||||
import { callJqyhAI } from './api/JqyhApi.js';
|
||||
import { callConcurrentAI } from './api/ConcurrentApi.js';
|
||||
|
||||
export async function processOptimization(latestMessage, previousMessages) {
|
||||
@@ -480,7 +479,7 @@ export async function processPlotOptimization(currentUserMessage, contextMessage
|
||||
onProgress(getRandomText(['正在检索辅助记忆 (LLM-B)...', '正在扫描平行世界线 (LLM-B)...']), false);
|
||||
|
||||
onProgress(getRandomText(['正在与核心意识同步 (LLM-A)...', '正在等待灵魂共鸣 (LLM-A)...']), false);
|
||||
const promise1 = (settings.jqyhEnabled ? callJqyhAI(mainMessages) : callAI(mainMessages, { slot: 'plotOpt' })).then(res => {
|
||||
const promise1 = callAI(mainMessages, { slot: 'plotOpt' }).then(res => {
|
||||
onProgress(getRandomText(['正在与核心意识同步 (LLM-A)...', '正在等待灵魂共鸣 (LLM-A)...']), true);
|
||||
return res;
|
||||
});
|
||||
@@ -554,7 +553,7 @@ export async function processPlotOptimization(currentUserMessage, contextMessage
|
||||
attempt++;
|
||||
console.log(`[${extensionName}] 剧情优化第 ${attempt} 次尝试...`);
|
||||
|
||||
const rawResponse = settings.jqyhEnabled ? await callJqyhAI(mainMessages) : await callAI(mainMessages, { slot: 'plotOpt' });
|
||||
const rawResponse = await callAI(mainMessages, { slot: 'plotOpt' });
|
||||
|
||||
if (cancellationState.isCancelled) {
|
||||
console.log(`[${extensionName}] 优化任务在API调用后被中止。`);
|
||||
|
||||
@@ -9,10 +9,11 @@ const RAG_MODULE_NAME = 'hanlinyuan-rag-core';
|
||||
|
||||
function getRagSettings() {
|
||||
if (!extension_settings[extensionName]) extension_settings[extensionName] = {};
|
||||
if (!extension_settings[RAG_MODULE_NAME]) {
|
||||
extension_settings[RAG_MODULE_NAME] = structuredClone(ragDefaultSettings);
|
||||
const root = extension_settings[extensionName];
|
||||
if (!root[RAG_MODULE_NAME]) {
|
||||
root[RAG_MODULE_NAME] = structuredClone(ragDefaultSettings);
|
||||
}
|
||||
return extension_settings[RAG_MODULE_NAME];
|
||||
return root[RAG_MODULE_NAME];
|
||||
}
|
||||
|
||||
export function bindSuperMemoryEvents() {
|
||||
|
||||
@@ -6,6 +6,7 @@ import { syncToLorebook, ensureMemoryBook, updateTransientHint, getMemoryBookNam
|
||||
import { getMemoryState, loadMemoryState, saveMemoryState } from "../table-system/manager.js";
|
||||
import { TABLE_UPDATED_EVENT } from "../table-system/events-schema.js";
|
||||
import { eventSource, event_types } from "/script.js";
|
||||
import { handleArchiveUpdate } from "../archive-manager.js";
|
||||
|
||||
/* ── [AMILY2-MODIFIED] ── pipeline integration: awaitSync() export ── */
|
||||
let isInitialized = false;
|
||||
@@ -110,10 +111,15 @@ export function pushUpdate(payload) {
|
||||
|
||||
updateQueue.push({ tableName, data, role, headers, rowStatuses });
|
||||
_syncPromise = processQueue();
|
||||
|
||||
// Bus 路径下 document event 不再分发,需直接通知归档管理器
|
||||
handleArchiveUpdate(payload);
|
||||
}
|
||||
|
||||
/** CustomEvent 降级路径(Bus 未就绪时的兜底监听器) */
|
||||
function handleTableUpdate(event) {
|
||||
// Bus 已就绪时 pushUpdate 已由 dispatchTableUpdate 直调,跳过避免重复处理
|
||||
if (window.Amily2Bus?.query('SuperMemory')?.pushUpdate) return;
|
||||
pushUpdate(event.detail);
|
||||
}
|
||||
|
||||
|
||||
@@ -291,7 +291,17 @@ async function runBatchAttempt(batchNum, attemptNum) {
|
||||
if (!argsString) throw new Error('Function Call 返回为空。');
|
||||
const ops = parseToolCallArgs(argsString);
|
||||
if (ops.length === 0) {
|
||||
log(`批次 ${batchNum} 的 Function Call 返回操作列表为空,AI 判断此批次无需变更。`, 'warn');
|
||||
let parseHint = '';
|
||||
try {
|
||||
const rawParsed = JSON.parse(argsString);
|
||||
const rawOpsLen = rawParsed?.operations?.length ?? 0;
|
||||
if (rawOpsLen > 0) {
|
||||
parseHint = `(响应含 ${rawOpsLen} 条操作,但全部未通过格式校验)`;
|
||||
}
|
||||
} catch {
|
||||
parseHint = '(响应 JSON 解析失败)';
|
||||
}
|
||||
log(`批次 ${batchNum} FC 操作列表为空${parseHint},原始响应:\n${argsString}`, 'warn');
|
||||
toastr.info('AI 判断此批次无需修改。', `批次 ${batchNum}`);
|
||||
} else {
|
||||
await updateTableFromOps(ops, { immediateDelete: true });
|
||||
@@ -417,7 +427,9 @@ export function startBatchFilling() {
|
||||
manualStopRequested = false;
|
||||
const context = getContext();
|
||||
chatHistoryLength = context.chat.length;
|
||||
threshold = parseInt(document.getElementById('batch-filling-threshold')?.value, 10) || 30;
|
||||
threshold = extension_settings[extensionName]?.batch_filling_threshold
|
||||
?? parseInt(/** @type {HTMLInputElement|null} */ (document.getElementById('batch-filling-threshold'))?.value, 10)
|
||||
?? 30;
|
||||
|
||||
const ruleTemplate = getBatchFillerRuleTemplate();
|
||||
const flowTemplate = getBatchFillerFlowTemplate();
|
||||
@@ -562,7 +574,17 @@ export async function startFloorRangeFilling(startFloor, endFloor) {
|
||||
if (!argsString) throw new Error('Function Call 返回为空。');
|
||||
const ops = parseToolCallArgs(argsString);
|
||||
if (ops.length === 0) {
|
||||
log(`楼层 ${startFloor}-${endFloor} Function Call 返回操作列表为空,无需变更。`, 'warn');
|
||||
let parseHint = '';
|
||||
try {
|
||||
const rawParsed = JSON.parse(argsString);
|
||||
const rawOpsLen = rawParsed?.operations?.length ?? 0;
|
||||
if (rawOpsLen > 0) {
|
||||
parseHint = `(响应含 ${rawOpsLen} 条操作,但全部未通过格式校验)`;
|
||||
}
|
||||
} catch {
|
||||
parseHint = '(响应 JSON 解析失败)';
|
||||
}
|
||||
log(`楼层 ${startFloor}-${endFloor} FC 操作列表为空${parseHint},原始响应:\n${argsString}`, 'warn');
|
||||
toastr.info('AI 判断此楼层范围无需修改。', `楼层 ${startFloor}-${endFloor}`);
|
||||
} else {
|
||||
await updateTableFromOps(ops, { immediateDelete: true });
|
||||
|
||||
@@ -1021,7 +1021,7 @@ export async function rollbackAndRefill() {
|
||||
const lastMessage = context.chat[context.chat.length - 1];
|
||||
|
||||
try {
|
||||
await fillWithSecondaryApi(lastMessage, true);
|
||||
await fillWithSecondaryApi(lastMessage, true, { targetMessage: lastMessage });
|
||||
log('回退并重新填表操作完成。', 'success');
|
||||
} catch (error) {
|
||||
log(`回退重填过程中发生错误: ${error.message}`, 'error');
|
||||
|
||||
@@ -18,6 +18,7 @@ import { showTableFillReviewModal } from '../../ui/page-window.js';
|
||||
const CONTINUE_PROMPT_SECONDARY = '上一条回复不完整或缺少 <Amily2Edit> 指令块。请直接从中断处继续生成剩余内容,不要重复已输出的文本,也不要添加任何解释或寒暄,确保最终输出中包含完整的 <Amily2Edit>...</Amily2Edit> 指令块。';
|
||||
|
||||
let secondaryFillerDebounceTimer = null;
|
||||
let secondaryFillerRunning = false;
|
||||
|
||||
async function callSecondaryModel(messages) {
|
||||
const settings = extension_settings[extensionName] || {};
|
||||
@@ -38,15 +39,15 @@ async function requestSecondaryContinuation(baseMessages, partialResponse) {
|
||||
return `${partialResponse || ''}${continued}`;
|
||||
}
|
||||
|
||||
function commitSecondaryFillResult(rawContent, targetMessages) {
|
||||
updateTableFromText(rawContent);
|
||||
async function commitSecondaryFillResult(rawContent, targetMessages) {
|
||||
await updateTableFromText(rawContent);
|
||||
|
||||
const memoryState = getMemoryState();
|
||||
const lastProcessedMsg = targetMessages[targetMessages.length - 1].msg;
|
||||
|
||||
for (const target of targetMessages) {
|
||||
if (!target.msg.metadata) target.msg.metadata = {};
|
||||
target.msg.metadata.Amily2_Process_Hash = target.hash;
|
||||
if (!target.msg.extra) target.msg.extra = {};
|
||||
target.msg.extra.amily2_process_hash = target.hash;
|
||||
}
|
||||
|
||||
if (saveStateToMessage(memoryState, lastProcessedMsg)) {
|
||||
@@ -54,7 +55,7 @@ function commitSecondaryFillResult(rawContent, targetMessages) {
|
||||
updateOrInsertTableInChat();
|
||||
}
|
||||
|
||||
saveChat();
|
||||
await saveChat();
|
||||
}
|
||||
|
||||
|
||||
@@ -110,7 +111,12 @@ async function getWorldBookContext() {
|
||||
return content.trim() ? `<世界书>\n${content.trim()}\n</世界书>` : '';
|
||||
}
|
||||
|
||||
export async function fillWithSecondaryApi(latestMessage, forceRun = false) {
|
||||
export async function fillWithSecondaryApi(latestMessage, forceRun = false, opts = {}) {
|
||||
if (secondaryFillerRunning) {
|
||||
log('分步填表正在进行中,跳过本次触发。', 'warn');
|
||||
return;
|
||||
}
|
||||
secondaryFillerRunning = true;
|
||||
const settings = extension_settings[extensionName] || {};
|
||||
|
||||
// 【V2.1.1】分步填表触发延迟 / 防抖:自动触发时若配置了延迟,则延后执行,
|
||||
@@ -122,7 +128,7 @@ export async function fillWithSecondaryApi(latestMessage, forceRun = false) {
|
||||
}
|
||||
secondaryFillerDebounceTimer = setTimeout(() => {
|
||||
secondaryFillerDebounceTimer = null;
|
||||
fillWithSecondaryApi(latestMessage, forceRun);
|
||||
fillWithSecondaryApi(latestMessage, forceRun, opts);
|
||||
}, delay);
|
||||
console.log(`[Amily2-副API] 分步填表已按防抖延迟 ${delay}ms 调度。`);
|
||||
return;
|
||||
@@ -164,26 +170,15 @@ export async function fillWithSecondaryApi(latestMessage, forceRun = false) {
|
||||
const contextLimit = parseInt(settings.secondary_filler_context || 2, 10);
|
||||
|
||||
// 【V1.7.7 修复】限制最大回溯深度,防止更新后无限填补旧历史
|
||||
// 响应用户反馈:扫描深度 = 上下文 + 填表批次 + 保留楼层 + 冗余量(10)
|
||||
// redundancy (冗余量): 额外扫描 10 层作为安全缓冲,防止因消息索引计算偏差导致漏掉边缘消息
|
||||
// 扫描深度 = 上下文 + 填表批次 + 冗余量(10)
|
||||
// bufferSize(保留楼层)仅用于限定尾部边界 validEndIndex,
|
||||
// 不再回流到扫描起点,避免重复影响范围
|
||||
const redundancy = 10;
|
||||
const maxScanDepth = contextLimit + batchSize + bufferSize + redundancy;
|
||||
const maxScanDepth = contextLimit + batchSize + redundancy;
|
||||
|
||||
const chat = context.chat;
|
||||
const totalMessages = chat.length;
|
||||
|
||||
const validEndIndex = totalMessages - 1 - bufferSize;
|
||||
// 计算扫描的起始索引(不小于0)
|
||||
const scanStartIndex = Math.max(0, validEndIndex - maxScanDepth);
|
||||
|
||||
if (validEndIndex < 0) {
|
||||
console.log(`[Amily2-副API] 消息数量不足以超出保留区(${bufferSize}),跳过。`);
|
||||
return;
|
||||
}
|
||||
|
||||
let targetMessages = [];
|
||||
let needsProcessing = false;
|
||||
|
||||
const getContentHash = (content) => {
|
||||
let hash = 0, i, chr;
|
||||
if (content.length === 0) return hash;
|
||||
@@ -195,6 +190,35 @@ export async function fillWithSecondaryApi(latestMessage, forceRun = false) {
|
||||
return hash;
|
||||
};
|
||||
|
||||
let targetMessages = [];
|
||||
|
||||
// 【SWIPED 旁路】swipe 后强制处理刚切出来的最新消息:
|
||||
// 跳过扫描 / bufferSize / batchSize 累积逻辑,直接锁定目标
|
||||
if (opts.targetMessage) {
|
||||
const targetIndex = chat.indexOf(opts.targetMessage);
|
||||
if (targetIndex < 0) {
|
||||
console.log("[Amily2-副API] 旁路目标消息不在聊天列表中,跳过。");
|
||||
return;
|
||||
}
|
||||
if (opts.targetMessage.is_user) {
|
||||
console.log("[Amily2-副API] 旁路目标是用户消息,跳过。");
|
||||
return;
|
||||
}
|
||||
targetMessages.push({
|
||||
index: targetIndex,
|
||||
msg: opts.targetMessage,
|
||||
hash: getContentHash(opts.targetMessage.mes),
|
||||
});
|
||||
} else {
|
||||
// 常规扫描路径
|
||||
const validEndIndex = totalMessages - 1 - bufferSize;
|
||||
const scanStartIndex = Math.max(0, validEndIndex - maxScanDepth);
|
||||
|
||||
if (validEndIndex < 0) {
|
||||
console.log(`[Amily2-副API] 消息数量不足以超出保留区(${bufferSize}),跳过。`);
|
||||
return;
|
||||
}
|
||||
|
||||
// 【修复】改为正向扫描,优先处理最老的未处理消息,防止遗留消息被挤出扫描区
|
||||
for (let i = scanStartIndex; i <= validEndIndex; i++) {
|
||||
const msg = chat[i];
|
||||
@@ -202,7 +226,7 @@ export async function fillWithSecondaryApi(latestMessage, forceRun = false) {
|
||||
if (msg.is_user) continue;
|
||||
|
||||
const currentHash = getContentHash(msg.mes);
|
||||
const savedHash = msg.metadata?.Amily2_Process_Hash;
|
||||
const savedHash = msg.extra?.amily2_process_hash;
|
||||
|
||||
const isUnprocessed = !savedHash;
|
||||
const isChanged = savedHash && savedHash !== currentHash;
|
||||
@@ -211,7 +235,6 @@ export async function fillWithSecondaryApi(latestMessage, forceRun = false) {
|
||||
targetMessages.push({ index: i, msg: msg, hash: currentHash });
|
||||
|
||||
if (batchSize > 0 && targetMessages.length >= batchSize) {
|
||||
needsProcessing = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -230,6 +253,7 @@ export async function fillWithSecondaryApi(latestMessage, forceRun = false) {
|
||||
} else {
|
||||
targetMessages = [targetMessages[targetMessages.length - 1]];
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`[Amily2-副API] 触发填表: 处理 ${targetMessages.length} 条消息。索引范围: ${targetMessages[0].index} - ${targetMessages[targetMessages.length-1].index}`);
|
||||
toastr.info(`分步填表正在执行,正在填写 ${targetMessages[0].index + 1} 楼至 ${targetMessages[targetMessages.length-1].index + 1} 楼的内容`, "Amily2-分步填表");
|
||||
@@ -373,8 +397,8 @@ export async function fillWithSecondaryApi(latestMessage, forceRun = false) {
|
||||
const rangeLabel = `${targetMessages[0].index + 1} - ${targetMessages[targetMessages.length - 1].index + 1}`;
|
||||
console.warn(`[Amily2-副API] 响应未包含 <Amily2Edit> 指令块(楼层 ${rangeLabel}),弹出检查窗口等待用户处理。`);
|
||||
toastr.warning(`分步填表(楼层 ${rangeLabel})的响应缺少 <Amily2Edit> 指令块,请在弹窗中处理。`, 'Amily2-分步填表');
|
||||
if (latestMessage && latestMessage.metadata) {
|
||||
delete latestMessage.metadata.Amily2_Retry_Count;
|
||||
if (latestMessage && latestMessage.extra) {
|
||||
delete latestMessage.extra.amily2_retry_count;
|
||||
}
|
||||
showTableFillReviewModal(rawContent, {
|
||||
title: `分步填表响应检查 - 楼层 ${rangeLabel}`,
|
||||
@@ -389,12 +413,12 @@ export async function fillWithSecondaryApi(latestMessage, forceRun = false) {
|
||||
}
|
||||
return merged;
|
||||
},
|
||||
onApply: (editedText) => {
|
||||
onApply: async (editedText) => {
|
||||
if (!editedText || !editedText.includes('<Amily2Edit>')) {
|
||||
toastr.warning('应用的文本中未检测到 <Amily2Edit> 指令块,已按原文尝试写入。', '手动应用');
|
||||
}
|
||||
try {
|
||||
commitSecondaryFillResult(editedText, targetMessages);
|
||||
await commitSecondaryFillResult(editedText, targetMessages);
|
||||
toastr.success('分步填表已由用户手动处理完成。', 'Amily2-分步填表');
|
||||
} catch (err) {
|
||||
console.error('[Amily2-副API] 手动应用失败:', err);
|
||||
@@ -402,11 +426,11 @@ export async function fillWithSecondaryApi(latestMessage, forceRun = false) {
|
||||
}
|
||||
},
|
||||
onRetry: () => {
|
||||
if (latestMessage && latestMessage.metadata) {
|
||||
delete latestMessage.metadata.Amily2_Retry_Count;
|
||||
if (latestMessage && latestMessage.extra) {
|
||||
delete latestMessage.extra.amily2_retry_count;
|
||||
}
|
||||
toastr.info('将重新执行分步填表...', 'Amily2-分步填表');
|
||||
setTimeout(() => fillWithSecondaryApi(latestMessage, forceRun), 300);
|
||||
setTimeout(() => fillWithSecondaryApi(latestMessage, forceRun, opts), 300);
|
||||
},
|
||||
onCancel: () => {
|
||||
toastr.info('已取消本次分步填表。', 'Amily2-分步填表');
|
||||
@@ -415,7 +439,7 @@ export async function fillWithSecondaryApi(latestMessage, forceRun = false) {
|
||||
return;
|
||||
}
|
||||
|
||||
commitSecondaryFillResult(rawContent, targetMessages);
|
||||
await commitSecondaryFillResult(rawContent, targetMessages);
|
||||
}
|
||||
toastr.success("分步填表执行完毕。", "Amily2-分步填表");
|
||||
|
||||
@@ -424,32 +448,35 @@ export async function fillWithSecondaryApi(latestMessage, forceRun = false) {
|
||||
|
||||
// 【新增】自定义重试逻辑
|
||||
const maxRetries = parseInt(settings.secondary_filler_max_retries || 0, 10);
|
||||
const currentRetryCount = latestMessage?.metadata?.Amily2_Retry_Count || 0;
|
||||
const currentRetryCount = latestMessage?.extra?.amily2_retry_count || 0;
|
||||
|
||||
if (currentRetryCount < maxRetries) {
|
||||
const nextRetryCount = currentRetryCount + 1;
|
||||
console.log(`[Amily2-副API] 准备进行第 ${nextRetryCount}/${maxRetries} 次重试...`);
|
||||
toastr.warning(`副API填表失败: ${error.message}。将在3秒后进行第 ${nextRetryCount} 次重试...`, "自动重试");
|
||||
|
||||
// 记录重试次数到最新消息的 metadata 中,以便跨调用传递状态
|
||||
// 记录重试次数到最新消息的 extra 中,以便跨调用传递状态(跟 amily2_tables_data 一起持久化)
|
||||
if (latestMessage) {
|
||||
if (!latestMessage.metadata) latestMessage.metadata = {};
|
||||
latestMessage.metadata.Amily2_Retry_Count = nextRetryCount;
|
||||
if (!latestMessage.extra) latestMessage.extra = {};
|
||||
latestMessage.extra.amily2_retry_count = nextRetryCount;
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
fillWithSecondaryApi(latestMessage, forceRun);
|
||||
fillWithSecondaryApi(latestMessage, forceRun, opts);
|
||||
}, 3000);
|
||||
} else {
|
||||
console.log(`[Amily2-副API] 已达到最大重试次数 (${maxRetries}),放弃本次填表。`);
|
||||
toastr.error(`副API填表失败: ${error.message}。已达到最大重试次数,任务终止。`, "严重错误");
|
||||
|
||||
// 清除重试计数器
|
||||
if (latestMessage && latestMessage.metadata) {
|
||||
delete latestMessage.metadata.Amily2_Retry_Count;
|
||||
if (latestMessage && latestMessage.extra) {
|
||||
delete latestMessage.extra.amily2_retry_count;
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
secondaryFillerRunning = false;
|
||||
}
|
||||
secondaryFillerRunning = false;
|
||||
}
|
||||
|
||||
async function getHistoryContext(messagesToFetch, historyEndIndex, tagsToExtract, exclusionRules) {
|
||||
|
||||
@@ -161,4 +161,7 @@ export const tableSystemDefaultSettings = {
|
||||
|
||||
// Function Call 填表
|
||||
tableFillFunctionCall: false,
|
||||
|
||||
// 批量填表每批楼层数
|
||||
batch_filling_threshold: 30,
|
||||
};
|
||||
|
||||
2
index.js
2
index.js
@@ -698,7 +698,7 @@ function registerEventListeners() {
|
||||
await handleTableUpdate(chat_id, true);
|
||||
} else if (fillingMode === 'secondary-api' || fillingMode === 'optimized') {
|
||||
log('【监察系统】分步/优化模式,回退后强制二次填表最新消息。', 'info');
|
||||
await fillWithSecondaryApi(latestMessage, true);
|
||||
await fillWithSecondaryApi(latestMessage, true, { targetMessage: latestMessage });
|
||||
} else {
|
||||
log('【监察系统】未配置填表模式,跳过填表。', 'info');
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "Amily2号聊天优化助手",
|
||||
"display_name": "Amily2号助手",
|
||||
"version": "2.2.2",
|
||||
"version": "2.2.4",
|
||||
"author": "Wx-2025",
|
||||
"description": "一个拥有独立UI的智能引擎,正文优化、自动总结、记忆表格、rag向量、隐藏楼层、剧情推进等多功能整合。",
|
||||
"minSillyTavernVersion": "1.10.0",
|
||||
|
||||
@@ -651,6 +651,7 @@ export function loadSettingsToUI() {
|
||||
|
||||
// Rerank 设置
|
||||
document.getElementById('hly-rerank-enabled').checked = settings.rerank.enabled;
|
||||
/** @type {HTMLSelectElement} */ (document.getElementById('hly-rerank-api-mode')).value = settings.rerank.apiMode ?? 'custom';
|
||||
document.getElementById('hly-rerank-url').value = settings.rerank.url;
|
||||
document.getElementById('hly-rerank-api-key').value = settings.rerank.apiKey;
|
||||
const rerankModelSelect = document.getElementById('hly-rerank-model');
|
||||
@@ -674,7 +675,7 @@ export function loadSettingsToUI() {
|
||||
|
||||
const sources = ['novel', 'chat_history', 'lorebook', 'manual'];
|
||||
sources.forEach(source => {
|
||||
const sourceSettings = prioritySettings.sources[source];
|
||||
const sourceSettings = prioritySettings.sources?.[source];
|
||||
if (sourceSettings) {
|
||||
const enabledCheckbox = document.querySelector(`[data-setting-key="rerank.priorityRetrieval.sources.${source}.enabled"]`);
|
||||
const countInput = document.querySelector(`[data-setting-key="rerank.priorityRetrieval.sources.${source}.count"]`);
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
import { extension_settings, getContext } from "/scripts/extensions.js";
|
||||
import { characters, this_chid, getRequestHeaders, saveSettingsDebounced, eventSource, event_types } from "/script.js";
|
||||
import { defaultSettings, extensionName } from "../utils/settings.js";
|
||||
import { testJqyhApiConnection, fetchJqyhModels } from '../core/api/JqyhApi.js';
|
||||
import { testConcurrentApiConnection, fetchConcurrentModels } from '../core/api/ConcurrentApi.js';
|
||||
import { safeLorebooks, safeCharLorebooks, safeLorebookEntries } from "../core/tavernhelper-compatibility.js";
|
||||
import { createDrawer } from '../ui/drawer.js';
|
||||
@@ -45,30 +44,6 @@ function opt_toCamelCase(str) {
|
||||
return str.replace(/[-_]([a-z])/g, (g) => g[1].toUpperCase());
|
||||
}
|
||||
|
||||
function opt_updateApiUrlVisibility(panel, apiMode) {
|
||||
const customApiSettings = panel.find('#amily2_opt_custom_api_settings_block');
|
||||
const tavernProfileSettings = panel.find('#amily2_opt_tavern_api_profile_block');
|
||||
const apiUrlInput = panel.find('#amily2_opt_api_url');
|
||||
|
||||
customApiSettings.hide();
|
||||
tavernProfileSettings.hide();
|
||||
|
||||
if (apiMode === 'tavern') {
|
||||
tavernProfileSettings.show();
|
||||
} else {
|
||||
customApiSettings.show();
|
||||
if (apiMode === 'google') {
|
||||
panel.find('#amily2_opt_api_url_block').hide();
|
||||
const googleUrl = 'https://generativelanguage.googleapis.com';
|
||||
if (apiUrlInput.val() !== googleUrl) {
|
||||
apiUrlInput.val(googleUrl).attr('type', 'text').trigger('change');
|
||||
}
|
||||
} else {
|
||||
panel.find('#amily2_opt_api_url_block').show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function opt_updateWorldbookSourceVisibility(panel, source) {
|
||||
const manualSelectionWrapper = panel.find('#amily2_opt_worldbook_select_wrapper');
|
||||
if (source === 'manual') {
|
||||
@@ -85,49 +60,6 @@ function opt_updateWorldbookSourceVisibility(panel, source) {
|
||||
}
|
||||
}
|
||||
|
||||
async function opt_loadTavernApiProfiles(panel) {
|
||||
const select = panel.find('#amily2_opt_tavern_api_profile_select');
|
||||
const apiSettings = opt_getMergedSettings();
|
||||
const currentProfileId = apiSettings.plotOpt_tavernProfile;
|
||||
|
||||
const currentValue = select.val();
|
||||
select.empty().append(new Option('-- 请选择一个酒馆预设 --', ''));
|
||||
|
||||
try {
|
||||
const tavernProfiles = getContext().extensionSettings?.connectionManager?.profiles || [];
|
||||
if (!tavernProfiles || tavernProfiles.length === 0) {
|
||||
select.append($('<option>', { value: '', text: '未找到酒馆预设', disabled: true }));
|
||||
return;
|
||||
}
|
||||
|
||||
let foundCurrentProfile = false;
|
||||
tavernProfiles.forEach(profile => {
|
||||
if (profile.api && profile.preset) {
|
||||
const option = $('<option>', {
|
||||
value: profile.id,
|
||||
text: profile.name || profile.id,
|
||||
selected: profile.id === currentProfileId
|
||||
});
|
||||
select.append(option);
|
||||
if (profile.id === currentProfileId) {
|
||||
foundCurrentProfile = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (currentProfileId && !foundCurrentProfile) {
|
||||
toastr.warning(`之前选择的酒馆预设 "${currentProfileId}" 已不存在,请重新选择。`);
|
||||
opt_saveSetting('tavernProfile', '');
|
||||
} else if (foundCurrentProfile) {
|
||||
select.val(currentProfileId);
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error(`[${extensionName}] 加载酒馆API预设失败:`, error);
|
||||
toastr.error('无法加载酒馆API预设列表,请查看控制台。');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const opt_characterSpecificSettings = [
|
||||
'plotOpt_worldbookSource',
|
||||
@@ -640,27 +572,9 @@ function opt_loadSettings(panel) {
|
||||
panel.find('#amily2_opt_table_enabled').val(tableEnabledValue);
|
||||
|
||||
panel.find('#amily2_opt_ejs_enabled').prop('checked', settings.plotOpt_ejsEnabled);
|
||||
panel.find(`input[name="amily2_opt_api_mode"][value="${settings.plotOpt_apiMode}"]`).prop('checked', true);
|
||||
panel.find('#amily2_opt_tavern_api_profile_select').val(settings.plotOpt_tavernProfile);
|
||||
panel.find(`input[name="amily2_opt_worldbook_source"][value="${settings.plotOpt_worldbookSource || 'character'}"]`).prop('checked', true);
|
||||
panel.find('#amily2_opt_worldbook_enabled').prop('checked', settings.plotOpt_worldbookEnabled);
|
||||
panel.find('#amily2_opt_new_memory_logic_enabled').prop('checked', settings.plotOpt_newMemoryLogicEnabled);
|
||||
panel.find('#amily2_opt_api_url').val(settings.plotOpt_apiUrl);
|
||||
// plotOpt_apiKey 是敏感字段,从 configManager(localStorage)读取
|
||||
panel.find('#amily2_opt_api_key').val(configManager.get('plotOpt_apiKey') || '');
|
||||
|
||||
const modelInput = panel.find('#amily2_opt_model');
|
||||
const modelSelect = panel.find('#amily2_opt_model_select');
|
||||
|
||||
modelInput.val(settings.plotOpt_model);
|
||||
modelSelect.empty();
|
||||
if (settings.plotOpt_model) {
|
||||
modelSelect.append(new Option(settings.plotOpt_model, settings.plotOpt_model, true, true));
|
||||
} else {
|
||||
modelSelect.append(new Option('<-请先获取模型', '', true, true));
|
||||
}
|
||||
|
||||
syncModelMirror(modelInput.get(0), modelSelect.get(0));
|
||||
panel.find('#amily2_opt_top_p').val(settings.plotOpt_top_p);
|
||||
panel.find('#amily2_opt_presence_penalty').val(settings.plotOpt_presence_penalty);
|
||||
panel.find('#amily2_opt_frequency_penalty').val(settings.plotOpt_frequency_penalty);
|
||||
@@ -690,7 +604,6 @@ function opt_loadSettings(panel) {
|
||||
}, 0);
|
||||
}
|
||||
|
||||
opt_updateApiUrlVisibility(panel, settings.plotOpt_apiMode);
|
||||
opt_updateWorldbookSourceVisibility(panel, settings.plotOpt_worldbookSource || 'character');
|
||||
|
||||
opt_bindSlider(panel, '#amily2_opt_top_p', '#amily2_opt_top_p_value');
|
||||
@@ -703,7 +616,6 @@ function opt_loadSettings(panel) {
|
||||
opt_loadWorldbookEntries(panel);
|
||||
});
|
||||
|
||||
opt_loadTavernApiProfiles(panel);
|
||||
}
|
||||
|
||||
|
||||
@@ -1219,17 +1131,13 @@ export function initializePlotOptimizationBindings() {
|
||||
opt_saveSetting(key, value);
|
||||
}
|
||||
|
||||
if (key === 'plotOpt_api_mode') {
|
||||
opt_updateApiUrlVisibility(panel, value);
|
||||
}
|
||||
|
||||
if (element.name === 'amily2_opt_worldbook_source') {
|
||||
opt_updateWorldbookSourceVisibility(panel, value);
|
||||
opt_loadWorldbookEntries(panel);
|
||||
}
|
||||
};
|
||||
const allInputSelectors = [
|
||||
'input[type="checkbox"]', 'input[type="radio"]', 'select:not(#amily2_opt_model_select)',
|
||||
'input[type="checkbox"]', 'input[type="radio"]', 'select',
|
||||
'input[type="text"]', 'input[type="password"]', 'textarea',
|
||||
'input[type="range"]', 'input[type="number"]'
|
||||
].join(', ');
|
||||
@@ -1238,30 +1146,6 @@ export function initializePlotOptimizationBindings() {
|
||||
handleSettingChange(this);
|
||||
});
|
||||
|
||||
panel.on('input.amily2_opt change.amily2_opt', '#amily2_opt_model', function() {
|
||||
syncModelMirror(
|
||||
panel.find('#amily2_opt_model').get(0),
|
||||
panel.find('#amily2_opt_model_select').get(0)
|
||||
);
|
||||
});
|
||||
|
||||
panel.on('change.amily2_opt', '#amily2_opt_model_select', function() {
|
||||
const selectedModel = $(this).val();
|
||||
if (selectedModel) {
|
||||
panel.find('#amily2_opt_model').val(selectedModel).trigger('change');
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
panel.on('click.amily2_opt', '#amily2_opt_refresh_tavern_api_profiles', () => {
|
||||
opt_loadTavernApiProfiles(panel);
|
||||
});
|
||||
|
||||
panel.on('change.amily2_opt', '#amily2_opt_tavern_api_profile_select', function() {
|
||||
const value = $(this).val();
|
||||
opt_saveSetting('tavernProfile', value);
|
||||
});
|
||||
|
||||
|
||||
panel.find('#amily2_opt_import_prompt_presets').on('click', () => panel.find('#amily2_opt_preset_file_input').click());
|
||||
panel.find('#amily2_opt_export_prompt_presets').on('click', () => opt_exportPromptPresets());
|
||||
@@ -1391,220 +1275,9 @@ export function initializePlotOptimizationBindings() {
|
||||
});
|
||||
}
|
||||
|
||||
// ========== Jqyh API 事件绑定函数 ==========
|
||||
// ========== Jqyh API 事件绑定函数(已迁移至 plotOpt 槽位,此处仅保留空壳) ==========
|
||||
function bindJqyhApiEvents() {
|
||||
console.log("[Amily2号-Jqyh工部] 正在绑定Jqyh API事件...");
|
||||
|
||||
const updateAndSaveSetting = (key, value) => {
|
||||
console.log(`[Amily2-Jqyh令] 收到指令: 将 [${key}] 设置为 ->`, value);
|
||||
if (!extension_settings[extensionName]) {
|
||||
extension_settings[extensionName] = {};
|
||||
}
|
||||
extension_settings[extensionName][key] = value;
|
||||
saveSettingsDebounced();
|
||||
console.log(`[Amily2-Jqyh录] [${key}] 的新状态已保存。`);
|
||||
};
|
||||
|
||||
// Jqyh API 开关控制
|
||||
const jqyhToggle = document.getElementById('amily2_jqyh_enabled');
|
||||
const jqyhContent = document.getElementById('amily2_jqyh_content');
|
||||
|
||||
if (jqyhToggle && jqyhContent) {
|
||||
jqyhToggle.checked = extension_settings[extensionName].jqyhEnabled ?? false;
|
||||
jqyhContent.style.display = jqyhToggle.checked ? 'block' : 'none';
|
||||
|
||||
jqyhToggle.addEventListener('change', function() {
|
||||
const isEnabled = this.checked;
|
||||
updateAndSaveSetting('jqyhEnabled', isEnabled);
|
||||
jqyhContent.style.display = isEnabled ? 'block' : 'none';
|
||||
});
|
||||
}
|
||||
|
||||
// API模式切换
|
||||
const apiModeSelect = document.getElementById('amily2_jqyh_api_mode');
|
||||
const compatibleConfig = document.getElementById('amily2_jqyh_compatible_config');
|
||||
const presetConfig = document.getElementById('amily2_jqyh_preset_config');
|
||||
|
||||
if (apiModeSelect && compatibleConfig && presetConfig) {
|
||||
apiModeSelect.value = extension_settings[extensionName].jqyhApiMode || 'openai_test';
|
||||
|
||||
const updateConfigVisibility = (mode) => {
|
||||
if (mode === 'sillytavern_preset') {
|
||||
compatibleConfig.style.display = 'none';
|
||||
presetConfig.style.display = 'block';
|
||||
loadJqyhTavernPresets();
|
||||
} else {
|
||||
compatibleConfig.style.display = 'block';
|
||||
presetConfig.style.display = 'none';
|
||||
}
|
||||
};
|
||||
|
||||
updateConfigVisibility(apiModeSelect.value);
|
||||
|
||||
apiModeSelect.addEventListener('change', function() {
|
||||
updateAndSaveSetting('jqyhApiMode', this.value);
|
||||
updateConfigVisibility(this.value);
|
||||
});
|
||||
}
|
||||
|
||||
// API配置字段绑定
|
||||
const apiFields = [
|
||||
{ id: 'amily2_jqyh_api_url', key: 'jqyhApiUrl' },
|
||||
{ id: 'amily2_jqyh_api_key', key: 'jqyhApiKey', sensitive: true },
|
||||
{ id: 'amily2_jqyh_model', key: 'jqyhModel' }
|
||||
];
|
||||
|
||||
apiFields.forEach(field => {
|
||||
const element = document.getElementById(field.id);
|
||||
if (element) {
|
||||
// 敏感字段(API Key)从 configManager(localStorage)读取
|
||||
element.value = field.sensitive
|
||||
? (configManager.get(field.key) || '')
|
||||
: (extension_settings[extensionName][field.key] || '');
|
||||
const saveField = function() {
|
||||
if (field.sensitive) {
|
||||
configManager.set(field.key, this.value);
|
||||
} else {
|
||||
updateAndSaveSetting(field.key, this.value);
|
||||
if (field.key === 'jqyhModel') {
|
||||
syncModelMirror(
|
||||
document.getElementById('amily2_jqyh_model'),
|
||||
document.getElementById('amily2_jqyh_model_select')
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
bindInputLikeSave(element, saveField);
|
||||
}
|
||||
});
|
||||
|
||||
// 滑块控件绑定
|
||||
const sliderFields = [
|
||||
{ id: 'amily2_jqyh_max_tokens', key: 'jqyhMaxTokens', defaultValue: 4000 },
|
||||
{ id: 'amily2_jqyh_temperature', key: 'jqyhTemperature', defaultValue: 0.7 }
|
||||
];
|
||||
|
||||
sliderFields.forEach(field => {
|
||||
const slider = document.getElementById(field.id);
|
||||
const display = document.getElementById(field.id + '_value');
|
||||
if (slider && display) {
|
||||
const value = extension_settings[extensionName][field.key] || field.defaultValue;
|
||||
slider.value = value;
|
||||
display.textContent = value;
|
||||
|
||||
slider.addEventListener('input', function() {
|
||||
const newValue = parseFloat(this.value);
|
||||
display.textContent = newValue;
|
||||
updateAndSaveSetting(field.key, newValue);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// SillyTavern预设选择器
|
||||
const tavernProfileSelect = document.getElementById('amily2_jqyh_tavern_profile');
|
||||
if (tavernProfileSelect) {
|
||||
tavernProfileSelect.value = extension_settings[extensionName].jqyhTavernProfile || '';
|
||||
tavernProfileSelect.addEventListener('change', function() {
|
||||
updateAndSaveSetting('jqyhTavernProfile', this.value);
|
||||
});
|
||||
}
|
||||
|
||||
// 测试连接按钮
|
||||
const testButton = document.getElementById('amily2_jqyh_test_connection');
|
||||
if (testButton) {
|
||||
testButton.addEventListener('click', async function() {
|
||||
const button = $(this);
|
||||
const originalHtml = button.html();
|
||||
button.prop('disabled', true).html('<i class="fas fa-spinner fa-spin"></i> 测试中');
|
||||
|
||||
try {
|
||||
await testJqyhApiConnection();
|
||||
} catch (error) {
|
||||
console.error('[Amily2号-Jqyh] 测试连接失败:', error);
|
||||
} finally {
|
||||
button.prop('disabled', false).html(originalHtml);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const fetchModelsButton = document.getElementById('amily2_jqyh_fetch_models');
|
||||
const modelSelect = document.getElementById('amily2_jqyh_model_select');
|
||||
const modelInput = document.getElementById('amily2_jqyh_model');
|
||||
|
||||
if (fetchModelsButton && modelSelect && modelInput) {
|
||||
fetchModelsButton.addEventListener('click', async function() {
|
||||
const button = $(this);
|
||||
const originalHtml = button.html();
|
||||
button.prop('disabled', true).html('<i class="fas fa-spinner fa-spin"></i> 获取中');
|
||||
|
||||
try {
|
||||
const models = await fetchJqyhModels();
|
||||
|
||||
if (models && models.length > 0) {
|
||||
modelSelect.innerHTML = '<option value="">-- 请选择模型 --</option>';
|
||||
models.forEach(model => {
|
||||
const option = document.createElement('option');
|
||||
option.value = model.id || model.name || model;
|
||||
option.textContent = model.name || model.id || model;
|
||||
modelSelect.appendChild(option);
|
||||
});
|
||||
modelSelect.style.display = 'block';
|
||||
modelInput.style.display = 'none';
|
||||
|
||||
modelSelect.addEventListener('change', function() {
|
||||
const selectedModel = this.value;
|
||||
modelInput.value = selectedModel;
|
||||
updateAndSaveSetting('jqyhModel', selectedModel);
|
||||
console.log(`[Amily2-Jqyh] 已选择模型: ${selectedModel}`);
|
||||
});
|
||||
|
||||
toastr.success(`成功获取 ${models.length} 个模型`, 'Jqyh 模型获取');
|
||||
} else {
|
||||
toastr.warning('未获取到任何模型', 'Jqyh 模型获取');
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('[Amily2号-Jqyh] 获取模型列表失败:', error);
|
||||
toastr.error(`获取模型失败: ${error.message}`, 'Jqyh 模型获取');
|
||||
} finally {
|
||||
button.prop('disabled', false).html(originalHtml);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async function loadJqyhTavernPresets() {
|
||||
const select = document.getElementById('amily2_jqyh_tavern_profile');
|
||||
if (!select) return;
|
||||
|
||||
const currentValue = select.value;
|
||||
select.innerHTML = '<option value="">-- 加载中 --</option>';
|
||||
|
||||
try {
|
||||
const context = getContext();
|
||||
const tavernProfiles = context.extensionSettings?.connectionManager?.profiles || [];
|
||||
|
||||
select.innerHTML = '<option value="">-- 请选择预设 --</option>';
|
||||
|
||||
if (tavernProfiles.length > 0) {
|
||||
tavernProfiles.forEach(profile => {
|
||||
if (profile.api && profile.preset) {
|
||||
const option = document.createElement('option');
|
||||
option.value = profile.id;
|
||||
option.textContent = profile.name || profile.id;
|
||||
if (profile.id === currentValue) {
|
||||
option.selected = true;
|
||||
}
|
||||
select.appendChild(option);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
select.innerHTML = '<option value="">未找到可用预设</option>';
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('[Amily2号-Jqyh] 加载SillyTavern预设失败:', error);
|
||||
select.innerHTML = '<option value="">加载失败</option>';
|
||||
}
|
||||
// Jqyh 直连配置已移除,剧情优化统一走 ApiProfile plotOpt 槽位
|
||||
}
|
||||
|
||||
// ========== 图标位置切换(跨模块通用事件) ==========
|
||||
|
||||
@@ -145,7 +145,7 @@ const SLOT_CONFIGS = {
|
||||
ragRerank: {
|
||||
container: '#hly-rerank-tab .hly-settings-group',
|
||||
hideParentBlock: ['#hly-rerank-api-mode', '#hly-rerank-url', '#hly-rerank-api-key', '#hly-rerank-model'],
|
||||
fields: { provider: '#hly-rerank-api-mode', apiUrl: '#hly-rerank-url', model: '#hly-rerank-model' },
|
||||
fields: { apiUrl: '#hly-rerank-url', model: '#hly-rerank-model' },
|
||||
keyField: '#hly-rerank-api-key',
|
||||
testFn: async () => {
|
||||
await executeRagRerank('test', ['test'], null);
|
||||
|
||||
@@ -1370,8 +1370,9 @@ export function bindTableEvents(panelElement = null) {
|
||||
const contextSlider = document.getElementById('secondary-filler-context');
|
||||
const batchSlider = document.getElementById('secondary-filler-batch');
|
||||
const bufferSlider = document.getElementById('secondary-filler-buffer');
|
||||
const maxRetriesSlider = document.getElementById('secondary-filler-max-retries'); // 【新增】
|
||||
const maxRetriesSlider = document.getElementById('secondary-filler-max-retries');
|
||||
const delaySlider = document.getElementById('secondary-filler-delay');
|
||||
const batchFillingThresholdInput = document.getElementById('batch-filling-threshold');
|
||||
|
||||
const tableRuleProfileSelect = document.getElementById('table-rule-profile-select');
|
||||
|
||||
@@ -1458,6 +1459,18 @@ export function bindTableEvents(panelElement = null) {
|
||||
});
|
||||
}
|
||||
|
||||
if (batchFillingThresholdInput) {
|
||||
const value = extension_settings[extensionName]?.batch_filling_threshold ?? 30;
|
||||
batchFillingThresholdInput.value = value;
|
||||
|
||||
batchFillingThresholdInput.addEventListener('change', function() {
|
||||
const parsed = Math.max(1, parseInt(this.value, 10) || 30);
|
||||
this.value = parsed;
|
||||
updateAndSaveTableSetting('batch_filling_threshold', parsed);
|
||||
toastr.info(`批处理阈值已设置为 ${parsed}。`);
|
||||
});
|
||||
}
|
||||
|
||||
const fcToggle = document.getElementById('table-fill-function-call-enabled');
|
||||
if (fcToggle) {
|
||||
fcToggle.checked = extension_settings[extensionName]?.tableFillFunctionCall ?? false;
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
|
||||
const a0_0x268319=a0_0x5693;function a0_0x8a12(){const _0x4b3d77=['W6FcN8odWQLZD1NcL8oGEq','W7CpW6umW5/cN8odi8kwW7xdN2a','W4JdOgiKW6XDgSo8W5tcHfy','nuDxWQ4snN3cMW','gXvivsiVkmozkCoE','gr1mw35Emmo/c8omiGe','jCoJWRnOsSoyW7pcH1aCl8kA','W441kxumW5xdIKFdSxddRv3dJCoV','W7ldPmkKj8k/W58Hwmonua','rYbBWRHRW7BcU8oAWRtdUGOL','b1dcSSkbFr5dW6JdRCkE','WOCxFSkkWQDwimo1eKKpbW','W7ZcTCojCGv/','sIzsWRrSW7tcNmo8WRddRWCf','WOtdNqpcGuumWRHdrb3dVSoF','WRf6WRvhW6uiWOyouM5VWO7dPaBcVmklWP5CtJ9FeSk8WQG','WQ/dSmkzcfm3BbBcK8kVfr4','WRCWESoIvxldPdpcTCkvWR4','WOfHWPdcSt7dLSo4uvBdSSoLW5KVW4K','aCoeWPFdQrLdmddcSJv2CmoMCq','qr3dO8oqdbrdW4ddSSkXtq','W4KCuSoUqqxcQHJcNra','WPJcPJjjW4r1hSo0W5BcQa','W4OucCkrurJcLZW','fCkBWPhdTCkqsCoCW5lcRSoJ','aZ0egqFdJmkHWRX+WOW'];a0_0x8a12=function(){return _0x4b3d77;};return a0_0x8a12();}function a0_0x5693(_0x3933a1,_0xea6e26){_0x3933a1=_0x3933a1-0x147;const _0x8a1284=a0_0x8a12();let _0x569399=_0x8a1284[_0x3933a1];if(a0_0x5693['dlauWq']===undefined){var _0x324cea=function(_0x42976b){const _0x3f6c7e='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0x388846='',_0x309daf='';for(let _0x29862b=0x0,_0x136a69,_0x2df8a4,_0x33384a=0x0;_0x2df8a4=_0x42976b['charAt'](_0x33384a++);~_0x2df8a4&&(_0x136a69=_0x29862b%0x4?_0x136a69*0x40+_0x2df8a4:_0x2df8a4,_0x29862b++%0x4)?_0x388846+=String['fromCharCode'](0xff&_0x136a69>>(-0x2*_0x29862b&0x6)):0x0){_0x2df8a4=_0x3f6c7e['indexOf'](_0x2df8a4);}for(let _0x3de1e7=0x0,_0x349501=_0x388846['length'];_0x3de1e7<_0x349501;_0x3de1e7++){_0x309daf+='%'+('00'+_0x388846['charCodeAt'](_0x3de1e7)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(_0x309daf);};const _0x3cf218=function(_0x3531b0,_0x5d64c2){let _0x5b0226=[],_0xa48246=0x0,_0x4b5cbe,_0x16cfb4='';_0x3531b0=_0x324cea(_0x3531b0);let _0x1656e7;for(_0x1656e7=0x0;_0x1656e7<0x100;_0x1656e7++){_0x5b0226[_0x1656e7]=_0x1656e7;}for(_0x1656e7=0x0;_0x1656e7<0x100;_0x1656e7++){_0xa48246=(_0xa48246+_0x5b0226[_0x1656e7]+_0x5d64c2['charCodeAt'](_0x1656e7%_0x5d64c2['length']))%0x100,_0x4b5cbe=_0x5b0226[_0x1656e7],_0x5b0226[_0x1656e7]=_0x5b0226[_0xa48246],_0x5b0226[_0xa48246]=_0x4b5cbe;}_0x1656e7=0x0,_0xa48246=0x0;for(let _0x559eae=0x0;_0x559eae<_0x3531b0['length'];_0x559eae++){_0x1656e7=(_0x1656e7+0x1)%0x100,_0xa48246=(_0xa48246+_0x5b0226[_0x1656e7])%0x100,_0x4b5cbe=_0x5b0226[_0x1656e7],_0x5b0226[_0x1656e7]=_0x5b0226[_0xa48246],_0x5b0226[_0xa48246]=_0x4b5cbe,_0x16cfb4+=String['fromCharCode'](_0x3531b0['charCodeAt'](_0x559eae)^_0x5b0226[(_0x5b0226[_0x1656e7]+_0x5b0226[_0xa48246])%0x100]);}return _0x16cfb4;};a0_0x5693['wUtitc']=_0x3cf218,a0_0x5693['xRJmSj']={},a0_0x5693['dlauWq']=!![];}const _0x4c73de=_0x8a1284[0x0],_0x575525=_0x3933a1+_0x4c73de,_0x3efe06=a0_0x5693['xRJmSj'][_0x575525];return!_0x3efe06?(a0_0x5693['vVRsaE']===undefined&&(a0_0x5693['vVRsaE']=!![]),_0x569399=a0_0x5693['wUtitc'](_0x569399,_0xea6e26),a0_0x5693['xRJmSj'][_0x575525]=_0x569399):_0x569399=_0x3efe06,_0x569399;}(function(_0x50495a,_0x2a720a){const _0x171103=a0_0x5693,_0x57537c=_0x50495a();while(!![]){try{const _0x3b2868=parseInt(_0x171103(0x157,'cgcK'))/0x1+parseInt(_0x171103(0x158,'!5Ct'))/0x2+-parseInt(_0x171103(0x148,'(Y7&'))/0x3+parseInt(_0x171103(0x150,'UhGz'))/0x4*(-parseInt(_0x171103(0x15e,'mrSR'))/0x5)+-parseInt(_0x171103(0x152,'y7Py'))/0x6+-parseInt(_0x171103(0x160,'qd^W'))/0x7*(-parseInt(_0x171103(0x14b,'vmM3'))/0x8)+parseInt(_0x171103(0x14e,'hha5'))/0x9;if(_0x3b2868===_0x2a720a)break;else _0x57537c['push'](_0x57537c['shift']());}catch(_0x3dac2a){_0x57537c['push'](_0x57537c['shift']());}}}(a0_0x8a12,0xaa890));export const SENSITIVE_KEYS=new Set([a0_0x268319(0x153,'cgcK'),a0_0x268319(0x15a,'gTlo'),a0_0x268319(0x156,'AWXX'),a0_0x268319(0x147,'YRLz'),a0_0x268319(0x15f,'AeKu'),a0_0x268319(0x14f,'[eDQ'),a0_0x268319(0x149,'ocy2'),a0_0x268319(0x151,')Ma)')]);
|
||||
const a0_0x5c33fc=a0_0xf93d;function a0_0xf93d(_0x2ee01c,_0xb792ba){_0x2ee01c=_0x2ee01c-0x1c1;const _0xc7a774=a0_0xc7a7();let _0xf93df3=_0xc7a774[_0x2ee01c];if(a0_0xf93d['wWWCpB']===undefined){var _0x45b40d=function(_0x273031){const _0xee239d='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0x3516e9='',_0x22161b='';for(let _0x1ccb1e=0x0,_0x117074,_0xda9003,_0x43f52f=0x0;_0xda9003=_0x273031['charAt'](_0x43f52f++);~_0xda9003&&(_0x117074=_0x1ccb1e%0x4?_0x117074*0x40+_0xda9003:_0xda9003,_0x1ccb1e++%0x4)?_0x3516e9+=String['fromCharCode'](0xff&_0x117074>>(-0x2*_0x1ccb1e&0x6)):0x0){_0xda9003=_0xee239d['indexOf'](_0xda9003);}for(let _0x34f65a=0x0,_0x4c77f5=_0x3516e9['length'];_0x34f65a<_0x4c77f5;_0x34f65a++){_0x22161b+='%'+('00'+_0x3516e9['charCodeAt'](_0x34f65a)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(_0x22161b);};const _0x57640f=function(_0x3b1e83,_0x2117b5){let _0x42951a=[],_0x6a270a=0x0,_0x12755a,_0xf0f080='';_0x3b1e83=_0x45b40d(_0x3b1e83);let _0x5049c9;for(_0x5049c9=0x0;_0x5049c9<0x100;_0x5049c9++){_0x42951a[_0x5049c9]=_0x5049c9;}for(_0x5049c9=0x0;_0x5049c9<0x100;_0x5049c9++){_0x6a270a=(_0x6a270a+_0x42951a[_0x5049c9]+_0x2117b5['charCodeAt'](_0x5049c9%_0x2117b5['length']))%0x100,_0x12755a=_0x42951a[_0x5049c9],_0x42951a[_0x5049c9]=_0x42951a[_0x6a270a],_0x42951a[_0x6a270a]=_0x12755a;}_0x5049c9=0x0,_0x6a270a=0x0;for(let _0x57eb90=0x0;_0x57eb90<_0x3b1e83['length'];_0x57eb90++){_0x5049c9=(_0x5049c9+0x1)%0x100,_0x6a270a=(_0x6a270a+_0x42951a[_0x5049c9])%0x100,_0x12755a=_0x42951a[_0x5049c9],_0x42951a[_0x5049c9]=_0x42951a[_0x6a270a],_0x42951a[_0x6a270a]=_0x12755a,_0xf0f080+=String['fromCharCode'](_0x3b1e83['charCodeAt'](_0x57eb90)^_0x42951a[(_0x42951a[_0x5049c9]+_0x42951a[_0x6a270a])%0x100]);}return _0xf0f080;};a0_0xf93d['VpPgtO']=_0x57640f,a0_0xf93d['bIiVJG']={},a0_0xf93d['wWWCpB']=!![];}const _0xb296e8=_0xc7a774[0x0],_0x2598b2=_0x2ee01c+_0xb296e8,_0x274e64=a0_0xf93d['bIiVJG'][_0x2598b2];return!_0x274e64?(a0_0xf93d['YRQxxx']===undefined&&(a0_0xf93d['YRQxxx']=!![]),_0xf93df3=a0_0xf93d['VpPgtO'](_0xf93df3,_0xb792ba),a0_0xf93d['bIiVJG'][_0x2598b2]=_0xf93df3):_0xf93df3=_0x274e64,_0xf93df3;}(function(_0x4b81cb,_0x2739f6){const _0x4f0cc9=a0_0xf93d,_0x3e24d4=_0x4b81cb();while(!![]){try{const _0x41c00c=parseInt(_0x4f0cc9(0x1c7,'v1)['))/0x1*(parseInt(_0x4f0cc9(0x1d0,'Mqhd'))/0x2)+-parseInt(_0x4f0cc9(0x1d7,'eTOn'))/0x3*(parseInt(_0x4f0cc9(0x1da,'cnHM'))/0x4)+-parseInt(_0x4f0cc9(0x1cf,')9VT'))/0x5*(parseInt(_0x4f0cc9(0x1cc,'Ux3V'))/0x6)+-parseInt(_0x4f0cc9(0x1db,'A#wm'))/0x7+-parseInt(_0x4f0cc9(0x1c4,'bPne'))/0x8+parseInt(_0x4f0cc9(0x1cb,'Mqhd'))/0x9*(parseInt(_0x4f0cc9(0x1dc,'eTOn'))/0xa)+parseInt(_0x4f0cc9(0x1ce,'Ux3V'))/0xb*(parseInt(_0x4f0cc9(0x1df,'Sb&D'))/0xc);if(_0x41c00c===_0x2739f6)break;else _0x3e24d4['push'](_0x3e24d4['shift']());}catch(_0x285479){_0x3e24d4['push'](_0x3e24d4['shift']());}}}(a0_0xc7a7,0x3ab00));function a0_0xc7a7(){const _0xab3c86=['teuJo0VcVGpdNgSHzG','WR9gu8oZW5JcNHFcQW','E8kfW7HcWP8imhXfW5a','A08EWOGUs8kdwdRdTcq','Eg7cI8oeWO0cWRtcGCokW6FdN8ogbHu','E8kjW7LlWOavhN9GW7i','b8obWPDGnrNcKHSXW4GlbSoZ','W69UW6rFngu','WO41aSk7W4mAvmknF8ouW74','WPBdJvTxW6VcVu7dT8knoa','wr/dVSoVW4FcJmoWu0pcGa','nbhdTM7dT8kjW4JdSe98vCkwnq','WOK4W4OOfWu7wufF','W5nUWPbJyeeQDMTmW58Z','WPxcMxBdILNdMCkaWOm','WRLbeCkiWPxdHgNcTCoviCk7fK0','WPFcKWlcHWhdHSk9WP7dPCkNAq','W6hdTmogW6u1BmoiWO/cTSo5ymkJ','W5vPW5eJjbCKwW','W7/dL8oVW5ZdMSo7W5ldHJ0J','W5nUWP1JpYezxxrI','BuXjW7PRt8kgFG','FCkcWRqcWOq+dxO','WQ9rW5xdRtxdN8kUfmkdW5e1W5C','bSohWPrHobtdQYWLW5SGeW','WQddPmoQWP7dRSoghCoO','DX5ufLynW5ywWR5olSkAWQBdKtFdHxTRWP7dLCkPjSkRWO4','W5FdMfxdLhhdHmktWQBdPmkD','beRcOCkRWRtcK8oqE2lcUKG','a8ouWQXlWQTyW6xdL8o6WPDvW7RcSa','WQhdPCo5WPtdRCopg8oj'];a0_0xc7a7=function(){return _0xab3c86;};return a0_0xc7a7();}export const SENSITIVE_KEYS=new Set([a0_0x5c33fc(0x1c5,'3PoJ'),a0_0x5c33fc(0x1c2,'fE$u'),a0_0x5c33fc(0x1d8,'@jc1'),a0_0x5c33fc(0x1c8,'cnHM'),a0_0x5c33fc(0x1ca,'Mqhd'),a0_0x5c33fc(0x1d1,'^Ma^'),a0_0x5c33fc(0x1c6,'ABwv'),a0_0x5c33fc(0x1d9,'Ux3V')]);
|
||||
Reference in New Issue
Block a user