📑

stable diffusion webuiのAPIを使う方法

2023/07/18に公開

AUTOMATIC1111のstable diffusion webuiのAPIを使います。

以下のものの使い方がわかります。

  • webuiのAPIの起動方法
  • APIを使ってt2i、i2iの使い方

webuiのAPI起動

webui-user.batset COMMANDLINE_ARGSにコマンドライン引数を追加します。

set COMMANDLINE_ARGS=--api

起動したらhttp://127.0.0.1:7861/docs(もしくは起動時のwebuiのURL+/docs)にアクセスしてください。
FastAPIのドキュメントページが開きます。

画像生成

ローカル環境でする場合は仮想環境の作成することをおすすめします。
venvを使った仮想環境の作り方

使用ライブラリ
pip install Pillow requests

t2i

/sdapi/v1/txt2imgをクリックするとリクエストできる値が確認できます。

設定していない値はでデフォルトのものが使われます。
今回はpromptstepsを設定しています。

payload = {
    "prompt": "puppy dog",
    "steps": 5
}

以下のコードでAPIリクエストできます。

url = "http://127.0.0.1:7861"

response = requests.post(url=f'{url}/sdapi/v1/txt2img', json=payload)

リクエストして、返されたものは「images(画像)、parameter(パラメータ)、info(情報)」になります。


画像を保存するには

imagesには、大きなテキスト情報が入っており、画像として保存するには、以下のコードが必要になります。

  • テキストデータをバイナリデータにデコード
  • PILのImageでバイナリデータを開く
image = Image.open(io.BytesIO(base64.b64decode(i.split(",",1)[0])))

/sdapi/v1/png-infoにAPIリクエストを送り、画像の情報を取得します。
取得することによって、webuiのPNG Infoで画像の情報が見れるようになります。

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

response2.json().get("info")で情報が取得でます。


  • PILのPngImagePluginを使い画像にメタデータを挿入
  • 最後にメタデータを含む画像を保存
pnginfo = PngImagePlugin.PngInfo()
pnginfo.add_text("parameters", response2.json().get("info"))
image.save('output_t2i.png', pnginfo=pnginfo)
全体のコード
import requests
import io
import base64
from PIL import Image, PngImagePlugin

url = "http://127.0.0.1:7861"

payload = {
    "prompt": "puppy dog",
    "steps": 5
}

response = requests.post(url=f'{url}/sdapi/v1/txt2img', json=payload)

r = response.json()

for i in r['images']:
    image = Image.open(io.BytesIO(base64.b64decode(i.split(",",1)[0])))
 
    png_payload = {
        "image": "data:image/png;base64," + i
    }
    response2 = requests.post(url=f'{url}/sdapi/v1/png-info', json=png_payload)

    pnginfo = PngImagePlugin.PngInfo()
    pnginfo.add_text("parameters", response2.json().get("info"))
    image.save('output_t2i.png', pnginfo=pnginfo)

i2i

読み込む画像をバイナリデータからテキストデータに変換する必要があります。

img_path = "画像ファイルパス"
image = Image.open(img_path)

# バイナリデータからテキスト変換
with io.BytesIO() as img_bytes:
    image.save(img_bytes, format='PNG')
    img_b64 = base64.b64encode(img_bytes.getvalue()).decode()
png_data = {}
png_data["image"] = [img_b64]

読み込んだ画像をpayloadinit_imagesを追加します。

payload = {
    "init_images": png_data["image"],
    "prompt": "puppy dog",
    "steps": 5
}

あとはt2iの処理と同じです。

全体のコード
import json
import requests
import io
import base64
from PIL import Image, PngImagePlugin

url = "http://127.0.0.1:7861"

# img_path = "画像ファイルパス"
img_path = "00094-2257619113.png"
image = Image.open(img_path)

# バイナリデータからテキスト変換
with io.BytesIO() as img_bytes:
    image.save(img_bytes, format='PNG')
    img_bytes = base64.b64encode(img_bytes.getvalue()).decode()
    
png_payload = {}
png_payload["image"] = [img_bytes]

payload = {
    "init_images": png_payload["image"],
    "prompt": "puppy dog",
    "steps": 5
}

response = requests.post(url=f'{url}/sdapi/v1/img2img', json=payload)

r = response.json()

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

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

    pnginfo = PngImagePlugin.PngInfo()
    pnginfo.add_text("parameters", response2.json().get("info"))
    image.save('output_i2i.png', pnginfo=pnginfo)

その他

docuを参考にpayload辞書に必要なキーと値を追加

webui API(辞書のキーに記述)
Negative Prompt negative_prompt
width width
Hheight height
CFG Scale cfg_scale
Hires.fix enable_hr
payload = {
    "prompt": "puppy dog",
    "steps": 5,
    # 追加していく
}

response = requests.post(url=f'{url}/sdapi/v1/txt2img', json=payload)

プロンプト、ネガティブにLoraなども、含むことができます。


モデル

一覧取得

/sdapi/v1/sd-modelsにリクエストをすると、自身の持っているモデルを一覧で取得できます。

import requests
from pprint import pprint

url = "http://127.0.0.1:7861"

sd_models = requests.get(f"{url}/sdapi/v1/sd-models").json()

sd_models = [i["title"] for i in sd_models]

# pprint(sd_models)

with open("sd_model.txt", '+w', encoding='UTF-8') as f:
    f.write('\n'.join(sd_models))

自身の持っているモデルとハッシュを以下のように取得できます。

AnythingV5_v5PrtRE.safetensors [7f96a1a9ca]
anything-v4.5-pruned-fp16.ckpt [f773383dbc]
AnythingV5Ink_v5PrtRE.safetensors [7f96a1a9ca]
...

モデルの変更

モデルの変更には/sdapi/v1/optionsにAPIリクエストを送ります。

AnythingV5Ink_v5PrtRE.safetensors [7f96a1a9ac]のように、モデル名(AnythingV5Ink_v5PrtRE.safetensors)とハッシュ([7f96a1a9ac])が必要になります。

モデル一覧取得したものを使います

model = "AnythingV5Ink_v5PrtRE.safetensors [7f96a1a9ac]"
option_payload = {
    "sd_model_checkpoint": model,
    # "CLIP_stop_at_last_layers": 2
}

response = requests.post(url=f'{url}/sdapi/v1/options', json=option_payload)
全体のコード モデルの変更
import requests
import io
import base64
from PIL import Image, PngImagePlugin

url = "http://127.0.0.1:7861"

# オプション設定
model = "AnythingV5Ink_v5PrtRE.safetensors [7f96a1a9ac]"
option_payload = {
    "sd_model_checkpoint": model,
    # "CLIP_stop_at_last_layers": 2
}

response = requests.post(url=f'{url}/sdapi/v1/options', json=option_payload)

payload = {
    "prompt": "puppy dog",
    "steps": 5
}

response = requests.post(url=f'{url}/sdapi/v1/txt2img', json=payload)

r = response.json()

for i in r['images']:
    image = Image.open(io.BytesIO(base64.b64decode(i.split(",",1)[0])))
 
    png_payload = {
        "image": "data:image/png;base64," + i
    }
    response2 = requests.post(url=f'{url}/sdapi/v1/png-info', json=png_payload)

    pnginfo = PngImagePlugin.PngInfo()
    pnginfo.add_text("parameters", response2.json().get("info"))
    image.save('output_t2i.png', pnginfo=pnginfo)

サンプラー

一覧取得

/sdapi/v1/samplersにリクエストをすると、webuiにあるサンプラーを一覧で取得できます。

import requests
from pprint import pprint

url = "http://127.0.0.1:7861"

sd_samplers = requests.get(f"{url}/sdapi/v1/samplers").json()

sd_samplers = [i["name"] for i in sd_samplers]

# pprint(sd_models)

with open("sd_sampler.txt", '+w', encoding='UTF-8') as f:
    f.write('\n'.join(sd_samplers))

webuiにあるサンプラーを以下のように取得できます。

Euler a
Euler
LMS
Heun
...

サンプラー追加

docuを参考にsampler_indexを追加し任意のサンプラーを選択する。

payload = {
    "prompt": "puppy dog",
    "steps": 5,
    "sampler_index": "DPM++ 2M Karras",
}
全体のコード サンプラー追加
import requests
import io
import base64
from PIL import Image, PngImagePlugin

url = "http://127.0.0.1:7861"

# オプション設定
model = "AnythingV5Ink_v5PrtRE.safetensors [7f96a1a9ac]"
option_payload = {
    "sd_model_checkpoint": model,
    # "CLIP_stop_at_last_layers": 2
}

response = requests.post(url=f'{url}/sdapi/v1/options', json=option_payload)

payload = {
    "prompt": "puppy dog",
    "steps": 5
}

response = requests.post(url=f'{url}/sdapi/v1/txt2img', json=payload)

r = response.json()

for i in r['images']:
    image = Image.open(io.BytesIO(base64.b64decode(i.split(",",1)[0])))
 
    png_payload = {
        "image": "data:image/png;base64," + i
    }
    response2 = requests.post(url=f'{url}/sdapi/v1/png-info', json=png_payload)

    pnginfo = PngImagePlugin.PngInfo()
    pnginfo.add_text("parameters", response2.json().get("info"))
    image.save('output_t2i.png', pnginfo=pnginfo)

参照

https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/API

Discussion