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

Platform For AI:AI 動画生成 - ComfyUI のデプロイ

最終更新日:Mar 01, 2026

ComfyUI は、Stable Diffusion 向けのノードベースのユーザーインターフェースであり、ショートビデオコンテンツの生成やアニメーション制作などのタスクに対応する複雑な AIGC ワークフローを構築できます。このトピックでは、Elastic Algorithm Service (EAS) で ComfyUI をデプロイして使用する方法について説明します。

エディションガイド

シナリオ

呼び出しメソッド

Standard Edition

  • シングルユーザーの WebUI または API 呼び出し。入門や開発・テストに適しています。

  • 同時実行性能が限られているため、単一インスタンスでのデプロイを推奨します。

  • WebUI

  • オンラインデバッグ

  • API 呼び出し (同期)

API Edition

  • 高い同時実行性能。本番環境に適しています。

  • デプロイが比較的複雑で、キューサービスインスタンスを作成するために追加の CPU リソースが必要です。

API 呼び出し (非同期)

Cluster Edition WebUI

  • 複数のユーザーが環境を隔離して同時に WebUI を使用。チームでの共同作業や教育に適しています。

  • リソース消費が高い。動作原理の詳細については、「Cluster Edition サービスの動作原理の紹介」をご参照ください。

WebUI

Serverless Edition

  • デプロイは無料で、画像生成時間に基づいて課金されます。コストが非常に低く、需要の変動に対応できます。

  • カスタムモデルやプラグインは使用できません。デプロイは中国 (上海) および中国 (杭州) リージョンでのみサポートされています。

WebUI

説明

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

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

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

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

課金

  • Serverless Edition:デプロイは無料です。実際の推論時間に基づいて課金されます。

  • その他のエディション:デプロイされたリソースと実行時間に対して課金されます。サービスが正常にデプロイされると、使用されていなくても料金が発生します。

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

サービスのデプロイ

Serverless Edition は、シナリオベースのモデルデプロイ方法でのみデプロイできます。Standard、Cluster、および API エディションは、シンプルなシナリオベースのモデルデプロイ方法または、より多くの機能をサポートするカスタムモデルデプロイ方法でデプロイできます。

重要
  • ComfyUI はシングルカードモード (単一マシン単一カードまたは複数マシン単一カード) のみをサポートし、複数カードの同時操作はサポートしていません。EAS インスタンスには ComfyUI プロセスが 1 つしかないため、デプロイ時に 2 × A10 のような複数の GPU 仕様を持つインスタンスを選択しても、使用される GPU は 1 つだけです。単一の画像生成タスクは高速化されません。

  • 負荷分散:API Edition をデプロイし、非同期キューを使用して負荷分散を実装する必要があります。

方法 1:シナリオベースのモデルデプロイ (推奨)

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

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

  3. [AI 動画生成:ComfyUI ベースのデプロイ] ページで、次のパラメーターを設定します。

    • [エディション]:「エディションガイド」に基づいてエディションを選択します。

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

    • [リソース構成]:GU30、A10、または T4 GPU タイプを使用することを推奨します。システムはデフォルトで [GPU] > [ml.gu7i.c16m60.1-gu30] に設定されており、これはコスト効率の高いオプションです。

  4. [デプロイ] をクリックします。デプロイには約 5 分かかります。[サービスステータス][実行中] に変わると、デプロイは成功です。

方法 2:カスタムモデルデプロイ

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

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

  3. [カスタムデプロイ] ページで、次の主要なパラメーターを設定します。詳細については、「カスタムデプロイのパラメーター説明」をご参照ください。

    • [デプロイ方法][イメージデプロイ] に設定し、[Web アプリケーションを有効にする] チェックボックスをオンにします。

    • [イメージ構成][公式イメージ] リストで、[comfyui] > [comfyui:1.9] を選択します。イメージタグの x.x は Standard Edition、x.x-api は API Edition、x.x-cluster は Cluster Edition を示します。

      説明
      • バージョンは急速に更新されるため、デプロイ時には最新のイメージバージョンを選択できます。

      • 各バージョンのシナリオの詳細については、「エディションガイド」をご参照ください。

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

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

      • [マウントパス]:これを /code/data-oss に設定します。これにより、設定された OSS ファイルディレクトリがイメージ内の /code/data-oss パスにマウントされます。

    • コマンドの実行:

      • イメージバージョンを設定すると、システムは自動的に実行コマンドを python main.py --listen --port 8000 に設定します。ポート番号は 8000 です。

      • ストレージをマウントした場合、[起動コマンド]--data-dir パラメーターを追加し、その値をマウントディレクトリに設定する必要があります。このマウントディレクトリは [マウントパス] と同じでなければなりません。例:python main.py --listen --port 8000 --data-dir /code/data-oss

    • [リソースタイプ][パブリックリソース] に設定します。

    • [デプロイリソース]:リソース仕様は GPU タイプでなければなりません。[ml.gu7i.c16m60.1-gu30] を推奨します。これは最もコスト効率の高いオプションです。在庫が不足している場合は、[ecs.gn6i-c16g1.4xlarge] を選択できます。

  4. [デプロイ] をクリックします。サービスのデプロイには約 5 分かかります。[サービスステータス][実行中] になると、サービスは正常にデプロイされています。

サービスの呼び出し

WebUI の使用

重要

Standard、Cluster、および Serverless エディションは WebUI をサポートしています。

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

ページの読み込みが遅い場合は、「ページのフリーズまたはリフレッシュに時間がかかる」をご参照ください。

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

WebUI はカスタムワークフロー構成をサポートし、複数のプリセットテンプレートを提供します。[ワークフロー] > [テンプレートの参照] ページでテンプレートを選択できます。このトピックでは、Wan VACE Text to Video ワークフローテンプレートを例として使用します。

説明

Serverless Edition の場合、このワークフローはテンプレートに含まれていません。別のテンプレートを使用するか、[ワークフロー] > [開く] を選択してローカルファイルシステムからワークフローをロードできます。

image

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

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

image.png

まず、[Load models here] エリアで wan2.1_vace_14B_fp16.safetensorsWan21_CausVid_14B_T2V_lora_rank32.safetensors モデルを再選択します。

image

ワークフローが正常に実行されると、生成された動画が [Save Video] エリアに表示されます。image

2. サードパーティモデルの使用とカスタムノード (ComfyUI プラグイン) のインストール

  1. デプロイされた ComfyUI のバージョンが Serverless Edition でないことを確認してください。Serverless Edition は組み込みのモデルとノードしか使用できません。

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

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

    image

    ここで:

    • custom_nodes:このディレクトリはノードファイルを保存するために使用されます。

    • models:このディレクトリはモデルファイルを保存するために使用されます。

  3. モデルまたはノードファイルのアップロード。OSS を例にとると、コンソールで OSS にファイルをアップロードできます。大きなファイルについては、「OSS に大きなファイルをアップロードする方法」をご参照ください。

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

      • チェックポイントローダーの場合、モデルは models/checkpoints にアップロードする必要があります。

      • スタイルモデルローダーの場合、モデルは models/styles にアップロードする必要があります。

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

  4. 新しいモデルのロードまたはプロセスの再起動。

    マウントされたバケットにモデルをアップロードした後、[PaiCustom] > [新しいモデルのロード] をクリックします。それでもモデルが見つからない場合は、[プロセスの再起動] をクリックします。プロセスが再起動したら、ページをリフレッシュします。

    ノードファイルをアップロードした後、[プロセスの再起動] をクリックします。プロセスが再起動したら、ブラウザのページをリフレッシュします。

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

ワークフローをデバッグした後、[ワークフロー] > [エクスポート (API)] をクリックしてワークフローを JSON ファイルとして保存します。その後、このファイルを API 呼び出しに使用できます。

image

API 呼び出し

重要

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

API Edition サービスは非同期呼び出しのみをサポートし、api_prompt パスのみをサポートします。

ComfyUI の API リクエストボディはワークフローの構成に依存します。まず、WebUI からワークフローの JSON ファイルをセットアップし、エクスポートする必要があります。

  • 同期呼び出し:リクエストボディは、ワークフロー 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)] ページで、対象のサービスを見つけ、[操作] 列の [オンラインデバッグ] をクリックします。

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

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

    2. [リクエストの送信] をクリックして、[デバッグ情報] エリアでレスポンスを表示します。次の図を参照してください。image

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

    1. [オンライン API デバッグリクエストパラメーター] エリアで、リクエストメソッドを GET に設定し、テキストボックスに /history/<prompt id> を入力します。次の図を参照してください。image

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

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

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

同期呼び出し

  1. エンドポイント情報を表示します。

    1. [推論サービス] タブで、対象のサービス名をクリックして [概要] ページに移動します。[基本情報] セクションで、[エンドポイント情報を表示] をクリックします。

    2. [呼び出し方法] パネルで、エンドポイントとトークンを取得します。要件に応じてインターネットまたは VPC エンドポイントを選択します。以下の例では、これらの値のプレースホルダーとして <EAS_ENDPOINT><EAS_TOKEN> を使用します。

      image

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

    • HTTP リクエストメソッド:POST。

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

    • リクエストヘッダー (Headers)

      ヘッダー

      説明

      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":
        ...omitted
    }'

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

    Python

    サンプルコード:

    import requests
    import json
    
    # ステップ 1 で取得したエンドポイントとトークンに <EAS_ENDPOINT> と <EAS_TOKEN> を置き換えます。
    service_url = "<EAS_ENDPOINT>"
    token = "<EAS_TOKEN>"
    
    if service_url[-1] == "/":
        service_url = service_url[:-1]
    
    # リクエストボディ。ペイロードの prompt の値をワークフローに対応する JSON ファイルの内容として設定します。
    payload = """{
        "prompt":
        ...omitted
    }"""
    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> を前のステップで取得した prompt_id に置き換えます。

    • リクエストヘッダー

      ヘッダー

      説明

      Authorization

      <EAS_TOKEN>

      ライセンスキー。ステップ 1 で取得します。

    サンプルコード:

    cURL

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

    Python

    import requests
    
    # ステップ 1 で取得したエンドポイントとトークンに <EAS_ENDPOINT> と <EAS_TOKEN> を置き換えます。
    # ステップ 2 で取得した prompt_id に <prompt_id> を置き換えます。
    service_url = "<EAS_ENDPOINT>"
    token = "<EAS_TOKEN>"
    prompt_id = "<prompt_id>"
    
    if service_url[-1] == "/":
        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": ...omitted,
            "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": ...omitted,
            }
        }
    }
    

    このサンプルレスポンスの outputs は、プロンプトによって生成された画像、webp ファイル、および mp4 ビデオを提供します。これらのファイルは、マウントされたストレージの output ディレクトリでファイル名によって見つけることができます。

非同期呼び出し

重要

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

{service_url}/api_prompt?task_id={一意の値を割り当てる必要があります}

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

    image

  2. リクエストをプッシュします。

    サンプルコード:

    import requests,io,base64
    from PIL import Image, PngImagePlugin
    import json
    
    service_url = "<EAS_ENDPOINT>"
    token = "<EAS_TOKEN>"
    
    if service_url[-1] == "/":
        service_url = service_url[:-1]
    
    session = requests.session()
    session.headers.update({"Authorization":token})
    
    # リクエストボディ。ワークフロー JSON ファイルの内容です。複数行の文字列として定義するには """ """ を使用します。そうしないと、ワークフロー JSON のブール値 (true と false) の最初の文字を大文字にする必要があります。
    payload = """{
        '3': 
        ...omitted
      }
      """
    payload = json.loads(payload)
    
    for i in range(5):
      # task_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>"
      
      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 ディレクトリで確認できます。

説明

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

よくある質問

モデルとノード

1. WebUI エラー:モデルが見つかりません

問題の説明:次のエラーが報告されます:

image.png

解決策:このチェックは PAI にデプロイされた ComfyUI には無効です。実行時エラーが優先されます。[このメッセージを再度表示しない] チェックボックスをオンにするか、設定でモデル検証を無効にすることを推奨します。

image

2. 新しいモデルをアップロードしましたが、見つかりません

まず、Serverless Edition を使用していないか確認してください。Serverless Edition は独自のモデルのアップロードをサポートしていません。Standard または Cluster Edition を使用してください。サポートされているバージョンを使用している場合は、次の手順を実行します:

  1. ページで [PaiCustom] をクリックし、[新しいモデルのロード] を選択します。image

  2. それでもうまくいかない場合は、[プロセスの再起動] をクリックします。image

3. モデルローダーに「undefined」と表示される

まず、モデルディレクトリが正しいことを確認してください。必要なディレクトリはモデルローダーによって異なります。

サービス開始後にモデルファイルが更新された場合は、サービスを再起動してください。

4. ノードが見つかりません

5. ComfyUI Manager がモデルのダウンロードまたはノードのインストールに失敗する

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

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

6. 利用可能なモデルファイルとノード (ComfyUI プラグイン) のリストを表示するにはどうすればよいですか?

  • モデルファイル:対応するモデル読み込みノードで表示します。例えば、チェックポイントローダーのドロップダウンリストで利用可能なモデルファイルを表示できます。

  • ノード:インストールされているすべての ComfyUI プラグインのノードを表示するには、WebUI ページを右クリックし、ショートカットメニューから [ノードの追加] をクリックします。

イメージと依存関係

1. wheel パッケージをインストールするにはどうすればよいですか?

  1. マウント構成が完了していることを確認してください。次の例では、OSS パス Uri が oss://examplebucket/comfyui であると仮定します。image

  2. wheel パッケージをマウントされた OSS の oss://examplebucket/comfyui/models/whl にアップロードします。whl フォルダが存在しない場合は作成します。

  3. この例では、OSS マウントパスは /mnt/data です。実行コマンドの前に pip install /mnt/data/models/whl/xxx.whl コマンドを追加します。このコマンドでは、/mnt/data はご利用の OSS マウントパス、xxx.whl はご利用の wheel パッケージの名前です。

    image

2. イメージのバージョンを更新し、インストール済みのカスタムモデルを保持するにはどうすればよいですか?

Serverless バージョンの ComfyUI イメージは更新できません。ただし、OSS または NAS ストレージがマウントされている他のバージョンでは、カスタムモデルは保持されます。これにより、サービス構成の [公式イメージ] を更新しても、カスタムモデルに影響はありません。そのためには、次の手順を実行します:

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

    image

  2. サービスがシナリオベースの方法でデプロイされた場合は、カスタムデプロイに切り替えます。右側で [サービス構成] をクリックし、JSON ファイルを編集して、コンテナーの image フィールドを更新します。例えば、pai-eas/comfyui:1.9 の 1.9 を必要なバージョンに変更します。

    image

  3. 編集ウィンドウで、[直接更新] をクリックします。

3. イメージに依存関係ライブラリがありません

サードパーティライブラリを構成して、不足している依存関係をインストールします。手順は次のとおりです:

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

    image

  2. サービスがシナリオベースの方法でデプロイされた場合は、カスタムデプロイに切り替えます。右側で [環境コンテキスト] をクリックします。[その他の構成] セクションで、サードパーティライブラリの構成を見つけ、指定された形式で必要な依存関係を入力します。

    image

    image

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

実行時の例外

1. ページのフリーズまたはリフレッシュに時間がかかりすぎる

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

  • ストレージがマウントされている場合は、マウントディレクトリの input、output、および temp フォルダ内のファイルをクリアします。

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

2. ワークフローが途中で実行され、プロセスが再起動する

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

3. RuntimeError: CUDA error: out of memory

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

4. API 呼び出しエラー:「url not found」または「404 page not found」?

  1. デプロイされたサービスが Serverless Edition かどうかを確認してください。Serverless Edition は API 呼び出しをサポートしていません。

  2. サービスバージョンが正しい場合は、API 宛先 URL が完全であることを確認してください。同期呼び出しの場合、/prompt パスを追加する必要があります。

5. サービスが常に「待機中」状態であるか、ComfyUI が画像を生成できない

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

6. なぜサービスは一定期間実行された後、自動的に停止するのですか?

Serverless Edition のモデルサービスが長期間リクエストや計算タスクを受信しない場合、システムはコストを削減するためにリソースを自動的に解放することがあります。

その他

1. ログイン不要 URL の有効期間を延長するにはどうすればよいですか?

API を使用して、指定された有効期間を持つログイン不要の Web アクセスリンクを取得できます。

  1. DescribeServiceSignedUrl API リンクをクリックして API ページに移動します。

  2. サービスリージョンを選択します。

image

  1. サービスが配置されているリージョンとサービス名を入力します。この情報は EAS サービスの概要ページから取得できます。

    image

  2. その他のパラメーターは次のとおりです:

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

    • Expire time:長い有効期間を設定するには、9007199254740991 を入力します。現在の最大有効期間は 12 時間です。

      それ以外の場合は、秒単位の整数値を入力します。

    • Internal whether it is a VPC link:VPC 呼び出しでない場合は false を選択します。それ以外の場合は true を選択します。

  3. [呼び出しの開始] をクリックします。レスポンスの SignedUrl が、サービスのログイン不要の Web アクセスリンクです。

2. xFormers が画像生成速度に与える高速化効果

xFormers は Transformer ベースのオープンソースの高速化ツールで、画像や動画の生成時間を大幅に短縮し、ビデオメモリの使用量を削減できます。デフォルトでは、ComfyUI イメージデプロイで xFormers の高速化が有効になっています。高速化の効果はワークフローのサイズに依存します。特に NVIDIA グラフィックスカードを使用する GPU 集中型の呼び出しで、改善がより顕著になります。

3. ComfyUI Serverless Edition をデプロイする際の EAS と Function Compute の主な違い

  • EAS:ステートフルで長時間実行されるサービスに適しています。モデルをオンライン推論サービスまたは AI-Web アプリケーションとしてワンクリックでデプロイでき、弾力的なスケーリングやブルーグリーンデプロイメントなどの機能が含まれています。例えば、EAS でシナリオベースのモデルデプロイまたはカスタムモデルデプロイを使用して ComfyUI をデプロイできます。

  • Function Compute:サーバーレスアーキテクチャに基づいており、従量課金や弾力的なスケーリングなどの利点を提供します。高品質な画像生成が必要なシナリオに適しています。ComfyUI モデルをカスタマイズし、プラグインをインストールできます。例えば、Function Compute 3.0 コンソールでアプリケーションを作成し、ComfyUI テンプレートを選択して設定項目を設定できます。

4. WebUI ページのデフォルト言語を切り替えるにはどうすればよいですか?

  1. WebUI ページで、左下隅の設定ボタン image をクリックします。

  2. [設定] ダイアログボックスで、次の 2 つの場所で言語を設定します。パラメーターを設定した後、ページをリフレッシュします。

    • 左側のナビゲーションウィンドウで、[Comfy] を選択します。右側のリージョン設定で、目的の言語を選択します。image

    • 左側のナビゲーションウィンドウで、[言語] を選択します。右側の [ロケール] セクションで、目的の言語を選択します。image

付録

Cluster Edition サービスの動作原理の紹介

次の図は、実装原理を示しています:

image
  • Cluster Edition サービスは、マルチユーザーシナリオ向けに設計されています。クライアントとバックエンドの推論インスタンスを分離することで、複数のユーザーがバックエンドの推論インスタンスを共有できます。これにより、インスタンスの利用率が向上し、推論コストが削減されます。

  • 各ユーザーは独立したバックエンド環境と作業ディレクトリを持ち、効率的な GPU 共有とファイル管理が可能です。

  • プロキシはクライアントプロセスと推論インスタンスを管理します。すべてのユーザー操作は自身のプロセスで処理され、ファイル操作はパブリックディレクトリと個人ディレクトリに限定されます。これにより、ユーザー間の作業ディレクトリが効果的に隔離されます。ユーザーがリクエストを処理する必要がある場合、プロキシはバックエンドから利用可能なアイドル状態のインスタンスを見つけて推論リクエストを処理します。