Tous les produits
Search
Centre de documentation

Platform For AI:Déployer un service ComfyUI pour la génération de vidéos par IA

Dernière mise à jour :Oct 10, 2026

ComfyUI est un outil AIGC basé sur des nœuds, construit sur Stable Diffusion, conçu pour la génération de vidéos courtes et la production d'animations. PAI-EAS prend en charge le déploiement de services ComfyUI adapté à différents scénarios.

Avant de commencer

Principales limites et considérations

Lisez cette section avant le déploiement afin d'éviter le gaspillage de ressources et les erreurs courantes.

  • Ressources de déploiement : Nous recommandons les types d'instance GPU GU30, NVIDIA A10 ou NVIDIA T4. Le type d'instance ml.gu7i.c16m60.1-gu30 offre le meilleur rapport qualité-prix.

    Important

    Chaque instance PAI-EAS exécute un seul processus ComfyUI et ne prend en charge qu'un seul GPU (une instance unique avec un seul GPU ou plusieurs instances avec un seul GPU chacune). L'inférence parallèle sur plusieurs GPU n'est pas prise en charge. Ne sélectionnez pas de types d'instance multi-GPU (tels que 2×A10). Les types d'instance multi-GPU gaspillent des ressources et n'améliorent pas les performances pour une tâche unique.

  • Mise à l'échelle horizontale : Pour augmenter la concurrence, utilisez l'API Edition et augmentez le nombre de replicas au lieu de sélectionner un type d'instance multi-GPU.

Choisir une édition de déploiement

Sélectionnez l'édition qui correspond le mieux à votre cas d'utilisation :

Édition

Cas d'utilisation

Méthode d'accès

Fonctionnalités clés

Méthode de facturation

Standard Edition

Développement et tests pour un utilisateur unique

  • WebUI

  • Appels API (synchrones, avec débogage en ligne)

  • Concurrence limitée

  • Déploiement d'une instance unique

Lors du déploiement sur des ressources publiques, la facturation commence dès que l'instance est en cours d'exécution, même sans aucun appel API.

API Edition

Charges de travail de production à forte concurrence

Appels API (asynchrones)

  • Basé sur le service de file d'attente PAI-EAS

  • Nécessite des ressources CPU supplémentaires

  • Prend en charge l'équilibrage de charge

Cluster Edition WebUI

Équipes multi-utilisateurs et formation

WebUI

  • Environnements utilisateur isolés

  • Ressources GPU partagées

  • Consommation de ressources plus élevée

Pour plus d'informations sur le fonctionnement, consultez Fonctionnement de Cluster Edition

Pour plus d'informations sur la facturation, consultez Facturation d'Elastic Algorithm Service (EAS).

Remarque

Les appels API synchrones et asynchrones diffèrent selon l'utilisation ou non du service de file d'attente PAI-EAS :

  • Appel synchrone : Envoie une requête directement à l'instance d'inférence sans utiliser le service de file d'attente PAI-EAS.

  • Appel asynchrone : Utilise le service de file d'attente PAI-EAS. Les requêtes sont soumises à une file d'attente d'entrée et les résultats sont livrés via un modèle d'abonnement.

Comme ComfyUI dispose de son propre système de file d'attente asynchrone intégré, même les appels synchrones sont traités de manière asynchrone en arrière-plan. Après avoir soumis une requête, le système renvoie un Prompt ID que vous utilisez pour interroger le résultat de l'inférence.

Déployer le service

Standard Edition, Cluster Edition et API Edition : Vous pouvez utiliser le déploiement de modèles basé sur des scénarios pour une expérience simplifiée, ou le déploiement de modèles personnalisés pour des options de configuration avancées.

Méthode 1 : Déploiement de modèles basé sur des scénarios (recommandé)

  1. Connectez-vous à la console PAI. Sélectionnez une région en haut de la page. Ensuite, sélectionnez l'espace de travail souhaité et cliquez sur Enter Elastic Algorithm Service (EAS).

  2. Sur la page Elastic Algorithm Service (EAS), cliquez sur Deploy Service. Dans la section Scenario-based Model Deployment, cliquez sur AI Video Generation: ComfyUI-based Deployment.

  3. Configurez les paramètres clés suivants et définissez les autres paramètres selon vos besoins :

    • Version : Consultez Choisir une édition de déploiement.

    • Model Settings : Par exemple, en utilisant Object Storage Service (OSS), sélectionnez un bucket et un répertoire. Une fois le déploiement réussi, le système crée automatiquement les répertoires ComfyUI requis à cet emplacement.

      Important

      PAI-EAS ne prend pas en charge l'installation directe de nœuds personnalisés (plugins) depuis le réseau via ComfyUI Manager ou Git Clone. Pour utiliser vos propres modèles, installer des nœuds personnalisés ou effectuer des appels API, vous devez configurer ce point de montage de stockage.

    • Resource Configuration : Vous devez sélectionner un type d'instance GPU. Nous recommandons GU30, NVIDIA A10 ou NVIDIA T4. ml.gu7i.c16m60.1-gu30 offre le meilleur rapport qualité-prix. Si ce type d'instance n'est pas disponible, sélectionnez plutôt ecs.gn6i-c16g1.4xlarge.

  4. Cliquez sur Deploy. Attendez environ 5 minutes. Lorsque le Service Status passe à Running, le déploiement est terminé.

Méthode 2 : Déploiement de modèles personnalisés

  1. Connectez-vous à la console PAI. Sélectionnez une région en haut de la page. Ensuite, sélectionnez l'espace de travail souhaité et cliquez sur Enter Elastic Algorithm Service (EAS).

  2. Cliquez sur Deploy Service Dans la section Inference Service, cliquez sur Custom Deployment dans la section Custom Model Deployment.

  3. Configurez les paramètres clés suivants :

    • Deployment Method : Sélectionnez Image-based Deployment et cochez la case Enable Web App.

    • Image Configuration : Dans la liste Alibaba Cloud Image, sélectionnez comfyui:2.3. Convention de nommage des versions d'image : x.x pour Standard Edition, x.x-api pour API Edition et x.x-cluster pour Cluster Edition.

      Remarque
      • Étant donné que les versions sont mises à jour fréquemment, sélectionnez la dernière version d'image disponible lors du déploiement.

      • Pour les cas d'utilisation de chaque édition, consultez Choisir une édition de déploiement.

    • Mount storage : En prenant Object Storage Service (OSS) comme exemple, sélectionnez un bucket et un répertoire. Une fois le déploiement réussi, le système crée automatiquement les répertoires ComfyUI requis à cet emplacement. Assurez-vous que le bucket se trouve dans la même région que le service PAI-EAS.

      Important

      PAI-EAS ne prend pas en charge l'installation directe de nœuds personnalisés (plugins) depuis le réseau via ComfyUI Manager ou Git Clone. Pour utiliser vos propres modèles, installer des nœuds personnalisés ou effectuer des appels API, vous devez configurer ce point de montage de stockage.

      • URI : Cliquez sur image pour sélectionner un répertoire OSS existant. Par exemple, oss://bucket-test/data-oss/.

      • Mount Path : Définissez-le sur /mnt/data pour monter le répertoire OSS sur le chemin du conteneur /mnt/data.

    • Command to Run :

      • Après avoir sélectionné une version d'image, le système configure automatiquement la commande d'exécution.

      • Si vous avez configuré un point de montage de stockage, vous devez ajouter le paramètre --data-dir à la Command, et sa valeur doit correspondre exactement au Mount Path. Par exemple, python main.py --listen --port 8000 --data-dir /mnt/data --cache-root /stable-diffusion-cache.

    • Resource Type : Sélectionnez Public Resources.

    • Deployment : Vous devez sélectionner un type d'instance GPU. Nous recommandons GU30, NVIDIA A10 ou NVIDIA T4. ml.gu7i.c16m60.1-gu30 offre le meilleur rapport qualité-prix. Si ce type d'instance n'est pas disponible, sélectionnez plutôt ecs.gn6i-c16g1.4xlarge.

  4. Cliquez sur Deploy. Le déploiement prend environ 5 minutes. Lorsque le Service Status passe à Running, le service est déployé.

Utiliser le service via WebUI

Important

Standard Edition et Cluster Edition prennent en charge l'accès via WebUI.

Ouvrir l'interface web

Cliquez sur le nom du service cible pour ouvrir la page Overview, puis cliquez sur Web Application dans le coin supérieur droit.

Si la page met longtemps à se charger, consultez La page se fige ou met trop de temps à se charger .

Utiliser un workflow de modèle

ComfyUI fournit des modèles prédéfinis pour les tâches courantes.

  1. Sélectionnez un modèle (par exemple, Wan VACE Text to Video).

    Remarque

    Les modèles varient selon les versions d'image ComfyUI. Si le modèle d'exemple n'est pas disponible, sélectionnez un autre modèle ou chargez un fichier de workflow depuis le système de fichiers local.

  2. Une fois le workflow chargé, vous pouvez voir des erreurs concernant des modèles manquants. Vous pouvez ignorer ces erreurs (nous vous recommandons de sélectionner l'option pour ne plus afficher ce message).

  3. Étant donné que les chemins d'accès aux modèles peuvent avoir changé, l'exécution directe du workflow peut produire l'erreur suivante :

    Prompt outputs failed validation:
    UNETLoader:
    - Value not in list: unet_name: 'wan2.1_vace_14B_fp16.safetensors' not in (list of length 200)
    LoraLoader:
    - Value not in list: lora_name: 'Wan21_CausVid_14B_T2V_lora_rank32.safetensors' not in (list of length 364)

    Dans la section Load models here, resélectionnez wan2.1_vace_14B_fp16.safetensors dans le chargeur UNET et Wan21_CausVid_14B_T2V_lora_rank32.safetensors dans le chargeur LoRA.

  4. Une fois le workflow exécuté avec succès, la vidéo générée apparaît dans la section Save Video. image

Utiliser des modèles et des nœuds personnalisés

  1. Assurez-vous que le service dispose d'un point de montage de stockage configuré. Une fois le service déployé, le système crée automatiquement la structure de répertoires suivante dans le stockage OSS ou NAS monté.

    data-oss/
    ├── custom_nodes/     # Custom node files (ComfyUI plugins)
    ├── models/           # Model files
    ├── input/
    ├── output/
    ├── unet/
    └── temp/
  2. Téléchargez les fichiers de modèle ou de nœud. Par exemple, vous pouvez utiliser OSS et télécharger des fichiers vers OSS via la console. Pour les fichiers volumineux, consultez Comment télécharger de grands objets vers OSS ?.

    • Télécharger des fichiers de modèle : Consultez la documentation du dépôt source pour le nœud qui utilise le modèle, et téléchargez le modèle dans le sous-répertoire correspondant sous models. Par exemple :

      • Chargeur de checkpoint : Téléchargez les modèles vers models/checkpoints.

      • Chargeur de modèle de style : Téléchargez les modèles vers models/styles.

    • Télécharger des fichiers de nœud : Téléchargez les nœuds personnalisés dans le répertoire custom_nodes du stockage monté.

  3. Charger le nouveau contenu.

    • Modèles : En haut de la page, cliquez sur PaiCustom > Load New Models. Si le modèle n'apparaît toujours pas, cliquez sur PaiCustom > Restart Process. Une fois le processus redémarré, actualisez la page du navigateur.

    • Nœuds : Cliquez sur Restart Process. Une fois le processus redémarré, actualisez la page du navigateur.

Appeler le service via l'API

Vous pouvez appeler le service ComfyUI via son API pour l'intégrer à vos applications et automatiser la génération de contenu. Le flux de travail principal consiste à : soumettre un workflow JSON > obtenir un ID de tâche > utiliser cet ID de tâche pour récupérer le résultat de la génération.

Important
  • Prise en charge par édition : L'édition Standard prend uniquement en charge les appels synchrones et offre des fonctionnalités de débogage en ligne. L'édition API ne prend en charge que les appels asynchrones et uniquement le point de terminaison /prompt.

  • Récupération des fichiers générés : Les images et vidéos générées sont stockées dans le répertoire output monté. Les réponses de l'API renvoient les noms de fichiers et de sous-répertoires, et non les fichiers eux-mêmes. Pour OSS, construisez le chemin d'accès complet au fichier pour le télécharger. Pour plus d'informations, consultez la rubrique Télécharger des fichiers OSS à l'aide du SDK Alibaba Cloud.

Préparer le corps de la requête API

Le format du corps de la requête dépend de la méthode d'appel :

  • Appel synchrone : encapsulez le contenu JSON du workflow dans une paire clé-valeur prompt.

  • Appel asynchrone : le corps de la requête correspond directement au contenu JSON du workflow.

Remarque

Comment télécharger un workflow : Dans le coin supérieur gauche de la page ComfyUI, cliquez sur image > File > Export (API).

Étant donné que le workflow Wan VACE Text to Video mentionné ci-dessus est long à exécuter, un workflow de test est fourni ci-après pour faciliter les tests (chaque exécution dure environ 3 minutes).

Cliquez pour afficher l'exemple de corps de requête pour le workflow de test

Appel synchrone

{
    "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": "KSampler"
            }
        },
        "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": "KSampler"
            }
        },
        "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"
            }
        }
    }
}

Appel asynchrone

{
    "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": "KSampler"
        }
    },
    "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": "KSampler"
        }
    },
    "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"
        }
    }
}

Appels synchrones

Les appels synchrones envoient des requêtes directement à l'instance de service PAI-EAS. Cette méthode convient aux scénarios de développement, de test et de faible concurrence.

Débogage en ligne

Le débogage en ligne vous permet de tester les appels d'API directement dans la console sans écrire de code. Cela s'avère utile pour valider rapidement les configurations de workflow.

Sur la page Elastic Algorithm Service (EAS), cliquez sur Online Debugging dans la colonne Actions du service cible pour ouvrir la page de débogage en ligne.

  1. Envoyez une requête POST pour obtenir l'ID de prompt.

    1. Dans la section Request Parameter Online Tuning de la page de débogage, saisissez le corps de requête préparé dans le champ Body, et ajoutez /prompt à l'URL de la requête.

    2. Cliquez sur Send Request pour afficher la réponse dans la section Debugging Information.

      Après l'envoi de la requête, le panneau Debug Info situé à droite affiche la réponse : le code d'état est 200 et le corps de la réponse contient les champs prompt_id (par exemple, 130bc***c8c-3a1359a04e5d), number et node_errors. Notez la valeur de prompt_id pour l'utiliser à l'étape suivante.

  2. Envoyez une requête GET pour récupérer le résultat de l'inférence à l'aide de l'ID de prompt.

    1. Dans la section Request Parameter Online Tuning, modifiez la méthode de requête en GET et saisissez /history/<prompt id> dans le champ URL.

      Remplacez <prompt id> par l'ID de prompt obtenu à l'étape 1.

    2. Cliquez sur Send Request pour récupérer le résultat de l'inférence.

      Vous trouverez la sortie générée dans le répertoire output du stockage monté.

Appels basés sur le code

Vous pouvez appeler l'API par le biais de code pour intégrer ComfyUI à vos applications. Le flux de travail est identique à celui du débogage en ligne : obtenez d'abord l'ID de prompt, puis interrogez le résultat de l'inférence.

  1. Affichez les informations d'appel.

    1. Dans l'onglet Inference Services, cliquez sur le nom du service cible pour ouvrir la page Overview.

    2. Dans la section Basic Information, cliquez sur View Call Information.

    3. Dans le panneau Call Information, copiez le point de terminaison d'accès et le jeton :

      Le panneau Call Information comporte deux onglets : Shared Gateway et VPC Direct Connection. Le point de terminaison public, le point de terminaison VPC et le jeton se trouvent dans l'onglet Shared Gateway.

      • Sélectionnez le Public Endpoint ou le VPC Endpoint selon vos besoins.

      • Les exemples ci-dessous utilisent pour le point de terminaison d'accès et pour le jeton.

  2. Envoyez une requête pour obtenir l'ID de prompt.

    • Méthode HTTP : POST.

    • URL de la requête : <EAS_ENDPOINT>/prompt. Si <EAS_ENDPOINT> se termine par /, supprimez la barre oblique finale. L'URL finale ressemble à ceci : http://comfyui****.175805416243****.cn-beijing.pai-eas.aliyuncs.com/prompt.

    • En-têtes de requête :

      Header

      Value

      Description

      Authorization

      <EAS_TOKEN>

      Le jeton d'autorisation.

      Content-Type

      application/json

      Spécifie le format du corps de la requête.

    Exemples de code :

    cURL

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

    Le paramètre --data-raw contient le corps de la requête.

    Python

    Exemple de code :

    import requests
    import json
    
    # Replace <EAS_ENDPOINT> and <EAS_TOKEN> with the endpoint and token from Step 1.
    service_url = "<EAS_ENDPOINT>"
    token = "<EAS_TOKEN>"
    
    if service_url[-1] == "/":
        service_url = service_url[:-1]
    
    # Request body: set the "prompt" value to the workflow JSON content.
    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)

    Exemple de réponse :

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

    Extrayez l'ID de prompt de la réponse.

  3. Récupérez le résultat de l'inférence.

    • Méthode HTTP : GET

    • URL de la requête : <EAS_ENDPOINT>/history/<prompt_id>. Remplacez <prompt_id> par le prompt_id obtenu à l'étape 1.

    • En-têtes de requête :

      Header

      Value

      Description

      Authorization

      <EAS_TOKEN>

      Le jeton d'autorisation obtenu à l'étape 1.

    Exemples de code :

    cURL

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

    Python

    import requests
    
    # Replace <EAS_ENDPOINT> and <EAS_TOKEN> with the endpoint and token from Step 1.
    # Replace <prompt_id> with the prompt_id obtained in Step 2.
    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)

    Exemple de réponse :

    Cliquez pour afficher l'exemple de réponse

    {
        "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)"
            }
        }
    }

    Le champ outputs de la réponse contient les images (PNG/WebP) et vidéos (MP4) générées. Vous pouvez localiser ces fichiers dans le répertoire output du stockage monté en recherchant les noms de fichiers.

Appels asynchrones

Les appels asynchrones sont conçus pour les charges de travail de production à forte concurrence. Cette méthode utilise le service de file d'attente PAI-EAS pour l'équilibrage de charge. Les requêtes retournent immédiatement et vous récupérez les résultats en vous abonnant à la file d'attente de résultats.

Important

Les appels asynchrones prennent uniquement en charge le point de terminaison api_prompt. Le paramètre task_id est un identifiant essentiel pour faire correspondre les requêtes aux résultats. Attribuez une valeur unique à chaque requête afin de pouvoir la corréler avec le résultat correspondant dans la file d'attente. Le chemin de la requête est le suivant :

{service_url}/api_prompt?task_id={assign a unique value}

  1. Affichez les informations d'appel.

    Dans l'onglet Inference Services, cliquez sur le nom du service cible pour ouvrir la page Overview. Dans la section Basic Information, cliquez sur View Call Information. Dans l'onglet Asynchronous Call de la boîte de dialogue Call Information, affichez le point de terminaison d'accès au service et le jeton.

    image

    Les sections suivantes utilisent <EAS_ENDPOINT> pour désigner le Internet Input Endpoint (si l'appelant se trouve dans le même VPC que PAI-EAS, vous pouvez utiliser le VPC Input Endpoint), et <EAS_TOKEN> pour désigner le Token.

  2. Envoyez une requête.

    Exemple de code :

    import requests
    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})
    
    # Request body - workflow JSON, no need to wrap with "prompt".
    # Use triple quotes to define it as a multi-line string, otherwise you need to capitalize the boolean values (true and false) in the workflow JSON.
    payload = """{
        '3':
        ...omitted
      }
      """
    payload = json.loads(payload)
    
    for i in range(5):
      # task_id is the key identifier for matching requests and results. Assign a unique value to each request to correlate with the queue results later.
      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. Abonnez-vous aux résultats.

    1. Installez le SDK eas_prediction.

      pip install eas_prediction  --user
    2. Exécutez le code suivant pour récupérer le résultat.

      from eas_prediction import QueueClient
      from urllib.parse import urlparse, urlunparse
      
      service_url     = "<EAS_ENDPOINT>"
      token           = "<EAS_TOKEN>"
      
      # Parse service 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}.")
      
      # Create result queue client
      sink_queue = QueueClient(service_domain, f'{service_name}/sink')
      sink_queue.set_token(token)
      sink_queue.init()
      
      # Listen for results
      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}')
          # Commit acknowledgment
          sink_queue.commit(x.index)

      Exemple de réponse :

      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"}]}}]'

      Vous trouverez les fichiers de résultat de l'inférence dans le répertoire output du stockage monté.

FAQ

Vous trouverez ci-dessous les problèmes courants et leurs solutions lors du déploiement et de l'utilisation de ComfyUI.

Problèmes de déploiement

Q : Le service reste en attente ou ComfyUI ne génère aucune sortie

Ce problème est généralement dû à des ressources insuffisantes. Vérifiez que l'image du service et le type d'instance sont correctement configurés. Nous recommandons les types d'instance GPU GU30, NVIDIA A10 ou NVIDIA T4. Le type d'instance ml.gu7i.c16m60.1-gu30 offre le meilleur rapport qualité-prix.

Problèmes liés aux modèles et aux nœuds

Q : L'interface Web affiche une erreur « Missing Model »

Problème : Une boîte de dialogue intitulée Missing Model indique que le modèle situé dans checkpoints/v1-5-pruned-emaonly-fp16.safetensors est manquant, et un avertissement rouge à gauche affiche Invalid directory specified (does this require custom nodes?).

Solution : Vous pouvez ignorer cette erreur en toute sécurité. Cette vérification de validation ne s'applique pas à ComfyUI déployé sur PAI. Fiez-vous plutôt aux erreurs d'exécution réelles.

Nous vous recommandons de sélectionner l'option permettant de ne plus afficher ce message, ou de désactiver la validation des modèles dans Settings.

Q : J'ai téléchargé un nouveau modèle, mais je ne le trouve pas

Solution :

  1. Cliquez sur PaiCustom et sélectionnez Load New Models.

  2. Si le modèle n'apparaît toujours pas, cliquez sur Restart Process.

Q : Le chargeur de modèles affiche « undefined »

Commencez par vérifier que le fichier de modèle est placé dans le répertoire correct requis par le nœud de chargement de modèle.

Si vous avez téléchargé le modèle après le déploiement, redémarrez le service.

Q : Impossible de trouver un nœud

Q : ComfyUI Manager échoue à télécharger des modèles ou à installer des nœuds

Nous ne recommandons pas l'utilisation de ComfyUI Manager avec ComfyUI déployé sur PAI-EAS. ComfyUI Manager télécharge des modèles et du code de plugin depuis des sources externes telles que GitHub, ce qui échoue fréquemment en raison des restrictions réseau.

Préférez le téléchargement des fichiers de modèles et de nœuds vers le stockage monté. Pour plus d'informations, consultez la section Utiliser des modèles personnalisés et installer des nœuds (plugins ComfyUI).

Q : Comment afficher les fichiers de modèles et les nœuds disponibles (plugins ComfyUI)

  • Fichiers de modèles : Vérifiez-les depuis le nœud de chargement de modèle correspondant. Par exemple, affichez les fichiers de modèles disponibles dans la liste déroulante du chargeur de points de contrôle (Checkpoint loader).

  • Nœuds : Cliquez avec le bouton droit sur la page de l'interface Web et sélectionnez Add Node dans le menu contextuel pour afficher tous les plugins ComfyUI installés.

Erreurs d'exécution

Q : La page se fige ou met trop de temps à charger

  • Actualisez la page, videz le cache du navigateur ou accédez au service en mode navigation privée.

  • Si le stockage est monté, supprimez les fichiers des répertoires input/, output/ et temp/.

  • Essayez de redémarrer le service.

Q : Le processus redémarre au milieu du workflow

Si les journaux de l'instance contiennent run.sh: line 54: 531285 Killed python -u main_run.py "$@", le processus a été arrêté en raison d'une condition de manque de mémoire (OOM). Le processus redémarre automatiquement après un événement OOM.

Q : RuntimeError: CUDA error: out of memory

Cela signifie que la mémoire GPU est épuisée. Pour les modèles d'images, réduisez la résolution de l'image ou la taille du lot. Pour les modèles vidéo, réduisez le nombre d'images ou la résolution.

Q : L'appel API renvoie « url not found » ou « 404 page not found »

  1. Vérifiez que l'URL du endpoint API est complète. Pour les appels synchrones, vous devez ajouter le chemin /prompt.

Autres

Q : Performances de l'accélération xFormers

xFormers est un outil d'accélération open source basé sur Transformer qui réduit le temps de génération d'images et de vidéos ainsi que l'utilisation de la mémoire GPU.

Les images ComfyUI ont l'accélération xFormers activée par défaut. L'effet d'accélération dépend de la taille du workflow, avec des améliorations plus notables sur les opérations gourmandes en GPU, en particulier avec les GPU NVIDIA.

Étapes suivantes

Après avoir déployé le service ComfyUI, vous pouvez :

  • Surveillance du service : Configurez la surveillance et les alertes pour suivre l'état du service en temps réel. Pour plus d'informations, consultez la section Afficher les métriques de surveillance du service.

  • Auto Scaling : Configurez des politiques Auto Scaling basées sur la charge de travail pour optimiser l'utilisation des ressources et les coûts. Pour plus d'informations, consultez la section Auto Scaling.

  • Optimisation des coûts : Comprenez les méthodes de facturation de PAI-EAS et choisissez le type d'instance et l'édition de déploiement appropriés pour réduire les coûts. Pour plus d'informations, consultez la section Présentation de la facturation.

Référence

Installer des packages Python

Installer un package .whl en exécutant une commande

  1. Assurez-vous que le service dispose d'un montage de stockage configuré. Par exemple, supposons que le chemin OSS (URI) soit oss://examplebucket/comfyui/ et que le chemin de montage soit /mnt/data/.

  2. Téléchargez le fichier .whl dans le répertoire oss://examplebucket/comfyui/models/whl. Si le répertoire whl n'existe pas, créez-le d'abord.

  3. Mettez à jour la section Command to Run du service : ajoutez pip install /mnt/data/models/whl/xxx.whl au début de la commande d'exécution. Dans cette commande, /mnt/data est le chemin de montage OSS, et xxx.whl est le nom du package .whl.

  4. Redémarrez le service.

Installer des packages via la configuration de bibliothèques tierces

  1. Sur la page des détails du service, cliquez sur Update dans le coin supérieur droit.

  2. Si le service a été déployé via un déploiement de modèle basé sur un scénario, passez au déploiement de modèle personnalisé.

  3. Dans la section Environment Information , configurez les dépendances dans la zone Third-party Library Configuration.

  4. Cliquez sur Update en bas de la page pour appliquer la mise à jour.

Mettre à jour la version de l'image

Si le service dispose d'un stockage OSS ou NAS monté, les modèles personnalisés sont stockés dans le stockage OSS ou NAS et ne sont pas affectés par une mise à jour de la version de l'image.

  1. Sur la page des détails du service, cliquez sur Update dans le coin supérieur droit.

  2. Si le service a été déployé via un déploiement de modèle basé sur un scénario, passez au déploiement de modèle personnalisé.

  3. Dans la section Service Configuration , modifiez la configuration JSON et mettez à jour le champ image sous containers vers la version souhaitée (par exemple, changez 1.9 par la version cible).

  4. Cliquez sur Update Directly.

Générer une URL sans connexion avec une période de validité personnalisée

Vous pouvez utiliser une API pour générer une URL d'accès Web sans connexion avec une période de validité spécifiée.

  1. Accédez à la page de l'API DescribeServiceSignedUrl.

  2. Sélectionnez le endpoint du service.

  3. Définissez les paramètres suivants :

    • ClusterId (Region) et ServiceName : Saisissez la région et le nom du service.

      Sur la page de présentation du service EAS, le champ Service Name affiche la valeur ServiceName. La région est intégrée dans l'adresse de l'image du nœud (par exemple, cn-hangzhou correspond à la valeur de région ClusterId). Vous pouvez cliquer sur View Web Application dans le coin supérieur droit pour ouvrir le service.

    • Type (Page type) : Sélectionnez webview dans la liste déroulante.

    • Expire (Expiration time) : Saisissez un entier en secondes. La valeur maximale est de 43 200 secondes (12 heures). Définissez cette valeur selon vos besoins.

    • Internal (VPC access) : Définissez sur false (accès public) ou true (accès VPC).

  4. Cliquez sur Call API. Le champ SignedUrl dans la réponse contient l'URL d'accès Web sans connexion.

Modifier la langue par défaut de l'interface Web

  1. Sur la page de l'interface Web, cliquez sur le bouton Settings dans le coin inférieur gauche.

  2. Configurez la langue aux deux emplacements suivants, puis actualisez et rechargez la page.

    • Comfy > Locale.

    • Language > Locale.

Annexe

Fonctionnement de l'édition Cluster

Le diagramme suivant illustre l'architecture :

image

L'édition Cluster est conçue pour les scénarios multi-utilisateurs. Elle introduit une couche proxy qui découple les clients des instances d'inférence backend.

  • Chaque utilisateur dispose d'un environnement backend et d'un répertoire de travail indépendants, mais partage le pool d'instances d'inférence GPU backend.

  • Lorsqu'un utilisateur envoie une requête d'inférence, le proxy sélectionne une instance disponible dans le pool pour traiter la requête.

Ce mécanisme de multiplexage temporel isole les environnements utilisateur tout en maximisant l'utilisation des ressources GPU et en réduisant les coûts d'inférence dans les scénarios multi-utilisateurs.