Files
cbpark84-ComfyBridgeIO/client/workflow.py
T
cbpark84andClaude Sonnet 4.6 9a2bcdd4fa feat: initial project structure for ComfyBridgeIO
- ComfyUI custom nodes: BridgeInput (11 types) + BridgeOutput
- AnyType wildcard for universal output capture
- Custom server route: GET /comfybridge/results/{prompt_id}
- Python async client (ComfyBridge) + sync wrapper (ComfyBridgeSync)
- Workflow JSON parser and patcher (deepcopy, original unchanged)
- WebSocket completion detection
- BridgeResult container with PIL/bytes helpers
- Examples: basic_text_to_image.py, agent_loop.py
- Unit tests for workflow parser and client

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-16 10:45:26 +09:00

68 lines
2.1 KiB
Python

"""워크플로우 JSON 파서 및 BridgeInput 값 패처."""
import copy
import json
from pathlib import Path
from typing import Any
from .types import convert_value
BRIDGE_INPUT_PREFIX = "BridgeInput"
def load_workflow(source: str | dict | Path) -> dict:
"""워크플로우를 파일 경로 또는 dict로 로드한다."""
if isinstance(source, dict):
return source
path = Path(source)
with path.open("r", encoding="utf-8") as f:
return json.load(f)
def find_bridge_inputs(workflow: dict) -> dict[str, tuple[str, str]]:
"""
워크플로우에서 BridgeInput 노드를 탐색한다.
Returns:
{ "input_name": (node_id, type_name) }
예: { "prompt": ("1", "STRING"), "steps": ("3", "INT") }
"""
result: dict[str, tuple[str, str]] = {}
for node_id, node in workflow.items():
class_type = node.get("class_type", "")
if class_type.startswith(BRIDGE_INPUT_PREFIX):
name = node.get("inputs", {}).get("name")
type_name = class_type[len(BRIDGE_INPUT_PREFIX):]
if name:
result[name] = (node_id, type_name)
return result
def patch_inputs(workflow: dict, inputs: dict[str, Any]) -> dict:
"""
원본 워크플로우를 deepcopy 후 BridgeInput 노드의 value를 패치한다.
원본 파일은 절대 수정하지 않는다.
Args:
workflow: ComfyUI API 포맷 워크플로우 dict
inputs: { "name": value } 주입할 값 딕셔너리
Raises:
ValueError: 워크플로우에 해당 이름의 BridgeInput 노드가 없을 때
"""
patched = copy.deepcopy(workflow)
bridge_map = find_bridge_inputs(patched)
for name, value in inputs.items():
if name not in bridge_map:
available = list(bridge_map.keys())
raise ValueError(
f"BridgeInput '{name}' not found in workflow. "
f"Available inputs: {available}"
)
node_id, type_name = bridge_map[name]
converted = convert_value(value, type_name)
patched[node_id]["inputs"]["value"] = converted
return patched