"""BridgeInput/Output 스키마 자동 추출 및 검증.""" from typing import Any, Dict, List, Optional, Tuple BRIDGE_INPUT_PREFIX = "BridgeInput" BRIDGE_OUTPUT = "BridgeOutput" def extract_schema(workflow: dict) -> Dict[str, Any]: """ 워크플로우에서 BridgeInput/BridgeOutput 스키마를 추출한다. Returns: { "inputs": { "input_name": { "type": "STRING" | "INT" | "FLOAT" | "BOOLEAN" | "IMAGE" | ... "node_id": "1", "required": True, } }, "outputs": { "output_name": { "type": "IMAGE" | "STRING" | ... (from BridgeOutput) "node_id": "9", } } } """ inputs: Dict[str, Dict[str, Any]] = {} outputs: Dict[str, Dict[str, Any]] = {} for node_id, node in workflow.items(): if not isinstance(node, dict): continue class_type = node.get("class_type", "") node_inputs = node.get("inputs", {}) # BridgeInput 노드 if class_type.startswith(BRIDGE_INPUT_PREFIX): input_name = node_inputs.get("name") if input_name: type_name = class_type[len(BRIDGE_INPUT_PREFIX):] inputs[input_name] = { "type": type_name, "node_id": node_id, "required": True, } # BridgeOutput 노드 elif class_type == BRIDGE_OUTPUT: output_name = node_inputs.get("name") if output_name: outputs[output_name] = { "node_id": node_id, } return {"inputs": inputs, "outputs": outputs} def validate_inputs(schema: Dict[str, Any], inputs: Dict[str, Any]) -> Tuple[bool, List[str]]: """ 입력이 스키마와 일치하는지 검증한다. Returns: (is_valid, error_messages) """ errors = [] required_inputs = schema.get("inputs", {}) for name, spec in required_inputs.items(): if spec.get("required") and name not in inputs: errors.append(f"Required input '{name}' ({spec['type']}) not provided") for name in inputs: if name not in required_inputs: errors.append(f"Unknown input '{name}' (not found in workflow)") return len(errors) == 0, errors def describe_schema(schema: Dict[str, Any]) -> str: """스키마를 인간이 읽을 수 있는 형태로 반환한다.""" lines = ["Schema:"] inputs = schema.get("inputs", {}) if inputs: lines.append(" Inputs:") for name, spec in inputs.items(): required = " (required)" if spec.get("required") else " (optional)" lines.append(f" - {name}: {spec.get('type', 'UNKNOWN')}{required}") else: lines.append(" Inputs: (none)") outputs = schema.get("outputs", {}) if outputs: lines.append(" Outputs:") for name, spec in outputs.items(): lines.append(f" - {name}") else: lines.append(" Outputs: (none)") return "\n".join(lines)