stable-diffusion-webuiのtxt2imgをAPIでランダムワード生成自動化

# 追記
**AUTOMATIC1111/stable-diffusion-webui にAPIが追加されていました。**

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

初期設定が必要なので webui-user.bat をテキストエディタで開いて
```webui-user.bat
set COMMANDLINE_ARGS=--api
```
と追記して webui-user.bat を起動すると使えるようになります。

**stable-diffusion-webuiに連続生成する機能があるそうです。**
ご指摘頂きありがとうございます。

https://note.com/yamkaz/n/n55c3ac365f34#2914b3b1-79f5-42b9-b942-c36d4fb71c81

この記事は、Waifu DiffusionやNovelAI Diffusion等でランダムなPromptワードを指定してイラストを自動生成する場合や、APIの使い方の参考にしてください。

# はじめに
![hoge_2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2694201/834c8a74-fd09-5a0c-7ee1-979b1a15a436.gif)

AUTOMATIC1111/stable-diffusion-webuiでは、固定されたPromptワードで毎回ボタンをクリックして生成するため、自動生成する方法を考えました。

SeleniumとWebDriverを使用する方法も考えましたがGradioでUIが生成され
ていたため、AUTOMATIC1111/stable-diffusion-webuiからフォークされたリポジトリを使用しました。

かんたんなPythonプログラム例も張っておきます。

全て自己責任でお願い致します。

# 準備
AUTOMATIC1111/stable-diffusion-webuiをkritaから動かすために開発されているリポジトリですが、APIが実装されていて更新頻度も高かったのでこちらを使用しました。

https://github.com/Interpause/auto-sd-krita/tree/5dae426

AUTOMATIC1111/stable-diffusion-webuiの初期設定と同様にckptファイルを「models\Stable-diffusion」フォルダに配置します。
APIからckptファイルを選択できるようですが、うまくいかなかったので一種類のみ配置します。

NovelAIの場合はhypernetworkのptファイルを「models\hypernetworks」に配置します。

webui.batを開いて起動します。

hypernetworkはAPIで指定できないようなので「http\://127.0.0.1:7860」をブラウザで開いて設定します。

APIは「http\://127.0.0.1:8000/docs」で確認できます。
```python:Pythonでtxt2img
requests.post(url="http://127.0.0.1:8000/txt2img", json=params).json()
```

# プログラム例
画像サイズは 「"orig_width"」と「 "orig_height"」で指定します。
生成された画像は、「"outputs/krita-out"」フォルダに保存され、「outputs\txt2img-images」フォルダにも512×512の画像が生成されます。
「"sd_model"」はckptファイルの選択ですが、「"model.ckpt"」のままでも自動で選択されました。

## 固定ワードで連続生成
```
import requests

params = {
  "restore_faces": False,
  "face_restorer": "CodeFormer",
  "codeformer_weight": 0.5,
  "sd_model": "model.ckpt",
  "prompt": "masterpiece, high quality, full body , a girl , looking at viewer",
  "negative_prompt": "lowres, bad anatomy, bad hands, text, error, missing fingers, extra digit, fewer digits, cropped, worst quality, low quality, normal quality, jpeg artifacts, signature, watermark, username, blurry",
  "seed": -1,
  "seed_enable_extras": False,
  "subseed": -1,
  "subseed_strength": 0,
  "seed_resize_from_h": 0,
  "seed_resize_from_w": 0,
  "sampler_name": "Euler a",
  "steps": 30,
  "cfg_scale": 7.5,
  "denoising_strength": 0.35,
  "batch_count": 1,
  "batch_size": 1,
  "base_size": 512,
  "max_size": 768,
  "tiling": False,
  "highres_fix": False,
  "firstphase_height": 512,
  "firstphase_width": 512,
  "upscaler_name": "None",
  "filter_nsfw": False,
  "include_grid": False,
  "sample_path": "outputs/krita-out",
  "orig_width": 512,
  "orig_height": 512
}

def main():
    while True:
        try:
            r = requests.post(url="http://127.0.0.1:8000/txt2img", json=params).json()
            if r['outputs'] == []:
                    break
            print( 'Prompt：' + r['info'].split(':')[1].replace(', "all_prompts"','').replace('"','') + ' で生成しました。' )
        except:
            break
        
if __name__ == "__main__":
    main()
```
## 固定ワード+ランダムワードで連続生成
ランダムPromptワード「"random_prompt"」各行の「,」で区切られたワード1つをランダムで選択して、上から順番につなげ固定Promptワード「"default_prompt"」Promptワードを生成します。
例1
 masterpiece, high quality, full body, a girl , blond hair ,School uniforms ,check skert ,Long hair , Beach , Summer , fox ears
例2
masterpiece, high quality, full body, a girl ,Red hair , Chinese dresses ,denim skert , twin-tail hair , countryside , Autumn , bear ears

```
import requests
import random

f = {
    "prompt":{
        "default_prompt": "masterpiece, high quality, full body, a girl",
        "random_prompt":[
            "Red hair, blue hair, blond hair, silver hair",
            "School uniforms, Chinese dresses",
            "denim shorts,check skert,denim skert",
            "Long hair, short hair, twin-tail hair, ponytail",
            "city, Beach, countryside",
            "Spring, Summer, Autumn, Winter",
            "Cat ears, fox ears, bear ears"
        ]
    },
    "negative_prompt":{
        "default_negative_prompt": "lowres, bad anatomy, bad hands, text, error, missing fingers, extra digit, fewer digits, cropped, worst quality, low quality, normal quality, jpeg artifacts, signature, watermark, username, blurry",
        "random_negative_prompt": [
            "dog year"
        ]
    },
    "params":{
        "restore_faces": "False",
        "face_restorer": "CodeFormer",
        "codeformer_weight": 0.5,
        "sd_model": "model.ckpt",
        "seed": -1,
        "seed_enable_extras": "False",
        "subseed": -1,
        "subseed_strength": 0,
        "seed_resize_from_h": 0,
        "seed_resize_from_w": 0,
        "sampler_name": "Euler a",
        "steps": 30,
        "cfg_scale": 7.5,
        "denoising_strength": 0.35,
        "batch_count": 1,
        "batch_size": 1,
        "base_size": 512,
        "max_size": 768,
        "tiling": "False",
        "highres_fix": "False",
        "firstphase_height": 512,
        "firstphase_width": 512,
        "upscaler_name": "None",
        "filter_nsfw": "False",
        "include_grid": "False",
        "sample_path": "outputs/krita-out",
        "orig_width": 512,
        "orig_height": 512
    }
}

def bool_check(s):
    if isinstance( s, str ) and s.lower() == 'false':
        return False
    elif isinstance( s, str ) and s.lower() == 'true':
        return True
    return s

def main():
    while True:
        try:
            f['params']['prompt'] = f['prompt']['default_prompt'] + ''.join([' ,'+_.split(",")[random.randrange(len(_.split(",")))] for _ in f['prompt']['random_prompt']])
            f['params']['negative_prompt'] = f['negative_prompt']['default_negative_prompt'] + ''.join([' ,'+_.split(",")[random.randrange(len(_.split(",")))] for _ in f['negative_prompt']['random_negative_prompt']])

            for _ in f['params']:
                f['params'][_] = bool_check(f['params'][_])

            r = requests.post(url="http://127.0.0.1:8000/txt2img", json=f['params']).json()
            
            if r['outputs'] == []:
                print('Error')
                break
				
            print( 'Prompt：' + r['info'].split(':')[1].replace(', "all_prompts"','').replace('"','') + ' で生成しました。' )
            
        except Exception as e:
            print(e)
            print(r)
            print('Error')
            break
        
if __name__ == "__main__":
    main()
```