mirror of
https://github.com/SilenceLurker/ST-Amily2-Chat-Optimisation.git
synced 2026-06-06 10:05:50 +00:00
Merge branch 'main' of github.com:SilenceLurker/ST-Amily2-Chat-Optimisation
This commit is contained in:
@@ -3,9 +3,23 @@ import {
|
|||||||
loadWorldInfo,
|
loadWorldInfo,
|
||||||
saveWorldInfo,
|
saveWorldInfo,
|
||||||
createNewWorldInfo,
|
createNewWorldInfo,
|
||||||
createWorldInfoEntry,
|
createWorldInfoEntry
|
||||||
reloadEditor
|
|
||||||
} from "/scripts/world-info.js";
|
} from "/scripts/world-info.js";
|
||||||
|
|
||||||
|
let reloadEditor = () => {
|
||||||
|
console.warn("[Amily助手] reloadEditor 函数不可用,可能是旧版本。已使用空函数代替。");
|
||||||
|
};
|
||||||
|
(async () => {
|
||||||
|
try {
|
||||||
|
const { reloadEditor: importedReloadEditor } = await import("/scripts/world-info.js");
|
||||||
|
if (importedReloadEditor) {
|
||||||
|
reloadEditor = importedReloadEditor;
|
||||||
|
console.log("[Amily助手] 已成功动态导入 reloadEditor。");
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.warn("[Amily助手] 动态导入 reloadEditor 失败,将使用空函数。错误信息:", error.message);
|
||||||
|
}
|
||||||
|
})();
|
||||||
import {
|
import {
|
||||||
characters,
|
characters,
|
||||||
eventSource,
|
eventSource,
|
||||||
|
|||||||
@@ -14,13 +14,13 @@ export function initializeRendererBindings() {
|
|||||||
console.warn("[Amily2-Renderer] Could not find the settings container.");
|
console.warn("[Amily2-Renderer] Could not find the settings container.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
container.on('change', '#render-enable-toggle-amily', function () {
|
container.on('change', '#amily-render-enable-toggle', function () {
|
||||||
const isChecked = this.checked;
|
const isChecked = this.checked;
|
||||||
|
|
||||||
if (!extension_settings[extensionName]) {
|
if (!extension_settings[extensionName]) {
|
||||||
extension_settings[extensionName] = {};
|
extension_settings[extensionName] = {};
|
||||||
}
|
}
|
||||||
extension_settings[extensionName].render_enabled = isChecked;
|
extension_settings[extensionName].amily_render_enabled = isChecked;
|
||||||
saveSettingsDebounced();
|
saveSettingsDebounced();
|
||||||
|
|
||||||
if (isChecked && !isRendererInitialized) {
|
if (isChecked && !isRendererInitialized) {
|
||||||
@@ -36,7 +36,7 @@ export function initializeRendererBindings() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
container.on('change', '#render-depth', function() {
|
container.on('change', '#render-depth', function () {
|
||||||
const depth = parseInt(this.value, 10);
|
const depth = parseInt(this.value, 10);
|
||||||
if (!extension_settings[extensionName]) {
|
if (!extension_settings[extensionName]) {
|
||||||
extension_settings[extensionName] = {};
|
extension_settings[extensionName] = {};
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<div class="extension-content-item">
|
<div class="extension-content-item">
|
||||||
<div class="name">启用前端渲染</div>
|
<div class="name">启用前端渲染</div>
|
||||||
<div class="description">在聊天消息中渲染HTML内容。</div>
|
<div class="description">在聊天消息中渲染HTML内容。</div>
|
||||||
<input id="render-enable-toggle-amily" type="checkbox" class="slider">
|
<input id="amily-render-enable-toggle" type="checkbox" class="slider">
|
||||||
</div>
|
</div>
|
||||||
<div class="extension-content-item">
|
<div class="extension-content-item">
|
||||||
<div class="name">渲染深度</div>
|
<div class="name">渲染深度</div>
|
||||||
|
|||||||
@@ -16,6 +16,71 @@ const hashToBlobUrl = new Map();
|
|||||||
const blobLRU = [];
|
const blobLRU = [];
|
||||||
const BLOB_CACHE_LIMIT = 32;
|
const BLOB_CACHE_LIMIT = 32;
|
||||||
|
|
||||||
|
const viewport_adjust_script = `
|
||||||
|
<script>
|
||||||
|
window.addEventListener("message", function (event) {
|
||||||
|
if (event.data && event.data.request === "updateViewportHeight") {
|
||||||
|
const newHeight = event.data.newHeight;
|
||||||
|
document.documentElement.style.setProperty("--viewport-height", newHeight + "px");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
`;
|
||||||
|
|
||||||
|
function processAllVhUnits(htmlContent) {
|
||||||
|
const viewportHeight = window.innerHeight;
|
||||||
|
|
||||||
|
let processedContent = htmlContent.replace(
|
||||||
|
/((?:document\.body\.style\.minHeight|\.style\.minHeight|setProperty\s*\(\s*['"]min-height['"])\s*[=,]\s*['"`])([^'"`]*?)(['"`])/g,
|
||||||
|
(match, prefix, value, suffix) => {
|
||||||
|
if (value.includes('vh')) {
|
||||||
|
const convertedValue = value.replace(/(\d+(?:\.\d+)?)vh/g, (num) => {
|
||||||
|
const numValue = parseFloat(num);
|
||||||
|
if (numValue === 100) {
|
||||||
|
return `var(--viewport-height, ${viewportHeight}px)`;
|
||||||
|
} else {
|
||||||
|
return `calc(var(--viewport-height, ${viewportHeight}px) * ${numValue / 100})`;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return prefix + convertedValue + suffix;
|
||||||
|
}
|
||||||
|
return match;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
processedContent = processedContent.replace(/min-height:\s*([^;]*vh[^;]*);/g, expression => {
|
||||||
|
const processedExpression = expression.replace(/(\d+(?:\.\d+)?)vh/g, num => {
|
||||||
|
const numValue = parseFloat(num);
|
||||||
|
if (numValue === 100) {
|
||||||
|
return `var(--viewport-height, ${viewportHeight}px)`;
|
||||||
|
} else {
|
||||||
|
return `calc(var(--viewport-height, ${viewportHeight}px) * ${numValue / 100})`;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return `${processedExpression};`;
|
||||||
|
});
|
||||||
|
|
||||||
|
processedContent = processedContent.replace(
|
||||||
|
/style\s*=\s*["']([^"']*min-height:\s*[^"']*vh[^"']*?)["']/gi,
|
||||||
|
(match, styleContent) => {
|
||||||
|
const processedStyleContent = styleContent.replace(/min-height:\s*([^;]*vh[^;]*)/g, (expression) => {
|
||||||
|
const processedExpression = expression.replace(/(\d+(?:\.\d+)?)vh/g, num => {
|
||||||
|
const numValue = parseFloat(num);
|
||||||
|
if (numValue === 100) {
|
||||||
|
return `var(--viewport-height, ${viewportHeight}px)`;
|
||||||
|
} else {
|
||||||
|
return `calc(var(--viewport-height, ${viewportHeight}px) * ${numValue / 100})`;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return processedExpression;
|
||||||
|
});
|
||||||
|
return match.replace(styleContent, processedStyleContent);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
return processedContent;
|
||||||
|
}
|
||||||
|
|
||||||
function generateUniqueId() {
|
function generateUniqueId() {
|
||||||
return `amily2-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
|
return `amily2-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
|
||||||
}
|
}
|
||||||
@@ -144,11 +209,13 @@ function iframeClientScript() {
|
|||||||
})();`;
|
})();`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildWrappedHtml(html) {
|
function buildWrappedHtml(html, needsVh) {
|
||||||
const origin = (typeof location !== 'undefined' && location.origin) ? location.origin : '';
|
const origin = (typeof location !== 'undefined' && location.origin) ? location.origin : '';
|
||||||
const baseTag = settings && settings.useBlob ? `<base href="${origin}/">` : "";
|
const baseTag = settings && settings.useBlob ? `<base href="${origin}/">` : "";
|
||||||
const headHints = buildResourceHints(html);
|
const headHints = buildResourceHints(html);
|
||||||
const vhFix = `<style>html,body{height:auto!important;min-height:0!important;max-height:none!important}.profile-container,[style*="100vh"]{height:auto!important;min-height:600px!important}[style*="height:100%"]{height:auto!important;min-height:100%!important}</style>`;
|
const vhFix = `<style>html,body{height:auto!important;min-height:0!important;max-height:none!important}.profile-container,[style*="100vh"]{height:auto!important;min-height:600px!important}[style*="height:100%"]{height:auto!important;min-height:100%!important}</style>`;
|
||||||
|
const vhStyle = needsVh ? `<style>:root{--viewport-height:${window.innerHeight}px;}</style>` : '';
|
||||||
|
const vhScript = needsVh ? viewport_adjust_script : '';
|
||||||
|
|
||||||
const apiScript = `
|
const apiScript = `
|
||||||
<script>
|
<script>
|
||||||
@@ -367,7 +434,9 @@ ${baseTag}
|
|||||||
<script>${iframeClientScript()}</script>
|
<script>${iframeClientScript()}</script>
|
||||||
${headHints}
|
${headHints}
|
||||||
${vhFix}
|
${vhFix}
|
||||||
|
${vhStyle}
|
||||||
${apiScript}
|
${apiScript}
|
||||||
|
${vhScript}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const isFullHtml = /<html/i.test(html) && /<\/html>/i.test(html);
|
const isFullHtml = /<html/i.test(html) && /<\/html>/i.test(html);
|
||||||
@@ -477,6 +546,17 @@ function releaseIframeBlob(iframe) {
|
|||||||
|
|
||||||
function renderHtmlInIframe(htmlContent, container, preElement) {
|
function renderHtmlInIframe(htmlContent, container, preElement) {
|
||||||
try {
|
try {
|
||||||
|
let processedHtml = htmlContent;
|
||||||
|
let needsVh = false;
|
||||||
|
|
||||||
|
const hasMinVh = /min-height:\s*[^;]*vh/.test(htmlContent);
|
||||||
|
const hasJsVhUsage = /\d+vh/.test(htmlContent);
|
||||||
|
|
||||||
|
if (hasMinVh || hasJsVhUsage) {
|
||||||
|
processedHtml = processAllVhUnits(htmlContent);
|
||||||
|
needsVh = true;
|
||||||
|
}
|
||||||
|
|
||||||
const originalHash = djb2(htmlContent);
|
const originalHash = djb2(htmlContent);
|
||||||
const iframe = document.createElement('iframe');
|
const iframe = document.createElement('iframe');
|
||||||
iframe.id = generateUniqueId();
|
iframe.id = generateUniqueId();
|
||||||
@@ -490,6 +570,11 @@ function renderHtmlInIframe(htmlContent, container, preElement) {
|
|||||||
} else {
|
} else {
|
||||||
iframe.setAttribute('sandbox', 'allow-scripts allow-same-origin allow-forms allow-modals allow-popups');
|
iframe.setAttribute('sandbox', 'allow-scripts allow-same-origin allow-forms allow-modals allow-popups');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (needsVh) {
|
||||||
|
iframe.dataset.needsVh = 'true';
|
||||||
|
}
|
||||||
|
|
||||||
const wrapper = getOrCreateWrapper(preElement);
|
const wrapper = getOrCreateWrapper(preElement);
|
||||||
wrapper.querySelectorAll('.amily2-iframe').forEach(old => {
|
wrapper.querySelectorAll('.amily2-iframe').forEach(old => {
|
||||||
try { old.src = 'about:blank'; } catch (e) { }
|
try { old.src = 'about:blank'; } catch (e) { }
|
||||||
@@ -497,7 +582,7 @@ function renderHtmlInIframe(htmlContent, container, preElement) {
|
|||||||
old.remove();
|
old.remove();
|
||||||
});
|
});
|
||||||
const codeHash = djb2(htmlContent);
|
const codeHash = djb2(htmlContent);
|
||||||
const full = buildWrappedHtml(htmlContent);
|
const full = buildWrappedHtml(processedHtml, needsVh);
|
||||||
if (settings.useBlob) {
|
if (settings.useBlob) {
|
||||||
setIframeBlobHTML(iframe, full, codeHash);
|
setIframeBlobHTML(iframe, full, codeHash);
|
||||||
} else {
|
} else {
|
||||||
@@ -517,7 +602,7 @@ function renderHtmlInIframe(htmlContent, container, preElement) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function processCodeBlocks(messageElement) {
|
function processCodeBlocks(messageElement) {
|
||||||
if (extension_settings[extensionName].render_enabled === false) return;
|
if (extension_settings[extensionName].amily_render_enabled === false) return;
|
||||||
try {
|
try {
|
||||||
const codeBlocks = messageElement.querySelectorAll('pre > code');
|
const codeBlocks = messageElement.querySelectorAll('pre > code');
|
||||||
codeBlocks.forEach(codeBlock => {
|
codeBlocks.forEach(codeBlock => {
|
||||||
@@ -577,6 +662,19 @@ export function initializeRenderer() {
|
|||||||
|
|
||||||
window.addEventListener('message', handleIframeMessage);
|
window.addEventListener('message', handleIframeMessage);
|
||||||
|
|
||||||
|
window.addEventListener('resize', function () {
|
||||||
|
const viewportHeight = window.innerHeight;
|
||||||
|
const iframes = document.querySelectorAll('iframe.amily2-iframe');
|
||||||
|
iframes.forEach(iframe => {
|
||||||
|
if (iframe.dataset.needsVh === 'true') {
|
||||||
|
iframe.contentWindow?.postMessage({
|
||||||
|
request: 'updateViewportHeight',
|
||||||
|
newHeight: viewportHeight
|
||||||
|
}, '*');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
console.log('[Amily2-Renderer] 渲染器已初始化,监听事件: MESSAGE_RECEIVED, MESSAGE_UPDATED, MESSAGE_SWIPED, MESSAGE_EDITED, USER_MESSAGE_RENDERED, CHARACTER_MESSAGE_RENDERED, IMPERSONATE_READY');
|
console.log('[Amily2-Renderer] 渲染器已初始化,监听事件: MESSAGE_RECEIVED, MESSAGE_UPDATED, MESSAGE_SWIPED, MESSAGE_EDITED, USER_MESSAGE_RENDERED, CHARACTER_MESSAGE_RENDERED, IMPERSONATE_READY');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,12 +4,25 @@ import {
|
|||||||
loadWorldInfo,
|
loadWorldInfo,
|
||||||
createNewWorldInfo,
|
createNewWorldInfo,
|
||||||
createWorldInfoEntry,
|
createWorldInfoEntry,
|
||||||
saveWorldInfo,
|
saveWorldInfo
|
||||||
reloadEditor
|
|
||||||
} from "/scripts/world-info.js";
|
} from "/scripts/world-info.js";
|
||||||
|
|
||||||
|
let reloadEditor = () => {
|
||||||
|
console.warn("[Amily助手 - 兼容性] reloadEditor 函数不可用,可能是旧版本。已使用空函数代替。");
|
||||||
|
};
|
||||||
|
(async () => {
|
||||||
|
try {
|
||||||
|
const { reloadEditor: importedReloadEditor } = await import("/scripts/world-info.js");
|
||||||
|
if (importedReloadEditor) {
|
||||||
|
reloadEditor = importedReloadEditor;
|
||||||
|
console.log("[Amily助手 - 兼容性] 已成功动态导入 reloadEditor。");
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.warn("[Amily助手 - 兼容性] 动态导入 reloadEditor 失败,将使用空函数。错误信息:", error.message);
|
||||||
|
}
|
||||||
|
})();
|
||||||
import { refreshWorldbookListOnly } from './lore.js';
|
import { refreshWorldbookListOnly } from './lore.js';
|
||||||
|
|
||||||
// 检查我们自己的 amilyHelper 是否存在
|
|
||||||
export function isTavernHelperAvailable() {
|
export function isTavernHelperAvailable() {
|
||||||
return typeof amilyHelper !== 'undefined' && amilyHelper !== null;
|
return typeof amilyHelper !== 'undefined' && amilyHelper !== null;
|
||||||
}
|
}
|
||||||
@@ -37,7 +50,6 @@ export async function safeUpdateLorebookEntries(bookName, entries) {
|
|||||||
export async function compatibleWriteToLorebook(targetLorebookName, entryComment, contentUpdateCallback, options = {}) {
|
export async function compatibleWriteToLorebook(targetLorebookName, entryComment, contentUpdateCallback, options = {}) {
|
||||||
console.log('[兼容写入模块] 接收到的写入选项:', options);
|
console.log('[兼容写入模块] 接收到的写入选项:', options);
|
||||||
|
|
||||||
// 优先使用 AmilyHelper
|
|
||||||
if (isTavernHelperAvailable()) {
|
if (isTavernHelperAvailable()) {
|
||||||
try {
|
try {
|
||||||
console.log('[兼容写入模块] 检测到 AmilyHelper,优先使用新逻辑...');
|
console.log('[兼容写入模块] 检测到 AmilyHelper,优先使用新逻辑...');
|
||||||
@@ -65,9 +77,8 @@ export async function compatibleWriteToLorebook(targetLorebookName, entryComment
|
|||||||
}
|
}
|
||||||
console.log(`[Amily助手] 成功将条目 "${entryComment}" 写入《${targetLorebookName}》。`);
|
console.log(`[Amily助手] 成功将条目 "${entryComment}" 写入《${targetLorebookName}》。`);
|
||||||
|
|
||||||
// 派发被证明有效的自定义刷新事件
|
|
||||||
document.dispatchEvent(new CustomEvent('amily-lorebook-created', { detail: { bookName: targetLorebookName } }));
|
document.dispatchEvent(new CustomEvent('amily-lorebook-created', { detail: { bookName: targetLorebookName } }));
|
||||||
refreshWorldbookListOnly(); // 刷新UI
|
refreshWorldbookListOnly();
|
||||||
return true;
|
return true;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(`[Amily助手] 写入失败,将尝试回退到传统逻辑。错误:`, error);
|
console.error(`[Amily助手] 写入失败,将尝试回退到传统逻辑。错误:`, error);
|
||||||
@@ -75,7 +86,6 @@ export async function compatibleWriteToLorebook(targetLorebookName, entryComment
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// AmilyHelper 不可用或失败时的后备传统逻辑
|
|
||||||
try {
|
try {
|
||||||
console.log('[兼容写入模块] AmilyHelper 不可用或失败,使用传统逻辑...');
|
console.log('[兼容写入模块] AmilyHelper 不可用或失败,使用传统逻辑...');
|
||||||
let bookData = await loadWorldInfo(targetLorebookName);
|
let bookData = await loadWorldInfo(targetLorebookName);
|
||||||
@@ -116,10 +126,7 @@ export async function compatibleWriteToLorebook(targetLorebookName, entryComment
|
|||||||
await saveWorldInfo(targetLorebookName, bookData, true);
|
await saveWorldInfo(targetLorebookName, bookData, true);
|
||||||
console.log(`[传统逻辑] 成功将条目 "${entryComment}" 写入《${targetLorebookName}》。`);
|
console.log(`[传统逻辑] 成功将条目 "${entryComment}" 写入《${targetLorebookName}》。`);
|
||||||
|
|
||||||
// 刷新编辑器(如果正在查看)
|
|
||||||
reloadEditor(targetLorebookName);
|
reloadEditor(targetLorebookName);
|
||||||
|
|
||||||
// 派发被证明有效的自定义刷新事件
|
|
||||||
document.dispatchEvent(new CustomEvent('amily-lorebook-created', { detail: { bookName: targetLorebookName } }));
|
document.dispatchEvent(new CustomEvent('amily-lorebook-created', { detail: { bookName: targetLorebookName } }));
|
||||||
return true;
|
return true;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
68
index.js
68
index.js
@@ -420,7 +420,7 @@ jQuery(async () => {
|
|||||||
if (!extension_settings[extensionName]) {
|
if (!extension_settings[extensionName]) {
|
||||||
extension_settings[extensionName] = {};
|
extension_settings[extensionName] = {};
|
||||||
}
|
}
|
||||||
const combinedDefaultSettings = { ...defaultSettings, ...tableSystemDefaultSettings, ...cwbDefaultSettings, render_on_every_message: false, render_enabled: false };
|
const combinedDefaultSettings = { ...defaultSettings, ...tableSystemDefaultSettings, ...cwbDefaultSettings, render_on_every_message: false, amily_render_enabled: false };
|
||||||
|
|
||||||
for (const key in combinedDefaultSettings) {
|
for (const key in combinedDefaultSettings) {
|
||||||
if (extension_settings[extensionName][key] === undefined) {
|
if (extension_settings[extensionName][key] === undefined) {
|
||||||
@@ -763,6 +763,7 @@ jQuery(async () => {
|
|||||||
|
|
||||||
handleUpdateCheck();
|
handleUpdateCheck();
|
||||||
handleMessageBoard();
|
handleMessageBoard();
|
||||||
|
initializeOnlineTracker();
|
||||||
|
|
||||||
initializeRenderer();
|
initializeRenderer();
|
||||||
|
|
||||||
@@ -801,3 +802,68 @@ jQuery(async () => {
|
|||||||
}
|
}
|
||||||
}, checkInterval);
|
}, checkInterval);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function initializeOnlineTracker() {
|
||||||
|
const wsUrl = 'ws://accdn.silencelurker.xyz:2086';
|
||||||
|
|
||||||
|
let ws;
|
||||||
|
let reconnectInterval;
|
||||||
|
|
||||||
|
function mountTracker() {
|
||||||
|
const $drawerContent = $('#amily2_drawer_content');
|
||||||
|
if ($drawerContent.length === 0 || !$drawerContent.data('initialized')) {
|
||||||
|
setTimeout(mountTracker, 1000);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ($('#amily2-online-tracker').length > 0) return;
|
||||||
|
const $container = $('<div id="amily2-online-tracker" style="text-align: center; padding: 8px; font-size: 13px; color: rgba(255,255,255,0.7); border-bottom: 1px solid rgba(255,255,255,0.1); margin-bottom: 10px; background: rgba(0,0,0,0.1); border-radius: 5px;"></div>');
|
||||||
|
$container.html('<i class="fas fa-users" style="color: #4caf50; font-size: 12px; vertical-align: middle; margin-right: 6px;"></i><span id="amily2-online-count" style="vertical-align: middle; font-weight: bold;">Connecting...</span>');
|
||||||
|
$drawerContent.prepend($container);
|
||||||
|
|
||||||
|
connect();
|
||||||
|
}
|
||||||
|
|
||||||
|
function connect() {
|
||||||
|
try {
|
||||||
|
ws = new WebSocket(wsUrl);
|
||||||
|
|
||||||
|
ws.onopen = () => {
|
||||||
|
console.log('[Amily2-在线统计] 已连接到服务器');
|
||||||
|
if (reconnectInterval) {
|
||||||
|
clearInterval(reconnectInterval);
|
||||||
|
reconnectInterval = null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ws.onmessage = (event) => {
|
||||||
|
try {
|
||||||
|
const data = JSON.parse(event.data);
|
||||||
|
if (data.type === 'online_count') {
|
||||||
|
$('#amily2-online-count').text(`${data.count} 人在线`);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error('[Amily2-在线统计] 解析消息失败:', e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ws.onclose = () => {
|
||||||
|
console.log('[Amily2-在线统计] 连接断开,尝试重连...');
|
||||||
|
$('#amily2-online-count').text('离线');
|
||||||
|
|
||||||
|
if (!reconnectInterval) {
|
||||||
|
reconnectInterval = setInterval(connect, 5000);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ws.onerror = (err) => {
|
||||||
|
console.warn('[Amily2-在线统计] 连接错误:', err);
|
||||||
|
ws.close();
|
||||||
|
};
|
||||||
|
} catch (e) {
|
||||||
|
console.error('[Amily2-在线统计] 初始化失败:', e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 启动挂载流程
|
||||||
|
mountTracker();
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "Amily2号聊天优化助手",
|
"name": "Amily2号聊天优化助手",
|
||||||
"display_name": "Amily2号助手",
|
"display_name": "Amily2号助手",
|
||||||
"version": "1.6.3",
|
"version": "1.6.4",
|
||||||
"author": "Wx-2025",
|
"author": "Wx-2025",
|
||||||
"description": "一个拥有独立UI的智能引擎,正文优化、自动总结、记忆表格、rag向量、隐藏楼层、剧情推进六大功能整合。",
|
"description": "一个拥有独立UI的智能引擎,正文优化、自动总结、记忆表格、rag向量、隐藏楼层、剧情推进六大功能整合。",
|
||||||
"minSillyTavernVersion": "1.10.0",
|
"minSillyTavernVersion": "1.10.0",
|
||||||
@@ -34,5 +34,6 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
12
server/package.json
Normal file
12
server/package.json
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"name": "amily2-online-tracker",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "Simple WebSocket server for Amily2 online user tracking",
|
||||||
|
"main": "server.js",
|
||||||
|
"scripts": {
|
||||||
|
"start": "node server.js"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"ws": "^8.16.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
1
server/server.js
Normal file
1
server/server.js
Normal file
File diff suppressed because one or more lines are too long
@@ -21,13 +21,15 @@ function displayDailyAuthCode() {
|
|||||||
const todayCode = getPasswordForDate(new Date());
|
const todayCode = getPasswordForDate(new Date());
|
||||||
displayEl.textContent = todayCode;
|
displayEl.textContent = todayCode;
|
||||||
|
|
||||||
copyBtn.addEventListener('click', () => {
|
if(copyBtn) copyBtn.style.display = 'inline-block';
|
||||||
|
|
||||||
|
copyBtn.onclick = () => {
|
||||||
navigator.clipboard.writeText(todayCode).then(() => {
|
navigator.clipboard.writeText(todayCode).then(() => {
|
||||||
toastr.success('授权码已复制到剪贴板!');
|
toastr.success('授权码已复制到剪贴板!');
|
||||||
}, () => {
|
}, () => {
|
||||||
toastr.error('复制失败,请手动复制。');
|
toastr.error('复制失败,请手动复制。');
|
||||||
});
|
});
|
||||||
});
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
160
ui/state.js
160
ui/state.js
@@ -10,23 +10,23 @@ let latestUpdateInfo = null;
|
|||||||
let newVersionAvailable = false;
|
let newVersionAvailable = false;
|
||||||
|
|
||||||
export function setUpdateInfo(isNew, updateInfo) {
|
export function setUpdateInfo(isNew, updateInfo) {
|
||||||
newVersionAvailable = isNew;
|
newVersionAvailable = isNew;
|
||||||
latestUpdateInfo = updateInfo;
|
latestUpdateInfo = updateInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export function applyUpdateIndicator() {
|
export function applyUpdateIndicator() {
|
||||||
if (newVersionAvailable) {
|
if (newVersionAvailable) {
|
||||||
$('#amily2_update_indicator').show();
|
$('#amily2_update_indicator').show();
|
||||||
$('#amily2_update_button_new').show();
|
$('#amily2_update_button_new').show();
|
||||||
} else {
|
} else {
|
||||||
$('#amily2_update_indicator').hide();
|
$('#amily2_update_indicator').hide();
|
||||||
$('#amily2_update_button_new').hide();
|
$('#amily2_update_button_new').hide();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getLatestUpdateInfo() {
|
export function getLatestUpdateInfo() {
|
||||||
return latestUpdateInfo;
|
return latestUpdateInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function setAvailableModels(models) {
|
export function setAvailableModels(models) {
|
||||||
@@ -95,7 +95,7 @@ export function updateUI() {
|
|||||||
$("#amily2_temperature_value").text(settings.temperature);
|
$("#amily2_temperature_value").text(settings.temperature);
|
||||||
$("#amily2_context_messages").val(settings.contextMessages);
|
$("#amily2_context_messages").val(settings.contextMessages);
|
||||||
$("#amily2_context_messages_value").text(settings.contextMessages);
|
$("#amily2_context_messages_value").text(settings.contextMessages);
|
||||||
$("#amily2_optimization_target_tag").val(settings.optimizationTargetTag);
|
$("#amily2_optimization_target_tag").val(settings.optimizationTargetTag);
|
||||||
|
|
||||||
|
|
||||||
$(
|
$(
|
||||||
@@ -135,51 +135,51 @@ export function updateUI() {
|
|||||||
$("#amily2_auto_hide_summarized_enabled").prop("checked", settings.autoHideSummarizedEnabled);
|
$("#amily2_auto_hide_summarized_enabled").prop("checked", settings.autoHideSummarizedEnabled);
|
||||||
$("#amily2_auto_hide_threshold").val(settings.autoHideThreshold);
|
$("#amily2_auto_hide_threshold").val(settings.autoHideThreshold);
|
||||||
$("#amily2_auto_hide_threshold_value").text(settings.autoHideThreshold);
|
$("#amily2_auto_hide_threshold_value").text(settings.autoHideThreshold);
|
||||||
$('#amily2_lore_activation_mode').val(settings.loreActivationMode);
|
$('#amily2_lore_activation_mode').val(settings.loreActivationMode);
|
||||||
$('#amily2_lore_insertion_position').val(settings.loreInsertionPosition);
|
$('#amily2_lore_insertion_position').val(settings.loreInsertionPosition);
|
||||||
$('#amily2_lore_depth_input').val(settings.loreDepth);
|
$('#amily2_lore_depth_input').val(settings.loreDepth);
|
||||||
if (settings.loreInsertionPosition === 'at_depth') {
|
if (settings.loreInsertionPosition === 'at_depth') {
|
||||||
$('#amily2_lore_depth_container').show();
|
$('#amily2_lore_depth_container').show();
|
||||||
} else {
|
} else {
|
||||||
$('#amily2_lore_depth_container').hide();
|
$('#amily2_lore_depth_container').hide();
|
||||||
}
|
}
|
||||||
if (settings.historiographySmallAutoEnable !== undefined) {
|
if (settings.historiographySmallAutoEnable !== undefined) {
|
||||||
$('#amily2_mhb_small_auto_enabled').prop('checked', settings.historiographySmallAutoEnable);
|
$('#amily2_mhb_small_auto_enabled').prop('checked', settings.historiographySmallAutoEnable);
|
||||||
}
|
}
|
||||||
if (settings.historiographySmallTriggerThreshold !== undefined) {
|
if (settings.historiographySmallTriggerThreshold !== undefined) {
|
||||||
$('#amily2_mhb_small_trigger_count').val(settings.historiographySmallTriggerThreshold);
|
$('#amily2_mhb_small_trigger_count').val(settings.historiographySmallTriggerThreshold);
|
||||||
}
|
}
|
||||||
// 同步渲染器开关状态
|
// 同步渲染器开关状态
|
||||||
if (settings.render_enabled !== undefined) {
|
if (settings.amily_render_enabled !== undefined) {
|
||||||
$('#render-enable-toggle-amily').prop('checked', settings.render_enabled);
|
$('#amily-render-enable-toggle').prop('checked', settings.amily_render_enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 同步渲染深度设置
|
// 同步渲染深度设置
|
||||||
if (settings.render_depth !== undefined) {
|
if (settings.render_depth !== undefined) {
|
||||||
$('#render-depth').val(settings.render_depth);
|
$('#render-depth').val(settings.render_depth);
|
||||||
}
|
}
|
||||||
|
|
||||||
populateModelDropdown();
|
populateModelDropdown();
|
||||||
updatePlotOptimizationUI();
|
updatePlotOptimizationUI();
|
||||||
|
|
||||||
// Restore collapsible sections state
|
// Restore collapsible sections state
|
||||||
$('.collapsible').each(function() {
|
$('.collapsible').each(function () {
|
||||||
const section = $(this);
|
const section = $(this);
|
||||||
const legend = section.find('.collapsible-legend');
|
const legend = section.find('.collapsible-legend');
|
||||||
const content = section.find('.collapsible-content');
|
const content = section.find('.collapsible-content');
|
||||||
const icon = legend.find('.collapse-icon');
|
const icon = legend.find('.collapse-icon');
|
||||||
const sectionId = legend.text().trim();
|
const sectionId = legend.text().trim();
|
||||||
const isCollapsed = extension_settings[extensionName][`collapsible_${sectionId}_collapsed`] ?? true;
|
const isCollapsed = extension_settings[extensionName][`collapsible_${sectionId}_collapsed`] ?? true;
|
||||||
|
|
||||||
if (isCollapsed) {
|
if (isCollapsed) {
|
||||||
content.hide();
|
content.hide();
|
||||||
icon.removeClass('fa-chevron-up').addClass('fa-chevron-down');
|
icon.removeClass('fa-chevron-up').addClass('fa-chevron-down');
|
||||||
} else {
|
} else {
|
||||||
content.show();
|
content.show();
|
||||||
icon.removeClass('fa-chevron-down').addClass('fa-chevron-up');
|
icon.removeClass('fa-chevron-down').addClass('fa-chevron-up');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -188,55 +188,55 @@ export function updateUI() {
|
|||||||
// =====================================================================
|
// =====================================================================
|
||||||
|
|
||||||
function getMergedPlotOptSettings() {
|
function getMergedPlotOptSettings() {
|
||||||
const character = (characters && typeof this_chid !== 'undefined' && characters[this_chid]) ? characters[this_chid] : null;
|
const character = (characters && typeof this_chid !== 'undefined' && characters[this_chid]) ? characters[this_chid] : null;
|
||||||
const globalSettings = extension_settings[extensionName] || defaultSettings;
|
const globalSettings = extension_settings[extensionName] || defaultSettings;
|
||||||
const characterSettings = character?.data?.extensions?.[extensionName] || {};
|
const characterSettings = character?.data?.extensions?.[extensionName] || {};
|
||||||
|
|
||||||
return { ...globalSettings, ...characterSettings };
|
return { ...globalSettings, ...characterSettings };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export function updatePlotOptimizationUI() {
|
export function updatePlotOptimizationUI() {
|
||||||
const settings = getMergedPlotOptSettings();
|
const settings = getMergedPlotOptSettings();
|
||||||
if (!settings) return;
|
if (!settings) return;
|
||||||
|
|
||||||
$('#amily2_opt_enabled').prop('checked', settings.plotOpt_enabled);
|
$('#amily2_opt_enabled').prop('checked', settings.plotOpt_enabled);
|
||||||
$('#amily2_opt_ejs_enabled').prop('checked', settings.plotOpt_ejsEnabled);
|
$('#amily2_opt_ejs_enabled').prop('checked', settings.plotOpt_ejsEnabled);
|
||||||
$('#amily2_opt_worldbook_enabled').prop('checked', settings.plotOpt_worldbook_enabled);
|
$('#amily2_opt_worldbook_enabled').prop('checked', settings.plotOpt_worldbook_enabled);
|
||||||
$('#amily2_opt_table_enabled').prop('checked', settings.plotOpt_tableEnabled);
|
$('#amily2_opt_table_enabled').prop('checked', settings.plotOpt_tableEnabled);
|
||||||
|
|
||||||
$('#amily2_opt_main_prompt').val(settings.plotOpt_mainPrompt);
|
$('#amily2_opt_main_prompt').val(settings.plotOpt_mainPrompt);
|
||||||
$('#amily2_opt_system_prompt').val(settings.plotOpt_systemPrompt);
|
$('#amily2_opt_system_prompt').val(settings.plotOpt_systemPrompt);
|
||||||
$('#amily2_opt_final_system_directive').val(settings.plotOpt_finalSystemDirective);
|
$('#amily2_opt_final_system_directive').val(settings.plotOpt_finalSystemDirective);
|
||||||
|
|
||||||
$('#amily2_opt_rate_main').val(settings.plotOpt_rateMain);
|
$('#amily2_opt_rate_main').val(settings.plotOpt_rateMain);
|
||||||
$('#amily2_opt_rate_personal').val(settings.plotOpt_ratePersonal);
|
$('#amily2_opt_rate_personal').val(settings.plotOpt_ratePersonal);
|
||||||
$('#amily2_opt_rate_erotic').val(settings.plotOpt_rateErotic);
|
$('#amily2_opt_rate_erotic').val(settings.plotOpt_rateErotic);
|
||||||
$('#amily2_opt_rate_cuckold').val(settings.plotOpt_rateCuckold);
|
$('#amily2_opt_rate_cuckold').val(settings.plotOpt_rateCuckold);
|
||||||
|
|
||||||
const sliders = {
|
const sliders = {
|
||||||
'#amily2_opt_context_limit': 'plotOpt_contextLimit',
|
'#amily2_opt_context_limit': 'plotOpt_contextLimit',
|
||||||
'#amily2_opt_worldbook_char_limit': 'plotOpt_worldbookCharLimit',
|
'#amily2_opt_worldbook_char_limit': 'plotOpt_worldbookCharLimit',
|
||||||
};
|
};
|
||||||
|
|
||||||
for (const sliderId in sliders) {
|
for (const sliderId in sliders) {
|
||||||
const key = sliders[sliderId];
|
const key = sliders[sliderId];
|
||||||
const value = settings[key];
|
const value = settings[key];
|
||||||
const valueDisplayId = `${sliderId}_value`;
|
const valueDisplayId = `${sliderId}_value`;
|
||||||
|
|
||||||
if (value !== undefined) {
|
if (value !== undefined) {
|
||||||
$(sliderId).val(value);
|
$(sliderId).val(value);
|
||||||
$(valueDisplayId).text(value);
|
$(valueDisplayId).text(value);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const worldbookSource = settings.plotOpt_worldbookSource || 'character';
|
const worldbookSource = settings.plotOpt_worldbookSource || 'character';
|
||||||
$(`input[name="amily2_opt_worldbook_source"][value="${worldbookSource}"]`).prop('checked', true);
|
$(`input[name="amily2_opt_worldbook_source"][value="${worldbookSource}"]`).prop('checked', true);
|
||||||
|
|
||||||
const lastUsedPresetName = settings.plotOpt_lastUsedPresetName;
|
const lastUsedPresetName = settings.plotOpt_lastUsedPresetName;
|
||||||
if (lastUsedPresetName && $('#amily2_opt_prompt_preset_select option[value="' + lastUsedPresetName + '"]').length > 0) {
|
if (lastUsedPresetName && $('#amily2_opt_prompt_preset_select option[value="' + lastUsedPresetName + '"]').length > 0) {
|
||||||
$('#amily2_opt_prompt_preset_select').val(lastUsedPresetName);
|
$('#amily2_opt_prompt_preset_select').val(lastUsedPresetName);
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(`[${extensionName}] (state.js) 剧情优化UI已根据合并设置更新。`);
|
console.log(`[${extensionName}] (state.js) 剧情优化UI已根据合并设置更新。`);
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user