mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
rebrand CLI from "dream" to "invoke"
- rename dream.py to invoke.py - create a compatibility script named dream.py that execs() invoke.py - redo documentation - change help message in args - this does **not** rename the libraries, which are still ldm.dream.util, etc
This commit is contained in:
parent
7a701506a4
commit
98fe044dee
@ -1,4 +1,4 @@
|
|||||||
name: Test Dream with Conda
|
name: Test Invoke with Conda
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
@ -9,7 +9,7 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
os: [ ubuntu-latest, macos-12 ]
|
os: [ ubuntu-latest, macos-12 ]
|
||||||
name: Test dream.py on ${{ matrix.os }} with conda
|
name: Test invoke.py on ${{ matrix.os }} with conda
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
steps:
|
steps:
|
||||||
- run: |
|
- run: |
|
||||||
@ -85,9 +85,9 @@ jobs:
|
|||||||
fi
|
fi
|
||||||
# Utterly hacky, but I don't know how else to do this
|
# Utterly hacky, but I don't know how else to do this
|
||||||
if [[ ${{ github.ref }} == 'refs/heads/master' ]]; then
|
if [[ ${{ github.ref }} == 'refs/heads/master' ]]; then
|
||||||
time ${{ steps.vars.outputs.PYTHON_BIN }} scripts/dream.py --from_file tests/preflight_prompts.txt
|
time ${{ steps.vars.outputs.PYTHON_BIN }} scripts/invoke.py --from_file tests/preflight_prompts.txt
|
||||||
elif [[ ${{ github.ref }} == 'refs/heads/development' ]]; then
|
elif [[ ${{ github.ref }} == 'refs/heads/development' ]]; then
|
||||||
time ${{ steps.vars.outputs.PYTHON_BIN }} scripts/dream.py --from_file tests/dev_prompts.txt
|
time ${{ steps.vars.outputs.PYTHON_BIN }} scripts/invoke.py --from_file tests/dev_prompts.txt
|
||||||
fi
|
fi
|
||||||
mkdir -p outputs/img-samples
|
mkdir -p outputs/img-samples
|
||||||
- name: Archive results
|
- name: Archive results
|
10
README.md
10
README.md
@ -24,7 +24,7 @@ _This repository was formally known as lstein/stable-diffusion_
|
|||||||
[CI checks on dev badge]: https://flat.badgen.net/github/checks/invoke-ai/InvokeAI/development?label=CI%20status%20on%20dev&cache=900&icon=github
|
[CI checks on dev badge]: https://flat.badgen.net/github/checks/invoke-ai/InvokeAI/development?label=CI%20status%20on%20dev&cache=900&icon=github
|
||||||
[CI checks on dev link]: https://github.com/invoke-ai/InvokeAI/actions?query=branch%3Adevelopment
|
[CI checks on dev link]: https://github.com/invoke-ai/InvokeAI/actions?query=branch%3Adevelopment
|
||||||
[CI checks on main badge]: https://flat.badgen.net/github/checks/invoke-ai/InvokeAI/main?label=CI%20status%20on%20main&cache=900&icon=github
|
[CI checks on main badge]: https://flat.badgen.net/github/checks/invoke-ai/InvokeAI/main?label=CI%20status%20on%20main&cache=900&icon=github
|
||||||
[CI checks on main link]: https://github.com/invoke-ai/InvokeAI/actions/workflows/test-dream-conda.yml
|
[CI checks on main link]: https://github.com/invoke-ai/InvokeAI/actions/workflows/test-invoke-conda.yml
|
||||||
[discord badge]: https://flat.badgen.net/discord/members/ZmtBAhwWhy?icon=discord
|
[discord badge]: https://flat.badgen.net/discord/members/ZmtBAhwWhy?icon=discord
|
||||||
[discord link]: https://discord.gg/ZmtBAhwWhy
|
[discord link]: https://discord.gg/ZmtBAhwWhy
|
||||||
[github forks badge]: https://flat.badgen.net/github/forks/invoke-ai/InvokeAI?icon=github
|
[github forks badge]: https://flat.badgen.net/github/forks/invoke-ai/InvokeAI?icon=github
|
||||||
@ -94,10 +94,10 @@ You wil need one of the following:
|
|||||||
|
|
||||||
Precision is auto configured based on the device. If however you encounter
|
Precision is auto configured based on the device. If however you encounter
|
||||||
errors like 'expected type Float but found Half' or 'not implemented for Half'
|
errors like 'expected type Float but found Half' or 'not implemented for Half'
|
||||||
you can try starting `dream.py` with the `--precision=float32` flag:
|
you can try starting `invoke.py` with the `--precision=float32` flag:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
(ldm) ~/stable-diffusion$ python scripts/dream.py --precision=float32
|
(ldm) ~/stable-diffusion$ python scripts/invoke.py --precision=float32
|
||||||
```
|
```
|
||||||
|
|
||||||
### Features
|
### Features
|
||||||
@ -130,7 +130,7 @@ you can try starting `dream.py` with the `--precision=float32` flag:
|
|||||||
|
|
||||||
- vNEXT (TODO 2022)
|
- vNEXT (TODO 2022)
|
||||||
|
|
||||||
- Deprecated `--full_precision` / `-F`. Simply omit it and `dream.py` will auto
|
- Deprecated `--full_precision` / `-F`. Simply omit it and `invoke.py` will auto
|
||||||
configure. To switch away from auto use the new flag like `--precision=float32`.
|
configure. To switch away from auto use the new flag like `--precision=float32`.
|
||||||
|
|
||||||
- v1.14 (11 September 2022)
|
- v1.14 (11 September 2022)
|
||||||
@ -156,7 +156,7 @@ you can try starting `dream.py` with the `--precision=float32` flag:
|
|||||||
- A new configuration file scheme that allows new models (including upcoming
|
- A new configuration file scheme that allows new models (including upcoming
|
||||||
stable-diffusion-v1.5) to be added without altering the code.
|
stable-diffusion-v1.5) to be added without altering the code.
|
||||||
([David Wager](https://github.com/maddavid12))
|
([David Wager](https://github.com/maddavid12))
|
||||||
- Can specify --grid on dream.py command line as the default.
|
- Can specify --grid on invoke.py command line as the default.
|
||||||
- Miscellaneous internal bug and stability fixes.
|
- Miscellaneous internal bug and stability fixes.
|
||||||
- Works on M1 Apple hardware.
|
- Works on M1 Apple hardware.
|
||||||
- Multiple bug fixes.
|
- Multiple bug fixes.
|
||||||
|
@ -5,9 +5,9 @@
|
|||||||
- Supports a Google Colab notebook for a standalone server running on Google hardware [Arturo Mendivil](https://github.com/artmen1516)
|
- Supports a Google Colab notebook for a standalone server running on Google hardware [Arturo Mendivil](https://github.com/artmen1516)
|
||||||
- WebUI supports GFPGAN/ESRGAN facial reconstruction and upscaling [Kevin Gibbons](https://github.com/bakkot)
|
- WebUI supports GFPGAN/ESRGAN facial reconstruction and upscaling [Kevin Gibbons](https://github.com/bakkot)
|
||||||
- WebUI supports incremental display of in-progress images during generation [Kevin Gibbons](https://github.com/bakkot)
|
- WebUI supports incremental display of in-progress images during generation [Kevin Gibbons](https://github.com/bakkot)
|
||||||
- Output directory can be specified on the dream> command line.
|
- Output directory can be specified on the invoke> command line.
|
||||||
- The grid was displaying duplicated images when not enough images to fill the final row [Muhammad Usama](https://github.com/SMUsamaShah)
|
- The grid was displaying duplicated images when not enough images to fill the final row [Muhammad Usama](https://github.com/SMUsamaShah)
|
||||||
- Can specify --grid on dream.py command line as the default.
|
- Can specify --grid on invoke.py command line as the default.
|
||||||
- Miscellaneous internal bug and stability fixes.
|
- Miscellaneous internal bug and stability fixes.
|
||||||
|
|
||||||
---
|
---
|
||||||
@ -16,13 +16,13 @@
|
|||||||
|
|
||||||
- Improved file handling, including ability to read prompts from standard input.
|
- Improved file handling, including ability to read prompts from standard input.
|
||||||
(kudos to [Yunsaki](https://github.com/yunsaki)
|
(kudos to [Yunsaki](https://github.com/yunsaki)
|
||||||
- The web server is now integrated with the dream.py script. Invoke by adding --web to
|
- The web server is now integrated with the invoke.py script. Invoke by adding --web to
|
||||||
the dream.py command arguments.
|
the invoke.py command arguments.
|
||||||
- Face restoration and upscaling via GFPGAN and Real-ESGAN are now automatically
|
- Face restoration and upscaling via GFPGAN and Real-ESGAN are now automatically
|
||||||
enabled if the GFPGAN directory is located as a sibling to Stable Diffusion.
|
enabled if the GFPGAN directory is located as a sibling to Stable Diffusion.
|
||||||
VRAM requirements are modestly reduced. Thanks to both [Blessedcoolant](https://github.com/blessedcoolant) and
|
VRAM requirements are modestly reduced. Thanks to both [Blessedcoolant](https://github.com/blessedcoolant) and
|
||||||
[Oceanswave](https://github.com/oceanswave) for their work on this.
|
[Oceanswave](https://github.com/oceanswave) for their work on this.
|
||||||
- You can now swap samplers on the dream> command line. [Blessedcoolant](https://github.com/blessedcoolant)
|
- You can now swap samplers on the invoke> command line. [Blessedcoolant](https://github.com/blessedcoolant)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@ -32,7 +32,7 @@
|
|||||||
- You now can specify a seed of -1 to use the previous image's seed, -2 to use the seed for the image generated before that, etc.
|
- You now can specify a seed of -1 to use the previous image's seed, -2 to use the seed for the image generated before that, etc.
|
||||||
Seed memory only extends back to the previous command, but will work on all images generated with the -n# switch.
|
Seed memory only extends back to the previous command, but will work on all images generated with the -n# switch.
|
||||||
- Variant generation support temporarily disabled pending more general solution.
|
- Variant generation support temporarily disabled pending more general solution.
|
||||||
- Created a feature branch named **yunsaki-morphing-dream** which adds experimental support for
|
- Created a feature branch named **yunsaki-morphing-invoke** which adds experimental support for
|
||||||
iteratively modifying the prompt and its parameters. Please see[ Pull Request #86](https://github.com/lstein/stable-diffusion/pull/86)
|
iteratively modifying the prompt and its parameters. Please see[ Pull Request #86](https://github.com/lstein/stable-diffusion/pull/86)
|
||||||
for a synopsis of how this works. Note that when this feature is eventually added to the main branch, it will may be modified
|
for a synopsis of how this works. Note that when this feature is eventually added to the main branch, it will may be modified
|
||||||
significantly.
|
significantly.
|
||||||
@ -57,7 +57,7 @@
|
|||||||
|
|
||||||
## v1.08 (24 August 2022)
|
## v1.08 (24 August 2022)
|
||||||
|
|
||||||
- Escape single quotes on the dream> command before trying to parse. This avoids
|
- Escape single quotes on the invoke> command before trying to parse. This avoids
|
||||||
parse errors.
|
parse errors.
|
||||||
- Removed instruction to get Python3.8 as first step in Windows install.
|
- Removed instruction to get Python3.8 as first step in Windows install.
|
||||||
Anaconda3 does it for you.
|
Anaconda3 does it for you.
|
||||||
@ -94,7 +94,7 @@
|
|||||||
be regenerated with the indicated key
|
be regenerated with the indicated key
|
||||||
|
|
||||||
- It should no longer be possible for one image to overwrite another
|
- It should no longer be possible for one image to overwrite another
|
||||||
- You can use the "cd" and "pwd" commands at the dream> prompt to set and retrieve
|
- You can use the "cd" and "pwd" commands at the invoke> prompt to set and retrieve
|
||||||
the path of the output directory.
|
the path of the output directory.
|
||||||
|
|
||||||
---
|
---
|
||||||
@ -128,7 +128,7 @@
|
|||||||
- added k_lms sampling.
|
- added k_lms sampling.
|
||||||
**Please run "conda env update" to load the k_lms dependencies!!**
|
**Please run "conda env update" to load the k_lms dependencies!!**
|
||||||
- use half precision arithmetic by default, resulting in faster execution and lower memory requirements
|
- use half precision arithmetic by default, resulting in faster execution and lower memory requirements
|
||||||
Pass argument --full_precision to dream.py to get slower but more accurate image generation
|
Pass argument --full_precision to invoke.py to get slower but more accurate image generation
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
@ -12,10 +12,10 @@ title: Changelog
|
|||||||
[Kevin Gibbons](https://github.com/bakkot)
|
[Kevin Gibbons](https://github.com/bakkot)
|
||||||
- WebUI supports incremental display of in-progress images during generation
|
- WebUI supports incremental display of in-progress images during generation
|
||||||
[Kevin Gibbons](https://github.com/bakkot)
|
[Kevin Gibbons](https://github.com/bakkot)
|
||||||
- Output directory can be specified on the dream> command line.
|
- Output directory can be specified on the invoke> command line.
|
||||||
- The grid was displaying duplicated images when not enough images to fill the
|
- The grid was displaying duplicated images when not enough images to fill the
|
||||||
final row [Muhammad Usama](https://github.com/SMUsamaShah)
|
final row [Muhammad Usama](https://github.com/SMUsamaShah)
|
||||||
- Can specify --grid on dream.py command line as the default.
|
- Can specify --grid on invoke.py command line as the default.
|
||||||
- Miscellaneous internal bug and stability fixes.
|
- Miscellaneous internal bug and stability fixes.
|
||||||
|
|
||||||
---
|
---
|
||||||
@ -24,14 +24,14 @@ title: Changelog
|
|||||||
|
|
||||||
- Improved file handling, including ability to read prompts from standard input.
|
- Improved file handling, including ability to read prompts from standard input.
|
||||||
(kudos to [Yunsaki](https://github.com/yunsaki)
|
(kudos to [Yunsaki](https://github.com/yunsaki)
|
||||||
- The web server is now integrated with the dream.py script. Invoke by adding
|
- The web server is now integrated with the invoke.py script. Invoke by adding
|
||||||
--web to the dream.py command arguments.
|
--web to the invoke.py command arguments.
|
||||||
- Face restoration and upscaling via GFPGAN and Real-ESGAN are now automatically
|
- Face restoration and upscaling via GFPGAN and Real-ESGAN are now automatically
|
||||||
enabled if the GFPGAN directory is located as a sibling to Stable Diffusion.
|
enabled if the GFPGAN directory is located as a sibling to Stable Diffusion.
|
||||||
VRAM requirements are modestly reduced. Thanks to both
|
VRAM requirements are modestly reduced. Thanks to both
|
||||||
[Blessedcoolant](https://github.com/blessedcoolant) and
|
[Blessedcoolant](https://github.com/blessedcoolant) and
|
||||||
[Oceanswave](https://github.com/oceanswave) for their work on this.
|
[Oceanswave](https://github.com/oceanswave) for their work on this.
|
||||||
- You can now swap samplers on the dream> command line.
|
- You can now swap samplers on the invoke> command line.
|
||||||
[Blessedcoolant](https://github.com/blessedcoolant)
|
[Blessedcoolant](https://github.com/blessedcoolant)
|
||||||
|
|
||||||
---
|
---
|
||||||
@ -45,7 +45,7 @@ title: Changelog
|
|||||||
back to the previous command, but will work on all images generated with the
|
back to the previous command, but will work on all images generated with the
|
||||||
-n# switch.
|
-n# switch.
|
||||||
- Variant generation support temporarily disabled pending more general solution.
|
- Variant generation support temporarily disabled pending more general solution.
|
||||||
- Created a feature branch named **yunsaki-morphing-dream** which adds
|
- Created a feature branch named **yunsaki-morphing-invoke** which adds
|
||||||
experimental support for iteratively modifying the prompt and its parameters.
|
experimental support for iteratively modifying the prompt and its parameters.
|
||||||
Please
|
Please
|
||||||
see[ Pull Request #86](https://github.com/lstein/stable-diffusion/pull/86) for
|
see[ Pull Request #86](https://github.com/lstein/stable-diffusion/pull/86) for
|
||||||
@ -75,7 +75,7 @@ title: Changelog
|
|||||||
|
|
||||||
## v1.08 <small>(24 August 2022)</small>
|
## v1.08 <small>(24 August 2022)</small>
|
||||||
|
|
||||||
- Escape single quotes on the dream> command before trying to parse. This avoids
|
- Escape single quotes on the invoke> command before trying to parse. This avoids
|
||||||
parse errors.
|
parse errors.
|
||||||
- Removed instruction to get Python3.8 as first step in Windows install.
|
- Removed instruction to get Python3.8 as first step in Windows install.
|
||||||
Anaconda3 does it for you.
|
Anaconda3 does it for you.
|
||||||
@ -112,7 +112,7 @@ title: Changelog
|
|||||||
can be regenerated with the indicated key
|
can be regenerated with the indicated key
|
||||||
|
|
||||||
- It should no longer be possible for one image to overwrite another
|
- It should no longer be possible for one image to overwrite another
|
||||||
- You can use the "cd" and "pwd" commands at the dream> prompt to set and
|
- You can use the "cd" and "pwd" commands at the invoke> prompt to set and
|
||||||
retrieve the path of the output directory.
|
retrieve the path of the output directory.
|
||||||
|
|
||||||
## v1.04 <small>(22 August 2022 - after the drop)</small>
|
## v1.04 <small>(22 August 2022 - after the drop)</small>
|
||||||
@ -139,5 +139,5 @@ title: Changelog
|
|||||||
- added k_lms sampling. **Please run "conda env update -f environment.yaml" to
|
- added k_lms sampling. **Please run "conda env update -f environment.yaml" to
|
||||||
load the k_lms dependencies!!**
|
load the k_lms dependencies!!**
|
||||||
- use half precision arithmetic by default, resulting in faster execution and
|
- use half precision arithmetic by default, resulting in faster execution and
|
||||||
lower memory requirements Pass argument --full_precision to dream.py to get
|
lower memory requirements Pass argument --full_precision to invoke.py to get
|
||||||
slower but more accurate image generation
|
slower but more accurate image generation
|
||||||
|
@ -8,8 +8,8 @@ hide:
|
|||||||
|
|
||||||
## **Interactive Command Line Interface**
|
## **Interactive Command Line Interface**
|
||||||
|
|
||||||
The `dream.py` script, located in `scripts/dream.py`, provides an interactive
|
The `invoke.py` script, located in `scripts/dream.py`, provides an interactive
|
||||||
interface to image generation similar to the "dream mothership" bot that Stable
|
interface to image generation similar to the "invoke mothership" bot that Stable
|
||||||
AI provided on its Discord server.
|
AI provided on its Discord server.
|
||||||
|
|
||||||
Unlike the `txt2img.py` and `img2img.py` scripts provided in the original
|
Unlike the `txt2img.py` and `img2img.py` scripts provided in the original
|
||||||
@ -34,21 +34,21 @@ The script is confirmed to work on Linux, Windows and Mac systems.
|
|||||||
currently rudimentary, but a much better replacement is on its way.
|
currently rudimentary, but a much better replacement is on its way.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
(ldm) ~/stable-diffusion$ python3 ./scripts/dream.py
|
(ldm) ~/stable-diffusion$ python3 ./scripts/invoke.py
|
||||||
* Initializing, be patient...
|
* Initializing, be patient...
|
||||||
Loading model from models/ldm/text2img-large/model.ckpt
|
Loading model from models/ldm/text2img-large/model.ckpt
|
||||||
(...more initialization messages...)
|
(...more initialization messages...)
|
||||||
|
|
||||||
* Initialization done! Awaiting your command...
|
* Initialization done! Awaiting your command...
|
||||||
dream> ashley judd riding a camel -n2 -s150
|
invoke> ashley judd riding a camel -n2 -s150
|
||||||
Outputs:
|
Outputs:
|
||||||
outputs/img-samples/00009.png: "ashley judd riding a camel" -n2 -s150 -S 416354203
|
outputs/img-samples/00009.png: "ashley judd riding a camel" -n2 -s150 -S 416354203
|
||||||
outputs/img-samples/00010.png: "ashley judd riding a camel" -n2 -s150 -S 1362479620
|
outputs/img-samples/00010.png: "ashley judd riding a camel" -n2 -s150 -S 1362479620
|
||||||
|
|
||||||
dream> "there's a fly in my soup" -n6 -g
|
invoke> "there's a fly in my soup" -n6 -g
|
||||||
outputs/img-samples/00011.png: "there's a fly in my soup" -n6 -g -S 2685670268
|
outputs/img-samples/00011.png: "there's a fly in my soup" -n6 -g -S 2685670268
|
||||||
seeds for individual rows: [2685670268, 1216708065, 2335773498, 822223658, 714542046, 3395302430]
|
seeds for individual rows: [2685670268, 1216708065, 2335773498, 822223658, 714542046, 3395302430]
|
||||||
dream> q
|
invoke> q
|
||||||
|
|
||||||
# this shows how to retrieve the prompt stored in the saved image's metadata
|
# this shows how to retrieve the prompt stored in the saved image's metadata
|
||||||
(ldm) ~/stable-diffusion$ python ./scripts/images2prompt.py outputs/img_samples/*.png
|
(ldm) ~/stable-diffusion$ python ./scripts/images2prompt.py outputs/img_samples/*.png
|
||||||
@ -57,10 +57,10 @@ dream> q
|
|||||||
00011.png: "there's a fly in my soup" -n6 -g -S 2685670268
|
00011.png: "there's a fly in my soup" -n6 -g -S 2685670268
|
||||||
```
|
```
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
The `dream>` prompt's arguments are pretty much identical to those used in the
|
The `invoke>` prompt's arguments are pretty much identical to those used in the
|
||||||
Discord bot, except you don't need to type "!dream" (it doesn't hurt if you do).
|
Discord bot, except you don't need to type "!invoke" (it doesn't hurt if you do).
|
||||||
A significant change is that creation of individual images is now the default
|
A significant change is that creation of individual images is now the default
|
||||||
unless `--grid` (`-g`) is given. A full list is given in
|
unless `--grid` (`-g`) is given. A full list is given in
|
||||||
[List of prompt arguments](#list-of-prompt-arguments).
|
[List of prompt arguments](#list-of-prompt-arguments).
|
||||||
@ -73,7 +73,7 @@ the location of the model weight files.
|
|||||||
|
|
||||||
### List of arguments recognized at the command line
|
### List of arguments recognized at the command line
|
||||||
|
|
||||||
These command-line arguments can be passed to `dream.py` when you first run it
|
These command-line arguments can be passed to `invoke.py` when you first run it
|
||||||
from the Windows, Mac or Linux command line. Some set defaults that can be
|
from the Windows, Mac or Linux command line. Some set defaults that can be
|
||||||
overridden on a per-prompt basis (see [List of prompt arguments]
|
overridden on a per-prompt basis (see [List of prompt arguments]
|
||||||
(#list-of-prompt-arguments). Others
|
(#list-of-prompt-arguments). Others
|
||||||
@ -112,15 +112,15 @@ These arguments are deprecated but still work:
|
|||||||
| --laion400m | -l | False | Use older LAION400m weights; use `--model=laion400m` instead |
|
| --laion400m | -l | False | Use older LAION400m weights; use `--model=laion400m` instead |
|
||||||
|
|
||||||
**A note on path names:** On Windows systems, you may run into
|
**A note on path names:** On Windows systems, you may run into
|
||||||
problems when passing the dream script standard backslashed path
|
problems when passing the invoke script standard backslashed path
|
||||||
names because the Python interpreter treats "\" as an escape.
|
names because the Python interpreter treats "\" as an escape.
|
||||||
You can either double your slashes (ick): C:\\\\path\\\\to\\\\my\\\\file, or
|
You can either double your slashes (ick): C:\\\\path\\\\to\\\\my\\\\file, or
|
||||||
use Linux/Mac style forward slashes (better): C:/path/to/my/file.
|
use Linux/Mac style forward slashes (better): C:/path/to/my/file.
|
||||||
|
|
||||||
## List of prompt arguments
|
## List of prompt arguments
|
||||||
|
|
||||||
After the dream.py script initializes, it will present you with a
|
After the invoke.py script initializes, it will present you with a
|
||||||
**dream>** prompt. Here you can enter information to generate images
|
**invoke>** prompt. Here you can enter information to generate images
|
||||||
from text (txt2img), to embellish an existing image or sketch
|
from text (txt2img), to embellish an existing image or sketch
|
||||||
(img2img), or to selectively alter chosen regions of the image
|
(img2img), or to selectively alter chosen regions of the image
|
||||||
(inpainting).
|
(inpainting).
|
||||||
@ -128,13 +128,13 @@ from text (txt2img), to embellish an existing image or sketch
|
|||||||
### This is an example of txt2img:
|
### This is an example of txt2img:
|
||||||
|
|
||||||
~~~~
|
~~~~
|
||||||
dream> waterfall and rainbow -W640 -H480
|
invoke> waterfall and rainbow -W640 -H480
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
This will create the requested image with the dimensions 640 (width)
|
This will create the requested image with the dimensions 640 (width)
|
||||||
and 480 (height).
|
and 480 (height).
|
||||||
|
|
||||||
Here are the dream> command that apply to txt2img:
|
Here are the invoke> command that apply to txt2img:
|
||||||
|
|
||||||
| Argument | Shortcut | Default | Description |
|
| Argument | Shortcut | Default | Description |
|
||||||
|--------------------|------------|---------------------|--------------|
|
|--------------------|------------|---------------------|--------------|
|
||||||
@ -167,7 +167,7 @@ the nearest multiple of 64.
|
|||||||
### This is an example of img2img:
|
### This is an example of img2img:
|
||||||
|
|
||||||
~~~~
|
~~~~
|
||||||
dream> waterfall and rainbow -I./vacation-photo.png -W640 -H480 --fit
|
invoke> waterfall and rainbow -I./vacation-photo.png -W640 -H480 --fit
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
This will modify the indicated vacation photograph by making it more
|
This will modify the indicated vacation photograph by making it more
|
||||||
@ -188,7 +188,7 @@ accepts additional options:
|
|||||||
### This is an example of inpainting:
|
### This is an example of inpainting:
|
||||||
|
|
||||||
~~~~
|
~~~~
|
||||||
dream> waterfall and rainbow -I./vacation-photo.png -M./vacation-mask.png -W640 -H480 --fit
|
invoke> waterfall and rainbow -I./vacation-photo.png -M./vacation-mask.png -W640 -H480 --fit
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
This will do the same thing as img2img, but image alterations will
|
This will do the same thing as img2img, but image alterations will
|
||||||
@ -224,20 +224,20 @@ Some examples:
|
|||||||
|
|
||||||
Upscale to 4X its original size and fix faces using codeformer:
|
Upscale to 4X its original size and fix faces using codeformer:
|
||||||
~~~
|
~~~
|
||||||
dream> !fix 0000045.4829112.png -G1 -U4 -ft codeformer
|
invoke> !fix 0000045.4829112.png -G1 -U4 -ft codeformer
|
||||||
~~~
|
~~~
|
||||||
|
|
||||||
Use the GFPGAN algorithm to fix faces, then upscale to 3X using --embiggen:
|
Use the GFPGAN algorithm to fix faces, then upscale to 3X using --embiggen:
|
||||||
|
|
||||||
~~~
|
~~~
|
||||||
dream> !fix 0000045.4829112.png -G0.8 -ft gfpgan
|
invoke> !fix 0000045.4829112.png -G0.8 -ft gfpgan
|
||||||
>> fixing outputs/img-samples/0000045.4829112.png
|
>> fixing outputs/img-samples/0000045.4829112.png
|
||||||
>> retrieved seed 4829112 and prompt "boy enjoying a banana split"
|
>> retrieved seed 4829112 and prompt "boy enjoying a banana split"
|
||||||
>> GFPGAN - Restoring Faces for image seed:4829112
|
>> GFPGAN - Restoring Faces for image seed:4829112
|
||||||
Outputs:
|
Outputs:
|
||||||
[1] outputs/img-samples/000017.4829112.gfpgan-00.png: !fix "outputs/img-samples/0000045.4829112.png" -s 50 -S -W 512 -H 512 -C 7.5 -A k_lms -G 0.8
|
[1] outputs/img-samples/000017.4829112.gfpgan-00.png: !fix "outputs/img-samples/0000045.4829112.png" -s 50 -S -W 512 -H 512 -C 7.5 -A k_lms -G 0.8
|
||||||
|
|
||||||
dream> !fix 000017.4829112.gfpgan-00.png --embiggen 3
|
invoke> !fix 000017.4829112.gfpgan-00.png --embiggen 3
|
||||||
...lots of text...
|
...lots of text...
|
||||||
Outputs:
|
Outputs:
|
||||||
[2] outputs/img-samples/000018.2273800735.embiggen-00.png: !fix "outputs/img-samples/000017.243781548.gfpgan-00.png" -s 50 -S 2273800735 -W 512 -H 512 -C 7.5 -A k_lms --embiggen 3.0 0.75 0.25
|
[2] outputs/img-samples/000018.2273800735.embiggen-00.png: !fix "outputs/img-samples/000017.243781548.gfpgan-00.png" -s 50 -S 2273800735 -W 512 -H 512 -C 7.5 -A k_lms --embiggen 3.0 0.75 0.25
|
||||||
@ -251,9 +251,9 @@ provide either the name of a file in the current output directory, or
|
|||||||
a full file path.
|
a full file path.
|
||||||
|
|
||||||
~~~
|
~~~
|
||||||
dream> !fetch 0000015.8929913.png
|
invoke> !fetch 0000015.8929913.png
|
||||||
# the script returns the next line, ready for editing and running:
|
# the script returns the next line, ready for editing and running:
|
||||||
dream> a fantastic alien landscape -W 576 -H 512 -s 60 -A plms -C 7.5
|
invoke> a fantastic alien landscape -W 576 -H 512 -s 60 -A plms -C 7.5
|
||||||
~~~
|
~~~
|
||||||
|
|
||||||
Note that this command may behave unexpectedly if given a PNG file that
|
Note that this command may behave unexpectedly if given a PNG file that
|
||||||
@ -261,7 +261,7 @@ was not generated by InvokeAI.
|
|||||||
|
|
||||||
## !history
|
## !history
|
||||||
|
|
||||||
The dream script keeps track of all the commands you issue during a
|
The invoke script keeps track of all the commands you issue during a
|
||||||
session, allowing you to re-run them. On Mac and Linux systems, it
|
session, allowing you to re-run them. On Mac and Linux systems, it
|
||||||
also writes the command-line history out to disk, giving you access to
|
also writes the command-line history out to disk, giving you access to
|
||||||
the most recent 1000 commands issued.
|
the most recent 1000 commands issued.
|
||||||
@ -272,7 +272,7 @@ issued during the session (Windows), or the most recent 1000 commands
|
|||||||
where "NNN" is the history line number. For example:
|
where "NNN" is the history line number. For example:
|
||||||
|
|
||||||
~~~
|
~~~
|
||||||
dream> !history
|
invoke> !history
|
||||||
...
|
...
|
||||||
[14] happy woman sitting under tree wearing broad hat and flowing garment
|
[14] happy woman sitting under tree wearing broad hat and flowing garment
|
||||||
[15] beautiful woman sitting under tree wearing broad hat and flowing garment
|
[15] beautiful woman sitting under tree wearing broad hat and flowing garment
|
||||||
@ -280,8 +280,8 @@ dream> !history
|
|||||||
[20] watercolor of beautiful woman sitting under tree wearing broad hat and flowing garment -v0.2 -n6 -S2878767194
|
[20] watercolor of beautiful woman sitting under tree wearing broad hat and flowing garment -v0.2 -n6 -S2878767194
|
||||||
[21] surrealist painting of beautiful woman sitting under tree wearing broad hat and flowing garment -v0.2 -n6 -S2878767194
|
[21] surrealist painting of beautiful woman sitting under tree wearing broad hat and flowing garment -v0.2 -n6 -S2878767194
|
||||||
...
|
...
|
||||||
dream> !20
|
invoke> !20
|
||||||
dream> watercolor of beautiful woman sitting under tree wearing broad hat and flowing garment -v0.2 -n6 -S2878767194
|
invoke> watercolor of beautiful woman sitting under tree wearing broad hat and flowing garment -v0.2 -n6 -S2878767194
|
||||||
~~~
|
~~~
|
||||||
|
|
||||||
## !search <search string>
|
## !search <search string>
|
||||||
@ -290,7 +290,7 @@ This is similar to !history but it only returns lines that contain
|
|||||||
`search string`. For example:
|
`search string`. For example:
|
||||||
|
|
||||||
~~~
|
~~~
|
||||||
dream> !search surreal
|
invoke> !search surreal
|
||||||
[21] surrealist painting of beautiful woman sitting under tree wearing broad hat and flowing garment -v0.2 -n6 -S2878767194
|
[21] surrealist painting of beautiful woman sitting under tree wearing broad hat and flowing garment -v0.2 -n6 -S2878767194
|
||||||
~~~
|
~~~
|
||||||
|
|
||||||
@ -312,16 +312,16 @@ command completion.
|
|||||||
- To paste a cut section back in, position the cursor where you want to paste, and type CTRL-Y
|
- To paste a cut section back in, position the cursor where you want to paste, and type CTRL-Y
|
||||||
|
|
||||||
Windows users can get similar, but more limited, functionality if they
|
Windows users can get similar, but more limited, functionality if they
|
||||||
launch dream.py with the "winpty" program and have the `pyreadline3`
|
launch invoke.py with the "winpty" program and have the `pyreadline3`
|
||||||
library installed:
|
library installed:
|
||||||
|
|
||||||
~~~
|
~~~
|
||||||
> winpty python scripts\dream.py
|
> winpty python scripts\invoke.py
|
||||||
~~~
|
~~~
|
||||||
|
|
||||||
On the Mac and Linux platforms, when you exit dream.py, the last 1000
|
On the Mac and Linux platforms, when you exit invoke.py, the last 1000
|
||||||
lines of your command-line history will be saved. When you restart
|
lines of your command-line history will be saved. When you restart
|
||||||
dream.py, you can access the saved history using the up-arrow key.
|
invoke.py, you can access the saved history using the up-arrow key.
|
||||||
|
|
||||||
In addition, limited command-line completion is installed. In various
|
In addition, limited command-line completion is installed. In various
|
||||||
contexts, you can start typing your command and press tab. A list of
|
contexts, you can start typing your command and press tab. A list of
|
||||||
@ -334,7 +334,7 @@ will attempt to complete pathnames for you. This is most handy for the
|
|||||||
the path with a slash ("/") or "./". For example:
|
the path with a slash ("/") or "./". For example:
|
||||||
|
|
||||||
~~~
|
~~~
|
||||||
dream> zebra with a mustache -I./test-pictures<TAB>
|
invoke> zebra with a mustache -I./test-pictures<TAB>
|
||||||
-I./test-pictures/Lincoln-and-Parrot.png -I./test-pictures/zebra.jpg -I./test-pictures/madonna.png
|
-I./test-pictures/Lincoln-and-Parrot.png -I./test-pictures/zebra.jpg -I./test-pictures/madonna.png
|
||||||
-I./test-pictures/bad-sketch.png -I./test-pictures/man_with_eagle/
|
-I./test-pictures/bad-sketch.png -I./test-pictures/man_with_eagle/
|
||||||
```
|
```
|
||||||
|
@ -106,8 +106,8 @@ Running Embiggen with 512x512 tiles on an existing image, scaling up by a factor
|
|||||||
and doing the same again (default ESRGAN strength is 0.75, default overlap between tiles is 0.25):
|
and doing the same again (default ESRGAN strength is 0.75, default overlap between tiles is 0.25):
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
dream > a photo of a forest at sunset -s 100 -W 512 -H 512 -I outputs/forest.png -f 0.4 -embiggen 2.5
|
invoke > a photo of a forest at sunset -s 100 -W 512 -H 512 -I outputs/forest.png -f 0.4 -embiggen 2.5
|
||||||
dream > a photo of a forest at sunset -s 100 -W 512 -H 512 -I outputs/forest.png -f 0.4 -embiggen 2.5 0.75 0.25
|
invoke > a photo of a forest at sunset -s 100 -W 512 -H 512 -I outputs/forest.png -f 0.4 -embiggen 2.5 0.75 0.25
|
||||||
```
|
```
|
||||||
|
|
||||||
If your starting image was also 512x512 this should have taken 9 tiles.
|
If your starting image was also 512x512 this should have taken 9 tiles.
|
||||||
@ -118,7 +118,7 @@ If there weren't enough clouds in the sky of that forest you just made
|
|||||||
tiles:
|
tiles:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
dream> a photo of puffy clouds over a forest at sunset -s 100 -W 512 -H 512 -I outputs/000002.seed.png -f 0.5 -embiggen_tiles 1 2 3
|
invoke> a photo of puffy clouds over a forest at sunset -s 100 -W 512 -H 512 -I outputs/000002.seed.png -f 0.5 -embiggen_tiles 1 2 3
|
||||||
```
|
```
|
||||||
|
|
||||||
## Fixing Previously-Generated Images
|
## Fixing Previously-Generated Images
|
||||||
@ -129,7 +129,7 @@ syntax `!fix path/to/file.png <embiggen>`. For example, you can rewrite the
|
|||||||
previous command to look like this:
|
previous command to look like this:
|
||||||
|
|
||||||
~~~~
|
~~~~
|
||||||
dream> !fix ./outputs/000002.seed.png -embiggen_tiles 1 2 3
|
invoke> !fix ./outputs/000002.seed.png -embiggen_tiles 1 2 3
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
A new file named `000002.seed.fixed.png` will be created in the output directory. Note that
|
A new file named `000002.seed.fixed.png` will be created in the output directory. Note that
|
||||||
|
@ -67,7 +67,7 @@ gaussian noise and progressively refines it over the requested number of steps,
|
|||||||
**Let's start** by thinking about vanilla `prompt2img`, just generating an image from a prompt. If the step count is 10, then the "latent space" (Stable Diffusion's internal representation of the image) for the prompt "fire" with seed `1592514025` develops something like this:
|
**Let's start** by thinking about vanilla `prompt2img`, just generating an image from a prompt. If the step count is 10, then the "latent space" (Stable Diffusion's internal representation of the image) for the prompt "fire" with seed `1592514025` develops something like this:
|
||||||
|
|
||||||
```commandline
|
```commandline
|
||||||
dream> "fire" -s10 -W384 -H384 -S1592514025
|
invoke> "fire" -s10 -W384 -H384 -S1592514025
|
||||||
```
|
```
|
||||||
|
|
||||||

|

|
||||||
@ -95,7 +95,7 @@ Notice how much more fuzzy the starting image is for strength `0.7` compared to
|
|||||||
| | strength = 0.7 | strength = 0.4 |
|
| | strength = 0.7 | strength = 0.4 |
|
||||||
| -- | -- | -- |
|
| -- | -- | -- |
|
||||||
| initial image that SD sees |  |  |
|
| initial image that SD sees |  |  |
|
||||||
| steps argument to `dream>` | `-S10` | `-S10` |
|
| steps argument to `invoke>` | `-S10` | `-S10` |
|
||||||
| steps actually taken | 7 | 4 |
|
| steps actually taken | 7 | 4 |
|
||||||
| latent space at each step |  |  |
|
| latent space at each step |  |  |
|
||||||
| output |  |  |
|
| output |  |  |
|
||||||
@ -106,10 +106,10 @@ Both of the outputs look kind of like what I was thinking of. With the strength
|
|||||||
If you want to try this out yourself, all of these are using a seed of `1592514025` with a width/height of `384`, step count `10`, the default sampler (`k_lms`), and the single-word prompt `fire`:
|
If you want to try this out yourself, all of these are using a seed of `1592514025` with a width/height of `384`, step count `10`, the default sampler (`k_lms`), and the single-word prompt `fire`:
|
||||||
|
|
||||||
```commandline
|
```commandline
|
||||||
dream> "fire" -s10 -W384 -H384 -S1592514025 -I /tmp/fire-drawing.png --strength 0.7
|
invoke> "fire" -s10 -W384 -H384 -S1592514025 -I /tmp/fire-drawing.png --strength 0.7
|
||||||
```
|
```
|
||||||
|
|
||||||
The code for rendering intermediates is on my (damian0815's) branch [document-img2img](https://github.com/damian0815/InvokeAI/tree/document-img2img) - run `dream.py` and check your `outputs/img-samples/intermediates` folder while generating an image.
|
The code for rendering intermediates is on my (damian0815's) branch [document-img2img](https://github.com/damian0815/InvokeAI/tree/document-img2img) - run `invoke.py` and check your `outputs/img-samples/intermediates` folder while generating an image.
|
||||||
|
|
||||||
### Compensating for the reduced step count
|
### Compensating for the reduced step count
|
||||||
|
|
||||||
@ -118,7 +118,7 @@ After putting this guide together I was curious to see how the difference would
|
|||||||
Here's strength `0.4` (note step count `50`, which is `20 ÷ 0.4` to make sure SD does `20` steps from my image):
|
Here's strength `0.4` (note step count `50`, which is `20 ÷ 0.4` to make sure SD does `20` steps from my image):
|
||||||
|
|
||||||
```commandline
|
```commandline
|
||||||
dream> "fire" -s50 -W384 -H384 -S1592514025 -I /tmp/fire-drawing.png -f 0.4
|
invoke> "fire" -s50 -W384 -H384 -S1592514025 -I /tmp/fire-drawing.png -f 0.4
|
||||||
```
|
```
|
||||||
|
|
||||||

|

|
||||||
@ -126,7 +126,7 @@ dream> "fire" -s50 -W384 -H384 -S1592514025 -I /tmp/fire-drawing.png -f 0.4
|
|||||||
and strength `0.7` (note step count `30`, which is roughly `20 ÷ 0.7` to make sure SD does `20` steps from my image):
|
and strength `0.7` (note step count `30`, which is roughly `20 ÷ 0.7` to make sure SD does `20` steps from my image):
|
||||||
|
|
||||||
```commandline
|
```commandline
|
||||||
dream> "fire" -s30 -W384 -H384 -S1592514025 -I /tmp/fire-drawing.png -f 0.7
|
invoke> "fire" -s30 -W384 -H384 -S1592514025 -I /tmp/fire-drawing.png -f 0.7
|
||||||
```
|
```
|
||||||
|
|
||||||

|

|
||||||
|
@ -8,7 +8,7 @@ title: Inpainting
|
|||||||
|
|
||||||
Inpainting is really cool. To do it, you start with an initial image and use a photoeditor to make
|
Inpainting is really cool. To do it, you start with an initial image and use a photoeditor to make
|
||||||
one or more regions transparent (i.e. they have a "hole" in them). You then provide the path to this
|
one or more regions transparent (i.e. they have a "hole" in them). You then provide the path to this
|
||||||
image at the dream> command line using the `-I` switch. Stable Diffusion will only paint within the
|
image at the invoke> command line using the `-I` switch. Stable Diffusion will only paint within the
|
||||||
transparent region.
|
transparent region.
|
||||||
|
|
||||||
There's a catch. In the current implementation, you have to prepare the initial image correctly so
|
There's a catch. In the current implementation, you have to prepare the initial image correctly so
|
||||||
@ -17,13 +17,13 @@ applications will by default erase the color information under the transparent p
|
|||||||
them with white or black, which will lead to suboptimal inpainting. You also must take care to
|
them with white or black, which will lead to suboptimal inpainting. You also must take care to
|
||||||
export the PNG file in such a way that the color information is preserved.
|
export the PNG file in such a way that the color information is preserved.
|
||||||
|
|
||||||
If your photoeditor is erasing the underlying color information, `dream.py` will give you a big fat
|
If your photoeditor is erasing the underlying color information, `invoke.py` will give you a big fat
|
||||||
warning. If you can't find a way to coax your photoeditor to retain color values under transparent
|
warning. If you can't find a way to coax your photoeditor to retain color values under transparent
|
||||||
areas, then you can combine the `-I` and `-M` switches to provide both the original unedited image
|
areas, then you can combine the `-I` and `-M` switches to provide both the original unedited image
|
||||||
and the masked (partially transparent) image:
|
and the masked (partially transparent) image:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
dream> "man with cat on shoulder" -I./images/man.png -M./images/man-transparent.png
|
invoke> "man with cat on shoulder" -I./images/man.png -M./images/man-transparent.png
|
||||||
```
|
```
|
||||||
|
|
||||||
We are hoping to get rid of the need for this workaround in an upcoming release.
|
We are hoping to get rid of the need for this workaround in an upcoming release.
|
||||||
@ -69,7 +69,7 @@ We are hoping to get rid of the need for this workaround in an upcoming release.
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
7. After following the inpainting instructions above (either through the CLI or the Web UI), marvel at your newfound ability to selectively dream. Lookin' good!
|
7. After following the inpainting instructions above (either through the CLI or the Web UI), marvel at your newfound ability to selectively invoke. Lookin' good!
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
@ -22,10 +22,10 @@ Output Example: 
|
|||||||
|
|
||||||
The seamless tiling mode causes generated images to seamlessly tile with itself. To use it, add the
|
The seamless tiling mode causes generated images to seamlessly tile with itself. To use it, add the
|
||||||
`--seamless` option when starting the script which will result in all generated images to tile, or
|
`--seamless` option when starting the script which will result in all generated images to tile, or
|
||||||
for each `dream>` prompt as shown here:
|
for each `invoke>` prompt as shown here:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
dream> "pond garden with lotus by claude monet" --seamless -s100 -n4
|
invoke> "pond garden with lotus by claude monet" --seamless -s100 -n4
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
@ -42,12 +42,12 @@ Here's an example of using this to do a quick refinement. It also illustrates us
|
|||||||
switch to turn on upscaling and face enhancement (see previous section):
|
switch to turn on upscaling and face enhancement (see previous section):
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
dream> a cute child playing hopscotch -G0.5
|
invoke> a cute child playing hopscotch -G0.5
|
||||||
[...]
|
[...]
|
||||||
outputs/img-samples/000039.3498014304.png: "a cute child playing hopscotch" -s50 -W512 -H512 -C7.5 -mk_lms -S3498014304
|
outputs/img-samples/000039.3498014304.png: "a cute child playing hopscotch" -s50 -W512 -H512 -C7.5 -mk_lms -S3498014304
|
||||||
|
|
||||||
# I wonder what it will look like if I bump up the steps and set facial enhancement to full strength?
|
# I wonder what it will look like if I bump up the steps and set facial enhancement to full strength?
|
||||||
dream> a cute child playing hopscotch -G1.0 -s100 -S -1
|
invoke> a cute child playing hopscotch -G1.0 -s100 -S -1
|
||||||
reusing previous seed 3498014304
|
reusing previous seed 3498014304
|
||||||
[...]
|
[...]
|
||||||
outputs/img-samples/000040.3498014304.png: "a cute child playing hopscotch" -G1.0 -s100 -W512 -H512 -C7.5 -mk_lms -S3498014304
|
outputs/img-samples/000040.3498014304.png: "a cute child playing hopscotch" -G1.0 -s100 -W512 -H512 -C7.5 -mk_lms -S3498014304
|
||||||
|
@ -31,7 +31,7 @@ Pretty nice, but it's annoying that the top of her head is cut
|
|||||||
off. She's also a bit off center. Let's fix that!
|
off. She's also a bit off center. Let's fix that!
|
||||||
|
|
||||||
~~~~
|
~~~~
|
||||||
dream> !fix images/curly.png --outcrop top 64 right 64
|
invoke> !fix images/curly.png --outcrop top 64 right 64
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
This is saying to apply the `outcrop` extension by extending the top
|
This is saying to apply the `outcrop` extension by extending the top
|
||||||
@ -67,7 +67,7 @@ differences. Starting with the same image, here is how we would add an
|
|||||||
additional 64 pixels to the top of the image:
|
additional 64 pixels to the top of the image:
|
||||||
|
|
||||||
~~~
|
~~~
|
||||||
dream> !fix images/curly.png --out_direction top 64
|
invoke> !fix images/curly.png --out_direction top 64
|
||||||
~~~
|
~~~
|
||||||
|
|
||||||
(you can abbreviate ``--out_direction` as `-D`.
|
(you can abbreviate ``--out_direction` as `-D`.
|
||||||
|
@ -25,7 +25,7 @@ the standard install location for python packages, and will put GFPGAN into a
|
|||||||
subdirectory of "src" in the InvokeAI directory. (The reason for this is
|
subdirectory of "src" in the InvokeAI directory. (The reason for this is
|
||||||
that the standard GFPGAN distribution has a minor bug that adversely affects
|
that the standard GFPGAN distribution has a minor bug that adversely affects
|
||||||
image color.) Upscaling with Real-ESRGAN should "just work" without further
|
image color.) Upscaling with Real-ESRGAN should "just work" without further
|
||||||
intervention. Simply pass the --upscale (-U) option on the dream> command line,
|
intervention. Simply pass the --upscale (-U) option on the invoke> command line,
|
||||||
or indicate the desired scale on the popup in the Web GUI.
|
or indicate the desired scale on the popup in the Web GUI.
|
||||||
|
|
||||||
For **GFPGAN** to work, there is one additional step needed. You will need to
|
For **GFPGAN** to work, there is one additional step needed. You will need to
|
||||||
@ -42,14 +42,14 @@ Make sure that you're in the InvokeAI directory when you do this.
|
|||||||
|
|
||||||
Alternatively, if you have GFPGAN installed elsewhere, or if you are using an
|
Alternatively, if you have GFPGAN installed elsewhere, or if you are using an
|
||||||
earlier version of this package which asked you to install GFPGAN in a sibling
|
earlier version of this package which asked you to install GFPGAN in a sibling
|
||||||
directory, you may use the `--gfpgan_dir` argument with `dream.py` to set a
|
directory, you may use the `--gfpgan_dir` argument with `invoke.py` to set a
|
||||||
custom path to your GFPGAN directory. _There are other GFPGAN related boot
|
custom path to your GFPGAN directory. _There are other GFPGAN related boot
|
||||||
arguments if you wish to customize further._
|
arguments if you wish to customize further._
|
||||||
|
|
||||||
!!! warning "Internet connection needed"
|
!!! warning "Internet connection needed"
|
||||||
|
|
||||||
Users whose GPU machines are isolated from the Internet (e.g.
|
Users whose GPU machines are isolated from the Internet (e.g.
|
||||||
on a University cluster) should be aware that the first time you run dream.py with GFPGAN and
|
on a University cluster) should be aware that the first time you run invoke.py with GFPGAN and
|
||||||
Real-ESRGAN turned on, it will try to download model files from the Internet. To rectify this, you
|
Real-ESRGAN turned on, it will try to download model files from the Internet. To rectify this, you
|
||||||
may run `python3 scripts/preload_models.py` after you have installed GFPGAN and all its
|
may run `python3 scripts/preload_models.py` after you have installed GFPGAN and all its
|
||||||
dependencies.
|
dependencies.
|
||||||
@ -94,13 +94,13 @@ too.
|
|||||||
### Example Usage
|
### Example Usage
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
dream> superman dancing with a panda bear -U 2 0.6 -G 0.4
|
invoke> superman dancing with a panda bear -U 2 0.6 -G 0.4
|
||||||
```
|
```
|
||||||
|
|
||||||
This also works with img2img:
|
This also works with img2img:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
dream> a man wearing a pineapple hat -I path/to/your/file.png -U 2 0.5 -G 0.6
|
invoke> a man wearing a pineapple hat -I path/to/your/file.png -U 2 0.5 -G 0.6
|
||||||
```
|
```
|
||||||
|
|
||||||
!!! note
|
!!! note
|
||||||
@ -168,7 +168,7 @@ previously-generated file. Just use the syntax `!fix path/to/file.png
|
|||||||
just run:
|
just run:
|
||||||
|
|
||||||
```
|
```
|
||||||
dream> !fix ./outputs/img-samples/000044.2945021133.png -G 0.8 -U 2
|
invoke> !fix ./outputs/img-samples/000044.2945021133.png -G 0.8 -U 2
|
||||||
```
|
```
|
||||||
|
|
||||||
A new file named `000044.2945021133.fixed.png` will be created in the output
|
A new file named `000044.2945021133.fixed.png` will be created in the output
|
||||||
@ -178,5 +178,5 @@ unlike the behavior at generate time.
|
|||||||
### Disabling:
|
### Disabling:
|
||||||
|
|
||||||
If, for some reason, you do not wish to load the GFPGAN and/or ESRGAN libraries,
|
If, for some reason, you do not wish to load the GFPGAN and/or ESRGAN libraries,
|
||||||
you can disable them on the dream.py command line with the `--no_restore` and
|
you can disable them on the invoke.py command line with the `--no_restore` and
|
||||||
`--no_upscale` options, respectively.
|
`--no_upscale` options, respectively.
|
||||||
|
@ -6,9 +6,9 @@ title: Prompting Features
|
|||||||
|
|
||||||
## **Reading Prompts from a File**
|
## **Reading Prompts from a File**
|
||||||
|
|
||||||
You can automate `dream.py` by providing a text file with the prompts you want to run, one line per
|
You can automate `invoke.py` by providing a text file with the prompts you want to run, one line per
|
||||||
prompt. The text file must be composed with a text editor (e.g. Notepad) and not a word processor.
|
prompt. The text file must be composed with a text editor (e.g. Notepad) and not a word processor.
|
||||||
Each line should look like what you would type at the dream> prompt:
|
Each line should look like what you would type at the invoke> prompt:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
a beautiful sunny day in the park, children playing -n4 -C10
|
a beautiful sunny day in the park, children playing -n4 -C10
|
||||||
@ -16,16 +16,16 @@ stormy weather on a mountain top, goats grazing -s100
|
|||||||
innovative packaging for a squid's dinner -S137038382
|
innovative packaging for a squid's dinner -S137038382
|
||||||
```
|
```
|
||||||
|
|
||||||
Then pass this file's name to `dream.py` when you invoke it:
|
Then pass this file's name to `invoke.py` when you invoke it:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
(ldm) ~/stable-diffusion$ python3 scripts/dream.py --from_file "path/to/prompts.txt"
|
(ldm) ~/stable-diffusion$ python3 scripts/invoke.py --from_file "path/to/prompts.txt"
|
||||||
```
|
```
|
||||||
|
|
||||||
You may read a series of prompts from standard input by providing a filename of `-`:
|
You may read a series of prompts from standard input by providing a filename of `-`:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
(ldm) ~/stable-diffusion$ echo "a beautiful day" | python3 scripts/dream.py --from_file -
|
(ldm) ~/stable-diffusion$ echo "a beautiful day" | python3 scripts/invoke.py --from_file -
|
||||||
```
|
```
|
||||||
---
|
---
|
||||||
|
|
||||||
|
@ -56,22 +56,22 @@ configs/stable_diffusion/v1-finetune.yaml (currently set to 4000000)
|
|||||||
## **Run the Model**
|
## **Run the Model**
|
||||||
|
|
||||||
Once the model is trained, specify the trained .pt or .bin file when starting
|
Once the model is trained, specify the trained .pt or .bin file when starting
|
||||||
dream using
|
invoke using
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
python3 ./scripts/dream.py --embedding_path /path/to/embedding.pt
|
python3 ./scripts/invoke.py --embedding_path /path/to/embedding.pt
|
||||||
```
|
```
|
||||||
|
|
||||||
Then, to utilize your subject at the dream prompt
|
Then, to utilize your subject at the invoke prompt
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
dream> "a photo of *"
|
invoke> "a photo of *"
|
||||||
```
|
```
|
||||||
|
|
||||||
This also works with image2image
|
This also works with image2image
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
dream> "waterfall and rainbow in the style of *" --init_img=./init-images/crude_drawing.png --strength=0.5 -s100 -n4
|
invoke> "waterfall and rainbow in the style of *" --init_img=./init-images/crude_drawing.png --strength=0.5 -s100 -n4
|
||||||
```
|
```
|
||||||
|
|
||||||
For .pt files it's also possible to train multiple tokens (modify the
|
For .pt files it's also possible to train multiple tokens (modify the
|
||||||
|
@ -34,7 +34,7 @@ First we let SD create a series of images in the usual way, in this case
|
|||||||
requesting six iterations:
|
requesting six iterations:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
dream> lucy lawless as xena, warrior princess, character portrait, high resolution -n6
|
invoke> lucy lawless as xena, warrior princess, character portrait, high resolution -n6
|
||||||
...
|
...
|
||||||
Outputs:
|
Outputs:
|
||||||
./outputs/Xena/000001.1579445059.png: "prompt" -s50 -W512 -H512 -C7.5 -Ak_lms -S1579445059
|
./outputs/Xena/000001.1579445059.png: "prompt" -s50 -W512 -H512 -C7.5 -Ak_lms -S1579445059
|
||||||
@ -57,7 +57,7 @@ differing by a variation amount of 0.2. This number ranges from `0` to `1.0`,
|
|||||||
with higher numbers being larger amounts of variation.
|
with higher numbers being larger amounts of variation.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
dream> "prompt" -n6 -S3357757885 -v0.2
|
invoke> "prompt" -n6 -S3357757885 -v0.2
|
||||||
...
|
...
|
||||||
Outputs:
|
Outputs:
|
||||||
./outputs/Xena/000002.784039624.png: "prompt" -s50 -W512 -H512 -C7.5 -Ak_lms -V 784039624:0.2 -S3357757885
|
./outputs/Xena/000002.784039624.png: "prompt" -s50 -W512 -H512 -C7.5 -Ak_lms -V 784039624:0.2 -S3357757885
|
||||||
@ -89,7 +89,7 @@ We combine the two variations using `-V` (`--with_variations`). Again, we must
|
|||||||
provide the seed for the originally-chosen image in order for this to work.
|
provide the seed for the originally-chosen image in order for this to work.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
dream> "prompt" -S3357757885 -V3647897225,0.1,1614299449,0.1
|
invoke> "prompt" -S3357757885 -V3647897225,0.1,1614299449,0.1
|
||||||
Outputs:
|
Outputs:
|
||||||
./outputs/Xena/000003.1614299449.png: "prompt" -s50 -W512 -H512 -C7.5 -Ak_lms -V 3647897225:0.1,1614299449:0.1 -S3357757885
|
./outputs/Xena/000003.1614299449.png: "prompt" -s50 -W512 -H512 -C7.5 -Ak_lms -V 3647897225:0.1,1614299449:0.1 -S3357757885
|
||||||
```
|
```
|
||||||
@ -105,7 +105,7 @@ latter, using both the `-V` (combining) and `-v` (variation strength) options.
|
|||||||
Note that we use `-n6` to generate 6 variations:
|
Note that we use `-n6` to generate 6 variations:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
dream> "prompt" -S3357757885 -V3647897225,0.1,1614299449,0.1 -v0.05 -n6
|
invoke> "prompt" -S3357757885 -V3647897225,0.1,1614299449,0.1 -v0.05 -n6
|
||||||
Outputs:
|
Outputs:
|
||||||
./outputs/Xena/000004.3279757577.png: "prompt" -s50 -W512 -H512 -C7.5 -Ak_lms -V 3647897225:0.1,1614299449:0.1,3279757577:0.05 -S3357757885
|
./outputs/Xena/000004.3279757577.png: "prompt" -s50 -W512 -H512 -C7.5 -Ak_lms -V 3647897225:0.1,1614299449:0.1,3279757577:0.05 -S3357757885
|
||||||
./outputs/Xena/000004.2853129515.png: "prompt" -s50 -W512 -H512 -C7.5 -Ak_lms -V 3647897225:0.1,1614299449:0.1,2853129515:0.05 -S3357757885
|
./outputs/Xena/000004.2853129515.png: "prompt" -s50 -W512 -H512 -C7.5 -Ak_lms -V 3647897225:0.1,1614299449:0.1,2853129515:0.05 -S3357757885
|
||||||
|
@ -5,11 +5,11 @@ title: Barebones Web Server
|
|||||||
# :material-web: Barebones Web Server
|
# :material-web: Barebones Web Server
|
||||||
|
|
||||||
As of version 1.10, this distribution comes with a bare bones web server (see
|
As of version 1.10, this distribution comes with a bare bones web server (see
|
||||||
screenshot). To use it, run the `dream.py` script by adding the `--web`
|
screenshot). To use it, run the `invoke.py` script by adding the `--web`
|
||||||
option.
|
option.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
(ldm) ~/stable-diffusion$ python3 scripts/dream.py --web
|
(ldm) ~/stable-diffusion$ python3 scripts/invoke.py --web
|
||||||
```
|
```
|
||||||
|
|
||||||
You can then connect to the server by pointing your web browser at
|
You can then connect to the server by pointing your web browser at
|
||||||
@ -18,4 +18,4 @@ http://localhost:9090, or to the network name or IP address of the server.
|
|||||||
Kudos to [Tesseract Cat](https://github.com/TesseractCat) for contributing this
|
Kudos to [Tesseract Cat](https://github.com/TesseractCat) for contributing this
|
||||||
code, and to [dagf2101](https://github.com/dagf2101) for refining it.
|
code, and to [dagf2101](https://github.com/dagf2101) for refining it.
|
||||||
|
|
||||||

|

|
||||||
|
@ -51,7 +51,7 @@ rm ${PIP_LOG}
|
|||||||
|
|
||||||
### **QUESTION**
|
### **QUESTION**
|
||||||
|
|
||||||
`dream.py` crashes with the complaint that it can't find `ldm.simplet2i.py`. Or it complains that
|
`invoke.py` crashes with the complaint that it can't find `ldm.simplet2i.py`. Or it complains that
|
||||||
function is being passed incorrect parameters.
|
function is being passed incorrect parameters.
|
||||||
|
|
||||||
### **SOLUTION**
|
### **SOLUTION**
|
||||||
@ -63,7 +63,7 @@ Reinstall the stable diffusion modules. Enter the `stable-diffusion` directory a
|
|||||||
|
|
||||||
### **QUESTION**
|
### **QUESTION**
|
||||||
|
|
||||||
`dream.py` dies, complaining of various missing modules, none of which starts with `ldm``.
|
`invoke.py` dies, complaining of various missing modules, none of which starts with `ldm``.
|
||||||
|
|
||||||
### **SOLUTION**
|
### **SOLUTION**
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ template: main.html
|
|||||||
[CI checks on dev badge]: https://flat.badgen.net/github/checks/lstein/stable-diffusion/development?label=CI%20status%20on%20dev&cache=900&icon=github
|
[CI checks on dev badge]: https://flat.badgen.net/github/checks/lstein/stable-diffusion/development?label=CI%20status%20on%20dev&cache=900&icon=github
|
||||||
[CI checks on dev link]: https://github.com/lstein/stable-diffusion/actions?query=branch%3Adevelopment
|
[CI checks on dev link]: https://github.com/lstein/stable-diffusion/actions?query=branch%3Adevelopment
|
||||||
[CI checks on main badge]: https://flat.badgen.net/github/checks/lstein/stable-diffusion/main?label=CI%20status%20on%20main&cache=900&icon=github
|
[CI checks on main badge]: https://flat.badgen.net/github/checks/lstein/stable-diffusion/main?label=CI%20status%20on%20main&cache=900&icon=github
|
||||||
[CI checks on main link]: https://github.com/lstein/stable-diffusion/actions/workflows/test-dream-conda.yml
|
[CI checks on main link]: https://github.com/lstein/stable-diffusion/actions/workflows/test-invoke-conda.yml
|
||||||
[discord badge]: https://flat.badgen.net/discord/members/htRgbc7e?icon=discord
|
[discord badge]: https://flat.badgen.net/discord/members/htRgbc7e?icon=discord
|
||||||
[discord link]: https://discord.com/invite/htRgbc7e
|
[discord link]: https://discord.com/invite/htRgbc7e
|
||||||
[github forks badge]: https://flat.badgen.net/github/forks/lstein/stable-diffusion?icon=github
|
[github forks badge]: https://flat.badgen.net/github/forks/lstein/stable-diffusion?icon=github
|
||||||
@ -85,21 +85,21 @@ You wil need one of the following:
|
|||||||
|
|
||||||
!!! note
|
!!! note
|
||||||
|
|
||||||
If you are have a Nvidia 10xx series card (e.g. the 1080ti), please run the dream script in
|
If you are have a Nvidia 10xx series card (e.g. the 1080ti), please run the invoke script in
|
||||||
full-precision mode as shown below.
|
full-precision mode as shown below.
|
||||||
|
|
||||||
Similarly, specify full-precision mode on Apple M1 hardware.
|
Similarly, specify full-precision mode on Apple M1 hardware.
|
||||||
|
|
||||||
To run in full-precision mode, start `dream.py` with the `--full_precision` flag:
|
To run in full-precision mode, start `invoke.py` with the `--full_precision` flag:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
(ldm) ~/stable-diffusion$ python scripts/dream.py --full_precision
|
(ldm) ~/stable-diffusion$ python scripts/invoke.py --full_precision
|
||||||
```
|
```
|
||||||
## :octicons-log-16: Latest Changes
|
## :octicons-log-16: Latest Changes
|
||||||
|
|
||||||
### vNEXT <small>(TODO 2022)</small>
|
### vNEXT <small>(TODO 2022)</small>
|
||||||
|
|
||||||
- Deprecated `--full_precision` / `-F`. Simply omit it and `dream.py` will auto
|
- Deprecated `--full_precision` / `-F`. Simply omit it and `invoke.py` will auto
|
||||||
configure. To switch away from auto use the new flag like `--precision=float32`.
|
configure. To switch away from auto use the new flag like `--precision=float32`.
|
||||||
|
|
||||||
### v1.14 <small>(11 September 2022)</small>
|
### v1.14 <small>(11 September 2022)</small>
|
||||||
@ -124,7 +124,7 @@ You wil need one of the following:
|
|||||||
[Kevin Gibbons](https://github.com/bakkot)
|
[Kevin Gibbons](https://github.com/bakkot)
|
||||||
- A new configuration file scheme that allows new models (including upcoming stable-diffusion-v1.5)
|
- A new configuration file scheme that allows new models (including upcoming stable-diffusion-v1.5)
|
||||||
to be added without altering the code. ([David Wager](https://github.com/maddavid12))
|
to be added without altering the code. ([David Wager](https://github.com/maddavid12))
|
||||||
- Can specify --grid on dream.py command line as the default.
|
- Can specify --grid on invoke.py command line as the default.
|
||||||
- Miscellaneous internal bug and stability fixes.
|
- Miscellaneous internal bug and stability fixes.
|
||||||
- Works on M1 Apple hardware.
|
- Works on M1 Apple hardware.
|
||||||
- Multiple bug fixes.
|
- Multiple bug fixes.
|
||||||
|
@ -136,7 +136,7 @@ $TAG_STABLE_DIFFUSION
|
|||||||
|
|
||||||
## Startup
|
## Startup
|
||||||
|
|
||||||
If you're on a **Linux container** the `dream` script is **automatically
|
If you're on a **Linux container** the `invoke` script is **automatically
|
||||||
started** and the output dir set to the Docker volume you created earlier.
|
started** and the output dir set to the Docker volume you created earlier.
|
||||||
|
|
||||||
If you're **directly on macOS follow these startup instructions**.
|
If you're **directly on macOS follow these startup instructions**.
|
||||||
@ -148,14 +148,14 @@ half-precision requires autocast and won't work.
|
|||||||
By default the images are saved in `outputs/img-samples/`.
|
By default the images are saved in `outputs/img-samples/`.
|
||||||
|
|
||||||
```Shell
|
```Shell
|
||||||
python3 scripts/dream.py --full_precision
|
python3 scripts/invoke.py --full_precision
|
||||||
```
|
```
|
||||||
|
|
||||||
You'll get the script's prompt. You can see available options or quit.
|
You'll get the script's prompt. You can see available options or quit.
|
||||||
|
|
||||||
```Shell
|
```Shell
|
||||||
dream> -h
|
invoke> -h
|
||||||
dream> q
|
invoke> q
|
||||||
```
|
```
|
||||||
|
|
||||||
## Text to Image
|
## Text to Image
|
||||||
@ -166,10 +166,10 @@ Then increase steps to 100 or more for good (but slower) results.
|
|||||||
The prompt can be in quotes or not.
|
The prompt can be in quotes or not.
|
||||||
|
|
||||||
```Shell
|
```Shell
|
||||||
dream> The hulk fighting with sheldon cooper -s5 -n1
|
invoke> The hulk fighting with sheldon cooper -s5 -n1
|
||||||
dream> "woman closeup highly detailed" -s 150
|
invoke> "woman closeup highly detailed" -s 150
|
||||||
# Reuse previous seed and apply face restoration
|
# Reuse previous seed and apply face restoration
|
||||||
dream> "woman closeup highly detailed" --steps 150 --seed -1 -G 0.75
|
invoke> "woman closeup highly detailed" --steps 150 --seed -1 -G 0.75
|
||||||
```
|
```
|
||||||
|
|
||||||
You'll need to experiment to see if face restoration is making it better or
|
You'll need to experiment to see if face restoration is making it better or
|
||||||
@ -210,28 +210,28 @@ If you're on a Docker container, copy your input image into the Docker volume
|
|||||||
docker cp /Users/<your-user>/Pictures/sketch-mountains-input.jpg dummy:/data/
|
docker cp /Users/<your-user>/Pictures/sketch-mountains-input.jpg dummy:/data/
|
||||||
```
|
```
|
||||||
|
|
||||||
Try it out generating an image (or more). The `dream` script needs absolute
|
Try it out generating an image (or more). The `invoke` script needs absolute
|
||||||
paths to find the image so don't use `~`.
|
paths to find the image so don't use `~`.
|
||||||
|
|
||||||
If you're on your Mac
|
If you're on your Mac
|
||||||
|
|
||||||
```Shell
|
```Shell
|
||||||
dream> "A fantasy landscape, trending on artstation" -I /Users/<your-user>/Pictures/sketch-mountains-input.jpg --strength 0.75 --steps 100 -n4
|
invoke> "A fantasy landscape, trending on artstation" -I /Users/<your-user>/Pictures/sketch-mountains-input.jpg --strength 0.75 --steps 100 -n4
|
||||||
```
|
```
|
||||||
|
|
||||||
If you're on a Linux container on your Mac
|
If you're on a Linux container on your Mac
|
||||||
|
|
||||||
```Shell
|
```Shell
|
||||||
dream> "A fantasy landscape, trending on artstation" -I /data/sketch-mountains-input.jpg --strength 0.75 --steps 50 -n1
|
invoke> "A fantasy landscape, trending on artstation" -I /data/sketch-mountains-input.jpg --strength 0.75 --steps 50 -n1
|
||||||
```
|
```
|
||||||
|
|
||||||
## Web Interface
|
## Web Interface
|
||||||
|
|
||||||
You can use the `dream` script with a graphical web interface. Start the web
|
You can use the `invoke` script with a graphical web interface. Start the web
|
||||||
server with:
|
server with:
|
||||||
|
|
||||||
```Shell
|
```Shell
|
||||||
python3 scripts/dream.py --full_precision --web
|
python3 scripts/invoke.py --full_precision --web
|
||||||
```
|
```
|
||||||
|
|
||||||
If it's running on your Mac point your Mac web browser to http://127.0.0.1:9090
|
If it's running on your Mac point your Mac web browser to http://127.0.0.1:9090
|
||||||
|
@ -89,16 +89,16 @@ This will create InvokeAI folder where you will follow the rest of the steps.
|
|||||||
|
|
||||||
```
|
```
|
||||||
# for the pre-release weights use the -l or --liaon400m switch
|
# for the pre-release weights use the -l or --liaon400m switch
|
||||||
(ldm) ~/InvokeAI$ python3 scripts/dream.py -l
|
(ldm) ~/InvokeAI$ python3 scripts/invoke.py -l
|
||||||
|
|
||||||
# for the post-release weights do not use the switch
|
# for the post-release weights do not use the switch
|
||||||
(ldm) ~/InvokeAI$ python3 scripts/dream.py
|
(ldm) ~/InvokeAI$ python3 scripts/invoke.py
|
||||||
|
|
||||||
# for additional configuration switches and arguments, use -h or --help
|
# for additional configuration switches and arguments, use -h or --help
|
||||||
(ldm) ~/InvokeAI$ python3 scripts/dream.py -h
|
(ldm) ~/InvokeAI$ python3 scripts/invoke.py -h
|
||||||
```
|
```
|
||||||
|
|
||||||
9. Subsequently, to relaunch the script, be sure to run "conda activate ldm" (step 5, second command), enter the `InvokeAI` directory, and then launch the dream script (step 8). If you forget to activate the ldm environment, the script will fail with multiple `ModuleNotFound` errors.
|
9. Subsequently, to relaunch the script, be sure to run "conda activate ldm" (step 5, second command), enter the `InvokeAI` directory, and then launch the invoke script (step 8). If you forget to activate the ldm environment, the script will fail with multiple `ModuleNotFound` errors.
|
||||||
|
|
||||||
## Updating to newer versions of the script
|
## Updating to newer versions of the script
|
||||||
|
|
||||||
|
@ -137,10 +137,10 @@ ln -s "$PATH_TO_CKPT/sd-v1-4.ckpt" \
|
|||||||
python scripts/preload_models.py
|
python scripts/preload_models.py
|
||||||
|
|
||||||
# now you can run SD in CLI mode
|
# now you can run SD in CLI mode
|
||||||
python scripts/dream.py --full_precision # (1)!
|
python scripts/invoke.py --full_precision # (1)!
|
||||||
|
|
||||||
# or run the web interface!
|
# or run the web interface!
|
||||||
python scripts/dream.py --web
|
python scripts/invoke.py --web
|
||||||
|
|
||||||
# The original scripts should work as well.
|
# The original scripts should work as well.
|
||||||
python scripts/orig_scripts/txt2img.py \
|
python scripts/orig_scripts/txt2img.py \
|
||||||
@ -155,7 +155,7 @@ it isn't required but wont hurt.
|
|||||||
|
|
||||||
## Common problems
|
## Common problems
|
||||||
|
|
||||||
After you followed all the instructions and try to run dream.py, you might
|
After you followed all the instructions and try to run invoke.py, you might
|
||||||
get several errors. Here's the errors I've seen and found solutions for.
|
get several errors. Here's the errors I've seen and found solutions for.
|
||||||
|
|
||||||
### Is it slow?
|
### Is it slow?
|
||||||
@ -220,9 +220,9 @@ There are several causes of these errors:
|
|||||||
"(ldm)" then you activated it. If it begins with "(base)" or something else
|
"(ldm)" then you activated it. If it begins with "(base)" or something else
|
||||||
you haven't.
|
you haven't.
|
||||||
|
|
||||||
2. You might've run `./scripts/preload_models.py` or `./scripts/dream.py`
|
2. You might've run `./scripts/preload_models.py` or `./scripts/invoke.py`
|
||||||
instead of `python ./scripts/preload_models.py` or
|
instead of `python ./scripts/preload_models.py` or
|
||||||
`python ./scripts/dream.py`. The cause of this error is long so it's below.
|
`python ./scripts/invoke.py`. The cause of this error is long so it's below.
|
||||||
|
|
||||||
<!-- I could not find out where the error is, otherwise would have marked it as a footnote -->
|
<!-- I could not find out where the error is, otherwise would have marked it as a footnote -->
|
||||||
|
|
||||||
@ -519,7 +519,7 @@ use ARM packages, and use `nomkl` as described above.
|
|||||||
May appear when just starting to generate, e.g.:
|
May appear when just starting to generate, e.g.:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
dream> clouds
|
invoke> clouds
|
||||||
Generating: 0%| | 0/1 [00:00<?, ?it/s]/Users/[...]/dev/stable-diffusion/ldm/modules/embedding_manager.py:152: UserWarning: The operator 'aten::nonzero' is not currently supported on the MPS backend and will fall back to run on the CPU. This may have performance implications. (Triggered internally at /Users/runner/work/_temp/anaconda/conda-bld/pytorch_1662016319283/work/aten/src/ATen/mps/MPSFallback.mm:11.)
|
Generating: 0%| | 0/1 [00:00<?, ?it/s]/Users/[...]/dev/stable-diffusion/ldm/modules/embedding_manager.py:152: UserWarning: The operator 'aten::nonzero' is not currently supported on the MPS backend and will fall back to run on the CPU. This may have performance implications. (Triggered internally at /Users/runner/work/_temp/anaconda/conda-bld/pytorch_1662016319283/work/aten/src/ATen/mps/MPSFallback.mm:11.)
|
||||||
placeholder_idx = torch.where(
|
placeholder_idx = torch.where(
|
||||||
loc("mps_add"("(mpsFileLoc): /AppleInternal/Library/BuildRoots/20d6c351-ee94-11ec-bcaf-7247572f23b4/Library/Caches/com.apple.xbs/Sources/MetalPerformanceShadersGraph/mpsgraph/MetalPerformanceShadersGraph/Core/Files/MPSGraphUtilities.mm":219:0)): error: input types 'tensor<2x1280xf32>' and 'tensor<*xf16>' are not broadcast compatible
|
loc("mps_add"("(mpsFileLoc): /AppleInternal/Library/BuildRoots/20d6c351-ee94-11ec-bcaf-7247572f23b4/Library/Caches/com.apple.xbs/Sources/MetalPerformanceShadersGraph/mpsgraph/MetalPerformanceShadersGraph/Core/Files/MPSGraphUtilities.mm":219:0)): error: input types 'tensor<2x1280xf32>' and 'tensor<*xf16>' are not broadcast compatible
|
||||||
|
@ -101,13 +101,13 @@ you may instead create a shortcut to it from within `models\ldm\stable-diffusion
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
# for the pre-release weights
|
# for the pre-release weights
|
||||||
python scripts\dream.py -l
|
python scripts\invoke.py -l
|
||||||
|
|
||||||
# for the post-release weights
|
# for the post-release weights
|
||||||
python scripts\dream.py
|
python scripts\invoke.py
|
||||||
```
|
```
|
||||||
|
|
||||||
10. Subsequently, to relaunch the script, first activate the Anaconda command window (step 3),enter the InvokeAI directory (step 5, `cd \path\to\InvokeAI`), run `conda activate ldm` (step 6b), and then launch the dream script (step 9).
|
10. Subsequently, to relaunch the script, first activate the Anaconda command window (step 3),enter the InvokeAI directory (step 5, `cd \path\to\InvokeAI`), run `conda activate ldm` (step 6b), and then launch the invoke script (step 9).
|
||||||
|
|
||||||
**Note:** Tildebyte has written an alternative
|
**Note:** Tildebyte has written an alternative
|
||||||
["Easy peasy Windows install"](https://github.com/invoke-ai/InvokeAI/wiki/Easy-peasy-Windows-install)
|
["Easy peasy Windows install"](https://github.com/invoke-ai/InvokeAI/wiki/Easy-peasy-Windows-install)
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
"""Helper class for dealing with image generation arguments.
|
"""Helper class for dealing with image generation arguments.
|
||||||
|
|
||||||
The Args class parses both the command line (shell) arguments, as well as the
|
The Args class parses both the command line (shell) arguments, as well as the
|
||||||
command string passed at the dream> prompt. It serves as the definitive repository
|
command string passed at the invoke> prompt. It serves as the definitive repository
|
||||||
of all the arguments used by Generate and their default values, and implements the
|
of all the arguments used by Generate and their default values, and implements the
|
||||||
preliminary metadata standards discussed here:
|
preliminary metadata standards discussed here:
|
||||||
|
|
||||||
@ -19,7 +19,7 @@ To use:
|
|||||||
print('oops')
|
print('oops')
|
||||||
sys.exit(-1)
|
sys.exit(-1)
|
||||||
|
|
||||||
# read in a command passed to the dream> prompt:
|
# read in a command passed to the invoke> prompt:
|
||||||
opts = opt.parse_cmd('do androids dream of electric sheep? -H256 -W1024 -n4')
|
opts = opt.parse_cmd('do androids dream of electric sheep? -H256 -W1024 -n4')
|
||||||
|
|
||||||
# The Args object acts like a namespace object
|
# The Args object acts like a namespace object
|
||||||
@ -64,7 +64,7 @@ To generate a dict representing RFC266 metadata:
|
|||||||
This will generate an RFC266 dictionary that can then be turned into a JSON
|
This will generate an RFC266 dictionary that can then be turned into a JSON
|
||||||
and written to the PNG file. The optional seeds, weights, model_hash and
|
and written to the PNG file. The optional seeds, weights, model_hash and
|
||||||
postprocesser arguments are not available to the opt object and so must be
|
postprocesser arguments are not available to the opt object and so must be
|
||||||
provided externally. See how dream.py does it.
|
provided externally. See how invoke.py does it.
|
||||||
|
|
||||||
Note that this function was originally called format_metadata() and a wrapper
|
Note that this function was originally called format_metadata() and a wrapper
|
||||||
is provided that issues a deprecation notice.
|
is provided that issues a deprecation notice.
|
||||||
@ -120,7 +120,7 @@ class Args(object):
|
|||||||
'''
|
'''
|
||||||
Initialize new Args class. It takes two optional arguments, an argparse
|
Initialize new Args class. It takes two optional arguments, an argparse
|
||||||
parser for switches given on the shell command line, and an argparse
|
parser for switches given on the shell command line, and an argparse
|
||||||
parser for switches given on the dream> CLI line. If one or both are
|
parser for switches given on the invoke> CLI line. If one or both are
|
||||||
missing, it creates appropriate parsers internally.
|
missing, it creates appropriate parsers internally.
|
||||||
'''
|
'''
|
||||||
self._arg_parser = arg_parser or self._create_arg_parser()
|
self._arg_parser = arg_parser or self._create_arg_parser()
|
||||||
@ -137,7 +137,7 @@ class Args(object):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
def parse_cmd(self,cmd_string):
|
def parse_cmd(self,cmd_string):
|
||||||
'''Parse a dream>-style command string '''
|
'''Parse a invoke>-style command string '''
|
||||||
command = cmd_string.replace("'", "\\'")
|
command = cmd_string.replace("'", "\\'")
|
||||||
try:
|
try:
|
||||||
elements = shlex.split(command)
|
elements = shlex.split(command)
|
||||||
@ -478,23 +478,23 @@ class Args(object):
|
|||||||
)
|
)
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
# This creates the parser that processes commands on the dream> command line
|
# This creates the parser that processes commands on the invoke> command line
|
||||||
def _create_dream_cmd_parser(self):
|
def _create_dream_cmd_parser(self):
|
||||||
parser = argparse.ArgumentParser(
|
parser = argparse.ArgumentParser(
|
||||||
formatter_class=RawTextHelpFormatter,
|
formatter_class=RawTextHelpFormatter,
|
||||||
description=
|
description=
|
||||||
"""
|
"""
|
||||||
*Image generation:*
|
*Image generation:*
|
||||||
dream> a fantastic alien landscape -W576 -H512 -s60 -n4
|
invoke> a fantastic alien landscape -W576 -H512 -s60 -n4
|
||||||
|
|
||||||
*postprocessing*
|
*postprocessing*
|
||||||
!fix applies upscaling/facefixing to a previously-generated image.
|
!fix applies upscaling/facefixing to a previously-generated image.
|
||||||
dream> !fix 0000045.4829112.png -G1 -U4 -ft codeformer
|
invoke> !fix 0000045.4829112.png -G1 -U4 -ft codeformer
|
||||||
|
|
||||||
*History manipulation*
|
*History manipulation*
|
||||||
!fetch retrieves the command used to generate an earlier image.
|
!fetch retrieves the command used to generate an earlier image.
|
||||||
dream> !fetch 0000015.8929913.png
|
invoke> !fetch 0000015.8929913.png
|
||||||
dream> a fantastic alien landscape -W 576 -H 512 -s 60 -A plms -C 7.5
|
invoke> a fantastic alien landscape -W 576 -H 512 -s 60 -A plms -C 7.5
|
||||||
|
|
||||||
!history lists all the commands issued during the current session.
|
!history lists all the commands issued during the current session.
|
||||||
|
|
||||||
|
570
scripts/dream.py
570
scripts/dream.py
@ -1,570 +1,12 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# Copyright (c) 2022 Lincoln D. Stein (https://github.com/lstein)
|
# Copyright (c) 2022 Lincoln D. Stein (https://github.com/lstein)
|
||||||
|
|
||||||
import os
|
|
||||||
import re
|
|
||||||
import sys
|
import sys
|
||||||
import shlex
|
import os.path
|
||||||
import copy
|
|
||||||
import warnings
|
|
||||||
import time
|
|
||||||
import traceback
|
|
||||||
sys.path.append('.') # corrects a weird problem on Macs
|
|
||||||
from ldm.dream.readline import get_completer
|
|
||||||
from ldm.dream.args import Args, metadata_dumps, metadata_from_png, dream_cmd_from_png
|
|
||||||
from ldm.dream.pngwriter import PngWriter, retrieve_metadata, write_metadata
|
|
||||||
from ldm.dream.image_util import make_grid
|
|
||||||
from ldm.dream.log import write_log
|
|
||||||
from omegaconf import OmegaConf
|
|
||||||
from backend.invoke_ai_web_server import InvokeAIWebServer
|
|
||||||
|
|
||||||
|
script_path = sys.argv[0]
|
||||||
|
script_args = sys.argv[1:]
|
||||||
|
script_dir,script_name = os.path.split(script_path)
|
||||||
|
script_dest = os.path.join(script_dir,'invoke.py')
|
||||||
|
os.execlp('python3','python3',script_dest,*script_args)
|
||||||
|
|
||||||
def main():
|
|
||||||
"""Initialize command-line parsers and the diffusion model"""
|
|
||||||
opt = Args()
|
|
||||||
args = opt.parse_args()
|
|
||||||
if not args:
|
|
||||||
sys.exit(-1)
|
|
||||||
|
|
||||||
if args.laion400m:
|
|
||||||
print('--laion400m flag has been deprecated. Please use --model laion400m instead.')
|
|
||||||
sys.exit(-1)
|
|
||||||
if args.weights:
|
|
||||||
print('--weights argument has been deprecated. Please edit ./configs/models.yaml, and select the weights using --model instead.')
|
|
||||||
sys.exit(-1)
|
|
||||||
|
|
||||||
print('* Initializing, be patient...\n')
|
|
||||||
from ldm.generate import Generate
|
|
||||||
|
|
||||||
# these two lines prevent a horrible warning message from appearing
|
|
||||||
# when the frozen CLIP tokenizer is imported
|
|
||||||
import transformers
|
|
||||||
transformers.logging.set_verbosity_error()
|
|
||||||
|
|
||||||
# Loading Face Restoration and ESRGAN Modules
|
|
||||||
try:
|
|
||||||
gfpgan, codeformer, esrgan = None, None, None
|
|
||||||
if opt.restore or opt.esrgan:
|
|
||||||
from ldm.dream.restoration import Restoration
|
|
||||||
restoration = Restoration()
|
|
||||||
if opt.restore:
|
|
||||||
gfpgan, codeformer = restoration.load_face_restore_models(opt.gfpgan_dir, opt.gfpgan_model_path)
|
|
||||||
else:
|
|
||||||
print('>> Face restoration disabled')
|
|
||||||
if opt.esrgan:
|
|
||||||
esrgan = restoration.load_esrgan(opt.esrgan_bg_tile)
|
|
||||||
else:
|
|
||||||
print('>> Upscaling disabled')
|
|
||||||
else:
|
|
||||||
print('>> Face restoration and upscaling disabled')
|
|
||||||
except (ModuleNotFoundError, ImportError):
|
|
||||||
print(traceback.format_exc(), file=sys.stderr)
|
|
||||||
print('>> You may need to install the ESRGAN and/or GFPGAN modules')
|
|
||||||
|
|
||||||
# creating a simple text2image object with a handful of
|
|
||||||
# defaults passed on the command line.
|
|
||||||
# additional parameters will be added (or overriden) during
|
|
||||||
# the user input loop
|
|
||||||
try:
|
|
||||||
gen = Generate(
|
|
||||||
conf = opt.conf,
|
|
||||||
model = opt.model,
|
|
||||||
sampler_name = opt.sampler_name,
|
|
||||||
embedding_path = opt.embedding_path,
|
|
||||||
full_precision = opt.full_precision,
|
|
||||||
precision = opt.precision,
|
|
||||||
gfpgan=gfpgan,
|
|
||||||
codeformer=codeformer,
|
|
||||||
esrgan=esrgan,
|
|
||||||
free_gpu_mem=opt.free_gpu_mem,
|
|
||||||
)
|
|
||||||
except (FileNotFoundError, IOError, KeyError) as e:
|
|
||||||
print(f'{e}. Aborting.')
|
|
||||||
sys.exit(-1)
|
|
||||||
|
|
||||||
# make sure the output directory exists
|
|
||||||
if not os.path.exists(opt.outdir):
|
|
||||||
os.makedirs(opt.outdir)
|
|
||||||
|
|
||||||
# load the infile as a list of lines
|
|
||||||
infile = None
|
|
||||||
if opt.infile:
|
|
||||||
try:
|
|
||||||
if os.path.isfile(opt.infile):
|
|
||||||
infile = open(opt.infile, 'r', encoding='utf-8')
|
|
||||||
elif opt.infile == '-': # stdin
|
|
||||||
infile = sys.stdin
|
|
||||||
else:
|
|
||||||
raise FileNotFoundError(f'{opt.infile} not found.')
|
|
||||||
except (FileNotFoundError, IOError) as e:
|
|
||||||
print(f'{e}. Aborting.')
|
|
||||||
sys.exit(-1)
|
|
||||||
|
|
||||||
if opt.seamless:
|
|
||||||
print(">> changed to seamless tiling mode")
|
|
||||||
|
|
||||||
# preload the model
|
|
||||||
gen.load_model()
|
|
||||||
|
|
||||||
# web server loops forever
|
|
||||||
if opt.web or opt.gui:
|
|
||||||
invoke_ai_web_server_loop(gen, gfpgan, codeformer, esrgan)
|
|
||||||
sys.exit(0)
|
|
||||||
|
|
||||||
if not infile:
|
|
||||||
print(
|
|
||||||
"\n* Initialization done! Awaiting your command (-h for help, 'q' to quit)"
|
|
||||||
)
|
|
||||||
|
|
||||||
main_loop(gen, opt, infile)
|
|
||||||
|
|
||||||
# TODO: main_loop() has gotten busy. Needs to be refactored.
|
|
||||||
def main_loop(gen, opt, infile):
|
|
||||||
"""prompt/read/execute loop"""
|
|
||||||
done = False
|
|
||||||
path_filter = re.compile(r'[<>:"/\\|?*]')
|
|
||||||
last_results = list()
|
|
||||||
model_config = OmegaConf.load(opt.conf)[opt.model]
|
|
||||||
|
|
||||||
# The readline completer reads history from the .dream_history file located in the
|
|
||||||
# output directory specified at the time of script launch. We do not currently support
|
|
||||||
# changing the history file midstream when the output directory is changed.
|
|
||||||
completer = get_completer(opt)
|
|
||||||
output_cntr = completer.get_current_history_length()+1
|
|
||||||
|
|
||||||
# os.pathconf is not available on Windows
|
|
||||||
if hasattr(os, 'pathconf'):
|
|
||||||
path_max = os.pathconf(opt.outdir, 'PC_PATH_MAX')
|
|
||||||
name_max = os.pathconf(opt.outdir, 'PC_NAME_MAX')
|
|
||||||
else:
|
|
||||||
path_max = 260
|
|
||||||
name_max = 255
|
|
||||||
|
|
||||||
while not done:
|
|
||||||
operation = 'generate' # default operation, alternative is 'postprocess'
|
|
||||||
|
|
||||||
if completer:
|
|
||||||
completer.set_default_dir(opt.outdir)
|
|
||||||
|
|
||||||
try:
|
|
||||||
command = get_next_command(infile)
|
|
||||||
except EOFError:
|
|
||||||
done = True
|
|
||||||
continue
|
|
||||||
|
|
||||||
# skip empty lines
|
|
||||||
if not command.strip():
|
|
||||||
continue
|
|
||||||
|
|
||||||
if command.startswith(('#', '//')):
|
|
||||||
continue
|
|
||||||
|
|
||||||
if len(command.strip()) == 1 and command.startswith('q'):
|
|
||||||
done = True
|
|
||||||
break
|
|
||||||
|
|
||||||
if command.startswith('!'):
|
|
||||||
subcommand = command[1:]
|
|
||||||
|
|
||||||
if subcommand.startswith('dream'): # in case a stored prompt still contains the !dream command
|
|
||||||
command = command.replace('!dream ','',1)
|
|
||||||
|
|
||||||
elif subcommand.startswith('fix'):
|
|
||||||
command = command.replace('!fix ','',1)
|
|
||||||
operation = 'postprocess'
|
|
||||||
|
|
||||||
elif subcommand.startswith('fetch'):
|
|
||||||
file_path = command.replace('!fetch ','',1)
|
|
||||||
retrieve_dream_command(opt,file_path,completer)
|
|
||||||
continue
|
|
||||||
|
|
||||||
elif subcommand.startswith('history'):
|
|
||||||
completer.show_history()
|
|
||||||
continue
|
|
||||||
|
|
||||||
elif subcommand.startswith('search'):
|
|
||||||
search_str = command.replace('!search ','',1)
|
|
||||||
completer.show_history(search_str)
|
|
||||||
continue
|
|
||||||
|
|
||||||
elif subcommand.startswith('clear'):
|
|
||||||
completer.clear_history()
|
|
||||||
continue
|
|
||||||
|
|
||||||
elif re.match('^(\d+)',subcommand):
|
|
||||||
command_no = re.match('^(\d+)',subcommand).groups()[0]
|
|
||||||
command = completer.get_line(int(command_no))
|
|
||||||
completer.set_line(command)
|
|
||||||
continue
|
|
||||||
|
|
||||||
else: # not a recognized subcommand, so give the --help text
|
|
||||||
command = '-h'
|
|
||||||
|
|
||||||
if opt.parse_cmd(command) is None:
|
|
||||||
continue
|
|
||||||
|
|
||||||
if opt.init_img:
|
|
||||||
try:
|
|
||||||
if not opt.prompt:
|
|
||||||
oldargs = metadata_from_png(opt.init_img)
|
|
||||||
opt.prompt = oldargs.prompt
|
|
||||||
print(f'>> Retrieved old prompt "{opt.prompt}" from {opt.init_img}')
|
|
||||||
except (OSError, AttributeError, KeyError):
|
|
||||||
pass
|
|
||||||
|
|
||||||
if len(opt.prompt) == 0:
|
|
||||||
print('\nTry again with a prompt!')
|
|
||||||
continue
|
|
||||||
|
|
||||||
# width and height are set by model if not specified
|
|
||||||
if not opt.width:
|
|
||||||
opt.width = model_config.width
|
|
||||||
if not opt.height:
|
|
||||||
opt.height = model_config.height
|
|
||||||
|
|
||||||
# retrieve previous value of init image if requested
|
|
||||||
if opt.init_img is not None and re.match('^-\\d+$', opt.init_img):
|
|
||||||
try:
|
|
||||||
opt.init_img = last_results[int(opt.init_img)][0]
|
|
||||||
print(f'>> Reusing previous image {opt.init_img}')
|
|
||||||
except IndexError:
|
|
||||||
print(
|
|
||||||
f'>> No previous initial image at position {opt.init_img} found')
|
|
||||||
opt.init_img = None
|
|
||||||
continue
|
|
||||||
|
|
||||||
# try to relativize pathnames
|
|
||||||
for attr in ('init_img','init_mask','init_color','embedding_path'):
|
|
||||||
if getattr(opt,attr) and not os.path.exists(getattr(opt,attr)):
|
|
||||||
basename = getattr(opt,attr)
|
|
||||||
path = os.path.join(opt.outdir,basename)
|
|
||||||
setattr(opt,attr,path)
|
|
||||||
|
|
||||||
# retrieve previous value of seed if requested
|
|
||||||
if opt.seed is not None and opt.seed < 0:
|
|
||||||
try:
|
|
||||||
opt.seed = last_results[opt.seed][1]
|
|
||||||
print(f'>> Reusing previous seed {opt.seed}')
|
|
||||||
except IndexError:
|
|
||||||
print(f'>> No previous seed at position {opt.seed} found')
|
|
||||||
opt.seed = None
|
|
||||||
continue
|
|
||||||
|
|
||||||
if opt.strength is None:
|
|
||||||
opt.strength = 0.75 if opt.out_direction is None else 0.83
|
|
||||||
|
|
||||||
if opt.with_variations is not None:
|
|
||||||
opt.with_variations = split_variations(opt.with_variations)
|
|
||||||
|
|
||||||
if opt.prompt_as_dir:
|
|
||||||
# sanitize the prompt to a valid folder name
|
|
||||||
subdir = path_filter.sub('_', opt.prompt)[:name_max].rstrip(' .')
|
|
||||||
|
|
||||||
# truncate path to maximum allowed length
|
|
||||||
# 39 is the length of '######.##########.##########-##.png', plus two separators and a NUL
|
|
||||||
subdir = subdir[:(path_max - 39 - len(os.path.abspath(opt.outdir)))]
|
|
||||||
current_outdir = os.path.join(opt.outdir, subdir)
|
|
||||||
|
|
||||||
print('Writing files to directory: "' + current_outdir + '"')
|
|
||||||
|
|
||||||
# make sure the output directory exists
|
|
||||||
if not os.path.exists(current_outdir):
|
|
||||||
os.makedirs(current_outdir)
|
|
||||||
else:
|
|
||||||
if not os.path.exists(opt.outdir):
|
|
||||||
os.makedirs(opt.outdir)
|
|
||||||
current_outdir = opt.outdir
|
|
||||||
|
|
||||||
# Here is where the images are actually generated!
|
|
||||||
last_results = []
|
|
||||||
try:
|
|
||||||
file_writer = PngWriter(current_outdir)
|
|
||||||
results = [] # list of filename, prompt pairs
|
|
||||||
grid_images = dict() # seed -> Image, only used if `opt.grid`
|
|
||||||
prior_variations = opt.with_variations or []
|
|
||||||
prefix = file_writer.unique_prefix()
|
|
||||||
|
|
||||||
def image_writer(image, seed, upscaled=False, first_seed=None, use_prefix=None):
|
|
||||||
# note the seed is the seed of the current image
|
|
||||||
# the first_seed is the original seed that noise is added to
|
|
||||||
# when the -v switch is used to generate variations
|
|
||||||
nonlocal prior_variations
|
|
||||||
nonlocal prefix
|
|
||||||
if use_prefix is not None:
|
|
||||||
prefix = use_prefix
|
|
||||||
|
|
||||||
path = None
|
|
||||||
if opt.grid:
|
|
||||||
grid_images[seed] = image
|
|
||||||
else:
|
|
||||||
postprocessed = upscaled if upscaled else operation=='postprocess'
|
|
||||||
filename, formatted_dream_prompt = prepare_image_metadata(
|
|
||||||
opt,
|
|
||||||
prefix,
|
|
||||||
seed,
|
|
||||||
operation,
|
|
||||||
prior_variations,
|
|
||||||
postprocessed,
|
|
||||||
first_seed
|
|
||||||
)
|
|
||||||
path = file_writer.save_image_and_prompt_to_png(
|
|
||||||
image = image,
|
|
||||||
dream_prompt = formatted_dream_prompt,
|
|
||||||
metadata = metadata_dumps(
|
|
||||||
opt,
|
|
||||||
seeds = [seed if opt.variation_amount==0 and len(prior_variations)==0 else first_seed],
|
|
||||||
model_hash = gen.model_hash,
|
|
||||||
),
|
|
||||||
name = filename,
|
|
||||||
)
|
|
||||||
|
|
||||||
# update rfc metadata
|
|
||||||
if operation == 'postprocess':
|
|
||||||
tool = re.match('postprocess:(\w+)',opt.last_operation).groups()[0]
|
|
||||||
add_postprocessing_to_metadata(
|
|
||||||
opt,
|
|
||||||
opt.prompt,
|
|
||||||
filename,
|
|
||||||
tool,
|
|
||||||
formatted_dream_prompt,
|
|
||||||
)
|
|
||||||
|
|
||||||
if (not postprocessed) or opt.save_original:
|
|
||||||
# only append to results if we didn't overwrite an earlier output
|
|
||||||
results.append([path, formatted_dream_prompt])
|
|
||||||
|
|
||||||
# so that the seed autocompletes (on linux|mac when -S or --seed specified
|
|
||||||
if completer:
|
|
||||||
completer.add_seed(seed)
|
|
||||||
completer.add_seed(first_seed)
|
|
||||||
last_results.append([path, seed])
|
|
||||||
|
|
||||||
if operation == 'generate':
|
|
||||||
catch_ctrl_c = infile is None # if running interactively, we catch keyboard interrupts
|
|
||||||
opt.last_operation='generate'
|
|
||||||
gen.prompt2image(
|
|
||||||
image_callback=image_writer,
|
|
||||||
catch_interrupts=catch_ctrl_c,
|
|
||||||
**vars(opt)
|
|
||||||
)
|
|
||||||
elif operation == 'postprocess':
|
|
||||||
print(f'>> fixing {opt.prompt}')
|
|
||||||
opt.last_operation = do_postprocess(gen,opt,image_writer)
|
|
||||||
|
|
||||||
if opt.grid and len(grid_images) > 0:
|
|
||||||
grid_img = make_grid(list(grid_images.values()))
|
|
||||||
grid_seeds = list(grid_images.keys())
|
|
||||||
first_seed = last_results[0][1]
|
|
||||||
filename = f'{prefix}.{first_seed}.png'
|
|
||||||
formatted_dream_prompt = opt.dream_prompt_str(seed=first_seed,grid=True,iterations=len(grid_images))
|
|
||||||
formatted_dream_prompt += f' # {grid_seeds}'
|
|
||||||
metadata = metadata_dumps(
|
|
||||||
opt,
|
|
||||||
seeds = grid_seeds,
|
|
||||||
model_hash = gen.model_hash
|
|
||||||
)
|
|
||||||
path = file_writer.save_image_and_prompt_to_png(
|
|
||||||
image = grid_img,
|
|
||||||
dream_prompt = formatted_dream_prompt,
|
|
||||||
metadata = metadata,
|
|
||||||
name = filename
|
|
||||||
)
|
|
||||||
results = [[path, formatted_dream_prompt]]
|
|
||||||
|
|
||||||
except AssertionError as e:
|
|
||||||
print(e)
|
|
||||||
continue
|
|
||||||
|
|
||||||
except OSError as e:
|
|
||||||
print(e)
|
|
||||||
continue
|
|
||||||
|
|
||||||
print('Outputs:')
|
|
||||||
log_path = os.path.join(current_outdir, 'dream_log')
|
|
||||||
output_cntr = write_log(results, log_path ,('txt', 'md'), output_cntr)
|
|
||||||
print()
|
|
||||||
if operation == 'postprocess':
|
|
||||||
completer.add_history(f'!fix {command}')
|
|
||||||
else:
|
|
||||||
completer.add_history(command)
|
|
||||||
|
|
||||||
print('goodbye!')
|
|
||||||
|
|
||||||
def do_postprocess (gen, opt, callback):
|
|
||||||
file_path = opt.prompt # treat the prompt as the file pathname
|
|
||||||
if os.path.dirname(file_path) == '': #basename given
|
|
||||||
file_path = os.path.join(opt.outdir,file_path)
|
|
||||||
|
|
||||||
tool=None
|
|
||||||
if opt.gfpgan_strength > 0:
|
|
||||||
tool = opt.facetool
|
|
||||||
elif opt.embiggen:
|
|
||||||
tool = 'embiggen'
|
|
||||||
elif opt.upscale:
|
|
||||||
tool = 'upscale'
|
|
||||||
elif opt.out_direction:
|
|
||||||
tool = 'outpaint'
|
|
||||||
elif opt.outcrop:
|
|
||||||
tool = 'outcrop'
|
|
||||||
opt.save_original = True # do not overwrite old image!
|
|
||||||
opt.last_operation = f'postprocess:{tool}'
|
|
||||||
try:
|
|
||||||
gen.apply_postprocessor(
|
|
||||||
image_path = file_path,
|
|
||||||
tool = tool,
|
|
||||||
gfpgan_strength = opt.gfpgan_strength,
|
|
||||||
codeformer_fidelity = opt.codeformer_fidelity,
|
|
||||||
save_original = opt.save_original,
|
|
||||||
upscale = opt.upscale,
|
|
||||||
out_direction = opt.out_direction,
|
|
||||||
outcrop = opt.outcrop,
|
|
||||||
callback = callback,
|
|
||||||
opt = opt,
|
|
||||||
)
|
|
||||||
except OSError:
|
|
||||||
print(f'** {file_path}: file could not be read')
|
|
||||||
return
|
|
||||||
except (KeyError, AttributeError):
|
|
||||||
print(traceback.format_exc(), file=sys.stderr)
|
|
||||||
return
|
|
||||||
return opt.last_operation
|
|
||||||
|
|
||||||
def add_postprocessing_to_metadata(opt,original_file,new_file,tool,command):
|
|
||||||
original_file = original_file if os.path.exists(original_file) else os.path.join(opt.outdir,original_file)
|
|
||||||
new_file = new_file if os.path.exists(new_file) else os.path.join(opt.outdir,new_file)
|
|
||||||
meta = retrieve_metadata(original_file)['sd-metadata']
|
|
||||||
img_data = meta['image']
|
|
||||||
pp = img_data.get('postprocessing',[]) or []
|
|
||||||
pp.append(
|
|
||||||
{
|
|
||||||
'tool':tool,
|
|
||||||
'dream_command':command,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
meta['image']['postprocessing'] = pp
|
|
||||||
write_metadata(new_file,meta)
|
|
||||||
|
|
||||||
def prepare_image_metadata(
|
|
||||||
opt,
|
|
||||||
prefix,
|
|
||||||
seed,
|
|
||||||
operation='generate',
|
|
||||||
prior_variations=[],
|
|
||||||
postprocessed=False,
|
|
||||||
first_seed=None
|
|
||||||
):
|
|
||||||
|
|
||||||
if postprocessed and opt.save_original:
|
|
||||||
filename = choose_postprocess_name(opt,prefix,seed)
|
|
||||||
else:
|
|
||||||
filename = f'{prefix}.{seed}.png'
|
|
||||||
|
|
||||||
if opt.variation_amount > 0:
|
|
||||||
first_seed = first_seed or seed
|
|
||||||
this_variation = [[seed, opt.variation_amount]]
|
|
||||||
opt.with_variations = prior_variations + this_variation
|
|
||||||
formatted_dream_prompt = opt.dream_prompt_str(seed=first_seed)
|
|
||||||
elif len(prior_variations) > 0:
|
|
||||||
formatted_dream_prompt = opt.dream_prompt_str(seed=first_seed)
|
|
||||||
elif operation == 'postprocess':
|
|
||||||
formatted_dream_prompt = '!fix '+opt.dream_prompt_str(seed=seed)
|
|
||||||
else:
|
|
||||||
formatted_dream_prompt = opt.dream_prompt_str(seed=seed)
|
|
||||||
return filename,formatted_dream_prompt
|
|
||||||
|
|
||||||
def choose_postprocess_name(opt,prefix,seed) -> str:
|
|
||||||
match = re.search('postprocess:(\w+)',opt.last_operation)
|
|
||||||
if match:
|
|
||||||
modifier = match.group(1) # will look like "gfpgan", "upscale", "outpaint" or "embiggen"
|
|
||||||
else:
|
|
||||||
modifier = 'postprocessed'
|
|
||||||
|
|
||||||
counter = 0
|
|
||||||
filename = None
|
|
||||||
available = False
|
|
||||||
while not available:
|
|
||||||
if counter == 0:
|
|
||||||
filename = f'{prefix}.{seed}.{modifier}.png'
|
|
||||||
else:
|
|
||||||
filename = f'{prefix}.{seed}.{modifier}-{counter:02d}.png'
|
|
||||||
available = not os.path.exists(os.path.join(opt.outdir,filename))
|
|
||||||
counter += 1
|
|
||||||
return filename
|
|
||||||
|
|
||||||
def get_next_command(infile=None) -> str: # command string
|
|
||||||
if infile is None:
|
|
||||||
command = input('dream> ')
|
|
||||||
else:
|
|
||||||
command = infile.readline()
|
|
||||||
if not command:
|
|
||||||
raise EOFError
|
|
||||||
else:
|
|
||||||
command = command.strip()
|
|
||||||
if len(command)>0:
|
|
||||||
print(f'#{command}')
|
|
||||||
return command
|
|
||||||
|
|
||||||
def invoke_ai_web_server_loop(gen, gfpgan, codeformer, esrgan):
|
|
||||||
print('\n* --web was specified, starting web server...')
|
|
||||||
# Change working directory to the stable-diffusion directory
|
|
||||||
os.chdir(
|
|
||||||
os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
|
|
||||||
)
|
|
||||||
|
|
||||||
invoke_ai_web_server = InvokeAIWebServer(generate=gen, gfpgan=gfpgan, codeformer=codeformer, esrgan=esrgan)
|
|
||||||
|
|
||||||
try:
|
|
||||||
invoke_ai_web_server.run()
|
|
||||||
except KeyboardInterrupt:
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
def split_variations(variations_string) -> list:
|
|
||||||
# shotgun parsing, woo
|
|
||||||
parts = []
|
|
||||||
broken = False # python doesn't have labeled loops...
|
|
||||||
for part in variations_string.split(','):
|
|
||||||
seed_and_weight = part.split(':')
|
|
||||||
if len(seed_and_weight) != 2:
|
|
||||||
print(f'** Could not parse with_variation part "{part}"')
|
|
||||||
broken = True
|
|
||||||
break
|
|
||||||
try:
|
|
||||||
seed = int(seed_and_weight[0])
|
|
||||||
weight = float(seed_and_weight[1])
|
|
||||||
except ValueError:
|
|
||||||
print(f'** Could not parse with_variation part "{part}"')
|
|
||||||
broken = True
|
|
||||||
break
|
|
||||||
parts.append([seed, weight])
|
|
||||||
if broken:
|
|
||||||
return None
|
|
||||||
elif len(parts) == 0:
|
|
||||||
return None
|
|
||||||
else:
|
|
||||||
return parts
|
|
||||||
|
|
||||||
def retrieve_dream_command(opt,file_path,completer):
|
|
||||||
'''
|
|
||||||
Given a full or partial path to a previously-generated image file,
|
|
||||||
will retrieve and format the dream command used to generate the image,
|
|
||||||
and pop it into the readline buffer (linux, Mac), or print out a comment
|
|
||||||
for cut-and-paste (windows)
|
|
||||||
'''
|
|
||||||
dir,basename = os.path.split(file_path)
|
|
||||||
if len(dir) == 0:
|
|
||||||
path = os.path.join(opt.outdir,basename)
|
|
||||||
else:
|
|
||||||
path = file_path
|
|
||||||
try:
|
|
||||||
cmd = dream_cmd_from_png(path)
|
|
||||||
except OSError:
|
|
||||||
print(f'** {path}: file could not be read')
|
|
||||||
return
|
|
||||||
except (KeyError, AttributeError):
|
|
||||||
print(f'** {path}: file has no metadata')
|
|
||||||
return
|
|
||||||
completer.set_line(cmd)
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
main()
|
|
||||||
|
570
scripts/invoke.py
Normal file
570
scripts/invoke.py
Normal file
@ -0,0 +1,570 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# Copyright (c) 2022 Lincoln D. Stein (https://github.com/lstein)
|
||||||
|
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
import shlex
|
||||||
|
import copy
|
||||||
|
import warnings
|
||||||
|
import time
|
||||||
|
import traceback
|
||||||
|
sys.path.append('.') # corrects a weird problem on Macs
|
||||||
|
from ldm.dream.readline import get_completer
|
||||||
|
from ldm.dream.args import Args, metadata_dumps, metadata_from_png, dream_cmd_from_png
|
||||||
|
from ldm.dream.pngwriter import PngWriter, retrieve_metadata, write_metadata
|
||||||
|
from ldm.dream.image_util import make_grid
|
||||||
|
from ldm.dream.log import write_log
|
||||||
|
from omegaconf import OmegaConf
|
||||||
|
from backend.invoke_ai_web_server import InvokeAIWebServer
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""Initialize command-line parsers and the diffusion model"""
|
||||||
|
opt = Args()
|
||||||
|
args = opt.parse_args()
|
||||||
|
if not args:
|
||||||
|
sys.exit(-1)
|
||||||
|
|
||||||
|
if args.laion400m:
|
||||||
|
print('--laion400m flag has been deprecated. Please use --model laion400m instead.')
|
||||||
|
sys.exit(-1)
|
||||||
|
if args.weights:
|
||||||
|
print('--weights argument has been deprecated. Please edit ./configs/models.yaml, and select the weights using --model instead.')
|
||||||
|
sys.exit(-1)
|
||||||
|
|
||||||
|
print('* Initializing, be patient...\n')
|
||||||
|
from ldm.generate import Generate
|
||||||
|
|
||||||
|
# these two lines prevent a horrible warning message from appearing
|
||||||
|
# when the frozen CLIP tokenizer is imported
|
||||||
|
import transformers
|
||||||
|
transformers.logging.set_verbosity_error()
|
||||||
|
|
||||||
|
# Loading Face Restoration and ESRGAN Modules
|
||||||
|
try:
|
||||||
|
gfpgan, codeformer, esrgan = None, None, None
|
||||||
|
if opt.restore or opt.esrgan:
|
||||||
|
from ldm.dream.restoration import Restoration
|
||||||
|
restoration = Restoration()
|
||||||
|
if opt.restore:
|
||||||
|
gfpgan, codeformer = restoration.load_face_restore_models(opt.gfpgan_dir, opt.gfpgan_model_path)
|
||||||
|
else:
|
||||||
|
print('>> Face restoration disabled')
|
||||||
|
if opt.esrgan:
|
||||||
|
esrgan = restoration.load_esrgan(opt.esrgan_bg_tile)
|
||||||
|
else:
|
||||||
|
print('>> Upscaling disabled')
|
||||||
|
else:
|
||||||
|
print('>> Face restoration and upscaling disabled')
|
||||||
|
except (ModuleNotFoundError, ImportError):
|
||||||
|
print(traceback.format_exc(), file=sys.stderr)
|
||||||
|
print('>> You may need to install the ESRGAN and/or GFPGAN modules')
|
||||||
|
|
||||||
|
# creating a simple text2image object with a handful of
|
||||||
|
# defaults passed on the command line.
|
||||||
|
# additional parameters will be added (or overriden) during
|
||||||
|
# the user input loop
|
||||||
|
try:
|
||||||
|
gen = Generate(
|
||||||
|
conf = opt.conf,
|
||||||
|
model = opt.model,
|
||||||
|
sampler_name = opt.sampler_name,
|
||||||
|
embedding_path = opt.embedding_path,
|
||||||
|
full_precision = opt.full_precision,
|
||||||
|
precision = opt.precision,
|
||||||
|
gfpgan=gfpgan,
|
||||||
|
codeformer=codeformer,
|
||||||
|
esrgan=esrgan,
|
||||||
|
free_gpu_mem=opt.free_gpu_mem,
|
||||||
|
)
|
||||||
|
except (FileNotFoundError, IOError, KeyError) as e:
|
||||||
|
print(f'{e}. Aborting.')
|
||||||
|
sys.exit(-1)
|
||||||
|
|
||||||
|
# make sure the output directory exists
|
||||||
|
if not os.path.exists(opt.outdir):
|
||||||
|
os.makedirs(opt.outdir)
|
||||||
|
|
||||||
|
# load the infile as a list of lines
|
||||||
|
infile = None
|
||||||
|
if opt.infile:
|
||||||
|
try:
|
||||||
|
if os.path.isfile(opt.infile):
|
||||||
|
infile = open(opt.infile, 'r', encoding='utf-8')
|
||||||
|
elif opt.infile == '-': # stdin
|
||||||
|
infile = sys.stdin
|
||||||
|
else:
|
||||||
|
raise FileNotFoundError(f'{opt.infile} not found.')
|
||||||
|
except (FileNotFoundError, IOError) as e:
|
||||||
|
print(f'{e}. Aborting.')
|
||||||
|
sys.exit(-1)
|
||||||
|
|
||||||
|
if opt.seamless:
|
||||||
|
print(">> changed to seamless tiling mode")
|
||||||
|
|
||||||
|
# preload the model
|
||||||
|
gen.load_model()
|
||||||
|
|
||||||
|
# web server loops forever
|
||||||
|
if opt.web or opt.gui:
|
||||||
|
invoke_ai_web_server_loop(gen, gfpgan, codeformer, esrgan)
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
if not infile:
|
||||||
|
print(
|
||||||
|
"\n* Initialization done! Awaiting your command (-h for help, 'q' to quit)"
|
||||||
|
)
|
||||||
|
|
||||||
|
main_loop(gen, opt, infile)
|
||||||
|
|
||||||
|
# TODO: main_loop() has gotten busy. Needs to be refactored.
|
||||||
|
def main_loop(gen, opt, infile):
|
||||||
|
"""prompt/read/execute loop"""
|
||||||
|
done = False
|
||||||
|
path_filter = re.compile(r'[<>:"/\\|?*]')
|
||||||
|
last_results = list()
|
||||||
|
model_config = OmegaConf.load(opt.conf)[opt.model]
|
||||||
|
|
||||||
|
# The readline completer reads history from the .dream_history file located in the
|
||||||
|
# output directory specified at the time of script launch. We do not currently support
|
||||||
|
# changing the history file midstream when the output directory is changed.
|
||||||
|
completer = get_completer(opt)
|
||||||
|
output_cntr = completer.get_current_history_length()+1
|
||||||
|
|
||||||
|
# os.pathconf is not available on Windows
|
||||||
|
if hasattr(os, 'pathconf'):
|
||||||
|
path_max = os.pathconf(opt.outdir, 'PC_PATH_MAX')
|
||||||
|
name_max = os.pathconf(opt.outdir, 'PC_NAME_MAX')
|
||||||
|
else:
|
||||||
|
path_max = 260
|
||||||
|
name_max = 255
|
||||||
|
|
||||||
|
while not done:
|
||||||
|
operation = 'generate' # default operation, alternative is 'postprocess'
|
||||||
|
|
||||||
|
if completer:
|
||||||
|
completer.set_default_dir(opt.outdir)
|
||||||
|
|
||||||
|
try:
|
||||||
|
command = get_next_command(infile)
|
||||||
|
except EOFError:
|
||||||
|
done = True
|
||||||
|
continue
|
||||||
|
|
||||||
|
# skip empty lines
|
||||||
|
if not command.strip():
|
||||||
|
continue
|
||||||
|
|
||||||
|
if command.startswith(('#', '//')):
|
||||||
|
continue
|
||||||
|
|
||||||
|
if len(command.strip()) == 1 and command.startswith('q'):
|
||||||
|
done = True
|
||||||
|
break
|
||||||
|
|
||||||
|
if command.startswith('!'):
|
||||||
|
subcommand = command[1:]
|
||||||
|
|
||||||
|
if subcommand.startswith('dream'): # in case a stored prompt still contains the !dream command
|
||||||
|
command = command.replace('!dream ','',1)
|
||||||
|
|
||||||
|
elif subcommand.startswith('fix'):
|
||||||
|
command = command.replace('!fix ','',1)
|
||||||
|
operation = 'postprocess'
|
||||||
|
|
||||||
|
elif subcommand.startswith('fetch'):
|
||||||
|
file_path = command.replace('!fetch ','',1)
|
||||||
|
retrieve_dream_command(opt,file_path,completer)
|
||||||
|
continue
|
||||||
|
|
||||||
|
elif subcommand.startswith('history'):
|
||||||
|
completer.show_history()
|
||||||
|
continue
|
||||||
|
|
||||||
|
elif subcommand.startswith('search'):
|
||||||
|
search_str = command.replace('!search ','',1)
|
||||||
|
completer.show_history(search_str)
|
||||||
|
continue
|
||||||
|
|
||||||
|
elif subcommand.startswith('clear'):
|
||||||
|
completer.clear_history()
|
||||||
|
continue
|
||||||
|
|
||||||
|
elif re.match('^(\d+)',subcommand):
|
||||||
|
command_no = re.match('^(\d+)',subcommand).groups()[0]
|
||||||
|
command = completer.get_line(int(command_no))
|
||||||
|
completer.set_line(command)
|
||||||
|
continue
|
||||||
|
|
||||||
|
else: # not a recognized subcommand, so give the --help text
|
||||||
|
command = '-h'
|
||||||
|
|
||||||
|
if opt.parse_cmd(command) is None:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if opt.init_img:
|
||||||
|
try:
|
||||||
|
if not opt.prompt:
|
||||||
|
oldargs = metadata_from_png(opt.init_img)
|
||||||
|
opt.prompt = oldargs.prompt
|
||||||
|
print(f'>> Retrieved old prompt "{opt.prompt}" from {opt.init_img}')
|
||||||
|
except (OSError, AttributeError, KeyError):
|
||||||
|
pass
|
||||||
|
|
||||||
|
if len(opt.prompt) == 0:
|
||||||
|
print('\nTry again with a prompt!')
|
||||||
|
continue
|
||||||
|
|
||||||
|
# width and height are set by model if not specified
|
||||||
|
if not opt.width:
|
||||||
|
opt.width = model_config.width
|
||||||
|
if not opt.height:
|
||||||
|
opt.height = model_config.height
|
||||||
|
|
||||||
|
# retrieve previous value of init image if requested
|
||||||
|
if opt.init_img is not None and re.match('^-\\d+$', opt.init_img):
|
||||||
|
try:
|
||||||
|
opt.init_img = last_results[int(opt.init_img)][0]
|
||||||
|
print(f'>> Reusing previous image {opt.init_img}')
|
||||||
|
except IndexError:
|
||||||
|
print(
|
||||||
|
f'>> No previous initial image at position {opt.init_img} found')
|
||||||
|
opt.init_img = None
|
||||||
|
continue
|
||||||
|
|
||||||
|
# try to relativize pathnames
|
||||||
|
for attr in ('init_img','init_mask','init_color','embedding_path'):
|
||||||
|
if getattr(opt,attr) and not os.path.exists(getattr(opt,attr)):
|
||||||
|
basename = getattr(opt,attr)
|
||||||
|
path = os.path.join(opt.outdir,basename)
|
||||||
|
setattr(opt,attr,path)
|
||||||
|
|
||||||
|
# retrieve previous value of seed if requested
|
||||||
|
if opt.seed is not None and opt.seed < 0:
|
||||||
|
try:
|
||||||
|
opt.seed = last_results[opt.seed][1]
|
||||||
|
print(f'>> Reusing previous seed {opt.seed}')
|
||||||
|
except IndexError:
|
||||||
|
print(f'>> No previous seed at position {opt.seed} found')
|
||||||
|
opt.seed = None
|
||||||
|
continue
|
||||||
|
|
||||||
|
if opt.strength is None:
|
||||||
|
opt.strength = 0.75 if opt.out_direction is None else 0.83
|
||||||
|
|
||||||
|
if opt.with_variations is not None:
|
||||||
|
opt.with_variations = split_variations(opt.with_variations)
|
||||||
|
|
||||||
|
if opt.prompt_as_dir:
|
||||||
|
# sanitize the prompt to a valid folder name
|
||||||
|
subdir = path_filter.sub('_', opt.prompt)[:name_max].rstrip(' .')
|
||||||
|
|
||||||
|
# truncate path to maximum allowed length
|
||||||
|
# 39 is the length of '######.##########.##########-##.png', plus two separators and a NUL
|
||||||
|
subdir = subdir[:(path_max - 39 - len(os.path.abspath(opt.outdir)))]
|
||||||
|
current_outdir = os.path.join(opt.outdir, subdir)
|
||||||
|
|
||||||
|
print('Writing files to directory: "' + current_outdir + '"')
|
||||||
|
|
||||||
|
# make sure the output directory exists
|
||||||
|
if not os.path.exists(current_outdir):
|
||||||
|
os.makedirs(current_outdir)
|
||||||
|
else:
|
||||||
|
if not os.path.exists(opt.outdir):
|
||||||
|
os.makedirs(opt.outdir)
|
||||||
|
current_outdir = opt.outdir
|
||||||
|
|
||||||
|
# Here is where the images are actually generated!
|
||||||
|
last_results = []
|
||||||
|
try:
|
||||||
|
file_writer = PngWriter(current_outdir)
|
||||||
|
results = [] # list of filename, prompt pairs
|
||||||
|
grid_images = dict() # seed -> Image, only used if `opt.grid`
|
||||||
|
prior_variations = opt.with_variations or []
|
||||||
|
prefix = file_writer.unique_prefix()
|
||||||
|
|
||||||
|
def image_writer(image, seed, upscaled=False, first_seed=None, use_prefix=None):
|
||||||
|
# note the seed is the seed of the current image
|
||||||
|
# the first_seed is the original seed that noise is added to
|
||||||
|
# when the -v switch is used to generate variations
|
||||||
|
nonlocal prior_variations
|
||||||
|
nonlocal prefix
|
||||||
|
if use_prefix is not None:
|
||||||
|
prefix = use_prefix
|
||||||
|
|
||||||
|
path = None
|
||||||
|
if opt.grid:
|
||||||
|
grid_images[seed] = image
|
||||||
|
else:
|
||||||
|
postprocessed = upscaled if upscaled else operation=='postprocess'
|
||||||
|
filename, formatted_dream_prompt = prepare_image_metadata(
|
||||||
|
opt,
|
||||||
|
prefix,
|
||||||
|
seed,
|
||||||
|
operation,
|
||||||
|
prior_variations,
|
||||||
|
postprocessed,
|
||||||
|
first_seed
|
||||||
|
)
|
||||||
|
path = file_writer.save_image_and_prompt_to_png(
|
||||||
|
image = image,
|
||||||
|
dream_prompt = formatted_dream_prompt,
|
||||||
|
metadata = metadata_dumps(
|
||||||
|
opt,
|
||||||
|
seeds = [seed if opt.variation_amount==0 and len(prior_variations)==0 else first_seed],
|
||||||
|
model_hash = gen.model_hash,
|
||||||
|
),
|
||||||
|
name = filename,
|
||||||
|
)
|
||||||
|
|
||||||
|
# update rfc metadata
|
||||||
|
if operation == 'postprocess':
|
||||||
|
tool = re.match('postprocess:(\w+)',opt.last_operation).groups()[0]
|
||||||
|
add_postprocessing_to_metadata(
|
||||||
|
opt,
|
||||||
|
opt.prompt,
|
||||||
|
filename,
|
||||||
|
tool,
|
||||||
|
formatted_dream_prompt,
|
||||||
|
)
|
||||||
|
|
||||||
|
if (not postprocessed) or opt.save_original:
|
||||||
|
# only append to results if we didn't overwrite an earlier output
|
||||||
|
results.append([path, formatted_dream_prompt])
|
||||||
|
|
||||||
|
# so that the seed autocompletes (on linux|mac when -S or --seed specified
|
||||||
|
if completer:
|
||||||
|
completer.add_seed(seed)
|
||||||
|
completer.add_seed(first_seed)
|
||||||
|
last_results.append([path, seed])
|
||||||
|
|
||||||
|
if operation == 'generate':
|
||||||
|
catch_ctrl_c = infile is None # if running interactively, we catch keyboard interrupts
|
||||||
|
opt.last_operation='generate'
|
||||||
|
gen.prompt2image(
|
||||||
|
image_callback=image_writer,
|
||||||
|
catch_interrupts=catch_ctrl_c,
|
||||||
|
**vars(opt)
|
||||||
|
)
|
||||||
|
elif operation == 'postprocess':
|
||||||
|
print(f'>> fixing {opt.prompt}')
|
||||||
|
opt.last_operation = do_postprocess(gen,opt,image_writer)
|
||||||
|
|
||||||
|
if opt.grid and len(grid_images) > 0:
|
||||||
|
grid_img = make_grid(list(grid_images.values()))
|
||||||
|
grid_seeds = list(grid_images.keys())
|
||||||
|
first_seed = last_results[0][1]
|
||||||
|
filename = f'{prefix}.{first_seed}.png'
|
||||||
|
formatted_dream_prompt = opt.dream_prompt_str(seed=first_seed,grid=True,iterations=len(grid_images))
|
||||||
|
formatted_dream_prompt += f' # {grid_seeds}'
|
||||||
|
metadata = metadata_dumps(
|
||||||
|
opt,
|
||||||
|
seeds = grid_seeds,
|
||||||
|
model_hash = gen.model_hash
|
||||||
|
)
|
||||||
|
path = file_writer.save_image_and_prompt_to_png(
|
||||||
|
image = grid_img,
|
||||||
|
dream_prompt = formatted_dream_prompt,
|
||||||
|
metadata = metadata,
|
||||||
|
name = filename
|
||||||
|
)
|
||||||
|
results = [[path, formatted_dream_prompt]]
|
||||||
|
|
||||||
|
except AssertionError as e:
|
||||||
|
print(e)
|
||||||
|
continue
|
||||||
|
|
||||||
|
except OSError as e:
|
||||||
|
print(e)
|
||||||
|
continue
|
||||||
|
|
||||||
|
print('Outputs:')
|
||||||
|
log_path = os.path.join(current_outdir, 'dream_log')
|
||||||
|
output_cntr = write_log(results, log_path ,('txt', 'md'), output_cntr)
|
||||||
|
print()
|
||||||
|
if operation == 'postprocess':
|
||||||
|
completer.add_history(f'!fix {command}')
|
||||||
|
else:
|
||||||
|
completer.add_history(command)
|
||||||
|
|
||||||
|
print('goodbye!')
|
||||||
|
|
||||||
|
def do_postprocess (gen, opt, callback):
|
||||||
|
file_path = opt.prompt # treat the prompt as the file pathname
|
||||||
|
if os.path.dirname(file_path) == '': #basename given
|
||||||
|
file_path = os.path.join(opt.outdir,file_path)
|
||||||
|
|
||||||
|
tool=None
|
||||||
|
if opt.gfpgan_strength > 0:
|
||||||
|
tool = opt.facetool
|
||||||
|
elif opt.embiggen:
|
||||||
|
tool = 'embiggen'
|
||||||
|
elif opt.upscale:
|
||||||
|
tool = 'upscale'
|
||||||
|
elif opt.out_direction:
|
||||||
|
tool = 'outpaint'
|
||||||
|
elif opt.outcrop:
|
||||||
|
tool = 'outcrop'
|
||||||
|
opt.save_original = True # do not overwrite old image!
|
||||||
|
opt.last_operation = f'postprocess:{tool}'
|
||||||
|
try:
|
||||||
|
gen.apply_postprocessor(
|
||||||
|
image_path = file_path,
|
||||||
|
tool = tool,
|
||||||
|
gfpgan_strength = opt.gfpgan_strength,
|
||||||
|
codeformer_fidelity = opt.codeformer_fidelity,
|
||||||
|
save_original = opt.save_original,
|
||||||
|
upscale = opt.upscale,
|
||||||
|
out_direction = opt.out_direction,
|
||||||
|
outcrop = opt.outcrop,
|
||||||
|
callback = callback,
|
||||||
|
opt = opt,
|
||||||
|
)
|
||||||
|
except OSError:
|
||||||
|
print(f'** {file_path}: file could not be read')
|
||||||
|
return
|
||||||
|
except (KeyError, AttributeError):
|
||||||
|
print(traceback.format_exc(), file=sys.stderr)
|
||||||
|
return
|
||||||
|
return opt.last_operation
|
||||||
|
|
||||||
|
def add_postprocessing_to_metadata(opt,original_file,new_file,tool,command):
|
||||||
|
original_file = original_file if os.path.exists(original_file) else os.path.join(opt.outdir,original_file)
|
||||||
|
new_file = new_file if os.path.exists(new_file) else os.path.join(opt.outdir,new_file)
|
||||||
|
meta = retrieve_metadata(original_file)['sd-metadata']
|
||||||
|
img_data = meta['image']
|
||||||
|
pp = img_data.get('postprocessing',[]) or []
|
||||||
|
pp.append(
|
||||||
|
{
|
||||||
|
'tool':tool,
|
||||||
|
'dream_command':command,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
meta['image']['postprocessing'] = pp
|
||||||
|
write_metadata(new_file,meta)
|
||||||
|
|
||||||
|
def prepare_image_metadata(
|
||||||
|
opt,
|
||||||
|
prefix,
|
||||||
|
seed,
|
||||||
|
operation='generate',
|
||||||
|
prior_variations=[],
|
||||||
|
postprocessed=False,
|
||||||
|
first_seed=None
|
||||||
|
):
|
||||||
|
|
||||||
|
if postprocessed and opt.save_original:
|
||||||
|
filename = choose_postprocess_name(opt,prefix,seed)
|
||||||
|
else:
|
||||||
|
filename = f'{prefix}.{seed}.png'
|
||||||
|
|
||||||
|
if opt.variation_amount > 0:
|
||||||
|
first_seed = first_seed or seed
|
||||||
|
this_variation = [[seed, opt.variation_amount]]
|
||||||
|
opt.with_variations = prior_variations + this_variation
|
||||||
|
formatted_dream_prompt = opt.dream_prompt_str(seed=first_seed)
|
||||||
|
elif len(prior_variations) > 0:
|
||||||
|
formatted_dream_prompt = opt.dream_prompt_str(seed=first_seed)
|
||||||
|
elif operation == 'postprocess':
|
||||||
|
formatted_dream_prompt = '!fix '+opt.dream_prompt_str(seed=seed)
|
||||||
|
else:
|
||||||
|
formatted_dream_prompt = opt.dream_prompt_str(seed=seed)
|
||||||
|
return filename,formatted_dream_prompt
|
||||||
|
|
||||||
|
def choose_postprocess_name(opt,prefix,seed) -> str:
|
||||||
|
match = re.search('postprocess:(\w+)',opt.last_operation)
|
||||||
|
if match:
|
||||||
|
modifier = match.group(1) # will look like "gfpgan", "upscale", "outpaint" or "embiggen"
|
||||||
|
else:
|
||||||
|
modifier = 'postprocessed'
|
||||||
|
|
||||||
|
counter = 0
|
||||||
|
filename = None
|
||||||
|
available = False
|
||||||
|
while not available:
|
||||||
|
if counter == 0:
|
||||||
|
filename = f'{prefix}.{seed}.{modifier}.png'
|
||||||
|
else:
|
||||||
|
filename = f'{prefix}.{seed}.{modifier}-{counter:02d}.png'
|
||||||
|
available = not os.path.exists(os.path.join(opt.outdir,filename))
|
||||||
|
counter += 1
|
||||||
|
return filename
|
||||||
|
|
||||||
|
def get_next_command(infile=None) -> str: # command string
|
||||||
|
if infile is None:
|
||||||
|
command = input('invoke> ')
|
||||||
|
else:
|
||||||
|
command = infile.readline()
|
||||||
|
if not command:
|
||||||
|
raise EOFError
|
||||||
|
else:
|
||||||
|
command = command.strip()
|
||||||
|
if len(command)>0:
|
||||||
|
print(f'#{command}')
|
||||||
|
return command
|
||||||
|
|
||||||
|
def invoke_ai_web_server_loop(gen, gfpgan, codeformer, esrgan):
|
||||||
|
print('\n* --web was specified, starting web server...')
|
||||||
|
# Change working directory to the stable-diffusion directory
|
||||||
|
os.chdir(
|
||||||
|
os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
|
||||||
|
)
|
||||||
|
|
||||||
|
invoke_ai_web_server = InvokeAIWebServer(generate=gen, gfpgan=gfpgan, codeformer=codeformer, esrgan=esrgan)
|
||||||
|
|
||||||
|
try:
|
||||||
|
invoke_ai_web_server.run()
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def split_variations(variations_string) -> list:
|
||||||
|
# shotgun parsing, woo
|
||||||
|
parts = []
|
||||||
|
broken = False # python doesn't have labeled loops...
|
||||||
|
for part in variations_string.split(','):
|
||||||
|
seed_and_weight = part.split(':')
|
||||||
|
if len(seed_and_weight) != 2:
|
||||||
|
print(f'** Could not parse with_variation part "{part}"')
|
||||||
|
broken = True
|
||||||
|
break
|
||||||
|
try:
|
||||||
|
seed = int(seed_and_weight[0])
|
||||||
|
weight = float(seed_and_weight[1])
|
||||||
|
except ValueError:
|
||||||
|
print(f'** Could not parse with_variation part "{part}"')
|
||||||
|
broken = True
|
||||||
|
break
|
||||||
|
parts.append([seed, weight])
|
||||||
|
if broken:
|
||||||
|
return None
|
||||||
|
elif len(parts) == 0:
|
||||||
|
return None
|
||||||
|
else:
|
||||||
|
return parts
|
||||||
|
|
||||||
|
def retrieve_dream_command(opt,file_path,completer):
|
||||||
|
'''
|
||||||
|
Given a full or partial path to a previously-generated image file,
|
||||||
|
will retrieve and format the dream command used to generate the image,
|
||||||
|
and pop it into the readline buffer (linux, Mac), or print out a comment
|
||||||
|
for cut-and-paste (windows)
|
||||||
|
'''
|
||||||
|
dir,basename = os.path.split(file_path)
|
||||||
|
if len(dir) == 0:
|
||||||
|
path = os.path.join(opt.outdir,basename)
|
||||||
|
else:
|
||||||
|
path = file_path
|
||||||
|
try:
|
||||||
|
cmd = dream_cmd_from_png(path)
|
||||||
|
except OSError:
|
||||||
|
print(f'** {path}: file could not be read')
|
||||||
|
return
|
||||||
|
except (KeyError, AttributeError):
|
||||||
|
print(f'** {path}: file has no metadata')
|
||||||
|
return
|
||||||
|
completer.set_line(cmd)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
Loading…
x
Reference in New Issue
Block a user