Compare commits
@@ -0,0 +1,60 @@
|
||||
"""PostToolUse hook: regenerate README.index.md / DEVLOG.index.md right after
|
||||
Claude Code edits README.md or DEVLOG.md, so graphify's excluded-doc index
|
||||
stand-ins (see .graphifyignore) never drift from the source files within a
|
||||
session. A git pre-commit hook covers edits made outside Claude Code.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
TARGETS = {"readme.md": "readme", "devlog.md": "devlog"}
|
||||
|
||||
|
||||
def main() -> None:
|
||||
try:
|
||||
payload = json.load(sys.stdin)
|
||||
except (json.JSONDecodeError, ValueError):
|
||||
return
|
||||
|
||||
if payload.get("tool_name") not in ("Edit", "Write"):
|
||||
return
|
||||
|
||||
file_path = payload.get("tool_input", {}).get("file_path", "")
|
||||
if not file_path:
|
||||
return
|
||||
|
||||
name = Path(file_path).name.lower()
|
||||
target = TARGETS.get(name)
|
||||
if target is None:
|
||||
return
|
||||
|
||||
project_dir = os.environ.get("CLAUDE_PROJECT_DIR") or str(Path(file_path).resolve().parent)
|
||||
script = Path(project_dir) / "tools" / "generate_doc_index.py"
|
||||
if not script.exists():
|
||||
return
|
||||
|
||||
result = subprocess.run(
|
||||
[sys.executable, str(script), target],
|
||||
cwd=project_dir,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=30,
|
||||
)
|
||||
if result.returncode == 0:
|
||||
print(json.dumps({"systemMessage": f"[doc-index] {result.stdout.strip()}"}))
|
||||
else:
|
||||
print(
|
||||
json.dumps(
|
||||
{"systemMessage": f"[doc-index] generate_doc_index.py {target} failed: {result.stderr.strip()}"}
|
||||
),
|
||||
file=sys.stderr,
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"hooks": {
|
||||
"PreToolUse": [
|
||||
{
|
||||
"matcher": "Bash|Grep",
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "C:/Users/statsu-11/.local/bin/graphify.EXE hook-guard search"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"matcher": "Read|Glob",
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "C:/Users/statsu-11/.local/bin/graphify.EXE hook-guard read"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"PostToolUse": [
|
||||
{
|
||||
"matcher": "Edit|Write",
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "python \"$CLAUDE_PROJECT_DIR/.claude/hooks/on_doc_edit.py\"",
|
||||
"timeout": 30
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
# graphify: keep graph.json/graphify-out/ out of Claude Code's automatic
|
||||
# context so re-running `graphify extract` doesn't churn the prompt cache
|
||||
# on every rebuild. These are still tracked by git (see .gitignore).
|
||||
graph.json
|
||||
graphify-out/
|
||||
@@ -0,0 +1,29 @@
|
||||
# ComfyUI-Workflow-Studio - Unsloth backend (AI TOOL tab / sidebar A tab)
|
||||
#
|
||||
# Unsloth Desktop requires an API key even for local access
|
||||
# (Settings -> API in the Unsloth app, shown only once when issued).
|
||||
#
|
||||
# Alternatively leave the key empty and turn on Keyless API access ->
|
||||
# "Chat and inference" in Unsloth Desktop's Settings -> API; requests are then
|
||||
# sent without a key. That setting also serves your private LAN, and keep
|
||||
# "Allow tools" OFF.
|
||||
#
|
||||
# 1. Copy this file to ".env" (same directory as this example file)
|
||||
# 2. Paste your key after the "=" below (do NOT add a leading #, or the
|
||||
# line becomes a comment and the key will not be loaded)
|
||||
# 3. Restart ComfyUI
|
||||
|
||||
UNSLOTH_API_KEY=
|
||||
|
||||
# ComfyUI-Workflow-Studio - Gallery Semantic Search (Gemini Embedding 2)
|
||||
# Get a key at https://aistudio.google.com (free tier available).
|
||||
# Same steps as above: copy to ".env", paste the key, restart ComfyUI.
|
||||
GEMINI_API_KEY=
|
||||
|
||||
# ComfyUI-Workflow-Studio - Partner API nodes in GenerateUI (Nano Banana, Kling, Seedream, ...)
|
||||
# A Comfy API key issued at https://platform.comfy.org (separate from the Gemini key above;
|
||||
# usage is billed as Comfy credits). With it set, GenerateUI queues prompts through the plugin
|
||||
# server, which adds the key to the request only when the workflow contains a partner API node.
|
||||
# Same steps as above: copy to ".env", paste the key, restart ComfyUI.
|
||||
|
||||
COMFY_API_KEY=
|
||||
@@ -0,0 +1,22 @@
|
||||
name: Publish to Comfy Registry
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- "pyproject.toml"
|
||||
|
||||
jobs:
|
||||
publish-node:
|
||||
name: Publish Custom Node to registry
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Publish Custom Node
|
||||
uses: Comfy-Org/publish-node-action@d2366e7abb6ab16f3bb03e3520ae25c8cf749bc9 # 1.0.1
|
||||
with:
|
||||
personal_access_token: ${{ secrets.REGISTRY_ACCESS_TOKEN }}
|
||||
@@ -5,3 +5,10 @@ __pycache__/
|
||||
.venv
|
||||
*.egg-info/
|
||||
data/
|
||||
|
||||
# graphify: local-only knowledge graph output, not shared with other clones
|
||||
graphify-out/
|
||||
|
||||
# Working-notes plan docs — local scratch, not meant to ship with the repo
|
||||
VIDEO_EDIT_TAB_PLAN.md
|
||||
QWEN_CHAT_INTEGRATION_PLAN.md
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
# Private/unpublished planning notes — never committed to git, must not leak
|
||||
# into the published graphify-out/ knowledge graph either.
|
||||
QWEN_CHAT_INTEGRATION_PLAN.md
|
||||
|
||||
# Too large for reliable local-Ollama semantic extraction (large chunks make the
|
||||
# model summarize in prose instead of emitting JSON, and time out on slower
|
||||
# models/hardware). README.index.md / DEVLOG.index.md are condensed stand-ins
|
||||
# that graphify extracts instead — regenerate them after editing the originals.
|
||||
README.md
|
||||
DEVLOG.md
|
||||
@@ -185,3 +185,43 @@ os.environ["HF_HOME"] = "D:\\hf_cache"
|
||||
5. `INPUT_TYPES` 変更時は `widgets_values` も同時更新
|
||||
6. 削除した依存への参照が残っていないか grep で確認
|
||||
7. ComfyUI完全再起動 → ワークフロー読み込み → エンドツーエンド実行確認
|
||||
|
||||
---
|
||||
|
||||
## リリース手順
|
||||
|
||||
コミット・プッシュ・GitHub リリース(`gh release create`)を行う際は、**必ず以下の順序**で実施する。
|
||||
|
||||
1. `pyproject.toml` の `version` を新バージョン番号に更新してステージングに含める
|
||||
2. `README.md` のバージョンバッジを更新(``)
|
||||
3. `DEVLOG.md` の先頭に変更詳細エントリを追加
|
||||
4. 上記すべてを同一コミットにまとめてプッシュ
|
||||
5. `gh release create vX.Y.Z` でリリースを作成(リリースノート本文に変更点を記載する — v0.3.90でREADME.mdのChangelogセクションは廃止したため、以後のバージョン履歴はGitHub Releaseのリリースノートのみで管理する)
|
||||
|
||||
`pyproject.toml` のバージョン変更が GitHub Actions のトリガー(`paths: pyproject.toml`)になっており、ComfyUI Registry への自動公開もここで行われる。バージョン更新を忘れると Registry に反映されない。
|
||||
|
||||
<!-- graphify運用は一時停止中(2026-08-23〜、ユーザー指示により凍結)。再開時はこのコメントブロックを解除すること。graphify-out/ 自体は削除しておらずそのまま残っている。
|
||||
|
||||
## graphify
|
||||
|
||||
This project has a knowledge graph at graphify-out/ with god nodes, community structure, and cross-file relationships.
|
||||
|
||||
Rules:
|
||||
- For codebase questions, first run `graphify query "<question>"` when graphify-out/graph.json exists. Use `graphify path "<A>" "<B>"` for relationships and `graphify explain "<concept>"` for focused concepts. These return a scoped subgraph, usually much smaller than GRAPH_REPORT.md or raw grep output.
|
||||
- If graphify-out/wiki/index.md exists, use it for broad navigation instead of raw source browsing.
|
||||
- Read graphify-out/GRAPH_REPORT.md only for broad architecture review or when query/path/explain do not surface enough context.
|
||||
- After modifying code, run `graphify update .` to keep the graph current (AST-only, no API cost).
|
||||
|
||||
### README.md / DEVLOG.md の索引ファイル
|
||||
|
||||
`README.md`/`DEVLOG.md`はサイズが大きすぎてローカルOllamaでの意味抽出が不安定になる(大きな塊を渡すとJSONではなく散文の要約を返す、または処理がタイムアウトする)ため、`.graphifyignore`でgraphifyの抽出対象から除外している。代わりに縮小版の`README.index.md`/`DEVLOG.index.md`を抽出対象にしている。
|
||||
|
||||
- 生成スクリプト: `python tools/generate_doc_index.py [readme|devlog|all]`
|
||||
- 自動化: `README.md`/`DEVLOG.md`を編集すると以下の2つのフックが自動でindexを再生成する
|
||||
- Claude Code PostToolUseフック(`.claude/hooks/on_doc_edit.py`)— Edit/Write直後に即時実行
|
||||
- git pre-commitフック(`.git/hooks/pre-commit`)— コミット時にstagedファイルを検知して再生成し、同じコミットに含める(他エディタでの編集にも対応)
|
||||
- 索引ファイルを手動で編集しない(次の生成で上書きされる)
|
||||
- 索引ファイル再生成後は`graphify update .`を実行してグラフに反映する
|
||||
|
||||
-->
|
||||
|
||||
|
||||
@@ -0,0 +1,216 @@
|
||||
# DEVLOG Index — ComfyUI-Workflow-Studio
|
||||
|
||||
Condensed version-by-version index of DEVLOG.md (each line: version + one-line summary of what changed and why). Full rationale, code details, and "How to apply" lessons live in the excluded DEVLOG.md itself; this index exists so graphify can extract a queryable semantic node per release without feeding the full log to the local Ollama model. Regenerate with `python tools/generate_doc_index.py devlog` whenever DEVLOG.md changes.
|
||||
|
||||
- **v0.9.6(2026-11-12)** — マニュアル v0.9.6版(ja/en)
|
||||
- **v0.9.5(2026-11-11)** — AI TOOL Chat: スキル v2(metadata・同梱スキルの版管理・プロンプトボタン)
|
||||
- **v0.9.4(2026-11-07)** — Gallery: 3Dモデル対応(GLB / glTF / VRM / PLY / SPZ)
|
||||
- **v0.9.3(2026-11-05)** — Image Edit: Drawツールのカラーパレット・ショートカット・スポイト(Comic Creator v1.67.0 から移植)
|
||||
- **v0.9.2(2026-11-03)** — Selectorイベントループ有効時に画像が壊れて届く不具合を修正
|
||||
- **v0.9.1(2026-11-03)** — TagSpace: 選んだタグだけを追加 / タグのカッコをエスケープして追加
|
||||
- **v0.9.0(2026-11-03)** — マニュアル(画像なし配布版)を v0.9.0 に改訂
|
||||
- **v0.8.14(2026-11-03)** — Fibo 2.0 Edit / FastH3 OmniRef / Pika-H3-Flex 対応(GenerateUI・Metadata・Videoタブ)
|
||||
- **v0.8.13(2026-10-27)** — Edit in Mask Editor One: 送信画像をノードへ永続化(Mask Editor One v0.1.12 対応)
|
||||
- **v0.8.12(2026-10-27)** — Comic Creator向け複数画像I2Iブリッジ + GenerateUI Inputタブ: Prompt/Image統合・Raw JSON折りたたみ
|
||||
- **v0.8.11(2026-10-26)** — Gallery: Send CC をレイアウト/Imageタブの2ボタンに分割
|
||||
- **v0.8.10(2026-10-23)** — Tagger: PixAI Tagger v1.0 対応
|
||||
- **v0.8.9(2026-10-20)** — Video: アセット登録ボタン / Editの音声変換 / ソースパネルのレイアウト
|
||||
- **v0.8.8(2026-10-19)** — MOSS-Image 対応(GenerateUI / Gallery / Metadata / Iタブ)
|
||||
- **v0.8.7(2026-10-16)** — Qwen Image 2.1 Turbo(ComfyUI公式テンプレート T2I / I2I)対応
|
||||
- **v0.8.6(2026-10-14)** — GenerateUI: パートナーAPIノード(Nano Banana 等)の実行に対応
|
||||
- **v0.8.5(2026-10-14)** — Metadata / I タブ: Gemini 系ノード(Nano Banana)の画像を読めるように
|
||||
- **v0.8.4(2026-10-14)** — ComfyUI v0.40.0 対応: ネイティブ LoRA スタックノード(`LoadLoraModel` / `LoadLoraTextEncoder`)
|
||||
- **v0.8.3(2026-10-13)** — GenerateUI: シードモード「Workflow」を追加(改善候補メモ 2-A)
|
||||
- **v0.8.2(2026-10-12)** — Gallery: セマンティック検索(Gemini Embedding 2 / EmbeddingGemma 2)
|
||||
- **v0.8.1(2026-10-11)** — バグ修正
|
||||
- **v0.8.0(2026-10-11)** — Gallery: 音声ファイル対応(wav / mp3 / ogg / m4a / flac / opus)
|
||||
- **v0.7.14(2026-10-09)** — Comic Creator連携: nanobananaタブの生成履歴をGallery/Metadataタブに表示
|
||||
- **v0.7.13(2026-10-06)** — VRAM調整(Ollama)— Comic Creatorから移植
|
||||
- **v0.7.12(2026-10-04)** — セキュリティ: バックエンド接続先をブラウザから任意指定できた問題(SSRF)を修正
|
||||
- **v0.7.11(2026-10-02)** — セキュリティ: CivitAI情報の説明文のHTML無害化(保存型XSS対策)
|
||||
- **v0.7.10(2026-10-02)** — Windows: ComfyUIが固まる問題の原因特定と対策(Selectorイベントループ)
|
||||
- **v0.7.9(2026-10-02)** — Models: CivitAIベースモデルからの自動バッジ作成
|
||||
- **v0.7.8(2026-10-01)** — Video Edit: マルチトラック化(ビデオ/オーバーレイ/テキスト/オーディオ)
|
||||
- **v0.7.7(2026-09-30)** — 意思決定モデル: Ollama 0.35+ バックエンド追加
|
||||
- **v0.7.6(2026-09-30)** — Settings: 意思決定モデル (Laya) の専用設定
|
||||
- **v0.7.5(2026-09-30)** — Ming Image ワークフロー対応(GenerateUI / Gallery・Metadata / サイドパネルIタブ)
|
||||
- **v0.7.4(2026-09-29)** — Video Edit: BGM/音声トラック合成(Phase 4)— 複数クリップ結合時の音声消失も解消
|
||||
- **v0.7.3(2026-09-24)** — GenerateUIタブにQwen Image 2.1(TextEncodeQwenImage21)対応を追加
|
||||
- **v0.7.2(2026-09-18)** — Workflowタブにソート機能追加(Date/Name 昇順降順)
|
||||
- **v0.7.1(2026-09-17)** — セキュリティ修正: Tagger VLM の Unsloth 経路でAPIキーがSSRFにより外部送信され得る不備を修正
|
||||
- **v0.7.0(2026-09-17)** — プレビュー枠の高さ固定・AssetサブタブをPlan/Editと並ぶ中央下部へ移設・トリムパネルにClipchamp風スクラバー追加・Frame保存のVideo Assets登録とAsset→Plan画像連携
|
||||
- **v0.6.3** — Send CCボタンでMP4動画をComic Creatorの新設「動画ツール」へ送れるように対応
|
||||
- **v0.6.2** — Image Editタブにペンタブレット筆圧対応とFillツール(バケツ塗りつぶし)を追加
|
||||
- **v0.6.1** — Galleryタブの検索が「読み込み中」のまま止まりクリアでも中断できない不具合、および50枚程度のフォルダでも数秒〜十数秒かかる不具合を修正
|
||||
- **v0.6.0** — Gallery/Image Edit両タブにPSD(Photoshop)対応を追加 — 複数画像の一括PSD書き出し、レイヤー保存/読み込み、Gallery表示、Image Editのレイヤーパネル改善
|
||||
- **v0.5.8** — Tagger DBタブに一括削除機能を追加(外部コントリビューターPRのレビュー・検証・修正・マージ)
|
||||
- **v0.5.7** — 設定エクスポート/フルバックアップのドキュメント修正: v0.5.5のVideo Plan機能追加分の言及漏れ
|
||||
- **v0.5.6** — バグ修正: WD Taggerで不正確なタグが生成される問題を修正(GitHub Issue #1)
|
||||
- **v0.5.5** — Videoタブ全面刷新: Plan/Asset/Editバッチ生成 + Projectサブタブ + プレビュー2ペイン化 + Video Assets/Video Temp運用整理 + Galleryメタデータ消失バグ根本修正
|
||||
- **v0.5.4** — 機能追加: Video/GenerateUIタブのLTX-2.5・Wan2.2対応拡大 + AI Assistant設定のUnsloth対応・独立モーダル化・モデルアンロード機能
|
||||
- **v0.5.3** — バグ修正: Labタブのワークフロー切替時に前の内容が残留 + Galleryタブの読み込み高速化・root自動展開 + READMEスクリーンショット刷新
|
||||
- **v0.5.2** — 機能追加: GenerateUI/Labタブの動画ワークフロー対応 + VideoタブにFrame抽出/GIF変換機能 + データ管理監査とZIPフルバックアップ + Send to LI node統一
|
||||
- **v0.5.1** — 機能追加: mp4動画の埋め込みメタデータ対応(Gallery Prompt/JSON・Metadataサブタブ・サイドパネルIタブ)+ Gallery Infoタブに寸法/再生時間表示 + MiniMax H3等オールインワン動画ノードのプロンプト抽出バグ修正
|
||||
- **v0.5.0** — 機能追加: mp4動画Gallery対応 + Videoタブ新設(MiniMax H3専用) + バグ修正: Galleryのタグ/メモが再起動後に消える
|
||||
- **v0.4.8** — 機能追加: LabタブにPromptグループ一括適用+キーフレーム並べ替え + バグ修正: デフォルトワークフローの上書き保存が反映されない + Styleテーブルの「このファイルへ追加」対応
|
||||
- **v0.4.7** — 機能追加: Prompt Tab内部リファクタ + Gallery Promptタブ新設 + Send to Canvas改善 + Presetsソート
|
||||
- **v0.4.6** — 機能追加: MetadataタブをGalleryタブへ統合 + Promptタブに一覧編集可能なTable表示を新設
|
||||
- **v0.4.5** — 調査: トップバー保存ワークフローのRMBG不具合報告(原因なし) + バグ修正: LabタブModel列の無意味な空キーフレーム表示を解消
|
||||
- **v0.4.4** — 機能追加: Lab/GenerateUI ModelタブへLoRAバイパス機能 + AI TOOL Chatの画像生成パラメータ拡張
|
||||
- **v0.4.3** — バグ修正: 共有モーダルのお気に入り☆/リネームがLabモーダルへ残留 + Lab Model列の+/-をCheckpoint/LoRA/VAEで完全独立化
|
||||
- **v0.4.2** — 機能追加: Lab「Model」列統合(Checkpoint / LoRA Single / VAE)+ フィールド単位継承 + C/L/V表示切替
|
||||
- **v0.4.1** — UX改善: Mask Editor One連携ボタンを「選択中ノード優先」方式に再設計
|
||||
- **v0.4.0** — リファクタリング: image-edit-tab.js / models-tab.js の低凝集度モジュール分割
|
||||
- **v0.3.99** — 機能追加: AI TOOLタブ + サイドパネルAタブにUnslothバックエンド追加(APIキーは.env管理、SSRF脆弱性修正、reasoning_content対応)
|
||||
- **v0.3.98** — 機能追加・バグ修正: AI TOOL翻訳の信頼性向上 + GenerateUI Modelタブ再構成(ハイライト色・折りたたみ・並び替え)+ Thinking mode/Max tokens設定
|
||||
- **v0.3.97** — 機能追加・バグ修正: KREA-2ワークフロー対応 + Labタブ拡張(Clear/Get from Previous/Bypass/ライブ反映)+ Input Imageプレースホルダ機能
|
||||
- **v0.3.96** — バグ修正: カタログ作成バッチが特定件数で無言停止する問題の修正 + Style Catalog/Promptタブ機能拡張
|
||||
- **v0.3.95** — 機能追加: Style/Prompt→ImagePrompt改名 + Style_Catalogギャラリー新設 + GenerateUI「カタログ作成」機能
|
||||
- **v0.3.94** — 機能追加: Gallery タブのサブタブ化 + Style/Prompt ギャラリー新設(視覚的プロンプトビルダー)
|
||||
- **v0.3.93** — バグ修正・機能改善: Labタブ VAEキーフレーム不発バグの修正+Style適用UI刷新+Plan JSONスクロール同期修正+キーフレーム個別削除+Batch数超過警告+ワイルドカード対応+Save index image デフォルトON
|
||||
- **v0.3.92** — バグ修正: CLIPTextEncodeEditPlus使用ワークフローがGenerateUI経由だと直接実行と異なる画像になる問題(根本原因はconvertUiToApiのForceInput 未考慮バグ)+LoRA Stack機能の改善一式
|
||||
- **v0.3.91** — 機能拡張: Labインデックス画像にPlanメタデータをPNG埋め込み+README構成整理(Changelogセクション廃止)
|
||||
- **v0.3.90** — 機能拡張: Labタブの進化(ワークフロー呼び出し・T2I対応・Run時インデックス画像Output保存+Eagle連携・プラン接頭辞)+Galleryタブのルート表示簡略化
|
||||
- **v0.3.89** — バグ修正: v0.3.88で追加したLab機能への実動作確認フィードバック3件を反映
|
||||
- **v0.3.88** — 機能拡張: Labタブ Promptセルにスタイル適用・画像/GenerateUIからのプロンプト取得、Checkpoint/VAEフィルター、Plan JSONサブタブを追加
|
||||
- **v0.3.87** — 追加機能: GenerateUIタブに実験的な「Lab」サブタブを追加(I2Iバッチ生成・キーフレーム方式)
|
||||
- **v0.3.86** — バグ修正: 画像を一括生成(I2I)等の連続実行で "GalleryMetadataStore: save error: dictionary changed size during iteration" が発生
|
||||
- **v0.3.85** — 機能拡張: Generate UI連携ブリッジ(T2I)にデフォルトワークフロー・Negativeプロンプト対応を追加
|
||||
- **v0.3.84** — バグ修正: ernie_t2i.jsonをGenerateUIタブで実行すると "Prompt outputs failed validation" エラー
|
||||
- **v0.3.83** — 追加機能: Ernie Image(ernie-image / ernie-image-turbo)ワークフロー対応 + プロンプトがリンク経由のノードから供給されるパターンの修正
|
||||
- **v0.3.82** — バグ修正: MetadataタブとサイドパネルIタブでLongCat/Boogu/HiDream E1/FireRed等のプロンプトが表示されない不具合
|
||||
- **v0.3.81** — 追加機能: GenerateUIタブでFlux.2 Klein / LongCat / Boogu / HiDream E1 / FireRedのImage Editワークフローに対応
|
||||
- **v0.3.80** — 追加機能: Comic Creator「半自動マンガ作成」向けブリッジ(LLMプロンプト下書き・バッチ画像生成)
|
||||
- **v0.3.79** — 追加機能: サイドパネル(Workflow Studio Library)IタブのMage-Flow等サブグラフワークフロー対応
|
||||
- **v0.3.78** — 追加機能: Eagle自動保存のSVG対応
|
||||
- **v0.3.76** — 追加機能: Comic Creator向けI2I実行ブリッジ`_wfmReceiveI2IRunRequest`
|
||||
- **v0.3.77** — 追加機能: GalleryタブでSVGファイルの表示・管理に対応
|
||||
- **v0.3.75** — Lemonadeバックエンド追加(3つ目のAIバックエンド)
|
||||
- **v0.3.74** — AI TOOL Chatペインの画像添付対応 + I2I連携
|
||||
- **v0.3.73** — AI TOOL Chatペインからの対話式画像生成(Tool Calling)+ Checkpoint関連の安全策
|
||||
- **v0.3.72** — Comic Creator連携用の外部Inpaintエントリポイントを追加
|
||||
- **v0.3.71** — Inpaint機能の追加(GenerateUI Imageタブ + Image Edit「Inpaint」タブ)
|
||||
- **v0.3.70** — Workflow AI要約: Ollama 404エラー修正
|
||||
- **v0.3.69** — Gallery → ComfyUI Comic Creator 連携(Send CC ボタン)
|
||||
- **v0.3.68** — MASK EDITOR ONE セクション常時表示化
|
||||
- **v0.3.67** — Alt+Click Apply & Generate
|
||||
- **計画: Image Edit 拡張 — ABRブラシ連携 + Mask Editor One 統合** — フェーズ1: Draw ツール — ABRブラシ対応
|
||||
- **2026-06-29: v0.3.66 — Mask ツール 5サブツール追加(Color / Alpha / Text / Vector / Shape)・Support リンク追加** — 概要
|
||||
- **2026-06-29: v0.3.65 — Mask Editor One 連携修正・トップバーアイコン修正・Mask ABRブラシ対応** — 概要
|
||||
- **2026-06-28: v0.3.64 — Image Edit マスク Add/Subtract・BiRefNet BG Remove・SAM3 セグメンテーション・ブラシカーソルバグ修正** — 概要
|
||||
- **2026-06-28: v0.3.63 — ノードタブ複数選択・全タブフィルタークリア・検索Xボタン** — 概要
|
||||
- **2026-06-27: WFS_PromptText の GenerateUI 対応・ドロップ時 title 固定** — 概要
|
||||
- **2026-06-27: v0.3.62 — Send GenUI Image ボタン追加・tagger_settings.json バグ修正・README 更新** — 概要
|
||||
- **2026-06-27: データ管理バグ修正 — tagger_settings.json をエクスポート対象に追加** — 概要
|
||||
- **2026-06-27: v0.3.61 — G'MIC バグ修正・セキュリティ・Draw/Mask ブラシ操作性改善** — 概要
|
||||
- **2026-06-27: v0.3.60 — Image Edit Filter Tool (G'MIC-Qt 連携) 実装** — 概要
|
||||
- **2026-06-27: v0.3.59 — Image Edit Mask Tool 実装・Draw/Mask 描画バグ修正・クリッピング保存対応** — 概要
|
||||
- **2026-06-27: v0.3.58 — GenerateUI Model タブ GGUF対応拡張(Diffusion Model / Text Encoder)** — 概要
|
||||
- **2026-06-26: v0.3.57 — Image Edit Blur Tool / BG Remove Tool 追加** — 概要
|
||||
- **2026-06-26: v0.3.56 — Style機能追加(GenerateUI ツールバー & Batchタブ)** — 概要
|
||||
- **2026-06-25: v0.3.55 — グループ機能バグ修正(全タブ)** — 根本原因(データ消失): パス区切り文字の不一致
|
||||
- **2026-06-25: v0.3.54 — Image Edit Shape ツール追加・Models タブ overlay バグ修正** — Image Edit Tab — Shape ツール(□ / S キー)
|
||||
- **2026-06-25: v0.3.53 — Image Edit Tab 実装・レイヤーロック・ギャラリー保存** — Image Edit Tab(新規タブ)
|
||||
- **2026-06-25: GenUI設定タブ LATENT IMAGE にプリセット機能を追加** — 変更内容
|
||||
- **2026-06-24: GenUI ModelでLoRA適用後、Modelサブタブ再表示時に値がリセットされるバグ修正** — 問題
|
||||
- **2026-06-24: v0.3.51 — Embedding GenUI PP/NP対応 + GenerateUIプロンプトタブEmbeddingセレクタ追加** — 変更内容
|
||||
- **2026-06-24: v0.3.51 — GenerateUIタブ Hypernetwork対応 + ModelsタブGenUI Modelボタン追加** — 変更内容
|
||||
- **2026-06-24: v0.3.51 — Hypernetwork/Embeddingモデル未表示バグ修正** — 原因
|
||||
- **2026-06-24: v0.3.51 — ModelsタブサイドパネルにGenUI Modelボタン追加** — 変更内容
|
||||
- **2026-06-22: v0.3.50 — ギャラリータブ プロンプト検索負荷改善(バックグラウンドインデックス)** — 問題
|
||||
- **2026-06-22: v0.3.49 — 生成UIタブ A1111風ワイルドカード展開・ギャラリータブ バグ修正2件** — 生成UIタブ — A1111風SPAサイドワイルドカード展開
|
||||
- **2026-06-22: v0.3.48 — ギャラリータブ 画像ダウンロード・一括エクスポート機能追加** — 詳細パネルの画像プレビューにダウンロード機能を追加
|
||||
- **2026-06-22: v0.3.47 — モデルタブ ファイル移動後グループ状態修正** — モデル移動後のグループ状態不整合を修正
|
||||
- **2026-06-21: v0.3.46 — プロンプトタブ AI Assistant LM Studio対応・設定タブ AI Assistant設定に変更** — 設定タブ「AI Assistant設定(プロンプトタブ)」
|
||||
- **2026-06-21: v0.3.45 — グループ孤立エントリ自動クリーンアップ・Galleryタブ Shift+クリック範囲選択** — グループ孤立エントリ自動クリーンアップ
|
||||
- **2026-06-21: v0.3.44 — Galleryタブ高速化・比較モード・バルク強化・バルクバーUI整理** — フェーズ2-A: サーバーサイドサムネイル生成
|
||||
- **2026-06-21: ヘルプタブ改善 — Gallery mode 多言語対応・フォント拡大・検索機能追加** — Gallery mode の多言語対応
|
||||
- **2026-06-21: Send to Canvas — window.opener経由のキャンバス直接ロード対応**
|
||||
- **2026-06-20: API形式ワークフローのキャンバス読み込み修正・画像メタデータ埋め込み修正** — API形式ワークフローをキャンバスへドラッグすると空になる問題を修正
|
||||
- **2026-06-20: セキュリティ修正(XSS・パスバリデーション)** — 修正内容
|
||||
- **2026-06-20: WFS_GalleryFeeder — ComfyUI キャンバス上コントロール追加** — 新規ファイル(`web/comfyui/gallery_feeder_extension.js`)
|
||||
- **2026-06-20: __Feeder__ グループ保護 + サムネイル F ボタン + seed バグ修正** — `__Feeder__` グループの予約済み保護
|
||||
- **2026-06-20: Gallery Feeder 機能追加(WFS_GalleryFeeder ノード)** — 概要
|
||||
- **2026-06-19: Generate UI — ImpactWildcardEncode/Processor プロンプト検出バグ修正(v0.3.41)** — 修正内容(`static/js/comfyui-workflow.js`)
|
||||
- **2026-06-19: AI TOOL タブ Chat ペイン・ワイルドカード生成追加(v0.3.40)** — Chat ペイン(`templates/index.html`, `static/css/main.css`, `static/js/ai-tab.js`, `web/comfyui/node_sets_menu.js`)
|
||||
- **2026-06-18: Send to Canvas機能追加(ワークフロータブ・ギャラリータブ→LibraryタイトルDnD)** — ワークフロータブ — Send to Canvas(`static/js/workflow-tab.js`, `static/js/app.js`, `templates/index.html`)
|
||||
- **2026-06-15: TaggerシングルGenUI:Pボタン追加+生成UIのZITワークフロープロンプト解析修正** — TaggerシングルGenUI:Pボタン(`templates/index.html`, `static/js/tagger-tab.js`, `static/js/i18n.js`)
|
||||
- **2026-06-15: Taggerバッチ.txt出力追加+Galleryタグ保存バグ修正** — Taggerバッチ.txt出力(`templates/index.html`, `static/js/tagger-tab.js`, `static/js/i18n.js`, `py/routes/tagger_routes.py`, `py/services/tagger_service.py`)
|
||||
- **2026-06-15: Taggerタブ新規実装+ギャラリー詳細パネルUI改善+パストラバーサル修正** — Taggerタブ新規実装
|
||||
- **2026-06-15: 全選択ボタン追加+ギャラリーバルクバーi18n対応** — 変更内容
|
||||
- **2026-06-10: v0.3.36 — コードレビュー修正+リファクタリング+README刷新** — コードレビュー修正(v0.3.35の不具合10件)
|
||||
- **2026-06-10: v0.3.35 — テーブルソート・Load GenUI・ワークフロー保存** — 変更内容
|
||||
- **2026-06-09: v0.3.34 — Modelsタブ テーブルビュー強化・バルク操作改善** — 変更内容
|
||||
- **2026-06-09: v0.3.33 — LoRAペイン・ワークフロー解析バグ修正** — 変更内容
|
||||
- **2026-06-08: v0.3.32 — Lora Loader (LoraManager) LoRA検出対応・ライブラリ機能拡張** — 変更内容
|
||||
- **2026-06-08: v0.3.31 — LoRAペイン Single/Stack タブ分割・GenUI Model LoRA対応強化** — 変更内容
|
||||
- **2026-06-08: v0.3.30 — LoRAスタック トリガーワードバグ修正・ヘルプ更新** — 変更内容
|
||||
- **2026-06-08: v0.3.29 — LoRAセクション統合・ヘルプタブサイドバー・UI細部改善** — 変更内容
|
||||
- **2026-06-08: 生成UIタブ 複数改善 — LoRA Stackトリガーワード連携・Reset Workflowボタン・Inputタブタブ化** — 変更内容
|
||||
- **2026-06-08: Feederタブ UI改善 — (root)自動選択・PREVIEWペイン右移動・RUN中プレビュー反映** — 変更内容
|
||||
- **2026-06-07: v0.3.28 — Batchタブ Sampler/Scheduler対応 + Modelsサムネイルバグ修正** — 概要
|
||||
- **2026-06-07: v0.3.27 — model-and-prompt-from-metadata カスタムノード対応 + README修正** — 概要
|
||||
- **2026-06-07: v0.3.26 — Stack LORA SYNTAX 表示修正 + 全体強度調整 UI** — 概要
|
||||
- **2026-06-07: v0.3.25 — Lora Loader (LoraManager) 対応 + Stack 有効無効切り替え** — 概要
|
||||
- **2026-06-06: v0.3.24 — Lora Stack 登録機能 + 生成UI Model タブ 3ペイン化** — 概要
|
||||
- **2026-06-05: v0.3.23 — バグ修正2件** — バグ修正
|
||||
- **2026-06-05: v0.3.22 — カードビュー廃止 + Batch タイプ切り替え UI + 4タイプバッチ生成** — 概要
|
||||
- **2026-06-05: (未リリース) — 生成UIタブ Batch 4タイプ対応(Lora/Prompt/Workflow グループ選択 + BATCH QUEUE 4列化)** — 概要
|
||||
- **2026-06-05: (未リリース) — Prompt・Workflow Batchグループ登録UI** — 概要
|
||||
- **2026-06-04: (未リリース) — モデルBatchグループ登録UI(サムネイル/カード/テーブル・フィルター・一括解除)** — 概要
|
||||
- **2026-06-04: (未リリース) — Batch予約グループ・Presets Save後リセット・グループフィルター種別絞り込み** — 概要
|
||||
- **2026-05-31: v0.3.21 — CivitAI ホスト設定・Sample サブタブ・URL 修正・ヘルプ i18n 整備** — 概要
|
||||
- **2026-05-31: v0.3.20 — CivitAI 詳細パネル強化(Type / Hash 表示・URL 修正・画像別タブ)** — 概要
|
||||
- **2026-05-31: v0.3.19 — CivitAI 連携強化(バッチ高速化・リトライ・APIキー・フィールド拡充)** — 概要
|
||||
- **2026-05-31: v0.3.18 — Batch タブ追加・Models 複数選択強化** — 概要
|
||||
- **2026-05-31: v0.3.17 patch — SSLコンテキスト セキュリティ強化** — 概要
|
||||
- **2026-05-30: v0.3.17 — SSL証明書エラー修正・Lora Manager対応** — 概要
|
||||
- **2026-05-20: v0.3.16 — CivitAIプレビューフォールバック表示** — 概要
|
||||
- **2026-05-20: v0.3.15 — サンプルワークフロー同梱・CivitAI自動プレビュー・Create Tagsオプション** — 概要
|
||||
- **2026-05-20: AI TOOL タブ 英語化(SPA・Libraryパネル)** — 概要
|
||||
- **2026-05-19: v0.3.14 — AI TOOL タブ 3ペイン化・RAW JSON 文字色カスタマイズ** — 概要
|
||||
- **2026-05-19: v0.3.13 — AI タブ(A)追加** — 概要
|
||||
- **2026-05-18: v0.3.12 リリース — README スクリーンショット刷新 / workflow_analyzer 拡張** — 概要
|
||||
- **2026-05-17: RAW JSON パネルに検索機能を追加** — 概要
|
||||
- **2026-05-17: v0.3.11 Metadata タブ対応ノードタイプ拡張 / Settings テキストサイズ UI 追加** — 概要
|
||||
- **2026-05-17: v0.3.10 Information タブ キャンバスドラッグ対応 / ノードタイプ拡張 / バグ修正** — 概要
|
||||
- **2026-05-16: v0.3.9 サイドパネル I タブ追加 / トップバーアイコン修正** — 概要
|
||||
- **2026-05-16: v0.3.8 Metadata タブ: data9 対応 / プロンプト判別不能テキスト** — 概要
|
||||
- **2026-05-15: v0.3.7 Metadata タブ: Flux2 / Qwen / Z-Image 対応** — 概要
|
||||
- **2026-05-15: v0.3.6 Metadata タブ追加** — 概要
|
||||
- **2026-05-09: v0.3.5 GenerateUI — Feeder サブタブ・ワークフロー解析精度向上** — 概要
|
||||
- **2026-04-29: v0.3.4 GenerateUI — Checkpoint Batch 刷新・Settings 横並びレイアウト・ヘルプ i18n 修正** — 概要
|
||||
- **2026-04-28: v0.3.3 Promptタブ — ワイルドカード支援パネル・Impact Packシンボリックリンク連携・サブディレクトリ対応・GenerateUI修正** — 概要
|
||||
- **2026-04-28: v0.3.2 生成UIタブ — Checkpoint Batch・Seed UIレイアウト修正** — 概要
|
||||
- **2026-04-27: v0.3.1 ギャラリー拡張(フォルダ/ファイル操作・ワークフロー保存)** — 概要
|
||||
- **2026-04-18: v0.3.0 モデルグループ表示改善(全タイプ横断・サイドパネル修正)** — 概要
|
||||
- **2026-04-18: v0.2.9 モデル有効/無効・複数選択・一括削除** — 概要
|
||||
- **2026-04-14: v0.2.8 データ保存先変更・エクスポート/インポート機能追加** — 概要
|
||||
- **2026-04-06: v0.2.6 UI改善・バッジ保存修正・フォルダフィルター追加** — 概要
|
||||
- **2026-04-04: v0.2.5 追加修正** — 概要
|
||||
- **2026-04-03: v0.2.5 サイドパネル Category/Package サブタブ・テーマ設定・Workflow修正** — 概要
|
||||
- **2026-03-29: v0.2.4 GenerateUIタブ レイアウト再設計** — 概要
|
||||
- **2026-03-29: v0.2.3 バッジ統一・GenUI Model・サイドパネルModels拡充** — 概要
|
||||
- **2026-03-28: v0.2.2 Modelsタブ・CivitAI連携** — 概要
|
||||
- **2026-03-27: テーマカスタマイズ機能・設定タブ改善** — 概要
|
||||
- **2026-03-26: トップバーボタンアイコン修正・Appモードバッジ調査** — 概要
|
||||
- **2026-03-25: v0.2.0 プロンプトプリセット機能・Workflow Studio Library** — 概要
|
||||
- **2026-03-24: v0.1.9 サイドパネルUI改善・保存ダイアログ・バグ修正** — 概要
|
||||
- **2026-03-24: v0.1.8 WF & Node Library サイドパネル拡張** — 概要
|
||||
- **2026-03-23: v0.1.7 Nodes タブ追加** — 概要
|
||||
- **2026-03-23: v0.1.6 パストラバーサル脆弱性修正** — 概要
|
||||
- **2026-03-22: v0.1.5 テーマシステム追加** — 概要
|
||||
- **2026-03-22: v0.1.4 App形式対応・プリセットコピー・分析バグ修正** — 概要
|
||||
- **2026-03-21: v0.1.3 ヘルプ&サポートタブ追加** — 概要
|
||||
- **2026-03-19: v0.1.2 リリース** — 概要
|
||||
- **2026-03-19: v0.1.1 リリース** — 概要
|
||||
- **2026-03-18: プロジェクトリネーム & アイコン適用** — 概要
|
||||
- **2026-03-18: デフォルトビュー設定追加** — 概要
|
||||
- **2026-03-18: MarkdownNote表示専用ノード除外** — 概要
|
||||
- **2026-03-18: サブグラフワークフロー対応 & 変換精度修正** — 概要
|
||||
- **2026-03-18: Raw JSON同期修正** — 概要
|
||||
- **プロジェクト構成 (現在)**
|
||||
- **2026-03-18: JSONシンタックスハイライト** — 概要
|
||||
- **2026-03-18: プロンプトタブ 中国語↔英語翻訳追加** — 概要
|
||||
- **2026-03-18: v0.1.0 リリース** — 概要
|
||||
- **2026-04-13: Gallery タブ追加 & 全タブ Group UI 統一** — 概要
|
||||
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2026 ketle-man
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -0,0 +1,285 @@
|
||||
# README Index — ComfyUI-Workflow-Studio
|
||||
|
||||
Condensed index of README.md: intro summary, feature names per tab (full descriptions live in the excluded README.md), and the installation/usage/requirements/project-structure sections verbatim. Exists so graphify can extract this without feeding the full README (with its screenshot table) to the local Ollama model. Regenerate with `python tools/generate_doc_index.py readme` whenever README.md changes.
|
||||
|
||||
# ComfyUI-Workflow-Studio
|
||||
|
||||
A comprehensive workflow, asset management, and generation UI plugin for [ComfyUI](https://github.com/comfyanonymous/ComfyUI).
|
||||
|
||||
**📁 Management** — organize all your assets in one studio
|
||||
|
||||
- Workflow, model, image, and prompt management
|
||||
- AI-powered prompt writing assistance, translation, and tag generation
|
||||
- File drop & Gallery-linked metadata viewing — inspect and reuse generation settings instantly
|
||||
- Semantic image search in the Gallery — find images by describing them, or list images similar to a selected one
|
||||
|
||||
**⚡ GenerateUI** — a productivity-focused generation tab connected to every other tab
|
||||
|
||||
- Batch generation across models, samplers, prompts, and workflows
|
||||
- Image Feeder for continuous folder-based generation
|
||||
- Lab: experimental I2I batch generation with independent per-iteration keyframes for Model (Checkpoint/LoRA Single/VAE)/Prompt/KSampler
|
||||
|
||||
**📚 Workflow Studio Library** — a multi-function side panel for smooth ComfyUI integration
|
||||
|
||||
- Drag & drop models, nodes, prompts, and workflows straight onto the canvas
|
||||
- **Send to Canvas**: click "Send to Canvas" (Workflow tab) or "Copy & Send Canvas" (Gallery tab) to send the workflow directly to the ComfyUI canvas — UI and API formats both supported
|
||||
- View metadata from images / JSON, then drop the detected models and prompts onto the canvas
|
||||
- Built-in AI tools (translation and more)
|
||||
|
||||

|
||||

|
||||
|
||||
## Features (tab -> feature names)
|
||||
|
||||
### Workflow Tab
|
||||
Thumbnail / Table views, Thumbnail side panel, Badge filtering, Search, Side panel tabs, Badge management, AI summary, Import / Export, Side panel toolbar buttons, Default view setting, Search clear (✕), Clear all filters (✕ Clear), Sort, GenerateUI Check
|
||||
|
||||
### Canvas Snapshot (v0.1.2)
|
||||
One-click capture, Auto-save as thumbnail, Embedded workflow metadata, Auto-import
|
||||
|
||||
### GenerateUI Tab (v0.3.5)
|
||||
6-tab layout, Save button, Input tab, Multi-image I2I for Comic Creator, Model tab, Settings tab, Always-visible Raw JSON, Bypass/Mute node handling, One-click generation, Seed control, Style selector, Create Catalog / Catalog buttons, Batch type selector, Batch tab, UI-to-API conversion, Video workflow support, Eagle integration, Qwen Image 2.1 support, Ming Image support, P-H3 Image support, MiniMax-H3-Image support
|
||||
|
||||
### Feeder subtab (v0.3.5 / v0.3.42)
|
||||
ImageFeeder node control, Image library, Selection management, Presets, Continuous Run loop, Index sync, Seed, WFS_GalleryFeeder node, Node & group selector, Image grid, After Gen modes, Run / Stop controls
|
||||
|
||||
### Lab subtab (v0.3.87 – v0.9.5)
|
||||
Setting / Results / Plan JSON sub-panels, Per-column keyframes, Model column — Checkpoint / LoRA Single / VAE, Empty state when no matching node exists, Wildcards, Prompt cell extras, Keyframe #1 live-reflect, Bypass checkbox, LoRA node bypass & prompt injection, T2I workflow support, Use generated image for next, Workflow recall, Plan files, Plan Load, Plan JSON tab, Save index image to Output on Run, Index images are self-contained plan files, Eagle integration, Select vs. edit, and keyframe reordering, PG — apply a Prompt tab preset group, Video workflow support, Use generated image for next, now video-aware, Plans from a story
|
||||
|
||||
### Prompt Tab
|
||||
3-column layout, AI chat assistant, Image attachment, Translation, Prompt presets, Preset Manager, Group management, Clipboard copy, GenUI Set, Wildcard/Style tab bar, Wildcard input toolbar, Wildcard file manager, Style manager, Form / Table toggle, Table view — Presets / Presets Group / Wildcards / Style
|
||||
|
||||
### Settings Tab
|
||||
2-column layout, Collapsible sections, Theme selection, Theme customization, Workflows directory, Gallery output directory, Eagle connection, CivitAI Host, CivitAI API Key, Default workflow, Default Checkpoint, VRAM Management (Ollama), Video Playback Volume, Data Management, Text Size, RAW JSON Colors, GenerateUI Model Tab Highlight, Wildcard Integration, G'MIC-Qt Integration, Language
|
||||
|
||||
### Gallery Tab (v0.3.44)
|
||||
Output / ImagePrompt / Style_Catalog / Metadata sub-tabs, Image browser, Folder tree root label, Thumbnail / Table views, Folder management, File operations, Download, MP4 video support, MP4 embedded metadata, WebM support, Embedded metadata reading fixes, Audio support, File conversion, Move To folder filter, Semantic Search, Audio waveform colors, Info tab: dimensions & duration, Multi-select, Image Compare, Prompt search, Server-side filtering, Group management, Thumbnail F button, Favorites, Detail panel, Prompt tab, Nanobanana tab, Gemini / Nano Banana nodes, MOSS-Image in GenerateUI, Faster GenerateUI Check / conversion, Partner API nodes in GenerateUI, Workflow viewer, GenUI button, Image Edit button, Send GenUI Image button, Send to LI node button, Send to LV node button, Send CC Layout / Send CC Image buttons, Search clear (✕), Clear all filters (✕ Clear), Workflow auto-save, Output folder configurable, SVG file support, PSD file support, 3D model support, Performance
|
||||
|
||||
### ImagePrompt Gallery subtab (v0.3.94, renamed from Style/Prompt in v0.3.95)
|
||||
Visual prompt library, 3-column layout, Prompt builder (right pane), Plain-text prompt storage, ponyxlWildcardsVault format support, Seed data importer
|
||||
|
||||
### Style_Catalog Gallery subtab (v0.3.95)
|
||||
Visual Style picker, 3-column layout, Positive/Negative panel, Select as Style button, Load in GenerateUI / Open in Metadata Tab buttons, Double-click to enlarge
|
||||
|
||||
### Metadata Gallery subtab (v0.3.8, moved from a top-level tab in v0.4.6)
|
||||
Now inside Gallery, 3-column layout, File drop, MP4 embedded metadata, Settings section, Nanobanana section, Model extraction, LoRA extraction, Prompt extraction, Prompt actions, Format support, Format note
|
||||
|
||||
### Nodes Tab (v0.1.7)
|
||||
Node Browser, Search & Filter, Package badges, Node detail panel, Node Sets, Right-click context menu, Multi-select, Search clear (✕), Clear all filters (✕ Clear)
|
||||
|
||||
### Models Tab (v0.2.3)
|
||||
Model Browser, Thumbnail / Table views, Table column sort, Search & Filter, User-defined badges, Side panel tabs, CivitAI integration, CivitAI panel — Info / Sample sub-tabs, CivitAI panel states, Batch CivitAI fetch, Detail modal, GenUI Model button, Group management, Table view memo, Preview images, Enable / Disable models, Multi-select & bulk operations, Search clear (✕), Clear all filters (✕ Clear)
|
||||
|
||||
### Tagger Tab (v0.3.38)
|
||||
3 sub-tabs, Model support, Threshold sliders, VLM tagging, Single tab, Single output options, Batch tab, DB tab, Dependencies
|
||||
|
||||
### TagSpace Tab (v0.9.0)
|
||||
Choose tags visually in a 3D latent space, Build / Update, Choosing tags, Explore, Search with a card's or Gallery image's tags, Make a prompt, Tagger fill, Glow / Twinkle, Hover preview, Requirements
|
||||
|
||||
### Image Edit Tab (v0.3.65)
|
||||
Layer-based image editor, Loading images, Open PSD button, Close button, New button, Tools, Layer panel, Duplicate layer (⧉), Layer lock, Text quality, Export, Canvas navigation, Undo / Redo
|
||||
|
||||
### Video Tab (v0.5.0 – v0.7.4)
|
||||
Dedicated video generation UI, independent of GenerateUI, Plan subtab, Base settings row, Edit subtab, Edit: Multi-track, Edit: Audio / BGM, Edit: Text overlays, Edit: Crop, Edit: Convert audio, Edit: Undo / Redo, Edit project persistence, Asset subtab, Project subtab, Two center previews, Register as Asset, First Frame / Last Frame are both optional, Semantic node lookup, not hardcoded IDs, Field highlight color, Load in Video, Frame tab, GIF tab, Playback volume
|
||||
|
||||
### AI TOOL Tab (v0.3.14 – v0.9.5)
|
||||
4-pane layout, Translation pane, Chat pane, Chat pane — image generation via Tool Calling, Chat pane — generate_image extra parameters, TOOLS pane (VLM), TOOLS pane — shared Chat attachment, TOOLS pane (Wildcards), Chat pane — image-to-image (I2I), Chat pane — SVG generation, no ComfyUI workflow involved, Chat pane — Skills, Chat pane — Skills v2, Built-in skills, Chat pane — Image check & refine loop, Chat pane — Workflow Doctor, Chat pane — Storyboard to Lab, Chat pane — Agent Skills folders, TOOLS pane — OCR, Collapsible Translation / Settings panes, Settings pane, Unsloth backend, Decision API client, Settings pane — Chat Image Generation, Settings pane — Chat I2I Generation, Settings pane — Generation, Model unload, Settings shared, Backend support, URL security, Lemonade's other endpoints (not integrated)
|
||||
|
||||
### Workflow Studio Library (ComfyUI Side Panel) (v0.3.9)
|
||||
Tab layout (W / N / P / M / I / A), W — Workflows tab, N — Nodes tab, M — Models tab, P — Prompts tab, I — Information tab, A — AI TOOL tab, Drag & drop workflows, Drag & drop nodes, Drag & drop prompts, Send to Canvas, Copy prompts, Double-click, Search, ⚙ Theme settings
|
||||
|
||||
### Help & Support Tab (v0.1.3)
|
||||
Sidebar navigation, Support, Feature list, Keyboard Shortcuts
|
||||
|
||||
## Installation
|
||||
|
||||
### Via ComfyUI Manager (Recommended)
|
||||
|
||||
Search for **Workflow Studio** in ComfyUI Manager and install.
|
||||
|
||||
### Manual Installation
|
||||
|
||||
```bash
|
||||
cd ComfyUI/custom_nodes
|
||||
git clone https://github.com/ketle-man/ComfyUI-Workflow-Studio.git
|
||||
```
|
||||
|
||||
Restart ComfyUI after installation.
|
||||
|
||||
---
|
||||
|
||||
## Sample Workflows
|
||||
|
||||
Sample workflows are included in the `workflows/` folder. You can open them directly in ComfyUI via drag & drop, or load them from the Workflow tab.
|
||||
|
||||
Samples for the Feeder tab: `ws_sdxl_image_feeder_i2i` / `ws_dwpose_image_feeder` (Image Loop mode, require the `comfyui-image-feeder` custom node) and `ws_sdxl_gallery_feeder_i2i` (v0.8.3, SDXL I2I with the bundled **WFS_GalleryFeeder** node — no extra custom node needed; put images in the `__Feeder__` Gallery group and use the Feeder tab's Gallery mode).
|
||||
|
||||
> **Note:** Some sample workflows require additional custom nodes.
|
||||
> If a node is shown as missing (red/unknown) after loading, install the required custom nodes via **ComfyUI Manager** or by cloning the repository from GitHub into your `ComfyUI/custom_nodes/` directory.
|
||||
>
|
||||
> ```bash
|
||||
> cd ComfyUI/custom_nodes
|
||||
> git clone <repository-url>
|
||||
> ```
|
||||
>
|
||||
> After installation, restart ComfyUI to activate the new nodes.
|
||||
|
||||
---
|
||||
|
||||
## Manual
|
||||
|
||||
A beginner-oriented manual (covers v0.9.6, text-only edition without screenshots) is available in [`docs/manual/`](docs/manual/):
|
||||
|
||||
- English: [`docs/manual/en/`](docs/manual/en/) — ZIP: `Workflow_Studio_Manual_v0.9.6_en.zip`
|
||||
- 日本語: [`docs/manual/`](docs/manual/) — ZIP: `Workflow_Studio_Manual_v0.9.6.zip`
|
||||
|
||||
An EPUB edition with screenshots (Japanese and English, v0.9.6) is available on [Google Drive](https://drive.google.com/drive/folders/14mOHcnLYrFgNrOo6fy7ELyFjjWrAoU-_?usp=sharing).
|
||||
|
||||
---
|
||||
|
||||
## Usage
|
||||
|
||||
### Launch
|
||||
|
||||
Click the **W** button in the ComfyUI top menu bar, or navigate to:
|
||||
|
||||
```
|
||||
http://127.0.0.1:8188/wfm
|
||||
```
|
||||
|
||||
> **Tip:** Shift+Click the W button to open in a new window.
|
||||
|
||||
### Canvas Snapshot
|
||||
|
||||
Click the **camera icon** (next to the W button) in ComfyUI's top bar to capture the current workflow canvas as a thumbnail. The image is automatically saved to the workflow data folder and appears in Workflow Studio's workflow list.
|
||||
|
||||
### Quick Start
|
||||
|
||||
1. **Workflow Tab** — Your workflows from `ComfyUI/user/default/workflows/` are automatically listed
|
||||
2. **Click a workflow** — View thumbnail, JSON details, and metadata in the side panel
|
||||
3. **Load in GenerateUI** — Click the button to load a workflow into the generation interface
|
||||
4. **Adjust parameters** — Modify prompts, models, seeds, and settings via the auto-generated UI
|
||||
5. **Generate** — Hit the Generate button to queue the prompt
|
||||
|
||||
---
|
||||
|
||||
## Requirements
|
||||
|
||||
- **ComfyUI** — any recent version (v1.33.9+ recommended for action bar integration)
|
||||
- **Python 3.10+**
|
||||
- **Jinja2** — `pip install jinja2` (usually included with ComfyUI)
|
||||
|
||||
### Optional
|
||||
|
||||
- **[Ollama](https://ollama.com/)** — for AI chat assistant, translation, and VLM features
|
||||
- **[LM Studio](https://lmstudio.ai/)** — alternative backend for translation and VLM (OpenAI-compatible API)
|
||||
- **[Lemonade Server](https://lemonade-server.ai/)** — alternative backend for translation, chat, and VLM (OpenAI-compatible API)
|
||||
- **[Unsloth](https://unsloth.ai/)** — alternative backend for translation, chat, and VLM (OpenAI-compatible API); needs an API key set via `UNSLOTH_API_KEY` in a `.env` file, or Unsloth's Keyless API access → "Chat and inference" turned on — `pip install -r requirements.txt` for `python-dotenv`
|
||||
- **Gemini API key / EmbeddingGemma 2** (v0.8.2) — only for the Gallery's Semantic Search: either set `GEMINI_API_KEY` in the plugin's `.env` (key from [Google AI Studio](https://aistudio.google.com); free tier available, paid beyond it), or use the local **EmbeddingGemma 2** in [Ollama](https://ollama.com) (no key; `ollama pull embeddinggemma-2:740m` or `embeddinggemma-2:440m`)
|
||||
- **[Eagle](https://eagle.cool/)** — for auto-saving generated images with metadata
|
||||
- **[comfyui-mask-editor-one](https://github.com/ketle-man/comfyui-mask-editor-one) (v0.1.9+)** — enables BiRefNet background removal, SAM3 text-prompt segmentation, and ABR stamp-brush library in the Image Edit Mask tool; `birefnet.safetensors` must be placed in `ComfyUI/models/background_removal/` for BiRefNet
|
||||
- **[psd-tools](https://pypi.org/project/psd-tools/)** (v0.6.0) — enables all PSD (Photoshop) features: Gallery bulk "Create PSD" export, Gallery browsing/thumbnails for `.psd` files, and Image Edit's Save PSD / Open PSD buttons; `pip install -r requirements.txt` (ships prebuilt wheels, no C compiler required); without it, PSD-related actions show an error toast with the install command instead of failing silently
|
||||
|
||||
#### Backend connection security (v0.7.12)
|
||||
|
||||
Server-side proxies for Ollama, LM Studio, Lemonade, Unsloth, the Tagger VLM and Eagle only connect to **localhost / 127.0.0.1 / ::1** (any port); `http(s)` only, no credentials in the URL, and redirects are never followed. To use a backend on another machine (e.g. an Ollama server on your LAN), list it in the `WFS_ALLOWED_BACKEND_HOSTS` environment variable (comma-separated `host` or `host:port`, e.g. `192.168.1.20:11434,gpu-box`) and restart ComfyUI. If you start ComfyUI with `--listen`, anyone who can reach it can use these routes, so only do that on a trusted network.
|
||||
|
||||
---
|
||||
|
||||
## Supported Languages
|
||||
|
||||
| Language | Status |
|
||||
| -------- | ------ |
|
||||
| English | Full |
|
||||
| Japanese | Full |
|
||||
| Chinese | Full |
|
||||
|
||||
---
|
||||
|
||||
## Project Structure
|
||||
|
||||
```
|
||||
ComfyUI-Workflow-Studio/
|
||||
├── __init__.py # ComfyUI entry point
|
||||
├── py/
|
||||
│ ├── wfm.py # Main class & route registration
|
||||
│ ├── config.py # Path configuration
|
||||
│ ├── nodes/
|
||||
│ │ ├── prompt_text.py # WFS_PromptText custom node (positive/negative prompt)
|
||||
│ │ └── gallery_feeder_node.py # WFS_GalleryFeeder custom node (gallery group → IMAGE)
|
||||
│ ├── routes/
|
||||
│ │ ├── workflow_routes.py # Workflow CRUD & analysis API
|
||||
│ │ ├── nodes_routes.py # Nodes metadata & node sets API
|
||||
│ │ ├── models_routes.py # Model metadata, preview, CivitAI API
|
||||
│ │ ├── prompts_routes.py # Prompt presets CRUD API
|
||||
│ │ ├── settings_routes.py # Settings API
|
||||
│ │ ├── ollama_routes.py # Ollama proxy API
|
||||
│ │ ├── eagle_routes.py # Eagle integration API
|
||||
│ │ ├── gallery_routes.py # Gallery tab API (Output + ImagePrompt + Style_Catalog sub-tabs)
|
||||
│ │ └── tagspace_routes.py # TagSpace tab API (build / space / search / neighbors)
|
||||
│ └── services/
|
||||
│ ├── workflow_service.py # Workflow file operations
|
||||
│ ├── nodes_service.py # Node metadata & node sets
|
||||
│ ├── models_service.py # Model metadata & preview images
|
||||
│ ├── civitai_service.py # CivitAI API integration & cache
|
||||
│ ├── prompts_service.py # Prompt presets persistence
|
||||
│ ├── workflow_analyzer.py # Model/node detection
|
||||
│ ├── settings_service.py # Settings persistence
|
||||
│ ├── png_extractor.py # PNG metadata extraction
|
||||
│ ├── gallery_service.py # Gallery image scanning, .txt sidecar & ponyxlWildcardsVault prompt resolution
|
||||
│ └── gallery_metadata.py # Gallery per-image metadata store (favorites/tags/memo/groups)
|
||||
├── templates/
|
||||
│ └── index.html # SPA template (Workflow/GenerateUI/Prompt/Metadata/Gallery/Nodes/Models/Settings/Help/AI)
|
||||
├── static/
|
||||
│ ├── favicon.svg # Browser tab icon (W+S Wave)
|
||||
│ ├── css/main.css # Styles
|
||||
│ └── js/
|
||||
│ ├── app.js # App initialization & routing
|
||||
│ ├── workflow-tab.js # Workflow browser
|
||||
│ ├── generate-tab.js # Generation UI
|
||||
│ ├── feeder-tab.js # Feeder subtab (Image Loop + Gallery modes)
|
||||
│ ├── gallery-tab.js # Gallery tab: Output sub-tab (image browser, groups, metadata) + sub-tab switching
|
||||
│ ├── image-prompt-tab.js # Gallery tab: ImagePrompt sub-tab (visual prompt builder)
|
||||
│ ├── style-catalog-tab.js # Gallery tab: Style_Catalog sub-tab (visual Style picker)
|
||||
│ ├── tagger-tab.js # Tagger tab (WD Tagger, DeepDanbooru, Ollama VLM)
|
||||
│ ├── prompt-tab.js # AI assistant & presets
|
||||
│ ├── metadata-tab.js # Metadata extraction & display (PNG/WebP/JSON)
|
||||
│ ├── settings-tab.js # Settings panel
|
||||
│ ├── comfyui-client.js # ComfyUI WebSocket/API client
|
||||
│ ├── nodes-tab.js # Node browser & node sets
|
||||
│ ├── models-tab.js # Model browser & CivitAI integration
|
||||
│ ├── ai-tab.js # AI TOOL tab (Translation | Chat | TOOLS/VLM | Settings)
|
||||
│ ├── comfyui-workflow.js # UI-to-API format conversion
|
||||
│ ├── comfyui-editor.js # Dynamic parameter editor
|
||||
│ ├── json-highlight.js # JSON syntax highlighting
|
||||
│ ├── util.js # Shared utilities (escapeHtml, readJsonStorage, getSettings)
|
||||
│ └── i18n.js # Internationalization
|
||||
├── web/comfyui/
|
||||
│ ├── top_menu_extension.js # ComfyUI menu bar integration
|
||||
│ ├── node_sets_menu.js # Workflow Studio Library side panel
|
||||
│ └── gallery_feeder_extension.js # WFS_GalleryFeeder canvas widgets (After Gen / Run / Stop)
|
||||
├── tools/
|
||||
│ └── import_style_prompt_seed.py # Dev tool: pre-process a wildcards-vault source into ws_image_prompt (not run by the plugin itself)
|
||||
└── data/ # Fallback data dir (used when ComfyUI user/default/ is not found)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## License
|
||||
|
||||
MIT License
|
||||
|
||||
---
|
||||
|
||||
## Acknowledgements
|
||||
|
||||
- [ComfyUI](https://github.com/comfyanonymous/ComfyUI) by comfyanonymous
|
||||
- [ComfyUI-Custom-Scripts](https://github.com/pythongosssss/ComfyUI-Custom-Scripts) by pythongosssss — Canvas snapshot and PNG workflow embedding implementation reference
|
||||
- [ComfyUI-Lora-Manager](https://github.com/willmiao/ComfyUI-Lora-Manager) — Plugin architecture and UI pattern reference
|
||||
- [Ollama](https://ollama.com/) for local LLM inference
|
||||
- [Eagle](https://eagle.cool/) for image management
|
||||
- [Pillow (PIL Fork)](https://python-pillow.org/) — server-side thumbnail generation (`data/thumb_cache/`)
|
||||
- [ComfyUI-Gallery](https://github.com/PanicTitan/ComfyUI-Gallery) by PanicTitan — thumbnail grid UX reference
|
||||
- [infinite-image-browsing](https://github.com/zanllp/sd-webui-infinite-image-browsing) by zanllp — thumbnail caching and index strategy reference
|
||||
- [Fooocus](https://github.com/lllyasviel/Fooocus) by lllyasviel — style preset JSON format reference
|
||||
|
||||
@@ -1,70 +1,208 @@
|
||||
# ComfyUI-Workflow-Studio
|
||||
|
||||
A comprehensive workflow management and generation UI plugin for [ComfyUI](https://github.com/comfyanonymous/ComfyUI).
|
||||
A comprehensive workflow, asset management, and generation UI plugin for [ComfyUI](https://github.com/comfyanonymous/ComfyUI).
|
||||
|
||||
Browse, organize, and execute workflows directly from a dedicated studio interface — without switching between windows or manually editing JSON.
|
||||
**📁 Management** — organize all your assets in one studio
|
||||
|
||||
- Workflow, model, image, and prompt management
|
||||
- AI-powered prompt writing assistance, translation, and tag generation
|
||||
- File drop & Gallery-linked metadata viewing — inspect and reuse generation settings instantly
|
||||
- Semantic image search in the Gallery — find images by describing them, or list images similar to a selected one
|
||||
|
||||
**⚡ GenerateUI** — a productivity-focused generation tab connected to every other tab
|
||||
|
||||
- Batch generation across models, samplers, prompts, and workflows
|
||||
- Image Feeder for continuous folder-based generation
|
||||
- Lab: experimental I2I batch generation with independent per-iteration keyframes for Model (Checkpoint/LoRA Single/VAE)/Prompt/KSampler
|
||||
|
||||
**📚 Workflow Studio Library** — a multi-function side panel for smooth ComfyUI integration
|
||||
|
||||
- Drag & drop models, nodes, prompts, and workflows straight onto the canvas
|
||||
- **Send to Canvas**: click "Send to Canvas" (Workflow tab) or "Copy & Send Canvas" (Gallery tab) to send the workflow directly to the ComfyUI canvas — UI and API formats both supported
|
||||
- View metadata from images / JSON, then drop the detected models and prompts onto the canvas
|
||||
- Built-in AI tools (translation and more)
|
||||
|
||||

|
||||

|
||||

|
||||
|
||||
## Screenshots
|
||||
|
||||
| Workflow Tab | GenerateUI Tab |
|
||||
|:---:|:---:|
|
||||
|  |  |
|
||||
| Workflow Tab | Models Tab |
|
||||
| :-------------------------------------: | :---------------------------------: |
|
||||
|  |  |
|
||||
|
||||
| Prompt Tab | Settings Tab |
|
||||
|:---:|:---:|
|
||||
|  |  |
|
||||
| Prompt Input Assistance | GenUI Batch |
|
||||
| :----------------------------------------------------------: | :-------------------------------------: |
|
||||
|  |  |
|
||||
|
||||
| Nodes Tab | Models Tab |
|
||||
|:---:|:---:|
|
||||
|  |  |
|
||||
| Top Bar | Image Edit Tab |
|
||||
| :----------------------------: | :--------------------------------------: |
|
||||
|  |  |
|
||||
|
||||
| Gallery Tab | Help & Support Tab |
|
||||
|:---:|:---:|
|
||||
|  |  |
|
||||
| WS Library | Library Information |
|
||||
| :----------------------------------: | :---------------------------------------------------: |
|
||||
|  |  |
|
||||
|
||||
| Workflow Studio Library (ComfyUI) | ComfyUI Integration |
|
||||
|:---:|:---:|
|
||||
|  |  |
|
||||
| Video Tab | AI TOOL Tab |
|
||||
| :----------------------------------: | :--------------------------------------: |
|
||||
|  |  |
|
||||
|
||||
| Video Tab - Edit | Video Tab - Asset |
|
||||
| :----------------------------------: | :-----------------------------------: |
|
||||
|  |  |
|
||||
|
||||
| Lab Tab | Lab Index Image |
|
||||
| :--------------------------------: | :------------------------------------------: |
|
||||
|  |  |
|
||||
|
||||
| Gallery Tab - Semantic Search ("sunset city street") | TagSpace Tab - Search ("sunset city street") |
|
||||
| :-----------------------------------------------------------------: | :-----------------------------------------: |
|
||||
|  |  |
|
||||
|
||||
---
|
||||
|
||||
## Features
|
||||
|
||||
### Workflow Tab
|
||||
- **Thumbnail / Card / Table views** — switch between view modes to browse your workflow library
|
||||
<details>
|
||||
<summary><h3>Workflow Tab</h3></summary>
|
||||
|
||||
- **Thumbnail / Table views** — switch between view modes to browse your workflow library
|
||||
- **Thumbnail side panel** — preview workflow canvas snapshots in the side panel
|
||||
- **Badge filtering** — filter by user-defined badges (free labels you assign to each workflow)
|
||||
- **Search** — full-text search across workflow names and metadata
|
||||
- **Side panel tabs** — Thumbnail preview, JSON viewer with syntax highlighting, and Group management
|
||||
- **Badge management** — add, rename, delete badges with custom colors shared with the Models tab (⚙ Badge button)
|
||||
- **AI summary** — generate workflow descriptions using Ollama
|
||||
- **Import / Export** — import workflows from files or clipboard, open in ComfyUI directly
|
||||
- **Default view setting** — persist your preferred view mode (Thumbnail / Card / Table)
|
||||
- **Import / Export** — import workflows from files or clipboard; **Send to Canvas** button sends the selected workflow directly to the ComfyUI canvas (UI and API formats both supported)
|
||||
- **Side panel toolbar buttons** (v0.5.0) — selecting a card shows three buttons in the top toolbar: **Load in GenerateUI**, **Load in Video** (loads a MiniMax H3 Image-to-Video, LTX-2.5 (Text/Image/First&Last-Frame to Video), or Wan2.2 (Text to Video) workflow into the Video tab (LTX-2.5/Wan2.2 support: v0.5.4); shows an error toast for workflows that don't contain a supported node), and **Send to Canvas**; the detail modal's duplicate copies of these three buttons were removed in favor of this single toolbar location
|
||||
- **Default view setting** — persist your preferred view mode (Thumbnail / Table)
|
||||
- **Search clear (✕)** — inline ✕ button appears inside the search box whenever text is entered; click to clear immediately
|
||||
- **Clear all filters (✕ Clear)** — rightmost toolbar button; resets search text, group filter, and badge filter (ALL) in one click
|
||||
- **Sort** (v0.7.2) — Date (Newest/Oldest) / Name (A-Z/Z-A) dropdown next to the group filter, persisted via localStorage — same pattern as the Gallery tab's sort control
|
||||
- **GenerateUI Check** (v0.7.13) — tells whether a workflow will run in GenerateUI before you load it. The side panel shows the format badge (UI / API / App) and two ✅ / ⚠ / ❌ result badges below the workflow name, checked automatically on selection; the detail modal shows the format badge, a **GenerateUI Check** button and the same badges below the title. Hover a badge for the reasons. **Conversion** runs the same UI→API conversion as GenerateUI: ❌ for unsupported formats, conversion errors or node types not installed in this ComfyUI (the prompt would be rejected), ⚠ for values not available here (models, LoRAs, images…) — UI-format workflows get them silently replaced with the first choice, API-format workflows are sent as-is and rejected by ComfyUI's validation. **Operability** is the share of nodes with settings that GenerateUI's fields expose (✅ 80%+ / ⚠ 50%+ / ❌ below), listing the nodes you'd still have to change in the node graph. Results aren't saved; a check takes about 20 ms once ComfyUI's node list (`/object_info`) is cached (the first one after opening the page waits about 10 s for it; the detail modal prefetches it). The Decision Model was evaluated for the operability rating but couldn't tell good and bad workflows apart, so it is rule-based
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><h3>Canvas Snapshot (v0.1.2)</h3></summary>
|
||||
|
||||
### Canvas Snapshot (v0.1.2)
|
||||
- **One-click capture** — click the camera button in ComfyUI's top bar to snapshot the current workflow canvas
|
||||
- **Auto-save as thumbnail** — the snapshot is saved directly to the workflow data folder as a PNG thumbnail
|
||||
- **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.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
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><h3>GenerateUI Tab (v0.3.5)</h3></summary>
|
||||
|
||||
- **6-tab layout** — Input / Model / Settings / Feeder / Batch / **Lab** tabs; Input, Model, and Settings each include a Raw JSON column on the right for instant preview and direct editing
|
||||
- **Save button** — located at the right end of the subtab row; opens a filename dialog (default: current workflow name) and saves the current workflow as a `.json` file to the Workflow tab via the import API; hidden while the Batch or Lab subtab is active (v0.4.6), since those work on workflow copies / their own Plan files rather than the currently loaded workflow
|
||||
- **Default-workflow snapshot fix** (v0.4.8) — overwriting the loaded workflow under a filename that's currently set as the auto-load **Default workflow** (Settings tab, see below) now also refreshes that cached snapshot; previously only the file on disk was updated, so the old (pre-edit) version — including any checkpoint no longer installed — kept reappearing after every page reload until the default was re-set by hand
|
||||
- **Input tab** — Prompt (left) and Image (right, about 3:2) side by side on one screen (drag-and-drop upload; Image wraps under Prompt when the area is narrow, about 720px or less); Prompt area shows Positive Prompt and Negative Prompt textareas, plus an **Embeddings selector** at the bottom (Filter + Select + Weight input + Paste button); Paste inserts `(embedding:Name:weight)` at the cursor position of the last focused textarea (defaults to Positive when neither is focused); Raw JSON (540px) in the right column, collapsible to a slim strip with the » button (Input tab only; remembered)
|
||||
- **Multi-image I2I for Comic Creator** (v0.8.12) — new iframe bridge `window._wfmReceiveMultiImageI2IRunRequest(imageBlobs, params, workflowData?, workflowFilename?)` used by Comic Creator's Nanobanana+ tab (Local mode): image *i* goes to the workflow's *i*-th LoadImage node (extra images are ignored), and optional width / height / steps / cfg / denoise / sampler / scheduler / seed are written through `setGenerationParams`; returns `{ ok, url, slotCount, usedImages }`
|
||||
- **Revert button** (v0.3.70) — a ↺ button next to each Apply button reverts the textarea to the node's currently applied value (the reverse of Apply)
|
||||
- **Emphasis weight editing** (v0.3.70) — select text (or just place the cursor on a word/parenthesis block) and press Ctrl+↑/↓ to adjust `(text:weight)` by ±0.05, A1111/native-ComfyUI style; parentheses are removed automatically when the weight returns to 1.0
|
||||
- **Mask slot for inpainting** (v0.3.71) — LoadImage slots whose MASK output feeds an inpaint node (e.g. `VAEEncodeForInpaint`) show an additional Mask drop zone; when a mask is set, image + mask are composited into a single RGBA upload (mask baked into the alpha channel) matching ComfyUI's native alpha→MASK extraction — no extra nodes required
|
||||
- **Placeholder Image + Clear** (v0.3.97) — each LoadImage card gets a **Clear** button (resets that card's pending selection/preview back to empty; doesn't touch the workflow node itself) and a **Placeholder** button; a collapsible **Placeholder Image** section (collapsed by default) at the top of the Image sub-panel configures one shared default — **Color** mode (set Width/Height/Color, generates a solid-color PNG on the fly) or **Image** mode (drop one default image, reused as-is) — remembered across sessions; clicking a card's own Placeholder button immediately replaces just that card's image with the configured default, so multiple LoadImage cards can each be replaced individually with one click
|
||||
- **Model tab** — Checkpoint, VAE, Diffusion Model (UNETLoader / UnetLoaderGGUF / LoaderGGUF), and Text Encoder (CLIPLoader / DualCLIPLoader / ClipLoaderGGUF / DualClipLoaderGGUF — single clip: type + device; dual clip: two clip selectors + type + device) are always shown; **ControlNet** and **Hypernetwork** (with Strength field) are collapsed by default (v0.3.98) since they're used less often — click their header to expand; **LoRA** (Single/Stack tabs) has its own column; all selectors have a filter; Raw JSON on the right
|
||||
- **Highlight color** (v0.3.98) — the label of each model type above, plus the LoRA column header, turns a distinct color (default bright green, customizable in the Settings tab) when the loaded workflow actually contains that type of node; stays visible even while ControlNet/Hypernetwork are collapsed, so relevance is visible without expanding
|
||||
- **LoRA Stack Group toggle** (v0.3.92) — for `Lora Loader (LoraManager)` nodes, a **Use Stack Group** checkbox next to the Single/Stack tabs switches what the Stack tab shows and edits: OFF (the default whenever a workflow is loaded) displays and edits the LoRAs actually configured in the workflow's own Lora Manager node — correctly showing every LoRA it holds, not just the first one; ON switches to the LoRA group registered in the Models tab instead; toggling either direction clears the node's LoRA list first, then loads it from the newly selected source, and switching back to OFF restores exactly the list that was present when the workflow was loaded
|
||||
- **Native Load LoRA nodes** (v0.8.4) — ComfyUI v0.40's `Load LoRA (Model)` / `Load LoRA (Text Encoder)` pair (each node holds up to 20 rows of LoRA / strength / enabled) is detected and edited like the other LoRA nodes: Single / Stack Apply, the Models tab "Apply", the LoRA batch, Lab and the Bypass button write both nodes together (the Model node takes Str M, the Text Encoder node takes Str C); Stack Apply writes the whole Stack group as rows, and the Metadata tab / side-panel I tab list their LoRAs. API-format workflows only for now — ComfyUI frontend 1.55.17 cannot add rows to these nodes in its own graph editor, so UI-format workflows carry no `widgets_values` for them yet
|
||||
- **LoRA Bypass button** (v0.4.4) — a ⛔ toggle next to the Refresh Stack group button in the LoRA column header; forces the target LoRA node's strength to 0 (`strength_model`/`strength_clip` for a standard LoraLoader, or every entry's `strength`/`clipStrength` for a Lora Manager node — its LoRA list stays intact, not replaced) without touching the actual ComfyUI node's mode; click again to restore the exact values that were there before toggling; targets whichever node Single/Stack Apply default to (the workflow's Lora Manager node if it has one, else the first LoRA node); clicking a Single or Stack Apply button clears the bypass state so it can't silently reassert itself later
|
||||
- **Settings tab** — KSampler and Latent Image side by side at 50% width each; 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; built-in **search bar** (always shown) finds all matches as you type with count display (`3/12`); navigate with ↑/↓ buttons or Enter / Shift+Enter; Escape or ✕ clears; current match highlighted in orange, other matches in yellow
|
||||
- **Bypass/Mute node handling** (v0.3.75) — loading a UI-format workflow with Bypass-mode nodes now reroutes their wires to the upstream source (matching same-type input/output slots, recursively through chained bypasses) instead of leaving a dangling reference that failed validation; Mute-mode nodes are excluded without rerouting, same as ComfyUI itself; when either is present, a note listing the affected nodes appears above the Raw JSON search bar in the Input/Model/Settings tabs
|
||||
- **One-click generation** — queue prompts to ComfyUI without leaving the studio
|
||||
- **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
|
||||
- **Workflow seed mode** (v0.8.3) — the mode selector's new **Workflow** option generates with the loaded workflow's own seed as-is (no override), e.g. to reproduce a Gallery image with its original seed; falls back to the Seed field only if the workflow has no literal seed input. Seed overrides no longer leak back into the loaded workflow (generation now works on a deep copy), so Workflow mode still sees the original seed after Random runs
|
||||
- **Style selector** — checkbox and dropdown next to the Reset Workflow button; enable to apply a Fooocus-style JSON to positive and negative prompts at generation time; style files (`*.json`) are loaded from `user/default/Workflow-Studio/style/`; the style's `{prompt}` placeholder is replaced with the original prompt text, or the style is appended if no placeholder exists; `negative_prompt` is appended to the existing negative prompt; styles are applied to a per-generation copy and do not modify the loaded workflow
|
||||
- **Wildcards inside a Style now expand** (v0.4.7) — an A1111-style `__wildcard__` reference written into a Style's Positive/Negative prompt is expanded at generation time just like one typed directly into GenerateUI; the Style text is merged into the prompt *before* wildcard expansion runs (previously the order was reversed, so a Style's own wildcard references were sent to ComfyUI unexpanded)
|
||||
- **Create Catalog / Catalog buttons** (v0.3.95) — next to the Style dropdown. **Create Catalog** generates one preview image per Style checked in the Batch tab's Style sub-tab (using the currently loaded workflow, typically T2I), then saves each result into a chosen `ws_style_catalog` subfolder named after the Style (existing files with the same name are overwritten); a modal lets you create a new destination folder or pick an existing one — separate folders are useful for grouping catalogs by checkpoint or by purpose. **Catalog** jumps straight to the Gallery tab's Style_Catalog sub-tab to browse the results (see below)
|
||||
- **Don't keep a copy in the Output folder** (v0.3.96) — checkbox in the Create Catalog modal; each generation still writes a normal file to the Output folder first (the workflow's own Save Image node always does that), but once its copy has been saved into the catalog folder, checking this deletes that Output-folder original right away — keeps a large catalog run (e.g. every Style at once) from flooding the Output folder with near-duplicate files; if a style's catalog copy fails to save, its Output file is left alone rather than deleted
|
||||
- **Batch type selector** — check one of the column header checkboxes in the Batch Queue pane (Checkpoint / Lora / Prompt / Workflow / Sampler / Scheduler / Style) to activate that batch type; only one type can be active at a time; the Batch panel below Generate shows the active type, progress, and Pause/Resume/Stop controls
|
||||
- **Batch tab** (v0.3.18) — dedicated 3-pane layout for assembling the batch queue:
|
||||
- **Left pane** — 4 tabs: **Checkpoints** (file-tree; Filter / All / None), **Sampler** (KSampler sampler list), **Scheduler** (KSampler scheduler list), **Style** (flat list of all styles from `Workflow-Studio/style/`; All / None buttons)
|
||||
- **Center pane** — group-based selection with inner tabs (Checkpoint | Lora | Prompt | Workflow); Checkpoint/Lora groups come from the Models tab, Prompt groups from the Prompt tab, Workflow groups from the Workflow tab — check a group to add all its members, expand ▶ to select individually
|
||||
- **Right pane (Batch Queue)** — 7 columns: Checkpoint / Lora / Prompt / Workflow / Sampler / Scheduler / **Style**; each column header has an enable checkbox (radio behavior: only one at a time); count shown per column; Style batch applies each selected style sequentially to a workflow copy
|
||||
- **Lora batch prompt sync** (v0.3.69) — for each selected LoRA, its syntax (`<lora:name:strength_model:strength_clip>`) and CivitAI trained words are automatically appended to the Positive prompt (rebuilt from the original prompt each time, not accumulated), then restored to the pre-batch state when the batch completes or is stopped; if a selected LoRA is not yet recognized by ComfyUI's model list, a warning toast suggests a Refresh or restart
|
||||
- **UI-to-API conversion** — automatic conversion supporting subgraphs (nested workflows), COMBO types, and display-only node exclusion; improved analysis covers SDXL multi-hop CONDITIONING chains, CLIPTextEncodeSDXL, SDXLPromptStyler, KSamplerAdvanced, and Guider-based "Advanced Sampling" workflows (`SamplerCustomAdvanced`/`SamplerCustom` + `CFGGuider`/`DualCFGGuider`/`BasicGuider` + `RandomNoise` + `KSamplerSelect` + `*Scheduler` — Flux.2 Klein, LongCat, Boogu, HiDream E1, etc.)
|
||||
- **MultiType widget-value bug fix** (v0.5.4) — a node input declaring a comma-joined MultiType (e.g. LTX-2.5's `LTXVEmptyLatentAudio.frame_rate: "FLOAT,INT"`) was silently dropped from the widget list instead of being recognized as a scalar widget, which shifted every subsequent widget's value onto the wrong input (surfaced as `LTXVEmptyLatentAudio.batch_size` receiving `frame_rate`'s value and video generation failing with "Expected size 1 but got size 25")
|
||||
- **Video workflow support** (v0.5.2) — loading a MiniMax H3 (or other all-in-one video-generation) workflow now works from GenerateUI too, not just the dedicated Video tab: the Input tab's Prompt field picks up its `prompt` widget, the Image tab picks up its LoadImage-based `first_frame` the same way any other I2I workflow does, and generation runs with a longer timeout since video generation takes much longer than a still image; the result preview shows the generated mp4 inline (`<video>`) instead of trying to render it as an image
|
||||
- **LTX-2.5 / Wan2.2 support** (v0.5.4) — these follow ComfyUI's regular node-graph pattern rather than an all-in-one node, so they needed their own detection: Positive/Negative Prompt now traces through LTX-2.5's `LTXVDualCFGGuider`/`LTXVConditioning` nodes to the actual prompt text, and the Settings tab's Latent Image section recognizes Wan2.2's `EmptyHunyuanLatentVideo` and LTX-2.5's `EmptyLTXVLatentVideo` (width/height/batch size, plus an added **Length (frames)** field) instead of showing "No EmptyLatentImage node found"; the extended generation timeout now also triggers off a `SaveVideo`/`CreateVideo` node anywhere in the graph, not just an all-in-one node
|
||||
- **Eagle integration** — auto-save generated images to [Eagle](https://eagle.cool/) with metadata
|
||||
- **Qwen Image 2.1 support** (v0.7.3) — `TextEncodeQwenImage21` (the unified T2I/Edit encoder used by Comfy-Org's Qwen-Image-2.1 workflow templates) is now recognized: its `prompt`/`negative_prompt` widgets populate the Input tab's Positive/Negative Prompt textareas and are editable like any other prompt node; its `resolution` (a pixel-budget int, not width/height) is exposed for Raw JSON editing. No extra work was needed for the model's up to 10 reference images (`image_1`…`image_10`, used for image editing) — each one arrives as an ordinary LoadImage node, so it already gets its own card in the Input tab's Image sub-panel via the existing generic LoadImage detection
|
||||
- **Ming Image support** (v0.7.5) — `TextEncodeMingImageEdit` (single `prompt` widget, up to 8 optional `images.image_N` reference inputs; role taken from the sampler/guider wiring, so the empty-prompt negative instance in layer-decomposition workflows shows as Negative) and `EmptyQwenImageLayeredLatentImage` (Latent panel; `layers` kept as-is) are recognized in GenerateUI, and Gallery/Metadata/sidepanel I tab now show their prompts as Positive. The Sampler field is disabled (N/A) when the SAMPLER input comes from a node without `sampler_name` (e.g. `SamplerLCM`). **Fix:** top-level nodes whose widgets are converted to wired inputs (e.g. `EmptyLatentImage` width/height fed by `GetImageSize`) keep those values in `widgets_values`; they were not stripped outside subgraphs, shifting later values (`batch_size` became `1024`, KSampler `steps`/`cfg` misread). Also: `BasicGuider`'s `conditioning` is treated as positive, and a linked text input wins over the stale widget text in UI-format metadata
|
||||
- **P-H3 Image support** (v0.9.4) — the `PH3ImageConditioning` templates (Image Edit and T2I) load and run from GenerateUI, with the prompt shown on the Input tab and read back by the Metadata tab. Width and height follow the workflow's wiring, and the prompt upsampler runs as set in the workflow
|
||||
- **MiniMax-H3-Image support** (v0.9.6) — the `MiniMaxH3ImageConditioning` templates (Image Edit and T2I) load and run from GenerateUI the same way, with the prompt shown on the Input tab and read back by the Metadata tab and the sidepanel I tab
|
||||
|
||||
### Prompt Tab
|
||||
- **3-column layout** — AI Assistant (left), Presets/Preset Manager tab-panel (center), Wildcard support (right)
|
||||
- **AI chat assistant** — powered by [Ollama](https://ollama.com/), generate and refine prompts interactively
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><h3>Feeder subtab (v0.3.5 / v0.3.42)</h3></summary>
|
||||
|
||||
Two independent modes selectable via **[Image Loop] / [Gallery]** toggle buttons at the top of the left pane (persisted in `localStorage`).
|
||||
|
||||
**Image Loop mode** — requires the **[comfyui-image-feeder](https://github.com/ketle-man/comfyui-image-feeder)** custom node.
|
||||
|
||||
- **ImageFeeder node control** — select the target node from a dropdown auto-populated from the loaded workflow; edit all node parameters (Directory, Sort Mode, Index, Start/End Index, Batch Size, Seed, Use Selection) and Apply to the workflow
|
||||
- **Image library** — 3-pane layout: folder tree (left) browsing `user/default/image-loop-data/`, image grid with checkbox selection (center), preview panel with resolution and file size (right)
|
||||
- **Selection management** — check individual images; All / None buttons for the current folder; selected files are reflected in `selected_files` on Apply
|
||||
- **Presets** — save the current directory + selection as a named preset; load or delete presets (server-side persistence via `image-feeder-presets.json`)
|
||||
- **Continuous Run loop** — Run / Stop buttons below the presets; **After gen** mode controls index behavior after each generation:
|
||||
- **Loop** — advance index and wrap back to 0 when all images are exhausted (runs indefinitely)
|
||||
- **Increment** — advance index and auto-stop when all images are consumed
|
||||
- **Fixed** — always use the same index
|
||||
- **Index sync** — after each generation the node returns `next_index` via WebSocket (`image_loop_node_sync`); the Index field updates automatically
|
||||
- **Seed** — Run loop uses the right-pane seed setting (Random / Fixed / Increment / Decrement); the node's own Seed field only affects random sort order
|
||||
|
||||
**Gallery mode** (v0.3.42) — no external plugin required; uses the built-in **WFS_GalleryFeeder** custom node.
|
||||
|
||||
- **WFS_GalleryFeeder node** — reads images directly from a Gallery group and outputs them one at a time; inputs: `group_name`, `index`, `sort_mode` (filename_asc / filename_desc / random), `seed`
|
||||
- **Node & group selector** — pick the WFS_GalleryFeeder node from the loaded workflow and choose which Gallery group to feed images from; `__Feeder__` group is auto-created on first open
|
||||
- **Image grid** — center pane shows all images in the selected group; click any image to update the Index to that position
|
||||
- **After Gen modes** — Loop (wrap at end and continue indefinitely), Increment (stop automatically when last image is reached), Fixed (always use the same index)
|
||||
- **Run / Stop controls** — left pane Run / Stop buttons manage the generation loop; After Gen combo (loop / increment / fixed), ▶ Run, and ■ Stop widgets are also available directly on the WFS_GalleryFeeder node in the ComfyUI canvas (`gallery_feeder_extension.js`)
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><h3>Lab subtab (v0.3.87 – v0.9.5)</h3></summary>
|
||||
|
||||
An experimental batch generator: runs the workflow currently loaded in GenerateUI N times, letting Model (Checkpoint/LoRA Single/VAE) / Prompt / KSampler each change independently starting at a chosen iteration — unlike the Batch tab's single-axis queue, every column keeps its own list of change points. Never mutates the loaded workflow; every iteration runs on a fresh clone. Works with both I2I and T2I workflows (v0.3.90).
|
||||
|
||||
- **Setting / Results / Plan JSON sub-panels** — Setting: image drop zone + 3 keyframe columns + run controls; Results: source image and up to 9 generated thumbnails (click to enlarge); Plan JSON: the current plan as raw editable JSON (v0.3.88)
|
||||
- **Per-column keyframes** — Checkpoint, LoRA, VAE, Prompt, and KSampler each hold their own fully independent list of `{iteration, value}` keyframes; +/− per column adds/removes the last keyframe (iteration #1 is fixed and can't be removed); any keyframe other than #1 can also be deleted individually from inside its own edit modal (v0.3.93), not just the last one; click a cell to edit its value, the iteration it starts applying from, and a "revert to #1's setting" checkbox; the effective value at iteration N is the latest keyframe with iteration ≤ N, carried forward until the next one changes it; lowering the Batch count below an existing keyframe's iteration doesn't delete or renumber it — a warning toast appears and it just stays dormant until Batch count is raised again (v0.3.93)
|
||||
- **Model column — Checkpoint / LoRA Single / VAE** (v0.4.2, redesigned v0.4.3) — Checkpoint and VAE (and now LoRA) share one visual "Model" column; a `[C][L][V]` toggle in its header picks which of the three independent keyframe lists the shared cell list, its own +/-, and its edit modal currently operate on — each behaves exactly like its own column (same as Prompt/KSampler), just sharing the Model column's screen space, so adding, removing, editing, reverting, or bypassing a keyframe while viewing one never touches the other two. Each toggle button lights up the same highlight color as GenerateUI's Model tab (configurable in Settings) when the loaded workflow actually contains that node type. A field left blank in a later keyframe's edit modal shows "(inherits: ...)" instead of "(workflow default)" when an earlier keyframe in that same list already set something. LoRA support is Single only (no Stack, matching the experimental scope of this tab); if a LoRA is set but the loaded workflow has no LoRA node at all, Run warns once and skips it rather than auto-inserting one — unlike VAE (which does auto-inject a VAELoader when missing), wiring in a LoraLoader would require rewiring the Checkpoint's model/clip outputs through it
|
||||
- **Empty state when no matching node exists** (v0.4.5) — Checkpoint/LoRA/VAE each show "No matching node in this workflow" instead of a keyframe list when the loaded workflow has no node that column could actually override, and the column's +/− is disabled too, so no dead "(workflow default)" keyframe row can be created in the first place; VAE still counts as usable whenever a Checkpoint node exists, since its baked-in VAE can still be overridden via auto-injected VAELoader as above
|
||||
- **Wildcards** (v0.3.93) — Prompt keyframes' Positive/Negative text supports the same A1111-style `__name__` syntax as the main GenerateUI prompt fields; each keyframe is expanded fresh right before that iteration runs, so reusing the same keyframe across iterations can still draw a different random line each time
|
||||
- **Prompt cell extras** (v0.3.88, refined in v0.3.89, v0.3.93, and v0.3.97) — **Get from GenerateUI** fills Positive/Negative from the workflow currently loaded in GenerateUI; **Get from Image** extracts a prompt from the image currently loaded in Lab's own Image drop zone (same detection as the Metadata tab; no separate file picker); **Get from Previous** (v0.3.97) copies both Positive and Negative wholesale from the keyframe immediately before this one in the same column (e.g. editing #3 copies #2's prompt; not shown on keyframe #1, which has no earlier row); **Clear** (v0.3.97) empties both fields; **Style** row — an **Apply** button merges whichever style is currently selected in GenerateUI's own top-bar Style dropdown into the Positive/Negative text below, comma-separated after any existing text (never clears it) and works regardless of that top-bar's own Style enable checkbox; a checkbox next to it tracks on/off and shows the applied style's name beside itself (not on the button) — unchecking only clears that name label, the already-merged text stays and is yours to edit/delete by hand
|
||||
- **Keyframe #1 live-reflect** (v0.3.97) — in every column, keyframe #1 shows the currently loaded workflow's own live setting instead of a blank placeholder — for the Model column this covers Checkpoint and VAE only, LoRA is never live-reflected since there's no reliable way to infer "the" active LoRA back out of a workflow node — both in its grid cell (dashed border) and pre-filled into its edit modal, for as long as it hasn't been explicitly saved with an override; saving it — even unchanged — locks that value in as a real override and the dashed/live styling goes away; switching to the Lab subtab always refreshes this against whatever is currently loaded in GenerateUI
|
||||
- **Bypass checkbox** (v0.3.97) — available on every keyframe including #1; skips that row entirely when picking which setting applies at a given iteration, as if it didn't exist, so whatever was active before it keeps running instead; Lab-internal only, never touches the actual ComfyUI node's mode; disables that row's value fields and its Revert checkbox while checked (mutually exclusive with Revert); the cell shows an amber "⏭ Bypassed" label, taking priority over both the Revert and live-reflect display
|
||||
- **LoRA node bypass & prompt injection** (v0.4.4) — inside the LoRA keyframe's own edit modal, two checkboxes independent of the row-level Bypass above: **Bypass LoRA node** forces that keyframe's `strength_model`/`strength_clip` to 0 at apply-time — the behavioral equivalent of ComfyUI's node Bypass (mode:4), since the workflow used here is already API-format with no `mode` concept; **Apply LoRA syntax + trigger words to Positive prompt** appends `<lora:name:strengthModel:strengthClip>` plus that LoRA's cached CivitAI trigger words to the Positive prompt, comma-separated, at apply-time — the same format GenerateUI's own Model tab Apply button writes. Switching keyframes (a different LoRA, this checkbox turned off, or the row Bypassed) always strips exactly what the previous iteration injected before adding anything new, so a batch never accumulates every LoRA it has used; the prompt checkbox is disabled automatically while Bypass LoRA node is checked
|
||||
- **T2I workflow support** (v0.3.90) — a **T2I workflow (no source image)** checkbox in the Image pane skips the source-image requirement and never touches a LoadImage node, so workflows with no image input (e.g. plain `EmptyLatentImage` txt2img) can also use the Model/Prompt/KSampler keyframes; the Image drop zone and "Use generated image for next" are greyed out (not cleared) while it's on; saved with the plan as `t2i_mode`
|
||||
- **Use generated image for next** — optional checkbox that chains iterations: from iteration 2 onward the previous iteration's first output image is fed back in as the I2I source instead of the original dropped image, using ComfyUI's `"name [type]"` annotated-filename reference (no re-upload needed); disabled together with the Image drop zone in T2I mode
|
||||
- **Workflow recall** (v0.3.90) — every saved plan records the filename of the workflow that was loaded in GenerateUI at save time (`workflow_filename` in the Plan JSON); after loading a plan, an **Open Workflow** button appears next to it — click to load that exact workflow file back into GenerateUI (asks for confirmation first, since it replaces whatever is currently loaded)
|
||||
- **Plan files** — Plan Save (silently overwrites the loaded plan) / Save As (always asks for a new name) / Plan Clear; plans are stored as `ws_labplan_<name>.json` in `user/default/Workflow-Studio/lab_plan/` (the `ws_labplan_` prefix is added automatically, v0.3.90 — type just the plain name when prompted), alongside an auto-generated `ws_labplan_<name>.png` index image (a 3-per-row contact sheet of up to 9 result thumbnails)
|
||||
- **Plan Load** — same drag-and-drop / click-to-browse drop zone as the Image slot; drop a plan's `.json` (read directly in the browser) or any of its index-image `.png`s — since v0.3.91 every index image carries the full plan embedded in it directly (see below), so it's read straight from the file with no server round-trip; older index images without that embedding fall back to fetching a same-named `.json` from the server
|
||||
- **Plan JSON tab** (v0.3.88) — view/edit the current plan as raw JSON (same shape saved to disk); Refresh re-reads it from the Setting tab, Apply to Setting parses your edits and writes them back into the Setting tab's columns/note/batch/chain-image/source-image/results — the same effect as loading that JSON as a plan file, without saving it first
|
||||
- **Save index image to Output on Run** (v0.3.90, on by default since v0.3.93) — checkbox in the run controls; when checked, every completed Run also builds the same contact-sheet index image used for Plan files and saves it directly into ComfyUI's own Output folder as `Lab_index_<counter>_.png` (auto-numbered like a normal generated image, right alongside the images that Run just generated); independent of Plan Save, which always writes its own copy next to the plan file regardless of this checkbox; saved with the plan as `save_index_on_run`
|
||||
- **Index images are self-contained plan files** (v0.3.91) — every index-image PNG, whether from Plan Save/Save As or from Save index image to Output on Run, carries the entire plan embedded directly in the file as a PNG `wfm_lab_plan` chunk; this is what lets the Output-folder copy above work as a Plan Load source even though it has no matching `.json` anywhere
|
||||
- **Eagle integration** — every image Lab generates is auto-saved to Eagle the same way as GenerateUI's own Generate button, if enabled in the Settings tab; the Output-folder index image above is included too (v0.3.90) once saved
|
||||
- **Select vs. edit, and keyframe reordering** (v0.4.8) — a single click on a keyframe cell now only selects it (blue outline); double-click to open its edit modal as before. Each column's header (Model / Prompt / KSampler) also gets **▲ / ▼** buttons that swap the selected keyframe with its immediate neighbor, reordering keyframes without retyping them; keyframe #1 (the live-reflecting baseline) can never move, and nothing can be swapped into its slot
|
||||
- **PG — apply a Prompt tab preset group** (v0.4.8) — a **PG** button on the Prompt column header opens a picker for the Prompt tab's Table-view preset groups (the same groups the Batch tab's checklist uses); choosing one replaces the entire Prompt column with one keyframe per preset in that group's order, starting at #1 (#1 is overwritten, not appended after). If the group has more presets than the current Batch count, Batch count is raised automatically to fit (capped at 50, the Batch input's own limit); anything still beyond that shows the existing "keyframes beyond Batch count" warning instead of being dropped
|
||||
- **Video workflow support** (v0.5.2) — loading a MiniMax H3 (or other all-in-one video-generation) workflow into GenerateUI and running Lab now works end to end: the Prompt column writes to its `prompt` widget, the KSampler column auto-hides (same "no matching node" treatment as Model sub-columns) since the sampler wired internally is a fixed part of the model's own preset rather than something meant to be tuned per keyframe, the Results grid plays mp4 results inline, and the contact-sheet index image draws each video result's last frame instead of failing silently onto a black square
|
||||
- **Use generated image for next, now video-aware** (v0.5.2) — when a Run's output is a video, the "Use generated image for next" chain extracts its last frame client-side (canvas) and uploads it as the next iteration's source image, instead of trying to feed the raw mp4 into a LoadImage node
|
||||
- **Plans from a story** (v0.9.5) — AI TOOL Chat's **Storyboard to Lab** skill loads a ready plan here via **Open in Lab**; KSampler cells now show every value that is set (Step / CFG / Denoise / sampler / scheduler / Seed) instead of "(workflow default)" when only the seed or sampler is set
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><h3>Prompt Tab</h3></summary>
|
||||
|
||||
- **3-column layout** — AI Assistant (left), Presets/Preset Manager tab-panel (center), Wildcard/Style support (right)
|
||||
- **AI chat assistant** — generate and refine prompts interactively using Ollama, LM Studio, Lemonade, or Unsloth (multi-backend: v0.5.4)
|
||||
- **⚙ Settings modal** (v0.5.4) — replaces the old central Settings-tab panel; opens a dedicated modal (Backend / Connection / Model / Generation / Unload / Save) scoped to this tab only, saved under its own `localStorage` key so it stays independent of the Tagger tab's VLM settings; **Thinking mode** and **Max tokens** apply to every chat request, and an **Unload** button frees the selected model from Ollama/LM Studio/Lemonade (Unsloth has no such API and is shown as unsupported)
|
||||
- **Image attachment** — attach reference images for vision-capable models
|
||||
- **Translation** — JA/EN/ZH translation buttons for multilingual prompt creation
|
||||
- **Prompt presets** — save/load reusable prompt templates (positive & negative) with category support
|
||||
@@ -72,10 +210,32 @@ Browse, organize, and execute workflows directly from a dedicated studio interfa
|
||||
- **Group management** — create groups, assign/remove presets, delete groups from the Presets panel
|
||||
- **Clipboard copy** — copy positive/negative prompts individually (PP Copy / NP Copy)
|
||||
- **GenUI Set** — apply preset prompts directly to the GenerateUI interface
|
||||
- **Wildcard/Style tab bar** (v0.3.96) — the right pane switches between the wildcard tools below and a Style manager (same pane, two modes)
|
||||
- **Wildcard input toolbar** — one-click buttons to insert `{|}`, `{n$|}`, `__|__`, `<lora::1:LBW=;>` and other wildcard syntax; wraps selected text when applicable
|
||||
- **Wildcard file manager** — create, view, and edit `.txt` / `.yaml` wildcard files stored in `user/default/Workflow-Studio/wildcard/`; click a filename in the file picker to insert `__filename__` at cursor
|
||||
- **Style manager** (v0.3.96) — create, edit, and delete registered Styles (the same ones used by GenerateUI's Style dropdown, the Batch tab, and the Style Catalog), using the same list→editor CRUD pattern as the Wildcard file manager above; each entry has a Name, a Positive prompt (supports the `{prompt}` placeholder, or appends if omitted), and an optional Negative prompt
|
||||
- **Source-file badge & in-place editing** — each list entry shows its defining file as a small badge next to its name (e.g. `sdxl_styles_diva.json`); renaming a style keeps its position in that same file rather than moving it; a name must be unique across all styles
|
||||
- **New styles go to a dedicated file** — created via **+ New**, a style is appended to its own `custom.json` inside the style folder, so the bundled style packs are never modified directly
|
||||
- **+ Add to this file** — while editing an existing style, this button clears the form for a brand-new entry that gets appended to that *same* file instead of the default `custom.json` — the way to add a style into one of the bundled packs
|
||||
- Saving, renaming, or deleting a style immediately refreshes GenerateUI's Style dropdown, the Batch tab's checklist, and the Style Catalog's name list — no reload needed
|
||||
- **Form / Table toggle** (v0.4.6) — two top-level tabs at the top of Prompt Tab: **Form** is the one-item-at-a-time editor described above; **Table** shows the same Presets / Wildcards / Style data all at once as editable spreadsheets, useful once there are more than a handful of items to manage
|
||||
- **Table view — Presets / Presets Group / Wildcards / Style** (v0.4.6) — four sub-tabs, each an editable table built from the exact same data as the Form tab above (changes on either side stay in sync)
|
||||
- **Row selection & bulk delete** — every table shares a left-most auto-numbered **#** column; click a number to select that row (multiple at once), then use the toolbar's **Delete** button to remove every selected row in one confirm, or **Deselect** to clear the selection — replacing per-row delete buttons, which were too easy to misclick
|
||||
- **Double-click to edit in a modal** — double-clicking a row's number opens a larger prompt-editing modal instead of the small in-table textarea; Presets/Style show Positive/Negative toggle buttons above one shared textarea (switching preserves unsaved text on the other side), Wildcards shows just the file content; Save writes back and closes the modal, Close discards changes
|
||||
- **Wildcard syntax toolbar in the Presets modal** (v0.4.7) — the same `{|}` / `__|__` / `<lora>` / file-picker toolbar as the Form tab's Wildcard composer appears above the Presets modal's textarea, since that's where a wildcard reference typically ends up; not shown in the Wildcards or Style modals (the Wildcard modal edits the raw file content itself, and Style prompts have no such wildcard-composer connection)
|
||||
- **+ New row** — the toolbar's **+ New ...** button adds a blank editable row with small ✓ (Add) / ✕ (Cancel) icons in place of its number
|
||||
- **Presets table** — **★** (favorite) and **B** (Batch group) columns work as toggle switches, same as the Form tab's Preset Manager; the toolbar's **BC** button clears the whole Batch group at once; **PP Copy** / **NP Copy** copy the single selected row's positive/negative prompt to the clipboard; a **group select + Add to Group** control bulk-adds every selected preset to a chosen group in one click — searching/selecting from the table itself (rather than a long per-group preset picker) keeps group assignment usable once there are many presets
|
||||
- **★ / B sort toggles** (v0.4.7) — toolbar buttons next to the search box bring favorited and/or batch-selected presets to the top of the list; both can be enabled together (★ takes priority, B breaks ties), and everything else keeps its original relative order; toggling a row's own ★/B while a sort is active re-sorts immediately
|
||||
- **Presets Group table** — create, rename, and delete groups, with each group's members shown as removable badges; the reserved **Batch** group is not listed here — it's managed entirely through the Presets table's B column and BC button instead
|
||||
- **Wildcards table** — same files as the Form tab's Wildcard file manager above; editing the File path or the Ext dropdown renames the file (saves the content under the new name, then removes the old file)
|
||||
- **Style table** — same styles as the Form tab's Style manager above, editable inline the same way as Presets
|
||||
- **+ Add to this file** (v0.4.8) — select exactly one row whose File badge isn't `custom.json` to enable this toolbar button, bringing the Form tab's same-file-add capability (above) to the Table view too; it adds a blank row targeting that same file (shown as a badge in the File column even before saving); custom.json entries and multi-row selections leave it disabled — use the regular + New Style button for those instead
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><h3>Settings Tab</h3></summary>
|
||||
|
||||
### Settings Tab
|
||||
- **2-column layout** — left column for all settings; right column shows the Theme panel fixed in place (sticky)
|
||||
- **Collapsible sections** — all settings organized in accordion panels for a clean layout
|
||||
- **Theme selection** — 13 built-in themes with visual swatch preview (Dark, Pop, Minimalist, Cyberpunk, Glassmorphism, Neumorphism, Retro Pixel, Pastel, Brutalism, Earthy, Material, Monotone, Corporate)
|
||||
@@ -83,70 +243,330 @@ Browse, organize, and execute workflows directly from a dedicated studio interfa
|
||||
- **Workflows directory** — configure which folder to scan for workflows
|
||||
- **Gallery output directory** — configure which output folder the Gallery tab scans for images
|
||||
- **Eagle connection** — set Eagle API endpoint for auto-save
|
||||
- **Ollama connection** — configure Ollama server URL
|
||||
- **CivitAI Host** — choose which site opens when clicking a model link: `civitai.com` (SFW only) or `civitai.red` (unrestricted); saved to `settings.json` and synced to `localStorage` for the Models tab to use without extra fetches
|
||||
- **CivitAI API Key** — optional Bearer token for authenticated CivitAI access; stored in `settings.json` (excluded from data exports); environment variable `CIVITAI_API_KEY` takes priority if set
|
||||
- **Default workflow** — set a workflow to auto-load on startup
|
||||
- **Data Management** — export all plugin data (settings, metadata, prompts, etc.) to a single JSON file; import to restore data (useful when migrating or reinstalling)
|
||||
- **Default Checkpoint** (v0.3.73) — optional checkbox to force every checkpoint loader node's model to a chosen default whenever a workflow is loaded into GenerateUI; a safeguard against generation errors or garbled images from a stale/mismatched checkpoint saved in the workflow file
|
||||
- ~~AI Assistant Settings~~ (removed in v0.5.4) — the central Ollama backend/URL/model panel that used to live here was replaced by a ⚙ Settings button + modal directly in the Prompt tab and the Tagger tab, each with its own independent configuration (backend, URL, model, Thinking mode, Max tokens, and a model Unload button) — see those tabs below; the AI TOOL tab's own Settings pane is unaffected
|
||||
- **VRAM Management (Ollama)** (v0.7.13) — right before every image generation from Workflow Studio (GenerateUI, Lab, batches, Video, AI TOOL chat generation — anything that goes through its queue), unload the models Ollama has loaded so ComfyUI has free VRAM. **Before generating**: Do nothing (default) / Unload only as much as needed when free VRAM is below a target (biggest model first, one at a time, stopping once the target is reached) / Unload everything every time; **Target free VRAM (GB)** for the second mode; **Unload all now** button. Free VRAM is measured with `nvidia-smi` (plus ComfyUI's own unused torch cache), because ComfyUI's free-VRAM figure may not change when Ollama loads a model; non-NVIDIA GPUs fall back to ComfyUI's value. Targets Ollama on localhost — the default `127.0.0.1:11434` plus the AI TOOL / Prompt / Tagger AI settings and the Decision Model when they use Ollama (other hosts only via `WFS_ALLOWED_BACKEND_HOSTS`); LM Studio etc. and ComfyUI's own models are not touched. A toast reports what was unloaded, an unreachable target or a failure; generation continues either way. Running a workflow from the ComfyUI canvas itself is not covered. Server route: `POST /api/wfm/vram/prepare` (JSON only). Ported from ComfyUI Comic Creator
|
||||
- **Video Playback Volume** (v0.5.4) — the video preview's volume is remembered here and shared across every video player in the plugin (Video tab, Gallery tab), instead of resetting to maximum whenever a different video is opened
|
||||
- **Data Management** — export core settings/metadata/prompts/CivitAI cache to a single JSON file; import to restore data (useful when migrating or reinstalling); API keys are excluded from exports for security
|
||||
- **Full Backup (ZIP)** (v0.5.2) — additionally covers what the JSON bundle can't represent: folder-based data (AI Skills, Lab Plans, Video Plans, Video Edit projects, Style presets) and the Tagger SQLite database; two opt-in checkboxes can also include ComfyUI's default workflows folder (`user/default/workflows`) and the Impact Pack's wildcard folder in the export — both of those are export-only and stored under an `_external/` prefix in the ZIP that Restore always skips, since auto-overwriting files a different plugin/ComfyUI core manages would be unsafe; copy them back by hand if needed. A third opt-in checkbox (v0.7.6) bundles the clips/BGM/sounds/overlay clips that saved Video Edit projects reference in ComfyUI's input folder (the project JSON only stores references) under `_video_edit_media/`; unlike `_external/`, these are restored into the input folder, never overwriting a file that already exists there. Restoring overwrites existing files; restart ComfyUI afterward for either restore path
|
||||
- **Text Size** — one slider (10–28 px) adjusts font size for all prompt and chat textareas at once: Generate UI positive/negative prompts, AI Assistant chat input, Preset prompts, Wildcard prompt and file editor, and Metadata prompt full preview; takes effect immediately and saved with Save Settings
|
||||
- **RAW JSON Colors** — customize the 6 syntax highlight colors for the Raw JSON editor in Generate UI: Default Text (base), Name/Scheduler (yellow), Title (pink), Width/Height (green), Prompt/Text (cyan), Image/File (red); changes apply immediately on color pick; Reset Defaults restores the original scheme; saved to `localStorage` under `wfm_settings.jsonColors` and applied on startup
|
||||
- **GenerateUI Model Tab Highlight** (v0.3.98) — pick the color used to mark Checkpoint/VAE/Diffusion Model/Text Encoder/ControlNet/Hypernetwork labels and the LoRA column header in GenerateUI's Model tab when the loaded workflow actually contains that type of node; default bright green; changes apply immediately, Reset Defaults restores it; saved to `localStorage` under `wfm_settings.modelTabActiveColor`; the same color and mechanism also drives the Video tab's field highlighting (v0.5.4, see above)
|
||||
- **Wildcard Integration** — link the WFS wildcard directory to ComfyUI-Impact-Pack's `wildcards/` directory (directory junction on Windows, symlink on other OS); existing WFS wildcard files are automatically migrated; requires [ComfyUI-Impact-Pack](https://github.com/ltdrdata/ComfyUI-Impact-Pack)
|
||||
- **G'MIC-Qt Integration** — set the path to `gmic_qt.exe` for the Image Edit Filter tool; download G'MIC-Qt Standalone from `gmic.eu/download.html` (Windows: `gmic_qt-win64.zip`), extract anywhere, then enter the full path to `gmic_qt.exe` and click Save
|
||||
- **Language** — English / Japanese / Chinese
|
||||
|
||||
### Gallery Tab (v0.3.1)
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><h3>Gallery Tab (v0.3.44)</h3></summary>
|
||||
|
||||
- **Output / ImagePrompt / Style_Catalog / Metadata sub-tabs** (v0.3.94, v0.3.95, v0.4.6) — four sub-tabs at the top of the Gallery tab: **Output** (the image browser described below), **ImagePrompt** and **Style_Catalog** (separate visual libraries — see their own sections below), and **Metadata** (embeds the full Metadata tab — see its own section below)
|
||||
- **Image browser** — browse ComfyUI output images (Thumbnail / Table views) with server-side scanning optimized for 6,000+ image libraries
|
||||
- **Folder tree root label** (v0.3.90) — the root entry in the folder tree is labeled simply **[root]**, no longer suffixed with the scanned folder's own directory name (which could be a misleading, environment-specific name — e.g. StabilityMatrix installs where the output folder is a symlink named `Text2Img` — even though the folder holds every kind of generated output, not just text-to-image results)
|
||||
- **Thumbnail / Table views** — switch view modes; Favorites column shown leftmost in Table view
|
||||
- **Folder management** — create subfolders ("+ New") or delete the selected folder with all contents ("Del") from the folder tree header
|
||||
- **File operations** — move or delete individual images from the detail panel's Info tab; bulk Move To... and Delete from the multi-select bar
|
||||
- **Multi-select** — Ctrl+click to select multiple images; Bulk Bar appears for batch operations (group, favorite, move, delete)
|
||||
- **File operations** — move or delete individual images from the detail panel's Info tab; bulk Move To..., Export, and Delete File from the multi-select bar
|
||||
- **Download** (v0.5.0) — a dedicated orange **Download** button in the detail panel's action-button row (next to Tagger); replaces the old preview-image hover overlay, which blocked video playback controls
|
||||
- **MP4 video support** (v0.5.0) — `.mp4` files are browsable, previewable (detail panel with native `<video controls>`, lightbox, and Compare), and included in favorites/tags/groups/move/delete/export alongside images; server-side thumbnails are generated from the first video frame via PyAV (falls back to a placeholder if PyAV/ffmpeg decoding isn't available); a small ▶ badge overlays video thumbnails in the grid
|
||||
- **MP4 embedded metadata** (v0.5.1) — the Prompt and JSON tabs now also work for `.mp4` files: reads the `workflow`/`prompt` container tags ComfyUI's `SaveVideo` writes into the mp4 (via PyAV server-side), including all-in-one video-generation nodes that carry their prompt directly on a `prompt` input rather than a separate `CLIPTextEncode`-style node (e.g. `MiniMaxH3ImageToVideo`)
|
||||
- **WebM support** (v0.7.14) — `.webm` files get the same treatment as `.mp4` everywhere above (browsing, thumbnails, dimensions/duration, embedded workflow/prompt metadata, favorites/tags/groups/move/delete/export, Compare, Comic Creator video send): all the video-specific code paths go through PyAV, which handles both containers identically, so no format-specific logic was needed beyond recognizing the extension
|
||||
|
||||
- **Embedded metadata reading fixes** (v0.8.0) — PNG chunks appended after `IEND` (ComfyUI-Custom-Scripts writes `workflow` there) are now read; `.webp` files expose their EXIF `workflow`/`prompt` to the Prompt and JSON tabs; images without a ComfyUI workflow (A1111 / Forge / Fooocus) show their `parameters` prompts in the Prompt tab; API-format `ImageMetadataLoRALoader` LoRAs are listed in the Metadata tab and the side-panel I tab
|
||||
- **Audio support** (v0.8.0) — `.wav` / `.mp3` / `.ogg` / `.m4a` / `.flac` / `.opus` files are browsable alongside images and videos (for ComfyUI music generation output): thumbnails are waveform images generated server-side (PyAV, cached), the detail panel / lightbox / Compare show the waveform with a built-in audio player (shared volume setting with videos), the Info tab shows the duration, and the Prompt / JSON tabs read the `prompt` / `workflow` tags that SaveAudio-type nodes embed (FLAC / MP3 / Opus); favorites, tags, groups, move, delete, and export work as for other files, while image-only actions (PSD export, Edit Layers) skip audio; in the Video tab's Asset sub-tab, audio files added to the Video Assets group appear with an "Audio Only" filter, an inline player, and **Set as BGM** / **Add as sound** buttons that feed the Edit sub-tab
|
||||
- **File conversion** (v0.8.0) — a **Convert...** button in the Gallery bulk bar (shown when the selection contains audio or video) converts audio files to FLAC / MP3 / Opus / M4A / WAV, or extracts the audio track of videos, using PyAV (no system ffmpeg needed); bitrate, sample rate (44.1 / 48 kHz) and channels (mono / stereo) are selectable, output goes next to the source as a new file (`name.ext`, or `name_converted.ext` if taken). ComfyUI `prompt` / `workflow` tags (and title / artist / album tags) are carried over to formats that can hold them — WAV cannot, so they are skipped there; favorite / tags / memo / groups can be carried over, and the original can optionally be deleted after a successful conversion (with a confirmation). `.ogg` is readable but not offered as an output (the bundled PyAV has no Vorbis encoder)
|
||||
- **Move To folder filter** (v0.8.0) — the Move To dialog (detail panel and bulk bar) has a filter box that narrows the folder list by name or path (space = AND), Enter moves to the first match; the move toast now reads "Moved N file(s)" since audio/video files are moved too
|
||||
- **Semantic Search** (v0.8.2) — find images by meaning instead of keywords. The **S** button next to the search box turns it on: the search box then takes a free-text description (e.g. "sunset city street"), Enter searches, and results are ordered by similarity with a score badge on each thumbnail. Turning **S** on also shows a second toolbar row (left-aligned): **Similar** (lists images similar to the selected one; selecting another image keeps the list, **↻** re-runs it for the newly selected image, pressing Similar again returns to the normal list), the **⚙** settings button, and the result count. Searches cover the selected folder and its subfolders; sort and tag/group filters do not apply to semantic results
|
||||
- **Index window (⚙)** — three tabs. **Index**: target folder (optionally with subfolders), "new/changed only" or "rebuild all", progress bar, stop, delete all. **Model**: choose with radio buttons between **Gemini Embedding 2** (API; set `GEMINI_API_KEY` in the plugin's `.env` and restart ComfyUI — the free tier exists but content sent on it may be used by Google to improve its products, beyond it the API is paid) and **EmbeddingGemma 2** (runs locally in Ollama, free, no key), plus vector size (Gemini 768 / 1536 / 3072, EmbeddingGemma 2 128 / 256 / 512 / 768), and for EmbeddingGemma 2 the Ollama URL and the model size (740m or 440m). **Search**: minimum score for similar-image results (e.g. `0.6` shows only images scoring 0.6 or higher), minimum score for text search, and maximum results — stored per model because score levels differ between models
|
||||
- **Index state in the folder tree** — a green dot next to a folder's image count means every image directly in that folder is indexed; the index is one shared store, so folders can be indexed one at a time. Images, plus videos / PSD via their thumbnails (audio is skipped), are embedded; changing the model, vector size or image precision requires "Rebuild all"
|
||||
- **EmbeddingGemma 2 in Ollama** — download the model with `ollama pull embeddinggemma-2:740m` (text + image + audio) or `ollama pull embeddinggemma-2:440m` (text + image, smaller). Both return identical vectors, so you can switch sizes without rebuilding (`:latest` is the same as 740m and is used when 740m is missing; 270m / 570m cannot embed images). Images are sent 4 per request (≈0.1–0.2 s per image on an NVIDIA GPU) and retried automatically when Ollama drops a connection. The model is unloaded from VRAM when indexing finishes. Indexes built with the earlier built-in ONNX runtime keep working (cos ≈0.97 with the Ollama vectors); use "rebuild all" to regenerate them exactly. Other Ollama hosts must be listed in `WFS_ALLOWED_BACKEND_HOSTS`
|
||||
- **Audio waveform colors** (v0.8.0) — waveform thumbnails are colored per format (MP3 blue, WAV green, FLAC amber, OGG/Opus purple, M4A rose)
|
||||
- **Info tab: dimensions & duration** (v0.5.1) — the detail panel's Info tab now also shows image dimensions (width×height) or video duration, in addition to filename, size, date, tags, and memo
|
||||
- **Multi-select** — Ctrl+click to select multiple images; Bulk Bar appears for batch operations: select group → "Add to Group" / "Remove from Group"; Favorite All / Unfavorite All; Compare (2–4 images); Move To...; **Export** (downloads all selected images as a ZIP file); **Create PSD** (v0.6.0, combines the selected images into one layered PSD file, positioned top-left on a canvas sized to the largest image); **Edit as Layers** (v0.6.0, opens all selected images in the Image Edit tab at once, each as its own layer); Delete File
|
||||
- **Image Compare** — select 2–4 images with Ctrl+click, then click "Compare" in the Bulk Bar to open a side-by-side lightbox; grid adapts to the number of selected images
|
||||
- **Prompt search** — text search covers filename, tags, memo, and prompt text (A1111 `parameters` field cached on first detail panel open)
|
||||
- **Server-side filtering** — filter by group, favorites, or tags with fast server-side set lookup (no full rescan)
|
||||
- **Group management** — create, rename, delete groups and assign/remove images using the same 4-section panel as Models tab
|
||||
- **Group management** — create, rename, delete groups and assign/remove images using the same 4-section panel as Models tab; **`__Feeder__`** is a reserved group (🔒 prefix) that cannot be renamed or deleted; used by the Feeder Gallery mode to define the generation queue; **FC** button in the toolbar clears all members without deleting the group
|
||||
- **Thumbnail F button** — cyan overlay button (top-left of each image card) toggles the image's membership in the `__Feeder__` group; cyan and always-visible when the image is in the group; visible on hover only when inactive
|
||||
- **Favorites** — star images inline without reopening the detail panel
|
||||
- **Detail panel** — view filename, path, tags, groups, and metadata in a slide-out panel
|
||||
- **Workflow viewer** — Metadata tab displays workflow JSON from PNG embedded data (`prompt` / `workflow` keys) or from workflow saved by the Generate UI tab
|
||||
- **Detail panel** — view filename, path, tags, groups, and metadata in a slide-out panel; four or five tabs — **Info** / **JSON** / **Groups** / **Prompt** / **Nanobanana** (only for `cc_nanobanana`-folder images, see below)
|
||||
- **Prompt tab** (v0.4.7) — selected by default (the most frequently checked piece of info shouldn't need an extra click); lists every positive/negative prompt candidate found in the embedded workflow with POS/NEG badges, reusing the exact same list→click→full-text UI as the Metadata tab; extracts from the API-format embedding when available rather than the UI-format one, since a workflow with independent top-level and subgraph sampling chains (e.g. Krea-2) can otherwise have some of its prompts missed; hidden entirely for images in the `cc_nanobanana` folder (see Nanobanana tab below), since they carry no embedded ComfyUI workflow to extract a prompt from
|
||||
- **Nanobanana tab** (v0.7.14) — shown only for images in a `cc_nanobanana` folder (written by ComfyUI Comic Creator's Nanobanana tab) that have a matching entry in that folder's `history.jsonl` generation log; shows engine, model, image size, seed, timestamp, and the prompt/negative prompt actually used — the same info is also surfaced in the Metadata tab (see below) when opened from here via the **Metadata** button
|
||||
- **Gemini / Nano Banana nodes** (v0.8.5) — images generated by ComfyUI's native Nano Banana nodes (`GeminiNanoBanana2V2` etc., e.g. via ComfyUI Comic Creator's "ComfyUI native node" engine) are readable like any other ComfyUI image: the Metadata tab and the side-panel I tab show the prompt (in the prompt list, including the appended `NEGATIVE_PROMPT:` text), the model name (under Diffusion Model, e.g. `Gemini Nano Banana 2.1`) and the seed; these images need no history file and are not special-cased like the `cc_nanobanana` folder (API-format workflows only)
|
||||
- **MOSS-Image in GenerateUI** (v0.8.8) — the official MOSS-Image templates (Base / SFT, T2I and the bounding-box layout versions) load and run from GenerateUI; a custom (non-official) manga workflow using MOSS-Image Base with the 8-step distillation LoRA was also tested and works. The `MOSSImageLayoutPrompt` text is edited as the positive prompt, `CreateBoundingBoxes` converts correctly (the boxes themselves are still drawn on ComfyUI's canvas), and the Gallery Prompt tab, Metadata tab and side-panel I tab read the prompt, models and sampler settings of MOSS images. Newer frontends save subgraph widget values by name (`widgets_values_named`); these are now read correctly, so model names and sampler values no longer shift
|
||||
- **Faster GenerateUI Check / conversion** (v0.8.8) — the first conversion or check used to download the full `/object_info` (tens of MB, 40+ s on installs with many custom nodes); it now fetches only the node types the workflow uses (about 0.25 s) and caches them per type
|
||||
- **Partner API nodes in GenerateUI** (v0.8.6) — workflows containing ComfyUI's partner API nodes (Nano Banana / Gemini image nodes, etc.) can be run from GenerateUI. These nodes need Comfy credentials in the `/prompt` request's `extra_data`, which ComfyUI's own screen adds automatically but a separate page cannot: add `COMFY_API_KEY=...` (a Comfy API key issued at platform.comfy.org) to the plugin's `.env` and restart ComfyUI. With it set, GenerateUI queues prompts through the plugin server (`/api/wfm/partner/prompt`), which adds the key only when the workflow contains an API node (`api_node` in `/object_info`) and only for this ComfyUI instance; the key never reaches the browser, and usage is billed as Comfy credits. Without a key, an authentication error now shows how to set it up. A Gemini image node's prompt shows in the Prompt tab (reference images go through `LoadImage` in the Image tab); sample: `ws_nano_banana_2_1_t2i`. Also fixed: UI-format → API-format conversion misaligned `widgets_values` for nodes whose DynamicCombo option has socket sub-inputs (Nano Banana 2.1's `images` / `files`) or a widget right after a `control_after_generate` seed; Gallery now shows the Prompt tab for `cc_nanobanana`-folder images that carry embedded metadata (images made through Comic Creator's ComfyUI native node engine)
|
||||
- **Workflow viewer** — Metadata tab displays workflow JSON from PNG embedded data (`prompt` / `workflow` keys) or from workflow saved by the Generate UI tab; **Copy & Send Canvas** button copies the JSON to the clipboard and sends the workflow directly to the ComfyUI canvas (UI and API formats both supported)
|
||||
- **GenUI button** (renamed from "Load GenUI" in v0.5.0 for readability) — loads the embedded ComfyUI workflow from the selected image directly into the GenerateUI tab; shows a warning toast if no workflow is embedded or the format is unsupported; Metadata button is styled green, GenUI button uses the primary accent color
|
||||
- **Image Edit button** — toolbar button; sends the selected image directly to the Image Edit tab as the base layer; PSD files (v0.6.0) are fully decomposed into their original layers instead of being flattened into one image
|
||||
- **Send GenUI Image button** — toolbar button (next to Image Edit); uploads the selected image to ComfyUI and sets it as the input for the first LoadImage node in the GenerateUI tab; automatically switches to GenerateUI → Input → Image; requires a workflow with at least one LoadImage node to be loaded
|
||||
- **Send to LI node button** (v0.5.2) — toolbar button (next to Send GenUI Image); uploads the selected image and writes its filename into the `image` widget of the node currently selected on the ComfyUI canvas (falling back to the first LoadImage-type node found) — same destination and cross-window bridge as the Image Edit tab's **Send to LI node** button (renamed from "Send to Workflow" in this same release), so both entry points now share one consistent name; requires Workflow Studio to have been opened from ComfyUI's top menu button
|
||||
- **Send to LV node button** (v0.7.14) — toolbar button (next to Send to LI node), the video equivalent: uploads the selected video and writes its filename into the `file` widget of the node currently selected on the ComfyUI canvas, restricted to ComfyUI's native **Load Video** node (`LoadVideo`) since `file` as a widget name isn't unique enough to search for generically the way `image` is; only enabled when the selected item is a video (mp4/webm); same cross-window bridge and launch requirement as Send to LI node
|
||||
- **Send CC Layout / Send CC Image buttons** (v0.3.69, split in v0.8.11) — toolbar buttons, shown only when this Gallery tab is embedded as an iframe inside ComfyUI Comic Creator (a separate custom node). **Send CC Layout** sends the selected image directly into Comic Creator's Layout tab (the currently selected panel/overlay); when the selected file is an MP4 video (v0.6.3), it is routed to the Layout-tab Video tool instead — inserted as a new video object in the selected panel (playable, capturable to a still frame) rather than as a flattened image. **Send CC Image** (v0.8.11) switches Comic Creator to its Image tab and loads the selected image there — as a new layer if a document is already open, otherwise as a new canvas; videos are not supported there and show an info toast. Requires a Comic Creator version that provides `window.sendImageToImageTab` (the one released together with v0.8.11).
|
||||
- **Search clear (✕)** — inline ✕ button appears inside the search box whenever text is entered; click to clear immediately
|
||||
- **Clear all filters (✕ Clear)** — toolbar button next to the view-mode (Thumbnail/Table) switch (v0.5.2, moved from the toolbar's rightmost position so it sits with the other display-affecting controls); resets search text, tag filter, group filter, and favorites filter in one click (sort order is preserved)
|
||||
- **Workflow auto-save** — images generated from the Generate UI tab have their workflow automatically saved to gallery metadata
|
||||
- **Output folder configurable** — set the scanned output folder from Settings tab
|
||||
- **Performance** — folder-level mtime cache (30s TTL) for fast incremental refresh; tree expansion state preserved across folder operations
|
||||
- **SVG file support** (v0.3.77) — `.svg` files are browsable, previewable (detail panel and lightbox), and included in favorites/tags/groups/move/delete/export alongside raster formats; served as-is with no rasterized thumbnail, since `<img>` scales vector graphics natively at any size
|
||||
- **PSD file support** (v0.6.0) — `.psd` files are browsable alongside other formats; thumbnails and full-size previews show every layer merged together (hidden layers excluded), rendered server-side via `psd-tools` and disk-cached; the underlying PSD file itself is never modified — only the Gallery preview is a flattened rendering
|
||||
- **3D model support** (v0.9.4) — `.glb` / `.gltf` / `.vrm` / `.ply` (mesh, point cloud or Gaussian splat) / `.spz` files are browsable alongside images with a **3D** badge and open in a built-in viewer in the detail panel, lightbox and compare view (drag to rotate, right-drag to pan, wheel to zoom). Thumbnails are rendered by your browser the first time a file appears and then kept on the server (files over 128 MB get one when opened). Workflows saved by ComfyUI's SaveGLB are read like an image's. A `.gltf` using separate `.bin` or texture files needs them to stay in place: Move and Delete only affect the `.gltf` itself. KTX2-compressed textures are not supported
|
||||
- **Performance** — server-side 256px JPEG thumbnail generation with disk cache (`data/thumb_cache/`); infinite-scroll paging (50 images per page, IntersectionObserver); folder-level mtime cache (60s TTL); bulk operations use single-request API endpoints
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><h3>ImagePrompt Gallery subtab (v0.3.94, renamed from Style/Prompt in v0.3.95)</h3></summary>
|
||||
|
||||
- **Visual prompt library** — a Gallery sub-tab for browsing reference images and building prompts from them visually, separate from the Output browser; manages a dedicated `ws_image_prompt` folder, created automatically inside the ComfyUI output directory
|
||||
- **3-column layout** — folder tree (left) | thumbnail grid (center) | prompt builder (right); selecting any folder (including a parent category folder) recursively shows every image in its subfolders too, both in the grid and in the tree's count badges
|
||||
- **Prompt builder (right pane)** — clicking a thumbnail previews it and its prompt text without adding it yet; **+ Add** appends it as a removable chip under "Selected Prompts" (**Clear All** to reset); **Save** edits and persists the prompt text for that image; **Final Prompt** combines all chips into one comma-separated, freely-editable text; **Copy** sends it to the clipboard
|
||||
- **Plain-text prompt storage** — each image's prompt lives in a `.txt` sidecar file next to it (same base name, no database) — anyone can add their own entries by dropping an image + matching `.txt` file into a subfolder; the Output Gallery's own detail panel reads and displays the same file when browsing into `ws_image_prompt`
|
||||
- **ponyxlWildcardsVault format support** — if no `.txt` sidecar exists, prompts are resolved on the fly from a `*.yaml` + `thumbnails/` (also `thumbnails_option2/`) pack placed directly under the folder, using the same key/tag structure as Navimixu's [PonyXL Wildcards Vault](https://civitai.com/models/615967/ponyxl-wildcards-vault) packs — just drop the downloaded pack folder in, no import step required
|
||||
- **Seed data importer** — `tools/import_style_prompt_seed.py` (dev tool, ships no image data) pre-processes a wildcards-vault-style source folder into portable image + `.txt` pairs under `ws_image_prompt`, for archiving a stable, portable copy instead of relying on the on-the-fly YAML fallback
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><h3>Style_Catalog Gallery subtab (v0.3.95)</h3></summary>
|
||||
|
||||
- **Visual Style picker** — a third Gallery sub-tab for picking a registered GenerateUI Style (`user/default/Workflow-Studio/style/*.json`) by its preview image instead of its name in a dropdown; manages a dedicated `ws_style_catalog` folder, created automatically inside the ComfyUI output directory; populated by GenerateUI's **Create Catalog** button (see GenerateUI Tab above)
|
||||
- **3-column layout** — folder tree (left) | thumbnail grid (center) | Positive/Negative prompt panel (right); like ImagePrompt, selecting a parent folder recursively shows every image in its subfolders
|
||||
- **Positive/Negative panel** — clicking a thumbnail reads the Positive/Negative prompt actually embedded in that generated image (reusing the Metadata tab's extraction logic — no separate metadata store), each with its own **Copy** button
|
||||
- **Select as Style button** — matches the selected image's filename (without extension) against a registered Style name and switches the GenerateUI tab's Style dropdown to it; a visual shortcut into the existing named-Style system, not a one-off apply of the embedded prompt — if the Style was renamed or deleted since the catalog image was created, a "no matching style" toast is shown instead
|
||||
- **Load in GenerateUI / Open in Metadata Tab buttons** (v0.3.96) — read the workflow embedded in the catalog image itself (a byte-identical copy of the original output image, so it carries the same PNG metadata) and either load it straight into the GenerateUI editor or open the image in the Metadata tab — no need to hunt down the original file in the Output folder, and works even on catalog images created before this feature existed
|
||||
- **Double-click to enlarge** (v0.3.96) — double-click a thumbnail in the center grid, or the selected-image preview in the right panel, for the same full-size lightbox view as the Output Gallery
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><h3>Metadata Gallery subtab (v0.3.8, moved from a top-level tab in v0.4.6)</h3></summary>
|
||||
|
||||
- **Now inside Gallery** (v0.4.6) — this used to be its own top-level tab; it's now the fourth Gallery sub-tab, to the right of Style_Catalog — everything below works exactly the same as before
|
||||
- **3-column layout** — Drop zone (left) | Model info + LoRA + Prompt (center) | Settings + Nanobanana (right, v0.7.14 — LoRA and Prompt moved here from the right column, swapping places with these two new sections)
|
||||
- **File drop** — drop a ComfyUI-generated PNG / WebP / MP4 or workflow JSON onto the drop zone (or click to open a file picker); PNG/WebP images are shown as a preview
|
||||
- **MP4 embedded metadata** (v0.5.1) — reads the `workflow`/`prompt` container tags ComfyUI's `SaveVideo` writes into the mp4's `moov/udta/meta` box (parsed client-side, no server round-trip); also recognizes all-in-one video-generation nodes that carry their prompt directly on a `prompt` input instead of a separate `CLIPTextEncode`-style node (e.g. `MiniMaxH3ImageToVideo`); WebM isn't supported here (this parser only understands MP4's ISO-BMFF container) — the Gallery tab's own video metadata reading (PyAV-based, see Gallery Tab above) covers WebM instead
|
||||
- **Settings section** (v0.7.14) — image size (width×height) and, when the embedded workflow has a KSampler-type node, its Seed / Steps / CFG / Sampler / Scheduler / Denoise values, read from the API-format embedding's named inputs (UI-format workflows are converted through the same UI→API path GenerateUI uses first)
|
||||
- **Nanobanana section** (v0.7.14) — shown only for images from ComfyUI Comic Creator's Nanobanana tab (a `cc_nanobanana`-folder image opened via the Gallery tab's **Metadata** button, with a matching entry in that folder's `history.jsonl` log); shows engine, model, image size, seed, timestamp, and the prompt/negative prompt actually used — since these images carry no embedded ComfyUI workflow, this section's data replaces what would otherwise be a "no metadata found" error, with the rest of the layout (Checkpoint/LoRA/Prompt/Settings) simply staying empty
|
||||
- **Model extraction** — automatically extracts Checkpoint, VAE, Diffusion Model, and Text Encoder names from the workflow; supports both standard and subgraph-based workflows (Flux.2 Dev/Klein, Qwen-Image-Edit/2511/Layered, Z-Image Base/Turbo, Ernie Image, WAN2.2, Mage-Flow, LongCat, Boogu, HiDream E1, FireRed, Krea-2 Turbo, MOSS-Image); node types covered: UNETLoader, UnetLoaderGGUF, UNETLoaderGGUF (e.g. HiDream GGUF), CLIPLoader, DualCLIPLoader, TripleCLIPLoader, QuadrupleCLIPLoader (e.g. HiDream 4-CLIP)
|
||||
- **LoRA extraction** — lists all LoRA models with `strength_model / strength_clip` values
|
||||
- **Prompt extraction** — lists prompts with POS / NEG badges when positive/negative can be determined; when distinction is not possible (e.g. `SamplerCustomAdvanced`, intermediate nodes, cross-level connections), prompts are shown without a badge as plain **Text**; click any entry to view the full text below
|
||||
- **CLIP Text Encode edit+ support** (v0.3.92) — `CLIPTextEncodeEditPlus` nodes are resolved using the same RAW / EDIT / front / back combination rule as the node itself, correctly merging the linked `text1` (e.g. a Lora Manager's trigger words) with the editable `text_edit` field instead of showing only one side
|
||||
- **Custom multi-output text node fix** (v0.7.14) — nodes whose text output comes from a differently-named widget (e.g. ComfyUI-LiveChatStream's `response`/`positive`/`negative` outputs, backed by `response_text`/`prompt_text`/`negative_text` widgets) previously resolved to nothing when the API-format embedding was used, since the generic key lookup didn't recognize those widget names — LiveChatStream is now resolved by name explicitly; confirmed working with response text up to 40,000 characters
|
||||
- **Prompt actions** — Copy to clipboard, **GenUI:P/N** (set GenerateUI positive/negative prompt), **Prompt:P/N** (set Prompt tab preset positive/negative)
|
||||
- **Format support** — ComfyUI PNG/WebP/MP4/JSON (standard + Flux.2 / Qwen-Image / Z-Image / Ernie Image / WAN2.2 / Mage-Flow / LongCat / Boogu / HiDream E1 / FireRed / Krea-2 Turbo / MOSS-Image subgraph workflows), SD WebUI, SD Forge, Fooocus
|
||||
- **Format note** — supported formats and covered model types are always shown in the left column
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><h3>Nodes Tab (v0.1.7)</h3></summary>
|
||||
|
||||
### Nodes Tab (v0.1.7)
|
||||
- **Node Browser** — browse all installed ComfyUI nodes from `/object_info` API with Card/Table views
|
||||
- **Search & Filter** — full-text search, filter by category, package, tags, groups, and favorites
|
||||
- **Package badges** — color-coded badges generated from package names
|
||||
- **Node detail panel** — view I/O specifications, edit tags, manage groups
|
||||
- **Node Sets** — save multiple nodes + connections as reusable sets from the ComfyUI canvas
|
||||
- **Right-click context menu** — "Save as Node Set" option on any node in ComfyUI
|
||||
- **Multi-select** — Ctrl+click to toggle individual nodes, Shift+click for range selection; bulk action bar appears with: add to group / remove from group / create & add group / bulk favorite / unfavorite
|
||||
- **Search clear (✕)** — inline ✕ button appears inside the search box whenever text is entered; click to clear immediately
|
||||
- **Clear all filters (✕ Clear)** — rightmost toolbar button; resets search text, category, package, tag, group, and favorites filter in one click
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><h3>Models Tab (v0.2.3)</h3></summary>
|
||||
|
||||
### Models Tab (v0.2.3)
|
||||
- **Model Browser** — browse all installed ComfyUI models (Checkpoint, LoRA, VAE, ControlNet, UNET, TextEncoder, Hypernetwork, Embedding) with sub-tab switching
|
||||
- **Thumbnail / Card / Table views** — switch between view modes with pagination (24 items per page)
|
||||
- **Thumbnail / Table views** — switch between view modes with pagination (24 items per page); Table view includes **Type** and **Base Model** columns sourced from cached CivitAI data, displayed between the Subdirectory and Extension columns; Enable/Disable column labeled **E/D**
|
||||
- **Table column sort** — click any column header to sort ascending (▲), click again for descending (▼), click a third time to clear; active column highlighted in accent color
|
||||
- **Search & Filter** — full-text search, filter by tags, groups, and favorites
|
||||
- **User-defined badges** — assign free-label badges to models; badge colors shared with the Workflow tab palette
|
||||
- **Side panel tabs** — Info (file path display with click-to-copy, tags, memo), Groups management, CivitAI integration
|
||||
- **CivitAI integration** — fetch model metadata by SHA256 hash, view base model, trained words, tags, and model page link
|
||||
- **Batch CivitAI fetch** — one-click batch fetch for all models of a type with SSE progress streaming
|
||||
- **Detail modal** — preview image, CivitAI info, thumbnail change via file upload
|
||||
- **GenUI Model button** — apply the selected model directly to the corresponding node in GenerateUI's current workflow (Checkpoint, LoRA, VAE, ControlNet, UNET, TextEncoder)
|
||||
- **Group management** — create, rename, delete groups and assign/remove models; groups are scoped per model type (checkpoint groups only appear in the Checkpoint tab)
|
||||
- **Side panel tabs** — opens to CivitAI tab by default when a model is selected; Info (file path display with click-to-copy, tags, memo), Groups management, CivitAI integration
|
||||
- **CivitAI integration** — fetch model metadata by SHA256 hash; side panel shows **Type** (badge), **Base Model**, **Hash** (BLAKE3/SHA256, click to copy), trained words, tags, and model page link; model link opens in the site selected in Settings (civitai.com or civitai.red)
|
||||
- **CivitAI panel — Info / Sample sub-tabs** — Info tab shows model details (name, type, base model, hash, trigger words, tags, description); Sample tab shows all sample images (count shown in tab label); clicking any image opens the full-size version in a new tab
|
||||
- **CivitAI panel states** — three distinct states: not yet checked (fetch button), checked but not found on CivitAI (re-check button with notice), and found (full info display); clicking the CivitAI tab always refreshes to the latest state
|
||||
- **Batch CivitAI fetch** — one-click batch fetch using `POST /model-versions/by-hash` (up to 100 models per request) with SSE progress streaming; previews are auto-saved for models without one
|
||||
- **Detail modal** — preview image, CivitAI info, thumbnail change via file upload; **Delete** button permanently removes the model file and all associated sidecar files (preview images, `.json`, `.civitai.info`, `.metadata.json`, `.cm-info.json`)
|
||||
- **GenUI Model button** — apply the selected model directly to the corresponding node in GenerateUI's current workflow (Checkpoint, LoRA, VAE, ControlNet, UNET, TextEncoder, Hypernetwork); **Embedding** type shows **GenUI PP** / **GenUI NP** buttons instead — appends `(embedding:Name:1.0)` to the Positive or Negative prompt of the loaded workflow; also accessible from the side panel nav bar and the detail modal
|
||||
- **Group management** — create, rename, delete groups and assign/remove models; groups are scoped per model type (checkpoint groups only appear in the Checkpoint tab); Checkpoint and LoRA tabs include **B (Batch)** and **S (Stack)** quick-assign buttons per card/row for one-click group membership toggle without grid re-render
|
||||
- **Table view memo** — memo column displayed in table view for quick reference
|
||||
- **Preview images** — auto-detect `{model_stem}.preview.png` next to model files
|
||||
- **Enable / Disable models** — hide models from ComfyUI by renaming the file extension (`.disabled` suffix); toggle per card (⏸ button), per group (Enable All / Disable All), or filter by status (All / Enabled / Disabled)
|
||||
- **Multi-select & bulk operations** — enter selection mode to check multiple models; bulk action bar supports add/remove from groups and permanent file deletion (model file + preview images + sidecar files such as `.json` / `.info`)
|
||||
- **Multi-select & bulk operations** — click the green **Select** button to enter selection mode and check multiple models; the bulk action bar is organized in three rows:
|
||||
- **Group row** — select an existing group and **Add** / **Remove**, or type a new name and **Create & Add**
|
||||
- **Badge row** — select a badge and **+Badge** / **−Badge** to apply or remove from all selected
|
||||
- **File row** — select a destination subfolder (or type a new folder name and create it) then **Move** to relocate the model file with all sidecar files; **Delete Files** (right end) permanently removes selected models and all associated files
|
||||
- **Search clear (✕)** — inline ✕ button appears inside the search box whenever text is entered; click to clear immediately
|
||||
- **Clear all filters (✕ Clear)** — rightmost toolbar button; resets search text, tag filter, folder filter, group filter, favorites filter, and status filter in one click
|
||||
|
||||
### Workflow Studio Library (ComfyUI Side Panel) (v0.2.5)
|
||||
- **Workflows tab** — browse favorite workflows (All / ★ Favorites / Groups / By Badge sub-tabs), ★ star shown for favorites in All view
|
||||
- **Nodes tab** — browse favorite nodes (All / ★ Favorites / Groups / Sets / 📂 Category / 🧩 Package sub-tabs), ★ star shown for favorites in All view
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><h3>Tagger Tab (v0.3.38)</h3></summary>
|
||||
|
||||
- **3 sub-tabs** — Single / Batch / DB for single-image tagging, folder batch processing, and tag database management
|
||||
- **Model support** — WD Tagger (ONNX, NCHW/NHWC auto-detect), SwinV2 (ONNX), DeepDanbooru (.h5, requires TensorFlow); place each model in its own subfolder under `ComfyUI/models/tagger/<model-name>/` containing the `.onnx` + `selected_tags.csv` (or `.h5` + label file). **PixAI Tagger v1.0** (v0.8.10) is supported via the community ONNX conversion [Mexes/pixai-tagger-v1.0-onnx-fp32-fp16-int8](https://huggingface.co/Mexes/pixai-tagger-v1.0-onnx-fp32-fp16-int8): put one of `model.onnx` / `model_fp16.onnx` / `model_int8.onnx` (only one `.onnx` per folder) together with `selected_tags.csv` and `preprocess.json` in a subfolder. It is detected by `preprocess.json` and uses its own preprocessing (1008px, black padding, RGB, mean/std 0.5; the model already outputs probabilities); tags come from the general / style / copyright / character categories (meta and rating are left out). Selecting it switches the sliders to its recommended defaults (Threshold 0.17 / Char Thr. 0.27); the sliders then offset the recommended per-category values (Threshold moves general and style, Char Thr. moves character and copyright). FP16 needs a GPU to be fast: with both `onnxruntime` and `onnxruntime-gpu` installed the CPU package overwrites the GPU one and CUDA is silently unavailable, so keep only `onnxruntime-gpu`
|
||||
- **Threshold sliders** — General threshold (default 0.35) and Character threshold for `character:` prefix tags (default 0.85); sliders update the display value in real time
|
||||
- **VLM tagging** (v0.3.38, multi-backend: v0.5.4) — optional vision model alongside WD Tagger, running on Ollama, LM Studio, Lemonade, or Unsloth through the same unified backend used by the Prompt tab; results from both models are merged into one comma-separated tag string
|
||||
- **⚙ Settings modal** (v0.5.4) — a Settings button (Single and Batch tabs) opens the same modal component as the Prompt tab's AI Assistant (Backend / Connection / Model / Generation / Unload), but saved under its own `localStorage` key so Tagger's VLM backend/model choice is independent of the Prompt tab's; **Thinking mode** and **Max tokens** apply to VLM requests too, and the **Unload** button frees the selected model (Ollama/LM Studio/Lemonade; Unsloth unsupported) — replaces the old Tagger-only direct Ollama URL/model fields
|
||||
- **Single tab** — drag & drop an image onto the preview area or click Upload; Gallery detail panel **Tagger** button opens the selected image directly here
|
||||
- **Single output options** — (1) **GenUI:P** — appends tags to the GenerateUI tab's positive prompt and immediately applies to the loaded workflow; (2) **Send to Prompt** — appends tags to the Prompt tab's positive textarea; (3) **Save to Gallery** — saves tags to Gallery image metadata (requires image opened from Gallery); (4) **Write to File** — embeds tags into JPEG EXIF (`ImageDescription`) or PNG `tEXt` chunk (`Tags` key), other formats get a `.tags.json` sidecar; (5) **Save to DB** — stores in internal SQLite database
|
||||
- **Batch tab** — enter a folder path, configure WD Tagger thresholds and (via the same ⚙ Settings modal as Single) the VLM backend; output options: **Save to DB** (default on), **Write to File** (EXIF/PNG metadata), **Write .txt** (creates `<filename>.txt` alongside each image with all tags); real-time progress bar and log; Stop cancels after the current image
|
||||
- **DB tab** — searchable SQLite database of all tagged images; click a row to open the edit panel and modify WD Tags / VLM Tags; Save updates the record, Delete removes it; Export CSV downloads all records; **bulk delete** (v0.5.8) — per-row checkboxes plus a header checkbox to select/deselect all, a confirmation dialog before deleting the selected records
|
||||
- **Dependencies** — install into ComfyUI's embedded Python: `python_embedded\python.exe -m pip install -r requirements.txt`; for GPU inference use `onnxruntime-gpu`; TensorFlow (DeepDanbooru) is optional and commented out in `requirements.txt`
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><h3>TagSpace Tab (v0.9.0)</h3></summary>
|
||||
|
||||
- **Choose tags visually in a 3D latent space** — WFS's own data is placed in the EmbeddingGemma 2 vector space and shown in 3D (three.js, bundled): **Cards** (ImagePrompt images with their prompt, drawn as thumbnails), **Tags** (words split out of ImagePrompt prompts, the positive prompts embedded in Gallery images, wildcards, the Tagger DB and the Prompt library, colored by source) and **Gallery points** (a sample of indexed Gallery images as a faint background, each carrying the tags from its own prompt). Nearby items have similar meanings
|
||||
- **Build / Update** — collects the cards, adds card images that are not yet indexed to the Gallery semantic index, reads the positive prompt embedded in each indexed Gallery image (followed upstream from the sampler's `positive` input, never the negative; cached in `tagspace_prompts.json`, deleted images are skipped), embeds new tags with Ollama (cached in `tagspace_tags.npz`) and projects everything to 3D with PCA. Prompts are split only at commas (and `|` `{}` `BREAK`), not at spaces; phrases over 5 words are dropped. **Tags** sets how many tags are kept — each source is ranked by how many prompts use a tag and the sources take turns, so the many Gallery prompts do not crowd out the others; **Gallery points** sets how many Gallery images are shown. Images and text form two separate clusters in the same space (modality gap), so each is centered on its own mean (images: the cards) before PCA, which makes cards and their matching tags overlap. First build: about 2.5 min for ~1,000 cards plus about 2 min to read the prompts of 29,000 Gallery images (64% had a readable positive prompt); rebuilds with caches: about 15 s
|
||||
- **Choosing tags** — **All tags** uses every candidate tag instead of the Tags number (up to 20,000); **Min uses** drops tags used in fewer prompts than that (all sources combined); **Wildcards** turns wildcard files on or off as a tag source. Words found only in wildcards are most of the distinct tags (about 37,000 of 47,600 in testing), so All tags without wildcards gives about 10,400 tags (about 6,800 with Min uses 2); ~32,000 points still render at 60 fps. Wildcard YAML is read with a YAML parser, so multi-line (`- >-`) items are included; JSON fragments embedded in prompts (e.g. MOSS-Image bbox layouts) and model file names are not turned into tags
|
||||
- **Explore** — drag to rotate, right-drag to pan, wheel to zoom; hover shows name, thumbnail and prompt/sources; layer checkboxes for Cards / Thumbnails / Tags / Gallery, and source checkboxes (ImagePrompt / Gallery prompts / Tagger DB / Prompt library / Wildcards) that show or hide tags by origin — a tag stays visible while any of its sources is on, and hidden tags are left out of the nearby/search lists. The search box (Enter, any language) places a marker for the text and lists the nearest items
|
||||
- **Search with a card's or Gallery image's tags** — a selected card or Gallery point lists its prompt tags as buttons; pick some and search the space with them (joined in prompt order); while tags are picked, the Add button becomes "Add selected (N)" and adds only those tags. A selected Gallery point also has **Open in Gallery**, which opens its folder in the Gallery tab with the image selected (filters are cleared)
|
||||
- **Make a prompt** — click a card or tag to select it and list nearby items (clicking does not change the prompt); double-click it, press **Add** next to its name under Selection, or press **+** in the list to add it (again to remove); cards and tags are ranked separately and interleaved, so a card also shows its closest tags. Adding a Gallery point adds all tags from that image's prompt as one chip (images without readable tags cannot be added); clicking one lists similar Gallery images together with nearby tags and cards (cards, tags and searches never list Gallery images). The prompt joins the chips with duplicates removed; **Add to GenerateUI (Positive)** appends it to the loaded workflow's positive prompt, **Copy** puts it on the clipboard
|
||||
- **Tagger fill** — Gallery images without a readable prompt (about a third) can be tagged with a Tagger model (ONNX models from the Tagger tab) during Build / Update — either only the sampled Gallery points or every indexed image without prompt tags. Default thresholds, rating labels dropped, results cached per image and model in `tagspace_tagger.json` (stopping keeps finished images). The tags form the **Tagger fill** source and become the tags of those Gallery points. The status shows CUDA/CPU: on the CPU it is about 0.5 s per image, so make sure `onnxruntime-gpu` is active before tagging everything
|
||||
- **Glow / Twinkle** — points are drawn as glowing stars on a night-sky background (Gallery points dimmed so dense areas don't wash out); **Twinkle** makes tags, cards and Gallery points twinkle slowly with individual rhythms (selection/nearby highlights stay steady). Both are toolbar toggles; turning Glow off restores the plain dots
|
||||
- **Hover preview** — hovering the image under Selection or a thumbnail in the Nearby list shows an enlarged preview without changing the selection; the Add / Remove button sits on Selection's title row so it stays reachable while the text scrolls
|
||||
- **Requirements** — Ollama with EmbeddingGemma 2 (Gallery > Semantic settings > Model); a Gallery semantic index built with Gemini must be rebuilt with EmbeddingGemma 2 first
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><h3>Image Edit Tab (v0.3.65)</h3></summary>
|
||||
|
||||
- **Layer-based image editor** — compose images with multiple layers (Image, Text, Draw, Mask types) and export the composite as PNG or a fully layered PSD
|
||||
- **Loading images** — drag & drop onto the canvas, **File Open** button (renamed from Upload in v0.6.0), or send from the Gallery tab via the **Image Edit** toolbar button; first image becomes Layer 1 (auto-locked), subsequent images are added as new layers scaled to fit the canvas
|
||||
- **Open PSD button** (v0.6.0, next to File Open) — loads a layered PSD file from disk and decomposes it into individual layers, restoring each layer's position, size, visibility, opacity, and blend mode; groups and non-raster layers (adjustment layers, etc.) are flattened into their rendered appearance
|
||||
- **Close button** (v0.6.0, next to Open PSD) — closes the current document after a confirmation prompt, discarding all layers and unsaved edits and returning to the empty placeholder view
|
||||
- **New button** — create a blank canvas with custom dimensions (WxH prompt); clears all existing layers and automatically adds an empty Layer 1 (v0.3.70)
|
||||
- **Tools** — Select (V), Draw (B), Text (T), Shape (S), Fill (G), Mask (🎭), Blur (≈), BG Remove (⬚), Filter (★), Inpaint (🩹); tool options bar updates per active tool
|
||||
- **Select** — click to select; drag to move; drag corner handles to resize; drag circle handle to rotate; Flip H / Flip V / Rotate angle in the options bar; double-click a text layer to re-edit its content
|
||||
- **Draw** — freehand brush; options: color, brush size, blend mode; paints directly onto the active draw layer while all other layers remain visible; brush cursor shown as a size-accurate circle; strokes can start from outside the canvas margin and continue past the edge; **pen tablet support** (v0.6.2) — brush size and opacity respond to pen pressure (mouse behaves exactly as before); the canvas listens for Pointer Events so pen, touch, and mouse all work through the same code path; **color palette** on the second row — Color 1/Color 2, 20 basic colors, and 20 custom slots (registered and edited colors are saved in the browser); **eyedropper** button next to Color picks a color from the canvas (`Esc` cancels); shortcuts while Draw is active: `D` Draw, `E` Erase, `X` switch Color 1/2, `[` `]` brush size, `B` open or close the brush picker (`Esc` also closes it)
|
||||
- **Text** — click to place; configure font, size, bold/italic, align, and color; placed as an exact-size text layer sized to the measured bounding box; double-click to re-edit
|
||||
- **Shape** — drag to draw geometric shapes (Rect / Ellipse / Line / FreeLine); options: shape type, Rounded toggle (Rect/Ellipse), Fill color, Stroke color + width, Opacity; each committed shape becomes an independent draw layer; Stroke None hidden for Line/FreeLine (stroke always active)
|
||||
- **Fill** (v0.6.2) — bucket fill; click a contiguous same-color region on the active layer to flood-fill it (scanline-based, ported from the Comic Creator plugin's Image tab); **Properties pane**: Mode (Solid / Gradient) — Solid: Color picker; Gradient: Shape (Linear / Radial), a draggable color-stop Ramp (click a stop to select it, drag to reposition, +/- to add/remove stops, color swatch to edit the selected stop's color), and a Direction dial (drag to set angle/radius); both Tolerance (0–255, color-match threshold) and Opacity apply to either mode; Ramp and Direction dial are pointer-event based with pointer capture, so pen tablets work the same as mouse
|
||||
- **Mask** — 7 sub-tools for painting masks onto a dedicated mask layer; click **Mask** on the second row of the Layers header (renamed from "M" and moved to its own row in v0.6.0) to add a mask layer (Mask tool activates automatically); clicking a mask layer in the list also switches to the Mask tool; **Tool Options bar**: sub-tool buttons (Paint / Color / Alpha / Text / Vector / Shape / SAM3), Invert checkbox, Overlay color picker (default red), Blur slider (0–50 px); the overlay is only shown for the currently active mask layer, other mask layers stay hidden until selected (v0.3.70); SAM3 requires Mask Editor One (disabled when not installed); Color / Alpha / Text / Vector / Shape work without Mask Editor One; **Properties pane — Paint**: Mode (Add / Erase), Size (1–200 px), Hardness (0–100%); brush size responds to pen pressure on a tablet (v0.6.2, same as the Draw tool); **MASK EDITOR ONE section** (Paint sub-tool, visible when installed): Select opens the ABR stamp-brush library; ✕ clears back to Circle; when an image brush is active, Hardness is disabled and Spacing (5–100%), Angle (0–359°), Sz Jitter (0–100%), Rot. Jitter (on/off) appear; **Edit in Mask Editor One →** (v0.4.0) — sends the current canvas composite (plus the active mask layer's content, if one is selected) to a MaskEditorOne node on the ComfyUI canvas — the currently selected node if it is one, otherwise the first MaskEditorOne node found in the graph (same selection logic as **Send to LI node**) — and opens its full interactive editor (paint, SAM3, BiRefNet, shapes, etc.) in the ComfyUI browser tab; clicking Apply there imports the result back here as a new mask layer; requires Workflow Studio to have been launched from ComfyUI's top-menu button and at least one MaskEditorOne node to exist on the ComfyUI canvas; **Properties pane — Color**: click canvas to flood-select pixels by color similarity; Mode (Add / Subtract), Tolerance (0–255), Feather % (0–100); **Properties pane — Alpha**: extract the active layer's transparency as a mask; Threshold, Invert checkbox, Extract Alpha button; **Properties pane — Text**: click canvas to open a stamp overlay — enter text, set Font / Size / Bold / Italic / Align / Mode (Add / Erase), Stamp or Ctrl+Enter to apply; multi-line supported; **Properties pane — Vector**: click to add Catmull-Rom spline points; Enter (or click first point) closes and fills the polygon; Backspace removes the last point; Esc resets; Mode (Add / Erase); **Properties pane — Shape**: drag to draw Rect or Ellipse; hold Shift for square/circle; blue dashed outline preview while dragging; Mode (Add / Erase); **Properties pane — SAM3**: enter a text prompt, set Max candidates (3/6/9/12), click Segment; select candidate thumbnails (multi-select), Apply Selected (N) applies with current Mode; **Mask layer A/S operation**: A/S toggle — Add (green) composites normally, Subtract (red) cuts the mask from below; **✂ clipping mask button** clips the layer below to the painted area; brush cursor shown as size-accurate circle; strokes can start from outside the canvas margin and continue past the edge Since v0.8.13 the sent image is also saved to the node's `node.properties.bg_image` (via `node._persistBgDataUrl`, Mask Editor One v0.1.12 or later; ignored on older versions) and the mask layer data carries the image `width`/`height`, so the image and the mask preview survive a ComfyUI page reload or workflow tab switch instead of an older image being restored.
|
||||
- **Blur** — **Whole Blur**: Gaussian blur to the entire active layer with intensity slider (1–50 px); **Whole Mosaic**: pixelation mosaic with block-size slider (5–100 px); **Rect Blur / Rect Mosaic**: enable the toggle then drag a rectangle on the canvas to apply blur or mosaic to that region only (blue preview for blur, orange for mosaic); Rect Blur and Rect Mosaic are mutually exclusive; all operations support Undo
|
||||
- **BG Remove** — remove the background from the active layer; **Lightweight (@imgly)**: runs entirely in the browser via CDN (no server required; ~40 MB model downloaded on first use); **BiRefNet**: high-quality removal via Mask Editor One's Python backend (requires Mask Editor One installed and `birefnet.safetensors` in `ComfyUI/models/background_removal/`); **New Layer** option (default on) adds the result as a new layer above the original; when off, replaces the active layer in-place
|
||||
- **Filter (G'MIC)** — apply G'MIC-Qt filter effects to the active image layer; click **Edit with G'MIC** to launch G'MIC-Qt GUI; select a filter and click OK — a "G'MIC-Qt filter output" window appears; close it to save the result back as the active layer; requires G'MIC-Qt Standalone installed and path configured in Settings → G'MIC-Qt Executable Path
|
||||
- **Inpaint** (v0.3.71) — composites the visible layers plus a Mask layer into one RGBA image (mask baked into the alpha channel) and applies it to the first inpaint-capable LoadImage node in the workflow currently loaded in GenerateUI (a node whose MASK output feeds something like `VAEEncodeForInpaint`); also supports workflows built around the **Mask Editor One** custom node (`comfyui-mask-editor-one`) instead of LoadImage — image/mask are pushed via its node_id-keyed server cache and `layer_data` widget; **Properties pane**: Positive/Negative prompts, Grow Mask By (applied to the VAE Encode (for Inpainting) node), Denoise (applied to KSampler), Run button; **Use dedicated workflow** checkbox — when off, generates against the workflow currently loaded in GenerateUI; when on, pick a saved workflow from the dropdown to load, edit, and generate entirely in the background without disturbing what's shown in GenerateUI; the result image is shown back in the Properties pane when generation completes; requires a Mask layer painted first (Mask tool)
|
||||
- **Layer panel** — layer list with visibility (👁/🚫), lock (🔒/🔓), and clipping-mask (✂) toggles; opacity slider; type icons (🖼 image / T text / ✏ draw / ⬚ mask); Layer 1 is automatically locked on first image load; header is arranged in two rows (v0.6.0) — +, **⧉ Duplicate**, −, ↑, ↓ on top, **Mask** alone below
|
||||
- **Duplicate layer (⧉)** (v0.6.0) — copies the active layer, including its pixels, position, size, opacity, blend mode, and visibility, and inserts the copy directly above the original as the new active layer; works on any layer type (image, draw, text, mask)
|
||||
- **Layer lock** — locked layers show an orange bounding box and 🔒 icon on the canvas; move/resize/rotate are disabled while locked; click the 🔓 button in the layer row to unlock
|
||||
- **Text quality** — text layers are rendered at their measured bounding-box size; resizing with the Select tool regenerates the canvas at the new display resolution so text stays sharp
|
||||
- **Export** — Save PNG (download composite locally); **Save to Gallery** (saves to Gallery root folder with a timestamped default name `wfs-image-YYYYMMDDHHmmss`); **Save PSD** (v0.6.0, downloads a layered PSD file with every layer preserved separately — position, rotation, flip, and scale are baked into each layer's pixels since PSD layers cannot store a rotation angle, while opacity, blend mode, and visibility are kept as real, editable PSD layer attributes; clipping masks are merged into their target layer since PSD's native layer-mask mechanism isn't used); **Send to LI node** (renamed from "Send to Workflow" in v0.5.2) — uploads to ComfyUI's input folder via `/upload/image`, then writes the resulting filename directly into the `image` widget of the node currently selected on the ComfyUI canvas (falls back to the first LoadImage-type node found); requires Workflow Studio to have been launched from ComfyUI's top-menu button so the ComfyUI tab is reachable; the Gallery tab's toolbar has the same button (v0.5.2, see Gallery Tab below) so a selected Gallery image can be sent the same way without going through Image Edit first
|
||||
- **Canvas navigation** — scroll-wheel zoom, Space + drag to pan; zoom indicator in the bottom bar
|
||||
- **Undo / Redo** — Ctrl+Z / Ctrl+Y (or toolbar buttons); keyboard shortcuts: V (Select), B (Draw), T (Text), S (Shape), G (Fill), Delete (remove selected layer when 2+ exist)
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><h3>Video Tab (v0.5.0 – v0.7.4)</h3></summary>
|
||||
|
||||
- **Dedicated video generation UI, independent of GenerateUI** — a purpose-built tab for MiniMax H3 (Image to Video), LTX-2.5 (Text / Image / First & Last Frame to Video), Wan2.2 (Text to Video), and FastH3 OmniRef (MiniMax H3 Reference to Video) workflows (LTX-2.5/Wan2.2: v0.5.4); does not share state with the GenerateUI tab, and model selection (UNet/CLIP/VAE/Audio VAE) is fixed to the loaded workflow's own defaults rather than editable here
|
||||
- **Plan subtab** (center panel, batch redesign in v0.5.5) — a **plan** is a sequence of timeline blocks, each a fully self-contained generation job with its own Prompt, Duration, and First/Last Image; split the timeline with **+ Split** / **+ Block** / **Delete**, then **Run** to generate every block in order (Pause/Cancel work mid-run) — a plan with a single block behaves exactly like the old one-shot form. First Image can be None, an explicit image, or "use previous block's last frame" (chaining — an explicit Last Image on the previous block always wins over extracting one from its generated output). Save / Save As / Clear a plan (`ws_videoplan_*.json`, with a PNG contact-sheet thumbnail that embeds the full plan data so dropping the image back on works too)
|
||||
- **Base settings row** (topbar, v0.5.7) — Aspect Ratio / Megapixels / Multiple / Duration (seconds) / Noise Seed on one row — Duration always reflects the currently selected block (each block keeps its own value), the rest are plan-wide — plus a second row of model-specific fields: Width / Height (become directly editable for workflows with no Resolution Selector node, e.g. Wan2.2 and LTX-2.5's First & Last Frame to Video), Turbo Mode / Strength / Steps (MiniMax H3's turbo LoRA — Turbo Mode doubles as Wan2.2's own turbo toggle, sharing one field), and Prompt Enhance (LTX-2.5 only). Every field in both rows is enabled only when the loaded workflow actually has it — see Field highlight color below (one exception: Wan2.2's Text-to-Video variant doesn't expose Noise Seed at all, so it alone leaves that field disabled)
|
||||
- **Edit subtab** (v0.7.0) — a lightweight clip timeline for trimming and concatenating video/image clips outside of generation: add clips via the Video Source panel's **Add to Edit** button or the Asset subtab's **Send to Edit** button, drag blocks to reorder (or use the ◀/▶ toolbar buttons), Duplicate/Delete the selected clip, Clear to empty the timeline. The trim panel for a selected video clip shows a Clipchamp-style scrubber — a time ruler, a draggable playhead synced to the Source preview, and draggable in/out handles with time badges (image clips get a simple hold-duration field instead); the playhead's own time badge sits a row above the in/out handle badges (v0.7.2) so it stays legible even when the playhead lands right on a trim point, and the scrubber has extra headroom/height and spacing from the clip name above it (v0.7.2). **▶ Preview** plays every ready clip back-to-back (trimmed to its in/out points) in the result preview, and **Export** builds and runs the actual ComfyUI graph (trim → crop → concatenate if more than one clip → save), tagging the result into Video Temp automatically. Multi-clip exports keep each clip's own audio (v0.7.4 — previously they were always silent). **Clear** empties the clips and also resets the Audio section to its defaults (v0.7.4)
|
||||
- **Edit: Multi-track** (v0.7.8) — the buttons above the timeline switch the track view: **Video** (blue), **Overlay** (blue), **Text** (green) and **Audio** (red), and the tool menu below follows it (Video: trim + crop / Overlay: overlay clips / Text: text overlays / Audio: audio settings); Save / Load / Export stay fixed on the right. **Text** now belongs to the timeline (absolute seconds, no longer to a clip): drag a band to move it — even across clips — or drag its edges to retime it; projects saved with clip-relative text are converted on load. **Audio** adds any number of **+ Sound...** clips (sound effects, voice) that you place by dragging their bands, trim by dragging an edge, with their own start / length / volume, on top of the full-length BGM. **Overlay** adds picture-in-picture clips (video or image) via **+ Overlay clip...** or the Asset subtab's **Add as overlay (PinP)** button, each with its own time, position (9 presets or X/Y), size and opacity, shown as dashed boxes in the previews and composited over the main video in the same pass that burns in text on Export (an overlay's own audio is not mixed). Undo/Redo and project Save/Load cover all of it, and Full Backup's "Include media used by Video Edit projects" now also bundles the sounds' and overlays' media.
|
||||
- **Edit: Audio / BGM** (v0.7.4) — the export panel's **Audio** section sets the soundtrack: **Keep original audio** (with its own volume in dB) keeps every clip's audio aligned to its segment even across multiple clips (image clips contribute silence), and one **BGM** file is laid over the whole video with its own volume and start offset (a longer BGM is cut to the video length). Pick the BGM with **BGM...**, by dropping an audio/video file onto the Audio section, or with **Set as BGM** on a video in the Asset subtab (that video's audio track is used; videos without audio are rejected). Built entirely inside the export graph with ComfyUI core audio nodes (EmptyAudio / AudioMerge / AudioConcat / LoadAudio / TrimAudioDuration / AudioAdjustVolume) passed to ConcatenateVideo's `complete_audio` — no extra dependencies. ▶ Preview plays the BGM alongside the clips
|
||||
- **Edit: Text overlays** (v0.7.4) — each clip can carry any number of text overlays (**+ Add text** under the trim panel): text, start/end seconds within the clip, size as % of frame height, color, 9-position anchor, outline, and an optional background box. They follow the clip when it's reordered, are previewed live over the Source/Result panes, and are burned in on Export as a final pass (PyAV decode → Pillow → H.264 encode, frame by frame so memory stays flat; the soundtrack is remuxed untouched). Japanese/CJK text renders with a system CJK font (Meiryo / Yu Gothic / Noto Sans JP on Windows)
|
||||
- **Edit: Crop** (v0.7.4) — **Edit crop** puts a draggable/corner-resizable rectangle over the Source preview (optionally locked to 16:9 / 9:16 / 1:1 / 4:3 / 3:4); **Done** keeps it, **Cancel** restores the crop from before editing, and switching to another subtab/tab ends editing like Done. Export applies it with ComfyUI core `VideoCrop`; the output size is the first video clip's cropped size, and other clips of a different size are center-fit to it. Text overlay previews are drawn relative to the cropped frame
|
||||
- **Edit: Convert audio** (v0.8.9) — a **Convert audio...** button sits next to the crop buttons (separated by `|`); it converts the selected video clip's audio track to FLAC / MP3 / Opus / M4A / WAV with the same dialog as Gallery's **Convert...** (bitrate, sample rate, channels), and saves the result into the output/video folder so it shows up in Gallery. Delete-original and carry-over-gallery-meta options are not offered here. Server route: `POST /api/wfm/video/edit/convert-audio`
|
||||
- **Edit: Undo / Redo** (v0.7.4) — **↶ / ↷** in the timeline toolbar (or Ctrl+Z / Ctrl+Y / Ctrl+Shift+Z outside text fields) step through edits to clips, trims, crops, text and audio settings; a deleted clip comes back without re-uploading. History resets when a project is loaded
|
||||
- **Edit project persistence** (v0.7.2) — **Save** / **Save As** / **Load** buttons in the Edit subtab's export panel persist the timeline itself (clip order, trim points, and which uploaded server-side file each clip refers to — plus crops, text overlays and audio/BGM settings since v0.7.4) as a `ws_videoeditproj_*.json` project file; Load re-fetches and re-probes each clip from its saved server reference, so the original files need to still exist
|
||||
- **Asset subtab** (center panel, next to Plan/Edit — moved here from the sidebar in v0.7.0) — browses generated videos/images through three groups: **Video Assets** (a manually-curated keeper group you organize yourself, on your own schedule), **Video Temp** (every plan run's output lands here automatically regardless of whether the plan itself was saved — a **Clear Video Temp** button in the Gallery tab's detail panel empties it in one click), and **All Video Assets** (the union of both); a filename search box, a video/image type filter dropdown (All Types / Video Only / Image Only, v0.7.2), and a thumbnail-grid/table (▦/☰) view toggle sit above the list (v0.7.0). Selecting an item shows it in the center preview and lets you tag/memo it, **Send to Edit** (queues it as a clip in the Edit subtab), **Set as BGM** for videos (v0.7.4 — uses its audio track as the Edit BGM), jump straight to the full Gallery tab, or — for images only — **Set as First Image** / **Set as Last Image** (v0.7.0, uploads it straight into the currently-selected Plan block and switches to the Plan subtab)
|
||||
- **Project subtab** (sidebar) — lists saved plan files while the center Plan subtab is active, or saved Edit projects while the center Edit subtab is active (v0.7.2 — thumbnail/block-or-clip-count/last-updated) — click one to load it into the matching editor, or delete it with the × button; the panel collapses back down when its own tab is clicked again, and switching Plan↔Edit while it's open refreshes the list in place
|
||||
- **Two center previews** (v0.5.5) — the left preview shows either the video currently selected in the Asset subtab or whatever's dropped/picked in the **Video Source** panel to its left (**Clear** resets it to empty); the right preview always shows the most recently generated clip; both preview frames are a fixed height (v0.7.0) so switching sources never shifts the Plan/Edit/Asset panel below them. The Frame/GIF tools act on whichever preview was touched most recently
|
||||
- **Register as Asset** (v0.8.9) — a **Register as Asset** button in the Video Source panel (next to **Add to Edit** and **Clear**) puts the loaded video into the **Video Assets** group so it appears in the Asset subtab: local files are uploaded and copied into output/video (Gallery only lists the output folder), sources already in output are just tagged. The Video Source panel was also widened so the file name stays on one line and the three buttons fit in a row. Server route: `POST /api/wfm/video/asset/register`
|
||||
- **First Frame / Last Frame are both optional** — leaving First Image empty runs the workflow text-only (the node is simply left unconnected — a "bypass"); workflows that don't even include a LoadImage node for First Frame are supported out of the box (Wan2.2's Text-to-Video graph has neither slot at all), and a LoadImage node is only injected into the graph on the fly if an image is actually supplied
|
||||
- **Semantic node lookup, not hardcoded IDs** (generalized in v0.5.4) — detects which of the three families is loaded from its subgraph's internal node types (or, for Wan2.2, the subgraph's own name — it has no distinctive internal node type), then locates its Resolution Selector and LoadImage node(s) by the subgraph's *public input label* (`prompt`, `duration`, `width`, `first_frame`, `last_frame`) rather than a fixed slot index — so it keeps working even though the three families expose those inputs under different internal names; a workflow no longer needs to match any bundled reference file's exact node IDs, and no fallback test workflow is auto-loaded on tab open
|
||||
- **Field highlight color** — Prompt / Duration / First Image / Last Image / Aspect Ratio / Megapixels / Multiple / Noise Seed / Width / Height / Turbo Mode / Strength / Steps / Prompt Enhance labels turn the same highlight color as the GenerateUI Model tab (shared setting, customizable in the Settings tab — see below) when the loaded workflow actually exposes that field; e.g. a Wan2.2 workflow (no Resolution Selector node) leaves Aspect Ratio / Megapixels / Multiple unhighlighted while Width / Height light up instead
|
||||
- **Load in Video** (Workflow tab) — load any workflow containing a MiniMax H3 Image-to-Video node, an LTX-2.5 Text/Image/First&Last-Frame-to-Video node, a Wan2.2 Text-to-Video node, or a FastH3 OmniRef (MiniMax H3 Reference-to-Video) node — for FastH3 / Pika-H3-Flex the First Image and Last Image fields become Reference Image (ref_image_0) and Reference Image 2 (ref_image_1); leaving either one empty (None / Clear) disconnects that reference input even if the workflow had an image wired to it; Reference Image 2 is never used as the previous block's last frame for "Use previous block's last frame" (the actually generated last frame is used instead) straight into this tab from the Workflow tab's side-panel toolbar (next to Load in GenerateUI) — starts a fresh single-block plan seeded from the workflow's own current values; unsupported workflows show an error toast instead of loading
|
||||
- **Frame tab** (right panel) — captures the active preview's current playback position as a still frame: play/seek to the position you want, click **Capture Frame** (client-side canvas, no server round-trip), then **Save to Output** to write it as a PNG into ComfyUI's own Output folder (auto-numbered, same pattern as other generated images); an optional **Add to Video Assets group** checkbox (v0.7.0) also tags the saved frame into Gallery's Video Assets group
|
||||
- **GIF tab** (right panel) — converts the active preview to an animated GIF; set Start/End (seconds), FPS, and an optional Max Width, then **Convert to GIF** — the server decodes the video (PyAV) and encodes an animated GIF (Pillow), both dependencies ComfyUI itself already requires, so no ffmpeg binary or extra install is needed; the result is saved into ComfyUI's Output folder and previewed inline
|
||||
- **Playback volume** — the preview player's volume is saved to the Settings tab and shared across every video player in the plugin (Video tab, Gallery tab), so it no longer resets to maximum each time a different video is opened
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><h3>AI TOOL Tab (v0.3.14 – v0.9.5)</h3></summary>
|
||||
|
||||
- **4-pane layout** — Translation | Chat | TOOLS | Settings; all panes always visible simultaneously; no sub-tab switching required
|
||||
- **Translation pane** — translate text between Japanese, English, Chinese, or a custom Free language using Ollama, LM Studio, Lemonade, or Unsloth; language selectors with ⇄ swap button (swaps both language selectors and text content); selections saved automatically
|
||||
- **Reliability fix** (v0.3.98) — switched from a raw single-string prompt to a system-role chat request (Ollama `/api/chat`, LM Studio/Lemonade `/v1/chat/completions` with a `system` message) so small local models follow the "translation only" instruction more reliably; output is cleaned of common LLM preambles/quotes, and a warning toast appears if the model appears to have echoed the source text unchanged instead of translating it
|
||||
- **Chat pane** (v0.3.40) — multi-turn conversation with the LLM; full conversation history sent each turn for context; Enter to send, Shift+Enter for a newline; Clear button resets history; Ollama uses `/api/chat`, LM Studio, Lemonade, and Unsloth use `/v1/chat/completions`
|
||||
- **Chat pane — image generation via Tool Calling** (v0.3.73) — if the selected model supports tool calling and the user asks for an image, a `generate_image` tool is invoked and the request runs through the same generation pipeline as the GenerateUI Generate button, with the result shown inline in the chat; an "Allow image generation" checkbox in the input row toggles this on/off (default on); the workflow used is the one currently loaded in GenerateUI, or a dedicated saved workflow configured in the Settings pane; models verified to work well for tool calling and vision: **Gemma 4:e4b**, **Qwen 3.5:9b**, **Ministral 3:3b** (Ollama)
|
||||
- **Chat pane — generate_image extra parameters** (v0.4.4) — besides `prompt`/`negative_prompt`, the tool call also accepts optional `steps`, `cfg`, `sampler_name`, `scheduler`, `denoise`, `seed`, `width`, `height`, `batch_size` (number of images produced in that one call), and `aspect_ratio` (a ratio preset like `3:2`, resolved against the node's actual COMBO options via `/object_info` and applied only if the workflow has a **Resolution Selector** node feeding width/height — ignored otherwise); anything the model doesn't supply keeps the loaded workflow's own current setting; `batch_size` > 1 shows every generated image inline in the same chat bubble
|
||||
- **TOOLS pane (VLM)** — drop an image into the 110px drop zone, select a task (Describe Image / Create Prompt / Create Tags), and click Run to analyze with a vision model; result shown in the output area with a Copy button
|
||||
- **TOOLS pane — shared Chat attachment** (v0.3.74) — an image dropped in the TOOLS drop zone is also usable as the Chat pane's attachment: it's sent to the LLM as vision input, and used as the base image when `generate_image` runs image-to-image; a ✕ button clears it (from either the TOOLS preview or the Chat attachment indicator); it stays attached across turns until explicitly cleared
|
||||
- **TOOLS pane (Wildcards)** (v0.3.40) — select "Create wildcards" from the task dropdown; enter a category name and count; click Run to generate plain-text wildcard entries one per line (no markdown, no numbering); result can be copied directly into wildcard `.txt` files
|
||||
- **Chat pane — image-to-image (I2I)** (v0.3.74) — when an image is attached and `generate_image` is invoked, the attachment is uploaded and swapped into the target workflow's LoadImage node instead of running text-to-image; the target workflow is the one currently loaded in GenerateUI, or a dedicated I2I workflow configured in the Settings pane
|
||||
- **Chat pane — SVG generation, no ComfyUI workflow involved** (v0.3.77) — the LLM can also produce SVG graphics directly as text; if a reply contains SVG code (wrapped in a markdown code fence or written directly as a bare `<svg>...</svg>`), it's rendered inline as a preview and a "Save to Gallery" button writes it as a `.svg` file to the Gallery tab's output folder; unlike the Tool Calling image generation flow above, this is plain text pattern matching, so it works with any model regardless of tool-calling support
|
||||
- **Chat pane — Skills** (v0.3.79) — select a `.md` skill file from a dropdown above the message list to prepend its instructions to the conversation as a system prompt (not shown in the visible chat log); a pencil button opens an in-pane manager (list + inline editor, same pattern as the Prompt tab's wildcard file manager) to create, edit, or delete skill files stored in `user/default/Workflow-Studio/ai_skills/`; a file's `---`-delimited frontmatter (`name`/`description`) is shown in the dropdown; two starter skills are bundled — **SVG Icon Generator** (explicitly decomposes the subject into parts before drawing, which markedly improves recognizability from small local models) and **Skill Creator** (interviews you conversationally and drafts a new skill as a ```skill code block; a "Save as new skill" button appears under such replies and opens the manager pre-filled with the draft)
|
||||
- **Chat pane — Skills v2** (v0.9.5) — skills keep the portable `name`/`description` frontmatter (Agent Skills / SKILL.md style) and add optional `metadata:` keys: `output` (`prompt` or `svg` — the reply is checked and, if the model tried to output one but it is broken, it is asked once to fix it), `tools` (`[]` = never start image generation), `temperature`, `think`, and `context` (`workflow` summary, `current-prompt`, `workflow-detail`, `logs`). Six built-in skills ship in `py/services/builtin_skills/` with a version number: untouched copies are upgraded automatically, edited ones keep your text and show a ↻ button. A ```` ```prompt ```` block in a reply gets **Apply to GenerateUI** / **Generate with this prompt** / **Copy** buttons, and replies are rendered as Markdown (HTML-escaped first)
|
||||
- **Built-in skills** (v0.9.5) — **T2I Prompt Enhancer** (writes natural sentences for Qwen-Image / FLUX / Z-Image, Danbooru tags for Illustrious / Pony, phrases for realistic SDXL, based on the workflow loaded in GenerateUI), **Image to Prompt** (recreates an image attached in TOOLS), **Storyboard to Lab**, **Workflow Doctor**, **SVG Icon Generator** v2 (line/flat/duotone/mono styles) and **Skill Creator** v3. The prompt text currently in GenerateUI is only passed to the model when your message refers to it, because small models copied an old negative prompt into new ones even when told not to
|
||||
- **Chat pane — Image check & refine loop** (v0.9.5) — with **Check images** on, the chat model turns the request into 3–8 yes/no checks and an Ollama decision model with image input (`d3:4b` by default; `clef-flash` / `clef` also work) answers them with probabilities: ✔ ≥ 85%, ? 30–85%, ✘ < 30%. Swap checks ("the hat is not on the girl") catch the attribute mix-ups the judge otherwise passes. **Fix missing items and regenerate** sends only the unmet items back for a rewritten prompt; 0–3 automatic rounds are configurable. SVG replies are rendered and checked part by part the same way
|
||||
- **Chat pane — Workflow Doctor** (v0.9.5) — diagnoses the workflow loaded in GenerateUI from facts checked on every message: node types that are not installed, model files or options missing from ComfyUI's lists (with the closest existing names), broken links, unconnected core-type required inputs, the last execution error from `/history`, and the latest error block of the ComfyUI log (no false positives across 77 local workflows)
|
||||
- **Chat pane — Storyboard to Lab** (v0.9.5) — a ```` ```labplan ```` reply becomes a Lab plan (one scene per iteration, T2I mode, identical character descriptions, fixed seed); **Open in Lab** loads it into GenerateUI > Lab
|
||||
- **Chat pane — Agent Skills folders** (v0.9.5) — **Import** in the skill manager adds a `.zip` containing `SKILL.md` (or a single `.md`); only text files are kept, scripts are never extracted or run, and zip-slip / size limits apply. Reference files are listed to the model and read on demand through a `read_skill_file` tool (progressive disclosure; needs a tool-capable model)
|
||||
- **TOOLS pane — OCR** (v0.9.5) — **OCR (extract text)** reads text with an Ollama OCR model (LightOnOCR-3 by default; PaddleOCR-VL, GLM-OCR and DeepSeek-OCR are listed too). Ported from Comic Creator's OCR tab: 1600 px white-background JPEG, temperature 0, grayscale retry on empty / looping output. **Show text positions** (LightOnOCR / DeepSeek-OCR) overlays numbered boxes; clicking one selects its line. **To Translation** / **To Chat** pass any TOOLS result on
|
||||
- **Collapsible Translation / Settings panes** (v0.9.5) — the arrow in each header folds the pane into a thin strip (click the strip to reopen); the state is remembered
|
||||
- **Settings pane** — choose backend (Ollama / LM Studio / Lemonade / Unsloth), set the API URL, test connection, select a model (with refresh button), and configure Free language names for translation source and destination
|
||||
- **Unsloth backend** (v0.3.99) — Unsloth Desktop's OpenAI-compatible API requires an API key even for local access unless its **Keyless API access → "Chat and inference"** setting is on; unlike the other backends it's proxied server-side (`py/routes/unsloth_routes.py`, `POST /api/wfm/unsloth/proxy`) so the key never reaches the browser: set `UNSLOTH_API_KEY` in a `.env` file in the plugin folder (copy `.env.example`, loaded via `python-dotenv` in `prestartup_script.py`) and restart ComfyUI — or, since v0.7.7, leave `UNSLOTH_API_KEY` unset and turn on Keyless API access → "Chat and inference" in Unsloth Desktop (requests are then relayed without an `Authorization` header, still only to localhost; that Unsloth setting also opens the API to your private LAN, and "Allow tools" should stay off). A 401 with no key set returns a message explaining both options; also requires **"Auto model switching (OpenAI API)"** to be turned on in the Unsloth Desktop app's own Settings screen — with it off, requests fail with HTTP 404 unless a model was already manually loaded in the Unsloth Studio UI
|
||||
- **Decision API client** (v0.7.5, foundation) — `static/js/decision-client.js` calls Unsloth Desktop's Decision API (`/v1/systemone`, TypeSafe-compatible Laya decision models) through the same key-attaching server proxy: `decide(state, questions)` / `decideMany`, question builders `noul`/`choice`/`score`, and `isYes`/`pickChoice`/`pickScore` helpers that threshold on `probabilities` (as Unsloth recommends) and flag low-probability answers as not confident. Requires **Decision API → Serve requests** enabled in Unsloth Desktop. **Ollama 0.35+ backend** (v0.7.7) — Ollama's own `/v1/systemone` (decision models `tev1` 4B / `tev1:0.8b` 812 MB / `nimble` 9B / `clef` 27B vision-capable, pulled with `ollama pull`; no key, called directly from the browser); the model list shows only installed models whose `capabilities` include `decision`, with a ↻ refresh button and a pull hint when none are installed. **Image input** (v0.7.14, ported from ComfyUI Comic Creator) — most decision models are text-only, but Ollama's `clef` accepts images directly: `decide()` takes an optional 4th `images` argument (base64, no `data:` prefix), `imageToBase64()` converts a Blob/data URL/image URL, and `supportsDecisionVision()` checks whether the currently-configured model accepts them (via `/api/show`'s `capabilities`/`projector_info`, since not every Ollama build reports `vision` for decision models) — call it before passing images, since a non-vision model errors out on them; confirmed working end to end against `clef`. Connection settings live in the Settings tab's own **Decision Model** section (v0.7.6): backend (Unsloth / Ollama), URL, model and default probability threshold, stored under `wfm_decision_settings` independently of the AI TOOL / Tagger backends, with a Test button (one yes/no question). No feature uses it yet
|
||||
- **Settings pane — Chat Image Generation** (v0.3.73) — "Use dedicated workflow" checkbox lets Chat-triggered image generation use a saved workflow of your choice instead of the one currently loaded in GenerateUI, without disturbing what's shown there (same pattern as Image Edit's Inpaint dedicated workflow)
|
||||
- **Settings pane — Chat I2I Generation** (v0.3.74) — same "Use dedicated workflow" pattern as above, but for image-to-image generation when an image is attached; independent of the text-to-image dedicated workflow setting
|
||||
- **Settings pane — Generation** (v0.3.98) — **Thinking mode** toggle (off by default; sends Ollama's `think` flag, and regardless of backend, any `<think>...</think>` block is stripped from the output when off so reasoning models don't clutter Translation/Chat/TOOLS results) and **Max tokens** (Ollama: `options.num_predict`; LM Studio/Lemonade/Unsloth: `max_tokens`; `0` = unlimited)
|
||||
- **Model unload** (v0.5.4) — an Unload button next to the model selector frees VRAM/memory by unloading the currently selected model from Ollama (`keep_alive:0` via `/api/generate`, the officially documented method — Ollama has no dedicated unload endpoint), LM Studio (`/api/v1/models/unload`), or Lemonade (`/api/v1/unload`); Unsloth exposes no equivalent API and the button is disabled for that backend. **Since v0.7.13**, with the Ollama backend the Unload button here and in the Prompt / Tagger ⚙ Settings modals unloads **every** model loaded in Ollama on localhost, decision models included — the same server step as Settings → VRAM Management's **Unload all now** (a toast shows the models unloaded and the free VRAM before → after)
|
||||
- **Settings shared** — settings saved to `localStorage` under `wfm_ai_settings`; shared with the Library panel's AI TOOL tab so configuration is consistent across both interfaces
|
||||
- **Backend support** — Ollama (`/api/generate` for text, `/api/chat` for conversations, `/api/tags` for model list); LM Studio and Lemonade via the OpenAI-compatible API directly from the browser (`/v1/chat/completions`, `/v1/models`); Unsloth via the same OpenAI-compatible API but relayed through a server-side proxy that attaches the `Authorization: Bearer` header; VLM images sent as base64 (`images:[]` for Ollama, `image_url` content block for LM Studio/Lemonade/Unsloth)
|
||||
- **URL security** — backend URL validated via `new URL()` to enforce `http://` or `https://` scheme
|
||||
- **Lemonade's other endpoints (not integrated)** — Lemonade Server also exposes OpenAI-compatible image generation (`/v1/images/generations`), text-to-speech (`/v1/audio/speech`), and transcription (`/v1/audio/transcriptions`) endpoints; these are not wired up — image generation would duplicate the existing ComfyUI-workflow-based `generate_image` tool call, and audio/TTS has no corresponding UI yet, so both are future considerations rather than a natural extension of the current backend switch
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><h3>Workflow Studio Library (ComfyUI Side Panel) (v0.3.9)</h3></summary>
|
||||
|
||||
- **Tab layout (W / N / P / M / I / A)** — compact single-letter tabs with full name shown on hover
|
||||
- **W — Workflows tab** — browse favorite workflows (All / ★ Favorites / Groups / By Badge sub-tabs), ★ star shown for favorites in All view
|
||||
- **N — Nodes tab** — browse favorite nodes (All / ★ Favorites / Groups / Sets / 📂 Category / 🧩 Package sub-tabs), ★ star shown for favorites in All view; **Alt+click** a node to add it to (or remove it from) Favorites; the tab now opens without waiting for `/object_info` (v0.8.0)
|
||||
- **Category sub-tab** — dropdown to filter nodes by top-level category
|
||||
- **Package sub-tab** — dropdown to filter nodes by custom node package name
|
||||
- **Models tab** — browse installed models (All / ★ Favorites / Groups / By Type sub-tabs)
|
||||
- **Prompts tab** — browse prompt presets with All / Favorites / Categories sub-tabs
|
||||
- **M — Models tab** — browse installed models (All / ★ Favorites / Groups / By Type sub-tabs); LoRA groups show an **All N LoRAs** item — drag to canvas to place a `Lora Loader (LoraManager)` node with all LoRAs pre-loaded
|
||||
- **P — Prompts tab** — browse prompt presets with All / ★ Favorites / Categories sub-tabs; **Groups sub-tab** (row 2) — view presets by group (shared with the Batch tab's `wfm_prompt_preset_groups`)
|
||||
- **I — Information tab** — drop a ComfyUI-generated PNG/WebP/MP4 or workflow JSON in the side panel to view its metadata; detects LoRAs from `LoraLoader`, `LoraLoaderModelOnly`, `Lora Loader (LoraManager)`, and `ImageMetadataLoRALoader` nodes (API format supported); supports `UnetLoaderGGUF` and `QuadrupleCLIPLoader` node types; preview area fixed at 110px
|
||||
- **MP4 embedded metadata** (v0.5.1) — reads the `workflow`/`prompt` container tags ComfyUI's `SaveVideo` writes into the mp4's `moov/udta/meta` box, parsed entirely client-side (same box-walking logic as the Gallery tab's Metadata sub-tab); also recognizes all-in-one video-generation nodes that carry their prompt directly on a `prompt` input rather than a separate `CLIPTextEncode`-style node (e.g. `MiniMaxH3ImageToVideo`)
|
||||
- **A — AI TOOL tab** — Translation, Chat, TOOLS, and Settings sub-tabs powered by Ollama, LM Studio, Lemonade, or Unsloth; Chat supports multi-turn conversations (full history sent each turn); TOOLS includes VLM image analysis and wildcard generation; settings (backend, URL, model) shared with the SPA AI TOOL tab via `localStorage`
|
||||
- **VRAM (Ollama) → Unload all now** (v0.7.13) — in the A tab's Settings sub-tab; unloads every model loaded in Ollama on localhost, decision models included (same as Workflow Studio's Settings → VRAM Management)
|
||||
- **model sub-tab** — Checkpoint, VAE, Diffusion Model, and Text Encoder; drag items to canvas to place the corresponding loader node (Checkpoint → `CheckpointLoaderSimple`, VAE → `VAELoader`, Diffusion Model → `UNETLoader`, Text Encoder → `CLIPLoader`); double-click also places at canvas center
|
||||
- **lora sub-tab** — detects LoRAs from `LoraLoader`, `LoraLoaderModelOnly`, and `Lora Loader (LoraManager)` nodes (API format `inputs.loras.__value__` supported); shows `strength_model / strength_clip` values; drag individual LoRA to place `LoraLoader`; **Multiple LORA** section (appears for 1+ LoRAs) drags all LoRAs into a single `Lora Loader (LoraManager)` node with LoRA syntax pre-filled
|
||||
- **Prompts sub-tab** — POS / NEG badge list; drag a prompt to place `CLIPTextEncode` with text pre-filled; click any entry to view full text + Copy button
|
||||
- **Drag & drop workflows** — drag a workflow onto the canvas to load it
|
||||
- **Drag & drop nodes** — drag nodes/node sets onto the canvas to place them
|
||||
- **Drag & drop prompts** — drag a preset onto the canvas to create a WFS_PromptText node with positive/negative prompts
|
||||
- **Send to Canvas** — clicking "Send to Canvas" (Workflow tab toolbar / detail modal) sends the workflow directly to the ComfyUI canvas via `window.opener` when available (UI and API formats both supported); if Workflow Studio was opened from a bookmark instead of the ComfyUI toolbar (or in another tab), it filters the Library's **W** tab down to that workflow's card instead (v0.4.7) — drag the card onto the canvas yourself; this replaced the old title-drag fallback, which had no thumbnail and didn't work for API-format workflows at all. "Copy & Send Canvas" (Gallery tab JSON panel) still uses only `window.opener` + title-drag for UI-format workflows, since the embedded workflow it sends isn't a saved Library file to filter down to
|
||||
- **Copy prompts** — copy individual positive (P) or negative (N) prompts from sidebar items
|
||||
- **Double-click** — load workflows or place nodes without dragging
|
||||
- **Search** — search within each sub-tab to quickly find items
|
||||
- **⚙ Theme settings** — customize panel background, sub-header background, text, border, and secondary text colors; saved to localStorage and applied on every open
|
||||
|
||||
### Help & Support Tab (v0.1.3)
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><h3>Help & Support Tab (v0.1.3)</h3></summary>
|
||||
|
||||
- **Sidebar navigation** — 2-column layout: left sidebar (15 topics) + right content pane; click any topic to switch the displayed content
|
||||
- **Support** — fixed at the bottom of the sidebar; shows GitHub, Ko-fi, **ComfyUI Image Feeder**, and **Mask Editor One** repository links in the right pane
|
||||
- **Feature list** — overview of all features organized by tab
|
||||
- **Tips** — quick tips for drag & drop import, favorites, and default workflow
|
||||
- **Support links** — GitHub repository and Ko-fi donation page
|
||||
- **Keyboard Shortcuts** and **Troubleshooting** sections included
|
||||
|
||||
</details>
|
||||
|
||||
---
|
||||
|
||||
@@ -167,6 +587,35 @@ Restart ComfyUI after installation.
|
||||
|
||||
---
|
||||
|
||||
## Sample Workflows
|
||||
|
||||
Sample workflows are included in the `workflows/` folder. You can open them directly in ComfyUI via drag & drop, or load them from the Workflow tab.
|
||||
|
||||
Samples for the Feeder tab: `ws_sdxl_image_feeder_i2i` / `ws_dwpose_image_feeder` (Image Loop mode, require the `comfyui-image-feeder` custom node) and `ws_sdxl_gallery_feeder_i2i` (v0.8.3, SDXL I2I with the bundled **WFS_GalleryFeeder** node — no extra custom node needed; put images in the `__Feeder__` Gallery group and use the Feeder tab's Gallery mode).
|
||||
|
||||
> **Note:** Some sample workflows require additional custom nodes.
|
||||
> If a node is shown as missing (red/unknown) after loading, install the required custom nodes via **ComfyUI Manager** or by cloning the repository from GitHub into your `ComfyUI/custom_nodes/` directory.
|
||||
>
|
||||
> ```bash
|
||||
> cd ComfyUI/custom_nodes
|
||||
> git clone <repository-url>
|
||||
> ```
|
||||
>
|
||||
> After installation, restart ComfyUI to activate the new nodes.
|
||||
|
||||
---
|
||||
|
||||
## Manual
|
||||
|
||||
A beginner-oriented manual (covers v0.9.6, text-only edition without screenshots) is available in [`docs/manual/`](docs/manual/):
|
||||
|
||||
- English: [`docs/manual/en/`](docs/manual/en/) — ZIP: `Workflow_Studio_Manual_v0.9.6_en.zip`
|
||||
- 日本語: [`docs/manual/`](docs/manual/) — ZIP: `Workflow_Studio_Manual_v0.9.6.zip`
|
||||
|
||||
An EPUB edition with screenshots (Japanese and English, v0.9.6) is available on [Google Drive](https://drive.google.com/drive/folders/14mOHcnLYrFgNrOo6fy7ELyFjjWrAoU-_?usp=sharing).
|
||||
|
||||
---
|
||||
|
||||
## Usage
|
||||
|
||||
### Launch
|
||||
@@ -201,152 +650,31 @@ Click the **camera icon** (next to the W button) in ComfyUI's top bar to capture
|
||||
|
||||
### Optional
|
||||
|
||||
- **[Ollama](https://ollama.com/)** — for AI chat assistant and translation features
|
||||
- **[Ollama](https://ollama.com/)** — for AI chat assistant, translation, and VLM features
|
||||
- **[LM Studio](https://lmstudio.ai/)** — alternative backend for translation and VLM (OpenAI-compatible API)
|
||||
- **[Lemonade Server](https://lemonade-server.ai/)** — alternative backend for translation, chat, and VLM (OpenAI-compatible API)
|
||||
- **[Unsloth](https://unsloth.ai/)** — alternative backend for translation, chat, and VLM (OpenAI-compatible API); needs an API key set via `UNSLOTH_API_KEY` in a `.env` file, or Unsloth's Keyless API access → "Chat and inference" turned on — `pip install -r requirements.txt` for `python-dotenv`
|
||||
- **Gemini API key / EmbeddingGemma 2** (v0.8.2) — only for the Gallery's Semantic Search: either set `GEMINI_API_KEY` in the plugin's `.env` (key from [Google AI Studio](https://aistudio.google.com); free tier available, paid beyond it), or use the local **EmbeddingGemma 2** in [Ollama](https://ollama.com) (no key; `ollama pull embeddinggemma-2:740m` or `embeddinggemma-2:440m`)
|
||||
- **[Eagle](https://eagle.cool/)** — for auto-saving generated images with metadata
|
||||
- **[comfyui-mask-editor-one](https://github.com/ketle-man/comfyui-mask-editor-one) (v0.1.9+)** — enables BiRefNet background removal, SAM3 text-prompt segmentation, and ABR stamp-brush library in the Image Edit Mask tool; `birefnet.safetensors` must be placed in `ComfyUI/models/background_removal/` for BiRefNet
|
||||
- **[psd-tools](https://pypi.org/project/psd-tools/)** (v0.6.0) — enables all PSD (Photoshop) features: Gallery bulk "Create PSD" export, Gallery browsing/thumbnails for `.psd` files, and Image Edit's Save PSD / Open PSD buttons; `pip install -r requirements.txt` (ships prebuilt wheels, no C compiler required); without it, PSD-related actions show an error toast with the install command instead of failing silently
|
||||
|
||||
#### Backend connection security (v0.7.12)
|
||||
|
||||
Server-side proxies for Ollama, LM Studio, Lemonade, Unsloth, the Tagger VLM and Eagle only connect to **localhost / 127.0.0.1 / ::1** (any port); `http(s)` only, no credentials in the URL, and redirects are never followed. To use a backend on another machine (e.g. an Ollama server on your LAN), list it in the `WFS_ALLOWED_BACKEND_HOSTS` environment variable (comma-separated `host` or `host:port`, e.g. `192.168.1.20:11434,gpu-box`) and restart ComfyUI. If you start ComfyUI with `--listen`, anyone who can reach it can use these routes, so only do that on a trusted network.
|
||||
|
||||
---
|
||||
|
||||
## Supported Languages
|
||||
|
||||
| Language | Status |
|
||||
|----------|--------|
|
||||
| -------- | ------ |
|
||||
| English | Full |
|
||||
| Japanese | Full |
|
||||
| Chinese | Full |
|
||||
|
||||
---
|
||||
|
||||
## Changelog
|
||||
|
||||
### v0.3.3
|
||||
- **Wildcard support panel** — new right column in the Prompt tab with a one-click toolbar for inserting wildcard syntax (`{|}`, `{n$|}`, `__|__`, `:`, `;`, `$`, `<lora::1:LBW=;>`, `[]`, single/multi pick) and wrapping selected text; dedicated prompt textarea and wildcard file picker (click to insert `__filename__`)
|
||||
- **Wildcard file manager** — create, view, edit, and delete `.txt` / `.yaml` wildcard files stored in `user/default/Workflow-Studio/wildcard/`; editor opens inline with filename input and save/cancel controls
|
||||
- **Preset/Preset Manager tab switch** — the center pane of the Prompt tab is now a two-tab panel (Presets / Preset Manager) to reclaim horizontal space for the new wildcard panel
|
||||
- **Wildcard Integration setting** — new accordion section in Settings tab; auto-detects ComfyUI-Impact-Pack; when installed, provides a button to create a directory junction (Windows) or symlink (other OS) from the WFS wildcard directory to Impact Pack's `wildcards/` directory; existing WFS files are migrated automatically; a Remove Link button reverses the operation
|
||||
|
||||
### 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
|
||||
- **Tree state preserved** — folder expansion state is maintained after create/delete/move/refresh operations
|
||||
- **Workflow viewer improved** — Metadata tab now reads both `prompt` (API format, the default for most ComfyUI-generated images) and `workflow` (UI format) keys from PNG metadata, covering virtually all ComfyUI output
|
||||
- **Workflow auto-save** — after each generation in the Generate UI tab, the current workflow is automatically saved to gallery metadata for the generated images; shown in the Metadata tab even if PNG embedding is absent
|
||||
|
||||
### v0.3.0
|
||||
- **Cross-type group filter** — the group filter dropdown in the Models tab now shows groups from all model types simultaneously, each prefixed with a type label (`[Checkpoint]`, `[LoRA]`, etc.); selecting a group automatically switches to the corresponding model type
|
||||
- **Sidebar group display fixed** — the ComfyUI sidebar "Model Groups" view now correctly renders per-type groups (introduced in v0.2.9) with a type label on each group header; fixes a crash where `.filter is not a function` was thrown on the new nested group structure
|
||||
|
||||
### v0.2.9
|
||||
- **Model Enable/Disable** — hide models from ComfyUI by renaming the file extension to `.disabled`; toggle per model (⏸ button on each card/row), per group (Enable All / Disable All buttons in the Group panel), or filter the grid by status (All / Enabled only / Disabled only). Changes take effect after ComfyUI refresh.
|
||||
- **Per-type model groups** — groups are now scoped to each model type; checkpoint groups only appear in the Checkpoint tab, LoRA groups only in the LoRA tab, etc. Existing flat groups are automatically migrated.
|
||||
- **Multi-select mode** — click the Select button in the toolbar to enter selection mode; check individual models across Thumbnail / Card / Table views
|
||||
- **Bulk group operations** — with models selected, add or remove them from any group in one click, or create a new group and add them simultaneously
|
||||
- **Bulk file delete** — permanently delete selected model files along with all associated preview images and sidecar files (`.json`, `.civitai.info`, `.info`); requires confirmation before deleting
|
||||
- **Bug fix** — models in subdirectories could not be disabled due to a path-doubling error; fixed by computing the rename target from `path.name` instead of `model_name`
|
||||
- **Bug fix** — Hypernetwork tab showed `C`, `O`, `M`, `B` as fake model items; caused by the new ComfyUI API format returning `"COMBO"` as the first element; fixed in `comfyui-client.js`
|
||||
|
||||
### v0.2.8
|
||||
- **Data storage moved** — plugin data (settings, metadata, prompts, etc.) is now stored in `ComfyUI/user/default/Workflow-Studio/` instead of `custom_nodes/ComfyUI-Workflow-Studio/data/`; falls back to the old `data/` directory if `user/default/` does not exist
|
||||
- **Data Management section** — new Settings tab section to export all plugin data to a single JSON file and import it back; useful for migration, backup, and reinstallation
|
||||
|
||||
### v0.2.7
|
||||
- **Gallery tab** — new image browser for ComfyUI output folder; Thumbnail/Table views, multi-select with Bulk Bar, server-side group/tag/favorite filtering, group management (rename support), performance-optimized with + mtime folder cache
|
||||
- **Group UI unified** — Workflow, Nodes, and Gallery group panels rebuilt to match the Models tab 4-section pattern (Current Groups / Add to Group / Create New Group / Manage Groups); Rename support added to Workflow and Nodes tabs
|
||||
- **Settings 2-column layout** — Theme panel fixed on the right (50% width, sticky); all other settings flow continuously on the left with no visual gap
|
||||
- **Gallery output directory setting** — configure the output folder scanned by Gallery tab from Settings
|
||||
- **Help tab** — Gallery tab description card added
|
||||
|
||||
### v0.2.5
|
||||
- **Sidebar Category/Package sub-tabs** — added 📂 Category and 🧩 Package sub-tabs to the Nodes tab in Workflow Studio Library; each shows a dropdown to filter nodes by category or custom node package (reads `/object_info` for accurate package detection)
|
||||
- **Sidebar theme settings** — added ⚙ button in the panel header to customize background, sub-header background, text, border, and secondary text colors with live preview; settings saved to localStorage
|
||||
- **Sidebar TextEncoder (By Type)** — fixed TextEncoder not appearing in Models → By Type; now uses `DualCLIPLoader` → `CLIPLoader` fallback to retrieve `clip_name1` list
|
||||
- **Hide `.index.json`** — excluded `.index.json` from both the Workflow tab and the Workflow Studio Library side panel
|
||||
|
||||
### v0.2.4
|
||||
- **GenerateUI tab redesign** — reorganized from 5 tabs (Prompt/Image/Model/Settings/Raw JSON) to 3 tabs (Input/Model/Settings); each tab shows a Raw JSON column (540px) for instant JSON preview and direct editing from any tab
|
||||
- **Input tab** — Prompt and Image stacked vertically in the left column
|
||||
- **Settings tab** — KSampler and LatentImage stacked vertically in the left column
|
||||
- **Raw JSON tab removed** — Raw JSON is now always visible as a right-column panel within each tab
|
||||
|
||||
### v0.2.3
|
||||
- **Badge system unified** — Workflow and Models tabs now share a single badge palette (`⚙ Badge` button); workflow auto-analysis model type system removed in favor of user-defined free-label badges
|
||||
- **GenUI Model button** — apply any model from the Models tab directly to the corresponding node in GenerateUI's current workflow (available in detail modal and side panel; Checkpoint / LoRA / VAE / ControlNet / UNET / TextEncoder)
|
||||
- **Sidebar Models tab** — added All / ★ Favorites / Groups / By Type sub-tabs to the Models section of Workflow Studio Library
|
||||
- **Sidebar All views** — ★ star displayed for favorite items in Workflows and Nodes All sub-tabs
|
||||
- **Sidebar panel width** — widened from 280px to 310px
|
||||
|
||||
### v0.2.2
|
||||
- **Models tab** — browse, search, and manage all installed ComfyUI models (Checkpoint, LoRA, VAE, ControlNet, UNET, TextEncoder) with Thumbnail/Card/Table views
|
||||
- **CivitAI integration** — fetch model metadata by SHA256 hash (individual or batch per model type) with SSE progress streaming
|
||||
- **Model groups** — create, rename, delete groups and assign/remove models for organization
|
||||
- **Model metadata** — persistent favorites, tags, memo, and SHA256 hash per model
|
||||
- **Preview images** — auto-detect and display preview images, change via file upload in detail modal
|
||||
- **Table view memo column** — memo displayed in table view with compact subdir/extension columns
|
||||
- **Side panel file path** — display full file path with click-to-copy in model info panel
|
||||
- **Node card redesign** — removed package badge, added left border color-coding by package
|
||||
- **Toolbar pagination** — pagination controls moved to toolbar for all tabs (Models, Workflows, Nodes)
|
||||
- **Help tab updated** — Models Tab section added to feature list
|
||||
|
||||
### v0.2.0
|
||||
- **Prompt presets in sidebar** — added Prompts tab to Workflow Studio Library (ComfyUI side panel) with All / Favorites / Categories sub-tabs
|
||||
- **WFS_PromptText custom node** — drag prompt presets onto the canvas to create nodes with positive/negative prompt outputs
|
||||
- **Preset Manager** — 3-column layout in Prompt tab: AI Assistant | Presets editor | Preset Manager (All / Favorites / Groups)
|
||||
- **Group management** — create groups, assign/remove presets, delete groups from the Presets panel
|
||||
- **GenUI Set** — renamed "Apply" button to clarify its purpose (applies presets to GenerateUI)
|
||||
- **Sidebar P/N copy buttons** — copy positive or negative prompts individually from sidebar items
|
||||
- **Panel renamed** — "WF & Node Library" renamed to "Workflow Studio Library"
|
||||
- **Backend API for presets** — presets migrated from localStorage to server-side API with one-time migration
|
||||
- **Help tab updated** — Prompt Tab and Workflow Studio Library sections reflect new features
|
||||
|
||||
### v0.1.9
|
||||
- **Side panel 2-row sub-tabs** — Workflows: row 1 (Workflows / Favorites / Groups), row 2 (Model Type); Nodes: row 1 (Nodes / Favorites / Groups), row 2 (Sets)
|
||||
- **Save dialog** — canvas snapshot now shows a filename edit dialog instead of auto-naming
|
||||
- **API/App format badge** — workflow items in side panel show red (API) or orange (APP) badge
|
||||
- **Group auto-cleanup** — deleted workflows are automatically removed from groups on refresh
|
||||
|
||||
### v0.1.8
|
||||
- **WF & Node Library side panel** — renamed from "Node Library", added two top-level tabs (Workflows / Nodes) accessible from ComfyUI top bar
|
||||
- **Workflows tab** — browse favorite workflows, filter by model type, filter by group with collapsible sections
|
||||
- **Workflow drag & drop** — drag workflows from the side panel onto the canvas to load them instantly
|
||||
- **Help tab update** — added Nodes Tab and WF & Node Library sections to the feature list
|
||||
|
||||
### v0.1.7
|
||||
- **Nodes tab** — browse, search, and filter all installed ComfyUI nodes with Card/Table views, pagination (50 nodes/page), package color badges, and node detail side panel with I/O specs
|
||||
- **Node Sets** — save selected nodes + connections from ComfyUI canvas as reusable sets via right-click context menu
|
||||
- **Node Library side panel** — accessible from ComfyUI top bar with Favorites, Sets, and Groups tabs, drag & drop placement
|
||||
- **3 top bar buttons** — Workflow Studio, Canvas Snapshot, and Node Library buttons in ComfyUI's action bar
|
||||
|
||||
### v0.1.6
|
||||
- **Security fix** — path traversal vulnerability in `workflow_service.py` (reported via ComfyUI-Manager PR review)
|
||||
|
||||
### v0.1.5
|
||||
- **Theme system** — 13 built-in themes selectable from Settings tab with instant preview (Deep Ocean Dark, Pop & Vibrant, Light Minimalist, Cyberpunk, Glassmorphism, Neumorphism, Retro 8-bit, Pastel Dream, Brutalism, Earthy, Material UI, Monotone + Accent, Corporate Trust)
|
||||
- Theme preference persisted in localStorage and restored on page load (no flash)
|
||||
- Special CSS effects per theme: neon glow (Cyberpunk), backdrop blur (Glassmorphism), dual shadow (Neumorphism), pixel borders (Retro/Brutalism)
|
||||
|
||||
### v0.1.4
|
||||
- **App format support** — detect `.app.json` workflows (ComfyUI App mode), show "App Format" badge, block loading in GenerateUI with guidance message
|
||||
- **Preset clipboard copy** — added PP Copy / NP Copy buttons to copy positive/negative prompts to clipboard
|
||||
- **Analysis bugfix** — fixed workflow analysis crash when `widgets_values` contains non-string values (e.g. integers)
|
||||
|
||||
### v0.1.3
|
||||
- Added **Help & Support tab** — feature list, tips, and support links (GitHub, Ko-fi)
|
||||
- Multi-language support (EN/JA/ZH) for all help content
|
||||
|
||||
### v0.1.2
|
||||
- Added **Canvas Snapshot** button to ComfyUI top bar — capture workflow canvas as PNG thumbnail with embedded workflow metadata
|
||||
- Added **Thumbnail tab** to the workflow side panel for quick visual preview
|
||||
- Added **Thumbnail section** to the workflow detail modal
|
||||
- Snapshot images are auto-imported as workflows with thumbnails
|
||||
|
||||
### v0.1.1
|
||||
- Initial feature set: Workflow management, GenerateUI, Prompt assistant, Settings
|
||||
|
||||
---
|
||||
|
||||
## Project Structure
|
||||
|
||||
```
|
||||
@@ -356,7 +684,8 @@ ComfyUI-Workflow-Studio/
|
||||
│ ├── wfm.py # Main class & route registration
|
||||
│ ├── config.py # Path configuration
|
||||
│ ├── nodes/
|
||||
│ │ └── prompt_text.py # WFS_PromptText custom node (positive/negative prompt)
|
||||
│ │ ├── prompt_text.py # WFS_PromptText custom node (positive/negative prompt)
|
||||
│ │ └── gallery_feeder_node.py # WFS_GalleryFeeder custom node (gallery group → IMAGE)
|
||||
│ ├── routes/
|
||||
│ │ ├── workflow_routes.py # Workflow CRUD & analysis API
|
||||
│ │ ├── nodes_routes.py # Nodes metadata & node sets API
|
||||
@@ -364,7 +693,9 @@ ComfyUI-Workflow-Studio/
|
||||
│ │ ├── prompts_routes.py # Prompt presets CRUD API
|
||||
│ │ ├── settings_routes.py # Settings API
|
||||
│ │ ├── ollama_routes.py # Ollama proxy API
|
||||
│ │ └── eagle_routes.py # Eagle integration API
|
||||
│ │ ├── eagle_routes.py # Eagle integration API
|
||||
│ │ ├── gallery_routes.py # Gallery tab API (Output + ImagePrompt + Style_Catalog sub-tabs)
|
||||
│ │ └── tagspace_routes.py # TagSpace tab API (build / space / search / neighbors)
|
||||
│ └── services/
|
||||
│ ├── workflow_service.py # Workflow file operations
|
||||
│ ├── nodes_service.py # Node metadata & node sets
|
||||
@@ -373,9 +704,11 @@ ComfyUI-Workflow-Studio/
|
||||
│ ├── prompts_service.py # Prompt presets persistence
|
||||
│ ├── workflow_analyzer.py # Model/node detection
|
||||
│ ├── settings_service.py # Settings persistence
|
||||
│ └── png_extractor.py # PNG metadata extraction
|
||||
│ ├── png_extractor.py # PNG metadata extraction
|
||||
│ ├── gallery_service.py # Gallery image scanning, .txt sidecar & ponyxlWildcardsVault prompt resolution
|
||||
│ └── gallery_metadata.py # Gallery per-image metadata store (favorites/tags/memo/groups)
|
||||
├── templates/
|
||||
│ └── index.html # SPA template (Workflow/GenerateUI/Prompt/Settings/Nodes/Models/Help)
|
||||
│ └── index.html # SPA template (Workflow/GenerateUI/Prompt/Metadata/Gallery/Nodes/Models/Settings/Help/AI)
|
||||
├── static/
|
||||
│ ├── favicon.svg # Browser tab icon (W+S Wave)
|
||||
│ ├── css/main.css # Styles
|
||||
@@ -383,18 +716,29 @@ ComfyUI-Workflow-Studio/
|
||||
│ ├── app.js # App initialization & routing
|
||||
│ ├── workflow-tab.js # Workflow browser
|
||||
│ ├── generate-tab.js # Generation UI
|
||||
│ ├── feeder-tab.js # Feeder subtab (Image Loop + Gallery modes)
|
||||
│ ├── gallery-tab.js # Gallery tab: Output sub-tab (image browser, groups, metadata) + sub-tab switching
|
||||
│ ├── image-prompt-tab.js # Gallery tab: ImagePrompt sub-tab (visual prompt builder)
|
||||
│ ├── style-catalog-tab.js # Gallery tab: Style_Catalog sub-tab (visual Style picker)
|
||||
│ ├── tagger-tab.js # Tagger tab (WD Tagger, DeepDanbooru, Ollama VLM)
|
||||
│ ├── prompt-tab.js # AI assistant & presets
|
||||
│ ├── metadata-tab.js # Metadata extraction & display (PNG/WebP/JSON)
|
||||
│ ├── settings-tab.js # Settings panel
|
||||
│ ├── comfyui-client.js # ComfyUI WebSocket/API client
|
||||
│ ├── nodes-tab.js # Node browser & node sets
|
||||
│ ├── models-tab.js # Model browser & CivitAI integration
|
||||
│ ├── ai-tab.js # AI TOOL tab (Translation | Chat | TOOLS/VLM | Settings)
|
||||
│ ├── comfyui-workflow.js # UI-to-API format conversion
|
||||
│ ├── comfyui-editor.js # Dynamic parameter editor
|
||||
│ ├── json-highlight.js # JSON syntax highlighting
|
||||
│ ├── util.js # Shared utilities (escapeHtml, readJsonStorage, getSettings)
|
||||
│ └── i18n.js # Internationalization
|
||||
├── web/comfyui/
|
||||
│ ├── top_menu_extension.js # ComfyUI menu bar integration
|
||||
│ └── node_sets_menu.js # Workflow Studio Library side panel
|
||||
│ ├── node_sets_menu.js # Workflow Studio Library side panel
|
||||
│ └── gallery_feeder_extension.js # WFS_GalleryFeeder canvas widgets (After Gen / Run / Stop)
|
||||
├── tools/
|
||||
│ └── import_style_prompt_seed.py # Dev tool: pre-process a wildcards-vault source into ws_image_prompt (not run by the plugin itself)
|
||||
└── data/ # Fallback data dir (used when ComfyUI user/default/ is not found)
|
||||
```
|
||||
|
||||
@@ -410,6 +754,11 @@ MIT License
|
||||
|
||||
- [ComfyUI](https://github.com/comfyanonymous/ComfyUI) by comfyanonymous
|
||||
- [ComfyUI-Custom-Scripts](https://github.com/pythongosssss/ComfyUI-Custom-Scripts) by pythongosssss — Canvas snapshot and PNG workflow embedding implementation reference
|
||||
- [ComfyUI-Lora-Manager](https://github.com/willchil/ComfyUI-Lora-Manager) — Plugin architecture and UI pattern reference
|
||||
- [ComfyUI-Lora-Manager](https://github.com/willmiao/ComfyUI-Lora-Manager) — Plugin architecture and UI pattern reference
|
||||
- [Ollama](https://ollama.com/) for local LLM inference
|
||||
- [Eagle](https://eagle.cool/) for image management
|
||||
- [Pillow (PIL Fork)](https://python-pillow.org/) — server-side thumbnail generation (`data/thumb_cache/`)
|
||||
- [ComfyUI-Gallery](https://github.com/PanicTitan/ComfyUI-Gallery) by PanicTitan — thumbnail grid UX reference
|
||||
- [infinite-image-browsing](https://github.com/zanllp/sd-webui-infinite-image-browsing) by zanllp — thumbnail caching and index strategy reference
|
||||
- [Fooocus](https://github.com/lllyasviel/Fooocus) by lllyasviel — style preset JSON format reference
|
||||
|
||||
|
||||
@@ -9,15 +9,16 @@ WorkflowStudio.add_routes()
|
||||
|
||||
# Register custom nodes (isolated loading)
|
||||
_NODE_MODULES = {
|
||||
"WFS_PromptText": (".py.nodes.prompt_text", "WFS_PromptText"),
|
||||
"WFS_PromptText": (".py.nodes.prompt_text", "WFS_PromptText", "Prompt Text (WFS)"),
|
||||
"WFS_GalleryFeeder": (".py.nodes.gallery_feeder_node", "WFS_GalleryFeeder", "Gallery Feeder (WFS)"),
|
||||
}
|
||||
|
||||
for _name, (_mod_path, _cls_name) in _NODE_MODULES.items():
|
||||
for _name, (_mod_path, _cls_name, _display_name) in _NODE_MODULES.items():
|
||||
try:
|
||||
import importlib
|
||||
_mod = importlib.import_module(_mod_path, package=__name__)
|
||||
NODE_CLASS_MAPPINGS[_name] = getattr(_mod, _cls_name)
|
||||
NODE_DISPLAY_NAME_MAPPINGS[_name] = "Prompt Text (WFS)"
|
||||
NODE_DISPLAY_NAME_MAPPINGS[_name] = _display_name
|
||||
except Exception as _e:
|
||||
print(f"[WARNING] Workflow Studio: Failed to load '{_name}': {_e}")
|
||||
|
||||
|
||||
|
After Width: | Height: | Size: 193 KiB |
|
After Width: | Height: | Size: 273 KiB |
|
After Width: | Height: | Size: 181 KiB |
|
After Width: | Height: | Size: 62 KiB |
|
After Width: | Height: | Size: 181 KiB |
|
After Width: | Height: | Size: 161 KiB |
|
After Width: | Height: | Size: 279 KiB |
|
After Width: | Height: | Size: 427 KiB |
|
After Width: | Height: | Size: 330 KiB |
|
After Width: | Height: | Size: 1.4 MiB |
|
After Width: | Height: | Size: 942 KiB |
|
After Width: | Height: | Size: 1.7 MiB |
|
After Width: | Height: | Size: 72 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 64 KiB |
|
After Width: | Height: | Size: 35 KiB |
@@ -0,0 +1,32 @@
|
||||
# はじめてのComfyUI Workflow Studio
|
||||
|
||||
ノードが苦手でも大丈夫 ― 画像生成をもっと手軽に、もっと整理して
|
||||
|
||||
- 対象バージョン:Workflow Studio v0.9.6
|
||||
- 著者:ketle-man
|
||||
- © 2026 ketle-man
|
||||
|
||||
このマニュアルは、Kindle版をもとにした **画像なしのテキスト版** です。
|
||||
章ごとのファイルは `chapters/` フォルダ、全章をまとめたファイルは `Workflow_Studio_Manual_v0.9.6.md` です。
|
||||
画面の例は省略しているため、実際の画面はWorkflow Studioのヘルプタブとあわせてご覧ください。
|
||||
|
||||
## 目次
|
||||
|
||||
- [00_はじめに](chapters/00_はじめに.md)
|
||||
- [01_第1章_基礎知識](chapters/01_第1章_基礎知識.md)
|
||||
- [02_第2章_インストールと起動](chapters/02_第2章_インストールと起動.md)
|
||||
- [03_第3章_画面の見方](chapters/03_第3章_画面の見方.md)
|
||||
- [04_第4章_ワークフロータブ](chapters/04_第4章_ワークフロータブ.md)
|
||||
- [05_第5章_生成UI_前半](chapters/05_第5章_生成UI_前半.md)
|
||||
- [05_第5章_生成UI_後半](chapters/05_第5章_生成UI_後半.md)
|
||||
- [06_第6章_モデルタブ](chapters/06_第6章_モデルタブ.md)
|
||||
- [07_第7章_プロンプトタブ](chapters/07_第7章_プロンプトタブ.md)
|
||||
- [08_第8章_ギャラリータブ](chapters/08_第8章_ギャラリータブ.md)
|
||||
- [09_第9章_WS_Library](chapters/09_第9章_WS_Library.md)
|
||||
- [10_第10章_AI_TOOL](chapters/10_第10章_AI_TOOL.md)
|
||||
- [11_第11章_さらに広がる機能](chapters/11_第11章_さらに広がる機能.md)
|
||||
- [12_第12章_困ったときは](chapters/12_第12章_困ったときは.md)
|
||||
- [13_付録](chapters/13_付録.md)
|
||||
- [14_おわりに](chapters/14_おわりに.md)
|
||||
|
||||
全章まとめ:[Workflow_Studio_Manual_v0.9.6.md](Workflow_Studio_Manual_v0.9.6.md)
|
||||
@@ -0,0 +1,172 @@
|
||||
# はじめに
|
||||
|
||||
「ComfyUIを入れてみたけれど、ノード画面を見て手が止まってしまった」
|
||||
「ネットで拾ったワークフローが増えすぎて、どれが何だか分からない」
|
||||
「前にうまくいった画像の設定を、もう一度使いたいのに見つからない」
|
||||
|
||||
本書は、そんな方のための **ComfyUI-Workflow-Studio**(以下、Workflow Studio)の入門書です。
|
||||
|
||||
---
|
||||
|
||||
## ComfyUIは、なぜ難しいのか
|
||||
|
||||
ComfyUIは、いま最も自由度の高い画像生成AIソフトの1つです。
|
||||
新しいモデルや技術が発表されると、真っ先に使えるようになるのは、たいていComfyUIです。
|
||||
それなのに、多くの人が最初の一歩でつまずいてしまいます。その理由は、ComfyUIが **普通のアプリケーションとはまったく違う考え方** で作られているからです。
|
||||
|
||||
### 普通のアプリケーションとの違い
|
||||
| | 普通のアプリケーション | ComfyUI |
|
||||
| --- | --- | --- |
|
||||
| 画面 | 開発者が設計した、決まった画面 | ノード(箱)を線でつないで、自分で組み立てる |
|
||||
| 使い方 | ボタンやメニューを押せば動く | どのノードを、どうつなぐかを知らないと動かない |
|
||||
| 機能の追加 | アップデートを待つ | 誰かが作ったカスタムノードを、自分で追加する |
|
||||
| 設定の場所 | 設定画面にまとまっている | ワークフローの中の、あちこちのノードに散らばっている |
|
||||
|
||||
普通のアプリケーションは、言わば「完成品の家電」です。電源を入れれば、決められた使い方ですぐに使えます。
|
||||
一方のComfyUIは、「部品から組み立てる工作キット」です。
|
||||
組み立て方さえ分かれば、どんなものでも作れますが、組み立て方を知らなければ何も作れません。
|
||||
|
||||
### 自由さと、その副作用
|
||||
ComfyUIの最大の魅力は、この **カスタマイズの自由さ** です。
|
||||
世界中の開発者が作ったカスタムノードを組み合わせて、自分だけの処理の流れ(ワークフロー)を作れます。
|
||||
ネットには、上級者が作った高度なワークフローがたくさん公開されていて、ダウンロードすればすぐに試せます。
|
||||
|
||||
しかし、自由さには副作用もあります。
|
||||
|
||||
- **ワークフローが増えすぎる** - 試したいものを次々ダウンロードするうちに、どれが何だか分からなくなる
|
||||
- **どこを触ればいいか分からない** - 他人が作った大きなワークフローは、プロンプトを変えたいだけでも、該当するノードを探すのに苦労する
|
||||
- **素材がバラバラになる** - モデル・LoRA・プロンプト・生成画像が、それぞれ別の場所に散らばり、管理する道具がない
|
||||
- **試行錯誤に手間がかかる** - 条件を少しずつ変えて比べたいだけでも、1回ごとにノードの値を書き換える必要がある
|
||||
|
||||
ComfyUIは「組み立てる」ための道具としては非常に優秀ですが、
|
||||
「整理する」「繰り返し使う」「手軽に試す」ための道具は、ほとんど用意されていません。
|
||||
この空白を埋めるために作られたのが、Workflow Studioです。
|
||||
|
||||
---
|
||||
|
||||
## Workflow Studioの特色
|
||||
|
||||
### 1. なぜ専用画面(SPA)なのか - 「組み立てる」と「使う」を分ける
|
||||
Workflow Studioは、ComfyUIの上部メニューの **W** ボタンから開く、**独立した専用画面**(SPA:シングルページアプリケーション)です。
|
||||
|
||||
ワークフローを組み立てる作業は、ComfyUIのノード画面で試行錯誤するのがいちばんです。
|
||||
Workflow Studioは、そうして作り上げたワークフローを **素早く活用する** ための画面として生まれました。
|
||||
|
||||
そのため、Workflow Studioはワークフローを **入力・処理・出力** の3つに分けて考え、次のように設計されています。
|
||||
|
||||
| 段階 | 設計の考え方 |
|
||||
| --- | --- |
|
||||
| 入力 | プロンプトや画像を入れやすくする |
|
||||
| 処理 | 値の変更は、最小限の操作で済むようにする |
|
||||
| 出力 | 生成されたデータを管理しやすくする |
|
||||
|
||||
設計の根底には、製造現場などで使われる **5S(整理・整頓・清掃・清潔・しつけ)** の考え方があります。
|
||||
必要なものを、必要なときに、すぐ取り出して使える状態を保つことを目指しています。
|
||||
|
||||
そして、ComfyUIのノード画面とWorkflow Studioの2つの画面をつなぐのが、ノード画面の横に開く **WS Library** です。
|
||||
補助機能とあわせて、2つの画面を行き来する作業をスムーズにします。
|
||||
|
||||
### 2. 管理 - 散らばった素材を1か所に
|
||||
| 管理できるもの | できること |
|
||||
| --- | --- |
|
||||
| ワークフロー | サムネイル付きの一覧、バッジ・グループで分類、検索、生成UIで動くかの事前チェック |
|
||||
| モデル・LoRA | 種類ごとの一覧、Civitaiからの情報(トリガーワード・サンプル画像)の自動取得 |
|
||||
| プロンプト | プリセットとして保存・分類、ワイルドカード、スタイル |
|
||||
| 生成画像・音声 | フォルダごとの閲覧、プロンプトや「意味」での検索、埋め込まれた設定の読み取りと再現(音声ファイルにも対応) |
|
||||
|
||||
### 3. 効率化 - ノードを触らずに、すばやく試す
|
||||
- **生成UIタブ** - ワークフローの中から、プロンプト・モデル・サイズなど、よく変える項目だけを自動で取り出し、入力フォームにします。他人が作った大きなワークフローでも、ノードを探さずに使えます
|
||||
- **バッチ生成** - 「手持ちのモデルを全部試す」「プロンプトを順番に試す」「サンプラーを比べる」といった試行錯誤を、まとめて自動で実行します
|
||||
- **Feeder・Lab** - たくさんの画像を順番に処理したり、複数の条件を段階的に切り替えたりする、さらに進んだ自動化もできます
|
||||
|
||||
### 4. 補助機能 - 生成の前後を手助けする
|
||||
- **画像編集(Image Edit)** - レイヤー付きの簡易編集、マスクを使った部分的な描き直し(インペイント)
|
||||
- **ローカルAI連携** - 日本語からのプロンプト翻訳、画像からのプロンプト・タグ作成
|
||||
- **Tagger・Video** - 画像からのタグ自動生成、動画の生成と簡単な編集
|
||||
- **TagSpace** - 手持ちのプロンプト・タグ・生成画像を「意味の近さ」で3Dの空間に並べ、眺めながらタグを選ぶ
|
||||
|
||||
---
|
||||
|
||||
## インストールして損のないカスタムノード
|
||||
|
||||
Workflow Studioは、次の理由から、ComfyUIを使うすべての人に **「とりあえず入れておいて損はない」** カスタムノードだと言えます。
|
||||
|
||||
- **無料で、ComfyUI Managerからすぐに入れられる**
|
||||
- **基本機能に、追加の準備がいらない** - 必要なものはComfyUIに最初から含まれています。AIや画像編集などの追加機能は、使いたくなったときに準備すれば十分です
|
||||
- **今の使い方を変えなくていい** - ワークフローはComfyUIの保存フォルダをそのまま使います。ノード画面での作業も、これまでどおりできます
|
||||
- **使った分だけ便利になる** - ワークフローを一覧で眺めるだけ、生成画像の設定を確かめるだけ、といった使い方から始めて、慣れてきたら生成UIやバッチ生成へと、少しずつ活用の幅を広げられます
|
||||
|
||||
ComfyUIの「自由さ」はそのままに、「分かりやすさ」と「手軽さ」を足してくれる - それがWorkflow Studioです。
|
||||
|
||||
## この本で分かること
|
||||
|
||||
- Workflow Studioのインストールと、基本的な画面の見方
|
||||
- 手持ちのワークフローを、サムネイル付きで整理する方法
|
||||
- ノード画面を触らずに、はじめての1枚を生成する方法
|
||||
- モデル・LoRA・プロンプトを管理して、うまくいった設定を再利用する方法
|
||||
- 生成した画像から、使った設定を読み取って再現する方法
|
||||
- ローカルAIを使った、プロンプトの翻訳や画像の読み取り
|
||||
- よくあるトラブルとその対処法
|
||||
|
||||
## この本で扱わないこと
|
||||
|
||||
- ComfyUI本体のインストール方法
|
||||
(ComfyUIをすでに入れて、起動できる状態から説明を始めます)
|
||||
- ノードを一から組み立てて、ワークフローを自作する方法
|
||||
- 画像生成AIのしくみや、モデルの学習(LoRAの作り方など)の詳しい解説
|
||||
|
||||
---
|
||||
|
||||
## 対象読者
|
||||
|
||||
- ComfyUIを入れたばかりの方、これから本格的に使いたい方
|
||||
- ノード画面が苦手で、もっと手軽に画像を生成したい方
|
||||
- ワークフローやモデル、プロンプトが増えて、整理に困っている方
|
||||
|
||||
パソコンの基本的な操作(ファイルのコピー、フォルダを開く、ブラウザを使う)ができれば、読み進められるように書いています。
|
||||
|
||||
---
|
||||
|
||||
## 本書の対象バージョンと環境
|
||||
|
||||
- **Workflow Studio**:v0.9.6
|
||||
- **ComfyUI**:本書執筆時点の最新版
|
||||
- **OS**:Windows(画面の例はWindowsのものです)
|
||||
|
||||
Workflow Studioは活発に開発が続けられているため、
|
||||
バージョンによっては、画面の見た目やボタンの位置が本書と異なる場合があります。
|
||||
大きく変わった機能は、Workflow Studioの **ヘルプ** タブや、GitHubのリリースノートも確認してください。
|
||||
|
||||
---
|
||||
|
||||
## 本書の表記ルール
|
||||
|
||||
| 表記 | 意味 |
|
||||
| --- | --- |
|
||||
| **太字** | 画面に表示されるボタン名・項目名 |
|
||||
| 「生成UI(GenerateUI)」 | 日本語表示の名前(英語表示の名前) |
|
||||
| `ComfyUI/models/` | フォルダやファイルの場所。環境による読み替えは第2章 2-6 を参照 |
|
||||
| `Ctrl+Z` | キーボードの操作。「+」は同時に押すことを表します |
|
||||
|
||||
> **ポイント**
|
||||
> 知っておくと便利な情報です。
|
||||
|
||||
> **注意**
|
||||
> 間違えるとデータが消えたり、うまく動かなかったりする、気をつけてほしい情報です。
|
||||
|
||||
### 画面の言語について
|
||||
Workflow Studioは英語・日本語・中国語に対応しています。本書では、**日本語表示** の画面で説明します。
|
||||
ただし、生成UIなど一部の画面は、日本語表示にしても英語のまま表示されるボタンや項目があります。
|
||||
その場合は、英語の表示名をそのまま使って説明しています。
|
||||
|
||||
---
|
||||
|
||||
## 本書の読み進め方
|
||||
|
||||
はじめての方は、**第1章から第5章まで** を順番に読み、実際に手を動かしてみてください。
|
||||
第5章で「はじめての1枚」が生成できれば、Workflow Studioの基本は身についています。
|
||||
|
||||
第6章以降は、必要になったところから読んでもかまいません。
|
||||
困ったときは、第12章のトラブルシューティングと、付録の用語集を活用してください。
|
||||
|
||||
それでは、Workflow Studioで、もっと手軽に、もっと楽しく画像生成を始めましょう。
|
||||
@@ -0,0 +1,148 @@
|
||||
# 第1章 ComfyUIとWorkflow Studioの基礎知識
|
||||
|
||||
この章では、操作を始める前に知っておきたい考え方と言葉を整理します。
|
||||
パソコンを触りながら読む必要はありません。通勤中やすきま時間に、気軽に読み進めてください。
|
||||
|
||||
---
|
||||
|
||||
## 1-1 ComfyUIってなに?
|
||||
|
||||
ComfyUI(コンフィーユーアイ)は、画像生成AIを自分のパソコンで動かすための無料ソフトです。
|
||||
Stable Diffusion や FLUX など、さまざまな画像生成AIのモデルに対応しています。
|
||||
|
||||
ComfyUIのいちばんの特徴は、**処理の流れを「箱」と「線」でつないで組み立てる**ことです。
|
||||
|
||||
「モデルを読み込む箱」→「プロンプトを入れる箱」→「画像を作る箱」→「保存する箱」……
|
||||
というように、箱どうしを線でつなぐと、その順番で処理が行われます。
|
||||
|
||||
この方式には、大きなメリットがあります。
|
||||
|
||||
- 処理の中身がすべて見えるので、細かく調整できる
|
||||
- 新しい技術が出ても、箱を追加するだけで試せる
|
||||
- 組み立てた流れを保存して、何度でも使い回せる
|
||||
|
||||
一方で、はじめて触る人にとっては「どこを触ればいいのか分からない」画面でもあります。
|
||||
この本で紹介する **Workflow Studio** は、まさにその「分かりにくさ」をやわらげるための道具です。
|
||||
|
||||
---
|
||||
|
||||
## 1-2 覚えておきたい5つの言葉
|
||||
|
||||
ComfyUIを使ううえで、最低限知っておきたい言葉は次の5つです。
|
||||
|
||||
### ① ノード(Node)
|
||||
画面上に並ぶ「箱」のことです。
|
||||
1つのノードは1つの仕事を受け持ちます。たとえば「モデルを読み込む」「画像を保存する」などです。
|
||||
ノードには入口(入力)と出口(出力)があり、線でつないでデータを受け渡します。
|
||||
|
||||
### ② ワークフロー(Workflow)
|
||||
ノードを線でつないだ「処理の流れ全体」のことです。
|
||||
料理にたとえると、ノードが「切る」「炒める」などの作業で、ワークフローは「レシピ」にあたります。
|
||||
ワークフローはJSON(ジェイソン)という形式のファイルで保存できます。
|
||||
|
||||
> **ポイント**
|
||||
> ComfyUIで作った画像には、多くの場合ワークフローの情報が埋め込まれています。
|
||||
> その画像をComfyUIの画面にドラッグすると、同じワークフローを呼び出せます。
|
||||
|
||||
### ③ モデル(Model)
|
||||
画像を作る「AIの頭脳」にあたるファイルです。数GB〜数十GBと大きいのが一般的です。
|
||||
代表的なものに次の種類があります(詳しくは第6章で説明します)。
|
||||
|
||||
| 種類 | ひとことで言うと |
|
||||
| --- | --- |
|
||||
| Checkpoint(チェックポイント) | 画像生成の本体となるモデル |
|
||||
| LoRA(ローラ) | 絵柄やキャラクターを追加で覚えさせる小さな追加モデル |
|
||||
| VAE | 画像の色合いや細部の仕上げを担当するモデル |
|
||||
|
||||
### ④ プロンプト(Prompt)
|
||||
AIに「どんな画像を作ってほしいか」を伝える文章です。いわゆる「呪文」です。
|
||||
描いてほしいものを書く **ポジティブプロンプト** と、
|
||||
描いてほしくないものを書く **ネガティブプロンプト** の2種類があります。
|
||||
|
||||
### ⑤ キュー(Queue)
|
||||
「生成の予約リスト」のことです。
|
||||
ComfyUIでは、生成ボタンを押すとまずキューに予約が入り、順番に処理されます。
|
||||
何枚分も予約しておけば、席を外している間にまとめて生成してくれます。
|
||||
|
||||
---
|
||||
|
||||
## 1-3 ComfyUIで初心者がつまずくところ
|
||||
|
||||
ComfyUIを入れてみたものの、こんなところで手が止まっていませんか。
|
||||
|
||||
1. **ワークフローが増えて、どれが何だか分からない**
|
||||
ネットで拾ったワークフローを保存していくうちに、ファイル名だけでは見分けがつかなくなります。
|
||||
|
||||
2. **毎回ノード画面で値を探すのが大変**
|
||||
プロンプトやシード値を変えたいだけなのに、大きなワークフローの中から該当するノードを探す必要があります。
|
||||
|
||||
3. **モデルやプロンプトの管理がバラバラ**
|
||||
どのモデルをどこに置いたか、前にうまくいったプロンプトは何だったか……が分からなくなりがちです。
|
||||
|
||||
4. **前に作った画像の設定を再現できない**
|
||||
「あの画像、どの設定で作ったっけ?」となっても、調べ方が分からないことがあります。
|
||||
|
||||
どれも、ComfyUIの機能が足りないというより、**「整理」と「入口」が足りない**ことが原因です。
|
||||
|
||||
---
|
||||
|
||||
## 1-4 Workflow Studioでできること
|
||||
|
||||
Workflow Studioは、ComfyUIに追加して使う **拡張機能(カスタムノード)** です。
|
||||
ComfyUIの中に「管理と生成のための専用画面」を追加してくれます。
|
||||
|
||||
先ほどの4つのつまずきに対して、Workflow Studioは次のように応えます。
|
||||
|
||||
| つまずき | Workflow Studioの解決策 | 本書の章 |
|
||||
| --- | --- | --- |
|
||||
| ワークフローが見分けられない | サムネイル付きの一覧、バッジ・グループ分け、検索 | 第4章 |
|
||||
| ノード画面で値を探すのが大変 | 「生成UI」タブで、必要な項目だけをフォームとして表示 | 第5章 |
|
||||
| モデル・プロンプトがバラバラ | モデルタブ・プロンプトタブでまとめて管理 | 第6・7章 |
|
||||
| 設定を再現できない | ギャラリーで画像のメタデータを確認し、キャンバスへ送る | 第8章 |
|
||||
|
||||
さらに、ComfyUIのノード画面の横に **WS Library** というサイドパネルが追加され、
|
||||
モデルやプロンプトをドラッグ&ドロップでノード画面に置けるようになります(第9章)。
|
||||
|
||||
ローカルで動くAI(OllamaやLM Studioなど)を用意すれば、
|
||||
プロンプトの翻訳や、画像からのタグ生成といったAI補助も使えます(第10章)。
|
||||
|
||||
> **ポイント**
|
||||
> Workflow Studioは、ComfyUIの代わりになるソフトではありません。
|
||||
> 画像を作るのはあくまでComfyUIで、Workflow Studioはその「操作パネル」と「整理棚」の役割です。
|
||||
> そのため、ComfyUIが起動していないと使えません。
|
||||
|
||||
### 画面は日本語で使えます
|
||||
Workflow Studioは英語・日本語・中国語に対応しています。
|
||||
本書では日本語表示の画面で説明し、必要に応じて英語表示の名前を( )で添えます。
|
||||
|
||||
例:「生成UI(GenerateUI)」タブ、「ワークフロー(Workflow)」タブ
|
||||
|
||||
---
|
||||
|
||||
## 1-5 本書の進め方
|
||||
|
||||
本書は、次の順番で読み進めることを想定しています。
|
||||
|
||||
1. **準備する**(第2〜3章)
|
||||
インストールして、画面の見方を覚えます。
|
||||
|
||||
2. **整理する**(第4章)
|
||||
手持ちのワークフローを一覧で見られるようにします。
|
||||
|
||||
3. **作る**(第5章)
|
||||
ノード画面を触らずに、はじめての1枚を生成します。
|
||||
ここまで読めば、Workflow Studioの基本は使えるようになります。
|
||||
|
||||
4. **貯める・見返す**(第6〜8章)
|
||||
モデル・プロンプト・生成画像を管理し、うまくいった設定を再利用します。
|
||||
|
||||
5. **広げる**(第9〜11章)
|
||||
サイドパネルやAI補助など、便利な機能を必要に応じて取り入れます。
|
||||
|
||||
困ったときは、第12章のトラブルシューティングと付録の用語集を見てください。
|
||||
|
||||
> **この章のまとめ**
|
||||
> - ComfyUIは、ノード(箱)をつないだワークフローで画像を作るソフト
|
||||
> - 覚える言葉は「ノード」「ワークフロー」「モデル」「プロンプト」「キュー」の5つ
|
||||
> - Workflow Studioは、ComfyUIに「整理棚」と「かんたん操作パネル」を追加する拡張機能
|
||||
> - まずは第5章の「はじめての1枚」を目標にしよう
|
||||
@@ -0,0 +1,254 @@
|
||||
# 第2章 インストールと起動
|
||||
|
||||
この章では、Workflow StudioをComfyUIに追加して、はじめて画面を開くところまで進めます。
|
||||
ComfyUI本体はすでにインストール済みで、起動できる状態であることを前提にしています。
|
||||
|
||||
---
|
||||
|
||||
## 2-1 動作に必要なもの
|
||||
|
||||
### 必須
|
||||
| 必要なもの | 説明 |
|
||||
| --- | --- |
|
||||
| ComfyUI | 最近のバージョンであればOK。上部メニューにボタンを並べる機能を使うため、新しめのバージョン(フロントエンド v1.33.9 以降)がおすすめです |
|
||||
| Python 3.10 以上 | ComfyUIに同梱されているものでかまいません |
|
||||
| Webブラウザ | Chrome や Edge など、ComfyUIの画面を開いているブラウザ |
|
||||
|
||||
Workflow Studioの基本機能は、ComfyUIが動いていれば追加の準備なしで使えます。
|
||||
|
||||
### あとから必要に応じて
|
||||
次のものは、特定の機能を使うときだけ必要です。最初は気にしなくてかまいません。
|
||||
|
||||
- **Ollama / LM Studio など** - プロンプトの翻訳やAIチャットなどのAI補助機能(第10章)。
|
||||
ギャラリーのセマンティック検索をローカルで行うとき(第8章)と、TagSpaceタブ(第11章)には **Ollama** が必要です
|
||||
- **Eagle** - 生成画像を画像管理ソフトEagleに自動保存する機能(第8章)
|
||||
- **追加のPythonパッケージ** - Tagger(画像からのタグ生成)やPSD書き出しなど(第11章)
|
||||
|
||||
> **ポイント**
|
||||
> 「全部そろえないと使えない」わけではありません。
|
||||
> まずは本体だけ入れて、使いたい機能が出てきたときに追加しましょう。
|
||||
|
||||
---
|
||||
|
||||
## 2-2 ComfyUI Managerでインストールする(おすすめ)
|
||||
|
||||
**ComfyUI Manager** は、カスタムノード(拡張機能)を画面上から検索・インストールできる管理ツールです。
|
||||
最近のComfyUIには最初から入っていることが多く、いちばん手軽な方法です。
|
||||
|
||||
1. ComfyUIを起動し、ブラウザで画面を開きます。
|
||||
2. 上部メニューの **「Manager」** ボタンをクリックします。
|
||||
|
||||
3. **「Custom Nodes Manager」** をクリックします。
|
||||
4. 検索欄に **`Workflow Studio`** と入力します。
|
||||
5. 一覧に表示された **ComfyUI-Workflow-Studio** の **「Install」** をクリックします。
|
||||
|
||||
6. インストールが終わったら、画面の案内に従って **ComfyUIを再起動** します。
|
||||
|
||||
> **注意**
|
||||
> ComfyUIは、起動したときに一度だけ拡張機能を読み込みます。
|
||||
> インストール後は必ずComfyUIを再起動してください。ブラウザの再読み込みだけでは反映されません。
|
||||
|
||||
---
|
||||
|
||||
## 2-3 手動でインストールする(git clone)
|
||||
|
||||
ComfyUI Managerが使えない場合や、Gitに慣れている方は、手動でもインストールできます。
|
||||
コマンドを入力する画面(Windowsなら「コマンドプロンプト」や「ターミナル」)を使います。
|
||||
|
||||
1. ComfyUIのフォルダの中にある **`custom_nodes`** フォルダに移動します。
|
||||
|
||||
```
|
||||
cd ComfyUI/custom_nodes
|
||||
```
|
||||
|
||||
2. 次のコマンドを入力して、Workflow Studioをダウンロードします。
|
||||
|
||||
```
|
||||
git clone https://github.com/ketle-man/ComfyUI-Workflow-Studio.git
|
||||
```
|
||||
|
||||
3. `custom_nodes` の中に **`ComfyUI-Workflow-Studio`** フォルダができていればOKです。
|
||||
4. ComfyUIを再起動します。
|
||||
|
||||
> **ポイント**
|
||||
> `git` コマンドが使えない場合は、Git(Git for Windowsなど)を先にインストールする必要があります。
|
||||
> 不安な方は、2-2のComfyUI Managerを使う方法がおすすめです。
|
||||
|
||||
---
|
||||
|
||||
## 2-4 起動する
|
||||
|
||||
### Wボタンから開く
|
||||
ComfyUIを再起動すると、画面上部のメニューに **「W」** のボタンが追加されています。
|
||||
これがWorkflow Studioを開くボタンです。
|
||||
|
||||
- **クリック** - 新しいタブでWorkflow Studioが開きます。
|
||||
- **Shiftキーを押しながらクリック** - 新しいウィンドウで開きます。ComfyUIの画面と並べて使いたいときに便利です。
|
||||
|
||||
Wボタンの近くには、**カメラのボタン** も追加されています。
|
||||
これは、ワークフローの画面をサムネイルとして保存するためのボタンです(第4章で使います)。
|
||||
|
||||
### アドレスとポート番号のしくみ
|
||||
Wボタンを押すと、ブラウザのアドレス欄にWorkflow Studioのアドレスが表示されます。
|
||||
このアドレスの見方を知っておくと、ブックマークから直接開いたり、トラブルのときに原因を探したりできます。
|
||||
|
||||
アドレスは、次の3つの部分でできています。
|
||||
|
||||
| 部分 | 例 | 意味 |
|
||||
| --- | --- | --- |
|
||||
| ホスト | `127.0.0.1` | どのパソコンにつなぐか。`127.0.0.1`(または `localhost`)は「自分のパソコン」を表す特別な番号です |
|
||||
| ポート番号 | `8188` | そのパソコンの中の、どのソフトにつなぐか |
|
||||
| パス | `/wfm` | そのソフトの中の、どのページを開くか |
|
||||
|
||||
この3つを「`ホスト:ポート番号/パス`」の形でつなげたものが、Workflow Studioのアドレスになります。
|
||||
|
||||
#### ポート番号とは
|
||||
1台のパソコンの中では、たくさんのソフトが同時に通信しています。
|
||||
そこで、どのソフトあての通信なのかを区別するために使われるのが **ポート番号** です。
|
||||
|
||||
マンションにたとえると、ホスト(`127.0.0.1`)が「建物の住所」、ポート番号が「部屋番号」にあたります。
|
||||
同じ建物でも、部屋番号を間違えると目的の相手には届きません。
|
||||
|
||||
ComfyUIは、起動したときに決められたポート番号で待ち受けています。
|
||||
よく使われる番号は次のとおりです。
|
||||
|
||||
| ComfyUIの種類・起動方法 | よく使われるポート番号 |
|
||||
| --- | --- |
|
||||
| ポータブル版・手動インストール版(標準設定) | 8188 |
|
||||
| ComfyUI Desktop(デスクトップアプリ版) | 8000 |
|
||||
| 起動オプション `--port` を指定した場合 | 指定した番号 |
|
||||
|
||||
Stability Matrixなどのランチャーを使っている場合も、ランチャー側の設定で番号が変わることがあります。
|
||||
|
||||
#### 自分のポート番号を確かめる
|
||||
いちばん確実なのは、**いまComfyUIを開いているブラウザのアドレス欄を見る** ことです。
|
||||
`127.0.0.1:` や `localhost:` のあとに続く数字が、ポート番号です。
|
||||
|
||||
ComfyUIを起動したときの黒い画面(コンソール)にも、
|
||||
`To see the GUI go to: http://127.0.0.1:〇〇〇〇` のように表示されます。
|
||||
|
||||
#### アドレスを直接入力して開く
|
||||
ポート番号が分かれば、Wボタンを使わずにWorkflow Studioを開けます。
|
||||
ComfyUIのアドレスの末尾に **`/wfm`** を付けるだけです。
|
||||
|
||||
- ComfyUIが `127.0.0.1:8188` で開いている → Workflow Studioは `127.0.0.1:8188/wfm`
|
||||
- ComfyUIが `127.0.0.1:8000` で開いている → Workflow Studioは `127.0.0.1:8000/wfm`
|
||||
|
||||
よく使う方は、このアドレスをブックマークしておくと便利です。
|
||||
|
||||
> **注意**
|
||||
> ブックマークから開いた場合、ワークフローをComfyUIのキャンバスへ直接送る「Send to Canvas」が使えません。
|
||||
> 代わりに、ComfyUI側のサイドパネル(WS Library)にそのワークフローが表示されるので、自分でキャンバスへドラッグします(第4章・第9章)。
|
||||
> ComfyUIの画面と行き来しながら使うときは、Wボタンから開くのがおすすめです。
|
||||
|
||||
> **ポイント**
|
||||
> Workflow StudioはComfyUIの一部として動いているため、ComfyUIと同じポート番号を使います。
|
||||
> Workflow Studio専用のポート番号はありません。
|
||||
|
||||
---
|
||||
|
||||
## 2-5 表示言語を日本語にする
|
||||
|
||||
Workflow Studioは、はじめは **英語** で表示されます。次の手順で日本語に切り替えましょう。
|
||||
|
||||
1. 上部のタブから **「Settings」** を開きます。
|
||||
2. **「UI Language」** の欄で **「日本語」** を選びます。
|
||||
|
||||
3. 「言語を変更しました。再読み込みします...」という表示のあと、ページが自動で再読み込みされ、日本語表示に切り替わります。
|
||||
|
||||
日本語に切り替えると、タブの名前は次のように変わります(一部は英語のままです)。
|
||||
|
||||
| 英語表示 | 日本語表示 |
|
||||
| --- | --- |
|
||||
| Workflow | ワークフロー |
|
||||
| GenerateUI | 生成UI |
|
||||
| Gallery | ギャラリー |
|
||||
| Prompt | プロンプト |
|
||||
| Models | モデル |
|
||||
| Nodes | ノード |
|
||||
| Settings | 設定 |
|
||||
| Help | ヘルプ |
|
||||
| AI TOOL / Tagger / Image Edit / Video | (英語のまま) |
|
||||
|
||||
> **ポイント**
|
||||
> 言語の設定は、使っている **ブラウザごと** に保存されます。
|
||||
> 別のブラウザや別のパソコンから開いた場合は、もう一度設定してください。
|
||||
|
||||
同じ場所にある **「要約言語」** は、AIでワークフローの説明文を作るときの言語です(第10章)。今は変更しなくてかまいません。
|
||||
|
||||
---
|
||||
|
||||
## 2-6 環境ごとのフォルダの場所
|
||||
|
||||
ComfyUIには、いくつかの入れ方があります。入れ方によって、フォルダの場所が少しずつ違います。
|
||||
本書では、フォルダの場所を **`ComfyUI/` から始まる形** で書いています。
|
||||
お使いの環境に合わせて、下の表の「`ComfyUI/` にあたる場所」に読み替えてください。
|
||||
|
||||
### 本書の書き方と、各環境での場所
|
||||
| 本書の表記 | 中身 | ポータブル版 | ComfyUI Desktop | Stability Matrix |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `ComfyUI/` | ComfyUIの本体フォルダ | `ComfyUI_windows_portable/ComfyUI/` | インストール時に選んだフォルダ(標準では「ドキュメント」内の `ComfyUI`) | `(データフォルダ)/Packages/ComfyUI/` |
|
||||
| `ComfyUI/custom_nodes/` | カスタムノード(Workflow Studioもここ) | `ComfyUI/custom_nodes/` | `ComfyUI/custom_nodes/` | `ComfyUI/custom_nodes/` |
|
||||
| `ComfyUI/models/` | モデル | `ComfyUI/models/` | `ComfyUI/models/` | `(データフォルダ)/Models/`(全パッケージで共有) |
|
||||
| `ComfyUI/output/` | 生成した画像 | `ComfyUI/output/` | `ComfyUI/output/` | `(データフォルダ)/Images/` |
|
||||
| `ComfyUI/user/default/workflows/` | 保存したワークフロー | `ComfyUI/user/default/workflows/` | `ComfyUI/user/default/workflows/` | `ComfyUI/user/default/workflows/` |
|
||||
| ComfyUIのPython | 追加パッケージのインストール先 | `ComfyUI_windows_portable/python_embeded/python.exe` | `ComfyUI/.venv/Scripts/python.exe` | `ComfyUI/venv/Scripts/python.exe` |
|
||||
| 標準のポート番号 | 2-4参照 | 8188 | 8000 | 8188 |
|
||||
|
||||
> **ポイント**
|
||||
> 表の中の `ComfyUI/` は、それぞれの環境の「`ComfyUI/` にあたる場所」を指します。
|
||||
> パスの区切りは、Windowsでは `/` の代わりに `\` で表示されます。
|
||||
|
||||
### ポータブル版
|
||||
ダウンロードしたZIPファイルを展開してできた `ComfyUI_windows_portable` フォルダの中に、すべてが入っています。
|
||||
起動は、フォルダ内の `run_nvidia_gpu.bat` などで行います。
|
||||
**Python** は、ComfyUI専用の `python_embeded` フォルダの中のものを使います(第11章 11-2)。
|
||||
|
||||
### ComfyUI Desktop
|
||||
インストーラーで入れるアプリ版です。最初の起動時に、データを置くフォルダを選びます。
|
||||
フォルダの場所を忘れたときは、アプリのメニューからフォルダを開く項目(「Open Folder」など)を使うと確認できます。
|
||||
標準のポート番号が **8000** なので、アドレスを直接入力するときは注意してください(2-4)。
|
||||
|
||||
### Stability Matrix
|
||||
複数の画像生成ソフトをまとめて管理できるランチャーです。
|
||||
最初に決めた **データフォルダ**(例:`StabilityMatrix/Data/`)の中に、次のように分かれて入っています。
|
||||
|
||||
- **ComfyUI本体** - `Data/Packages/ComfyUI/`
|
||||
- **モデル** - `Data/Models/` の中に、種類ごとのフォルダ(Checkpointは `StableDiffusion`、LoRAは `Lora` など)。ほかのソフトと共有されます
|
||||
- **生成した画像** - `Data/Images/` の中
|
||||
|
||||
> **注意**
|
||||
> Stability Matrixでは、モデルや画像のフォルダが **ComfyUIの本体フォルダの外** にあります。
|
||||
> 本書で「`ComfyUI/models/checkpoints` に置く」と書いてある場合は、Stability Matrixの共有モデルフォルダ(`Data/Models/StableDiffusion` など)に置いてください。
|
||||
> ギャラリーに画像が出てこないときは、設定タブの「ギャラリー Outputフォルダ」が `Data/Images/` の中を指しているか確認しましょう。
|
||||
|
||||
> **ポイント**
|
||||
> フォルダの名前や構成は、各ソフトのバージョンアップで変わることがあります。
|
||||
> 見つからないときは、各ソフトの公式の説明も確認してください。
|
||||
|
||||
---
|
||||
|
||||
## 2-7 うまく起動しないときは
|
||||
|
||||
### Wボタンが表示されない
|
||||
- **ComfyUIを再起動しましたか?** ブラウザの再読み込みだけでは反映されません。
|
||||
- **インストール先は正しいですか?** `ComfyUI/custom_nodes/ComfyUI-Workflow-Studio` にフォルダがあるか確認してください。
|
||||
フォルダの中にさらに同じ名前のフォルダがある(二重になっている)と読み込まれません。
|
||||
- **ComfyUIのバージョンが古くありませんか?** ComfyUI Managerなどから本体を更新してみてください。
|
||||
|
||||
### ページが開かない・「接続できません」と表示される
|
||||
- **ComfyUIは起動していますか?** Workflow StudioはComfyUIの中で動くため、ComfyUIを終了すると開けません。
|
||||
- **ポート番号は合っていますか?** 2-4の方法で、ComfyUIのポート番号を確認してください。
|
||||
たとえばComfyUI Desktopを使っているのに `8188` を入力していると、つながりません。
|
||||
|
||||
### 起動時のコンソールにエラーが出る
|
||||
ComfyUIを起動したときの黒い画面に、`ComfyUI-Workflow-Studio` に関するエラーが表示されていないか確認します。
|
||||
エラーの内容をメモしておくと、第12章のトラブルシューティングや、GitHubで質問するときに役立ちます。
|
||||
|
||||
> **この章のまとめ**
|
||||
> - インストールはComfyUI Managerで「Workflow Studio」を検索するのがかんたん
|
||||
> - インストール後は必ずComfyUIを再起動する
|
||||
> - 上部メニューの「W」ボタンで開く(Shift+クリックで別ウィンドウ)
|
||||
> - アドレスは「ホスト:ポート番号/wfm」。ポート番号はComfyUIを開いているアドレス欄で確認できる
|
||||
> - 設定タブの「UI Language」で日本語に切り替える
|
||||
> - フォルダの場所は環境(ポータブル版・Desktop・Stability Matrix)によって違う。本書の `ComfyUI/` は読み替える
|
||||
@@ -0,0 +1,146 @@
|
||||
# 第3章 画面の見方
|
||||
|
||||
Workflow Studioにはたくさんのタブがありますが、最初から全部を覚える必要はありません。
|
||||
この章では、それぞれのタブが「何をする場所か」をざっくりつかみ、
|
||||
ComfyUI側に追加されるボタンとサイドパネルの役割を確認します。
|
||||
|
||||
---
|
||||
|
||||
## 3-1 タブの一覧と役割
|
||||
|
||||
Workflow Studioを開くと、画面の上部にタブが横一列に並んでいます。
|
||||
|
||||
左から順に、次のタブがあります。
|
||||
「よく使う」に★が付いたタブから覚えていけば十分です。
|
||||
|
||||
| タブ(日本語表示) | 英語表示 | 何をする場所か | よく使う | 本書の章 |
|
||||
| --- | --- | --- | :---: | --- |
|
||||
| ワークフロー | Workflow | 保存したワークフローの一覧・整理 | ★ | 第4章 |
|
||||
| ノード | Nodes | ノードの一覧・お気に入り登録 | | 第11章 |
|
||||
| モデル | Models | Checkpoint・LoRAなどモデルの一覧・整理 | ★ | 第6章 |
|
||||
| 生成UI | GenerateUI | ノード画面を触らずに画像を生成 | ★ | 第5章 |
|
||||
| プロンプト | Prompt | プロンプトの保存・分類・AI補助 | ★ | 第7章 |
|
||||
| ギャラリー | Gallery | 生成した画像の閲覧・設定の確認 | ★ | 第8章 |
|
||||
| Image Edit | Image Edit | 画像の簡易編集・マスク作成 | | 第11章 |
|
||||
| Video | Video | 動画生成・動画編集 | | 第11章 |
|
||||
| Tagger | Tagger | 画像からタグ(プロンプト)を自動生成 | | 第11章 |
|
||||
| TagSpace | TagSpace | タグ・プロンプト・生成画像を意味の近さで3D表示し、タグを選ぶ | | 第11章 |
|
||||
| 設定 | Settings | 言語・テーマ・フォルダなどの設定 | | 本章・第11章 |
|
||||
| ヘルプ | Help | 機能一覧・ショートカット・トラブル対処 | | 本章 |
|
||||
| AI TOOL | AI TOOL | ローカルAIによる翻訳・チャット・画像解析・文字起こし(OCR) | | 第10章 |
|
||||
|
||||
### タブは「整理する」「作る」「補助する」の3グループで考える
|
||||
タブが多くて迷ったときは、次の3つのグループに分けて考えると分かりやすくなります。
|
||||
|
||||
- **整理する** - ワークフロー/ノード/モデル/プロンプト/ギャラリー
|
||||
手持ちの素材を一覧にして、探しやすくするタブです。
|
||||
- **作る** - 生成UI/Image Edit/Video
|
||||
実際に画像や動画を作ったり、手を加えたりするタブです。
|
||||
- **補助する** - AI TOOL/Tagger/TagSpace/設定/ヘルプ
|
||||
他のタブでの作業を助けたり、全体の設定をしたりするタブです。
|
||||
|
||||
> **ポイント**
|
||||
> 各タブは互いにつながっています。
|
||||
> たとえば、ワークフロータブで選んだワークフローを生成UIに読み込んだり、
|
||||
> プロンプトタブで保存したプロンプトを生成UIで呼び出したりできます。
|
||||
|
||||
### ヘルプタブ
|
||||
困ったときに最初に開きたいのが **ヘルプ** タブです。
|
||||
左側に話題の一覧が並び、クリックすると右側に説明が表示されます。
|
||||
|
||||
- 機能一覧(タブごとの機能の概要)
|
||||
- キーボードショートカット
|
||||
- トラブルシューティング
|
||||
- サポート(GitHubなどへのリンク)
|
||||
|
||||
本書を読みながら「このボタンは何だっけ?」と思ったときにも役立ちます。
|
||||
|
||||
---
|
||||
|
||||
## 3-2 ComfyUI側に追加されるボタン
|
||||
|
||||
Workflow Studioをインストールすると、ComfyUIの画面上部のメニューに **3つのボタン** が追加されます。
|
||||
|
||||
| ボタン | 名前 | 役割 |
|
||||
| --- | --- | --- |
|
||||
| ① W | Workflow Studioを開く | Workflow Studioを新しいタブで開きます。Shift+クリックで新しいウィンドウ(第2章) |
|
||||
| ② カメラ | キャンバススナップショット | いまのノード画面を画像として保存し、ワークフローのサムネイルにします(第4章) |
|
||||
| ③ 四角が並んだアイコン | WS Library | ノード画面の横にサイドパネルを開閉します(3-3) |
|
||||
|
||||
ボタンにマウスを重ねると、英語で説明が表示されます。
|
||||
|
||||
> **ポイント**
|
||||
> Workflow Studio本体(タブが並ぶ画面)と、ComfyUIのノード画面は **別のブラウザタブ** で開きます。
|
||||
> 「整理や生成はWorkflow Studio」「細かい組み立てはComfyUIのノード画面」と使い分け、
|
||||
> 2つの画面を行き来しながら使うのが基本のスタイルです。
|
||||
|
||||
---
|
||||
|
||||
## 3-3 サイドパネル「WS Library」
|
||||
|
||||
③のボタンを押すと、ComfyUIのノード画面の横に **WS Library(Workflow Studio Library)** というパネルが開きます。
|
||||
|
||||
WS Libraryは、**Workflow Studioで整理した素材を、ノード画面ですぐ使うための棚** です。
|
||||
パネルの上部には、1文字のタブが並んでいます(マウスを重ねると正式な名前が表示されます)。
|
||||
|
||||
| タブ | 名前 | できること |
|
||||
| --- | --- | --- |
|
||||
| W | Workflows | ワークフローをドラッグしてキャンバスに読み込む |
|
||||
| N | Nodes | お気に入りのノードやノードセットをキャンバスに置く |
|
||||
| P | Prompts | 保存したプロンプトをキャンバスに置く・コピーする |
|
||||
| M | Models | モデルをドラッグして、読み込み用のノードごとキャンバスに置く |
|
||||
| I | Information | 画像やワークフローのファイルを落として、中身(使ったモデルやプロンプト)を調べる |
|
||||
| A | AI TOOL | 翻訳やチャットなどのAI機能を、ノード画面のまま使う |
|
||||
|
||||
たとえば M タブからモデルをキャンバスへドラッグすると、そのモデルを読み込むノードが自動で配置されます。
|
||||
ノードを一覧から探して置いて、ファイル名を選んで……という手間が省けます。
|
||||
|
||||
詳しい使い方は第9章で説明します。今は「ノード画面の横に、素材の棚を出せる」とだけ覚えておけば大丈夫です。
|
||||
|
||||
---
|
||||
|
||||
## 3-4 テーマと見た目の設定
|
||||
|
||||
Workflow Studioの見た目は、**設定** タブで好みに合わせて変えられます。
|
||||
長時間使う道具なので、目が疲れにくい配色や読みやすい文字サイズにしておくのがおすすめです。
|
||||
|
||||
### テーマ
|
||||
**「テーマ」** の欄から、画面全体の配色を選べます。標準は暗い配色の「Deep Ocean Dark」です。
|
||||
|
||||
| テーマの例 | 雰囲気 |
|
||||
| --- | --- |
|
||||
| Deep Ocean Dark(デフォルト) | 暗めの青。画像が見やすい |
|
||||
| Light Minimalist(クリーン) | 白基調で明るくシンプル |
|
||||
| Pastel Dream(パステル) | やわらかいパステル調 |
|
||||
| Corporate Trust(企業向け) | 落ち着いた白と青 |
|
||||
|
||||
このほか、ポップ調・サイバーパンク・レトロなど、全部で13種類のテーマがあります。
|
||||
|
||||
> **ポイント**
|
||||
> 生成した画像の色を確認するときは、暗めのテーマのほうが色を見分けやすくなります。
|
||||
> 迷ったら、まずはデフォルトのまま使ってみましょう。
|
||||
|
||||
### カスタマイズ
|
||||
**「カスタマイズ」** を開くと、選んだテーマをさらに細かく調整できます。
|
||||
|
||||
- **カラー調整** - 背景・テキスト・アクセントなどの色を個別に変更
|
||||
- **背景パターン** - ストライプやドットなどの模様を背景に追加
|
||||
- **フォント** - 文字の書体を変更(Zen丸ゴシック、BIZ UDPゴシックなど日本語フォントも選べます)
|
||||
|
||||
調整が終わったら **「適用して保存」** を押します。
|
||||
元に戻したいときは **「カスタマイズをリセット」** を押します。
|
||||
|
||||
### 文字サイズ
|
||||
**「文字サイズ」** の欄で、画面全体の文字の大きさを変えられます。
|
||||
文字が小さくて読みにくいと感じたら、ここで大きくしましょう。
|
||||
|
||||
### WS Libraryの見た目
|
||||
WS Library(3-3)の配色は、パネル内の **歯車ボタン**から別に設定できます。
|
||||
ComfyUIの画面の色に合わせて、背景や文字の色を調整できます。
|
||||
|
||||
> **この章のまとめ**
|
||||
> - タブは「整理する」「作る」「補助する」の3グループで考えると分かりやすい
|
||||
> - まずはワークフロー・モデル・生成UI・プロンプト・ギャラリーの5つを覚えれば十分
|
||||
> - ComfyUIの上部には「W」「カメラ」「WS Library」の3つのボタンが追加される
|
||||
> - WS Libraryは、ノード画面の横に出せる素材の棚
|
||||
> - 見た目は設定タブのテーマ・カスタマイズ・文字サイズで調整できる
|
||||
@@ -0,0 +1,305 @@
|
||||
# 第4章 ワークフロータブ - 作ったワークフローを整理する
|
||||
|
||||
ワークフロータブは、Workflow Studioを開いたときに最初に表示される、いわば「玄関」です。
|
||||
この章では、手持ちのワークフローを一覧で見られるようにし、
|
||||
あとから探しやすいように整理する方法を学びます。
|
||||
|
||||
---
|
||||
|
||||
## 4-1 ワークフローが自動で一覧表示されるしくみ
|
||||
|
||||
ワークフロータブを開くと、すでにいくつかのワークフローが並んでいるかもしれません。
|
||||
これは、Workflow StudioがComfyUIのワークフロー保存フォルダを自動で読み込んでいるためです。
|
||||
|
||||
ComfyUIのノード画面で「保存(Save)」したワークフローは、通常、次のフォルダに保存されます。
|
||||
|
||||
```
|
||||
ComfyUI/user/default/workflows/
|
||||
```
|
||||
|
||||
Workflow Studioは、このフォルダの中のワークフローを一覧にして表示します。
|
||||
つまり、**ComfyUIで保存したワークフローは、何もしなくてもワークフロータブに並ぶ** というわけです。
|
||||
|
||||
> **ポイント**
|
||||
> ComfyUIで新しく保存したワークフローが一覧に出てこないときは、
|
||||
> ツールバーの **「更新」** ボタンを押してください。最新の状態に読み込み直します。
|
||||
|
||||
> **ポイント**
|
||||
> 読み込むフォルダは、設定タブの **「ワークフローデータフォルダ」** で変更できます。
|
||||
> 特に理由がなければ、そのままで問題ありません。
|
||||
|
||||
---
|
||||
|
||||
## 4-2 画面の見方と表示の切り替え
|
||||
|
||||
ワークフロータブは、大きく3つの部分に分かれています。
|
||||
|
||||
| 番号 | 場所 | 役割 |
|
||||
| --- | --- | --- |
|
||||
| ① | ツールバー(上部) | 検索・絞り込み・並べ替え・各種ボタン |
|
||||
| ② | 一覧(中央) | ワークフローがカードまたは表で並ぶ |
|
||||
| ③ | サイドパネル(右側) | 選んだワークフローのサムネイルや中身を表示 |
|
||||
|
||||
### サムネイル表示とテーブル表示
|
||||
ツールバーの切り替えボタンで、一覧の表示方法を変えられます。
|
||||
|
||||
- **サムネイル** - 画像付きのカードで並べます。見た目で探したいときに便利です。
|
||||
- **テーブル** - 表形式で並べます。たくさんのワークフローを名前で探したいときに便利です。
|
||||
|
||||
### クリックとダブルクリック
|
||||
一覧のワークフローは、クリックの仕方で動きが変わります。
|
||||
|
||||
| 操作 | 動き |
|
||||
| --- | --- |
|
||||
| クリック | 右側のサイドパネルに内容を表示(ワークフローを「選択」した状態になる) |
|
||||
| ダブルクリック | 詳細画面を開く(バッジ・タグ・メモの編集など。4-4で説明) |
|
||||
|
||||
### サイドパネル
|
||||
ワークフローをクリックすると、右側のサイドパネルに次の3つのタブが表示されます。
|
||||
|
||||
- **サムネイル** - ワークフローの画像を大きく表示
|
||||
- **JSON** - ワークフローの中身(JSONデータ)を色分けして表示。「コピー」ボタンで丸ごとコピーできます
|
||||
- **グループ** - ワークフローをグループに分類(4-4で説明)
|
||||
|
||||
ワークフロー名の下には、**ワークフローの形式**(UI形式/API形式など)と、
|
||||
生成UIで使えるかどうかの **チェック結果** が表示されます(4-7で説明)。
|
||||
|
||||
---
|
||||
|
||||
## 4-3 カメラボタンでサムネイルを撮る
|
||||
|
||||
ComfyUIで保存しただけのワークフローは、サムネイル画像がなく、一覧では見分けにくいことがあります。
|
||||
そこで使うのが、ComfyUIの上部メニューに追加された **カメラボタン**(キャンバススナップショット)です。
|
||||
|
||||
### サムネイルの撮り方
|
||||
1. ComfyUIのノード画面で、サムネイルにしたいワークフローを開きます。
|
||||
2. ワークフロー全体が見やすくなるように、画面の位置や拡大率を調整します。
|
||||
3. 上部メニューの **カメラボタン** をクリックします。
|
||||
|
||||
4. 保存する名前を確認する画面が表示されます。必要に応じて名前を変えて保存します。
|
||||
(最初は、いま開いているワークフローの名前が入っています)
|
||||
5. 「Workflow saved」と表示されれば完了です。
|
||||
|
||||
Workflow Studioのワークフロータブを開く(または「更新」を押す)と、
|
||||
撮影した画像がサムネイルとして付いたワークフローが一覧に表示されます。
|
||||
|
||||
> **ポイント**
|
||||
> カメラボタンで保存した画像(PNG)には、ワークフローの情報も埋め込まれています。
|
||||
> この画像をComfyUIのノード画面にドラッグ&ドロップすると、そのワークフローを読み込めます。
|
||||
> 画像ファイル1つで「見た目」と「中身」の両方を持ち運べるので便利です。
|
||||
|
||||
### あとからサムネイルを変える
|
||||
すでにあるワークフローのサムネイルを差し替えたいときは、
|
||||
ワークフローをダブルクリックして詳細画面を開き、**「サムネイル変更」** を押して画像を選びます。
|
||||
|
||||
---
|
||||
|
||||
## 4-4 お気に入り・バッジ・グループで分類する
|
||||
|
||||
ワークフローが増えてきたら、分類しておくと目的のものをすぐに見つけられます。
|
||||
Workflow Studioには、分類のしかたが3種類あります。
|
||||
|
||||
| 方法 | どんなときに使う? | 例 |
|
||||
| --- | --- | --- |
|
||||
| お気に入り(★) | よく使うものに印を付けたい | 毎日使う基本のワークフロー |
|
||||
| バッジ | 色付きのラベルで、ひと目で種類を分けたい | 「SDXL」「FLUX」「動画」「実験中」 |
|
||||
| グループ | 用途やプロジェクトごとにまとめたい | 「キャラクター制作」「背景素材」 |
|
||||
|
||||
### お気に入り(★)
|
||||
カードの **★** をクリックすると、お気に入りに登録されます。
|
||||
ツールバー上部の **★** ボタンを押すと、お気に入りだけを表示できます(**ALL** で全件表示に戻ります)。
|
||||
|
||||
お気に入りに登録したワークフローは、ComfyUI側のサイドパネル(WS Library)の
|
||||
「★ Favorites」にも表示されます(第9章)。
|
||||
|
||||
### バッジ
|
||||
バッジは、ワークフローに付ける **色付きのラベル** です。
|
||||
1つのワークフローに複数のバッジを付けることもできます。
|
||||
|
||||
**① バッジを作る**
|
||||
1. ツールバーの **「Badge」** ボタンを押します。
|
||||
2. **「バッジ名...」** の欄に名前を入力し、**「追加」** を押します。
|
||||
3. 色の見本をクリックすると、バッジの色を変えられます。
|
||||
|
||||
**② ワークフローにバッジを付ける**
|
||||
1. ワークフローをダブルクリックして、詳細画面を開きます。
|
||||
2. **「バッジ」** の欄で、付けたいバッジにチェックを入れます。
|
||||
3. **「保存」** を押します。
|
||||
|
||||
**③ バッジで絞り込む**
|
||||
バッジを作ると、ツールバー上部の ★・ALL ボタンの横にバッジが並びます。
|
||||
バッジをクリックすると、そのバッジが付いたワークフローだけが表示されます。
|
||||
|
||||
> **ポイント**
|
||||
> バッジの種類と色は、モデルタブ(第6章)と共通です。
|
||||
> 「SDXL」というバッジを作れば、ワークフローにもモデルにも同じ色で付けられます。
|
||||
|
||||
### グループ
|
||||
グループは、ワークフローを **用途ごとにまとめる箱** です。
|
||||
|
||||
1. ワークフローをクリックして選択します。
|
||||
2. 右側のサイドパネルで **「グループ」** タブを開きます。
|
||||
3. **「新規グループ作成」** でグループを作るか、既存のグループを選んで **「グループに追加」** します。
|
||||
|
||||
ツールバーの **「全グループ」** と書かれたプルダウンからグループを選ぶと、そのグループのワークフローだけが表示されます。
|
||||
|
||||
### タグとメモ
|
||||
詳細画面では、ほかにも次の情報を書き込めます。
|
||||
|
||||
- **タグ** - 検索用のキーワード。カンマ(,)で区切って複数入力できます。
|
||||
- **メモ** - 使い方の注意点や、うまくいった設定など、自由なメモ。
|
||||
|
||||
ネットから入手したワークフローに「配布元」や「必要なカスタムノード」をメモしておくと、あとで困りません。
|
||||
|
||||
### 名前の変更と削除
|
||||
- **名前を変える** - 詳細画面の上部にあるワークフロー名をクリックすると、名前を編集できます。
|
||||
- **削除する** - 詳細画面の **「削除」** ボタンを押します。
|
||||
|
||||
> **注意**
|
||||
> 削除すると、ComfyUIのワークフロー保存フォルダにあるファイルそのもの(サムネイル画像も含む)が削除されます。
|
||||
> 大切なワークフローは、削除する前に別の場所へバックアップしておきましょう。
|
||||
|
||||
---
|
||||
|
||||
## 4-5 検索・並べ替え・フィルタ解除
|
||||
|
||||
### 検索
|
||||
ツールバーの **「検索...」** 欄にキーワードを入力すると、名前やタグなどに一致するワークフローだけが表示されます。
|
||||
入力欄の右端の **×** を押すと、検索文字がすぐに消えます。
|
||||
|
||||
### 並べ替え
|
||||
検索欄の横のプルダウンで、並び順を変えられます。
|
||||
|
||||
| 選択肢 | 並び順 |
|
||||
| --- | --- |
|
||||
| Date (Newest) | 新しい順 |
|
||||
| Date (Oldest) | 古い順 |
|
||||
| Name A-Z | 名前の昇順 |
|
||||
| Name Z-A | 名前の降順 |
|
||||
|
||||
選んだ並び順は記憶され、次に開いたときも同じ順番で表示されます。
|
||||
|
||||
### フィルタをまとめて解除
|
||||
検索・グループ・バッジで絞り込んでいるうちに、「なぜか一覧に出てこない」と迷うことがあります。
|
||||
そんなときは、ツールバー右端の **「× クリア」** を押してください。
|
||||
検索文字・グループ・バッジの絞り込みが一度に解除され、すべてのワークフローが表示されます。
|
||||
|
||||
---
|
||||
|
||||
## 4-6 インポートとキャンバスへ送る
|
||||
|
||||
### ワークフローを取り込む(インポート)
|
||||
ネットから入手したワークフローのファイル(`.json` または ワークフロー入りの `.png`)は、
|
||||
次のどちらかの方法でワークフロータブに取り込めます。
|
||||
|
||||
- ツールバーの **「インポート」** ボタンを押して、ファイルを選ぶ(複数選択も可能)
|
||||
- ファイルを、ワークフロータブの一覧部分に **ドラッグ&ドロップ** する
|
||||
|
||||
取り込んだワークフローは、ComfyUIのワークフロー保存フォルダに保存され、一覧に追加されます。
|
||||
|
||||
### 選んだワークフローを使う
|
||||
ワークフローをクリックして選択すると、ツールバーの次の3つのボタンが押せるようになります。
|
||||
|
||||
| ボタン | 動き |
|
||||
| --- | --- |
|
||||
| 生成UIに読み込み | 生成UIタブに読み込み、ノード画面を触らずに生成できる状態にする(第5章) |
|
||||
| Videoに読み込み | 動画生成用のワークフローをVideoタブに読み込む(第11章) |
|
||||
| キャンバスへ送る | ComfyUIのノード画面にワークフローを読み込む |
|
||||
|
||||
> **ポイント**
|
||||
> ボタンが押せない(灰色の)ときは、まだワークフローを選択していません。
|
||||
> 一覧のワークフローを一度クリックしてから押してください。
|
||||
|
||||
**「キャンバスへ送る」** を押すと、Workflow Studioを開いたComfyUIのノード画面に、そのワークフローが読み込まれます。
|
||||
Workflow Studioで探して、ComfyUIで細かく編集する、という使い方ができます。
|
||||
|
||||
> **注意**
|
||||
> 「キャンバスへ送る」は、ComfyUIの **Wボタンから開いた** Workflow Studioで使えます。
|
||||
> ブックマークなどから直接開いた場合は、ComfyUI側のWS Libraryにそのワークフローが表示されるので、
|
||||
> そこからキャンバスへドラッグしてください(第2章・第9章)。
|
||||
|
||||
---
|
||||
|
||||
## 4-7 生成UIで動くか事前にチェックする(GenerateUIチェック)
|
||||
|
||||
すべてのワークフローが、生成UI(第5章)でそのまま使えるわけではありません。
|
||||
特殊なカスタムノードを使っていたり、手元にないモデルを指定していたりすると、うまく動かないことがあります。
|
||||
|
||||
そこで、生成UIに読み込む前に、使えそうかどうかを自動でチェックする機能があります。
|
||||
|
||||
### チェック結果の見方
|
||||
ワークフローをクリックすると、サイドパネルのワークフロー名の下に、次の情報が表示されます。
|
||||
|
||||
- **形式バッジ** - ワークフローの保存形式(UI形式/API形式/App形式)
|
||||
- **変換** - 生成UIで使える形に変換できるか
|
||||
- **操作性** - 生成UIの画面だけで、どのくらい設定を変えられるか
|
||||
|
||||
それぞれ、次の3段階で表示されます。
|
||||
|
||||
| 表示 | 意味 |
|
||||
| --- | --- |
|
||||
| ○(チェックマーク) | 問題なし |
|
||||
| △(警告マーク) | 使えるが注意が必要 |
|
||||
| ×(バツ印) | 生成UIでは使えない、または使いにくい |
|
||||
|
||||
バッジにマウスを重ねると、判定の理由が表示されます。
|
||||
|
||||
### よくある判定と対処
|
||||
| 判定 | よくある理由 | 対処 |
|
||||
| --- | --- | --- |
|
||||
| 変換 × | ワークフローに必要なカスタムノードがインストールされていない | ComfyUI Managerで不足しているノードをインストールする(第12章) |
|
||||
| 変換 △ | 指定されたモデルやLoRAが手元にない | 生成UIで手元のモデルを選び直す。UI形式の場合は、自動で一覧の先頭のモデルに差し替えられるので注意 |
|
||||
| 操作性 △/× | 生成UIに表示されない設定が多い | 表示されないノードの設定は、ComfyUIのノード画面で変更する |
|
||||
|
||||
> **ポイント**
|
||||
> 操作性は、「設定を持つノードのうち、生成UIに表示されるものの割合」です。
|
||||
> 80%以上で ○、50%以上で △、それ未満で × になります。
|
||||
> △ や × でも生成自体はできることが多いので、「生成UIだけで完結しにくい」という目安として見てください。
|
||||
|
||||
> **ポイント**
|
||||
> チェックは、そのワークフローで使っているノードの情報だけをComfyUIから取得して行います(v0.8.8〜)。
|
||||
> 以前は最初の1回に数十秒かかることがありましたが、今は一瞬で結果が出ます。
|
||||
|
||||
---
|
||||
|
||||
## 4-8 付属のサンプルワークフローを使ってみる
|
||||
|
||||
Workflow Studioには、すぐに試せるサンプルワークフローが付属しています。
|
||||
サンプルは、Workflow Studioをインストールしたフォルダの中の **`workflows`** フォルダにあります。
|
||||
|
||||
```
|
||||
ComfyUI/custom_nodes/ComfyUI-Workflow-Studio/workflows/
|
||||
```
|
||||
|
||||
各サンプルには、同じ名前の `.json`(ワークフロー本体)と `.png`(サムネイル画像)が入っています。
|
||||
|
||||
### はじめての方におすすめのサンプル
|
||||
| ファイル名 | 内容 |
|
||||
| --- | --- |
|
||||
| `ws_sdxl_t2i_basic` | SDXLモデルで、文章から画像を作る基本のワークフロー |
|
||||
| `ws_sd15_t2i_basic` | SD1.5モデルで、文章から画像を作る基本のワークフロー |
|
||||
|
||||
お手元にあるモデルの種類(SDXLかSD1.5か)に合わせて選んでください。
|
||||
|
||||
### サンプルを取り込む
|
||||
1. ワークフロータブの **「インポート」** を押します。
|
||||
2. 上記の `workflows` フォルダを開き、使いたいサンプルの `.png` ファイルを選びます。
|
||||
(`.png` を選ぶと、サムネイル付きで取り込まれます)
|
||||
3. 一覧に追加されたことを確認します。
|
||||
|
||||
ほかにも、ポーズ指定やインペイント(画像の一部の描き直し)など、応用的なサンプルも入っています。
|
||||
|
||||
> **注意**
|
||||
> 一部のサンプルは、追加のカスタムノードが必要です。
|
||||
> ノード画面で赤く表示されるノードがある場合は、ComfyUI Managerで不足しているノードをインストールしてください(第12章)。
|
||||
> 4-7のGenerateUIチェックで「変換 ×」と表示されるのも、多くはこのケースです。
|
||||
|
||||
次の章では、取り込んだ基本のサンプルを生成UIに読み込んで、いよいよはじめての1枚を生成します。
|
||||
|
||||
> **この章のまとめ**
|
||||
> - ComfyUIで保存したワークフローは、自動でワークフロータブに並ぶ
|
||||
> - クリックでサイドパネルに表示、ダブルクリックで詳細画面
|
||||
> - カメラボタンで、ワークフローに見分けやすいサムネイルを付けられる
|
||||
> - お気に入り・バッジ・グループで分類し、検索・並べ替えで探す。迷ったら「× クリア」
|
||||
> - 「生成UIに読み込み」「キャンバスへ送る」で、選んだワークフローをすぐ使える
|
||||
> - GenerateUIチェックで、生成UIで動くかを事前に確認できる
|
||||
@@ -0,0 +1,255 @@
|
||||
# 第5章 生成UIタブ - ノードを触らずに画像を作る
|
||||
|
||||
いよいよ、Workflow Studioで画像を生成します。
|
||||
**生成UI(GenerateUI)** タブは、ワークフローの中から「プロンプト」「モデル」「サイズ」など
|
||||
よく変える項目だけを取り出して、入力フォームとして表示してくれる画面です。
|
||||
ノードを探して線をたどる必要はありません。
|
||||
|
||||
この章の前半(5-1〜5-4)では、第4章で取り込んだ基本のサンプルを使って、はじめての1枚を生成します。
|
||||
|
||||
> **事前に準備しておくもの**
|
||||
> - ComfyUIが起動していること
|
||||
> - Checkpointモデルが1つ以上、ComfyUIの `models/checkpoints` フォルダに入っていること
|
||||
> - 第4章で、サンプルワークフロー(`ws_sdxl_t2i_basic` など)を取り込んでいること
|
||||
|
||||
---
|
||||
|
||||
## 5-1 ワークフローを生成UIに読み込む
|
||||
|
||||
1. **ワークフロー** タブを開きます。
|
||||
2. 使いたいワークフロー(例:`ws_sdxl_t2i_basic`)を **クリック** して選択します。
|
||||
3. サイドパネルの **GenerateUIチェック**(第4章 4-7)で、「変換」が ○ になっていることを確認します。
|
||||
4. ツールバーの **「生成UIに読み込み」** を押します。
|
||||
|
||||
自動で **生成UI** タブに切り替わり、ワークフローの内容が読み込まれます。
|
||||
画面上部に、読み込んだワークフローの名前が表示されていれば成功です。
|
||||
|
||||
> **ポイント**
|
||||
> 生成UIの画面は、ボタンや項目名の多くが英語のまま表示されます。
|
||||
> 本書では、英語の表示名をそのまま使い、必要に応じて意味を添えて説明します。
|
||||
|
||||
---
|
||||
|
||||
## 5-2 生成UIの画面の見方
|
||||
|
||||
生成UIタブは、大きく次の部分に分かれています。
|
||||
|
||||
| 番号 | 場所 | 役割 |
|
||||
| --- | --- | --- |
|
||||
| ① | 上部のバー | ComfyUIとの接続状態、ワークフロー名、各種ボタン |
|
||||
| ② | サブタブ | Input/Model/Settings/Feeder/Batch/Lab の切り替え |
|
||||
| ③ | 編集エリア(中央) | 選んだサブタブの設定項目 |
|
||||
| ④ | Raw JSON(右側) | ワークフローの中身をJSONで表示(上級者向け) |
|
||||
| ⑤ | 生成パネル | Generateボタン、進み具合、シード設定、生成結果 |
|
||||
|
||||
### ① 上部のバー
|
||||
| 表示・ボタン | 意味 |
|
||||
| --- | --- |
|
||||
| Connected/Disconnected | ComfyUIとつながっているか。緑の **Connected** なら生成できます |
|
||||
| Connect | ComfyUIに接続し直す |
|
||||
| Refresh Models | モデルの一覧を読み込み直す(ComfyUIにモデルを追加したあとに押す) |
|
||||
| Reset Workflow | 編集した内容を捨てて、ワークフローを読み込んだ直後の状態に戻す |
|
||||
| ワークフロー名 | いま読み込んでいるワークフロー |
|
||||
|
||||
> **ポイント**
|
||||
> 生成UIタブを開くと、ComfyUIへの接続は自動で行われます。
|
||||
> **Disconnected** と表示されている場合は、ComfyUIが起動しているか確認して **Connect** を押してください。
|
||||
|
||||
### ② サブタブ
|
||||
| サブタブ | 何を設定するか | 本書 |
|
||||
| --- | --- | --- |
|
||||
| Input | プロンプト、入力画像 | 5-3 |
|
||||
| Model | Checkpoint・VAE・LoRAなどのモデル | 5-3 |
|
||||
| Settings | シード・ステップ数・サンプラー・画像サイズなど | 5-4 |
|
||||
| Feeder | フォルダの画像を順番に処理する | 5-6 |
|
||||
| Batch | 条件を変えながらまとめて生成する | 5-5 |
|
||||
| Lab | 実験的なI2Iバッチ生成(上級) | 5-7 |
|
||||
|
||||
まずは **Input・Model・Settings** の3つだけ覚えれば十分です。
|
||||
|
||||
### ④ Raw JSON
|
||||
Input・Model・Settingsの右側には、ワークフローの中身がJSON形式で表示されます。
|
||||
フォームで値を変えると、ここにも反映されます。
|
||||
慣れないうちは、ここは「見るだけ」にしておきましょう。
|
||||
|
||||
Inputサブタブでは、Raw JSONの上端にある **»** ボタンで、Raw JSONを右端の細い帯に折りたためます(v0.8.12〜)。
|
||||
プロンプトや画像の欄が広くなります。もう一度押すと元に戻り、折りたたんだ状態は次回も記憶されます。
|
||||
|
||||
---
|
||||
|
||||
## 5-3 はじめての1枚を生成する
|
||||
|
||||
いよいよ生成です。最低限、次の3つを確認・設定します。
|
||||
|
||||
1. どのモデルで描くか(Model)
|
||||
2. 何を描くか(Input)
|
||||
3. 生成する(Generate)
|
||||
|
||||
### 手順1:モデルを選ぶ(Model)
|
||||
1. サブタブの **Model** を開きます。
|
||||
2. **Checkpoint** の欄で、手元にあるモデルを選びます。
|
||||
一覧が長い場合は、欄の上の入力欄に文字を入れると絞り込めます。
|
||||
3. 欄の下にある **Apply** ボタンを押します。
|
||||
|
||||
> **ポイント:モデルが見つからないとき**
|
||||
> ワークフローに保存されているモデルが、あなたのパソコンに入っていないことがあります。
|
||||
> 配布されているワークフローを使うときは、ほぼ必ず起こります。次のどちらかの形で知らせてくれます。
|
||||
> - 欄に「△ (モデル名)(見つかりません)」と表示される
|
||||
> - 読み込んだときに「このワークフローのCheckpoint「…」が見つからず、無警告で別のモデルに差し替えられました」と表示される
|
||||
> (この場合、手元のモデルの一覧の先頭のものに自動で差し替わっています)
|
||||
>
|
||||
> なお v0.8.7〜は、フォルダ名が違うだけで同じファイル名のモデルが手元に1つだけあれば、先頭のものではなく、そのモデルに自動で差し替わります。
|
||||
> (公式テンプレートはフォルダ名なしでモデル名を保存していることが多く、以前は無関係なモデルに差し替わることがありました)
|
||||
>
|
||||
> どちらの場合も、一覧から使いたいモデルを選び直して、Apply を押してください。
|
||||
> 毎回選び直すのが面倒なときは、設定タブの **デフォルトCheckpoint**(第11章)が便利です。
|
||||
|
||||
> **注意:Applyを押し忘れない**
|
||||
> 生成UIでは、モデルやSettings(5-4)の値を変えたあと **Apply** ボタンを押して、はじめてワークフローに反映されます。
|
||||
> Applyを押さずにGenerateすると、**変更前の値のまま** 生成されてしまいます。
|
||||
> 「設定を変えたのに結果が変わらない」ときは、まずApplyの押し忘れを疑いましょう。
|
||||
> (プロンプトの入力欄だけは、Generateを押したときに自動で反映されます)
|
||||
|
||||
> **ポイント**
|
||||
> 項目名が明るい緑色で表示されているのは、読み込んだワークフローにそのモデルのノードが含まれている項目です。
|
||||
> 緑色でない項目は、変更してもこのワークフローには影響しません。
|
||||
|
||||
### 手順2:プロンプトを書く(Input)
|
||||
1. サブタブの **Input** を開きます。
|
||||
左側にプロンプト(Prompt)の欄、右側に入力画像(Image)の欄が並んでいます(v0.8.12〜。それまではPrompt/Imageを切り替える形でした)。
|
||||
画面の幅が狭いときは、Imageの欄はプロンプトの下に回ります。
|
||||
2. **Positive Prompt** の欄に、描いてほしい内容を英語で入力します。
|
||||
|
||||
```
|
||||
a cute cat sitting on a windowsill, sunlight, soft colors, high quality
|
||||
```
|
||||
|
||||
3. **Positive Prompt** の **Apply** を押します。
|
||||
4. 必要に応じて **Negative Prompt** の欄に、描いてほしくない内容を入力し、こちらも **Apply** を押します。
|
||||
|
||||
> プロンプトは、Applyを押し忘れてもGenerateを押したときに自動で反映されます。
|
||||
> ただし、Raw JSON(右側)で反映結果を確かめられるので、Applyを押す習慣をつけておくと安心です。
|
||||
|
||||
```
|
||||
low quality, blurry, bad anatomy
|
||||
```
|
||||
|
||||
> **ポイント**
|
||||
> Apply の横にある **↺(戻す)** ボタンを押すと、入力欄の内容を、いまワークフローに反映されている値に戻せます。
|
||||
> 書き換えに失敗したときに便利です。
|
||||
|
||||
> **ポイント**
|
||||
> 英語が苦手な方は、第7章・第10章で紹介するAI翻訳機能を使うと、日本語で考えたプロンプトを英語にできます。
|
||||
|
||||
### 手順3:生成する(Generate)
|
||||
1. 画面の生成パネルにある **Generate** ボタンを押します。
|
||||
2. 進み具合を表すバーが伸びていき、パーセントが表示されます。
|
||||
3. 「Done」と表示されると、生成された画像が生成パネルに表示されます。
|
||||
|
||||
おめでとうございます。これで、Workflow Studioではじめての1枚が完成しました。
|
||||
|
||||
生成した画像は、ComfyUIで生成した場合と同じく、ComfyUIの `output` フォルダに保存されます。
|
||||
あとから見返したいときは、**ギャラリー** タブ(第8章)で一覧できます。
|
||||
|
||||
> **ポイント:途中で止めたいとき**
|
||||
> 生成中は、Generateボタンの横に **Stop** ボタンが表示されます。押すと生成を中断します。
|
||||
|
||||
> **ポイント:ApplyとGenerateを一度に**
|
||||
> **Alt キーを押しながら Apply** をクリックすると、値の反映と生成を一度に行えます。
|
||||
> 慣れてきたら、プロンプトを書き換えて Alt+Apply、という流れで手早く試せます。
|
||||
|
||||
### 生成したワークフローを保存する
|
||||
生成UIで変えた設定を、あとでまた使いたいときは、サブタブの右端にある **Save** ボタンを押します。
|
||||
名前を付けて保存すると、ワークフロータブに新しいワークフローとして追加されます。
|
||||
|
||||
---
|
||||
|
||||
## 5-4 シード・サンプラー・ステップ数の意味
|
||||
|
||||
1枚目が生成できたら、次は **Settings** サブタブで、画像の仕上がりを左右する設定を見てみましょう。
|
||||
|
||||
Settingsタブは、3つの列に分かれています。
|
||||
|
||||
- **KSampler(左)** - 画像をどのように描くかの設定
|
||||
- **Latent Image(中央)** - 画像の大きさと枚数の設定
|
||||
- **スイッチ(右、v0.9.6〜)** - ワークフローの中のオン・オフの切り替え
|
||||
|
||||
ここでも、KSamplerとLatent Imageは、値を変えたら各ブロックの **Apply** を押すのを忘れないようにしましょう(スイッチの列はApply不要です)。
|
||||
|
||||
### KSampler の項目
|
||||
| 項目 | 意味 | 初心者向けの目安 |
|
||||
| --- | --- | --- |
|
||||
| Seed(シード) | 画像のもとになる「乱数の種」。同じ設定・同じシードなら、ほぼ同じ画像になる | 生成時は生成パネルのシード設定(下記)が優先されるので、ここは「読み込んだワークフローのシードの確認用」と考える。ワークフローのシードをそのまま使いたいときは、生成パネルのモードを **Workflow** にする |
|
||||
| Steps(ステップ数) | 描き込みを何回くり返すか。多いほど丁寧だが時間がかかる | 20〜30 |
|
||||
| CFG | プロンプトにどれだけ忠実に従うか。高すぎると色や形が崩れやすい | SDXLなら5〜8程度 |
|
||||
| Sampler(サンプラー) | 描き方のアルゴリズム | `euler`、`dpmpp_2m` など |
|
||||
| Scheduler(スケジューラー) | ステップごとの描き込み量の配分 | `normal`、`karras` など |
|
||||
| Denoise | 元の画像をどれだけ描き変えるか。文章から作る場合は 1.0 | 1.0(画像から作る場合は 0.4〜0.7 など) |
|
||||
|
||||
> **ポイント**
|
||||
> 目安の値はモデルによって異なります。モデルの配布ページ(Civitaiなど)に推奨値が書かれていることが多いので、確認してみましょう。
|
||||
> 迷ったら、サンプルワークフローに最初から入っている値のまま使えば大丈夫です。
|
||||
|
||||
### Latent Image の項目
|
||||
| 項目 | 意味 | 目安 |
|
||||
| --- | --- | --- |
|
||||
| Width(幅) | 画像の横の大きさ(ピクセル) | SDXLなら1024前後、SD1.5なら512前後 |
|
||||
| Height(高さ) | 画像の縦の大きさ(ピクセル) | 同上 |
|
||||
| Batch Size | 1回の生成で何枚作るか | 1〜4(多いほどメモリを使う) |
|
||||
|
||||
> **注意**
|
||||
> モデルが学習したサイズから大きく外れると、人物が二重になったり、構図が崩れたりしやすくなります。
|
||||
> 縦長・横長にしたいときも、合計のピクセル数がおおよそ同じになるように調整しましょう(例:SDXLなら 832×1216 など)。
|
||||
|
||||
### スイッチの項目(v0.9.6〜)
|
||||
ワークフローの中にある「オン・オフ」の設定が、ノード名と項目名つきで一覧になります。
|
||||
チェックボックスをクリックすると、その場で切り替わります。**Apply を押す必要はありません**。切り替えた値は右側の Raw JSON にもすぐ反映されます。
|
||||
|
||||
一覧に出るのは、次の2種類です。
|
||||
|
||||
- 値が true/false の項目 - プロンプト強化(PE)のオン・オフを切り替えるスイッチや「Boolean」ノード、TextGenerate の thinking など
|
||||
- 選択肢が2つだけのオン・オフの項目 - enable/disable、on/off、yes/no など。KSamplerAdvanced の add_noise、DWPreprocessor の detect_hand(手を検出するか)など
|
||||
|
||||
各行の右端には、いまの値(true/false、enable/disable など)が表示されます。
|
||||
行にマウスを乗せると、ノードの番号と種類を確認できます。
|
||||
|
||||
> **ポイント**
|
||||
> 別のノードから線でつながっている項目は、一覧に出ません。代わりに、つながっている元のノード(たとえば「Enable PE?」という名前の Boolean ノード)が出るので、そちらを切り替えてください。
|
||||
> ノードに名前を付けていないワークフローでは、ノードの種類名(ComfySwitchNode など)で表示されます。
|
||||
> オン・オフの項目が1つも無いワークフローでは「このワークフローに true/false の項目はありません」と表示されます。
|
||||
|
||||
### シードの管理(生成パネル)
|
||||
シードは、生成パネルの **Seed** 欄と、その下のプルダウンで管理します。
|
||||
|
||||
| モード | 動き | 使いどころ |
|
||||
| --- | --- | --- |
|
||||
| Random | 毎回ランダムなシードで生成 | いろいろな絵を試したいとき |
|
||||
| Fixed | Seed欄の値で固定 | 気に入った絵をもとに、プロンプトだけ変えて比べたいとき |
|
||||
| Increment | 生成するたびに1ずつ増やす | 少しずつ違う絵を順番に作りたいとき |
|
||||
| Decrement | 生成するたびに1ずつ減らす | Incrementの逆 |
|
||||
| Workflow | ワークフローに入っているシードを、上書きせずそのまま使う | ギャラリーから読み込んだ画像や、配布されたワークフローを、元のシードで再現したいとき |
|
||||
|
||||
生成が終わると、Seed欄には **実際に使われたシード値** が表示されます。
|
||||
|
||||
> **ポイント:Workflowモード(v0.8.3〜)**
|
||||
> モードを **Workflow** にすると、Seed欄の値やランダムではなく、読み込んだワークフロー自身のシードで生成します。
|
||||
> Randomで何枚か試したあとでも、ワークフロー本来のシード(読み込んだ時点の値)に戻って生成されます。
|
||||
> ワークフローにシードの入力が見つからない場合は、Seed欄の値(−1ならランダム)が使われます。
|
||||
> 同じシードと同じ設定で続けて2回押すと、ComfyUIは計算済みの結果を再利用するため、新しい画像は増えません(故障ではありません)。
|
||||
|
||||
### 気に入った絵を「育てる」流れ
|
||||
シードを使うと、気に入った1枚をもとに少しずつ改良できます。
|
||||
|
||||
1. **Random** で何枚か生成し、気に入った構図の絵を探す
|
||||
2. 気に入った絵が出たら、モードを **Fixed** に切り替える(Seed欄にはその絵のシードが入っています)
|
||||
3. プロンプトに言葉を足したり、Stepsを変えたりして、違いを比べる
|
||||
|
||||
シードを固定すると、「何を変えたら、どう変わったか」が分かりやすくなります。
|
||||
これは、画像生成に慣れるためのいちばんの近道です。
|
||||
|
||||
> **この章(前半)のまとめ**
|
||||
> - ワークフロータブで選んで「生成UIに読み込み」を押すと、生成UIで編集できる
|
||||
> - 基本は Input(プロンプト)・Model(モデル)・Settings(細かい設定)の3つのサブタブ
|
||||
> - モデルやSettingsの値を変えたら必ず **Apply**。押し忘れると変更前の値で生成される(プロンプトとSettingsのスイッチ列は自動で反映)
|
||||
> - Generate で生成。Alt+Apply なら反映と生成を一度に行える
|
||||
> - シードを Fixed にすると、気に入った絵をもとに条件を変えて比べられる。ワークフローのシードをそのまま使うなら Workflow
|
||||
@@ -0,0 +1,243 @@
|
||||
## 5-5 バッチ生成 - 条件を変えながらまとめて試す
|
||||
|
||||
画像生成に慣れてくると、こんなことを試したくなります。
|
||||
|
||||
- 同じプロンプトで、手持ちのモデルを全部試して比べたい
|
||||
- いくつかのプロンプトを、順番に生成したい
|
||||
- どのサンプラーがこのモデルに合うのか、まとめて確かめたい
|
||||
|
||||
1枚ずつ設定を変えてGenerateを押すのは大変です。
|
||||
**Batch** サブタブを使うと、「何を変えながら生成するか」をまとめて指定し、自動で順番に生成できます。
|
||||
|
||||
### バッチで変えられるもの
|
||||
バッチでは、次の7種類のうち **1種類** を選んで、順番に変えながら生成します。
|
||||
|
||||
| 種類 | 何が変わるか | 使いどころ |
|
||||
| --- | --- | --- |
|
||||
| Checkpoint | モデル | モデルの描き味を比べる |
|
||||
| Lora | LoRA | LoRAの効果を比べる |
|
||||
| Prompt | プロンプト | 保存したプロンプトを順番に試す |
|
||||
| Workflow | ワークフロー | 複数のワークフローを順番に実行する |
|
||||
| Sampler | サンプラー | サンプラーの違いを比べる |
|
||||
| Scheduler | スケジューラー | スケジューラーの違いを比べる |
|
||||
| Style | スタイル | スタイルの違いを比べる |
|
||||
|
||||
> **ポイント**
|
||||
> 一度に変えられるのは1種類だけです。
|
||||
> 「モデルもプロンプトも同時に変えたい」という場合は、5-7の Lab を使います。
|
||||
|
||||
### Batchタブの画面
|
||||
Batchタブは、左・中央・右の3つの部分に分かれています。
|
||||
|
||||
| 場所 | 役割 |
|
||||
| --- | --- |
|
||||
| 左(リスト) | Checkpoints/Sampler/Scheduler/Style を一覧から選ぶ |
|
||||
| 中央(グループ) | Checkpoint/Lora/Prompt/Workflow を「グループ」単位で選ぶ |
|
||||
| 右(Batch Queue) | 選んだ項目の一覧。実行する種類をここで決める |
|
||||
|
||||
中央のグループは、それぞれのタブで作ったグループと連動しています。
|
||||
|
||||
- Checkpoint・Lora のグループ → モデルタブ(第6章)
|
||||
- Prompt のグループ → プロンプトタブ(第7章)
|
||||
- Workflow のグループ → ワークフロータブ(第4章)
|
||||
|
||||
### 例:手持ちのモデルを比べる
|
||||
同じプロンプト・同じシードで、3つのモデルの描き味を比べてみましょう。
|
||||
|
||||
1. 5-3の手順で、比べたいプロンプトを入れたワークフローを読み込んでおきます。
|
||||
2. 生成パネルのシードのモードを **Fixed** にします。
|
||||
(シードを固定すると、モデル以外の条件がそろい、違いが分かりやすくなります)
|
||||
3. **Batch** サブタブを開きます。
|
||||
4. 左側の **Checkpoints** タブで、比べたいモデルにチェックを入れます。
|
||||
5. 右側の **Batch Queue** で、**Checkpoint** の列の見出しにあるチェックボックスをオンにします。
|
||||
列には、選んだモデルの一覧と件数が表示されます。
|
||||
|
||||
6. **Generate** を押します。
|
||||
|
||||
選んだモデルで順番に生成が行われます。
|
||||
生成パネルの **Batch** 欄に、いま何番目を生成しているか、全体の進み具合が表示されます。
|
||||
|
||||
- **Pause** - 一時停止します。もう一度押すと再開します。
|
||||
- **Stop** - バッチ全体を中止します。
|
||||
|
||||
> **注意**
|
||||
> Batch Queueの列のチェックがオンのままだと、次にGenerateを押したときもバッチ生成になります。
|
||||
> 1枚だけ生成したいときは、列のチェックをオフにしてください。
|
||||
|
||||
> **ポイント:LoRAのバッチ**
|
||||
> Loraのバッチでは、選んだLoRAの書式(`<lora:名前:強さ>`)と、Civitaiから取得したトリガーワードが、
|
||||
> 自動でPositive Promptに追加されます。バッチが終わると、元のプロンプトに戻ります。
|
||||
|
||||
---
|
||||
|
||||
## 5-6 Feeder - フォルダの画像を順番に処理する
|
||||
|
||||
**Feeder** は、たくさんの画像を1枚ずつワークフローに送り込んで、順番に処理する機能です。
|
||||
たとえば、次のような使い方ができます。
|
||||
|
||||
- 撮りためた写真を、まとめてイラスト風に変換する(I2I:画像から画像を作る)
|
||||
- 複数の画像からポーズを読み取って、同じポーズのキャラクターを描く
|
||||
|
||||
Feederには2つのモードがあり、Feederタブ左上の **[Image Loop]/[Gallery]** ボタンで切り替えます。
|
||||
|
||||
| モード | 画像の取り出し元 | 必要なもの |
|
||||
| --- | --- | --- |
|
||||
| Image Loop | パソコン内のフォルダ | カスタムノード **comfyui-image-feeder**(別途インストール) |
|
||||
| Gallery | ギャラリータブのグループ | 追加インストール不要(Workflow Studioに付属の **Gallery Feeder (WFS)** ノード) |
|
||||
|
||||
> **ポイント**
|
||||
> どちらのモードも、**ワークフローの中に専用のノード** が入っている必要があります。
|
||||
> 普通のワークフローを読み込んだだけでは使えません。
|
||||
|
||||
### Galleryモードの使い方(追加インストール不要)
|
||||
1. ComfyUIのノード画面で、ワークフローの「画像を読み込む」部分に **Gallery Feeder (WFS)** ノードを置き、
|
||||
画像の出力をつなぎます。保存して、生成UIに読み込みます。
|
||||
2. **ギャラリー** タブ(第8章)で、処理したい画像をグループにまとめておきます。
|
||||
(Feederタブを初めて開くと、`__Feeder__` というグループが自動で作られます。これを使ってもかまいません)
|
||||
3. 生成UIの **Feeder** サブタブを開き、**[Gallery]** を選びます。
|
||||
4. 対象の **Gallery Feeder Node** と、画像を取り出す **グループ** を選び、**Apply** を押します。
|
||||
5. 中央にグループの画像が並びます。画像をクリックすると、その画像から処理を始められます。
|
||||
6. **After gen**(生成後の動き)を選び、**▶ Run** を押します。
|
||||
|
||||
### After gen(生成後の動き)
|
||||
| モード | 動き |
|
||||
| --- | --- |
|
||||
| Loop | 次の画像へ進み、最後まで行ったら最初に戻って続ける(■ Stopを押すまで止まらない) |
|
||||
| Increment | 次の画像へ進み、最後の画像を処理したら自動で止まる |
|
||||
| Fixed | 同じ画像を使い続ける(シードだけ変えて何枚も作りたいとき) |
|
||||
|
||||
はじめは **Increment** を選ぶと、全部の画像を1回ずつ処理して自動で止まるので安心です。
|
||||
|
||||
### Image Loopモード
|
||||
Image Loopモードでは、パソコン内のフォルダ(`ComfyUI/user/default/image-loop-data/`)の画像を使います。
|
||||
フォルダの画像を選んで、プリセットとして保存しておくこともできます。
|
||||
別途 **comfyui-image-feeder** カスタムノードが必要です。
|
||||
|
||||
付属のサンプル `ws_sdxl_image_feeder_i2i`(I2I)と `ws_dwpose_image_feeder`(ポーズ読み取り)は、このImage Loopモード用です。
|
||||
|
||||
### Galleryモードのサンプル(v0.8.3〜)
|
||||
Galleryモードには、付属のサンプル `ws_sdxl_gallery_feeder_i2i`(SDXLのI2I)が使えます。
|
||||
ノードを自分で置く必要がなく、**Gallery Feeder (WFS)** ノードがあらかじめ入っています(グループ名は `__Feeder__`、並び順は filename_asc)。
|
||||
|
||||
1. ワークフロータブでサンプルを取り込み、**生成UIに読み込み** を押します。
|
||||
2. ギャラリーで、処理したい画像のサムネイル左上の **F** ボタンを押して `__Feeder__` グループに入れます。
|
||||
3. **Feeder** サブタブで **[Gallery]** を選び、Gallery Feeder Node とグループを選んで **Apply**。
|
||||
4. Model サブタブで、手元のCheckpointとVAEを選び直して **Apply**(サンプルのモデル名は作者の環境のものです)。
|
||||
5. **After gen** を **Increment** にして **▶ Run** を押します。
|
||||
|
||||
---
|
||||
|
||||
## 5-7 Lab - 実験的なI2Iバッチ生成(上級)
|
||||
|
||||
**Lab** は、5-5のバッチ生成をさらに発展させた、上級者向けの実験的な機能です。
|
||||
はじめのうちは読み飛ばしてもかまいません。
|
||||
|
||||
### Batchとの違い
|
||||
| | Batch(5-5) | Lab |
|
||||
| --- | --- | --- |
|
||||
| 一度に変えられるもの | 1種類だけ | モデル・プロンプト・KSamplerを **それぞれ別々に** |
|
||||
| 変えるタイミング | 毎回 | 「何回目から変えるか」を自由に指定 |
|
||||
| 生成した画像を次の入力に | できない | できる(連鎖させられる) |
|
||||
|
||||
### キーフレームという考え方
|
||||
Labでは、「何回目の生成から、どの設定に切り替えるか」を **キーフレーム** として指定します。
|
||||
|
||||
例:10回生成する場合
|
||||
|
||||
| 回 | モデル | プロンプト | KSampler |
|
||||
| --- | --- | --- | --- |
|
||||
| 1〜10 | モデルA | - | - |
|
||||
| 1〜4 | - | 「朝の街」 | - |
|
||||
| 5〜10 | - | 「夜の街」 | - |
|
||||
| 1〜7 | - | - | Steps 20 |
|
||||
| 8〜10 | - | - | Steps 40 |
|
||||
|
||||
このように、列ごとに切り替えのタイミングを別々に決められます。
|
||||
次のキーフレームが来るまでは、前の設定が引き継がれます。
|
||||
|
||||
### 基本の流れ
|
||||
1. 生成UIにワークフローを読み込みます。
|
||||
2. **Lab** サブタブを開きます。
|
||||
3. I2I(画像から画像)の場合は、元になる画像をドロップします。
|
||||
文章から作る(T2I)場合は、**T2I workflow (no source image)** にチェックを入れます。
|
||||
4. 生成回数(Batch)を決めます。
|
||||
5. Model・Prompt・KSampler の各列で **+** を押してキーフレームを追加し、
|
||||
キーフレームをダブルクリックして、「何回目から」「どの設定に」するかを入力します。
|
||||
KSampler列のセルには、指定した項目(Step・CFG・Denoise・サンプラー・スケジューラー・Seed)が表示されます。
|
||||
何も指定していないセルは「(ワークフローの設定のまま)」と表示されます。
|
||||
6. **Run** を押します。
|
||||
|
||||
結果は **Results** パネルに一覧表示されます。
|
||||
|
||||
### 便利な機能
|
||||
- **Use generated image for next** - 生成した画像を、次の回の入力画像として使います。
|
||||
少しずつ変化していく連続画像を作れます。
|
||||
- **Plan Save** - 設定(プラン)を保存できます。保存すると、結果をまとめた一覧画像も作られ、
|
||||
その画像をドロップすれば同じプランを読み込み直せます。
|
||||
- **物語からプランを作る**(v0.9.5〜) - AI TOOLのChatで **Storyboard to Lab** スキルを使うと、
|
||||
物語をシーンごとのプロンプトに分けたプランを作り、**Labで開く** ボタンでここに読み込めます(第10章 10-5)。
|
||||
|
||||
---
|
||||
|
||||
## 5-8 パートナーAPI(Nano Banana)を使う
|
||||
|
||||
ComfyUIには、Googleの画像生成モデル **Nano Banana**(Gemini画像ノード)のように、
|
||||
クラウドのサービスに生成を任せる **パートナーAPIノード** があります。
|
||||
v0.8.6〜は、こうしたノードを含むワークフローも生成UIで実行できます。
|
||||
|
||||
> **注意**
|
||||
> パートナーAPIノードは、自分のパソコンのGPUではなくクラウドで動き、**Comfyクレジット(有料)を消費** します。
|
||||
> BatchやLabなどで繰り返し実行すると、回数ぶんのクレジットが続けて消費されます。
|
||||
|
||||
### 準備:Comfy APIキーを設定する
|
||||
1. platform.comfy.org でComfy APIキーを発行します。
|
||||
2. プラグインのフォルダにある `.env` に、`COMFY_API_KEY=発行したキー` という行を追加します。
|
||||
(`.env` がなければ `.env.example` をコピーして作ります)
|
||||
3. ComfyUIを再起動します。`.env` は起動時にしか読み込まれません。
|
||||
|
||||
キーはサーバー側でだけ使われ、ブラウザには送られません。
|
||||
キーを設定していない状態で実行すると、「パートナーAPIノードの認証に失敗しました」という案内が出ます。
|
||||
|
||||
### 使い方
|
||||
1. ワークフロータブで、Nano Bananaのサンプル(`ws_nano_banana_2_1_t2i`)を生成UIに読み込みます。
|
||||
2. **Input** サブタブの左側(Prompt)でプロンプトを編集し、**Apply** を押します。
|
||||
3. 参考画像を使うときは、**Input** サブタブの右側(Image)の画像カードで指定します。
|
||||
4. **Generate** を押します。
|
||||
|
||||
> **ポイント**
|
||||
> ComfyUI本体の画面でログインして実行する方法もあります。その場合は `.env` の設定は要りません。
|
||||
|
||||
---
|
||||
|
||||
## 5-9 対応ワークフローが増えました(v0.8.4〜)
|
||||
|
||||
生成UIで使えるワークフローが、次のように増えています。使い方は、ほかのワークフローと同じです。
|
||||
|
||||
| 対応したもの | 内容 |
|
||||
| --- | --- |
|
||||
| Qwen Image 2.1 Turbo | ComfyUI公式テンプレートの文章から画像(T2I)・画像から画像(I2I)。プロンプトエンハンサー(プロンプトを自動で補う機能)の入力欄にも、編集が反映される |
|
||||
| Flux.3 Klein | 公式テンプレート4種(KleinとKlein SDのT2IとImage Edit) |
|
||||
| MOSS-Image | Base/SFTのT2Iと、枠で位置を指定するバウンディングボックス版 |
|
||||
| Fibo 2.0 Edit(v0.8.14〜) | 画像編集のワークフロー。プロンプト強化(PE)を使う構成でも、プロンプト欄の編集がPEのオン・オフどちらにも反映される。ネガティブの欄にはVGL形式(JSON)の説明文がそのまま入る。幅・高さ(Settings)は0で自動 |
|
||||
| FastH3 OmniRef/Pika-H3-Flex(v0.8.14〜) | MiniMax H3の「参照画像から動画」(Reference to Video)。動画のワークフローとして扱われ、Videoタブ(第11章)でも使える |
|
||||
| ネイティブLoRAスタック | ComfyUI v0.40のLoRAをまとめて読み込むノード(LoadLoraModel/LoadLoraTextEncoder)。Apply・バイパス・Metadata表示に対応 |
|
||||
| P-H3 Image(v0.9.4〜) | 画像編集とT2Iのテンプレート。プロンプトはInputタブに表示され、Metadataタブでも読める。ネガティブの欄は無い。幅・高さはワークフローのつなぎ方に従い、プロンプトを補う機能(プロンプトアップサンプラー)もワークフローの設定どおりに動く |
|
||||
| MiniMax H3 Image(v0.9.6〜) | ComfyUI公式の画像編集とT2Iのテンプレート。P-H3 Imageと同じく、プロンプトはInputタブに表示され、MetadataタブとサイドパネルのIタブでも読める。ネガティブの欄は無い。プロンプト強化(PE)のオン・オフは、Settingsタブのスイッチの列(5-4)で切り替えられる |
|
||||
|
||||
> **注意**
|
||||
> ネイティブLoRAスタックのノードは、保存形式が **API形式のワークフローのみ** 対応です。
|
||||
> ComfyUI本体の画面がこのノードの行追加にまだ対応していないためで、UI形式のワークフローは対象外です。
|
||||
|
||||
> **ポイント**
|
||||
> 2枚の画像をスライダーで見比べる **Compare Images**(ImageCompare)ノードを含むワークフローは、以前は生成UIから実行すると、このノードだけエラーになっていました(v0.9.6で修正)。
|
||||
|
||||
> **ポイント**
|
||||
> 画像のメタデータを見るMetadataタブとサイドパネルの **I** タブでも、Nano Bananaで作った画像を読めます(v0.8.5〜)。
|
||||
> プロンプトは、Positive/Negativeに分けずに全文が1件で表示されます。
|
||||
|
||||
> **この章(後半)のまとめ**
|
||||
> - Batchサブタブで、モデル・プロンプト・サンプラーなどを1種類ずつ変えながらまとめて生成できる
|
||||
> - Batch Queueの列のチェックで種類を選び、Generateで開始。終わったらチェックを外す
|
||||
> - Feederは、たくさんの画像を1枚ずつワークフローに送り込む機能。専用ノードが必要
|
||||
> - Labは、複数の設定を別々のタイミングで切り替えられる上級者向けの機能
|
||||
> - パートナーAPIノード(Nano Bananaなど)は、`.env` の `COMFY_API_KEY` を設定すれば実行できる。クレジットが消費される
|
||||
@@ -0,0 +1,184 @@
|
||||
# 第6章 モデルタブ - モデルとLoRAを管理する
|
||||
|
||||
画像生成を続けていると、モデルやLoRAのファイルはどんどん増えていきます。
|
||||
「このファイル、何のモデルだっけ?」「あのLoRAのトリガーワードは何だった?」
|
||||
- そんな悩みを解決するのが **モデル(Models)** タブです。
|
||||
|
||||
---
|
||||
|
||||
## 6-1 モデルの種類
|
||||
|
||||
モデルタブの上部には、モデルの種類ごとのタブが並んでいます。
|
||||
それぞれ、ComfyUIの `models` フォルダの中の対応するフォルダに入っているファイルが表示されます。
|
||||
|
||||
| 種類 | ひとことで言うと | 主な置き場所 |
|
||||
| --- | --- | --- |
|
||||
| Checkpoint | 画像生成の本体。これがないと始まらない | `models/checkpoints` |
|
||||
| LoRA | 絵柄・キャラクター・服装などを追加で覚えさせる小さなモデル | `models/loras` |
|
||||
| VAE | 画像の色合いや細部を仕上げる。Checkpointに内蔵されていることも多い | `models/vae` |
|
||||
| ControlNet | ポーズや線画など、構図を指定するためのモデル | `models/controlnet` |
|
||||
| UNET | FLUXなど新しい形式のモデルの本体(Diffusion Model) | `models/diffusion_models` など |
|
||||
| TextEncoder | プロンプトの文章をAIが理解できる形に変換するモデル | `models/text_encoders` など |
|
||||
| Hypernetwork | 絵柄を調整する古い形式の追加モデル | `models/hypernetworks` |
|
||||
| Embedding | 特定の単語に意味を覚えさせた小さなファイル(ネガティブ用が多い) | `models/embeddings` |
|
||||
|
||||
> **ポイント**
|
||||
> はじめは **Checkpoint** と **LoRA** の2つを使いこなせれば十分です。
|
||||
> FLUXなどの新しいモデルを使うようになると、UNETやTextEncoderの出番が増えてきます。
|
||||
|
||||
---
|
||||
|
||||
## 6-2 一覧の表示と探し方
|
||||
|
||||
### 最初の読み込み
|
||||
モデルタブを初めて開いたときは、一覧が空で「更新ボタンでモデルを読み込み...」と表示されます。
|
||||
ツールバーの **「更新」** を押すと、モデルの一覧が表示されます。
|
||||
新しくモデルを追加したときも、「更新」を押してください。
|
||||
|
||||
### サムネイル表示とテーブル表示
|
||||
ワークフロータブと同じく、**サムネイル** と **テーブル** を切り替えられます。
|
||||
1ページに24件ずつ表示されます。
|
||||
|
||||
テーブル表示では、列の見出しをクリックすると、その列で並べ替えができます
|
||||
(1回目:昇順 ▲、2回目:降順 ▼、3回目:並べ替え解除)。
|
||||
|
||||
> **ポイント**
|
||||
> サムネイルは、モデルファイルと同じ場所にある `(モデル名).preview.png` が自動で使われます。
|
||||
> 画像がないモデルも、6-3の方法でCivitaiから取得したり、自分で設定したりできます。
|
||||
|
||||
### 検索と絞り込み
|
||||
ツールバーには、絞り込みのための項目が並んでいます。
|
||||
|
||||
| 項目 | 絞り込み内容 |
|
||||
| --- | --- |
|
||||
| モデルを検索... | 名前などのキーワード |
|
||||
| ★ | お気に入りだけ |
|
||||
| すべてのタグ | タグ |
|
||||
| All Folders | サブフォルダ |
|
||||
| All Groups | グループ |
|
||||
| All/Enabled only/Disabled only | 有効・無効の状態(6-5) |
|
||||
|
||||
絞り込みすぎて分からなくなったら、ツールバー右端の **「× クリア」** ですべて解除できます。
|
||||
|
||||
### お気に入り・バッジ・グループ
|
||||
分類のしかたは、ワークフロータブ(第4章 4-4)とほぼ同じです。
|
||||
|
||||
- **お気に入り(★)** - よく使うモデルに印を付ける
|
||||
- **バッジ** - **「Badge」** で作った色付きラベルを付ける。バッジの種類と色はワークフロータブと共通です
|
||||
- **グループ** - モデルをクリックし、サイドパネルの **「グループ」** タブで追加する
|
||||
|
||||
> **ポイント**
|
||||
> グループは **モデルの種類ごと** に分かれています。
|
||||
> Checkpointのグループは、Checkpointタブにだけ表示されます。
|
||||
> ここで作ったグループは、生成UIのバッチ生成(第5章 5-5)でも使えます。
|
||||
|
||||
---
|
||||
|
||||
## 6-3 Civitaiの情報を取り込む
|
||||
|
||||
**Civitai(シビタイ)** は、画像生成モデルが多数公開されている共有サイトです。
|
||||
ネットから入手したモデルの多くは、Civitaiで配布されています。
|
||||
|
||||
Workflow Studioは、手元のモデルファイルから **ハッシュ値**(ファイルの指紋のような値)を計算し、
|
||||
Civitaiに登録されている情報を自動で探し出せます。
|
||||
|
||||
### 取得できる情報
|
||||
- モデルの名前・種類(Checkpoint/LoRAなど)
|
||||
- **Base Model**(SDXL、SD1.5、FLUX など、どの系統のモデルか)
|
||||
- **トリガーワード**(LoRAの効果を出すために、プロンプトに入れる言葉)
|
||||
- タグ・説明文
|
||||
- サンプル画像(サムネイルにも使われます)
|
||||
|
||||
### 1つずつ取得する
|
||||
1. モデルをクリックして選択します。
|
||||
2. 右側のサイドパネルで **「CivitAI」** タブを開きます(モデルを選ぶと最初にこのタブが開きます)。
|
||||
3. **「CivitAIから取得」** を押します。
|
||||
|
||||
取得が終わると、モデルの情報が表示されます。
|
||||
**Sample** タブでは、Civitaiに投稿されたサンプル画像を見られます。
|
||||
|
||||
### まとめて取得する
|
||||
ツールバーの **「CivitAI」** ボタンを押すと、表示中の種類のモデルについて、まとめて情報を取得します。
|
||||
すでに情報を取得済みのモデルは飛ばされるので、モデルを追加したあとに何度押しても大丈夫です。
|
||||
サムネイル画像がないモデルには、プレビュー画像も自動で保存されます。
|
||||
|
||||
> **ポイント**
|
||||
> ハッシュ値の計算には、モデルの大きさに応じて時間がかかります。
|
||||
> 数GBのモデルがたくさんある場合は、時間に余裕があるときに実行しましょう。
|
||||
|
||||
> **ポイント**
|
||||
> Civitaiで見つからなかったモデルは「確認済みですが、このモデルはCivitAIに見つかりませんでした。」と表示されます。
|
||||
> 自分で作ったモデルや、Civitai以外で配布されているモデルは、見つからないのが普通です。
|
||||
> **「未登録はスキップ」** にチェックを入れておくと、まとめて取得するときに、見つからなかったモデルを再確認せずに飛ばします。
|
||||
|
||||
> **ポイント:APIキー**
|
||||
> 設定タブの **「CivitAI APIキー」** は、入力しなくても使えます(省略可)。
|
||||
> 一部の情報の取得に認証が必要な場合に、Civitaiのアカウント設定で発行したキーを入力します。
|
||||
|
||||
### LoRAを使うときに特に便利
|
||||
LoRAは、**トリガーワード** をプロンプトに入れないと効果が出ないものが多くあります。
|
||||
Civitaiの情報を取得しておけば、サイドパネルでトリガーワードをすぐに確認できます。
|
||||
また、生成UIのバッチ生成でLoRAを使うと、トリガーワードが自動でプロンプトに追加されます(第5章 5-5)。
|
||||
|
||||
---
|
||||
|
||||
## 6-4 モデルを生成やキャンバスで使う
|
||||
|
||||
### 生成UIにセットする(GenUI Model)
|
||||
モデルタブで選んだモデルを、そのまま生成UIのワークフローにセットできます。
|
||||
|
||||
1. 生成UIに、ワークフローを読み込んでおきます(第5章 5-1)。
|
||||
2. モデルタブで、使いたいモデルを選択します。
|
||||
3. **「GenUI Model」** ボタンを押します。
|
||||
|
||||
これで、生成UIのワークフローのモデルが、選んだモデルに差し替わります。
|
||||
Civitaiのサンプル画像を見比べながら、気になったモデルをすぐ試せます。
|
||||
|
||||
> **ポイント**
|
||||
> Embeddingの場合は、**GenUI PP**(ポジティブプロンプトに追加)と **GenUI NP**(ネガティブプロンプトに追加)のボタンが表示されます。
|
||||
> ネガティブ用のEmbeddingは、GenUI NP で追加しましょう。
|
||||
|
||||
> **注意**
|
||||
> 生成UIのワークフローに、そのモデルを読み込むノードがない場合は使えません。
|
||||
> たとえば、LoRAのノードがないワークフローに、LoRAはセットできません。
|
||||
|
||||
### ComfyUIのノード画面で使う
|
||||
ComfyUIのノード画面の横にある **WS Library** の **M(Models)** タブからモデルをキャンバスへドラッグすると、
|
||||
そのモデルを読み込むノードが自動で置かれます(第9章)。
|
||||
|
||||
---
|
||||
|
||||
## 6-5 使わないモデルを片付ける
|
||||
|
||||
### 有効・無効の切り替え
|
||||
しばらく使わないモデルは、削除せずに **無効(Disable)** にしておけます。
|
||||
無効にしたモデルは、ComfyUIのモデル選択の一覧に表示されなくなるので、一覧がすっきりします。
|
||||
|
||||
- カードの **一時停止(⏸)** ボタンで、1つずつ有効・無効を切り替えられます。
|
||||
- グループ単位で、まとめて有効・無効にすることもできます。
|
||||
|
||||
> **ポイント**
|
||||
> 無効にすると、ファイルの名前の末尾に `.disabled` が付きます。ファイル自体は消えません。
|
||||
> 有効に戻すと、元の名前に戻ります。
|
||||
|
||||
### まとめて操作する(Select)
|
||||
緑色の **Select** ボタンを押すと、複数のモデルにチェックを入れて、まとめて操作できます。
|
||||
|
||||
- グループへの追加・削除
|
||||
- バッジの追加・削除
|
||||
- 別のサブフォルダへの移動(プレビュー画像などの関連ファイルも一緒に移動)
|
||||
- 削除
|
||||
|
||||
### 削除
|
||||
詳細画面やSelectから、モデルを削除できます。
|
||||
|
||||
> **注意**
|
||||
> 削除すると、モデルファイルと、関連するファイル(プレビュー画像、Civitai情報など)が **完全に削除** されます。
|
||||
> モデルは再ダウンロードに時間がかかるものが多いので、迷ったら削除ではなく「無効」にしておきましょう。
|
||||
|
||||
> **この章のまとめ**
|
||||
> - モデルタブでは、ComfyUIのモデルを種類ごとに一覧できる。最初に「更新」を押す
|
||||
> - お気に入り・バッジ・グループで分類できる。グループはバッチ生成でも使える
|
||||
> - 「CivitAIから取得」で、Base Model・トリガーワード・サンプル画像などを自動で取り込める
|
||||
> - 「GenUI Model」で、選んだモデルをすぐ生成UIで試せる
|
||||
> - 使わないモデルは削除せず「無効」にしておくと安心
|
||||
@@ -0,0 +1,254 @@
|
||||
# 第7章 プロンプトタブ - 呪文を貯めて、育てる
|
||||
|
||||
うまくいったプロンプトは、あなただけの財産です。
|
||||
でも、メモ帳に貼り付けておくだけでは、どれが何の呪文だったか分からなくなりがちです。
|
||||
|
||||
**プロンプト(Prompt)** タブは、プロンプトを **保存・分類・再利用** するための場所です。
|
||||
さらに、ローカルAIを使った翻訳や、プロンプトを毎回少しずつ変える「ワイルドカード」も使えます。
|
||||
|
||||
---
|
||||
|
||||
## 7-1 プロンプトの基本
|
||||
|
||||
プロンプトタブの使い方に入る前に、プロンプトの書き方の基本を押さえておきましょう。
|
||||
|
||||
### ポジティブとネガティブ
|
||||
| 種類 | 書く内容 | 例 |
|
||||
| --- | --- | --- |
|
||||
| Positive Prompt(ポジティブ) | 描いてほしいもの | `1girl, smiling, school uniform, cherry blossoms, spring` |
|
||||
| Negative Prompt(ネガティブ) | 描いてほしくないもの | `low quality, blurry, extra fingers, watermark` |
|
||||
|
||||
### 書き方のコツ
|
||||
- **英語で書く** - 多くのモデルは英語で学習されています。
|
||||
- **カンマ(,)で区切る** - 単語や短いフレーズを、カンマで区切って並べるのが一般的です。
|
||||
- **大事なものを前に** - 前に書いた言葉ほど、強く反映されやすい傾向があります。
|
||||
- **強調したい言葉は (言葉:数値)** - `(red hair:1.3)` のように書くと、その言葉を強調できます(1.0が標準)。
|
||||
|
||||
> **ポイント:強調の数値をキーボードで変える**
|
||||
> 生成UIのプロンプト入力欄で、強調したい言葉を選んで **Ctrl+↑/↓** を押すと、
|
||||
> `(言葉:数値)` の数値を0.05ずつ増減できます。数値が1.0に戻ると、カッコは自動で外れます。
|
||||
|
||||
> **ポイント**
|
||||
> SDXLのアニメ系モデルは「タグを並べる」書き方、FLUXなどの新しいモデルは「普通の英文で説明する」書き方が向いています。
|
||||
> モデルの配布ページに、おすすめの書き方が載っていることも多いので確認してみましょう。
|
||||
|
||||
---
|
||||
|
||||
## 7-2 プロンプトタブの画面
|
||||
|
||||
プロンプトタブは、左・中央・右の3つの列に分かれています。
|
||||
|
||||
| 列 | 名前 | 役割 |
|
||||
| --- | --- | --- |
|
||||
| 左 | AI Assistant | ローカルAIとのチャット・翻訳(7-5) |
|
||||
| 中央 | Presets/Preset Manager | プロンプトの保存・一覧・分類(7-3) |
|
||||
| 右 | Wildcard/Style | ワイルドカードとスタイルの管理(7-4) |
|
||||
|
||||
画面上部の **Form/Table** で、表示方法を切り替えられます。
|
||||
|
||||
- **Form** - 1件ずつ編集する画面(この章で説明する画面です)
|
||||
- **Table** - プリセットやワイルドカードを表形式でまとめて編集する画面(件数が増えてきたら便利)
|
||||
|
||||
---
|
||||
|
||||
## 7-3 プリセットとして保存・分類する
|
||||
|
||||
**プリセット** は、ポジティブ・ネガティブのプロンプトをひと組にして、名前を付けて保存したものです。
|
||||
|
||||
### プリセットを保存する
|
||||
1. 中央の列で **Presets** タブを開きます。
|
||||
2. 一番上のプルダウンが **New Preset (none selected)** になっていることを確認します。
|
||||
3. 次の項目を入力します。
|
||||
|
||||
| 項目 | 内容 |
|
||||
| --- | --- |
|
||||
| Preset Name | プリセットの名前(例:`桜と制服`) |
|
||||
| Category | 分類(例:`Portrait`、`Landscape`)。省略してもかまいません |
|
||||
| Positive Prompt | 描いてほしいもの |
|
||||
| Negative Prompt | 描いてほしくないもの |
|
||||
|
||||
4. **Save** を押します。「プリセットを保存しました」と表示されれば完了です。
|
||||
|
||||
> **ポイント**
|
||||
> 生成UIで試して「これは良い!」と思ったプロンプトを、その場でプリセットに保存する習慣をつけましょう。
|
||||
> あとから同じ雰囲気の画像を作りたいときに、すぐに呼び出せます。
|
||||
|
||||
### プリセットを呼び出して使う
|
||||
1. 一番上のプルダウンから、使いたいプリセットを選びます。
|
||||
2. 使い方に応じてボタンを押します。
|
||||
|
||||
| ボタン | 動き |
|
||||
| --- | --- |
|
||||
| GenUI Set | 生成UIのプロンプト欄に、ポジティブとネガティブをまとめてセットする |
|
||||
| PP Copy | ポジティブプロンプトをコピーする |
|
||||
| NP Copy | ネガティブプロンプトをコピーする |
|
||||
|
||||
> **注意**
|
||||
> **GenUI Set** は、生成UIにワークフローが読み込まれているときに使えます。
|
||||
> 先に第5章の手順でワークフローを読み込んでおきましょう。
|
||||
|
||||
### グループで分類する
|
||||
プリセットも、グループで分類できます。
|
||||
|
||||
1. プリセットを選んだ状態で、**+ Group** を押して新しいグループを作ります。
|
||||
2. **Select group...** からグループを選び、**Add to Group** を押します。
|
||||
|
||||
グループは削除することもできます(**Del Group**)。
|
||||
|
||||
ここで作ったグループは、生成UIのバッチ生成(第5章 5-5)で「Prompt」のグループとして使えます。
|
||||
たとえば「季節シリーズ」というグループに春・夏・秋・冬のプリセットを入れておけば、
|
||||
4つの季節の絵をまとめて生成できます。
|
||||
|
||||
### Preset Manager で一覧する
|
||||
中央の列の **Preset Manager** タブでは、保存したプリセットを一覧で見られます。
|
||||
|
||||
- **All** - すべてのプリセット
|
||||
- **★** - お気に入りに登録したプリセット
|
||||
- **Groups** - グループごとの表示
|
||||
|
||||
上部の **Search presets...** 欄で、プリセットを検索できます。
|
||||
|
||||
保存したプリセットは、ComfyUIのノード画面の横にある **WS Library** の **P(Prompts)** タブにも表示され、
|
||||
キャンバスへドラッグして使えます(第9章)。
|
||||
|
||||
---
|
||||
|
||||
## 7-4 ワイルドカードとスタイル
|
||||
|
||||
右の列では、プロンプトを自動で変化させる **ワイルドカード** と、
|
||||
プロンプトに雰囲気を足す **スタイル** を管理します。
|
||||
列の上部の **Wildcard/Style** で切り替えます。
|
||||
|
||||
### ワイルドカードとは
|
||||
ワイルドカードは、**生成するたびに、プロンプトの一部をランダムに入れ替える** しくみです。
|
||||
同じプロンプトのまま、バリエーションのある画像をたくさん作れます。
|
||||
|
||||
Workflow Studioでいちばん手軽なのは、**ワイルドカードファイル** を使う方法です。
|
||||
候補を書いたファイルを作っておき、プロンプトに `__ファイル名__` と書くと、
|
||||
生成するたびにファイルの中から1行がランダムに選ばれます。
|
||||
|
||||
### ワイルドカードファイルを作る
|
||||
例として、色の候補を入れた `colors` というファイルを作ってみましょう。
|
||||
|
||||
1. 右の列で **Wildcard** を選び、**Wildcard Files** の **+ New** を押します。
|
||||
2. ファイル名(例:`colors`)を入力し、形式は **txt** を選びます。
|
||||
3. 候補を1行に1つずつ入力します。
|
||||
|
||||
```
|
||||
red
|
||||
blue
|
||||
green
|
||||
golden
|
||||
```
|
||||
|
||||
4. **Save** を押します。
|
||||
|
||||
### ワイルドカードを使う
|
||||
プロンプトに、ファイル名を `__`(アンダースコア2つ)で囲んで書きます。
|
||||
|
||||
```
|
||||
1girl, __colors__ dress, standing in a garden
|
||||
```
|
||||
|
||||
生成UIで生成するたびに、`__colors__` の部分が `red`・`blue`・`green`・`golden` のどれかに置き換わります。
|
||||
|
||||
> **ポイント**
|
||||
> `__colors__` を手で入力する代わりに、右の列の **File** ボタンでファイルを選んで挿入することもできます。
|
||||
|
||||
### もっと高度な書き方(Impact Pack 用)
|
||||
右の列の上部には、`{ }`、`$$`、`[ ]` などの記号を挿入するボタンもあります。
|
||||
これらは、次のような書き方のためのものです。
|
||||
|
||||
| 書き方 | 意味 |
|
||||
| --- | --- |
|
||||
| `{cat|dog|rabbit}` | 3つの中から1つを選ぶ |
|
||||
| `{2$$cat|dog|bird}` | 3つの中から2つを選ぶ |
|
||||
|
||||
※ 本書では見やすさのため `|` と全角で表記しています。実際には半角の `|`(縦棒)を使います。
|
||||
|
||||
> **注意**
|
||||
> 生成UIが自動で展開するのは、`__ファイル名__` の書き方だけです。
|
||||
> `{A|B}` などの書き方を使うには、カスタムノード **ComfyUI-Impact-Pack** のワイルドカード用ノード
|
||||
> (ImpactWildcardProcessor など)をワークフローに入れておく必要があります。
|
||||
> 慣れないうちは、`__ファイル名__` の書き方だけ使えば十分です。
|
||||
|
||||
### 作ったプロンプトを送る
|
||||
右の列で組み立てたプロンプトは、下のボタンで送り出せます。
|
||||
|
||||
- **→ Pos** - プリセットのPositive Promptへ送る
|
||||
- **→ Neg** - プリセットのNegative Promptへ送る
|
||||
- **Copy** - コピーする
|
||||
|
||||
`__ファイル名__` の部分は、生成UIで生成するときに自動で展開されます。
|
||||
|
||||
### スタイル
|
||||
**スタイル** は、プロンプトに付け足す「雰囲気のテンプレート」です。
|
||||
たとえば「映画風」というスタイルには、`cinematic still, {prompt}, dramatic lighting` のような内容が登録されています。
|
||||
`{prompt}` の部分に、あなたのプロンプトが入ります。
|
||||
|
||||
スタイルを使うには、生成UIの上部のバーで、**Style** のチェックボックスをオンにして、プルダウンからスタイルを選びます。
|
||||
生成するときに、選んだスタイルがプロンプトに自動で合成されます(ワークフローそのものは書き換わりません)。
|
||||
|
||||
Workflow Studioにはたくさんのスタイルが付属しています。
|
||||
プロンプトタブの **Style** では、スタイルの一覧を見たり、**+ New** で自分のスタイルを作ったりできます。
|
||||
|
||||
> **ポイント**
|
||||
> どのスタイルがどんな雰囲気になるかは、生成UIの **Create Catalog** で、スタイルごとの見本画像をまとめて作ると分かりやすくなります。
|
||||
> 作った見本は、ギャラリータブの Style_Catalog で一覧できます(第8章)。
|
||||
|
||||
---
|
||||
|
||||
## 7-5 AIで翻訳・プロンプト作りを手伝ってもらう
|
||||
|
||||
左の列の **AI Assistant** では、パソコンで動くAI(ローカルAI)に、プロンプト作りを手伝ってもらえます。
|
||||
|
||||
> **事前に必要なもの**
|
||||
> この機能を使うには、**Ollama** や **LM Studio** などのローカルAIソフトと、AIモデルの準備が必要です。
|
||||
> 準備の方法は第10章で説明します。準備ができていない場合、AI Assistantの上部に **Disconnected** と表示されます。
|
||||
|
||||
### 日本語を英語に翻訳する
|
||||
英語のプロンプトが苦手でも大丈夫です。
|
||||
|
||||
1. 左の列の下にある入力欄に、日本語で描きたい内容を書きます。
|
||||
|
||||
```
|
||||
桜の木の下で微笑む制服姿の少女、春の柔らかい光
|
||||
```
|
||||
|
||||
2. **Translate:** の **JA→EN** ボタンを押します。
|
||||
3. チャット欄に、英語に翻訳された結果が表示されます。
|
||||
|
||||
翻訳結果の下に表示されるボタンで、結果を使えます。
|
||||
|
||||
| ボタン | 動き |
|
||||
| --- | --- |
|
||||
| 生成UIに適用 | 生成UIのポジティブプロンプト欄に入れる |
|
||||
| コピー | コピーする(プリセットに貼り付けるときなど) |
|
||||
|
||||
英語のプロンプトの意味を知りたいときは、反対に **EN→JA** で日本語に訳せます。
|
||||
|
||||
### AIと相談しながらプロンプトを作る
|
||||
入力欄に質問を書いて **Send**(または Enter キー)を押すと、AIとチャットできます。
|
||||
|
||||
- 「夕暮れの海辺の風景のプロンプトを、英語のタグ形式で作って」
|
||||
- 「このプロンプトに、もっと幻想的な雰囲気を足して」
|
||||
|
||||
のように頼むと、プロンプトの案を出してくれます。
|
||||
画像を読み取れるAIモデルを使っている場合は、**Attach Image** で画像を添付して、
|
||||
「この画像の雰囲気をプロンプトにして」と頼むこともできます。
|
||||
|
||||
- **Shift+Enter** - 改行
|
||||
- **Clear Chat** - 会話をリセット
|
||||
- **歯車ボタン** - 使うAIソフトやモデルの設定(第10章)
|
||||
|
||||
> **注意**
|
||||
> ローカルAIの答えは、いつも正しいとは限りません。
|
||||
> 出てきたプロンプトは、実際に生成して確かめながら調整しましょう。
|
||||
|
||||
> **この章のまとめ**
|
||||
> - プロンプトは英語・カンマ区切りが基本。強調は `(言葉:数値)`
|
||||
> - うまくいったプロンプトは、プリセットとして名前を付けて保存する
|
||||
> - 「GenUI Set」で、プリセットをすぐ生成UIにセットできる
|
||||
> - グループに分けると、バッチ生成でまとめて試せる
|
||||
> - ワイルドカードファイルを作って `__ファイル名__` と書くと、生成のたびにプロンプトを変化させられる
|
||||
> - ローカルAIを用意すれば、日本語からの翻訳やプロンプトの相談ができる
|
||||
@@ -0,0 +1,332 @@
|
||||
# 第8章 ギャラリータブ - 生成した画像を見返す
|
||||
|
||||
画像生成を続けていると、ComfyUIの `output` フォルダには何百、何千枚もの画像がたまっていきます。
|
||||
**ギャラリー(Gallery)** タブは、それらの画像を快適に見返し、
|
||||
「この画像、どうやって作ったんだっけ?」を解決するための場所です。
|
||||
|
||||
ComfyUIで生成した画像には、生成に使ったワークフローやプロンプトの情報(**メタデータ**)が埋め込まれています。
|
||||
ギャラリータブでは、この情報を読み取って、同じ設定をすぐに再現できます。
|
||||
また、動画(MP4・WebM)や音声ファイル(WAV・MP3・OGG・M4A・FLAC・Opus)、3Dモデル(GLB・glTF・VRM・PLY・SPZ)も、画像と同じ一覧で扱えます。
|
||||
|
||||
---
|
||||
|
||||
## 8-1 画像を一覧する
|
||||
|
||||
ギャラリータブの上部には、4つのサブタブがあります。
|
||||
|
||||
| サブタブ | 役割 | 本書 |
|
||||
| --- | --- | --- |
|
||||
| Output | 生成した画像の一覧(ふだん使うのはここ) | 8-1〜8-3 |
|
||||
| ImagePrompt | 見本画像を見ながらプロンプトを組み立てる | 8-4 |
|
||||
| Style_Catalog | スタイルの見本画像から選ぶ | 8-4 |
|
||||
| メタデータ | 画像ファイルをドロップして、中の情報を調べる | 8-2 |
|
||||
|
||||
### Outputの画面
|
||||
**Output** サブタブは、左・中央・右の3つの部分に分かれています。
|
||||
|
||||
| 場所 | 役割 |
|
||||
| --- | --- |
|
||||
| 左(フォルダ) | `output` フォルダの中のフォルダ一覧。いちばん上の **[root]** が `output` フォルダ全体 |
|
||||
| 中央(一覧) | 選んだフォルダの画像。下へスクロールすると続きが読み込まれる |
|
||||
| 右(詳細パネル) | 選んだ画像の情報(8-2) |
|
||||
|
||||
まず、左のフォルダ一覧からフォルダを選ぶと、中央に画像が表示されます。
|
||||
|
||||
> **ポイント**
|
||||
> 生成UIやComfyUIで新しく生成した画像が出てこないときは、ツールバーの **Refresh** を押してください。
|
||||
|
||||
> **ポイント**
|
||||
> 読み込む `output` フォルダの場所は、設定タブの **「ギャラリー Outputフォルダ」** で変更できます。
|
||||
|
||||
### 表示の切り替え・検索・並べ替え
|
||||
ほかのタブと同じく、次の操作ができます。
|
||||
|
||||
- **サムネイル/テーブル** - サムネイル表示とテーブル表示の切り替え
|
||||
- **検索欄** - ファイル名・タグ・メモ・**プロンプトの内容** で検索。横の **S** ボタンをオンにすると、文章の意味で探せます(8-6)
|
||||
- **並べ替え** - Date (Newest)/Date (Oldest)/Name A-Z/Name Z-A
|
||||
- **★** - お気に入りだけ表示
|
||||
- **× クリア** - 絞り込みをまとめて解除
|
||||
|
||||
> **ポイント**
|
||||
> 検索欄では、プロンプトの言葉でも探せます。
|
||||
> たとえば「cat」で検索すると、プロンプトに cat を含む画像が見つかります。
|
||||
> (プロンプトの検索は、一度詳細パネルで開いた画像が対象になります)
|
||||
|
||||
### 大きく見る・比べる
|
||||
- 画像をクリックすると、右の詳細パネルに大きく表示されます。
|
||||
- **Ctrl キーを押しながら** 画像をクリックすると、複数の画像を選べます。
|
||||
2〜4枚選んで **比較** を押すと、並べて見比べられます。
|
||||
|
||||
シードやモデルだけを変えて作った画像を並べると、違いがよく分かります。
|
||||
|
||||
### 整理する
|
||||
- **お気に入り(★)・タグ・メモ・グループ** で分類できます(詳細パネルで設定)。
|
||||
- 複数選択して、まとめてグループに追加したり、別のフォルダへ移動したりできます。
|
||||
移動先を選ぶ画面(**移動先...**)には絞り込み欄があり、フォルダ名の一部を入れると候補が絞られ、Enterで先頭の候補へ移動できます。
|
||||
- **エクスポート** を押すと、選んだ画像をZIPファイルにまとめてダウンロードできます。
|
||||
|
||||
> **注意**
|
||||
> 詳細パネルの **Delete** や、複数選択の **ファイル削除** を使うと、画像ファイルそのものが削除されます。
|
||||
|
||||
---
|
||||
|
||||
## 8-2 メタデータから生成設定を読み取る
|
||||
|
||||
画像をクリックすると、右の詳細パネルに4つのタブが表示されます。
|
||||
|
||||
| タブ | 内容 |
|
||||
| --- | --- |
|
||||
| プロンプト | 画像の生成に使われたプロンプト(最初に表示されるタブ) |
|
||||
| 基本情報 | ファイル名・大きさ・日時・タグ・メモ |
|
||||
| メタデータ | 画像に埋め込まれたワークフロー(JSON) |
|
||||
| グループ | グループの設定 |
|
||||
|
||||
### プロンプトを確認する
|
||||
**プロンプト** タブには、画像に埋め込まれていたプロンプトが一覧表示されます。
|
||||
ポジティブには **POS**、ネガティブには **NEG** の印が付きます。
|
||||
項目をクリックすると、全文が表示されます。
|
||||
|
||||
### もっと詳しく調べる(メタデータサブタブ)
|
||||
使ったモデルやLoRAまで詳しく知りたいときは、詳細パネルの **Metadata** ボタンを押します
|
||||
(または、Alt キーを押しながら画像をクリック)。
|
||||
ギャラリーの **メタデータ** サブタブが開き、次の情報が整理されて表示されます。
|
||||
|
||||
- **モデル** - Checkpoint、VAE、Diffusion Model、Text Encoder(中央の列)
|
||||
- **LoRA** - 使われたLoRAと、その強さ(中央の列)
|
||||
- **プロンプト** - ポジティブ・ネガティブ(中央の列)
|
||||
- **Settings** - 画像サイズ(幅×高さ)と、KSamplerの Seed・Steps・CFG・Sampler・Scheduler・Denoise(右の列。v0.7.14〜)
|
||||
- **Nanobanana** - Comic Creatorのnanobananaタブで作った画像の、エンジン・モデル・プロンプトなどの生成履歴(右の列。該当する画像のみ)
|
||||
|
||||
プロンプトの横のボタンで、内容をほかのタブに送れます。
|
||||
|
||||
| ボタン | 動き |
|
||||
| --- | --- |
|
||||
| Copy | コピー |
|
||||
| GenUI:P/GenUI:N | 生成UIのポジティブ/ネガティブに入れる |
|
||||
| Prompt:P/Prompt:N | プロンプトタブのプリセットのポジティブ/ネガティブに入れる |
|
||||
|
||||
> **ポイント:ネットで見つけた画像も調べられる**
|
||||
> メタデータサブタブの左側に、画像ファイルを **ドロップ** すると、その画像の情報を調べられます。
|
||||
> ComfyUIの画像だけでなく、SD WebUI(AUTOMATIC1111)、SD Forge、Fooocus で作られたPNG画像にも対応しています。
|
||||
> 配布サイトで見つけた画像の作り方を知りたいときに便利です
|
||||
> (ただし、投稿時にメタデータが消されている画像からは読み取れません)。
|
||||
|
||||
---
|
||||
|
||||
## 8-3 同じ設定を再現する
|
||||
|
||||
ギャラリーのいちばん便利な使い方は、**気に入った画像と同じ設定で、もう一度生成する** ことです。
|
||||
方法は2つあります。
|
||||
|
||||
### 方法1:生成UIで再現する(GenUI)
|
||||
1. ギャラリーで、再現したい画像をクリックします。
|
||||
2. 詳細パネルの **GenUI** ボタンを押します。
|
||||
3. 画像に埋め込まれていたワークフローが、生成UIに読み込まれます。
|
||||
|
||||
あとは第5章と同じように、プロンプトを少し変えたり、シードを変えたりして生成できます。
|
||||
|
||||
> **ポイント**
|
||||
> **同じ画像をもう一度作りたいとき(v0.8.3〜)**
|
||||
> 画像に埋め込まれているワークフローには、そのときのシード値も入っています。
|
||||
> 生成パネルのシードのモードを **Workflow** にして Generate を押すと、そのシードのまま生成されます。
|
||||
>
|
||||
> モードが Random のままだと、別のシードで生成されます。
|
||||
> また、Fixed を使う場合は、**Settings** サブタブの **Seed** 欄の値を生成パネルの **Seed** 欄に貼り付けてください(生成パネルの値が優先されるため)。
|
||||
|
||||
### 方法2:ComfyUIのノード画面で再現する(コピー&キャンバスへ送る)
|
||||
1. ギャラリーで、再現したい画像をクリックします。
|
||||
2. 詳細パネルの **JSON** タブを開きます。
|
||||
3. **Copy & Send Canvas**(コピー&キャンバスへ送る)を押します。
|
||||
(このボタンは英語表示のままです。ワークフローが埋め込まれた画像でだけ押せます)
|
||||
|
||||
ComfyUIのノード画面に、その画像を作ったワークフローが読み込まれます。
|
||||
ノード画面で細かく手を加えたいときは、こちらを使います。
|
||||
|
||||
> **注意**
|
||||
> 「この画像にはComfyUIワークフローが埋め込まれていません」と表示される場合は、再現できません。
|
||||
> ワークフローの情報が保存されない設定で作った画像や、別のソフトで編集・圧縮した画像などが当てはまります。
|
||||
|
||||
### 画像を次の生成の材料にする
|
||||
ギャラリーの画像を、生成の「入力画像」として使うこともできます。
|
||||
|
||||
| ボタン | 動き |
|
||||
| --- | --- |
|
||||
| Send GenUI Image | 選んだ画像を、生成UIのワークフローの入力画像(LoadImageノード)にセットする |
|
||||
| Send to LI node | 選んだ画像を、ComfyUIのノード画面で選んでいる画像読み込みノードにセットする |
|
||||
| Image Edit | 選んだ画像を Image Edit タブで開く(第11章) |
|
||||
| Send CC Layout | 選んだ画像を Comic Creator のレイアウトタブ(選択中のコマ/オーバーレイ)に送る(Comic Creatorの中でギャラリーを開いたときだけ表示。第11章 11-6) |
|
||||
| Send CC Image | 選んだ画像を Comic Creator の Image タブに送る(作業中のレイヤーがあれば新規レイヤー、なければ新規キャンバス。動画は未対応。表示条件は Send CC Layout と同じ) |
|
||||
|
||||
I2I(画像から画像を作る)ワークフローで、生成した画像をさらに描き直していくときに便利です。
|
||||
|
||||
---
|
||||
|
||||
## 8-4 ImagePrompt と Style_Catalog
|
||||
|
||||
### ImagePrompt - 見本画像からプロンプトを組み立てる
|
||||
**ImagePrompt** は、「見本画像」と「プロンプト」をセットで並べて、
|
||||
見た目で選びながらプロンプトを組み立てるためのサブタブです。
|
||||
|
||||
1. 見本画像をクリックすると、右側にその画像のプロンプトが表示されます。
|
||||
2. **+ Add** を押すと、**Selected Prompts** に追加されます。
|
||||
3. いくつか追加すると、**Final Prompt** に、カンマ区切りでまとめたプロンプトができあがります。
|
||||
4. **Copy** でコピーして、生成UIやプリセットに貼り付けます。
|
||||
|
||||
見本画像は、`output` フォルダの中に自動で作られる `ws_image_prompt` フォルダに置きます。
|
||||
画像と同じ名前の `.txt` ファイル(中身がプロンプト)を一緒に置くと、見本として使えるようになります。
|
||||
|
||||
> **例**
|
||||
> `ws_image_prompt/髪型/ponytail.png` と `ws_image_prompt/髪型/ponytail.txt`(中身:`ponytail, long hair`)
|
||||
|
||||
### Style_Catalog - スタイルを見本画像で選ぶ
|
||||
第7章で紹介したスタイルは、名前だけではどんな雰囲気になるか分かりにくいものです。
|
||||
**Style_Catalog** では、スタイルごとの見本画像を並べて、見た目で選べます。
|
||||
|
||||
見本画像は、生成UIの上部のバーにある **Create Catalog** で作ります。
|
||||
|
||||
1. 生成UIに、文章から画像を作るワークフローを読み込みます。
|
||||
2. **Batch** サブタブの **Style** で、見本を作りたいスタイルにチェックを入れます。
|
||||
3. 上部のバーの **Create Catalog** を押し、保存先のフォルダを決めて実行します。
|
||||
4. 上部のバーの **Catalog** を押すと、ギャラリーの Style_Catalog に移動します。
|
||||
|
||||
Style_Catalog で見本画像を選び、**Select as Style** を押すと、
|
||||
生成UIのスタイルが、そのスタイルに切り替わります。
|
||||
|
||||
> **ポイント**
|
||||
> モデルによってスタイルの効き方は変わります。
|
||||
> 保存先のフォルダをモデルごとに分けておくと、比べやすくなります。
|
||||
|
||||
---
|
||||
|
||||
## 8-5 Eagle連携・PSD書き出し(任意)
|
||||
|
||||
ここからは、必要な方だけが使う機能です。
|
||||
|
||||
### Eagle連携
|
||||
**Eagle** は、画像を整理するための有料ソフトです。
|
||||
設定タブの **Eagle連携** を有効にすると、生成UIで生成した画像を、プロンプトなどの情報付きで自動的にEagleに保存できます。
|
||||
Eagleで画像を管理している方は、試してみてください。
|
||||
|
||||
### PSD書き出し
|
||||
ギャラリーで複数の画像を選び、**PSD作成** を押すと、
|
||||
それぞれの画像をレイヤーとして重ねたPSD(Photoshop形式)のファイルを作れます。
|
||||
差分画像をまとめて、画像編集ソフトで仕上げたいときに便利です。
|
||||
|
||||
> **注意**
|
||||
> PSD関連の機能を使うには、追加のPythonパッケージ(psd-tools)が必要です。
|
||||
> 入っていない場合は、インストール方法がエラーメッセージで表示されます(第11章)。
|
||||
|
||||
---
|
||||
|
||||
## 8-6 画像を「意味」で探す(セマンティック検索)
|
||||
|
||||
通常の検索は、ファイル名・タグ・プロンプトの文字が一致した画像を探します。
|
||||
**セマンティック検索**(v0.8.2〜)は、画像の「意味」で探します。
|
||||
たとえば「夕暮れの街並み」と入れると、プロンプトにその言葉が無くても、雰囲気の合う画像が見つかります。
|
||||
また、選んだ画像に **似た画像** の一覧を出すこともできます。
|
||||
|
||||
### 使い方
|
||||
1. 検索欄の横の **S** ボタンをオンにします。検索欄が意味検索に切り替わり、ツールバーに2行目が現れます。
|
||||
2. 2行目の **歯車ボタン**(設定)を押し、**インデックス**(検索用の索引)を作ります(下記)。
|
||||
3. 検索欄に文章を入れて **Enter** を押します。結果はスコア順に並び、サムネイルにスコアが表示されます。
|
||||
4. 画像を選んで2行目の **Similar** を押すと、その画像に似た画像が並びます。別の画像を選んで **↻(更新)** を押すと、その画像の類似を出し直します。もう一度 **Similar** を押すと、通常の表示に戻ります。
|
||||
|
||||
> **ポイント**
|
||||
> 意味検索の結果には、並べ替えやタグ・グループの絞り込みは効きません。
|
||||
> 検索の範囲は、選んでいるフォルダの中(サブフォルダを含む)です。
|
||||
> フォルダツリーの枚数の横に緑の点があるフォルダは、直下の画像がすべてインデックス済みです。
|
||||
|
||||
### モデルを選ぶ(歯車ボタンの「モデル設定」タブ)
|
||||
| モデル | 特徴 | 準備 |
|
||||
| --- | --- | --- |
|
||||
| Gemini Embedding 2 | Googleのサービスで計算する。速い。画像をGoogleに送る | APIキーを取得し、プラグインの `.env` に `GEMINI_API_KEY=キー` と書いて、ComfyUIを再起動する |
|
||||
| EmbeddingGemma 2 | パソコンの中で、**Ollama** を使って計算する(ローカル・無料)。外部に送らない | Ollamaをインストールして起動し、`ollama pull embeddinggemma-2:740m`(または軽量版の `embeddinggemma-2:440m`)を実行する。モデル設定タブで **Ollama URL**(通常は変更不要)と **モデルサイズ** を選ぶ |
|
||||
|
||||
> **注意:Geminiを使うとき**
|
||||
> 画像がGoogleのサービスに送られます。無料枠で送った内容は、Googleの製品改善に使われる場合があります。
|
||||
> 公開したくない画像が多い場合は、ローカルの EmbeddingGemma 2 を選んでください。
|
||||
> APIキーは `.env` にだけ書き、他人に見せないようにしましょう。
|
||||
|
||||
### インデックスを作る(歯車ボタンの「インデックス」タブ)
|
||||
1. 対象のフォルダを選びます(サブフォルダを含めるかも選べます)。
|
||||
2. 「新規のみ」か「全件再作成」を選んで開始します。進み具合が表示され、途中で停止もできます。
|
||||
3. インデックスは全フォルダで共通の1つです。フォルダごとに少しずつ作っても構いません。
|
||||
|
||||
モデルやベクトル次元を変えたときは、**全件再作成** が必要です。
|
||||
|
||||
### 速さの目安と設定
|
||||
- ローカルのEmbeddingGemma 2は、v0.8.14からOllamaで動くようになりました(それまでの、ComfyUIのPythonで動かす方式は廃止)。
|
||||
NVIDIAのGPUなら1枚あたり約0.1〜0.2秒です。インデックスを作り終えると、モデルはGPUメモリから自動で降ろされます。
|
||||
- インデックスを作るときと、検索するときは、Ollamaが起動している必要があります。
|
||||
- モデルサイズの740m(テキスト+画像+音声)と440m(テキスト+画像・軽量)は同じ結果を返すので、切り替えても全件再作成は不要です。
|
||||
v0.8.13以前に作ったインデックスも、そのまま使えます。
|
||||
- **検索設定** タブで、類似画像・文章検索それぞれの「最小スコア」と最大表示件数を決められます。
|
||||
スコアの水準はモデルによって違うため、モデルごとに保存されます。
|
||||
|
||||
---
|
||||
|
||||
## 8-7 音声ファイルの扱いと変換
|
||||
|
||||
ComfyUIで音楽や効果音を作る機会が増えたため、ギャラリーは音声ファイルも扱えます(v0.8.0〜)。
|
||||
対応しているのは、WAV・MP3・OGG・M4A・FLAC・Opus です。
|
||||
|
||||
- 一覧には、音の形(波形)のサムネイルと、♪ のバッジが表示されます。波形の色は形式ごとに違います(MP3は青、WAVは緑、FLACは琥珀色、OGG/Opusは紫、M4Aはピンク)。
|
||||
- 選ぶと、右の詳細パネルに波形とプレイヤーが表示され、その場で再生できます。
|
||||
- 保存時にワークフロー(`prompt`/`workflow`)が埋め込まれている音声は、プロンプトやJSONのタブも使えます。
|
||||
- 動画(MP4・WebM)も同様に一覧できます。**Send to LV node** ボタンで、選んだ動画を、ComfyUIの画面で選択中の **Load Video** ノードに送れます(画像版の Send to LI node の動画版です)。
|
||||
|
||||
### ファイルを変換する
|
||||
音声または動画を含めて複数選択すると、一括操作バーに **変換...** が現れます。
|
||||
|
||||
1. 変換したいファイルを選び、**変換...** を押します。
|
||||
2. 出力形式(FLAC/MP3/Opus/M4A/WAV)と、必要ならビットレート・サンプルレート・チャンネル数を決めます。
|
||||
3. 実行すると、同じフォルダに別のファイルとして保存されます(同名があるときは `名前_converted` のように連番が付き、上書きはされません)。
|
||||
|
||||
動画を選んだときは、音声トラックだけを取り出して保存します。
|
||||
|
||||
| 引き継ぎ | 説明 |
|
||||
| --- | --- |
|
||||
| ワークフロー情報 | MP3・FLAC・Opus・M4A には引き継がれる。WAVには引き継げない(通知が出る) |
|
||||
| お気に入り・タグ・メモ・グループ | 引き継ぐかを選べる |
|
||||
| 元ファイルの削除 | 変換に成功したあとで削除するかを選べる(確認画面あり) |
|
||||
|
||||
> **ポイント**
|
||||
> OGG は再生はできますが、変換の出力形式には選べません。
|
||||
> ほかの動画編集ソフトを入れなくても、Workflow Studioだけで変換できます。
|
||||
|
||||
> **ポイント:Videoタブでの活用**
|
||||
> Video の Asset サブタブでは、音声ファイルを「BGMに設定」したり、「サウンドとして追加」したりできます(第11章 11-4)。
|
||||
|
||||
---
|
||||
|
||||
## 8-8 3Dモデルを見る(v0.9.4〜)
|
||||
|
||||
ComfyUIで3Dモデルを作るワークフロー(画像から3Dなど)の結果も、ギャラリーで確かめられます。
|
||||
対応しているのは、GLB・glTF・VRM・PLY(メッシュ/点群/ガウシアンスプラット)・SPZ です。
|
||||
|
||||
- 一覧には「**3D**」のバッジ付きで並びます。サムネイルは、最初に一覧に出たときにブラウザが描いてサーバーに保存します
|
||||
(128MBを超えるファイルは、開いたときに保存します)。
|
||||
- 選ぶと、右の詳細パネルの内蔵ビューアで立体として表示されます。ダブルクリックで大きく表示できます。
|
||||
|
||||
| 操作 | 動き |
|
||||
| --- | --- |
|
||||
| ドラッグ | 回転する |
|
||||
| 右ドラッグ | 位置を動かす |
|
||||
| マウスホイール | 拡大・縮小 |
|
||||
| ⟲(リセット)ボタン | 最初の向きに戻す |
|
||||
|
||||
- ComfyUIの **SaveGLB** で保存したモデルは、画像と同じようにワークフローを読み取れます(8-2・8-3)。
|
||||
|
||||
> **注意**
|
||||
> - 3Dファイルは、Image Edit・生成UI・Tagger・Feederには送れません。
|
||||
> - `.gltf` の中には、別の `.bin` や画像ファイルを参照しているものがあります。ギャラリーで移動・削除しても動くのは `.gltf` 本体だけなので、参照しているファイルの場所は変えないでください。
|
||||
|
||||
> **この章のまとめ**
|
||||
> - ギャラリーのOutputで、生成した画像をフォルダごとに見返せる。プロンプトの言葉でも検索できる
|
||||
> - 詳細パネルのプロンプトタブで、画像の生成に使ったプロンプトがすぐ分かる
|
||||
> - 「GenUI」で生成UIに、「コピー&キャンバスへ送る」でノード画面に、同じワークフローを再現できる
|
||||
> - 再現するときは、シードのモードを Workflow(または Fixed)にする
|
||||
> - メタデータサブタブに画像をドロップすると、モデル・LoRA・プロンプトを詳しく調べられる
|
||||
> - Sボタンで、文章の意味や「似た画像」から探せる(セマンティック検索)
|
||||
> - 音声ファイルも一覧・再生・変換できる
|
||||
> - 3Dモデル(GLB・glTF・VRM・PLY・SPZ)も、ギャラリーで回して確かめられる(8-8)
|
||||
@@ -0,0 +1,171 @@
|
||||
# 第9章 WS Library - ComfyUI画面の中で使う
|
||||
|
||||
ここまでの章では、Workflow Studio本体(タブが並ぶ画面)を中心に使ってきました。
|
||||
この章では、ComfyUIのノード画面の横に開く **WS Library(Workflow Studio Library)** を使います。
|
||||
|
||||
WS Libraryを使うと、Workflow Studioで整理したワークフロー・ノード・モデル・プロンプトを、
|
||||
**ノード画面にドラッグ&ドロップするだけ** で使えます。
|
||||
ノード画面で作業する時間が長い方ほど、便利さを実感できる機能です。
|
||||
|
||||
---
|
||||
|
||||
## 9-1 WS Libraryを開く
|
||||
|
||||
1. ComfyUIのノード画面を開きます。
|
||||
2. 上部メニューに追加された **WS Library** ボタン(四角が並んだアイコン)を押します。
|
||||
|
||||
画面の端にパネルが開きます。もう一度ボタンを押すと閉じます。
|
||||
|
||||
### 6つのタブ
|
||||
パネルの上部には、1文字のタブが並んでいます。マウスを重ねると、正式な名前が表示されます。
|
||||
|
||||
| タブ | 名前 | できること | 本書 |
|
||||
| --- | --- | --- | --- |
|
||||
| W | Workflows | ワークフローを読み込む | 9-2 |
|
||||
| N | Nodes | ノードやノードセットを置く | 9-2 |
|
||||
| M | Models | モデルを読み込むノードを置く | 9-2 |
|
||||
| P | Prompts | 保存したプロンプトを置く・コピーする | 9-2 |
|
||||
| I | Information | 画像やワークフローの中身を調べて、使われた素材を置く | 9-3 |
|
||||
| A | AI TOOL | 翻訳やチャットなどのAI機能を使う | 第10章 |
|
||||
|
||||
各タブの中には、さらに小さなタブ(サブタブ)があります。
|
||||
多くのタブで、次のサブタブが共通して使えます。
|
||||
|
||||
- **All** - すべて
|
||||
- **★ Favorites** - Workflow Studio本体でお気に入りに登録したもの
|
||||
- **Groups** - Workflow Studio本体で作ったグループごと
|
||||
|
||||
また、各サブタブの検索欄で、名前を入力して絞り込めます。
|
||||
|
||||
> **ポイント**
|
||||
> WS Libraryに表示される内容は、Workflow Studio本体での整理(お気に入り・グループ・バッジ)と連動しています。
|
||||
> 本体でしっかり整理しておくほど、WS Libraryも使いやすくなります。
|
||||
|
||||
---
|
||||
|
||||
## 9-2 ドラッグ&ドロップでキャンバスに置く
|
||||
|
||||
WS Libraryの基本操作は、とてもシンプルです。
|
||||
|
||||
| 操作 | 動き |
|
||||
| --- | --- |
|
||||
| キャンバスへドラッグ&ドロップ | ドロップした位置に置く・読み込む |
|
||||
| ダブルクリック | 画面の中央付近に置く・読み込む |
|
||||
|
||||
### W - ワークフローを読み込む
|
||||
ワークフローをキャンバスへドラッグ(またはダブルクリック)すると、そのワークフローが読み込まれます。
|
||||
エクスプローラーからワークフローのファイルをドロップしたときと同じ動きです。
|
||||
|
||||
サブタブ:All/★ Favorites/Groups/By Badge(バッジごと)
|
||||
|
||||
> **ポイント**
|
||||
> Workflow Studio本体をブックマークから開いていて「キャンバスへ送る」が使えない場合は、
|
||||
> このWタブに対象のワークフローが表示されるので、ここからドラッグしてください(第4章 4-6)。
|
||||
|
||||
### M - モデルを置く
|
||||
モデルをキャンバスへドラッグすると、**そのモデルが選ばれた状態の読み込みノード** が置かれます。
|
||||
|
||||
| モデルの種類 | 置かれるノード |
|
||||
| --- | --- |
|
||||
| Checkpoint | Load Checkpoint(CheckpointLoaderSimple) |
|
||||
| LoRA | Load LoRA(LoraLoader) |
|
||||
| VAE | Load VAE(VAELoader) |
|
||||
| ControlNet | Load ControlNet Model(ControlNetLoader) |
|
||||
| UNET | Load Diffusion Model(UNETLoader) |
|
||||
| TextEncoder | Load CLIP(CLIPLoader) |
|
||||
| Hypernetwork | HypernetworkLoader |
|
||||
|
||||
ノードを一覧から探して、置いて、ファイル名をプルダウンから選んで……という手間がなくなります。
|
||||
置いたあとは、ほかのノードと線でつないで使います。
|
||||
|
||||
サブタブ:All/★ Favorites/Groups/By Type(種類ごと)
|
||||
|
||||
> **ポイント**
|
||||
> Embeddingには読み込み用のノードがないため、キャンバスに置くことはできません。
|
||||
|
||||
> **ポイント:LoRAをまとめて置く**
|
||||
> LoRAのグループには **All N LoRAs**(Nはグループ内のLoRAの数)という項目が表示されます。
|
||||
> これをドラッグすると、グループ内のLoRAがすべて入った状態の `Lora Loader (LoraManager)` ノードが置かれます。
|
||||
> (カスタムノード **ComfyUI-Lora-Manager** が必要です)
|
||||
|
||||
### P - プロンプトを置く
|
||||
保存したプリセット(第7章)をキャンバスへドラッグすると、
|
||||
ポジティブ・ネガティブのプロンプトが入った **Prompt Text (WFS)** ノードが置かれます。
|
||||
これはWorkflow Studioに付属しているノードで、プロンプトの文章を出力します。
|
||||
|
||||
プロンプトを貼り付けたいだけのときは、項目の **P**(ポジティブ)/**N**(ネガティブ)ボタンでコピーできます。
|
||||
|
||||
サブタブ:All/★ Favorites/Categories(カテゴリーごと)/Groups
|
||||
|
||||
### N - ノードを置く
|
||||
ノードをキャンバスへドラッグすると、そのノードが置かれます。
|
||||
よく使うノードをWorkflow Studio本体の **ノード** タブでお気に入りに登録しておくと、すぐに取り出せます。
|
||||
Nタブの一覧で、ノードを **Alt+クリック** すると、その場でお気に入りのオン/オフを切り替えられます(v0.8.0〜)。
|
||||
Nタブは、ノードの詳細情報を待たずに一覧を先に表示するため、以前より速く開きます。
|
||||
|
||||
サブタブ:All/★ Favorites/Groups/Sets/Category(カテゴリーごと)/Package(カスタムノードのパッケージごと)
|
||||
|
||||
### ノードセット - よく使う組み合わせを丸ごと保存する
|
||||
**ノードセット** は、複数のノードとそのつながりを、ひとまとまりで保存したものです。
|
||||
「いつも同じ組み合わせで使うノード群」を保存しておけば、ドラッグ1回で丸ごと置けます。
|
||||
|
||||
**ノードセットを作る**
|
||||
1. ComfyUIのノード画面で、保存したいノードを選択します(Ctrlキーを押しながらクリック、またはドラッグで範囲選択)。
|
||||
2. 選んだノードの上で **右クリック** し、**Save as Node Set** を選びます。
|
||||
3. 名前を付けて保存します。
|
||||
|
||||
**ノードセットを使う**
|
||||
WS Libraryの **N** タブの **Sets** サブタブから、キャンバスへドラッグします。
|
||||
|
||||
> **例**
|
||||
> 「顔を自動で補正するノード群」や「高解像度化(アップスケール)のノード群」など、
|
||||
> どのワークフローにも後から付け足したい部品をセットにしておくと便利です。
|
||||
|
||||
---
|
||||
|
||||
## 9-3 Informationタブで画像の中身を調べる
|
||||
|
||||
**I(Information)** タブは、画像やワークフローのファイルを調べて、
|
||||
**使われていたモデルやプロンプトを、そのままキャンバスに置ける** 機能です。
|
||||
ギャラリーのメタデータ(第8章 8-2)を、ノード画面の中で使えるようにしたものと考えてください。
|
||||
|
||||
### 使い方
|
||||
1. WS Libraryの **I** タブを開きます。
|
||||
2. 調べたいファイル(ComfyUIで作ったPNG・WebP・MP4・WebMの画像や動画、またはワークフローのJSON)を、パネルにドロップします。
|
||||
3. ファイルの中から見つかった素材が、サブタブに分かれて表示されます。
|
||||
|
||||
| サブタブ | 内容 | キャンバスへドラッグすると |
|
||||
| --- | --- | --- |
|
||||
| model | Checkpoint・VAE・Diffusion Model・Text Encoder | 対応する読み込みノードが置かれる |
|
||||
| lora | 使われていたLoRAと、その強さ | LoRAの読み込みノードが置かれる |
|
||||
| Prompts | ポジティブ(POS)・ネガティブ(NEG)のプロンプト | プロンプトの入ったテキストエンコードノードが置かれる |
|
||||
|
||||
プロンプトの項目をクリックすると全文が表示され、**Copy** でコピーもできます。
|
||||
|
||||
### こんなときに便利
|
||||
- 「前に作ったあの画像と、同じモデルとLoRAで新しいワークフローを組みたい」
|
||||
- 「ネットで見つけたワークフローのプロンプトだけ借りたい」
|
||||
- 「この画像、どのLoRAをどれくらいの強さで使っていたっけ?」
|
||||
|
||||
ワークフローを丸ごと読み込むのではなく、**必要な部品だけを取り出して使える** のがポイントです。
|
||||
|
||||
---
|
||||
|
||||
## 9-4 WS Libraryの見た目を変える
|
||||
|
||||
WS Libraryのパネル内にある **歯車ボタン**から、パネルの配色を設定できます。
|
||||
|
||||
- パネルの背景色
|
||||
- サブヘッダーの背景色
|
||||
- 文字の色・補助的な文字の色
|
||||
- 枠線の色
|
||||
|
||||
ComfyUIのテーマに合わせて調整すると、違和感なく使えます。
|
||||
設定はブラウザに保存され、次に開いたときも反映されます。
|
||||
|
||||
> **この章のまとめ**
|
||||
> - WS Libraryは、ComfyUIのノード画面の横に開く「素材の棚」
|
||||
> - W・N・M・P のタブから、ワークフロー・ノード・モデル・プロンプトをドラッグ(またはダブルクリック)で置ける
|
||||
> - Mタブからモデルをドラッグすると、モデルが選ばれた状態の読み込みノードが置かれる
|
||||
> - 右クリックの「Save as Node Set」で、よく使うノードの組み合わせを保存できる
|
||||
> - Iタブに画像をドロップすると、使われていたモデル・LoRA・プロンプトを取り出して使える
|
||||
@@ -0,0 +1,438 @@
|
||||
# 第10章 AI TOOL - ローカルAIを助手にする
|
||||
|
||||
Workflow Studioは、パソコンの中で動く **ローカルAI(大規模言語モデル)** と連携できます。
|
||||
ローカルAIを用意すると、次のようなことができるようになります。
|
||||
|
||||
- 日本語で考えた内容を、英語のプロンプトに翻訳する
|
||||
- AIとチャットしながら、プロンプトのアイデアを出してもらう
|
||||
- 画像を見せて、その画像の説明やプロンプト、タグを作ってもらう
|
||||
- ワイルドカード用の候補リストを作ってもらう
|
||||
- **スキル** を選んで、プロンプト作り・ストーリーボード・不具合の相談など、得意分野を切り替える(v0.9.5〜)
|
||||
- 生成した画像が依頼どおりかをAIにチェックさせて、足りない点だけ直す(v0.9.5〜)
|
||||
- 画像に写っている文字を読み取る(OCR、v0.9.5〜)
|
||||
|
||||
インターネット上のサービスではなく、自分のパソコンの中で動くので、
|
||||
**入力した内容や画像が外部に送られない** のが大きな特長です。
|
||||
|
||||
> **ポイント**
|
||||
> AI機能は「あると便利」な機能です。使わなくても、Workflow Studioの基本機能はすべて使えます。
|
||||
> パソコンの性能(特にGPUのメモリ)に余裕がある方は、ぜひ試してみてください。
|
||||
|
||||
---
|
||||
|
||||
## 10-1 ローカルAIソフトを準備する
|
||||
|
||||
### 対応しているソフト
|
||||
Workflow Studioは、次の4つのローカルAIソフトに対応しています。
|
||||
|
||||
| ソフト | 特徴 | 標準のアドレス |
|
||||
| --- | --- | --- |
|
||||
| **Ollama**(オラマ) | 定番。モデルのダウンロードから実行までかんたん | `http://localhost:11434` |
|
||||
| **LM Studio** | 画面で操作できる。モデル探しもアプリ内でできる | `http://localhost:1234` |
|
||||
| Lemonade Server | AMD製のGPU・NPUでも動かしやすい | `http://localhost:13305` |
|
||||
| Unsloth | APIキーなどの追加設定が必要(上級者向け) | `http://localhost:8888` |
|
||||
|
||||
はじめての方には **Ollama** をおすすめします。本章では、Ollamaを例に説明します。
|
||||
|
||||
> **ポイント**
|
||||
> アドレスの `localhost` は「自分のパソコン」、その後ろの数字は **ポート番号** です(第2章 2-4)。
|
||||
> ComfyUIと同じように、AIソフトもそれぞれ決まったポート番号で待ち受けています。
|
||||
|
||||
### Ollamaの準備
|
||||
1. Ollamaの公式サイトから、お使いのOS用のインストーラーをダウンロードして、インストールします。
|
||||
2. Ollamaを起動します(Windowsでは、インストール後に自動で起動し、タスクバーの通知領域に常駐します)。
|
||||
3. 使うAIモデルをダウンロードします。コマンドプロンプトなどで、次のように入力します。
|
||||
|
||||
```
|
||||
ollama pull (モデル名)
|
||||
```
|
||||
|
||||
モデル名は、Ollamaの公式サイトのモデル一覧で確認できます。
|
||||
|
||||
> **モデル選びの目安**
|
||||
> - **画像を読み取る機能(VLM)も使いたい** → 画像入力(vision)に対応したモデルを選ぶ
|
||||
> (作者の検証では、Gemma 4 の `e4b` などで画像生成・画像読み取りがうまく動いています)
|
||||
> - **GPUのメモリが少ない** → パラメータ数の小さいモデル(数B=数十億程度)を選ぶ
|
||||
> - 翻訳の精度を重視するなら、日本語が得意なモデルを選ぶ
|
||||
>
|
||||
> AIモデルの世界は変化が速いので、新しいモデルも試してみてください。
|
||||
|
||||
> **注意:GPUのメモリの取り合い**
|
||||
> ローカルAIも、画像生成と同じく **GPUのメモリ(VRAM)** を使います。
|
||||
> 両方を同時に動かすと、メモリが足りなくなって画像生成が遅くなったり、エラーになったりします。
|
||||
> 対策は 10-3 で説明します。
|
||||
|
||||
---
|
||||
|
||||
## 10-2 AI TOOLタブを使う
|
||||
|
||||
Workflow Studio本体の **AI TOOL** タブを開きます。
|
||||
画面は4つの部分に分かれていて、すべて同時に表示されます。
|
||||
|
||||
| 部分 | できること |
|
||||
| --- | --- |
|
||||
| 翻訳 | 日本語・英語・中国語などの翻訳 |
|
||||
| Chat | AIとの会話。スキルで得意分野を切り替えられる。条件がそろえば、会話から画像生成も |
|
||||
| TOOLS | 画像の読み取り(VLM)、文字起こし(OCR)、ワイルドカード作成 |
|
||||
| 設定 | 使うAIソフト・モデルの設定 |
|
||||
|
||||
> **ポイント:翻訳と設定はたためる(v0.9.5〜)**
|
||||
> 翻訳と設定の見出しの右端にある矢印(◀/▶)を押すと、その部分が細い帯にたたまれ、空いた幅をChatとTOOLSが使います。
|
||||
> 帯のどこかをクリックすると元に戻ります。たたんだ状態は、次に開いたときも保たれます。
|
||||
|
||||
### 最初に:設定でAIソフトとつなぐ
|
||||
1. **設定** の **バックエンド** で、使うソフト(例:Ollama)を選びます。
|
||||
2. **接続設定** のアドレスを確認します。Ollamaを標準のまま使っている場合は、変更不要です。
|
||||
3. **接続テスト** を押します。「接続成功」と表示されればOKです。
|
||||
4. **モデル選択** の **更新** を押し、一覧から使うモデルを選びます。
|
||||
5. **設定を保存** を押します。
|
||||
|
||||
> **ポイント**
|
||||
> ここでの設定は、ComfyUI側のWS Libraryの **A(AI TOOL)** タブと共通です。
|
||||
> 一方、プロンプトタブ(第7章)とTaggerタブには、それぞれ専用の **歯車ボタン** 設定があります。
|
||||
> 「AI TOOLタブでは使えるのに、プロンプトタブでは Disconnected」というときは、プロンプトタブの歯車ボタンでも同じように設定してください。
|
||||
|
||||
> **うまくつながらないとき**
|
||||
> - Ollamaなどのソフトが起動しているか確認します。
|
||||
> - LM Studioは、アプリ内で **サーバーを起動** しておく必要があります。
|
||||
> - アドレスのポート番号が、ソフト側の設定と合っているか確認します。
|
||||
> - モデルの一覧が空のときは、モデルがダウンロードされているか確認します。
|
||||
|
||||
### 翻訳
|
||||
1. 翻訳元と翻訳先の言語を選びます(**⇄(入れ替え)** ボタンで入れ替え)。
|
||||
2. 入力欄に文章を書き、**翻訳** を押します。
|
||||
3. 結果を **コピー** して、生成UIやプリセットに貼り付けます。
|
||||
|
||||
> **ポイント**
|
||||
> TOOLSで読み取った文字(10-8のOCRなど)は、TOOLSの **翻訳へ送る** で、この入力欄にそのまま入れられます。
|
||||
|
||||
> **ポイント**
|
||||
> 小さなモデルは、翻訳せずに元の文章をそのまま返してしまうことがあります。
|
||||
> その場合は「モデルが原文をそのまま返しました」と表示されるので、別のモデルを試してください。
|
||||
|
||||
### Chat
|
||||
入力欄に話しかけて、**Enter** で送信します(**Shift+Enter** で改行)。
|
||||
会話の流れを覚えているので、「もっと明るい雰囲気にして」のような続けての依頼もできます。
|
||||
**Clear** で会話をリセットします。
|
||||
|
||||
> **ポイント:チャットから画像を生成する(上級)**
|
||||
> 「ツール呼び出し(Tool Calling)」に対応したモデルを使うと、
|
||||
> チャットで「猫の絵を描いて」と頼むだけで、生成UIに読み込んだワークフローで画像が生成され、チャット内に表示されます。
|
||||
> この機能は、入力欄の横の **画像生成を許可する** のチェックでオン・オフできます。
|
||||
|
||||
> **ポイント**
|
||||
> Chatの上にあるドロップダウンで **スキル** を選ぶと、AIの得意分野を切り替えられます(10-5)。
|
||||
> AIの返事は、見出し・箇条書き・コードの枠を整えて表示されます(v0.9.5〜)。
|
||||
|
||||
### TOOLS - 画像を読み取る(VLM)
|
||||
画像入力に対応したモデル(VLM)を使うと、画像の内容をAIに読み取らせることができます。
|
||||
|
||||
1. **TOOLS** の枠に、画像(PNG/JPG/WebP)をドロップします。
|
||||
2. 作業を選びます。
|
||||
|
||||
| 作業 | 内容 |
|
||||
| --- | --- |
|
||||
| 画像の解説 | 画像に何が写っているかを文章で説明する |
|
||||
| プロンプト作成 | 画像を再現するためのプロンプトを作る |
|
||||
| Create tags(英語表示のまま) | 画像の要素をタグ形式で書き出す |
|
||||
| Create wildcards(英語表示のまま) | カテゴリー名と件数を指定して、ワイルドカードの候補を作る(画像は不要) |
|
||||
| 文字起こし(OCR) | 画像に写っている文字を読み取る(10-8) |
|
||||
|
||||
3. **実行** を押します。
|
||||
4. 結果の下のボタンで、結果を使います(v0.9.5〜)。
|
||||
|
||||
| ボタン | 動き |
|
||||
| --- | --- |
|
||||
| 翻訳へ送る | 翻訳の入力欄に入れる(翻訳がたたまれていれば開く) |
|
||||
| Chatへ送る | Chatの入力欄に追加する |
|
||||
| コピー | クリップボードにコピーする |
|
||||
|
||||
> **例**
|
||||
> 気に入ったイラストの雰囲気をまねしたいとき、その画像から「プロンプト作成」をして、
|
||||
> できたプロンプトを生成UIで使ってみる - という使い方ができます。
|
||||
|
||||
### ComfyUIの画面の中でも使える
|
||||
同じAI機能は、ComfyUI側のWS Libraryの **A** タブでも使えます。
|
||||
ノード画面で作業しながら、ちょっと翻訳したいときに便利です。
|
||||
|
||||
---
|
||||
|
||||
## 10-3 VRAMの解放とメモリ管理
|
||||
|
||||
10-1で触れたとおり、ローカルAIと画像生成は、GPUのメモリ(VRAM)を取り合います。
|
||||
Ollamaは、一度使ったモデルをしばらくメモリに置いたままにするため、
|
||||
AIを使ったあとに画像生成をすると、メモリが足りなくなることがあります。
|
||||
|
||||
### 手動で解放する
|
||||
AI TOOLの設定にある **モデルをアンロード** を押すと、AIモデルがメモリから降ろされ、VRAMが空きます。
|
||||
(Ollamaの場合は、読み込まれているすべてのモデルが降ろされます)
|
||||
|
||||
### 生成の前に自動で解放する
|
||||
設定タブの **VRAM調整(Ollama)** で、画像生成の直前に自動でOllamaのモデルを降ろすように設定できます。
|
||||
|
||||
| 生成前の動作 | 動き |
|
||||
| --- | --- |
|
||||
| 何もしない | 自動では降ろさない |
|
||||
| 空きが目標未満のときだけ必要な分をアンロード | 空きVRAMが **目標の空き(GB)** より少ないときだけ降ろす |
|
||||
| 毎回すべてアンロード | 生成のたびに、必ずすべて降ろす |
|
||||
|
||||
> **ポイント**
|
||||
> どれを選べばよいか迷ったら、「空きが目標未満のときだけ必要な分をアンロード」がおすすめです。
|
||||
> 目標の空きには、画像生成に必要なメモリの量(使うモデルによって異なります)を目安に入力します。
|
||||
> **今すぐすべてアンロード** ボタンで、その場ですぐに解放することもできます。
|
||||
|
||||
> **注意**
|
||||
> この自動解放は、Ollamaだけが対象です。LM Studioなどを使っている場合は、手動で解放してください。
|
||||
|
||||
---
|
||||
|
||||
## 10-4 セキュリティ上の注意
|
||||
|
||||
### 標準では「自分のパソコン」のAIにだけつながる
|
||||
安全のため、Workflow StudioがつなぐAIソフト(Ollama、LM Studioなど)は、標準では
|
||||
**同じパソコンの中(localhost/127.0.0.1)で動いているもの** に限られています。
|
||||
|
||||
### 別のパソコンのAIを使いたいとき
|
||||
家庭内LANにある別のパソコン(GPUの強いパソコンなど)でOllamaを動かして使いたい場合は、
|
||||
環境変数 **`WFS_ALLOWED_BACKEND_HOSTS`** に、つなぎたいパソコンのアドレスを登録して、ComfyUIを再起動します。
|
||||
|
||||
```
|
||||
WFS_ALLOWED_BACKEND_HOSTS=192.168.1.20:11434
|
||||
```
|
||||
|
||||
複数ある場合は、カンマ(,)で区切って並べます。
|
||||
環境変数の設定方法は、ComfyUIの起動方法によって異なります。
|
||||
|
||||
### ComfyUIを `--listen` 付きで起動している場合
|
||||
ComfyUIを `--listen` オプション付きで起動すると、同じネットワークにいるほかのパソコンやスマホからも
|
||||
ComfyUI(とWorkflow Studio)にアクセスできるようになります。
|
||||
その場合、アクセスできる人なら誰でも、あなたのAIソフトや画像を使えてしまいます。
|
||||
|
||||
> **注意**
|
||||
> `--listen` は、家庭内LANなど **信頼できるネットワークでだけ** 使ってください。
|
||||
> カフェや公共のWi-Fiでは使わないようにしましょう。
|
||||
|
||||
---
|
||||
|
||||
## 10-5 スキル - Chatの得意分野を切り替える(v0.9.5〜)
|
||||
|
||||
**スキル** は、Chatに「どんな役割で、どんな形で答えるか」を教える指示書です。
|
||||
Chatの上のドロップダウン(最初は「-- スキルなし --」)で選ぶと、そのスキルの指示が毎回の会話に付けて送られます
|
||||
(指示の文章はチャットの画面には表示されません)。
|
||||
|
||||
### 最初から入っているスキル
|
||||
Workflow Studioには、次の6つのスキルが入っています(名前は英語表示のままです)。
|
||||
|
||||
| スキル | 何をするか | 結果の使い方 |
|
||||
| --- | --- | --- |
|
||||
| T2I Prompt Enhancer | 短いアイデアを、生成UIのワークフローのモデルに合った書き方のプロンプトにする | プロンプトの下のボタン |
|
||||
| Image to Prompt | TOOLSに入れた画像を再現するプロンプトを書く(画像を読み取れるモデルが必要) | プロンプトの下のボタン |
|
||||
| Storyboard to Lab | 物語をシーンごとのプロンプトに分け、Labで連続生成できる形にする | **Labで開く** |
|
||||
| Workflow Doctor | ワークフローの説明や、エラーの原因の相談にのる(10-7) | 文章で答える |
|
||||
| SVG Icon Generator | 簡単なアイコンやイラストをSVG(ベクター画像)で描く | プレビューと **Galleryに保存** |
|
||||
| Skill Creator | 質問に答えていくと、新しいスキルを作ってくれる(10-9) | **スキルとして保存** |
|
||||
|
||||
### プロンプトを作って、そのまま生成する(T2I Prompt Enhancer)
|
||||
1. 生成UIに、使うワークフローを読み込みます。スキルはこのワークフローのモデルを見て、プロンプトの書き方を決めます。
|
||||
2. AI TOOLのChatで、ドロップダウンから **T2I Prompt Enhancer** を選びます。
|
||||
3. 「雨の夜の東京、ネオン、傘を持つ猫」のように、日本語で作りたい絵を書いて送信します。
|
||||
4. 返事に、選んだ書き方(`Style:` の行)と、英語のプロンプトの枠が表示されます。その下のボタンで使います。
|
||||
|
||||
| ボタン | 動き |
|
||||
| --- | --- |
|
||||
| GenerateUIに反映 | 生成UIのポジティブ/ネガティブの欄に書き込む |
|
||||
| このプロンプトで生成 | その場で生成し、チャットに画像を表示する |
|
||||
| コピー | ポジティブプロンプトをコピーする |
|
||||
|
||||
モデルに合わせた書き方は、次のとおりです。
|
||||
|
||||
| 生成UIのモデル | プロンプトの書き方 |
|
||||
| --- | --- |
|
||||
| Qwen-Image、FLUX、Z-Image など | 英語の文章(ネガティブは、CFGが1前後なら空にする) |
|
||||
| Illustrious、NoobAI、Pony など(SDXLのアニメ系) | Danbooruのタグ(品質タグから始める) |
|
||||
| 写実系のSDXL、SD1.5 | 短い言葉をカンマで並べる |
|
||||
|
||||
> **ポイント**
|
||||
> 「もっと夜らしく」「猫を2匹に」のように続けて頼むと、直したプロンプト全体を出し直します。
|
||||
|
||||
> **ポイント:今入っているプロンプトは渡さない**
|
||||
> 生成UIに今入っているプロンプトは、ふだんはAIに渡しません。渡すと、小さなモデルが古いネガティブプロンプトなどを新しいプロンプトに混ぜてしまうためです。
|
||||
> 「**今のプロンプトを改善して**」のように、今のプロンプトに触れて頼んだときだけ渡します。
|
||||
|
||||
### ストーリーボードから連続生成する(Storyboard to Lab)
|
||||
1. 生成UIに、文章から画像を作る(T2I)ワークフローを読み込みます。
|
||||
2. Chatで **Storyboard to Lab** を選び、「茶トラの子猫が朝目覚めて、庭で蝶を追いかけ、夕方に縁側で昼寝する。3シーンで」のように頼みます。
|
||||
3. 返事に、シーンの一覧と **Labで開く(3シーン)** ボタンが表示されます。ボタンを押します。
|
||||
4. 生成UIの **Lab**(第5章 5-7)が開き、まだ保存していないプランとして読み込まれます。
|
||||
T2Iモードになり、Batchがシーンの数に、Prompt列がシーンごとのキーフレームになります。KSampler列には、全シーン共通のシード(`Seed …`)が入ります。
|
||||
5. 内容を確かめて **Run** を押します。残したいときは **Plan Save** で保存します。
|
||||
|
||||
> **ポイント**
|
||||
> 登場人物の見た目(髪・服の色など)は、全シーンで同じ文章が入るように書かれ、シードも固定されます。
|
||||
> そのため、シーンが変わっても同じキャラクターに見えやすくなります。
|
||||
|
||||
### 返事の自動チェック
|
||||
プロンプトやSVGを出すスキルでは、Workflow Studioが返事の形を自動で確かめます。
|
||||
プロンプトの枠が崩れている、SVGが閉じていない、といった問題があると、
|
||||
点線の枠で「**自動チェック:…**」と表示し、AIに1回だけ直させます。
|
||||
説明だけを頼んだときなど、プロンプトやSVGを出していない返事はそのままにします。
|
||||
|
||||
### スキルの管理(鉛筆ボタン)
|
||||
ドロップダウンの右の鉛筆ボタンで、スキルの一覧が開きます。
|
||||
|
||||
- **+ 新規** で新しいスキルを書く、各行の鉛筆ボタンで編集・削除する、**取り込み** で他のスキルを追加する(10-9)
|
||||
- 最初から入っているスキルには **同梱** と表示されます。
|
||||
編集していない同梱スキルは、Workflow Studioを更新すると自動で新しい版になります。
|
||||
編集したスキルは自動では置き換わらず、新しい版があると **↻(更新)** ボタンが表示されます。
|
||||
- スキルのファイルは `ComfyUI/user/default/Workflow-Studio/ai_skills/` に保存されます。
|
||||
|
||||
> **注意**
|
||||
> ↻(更新)で新しい版に置き換えると、そのスキルに加えた編集は消えます。
|
||||
|
||||
---
|
||||
|
||||
## 10-6 生成した画像をチェックして直す(v0.9.5〜)
|
||||
|
||||
チャットから生成した画像が、頼んだとおりになっているかをAIに確かめさせる機能です。
|
||||
足りないところがあれば、その点だけを直したプロンプトで描き直せます。
|
||||
|
||||
### 準備:判定用のモデル
|
||||
チェックには、ふつうのチャット用モデルではなく、Ollamaの **意思決定モデル**(はい/いいえを確率で答えるモデル)を使います。
|
||||
画像を読み取れるもの(作者の環境では `d3:4b`、`clef-flash`、`clef` で動作を確認)を、`ollama pull` で用意します。
|
||||
|
||||
> **ポイント:なぜ専用のモデルを使うのか**
|
||||
> 作者の検証では、チャット用のモデルに画像を見せて「剣を持っているか」と聞くと、持っていないのに「はい」と答えることがありました。
|
||||
> 意思決定モデルは「はい」の確率を数字で返すので、あいまいな答えを見分けられます。
|
||||
|
||||
1. AI TOOLの **設定** にある **CHAT 画像チェック** で、**判定モデル(Ollamaの意思決定モデル)** を選びます(一覧が空なら **更新**)。
|
||||
2. **自動修正の回数** を選びます。最初は **0(ボタンで修正)** がおすすめです。
|
||||
3. **設定を保存** を押します。
|
||||
|
||||
### 使い方
|
||||
1. Chatの入力欄の下にある **画像をチェック** にチェックを入れます。
|
||||
2. チャットから画像を生成します(AIの画像生成、または **このプロンプトで生成**)。
|
||||
3. 画像の下に結果のカードが表示されます。AIが頼んだ内容を3〜8個の確認項目に分け、1つずつ確かめた結果です。
|
||||
|
||||
| 表示 | 意味 |
|
||||
| --- | --- |
|
||||
| ✔(満たしている) | 「はい」の確率が85%以上 |
|
||||
| ?(はっきりしない) | 30〜85% |
|
||||
| ✘(満たしていない) | 30%未満 |
|
||||
|
||||
4. ✘や?があるときは **足りない点を直して再生成** を押します。満たしていない項目だけをAIに伝え、プロンプトを書き直して描き直します。
|
||||
|
||||
自動修正の回数を1〜3にすると、ボタンを押さなくても、その回数まで自動でくり返します。
|
||||
|
||||
> **ポイント:SVGもチェックできる**
|
||||
> SVG Icon Generatorで描いたSVGも、画像にしてから「頼んだものに見えるか」「部品(くちばし・翼など)が描けているか」をチェックします。
|
||||
> **分かりにくい部分を描き直させる** で直させられます。
|
||||
|
||||
> **注意**
|
||||
> - チェックは完ぺきではありません。とくに「誰が何を身につけているか」の取り違えに弱いため、
|
||||
> 人物が複数いるときは「帽子は女の子ではない」のような逆向きの確認項目を自動で加えて補っています。
|
||||
> - 描き直しの上手さは、チャット用モデルの力しだいです。直らないときは、頼み方を変えるか、モデルを変えてください。
|
||||
> - 判定モデルもGPUのメモリを使います(`d3:4b` で約6GB)。読み込んだあとは、1回のチェックが数秒です。
|
||||
|
||||
---
|
||||
|
||||
## 10-7 ワークフローの不具合を相談する(Workflow Doctor、v0.9.5〜)
|
||||
|
||||
**Workflow Doctor** は、生成UIに読み込んだワークフローの説明や、エラーの原因の相談にのるスキルです。
|
||||
AIの知識だけに頼らず、送信するたびにWorkflow Studioが実際に確かめた次の内容をAIに渡します。
|
||||
|
||||
| 確かめる内容 | 例 |
|
||||
| --- | --- |
|
||||
| インストールされていないノード | ComfyUIが知らないノードの名前 |
|
||||
| ComfyUIの一覧に無いファイル・設定値 | 見つからないモデルやLoRA(似た名前の候補も) |
|
||||
| 線のつながり | つながっていない入力、存在しないノードへの線 |
|
||||
| 直近の実行エラー | ComfyUIの履歴に残ったエラーの内容 |
|
||||
| ComfyUIのログ | ログに出た最新のエラーの部分 |
|
||||
|
||||
### 使い方
|
||||
1. 相談したいワークフローを生成UIに読み込みます(エラーの相談なら、一度実行してエラーを出しておきます)。
|
||||
2. Chatで **Workflow Doctor** を選びます。
|
||||
3. 「実行する前に問題がないか確認して」「さっきのエラーの原因は?」のように聞きます。
|
||||
|
||||
> **例**
|
||||
> LoRAのファイルを別のフォルダに移したワークフローで聞くと、
|
||||
> 「`temp\` のフォルダに指定されたファイルが見つからない。`Illustrious\` に同じ名前のファイルがある」と、直し方まで答えました。
|
||||
|
||||
> **ポイント**
|
||||
> 確かめる内容は、送信のたびに作り直されます。直したあとは、もう一度聞いてみてください。
|
||||
|
||||
---
|
||||
|
||||
## 10-8 画像の文字を読み取る(OCR、v0.9.5〜)
|
||||
|
||||
TOOLSで、画像に写っている文字を読み取れます。読み取った文字は、そのまま翻訳やChatに送れます。
|
||||
|
||||
### 準備:OCR用のモデル
|
||||
OCRには、チャット用とは別の、文字を読むのが得意なモデルを使います。Ollamaで用意してください。
|
||||
作者の環境で、横書きと縦書きの日本語・英語がまじった画像を読ませた結果は次のとおりです。
|
||||
|
||||
| モデル | 時間 | 読み取り |
|
||||
| --- | --- | --- |
|
||||
| LightOnOCR-3(`maternion/LightOnOCR-3:4b`) | 約1秒(位置つきは約6〜8秒) | すべて読めた |
|
||||
| PaddleOCR-VL(マンガ向けの版) | 約4秒 | すべて読めた |
|
||||
| DeepSeek-OCR系 | 約14秒 | すべて読めた(いつも位置つき) |
|
||||
| PaddleOCR-VL 1.6、GLM-OCR | 約11〜15秒 | 縦書きを読み落とした |
|
||||
|
||||
### 使い方
|
||||
1. TOOLSに画像をドロップします。
|
||||
2. 作業で **文字起こし(OCR)** を選びます。
|
||||
3. **OCRモデル** を選びます。名前に「ocr」を含むOllamaのモデルが、向いている順に並びます(一覧が空なら ↻ を押します)。
|
||||
4. **実行** を押します。読み取った文字が、結果の欄に1行ずつ表示されます。
|
||||
|
||||
> **ポイント:文字の位置を表示**
|
||||
> **文字の位置を表示** にチェックを入れると、画像の上に番号つきの枠が重なり、どこの文字かが分かります。
|
||||
> 枠をクリックすると、結果の欄の同じ行が選ばれます。
|
||||
> 位置を返せるのは LightOnOCR と DeepSeek-OCR系だけです。ほかのモデルでは、このチェックは選べません。
|
||||
|
||||
> **ポイント**
|
||||
> 結果が空だったり、同じ行がくり返されたりしたときは、自動で白黒(グレースケール)にして1回だけ読み直します。
|
||||
|
||||
---
|
||||
|
||||
## 10-9 スキルを自作・取り込む(上級、v0.9.5〜)
|
||||
|
||||
### Skill Creatorで作る
|
||||
Chatで **Skill Creator** を選び、「〇〇が得意なスキルを作りたい」と話しかけます。
|
||||
AIが1つずつ質問してくるので答えていくと、スキルの下書きができます。
|
||||
返事の下の **スキルとして保存** を押すと、スキルの一覧に下書きが入った状態で開くので、確かめて保存します。
|
||||
「このスキルの、ここがうまくいかない」と相談して、今あるスキルを直してもらうこともできます。
|
||||
|
||||
### スキルのファイルの中身
|
||||
スキルは、テキストファイル(`.md`)です。先頭の `---` で囲んだ部分に名前と説明を書き、その下にAIへの指示を書きます。
|
||||
先頭の部分の `metadata:` には、次の設定も書けます(書かなくてもかまいません)。
|
||||
|
||||
| 設定 | 意味 |
|
||||
| --- | --- |
|
||||
| `output` | `prompt` か `svg`。返事の形を自動でチェックし、ボタンを付ける |
|
||||
| `tools` | `[]` にすると、AIが自分で画像生成を始めない |
|
||||
| `temperature` | 答えのばらつき(0.3なら安定、0.9なら自由) |
|
||||
| `think` | 考える(Thinking)モードを、このスキルだけオン/オフにする |
|
||||
| `context` | AIに渡す情報。`workflow`(ワークフローの要約)、`current-prompt`(今のプロンプト)、`workflow-detail`/`logs`(Workflow Doctorと同じ確認内容) |
|
||||
|
||||
### ほかのスキルを取り込む
|
||||
スキルの一覧の **取り込み** で、次のファイルを追加できます。
|
||||
|
||||
- `.md` のスキル1つ
|
||||
- `SKILL.md` を含むフォルダをZIPにしたもの(**Agent Skills** という、多くのAIツールで共通の形式)
|
||||
|
||||
フォルダの中のテキストファイル(参考資料など)も一緒に取り込まれ、AIが必要になったときだけ読みに行きます
|
||||
(ツール呼び出しに対応したモデルが必要です)。
|
||||
|
||||
> **注意**
|
||||
> - 取り込むのはテキストファイルだけです。スクリプトなどのプログラムは取り込まず、実行もしません。
|
||||
> - スキルの指示は、そのままAIに渡されます。他の人が作ったスキルは、中身を読んでから使ってください。
|
||||
|
||||
> **この章のまとめ**
|
||||
> - ローカルAI(Ollamaなど)を用意すると、翻訳・チャット・画像の読み取りができる。入力内容は外部に送られない
|
||||
> - AI TOOLタブの設定で、バックエンド・アドレス・モデルを選び、接続テストをする
|
||||
> - プロンプトタブとTaggerタブには、別に歯車ボタンの設定がある
|
||||
> - AIと画像生成はVRAMを取り合う。「モデルをアンロード」や「VRAM調整(Ollama)」で解放する
|
||||
> - 標準では自分のパソコンのAIにだけつながる。`--listen` は信頼できるネットワークだけで
|
||||
> - **スキル** で得意分野を切り替える。T2I Prompt Enhancer でプロンプトを作り、ボタンで生成UIに反映・生成できる
|
||||
> - **画像をチェック** をオンにすると、意思決定モデルが生成画像を確かめ、足りない点だけ直して描き直せる
|
||||
> - Workflow Doctor は、実際に確かめた事実をもとにワークフローの不具合を相談にのる
|
||||
> - TOOLSの **文字起こし(OCR)** で画像の文字を読み取り、翻訳やChatへ送れる
|
||||
@@ -0,0 +1,353 @@
|
||||
# 第11章 さらに広がる機能(紹介編)
|
||||
|
||||
ここまでで、Workflow Studioの基本的な使い方はひととおり身につきました。
|
||||
この章では、まだ紹介していないタブや機能を、**どんなことができるか** を中心に紹介します。
|
||||
すべてを今すぐ使う必要はありません。「こんなこともできるんだ」と頭の片隅に置いておき、
|
||||
必要になったときに試してみてください。
|
||||
|
||||
---
|
||||
|
||||
## 11-1 ノードタブ - インストール済みのノードを一覧する
|
||||
|
||||
**ノード(Nodes)** タブでは、ComfyUIにインストールされているすべてのノードを一覧できます。
|
||||
|
||||
- **検索・絞り込み** - 名前、カテゴリー、パッケージ(どのカスタムノードに含まれるか)で絞り込めます。数千個あっても、一覧が先に表示されて検索も軽く動きます(v0.8.0〜)。
|
||||
- **詳細パネル** - ノードを選ぶと、入力と出力の種類(I/O仕様)を確認できます。
|
||||
- **お気に入り・グループ・タグ** - よく使うノードを整理できます。
|
||||
|
||||
ここでお気に入りやグループに登録したノードは、WS Libraryの **N** タブに表示され、
|
||||
ノード画面へドラッグで置けるようになります(第9章)。
|
||||
|
||||
> **こんなときに**
|
||||
> 「カスタムノードを入れたけど、どんなノードが増えたのか分からない」
|
||||
> → **パッケージ** で絞り込むと、そのカスタムノードに含まれるノードの一覧が見られます。
|
||||
|
||||
---
|
||||
|
||||
## 11-2 Tagger - 画像からタグを自動で作る
|
||||
|
||||
**Tagger** タブは、画像を読み取って、その画像を表すタグ(`1girl, long hair, smile` など)を自動で作る機能です。
|
||||
アニメ系のモデルのプロンプト作りや、学習用画像のタグ付けに使えます。
|
||||
|
||||
### 3つのサブタブ
|
||||
| サブタブ | できること |
|
||||
| --- | --- |
|
||||
| Single | 1枚の画像からタグを作る |
|
||||
| Batch | フォルダ内の画像に、まとめてタグを付ける(画像と同じ名前の `.txt` ファイルを書き出すことも可能) |
|
||||
| DB | タグを付けた画像の記録を検索・編集する |
|
||||
|
||||
### 使い方(Single)
|
||||
1. 画像を、プレビュー部分にドロップします(ギャラリーの詳細パネルの **Tagger** ボタンからも開けます)。
|
||||
2. 使うモデルを選び、実行ボタンを押してタグを作ります。
|
||||
3. 結果を使います。
|
||||
|
||||
| ボタン | 動き |
|
||||
| --- | --- |
|
||||
| GenUI:P | 生成UIのポジティブプロンプトに追加する |
|
||||
| Send to Prompt | プロンプトタブのポジティブプロンプトに追加する |
|
||||
|
||||
**しきい値** のスライダーで、どのくらい確かなタグまで出すかを調整できます。
|
||||
数値を上げるとタグは少なく確かなものだけに、下げると多くなります。
|
||||
|
||||
### 準備が必要
|
||||
Taggerを使うには、次の準備が必要です。
|
||||
|
||||
1. **タグ付け用のモデル**(WD Tagger など)を、ComfyUIの `models/tagger/(モデル名)/` フォルダに置きます。
|
||||
フォルダには、`.onnx` ファイルと `selected_tags.csv` を入れます。
|
||||
**PixAI Tagger v1.0**(v0.8.10〜)も使えます。Hugging Faceのコミュニティ変換版(`Mexes/pixai-tagger-v1.0-onnx-fp32-fp16-int8`)から、
|
||||
`.onnx` を1つ(GPUなら `model_fp16.onnx` がおすすめ)と、`selected_tags.csv`・`preprocess.json` を同じフォルダに入れると、自動で判別されます。
|
||||
PixAIのモデルを選ぶと、しきい値のスライダーが、PixAIの推奨値(0.17/0.27)に切り替わります。
|
||||
2. **追加のPythonパッケージ** をインストールします。
|
||||
Workflow Studioのフォルダにある `requirements.txt` を使います。
|
||||
|
||||
```
|
||||
(ComfyUIのPython) -m pip install -r requirements.txt
|
||||
```
|
||||
|
||||
「ComfyUIのPython」の場所は環境によって違います。第2章 2-6 の表で確認してください
|
||||
(例:Windowsのポータブル版では `python_embeded` フォルダの中の `python.exe`)。
|
||||
|
||||
> **注意**
|
||||
> パソコンにもともと入っているPythonにインストールしても、ComfyUIからは使えません。
|
||||
> 必ず、**ComfyUIが使っているPython** にインストールしてください。
|
||||
> 分からない場合は、ComfyUI Managerの機能でパッケージをインストールする方法もあります。
|
||||
|
||||
> **注意:GPUで動いているか確認する**
|
||||
> Taggerは、NVIDIAのGPUで動かすと1枚あたり1秒かからないのに対し、CPUで動くとPixAIでは1枚あたり20秒ほどかかります。
|
||||
> とても遅いときは、GPU用のパッケージが正しく入っているか確認してください(第12章 12-5)。
|
||||
|
||||
> **ポイント**
|
||||
> ローカルAI(第10章)の画像読み取り(VLM)と組み合わせて、両方の結果をまとめたタグを作ることもできます。
|
||||
|
||||
---
|
||||
|
||||
## 11-3 Image Edit - 生成した画像にちょっと手を加える
|
||||
|
||||
**Image Edit** タブは、レイヤー機能を持った簡易画像編集ツールです。
|
||||
生成した画像に文字を入れたり、一部を描き直すためのマスクを作ったりできます。
|
||||
|
||||
### 主な機能
|
||||
| ツール | できること |
|
||||
| --- | --- |
|
||||
| Select | レイヤーの移動・拡大縮小・回転 |
|
||||
| Draw | ペンで描く(ペンタブレットの筆圧にも対応) |
|
||||
| Text | 文字を入れる |
|
||||
| Shape | 四角・丸・線を描く |
|
||||
| Fill | 塗りつぶし・グラデーション |
|
||||
| Mask | 描き直したい部分を指定する(マスク作成) |
|
||||
| Blur | ぼかし・モザイク |
|
||||
| BG Remove | 背景を消す |
|
||||
| Inpaint | マスクした部分を、生成UIのワークフローで描き直す |
|
||||
|
||||
- 画像は、ドラッグ&ドロップ、**File Open**、またはギャラリーの **Image Edit** ボタンで開きます。
|
||||
- 編集した画像は、**Save PNG**(ダウンロード)、**Save to Gallery**(ギャラリーに保存)などで保存します。
|
||||
- **Ctrl+Z** で元に戻す、**Ctrl+Y** でやり直しができます。
|
||||
|
||||
### Drawの色とショートカット(v0.9.3〜)
|
||||
**Draw** を選ぶと、ツールの2段目に **カラーパレット** が表示されます。
|
||||
|
||||
- **色1/色2**、基本色20色、カスタム色20枠が並びます。色をクリックすると、その色で描けます。
|
||||
- **+** か空いている枠をクリックすると、今の色をカスタム色に登録します。色の上で右クリックすると、登録・編集・削除ができます(基本色も変えられ、最初の色に戻せます)。
|
||||
登録した色は、ブラウザごとに保存されます。
|
||||
- 右側の **Color** の隣にある **スポイト** ボタンで、キャンバスの色を拾えます(Escで取り消し)。
|
||||
- 描き始めの色は黒(色1)と白(色2)です。
|
||||
|
||||
| キー(Draw中) | 動き |
|
||||
| --- | --- |
|
||||
| D/E | 描く(Draw)/消す(Erase) |
|
||||
| X | 色1と色2を入れ替える |
|
||||
| [ / ] | ブラシを小さく/大きくする(実際は半角の `[` `]`) |
|
||||
| B | ブラシの選択を開く・閉じる(Escでも閉じる) |
|
||||
|
||||
### インペイント(部分の描き直し)
|
||||
Image Editのいちばん便利な使い方が、**インペイント** です。
|
||||
「顔だけ描き直したい」「手が崩れたところだけ直したい」というときに使います。
|
||||
|
||||
1. 生成UIに、インペイント用のワークフロー(付属サンプルの `ws_inpaint_basic` など)を読み込みます。
|
||||
2. Image Editで画像を開き、**Mask** で描き直したい部分を塗ります。
|
||||
3. **Inpaint** ツールで実行すると、塗った部分だけが描き直されます。
|
||||
|
||||
> **ポイント**
|
||||
> 背景を消す機能の高品質版や、より高度なマスク機能を使うには、
|
||||
> 作者の別のカスタムノード **comfyui-mask-editor-one** が必要です。
|
||||
> PSD形式での保存・読み込みには、追加のPythonパッケージ(psd-tools)が必要です。
|
||||
|
||||
---
|
||||
|
||||
## 11-4 Video - 動画を作る・つなぐ
|
||||
|
||||
**Video** タブは、動画生成モデルを使って、画像や文章から短い動画を作るための専用画面です。
|
||||
|
||||
### 対応している動画生成モデル
|
||||
- **MiniMax H3**(画像から動画)
|
||||
- **LTX-2.5**(文章から動画、画像から動画、最初と最後の画像を指定して動画)
|
||||
- **Wan2.2**(文章から動画)
|
||||
- **FastH3 OmniRef/Pika-H3-Flex**(MiniMax H3の参照画像から動画。v0.8.14〜)
|
||||
|
||||
対応するワークフローを、ワークフロータブの **Videoに読み込み** で読み込んで使います(第4章 4-6)。
|
||||
|
||||
### 主な機能
|
||||
| サブタブ | できること |
|
||||
| --- | --- |
|
||||
| Plan | 動画を「ブロック」に分け、ブロックごとにプロンプト・長さ・最初/最後の画像を決めて、順番に生成する |
|
||||
| Edit | 生成した動画や画像を並べて、切り取り・つなぎ合わせ・文字入れ・BGM付けをして書き出す |
|
||||
| Asset | 生成した動画や画像、音声を一覧する。音声は「BGMに設定」や「サウンドとして追加」ができる(種類フィルタの Audio Only で音声だけ表示) |
|
||||
|
||||
そのほか、動画の好きな場面を静止画として保存する **Frame** や、動画をGIFアニメに変換する **GIF** の機能もあります。
|
||||
|
||||
### アセット登録と音声変換(v0.8.9〜)
|
||||
- **アセット登録** - 左側の動画ソースパネルのボタンです。パソコン内の動画を、outputフォルダ(`output/video`)へコピーして「Video Assets」グループに登録します。
|
||||
登録すると、Assetサブタブの一覧に出て、Editなどで使えるようになります。
|
||||
すでにoutputフォルダにある動画(Assetで選んだものや生成結果)は、コピーせずにグループへの登録だけを行います。同じ名前があるときは、名前の後ろに連番が付きます。
|
||||
- **音声変換...** - Editサブタブの、クロップのボタンの横にあるボタンです。選んだ動画クリップの音声だけを、FLAC・MP3・Opus・M4A・WAVに変換して `output/video` に保存します。
|
||||
ギャラリーの変換と同じ画面です。音声が入っている動画クリップだけが対象です。
|
||||
- 音声変換のボタンを押すと、次の画面が開きます。**出力形式**(FLACなど)、**サンプルレート**、**チャンネル** を選び、**変換** を押します。
|
||||
「埋め込みのprompt/workflowタグを引き継ぐ」にチェックを入れると、タグを持つ形式(FLACなど)で、元の動画の情報を引き継げます。
|
||||
|
||||
- 動画ソースパネルは少し広くなり、ファイル名が1行で表示され、ボタンも横一列に並ぶようになりました。
|
||||
|
||||
### 参照画像から動画(FastH3 OmniRef/Pika-H3-Flex)(v0.8.14〜)
|
||||
このタイプのワークフローは、最初と最後の画像ではなく、**参照画像** をもとに動画を作ります。
|
||||
そのため、Planサブタブの画像の欄は、次のように名前が変わります。
|
||||
|
||||
| 欄 | このタイプでの意味 |
|
||||
| --- | --- |
|
||||
| Reference Image | 1枚目の参照画像(ふだんの First Image の欄) |
|
||||
| Reference Image 2 (optional) | 2枚目の参照画像(ふだんの Last Image の欄) |
|
||||
|
||||
- プロンプト・長さ(秒)・縦横比などは、ほかの動画ワークフローと同じように使えます。
|
||||
- 画像の欄を **None** や **Clear** で空にしたブロックは、ワークフローに参照画像が設定されていても、その画像を使わずに生成します。
|
||||
「+ Block」で追加したブロックは画像が空の状態で始まるので、参照画像が必要なブロックでは、それぞれ画像を指定してください。
|
||||
- 画像の選び方で **Use previous block's last frame**(前のブロックの最後のフレームを使う)を選ぶと、前のブロックで実際に生成された動画の最後のフレームが、そのブロックの1枚目の参照画像になります。
|
||||
- Assetサブタブのボタンも「Reference Imageに設定」「Reference Image 2に設定」に変わります。
|
||||
|
||||
> **注意**
|
||||
> 動画生成は、画像生成よりもはるかに多くのGPUメモリと時間を使います。
|
||||
> 使うモデルの必要スペックを確認してから試しましょう。
|
||||
|
||||
---
|
||||
|
||||
## 11-5 設定タブの主な項目
|
||||
|
||||
**設定** タブでは、Workflow Studio全体の設定をします。
|
||||
項目ごとに折りたたまれているので、見出しをクリックして開きます。
|
||||
ここでは、これまでの章で紹介していない項目を中心に紹介します。
|
||||
|
||||
| 項目 | 内容 | 関連する章 |
|
||||
| --- | --- | --- |
|
||||
| テーマ | 画面の配色・フォント | 第3章 |
|
||||
| UI言語/要約言語 | 表示言語 | 第2章 |
|
||||
| 文字サイズ | プロンプト入力欄などの文字の大きさ | 第3章 |
|
||||
| ワークフローデータフォルダ | ワークフローを読み込むフォルダ | 第4章 |
|
||||
| ギャラリー Outputフォルダ | ギャラリーで表示するフォルダ | 第8章 |
|
||||
| デフォルトワークフロー | Workflow Studioを開いたとき、生成UIに自動で読み込むワークフロー | 下記 |
|
||||
| デフォルトCheckpoint | 生成UIにワークフローを読み込むとき、モデルを自動で差し替える | 下記 |
|
||||
| CivitAI APIキー | Civitaiの情報取得用(省略可) | 第6章 |
|
||||
| Eagle 連携 (オプション) | 生成画像をEagleに自動保存 | 第8章 |
|
||||
| VRAM調整(Ollama) | 生成前にAIモデルをメモリから降ろす | 第10章 |
|
||||
| データ管理 | 設定やデータのバックアップ・復元 | 下記 |
|
||||
|
||||
### デフォルトワークフロー
|
||||
いつも使う基本のワークフローを設定しておくと、Workflow Studioを開いたときに生成UIへ自動で読み込まれます。
|
||||
ワークフロータブの詳細画面の **デフォルトに設定** ボタンからも設定できます。
|
||||
|
||||
### デフォルトCheckpoint
|
||||
ネットから入手したワークフローには、手元にないモデルが指定されていることがよくあります(第5章 5-3)。
|
||||
**デフォルトCheckpoint** を設定してオンにしておくと、生成UIにワークフローを読み込むたびに、
|
||||
Checkpointが自動で指定のモデルに差し替わります。モデルの選び直しの手間が省けます。
|
||||
|
||||
### データ管理(バックアップ)
|
||||
**データ管理** では、Workflow Studioで整理した情報(お気に入り・バッジ・グループ・プリセットなど)を
|
||||
ファイルに書き出したり(エクスポート)、読み込んで元に戻したり(インポート)できます。
|
||||
|
||||
**フルバックアップ (ZIP)** を使うと、スタイルやLabのプランなどのフォルダ単位のデータも含めて、まとめてバックアップできます。
|
||||
|
||||
> **ポイント**
|
||||
> パソコンの買い替えやComfyUIの入れ直しの前には、必ずバックアップを取っておきましょう。
|
||||
> 時間をかけて整理した情報を、そのまま新しい環境に引き継げます。
|
||||
> (安全のため、APIキーはバックアップに含まれません)
|
||||
|
||||
## 11-6 連携ソフト:ComfyUI Comic Creator - 生成した画像でマンガを作る
|
||||
|
||||
**ComfyUI Comic Creator**(以下、Comic Creator)は、Workflow Studioと同じ作者が開発している、
|
||||
ComfyUI上で動く **マンガ制作用** のカスタムノードです。
|
||||
Workflow Studioとは別にインストールするソフトですが、両方を入れると連携して使えます。
|
||||
|
||||
### Comic Creatorでできること
|
||||
| 機能 | 内容 |
|
||||
| --- | --- |
|
||||
| コマ割り | テンプレートを選んで、ページにコマを作る(自作テンプレートも登録可能) |
|
||||
| 画像の配置 | コマに画像をドラッグ&ドロップで配置する |
|
||||
| フキダシ・テキスト | 縦書き・横書きのセリフ、さまざまな形のフキダシ、効果文字を入れる |
|
||||
| マンガ効果 | 集中線・スクリーントーン・網点(ハーフトーン)などを加える |
|
||||
| 画像の編集 | レイヤー付きの画像編集(Image タブ) |
|
||||
| AIでの自動作成 | お題から、ストーリー・脚本・コマ割りをAIで下書きする(Auto タブ) |
|
||||
| 書き出し | JPEG/PNG/WebP/SVG/PDF/**EPUB** 形式で出力する |
|
||||
|
||||
### Workflow Studioとの連携
|
||||
両方をインストールすると、次のような連携ができます。
|
||||
|
||||
- **Comic Creatorの中でWorkflow Studioのギャラリーを使う**
|
||||
Comic Creatorの中にWorkflow Studioのギャラリーが表示され、生成した画像を選んで **Send CC Layout**(レイアウトタブのコマ/オーバーレイへ)または **Send CC Image**(Imageタブへ)ボタンで送れます。
|
||||
(Send CCボタンは、Comic Creatorの中で開いたギャラリーにだけ表示されます)
|
||||
- **Comic Creatorから画像を生成する**
|
||||
Comic Creatorの画面から、Workflow Studio(生成UI)を通して、コマに入れる画像を生成したり(T2I)、
|
||||
描いたラフや配置した画像をもとに描き直したり(I2I・インペイント)できます。
|
||||
Comic CreatorのNanobanana+タブ(ローカルモード)からは、複数の参照画像を使う画像編集のワークフロー(Flux.3 Klein、Qwen Image 2.1 など)も実行できます(v0.8.12〜)。
|
||||
|
||||
「Workflow Studioで画像を作る → Comic Creatorでマンガにまとめる」という流れで、
|
||||
画像生成からマンガの完成までを、ComfyUIの中だけで行えます。
|
||||
|
||||
### インストールと起動
|
||||
1. ComfyUI Managerの **Install via Git URL** に、次のURLを入力してインストールします。
|
||||
|
||||
```
|
||||
https://github.com/ketle-man/comfyui-comic-creator
|
||||
```
|
||||
|
||||
(手動の場合は、Workflow Studioと同じく `ComfyUI/custom_nodes/` に `git clone` します)
|
||||
|
||||
2. ComfyUIを再起動します。
|
||||
3. ComfyUIの上部メニューに追加された **CC** ボタンを押すと、Comic Creatorが新しいタブで開きます。
|
||||
|
||||
> **ポイント**
|
||||
> Comic Creatorの詳しい使い方は、アプリ内の **ヘルプ** タブ(日本語対応・検索機能あり)を参照してください。
|
||||
|
||||
---
|
||||
|
||||
## 11-7 TagSpace - タグとプロンプトを「意味の地図」から選ぶ(v0.9.0〜)
|
||||
|
||||
**TagSpace** タブは、Workflow Studioの中にあるプロンプトやタグ、生成した画像を、
|
||||
**意味の近さ** にしたがって3Dの空間に並べて表示する機能です。
|
||||
近くにあるものほど意味が近いので、「この雰囲気に近いタグは何だろう」と眺めながら、タグを選んでプロンプトを作れます。
|
||||
|
||||
### 空間に並ぶもの
|
||||
| 種類 | 中身 | 表示 |
|
||||
| --- | --- | --- |
|
||||
| カード | ギャラリーの **ImagePrompt**(第8章 8-4)の見本画像と、そのプロンプト | サムネイル |
|
||||
| タグ | ImagePromptのプロンプト・生成画像に埋め込まれたプロンプト・ワイルドカード・Tagger DB・Promptライブラリの文を、カンマで区切った語 | 出典ごとに色分けした点 |
|
||||
| Gallery点 | ギャラリーの生成画像の一部(それぞれ、自分のプロンプトのタグを持つ) | 薄い点 |
|
||||
|
||||
### 準備
|
||||
ギャラリーのセマンティック検索(第8章 8-6)と同じく、**Ollama** と **EmbeddingGemma 2** が必要です。
|
||||
ギャラリーのセマンティック検索の索引を、Gemini Embedding 2で作っている場合は、先にEmbeddingGemma 2で作り直してください。
|
||||
|
||||
### 空間を作る
|
||||
ツールバーで設定を選び、**作成 / 更新** を押します。
|
||||
|
||||
| 項目 | 内容 |
|
||||
| --- | --- |
|
||||
| タグ数 | 空間に入れるタグの数。出典ごとに、よく使われている順に交互に選ぶ |
|
||||
| 全タグ | オンにすると、タグ数の代わりに候補のタグをすべて使う(上限2万件) |
|
||||
| 最低出現回数 | この回数未満しか使われていないタグを除く。2にすると、1回だけの表記ゆれなどが消える |
|
||||
| ワイルドカード | ワイルドカードをタグの材料に含めるかどうか |
|
||||
| Gallery点数 | 表示する生成画像の数(0で表示なし) |
|
||||
| Tagger補完 | プロンプトを取り出せない生成画像に、Taggerのモデルでタグを付ける(OFF/モデル名。「Gallery点のみ」か「プロンプトの無い全画像」を選ぶ) |
|
||||
|
||||
- 1回目は、画像のプロンプトの読み取りやタグの準備に数分かかります。2回目からは、前回の結果を使うので数秒〜数十秒で終わります。
|
||||
- 状態表示に、カード・タグ・Gallery点の数が出ます。候補の一部だけを使ったときは「(候補 N)」と出ます。
|
||||
|
||||
> **ポイント**
|
||||
> タグの種類の大半は、ワイルドカードにしか出てこない語です。
|
||||
> 「ワイルドカード」をオフにして「全タグ」をオンにすると、自分が実際に使ってきたタグだけを全部並べられます(検証環境では約1万種)。
|
||||
|
||||
> **注意**
|
||||
> Tagger補完は、CPUで動くと1枚あたり0.5秒ほどかかります。「プロンプトの無い全画像」を選ぶ前に、TaggerがGPUで動いているか確認してください(第12章 12-5)。
|
||||
|
||||
### 見る・探す
|
||||
- **ドラッグ** で回転、**右ドラッグ** で移動、**ホイール** でズームします。
|
||||
- 点にカーソルを合わせると、名前・サムネイル・プロンプトや出典が表示されます。
|
||||
- ツールバーのチェックボックスで、カード・サムネイル・タグ・Galleryの表示や、**発光**(夜空に光る星のような表示)・**またたき** を切り替えます。
|
||||
出典ごとのチェックボックスで、タグを出典ごとに表示・非表示にできます。
|
||||
- 右上の検索欄に言葉や文章を入れて **Enter** を押すと(日本語も可)、その意味の位置に白い印が付き、近いカードやタグが一覧に出ます。
|
||||
|
||||
### タグを選んでプロンプトを作る
|
||||
1. カードやタグをクリックすると選択され、右の **近くの要素** に、意味の近いカード・タグが並びます。
|
||||
(Gallery点をクリックすると、似ている生成画像も並びます)
|
||||
2. プロンプトに入れたいものを **ダブルクリック** するか、**選択中** の **追加**、または一覧の **+** を押します。
|
||||
カードはプロンプト全体、タグはタグそのもの、Gallery点はその画像のタグが、右端の **プロンプト** 欄に入ります。
|
||||
3. **GenerateUIへ追記(Positive)** で、生成UIに読み込んだワークフローのポジティブプロンプトに追記します(先に生成UIでワークフローを読み込んでおきます)。
|
||||
**コピー** でクリップボードにコピーすることもできます。
|
||||
|
||||
### カードや生成画像のタグで探す
|
||||
カードやGallery点を選ぶと、**選択中** に、そのプロンプトのタグがボタンで並びます。
|
||||
タグをクリックして選び(もう一度で解除)、**選択したタグで空間検索** を押すと、選んだタグで空間を検索します。
|
||||
「この画像の、髪型と服装だけに近いものを探したい」といったときに便利です。
|
||||
タグを選んでいる間は、**選択中** の **追加** ボタンが **選択したタグを追加(N)** に変わり、選んだタグだけをプロンプト欄に追加できます。
|
||||
タグを選んでいなければ、これまでどおり全体(カードはプロンプト全文、Gallery点はすべてのタグ)が追加されます。
|
||||
|
||||
Gallery点を選んでいるときは、**選択中** に **Galleryで開く** ボタンも表示されます。
|
||||
押すとギャラリータブに切り替わり、その画像のフォルダが選ばれ、画像一覧でその画像が選択された状態になります(右の詳細も開きます)。
|
||||
画像が一覧に必ず出るよう、ギャラリーの検索・お気に入り・タグ・グループの絞り込みは解除されます。
|
||||
カードのプロンプト全文は、**プロンプト全文** を開くと読めます。
|
||||
|
||||
---
|
||||
|
||||
> **この章のまとめ**
|
||||
> - ノードタブでインストール済みのノードを一覧・整理でき、WS Libraryで使える
|
||||
> - Taggerは画像からタグを自動生成する。モデルと追加パッケージの準備が必要
|
||||
> - Image Editはレイヤー付きの簡易編集ツール。インペイントで部分的な描き直しもできる
|
||||
> - Videoタブで、対応する動画生成モデルを使った動画作りと簡単な編集ができる
|
||||
> - 設定タブの「デフォルトCheckpoint」と「データ管理(バックアップ)」は特に便利
|
||||
> - 同じ作者の Comic Creator と組み合わせると、生成した画像でマンガを作れる
|
||||
> - TagSpaceでは、手持ちのタグ・プロンプト・生成画像を意味の近さで3Dに並べ、眺めながらタグを選んでプロンプトを作れる
|
||||
@@ -0,0 +1,230 @@
|
||||
# 第12章 困ったときは(トラブルシューティング/FAQ)
|
||||
|
||||
この章では、Workflow Studioを使っていてよく起こるトラブルと、その対処方法をまとめます。
|
||||
困ったときは、まず **「症状」** の見出しから、自分の状況に近いものを探してください。
|
||||
|
||||
> **まず試してほしい3つのこと**
|
||||
> どんなトラブルでも、次の3つで解決することがよくあります。
|
||||
> 1. ブラウザのページを再読み込みする(F5キー)
|
||||
> 2. Workflow Studioの各タブの **更新**(Refresh)ボタンを押す
|
||||
> 3. ComfyUIを完全に終了して、起動し直す
|
||||
|
||||
---
|
||||
|
||||
## 12-1 起動・接続のトラブル
|
||||
|
||||
### Wボタンが表示されない
|
||||
| 原因 | 対処 |
|
||||
| --- | --- |
|
||||
| インストール後にComfyUIを再起動していない | ComfyUIを完全に終了して、起動し直す(ブラウザの再読み込みだけでは反映されません) |
|
||||
| フォルダの場所が違う | `ComfyUI/custom_nodes/ComfyUI-Workflow-Studio` にフォルダがあるか確認する。フォルダが二重になっていないかも確認 |
|
||||
| ComfyUIが古い | ComfyUI本体を更新する |
|
||||
|
||||
### Workflow Studioのページが開かない
|
||||
- ComfyUIは起動していますか? Workflow StudioはComfyUIの中で動いているため、ComfyUIを終了すると開けません。
|
||||
- アドレスの **ポート番号** は合っていますか? ComfyUIを開いているブラウザのアドレス欄で確認できます(第2章 2-4)。
|
||||
|
||||
### 生成UIが「Disconnected」になる
|
||||
1. ComfyUIが起動していて、ComfyUIの画面で画像を生成できるか確認します。
|
||||
2. 生成UIの上部の **Connect** を押します。
|
||||
3. それでもつながらない場合は、ブラウザのページを再読み込みします。
|
||||
|
||||
### 更新したのに動きが変わらない
|
||||
Workflow Studioを更新(アップデート)したあとは、必ずComfyUIを再起動してください。
|
||||
それでも古い動きのままのときは、ブラウザのキャッシュが残っている可能性があります。
|
||||
**Ctrl+F5**(強制再読み込み)を試してください。
|
||||
|
||||
---
|
||||
|
||||
## 12-2 ワークフローのトラブル
|
||||
|
||||
### ワークフローが一覧に出てこない
|
||||
| 原因 | 対処 |
|
||||
| --- | --- |
|
||||
| 一覧が古いまま | ワークフロータブの **更新** を押す |
|
||||
| 絞り込みがかかっている | ツールバー右端の **× クリア** を押す |
|
||||
| 別のフォルダに保存している | 設定タブの「ワークフローデータフォルダ」を確認する |
|
||||
|
||||
### ノードが赤く表示される(missing)
|
||||
ワークフローを読み込んだとき、ノードが赤く表示されたり、「見つからないノードがあります」と表示されたりすることがあります。
|
||||
これは、そのワークフローに必要な **カスタムノードがインストールされていない** という意味です。
|
||||
|
||||
**対処**
|
||||
1. ComfyUIの **Manager** を開きます。
|
||||
2. **Install Missing Custom Nodes**(不足しているカスタムノードをインストール)を選びます。
|
||||
3. 表示されたカスタムノードをインストールし、ComfyUIを再起動します。
|
||||
|
||||
> **ポイント**
|
||||
> ワークフロータブの **GenerateUIチェック**(第4章 4-7)で「変換 ×」になるのも、多くはこれが原因です。
|
||||
> バッジにマウスを重ねると、足りないノードの名前が表示されます。
|
||||
|
||||
### 生成UIで「使えない」と判定された
|
||||
| 判定 | 意味と対処 |
|
||||
| --- | --- |
|
||||
| 変換 × | 必要なカスタムノードがない → 上の「ノードが赤く表示される」を参照 |
|
||||
| 変換 △ | 手元にないモデルなどが指定されている → 生成UIで選び直す(12-3) |
|
||||
| 操作性 △/× | 生成UIに表示されない設定が多い → 生成はできることが多い。細かい設定はComfyUIのノード画面で変更する |
|
||||
|
||||
---
|
||||
|
||||
## 12-3 生成のトラブル
|
||||
|
||||
### 設定を変えたのに、結果が変わらない
|
||||
いちばん多い原因は、**Apply の押し忘れ** です。
|
||||
生成UIでは、モデルやSettings(ステップ数・サイズなど)の値を変えたあと、**Apply** を押さないとワークフローに反映されません(第5章 5-3)。
|
||||
ただし、Settingsタブの右端のスイッチの列は、クリックした時点で反映されます(第5章 5-4)。
|
||||
右側の **Raw JSON** を見ると、実際に反映されている値を確認できます。
|
||||
|
||||
### 読み込んだワークフローとは違う内容で生成される
|
||||
**Batch** サブタブで、バッチの種類のチェックがオンのまま残っていると、
|
||||
Generateを押したときにバッチ生成が実行されます(第5章 5-5)。
|
||||
Batchサブタブを開き、Batch Queueの列のチェックをすべてオフにしてください。
|
||||
|
||||
### 思っていたのと違うモデルで生成される
|
||||
ワークフローに保存されているモデルが手元にないと、別のモデルに自動で差し替えられることがあります。
|
||||
その場合は「Checkpoint「…」が見つからず、無警告で別のモデルに差し替えられました」と表示されます。
|
||||
(v0.8.7〜は、フォルダ名だけが違う同名のモデルが1つだけ手元にあれば、それに自動で差し替わります)
|
||||
生成UIの **Model** サブタブで、使いたいモデルを選び直して **Apply** を押してください。
|
||||
|
||||
いつも同じモデルを使いたい場合は、設定タブの **デフォルトCheckpoint** を使うと便利です(第11章 11-5)。
|
||||
|
||||
### 同じ設定なのに、同じ画像にならない
|
||||
生成パネルのシードのモードが **Random** になっていませんか?
|
||||
同じ画像を作るには、シードを **Workflow**(ワークフローのシードをそのまま使う)か **Fixed**(Seed欄の値で固定)にする必要があります。
|
||||
同じシード・同じ設定で続けて生成して新しい画像が増えないのは、ComfyUIが計算済みの結果を再利用しているためで、故障ではありません。
|
||||
ギャラリーの画像を再現する手順は、第8章 8-3を参照してください。
|
||||
|
||||
### 生成が遅い・エラーで止まる(メモリ不足)
|
||||
| 原因 | 対処 |
|
||||
| --- | --- |
|
||||
| ローカルAIがGPUメモリを使っている | AI TOOLの **モデルをアンロード** を押す。設定タブの **VRAM調整(Ollama)** を使う(第10章 10-3) |
|
||||
| 画像サイズやBatch Sizeが大きすぎる | Settingsサブタブで Width・Height・Batch Size を小さくする |
|
||||
| モデルがGPUに対して大きすぎる | より小さいモデル(GGUF版など)を使う |
|
||||
|
||||
### モデルを移動・削除したあとにエラーが出る
|
||||
ComfyUIが、モデルの古い場所を覚えていることがあります。
|
||||
ComfyUIのメニューの **Hard Reset**(キューのメニュー内)を実行するか、ComfyUIを再起動してください。
|
||||
|
||||
### 新しく入れたモデルが一覧に出てこない
|
||||
生成UIの **Refresh Models**、またはモデルタブの **更新** を押してください。
|
||||
それでも出てこない場合は、モデルを置いたフォルダが正しいか(第6章 6-1)を確認します。
|
||||
|
||||
---
|
||||
|
||||
## 12-4 AI機能のトラブル
|
||||
|
||||
### AI機能が「Disconnected」になる・つながらない
|
||||
1. Ollamaなどのソフトが起動しているか確認します。
|
||||
LM StudioやLemonadeの場合は、アプリ内で **サーバーを起動** し、モデルを読み込んでおく必要があります。
|
||||
2. 設定のアドレス(ポート番号)が、ソフト側と合っているか確認します。
|
||||
3. **接続テスト** を押して、結果を確認します。
|
||||
|
||||
### AI TOOLタブでは使えるのに、プロンプトタブでは使えない
|
||||
AIの設定は、場所によって別々に保存されています(第10章 10-2)。
|
||||
|
||||
| 場所 | 設定する場所 |
|
||||
| --- | --- |
|
||||
| AI TOOLタブ/WS LibraryのAタブ | AI TOOLタブの設定(共通) |
|
||||
| プロンプトタブ | プロンプトタブのAI Assistantの **歯車ボタン** |
|
||||
| Taggerタブ | Taggerタブの **歯車ボタン** |
|
||||
|
||||
### モデルの一覧が空になる
|
||||
AIモデルがダウンロードされていない可能性があります。
|
||||
Ollamaの場合は `ollama pull (モデル名)` でモデルをダウンロードしてから、モデル選択の **更新** を押してください。
|
||||
|
||||
### 別のパソコンのOllamaにつながらない
|
||||
安全のため、標準では同じパソコンの中のAIソフトにしかつながりません。
|
||||
環境変数 `WFS_ALLOWED_BACKEND_HOSTS` の設定が必要です(第10章 10-4)。
|
||||
|
||||
### 画像チェックの判定モデルや、OCRモデルが一覧に出てこない
|
||||
- 判定モデルの一覧には、Ollamaの **意思決定モデル** のうち、画像を読み取れるものだけが出ます。
|
||||
ふつうのチャット用モデルは出ません。Ollamaを新しい版に更新し、意思決定モデルを `ollama pull` してから **更新** を押します(第10章 10-6)。
|
||||
- OCRモデルの一覧には、名前に「ocr」を含むOllamaのモデルだけが出ます。取得後に ↻ を押します(第10章 10-8)。
|
||||
- どちらも、AI TOOLのバックエンドがOllamaならそのアドレス、そうでなければ `http://localhost:11434` のOllamaを見に行きます。
|
||||
|
||||
### 画像チェックで、何度直しても満たされない
|
||||
- 描き直しの上手さは、チャット用モデルの力しだいです。頼み方を短く具体的にするか、別のモデルを試してください。
|
||||
- チェック自体もまちがえることがあります。画像を自分の目でも確かめてください。
|
||||
- 自動修正の回数を上げすぎると、生成の時間とGPUのメモリを使い続けます。最初は「0(ボタンで修正)」がおすすめです。
|
||||
|
||||
### AIがスキルの資料を読まない・チャットから画像を生成しない
|
||||
取り込んだスキルの参考資料を読む機能と、チャットからの画像生成は、
|
||||
**ツール呼び出し(Tool Calling)に対応したモデル** でないと動きません。対応しているモデルに切り替えてください。
|
||||
|
||||
---
|
||||
|
||||
## 12-5 そのほかの機能のトラブル
|
||||
|
||||
### Taggerにモデルが表示されない
|
||||
- `ComfyUI/models/tagger/(モデル名)/` フォルダに、`.onnx` ファイル(と `selected_tags.csv`)が入っているか確認します。
|
||||
- 追加のPythonパッケージ(onnxruntime)が、**ComfyUIが使っているPython** にインストールされているか確認します(第11章 11-2)。
|
||||
|
||||
### Taggerがとても遅い(GPUが使われない)
|
||||
ComfyUIのPythonに、CPU版の `onnxruntime` とGPU版の `onnxruntime-gpu` が両方入っていると、GPUが使われなくなります。
|
||||
(ほかのカスタムノードのインストールで、CPU版が入ることがあります)
|
||||
ComfyUIを停止し、ComfyUIのPythonで `pip uninstall -y onnxruntime onnxruntime-gpu` のあと `pip install onnxruntime-gpu` を実行して、ComfyUIを再起動してください(DirectMLは非対応)。
|
||||
|
||||
### PSD関連の機能がエラーになる
|
||||
追加のPythonパッケージ(psd-tools)が必要です。
|
||||
エラーメッセージに表示されるインストール用のコマンドを、ComfyUIが使っているPythonで実行してから、ComfyUIを再起動してください。
|
||||
|
||||
### セマンティック検索(Gallery)がうまく動かない
|
||||
| 症状 | 原因 | 対処 |
|
||||
| --- | --- | --- |
|
||||
| 「Ollamaに接続できません」と出る | Ollamaが起動していない、またはOllama URLが違う | Ollamaを起動する(インデックス作成中と検索時に必要)。歯車ボタンのモデル設定タブでOllama URLを確認する |
|
||||
| 「Ollamaのモデルが未取得です」と出る | EmbeddingGemma 2をダウンロードしていない | `ollama pull embeddinggemma-2:740m`(または `embeddinggemma-2:440m`)を実行する |
|
||||
| インデックス作成が「connection was forcibly closed」などでときどき失敗する | セキュリティソフト(AdGuardなど)がOllamaの通信に割り込んでいる | Ollamaをフィルタの対象から外す。失敗した画像は、次回の「新規・変更された画像のみ」で作り直される |
|
||||
| Geminiで「GEMINI_API_KEYが未設定」と出る・キーが拒否される | `.env` にキーが無い、または行頭に `#` が付いている | プラグインの `.env`(`.env.example` をコピー)に `GEMINI_API_KEY=キー` と書き、ComfyUIを再起動する。`.env` は起動時にしか読み込まれない |
|
||||
| 検索やSimilarの結果が出ない | 選んだフォルダにインデックス済みの画像が無い | 歯車ボタンでインデックスを作る。緑の点があるフォルダを選ぶ。モデルやベクトル次元を変えたときは「全件再作成」 |
|
||||
|
||||
### TagSpaceの空間が作れない
|
||||
| 症状 | 原因 | 対処 |
|
||||
| --- | --- | --- |
|
||||
| 「OllamaのEmbeddingGemma 2が必要です」と出る | Ollamaが起動していない、またはモデルが無い | セマンティック検索と同じ準備をする(上の表) |
|
||||
| 「Galleryのセマンティック索引は … で作られています」と出る | ギャラリーの索引をGeminiで作っている | ギャラリーのセマンティック設定でEmbeddingGemma 2を選び、「全件再作成」する |
|
||||
| 作成にとても時間がかかる | 1回目は、画像のプロンプトの読み取りと、新しいタグの準備に時間がかかる | 2回目からは速くなる。Tagger補完を使うときは、TaggerがGPUで動いているか確認する(上の「Taggerがとても遅い」) |
|
||||
|
||||
### パートナーAPI(Nano Banana)が「認証に失敗しました」と出る
|
||||
`.env` にComfy APIキーが無いのが原因です。プラグインの `.env` に `COMFY_API_KEY=キー`(platform.comfy.orgで発行)を書き、ComfyUIを再起動してください(第5章 5-8)。
|
||||
`.env` は起動時にしか読み込まれません。
|
||||
|
||||
### ComfyUIが固まる(どのタブも反応しなくなる)
|
||||
Windowsで、プレビュー画像の多いモデルタブの一覧を切り替えたあとなどに、ComfyUIが反応しなくなる(生成もできなくなる)場合があります。
|
||||
設定タブの **Windowsの安定性(イベントループ)** で、**WindowsでSelectorイベントループを使用する** をオンにして、ComfyUIを再起動してください。
|
||||
|
||||
### ギャラリーの画像の一部が、別の画像のように壊れて見える
|
||||
上の **Selectorイベントループ** をオンにしているとき、v0.9.1までは、ギャラリーのプレビューや Download で受け取った画像の一部が壊れることがありました
|
||||
(出力フォルダのファイル自体は正常です)。v0.9.2で直っています。
|
||||
Workflow Studioを更新したあと、壊れた画像がブラウザに残っていることがあるので、**Ctrl+F5** で再読み込みしてください。
|
||||
|
||||
### ギャラリーに画像が出てこない
|
||||
- ギャラリーの **Refresh** を押します。
|
||||
- 設定タブの「ギャラリー Outputフォルダ」が、ComfyUIの画像保存先と合っているか確認します。
|
||||
|
||||
---
|
||||
|
||||
## 12-6 それでも解決しないときは
|
||||
|
||||
### Workflow Studioのヘルプを見る
|
||||
Workflow Studioの **ヘルプ** タブにも、トラブルシューティングの情報があります。
|
||||
本書の発行後に追加された情報が載っていることもあります。
|
||||
|
||||
### GitHubで質問・報告する
|
||||
解決しない問題は、Workflow StudioのGitHubリポジトリの **Issues** で報告できます。
|
||||
報告するときは、次の情報を添えると、原因が見つかりやすくなります。
|
||||
|
||||
- Workflow Studioのバージョン
|
||||
- ComfyUIのバージョンと、インストール方法(ポータブル版、Desktop版、Stability Matrixなど)
|
||||
- どの画面で、何をしたら、どうなったか
|
||||
- ComfyUIを起動した黒い画面(コンソール)に表示されたエラーメッセージ
|
||||
- ブラウザの開発者ツール(F12キー)の「Console」に表示された赤いエラーメッセージ
|
||||
|
||||
> **注意**
|
||||
> エラーメッセージを貼り付けるときは、パソコンのユーザー名などの個人情報が含まれていないか確認しましょう。
|
||||
|
||||
> **この章のまとめ**
|
||||
> - 困ったら「再読み込み」「更新ボタン」「ComfyUIの再起動」をまず試す
|
||||
> - 赤いノードは、カスタムノードの不足。ComfyUI Managerの Install Missing Custom Nodes で解決
|
||||
> - 設定が反映されないときは、Applyの押し忘れとBatchのチェックの残りを確認
|
||||
> - メモリ不足は、ローカルAIのアンロードや画像サイズの見直しで対処
|
||||
> - 解決しないときは、ヘルプタブやGitHubのIssuesを活用する
|
||||
@@ -0,0 +1,144 @@
|
||||
# 付録
|
||||
|
||||
## 付録A 用語集
|
||||
|
||||
本書に登場する主な言葉を、五十音順・アルファベット順にまとめました。
|
||||
|
||||
### 日本語
|
||||
| 用語 | 意味 | 本書 |
|
||||
| --- | --- | --- |
|
||||
| 意思決定モデル | 質問に「はい」の確率などを数字で答えるAIモデル。画像チェックの判定に使う | 第10章 |
|
||||
| インペイント | 画像の一部(マスクした部分)だけを描き直すこと | 第11章 |
|
||||
| カスタムノード | ComfyUIに後から追加するノード・拡張機能。Workflow Studioもその1つ | 第1章 |
|
||||
| キャンバス | ComfyUIのノード画面で、ノードを並べる作業スペース | 第3章 |
|
||||
| キュー | 生成の予約リスト。順番に処理される | 第1章 |
|
||||
| キーフレーム | Labで「何回目から設定を切り替えるか」を指定したもの | 第5章 |
|
||||
| サンプラー | 画像を描くときのアルゴリズム(euler など) | 第5章 |
|
||||
| シード | 画像のもとになる乱数の種。同じなら、ほぼ同じ画像になる | 第5章 |
|
||||
| セマンティック検索 | 文章や画像の「意味」で画像を探す検索。ギャラリーのSボタンで使う | 第8章 |
|
||||
| スキル | AI TOOLのChatに、役割や答え方を教える指示書。選ぶと得意分野が切り替わる | 第10章 |
|
||||
| スケジューラー | ステップごとの描き込み量の配分のしかた | 第5章 |
|
||||
| スタイル | プロンプトに付け足す雰囲気のテンプレート | 第7章 |
|
||||
| ステップ数 | 描き込みをくり返す回数 | 第5章 |
|
||||
| トリガーワード | LoRAの効果を出すために、プロンプトに入れる言葉 | 第6章 |
|
||||
| ネガティブプロンプト | 描いてほしくないものを書くプロンプト | 第7章 |
|
||||
| ノード | ComfyUIの画面に並ぶ「箱」。1つの処理を受け持つ | 第1章 |
|
||||
| ノードセット | 複数のノードとつながりを、ひとまとまりで保存したもの | 第9章 |
|
||||
| バッジ | ワークフローやモデルに付ける、色付きのラベル | 第4章 |
|
||||
| バッチ生成 | 条件を変えながら、まとめて自動で生成すること | 第5章 |
|
||||
| ハッシュ値 | ファイルの中身から計算される「指紋」のような値。Civitaiでモデルを探すのに使う | 第6章 |
|
||||
| プリセット | ポジティブ・ネガティブのプロンプトをひと組にして保存したもの | 第7章 |
|
||||
| プロンプト | AIに「どんな画像を作ってほしいか」を伝える文章 | 第1章 |
|
||||
| ポジティブプロンプト | 描いてほしいものを書くプロンプト | 第7章 |
|
||||
| ポート番号 | 1台のパソコンの中で、通信先のソフトを区別するための番号 | 第2章 |
|
||||
| マスク | 画像の中で、処理の対象にする部分を指定したもの | 第11章 |
|
||||
| メタデータ | 画像に埋め込まれた、生成時の設定などの情報 | 第8章 |
|
||||
| モデル | 画像を作る「AIの頭脳」にあたるファイル | 第1章 |
|
||||
| ローカルAI | 自分のパソコンの中で動くAI(Ollamaなど) | 第10章 |
|
||||
| ワークフロー | ノードを線でつないだ、処理の流れ全体 | 第1章 |
|
||||
| ワイルドカード | 生成のたびに、プロンプトの一部をランダムに入れ替えるしくみ | 第7章 |
|
||||
|
||||
### アルファベット
|
||||
| 用語 | 意味 | 本書 |
|
||||
| --- | --- | --- |
|
||||
| API形式/UI形式 | ワークフローの保存形式。UI形式はノードの位置なども含み、API形式は処理の内容だけを含む | 第4章 |
|
||||
| Apply | 生成UIで、変更した値をワークフローに反映するボタン | 第5章 |
|
||||
| CFG | プロンプトにどれだけ忠実に従うかの強さ | 第5章 |
|
||||
| Checkpoint | 画像生成の本体となるモデル | 第6章 |
|
||||
| Civitai | 画像生成モデルの共有サイト | 第6章 |
|
||||
| ComfyUI Manager | カスタムノードを検索・インストールするための管理ツール | 第2章 |
|
||||
| Denoise | 元の画像をどれだけ描き変えるかの強さ | 第5章 |
|
||||
| Embedding | 特定の単語に意味を覚えさせた小さなファイル | 第6章 |
|
||||
| I2I(Image to Image) | 画像をもとに、新しい画像を作ること | 第5章 |
|
||||
| JSON | ワークフローの保存に使われるデータ形式 | 第1章 |
|
||||
| LoRA | 絵柄やキャラクターなどを追加で覚えさせる小さなモデル | 第6章 |
|
||||
| OCR | 画像に写っている文字を読み取ること | 第10章 |
|
||||
| Ollama | ローカルAIを手軽に動かせるソフト | 第10章 |
|
||||
| T2I(Text to Image) | 文章(プロンプト)から画像を作ること | 第5章 |
|
||||
| TagSpace | タグ・プロンプト・生成画像を意味の近さで3Dの空間に並べて表示するタブ | 第11章 |
|
||||
| VAE | 画像の色合いや細部を仕上げるモデル | 第6章 |
|
||||
| VLM | 画像を読み取れるAIモデル | 第10章 |
|
||||
| VRAM | GPU(グラフィックボード)のメモリ | 第10章 |
|
||||
| WS Library | ComfyUIのノード画面の横に開く、Workflow Studioのサイドパネル | 第9章 |
|
||||
|
||||
---
|
||||
|
||||
## 付録B キーボード・マウス操作
|
||||
|
||||
### 全体
|
||||
| 操作 | 動き |
|
||||
| --- | --- |
|
||||
| Esc | 開いている画面(モーダル・パネル)を閉じる |
|
||||
| Enter | 名前の変更を確定する/チャットを送信する |
|
||||
| Shift+Enter | チャットで改行する |
|
||||
| ダブルクリック | 詳細画面を開く(ワークフロー・モデルなど) |
|
||||
| Shift+クリック(Wボタン) | Workflow Studioを新しいウィンドウで開く |
|
||||
|
||||
### 生成UI
|
||||
| 操作 | 動き |
|
||||
| --- | --- |
|
||||
| Alt+クリック(Apply) | 値の反映と生成を一度に行う |
|
||||
| Ctrl+↑/↓(プロンプト入力欄) | 選んだ言葉の強調 `(言葉:数値)` を0.05ずつ増減する |
|
||||
| Enter/Shift+Enter(Raw JSONの検索欄) | 次の一致/前の一致へ移動する |
|
||||
|
||||
### ギャラリー
|
||||
| 操作 | 動き |
|
||||
| --- | --- |
|
||||
| Ctrl+クリック | 複数の画像を選ぶ |
|
||||
| Alt+クリック | 画像をメタデータサブタブで開く |
|
||||
| Enter(意味検索がオンのとき) | 検索欄の文章で意味検索を実行する |
|
||||
|
||||
### WS Library
|
||||
| 操作 | 動き |
|
||||
| --- | --- |
|
||||
| ドラッグ&ドロップ | キャンバスのドロップした位置に置く・読み込む |
|
||||
| ダブルクリック | キャンバスの中央付近に置く・読み込む |
|
||||
| Alt+クリック(Nタブ) | ノードのお気に入りをオン/オフする |
|
||||
|
||||
### Image Edit
|
||||
| 操作 | 動き |
|
||||
| --- | --- |
|
||||
| V/B/T/S/G | Select/Draw/Text/Shape/Fill ツールに切り替え |
|
||||
| Ctrl+Z/Ctrl+Y | 元に戻す/やり直す |
|
||||
| マウスホイール | 拡大・縮小 |
|
||||
| Space+ドラッグ | 表示位置を移動する |
|
||||
| Delete | 選んでいるレイヤーを削除する(レイヤーが2つ以上あるとき) |
|
||||
| D/E(Draw中) | 描く/消す |
|
||||
| X(Draw中) | 色1と色2を入れ替える |
|
||||
| [/](Draw中) | ブラシを小さく/大きくする(実際は半角の `[` `]`) |
|
||||
| B(Draw中) | ブラシの選択を開く・閉じる |
|
||||
|
||||
---
|
||||
|
||||
## 付録C 参考リンク
|
||||
|
||||
### Workflow Studio
|
||||
- GitHub(最新版・リリースノート・不具合報告)
|
||||
https://github.com/ketle-man/ComfyUI-Workflow-Studio
|
||||
|
||||
### ComfyUI本体と管理ツール
|
||||
- ComfyUI
|
||||
https://github.com/comfyanonymous/ComfyUI
|
||||
- ComfyUI Manager
|
||||
https://github.com/Comfy-Org/ComfyUI-Manager
|
||||
|
||||
### 本書で紹介した関連ソフト・サービス
|
||||
| 名前 | 用途 | 本書 |
|
||||
| --- | --- | --- |
|
||||
| Civitai(https://civitai.com/) | モデルの入手・情報取得 | 第6章 |
|
||||
| Ollama(https://ollama.com/) | ローカルAI | 第10章 |
|
||||
| LM Studio(https://lmstudio.ai/) | ローカルAI | 第10章 |
|
||||
| Lemonade Server(https://lemonade-server.ai/) | ローカルAI | 第10章 |
|
||||
| Eagle(https://eagle.cool/) | 画像管理ソフト | 第8章 |
|
||||
|
||||
### 一緒に使うと便利なカスタムノード
|
||||
| 名前 | 用途 | 本書 |
|
||||
| --- | --- | --- |
|
||||
| ComfyUI Comic Creator(https://github.com/ketle-man/comfyui-comic-creator) | マンガ制作。ギャラリー・画像生成と連携 | 第11章 |
|
||||
| comfyui-image-feeder(https://github.com/ketle-man/comfyui-image-feeder) | FeederのImage Loopモード | 第5章 |
|
||||
| comfyui-mask-editor-one(https://github.com/ketle-man/comfyui-mask-editor-one) | Image Editの高度なマスク・背景除去 | 第11章 |
|
||||
| ComfyUI-Impact-Pack(https://github.com/ltdrdata/ComfyUI-Impact-Pack) | `{A|B}` 形式のワイルドカード | 第7章 |
|
||||
| ComfyUI-Lora-Manager | LoRAの管理・WS LibraryでのLoRAのまとめ置き | 第9章 |
|
||||
|
||||
> **注意**
|
||||
> リンク先の内容やURLは、変更される場合があります。
|
||||
@@ -0,0 +1,27 @@
|
||||
# おわりに
|
||||
|
||||
最後まで読んでいただき、ありがとうございました。
|
||||
|
||||
ComfyUIは、とても自由で奥の深いソフトです。
|
||||
その自由さゆえに、はじめての方には「どこから手をつければいいのか分からない」ソフトでもあります。
|
||||
Workflow Studioは、その入口を少しでも広げ、
|
||||
「作ること」と「整理すること」をもっと気軽にしたいという思いから生まれました。
|
||||
|
||||
本書で紹介した使い方を、あらためて振り返ってみましょう。
|
||||
|
||||
1. **整理する** - ワークフロー・モデル・プロンプトを、サムネイルやバッジで見分けやすくする
|
||||
2. **作る** - 生成UIで、ノード画面を触らずに画像を生成する
|
||||
3. **貯める** - うまくいったプロンプトや設定を、プリセットやギャラリーに残す
|
||||
4. **再現する** - 画像のメタデータから、同じ設定をすぐに呼び出す
|
||||
5. **広げる** - バッチ生成やローカルAIで、試行錯誤のスピードを上げる
|
||||
|
||||
画像生成が上達するいちばんの近道は、**たくさん試して、うまくいったものを残していく** ことです。
|
||||
Workflow Studioが、その積み重ねを支える道具になれば幸いです。
|
||||
|
||||
Workflow Studioは、これからも機能の追加や改善を続けていきます。
|
||||
新しい機能や変更点は、GitHubのリリースノートでお知らせしています。
|
||||
使ってみての感想や、「こんな機能がほしい」というご要望も、GitHubでお待ちしています。
|
||||
|
||||
あなたの画像生成ライフが、もっと楽しく、もっと豊かなものになりますように。
|
||||
|
||||
ketle-man
|
||||
@@ -0,0 +1,32 @@
|
||||
# Getting Started with ComfyUI Workflow Studio
|
||||
|
||||
Don't Be Afraid of Nodes - Generate Images More Easily and Keep Them Organized
|
||||
|
||||
- Covers: Workflow Studio v0.9.6
|
||||
- Author: ketle-man
|
||||
- (c) 2026 ketle-man
|
||||
|
||||
This is the **text-only edition** (without screenshots) of the Kindle book.
|
||||
Chapter files are in the `chapters/` folder; the whole book in one file is `Workflow_Studio_Manual_v0.9.6_en.md`.
|
||||
Screen examples are omitted, so please use the book together with Workflow Studio's Help tab.
|
||||
|
||||
## Contents
|
||||
|
||||
- [00_Introduction](chapters/00_Introduction.md)
|
||||
- [01_Chapter1_Basics](chapters/01_Chapter1_Basics.md)
|
||||
- [02_Chapter2_Install_and_Launch](chapters/02_Chapter2_Install_and_Launch.md)
|
||||
- [03_Chapter3_Screen_Tour](chapters/03_Chapter3_Screen_Tour.md)
|
||||
- [04_Chapter4_Workflow_Tab](chapters/04_Chapter4_Workflow_Tab.md)
|
||||
- [05_Chapter5_GenerateUI_Part1](chapters/05_Chapter5_GenerateUI_Part1.md)
|
||||
- [05_Chapter5_GenerateUI_Part2](chapters/05_Chapter5_GenerateUI_Part2.md)
|
||||
- [06_Chapter6_Models_Tab](chapters/06_Chapter6_Models_Tab.md)
|
||||
- [07_Chapter7_Prompt_Tab](chapters/07_Chapter7_Prompt_Tab.md)
|
||||
- [08_Chapter8_Gallery_Tab](chapters/08_Chapter8_Gallery_Tab.md)
|
||||
- [09_Chapter9_WS_Library](chapters/09_Chapter9_WS_Library.md)
|
||||
- [10_Chapter10_AI_TOOL](chapters/10_Chapter10_AI_TOOL.md)
|
||||
- [11_Chapter11_More_Features](chapters/11_Chapter11_More_Features.md)
|
||||
- [12_Chapter12_Troubleshooting](chapters/12_Chapter12_Troubleshooting.md)
|
||||
- [13_Appendix](chapters/13_Appendix.md)
|
||||
- [14_Afterword](chapters/14_Afterword.md)
|
||||
|
||||
Whole book: [Workflow_Studio_Manual_v0.9.6_en.md](Workflow_Studio_Manual_v0.9.6_en.md)
|
||||
@@ -0,0 +1,171 @@
|
||||
# Introduction
|
||||
|
||||
"I installed ComfyUI, but the node screen made me freeze."
|
||||
"I downloaded so many workflows from the web that I can't tell which is which."
|
||||
"I want to reuse the settings of an image that turned out well, but I can't find them."
|
||||
|
||||
This book is for people like that. It is an introduction to **ComfyUI-Workflow-Studio** (Workflow Studio from here on).
|
||||
|
||||
---
|
||||
|
||||
## Why is ComfyUI hard?
|
||||
|
||||
ComfyUI is one of the most flexible image-generation AI tools available today.
|
||||
When a new model or technique is announced, ComfyUI is usually the first place you can use it.
|
||||
Even so, many people stumble at the very first step. The reason is that ComfyUI is built on **a completely different way of thinking from ordinary applications**.
|
||||
|
||||
### How it differs from ordinary applications
|
||||
| | Ordinary application | ComfyUI |
|
||||
| --- | --- | --- |
|
||||
| Screen | A fixed screen designed by the developer | You assemble it yourself by connecting nodes (boxes) with lines |
|
||||
| Usage | Press buttons and menus and it works | You must know which nodes to connect, and how |
|
||||
| Adding features | Wait for an update | You add custom nodes made by other people yourself |
|
||||
| Where settings live | Collected in a settings screen | Scattered across many nodes inside the workflow |
|
||||
|
||||
An ordinary application is like a "finished appliance". Switch it on and you can use it right away, the way it was designed.
|
||||
ComfyUI, on the other hand, is "a kit you build from parts".
|
||||
If you know how to build, you can make anything. If you don't, you can make nothing.
|
||||
|
||||
### Freedom, and its side effects
|
||||
The greatest appeal of ComfyUI is this **freedom to customize**.
|
||||
You can combine custom nodes made by developers around the world to build your own flow of processing (a workflow).
|
||||
Advanced workflows made by experienced users are published all over the web, and you can try them right after downloading.
|
||||
|
||||
But freedom has side effects too.
|
||||
|
||||
- **Workflows pile up** - as you keep downloading things to try, you lose track of which is which
|
||||
- **You don't know where to touch** - in a large workflow made by someone else, even changing just the prompt means hunting for the right node
|
||||
- **Your materials get scattered** - models, LoRAs, prompts and generated images end up in separate places, with no tool to manage them
|
||||
- **Trial and error takes effort** - even to compare a few conditions, you must rewrite node values by hand every time
|
||||
|
||||
ComfyUI is excellent as a tool for "building", but
|
||||
it offers almost nothing for "organizing", "reusing" and "trying things quickly".
|
||||
Workflow Studio was made to fill that gap.
|
||||
|
||||
---
|
||||
|
||||
## What makes Workflow Studio different
|
||||
|
||||
### 1. Why a dedicated screen (SPA)? - separating "building" from "using"
|
||||
Workflow Studio is an **independent, dedicated screen** (an SPA: single-page application) that you open from the **W** button in ComfyUI's top menu.
|
||||
|
||||
Building a workflow is best done by trial and error on ComfyUI's node screen.
|
||||
Workflow Studio was created as a screen for **putting the workflows you have built to quick use**.
|
||||
|
||||
For that reason, Workflow Studio thinks of a workflow as three stages, **input, processing and output**, and is designed as follows.
|
||||
|
||||
| Stage | Design idea |
|
||||
| --- | --- |
|
||||
| Input | Make it easy to enter prompts and images |
|
||||
| Processing | Keep changing values down to the fewest possible operations |
|
||||
| Output | Make generated data easy to manage |
|
||||
|
||||
Underlying the design is the **5S** way of thinking (sort, set in order, shine, standardize, sustain) used in manufacturing.
|
||||
The aim is to keep what you need in a state where you can take it out and use it, when you need it, right away.
|
||||
|
||||
The thing that connects the two screens, ComfyUI's node screen and Workflow Studio, is the **WS Library**, which opens beside the node screen.
|
||||
Together with the supporting features, it makes moving between the two screens smooth.
|
||||
|
||||
### 2. Management - everything scattered, in one place
|
||||
| What you can manage | What you can do |
|
||||
| --- | --- |
|
||||
| Workflows | Thumbnail list, sorting by badges and groups, search, a pre-check of whether a workflow will work in GenerateUI |
|
||||
| Models and LoRAs | Lists by type, automatic retrieval of Civitai information (trigger words, sample images) |
|
||||
| Prompts | Save and sort as presets, wildcards, styles |
|
||||
| Generated images and audio | Browsing folder by folder, search by prompt or by "meaning", reading and reproducing embedded settings (audio files are supported too) |
|
||||
|
||||
### 3. Efficiency - try things quickly without touching nodes
|
||||
- **GenerateUI tab** - automatically picks out, from inside a workflow, the items you change often (prompt, model, size and so on) and turns them into an input form. Even large workflows made by others can be used without hunting for nodes
|
||||
- **Batch generation** - automatically runs your trial and error in bulk: "try all my models", "try prompts one after another", "compare samplers"
|
||||
- **Feeder and Lab** - more advanced automation, such as processing many images in order, or switching several conditions step by step
|
||||
|
||||
### 4. Support features - help before and after generation
|
||||
- **Image Edit** - simple layer-based editing, and redrawing parts with a mask (inpainting)
|
||||
- **Local AI integration** - translating prompts from Japanese, creating prompts and tags from images
|
||||
- **Tagger and Video** - automatic tag generation from images, and video generation with simple editing
|
||||
- **TagSpace** - lays out your own prompts, tags and generated images in a 3D space by closeness of meaning, so you can browse it and pick tags
|
||||
|
||||
---
|
||||
|
||||
## A custom node that is worth installing
|
||||
|
||||
For the following reasons, Workflow Studio is a custom node that is **"worth installing just in case"** for everyone who uses ComfyUI.
|
||||
|
||||
- **It is free, and you can install it right away from ComfyUI Manager**
|
||||
- **The basic features need no extra preparation** - everything required is already included with ComfyUI. Extras such as AI and image editing can be prepared when you want to use them
|
||||
- **You don't have to change how you work now** - workflows use ComfyUI's own save folder as it is. You can keep working on the node screen as before
|
||||
- **It gets more useful the more you use it** - start with just browsing a list of workflows or checking the settings of generated images, then widen your use to GenerateUI and batch generation as you get used to it
|
||||
|
||||
It keeps ComfyUI's "freedom" and adds "clarity" and "ease". That is Workflow Studio.
|
||||
|
||||
## What you will learn in this book
|
||||
|
||||
- Installing Workflow Studio and how to read its screens
|
||||
- Organizing the workflows you already have, with thumbnails
|
||||
- Generating your first image without touching the node screen
|
||||
- Managing models, LoRAs and prompts so you can reuse settings that worked
|
||||
- Reading the settings used from a generated image and reproducing them
|
||||
- Translating prompts and reading images with local AI
|
||||
- Common problems and how to fix them
|
||||
|
||||
## What this book does not cover
|
||||
|
||||
- How to install ComfyUI itself
|
||||
(the explanation starts from the point where ComfyUI is already installed and can be launched)
|
||||
- How to build a workflow from scratch by assembling nodes
|
||||
- Detailed explanations of how image-generation AI works, or of model training (such as how to make a LoRA)
|
||||
|
||||
---
|
||||
|
||||
## Who this book is for
|
||||
|
||||
- People who have just installed ComfyUI, or who want to start using it seriously
|
||||
- People who find the node screen hard and want to generate images more easily
|
||||
- People who are struggling to organize growing numbers of workflows, models and prompts
|
||||
|
||||
It is written so that you can follow it if you know basic computer operations (copying files, opening folders, using a browser).
|
||||
|
||||
---
|
||||
|
||||
## Version and environment covered
|
||||
|
||||
- **Workflow Studio**: v0.9.6
|
||||
- **ComfyUI**: the latest version at the time of writing
|
||||
- **OS**: Windows (screen examples are from Windows)
|
||||
|
||||
Workflow Studio is under active development, so
|
||||
depending on the version, the look of the screens and the positions of buttons may differ from this book.
|
||||
For features that have changed significantly, also check Workflow Studio's **Help** tab and the release notes on GitHub.
|
||||
|
||||
---
|
||||
|
||||
## Notation used in this book
|
||||
|
||||
| Notation | Meaning |
|
||||
| --- | --- |
|
||||
| **Bold** | Button names and item names shown on screen |
|
||||
| "GenerateUI" | The name as shown on screen |
|
||||
| `ComfyUI/models/` | The location of a folder or file. For how to read this for your environment, see Chapter 2, section 2-6 |
|
||||
| `Ctrl + Z` | A keyboard operation. "+" means pressing the keys at the same time |
|
||||
|
||||
> **Tip**
|
||||
> Information that is handy to know.
|
||||
|
||||
> **Caution**
|
||||
> Information to be careful about, because getting it wrong can lose data or stop things from working.
|
||||
|
||||
### About the display language
|
||||
Workflow Studio supports English, Japanese and Chinese. This English edition explains things using the **English display**.
|
||||
You can change the display language in the Settings tab (Chapter 2, section 2-5).
|
||||
|
||||
---
|
||||
|
||||
## How to read this book
|
||||
|
||||
If you are new, read **Chapters 1 to 5** in order and try things by hand.
|
||||
Once you have generated your first image in Chapter 5, you have the basics of Workflow Studio.
|
||||
|
||||
From Chapter 6 onward, feel free to read from whichever place you need.
|
||||
When in trouble, use the troubleshooting in Chapter 12 and the glossary in the appendix.
|
||||
|
||||
Now, let's start generating images with Workflow Studio, more easily and more enjoyably.
|
||||
@@ -0,0 +1,146 @@
|
||||
# Chapter 1 Basics of ComfyUI and Workflow Studio
|
||||
|
||||
This chapter sorts out the ideas and terms worth knowing before you start operating anything.
|
||||
You don't need to read it at the computer. Read it casually on your commute or in spare moments.
|
||||
|
||||
---
|
||||
|
||||
## 1-1 What is ComfyUI?
|
||||
|
||||
ComfyUI is free software for running image-generation AI on your own computer.
|
||||
It supports many image-generation models, such as Stable Diffusion and FLUX.
|
||||
|
||||
The biggest feature of ComfyUI is that **you build the flow of processing by connecting "boxes" with "lines"**.
|
||||
|
||||
"A box that loads the model" -> "a box that takes the prompt" -> "a box that makes the image" -> "a box that saves it"...
|
||||
When you connect boxes with lines like this, processing happens in that order.
|
||||
|
||||
This approach has big advantages.
|
||||
|
||||
- Everything about the processing is visible, so you can fine-tune it
|
||||
- Even when a new technique appears, you can try it just by adding a box
|
||||
- You can save a flow you have built and reuse it as many times as you like
|
||||
|
||||
On the other hand, for someone touching it for the first time, it is also a screen where "you don't know where to touch".
|
||||
**Workflow Studio**, introduced in this book, is exactly a tool for softening that "hard-to-understand" quality.
|
||||
|
||||
---
|
||||
|
||||
## 1-2 Five terms to remember
|
||||
|
||||
The minimum set of terms worth knowing for using ComfyUI is these five.
|
||||
|
||||
### 1. Node
|
||||
The "boxes" arranged on the screen.
|
||||
One node handles one job, for example "load a model" or "save an image".
|
||||
A node has entrances (inputs) and exits (outputs), and passes data along through connecting lines.
|
||||
|
||||
### 2. Workflow
|
||||
The "whole flow of processing" made by connecting nodes with lines.
|
||||
To use a cooking analogy, nodes are tasks such as "chop" and "stir-fry", and the workflow is the "recipe".
|
||||
A workflow can be saved as a file in a format called JSON.
|
||||
|
||||
> **Tip**
|
||||
> Images made in ComfyUI usually have the workflow information embedded in them.
|
||||
> If you drag such an image onto the ComfyUI screen, you can recall the same workflow.
|
||||
|
||||
### 3. Model
|
||||
The file that acts as the "AI brain" that makes images. They are typically large, from a few GB to tens of GB.
|
||||
The main kinds are as follows (Chapter 6 explains them in detail).
|
||||
|
||||
| Kind | In a phrase |
|
||||
| --- | --- |
|
||||
| Checkpoint | The model that forms the core of image generation |
|
||||
| LoRA | A small add-on model that teaches an art style or a character |
|
||||
| VAE | The model in charge of finishing the colors and fine details of an image |
|
||||
|
||||
### 4. Prompt
|
||||
The text that tells the AI "what kind of image you want". It is what people call a "spell".
|
||||
There are two kinds: the **positive prompt**, where you write what you want drawn, and
|
||||
the **negative prompt**, where you write what you do not want drawn.
|
||||
|
||||
### 5. Queue
|
||||
The "reservation list for generation".
|
||||
In ComfyUI, pressing the generate button first puts a reservation in the queue, and the reservations are processed in order.
|
||||
If you reserve many images, they are generated in bulk while you are away from your seat.
|
||||
|
||||
---
|
||||
|
||||
## 1-3 Where beginners get stuck in ComfyUI
|
||||
|
||||
You installed ComfyUI, but have you stopped at any of these points?
|
||||
|
||||
1. **Workflows pile up and you can't tell which is which**
|
||||
As you keep saving workflows you found online, file names alone stop being enough to tell them apart.
|
||||
|
||||
2. **Hunting for values on the node screen every time is tiring**
|
||||
You only want to change the prompt or seed value, yet you have to find the right node inside a large workflow.
|
||||
|
||||
3. **Models and prompts are managed in a scattered way**
|
||||
It is easy to lose track of where you put which model, or what prompt worked last time.
|
||||
|
||||
4. **You can't reproduce the settings of an image you made before**
|
||||
Even when you wonder "which settings made that image?", you may not know how to look it up.
|
||||
|
||||
None of these is really a lack of ComfyUI features. The cause is **a lack of "organization" and of an "entrance"**.
|
||||
|
||||
---
|
||||
|
||||
## 1-4 What Workflow Studio can do
|
||||
|
||||
Workflow Studio is an **extension (a custom node)** that you add to ComfyUI.
|
||||
It adds "a dedicated screen for management and generation" inside ComfyUI.
|
||||
|
||||
Workflow Studio answers the four sticking points above as follows.
|
||||
|
||||
| Sticking point | Workflow Studio's solution | Chapter |
|
||||
| --- | --- | --- |
|
||||
| Can't tell workflows apart | A thumbnail list, badges and groups, search | Chapter 4 |
|
||||
| Hunting for values on the node screen is tiring | The GenerateUI tab shows only the items you need as a form | Chapter 5 |
|
||||
| Models and prompts are scattered | Managed together in the Models tab and the Prompt tab | Chapters 6 and 7 |
|
||||
| Can't reproduce settings | Check an image's metadata in the Gallery and send it to the canvas | Chapter 8 |
|
||||
|
||||
In addition, a side panel called the **WS Library** is added beside ComfyUI's node screen,
|
||||
letting you place models and prompts onto the node screen by drag and drop (Chapter 9).
|
||||
|
||||
If you prepare AI that runs locally (such as Ollama or LM Studio),
|
||||
you can also use AI support such as prompt translation and tag generation from images (Chapter 10).
|
||||
|
||||
> **Tip**
|
||||
> Workflow Studio is not software that replaces ComfyUI.
|
||||
> It is ComfyUI that makes the images; Workflow Studio plays the role of its "control panel" and "storage shelf".
|
||||
> For that reason, it cannot be used unless ComfyUI is running.
|
||||
|
||||
### The screens can be used in your language
|
||||
Workflow Studio supports English, Japanese and Chinese.
|
||||
This edition explains things using the English display.
|
||||
|
||||
---
|
||||
|
||||
## 1-5 How this book proceeds
|
||||
|
||||
This book is meant to be read in the following order.
|
||||
|
||||
1. **Prepare** (Chapters 2 and 3)
|
||||
Install it and learn how to read the screens.
|
||||
|
||||
2. **Organize** (Chapter 4)
|
||||
Make the workflows you already have viewable as a list.
|
||||
|
||||
3. **Create** (Chapter 5)
|
||||
Generate your first image without touching the node screen.
|
||||
If you read this far, you can use the basics of Workflow Studio.
|
||||
|
||||
4. **Collect and review** (Chapters 6 to 8)
|
||||
Manage models, prompts and generated images, and reuse settings that worked.
|
||||
|
||||
5. **Expand** (Chapters 9 to 11)
|
||||
Bring in handy features such as the side panel and AI support, as you need them.
|
||||
|
||||
When in trouble, see the troubleshooting in Chapter 12 and the glossary in the appendix.
|
||||
|
||||
> **Summary of this chapter**
|
||||
> - ComfyUI is software that makes images with a workflow of connected nodes (boxes)
|
||||
> - The five terms to remember are "node", "workflow", "model", "prompt" and "queue"
|
||||
> - Workflow Studio is an extension that adds a "storage shelf" and an "easy control panel" to ComfyUI
|
||||
> - First, aim for the "first image" in Chapter 5
|
||||
@@ -0,0 +1,254 @@
|
||||
# Chapter 2 Installation and Launch
|
||||
|
||||
In this chapter we add Workflow Studio to ComfyUI and go as far as opening its screen for the first time.
|
||||
It assumes that ComfyUI itself is already installed and can be launched.
|
||||
|
||||
---
|
||||
|
||||
## 2-1 What you need
|
||||
|
||||
### Required
|
||||
| What you need | Description |
|
||||
| --- | --- |
|
||||
| ComfyUI | A recent version is fine. Because it uses a feature that places buttons in the top menu, a fairly new version (frontend v1.33.9 or later) is recommended |
|
||||
| Python 3.10 or later | The one bundled with ComfyUI is fine |
|
||||
| A web browser | Such as Chrome or Edge: the browser in which you open the ComfyUI screen |
|
||||
|
||||
The basic features of Workflow Studio work with no extra preparation as long as ComfyUI is running.
|
||||
|
||||
### Later, as needed
|
||||
The following are needed only when you use particular features. You can ignore them at first.
|
||||
|
||||
- **Ollama, LM Studio and similar** - AI support features such as prompt translation and AI chat (Chapter 10).
|
||||
**Ollama** is also needed for local semantic search in the Gallery (Chapter 8) and for the TagSpace tab (Chapter 11)
|
||||
- **Eagle** - a feature that automatically saves generated images to the image-management software Eagle (Chapter 8)
|
||||
- **Extra Python packages** - Tagger (tag generation from images), PSD export and the like (Chapter 11)
|
||||
|
||||
> **Tip**
|
||||
> It is not the case that "you can't use it unless you have everything".
|
||||
> Start by installing only the main part, and add things when features you want to use come up.
|
||||
|
||||
---
|
||||
|
||||
## 2-2 Install with ComfyUI Manager (recommended)
|
||||
|
||||
**ComfyUI Manager** is a management tool that lets you search for and install custom nodes (extensions) from the screen.
|
||||
Recent versions of ComfyUI often include it from the start, and it is the easiest method.
|
||||
|
||||
1. Start ComfyUI and open its screen in the browser.
|
||||
2. Click the **"Manager"** button in the top menu.
|
||||
|
||||
3. Click **"Custom Nodes Manager"**.
|
||||
4. Type **`Workflow Studio`** in the search box.
|
||||
5. Click **"Install"** on **ComfyUI-Workflow-Studio** in the list.
|
||||
|
||||
6. When the installation finishes, **restart ComfyUI** following the on-screen guidance.
|
||||
|
||||
> **Caution**
|
||||
> ComfyUI loads extensions only once, when it starts.
|
||||
> Always restart ComfyUI after installing. Reloading the browser alone will not take effect.
|
||||
|
||||
---
|
||||
|
||||
## 2-3 Install manually (git clone)
|
||||
|
||||
If ComfyUI Manager is not available, or if you are comfortable with Git, you can also install manually.
|
||||
You use a screen where you type commands (on Windows, "Command Prompt" or "Terminal").
|
||||
|
||||
1. Move to the **`custom_nodes`** folder inside the ComfyUI folder.
|
||||
|
||||
```
|
||||
cd ComfyUI/custom_nodes
|
||||
```
|
||||
|
||||
2. Type the following command to download Workflow Studio.
|
||||
|
||||
```
|
||||
git clone https://github.com/ketle-man/ComfyUI-Workflow-Studio.git
|
||||
```
|
||||
|
||||
3. If a **`ComfyUI-Workflow-Studio`** folder now exists inside `custom_nodes`, it worked.
|
||||
4. Restart ComfyUI.
|
||||
|
||||
> **Tip**
|
||||
> If the `git` command is not available, you first need to install Git (for example Git for Windows).
|
||||
> If you are unsure, the ComfyUI Manager method in 2-2 is recommended.
|
||||
|
||||
---
|
||||
|
||||
## 2-4 Launching
|
||||
|
||||
### Open it from the W button
|
||||
When you restart ComfyUI, a **"W"** button has been added to the menu at the top of the screen.
|
||||
This is the button that opens Workflow Studio.
|
||||
|
||||
- **Click** - Workflow Studio opens in a new tab.
|
||||
- **Shift + click** - It opens in a new window. Handy when you want to use it side by side with the ComfyUI screen.
|
||||
|
||||
A **camera button** has also been added near the W button.
|
||||
It is the button for saving a workflow screen as a thumbnail (you use it in Chapter 4).
|
||||
|
||||
### How addresses and port numbers work
|
||||
When you press the W button, the address of Workflow Studio appears in the browser's address bar.
|
||||
Knowing how to read this address lets you open it directly from a bookmark and track down causes when something goes wrong.
|
||||
|
||||
The address is made of the following three parts.
|
||||
|
||||
| Part | Example | Meaning |
|
||||
| --- | --- | --- |
|
||||
| Host | `127.0.0.1` | Which computer to connect to. `127.0.0.1` (or `localhost`) is a special address meaning "this computer" |
|
||||
| Port number | `8188` | Which piece of software on that computer to connect to |
|
||||
| Path | `/wfm` | Which page inside that software to open |
|
||||
|
||||
Joining these three in the form "`host:port-number/path`" gives the address of Workflow Studio.
|
||||
|
||||
#### What is a port number?
|
||||
Many pieces of software on one computer communicate at the same time.
|
||||
The **port number** is what is used to distinguish which software a communication is meant for.
|
||||
|
||||
To use an apartment building as an analogy, the host (`127.0.0.1`) is the "address of the building" and the port number is the "room number".
|
||||
Even in the same building, if you get the room number wrong, you will not reach the person you want.
|
||||
|
||||
ComfyUI listens on a port number decided when it starts.
|
||||
Commonly used numbers are as follows.
|
||||
|
||||
| Kind of ComfyUI / how it was started | Commonly used port number |
|
||||
| --- | --- |
|
||||
| Portable version or manual install (default settings) | 8188 |
|
||||
| ComfyUI Desktop (the desktop app version) | 8000 |
|
||||
| When the `--port` startup option is given | The number you specified |
|
||||
|
||||
If you use a launcher such as Stability Matrix, the number may also change depending on the launcher's settings.
|
||||
|
||||
#### Checking your own port number
|
||||
The most reliable way is to **look at the address bar of the browser in which you have ComfyUI open right now**.
|
||||
The number after `127.0.0.1:` or `localhost:` is the port number.
|
||||
|
||||
The black screen (console) shown when you start ComfyUI also displays a line such as
|
||||
`To see the GUI go to: http://127.0.0.1:XXXX`.
|
||||
|
||||
#### Opening it by typing the address directly
|
||||
If you know the port number, you can open Workflow Studio without the W button.
|
||||
Just add **`/wfm`** to the end of ComfyUI's address.
|
||||
|
||||
- ComfyUI is open at `127.0.0.1:8188` -> Workflow Studio is at `127.0.0.1:8188/wfm`
|
||||
- ComfyUI is open at `127.0.0.1:8000` -> Workflow Studio is at `127.0.0.1:8000/wfm`
|
||||
|
||||
If you use it often, bookmarking this address is handy.
|
||||
|
||||
> **Caution**
|
||||
> When you open it from a bookmark, "Send to Canvas", which sends a workflow directly to ComfyUI's canvas, cannot be used.
|
||||
> Instead, that workflow appears in ComfyUI's side panel (the WS Library), and you drag it onto the canvas yourself (Chapters 4 and 9).
|
||||
> If you use it while going back and forth with the ComfyUI screen, opening it from the W button is recommended.
|
||||
|
||||
> **Tip**
|
||||
> Workflow Studio runs as a part of ComfyUI, so it uses the same port number as ComfyUI.
|
||||
> There is no port number dedicated to Workflow Studio.
|
||||
|
||||
---
|
||||
|
||||
## 2-5 Changing the display language
|
||||
|
||||
Workflow Studio is displayed in **English** at first. You can switch it to Japanese or Chinese as follows.
|
||||
|
||||
1. Open **"Settings"** from the tabs at the top.
|
||||
2. In the **"UI Language"** field, choose the language you want.
|
||||
|
||||
3. After a notice that the language was changed, the page reloads automatically and switches to the new display language.
|
||||
|
||||
If you switch to Japanese, the tab names change as follows (some stay in English).
|
||||
|
||||
| English display | Japanese display |
|
||||
| --- | --- |
|
||||
| Workflow | ワークフロー |
|
||||
| GenerateUI | 生成UI |
|
||||
| Gallery | ギャラリー |
|
||||
| Prompt | プロンプト |
|
||||
| Models | モデル |
|
||||
| Nodes | ノード |
|
||||
| Settings | 設定 |
|
||||
| Help | ヘルプ |
|
||||
| AI TOOL / Tagger / Image Edit / Video | (stay in English) |
|
||||
|
||||
> **Tip**
|
||||
> The language setting is saved **per browser** you use.
|
||||
> If you open it from another browser or another computer, set it again.
|
||||
|
||||
The **"Summary Language"** field in the same place is the language used when AI creates descriptions of workflows (Chapter 10). You do not need to change it for now.
|
||||
|
||||
---
|
||||
|
||||
## 2-6 Folder locations in each environment
|
||||
|
||||
There are several ways to install ComfyUI. Depending on how it was installed, the folder locations differ slightly.
|
||||
In this book, folder locations are written in a form **starting from `ComfyUI/`**.
|
||||
Read it as the "place that corresponds to `ComfyUI/`" in the table below, to match your environment.
|
||||
|
||||
### How this book writes it, and where it is in each environment
|
||||
| Notation in this book | Contents | Portable version | ComfyUI Desktop | Stability Matrix |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `ComfyUI/` | ComfyUI's main folder | `ComfyUI_windows_portable/ComfyUI/` | The folder you chose at install time (by default `ComfyUI` inside "Documents") | `(data folder)/Packages/ComfyUI/` |
|
||||
| `ComfyUI/custom_nodes/` | Custom nodes (Workflow Studio too) | `ComfyUI/custom_nodes/` | `ComfyUI/custom_nodes/` | `ComfyUI/custom_nodes/` |
|
||||
| `ComfyUI/models/` | Models | `ComfyUI/models/` | `ComfyUI/models/` | `(data folder)/Models/` (shared by all packages) |
|
||||
| `ComfyUI/output/` | Generated images | `ComfyUI/output/` | `ComfyUI/output/` | `(data folder)/Images/` |
|
||||
| `ComfyUI/user/default/workflows/` | Saved workflows | `ComfyUI/user/default/workflows/` | `ComfyUI/user/default/workflows/` | `ComfyUI/user/default/workflows/` |
|
||||
| ComfyUI's Python | Where extra packages are installed | `ComfyUI_windows_portable/python_embeded/python.exe` | `ComfyUI/.venv/Scripts/python.exe` | `ComfyUI/venv/Scripts/python.exe` |
|
||||
| Default port number | See 2-4 | 8188 | 8000 | 8188 |
|
||||
|
||||
> **Tip**
|
||||
> `ComfyUI/` in the table refers to the "place that corresponds to `ComfyUI/`" in each environment.
|
||||
> On Windows, path separators are shown as `\` instead of `/`.
|
||||
|
||||
### Portable version
|
||||
Everything is inside the `ComfyUI_windows_portable` folder created by extracting the downloaded ZIP file.
|
||||
You launch it with `run_nvidia_gpu.bat` or similar inside the folder.
|
||||
For **Python**, you use the one inside the `python_embeded` folder dedicated to ComfyUI (Chapter 11, section 11-2).
|
||||
|
||||
### ComfyUI Desktop
|
||||
This is the app version installed with an installer. At first launch, you choose the folder in which to put data.
|
||||
If you forget where the folder is, you can check it with the app's menu item that opens the folder ("Open Folder" or similar).
|
||||
The default port number is **8000**, so be careful when typing the address directly (2-4).
|
||||
|
||||
### Stability Matrix
|
||||
This is a launcher that manages several image-generation programs together.
|
||||
Inside the **data folder** you chose first (for example `StabilityMatrix/Data/`), things are separated as follows.
|
||||
|
||||
- **ComfyUI itself** - `Data/Packages/ComfyUI/`
|
||||
- **Models** - folders by type inside `Data/Models/` (`StableDiffusion` for Checkpoints, `Lora` for LoRAs, and so on). They are shared with other programs
|
||||
- **Generated images** - inside `Data/Images/`
|
||||
|
||||
> **Caution**
|
||||
> In Stability Matrix, the folders for models and images are **outside ComfyUI's main folder**.
|
||||
> Where this book says "put it in `ComfyUI/models/checkpoints`", put it in Stability Matrix's shared model folder (such as `Data/Models/StableDiffusion`).
|
||||
> If images do not appear in the Gallery, check that the "Gallery Output Folder" in the Settings tab points inside `Data/Images/`.
|
||||
|
||||
> **Tip**
|
||||
> Folder names and structure can change with each program's version updates.
|
||||
> If you cannot find something, also check each program's official documentation.
|
||||
|
||||
---
|
||||
|
||||
## 2-7 If it does not start properly
|
||||
|
||||
### The W button does not appear
|
||||
- **Did you restart ComfyUI?** Reloading the browser alone does not take effect.
|
||||
- **Is the install location correct?** Check that the folder exists at `ComfyUI/custom_nodes/ComfyUI-Workflow-Studio`.
|
||||
If there is another folder with the same name inside it (a doubled folder), it will not be loaded.
|
||||
- **Is your ComfyUI version old?** Try updating the main program from ComfyUI Manager or similar.
|
||||
|
||||
### The page does not open, or "cannot connect" is shown
|
||||
- **Is ComfyUI running?** Workflow Studio runs inside ComfyUI, so you cannot open it if you quit ComfyUI.
|
||||
- **Is the port number right?** Check ComfyUI's port number using the method in 2-4.
|
||||
For example, if you use ComfyUI Desktop but type `8188`, it will not connect.
|
||||
|
||||
### An error appears in the console at startup
|
||||
Check whether the black screen shown when you start ComfyUI displays any error about `ComfyUI-Workflow-Studio`.
|
||||
Noting the content of the error will help with the troubleshooting in Chapter 12, and when asking questions on GitHub.
|
||||
|
||||
> **Summary of this chapter**
|
||||
> - The easy way to install is to search for "Workflow Studio" in ComfyUI Manager
|
||||
> - Always restart ComfyUI after installing
|
||||
> - Open it with the "W" button in the top menu (Shift + click for a separate window)
|
||||
> - The address is "host:port-number/wfm". You can check the port number in the address bar where ComfyUI is open
|
||||
> - Switch the language in the Settings tab with "UI Language"
|
||||
> - Folder locations differ by environment (portable version, Desktop, Stability Matrix). Read `ComfyUI/` in this book accordingly
|
||||
@@ -0,0 +1,146 @@
|
||||
# Chapter 3 Reading the Screens
|
||||
|
||||
Workflow Studio has many tabs, but you do not need to memorize all of them from the start.
|
||||
In this chapter you will get a rough idea of "what each tab is for",
|
||||
and check the roles of the buttons and the side panel added to the ComfyUI side.
|
||||
|
||||
---
|
||||
|
||||
## 3-1 The tabs and their roles
|
||||
|
||||
When you open Workflow Studio, tabs are lined up in a row across the top of the screen.
|
||||
|
||||
From the left, there are the following tabs.
|
||||
It is enough to learn the tabs marked with a star under "Often used" first.
|
||||
|
||||
| Tab | What it is for | Often used | Chapter in this book |
|
||||
| --- | --- | :---: | --- |
|
||||
| Workflow | Listing and organizing saved workflows | * | Chapter 4 |
|
||||
| Nodes | Listing nodes and registering favorites | | Chapter 11 |
|
||||
| Models | Listing and organizing models such as Checkpoints and LoRAs | * | Chapter 6 |
|
||||
| GenerateUI | Generating images without touching the node screen | * | Chapter 5 |
|
||||
| Prompt | Saving and sorting prompts, AI assistance | * | Chapter 7 |
|
||||
| Gallery | Browsing generated images, checking their settings | * | Chapter 8 |
|
||||
| Image Edit | Simple image editing, making masks | | Chapter 11 |
|
||||
| Video | Video generation and video editing | | Chapter 11 |
|
||||
| Tagger | Automatically generating tags (prompts) from images | | Chapter 11 |
|
||||
| TagSpace | Showing tags, prompts and generated images in 3D by closeness of meaning, and picking tags | | Chapter 11 |
|
||||
| Settings | Language, theme, folders and other settings | | This chapter, Chapter 11 |
|
||||
| Help | Feature list, shortcuts, troubleshooting | | This chapter |
|
||||
| AI TOOL | Translation, chat, image analysis and text reading (OCR) with local AI | | Chapter 10 |
|
||||
|
||||
### Think of the tabs in three groups: "organize", "create" and "support"
|
||||
If the number of tabs makes you lose your way, it helps to think of them in these three groups.
|
||||
|
||||
- **Organize** - Workflow / Nodes / Models / Prompt / Gallery
|
||||
Tabs that list your materials so they are easy to find.
|
||||
- **Create** - GenerateUI / Image Edit / Video
|
||||
Tabs for actually making images and videos, or touching them up.
|
||||
- **Support** - AI TOOL / Tagger / TagSpace / Settings / Help
|
||||
Tabs that help with work in other tabs, or hold overall settings.
|
||||
|
||||
> **Tip**
|
||||
> The tabs are connected to each other.
|
||||
> For example, you can load a workflow picked in the Workflow tab into GenerateUI,
|
||||
> or recall a prompt saved in the Prompt tab from GenerateUI.
|
||||
|
||||
### The Help tab
|
||||
The first thing to open when in trouble is the **Help** tab.
|
||||
A list of topics is lined up on the left, and clicking one shows the explanation on the right.
|
||||
|
||||
- The feature list (an overview of each tab's features)
|
||||
- Keyboard shortcuts
|
||||
- Troubleshooting
|
||||
- Support (links to GitHub and so on)
|
||||
|
||||
It is also useful when, reading this book, you wonder "what was this button?".
|
||||
|
||||
---
|
||||
|
||||
## 3-2 Buttons added to the ComfyUI side
|
||||
|
||||
When you install Workflow Studio, **three buttons** are added to the menu at the top of ComfyUI's screen.
|
||||
|
||||
| Button | Name | Role |
|
||||
| --- | --- | --- |
|
||||
| 1. W | Open Workflow Studio | Opens Workflow Studio in a new tab. Shift + click opens a new window (Chapter 2) |
|
||||
| 2. Camera | Canvas snapshot | Saves the current node screen as an image and makes it the workflow's thumbnail (Chapter 4) |
|
||||
| 3. An icon of lined-up squares | WS Library | Opens and closes a side panel beside the node screen (3-3) |
|
||||
|
||||
When you hover the mouse over a button, a description is shown.
|
||||
|
||||
> **Tip**
|
||||
> The main part of Workflow Studio (the screen with the row of tabs) and ComfyUI's node screen open in **separate browser tabs**.
|
||||
> The basic style is to use the two screens back and forth: "organizing and generating in Workflow Studio",
|
||||
> "detailed building on ComfyUI's node screen".
|
||||
|
||||
---
|
||||
|
||||
## 3-3 The side panel "WS Library"
|
||||
|
||||
When you press button 3, a panel called the **WS Library (Workflow Studio Library)** opens beside ComfyUI's node screen.
|
||||
|
||||
The WS Library is **a shelf for using the materials you organized in Workflow Studio right away on the node screen**.
|
||||
Single-letter tabs are lined up at the top of the panel (hover the mouse over one to see its proper name).
|
||||
|
||||
| Tab | Name | What you can do |
|
||||
| --- | --- | --- |
|
||||
| W | Workflows | Drag a workflow to load it onto the canvas |
|
||||
| N | Nodes | Place favorite nodes and node sets on the canvas |
|
||||
| P | Prompts | Place or copy saved prompts onto the canvas |
|
||||
| M | Models | Drag a model to place it onto the canvas together with a loader node |
|
||||
| I | Information | Drop an image or workflow file to inspect its contents (the models and prompts used) |
|
||||
| A | AI TOOL | Use AI features such as translation and chat while staying on the node screen |
|
||||
|
||||
For example, when you drag a model from the M tab onto the canvas, a node that loads that model is placed automatically.
|
||||
It saves the trouble of finding a node in a list, placing it, choosing the file name, and so on.
|
||||
|
||||
Chapter 9 explains how to use it in detail. For now, it is enough to remember only that "you can bring out a shelf of materials beside the node screen".
|
||||
|
||||
---
|
||||
|
||||
## 3-4 Theme and appearance settings
|
||||
|
||||
The look of Workflow Studio can be changed to your liking in the **Settings** tab.
|
||||
Because it is a tool you use for long periods, a color scheme that is easy on the eyes and a readable text size are recommended.
|
||||
|
||||
### Theme
|
||||
From the **"Theme"** field you can choose the color scheme of the whole screen. The default is the dark scheme "Deep Ocean Dark".
|
||||
|
||||
| Example theme | Feel |
|
||||
| --- | --- |
|
||||
| Deep Ocean Dark (default) | Dark blue. Images are easy to see |
|
||||
| Light Minimalist (clean) | White-based, bright and simple |
|
||||
| Pastel Dream (pastel) | Soft pastel tones |
|
||||
| Corporate Trust (for business) | Calm white and blue |
|
||||
|
||||
Besides these, there are 13 themes in all, including pop, cyberpunk and retro.
|
||||
|
||||
> **Tip**
|
||||
> When checking the colors of generated images, a darker theme makes colors easier to tell apart.
|
||||
> If you can't decide, try using the default for now.
|
||||
|
||||
### Customize
|
||||
Opening **"Customize"** lets you fine-tune the chosen theme further.
|
||||
|
||||
- **Color Override** - change colors such as background, text and accent individually
|
||||
- **Background Pattern** - add patterns such as stripes or dots to the background
|
||||
- **Font** - change the typeface (Japanese fonts such as Zen Maru Gothic and BIZ UDPGothic can also be chosen)
|
||||
|
||||
When you finish adjusting, press **"Apply & Save"**.
|
||||
To go back, press **"Reset Customization"**.
|
||||
|
||||
### Text Size
|
||||
With the **"Text Size"** field you can change the size of the text across the whole screen.
|
||||
If the text feels too small to read, make it bigger here.
|
||||
|
||||
### The look of the WS Library
|
||||
The colors of the WS Library (3-3) can be set separately from the **gear button** inside the panel.
|
||||
You can adjust the background and text colors to match the colors of the ComfyUI screen.
|
||||
|
||||
> **Summary of this chapter**
|
||||
> - Thinking of the tabs in three groups, "organize", "create" and "support", makes them easy to follow
|
||||
> - For now, it is enough to learn five: Workflow, Models, GenerateUI, Prompt and Gallery
|
||||
> - Three buttons, "W", "camera" and "WS Library", are added to the top of ComfyUI
|
||||
> - The WS Library is a shelf of materials you can bring out beside the node screen
|
||||
> - The look can be adjusted with the Settings tab's Theme, Customize and Text Size
|
||||
@@ -0,0 +1,306 @@
|
||||
# Chapter 4 The Workflow Tab - Organizing the Workflows You Made
|
||||
|
||||
The Workflow tab is the first thing shown when you open Workflow Studio, a kind of "front door".
|
||||
In this chapter you will learn how to make the workflows you already have viewable as a list,
|
||||
and how to organize them so they are easy to find later.
|
||||
|
||||
---
|
||||
|
||||
## 4-1 How workflows are listed automatically
|
||||
|
||||
When you open the Workflow tab, some workflows may already be lined up.
|
||||
This is because Workflow Studio automatically reads ComfyUI's workflow save folder.
|
||||
|
||||
A workflow you "Save" on ComfyUI's node screen is normally saved in the following folder.
|
||||
|
||||
```
|
||||
ComfyUI/user/default/workflows/
|
||||
```
|
||||
|
||||
Workflow Studio lists the workflows inside this folder.
|
||||
In other words, **workflows saved in ComfyUI line up in the Workflow tab without your doing anything**.
|
||||
|
||||
> **Tip**
|
||||
> If a workflow you just saved in ComfyUI does not appear in the list,
|
||||
> press the **"Refresh"** button on the toolbar. It reloads to the latest state.
|
||||
|
||||
> **Tip**
|
||||
> The folder that is read can be changed with the **"Workflow Data Folder"** setting in the Settings tab.
|
||||
> Unless you have a reason, leaving it as it is causes no problem.
|
||||
|
||||
---
|
||||
|
||||
## 4-2 Reading the screen and switching the display
|
||||
|
||||
The Workflow tab is divided into three main parts.
|
||||
|
||||
| No. | Place | Role |
|
||||
| --- | --- | --- |
|
||||
| 1 | Toolbar (top) | Search, filtering, sorting, various buttons |
|
||||
| 2 | List (center) | Workflows lined up as cards or in a table |
|
||||
| 3 | Side panel (right) | Shows the thumbnail and contents of the selected workflow |
|
||||
|
||||
### Thumbnail view and table view
|
||||
With the switch buttons on the toolbar you can change how the list is displayed.
|
||||
|
||||
- **Thumbnail** - lines them up as cards with images. Handy when you want to find things by how they look.
|
||||
- **Table** - lines them up in a table. Handy when you want to find one among many workflows by name.
|
||||
|
||||
### Click and double-click
|
||||
Workflows in the list behave differently depending on how you click.
|
||||
|
||||
| Operation | What happens |
|
||||
| --- | --- |
|
||||
| Click | Shows the contents in the right-hand side panel (the workflow becomes "selected") |
|
||||
| Double-click | Opens the detail screen (editing badges, tags and memo; explained in 4-4) |
|
||||
|
||||
### The side panel
|
||||
When you click a workflow, the following three tabs appear in the right-hand side panel.
|
||||
|
||||
- **Thumbnail** - shows the workflow's image large
|
||||
- **JSON** - shows the contents (JSON data) of the workflow with color coding. The "Copy" button copies it all
|
||||
- **Groups** - sorts the workflow into groups (explained in 4-4)
|
||||
|
||||
Below the workflow name, the **format of the workflow** (UI format, API format and so on) and
|
||||
the **check result** of whether it can be used in GenerateUI are shown (explained in 4-7).
|
||||
|
||||
---
|
||||
|
||||
## 4-3 Taking a thumbnail with the camera button
|
||||
|
||||
A workflow that you only saved in ComfyUI has no thumbnail image, and can be hard to tell apart in the list.
|
||||
That is where the **camera button** (canvas snapshot) added to ComfyUI's top menu comes in.
|
||||
|
||||
### How to take a thumbnail
|
||||
1. On ComfyUI's node screen, open the workflow you want to make a thumbnail of.
|
||||
2. Adjust the screen position and zoom so that the whole workflow is easy to see.
|
||||
3. Click the **camera button** in the top menu.
|
||||
|
||||
4. A screen for confirming the name to save appears. Change the name if you wish and save.
|
||||
(At first, the name of the workflow currently open is filled in)
|
||||
5. When "Workflow saved" is shown, you are done.
|
||||
|
||||
When you open the Workflow tab of Workflow Studio (or press "Refresh"),
|
||||
the workflow appears in the list with the image you took attached as its thumbnail.
|
||||
|
||||
> **Tip**
|
||||
> The image (PNG) saved with the camera button also has the workflow information embedded in it.
|
||||
> If you drag and drop this image onto ComfyUI's node screen, you can load that workflow.
|
||||
> A single image file carries both the "look" and the "contents", which is handy.
|
||||
|
||||
### Changing a thumbnail later
|
||||
To replace the thumbnail of an existing workflow,
|
||||
double-click the workflow to open the detail screen, press **"Change Thumbnail"** and choose an image.
|
||||
|
||||
---
|
||||
|
||||
## 4-4 Sorting with favorites, badges and groups
|
||||
|
||||
As workflows increase, sorting them lets you find what you want right away.
|
||||
Workflow Studio has three ways to sort.
|
||||
|
||||
| Method | When to use it | Example |
|
||||
| --- | --- | --- |
|
||||
| Favorites (star) | You want to mark the ones you use often | The basic workflow you use every day |
|
||||
| Badges | You want to tell kinds apart at a glance with colored labels | "SDXL", "FLUX", "Video", "Experimenting" |
|
||||
| Groups | You want to gather them by purpose or project | "Character work", "Background materials" |
|
||||
|
||||
### Favorites (star)
|
||||
Click the **star** on a card to register it as a favorite.
|
||||
Press the **star** button at the top of the toolbar to show only favorites (**ALL** returns to showing everything).
|
||||
|
||||
Workflows registered as favorites also appear under
|
||||
"Favorites" in ComfyUI's side panel (the WS Library) (Chapter 9).
|
||||
|
||||
### Badges
|
||||
A badge is a **colored label** you attach to a workflow.
|
||||
You can also attach several badges to one workflow.
|
||||
|
||||
**1. Make a badge**
|
||||
1. Press the **"Badge"** button on the toolbar.
|
||||
2. Type a name in the **"Badge label..."** field and press **"Add"**.
|
||||
3. Click a color swatch to change the badge's color.
|
||||
|
||||
**2. Attach a badge to a workflow**
|
||||
1. Double-click the workflow to open the detail screen.
|
||||
2. In the **"Badges"** field, tick the badges you want to attach.
|
||||
3. Press **"Save"**.
|
||||
|
||||
**3. Filter by badge**
|
||||
Once you have made badges, they line up next to the star and ALL buttons at the top of the toolbar.
|
||||
Click a badge to show only the workflows that have that badge.
|
||||
|
||||
> **Tip**
|
||||
> The kinds and colors of badges are shared with the Models tab (Chapter 6).
|
||||
> If you make a badge called "SDXL", you can attach it in the same color to both workflows and models.
|
||||
|
||||
### Groups
|
||||
A group is **a box for gathering workflows by purpose**.
|
||||
|
||||
1. Click a workflow to select it.
|
||||
2. In the right-hand side panel, open the **"Groups"** tab.
|
||||
3. Make a group with **"Create New Group"**, or pick an existing group and **"Add to Group"**.
|
||||
|
||||
If you choose a group from the pull-down labeled **"All Groups"** on the toolbar, only the workflows in that group are shown.
|
||||
|
||||
### Tags and memo
|
||||
On the detail screen you can also write the following.
|
||||
|
||||
- **Tags** - keywords for searching. You can enter several, separated by commas (,).
|
||||
- **Memo** - free notes, such as cautions on how to use it or settings that worked well.
|
||||
|
||||
If you note the "source" and the "required custom nodes" for a workflow you got online, you will not be in trouble later.
|
||||
|
||||
### Renaming and deleting
|
||||
- **Rename** - click the workflow name at the top of the detail screen to edit it.
|
||||
- **Delete** - press the **"Delete"** button on the detail screen.
|
||||
|
||||
> **Caution**
|
||||
> Deleting removes the file itself in ComfyUI's workflow save folder (including the thumbnail image).
|
||||
> For workflows that matter, back them up somewhere else before deleting.
|
||||
|
||||
---
|
||||
|
||||
## 4-5 Search, sorting and clearing filters
|
||||
|
||||
### Search
|
||||
Type a keyword in the **"Search..."** box on the toolbar, and only workflows whose name, tags and so on match are shown.
|
||||
Pressing the **x** at the right end of the box clears the search text immediately.
|
||||
|
||||
### Sorting
|
||||
With the pull-down next to the search box you can change the order.
|
||||
|
||||
| Choice | Order |
|
||||
| --- | --- |
|
||||
| Date (Newest) | Newest first |
|
||||
| Date (Oldest) | Oldest first |
|
||||
| Name A-Z | Ascending by name |
|
||||
| Name Z-A | Descending by name |
|
||||
|
||||
The order you choose is remembered, and the same order is used the next time you open it.
|
||||
|
||||
### Clearing filters all at once
|
||||
While narrowing down by search, group and badge, you may wonder "why doesn't it show up in the list?".
|
||||
In that case, press **"x Clear"** at the right end of the toolbar.
|
||||
The search text, group and badge filters are all cleared at once, and every workflow is shown.
|
||||
|
||||
---
|
||||
|
||||
## 4-6 Importing, and sending to the canvas
|
||||
|
||||
### Bringing in workflows (import)
|
||||
Workflow files you got online (`.json`, or `.png` containing a workflow)
|
||||
can be brought into the Workflow tab in either of these ways.
|
||||
|
||||
- Press the **"Import"** button on the toolbar and choose files (you can select several)
|
||||
- **Drag and drop** the files onto the list area of the Workflow tab
|
||||
|
||||
Imported workflows are saved in ComfyUI's workflow save folder and added to the list.
|
||||
|
||||
### Using the selected workflow
|
||||
When you click a workflow to select it, the following three buttons on the toolbar become pressable.
|
||||
|
||||
| Button | What happens |
|
||||
| --- | --- |
|
||||
| Load in GenerateUI | Loads it into the GenerateUI tab so you can generate without touching the node screen (Chapter 5) |
|
||||
| Load in Video | Loads a workflow for video generation into the Video tab (Chapter 11) |
|
||||
| Send to Canvas | Loads the workflow onto ComfyUI's node screen |
|
||||
|
||||
> **Tip**
|
||||
> If a button cannot be pressed (it is gray), you have not yet selected a workflow.
|
||||
> Click a workflow in the list once, then press it.
|
||||
|
||||
When you press **"Send to Canvas"**, that workflow is loaded onto the node screen of the ComfyUI from which you opened Workflow Studio.
|
||||
You can use it like this: find in Workflow Studio, edit in detail in ComfyUI.
|
||||
|
||||
> **Caution**
|
||||
> "Send to Canvas" works in Workflow Studio **opened from ComfyUI's W button**.
|
||||
> If you opened it directly, for example from a bookmark, that workflow appears in the WS Library on the ComfyUI side,
|
||||
> so drag it onto the canvas from there (Chapters 2 and 9).
|
||||
|
||||
---
|
||||
|
||||
## 4-7 Checking in advance whether it works in GenerateUI (GenerateUI Check)
|
||||
|
||||
Not every workflow can be used as it is in GenerateUI (Chapter 5).
|
||||
If it uses special custom nodes, or specifies models you do not have, it may not work well.
|
||||
|
||||
So before you load one into GenerateUI, there is a feature that automatically checks whether it looks usable.
|
||||
|
||||
### Reading the check result
|
||||
When you click a workflow, the following information appears below the workflow name in the side panel.
|
||||
|
||||
- **Format badge** - the workflow's save format (UI format / API format / App format)
|
||||
- **Convert** - whether it can be converted into a form GenerateUI can use
|
||||
- **Operability** - how many of the settings can be changed on the GenerateUI screen alone
|
||||
|
||||
Each is shown in one of three levels.
|
||||
|
||||
| Display | Meaning |
|
||||
| --- | --- |
|
||||
| Check mark | No problem |
|
||||
| Warning mark | Usable, but needs care |
|
||||
| Cross mark | Cannot be used in GenerateUI, or is hard to use |
|
||||
|
||||
Hovering the mouse over a badge shows the reason for the judgment.
|
||||
|
||||
### Common judgments and what to do
|
||||
| Judgment | Common reason | What to do |
|
||||
| --- | --- | --- |
|
||||
| Convert: cross | The custom nodes the workflow needs are not installed | Install the missing nodes with ComfyUI Manager (Chapter 12) |
|
||||
| Convert: warning | The specified model or LoRA is not on your computer | Choose a model you have in GenerateUI. For UI-format workflows, note that it is automatically replaced with the first model in the list |
|
||||
| Operability: warning / cross | Many settings are not shown in GenerateUI | Change settings of nodes that are not shown on ComfyUI's node screen |
|
||||
|
||||
> **Tip**
|
||||
> Operability is "the share of nodes that have settings which are shown in GenerateUI".
|
||||
> It is a check mark at 80% or more, a warning at 50% or more, and a cross below that.
|
||||
> Even with a warning or cross, generation itself is often possible, so treat it as a rough indication of "hard to finish using GenerateUI alone".
|
||||
|
||||
> **Tip**
|
||||
> The check fetches from ComfyUI only the information of the nodes that workflow uses (v0.8.8 and later).
|
||||
> It used to take tens of seconds the first time, but now the result appears almost instantly.
|
||||
> From the second time on, results appear immediately.
|
||||
|
||||
---
|
||||
|
||||
## 4-8 Trying the bundled sample workflows
|
||||
|
||||
Workflow Studio comes with sample workflows you can try right away.
|
||||
The samples are in the **`workflows`** folder inside the folder where you installed Workflow Studio.
|
||||
|
||||
```
|
||||
ComfyUI/custom_nodes/ComfyUI-Workflow-Studio/workflows/
|
||||
```
|
||||
|
||||
Each sample has a `.json` (the workflow itself) and a `.png` (the thumbnail image) of the same name.
|
||||
|
||||
### Samples recommended for beginners
|
||||
| File name | Contents |
|
||||
| --- | --- |
|
||||
| `ws_sdxl_t2i_basic` | A basic workflow that makes images from text with an SDXL model |
|
||||
| `ws_sd15_t2i_basic` | A basic workflow that makes images from text with an SD1.5 model |
|
||||
|
||||
Choose according to the kind of model you have (SDXL or SD1.5).
|
||||
|
||||
### Importing a sample
|
||||
1. Press **"Import"** in the Workflow tab.
|
||||
2. Open the `workflows` folder above and choose the `.png` file of the sample you want to use.
|
||||
(If you choose the `.png`, it is imported with its thumbnail)
|
||||
3. Check that it has been added to the list.
|
||||
|
||||
There are also more advanced samples, such as pose specification and inpainting (redrawing part of an image).
|
||||
|
||||
> **Caution**
|
||||
> Some samples require additional custom nodes.
|
||||
> If any nodes are shown in red on the node screen, install the missing nodes with ComfyUI Manager (Chapter 12).
|
||||
> The "Convert: cross" shown in the GenerateUI Check of 4-7 is also mostly this case.
|
||||
|
||||
In the next chapter, you load the basic sample you just imported into GenerateUI and finally generate your first image.
|
||||
|
||||
> **Summary of this chapter**
|
||||
> - Workflows saved in ComfyUI line up automatically in the Workflow tab
|
||||
> - Click to show in the side panel; double-click for the detail screen
|
||||
> - With the camera button you can give a workflow a thumbnail that is easy to recognize
|
||||
> - Sort with favorites, badges and groups, and find with search and sorting. If lost, use "x Clear"
|
||||
> - With "Load in GenerateUI" and "Send to Canvas" you can use the selected workflow right away
|
||||
> - The GenerateUI Check lets you confirm in advance whether it works in GenerateUI
|
||||
@@ -0,0 +1,255 @@
|
||||
# Chapter 5 The GenerateUI Tab - Making Images Without Touching Nodes
|
||||
|
||||
At last, you generate an image with Workflow Studio.
|
||||
The **GenerateUI** tab is a screen that picks out, from inside a workflow, the items you change often, such as "prompt", "model" and "size",
|
||||
and shows them as an input form.
|
||||
You no longer need to find nodes and follow lines.
|
||||
|
||||
In the first half of this chapter (5-1 to 5-4), you use the basic sample imported in Chapter 4 to generate your first image.
|
||||
|
||||
> **Before you start**
|
||||
> - ComfyUI is running
|
||||
> - At least one Checkpoint model is in ComfyUI's `models/checkpoints` folder
|
||||
> - You have imported a sample workflow (such as `ws_sdxl_t2i_basic`) in Chapter 4
|
||||
|
||||
---
|
||||
|
||||
## 5-1 Loading a workflow into GenerateUI
|
||||
|
||||
1. Open the **Workflow** tab.
|
||||
2. **Click** the workflow you want to use (for example `ws_sdxl_t2i_basic`) to select it.
|
||||
3. In the side panel's **GenerateUI Check** (Chapter 4, section 4-7), confirm that "Convert" shows a check mark.
|
||||
4. Press **"Load in GenerateUI"** on the toolbar.
|
||||
|
||||
The screen switches automatically to the **GenerateUI** tab, and the contents of the workflow are loaded.
|
||||
If the name of the loaded workflow is shown at the top of the screen, it worked.
|
||||
|
||||
> **Tip**
|
||||
> On the GenerateUI screen, button and item names are shown in English.
|
||||
> This book uses the displayed English names as they are.
|
||||
|
||||
---
|
||||
|
||||
## 5-2 Reading the GenerateUI screen
|
||||
|
||||
The GenerateUI tab is divided into the following main parts.
|
||||
|
||||
| No. | Place | Role |
|
||||
| --- | --- | --- |
|
||||
| 1 | Top bar | Connection state with ComfyUI, workflow name, various buttons |
|
||||
| 2 | Subtabs | Switch between Input / Model / Settings / Feeder / Batch / Lab |
|
||||
| 3 | Editing area (center) | The settings of the chosen subtab |
|
||||
| 4 | Raw JSON (right side) | Shows the contents of the workflow as JSON (for advanced users) |
|
||||
| 5 | Generate panel | The Generate button, progress, seed settings, generated results |
|
||||
|
||||
### 1. The top bar
|
||||
| Display / button | Meaning |
|
||||
| --- | --- |
|
||||
| Connected / Disconnected | Whether it is connected to ComfyUI. If it is a green **Connected**, you can generate |
|
||||
| Connect | Reconnects to ComfyUI |
|
||||
| Refresh Models | Reloads the list of models (press it after adding models to ComfyUI) |
|
||||
| Reset Workflow | Discards edits and returns to the state right after loading the workflow |
|
||||
| Workflow name | The workflow currently loaded |
|
||||
|
||||
> **Tip**
|
||||
> When you open the GenerateUI tab, it connects to ComfyUI automatically.
|
||||
> If it shows **Disconnected**, check that ComfyUI is running and press **Connect**.
|
||||
|
||||
### 2. The subtabs
|
||||
| Subtab | What you set | In this book |
|
||||
| --- | --- | --- |
|
||||
| Input | Prompts, input images | 5-3 |
|
||||
| Model | Models such as Checkpoint, VAE and LoRA | 5-3 |
|
||||
| Settings | Seed, step count, sampler, image size and so on | 5-4 |
|
||||
| Feeder | Process images in a folder in order | 5-6 |
|
||||
| Batch | Generate in bulk while changing conditions | 5-5 |
|
||||
| Lab | Experimental I2I batch generation (advanced) | 5-7 |
|
||||
|
||||
At first, it is enough to learn just the three: **Input, Model and Settings**.
|
||||
|
||||
### 4. Raw JSON
|
||||
To the right of Input, Model and Settings, the contents of the workflow are shown in JSON format.
|
||||
When you change values in the form, they are reflected here too.
|
||||
Until you are used to it, treat this as "view only".
|
||||
|
||||
On the Input subtab, the **>>** button at the top of the Raw JSON folds it into a thin strip at the right edge (v0.8.12 and later),
|
||||
which gives the prompt and image areas more room. Press it again to unfold it; the folded state is remembered.
|
||||
|
||||
---
|
||||
|
||||
## 5-3 Generating your first image
|
||||
|
||||
Now, to generate. At minimum, you check and set these three things.
|
||||
|
||||
1. Which model to draw with (Model)
|
||||
2. What to draw (Input)
|
||||
3. Generate (Generate)
|
||||
|
||||
### Step 1: Choose a model (Model)
|
||||
1. Open the **Model** subtab.
|
||||
2. In the **Checkpoint** field, choose a model you have.
|
||||
If the list is long, typing characters in the box above the field narrows it down.
|
||||
3. Press the **Apply** button below the field.
|
||||
|
||||
> **Tip: when a model cannot be found**
|
||||
> The model saved in a workflow may not be on your computer.
|
||||
> You will almost always run into this when using distributed workflows. It is signaled in one of two ways.
|
||||
> - The field shows "(model name) (not found)" with a warning mark
|
||||
> - When loading, a message says the workflow's Checkpoint "..." was not found and was replaced with another model without warning
|
||||
> (in this case it has been replaced automatically with the first model in the list you have)
|
||||
>
|
||||
> From v0.8.7, if you have exactly one model with the same file name that differs only in its folder, it is replaced with that model instead of the first one.
|
||||
> (Official templates often save model names without a folder, and the old behavior could swap in an unrelated model.)
|
||||
>
|
||||
> In either case, choose the model you want to use from the list and press Apply.
|
||||
> If choosing again each time is a nuisance, the **Default Checkpoint** in the Settings tab (Chapter 11) is handy.
|
||||
|
||||
> **Caution: Don't forget Apply**
|
||||
> In GenerateUI, after changing a model or the Settings values (5-4), you must press **Apply** for them to be reflected in the workflow.
|
||||
> If you Generate without pressing Apply, the image is generated **with the values from before the change**.
|
||||
> When "I changed a setting but the result didn't change", suspect a forgotten Apply first.
|
||||
> (Only the prompt input fields are reflected automatically when you press Generate)
|
||||
|
||||
> **Tip**
|
||||
> Item names shown in bright green are items for which the loaded workflow contains a node for that model.
|
||||
> Items that are not green have no effect on this workflow even if you change them.
|
||||
|
||||
### Step 2: Write a prompt (Input)
|
||||
1. Open the **Input** subtab.
|
||||
The prompt area (Prompt) is on the left and the input image area (Image) is on the right (v0.8.12 and later; before that you switched between Prompt and Image).
|
||||
When the screen is narrow, the Image area moves below the prompts.
|
||||
2. In the **Positive Prompt** field, enter in English what you want drawn.
|
||||
|
||||
```
|
||||
a cute cat sitting on a windowsill, sunlight, soft colors, high quality
|
||||
```
|
||||
|
||||
3. Press **Apply** for the **Positive Prompt**.
|
||||
4. If needed, enter in the **Negative Prompt** field what you do not want drawn, and press **Apply** for that too.
|
||||
|
||||
> Even if you forget Apply, the prompt is reflected automatically when you press Generate.
|
||||
> However, you can check the reflected result in the Raw JSON (right side), so it is reassuring to get into the habit of pressing Apply.
|
||||
|
||||
```
|
||||
low quality, blurry, bad anatomy
|
||||
```
|
||||
|
||||
> **Tip**
|
||||
> Pressing the **reset arrow** button next to Apply returns the contents of the field to the value currently reflected in the workflow.
|
||||
> Handy when an edit went wrong.
|
||||
|
||||
> **Tip**
|
||||
> If you are not good at English, the AI translation features introduced in Chapters 7 and 10 let you turn a prompt you thought up in your own language into English.
|
||||
|
||||
### Step 3: Generate (Generate)
|
||||
1. Press the **Generate** button in the generate panel on the screen.
|
||||
2. A bar showing progress extends, and a percentage is displayed.
|
||||
3. When "Done" is shown, the generated image appears in the generate panel.
|
||||
|
||||
Congratulations. You have completed your first image with Workflow Studio.
|
||||
|
||||
A generated image is saved in ComfyUI's `output` folder, just as when generated in ComfyUI.
|
||||
To look at it again later, you can browse it in the **Gallery** tab (Chapter 8).
|
||||
|
||||
> **Tip: when you want to stop partway**
|
||||
> During generation, a **Stop** button appears next to the Generate button. Pressing it interrupts generation.
|
||||
|
||||
> **Tip: Apply and Generate at once**
|
||||
> **Click Apply while holding the Alt key** to reflect the values and generate in one go.
|
||||
> Once you are used to it, you can try things quickly: rewrite the prompt, then Alt + Apply.
|
||||
|
||||
### Saving the workflow you generated with
|
||||
If you want to use settings changed in GenerateUI again later, press the **Save** button at the right end of the subtabs.
|
||||
If you save it with a name, it is added as a new workflow in the Workflow tab.
|
||||
|
||||
---
|
||||
|
||||
## 5-4 What seed, sampler and step count mean
|
||||
|
||||
Once the first image is out, next look at the **Settings** subtab, where settings that decide how the result turns out are found.
|
||||
|
||||
The Settings tab is divided into three columns.
|
||||
|
||||
- **KSampler (left)** - settings for how the image is drawn
|
||||
- **Latent Image (middle)** - settings for the size and number of images
|
||||
- **Switches (right, v0.9.6+)** - the on/off settings inside the workflow
|
||||
|
||||
Here too, for KSampler and Latent Image, don't forget to press **Apply** on each block after changing values (the Switches column needs no Apply).
|
||||
|
||||
### KSampler items
|
||||
| Item | Meaning | Rule of thumb for beginners |
|
||||
| --- | --- | --- |
|
||||
| Seed | The "seed of the random numbers" the image grows from. With the same settings and the same seed, you get almost the same image | When generating, the seed settings in the generate panel (below) take priority, so think of this as "for checking the seed of the loaded workflow". To use the workflow's seed as it is, set the generate panel's mode to **Workflow** |
|
||||
| Steps | How many times to repeat the drawing. More is more careful but takes longer | 20 to 30 |
|
||||
| CFG | How faithfully to follow the prompt. Too high and colors and shapes tend to break down | About 5 to 8 for SDXL |
|
||||
| Sampler | The drawing algorithm | `euler`, `dpmpp_2m` and so on |
|
||||
| Scheduler | How the drawing amount is distributed across steps | `normal`, `karras` and so on |
|
||||
| Denoise | How much to redraw the original image. 1.0 when making from text | 1.0 (0.4 to 0.7 and so on when making from an image) |
|
||||
|
||||
> **Tip**
|
||||
> The suggested values differ by model. The model's distribution page (Civitai and so on) often lists recommended values, so check it.
|
||||
> If unsure, using the values the sample workflow starts with is fine.
|
||||
|
||||
### Latent Image items
|
||||
| Item | Meaning | Rule of thumb |
|
||||
| --- | --- | --- |
|
||||
| Width | Horizontal size of the image (pixels) | Around 1024 for SDXL, around 512 for SD1.5 |
|
||||
| Height | Vertical size of the image (pixels) | Same as above |
|
||||
| Batch Size | How many images to make in one generation | 1 to 4 (more uses more memory) |
|
||||
|
||||
> **Caution**
|
||||
> If you stray far from the size the model learned, people tend to come out doubled or the composition falls apart.
|
||||
> Even when you want portrait or landscape, adjust so the total pixel count stays about the same (for example 832x1216 for SDXL).
|
||||
|
||||
### Switches items (v0.9.6+)
|
||||
The "on/off" settings inside the workflow are listed with their node name and item name.
|
||||
Clicking a checkbox switches it right away. **You don't need to press Apply**. The new value also shows up in the Raw JSON on the right at once.
|
||||
|
||||
Two kinds of items are listed:
|
||||
|
||||
- Items whose value is true/false - for example the switch that turns the prompt enhancer (PE) on and off, "Boolean" nodes, and TextGenerate's thinking
|
||||
- On/off items with only two choices - enable/disable, on/off, yes/no and so on. For example KSamplerAdvanced's add_noise and DWPreprocessor's detect_hand (whether to detect hands)
|
||||
|
||||
The right end of each row shows the current value (true/false, enable/disable and so on).
|
||||
Hover over a row to see the node's number and type.
|
||||
|
||||
> **Tip**
|
||||
> Items wired from another node are not listed. Instead, the source node they are wired from (for example a Boolean node named "Enable PE?") is listed, so switch that one.
|
||||
> In workflows where nodes have no names, the node type name (such as ComfySwitchNode) is shown.
|
||||
> If the workflow has no on/off items at all, "No true/false settings in this workflow" is shown.
|
||||
|
||||
### Managing the seed (generate panel)
|
||||
The seed is managed with the **Seed** field in the generate panel and the pull-down below it.
|
||||
|
||||
| Mode | What it does | When to use it |
|
||||
| --- | --- | --- |
|
||||
| Random | Generates with a random seed every time | When you want to try various pictures |
|
||||
| Fixed | Fixes it to the value in the Seed field | When you want to keep a picture you like and change only the prompt to compare |
|
||||
| Increment | Increases the seed by 1 each time you generate | When you want to make slightly different pictures in sequence |
|
||||
| Decrement | Decreases the seed by 1 each time you generate | The reverse of Increment |
|
||||
| Workflow | Uses the seed in the workflow as it is, without overriding it | When you want to reproduce, with the original seed, an image loaded from the Gallery or a distributed workflow |
|
||||
|
||||
When generation finishes, the Seed field shows **the seed value actually used**.
|
||||
|
||||
> **Tip: Workflow mode (v0.8.3 and later)**
|
||||
> If you set the mode to **Workflow**, it generates with the loaded workflow's own seed, not the Seed field's value or a random one.
|
||||
> Even after trying several images with Random, it returns to the workflow's original seed (the value at the time of loading) when generating.
|
||||
> If no seed input can be found in the workflow, the value in the Seed field is used (random if it is -1).
|
||||
> If you press it twice in a row with the same seed and the same settings, ComfyUI reuses the already computed result, so no new image is added (this is not a malfunction).
|
||||
|
||||
### The flow of "growing" a picture you like
|
||||
Using the seed, you can improve a picture you like a little at a time.
|
||||
|
||||
1. Generate several with **Random** and look for a composition you like
|
||||
2. When a picture you like appears, switch the mode to **Fixed** (the Seed field already holds that picture's seed)
|
||||
3. Add words to the prompt or change Steps, and compare the differences
|
||||
|
||||
Fixing the seed makes it easy to see "what you changed, and how it changed".
|
||||
This is the shortest path to getting used to image generation.
|
||||
|
||||
> **Summary of this chapter (first half)**
|
||||
> - Select in the Workflow tab and press "Load in GenerateUI" to edit in GenerateUI
|
||||
> - The basics are the three subtabs Input (prompt), Model (model) and Settings (detailed settings)
|
||||
> - After changing the model or Settings values, always press **Apply**. If you forget, it generates with the values from before the change (prompts and the Settings Switches column are reflected automatically)
|
||||
> - Generate to produce. Alt + Apply reflects and generates in one go
|
||||
> - If you set the seed to Fixed, you can keep a picture you like and compare by changing conditions. To use the workflow's seed as it is, use Workflow
|
||||
@@ -0,0 +1,240 @@
|
||||
## 5-5 Batch generation - trying while changing conditions
|
||||
|
||||
As you get used to image generation, you start wanting to try things like these.
|
||||
|
||||
- Try all the models you have with the same prompt and compare them
|
||||
- Generate several prompts one after another
|
||||
- Check in bulk which sampler suits this model
|
||||
|
||||
Changing the settings and pressing Generate for each image is a lot of work.
|
||||
With the **Batch** subtab, you specify "what to change while generating" all at once, and it generates in order automatically.
|
||||
|
||||
### What can be changed in a batch
|
||||
In a batch, you choose **one** of the following seven kinds and generate while changing it in order.
|
||||
|
||||
| Kind | What changes | When to use it |
|
||||
| --- | --- | --- |
|
||||
| Checkpoint | The model | Compare how models draw |
|
||||
| Lora | The LoRA | Compare the effect of LoRAs |
|
||||
| Prompt | The prompt | Try saved prompts in order |
|
||||
| Workflow | The workflow | Run several workflows in order |
|
||||
| Sampler | The sampler | Compare the differences between samplers |
|
||||
| Scheduler | The scheduler | Compare the differences between schedulers |
|
||||
| Style | The style | Compare the differences between styles |
|
||||
|
||||
> **Tip**
|
||||
> Only one kind can be changed at a time.
|
||||
> If you want to change both the model and the prompt at once, use the Lab in 5-7.
|
||||
|
||||
### The Batch tab screen
|
||||
The Batch tab is divided into three parts: left, center and right.
|
||||
|
||||
| Place | Role |
|
||||
| --- | --- |
|
||||
| Left (lists) | Choose Checkpoints / Sampler / Scheduler / Style from a list |
|
||||
| Center (groups) | Choose Checkpoint / Lora / Prompt / Workflow by "group" |
|
||||
| Right (Batch Queue) | The list of chosen items. This is where you decide which kind to run |
|
||||
|
||||
The groups in the center are linked to the groups made in each tab.
|
||||
|
||||
- Checkpoint and Lora groups -> the Models tab (Chapter 6)
|
||||
- Prompt groups -> the Prompt tab (Chapter 7)
|
||||
- Workflow groups -> the Workflow tab (Chapter 4)
|
||||
|
||||
### Example: comparing the models you have
|
||||
Let's compare how three models draw, using the same prompt and the same seed.
|
||||
|
||||
1. Using the steps in 5-3, load beforehand a workflow with the prompt you want to compare.
|
||||
2. Set the seed mode in the generate panel to **Fixed**.
|
||||
(Fixing the seed evens out every condition except the model, so the difference is easy to see)
|
||||
3. Open the **Batch** subtab.
|
||||
4. On the left **Checkpoints** tab, tick the models you want to compare.
|
||||
5. In the right-hand **Batch Queue**, turn on the checkbox in the heading of the **Checkpoint** column.
|
||||
The column shows the list of chosen models and their count.
|
||||
|
||||
6. Press **Generate**.
|
||||
|
||||
It generates in order with the chosen models.
|
||||
The **Batch** area of the generate panel shows which one is being generated now, and the overall progress.
|
||||
|
||||
- **Pause** - pauses. Pressing it again resumes.
|
||||
- **Stop** - stops the whole batch.
|
||||
|
||||
> **Caution**
|
||||
> If a Batch Queue column's checkbox stays on, the next time you press Generate it will run as a batch again.
|
||||
> If you want to generate just one image, turn the column's checkbox off.
|
||||
|
||||
> **Tip: LoRA batches**
|
||||
> In a Lora batch, the format of the chosen LoRA (`<lora:name:strength>`) and the trigger words obtained from Civitai
|
||||
> are added automatically to the Positive Prompt. When the batch ends, it returns to the original prompt.
|
||||
|
||||
---
|
||||
|
||||
## 5-6 Feeder - processing images from a folder in order
|
||||
|
||||
**Feeder** is a feature that feeds many images one at a time into a workflow and processes them in order.
|
||||
For example, you can use it like this.
|
||||
|
||||
- Convert photos you have collected into an illustration style in bulk (I2I: making an image from an image)
|
||||
- Read poses from several images and draw a character in the same pose
|
||||
|
||||
Feeder has two modes, switched with the **[Image Loop] / [Gallery]** buttons at the top left of the Feeder tab.
|
||||
|
||||
| Mode | Where images are taken from | What you need |
|
||||
| --- | --- | --- |
|
||||
| Image Loop | A folder on your computer | The custom node **comfyui-image-feeder** (installed separately) |
|
||||
| Gallery | A group in the Gallery tab | No extra installation (the **Gallery Feeder (WFS)** node bundled with Workflow Studio) |
|
||||
|
||||
> **Tip**
|
||||
> In both modes, **a dedicated node must be in the workflow**.
|
||||
> It cannot be used just by loading an ordinary workflow.
|
||||
|
||||
### How to use Gallery mode (no extra installation)
|
||||
1. On ComfyUI's node screen, place a **Gallery Feeder (WFS)** node where the workflow "loads an image",
|
||||
and connect its image output. Save, and load it into GenerateUI.
|
||||
2. In the **Gallery** tab (Chapter 8), gather the images you want to process into a group.
|
||||
(When you first open the Feeder tab, a group called `__Feeder__` is created automatically. You may use this)
|
||||
3. Open the **Feeder** subtab of GenerateUI and choose **[Gallery]**.
|
||||
4. Choose the target **Gallery Feeder Node** and the **group** to take images from, and press **Apply**.
|
||||
5. The images of the group line up in the center. Click an image to start processing from that image.
|
||||
6. Choose **After gen** (what to do after generation) and press **Run**.
|
||||
|
||||
### After gen (what to do after generation)
|
||||
| Mode | What it does |
|
||||
| --- | --- |
|
||||
| Loop | Moves to the next image and, on reaching the end, returns to the start and continues (does not stop until you press Stop) |
|
||||
| Increment | Moves to the next image, and stops automatically after processing the last one |
|
||||
| Fixed | Keeps using the same image (when you want to make many images changing only the seed) |
|
||||
|
||||
At first, choosing **Increment** is reassuring: it processes each image once and stops automatically.
|
||||
|
||||
### Image Loop mode
|
||||
In Image Loop mode, you use the images in a folder on your computer (`ComfyUI/user/default/image-loop-data/`).
|
||||
You can also choose images from the folder and save them as a preset.
|
||||
The **comfyui-image-feeder** custom node is needed separately.
|
||||
|
||||
The bundled samples `ws_sdxl_image_feeder_i2i` (I2I) and `ws_dwpose_image_feeder` (pose reading) are for this Image Loop mode.
|
||||
|
||||
### A sample for Gallery mode (v0.8.3 and later)
|
||||
For Gallery mode you can use the bundled sample `ws_sdxl_gallery_feeder_i2i` (SDXL I2I).
|
||||
You do not need to place nodes yourself: a **Gallery Feeder (WFS)** node is already in it (group name `__Feeder__`, sort order filename_asc).
|
||||
|
||||
1. Import the sample in the Workflow tab and press **Load in GenerateUI**.
|
||||
2. In the Gallery, press the **F** button at the top left of the thumbnail of each image you want to process, to put it into the `__Feeder__` group.
|
||||
3. In the **Feeder** subtab, choose **[Gallery]**, choose the Gallery Feeder Node and the group, and press **Apply**.
|
||||
4. In the Model subtab, choose again the Checkpoint and VAE you have, and press **Apply** (the model names in the sample are those of the author's environment).
|
||||
5. Set **After gen** to **Increment** and press **Run**.
|
||||
|
||||
---
|
||||
|
||||
## 5-7 Lab - experimental I2I batch generation (advanced)
|
||||
|
||||
**Lab** is an advanced, experimental feature that develops the batch generation of 5-5 further.
|
||||
Feel free to skip it at first.
|
||||
|
||||
### Differences from Batch
|
||||
| | Batch (5-5) | Lab |
|
||||
| --- | --- | --- |
|
||||
| What can be changed at once | Only one kind | Model, prompt and KSampler **separately from each other** |
|
||||
| When changes happen | Every time | You freely specify "from which run to change" |
|
||||
| Using a generated image as the next input | Not possible | Possible (can be chained) |
|
||||
|
||||
### The idea of keyframes
|
||||
In Lab, you specify "from which generation run to switch to which setting" as **keyframes**.
|
||||
|
||||
Example: generating 10 times
|
||||
|
||||
| Runs | Model | Prompt | KSampler |
|
||||
| --- | --- | --- | --- |
|
||||
| 1 to 10 | Model A | - | - |
|
||||
| 1 to 4 | - | "Morning city" | - |
|
||||
| 5 to 10 | - | "Night city" | - |
|
||||
| 1 to 7 | - | - | Steps 20 |
|
||||
| 8 to 10 | - | - | Steps 40 |
|
||||
|
||||
In this way, the timing of switching can be decided separately for each column.
|
||||
Until the next keyframe arrives, the previous setting is carried over.
|
||||
|
||||
### Basic flow
|
||||
1. Load a workflow into GenerateUI.
|
||||
2. Open the **Lab** subtab.
|
||||
3. For I2I (image to image), drop the source image.
|
||||
When making from text (T2I), tick **T2I workflow (no source image)**.
|
||||
4. Decide the number of generations (Batch).
|
||||
5. In each of the Model, Prompt and KSampler columns, press **+** to add a keyframe,
|
||||
then double-click the keyframe and enter "from which run" and "to which setting".
|
||||
Cells in the KSampler column show the items you set (Step, CFG, Denoise, sampler, scheduler, Seed).
|
||||
A cell with nothing set shows "(workflow default)".
|
||||
6. Press **Run**.
|
||||
|
||||
Results are listed in the **Results** panel.
|
||||
|
||||
### Handy features
|
||||
- **Use generated image for next** - uses the generated image as the input image of the next run.
|
||||
You can make a series of images that change little by little.
|
||||
- **Plan Save** - lets you save the settings (the plan). When saved, an overview image summarizing the results is also made,
|
||||
and dropping that image lets you load the same plan again.
|
||||
- **Making a plan from a story** (v0.9.5+) - with the **Storyboard to Lab** skill in the AI TOOL chat,
|
||||
a story is split into one prompt per scene and the **Open in Lab** button loads the plan here (Chapter 10, section 10-5).
|
||||
|
||||
---
|
||||
|
||||
## 5-8 Using partner APIs (Nano Banana)
|
||||
|
||||
ComfyUI has **partner API nodes**, such as Google's **Nano Banana** image model (the Gemini image nodes), that hand the generation over to a cloud service.
|
||||
From v0.8.6, GenerateUI can also run workflows that contain these nodes.
|
||||
|
||||
> **Caution**
|
||||
> Partner API nodes run in the cloud, not on your PC's GPU, and **consume Comfy credits (paid)**.
|
||||
> If you run them repeatedly with Batch, Lab and so on, credits are consumed once per run.
|
||||
|
||||
### Preparation: set your Comfy API key
|
||||
1. Issue a Comfy API key at platform.comfy.org.
|
||||
2. Add the line `COMFY_API_KEY=your key` to the `.env` file in the plugin folder.
|
||||
(If there is no `.env`, copy `.env.example` to make one.)
|
||||
3. Restart ComfyUI. `.env` is read only at startup.
|
||||
|
||||
The key is used only on the server side and is never sent to the browser.
|
||||
If you run without a key, a message says that partner API authentication failed and how to set it up.
|
||||
|
||||
### How to use
|
||||
1. In the Workflow tab, load the Nano Banana sample (`ws_nano_banana_2_1_t2i`) into GenerateUI.
|
||||
2. Edit the prompt on the left side (Prompt) of the **Input** subtab and press **Apply**.
|
||||
3. To use reference images, specify them on the image cards on the right side (Image) of the **Input** subtab.
|
||||
4. Press **Generate**.
|
||||
|
||||
> **Tip**
|
||||
> You can also run it from ComfyUI's own screen while logged in. In that case you do not need the `.env` setting.
|
||||
|
||||
---
|
||||
|
||||
## 5-9 More workflows are supported (v0.8.4 and later)
|
||||
|
||||
The workflows you can use in GenerateUI have increased as follows. They are used the same way as other workflows.
|
||||
|
||||
- **Qwen Image 2.1 Turbo** - ComfyUI's official templates for text to image (T2I) and image to image (I2I). Edits also carry over to the prompt enhancer's input (the feature that expands your prompt automatically).
|
||||
- **Flux.3 Klein** - the four official templates (T2I and Image Edit, for Klein and Klein SD).
|
||||
- **MOSS-Image** - Base/SFT T2I, and the bounding-box versions that specify positions with frames.
|
||||
- **Fibo 2.0 Edit** (v0.8.14 and later) - an image-editing workflow. With the prompt enhancer (PE) setup, edits in the prompt area apply whether PE is on or off. The negative area holds a VGL-format (JSON) description as is. Width and height (Settings) of 0 mean automatic.
|
||||
- **FastH3 OmniRef / Pika-H3-Flex** (v0.8.14 and later) - MiniMax H3 reference to video. Treated as video workflows, and also usable in the Video tab (Chapter 11).
|
||||
- **Native LoRA stack** - ComfyUI v0.40's nodes that load several LoRAs at once (LoadLoraModel / LoadLoraTextEncoder). Apply, bypass and the Metadata display are supported.
|
||||
- **P-H3 Image** (v0.9.4+) - the image-edit and T2I templates. The prompt is shown on the Input tab and can be read by the Metadata tab; there is no negative prompt field. Width and height follow the workflow's wiring, and the prompt upsampler runs as set in the workflow.
|
||||
- **MiniMax H3 Image** (v0.9.6+) - ComfyUI's official image-edit and T2I templates. As with P-H3 Image, the prompt is shown on the Input tab and can be read by the Metadata tab and the sidepanel I tab; there is no negative prompt field. The prompt enhancer (PE) can be turned on and off in the Settings tab's Switches column (5-4).
|
||||
|
||||
> **Caution**
|
||||
> The native LoRA stack nodes are supported **only in API-format workflows**.
|
||||
> ComfyUI's own screen cannot yet add rows to this node, so UI-format workflows are not covered.
|
||||
|
||||
> **Tip**
|
||||
> Workflows containing the **Compare Images** (ImageCompare) node, which compares two images with a slider, used to fail on that node when run from GenerateUI (fixed in v0.9.6).
|
||||
|
||||
> **Tip**
|
||||
> The Metadata tab and the side panel's **I** tab can also read images made with Nano Banana (v0.8.5 and later).
|
||||
> The prompt appears as one whole entry, not split into Positive/Negative.
|
||||
|
||||
> **Summary of this chapter (second half)**
|
||||
> - With the Batch subtab, you can generate in bulk while changing the model, prompt, sampler and so on, one kind at a time
|
||||
> - Choose the kind with the Batch Queue column checkbox and start with Generate. Turn the check off when done
|
||||
> - Feeder is a feature that feeds many images one at a time into a workflow. A dedicated node is required
|
||||
> - Lab is an advanced feature that can switch several settings at separate timings
|
||||
> - Partner API nodes (Nano Banana and others) run once `COMFY_API_KEY` is set in `.env`. They consume credits
|
||||
@@ -0,0 +1,184 @@
|
||||
# Chapter 6 The Models Tab - Managing Models and LoRAs
|
||||
|
||||
As you keep generating images, model and LoRA files keep increasing.
|
||||
"What model was this file?" "What was that LoRA's trigger word?"
|
||||
- The **Models** tab is what solves worries like these.
|
||||
|
||||
---
|
||||
|
||||
## 6-1 Kinds of models
|
||||
|
||||
At the top of the Models tab, tabs for each kind of model are lined up.
|
||||
Each shows the files in the corresponding folder inside ComfyUI's `models` folder.
|
||||
|
||||
| Kind | In a phrase | Main location |
|
||||
| --- | --- | --- |
|
||||
| Checkpoint | The core of image generation. Nothing starts without it | `models/checkpoints` |
|
||||
| LoRA | A small model that teaches an art style, character, outfit and so on | `models/loras` |
|
||||
| VAE | Finishes the colors and fine details of an image. Often built into the Checkpoint | `models/vae` |
|
||||
| ControlNet | A model for specifying composition, such as poses and line art | `models/controlnet` |
|
||||
| UNET | The core of newer-format models such as FLUX (Diffusion Model) | `models/diffusion_models` and so on |
|
||||
| TextEncoder | A model that converts the prompt text into a form the AI can understand | `models/text_encoders` and so on |
|
||||
| Hypernetwork | An older-format add-on model for adjusting art style | `models/hypernetworks` |
|
||||
| Embedding | A small file that teaches a particular word a meaning (often used for negatives) | `models/embeddings` |
|
||||
|
||||
> **Tip**
|
||||
> At first, it is enough to make good use of just two: **Checkpoint** and **LoRA**.
|
||||
> When you start using newer models such as FLUX, UNET and TextEncoder come up more often.
|
||||
|
||||
---
|
||||
|
||||
## 6-2 Displaying and finding in the list
|
||||
|
||||
### The first load
|
||||
When you open the Models tab for the first time, the list is empty and a message says to load models with the refresh button.
|
||||
Press **"Refresh"** on the toolbar and the list of models appears.
|
||||
Press "Refresh" also when you have added new models.
|
||||
|
||||
### Thumbnail view and table view
|
||||
As in the Workflow tab, you can switch between **Thumbnail** and **Table**.
|
||||
24 items are shown per page.
|
||||
|
||||
In table view, clicking a column heading sorts by that column
|
||||
(first click: ascending, second click: descending, third click: sorting off).
|
||||
|
||||
> **Tip**
|
||||
> For thumbnails, `(model name).preview.png` located in the same place as the model file is used automatically.
|
||||
> For models without an image, you can get one from Civitai using the method in 6-3, or set one yourself.
|
||||
|
||||
### Searching and filtering
|
||||
The toolbar has items for filtering.
|
||||
|
||||
| Item | What it filters |
|
||||
| --- | --- |
|
||||
| Search models... | Keywords such as the name |
|
||||
| Star | Favorites only |
|
||||
| All Tags | Tags |
|
||||
| All Folders | Subfolders |
|
||||
| All Groups | Groups |
|
||||
| All / Enabled only / Disabled only | Enabled or disabled state (6-5) |
|
||||
|
||||
If you narrow down so far that you lose track, press **"x Clear"** at the right end of the toolbar to clear everything.
|
||||
|
||||
### Favorites, badges and groups
|
||||
The way of sorting is almost the same as in the Workflow tab (Chapter 4, section 4-4).
|
||||
|
||||
- **Favorites (star)** - mark models you use often
|
||||
- **Badges** - attach colored labels made with **"Badge"**. The kinds and colors of badges are shared with the Workflow tab
|
||||
- **Groups** - click a model and add it in the side panel's **"Groups"** tab
|
||||
|
||||
> **Tip**
|
||||
> Groups are divided **by kind of model**.
|
||||
> A Checkpoint group is shown only in the Checkpoint tab.
|
||||
> Groups made here can also be used in the GenerateUI batch generation (Chapter 5, section 5-5).
|
||||
|
||||
---
|
||||
|
||||
## 6-3 Bringing in Civitai information
|
||||
|
||||
**Civitai** is a sharing site where many image-generation models are published.
|
||||
Many of the models you get online are distributed on Civitai.
|
||||
|
||||
Workflow Studio computes a **hash value** (a value like a fingerprint of the file) from your local model file,
|
||||
and can automatically look up the information registered on Civitai.
|
||||
|
||||
### What information you can get
|
||||
- The model's name and kind (Checkpoint, LoRA and so on)
|
||||
- **Base Model** (which family the model belongs to: SDXL, SD1.5, FLUX and so on)
|
||||
- **Trigger words** (words to put in the prompt to bring out a LoRA's effect)
|
||||
- Tags and description
|
||||
- Sample images (also used for thumbnails)
|
||||
|
||||
### Getting one at a time
|
||||
1. Click a model to select it.
|
||||
2. In the right-hand side panel, open the **"CivitAI"** tab (this tab opens first when you select a model).
|
||||
3. Press **"Fetch from CivitAI"**.
|
||||
|
||||
When fetching finishes, the model's information is shown.
|
||||
In the **Sample** tab, you can look at sample images posted to Civitai.
|
||||
|
||||
### Getting them in bulk
|
||||
Press the **"CivitAI"** button on the toolbar to fetch information in bulk for the models of the kind being shown.
|
||||
Models whose information has already been fetched are skipped, so it is fine to press it again and again after adding models.
|
||||
For models without a thumbnail image, a preview image is also saved automatically.
|
||||
|
||||
> **Tip**
|
||||
> Computing the hash value takes time depending on the size of the model.
|
||||
> If you have many models of several GB, run it when you have time to spare.
|
||||
|
||||
> **Tip**
|
||||
> A model that was not found on Civitai shows a message saying it was checked but this model was not found on CivitAI.
|
||||
> For models you made yourself, or models distributed somewhere other than Civitai, not being found is normal.
|
||||
> If you tick **"Skip not found"**, models that were not found are skipped without being rechecked when fetching in bulk.
|
||||
|
||||
> **Tip: API key**
|
||||
> The **"CivitAI API Key"** in the Settings tab can be left empty (optional).
|
||||
> If authentication is needed to get some information, enter a key issued in your Civitai account settings.
|
||||
|
||||
### Especially handy when using LoRAs
|
||||
Many LoRAs have no effect unless you put their **trigger words** in the prompt.
|
||||
If you have fetched the Civitai information, you can check the trigger words in the side panel right away.
|
||||
Also, when you use a LoRA in GenerateUI batch generation, the trigger words are added to the prompt automatically (Chapter 5, section 5-5).
|
||||
|
||||
---
|
||||
|
||||
## 6-4 Using models in generation and on the canvas
|
||||
|
||||
### Set it in GenerateUI (GenUI Model)
|
||||
You can set the model chosen in the Models tab directly into the workflow in GenerateUI.
|
||||
|
||||
1. Load a workflow into GenerateUI beforehand (Chapter 5, section 5-1).
|
||||
2. In the Models tab, select the model you want to use.
|
||||
3. Press the **"GenUI Model"** button.
|
||||
|
||||
The model in the GenerateUI workflow is now replaced with the one you chose.
|
||||
While comparing Civitai sample images, you can try any model that catches your eye right away.
|
||||
|
||||
> **Tip**
|
||||
> For an Embedding, **GenUI PP** (add to the positive prompt) and **GenUI NP** (add to the negative prompt) buttons are shown.
|
||||
> Add negative Embeddings with GenUI NP.
|
||||
|
||||
> **Caution**
|
||||
> It cannot be used if the GenerateUI workflow has no node that loads that model.
|
||||
> For example, you cannot set a LoRA in a workflow that has no LoRA node.
|
||||
|
||||
### Using it on ComfyUI's node screen
|
||||
If you drag a model from the **M (Models)** tab of the **WS Library** beside ComfyUI's node screen onto the canvas,
|
||||
a node that loads that model is placed automatically (Chapter 9).
|
||||
|
||||
---
|
||||
|
||||
## 6-5 Tidying away models you do not use
|
||||
|
||||
### Switching enabled and disabled
|
||||
Models you will not use for a while can be set to **Disable** instead of being deleted.
|
||||
A disabled model no longer appears in ComfyUI's model-selection lists, so the lists become tidier.
|
||||
|
||||
- With the **pause (II)** button on a card, you can switch enabled and disabled one at a time.
|
||||
- You can also enable or disable them in bulk, by group.
|
||||
|
||||
> **Tip**
|
||||
> When disabled, `.disabled` is added to the end of the file name. The file itself is not deleted.
|
||||
> When you enable it again, the original name comes back.
|
||||
|
||||
### Operating in bulk (Select)
|
||||
Press the green **Select** button to tick several models and operate on them together.
|
||||
|
||||
- Add to or remove from a group
|
||||
- Add or remove badges
|
||||
- Move to another subfolder (related files such as preview images move together)
|
||||
- Delete
|
||||
|
||||
### Deleting
|
||||
You can delete a model from the detail screen or from Select.
|
||||
|
||||
> **Caution**
|
||||
> Deleting **permanently removes** the model file and its related files (preview image, Civitai information and so on).
|
||||
> Many models take a long time to download again, so if in doubt, "disable" instead of deleting.
|
||||
|
||||
> **Summary of this chapter**
|
||||
> - In the Models tab you can list ComfyUI's models by kind. Press "Refresh" first
|
||||
> - You can sort with favorites, badges and groups. Groups can also be used in batch generation
|
||||
> - With "Fetch from CivitAI", you can automatically bring in Base Model, trigger words, sample images and more
|
||||
> - With "GenUI Model", you can try the chosen model in GenerateUI right away
|
||||
> - For models you do not use, "disable" rather than delete, to be safe
|
||||
@@ -0,0 +1,250 @@
|
||||
# Chapter 7 The Prompt Tab - Collecting and Growing Your Spells
|
||||
|
||||
A prompt that worked well is your own treasure.
|
||||
But if you only paste it into a notepad, you can easily lose track of which was which.
|
||||
|
||||
The **Prompt** tab is a place to **save, sort and reuse** prompts.
|
||||
In addition, you can use translation with local AI, and "wildcards" that change the prompt a little each time.
|
||||
|
||||
---
|
||||
|
||||
## 7-1 Prompt basics
|
||||
|
||||
Before getting into how to use the Prompt tab, let's cover the basics of writing prompts.
|
||||
|
||||
### Positive and negative
|
||||
| Kind | What to write | Example |
|
||||
| --- | --- | --- |
|
||||
| Positive Prompt | What you want drawn | `1girl, smiling, school uniform, cherry blossoms, spring` |
|
||||
| Negative Prompt | What you do not want drawn | `low quality, blurry, extra fingers, watermark` |
|
||||
|
||||
### Tips for writing
|
||||
- **Write in English** - most models were trained on English.
|
||||
- **Separate with commas (,)** - it is common to line up words and short phrases separated by commas.
|
||||
- **Put important things first** - words written earlier tend to be reflected more strongly.
|
||||
- **Emphasize words with (word:number)** - writing `(red hair:1.3)` emphasizes that word (1.0 is the default).
|
||||
|
||||
> **Tip: change the emphasis number from the keyboard**
|
||||
> In the prompt field of GenerateUI, select the word to emphasize and press **Ctrl + Up/Down**
|
||||
> to raise or lower the number in `(word:number)` by 0.05. When the number returns to 1.0, the parentheses are removed automatically.
|
||||
|
||||
> **Tip**
|
||||
> Anime-style SDXL models suit "lining up tags", and newer models such as FLUX suit "describing in ordinary English sentences".
|
||||
> The model's distribution page often lists a recommended way of writing, so check it.
|
||||
|
||||
---
|
||||
|
||||
## 7-2 The Prompt tab screen
|
||||
|
||||
The Prompt tab is divided into three columns: left, center and right.
|
||||
|
||||
| Column | Name | Role |
|
||||
| --- | --- | --- |
|
||||
| Left | AI Assistant | Chat and translation with local AI (7-5) |
|
||||
| Center | Presets / Preset Manager | Saving, listing and sorting prompts (7-3) |
|
||||
| Right | Wildcard / Style | Managing wildcards and styles (7-4) |
|
||||
|
||||
With **Form / Table** at the top of the screen, you can switch how things are displayed.
|
||||
|
||||
- **Form** - a screen for editing one item at a time (the screen this chapter explains)
|
||||
- **Table** - a screen for editing presets and wildcards together in a table (handy when the count grows)
|
||||
|
||||
---
|
||||
|
||||
## 7-3 Saving and sorting as presets
|
||||
|
||||
A **preset** is a pair of positive and negative prompts saved together under a name.
|
||||
|
||||
### Saving a preset
|
||||
1. In the center column, open the **Presets** tab.
|
||||
2. Check that the topmost pull-down shows **New Preset (none selected)**.
|
||||
3. Fill in the following items.
|
||||
|
||||
| Item | Contents |
|
||||
| --- | --- |
|
||||
| Preset Name | The name of the preset (for example `Sakura and uniform`) |
|
||||
| Category | A classification (for example `Portrait`, `Landscape`). May be omitted |
|
||||
| Positive Prompt | What you want drawn |
|
||||
| Negative Prompt | What you do not want drawn |
|
||||
|
||||
4. Press **Save**. When a message says the preset was saved, you are done.
|
||||
|
||||
> **Tip**
|
||||
> Get into the habit of saving prompts you tried in GenerateUI and thought "this is good!" as presets on the spot.
|
||||
> Later, when you want to make an image with the same feel, you can recall it right away.
|
||||
|
||||
### Recalling and using a preset
|
||||
1. From the topmost pull-down, choose the preset you want to use.
|
||||
2. Press a button according to how you want to use it.
|
||||
|
||||
| Button | What it does |
|
||||
| --- | --- |
|
||||
| GenUI Set | Sets both the positive and negative into the prompt fields of GenerateUI at once |
|
||||
| PP Copy | Copies the positive prompt |
|
||||
| NP Copy | Copies the negative prompt |
|
||||
|
||||
> **Caution**
|
||||
> **GenUI Set** can be used while a workflow is loaded in GenerateUI.
|
||||
> Load a workflow first, using the steps in Chapter 5.
|
||||
|
||||
### Sorting with groups
|
||||
Presets can also be sorted into groups.
|
||||
|
||||
1. With a preset selected, press **+ Group** to make a new group.
|
||||
2. Choose a group from **Select group...** and press **Add to Group**.
|
||||
|
||||
A group can also be deleted (**Del Group**).
|
||||
|
||||
Groups made here can be used as "Prompt" groups in GenerateUI batch generation (Chapter 5, section 5-5).
|
||||
For example, if you put spring, summer, autumn and winter presets in a group called "Seasons series",
|
||||
you can generate the pictures of all four seasons in bulk.
|
||||
|
||||
### Listing with Preset Manager
|
||||
In the **Preset Manager** tab of the center column, you can see the saved presets as a list.
|
||||
|
||||
- **All** - all presets
|
||||
- **Star** - presets registered as favorites
|
||||
- **Groups** - shown by group
|
||||
|
||||
With the **Search presets...** box at the top, you can search presets.
|
||||
|
||||
Saved presets are also shown in the **P (Prompts)** tab of the **WS Library** beside ComfyUI's node screen,
|
||||
and can be dragged onto the canvas for use (Chapter 9).
|
||||
|
||||
---
|
||||
|
||||
## 7-4 Wildcards and styles
|
||||
|
||||
In the right column, you manage **wildcards**, which change the prompt automatically,
|
||||
and **styles**, which add a mood to the prompt.
|
||||
Switch with **Wildcard / Style** at the top of the column.
|
||||
|
||||
### What is a wildcard?
|
||||
A wildcard is a mechanism that **randomly swaps out a part of the prompt every time you generate**.
|
||||
With the same prompt, you can make many images with variation.
|
||||
|
||||
The easiest way in Workflow Studio is to use a **wildcard file**.
|
||||
Make a file listing candidates, and when you write `__filename__` in the prompt,
|
||||
one line from the file is chosen at random every time you generate.
|
||||
|
||||
### Making a wildcard file
|
||||
As an example, let's make a file called `colors` containing candidate colors.
|
||||
|
||||
1. In the right column, choose **Wildcard** and press **+ New** under **Wildcard Files**.
|
||||
2. Enter a file name (for example `colors`) and choose **txt** as the format.
|
||||
3. Enter one candidate per line.
|
||||
|
||||
```
|
||||
red
|
||||
blue
|
||||
green
|
||||
golden
|
||||
```
|
||||
|
||||
4. Press **Save**.
|
||||
|
||||
### Using a wildcard
|
||||
In the prompt, write the file name enclosed in `__` (two underscores).
|
||||
|
||||
```
|
||||
1girl, __colors__ dress, standing in a garden
|
||||
```
|
||||
|
||||
Each time you generate in GenerateUI, the `__colors__` part is replaced with one of `red`, `blue`, `green` or `golden`.
|
||||
|
||||
> **Tip**
|
||||
> Instead of typing `__colors__` by hand, you can also choose a file with the **File** button in the right column and insert it.
|
||||
|
||||
### More advanced notation (for Impact Pack)
|
||||
At the top of the right column there are also buttons that insert symbols such as `{ }`, `$$` and `[ ]`.
|
||||
These are for notations like the following.
|
||||
|
||||
- `{cat|dog|rabbit}` - choose one out of the three
|
||||
- `{2$$cat|dog|bird}` - choose two out of the three
|
||||
|
||||
> **Caution**
|
||||
> What GenerateUI expands automatically is only the `__filename__` notation.
|
||||
> To use notations such as `{A|B}`, you need to put the wildcard node of the custom node **ComfyUI-Impact-Pack**
|
||||
> (ImpactWildcardProcessor and so on) in the workflow.
|
||||
> Until you are used to it, using only the `__filename__` notation is enough.
|
||||
|
||||
### Sending the prompt you built
|
||||
The prompt you built in the right column can be sent out with the buttons below.
|
||||
|
||||
- **-> Pos** - send to the preset's Positive Prompt
|
||||
- **-> Neg** - send to the preset's Negative Prompt
|
||||
- **Copy** - copy it
|
||||
|
||||
The `__filename__` parts are expanded automatically when you generate in GenerateUI.
|
||||
|
||||
### Styles
|
||||
A **style** is a "mood template" added to the prompt.
|
||||
For example, the "cinematic" style has contents registered such as `cinematic still, {prompt}, dramatic lighting`.
|
||||
Your own prompt goes into the `{prompt}` part.
|
||||
|
||||
To use a style, in the top bar of GenerateUI, turn on the **Style** checkbox and choose a style from the pull-down.
|
||||
When you generate, the chosen style is combined into the prompt automatically (the workflow itself is not rewritten).
|
||||
|
||||
Many styles come with Workflow Studio.
|
||||
In **Style** of the Prompt tab, you can look at the list of styles and make your own with **+ New**.
|
||||
|
||||
> **Tip**
|
||||
> To see what mood each style gives, it helps to use **Create Catalog** in GenerateUI to make sample images for each style in bulk.
|
||||
> The samples you make can be listed in the Style_Catalog of the Gallery tab (Chapter 8).
|
||||
|
||||
---
|
||||
|
||||
## 7-5 Getting AI to help with translation and prompt making
|
||||
|
||||
In the **AI Assistant** in the left column, you can have AI running on your computer (local AI) help you make prompts.
|
||||
|
||||
> **What you need in advance**
|
||||
> To use this feature, you need local AI software such as **Ollama** or **LM Studio**, and an AI model prepared.
|
||||
> How to prepare is explained in Chapter 10. If it is not ready, **Disconnected** is shown at the top of the AI Assistant.
|
||||
|
||||
### Translating your language into English
|
||||
Even if you are not good at English prompts, it is fine.
|
||||
|
||||
1. In the input box at the bottom of the left column, write in your language what you want drawn.
|
||||
|
||||
```
|
||||
A girl in a school uniform smiling under a cherry tree, soft spring light
|
||||
```
|
||||
|
||||
2. Press the **JA->EN** button under **Translate:** (choose the languages to suit your text).
|
||||
3. The translated result is shown in the chat area.
|
||||
|
||||
With the buttons shown below the translation result, you can use the result.
|
||||
|
||||
| Button | What it does |
|
||||
| --- | --- |
|
||||
| Apply to GenerateUI | Puts it into the positive prompt field of GenerateUI |
|
||||
| Copy | Copies it (for pasting into a preset and so on) |
|
||||
|
||||
When you want to know the meaning of an English prompt, you can conversely translate it with **EN->JA**.
|
||||
|
||||
### Making prompts while consulting the AI
|
||||
Write a question in the input box and press **Send** (or the Enter key) to chat with the AI.
|
||||
|
||||
- "Make a prompt for a sunset seaside scene, in English tag format"
|
||||
- "Add a more fantastical mood to this prompt"
|
||||
|
||||
If you ask like this, it offers draft prompts.
|
||||
If you are using an AI model that can read images, you can attach an image with **Attach Image**
|
||||
and ask "turn the mood of this image into a prompt".
|
||||
|
||||
- **Shift + Enter** - line break
|
||||
- **Clear Chat** - reset the conversation
|
||||
- **Gear button** - settings for which AI software and model to use (Chapter 10)
|
||||
|
||||
> **Caution**
|
||||
> A local AI's answers are not always correct.
|
||||
> Adjust the prompts that come out while actually generating to check them.
|
||||
|
||||
> **Summary of this chapter**
|
||||
> - Prompts are basically English and comma-separated. Emphasis is `(word:number)`
|
||||
> - Save prompts that worked as presets with a name
|
||||
> - With "GenUI Set", you can set a preset into GenerateUI right away
|
||||
> - If you sort them into groups, you can try them in bulk with batch generation
|
||||
> - Make a wildcard file and write `__filename__` to make the prompt vary with each generation
|
||||
> - If you prepare local AI, you can translate and consult about prompts
|
||||
@@ -0,0 +1,331 @@
|
||||
# Chapter 8 The Gallery Tab - Looking Back at Generated Images
|
||||
|
||||
As you keep generating images, hundreds and thousands of images pile up in ComfyUI's `output` folder.
|
||||
The **Gallery** tab is a place to browse them comfortably,
|
||||
and to solve "how did I make this image?".
|
||||
|
||||
Images generated in ComfyUI have information about the workflow and prompt used for generation (**metadata**) embedded in them.
|
||||
The Gallery tab reads this information so that you can reproduce the same settings right away.
|
||||
Videos (MP4 and WebM), audio files (WAV, MP3, OGG, M4A, FLAC and Opus) and 3D models (GLB, glTF, VRM, PLY and SPZ) can also be handled in the same list as images.
|
||||
|
||||
---
|
||||
|
||||
## 8-1 Listing images
|
||||
|
||||
At the top of the Gallery tab there are four subtabs.
|
||||
|
||||
| Subtab | Role | In this book |
|
||||
| --- | --- | --- |
|
||||
| Output | The list of generated images (this is what you normally use) | 8-1 to 8-3 |
|
||||
| ImagePrompt | Build prompts while looking at sample images | 8-4 |
|
||||
| Style_Catalog | Choose from sample images of styles | 8-4 |
|
||||
| Metadata | Drop an image file to inspect the information in it | 8-2 |
|
||||
|
||||
### The Output screen
|
||||
The **Output** subtab is divided into three parts: left, center and right.
|
||||
|
||||
| Place | Role |
|
||||
| --- | --- |
|
||||
| Left (folders) | The list of folders inside the `output` folder. The topmost **[root]** is the whole `output` folder |
|
||||
| Center (list) | The images of the chosen folder. Scroll down and more are loaded |
|
||||
| Right (detail panel) | Information about the chosen image (8-2) |
|
||||
|
||||
First, choose a folder from the folder list on the left, and its images appear in the center.
|
||||
|
||||
> **Tip**
|
||||
> If images you newly generated in GenerateUI or ComfyUI do not appear, press **Refresh** on the toolbar.
|
||||
|
||||
> **Tip**
|
||||
> The location of the `output` folder that is read can be changed with **"Gallery Output Folder"** in the Settings tab.
|
||||
|
||||
### Switching the display, searching and sorting
|
||||
As in other tabs, you can do the following.
|
||||
|
||||
- **Thumbnail / Table** - switch between thumbnail display and table display
|
||||
- **Search box** - search by file name, tags, memo and **the contents of the prompt**. If you turn on the **S** button next to it, you can search by the meaning of a sentence (8-6)
|
||||
- **Sorting** - Date (Newest) / Date (Oldest) / Name A-Z / Name Z-A
|
||||
- **Star** - show favorites only
|
||||
- **x Clear** - clear all filters at once
|
||||
|
||||
> **Tip**
|
||||
> In the search box you can also search by words in the prompt.
|
||||
> For example, searching "cat" finds images whose prompt contains cat.
|
||||
> (Prompt search targets images that you have opened once in the detail panel)
|
||||
|
||||
### Looking large, and comparing
|
||||
- Clicking an image shows it large in the right-hand detail panel.
|
||||
- **Hold the Ctrl key** and click images to select several.
|
||||
Select two to four and press **Compare** to view them side by side.
|
||||
|
||||
Lining up images made by changing only the seed or the model makes the differences easy to see.
|
||||
|
||||
### Organizing
|
||||
- You can sort with **favorites (star), tags, memo and groups** (set in the detail panel).
|
||||
- You can select several and add them to a group together, or move them to another folder.
|
||||
The screen for choosing the destination (**Move To...**) has a filter box: enter part of a folder name to narrow the candidates, and press Enter to move to the first candidate.
|
||||
- Pressing **Export** bundles the chosen images into a ZIP file for download.
|
||||
|
||||
> **Caution**
|
||||
> Using **Delete** in the detail panel, or **Delete File** for a multiple selection, deletes the image files themselves.
|
||||
|
||||
---
|
||||
|
||||
## 8-2 Reading generation settings from metadata
|
||||
|
||||
When you click an image, four tabs appear in the right-hand detail panel.
|
||||
|
||||
| Tab | Contents |
|
||||
| --- | --- |
|
||||
| Prompt | The prompts used to generate the image (the tab shown first) |
|
||||
| Info | File name, size, date, tags, memo |
|
||||
| JSON | The workflow embedded in the image (JSON) |
|
||||
| Groups | Group settings |
|
||||
|
||||
### Checking the prompt
|
||||
The **Prompt** tab lists the prompts that were embedded in the image.
|
||||
Positive ones are marked **POS**, negative ones **NEG**.
|
||||
Clicking an item shows the whole text.
|
||||
|
||||
### Examining more closely (the Metadata subtab)
|
||||
When you want to know in detail even the models and LoRAs used, press the **Metadata** button in the detail panel
|
||||
(or click an image while holding the Alt key).
|
||||
The Gallery's **Metadata** subtab opens and the following information is shown in an organized way.
|
||||
|
||||
- **Models** - Checkpoint, VAE, Diffusion Model, Text Encoder (center column)
|
||||
- **LoRA** - the LoRAs used and their strength (center column)
|
||||
- **Prompt** - positive and negative (center column)
|
||||
- **Settings** - the image size (width x height), and the KSampler's Seed, Steps, CFG, Sampler, Scheduler and Denoise (right column; v0.7.14 and later)
|
||||
- **Nanobanana** - the generation history of images made in Comic Creator's nanobanana tab: engine, model, prompt and so on (right column; only for matching images)
|
||||
|
||||
With the buttons beside the prompt, you can send the contents to other tabs.
|
||||
|
||||
| Button | What it does |
|
||||
| --- | --- |
|
||||
| Copy | Copy |
|
||||
| GenUI:P / GenUI:N | Put it into GenerateUI's positive / negative |
|
||||
| Prompt:P / Prompt:N | Put it into the positive / negative of a preset in the Prompt tab |
|
||||
|
||||
> **Tip: you can also examine images you found online**
|
||||
> If you **drop** an image file onto the left side of the Metadata subtab, you can examine that image's information.
|
||||
> Besides ComfyUI images, PNG images made with SD WebUI (AUTOMATIC1111), SD Forge and Fooocus are also supported.
|
||||
> Handy when you want to know how an image found on a distribution site was made
|
||||
> (however, it cannot be read from images whose metadata was stripped when they were posted).
|
||||
|
||||
---
|
||||
|
||||
## 8-3 Reproducing the same settings
|
||||
|
||||
The handiest use of the Gallery is to **generate again with the same settings as an image you like**.
|
||||
There are two ways.
|
||||
|
||||
### Method 1: Reproduce in GenerateUI (Load GenUI)
|
||||
1. In the Gallery, click the image you want to reproduce.
|
||||
2. Press the **Load GenUI** button in the detail panel.
|
||||
3. The workflow embedded in the image is loaded into GenerateUI.
|
||||
|
||||
After that, as in Chapter 5, you can generate while changing the prompt a little or changing the seed.
|
||||
|
||||
> **Tip**
|
||||
> **When you want to make the same image again (v0.8.3 and later)**
|
||||
> The workflow embedded in the image also contains the seed value from that time.
|
||||
> If you set the generate panel's seed mode to **Workflow** and press Generate, it generates with that seed as it is.
|
||||
>
|
||||
> If the mode stays at Random, it generates with a different seed.
|
||||
> Also, if you use Fixed, paste the value of the **Seed** field in the **Settings** subtab into the generate panel's **Seed** field (because the generate panel's value takes priority).
|
||||
|
||||
### Method 2: Reproduce on ComfyUI's node screen (Copy & Send Canvas)
|
||||
1. In the Gallery, click the image you want to reproduce.
|
||||
2. Open the **JSON** tab in the detail panel.
|
||||
3. Press **Copy & Send Canvas**.
|
||||
|
||||
The workflow that made that image is loaded onto ComfyUI's node screen.
|
||||
Use this when you want to adjust things in detail on the node screen.
|
||||
|
||||
> **Caution**
|
||||
> If a message says "this image has no ComfyUI workflow embedded", it cannot be reproduced.
|
||||
> This applies to images made with settings that do not save workflow information, and images edited or compressed with other software.
|
||||
|
||||
### Using an image as material for the next generation
|
||||
You can also use a Gallery image as an "input image" for generation.
|
||||
|
||||
| Button | What it does |
|
||||
| --- | --- |
|
||||
| Send GenUI Image | Sets the chosen image as the input image (LoadImage node) of the GenerateUI workflow |
|
||||
| Send to LI node | Sets the chosen image on the image-loading node currently selected on ComfyUI's node screen |
|
||||
| Image Edit | Opens the chosen image in the Image Edit tab (Chapter 11) |
|
||||
| Send CC Layout | Sends the chosen image to Comic Creator's Layout tab (the selected panel / overlay) (shown only when the Gallery is opened inside Comic Creator; Chapter 11, section 11-6) |
|
||||
| Send CC Image | Sends the chosen image to Comic Creator's Image tab (as a new layer if a document is open, otherwise as a new canvas; videos are not supported; shown under the same condition as Send CC Layout) |
|
||||
|
||||
Handy when redrawing a generated image further with an I2I (image to image) workflow.
|
||||
|
||||
---
|
||||
|
||||
## 8-4 ImagePrompt and Style_Catalog
|
||||
|
||||
### ImagePrompt - building prompts from sample images
|
||||
**ImagePrompt** is a subtab for building prompts by choosing visually,
|
||||
with "sample images" and "prompts" lined up as sets.
|
||||
|
||||
1. Click a sample image and the prompt of that image appears on the right side.
|
||||
2. Press **+ Add** and it is added to **Selected Prompts**.
|
||||
3. After adding several, a **Final Prompt**, with them joined by commas, is produced.
|
||||
4. Use **Copy** to copy it and paste it into GenerateUI or a preset.
|
||||
|
||||
Put the sample images in the `ws_image_prompt` folder, which is created automatically inside the `output` folder.
|
||||
If you put a `.txt` file with the same name as the image (its contents being the prompt) alongside it, it becomes usable as a sample.
|
||||
|
||||
> **Example**
|
||||
> `ws_image_prompt/hairstyle/ponytail.png` and `ws_image_prompt/hairstyle/ponytail.txt` (contents: `ponytail, long hair`)
|
||||
|
||||
### Style_Catalog - choosing styles by sample images
|
||||
The styles introduced in Chapter 7 are hard to picture from their names alone.
|
||||
In **Style_Catalog**, you can line up sample images for each style and choose by how they look.
|
||||
|
||||
Sample images are made with **Create Catalog** in the top bar of GenerateUI.
|
||||
|
||||
1. Load a workflow that makes images from text into GenerateUI.
|
||||
2. In the **Style** section of the **Batch** subtab, tick the styles you want samples of.
|
||||
3. Press **Create Catalog** in the top bar, decide the destination folder and run.
|
||||
4. Press **Catalog** in the top bar to move to Style_Catalog in the Gallery.
|
||||
|
||||
When you choose a sample image in Style_Catalog and press **Select as Style**,
|
||||
GenerateUI's style switches to that style.
|
||||
|
||||
> **Tip**
|
||||
> How a style takes effect changes with the model.
|
||||
> If you separate the destination folders by model, they are easier to compare.
|
||||
|
||||
---
|
||||
|
||||
## 8-5 Eagle integration and PSD export (optional)
|
||||
|
||||
From here on, these are features only for those who need them.
|
||||
|
||||
### Eagle integration
|
||||
**Eagle** is paid software for organizing images.
|
||||
If you enable **Eagle integration** in the Settings tab, images generated in GenerateUI can be automatically saved to Eagle together with information such as the prompt.
|
||||
If you manage images in Eagle, give it a try.
|
||||
|
||||
### PSD export
|
||||
Select several images in the Gallery and press **Create PSD**,
|
||||
and you can make a PSD (Photoshop format) file with each image stacked as a layer.
|
||||
Handy when you want to gather difference images together and finish them in image-editing software.
|
||||
|
||||
> **Caution**
|
||||
> To use PSD-related features, an extra Python package (psd-tools) is needed.
|
||||
> If it is not installed, the installation method is shown in an error message (Chapter 11).
|
||||
|
||||
---
|
||||
|
||||
## 8-6 Finding images by "meaning" (semantic search)
|
||||
|
||||
Normal search finds images whose file name, tags or prompt characters match.
|
||||
**Semantic search** (v0.8.2 and later) searches by the "meaning" of an image.
|
||||
For example, if you enter "a city street at dusk", it finds images with a matching mood even when the prompt does not contain those words.
|
||||
You can also bring up a list of **similar images** to the one you choose.
|
||||
|
||||
### How to use it
|
||||
1. Turn on the **S** button next to the search box. The search box switches to semantic search, and a second row appears on the toolbar.
|
||||
2. Press the **gear** (settings) button on the second row and build the **index** (an index for searching) (see below).
|
||||
3. Enter a sentence in the search box and press **Enter**. Results line up in score order, with the score shown on each thumbnail.
|
||||
4. Select an image and press **Similar** on the second row, and images similar to it line up. Select another image and press the **refresh** button to redo the similar-image list for that image. Press **Similar** again to return to the normal display.
|
||||
|
||||
> **Tip**
|
||||
> Sorting and tag/group filtering do not apply to semantic search results.
|
||||
> The search range is inside the folder you have selected (including subfolders).
|
||||
> A folder with a green dot next to its image count has all the images directly in it indexed.
|
||||
|
||||
### Choosing a model (the "Model" tab of the gear)
|
||||
| Model | Characteristics | Preparation |
|
||||
| --- | --- | --- |
|
||||
| Gemini Embedding 2 | Computed on Google's service. Fast. Images are sent to Google | Get an API key, write `GEMINI_API_KEY=key` in the plugin's `.env`, and restart ComfyUI |
|
||||
| EmbeddingGemma 2 | Computed inside your computer with **Ollama** (local, free). Nothing is sent outside | Install and start Ollama, then run `ollama pull embeddinggemma-2:740m` (or the lighter `embeddinggemma-2:440m`). On the Model tab, choose the **Ollama URL** (usually unchanged) and the **Model size** |
|
||||
|
||||
> **Caution: when using Gemini**
|
||||
> Images are sent to Google's service. Content sent under the free tier may be used by Google to improve its products.
|
||||
> If you have many images you do not want to expose, choose the local EmbeddingGemma 2.
|
||||
> Write the API key only in `.env`, and do not show it to others.
|
||||
|
||||
### Building the index (the "Index" tab of the gear)
|
||||
1. Choose the target folder (you can also choose whether to include subfolders).
|
||||
2. Choose "new only" or "rebuild all" and start. Progress is shown, and you can stop partway.
|
||||
3. The index is one shared across all folders. You may build it a little at a time, folder by folder.
|
||||
|
||||
When you change the model or the vector dimension, a **rebuild of everything** is needed.
|
||||
|
||||
### Speed guidelines and settings
|
||||
- Since v0.8.14 the local EmbeddingGemma 2 runs in Ollama (the earlier way of running it in ComfyUI's Python was removed).
|
||||
On an NVIDIA GPU it takes about 0.1 to 0.2 second per image. When indexing finishes, the model is unloaded from GPU memory automatically.
|
||||
- Ollama must be running while you build the index and while you search.
|
||||
- The 740m (text + image + audio) and 440m (text + image, lighter) model sizes return the same results, so switching does not need a rebuild.
|
||||
Indexes made with v0.8.13 or earlier keep working as they are.
|
||||
- In the **Search** tab, you can decide the "minimum score" for similar-image and text search, and the maximum number of results.
|
||||
Because the score level differs by model, it is saved per model.
|
||||
|
||||
---
|
||||
|
||||
## 8-7 Handling audio files, and converting
|
||||
|
||||
As opportunities to make music and sound effects in ComfyUI have increased, the Gallery can handle audio files too (v0.8.0 and later).
|
||||
Supported are WAV, MP3, OGG, M4A, FLAC and Opus.
|
||||
|
||||
- In the list, a waveform thumbnail and a note badge are shown. The waveform color differs by format (MP3 blue, WAV green, FLAC amber, OGG/Opus purple, M4A pink).
|
||||
- When you select one, the waveform and a player appear in the right-hand detail panel, and you can play it right there.
|
||||
- For audio saved with a workflow (`prompt` / `workflow`) embedded, the Prompt and JSON tabs also work.
|
||||
- Videos (MP4 and WebM) can be listed in the same way. With the **Send to LV node** button, you can send the chosen video to the **Load Video** node selected on the ComfyUI screen (the video version of Send to LI node for images).
|
||||
|
||||
### Converting files
|
||||
When you select several items including audio or video, **Convert...** appears on the bulk-action bar.
|
||||
|
||||
1. Select the files you want to convert and press **Convert...**.
|
||||
2. Decide the output format (FLAC / MP3 / Opus / M4A / WAV) and, if needed, the bitrate, sample rate and number of channels.
|
||||
3. When run, the result is saved as a separate file in the same folder (if the same name exists, a number is added such as `name_converted`, and nothing is overwritten).
|
||||
|
||||
When you choose a video, only the audio track is extracted and saved.
|
||||
|
||||
| Carried over | Description |
|
||||
| --- | --- |
|
||||
| Workflow information | Carried over to MP3, FLAC, Opus and M4A. It cannot be carried over to WAV (a notice appears) |
|
||||
| Favorites, tags, memo, groups | You can choose whether to carry them over |
|
||||
| Deleting the original file | You can choose whether to delete it after a successful conversion (with a confirmation screen) |
|
||||
|
||||
> **Tip**
|
||||
> OGG can be played, but cannot be chosen as an output format of conversion.
|
||||
> You can convert with Workflow Studio alone, without installing other video-editing software.
|
||||
|
||||
> **Tip: use in the Video tab**
|
||||
> In the Asset subtab of Video, you can set an audio file as "Set as BGM" or "Add as sound" (Chapter 11, section 11-4).
|
||||
|
||||
---
|
||||
|
||||
## 8-8 Viewing 3D models (v0.9.4+)
|
||||
|
||||
The results of ComfyUI workflows that make 3D models (such as image to 3D) can also be checked in the Gallery.
|
||||
Supported formats are GLB, glTF, VRM, PLY (mesh, point cloud or Gaussian splat) and SPZ.
|
||||
|
||||
- They are listed with a "**3D**" badge. The thumbnail is drawn by your browser the first time the file appears in the list and is then kept on the server
|
||||
(files over 128 MB get one when opened).
|
||||
- When selected, the file is shown in 3D in the built-in viewer of the detail panel on the right. Double-click to enlarge it.
|
||||
|
||||
| Action | What it does |
|
||||
| --- | --- |
|
||||
| Drag | Rotate |
|
||||
| Right-drag | Move (pan) |
|
||||
| Mouse wheel | Zoom in / out |
|
||||
| ⟲ (reset) button | Return to the starting view |
|
||||
|
||||
- For a model saved with ComfyUI's **SaveGLB**, the workflow can be read just like an image's (sections 8-2 and 8-3).
|
||||
|
||||
> **Caution**
|
||||
> - 3D files cannot be sent to Image Edit, GenerateUI, Tagger or Feeder.
|
||||
> - Some `.gltf` files refer to separate `.bin` or image files. Moving or deleting in the Gallery only affects the `.gltf` itself, so do not change where those files are.
|
||||
|
||||
> **Summary of this chapter**
|
||||
> - In the Gallery's Output, you can look back at generated images folder by folder. You can also search by words in the prompt
|
||||
> - The detail panel's Prompt tab shows right away the prompt used to generate the image
|
||||
> - With "Load GenUI" you can reproduce the same workflow in GenerateUI, and with "Copy & Send Canvas" on the node screen
|
||||
> - To reproduce, set the seed mode to Workflow (or Fixed)
|
||||
> - If you drop an image onto the Metadata subtab, you can examine the models, LoRAs and prompt in detail
|
||||
> - With the S button you can search by the meaning of a sentence or by "similar images" (semantic search)
|
||||
> - Audio files can also be listed, played and converted
|
||||
> - 3D models (GLB, glTF, VRM, PLY, SPZ) can also be turned around and checked in the Gallery (8-8)
|
||||
@@ -0,0 +1,171 @@
|
||||
# Chapter 9 The WS Library - Using It Inside the ComfyUI Screen
|
||||
|
||||
In the chapters so far, we mainly used the main part of Workflow Studio (the screen with the row of tabs).
|
||||
In this chapter, we use the **WS Library (Workflow Studio Library)** that opens beside ComfyUI's node screen.
|
||||
|
||||
With the WS Library, you can use the workflows, nodes, models and prompts you organized in Workflow Studio
|
||||
**just by dragging and dropping onto the node screen**.
|
||||
It is a feature whose convenience you feel more the longer you spend working on the node screen.
|
||||
|
||||
---
|
||||
|
||||
## 9-1 Opening the WS Library
|
||||
|
||||
1. Open ComfyUI's node screen.
|
||||
2. Press the **WS Library** button (the icon of lined-up squares) added to the top menu.
|
||||
|
||||
A panel opens at the edge of the screen. Press the button again to close it.
|
||||
|
||||
### Six tabs
|
||||
At the top of the panel, single-letter tabs are lined up. Hovering the mouse shows the proper name.
|
||||
|
||||
| Tab | Name | What you can do | In this book |
|
||||
| --- | --- | --- | --- |
|
||||
| W | Workflows | Load workflows | 9-2 |
|
||||
| N | Nodes | Place nodes and node sets | 9-2 |
|
||||
| M | Models | Place nodes that load models | 9-2 |
|
||||
| P | Prompts | Place or copy saved prompts | 9-2 |
|
||||
| I | Information | Inspect images and workflows and place the materials used | 9-3 |
|
||||
| A | AI TOOL | Use AI features such as translation and chat | Chapter 10 |
|
||||
|
||||
Inside each tab there are further small tabs (subtabs).
|
||||
In many tabs, the following subtabs are common.
|
||||
|
||||
- **All** - everything
|
||||
- **Favorites** - things registered as favorites in the main Workflow Studio
|
||||
- **Groups** - by the groups made in the main Workflow Studio
|
||||
|
||||
Also, in each subtab's search box, you can narrow down by typing a name.
|
||||
|
||||
> **Tip**
|
||||
> What is shown in the WS Library is linked to the organization done in the main Workflow Studio (favorites, groups, badges).
|
||||
> The better you organize in the main part, the easier the WS Library is to use.
|
||||
|
||||
---
|
||||
|
||||
## 9-2 Placing onto the canvas with drag and drop
|
||||
|
||||
The basic operation of the WS Library is very simple.
|
||||
|
||||
| Operation | What happens |
|
||||
| --- | --- |
|
||||
| Drag and drop onto the canvas | Places or loads it at the dropped position |
|
||||
| Double-click | Places or loads it near the center of the screen |
|
||||
|
||||
### W - Load a workflow
|
||||
When you drag a workflow onto the canvas (or double-click it), that workflow is loaded.
|
||||
It behaves the same as when you drop a workflow file from the file explorer.
|
||||
|
||||
Subtabs: All / Favorites / Groups / By Badge (by badge)
|
||||
|
||||
> **Tip**
|
||||
> If you opened the main Workflow Studio from a bookmark and "Send to Canvas" is unavailable,
|
||||
> the target workflow is shown in this W tab, so drag it from here (Chapter 4, section 4-6).
|
||||
|
||||
### M - Place a model
|
||||
When you drag a model onto the canvas, **a loader node with that model already chosen** is placed.
|
||||
|
||||
| Kind of model | Node placed |
|
||||
| --- | --- |
|
||||
| Checkpoint | Load Checkpoint (CheckpointLoaderSimple) |
|
||||
| LoRA | Load LoRA (LoraLoader) |
|
||||
| VAE | Load VAE (VAELoader) |
|
||||
| ControlNet | Load ControlNet Model (ControlNetLoader) |
|
||||
| UNET | Load Diffusion Model (UNETLoader) |
|
||||
| TextEncoder | Load CLIP (CLIPLoader) |
|
||||
| Hypernetwork | HypernetworkLoader |
|
||||
|
||||
The trouble of finding a node in a list, placing it, choosing the file name from a pull-down and so on goes away.
|
||||
After placing it, you connect it with lines to other nodes and use it.
|
||||
|
||||
Subtabs: All / Favorites / Groups / By Type (by kind)
|
||||
|
||||
> **Tip**
|
||||
> There is no loader node for Embeddings, so they cannot be placed on the canvas.
|
||||
|
||||
> **Tip: placing LoRAs in bulk**
|
||||
> In a LoRA group, an item called **All N LoRAs** (N is the number of LoRAs in the group) is shown.
|
||||
> If you drag it, a `Lora Loader (LoraManager)` node containing all the LoRAs in the group is placed.
|
||||
> (The custom node **ComfyUI-Lora-Manager** is required)
|
||||
|
||||
### P - Place a prompt
|
||||
When you drag a saved preset (Chapter 7) onto the canvas,
|
||||
a **Prompt Text (WFS)** node containing the positive and negative prompts is placed.
|
||||
This is a node bundled with Workflow Studio, and it outputs the prompt text.
|
||||
|
||||
If you only want to paste the prompt, you can copy it with the **P** (positive) / **N** (negative) buttons on the item.
|
||||
|
||||
Subtabs: All / Favorites / Categories (by category) / Groups
|
||||
|
||||
### N - Place a node
|
||||
When you drag a node onto the canvas, that node is placed.
|
||||
If you register frequently used nodes as favorites in the **Nodes** tab of the main Workflow Studio, you can take them out quickly.
|
||||
In the N tab's list, **Alt + click** a node to switch its favorite on or off on the spot (v0.8.0 and later).
|
||||
The N tab opens faster than before, because it shows the list first without waiting for the nodes' detailed information.
|
||||
|
||||
Subtabs: All / Favorites / Groups / Sets / Category (by category) / Package (by custom-node package)
|
||||
|
||||
### Node sets - saving a frequently used combination as a whole
|
||||
A **node set** is a bundle of several nodes and their connections saved together.
|
||||
If you save "a group of nodes you always use in the same combination", you can place the whole thing with one drag.
|
||||
|
||||
**Making a node set**
|
||||
1. On ComfyUI's node screen, select the nodes you want to save (click while holding the Ctrl key, or drag to select a range).
|
||||
2. **Right-click** on the selected nodes and choose **Save as Node Set**.
|
||||
3. Save it with a name.
|
||||
|
||||
**Using a node set**
|
||||
From the **Sets** subtab of the WS Library's **N** tab, drag it onto the canvas.
|
||||
|
||||
> **Example**
|
||||
> It is handy to make sets of parts you want to add afterwards to any workflow,
|
||||
> such as "a group of nodes that automatically corrects faces" or "a group of nodes for upscaling".
|
||||
|
||||
---
|
||||
|
||||
## 9-3 Inspecting the contents of an image in the Information tab
|
||||
|
||||
The **I (Information)** tab is a feature that inspects image and workflow files and lets you
|
||||
**place the models and prompts that were used straight onto the canvas**.
|
||||
Think of it as the Gallery's metadata (Chapter 8, section 8-2) made usable inside the node screen.
|
||||
|
||||
### How to use it
|
||||
1. Open the **I** tab of the WS Library.
|
||||
2. Drop the file you want to inspect (a PNG, WebP, MP4 or WebM image or video made in ComfyUI, or a workflow JSON) onto the panel.
|
||||
3. The materials found in the file are shown, split into subtabs.
|
||||
|
||||
| Subtab | Contents | When dragged onto the canvas |
|
||||
| --- | --- | --- |
|
||||
| model | Checkpoint, VAE, Diffusion Model, Text Encoder | The corresponding loader node is placed |
|
||||
| lora | The LoRAs used and their strength | A LoRA loader node is placed |
|
||||
| Prompts | Positive (POS) and negative (NEG) prompts | A text-encode node containing the prompt is placed |
|
||||
|
||||
Clicking a prompt item shows the whole text, and **Copy** also copies it.
|
||||
|
||||
### When it is handy
|
||||
- "I want to build a new workflow with the same model and LoRAs as that image I made before"
|
||||
- "I just want to borrow the prompt from a workflow I found online"
|
||||
- "Which LoRA did this image use, and at what strength?"
|
||||
|
||||
The point is that rather than loading the whole workflow, **you can take out and use only the parts you need**.
|
||||
|
||||
---
|
||||
|
||||
## 9-4 Changing the look of the WS Library
|
||||
|
||||
From the **gear button** inside the WS Library panel, you can set the panel's colors.
|
||||
|
||||
- The panel's background color
|
||||
- The sub-header's background color
|
||||
- Text color, and the color of auxiliary text
|
||||
- Border color
|
||||
|
||||
If you adjust them to match ComfyUI's theme, you can use it without any sense of mismatch.
|
||||
The settings are saved in the browser and applied the next time you open it.
|
||||
|
||||
> **Summary of this chapter**
|
||||
> - The WS Library is a "shelf of materials" that opens beside ComfyUI's node screen
|
||||
> - From the W, N, M and P tabs, you can place workflows, nodes, models and prompts by dragging (or double-clicking)
|
||||
> - If you drag a model from the M tab, a loader node with the model already chosen is placed
|
||||
> - With "Save as Node Set" in the right-click menu, you can save a combination of frequently used nodes
|
||||
> - If you drop an image onto the I tab, you can take out and use the models, LoRAs and prompts that were used
|
||||
@@ -0,0 +1,437 @@
|
||||
# Chapter 10 AI TOOL - Making Local AI Your Assistant
|
||||
|
||||
Workflow Studio can work together with **local AI (large language models)** running inside your computer.
|
||||
If you prepare local AI, you can do things like the following.
|
||||
|
||||
- Translate what you thought up in your own language into an English prompt
|
||||
- Chat with the AI and have it come up with prompt ideas
|
||||
- Show it an image and have it make a description, prompt or tags for that image
|
||||
- Have it make candidate lists for wildcards
|
||||
- Pick a **skill** to switch what it is good at: writing prompts, storyboards, troubleshooting and more (v0.9.5+)
|
||||
- Have it check whether a generated image matches your request and fix only what is missing (v0.9.5+)
|
||||
- Read the text shown in an image (OCR, v0.9.5+)
|
||||
|
||||
Because it runs inside your own computer rather than as a service on the internet,
|
||||
a big feature is that **what you type and the images you use are not sent outside**.
|
||||
|
||||
> **Tip**
|
||||
> AI features are "nice to have" features. Even if you do not use them, all of Workflow Studio's basic features are available.
|
||||
> If your computer has room to spare (especially GPU memory), please give them a try.
|
||||
|
||||
---
|
||||
|
||||
## 10-1 Preparing local AI software
|
||||
|
||||
### Supported software
|
||||
Workflow Studio supports the following four pieces of local AI software.
|
||||
|
||||
| Software | Characteristics | Default address |
|
||||
| --- | --- | --- |
|
||||
| **Ollama** | The standard. Easy from downloading models to running them | `http://localhost:11434` |
|
||||
| **LM Studio** | Operated from a screen. You can also look for models inside the app | `http://localhost:1234` |
|
||||
| Lemonade Server | Easy to run on AMD GPUs and NPUs | `http://localhost:13305` |
|
||||
| Unsloth | Requires extra setup such as an API key (for advanced users) | `http://localhost:8888` |
|
||||
|
||||
For beginners, **Ollama** is recommended. This chapter explains using Ollama as the example.
|
||||
|
||||
> **Tip**
|
||||
> `localhost` in the address means "this computer", and the number after it is the **port number** (Chapter 2, section 2-4).
|
||||
> Just like ComfyUI, AI software also listens on its own fixed port number.
|
||||
|
||||
### Preparing Ollama
|
||||
1. From Ollama's official site, download the installer for your OS and install it.
|
||||
2. Start Ollama (on Windows it starts automatically after installation and stays resident in the taskbar's notification area).
|
||||
3. Download the AI model you will use. In Command Prompt or similar, type the following.
|
||||
|
||||
```
|
||||
ollama pull (model name)
|
||||
```
|
||||
|
||||
Model names can be checked in the model list on Ollama's official site.
|
||||
|
||||
> **Guide to choosing a model**
|
||||
> - **You also want the image-reading feature (VLM)** -> choose a model that supports image input (vision)
|
||||
> (in the author's testing, image generation and image reading work well with Gemma 4 `e4b` and similar)
|
||||
> - **GPU memory is small** -> choose a model with a small parameter count (a few B, that is a few billion)
|
||||
> - If translation accuracy matters, choose a model that is good at your language
|
||||
>
|
||||
> The world of AI models changes quickly, so please try newer models too.
|
||||
|
||||
> **Caution: competing for GPU memory**
|
||||
> Local AI also uses **GPU memory (VRAM)**, just like image generation.
|
||||
> If you run both at the same time, memory runs short and image generation slows down or errors out.
|
||||
> Countermeasures are explained in 10-3.
|
||||
|
||||
---
|
||||
|
||||
## 10-2 Using the AI TOOL tab
|
||||
|
||||
Open the **AI TOOL** tab of the main Workflow Studio.
|
||||
The screen is divided into four parts, all shown at the same time.
|
||||
|
||||
| Part | What you can do |
|
||||
| --- | --- |
|
||||
| Translate | Translation between languages such as Japanese, English and Chinese |
|
||||
| Chat | Conversation with the AI. Skills switch what it is good at. If the conditions are met, generating images from the conversation too |
|
||||
| TOOLS | Reading images (VLM), reading text (OCR), making wildcards |
|
||||
| Settings | Settings for which AI software and model to use |
|
||||
|
||||
> **Tip: Translate and Settings can be collapsed (v0.9.5+)**
|
||||
> Press the arrow (◀ / ▶) at the right end of the Translate or Settings header to collapse that part into a thin strip, giving Chat and TOOLS more room.
|
||||
> Click anywhere on the strip to open it again. The collapsed state is kept the next time you open the tab.
|
||||
|
||||
### First: connect to the AI software in the settings
|
||||
1. In **Backend** under the settings, choose the software to use (for example Ollama).
|
||||
2. Check the address under **Connection**. If you use Ollama with its defaults, no change is needed.
|
||||
3. Press **Test Connection**. If it shows success, it is OK.
|
||||
4. Press **Refresh** next to **Model** and choose the model to use from the list.
|
||||
5. Press **Save Settings**.
|
||||
|
||||
> **Tip**
|
||||
> The settings here are shared with the **A (AI TOOL)** tab of the WS Library on the ComfyUI side.
|
||||
> On the other hand, the Prompt tab (Chapter 7) and the Tagger tab each have their own **gear button** settings.
|
||||
> If "it works in the AI TOOL tab but the Prompt tab says Disconnected", set the same thing with the gear button in the Prompt tab as well.
|
||||
|
||||
> **If it does not connect well**
|
||||
> - Check that software such as Ollama is running.
|
||||
> - For LM Studio, you need to **start the server** inside the app.
|
||||
> - Check that the port number in the address matches the software's settings.
|
||||
> - If the model list is empty, check that the model has been downloaded.
|
||||
|
||||
### Translate
|
||||
1. Choose the source and target languages (swap them with the **swap** button).
|
||||
2. Write the text in the input box and press **Translate**.
|
||||
3. **Copy** the result and paste it into GenerateUI or a preset.
|
||||
|
||||
> **Tip**
|
||||
> Text read in TOOLS (such as OCR in 10-8) can be put straight into this input box with **To Translation** in TOOLS.
|
||||
|
||||
> **Tip**
|
||||
> Small models sometimes return the original text as it is without translating.
|
||||
> In that case a message says the model returned the original text, so try another model.
|
||||
|
||||
### Chat
|
||||
Talk in the input box and send with **Enter** (**Shift + Enter** for a line break).
|
||||
It remembers the flow of the conversation, so follow-up requests such as "make it a brighter mood" also work.
|
||||
**Clear** resets the conversation.
|
||||
|
||||
> **Tip: generating images from chat (advanced)**
|
||||
> If you use a model that supports "Tool Calling",
|
||||
> just asking in chat "draw a cat" generates an image with the workflow loaded in GenerateUI, and it is shown inside the chat.
|
||||
> This feature can be turned on or off with the **Allow image generation** check next to the input box.
|
||||
|
||||
> **Tip**
|
||||
> Choose a **skill** in the dropdown above the chat to switch what the AI is good at (10-5).
|
||||
> The AI's replies are shown with headings, lists and code boxes formatted (v0.9.5+).
|
||||
|
||||
### TOOLS - reading images (VLM)
|
||||
With a model that supports image input (a VLM), you can have the AI read the contents of an image.
|
||||
|
||||
1. Drop an image (PNG / JPG / WebP) into the **TOOLS** frame.
|
||||
2. Choose a task.
|
||||
|
||||
| Task | Contents |
|
||||
| --- | --- |
|
||||
| Describe | Explains in text what is in the image |
|
||||
| Create prompt | Makes a prompt for reproducing the image |
|
||||
| Create tags | Writes out the elements of the image in tag format |
|
||||
| Create wildcards | Makes candidate wildcard lists by specifying a category name and count (no image needed) |
|
||||
| OCR (extract text) | Reads the text shown in the image (10-8) |
|
||||
|
||||
3. Press **Run**.
|
||||
4. Use the result with the buttons under it (v0.9.5+).
|
||||
|
||||
| Button | What it does |
|
||||
| --- | --- |
|
||||
| To Translation | Puts it into the Translate input box (opens Translate if it is collapsed) |
|
||||
| To Chat | Adds it to the chat input box |
|
||||
| Copy | Copies it to the clipboard |
|
||||
|
||||
> **Example**
|
||||
> When you want to imitate the mood of an illustration you like, run "Create prompt" on that image
|
||||
> and try the resulting prompt in GenerateUI - you can use it like that.
|
||||
|
||||
### It can be used inside the ComfyUI screen too
|
||||
The same AI features can also be used in the **A** tab of the WS Library on the ComfyUI side.
|
||||
Handy when you want to translate something briefly while working on the node screen.
|
||||
|
||||
---
|
||||
|
||||
## 10-3 Freeing VRAM and managing memory
|
||||
|
||||
As touched on in 10-1, local AI and image generation compete for GPU memory (VRAM).
|
||||
Ollama keeps a model that has been used in memory for a while,
|
||||
so if you generate images after using the AI, memory may run short.
|
||||
|
||||
### Freeing manually
|
||||
Pressing **Unload Model** in the AI TOOL settings takes the AI model out of memory and frees VRAM.
|
||||
(With Ollama, all loaded models are unloaded)
|
||||
|
||||
### Freeing automatically before generation
|
||||
In **VRAM Management (Ollama)** in the Settings tab, you can set Ollama's models to be unloaded automatically just before image generation.
|
||||
|
||||
| Behavior before generation | What it does |
|
||||
| --- | --- |
|
||||
| Do nothing | Does not unload automatically |
|
||||
| Unload what is needed only when free memory is below the target | Unloads only when free VRAM is less than the **Target free VRAM (GB)** |
|
||||
| Unload everything every time | Always unloads everything at every generation |
|
||||
|
||||
> **Tip**
|
||||
> If you can't decide which to choose, "Unload what is needed only when free memory is below the target" is recommended.
|
||||
> For the target free VRAM, enter a rough value of the amount of memory image generation needs (it differs by the model you use).
|
||||
> The **Unload all now** button can also free it immediately, on the spot.
|
||||
|
||||
> **Caution**
|
||||
> This automatic unloading applies to Ollama only. If you use LM Studio or similar, free memory manually.
|
||||
|
||||
---
|
||||
|
||||
## 10-4 Security notes
|
||||
|
||||
### By default it connects only to AI on "your own computer"
|
||||
For safety, the AI software Workflow Studio connects to (Ollama, LM Studio and so on) is by default limited to
|
||||
**software running inside the same computer (localhost / 127.0.0.1)**.
|
||||
|
||||
### When you want to use AI on another computer
|
||||
If you want to run Ollama on another computer on your home LAN (such as a computer with a strong GPU) and use it,
|
||||
register the address of the computer you want to connect to in the environment variable **`WFS_ALLOWED_BACKEND_HOSTS`**, and restart ComfyUI.
|
||||
|
||||
```
|
||||
WFS_ALLOWED_BACKEND_HOSTS=192.168.1.20:11434
|
||||
```
|
||||
|
||||
If there are several, list them separated by commas (,).
|
||||
How to set environment variables differs depending on how you start ComfyUI.
|
||||
|
||||
### If you start ComfyUI with `--listen`
|
||||
If you start ComfyUI with the `--listen` option, other computers and smartphones on the same network
|
||||
can also access ComfyUI (and Workflow Studio).
|
||||
In that case, anyone who can access it can use your AI software and images.
|
||||
|
||||
> **Caution**
|
||||
> Use `--listen` **only on a trusted network**, such as a home LAN.
|
||||
> Do not use it in cafes or on public Wi-Fi.
|
||||
|
||||
---
|
||||
|
||||
## 10-5 Skills - switching what the chat is good at (v0.9.5+)
|
||||
|
||||
A **skill** is a set of instructions that tells the chat what role to play and how to answer.
|
||||
When you pick one in the dropdown above the chat (it starts as "-- No skill --"), its instructions are sent along with every message
|
||||
(the instructions themselves are not shown in the chat).
|
||||
|
||||
### Built-in skills
|
||||
Workflow Studio comes with the following six skills.
|
||||
|
||||
| Skill | What it does | How you use the result |
|
||||
| --- | --- | --- |
|
||||
| T2I Prompt Enhancer | Turns a short idea into a prompt written the way the model in your GenerateUI workflow understands best | Buttons under the prompt |
|
||||
| Image to Prompt | Writes a prompt that recreates the image you put in TOOLS (needs a model that can read images) | Buttons under the prompt |
|
||||
| Storyboard to Lab | Splits a story into one prompt per scene, ready for continuous generation in Lab | **Open in Lab** |
|
||||
| Workflow Doctor | Explains the workflow and helps you find the cause of errors (10-7) | Answers in text |
|
||||
| SVG Icon Generator | Draws simple icons and illustrations as SVG (vector images) | Preview and **Save to Gallery** |
|
||||
| Skill Creator | Asks you questions and builds a new skill (10-9) | **Save as new skill** |
|
||||
|
||||
### Making a prompt and generating with it (T2I Prompt Enhancer)
|
||||
1. Load the workflow you want to use into GenerateUI. The skill looks at that workflow's model to decide how to write the prompt.
|
||||
2. In the AI TOOL chat, choose **T2I Prompt Enhancer** in the dropdown.
|
||||
3. Describe the picture in your own words, for example "a cat holding an umbrella in rainy Tokyo at night, neon", and send it.
|
||||
4. The reply shows which writing style was chosen (the `Style:` line) and the English prompt in a box. Use the buttons under it.
|
||||
|
||||
| Button | What it does |
|
||||
| --- | --- |
|
||||
| Apply to GenerateUI | Writes the positive / negative prompt into GenerateUI |
|
||||
| Generate with this prompt | Generates right away and shows the image in the chat |
|
||||
| Copy | Copies the positive prompt |
|
||||
|
||||
The writing style depends on the model:
|
||||
|
||||
| Model in GenerateUI | How the prompt is written |
|
||||
| --- | --- |
|
||||
| Qwen-Image, FLUX, Z-Image, etc. | English sentences (the negative is left empty when CFG is about 1) |
|
||||
| Illustrious, NoobAI, Pony, etc. (SDXL anime models) | Danbooru tags (starting with quality tags) |
|
||||
| Realistic SDXL, SD1.5 | Short phrases separated by commas |
|
||||
|
||||
> **Tip**
|
||||
> Follow-up requests such as "make it more night-like" or "two cats" give you the whole updated prompt again.
|
||||
|
||||
> **Tip: the prompt currently in GenerateUI is not sent**
|
||||
> Normally the prompt already typed into GenerateUI is not passed to the AI, because small models tend to mix it (for example an old negative prompt) into the new prompt.
|
||||
> It is passed only when your message refers to it, such as "**improve the current prompt**".
|
||||
|
||||
### Generating a storyboard in a row (Storyboard to Lab)
|
||||
1. Load a text-to-image (T2I) workflow into GenerateUI.
|
||||
2. In the chat, choose **Storyboard to Lab** and ask, for example, "A tabby kitten wakes up in the morning, chases a butterfly in the garden, and naps on the veranda in the evening. 3 scenes."
|
||||
3. The reply shows the scene list and an **Open in Lab (3 scenes)** button. Press it.
|
||||
4. GenerateUI's **Lab** (Chapter 5, section 5-7) opens with the plan loaded as an unsaved plan.
|
||||
T2I mode is on, Batch is the number of scenes, and the Prompt column has one keyframe per scene. The KSampler column holds a seed shared by all scenes (`Seed ...`).
|
||||
5. Check it and press **Run**. To keep it, use **Plan Save**.
|
||||
|
||||
> **Tip**
|
||||
> The characters' looks (hair, clothing colors and so on) are written with the same words in every scene, and the seed is fixed,
|
||||
> so the same character is easier to keep across scenes.
|
||||
|
||||
### Automatic check of replies
|
||||
For skills that output a prompt or an SVG, Workflow Studio checks the shape of the reply automatically.
|
||||
If, for example, the prompt box is broken or the SVG is not closed, a dashed notice "**Auto-check: ...**" appears and the AI is asked once to fix it.
|
||||
Replies that do not try to output a prompt or SVG (for example when you only asked for an explanation) are left alone.
|
||||
|
||||
### Managing skills (pencil button)
|
||||
The pencil button to the right of the dropdown opens the skill list.
|
||||
|
||||
- **+ New** writes a new skill, the pencil on each row edits or deletes it, and **Import** adds other skills (10-9)
|
||||
- Skills that ship with Workflow Studio are marked **built-in**.
|
||||
Built-in skills you have not edited are updated automatically when Workflow Studio is updated.
|
||||
An edited one is not replaced automatically; when a newer version exists, a **↻ (update)** button appears.
|
||||
- Skill files are saved in `ComfyUI/user/default/Workflow-Studio/ai_skills/`.
|
||||
|
||||
> **Caution**
|
||||
> Replacing a skill with the newer version via ↻ (update) discards your edits to that skill.
|
||||
|
||||
---
|
||||
|
||||
## 10-6 Checking generated images and fixing them (v0.9.5+)
|
||||
|
||||
This feature has the AI check whether an image generated from the chat matches what you asked for.
|
||||
If something is missing, you can redraw with a prompt that fixes just that.
|
||||
|
||||
### Preparation: a judging model
|
||||
The check does not use a normal chat model but an Ollama **decision model** (a model that answers yes/no questions with a probability).
|
||||
Get one that can read images with `ollama pull` (the author confirmed `d3:4b`, `clef-flash` and `clef`).
|
||||
|
||||
> **Tip: why a separate model**
|
||||
> In the author's tests, a chat model shown an image sometimes answered "yes" to "is the person holding a sword?" when there was no sword.
|
||||
> A decision model returns the probability of "yes" as a number, so uncertain answers can be told apart.
|
||||
|
||||
1. In AI TOOL's **Settings**, under **Chat Image Check**, choose the **Judge model (Ollama decision model)** (press **Refresh** if the list is empty).
|
||||
2. Choose **Automatic fix rounds**. **0 (fix by button)** is recommended at first.
|
||||
3. Press **Save Settings**.
|
||||
|
||||
### How to use it
|
||||
1. Tick **Check images** below the chat input.
|
||||
2. Generate an image from the chat (the AI's image generation, or **Generate with this prompt**).
|
||||
3. A result card appears under the image. The AI splits your request into 3 to 8 check items and checks them one by one.
|
||||
|
||||
| Mark | Meaning |
|
||||
| --- | --- |
|
||||
| ✔ (met) | Probability of "yes" is 85% or more |
|
||||
| ? (unclear) | 30-85% |
|
||||
| ✘ (not met) | Less than 30% |
|
||||
|
||||
4. If there is a ✘ or ?, press **Fix missing items and regenerate**. Only the unmet items are sent to the AI, which rewrites the prompt and draws again.
|
||||
|
||||
If you set Automatic fix rounds to 1-3, this repeats automatically up to that number of times.
|
||||
|
||||
> **Tip: SVGs can be checked too**
|
||||
> SVGs drawn with SVG Icon Generator are turned into an image and checked for "does it look like what you asked for" and "are its parts (beak, wings and so on) drawn".
|
||||
> **Ask to redraw unclear parts** asks the AI to fix them.
|
||||
|
||||
> **Caution**
|
||||
> - The check is not perfect. It is especially weak at "who is wearing what",
|
||||
> so when there are several people it automatically adds reverse check items such as "the hat is not on the girl" to compensate.
|
||||
> - How well the redraw works depends on the chat model. If it does not improve, change your request or the model.
|
||||
> - The judging model also uses GPU memory (about 6 GB for `d3:4b`). Once loaded, a check takes a few seconds.
|
||||
|
||||
---
|
||||
|
||||
## 10-7 Asking about workflow problems (Workflow Doctor, v0.9.5+)
|
||||
|
||||
**Workflow Doctor** is a skill that explains the workflow loaded in GenerateUI and helps you find the cause of errors.
|
||||
Instead of relying only on the AI's knowledge, every time you send a message Workflow Studio passes it the following facts it has actually checked.
|
||||
|
||||
| What is checked | Example |
|
||||
| --- | --- |
|
||||
| Nodes that are not installed | Names of nodes ComfyUI does not know |
|
||||
| Files and values not in ComfyUI's lists | Models or LoRAs that cannot be found (with similar names) |
|
||||
| Connections | Inputs that are not connected, links to nodes that do not exist |
|
||||
| The last execution error | The error recorded in ComfyUI's history |
|
||||
| ComfyUI's log | The latest error part of the log |
|
||||
|
||||
### How to use it
|
||||
1. Load the workflow you want to ask about into GenerateUI (for an error, run it once so the error is recorded).
|
||||
2. In the chat, choose **Workflow Doctor**.
|
||||
3. Ask, for example, "check this workflow for problems before I run it" or "what caused the last error?".
|
||||
|
||||
> **Example**
|
||||
> For a workflow whose LoRA file had been moved to another folder, it answered
|
||||
> "the file specified in the `temp\` folder cannot be found; a file with the same name exists in `Illustrious\`", including how to fix it.
|
||||
|
||||
> **Tip**
|
||||
> The checked facts are rebuilt every time you send a message. After fixing something, just ask again.
|
||||
|
||||
---
|
||||
|
||||
## 10-8 Reading text in images (OCR, v0.9.5+)
|
||||
|
||||
In TOOLS you can read the text shown in an image. The text you read can be sent straight to translation or the chat.
|
||||
|
||||
### Preparation: an OCR model
|
||||
OCR uses a model that is good at reading text, separate from the chat model. Prepare one in Ollama.
|
||||
These are the author's results on an image mixing horizontal and vertical Japanese and English text.
|
||||
|
||||
| Model | Time | Result |
|
||||
| --- | --- | --- |
|
||||
| LightOnOCR-3 (`maternion/LightOnOCR-3:4b`) | About 1 s (6-8 s with positions) | Read everything |
|
||||
| PaddleOCR-VL (manga version) | About 4 s | Read everything |
|
||||
| DeepSeek-OCR family | About 14 s | Read everything (always with positions) |
|
||||
| PaddleOCR-VL 1.6, GLM-OCR | About 11-15 s | Missed the vertical text |
|
||||
|
||||
### How to use it
|
||||
1. Drop an image into TOOLS.
|
||||
2. Choose **OCR (extract text)** as the task.
|
||||
3. Choose the **OCR model**. Ollama models whose name contains "ocr" are listed, best first (press ↻ if the list is empty).
|
||||
4. Press **Run**. The text is shown in the result box, one line each.
|
||||
|
||||
> **Tip: Show text positions**
|
||||
> Tick **Show text positions** to draw numbered boxes over the image so you can see where each text is.
|
||||
> Clicking a box selects the same line in the result box.
|
||||
> Only LightOnOCR and the DeepSeek-OCR family can return positions; for other models this check cannot be selected.
|
||||
|
||||
> **Tip**
|
||||
> If the result is empty or the same line repeats, it is automatically read once more in grayscale.
|
||||
|
||||
---
|
||||
|
||||
## 10-9 Making and importing skills (advanced, v0.9.5+)
|
||||
|
||||
### Making one with Skill Creator
|
||||
In the chat, choose **Skill Creator** and say something like "I want a skill that is good at ...".
|
||||
The AI asks questions one at a time; answer them and you get a draft skill.
|
||||
Press **Save as new skill** under the reply; the skill list opens with the draft filled in, so check it and save.
|
||||
You can also ask it to improve an existing skill, for example "this part of this skill does not work well".
|
||||
|
||||
### What a skill file contains
|
||||
A skill is a text file (`.md`). Write the name and description in the part enclosed by `---` at the top, and the instructions for the AI below it.
|
||||
Under `metadata:` in the top part you can also write these settings (all optional).
|
||||
|
||||
| Setting | Meaning |
|
||||
| --- | --- |
|
||||
| `output` | `prompt` or `svg`. Checks the shape of the reply automatically and adds the buttons |
|
||||
| `tools` | `[]` stops the AI from starting image generation on its own |
|
||||
| `temperature` | How varied the answers are (0.3 stable, 0.9 free) |
|
||||
| `think` | Turns Thinking mode on or off just for this skill |
|
||||
| `context` | Information passed to the AI: `workflow` (workflow summary), `current-prompt` (the current prompt), `workflow-detail` / `logs` (the same checks as Workflow Doctor) |
|
||||
|
||||
### Importing other skills
|
||||
**Import** in the skill list adds:
|
||||
|
||||
- a single `.md` skill
|
||||
- a ZIP of a folder containing `SKILL.md` (the **Agent Skills** format shared by many AI tools)
|
||||
|
||||
Text files in the folder (reference material and so on) are imported too, and the AI reads them only when it needs them
|
||||
(this needs a model that supports tool calling).
|
||||
|
||||
> **Caution**
|
||||
> - Only text files are imported. Programs such as scripts are not imported and never run.
|
||||
> - A skill's instructions are passed to the AI as they are. Read a skill made by someone else before using it.
|
||||
|
||||
> **Summary of this chapter**
|
||||
> - If you prepare local AI (Ollama and so on), you can translate, chat and read images. What you type is not sent outside
|
||||
> - In the AI TOOL tab's settings, choose the backend, address and model, and test the connection
|
||||
> - The Prompt tab and Tagger tab have separate gear-button settings
|
||||
> - AI and image generation compete for VRAM. Free it with "Unload Model" or "VRAM Management (Ollama)"
|
||||
> - By default it connects only to AI on your own computer. Use `--listen` only on a trusted network
|
||||
> - **Skills** switch what the chat is good at. T2I Prompt Enhancer writes a prompt that buttons apply to GenerateUI or generate with
|
||||
> - With **Check images** on, a decision model checks the generated image and you can redraw fixing only what is missing
|
||||
> - Workflow Doctor helps with workflow problems based on facts it has actually checked
|
||||
> - **OCR (extract text)** in TOOLS reads the text in an image and sends it to translation or the chat
|
||||
@@ -0,0 +1,347 @@
|
||||
# Chapter 11 Even More Features (Overview)
|
||||
|
||||
By now, you have covered the basic usage of Workflow Studio from start to finish.
|
||||
This chapter introduces the tabs and features not yet covered, focusing on **what you can do with them**.
|
||||
You do not need to use everything right now. Keep in the back of your mind that "you can do this too",
|
||||
and try them when you need them.
|
||||
|
||||
---
|
||||
|
||||
## 11-1 The Nodes tab - listing the installed nodes
|
||||
|
||||
In the **Nodes** tab, you can list all the nodes installed in ComfyUI.
|
||||
|
||||
- **Search and filtering** - narrow down by name, category and package (which custom node it belongs to). Even with thousands of nodes, the list appears first and search runs lightly (v0.8.0 and later).
|
||||
- **Detail panel** - when you select a node, you can check the kinds of its inputs and outputs (the I/O specification).
|
||||
- **Favorites, groups and tags** - organize the nodes you use often.
|
||||
|
||||
Nodes you register as favorites or in groups here are shown in the **N** tab of the WS Library,
|
||||
and can be placed by dragging onto the node screen (Chapter 9).
|
||||
|
||||
> **When it helps**
|
||||
> "I installed a custom node but can't tell what nodes were added"
|
||||
> -> narrow down by **Package** and you can see the list of nodes contained in that custom node.
|
||||
|
||||
---
|
||||
|
||||
## 11-2 Tagger - automatically making tags from images
|
||||
|
||||
The **Tagger** tab is a feature that reads an image and automatically makes tags that describe it (such as `1girl, long hair, smile`).
|
||||
It can be used for making prompts for anime-style models, and for tagging images for training.
|
||||
|
||||
### Three subtabs
|
||||
| Subtab | What you can do |
|
||||
| --- | --- |
|
||||
| Single | Make tags from one image |
|
||||
| Batch | Tag the images in a folder in bulk (it can also write out a `.txt` file with the same name as each image) |
|
||||
| DB | Search and edit the records of images you tagged |
|
||||
|
||||
### How to use it (Single)
|
||||
1. Drop an image onto the preview area (you can also open it from the **Tagger** button in the Gallery's detail panel).
|
||||
2. Choose the model to use and press the run button to make tags.
|
||||
3. Use the result.
|
||||
|
||||
| Button | What it does |
|
||||
| --- | --- |
|
||||
| GenUI:P | Adds it to GenerateUI's positive prompt |
|
||||
| Send to Prompt | Adds it to the positive prompt in the Prompt tab |
|
||||
|
||||
With the **threshold** slider, you can adjust how certain a tag must be to be shown.
|
||||
Raising the number leaves only fewer, more certain tags; lowering it gives more.
|
||||
|
||||
### Preparation needed
|
||||
To use Tagger, you need the following preparation.
|
||||
|
||||
1. Put a **model for tagging** (such as WD Tagger) in ComfyUI's `models/tagger/(model name)/` folder.
|
||||
Put a `.onnx` file and `selected_tags.csv` in the folder.
|
||||
**PixAI Tagger v1.0** (v0.8.10 and later) also works. From the community conversion on Hugging Face (`Mexes/pixai-tagger-v1.0-onnx-fp32-fp16-int8`),
|
||||
put one `.onnx` file (`model_fp16.onnx` is recommended for a GPU) together with `selected_tags.csv` and `preprocess.json` in one folder, and it is detected automatically.
|
||||
When you choose a PixAI model, the threshold sliders switch to PixAI's recommended values (0.17 / 0.27).
|
||||
2. Install the **extra Python packages**.
|
||||
Use the `requirements.txt` in the Workflow Studio folder.
|
||||
|
||||
```
|
||||
(ComfyUI's Python) -m pip install -r requirements.txt
|
||||
```
|
||||
|
||||
The location of "ComfyUI's Python" differs by environment. Check the table in Chapter 2, section 2-6
|
||||
(for example, for the Windows portable version it is `python.exe` inside the `python_embeded` folder).
|
||||
|
||||
> **Caution**
|
||||
> Installing into the Python that was already on your computer cannot be used from ComfyUI.
|
||||
> Always install into **the Python that ComfyUI uses**.
|
||||
> If you are not sure, there is also a method of installing packages with a ComfyUI Manager feature.
|
||||
|
||||
> **Caution: check that it runs on the GPU**
|
||||
> On an NVIDIA GPU, Tagger takes less than a second per image, but on the CPU, PixAI takes about 20 seconds per image.
|
||||
> If it is very slow, check that the GPU package is installed correctly (Chapter 12, section 12-5).
|
||||
|
||||
> **Tip**
|
||||
> You can also combine it with the local AI image reading (VLM) from Chapter 10 to make tags that combine both results.
|
||||
|
||||
---
|
||||
|
||||
## 11-3 Image Edit - touching up generated images
|
||||
|
||||
The **Image Edit** tab is a simple image-editing tool with layers.
|
||||
You can put text on a generated image, or make a mask for redrawing part of it.
|
||||
|
||||
### Main features
|
||||
| Tool | What you can do |
|
||||
| --- | --- |
|
||||
| Select | Move, scale and rotate layers |
|
||||
| Draw | Draw with a pen (pen-tablet pressure is also supported) |
|
||||
| Text | Put in text |
|
||||
| Shape | Draw rectangles, circles and lines |
|
||||
| Fill | Fill and gradients |
|
||||
| Mask | Specify the part you want redrawn (making a mask) |
|
||||
| Blur | Blur and mosaic |
|
||||
| BG Remove | Remove the background |
|
||||
| Inpaint | Redraw the masked part with the GenerateUI workflow |
|
||||
|
||||
- Open an image by drag and drop, **File Open**, or the **Image Edit** button in the Gallery.
|
||||
- Save the edited image with **Save PNG** (download), **Save to Gallery** and so on.
|
||||
- Undo with **Ctrl + Z**, redo with **Ctrl + Y**.
|
||||
|
||||
### Draw colors and shortcuts (v0.9.3+)
|
||||
When you choose **Draw**, a **color palette** appears in the second row of the tool options.
|
||||
|
||||
- It shows **Color 1 / Color 2**, 20 basic colors and 20 custom slots. Click a color to paint with it.
|
||||
- Click **+** or an empty slot to register the current color as a custom color. Right-click a color to register, edit or delete it (basic colors can be changed too, and returned to their original color).
|
||||
Registered colors are saved per browser.
|
||||
- The **eyedropper** button next to **Color** on the right picks a color from the canvas (Esc cancels).
|
||||
- The starting colors are black (Color 1) and white (Color 2).
|
||||
|
||||
| Key (while Draw is active) | What it does |
|
||||
| --- | --- |
|
||||
| D / E | Draw / Erase |
|
||||
| X | Swap Color 1 and Color 2 |
|
||||
| [ / ] | Make the brush smaller / larger |
|
||||
| B | Open or close the brush picker (Esc also closes it) |
|
||||
|
||||
### Inpainting (redrawing part of an image)
|
||||
The handiest use of Image Edit is **inpainting**.
|
||||
It is for when "I want to redraw only the face" or "I want to fix only the place where the hand broke".
|
||||
|
||||
1. Load an inpainting workflow (such as the bundled sample `ws_inpaint_basic`) into GenerateUI.
|
||||
2. Open the image in Image Edit and paint the part you want redrawn with **Mask**.
|
||||
3. Run it with the **Inpaint** tool, and only the painted part is redrawn.
|
||||
|
||||
> **Tip**
|
||||
> To use a higher-quality version of background removal, or more advanced masking,
|
||||
> the author's separate custom node **comfyui-mask-editor-one** is needed.
|
||||
> Saving and loading in PSD format requires an extra Python package (psd-tools).
|
||||
|
||||
---
|
||||
|
||||
## 11-4 Video - making and joining videos
|
||||
|
||||
The **Video** tab is a dedicated screen for making short videos from images or text using video-generation models.
|
||||
|
||||
### Supported video-generation models
|
||||
- **MiniMax H3** (image to video)
|
||||
- **LTX-2.5** (text to video, image to video, and video from specified first and last images)
|
||||
- **Wan2.2** (text to video)
|
||||
- **FastH3 OmniRef / Pika-H3-Flex** (MiniMax H3 reference to video, v0.8.14 and later)
|
||||
|
||||
You load a matching workflow with **Load in Video** in the Workflow tab and use it (Chapter 4, section 4-6).
|
||||
|
||||
### Main features
|
||||
| Subtab | What you can do |
|
||||
| --- | --- |
|
||||
| Plan | Divide a video into "blocks", decide the prompt, length and first/last image for each block, and generate in order |
|
||||
| Edit | Line up generated videos and images, then cut, join, add text and BGM, and export |
|
||||
| Asset | List generated videos, images and audio. Audio can be set as BGM or added as sound (the Audio Only type filter shows audio only) |
|
||||
|
||||
There are also the **Frame** feature, which saves a favorite scene of a video as a still image, and **GIF**, which converts a video to an animated GIF.
|
||||
|
||||
### Register as Asset and audio conversion (v0.8.9 and later)
|
||||
- **Register as Asset** - a button in the Video Source panel on the left. It copies a video from your PC into the output folder (`output/video`) and registers it in the "Video Assets" group.
|
||||
Once registered, it appears in the Asset subtab list and can be used in Edit and elsewhere.
|
||||
Videos already in the output folder (ones chosen in Asset or generation results) are only tagged into the group, not copied. If the name already exists, a number is added after it.
|
||||
- **Convert audio...** - a button next to the crop buttons in the Edit subtab. It converts only the audio of the selected video clip to FLAC, MP3, Opus, M4A or WAV and saves it into `output/video`.
|
||||
It is the same dialog as Gallery's Convert. Only video clips that contain audio are covered.
|
||||
- Pressing the audio-conversion button opens the dialog below. Choose the **output format** (such as FLAC), the **sample rate** and the **channels**, then press **Convert**.
|
||||
If you check the option to carry over the embedded prompt/workflow tags, the original video's information is kept in formats that can hold tags (such as FLAC).
|
||||
|
||||
- The Video Source panel is a little wider, the file name shows on one line, and the buttons sit in a single row.
|
||||
|
||||
### Reference to video (FastH3 OmniRef / Pika-H3-Flex) (v0.8.14 and later)
|
||||
These workflows make a video from **reference images** instead of a first and last frame,
|
||||
so the image fields in the Plan subtab are renamed:
|
||||
|
||||
- **Reference Image** - the first reference image (the usual First Image field)
|
||||
- **Reference Image 2 (optional)** - the second reference image (the usual Last Image field)
|
||||
|
||||
- Prompt, duration (seconds), aspect ratio and so on work the same as for other video workflows.
|
||||
- A block whose image field is left empty with **None** or **Clear** is generated without that image, even if the workflow has a reference image wired in.
|
||||
Blocks added with "+ Block" start with empty images, so set an image on each block that needs a reference.
|
||||
- Choosing **Use previous block's last frame** makes the last frame of the video actually generated by the previous block the first reference image of that block.
|
||||
- The Asset subtab buttons also change to "Set as Reference Image" and "Set as Reference Image 2".
|
||||
|
||||
> **Caution**
|
||||
> Video generation uses far more GPU memory and time than image generation.
|
||||
> Check the required specs of the model before trying it.
|
||||
|
||||
---
|
||||
|
||||
## 11-5 Main items of the Settings tab
|
||||
|
||||
In the **Settings** tab, you configure Workflow Studio as a whole.
|
||||
Items are collapsed, so click a heading to open it.
|
||||
Here we mainly introduce items not covered in earlier chapters.
|
||||
|
||||
| Item | Contents | Related chapter |
|
||||
| --- | --- | --- |
|
||||
| Theme | Screen color scheme and font | Chapter 3 |
|
||||
| UI Language / Summary Language | Display language | Chapter 2 |
|
||||
| Text Size | Size of text such as in the prompt fields | Chapter 3 |
|
||||
| Workflow Data Folder | The folder workflows are read from | Chapter 4 |
|
||||
| Gallery Output Folder | The folder shown in the Gallery | Chapter 8 |
|
||||
| Default Workflow | The workflow automatically loaded into GenerateUI when you open Workflow Studio | Below |
|
||||
| Default Checkpoint | Automatically replaces the model when loading a workflow into GenerateUI | Below |
|
||||
| CivitAI API Key | For fetching Civitai information (optional) | Chapter 6 |
|
||||
| Eagle integration (optional) | Automatically save generated images to Eagle | Chapter 8 |
|
||||
| VRAM Management (Ollama) | Unload AI models from memory before generation | Chapter 10 |
|
||||
| Data Management | Backing up and restoring settings and data | Below |
|
||||
|
||||
### Default Workflow
|
||||
If you set the basic workflow you always use, it is loaded into GenerateUI automatically when you open Workflow Studio.
|
||||
You can also set it with the **Set as Default** button on the Workflow tab's detail screen.
|
||||
|
||||
### Default Checkpoint
|
||||
Workflows you get online often specify models you do not have (Chapter 5, section 5-3).
|
||||
If you set a **Default Checkpoint** and turn it on, each time you load a workflow into GenerateUI,
|
||||
the Checkpoint is automatically replaced with the specified model. It saves the trouble of choosing a model again.
|
||||
|
||||
### Data Management (backup)
|
||||
In **Data Management**, you can write out the information you organized in Workflow Studio (favorites, badges, groups, presets and so on)
|
||||
to a file (Export), and read it back to restore it (Import).
|
||||
|
||||
With **Full Backup (ZIP)**, you can back up everything together, including folder-based data such as styles and Lab plans.
|
||||
|
||||
> **Tip**
|
||||
> Always take a backup before buying a new computer or reinstalling ComfyUI.
|
||||
> The information you spent time organizing can be carried over as it is to the new environment.
|
||||
> (For safety, API keys are not included in backups)
|
||||
|
||||
## 11-6 A companion app: ComfyUI Comic Creator - making manga from generated images
|
||||
|
||||
**ComfyUI Comic Creator** (Comic Creator from here on) is a custom node **for making manga** that runs on ComfyUI,
|
||||
developed by the same author as Workflow Studio.
|
||||
It is software you install separately from Workflow Studio, but if you install both, they work together.
|
||||
|
||||
### What you can do with Comic Creator
|
||||
| Feature | Contents |
|
||||
| --- | --- |
|
||||
| Panel layout | Choose a template and make panels on a page (your own templates can also be registered) |
|
||||
| Placing images | Place images into panels by drag and drop |
|
||||
| Speech balloons and text | Vertical and horizontal dialogue, balloons of various shapes, sound-effect text |
|
||||
| Manga effects | Add speed lines, screen tones, halftone dots and so on |
|
||||
| Image editing | Image editing with layers (the Image tab) |
|
||||
| Automatic creation with AI | Draft a story, script and panel layout from a theme with AI (the Auto tab) |
|
||||
| Export | Output as JPEG / PNG / WebP / SVG / PDF / **EPUB** |
|
||||
|
||||
### Working together with Workflow Studio
|
||||
If you install both, the following integrations are possible.
|
||||
|
||||
- **Use Workflow Studio's Gallery inside Comic Creator**
|
||||
Workflow Studio's Gallery appears inside Comic Creator, and you can choose generated images and send them to panels with **Send CC Layout** (Layout tab panel / overlay) or to the Image tab with **Send CC Image**.
|
||||
(The Send CC buttons are shown only in a Gallery opened inside Comic Creator)
|
||||
- **Generate images from Comic Creator**
|
||||
From the Comic Creator screen, through Workflow Studio (GenerateUI), you can generate images to put in panels (T2I),
|
||||
or redraw based on a rough you drew or an image you placed (I2I and inpainting).
|
||||
From Comic Creator's Nanobanana+ tab (local mode), you can also run image-editing workflows that use several reference images (Flux.3 Klein, Qwen Image 2.1 and so on) (v0.8.12 and later).
|
||||
|
||||
With the flow "make images in Workflow Studio -> put them together as manga in Comic Creator",
|
||||
you can go from image generation to finished manga entirely inside ComfyUI.
|
||||
|
||||
### Installing and launching
|
||||
1. In ComfyUI Manager's **Install via Git URL**, enter the following URL and install.
|
||||
|
||||
```
|
||||
https://github.com/ketle-man/comfyui-comic-creator
|
||||
```
|
||||
|
||||
(For a manual install, `git clone` into `ComfyUI/custom_nodes/`, same as Workflow Studio)
|
||||
|
||||
2. Restart ComfyUI.
|
||||
3. Press the **CC** button added to ComfyUI's top menu, and Comic Creator opens in a new tab.
|
||||
|
||||
> **Tip**
|
||||
> For detailed usage of Comic Creator, see the **Help** tab inside the app (with search).
|
||||
|
||||
---
|
||||
|
||||
## 11-7 TagSpace - picking tags and prompts from a "map of meaning" (v0.9.0 and later)
|
||||
|
||||
The **TagSpace** tab lays out the prompts, tags and generated images inside Workflow Studio in a 3D space
|
||||
according to **closeness of meaning**. Things close together mean similar things, so you can browse the space
|
||||
("which tags are close to this mood?") and pick tags to build a prompt.
|
||||
|
||||
### What is in the space
|
||||
- **Cards** - the sample images of the Gallery's **ImagePrompt** (Chapter 8, section 8-4) with their prompts, shown as thumbnails
|
||||
- **Tags** - words taken (split at commas) from ImagePrompt prompts, prompts embedded in generated images, wildcards, the Tagger DB and the Prompt library, shown as dots colored by source
|
||||
- **Gallery points** - some of your generated images, shown as faint dots (each carries the tags of its own prompt)
|
||||
|
||||
### Preparation
|
||||
As with the Gallery's semantic search (Chapter 8, section 8-6), **Ollama** and **EmbeddingGemma 2** are needed.
|
||||
If the Gallery's semantic index was made with Gemini Embedding 2, rebuild it with EmbeddingGemma 2 first.
|
||||
|
||||
### Building the space
|
||||
Choose the settings in the toolbar and press **Build / Update**.
|
||||
|
||||
- **Tags** - how many tags to include. The sources take turns, each in order of how often a tag is used
|
||||
- **All tags** - when on, every candidate tag is used instead of the Tags number (up to 20,000)
|
||||
- **Min uses** - leaves out tags used fewer times than this. 2 removes one-off spelling variants and the like
|
||||
- **Wildcards** - whether wildcards are used as a tag source
|
||||
- **Gallery points** - how many generated images to show (0 = none)
|
||||
- **Tagger fill** - tags generated images whose prompt cannot be read, using a Tagger model (OFF / a model name; choose "Gallery points only" or "All images without a prompt")
|
||||
|
||||
- The first build takes a few minutes to read image prompts and prepare tags. Later builds reuse the previous results and finish in seconds to tens of seconds.
|
||||
- The status line shows the numbers of cards, tags and Gallery points. When only part of the candidates is used, "(of N candidates)" is shown.
|
||||
|
||||
> **Tip**
|
||||
> Most distinct tags are words that only appear in wildcards.
|
||||
> Turning "Wildcards" off and "All tags" on lays out every tag you have actually used (about 10,000 in testing).
|
||||
|
||||
> **Caution**
|
||||
> Tagger fill takes about 0.5 second per image on the CPU. Before choosing "All images without a prompt", check that Tagger runs on the GPU (Chapter 12, section 12-5).
|
||||
|
||||
### Looking and searching
|
||||
- **Drag** to rotate, **right-drag** to pan, and use the **wheel** to zoom.
|
||||
- Hovering over a point shows its name, thumbnail and prompt or sources.
|
||||
- The toolbar checkboxes switch Cards, Thumbnails, Tags and Gallery on or off, as well as **Glow** (stars shining in a night sky) and **Twinkle**.
|
||||
The checkboxes for each source show or hide tags by source.
|
||||
- Type words or a sentence in the search box at the top right and press **Enter** (any language). A white mark is placed at that meaning, and nearby cards and tags are listed.
|
||||
|
||||
### Picking tags to build a prompt
|
||||
1. Click a card or tag to select it. Cards and tags close in meaning are listed under **Nearby** on the right.
|
||||
(Clicking a Gallery point also lists similar generated images)
|
||||
2. **Double-click** what you want in the prompt, or press **Add** in **Selection**, or the **+** in the list.
|
||||
A card adds its whole prompt, a tag adds the tag itself, and a Gallery point adds that image's tags to the **Prompt** area at the far right.
|
||||
3. **Add to GenerateUI (Positive)** appends it to the positive prompt of the workflow loaded in GenerateUI (load a workflow in GenerateUI first).
|
||||
You can also **Copy** it to the clipboard.
|
||||
|
||||
### Searching with the tags of a card or generated image
|
||||
When you select a card or Gallery point, its prompt tags are shown as buttons under **Selection**.
|
||||
Click tags to choose them (click again to deselect) and press **Search with selected** to search the space with them.
|
||||
This helps when you want to find things close to, say, only the hairstyle and clothing of an image.
|
||||
While tags are selected, the **Add** button in **Selection** becomes **Add selected (N)** and adds only those tags to the prompt area.
|
||||
With no tags selected it adds the whole item as before (a card's whole prompt, or all tags of a Gallery point).
|
||||
|
||||
When a Gallery point is selected, **Selection** also shows an **Open in Gallery** button.
|
||||
It switches to the Gallery tab, selects the image's folder, and selects the image in the list (its details open on the right).
|
||||
So that the image is sure to appear, the Gallery's search, favorite, tag and group filters are cleared.
|
||||
A card's whole prompt can be read under **Full prompt**.
|
||||
|
||||
---
|
||||
|
||||
> **Summary of this chapter**
|
||||
> - In the Nodes tab you can list and organize installed nodes, and use them in the WS Library
|
||||
> - Tagger automatically generates tags from images. A model and extra packages must be prepared
|
||||
> - Image Edit is a simple editing tool with layers. Inpainting also lets you redraw parts
|
||||
> - In the Video tab, you can make videos with supported video-generation models and do simple editing
|
||||
> - "Default Checkpoint" and "Data Management (backup)" in the Settings tab are especially handy
|
||||
> - Combined with Comic Creator by the same author, you can make manga from generated images
|
||||
> - TagSpace lays out your tags, prompts and generated images in 3D by closeness of meaning, so you can browse it and pick tags for a prompt
|
||||
@@ -0,0 +1,230 @@
|
||||
# Chapter 12 When You Are in Trouble (Troubleshooting / FAQ)
|
||||
|
||||
This chapter collects the troubles that often occur when using Workflow Studio, and how to deal with them.
|
||||
When in trouble, first look in the **"symptom"** headings for the one closest to your situation.
|
||||
|
||||
> **Three things to try first**
|
||||
> For almost any trouble, these three often solve it.
|
||||
> 1. Reload the browser page (F5 key)
|
||||
> 2. Press the **Refresh** button of each Workflow Studio tab
|
||||
> 3. Quit ComfyUI completely and start it again
|
||||
|
||||
---
|
||||
|
||||
## 12-1 Startup and connection troubles
|
||||
|
||||
### The W button does not appear
|
||||
| Cause | What to do |
|
||||
| --- | --- |
|
||||
| You did not restart ComfyUI after installing | Quit ComfyUI completely and start it again (reloading the browser alone does not take effect) |
|
||||
| The folder is in the wrong place | Check that the folder exists at `ComfyUI/custom_nodes/ComfyUI-Workflow-Studio`. Also check that the folder is not doubled |
|
||||
| ComfyUI is old | Update ComfyUI itself |
|
||||
|
||||
### The Workflow Studio page does not open
|
||||
- Is ComfyUI running? Workflow Studio runs inside ComfyUI, so you cannot open it if you quit ComfyUI.
|
||||
- Is the **port number** in the address right? You can check it in the address bar of the browser where ComfyUI is open (Chapter 2, section 2-4).
|
||||
|
||||
### GenerateUI shows "Disconnected"
|
||||
1. Check that ComfyUI is running and that you can generate an image on ComfyUI's screen.
|
||||
2. Press **Connect** at the top of GenerateUI.
|
||||
3. If it still does not connect, reload the browser page.
|
||||
|
||||
### You updated but the behavior did not change
|
||||
After updating Workflow Studio, always restart ComfyUI.
|
||||
If it still behaves the old way, the browser cache may remain.
|
||||
Try **Ctrl + F5** (forced reload).
|
||||
|
||||
---
|
||||
|
||||
## 12-2 Workflow troubles
|
||||
|
||||
### Workflows do not appear in the list
|
||||
| Cause | What to do |
|
||||
| --- | --- |
|
||||
| The list is still old | Press **Refresh** in the Workflow tab |
|
||||
| A filter is applied | Press **x Clear** at the right end of the toolbar |
|
||||
| You saved to another folder | Check "Workflow Data Folder" in the Settings tab |
|
||||
|
||||
### Nodes are shown in red (missing)
|
||||
When you load a workflow, nodes may be shown in red, or a message may say there are missing nodes.
|
||||
This means **the custom nodes the workflow needs are not installed**.
|
||||
|
||||
**What to do**
|
||||
1. Open ComfyUI's **Manager**.
|
||||
2. Choose **Install Missing Custom Nodes**.
|
||||
3. Install the custom nodes shown, and restart ComfyUI.
|
||||
|
||||
> **Tip**
|
||||
> The "Convert: cross" in the Workflow tab's **GenerateUI Check** (Chapter 4, section 4-7) is also mostly caused by this.
|
||||
> Hovering the mouse over the badge shows the names of the missing nodes.
|
||||
|
||||
### GenerateUI judged it "unusable"
|
||||
| Judgment | Meaning and what to do |
|
||||
| --- | --- |
|
||||
| Convert: cross | A required custom node is missing -> see "Nodes are shown in red" above |
|
||||
| Convert: warning | A model you do not have is specified -> choose again in GenerateUI (12-3) |
|
||||
| Operability: warning / cross | Many settings are not shown in GenerateUI -> generation is often still possible. Change detailed settings on ComfyUI's node screen |
|
||||
|
||||
---
|
||||
|
||||
## 12-3 Generation troubles
|
||||
|
||||
### You changed a setting but the result did not change
|
||||
The most common cause is **forgetting to press Apply**.
|
||||
In GenerateUI, after changing the model or Settings values (steps, size and so on), the change is not reflected in the workflow unless you press **Apply** (Chapter 5, section 5-3).
|
||||
The Switches column at the right of the Settings tab is the exception: it takes effect the moment you click (Chapter 5, section 5-4).
|
||||
Looking at the **Raw JSON** on the right lets you check the values actually reflected.
|
||||
|
||||
### It generates something different from the loaded workflow
|
||||
If a batch kind's checkbox in the **Batch** subtab stays on,
|
||||
a batch generation runs when you press Generate (Chapter 5, section 5-5).
|
||||
Open the Batch subtab and turn off all the Batch Queue column checkboxes.
|
||||
|
||||
### It generates with a different model than you expected
|
||||
If the model saved in the workflow is not on your computer, it may be replaced automatically with another model.
|
||||
In that case a message says the Checkpoint "..." was not found and was replaced with another model without warning.
|
||||
(From v0.8.7, if you have exactly one model with the same name that differs only in its folder, it is replaced with that one.)
|
||||
In the **Model** subtab of GenerateUI, choose the model you want to use again and press **Apply**.
|
||||
|
||||
If you always want to use the same model, the **Default Checkpoint** in the Settings tab is handy (Chapter 11, section 11-5).
|
||||
|
||||
### It does not become the same image even with the same settings
|
||||
Is the seed mode in the generate panel set to **Random**?
|
||||
To make the same image, you need to set the seed to **Workflow** (use the workflow's seed as it is) or **Fixed** (fix it to the value in the Seed field).
|
||||
If no new image is added when you generate in a row with the same seed and settings, that is because ComfyUI reuses the already computed result, not a malfunction.
|
||||
For the steps to reproduce a Gallery image, see Chapter 8, section 8-3.
|
||||
|
||||
### Slow generation, or it stops with an error (out of memory)
|
||||
| Cause | What to do |
|
||||
| --- | --- |
|
||||
| Local AI is using GPU memory | Press **Unload Model** in AI TOOL. Use **VRAM Management (Ollama)** in the Settings tab (Chapter 10, section 10-3) |
|
||||
| The image size or Batch Size is too large | Make Width, Height and Batch Size smaller in the Settings subtab |
|
||||
| The model is too large for your GPU | Use a smaller model (such as a GGUF version) |
|
||||
|
||||
### Errors appear after moving or deleting a model
|
||||
ComfyUI may remember the old location of a model.
|
||||
Run **Hard Reset** in ComfyUI's menu (inside the queue menu), or restart ComfyUI.
|
||||
|
||||
### A newly added model does not appear in the list
|
||||
Press **Refresh Models** in GenerateUI, or **Refresh** in the Models tab.
|
||||
If it still does not appear, check that the folder where you put the model is correct (Chapter 6, section 6-1).
|
||||
|
||||
---
|
||||
|
||||
## 12-4 AI feature troubles
|
||||
|
||||
### AI features show "Disconnected" or do not connect
|
||||
1. Check that software such as Ollama is running.
|
||||
For LM Studio or Lemonade, you need to **start the server** inside the app and have a model loaded.
|
||||
2. Check that the address (port number) in the settings matches the software.
|
||||
3. Press **Test Connection** and check the result.
|
||||
|
||||
### It works in the AI TOOL tab but not in the Prompt tab
|
||||
AI settings are saved separately depending on the place (Chapter 10, section 10-2).
|
||||
|
||||
| Place | Where to set it |
|
||||
| --- | --- |
|
||||
| AI TOOL tab / the A tab of the WS Library | The AI TOOL tab's settings (shared) |
|
||||
| Prompt tab | The **gear button** of the AI Assistant in the Prompt tab |
|
||||
| Tagger tab | The **gear button** in the Tagger tab |
|
||||
|
||||
### The model list is empty
|
||||
The AI model may not have been downloaded.
|
||||
For Ollama, download the model with `ollama pull (model name)`, then press **Refresh** in the model selection.
|
||||
|
||||
### It does not connect to Ollama on another computer
|
||||
For safety, by default it connects only to AI software inside the same computer.
|
||||
You need to set the environment variable `WFS_ALLOWED_BACKEND_HOSTS` (Chapter 10, section 10-4).
|
||||
|
||||
### The judge model for image checks, or the OCR model, does not appear in the list
|
||||
- The judge model list shows only Ollama **decision models** that can read images; normal chat models are not shown.
|
||||
Update Ollama, `ollama pull` a decision model, then press **Refresh** (Chapter 10, section 10-6).
|
||||
- The OCR model list shows only Ollama models whose name contains "ocr". Press ↻ after getting one (Chapter 10, section 10-8).
|
||||
- Both look at Ollama at the AI TOOL backend address when the backend is Ollama, otherwise at `http://localhost:11434`.
|
||||
|
||||
### Image checks never pass no matter how often it fixes
|
||||
- How well the redraw works depends on the chat model. Make your request shorter and more concrete, or try another model.
|
||||
- The check itself can be wrong too. Look at the image yourself as well.
|
||||
- Too many automatic fix rounds keep using generation time and GPU memory. "0 (fix by button)" is recommended at first.
|
||||
|
||||
### The AI does not read a skill's reference files, or does not generate images from the chat
|
||||
Reading the reference files of an imported skill and generating images from the chat only work with
|
||||
**a model that supports tool calling**. Switch to such a model.
|
||||
|
||||
---
|
||||
|
||||
## 12-5 Troubles with other features
|
||||
|
||||
### No model appears in Tagger
|
||||
- Check that a `.onnx` file (and `selected_tags.csv`) is in the `ComfyUI/models/tagger/(model name)/` folder.
|
||||
- Check that the extra Python package (onnxruntime) is installed in **the Python that ComfyUI uses** (Chapter 11, section 11-2).
|
||||
|
||||
### Tagger is very slow (the GPU is not used)
|
||||
If ComfyUI's Python has both the CPU package `onnxruntime` and the GPU package `onnxruntime-gpu`, the GPU stops being used.
|
||||
(Installing other custom nodes can bring in the CPU package.)
|
||||
Stop ComfyUI, then in ComfyUI's Python run `pip uninstall -y onnxruntime onnxruntime-gpu` followed by `pip install onnxruntime-gpu`, and restart ComfyUI (DirectML is not supported).
|
||||
|
||||
### PSD-related features give an error
|
||||
An extra Python package (psd-tools) is needed.
|
||||
Run the installation command shown in the error message in the Python that ComfyUI uses, then restart ComfyUI.
|
||||
|
||||
### Semantic search (Gallery) does not work well
|
||||
| Symptom | Cause | What to do |
|
||||
| --- | --- | --- |
|
||||
| "Cannot reach Ollama" is shown | Ollama is not running, or the Ollama URL is wrong | Start Ollama (it is needed while indexing and searching). Check the Ollama URL on the gear button's Model tab |
|
||||
| "The Ollama model is not downloaded" is shown | EmbeddingGemma 2 has not been downloaded | Run `ollama pull embeddinggemma-2:740m` (or `embeddinggemma-2:440m`) |
|
||||
| Indexing sometimes fails with "connection was forcibly closed" or similar | Security software (such as AdGuard) is intercepting Ollama's traffic | Exclude Ollama from filtering. Failed images are processed again by the next "New / changed images only" run |
|
||||
| Gemini says "GEMINI_API_KEY is not set", or the key is rejected | There is no key in `.env`, or the line starts with `#` | Write `GEMINI_API_KEY=key` in the plugin's `.env` (copy `.env.example`) and restart ComfyUI. `.env` is only read at startup |
|
||||
| Search or Similar gives no results | The selected folder has no indexed images | Build the index with the gear button. Choose a folder with a green dot. When you change the model or vector dimension, "rebuild all" |
|
||||
|
||||
### The TagSpace space cannot be built
|
||||
| Symptom | Cause | What to do |
|
||||
| --- | --- | --- |
|
||||
| "EmbeddingGemma 2 in Ollama is required" is shown | Ollama is not running, or the model is missing | Prepare the same way as for semantic search (table above) |
|
||||
| "The Gallery semantic index was made with ..." is shown | The Gallery index was made with Gemini | Choose EmbeddingGemma 2 in the Gallery's semantic settings and rebuild all |
|
||||
| Building takes a very long time | The first build reads image prompts and prepares new tags | Later builds are faster. When using Tagger fill, check that Tagger runs on the GPU ("Tagger is very slow" above) |
|
||||
|
||||
### A partner API (Nano Banana) says authentication failed
|
||||
The cause is a missing Comfy API key in `.env`. Write `COMFY_API_KEY=your key` (issued at platform.comfy.org) in the plugin's `.env` and restart ComfyUI (Chapter 5, section 5-8).
|
||||
`.env` is read only at startup.
|
||||
|
||||
### ComfyUI freezes (no tab responds)
|
||||
On Windows, ComfyUI can stop responding (generation included), for example after switching a Models tab list with many preview images.
|
||||
In the Settings tab, under **Windows Stability (Event Loop)**, turn on **Use the Selector event loop on Windows (restart required)** and restart ComfyUI.
|
||||
|
||||
### Part of a Gallery image looks broken, as if mixed with another image
|
||||
With the **Selector event loop** above turned on, up to v0.9.1 part of an image received by the Gallery preview or Download could be corrupted
|
||||
(the file in the output folder itself is fine). This is fixed in v0.9.2.
|
||||
After updating Workflow Studio, broken images may remain in the browser cache, so reload with **Ctrl + F5**.
|
||||
|
||||
### Images do not appear in the Gallery
|
||||
- Press **Refresh** in the Gallery.
|
||||
- Check that the "Gallery Output Folder" in the Settings tab matches where ComfyUI saves images.
|
||||
|
||||
---
|
||||
|
||||
## 12-6 If it is still not solved
|
||||
|
||||
### Look at Workflow Studio's Help
|
||||
The **Help** tab of Workflow Studio also has troubleshooting information.
|
||||
It may include information added after this book was published.
|
||||
|
||||
### Ask or report on GitHub
|
||||
Problems that are not solved can be reported in **Issues** on Workflow Studio's GitHub repository.
|
||||
When reporting, attaching the following information makes the cause easier to find.
|
||||
|
||||
- The Workflow Studio version
|
||||
- The ComfyUI version and how it was installed (portable version, Desktop version, Stability Matrix and so on)
|
||||
- On which screen, what you did, and what happened
|
||||
- The error message shown on the black screen (console) where ComfyUI was started
|
||||
- The red error message shown in the "Console" of the browser's developer tools (F12 key)
|
||||
|
||||
> **Caution**
|
||||
> When pasting error messages, check that they do not contain personal information such as your computer's user name.
|
||||
|
||||
> **Summary of this chapter**
|
||||
> - When in trouble, first try "reload", "Refresh buttons" and "restarting ComfyUI"
|
||||
> - Red nodes mean missing custom nodes. Solve with ComfyUI Manager's Install Missing Custom Nodes
|
||||
> - When settings are not reflected, check for a forgotten Apply and a leftover Batch check
|
||||
> - For out-of-memory, deal with it by unloading local AI and reviewing the image size
|
||||
> - When not solved, make use of the Help tab and GitHub Issues
|
||||
@@ -0,0 +1,139 @@
|
||||
# Appendix
|
||||
|
||||
## Appendix A Glossary
|
||||
|
||||
The main terms that appear in this book, in alphabetical order.
|
||||
|
||||
| Term | Meaning | In this book |
|
||||
| --- | --- | --- |
|
||||
| API format / UI format | The save format of a workflow. UI format includes things such as node positions; API format contains only the processing content | Chapter 4 |
|
||||
| Apply | The button in GenerateUI that reflects changed values into the workflow | Chapter 5 |
|
||||
| Badge | A colored label attached to a workflow or model | Chapter 4 |
|
||||
| Batch generation | Automatically generating in bulk while changing conditions | Chapter 5 |
|
||||
| Canvas | The work space where nodes are laid out on ComfyUI's node screen | Chapter 3 |
|
||||
| CFG | How strongly to follow the prompt | Chapter 5 |
|
||||
| Checkpoint | The model that forms the core of image generation | Chapter 6 |
|
||||
| Civitai | A sharing site for image-generation models | Chapter 6 |
|
||||
| ComfyUI Manager | A management tool for searching for and installing custom nodes | Chapter 2 |
|
||||
| Custom node | A node or extension added to ComfyUI afterwards. Workflow Studio is one of them | Chapter 1 |
|
||||
| Decision model | An AI model that answers questions with numbers such as the probability of "yes". Used to judge image checks | Chapter 10 |
|
||||
| Denoise | How strongly to redraw the original image | Chapter 5 |
|
||||
| Embedding | A small file that teaches a particular word a meaning | Chapter 6 |
|
||||
| Hash value | A "fingerprint"-like value computed from a file's contents. Used to look up models on Civitai | Chapter 6 |
|
||||
| I2I (Image to Image) | Making a new image based on an image | Chapter 5 |
|
||||
| Inpainting | Redrawing only part of an image (the masked part) | Chapter 11 |
|
||||
| JSON | The data format used to save workflows | Chapter 1 |
|
||||
| Keyframe | In Lab, a specification of "from which run to switch settings" | Chapter 5 |
|
||||
| Local AI | AI that runs inside your own computer (such as Ollama) | Chapter 10 |
|
||||
| LoRA | A small model that teaches an art style, character and so on as an add-on | Chapter 6 |
|
||||
| Mask | A specification of the part of an image to be processed | Chapter 11 |
|
||||
| Metadata | Information embedded in an image, such as the settings used at generation | Chapter 8 |
|
||||
| Model | The file that acts as the "AI brain" that makes images | Chapter 1 |
|
||||
| Negative prompt | A prompt where you write what you do not want drawn | Chapter 7 |
|
||||
| Node | A "box" arranged on ComfyUI's screen. It handles one process | Chapter 1 |
|
||||
| Node set | Several nodes and their connections saved together | Chapter 9 |
|
||||
| OCR | Reading the text shown in an image | Chapter 10 |
|
||||
| Ollama | Software for running local AI easily | Chapter 10 |
|
||||
| Port number | A number for distinguishing which software to communicate with inside one computer | Chapter 2 |
|
||||
| Positive prompt | A prompt where you write what you want drawn | Chapter 7 |
|
||||
| Preset | A pair of positive and negative prompts saved together | Chapter 7 |
|
||||
| Prompt | The text that tells the AI "what kind of image you want" | Chapter 1 |
|
||||
| Queue | The reservation list for generation. Processed in order | Chapter 1 |
|
||||
| Sampler | The algorithm used when drawing an image (such as euler) | Chapter 5 |
|
||||
| Scheduler | How the drawing amount is distributed across steps | Chapter 5 |
|
||||
| Seed | The seed of random numbers an image grows from. If the same, you get almost the same image | Chapter 5 |
|
||||
| Semantic search | Searching images by the "meaning" of a sentence or image. Used with the Gallery's S button | Chapter 8 |
|
||||
| Skill | Instructions that tell the AI TOOL chat its role and how to answer. Picking one switches what it is good at | Chapter 10 |
|
||||
| Steps | The number of times drawing is repeated | Chapter 5 |
|
||||
| Style | A mood template added to a prompt | Chapter 7 |
|
||||
| T2I (Text to Image) | Making an image from text (a prompt) | Chapter 5 |
|
||||
| TagSpace | A tab that lays out tags, prompts and generated images in 3D by closeness of meaning | Chapter 11 |
|
||||
| Trigger word | A word to put in the prompt to bring out a LoRA's effect | Chapter 6 |
|
||||
| VAE | The model that finishes an image's colors and fine details | Chapter 6 |
|
||||
| VLM | An AI model that can read images | Chapter 10 |
|
||||
| VRAM | The memory of the GPU (graphics card) | Chapter 10 |
|
||||
| Wildcard | A mechanism that randomly swaps a part of the prompt at every generation | Chapter 7 |
|
||||
| Workflow | The whole flow of processing made by connecting nodes with lines | Chapter 1 |
|
||||
| WS Library | Workflow Studio's side panel that opens beside ComfyUI's node screen | Chapter 9 |
|
||||
|
||||
---
|
||||
|
||||
## Appendix B Keyboard and mouse operations
|
||||
|
||||
### General
|
||||
| Operation | What happens |
|
||||
| --- | --- |
|
||||
| Esc | Closes the open screen (modal or panel) |
|
||||
| Enter | Confirms a rename / sends a chat message |
|
||||
| Shift + Enter | Line break in chat |
|
||||
| Double-click | Opens the detail screen (workflows, models and so on) |
|
||||
| Shift + click (W button) | Opens Workflow Studio in a new window |
|
||||
|
||||
### GenerateUI
|
||||
| Operation | What happens |
|
||||
| --- | --- |
|
||||
| Alt + click (Apply) | Reflects the values and generates at once |
|
||||
| Ctrl + Up/Down (prompt field) | Raises or lowers the emphasis `(word:number)` of the selected word by 0.05 |
|
||||
| Enter / Shift + Enter (Raw JSON search box) | Moves to the next / previous match |
|
||||
|
||||
### Gallery
|
||||
| Operation | What happens |
|
||||
| --- | --- |
|
||||
| Ctrl + click | Select several images |
|
||||
| Alt + click | Open the image in the Metadata subtab |
|
||||
| Enter (when semantic search is on) | Run a semantic search with the text in the search box |
|
||||
|
||||
### WS Library
|
||||
| Operation | What happens |
|
||||
| --- | --- |
|
||||
| Drag and drop | Place or load at the dropped position on the canvas |
|
||||
| Double-click | Place or load near the center of the canvas |
|
||||
| Alt + click (N tab) | Switch a node's favorite on or off |
|
||||
|
||||
### Image Edit
|
||||
| Operation | What happens |
|
||||
| --- | --- |
|
||||
| V / B / T / S / G | Switch to the Select / Draw / Text / Shape / Fill tool |
|
||||
| Ctrl + Z / Ctrl + Y | Undo / redo |
|
||||
| Mouse wheel | Zoom in and out |
|
||||
| Space + drag | Move the view position |
|
||||
| Delete | Delete the selected layer (when there are two or more layers) |
|
||||
| D / E (while Draw is active) | Draw / Erase |
|
||||
| X (while Draw is active) | Swap Color 1 and Color 2 |
|
||||
| [ / ] (while Draw is active) | Make the brush smaller / larger |
|
||||
| B (while Draw is active) | Open or close the brush picker |
|
||||
|
||||
---
|
||||
|
||||
## Appendix C Reference links
|
||||
|
||||
### Workflow Studio
|
||||
- GitHub (latest version, release notes, bug reports)
|
||||
https://github.com/ketle-man/ComfyUI-Workflow-Studio
|
||||
|
||||
### ComfyUI itself and management tools
|
||||
- ComfyUI
|
||||
https://github.com/comfyanonymous/ComfyUI
|
||||
- ComfyUI Manager
|
||||
https://github.com/Comfy-Org/ComfyUI-Manager
|
||||
|
||||
### Related software and services introduced in this book
|
||||
| Name | Use | In this book |
|
||||
| --- | --- | --- |
|
||||
| Civitai (https://civitai.com/) | Getting models, fetching information | Chapter 6 |
|
||||
| Ollama (https://ollama.com/) | Local AI | Chapter 10 |
|
||||
| LM Studio (https://lmstudio.ai/) | Local AI | Chapter 10 |
|
||||
| Lemonade Server (https://lemonade-server.ai/) | Local AI | Chapter 10 |
|
||||
| Eagle (https://eagle.cool/) | Image-management software | Chapter 8 |
|
||||
|
||||
### Custom nodes that are handy to use together
|
||||
| Name | Use | In this book |
|
||||
| --- | --- | --- |
|
||||
| ComfyUI Comic Creator (https://github.com/ketle-man/comfyui-comic-creator) | Manga making. Works with the Gallery and image generation | Chapter 11 |
|
||||
| comfyui-image-feeder (https://github.com/ketle-man/comfyui-image-feeder) | Feeder's Image Loop mode | Chapter 5 |
|
||||
| comfyui-mask-editor-one (https://github.com/ketle-man/comfyui-mask-editor-one) | Advanced masking and background removal in Image Edit | Chapter 11 |
|
||||
| ComfyUI-Impact-Pack (https://github.com/ltdrdata/ComfyUI-Impact-Pack) | Curly-brace-style wildcards | Chapter 7 |
|
||||
| ComfyUI-Lora-Manager | Managing LoRAs; placing LoRAs together from the WS Library | Chapter 9 |
|
||||
|
||||
> **Caution**
|
||||
> The contents and URLs of linked pages may change.
|
||||
@@ -0,0 +1,27 @@
|
||||
# Afterword
|
||||
|
||||
Thank you for reading to the end.
|
||||
|
||||
ComfyUI is very free and deep software.
|
||||
Because of that freedom, it is also software where beginners think "I don't know where to start".
|
||||
Workflow Studio was born from the wish to widen that entrance a little,
|
||||
and to make "creating" and "organizing" more casual.
|
||||
|
||||
Let's look back once more at the ways of using it introduced in this book.
|
||||
|
||||
1. **Organize** - make workflows, models and prompts easy to tell apart with thumbnails and badges
|
||||
2. **Create** - generate images in GenerateUI without touching the node screen
|
||||
3. **Collect** - keep prompts and settings that worked in presets and the Gallery
|
||||
4. **Reproduce** - recall the same settings right away from an image's metadata
|
||||
5. **Expand** - speed up trial and error with batch generation and local AI
|
||||
|
||||
The shortest path to improving at image generation is to **try a lot, and keep what worked**.
|
||||
I will be glad if Workflow Studio becomes a tool that supports that accumulation.
|
||||
|
||||
Workflow Studio will continue to gain features and improvements.
|
||||
New features and changes are announced in the release notes on GitHub.
|
||||
Your impressions after using it, and requests such as "I want this feature", are also welcome on GitHub.
|
||||
|
||||
May your life with image generation become more fun and richer.
|
||||
|
||||
ketle-man
|
||||
|
Before Width: | Height: | Size: 116 KiB |
|
Before Width: | Height: | Size: 100 KiB |
|
Before Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 81 KiB |
|
Before Width: | Height: | Size: 975 KiB |
|
Before Width: | Height: | Size: 160 KiB |
|
Before Width: | Height: | Size: 45 KiB |
|
Before Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 117 KiB |
|
Before Width: | Height: | Size: 148 KiB |
|
After Width: | Height: | Size: 422 KiB |
@@ -0,0 +1,78 @@
|
||||
"""Runs before ComfyUI imports any custom node — the only place early enough
|
||||
to populate os.environ for code that reads env vars at import/request time.
|
||||
|
||||
Loads a .env file (if present) from this plugin's root directory so the
|
||||
Unsloth backend's API key (UNSLOTH_API_KEY) can be set without editing
|
||||
settings.json or exposing it to the frontend.
|
||||
"""
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
PLUGIN_DIR = Path(__file__).resolve().parent
|
||||
ENV_FILE = PLUGIN_DIR / ".env"
|
||||
|
||||
|
||||
def _maybe_use_selector_event_loop():
|
||||
"""Windows: ProactorEventLoop(IOCP) を SelectorEventLoop に切り替える(既定はオフ)。
|
||||
|
||||
環境によっては、ソケットclose(closesocket/NtClose)でイベントループがOSカーネル内で停止し、
|
||||
ComfyUI全体が無応答になる(再起動するまでポートも解放されない)。Selector方式はIOCPを使わず、
|
||||
この停止を避けられる可能性がある。副作用: asyncioのサブプロセス機能が使えない、
|
||||
同時接続数の上限(約512)がある。
|
||||
|
||||
有効化: 環境変数 WFS_SELECTOR_LOOP=1、または
|
||||
user/default/Workflow-Studio/settings.json に "windows_selector_event_loop": true
|
||||
ComfyUIがイベントループを作成する前に呼ぶ必要があるため、ここ(prestartup)で設定する。
|
||||
"""
|
||||
import os
|
||||
import sys
|
||||
|
||||
if sys.platform != "win32":
|
||||
return
|
||||
enabled = os.environ.get("WFS_SELECTOR_LOOP", "").strip().lower() in ("1", "true", "yes")
|
||||
if not enabled:
|
||||
try:
|
||||
import json
|
||||
candidates = [
|
||||
PLUGIN_DIR.parent.parent / "user" / "default" / "Workflow-Studio" / "settings.json",
|
||||
PLUGIN_DIR / "data" / "settings.json", # config.py fallback when user/default is absent
|
||||
]
|
||||
for settings in candidates:
|
||||
if settings.is_file():
|
||||
with open(settings, "r", encoding="utf-8") as f:
|
||||
enabled = bool(json.load(f).get("windows_selector_event_loop", False))
|
||||
break
|
||||
except Exception:
|
||||
enabled = False
|
||||
if not enabled:
|
||||
return
|
||||
try:
|
||||
import asyncio
|
||||
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
|
||||
print("[Workflow Studio] Using WindowsSelectorEventLoopPolicy (windows_selector_event_loop enabled)")
|
||||
except Exception as e:
|
||||
print(f"[WARNING] Workflow Studio: failed to switch to selector event loop: {e}")
|
||||
return
|
||||
# Selector方式ではloop.sendfileがasyncioの_sendfile_fallbackになるが、これは16KBバッファを
|
||||
# 使い回しつつ未送信分をコピーせずトランスポートに積むため、送信が詰まると後続ブロックで
|
||||
# 上書きされ画像等が壊れて届く(Python 3.12で確認)。aiohttpのsendfileを無効化し、
|
||||
# チャンクごとに新しいbytesを読む自前フォールバックを使わせる
|
||||
os.environ["AIOHTTP_NOSENDFILE"] = "1"
|
||||
fileresponse = sys.modules.get("aiohttp.web_fileresponse")
|
||||
if fileresponse is not None:
|
||||
fileresponse.NOSENDFILE = True
|
||||
|
||||
|
||||
_maybe_use_selector_event_loop()
|
||||
|
||||
if ENV_FILE.exists():
|
||||
try:
|
||||
from dotenv import load_dotenv
|
||||
load_dotenv(ENV_FILE)
|
||||
except ImportError:
|
||||
print(
|
||||
"[WARNING] Workflow Studio: .env file found but python-dotenv is not installed "
|
||||
"(pip install -r requirements.txt). UNSLOTH_API_KEY / GEMINI_API_KEY will not be loaded from .env."
|
||||
)
|
||||
except Exception as e:
|
||||
print(f"[WARNING] Workflow Studio: failed to load .env file: {e}")
|
||||
@@ -1,9 +1,66 @@
|
||||
import os
|
||||
import logging
|
||||
import re
|
||||
from pathlib import Path
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# ─── パス検査(クライアント由来のパスを resolve() する前に文字列のまま検査する)───
|
||||
# Windows では UNC パス(\\host\share)は resolve()・exists() を呼んだ時点で相手ホストへ
|
||||
# Windows アカウントの資格情報付きで接続してしまうため、チェックはパス操作より先に行う。
|
||||
|
||||
_DRIVE_RE = re.compile(r"^[A-Za-z]:")
|
||||
|
||||
|
||||
def is_unc(value) -> bool:
|
||||
"""ネットワーク共有/デバイスパス(\\\\host\\share, //host/share, \\\\?\\ 等)か。"""
|
||||
return str(value or "").replace("/", "\\").startswith("\\\\")
|
||||
|
||||
|
||||
def is_safe_rel(rel) -> bool:
|
||||
"""相対パスとして安全か。UNC・ドライブ指定・絶対パス・「..」・空セグメントを
|
||||
結合・resolve() より前に文字列のまま拒否する。"""
|
||||
s = str(rel or "")
|
||||
if not s or "\x00" in s:
|
||||
return False
|
||||
if s.startswith(("/", "\\")) or _DRIVE_RE.match(s):
|
||||
return False
|
||||
return not any(part in ("", "..") for part in re.split(r"[/\\]", s))
|
||||
|
||||
|
||||
def resolve_untrusted(value, roots=()) -> Path:
|
||||
"""クライアント由来の絶対パス文字列を検査してから resolve() して返す。
|
||||
|
||||
ファイルシステムに触れない文字列処理(normpath)だけで「..」を正規化・拒否し、
|
||||
UNC は roots のうち UNC のルート配下に文字列上一致する場合のみ許可する
|
||||
(ギャラリーのルートをネットワーク共有に置いている構成だけを通すため)。
|
||||
拒否時は ValueError。"""
|
||||
s = str(value or "")
|
||||
if not s or "\x00" in s:
|
||||
raise ValueError("Access denied: invalid path")
|
||||
p = Path(os.path.normpath(s))
|
||||
if ".." in p.parts:
|
||||
raise ValueError("Access denied: path traversal")
|
||||
if is_unc(s):
|
||||
for root in roots:
|
||||
if root is None or not is_unc(str(root)):
|
||||
continue
|
||||
try:
|
||||
p.relative_to(Path(root)) # 文字列上の照合(解決しない)
|
||||
return p.resolve()
|
||||
except (ValueError, OSError):
|
||||
continue
|
||||
raise ValueError("Access denied: network path")
|
||||
# 受け付ける形はドライブレター絶対パス(Windows)または / 始まり(その他OS)に限る。
|
||||
# ルート相対(\foo)・ドライブ相対(C:foo)・NT デバイス形式(\??\, \.\ 等)・相対パスは拒否する
|
||||
if os.name == "nt":
|
||||
if not re.match(r"^[A-Za-z]:[\\/]", s):
|
||||
raise ValueError("Access denied: invalid path")
|
||||
elif not s.startswith("/"):
|
||||
raise ValueError("Access denied: invalid path")
|
||||
return p.resolve()
|
||||
|
||||
|
||||
# Plugin root directory
|
||||
PLUGIN_DIR = Path(__file__).resolve().parent.parent
|
||||
|
||||
@@ -69,3 +126,12 @@ NODE_SETS_FILE = DATA_DIR / "node_sets.json"
|
||||
PROMPTS_FILE = DATA_DIR / "prompts.json"
|
||||
MODEL_METADATA_FILE = DATA_DIR / "model_metadata.json"
|
||||
WILDCARD_DIR = DATA_DIR / "wildcard"
|
||||
AI_SKILLS_DIR = DATA_DIR / "ai_skills"
|
||||
LAB_PLAN_DIR = DATA_DIR / "lab_plan"
|
||||
VIDEO_PLAN_DIR = DATA_DIR / "video_plan"
|
||||
VIDEO_EDIT_PROJECT_DIR = DATA_DIR / "video_edit_project"
|
||||
|
||||
# Tagger
|
||||
TAGGER_DB_FILE = DATA_DIR / "tagger.db"
|
||||
TAGGER_SETTINGS_FILE = DATA_DIR / "tagger_settings.json"
|
||||
TAGGER_MODELS_DIR = _COMFYUI_ROOT / "models" / "tagger"
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
"""WFS_GalleryFeeder – Feeds images from a gallery group into a workflow."""
|
||||
import json
|
||||
import random
|
||||
import logging
|
||||
from pathlib import Path
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# Feeder専用グループ名(gallery_metadata.json 内で予約される)
|
||||
FEEDER_GROUP = "__Feeder__"
|
||||
|
||||
|
||||
class WFS_GalleryFeeder:
|
||||
"""Gallery グループ内の画像をインデックス順に1枚ずつ出力するノード。"""
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"group_name": ("STRING", {"default": FEEDER_GROUP}),
|
||||
"index": ("INT", {"default": 0, "min": 0, "max": 99999}),
|
||||
"sort_mode": (["filename_asc", "filename_desc", "random"],),
|
||||
"seed": ("INT", {"default": 0, "min": 0, "max": 0xffffffffffffffff}),
|
||||
},
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("IMAGE",)
|
||||
RETURN_NAMES = ("image",)
|
||||
FUNCTION = "execute"
|
||||
CATEGORY = "Workflow Studio"
|
||||
OUTPUT_NODE = False
|
||||
|
||||
@classmethod
|
||||
def IS_CHANGED(cls, **kwargs):
|
||||
# 毎回実行させる(インデックスが変わるため)
|
||||
return float("NaN")
|
||||
|
||||
def execute(self, group_name: str, index: int, sort_mode: str, seed: int):
|
||||
import torch
|
||||
import numpy as np
|
||||
from PIL import Image as PILImage
|
||||
|
||||
paths = self._get_sorted_paths(group_name, sort_mode, seed)
|
||||
if not paths:
|
||||
logger.warning("WFS_GalleryFeeder: group '%s' is empty or not found", group_name)
|
||||
return (torch.zeros(1, 64, 64, 3),)
|
||||
|
||||
img_path = paths[index % len(paths)]
|
||||
try:
|
||||
img = PILImage.open(img_path).convert("RGB")
|
||||
except Exception as e:
|
||||
logger.error("WFS_GalleryFeeder: failed to load '%s': %s", img_path, e)
|
||||
return (torch.zeros(1, 64, 64, 3),)
|
||||
|
||||
arr = np.array(img, dtype=np.float32) / 255.0
|
||||
tensor = torch.from_numpy(arr).unsqueeze(0)
|
||||
return (tensor,)
|
||||
|
||||
# ── 内部ヘルパー ──────────────────────────────────────────────
|
||||
|
||||
def _get_sorted_paths(self, group_name: str, sort_mode: str, seed: int) -> list[str]:
|
||||
metadata_file = self._find_metadata_file()
|
||||
if not metadata_file.exists():
|
||||
return []
|
||||
try:
|
||||
with open(metadata_file, "r", encoding="utf-8") as f:
|
||||
data = json.load(f)
|
||||
except Exception as e:
|
||||
logger.error("WFS_GalleryFeeder: metadata read error: %s", e)
|
||||
return []
|
||||
|
||||
paths = [
|
||||
key for key, meta in data.get("images", {}).items()
|
||||
if group_name in meta.get("groups", []) and Path(key).exists()
|
||||
]
|
||||
|
||||
if sort_mode == "filename_asc":
|
||||
paths.sort(key=lambda p: Path(p).name.lower())
|
||||
elif sort_mode == "filename_desc":
|
||||
paths.sort(key=lambda p: Path(p).name.lower(), reverse=True)
|
||||
elif sort_mode == "random":
|
||||
rng = random.Random(seed)
|
||||
rng.shuffle(paths)
|
||||
|
||||
return paths
|
||||
|
||||
@staticmethod
|
||||
def _find_metadata_file() -> Path:
|
||||
# py/nodes/ -> py/ -> plugin root -> ComfyUI/custom_nodes/ -> ComfyUI root
|
||||
plugin_root = Path(__file__).resolve().parent.parent.parent
|
||||
comfyui_root = plugin_root.parent.parent
|
||||
user_default = comfyui_root / "user" / "default"
|
||||
if user_default.is_dir():
|
||||
return user_default / "Workflow-Studio" / "gallery_metadata.json"
|
||||
return plugin_root / "data" / "gallery_metadata.json"
|
||||
@@ -3,11 +3,15 @@
|
||||
import asyncio
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import urllib.request
|
||||
import urllib.error
|
||||
|
||||
from aiohttp import web
|
||||
|
||||
from ..config import is_safe_rel
|
||||
from ..services.url_guard import require_backend_url, urlopen as _guarded_urlopen
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@@ -17,6 +21,89 @@ def setup_routes(app: web.Application):
|
||||
app.router.add_post("/api/wfm/eagle/test", handle_test)
|
||||
|
||||
|
||||
def _resolve_local_path(filename, subfolder, type_name):
|
||||
"""filename/subfolder/type を ComfyUI 出力ディレクトリ上の実パスに解決する。
|
||||
ComfyUI と Eagle が同一マシン上で動作している場合のみ有効なパスが返る
|
||||
(別マシンの場合は None を返し、呼び出し側は addFromURL にフォールバックする)。"""
|
||||
try:
|
||||
import folder_paths # type: ignore
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
base_dir = folder_paths.get_directory_by_type(type_name or "output")
|
||||
if not base_dir:
|
||||
return None
|
||||
base_dir = os.path.abspath(base_dir)
|
||||
|
||||
filename = os.path.basename(filename or "")
|
||||
if not filename:
|
||||
return None
|
||||
|
||||
# subfolder の UNC・ドライブ指定・絶対パス・「..」は、結合より前に文字列のまま拒否する
|
||||
# (別ドライブ/UNC だと下の commonpath が ValueError を投げるため、その前に弾く)
|
||||
if subfolder and not is_safe_rel(subfolder):
|
||||
return None
|
||||
|
||||
full_dir = os.path.abspath(os.path.join(base_dir, subfolder or ""))
|
||||
# Windowsはパス比較で大文字小文字を区別しないため normcase で正規化してから比較する
|
||||
if os.path.commonpath((os.path.normcase(full_dir), os.path.normcase(base_dir))) != os.path.normcase(base_dir):
|
||||
# ディレクトリトラバーサル対策: base_dir 配下以外は拒否
|
||||
return None
|
||||
|
||||
full_path = os.path.join(full_dir, filename)
|
||||
if not os.path.isfile(full_path):
|
||||
return None
|
||||
return full_path
|
||||
|
||||
|
||||
def _resolve_absolute_svg_path(abs_path):
|
||||
"""comfyui-tosvg の Save SVG String ノードなどが返す絶対パスを検証する。
|
||||
ComfyUI管理下(output/input/temp)ディレクトリ配下の実在する .svg ファイルのみ許可する
|
||||
(任意の絶対パスをそのまま信頼すると、外部からこのAPIを叩かれた際に
|
||||
ローカルの任意ファイルを送信させられてしまうため)。"""
|
||||
if not abs_path or not abs_path.lower().endswith(".svg"):
|
||||
return None
|
||||
try:
|
||||
import folder_paths # type: ignore
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
# isfile() も UNC(\\host\share)だと相手ホストへ資格情報付きで接続してしまうため、
|
||||
# 文字列処理(abspath/commonpath)だけで ComfyUI 管理下と確認できるまでファイルシステムに触れない
|
||||
abs_path = os.path.abspath(abs_path)
|
||||
|
||||
for type_name in ("output", "temp", "input"):
|
||||
base_dir = folder_paths.get_directory_by_type(type_name)
|
||||
if not base_dir:
|
||||
continue
|
||||
base_dir = os.path.abspath(base_dir)
|
||||
try:
|
||||
# Windowsはパス比較で大文字小文字を区別しないため normcase で正規化してから比較する
|
||||
if os.path.commonpath((os.path.normcase(abs_path), os.path.normcase(base_dir))) == os.path.normcase(base_dir):
|
||||
return abs_path if os.path.isfile(abs_path) else None
|
||||
except ValueError:
|
||||
# Windowsで異なるドライブレターやUNCの場合 commonpath が例外を投げる
|
||||
continue
|
||||
return None
|
||||
|
||||
|
||||
def _eagle_add_from_path(eagle_url, file_path, name, tags):
|
||||
"""Proxy request to Eagle's addFromPath API (runs in thread).
|
||||
SVG は ComfyUI の /view がセキュリティ上 application/octet-stream +
|
||||
attachment で返すため、addFromURL 経由だと正しい種別で保存されないことがある。
|
||||
ComfyUI と Eagle が同一マシン上にある場合はローカルパスを直接渡す方が確実。"""
|
||||
eagle_url = eagle_url.rstrip("/")
|
||||
payload = json.dumps({"path": file_path, "name": name, "tags": tags}).encode("utf-8")
|
||||
req = urllib.request.Request(
|
||||
f"{eagle_url}/api/item/addFromPath",
|
||||
data=payload,
|
||||
headers={"Content-Type": "application/json"},
|
||||
method="POST",
|
||||
)
|
||||
with _guarded_urlopen(req, timeout=10) as resp:
|
||||
return json.loads(resp.read().decode("utf-8"))
|
||||
|
||||
|
||||
def _eagle_add(eagle_url, image_url, name, tags):
|
||||
"""Proxy request to Eagle API (runs in thread)."""
|
||||
eagle_url = eagle_url.rstrip("/")
|
||||
@@ -48,7 +135,7 @@ def _eagle_add(eagle_url, image_url, name, tags):
|
||||
headers={"Content-Type": "application/json"},
|
||||
method="POST",
|
||||
)
|
||||
with urllib.request.urlopen(req, timeout=10) as resp:
|
||||
with _guarded_urlopen(req, timeout=10) as resp:
|
||||
return json.loads(resp.read().decode("utf-8"))
|
||||
|
||||
|
||||
@@ -59,7 +146,7 @@ def _eagle_test(eagle_url):
|
||||
f"{eagle_url}/api/application/info",
|
||||
method="GET",
|
||||
)
|
||||
with urllib.request.urlopen(req, timeout=5) as resp:
|
||||
with _guarded_urlopen(req, timeout=5) as resp:
|
||||
return json.loads(resp.read().decode("utf-8"))
|
||||
|
||||
|
||||
@@ -67,15 +154,37 @@ async def handle_add(request: web.Request) -> web.Response:
|
||||
"""POST /api/wfm/eagle/add - Add image to Eagle."""
|
||||
try:
|
||||
body = await request.json()
|
||||
eagle_url = body.get("eagleUrl", "http://localhost:41595")
|
||||
eagle_url = require_backend_url(body.get("eagleUrl", "http://localhost:41595"))
|
||||
image_url = body.get("url", "")
|
||||
name = body.get("name", "image.png")
|
||||
tags = body.get("tags", [])
|
||||
filename = body.get("filename", "")
|
||||
subfolder = body.get("subfolder", "")
|
||||
file_type = body.get("type", "output")
|
||||
local_path_hint = body.get("localPath", "")
|
||||
|
||||
if not image_url:
|
||||
if not image_url and not local_path_hint:
|
||||
return web.json_response({"status": "error", "message": "No URL provided"}, status=400)
|
||||
|
||||
result = await asyncio.to_thread(_eagle_add, eagle_url, image_url, name, tags)
|
||||
# SVG は /view が application/octet-stream + attachment で返すため、
|
||||
# ローカルファイルが解決できる場合は addFromPath で直接渡す
|
||||
local_path = None
|
||||
if local_path_hint:
|
||||
# comfyui-tosvg の Save SVG String ノードなど、絶対パスが既知の場合
|
||||
local_path = _resolve_absolute_svg_path(local_path_hint)
|
||||
elif (filename or name or "").lower().endswith(".svg"):
|
||||
local_path = _resolve_local_path(filename or name, subfolder, file_type)
|
||||
|
||||
if not local_path and not image_url:
|
||||
return web.json_response(
|
||||
{"status": "error", "message": f"Could not resolve local SVG path: {local_path_hint}"},
|
||||
status=400,
|
||||
)
|
||||
|
||||
if local_path:
|
||||
result = await asyncio.to_thread(_eagle_add_from_path, eagle_url, local_path, name, tags)
|
||||
else:
|
||||
result = await asyncio.to_thread(_eagle_add, eagle_url, image_url, name, tags)
|
||||
return web.json_response(result)
|
||||
except urllib.error.URLError as e:
|
||||
logger.error("Eagle URL error: %s", e)
|
||||
@@ -92,7 +201,7 @@ async def handle_test(request: web.Request) -> web.Response:
|
||||
"""POST /api/wfm/eagle/test - Test Eagle connection."""
|
||||
try:
|
||||
body = await request.json()
|
||||
eagle_url = body.get("eagleUrl", "http://localhost:41595")
|
||||
eagle_url = require_backend_url(body.get("eagleUrl", "http://localhost:41595"))
|
||||
result = await asyncio.to_thread(_eagle_test, eagle_url)
|
||||
return web.json_response({
|
||||
"status": "success",
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
"""
|
||||
Gallery Routes - ギャラリータブ用APIエンドポイント
|
||||
"""
|
||||
import asyncio
|
||||
import json
|
||||
import mimetypes
|
||||
import logging
|
||||
@@ -9,32 +10,248 @@ from aiohttp import web
|
||||
|
||||
from ..config import DATA_DIR
|
||||
from ..services.gallery_service import GalleryService
|
||||
from ..services.semantic_service import SemanticService, SemanticError, DEFAULT_DIM, MODEL as SEMANTIC_DEFAULT_MODEL
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
_service = GalleryService(DATA_DIR)
|
||||
_semantic = SemanticService(DATA_DIR, _service)
|
||||
|
||||
|
||||
def _init_allowed_root() -> None:
|
||||
"""起動時に保存済みの出力ディレクトリで _allowed_root を初期化する。
|
||||
Gallery タブを開く前に Feeder タブの Gallery モードが serve_image を呼んでも
|
||||
404 にならないようにするために必要。"""
|
||||
try:
|
||||
settings_file = DATA_DIR / "settings.json"
|
||||
if settings_file.exists():
|
||||
with open(settings_file, "r", encoding="utf-8") as f:
|
||||
settings = json.load(f)
|
||||
saved_root = settings.get("gallery_output_dir", "").strip()
|
||||
if saved_root and Path(saved_root).is_dir():
|
||||
_service.update_output_root(saved_root)
|
||||
return
|
||||
except Exception as e:
|
||||
logger.warning("GalleryRoutes: failed to load saved gallery root: %s", e)
|
||||
|
||||
# フォールバック: ComfyUI のデフォルト output フォルダ
|
||||
try:
|
||||
import folder_paths # type: ignore
|
||||
output_dir = folder_paths.get_output_directory()
|
||||
if output_dir and Path(output_dir).is_dir():
|
||||
_service.update_output_root(output_dir)
|
||||
except Exception as e:
|
||||
logger.warning("GalleryRoutes: failed to get ComfyUI output dir: %s", e)
|
||||
|
||||
# ImagePrompt/Style Catalogギャラリー用に実outputフォルダを常に別途保持する
|
||||
# (Settingsで_allowed_rootが別フォルダに変更されていても影響しないようにするため)
|
||||
try:
|
||||
import folder_paths # type: ignore
|
||||
output_dir = folder_paths.get_output_directory()
|
||||
if output_dir and Path(output_dir).is_dir():
|
||||
_service.set_comfy_output_root(output_dir)
|
||||
except Exception as e:
|
||||
logger.warning("GalleryRoutes: failed to get ComfyUI output dir for image-prompt root: %s", e)
|
||||
|
||||
|
||||
_init_allowed_root()
|
||||
|
||||
|
||||
# Windowsのレジストリ依存で音声のMIMEが返らない/不統一なため明示登録する(<audio>の再生に必要)
|
||||
for _ext, _mime in ((".wav", "audio/wav"), (".mp3", "audio/mpeg"), (".ogg", "audio/ogg"),
|
||||
(".opus", "audio/ogg"), (".m4a", "audio/mp4"), (".flac", "audio/flac"),
|
||||
(".glb", "model/gltf-binary"), (".vrm", "model/gltf-binary"), (".gltf", "model/gltf+json"),
|
||||
(".ply", "application/octet-stream"), (".spz", "application/octet-stream"),
|
||||
(".bin", "application/octet-stream")):
|
||||
mimetypes.add_type(_mime, _ext)
|
||||
|
||||
|
||||
def setup_routes(app: web.Application):
|
||||
app.router.add_get("/wfm/gallery/folders", list_folders)
|
||||
app.router.add_get("/wfm/gallery/semantic/status", semantic_status)
|
||||
app.router.add_get("/wfm/gallery/semantic/folders", semantic_folders)
|
||||
app.router.add_post("/wfm/gallery/semantic/index", semantic_index)
|
||||
app.router.add_post("/wfm/gallery/semantic/cancel", semantic_cancel)
|
||||
app.router.add_post("/wfm/gallery/semantic/search", semantic_search)
|
||||
app.router.add_post("/wfm/gallery/semantic/similar", semantic_similar)
|
||||
app.router.add_post("/wfm/gallery/semantic/clear", semantic_clear)
|
||||
app.router.add_post("/wfm/gallery/semantic/test", semantic_test)
|
||||
app.router.add_post("/wfm/gallery/semantic/options", semantic_options)
|
||||
app.router.add_get("/wfm/gallery/images", list_images)
|
||||
app.router.add_get("/wfm/gallery/image/meta", get_image_meta)
|
||||
app.router.add_get("/wfm/gallery/image/workflow", get_image_workflow)
|
||||
app.router.add_get("/wfm/gallery/image/serve", serve_image)
|
||||
app.router.add_get("/wfm/gallery/image/thumb", serve_thumb)
|
||||
app.router.add_post("/wfm/gallery/image/thumb3d", save_model3d_thumb)
|
||||
app.router.add_get("/wfm/gallery/model3d/asset", serve_model3d_asset)
|
||||
app.router.add_post("/wfm/gallery/image/meta", save_image_meta)
|
||||
app.router.add_get("/wfm/gallery/image-prompt/root", get_image_prompt_root)
|
||||
app.router.add_post("/wfm/gallery/image/image-prompt", save_image_prompt)
|
||||
app.router.add_get("/wfm/gallery/style-catalog/root", get_style_catalog_root)
|
||||
app.router.add_post("/wfm/gallery/image/save", save_image_to_gallery)
|
||||
app.router.add_post("/wfm/gallery/image/save-to-folder", save_image_to_folder_route)
|
||||
app.router.add_post("/wfm/gallery/output-image/delete", delete_output_image)
|
||||
app.router.add_post("/wfm/gallery/image/favorite", toggle_favorite)
|
||||
app.router.add_get("/wfm/gallery/groups", list_groups)
|
||||
app.router.add_post("/wfm/gallery/groups", create_group)
|
||||
app.router.add_put("/wfm/gallery/groups/{name}", rename_group)
|
||||
app.router.add_delete("/wfm/gallery/groups/{name}", delete_group)
|
||||
app.router.add_post("/wfm/gallery/groups/ensure", ensure_group)
|
||||
app.router.add_post("/wfm/gallery/groups/{name}/add", add_to_group)
|
||||
app.router.add_post("/wfm/gallery/groups/{name}/remove", remove_from_group)
|
||||
app.router.add_post("/wfm/gallery/groups/{name}/clear", clear_group_images)
|
||||
app.router.add_get("/wfm/gallery/groups/{name}/images", list_group_images)
|
||||
# バルク操作
|
||||
app.router.add_post("/wfm/gallery/bulk/favorite", bulk_favorite)
|
||||
app.router.add_post("/wfm/gallery/convert", convert_file_route)
|
||||
app.router.add_post("/wfm/gallery/bulk/group", bulk_group)
|
||||
# フォルダ・ファイル操作
|
||||
app.router.add_post("/wfm/gallery/folder", create_folder_route)
|
||||
app.router.add_delete("/wfm/gallery/folder", delete_folder_route)
|
||||
app.router.add_post("/wfm/gallery/images/delete", delete_images_route)
|
||||
app.router.add_post("/wfm/gallery/images/move", move_images_route)
|
||||
app.router.add_post("/wfm/gallery/images/export-zip", export_images_zip)
|
||||
app.router.add_post("/wfm/gallery/images/export-psd", export_images_psd)
|
||||
app.router.add_post("/wfm/gallery/image/export-psd-layers", export_psd_from_layers)
|
||||
app.router.add_post("/wfm/gallery/image/import-psd-layers", import_psd_layers)
|
||||
app.router.add_get("/wfm/gallery/image/psd-layers", get_psd_layers)
|
||||
|
||||
|
||||
# ──────────────────────────────────────────────────────────────
|
||||
# セマンティック検索 (Gemini Embedding 2 / Ollama EmbeddingGemma 2)
|
||||
# ──────────────────────────────────────────────────────────────
|
||||
|
||||
def _semantic_error(e: SemanticError) -> web.Response:
|
||||
# code はフロントのi18n用。message は詳細(APIキー等の秘密は含まない)
|
||||
return web.json_response({"error": str(e), "code": e.code}, status=400)
|
||||
|
||||
|
||||
def _num(body: dict, key: str, default, lo, hi, cast=int):
|
||||
"""リクエストの数値パラメータを検証して範囲内に収める。数値でなければ400相当のSemanticErrorにする"""
|
||||
raw = body.get(key, default)
|
||||
if raw is None or raw == "":
|
||||
raw = default
|
||||
try:
|
||||
v = cast(raw)
|
||||
except (TypeError, ValueError, OverflowError):
|
||||
raise SemanticError("bad_param", key)
|
||||
if v != v: # NaN
|
||||
raise SemanticError("bad_param", key)
|
||||
return max(lo, min(v, hi))
|
||||
|
||||
|
||||
async def _json_body(request: web.Request) -> dict:
|
||||
try:
|
||||
body = await request.json()
|
||||
return body if isinstance(body, dict) else {}
|
||||
except Exception:
|
||||
return {}
|
||||
|
||||
|
||||
async def semantic_status(request: web.Request) -> web.Response:
|
||||
folder = request.rel_url.query.get("folder", "")
|
||||
recursive = request.rel_url.query.get("recursive", "true") == "true"
|
||||
try:
|
||||
return web.json_response(await asyncio.to_thread(_semantic.status, folder, recursive))
|
||||
except Exception as e:
|
||||
logger.error("semantic_status error: %s", e)
|
||||
return web.json_response({"error": str(e)}, status=500)
|
||||
|
||||
|
||||
async def semantic_folders(request: web.Request) -> web.Response:
|
||||
root = request.rel_url.query.get("root", "")
|
||||
try:
|
||||
return web.json_response({"folders": await asyncio.to_thread(_semantic.folder_status, root)})
|
||||
except SemanticError as e:
|
||||
return _semantic_error(e)
|
||||
except Exception as e:
|
||||
logger.error("semantic_folders error: %s", e)
|
||||
return web.json_response({"error": str(e)}, status=500)
|
||||
|
||||
|
||||
def _apply_local_options(body: dict) -> None:
|
||||
"""リクエストに Ollama の接続先/モデルサイズが含まれていれば反映・保存する"""
|
||||
if "ollama_url" in body:
|
||||
_semantic.set_local_options(str(body.get("ollama_url", "")), str(body.get("ollama_tag", "")))
|
||||
|
||||
|
||||
async def semantic_index(request: web.Request) -> web.Response:
|
||||
body = await _json_body(request)
|
||||
try:
|
||||
_apply_local_options(body)
|
||||
await asyncio.to_thread(
|
||||
_semantic.start_index,
|
||||
str(body.get("folder", "")),
|
||||
bool(body.get("recursive", True)),
|
||||
"all" if body.get("mode") == "all" else "missing",
|
||||
str(body.get("model", SEMANTIC_DEFAULT_MODEL)),
|
||||
_num(body, "dim", DEFAULT_DIM, 0, 100000),
|
||||
)
|
||||
return web.json_response({"ok": True})
|
||||
except SemanticError as e:
|
||||
return _semantic_error(e)
|
||||
except Exception as e:
|
||||
logger.error("semantic_index error: %s", e)
|
||||
return web.json_response({"error": str(e)}, status=500)
|
||||
|
||||
|
||||
async def semantic_cancel(request: web.Request) -> web.Response:
|
||||
_semantic.cancel()
|
||||
return web.json_response({"ok": True})
|
||||
|
||||
|
||||
async def semantic_search(request: web.Request) -> web.Response:
|
||||
body = await _json_body(request)
|
||||
try:
|
||||
limit = _num(body, "limit", 200, 1, 1000)
|
||||
min_score = _num(body, "min_score", 0.0, -1.0, 1.0, float)
|
||||
images = await asyncio.to_thread(
|
||||
_semantic.search_text, str(body.get("query", "")), str(body.get("folder", "")),
|
||||
bool(body.get("recursive", True)), limit, min_score,
|
||||
)
|
||||
return web.json_response({"images": images, "total": len(images)})
|
||||
except SemanticError as e:
|
||||
return _semantic_error(e)
|
||||
except Exception as e:
|
||||
logger.error("semantic_search error: %s", e)
|
||||
return web.json_response({"error": str(e)}, status=500)
|
||||
|
||||
|
||||
async def semantic_similar(request: web.Request) -> web.Response:
|
||||
body = await _json_body(request)
|
||||
try:
|
||||
limit = _num(body, "limit", 200, 1, 1000)
|
||||
min_score = _num(body, "min_score", 0.0, -1.0, 1.0, float)
|
||||
images = await asyncio.to_thread(
|
||||
_semantic.search_similar, str(body.get("path", "")), str(body.get("folder", "")),
|
||||
bool(body.get("recursive", True)), limit, min_score,
|
||||
)
|
||||
return web.json_response({"images": images, "total": len(images)})
|
||||
except SemanticError as e:
|
||||
return _semantic_error(e)
|
||||
except Exception as e:
|
||||
logger.error("semantic_similar error: %s", e)
|
||||
return web.json_response({"error": str(e)}, status=500)
|
||||
|
||||
|
||||
async def semantic_clear(request: web.Request) -> web.Response:
|
||||
try:
|
||||
await asyncio.to_thread(_semantic.clear)
|
||||
return web.json_response({"ok": True})
|
||||
except SemanticError as e:
|
||||
return _semantic_error(e)
|
||||
|
||||
|
||||
async def semantic_test(request: web.Request) -> web.Response:
|
||||
body = await _json_body(request)
|
||||
try:
|
||||
_apply_local_options(body)
|
||||
res = await asyncio.to_thread(_semantic.test_connection, str(body.get("model", SEMANTIC_DEFAULT_MODEL)), _num(body, "dim", DEFAULT_DIM, 0, 100000))
|
||||
return web.json_response({"ok": True, **res})
|
||||
except SemanticError as e:
|
||||
return _semantic_error(e)
|
||||
except Exception as e:
|
||||
return web.json_response({"error": str(e)}, status=500)
|
||||
|
||||
|
||||
# ──────────────────────────────────────────────────────────────
|
||||
@@ -64,19 +281,25 @@ async def list_images(request: web.Request) -> web.Response:
|
||||
favorite_only = request.rel_url.query.get("favorite", "false") == "true"
|
||||
tag_filter = request.rel_url.query.get("tag", "")
|
||||
group_filter = request.rel_url.query.get("group", "")
|
||||
recursive = request.rel_url.query.get("recursive", "false") == "true"
|
||||
|
||||
if not folder:
|
||||
return web.json_response({"error": "folder parameter required"}, status=400)
|
||||
|
||||
try:
|
||||
images = _service.list_images(
|
||||
images = await asyncio.to_thread(
|
||||
_service.list_images,
|
||||
folder,
|
||||
search=search,
|
||||
sort_by=sort_by,
|
||||
favorite_only=favorite_only,
|
||||
tag_filter=tag_filter,
|
||||
group_filter=group_filter,
|
||||
recursive=recursive,
|
||||
)
|
||||
# 検索なしのフォルダロード時にバックグラウンドインデックスを起動
|
||||
if not search:
|
||||
_service.start_background_index(folder)
|
||||
return web.json_response({"images": images, "total": len(images)})
|
||||
except Exception as e:
|
||||
logger.error("list_images error: %s", e)
|
||||
@@ -104,9 +327,15 @@ async def get_image_workflow(request: web.Request) -> web.Response:
|
||||
return web.json_response({"error": "path required"}, status=400)
|
||||
try:
|
||||
wf = _service.extract_workflow_from_metadata(path)
|
||||
if wf is None:
|
||||
return web.json_response({"workflow": None, "has_workflow": False})
|
||||
return web.json_response({"workflow": wf, "has_workflow": True})
|
||||
# prompt_workflow: プロンプト抽出専用(PNG[prompt]優先)。トップレベルとサブグラフに
|
||||
# 独立した複数系統を持つワークフローではUI形式(workflow)からの抽出がトップレベル
|
||||
# 系統しか拾えないことがあるため、Promptタブはこちらを使う(Metadataタブと揃える)。
|
||||
prompt_wf = _service.extract_prompt_workflow_from_metadata(path)
|
||||
return web.json_response({
|
||||
"workflow": wf,
|
||||
"has_workflow": wf is not None,
|
||||
"prompt_workflow": prompt_wf,
|
||||
})
|
||||
except Exception as e:
|
||||
return web.json_response({"error": str(e)}, status=500)
|
||||
|
||||
@@ -116,7 +345,10 @@ async def serve_image(request: web.Request) -> web.Response:
|
||||
if not path:
|
||||
return web.Response(status=400)
|
||||
|
||||
img_path = _service.serve_image(path)
|
||||
# PSDの合成処理はCPU負荷が高く同期実行するとイベントループ全体をブロックする
|
||||
# (他の並行リクエスト、例えば別画像のサムネイル配信も止まってしまう)ためexecutorで実行する
|
||||
loop = asyncio.get_event_loop()
|
||||
img_path = await loop.run_in_executor(None, _service.serve_image, path)
|
||||
if img_path is None:
|
||||
return web.Response(status=404)
|
||||
|
||||
@@ -127,6 +359,119 @@ async def serve_image(request: web.Request) -> web.Response:
|
||||
})
|
||||
|
||||
|
||||
async def serve_thumb(request: web.Request) -> web.Response:
|
||||
"""サムネイル配信。Pillowで縮小したJPEGをディスクキャッシュして返す。"""
|
||||
path = request.rel_url.query.get("path", "")
|
||||
if not path:
|
||||
return web.Response(status=400)
|
||||
try:
|
||||
width = int(request.rel_url.query.get("w", "256"))
|
||||
width = max(32, min(512, width))
|
||||
except ValueError:
|
||||
width = 256
|
||||
|
||||
# PSD/MP4のサムネイル生成はCPU負荷が高く同期実行するとイベントループ全体をブロックするため
|
||||
# executorで実行する(他画像のサムネイル配信が巻き添えで遅延・停止するのを防ぐ)
|
||||
loop = asyncio.get_event_loop()
|
||||
thumb_path = await loop.run_in_executor(None, _service.serve_thumbnail, path, width)
|
||||
if thumb_path is None:
|
||||
return web.Response(status=404)
|
||||
|
||||
ext = thumb_path.suffix.lower()
|
||||
if ext in (".jpg", ".jpeg"):
|
||||
content_type = "image/jpeg"
|
||||
elif ext == ".gif":
|
||||
content_type = "image/gif"
|
||||
else:
|
||||
content_type = mimetypes.guess_type(str(thumb_path))[0] or "image/jpeg"
|
||||
|
||||
return web.FileResponse(thumb_path, headers={
|
||||
"Content-Type": content_type,
|
||||
"Cache-Control": "max-age=86400",
|
||||
})
|
||||
|
||||
|
||||
async def save_model3d_thumb(request: web.Request) -> web.Response:
|
||||
"""POST /wfm/gallery/image/thumb3d — ブラウザが描画した3Dモデルのサムネイルを保存する"""
|
||||
try:
|
||||
body = await request.json()
|
||||
path = body.get("path", "")
|
||||
image = body.get("image", "")
|
||||
if not path or not image:
|
||||
return web.json_response({"ok": False, "error": "path and image required"}, status=400)
|
||||
loop = asyncio.get_event_loop()
|
||||
result = await loop.run_in_executor(None, _service.save_model3d_thumbnail, path, image)
|
||||
return web.json_response(result, status=200 if result.get("ok") else 400)
|
||||
except Exception as e:
|
||||
return web.json_response({"ok": False, "error": str(e)}, status=500)
|
||||
|
||||
|
||||
async def serve_model3d_asset(request: web.Request) -> web.Response:
|
||||
"""GET /wfm/gallery/model3d/asset — .gltfが参照する外部ファイル(.bin/テクスチャ)を配信する"""
|
||||
path = request.rel_url.query.get("path", "")
|
||||
uri = request.rel_url.query.get("uri", "")
|
||||
if not path or not uri:
|
||||
return web.Response(status=400)
|
||||
asset = _service.serve_model3d_asset(path, uri)
|
||||
if asset is None:
|
||||
return web.Response(status=404)
|
||||
content_type, _ = mimetypes.guess_type(str(asset))
|
||||
return web.FileResponse(asset, headers={
|
||||
"Content-Type": content_type or "application/octet-stream",
|
||||
"Cache-Control": "max-age=3600",
|
||||
})
|
||||
|
||||
|
||||
# ──────────────────────────────────────────────────────────────
|
||||
# バルク操作
|
||||
# ──────────────────────────────────────────────────────────────
|
||||
|
||||
async def convert_file_route(request: web.Request) -> web.Response:
|
||||
"""POST /wfm/gallery/convert — 音声/動画の音声を別形式へ変換(1ファイルずつ呼ぶ)"""
|
||||
try:
|
||||
body = await request.json()
|
||||
path = body.get("path", "")
|
||||
if not path:
|
||||
return web.json_response({"ok": False, "error": "path required"}, status=400)
|
||||
# 変換はCPU負荷が高く同期実行するとイベントループ全体が止まるためexecutorで実行する
|
||||
loop = asyncio.get_event_loop()
|
||||
result = await loop.run_in_executor(None, _service.convert_file, path, body)
|
||||
return web.json_response(result, status=200 if result.get("ok") else 400)
|
||||
except Exception as e:
|
||||
return web.json_response({"ok": False, "error": str(e)}, status=500)
|
||||
|
||||
|
||||
async def bulk_favorite(request: web.Request) -> web.Response:
|
||||
"""POST /wfm/gallery/bulk/favorite — 複数画像のお気に入りを一括設定"""
|
||||
try:
|
||||
body = await request.json()
|
||||
paths = body.get("paths", [])
|
||||
value = bool(body.get("value", True))
|
||||
if not paths:
|
||||
return web.json_response({"error": "paths required"}, status=400)
|
||||
result = _service.bulk_set_favorite(paths, value)
|
||||
return web.json_response(result)
|
||||
except Exception as e:
|
||||
return web.json_response({"error": str(e)}, status=500)
|
||||
|
||||
|
||||
async def bulk_group(request: web.Request) -> web.Response:
|
||||
"""POST /wfm/gallery/bulk/group — 複数画像のグループ追加/削除を一括処理"""
|
||||
try:
|
||||
body = await request.json()
|
||||
paths = body.get("paths", [])
|
||||
group = body.get("group", "").strip()
|
||||
action = body.get("action", "add") # "add" or "remove"
|
||||
if not paths or not group:
|
||||
return web.json_response({"error": "paths and group required"}, status=400)
|
||||
if action not in ("add", "remove"):
|
||||
return web.json_response({"error": "action must be 'add' or 'remove'"}, status=400)
|
||||
result = _service.bulk_group_op(paths, group, action)
|
||||
return web.json_response(result)
|
||||
except Exception as e:
|
||||
return web.json_response({"error": str(e)}, status=500)
|
||||
|
||||
|
||||
async def save_image_meta(request: web.Request) -> web.Response:
|
||||
try:
|
||||
body = await request.json()
|
||||
@@ -140,6 +485,36 @@ async def save_image_meta(request: web.Request) -> web.Response:
|
||||
return web.json_response({"error": str(e)}, status=500)
|
||||
|
||||
|
||||
async def get_image_prompt_root(request: web.Request) -> web.Response:
|
||||
"""GET /wfm/gallery/image-prompt/root — ImagePromptギャラリーのルートフォルダを返す"""
|
||||
root = _service.get_image_prompt_root()
|
||||
if root is None:
|
||||
return web.json_response({"error": "ComfyUI output directory not resolved"}, status=500)
|
||||
return web.json_response({"root": root})
|
||||
|
||||
|
||||
async def save_image_prompt(request: web.Request) -> web.Response:
|
||||
"""POST /wfm/gallery/image/image-prompt — 画像の.txtサイドカーにプロンプトを保存"""
|
||||
try:
|
||||
body = await request.json()
|
||||
img_path = body.get("path", "")
|
||||
prompt = body.get("prompt", "")
|
||||
if not img_path:
|
||||
return web.json_response({"error": "path required"}, status=400)
|
||||
ok = _service.save_image_prompt(img_path, prompt)
|
||||
return web.json_response({"ok": ok})
|
||||
except Exception as e:
|
||||
return web.json_response({"error": str(e)}, status=500)
|
||||
|
||||
|
||||
async def get_style_catalog_root(request: web.Request) -> web.Response:
|
||||
"""GET /wfm/gallery/style-catalog/root — Style Catalogギャラリーのルートフォルダを返す"""
|
||||
root = _service.get_style_catalog_root()
|
||||
if root is None:
|
||||
return web.json_response({"error": "ComfyUI output directory not resolved"}, status=500)
|
||||
return web.json_response({"root": root})
|
||||
|
||||
|
||||
async def toggle_favorite(request: web.Request) -> web.Response:
|
||||
try:
|
||||
body = await request.json()
|
||||
@@ -152,6 +527,78 @@ async def toggle_favorite(request: web.Request) -> web.Response:
|
||||
return web.json_response({"error": str(e)}, status=500)
|
||||
|
||||
|
||||
async def save_image_to_gallery(request: web.Request) -> web.Response:
|
||||
"""Image Edit Tab / AI Chat からの画像(PNG等)やSVGをギャラリーのルートフォルダに保存する。
|
||||
imageData は data URL (data:<mime>;base64,<data>) を想定。ヘッダがなければPNG扱い(旧互換)。"""
|
||||
try:
|
||||
body = await request.json()
|
||||
filename = body.get("filename", "").strip()
|
||||
image_data = body.get("imageData", "")
|
||||
|
||||
if not filename or not image_data:
|
||||
return web.json_response({"error": "filename and imageData required"}, status=400)
|
||||
|
||||
if _service._allowed_root is None:
|
||||
return web.json_response({"error": "Gallery root not configured. Open Gallery tab and set output folder first."}, status=500)
|
||||
|
||||
result = _service.save_image_to_folder(str(_service._allowed_root), filename, image_data)
|
||||
if not result["ok"]:
|
||||
return web.json_response({"error": result["error"]}, status=400)
|
||||
|
||||
logger.info("save_image_to_gallery: saved %s", result["path"])
|
||||
return web.json_response({"ok": True, "path": result["path"]})
|
||||
except Exception as e:
|
||||
logger.error("save_image_to_gallery error: %s", e)
|
||||
return web.json_response({"error": str(e)}, status=500)
|
||||
|
||||
|
||||
async def save_image_to_folder_route(request: web.Request) -> web.Response:
|
||||
"""POST /wfm/gallery/image/save-to-folder — 任意フォルダへ画像を保存(同名なら上書き)。
|
||||
Style Catalogのカタログ作成で、スタイル名をファイル名として使う際に利用する。"""
|
||||
try:
|
||||
body = await request.json()
|
||||
folder = body.get("folder", "").strip()
|
||||
filename = body.get("filename", "").strip()
|
||||
image_data = body.get("imageData", "")
|
||||
|
||||
if not folder or not filename or not image_data:
|
||||
return web.json_response({"error": "folder, filename and imageData required"}, status=400)
|
||||
|
||||
result = _service.save_image_to_folder(folder, filename, image_data)
|
||||
if not result["ok"]:
|
||||
return web.json_response({"error": result["error"]}, status=400)
|
||||
return web.json_response({"ok": True, "path": result["path"]})
|
||||
except Exception as e:
|
||||
logger.error("save_image_to_folder_route error: %s", e)
|
||||
return web.json_response({"error": str(e)}, status=500)
|
||||
|
||||
|
||||
async def delete_output_image(request: web.Request) -> web.Response:
|
||||
"""POST /wfm/gallery/output-image/delete — ComfyUI標準の画像参照(filename/subfolder/type)から
|
||||
実ファイルを削除する。Style Catalogのカタログ作成で「Outputフォルダに画像を残さない」
|
||||
オプションが有効な時、カタログへコピー保存した直後の元画像を消すために使う。
|
||||
type="output" 以外は拒否する(temp/inputの誤削除を防止)。"""
|
||||
try:
|
||||
body = await request.json()
|
||||
filename = (body.get("filename") or "").strip()
|
||||
subfolder = body.get("subfolder") or ""
|
||||
img_type = body.get("type") or ""
|
||||
if not filename or img_type != "output":
|
||||
return web.json_response({"error": "filename required and type must be 'output'"}, status=400)
|
||||
|
||||
import folder_paths # type: ignore
|
||||
output_dir = Path(folder_paths.get_output_directory())
|
||||
target = output_dir / subfolder / filename
|
||||
|
||||
result = await asyncio.to_thread(_service.delete_images, [str(target)])
|
||||
if result["deleted"]:
|
||||
return web.json_response({"ok": True})
|
||||
return web.json_response({"error": "; ".join(result["errors"]) or "File not found"}, status=404)
|
||||
except Exception as e:
|
||||
logger.error("delete_output_image error: %s", e)
|
||||
return web.json_response({"error": str(e)}, status=500)
|
||||
|
||||
|
||||
# ──────────────────────────────────────────────────────────────
|
||||
# グループ管理
|
||||
# ──────────────────────────────────────────────────────────────
|
||||
@@ -174,10 +621,15 @@ async def create_group(request: web.Request) -> web.Response:
|
||||
return web.json_response({"error": str(e)}, status=500)
|
||||
|
||||
|
||||
_RESERVED_GROUPS = {"__Feeder__", "__Video Assets__", "__Video Temp__"}
|
||||
|
||||
|
||||
async def rename_group(request: web.Request) -> web.Response:
|
||||
"""PUT /wfm/gallery/groups/{name} - グループ名変更"""
|
||||
try:
|
||||
old_name = request.match_info.get("name", "")
|
||||
if old_name in _RESERVED_GROUPS:
|
||||
return web.json_response({"error": f"Group '{old_name}' is reserved and cannot be renamed"}, status=403)
|
||||
body = await request.json()
|
||||
new_name = body.get("new_name", "").strip()
|
||||
if not old_name or not new_name:
|
||||
@@ -192,6 +644,8 @@ async def rename_group(request: web.Request) -> web.Response:
|
||||
|
||||
async def delete_group(request: web.Request) -> web.Response:
|
||||
name = request.match_info.get("name", "")
|
||||
if name in _RESERVED_GROUPS:
|
||||
return web.json_response({"error": f"Group '{name}' is reserved and cannot be deleted"}, status=403)
|
||||
ok = _service.delete_group(name)
|
||||
return web.json_response({"ok": ok})
|
||||
|
||||
@@ -224,6 +678,28 @@ async def list_group_images(request: web.Request) -> web.Response:
|
||||
return web.json_response({"images": images})
|
||||
|
||||
|
||||
async def clear_group_images(request: web.Request) -> web.Response:
|
||||
"""POST /wfm/gallery/groups/{name}/clear - グループ内の全画像を除外"""
|
||||
name = request.match_info.get("name", "")
|
||||
if not name:
|
||||
return web.json_response({"error": "name required"}, status=400)
|
||||
ok = _service.clear_group(name)
|
||||
return web.json_response({"ok": ok})
|
||||
|
||||
|
||||
async def ensure_group(request: web.Request) -> web.Response:
|
||||
"""POST /wfm/gallery/groups/ensure - グループが存在しない場合のみ作成"""
|
||||
try:
|
||||
body = await request.json()
|
||||
name = body.get("name", "").strip()
|
||||
if not name:
|
||||
return web.json_response({"error": "name required"}, status=400)
|
||||
_service.ensure_group(name)
|
||||
return web.json_response({"ok": True})
|
||||
except Exception as e:
|
||||
return web.json_response({"error": str(e)}, status=500)
|
||||
|
||||
|
||||
# ──────────────────────────────────────────────────────────────
|
||||
# フォルダ・ファイル操作
|
||||
# ──────────────────────────────────────────────────────────────
|
||||
@@ -280,3 +756,144 @@ async def move_images_route(request: web.Request) -> web.Response:
|
||||
return web.json_response(result)
|
||||
except Exception as e:
|
||||
return web.json_response({"moved": [], "errors": [str(e)]}, status=500)
|
||||
|
||||
|
||||
async def export_images_zip(request: web.Request) -> web.Response:
|
||||
"""POST /wfm/gallery/images/export-zip - 複数画像をZIPファイルにしてダウンロード"""
|
||||
import zipfile
|
||||
import io
|
||||
|
||||
try:
|
||||
body = await request.json()
|
||||
paths = body.get("paths", [])
|
||||
if not paths:
|
||||
return web.json_response({"error": "paths required"}, status=400)
|
||||
|
||||
# ZIPファイルをメモリ上に作成
|
||||
zip_buffer = io.BytesIO()
|
||||
with zipfile.ZipFile(zip_buffer, "w", zipfile.ZIP_DEFLATED) as zf:
|
||||
for path in paths:
|
||||
file_path = Path(path)
|
||||
# セキュリティ: 許可されたディレクトリ内のみ
|
||||
if not _service._check_path_allowed(file_path):
|
||||
continue
|
||||
if file_path.exists() and file_path.is_file():
|
||||
# ファイル名のみをアーカイブに入れる(パス情報は含めない)
|
||||
zf.write(file_path, arcname=file_path.name)
|
||||
|
||||
zip_buffer.seek(0)
|
||||
return web.Response(
|
||||
body=zip_buffer.getvalue(),
|
||||
content_type="application/zip",
|
||||
headers={"Content-Disposition": "attachment; filename=gallery_export.zip"}
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error("Error exporting images to ZIP: %s", e)
|
||||
return web.json_response({"error": str(e)}, status=500)
|
||||
|
||||
|
||||
async def export_images_psd(request: web.Request) -> web.Response:
|
||||
"""POST /wfm/gallery/images/export-psd - 複数画像を1つのPSD(レイヤー分割)にしてダウンロード"""
|
||||
try:
|
||||
body = await request.json()
|
||||
paths = body.get("paths", [])
|
||||
if not paths:
|
||||
return web.json_response({"error": "paths required"}, status=400)
|
||||
|
||||
psd_bytes = _service.build_psd_from_images(paths)
|
||||
|
||||
return web.Response(
|
||||
body=psd_bytes,
|
||||
content_type="image/vnd.adobe.photoshop",
|
||||
headers={"Content-Disposition": "attachment; filename=gallery_export.psd"}
|
||||
)
|
||||
except RuntimeError as e:
|
||||
logger.error("PSD export dependency missing: %s", e)
|
||||
return web.json_response({"error": str(e)}, status=500)
|
||||
except ValueError as e:
|
||||
return web.json_response({"error": str(e)}, status=400)
|
||||
except Exception as e:
|
||||
logger.error("Error exporting images to PSD: %s", e)
|
||||
return web.json_response({"error": str(e)}, status=500)
|
||||
|
||||
|
||||
async def export_psd_from_layers(request: web.Request) -> web.Response:
|
||||
"""POST /wfm/gallery/image/export-psd-layers - Image Editタブのレイヤー配列を1つのPSDにしてダウンロード"""
|
||||
try:
|
||||
body = await request.json()
|
||||
width = int(body.get("width", 0))
|
||||
height = int(body.get("height", 0))
|
||||
layers = body.get("layers", [])
|
||||
if not layers:
|
||||
return web.json_response({"error": "layers required"}, status=400)
|
||||
|
||||
psd_bytes = _service.build_psd_from_layers(width, height, layers)
|
||||
|
||||
return web.Response(
|
||||
body=psd_bytes,
|
||||
content_type="image/vnd.adobe.photoshop",
|
||||
headers={"Content-Disposition": "attachment; filename=image_edit_export.psd"}
|
||||
)
|
||||
except RuntimeError as e:
|
||||
logger.error("PSD export dependency missing: %s", e)
|
||||
return web.json_response({"error": str(e)}, status=500)
|
||||
except ValueError as e:
|
||||
return web.json_response({"error": str(e)}, status=400)
|
||||
except Exception as e:
|
||||
logger.error("Error exporting Image Edit layers to PSD: %s", e)
|
||||
return web.json_response({"error": str(e)}, status=500)
|
||||
|
||||
|
||||
async def import_psd_layers(request: web.Request) -> web.Response:
|
||||
"""POST /wfm/gallery/image/import-psd-layers - アップロードされたPSDをレイヤー配列(JSON)に分解して返す"""
|
||||
try:
|
||||
reader = await request.multipart()
|
||||
field = await reader.next()
|
||||
if field is None:
|
||||
return web.json_response({"error": "file required"}, status=400)
|
||||
psd_bytes = await field.read(decode=False)
|
||||
|
||||
loop = asyncio.get_event_loop()
|
||||
result = await loop.run_in_executor(None, _service.import_psd_layers, psd_bytes)
|
||||
return web.json_response(result)
|
||||
except RuntimeError as e:
|
||||
logger.error("PSD import dependency missing: %s", e)
|
||||
return web.json_response({"error": str(e)}, status=500)
|
||||
except ValueError as e:
|
||||
return web.json_response({"error": str(e)}, status=400)
|
||||
except Exception as e:
|
||||
logger.error("Error importing PSD layers: %s", e)
|
||||
return web.json_response({"error": str(e)}, status=500)
|
||||
|
||||
|
||||
async def get_psd_layers(request: web.Request) -> web.Response:
|
||||
"""GET /wfm/gallery/image/psd-layers - サーバー上のPSDファイルをレイヤー配列(JSON)に分解して返す
|
||||
(Galleryから直接Image Editへ送る際、アップロードの往復を挟まずに済ませるため)"""
|
||||
path = request.rel_url.query.get("path", "")
|
||||
if not path:
|
||||
return web.json_response({"error": "path required"}, status=400)
|
||||
try:
|
||||
loop = asyncio.get_event_loop()
|
||||
result = await loop.run_in_executor(None, _service.get_psd_layers_from_path, path)
|
||||
return web.json_response(result)
|
||||
except RuntimeError as e:
|
||||
logger.error("PSD import dependency missing: %s", e)
|
||||
return web.json_response({"error": str(e)}, status=500)
|
||||
except ValueError as e:
|
||||
return web.json_response({"error": str(e)}, status=400)
|
||||
except Exception as e:
|
||||
logger.error("Error reading PSD layers: %s", e)
|
||||
return web.json_response({"error": str(e)}, status=500)
|
||||
|
||||
|
||||
async def semantic_options(request: web.Request) -> web.Response:
|
||||
"""Ollama の接続先/モデルサイズを保存して、新しい状態を返す"""
|
||||
body = await _json_body(request)
|
||||
try:
|
||||
await asyncio.to_thread(_apply_local_options, body)
|
||||
return web.json_response(await asyncio.to_thread(_semantic.status))
|
||||
except SemanticError as e:
|
||||
return _semantic_error(e)
|
||||
except Exception as e:
|
||||
logger.error("semantic_options error: %s", e)
|
||||
return web.json_response({"error": str(e)}, status=500)
|
||||
|
||||
@@ -0,0 +1,186 @@
|
||||
"""G'MIC-Qt integration API routes."""
|
||||
|
||||
import asyncio
|
||||
import base64
|
||||
import datetime
|
||||
import json
|
||||
import logging
|
||||
import mimetypes
|
||||
import os
|
||||
import subprocess
|
||||
import threading
|
||||
import uuid
|
||||
from pathlib import Path
|
||||
from aiohttp import web
|
||||
|
||||
from ..services.settings_service import SettingsService
|
||||
from ..config import DATA_DIR, resolve_untrusted
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
_settings = SettingsService()
|
||||
|
||||
# Global job store
|
||||
# key: job_id, value: dict {status, message, result_path, error}
|
||||
_gmic_jobs = {}
|
||||
_gmic_jobs_lock = threading.Lock()
|
||||
|
||||
def _gmic_run_gui(job_id: str, input_path: str, output_path: str, gmic_exe: str):
|
||||
"""Run gmic_qt.exe in a background process/thread and wait for completion.
|
||||
|
||||
G'MIC-Qt Standalone argument order: -o <output> <input>
|
||||
After OK the "filter output" window appears; closing it saves to output_path.
|
||||
"""
|
||||
args = [gmic_exe, "-o", output_path, input_path]
|
||||
logger.info("[gmic] Launching: %s", " ".join(args))
|
||||
try:
|
||||
with _gmic_jobs_lock:
|
||||
_gmic_jobs[job_id]["status"] = "processing"
|
||||
_gmic_jobs[job_id]["message"] = "G'MIC GUIで編集中..."
|
||||
|
||||
import time
|
||||
|
||||
kwargs = {}
|
||||
if os.name == "nt":
|
||||
# Required on Windows to show the GUI window from a background process
|
||||
kwargs["creationflags"] = subprocess.CREATE_NEW_CONSOLE
|
||||
|
||||
proc = subprocess.Popen(args, **kwargs)
|
||||
proc.wait()
|
||||
|
||||
time.sleep(0.5)
|
||||
|
||||
if os.path.exists(output_path) and os.path.getsize(output_path) > 0:
|
||||
with _gmic_jobs_lock:
|
||||
_gmic_jobs[job_id]["status"] = "completed"
|
||||
_gmic_jobs[job_id]["result_path"] = output_path
|
||||
_gmic_jobs[job_id]["message"] = "完了"
|
||||
logger.info("[gmic] Result saved: %s", output_path)
|
||||
else:
|
||||
raise ValueError("G'MIC GUIがキャンセルされました")
|
||||
except Exception as e:
|
||||
with _gmic_jobs_lock:
|
||||
_gmic_jobs[job_id]["status"] = "failed"
|
||||
_gmic_jobs[job_id]["error"] = str(e)
|
||||
_gmic_jobs[job_id]["message"] = f"エラー: {str(e)}"
|
||||
logger.error("[gmic] Error: %s", e)
|
||||
|
||||
def setup_routes(app: web.Application):
|
||||
"""Register G'MIC API routes."""
|
||||
app.router.add_post("/api/wfm/gmic/open", handle_open)
|
||||
app.router.add_get("/api/wfm/gmic/status/{job_id}", handle_status)
|
||||
app.router.add_post("/api/wfm/gmic/result", handle_result)
|
||||
|
||||
async def handle_open(request: web.Request) -> web.Response:
|
||||
"""POST /api/wfm/gmic/open - Open image in G'MIC GUI."""
|
||||
try:
|
||||
body = await request.json()
|
||||
image_b64 = body.get("image_b64", "")
|
||||
if not image_b64:
|
||||
return web.json_response({"error": "image_b64 field is required"}, status=400)
|
||||
|
||||
# Retrieve setting for gmic path
|
||||
data = _settings.load()
|
||||
gmic_exe = data.get("gmic_qt_path", "")
|
||||
if not os.path.isabs(gmic_exe) or os.path.splitext(gmic_exe)[1].lower() != ".exe" or not os.path.isfile(gmic_exe):
|
||||
return web.json_response({
|
||||
"error": f"G'MIC executable not found at: {gmic_exe}. Please configure an absolute .exe path in settings."
|
||||
}, status=400)
|
||||
|
||||
ext = ".png"
|
||||
if image_b64.startswith("data:"):
|
||||
header, image_b64 = image_b64.split(",", 1)
|
||||
mime = header.split(";")[0].split(":")[1]
|
||||
guessed = mimetypes.guess_extension(mime)
|
||||
if guessed:
|
||||
ext = ".jpg" if guessed == ".jpe" else guessed
|
||||
|
||||
img_bytes = base64.b64decode(image_b64)
|
||||
|
||||
temp_dir = Path(DATA_DIR) / "gmic_temp"
|
||||
temp_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
now_str = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
|
||||
input_path = str(temp_dir / f"gmic_input_{now_str}{ext}")
|
||||
output_path = str(temp_dir / f"gmic_output_{now_str}_{str(uuid.uuid4())[:8]}{ext}")
|
||||
|
||||
with open(input_path, "wb") as f:
|
||||
f.write(img_bytes)
|
||||
|
||||
job_id = str(uuid.uuid4())
|
||||
with _gmic_jobs_lock:
|
||||
_gmic_jobs[job_id] = {
|
||||
"status": "pending",
|
||||
"message": "G'MIC GUIを起動中...",
|
||||
"result_path": None,
|
||||
"error": None,
|
||||
}
|
||||
|
||||
# Start G'MIC thread
|
||||
t = threading.Thread(
|
||||
target=_gmic_run_gui,
|
||||
args=(job_id, input_path, output_path, gmic_exe),
|
||||
daemon=True,
|
||||
)
|
||||
t.start()
|
||||
|
||||
return web.json_response({"job_id": job_id, "status": "pending", "message": "起動中"})
|
||||
except Exception as e:
|
||||
logger.error("[gmic] open error: %s", e)
|
||||
return web.json_response({"error": str(e)}, status=500)
|
||||
|
||||
async def handle_status(request: web.Request) -> web.Response:
|
||||
"""GET /api/wfm/gmic/status/{job_id} - Check job status."""
|
||||
try:
|
||||
job_id = request.match_info.get("job_id", "")
|
||||
with _gmic_jobs_lock:
|
||||
job = _gmic_jobs.get(job_id)
|
||||
if job is None:
|
||||
return web.json_response({"error": "Job not found"}, status=404)
|
||||
return web.json_response({
|
||||
"job_id": job_id,
|
||||
"status": job["status"],
|
||||
"message": job.get("message", ""),
|
||||
"result_path": job.get("result_path"),
|
||||
"error": job.get("error"),
|
||||
})
|
||||
except Exception as e:
|
||||
logger.error("[gmic] status error: %s", e)
|
||||
return web.json_response({"error": str(e)}, status=500)
|
||||
|
||||
async def handle_result(request: web.Request) -> web.Response:
|
||||
"""POST /api/wfm/gmic/result - Get result image base64."""
|
||||
try:
|
||||
body = await request.json()
|
||||
result_path = body.get("result_path", "")
|
||||
|
||||
# Path traversal guard: only allow files inside gmic_temp.
|
||||
# UNC(\\host\share)は exists()/resolve() を呼んだ時点で相手ホストへ資格情報付きで
|
||||
# 接続してしまうため、パス操作より先に文字列のまま検査する(resolve_untrusted)。
|
||||
allowed_dir = (Path(DATA_DIR) / "gmic_temp").resolve()
|
||||
try:
|
||||
resolved = resolve_untrusted(result_path)
|
||||
resolved.relative_to(allowed_dir)
|
||||
except ValueError:
|
||||
return web.json_response({"error": "Access denied: path outside gmic_temp"}, status=403)
|
||||
if not resolved.is_file():
|
||||
return web.json_response({"error": f"Result file not found: {result_path}"}, status=404)
|
||||
|
||||
with open(resolved, "rb") as f:
|
||||
img_bytes = f.read()
|
||||
|
||||
ext = os.path.splitext(result_path)[1].lower()
|
||||
mime_map = {
|
||||
".png": "image/png",
|
||||
".jpg": "image/jpeg",
|
||||
".jpeg": "image/jpeg",
|
||||
".webp": "image/webp",
|
||||
".bmp": "image/bmp",
|
||||
".tiff": "image/tiff"
|
||||
}
|
||||
mime = mime_map.get(ext, "image/png")
|
||||
b64 = base64.b64encode(img_bytes).decode("ascii")
|
||||
return web.json_response({"image_b64": f"data:{mime};base64,{b64}"})
|
||||
except Exception as e:
|
||||
logger.error("[gmic] result error: %s", e)
|
||||
return web.json_response({"error": str(e)}, status=500)
|
||||
@@ -0,0 +1,85 @@
|
||||
"""Lab tab plan file management API routes."""
|
||||
|
||||
import asyncio
|
||||
import logging
|
||||
|
||||
from aiohttp import web
|
||||
|
||||
from ..config import LAB_PLAN_DIR
|
||||
from ..services.lab_plan_service import LabPlanService
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
_service = LabPlanService(LAB_PLAN_DIR)
|
||||
|
||||
|
||||
def setup_routes(app: web.Application):
|
||||
app.router.add_get("/api/wfm/lab/plans", handle_list)
|
||||
app.router.add_get("/api/wfm/lab/plans/content", handle_get_content)
|
||||
app.router.add_post("/api/wfm/lab/plans/save", handle_save)
|
||||
app.router.add_post("/api/wfm/lab/plans/delete", handle_delete)
|
||||
app.router.add_post("/api/wfm/lab/index-image/save-to-output", handle_save_index_to_output)
|
||||
|
||||
|
||||
async def handle_list(request: web.Request) -> web.Response:
|
||||
try:
|
||||
result = await asyncio.to_thread(_service.list_plans)
|
||||
return web.json_response(result)
|
||||
except Exception as e:
|
||||
logger.error("Error listing lab plans: %s", e)
|
||||
return web.json_response({"error": str(e)}, status=500)
|
||||
|
||||
|
||||
async def handle_get_content(request: web.Request) -> web.Response:
|
||||
filename = request.rel_url.query.get("filename", "")
|
||||
try:
|
||||
data = await asyncio.to_thread(_service.get_plan, filename)
|
||||
return web.json_response({"data": data})
|
||||
except FileNotFoundError:
|
||||
return web.json_response({"error": "not found"}, status=404)
|
||||
except ValueError as e:
|
||||
return web.json_response({"error": str(e)}, status=400)
|
||||
except Exception as e:
|
||||
logger.error("Error getting lab plan content: %s", e)
|
||||
return web.json_response({"error": str(e)}, status=500)
|
||||
|
||||
|
||||
async def handle_save(request: web.Request) -> web.Response:
|
||||
try:
|
||||
body = await request.json()
|
||||
filename = body.get("filename", "")
|
||||
data = body.get("data", {})
|
||||
index_image_base64 = body.get("index_image_base64")
|
||||
result = await asyncio.to_thread(_service.save_plan, filename, data, index_image_base64)
|
||||
return web.json_response({"status": "ok", **result})
|
||||
except ValueError as e:
|
||||
return web.json_response({"error": str(e)}, status=400)
|
||||
except Exception as e:
|
||||
logger.error("Error saving lab plan: %s", e)
|
||||
return web.json_response({"error": str(e)}, status=500)
|
||||
|
||||
|
||||
async def handle_delete(request: web.Request) -> web.Response:
|
||||
try:
|
||||
body = await request.json()
|
||||
filename = body.get("filename", "")
|
||||
await asyncio.to_thread(_service.delete_plan, filename)
|
||||
return web.json_response({"status": "ok"})
|
||||
except ValueError as e:
|
||||
return web.json_response({"error": str(e)}, status=400)
|
||||
except Exception as e:
|
||||
logger.error("Error deleting lab plan: %s", e)
|
||||
return web.json_response({"error": str(e)}, status=500)
|
||||
|
||||
|
||||
async def handle_save_index_to_output(request: web.Request) -> web.Response:
|
||||
try:
|
||||
body = await request.json()
|
||||
image_base64 = body.get("image_base64", "")
|
||||
if not image_base64:
|
||||
return web.json_response({"error": "image_base64 required"}, status=400)
|
||||
result = await asyncio.to_thread(_service.save_index_image_to_output, image_base64)
|
||||
return web.json_response({"status": "ok", **result})
|
||||
except Exception as e:
|
||||
logger.error("Error saving lab index image to output: %s", e)
|
||||
return web.json_response({"error": str(e)}, status=500)
|
||||
@@ -20,6 +20,7 @@ def setup_routes(app: web.Application):
|
||||
app.router.add_get("/api/wfm/models/metadata", handle_get_metadata)
|
||||
app.router.add_post("/api/wfm/models/metadata", handle_save_metadata)
|
||||
app.router.add_get("/api/wfm/models/preview", handle_get_preview)
|
||||
app.router.add_get("/api/wfm/models/preview-keys", handle_get_preview_keys)
|
||||
app.router.add_get("/api/wfm/models/groups", handle_get_groups)
|
||||
app.router.add_post("/api/wfm/models/groups", handle_save_groups)
|
||||
app.router.add_post("/api/wfm/models/civitai/fetch", handle_civitai_fetch)
|
||||
@@ -31,6 +32,9 @@ def setup_routes(app: web.Application):
|
||||
app.router.add_post("/api/wfm/models/toggle", handle_toggle_model)
|
||||
app.router.add_post("/api/wfm/models/group-toggle", handle_toggle_group)
|
||||
app.router.add_post("/api/wfm/models/delete", handle_delete_models)
|
||||
app.router.add_get("/api/wfm/models/subdirs", handle_get_subdirs)
|
||||
app.router.add_post("/api/wfm/models/move", handle_move_models)
|
||||
app.router.add_get("/api/wfm/models/files", handle_list_model_files)
|
||||
|
||||
|
||||
# ── Model Metadata ─────────────────────────────────────────
|
||||
@@ -136,24 +140,48 @@ async def handle_civitai_fetch(request: web.Request) -> web.Response:
|
||||
)
|
||||
if not sha256:
|
||||
return web.json_response({"error": "Failed to calculate hash"}, status=500)
|
||||
# Cache the hash in model metadata
|
||||
await asyncio.to_thread(
|
||||
_service.update_metadata, model_name, {"sha256": sha256}
|
||||
)
|
||||
# Cache the hash (+ size/mtime so a replaced file invalidates it) in model metadata
|
||||
try:
|
||||
st = file_path.stat()
|
||||
hash_meta = {"sha256": sha256, "sha256Size": st.st_size, "sha256Mtime": st.st_mtime}
|
||||
except OSError:
|
||||
hash_meta = {"sha256": sha256}
|
||||
await asyncio.to_thread(_service.update_metadata, model_name, hash_meta)
|
||||
|
||||
# Fetch from CivitAI
|
||||
info = await asyncio.to_thread(_civitai.fetch_by_hash, sha256)
|
||||
if not info:
|
||||
await asyncio.to_thread(
|
||||
_service.update_metadata, model_name, {"civitaiNotFound": True}
|
||||
)
|
||||
return web.json_response({
|
||||
"status": "not_found",
|
||||
"sha256": sha256,
|
||||
"message": "Model not found on CivitAI"
|
||||
})
|
||||
|
||||
# Auto-set preview if none exists and CivitAI has images
|
||||
preview_saved = False
|
||||
if info.get("images"):
|
||||
has_preview = await asyncio.to_thread(_service.find_preview_image, model_type, model_name)
|
||||
if not has_preview:
|
||||
image_url = info["images"][0]
|
||||
preview_path = file_path.parent / (file_path.stem + ".preview.png")
|
||||
preview_saved = await asyncio.to_thread(
|
||||
CivitaiService.download_image, image_url, preview_path
|
||||
)
|
||||
if preview_saved:
|
||||
logger.info("Auto-saved preview for %s from CivitAI", model_name)
|
||||
|
||||
if model_meta.get("civitaiNotFound"):
|
||||
await asyncio.to_thread(
|
||||
_service.update_metadata, model_name, {"civitaiNotFound": False}
|
||||
)
|
||||
return web.json_response({
|
||||
"status": "ok",
|
||||
"sha256": sha256,
|
||||
"civitai": info,
|
||||
"preview_saved": preview_saved,
|
||||
})
|
||||
except Exception as e:
|
||||
logger.error("CivitAI fetch error: %s", e)
|
||||
@@ -227,55 +255,169 @@ async def handle_civitai_batch(request: web.Request) -> web.Response:
|
||||
def on_progress(current, total, model_name, status):
|
||||
progress_q.put({"current": current, "total": total, "model": model_name, "status": status})
|
||||
|
||||
# 保存済みsha256(size/mtime付き)を渡して再ハッシュを避ける
|
||||
import time as _time
|
||||
all_meta0 = _service.get_all_metadata()
|
||||
known = {}
|
||||
for n, _p in model_files:
|
||||
m = all_meta0.get(n) or {}
|
||||
if m.get("sha256"):
|
||||
known[n] = {"sha256": m["sha256"], "size": m.get("sha256Size"), "mtime": m.get("sha256Mtime")}
|
||||
|
||||
# 未計算のものは Lora Manager が保持済みのsha256を借りる(サイズ一致時のみ。ハッシュ計算を省く)
|
||||
if len(known) < len(model_files):
|
||||
from ..services.lora_manager_bridge import fetch_lm_hashes, _norm
|
||||
# Hostヘッダは信用せず、自分自身のループバック+実際のポートへ接続する(Host偽装/DNSリバインディング対策)
|
||||
sockname = request.transport.get_extra_info("sockname") if request.transport else None
|
||||
port = sockname[1] if sockname else (request.url.port or 8188)
|
||||
origin = f"http://127.0.0.1:{port}"
|
||||
lm = await asyncio.to_thread(fetch_lm_hashes, origin, model_type)
|
||||
for n, p in model_files:
|
||||
if n in known:
|
||||
continue
|
||||
e = lm.get(_norm(p))
|
||||
try:
|
||||
if e and e.get("size") is not None and int(e["size"]) == p.stat().st_size:
|
||||
known[n] = {"sha256": e["sha256"], "size": int(e["size"]), "mtime": None}
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
# ハッシュ確定ごとに溜め、5秒おきにメタデータへ書き出す(途中で止めても計算済み分が残る)
|
||||
pending_hashes = {}
|
||||
last_flush = [_time.monotonic()]
|
||||
|
||||
def flush_hashes():
|
||||
if not pending_hashes:
|
||||
return
|
||||
try:
|
||||
all_meta = _service.get_all_metadata()
|
||||
for mname, (sha, size, mtime) in list(pending_hashes.items()):
|
||||
entry = all_meta.setdefault(mname, {"tags": [], "favorite": False, "memo": ""})
|
||||
entry["sha256"] = sha
|
||||
entry["sha256Size"] = size
|
||||
entry["sha256Mtime"] = mtime
|
||||
_service._save_metadata(all_meta)
|
||||
pending_hashes.clear()
|
||||
except Exception as e:
|
||||
logger.warning("Failed to flush hashes: %s", e)
|
||||
last_flush[0] = _time.monotonic()
|
||||
|
||||
def on_hash(name, sha, size, mtime):
|
||||
pending_hashes[name] = (sha, size, mtime)
|
||||
if _time.monotonic() - last_flush[0] > 5:
|
||||
flush_hashes()
|
||||
|
||||
# Start batch in background thread
|
||||
import threading
|
||||
cancel = threading.Event()
|
||||
loop = asyncio.get_event_loop()
|
||||
fetch_task = loop.run_in_executor(None, _civitai.batch_fetch, model_files, on_progress)
|
||||
fetch_task = loop.run_in_executor(
|
||||
None, lambda: _civitai.batch_fetch(model_files, on_progress, known, on_hash, cancel=cancel)
|
||||
)
|
||||
|
||||
# Stream progress events
|
||||
import time as _time
|
||||
try:
|
||||
while not fetch_task.done():
|
||||
# Drain queue
|
||||
while not progress_q.empty():
|
||||
try:
|
||||
p = progress_q.get_nowait()
|
||||
await response.write(send_sse("progress", p))
|
||||
except queue.Empty:
|
||||
break
|
||||
await asyncio.sleep(0.1)
|
||||
|
||||
while not fetch_task.done():
|
||||
# Drain queue
|
||||
# Drain remaining events
|
||||
while not progress_q.empty():
|
||||
try:
|
||||
p = progress_q.get_nowait()
|
||||
await response.write(send_sse("progress", p))
|
||||
except queue.Empty:
|
||||
break
|
||||
await asyncio.sleep(0.1)
|
||||
|
||||
# Drain remaining events
|
||||
while not progress_q.empty():
|
||||
except (ConnectionResetError, asyncio.CancelledError) as e:
|
||||
# クライアント切断(再読み込み・タブ遷移): 重いハッシュ計算を打ち切り、計算済み分だけ保存して終了
|
||||
logger.info("civitai batch: client disconnected, cancelling (%s)", type(e).__name__)
|
||||
cancel.set()
|
||||
try:
|
||||
p = progress_q.get_nowait()
|
||||
await response.write(send_sse("progress", p))
|
||||
except queue.Empty:
|
||||
break
|
||||
await asyncio.shield(fetch_task)
|
||||
except Exception:
|
||||
pass
|
||||
await asyncio.to_thread(flush_hashes)
|
||||
if isinstance(e, asyncio.CancelledError):
|
||||
raise
|
||||
return response
|
||||
|
||||
# Get results and update metadata
|
||||
results = fetch_task.result()
|
||||
try:
|
||||
results = fetch_task.result()
|
||||
finally:
|
||||
await asyncio.to_thread(flush_hashes)
|
||||
meta_updates = {}
|
||||
for model_name, result in results.items():
|
||||
sha256 = result.get("sha256")
|
||||
if sha256:
|
||||
meta_updates[model_name] = sha256
|
||||
|
||||
# Bulk update sha256 in metadata
|
||||
# Bulk update sha256 (+ CivitAI not-found marker) in metadata
|
||||
if meta_updates:
|
||||
all_meta = _service.get_all_metadata()
|
||||
for mname, sha in meta_updates.items():
|
||||
if mname not in all_meta:
|
||||
all_meta[mname] = {"tags": [], "favorite": False, "memo": ""}
|
||||
all_meta[mname]["sha256"] = sha
|
||||
r = results[mname]
|
||||
if r.get("civitai"):
|
||||
all_meta[mname].pop("civitaiNotFound", None)
|
||||
elif not r.get("fetch_failed") and not r.get("error"):
|
||||
all_meta[mname]["civitaiNotFound"] = _service._now_iso()
|
||||
_service._save_metadata(all_meta)
|
||||
|
||||
# Auto-set previews for models without preview image
|
||||
# (ネットワークI/Oなのでイベントループを塞がないようスレッドで並列実行)
|
||||
await response.write(send_sse("progress", {
|
||||
"current": len(model_files), "total": len(model_files), "model": "", "status": "previews",
|
||||
}))
|
||||
dirs = _get_model_dirs(model_type)
|
||||
|
||||
def _save_previews():
|
||||
jobs = []
|
||||
for model_name, result in results.items():
|
||||
civitai = result.get("civitai")
|
||||
if not civitai or not civitai.get("images"):
|
||||
continue
|
||||
if _service.find_preview_image(model_type, model_name):
|
||||
continue
|
||||
model_file = None
|
||||
for d in dirs:
|
||||
p = d / model_name
|
||||
if p.is_file():
|
||||
model_file = p
|
||||
break
|
||||
if not model_file:
|
||||
continue
|
||||
jobs.append((model_name, civitai["images"][0],
|
||||
model_file.parent / (model_file.stem + ".preview.png")))
|
||||
if not jobs:
|
||||
return 0
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
with ThreadPoolExecutor(max_workers=2) as pool:
|
||||
oks = list(pool.map(lambda j: CivitaiService.download_image(j[1], j[2]), jobs))
|
||||
for (mname, _u, _p), ok in zip(jobs, oks):
|
||||
if ok:
|
||||
logger.info("Auto-saved preview for %s from CivitAI", mname)
|
||||
return sum(1 for ok in oks if ok)
|
||||
|
||||
preview_saved_count = await asyncio.to_thread(_save_previews)
|
||||
|
||||
# Send final result
|
||||
summary = {
|
||||
"total": len(model_files),
|
||||
"found": sum(1 for r in results.values() if r.get("civitai")),
|
||||
"not_found": sum(1 for r in results.values() if r.get("sha256") and not r.get("civitai")),
|
||||
"errors": sum(1 for r in results.values() if r.get("error")),
|
||||
"needs_hash": sum(1 for r in results.values() if r.get("needs_hash")),
|
||||
"hashes": {name: r.get("sha256") for name, r in results.items() if r.get("sha256")},
|
||||
"preview_saved": preview_saved_count,
|
||||
}
|
||||
await response.write(send_sse("done", summary))
|
||||
await response.write_eof()
|
||||
@@ -285,6 +427,22 @@ async def handle_civitai_batch(request: web.Request) -> web.Response:
|
||||
# ── Model Preview Image ───────────────────────────────────
|
||||
|
||||
|
||||
async def handle_get_preview_keys(request: web.Request) -> web.Response:
|
||||
"""GET /api/wfm/models/preview-keys?type=checkpoint
|
||||
|
||||
プレビュー画像を持つモデルのキー一覧を返す(無いモデルへの画像リクエスト=404を避けるため)。
|
||||
"""
|
||||
model_type = request.query.get("type", "")
|
||||
if not model_type:
|
||||
return web.json_response({"error": "type required"}, status=400)
|
||||
try:
|
||||
keys = await asyncio.to_thread(_service.list_preview_keys, model_type)
|
||||
return web.json_response({"keys": keys})
|
||||
except Exception as e:
|
||||
logger.error("Error listing preview keys: %s", e)
|
||||
return web.json_response({"error": str(e)}, status=500)
|
||||
|
||||
|
||||
async def handle_get_preview(request: web.Request) -> web.Response:
|
||||
"""GET /api/wfm/models/preview?type=checkpoint&name=model.safetensors"""
|
||||
model_type = request.query.get("type", "")
|
||||
@@ -307,7 +465,7 @@ async def handle_get_preview(request: web.Request) -> web.Response:
|
||||
return web.FileResponse(
|
||||
preview_path,
|
||||
headers={"Content-Type": content_type or "image/png",
|
||||
"Cache-Control": "public, max-age=3600"},
|
||||
"Cache-Control": "no-cache"},
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error("Error serving model preview: %s", e)
|
||||
@@ -346,7 +504,7 @@ async def handle_change_preview(request: web.Request) -> web.Response:
|
||||
if image_data is None:
|
||||
return web.json_response({"error": "file required"}, status=400)
|
||||
|
||||
# Resolve model file path
|
||||
# Resolve model file path (also check .disabled variants)
|
||||
from ..services.models_service import _get_model_dirs
|
||||
dirs = _get_model_dirs(model_type)
|
||||
model_path = None
|
||||
@@ -355,6 +513,11 @@ async def handle_change_preview(request: web.Request) -> web.Response:
|
||||
if candidate.is_file():
|
||||
model_path = candidate
|
||||
break
|
||||
# disabled モデルも対象にする
|
||||
disabled_candidate = d / (model_name + ".disabled")
|
||||
if disabled_candidate.is_file():
|
||||
model_path = disabled_candidate
|
||||
break
|
||||
|
||||
if not model_path:
|
||||
return web.json_response({"error": "Model file not found"}, status=404)
|
||||
@@ -529,3 +692,67 @@ async def handle_delete_models(request: web.Request) -> web.Response:
|
||||
except Exception as e:
|
||||
logger.error("Error in delete_models: %s", e)
|
||||
return web.json_response({"error": str(e)}, status=500)
|
||||
|
||||
|
||||
_VALID_MODEL_TYPES = frozenset(
|
||||
["checkpoint", "lora", "vae", "controlnet", "unet", "textencoder", "hypernetwork", "embedding"]
|
||||
)
|
||||
|
||||
|
||||
async def handle_get_subdirs(request: web.Request) -> web.Response:
|
||||
"""GET /api/wfm/models/subdirs?type=checkpoint
|
||||
Returns list of root-level subdirectory names for the given model type.
|
||||
"""
|
||||
try:
|
||||
model_type = request.rel_url.query.get("type", "")
|
||||
if model_type not in _VALID_MODEL_TYPES:
|
||||
return web.json_response({"error": "Invalid model type"}, status=400)
|
||||
result = await asyncio.to_thread(_service.get_subdirs, model_type)
|
||||
return web.json_response(result)
|
||||
except Exception as e:
|
||||
return web.json_response({"error": str(e)}, status=500)
|
||||
|
||||
|
||||
async def handle_move_models(request: web.Request) -> web.Response:
|
||||
"""POST /api/wfm/models/move
|
||||
|
||||
Body: { "model_type": "checkpoint", "model_names": [...], "dest": "sdxl" }
|
||||
dest: "" = root, or a root-level subfolder name (no path separators, no "..").
|
||||
"""
|
||||
try:
|
||||
body = await request.json()
|
||||
model_type = body.get("model_type", "")
|
||||
model_names = body.get("model_names", [])
|
||||
dest_subdir = body.get("dest", "")
|
||||
if model_type not in _VALID_MODEL_TYPES:
|
||||
return web.json_response({"error": "Invalid model type"}, status=400)
|
||||
if not isinstance(model_names, list) or not model_names:
|
||||
return web.json_response({"error": "model_names must be a non-empty list"}, status=400)
|
||||
if not isinstance(dest_subdir, str):
|
||||
return web.json_response({"error": "dest must be a string"}, status=400)
|
||||
result = await asyncio.to_thread(_service.move_models, model_type, model_names, dest_subdir)
|
||||
return web.json_response(result)
|
||||
except Exception as e:
|
||||
logger.error("Error in move_models: %s", e)
|
||||
return web.json_response({"error": str(e)}, status=500)
|
||||
|
||||
|
||||
# ── Model File List ───────────────────────────────────────
|
||||
|
||||
|
||||
async def handle_list_model_files(request: web.Request) -> web.Response:
|
||||
"""GET /api/wfm/models/files?type=<model_type>
|
||||
Returns sorted list of model file names (with extension) for the given type.
|
||||
Used as a fallback when ComfyUI's /embeddings endpoint is not accessible.
|
||||
"""
|
||||
from ..services.models_service import MODEL_TYPE_FOLDER_KEYS
|
||||
model_type = request.query.get("type", "")
|
||||
if not model_type or model_type not in MODEL_TYPE_FOLDER_KEYS:
|
||||
return web.json_response({"error": "invalid type"}, status=400)
|
||||
try:
|
||||
extra_only = request.query.get("extra_only") == "1"
|
||||
result = await asyncio.to_thread(_service.list_model_files, model_type, extra_only)
|
||||
return web.json_response(result)
|
||||
except Exception as e:
|
||||
logger.error("Error listing model files for %s: %s", model_type, e)
|
||||
return web.json_response({"error": str(e)}, status=500)
|
||||
|
||||
@@ -15,6 +15,7 @@ _service = NodesService()
|
||||
def setup_routes(app: web.Application):
|
||||
"""Register all node management API routes."""
|
||||
# Node metadata
|
||||
app.router.add_get("/api/wfm/nodes/light", handle_get_light_nodes)
|
||||
app.router.add_get("/api/wfm/nodes/metadata", handle_get_metadata)
|
||||
app.router.add_post("/api/wfm/nodes/metadata", handle_save_metadata)
|
||||
# Node groups
|
||||
@@ -28,6 +29,50 @@ def setup_routes(app: web.Application):
|
||||
app.router.add_get("/api/wfm/node-sets/export", handle_export_set)
|
||||
|
||||
|
||||
# ── Light node list ────────────────────────────────────────
|
||||
|
||||
|
||||
def _build_light_node_list() -> list[dict]:
|
||||
"""全ノードの軽量情報(INPUT_TYPES を呼ばない)。
|
||||
|
||||
/object_info は各ノードの INPUT_TYPES() を呼ぶため、モデル一覧を走査するノードが
|
||||
多い環境では十数秒かかる。Nodesタブの一覧表示に必要なのはクラス属性だけなので、
|
||||
それらのみを読んで高速に返す(入力定義は呼び出し側が /object_info で後から補う)。
|
||||
"""
|
||||
import nodes as comfy_nodes
|
||||
|
||||
result = []
|
||||
for name, cls in list(comfy_nodes.NODE_CLASS_MAPPINGS.items()):
|
||||
try:
|
||||
return_types = getattr(cls, "RETURN_TYPES", ()) or ()
|
||||
result.append({
|
||||
"name": name,
|
||||
"display_name": comfy_nodes.NODE_DISPLAY_NAME_MAPPINGS.get(name, name),
|
||||
"description": getattr(cls, "DESCRIPTION", "") or "",
|
||||
"category": getattr(cls, "CATEGORY", "sd") or "sd",
|
||||
"python_module": getattr(cls, "RELATIVE_PYTHON_MODULE", "nodes") or "nodes",
|
||||
"output": list(return_types),
|
||||
"output_name": list(getattr(cls, "RETURN_NAMES", None) or return_types),
|
||||
"output_node": getattr(cls, "OUTPUT_NODE", False) is True,
|
||||
"search_aliases": list(getattr(cls, "SEARCH_ALIASES", []) or []),
|
||||
"deprecated": bool(getattr(cls, "DEPRECATED", False)),
|
||||
"experimental": bool(getattr(cls, "EXPERIMENTAL", False)),
|
||||
})
|
||||
except Exception as e:
|
||||
logger.debug("light node info failed for %s: %s", name, e)
|
||||
return result
|
||||
|
||||
|
||||
async def handle_get_light_nodes(request: web.Request) -> web.Response:
|
||||
"""GET /api/wfm/nodes/light"""
|
||||
try:
|
||||
result = await asyncio.to_thread(_build_light_node_list)
|
||||
return web.json_response(result)
|
||||
except Exception as e:
|
||||
logger.error("Error building light node list: %s", e)
|
||||
return web.json_response({"error": str(e)}, status=500)
|
||||
|
||||
|
||||
# ── Node Metadata ──────────────────────────────────────────
|
||||
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import urllib.request
|
||||
from aiohttp import web
|
||||
|
||||
from ..services.settings_service import SettingsService
|
||||
from ..services.url_guard import require_backend_url, urlopen
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -39,11 +40,12 @@ async def handle_models(request: web.Request) -> web.Response:
|
||||
import asyncio
|
||||
try:
|
||||
cfg = _get_ollama_config()
|
||||
base_url = require_backend_url(cfg["url"])
|
||||
|
||||
def _fetch():
|
||||
url = f"{cfg['url']}/api/tags"
|
||||
url = f"{base_url}/api/tags"
|
||||
req = urllib.request.Request(url)
|
||||
with urllib.request.urlopen(req, timeout=5) as resp:
|
||||
with urlopen(req, timeout=5) as resp:
|
||||
return json.loads(resp.read().decode("utf-8"))
|
||||
|
||||
data = await asyncio.to_thread(_fetch)
|
||||
@@ -61,11 +63,12 @@ async def handle_test(request: web.Request) -> web.Response:
|
||||
import asyncio
|
||||
try:
|
||||
cfg = _get_ollama_config()
|
||||
base_url = require_backend_url(cfg["url"])
|
||||
|
||||
def _test():
|
||||
url = f"{cfg['url']}/api/tags"
|
||||
url = f"{base_url}/api/tags"
|
||||
req = urllib.request.Request(url, method="GET")
|
||||
with urllib.request.urlopen(req, timeout=5) as resp:
|
||||
with urlopen(req, timeout=5) as resp:
|
||||
return resp.status == 200
|
||||
|
||||
ok = await asyncio.to_thread(_test)
|
||||
@@ -82,7 +85,8 @@ async def handle_chat(request: web.Request) -> web.Response:
|
||||
try:
|
||||
body = await request.json()
|
||||
cfg = _get_ollama_config()
|
||||
model = body.get("model", cfg["model"])
|
||||
model = body.get("model") or cfg["model"]
|
||||
base_url = require_backend_url(body.get("url") or cfg["url"])
|
||||
messages = body.get("messages", [])
|
||||
|
||||
def _chat():
|
||||
@@ -92,14 +96,14 @@ async def handle_chat(request: web.Request) -> web.Response:
|
||||
"stream": False,
|
||||
}).encode("utf-8")
|
||||
|
||||
url = f"{cfg['url']}/api/chat"
|
||||
url = f"{base_url}/api/chat"
|
||||
req = urllib.request.Request(
|
||||
url,
|
||||
data=payload,
|
||||
headers={"Content-Type": "application/json"},
|
||||
method="POST",
|
||||
)
|
||||
with urllib.request.urlopen(req, timeout=120) as resp:
|
||||
with urlopen(req, timeout=120) as resp:
|
||||
return json.loads(resp.read().decode("utf-8"))
|
||||
|
||||
resp_data = await asyncio.to_thread(_chat)
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
"""Partner (API) node execution support for GenerateUI.
|
||||
|
||||
ComfyUI's partner API nodes (Nano Banana / Gemini, Kling, Seedream, ...) authenticate through the
|
||||
``extra_data`` of the ``/prompt`` request: ``auth_token_comfy_org`` (the browser's Comfy login) or
|
||||
``api_key_comfy_org`` (a Comfy API key issued at platform.comfy.org). ComfyUI's own web UI adds
|
||||
the login token automatically, but Workflow Studio is a separate page that POSTs to ``/prompt`` itself,
|
||||
so such a prompt fails with "Unauthorized: Please login first to use this node."
|
||||
|
||||
When COMFY_API_KEY is set (loaded from the plugin's .env by prestartup_script.py), the frontend
|
||||
queues prompts through this proxy instead. The proxy adds the key to ``extra_data`` — only when the
|
||||
prompt actually contains an API node (``api_node: true`` in /object_info) — and relays the request
|
||||
to the local ComfyUI. The key never reaches the browser. Usage is billed as Comfy credits.
|
||||
"""
|
||||
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
from urllib.parse import quote
|
||||
|
||||
import aiohttp
|
||||
from aiohttp import web
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
_api_node_cache: dict = {} # class_type -> bool (api_node flag); the node set only changes on restart
|
||||
|
||||
|
||||
def _get_comfy_key():
|
||||
"""Return the Comfy API key from the environment (.env), or None."""
|
||||
return os.environ.get("COMFY_API_KEY", "").strip() or None
|
||||
|
||||
|
||||
def _local_base_url() -> str:
|
||||
"""Base URL of this ComfyUI instance (from its --listen / --port launch arguments)."""
|
||||
try:
|
||||
from comfy.cli_args import args as _a
|
||||
port = getattr(_a, "port", None) or 8188
|
||||
host = str(getattr(_a, "listen", "") or "127.0.0.1").split(",")[0].strip()
|
||||
if host in ("", "0.0.0.0", "::"):
|
||||
host = "127.0.0.1"
|
||||
elif ":" in host:
|
||||
host = f"[{host}]"
|
||||
except Exception:
|
||||
host, port = "127.0.0.1", 8188
|
||||
return f"http://{host}:{port}"
|
||||
|
||||
|
||||
async def _is_api_node(sess: aiohttp.ClientSession, base: str, class_type: str) -> bool:
|
||||
if class_type in _api_node_cache:
|
||||
return _api_node_cache[class_type]
|
||||
for attempt in range(2): # /object_info occasionally drops the connection; one retry is enough
|
||||
try:
|
||||
async with sess.get(f"{base}/object_info/{quote(class_type, safe='')}") as r:
|
||||
if r.status == 200:
|
||||
info = await r.json(content_type=None)
|
||||
flag = bool((info.get(class_type) or {}).get("api_node"))
|
||||
_api_node_cache[class_type] = flag
|
||||
return flag
|
||||
break
|
||||
except Exception:
|
||||
if attempt == 1:
|
||||
logger.warning("object_info lookup failed for %s", class_type)
|
||||
return False
|
||||
|
||||
|
||||
def setup_routes(app: web.Application):
|
||||
app.router.add_get("/api/wfm/partner/status", handle_status)
|
||||
app.router.add_post("/api/wfm/partner/prompt", handle_prompt)
|
||||
|
||||
|
||||
async def handle_status(request: web.Request) -> web.Response:
|
||||
"""GET /api/wfm/partner/status - whether a Comfy API key is configured (the key itself is never returned)."""
|
||||
return web.json_response({"configured": _get_comfy_key() is not None})
|
||||
|
||||
|
||||
async def handle_prompt(request: web.Request) -> web.Response:
|
||||
"""POST /api/wfm/partner/prompt - Relay a /prompt request to this ComfyUI, adding the Comfy API key
|
||||
to ``extra_data`` when the prompt contains an API node. The response is passed through unchanged."""
|
||||
try:
|
||||
body = await request.json()
|
||||
except Exception:
|
||||
return web.json_response({"error": {"message": "invalid JSON body"}}, status=400)
|
||||
prompt = body.get("prompt")
|
||||
if not isinstance(prompt, dict):
|
||||
return web.json_response({"error": {"message": "prompt is required"}}, status=400)
|
||||
|
||||
base = _local_base_url()
|
||||
key = _get_comfy_key()
|
||||
try:
|
||||
async with aiohttp.ClientSession(timeout=aiohttp.ClientTimeout(total=120, connect=10)) as sess:
|
||||
if key:
|
||||
extra = body.get("extra_data")
|
||||
extra = extra if isinstance(extra, dict) else {}
|
||||
already = extra.get("auth_token_comfy_org") or extra.get("api_key_comfy_org")
|
||||
if not already:
|
||||
classes = {n.get("class_type") for n in prompt.values() if isinstance(n, dict) and n.get("class_type")}
|
||||
for cls in classes:
|
||||
if await _is_api_node(sess, base, cls):
|
||||
extra["api_key_comfy_org"] = key
|
||||
break
|
||||
body["extra_data"] = extra
|
||||
async with sess.post(f"{base}/prompt", json=body) as r:
|
||||
data = await r.read()
|
||||
return web.Response(status=r.status, body=data, content_type="application/json")
|
||||
except Exception as e:
|
||||
logger.error("partner prompt relay failed: %s", e)
|
||||
return web.json_response({"error": {"message": f"relay failed: {e}"}}, status=502)
|
||||
@@ -1,14 +1,18 @@
|
||||
"""Settings API routes."""
|
||||
|
||||
import asyncio
|
||||
import io
|
||||
import json
|
||||
import logging
|
||||
import shutil
|
||||
import tempfile
|
||||
import zipfile
|
||||
from pathlib import Path
|
||||
|
||||
from aiohttp import web
|
||||
|
||||
from ..services.settings_service import SettingsService
|
||||
from ..config import DEFAULT_WORKFLOWS_DIR, DATA_DIR
|
||||
from ..config import DEFAULT_WORKFLOWS_DIR, DATA_DIR, VIDEO_EDIT_PROJECT_DIR, is_safe_rel
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -23,6 +27,8 @@ _DATA_FILES = [
|
||||
"prompts.json",
|
||||
"model_metadata.json",
|
||||
"gallery_metadata.json",
|
||||
"tagger_settings.json",
|
||||
"civitai_cache.json",
|
||||
]
|
||||
|
||||
|
||||
@@ -32,10 +38,18 @@ def setup_routes(app: web.Application):
|
||||
app.router.add_post("/api/wfm/settings", handle_post)
|
||||
app.router.add_get("/api/wfm/settings/workflows-dir", handle_get_workflows_dir)
|
||||
app.router.add_post("/api/wfm/settings/workflows-dir", handle_set_workflows_dir)
|
||||
app.router.add_get("/api/wfm/settings/models-dir", handle_get_models_dir)
|
||||
app.router.add_post("/api/wfm/settings/models-dir", handle_set_models_dir)
|
||||
app.router.add_get("/api/wfm/settings/output-dir", handle_get_output_dir)
|
||||
app.router.add_post("/api/wfm/settings/output-dir", handle_set_output_dir)
|
||||
app.router.add_get("/api/wfm/settings/export", handle_export)
|
||||
app.router.add_post("/api/wfm/settings/import", handle_import)
|
||||
app.router.add_get("/api/wfm/settings/export-full", handle_export_full)
|
||||
app.router.add_post("/api/wfm/settings/import-full", handle_import_full)
|
||||
app.router.add_get("/api/wfm/styles", handle_get_styles)
|
||||
app.router.add_post("/api/wfm/styles", handle_create_style)
|
||||
app.router.add_put("/api/wfm/styles/{name}", handle_update_style)
|
||||
app.router.add_delete("/api/wfm/styles/{name}", handle_delete_style)
|
||||
|
||||
|
||||
async def handle_get(request: web.Request) -> web.Response:
|
||||
@@ -110,6 +124,47 @@ async def handle_set_workflows_dir(request: web.Request) -> web.Response:
|
||||
return web.json_response({"error": str(e)}, status=500)
|
||||
|
||||
|
||||
async def handle_get_models_dir(request: web.Request) -> web.Response:
|
||||
"""GET /api/wfm/settings/models-dir - 追加モデルフォルダ設定と現在有効な探索先を返す。"""
|
||||
try:
|
||||
from ..services.models_service import (
|
||||
MODEL_TYPE_FOLDER_KEYS, _get_model_dirs, parse_extra_model_roots,
|
||||
)
|
||||
saved = (await asyncio.to_thread(_service.load)).get("models_dir", "")
|
||||
effective = await asyncio.to_thread(
|
||||
lambda: {t: [str(d) for d in _get_model_dirs(t)] for t in MODEL_TYPE_FOLDER_KEYS}
|
||||
)
|
||||
return web.json_response({
|
||||
"saved": saved,
|
||||
"roots": parse_extra_model_roots(saved),
|
||||
"effective": effective,
|
||||
})
|
||||
except Exception as e:
|
||||
logger.error("Error getting models dir: %s", e)
|
||||
return web.json_response({"error": str(e)}, status=500)
|
||||
|
||||
|
||||
async def handle_set_models_dir(request: web.Request) -> web.Response:
|
||||
"""POST /api/wfm/settings/models-dir - 追加モデルフォルダを保存(`;`/改行区切りで複数可、空でリセット)。"""
|
||||
try:
|
||||
from ..services.models_service import parse_extra_model_roots
|
||||
body = await request.json()
|
||||
roots = parse_extra_model_roots(body.get("models_dir", ""))
|
||||
missing = [r for r in roots if not Path(r).is_dir()]
|
||||
if missing:
|
||||
return web.json_response(
|
||||
{"error": f"Folder not found: {', '.join(missing)}"}, status=400)
|
||||
saved = ";".join(roots)
|
||||
await asyncio.to_thread(_service.update, {"models_dir": saved})
|
||||
|
||||
from ..routes.models_routes import _service as models_service
|
||||
models_service._scan_cache.clear()
|
||||
return await handle_get_models_dir(request)
|
||||
except Exception as e:
|
||||
logger.error("Error setting models dir: %s", e)
|
||||
return web.json_response({"error": str(e)}, status=500)
|
||||
|
||||
|
||||
def _get_comfyui_output_dir() -> str:
|
||||
"""ComfyUIのデフォルトoutputフォルダを取得する。"""
|
||||
try:
|
||||
@@ -179,13 +234,20 @@ def _load_data_file(filename: str):
|
||||
return None
|
||||
|
||||
|
||||
# エクスポートから除外するsettings.jsonのキー(APIキーなどの機密情報)
|
||||
_SETTINGS_EXPORT_EXCLUDE = {"civitai_api_key"}
|
||||
|
||||
|
||||
def _build_export_bundle() -> dict:
|
||||
"""Collect all data files into a single export bundle."""
|
||||
bundle = {"__version": 1, "__source": "ComfyUI-Workflow-Studio"}
|
||||
for filename in _DATA_FILES:
|
||||
data = _load_data_file(filename)
|
||||
if data is not None:
|
||||
bundle[filename] = data
|
||||
if data is None:
|
||||
continue
|
||||
if filename == "settings.json" and isinstance(data, dict):
|
||||
data = {k: v for k, v in data.items() if k not in _SETTINGS_EXPORT_EXCLUDE}
|
||||
bundle[filename] = data
|
||||
return bundle
|
||||
|
||||
|
||||
@@ -234,3 +296,437 @@ async def handle_import(request: web.Request) -> web.Response:
|
||||
except Exception as e:
|
||||
logger.error("Error importing data: %s", e)
|
||||
return web.json_response({"error": str(e)}, status=500)
|
||||
|
||||
|
||||
# Full-backup (ZIP) export/import: unlike the flat _DATA_FILES JSON bundle above, this
|
||||
# covers the whole DATA_DIR — directory-shaped data (ai_skills/, lab_plan/, video_plan/,
|
||||
# style/) and the SQLite tagger.db that the JSON bundle can't represent. Excludes transient/cache
|
||||
# dirs, and wildcard/ specifically because it's typically a symlink into a *different*
|
||||
# custom_node's folder (comfyui-impact-pack) rather than this plugin's own data.
|
||||
_FULL_BACKUP_EXCLUDE_NAMES = {"gmic_temp", "thumb_cache", "wildcard"}
|
||||
|
||||
|
||||
def _add_file_to_zip(zf: zipfile.ZipFile, path: Path, base: Path):
|
||||
rel = str(path.relative_to(base)).replace("\\", "/")
|
||||
if path.name == "settings.json":
|
||||
# Same API-key scrubbing as the JSON-bundle export — fall through to a raw
|
||||
# copy if the file turns out to be unreadable/corrupt rather than skipping it.
|
||||
try:
|
||||
with open(path, "r", encoding="utf-8") as f:
|
||||
data = json.load(f)
|
||||
data = {k: v for k, v in data.items() if k not in _SETTINGS_EXPORT_EXCLUDE}
|
||||
zf.writestr(rel, json.dumps(data, ensure_ascii=False, indent=2))
|
||||
return
|
||||
except Exception:
|
||||
pass
|
||||
zf.write(path, rel)
|
||||
|
||||
|
||||
# Two folders this plugin doesn't own but users often want backed up alongside their
|
||||
# own data: ComfyUI's own default workflows dir, and the Impact Pack's wildcard
|
||||
# library (a separate custom_node — the plugin's own wildcard/ is usually just a
|
||||
# symlink into this same folder, see _FULL_BACKUP_EXCLUDE_NAMES above). Opt-in only
|
||||
# (see handle_export_full's include_workflows/include_wildcard query params), and
|
||||
# stored under an "_external/" prefix so _apply_full_backup_zip can recognize and
|
||||
# skip them on restore — see that function's docstring for why.
|
||||
def _default_workflows_dir() -> Path:
|
||||
from ..config import COMFYUI_ROOT
|
||||
return COMFYUI_ROOT / "user" / "default" / "workflows"
|
||||
|
||||
|
||||
def _impact_pack_wildcard_dir() -> Path:
|
||||
from ..config import COMFYUI_ROOT
|
||||
return COMFYUI_ROOT / "custom_nodes" / "comfyui-impact-pack" / "wildcards"
|
||||
|
||||
|
||||
def _add_external_dir_to_zip(zf: zipfile.ZipFile, src_dir: Path, zip_prefix: str):
|
||||
if not src_dir.is_dir() or src_dir.is_symlink():
|
||||
return
|
||||
for path in src_dir.rglob("*"):
|
||||
if path.is_dir() or path.is_symlink():
|
||||
continue
|
||||
rel = f"{zip_prefix}/{path.relative_to(src_dir)}".replace("\\", "/")
|
||||
zf.write(path, rel)
|
||||
|
||||
|
||||
# Video Edit projects (video_edit_project/*.json, inside DATA_DIR so always backed up) only
|
||||
# store *references* — serverRef {filename, subfolder, type:"input"} — to clips, the BGM,
|
||||
# timeline sounds and overlay (PinP) clips uploaded into ComfyUI's input dir, not the media itself. Backing up just the JSON means a
|
||||
# restored project on another machine (or after input/ is cleaned up) opens with its clips
|
||||
# missing. Opt-in (include_video_media) because the media can be large; stored under its own
|
||||
# prefix so _apply_full_backup_zip can route it back into the input dir, not DATA_DIR.
|
||||
_VIDEO_MEDIA_PREFIX = "_video_edit_media/"
|
||||
|
||||
|
||||
def _comfyui_input_dir() -> Path:
|
||||
import folder_paths
|
||||
return Path(folder_paths.get_input_directory())
|
||||
|
||||
|
||||
def _iter_video_edit_media_refs():
|
||||
"""Yields (subfolder, filename) for every input-dir file referenced by a saved Video
|
||||
Edit project (clips + BGM + timeline sounds + overlay clips). Unreadable project files
|
||||
are skipped."""
|
||||
if not VIDEO_EDIT_PROJECT_DIR.is_dir():
|
||||
return
|
||||
for path in sorted(VIDEO_EDIT_PROJECT_DIR.glob("*.json")):
|
||||
try:
|
||||
with open(path, "r", encoding="utf-8") as f:
|
||||
data = json.load(f)
|
||||
except Exception:
|
||||
continue
|
||||
# "sounds" / "pips" are top-level lists of {name, serverRef, ...} (absent in older projects).
|
||||
refs = [
|
||||
c.get("serverRef")
|
||||
for key in ("clips", "sounds", "pips")
|
||||
for c in data.get(key) or []
|
||||
if isinstance(c, dict)
|
||||
]
|
||||
bgm = (data.get("audio") or {}).get("bgm")
|
||||
if isinstance(bgm, dict):
|
||||
refs.append(bgm.get("serverRef"))
|
||||
for ref in refs:
|
||||
if not isinstance(ref, dict) or not ref.get("filename"):
|
||||
continue
|
||||
if (ref.get("type") or "input") != "input":
|
||||
continue
|
||||
yield (ref.get("subfolder") or "").strip("/\\"), ref["filename"]
|
||||
|
||||
|
||||
def _add_video_edit_media_to_zip(zf: zipfile.ZipFile) -> None:
|
||||
input_dir = _comfyui_input_dir().resolve()
|
||||
seen = set()
|
||||
for subfolder, filename in _iter_video_edit_media_refs():
|
||||
# プロジェクトファイルは細工できるため、UNC・絶対パス・「..」は結合・resolve() の前に
|
||||
# 文字列のまま拒否する(Windows では UNC を resolve() するだけで相手ホストへ接続する)
|
||||
if not is_safe_rel(filename) or (subfolder and not is_safe_rel(subfolder)):
|
||||
continue
|
||||
src = (input_dir / subfolder / filename).resolve()
|
||||
try:
|
||||
rel = src.relative_to(input_dir) # a crafted project file must not reach outside input/
|
||||
except ValueError:
|
||||
continue
|
||||
if rel in seen or not src.is_file():
|
||||
continue
|
||||
seen.add(rel)
|
||||
zf.write(src, _VIDEO_MEDIA_PREFIX + str(rel).replace("\\", "/"))
|
||||
|
||||
|
||||
def _build_full_backup_zip(include_workflows: bool = False, include_wildcard: bool = False,
|
||||
include_video_media: bool = False) -> bytes:
|
||||
"""Zips everything under DATA_DIR except the excluded names above. Walks
|
||||
top-level entries first so an excluded symlinked directory (wildcard/) is never
|
||||
even opened, rather than filtering after a recursive walk has already followed it.
|
||||
Optionally also includes the two external folders above under "_external/"."""
|
||||
buf = io.BytesIO()
|
||||
with zipfile.ZipFile(buf, "w", zipfile.ZIP_DEFLATED) as zf:
|
||||
for top in sorted(DATA_DIR.iterdir()):
|
||||
if top.name in _FULL_BACKUP_EXCLUDE_NAMES or top.is_symlink():
|
||||
continue
|
||||
if top.is_file():
|
||||
_add_file_to_zip(zf, top, DATA_DIR)
|
||||
elif top.is_dir():
|
||||
for path in top.rglob("*"):
|
||||
if path.is_dir() or path.is_symlink():
|
||||
continue
|
||||
_add_file_to_zip(zf, path, DATA_DIR)
|
||||
|
||||
if include_workflows:
|
||||
_add_external_dir_to_zip(zf, _default_workflows_dir(), "_external/default_workflows")
|
||||
if include_wildcard:
|
||||
_add_external_dir_to_zip(zf, _impact_pack_wildcard_dir(), "_external/wildcard")
|
||||
if include_video_media:
|
||||
_add_video_edit_media_to_zip(zf)
|
||||
return buf.getvalue()
|
||||
|
||||
|
||||
def _apply_full_backup_zip(zip_source) -> dict:
|
||||
"""Extracts a full-backup ZIP into DATA_DIR, overwriting existing files. Guards
|
||||
against Zip Slip (entries whose path resolves outside DATA_DIR via '..' or an
|
||||
absolute path) by checking each entry before writing it.
|
||||
|
||||
Entries under "_external/" (default workflows dir, Impact Pack wildcards — see
|
||||
_build_full_backup_zip) are always skipped here rather than restored: they live
|
||||
outside DATA_DIR and are managed by ComfyUI core / a different custom_node, so
|
||||
auto-restoring them could silently overwrite files this plugin doesn't own. They
|
||||
stay in the ZIP for the user to copy back manually if they want them.
|
||||
|
||||
Entries under "_video_edit_media/" (media referenced by Video Edit projects) are restored
|
||||
into ComfyUI's input dir instead, but never overwrite an existing file there — a file
|
||||
with the same name is assumed to be the same upload (ComfyUI dedupes uploads by renaming),
|
||||
and input/ is shared with every other workflow."""
|
||||
summary = {"extracted": [], "skipped": [], "media_restored": [], "media_existing": []}
|
||||
DATA_DIR.mkdir(parents=True, exist_ok=True)
|
||||
base = DATA_DIR.resolve()
|
||||
input_base = None
|
||||
# zip_source: raw bytes, or a seekable file object (the upload handler spools to a temp file).
|
||||
if isinstance(zip_source, (bytes, bytearray)):
|
||||
zip_source = io.BytesIO(zip_source)
|
||||
with zipfile.ZipFile(zip_source) as zf:
|
||||
for info in zf.infolist():
|
||||
if info.is_dir():
|
||||
continue
|
||||
if info.filename.startswith("_external/"):
|
||||
summary["skipped"].append(info.filename)
|
||||
continue
|
||||
if info.filename.startswith(_VIDEO_MEDIA_PREFIX):
|
||||
media_rel = info.filename[len(_VIDEO_MEDIA_PREFIX):]
|
||||
# ZIP エントリ名は細工できるため、UNC・絶対パス・「..」は結合・resolve() の前に
|
||||
# 文字列のまま拒否する(Windows では UNC を resolve() するだけで相手ホストへ接続する)
|
||||
if not is_safe_rel(media_rel):
|
||||
summary["skipped"].append(info.filename)
|
||||
continue
|
||||
if input_base is None:
|
||||
input_base = _comfyui_input_dir().resolve()
|
||||
target = (input_base / media_rel).resolve()
|
||||
try:
|
||||
target.relative_to(input_base)
|
||||
except ValueError:
|
||||
summary["skipped"].append(info.filename)
|
||||
continue
|
||||
if target.exists():
|
||||
summary["media_existing"].append(info.filename)
|
||||
continue
|
||||
target.parent.mkdir(parents=True, exist_ok=True)
|
||||
with zf.open(info) as src, open(target, "wb") as dst:
|
||||
shutil.copyfileobj(src, dst)
|
||||
summary["media_restored"].append(info.filename)
|
||||
continue
|
||||
if not is_safe_rel(info.filename):
|
||||
summary["skipped"].append(info.filename)
|
||||
continue
|
||||
target = (base / info.filename).resolve()
|
||||
try:
|
||||
target.relative_to(base)
|
||||
except ValueError:
|
||||
summary["skipped"].append(info.filename)
|
||||
continue
|
||||
target.parent.mkdir(parents=True, exist_ok=True)
|
||||
with zf.open(info) as src, open(target, "wb") as dst:
|
||||
shutil.copyfileobj(src, dst)
|
||||
summary["extracted"].append(info.filename)
|
||||
return summary
|
||||
|
||||
|
||||
async def handle_export_full(request: web.Request) -> web.Response:
|
||||
"""GET /api/wfm/settings/export-full - Download a ZIP of the entire data
|
||||
directory, including data the flat JSON bundle (handle_export) can't represent.
|
||||
Optional query params include_workflows=1 / include_wildcard=1 additionally bundle
|
||||
ComfyUI's default workflows dir / the Impact Pack's wildcard dir (see
|
||||
_build_full_backup_zip) — both restore-excluded, export-only, manual-copy-back.
|
||||
include_video_media=1 adds the input-dir media referenced by Video Edit projects,
|
||||
which *is* restored (into input/, without overwriting)."""
|
||||
try:
|
||||
include_workflows = request.rel_url.query.get("include_workflows") == "1"
|
||||
include_wildcard = request.rel_url.query.get("include_wildcard") == "1"
|
||||
include_video_media = request.rel_url.query.get("include_video_media") == "1"
|
||||
zip_bytes = await asyncio.to_thread(
|
||||
_build_full_backup_zip, include_workflows, include_wildcard, include_video_media)
|
||||
return web.Response(
|
||||
body=zip_bytes,
|
||||
content_type="application/zip",
|
||||
headers={"Content-Disposition": 'attachment; filename="wfm-full-backup.zip"'},
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error("Error building full backup: %s", e)
|
||||
return web.json_response({"error": str(e)}, status=500)
|
||||
|
||||
|
||||
async def handle_import_full(request: web.Request) -> web.Response:
|
||||
"""POST /api/wfm/settings/import-full - Upload and restore a full-backup ZIP."""
|
||||
try:
|
||||
reader = await request.multipart()
|
||||
field = await reader.next()
|
||||
if field is None or field.name != "file":
|
||||
return web.json_response({"error": "file field required"}, status=400)
|
||||
# Stream to a temp file with read_chunk() instead of field.read(): aiohttp (3.14+)
|
||||
# enforces ComfyUI's --max-upload-size (default 100 MB) inside BodyPartReader.read(),
|
||||
# and a backup with the opt-in workflows/wildcard/Video Edit media easily exceeds it
|
||||
# ("Request Entity Too Large"). Also avoids holding the whole ZIP in memory.
|
||||
with tempfile.TemporaryFile() as tmp:
|
||||
while True:
|
||||
chunk = await field.read_chunk(1024 * 1024)
|
||||
if not chunk:
|
||||
break
|
||||
await asyncio.to_thread(tmp.write, chunk)
|
||||
tmp.seek(0)
|
||||
summary = await asyncio.to_thread(_apply_full_backup_zip, tmp)
|
||||
return web.json_response({"status": "ok", **summary})
|
||||
except zipfile.BadZipFile:
|
||||
return web.json_response({"error": "Not a valid ZIP file"}, status=400)
|
||||
except Exception as e:
|
||||
logger.error("Error importing full backup: %s", e)
|
||||
return web.json_response({"error": str(e)}, status=500)
|
||||
|
||||
|
||||
def _style_files() -> list:
|
||||
style_dir = DATA_DIR / "style"
|
||||
if not style_dir.is_dir():
|
||||
return []
|
||||
return sorted(style_dir.glob("*.json"))
|
||||
|
||||
|
||||
def _load_styles() -> list:
|
||||
"""Load all style JSON files from DATA_DIR/style/ directory.
|
||||
各エントリに定義元ファイル名を "file" として付与する(Promptタブの一覧表示・
|
||||
「このファイルへ追加」機能で使用)。"""
|
||||
styles = []
|
||||
for json_file in _style_files():
|
||||
try:
|
||||
with open(json_file, "r", encoding="utf-8") as f:
|
||||
data = json.load(f)
|
||||
if isinstance(data, list):
|
||||
for entry in data:
|
||||
if isinstance(entry, dict):
|
||||
entry = dict(entry)
|
||||
entry["file"] = json_file.name
|
||||
styles.append(entry)
|
||||
except Exception as e:
|
||||
logger.warning("Failed to load style file %s: %s", json_file.name, e)
|
||||
return styles
|
||||
|
||||
|
||||
async def handle_get_styles(request: web.Request) -> web.Response:
|
||||
"""GET /api/wfm/styles - Get all styles from style directory."""
|
||||
try:
|
||||
styles = await asyncio.to_thread(_load_styles)
|
||||
return web.json_response(styles)
|
||||
except Exception as e:
|
||||
logger.error("Error loading styles: %s", e)
|
||||
return web.json_response({"error": str(e)}, status=500)
|
||||
|
||||
|
||||
# Promptタブ「Style」サブタブでの新規作成分の保存先。既存スタイルの編集は
|
||||
# 元々そのスタイルが記載されているファイルをそのまま書き換える(他ファイルへは移動しない)。
|
||||
_CUSTOM_STYLE_FILENAME = "custom.json"
|
||||
|
||||
|
||||
def _find_style(name: str):
|
||||
"""名前が一致する最初のスタイルを探し、(ファイルパス, そのファイルの全データ, インデックス) を返す。
|
||||
見つからなければ None。"""
|
||||
for json_file in _style_files():
|
||||
try:
|
||||
with open(json_file, "r", encoding="utf-8") as f:
|
||||
data = json.load(f)
|
||||
except Exception as e:
|
||||
logger.warning("Failed to load style file %s: %s", json_file.name, e)
|
||||
continue
|
||||
if not isinstance(data, list):
|
||||
continue
|
||||
for i, entry in enumerate(data):
|
||||
if isinstance(entry, dict) and entry.get("name") == name:
|
||||
return json_file, data, i
|
||||
return None
|
||||
|
||||
|
||||
def _write_style_file(path: Path, data: list) -> None:
|
||||
with open(path, "w", encoding="utf-8") as f:
|
||||
json.dump(data, f, ensure_ascii=False, indent=2)
|
||||
f.write("\n")
|
||||
|
||||
|
||||
async def handle_create_style(request: web.Request) -> web.Response:
|
||||
"""POST /api/wfm/styles - 新規スタイルを作成する。
|
||||
body.file を指定すると既存のそのファイルへ追記する(Promptタブの「このファイルへ追加」用、
|
||||
ファイル名はstyleディレクトリに実在するもののみ許可しパストラバーサルを防ぐ)。
|
||||
未指定ならデフォルトのcustom.jsonへ追記する。"""
|
||||
try:
|
||||
body = await request.json()
|
||||
name = (body.get("name") or "").strip()
|
||||
prompt = body.get("prompt", "") or ""
|
||||
negative_prompt = body.get("negative_prompt", "") or ""
|
||||
target_file = (body.get("file") or "").strip()
|
||||
if not name:
|
||||
return web.json_response({"error": "name is required"}, status=400)
|
||||
|
||||
def _create():
|
||||
if _find_style(name) is not None:
|
||||
return "duplicate"
|
||||
style_dir = DATA_DIR / "style"
|
||||
style_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
if target_file:
|
||||
path = next((f for f in _style_files() if f.name == target_file), None)
|
||||
if path is None:
|
||||
return "file_not_found"
|
||||
else:
|
||||
path = style_dir / _CUSTOM_STYLE_FILENAME
|
||||
|
||||
data = []
|
||||
if path.is_file():
|
||||
try:
|
||||
with open(path, "r", encoding="utf-8") as f:
|
||||
loaded = json.load(f)
|
||||
if isinstance(loaded, list):
|
||||
data = loaded
|
||||
except Exception as e:
|
||||
logger.warning("Failed to load %s, recreating: %s", path.name, e)
|
||||
data.append({"name": name, "prompt": prompt, "negative_prompt": negative_prompt})
|
||||
_write_style_file(path, data)
|
||||
return "ok"
|
||||
|
||||
result = await asyncio.to_thread(_create)
|
||||
if result == "duplicate":
|
||||
return web.json_response({"error": f'Style "{name}" already exists'}, status=400)
|
||||
if result == "file_not_found":
|
||||
return web.json_response({"error": f'File "{target_file}" not found'}, status=400)
|
||||
return web.json_response({"ok": True})
|
||||
except Exception as e:
|
||||
logger.error("Error creating style: %s", e)
|
||||
return web.json_response({"error": str(e)}, status=500)
|
||||
|
||||
|
||||
async def handle_update_style(request: web.Request) -> web.Response:
|
||||
"""PUT /api/wfm/styles/{name} - 既存スタイルを更新する(記載元のファイルをそのまま書き換え、リネームも可)。"""
|
||||
try:
|
||||
original_name = request.match_info.get("name", "")
|
||||
body = await request.json()
|
||||
new_name = (body.get("name") or "").strip()
|
||||
prompt = body.get("prompt", "") or ""
|
||||
negative_prompt = body.get("negative_prompt", "") or ""
|
||||
if not new_name:
|
||||
return web.json_response({"error": "name is required"}, status=400)
|
||||
|
||||
def _update():
|
||||
found = _find_style(original_name)
|
||||
if found is None:
|
||||
return "not_found"
|
||||
path, data, idx = found
|
||||
if new_name != original_name and _find_style(new_name) is not None:
|
||||
return "duplicate"
|
||||
data[idx] = {"name": new_name, "prompt": prompt, "negative_prompt": negative_prompt}
|
||||
_write_style_file(path, data)
|
||||
return "ok"
|
||||
|
||||
result = await asyncio.to_thread(_update)
|
||||
if result == "not_found":
|
||||
return web.json_response({"error": "Style not found"}, status=404)
|
||||
if result == "duplicate":
|
||||
return web.json_response({"error": f'Style "{new_name}" already exists'}, status=400)
|
||||
return web.json_response({"ok": True})
|
||||
except Exception as e:
|
||||
logger.error("Error updating style: %s", e)
|
||||
return web.json_response({"error": str(e)}, status=500)
|
||||
|
||||
|
||||
async def handle_delete_style(request: web.Request) -> web.Response:
|
||||
"""DELETE /api/wfm/styles/{name} - スタイルを削除する(記載元のファイルから該当エントリのみ除去)。"""
|
||||
try:
|
||||
name = request.match_info.get("name", "")
|
||||
|
||||
def _delete():
|
||||
found = _find_style(name)
|
||||
if found is None:
|
||||
return False
|
||||
path, data, idx = found
|
||||
del data[idx]
|
||||
_write_style_file(path, data)
|
||||
return True
|
||||
|
||||
ok = await asyncio.to_thread(_delete)
|
||||
if not ok:
|
||||
return web.json_response({"error": "Style not found"}, status=404)
|
||||
return web.json_response({"ok": True})
|
||||
except Exception as e:
|
||||
logger.error("Error deleting style: %s", e)
|
||||
return web.json_response({"error": str(e)}, status=500)
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
"""AI skill (.md system prompt) file management API routes."""
|
||||
|
||||
import asyncio
|
||||
import logging
|
||||
|
||||
from aiohttp import web
|
||||
|
||||
from ..config import AI_SKILLS_DIR
|
||||
from ..services.skill_service import SkillService
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
_service = SkillService(AI_SKILLS_DIR)
|
||||
|
||||
|
||||
def setup_routes(app: web.Application):
|
||||
app.router.add_get("/api/wfm/skills", handle_list)
|
||||
app.router.add_get("/api/wfm/skills/content", handle_get_content)
|
||||
app.router.add_post("/api/wfm/skills/save", handle_save)
|
||||
app.router.add_post("/api/wfm/skills/delete", handle_delete)
|
||||
app.router.add_post("/api/wfm/skills/restore-builtin", handle_restore_builtin)
|
||||
app.router.add_post("/api/wfm/skills/import", handle_import)
|
||||
app.router.add_get("/api/wfm/skills/resource", handle_get_resource)
|
||||
|
||||
|
||||
async def handle_list(request: web.Request) -> web.Response:
|
||||
try:
|
||||
result = await asyncio.to_thread(_service.list_skills)
|
||||
return web.json_response(result)
|
||||
except Exception as e:
|
||||
logger.error("Error listing skills: %s", e)
|
||||
return web.json_response({"error": str(e)}, status=500)
|
||||
|
||||
|
||||
async def handle_get_content(request: web.Request) -> web.Response:
|
||||
filename = request.rel_url.query.get("filename", "")
|
||||
try:
|
||||
content = await asyncio.to_thread(_service.get_content, filename)
|
||||
return web.json_response({"content": content})
|
||||
except FileNotFoundError:
|
||||
return web.json_response({"error": "not found"}, status=404)
|
||||
except Exception as e:
|
||||
logger.error("Error getting skill content: %s", e)
|
||||
return web.json_response({"error": str(e)}, status=500)
|
||||
|
||||
|
||||
async def handle_save(request: web.Request) -> web.Response:
|
||||
try:
|
||||
body = await request.json()
|
||||
filename = body.get("filename", "")
|
||||
content = body.get("content", "")
|
||||
result = await asyncio.to_thread(_service.save_file, filename, content)
|
||||
return web.json_response({"status": "ok", "file": result})
|
||||
except Exception as e:
|
||||
logger.error("Error saving skill: %s", e)
|
||||
return web.json_response({"error": str(e)}, status=500)
|
||||
|
||||
|
||||
async def handle_delete(request: web.Request) -> web.Response:
|
||||
try:
|
||||
body = await request.json()
|
||||
filename = body.get("filename", "")
|
||||
await asyncio.to_thread(_service.delete_file, filename)
|
||||
return web.json_response({"status": "ok"})
|
||||
except Exception as e:
|
||||
logger.error("Error deleting skill: %s", e)
|
||||
return web.json_response({"error": str(e)}, status=500)
|
||||
|
||||
|
||||
async def handle_restore_builtin(request: web.Request) -> web.Response:
|
||||
"""Overwrite a built-in skill with the shipped version (user-confirmed in the UI)."""
|
||||
try:
|
||||
body = await request.json()
|
||||
filename = body.get("filename", "")
|
||||
result = await asyncio.to_thread(_service.restore_builtin, filename)
|
||||
return web.json_response({"status": "ok", "file": result})
|
||||
except ValueError as e:
|
||||
return web.json_response({"error": str(e)}, status=400)
|
||||
except Exception as e:
|
||||
logger.error("Error restoring built-in skill: %s", e)
|
||||
return web.json_response({"error": str(e)}, status=500)
|
||||
|
||||
|
||||
async def handle_import(request: web.Request) -> web.Response:
|
||||
"""Import an Agent Skills folder (.zip) or a single .md skill (multipart field "file")."""
|
||||
try:
|
||||
form = await request.post()
|
||||
upload = form.get("file")
|
||||
if upload is None or not hasattr(upload, "file"):
|
||||
return web.json_response({"error": "no file"}, status=400)
|
||||
data = upload.file.read(20 * 1024 * 1024 + 1)
|
||||
if len(data) > 20 * 1024 * 1024:
|
||||
return web.json_response({"error": "file too large (max 20 MB)"}, status=400)
|
||||
result = await asyncio.to_thread(_service.import_skill, upload.filename or "", data)
|
||||
return web.json_response({"status": "ok", **result})
|
||||
except ValueError as e:
|
||||
return web.json_response({"error": str(e)}, status=400)
|
||||
except Exception as e:
|
||||
logger.error("Error importing skill: %s", e)
|
||||
return web.json_response({"error": str(e)}, status=500)
|
||||
|
||||
|
||||
async def handle_get_resource(request: web.Request) -> web.Response:
|
||||
"""Read one reference file of a folder skill (?skill=<folder>&path=<relative path>)."""
|
||||
folder = request.rel_url.query.get("skill", "")
|
||||
rel = request.rel_url.query.get("path", "")
|
||||
try:
|
||||
content = await asyncio.to_thread(_service.get_resource, folder, rel)
|
||||
return web.json_response({"content": content})
|
||||
except FileNotFoundError:
|
||||
return web.json_response({"error": "not found"}, status=404)
|
||||
except ValueError as e:
|
||||
return web.json_response({"error": str(e)}, status=400)
|
||||
except Exception as e:
|
||||
logger.error("Error reading skill resource: %s", e)
|
||||
return web.json_response({"error": str(e)}, status=500)
|
||||
@@ -0,0 +1,243 @@
|
||||
"""Tagger API routes."""
|
||||
|
||||
import asyncio
|
||||
import logging
|
||||
|
||||
from aiohttp import web
|
||||
|
||||
from ..config import TAGGER_DB_FILE, TAGGER_MODELS_DIR, TAGGER_SETTINGS_FILE
|
||||
from ..services.tagger_db_service import TaggerDbService
|
||||
from ..services.tagger_service import TaggerService
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
_svc = TaggerService(TAGGER_MODELS_DIR, TAGGER_SETTINGS_FILE)
|
||||
_db = TaggerDbService(TAGGER_DB_FILE)
|
||||
|
||||
|
||||
def setup_routes(app: web.Application):
|
||||
app.router.add_get("/wfm/tagger/models", handle_models)
|
||||
app.router.add_post("/wfm/tagger/predict", handle_predict)
|
||||
app.router.add_get("/wfm/tagger/vlm/models", handle_vlm_models)
|
||||
app.router.add_post("/wfm/tagger/vlm/predict", handle_vlm_predict)
|
||||
app.router.add_post("/wfm/tagger/batch/start", handle_batch_start)
|
||||
app.router.add_get("/wfm/tagger/batch/status", handle_batch_status)
|
||||
app.router.add_post("/wfm/tagger/batch/stop", handle_batch_stop)
|
||||
app.router.add_get("/wfm/tagger/db/list", handle_db_list)
|
||||
app.router.add_get("/wfm/tagger/db/search", handle_db_search)
|
||||
app.router.add_put("/wfm/tagger/db/{id}", handle_db_update)
|
||||
app.router.add_delete("/wfm/tagger/db/{id}", handle_db_delete)
|
||||
app.router.add_delete("/wfm/tagger/db", handle_db_delete_bulk)
|
||||
app.router.add_get("/wfm/tagger/db/export", handle_db_export)
|
||||
app.router.add_post("/wfm/tagger/db/save", handle_db_save)
|
||||
app.router.add_post("/wfm/tagger/write_meta", handle_write_meta)
|
||||
app.router.add_get("/wfm/tagger/settings", handle_settings_get)
|
||||
app.router.add_post("/wfm/tagger/settings", handle_settings_save)
|
||||
|
||||
|
||||
async def handle_models(request: web.Request) -> web.Response:
|
||||
try:
|
||||
models = await asyncio.to_thread(_svc.list_models)
|
||||
return web.json_response({"models": models})
|
||||
except Exception as e:
|
||||
logger.error("handle_models: %s", e)
|
||||
return web.json_response({"error": str(e)}, status=500)
|
||||
|
||||
|
||||
async def handle_predict(request: web.Request) -> web.Response:
|
||||
try:
|
||||
body = await request.json()
|
||||
b64 = body.get("image_b64", "")
|
||||
model = body.get("model", "")
|
||||
if not b64 or not model:
|
||||
return web.json_response({"error": "image_b64 and model required"}, status=400)
|
||||
result = await asyncio.to_thread(
|
||||
_svc.predict, b64, model,
|
||||
float(body.get("threshold", 0.35)),
|
||||
float(body.get("char_threshold", 0.85)),
|
||||
)
|
||||
return web.json_response(result)
|
||||
except Exception as e:
|
||||
logger.error("handle_predict: %s", e)
|
||||
return web.json_response({"error": str(e)}, status=500)
|
||||
|
||||
|
||||
async def handle_vlm_models(request: web.Request) -> web.Response:
|
||||
backend = request.rel_url.query.get("backend", "ollama")
|
||||
api_url = request.rel_url.query.get("api_url", "http://127.0.0.1:11434")
|
||||
try:
|
||||
models = await asyncio.to_thread(_svc.vlm_models, backend, api_url)
|
||||
return web.json_response({"models": models})
|
||||
except Exception as e:
|
||||
return web.json_response({"error": str(e)}, status=500)
|
||||
|
||||
|
||||
async def handle_vlm_predict(request: web.Request) -> web.Response:
|
||||
try:
|
||||
body = await request.json()
|
||||
result = await asyncio.to_thread(
|
||||
_svc.vlm_predict,
|
||||
body.get("image_b64", ""),
|
||||
body.get("backend", "ollama"),
|
||||
body.get("api_url", "http://127.0.0.1:11434"),
|
||||
body.get("model", ""),
|
||||
body.get("prompt", ""),
|
||||
int(body.get("max_tags", 40)),
|
||||
bool(body.get("thinking_mode", False)),
|
||||
int(body.get("max_tokens", 0)),
|
||||
)
|
||||
return web.json_response(result)
|
||||
except Exception as e:
|
||||
return web.json_response({"error": str(e)}, status=500)
|
||||
|
||||
|
||||
async def handle_batch_start(request: web.Request) -> web.Response:
|
||||
try:
|
||||
body = await request.json()
|
||||
result = await asyncio.to_thread(
|
||||
_svc.batch_start,
|
||||
body.get("folder", ""),
|
||||
body.get("model", ""),
|
||||
float(body.get("threshold", 0.35)),
|
||||
float(body.get("char_threshold", 0.85)),
|
||||
bool(body.get("use_ollama", False)),
|
||||
body.get("vlm_backend", "ollama"),
|
||||
body.get("vlm_api_url", "http://127.0.0.1:11434"),
|
||||
body.get("ollama_model", ""),
|
||||
body.get("ollama_prompt", ""),
|
||||
int(body.get("ollama_max_tags", 40)),
|
||||
bool(body.get("save_db", True)),
|
||||
bool(body.get("write_file", False)),
|
||||
bool(body.get("write_txt", False)),
|
||||
_db,
|
||||
bool(body.get("thinking_mode", False)),
|
||||
int(body.get("max_tokens", 0)),
|
||||
)
|
||||
return web.json_response(result)
|
||||
except Exception as e:
|
||||
return web.json_response({"error": str(e)}, status=500)
|
||||
|
||||
|
||||
async def handle_batch_status(request: web.Request) -> web.Response:
|
||||
return web.json_response(_svc.batch_status())
|
||||
|
||||
|
||||
async def handle_batch_stop(request: web.Request) -> web.Response:
|
||||
_svc.batch_stop()
|
||||
return web.json_response({"ok": True})
|
||||
|
||||
|
||||
async def handle_db_list(request: web.Request) -> web.Response:
|
||||
try:
|
||||
limit = int(request.rel_url.query.get("limit", 100))
|
||||
offset = int(request.rel_url.query.get("offset", 0))
|
||||
rows = await asyncio.to_thread(_db.list, limit, offset)
|
||||
total = await asyncio.to_thread(_db.total)
|
||||
return web.json_response({"rows": rows, "total": total})
|
||||
except Exception as e:
|
||||
return web.json_response({"error": str(e)}, status=500)
|
||||
|
||||
|
||||
async def handle_db_search(request: web.Request) -> web.Response:
|
||||
try:
|
||||
q = request.rel_url.query.get("q", "")
|
||||
rows = await asyncio.to_thread(_db.search, q)
|
||||
return web.json_response({"rows": rows})
|
||||
except Exception as e:
|
||||
return web.json_response({"error": str(e)}, status=500)
|
||||
|
||||
|
||||
async def handle_db_update(request: web.Request) -> web.Response:
|
||||
try:
|
||||
row_id = int(request.match_info["id"])
|
||||
body = await request.json()
|
||||
await asyncio.to_thread(
|
||||
_db.update, row_id,
|
||||
body.get("interrogator_tags", ""),
|
||||
body.get("vlm_tags", ""),
|
||||
)
|
||||
return web.json_response({"ok": True})
|
||||
except Exception as e:
|
||||
return web.json_response({"error": str(e)}, status=500)
|
||||
|
||||
|
||||
async def handle_db_delete(request: web.Request) -> web.Response:
|
||||
try:
|
||||
row_id = int(request.match_info["id"])
|
||||
await asyncio.to_thread(_db.delete, row_id)
|
||||
return web.json_response({"ok": True})
|
||||
except Exception as e:
|
||||
return web.json_response({"error": str(e)}, status=500)
|
||||
|
||||
async def handle_db_delete_bulk(request: web.Request) -> web.Response:
|
||||
try:
|
||||
data = await request.json()
|
||||
ids = data.get("ids", [])
|
||||
|
||||
if not ids:
|
||||
return web.json_response(
|
||||
{"error": "No IDs specified"},
|
||||
status=400,
|
||||
)
|
||||
|
||||
ids = [int(row_id) for row_id in ids]
|
||||
|
||||
deleted_count = await asyncio.to_thread(_db.delete_bulk, ids)
|
||||
|
||||
return web.json_response({
|
||||
"ok": True,
|
||||
"count": deleted_count,
|
||||
})
|
||||
except Exception as e:
|
||||
return web.json_response({"error": str(e)}, status=500)
|
||||
|
||||
async def handle_db_export(request: web.Request) -> web.Response:
|
||||
try:
|
||||
csv_data = await asyncio.to_thread(_db.export_csv)
|
||||
return web.Response(
|
||||
body=csv_data.encode("utf-8"),
|
||||
content_type="text/csv",
|
||||
headers={"Content-Disposition": "attachment; filename=tagger_tags.csv"},
|
||||
)
|
||||
except Exception as e:
|
||||
return web.json_response({"error": str(e)}, status=500)
|
||||
|
||||
|
||||
async def handle_db_save(request: web.Request) -> web.Response:
|
||||
try:
|
||||
body = await request.json()
|
||||
row_id = await asyncio.to_thread(
|
||||
_db.save,
|
||||
body.get("filename", ""),
|
||||
body.get("interrogator_tags", ""),
|
||||
body.get("vlm_tags", ""),
|
||||
)
|
||||
return web.json_response({"ok": True, "id": row_id})
|
||||
except Exception as e:
|
||||
return web.json_response({"error": str(e)}, status=500)
|
||||
|
||||
|
||||
async def handle_write_meta(request: web.Request) -> web.Response:
|
||||
try:
|
||||
body = await request.json()
|
||||
result = await asyncio.to_thread(
|
||||
_svc.write_meta_to_file,
|
||||
body.get("path", ""),
|
||||
body.get("tags", ""),
|
||||
)
|
||||
return web.json_response(result)
|
||||
except Exception as e:
|
||||
return web.json_response({"error": str(e)}, status=500)
|
||||
|
||||
|
||||
async def handle_settings_get(request: web.Request) -> web.Response:
|
||||
return web.json_response(_svc.load_settings())
|
||||
|
||||
|
||||
async def handle_settings_save(request: web.Request) -> web.Response:
|
||||
try:
|
||||
body = await request.json()
|
||||
await asyncio.to_thread(_svc.save_settings, body)
|
||||
return web.json_response({"ok": True})
|
||||
except Exception as e:
|
||||
return web.json_response({"error": str(e)}, status=500)
|
||||
@@ -0,0 +1,83 @@
|
||||
"""
|
||||
TagSpace Routes - タグ/ImagePromptカード/Gallery画像を3D潜在空間に並べるタブ用API
|
||||
"""
|
||||
import asyncio
|
||||
import logging
|
||||
|
||||
from aiohttp import web
|
||||
|
||||
from ..config import DATA_DIR
|
||||
from ..services.tagspace_service import TagSpaceService, DEFAULT_MAX_TAGS, DEFAULT_BG, MAX_TAGS_LIMIT, MIN_COUNT_LIMIT
|
||||
from ..services.semantic_service import SemanticError
|
||||
from .gallery_routes import _service as _gallery, _semantic, _semantic_error, _num, _json_body
|
||||
from .tagger_routes import _svc as _tagger
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
_tagspace = TagSpaceService(DATA_DIR, _gallery, _semantic, _tagger)
|
||||
|
||||
|
||||
def setup_routes(app: web.Application):
|
||||
app.router.add_get("/wfm/tagspace/status", tagspace_status)
|
||||
app.router.add_get("/wfm/tagspace/space", tagspace_space)
|
||||
app.router.add_post("/wfm/tagspace/build", tagspace_build)
|
||||
app.router.add_post("/wfm/tagspace/cancel", tagspace_cancel)
|
||||
app.router.add_post("/wfm/tagspace/search", tagspace_search)
|
||||
app.router.add_post("/wfm/tagspace/neighbors", tagspace_neighbors)
|
||||
|
||||
|
||||
async def _call(fn, *args) -> web.Response:
|
||||
try:
|
||||
return web.json_response(await asyncio.to_thread(fn, *args))
|
||||
except SemanticError as e:
|
||||
return _semantic_error(e)
|
||||
except Exception as e:
|
||||
logger.error("tagspace %s error: %s", getattr(fn, "__name__", fn), e)
|
||||
return web.json_response({"error": str(e)}, status=500)
|
||||
|
||||
|
||||
async def tagspace_status(request: web.Request) -> web.Response:
|
||||
return await _call(_tagspace.status)
|
||||
|
||||
|
||||
async def tagspace_space(request: web.Request) -> web.Response:
|
||||
return await _call(_tagspace.space)
|
||||
|
||||
|
||||
async def tagspace_build(request: web.Request) -> web.Response:
|
||||
body = await _json_body(request)
|
||||
try:
|
||||
# max_tags=0 は全タグ(サービス側で ALL_TAGS_LIMIT まで)
|
||||
max_tags = _num(body, "max_tags", DEFAULT_MAX_TAGS, 0, MAX_TAGS_LIMIT)
|
||||
bg = _num(body, "background", DEFAULT_BG, 0, 20000)
|
||||
min_count = _num(body, "min_count", 1, 1, MIN_COUNT_LIMIT)
|
||||
except SemanticError as e:
|
||||
return _semantic_error(e)
|
||||
tagger_model = str(body.get("tagger_model", "") or "")
|
||||
tagger_scope = str(body.get("tagger_scope", "background") or "background")
|
||||
wildcard = body.get("wildcard", True) is not False
|
||||
return await _call(lambda: (_tagspace.start_build(max_tags, bg, tagger_model, tagger_scope, min_count, wildcard),
|
||||
{"ok": True})[1])
|
||||
|
||||
|
||||
async def tagspace_cancel(request: web.Request) -> web.Response:
|
||||
_tagspace.cancel()
|
||||
return web.json_response({"ok": True})
|
||||
|
||||
|
||||
async def tagspace_search(request: web.Request) -> web.Response:
|
||||
body = await _json_body(request)
|
||||
try:
|
||||
k = _num(body, "k", 20, 1, 200)
|
||||
except SemanticError as e:
|
||||
return _semantic_error(e)
|
||||
return await _call(_tagspace.search, str(body.get("query", "")), k)
|
||||
|
||||
|
||||
async def tagspace_neighbors(request: web.Request) -> web.Response:
|
||||
body = await _json_body(request)
|
||||
try:
|
||||
k = _num(body, "k", 20, 1, 200)
|
||||
except SemanticError as e:
|
||||
return _semantic_error(e)
|
||||
return await _call(_tagspace.neighbors, str(body.get("id", "")), k)
|
||||
@@ -0,0 +1,104 @@
|
||||
"""Unsloth API proxy routes.
|
||||
|
||||
Unlike Ollama/LM Studio/Lemonade, Unsloth Desktop requires an API key even
|
||||
for local access (Authorization: Bearer sk-unsloth-...). The key lives in
|
||||
UNSLOTH_API_KEY (loaded from a .env file by prestartup_script.py) and is
|
||||
never sent to the frontend — the frontend calls this proxy with the target
|
||||
path/method/payload, and the server attaches the Authorization header before
|
||||
relaying to Unsloth's OpenAI-compatible API — and, via the same relay, to its
|
||||
Decision API (/v1/systemone, TypeSafe-compatible Laya decision models; see
|
||||
static/js/decision-client.js).
|
||||
|
||||
The key is optional: when UNSLOTH_API_KEY is unset the request is relayed
|
||||
without an Authorization header, which works when Unsloth Desktop has
|
||||
Keyless API access → "Chat and inference" turned on (localhost / private LAN).
|
||||
"""
|
||||
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import urllib.request
|
||||
from urllib.error import HTTPError, URLError
|
||||
|
||||
from aiohttp import web
|
||||
|
||||
from ..services.url_guard import HINT as _URL_HINT, is_allowed_backend_url, urlopen as _guarded_urlopen
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
UNSLOTH_DEFAULT_URL = "http://localhost:8888"
|
||||
_ALLOWED_PATHS = {"/v1/models", "/v1/chat/completions", "/v1/systemone"}
|
||||
# baseUrl is client-supplied (so a custom Unsloth port works), but the
|
||||
# Authorization header carries a real secret — restrict the host (loopback, or
|
||||
# WFS_ALLOWED_BACKEND_HOSTS set by the operator) so this proxy can't be used to
|
||||
# exfiltrate UNSLOTH_API_KEY to an arbitrary server (SSRF). Redirects are not followed.
|
||||
|
||||
|
||||
def _get_api_key():
|
||||
"""Return the Unsloth API key from the environment (.env), or None."""
|
||||
return os.environ.get("UNSLOTH_API_KEY", "").strip() or None
|
||||
|
||||
|
||||
# Shown when a keyless request is rejected — also used by the Tagger's Unsloth VLM path.
|
||||
KEYLESS_REJECTED_MESSAGE = (
|
||||
"Unsloth rejected the request without an API key (HTTP 401). Either set UNSLOTH_API_KEY "
|
||||
"in the plugin's .env (copy .env.example) and restart ComfyUI, or turn on Keyless API "
|
||||
"access -> \"Chat and inference\" in Unsloth Desktop's Settings -> API."
|
||||
)
|
||||
|
||||
|
||||
def setup_routes(app: web.Application):
|
||||
"""Register Unsloth API routes."""
|
||||
app.router.add_post("/api/wfm/unsloth/proxy", handle_proxy)
|
||||
|
||||
|
||||
async def handle_proxy(request: web.Request) -> web.Response:
|
||||
"""POST /api/wfm/unsloth/proxy - Relay a request to Unsloth's OpenAI-compatible / Decision API.
|
||||
|
||||
Body: { baseUrl, path: "/v1/models" | "/v1/chat/completions" | "/v1/systemone",
|
||||
method: "GET" | "POST", payload }
|
||||
"""
|
||||
import asyncio
|
||||
try:
|
||||
body = await request.json()
|
||||
base_url = (body.get("baseUrl") or UNSLOTH_DEFAULT_URL).rstrip("/")
|
||||
path = body.get("path") or "/v1/models"
|
||||
method = (body.get("method") or "GET").upper()
|
||||
payload = body.get("payload")
|
||||
|
||||
if path not in _ALLOWED_PATHS or method not in ("GET", "POST"):
|
||||
return web.json_response({"message": "Unsupported proxy target"}, status=400)
|
||||
|
||||
if not is_allowed_backend_url(base_url):
|
||||
return web.json_response({"message": _URL_HINT}, status=400)
|
||||
|
||||
# No key → relay without Authorization (Unsloth's Keyless API access); if Unsloth
|
||||
# still demands one, the 401 below explains both ways to fix it.
|
||||
api_key = _get_api_key()
|
||||
|
||||
def _fetch():
|
||||
data = json.dumps(payload).encode("utf-8") if payload is not None else None
|
||||
headers = {"Authorization": f"Bearer {api_key}"} if api_key else {}
|
||||
if data is not None:
|
||||
headers["Content-Type"] = "application/json"
|
||||
req = urllib.request.Request(f"{base_url}{path}", data=data, headers=headers, method=method)
|
||||
with _guarded_urlopen(req, timeout=120) as resp:
|
||||
return json.loads(resp.read().decode("utf-8"))
|
||||
|
||||
data = await asyncio.to_thread(_fetch)
|
||||
return web.json_response(data)
|
||||
|
||||
except HTTPError as e:
|
||||
detail = e.read().decode("utf-8", errors="replace") if e.fp else str(e)
|
||||
logger.warning("Unsloth proxy HTTP error: %s %s", e.code, detail)
|
||||
if e.code == 401 and not _get_api_key():
|
||||
return web.json_response({"message": KEYLESS_REJECTED_MESSAGE}, status=401)
|
||||
# Include a short excerpt of Unsloth's own error body — Decision API schema errors
|
||||
# (e.g. a malformed question) are otherwise impossible to diagnose from the frontend.
|
||||
return web.json_response({"message": f"Unsloth API error: HTTP {e.code} {detail[:300]}".strip()}, status=e.code)
|
||||
except URLError as e:
|
||||
logger.warning("Unsloth proxy connection error: %s", e)
|
||||
return web.json_response({"message": f"Could not reach Unsloth: {e.reason}"}, status=502)
|
||||
except Exception as e:
|
||||
logger.error("Unsloth proxy error: %s", e)
|
||||
return web.json_response({"message": str(e)}, status=500)
|
||||
@@ -0,0 +1,280 @@
|
||||
"""Video tab API routes: last-frame capture, animated GIF conversion, Edit
|
||||
tab probe/text-overlay burn-in, and Plan/Edit project file management."""
|
||||
|
||||
import asyncio
|
||||
import logging
|
||||
|
||||
from aiohttp import web
|
||||
|
||||
from ..config import VIDEO_PLAN_DIR, VIDEO_EDIT_PROJECT_DIR
|
||||
from ..services.video_service import VideoService
|
||||
from ..services.video_plan_service import VideoPlanService
|
||||
from ..services.video_edit_project_service import VideoEditProjectService
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
_service = VideoService()
|
||||
_plan_service = VideoPlanService(VIDEO_PLAN_DIR)
|
||||
_edit_project_service = VideoEditProjectService(VIDEO_EDIT_PROJECT_DIR)
|
||||
|
||||
|
||||
def setup_routes(app: web.Application):
|
||||
app.router.add_post("/api/wfm/video/frame/save-to-output", handle_save_frame)
|
||||
app.router.add_post("/api/wfm/video/to-gif", handle_to_gif)
|
||||
app.router.add_post("/api/wfm/video/asset/register", handle_register_asset)
|
||||
app.router.add_post("/api/wfm/video/edit/convert-audio", handle_convert_audio)
|
||||
app.router.add_get("/api/wfm/video/edit/probe", handle_probe_video)
|
||||
app.router.add_post("/api/wfm/video/edit/overlay-text", handle_overlay_text)
|
||||
|
||||
app.router.add_get("/api/wfm/video/plans", handle_list_plans)
|
||||
app.router.add_get("/api/wfm/video/plans/content", handle_get_plan_content)
|
||||
app.router.add_post("/api/wfm/video/plans/save", handle_save_plan)
|
||||
app.router.add_post("/api/wfm/video/plans/delete", handle_delete_plan)
|
||||
app.router.add_post("/api/wfm/video/index-image/save-to-output", handle_save_index_to_output)
|
||||
|
||||
app.router.add_get("/api/wfm/video/edit/projects", handle_list_edit_projects)
|
||||
app.router.add_get("/api/wfm/video/edit/projects/content", handle_get_edit_project_content)
|
||||
app.router.add_post("/api/wfm/video/edit/projects/save", handle_save_edit_project)
|
||||
app.router.add_post("/api/wfm/video/edit/projects/delete", handle_delete_edit_project)
|
||||
|
||||
|
||||
async def handle_save_frame(request: web.Request) -> web.Response:
|
||||
try:
|
||||
body = await request.json()
|
||||
image_base64 = body.get("image_base64", "")
|
||||
if not image_base64:
|
||||
return web.json_response({"error": "image_base64 required"}, status=400)
|
||||
result = await asyncio.to_thread(_service.save_frame_to_output, image_base64)
|
||||
return web.json_response({"status": "ok", **result})
|
||||
except Exception as e:
|
||||
logger.error("Error saving video frame to output: %s", e)
|
||||
return web.json_response({"error": str(e)}, status=500)
|
||||
|
||||
|
||||
async def handle_register_asset(request: web.Request) -> web.Response:
|
||||
try:
|
||||
body = await request.json()
|
||||
filename = body.get("filename", "")
|
||||
if not filename:
|
||||
return web.json_response({"error": "filename required"}, status=400)
|
||||
result = await asyncio.to_thread(
|
||||
_service.register_asset, filename, body.get("subfolder", ""), body.get("type", "input")
|
||||
)
|
||||
return web.json_response({"status": "ok", **result})
|
||||
except FileNotFoundError as e:
|
||||
return web.json_response({"error": str(e)}, status=404)
|
||||
except ValueError as e:
|
||||
return web.json_response({"error": str(e)}, status=400)
|
||||
except Exception as e:
|
||||
logger.error("Error registering video asset: %s", e)
|
||||
return web.json_response({"error": str(e)}, status=500)
|
||||
|
||||
|
||||
async def handle_convert_audio(request: web.Request) -> web.Response:
|
||||
try:
|
||||
body = await request.json()
|
||||
filename = body.get("filename", "")
|
||||
if not filename:
|
||||
return web.json_response({"error": "filename required"}, status=400)
|
||||
# PyAVの変換はCPU負荷が高いのでスレッドで実行する(イベントループを止めない)
|
||||
result = await asyncio.to_thread(
|
||||
_service.convert_audio_to_output, filename, body.get("subfolder", ""), body.get("type", "input"), body
|
||||
)
|
||||
return web.json_response({"ok": True, **result})
|
||||
except FileNotFoundError as e:
|
||||
return web.json_response({"ok": False, "error": str(e)}, status=404)
|
||||
except ValueError as e:
|
||||
return web.json_response({"ok": False, "error": str(e)}, status=400)
|
||||
except Exception as e:
|
||||
logger.error("Error converting clip audio: %s", e)
|
||||
return web.json_response({"ok": False, "error": str(e)}, status=500)
|
||||
|
||||
|
||||
async def handle_to_gif(request: web.Request) -> web.Response:
|
||||
try:
|
||||
body = await request.json()
|
||||
filename = body.get("filename", "")
|
||||
subfolder = body.get("subfolder", "")
|
||||
type_ = body.get("type", "output")
|
||||
start_time = float(body.get("start_time") or 0)
|
||||
end_time_raw = body.get("end_time")
|
||||
end_time = float(end_time_raw) if end_time_raw not in (None, "") else None
|
||||
fps = float(body.get("fps") or 10)
|
||||
max_width_raw = body.get("max_width")
|
||||
max_width = int(max_width_raw) if max_width_raw not in (None, "") else None
|
||||
|
||||
if not filename:
|
||||
return web.json_response({"error": "filename required"}, status=400)
|
||||
|
||||
result = await asyncio.to_thread(
|
||||
_service.convert_to_gif, filename, subfolder, type_, start_time, end_time, fps, max_width
|
||||
)
|
||||
return web.json_response({"status": "ok", **result})
|
||||
except FileNotFoundError as e:
|
||||
return web.json_response({"error": str(e)}, status=404)
|
||||
except ValueError as e:
|
||||
return web.json_response({"error": str(e)}, status=400)
|
||||
except Exception as e:
|
||||
logger.error("Error converting video to GIF: %s", e)
|
||||
return web.json_response({"error": str(e)}, status=500)
|
||||
|
||||
|
||||
async def handle_probe_video(request: web.Request) -> web.Response:
|
||||
filename = request.rel_url.query.get("filename", "")
|
||||
subfolder = request.rel_url.query.get("subfolder", "")
|
||||
type_ = request.rel_url.query.get("type", "input")
|
||||
if not filename:
|
||||
return web.json_response({"error": "filename required"}, status=400)
|
||||
try:
|
||||
result = await asyncio.to_thread(_service.probe_video, filename, subfolder, type_)
|
||||
return web.json_response(result)
|
||||
except FileNotFoundError as e:
|
||||
return web.json_response({"error": str(e)}, status=404)
|
||||
except ValueError as e:
|
||||
return web.json_response({"error": str(e)}, status=400)
|
||||
except Exception as e:
|
||||
logger.error("Error probing video: %s", e)
|
||||
return web.json_response({"error": str(e)}, status=500)
|
||||
|
||||
|
||||
async def handle_overlay_text(request: web.Request) -> web.Response:
|
||||
try:
|
||||
body = await request.json()
|
||||
filename = body.get("filename", "")
|
||||
subfolder = body.get("subfolder", "")
|
||||
type_ = body.get("type", "output")
|
||||
overlays = body.get("overlays") or []
|
||||
delete_source = bool(body.get("delete_source"))
|
||||
pips = body.get("pips") or []
|
||||
if not filename:
|
||||
return web.json_response({"error": "filename required"}, status=400)
|
||||
if not isinstance(overlays, list) or not isinstance(pips, list):
|
||||
return web.json_response({"error": "overlays and pips must be lists"}, status=400)
|
||||
|
||||
# Decode+re-encode of every frame — run off the event loop so other
|
||||
# requests aren't stalled for the duration of the burn-in.
|
||||
result = await asyncio.to_thread(
|
||||
_service.overlay_text_on_video, filename, subfolder, type_, overlays, "video/wfm_edit", delete_source, pips
|
||||
)
|
||||
return web.json_response({"status": "ok", **result})
|
||||
except FileNotFoundError as e:
|
||||
return web.json_response({"error": str(e)}, status=404)
|
||||
except ValueError as e:
|
||||
return web.json_response({"error": str(e)}, status=400)
|
||||
except Exception as e:
|
||||
logger.error("Error burning text overlay into video: %s", e)
|
||||
return web.json_response({"error": str(e)}, status=500)
|
||||
|
||||
|
||||
async def handle_list_plans(request: web.Request) -> web.Response:
|
||||
try:
|
||||
result = await asyncio.to_thread(_plan_service.list_plans)
|
||||
return web.json_response(result)
|
||||
except Exception as e:
|
||||
logger.error("Error listing video plans: %s", e)
|
||||
return web.json_response({"error": str(e)}, status=500)
|
||||
|
||||
|
||||
async def handle_get_plan_content(request: web.Request) -> web.Response:
|
||||
filename = request.rel_url.query.get("filename", "")
|
||||
try:
|
||||
data = await asyncio.to_thread(_plan_service.get_plan, filename)
|
||||
return web.json_response({"data": data})
|
||||
except FileNotFoundError:
|
||||
return web.json_response({"error": "not found"}, status=404)
|
||||
except ValueError as e:
|
||||
return web.json_response({"error": str(e)}, status=400)
|
||||
except Exception as e:
|
||||
logger.error("Error getting video plan content: %s", e)
|
||||
return web.json_response({"error": str(e)}, status=500)
|
||||
|
||||
|
||||
async def handle_save_plan(request: web.Request) -> web.Response:
|
||||
try:
|
||||
body = await request.json()
|
||||
filename = body.get("filename", "")
|
||||
data = body.get("data", {})
|
||||
index_image_base64 = body.get("index_image_base64")
|
||||
result = await asyncio.to_thread(_plan_service.save_plan, filename, data, index_image_base64)
|
||||
return web.json_response({"status": "ok", **result})
|
||||
except ValueError as e:
|
||||
return web.json_response({"error": str(e)}, status=400)
|
||||
except Exception as e:
|
||||
logger.error("Error saving video plan: %s", e)
|
||||
return web.json_response({"error": str(e)}, status=500)
|
||||
|
||||
|
||||
async def handle_delete_plan(request: web.Request) -> web.Response:
|
||||
try:
|
||||
body = await request.json()
|
||||
filename = body.get("filename", "")
|
||||
await asyncio.to_thread(_plan_service.delete_plan, filename)
|
||||
return web.json_response({"status": "ok"})
|
||||
except ValueError as e:
|
||||
return web.json_response({"error": str(e)}, status=400)
|
||||
except Exception as e:
|
||||
logger.error("Error deleting video plan: %s", e)
|
||||
return web.json_response({"error": str(e)}, status=500)
|
||||
|
||||
|
||||
async def handle_list_edit_projects(request: web.Request) -> web.Response:
|
||||
try:
|
||||
result = await asyncio.to_thread(_edit_project_service.list_projects)
|
||||
return web.json_response(result)
|
||||
except Exception as e:
|
||||
logger.error("Error listing video edit projects: %s", e)
|
||||
return web.json_response({"error": str(e)}, status=500)
|
||||
|
||||
|
||||
async def handle_get_edit_project_content(request: web.Request) -> web.Response:
|
||||
filename = request.rel_url.query.get("filename", "")
|
||||
try:
|
||||
data = await asyncio.to_thread(_edit_project_service.get_project, filename)
|
||||
return web.json_response({"data": data})
|
||||
except FileNotFoundError:
|
||||
return web.json_response({"error": "not found"}, status=404)
|
||||
except ValueError as e:
|
||||
return web.json_response({"error": str(e)}, status=400)
|
||||
except Exception as e:
|
||||
logger.error("Error getting video edit project content: %s", e)
|
||||
return web.json_response({"error": str(e)}, status=500)
|
||||
|
||||
|
||||
async def handle_save_edit_project(request: web.Request) -> web.Response:
|
||||
try:
|
||||
body = await request.json()
|
||||
filename = body.get("filename", "")
|
||||
data = body.get("data", {})
|
||||
result = await asyncio.to_thread(_edit_project_service.save_project, filename, data)
|
||||
return web.json_response({"status": "ok", **result})
|
||||
except ValueError as e:
|
||||
return web.json_response({"error": str(e)}, status=400)
|
||||
except Exception as e:
|
||||
logger.error("Error saving video edit project: %s", e)
|
||||
return web.json_response({"error": str(e)}, status=500)
|
||||
|
||||
|
||||
async def handle_delete_edit_project(request: web.Request) -> web.Response:
|
||||
try:
|
||||
body = await request.json()
|
||||
filename = body.get("filename", "")
|
||||
await asyncio.to_thread(_edit_project_service.delete_project, filename)
|
||||
return web.json_response({"status": "ok"})
|
||||
except ValueError as e:
|
||||
return web.json_response({"error": str(e)}, status=400)
|
||||
except Exception as e:
|
||||
logger.error("Error deleting video edit project: %s", e)
|
||||
return web.json_response({"error": str(e)}, status=500)
|
||||
|
||||
|
||||
async def handle_save_index_to_output(request: web.Request) -> web.Response:
|
||||
try:
|
||||
body = await request.json()
|
||||
image_base64 = body.get("image_base64", "")
|
||||
if not image_base64:
|
||||
return web.json_response({"error": "image_base64 required"}, status=400)
|
||||
result = await asyncio.to_thread(_plan_service.save_index_image_to_output, image_base64)
|
||||
return web.json_response({"status": "ok", **result})
|
||||
except Exception as e:
|
||||
logger.error("Error saving video index image to output: %s", e)
|
||||
return web.json_response({"error": str(e)}, status=500)
|
||||
@@ -0,0 +1,222 @@
|
||||
"""VRAM management: unload Ollama models before image generation to free VRAM.
|
||||
|
||||
Ported from ComfyUI Comic Creator (/api/ccc/vram/prepare), which follows ComfyUI-LiveChatStream's
|
||||
vram_prepare. ComfyUI's own free-VRAM figure (get_free_memory / system_stats vram_free) may not react
|
||||
to Ollama loading/unloading models (measured on ComfyUI_5: 8462MB before and after loading a 9B model
|
||||
while nvidia-smi went 6530 -> 469MB), so free VRAM is measured with nvidia-smi plus ComfyUI's own
|
||||
unused torch cache, falling back to get_free_memory when nvidia-smi is unavailable.
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import json
|
||||
import logging
|
||||
import math
|
||||
import subprocess
|
||||
import time
|
||||
import urllib.request
|
||||
from urllib.parse import urlparse
|
||||
|
||||
from aiohttp import web
|
||||
|
||||
from ..services.url_guard import is_allowed_backend_url, LOOPBACK_HOSTS, urlopen
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
_MB = 1024 * 1024
|
||||
_OLLAMA_DEFAULT_URL = "http://127.0.0.1:11434"
|
||||
_MAX_URLS = 6 # incl. the default; each unreachable URL costs a connect timeout
|
||||
_lock = asyncio.Lock() # never run concurrently (unloading and measuring interfere)
|
||||
|
||||
|
||||
def setup_routes(app: web.Application):
|
||||
app.router.add_post("/api/wfm/vram/prepare", handle_prepare)
|
||||
|
||||
|
||||
def _smi_free_mb(ident):
|
||||
flags = getattr(subprocess, "CREATE_NO_WINDOW", 0)
|
||||
out = subprocess.run(
|
||||
["nvidia-smi", "-i", str(ident), "--query-gpu=memory.free", "--format=csv,noheader,nounits"],
|
||||
capture_output=True, text=True, timeout=5, creationflags=flags,
|
||||
)
|
||||
if out.returncode != 0:
|
||||
raise RuntimeError(out.stderr.strip() or "nvidia-smi failed")
|
||||
return float(out.stdout.strip().splitlines()[0])
|
||||
|
||||
|
||||
def _free_vram_mb():
|
||||
"""Free VRAM (MB) usable for image generation, and its source ('nvidia-smi' / 'comfy')."""
|
||||
import torch
|
||||
import comfy.model_management as mm
|
||||
dev = mm.get_torch_device()
|
||||
if getattr(dev, "type", "cpu") == "cuda":
|
||||
try:
|
||||
st = torch.cuda.memory_stats(dev)
|
||||
cached = max(0, st["reserved_bytes.all.current"] - st["active_bytes.all.current"])
|
||||
try:
|
||||
free = _smi_free_mb(f"GPU-{torch.cuda.get_device_properties(dev).uuid}")
|
||||
except Exception:
|
||||
free = _smi_free_mb(dev.index or 0)
|
||||
return free + cached / _MB, "nvidia-smi"
|
||||
except Exception as e:
|
||||
logger.warning("[WFS] nvidia-smi free VRAM unavailable, falling back to ComfyUI: %s", e)
|
||||
return mm.get_free_memory(dev) / _MB, "comfy"
|
||||
|
||||
|
||||
def _wait_settled(prev_mb, timeout_s=6.0):
|
||||
"""After an unload, wait until free VRAM grows and levels off (Ollama runner exit); return it (MB)."""
|
||||
now = prev_mb
|
||||
last = None
|
||||
deadline = time.monotonic() + timeout_s
|
||||
while time.monotonic() < deadline:
|
||||
time.sleep(0.4)
|
||||
now, _ = _free_vram_mb()
|
||||
if last is not None and abs(now - last) < 32 and now > prev_mb + 32:
|
||||
break
|
||||
last = now
|
||||
return now
|
||||
|
||||
|
||||
def _ollama_json(base, path, payload=None, timeout=60):
|
||||
data = json.dumps(payload).encode("utf-8") if payload is not None else None
|
||||
req = urllib.request.Request(base + path, data=data, headers={"Content-Type": "application/json"},
|
||||
method="POST" if data is not None else "GET")
|
||||
with urlopen(req, timeout=timeout) as resp:
|
||||
return resp.status, resp.read()
|
||||
|
||||
|
||||
def _ollama_loaded_names(base):
|
||||
_, raw = _ollama_json(base, "/api/ps", timeout=5)
|
||||
return {m.get("name") for m in json.loads(raw.decode("utf-8")).get("models", [])}
|
||||
|
||||
|
||||
def _ollama_unload(base, name):
|
||||
"""Unload with keep_alive=0. Models that reject /api/generate (e.g. decision models) are retried
|
||||
with /api/chat. Ollama sometimes unloads a little later even after an error response, so finally
|
||||
check /api/ps to see whether it is still loaded."""
|
||||
errors = []
|
||||
for path, payload in (("/api/generate", {"model": name, "keep_alive": 0}),
|
||||
("/api/chat", {"model": name, "messages": [], "keep_alive": 0})):
|
||||
try:
|
||||
status, _ = _ollama_json(base, path, payload)
|
||||
if status == 200:
|
||||
return True
|
||||
errors.append(f"{path}: HTTP {status}")
|
||||
except Exception as e:
|
||||
errors.append(f"{path}: {e}")
|
||||
for _ in range(5):
|
||||
time.sleep(0.5)
|
||||
try:
|
||||
if name not in _ollama_loaded_names(base):
|
||||
return True
|
||||
except Exception:
|
||||
pass
|
||||
logger.warning("[WFS] vram: unload failed for %s: %s", name, "; ".join(errors))
|
||||
return False
|
||||
|
||||
|
||||
def _ollama_bases(urls):
|
||||
"""Deduplicated, permitted Ollama base URLs. localhost / 127.0.0.1 / ::1 count as one server.
|
||||
URLs the backend guard rejects are skipped (logged) rather than failing the whole request."""
|
||||
if urls is None:
|
||||
urls = []
|
||||
if not isinstance(urls, list):
|
||||
raise ValueError("urls must be an array")
|
||||
bases, seen = [], set()
|
||||
for raw in [_OLLAMA_DEFAULT_URL, *urls]:
|
||||
if not isinstance(raw, str) or not raw.strip():
|
||||
continue
|
||||
base = raw.strip().rstrip("/")
|
||||
if not is_allowed_backend_url(base):
|
||||
logger.warning("[WFS] vram: skipped backend URL not permitted by the guard: %s", base)
|
||||
continue
|
||||
p = urlparse(base)
|
||||
host = (p.hostname or "").lower()
|
||||
key = ("loopback" if host in LOOPBACK_HOSTS else host, p.scheme, p.port or (443 if p.scheme == "https" else 80))
|
||||
if key in seen:
|
||||
continue
|
||||
seen.add(key)
|
||||
bases.append(base)
|
||||
if len(bases) >= _MAX_URLS:
|
||||
break
|
||||
return bases
|
||||
|
||||
|
||||
def _prepare(mode, target_mb, bases):
|
||||
free_before, free_src = _free_vram_mb()
|
||||
cands, unreachable = [], []
|
||||
for base in bases:
|
||||
try:
|
||||
_, raw = _ollama_json(base, "/api/ps", timeout=5)
|
||||
for m in json.loads(raw.decode("utf-8")).get("models", []):
|
||||
if m.get("name"):
|
||||
cands.append({"base": base, "name": m["name"], "vram_mb": int(m.get("size_vram", 0) / _MB)})
|
||||
except Exception as e:
|
||||
# Ollama not running etc. Normal for the default URL, so not a failure; keep the reason in the
|
||||
# log only (the response doesn't reveal the state of caller-chosen local ports)
|
||||
logger.info("[WFS] vram: %s/api/ps failed: %r", base, e)
|
||||
unreachable.append({"url": base})
|
||||
unloaded, failed = [], []
|
||||
free_after = free_before
|
||||
if mode == "auto":
|
||||
# Ollama's size_vram excludes the KV cache etc. and is smaller than the VRAM actually freed.
|
||||
# Choosing by estimate could free too much, so unload the biggest first, one at a time, and stop
|
||||
# as soon as the measured free VRAM reaches the target
|
||||
cands.sort(key=lambda c: c["vram_mb"], reverse=True)
|
||||
for c in cands:
|
||||
if free_after >= target_mb:
|
||||
break
|
||||
if _ollama_unload(c["base"], c["name"]):
|
||||
unloaded.append(c)
|
||||
free_after = _wait_settled(free_after)
|
||||
else:
|
||||
failed.append(c)
|
||||
else:
|
||||
for c in cands:
|
||||
(unloaded if _ollama_unload(c["base"], c["name"]) else failed).append(c)
|
||||
if unloaded:
|
||||
free_after = _wait_settled(free_after)
|
||||
strip = lambda cs: [{"name": c["name"], "vram_mb": c["vram_mb"]} for c in cs]
|
||||
return {
|
||||
"status": "ok", "mode": mode, "target_gb": target_mb / 1024, "free_source": free_src,
|
||||
"free_before_mb": round(free_before), "free_after_mb": round(free_after),
|
||||
"unloaded": strip(unloaded), "failed": [c["name"] for c in failed],
|
||||
"unreachable": unreachable,
|
||||
"reached": free_after >= target_mb,
|
||||
}
|
||||
|
||||
|
||||
def _error(message, status):
|
||||
return web.json_response({"status": "error", "message": message}, status=status)
|
||||
|
||||
|
||||
async def handle_prepare(request: web.Request) -> web.Response:
|
||||
"""POST {mode:'auto'|'all', target_gb, urls:[Ollama URLs]}.
|
||||
auto: only when free VRAM is below target_gb, unload the models using the most VRAM until it is reached.
|
||||
all: unload every loaded model.
|
||||
The default 127.0.0.1:11434 is always included; other URLs must pass the backend URL guard."""
|
||||
# JSON only, so another site can't unload models with a simple (preflight-free) text/plain request
|
||||
if request.content_type != "application/json":
|
||||
return _error("Content-Type must be application/json", 415)
|
||||
try:
|
||||
data = await request.json()
|
||||
if not isinstance(data, dict):
|
||||
raise ValueError("body must be a JSON object")
|
||||
mode = data.get("mode")
|
||||
if mode not in ("auto", "all"):
|
||||
raise ValueError("mode must be auto or all")
|
||||
target_gb = float(data.get("target_gb", 8) or 0)
|
||||
if not math.isfinite(target_gb):
|
||||
raise ValueError("target_gb must be a finite number")
|
||||
target_mb = min(max(target_gb, 0.0), 64.0) * 1024
|
||||
bases = _ollama_bases(data.get("urls"))
|
||||
except Exception as e:
|
||||
return _error(str(e), 400)
|
||||
if _lock.locked():
|
||||
return _error("VRAM management is already running", 409)
|
||||
try:
|
||||
async with _lock:
|
||||
result = await asyncio.get_running_loop().run_in_executor(None, _prepare, mode, target_mb, bases)
|
||||
return web.json_response(result)
|
||||
except Exception as e:
|
||||
logger.error("[WFS] vram prepare error: %s", e)
|
||||
return _error(str(e), 500)
|
||||
@@ -0,0 +1,45 @@
|
||||
---
|
||||
name: Image to Prompt
|
||||
description: Looks at an attached image and writes a prompt that recreates it, in the style the current GenerateUI model understands best.
|
||||
metadata:
|
||||
wfs-version: 2
|
||||
output: prompt
|
||||
tools: []
|
||||
temperature: 0.3
|
||||
think: false
|
||||
context: [workflow]
|
||||
---
|
||||
|
||||
You reverse-engineer images into text-to-image prompts. The user attaches an image (in the TOOLS pane, which also attaches it to the chat) and you write a prompt that would recreate it with the model in their current workflow. This only works with a vision-capable chat model.
|
||||
|
||||
If no image is attached to the user's message, do not invent one: reply in one or two sentences asking them to drop an image into the TOOLS pane (PNG / JPG / WebP) and send their message again.
|
||||
|
||||
## Step 1 - look carefully, describe only what is visible
|
||||
Go through the image in this order and note only what you can actually see - never guess names of characters, people, brands or artists:
|
||||
1. Main subject(s): count, kind, apparent age group, hair, eyes, clothing and accessories with colors.
|
||||
2. Pose, action, expression, gaze direction.
|
||||
3. Setting and background, important objects.
|
||||
4. Lighting (direction, softness, time of day), color palette.
|
||||
5. Framing: shot size (close-up, upper body, full body, wide), camera angle, lens feel (shallow depth of field, wide angle).
|
||||
6. Medium and style: photo, anime illustration, 3D render, oil painting, flat vector, etc.
|
||||
7. Any readable text in the image - copy it exactly.
|
||||
|
||||
## Step 2 - pick the prompt style from the "Current workflow context"
|
||||
- NATURAL style (Qwen-Image, FLUX, Z-Image, HiDream, SD3 and other T5 / LLM text-encoder models): fluent English sentences in the order above, 40-120 words, no quality tags; text to render goes in double quotes. Leave negative empty when CFG is about 1.
|
||||
- TAG style (SDXL anime checkpoints: Illustrious, NoobAI, Animagine, Pony): Danbooru tags in the order quality -> count -> appearance -> expression/pose -> background -> lighting -> composition. Quality tags: Pony `score_9, score_8_up, score_7_up`; others `masterpiece, best quality, very aesthetic, absurdres`. Negative: `worst quality, low quality, lowres, bad anatomy, bad hands, jpeg artifacts, watermark, signature`.
|
||||
- MIXED style (realistic SDXL / SD1.5): short comma-separated descriptive phrases plus camera and lighting terms.
|
||||
- No context: use NATURAL.
|
||||
- Write every positive and negative prompt from scratch from the user's request and the style rules here. Only when the context contains "Prompts currently typed into the workflow" (it appears when the user refers to the current prompt) edit or extend those as the user asks; even then, keep only the parts the user wants to keep.
|
||||
|
||||
## Output format (always)
|
||||
1. One line starting with "Style:" naming the style and why (e.g. "Style: TAG - workflow uses an Illustrious checkpoint").
|
||||
2. The prompt in a fenced block labeled `prompt`:
|
||||
|
||||
```prompt
|
||||
positive: <the full prompt on one line>
|
||||
negative: <negative prompt on one line, or empty>
|
||||
```
|
||||
|
||||
3. One line "Aspect: W:H" matching the image's orientation (e.g. "Aspect: 2:3 (portrait)").
|
||||
|
||||
Reply to the user in their language outside the block; the prompt itself is English. If the user asks for changes ("make it night", "remove the hat"), output the complete updated block again.
|
||||
@@ -0,0 +1,55 @@
|
||||
---
|
||||
name: Skill Creator
|
||||
description: Interactively interviews you and drafts a new WFS chat skill (.md system prompt) ready to save.
|
||||
metadata:
|
||||
wfs-version: 3
|
||||
tools: []
|
||||
temperature: 0.5
|
||||
---
|
||||
|
||||
You are a skill-design assistant embedded in ComfyUI Workflow Studio's AI TOOL Chat pane. Your job is to interactively help the user design a NEW "skill" - a markdown file with frontmatter followed by system-prompt instructions. Once saved, a skill can be selected from a dropdown and is silently prepended to future chat messages as a system prompt.
|
||||
|
||||
## How to conduct the interview
|
||||
- Ask ONE focused question at a time, never a bulleted list of questions. Wait for the user's answer before asking the next one.
|
||||
- Cover, in this order, only what is not already clear from context:
|
||||
1. What task or domain should the skill specialize in (what should the model do differently once this skill is active)?
|
||||
2. What output format is expected - plain prose, a specific fenced code block, a fixed structure, a length limit? If the result is an image prompt, an SVG, or another skill, suggest the matching Workflow Studio output type below so the user gets action buttons for free.
|
||||
3. Any hard constraints or things to avoid (tone, forbidden content, security concerns, things past attempts got wrong)?
|
||||
4. Would a short worked example help smaller/local models follow the pattern more reliably? If yes, ask what a good example input/output looks like, or offer to draft one.
|
||||
- Keep it short - 3 to 5 questions is usually enough. If the user says "just generate it", "that's enough", or similar at any point, stop asking and produce the best skill you can from what you already have.
|
||||
|
||||
## Workflow Studio output types (the fenced blocks the app recognizes)
|
||||
- ```prompt block - an image-generation prompt in this exact shape (the app shows "Apply to GenerateUI" / "Generate with this prompt" buttons):
|
||||
positive: <prompt text>
|
||||
negative: <negative prompt text, may be empty>
|
||||
- ```svg block - one complete `<svg>` element (the app previews it, can save it to the Gallery, and auto-checks it).
|
||||
- ```skill block - a complete skill file (the app shows a "Save as new skill" button).
|
||||
|
||||
## Optional metadata a skill can declare
|
||||
All keys are optional and go under `metadata:` in the frontmatter. Only include the ones that matter for this skill.
|
||||
- `output`: `prompt` or `svg` - the app checks that the reply contains that block and automatically asks the model to fix it once if it is missing or broken.
|
||||
- `tools`: `[]` to never offer image generation to the model, or `[generate_image]` to let it start ComfyUI generation by itself (only when the user turned on the image-generation toggle).
|
||||
- `temperature`: a number such as `0.3` (precise, repeatable) to `0.9` (creative).
|
||||
- `think`: `true` / `false` to force the model's thinking mode on or off for this skill.
|
||||
- `context`: a list of facts sent with every message:
|
||||
- `workflow`: a summary of the workflow loaded in GenerateUI (model files, prompt nodes, CFG, resolution). The prompt text currently in the workflow is added only when the user's message refers to it ("improve the current prompt").
|
||||
- `current-prompt`: always include the prompt text currently in the workflow (for skills whose job is to edit that prompt).
|
||||
- `workflow-detail`: every node with its settings, checked against this ComfyUI install (missing nodes / files, broken links) - for troubleshooting skills.
|
||||
- `logs`: the last execution error and the latest error block of the ComfyUI log.
|
||||
|
||||
## Output format for the finished skill
|
||||
- Once you have enough information, output the complete skill file in a single fenced code block labeled `skill` (```skill ... ```). Never mix prose inside that block - explanation goes outside it.
|
||||
- The block must start with frontmatter in this shape (drop the `metadata:` part entirely if no key is needed):
|
||||
---
|
||||
name: <short display name, shown in the skill dropdown>
|
||||
description: <one sentence, shown as a tooltip in the dropdown>
|
||||
metadata:
|
||||
output: <prompt or svg>
|
||||
temperature: <number>
|
||||
---
|
||||
- After the frontmatter, write clear, imperative system-prompt instructions for the target skill: what role the model should take, concrete output-format rules, hard constraints, and - if useful - one short worked example following a "request -> ideal output" shape.
|
||||
- Write the instructions in English unless the user asks otherwise (small local models follow English instructions most reliably), but tell the skill to reply in the user's language.
|
||||
- After the code block, tell the user in one line that they can click the "Save as new skill" button below the message to add it, or copy the block manually into a new skill.
|
||||
|
||||
## Improving an existing skill
|
||||
If the user pastes an existing skill and describes what went wrong, do not interview from scratch: identify the cause in one or two sentences, then output the complete revised skill in a ```skill block, keeping its name unless asked to change it.
|
||||
@@ -0,0 +1,53 @@
|
||||
---
|
||||
name: Storyboard to Lab
|
||||
description: Turns a story or scene list into a Lab plan - one prompt per scene with consistent characters - that opens in GenerateUI > Lab with one click.
|
||||
metadata:
|
||||
wfs-version: 2
|
||||
output: labplan
|
||||
tools: []
|
||||
temperature: 0.6
|
||||
think: false
|
||||
context: [workflow]
|
||||
---
|
||||
|
||||
You are a storyboard artist for ComfyUI Workflow Studio. The user describes a story, a sequence, or a list of shots (in any language). You split it into scenes and write one text-to-image prompt per scene, packaged as a Lab plan: the Lab tab runs the scenes as consecutive iterations of the workflow loaded in GenerateUI.
|
||||
|
||||
## Before writing
|
||||
- If the user did not say how many scenes, use 4-8 that cover the story's key beats. Never exceed 32.
|
||||
- If an essential detail is missing and would change every scene (e.g. who the main character is), ask ONE short question first. Otherwise just make sensible choices.
|
||||
|
||||
## Consistency (the most important part)
|
||||
- Write a fixed "character sheet" phrase for each recurring character (hair, eyes, age range, outfit with colors) and paste it IDENTICALLY into every scene where that character appears. Do the same for a recurring place or style.
|
||||
- Keep one art style / medium for the whole plan and repeat it in every scene.
|
||||
- Use the same "seed" for the whole plan (any integer, e.g. 123456789) so the look stays stable; use null only if the user wants variety.
|
||||
|
||||
## Prompt style per scene
|
||||
Use the "Current workflow context" to choose the style:
|
||||
- NATURAL (Qwen-Image, FLUX, Z-Image, HiDream, SD3, other T5 / LLM-encoder models): English sentences - character sheet, action in this scene, setting, lighting, camera framing, style. 40-100 words, no quality tags. Negative empty when CFG is about 1.
|
||||
- TAG (Illustrious, NoobAI, Animagine, Pony): Danbooru tags - quality tags (Pony: `score_9, score_8_up, score_7_up`; others: `masterpiece, best quality, very aesthetic, absurdres`), count tag, character sheet tags, scene action, background, lighting, framing. Negative: `worst quality, low quality, lowres, bad anatomy, bad hands, jpeg artifacts, watermark, signature`.
|
||||
- MIXED (realistic SDXL / SD1.5): short descriptive phrases plus camera and lighting terms.
|
||||
- No context: NATURAL.
|
||||
- Write every positive and negative prompt from scratch from the user's request and the style rules here. Only when the context contains "Prompts currently typed into the workflow" (it appears when the user refers to the current prompt) edit or extend those as the user asks; even then, keep only the parts the user wants to keep.
|
||||
|
||||
Vary the camera framing across scenes (wide establishing shot, medium shot, close-up) like a real storyboard.
|
||||
|
||||
## Output format (always)
|
||||
1. A short numbered list of the scenes in the user's language (one line each).
|
||||
2. The plan in one fenced block labeled `labplan` containing valid JSON only (double quotes, no comments, no trailing commas):
|
||||
|
||||
```labplan
|
||||
{
|
||||
"name": "short_plan_name",
|
||||
"note": "one-line summary of the story",
|
||||
"seed": 123456789,
|
||||
"negative": "default negative prompt for every scene, written from the style rules above (empty string for CFG about 1)",
|
||||
"scenes": [
|
||||
{ "title": "Scene title", "positive": "full prompt for this scene" },
|
||||
{ "title": "Scene title", "positive": "full prompt", "negative": "only if this scene needs a different negative" }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
3. One line telling the user to press "Open in Lab" below the message, check the plan, and press Run in the Lab tab (GenerateUI must have the workflow loaded).
|
||||
|
||||
When the user asks for changes ("make scene 3 at night", "add a scene"), output the complete updated `labplan` block again, keeping the character sheets identical.
|
||||