2025年6月11日水曜日

stable-diffusion-webui-forge で API を使ってテキストから画像を生成する方

stable-diffusion-webui-forge で API を使ってテキストから画像を生成する方

概要

stable-diffusion-webui-forge の REST API を使って画像を生成する方法を紹介します

環境

  • macOS 15.5
  • stable-diffusion-web-ui-forge f2.0.1v1.10.1-previous-664-gd557aef9

API の起動

  • ./webui.sh --force-upcast-attention --api

--api オプションを付与して起動します

API リクエストに必要なペイロードを生成できるようにする

https://github.com/huchenlei/sd-webui-api-payload-display をインストールします

これで画像を生成後にその画像を API で生成した際の JSON ペイロードが確認できるようになります

生成されるペイロードには拡張機能用のペイロードを含まれるので不要なものは削除して OK です

以下のサンプルではすべてのペイロードを表示しています

ライブラリインストール

  • pipenv install Pillow requests

テキストから画像生成

レスポンスの兼ね合いで Python などのプログラムから実行することをおすすめします
ペイロードは JSON 文字列なのでプロンプトなどに改行コードが含まれる場合は削除してください
また true/false/null は True/False/None に置き換えて Python の辞書として使えるようにしておきましょう

import base64
import io

import requests
from PIL import Image, PngImagePlugin

model_name = "AnythingXL_xl.safetensors"
payload = {
    "alwayson_scripts": {
        "ADetailer": {
            "args": [
                False,
                False,
                {
                    "ad_cfg_scale": 7,
                    "ad_checkpoint": "Use same checkpoint",
                    "ad_clip_skip": 1,
                    "ad_confidence": 0.3,
                    "ad_controlnet_guidance_end": 1,
                    "ad_controlnet_guidance_start": 0,
                    "ad_controlnet_model": "None",
                    "ad_controlnet_module": "None",
                    "ad_controlnet_weight": 1,
                    "ad_denoising_strength": 0.4,
                    "ad_dilate_erode": 4,
                    "ad_inpaint_height": 512,
                    "ad_inpaint_only_masked": True,
                    "ad_inpaint_only_masked_padding": 32,
                    "ad_inpaint_width": 512,
                    "ad_mask_blur": 4,
                    "ad_mask_filter_method": "Area",
                    "ad_mask_k": 0,
                    "ad_mask_max_ratio": 1,
                    "ad_mask_merge_invert": "None",
                    "ad_mask_min_ratio": 0,
                    "ad_model": "face_yolov8n.pt",
                    "ad_model_classes": "",
                    "ad_negative_prompt": "",
                    "ad_noise_multiplier": 1,
                    "ad_prompt": "",
                    "ad_restore_face": False,
                    "ad_sampler": "DPM++ 2M",
                    "ad_scheduler": "Use same scheduler",
                    "ad_steps": 28,
                    "ad_tab_enable": True,
                    "ad_use_cfg_scale": False,
                    "ad_use_checkpoint": False,
                    "ad_use_clip_skip": False,
                    "ad_use_inpaint_width_height": False,
                    "ad_use_noise_multiplier": False,
                    "ad_use_sampler": False,
                    "ad_use_steps": False,
                    "ad_use_vae": False,
                    "ad_vae": "Use same VAE",
                    "ad_x_offset": 0,
                    "ad_y_offset": 0,
                    "is_api": [],
                },
                {
                    "ad_cfg_scale": 7,
                    "ad_checkpoint": "Use same checkpoint",
                    "ad_clip_skip": 1,
                    "ad_confidence": 0.3,
                    "ad_controlnet_guidance_end": 1,
                    "ad_controlnet_guidance_start": 0,
                    "ad_controlnet_model": "None",
                    "ad_controlnet_module": "None",
                    "ad_controlnet_weight": 1,
                    "ad_denoising_strength": 0.4,
                    "ad_dilate_erode": 4,
                    "ad_inpaint_height": 512,
                    "ad_inpaint_only_masked": True,
                    "ad_inpaint_only_masked_padding": 32,
                    "ad_inpaint_width": 512,
                    "ad_mask_blur": 4,
                    "ad_mask_filter_method": "Area",
                    "ad_mask_k": 0,
                    "ad_mask_max_ratio": 1,
                    "ad_mask_merge_invert": "None",
                    "ad_mask_min_ratio": 0,
                    "ad_model": "None",
                    "ad_model_classes": "",
                    "ad_negative_prompt": "",
                    "ad_noise_multiplier": 1,
                    "ad_prompt": "",
                    "ad_restore_face": False,
                    "ad_sampler": "DPM++ 2M",
                    "ad_scheduler": "Use same scheduler",
                    "ad_steps": 28,
                    "ad_tab_enable": True,
                    "ad_use_cfg_scale": False,
                    "ad_use_checkpoint": False,
                    "ad_use_clip_skip": False,
                    "ad_use_inpaint_width_height": False,
                    "ad_use_noise_multiplier": False,
                    "ad_use_sampler": False,
                    "ad_use_steps": False,
                    "ad_use_vae": False,
                    "ad_vae": "Use same VAE",
                    "ad_x_offset": 0,
                    "ad_y_offset": 0,
                    "is_api": [],
                },
                {
                    "ad_cfg_scale": 7,
                    "ad_checkpoint": "Use same checkpoint",
                    "ad_clip_skip": 1,
                    "ad_confidence": 0.3,
                    "ad_controlnet_guidance_end": 1,
                    "ad_controlnet_guidance_start": 0,
                    "ad_controlnet_model": "None",
                    "ad_controlnet_module": "None",
                    "ad_controlnet_weight": 1,
                    "ad_denoising_strength": 0.4,
                    "ad_dilate_erode": 4,
                    "ad_inpaint_height": 512,
                    "ad_inpaint_only_masked": True,
                    "ad_inpaint_only_masked_padding": 32,
                    "ad_inpaint_width": 512,
                    "ad_mask_blur": 4,
                    "ad_mask_filter_method": "Area",
                    "ad_mask_k": 0,
                    "ad_mask_max_ratio": 1,
                    "ad_mask_merge_invert": "None",
                    "ad_mask_min_ratio": 0,
                    "ad_model": "None",
                    "ad_model_classes": "",
                    "ad_negative_prompt": "",
                    "ad_noise_multiplier": 1,
                    "ad_prompt": "",
                    "ad_restore_face": False,
                    "ad_sampler": "DPM++ 2M",
                    "ad_scheduler": "Use same scheduler",
                    "ad_steps": 28,
                    "ad_tab_enable": True,
                    "ad_use_cfg_scale": False,
                    "ad_use_checkpoint": False,
                    "ad_use_clip_skip": False,
                    "ad_use_inpaint_width_height": False,
                    "ad_use_noise_multiplier": False,
                    "ad_use_sampler": False,
                    "ad_use_steps": False,
                    "ad_use_vae": False,
                    "ad_vae": "Use same VAE",
                    "ad_x_offset": 0,
                    "ad_y_offset": 0,
                    "is_api": [],
                },
                {
                    "ad_cfg_scale": 7,
                    "ad_checkpoint": "Use same checkpoint",
                    "ad_clip_skip": 1,
                    "ad_confidence": 0.3,
                    "ad_controlnet_guidance_end": 1,
                    "ad_controlnet_guidance_start": 0,
                    "ad_controlnet_model": "None",
                    "ad_controlnet_module": "None",
                    "ad_controlnet_weight": 1,
                    "ad_denoising_strength": 0.4,
                    "ad_dilate_erode": 4,
                    "ad_inpaint_height": 512,
                    "ad_inpaint_only_masked": True,
                    "ad_inpaint_only_masked_padding": 32,
                    "ad_inpaint_width": 512,
                    "ad_mask_blur": 4,
                    "ad_mask_filter_method": "Area",
                    "ad_mask_k": 0,
                    "ad_mask_max_ratio": 1,
                    "ad_mask_merge_invert": "None",
                    "ad_mask_min_ratio": 0,
                    "ad_model": "None",
                    "ad_model_classes": "",
                    "ad_negative_prompt": "",
                    "ad_noise_multiplier": 1,
                    "ad_prompt": "",
                    "ad_restore_face": False,
                    "ad_sampler": "DPM++ 2M",
                    "ad_scheduler": "Use same scheduler",
                    "ad_steps": 28,
                    "ad_tab_enable": True,
                    "ad_use_cfg_scale": False,
                    "ad_use_checkpoint": False,
                    "ad_use_clip_skip": False,
                    "ad_use_inpaint_width_height": False,
                    "ad_use_noise_multiplier": False,
                    "ad_use_sampler": False,
                    "ad_use_steps": False,
                    "ad_use_vae": False,
                    "ad_vae": "Use same VAE",
                    "ad_x_offset": 0,
                    "ad_y_offset": 0,
                    "is_api": [],
                },
            ]
        },
        "API payload": {"args": []},
        "ControlNet": {
            "args": [
                {
                    "batch_image_dir": "",
                    "batch_input_gallery": None,
                    "batch_mask_dir": "",
                    "batch_mask_gallery": None,
                    "control_mode": "Balanced",
                    "enabled": False,
                    "generated_image": None,
                    "guidance_end": 1.0,
                    "guidance_start": 0.0,
                    "hr_option": "Both",
                    "image": None,
                    "image_fg": None,
                    "input_mode": "simple",
                    "mask_image": None,
                    "mask_image_fg": None,
                    "model": "None",
                    "module": "None",
                    "pixel_perfect": False,
                    "processor_res": -1,
                    "resize_mode": "Crop and Resize",
                    "save_detected_map": True,
                    "threshold_a": -1,
                    "threshold_b": -1,
                    "use_preview_as_input": False,
                    "weight": 1,
                },
                {
                    "batch_image_dir": "",
                    "batch_input_gallery": None,
                    "batch_mask_dir": "",
                    "batch_mask_gallery": None,
                    "control_mode": "Balanced",
                    "enabled": False,
                    "generated_image": None,
                    "guidance_end": 1.0,
                    "guidance_start": 0.0,
                    "hr_option": "Both",
                    "image": None,
                    "image_fg": None,
                    "input_mode": "simple",
                    "mask_image": None,
                    "mask_image_fg": None,
                    "model": "None",
                    "module": "None",
                    "pixel_perfect": False,
                    "processor_res": -1,
                    "resize_mode": "Crop and Resize",
                    "save_detected_map": True,
                    "threshold_a": -1,
                    "threshold_b": -1,
                    "use_preview_as_input": False,
                    "weight": 1,
                },
                {
                    "batch_image_dir": "",
                    "batch_input_gallery": None,
                    "batch_mask_dir": "",
                    "batch_mask_gallery": None,
                    "control_mode": "Balanced",
                    "enabled": False,
                    "generated_image": None,
                    "guidance_end": 1.0,
                    "guidance_start": 0.0,
                    "hr_option": "Both",
                    "image": None,
                    "image_fg": None,
                    "input_mode": "simple",
                    "mask_image": None,
                    "mask_image_fg": None,
                    "model": "None",
                    "module": "None",
                    "pixel_perfect": False,
                    "processor_res": -1,
                    "resize_mode": "Crop and Resize",
                    "save_detected_map": True,
                    "threshold_a": -1,
                    "threshold_b": -1,
                    "use_preview_as_input": False,
                    "weight": 1,
                },
            ]
        },
        "Dynamic Prompts v2.17.1": {
            "args": [
                True,
                False,
                1,
                False,
                False,
                False,
                1.1,
                1.5,
                100,
                0.7,
                False,
                False,
                True,
                False,
                False,
                0,
                "Gustavosta/MagicPrompt-Stable-Diffusion",
                "",
            ]
        },
        "DynamicThresholding (CFG-Fix) Integrated": {
            "args": [
                False,
                7,
                1,
                "Constant",
                0,
                "Constant",
                0,
                1,
                "enable",
                "MEAN",
                "AD",
                1,
            ]
        },
        "Extra options": {"args": []},
        "FreeU Integrated (SD 1.x, SD 2.x, SDXL)": {
            "args": [False, 1.01, 1.02, 0.99, 0.95, 0, 1]
        },
        "Kohya HRFix Integrated": {
            "args": [False, 3, 2, 0, 0.35, True, "bicubic", "bicubic"]
        },
        "LatentModifier Integrated": {
            "args": [
                False,
                0,
                "anisotropic",
                0,
                "reinhard",
                100,
                0,
                "subtract",
                0,
                0,
                "gaussian",
                "add",
                0,
                100,
                127,
                0,
                "hard_clamp",
                5,
                0,
                "None",
                "None",
            ]
        },
        "MultiDiffusion Integrated": {
            "args": [False, "MultiDiffusion", 768, 768, 64, 4]
        },
        "Never OOM Integrated": {"args": [False, False]},
        "PerturbedAttentionGuidance Integrated": {"args": [False, 3, 0, 0, 1]},
        "Refiner": {"args": [False, "", 0.8]},
        "Sampler": {"args": [20, "DPM++ 2M SDE", "Karras"]},
        "Seed": {"args": [-1, False, -1, 0, 0, 0]},
        "SelfAttentionGuidance Integrated (SD 1.x, SD 2.x, SDXL)": {
            "args": [False, 0.5, 2, 1]
        },
        "StyleAlign Integrated": {"args": [False, 1]},
    },
    "batch_size": 1,
    "cfg_scale": 5,
    "comments": {},
    "denoising_strength": 0.7,
    "disable_extra_networks": False,
    "distilled_cfg_scale": 3.5,
    "do_not_save_grid": False,
    "do_not_save_samples": False,
    "enable_hr": False,
    "height": 1152,
    "hr_additional_modules": ["Use same choices"],
    "hr_cfg": 5,
    "hr_distilled_cfg": 3.5,
    "hr_negative_prompt": "",
    "hr_prompt": "",
    "hr_resize_x": 0,
    "hr_resize_y": 0,
    "hr_scale": 2,
    "hr_second_pass_steps": 0,
    "hr_upscaler": "Latent",
    "n_iter": 1,
    "negative_prompt": "low quality, worst quality, lowres, blurry, jpeg artifacts, text, watermark, error, extra limbs, mutated hands, poorly drawn hands, bad anatomy, unrealistic eyes, cloned face, multiple heads, bad proportions, out of frame, heavy makeup",
    "override_settings": {
        "sd_model_checkpoint": model_name,
    },
    "override_settings_restore_afterwards": True,
    "prompt": "masterpiece, best quality, ultra-detailed, 8k, cinematic lighting,\nbeautiful japanese young women, 20age, fair skin, light makeup, realistic face,\nlooking at viewer,\nbrown short hair,\nsmile,\npark background,\nsleeveless blouse, flare skirt,",
    "restore_faces": False,
    "s_churn": 0,
    "s_min_uncond": 0,
    "s_noise": 1,
    "s_tmax": None,
    "s_tmin": 0,
    "sampler_name": "DPM++ 2M SDE",
    "scheduler": "Karras",
    "script_args": [],
    "script_name": None,
    "seed": 1752460840,
    "seed_enable_extras": True,
    "seed_resize_from_h": -1,
    "seed_resize_from_w": -1,
    "steps": 20,
    "styles": [],
    "subseed": 33927003,
    "subseed_strength": 0,
    "tiling": False,
    "width": 896,
}

url = "http://127.0.0.1:7860"
response = requests.post(url=f"{url}/sdapi/v1/txt2img", json=payload)

r = response.json()

for index, image_info in enumerate(r["images"]):
    image = Image.open(io.BytesIO(base64.b64decode(image_info.split(",", 1)[0])))

    png_payload = {"image": "data:image/png;base64," + image_info}
    response_png_info = requests.post(url=f"{url}/sdapi/v1/png-info", json=png_payload)

    pnginfo = PngImagePlugin.PngInfo()
    pnginfo.add_text("parameters", response_png_info.json().get("info"))
    image.save(f"output_{index}.png", pnginfo=pnginfo)

override_settings は指定しない場合 sd-webui 上で指定しているモデルが使われます
基本は指定することをおすすめします

レスポンスはバイト情報なのでそこから画像を生成します
API では stable-diffusion-webui 側に画像は自動で保存されません

ただわざわざ保存しないでも stable-diffusion-webui 側にはちゃんと保存されているのでそれを参照するのであればわざわざレスポンスを保存しないでも OK です

API リファレンス

http://localhost:7860/docs にアクセスすると確認できます

最後に

stable-diffusion-webui-forge の REST API を使って Python スクリプトから画像を生成してみました
プロンプト情報などもコードで管理できるようになるのでかなり便利です
cron など自動実行などを仕掛けておけば勝手ガチャしてくれるようになります

Python スクリプトや流れは複雑になりますが XYZ-plot や Hires Fix などもできるので仕上げまで全自動にすることも可能かなと思います

参考サイト

0 件のコメント:

コメントを投稿