Repository: AUTOMATIC1111/stable-diffusion-webui

Issue:
[Bug]: Grid images of batch runs have incorrect metadata when the prompt changes over the batch (e.g. using wildcards)
### Is there an existing issue for this?

- [X] I have searched the existing issues and checked the recent builds/commits

### What happened?

This is halfway between a bug and feature request. I have a fix already implemented and will submit a PR later today.

The grid image of a batch run currently gets metadata identical to the first image of the batch. This is generally useful, because users can send the grid image to txt2img and reproduce the whole batch.

But there are extensions that modify the prompt for different images of a batch, e.g. wildcard extensions like [stable-diffusion-webui-wildcards](https://github.com/AUTOMATIC1111/stable-diffusion-webui-wildcards) or [sd-dynamic-prompts](https://github.com/adieyal/sd-dynamic-prompts), or another that I'm currently working on. The hardcoded webui behavior is slightly broken for these extensions since the grid image no longer contains the original prompt with the wildcard templates (it gets overwritten by the randomly generated tokens in the first image). The extension dev can work around this problem by duplicating the original prompt in `extra_generation_params` but this is awkward, pollutes the metadata with another huge prompt string and requires additional save/reload infrastructure by the extension dev.

Instead I think the batch grid should retain the original prompt used to create it (i.e. including the templates). Then the wildcards user can reproduce either individual images by sending the image to tx2img or the entire batch by sending the grid image instead.

The fix involves using `p.prompt` for grid images and `all_prompts[index]` for other images, see [line 587 of processing.py](https://github.com/stablegeniusdiffuser/stable-diffusion-webui/blob/baf6946e06249c5af9851c60171692c44ef633e0/modules/processing.py#L587).

### Steps to reproduce the problem

1. Create a batch using wildcards.
2. Examine the metadata of the grid image.


### What should have happened?

Keep the original prompt in the grid image metadata as described above.

### Commit where the problem happens

baf6946e (master) or 59419bd6 (dev)

### What Python version are you running on ?

Python 3.10.x

### What platforms do you use to access the UI ?

Windows

### What device are you running WebUI on?

Nvidia GPUs (RTX 20 above)

### What browsers do you use to access the UI ?

Google Chrome

### Command Line Arguments

```Shell
no
```


### List of extensions

https://github.com/adieyal/sd-dynamic-prompts

### Console logs

```Shell
no
```


### Additional information

_No response_


Discussion:

Resolving patch:
diff --git a/modules/processing.py b/modules/processing.py
--- a/modules/processing.py
+++ b/modules/processing.py
@@ -549,7 +549,7 @@ def program_version():
     return res
 
 
-def create_infotext(p, all_prompts, all_seeds, all_subseeds, comments=None, iteration=0, position_in_batch=0):
+def create_infotext(p, all_prompts, all_seeds, all_subseeds, comments=None, iteration=0, position_in_batch=0, use_main_prompt=False):
     index = position_in_batch + iteration * p.batch_size
 
     clip_skip = getattr(p, 'clip_skip', opts.CLIP_stop_at_last_layers)
@@ -589,9 +589,10 @@ def create_infotext(p, all_prompts, all_seeds, all_subseeds, comments=None, iter
 
     generation_params_text = ", ".join([k if k == v else f'{k}: {generation_parameters_copypaste.quote(v)}' for k, v in generation_params.items() if v is not None])
 
+    prompt_text = p.prompt if use_main_prompt else all_prompts[index]
     negative_prompt_text = f"\nNegative prompt: {p.all_negative_prompts[index]}" if p.all_negative_prompts[index] else ""
 
-    return f"{all_prompts[index]}{negative_prompt_text}\n{generation_params_text}".strip()
+    return f"{prompt_text}{negative_prompt_text}\n{generation_params_text}".strip()
 
 
 def process_images(p: StableDiffusionProcessing) -> Processed:
@@ -663,8 +664,8 @@ def process_images_inner(p: StableDiffusionProcessing) -> Processed:
     else:
         p.all_subseeds = [int(subseed) + x for x in range(len(p.all_prompts))]
 
-    def infotext(iteration=0, position_in_batch=0):
-        return create_infotext(p, p.all_prompts, p.all_seeds, p.all_subseeds, comments, iteration, position_in_batch)
+    def infotext(iteration=0, position_in_batch=0, use_main_prompt=False):
+        return create_infotext(p, p.all_prompts, p.all_seeds, p.all_subseeds, comments, iteration, position_in_batch, use_main_prompt)
 
     if os.path.exists(cmd_opts.embeddings_dir) and not p.do_not_reload_embeddings:
         model_hijack.embedding_db.load_textual_inversion_embeddings()
@@ -824,7 +825,7 @@ def infotext(iteration=0, position_in_batch=0):
             grid = images.image_grid(output_images, p.batch_size)
 
             if opts.return_grid:
-                text = infotext()
+                text = infotext(use_main_prompt=True)
                 infotexts.insert(0, text)
                 if opts.enable_pnginfo:
                     grid.info["parameters"] = text
@@ -832,7 +833,7 @@ def infotext(iteration=0, position_in_batch=0):
                 index_of_first_image = 1
 
             if opts.grid_save:
-                images.save_image(grid, p.outpath_grids, "grid", p.all_seeds[0], p.all_prompts[0], opts.grid_format, info=infotext(), short_filename=not opts.grid_extended_filename, p=p, grid=True)
+                images.save_image(grid, p.outpath_grids, "grid", p.all_seeds[0], p.all_prompts[0], opts.grid_format, info=infotext(use_main_prompt=True), short_filename=not opts.grid_extended_filename, p=p, grid=True)
 
     if not p.disable_extra_networks and p.extra_network_data:
         extra_networks.deactivate(p, p.extra_network_data)


Test patch: