本設計は、ローカルのRTX 3090 (VRAM 24GB)環境において、ComfyUI API (WebSocket経由)とMCP (Model Context Protocol)を組み合わせ、漫画コマ生成からVision(VLM)評価、低スコアの自動Inpaint修正、そして一貫したファイル命名規則(p003_c02_selected.png)までを完全自動化するパイプラインです。VRAMの競合を防ぐため、「生成ノード」と「Vision評価ノード」の逐次排他メモリ制御を実装し、破綻のない高速なコマ量産を実現します。
Prompt/Seedを置換
/api/prompt キュー送信
Florence-2/Qwen2.5-VL
再生成 or Inpaint
p003_c02_selected
RTX 3090のVRAM 24GBは強力ですが、Flux.1やSDXLの生成モデルと、Vision LLM(採点用)を同時にVRAM上に常駐させると、共有メモリ(システムRAM)へのスワップが発生し、処理速度が10分の1以下に低下します。
| 管理項目 | 2026年最適化アプローチ | VRAM制御仕様 |
|---|---|---|
| 並列キュー制御 | API経由のシングルスレッド逐次投入(同時実行数=1) | ComfyUI内部のQueue機能にスタックさせ、VRAM競合を回避。 |
| モデルアンロード | python_argsに --lowvram または --highvram を指定。 |
生成完了後、VLM起動前にComfyUIのモデルキャッシュを解放(API経由で /free エンドポイントを叩く)。 |
| Visionモデル選定 | ローカル実行時は Florence-2-large または Qwen2.5-VL-7B (INT4) を採用。 | VRAM消費を4GB〜8GBに抑え、生成モデル(SDXL: 約8GB)との共存を可能にする。 |
/free APIを呼び出すことで、未使用のモデルキャッシュを強制解放できます。パイプラインから生成と評価を交互に行う場合、このAPIコールをオーケストレーターに組み込むことが必須です。
以下は、ComfyUIのWebSocket APIを使用してワークフローJSONを動的に書き換え、生成、Vision採点、条件分岐(再生成/Inpaint)、および指定の命名規則での保存までを行う完全な実装スクリプトです。
pythonimport json
import urllib.request
import urllib.parse
import websocket
import uuid
import os
from PIL import Image
import io
# 設定値
COMFYUI_ADDRESS = "127.0.0.1:8188"
CLIENT_ID = str(uuid.uuid4())
OUTPUT_DIR = "./output_manga"
SCORE_THRESHOLD = 70 # 100点満点中70点未満で再生成/Inpaint
os.makedirs(OUTPUT_DIR, exist_ok=True)
# 1. ワークフローJSONの読み込みと動的書き換え
def load_and_modify_workflow(template_path, prompt_text, seed, input_image_path=None):
with open(template_path, 'r', encoding='utf-8') as f:
prompt_workflow = json.load(f)
# ノードIDはComfyUIの書き出しJSONに依存(以下は一般的なノードIDの例)
# CLIPTextEncode (プロンプト入力)
if "6" in prompt_workflow:
prompt_workflow["6"]["inputs"]["text"] = prompt_text
# KSampler (シード値)
if "3" in prompt_workflow:
prompt_workflow["3"]["inputs"]["seed"] = seed
# Inpaint用の画像入力がある場合
if input_image_path and "10" in prompt_workflow:
prompt_workflow["10"]["inputs"]["image"] = input_image_path
return prompt_workflow
# 2. ComfyUI APIへのジョブ投入と画像取得 (WebSocket経由)
def queue_prompt(prompt_workflow):
p = {"prompt": prompt_workflow, "client_id": CLIENT_ID}
data = json.dumps(p).encode('utf-8')
req = urllib.request.Request(f"http://{COMFYUI_ADDRESS}/prompt", data=data)
response = json.loads(urllib.request.urlopen(req).read().decode('utf-8'))
return response['prompt_id']
def wait_for_image(prompt_id):
ws = websocket.WebSocket()
ws.connect(f"ws://{COMFYUI_ADDRESS}/view?client_id={CLIENT_ID}")
while True:
out = ws.recv()
if isinstance(out, str):
message = json.loads(out)
if message['type'] == 'executing':
data = message['data']
if data['node'] is None and data['prompt_id'] == prompt_id:
break # 生成完了
# 履歴から画像ファイル名を取得
history_req = urllib.request.urlopen(f"http://{COMFYUI_ADDRESS}/history/{prompt_id}")
history = json.loads(history_req.read().decode('utf-8'))
node_outputs = history[prompt_id]['outputs']
for node_id in node_outputs:
if 'images' in node_outputs[node_id]:
for image in node_outputs[node_id]['images']:
return image['filename'] # 保存されたファイル名
return None
# 3. Vision (VLM) による仮の採点関数 (ローカルAPIまたはMCP経由を想定)
def evaluate_image_with_vlm(image_path, criteria="破綻がないか、デッサンが正しいか"):
# 2026年基準: ローカルの軽量VLM (Florence-2等) または Cloud VLM API を呼び出し
# ここではデモ用に模擬スコアと判定を返す
print(f"[Vision] {image_path} を評価中...")
# 実際の実装では、ここで画像をVLMに入力し、JSONでスコアをパースする
import random
score = random.randint(50, 95) # 模擬スコア
feedback = "顔のデッサンにやや崩れあり" if score < SCORE_THRESHOLD else "良好"
return score, feedback
# 4. メインオーケストレーター
def generate_manga_panel(page, cut, prompt_text, template_path, inpaint_template_path):
seed = 42
attempt = 1
max_attempts = 3
# 命名規則の定義
base_filename = f"p{page:03d}_c{cut:02d}"
while attempt <= max_attempts:
print(f"\n--- Page {page} Cut {cut} (試行 {attempt}/{max_attempts}) ---")
# ワークフローの書き換え
workflow = load_and_modify_workflow(template_path, prompt_text, seed + attempt)
# キュー投入と待機
prompt_id = queue_prompt(workflow)
filename = wait_for_image(prompt_id)
if not filename:
print("生成に失敗しました。")
attempt += 1
continue
# ComfyUIの一時ディレクトリから画像パスを取得
temp_image_path = f"./comfyui_output_dir/{filename}" # ComfyUIの出力パスに合わせる
# Visionによる採点
score, feedback = evaluate_image_with_vlm(temp_image_path)
print(f"評価スコア: {score}/100 | フィードバック: {feedback}")
if score >= SCORE_THRESHOLD:
# 合格: 最終保存
final_path = os.path.join(OUTPUT_DIR, f"{base_filename}_selected.png")
# 実際にはファイルをコピー
print(f"🎉 合格!保存先: {final_path}")
return final_path
else:
print(f"❌ 不合格 (スコア {score} < {SCORE_THRESHOLD})")
if attempt < max_attempts:
# Inpaintによる部分修正を試みる
print("Inpaintによる修正プロセスを開始します...")
inpaint_workflow = load_and_modify_workflow(
inpaint_template_path,
prompt_text + ", high quality, face corrected",
seed + 100,
input_image_path=temp_image_path
)
inpaint_prompt_id = queue_prompt(inpaint_workflow)
filename = wait_for_image(inpaint_prompt_id)
temp_image_path = f"./comfyui_output_dir/{filename}"
# 再度採点
score, feedback = evaluate_image_with_vlm(temp_image_path)
if score >= SCORE_THRESHOLD:
final_path = os.path.join(OUTPUT_DIR, f"{base_filename}_selected.png")
print(f"🎉 Inpaint修正成功!保存先: {final_path}")
return final_path
attempt += 1
# すべて失敗した場合、最もマシなものを保存
final_path = os.path.join(OUTPUT_DIR, f"{base_filename}_rejected.png")
print(f"⚠️ 規定試行回数を超過。暫定版を保存: {final_path}")
return final_path
# 実行例
# generate_manga_panel(page=3, cut=2, prompt_text="1guy, action pose, manga style", template_path="workflow_api.json", inpaint_template_path="inpaint_api.json")
MCP (Model Context Protocol) を介することで、Claude 3.5 SonnetやCursor等のLLMエージェントから、ローカルのComfyUI環境を直接制御・デバッグすることが可能になります。
/api/prompt を叩くツール(Tools)を公開。ノンストップ量産パイプラインにおいて、アセット管理の破綻を防ぐための厳格な命名規則です。
| ファイル名構成 | 例 | 用途・意味 |
|---|---|---|
p{page:03d}_c{cut:02d}_selected.png |
p003_c02_selected.png |
採用稿: Vision採点をクリアした、最終レイアウト用画像。 |
p{page:03d}_c{cut:02d}_raw_v{version:02d}.png |
p003_c02_raw_01.png |
未選別/生成履歴: 評価前の生出力アセット。 |
p{page:03d}_c{cut:02d}_inpaint.png |
p003_c02_inpaint.png |
中間生成物: Inpaint修正が適用された段階の画像。 |
p{page:03d}_c{cut:02d}_rejected.png |
p003_c02_rejected.png |
不採用稿: 閾値に達しなかったが、バックアップとして残す画像。 |
| フェーズ | タスク内容 | 目標時間/目安 |
|---|---|---|
| 1. 環境準備 | ComfyUIを起動し、対象のワークフローから「Save (API Format)」でJSONをエクスポート。 | 15分 |
| 2. スクリプト統合 | 上記のPythonスクリプトをローカルに保存し、ノードID("3", "6" 等)をエクスポートしたJSONに合わせて修正。 |
30分 |
| 3. テスト実行 | 1コマ(例: p001_c01)を指定し、生成からVision採点、保存までのループがエラーなく完走するか確認。 | 10分 |
| 4. MCP連携 (発展) | ClaudeのMCP設定ファイル(claude_desktop_config.json)にComfyUI MCPサーバーを登録し、自然言語からの指示出しをテスト。 |
45分 |