はじめに
ComfyUIは強力な画像生成ツールであり、FLUXモデルはその中でも特に注目される新しいモデルです。この記事では、Pythonスクリプトを使用してComfyUI FLUXモデルをAPIで呼び出し、画像を生成する方法を解説します。
PyGiCo改修中。。。
ComfyuiのFLUXをAPIで呼び出してPythonで実行してみた!
これは使えそう!!! https://t.co/tp0lsnZswD pic.twitter.com/xIxdgCsclD— Maki@Sunwood AI Labs. (@hAru_mAki_ch) August 5, 2024
PythonでComfyUIのAPIを操作してブログ記事用の自動画像生成システムの構築
はじめにブログの魅力を高める上で、適切な画像の使用は非常に重要です。しかし、毎回手動で画像を選択したり作成したりするのは、時間と労力がかかります。そこで、ブログの内容に基づいて自動的に画像を生成するシステムを構築することで、この問題を解決で...
ComfyUIでFlux AIを使う方法:詳細ガイド
はじめにFlux AIは、高品質な画像生成を可能にする強力なAIモデルです。本記事では、ComfyUI上でFlux AIを使用するための詳細な手順を解説します。初心者の方でも理解しやすいよう、ステップごとに丁寧に説明していきます。きたーーー...
必要なライブラリのインストール
まず、必要なライブラリをインストールします。以下のコマンドを実行してください:
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>
結果の解説
このスクリプトは以下の操作を行います:
- カスタムワークフローを読み込みます(
workflow\workflow_api_flux.json
)。 - "Photorealistic landscape"というプロンプトを設定します。
- ランダムなシード値を生成します(この例では737586)。
- プロンプトをComfyUIサーバーにキューイングします。
注意点
- このスクリプトを実行する前に、ComfyUIサーバーが起動していることを確認してください。
workflow_api_flux.json
ファイルが正しいパスに配置されていることを確認してください。- FLUXモデルが正しくComfyUIにインストールされていることを確認してください。
まとめ
このPythonスクリプトを使用することで、ComfyUIのFLUXモデルをプログラマティックに制御し、高品質な画像を生成することができます。プロンプトやシード値を変更することで、さまざまな画像を生成することが可能です。
リポジトリ
PyGiCo/example/python_usage_flux_simple.py at main · Sunwood-ai-labs/PyGiCo
Seamless ComfyUI Integration. Contribute to Sunwood-ai-labs/PyGiCo development by creating an account on GitHub.
コメント