FLUXをComfyUIのAPIからPythonで使用する方法

に公開

はじめに

ComfyUIは強力な画像生成ツールであり、FLUXモデルはその中でも特に注目される新しいモデルです。この記事では、Pythonスクリプトを使用してComfyUI FLUXモデルをAPIで呼び出し、画像を生成する方法を解説します。



https://hamaruki.com/python-comfyui-api-automated-image-generation/

https://hamaruki.com/using-flux-ai-comfyui-detailed-guide/

必要なライブラリのインストール

まず、必要なライブラリをインストールします。以下のコマンドを実行してください:

pip install rich pyfiglet

Pythonスクリプトの作成

以下のPythonスクリプトを作成します。このスクリプトは、ComfyUIのFLUXモデルを使用して画像を生成します。

import json
from urllib import request
import random
import os
from typing import Dict, Any, Optional
from rich.console import Console
from rich.panel import Panel
from rich.progress import Progress, SpinnerColumn, TextColumn
from rich.syntax import Syntax
from rich import print as rprint
from art import text2art
from pyfiglet import Figlet
from rich.text import Text

class ComfyUIPromptGeneratorFlux:
    """ComfyUIのプロンプトを生成し、サーバーにキューイングするクラス"""

    def __init__(self, server_address: str = "127.0.0.1:8188", workflow_path: Optional[str] = None):
        """
        コンストラクタ: クラスの初期化を行います
        
        :param server_address: ComfyUIサーバーのアドレス(デフォルトは localhost の 8188 ポート)
        :param workflow_path: ワークフローJSONファイルへのパス(デフォルトはNone)
        """
        self.console = Console(width=120)
        self.server_address = server_address
        
        if workflow_path is None:
            self.workflow_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'workflow_api.json')
        else:
            self.workflow_path = workflow_path
        
        self.prompt = self._load_workflow()

    def _load_workflow(self) -> Dict[str, Any]:
        """ワークフローJSONファイルを読み込むプライベートメソッド"""
        try:
            with Progress(
                SpinnerColumn(),
                TextColumn("[progress.description]{task.description}"),
                console=self.console
            ) as progress:
                task = progress.add_task("[cyan]Loading workflow...", total=None)
                with open(self.workflow_path, 'r') as file:
                    workflow = json.load(file)
                progress.update(task, completed=True)
            self.console.print(Panel(f"[green]Workflow loaded successfully from {self.workflow_path}[/green]"))
            return workflow
        except FileNotFoundError:
            self.console.print(Panel(f"[red]Workflow file not found: {self.workflow_path}[/red]", title="Error"))
            raise
        except json.JSONDecodeError:
            self.console.print(Panel(f"[red]Invalid JSON in workflow file: {self.workflow_path}[/red]", title="Error"))
            raise ValueError(f"Invalid JSON in workflow file: {self.workflow_path}")

    def set_clip_text(self, text: str, node_id: str = "283") -> None:
        """CLIPTextEncodeノードのテキストを設定するメソッド"""
        self.prompt[node_id]["inputs"]["text"] = text
        self.console.print(f"[yellow]CLIP text set to:[/yellow] {text}")

    def set_random_seed(self, node_id: str = "271") -> None:
        """KSamplerノードのシードをランダムに設定するメソッド"""
        seed = random.randint(1, 1_000_000)
        self.prompt[node_id]["inputs"]["noise_seed"] = seed
        self.console.print(f"[yellow]Random seed set to:[/yellow] {seed}")

    def queue_prompt(self) -> None:
        """プロンプトをComfyUIサーバーにキューイングするメソッド"""
        data = json.dumps({"prompt": self.prompt}).encode('utf-8')
        req = request.Request(f"http://{self.server_address}/prompt", data=data, headers={'Content-Type': 'application/json'})
        
        with Progress(
            SpinnerColumn(),
            TextColumn("[progress.description]{task.description}"),
            console=self.console
        ) as progress:
            task = progress.add_task("[cyan]Queueing prompt...", total=None)
            try:
                request.urlopen(req)
                progress.update(task, completed=True)
                self.console.print(Panel("[green]Prompt queued successfully[/green]"))
            except Exception as e:
                progress.update(task, completed=True)
                self.console.print(Panel(f"[red]Failed to queue prompt: {str(e)}[/red]", title="Error"))
                raise ConnectionError(f"Failed to queue prompt: {str(e)}")

    def generate_and_queue(self, clip_text: str) -> None:
        """プロンプトを生成し、キューイングするメソッド"""
        self.console.rule("[bold blue]Generating and Queueing Prompt")
        self.set_clip_text(text=clip_text, node_id="6")
        self.set_random_seed(node_id="25")
        self.queue_prompt()
        self.console.rule("[bold blue]Process Completed")

    def display_prompt(self) -> None:
        """現在のプロンプトを表示するメソッド"""
        prompt_json = json.dumps(self.prompt, indent=2)
        syntax = Syntax(prompt_json, "json", theme="monokai", line_numbers=True)
        self.console.print(Panel(syntax, title="Current Prompt", expand=True))

if __name__ == "__main__":
    console = Console(width=220)
    # Figletを使用してASCIIアートを生成
    f = Figlet(font='slant', width=200)
    title = f.renderText('ComfyUI Prompt Generator')
    
    # ASCIIアートをRichのTextオブジェクトに変換し、色を付ける
    title_text = Text.from_ansi(title)
    title_text.stylize("bold magenta")
    
    # パネル内にASCIIアートを表示
    console.print(Panel(title_text, expand=False, border_style="bold blue"))
    
    console.print(Panel("[bold cyan]ComfyUI Prompt Generator Demo[/bold cyan]"))

    console.rule("[bold green]Using Custom Workflow")
    
    # カスタムワークフローパスを指定
    custom_workflow_path = r"workflow\workflow_api_flux.json"
    custom_generator = ComfyUIPromptGeneratorFlux(workflow_path=custom_workflow_path)
    custom_generator.generate_and_queue("Photorealistic landscape")
    custom_generator.display_prompt()

スクリプトの実行

スクリプトを実行すると、以下のような出力が得られます:

(pygico-imagegen-py3.12) C:\Prj\PyGiCo>python example\python_usage_flux_simple.py
╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
    ______                ____      __  ______   ____                             __     ______                           __
   / ____/___  ____ ___  / __/_  __/ / / /  _/  / __ \_________  ____ ___  ____  / /_   / ____/__  ____  ___  _________ _/ /_____  _____
  / /   / __ \/ __ `__ \/ /_/ / / / / / // /   / /_/ / ___/ __ \/ __ `__ \/ __ \/ __/  / / __/ _ \/ __ \/ _ \/ ___/ __ `/ __/ __ \/ ___/ │
 / /___/ /_/ / / / / / / __/ /_/ / /_/ // /   / ____/ /  / /_/ / / / / / / /_/ / /_   / /_/ /  __/ / / /  __/ /  / /_/ / /_/ /_/ / /     │
 \____/\____/_/ /_/ /_/_/  \__, /\____/___/  /_/   /_/   \____/_/ /_/ /_/ .___/\__/   \____/\___/_/ /_/\___/_/   \__,_/\__/\____/_/      │
                          /____/                                       /_/                                                               │
╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
 ComfyUI Prompt Generator Demo                                                                                                                                                                                            

╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
────────────────────────────────────────────────────────────────────────────────────────────────── Using Custom Workflow ───────────────────────────────────────────────────────────────────────────────────────────────────
 Loading workflow...
╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
 Workflow loaded successfully from workflow\workflow_api_flux.json                                                    │
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
──────────────────────────────────────────── Generating and Queueing Prompt ────────────────────────────────────────────
CLIP text set to: Photorealistic landscape
Random seed set to: 737586
╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
 Prompt queued successfully                                                                                           │
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
 Queueing prompt...
────────────────────────────────────────────────── Process Completed ───────────────────────────────────────────────────
╭─────────────────────────────────────────────────── Current Prompt ───────────────────────────────────────────────────╮
     1 {                                                                                                              │
     2   "5": {                                                                                                       │
     3     "inputs": {                                                                                                │
     4       "width": 1920,                                                                                           │
     5       "height": 1024,                                                                                          │
     6       "batch_size": 1
     7     },                                                                                                         │
     8     "class_type": "EmptyLatentImage",                                                                          │
     9     "_meta": {                                                                                                 │
    10       "title": "Empty Latent Image"                                                                            │
    11     }                                                                                                          │
    12   },                                                                                                           │
    13   "6": {                                                                                                       │
    14     "inputs": {                                                                                                │
    15       "text": "Photorealistic landscape",                                                                      │
    16       "clip": [                                                                                                │
    17         "11",                                                                                                  │
    18         0
    19       ]                                                                                                        │
    20     },                                                                                                         │
    21     "class_type": "CLIPTextEncode",                                                                            │
    22     "_meta": {                                                                                                 │
    23       "title": "CLIP Text Encode (Prompt)"                                                                     │
    24     }                                                                                                          │
    25   },                                                                                                           │
    26   "8": {                                                                                                       │
    27     "inputs": {                                                                                                │
    28       "samples": [                                                                                             │
    29         "13",                                                                                                  │
    30         0
    31       ],                                                                                                       │
    32       "vae": [                                                                                                 │
    33         "10",                                                                                                  │
    34         0
    35       ]                                                                                                        │
    36     },                                                                                                         │
    37     "class_type": "VAEDecode",                                                                                 │
    38     "_meta": {                                                                                                 │
    39       "title": "VAE Decode"                                                                                    │
    40     }                                                                                                          │
    41   },                                                                                                           │
    42   "9": {                                                                                                       │
    43     "inputs": {                                                                                                │
    44       "filename_prefix": "ComfyUI",                                                                            │
    45       "images": [                                                                                              │
    46         "8",                                                                                                   │
    47         0
    48       ]                                                                                                        │
    49     },                                                                                                         │
    50     "class_type": "SaveImage",                                                                                 │
    51     "_meta": {                                                                                                 │
    52       "title": "Save Image"                                                                                    │
    53     }                                                                                                          │
    54   },                                                                                                           │
    55   "10": {                                                                                                      │
    56     "inputs": {                                                                                                │
    57       "vae_name": "ae.sft"                                                                                     │
    58     },                                                                                                         │
    59     "class_type": "VAELoader",                                                                                 │
    60     "_meta": {                                                                                                 │
    61       "title": "Load VAE"                                                                                      │
    62     }                                                                                                          │
    63   },                                                                                                           │
    64   "11": {                                                                                                      │
    65     "inputs": {                                                                                                │
    66       "clip_name1": "t5xxl_fp16.safetensors",                                                                  │
    67       "clip_name2": "clip_l_flux.safetensors",                                                                 │
    68       "type": "flux"                                                                                           │
    69     },                                                                                                         │
    70     "class_type": "DualCLIPLoader",                                                                            │
    71     "_meta": {                                                                                                 │
    72       "title": "DualCLIPLoader"                                                                                │
    73     }                                                                                                          │
    74   },                                                                                                           │
    75   "12": {                                                                                                      │
    76     "inputs": {                                                                                                │
    77       "unet_name": "flux1-dev.sft",                                                                            │
    78       "weight_dtype": "default"                                                                                │
    79     },                                                                                                         │
    80     "class_type": "UNETLoader",                                                                                │
    81     "_meta": {                                                                                                 │
    82       "title": "Load Diffusion Model"                                                                          │
    83     }                                                                                                          │
    84   },                                                                                                           │
    85   "13": {                                                                                                      │
    86     "inputs": {                                                                                                │
    87       "noise": [                                                                                               │
    88         "25",                                                                                                  │
    89         0
    90       ],                                                                                                       │
    91       "guider": [                                                                                              │
    92         "22",                                                                                                  │
    93         0
    94       ],                                                                                                       │
    95       "sampler": [                                                                                             │
    96         "16",                                                                                                  │
    97         0
    98       ],                                                                                                       │
    99       "sigmas": [                                                                                              │
   100         "17",                                                                                                  │
   101         0
   102       ],                                                                                                       │
   103       "latent_image": [                                                                                        │
   104         "5",                                                                                                   │
   105         0
   106       ]                                                                                                        │
   107     },                                                                                                         │
   108     "class_type": "SamplerCustomAdvanced",                                                                     │
   109     "_meta": {                                                                                                 │
   110       "title": "SamplerCustomAdvanced"                                                                         │
   111     }                                                                                                          │
   112   },                                                                                                           │
   113   "16": {                                                                                                      │
   114     "inputs": {                                                                                                │
   115       "sampler_name": "euler"                                                                                  │
   116     },                                                                                                         │
   117     "class_type": "KSamplerSelect",                                                                            │
   118     "_meta": {                                                                                                 │
   119       "title": "KSamplerSelect"                                                                                │
   120     }                                                                                                          │
   121   },                                                                                                           │
   122   "17": {                                                                                                      │
   123     "inputs": {                                                                                                │
   124       "scheduler": "simple",                                                                                   │
   125       "steps": 30,                                                                                             │
   126       "denoise": 1,                                                                                            │
   127       "model": [                                                                                               │
   128         "12",                                                                                                  │
   124       "scheduler": "simple",                                                                                   │
   125       "steps": 30,                                                                                             │
   126       "denoise": 1,                                                                                            │
   127       "model": [                                                                                               │
   128         "12",                                                                                                  │
   125       "steps": 30,                                                                                             │
   126       "denoise": 1,                                                                                            │
   127       "model": [                                                                                               │
   128         "12",                                                                                                  │
   126       "denoise": 1,                                                                                            │
   127       "model": [                                                                                               │
   128         "12",                                                                                                  │
   129         0
   127       "model": [                                                                                               │
   128         "12",                                                                                                  │
   129         0
   129         0
   130       ]                                                                                                        │
   131     },                                                                                                         │
   130       ]                                                                                                        │
   131     },                                                                                                         │
   131     },                                                                                                         │
   132     "class_type": "BasicScheduler",                                                                            │
   132     "class_type": "BasicScheduler",                                                                            │
   133     "_meta": {                                                                                                 │
   133     "_meta": {                                                                                                 │
   134       "title": "BasicScheduler"                                                                                │
   135     }                                                                                                          │
   134       "title": "BasicScheduler"                                                                                │
   135     }                                                                                                          │
   135     }                                                                                                          │
   136   },                                                                                                           │
   137   "22": {                                                                                                      │
   137   "22": {                                                                                                      │
   138     "inputs": {                                                                                                │
   139       "model": [                                                                                               │
   140         "12",                                                                                                  │
   139       "model": [                                                                                               │
   140         "12",                                                                                                  │
   141         0
   142       ],                                                                                                       │
   140         "12",                                                                                                  │
   141         0
   142       ],                                                                                                       │
   141         0
   142       ],                                                                                                       │
   142       ],                                                                                                       │
   143       "conditioning": [                                                                                        │
   144         "6",                                                                                                   │
   145         0
   146       ]                                                                                                        │
   147     },                                                                                                         │
   148     "class_type": "BasicGuider",                                                                               │
   149     "_meta": {                                                                                                 │
   150       "title": "BasicGuider"                                                                                   │
   143       "conditioning": [                                                                                        │
   144         "6",                                                                                                   │
   145         0
   146       ]                                                                                                        │
   147     },                                                                                                         │
   148     "class_type": "BasicGuider",                                                                               │
   149     "_meta": {                                                                                                 │
   143       "conditioning": [                                                                                        │
   144         "6",                                                                                                   │
   145         0
   146       ]                                                                                                        │
   147     },                                                                                                         │
   148     "class_type": "BasicGuider",                                                                               │
   143       "conditioning": [                                                                                        │
   144         "6",                                                                                                   │
   145         0
   146       ]                                                                                                        │
   147     },                                                                                                         │
   143       "conditioning": [                                                                                        │
   144         "6",                                                                                                   │
   145         0
   146       ]                                                                                                        │
   147     },                                                                                                         │
   143       "conditioning": [                                                                                        │
   144         "6",                                                                                                   │
   145         0
   143       "conditioning": [                                                                                        │
   144         "6",                                                                                                   │
   145         0
   143       "conditioning": [                                                                                        │
   143       "conditioning": [                                                                                        │
   144         "6",                                                                                                   │
   145         0
   146       ]                                                                                                        │
   143       "conditioning": [                                                                                        │
   144         "6",                                                                                                   │
   145         0
   143       "conditioning": [                                                                                        │
   144         "6",                                                                                                   │
   145         0
   143       "conditioning": [                                                                                        │
   143       "conditioning": [                                                                                        │
   144         "6",                                                                                                   │
   143       "conditioning": [                                                                                        │
   143       "conditioning": [                                                                                        │
   144         "6",                                                                                                   │
   145         0
   146       ]                                                                                                        │
   147     },                                                                                                         │
   148     "class_type": "BasicGuider",                                                                               │
   149     "_meta": {                                                                                                 │
   150       "title": "BasicGuider"                                                                                   │
   151     }                                                                                                          │
   152   },                                                                                                           │
   153   "25": {                                                                                                      │
   154     "inputs": {                                                                                                │
   155       "noise_seed": 1112723341199311,                                                                          │
   156       "seed": 737586
   157     },                                                                                                         │
   158     "class_type": "RandomNoise",                                                                               │
   143       "conditioning": [                                                                                        │
   144         "6",                                                                                                   │
   145         0
   146       ]                                                                                                        │
   147     },                                                                                                         │
   148     "class_type": "BasicGuider",                                                                               │
   149     "_meta": {                                                                                                 │
   150       "title": "BasicGuider"                                                                                   │
   151     }                                                                                                          │
   152   },                                                                                                           │
   153   "25": {                                                                                                      │
   154     "inputs": {                                                                                                │
   155       "noise_seed": 1112723341199311,                                                                          │
   143       "conditioning": [                                                                                        │
   144         "6",                                                                                                   │
   145         0
   146       ]                                                                                                        │
   147     },                                                                                                         │
   148     "class_type": "BasicGuider",                                                                               │
   149     "_meta": {                                                                                                 │
   150       "title": "BasicGuider"                                                                                   │
   151     }                                                                                                          │
   152   },                                                                                                           │
   143       "conditioning": [                                                                                        │
   144         "6",                                                                                                   │
   145         0
   146       ]                                                                                                        │
   147     },                                                                                                         │
   148     "class_type": "BasicGuider",                                                                               │
   149     "_meta": {                                                                                                 │
   150       "title": "BasicGuider"                                                                                   │
   143       "conditioning": [                                                                                        │
   144         "6",                                                                                                   │
   145         0
   146       ]                                                                                                        │
   143       "conditioning": [                                                                                        │
   144         "6",                                                                                                   │
   145         0
   143       "conditioning": [                                                                                        │
   144         "6",                                                                                                   │
   143       "conditioning": [                                                                                        │
   144         "6",                                                                                                   │
   143       "conditioning": [                                                                                        │
   143       "conditioning": [                                                                                        │
   143       "conditioning": [                                                                                        │
   144         "6",                                                                                                   │
   145         0
   146       ]                                                                                                        │
   143       "conditioning": [                                                                                        │
   144         "6",                                                                                                   │
   145         0
   143       "conditioning": [                                                                                        │
   144         "6",                                                                                                   │
   143       "conditioning": [                                                                                        │
   143       "conditioning": [                                                                                        │
   143       "conditioning": [                                                                                        │
   144         "6",                                                                                                   │
   145         0
   146       ]                                                                                                        │
   147     },                                                                                                         │
   148     "class_type": "BasicGuider",                                                                               │
   149     "_meta": {                                                                                                 │
   150       "title": "BasicGuider"                                                                                   │
   151     }                                                                                                          │
   152   },                                                                                                           │
   153   "25": {                                                                                                      │
   154     "inputs": {                                                                                                │
   155       "noise_seed": 1112723341199311,                                                                          │
   156       "seed": 737586
   157     },                                                                                                         │
   158     "class_type": "RandomNoise",                                                                               │
   159     "_meta": {                                                                                                 │
   160       "title": "RandomNoise"                                                                                   │
   161     }                                                                                                          │
   162   }                                                                                                            │
   163 }                                                                                                              │
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯

(pygico-imagegen-py3.12) C:\Prj\PyGiCo>

結果の解説

このスクリプトは以下の操作を行います:

  1. カスタムワークフローを読み込みます(workflow\workflow_api_flux.json)。
  2. "Photorealistic landscape"というプロンプトを設定します。
  3. ランダムなシード値を生成します(この例では737586)。
  4. プロンプトをComfyUIサーバーにキューイングします。

注意点

  • このスクリプトを実行する前に、ComfyUIサーバーが起動していることを確認してください。
  • workflow_api_flux.jsonファイルが正しいパスに配置されていることを確認してください。
  • FLUXモデルが正しくComfyUIにインストールされていることを確認してください。

まとめ

このPythonスクリプトを使用することで、ComfyUIのFLUXモデルをプログラマティックに制御し、高品質な画像を生成することができます。プロンプトやシード値を変更することで、さまざまな画像を生成することが可能です。

<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

リポジトリ

https://github.com/Sunwood-ai-labs/PyGiCo/blob/main/example/python_usage_flux_simple.py

Discussion