すべてのプロダクト
Search
ドキュメントセンター

Platform For AI:AI 動画生成:ComfyUI

最終更新日:Jul 29, 2026

ComfyUI は、Stable Diffusion をベースに構築されたノードベースの AIGC ツールで、短い動画やアニメーションの生成に使用されます。本記事では、Alibaba Cloud Elastic Algorithm Service (EAS) 上で ComfyUI をデプロイして使用する方法について説明します。

事前準備

重要な制限事項と考慮事項

リソースの無駄遣いを避け、一般的なエラーを防ぐために、デプロイ前に以下の制限事項をご確認ください。

  • デプロイリソース:GU30、A10、または T4 の GPU の使用を推奨します。インスタンスタイプ ml.gu7i.c16m60.1-gu30 は、コストパフォーマンスが非常に高いです。

    重要

    各 Elastic Algorithm Service (EAS) インスタンスは、1 つの ComfyUI プロセスのみを実行し、単一の GPU (マシンごとに 1 GPU) のみをサポートします。複数の GPU を使用した並列推論はサポートされていません。複数 GPU のインスタンスタイプ (例:2*A10) を選択しないでください。これはリソースの無駄遣いとなり、単一タスクのパフォーマンスを向上させません。

  • 水平スケーリング:並列処理能力を向上させるには、複数 GPU のインスタンスタイプを選択するのではなく、API 版 を使用して レプリカ数 を増やしてください。

  • ストレージの準備:カスタムモデルの使用、カスタムノードのインストール、または API 経由でのサービス呼び出しには、まず Object Storage Service (OSS) バケットまたは NAS ファイルシステムを作成する必要があります。詳細については、「Object Storage Service (OSS) クイックスタート」をご参照ください。

    EAS は、ComfyUI Manager や Git Clone などのツールを使用してインターネットから直接カスタムノード (プラグイン) をインストールすることをサポートしていません。すべてのカスタムコンテンツは、ストレージボリュームをマウントしてアップロードする必要があります。

デプロイエディション

ユースケースに最も適したエディションを選択してください:

エディション

シナリオ

呼び出しメソッド

特徴

課金

Standard Edition

単一ユーザーの開発とテスト

  • WebUI

  • API 呼び出し (同期、オンラインデバッグをサポート)

  • 限定的な同時実行数

  • 単一インスタンスをデプロイ

パブリックリソースでのデプロイの場合、使用量に関わらず、インスタンスがプロビジョニングされた瞬間から時間単位で課金されます。

API 版

高同時実行数の本番環境

API 呼び出し (非同期)

  • EAS キューサービス上に構築

  • 追加の CPU リソースが必要

  • 負荷分散をサポート

WebUI 用クラスター版

複数ユーザーのチームおよび教育目的

WebUI

  • ユーザー環境の隔離

  • 共有 GPU リソース

  • 高いリソース消費

動作原理の詳細については、「クラスター版サービスの概要」をご参照ください。

課金の詳細については、「Elastic Algorithm Service (EAS) の課金」をご参照ください。

説明

API 呼び出しが同期か非同期かは、EAS キューサービスを使用するかどうかによって決まります:

  • 同期呼び出し:EAS キューサービスをバイパスし、リクエストを直接推論インスタンスに送信します。

  • 非同期呼び出し:EAS キューサービスを使用します。リクエストは入力キューに送信され、結果はサブスクリプションを介してプッシュされます。

ComfyUI には独自の非同期キューイングシステムがあるため、同期呼び出しでも実質的には非同期です。リクエストを送信すると、システムはプロンプト ID を返します。その後、このプロンプト ID を使用してポーリングし、推論結果を取得する必要があります。

サービスのデプロイ

Standard、Cluster、API 版:シナリオベースのモデルデプロイ (より簡単) またはカスタムモデルデプロイ (より多くの機能) を使用できます。

シナリオモデル

  1. PAI コンソールにログインします。ページ上部でリージョンを選択し、目的のワークスペースを選択して Elastic Algorithm Service (EAS) をクリックします。

  2. Elastic Algorithm Service (EAS) ページで、モデルサービスの作成 をクリックします。シナリオベースのモデルデプロイ セクションで、AI 動画生成 - ComfyUI デプロイメント をクリックします。

  3. 以下の主要なパラメーターを設定します:

    • バージョンの選択:詳細については、「デプロイバージョンの選択」をご参照ください。

    • モデルの構成:独自のモデルを使用したり、カスタムノードをインストールしたり、API 呼び出しを行ったりする必要がある場合に、このパラメーターを設定します。例えば、Object Storage Service (OSS) を使用する場合、バケットとディレクトリを選択します。サービスのデプロイ後、システムは選択した場所に必須の ComfyUI ディレクトリを自動的に作成します。

    • リソース設定の選択:GPU インスタンスタイプを選択します。GU30、A10、または T4 の GPU の使用を推奨します。インスタンスタイプ ml.gu7i.c16m60.1-gu30 は、コストパフォーマンスが非常に高いです。利用できない場合は、ecs.gn6i-c16g1.4xlarge を選択できます。

  4. デプロイメント をクリックします。約 5 分待ちます。モデルのステータス実行中 に変わると、デプロイは完了です。

カスタムモデル

  1. PAI コンソールにログインします。ページ上部でリージョンを選択し、目的のワークスペースを選択して Elastic Algorithm Service (EAS) をクリックします。

  2. [サービスのデプロイ] をクリックします。[カスタムモデルのデプロイ] セクションで、[カスタムデプロイ] をクリックします。

  3. 以下の主要なパラメーターを設定します:

    • デプロイメント方式イメージデプロイメント を選択し、Web アプリケーションを有効にする チェックボックスをオンにします。

    • イメージ設定: Alibaba Cloud イメージ リストから、comfyui:1.9 を選択します。このフォーマットでは、x.x は標準版、x.x-api は API 版、x.x-cluster はクラスター版をそれぞれ示します。

      説明
      • バージョンは頻繁に更新されるため、最新のイメージバージョンを選択することを推奨します。

      • 各バージョンのユースケースの詳細については、「デプロイバージョンの選択」をご参照ください。

    • ストレージのマウント:独自のモデルを使用したり、カスタムノードをインストールしたり、API 呼び出しを行ったりする必要がある場合は、ストレージマウントを設定します。例えば、Object Storage Service (OSS) を使用する場合、バケットとディレクトリを選択します。サービスのデプロイ後、システムは選択した場所に必須の ComfyUI ディレクトリを自動的に作成します。ストレージスペースが EAS サービスと同じリージョンにあることを確認してください。

      • Uriimage をクリックして既存の OSS ストレージディレクトリを選択します。例:oss://bucket-test/data-oss/

      • マウントパス:このパラメーターを /mnt/data に設定します。これにより、指定した OSS ディレクトリがコンテナパス /mnt/data にマウントされます。

    • コマンドの実行

      • イメージバージョンを選択すると、システムが自動的に起動コマンドを入力します。

      • ストレージマウントを設定した場合、コマンドの実行--data-dir パラメーターを追加し、その値が マウントパス と一致することを確認する必要があります。例:python main.py --listen --port 8000 --data-dir /mnt/data --cache-root /stable-diffusion-cache

    • リソースタイプパブリックリソース を選択します。

    • リソースのデプロイメント:GPU インスタンスタイプを選択します。GU30、A10、または T4 の GPU の使用を推奨します。インスタンスタイプ ml.gu7i.c16m60.1-gu30 は、コストパフォーマンスが非常に高いです。利用できない場合は、ecs.gn6i-c16g1.4xlarge を選択できます。

  4. デプロイメント をクリックします。デプロイには約 5 分かかります。モデルのステータス実行中 に変わると、デプロイは完了です。

Web UI の使用

重要

Standard Edition とクラスター版は、Web UI 経由でのアクセスを提供します。

Web UI へのアクセス

対象のサービス名をクリックして 概要 ページに移動し、右上隅の Web アプリケーションの表示 をクリックします。

ページの読み込みが遅い、または応答しなくなった場合は、「ページの更新に時間がかかりすぎる、または応答しなくなる」をご参照ください。

テンプレートワークフローの使用

ComfyUI は、一般的なタスクのためのテンプレートを提供しています。

  1. [Wan VACE text-to-video] などのテンプレートを選択します。

    説明

    テンプレートは ComfyUI のイメージバージョンによって異なる場合があります。サンプルのテンプレートが利用できない場合は、別のテンプレートを使用できます。ローカルファイルシステムからワークフローをロードすることもできます。

image

  1. ワークフローが正常にロードされた後、モデルが見つからないというエラーは無視できます。「このメッセージを再度表示しない」チェックボックスを選択することを推奨します。

  2. パスの変更により、ワークフローを直接実行すると以下のエラーが発生する可能性があります。

    image.png

    まず、[Load models here] セクションで、モデル wan2.1_vace_14B_fp16.safetensorsWan21_CausVid_14B_T2V_lora_rank32.safetensors を再選択します。

    image

  3. ワークフローが正常に実行されると、生成された動画が [Save Video] セクションに表示されます。image

カスタムモデルとノードの使用

  1. サービスにストレージボリュームが設定されていることを確認します。カスタムデプロイを使用する場合、コマンドの実行--data-dir パラメーターを追加してディレクトリをマウントする必要があります。詳細については、「方法 2:カスタムモデルのデプロイ」をご参照ください。

    サービスのデプロイ後、システムはマウントされた OSS または NAS ストレージに以下のディレクトリ構造を自動的に作成します。

    data-oss/
    ├── custom_nodes/     # ノードファイル (ComfyUI プラグイン) を格納
    ├── models/           # モデルファイルを格納
    ├── input/
    ├── output/
    ├── unet/
    └── temp/
  2. モデルまたはノードファイルをアップロードします。例えば、OSS の場合、コンソールで OSS にファイルをアップロードできます。ラージオブジェクトについては、「OSS にラージオブジェクトをアップロードするにはどうすればよいですか?」をご参照ください。

    • モデルファイルのアップロード:ノードのソースリポジトリの指示に従い、models ディレクトリ以下の対応するサブディレクトリにモデルをアップロードします。例:

      • チェックポイントローダー:モデルを models/checkpoints にアップロードします。

      • スタイルモデルローダー:モデルを models/styles にアップロードします。

    • ノードファイルのアップロード:カスタムノードをマウントされたストレージボリューム上の custom_nodes ディレクトリにアップロードすることを推奨します。

  3. 新しいコンテンツをロードします。

    • モデル[PaiCustom] > [Load New Models] をクリックします。それでもモデルが見つからない場合は、[Restart Process] をクリックします。プロセスが正常に再起動した後、ブラウザページをリフレッシュします。

    • ノード[Restart Process] をクリックします。プロセスが正常に再起動した後、ブラウザページをリフレッシュします。

ワークフローのエクスポート

Web UI でワークフローをデバッグした後、API 呼び出しで使用するために JSON ファイルとして保存します。

image

API 呼び出し

API 呼び出しの概要

API 呼び出しをサービスに対して行うことで、ComfyUI をアプリケーションに統合し、AIGC コンテンツの生成を自動化できます。コアプロセスは、ワークフローの JSON 設定を送信し、タスク ID を受け取り、その ID を使用して生成された結果を取得することです。

重要

Standard Edition サービスは同期呼び出しのみをサポートし、オンラインデバッグを提供します。

API 版サービスは非同期呼び出しのみをサポートし、api_prompt パス経由でのみ利用可能です。

前提条件:ComfyUI API 呼び出しのリクエストボディは、ワークフローに依存します。まず、WebUI でワークフローを設定し、ワークフローを JSON ファイルとしてエクスポートします。

結果のダウンロード:生成された画像や動画は、マウントされた output ディレクトリに保存されます。API 呼び出しはファイル名とサブディレクトリ名を返します。OSS の場合、ファイルをダウンロードするには完全なファイルパスを構築する必要があります。詳細については、「Alibaba Cloud SDK を使用して OSS からファイルをダウンロードする」をご参照ください。

API リクエストボディ

リクエストボディの形式は、呼び出しメソッドによって異なります:

  • 同期呼び出しの場合、リクエストボディはワークフローの JSON コンテンツを prompt キー内にラップする必要があります。

  • 非同期呼び出しの場合、リクエストボディはワークフローの JSON コンテンツそのものです。

Wan VACE Text to Video ワークフローは時間がかかるため、このセクションではテスト用のサンプルワークフローを提供します。実行には約 3 分かかります。

リクエストボディのサンプル

同期呼び出し

{
    "prompt": {
        "3": {
            "inputs": {
                "seed": 423988542100860,
                "steps": 40,
                "cfg": 7,
                "sampler_name": "dpmpp_sde_gpu",
                "scheduler": "karras",
                "denoise": 1,
                "model": [
                    "4",
                    0
                ],
                "positive": [
                    "6",
                    0
                ],
                "negative": [
                    "7",
                    0
                ],
                "latent_image": [
                    "5",
                    0
                ]
            },
            "class_type": "KSampler",
            "_meta": {
                "title": "K Sampler"
            }
        },
        "4": {
            "inputs": {
                "ckpt_name": "LandscapeBING_v10.safetensors"
            },
            "class_type": "CheckpointLoaderSimple",
            "_meta": {
                "title": "Checkpoint Loader (Simple)"
            }
        },
        "5": {
            "inputs": {
                "width": 720,
                "height": 1280,
                "batch_size": 1
            },
            "class_type": "EmptyLatentImage",
            "_meta": {
                "title": "Empty Latent"
            }
        },
        "6": {
            "inputs": {
                "text": "Rocket takes off from the ground, fire, sky, airplane",
                "speak_and_recognation": {
                    "__value__": [
                        false,
                        true
                    ]
                },
                "clip": [
                    "4",
                    1
                ]
            },
            "class_type": "CLIPTextEncode",
            "_meta": {
                "title": "CLIP Text Encoder"
            }
        },
        "7": {
            "inputs": {
                "text": "",
                "speak_and_recognation": {
                    "__value__": [
                        false,
                        true
                    ]
                },
                "clip": [
                    "4",
                    1
                ]
            },
            "class_type": "CLIPTextEncode",
            "_meta": {
                "title": "CLIP Text Encoder"
            }
        },
        "8": {
            "inputs": {
                "samples": [
                    "3",
                    0
                ],
                "vae": [
                    "4",
                    2
                ]
            },
            "class_type": "VAEDecode",
            "_meta": {
                "title": "VAE Decode"
            }
        },
        "9": {
            "inputs": {
                "filename_prefix": "ComfyUI",
                "images": [
                    "8",
                    0
                ]
            },
            "class_type": "SaveImage",
            "_meta": {
                "title": "Save Image"
            }
        },
        "13": {
            "inputs": {
                "seed": 788620942678235,
                "steps": 40,
                "cfg": 2.5,
                "sampler_name": "euler_ancestral",
                "scheduler": "karras",
                "denoise": 1,
                "model": [
                    "17",
                    0
                ],
                "positive": [
                    "16",
                    0
                ],
                "negative": [
                    "16",
                    1
                ],
                "latent_image": [
                    "16",
                    2
                ]
            },
            "class_type": "KSampler",
            "_meta": {
                "title": "K Sampler"
            }
        },
        "14": {
            "inputs": {
                "samples": [
                    "13",
                    0
                ],
                "vae": [
                    "18",
                    2
                ]
            },
            "class_type": "VAEDecode",
            "_meta": {
                "title": "VAE Decode"
            }
        },
        "15": {
            "inputs": {
                "filename_prefix": "ComfyUI",
                "fps": 10.000000000000002,
                "lossless": false,
                "quality": 85,
                "method": "default",
                "images": [
                    "14",
                    0
                ]
            },
            "class_type": "SaveAnimatedWEBP",
            "_meta": {
                "title": "Save WEBP"
            }
        },
        "16": {
            "inputs": {
                "width": 512,
                "height": 768,
                "video_frames": 35,
                "motion_bucket_id": 140,
                "fps": 15,
                "augmentation_level": 0.15000000000000002,
                "clip_vision": [
                    "18",
                    1
                ],
                "init_image": [
                    "8",
                    0
                ],
                "vae": [
                    "18",
                    2
                ]
            },
            "class_type": "SVD_img2vid_Conditioning",
            "_meta": {
                "title": "SVD Image to Video Conditioning"
            }
        },
        "17": {
            "inputs": {
                "min_cfg": 1,
                "model": [
                    "18",
                    0
                ]
            },
            "class_type": "VideoLinearCFGGuidance",
            "_meta": {
                "title": "Linear CFG Guidance"
            }
        },
        "18": {
            "inputs": {
                "ckpt_name": "svd_xt.safetensors"
            },
            "class_type": "ImageOnlyCheckpointLoader",
            "_meta": {
                "title": "Checkpoint Loader (Image Only)"
            }
        },
        "19": {
            "inputs": {
                "frame_rate": 10,
                "loop_count": 0,
                "filename_prefix": "comfyUI",
                "format": "video/h264-mp4",
                "pix_fmt": "yuv420p",
                "crf": 20,
                "save_metadata": true,
                "trim_to_audio": false,
                "pingpong": false,
                "save_output": true,
                "images": [
                    "14",
                    0
                ]
            },
            "class_type": "VHS_VideoCombine",
            "_meta": {
                "title": "Combine to Video"
            }
        }
    }
}

非同期呼び出し

{
    "3": {
        "inputs": {
            "seed": 423988542100860,
            "steps": 40,
            "cfg": 7,
            "sampler_name": "dpmpp_sde_gpu",
            "scheduler": "karras",
            "denoise": 1,
            "model": [
                "4",
                0
            ],
            "positive": [
                "6",
                0
            ],
            "negative": [
                "7",
                0
            ],
            "latent_image": [
                "5",
                0
            ]
        },
        "class_type": "KSampler",
        "_meta": {
            "title": "K Sampler"
        }
    },
    "4": {
        "inputs": {
            "ckpt_name": "LandscapeBING_v10.safetensors"
        },
        "class_type": "CheckpointLoaderSimple",
        "_meta": {
            "title": "Checkpoint Loader (Simple)"
        }
    },
    "5": {
        "inputs": {
            "width": 720,
            "height": 1280,
            "batch_size": 1
        },
        "class_type": "EmptyLatentImage",
        "_meta": {
            "title": "Empty Latent"
        }
    },
    "6": {
        "inputs": {
            "text": "Rocket takes off from the ground, fire, sky, airplane",
            "speak_and_recognation": {
                "__value__": [
                    false,
                    true
                ]
            },
            "clip": [
                "4",
                1
            ]
        },
        "class_type": "CLIPTextEncode",
        "_meta": {
            "title": "CLIP Text Encoder"
        }
    },
    "7": {
        "inputs": {
            "text": "",
            "speak_and_recognation": {
                "__value__": [
                    false,
                    true
                ]
            },
            "clip": [
                "4",
                1
            ]
        },
        "class_type": "CLIPTextEncode",
        "_meta": {
            "title": "CLIP Text Encoder"
        }
    },
    "8": {
        "inputs": {
            "samples": [
                "3",
                0
            ],
            "vae": [
                "4",
                2
            ]
        },
        "class_type": "VAEDecode",
        "_meta": {
            "title": "VAE Decode"
        }
    },
    "9": {
        "inputs": {
            "filename_prefix": "ComfyUI",
            "images": [
                "8",
                0
            ]
        },
        "class_type": "SaveImage",
        "_meta": {
            "title": "Save Image"
        }
    },
    "13": {
        "inputs": {
            "seed": 788620942678235,
            "steps": 40,
            "cfg": 2.5,
            "sampler_name": "euler_ancestral",
            "scheduler": "karras",
            "denoise": 1,
            "model": [
                "17",
                0
            ],
            "positive": [
                "16",
                0
            ],
            "negative": [
                "16",
                1
            ],
            "latent_image": [
                "16",
                2
            ]
        },
        "class_type": "KSampler",
        "_meta": {
            "title": "K Sampler"
        }
    },
    "14": {
        "inputs": {
            "samples": [
                "13",
                0
            ],
            "vae": [
                "18",
                2
            ]
        },
        "class_type": "VAEDecode",
        "_meta": {
            "title": "VAE Decode"
        }
    },
    "15": {
        "inputs": {
            "filename_prefix": "ComfyUI",
            "fps": 10.000000000000002,
            "lossless": false,
            "quality": 85,
            "method": "default",
            "images": [
                "14",
                0
            ]
        },
        "class_type": "SaveAnimatedWEBP",
        "_meta": {
            "title": "Save WEBP"
        }
    },
    "16": {
        "inputs": {
            "width": 512,
            "height": 768,
            "video_frames": 35,
            "motion_bucket_id": 140,
            "fps": 15,
            "augmentation_level": 0.15000000000000002,
            "clip_vision": [
                "18",
                1
            ],
            "init_image": [
                "8",
                0
            ],
            "vae": [
                "18",
                2
            ]
        },
        "class_type": "SVD_img2vid_Conditioning",
        "_meta": {
            "title": "SVD Image to Video Conditioning"
        }
    },
    "17": {
        "inputs": {
            "min_cfg": 1,
            "model": [
                "18",
                0
            ]
        },
        "class_type": "VideoLinearCFGGuidance",
        "_meta": {
            "title": "Linear CFG Guidance"
        }
    },
    "18": {
        "inputs": {
            "ckpt_name": "svd_xt.safetensors"
        },
        "class_type": "ImageOnlyCheckpointLoader",
        "_meta": {
            "title": "Checkpoint Loader (Image Only)"
        }
    },
    "19": {
        "inputs": {
            "frame_rate": 10,
            "loop_count": 0,
            "filename_prefix": "comfyUI",
            "format": "video/h264-mp4",
            "pix_fmt": "yuv420p",
            "crf": 20,
            "save_metadata": true,
            "trim_to_audio": false,
            "pingpong": false,
            "save_output": true,
            "images": [
                "14",
                0
            ]
        },
        "class_type": "VHS_VideoCombine",
        "_meta": {
            "title": "Combine to Video"
        }
    }
}

同期呼び出し

同期呼び出しは、リクエストを直接 Elastic Algorithm Service (EAS) インスタンスに送信します。この方法は、開発、テスト、および低同時実行数のシナリオに適しています。

オンラインデバッグ

オンラインデバッグ機能を使用すると、コードを書かずにコンソールから直接 API 呼び出しをテストできます。ワークフロー設定の迅速な検証や問題のトラブルシューティングに最適です。

Elastic Algorithm Service (EAS) ページで、対象サービスの 操作 列にある オンラインデバッグ をクリックして、オンラインデバッグページに移動します。

  1. POST リクエストを送信してプロンプト ID を取得します。

    1. オンラインデバッグのリクエストパラメーター セクションの [ボディ] フィールドに準備したリクエストボディを入力し、リクエスト URL テキストボックスに /prompt を追加します。image

    2. リクエストの送信 をクリックして、デバッグ情報 エリアで応答を確認します。応答のサンプルを以下に示します。image

  2. プロンプト ID を使用して GET リクエストを送信し、推論結果を取得します。

    1. オンラインデバッグのリクエストパラメーター セクションで、リクエストメソッドを GET に設定し、テキストボックスに /history/<prompt id> を入力します。以下の図は例です。image

      ステップ 1 で取得したプロンプト ID で <prompt id> を置き換えます。

    2. リクエストの送信 をクリックして推論結果を取得します。

      生成された推論結果は、マウントされたストレージの output ディレクトリで確認できます。

コードによる呼び出し

コードから API 呼び出しを行って、ComfyUI をアプリケーションに統合することもできます。プロセスはオンラインデバッグと同じです:まずプロンプト ID を取得し、次に推論結果をクエリします。

  1. 呼び出し情報を表示します。

    1. オンライン推論サービス タブで、対象のサービス名をクリックして 概要 ページに移動します。

    2. 基本情報 セクションで、エンドポイント情報の表示 をクリックします。

    3. 呼び出し情報 パネルで、エンドポイントとトークンをコピーします:

      • 必要に応じて、インターネットエンドポイントまたは VPC エンドポイントを選択します。

      • 以下の例では、エンドポイントのプレースホルダーとして <EAS_ENDPOINT> を、トークンのプレースホルダーとして <EAS_TOKEN> を使用します。

      エンドポイント情報の表示 をクリックしてパネルを開きます。パネルには [共有ゲートウェイ][VPC 高速ダイレクト接続] の 2 つのタブがあります。パブリックネットワークアドレス、VPC アドレス、およびトークンは [共有ゲートウェイ] タブにあります。

  2. リクエストを送信してプロンプト ID を取得します。

    • HTTP メソッド:POST。

    • リクエストパス (URL)<EAS_ENDPOINT>/prompt<EAS_ENDPOINT> がスラッシュ (/) で終わる場合は、それを取り除きます。最終的な URL は http://comfyui****.175805416243****.cn-beijing.pai-eas.aliyuncs.com/prompt のようになります。

    • リクエストヘッダー

      ヘッダー

      説明

      Authorization

      <EAS_TOKEN>

      権限付与キー。

      Content-Type

      application/json

      リクエストボディのフォーマットを指定します。

    サンプルコード:

    cURL

    curl --location --request POST '<EAS_ENDPOINT>/prompt' \
    --header 'Authorization: <EAS_TOKEN>' \
    --header 'Content-Type: application/json' \
    --data-raw '{
        "prompt":
        ...省略
    }'

    ここで、--data-raw はリクエストボディです。

    Python

    以下はサンプルコードスニペットです:

    import requests
    import json
    
    # <EAS_ENDPOINT> と <EAS_TOKEN> をステップ 1 のエンドポイントとトークンに置き換えます。
    service_url = "<EAS_ENDPOINT>"
    token = "<EAS_TOKEN>"
    
    if service_url.endswith("/"):
        service_url = service_url[:-1]
    
    # リクエストボディ。ペイロードの 'prompt' キーの値をワークフロー JSON ファイルの内容に設定します。
    payload = """{
        "prompt":
        ...省略
    }"""
    payload = json.loads(payload)
    
    session = requests.session()
    session.headers.update({"Authorization": token})
      
    response = session.post(url=f'{service_url}/prompt', json=payload)
    if response.status_code != 200:
        raise Exception(response.content)
    
    data = response.json()
    print(data)

    以下は応答のサンプルです:

    {
        "prompt_id": "021ebc5b-e245-4e37-8bd3-00f7b949****",
        "number": 5,
        "node_errors": {}
    }

    応答からプロンプト ID を取得します。

  3. 推論結果を取得します。

    • HTTP リクエストメソッドGET

    • リクエスト URL<EAS_ENDPOINT>/history/<prompt_id><prompt_id> をステップ 1 で取得した prompt_id に置き換えます。

    • リクエストヘッダー

      ヘッダー

      説明

      Authorization

      <EAS_TOKEN>

      ステップ 1 の権限付与キー。

    サンプルコード:

    cURL

    curl --location --request GET '<EAS_ENDPOINT>/history/<prompt_id>' \
         --header 'Authorization: <EAS_TOKEN>'

    Python

    import requests
    
    # <EAS_ENDPOINT> と <EAS_TOKEN> をステップ 1 のエンドポイントとトークンに置き換えます。
    # <prompt_id> をステップ 2 のプロンプト ID に置き換えます。
    service_url = "<EAS_ENDPOINT>"
    token = "<EAS_TOKEN>"
    prompt_id = "<prompt_id>"
    
    if service_url.endswith("/"):
        service_url = service_url[:-1]
    
    session = requests.session()
    session.headers.update({"Authorization": token})
    
    response = session.get(url=f'{service_url}/history/{prompt_id}')
    
    if response.status_code != 200:
        raise Exception(response.content)
    
    data = response.json()
    print(data)

    以下は応答のサンプルです:

    応答のサンプル

    {
        "130bcd6b-5bb5-496c-9c8c-3a1359a0****": {
            "prompt": ...省略,
            "outputs": {
                "9": {
                    "images": [
                        {
                            "filename": "ComfyUI_1712645398_18dba34d-df87-4735-a577-c63d5506a6a1_.png",
                            "subfolder": "",
                            "type": "output"
                        }
                    ]
                },
                "15": {
                    "images": [
                        {
                            "filename": "ComfyUI_1712645867_.webp",
                            "subfolder": "",
                            "type": "output"
                        }
                    ],
                    "animated": [
                        true
                    ]
                },
                "19": {
                    "gifs": [
                        {
                            "filename": "comfyUI_00002.mp4",
                            "subfolder": "",
                            "type": "output",
                            "format": "video/h264-mp4"
                        }
                    ]
                }
            },
            "status": {
                "status_str": "success",
                "completed": true,
                "messages": ...省略
            }
        }
    }

    この例で返された outputs には、プロンプトから生成された画像、WebP ファイル、MP4 動画が含まれています。これらのファイルは、マウントされたストレージの output ディレクトリで名前によって見つけることができます。

非同期呼び出し

非同期呼び出しは、高同時実行数の本番環境に適しています。負荷分散のために EAS キューサービスを使用します。リクエストは送信後すぐに返され、結果キューをサブスクライブすることで結果を取得します。

重要

非同期呼び出しは api_prompt パスのみをサポートします。task_id パラメーターは、リクエストと結果を関連付けるために重要です。各リクエストの task_id に一意の値を割り当てて、キューからの対応する結果と一致させる必要があります。リクエストパスは次のとおりです:

{service_url}/api_prompt?task_id={your_unique_value}

  1. 呼び出し情報を表示します。

    オンライン推論サービス タブで、対象のサービス名をクリックして 概要 ページを開きます。基本情報 セクションで、エンドポイント情報の表示 をクリックします。呼び出し情報 ダイアログボックスの 非同期呼び出し タブで、サービスのエンドポイントとトークンを表示できます。

    このドキュメントでは、<EAS_ENDPOINT> は インターネット 呼び出しアドレス (またはクライアントと EAS が同じ VPC にある場合は VCP 呼び出しアドレス) を指し、<EAS_TOKEN> は トークン を指します。

  2. リクエストを送信します。

    以下はサンプルコードスニペットです:

    import requests
    import json
    
    service_url = "<EAS_ENDPOINT>"
    token = "<EAS_TOKEN>"
    
    if service_url.endswith("/"):
        service_url = service_url[:-1]
    
    session = requests.session()
    session.headers.update({"Authorization":token})
    
    # ペイロードは有効な JSON である必要があります。キーと文字列の値は二重引用符 ("") を使用する必要があります。
    payload = """{
        '3': 
        ...省略
      }
      """
    payload = json.loads(payload)
    
    for i in range(5):
      # 'task_id' パラメーターはリクエストと結果を一致させるために重要です。各リクエストに一意の ID を割り当てます。
      response = session.post(url=f'{service_url}/api_prompt?task_id=txt2img_{i}', json=payload)
      if response.status_code != 200:
        exit(f"send request error:{response.content}")
      else:
        print(f"send {i} success, index is {response.content}")
  3. 結果をサブスクライブします。

    1. eas_prediction SDK をインストールします。

      pip install eas_prediction --user
    2. 以下のコードを実行して結果を取得します。

      from eas_prediction import QueueClient
      from urllib.parse import urlparse, urlunparse
      
      service_url     = "<EAS_ENDPOINT>"
      token           = "<EAS_TOKEN>"
      
      # サービス URL を解析する
      def parse_service_url(service_url):
          parsed = urlparse(service_url)
          service_domain = f"{parsed.scheme}://{parsed.netloc}"
          path_parts = [p for p in parsed.path.strip('/').split('/') if p]
          service_name = path_parts[-1]
          return service_domain, service_name
      
      service_domain, service_name = parse_service_url(service_url)
      print(f"service_domain: {service_domain}, service_name: {service_name}.")
         
      # 結果キュークライアントを作成する
      sink_queue = QueueClient(service_domain, f'{service_name}/sink')
      sink_queue.set_token(token)
      sink_queue.init()
      
      # 結果をリッスンする
      watcher = sink_queue.watch(0, 5, auto_commit=False)
      for x in watcher.run():
          if 'task_id' in x.tags:
              print('index {} task_id is {}'.format(x.index, x.tags['task_id']))
          print(f'index {x.index} data is {x.data}')
          # 受信を確認するためにコミットする
          sink_queue.commit(x.index)

      以下は応答のサンプルです:

      index 42 task_id is txt2img_0
      index 42 data is b'[{"type": "executed", "data": {"node": "9", "output": {"images": [{"filename": "ComfyUI_1712647318_8e7f3c93-d2a8-4377-92d5-8eb552adc172_.png", "subfolder": "", "type": "output"}]}, "prompt_id": "c3c983b6-f92b-4dd5-b4dc-442db4d1736f"}}, {"type": "executed", "data": {"node": "15", "output": {"images": [{"filename": "ComfyUI_1712647895_.webp", "subfolder": "", "type": "output"}], "animated": [true]}, "prompt_id": "c3c983b6-f92b-4dd5-b4dc-442db4d1736f"}}, {"type": "executed", "data": {"node": "19", "output": {"gifs": [{"filename": "comfyUI_00001.mp4", "subfolder": "", "type": "output", "format": "video/h264-mp4"}]}, "prompt_id": "c3c983b6-f92b-4dd5-b4dc-442db4d1736f"}}, {"9": {"images": [{"filename": "ComfyUI_1712647318_8e7f3c93-d2a8-4377-92d5-8eb552adc172_.png", "subfolder": "", "type": "output"}]}, "15": {"images": [{"filename": "ComfyUI_1712647895_.webp", "subfolder": "", "type": "output"}], "animated": [true]}, "19": {"gifs": [{"filename": "comfyUI_00001.mp4", "subfolder": "", "type": "output", "format": "video/h264-mp4"}]}}]'
      index 43 task_id is txt2img_1
      index 43 data is b'[{"9": {"images": [{"filename": "ComfyUI_1712647318_8e7f3c93-d2a8-4377-92d5-8eb552adc172_.png", "subfolder": "", "type": "output"}]}, "15": {"images": [{"filename": "ComfyUI_1712647895_.webp", "subfolder": "", "type": "output"}], "animated": [true]}, "19": {"gifs": [{"filename": "comfyUI_00001.mp4", "subfolder": "", "type": "output", "format": "video/h264-mp4"}]}}]'
      index 44 task_id is txt2img_2
      index 44 data is b'[{"9": {"images": [{"filename": "ComfyUI_1712647318_8e7f3c93-d2a8-4377-92d5-8eb552adc172_.png", "subfolder": "", "type": "output"}]}, "15": {"images": [{"filename": "ComfyUI_1712647895_.webp", "subfolder": "", "type": "output"}], "animated": [true]}, "19": {"gifs": [{"filename": "comfyUI_00001.mp4", "subfolder": "", "type": "output", "format": "video/h264-mp4"}]}}]'
      index 45 task_id is txt2img_3
      index 45 data is b'[{"9": {"images": [{"filename": "ComfyUI_1712647318_8e7f3c93-d2a8-4377-92d5-8eb552adc172_.png", "subfolder": "", "type": "output"}]}, "15": {"images": [{"filename": "ComfyUI_1712647895_.webp", "subfolder": "", "type": "output"}], "animated": [true]}, "19": {"gifs": [{"filename": "comfyUI_00001.mp4", "subfolder": "", "type": "output", "format": "video/h264-mp4"}]}}]'
      index 46 task_id is txt2img_4
      index 46 data is b'[{"9": {"images": [{"filename": "ComfyUI_1712647318_8e7f3c93-d2a8-4377-92d5-8eb552adc172_.png", "subfolder": "", "type": "output"}]}, "15": {"images": [{"filename": "ComfyUI_1712647895_.webp", "subfolder": "", "type": "output"}], "animated": [true]}, "19": {"gifs": [{"filename": "comfyUI_00001.mp4", "subfolder": "", "type": "output", "format": "video/h264-mp4"}]}}]'

      推論結果ファイルは、マウントされたストレージの output ディレクトリで確認できます。

よくある質問

このセクションでは、ComfyUI のデプロイと使用に関する一般的な問題をカテゴリ別に説明します。

デプロイの問題

Q:サービスが「待機中」の状態でスタックしたり、画像を生成できないのはなぜですか?

この問題は通常、リソース仕様が不十分なために発生します。サービスイメージとリソース仕様が正しく設定されていることを確認してください。GU30、A10、または T4 の GPU タイプの使用を推奨します。インスタンスタイプ ml.gu7i.c16m60.1-gu30 は、コスト効率の高いオプションです。

モデルとノードの問題

Q:WebUI に「Missing Model」エラーが表示されます

説明:以下のエラーメッセージが表示されます:

image.png

解決策:このエラーは無視できます。このチェックは PAI にデプロイされた ComfyUI には適用されません。実際の問題を特定するには、実行時エラーに依存してください。

[Do not show this message again] を選択するか、[Settings] でモデル検証を無効にすることを推奨します。

image

Q:アップロードしたモデルが見つかりません

解決策:

  1. [PaiCustom] をクリックし、[Load New Model] を選択します。image

  2. それでもモデルが表示されない場合は、[Restart Process] をクリックします。image

Q:モデルローダーに「undefined」と表示されます

まず、モデルがモデルローダーで要求されるディレクトリにあることを確認してください。

デプロイ後にモデルをアップロードした場合は、サービスを再起動してください。

Q:ノードが見つかりません

Q:ComfyUI Manager がモデルのダウンロードやノードのインストールに失敗します

EAS にデプロイされた ComfyUI で ComfyUI Manager を使用することは避けてください。インターネットからモデルをダウンロードしたり、GitHub などのプラットフォームからコードをプルする必要があるプラグインをインストールしたりする際に、ネットワーク接続の問題が発生する可能性があります。

代わりに、モデルまたはノードファイルをサービスにマウントされたストレージにアップロードしてください。詳細については、「サードパーティモデルの使用とノード (ComfyUI プラグイン) のインストール」をご参照ください。

Q:利用可能なモデルとノードを表示するにはどうすればよいですか?

  • モデルファイル:チェックポイントローダーなどの対応する読み込みノードのドロップダウンリストで表示します。

  • ノード:インストールされているすべての ComfyUI プラグインを表示するには、WebUI を右クリックして [Add Node] を選択します。

実行時の例外

Q:ページがフリーズまたは読み込みが遅い

  • ページをリフレッシュするか、ブラウザのキャッシュをクリアするか、ブラウザのシークレットモードまたはプライベートモードを使用してください。

  • ストレージボリュームをマウントしている場合は、input/output/、および temp/ フォルダ内のファイルを削除してください。

  • サービスの再起動を試してください。

Q:ワークフロー実行中にプロセスが再起動する

インスタンスのログに run.sh: line 54: 531285 Killed python -u main_run.py "$@" というメッセージが含まれている場合、メモリ不足 (OOM) エラーを示しています。OOM エラーの後、プロセスは自動的に再起動します。

Q:RuntimeError: CUDA error: out of memory

このエラーは、ビデオメモリ (VRAM) が不足していることを示します。画像モデルを使用している場合は、画像の解像度またはバッチサイズを減らしてください。ビデオモデルの場合は、フレームレートまたは解像度を減らしてください。

Q:API 呼び出しが「url not found」または 404 エラーを返す

  1. API エンドポイント URL が完全であることを確認してください。同期呼び出しの場合、/prompt パスを追加する必要があります。

その他

Q:xFormers の高速化効果

xFormers は、画像と動画の生成時間を大幅に短縮し、ビデオメモリ (VRAM) の使用量を削減する、オープンソースの Transformer ベースの高速化ツールです。

デフォルトでは、ComfyUI のデプロイで xFormers の高速化が有効になっています。高速化の効果はワークフローのサイズに依存します。特に NVIDIA グラフィックスカードでの GPU を多用する呼び出しで、改善がより顕著になります。

次のステップ

ComfyUI サービスをデプロイした後、次のアクションを実行できます:

  • サービス監視:サービスの運用状況をリアルタイムで追跡するために、サービス監視とアラートを設定します。詳細については、「サービス監視の概要」をご参照ください。

  • オートスケーリング:ワークロードに基づいてオートスケーリングポリシーを設定し、リソースとコストを最適化します。詳細については、「オートスケーリング」をご参照ください。

  • コスト最適化:EAS の課金方法を理解し、適切なリソース仕様とデプロイバージョンを選択することでコストを削減します。詳細については、「課金の概要」をご参照ください。

関連資料

Python パッケージのインストール

コマンドによる方法

  1. サービスにストレージがマウントされていることを確認してください。OSS の Urioss://examplebucket/comfyui/ で、マウントパスが /mnt/data/ であると仮定します。image

  2. .whl ファイルを oss://examplebucket/comfyui/models/whl ディレクトリにアップロードします。whl フォルダが存在しない場合は作成してください。

  3. サービス設定の コマンドの実行 を更新し、その前に pip install /mnt/data/models/whl/xxx.whl を追加します。このコマンドでは、/mnt/data は OSS のマウントパスであり、xxx.whl は whl パッケージの名前です。

    image

  4. サービスを再起動します。

ライブラリ設定による方法

  1. サービス詳細ページの右上隅で、更新 をクリックします。

    image

  2. サービスがシナリオベースのデプロイでデプロイされた場合は、カスタムデプロイに切り替えます。

    image

  3. 環境コンテキスト セクションの [サードパーティライブラリの設定] で、依存パッケージを設定します。image

  4. ページ下部の 更新 ボタンをクリックして、サービスの更新を完了します。

イメージバージョンの更新

サービスに OSS または NAS からストレージがマウントされている場合、カスタムモデルはそのストレージに保存されます。イメージバージョンを更新しても、既存のカスタムモデルには影響しません。

  1. サービス詳細ページの右上隅で、更新 をクリックします。image

  2. サービスがシナリオベースのデプロイでデプロイされた場合は、カスタムデプロイに切り替えます。

  3. 対応する JSON 設定 セクションで、JSON 構成を編集し、containersimage フィールドを更新します。たとえば、図に示すように 1.9 を目的のバージョンに変更します。image

  4. [今すぐ更新] をクリックします。

署名付き URL の有効期間の延長

API を呼び出して、指定した有効期間を持つ署名付き Web アクセス URL を取得できます。

  1. DescribeServiceSignedUrl API ページに移動します。

  2. リージョンを選択します。image

  3. パラメーターを設定します:

    • ClusterId (リージョン) と ServiceName:サービスのリージョンと名前を入力します。この情報は EAS サービスの概要ページで確認できます。

      image

    • Type:ドロップダウンリストから webview を選択します。

    • Expire:秒単位の整数値を入力します。最大有効期間は 43,200 秒 (12 時間) です。必要に応じてこの値を設定することを推奨します。

    • Internal:パブリックアクセスには false を、VPC アクセスには true を設定します。

  4. [呼び出しを開始] をクリックします。応答の SignedUrl が、サービスへのログイン不要の Web アクセス用 URL です。

WebUI のデフォルト言語の変更

  1. WebUI ページで、左下隅の [Settings] ボタンをクリックします。

  2. 両方の場所で設定を構成した後、ページをリフレッシュして変更を適用します。

    • Comfy > Localeimage

    • Language > Locale:image

付録

クラスターサービスのアーキテクチャ

以下の図はアーキテクチャを示しています:

複数ユーザーシナリオ向けに設計されたクラスター版サービスは、クライアントとバックエンドの GPU 高速化推論インスタンスを分離するためにプロキシレイヤーを導入しています。

  • 各ユーザーは隔離されたバックエンド環境と作業ディレクトリを持ちますが、バックエンドの GPU 高速化推論インスタンスの共通プールを共有します。

  • ユーザーが推論リクエストを開始すると、プロキシはプールからアイドル状態のインスタンスを選択してリクエストを処理します。

このタイムシェアリングメカニズムにより、ユーザー環境の隔離が確保され、GPU リソースの利用率が向上し、複数ユーザーシナリオでの推論コストが削減されます。