From 68bb461f8e9248cb63ec525e812a5fea15a12d06 Mon Sep 17 00:00:00 2001 From: Wx-2025 <351320169@qq.com> Date: Sun, 19 Oct 2025 01:39:58 +0800 Subject: [PATCH] Update executor.js --- glossary/executor.js | 126 +++++++++++++++++++++++++++++++------------ 1 file changed, 93 insertions(+), 33 deletions(-) diff --git a/glossary/executor.js b/glossary/executor.js index a2e0988..85ed394 100644 --- a/glossary/executor.js +++ b/glossary/executor.js @@ -1,5 +1,5 @@ import { callSybdAI } from '../core/api/SybdApi.js'; -import { getTargetWorldBook, syncNovelLorebookEntries } from '../CharacterWorldBook/src/cwb_lorebookManager.js'; +import { extensionName } from '../utils/settings.js'; import { getPresetPrompts, getMixedOrder } from '../PresetSettings/index.js'; import { generateRandomSeed } from '../core/api.js'; @@ -7,7 +7,7 @@ const { TavernHelper } = window; function parseStructuredResponse(responseText) { const entries = []; - const entryRegex = /【(.*?)】.*?\[START_TABLE\]([\s\S]*?)\[END_TABLE\]/g; + const entryRegex = /\[--START_TABLE--\]\s*\[name\]:(.*?)\n([\s\S]*?)\[--END_TABLE--\]/g; let match; while ((match = entryRegex.exec(responseText)) !== null) { @@ -22,41 +22,48 @@ function parseStructuredResponse(responseText) { } -export async function executeNovelProcessing(recognizedChapters, batchSize, forceNew, updateStatusCallback) { +export async function executeNovelProcessing(processingState, updateStatusCallback) { + const { chunks: recognizedChapters, batchSize, forceNew, selectedWorldBook } = processingState; + if (recognizedChapters.length === 0) { updateStatusCallback('没有可处理的章节。', 'error'); - return; + throw new Error('没有可处理的章节。'); } updateStatusCallback('开始处理小说...', 'info'); try { - const bookName = await getTargetWorldBook(); - if (!bookName) throw new Error('无法确定目标世界书。'); - let existingEntriesContent = '当前世界书为空。'; - if (!forceNew) { - const allEntries = (await TavernHelper.getLorebookEntries(bookName)) || []; - const managedEntries = allEntries.filter(e => e.comment?.startsWith(`[Amily2小说处理]`)); - if (managedEntries.length > 0) { - existingEntriesContent = managedEntries.map(entry => { - return `【${entry.keyword}】\n[START_TABLE]\n${entry.content}\n[END_TABLE]`; - }).join('\n\n'); - } + const bookName = selectedWorldBook; + if (!bookName) { + throw new Error('请先在设置中选择一个目标世界书。'); } - for (let i = 0; i < recognizedChapters.length; i += batchSize) { + const allEntries = (await TavernHelper.getLorebookEntries(bookName)) || []; + const managedEntries = allEntries.filter(e => e.comment?.startsWith('[Amily2小说处理]') || e.comment?.startsWith('[Amily2-Glossary]')); + + let existingEntriesContent = '当前世界书为空。'; + if (!forceNew && managedEntries.length > 0) { + existingEntriesContent = managedEntries.map(entry => { + const name = entry.keyword; + return `[--START_TABLE--]\n[name]:${name}\n${entry.content}\n[--END_TABLE--]`; + }).join('\n\n'); + } + + for (let i = processingState.currentIndex; i < recognizedChapters.length; i += batchSize) { + if (processingState.isAborted) { + updateStatusCallback(`处理已中止。当前进度: ${i}/${recognizedChapters.length}`, 'info'); + return 'paused'; + } + processingState.currentIndex = i; + 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() } - ]; + const messages = [{ role: 'system', content: generateRandomSeed() }]; let promptCounter = 0; for (const item of order) { @@ -66,20 +73,15 @@ export async function executeNovelProcessing(recognizedChapters, batchSize, forc promptCounter++; } } else if (item.type === 'conditional') { - switch (item.id) { - case 'existingLore': - messages.push({ role: 'user', content: `# 已有世界书条目\n\n${existingEntriesContent}` }); - break; - case 'chapterContent': - messages.push({ role: 'user', content: `# 最新章节内容\n\n${chapterContent}\n\n请根据以上信息,分析并输出需要新增或更新的世界书条目。` }); - break; + 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请求。'); - } + if (messages.length <= 1) throw new Error('未能根据预设构建有效的API请求。'); const response = await callSybdAI(messages); if (!response || response.trim() === '无需更新') { @@ -93,13 +95,71 @@ export async function executeNovelProcessing(recognizedChapters, batchSize, forc continue; } - await syncNovelLorebookEntries(bookName, structuredData); - existingEntriesContent = response; + // --- 自定义同步逻辑 --- + const currentAllEntries = (await TavernHelper.getLorebookEntries(bookName)) || []; + const currentManagedEntries = currentAllEntries.filter(e => e.comment?.startsWith('[Amily2小说处理]') || e.comment?.startsWith('[Amily2-Glossary]')); + + const entriesToUpdate = []; + const entriesToCreate = []; + const fixedNovelEntries = ['世界观设定', '时间线', '角色关系网', '角色总览']; + + let maxPart = 0; + currentManagedEntries.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}部分`]; + entriesToCreate.push({ keys, content, comment, enabled: true, order: 100, position: 'before_char' }); + nextPart++; + continue; + } + + const existingEntry = currentManagedEntries.find(e => e.keyword === title); + + if (fixedNovelEntries.includes(title)) { + comment = `[Amily2小说处理] ${title}`; + keys = [`小说处理`, title]; + } else { + comment = `[Amily2-Glossary] ${title}`; + keys = [`自定义条目`, title]; + } + + const loreData = { keys, content, comment, enabled: true, order: 100, position: 'before_char' }; + + if (existingEntry) { + entriesToUpdate.push({ uid: existingEntry.uid, ...loreData }); + } else { + entriesToCreate.push(loreData); + } + } + + if (entriesToUpdate.length > 0) { + await TavernHelper.setLorebookEntries(bookName, entriesToUpdate); + updateStatusCallback(`更新了 ${entriesToUpdate.length} 个世界书条目。`, 'info'); + } + if (entriesToCreate.length > 0) { + await TavernHelper.createLorebookEntries(bookName, entriesToCreate); + updateStatusCallback(`创建了 ${entriesToCreate.length} 个新世界书条目。`, 'success'); + } + // --- 同步逻辑结束 --- + + existingEntriesContent = response; // 更新上下文以便下一个批次使用 } updateStatusCallback('小说处理完成!', 'success'); + return 'success'; } catch (error) { console.error('处理小说时发生严重错误:', error); updateStatusCallback(`处理失败: ${error.message}`, 'error'); + throw error; } }