Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0886ea6e2b |
@@ -1,5 +1,53 @@
|
||||
# DEVLOG - ComfyUI-Workflow-Studio
|
||||
|
||||
## 2026-04-28: v0.3.2 生成UIタブ — Checkpoint Batch・Seed UIレイアウト修正
|
||||
|
||||
### 概要
|
||||
|
||||
- 生成UIタブの右パネルに **Checkpoint Batch** 機能を追加
|
||||
- Seed行のレイアウトを2段構成に変更(seed値とモード選択が見切れる問題を解消)
|
||||
|
||||
### 変更内容
|
||||
|
||||
#### `templates/index.html` — UI要素追加・修正
|
||||
|
||||
**Checkpoint Batch パネル追加:**
|
||||
- 右パネル(Seed行の下・結果表示の上)に `wfm-ckpt-batch-panel` を追加
|
||||
- チェックボックス ON/OFF でバッチ設定欄を展開/折りたたみ
|
||||
- Include Folders テキスト入力 — カンマ区切りでサブフォルダ名を指定。空欄でcheckpointフォルダ内の全モデルを対象
|
||||
- Exclude Folders テキスト入力 — カンマ区切りで除外するサブフォルダ名を指定
|
||||
- 対象モデル数プレビュー表示 (`wfm-ckpt-batch-info`)
|
||||
- バッチ進捗エリア — 現在のモデル名、インデックス/総数、アンバー色プログレスバー (`wfm-ckpt-batch-bar`)
|
||||
|
||||
**Seed レイアウト修正:**
|
||||
- 横並び1行(`flex-direction: row`)→ 縦2行(`flex-direction: column`)に変更
|
||||
- 1行目: `Seed:` ラベル + 数値入力(`flex:1` で横幅いっぱい)
|
||||
- 2行目: モード選択セレクト(`width:100%`)
|
||||
|
||||
**ヘルプタブ:**
|
||||
- GenerateUI タブ説明に gen-11(Checkpoint Batch の説明)を追加
|
||||
- gen-8(Seed control)に2段レイアウト化の補足を追加
|
||||
|
||||
#### `static/js/generate-tab.js` — バッチロジック追加・生成処理リファクタリング
|
||||
|
||||
**新規追加:**
|
||||
- `_ckptBatch` — `{ aborted: false }` バッチ中断フラグ
|
||||
- `_parseFolderList(str)` — カンマ区切り文字列をトリム・小文字化して配列に変換
|
||||
- `_getModelFolder(modelPath)` — パスの最初の `/` より前を抽出してフォルダ名を取得。`\\` を `/` に正規化、ルート直下は `""` を返す
|
||||
- `_filterCheckpoints(checkpoints, includeStr, excludeStr)` — include/exclude フィルタを適用したチェックポイントリストを返す。大文字小文字を区別しない
|
||||
- `_updateBatchInfo()` — チェックポイントリストのフィルタ済み件数を `wfm-ckpt-batch-info` に即時反映
|
||||
- `initCheckpointBatch()` — チェックボックス・include/exclude 入力のイベントリスナーを登録
|
||||
- `_coreGenerate(silent)` — 1回の生成コア処理(`silent=true` のとき完了トーストを省略)。エラー時はスローする
|
||||
- `_runBatchGenerate()` — チェックポイントリストをループし `_coreGenerate` を順番に呼び出す。各反復でワークフロー内の全checkpointノードの `ckpt_name` を書き換える。エラーは件数カウントして継続。完了後に結果サマリをトースト表示
|
||||
|
||||
**変更:**
|
||||
- `handleGenerate()` — バッチが有効な場合は `_runBatchGenerate()` を、無効の場合は `_coreGenerate(false)` を呼び出すよう分岐。ボタン管理(disabled / Stop 表示)を共通 try/finally で処理
|
||||
- interrupt ボタンのハンドラ — `_ckptBatch.aborted = true` を設定してから `comfyUI.interrupt()` を呼び出し、単発生成とバッチの両方を停止できるように
|
||||
- Refresh Models ボタンのハンドラ — モデルリスト再取得後に `_updateBatchInfo()` を呼び出してバッチ件数を更新
|
||||
- `initGenerateTab()` — 末尾で `initCheckpointBatch()` を呼び出し。初期接続成功時に `_updateBatchInfo()` を呼び出し
|
||||
|
||||
---
|
||||
|
||||
## 2026-04-27: v0.3.1 ギャラリー拡張(フォルダ/ファイル操作・ワークフロー保存)
|
||||
|
||||
### 概要
|
||||
|
||||
@@ -5,7 +5,7 @@ A comprehensive workflow management and generation UI plugin for [ComfyUI](https
|
||||
Browse, organize, and execute workflows directly from a dedicated studio interface — without switching between windows or manually editing JSON.
|
||||
|
||||

|
||||

|
||||

|
||||
|
||||
## Screenshots
|
||||
|
||||
@@ -50,14 +50,15 @@ Browse, organize, and execute workflows directly from a dedicated studio interfa
|
||||
- **Embedded workflow metadata** — workflow JSON is embedded in the PNG (tEXt chunk), compatible with ComfyUI's drag-and-drop import
|
||||
- **Auto-import** — the captured workflow is automatically imported and appears in the Workflow tab
|
||||
|
||||
### GenerateUI Tab (v0.2.4)
|
||||
### GenerateUI Tab (v0.3.2)
|
||||
- **3-tab layout** — Input / Model / Settings tabs, each with a Raw JSON column on the right for instant preview and direct editing
|
||||
- **Input tab** — Prompt (top) and Image drag-and-drop (bottom) in the left column; Raw JSON (540px) in the right column
|
||||
- **Model tab** — Checkpoint, VAE, LoRA, ControlNet, UNET, TextEncoder selectors with filter; Raw JSON on the right
|
||||
- **Settings tab** — KSampler (top) and LatentImage (bottom) in the left column; Raw JSON on the right
|
||||
- **Always-visible Raw JSON** — edit the API-format JSON directly from any tab with syntax highlighting; Apply button reloads the workflow
|
||||
- **One-click generation** — queue prompts to ComfyUI without leaving the studio
|
||||
- **Seed control** — randomize, lock, or manually set seeds
|
||||
- **Seed control** — randomize, lock, or manually set seeds; seed input and mode selector stacked vertically for readability
|
||||
- **Checkpoint Batch** — enable via checkbox in the right panel to sequentially generate with every checkpoint model; filter by include folders (comma-separated subfolder names, empty = all) and/or exclude folders; Stop button aborts after the current generation completes; amber progress bar tracks per-model progress
|
||||
- **UI-to-API conversion** — automatic conversion supporting subgraphs (nested workflows), COMBO types, and display-only node exclusion
|
||||
- **Eagle integration** — auto-save generated images to [Eagle](https://eagle.cool/) with metadata
|
||||
|
||||
@@ -214,6 +215,10 @@ Click the **camera icon** (next to the W button) in ComfyUI's top bar to capture
|
||||
|
||||
## Changelog
|
||||
|
||||
### v0.3.2
|
||||
- **Checkpoint Batch** — new panel in the GenerateUI right column (below Seed, above results); enable via checkbox to auto-generate once per checkpoint model; filter included/excluded subfolders by comma-separated names (empty = all checkpoints); real-time preview of matched model count; amber progress bar shows current model name and index; Stop button aborts the loop after the current generation completes; failed models are counted and reported in the summary toast
|
||||
- **Seed layout fix** — seed value input and mode selector (Random / Fixed / Increment / Decrement) now stacked vertically so neither is clipped in narrow panels
|
||||
|
||||
### v0.3.1
|
||||
- **Folder operations** — create subfolders and delete folders (with all contents) directly from the folder tree header buttons
|
||||
- **File operations** — move or delete individual images from the detail panel; bulk move and bulk delete from the multi-select bar
|
||||
|
||||
+214
-76
@@ -150,7 +150,199 @@ export async function loadWorkflowIntoEditor(workflow, filename) {
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// Generation
|
||||
// Checkpoint Batch
|
||||
// ============================================
|
||||
|
||||
const _ckptBatch = { aborted: false };
|
||||
|
||||
function _parseFolderList(str) {
|
||||
return str.split(",").map((s) => s.trim().toLowerCase()).filter(Boolean);
|
||||
}
|
||||
|
||||
function _getModelFolder(modelPath) {
|
||||
const normalized = modelPath.replace(/\\/g, "/");
|
||||
const idx = normalized.indexOf("/");
|
||||
return idx === -1 ? "" : normalized.substring(0, idx).toLowerCase();
|
||||
}
|
||||
|
||||
function _filterCheckpoints(checkpoints, includeStr, excludeStr) {
|
||||
const inc = _parseFolderList(includeStr);
|
||||
const exc = _parseFolderList(excludeStr);
|
||||
return checkpoints.filter((m) => {
|
||||
const folder = _getModelFolder(m);
|
||||
if (inc.length > 0 && !inc.includes(folder)) return false;
|
||||
if (exc.length > 0 && exc.includes(folder)) return false;
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
function _updateBatchInfo() {
|
||||
const infoEl = document.getElementById("wfm-ckpt-batch-info");
|
||||
if (!infoEl) return;
|
||||
const inc = document.getElementById("wfm-ckpt-batch-include")?.value || "";
|
||||
const exc = document.getElementById("wfm-ckpt-batch-exclude")?.value || "";
|
||||
const n = _filterCheckpoints(comfyEditor.models.checkpoints, inc, exc).length;
|
||||
infoEl.textContent = `${n} checkpoint${n !== 1 ? "s" : ""} will be processed`;
|
||||
}
|
||||
|
||||
function initCheckpointBatch() {
|
||||
const checkbox = document.getElementById("wfm-ckpt-batch-enabled");
|
||||
const body = document.getElementById("wfm-ckpt-batch-body");
|
||||
|
||||
checkbox?.addEventListener("change", () => {
|
||||
if (body) body.style.display = checkbox.checked ? "block" : "none";
|
||||
if (checkbox.checked) _updateBatchInfo();
|
||||
});
|
||||
|
||||
document.getElementById("wfm-ckpt-batch-include")?.addEventListener("input", _updateBatchInfo);
|
||||
document.getElementById("wfm-ckpt-batch-exclude")?.addEventListener("input", _updateBatchInfo);
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// Generation (core — throws on error)
|
||||
// ============================================
|
||||
|
||||
async function _coreGenerate(silent = false) {
|
||||
const progressBar = document.getElementById("wfm-gen-progress-bar");
|
||||
const progressText = document.getElementById("wfm-gen-progress-text");
|
||||
const resultImg = document.getElementById("wfm-gen-result-img");
|
||||
const resultThumbs = document.getElementById("wfm-gen-result-thumbs");
|
||||
|
||||
const seedMode = document.getElementById("wfm-gen-seed-mode")?.value || "random";
|
||||
const seedValue = parseInt(document.getElementById("wfm-gen-seed-value")?.value) || -1;
|
||||
|
||||
if (progressBar) progressBar.style.width = "0%";
|
||||
if (progressText) progressText.textContent = "Starting...";
|
||||
|
||||
const { images, seed } = await comfyUI.generate(
|
||||
{ ...comfyUI.currentWorkflow },
|
||||
{
|
||||
seedMode,
|
||||
seedValue,
|
||||
onProgress: (pct) => {
|
||||
if (progressBar) progressBar.style.width = `${(pct * 100).toFixed(1)}%`;
|
||||
if (progressText) progressText.textContent = `${(pct * 100).toFixed(0)}%`;
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const seedEl = document.getElementById("wfm-gen-seed-value");
|
||||
if (seedEl) seedEl.value = seed;
|
||||
|
||||
if (progressText) progressText.textContent = `Done (${images.length} image${images.length !== 1 ? "s" : ""})`;
|
||||
if (progressBar) progressBar.style.width = "100%";
|
||||
|
||||
if (images.length > 0) {
|
||||
const blob = await comfyUI.getImageBlob(images[0]);
|
||||
const url = URL.createObjectURL(blob);
|
||||
if (resultImg) {
|
||||
resultImg.src = url;
|
||||
resultImg.style.display = "block";
|
||||
}
|
||||
|
||||
if (resultThumbs && images.length > 1) {
|
||||
resultThumbs.innerHTML = "";
|
||||
for (let i = 0; i < images.length; i++) {
|
||||
const b = i === 0 ? blob : await comfyUI.getImageBlob(images[i]);
|
||||
const u = i === 0 ? url : URL.createObjectURL(b);
|
||||
const thumb = document.createElement("img");
|
||||
thumb.src = u;
|
||||
thumb.className = `wfm-gen-thumb ${i === 0 ? "active" : ""}`;
|
||||
thumb.addEventListener("click", () => {
|
||||
resultImg.src = u;
|
||||
resultThumbs.querySelectorAll(".wfm-gen-thumb").forEach((t) => t.classList.remove("active"));
|
||||
thumb.classList.add("active");
|
||||
});
|
||||
resultThumbs.appendChild(thumb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (getEagleSettings().autoSave && images.length > 0) {
|
||||
for (const img of images) {
|
||||
const viewUrl = `/view?filename=${encodeURIComponent(img.filename)}&subfolder=${encodeURIComponent(img.subfolder || "")}&type=${encodeURIComponent(img.type || "output")}`;
|
||||
saveToEagle(viewUrl, img.filename);
|
||||
}
|
||||
}
|
||||
|
||||
if (images.length > 0) {
|
||||
saveGeneratedImagesMeta(images, { ...comfyUI.currentWorkflow }).catch(() => {});
|
||||
}
|
||||
|
||||
if (!silent) showToast("Generation complete", "success");
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// Batch generation loop
|
||||
// ============================================
|
||||
|
||||
async function _runBatchGenerate() {
|
||||
const ckptNodes = comfyUI.currentAnalysis?.checkpoint_nodes || [];
|
||||
if (ckptNodes.length === 0) {
|
||||
showToast("No checkpoint node found in workflow", "error");
|
||||
return;
|
||||
}
|
||||
|
||||
const inc = document.getElementById("wfm-ckpt-batch-include")?.value || "";
|
||||
const exc = document.getElementById("wfm-ckpt-batch-exclude")?.value || "";
|
||||
const list = _filterCheckpoints(comfyEditor.models.checkpoints, inc, exc);
|
||||
|
||||
if (list.length === 0) {
|
||||
showToast("No checkpoints match the folder filter", "error");
|
||||
return;
|
||||
}
|
||||
|
||||
const batchProgress = document.getElementById("wfm-ckpt-batch-progress");
|
||||
const batchCurrentName = document.getElementById("wfm-ckpt-batch-current-name");
|
||||
const batchCount = document.getElementById("wfm-ckpt-batch-count");
|
||||
const batchBar = document.getElementById("wfm-ckpt-batch-bar");
|
||||
const progressText = document.getElementById("wfm-gen-progress-text");
|
||||
|
||||
if (batchProgress) batchProgress.style.display = "block";
|
||||
|
||||
let completed = 0;
|
||||
let failed = 0;
|
||||
|
||||
for (let i = 0; i < list.length; i++) {
|
||||
if (_ckptBatch.aborted) break;
|
||||
|
||||
const model = list[i];
|
||||
if (batchCurrentName) batchCurrentName.textContent = model;
|
||||
if (batchCount) batchCount.textContent = `${i + 1} / ${list.length}`;
|
||||
if (batchBar) batchBar.style.width = `${((i / list.length) * 100).toFixed(1)}%`;
|
||||
if (progressText) progressText.textContent = `[${i + 1}/${list.length}] Loading...`;
|
||||
|
||||
for (const node of ckptNodes) {
|
||||
if (comfyUI.currentWorkflow?.[node.id]) {
|
||||
comfyUI.currentWorkflow[node.id].inputs.ckpt_name = model;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
await _coreGenerate(true);
|
||||
completed++;
|
||||
} catch (err) {
|
||||
if (_ckptBatch.aborted) break;
|
||||
failed++;
|
||||
showToast(`[${i + 1}/${list.length}] Failed: ${err.message}`, "error");
|
||||
}
|
||||
}
|
||||
|
||||
if (batchBar) batchBar.style.width = "100%";
|
||||
if (batchCurrentName) batchCurrentName.textContent = _ckptBatch.aborted ? "Stopped" : "Done";
|
||||
|
||||
if (_ckptBatch.aborted) {
|
||||
showToast(`Batch stopped — ${completed} completed, ${failed} failed`, "info");
|
||||
} else {
|
||||
showToast(
|
||||
`Batch complete: ${completed}/${list.length}${failed > 0 ? ` (${failed} failed)` : ""}`,
|
||||
failed > 0 ? "error" : "success"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// Generate entry point
|
||||
// ============================================
|
||||
|
||||
async function handleGenerate() {
|
||||
@@ -160,89 +352,29 @@ async function handleGenerate() {
|
||||
}
|
||||
if (comfyUI.generating) return;
|
||||
|
||||
const genBtn = document.getElementById("wfm-gen-generate-btn");
|
||||
const progressBar = document.getElementById("wfm-gen-progress-bar");
|
||||
const progressText = document.getElementById("wfm-gen-progress-text");
|
||||
const interruptBtn = document.getElementById("wfm-gen-interrupt-btn");
|
||||
const resultImg = document.getElementById("wfm-gen-result-img");
|
||||
const resultThumbs = document.getElementById("wfm-gen-result-thumbs");
|
||||
|
||||
// Sync prompts to workflow
|
||||
comfyEditor.syncToWorkflow();
|
||||
|
||||
const seedMode = document.getElementById("wfm-gen-seed-mode")?.value || "random";
|
||||
const seedValue = parseInt(document.getElementById("wfm-gen-seed-value")?.value) || -1;
|
||||
const genBtn = document.getElementById("wfm-gen-generate-btn");
|
||||
const interruptBtn = document.getElementById("wfm-gen-interrupt-btn");
|
||||
|
||||
genBtn.disabled = true;
|
||||
if (interruptBtn) interruptBtn.style.display = "inline-block";
|
||||
if (progressBar) progressBar.style.width = "0%";
|
||||
if (progressText) progressText.textContent = "Starting...";
|
||||
_ckptBatch.aborted = false;
|
||||
|
||||
const batchEnabled = document.getElementById("wfm-ckpt-batch-enabled")?.checked;
|
||||
|
||||
try {
|
||||
const { images, seed } = await comfyUI.generate(
|
||||
{ ...comfyUI.currentWorkflow },
|
||||
{
|
||||
seedMode,
|
||||
seedValue,
|
||||
onProgress: (pct) => {
|
||||
if (progressBar) progressBar.style.width = `${(pct * 100).toFixed(1)}%`;
|
||||
if (progressText) progressText.textContent = `${(pct * 100).toFixed(0)}%`;
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
// Update seed display
|
||||
const seedEl = document.getElementById("wfm-gen-seed-value");
|
||||
if (seedEl) seedEl.value = seed;
|
||||
|
||||
if (progressText) progressText.textContent = `Done (${images.length} image${images.length !== 1 ? "s" : ""})`;
|
||||
if (progressBar) progressBar.style.width = "100%";
|
||||
|
||||
// Display results
|
||||
if (images.length > 0) {
|
||||
const blob = await comfyUI.getImageBlob(images[0]);
|
||||
const url = URL.createObjectURL(blob);
|
||||
if (resultImg) {
|
||||
resultImg.src = url;
|
||||
resultImg.style.display = "block";
|
||||
}
|
||||
|
||||
// Thumbnails for multiple images
|
||||
if (resultThumbs && images.length > 1) {
|
||||
resultThumbs.innerHTML = "";
|
||||
for (let i = 0; i < images.length; i++) {
|
||||
const b = i === 0 ? blob : await comfyUI.getImageBlob(images[i]);
|
||||
const u = i === 0 ? url : URL.createObjectURL(b);
|
||||
const thumb = document.createElement("img");
|
||||
thumb.src = u;
|
||||
thumb.className = `wfm-gen-thumb ${i === 0 ? "active" : ""}`;
|
||||
thumb.addEventListener("click", () => {
|
||||
resultImg.src = u;
|
||||
resultThumbs.querySelectorAll(".wfm-gen-thumb").forEach((t) => t.classList.remove("active"));
|
||||
thumb.classList.add("active");
|
||||
});
|
||||
resultThumbs.appendChild(thumb);
|
||||
}
|
||||
if (batchEnabled) {
|
||||
await _runBatchGenerate();
|
||||
} else {
|
||||
try {
|
||||
await _coreGenerate(false);
|
||||
} catch (err) {
|
||||
const progressText = document.getElementById("wfm-gen-progress-text");
|
||||
if (progressText) progressText.textContent = "Error";
|
||||
showToast("Generation error: " + err.message, "error");
|
||||
}
|
||||
}
|
||||
|
||||
// Eagle auto-save
|
||||
if (getEagleSettings().autoSave && images.length > 0) {
|
||||
for (const img of images) {
|
||||
const viewUrl = `/view?filename=${encodeURIComponent(img.filename)}&subfolder=${encodeURIComponent(img.subfolder || "")}&type=${encodeURIComponent(img.type || "output")}`;
|
||||
saveToEagle(viewUrl, img.filename);
|
||||
}
|
||||
}
|
||||
|
||||
// ギャラリーメタデータ: 生成ワークフローを保存
|
||||
if (images.length > 0) {
|
||||
saveGeneratedImagesMeta(images, { ...comfyUI.currentWorkflow }).catch(() => {});
|
||||
}
|
||||
|
||||
showToast("Generation complete", "success");
|
||||
} catch (err) {
|
||||
if (progressText) progressText.textContent = "Error";
|
||||
showToast("Generation error: " + err.message, "error");
|
||||
} finally {
|
||||
genBtn.disabled = false;
|
||||
if (interruptBtn) interruptBtn.style.display = "none";
|
||||
@@ -276,13 +408,15 @@ export async function initGenerateTab() {
|
||||
comfyEditor.renderAll(comfyUI.currentAnalysis, comfyUI.currentWorkflow);
|
||||
}
|
||||
showToast("Model lists refreshed", "success");
|
||||
_updateBatchInfo();
|
||||
});
|
||||
|
||||
// Generate button
|
||||
document.getElementById("wfm-gen-generate-btn")?.addEventListener("click", handleGenerate);
|
||||
|
||||
// Interrupt button
|
||||
// Interrupt button (stops both single generation and batch loop)
|
||||
document.getElementById("wfm-gen-interrupt-btn")?.addEventListener("click", async () => {
|
||||
_ckptBatch.aborted = true;
|
||||
await comfyUI.interrupt();
|
||||
showToast("Interrupted", "info");
|
||||
});
|
||||
@@ -350,11 +484,15 @@ export async function initGenerateTab() {
|
||||
_outputDir = (e.detail?.path || "").replace(/\\/g, "/").replace(/\/$/, "");
|
||||
});
|
||||
|
||||
// Checkpoint batch UI
|
||||
initCheckpointBatch();
|
||||
|
||||
// Auto-connect on init
|
||||
const connected = await comfyUI.checkConnection();
|
||||
updateStatus(connected);
|
||||
if (connected) {
|
||||
await comfyEditor.loadModelLists();
|
||||
_updateBatchInfo();
|
||||
}
|
||||
|
||||
// Auto-load default workflow (doesn't require ComfyUI connection)
|
||||
|
||||
+36
-5
@@ -330,10 +330,12 @@
|
||||
</div>
|
||||
|
||||
<!-- Seed -->
|
||||
<div style="display:flex;gap:8px;align-items:center;margin-top:8px;">
|
||||
<label style="font-size:12px;color:var(--wfm-text-secondary);white-space:nowrap;">Seed:</label>
|
||||
<input type="number" id="wfm-gen-seed-value" class="wfm-input" value="-1" style="width:130px;">
|
||||
<select id="wfm-gen-seed-mode" class="wfm-select" style="width:auto;">
|
||||
<div style="display:flex;flex-direction:column;gap:4px;margin-top:8px;">
|
||||
<div style="display:flex;gap:8px;align-items:center;">
|
||||
<label style="font-size:12px;color:var(--wfm-text-secondary);white-space:nowrap;">Seed:</label>
|
||||
<input type="number" id="wfm-gen-seed-value" class="wfm-input" value="-1" style="flex:1;min-width:0;">
|
||||
</div>
|
||||
<select id="wfm-gen-seed-mode" class="wfm-select" style="width:100%;">
|
||||
<option value="random">Random</option>
|
||||
<option value="fixed">Fixed</option>
|
||||
<option value="increment">Increment</option>
|
||||
@@ -342,6 +344,34 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Checkpoint Batch Panel -->
|
||||
<div class="wfm-gen-panel" id="wfm-ckpt-batch-panel">
|
||||
<div style="display:flex;align-items:center;gap:8px;">
|
||||
<input type="checkbox" id="wfm-ckpt-batch-enabled" style="width:14px;height:14px;cursor:pointer;accent-color:var(--wfm-primary);">
|
||||
<label for="wfm-ckpt-batch-enabled" style="font-weight:600;font-size:13px;cursor:pointer;">Checkpoint Batch</label>
|
||||
</div>
|
||||
<div id="wfm-ckpt-batch-body" style="display:none;margin-top:8px;">
|
||||
<div style="margin-bottom:6px;">
|
||||
<div style="font-size:11px;color:var(--wfm-text-secondary);margin-bottom:3px;">Include Folders (empty = all, comma-separated)</div>
|
||||
<input type="text" id="wfm-ckpt-batch-include" class="wfm-input" placeholder="e.g. sdxl, flux">
|
||||
</div>
|
||||
<div style="margin-bottom:6px;">
|
||||
<div style="font-size:11px;color:var(--wfm-text-secondary);margin-bottom:3px;">Exclude Folders (comma-separated)</div>
|
||||
<input type="text" id="wfm-ckpt-batch-exclude" class="wfm-input" placeholder="e.g. old, test">
|
||||
</div>
|
||||
<div id="wfm-ckpt-batch-info" style="font-size:11px;color:var(--wfm-text-secondary);"></div>
|
||||
<div id="wfm-ckpt-batch-progress" style="margin-top:8px;display:none;">
|
||||
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:4px;font-size:11px;">
|
||||
<span id="wfm-ckpt-batch-current-name" style="overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:75%;color:var(--wfm-text-primary);"></span>
|
||||
<span id="wfm-ckpt-batch-count" style="color:var(--wfm-text-secondary);white-space:nowrap;margin-left:8px;"></span>
|
||||
</div>
|
||||
<div class="wfm-gen-progress-track">
|
||||
<div id="wfm-ckpt-batch-bar" class="wfm-gen-progress-bar" style="background:var(--wfm-warning,#f59e0b);"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Result Display -->
|
||||
<div class="wfm-gen-result">
|
||||
<img id="wfm-gen-result-img" style="display:none;max-width:100%;border-radius:6px;">
|
||||
@@ -509,9 +539,10 @@
|
||||
<li id="wfm-help-gen-5">Model tab: Checkpoint, VAE, LoRA, ControlNet, UNET, TextEncoder selectors with filter</li>
|
||||
<li id="wfm-help-gen-6">Settings tab: KSampler (top) and LatentImage (bottom) in the left column</li>
|
||||
<li id="wfm-help-gen-7">Raw JSON always visible in the right column of each tab — edit directly and Apply to reload the workflow</li>
|
||||
<li id="wfm-help-gen-8">Seed control: random, fixed, increment, decrement</li>
|
||||
<li id="wfm-help-gen-8">Seed control: random, fixed, increment, decrement — seed input and mode selector stacked vertically for readability</li>
|
||||
<li id="wfm-help-gen-9">Generate, progress display, stop, and view results</li>
|
||||
<li id="wfm-help-gen-10">Eagle integration: auto-save generated images to Eagle</li>
|
||||
<li id="wfm-help-gen-11">Checkpoint Batch: enable via checkbox in the right panel to auto-generate once per checkpoint model; filter by include folders (comma-separated), exclude folders, or leave blank to use all checkpoints; Stop button aborts the loop after the current generation; per-model progress bar shown in amber</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user