Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c7bc792b49 | ||
|
|
808dc14bc0 | ||
|
|
08c8111c89 | ||
|
|
4a55a946bb | ||
|
|
dfaeddbbc7 | ||
|
|
90450c4fd5 |
+22
@@ -0,0 +1,22 @@
|
|||||||
|
# --- Python関連 ---
|
||||||
|
# これがJavaの.classに近いものじゃ。実行時に自動生成される。
|
||||||
|
__pycache__/
|
||||||
|
*.py[cod]
|
||||||
|
*$py.class
|
||||||
|
|
||||||
|
# 仮想環境(もしプロジェクト内に作っておるなら)
|
||||||
|
venv/
|
||||||
|
.venv/
|
||||||
|
env/
|
||||||
|
|
||||||
|
# --- エディタ・OS関連 ---
|
||||||
|
# VS Codeの設定ファイル(個人設定が含まれることがあるので除外)
|
||||||
|
.vscode/
|
||||||
|
# macOSが勝手に作るゴミ
|
||||||
|
.DS_Store
|
||||||
|
# Windowsのサムネイルキャッシュ
|
||||||
|
Thumbs.db
|
||||||
|
|
||||||
|
# --- ComfyUI/カスタムノード特有 ---
|
||||||
|
# もし一時ファイルやログを書き出す仕組みを作ったなら、それも追加じゃ
|
||||||
|
*.log
|
||||||
@@ -1,3 +1,34 @@
|
|||||||
|
# ⚠️ Project moved / 後継プロジェクトのお知らせ
|
||||||
|
|
||||||
|
This project has been succeeded by **ComfyUI-CheckpointHandpickerSuite**.
|
||||||
|
|
||||||
|
👉 https://github.com/ruminar/ComfyUI-CheckpointHandpickerSuite
|
||||||
|
|
||||||
|
`ComfyUI-CheckpointHandpickerSuite` includes the cleanup/review workflow from this project and adds:
|
||||||
|
|
||||||
|
- Checkpoint Name Cycler
|
||||||
|
- Checkpoint List Selector
|
||||||
|
- Checkpoint Status Tagger
|
||||||
|
- Ephemeral Preview
|
||||||
|
- ImageDir Preview
|
||||||
|
- Safe delete reservation workflow
|
||||||
|
|
||||||
|
This repository is kept for archive/reference purposes.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# ⚠️ 後継プロジェクトのお知らせ
|
||||||
|
|
||||||
|
このプロジェクトは、後継版である **ComfyUI-CheckpointHandpickerSuite** に統合・発展しました。
|
||||||
|
|
||||||
|
👉 https://github.com/ruminar/ComfyUI-CheckpointHandpickerSuite
|
||||||
|
|
||||||
|
新しいSuiteでは、このプロジェクトのCheckpoint整理・削除予約ワークフローに加えて、Checkpoint巡回、別タブレビュー、ステータスタグ付け、プレビュー機能などが追加されています。
|
||||||
|
|
||||||
|
このリポジトリは、過去版の参照用として残しています。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
# ComfyUI-CheckpointWidgetRefresh
|
# ComfyUI-CheckpointWidgetRefresh
|
||||||
|
|
||||||
ComfyUIを再起動せずに、Checkpoint系の選択リストを現在のファイル状態へ同期する小さなUIノードじゃ!
|
ComfyUIを再起動せずに、Checkpoint系の選択リストを現在のファイル状態へ同期する小さなUIノードじゃ!
|
||||||
@@ -16,6 +47,10 @@ ComfyUIを再起動せずに、Checkpoint系の選択リストを現在のファ
|
|||||||
- **バックエンドまで貫くパッチ** <br/>
|
- **バックエンドまで貫くパッチ** <br/>
|
||||||
ブラウザ上の表示を変えるだけではない。Python側の型定義(`INPUT_TYPES` など)まで更新するため、バリデーションで弾かれる心配も少ないのじゃ。
|
ブラウザ上の表示を変えるだけではない。Python側の型定義(`INPUT_TYPES` など)まで更新するため、バリデーションで弾かれる心配も少ないのじゃ。
|
||||||
|
|
||||||
|
- **Checkpoint Name Cycler との強力連携** (New!) <br/>
|
||||||
|
これと対となるノード、**[`Checkpoint Name Cycler`](https://github.com/ruminar/ComfyUI-CheckpointNameCycler)** があれば、巡回状態も初期化するぞ。 <br/>
|
||||||
|
`start_checkpoint` から改めて巡回を始めたい時は、リフレッシュボタンをクリックじゃ!
|
||||||
|
|
||||||
- **徹底した軽量設計** <br/>
|
- **徹底した軽量設計** <br/>
|
||||||
常時監視やポーリングは一切しない。おぬしが「今だ!」とボタンを押した時だけ動く、ワークフローの邪魔をしない奥ゆかしい実用品じゃ。
|
常時監視やポーリングは一切しない。おぬしが「今だ!」とボタンを押した時だけ動く、ワークフローの邪魔をしない奥ゆかしい実用品じゃ。
|
||||||
|
|
||||||
@@ -25,7 +60,7 @@ ComfyUIの `custom_nodes` ディレクトリで、以下のコマンドを打ち
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
git clone https://github.com/ruminar/ComfyUI-CheckpointWidgetRefresh.git
|
git clone https://github.com/ruminar/ComfyUI-CheckpointWidgetRefresh.git
|
||||||
````
|
```
|
||||||
|
|
||||||
## 使い方
|
## 使い方
|
||||||
|
|
||||||
@@ -41,12 +76,14 @@ git clone https://github.com/ruminar/ComfyUI-CheckpointWidgetRefresh.git
|
|||||||
|
|
||||||
<br/>
|
<br/>
|
||||||
|
|
||||||
<img width="982" height="418" alt="image" src="https://github.com/user-attachments/assets/112b8c0c-b2da-4d55-a622-5dbd0af9d2be" />
|
<img width="876" height="480" alt="image" src="https://github.com/user-attachments/assets/ce6f8c34-0828-44b4-aae5-538d7dcb9268" />
|
||||||
|
|
||||||
|
|
||||||
## 対応ノード
|
## 対応ノード
|
||||||
|
|
||||||
* `CheckpointLoaderSimple`
|
* `CheckpointLoaderSimple`
|
||||||
* `CheckpointNameSelector` 系ノード
|
* `CheckpointNameSelector` 系ノード
|
||||||
|
* [`CheckpointNameCycler`](https://github.com/ruminar/ComfyUI-CheckpointNameCycler)
|
||||||
|
|
||||||
## ライセンス
|
## ライセンス
|
||||||
|
|
||||||
@@ -56,5 +93,3 @@ GPL-3.0
|
|||||||
## 説明画像
|
## 説明画像
|
||||||
|
|
||||||
<img width="1024" height="1536" alt="ComfyUI-CheckpointWidgetRefresh説明" src="https://github.com/user-attachments/assets/d1b7e020-5f60-4ad8-a006-639ae3335fe4" />
|
<img width="1024" height="1536" alt="ComfyUI-CheckpointWidgetRefresh説明" src="https://github.com/user-attachments/assets/d1b7e020-5f60-4ad8-a006-639ae3335fe4" />
|
||||||
|
|
||||||
<br/>
|
|
||||||
|
|||||||
+11
-11
@@ -1,8 +1,15 @@
|
|||||||
# v0.1.0
|
# 0.2.0
|
||||||
|
|
||||||
初回リリースじゃ!
|
CheckpointNameCyclerとの連携機能を追加したのじゃ!
|
||||||
|
|
||||||
## 特徴
|
## 追加
|
||||||
|
|
||||||
|
- `Checkpoint Name Cycler` との連携に対応
|
||||||
|
- `CheckpointNameCycler` の候補リスト更新に対応
|
||||||
|
- `CheckpointNameCycler` のバックエンド側型定義更新に対応
|
||||||
|
- `CheckpointNameCycler` の内部状態リセットAPI呼び出しに対応
|
||||||
|
|
||||||
|
## 既存機能
|
||||||
|
|
||||||
- ComfyUIを再起動せずに、Checkpoint系の選択リストを現在のファイル状態へ同期
|
- ComfyUIを再起動せずに、Checkpoint系の選択リストを現在のファイル状態へ同期
|
||||||
- 標準の `CheckpointLoaderSimple` に対応
|
- 標準の `CheckpointLoaderSimple` に対応
|
||||||
@@ -10,13 +17,6 @@
|
|||||||
- フロントエンドのWidget候補だけでなく、バックエンド側の型定義も更新
|
- フロントエンドのWidget候補だけでなく、バックエンド側の型定義も更新
|
||||||
- 常時監視やポーリングなしの手動更新方式
|
- 常時監視やポーリングなしの手動更新方式
|
||||||
|
|
||||||
## 使い方
|
|
||||||
|
|
||||||
1. Checkpointを追加・削除する
|
|
||||||
2. `Checkpoint Widget Refresh` ノードをキャンバスに置く
|
|
||||||
3. `Refresh Checkpoint Widgets` ボタンを押す
|
|
||||||
4. そのまま作画する
|
|
||||||
|
|
||||||
## 備考
|
## 備考
|
||||||
|
|
||||||
動作確認は、標準の `CheckpointLoaderSimple` と art-venture の `CheckpointNameSelector` で行っています。
|
動作確認は、標準の `CheckpointLoaderSimple`、art-venture の `CheckpointNameSelector`、および `Checkpoint Name Cycler` で行っています。
|
||||||
@@ -20,13 +20,6 @@ def _clear_checkpoint_filename_cache():
|
|||||||
|
|
||||||
|
|
||||||
def _scan_registered_checkpoint_folders():
|
def _scan_registered_checkpoint_folders():
|
||||||
"""
|
|
||||||
Scan only ComfyUI-registered checkpoint folders.
|
|
||||||
|
|
||||||
This intentionally does NOT accept arbitrary user-supplied paths.
|
|
||||||
It should pick up files added/removed under normal checkpoints paths,
|
|
||||||
including paths registered through extra_model_paths.yaml.
|
|
||||||
"""
|
|
||||||
results = set()
|
results = set()
|
||||||
extensions = _get_supported_checkpoint_extensions()
|
extensions = _get_supported_checkpoint_extensions()
|
||||||
|
|
||||||
@@ -54,10 +47,6 @@ def _scan_registered_checkpoint_folders():
|
|||||||
|
|
||||||
|
|
||||||
def _get_fresh_checkpoints():
|
def _get_fresh_checkpoints():
|
||||||
"""
|
|
||||||
Prefer ComfyUI's own list after clearing its filename cache.
|
|
||||||
Merge direct scanning as a safety net for stale model-library states.
|
|
||||||
"""
|
|
||||||
_clear_checkpoint_filename_cache()
|
_clear_checkpoint_filename_cache()
|
||||||
|
|
||||||
results = set()
|
results = set()
|
||||||
@@ -75,17 +64,7 @@ def _get_fresh_checkpoints():
|
|||||||
return sorted(results, key=lambda value: value.lower())
|
return sorted(results, key=lambda value: value.lower())
|
||||||
|
|
||||||
|
|
||||||
def _patch_backend_checkpoint_widget_classes(checkpoints):
|
def _patch_backend_checkpoint_classes(checkpoints):
|
||||||
"""
|
|
||||||
Patch backend class contracts for checkpoint combo nodes.
|
|
||||||
|
|
||||||
Updating only the browser-side widget list is not enough.
|
|
||||||
ComfyUI backend prompt validation can still use stale INPUT_TYPES / RETURN_TYPES.
|
|
||||||
|
|
||||||
Targets:
|
|
||||||
- CheckpointNameSelector-style nodes
|
|
||||||
- CheckpointLoaderSimple
|
|
||||||
"""
|
|
||||||
patched = []
|
patched = []
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@@ -125,6 +104,32 @@ def _patch_backend_checkpoint_widget_classes(checkpoints):
|
|||||||
patched.append(name)
|
patched.append(name)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
if name == "CheckpointNameCycler":
|
||||||
|
def cycler_input_types(cls, _checkpoint_values=checkpoint_values):
|
||||||
|
values = list(_checkpoint_values) or [""]
|
||||||
|
return {
|
||||||
|
"required": {
|
||||||
|
"start_checkpoint": (values,),
|
||||||
|
"mode": (["fixed", "increment", "randomize", "shuffle_once"], {"default": "increment"}),
|
||||||
|
"change_every": ("INT", {"default": 1, "min": 1, "max": 999999}),
|
||||||
|
},
|
||||||
|
"hidden": {
|
||||||
|
"unique_id": "UNIQUE_ID",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
node_class.INPUT_TYPES = classmethod(cycler_input_types)
|
||||||
|
node_class.RETURN_TYPES = (
|
||||||
|
list(checkpoint_values),
|
||||||
|
"STRING",
|
||||||
|
"STRING",
|
||||||
|
"INT",
|
||||||
|
"INT",
|
||||||
|
"INT",
|
||||||
|
)
|
||||||
|
patched.append(name)
|
||||||
|
continue
|
||||||
|
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
print(f"[CheckpointWidgetRefresh] failed to patch {name}: {exc}")
|
print(f"[CheckpointWidgetRefresh] failed to patch {name}: {exc}")
|
||||||
|
|
||||||
@@ -137,7 +142,7 @@ routes = PromptServer.instance.routes
|
|||||||
@routes.get("/checkpoint_widget_refresh/checkpoints")
|
@routes.get("/checkpoint_widget_refresh/checkpoints")
|
||||||
async def checkpoint_widget_refresh_checkpoints(_request):
|
async def checkpoint_widget_refresh_checkpoints(_request):
|
||||||
checkpoints = _get_fresh_checkpoints()
|
checkpoints = _get_fresh_checkpoints()
|
||||||
patched = _patch_backend_checkpoint_widget_classes(checkpoints)
|
patched = _patch_backend_checkpoint_classes(checkpoints)
|
||||||
|
|
||||||
return web.json_response({
|
return web.json_response({
|
||||||
"checkpoints": checkpoints,
|
"checkpoints": checkpoints,
|
||||||
@@ -148,13 +153,6 @@ async def checkpoint_widget_refresh_checkpoints(_request):
|
|||||||
|
|
||||||
|
|
||||||
class CheckpointWidgetRefreshPanel:
|
class CheckpointWidgetRefreshPanel:
|
||||||
"""
|
|
||||||
UI-only panel node.
|
|
||||||
|
|
||||||
The refresh button itself is implemented in web/checkpoint_widget_refresh.js.
|
|
||||||
This backend node exists so the button can be placed inside a workflow as a small panel.
|
|
||||||
"""
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def INPUT_TYPES(cls):
|
def INPUT_TYPES(cls):
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -23,12 +23,24 @@ function isRefresherNode(node) {
|
|||||||
return getNodeTypeName(node) === REFRESHER_NODE_NAME;
|
return getNodeTypeName(node) === REFRESHER_NODE_NAME;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function findWidget(node, name) {
|
||||||
|
return (node?.widgets ?? []).find((widget) => widget?.name === name);
|
||||||
|
}
|
||||||
|
|
||||||
|
function findComboWidget(node, name) {
|
||||||
|
const widget = findWidget(node, name);
|
||||||
|
if (widget && Array.isArray(widget?.options?.values)) {
|
||||||
|
return widget;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
function findCheckpointWidget(node) {
|
function findCheckpointWidget(node) {
|
||||||
const widgets = node?.widgets ?? [];
|
return findComboWidget(node, "ckpt_name");
|
||||||
return widgets.find((widget) =>
|
}
|
||||||
widget?.name === "ckpt_name" &&
|
|
||||||
Array.isArray(widget?.options?.values)
|
function findStartCheckpointWidget(node) {
|
||||||
);
|
return findComboWidget(node, "start_checkpoint");
|
||||||
}
|
}
|
||||||
|
|
||||||
function outputNames(node) {
|
function outputNames(node) {
|
||||||
@@ -47,7 +59,23 @@ function hasLoaderOutputs(node) {
|
|||||||
return names.includes("model") && names.includes("clip") && names.includes("vae");
|
return names.includes("model") && names.includes("clip") && names.includes("vae");
|
||||||
}
|
}
|
||||||
|
|
||||||
function shouldTargetNode(node) {
|
function isCyclerNode(node) {
|
||||||
|
const typeName = getNodeTypeName(node);
|
||||||
|
if (typeName === "CheckpointNameCycler") {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const names = outputNames(node);
|
||||||
|
return (
|
||||||
|
names.includes("ckpt_name") &&
|
||||||
|
names.includes("ckpt_name_str") &&
|
||||||
|
names.includes("ckpt_name_safe") &&
|
||||||
|
names.includes("index") &&
|
||||||
|
names.includes("count")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function shouldTargetCheckpointWidgetNode(node) {
|
||||||
if (!node || isRefresherNode(node)) {
|
if (!node || isRefresherNode(node)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -79,7 +107,11 @@ function shouldPatchFutureNodeType(nodeData) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return name.includes("CheckpointNameSelector") || name === "CheckpointLoaderSimple";
|
return (
|
||||||
|
name.includes("CheckpointNameSelector") ||
|
||||||
|
name === "CheckpointLoaderSimple" ||
|
||||||
|
name === "CheckpointNameCycler"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function chooseReplacement(oldValues, newValues, currentValue) {
|
function chooseReplacement(oldValues, newValues, currentValue) {
|
||||||
@@ -94,7 +126,6 @@ function chooseReplacement(oldValues, newValues, currentValue) {
|
|||||||
const oldIndex = Array.isArray(oldValues) ? oldValues.indexOf(currentValue) : -1;
|
const oldIndex = Array.isArray(oldValues) ? oldValues.indexOf(currentValue) : -1;
|
||||||
|
|
||||||
if (oldIndex >= 0) {
|
if (oldIndex >= 0) {
|
||||||
// Prefer the next surviving item from the old list.
|
|
||||||
for (let index = oldIndex + 1; index < oldValues.length; index++) {
|
for (let index = oldIndex + 1; index < oldValues.length; index++) {
|
||||||
const candidate = oldValues[index];
|
const candidate = oldValues[index];
|
||||||
if (newValues.includes(candidate)) {
|
if (newValues.includes(candidate)) {
|
||||||
@@ -102,7 +133,6 @@ function chooseReplacement(oldValues, newValues, currentValue) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the deleted item was at the end, choose the previous survivor.
|
|
||||||
for (let index = oldIndex - 1; index >= 0; index--) {
|
for (let index = oldIndex - 1; index >= 0; index--) {
|
||||||
const candidate = oldValues[index];
|
const candidate = oldValues[index];
|
||||||
if (newValues.includes(candidate)) {
|
if (newValues.includes(candidate)) {
|
||||||
@@ -110,7 +140,6 @@ function chooseReplacement(oldValues, newValues, currentValue) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Last fallback: same numeric position in the new list if possible.
|
|
||||||
return newValues[Math.min(oldIndex, newValues.length - 1)] ?? newValues[0];
|
return newValues[Math.min(oldIndex, newValues.length - 1)] ?? newValues[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -164,25 +193,7 @@ function patchCheckpointSlotTypes(node, checkpoints) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function applyCheckpointListToNode(node, checkpoints) {
|
function updateComboWidget(node, widget, checkpoints) {
|
||||||
if (!shouldTargetNode(node)) {
|
|
||||||
return {
|
|
||||||
matched: false,
|
|
||||||
changed: false,
|
|
||||||
valueChanged: false,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const widget = findCheckpointWidget(node);
|
|
||||||
if (!widget) {
|
|
||||||
return {
|
|
||||||
matched: true,
|
|
||||||
changed: false,
|
|
||||||
valueChanged: false,
|
|
||||||
reason: "checkpoint widget not found",
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!widget.options) {
|
if (!widget.options) {
|
||||||
widget.options = {};
|
widget.options = {};
|
||||||
}
|
}
|
||||||
@@ -197,7 +208,6 @@ function applyCheckpointListToNode(node, checkpoints) {
|
|||||||
|
|
||||||
widget.options.values = newValues;
|
widget.options.values = newValues;
|
||||||
widget.value = newValue;
|
widget.value = newValue;
|
||||||
patchCheckpointSlotTypes(node, newValues);
|
|
||||||
|
|
||||||
const valuesChanged = !arraysEqual(oldValues, newValues);
|
const valuesChanged = !arraysEqual(oldValues, newValues);
|
||||||
const valueChanged = oldValue !== newValue;
|
const valueChanged = oldValue !== newValue;
|
||||||
@@ -215,7 +225,6 @@ function applyCheckpointListToNode(node, checkpoints) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
matched: true,
|
|
||||||
changed: valuesChanged || valueChanged,
|
changed: valuesChanged || valueChanged,
|
||||||
valueChanged,
|
valueChanged,
|
||||||
oldValue,
|
oldValue,
|
||||||
@@ -223,6 +232,64 @@ function applyCheckpointListToNode(node, checkpoints) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function applyCheckpointListToWidgetNode(node, checkpoints) {
|
||||||
|
if (!shouldTargetCheckpointWidgetNode(node)) {
|
||||||
|
return {
|
||||||
|
matched: false,
|
||||||
|
changed: false,
|
||||||
|
valueChanged: false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const widget = findCheckpointWidget(node);
|
||||||
|
if (!widget) {
|
||||||
|
return {
|
||||||
|
matched: true,
|
||||||
|
changed: false,
|
||||||
|
valueChanged: false,
|
||||||
|
reason: "checkpoint widget not found",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = updateComboWidget(node, widget, checkpoints);
|
||||||
|
patchCheckpointSlotTypes(node, checkpoints);
|
||||||
|
|
||||||
|
return {
|
||||||
|
matched: true,
|
||||||
|
...result,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function applyCheckpointListToCyclerNode(node, checkpoints) {
|
||||||
|
if (!isCyclerNode(node)) {
|
||||||
|
return {
|
||||||
|
matched: false,
|
||||||
|
changed: false,
|
||||||
|
valueChanged: false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const widget = findStartCheckpointWidget(node);
|
||||||
|
if (!widget) {
|
||||||
|
patchCheckpointSlotTypes(node, checkpoints);
|
||||||
|
node.setDirtyCanvas?.(true, true);
|
||||||
|
return {
|
||||||
|
matched: true,
|
||||||
|
changed: false,
|
||||||
|
valueChanged: false,
|
||||||
|
reason: "start_checkpoint widget not found",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = updateComboWidget(node, widget, checkpoints);
|
||||||
|
patchCheckpointSlotTypes(node, checkpoints);
|
||||||
|
|
||||||
|
return {
|
||||||
|
matched: true,
|
||||||
|
...result,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
async function fetchCheckpointList() {
|
async function fetchCheckpointList() {
|
||||||
const response = await api.fetchApi("/checkpoint_widget_refresh/checkpoints", {
|
const response = await api.fetchApi("/checkpoint_widget_refresh/checkpoints", {
|
||||||
cache: "no-store",
|
cache: "no-store",
|
||||||
@@ -240,6 +307,36 @@ async function fetchCheckpointList() {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function resetCyclersViaApi() {
|
||||||
|
try {
|
||||||
|
const response = await api.fetchApi("/checkpoint_name_cycler/reset", {
|
||||||
|
method: "POST",
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
return {
|
||||||
|
ok: false,
|
||||||
|
status: response.status,
|
||||||
|
resetCount: 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const payload = await response.json();
|
||||||
|
return {
|
||||||
|
ok: Boolean(payload.ok),
|
||||||
|
status: response.status,
|
||||||
|
resetCount: payload.reset_count ?? 0,
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
// Cycler may not be installed. That is fine.
|
||||||
|
return {
|
||||||
|
ok: false,
|
||||||
|
error,
|
||||||
|
resetCount: 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function updatePanelTitle(panelNode, text) {
|
function updatePanelTitle(panelNode, text) {
|
||||||
if (!panelNode) {
|
if (!panelNode) {
|
||||||
return;
|
return;
|
||||||
@@ -257,35 +354,51 @@ async function refreshCheckpointWidgets(panelNode = null) {
|
|||||||
const checkpoints = payload.checkpoints;
|
const checkpoints = payload.checkpoints;
|
||||||
lastCheckpointList = checkpoints;
|
lastCheckpointList = checkpoints;
|
||||||
|
|
||||||
let matched = 0;
|
let widgetMatched = 0;
|
||||||
let changed = 0;
|
let widgetChanged = 0;
|
||||||
let valueChanged = 0;
|
let valueChanged = 0;
|
||||||
|
let cyclerMatched = 0;
|
||||||
|
let cyclerChanged = 0;
|
||||||
|
let cyclerValueChanged = 0;
|
||||||
|
|
||||||
for (const node of app.graph?._nodes ?? []) {
|
for (const node of app.graph?._nodes ?? []) {
|
||||||
const result = applyCheckpointListToNode(node, checkpoints);
|
const widgetResult = applyCheckpointListToWidgetNode(node, checkpoints);
|
||||||
if (!result.matched) {
|
if (widgetResult.matched) {
|
||||||
continue;
|
widgetMatched += 1;
|
||||||
|
if (widgetResult.changed) {
|
||||||
|
widgetChanged += 1;
|
||||||
|
}
|
||||||
|
if (widgetResult.valueChanged) {
|
||||||
|
valueChanged += 1;
|
||||||
|
console.log(
|
||||||
|
`[CheckpointWidgetRefresh] ${getNodeTypeName(node)} #${node.id}: ` +
|
||||||
|
`${widgetResult.oldValue} -> ${widgetResult.newValue}`
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
matched += 1;
|
const cyclerResult = applyCheckpointListToCyclerNode(node, checkpoints);
|
||||||
if (result.changed) {
|
if (cyclerResult.matched) {
|
||||||
changed += 1;
|
cyclerMatched += 1;
|
||||||
}
|
if (cyclerResult.changed) {
|
||||||
if (result.valueChanged) {
|
cyclerChanged += 1;
|
||||||
valueChanged += 1;
|
}
|
||||||
console.log(
|
if (cyclerResult.valueChanged) {
|
||||||
`[CheckpointWidgetRefresh] ${getNodeTypeName(node)} #${node.id}: ` +
|
cyclerValueChanged += 1;
|
||||||
`${result.oldValue} -> ${result.newValue}`
|
}
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const title = `Updated ${changed}/${matched} ckpt widgets, ${checkpoints.length} ckpts`;
|
const resetResult = await resetCyclersViaApi();
|
||||||
|
const cyclerPart = cyclerMatched > 0 ? `, ${cyclerMatched} cyclers reset` : "";
|
||||||
|
const title = `Updated ${widgetChanged}/${widgetMatched} ckpt widgets${cyclerPart}, ${checkpoints.length} ckpts`;
|
||||||
updatePanelTitle(panelNode, title);
|
updatePanelTitle(panelNode, title);
|
||||||
|
|
||||||
console.log(
|
console.log(
|
||||||
`[CheckpointWidgetRefresh] ${title}. ` +
|
`[CheckpointWidgetRefresh] ${title}. ` +
|
||||||
`valueChanged=${valueChanged}, backend patched=${payload.patchedClassCount}`,
|
`valueChanged=${valueChanged}, cyclerChanged=${cyclerChanged}, ` +
|
||||||
|
`cyclerValueChanged=${cyclerValueChanged}, backend patched=${payload.patchedClassCount}, ` +
|
||||||
|
`cyclerResetOk=${resetResult.ok}, cyclerResetCount=${resetResult.resetCount}`,
|
||||||
payload.patchedClasses
|
payload.patchedClasses
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -333,7 +446,8 @@ function installFuturePatchHook(nodeType, nodeData) {
|
|||||||
|
|
||||||
if (lastCheckpointList) {
|
if (lastCheckpointList) {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
applyCheckpointListToNode(this, lastCheckpointList);
|
applyCheckpointListToWidgetNode(this, lastCheckpointList);
|
||||||
|
applyCheckpointListToCyclerNode(this, lastCheckpointList);
|
||||||
app.graph?.setDirtyCanvas?.(true, true);
|
app.graph?.setDirtyCanvas?.(true, true);
|
||||||
}, 0);
|
}, 0);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user