diff --git a/index.js b/index.js
index 2fb4dc4..d6f4a3d 100644
--- a/index.js
+++ b/index.js
@@ -2,6 +2,7 @@ import { createDrawer } from "./ui/drawer.js";
import "./PresetSettings/index.js"; // 【预设设置】独立模块
import "./PreOptimizationViewer/index.js"; // 【优化前文查看器】独立模块
import "./WorldEditor/WorldEditor.js"; // 【世界编辑器】独立模块
+import { showPlotOptimizationProgress, updatePlotOptimizationProgress, hidePlotOptimizationProgress } from './ui/optimization-progress.js';
import { registerSlashCommands } from "./core/commands.js";
import { onMessageReceived, handleTableUpdate } from "./core/events.js";
import { processPlotOptimization } from "./core/summarizer.js";
@@ -616,9 +617,18 @@ jQuery(async () => {
console.log("[Amily2号-开国大典] 步骤3.8:注册表格占位符宏...");
try {
-
+ // 【V144.0】注册上下文优化器宏 (已移至开国大典步骤0优先执行,此处仅保留重置逻辑)
+ // registerContextOptimizerMacros();
+
+ // 注册生成开始事件以重置缓冲区
eventSource.on(event_types.GENERATION_STARTED, () => {
resetContextBuffer();
+
+ // 故障恢复:如果生成开始了,说明之前的优化肯定结束了(或者被绕过了),强制重置标志位
+ if (isProcessingPlotOptimization) {
+ console.warn("[Amily2-剧情优化] 检测到生成开始,但优化标志位仍为 true。这可能是并发生成或状态未及时重置。");
+ // 我们不在这里强制重置,因为优化可能正在进行中,我们希望它完成并修改输入框。
+ }
});
const context = getContext();
@@ -645,17 +655,23 @@ jQuery(async () => {
async function onPlotGenerationAfterCommands(type, params, dryRun) {
clearUpdatedTables();
-
- console.log("[Amily2-剧情优化] Generation after commands triggered", { type, params, dryRun, isProcessing: isProcessingPlotOptimization });
-
- if (type === 'regenerate' || isProcessingPlotOptimization || dryRun) {
- console.log("[Amily2-剧情优化] Skipping due to conditions:", { type, isProcessing: isProcessingPlotOptimization, dryRun });
- return;
+ // 如果正在处理中,拦截所有其他触发(防止意外的双重触发)
+ if (isProcessingPlotOptimization) {
+ console.log("[Amily2-剧情优化] 优化正在进行中,拦截重复触发。");
+ return;
}
-
+
+ console.log("[Amily2-剧情优化] Generation after commands triggered", { type, params, dryRun });
+
+ // Skip for regenerations or dry runs
+ if (type === 'regenerate' || dryRun) {
+ console.log("[Amily2-剧情优化] Skipping due to regenerate or dryRun.");
+ return false;
+ }
+
const globalSettings = extension_settings[extensionName];
if (globalSettings?.plotOpt_enabled === false) {
- return;
+ return false;
}
const isJqyhEnabled = globalSettings?.jqyhEnabled === true;
@@ -663,117 +679,106 @@ jQuery(async () => {
if (!isJqyhEnabled && !isMainApiConfigured) {
console.log("[Amily2-剧情优化] 优化已启用,但Jqyh API已禁用且主页API未配置。");
- return;
+ return false;
}
-
+
+ // Determine the message to be processed
+ let userMessage = $('#send_textarea').val();
+ let isFromTextarea = true;
+ const context = getContext();
+ if (!userMessage) {
+ if (context.chat && context.chat.length > 0) {
+ const lastMsg = context.chat[context.chat.length - 1];
+ if (lastMsg.is_user) {
+ userMessage = lastMsg.mes;
+ isFromTextarea = false;
+ console.log("[Amily2-剧情优化] Detected empty textarea, processing last user message.");
+ }
+ }
+ }
+
+ if (!userMessage) {
+ return false; // Nothing to process
+ }
+
+ // Set the flag to prevent loops and show progress
isProcessingPlotOptimization = true;
- let plotOptimizationToast = null;
const cancellationState = { isCancelled: false };
+ showPlotOptimizationProgress(cancellationState);
+
+ const onProgress = (message, isDone = false, isSkipped = false) => {
+ updatePlotOptimizationProgress(message, isDone, isSkipped);
+ };
try {
- let userMessage = $('#send_textarea').val();
- let isFromTextarea = true;
- let targetMessageId = null;
- const context = getContext();
-
- if (!userMessage) {
- // 尝试从聊天记录中获取最后一条用户消息(针对 /send 指令场景)
- if (context.chat && context.chat.length > 0) {
- const lastMsg = context.chat[context.chat.length - 1];
- if (lastMsg.is_user) {
- userMessage = lastMsg.mes;
- isFromTextarea = false;
- targetMessageId = context.chat.length - 1;
- console.log("[Amily2-剧情优化] 检测到输入框为空,但最后一条消息为用户发送,将对其进行优化。");
- }
- }
- }
-
- if (!userMessage) {
- isProcessingPlotOptimization = false;
- return false;
- }
-
- const toastMessage = `
-
- 正在进行剧情优化...
-
-
- `;
-
- let cancellationReject;
const cancellationPromise = new Promise((_, reject) => {
- cancellationReject = reject;
- });
-
- plotOptimizationToast = toastr.info(toastMessage, '剧情优化', {
- timeOut: 0,
- extendedTimeOut: 0,
- tapToDismiss: false,
- onclick: null,
- escapeHtml: false,
- onShown: function() {
- $('#amily2-cancel-optimization-btn').one('click', function(event) {
- event.stopPropagation();
-
- if (plotOptimizationToast) {
- plotOptimizationToast.remove();
- plotOptimizationToast = null;
- }
-
- cancellationState.isCancelled = true;
- cancellationReject(new Error("Optimization cancelled by user"));
- });
- }
+ const checkCancel = setInterval(() => {
+ if (cancellationState.isCancelled) {
+ clearInterval(checkCancel);
+ reject(new Error("Optimization cancelled by user"));
+ }
+ }, 100);
});
const contextTurnCount = globalSettings.plotOpt_contextLimit || 10;
- let slicedContext = [];
-
- // 如果是从聊天记录中获取的消息,上下文需要排除最后一条
const contextSource = isFromTextarea ? context.chat : context.chat.slice(0, -1);
-
- if (contextTurnCount > 0) {
- slicedContext = contextSource.slice(-contextTurnCount);
- } else {
- slicedContext = contextSource;
- }
-
- const optimizationPromise = processPlotOptimization({ mes: userMessage }, slicedContext, cancellationState);
+ const slicedContext = contextTurnCount > 0 ? contextSource.slice(-contextTurnCount) : contextSource;
+ const optimizationPromise = processPlotOptimization({ mes: userMessage }, slicedContext, cancellationState, onProgress);
const result = await Promise.race([optimizationPromise, cancellationPromise]);
+ if (cancellationState.isCancelled) {
+ throw new Error("Optimization cancelled by user");
+ }
+
if (result && result.contentToAppend) {
+ const finalMessage = userMessage + '\n' + result.contentToAppend;
+
+ if (params && typeof params === 'object') {
+ try {
+ if (params.prompt) params.prompt = finalMessage;
+ if (Array.isArray(params.messages)) {
+ const lastMsg = params.messages[params.messages.length - 1];
+ if (lastMsg && lastMsg.role === 'user') {
+ lastMsg.content = finalMessage;
+ }
+ }
+ } catch (e) {
+ console.warn("[Amily2-剧情优化] 尝试修改 params 失败:", e);
+ }
+ }
+
if (isFromTextarea) {
- const currentUserInput = $('#send_textarea').val();
- const finalMessage = currentUserInput + '\n' + result.contentToAppend;
$('#send_textarea').val(finalMessage).trigger('input');
} else {
- const finalMessage = userMessage + '\n' + result.contentToAppend;
- await amilyHelper.setChatMessage(finalMessage, targetMessageId, { refresh: 'display_and_render_current' });
+ const targetMessageId = context.chat.length - 1;
+ await amilyHelper.setChatMessage(finalMessage, targetMessageId, { refresh: 'none' });
}
- toastr.success('剧情优化已完成并注入。', '操作成功');
+
+ toastr.success('剧情优化已完成并注入,继续生成...', '操作成功');
+
+ isProcessingPlotOptimization = false;
+ hidePlotOptimizationProgress();
+
+ return false;
} else {
console.log("[Amily2-剧情优化] Plot optimization returned no result. Sending original message.");
+ isProcessingPlotOptimization = false;
+ hidePlotOptimizationProgress();
+ return false;
}
-
- return false;
} catch (error) {
- if (error.message === "Optimization cancelled by user") {
+ if (cancellationState.isCancelled || error.message === "Optimization cancelled by user") {
console.log("[Amily2-剧情优化] 优化流程已被用户中止。发送原始消息。");
- toastr.warning('剧情优化任务已中止...', '操作取消', { timeOut: 2000 });
+ toastr.warning('记忆管理任务已中止。', '操作取消', { timeOut: 2000 });
} else {
console.error(`[Amily2-剧情优化] 处理发送前事件时出错:`, error);
- toastr.error('剧情优化处理失败。', '错误');
+ toastr.error('记忆管理处理失败,将发送原始消息。', '错误');
}
- return false;
- } finally {
isProcessingPlotOptimization = false;
- if (plotOptimizationToast) {
- toastr.clear(plotOptimizationToast);
- plotOptimizationToast = null;
- }
+ hidePlotOptimizationProgress();
+ return false;
}
}
if (!window.amily2EventsRegistered) {
@@ -891,21 +896,16 @@ jQuery(async () => {
console.log("【Amily2号】帝国秩序已完美建立。Amily2号的府邸已恭候陛下的莅临。");
- // 【新增功能】每次加载插件时,如果已授权,则弹出提示
if (checkAuthorization()) {
const userType = localStorage.getItem("plugin_user_type") || "未知";
const userNote = localStorage.getItem("plugin_user_note");
- // 1. 先显示本地缓存的状态,保证启动速度和体验
const displayNote = userNote || userType;
toastr.success(`欢迎回来!授权状态有效 (用户: ${displayNote})`, "Amily2 插件已就绪");
- // 2. 后台静默刷新,检查过期状态或信息更新
- // 即使本地有备注,也需要去服务器验证一下是否过期
refreshUserInfo().then(data => {
if (data && data.note && data.note !== userNote) {
console.log("[Amily2] 用户信息已更新:", data.note);
- // 如果备注变了,可以选择再次提示或者静默更新
}
}).catch(e => {
console.warn("[Amily2] 后台刷新用户信息失败:", e);