Add files via upload

This commit is contained in:
2025-07-07 02:07:41 +08:00
committed by GitHub
parent 93aeacc707
commit a5c5faf328
14 changed files with 2020 additions and 0 deletions

196
ui/bindings.js Normal file
View File

@@ -0,0 +1,196 @@
import { extension_settings } from "/scripts/extensions.js";
import { saveSettingsDebounced } from "/script.js";
import { defaultSettings, extensionName } from "../utils/settings.js";
import { pluginAuthStatus, activatePluginAuthorization } from "../utils/auth.js";
import { fetchSupportedModels } from "../core/api.js";
import { setAvailableModels, populateModelDropdown } from "./state.js";
import { fixCommand, testReplyChecker } from "../core/commands.js";
export function bindModalEvents() {
const container = $("#amily2-drawer-content");
if (container.data("events-bound")) return;
const snakeToCamel = (s) => s.replace(/_([a-z])/g, (g) => g[1].toUpperCase());
const updateAndSaveSetting = (key, value) => {
console.log(`[Amily-谕令确认] 收到指令: 将 [${key}] 设置为 ->`, value);
if (!extension_settings[extensionName]) {
extension_settings[extensionName] = {};
}
extension_settings[extensionName] = {
...extension_settings[extensionName],
[key]: value,
};
saveSettingsDebounced();
console.log(`[Amily-谕令镌刻] [${key}] 的新状态已保存。`);
};
container
.off("click.amily2.auth")
.on("click.amily2.auth", "#auth_submit", async function () {
const authCode = $("#amily2_auth_code").val().trim();
if (authCode) {
await activatePluginAuthorization(authCode);
} else {
toastr.warning("请输入授权码", "Amily2号");
}
});
container
.off("click.amily2.actions")
.on(
"click.amily2.actions",
"#amily2_refresh_models, #amily2_test, #amily2_fix_now",
async function () {
if (!pluginAuthStatus.authorized) return;
const button = $(this);
const originalHtml = button.html();
button
.prop("disabled", true)
.html('<i class="fas fa-spinner fa-spin"></i> 处理中');
try {
switch (this.id) {
case "amily2_refresh_models":
const models = await fetchSupportedModels();
if (models.length > 0) {
setAvailableModels(models);
localStorage.setItem(
"cached_models_amily2",
JSON.stringify(models),
);
populateModelDropdown();
}
break;
case "amily2_test":
await testReplyChecker();
break;
case "amily2_fix_now":
await fixCommand();
break;
}
} catch (error) {
console.error(`[Amily2-工部] 操作按钮 ${this.id} 执行失败:`, error);
toastr.error(`操作失败: ${error.message}`, "Amily2号");
} finally {
button.prop("disabled", false).html(originalHtml);
}
},
);
container
.off("change.amily2.checkbox")
.on(
"change.amily2.checkbox",
'input[type="checkbox"][id^="amily2_"]',
function () {
if (!pluginAuthStatus.authorized) return;
const key = snakeToCamel(this.id.replace("amily2_", ""));
updateAndSaveSetting(key, this.checked);
},
);
container
.off("change.amily2.radio")
.on(
"change.amily2.radio",
'input[type="radio"][name^="amily2_"]',
function () {
if (!pluginAuthStatus.authorized) return;
const key = snakeToCamel(this.name.replace("amily2_", ""));
const value = $(`input[name="${this.name}"]:checked`).val();
updateAndSaveSetting(key, value);
},
);
container
.off("change.amily2.text")
.on("change.amily2.text", "#amily2_api_url, #amily2_api_key", function () {
if (!pluginAuthStatus.authorized) return;
const key = snakeToCamel(this.id.replace("amily2_", ""));
updateAndSaveSetting(key, this.value);
toastr.success(`配置 [${key}] 已自动保存!`, "Amily2号");
});
container
.off("change.amily2.select")
.on("change.amily2.select", "select#amily2_model", function () {
if (!pluginAuthStatus.authorized) return;
const key = snakeToCamel(this.id.replace("amily2_", ""));
updateAndSaveSetting(key, this.value);
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);
},
);
const promptMap = {
mainPrompt: "#amily2_main_prompt",
systemPrompt: "#amily2_system_prompt",
summarizationPrompt: "#amily2_summarization_prompt",
outputFormatPrompt: "#amily2_output_format_prompt",
};
const selector = "#amily2_prompt_selector";
const editor = "#amily2_unified_editor";
const unifiedSaveButton = "#amily2_unified_save_button";
function updateEditorView() {
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("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号");
});
setTimeout(updateEditorView, 100);
container.data("events-bound", true);
}

131
ui/drawer.js Normal file
View File

@@ -0,0 +1,131 @@
import { extension_settings } from "/scripts/extensions.js";
import { extensionName, defaultSettings } from "../utils/settings.js";
import {
checkAuthorization,
displayExpiryInfo,
pluginAuthStatus,
} from "../utils/auth.js";
import {
updateUI,
setAvailableModels,
populateModelDropdown,
} from "./state.js";
import { bindModalEvents } from "./bindings.js";
import { fetchSupportedModels } from "../core/api.js";
const extensionFolderPath = `scripts/extensions/third-party/${extensionName}`;
async function loadSettings() {
if (!extension_settings[extensionName]) {
extension_settings[extensionName] = {};
}
Object.assign(extension_settings[extensionName], {
...defaultSettings,
...extension_settings[extensionName],
});
checkAuthorization();
const autoLogin = localStorage.getItem("plugin_auto_login") === "true";
console.log(
`[Amily2-调试] 授权状态: ${pluginAuthStatus.authorized}, 自动登录标志: ${autoLogin}`,
);
if (autoLogin && pluginAuthStatus.authorized) {
console.log("[Amily2号] 检测到有效授权将执行自动UI更新。");
}
$("#expiry_info").html(displayExpiryInfo());
updateUI();
if (pluginAuthStatus.authorized && extension_settings[extensionName].apiUrl) {
const cachedModels = localStorage.getItem("cached_models_amily2");
if (cachedModels) {
const models = JSON.parse(cachedModels);
console.log(`[Amily2号] 从缓存加载模型列表 (${models.length}个)`);
setAvailableModels(models);
populateModelDropdown();
} else {
toastr.info("正在自动加载模型列表...", "Amily2号");
setTimeout(async () => {
const models = await fetchSupportedModels();
if (models.length > 0) {
setAvailableModels(models);
localStorage.setItem("cached_models_amily2", JSON.stringify(models));
populateModelDropdown();
}
}, 500);
}
}
}
export function createDrawer() {
if ($("#amily2-main-drawer").length > 0) return;
const amily2DrawerHtml = `
<div id="amily2-main-drawer" class="drawer">
<div class="drawer-toggle drawer-header" title="Amily2号优化助手">
<div id="amily2-drawer-icon" class="drawer-icon fa-solid fa-magic fa-fw closedIcon interactable" tabindex="0"></div>
</div>
<div id="amily2-drawer-content" class="drawer-content" style="display: none;">
<!-- 王座将在此处动态加载 -->
</div>
</div>
`;
$("#sys-settings-button").after(amily2DrawerHtml);
$(document).on(
"mousedown",
"#amily2-main-drawer .drawer-toggle",
async function (e) {
e.preventDefault();
e.stopPropagation();
const drawerIcon = $("#amily2-drawer-icon");
const contentPanel = $("#amily2-drawer-content");
const isOpening = drawerIcon.hasClass("closedIcon");
$(".openIcon")
.not(drawerIcon)
.removeClass("openIcon")
.addClass("closedIcon");
$(".openDrawer")
.not(contentPanel)
.removeClass("openDrawer")
.slideUp({ duration: 200, easing: "swing" });
drawerIcon.toggleClass("closedIcon openIcon");
contentPanel.toggleClass("openDrawer");
contentPanel.slideToggle({
duration: 200,
easing: "swing",
});
const isInitialized = contentPanel.data("initialized");
if (isOpening && !isInitialized) {
try {
const modalContent = await $.get(
`${extensionFolderPath}/assets/amily2-modal.html`,
);
contentPanel.html(modalContent);
await loadSettings();
bindModalEvents();
contentPanel.data("initialized", true);
console.log("[Amily2号-建设部] 宫殿内室已根据最高指令激活。");
} catch (error) {
console.error("[Amily2号-建设部] 加载宫殿内部HTML失败:", error);
contentPanel.html(
'<p style="color:red; padding: 20px;">紧急报告无法加载Amily2号府邸内饰。</p>',
);
}
}
},
);
}

104
ui/state.js Normal file
View File

@@ -0,0 +1,104 @@
import { extension_settings } from "/scripts/extensions.js";
import { extensionName } from "../utils/settings.js";
import { pluginAuthStatus } from "../utils/auth.js";
let availableModels = [];
export function setAvailableModels(models) {
availableModels = models;
}
export function populateModelDropdown() {
const modelSelect = $("#amily2_model");
const modelNotes = $("#amily2_model_notes");
modelSelect.empty();
const currentModel = extension_settings[extensionName]?.model || "";
if (availableModels.length === 0) {
modelSelect.append('<option value="">无可用模型,请刷新</option>');
modelNotes.html(
'<span style="color: #ff9800;">请检查API配置后点击"刷新模型"</span>',
);
return;
}
const defaultOption = $("<option></option>").val("").text("-- 选择模型 --");
modelSelect.append(defaultOption);
availableModels.forEach((model) => {
const option = $("<option></option>").val(model).text(model);
if (model === currentModel) {
option.attr("selected", "selected");
}
modelSelect.append(option);
});
if (currentModel && modelSelect.val() === currentModel) {
modelNotes.html(`已选择: <strong>${currentModel}</strong>`);
} else {
modelNotes.html(`已加载 ${availableModels.length} 个可用模型`);
}
}
export function updateUI() {
if (!pluginAuthStatus.authorized) {
$("#auth_panel").show();
$(".plugin-features").hide();
} else {
$("#auth_panel").hide();
$(".plugin-features").show();
const settings = extension_settings[extensionName];
if (!settings) return; // 安全检查
// --- 通用设置 ---
$("#amily2_enabled").prop("checked", settings.enabled);
$("#amily2_api_url").val(settings.apiUrl);
$("#amily2_api_key").val(settings.apiKey);
$("#amily2_model").val(settings.model);
$("#amily2_max_tokens").val(settings.maxTokens);
$("#amily2_max_tokens_value").text(settings.maxTokens);
$("#amily2_temperature").val(settings.temperature);
$("#amily2_temperature_value").text(settings.temperature);
$("#amily2_context_messages").val(settings.contextMessages);
$("#amily2_context_messages_value").text(settings.contextMessages);
$(
`input[name="amily2_optimization_mode"][value="${settings.optimizationMode}"]`,
).prop("checked", true);
$("#amily2_optimization_enabled").prop(
"checked",
settings.optimizationEnabled,
);
$("#amily2_show_optimization_toast").prop(
"checked",
settings.showOptimizationToast,
);
$("#amily2_suppress_toast").prop("checked", settings.suppressToast);
$("#amily2_system_prompt").val(settings.systemPrompt);
$("#amily2_main_prompt").val(settings.mainPrompt);
$("#amily2_output_format_prompt").val(settings.outputFormatPrompt);
$("#amily2_summarization_prompt").val(settings.summarizationPrompt);
$("#amily2_worldbook_enabled").prop("checked", settings.worldbookEnabled);
$("#amily2_summarization_enabled").prop(
"checked",
settings.summarizationEnabled,
);
$(
`input[name="amily2_lorebook_target"][value="${settings.lorebookTarget}"]`,
).prop("checked", true);
populateModelDropdown();
}
}