72 lines
4.4 KiB
JavaScript
72 lines
4.4 KiB
JavaScript
import {T} from './i18n.js';
|
|
const stageNames={
|
|
CheckpointLoaderSimple:"Loading main model",UNETLoader:"Loading main model",UNETLoaderGGUF:"Loading main model",
|
|
CLIPLoader:"Loading text encoder",DualCLIPLoader:"Loading text encoder",VAELoader:"Loading VAE",
|
|
CLIPTextEncode:"Encoding prompts",LoraLoader:"Loading LoRA",'Power Lora Loader (rgthree)':"Loading LoRA",
|
|
AdachiInlineMask:"Reading source image and mask",AdachiWebUIInpaint:"Preparing inpaint sampling",
|
|
KSampler:"KSampler",KSamplerAdvanced:"KSampler",SamplerCustom:"Sampler",
|
|
VAEDecode:"VAE decode",VAEEncode:"VAE encode",AdachiImageCompare:"Preparing comparison images",
|
|
};
|
|
|
|
// Percentages describe the current node's reported steps, not invented overall
|
|
// job progress. Nodes without numeric progress use an indeterminate bar.
|
|
export class WorkspaceProgress {
|
|
constructor(onChange=()=>{}) {this.onChange=onChange;this.state='idle';this.buffer=[];}
|
|
begin(nodes={},promptId=null) {
|
|
this.nodes=nodes;this.promptId=promptId;this.state='queued';this.label=T("Queued…");
|
|
this.nodeId=null;this.value=null;this.max=null;this.buffer=[];this.emit();
|
|
}
|
|
attach(promptId) {
|
|
this.promptId=promptId;const events=this.buffer;this.buffer=[];
|
|
for(const [name,data] of events)if(data?.prompt_id===promptId)this.handle(name,data);
|
|
}
|
|
emit(){this.onChange(this);}
|
|
stage(id) {
|
|
const node=this.nodes?.[String(id)],type=node?.class_type;
|
|
return stageNames[type]?T(stageNames[type]):node?._meta?.title||type||T("Executing workflow");
|
|
}
|
|
finish(success,message) {
|
|
this.state=success?'complete':'error';this.label=message||(success?T("Generation complete"):T("Generation stopped"));
|
|
this.value=success?1:null;this.max=success?1:null;this.emit();
|
|
}
|
|
connection(connected) {
|
|
if(!['queued','running'].includes(this.state))return;
|
|
this.label=connected?T("Reconnected; waiting for execution progress…"):T("Connection lost; recovering execution progress…");this.value=this.max=null;this.emit();
|
|
}
|
|
handle(name,data={}) {
|
|
// Older frontends reduce executing payloads to a scalar node ID and
|
|
// dispatch null at completion, including before the submit HTTP reply.
|
|
if(data==null)return false;
|
|
if(name==='executing' && ['string','number'].includes(typeof data))data={node:String(data)};
|
|
if(typeof data!=='object')return false;
|
|
if(!['queued','running'].includes(this.state))return false;
|
|
if(!this.promptId){this.buffer.push([name,data]);if(this.buffer.length>64)this.buffer.shift();return false;}
|
|
if(data.prompt_id && data.prompt_id!==this.promptId)return false;
|
|
if(name==='execution_success'){this.finish(true);return true;}
|
|
if(['execution_error','execution_interrupted'].includes(name)){this.finish(false,data.exception_message||T("Generation stopped"));return true;}
|
|
if(name==='execution_start'){this.state='running';this.label=T("Starting execution…");this.emit();return true;}
|
|
if(name==='execution_cached'){
|
|
if(this.state==='queued'){this.label=T("Reading cache · {count} nodes",{count:data.nodes?.length||0});this.emit();}return true;
|
|
}
|
|
if(name==='progress_state') {
|
|
const running=Object.entries(data.nodes||{}).filter(([,n])=>n.state==='running');
|
|
if(!running.length)return false;
|
|
const [id,node]=running.at(-1);
|
|
return this.handle('progress',{...node,prompt_id:this.promptId,node:id,
|
|
max:Number(node.max)>1?node.max:0});
|
|
}
|
|
if(name==='executing' && data.node==null && data.node_id==null)return false;
|
|
const id=data.node ?? data.node_id ?? this.nodeId;
|
|
if(id==null || !this.nodes?.[String(id)])return false;
|
|
const changed=String(id)!==this.nodeId;this.nodeId=String(id);this.state='running';
|
|
if(changed || name==='executing'){this.value=this.max=null;}
|
|
const max=Number(data.max),value=Number(data.value);
|
|
if(name==='progress' && Number.isFinite(max) && max>0 && Number.isFinite(value)){
|
|
this.max=max;this.value=Math.max(0,Math.min(max,value));
|
|
const type=this.nodes[this.nodeId]?.class_type;
|
|
this.label=`${type==='AdachiWebUIInpaint'?T("Inpaint sampling (KSampler)"):this.stage(id)} · ${this.value} / ${this.max}`;
|
|
} else this.label=this.stage(id);
|
|
this.emit();return true;
|
|
}
|
|
}
|