Update executor.js

This commit is contained in:
2025-10-19 01:39:58 +08:00
committed by GitHub
parent ea3e82cd6b
commit 68bb461f8e

View File

@@ -1,5 +1,5 @@
import { callSybdAI } from '../core/api/SybdApi.js'; 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 { getPresetPrompts, getMixedOrder } from '../PresetSettings/index.js';
import { generateRandomSeed } from '../core/api.js'; import { generateRandomSeed } from '../core/api.js';
@@ -7,7 +7,7 @@ const { TavernHelper } = window;
function parseStructuredResponse(responseText) { function parseStructuredResponse(responseText) {
const entries = []; 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; let match;
while ((match = entryRegex.exec(responseText)) !== null) { 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) { if (recognizedChapters.length === 0) {
updateStatusCallback('没有可处理的章节。', 'error'); updateStatusCallback('没有可处理的章节。', 'error');
return; throw new Error('没有可处理的章节。');
} }
updateStatusCallback('开始处理小说...', 'info'); updateStatusCallback('开始处理小说...', 'info');
try { try {
const bookName = await getTargetWorldBook(); const bookName = selectedWorldBook;
if (!bookName) throw new Error('无法确定目标世界书。'); if (!bookName) {
let existingEntriesContent = '当前世界书为空。'; throw new Error('请先在设置中选择一个目标世界书。');
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');
}
} }
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 batch = recognizedChapters.slice(i, i + batchSize);
const progress = `(${i + batch.length}/${recognizedChapters.length})`; const progress = `(${i + batch.length}/${recognizedChapters.length})`;
updateStatusCallback(`正在处理批次 ${Math.floor(i / batchSize) + 1}... ${progress}`, 'info'); updateStatusCallback(`正在处理批次 ${Math.floor(i / batchSize) + 1}... ${progress}`, 'info');
const chapterContent = batch.map(c => `## ${c.title}\n${c.content}`).join('\n\n---\n\n'); const chapterContent = batch.map(c => `## ${c.title}\n${c.content}`).join('\n\n---\n\n');
const order = getMixedOrder('novel_processor') || []; const order = getMixedOrder('novel_processor') || [];
const presetPrompts = await getPresetPrompts('novel_processor'); const presetPrompts = await getPresetPrompts('novel_processor');
const messages = [{ role: 'system', content: generateRandomSeed() }];
const messages = [
{ role: 'system', content: generateRandomSeed() }
];
let promptCounter = 0; let promptCounter = 0;
for (const item of order) { for (const item of order) {
@@ -66,20 +73,15 @@ export async function executeNovelProcessing(recognizedChapters, batchSize, forc
promptCounter++; promptCounter++;
} }
} else if (item.type === 'conditional') { } else if (item.type === 'conditional') {
switch (item.id) { if (item.id === 'existingLore') {
case 'existingLore': messages.push({ role: 'user', content: `# 已有世界书条目\n\n${existingEntriesContent}` });
messages.push({ role: 'user', content: `# 已有世界书条目\n\n${existingEntriesContent}` }); } else if (item.id === 'chapterContent') {
break; messages.push({ role: 'user', content: `# 最新章节内容\n\n${chapterContent}\n\n请根据以上信息,分析并输出需要新增或更新的世界书条目。` });
case 'chapterContent':
messages.push({ role: 'user', content: `# 最新章节内容\n\n${chapterContent}\n\n请根据以上信息,分析并输出需要新增或更新的世界书条目。` });
break;
} }
} }
} }
if (messages.length <= 1) { if (messages.length <= 1) throw new Error('未能根据预设构建有效的API请求。');
throw new Error('未能根据预设构建有效的API请求。');
}
const response = await callSybdAI(messages); const response = await callSybdAI(messages);
if (!response || response.trim() === '无需更新') { if (!response || response.trim() === '无需更新') {
@@ -93,13 +95,71 @@ export async function executeNovelProcessing(recognizedChapters, batchSize, forc
continue; 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'); updateStatusCallback('小说处理完成!', 'success');
return 'success';
} catch (error) { } catch (error) {
console.error('处理小说时发生严重错误:', error); console.error('处理小说时发生严重错误:', error);
updateStatusCallback(`处理失败: ${error.message}`, 'error'); updateStatusCallback(`处理失败: ${error.message}`, 'error');
throw error;
} }
} }