From 2a739c5afb49acbbaa50bcd68358b19aa17700d5 Mon Sep 17 00:00:00 2001 From: Wx-2025 <351320169@qq.com> Date: Sun, 19 Oct 2025 17:16:58 +0800 Subject: [PATCH] Update GT_bindings.js --- glossary/GT_bindings.js | 771 +++++++++------------------------------- 1 file changed, 163 insertions(+), 608 deletions(-) diff --git a/glossary/GT_bindings.js b/glossary/GT_bindings.js index 901efd2..b4d2b22 100644 --- a/glossary/GT_bindings.js +++ b/glossary/GT_bindings.js @@ -1,630 +1,185 @@ -import { extension_settings, getContext } from "/scripts/extensions.js"; -import { saveSettingsDebounced, eventSource, event_types } from "/script.js"; -import { world_names } from "/scripts/world-info.js"; -import { extensionName } from "../utils/settings.js"; -import { testSybdApiConnection, fetchSybdModels } from '../core/api/SybdApi.js'; -import { handleFileUpload, processNovel } from './index.js'; -import { SETTINGS_KEY as PRESET_SETTINGS_KEY } from '../PresetSettings/config.js'; +import { callSybdAI } from '../core/api/SybdApi.js'; +import { extensionName } from '../utils/settings.js'; +import { getPresetPrompts, getMixedOrder } from '../PresetSettings/index.js'; +import { generateRandomSeed } from '../core/api.js'; +import { safeLorebookEntries, safeUpdateLorebookEntries, compatibleWriteToLorebook } from '../core/tavernhelper-compatibility.js'; -const moduleState = { - selectedWorldBook: '', -}; - -function updateAndSaveSetting(key, value) { - if (!extension_settings[extensionName]) { - extension_settings[extensionName] = {}; +function buildContextFromEntries(entries) { + if (!entries || entries.length === 0) { + return '当前世界书为空。'; } - extension_settings[extensionName][key] = value; - saveSettingsDebounced(); - console.log(`[Amily2-术语表] 设置项 '${key}' 已更新为: ${JSON.stringify(value)}`); + + const mappedContent = entries.map(entry => { + if (!Array.isArray(entry.keys) || entry.keys.length < 2) { + return null; + } + const name = entry.keys[1]; + return `[--START_TABLE--]\n[name]:${name}\n${entry.content}\n[--END_TABLE--]`; + }).filter(Boolean).join('\n\n'); + + return mappedContent || '当前世界书为空。'; } -function loadSettingsToUI() { - const settings = extension_settings[extensionName] || {}; - const container = document.getElementById('amily2_glossary_panel'); - if (!container) return; +function parseStructuredResponse(responseText) { + const entries = []; + const entryRegex = /\[--START_TABLE--\]\s*\[name\]:(.*?)\n([\s\S]*?)\[--END_TABLE--\]/g; + let match; - const inputs = container.querySelectorAll('[data-setting-key]'); - inputs.forEach(target => { - const key = target.dataset.settingKey; - const value = settings[key]; - - if (value === undefined) { - let defaultValue; - if (target.type === 'checkbox') { - defaultValue = target.checked; - } else if (target.type === 'range') { - defaultValue = target.dataset.type === 'float' ? parseFloat(target.value) : parseInt(target.value, 10); - } else { - defaultValue = target.value; - } - updateAndSaveSetting(key, defaultValue); - return; - }; - - if (target.type === 'checkbox') { - target.checked = value; - } else if (target.type === 'range') { - target.value = value; - const valueDisplay = document.getElementById(`${target.id}_value`); - if (valueDisplay) valueDisplay.textContent = value; + while ((match = entryRegex.exec(responseText)) !== null) { + const title = match[1].trim(); + const content = match[2].trim(); + if (title && content) { + entries.push({ title, content }); } - else { - target.value = value; - } - }); - - const sybdContent = document.getElementById('amily2_sybd_content'); - if (sybdContent) { - sybdContent.classList.remove('amily2-content-hidden'); - } - - const apiModeSelect = document.getElementById('amily2_sybd_api_mode'); - if (apiModeSelect) { - updateConfigVisibility(apiModeSelect.value); - } -} - -function bindAutoSaveEvents() { - const container = document.getElementById('amily2_glossary_panel'); - if (!container) return; - - const handler = (event) => { - const target = event.target; - const key = target.dataset.settingKey; - if (!key) return; - - let value; - const type = target.dataset.type || 'string'; - - if (target.type === 'checkbox') { - value = target.checked; - } else { - value = target.value; - } - - switch (type) { - case 'integer': value = parseInt(value, 10); break; - case 'float': value = parseFloat(value); break; - case 'boolean': value = (typeof value === 'boolean') ? value : (value === 'true'); break; - } - - updateAndSaveSetting(key, value); - - if (key === 'sybdApiMode') { - updateConfigVisibility(value); - } - if (target.type === 'range') { - document.getElementById(`${target.id}_value`).textContent = value; - } - }; - - container.addEventListener('change', handler); - container.addEventListener('input', (event) => { - if (event.target.type === 'range') handler(event); - }); -} - -function updateConfigVisibility(mode) { - const compatibleConfig = document.getElementById('amily2_sybd_compatible_config'); - const presetConfig = document.getElementById('amily2_sybd_preset_config'); - - if (mode === 'sillytavern_preset') { - compatibleConfig.style.display = 'none'; - presetConfig.style.display = 'block'; - loadTavernPresets(); - } else { - compatibleConfig.style.display = 'block'; - presetConfig.style.display = 'none'; - } -} - -async function loadTavernPresets() { - const select = document.getElementById('amily2_sybd_tavern_profile'); - if (!select) return; - - const currentValue = extension_settings[extensionName]?.sybdTavernProfile || ''; - 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 = new Option(profile.name || profile.id, profile.id); - select.add(option); - } - }); - select.value = currentValue; - } else { - select.innerHTML = ''; - } - } catch (error) { - console.error('[Amily2-术语表] 加载SillyTavern预设失败:', error); - select.innerHTML = ''; - } -} - -function bindManualActionEvents() { - const testBtn = document.getElementById('amily2_sybd_test_connection'); - if (testBtn) { - testBtn.addEventListener('click', async () => { - const originalHtml = testBtn.innerHTML; - testBtn.disabled = true; - testBtn.innerHTML = ' 测试中'; - await testSybdApiConnection(); - testBtn.disabled = false; - testBtn.innerHTML = originalHtml; - }); - } - - const fetchBtn = document.getElementById('amily2_sybd_fetch_models'); - const modelSelect = document.getElementById('amily2_sybd_model_select'); - const modelInput = document.getElementById('amily2_sybd_model'); - - if (fetchBtn && modelSelect && modelInput) { - fetchBtn.addEventListener('click', async () => { - const originalHtml = fetchBtn.innerHTML; - fetchBtn.disabled = true; - fetchBtn.innerHTML = ' 获取中'; - - try { - const models = await fetchSybdModels(); - if (models && models.length > 0) { - modelSelect.innerHTML = ''; - models.forEach(model => { - const option = new Option(model.name || model.id, model.id); - modelSelect.add(option); - }); - - modelSelect.style.display = 'block'; - modelInput.style.display = 'none'; - toastr.success(`成功获取 ${models.length} 个模型`); - } else { - toastr.warning('未获取到任何模型'); - } - } catch (error) { - toastr.error(`获取模型失败: ${error.message}`); - } finally { - fetchBtn.disabled = false; - fetchBtn.innerHTML = originalHtml; - } - }); - - modelSelect.addEventListener('change', () => { - const selectedModel = modelSelect.value; - if (selectedModel) { - modelInput.value = selectedModel; - modelInput.dispatchEvent(new Event('change', { bubbles: true })); - } - }); - } -} - -async function renderWorldBookEntries() { - const container = document.getElementById('world-book-entries-display'); - if (!container) return; - - const selectedBook = moduleState.selectedWorldBook; - if (!selectedBook) { - container.innerHTML = '

请先在“小说处理”标签页中选择一个世界书。

'; - return; - } - - container.innerHTML = '

正在加载条目...

'; - - try { - const { TavernHelper } = window; - if (!TavernHelper) { - container.innerHTML = '

TavernHelper 未找到!

'; - return; - } - - const allEntries = await TavernHelper.getLorebookEntries(selectedBook); - let managedEntries = allEntries.filter(e => e.comment?.startsWith('[Amily2小说处理]')); - - if (managedEntries.length === 0) { - container.innerHTML = '

未找到由小说处理功能生成的条目。

'; - return; - } - - container.innerHTML = ''; - - const summaryEntries = managedEntries.filter(e => e.comment.replace('[Amily2小说处理]', '').trim().startsWith('章节内容概述')); - const otherEntries = managedEntries.filter(e => !e.comment.replace('[Amily2小说处理]', '').trim().startsWith('章节内容概述')); - const sortedEntries = otherEntries.concat(summaryEntries); - - sortedEntries.forEach(entry => { - const entryElement = document.createElement('div'); - entryElement.className = 'world-book-entry-item'; - entryElement.dataset.entryId = entry.uid; - - const title = entry.comment.replace('[Amily2小说处理]', '').trim(); - - const renderContent = (content) => { - const trimmedContent = content.trim(); - if (trimmedContent.startsWith('graph') || trimmedContent.startsWith('flowchart')) { - try { - const lines = trimmedContent.split('\n').map(l => l.trim()).filter(l => l.includes('-->') || l.includes('--')); - let body = ''; - lines.forEach(line => { - if (line.startsWith('flowchart')) return; - let source = '', rel = '', target = ''; - - let match = line.match(/(.+?)\s*--\s*"(.*?)"\s*-->(.+)/); - if (match) { - [source, rel, target] = [match[1], match[2], match[3]]; - } else { - match = line.match(/(.+?)\s*-->\s*\|(.*?)\|(.+)/); - if (match) { - [source, rel, target] = [match[1], match[2], match[3]]; - } else { - match = line.match(/(.+?)\s*-->(.+)/); - if (match) { - [source, target] = [match[1], match[2]]; - rel = '(直接关联)'; - } - } - } - - if (source && target) { - body += `${source.trim()}${rel.trim()}${target.trim().replace(';','')}`; - } - }); - return `${body}
源头关系目标
`; - } catch { - return `
${content}
`; - } - } - if (trimmedContent.includes('|') && trimmedContent.includes('\n')) { - try { - const rows = trimmedContent.split('\n').filter(row => row.trim() && row.includes('|')); - let header = ''; - let body = ''; - let isHeaderRow = true; - rows.forEach(rowStr => { - if (rowStr.includes('---')) return; - const cells = rowStr.split('|').filter(c => c.trim()).map(cell => `${cell.trim()}`).join(''); - if (isHeaderRow) { - header += `${cells.replace(//g, '').replace(/<\/td>/g, '')}`; - isHeaderRow = false; - } else { - body += `${cells}`; - } - }); - return `${header}${body}
`; - } catch { - return `
${content}
`; - } - } - return `
${content}
`; - }; - - entryElement.innerHTML = ` -
- ${title} -
- - - -
-
-
${renderContent(entry.content)}
- - `; - - const editBtn = entryElement.querySelector('.edit-entry-btn'); - const saveBtn = entryElement.querySelector('.save-entry-btn'); - const cancelBtn = entryElement.querySelector('.cancel-entry-btn'); - const displayDiv = entryElement.querySelector('.entry-content-display'); - const editorDiv = entryElement.querySelector('.entry-content-editor'); - const textarea = editorDiv.querySelector('textarea'); - const originalContent = entry.content; - - editBtn.addEventListener('click', () => { - displayDiv.style.display = 'none'; - editorDiv.style.display = 'block'; - saveBtn.style.display = 'inline-block'; - cancelBtn.style.display = 'inline-block'; - editBtn.style.display = 'none'; - }); - - const hideEditor = () => { - displayDiv.style.display = 'block'; - editorDiv.style.display = 'none'; - saveBtn.style.display = 'none'; - cancelBtn.style.display = 'none'; - editBtn.style.display = 'inline-block'; - }; - - cancelBtn.addEventListener('click', () => { - textarea.value = originalContent; - hideEditor(); - }); - - saveBtn.addEventListener('click', async () => { - const newContent = textarea.value; - - displayDiv.innerHTML = renderContent(newContent); - hideEditor(); - - try { - const { TavernHelper } = window; - const entryToUpdate = { uid: entry.uid, content: newContent }; - await TavernHelper.setLorebookEntries(selectedBook, [entryToUpdate]); - toastr.success(`条目 "${title}" 已保存。`); - entry.content = newContent; - } catch (error) { - displayDiv.innerHTML = renderContent(originalContent); - console.error('保存世界书条目失败:', error); - toastr.error(`保存失败: ${error.message}`); - } - }); - - container.appendChild(entryElement); - }); - - } catch (error) { - console.error('加载世界书条目失败:', error); - container.innerHTML = `

加载失败: ${error.message}

`; - } -} - - -function bindTabEvents() { - const tabs = document.querySelectorAll('.glossary-tab'); - const contents = document.querySelectorAll('.glossary-content'); - - tabs.forEach(tab => { - tab.addEventListener('click', () => { - const tabId = tab.dataset.tab; - - tabs.forEach(t => t.classList.remove('active')); - tab.classList.add('active'); - - contents.forEach(content => { - if (content.id === `glossary-content-${tabId}`) { - content.classList.add('active'); - } else { - content.classList.remove('active'); - } - }); - - if (tabId === 'context') { - renderWorldBookEntries(); - } - }); - }); -} - -function bindNovelProcessEvents() { - const fileInput = document.getElementById('novel-file-input'); - const fileLabel = document.querySelector('label[for="novel-file-input"]'); - const processBtn = document.getElementById('novel-confirm-and-process'); - const chunkSizeInput = document.getElementById('novel-chunk-size'); - const chunkCountEl = document.getElementById('novel-chunk-count'); - const chunkPreviewEl = document.getElementById('novel-chunk-preview'); - - let fileContent = ''; - let processingState = { - chunks: [], - batchSize: 1, - forceNew: false, - selectedWorldBook: '', - currentIndex: 0, - isAborted: false, - isRunning: false, - lastStatus: 'idle', - }; - - function updateChunks() { - if (!fileContent) return; - const chunkSize = parseInt(chunkSizeInput.value, 10) || 5000; - const newChunks = []; - for (let i = 0; i < fileContent.length; i += chunkSize) { - newChunks.push({ title: `Part ${i/chunkSize + 1}`, content: fileContent.substring(i, i + chunkSize) }); - } - processingState.chunks = newChunks; - - chunkCountEl.textContent = newChunks.length; - chunkPreviewEl.innerHTML = newChunks.map((chunk, index) => - `
块 ${index + 1}: ${chunk.content.substring(0, 100)}...
` - ).join(''); - - resetProcessing(); } - function resetProcessing() { - processingState.currentIndex = 0; - processingState.isAborted = false; - processingState.isRunning = false; - processingState.lastStatus = 'idle'; - updateButtonUI(); - } - - function updateButtonUI() { - if (processingState.isRunning) { - processBtn.disabled = false; - processBtn.innerHTML = ' 请求中止'; - processBtn.classList.add('danger'); - } else { - processBtn.classList.remove('danger'); - switch (processingState.lastStatus) { - case 'paused': - processBtn.innerHTML = ' 继续处理'; - processBtn.disabled = false; - break; - case 'failed': - processBtn.innerHTML = ' 重试处理'; - processBtn.disabled = false; - break; - case 'success': - processBtn.innerHTML = ' 处理完成'; - processBtn.disabled = true; - break; - case 'idle': - default: - processBtn.innerHTML = '确认并开始处理'; - processBtn.disabled = processingState.chunks.length === 0; - break; - } - } - } - - async function startOrResumeProcessing() { - if (processingState.isRunning) return; - - processingState.isRunning = true; - processingState.isAborted = false; - updateButtonUI(); - - processingState.forceNew = document.getElementById('novel-force-new').checked; - processingState.batchSize = 1; - processingState.selectedWorldBook = moduleState.selectedWorldBook; - - try { - const result = await processNovel(processingState); - if (result === 'paused') { - processingState.lastStatus = 'paused'; - } else if (result === 'success') { - processingState.lastStatus = 'success'; - processingState.currentIndex = 0; - } - } catch (error) { - processingState.lastStatus = 'failed'; - processingState.isAborted = true; - } finally { - processingState.isRunning = false; - updateButtonUI(); - } - } - - if (fileLabel && fileInput) { - fileLabel.addEventListener('click', (event) => { - event.preventDefault(); - fileInput.click(); - }); - fileInput.addEventListener('change', (event) => { - handleFileUpload(event.target.files[0], (content) => { - fileContent = content; - updateChunks(); - }); - }); - } - - if (chunkSizeInput) { - chunkSizeInput.addEventListener('input', updateChunks); - } - - - if (processBtn) { - processBtn.addEventListener('click', async () => { - if (processingState.isRunning) { - processingState.isAborted = true; - processBtn.innerHTML = ' 正在中止...'; - processBtn.disabled = true; - } else { - if (processingState.lastStatus === 'success') { - resetProcessing(); - } - if (processingState.lastStatus === 'idle' || processingState.lastStatus === 'success') { - processingState.currentIndex = 0; - } - startOrResumeProcessing(); - } - }); - } + return entries; } -function isTavernHelperAvailable() { - return typeof window.TavernHelper !== 'undefined' && - window.TavernHelper !== null && - typeof window.TavernHelper.getLorebooks === 'function'; -} -async function safeLorebooks() { - try { - if (isTavernHelperAvailable()) { - return await window.TavernHelper.getLorebooks(); - } - return [...world_names]; - } catch (error) { - console.error('[Amily2-兼容性] 获取世界书列表失败:', error); - return [...world_names]; +export async function executeNovelProcessing(processingState, updateStatusCallback) { + const { chunks: recognizedChapters, batchSize, forceNew, selectedWorldBook } = processingState; + + if (recognizedChapters.length === 0) { + updateStatusCallback('没有可处理的章节。', 'error'); + throw new Error('没有可处理的章节。'); } -} -async function loadWorldBooks() { - const select = document.getElementById('novel-world-book-select'); - if (!select) return; - - const { extension_settings } = window; - const savedBook = extension_settings[extensionName]?.selectedWorldBook; - moduleState.selectedWorldBook = savedBook || ''; + updateStatusCallback('开始处理小说...', 'info'); try { - const allBooks = await safeLorebooks(); - select.innerHTML = ''; - - if (allBooks && allBooks.length > 0) { - allBooks.forEach(bookName => { - const option = new Option(bookName, bookName); - select.add(option); - }); - - if (savedBook && allBooks.includes(savedBook)) { - select.value = savedBook; - } - } else { - select.innerHTML = ''; + const bookName = selectedWorldBook; + if (!bookName) { + throw new Error('请先在设置中选择一个目标世界书。'); } - } catch (error) { - console.error('[Amily2-术语表] 加载世界书失败:', error); - select.innerHTML = ''; - } -} -export function bindGlossaryEvents() { - const panel = document.getElementById('amily2_glossary_panel'); - if (!panel || panel.dataset.eventsBound) { - return; - } + const allEntries = (await safeLorebookEntries(bookName)) || []; + const managedEntries = allEntries.filter(e => e.comment?.startsWith('[Amily2小说处理]') || e.comment?.startsWith('[Amily2-Glossary]')); + const localManagedEntries = [...managedEntries]; - console.log('[Amily2-术语表] 开始绑定UI事件 (最终重构版)...'); + let existingEntriesContent = '当前世界书为空。'; + if (!forceNew) { + existingEntriesContent = buildContextFromEntries(localManagedEntries); + } - loadSettingsToUI(); - bindAutoSaveEvents(); - bindManualActionEvents(); - bindTabEvents(); - bindNovelProcessEvents(); - loadWorldBooks(); - - // 监听角色加载事件,以确保 world_names 可用 - eventSource.on(event_types.CHARACTER_PAGE_LOADED, () => { - console.log('[Amily2-术语表] 检测到角色加载,重新加载世界书列表以确保同步。'); - loadWorldBooks(); - }); - - const worldBookSelect = document.getElementById('novel-world-book-select'); - if (worldBookSelect) { - worldBookSelect.addEventListener('change', () => { - const selectedValue = worldBookSelect.value; - updateAndSaveSetting('selectedWorldBook', selectedValue); - moduleState.selectedWorldBook = selectedValue; - - const contextTab = document.querySelector('.glossary-tab[data-tab="context"]'); - if (contextTab && contextTab.classList.contains('active')) { - renderWorldBookEntries(); + for (let i = processingState.currentIndex; i < recognizedChapters.length; i += batchSize) { + if (processingState.isAborted) { + updateStatusCallback(`处理已中止。当前进度: ${i}/${recognizedChapters.length}`, 'info'); + return 'paused'; } - }); - } + processingState.currentIndex = i; - panel.dataset.eventsBound = 'true'; - console.log('[Amily2-术语表] UI事件绑定完成 (最终重构版)。'); + const batch = recognizedChapters.slice(i, i + batchSize); + const progress = `(${i + batch.length}/${recognizedChapters.length})`; + updateStatusCallback(`正在处理批次 ${Math.floor(i / batchSize) + 1}... ${progress}`, 'info'); + + const chapterContent = batch.map(c => `## ${c.title}\n${c.content}`).join('\n\n---\n\n'); + const order = getMixedOrder('novel_processor') || []; + const presetPrompts = await getPresetPrompts('novel_processor'); + const messages = [{ role: 'system', content: generateRandomSeed() }]; + + let promptCounter = 0; + for (const item of order) { + if (item.type === 'prompt') { + if (presetPrompts && presetPrompts[promptCounter]) { + messages.push(presetPrompts[promptCounter]); + promptCounter++; + } + } else if (item.type === 'conditional') { + if (item.id === 'existingLore') { + messages.push({ role: 'user', content: `# 已有世界书条目\n\n${existingEntriesContent}` }); + } else if (item.id === 'chapterContent') { + messages.push({ role: 'user', content: `# 最新章节内容\n\n${chapterContent}\n\n请根据以上信息,分析并输出需要新增或更新的世界书条目。` }); + } + } + } + + if (messages.length <= 1) throw new Error('未能根据预设构建有效的API请求。'); + + const response = await callSybdAI(messages); + if (!response) { + throw new Error(`API调用失败,批次 ${Math.floor(i / batchSize) + 1} 未收到响应。`); + } + if (response.trim() === '无需更新') { + updateStatusCallback(`批次 ${Math.floor(i / batchSize) + 1} 无需更新。`, 'info'); + continue; + } + + const structuredData = parseStructuredResponse(response); + if (structuredData.length === 0) { + throw new Error(`未能从API响应中提取有效信息,批次 ${Math.floor(i / batchSize) + 1}。`); + } + + const entriesToUpdate = []; + const entriesToCreate = []; + const fixedNovelEntries = ['世界观设定', '时间线', '角色关系网', '角色总览']; + + let maxPart = 0; + localManagedEntries.forEach(entry => { + const match = entry.comment.match(/章节内容概述-第(\d+)部分/); + if (match && parseInt(match[1], 10) > maxPart) maxPart = parseInt(match[1], 10); + }); + let nextPart = maxPart + 1; + + for (const entry of structuredData) { + const { title, content } = entry; + let comment; + let keys; + + if (title === '章节内容概述') { + comment = `[Amily2小说处理] ${title}-第${nextPart}部分`; + keys = [`小说处理`, title, `第${nextPart}部分`]; + const newEntryData = { keys, content, comment, enabled: true, order: 100, position: 'before_char' }; + entriesToCreate.push(newEntryData); + localManagedEntries.push({ uid: -1, ...newEntryData, keys: keys }); + nextPart++; + continue; + } + + if (fixedNovelEntries.includes(title)) { + comment = `[Amily2小说处理] ${title}`; + keys = [`小说处理`, title]; + } else { + comment = `[Amily2-Glossary] ${title}`; + keys = [`自定义条目`, title]; + } + + const existingEntry = localManagedEntries.find(e => e.comment === comment); + const loreData = { keys, content, comment, enabled: true, order: 100, position: 'before_char' }; + + if (existingEntry) { + entriesToUpdate.push({ uid: existingEntry.uid, ...loreData }); + Object.assign(existingEntry, { ...loreData, keys: keys }); + } else { + entriesToCreate.push(loreData); + localManagedEntries.push({ uid: -1, ...loreData, keys: keys }); + } + } + + if (entriesToUpdate.length > 0) { + await safeUpdateLorebookEntries(bookName, entriesToUpdate); + updateStatusCallback(`更新了 ${entriesToUpdate.length} 个世界书条目。`, 'info'); + } + if (entriesToCreate.length > 0) { + for (const entry of entriesToCreate) { + await compatibleWriteToLorebook(bookName, entry.comment, () => entry.content, { + keys: entry.keys, + isConstant: false, + insertion_position: 'before_char', + depth: 100, + }); + } + updateStatusCallback(`创建了 ${entriesToCreate.length} 个新世界书条目。`, 'success'); + } + + existingEntriesContent = buildContextFromEntries(localManagedEntries); + } + + updateStatusCallback('小说处理完成!', 'success'); + return 'success'; + } catch (error) { + console.error('处理小说时发生严重错误:', error); + updateStatusCallback(`处理失败: ${error.message}`, 'error'); + throw error; + } }