pull/68/head
ThereforeGames 2023-01-25 20:47:33 -05:00
parent 3e50472878
commit 4786902851
24 changed files with 675 additions and 209 deletions

2
.gitignore vendored
View File

@ -133,7 +133,5 @@ dmypy.json
/templates/* /templates/*
# Default Templates # Default Templates
!/templates/common !/templates/common
!/templates/examples
!/templates/human
# clipseg weights # clipseg weights
/lib/clipseg/weights/* /lib/clipseg/weights/*

View File

@ -1,85 +0,0 @@
<p align="center">
<img src="https://user-images.githubusercontent.com/95403634/206286547-53f22ebf-e5fc-4bbd-8bad-53b9cb17ae64.png">
</p>
<p align="center"><strong>Links:</strong> 📣 <a href="./docs/ANNOUNCEMENTS.md">Announcements</a> | 📘 <a href="./docs/MANUAL.md">Manual</a> | ⏱ <a href="./docs/CHANGELOG.md">Changelog</a> | 🎓 <a href="./docs/GUIDE.md">Starter Guide</a></p>
## Introduction
**Unprompted is a powerful templating language written in Python.**
Unlike most templating languages, Unprompted was designed for **maximum readibility with natural language.** It is built around `[shortcodes]` and inspired by the likes of BBCode.
You can use Unprompted as a standalone library (e.g. `unprompted_dry.py`) or as an extension for [AUTOMATIC1111's Stable Diffusion Web UI](https://github.com/AUTOMATIC1111/stable-diffusion-webui). The extension allows you to create expressive, re-usable prompt templates that are both versatile and easy on the eyes.
## Features
- **Dozens of shortcodes** provided out of the box - there are `[if]` conditionals, powerful `[file]` imports, `[for]` loops and everything else the prompting enthusiast could possibly want
- Easily extendable with **custom shortcodes**
- Simple creation of `.txt` templates that can be organized according to your preferences
- Supports recursion, nested shortcodes, advanced logic operators, custom configs, pretty much all the good stuff one might expect from a modern language
- Supports **numerous Stable Diffusion variables** such as `negative_prompt` and `cfg_scale`
- Includes a growing list of examples that demonstrate advanced functionality, such as **customizing the weight of a choice list** and **applying emphasis to a random part of your prompt**
- Comprehensive documentation that is always up-to-date
- Free
- Developed by a human
## Installation
1. Visit the **Extensions** tab of Automatic's WebUI.
2. Visit the **Available** subtab.
3. Uncheck the "ads" filter and press the **Load from** button.
4. Scroll down to **Unprompted** and press the **Install** button.
## Usage
First, try the included demo template by entering the following as your prompt:
`[file human/main]`
This is a simple "person generator" that automatically chooses characteristics like hair color, race, and posture.
The `[file]` shortcode will look in `unprompted/templates` for the specified text file (in this case `unprompted/templates/human/main.txt`.) You do not need to enter the file extension.
**Example output:**
![image](https://user-images.githubusercontent.com/95403634/206287476-eb37cdaa-723d-41f4-bac9-02056e55767a.png)
## Next Steps
Once you have verified that Unprompted is installed and running correctly, you have a couple options:
1. You can visit the 🎓 [Starter Guide](./docs/GUIDE.md) for a crash course on creating your own templates
2. Or dive into the deep end by exploring the comprehensive 📘 [Manual](./docs/MANUAL.md)
## Premium Templates
While Unprompted is completely free to use, we do offer **Premium Template add-ons** that demonstrate some of the software's more advanced functionality.
<img align="left" src="https://i.ibb.co/1MSpHL4/Fantasy-Card-Template2.png" width=150>
### [Fantasy Card Template](https://payhip.com/b/hdgNR)
Generate a wide variety of creatures and characters in the style of a fantasy card game. Perfect for heroes, animals, monsters, and even crazy hybrids.
<br/>
<br/>
<br/>
<br/>
<br/>
<br/>
<br/>
<br/>
Purchases help fund this project. Your support is greatly appreciated! ❤️
## Acknowledgements
A big "thank you" to the authors of the following libraries that Unprompted depends on:
- [Python Shortcodes](https://www.dmulholl.com/dev/shortcodes.html) by Darren Mulholland
- [Simple Eval](https://github.com/danthedeckie/simpleeval) by @danthedeckie
- [Casefy](https://github.com/dmlls/python-casefy) by @dmlls
- [CLIPseg](https://github.com/timojl/clipseg) by uddecke, Timo and Ecker, Alexander
## 🔧 Found a problem? [Open an Issue.](https://github.com/ThereforeGames/unprompted/issues)
## 💬 For discussion and template sharing, use [the Discussion Board.](https://github.com/ThereforeGames/unprompted/discussions)

View File

@ -3,6 +3,27 @@ All notable changes to this project will be documented in this file.
For more details on new features, please check the [Manual](./MANUAL.md). For more details on new features, please check the [Manual](./MANUAL.md).
<details><summary>6.0.0 - 25 January 2023</summary>
### Added
- You can now change the active SD checkpoint with `[set sd_model]`
- New `[instance2mask]` shortcode by WeberSamuel (PR #48)
- New `[invert_mask]` shortcode by WeberSamuel (PR #48)
- New `[enable_multi_images]` shortcode by WeberSamuel (PR #48)
- The `[txt2mask]` shortcode now supports GPU (PR #48)
- New `[txt2mask]` arguments: `neg_precision`, `neg_padding`, and `neg_smoothing` by WeberSamuel (PR #48)
- The `[txt2mask]` argument `show` will also append a segmentation mask (PR #48)
- New UI option `Unprompted Seed` allows you to reproduce images that feature shortcodes with randomness, such as `[choose]`
### Changed
- Wizard Function default values are no longer written to ui-config.json
- Fixed `[img2img]` syntax for compatibility with latest A1111
- Fixed a rounding issue with Wizard shortcode number fields
- The Manual and Starter Guide have been reorganized into collapsible sections
- Moved all included templates into `templates\common` for simplicity
</details>
<details><summary>5.2.0 - 24 January 2023</summary> <details><summary>5.2.0 - 24 January 2023</summary>
### Added ### Added

View File

@ -1,10 +1,10 @@
# Starter Guide # Starter Guide
Let's walk through the process of making your own templates for Unprompted. It's fun and easy. Your first Unprompted template. It's a big step, I know. You feeling nervous? A sense of tremendous pressure maybe? Don't worry, it's not that hard to set this thing up.
For the purposes of this guide, we will construct a basic "human generator" similar to the one that is included with the repo download. For the purposes of this guide, we will construct a basic "human generator" similar to the one that is included with the repo download.
## 1) Create the entry point <details><summary>Step 1: Create the entry point</summary>
In the root directory of the WebUI app, navigate to `extensions/unprompted/templates`. This is where all your templates belong - you can organize the files here in any way you like. In the root directory of the WebUI app, navigate to `extensions/unprompted/templates`. This is where all your templates belong - you can organize the files here in any way you like.
@ -30,7 +30,9 @@ You can check the information underneath the resulting picture to confirm that S
Cool! Now let's proceed to the good stuff... Cool! Now let's proceed to the good stuff...
## 2) Using the \[choose\] shortcode </details>
<details><summary>Step 2: Using the [choose] shortcode</summary>
Let's ask Unprompted to choose between a man and a woman. This is easy to do: Let's ask Unprompted to choose between a man and a woman. This is easy to do:
@ -76,7 +78,9 @@ Yes, we are using a `[file]` shortcode inside of another file. This is perhaps o
Next, let's check out some other shortcodes we can use. Next, let's check out some other shortcodes we can use.
## 3) Managing Stable Diffusion options with \[set\] </details>
<details><summary>Step 3: Managing Stable Diffusion options with [set]</summary>
Unprompted has the ability to manage variables using `[set]` and `[get]`. You can create your own variables or even adjust the system variables used by the image generator. Unprompted has the ability to manage variables using `[set]` and `[get]`. You can create your own variables or even adjust the system variables used by the image generator.
@ -95,7 +99,9 @@ For improved image quality, we can also force a CFG scale of 7 and turn on the "
Now no matter how we change the UI, our template will continue using these optimized values. Now no matter how we change the UI, our template will continue using these optimized values.
## 4) Overriding parts of the template </details>
<details><summary>Step 4: Overriding parts of the template</summary>
Imagine a situation where you want the randomness a template offers, but you need to lock in a certain word or phrase of your choosing. Imagine a situation where you want the randomness a template offers, but you need to lock in a certain word or phrase of your choosing.
@ -123,7 +129,9 @@ That's it, now you've got pandas!
In the final section, we will learn about some more advanced functions. In the final section, we will learn about some more advanced functions.
## 5) Conditional shortcodes </details>
<details><summary>Step 5: Conditional shortcodes</summary>
The last subject I want to discuss are the conditional shortcodes `[if]` and `[chance]`. These will evaluate given variable(s) in deciding what to output. The last subject I want to discuss are the conditional shortcodes `[if]` and `[chance]`. These will evaluate given variable(s) in deciding what to output.
@ -147,12 +155,16 @@ Finally, if we want to make this occur only 75% of the time, we introduce `[chan
He'd like to congratulate you on making it this far. He'd like to congratulate you on making it this far.
## In conclusion </details>
<details><summary>GG no RE</summary>
I hope you found this starter guide useful and now have a better idea of what Unprompted brings to the table! I hope you found this starter guide useful and now have a better idea of what Unprompted brings to the table!
We have only scratched the surface here - when you're ready to do a deeper dive, please check out the full documentation here: We have only scratched the surface here - when you're ready to do a deeper dive, please check out the full documentation here (or simply click on the Manual tab if you're inside of the app itself):
[Unprompted Manual](MANUAL.md) [Unprompted Manual](MANUAL.md)
Good luck! Good luck!
</details>

View File

@ -2,45 +2,11 @@
Shortcode syntax is subject to change based on community feedback. Shortcode syntax is subject to change based on community feedback.
## Adding New Shortcodes If you encounter any confusing, incomplete, or out-of-date information here, please do not hesitate to open an issue. I appreciate it!
Shortcodes are loaded as Python modules from `unprompted/shortcodes`. You can make your own shortcodes by creating files there (preferably within the `/custom` subdirectory.) ## Proficiency
The shortcode name is defined by the filename, e.g. `override.py` will give you the ability to use `[override]`. Shortcode filenames should be unique. <details><summary>Atomic vs Block Shortcodes</summary>
A shortcode is structured as follows:
```
class Shortcode():
"""A description of the shortcode goes here."""
def __init__(self,Unprompted):
self.Unprompted = Unprompted
def run_block(self, pargs, kwargs, context,content):
return("")
def cleanup(self):
return("")
```
The `__init__` function gives the shortcode access to our main Unprompted object, and it's where you should declare any unique variables for your shortcode.
The `run_block` function contains the main logic for your shortcode. It has access to these special variables (the following documentation was pulled from the [Python Shortcodes](https://www.dmulholl.com/dev/shortcodes.html) library, on which Unprompted depends):
- `pargs`: a list of the shortcode's positional arguments.
- `kwargs`: a dictionary of the shortcode's keyword arguments.
- `context`: an optional arbitrary context object supplied by the caller.
- `content`: the string within the shortcode tags, e.g. `[tag]content[/tag]`
Positional and keyword arguments are passed as strings. The function itself should return a string which will replace the shortcode in the parsed text.
The `cleanup` function runs at the end of the processing chain. You can free any unnecessary variables from memory here.
For more details, please examine the code of the stock shortcodes.
## Atomic vs Block Shortcodes
Unprompted supports two types of shortcodes: Unprompted supports two types of shortcodes:
@ -61,7 +27,9 @@ def run_atomic(self, pargs, kwargs, context):
Atomic shortcodes do not receive a `content` variable. Atomic shortcodes do not receive a `content` variable.
## Understanding the Processing Chain </details>
<details><summary>Understanding the Processing Chain</summary>
It is important to understand that **inner shortcodes are processed before outer shortcodes**. It is important to understand that **inner shortcodes are processed before outer shortcodes**.
@ -79,7 +47,9 @@ In Unprompted, `another_var` will equal 0 regardless of the outcome of the `if`
The following section offers a solution. The following section offers a solution.
## Secondary Shortcode Tags </details>
<details><summary>Secondary Shortcode Tags</summary>
Unprompted allows you to write tags using `{}` instead of `[]` to defer processing. Unprompted allows you to write tags using `{}` instead of `[]` to defer processing.
@ -94,7 +64,7 @@ This way, the inner shortcode is not processed until *after* it is returned by t
Secondary shortcode tags give us a couple additional benefits: Secondary shortcode tags give us a couple additional benefits:
- If your shortcode is computationally expensive, you can avoid running it unless the outer shortcode succeeds. This is good for performance. - If your shortcode is computationally expensive, you can avoid running it unless the outer shortcode succeeds. This is good for performance.
- **You can pass them as arguments in shortcodes that support it.** For example, if you want to run the `[chance]` shortcode with dynamic probability, you can do it like this: `[chance _probability="{get my_var}"]content[/chance]` - **You can pass them as arguments in shortcodes that support it.** For example, if you want to run the `[chance]` shortcode with dynamic probability, you can do it like this: `[chance "{get my_var}"]content[/chance]`
Secondary shortcode tags can have infinite nested depth. The number of `{}` around a shortcode indicates its nested level. Consider this example: Secondary shortcode tags can have infinite nested depth. The number of `{}` around a shortcode indicates its nested level. Consider this example:
@ -124,7 +94,9 @@ wow
Rinse and repeat until no `{}` remain. Rinse and repeat until no `{}` remain.
## Advanced expressions </details>
<details><summary>Advanced Expressions</summary>
Most shortcodes support programming-style evaluation via the [simpleeval library](https://github.com/danthedeckie/simpleeval). Most shortcodes support programming-style evaluation via the [simpleeval library](https://github.com/danthedeckie/simpleeval).
@ -148,7 +120,9 @@ You can even mix advanced expressions with shortcodes. Check this out:
For more information on constructing advanced expressions, check the documentation linked above. For more information on constructing advanced expressions, check the documentation linked above.
## Escaping characters </details>
<details><summary>Escaping Characters</summary>
Use the backtick to print a shortcode as a literal part of your prompt. This may be useful if you wish to take advantage of the prompt editing features of the A1111 WebUI (which are denoted with square brackets and could thus conflict with Unprompted shortcodes.) Use the backtick to print a shortcode as a literal part of your prompt. This may be useful if you wish to take advantage of the prompt editing features of the A1111 WebUI (which are denoted with square brackets and could thus conflict with Unprompted shortcodes.)
@ -160,7 +134,23 @@ Also note: if a shortcode is undefined, Unprompted will print it as a literal as
Photo of a `[cat|dog] Photo of a `[cat|dog]
``` ```
## Why some shortcode arguments begin with an _underscore </details>
<details><summary>System Variables</summary>
In addition to all of the Stable Diffusion variables exposed by Automatic1111's WebUI, Unprompted gives you access to the following variables:
### batch_index
An integer that correponds to your progress in a batch run. For example, if your batch count is set to 5, then `batch_index` will return a value from 0 to 4.
### sd_model
You can set this variable to the name of a Stable Diffusion checkpoint, and Unprompted will load that checkpoint at the start of inference. This variable is powered by the WebUI's `get_closet_checkpoint_match()` function, which means that your model name does not have to be 100% accurate - but you should strive to use a string that's as accurate as possible.
</details>
<details><summary>Why some shortcode arguments begin with an _underscore</summary>
We use underscores to denote optional system arguments in shortcodes that may also accept dynamic, user-defined arguments. We use underscores to denote optional system arguments in shortcodes that may also accept dynamic, user-defined arguments.
@ -174,8 +164,12 @@ In short, if the argument begins with `_`, the program will assume it is a syste
That said, we're still ironing out the methodology for underscores - at the moment, some arguments may use underscores where it isn't strictly necessary. If you find any such cases feel free to open an Issue or Discussion Thread about it. That said, we're still ironing out the methodology for underscores - at the moment, some arguments may use underscores where it isn't strictly necessary. If you find any such cases feel free to open an Issue or Discussion Thread about it.
</details>
## The Wizard ## The Wizard
<details><summary>What is the Wizard?</summary>
The Unprompted WebUI extension has a dedicated panel called the Wizard. It is a GUI-based shortcode builder. The Unprompted WebUI extension has a dedicated panel called the Wizard. It is a GUI-based shortcode builder.
Pressing **"Generate Shortcode"** will assemble a ready-to-use block of code that you can add to your prompts. Pressing **"Generate Shortcode"** will assemble a ready-to-use block of code that you can add to your prompts.
@ -184,7 +178,9 @@ Alternatively, you can enable `Auto-include this in prompt` which will add the s
The Wizard includes two distinct modes: Shortcodes and Functions. The Wizard includes two distinct modes: Shortcodes and Functions.
### Shortcodes Mode </details>
<details><summary>Shortcodes Mode</summary>
This mode presents you with a list of all shortcodes that have a `ui()` block in their source code. This mode presents you with a list of all shortcodes that have a `ui()` block in their source code.
@ -212,7 +208,9 @@ There are a few reserved argument names that will modify the Wizard's behavior:
- `str`: This will inject the field's value into the shortcode, enclosing it in quotation marks. - `str`: This will inject the field's value into the shortcode, enclosing it in quotation marks.
- `int`: This will inject the field's value into the shortcode, casting it as an integer. - `int`: This will inject the field's value into the shortcode, casting it as an integer.
### Functions Mode </details>
<details><summary>Functions Mode</summary>
This mode presents you with a list of txt files inside your `Unprompted/templates` directory that begin with a `[template]` block. This mode presents you with a list of txt files inside your `Unprompted/templates` directory that begin with a `[template]` block.
@ -232,7 +230,9 @@ The `[set]` block supports `_ui` which determines the type of UI element to rend
- `dropdown`: A dropdown menu that is populated by the `_choices` argument, constructed as a delimited list. - `dropdown`: A dropdown menu that is populated by the `_choices` argument, constructed as a delimited list.
- `slider`: Limits selection to a range of numbers. You must also specify `_minimum`, `_maximum` and `_step` (step size, normally 1) for this element to work properly. - `slider`: Limits selection to a range of numbers. You must also specify `_minimum`, `_maximum` and `_step` (step size, normally 1) for this element to work properly.
## The config file </details>
<details><summary>The config file</summary>
Various aspects of Unprompted's behavior are controlled through `unprompted/config.json`. Various aspects of Unprompted's behavior are controlled through `unprompted/config.json`.
@ -301,20 +301,11 @@ The main purpose of this setting is for hardcoding shortcodes you want to run ev
Same as above, but for the negative prompt. Same as above, but for the negative prompt.
## System Variables </details>
In addition to all of the Stable Diffusion variables exposed by Automatic1111's WebUI, Unprompted gives you access to the following variables: ## Shortcodes
### batch_index
An integer that correponds to your progress in a batch run. For example, if your batch count is set to 5, then `batch_index` will return a value from 0 to 4.
## Stable Diffusion Shortcodes
This section describes all of the included shortcodes which are specifically designed for use with the A1111 WebUI.
### [file2mask]
<<<<<<< Updated upstream
Allows you to modify or replace your img2img mask with arbitrary files. Allows you to modify or replace your img2img mask with arbitrary files.
Supports the `mode` argument which determines how the file mask will behave alongside the existing mask: Supports the `mode` argument which determines how the file mask will behave alongside the existing mask:
@ -534,18 +525,22 @@ The content and `negative_mask` both support the vertical pipe delimiter (`|`) w
``` ```
## Basic Shortcodes ## Basic Shortcodes
=======
<details><summary>Basic Shortcodes</summary>
>>>>>>> Stashed changes
This section describes all of the included basic shortcodes and their functionality. This section describes all of the included basic shortcodes and their functionality.
### [#] <details><summary>[#]</summary>
Use this to write comments in your templates. Comments are ultimately discarded by Unprompted and will not affect your final output. Use this to write comments in your templates. Comments are ultimately discarded by Unprompted and will not affect your final output.
``` ```
[# This is my comment.] [# This is my comment.]
``` ```
</details>
### [##] <details><summary>[##]</summary>
Same as `[#]` but for multiline comments. Same as `[#]` but for multiline comments.
@ -557,7 +552,9 @@ I can't believe it, we're doing 3 lines of text!
[/##] [/##]
``` ```
### [after step(int)] </details>
<details><summary>[after step(int)]</summary>
Processes the content after the main task is complete. Processes the content after the main task is complete.
@ -573,7 +570,9 @@ Photo of a cat
[/after] [/after]
``` ```
### [array name(str)] </details>
<details><summary>[array name(str)]</summary>
Manages a group or list of values. Manages a group or list of values.
@ -625,12 +624,15 @@ Supports `_find` which will return the index of the first matching value in the
Supports `_shuffle` which will randomize the order of the array. Supports `_shuffle` which will randomize the order of the array.
</details>
### [case] <details><summary>[case]</summary>
See `[switch]`. See `[switch]`.
### [casing type] </details>
<details><summary>[casing type]</summary>
Converts the casing of content to the selected type. Possible types: Converts the casing of content to the selected type. Possible types:
@ -656,7 +658,9 @@ For more information on these types, consult the [casefy docs](https://github.co
Result: WHY AM I SCREAMING Result: WHY AM I SCREAMING
``` ```
### [chance int {_sides}] </details>
<details><summary>[chance int {_sides}]</summary>
Returns the content if the integer you passed is greater than or equal to a randomly generated number between 1 and 100. Returns the content if the integer you passed is greater than or equal to a randomly generated number between 1 and 100.
@ -666,7 +670,9 @@ You can change the upper boundary by specifying the optional `_sides` argument.
[chance 25]I will show up in your prompt 25% of the time.[/chance] [chance 25]I will show up in your prompt 25% of the time.[/chance]
``` ```
### [choose] </details>
<details><summary>[choose]</summary>
Randomly returns one of multiple options, as delimited by the vertical pipe or newline character. Randomly returns one of multiple options, as delimited by the vertical pipe or newline character.
@ -686,7 +692,7 @@ Supports the optional `_weighted` argument, which allows you to customize the pr
[/choose] [/choose]
``` ```
If you skip a weight value--e.g. `3|Apple|Strawberry`--then the option (Strawberry) will automatically have a weight value of 1. If you skip a weight value--e.g. `3|Apple|Strawberry`--then the following option (Strawberry) will automatically have a weight value of 1.
The weight value dictates the number of times that an option is added to the master list of choices, which is then shuffled and picked from at random. So, if your content is `2|Blue|3|Red|Green` the master list becomes `Blue,Blue,Red,Red,Red,Green`. The weight value dictates the number of times that an option is added to the master list of choices, which is then shuffled and picked from at random. So, if your content is `2|Blue|3|Red|Green` the master list becomes `Blue,Blue,Red,Red,Red,Green`.
@ -694,7 +700,9 @@ The weight value dictates the number of times that an option is added to the mas
[choose]red|yellow|blue|green[/choose] [choose]red|yellow|blue|green[/choose]
``` ```
### [config] </details>
<details><summary>[config]</summary>
Updates your Unprompted settings with the content for the duration of a run. Generally you would put this at the top of a template. Updates your Unprompted settings with the content for the duration of a run. Generally you would put this at the top of a template.
@ -712,7 +720,9 @@ Do not enter a file extension, `.json` is assumed.
[config]./my_custom_settings[/config] [config]./my_custom_settings[/config]
``` ```
### [do until(str)] </details>
<details><summary>[do until(str)]</summary>
Do-until style loop. The content is processed, then the `until` expression is evaluated - if it's true, the content is processed again. Repeat until `until` is false. Do-until style loop. The content is processed, then the `until` expression is evaluated - if it's true, the content is processed again. Repeat until `until` is false.
@ -724,7 +734,9 @@ Do-until style loop. The content is processed, then the `until` expression is ev
[/do] [/do]
``` ```
### [elif] </details>
<details><summary>[elif]</summary>
Shorthand "else if." Equivalent to `[else]{if my_var="something"}content{/if}[/else]`. Shorthand "else if." Equivalent to `[else]{if my_var="something"}content{/if}[/else]`.
@ -734,7 +746,9 @@ Shorthand "else if." Equivalent to `[else]{if my_var="something"}content{/if}[/e
[elif my_var=5]Return this content![/elif] [elif my_var=5]Return this content![/elif]
``` ```
### [else] </details>
<details><summary>[else]</summary>
Returns content if a previous conditional shortcode (e.g. `[if]` or `[chance]`) failed its check, otherwise discards content. Returns content if a previous conditional shortcode (e.g. `[if]` or `[chance]`) failed its check, otherwise discards content.
@ -744,7 +758,9 @@ Returns content if a previous conditional shortcode (e.g. `[if]` or `[chance]`)
[if my_var=0]Print something[/if][else]It turns out my_var did not equal 0.[/else] [if my_var=0]Print something[/if][else]It turns out my_var did not equal 0.[/else]
``` ```
### [eval] </details>
<details><summary>[eval]</summary>
Parses the content using the simpleeval library, returning the result. Particularly useful for arithmetic. Parses the content using the simpleeval library, returning the result. Particularly useful for arithmetic.
@ -754,7 +770,9 @@ simpleeval is designed to prevent the security risks of Python's stock `eval` fu
[eval]5 + 5[/eval] [eval]5 + 5[/eval]
``` ```
### [file path(str)] </details>
<details><summary>[file path(str)]</summary>
Processes the content of `path` (including any shortcodes therein) and returns the result. Processes the content of `path` (including any shortcodes therein) and returns the result.
@ -774,7 +792,9 @@ The file is expected to be `utf-8` encoding. You can change this with the option
[file my_template/common/adjective] [file my_template/common/adjective]
``` ```
### [filelist path(str)] </details>
<details><summary>[filelist path(str)]</summary>
Returns a delimited string containing the full paths of all files in a given path. Returns a delimited string containing the full paths of all files in a given path.
@ -786,7 +806,9 @@ Supports the optional `_delimiter` argument which lets you specify the separator
[filelist "C:/my_pictures/*.*"] [filelist "C:/my_pictures/*.*"]
``` ```
### [for var "test var" "update var"] </details>
<details><summary>[for var "test var" "update var"]</summary>
Returns the content an arbitrary number of times until the `test` condition returns false. Returns the content an arbitrary number of times until the `test` condition returns false.
@ -802,7 +824,9 @@ Current value of i: {get i}
[/for] [/for]
``` ```
### [get variable] </details>
<details><summary>[get variable]</summary>
Returns the value of `variable`. Returns the value of `variable`.
@ -820,7 +844,9 @@ You can change the default separator with `_sep`.
My name is [get name] My name is [get name]
``` ```
### [if variable {_not} {_any} {_is}] </details>
<details><summary>[if variable {_not} {_any} {_is}]</summary>
Checks whether `variable` is equal to the given value, returning the content if true, otherwise discarding the content. Checks whether `variable` is equal to the given value, returning the content if true, otherwise discarding the content.
@ -843,7 +869,9 @@ Supports [advanced expressions](#advanced-expressions) - useful for testing comp
[if "subject is 'man' or subject is 'woman'"]wearing a shirt[/if] [if "subject is 'man' or subject is 'woman'"]wearing a shirt[/if]
``` ```
### [info] </details>
<details><summary>[info]</summary>
Prints metadata about the content. You must pass the type(s) of data as positional arguments. Prints metadata about the content. You must pass the type(s) of data as positional arguments.
@ -862,7 +890,9 @@ Supports `clip_count` for retrieving the number of CLIP tokens in the content (i
Result: 5 Result: 5
``` ```
### [length] </details>
<details><summary>[length]</summary>
Returns the number of items in a delimited string. Returns the number of items in a delimited string.
@ -877,7 +907,9 @@ Supports the optional `_max` argument which caps the value returned by this shor
Result: 3 Result: 3
``` ```
### [max] </details>
<details><summary>[max]</summary>
Returns the greatest value among the arguments. Supports advanced expressions. Returns the greatest value among the arguments. Supports advanced expressions.
@ -889,7 +921,9 @@ Returns the greatest value among the arguments. Supports advanced expressions.
Result: 500 Result: 500
``` ```
### [min] </details>
<details><summary>[min]</summary>
Returns the smallest value among the arguments. Supports advanced expressions. Returns the smallest value among the arguments. Supports advanced expressions.
@ -901,7 +935,9 @@ Returns the smallest value among the arguments. Supports advanced expressions.
Result: 2 Result: 2
``` ```
### [override variable] </details>
<details><summary>[override variable]</summary>
Forces `variable` to equal the given value when attempting to `[set]` it. Forces `variable` to equal the given value when attempting to `[set]` it.
@ -913,7 +949,9 @@ In the example below, `my_variable` will equal "panda" after running the `[set]`
[override my_variable="panda"][set my_variable]fox[/set] [override my_variable="panda"][set my_variable]fox[/set]
``` ```
### [random {_min} {_max} {_float}] </details>
<details><summary>[random {_min} {_max} {_float}]</summary>
Returns a random integer between 0 and the given integer, e.g. `[random 2]` will return 0, 1, or 2. Returns a random integer between 0 and the given integer, e.g. `[random 2]` will return 0, 1, or 2.
@ -925,7 +963,9 @@ If you pass `_float` into this shortcode, it will support decimal numbers instea
[set restore_faces][random 1][/set] [set restore_faces][random 1][/set]
``` ```
### [repeat times(int) {_sep}] </details>
<details><summary>[repeat times(int) {_sep}]</summary>
Processes and returns the content a number of `times`. Processes and returns the content a number of `times`.
@ -940,7 +980,9 @@ Variable is currently: {set my_var _out _append}1</set>
[/repeat] [/repeat]
``` ```
### [replace] </details>
<details><summary>[replace]</summary>
Updates the content using argument pairings as replacement logic. Updates the content using argument pairings as replacement logic.
@ -959,7 +1001,9 @@ A photo of red flowers.
Result: A photo of purple marbles. Result: A photo of purple marbles.
``` ```
### [set {_append} {_prepend}] </details>
<details><summary>[set {_append} {_prepend}]</summary>
Sets a variable to the given content. Sets a variable to the given content.
@ -981,7 +1025,9 @@ Supports all Stable Diffusion variables that are exposed via Automatic's Script
[set my_var]This is the value of my_var[/set] [set my_var]This is the value of my_var[/set]
``` ```
### [sets] </details>
<details><summary>[sets]</summary>
The atomic version of `[set]` that allows you to set multiple variables at once. The atomic version of `[set]` that allows you to set multiple variables at once.
@ -991,7 +1037,9 @@ This shortcode processes your arguments with `[set]` directly, meaning you can t
[sets var_a=10 var_b=something var_c=500] [sets var_a=10 var_b=something var_c=500]
``` ```
### [substring {start} {end} {step} {unit}] </details>
<details><summary>[substring {start} {end} {step} {unit}]</summary>
Returns a slice of the content as determined by the keyword arguments. Returns a slice of the content as determined by the keyword arguments.
@ -1010,7 +1058,9 @@ Returns a slice of the content as determined by the keyword arguments.
Result: photo of a Result: photo of a
``` ```
### [switch var(str)] </details>
<details><summary>[switch var(str)]</summary>
Allows you to run different logic blocks with inner case statements that match the value of the given `var`. Allows you to run different logic blocks with inner case statements that match the value of the given `var`.
@ -1025,7 +1075,9 @@ Allows you to run different logic blocks with inner case statements that match t
[/switch] [/switch]
``` ```
### [while variable {_not} {_any} {_is}] </details>
<details><summary>[while variable {_not} {_any} {_is}]</summary>
Checks whether `variable` is equal to the given value, returning the content repeatedly until the condition is false. This can create an infinite loop if you're not careful. Checks whether `variable` is equal to the given value, returning the content repeatedly until the condition is false. This can create an infinite loop if you're not careful.
@ -1056,7 +1108,9 @@ Advanced expression demo:
[/while] [/while]
``` ```
### [unset variable] </details>
<details><summary>[unset variable]</summary>
Removes one or more variables from memory. Removes one or more variables from memory.
@ -1066,3 +1120,292 @@ Note that variables are automatically deleted at the end of each run - you do **
[set var_a=10 var_b="something"] [set var_a=10 var_b="something"]
[unset var_a var_b] [unset var_a var_b]
``` ```
<<<<<<< Updated upstream
=======
</details>
</details>
<details><summary>Stable Diffusion Shortcodes</summary>
This section describes all of the included shortcodes which are specifically designed for use with the A1111 WebUI.
<details><summary>[file2mask]</summary>
Allows you to modify or replace your img2img mask with arbitrary files.
Supports the `mode` argument which determines how the file mask will behave alongside the existing mask:
- `add` will overlay the two masks. This is the default value.
- `discard` will scrap the existing mask entirely.
- `subtract` will remove the file mask region from the existing mask region.
Supports the optional `_show` positional argument which will append the final mask to your generation output window.
```
Walter White[file2mask "C:/pictures/my_mask.png"]
```
</details>
<details><summary>[img2img]</summary>
Used within the `[after]` block to append an img2img task to your generation.
The image resulting from your main prompt (e.g. the txt2img result) will be used as the initial image for `[img2img]`.
While this shortcode does not take any arguments, most img2img settings can be set in advance. **Does not currently support batch_size or batch_count** - coming soon!
```
Photo of a cat
[after]
{sets prompt="Photo of a dog" denoising_strength=0.75}
{img2img}
[/after]
```
</details>
<details><summary>[img2img_autosize]</summary>
Automatically adjusts the width and height parameters in img2img mode based on the proportions of the input image.
Stable Diffuion generates images in sizes divisible by 64 pixels. If your initial image is something like 504x780, this shortcode will set the width and height to 512x768.
Supports `target_size` which is the minimum possible size of either dimension. Defaults to 512.
Supports `only_full_res` which, if true, will bypass this shortcode unless the "full resolution inpainting" setting is enabled. Defaults to false.
```
[img2img_autosize] Photo of a cat
```
</details>
<details><summary>[init_image path(str)]</summary>
Loads an image from the given `path` and sets it as the initial image for use with img2img.
Note that `path` must be an absolute path, including the file extension.
If the given `path` ends with the `*` wildcard, `[init_image]` will choose a random file in that directory.
**Important:** At the moment, you still have to select an image in the WebUI before pressing Generate, or this shortcode will throw an error. You can select any image - it doesn't matter what it is, just as long as the field isn't empty.
```
[init_image "C:/pictures/my_image.png"]
```
</details>
<details><summary>[invert_mask]</summary>
Inverts the mask. Great in combination with `[txt2mask]` and `[instance2mask]`.
</details>
<details><summary>[instance2mask]</summary>
Uses Mask R-CNN (an instance segmentation model) to predict instances. The found instances are mask. Different from `[txt2mask]` as it allows to run the inpainting for each found instance individually. This is useful, when using high resolution inpainting. This shortcode only works in the img2img tab of the A1111 WebUI.
**Important:** If per_instance is used it is assumed to be the last operator changing the mask.
The supported classes of instances are:
- `person`
- `bicycle`
- `car`
- `motorcycle`
- `airplane`
- `bus`
- `train`
- `truck`
- `boat`
- `traffic light`
- `fire hydrant`
- `stop sign`
- `parking meter`
- `bench`
- `bird`
- `cat`
- `dog`
- `horse`
- `sheep`
- `cow`
- `elephant`
- `bear`
- `zebra`
- `giraffe`
- `backpack`
- `umbrella`
- `handbag`
- `tie`
- `suitcase`
- `frisbee`
- `skis`
- `snowboard`
- `sports ball`
- `kite`
- `baseball bat`
- `baseball glove`
- `skateboard`
- `surfboard`
- `tennis racket`
- `bottle`
- `wine glass`
- `cup`
- `fork`
- `knife`
- `spoon`
- `bowl`
- `banana`
- `apple`
- `sandwich`
- `orange`
- `broccoli`
- `carrot`
- `hot dog`
- `pizza`
- `donut`
- `cake`
- `chair`
- `couch`
- `potted plant`
- `bed`
- `dining table`
- `toilet`
- `tv`
- `laptop`
- `mouse`
- `remote`
- `keyboard`
- `cell phone`
- `microwave`
- `oven`
- `toaster`
- `sink`
- `refrigerator`
- `book`
- `clock`
- `vase`
- `scissors`
- `teddy bear`
- `hair drier`
- `toothbrush`
Supports the `mode` argument which determines how the text mask will behave alongside a brush mask:
- `add` will overlay the two masks. This is the default value.
- `discard` will ignore the brush mask entirely.
- `subtract` will remove the brush mask region from the text mask region.
- `refine` will limit the inital mask to the selected instances.
Supports the optional `mask_precision` argument which determines the confidence of the instance mask. Default is 0.5, max value is 1.0. Lowering this value means you may select more than you intend per instance (instances may overlap).
Supports the optional `instance_precision` argument which determines the classification thresshold for instances to be masked. Reduce this, if instances are not detected successfully. Default is 0.85, max value is 1.0. Lowering this value can lead to wrongly classied areas.
Supports the optional `padding` argument which increases the radius of the instance masks by a given number of pixels.
Supports the optional `smoothing` argument which refines the boundaries of the mask, allowing you to create a smoother selection. Default is 0. Try a value of 20 or greater if you find that your masks are blocky.
Supports the optional `select` argument which defines how many instances to mask. Default value is 0, which means all instances.
Supports the optional `select_mode` argument which specifies which instances are selected:
- `overlap` will select the instances starting with the instance that has the greatest absolute brushed mask in it.
- `overlap relative` behaves similar to `overlap` but normalizes the areas by the size of the instance.
- `greatest area` will select the greatest instances by pixels first.
- `random` will select instances in a random order
Defaults to `overlap`.
Supports the optional `show` positional argument which will append the final masks to your generation output window and for debug purposes a combined instance segmentation image.
Supports the optional `per_instance` positional argument which will render and append the selected masks individually. Leading to better results if full resolution inpainting is used.
```
[instance2mask]clock[/txt2mask]
```
</details>
<details><summary>[enable_multi_images]</summary>
This is a helper shortcode that should be used if multiple init images, multiple masks or in combination with instance2mask per_instance should be used. Use this shortcode at the very end of the prompt, such that it can gather the correct init images and masks. Note that this operator will change the batch_size and batch_count (n_iter).
</details>
<details><summary>[txt2mask]</summary>
A port of [the script](https://github.com/ThereforeGames/txt2mask) by the same name, `[txt2mask]` allows you to create a region for inpainting based only on the text content (as opposed to the brush tool.) This shortcode only works in the img2img tab of the A1111 WebUI.
Supports the `mode` argument which determines how the text mask will behave alongside a brush mask:
- `add` will overlay the two masks. This is the default value.
- `discard` will ignore the brush mask entirely.
- `subtract` will remove the brush mask region from the text mask region.
Supports the optional `precision` argument which determines the confidence of the mask. Default is 100, max value is 255. Lowering this value means you may select more than you intend.
Supports the optional `padding` argument which increases the radius of your selection by a given number of pixels.
Supports the optional `smoothing` argument which refines the boundaries of the mask, allowing you to create a smoother selection. Default is 20. Try increasing this value if you find that your masks are looking blocky.
Supports the optional `size_var` argument which will cause the shortcode to calculate the region occupied by your mask selection as a percentage of the total canvas. That value is stored into the variable you specify. For example: `[txt2mask size_var=test]face[/txt2mask]` if "face" takes up 40% of the canvas, then the `test` variable will become 0.4.
Supports the optional `negative_mask` argument which will subtract areas from the content mask.
Supports the optional `neg_precision` argument which determines the confidence of the negative mask. Default is 100, max value is 255. Lowering this value means you may select more than you intend.
Supports the optional `neg_padding` which is the same as `padding` but for the negative prompts.
Supports the optional `neg_smoothing` which is the same as `smoothing` but for the negative prompts.
Supports the optional `save` argument which will output the final mask as a PNG image to the given filepath.
Supports the optional `show` positional argument which will append the final mask to your generation output window.
Supports the optional `legacy_weights` positional argument which will utilize the original CLIPseg weights. By default, `[txt2mask]` will use the [refined weights](https://github.com/timojl/clipseg#new-fine-grained-weights).
The content and `negative_mask` both support the vertical pipe delimiter (`|`) which allows you to specify multiple subjects for masking.
```
[txt2mask]head and shoulders[/txt2mask]Walter White
```
</details>
</details>
<details><summary>Adding New Shortcodes</summary>
Shortcodes are loaded as Python modules from `unprompted/shortcodes`. You can make your own shortcodes by creating files there (preferably within the `/custom` subdirectory.)
The shortcode name is defined by the filename, e.g. `override.py` will give you the ability to use `[override]`. Shortcode filenames should be unique.
A shortcode is structured as follows:
```
class Shortcode():
"""A description of the shortcode goes here."""
def __init__(self,Unprompted):
self.Unprompted = Unprompted
def run_block(self, pargs, kwargs, context,content):
return("")
def cleanup(self):
return("")
```
The `__init__` function gives the shortcode access to our main Unprompted object, and it's where you should declare any unique variables for your shortcode.
The `run_block` function contains the main logic for your shortcode. It has access to these special variables (the following documentation was pulled from the [Python Shortcodes](https://www.dmulholl.com/dev/shortcodes.html) library, on which Unprompted depends):
- `pargs`: a list of the shortcode's positional arguments.
- `kwargs`: a dictionary of the shortcode's keyword arguments.
- `context`: an optional arbitrary context object supplied by the caller.
- `content`: the string within the shortcode tags, e.g. `[tag]content[/tag]`
Positional and keyword arguments are passed as strings. The function itself should return a string which will replace the shortcode in the parsed text.
The `cleanup` function runs at the end of the processing chain. You can free any unnecessary variables from memory here.
For more details, please examine the code of the stock shortcodes.
</details>
>>>>>>> Stashed changes

View File

@ -10,7 +10,7 @@ import sys
class Unprompted: class Unprompted:
def __init__(self, base_dir="."): def __init__(self, base_dir="."):
self.VERSION = "5.2.0" self.VERSION = "6.0.0"
print(f"(Unprompted v{self.VERSION} by Therefore Games)") print(f"(Unprompted v{self.VERSION} by Therefore Games)")
self.log("Initializing Unprompted object...",False,"SETUP") self.log("Initializing Unprompted object...",False,"SETUP")

View File

@ -9,6 +9,7 @@ import gradio as gr
import modules.scripts as scripts import modules.scripts as scripts
from modules.processing import process_images,fix_seed,Processed from modules.processing import process_images,fix_seed,Processed
from modules.shared import opts, cmd_opts, state, Options from modules.shared import opts, cmd_opts, state, Options
from modules import sd_models
import lib_unprompted.shortcodes as shortcodes import lib_unprompted.shortcodes as shortcodes
from pathlib import Path from pathlib import Path
from enum import IntEnum,auto from enum import IntEnum,auto
@ -105,7 +106,7 @@ def wizard_generate_shortcode(option,is_img2img,prepend="",append=""):
result += " " + str(gr_obj.value) result += " " + str(gr_obj.value)
elif (block_name=="checkbox"): elif (block_name=="checkbox"):
if gr_obj.value: result += " " + arg_name if gr_obj.value: result += " " + arg_name
elif (block_name=="number"): result += f" {arg_name}={int(gr_obj.value)}" elif (block_name=="number"): result += f" {arg_name}={Unprompted.autocast(gr_obj.value)}"
elif (block_name=="textbox"): elif (block_name=="textbox"):
if len(gr_obj.value) > 0: result += f" {arg_name}=\"{gr_obj.value}\"" if len(gr_obj.value) > 0: result += f" {arg_name}=\"{gr_obj.value}\""
else: result += f" {arg_name}=\"{gr_obj.value}\"" else: result += f" {arg_name}=\"{gr_obj.value}\""
@ -148,6 +149,9 @@ class Scripts(scripts.Script):
with gr.Accordion("Unprompted", open=Unprompted.Config.ui.open): with gr.Accordion("Unprompted", open=Unprompted.Config.ui.open):
is_enabled = gr.Checkbox(label="Enabled",value=gradio_enabled_checkbox_workaround) is_enabled = gr.Checkbox(label="Enabled",value=gradio_enabled_checkbox_workaround)
unprompted_seed = gr.Number(label="Unprompted Seed",value=-1)
setattr(unprompted_seed,"do_not_save_to_config",True)
if (os.path.exists(f"{base_dir}/{Unprompted.Config.template_directory}/pro/fantasy_card/main{Unprompted.Config.txt_format}")): is_open = False if (os.path.exists(f"{base_dir}/{Unprompted.Config.template_directory}/pro/fantasy_card/main{Unprompted.Config.txt_format}")): is_open = False
else: is_open = True else: is_open = True
@ -174,13 +178,16 @@ class Scripts(scripts.Script):
if (block_name == "textbox"): if (block_name == "textbox"):
if "_placeholder" in kwargs: this_placeholder = kwargs["_placeholder"] if "_placeholder" in kwargs: this_placeholder = kwargs["_placeholder"]
else: this_placeholder = str(content) else: this_placeholder = str(content)
gr.Textbox(label=this_label,max_lines=1,placeholder=this_placeholder) obj = gr.Textbox(label=this_label,max_lines=1,placeholder=this_placeholder)
elif (block_name == "checkbox"): gr.Checkbox(label=this_label,value=bool(content)) elif (block_name == "checkbox"):
elif (block_name == "number"): gr.Number(label=this_label,value=int(content),interactive=True) obj = gr.Checkbox(label=this_label,value=bool(int(content)))
elif (block_name == "dropdown"): gr.Dropdown(label=this_label,choices=kwargs["_choices"].split(self.Unprompted.Config.syntax.delimiter)) elif (block_name == "number"): obj = gr.Number(label=this_label,value=int(content),interactive=True)
elif (block_name == "radio"): gr.Radio(label=this_label,choices=kwargs["_choices"].split(self.Unprompted.Config.syntax_delimiter),interactive=True) elif (block_name == "dropdown"): obj = gr.Dropdown(label=this_label,choices=kwargs["_choices"].split(self.Unprompted.Config.syntax.delimiter))
elif (block_name == "radio"): obj = gr.Radio(label=this_label,choices=kwargs["_choices"].split(self.Unprompted.Config.syntax_delimiter),interactive=True)
elif (block_name == "slider"): elif (block_name == "slider"):
gr.Slider(label=this_label,value=int(content),minimum=kwargs["_minimum"],maximum=kwargs["_maximum"],step=kwargs["_step"]) obj = gr.Slider(label=this_label,value=int(content),minimum=kwargs["_minimum"],maximum=kwargs["_maximum"],step=kwargs["_step"])
setattr(obj,"do_not_save_to_config",True)
return("") return("")
wizard_shortcode_parser.register(handler,"set",f"{Unprompted.Config.syntax.tag_close}set") wizard_shortcode_parser.register(handler,"set",f"{Unprompted.Config.syntax.tag_close}set")
@ -311,11 +318,15 @@ class Scripts(scripts.Script):
guide = gr.Markdown(value=get_markdown("docs/GUIDE.md")) guide = gr.Markdown(value=get_markdown("docs/GUIDE.md"))
return [is_enabled] return [is_enabled,unprompted_seed]
def process(self, p, is_enabled): def process(self, p, is_enabled, unprompted_seed):
if not is_enabled: if not is_enabled:
return p return p
if unprompted_seed != -1:
import random
random.seed(unprompted_seed)
def apply_prompt_template(string,template): def apply_prompt_template(string,template):
return template.replace("*",string) return template.replace("*",string)
@ -348,7 +359,7 @@ class Scripts(scripts.Script):
# Set up system var support - copy relevant p attributes into shortcode var object # Set up system var support - copy relevant p attributes into shortcode var object
for att in dir(p): for att in dir(p):
if not att.startswith("__") and att != "sd_model": # Workaround for sd_model var, will look into adding proper support soon if not att.startswith("__") and att != "sd_model":
Unprompted.shortcode_user_vars[att] = getattr(p,att) Unprompted.shortcode_user_vars[att] = getattr(p,att)
Unprompted.shortcode_user_vars["prompt"] = Unprompted.process_string(apply_prompt_template(original_prompt,Unprompted.Config.templates.default)) Unprompted.shortcode_user_vars["prompt"] = Unprompted.process_string(apply_prompt_template(original_prompt,Unprompted.Config.templates.default))
@ -356,9 +367,16 @@ class Scripts(scripts.Script):
# Apply any updates to system vars # Apply any updates to system vars
for att in dir(p): for att in dir(p):
if not att.startswith("__") and att != "sd_model": # Workaround for sd_model var, will look into adding proper support soon if not att.startswith("__") and att != "sd_model":
setattr(p,att,Unprompted.shortcode_user_vars[att]) setattr(p,att,Unprompted.shortcode_user_vars[att])
# Support loading a new checkpoint by name
if "sd_model" in Unprompted.shortcode_user_vars:
info = sd_models.get_closet_checkpoint_match(Unprompted.shortcode_user_vars["sd_model"])
print(info)
if (info): sd_models.reload_model_weights(None,info)
if p.seed is not None and p.seed != -1.0: if p.seed is not None and p.seed != -1.0:
if (Unprompted.is_int(p.seed)): p.seed = int(p.seed) if (Unprompted.is_int(p.seed)): p.seed = int(p.seed)
p.all_seeds[0] = p.seed p.all_seeds[0] = p.seed
@ -392,7 +410,7 @@ class Scripts(scripts.Script):
Unprompted.shortcode_objects[i].cleanup() Unprompted.shortcode_objects[i].cleanup()
# After routines # After routines
def postprocess(self, p, processed, is_enabled): def postprocess(self, p, processed, is_enabled, unprompted_seed):
Unprompted.log("Entering After routine...") Unprompted.log("Entering After routine...")
for i in Unprompted.after_routines: for i in Unprompted.after_routines:
Unprompted.shortcode_objects[i].after(p,processed) Unprompted.shortcode_objects[i].after(p,processed)

View File

@ -0,0 +1,146 @@
from re import sub
from modules.processing import StableDiffusionProcessingImg2Img, Processed, process_images
from modules import images
from torchvision.transforms.functional import to_pil_image, pil_to_tensor
import torch
from modules.shared import opts, state
class Shortcode():
def __init__(self,Unprompted):
self.Unprompted = Unprompted
self.init_images = []
self.image_masks = []
self.processing = False
self.orginal_n_iter = None
self.description = "Allows to use multiple init_images or multiple masks"
def run_atomic(self, pargs, kwargs, context):
if self.processing:
return ""
had_init_image = False
if "init_images" in self.Unprompted.shortcode_user_vars:
self.init_images += self.Unprompted.shortcode_user_vars["init_images"]
had_init_image = True
if "image_masks" in self.Unprompted.shortcode_user_vars:
self.image_masks += [self.Unprompted.shortcode_user_vars["image_masks"]]
elif "image_mask" in self.Unprompted.shortcode_user_vars:
self.image_masks += [[self.Unprompted.shortcode_user_vars["image_mask"]]]
elif had_init_image:
# each init_image has at least an empty mask
self.image_masks += [[]]
if "n_iter" in self.Unprompted.shortcode_user_vars:
self.orginal_n_iter = self.Unprompted.shortcode_user_vars["n_iter"]
self.Unprompted.shortcode_user_vars["n_iter"] = 0
return ""
def after(self, p:StableDiffusionProcessingImg2Img, processed: Processed):
if not self.processing and self.orginal_n_iter is not None:
self.processing = True
try:
mask_count = sum([len(masks) for masks in self.image_masks])
if mask_count == 0:
state.job_count = self.orginal_n_iter
else:
if len(self.init_images) == 1:
state.job_count = mask_count * self.orginal_n_iter
else:
state.job_count = mask_count
batched_init_imgs = [self.init_images[idx:idx+p.batch_size] for idx in range(0, len(self.init_images), p.batch_size)]
batched_prompts = [p.all_prompts[idx:idx+p.batch_size] for idx in range(0, len(p.all_prompts), p.batch_size)]
batched_neg_prompts = [p.all_negative_prompts[idx:idx+p.batch_size] for idx in range(0, len(p.all_negative_prompts), p.batch_size)]
batched_masks = [self.image_masks[idx:idx+p.batch_size] for idx in range(0, len(self.image_masks), p.batch_size)]
batched_seeds = [p.all_seeds[idx:idx+p.batch_size] for idx in range(0, len(p.all_seeds), p.batch_size)]
create_grid = not p.do_not_save_grid
save_imgs = not p.do_not_save_samples
p.do_not_save_grid = True
p.do_not_save_samples = True
p.n_iter = 1
if len(self.init_images) == 1:
batched_init_imgs = [[self.init_images[0]] * p.batch_size] * self.orginal_n_iter
batched_masks = [[self.image_masks[0]] * p.batch_size] * self.orginal_n_iter
for init_imgs, prompts, neg_prompts, seeds, maskss in zip(batched_init_imgs, batched_prompts, batched_neg_prompts, batched_seeds, batched_masks):
if sum([len(masks) for masks in maskss]) == 0:
p.init_images = init_imgs
p.all_prompts = batched_prompts
p.all_negative_prompts = batched_neg_prompts
p.all_seeds = seeds
p.mask = None
sub_processed = process_images(p)
processed.images += sub_processed.images
else:
output_resolution = (init_imgs[0].width, init_imgs[0].height) if p.inpaint_full_res else (p.width, p.height)
if len(self.init_images) == 1:
imgs = torch.stack([pil_to_tensor(init_imgs[0].resize(output_resolution))] * p.batch_size).clone()
for idx, mask in enumerate(maskss[0]):
p.init_images = [to_pil_image(img) for img in imgs]
p.image_mask = mask
p.all_prompts = prompts
p.all_negative_prompts = neg_prompts
p.all_seeds = [seed + idx + 800 for seed in seeds]
sub_processed = process_images(p)
mask = mask.resize(output_resolution)
mask = pil_to_tensor(mask) > 0
mask = mask.broadcast_to(imgs.shape)
imgs[mask] = torch.stack([pil_to_tensor(img) for img in sub_processed.images[:len(imgs)]])[mask]
processed.images += [to_pil_image(img) for img in imgs]
else:
for init_img, prompt, neg_prompt, seed, masks in zip(init_imgs, prompts, neg_prompts, seeds, maskss):
img = pil_to_tensor(init_img.resize(output_resolution))
for idx, mask in enumerate(masks):
p.batch_size = 1
p.init_images = [to_pil_image(img)]
p.image_mask = mask
p.all_prompts = [prompt]
p.all_negative_prompts = [neg_prompt]
p.all_seeds = [seed + idx + 800]
sub_processed = process_images(p)
mask = mask.resize(output_resolution)
mask = pil_to_tensor(mask) > 0
mask = mask.broadcast_to(img.shape)
img[mask] = pil_to_tensor(sub_processed.images[0])[mask]
processed.images.append(to_pil_image(img))
if opts.samples_save and save_imgs:
for img, prompt, neg_prompt, seed in zip(processed.images, p.all_prompts, p.all_negative_prompts, p.all_seeds):
images.save_image(img, p.outpath_samples, "", seed, prompt, opts.samples_format)
if create_grid and len(processed.images) > 1:
grid = images.image_grid(processed.images, p.batch_size * len(batched_init_imgs))
if opts.return_grid:
processed.images.insert(0, grid)
processed.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, short_filename=not opts.grid_extended_filename, p=p, grid=True)
finally:
self.processing = False
self.init_images = []
self.image_masks = []
self.orginal_n_iter = None
def ui(self,gr):
pass

View File

@ -18,17 +18,18 @@ class Shortcode():
break break
img2img_result = modules.img2img.img2img( img2img_result = modules.img2img.img2img(
self.Unprompted.shortcode_user_vars["mode"] if "mode" in self.Unprompted.shortcode_user_vars else 0, #p.mode "unprompted_img2img",
self.Unprompted.shortcode_user_vars["img2img_mode"] if "img2img_mode" in self.Unprompted.shortcode_user_vars else 0, #p.mode
self.Unprompted.shortcode_user_vars["prompt"], self.Unprompted.shortcode_user_vars["prompt"],
self.Unprompted.shortcode_user_vars["negative_prompt"], self.Unprompted.shortcode_user_vars["negative_prompt"],
"None", #prompt_style1 "None", # prompt_styles
"None", #prompt_style2
self.Unprompted.shortcode_user_vars["init_images"][len(self.Unprompted.after_processed.images) - 1], self.Unprompted.shortcode_user_vars["init_images"][len(self.Unprompted.after_processed.images) - 1],
None, # sketch
None, # p.init_img_with_mask None, # p.init_img_with_mask
None, # p.init_img_with_mask_orig None, # inpaint_color_sketch
None, # inpaint_color_sketch_orig
self.Unprompted.shortcode_user_vars["init_images"][len(self.Unprompted.after_processed.images) - 1], # p.init_img_inpaint self.Unprompted.shortcode_user_vars["init_images"][len(self.Unprompted.after_processed.images) - 1], # p.init_img_inpaint
init_mask, # p.init_mask_inpaint init_mask, # p.init_mask_inpaint
self.Unprompted.shortcode_user_vars["mask_mode"],
self.Unprompted.shortcode_user_vars["steps"], self.Unprompted.shortcode_user_vars["steps"],
sampler_index, sampler_index,
self.Unprompted.shortcode_user_vars["mask_blur"] if "mask_blur" in self.Unprompted.shortcode_user_vars else 0, # p.mask_blur self.Unprompted.shortcode_user_vars["mask_blur"] if "mask_blur" in self.Unprompted.shortcode_user_vars else 0, # p.mask_blur

View File

@ -1,5 +1,8 @@
<<<<<<< Updated upstream
from torchvision.utils import draw_segmentation_masks from torchvision.utils import draw_segmentation_masks
from torchvision.transforms.functional import pil_to_tensor, to_pil_image from torchvision.transforms.functional import pil_to_tensor, to_pil_image
=======
>>>>>>> Stashed changes
class Shortcode(): class Shortcode():
def __init__(self,Unprompted): def __init__(self,Unprompted):
@ -10,7 +13,6 @@ class Shortcode():
def run_block(self, pargs, kwargs, context, content): def run_block(self, pargs, kwargs, context, content):
from lib_unprompted.stable_diffusion.clipseg.models.clipseg import CLIPDensePredT from lib_unprompted.stable_diffusion.clipseg.models.clipseg import CLIPDensePredT
from PIL import ImageChops, Image, ImageOps from PIL import ImageChops, Image, ImageOps
import os.path import os.path
import torch import torch
@ -99,7 +101,11 @@ class Shortcode():
def get_mask(): def get_mask():
# load model # load model
model = CLIPDensePredT(version='ViT-B/16', reduce_dim=64, complex_trans_conv=not self.legacy_weights) model = CLIPDensePredT(version='ViT-B/16', reduce_dim=64, complex_trans_conv=not self.legacy_weights)
<<<<<<< Updated upstream
model_dir = f"{self.Unprompted.base_dir}/lib/stable_diffusion/clipseg/weights" model_dir = f"{self.Unprompted.base_dir}/lib/stable_diffusion/clipseg/weights"
=======
model_dir = f"{self.Unprompted.base_dir}/lib_unprompted/stable_diffusion/clipseg/weights"
>>>>>>> Stashed changes
os.makedirs(model_dir, exist_ok=True) os.makedirs(model_dir, exist_ok=True)
d64_filename = "rd64-uni.pth" if self.legacy_weights else "rd64-uni-refined.pth" d64_filename = "rd64-uni.pth" if self.legacy_weights else "rd64-uni-refined.pth"
@ -161,7 +167,7 @@ class Shortcode():
# Set up processor parameters correctly # Set up processor parameters correctly
self.image_mask = get_mask().resize((self.Unprompted.shortcode_user_vars["init_images"][0].width,self.Unprompted.shortcode_user_vars["init_images"][0].height)) self.image_mask = get_mask().resize((self.Unprompted.shortcode_user_vars["init_images"][0].width,self.Unprompted.shortcode_user_vars["init_images"][0].height))
self.Unprompted.shortcode_user_vars["mode"] = 1 self.Unprompted.shortcode_user_vars["mode"] = 0
self.Unprompted.shortcode_user_vars["mask_mode"] = 1 self.Unprompted.shortcode_user_vars["mask_mode"] = 1
self.Unprompted.shortcode_user_vars["image_mask"] =self.image_mask self.Unprompted.shortcode_user_vars["image_mask"] =self.image_mask
self.Unprompted.shortcode_user_vars["mask_for_overlay"] = self.image_mask self.Unprompted.shortcode_user_vars["mask_for_overlay"] = self.image_mask
@ -172,6 +178,9 @@ class Shortcode():
return "" return ""
def after(self,p=None,processed=None): def after(self,p=None,processed=None):
from torchvision.utils import draw_segmentation_masks
from torchvision.transforms.functional import pil_to_tensor, to_pil_image
if self.image_mask and self.show: if self.image_mask and self.show:
processed.images.append(self.image_mask) processed.images.append(self.image_mask)
@ -192,4 +201,7 @@ class Shortcode():
gr.Number(label="Smoothing radius in pixels 🡢 smoothing",value=20,interactive=True) gr.Number(label="Smoothing radius in pixels 🡢 smoothing",value=20,interactive=True)
gr.Number(label="Smoothing radius in pixels 🡢 neg_smoothing",value=20,interactive=True) gr.Number(label="Smoothing radius in pixels 🡢 neg_smoothing",value=20,interactive=True)
gr.Textbox(label="Negative mask prompt 🡢 negative_mask",max_lines=1) gr.Textbox(label="Negative mask prompt 🡢 negative_mask",max_lines=1)
gr.Number(label="Negative mask precision of selected area 🡢 neg_precision",value=100,interactive=True)
gr.Number(label="Negative mask padding radius in pixels 🡢 neg_padding",value=0,interactive=True)
gr.Number(label="Negative mask smoothing radius in pixels 🡢 neg_smoothing",value=20,interactive=True)
gr.Textbox(label="Save the mask size to the following variable 🡢 size_var",max_lines=1) gr.Textbox(label="Save the mask size to the following variable 🡢 size_var",max_lines=1)

View File

@ -8,7 +8,7 @@ Value of my_var: [get my_var]
[##] [##]
Old method: Old method (should still work):
You can add or subtract from an existing variable with 'set'. You can add or subtract from an existing variable with 'set'.

View File

@ -2,7 +2,7 @@
# https://patreon.com/thereforegames # https://patreon.com/thereforegames
# https://github.com/ThereforeGames/unprompted # https://github.com/ThereforeGames/unprompted
from lib.shared import Unprompted from lib_unprompted.shared import Unprompted
# Main object # Main object
Unprompted = Unprompted() Unprompted = Unprompted()