From f794f9562a9f78c9c548b46bb9f68b65357ec23d Mon Sep 17 00:00:00 2001 From: Wx-2025 <351320169@qq.com> Date: Wed, 3 Sep 2025 13:16:48 +0800 Subject: [PATCH] Update hanlinyuan-bindings.js --- ui/hanlinyuan-bindings.js | 602 +------------------------------------- 1 file changed, 1 insertion(+), 601 deletions(-) diff --git a/ui/hanlinyuan-bindings.js b/ui/hanlinyuan-bindings.js index d35f47f..fc136da 100644 --- a/ui/hanlinyuan-bindings.js +++ b/ui/hanlinyuan-bindings.js @@ -1,601 +1 @@ -import { extension_settings, getContext } from "/scripts/extensions.js"; -import { - extensionName, - defaultSettings, - saveSettings, -} from "../utils/settings.js"; -import { showHtmlModal } from './page-window.js'; -import { applyExclusionRules, extractBlocksByTags } from '../core/utils/rag-tag-extractor.js'; - -import { - getAvailableWorldbooks, getLoresForWorldbook, - executeManualSummary, executeRefinement, - executeExpedition, stopExpedition -} from "../core/historiographer.js"; - -import { getNgmsApiSettings, testNgmsApiConnection, fetchNgmsModels } from "../core/api/Ngms_api.js"; - - -function setupPromptEditor(type) { - const selector = document.getElementById( - `amily2_mhb_${type}_prompt_selector`, - ); - const editor = document.getElementById(`amily2_mhb_${type}_editor`); - const saveBtn = document.getElementById(`amily2_mhb_${type}_save_button`); - const restoreBtn = document.getElementById( - `amily2_mhb_${type}_restore_button`, - ); - - const jailbreakKey = - type === "small" - ? "historiographySmallJailbreakPrompt" - : "historiographyLargeJailbreakPrompt"; - const mainPromptKey = - type === "small" - ? "historiographySmallSummaryPrompt" - : "historiographyLargeRefinePrompt"; - - const updateEditorView = () => { - const selected = selector.value; - if (selected === "jailbreak") { - editor.value = extension_settings[extensionName][jailbreakKey]; - } else { - editor.value = extension_settings[extensionName][mainPromptKey]; - } - }; - - selector.addEventListener("change", updateEditorView); - - saveBtn.addEventListener("click", () => { - const selected = selector.value; - if (selected === "jailbreak") { - extension_settings[extensionName][jailbreakKey] = editor.value; - } else { - extension_settings[extensionName][mainPromptKey] = editor.value; - } - if (saveSettings()) { - toastr.success( - `${type === "small" ? "微言录" : "宏史卷"}的${selected === "jailbreak" ? "破限谕旨" : "纲要"}已保存!`, - ); - } - }); - - restoreBtn.addEventListener("click", () => { - const selected = selector.value; - if (selected === "jailbreak") { - editor.value = defaultSettings[jailbreakKey]; - } else { - editor.value = defaultSettings[mainPromptKey]; - } - toastr.info("已恢复为默认谕旨,请点击“保存当前”以确认。"); - }); - - updateEditorView(); - - - const expandBtn = document.getElementById(`amily2_mhb_${type}_expand_editor`); - - expandBtn.addEventListener('click', () => { - const selectedValue = selector.value; - const selectedText = selector.options[selector.selectedIndex].text; - const currentContent = editor.value; - - const dialogHtml = ` - `; - - const dialogElement = $(dialogHtml).appendTo('body'); - const dialogTextarea = dialogElement.find('textarea'); - dialogTextarea.val(currentContent); - - const closeDialog = () => { dialogElement[0].close(); dialogElement.remove(); }; - - dialogElement.find('.popup-button-ok').on('click', () => { - const newContent = dialogTextarea.val(); - editor.value = newContent; - if (selectedValue === "jailbreak") { - extension_settings[extensionName][jailbreakKey] = newContent; - } else { - extension_settings[extensionName][mainPromptKey] = newContent; - } - if (saveSettings()) { - toastr.success(`${type === 'small' ? '微言录' : '宏史卷'}的${selectedText}已镌刻!`); - } - closeDialog(); - }); - - dialogElement.find('.popup-button-cancel').on('click', closeDialog); - dialogElement[0].showModal(); - }); - -} - -export function bindHistoriographyEvents() { - console.log("[Amily2号-工部] 【敕史局】的专属工匠已就位..."); - - setupPromptEditor("small"); - setupPromptEditor("large"); - - // ========== 🛰️ Ngms API 系统绑定 ========== - bindNgmsApiEvents(); - - // ========== 📜 微言录 (Small Summary) 绑定 (无改动) ========== - const smallStartFloor = document.getElementById("amily2_mhb_small_start_floor"); - const smallEndFloor = document.getElementById("amily2_mhb_small_end_floor"); - const smallExecuteBtn = document.getElementById("amily2_mhb_small_manual_execute"); - const smallAutoEnable = document.getElementById("amily2_mhb_small_auto_enabled"); - const smallTriggerThreshold = document.getElementById("amily2_mhb_small_trigger_count"); - const writeToLorebook = document.getElementById("historiography_write_to_lorebook"); - const ingestToRag = document.getElementById("historiography_ingest_to_rag"); - - smallExecuteBtn.addEventListener("click", () => { - const start = parseInt(smallStartFloor.value, 10); - const end = parseInt(smallEndFloor.value, 10); - if (isNaN(start) || isNaN(end) || start <= 0 || end <= 0 || start > end) { - toastr.error("请输入有效的起始和结束楼层!", "圣谕有误"); - return; - } - executeManualSummary(start, end); - }); - - smallAutoEnable.addEventListener("change", (event) => { - extension_settings[extensionName].historiographySmallAutoEnable = event.target.checked; - saveSettings(); - }); - - smallTriggerThreshold.addEventListener("change", (event) => { - const value = parseInt(event.target.value, 10); - if (isNaN(value) || value < 1) { - - event.target.value = defaultSettings.historiographySmallTriggerThreshold; - toastr.warning("远征阈值必须是大于0的数字。已重置。", "圣谕有误"); - return; - } - extension_settings[extensionName].historiographySmallTriggerThreshold = value; - saveSettings(); - }); - - writeToLorebook.addEventListener("change", (event) => { - extension_settings[extensionName].historiographyWriteToLorebook = event.target.checked; - saveSettings(); - }); - - ingestToRag.addEventListener("change", (event) => { - extension_settings[extensionName].historiographyIngestToRag = event.target.checked; - saveSettings(); - }); - - - smallAutoEnable.checked = extension_settings[extensionName].historiographySmallAutoEnable ?? false; - smallTriggerThreshold.value = extension_settings[extensionName].historiographySmallTriggerThreshold ?? 30; - writeToLorebook.checked = extension_settings[extensionName].historiographyWriteToLorebook ?? true; - ingestToRag.checked = extension_settings[extensionName].historiographyIngestToRag ?? false; - - const autoSummaryInteractive = document.getElementById("historiography_auto_summary_interactive"); - autoSummaryInteractive.checked = extension_settings[extensionName].historiographyAutoSummaryInteractive ?? false; - autoSummaryInteractive.addEventListener("change", (event) => { - extension_settings[extensionName].historiographyAutoSummaryInteractive = event.target.checked; - saveSettings(); - }); - - // ========== 🏷️ 标签与排除规则绑定 (新增) ========== - const tagExtractionToggle = document.getElementById("historiography-tag-extraction-toggle"); - const tagInputContainer = document.getElementById("historiography-tag-input-container"); - const tagInput = document.getElementById("historiography-tag-input"); - const exclusionRulesBtn = document.getElementById("historiography-exclusion-rules-btn"); - - tagExtractionToggle.checked = extension_settings[extensionName].historiographyTagExtractionEnabled ?? false; - tagInput.value = extension_settings[extensionName].historiographyTags ?? ''; - tagInputContainer.style.display = tagExtractionToggle.checked ? 'block' : 'none'; - - tagExtractionToggle.addEventListener("change", (event) => { - const isEnabled = event.target.checked; - extension_settings[extensionName].historiographyTagExtractionEnabled = isEnabled; - tagInputContainer.style.display = isEnabled ? 'block' : 'none'; - saveSettings(); - }); - - tagInput.addEventListener("change", (event) => { - extension_settings[extensionName].historiographyTags = event.target.value; - saveSettings(); - }); - - exclusionRulesBtn.addEventListener("click", showHistoriographyExclusionRulesModal); - - - const expeditionExecuteBtn = document.getElementById("amily2_mhb_small_expedition_execute"); - - const updateExpeditionButtonUI = (state) => { - expeditionExecuteBtn.dataset.state = state; - switch (state) { - case 'running': - expeditionExecuteBtn.innerHTML = ' 停止远征'; - expeditionExecuteBtn.className = 'menu_button small_button interactable danger'; - break; - case 'paused': - expeditionExecuteBtn.innerHTML = ' 继续远征'; - expeditionExecuteBtn.className = 'menu_button small_button interactable success'; - break; - case 'idle': - default: - expeditionExecuteBtn.innerHTML = ' 开始远征'; - expeditionExecuteBtn.className = 'menu_button small_button interactable'; - break; - } - }; - - document.addEventListener('amily2-expedition-state-change', (e) => { - const { isRunning, manualStop } = e.detail; - if (isRunning) { - updateExpeditionButtonUI('running'); - } else if (manualStop) { - updateExpeditionButtonUI('paused'); - } else { - updateExpeditionButtonUI('idle'); - } - }); - - expeditionExecuteBtn.addEventListener("click", () => { - const currentState = expeditionExecuteBtn.dataset.state || 'idle'; - if (currentState === 'running') { - stopExpedition(); - } else { - executeExpedition(); - } - }); - - updateExpeditionButtonUI('idle'); - - // ========== 💎 宏史卷 (史册精炼) 绑定 ========== - const largeWbSelector = document.getElementById( - "amily2_mhb_large_worldbook_selector", - ); - const largeLoreSelector = document.getElementById( - "amily2_mhb_large_lore_selector", - ); - const largeRefreshWbBtn = document.getElementById( - "amily2_mhb_large_refresh_worldbooks", - ); - const largeRefreshLoresBtn = document.getElementById( - "amily2_mhb_large_refresh_lores", - ); - const largeRefineBtn = document.getElementById( - "amily2_mhb_large_refine_execute", - ); - - const updateWorldbookList = async () => { - largeWbSelector.innerHTML = ''; - const worldbooks = await getAvailableWorldbooks(); - largeWbSelector.innerHTML = ""; // 清空 - if (worldbooks && worldbooks.length > 0) { - worldbooks.forEach((wb) => { - const option = document.createElement("option"); - option.value = wb; - option.textContent = wb; - largeWbSelector.appendChild(option); - }); - - largeWbSelector.dispatchEvent(new Event("change")); - } else { - largeWbSelector.innerHTML = ''; - } - }; - - const updateLoreList = async () => { - const selectedWb = largeWbSelector.value; - if (!selectedWb) { - largeLoreSelector.innerHTML = ''; - return; - } - largeLoreSelector.innerHTML = ''; - const lores = await getLoresForWorldbook(selectedWb); - largeLoreSelector.innerHTML = ""; // 清空 - if (lores && lores.length > 0) { - lores.forEach((lore) => { - const option = document.createElement("option"); - option.value = lore.key; - option.textContent = `[${lore.key}] ${lore.comment}`; - largeLoreSelector.appendChild(option); - }); - } else { - largeLoreSelector.innerHTML = ''; - } - }; - - largeRefreshWbBtn.addEventListener("click", updateWorldbookList); - largeWbSelector.addEventListener("change", updateLoreList); - largeRefreshLoresBtn.addEventListener("click", updateLoreList); - - largeRefineBtn.addEventListener("click", () => { - const worldbook = largeWbSelector.value; - const loreKey = largeLoreSelector.value; - if (!worldbook || !loreKey) { - toastr.error("请先选择一个国史馆及其中的史册条目!", "圣谕不全"); - return; - } - - executeRefinement(worldbook, loreKey); - }); - - - const vectorizeSummaryContent = document.getElementById("amily2_vectorize_summary_content"); - vectorizeSummaryContent.checked = extension_settings[extensionName].historiographyVectorizeSummary ?? false; - vectorizeSummaryContent.addEventListener("change", (event) => { - extension_settings[extensionName].historiographyVectorizeSummary = event.target.checked; - saveSettings(); - }); -} - - -// ========== Ngms API 事件绑定函数 ========== -function bindNgmsApiEvents() { - console.log("[Amily2号-Ngms工部] 正在绑定Ngms API事件..."); - - const updateAndSaveSetting = (key, value) => { - console.log(`[Amily2-Ngms令] 收到指令: 将 [${key}] 设置为 ->`, value); - if (!extension_settings[extensionName]) { - extension_settings[extensionName] = {}; - } - extension_settings[extensionName][key] = value; - saveSettings(); - console.log(`[Amily2-Ngms录] [${key}] 的新状态已保存。`); - }; - - // Ngms API 开关控制 - const ngmsToggle = document.getElementById('amily2_ngms_enabled'); - const ngmsContent = document.getElementById('amily2_ngms_content'); - - if (ngmsToggle && ngmsContent) { - ngmsToggle.checked = extension_settings[extensionName].ngmsEnabled ?? false; - ngmsContent.style.display = ngmsToggle.checked ? 'block' : 'none'; - - ngmsToggle.addEventListener('change', function() { - const isEnabled = this.checked; - updateAndSaveSetting('ngmsEnabled', isEnabled); - ngmsContent.style.display = isEnabled ? 'block' : 'none'; - }); - } - - // API模式切换 - const apiModeSelect = document.getElementById('amily2_ngms_api_mode'); - const compatibleConfig = document.getElementById('amily2_ngms_compatible_config'); - const presetConfig = document.getElementById('amily2_ngms_preset_config'); - - if (apiModeSelect && compatibleConfig && presetConfig) { - apiModeSelect.value = extension_settings[extensionName].ngmsApiMode || 'openai_test'; - - const updateConfigVisibility = (mode) => { - if (mode === 'sillytavern_preset') { - compatibleConfig.style.display = 'none'; - presetConfig.style.display = 'block'; - loadNgmsTavernPresets(); - } else { - compatibleConfig.style.display = 'block'; - presetConfig.style.display = 'none'; - } - }; - - updateConfigVisibility(apiModeSelect.value); - - apiModeSelect.addEventListener('change', function() { - updateAndSaveSetting('ngmsApiMode', this.value); - updateConfigVisibility(this.value); - }); - } - - // API配置字段绑定 - const apiFields = [ - { id: 'amily2_ngms_api_url', key: 'ngmsApiUrl' }, - { id: 'amily2_ngms_api_key', key: 'ngmsApiKey' }, - { id: 'amily2_ngms_model', key: 'ngmsModel' } - ]; - - apiFields.forEach(field => { - const element = document.getElementById(field.id); - if (element) { - element.value = extension_settings[extensionName][field.key] || ''; - element.addEventListener('change', function() { - updateAndSaveSetting(field.key, this.value); - }); - } - }); - - // 滑块控件绑定 - const sliderFields = [ - { id: 'amily2_ngms_max_tokens', key: 'ngmsMaxTokens', defaultValue: 4000 }, - { id: 'amily2_ngms_temperature', key: 'ngmsTemperature', 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_ngms_tavern_profile'); - if (tavernProfileSelect) { - tavernProfileSelect.value = extension_settings[extensionName].ngmsTavernProfile || ''; - tavernProfileSelect.addEventListener('change', function() { - updateAndSaveSetting('ngmsTavernProfile', this.value); - }); - } - - // 测试连接按钮 - const testButton = document.getElementById('amily2_ngms_test_connection'); - if (testButton) { - testButton.addEventListener('click', async function() { - const button = $(this); - const originalHtml = button.html(); - button.prop('disabled', true).html(' 测试中'); - - try { - await testNgmsApiConnection(); - } catch (error) { - console.error('[Amily2号-Ngms] 测试连接失败:', error); - } finally { - button.prop('disabled', false).html(originalHtml); - } - }); - } - - // 获取模型按钮 - const fetchModelsButton = document.getElementById('amily2_ngms_fetch_models'); - const modelSelect = document.getElementById('amily2_ngms_model_select'); - const modelInput = document.getElementById('amily2_ngms_model'); - - if (fetchModelsButton && modelSelect && modelInput) { - fetchModelsButton.addEventListener('click', async function() { - const button = $(this); - const originalHtml = button.html(); - button.prop('disabled', true).html(' 获取中'); - - try { - const models = await fetchNgmsModels(); - - if (models && models.length > 0) { - // 清空并填充模型下拉框 - modelSelect.innerHTML = ''; - 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('ngmsModel', selectedModel); - console.log(`[Amily2-Ngms] 已选择模型: ${selectedModel}`); - }); - - toastr.success(`成功获取 ${models.length} 个模型`, 'Ngms 模型获取'); - } else { - toastr.warning('未获取到任何模型', 'Ngms 模型获取'); - } - - } catch (error) { - console.error('[Amily2号-Ngms] 获取模型列表失败:', error); - toastr.error(`获取模型失败: ${error.message}`, 'Ngms 模型获取'); - } finally { - button.prop('disabled', false).html(originalHtml); - } - }); - } -} - -// 加载SillyTavern预设列表 -async function loadNgmsTavernPresets() { - const select = document.getElementById('amily2_ngms_tavern_profile'); - if (!select) return; - - const currentValue = select.value; - select.innerHTML = ''; - - try { - const context = getContext(); - const tavernProfiles = context.extensionSettings?.connectionManager?.profiles || []; - - select.innerHTML = ''; - - 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 = ''; - } - } catch (error) { - console.error('[Amily2号-Ngms] 加载SillyTavern预设失败:', error); - select.innerHTML = ''; - } -} - -function showHistoriographyExclusionRulesModal() { - const rules = extension_settings[extensionName].historiographyExclusionRules || []; - - const createRuleRowHtml = (rule = { start: '', end: '' }, index) => ` -
在这里定义需要从提取内容中排除的文本片段。例如,排除HTML注释,可以设置开始字符为 \`\`。
-加载知识库列表失败:\x20','[翰林院-枢纽]\x20手动录入过程发生错误:','处理中:\x20','任务完成!成功录入\x20','fetchEmbeddingModels','apiEndpoint','\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20 当前角色还没有专属知识库。 可在此预览凝识结果。