mirror of
https://github.com/Wx-2025/ST-Amily2-Chat-Optimisation.git
synced 2026-06-06 01:05:50 +00:00
ci: auto build & obfuscate [2026-04-23 00:35:57] (Jenkins #17)
This commit is contained in:
@@ -679,11 +679,6 @@ export async function callCustomOpenAI(messages) {
|
||||
const headers = { ...getRequestHeaders(), 'Content-Type': 'application/json' };
|
||||
const body = JSON.stringify(requestBody);
|
||||
|
||||
console.groupCollapsed(`[CWB] API Call @ ${new Date().toLocaleTimeString()}`);
|
||||
console.log('Request URL:', fullApiUrl);
|
||||
console.log('Request Headers:', headers);
|
||||
console.log('Request Body:', requestBody);
|
||||
|
||||
try {
|
||||
const response = await fetch(fullApiUrl, {
|
||||
method: 'POST',
|
||||
@@ -693,27 +688,19 @@ export async function callCustomOpenAI(messages) {
|
||||
|
||||
if (!response.ok) {
|
||||
const errTxt = await response.text();
|
||||
console.error('API Error Response:', errTxt);
|
||||
throw new Error(`API请求失败: ${response.status} ${errTxt}`);
|
||||
}
|
||||
const data = await response.json();
|
||||
console.log('API Full Response:', data);
|
||||
|
||||
|
||||
if (data.choices && data.choices[0]?.message?.content) {
|
||||
console.log('Extracted Content:', data.choices[0].message.content.trim());
|
||||
console.groupEnd();
|
||||
return data.choices[0].message.content.trim();
|
||||
}
|
||||
|
||||
|
||||
throw new Error('API响应格式不正确。');
|
||||
|
||||
} catch (error) {
|
||||
console.error('API Call Failed:', error);
|
||||
console.error('[CWB] API Call Failed:', error);
|
||||
throw error;
|
||||
} finally {
|
||||
if (console.groupEnd) {
|
||||
console.groupEnd();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -322,8 +322,6 @@ export function bindSettingsEvents($settingsPanel) {
|
||||
configManager.set('cwb_api_key', apiKey);
|
||||
state.customApiConfig.apiKey = apiKey;
|
||||
updateApiStatusDisplay($panel);
|
||||
|
||||
console.log('[CWB] API Key已更新 - 状态长度:', state.customApiConfig.apiKey?.length || 0);
|
||||
});
|
||||
|
||||
$panel.on('input change', '#cwb-api-model', function(event) {
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
<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 class="amily2-rule-layout">
|
||||
<div class="amily2-rule-sidebar">
|
||||
<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-rule-main">
|
||||
<div class="amily2_settings_block">
|
||||
<label for="amily2_rule_profile_name">配置名称</label>
|
||||
<input id="amily2_rule_profile_name" class="text_pole" type="text" placeholder="例如:通用提取规则">
|
||||
@@ -25,7 +25,7 @@
|
||||
<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;">
|
||||
<div class="amily2-rule-actions">
|
||||
<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>
|
||||
@@ -42,4 +42,39 @@
|
||||
gap: 8px;
|
||||
align-items: center;
|
||||
}
|
||||
#amily2_rule_config_panel_root .amily2-rule-layout {
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
align-items: flex-start;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
#amily2_rule_config_panel_root .amily2-rule-sidebar {
|
||||
width: 260px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
#amily2_rule_config_panel_root .amily2-rule-main {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
#amily2_rule_config_panel_root .amily2-rule-actions {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
margin-top: 16px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
@media (max-width: 768px) {
|
||||
#amily2_rule_config_panel_root .amily2-rule-sidebar {
|
||||
width: 100%;
|
||||
}
|
||||
#amily2_rule_config_panel_root .amily2-rule-actions > .amily2-vbtn {
|
||||
flex: 1 1 calc(33.333% - 8px);
|
||||
min-width: 72px;
|
||||
}
|
||||
#amily2_rule_config_panel_root .amily2-rule-row {
|
||||
grid-template-columns: 1fr 1fr !important;
|
||||
}
|
||||
#amily2_rule_config_panel_root .amily2-rule-row > :last-child {
|
||||
grid-column: 1 / -1;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -179,9 +179,12 @@ class Amily2Updater {
|
||||
if (this.compareVersions(this.latestVersion, this.currentVersion) > 0) {
|
||||
$updateIndicator.show();
|
||||
$updateButton.attr('title', `发现新版本 ${this.latestVersion}!点击查看详情`);
|
||||
const safeVersion = /^[\w.+\-]{1,40}$/.test(String(this.latestVersion ?? '')) ? this.latestVersion : '未知';
|
||||
$updateButtonNew
|
||||
.show()
|
||||
.html(`<i class="fas fa-gift"></i> 新版 ${this.latestVersion}`)
|
||||
.empty()
|
||||
.append($('<i>').addClass('fas fa-gift'))
|
||||
.append(document.createTextNode(` 新版 ${safeVersion}`))
|
||||
.off('click')
|
||||
.on('click', () => this.showUpdateConfirmDialog());
|
||||
} else {
|
||||
|
||||
17
core/api.js
17
core/api.js
@@ -330,10 +330,12 @@ async function fetchGoogleDirectModels(apiUrl, apiKey) {
|
||||
const GOOGLE_API_BASE_URL = 'https://generativelanguage.googleapis.com';
|
||||
|
||||
const fetchGoogleModels = async (version) => {
|
||||
const url = `${GOOGLE_API_BASE_URL}/${version}/models?key=${apiKey}`;
|
||||
const url = `${GOOGLE_API_BASE_URL}/${version}/models`;
|
||||
console.log(`[Amily2号-使节团] 正在从 Google API (${version}) 获取模型列表: ${url}`);
|
||||
|
||||
const response = await fetch(url);
|
||||
|
||||
const response = await fetch(url, {
|
||||
headers: { 'x-goog-api-key': apiKey },
|
||||
});
|
||||
if (!response.ok) {
|
||||
console.warn(`获取 Google API (${version}) 模型列表失败: ${response.status}`);
|
||||
return [];
|
||||
@@ -745,12 +747,13 @@ async function callGoogleDirect(messages, options) {
|
||||
const GOOGLE_API_BASE_URL = 'https://generativelanguage.googleapis.com';
|
||||
|
||||
const apiVersion = options.model.includes('gemini-1.5') ? 'v1beta' : 'v1';
|
||||
const finalApiUrl = `${GOOGLE_API_BASE_URL}/${apiVersion}/models/${options.model}:generateContent?key=${options.apiKey}`;
|
||||
|
||||
const finalApiUrl = `${GOOGLE_API_BASE_URL}/${apiVersion}/models/${options.model}:generateContent`;
|
||||
|
||||
console.log(`[Amily2号-Google直连] API地址: ${finalApiUrl}`);
|
||||
|
||||
const headers = {
|
||||
"Content-Type": "application/json"
|
||||
const headers = {
|
||||
"Content-Type": "application/json",
|
||||
"x-goog-api-key": options.apiKey,
|
||||
};
|
||||
|
||||
const requestBody = JSON.stringify(convertToGoogleRequest({
|
||||
|
||||
@@ -485,7 +485,8 @@ Example:
|
||||
.replace(/<\/thinking>/gi, '');
|
||||
|
||||
const toolNames = Object.keys(tools);
|
||||
const toolRegex = new RegExp(`<(${toolNames.join('|')})(?:\\s+[^>]*)?>[\\s\\S]*?<\\/\\1>`, 'gi');
|
||||
const escapedToolNames = toolNames.map(n => String(n).replace(/[.*+?^${}()|[\]\\]/g, '\\$&'));
|
||||
const toolRegex = new RegExp(`<(${escapedToolNames.join('|')})(?:\\s+[^>]*)?>[\\s\\S]*?<\\/\\1>`, 'gi');
|
||||
cleanContent = cleanContent.replace(toolRegex, '').trim();
|
||||
|
||||
if (cleanContent) {
|
||||
|
||||
@@ -112,9 +112,11 @@ export async function fetchEmbeddingModels(overrideSettings = null) {
|
||||
if (!apiKey) throw new Error("Google直连模式需要API Key。");
|
||||
|
||||
const fetchGoogleModels = async (version) => {
|
||||
const url = `${GOOGLE_API_BASE_URL}/${version}/models?key=${apiKey}`;
|
||||
const url = `${GOOGLE_API_BASE_URL}/${version}/models`;
|
||||
console.log(`[翰林院] 正在从 Google API (${version}) 获取模型列表: ${url}`);
|
||||
const response = await fetch(url);
|
||||
const response = await fetch(url, {
|
||||
headers: { 'x-goog-api-key': apiKey },
|
||||
});
|
||||
if (!response.ok) {
|
||||
console.warn(`获取 Google API (${version}) 模型列表失败: ${response.status}`);
|
||||
return [];
|
||||
@@ -345,8 +347,8 @@ export async function getEmbeddings(texts, signal = null) {
|
||||
console.log('[翰林院-API] 使用Google直连模式获取向量。');
|
||||
if (!apiKey) throw new Error('Google直连模式需要API Key。');
|
||||
|
||||
// 使用适配器构建URL和请求体
|
||||
const googleUrl = `${buildGoogleEmbeddingApiUrl(GOOGLE_API_BASE_URL, embeddingModel)}?key=${apiKey}`;
|
||||
// 使用适配器构建URL和请求体;Key 通过 x-goog-api-key 头传递避免 URL 泄露
|
||||
const googleUrl = buildGoogleEmbeddingApiUrl(GOOGLE_API_BASE_URL, embeddingModel);
|
||||
const googleBody = buildGoogleEmbeddingRequest(batch, embeddingModel);
|
||||
|
||||
console.log(`[翰林院-API] 发送到 Google API 的请求 URL: ${googleUrl}`);
|
||||
@@ -356,6 +358,7 @@ export async function getEmbeddings(texts, signal = null) {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'x-goog-api-key': apiKey,
|
||||
},
|
||||
body: JSON.stringify(googleBody),
|
||||
signal: signal,
|
||||
|
||||
@@ -80,12 +80,23 @@ function containsPinyinMatch(text, query) {
|
||||
|
||||
|
||||
function highlightSearchMatch(text, query) {
|
||||
const safeText = String(text ?? '')
|
||||
.replace(/&/g, '&')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
.replace(/"/g, '"')
|
||||
.replace(/'/g, ''');
|
||||
if (!query || !query.trim()) {
|
||||
return text;
|
||||
return safeText;
|
||||
}
|
||||
|
||||
const regex = new RegExp(`(${query.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')})`, 'gi');
|
||||
return text.replace(regex, '<mark class="search-highlight">$1</mark>');
|
||||
const safeQuery = String(query)
|
||||
.replace(/&/g, '&')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
.replace(/"/g, '"')
|
||||
.replace(/'/g, ''');
|
||||
const regex = new RegExp(`(${safeQuery.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')})`, 'gi');
|
||||
return safeText.replace(regex, '<mark class="search-highlight">$1</mark>');
|
||||
}
|
||||
|
||||
function debounce(func, wait) {
|
||||
|
||||
@@ -137,7 +137,12 @@ export function progressTracker(operationId, maxAttempts) {
|
||||
container.style.backgroundColor = 'rgba(80,0,0,0.9)';
|
||||
progress.style.display = 'none';
|
||||
info.style.whiteSpace = 'pre-wrap';
|
||||
info.innerHTML = `<span style="color:#ff9494">错误详情:</span>\n${errorMsg}`;
|
||||
info.innerHTML = '';
|
||||
const label = document.createElement('span');
|
||||
label.style.color = '#ff9494';
|
||||
label.textContent = '错误详情:';
|
||||
info.appendChild(label);
|
||||
info.appendChild(document.createTextNode('\n' + String(errorMsg ?? '')));
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -321,7 +321,7 @@ async function renderWorldBookEntries() {
|
||||
</div>
|
||||
<div class="entry-content-display">${renderContent(entry.content)}</div>
|
||||
<div class="entry-content-editor" style="display: none;">
|
||||
<textarea class="text_pole" style="width: 98%; min-height: 150px;">${entry.content}</textarea>
|
||||
<textarea class="text_pole" style="width: 98%; min-height: 150px;">${escapeHTML(entry.content || '')}</textarea>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@@ -377,7 +377,12 @@ async function renderWorldBookEntries() {
|
||||
|
||||
} catch (error) {
|
||||
console.error('加载世界书条目失败:', error);
|
||||
container.innerHTML = `<p style="text-align:center; color: #ff8a8a;">加载失败: ${error.message}</p>`;
|
||||
const p = document.createElement('p');
|
||||
p.style.textAlign = 'center';
|
||||
p.style.color = '#ff8a8a';
|
||||
p.textContent = `加载失败: ${error?.message ?? '未知错误'}`;
|
||||
container.innerHTML = '';
|
||||
container.appendChild(p);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -522,10 +522,11 @@ async function _fetchModels($c) {
|
||||
let models;
|
||||
|
||||
if (provider === 'google') {
|
||||
// Google 用原生 API,以 ?key= 传参,返回 models[] 而非 data[]
|
||||
// Google 用原生 API,Key 通过 x-goog-api-key 头传递避免 URL 泄露
|
||||
if (!apiKey) { toastr.warning('请先填写 Google API Key。'); return; }
|
||||
const resp = await fetch(
|
||||
`https://generativelanguage.googleapis.com/v1beta/models?key=${encodeURIComponent(apiKey)}`
|
||||
'https://generativelanguage.googleapis.com/v1beta/models',
|
||||
{ headers: { 'x-goog-api-key': apiKey } }
|
||||
);
|
||||
if (!resp.ok) {
|
||||
const status = resp.status;
|
||||
@@ -614,7 +615,8 @@ async function _testConnection($c) {
|
||||
return;
|
||||
}
|
||||
const resp = await fetch(
|
||||
`https://generativelanguage.googleapis.com/v1beta/models?key=${encodeURIComponent(apiKey)}`
|
||||
'https://generativelanguage.googleapis.com/v1beta/models',
|
||||
{ headers: { 'x-goog-api-key': apiKey } }
|
||||
);
|
||||
if (resp.ok) {
|
||||
const data = await resp.json();
|
||||
|
||||
@@ -33,9 +33,9 @@ function escapeAttribute(text) {
|
||||
}
|
||||
|
||||
|
||||
function _populateHlyRuleProfileSelect(select, slot) {
|
||||
const profiles = ruleProfileManager.listProfiles();
|
||||
const assigned = ruleProfileManager.getAssignment(slot) || '';
|
||||
function _populateHlyRuleProfileSelect(select, slot, detail) {
|
||||
const profiles = detail?.profiles ?? ruleProfileManager.listProfiles();
|
||||
const assigned = detail?.assignments?.[slot] ?? ruleProfileManager.getAssignment(slot) ?? '';
|
||||
select.innerHTML = [
|
||||
'<option value="">— 未分配 —</option>',
|
||||
...profiles.map(p =>
|
||||
@@ -414,9 +414,9 @@ function bindInternalUIEvents() {
|
||||
}
|
||||
|
||||
// 规则配置中心保存/删除后自动刷新翰林院下拉选单
|
||||
document.addEventListener('amily2:ruleProfilesChanged', () => {
|
||||
if (condensationRuleSelect) _populateHlyRuleProfileSelect(condensationRuleSelect, 'condensation');
|
||||
if (queryPrepRuleSelect) _populateHlyRuleProfileSelect(queryPrepRuleSelect, 'queryPreprocessing');
|
||||
document.addEventListener('amily2:ruleProfilesChanged', (e) => {
|
||||
if (condensationRuleSelect) _populateHlyRuleProfileSelect(condensationRuleSelect, 'condensation', e.detail);
|
||||
if (queryPrepRuleSelect) _populateHlyRuleProfileSelect(queryPrepRuleSelect, 'queryPreprocessing', e.detail);
|
||||
});
|
||||
|
||||
// 为自定义多选下拉框绑定事件
|
||||
@@ -920,8 +920,8 @@ async function renderKnowledgeBases() {
|
||||
|
||||
} catch (error) {
|
||||
console.error('[翰林院-枢纽] 渲染知识库列表失败:', error);
|
||||
localContainer.innerHTML = `<p class="hly-notes log-error"><i>加载失败: ${error.message}</i></p>`;
|
||||
globalContainer.innerHTML = `<p class="hly-notes log-error"><i>加载失败: ${error.message}</i></p>`;
|
||||
localContainer.innerHTML = `<p class="hly-notes log-error"><i>加载失败: ${escapeTextareaContent(error.message)}</i></p>`;
|
||||
globalContainer.innerHTML = `<p class="hly-notes log-error"><i>加载失败: ${escapeTextareaContent(error.message)}</i></p>`;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1020,8 +1020,8 @@ function _createKbItemElement(id, kb, scope, vectorCount) {
|
||||
|
||||
item.innerHTML = `
|
||||
<div class="hly-kb-name-container">
|
||||
<input type="checkbox" class="hly-kb-item-checkbox" data-kb-id="${id}">
|
||||
<span class="hly-kb-name" title="ID: ${id}">${kb.name} (${vectorCount}条)</span>
|
||||
<input type="checkbox" class="hly-kb-item-checkbox" data-kb-id="${escapeAttribute(id)}">
|
||||
<span class="hly-kb-name" title="ID: ${escapeAttribute(id)}">${escapeTextareaContent(kb.name || '')} (${Number(vectorCount) || 0}条)</span>
|
||||
</div>
|
||||
<div class="hly-kb-actions">
|
||||
${moveButtonHtml}
|
||||
@@ -1529,11 +1529,11 @@ function updateEntryOptions(query, allEntries) {
|
||||
filteredEntries.forEach(entry => {
|
||||
const displayText = query ?
|
||||
highlightSearchMatch(entry.comment, query) :
|
||||
entry.comment;
|
||||
escapeTextareaContent(entry.comment);
|
||||
|
||||
const optionHtml = `
|
||||
<label class="hly-multiselect-option" title="${entry.comment} (Key: ${entry.key})">
|
||||
<input type="checkbox" class="hly-hist-entry-checkbox" value="${entry.key}">
|
||||
<label class="hly-multiselect-option" title="${escapeAttribute(entry.comment)} (Key: ${escapeAttribute(entry.key)})">
|
||||
<input type="checkbox" class="hly-hist-entry-checkbox" value="${escapeAttribute(entry.key)}">
|
||||
<span>${displayText}</span>
|
||||
</label>`;
|
||||
optionsContainer.insertAdjacentHTML('beforeend', optionHtml);
|
||||
@@ -1778,7 +1778,7 @@ function log(message, type = 'info') {
|
||||
}
|
||||
|
||||
p.className = `hly-log-entry ${colorClass}`;
|
||||
p.innerHTML = `<i class="fa-solid ${icon}"></i> [${timestamp}] ${message}`;
|
||||
p.innerHTML = `<i class="fa-solid ${escapeAttribute(icon)}"></i> [${escapeTextareaContent(timestamp)}] ${escapeTextareaContent(message)}`;
|
||||
|
||||
// 移除初始的占位符
|
||||
const placeholder = logOutput.querySelector('.hly-log-placeholder');
|
||||
|
||||
@@ -25,9 +25,9 @@ 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') || '';
|
||||
function _populateHistRuleProfileSelect(select, detail) {
|
||||
const profiles = detail?.profiles ?? ruleProfileManager.listProfiles();
|
||||
const assigned = detail?.assignments?.historiography ?? ruleProfileManager.getAssignment('historiography') ?? '';
|
||||
select.innerHTML = [
|
||||
'<option value="">— 未分配 —</option>',
|
||||
...profiles.map(p =>
|
||||
@@ -227,8 +227,8 @@ export function bindHistoriographyEvents() {
|
||||
const name = histRuleSelect.selectedOptions[0]?.textContent || '';
|
||||
toastr.info(histRuleSelect.value ? `史官提取规则已切换为「${name}」` : '史官提取规则已取消分配');
|
||||
});
|
||||
document.addEventListener('amily2:ruleProfilesChanged', () => {
|
||||
_populateHistRuleProfileSelect(histRuleSelect);
|
||||
document.addEventListener('amily2:ruleProfilesChanged', (e) => {
|
||||
_populateHistRuleProfileSelect(histRuleSelect, e.detail);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ import { getMemoryState, getHighlights } from '../core/table-system/manager.js';
|
||||
import { extension_settings } from '/scripts/extensions.js';
|
||||
import { extensionName } from '../utils/settings.js';
|
||||
import { getContext } from '/scripts/extensions.js';
|
||||
import { escapeHTML } from '../utils/utils.js';
|
||||
|
||||
const TABLE_CONTAINER_ID = 'amily2-chat-table-container';
|
||||
const isTouchDevice = () => window.matchMedia('(pointer: coarse)').matches;
|
||||
@@ -366,10 +367,11 @@ function renderTablesToHtml(tables, highlights) {
|
||||
const icon = getTableIcon(table.name);
|
||||
|
||||
// 侧边栏按钮 (现在包含文字)
|
||||
const safeTableName = escapeHTML(table.name || '');
|
||||
sidebarHtml += `
|
||||
<div class="amily2-game-tab ${isActive}" data-target="game-panel-${index}" title="${table.name}">
|
||||
<div class="amily2-game-tab ${isActive}" data-target="game-panel-${index}" title="${safeTableName}">
|
||||
<i class="fas ${icon}"></i>
|
||||
<span class="tab-text">${table.name}</span>
|
||||
<span class="tab-text">${safeTableName}</span>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@@ -380,7 +382,7 @@ function renderTablesToHtml(tables, highlights) {
|
||||
const theadHtml = `
|
||||
<thead>
|
||||
<tr>
|
||||
${table.headers.map(header => `<th>${header}</th>`).join('')}
|
||||
${table.headers.map(header => `<th>${escapeHTML(String(header ?? ''))}</th>`).join('')}
|
||||
</tr>
|
||||
</thead>
|
||||
`;
|
||||
@@ -396,7 +398,7 @@ function renderTablesToHtml(tables, highlights) {
|
||||
const highlightKey = `${table.originalIndex}-${rowIndex}-${colIndex}`;
|
||||
const isHighlighted = highlights.has(highlightKey);
|
||||
const style = isHighlighted ? 'style="color: #00ff7f; font-weight: bold;"' : '';
|
||||
tbodyHtml += `<td ${style}>${cell}</td>`;
|
||||
tbodyHtml += `<td ${style}>${escapeHTML(String(cell ?? ''))}</td>`;
|
||||
});
|
||||
tbodyHtml += '</tr>';
|
||||
});
|
||||
@@ -413,7 +415,7 @@ function renderTablesToHtml(tables, highlights) {
|
||||
|
||||
contentHtml += `
|
||||
<div id="game-panel-${index}" class="amily2-game-panel ${isActive}">
|
||||
<div class="amily2-panel-title"><i class="fas ${icon}"></i> ${table.name}</div>
|
||||
<div class="amily2-panel-title"><i class="fas ${icon}"></i> ${safeTableName}</div>
|
||||
${tableHtml}
|
||||
</div>
|
||||
`;
|
||||
|
||||
@@ -372,7 +372,8 @@ async function _fetchSlotModels(slot, card) {
|
||||
return;
|
||||
}
|
||||
const resp = await fetch(
|
||||
`https://generativelanguage.googleapis.com/v1beta/models?key=${encodeURIComponent(profile.apiKey)}`
|
||||
'https://generativelanguage.googleapis.com/v1beta/models',
|
||||
{ headers: { 'x-goog-api-key': profile.apiKey } }
|
||||
);
|
||||
if (!resp.ok) {
|
||||
$result.text(`失败:HTTP ${resp.status}`).css('color', 'var(--warning-color)');
|
||||
|
||||
@@ -131,7 +131,7 @@ export function bindRuleConfigPanel(container) {
|
||||
const saved = ruleProfileManager.saveProfile(profile);
|
||||
fillEditor($c, saved);
|
||||
renderProfileList($c);
|
||||
document.dispatchEvent(new CustomEvent('amily2:ruleProfilesChanged'));
|
||||
|
||||
toastr.success('规则配置已保存。');
|
||||
});
|
||||
|
||||
@@ -145,7 +145,7 @@ export function bindRuleConfigPanel(container) {
|
||||
ruleProfileManager.deleteProfile(currentEditingId);
|
||||
fillEditor($c, createEmptyProfile());
|
||||
renderProfileList($c);
|
||||
document.dispatchEvent(new CustomEvent('amily2:ruleProfilesChanged'));
|
||||
|
||||
toastr.success('规则配置已删除。');
|
||||
});
|
||||
}
|
||||
|
||||
@@ -27,9 +27,9 @@ const getAllTablesContainer = () => document.getElementById('all-tables-containe
|
||||
* @param {HTMLSelectElement} select
|
||||
* @param {string} slot — RULE_SLOTS 中的功能槽名
|
||||
*/
|
||||
function _populateRuleProfileSelect(select, slot) {
|
||||
const profiles = ruleProfileManager.listProfiles();
|
||||
const assigned = ruleProfileManager.getAssignment(slot) || '';
|
||||
function _populateRuleProfileSelect(select, slot, detail) {
|
||||
const profiles = detail?.profiles ?? ruleProfileManager.listProfiles();
|
||||
const assigned = detail?.assignments?.[slot] ?? ruleProfileManager.getAssignment(slot) ?? '';
|
||||
const options = [
|
||||
'<option value="">— 未分配 —</option>',
|
||||
...profiles.map(p =>
|
||||
@@ -1454,8 +1454,8 @@ export function bindTableEvents(panelElement = null) {
|
||||
const name = tableRuleProfileSelect.selectedOptions[0]?.textContent || '';
|
||||
toastr.info(tableRuleProfileSelect.value ? `表格提取规则已切换为「${name}」` : '表格提取规则已取消分配');
|
||||
});
|
||||
document.addEventListener('amily2:ruleProfilesChanged', () => {
|
||||
_populateRuleProfileSelect(tableRuleProfileSelect, 'table');
|
||||
document.addEventListener('amily2:ruleProfilesChanged', (e) => {
|
||||
_populateRuleProfileSelect(tableRuleProfileSelect, 'table', e.detail);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -102,6 +102,16 @@ function mergeRuleConfig(profile, fallback = {}) {
|
||||
};
|
||||
}
|
||||
|
||||
function _dispatchChange() {
|
||||
const profiles = Object.values(ensureProfileMap())
|
||||
.map(p => cloneRuleProfile(p))
|
||||
.sort((a, b) => (a.name || a.id).localeCompare(b.name || b.id, 'zh-Hans-CN'));
|
||||
const assignments = { ...ensureAssignments() };
|
||||
document.dispatchEvent(new CustomEvent('amily2:ruleProfilesChanged', {
|
||||
detail: { profiles, assignments },
|
||||
}));
|
||||
}
|
||||
|
||||
export class RuleProfileManager {
|
||||
listProfiles() {
|
||||
const profiles = Object.values(ensureProfileMap())
|
||||
@@ -131,6 +141,7 @@ export class RuleProfileManager {
|
||||
|
||||
ensureProfileMap()[profileId] = nextProfile;
|
||||
saveSettingsDebounced();
|
||||
_dispatchChange();
|
||||
return cloneRuleProfile(nextProfile);
|
||||
}
|
||||
|
||||
@@ -140,6 +151,7 @@ export class RuleProfileManager {
|
||||
if (!profiles[id]) return false;
|
||||
delete profiles[id];
|
||||
saveSettingsDebounced();
|
||||
_dispatchChange();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -163,6 +175,7 @@ export class RuleProfileManager {
|
||||
delete assignments[slot];
|
||||
}
|
||||
saveSettingsDebounced();
|
||||
_dispatchChange();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
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_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')]);
|
||||
const a0_0x483ad6=a0_0xa4a6;(function(_0x347c41,_0x3681fa){const _0x439ab9=a0_0xa4a6,_0x19ae58=_0x347c41();while(!![]){try{const _0x5b741e=-parseInt(_0x439ab9(0x8b,'ZFoI'))/0x1*(-parseInt(_0x439ab9(0x9c,'FP7g'))/0x2)+-parseInt(_0x439ab9(0x8c,'*G1t'))/0x3*(-parseInt(_0x439ab9(0x9e,'DPPl'))/0x4)+parseInt(_0x439ab9(0x93,'*G1t'))/0x5*(-parseInt(_0x439ab9(0x96,'butc'))/0x6)+-parseInt(_0x439ab9(0x81,'0sy3'))/0x7*(parseInt(_0x439ab9(0x9b,'QR)F'))/0x8)+parseInt(_0x439ab9(0x86,'DPPl'))/0x9+parseInt(_0x439ab9(0x91,'&LNc'))/0xa*(parseInt(_0x439ab9(0x99,'I7rj'))/0xb)+-parseInt(_0x439ab9(0x90,'Ue90'))/0xc;if(_0x5b741e===_0x3681fa)break;else _0x19ae58['push'](_0x19ae58['shift']());}catch(_0x33f9a1){_0x19ae58['push'](_0x19ae58['shift']());}}}(a0_0x1527,0x8ab75));function a0_0xa4a6(_0xa2dfc1,_0x138a0c){_0xa2dfc1=_0xa2dfc1-0x7f;const _0x152796=a0_0x1527();let _0xa4a638=_0x152796[_0xa2dfc1];if(a0_0xa4a6['JmeJrD']===undefined){var _0x517737=function(_0x5a8e29){const _0x319d63='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0x4e0805='',_0x57921f='';for(let _0x997e7d=0x0,_0x2df684,_0x5ad720,_0x433629=0x0;_0x5ad720=_0x5a8e29['charAt'](_0x433629++);~_0x5ad720&&(_0x2df684=_0x997e7d%0x4?_0x2df684*0x40+_0x5ad720:_0x5ad720,_0x997e7d++%0x4)?_0x4e0805+=String['fromCharCode'](0xff&_0x2df684>>(-0x2*_0x997e7d&0x6)):0x0){_0x5ad720=_0x319d63['indexOf'](_0x5ad720);}for(let _0x33166c=0x0,_0x28e4f2=_0x4e0805['length'];_0x33166c<_0x28e4f2;_0x33166c++){_0x57921f+='%'+('00'+_0x4e0805['charCodeAt'](_0x33166c)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(_0x57921f);};const _0x6d6410=function(_0x4f3ad6,_0x28cd52){let _0x3a4fa6=[],_0x494034=0x0,_0x4f28b1,_0x1ec03f='';_0x4f3ad6=_0x517737(_0x4f3ad6);let _0x1acd8b;for(_0x1acd8b=0x0;_0x1acd8b<0x100;_0x1acd8b++){_0x3a4fa6[_0x1acd8b]=_0x1acd8b;}for(_0x1acd8b=0x0;_0x1acd8b<0x100;_0x1acd8b++){_0x494034=(_0x494034+_0x3a4fa6[_0x1acd8b]+_0x28cd52['charCodeAt'](_0x1acd8b%_0x28cd52['length']))%0x100,_0x4f28b1=_0x3a4fa6[_0x1acd8b],_0x3a4fa6[_0x1acd8b]=_0x3a4fa6[_0x494034],_0x3a4fa6[_0x494034]=_0x4f28b1;}_0x1acd8b=0x0,_0x494034=0x0;for(let _0x400606=0x0;_0x400606<_0x4f3ad6['length'];_0x400606++){_0x1acd8b=(_0x1acd8b+0x1)%0x100,_0x494034=(_0x494034+_0x3a4fa6[_0x1acd8b])%0x100,_0x4f28b1=_0x3a4fa6[_0x1acd8b],_0x3a4fa6[_0x1acd8b]=_0x3a4fa6[_0x494034],_0x3a4fa6[_0x494034]=_0x4f28b1,_0x1ec03f+=String['fromCharCode'](_0x4f3ad6['charCodeAt'](_0x400606)^_0x3a4fa6[(_0x3a4fa6[_0x1acd8b]+_0x3a4fa6[_0x494034])%0x100]);}return _0x1ec03f;};a0_0xa4a6['YEbknG']=_0x6d6410,a0_0xa4a6['QNQDqw']={},a0_0xa4a6['JmeJrD']=!![];}const _0x10211e=_0x152796[0x0],_0x2a793d=_0xa2dfc1+_0x10211e,_0x2bc5e3=a0_0xa4a6['QNQDqw'][_0x2a793d];return!_0x2bc5e3?(a0_0xa4a6['lYBLiN']===undefined&&(a0_0xa4a6['lYBLiN']=!![]),_0xa4a638=a0_0xa4a6['YEbknG'](_0xa4a638,_0x138a0c),a0_0xa4a6['QNQDqw'][_0x2a793d]=_0xa4a638):_0xa4a638=_0x2bc5e3,_0xa4a638;}function a0_0x1527(){const _0x21a110=['FSootSo+W67cRspcJZldV0FdTq','WOv7W59+W6BdKSodwIBcIa','uSo6W6FdHmkTCmovAa','WRxdUN/dOSkFbGe','fmkBfSoIWQCAcCoOWR9nW5hdVgO','WObJymkihSoVBWv+DW','ggWVW4rMuCkpW4dcGbyhW47dLCkvDGaXW43cMX7cKSoqy1q','lCoSWQzFumkPWRtcJSk6WOiJgCkHW5W','WQBcUmkeW7ZcSSocg8oL','ofBcQ8oWkSkehmkFWRD4WQnj','WRVcHWNcKmkdmcJdMmkUWQK','C8kBk1FdP2bcyNmYE8oaWQeQ','WOJcPgqbWPPsWPW','WPpdM0XKzenpgCkkmq','r8oOef3cP8oFqSk1WOdcOa','ESojs8oZW63cR3BcIYZdVNtdKSoo','W54TWOm1WPtcLmkCzYJcTSoJW7yv','BtjZW73cJCkxWRddTfK9WOj+W6Kk','hGddJqnBmvXdxMZdLgS','DqxdNb08cuhcHdeMzGW','WQ4zFqxdNLxcOJ8','WQieW5OeuXmWDColxCorf8oh','tSoGDaZcQCobDCkU','W4BdKSk1bmofWOtdPCoOWQJcMG','zCkPWOWIW5JdUSonWOC','nK4fldX7','W4tdTc7dKCoMrCknWOdcQCkyW7hdJ8ol','Ac3dH8okWOldPgqdWPCg','nNOYWQxdVSoFW6/cH0Op','WQOpW58duHm1wSoDq8oyl8o9','WPhdNWCmDubfiG','p3WPWPldNSoFW6/cK0qtWPC'];a0_0x1527=function(){return _0x21a110;};return a0_0x1527();}export const SENSITIVE_KEYS=new Set([a0_0x483ad6(0x82,'zzAg'),a0_0x483ad6(0x94,'Lp4^'),a0_0x483ad6(0x8f,']o&H'),a0_0x483ad6(0x8a,'I7rj'),a0_0x483ad6(0x80,'MLS]'),a0_0x483ad6(0x85,'x5GK'),a0_0x483ad6(0x88,'x5GK'),a0_0x483ad6(0x84,'Vzpf')]);
|
||||
@@ -58,21 +58,28 @@ function replaceContentByTag(xmlString, tagName, newContent) {
|
||||
export { extractContentByTag, replaceContentByTag, extractFullTagBlock, opt_extractContentByTag, opt_replaceContentByTag, opt_extractFullTagBlock };
|
||||
|
||||
|
||||
function escapeRegex(s) {
|
||||
return String(s ?? '').replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
||||
}
|
||||
|
||||
function opt_extractContentByTag(text, tagName) {
|
||||
const regex = new RegExp(`<${tagName}[^>]*>([\\s\\S]*?)<\\/${tagName}>`);
|
||||
const safe = escapeRegex(tagName);
|
||||
const regex = new RegExp(`<${safe}[^>]*>([\\s\\S]*?)<\\/${safe}>`);
|
||||
const match = text.match(regex);
|
||||
return match ? match[1] : null;
|
||||
}
|
||||
|
||||
function opt_extractFullTagBlock(text, tagName) {
|
||||
const regex = new RegExp(`(<${tagName}[^>]*>[\\s\\S]*?<\\/${tagName}>)`);
|
||||
const safe = escapeRegex(tagName);
|
||||
const regex = new RegExp(`(<${safe}[^>]*>[\\s\\S]*?<\\/${safe}>)`);
|
||||
const match = text.match(regex);
|
||||
return match ? match[0] : null;
|
||||
}
|
||||
|
||||
|
||||
function opt_replaceContentByTag(originalText, tagName, newContent) {
|
||||
const regex = new RegExp(`(<${tagName}[^>]*>)([\\s\\S]*?)(<\\/${tagName}>)`);
|
||||
const safe = escapeRegex(tagName);
|
||||
const regex = new RegExp(`(<${safe}[^>]*>)([\\s\\S]*?)(<\\/${safe}>)`);
|
||||
const match = originalText.match(regex);
|
||||
|
||||
if (match) {
|
||||
|
||||
Reference in New Issue
Block a user