diff --git a/.gitignore b/.gitignore index 7446045..388ab26 100644 --- a/.gitignore +++ b/.gitignore @@ -34,3 +34,5 @@ Thumbs.db # Cursor .cursorrules + +*.log diff --git a/README.md b/README.md index a40ad42..9c4c6a9 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ ComfyUI-OneAPI is a plugin that provides simple REST API interfaces for ComfyUI, curl -X POST "http://localhost:8188/oneapi/v1/execute" \ -H "Content-Type: application/json" \ -d '{ - "workflow": {...} # Replace with your workflow JSON + "workflow": {...} # Supports JSON object, local filename, or URL }' ``` @@ -20,7 +20,7 @@ curl -X POST "http://localhost:8188/oneapi/v1/execute" \ ```json { - "workflow": {...} // API version of workflow JSON + "workflow": {...} # Supports JSON object, local filename, or URL } ``` @@ -87,7 +87,7 @@ POST /oneapi/v1/execute Request Body: { - "workflow": {...}, // API version of workflow JSON + "workflow": {...}, // Supports JSON object, local filename, or URL "params": {...}, // Optional: Parameter mapping "wait_for_result": true/false, // Optional: Wait for results (default true) "timeout": 300 // Optional: Timeout in seconds @@ -119,7 +119,7 @@ Add markers to SaveImage node titles: curl -X POST "http://localhost:8188/oneapi/v1/execute" \ -H "Content-Type: application/json" \ -d '{ - "workflow": '"$(cat workflows/example_workflow.json)"', + "workflow": "$(cat workflows/example_workflow.json)", # Supports JSON object, local filename, or URL "params": { "prompt": "a cute dog with a red hat" } @@ -132,7 +132,7 @@ curl -X POST "http://localhost:8188/oneapi/v1/execute" \ curl -X POST "http://localhost:8188/oneapi/v1/execute" \ -H "Content-Type: application/json" \ -d '{ - "workflow": '"$(cat workflows/example_img2img_workflow.json)"', + "workflow": "$(cat workflows/example_img2img_workflow.json)", # Supports JSON object, local filename, or URL "params": { "prompt": "a cute dog with a red hat", "image": "https://example.com/input.jpg" @@ -144,4 +144,30 @@ curl -X POST "http://localhost:8188/oneapi/v1/execute" \ - 🔄 This plugin uses HTTP polling to get results, does not provide WebSocket real-time progress - ⏱️ Long-running workflows may cause request timeouts, consider setting appropriate timeout values -- 🏷️ Parameter mapping and output marking depend on special markers in node titles \ No newline at end of file +- 🏷️ Parameter mapping and output marking depend on special markers in node titles + +## /oneapi/v1/execute API - workflow parameter supports three forms + +### Supported forms for the workflow parameter + +- 1. Pass workflow as a JSON object (original logic). +- 2. Pass a local workflow filename (e.g. `1.json`), which will be loaded from `user/default/workflows/1.json`. +- 3. Pass a workflow URL (e.g. `http://xxx/1.json`), which will be downloaded and parsed automatically. + +How to distinguish: +- If workflow is a dict, use it directly. +- If workflow is a string starting with `http://` or `https://`, treat as URL and download. +- Otherwise, treat as a local filename and load from `user/default/workflows` directory. + +**Examples:** +```json +// 1. Pass JSON directly +{"workflow": {"node1": {...}, ...}} + +// 2. Pass local filename +// 1.json corresponds to /user/default/workflows/1.json +{"workflow": "1.json"} + +// 3. Pass URL +{"workflow": "https://example.com/1.json"} +``` \ No newline at end of file diff --git a/README_CN.md b/README_CN.md index 480954b..9126f56 100644 --- a/README_CN.md +++ b/README_CN.md @@ -12,7 +12,7 @@ ComfyUI-OneAPI 是一个为 ComfyUI 提供简单REST API接口的插件,只需 curl -X POST "http://localhost:8188/oneapi/v1/execute" \ -H "Content-Type: application/json" \ -d '{ - "workflow": {...} # 替换为您的工作流JSON + "workflow": {...} # 支持JSON对象、本地文件名或URL }' ``` @@ -87,7 +87,7 @@ POST /oneapi/v1/execute 请求体: { - "workflow": {...}, // 工作流的API版JSON + "workflow": {...}, // 支持JSON对象、本地文件名或URL "params": {...}, // 可选:参数映射 "wait_for_result": true/false, // 可选:是否等待结果(默认true) "timeout": 300 // 可选:超时时间(秒) @@ -119,7 +119,7 @@ POST /oneapi/v1/execute curl -X POST "http://localhost:8188/oneapi/v1/execute" \ -H "Content-Type: application/json" \ -d '{ - "workflow": '"$(cat workflows/example_workflow.json)"', + "workflow": "$(cat workflows/example_workflow.json)", # 支持JSON对象、本地文件名或URL "params": { "prompt": "a cute dog with a red hat" } @@ -132,7 +132,7 @@ curl -X POST "http://localhost:8188/oneapi/v1/execute" \ curl -X POST "http://localhost:8188/oneapi/v1/execute" \ -H "Content-Type: application/json" \ -d '{ - "workflow": '"$(cat workflows/example_img2img_workflow.json)"', + "workflow": "$(cat workflows/example_img2img_workflow.json)", # 支持JSON对象、本地文件名或URL "params": { "prompt": "a cute dog with a red hat", "image": "https://example.com/input.jpg" @@ -144,4 +144,30 @@ curl -X POST "http://localhost:8188/oneapi/v1/execute" \ - 🔄 此插件使用HTTP轮询获取结果,不提供WebSocket实时进度 - ⏱️ 长时间运行的工作流可能导致超时,请设置合适的timeout值 -- 🏷️ 参数映射和输出标记依赖于节点标题中的特殊标记 \ No newline at end of file +- 🏷️ 参数映射和输出标记依赖于节点标题中的特殊标记 + +## /oneapi/v1/execute 接口说明 + +### workflow 参数支持三种形式 + +- 1. 直接传递 workflow 的 JSON 对象(原有逻辑)。 +- 2. 传递本地 workflow 文件名(如 `1.json`),会自动从 `user/default/workflows/1.json` 读取。 +- 3. 传递 workflow 的 URL(如 `http://xxx/1.json`),会自动下载并解析。 + +区分方式: +- 如果 workflow 是 dict,则直接用。 +- 如果 workflow 是字符串且以 `http://` 或 `https://` 开头,则当作 URL 下载。 +- 否则当作本地文件名,从 `user/default/workflows` 目录加载。 + +**示例:** +```json +// 1. 直接传 JSON +{"workflow": {"node1": {...}, ...}} + +// 2. 传本地文件名 +// 1.json 对应的是 /user/default/workflows/1.json +{"workflow": "1.json"} + +// 3. 传 URL +{"workflow": "https://example.com/1.json"} +``` \ No newline at end of file diff --git a/oneapi.py b/oneapi.py index 8b4575e..69e7d61 100644 --- a/oneapi.py +++ b/oneapi.py @@ -15,13 +15,18 @@ import execution # Get routes routes = PromptServer.instance.routes +# Get workflow paths +path_custom_nodes = os.path.dirname(os.path.dirname(__file__)) +path_comfyui_root = os.path.dirname(path_custom_nodes) +path_workflows = os.path.join(path_comfyui_root, 'user/default/workflows') + @routes.post('/oneapi/v1/execute') async def execute_workflow(request): """ Execute workflow API Parameters: - - workflow: Workflow JSON + - workflow: Workflow JSON, filename (under user/default/workflows/), or URL - params: Parameter mapping dictionary - wait_for_result: Whether to wait for results (default True) - timeout: Timeout in seconds (default 300) @@ -50,6 +55,19 @@ async def execute_workflow(request): params = data.get('params', {}) wait_for_result = data.get('wait_for_result', True) timeout = data.get('timeout', None) + + # Support workflow as local path or URL + if isinstance(workflow, dict): + pass # Use directly + elif isinstance(workflow, str): + if workflow.startswith('http://') or workflow.startswith('https://'): + # URL, download + workflow = await _load_workflow_from_url(workflow) + else: + # Local filename + workflow = _load_workflow_from_local(workflow) + else: + return web.json_response({"error": "Invalid workflow parameter"}, status=400) if not workflow: return web.json_response({"error": "Workflow data is missing"}, status=400) @@ -476,4 +494,32 @@ async def _wait_for_results(prompt_id, timeout=None, request=None, output_id_2_v # Wait before checking again await asyncio.sleep(1.0) +# New: Load workflow from local file + +def _load_workflow_from_local(filename): + """ + Load workflow JSON from user/default/workflows directory + """ + file_path = os.path.join(path_workflows, filename) + if not os.path.isfile(file_path): + raise Exception(f"Workflow file not found: {file_path}") + with open(file_path, 'r', encoding='utf-8') as f: + return json.load(f) + +# New: Load workflow from URL + +async def _load_workflow_from_url(url): + """ + Download workflow JSON from URL + """ + async with aiohttp.ClientSession() as session: + async with session.get(url) as response: + if response.status != 200: + raise Exception(f"Failed to download workflow: HTTP {response.status}") + text = await response.text() + try: + return json.loads(text) + except Exception as e: + raise Exception(f"Invalid workflow JSON from url: {e}") + print("ComfyUI-OneAPI routes registered") \ No newline at end of file