feat: add Start At Job # option for custom job resume/skipping
New 'Run Settings' section in Builder UI with a job number input. When set > 0, the generation loop skips all jobs before that number. Useful for resuming at a specific point without relying on auto-detection. Flows through session settings to the orchestrator. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
e1bba3e8f5
commit
9b8f01ea48
@@ -716,6 +716,10 @@ class UltimateConfigBuilder:
|
||||
cooldown_data = state.get("cooldown", {})
|
||||
if cooldown_data and cooldown_data.get("enabled", False):
|
||||
session_settings["cooldown"] = cooldown_data
|
||||
# Start At Job # (skip to a specific job number)
|
||||
start_at_job = state.get("start_at_job", 0)
|
||||
if start_at_job and int(start_at_job) > 0:
|
||||
session_settings["start_at_job"] = int(start_at_job)
|
||||
if session_settings:
|
||||
output_obj["_session_settings"] = session_settings
|
||||
|
||||
|
||||
@@ -775,6 +775,9 @@ def run_generation_loop(
|
||||
total_generated = 0
|
||||
gen_index_offset = len(existing_data.get("items", [])) # Sequential index for deterministic sort ordering
|
||||
skipped_count = 0
|
||||
start_at_job = int(session_settings.get("start_at_job", 0)) if session_settings else 0
|
||||
if start_at_job > 0:
|
||||
print(f"[GridTester] ⏭️ Start At Job #{start_at_job} — skipping earlier jobs")
|
||||
job_durations = []
|
||||
deferred_upscale_queue = []
|
||||
eta_start_time = time.time()
|
||||
@@ -1041,6 +1044,11 @@ def run_generation_loop(
|
||||
)
|
||||
actual_negative_prompt = conf["negative"]
|
||||
|
||||
# ==== START AT JOB # (skip earlier jobs) ====
|
||||
if start_at_job > 0 and current_job < start_at_job:
|
||||
skipped_count += 1
|
||||
continue
|
||||
|
||||
# ==== CHECK EXISTING MATCH ====
|
||||
match_index = check_if_job_completed(
|
||||
existing_data["items"],
|
||||
|
||||
@@ -5218,6 +5218,59 @@ export function renderCooldownSection(node, container) {
|
||||
|
||||
// --- MAIN RENDER UI FUNCTION ---
|
||||
|
||||
// ============================================================================
|
||||
// RUN SETTINGS (Start At Job #, etc.)
|
||||
// ============================================================================
|
||||
export function renderRunSettingsSection(node, container) {
|
||||
if (node.state.start_at_job === undefined) node.state.start_at_job = 0;
|
||||
|
||||
const section = document.createElement("div");
|
||||
section.className = "cb-section full-width";
|
||||
section.id = "cb-sec-runsettings";
|
||||
|
||||
const header = document.createElement("div");
|
||||
header.className = "cb-section-header";
|
||||
header.textContent = "▸ Run Settings";
|
||||
header.style.cursor = "pointer";
|
||||
|
||||
const content = document.createElement("div");
|
||||
content.className = "cb-section-content";
|
||||
content.style.display = "none";
|
||||
|
||||
header.onclick = () => {
|
||||
const isOpen = content.style.display !== "none";
|
||||
content.style.display = isOpen ? "none" : "block";
|
||||
header.textContent = (isOpen ? "▸" : "▾") + " Run Settings";
|
||||
};
|
||||
|
||||
// Start At Job # input
|
||||
const jobDiv = document.createElement("div");
|
||||
jobDiv.style.cssText = "margin-bottom: 8px; display: flex; align-items: center; gap: 8px;";
|
||||
const jobLabel = document.createElement("label");
|
||||
jobLabel.textContent = "Start At Job #:";
|
||||
jobLabel.style.cssText = "font-size: 12px; color: #ccc; white-space: nowrap;";
|
||||
const jobInput = document.createElement("input");
|
||||
jobInput.type = "number";
|
||||
jobInput.min = "0";
|
||||
jobInput.value = node.state.start_at_job || 0;
|
||||
jobInput.style.cssText = "width: 70px; background: #1a1a1a; color: #ccc; border: 1px solid #444; border-radius: 4px; padding: 4px 6px; font-size: 12px;";
|
||||
jobInput.onchange = () => {
|
||||
node.state.start_at_job = parseInt(jobInput.value) || 0;
|
||||
node.setDirtyCanvas(true);
|
||||
};
|
||||
const jobDesc = document.createElement("div");
|
||||
jobDesc.style.cssText = "font-size: 9px; color: #666;";
|
||||
jobDesc.textContent = "Skip to this job number (0 = start from beginning). Useful for resuming at a specific point.";
|
||||
jobDiv.appendChild(jobLabel);
|
||||
jobDiv.appendChild(jobInput);
|
||||
content.appendChild(jobDiv);
|
||||
content.appendChild(jobDesc);
|
||||
|
||||
section.appendChild(header);
|
||||
section.appendChild(content);
|
||||
container.appendChild(section);
|
||||
}
|
||||
|
||||
export function renderPreviewSection(container) {
|
||||
const section = document.createElement("div");
|
||||
section.className = "cb-section full-width";
|
||||
@@ -5413,6 +5466,7 @@ export async function renderUI(node, availableLoras, modelLists, loraFolders, av
|
||||
// Session-level settings (applies to all configs)
|
||||
renderUpscalingSection(node, mainContent, modelLists);
|
||||
renderCooldownSection(node, mainContent);
|
||||
renderRunSettingsSection(node, mainContent);
|
||||
|
||||
// JSON Preview Section
|
||||
renderPreviewSection(mainContent);
|
||||
|
||||
@@ -717,6 +717,11 @@ export function convertStateToConfigs(state) {
|
||||
sessionSettings.cooldown = { ...state.cooldown };
|
||||
}
|
||||
|
||||
// Start At Job # (skip to a specific job number)
|
||||
if (state.start_at_job && parseInt(state.start_at_job) > 0) {
|
||||
sessionSettings.start_at_job = parseInt(state.start_at_job);
|
||||
}
|
||||
|
||||
// Attach session settings to the configs output if any are enabled
|
||||
if (Object.keys(sessionSettings).length > 0) {
|
||||
configs._session_settings = sessionSettings;
|
||||
|
||||
Reference in New Issue
Block a user