Repository: AUTOMATIC1111/stable-diffusion-webui

Issue:
[Bug]: API image generation returns errors in console with some alwayson_scripts
### Is there an existing issue for this?

- [X] I have searched the existing issues and checked the recent builds/commits

### What happened?

webUI's console suddenly started returning errors unexpectedly when using `/sdapi/v1/txt2img` or `../img2img` calls such as the following (for my base install):
```
API 2023-03-15 16:56:02.038435 200 http/1.1 OPTIONS /sdapi/v1/txt2img 127.0.0.1 0.0
Error running process: E:\storage\stable-diffusion-webui\extensions\stable-diffusion-webui-aesthetic-gradients\scripts\aesthetic.py
Traceback (most recent call last):
  File "E:\storage\stable-diffusion-webui\modules\scripts.py", line 409, in process
    script.process(p, *script_args)
  File "E:\storage\stable-diffusion-webui\extensions\stable-diffusion-webui-aesthetic-gradients\scripts\aesthetic.py", line 36, in process
    aesthetic.set_aesthetic_params(p, float(aesthetic_lr), float(aesthetic_weight), int(aesthetic_steps), aesthetic_imgs, aesthetic_slerp, aesthetic_imgs_text, aesthetic_slerp_angle, aesthetic_text_negative)
TypeError: float() argument must be a string or a real number, not 'NoneType'

Error running process: E:\storage\stable-diffusion-webui\extensions\stable-diffusion-webui-conditioning-highres-fix\scripts\conditioning-highres-fix.py
Traceback (most recent call last):
  File "E:\storage\stable-diffusion-webui\modules\scripts.py", line 409, in process
    script.process(p, *script_args)
  File "E:\storage\stable-diffusion-webui\extensions\stable-diffusion-webui-conditioning-highres-fix\scripts\conditioning-highres-fix.py", line 22, in process
    if conditioning_highres_fix>0 and p.denoising_strength is not None:
TypeError: '>' not supported between instances of 'NoneType' and 'int'

Error running process: E:\storage\stable-diffusion-webui\extensions\stable-diffusion-webui-daam\scripts\daam_script.py
Traceback (most recent call last):
  File "E:\storage\stable-diffusion-webui\modules\scripts.py", line 409, in process
    script.process(p, *script_args)
  File "E:\storage\stable-diffusion-webui\extensions\stable-diffusion-webui-daam\scripts\daam_script.py", line 99, in process
    self.attentions = [s.strip() for s in attention_texts.split(",") if s.strip()]
AttributeError: 'NoneType' object has no attribute 'split'

Data shape for DDIM sampling is (2, 4, 64, 64), eta 0
Running DDIM Sampling with 31 timesteps
DDIM Sampler:   0%|                                                                                                                              | 0/31 [00:00<?, ?it/s]
```

i made a few local changes to both `modules/api/api.py` and `modules/scripts.py` to determine where this was occurring, and it seems to be `scripts.py:409` just simply running every script that has a visible UI element whether or not it was declared by way of adding 
```
        else:
            print("no alwayson scripts")
```
in `api.py:216-217`, as well as a simple `print(script)` in `scripts.py:407`

i installed a clean instance of webUI, added `--api` to commandline args, installed the [aesthetic gradients](https://github.com/AUTOMATIC1111/stable-diffusion-webui-aesthetic-gradients) extension, and confirmed via simple http://127.0.0.1:7860/docs POST test to the txt2img endpoint.  

reverting to commit 94ffa9fc5386e51f20692ab46906135e8de33110 prevents the issue from occurring

### Steps to reproduce the problem

0. enable `--api` commandline arg and install aesthetic gradients extension (for example)
1. Go to [local API docs](http://127.0.0.1:7860/docs)
2. Scroll down to `POST sdapi/v1/txt2img`, open it, click "try it out"
3. Paste the following into the input field
```
{
	"batch_size": 1,
	"cfg_scale": 7,
	"enable_hr": false,
	"height": 512,
	"n_iter": 1,
	"negative_prompt": "test",
	"prompt": "test",
	"restore_faces": false,
	"sampler_index": "DDIM",
	"seed": "1",
	"steps": 1,
	"width": 512
}
```
4. press execute and receive an error most similar to the following in the console
```
Error running process: E:\storage\webui-clean-2\extensions\stable-diffusion-webui-aesthetic-gradients\scripts\aesthetic.py
Traceback (most recent call last):
  File "E:\storage\webui-clean-2\modules\scripts.py", line 386, in process
    script.process(p, *script_args)
  File "E:\storage\webui-clean-2\extensions\stable-diffusion-webui-aesthetic-gradients\scripts\aesthetic.py", line 36, in process
    aesthetic.set_aesthetic_params(p, float(aesthetic_lr), float(aesthetic_weight), int(aesthetic_steps), aesthetic_imgs, aesthetic_slerp, aesthetic_imgs_text, aesthetic_slerp_angle, aesthetic_text_negative)
TypeError: float() argument must be a string or a real number, not 'NoneType'

Data shape for DDIM sampling is (1, 4, 64, 64), eta 0.0
Running DDIM Sampling with 1 timesteps
DDIM Sampler: 100%|███████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 1/1 [00:00<00:00,  5.56it/s]
```

### What should have happened?

preferably, no errors would be encountered and the console just chugs along without running scripts not defined in the request, but i suppose "always on" might be a hint there

### Commit where the problem happens

2174f58daee1e077eec1125e196d34cc93dbaf23

### What platforms do you use to access the UI ?

Windows

### What browsers do you use to access the UI ?

Mozilla Firefox

### Command Line Arguments

```Shell
--api --ckpt-dir "E:\storage\stable diffusion models" --vae-dir "E:\storage\stable diffusion VAEs"
```


### List of extensions

![image](https://user-images.githubusercontent.com/1649724/225466958-ebb0be67-82e2-4616-93ce-5a8de5195856.png)


### Console logs

(collected via commit 2174f58daee1e077eec1125e196d34cc93dbaf23)
```Shell
E:\storage\webui-clean-2>webui-user.bat
venv "E:\storage\webui-clean-2\venv\Scripts\Python.exe"
Python 3.10.6 (tags/v3.10.6:9c7b4bd, Aug  1 2022, 21:53:49) [MSC v.1932 64 bit (AMD64)]
Commit hash: 2174f58daee1e077eec1125e196d34cc93dbaf23
Installing requirements for Web UI
Launching Web UI with arguments: --api --ckpt-dir E:\storage\stable diffusion models --vae-dir E:\storage\stable diffusion VAEs
No module 'xformers'. Proceeding without it.
Loading weights [e1441589a6] from E:\storage\stable diffusion models\runwayML-sd-v1-5-pruned.ckpt
Creating model from config: E:\storage\webui-clean-2\configs\v1-inference.yaml
LatentDiffusion: Running in eps-prediction mode
DiffusionWrapper has 859.52 M params.
Applying cross attention optimization (Doggettx).
Textual inversion embeddings loaded(0):
Model loaded in 4.4s (load weights from disk: 1.7s, create model: 0.3s, apply weights to model: 0.5s, apply half(): 0.7s, move model to device: 0.6s, load textual inversion embeddings: 0.7s).
Running on local URL:  http://127.0.0.1:7860

To create a public link, set `share=True` in `launch()`.
Error running process: E:\storage\webui-clean-2\extensions\stable-diffusion-webui-aesthetic-gradients\scripts\aesthetic.py
Traceback (most recent call last):
  File "E:\storage\webui-clean-2\modules\scripts.py", line 386, in process
    script.process(p, *script_args)
  File "E:\storage\webui-clean-2\extensions\stable-diffusion-webui-aesthetic-gradients\scripts\aesthetic.py", line 36, in process
    aesthetic.set_aesthetic_params(p, float(aesthetic_lr), float(aesthetic_weight), int(aesthetic_steps), aesthetic_imgs, aesthetic_slerp, aesthetic_imgs_text, aesthetic_slerp_angle, aesthetic_text_negative)
TypeError: float() argument must be a string or a real number, not 'NoneType'

Data shape for DDIM sampling is (1, 4, 64, 64), eta 0.0
Running DDIM Sampling with 1 timesteps
DDIM Sampler: 100%|███████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 1/1 [00:06<00:00,  6.93s/it]
Error running process: E:\storage\webui-clean-2\extensions\stable-diffusion-webui-aesthetic-gradients\scripts\aesthetic.py                        | 0/1 [00:00<?, ?it/s]
Traceback (most recent call last):
  File "E:\storage\webui-clean-2\modules\scripts.py", line 386, in process
    script.process(p, *script_args)
  File "E:\storage\webui-clean-2\extensions\stable-diffusion-webui-aesthetic-gradients\scripts\aesthetic.py", line 36, in process
    aesthetic.set_aesthetic_params(p, float(aesthetic_lr), float(aesthetic_weight), int(aesthetic_steps), aesthetic_imgs, aesthetic_slerp, aesthetic_imgs_text, aesthetic_slerp_angle, aesthetic_text_negative)
TypeError: float() argument must be a string or a real number, not 'NoneType'

Data shape for DDIM sampling is (1, 4, 64, 64), eta 0.0
Running DDIM Sampling with 1 timesteps
DDIM Sampler: 100%|███████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 1/1 [00:00<00:00,  3.89it/s]
Error running process: E:\storage\webui-clean-2\extensions\stable-diffusion-webui-aesthetic-gradients\scripts\aesthetic.py
Traceback (most recent call last):
  File "E:\storage\webui-clean-2\modules\scripts.py", line 386, in process
    script.process(p, *script_args)
  File "E:\storage\webui-clean-2\extensions\stable-diffusion-webui-aesthetic-gradients\scripts\aesthetic.py", line 36, in process
    aesthetic.set_aesthetic_params(p, float(aesthetic_lr), float(aesthetic_weight), int(aesthetic_steps), aesthetic_imgs, aesthetic_slerp, aesthetic_imgs_text, aesthetic_slerp_angle, aesthetic_text_negative)
TypeError: float() argument must be a string or a real number, not 'NoneType'

Data shape for DDIM sampling is (1, 4, 64, 64), eta 0.0
Running DDIM Sampling with 1 timesteps
DDIM Sampler: 100%|███████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 1/1 [00:00<00:00,  5.56it/s]
Total progress: 3it [16:03, 283.56s/it]
```


### Additional information
don't mean to be that guy who asks someone specific for help, but @Vespinian? seems you might be the one to pester unfortunately


Discussion:
Yes, it's an unfortunate side effect of initializing script_arg array to None so that I can then insert the args at the correct place. If the extension doesn't handle receiving None in it's arg it will throw an error and extensions that don't take args will run either way. I did attempt to change the scriptrunner to remove from the alwayson_script list the script that were not included with more or less success but I'll give it another shot.

Resolving patch:
diff --git a/modules/api/api.py b/modules/api/api.py
--- a/modules/api/api.py
+++ b/modules/api/api.py
@@ -3,6 +3,7 @@
 import time
 import datetime
 import uvicorn
+import gradio as gr
 from threading import Lock
 from io import BytesIO
 from gradio.processing_utils import decode_base64_to_file
@@ -152,6 +153,9 @@ def __init__(self, app: FastAPI, queue_lock: Lock):
         self.add_api_route("/sdapi/v1/memory", self.get_memory, methods=["GET"], response_model=MemoryResponse)
         self.add_api_route("/sdapi/v1/scripts", self.get_scripts_list, methods=["GET"], response_model=ScriptsList)
 
+        self.default_script_arg_txt2img = []
+        self.default_script_arg_img2img = []
+
     def add_api_route(self, path: str, endpoint, **kwargs):
         if shared.cmd_opts.api_auth:
             return self.app.add_api_route(path, endpoint, dependencies=[Depends(self.auth)], **kwargs)
@@ -185,7 +189,7 @@ def get_script(self, script_name, script_runner):
         script_idx = script_name_to_index(script_name, script_runner.scripts)
         return script_runner.scripts[script_idx]
 
-    def init_script_args(self, request, selectable_scripts, selectable_idx, script_runner):
+    def init_default_script_args(self, script_runner):
         #find max idx from the scripts in runner and generate a none array to init script_args
         last_arg_index = 1
         for script in script_runner.scripts:
@@ -193,13 +197,24 @@ def init_script_args(self, request, selectable_scripts, selectable_idx, script_r
                 last_arg_index = script.args_to
         # None everywhere except position 0 to initialize script args
         script_args = [None]*last_arg_index
+        script_args[0] = 0
+
+        # get default values
+        with gr.Blocks(): # will throw errors calling ui function without this
+            for script in script_runner.scripts:
+                if script.ui(script.is_img2img):
+                    ui_default_values = []
+                    for elem in script.ui(script.is_img2img):
+                        ui_default_values.append(elem.value)
+                    script_args[script.args_from:script.args_to] = ui_default_values
+        return script_args
+
+    def init_script_args(self, request, default_script_args, selectable_scripts, selectable_idx, script_runner):
+        script_args = default_script_args.copy()
         # position 0 in script_arg is the idx+1 of the selectable script that is going to be run when using scripts.scripts_*2img.run()
         if selectable_scripts:
             script_args[selectable_scripts.args_from:selectable_scripts.args_to] = request.script_args
             script_args[0] = selectable_idx + 1
-        else:
-            # when [0] = 0 no selectable script to run
-            script_args[0] = 0
 
         # Now check for always on scripts
         if request.alwayson_scripts and (len(request.alwayson_scripts) > 0):
@@ -220,6 +235,8 @@ def text2imgapi(self, txt2imgreq: StableDiffusionTxt2ImgProcessingAPI):
         if not script_runner.scripts:
             script_runner.initialize_scripts(False)
             ui.create_ui()
+        if not self.default_script_arg_txt2img:
+            self.default_script_arg_txt2img = self.init_default_script_args(script_runner)
         selectable_scripts, selectable_script_idx = self.get_selectable_script(txt2imgreq.script_name, script_runner)
 
         populate = txt2imgreq.copy(update={  # Override __init__ params
@@ -235,7 +252,7 @@ def text2imgapi(self, txt2imgreq: StableDiffusionTxt2ImgProcessingAPI):
         args.pop('script_args', None) # will refeed them to the pipeline directly after initializing them
         args.pop('alwayson_scripts', None)
 
-        script_args = self.init_script_args(txt2imgreq, selectable_scripts, selectable_script_idx, script_runner)
+        script_args = self.init_script_args(txt2imgreq, self.default_script_arg_txt2img, selectable_scripts, selectable_script_idx, script_runner)
 
         send_images = args.pop('send_images', True)
         args.pop('save_images', None)
@@ -272,6 +289,8 @@ def img2imgapi(self, img2imgreq: StableDiffusionImg2ImgProcessingAPI):
         if not script_runner.scripts:
             script_runner.initialize_scripts(True)
             ui.create_ui()
+        if not self.default_script_arg_img2img:
+            self.default_script_arg_img2img = self.init_default_script_args(script_runner)
         selectable_scripts, selectable_script_idx = self.get_selectable_script(img2imgreq.script_name, script_runner)
 
         populate = img2imgreq.copy(update={  # Override __init__ params
@@ -289,7 +308,7 @@ def img2imgapi(self, img2imgreq: StableDiffusionImg2ImgProcessingAPI):
         args.pop('script_args', None)  # will refeed them to the pipeline directly after initializing them
         args.pop('alwayson_scripts', None)
 
-        script_args = self.init_script_args(img2imgreq, selectable_scripts, selectable_script_idx, script_runner)
+        script_args = self.init_script_args(img2imgreq, self.default_script_arg_img2img, selectable_scripts, selectable_script_idx, script_runner)
 
         send_images = args.pop('send_images', True)
         args.pop('save_images', None)


Test patch: