Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
99 changes: 54 additions & 45 deletions static/js/smart-canvas.js
Original file line number Diff line number Diff line change
Expand Up @@ -1165,6 +1165,15 @@ function persistActiveSmartSettings(){
subject.runSettings = settingsForStorage(settings);
rememberRecentSmartSettings(settings, subject);
}
function restoreSmartSettingsAfterRun(runNode, previousSettings){
const selected = selectedNode();
const activeSubject = isSmartRunnableNode(selected) ? selected : activeSettingsSubject();
if(activeSubject?.id === runNode?.id || !activeSubject){
settings = previousSettings;
return;
}
settings = smartSettingsForNode(activeSubject);
}
function rememberCanvasListProject(projectId){
const pid = projectId || 'default';
try { localStorage.setItem(CANVAS_LIST_PROJECT_KEY, pid); } catch(e){}
Expand Down Expand Up @@ -14547,37 +14556,37 @@ async function runGeneration(){
if(smartNodeInFlight(node)) return;
const refs = request.refs;
const previousSettings = cloneSmartSettings(settings);
const runSettings = smartSettingsForNode(node);
const runSettings = cloneSmartSettings(smartSettingsForNode(node));
settings = {...settings, ...cloneSmartSettings(runSettings || {})};
if(!prompt && smartRunNeedsPrompt(settings)){
settings = previousSettings;
if(!prompt && smartRunNeedsPrompt(runSettings)){
restoreSmartSettingsAfterRun(node, previousSettings);
toast(tr('smart.toastNeedPrompt'));
return;
}
const outpaintSize = node?.outpaintSize && Number(node.outpaintSize.width) > 0 && Number(node.outpaintSize.height) > 0
? {width:Math.round(Number(node.outpaintSize.width)), height:Math.round(Number(node.outpaintSize.height))}
: null;
if(outpaintSize && isApiLikeEngine(settings.engine) && settings.apiKind !== 'video'){
settings = {
...settings,
if(outpaintSize && isApiLikeEngine(runSettings.engine) && runSettings.apiKind !== 'video'){
Object.assign(runSettings, {
resolution:'custom',
ratio:'',
customWidth:outpaintSize.width,
customHeight:outpaintSize.height,
customSize:`${outpaintSize.width}x${outpaintSize.height}`
};
});
settings = {...settings, ...cloneSmartSettings(runSettings)};
}
const meta = snapshotRunMeta(prompt, node.id, request.displayPrompt, refs);
const logKind = isApiLikeEngine(settings.engine) && settings.apiKind === 'video' ? 'video' : 'image';
const logKind = isApiLikeEngine(runSettings.engine) && runSettings.apiKind === 'video' ? 'video' : 'image';
const runLog = smartRunSnapshot(node, prompt, refs, logKind);
rememberRecentSmartSettings(settings, node);
rememberRecentSmartSettings(runSettings, node);
const runLogStart = nowMs();
const expectedCount = settings.engine === 'runninghub'
const expectedCount = runSettings.engine === 'runninghub'
? 1
: settings.engine === 'comfy'
? (settings.comfyMode === 'text' || settings.comfyMode === 'enhance' || settings.comfyMode === 'edit' || settings.comfyMode === 'custom' ? 1 : 1)
: Math.max(1, Math.min(8, Number(settings.count || 1)));
const apiConcurrentRun = isApiLikeEngine(settings.engine) || settings.engine === 'runninghub' || settings.engine === 'modelscope' || settings.engine === 'comfy';
: runSettings.engine === 'comfy'
? (runSettings.comfyMode === 'text' || runSettings.comfyMode === 'enhance' || runSettings.comfyMode === 'edit' || runSettings.comfyMode === 'custom' ? 1 : 1)
: Math.max(1, Math.min(8, Number(runSettings.count || 1)));
const apiConcurrentRun = isApiLikeEngine(runSettings.engine) || runSettings.engine === 'runninghub' || runSettings.engine === 'modelscope' || runSettings.engine === 'comfy';
const nodeHasImages = isSmartGroupNode(node) ? imagesForNode(node).some(img => img?.url) : (node.images || []).some(img => img?.url);
const workflowModeRun = smartImageUsesWorkflowInput(node, smartLoopContext);
const sourceVisualState = isSmartImageNode(node) && nodeHasImages && !workflowModeRun ? {
Expand Down Expand Up @@ -14619,33 +14628,33 @@ async function runGeneration(){
}
render();
try {
if(settings.engine === 'comfy'){
await runComfyGeneration(pendingNode, prompt, refs, pendingNode, pendingMeta);
if(runSettings.engine === 'comfy'){
await runComfyGeneration(pendingNode, prompt, refs, pendingNode, pendingMeta, runSettings);
if(sourceVisualState) restoreSourceVisualState(node, sourceVisualState);
addSmartGenerationLog({run:runLog, outputs:pendingNode.images || [], runMs:nowMs() - runLogStart});
settings = previousSettings;
restoreSmartSettingsAfterRun(node, previousSettings);
return;
}
if(isApiLikeEngine(settings.engine) && settings.apiKind === 'video'){
const outVideos = await runApiVideoGeneration(prompt, refs);
if(isApiLikeEngine(runSettings.engine) && runSettings.apiKind === 'video'){
const outVideos = await runApiVideoGeneration(prompt, refs, runSettings);
if(!outVideos.length) throw new Error(tr('smart.errNoOutVideos'));
finalizePendingNode(pendingNode, outVideos, pendingMeta, 'video');
if(sourceVisualState) restoreSourceVisualState(node, sourceVisualState);
addSmartGenerationLog({run:runLog, outputs:outVideos, runMs:nowMs() - runLogStart});
clearPromptInput({preserveDraft:true});
settings = previousSettings;
restoreSmartSettingsAfterRun(node, previousSettings);
scheduleSave();
return;
}
const rhModelMode = settings.engine === 'runninghub' && Boolean(runningHubSelectedModel(settings));
const rhModelMode = runSettings.engine === 'runninghub' && Boolean(runningHubSelectedModel(runSettings));
const outImages = rhModelMode
? await runApiGeneration(prompt, refs, runningHubModelApiSettings(settings))
: settings.engine === 'runninghub'
? await runRunningHubGeneration(prompt, refs)
: settings.engine === 'modelscope'
? await runModelscopeGeneration(prompt, refs)
: await runApiGeneration(prompt, refs);
if(isApiLikeEngine(settings.engine) || rhModelMode){
? await runApiGeneration(prompt, refs, runningHubModelApiSettings(runSettings))
: runSettings.engine === 'runninghub'
? await runRunningHubGeneration(prompt, refs, runSettings)
: runSettings.engine === 'modelscope'
? await runModelscopeGeneration(prompt, refs, runSettings)
: await runApiGeneration(prompt, refs, runSettings);
if(isApiLikeEngine(runSettings.engine) || rhModelMode){
const taskIds = Array.isArray(outImages?.taskIds) ? outImages.taskIds : [];
if(!taskIds.length) throw new Error(tr('smart.errRunFailed'));
pendingNode.pendingTasks = taskIds.map(taskId => ({taskId, kind:'image', providerId:outImages.providerId, model:outImages.model}));
Expand All @@ -14660,7 +14669,7 @@ async function runGeneration(){
if(pendingNode.jimengPending || smartRecoverableImageTask(pendingNode)){
if(sourceVisualState) restoreSourceVisualState(node, sourceVisualState);
clearPromptInput({preserveDraft:true});
settings = previousSettings;
restoreSmartSettingsAfterRun(node, previousSettings);
scheduleSave();
return;
}
Expand All @@ -14669,7 +14678,7 @@ async function runGeneration(){
if(sourceVisualState) restoreSourceVisualState(node, sourceVisualState);
addSmartGenerationLog({run:runLog, outputs:pendingNode.images || [], runMs:nowMs() - runLogStart});
clearPromptInput({preserveDraft:true});
settings = previousSettings;
restoreSmartSettingsAfterRun(node, previousSettings);
scheduleSave();
return;
}
Expand All @@ -14679,10 +14688,10 @@ async function runGeneration(){
if(sourceVisualState) restoreSourceVisualState(node, sourceVisualState);
addSmartGenerationLog({run:runLog, outputs:outImages, runMs:nowMs() - runLogStart});
clearPromptInput({preserveDraft:true});
settings = previousSettings;
restoreSmartSettingsAfterRun(node, previousSettings);
scheduleSave();
} catch(e) {
settings = previousSettings;
restoreSmartSettingsAfterRun(node, previousSettings);
if(handleJimengPendingSignal(pendingNode, e)){
if(sourceVisualState) restoreSourceVisualState(node, sourceVisualState);
delete pendingNode._runMetaTargetId;
Expand Down Expand Up @@ -14917,14 +14926,14 @@ async function urlToBase64(url){
});
}
function sleep(ms){ return new Promise(resolve => setTimeout(resolve, ms)); }
async function runComfyGeneration(node, prompt, refs, pendingNode, meta){
async function runComfyGeneration(node, prompt, refs, pendingNode, meta, runSettings=settings){
const allRefs = refs || [];
refs = imageRefsOnly(allRefs);
const mode = settings.comfyMode || 'text';
if(mode === 'text') return runComfyText(node, prompt, pendingNode, meta);
if(mode === 'enhance') return runComfyEnhance(node, refs, pendingNode, meta);
if(mode === 'edit') return runComfyEdit(node, prompt, refs, pendingNode, meta);
const workflowName = settings.comfyWorkflow || comfyWorkflows[0]?.name || '';
const mode = runSettings.comfyMode || 'text';
if(mode === 'text') return runComfyText(node, prompt, pendingNode, meta, runSettings);
if(mode === 'enhance') return runComfyEnhance(node, refs, pendingNode, meta, runSettings);
if(mode === 'edit') return runComfyEdit(node, prompt, refs, pendingNode, meta, runSettings);
const workflowName = runSettings.comfyWorkflow || comfyWorkflows[0]?.name || '';
if(!workflowName) throw new Error(tr('smart.errNeedWorkflow'));
const wf = await fetch(`/api/workflows/${encodeURIComponent(workflowName)}`).then(async r => {
if(!r.ok) throw new Error(await r.text());
Expand All @@ -14944,10 +14953,10 @@ async function runComfyGeneration(node, prompt, refs, pendingNode, meta){
await assignMediaFields(fields.filter(f => comfyFieldKind(f) === 'video'), videoRefsOnly(allRefs));
await assignMediaFields(fields.filter(f => comfyFieldKind(f) === 'audio'), audioRefsOnly(allRefs));
fields.filter(f => comfyFieldKind(f) === 'setting').forEach(field => {
if(comfyRandomEnabledField(field) && smartComfyRandomActive(field.id)){
if(comfyRandomEnabledField(field) && smartComfyRandomActiveFor(runSettings, field.id)){
values[field.id] = smartComfyRandomValue(field);
} else {
values[field.id] = settings.comfyParams?.[field.id] ?? field.default;
values[field.id] = runSettings.comfyParams?.[field.id] ?? field.default;
}
});
const result = await runQueuedSmartComfyGenerate({prompt, workflow_json:workflowName, params:comfyParamsFromWorkflowValues(wf.config || {fields:[]}, values), type:'workflow-custom', client_id:smartClientId});
Expand All @@ -14968,8 +14977,8 @@ async function runComfyGeneration(node, prompt, refs, pendingNode, meta){
clearPromptInput({preserveDraft:true});
scheduleSave();
}
async function runComfyText(node, prompt, pendingNode, meta){
const data = await runQueuedSmartComfyGenerate({prompt, width:Number(settings.width || 1024), height:Number(settings.height || 1024), workflow_json:'Z-Image.json', type:'zimage', client_id:smartClientId});
async function runComfyText(node, prompt, pendingNode, meta, runSettings=settings){
const data = await runQueuedSmartComfyGenerate({prompt, width:Number(runSettings.width || 1024), height:Number(runSettings.height || 1024), workflow_json:'Z-Image.json', type:'zimage', client_id:smartClientId});
const out = data.outputs || data.images || [];
if(!out.length) throw new Error(tr('smart.errComfyNoImages'));
if(pendingNode){
Expand All @@ -14982,10 +14991,10 @@ async function runComfyText(node, prompt, pendingNode, meta){
clearPromptInput({preserveDraft:true});
scheduleSave();
}
async function runComfyEnhance(node, refs, pendingNode, meta){
async function runComfyEnhance(node, refs, pendingNode, meta, runSettings=settings){
if(!refs.length) throw new Error(tr('smart.errEnhanceNeedRefs'));
const inputName = await comfyNameForRef(refs[0]);
const data = await runQueuedSmartComfyGenerate({workflow_json:'Z-Image-Enhance.json', type:'enhance', params:{"15":{image:inputName},"204":{value:Number(settings.enhanceStrength ?? 0.5)}}, client_id:smartClientId});
const data = await runQueuedSmartComfyGenerate({workflow_json:'Z-Image-Enhance.json', type:'enhance', params:{"15":{image:inputName},"204":{value:Number(runSettings.enhanceStrength ?? 0.5)}}, client_id:smartClientId});
const out = data.outputs || data.images || [];
if(!out.length) throw new Error(tr('smart.errComfyNoImages'));
if(pendingNode){
Expand All @@ -14997,7 +15006,7 @@ async function runComfyEnhance(node, refs, pendingNode, meta){
}
scheduleSave();
}
async function runComfyEdit(node, prompt, refs, pendingNode, meta){
async function runComfyEdit(node, prompt, refs, pendingNode, meta, runSettings=settings){
if(!refs.length) throw new Error(tr('smart.errEditNeedRefs'));
const names = [];
for(const ref of refs.slice(0, 3)) names.push(await comfyNameForRef(ref));
Expand Down