Files
Van/攻城狮鹿鸣君 e233b0e89a make sample workflows teach portable integration
Treat prompts and source media as user-owned inputs, keep MediaHub credentials/config/execution in one reusable middle block, and reserve outputs for Preview/Save nodes.

Constraint: Samples must show users exactly which block to copy into an existing workflow.

Rejected: Classifying API Key and execution nodes as inputs or outputs | exposes internal mechanics and weakens sample readability.

Confidence: high

Scope-risk: narrow

Directive: Keep sample responsibilities separated and all connections flowing left to right.

Tested: 124 pytest tests; JavaScript syntax; Python compilation; JSON validation; live ComfyUI accepted all eight prompt structures.

Not-tested: Manual visual import of all eight revised examples.
2026-06-13 18:43:39 +08:00

79 lines
2.0 KiB
Python

#!/usr/bin/env python3
"""Apply the canonical three-region layout to user-facing workflows."""
import json
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
INPUT_X = 80
CONFIG_X = 620
EXECUTION_X = 1120
RESOLVE_X = 1500
OUTPUT_X = 1900
NODE_LAYOUT = {
"PrimitiveStringMultiline": (INPUT_X, 140, 420, 170),
"LoadImage": (INPUT_X, 390, 420, 320),
"MediaHubAPIKey": (CONFIG_X, 100, 340, 72),
"MediaHubGenerateImage": (EXECUTION_X, 260, 360, 130),
"MediaHubSubmitVideo": (EXECUTION_X, 300, 320, 130),
"MediaHubResolveVideo": (RESOLVE_X, 300, 320, 140),
"PreviewImage": (OUTPUT_X, 220, 460, 380),
"SaveVideo": (OUTPUT_X, 300, 420, 220),
}
GROUPS = [
{
"id": 1,
"title": "Inputs / 输入",
"bounding": [40, 40, 500, 780],
"color": "#3f789e",
"font_size": 24,
"flags": {},
},
{
"id": 2,
"title": "Provider Config / 配置",
"bounding": [580, 40, 1260, 780],
"color": "#9e7b3f",
"font_size": 24,
"flags": {},
},
{
"id": 3,
"title": "Outputs / 输出",
"bounding": [1860, 40, 540, 780],
"color": "#4b8a55",
"font_size": 24,
"flags": {},
},
]
def layout_workflow(path: Path) -> None:
workflow = json.loads(path.read_text())
for node in workflow["nodes"]:
node_type = node["type"]
if node_type.endswith("Config"):
node["pos"] = [CONFIG_X, 240]
node["size"] = [420, max(node["size"][1], 300)]
continue
if node_type in NODE_LAYOUT:
x, y, width, height = NODE_LAYOUT[node_type]
node["pos"] = [x, y]
node["size"] = [width, height]
workflow["groups"] = GROUPS
path.write_text(json.dumps(workflow, ensure_ascii=False, indent=2) + "\n")
def main() -> int:
for path in sorted((ROOT / "examples").glob("*_preview.json")):
layout_workflow(path)
return 0
if __name__ == "__main__":
raise SystemExit(main())