Add generation lock and floating-first auto
This commit is contained in:
@@ -10,6 +10,7 @@ import {
|
|||||||
saveSettings,
|
saveSettings,
|
||||||
findLastAIMessageId,
|
findLastAIMessageId,
|
||||||
classifyError,
|
classifyError,
|
||||||
|
isGenerating,
|
||||||
} from './novel-draw.js';
|
} from './novel-draw.js';
|
||||||
import { registerToToolbar, removeFromToolbar } from '../../widgets/message-toolbar.js';
|
import { registerToToolbar, removeFromToolbar } from '../../widgets/message-toolbar.js';
|
||||||
|
|
||||||
@@ -754,6 +755,11 @@ async function handleFloorDrawClick(messageId) {
|
|||||||
const panelData = panelMap.get(messageId);
|
const panelData = panelMap.get(messageId);
|
||||||
if (!panelData || panelData.state !== FloatState.IDLE) return;
|
if (!panelData || panelData.state !== FloatState.IDLE) return;
|
||||||
|
|
||||||
|
if (isGenerating()) {
|
||||||
|
toastr?.info?.('已有任务进行中,请等待完成');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await generateAndInsertImages({
|
await generateAndInsertImages({
|
||||||
messageId,
|
messageId,
|
||||||
@@ -777,8 +783,9 @@ async function handleFloorDrawClick(messageId) {
|
|||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('[NovelDraw]', e);
|
console.error('[NovelDraw]', e);
|
||||||
if (e.message === '已取消') {
|
if (e.message === '已取消' || e.message?.includes('已有任务进行中')) {
|
||||||
setFloorState(messageId, FloatState.IDLE);
|
setFloorState(messageId, FloatState.IDLE);
|
||||||
|
if (e.message?.includes('已有任务进行中')) toastr?.info?.(e.message);
|
||||||
} else {
|
} else {
|
||||||
setFloorState(messageId, FloatState.ERROR, { error: classifyError(e) });
|
setFloorState(messageId, FloatState.ERROR, { error: classifyError(e) });
|
||||||
}
|
}
|
||||||
@@ -1230,6 +1237,11 @@ async function handleFloatingDrawClick() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isGenerating()) {
|
||||||
|
toastr?.info?.('已有任务进行中,请等待完成');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await generateAndInsertImages({
|
await generateAndInsertImages({
|
||||||
messageId,
|
messageId,
|
||||||
@@ -1253,8 +1265,9 @@ async function handleFloatingDrawClick() {
|
|||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('[NovelDraw]', e);
|
console.error('[NovelDraw]', e);
|
||||||
if (e.message === '已取消') {
|
if (e.message === '已取消' || e.message?.includes('已有任务进行中')) {
|
||||||
setFloatingState(FloatState.IDLE);
|
setFloatingState(FloatState.IDLE);
|
||||||
|
if (e.message?.includes('已有任务进行中')) toastr?.info?.(e.message);
|
||||||
} else {
|
} else {
|
||||||
setFloatingState(FloatState.ERROR, { error: classifyError(e) });
|
setFloatingState(FloatState.ERROR, { error: classifyError(e) });
|
||||||
}
|
}
|
||||||
@@ -1547,4 +1560,5 @@ export {
|
|||||||
SIZE_OPTIONS,
|
SIZE_OPTIONS,
|
||||||
createFloatingButton,
|
createFloatingButton,
|
||||||
destroyFloatingButton,
|
destroyFloatingButton,
|
||||||
|
setFloatingState,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -274,7 +274,7 @@ function abortGeneration() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function isGenerating() {
|
function isGenerating() {
|
||||||
return generationAbortController !== null;
|
return autoBusy || generationAbortController !== null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ═══════════════════════════════════════════════════════════════════════════
|
// ═══════════════════════════════════════════════════════════════════════════
|
||||||
@@ -1723,12 +1723,16 @@ async function handleMessageModified(data) {
|
|||||||
// 多图生成
|
// 多图生成
|
||||||
// ═══════════════════════════════════════════════════════════════════════════
|
// ═══════════════════════════════════════════════════════════════════════════
|
||||||
|
|
||||||
async function generateAndInsertImages({ messageId, onStateChange }) {
|
async function generateAndInsertImages({ messageId, onStateChange, skipLock = false }) {
|
||||||
await loadSettings();
|
await loadSettings();
|
||||||
const ctx = getContext();
|
const ctx = getContext();
|
||||||
const message = ctx.chat?.[messageId];
|
const message = ctx.chat?.[messageId];
|
||||||
if (!message) throw new NovelDrawError('消息不存在', ErrorType.PARSE);
|
if (!message) throw new NovelDrawError('消息不存在', ErrorType.PARSE);
|
||||||
|
|
||||||
|
if (!skipLock && isGenerating()) {
|
||||||
|
throw new NovelDrawError('已有任务进行中', ErrorType.UNKNOWN);
|
||||||
|
}
|
||||||
|
|
||||||
generationAbortController = new AbortController();
|
generationAbortController = new AbortController();
|
||||||
const signal = generationAbortController.signal;
|
const signal = generationAbortController.signal;
|
||||||
|
|
||||||
@@ -1936,7 +1940,12 @@ async function generateAndInsertImages({ messageId, onStateChange }) {
|
|||||||
|
|
||||||
async function autoGenerateForLastAI() {
|
async function autoGenerateForLastAI() {
|
||||||
const s = getSettings();
|
const s = getSettings();
|
||||||
if (!isModuleEnabled() || s.mode !== 'auto' || autoBusy) return;
|
if (!isModuleEnabled() || s.mode !== 'auto') return;
|
||||||
|
|
||||||
|
if (isGenerating()) {
|
||||||
|
console.log('[NovelDraw] 自动模式:已有任务进行中,跳过');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const ctx = getContext();
|
const ctx = getContext();
|
||||||
const chat = ctx.chat || [];
|
const chat = ctx.chat || [];
|
||||||
@@ -1955,32 +1964,46 @@ async function autoGenerateForLastAI() {
|
|||||||
autoBusy = true;
|
autoBusy = true;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const { setStateForMessage, FloatState, ensureNovelDrawPanel } = await import('./floating-panel.js');
|
const { setStateForMessage, setFloatingState, FloatState, ensureNovelDrawPanel } = await import('./floating-panel.js');
|
||||||
|
const floatingOn = s.showFloatingButton === true;
|
||||||
|
const floorOn = s.showFloorButton !== false;
|
||||||
|
const useFloatingOnly = floatingOn && floorOn;
|
||||||
|
|
||||||
// 确保面板存在
|
const updateState = (state, data = {}) => {
|
||||||
|
if (useFloatingOnly || (floatingOn && !floorOn)) {
|
||||||
|
setFloatingState?.(state, data);
|
||||||
|
} else if (floorOn) {
|
||||||
|
setStateForMessage(lastIdx, state, data);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (floorOn && !useFloatingOnly) {
|
||||||
const messageEl = document.querySelector(`.mes[mesid="${lastIdx}"]`);
|
const messageEl = document.querySelector(`.mes[mesid="${lastIdx}"]`);
|
||||||
if (messageEl) {
|
if (messageEl) {
|
||||||
ensureNovelDrawPanel(messageEl, lastIdx, { force: true });
|
ensureNovelDrawPanel(messageEl, lastIdx, { force: true });
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
await generateAndInsertImages({
|
await generateAndInsertImages({
|
||||||
messageId: lastIdx,
|
messageId: lastIdx,
|
||||||
|
skipLock: true,
|
||||||
onStateChange: (state, data) => {
|
onStateChange: (state, data) => {
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case 'llm':
|
case 'llm':
|
||||||
setStateForMessage(lastIdx, FloatState.LLM);
|
updateState(FloatState.LLM);
|
||||||
break;
|
break;
|
||||||
case 'gen':
|
case 'gen':
|
||||||
case 'progress':
|
case 'progress':
|
||||||
setStateForMessage(lastIdx, FloatState.GEN, data);
|
updateState(FloatState.GEN, data);
|
||||||
break;
|
break;
|
||||||
case 'cooldown':
|
case 'cooldown':
|
||||||
setStateForMessage(lastIdx, FloatState.COOLDOWN, data);
|
updateState(FloatState.COOLDOWN, data);
|
||||||
break;
|
break;
|
||||||
case 'success':
|
case 'success':
|
||||||
setStateForMessage(
|
updateState(
|
||||||
lastIdx,
|
(data.aborted && data.success === 0) ? FloatState.IDLE
|
||||||
data.success === data.total ? FloatState.SUCCESS : FloatState.PARTIAL,
|
: (data.success < data.total) ? FloatState.PARTIAL
|
||||||
|
: FloatState.SUCCESS,
|
||||||
data
|
data
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
@@ -1993,8 +2016,16 @@ async function autoGenerateForLastAI() {
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('[NovelDraw] 自动配图失败:', e);
|
console.error('[NovelDraw] 自动配图失败:', e);
|
||||||
try {
|
try {
|
||||||
const { setStateForMessage, FloatState } = await import('./floating-panel.js');
|
const { setStateForMessage, setFloatingState, FloatState } = await import('./floating-panel.js');
|
||||||
|
const floatingOn = s.showFloatingButton === true;
|
||||||
|
const floorOn = s.showFloorButton !== false;
|
||||||
|
const useFloatingOnly = floatingOn && floorOn;
|
||||||
|
|
||||||
|
if (useFloatingOnly || (floatingOn && !floorOn)) {
|
||||||
|
setFloatingState?.(FloatState.ERROR, { error: classifyError(e) });
|
||||||
|
} else if (floorOn) {
|
||||||
setStateForMessage(lastIdx, FloatState.ERROR, { error: classifyError(e) });
|
setStateForMessage(lastIdx, FloatState.ERROR, { error: classifyError(e) });
|
||||||
|
}
|
||||||
} catch {}
|
} catch {}
|
||||||
} finally {
|
} finally {
|
||||||
autoBusy = false;
|
autoBusy = false;
|
||||||
|
|||||||
Reference in New Issue
Block a user