手軽で便利にローカル環境からStable Diffusion Web UIを呼び出す環境作った

はじめまして。
最近AIで画像生成にはまってます。

ネット上に自分がやりたいような環境の作り方が載ってなかったため、せっかくなので同じこと考えてる人がいたらと思い記事にします。
普段Pythonは触っておらずPython自体に詳しいわけではないのであしからず…。

## やりたいこと
1. 自分の慣れた環境(IDE)で簡単にStable Diffusion Web UIを立ち上げることが出来る
2. 初期パラメータを実行前に予め設定しておき、毎回起動するたびにお決まりの設定をし直す手間を省く
    - Step数変える
    - Scale変える
    - Width, Height変える
    - Sampler変える
    - 生成した画像の保存場所変える…などなど
    
~~毎回変えるのくっっっっっそめんどいっす…~~

## 前提条件
- OSはWindowsであること
- IDEの使用方法については説明しません。
    - VScodeなりIntelijなりお好きなものを使用してください。

## Pythonのインストール
※3.11以降はエラーが出る(2023/01/04時点)ので、ここでは `ver3.10.6` を使用します。
[Python ver3.10.6 ダウンロードリンク](https://www.python.org/downloads/release/python-3106/)

`Windows Installer (64-bit)`のインストーラーをダウンロードし、インストーラーを実行してください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3094216/98ce42a6-dd53-fedf-2832-425eeb7407d6.png)

`Add python 3.10 to PATH` にチェック
`Install Now` でインストールを実行
![Untitled.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3094216/4f854c94-2ec4-24e5-5310-884250170865.png)

インストール後、`Dissable path length limit` をクリック
![Untitled.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3094216/7b51899a-8ca4-10a1-631a-a10567e5bdff.png)


## Gitのインストール
公式サイトからインストーラーをダウンロード
[Gitインストーラーのダウンロードリンク](https://gitforwindows.org/)
画像省略しますが、素直にインストールをすればOKです。


## IDEのインストール 
自分の環境ではIDEのセットアップはすでに済んでいたため、前述の通りここでは省略します。
- 普段あまりプログラム触ってない人は JetBrains社の`PyCharm community edition` が無難にオススメかなって。
[PyCharmのダウンロード](https://www.jetbrains.com/ja-jp/pycharm/)
（自分は普段InteliJ IDEAを使ってるためPyCharm自体は使ったことないですが開発元は同じなので…）
- 導入方法や使用方法は懇切丁寧に説明してくれてる記事やサイトがたくさんあるのでそちらにお任せします。
[こことか？](https://corvus-window.com/install_python_and_pycharm/)


## Pythonコードの作成
やっと本題です。
とはいえ、以下をコピペしてもらえばほとんど問題ないと思います。
```python
import os
import subprocess
import shutil
import urllib.request
import json

# 自分が管理したいディレクトリのpathを記入
images_stored = "D:\images"
models_stored = "D:\learning_models"
stable_diffusion_dir = "D:\stable-diffusion-webui"

# Stable Diffusion Web UI 起動時の初期値を設定
default_sampler = "Euler"
default_steps = 50
default_width = 512
default_height = 512
default_batch_count = 1
default_batch_size = 1
default_CFG_scale = 4.5
default_Restore_faces = True
default_Hires_fix = True
default_Upscale_by = 2
default_Denoising_strength = 0

# ここに使用する学習モデルとダウンロードURLを記述する
learning_models = {
    "ACertainThing": "https://huggingface.co/JosephusCheung/ACertainThing/resolve/main/ACertainThing.ckpt",
    "Anything-V3.0": "https://huggingface.co/Linaqruf/anything-v3.0/resolve/main/Anything-V3.0.ckpt",
}

##################################################################################################
# ここから下はコードが読める人以外は編集しないことを推奨します。
##################################################################################################

# "/notebooks/images" が存在しなければ該当フォルダを作成する
if os.path.exists(images_stored):
    print(f"{images_stored} のディレクトリはすでに存在します。")
else:
    os.makedirs(models_stored, exist_ok=True)
    print(f"{images_stored} のディレクトリを作成しました。")
if os.path.exists("models_stored"):
    print(f"{models_stored} のディレクトリはすでに存在します。")
else:
    os.makedirs(models_stored, exist_ok=True)
    print(f"{models_stored} のディレクトリを作成しました。")


# Stable Diffusion Web UIのインストールおよび更新
if os.path.exists(stable_diffusion_dir):
    # ディレクトリが存在する場合は、そのディレクトリに移動し、最新の状態に更新する
    print("すでにStable Diffusion Web UIはインストール済みです。更新があるかチェックしています。")
    os.chdir(stable_diffusion_dir)
    subprocess.run(["git", "pull"])
else:
    # ディレクトリが存在しない場合は、git clone を実行する
    print("git cloneを実行します。AUTOMATIC1111/Stable Diffusion Web UIをダウンロードしています。")
    subprocess.run(["git", "clone", "https://github.com/AUTOMATIC1111/stable-diffusion-webui.git", stable_diffusion_dir])

# ckptファイルのダウンロードおよびコピー
for model, url in learning_models.items():
    if not os.path.exists(f"{stable_diffusion_dir}\models\Stable-diffusion\{model}.ckpt"):
        if not os.path.exists(f"{models_stored}\{model}.ckpt"):
            print(f"{model}.ckptがありません。Webからダウンロードしています。")
            urllib.request.urlretrieve(url, f"{stable_diffusion_dir}\models\Stable-diffusion")
            print("ckptファイルのバックアップを取得します。")
            shutil.copy(f"{stable_diffusion_dir}\models\Stable-diffusion\{model}.ckpt", models_stored)
        else:
            print(f"{model}.ckptが {models_stored} に存在します。{stable_diffusion_dir}\models\Stable-diffusion にコピーします。")
            shutil.copy(f"{models_stored}\{model}.ckpt", f"{stable_diffusion_dir}\models\Stable-diffusion")
            print(f"{model}.ckptファイルをコピーしました。")
    else:
        print(f"{model}.ckptを検出しました。")

# Stable Diffusionのコンフィグを編集
os.chdir(stable_diffusion_dir)
with open("config.json", "r") as f:
    config = json.load(f)
    config["outdir_samples"] = images_stored

with open("config.json", "w") as f:
    json.dump(config, f, indent=2)

with open("ui-config.json", "r") as f:
    config = json.load(f)
    config["txt2img/Sampling method/value"] = default_sampler
    config["txt2img/Sampling Steps/value"] = default_steps
    config["txt2img/Width/value"] = default_width
    config["txt2img/Height/value"] = default_height
    config["txt2img/Batch count/value"] = default_batch_count
    config["txt2img/Batch size/value"] = default_batch_size
    config["txt2img/CFG Scale/value"] = default_CFG_scale
    config["txt2img/Restore faces/value"] = default_Restore_faces
    config["txt2img/Hires. fix/value"] = default_Hires_fix
    config["txt2img/Upscale by/value"] = default_Upscale_by
    config["txt2img/Denoising strength/value"] = default_Denoising_strength

with open("ui-config.json", "w") as f:
    json.dump(config, f, indent=2)

# Stable Diffusion Web UIの起動
process = subprocess.Popen(['webui-user.bat'], stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)
while True:
    output = process.stdout.readline()
    if output == '' and process.poll() is not None:
        break
    if output:
        print(output.strip())

error = process.stderr.read()
if error:
    print(error)

process.wait()
```

### コードの解説

```python
# 自分が管理したいディレクトリのpathを記入
images_stored = "D:\images"
models_stored = "D:\learning_models"
stable_diffusion_dir = "D:\stable-diffusion-webui"
```
`images_stored` には生成した画像の保存先を指定してください。デフォルトだと深い場所にあって分かりづらいです。
`models_stored` には使用する学習モデルのckptファイルの保存先を指定します。実際にStable Diffusion Web UIが読み込む場所は異なり同じ学習モデルが2つ存在することになるので注意です。
`stable_diffusion_dir` にはStable Diffusion Web UIがインストールされるディレクトリになります。



実際のGUIは以下のようなものになりますが、それぞれの設定値の初期値をここで設定しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3094216/02d0d364-f4c3-3cb1-93f6-da8c821de21a.png)
使用していくうちに自分のお決まりの設定が出てくると思うので毎回起動時にその設定にするのがめんどくさいのでここで設定してしまいましょう。

```python
# Stable Diffusion Web UI 起動時の初期値を設定
default_sampler = "Euler"
default_steps = 50
default_width = 512
default_height = 512
default_batch_count = 1
default_batch_size = 1
default_CFG_scale = 4.5
default_Restore_faces = True
default_Hires_fix = True
default_Upscale_by = 2
default_Denoising_strength = 0
```

`default_sampler` の項目値だけは "Euler"のように`" "`で囲んでください。
`default_Restore_faces`と`default_Hires_fix`が設定出来る値は、`True` もしくは `False` です。
True はチェックが付いた状態
False はチェックが外れた状態
となります。

```python
# ここに使用する学習モデルとダウンロードURLを記述する
learning_models = {
    "ACertainThing": "https://huggingface.co/JosephusCheung/ACertainThing/resolve/main/ACertainThing.ckpt",
    "Anything-V3.0": "https://huggingface.co/Linaqruf/anything-v3.0/resolve/main/Anything-V3.0.ckpt",
}
```
ここでは使用する学習モデル名とダウンロードリンクを指定します。
入力形式は、`"model名":"URL"` です。
URLはHugging Face等のckptファイルが置いてあるダウンロード先から `download` を右クリックし、`リンクのアドレスをコピー` からURLをコピーすることが出来ます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3094216/c09894c1-dc72-5f67-9edf-37a0bf22452b.png)


設定は以上です。Pythonのコードを実行してみてください。
以下のようにローカルのURLが出てくればクリックすることでStable Diffusion Web UIが開くはずです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3094216/cecc5838-8ca1-f5e4-761d-f56f7cf2af45.png)

お疲れ様でした。