InvokeAI icon indicating copy to clipboard operation
InvokeAI copied to clipboard

[enhancement]: Bring back non-combinatorial dynamic prompts

Open gaspesla opened this issue 2 years ago • 17 comments

Is there an existing issue for this?

  • [X] I have searched the existing issues

Contact Details

[email protected]

What should this feature add?

In 3.3.0, dynamic prompts are now always combinatorial, running through all possible prompts in a fixed order. This means it's no longer possible to use the dynamic prompt feature to quickly get some variety. (I'm really not sure what it's for now?) Therefore, I'm requesting a way to turn off the combinatorial nature of the dynamic prompts feature.

For example, I'd like to give it a prompt like:

{rain|snow|sleet} on a {farm|pond|river}

and have it generate an arbitrary number of images with different seeds but with randomly selected dynamic phrasing.

Currently, my only option is to generate all nine possible combinations, always in the same fixed order.

Alternatives

I was hoping I could work around this limitation by doing multiple iterations with Max Prompts set to 1, but doing this completely deactivates the Dynamic Prompts feature. Setting it to 2 will always only ever generate rainy farms and rainy ponds.

Anyway, maybe I am just misunderstanding Dynamic Prompts, but not finding a use for it just yet. Thanks!

Additional Content

No response

gaspesla avatar Oct 16 '23 21:10 gaspesla

There are two common use-cases for dynamic prompts:

  1. Exploring the "prompt space" for a given seed by generating many variations of a prompt
  2. Getting some quick variation

#1 is what the app currently serves. #2 is what you (and at least one other person) have requested to be restored as an option.

I'm happy to bring this back. It shouldn't be too hard, as the backend that generates the prompts still has combinatorial as an option.


This would be a good first issue. The state, UI component to toggle combinatorial, and the backend route still exist, so the code changes would be pretty minimal.

My initial thoughts on implementing this:

  • Add a <ParamDynamicPromptsCombinatorial /> switch back to <ParamDynamicPromptsCollapse />
  • Add the combinatorial arg back to the dynamic prompts query in invokeai/frontend/web/src/services/api/endpoints/utilities.ts
  • In the debounced listener for dynamic prompts (invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/promptChanged.ts), grab the combinatorial boolean and use it in the query

There is one complication, though. The app currently always uses dynamic prompts. This is very convenient, because you don't need to toggle anything to use the syntax - it just works if you use the syntax.

If we allow disabling combinatorial, then you get situations where a prompt without the dynamic prompt syntax generates the max number of prompts: image

This is clearly not ideal. One solution might be to add an exclude duplicates option to the dynamic prompts UI that filters out duplicate prompts.

If you want to work on this request, check in before making a PR. Please reply here to raise your hand and describe your plan. My proposed solution may not be the best one - maybe there's a better user experience we can offer.

psychedelicious avatar Oct 18 '23 03:10 psychedelicious

The support article here says that

Once a Dynamic Prompt is configured, the system generates an array of combinations using the options provided. These combinations will then be ran in random order until the "Images" setting has been reached.

Is it out of date?

mirrexagon avatar Oct 31 '24 08:10 mirrexagon

Please implement at least a checkerbox "random combination" which forces Invoke to randomly choose a combination from all possible on each prompt. Exploring the prompt space is nice, but the real randomness without forcing me to iterate through numerous images is what I need 95% more often.

vkleinmp avatar Nov 04 '24 17:11 vkleinmp

I came here today to request exactly this. raises hand: me, too

From an implementation standpoint, while I can only guess as I don't know the code, I figure there must be some code that does the "oh, prompt list has more than (x, default 100) entries, truncate it" logic. Adding a "shuffle the list if flag is set" just before that step should be doable unless the architecture is doing some weirdly indirect things.

Because combining truncating with a list shuffle is exactly the same as picking a number of random choices from a list.

However, I see a potential pitfall with multiple iterations. Ideally, the shuffle+truncate should either run per iteration, not per batch, or be settable to per batch/iteration like the seed is for per image/iteration. If the current truncation is per batch, and not easily movable to per iteration, that could be an issue with this strategy.

HenryLoenwind avatar Dec 12 '24 16:12 HenryLoenwind

It seems that the ImpactWildcardProcessor offers the functionality people are asking for here.

gruppler avatar Dec 12 '24 21:12 gruppler

@HenryLoenwind The requested functionality is included in the dynamic-prompts library that the app uses, but not exposed in the UI. I made some suggestions over a year ago, which are still valid, in case a contributor wanted to work on this.

@gruppler That appears to be a comfy UI node, not compatible with Invoke.

psychedelicious avatar Dec 12 '24 21:12 psychedelicious

I just wanted to add a +1 for this ticket, I would love to see this upgrade so we can use dynamic prompting for variation again!!

ratacat avatar Jan 03 '25 19:01 ratacat

I'd like to see this too.

Scn64 avatar Jan 12 '25 07:01 Scn64

No updates from me, sorry. We'd love for a contributor to raise their hand for this feature. While we recognize it is a useful feature, we don't have any timeline for when we will get to it.

psychedelicious avatar Jan 24 '25 02:01 psychedelicious

Was looking for a solution to this exact issue—having it random would make it much more useful.

Volutionn avatar Jan 24 '25 08:01 Volutionn

Quick Fix

If you're looking for a quick solution, here's what worked for me:

  1. Open the following file: [invokeai_directory]/.venv/lib/python3.x/site-packages/invokeai/app/api/routers/utilities.py

  2. Locate the function parse_dynamicprompts.

  3. Update the following line: combinatorial: bool = Body(default=True, description="Whether to use the combinatorial generator")

    Change it to: combinatorial: bool = Body(default=False, description="Whether to use the combinatorial generator")

  4. Save the file and restart InvokeAI.

Volutionn avatar Jan 24 '25 10:01 Volutionn

Quick Fix

If you're looking for a quick solution, here's what worked for me:

  1. Open the following file: [invokeai_directory]/.venv/lib/python3.x/site-packages/invokeai/app/api/routers/utilities.py
  2. Locate the function parse_dynamicprompts.
  3. Update the following line: combinatorial: bool = Body(default=True, description="Whether to use the combinatorial generator") Change it to: combinatorial: bool = Body(default=False, description="Whether to use the combinatorial generator")
  4. Save the file and restart InvokeAI.

Great, thanks. The only caveat left is that at always generates the same combinations on consecutive batches. If it would just reshuffle them after a users submission it would be perfect.

vkleinmp avatar Jan 24 '25 10:01 vkleinmp

Great, thanks. The only caveat left is that at always generates the same combinations on consecutive batches. If it would just reshuffle them after a users submission it would be perfect.

@vkleinmp I noticed the same thing, but If you change the max prompts it actually reshuffles them. To reshuffle while keeping the same max prompts, say you have 50 max prompts—just set it to 49, refresh the page, and then set it back to 50. The result prompts will be reshuffled.

@Volutionn i dont see any of those similar files... this is how it looks for me?

@vedomedia the .env folder is usually hidden. If you enable the option to display hidden items, you should be able to see it. Alternatively, you can open your app's folder with VSCode, which shows hidden folders by default, and then search for this line across the folders: combinatorial: bool = Body(default=True, description="Whether to use the combinatorial generator")

Volutionn avatar Jan 25 '25 00:01 Volutionn

I tried using the ~ and @ symbols (example below) which would have been the perfect solution but doesn't work. Why not include it in InvokeAi (version 5.6.2) ?

Example: {~mega twintails|floofy bob|double bun} {@blue|pink|green|rainbow}

Source: https://github.com/adieyal/sd-dynamic-prompts/blob/main/docs/SYNTAX.md#samplers

SebastieZ avatar Feb 23 '25 05:02 SebastieZ

@SebastieZ Invoke does support that syntax, but a caching layer prevents it from giving you random results.

Invoke exposes the dynamic prompts library behind a HTTP API. You can use it here, after starting the app: http://localhost:9090/docs#/utilities/parse_dynamicprompts

In that interface, if you try the example prompt you provided a few times, you'll see it returns a new value each time.

But, as mentioned, the requests are cached when prompt parsing occurs in the UI. I'm going to skip over some technical stuff but suffice to say, Invoke's UI and graph execution make it tricky to opt of this caching.

The most straightforward way to enable that syntax in the UI would be to add a "reroll" button that clears the query cache and/or forces re-parsing the prompt. We'd be happy for a contributor to improve on this.

psychedelicious avatar Feb 24 '25 01:02 psychedelicious

Thanks @psychedelicious for this answer !!

This is the only way I found to get prompts with random content with InvokeAi.

In the official version of the utilities.py file located in the "invokeai.venv\Lib\site-packages\invokeai\app\api\routers" folder, I replaced the line "combinatorial: bool = Body(default=True, description="Whether to use the combinatorial generator")," with "combinatorial: bool = Body(default=False, description="Whether to use the combinatorial generator"),". Thanks @Volutionn!

In InvokeAi, I write my prompt "A {cat|dog|rabbit} with a {red|blue|green} collar, in a mysterious forest." with 1 iterations and I use the "Dynamic Prompts" interface to determine the number of images to generate by choosing a number such as 4 in the "Maximum number of prompts" option. I then get 4 different prompts with random content for 1 iteration, for a total of 4 generations. The problem now is that if I restart a new iteration, it will be done with the same 4 prompts. The solution is simple, just refresh the page with F5 to have 4 new prompts per iteration.

Be careful, if in the "Dynamic Prompts" interface, on the "Seed behavior" line, I choose "Seed per iteration (Use a different seed for each iteration)", I then get 4 images with the same seed since I only have 1 iteration. So you have to choose "Seed per image (Use a different seed for each image)" and InvokeAi will increment the previous seed by +1 at each prompt.

Example:

image 1 with a seed 1234567890 image 2 with a seed 1234567891 image 3 with a seed 1234567892 image 4 with a seed 1234567893

SebastieZ avatar Feb 24 '25 09:02 SebastieZ

You're welcome!

With that change, indeed you must refresh the page to get new prompts. That's the caving layer at work. You could also change any character in the prompt. For example, add a space. I think that would trigger it to get new prompts without refreshing.

psychedelicious avatar Feb 24 '25 11:02 psychedelicious