import { extension_settings, getContext } from "/scripts/extensions.js"; import { characters, this_chid, saveSettingsDebounced, eventSource, event_types } from "/script.js"; import { defaultSettings, extensionName, saveSettings, extensionBasePath } from "../utils/settings.js"; import { pluginAuthStatus, activatePluginAuthorization, getPasswordForDate } from "../utils/auth.js"; import { fetchModels, testApiConnection } from "../core/api.js"; import { safeLorebooks, safeCharLorebooks, safeLorebookEntries } from "../core/tavernhelper-compatibility.js"; import { configManager } from '../utils/config/ConfigManager.js'; import { setAvailableModels, populateModelDropdown, getLatestUpdateInfo } from "./state.js"; import { fixCommand, testReplyChecker } from "../core/commands.js"; import { messageFormatting } from '/script.js'; import { executeManualCommand } from '../core/autoHideManager.js'; import { showContentModal, showHtmlModal } from './page-window.js'; import { openAutoCharCardWindow } from '../core/auto-char-card/ui-bindings.js'; function displayDailyAuthCode() { const displayEl = document.getElementById('amily2_daily_code_display'); const copyBtn = document.getElementById('amily2_copy_daily_code'); if (displayEl && copyBtn) { const todayCode = getPasswordForDate(new Date()); displayEl.textContent = todayCode; if(copyBtn) copyBtn.style.display = 'inline-block'; copyBtn.onclick = () => { navigator.clipboard.writeText(todayCode).then(() => { toastr.success('授权码已复制到剪贴板!'); }, () => { toastr.error('复制失败,请手动复制。'); }); }; } } async function loadSillyTavernPresets() { console.log('[Amily2号-UI] 正在加载SillyTavern预设列表'); const select = $('#amily2_preset_selector'); const settings = extension_settings[extensionName] || {}; const currentProfileId = settings.tavernProfile || settings.selectedPreset; select.empty().append(new Option('-- 请选择一个酒馆预设 --', '')); try { const context = getContext(); const tavernProfiles = context.extensionSettings?.connectionManager?.profiles || []; if (!tavernProfiles || tavernProfiles.length === 0) { select.append($(''); }); container .off("input.amily2.text change.amily2.text") .on("input.amily2.text change.amily2.text", "#amily2_api_url, #amily2_api_key, #amily2_optimization_target_tag", function () { if (!pluginAuthStatus.authorized) return; const key = snakeToCamel(this.id.replace("amily2_", "")); // apiKey 是敏感字段,必须经 configManager 写入 localStorage if (key === 'apiKey') { configManager.set(key, this.value); } else { updateAndSaveSetting(key, this.value); } toastr.success(`配置 [${key}] 已自动保存!`, "Amily2号"); }); container .off("change.amily2.select") .on("change.amily2.select", "select#amily2_model, select#amily2_preset_selector", function () { if (!pluginAuthStatus.authorized) return; const key = snakeToCamel(this.id.replace("amily2_", "")); let valueToSave = this.value; if (this.id === 'amily2_preset_selector') { updateAndSaveSetting('tavernProfile', valueToSave); } else { updateAndSaveSetting(key, valueToSave); } if (this.id === 'amily2_model') { populateModelDropdown(); } }); container .off("input.amily2.range") .on( "input.amily2.range", 'input[type="range"][id^="amily2_"]', function () { if (!pluginAuthStatus.authorized) return; const key = snakeToCamel(this.id.replace("amily2_", "")); const value = this.id.includes("temperature") ? parseFloat(this.value) : parseInt(this.value, 10); $(`#${this.id}_value`).text(value); updateAndSaveSetting(key, value); }, ); container .off("input.amily2.number change.amily2.number") .on( "input.amily2.number change.amily2.number", "#amily2_max_tokens, #amily2_temperature, #amily2_context_messages", function () { if (!pluginAuthStatus.authorized) return; const key = snakeToCamel(this.id.replace("amily2_", "")); const value = this.id.includes("temperature") ? parseFloat(this.value) : parseInt(this.value, 10); if (Number.isNaN(value)) return; $(`#${this.id}_value`).text(value); updateAndSaveSetting(key, value); }, ); const promptMap = { mainPrompt: "#amily2_main_prompt", systemPrompt: "#amily2_system_prompt", outputFormatPrompt: "#amily2_output_format_prompt", }; const selector = "#amily2_prompt_selector"; const editor = "#amily2_unified_editor"; const unifiedSaveButton = "#amily2_unified_save_button"; function updateEditorView() { if (!$(selector).length) return; const selectedKey = $(selector).val(); if (!selectedKey) return; const content = extension_settings[extensionName][selectedKey] || ""; $(editor).val(content); } container .off("change.amily2.prompt_selector") .on("change.amily2.prompt_selector", selector, updateEditorView); container .off("input.amily2.unified_editor change.amily2.unified_editor") .on("input.amily2.unified_editor change.amily2.unified_editor", editor, function () { const selectedKey = $(selector).val(); if (!selectedKey) return; updateAndSaveSetting(selectedKey, $(this).val()); }); container .off("click.amily2.unified_save") .on("click.amily2.unified_save", unifiedSaveButton, function () { const selectedKey = $(selector).val(); if (!selectedKey) return; const newContent = $(editor).val(); updateAndSaveSetting(selectedKey, newContent); toastr.success(`谕令 [${selectedKey}] 已镌刻!`, "Amily2号"); }); container .off("click.amily2.unified_restore") .on("click.amily2.unified_restore", "#amily2_unified_restore_button", function () { const selectedKey = $(selector).val(); if (!selectedKey) return; const defaultValue = defaultSettings[selectedKey]; $(editor).val(defaultValue); updateAndSaveSetting(selectedKey, defaultValue); toastr.success(`谕令 [${selectedKey}] 已成功恢复为帝国初始蓝图。`, "Amily2号"); }); container .off("input.amily2.lore_settings change.amily2.lore_settings") .on("input.amily2.lore_settings change.amily2.lore_settings", 'select[id^="amily2_lore_"], input#amily2_lore_depth_input', function () { if (!pluginAuthStatus.authorized) return; let key = snakeToCamel(this.id.replace("amily2_", "")); if (key === 'loreDepthInput') { key = 'loreDepth'; } const value = (this.type === 'number') ? parseInt(this.value, 10) : this.value; updateAndSaveSetting(key, value); if (this.id === 'amily2_lore_insertion_position') { const depthContainer = $('#amily2_lore_depth_container'); if (this.value === 'at_depth') { depthContainer.slideDown(200); } else { depthContainer.slideUp(200); } } } ); container .off("click.amily2.lore_save") .on("click.amily2.lore_save", '#amily2_save_lore_settings', function () { if (!pluginAuthStatus.authorized) return; const button = $(this); const statusElement = $('#amily2_lore_save_status'); button.prop('disabled', true).html(' 已确认'); statusElement.text('圣意已在您每次更改时自动镌刻。').stop().fadeIn(); setTimeout(() => { button.prop('disabled', false).html(' 确认敕令'); statusElement.fadeOut(); }, 2500); }); setTimeout(updateEditorView, 100); updateModelInputView(); container.data("events-bound", true); // 【V60.0】新增:颜色定制UI事件绑定 const colorContainer = $("#amily2_drawer_content").length ? $("#amily2_drawer_content") : $("#amily2_chat_optimiser"); if (colorContainer.length && !colorContainer.data("color-events-bound")) { loadAndApplyCustomColors(colorContainer); colorContainer.on('input', '#amily2_bg_color, #amily2_button_color, #amily2_text_color', function() { applyAndSaveColors(colorContainer); }); // 新增:背景透明度滑块事件 colorContainer.on('input', '#amily2_bg_opacity', function() { const opacityValue = $(this).val(); $('#amily2_bg_opacity_value').text(opacityValue); document.documentElement.style.setProperty('--amily2-bg-opacity', opacityValue); if (!extension_settings[extensionName]) { extension_settings[extensionName] = {}; } extension_settings[extensionName]['bgOpacity'] = opacityValue; saveSettingsDebounced(); }); colorContainer.on('click', '#amily2_restore_colors', function() { const defaultColors = { '--amily2-bg-color': '#1e1e1e', '--amily2-button-color': '#4a4a4a', '--amily2-text-color': '#ffffff' }; colorContainer.find('#amily2_bg_color').val(defaultColors['--amily2-bg-color']); colorContainer.find('#amily2_button_color').val(defaultColors['--amily2-button-color']); colorContainer.find('#amily2_text_color').val(defaultColors['--amily2-text-color']); applyAndSaveColors(colorContainer); // 恢复默认透明度 const defaultOpacity = 0.85; $('#amily2_bg_opacity').val(defaultOpacity); $('#amily2_bg_opacity_value').text(defaultOpacity); document.documentElement.style.setProperty('--amily2-bg-opacity', defaultOpacity); if (extension_settings[extensionName]) { extension_settings[extensionName]['bgOpacity'] = defaultOpacity; saveSettingsDebounced(); } toastr.success('界面颜色与透明度已恢复为默认设置。'); }); // 新增:自定义背景图事件绑定 colorContainer.on('change', '#amily2_custom_bg_image', function(event) { const file = event.target.files[0]; if (file && file.type.startsWith('image/')) { const reader = new FileReader(); reader.onload = function(e) { const imageDataUrl = e.target.result; // 检查大小 if (imageDataUrl.length > 5 * 1024 * 1024) { // 5MB 限制 toastr.error('图片文件过大,请选择小于5MB的图片。'); return; } document.documentElement.style.setProperty('--amily2-bg-image', `url("${imageDataUrl}")`); if (!extension_settings[extensionName]) { extension_settings[extensionName] = {}; } extension_settings[extensionName]['customBgImage'] = imageDataUrl; saveSettingsDebounced(); toastr.success('自定义背景图已应用。'); }; reader.readAsDataURL(file); } }); colorContainer.on('click', '#amily2_restore_bg_image', function() { document.documentElement.style.setProperty('--amily2-bg-image', `url("${DEFAULT_BG_IMAGE_URL}")`); if (extension_settings[extensionName]) { delete extension_settings[extensionName]['customBgImage']; saveSettingsDebounced(); } $('#amily2_custom_bg_image').val(''); // 清空文件选择框 toastr.success('背景图已恢复为默认。'); }); colorContainer.data("color-events-bound", true); } } const DEFAULT_BG_IMAGE_URL = "https://cdn.jsdelivr.net/gh/Wx-2025/ST-Amily2-images@main/img/Amily-2.png"; function applyAndSaveColors(container) { const bgColor = container.find('#amily2_bg_color').val(); const btnColor = container.find('#amily2_button_color').val(); const textColor = container.find('#amily2_text_color').val(); const colors = { '--amily2-bg-color': bgColor, '--amily2-button-color': btnColor, '--amily2-text-color': textColor }; Object.entries(colors).forEach(([key, value]) => { document.documentElement.style.setProperty(key, value, 'important'); }); if (!extension_settings[extensionName]) { extension_settings[extensionName] = {}; } extension_settings[extensionName]['customColors'] = colors; saveSettingsDebounced(); } function loadAndApplyCustomColors(container) { const savedColors = extension_settings[extensionName]?.customColors; if (savedColors) { container.find('#amily2_bg_color').val(savedColors['--amily2-bg-color']); container.find('#amily2_button_color').val(savedColors['--amily2-button-color']); container.find('#amily2_text_color').val(savedColors['--amily2-text-color']); applyAndSaveColors(container); } const savedOpacity = extension_settings[extensionName]?.bgOpacity; if (savedOpacity !== undefined) { $('#amily2_bg_opacity').val(savedOpacity); $('#amily2_bg_opacity_value').text(savedOpacity); document.documentElement.style.setProperty('--amily2-bg-opacity', savedOpacity); } const savedBgImage = extension_settings[extensionName]?.customBgImage; const imageUrl = savedBgImage ? `url("${savedBgImage}")` : `url("${DEFAULT_BG_IMAGE_URL}")`; document.documentElement.style.setProperty('--amily2-bg-image', imageUrl); }