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

## はじめに

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

---

<blockquote class="twitter-tweet" data-media-max-width="560"><p lang="ja" dir="ltr">PyGiCo改修中。。。<br>ComfyuiのFLUXをAPIで呼び出してPythonで実行してみた！<br>これは使えそう！！！ <a href="https://t.co/tp0lsnZswD">https://t.co/tp0lsnZswD</a> <a href="https://t.co/xIxdgCsclD">pic.twitter.com/xIxdgCsclD</a></p>&mdash; Maki@Sunwood AI Labs. (@hAru_mAki_ch) <a href="https://twitter.com/hAru_mAki_ch/status/1820466771461378106?ref_src=twsrc%5Etfw">August 5, 2024</a></blockquote> 

---

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

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


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

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

```bash
pip install rich pyfiglet
```

## Pythonスクリプトの作成

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

```python
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()

```

## スクリプトの実行

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

```bash
(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