Compare commits

...
41 Commits
Author SHA1 Message Date
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> ae05379cc9 ci: bump actions/checkout from 4 to 5 (#4085)
Bumps [actions/checkout](https://github.com/actions/checkout) from 4 to 5.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-09-02 22:28:40 +02:00
Marvin M 59f183ab9b Fix: Readme path (#3841)
* Readme path fix

* fix '/' -> '\'
2025-01-24 11:55:35 +01:00
Manuel Schmid 4b5021f8f6 docs: remove link to SimpleSDXL (#3837)
see https://github.com/lllyasviel/Fooocus/issues/3836
2025-01-14 06:14:45 +01:00
lllyasviel d7439b2d60 Update readme.md 2024-08-18 23:02:09 -07:00
lllyasviel 670d798332 Update Project Status 2024-08-18 22:42:25 -07:00
Manuel Schmid 8da1d3ff68 Merge pull request #3507 from lllyasviel/develop
Release 2.5.5
2024-08-12 08:11:06 +02:00
Manuel Schmid 710a9fa2c5 release: bump version to 2.5.5, update changelog 2024-08-12 08:10:20 +02:00
Manuel Schmid 251a130f06 fix: move import to resolve colab issue (#3506) 2024-08-12 07:59:00 +02:00
Manuel Schmid 0a87da7dc1 Merge pull request #3503 from lllyasviel/develop
feat: change code owner from @mashb1t to @lllyasviel
2024-08-11 20:31:05 +02:00
Manuel Schmid 1d98d1c760 feat: change code owner from @mashb1t to @lllyasviel 2024-08-11 20:29:35 +02:00
Manuel Schmid 1068d3fde4 Merge pull request #3499 from lllyasviel/develop
Release 2.5.4
2024-08-11 18:50:18 +02:00
Manuel Schmid 082a5262b0 release: bump version to 2.5.4, update changelog 2024-08-11 18:48:31 +02:00
Manuel Schmid 14895ebb13 hotfix: yield enhance_input_image to correctly preview debug masks (#3497)
sort images starts from index <images_to_enhance_count>, which is 1 if enhance_input_image has been provided
2024-08-11 17:05:24 +02:00
Manuel Schmid b0d16a3aa7 fix: check all dirs instead of only the first one (#3495)
* fix: check all checkpoint dirs instead of only the first one for models

* fix: use get_file_from_folder_list instead of manually iterating over lists

* refactor: code cleanup
2024-08-11 15:31:24 +02:00
Manuel Schmid fd74b57f56 Merge pull request #3472 from lllyasviel/develop
fix: adjust validation of config settings
2024-08-08 13:17:06 +02:00
Manuel Schmid 8bd9ea1dbf fix: correctly validate default_inpaint_mask_sam_model 2024-08-08 13:15:15 +02:00
Manuel Schmid ee12d114c1 fix: add handling for default "None" value of default_ip_image_* 2024-08-08 13:15:04 +02:00
Manuel Schmid 2c78cec01d Merge pull request #3436 from lllyasviel/develop
fix: change wrong label for in describe apply styles checkbox
2024-08-03 15:18:24 +02:00
Manuel Schmid ef0acca9f9 fix: change wrong label for in describe apply styles checkbox 2024-08-03 15:16:18 +02:00
Manuel Schmid 60af8d2d84 Merge pull request #3434 from lllyasviel/develop
Release 2.5.3 - fix changelog
2024-08-03 15:11:35 +02:00
Manuel Schmid 39d07bf0f3 release: fix changelog 2024-08-03 15:10:27 +02:00
Manuel Schmid f0dcf5a911 Merge pull request #3433 from lllyasviel/develop
Release 2.5.3
2024-08-03 15:08:34 +02:00
Manuel Schmid c4d5b160be release: bump version to 2.5.3, update changelog 2024-08-03 15:07:14 +02:00
Manuel Schmid 2f08cb4360 feat: add checkbox and config to disable updating selected styles when describing an image (#3430)
* feat: add checkbox and config to disable updating selected styles when describing an image

* i18n: add translation for checkbox label

* feat: change describe content type from Radio to CheckboxGroup, add config

* fix: cast set to list when styles contains elements

* feat: sort styles after describe
2024-08-03 14:46:31 +02:00
Sergii DymchenkoandManuel Schmid da3d4d006f Use weights_only for loading (#3427)
Co-authored-by: Manuel Schmid <9307310+mashb1t@users.noreply.github.com>
2024-08-03 12:33:01 +02:00
Manuel Schmid c2dc17e883 Merge pull request #3384 from lllyasviel/develop
Release v2.5.2
2024-07-27 23:29:40 +02:00
Manuel Schmid 1a53e0676a release: bump version to 2.5.2, update changelog 2024-07-27 23:26:42 +02:00
Manuel Schmid a5040f6218 feat: count image count index from 1 (#3383)
* docs: update numbering of basic debug procedure in issue template
2024-07-27 23:07:44 +02:00
Manuel Schmid 3f25b885a7 feat: extend config settings for image input (#3382)
* docs: update numbering of basic debug procedure in issue template

* feat: add config default_image_prompt_checkbox

* feat: add config for default_image_prompt_advanced_checkbox

* feat: add config for default_inpaint_advanced_masking_checkbox

* feat: add config for default_invert_mask_checkbox

* feat: add config for default_developer_debug_mode_checkbox

* refactor: regroup checkbox configs

* feat: add config for default_uov_method

* feat: add configs for controlnet

default_controlnet_image_count, ip_images, ip_stop_ats, ip_weights and ip_types

* feat: add config for selected tab, rename desc to describe
2024-07-27 23:03:21 +02:00
Manuel Schmid e36fa0b5f7 docs: update numbering of basic debug procedure in issue template (#3376) 2024-07-27 13:14:44 +02:00
Manuel Schmid 1be3c504ed fix: add positive prompt if styles don't have a prompt placeholder (#3372)
fixes https://github.com/lllyasviel/Fooocus/issues/3367
2024-07-27 12:35:55 +02:00
Manuel Schmid c4ce2ce600 Merge pull request #3359 from lllyasviel/develop
Release v2.5.1
2024-07-25 16:00:08 +02:00
Manuel Schmid 03655fa5ea release: bump version to 2.5.1, update changelog 2024-07-25 15:22:02 +02:00
Manuel Schmid a9248c8e46 feat: sort enhance images (mashb1t#62)
* feat: add checkbox, config and handling for saving only the final enhanced image

* feat: sort output of enhance feature

(cherry picked from commit 9d45c0e6ca)
2024-07-25 15:21:56 +02:00
Manuel Schmid 37360e95fe feat: add checkbox, config and handling for saving only the final enhanced image (mashb1t#61)
(cherry picked from commit 829a6dc046)
2024-07-25 15:21:37 +02:00
Manuel Schmid 54985596e8 Merge remote-tracking branch 'upstream/main' into develop_upstream 2024-07-21 12:37:07 +02:00
Manuel Schmid 3a20e14ca0 docs: update attributes and add add inline prompt features section to readme (#3333)
* docs: update attributes and add add inline prompt features section to readme
* docs: update attributes to better show corresponding mutually exclusive groups
2024-07-21 12:36:54 +02:00
Manuel Schmid 2262061145 docs: update attributes to better show corresponding mutually exclusive groups 2024-07-21 12:36:04 +02:00
Manuel Schmid 56928b769b docs: update attributes and add add inline prompt features section to readme 2024-07-21 12:31:17 +02:00
Manuel Schmid 2e8cff296e fix: correctly debug preprocessor again (#3332)
fixes https://github.com/lllyasviel/Fooocus/issues/3327
as discussed in https://github.com/lllyasviel/Fooocus/discussions/3323

add missing inheritance for EarlyReturnException from BaseException to correctly throw and catch
2024-07-21 11:49:28 +02:00
Manuel Schmid f597bf1ab6 fix: allow reading of metadata from jpeg, jpg and webp again (#3301)
also massively improves metadata read speed by switching from filepath (tempfile) to pil, which allows direct processing
2024-07-17 23:30:51 +02:00
30 changed files with 446 additions and 184 deletions
+1 -1
View File
@@ -1 +1 @@
* @mashb1t * @lllyasviel
+3 -3
View File
@@ -16,9 +16,9 @@ body:
description: | description: |
Please perform basic debugging to see if your configuration is the cause of the issue. Please perform basic debugging to see if your configuration is the cause of the issue.
Basic debug procedure Basic debug procedure
 2. Update Fooocus - sometimes things just need to be updated  1. Update Fooocus - sometimes things just need to be updated
 3. Backup and remove your config.txt - check if the issue is caused by bad configuration  2. Backup and remove your config.txt - check if the issue is caused by bad configuration
 5. Try a fresh installation of Fooocus in a different directory - see if a clean installation solves the issue  3. Try a fresh installation of Fooocus in a different directory - see if a clean installation solves the issue
Before making a issue report please, check that the issue hasn't been reported recently. Before making a issue report please, check that the issue hasn't been reported recently.
options: options:
- label: The issue has not been resolved by following the [troubleshooting guide](https://github.com/lllyasviel/Fooocus/blob/main/troubleshoot.md) - label: The issue has not been resolved by following the [troubleshooting guide](https://github.com/lllyasviel/Fooocus/blob/main/troubleshoot.md)
+1 -1
View File
@@ -17,7 +17,7 @@ jobs:
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v4 uses: actions/checkout@v5
- name: Log in to the Container registry - name: Log in to the Container registry
uses: docker/login-action@v3 uses: docker/login-action@v3
+4 -1
View File
@@ -17,7 +17,7 @@ args_parser.parser.add_argument("--disable-offload-from-vram", action="store_tru
args_parser.parser.add_argument("--theme", type=str, help="launches the UI with light or dark theme", default=None) args_parser.parser.add_argument("--theme", type=str, help="launches the UI with light or dark theme", default=None)
args_parser.parser.add_argument("--disable-image-log", action='store_true', args_parser.parser.add_argument("--disable-image-log", action='store_true',
help="Prevent writing images and logs to hard drive.") help="Prevent writing images and logs to the outputs folder.")
args_parser.parser.add_argument("--disable-analytics", action='store_true', args_parser.parser.add_argument("--disable-analytics", action='store_true',
help="Disables analytics for Gradio.") help="Disables analytics for Gradio.")
@@ -28,6 +28,9 @@ args_parser.parser.add_argument("--disable-metadata", action='store_true',
args_parser.parser.add_argument("--disable-preset-download", action='store_true', args_parser.parser.add_argument("--disable-preset-download", action='store_true',
help="Disables downloading models for presets", default=False) help="Disables downloading models for presets", default=False)
args_parser.parser.add_argument("--disable-enhance-output-sorting", action='store_true',
help="Disables enhance output sorting for final image gallery.")
args_parser.parser.add_argument("--enable-auto-describe-image", action='store_true', args_parser.parser.add_argument("--enable-auto-describe-image", action='store_true',
help="Enables automatic description of uov and enhance image when prompt is empty", default=False) help="Enables automatic description of uov and enhance image when prompt is empty", default=False)
+2 -2
View File
@@ -216,9 +216,9 @@ def is_url(url_or_filename):
def load_checkpoint(model,url_or_filename): def load_checkpoint(model,url_or_filename):
if is_url(url_or_filename): if is_url(url_or_filename):
cached_file = download_cached_file(url_or_filename, check_hash=False, progress=True) cached_file = download_cached_file(url_or_filename, check_hash=False, progress=True)
checkpoint = torch.load(cached_file, map_location='cpu') checkpoint = torch.load(cached_file, map_location='cpu', weights_only=True)
elif os.path.isfile(url_or_filename): elif os.path.isfile(url_or_filename):
checkpoint = torch.load(url_or_filename, map_location='cpu') checkpoint = torch.load(url_or_filename, map_location='cpu', weights_only=True)
else: else:
raise RuntimeError('checkpoint url or path is invalid') raise RuntimeError('checkpoint url or path is invalid')
+2 -2
View File
@@ -78,9 +78,9 @@ def blip_nlvr(pretrained='',**kwargs):
def load_checkpoint(model,url_or_filename): def load_checkpoint(model,url_or_filename):
if is_url(url_or_filename): if is_url(url_or_filename):
cached_file = download_cached_file(url_or_filename, check_hash=False, progress=True) cached_file = download_cached_file(url_or_filename, check_hash=False, progress=True)
checkpoint = torch.load(cached_file, map_location='cpu') checkpoint = torch.load(cached_file, map_location='cpu', weights_only=True)
elif os.path.isfile(url_or_filename): elif os.path.isfile(url_or_filename):
checkpoint = torch.load(url_or_filename, map_location='cpu') checkpoint = torch.load(url_or_filename, map_location='cpu', weights_only=True)
else: else:
raise RuntimeError('checkpoint url or path is invalid') raise RuntimeError('checkpoint url or path is invalid')
state_dict = checkpoint['model'] state_dict = checkpoint['model']
+1 -1
View File
@@ -19,7 +19,7 @@ def init_detection_model(model_name, half=False, device='cuda', model_rootpath=N
url=model_url, model_dir='facexlib/weights', progress=True, file_name=None, save_dir=model_rootpath) url=model_url, model_dir='facexlib/weights', progress=True, file_name=None, save_dir=model_rootpath)
# TODO: clean pretrained model # TODO: clean pretrained model
load_net = torch.load(model_path, map_location=lambda storage, loc: storage) load_net = torch.load(model_path, map_location=lambda storage, loc: storage, weights_only=True)
# remove unnecessary 'module.' # remove unnecessary 'module.'
for k, v in deepcopy(load_net).items(): for k, v in deepcopy(load_net).items():
if k.startswith('module.'): if k.startswith('module.'):
+1 -1
View File
@@ -17,7 +17,7 @@ def init_parsing_model(model_name='bisenet', half=False, device='cuda', model_ro
model_path = load_file_from_url( model_path = load_file_from_url(
url=model_url, model_dir='facexlib/weights', progress=True, file_name=None, save_dir=model_rootpath) url=model_url, model_dir='facexlib/weights', progress=True, file_name=None, save_dir=model_rootpath)
load_net = torch.load(model_path, map_location=lambda storage, loc: storage) load_net = torch.load(model_path, map_location=lambda storage, loc: storage, weights_only=True)
model.load_state_dict(load_net, strict=True) model.load_state_dict(load_net, strict=True)
model.eval() model.eval()
model = model.to(device) model = model.to(device)
+1 -1
View File
@@ -104,7 +104,7 @@ def load_ip_adapter(clip_vision_path, ip_negative_path, ip_adapter_path):
offload_device = torch.device('cpu') offload_device = torch.device('cpu')
use_fp16 = model_management.should_use_fp16(device=load_device) use_fp16 = model_management.should_use_fp16(device=load_device)
ip_state_dict = torch.load(ip_adapter_path, map_location="cpu") ip_state_dict = torch.load(ip_adapter_path, map_location="cpu", weights_only=True)
plus = "latents" in ip_state_dict["image_proj"] plus = "latents" in ip_state_dict["image_proj"]
cross_attention_dim = ip_state_dict["ip_adapter"]["1.to_k_ip.weight"].shape[1] cross_attention_dim = ip_state_dict["ip_adapter"]["1.to_k_ip.weight"].shape[1]
sdxl = cross_attention_dim == 2048 sdxl = cross_attention_dim == 2048
+1 -1
View File
@@ -1 +1 @@
version = '2.5.0' version = '2.5.5'
+4
View File
@@ -17,6 +17,7 @@
"Content Type": "Content Type", "Content Type": "Content Type",
"Photograph": "Photograph", "Photograph": "Photograph",
"Art/Anime": "Art/Anime", "Art/Anime": "Art/Anime",
"Apply Styles": "Apply Styles",
"Describe this Image into Prompt": "Describe this Image into Prompt", "Describe this Image into Prompt": "Describe this Image into Prompt",
"Image Size and Recommended Size": "Image Size and Recommended Size", "Image Size and Recommended Size": "Image Size and Recommended Size",
"Upscale or Variation:": "Upscale or Variation:", "Upscale or Variation:": "Upscale or Variation:",
@@ -68,6 +69,9 @@
"Read wildcards in order": "Read wildcards in order", "Read wildcards in order": "Read wildcards in order",
"Black Out NSFW": "Black Out NSFW", "Black Out NSFW": "Black Out NSFW",
"Use black image if NSFW is detected.": "Use black image if NSFW is detected.", "Use black image if NSFW is detected.": "Use black image if NSFW is detected.",
"Save only final enhanced image": "Save only final enhanced image",
"Save Metadata to Images": "Save Metadata to Images",
"Adds parameters to generated images allowing manual regeneration.": "Adds parameters to generated images allowing manual regeneration.",
"\ud83d\udcda History Log": "\uD83D\uDCDA History Log", "\ud83d\udcda History Log": "\uD83D\uDCDA History Log",
"Image Style": "Image Style", "Image Style": "Image Style",
"Fooocus V2": "Fooocus V2", "Fooocus V2": "Fooocus V2",
+10 -5
View File
@@ -80,12 +80,13 @@ if args.gpu_device_id is not None:
os.environ['CUDA_VISIBLE_DEVICES'] = str(args.gpu_device_id) os.environ['CUDA_VISIBLE_DEVICES'] = str(args.gpu_device_id)
print("Set device to:", args.gpu_device_id) print("Set device to:", args.gpu_device_id)
if args.hf_mirror is not None : if args.hf_mirror is not None:
os.environ['HF_MIRROR'] = str(args.hf_mirror) os.environ['HF_MIRROR'] = str(args.hf_mirror)
print("Set hf_mirror to:", args.hf_mirror) print("Set hf_mirror to:", args.hf_mirror)
from modules import config from modules import config
from modules.hash_cache import init_cache from modules.hash_cache import init_cache
os.environ["U2NET_HOME"] = config.path_inpaint os.environ["U2NET_HOME"] = config.path_inpaint
os.environ['GRADIO_TEMP_DIR'] = config.temp_path os.environ['GRADIO_TEMP_DIR'] = config.temp_path
@@ -100,6 +101,8 @@ if config.temp_path_cleanup_on_launch:
def download_models(default_model, previous_default_models, checkpoint_downloads, embeddings_downloads, lora_downloads, vae_downloads): def download_models(default_model, previous_default_models, checkpoint_downloads, embeddings_downloads, lora_downloads, vae_downloads):
from modules.util import get_file_from_folder_list
for file_name, url in vae_approx_filenames: for file_name, url in vae_approx_filenames:
load_file_from_url(url=url, model_dir=config.path_vae_approx, file_name=file_name) load_file_from_url(url=url, model_dir=config.path_vae_approx, file_name=file_name)
@@ -114,9 +117,9 @@ def download_models(default_model, previous_default_models, checkpoint_downloads
return default_model, checkpoint_downloads return default_model, checkpoint_downloads
if not args.always_download_new_model: if not args.always_download_new_model:
if not os.path.exists(os.path.join(config.paths_checkpoints[0], default_model)): if not os.path.isfile(get_file_from_folder_list(default_model, config.paths_checkpoints)):
for alternative_model_name in previous_default_models: for alternative_model_name in previous_default_models:
if os.path.exists(os.path.join(config.paths_checkpoints[0], alternative_model_name)): if os.path.isfile(get_file_from_folder_list(alternative_model_name, config.paths_checkpoints)):
print(f'You do not have [{default_model}] but you have [{alternative_model_name}].') print(f'You do not have [{default_model}] but you have [{alternative_model_name}].')
print(f'Fooocus will use [{alternative_model_name}] to avoid downloading new models, ' print(f'Fooocus will use [{alternative_model_name}] to avoid downloading new models, '
f'but you are not using the latest models.') f'but you are not using the latest models.')
@@ -126,11 +129,13 @@ def download_models(default_model, previous_default_models, checkpoint_downloads
break break
for file_name, url in checkpoint_downloads.items(): for file_name, url in checkpoint_downloads.items():
load_file_from_url(url=url, model_dir=config.paths_checkpoints[0], file_name=file_name) model_dir = os.path.dirname(get_file_from_folder_list(file_name, config.paths_checkpoints))
load_file_from_url(url=url, model_dir=model_dir, file_name=file_name)
for file_name, url in embeddings_downloads.items(): for file_name, url in embeddings_downloads.items():
load_file_from_url(url=url, model_dir=config.path_embeddings, file_name=file_name) load_file_from_url(url=url, model_dir=config.path_embeddings, file_name=file_name)
for file_name, url in lora_downloads.items(): for file_name, url in lora_downloads.items():
load_file_from_url(url=url, model_dir=config.paths_loras[0], file_name=file_name) model_dir = os.path.dirname(get_file_from_folder_list(file_name, config.paths_loras))
load_file_from_url(url=url, model_dir=model_dir, file_name=file_name)
for file_name, url in vae_downloads.items(): for file_name, url in vae_downloads.items():
load_file_from_url(url=url, model_dir=config.path_vae, file_name=file_name) load_file_from_url(url=url, model_dir=config.path_vae, file_name=file_name)
@@ -8,7 +8,7 @@ class CLIPEmbeddingNoiseAugmentation(ImageConcatWithNoiseAugmentation):
if clip_stats_path is None: if clip_stats_path is None:
clip_mean, clip_std = torch.zeros(timestep_dim), torch.ones(timestep_dim) clip_mean, clip_std = torch.zeros(timestep_dim), torch.ones(timestep_dim)
else: else:
clip_mean, clip_std = torch.load(clip_stats_path, map_location="cpu") clip_mean, clip_std = torch.load(clip_stats_path, map_location="cpu", weights_only=True)
self.register_buffer("data_mean", clip_mean[None, :], persistent=False) self.register_buffer("data_mean", clip_mean[None, :], persistent=False)
self.register_buffer("data_std", clip_std[None, :], persistent=False) self.register_buffer("data_std", clip_std[None, :], persistent=False)
self.time_embed = Timestep(timestep_dim) self.time_embed = Timestep(timestep_dim)
+1 -1
View File
@@ -326,7 +326,7 @@ def load_embed(embedding_name, embedding_directory, embedding_size, embed_key=No
except: except:
embed_out = safe_load_embed_zip(embed_path) embed_out = safe_load_embed_zip(embed_path)
else: else:
embed = torch.load(embed_path, map_location="cpu") embed = torch.load(embed_path, map_location="cpu", weights_only=True)
except Exception as e: except Exception as e:
print(traceback.format_exc()) print(traceback.format_exc())
print() print()
@@ -377,15 +377,15 @@ class VQAutoEncoder(nn.Module):
) )
if model_path is not None: if model_path is not None:
chkpt = torch.load(model_path, map_location="cpu") chkpt = torch.load(model_path, map_location="cpu", weights_only=True)
if "params_ema" in chkpt: if "params_ema" in chkpt:
self.load_state_dict( self.load_state_dict(
torch.load(model_path, map_location="cpu")["params_ema"] torch.load(model_path, map_location="cpu", weights_only=True)["params_ema"]
) )
logger.info(f"vqgan is loaded from: {model_path} [params_ema]") logger.info(f"vqgan is loaded from: {model_path} [params_ema]")
elif "params" in chkpt: elif "params" in chkpt:
self.load_state_dict( self.load_state_dict(
torch.load(model_path, map_location="cpu")["params"] torch.load(model_path, map_location="cpu", weights_only=True)["params"]
) )
logger.info(f"vqgan is loaded from: {model_path} [params]") logger.info(f"vqgan is loaded from: {model_path} [params]")
else: else:
@@ -273,8 +273,8 @@ class GFPGANBilinear(nn.Module):
if decoder_load_path: if decoder_load_path:
self.stylegan_decoder.load_state_dict( self.stylegan_decoder.load_state_dict(
torch.load( torch.load(
decoder_load_path, map_location=lambda storage, loc: storage decoder_load_path, map_location=lambda storage, loc: storage,
)["params_ema"] weights_only=True)["params_ema"]
) )
# fix decoder without updating params # fix decoder without updating params
if fix_decoder: if fix_decoder:
@@ -373,8 +373,8 @@ class GFPGANv1(nn.Module):
if decoder_load_path: if decoder_load_path:
self.stylegan_decoder.load_state_dict( self.stylegan_decoder.load_state_dict(
torch.load( torch.load(
decoder_load_path, map_location=lambda storage, loc: storage decoder_load_path, map_location=lambda storage, loc: storage,
)["params_ema"] weights_only=True)["params_ema"]
) )
# fix decoder without updating params # fix decoder without updating params
if fix_decoder: if fix_decoder:
@@ -284,8 +284,8 @@ class GFPGANv1Clean(nn.Module):
if decoder_load_path: if decoder_load_path:
self.stylegan_decoder.load_state_dict( self.stylegan_decoder.load_state_dict(
torch.load( torch.load(
decoder_load_path, map_location=lambda storage, loc: storage decoder_load_path, map_location=lambda storage, loc: storage,
)["params_ema"] weights_only=True)["params_ema"]
) )
# fix decoder without updating params # fix decoder without updating params
if fix_decoder: if fix_decoder:
+59 -28
View File
@@ -9,7 +9,7 @@ patch_all()
class AsyncTask: class AsyncTask:
def __init__(self, args): def __init__(self, args):
from modules.flags import Performance, MetadataScheme, ip_list, controlnet_image_count from modules.flags import Performance, MetadataScheme, ip_list, disabled
from modules.util import get_enabled_loras from modules.util import get_enabled_loras
from modules.config import default_max_lora_number from modules.config import default_max_lora_number
import args_manager import args_manager
@@ -95,12 +95,13 @@ class AsyncTask:
self.inpaint_advanced_masking_checkbox = args.pop() self.inpaint_advanced_masking_checkbox = args.pop()
self.invert_mask_checkbox = args.pop() self.invert_mask_checkbox = args.pop()
self.inpaint_erode_or_dilate = args.pop() self.inpaint_erode_or_dilate = args.pop()
self.save_final_enhanced_image_only = args.pop() if not args_manager.args.disable_image_log else False
self.save_metadata_to_images = args.pop() if not args_manager.args.disable_metadata else False self.save_metadata_to_images = args.pop() if not args_manager.args.disable_metadata else False
self.metadata_scheme = MetadataScheme( self.metadata_scheme = MetadataScheme(
args.pop()) if not args_manager.args.disable_metadata else MetadataScheme.FOOOCUS args.pop()) if not args_manager.args.disable_metadata else MetadataScheme.FOOOCUS
self.cn_tasks = {x: [] for x in ip_list} self.cn_tasks = {x: [] for x in ip_list}
for _ in range(controlnet_image_count): for _ in range(modules.config.default_controlnet_image_count):
cn_img = args.pop() cn_img = args.pop()
cn_stop = args.pop() cn_stop = args.pop()
cn_weight = args.pop() cn_weight = args.pop()
@@ -153,12 +154,14 @@ class AsyncTask:
enhance_inpaint_erode_or_dilate, enhance_inpaint_erode_or_dilate,
enhance_mask_invert enhance_mask_invert
]) ])
self.should_enhance = self.enhance_checkbox and (self.enhance_uov_method != disabled.casefold() or len(self.enhance_ctrls) > 0)
self.images_to_enhance_count = 0
self.enhance_stats = {}
async_tasks = [] async_tasks = []
class EarlyReturnException: class EarlyReturnException(BaseException):
pass pass
@@ -277,7 +280,7 @@ def worker():
def process_task(all_steps, async_task, callback, controlnet_canny_path, controlnet_cpds_path, current_task_id, def process_task(all_steps, async_task, callback, controlnet_canny_path, controlnet_cpds_path, current_task_id,
denoising_strength, final_scheduler_name, goals, initial_latent, steps, switch, positive_cond, denoising_strength, final_scheduler_name, goals, initial_latent, steps, switch, positive_cond,
negative_cond, task, loras, tiled, use_expansion, width, height, base_progress, preparation_steps, negative_cond, task, loras, tiled, use_expansion, width, height, base_progress, preparation_steps,
total_count, show_intermediate_results): total_count, show_intermediate_results, persist_image=True):
if async_task.last_stop is not False: if async_task.last_stop is not False:
ldm_patched.modules.model_management.interrupt_current_processing() ldm_patched.modules.model_management.interrupt_current_processing()
if 'cn' in goals: if 'cn' in goals:
@@ -314,9 +317,8 @@ def worker():
if modules.config.default_black_out_nsfw or async_task.black_out_nsfw: if modules.config.default_black_out_nsfw or async_task.black_out_nsfw:
progressbar(async_task, current_progress, 'Checking for NSFW content ...') progressbar(async_task, current_progress, 'Checking for NSFW content ...')
imgs = default_censor(imgs) imgs = default_censor(imgs)
progressbar(async_task, current_progress, progressbar(async_task, current_progress, f'Saving image {current_task_id + 1}/{total_count} to system ...')
f'Saving image {current_task_id + 1}/{total_count} to system ...') img_paths = save_and_log(async_task, height, imgs, task, use_expansion, width, loras, persist_image)
img_paths = save_and_log(async_task, height, imgs, task, use_expansion, width, loras)
yield_result(async_task, img_paths, current_progress, async_task.black_out_nsfw, False, yield_result(async_task, img_paths, current_progress, async_task.black_out_nsfw, False,
do_not_show_finished_images=not show_intermediate_results or async_task.disable_intermediate_results) do_not_show_finished_images=not show_intermediate_results or async_task.disable_intermediate_results)
@@ -332,7 +334,7 @@ def worker():
async_task.adaptive_cfg async_task.adaptive_cfg
) )
def save_and_log(async_task, height, imgs, task, use_expansion, width, loras) -> list: def save_and_log(async_task, height, imgs, task, use_expansion, width, loras, persist_image=True) -> list:
img_paths = [] img_paths = []
for x in imgs: for x in imgs:
d = [('Prompt', 'prompt', task['log_positive_prompt']), d = [('Prompt', 'prompt', task['log_positive_prompt']),
@@ -387,7 +389,7 @@ def worker():
d.append(('Metadata Scheme', 'metadata_scheme', d.append(('Metadata Scheme', 'metadata_scheme',
async_task.metadata_scheme.value if async_task.save_metadata_to_images else async_task.save_metadata_to_images)) async_task.metadata_scheme.value if async_task.save_metadata_to_images else async_task.save_metadata_to_images))
d.append(('Version', 'version', 'Fooocus v' + fooocus_version.version)) d.append(('Version', 'version', 'Fooocus v' + fooocus_version.version))
img_paths.append(log(x, d, metadata_parser, async_task.output_format, task)) img_paths.append(log(x, d, metadata_parser, async_task.output_format, task, persist_image))
return img_paths return img_paths
@@ -687,13 +689,20 @@ def worker():
task_styles = async_task.style_selections.copy() task_styles = async_task.style_selections.copy()
if use_style: if use_style:
placeholder_replaced = False
for j, s in enumerate(task_styles): for j, s in enumerate(task_styles):
if s == random_style_name: if s == random_style_name:
s = get_random_style(task_rng) s = get_random_style(task_rng)
task_styles[j] = s task_styles[j] = s
p, n = apply_style(s, positive=task_prompt) p, n, style_has_placeholder = apply_style(s, positive=task_prompt)
if style_has_placeholder:
placeholder_replaced = True
positive_basic_workloads = positive_basic_workloads + p positive_basic_workloads = positive_basic_workloads + p
negative_basic_workloads = negative_basic_workloads + n negative_basic_workloads = negative_basic_workloads + n
if not placeholder_replaced:
positive_basic_workloads = [task_prompt] + positive_basic_workloads
else: else:
positive_basic_workloads.append(task_prompt) positive_basic_workloads.append(task_prompt)
@@ -958,7 +967,7 @@ def worker():
inpaint_engine, inpaint_respective_field, inpaint_strength, inpaint_engine, inpaint_respective_field, inpaint_strength,
prompt, negative_prompt, final_scheduler_name, goals, height, img, mask, prompt, negative_prompt, final_scheduler_name, goals, height, img, mask,
preparation_steps, steps, switch, tiled, total_count, use_expansion, use_style, preparation_steps, steps, switch, tiled, total_count, use_expansion, use_style,
use_synthetic_refiner, width, show_intermediate_results=True): use_synthetic_refiner, width, show_intermediate_results=True, persist_image=True):
base_model_additional_loras = [] base_model_additional_loras = []
inpaint_head_model_path = None inpaint_head_model_path = None
inpaint_parameterized = inpaint_engine != 'None' # inpaint_engine = None, improve detail inpaint_parameterized = inpaint_engine != 'None' # inpaint_engine = None, improve detail
@@ -979,7 +988,7 @@ def worker():
progressbar(async_task, current_progress, 'Checking for NSFW content ...') progressbar(async_task, current_progress, 'Checking for NSFW content ...')
img = default_censor(img) img = default_censor(img)
progressbar(async_task, current_progress, f'Saving image {current_task_id + 1}/{total_count} to system ...') progressbar(async_task, current_progress, f'Saving image {current_task_id + 1}/{total_count} to system ...')
uov_image_path = log(img, d, output_format=async_task.output_format) uov_image_path = log(img, d, output_format=async_task.output_format, persist_image=persist_image)
yield_result(async_task, uov_image_path, current_progress, async_task.black_out_nsfw, False, yield_result(async_task, uov_image_path, current_progress, async_task.black_out_nsfw, False,
do_not_show_finished_images=not show_intermediate_results or async_task.disable_intermediate_results) do_not_show_finished_images=not show_intermediate_results or async_task.disable_intermediate_results)
return current_progress, img, prompt, negative_prompt return current_progress, img, prompt, negative_prompt
@@ -1013,7 +1022,8 @@ def worker():
final_scheduler_name, goals, initial_latent, steps, switch, final_scheduler_name, goals, initial_latent, steps, switch,
task_enhance['c'], task_enhance['uc'], task_enhance, loras, task_enhance['c'], task_enhance['uc'], task_enhance, loras,
tiled, use_expansion, width, height, current_progress, tiled, use_expansion, width, height, current_progress,
preparation_steps, total_count, show_intermediate_results) preparation_steps, total_count, show_intermediate_results,
persist_image)
del task_enhance['c'], task_enhance['uc'] # Save memory del task_enhance['c'], task_enhance['uc'] # Save memory
return current_progress, imgs[0], prompt, negative_prompt return current_progress, imgs[0], prompt, negative_prompt
@@ -1021,7 +1031,7 @@ def worker():
def enhance_upscale(all_steps, async_task, base_progress, callback, controlnet_canny_path, controlnet_cpds_path, def enhance_upscale(all_steps, async_task, base_progress, callback, controlnet_canny_path, controlnet_cpds_path,
current_task_id, denoising_strength, done_steps_inpainting, done_steps_upscaling, enhance_steps, current_task_id, denoising_strength, done_steps_inpainting, done_steps_upscaling, enhance_steps,
prompt, negative_prompt, final_scheduler_name, height, img, preparation_steps, switch, tiled, prompt, negative_prompt, final_scheduler_name, height, img, preparation_steps, switch, tiled,
total_count, use_expansion, use_style, use_synthetic_refiner, width): total_count, use_expansion, use_style, use_synthetic_refiner, width, persist_image=True):
# reset inpaint worker to prevent tensor size issues and not mix upscale and inpainting # reset inpaint worker to prevent tensor size issues and not mix upscale and inpainting
inpaint_worker.current_task = None inpaint_worker.current_task = None
@@ -1039,7 +1049,7 @@ def worker():
controlnet_cpds_path, current_progress, current_task_id, denoising_strength, False, controlnet_cpds_path, current_progress, current_task_id, denoising_strength, False,
'None', 0.0, 0.0, prompt, negative_prompt, final_scheduler_name, 'None', 0.0, 0.0, prompt, negative_prompt, final_scheduler_name,
goals_enhance, height, img, None, preparation_steps, steps, switch, tiled, total_count, goals_enhance, height, img, None, preparation_steps, steps, switch, tiled, total_count,
use_expansion, use_style, use_synthetic_refiner, width) use_expansion, use_style, use_synthetic_refiner, width, persist_image=persist_image)
except ldm_patched.modules.model_management.InterruptProcessingException: except ldm_patched.modules.model_management.InterruptProcessingException:
if async_task.last_stop == 'skip': if async_task.last_stop == 'skip':
@@ -1156,6 +1166,8 @@ def worker():
current_progress += 1 current_progress += 1
progressbar(async_task, current_progress, 'Image processing ...') progressbar(async_task, current_progress, 'Image processing ...')
should_enhance = async_task.enhance_checkbox and (async_task.enhance_uov_method != flags.disabled.casefold() or len(async_task.enhance_ctrls) > 0)
if 'vary' in goals: if 'vary' in goals:
async_task.uov_input_image, denoising_strength, initial_latent, width, height, current_progress = apply_vary( async_task.uov_input_image, denoising_strength, initial_latent, width, height, current_progress = apply_vary(
async_task, async_task.uov_method, denoising_strength, async_task.uov_input_image, switch, async_task, async_task.uov_method, denoising_strength, async_task.uov_input_image, switch,
@@ -1211,6 +1223,8 @@ def worker():
height, width, _ = async_task.enhance_input_image.shape height, width, _ = async_task.enhance_input_image.shape
# input image already provided, processing is skipped # input image already provided, processing is skipped
steps = 0 steps = 0
yield_result(async_task, async_task.enhance_input_image, current_progress, async_task.black_out_nsfw, False,
async_task.disable_intermediate_results)
all_steps = steps * async_task.image_number all_steps = steps * async_task.image_number
@@ -1261,8 +1275,8 @@ def worker():
int(current_progress + async_task.callback_steps), int(current_progress + async_task.callback_steps),
f'Sampling step {step + 1}/{total_steps}, image {current_task_id + 1}/{total_count} ...', y)]) f'Sampling step {step + 1}/{total_steps}, image {current_task_id + 1}/{total_count} ...', y)])
should_enhance = async_task.enhance_checkbox and (async_task.enhance_uov_method != flags.disabled.casefold() or len(async_task.enhance_ctrls) > 0) show_intermediate_results = len(tasks) > 1 or async_task.should_enhance
show_intermediate_results = len(tasks) > 1 or should_enhance persist_image = not async_task.should_enhance or not async_task.save_final_enhanced_image_only
for current_task_id, task in enumerate(tasks): for current_task_id, task in enumerate(tasks):
progressbar(async_task, current_progress, f'Preparing task {current_task_id + 1}/{async_task.image_number} ...') progressbar(async_task, current_progress, f'Preparing task {current_task_id + 1}/{async_task.image_number} ...')
@@ -1275,7 +1289,8 @@ def worker():
initial_latent, async_task.steps, switch, task['c'], initial_latent, async_task.steps, switch, task['c'],
task['uc'], task, loras, tiled, use_expansion, width, task['uc'], task, loras, tiled, use_expansion, width,
height, current_progress, preparation_steps, height, current_progress, preparation_steps,
async_task.image_number, show_intermediate_results) async_task.image_number, show_intermediate_results,
persist_image)
current_progress = int(preparation_steps + (100 - preparation_steps) / float(all_steps) * async_task.steps * (current_task_id + 1)) current_progress = int(preparation_steps + (100 - preparation_steps) / float(all_steps) * async_task.steps * (current_task_id + 1))
images_to_enhance += imgs images_to_enhance += imgs
@@ -1293,7 +1308,7 @@ def worker():
execution_time = time.perf_counter() - execution_start_time execution_time = time.perf_counter() - execution_start_time
print(f'Generating and saving time: {execution_time:.2f} seconds') print(f'Generating and saving time: {execution_time:.2f} seconds')
if not should_enhance: if not async_task.should_enhance:
print(f'[Enhance] Skipping, preconditions aren\'t met') print(f'[Enhance] Skipping, preconditions aren\'t met')
stop_processing(async_task, processing_start_time) stop_processing(async_task, processing_start_time)
return return
@@ -1302,9 +1317,14 @@ def worker():
active_enhance_tabs = len(async_task.enhance_ctrls) active_enhance_tabs = len(async_task.enhance_ctrls)
should_process_enhance_uov = async_task.enhance_uov_method != flags.disabled.casefold() should_process_enhance_uov = async_task.enhance_uov_method != flags.disabled.casefold()
enhance_uov_before = False
enhance_uov_after = False
if should_process_enhance_uov: if should_process_enhance_uov:
active_enhance_tabs += 1 active_enhance_tabs += 1
enhance_uov_before = async_task.enhance_uov_processing_order == flags.enhancement_uov_before
enhance_uov_after = async_task.enhance_uov_processing_order == flags.enhancement_uov_after
total_count = len(images_to_enhance) * active_enhance_tabs total_count = len(images_to_enhance) * active_enhance_tabs
async_task.images_to_enhance_count = len(images_to_enhance)
base_progress = current_progress base_progress = current_progress
current_task_id = -1 current_task_id = -1
@@ -1312,19 +1332,23 @@ def worker():
done_steps_inpainting = 0 done_steps_inpainting = 0
enhance_steps, _, _, _ = apply_overrides(async_task, async_task.original_steps, height, width) enhance_steps, _, _, _ = apply_overrides(async_task, async_task.original_steps, height, width)
exception_result = None exception_result = None
for img in images_to_enhance: for index, img in enumerate(images_to_enhance):
async_task.enhance_stats[index] = 0
enhancement_image_start_time = time.perf_counter() enhancement_image_start_time = time.perf_counter()
last_enhance_prompt = async_task.prompt last_enhance_prompt = async_task.prompt
last_enhance_negative_prompt = async_task.negative_prompt last_enhance_negative_prompt = async_task.negative_prompt
if should_process_enhance_uov and async_task.enhance_uov_processing_order == flags.enhancement_uov_before: if enhance_uov_before:
current_task_id += 1 current_task_id += 1
persist_image = not async_task.save_final_enhanced_image_only or active_enhance_tabs == 0
current_task_id, done_steps_inpainting, done_steps_upscaling, img, exception_result = enhance_upscale( current_task_id, done_steps_inpainting, done_steps_upscaling, img, exception_result = enhance_upscale(
all_steps, async_task, base_progress, callback, controlnet_canny_path, controlnet_cpds_path, all_steps, async_task, base_progress, callback, controlnet_canny_path, controlnet_cpds_path,
current_task_id, denoising_strength, done_steps_inpainting, done_steps_upscaling, enhance_steps, current_task_id, denoising_strength, done_steps_inpainting, done_steps_upscaling, enhance_steps,
async_task.prompt, async_task.negative_prompt, final_scheduler_name, height, img, preparation_steps, async_task.prompt, async_task.negative_prompt, final_scheduler_name, height, img, preparation_steps,
switch, tiled, total_count, use_expansion, use_style, use_synthetic_refiner, width) switch, tiled, total_count, use_expansion, use_style, use_synthetic_refiner, width, persist_image)
async_task.enhance_stats[index] += 1
if exception_result == 'continue': if exception_result == 'continue':
continue continue
elif exception_result == 'break': elif exception_result == 'break':
@@ -1336,6 +1360,8 @@ def worker():
current_progress = int(base_progress + (100 - preparation_steps) / float(all_steps) * (done_steps_upscaling + done_steps_inpainting)) current_progress = int(base_progress + (100 - preparation_steps) / float(all_steps) * (done_steps_upscaling + done_steps_inpainting))
progressbar(async_task, current_progress, f'Preparing enhancement {current_task_id + 1}/{total_count} ...') progressbar(async_task, current_progress, f'Preparing enhancement {current_task_id + 1}/{total_count} ...')
enhancement_task_start_time = time.perf_counter() enhancement_task_start_time = time.perf_counter()
is_last_enhance_for_image = (current_task_id + 1) % active_enhance_tabs == 0 and not enhance_uov_after
persist_image = not async_task.save_final_enhanced_image_only or is_last_enhance_for_image
extras = {} extras = {}
if enhance_mask_model == 'sam': if enhance_mask_model == 'sam':
@@ -1366,13 +1392,13 @@ def worker():
async_task.yields.append(['preview', (current_progress, 'Loading ...', mask)]) async_task.yields.append(['preview', (current_progress, 'Loading ...', mask)])
yield_result(async_task, mask, current_progress, async_task.black_out_nsfw, False, yield_result(async_task, mask, current_progress, async_task.black_out_nsfw, False,
async_task.disable_intermediate_results) async_task.disable_intermediate_results)
async_task.enhance_stats[index] += 1
print(f'[Enhance] {dino_detection_count} boxes detected') print(f'[Enhance] {dino_detection_count} boxes detected')
print(f'[Enhance] {sam_detection_count} segments detected in boxes') print(f'[Enhance] {sam_detection_count} segments detected in boxes')
print(f'[Enhance] {sam_detection_on_mask_count} segments applied to mask') print(f'[Enhance] {sam_detection_on_mask_count} segments applied to mask')
if enhance_mask_model == 'sam' and ( if enhance_mask_model == 'sam' and (dino_detection_count == 0 or not async_task.debugging_dino and sam_detection_on_mask_count == 0):
dino_detection_count == 0 or not async_task.debugging_dino and sam_detection_on_mask_count == 0):
print(f'[Enhance] No "{enhance_mask_dino_prompt_text}" detected, skipping') print(f'[Enhance] No "{enhance_mask_dino_prompt_text}" detected, skipping')
continue continue
@@ -1385,7 +1411,8 @@ def worker():
enhance_inpaint_engine, enhance_inpaint_respective_field, enhance_inpaint_strength, enhance_inpaint_engine, enhance_inpaint_respective_field, enhance_inpaint_strength,
enhance_prompt, enhance_negative_prompt, final_scheduler_name, goals_enhance, height, img, mask, enhance_prompt, enhance_negative_prompt, final_scheduler_name, goals_enhance, height, img, mask,
preparation_steps, enhance_steps, switch, tiled, total_count, use_expansion, use_style, preparation_steps, enhance_steps, switch, tiled, total_count, use_expansion, use_style,
use_synthetic_refiner, width) use_synthetic_refiner, width, persist_image=persist_image)
async_task.enhance_stats[index] += 1
if (should_process_enhance_uov and async_task.enhance_uov_processing_order == flags.enhancement_uov_after if (should_process_enhance_uov and async_task.enhance_uov_processing_order == flags.enhancement_uov_after
and async_task.enhance_uov_prompt_type == flags.enhancement_uov_prompt_type_last_filled): and async_task.enhance_uov_prompt_type == flags.enhancement_uov_prompt_type_last_filled):
@@ -1412,14 +1439,18 @@ def worker():
if exception_result == 'break': if exception_result == 'break':
break break
if should_process_enhance_uov and async_task.enhance_uov_processing_order == flags.enhancement_uov_after: if enhance_uov_after:
current_task_id += 1 current_task_id += 1
# last step in enhance, always save
persist_image = True
current_task_id, done_steps_inpainting, done_steps_upscaling, img, exception_result = enhance_upscale( current_task_id, done_steps_inpainting, done_steps_upscaling, img, exception_result = enhance_upscale(
all_steps, async_task, base_progress, callback, controlnet_canny_path, controlnet_cpds_path, all_steps, async_task, base_progress, callback, controlnet_canny_path, controlnet_cpds_path,
current_task_id, denoising_strength, done_steps_inpainting, done_steps_upscaling, enhance_steps, current_task_id, denoising_strength, done_steps_inpainting, done_steps_upscaling, enhance_steps,
last_enhance_prompt, last_enhance_negative_prompt, final_scheduler_name, height, img, last_enhance_prompt, last_enhance_negative_prompt, final_scheduler_name, height, img,
preparation_steps, switch, tiled, total_count, use_expansion, use_style, use_synthetic_refiner, preparation_steps, switch, tiled, total_count, use_expansion, use_style, use_synthetic_refiner,
width) width, persist_image)
async_task.enhance_stats[index] += 1
if exception_result == 'continue': if exception_result == 'continue':
continue continue
elif exception_result == 'break': elif exception_result == 'break':
+114 -7
View File
@@ -403,12 +403,36 @@ default_performance = get_config_item_or_set_default(
validator=lambda x: x in Performance.values(), validator=lambda x: x in Performance.values(),
expected_type=str expected_type=str
) )
default_image_prompt_checkbox = get_config_item_or_set_default(
key='default_image_prompt_checkbox',
default_value=False,
validator=lambda x: isinstance(x, bool),
expected_type=bool
)
default_enhance_checkbox = get_config_item_or_set_default(
key='default_enhance_checkbox',
default_value=False,
validator=lambda x: isinstance(x, bool),
expected_type=bool
)
default_advanced_checkbox = get_config_item_or_set_default( default_advanced_checkbox = get_config_item_or_set_default(
key='default_advanced_checkbox', key='default_advanced_checkbox',
default_value=False, default_value=False,
validator=lambda x: isinstance(x, bool), validator=lambda x: isinstance(x, bool),
expected_type=bool expected_type=bool
) )
default_developer_debug_mode_checkbox = get_config_item_or_set_default(
key='default_developer_debug_mode_checkbox',
default_value=False,
validator=lambda x: isinstance(x, bool),
expected_type=bool
)
default_image_prompt_advanced_checkbox = get_config_item_or_set_default(
key='default_image_prompt_advanced_checkbox',
default_value=False,
validator=lambda x: isinstance(x, bool),
expected_type=bool
)
default_max_image_number = get_config_item_or_set_default( default_max_image_number = get_config_item_or_set_default(
key='default_max_image_number', key='default_max_image_number',
default_value=32, default_value=32,
@@ -469,6 +493,69 @@ default_inpaint_engine_version = get_config_item_or_set_default(
validator=lambda x: x in modules.flags.inpaint_engine_versions, validator=lambda x: x in modules.flags.inpaint_engine_versions,
expected_type=str expected_type=str
) )
default_selected_image_input_tab_id = get_config_item_or_set_default(
key='default_selected_image_input_tab_id',
default_value=modules.flags.default_input_image_tab,
validator=lambda x: x in modules.flags.input_image_tab_ids,
expected_type=str
)
default_uov_method = get_config_item_or_set_default(
key='default_uov_method',
default_value=modules.flags.disabled,
validator=lambda x: x in modules.flags.uov_list,
expected_type=str
)
default_controlnet_image_count = get_config_item_or_set_default(
key='default_controlnet_image_count',
default_value=4,
validator=lambda x: isinstance(x, int) and x > 0,
expected_type=int
)
default_ip_images = {}
default_ip_stop_ats = {}
default_ip_weights = {}
default_ip_types = {}
for image_count in range(default_controlnet_image_count):
image_count += 1
default_ip_images[image_count] = get_config_item_or_set_default(
key=f'default_ip_image_{image_count}',
default_value='None',
validator=lambda x: x == 'None' or isinstance(x, str) and os.path.exists(x),
expected_type=str
)
if default_ip_images[image_count] == 'None':
default_ip_images[image_count] = None
default_ip_types[image_count] = get_config_item_or_set_default(
key=f'default_ip_type_{image_count}',
default_value=modules.flags.default_ip,
validator=lambda x: x in modules.flags.ip_list,
expected_type=str
)
default_end, default_weight = modules.flags.default_parameters[default_ip_types[image_count]]
default_ip_stop_ats[image_count] = get_config_item_or_set_default(
key=f'default_ip_stop_at_{image_count}',
default_value=default_end,
validator=lambda x: isinstance(x, float) and 0 <= x <= 1,
expected_type=float
)
default_ip_weights[image_count] = get_config_item_or_set_default(
key=f'default_ip_weight_{image_count}',
default_value=default_weight,
validator=lambda x: isinstance(x, float) and 0 <= x <= 2,
expected_type=float
)
default_inpaint_advanced_masking_checkbox = get_config_item_or_set_default(
key='default_inpaint_advanced_masking_checkbox',
default_value=False,
validator=lambda x: isinstance(x, bool),
expected_type=bool
)
default_inpaint_method = get_config_item_or_set_default( default_inpaint_method = get_config_item_or_set_default(
key='default_inpaint_method', key='default_inpaint_method',
default_value=modules.flags.inpaint_option_default, default_value=modules.flags.inpaint_option_default,
@@ -526,12 +613,6 @@ default_enhance_tabs = get_config_item_or_set_default(
validator=lambda x: isinstance(x, int) and 1 <= x <= 5, validator=lambda x: isinstance(x, int) and 1 <= x <= 5,
expected_type=int expected_type=int
) )
default_enhance_checkbox = get_config_item_or_set_default(
key='default_enhance_checkbox',
default_value=False,
validator=lambda x: isinstance(x, bool),
expected_type=bool
)
default_enhance_uov_method = get_config_item_or_set_default( default_enhance_uov_method = get_config_item_or_set_default(
key='default_enhance_uov_method', key='default_enhance_uov_method',
default_value=modules.flags.disabled, default_value=modules.flags.disabled,
@@ -562,6 +643,12 @@ default_black_out_nsfw = get_config_item_or_set_default(
validator=lambda x: isinstance(x, bool), validator=lambda x: isinstance(x, bool),
expected_type=bool expected_type=bool
) )
default_save_only_final_enhanced_image = get_config_item_or_set_default(
key='default_save_only_final_enhanced_image',
default_value=False,
validator=lambda x: isinstance(x, bool),
expected_type=bool
)
default_save_metadata_to_images = get_config_item_or_set_default( default_save_metadata_to_images = get_config_item_or_set_default(
key='default_save_metadata_to_images', key='default_save_metadata_to_images',
default_value=False, default_value=False,
@@ -584,6 +671,13 @@ metadata_created_by = get_config_item_or_set_default(
example_inpaint_prompts = [[x] for x in example_inpaint_prompts] example_inpaint_prompts = [[x] for x in example_inpaint_prompts]
example_enhance_detection_prompts = [[x] for x in example_enhance_detection_prompts] example_enhance_detection_prompts = [[x] for x in example_enhance_detection_prompts]
default_invert_mask_checkbox = get_config_item_or_set_default(
key='default_invert_mask_checkbox',
default_value=False,
validator=lambda x: isinstance(x, bool),
expected_type=bool
)
default_inpaint_mask_model = get_config_item_or_set_default( default_inpaint_mask_model = get_config_item_or_set_default(
key='default_inpaint_mask_model', key='default_inpaint_mask_model',
default_value='isnet-general-use', default_value='isnet-general-use',
@@ -608,10 +702,23 @@ default_inpaint_mask_cloth_category = get_config_item_or_set_default(
default_inpaint_mask_sam_model = get_config_item_or_set_default( default_inpaint_mask_sam_model = get_config_item_or_set_default(
key='default_inpaint_mask_sam_model', key='default_inpaint_mask_sam_model',
default_value='vit_b', default_value='vit_b',
validator=lambda x: x in [y[1] for y in modules.flags.inpaint_mask_sam_model if y[1] == x], validator=lambda x: x in modules.flags.inpaint_mask_sam_model,
expected_type=str expected_type=str
) )
default_describe_apply_prompts_checkbox = get_config_item_or_set_default(
key='default_describe_apply_prompts_checkbox',
default_value=True,
validator=lambda x: isinstance(x, bool),
expected_type=bool
)
default_describe_content_type = get_config_item_or_set_default(
key='default_describe_content_type',
default_value=[modules.flags.describe_type_photo],
validator=lambda x: all(k in modules.flags.describe_types for k in x),
expected_type=list
)
config_dict["default_loras"] = default_loras = default_loras[:default_max_lora_number] + [[True, 'None', 1.0] for _ in range(default_max_lora_number - len(default_loras))] config_dict["default_loras"] = default_loras = default_loras[:default_max_lora_number] + [[True, 'None', 1.0] for _ in range(default_max_lora_number - len(default_loras))]
# mapping config to meta parameter # mapping config to meta parameter
+1 -1
View File
@@ -231,7 +231,7 @@ def get_previewer(model):
if vae_approx_filename in VAE_approx_models: if vae_approx_filename in VAE_approx_models:
VAE_approx_model = VAE_approx_models[vae_approx_filename] VAE_approx_model = VAE_approx_models[vae_approx_filename]
else: else:
sd = torch.load(vae_approx_filename, map_location='cpu') sd = torch.load(vae_approx_filename, map_location='cpu', weights_only=True)
VAE_approx_model = VAEApprox() VAE_approx_model = VAEApprox()
VAE_approx_model.load_state_dict(sd) VAE_approx_model.load_state_dict(sd)
del sd del sd
+6 -4
View File
@@ -67,6 +67,9 @@ default_vae = 'Default (model)'
refiner_swap_method = 'joint' refiner_swap_method = 'joint'
default_input_image_tab = 'uov_tab'
input_image_tab_ids = ['uov_tab', 'ip_tab', 'inpaint_tab', 'describe_tab', 'enhance_tab', 'metadata_tab']
cn_ip = "ImagePrompt" cn_ip = "ImagePrompt"
cn_ip_face = "FaceSwap" cn_ip_face = "FaceSwap"
cn_canny = "PyraCanny" cn_canny = "PyraCanny"
@@ -91,8 +94,9 @@ inpaint_option_detail = 'Improve Detail (face, hand, eyes, etc.)'
inpaint_option_modify = 'Modify Content (add objects, change background, etc.)' inpaint_option_modify = 'Modify Content (add objects, change background, etc.)'
inpaint_options = [inpaint_option_default, inpaint_option_detail, inpaint_option_modify] inpaint_options = [inpaint_option_default, inpaint_option_detail, inpaint_option_modify]
desc_type_photo = 'Photograph' describe_type_photo = 'Photograph'
desc_type_anime = 'Art/Anime' describe_type_anime = 'Art/Anime'
describe_types = [describe_type_photo, describe_type_anime]
sdxl_aspect_ratios = [ sdxl_aspect_ratios = [
'704*1408', '704*1344', '768*1344', '768*1280', '832*1216', '832*1152', '704*1408', '704*1344', '768*1344', '768*1280', '832*1216', '832*1152',
@@ -113,8 +117,6 @@ metadata_scheme = [
(f'{MetadataScheme.A1111.value} (plain text)', MetadataScheme.A1111.value), (f'{MetadataScheme.A1111.value} (plain text)', MetadataScheme.A1111.value),
] ]
controlnet_image_count = 4
class OutputFormat(Enum): class OutputFormat(Enum):
PNG = 'png' PNG = 'png'
+1 -1
View File
@@ -196,7 +196,7 @@ class InpaintWorker:
if inpaint_head_model is None: if inpaint_head_model is None:
inpaint_head_model = InpaintHead() inpaint_head_model = InpaintHead()
sd = torch.load(inpaint_head_model_path, map_location='cpu') sd = torch.load(inpaint_head_model_path, map_location='cpu', weights_only=True)
inpaint_head_model.load_state_dict(sd) inpaint_head_model.load_state_dict(sd)
feed = torch.cat([ feed = torch.cat([
+3 -4
View File
@@ -604,9 +604,8 @@ def get_metadata_parser(metadata_scheme: MetadataScheme) -> MetadataParser:
raise NotImplementedError raise NotImplementedError
def read_info_from_image(filepath) -> tuple[str | None, MetadataScheme | None]: def read_info_from_image(file) -> tuple[str | None, MetadataScheme | None]:
with Image.open(filepath) as image: items = (file.info or {}).copy()
items = (image.info or {}).copy()
parameters = items.pop('parameters', None) parameters = items.pop('parameters', None)
metadata_scheme = items.pop('fooocus_scheme', None) metadata_scheme = items.pop('fooocus_scheme', None)
@@ -615,7 +614,7 @@ def read_info_from_image(filepath) -> tuple[str | None, MetadataScheme | None]:
if parameters is not None and is_json(parameters): if parameters is not None and is_json(parameters):
parameters = json.loads(parameters) parameters = json.loads(parameters)
elif exif is not None: elif exif is not None:
exif = image.getexif() exif = file.getexif()
# 0x9286 = UserComment # 0x9286 = UserComment
parameters = exif.get(0x9286, None) parameters = exif.get(0x9286, None)
# 0x927C = MakerNote # 0x927C = MakerNote
+2 -2
View File
@@ -21,8 +21,8 @@ def get_current_html_path(output_format=None):
return html_name return html_name
def log(img, metadata, metadata_parser: MetadataParser | None = None, output_format=None, task=None) -> str: def log(img, metadata, metadata_parser: MetadataParser | None = None, output_format=None, task=None, persist_image=True) -> str:
path_outputs = modules.config.temp_path if args_manager.args.disable_image_log else modules.config.path_outputs path_outputs = modules.config.temp_path if args_manager.args.disable_image_log or not persist_image else modules.config.path_outputs
output_format = output_format if output_format else modules.config.default_output_format output_format = output_format if output_format else modules.config.default_output_format
date_string, local_temp_filename, only_name = generate_temp_filename(folder=path_outputs, extension=output_format) date_string, local_temp_filename, only_name = generate_temp_filename(folder=path_outputs, extension=output_format)
os.makedirs(os.path.dirname(local_temp_filename), exist_ok=True) os.makedirs(os.path.dirname(local_temp_filename), exist_ok=True)
+1 -1
View File
@@ -59,7 +59,7 @@ def get_random_style(rng: Random) -> str:
def apply_style(style, positive): def apply_style(style, positive):
p, n = styles[style] p, n = styles[style]
return p.replace('{prompt}', positive).splitlines(), n.splitlines() return p.replace('{prompt}', positive).splitlines(), n.splitlines(), '{prompt}' in p
def get_words(arrays, total_mult, index): def get_words(arrays, total_mult, index):
+1 -1
View File
@@ -17,7 +17,7 @@ def perform_upscale(img):
if model is None: if model is None:
model_filename = downloading_upscale_model() model_filename = downloading_upscale_model()
sd = torch.load(model_filename) sd = torch.load(model_filename, weights_only=True)
sdo = OrderedDict() sdo = OrderedDict()
for k, v in sd.items(): for k, v in sd.items():
sdo[k.replace('residual_block_', 'RDB')] = v sdo[k.replace('residual_block_', 'RDB')] = v
+70 -42
View File
@@ -1,40 +1,30 @@
<div align=center> <div align=center>
<img src="https://github.com/lllyasviel/Fooocus/assets/19834515/483fb86d-c9a2-4c20-997c-46dafc124f25"> <img src="https://github.com/lllyasviel/Fooocus/assets/19834515/483fb86d-c9a2-4c20-997c-46dafc124f25">
**Non-cherry-picked** random batch by just typing two words "forest elf",
without any parameter tweaking, without any strange prompt tags.
See also **non-cherry-picked** generalization and diversity tests [here](https://github.com/lllyasviel/Fooocus/discussions/2067) and [here](https://github.com/lllyasviel/Fooocus/discussions/808) and [here](https://github.com/lllyasviel/Fooocus/discussions/679) and [here](https://github.com/lllyasviel/Fooocus/discussions/679#realistic).
In the entire open source community, only Fooocus can achieve this level of **non-cherry-picked** quality.
</div> </div>
# Fooocus # Fooocus
Fooocus is an image generating software (based on [Gradio](https://www.gradio.app/)). [>>> Click Here to Install Fooocus <<<](#download)
Fooocus is a rethinking of Stable Diffusion and Midjourneys designs: Fooocus is an image generating software (based on [Gradio](https://www.gradio.app/) <a href='https://github.com/gradio-app/gradio'><img src='https://img.shields.io/github/stars/gradio-app/gradio'></a>).
* Learned from Stable Diffusion, the software is offline, open source, and free. Fooocus presents a rethinking of image generator designs. The software is offline, open source, and free, while at the same time, similar to many online image generators like Midjourney, the manual tweaking is not needed, and users only need to focus on the prompts and images. Fooocus has also simplified the installation: between pressing "download" and generating the first image, the number of needed mouse clicks is strictly limited to less than 3. Minimal GPU memory requirement is 4GB (Nvidia).
* Learned from Midjourney, the manual tweaking is not needed, and users only need to focus on the prompts and images.
Fooocus has included and automated [lots of inner optimizations and quality improvements](#tech_list). Users can forget all those difficult technical parameters, and just enjoy the interaction between human and computer to "explore new mediums of thought and expanding the imaginative powers of the human species" `[1]`.
Fooocus has simplified the installation. Between pressing "download" and generating the first image, the number of needed mouse clicks is strictly limited to less than 3. Minimal GPU memory requirement is 4GB (Nvidia).
`[1]` David Holz, 2019.
**Recently many fake websites exist on Google when you search “fooocus”. Do not trust those here is the only official source of Fooocus.** **Recently many fake websites exist on Google when you search “fooocus”. Do not trust those here is the only official source of Fooocus.**
## [Installing Fooocus](#download) # Project Status: Limited Long-Term Support (LTS) with Bug Fixes Only
# Moving from Midjourney to Fooocus The Fooocus project, built entirely on the **Stable Diffusion XL** architecture, is now in a state of limited long-term support (LTS) with bug fixes only. As the existing functionalities are considered as nearly free of programmartic issues (Thanks to [mashb1t](https://github.com/mashb1t)'s huge efforts), future updates will focus exclusively on addressing any bugs that may arise.
Using Fooocus is as easy as (probably easier than) Midjourney but this does not mean we lack functionality. Below are the details. **There are no current plans to migrate to or incorporate newer model architectures.** However, this may change during time with the development of open-source community. For example, if the community converge to one single dominant method for image generation (which may really happen in half or one years given the current status), Fooocus may also migrate to that exact method.
For those interested in utilizing newer models such as **Flux**, we recommend exploring alternative platforms such as [WebUI Forge](https://github.com/lllyasviel/stable-diffusion-webui-forge) (also from us), [ComfyUI/SwarmUI](https://github.com/comfyanonymous/ComfyUI). Additionally, several [excellent forks of Fooocus](https://github.com/lllyasviel/Fooocus?tab=readme-ov-file#forks) are available for experimentation.
Again, recently many fake websites exist on Google when you search “fooocus”. Do **NOT** get Fooocus from those websites this page is the only official source of Fooocus. We never have any website like such as “fooocus.com”, “fooocus.net”, “fooocus.co”, “fooocus.ai”, “fooocus.org”, “fooocus.pro”, “fooocus.one”. Those websites are ALL FAKE. **They have ABSOLUTLY no relationship to us. Fooocus is a 100% non-commercial offline open-source software.**
# Features
Below is a quick list using Midjourney's examples:
| Midjourney | Fooocus | | Midjourney | Fooocus |
| - | - | | - | - |
@@ -55,7 +45,7 @@ Using Fooocus is as easy as (probably easier than) Midjourney but this does
| InsightFace | Input Image -> Image Prompt -> Advanced -> FaceSwap | | InsightFace | Input Image -> Image Prompt -> Advanced -> FaceSwap |
| Describe | Input Image -> Describe | | Describe | Input Image -> Describe |
We also have a few things borrowed from the best parts of LeonardoAI: Below is a quick list using LeonardoAI's examples:
| LeonardoAI | Fooocus | | LeonardoAI | Fooocus |
| - | - | | - | - |
@@ -63,7 +53,7 @@ We also have a few things borrowed from the best parts of LeonardoAI:
| Advanced Sampler Parameters (like Contrast/Sharpness/etc) | Advanced -> Advanced -> Sampling Sharpness / etc | | Advanced Sampler Parameters (like Contrast/Sharpness/etc) | Advanced -> Advanced -> Sampling Sharpness / etc |
| User-friendly ControlNets | Input Image -> Image Prompt -> Advanced | | User-friendly ControlNets | Input Image -> Image Prompt -> Advanced |
Fooocus also developed many "fooocus-only" features for advanced users to get perfect results. [Click here to browse the advanced features.](https://github.com/lllyasviel/Fooocus/discussions/117) Also, [click here to browse the advanced features.](https://github.com/lllyasviel/Fooocus/discussions/117)
# Download # Download
@@ -119,7 +109,7 @@ See also the common problems and troubleshoots [here](troubleshoot.md).
### Colab ### Colab
(Last tested - 2024 Mar 18 by [mashb1t](https://github.com/mashb1t)) (Last tested - 2024 Aug 12 by [mashb1t](https://github.com/mashb1t))
| Colab | Info | Colab | Info
| --- | --- | | --- | --- |
@@ -225,7 +215,7 @@ Then run the `run.bat`.
AMD is not intensively tested, however. The AMD support is in beta. AMD is not intensively tested, however. The AMD support is in beta.
For AMD, use `.\python_embeded\python.exe entry_with_update.py --directml --preset anime` or `.\python_embeded\python.exe entry_with_update.py --directml --preset realistic` for Fooocus Anime/Realistic Edition. For AMD, use `.\python_embeded\python.exe Fooocus\entry_with_update.py --directml --preset anime` or `.\python_embeded\python.exe Fooocus\entry_with_update.py --directml --preset realistic` for Fooocus Anime/Realistic Edition.
### Mac ### Mac
@@ -303,7 +293,8 @@ In both ways the access is unauthenticated by default. You can add basic authent
## List of "Hidden" Tricks ## List of "Hidden" Tricks
<a name="tech_list"></a> <a name="tech_list"></a>
The below things are already inside the software, and **users do not need to do anything about these**. <details>
<summary>Click to see a list of tricks. Those are based on SDXL and are not very up-to-date with latest models.</summary>
1. GPT2-based [prompt expansion as a dynamic style "Fooocus V2".](https://github.com/lllyasviel/Fooocus/discussions/117#raw) (similar to Midjourney's hidden pre-processing and "raw" mode, or the LeonardoAI's Prompt Magic). 1. GPT2-based [prompt expansion as a dynamic style "Fooocus V2".](https://github.com/lllyasviel/Fooocus/discussions/117#raw) (similar to Midjourney's hidden pre-processing and "raw" mode, or the LeonardoAI's Prompt Magic).
2. Native refiner swap inside one single k-sampler. The advantage is that the refiner model can now reuse the base model's momentum (or ODE's history parameters) collected from k-sampling to achieve more coherent sampling. In Automatic1111's high-res fix and ComfyUI's node system, the base model and refiner use two independent k-samplers, which means the momentum is largely wasted, and the sampling continuity is broken. Fooocus uses its own advanced k-diffusion sampling that ensures seamless, native, and continuous swap in a refiner setup. (Update Aug 13: Actually, I discussed this with Automatic1111 several days ago, and it seems that the “native refiner swap inside one single k-sampler” is [merged]( https://github.com/AUTOMATIC1111/stable-diffusion-webui/pull/12371) into the dev branch of webui. Great!) 2. Native refiner swap inside one single k-sampler. The advantage is that the refiner model can now reuse the base model's momentum (or ODE's history parameters) collected from k-sampling to achieve more coherent sampling. In Automatic1111's high-res fix and ComfyUI's node system, the base model and refiner use two independent k-samplers, which means the momentum is largely wasted, and the sampling continuity is broken. Fooocus uses its own advanced k-diffusion sampling that ensures seamless, native, and continuous swap in a refiner setup. (Update Aug 13: Actually, I discussed this with Automatic1111 several days ago, and it seems that the “native refiner swap inside one single k-sampler” is [merged]( https://github.com/AUTOMATIC1111/stable-diffusion-webui/pull/12371) into the dev branch of webui. Great!)
@@ -319,6 +310,7 @@ The below things are already inside the software, and **users do not need to do
12. Using automatic1111's method to normalize prompt emphasizing. This significantly improves results when users directly copy prompts from civitai. 12. Using automatic1111's method to normalize prompt emphasizing. This significantly improves results when users directly copy prompts from civitai.
13. The joint swap system of the refiner now also supports img2img and upscale in a seamless way. 13. The joint swap system of the refiner now also supports img2img and upscale in a seamless way.
14. CFG Scale and TSNR correction (tuned for SDXL) when CFG is bigger than 10. 14. CFG Scale and TSNR correction (tuned for SDXL) when CFG is bigger than 10.
</details>
## Customization ## Customization
@@ -371,9 +363,8 @@ entry_with_update.py [-h] [--listen [IP]] [--port PORT]
[--hf-mirror HF_MIRROR] [--hf-mirror HF_MIRROR]
[--external-working-path PATH [PATH ...]] [--external-working-path PATH [PATH ...]]
[--output-path OUTPUT_PATH] [--output-path OUTPUT_PATH]
[--temp-path TEMP_PATH] [--temp-path TEMP_PATH] [--cache-path CACHE_PATH]
[--cache-path CACHE_PATH] [--in-browser] [--in-browser] [--disable-in-browser]
[--disable-in-browser]
[--gpu-device-id DEVICE_ID] [--gpu-device-id DEVICE_ID]
[--async-cuda-allocation | --disable-async-cuda-allocation] [--async-cuda-allocation | --disable-async-cuda-allocation]
[--disable-attention-upcast] [--disable-attention-upcast]
@@ -387,8 +378,7 @@ entry_with_update.py [-h] [--listen [IP]] [--port PORT]
[--preview-option [none,auto,fast,taesd]] [--preview-option [none,auto,fast,taesd]]
[--attention-split | --attention-quad | --attention-pytorch] [--attention-split | --attention-quad | --attention-pytorch]
[--disable-xformers] [--disable-xformers]
[--always-gpu | --always-high-vram | --always-normal-vram | [--always-gpu | --always-high-vram | --always-normal-vram | --always-low-vram | --always-no-vram | --always-cpu [CPU_NUM_THREADS]]
--always-low-vram | --always-no-vram | --always-cpu [CPU_NUM_THREADS]]
[--always-offload-from-vram] [--always-offload-from-vram]
[--pytorch-deterministic] [--disable-server-log] [--pytorch-deterministic] [--disable-server-log]
[--debug-mode] [--is-windows-embedded-python] [--debug-mode] [--is-windows-embedded-python]
@@ -398,25 +388,65 @@ entry_with_update.py [-h] [--listen [IP]] [--port PORT]
[--disable-offload-from-vram] [--theme THEME] [--disable-offload-from-vram] [--theme THEME]
[--disable-image-log] [--disable-analytics] [--disable-image-log] [--disable-analytics]
[--disable-metadata] [--disable-preset-download] [--disable-metadata] [--disable-preset-download]
[--enable-describe-uov-image] [--disable-enhance-output-sorting]
[--enable-auto-describe-image]
[--always-download-new-model] [--always-download-new-model]
[--rebuild-hash-cache [CPU_NUM_THREADS]]
``` ```
## Inline Prompt Features
### Wildcards
Example prompt: `__color__ flower`
Processed for positive and negative prompt.
Selects a random wildcard from a predefined list of options, in this case the `wildcards/color.txt` file.
The wildcard will be replaced with a random color (randomness based on seed).
You can also disable randomness and process a wildcard file from top to bottom by enabling the checkbox `Read wildcards in order` in Developer Debug Mode.
Wildcards can be nested and combined, and multiple wildcards can be used in the same prompt (example see `wildcards/color_flower.txt`).
### Array Processing
Example prompt: `[[red, green, blue]] flower`
Processed only for positive prompt.
Processes the array from left to right, generating a separate image for each element in the array. In this case 3 images would be generated, one for each color.
Increase the image number to 3 to generate all 3 variants.
Arrays can not be nested, but multiple arrays can be used in the same prompt.
Does support inline LoRAs as array elements!
### Inline LoRAs
Example prompt: `flower <lora:sunflowers:1.2>`
Processed only for positive prompt.
Applies a LoRA to the prompt. The LoRA file must be located in the `models/loras` directory.
## Advanced Features ## Advanced Features
[Click here to browse the advanced features.](https://github.com/lllyasviel/Fooocus/discussions/117) [Click here to browse the advanced features.](https://github.com/lllyasviel/Fooocus/discussions/117)
Fooocus also has many community forks, just like SD-WebUI's [vladmandic/automatic](https://github.com/vladmandic/automatic) and [anapnoe/stable-diffusion-webui-ux](https://github.com/anapnoe/stable-diffusion-webui-ux), for enthusiastic users who want to try! ## Forks
Below are some Forks to Fooocus:
| Fooocus' forks | | Fooocus' forks |
| - | | - |
| [fenneishi/Fooocus-Control](https://github.com/fenneishi/Fooocus-Control) </br>[runew0lf/RuinedFooocus](https://github.com/runew0lf/RuinedFooocus) </br> [MoonRide303/Fooocus-MRE](https://github.com/MoonRide303/Fooocus-MRE) </br> [metercai/SimpleSDXL](https://github.com/metercai/SimpleSDXL) </br> and so on ... | | [fenneishi/Fooocus-Control](https://github.com/fenneishi/Fooocus-Control) </br>[runew0lf/RuinedFooocus](https://github.com/runew0lf/RuinedFooocus) </br> [MoonRide303/Fooocus-MRE](https://github.com/MoonRide303/Fooocus-MRE) </br> [mashb1t/Fooocus](https://github.com/mashb1t/Fooocus) </br> and so on ... |
See also [About Forking and Promotion of Forks](https://github.com/lllyasviel/Fooocus/discussions/699).
## Thanks ## Thanks
Special thanks to [twri](https://github.com/twri) and [3Diva](https://github.com/3Diva) and [Marc K3nt3L](https://github.com/K3nt3L) for creating additional SDXL styles available in Fooocus. Thanks [daswer123](https://github.com/daswer123) for contributing the Canvas Zoom! Many thanks to [twri](https://github.com/twri) and [3Diva](https://github.com/3Diva) and [Marc K3nt3L](https://github.com/K3nt3L) for creating additional SDXL styles available in Fooocus.
The project starts from a mixture of [Stable Diffusion WebUI](https://github.com/AUTOMATIC1111/stable-diffusion-webui) and [ComfyUI](https://github.com/comfyanonymous/ComfyUI) codebases.
Also, thanks [daswer123](https://github.com/daswer123) for contributing the Canvas Zoom!
## Update Log ## Update Log
@@ -424,8 +454,6 @@ The log is [here](update_log.md).
## Localization/Translation/I18N ## Localization/Translation/I18N
**We need your help!** Please help translate Fooocus into international languages.
You can put json files in the `language` folder to translate the user interface. You can put json files in the `language` folder to translate the user interface.
For example, below is the content of `Fooocus/language/example.json`: For example, below is the content of `Fooocus/language/example.json`:
+30
View File
@@ -1,3 +1,33 @@
# [2.5.5](https://github.com/lllyasviel/Fooocus/releases/tag/v2.5.5)
* Fix colab inpaint issue by moving an import statement
# [2.5.4](https://github.com/lllyasviel/Fooocus/releases/tag/v2.5.4)
* Fix validation for default_ip_image_* and default_inpaint_mask_sam_model
* Fix enhance mask debugging in combination with image sorting
* Fix loading of checkpoints and LoRAs when using multiple directories in config and then switching presets
# [2.5.3](https://github.com/lllyasviel/Fooocus/releases/tag/v2.5.3)
* Only load weights from non-safetensors files, preventing harmful code injection
* Add checkbox for applying/resetting styles when describing images, also allowing multiple describe content types
# [2.5.2](https://github.com/lllyasviel/Fooocus/releases/tag/v2.5.2)
* Fix not adding positive prompt when styles didn't have a {prompt} placeholder in the positive prompt
* Extend config settings for input image, see list in [PR](https://github.com/lllyasviel/Fooocus/pull/3382)
# [2.5.1](https://github.com/lllyasviel/Fooocus/releases/tag/v2.5.1)
* Update download URL in readme
* Increase speed of metadata loading
* Fix reading of metadata from jpeg, jpg and webp (exif)
* Fix debug preprocessor
* Update attributes and add inline prompt features section to readme
* Add checkbox, config and handling for saving only the final enhanced image. Use config `default_save_only_final_enhanced_image`, default False.
* Add sorting of final images when enhanced is enabled. Use argument `--disable-enhance-output-sorting` to disable.
# [2.5.0](https://github.com/lllyasviel/Fooocus/releases/tag/v2.5.0) # [2.5.0](https://github.com/lllyasviel/Fooocus/releases/tag/v2.5.0)
This version includes various package updates. If the auto-update doesn't work you can do one of the following: This version includes various package updates. If the auto-update doesn't work you can do one of the following:
+108 -55
View File
@@ -73,6 +73,9 @@ def generate_clicked(task: worker.AsyncTask):
gr.update(visible=True, value=product), \ gr.update(visible=True, value=product), \
gr.update(visible=False) gr.update(visible=False)
if flag == 'finish': if flag == 'finish':
if not args_manager.args.disable_enhance_output_sorting:
product = sort_enhance_images(product, task)
yield gr.update(visible=False), \ yield gr.update(visible=False), \
gr.update(visible=False), \ gr.update(visible=False), \
gr.update(visible=False), \ gr.update(visible=False), \
@@ -90,6 +93,25 @@ def generate_clicked(task: worker.AsyncTask):
return return
def sort_enhance_images(images, task):
if not task.should_enhance or len(images) <= task.images_to_enhance_count:
return images
sorted_images = []
walk_index = task.images_to_enhance_count
for index, enhanced_img in enumerate(images[:task.images_to_enhance_count]):
sorted_images.append(enhanced_img)
if index not in task.enhance_stats:
continue
target_index = walk_index + task.enhance_stats[index]
if walk_index < len(images) and target_index <= len(images):
sorted_images += images[walk_index:target_index]
walk_index += task.enhance_stats[index]
return sorted_images
def inpaint_mode_change(mode, inpaint_engine_version): def inpaint_mode_change(mode, inpaint_engine_version):
assert mode in modules.flags.inpaint_options assert mode in modules.flags.inpaint_options
@@ -178,19 +200,19 @@ with shared.gradio_root:
stop_button.click(stop_clicked, inputs=currentTask, outputs=currentTask, queue=False, show_progress=False, _js='cancelGenerateForever') stop_button.click(stop_clicked, inputs=currentTask, outputs=currentTask, queue=False, show_progress=False, _js='cancelGenerateForever')
skip_button.click(skip_clicked, inputs=currentTask, outputs=currentTask, queue=False, show_progress=False) skip_button.click(skip_clicked, inputs=currentTask, outputs=currentTask, queue=False, show_progress=False)
with gr.Row(elem_classes='advanced_check_row'): with gr.Row(elem_classes='advanced_check_row'):
input_image_checkbox = gr.Checkbox(label='Input Image', value=False, container=False, elem_classes='min_check') input_image_checkbox = gr.Checkbox(label='Input Image', value=modules.config.default_image_prompt_checkbox, container=False, elem_classes='min_check')
enhance_checkbox = gr.Checkbox(label='Enhance', value=modules.config.default_enhance_checkbox, container=False, elem_classes='min_check') enhance_checkbox = gr.Checkbox(label='Enhance', value=modules.config.default_enhance_checkbox, container=False, elem_classes='min_check')
advanced_checkbox = gr.Checkbox(label='Advanced', value=modules.config.default_advanced_checkbox, container=False, elem_classes='min_check') advanced_checkbox = gr.Checkbox(label='Advanced', value=modules.config.default_advanced_checkbox, container=False, elem_classes='min_check')
with gr.Row(visible=False) as image_input_panel: with gr.Row(visible=modules.config.default_image_prompt_checkbox) as image_input_panel:
with gr.Tabs(): with gr.Tabs(selected=modules.config.default_selected_image_input_tab_id):
with gr.TabItem(label='Upscale or Variation') as uov_tab: with gr.Tab(label='Upscale or Variation', id='uov_tab') as uov_tab:
with gr.Row(): with gr.Row():
with gr.Column(): with gr.Column():
uov_input_image = grh.Image(label='Image', source='upload', type='numpy', show_label=False) uov_input_image = grh.Image(label='Image', source='upload', type='numpy', show_label=False)
with gr.Column(): with gr.Column():
uov_method = gr.Radio(label='Upscale or Variation:', choices=flags.uov_list, value=flags.disabled) uov_method = gr.Radio(label='Upscale or Variation:', choices=flags.uov_list, value=modules.config.default_uov_method)
gr.HTML('<a href="https://github.com/lllyasviel/Fooocus/discussions/390" target="_blank">\U0001F4D4 Documentation</a>') gr.HTML('<a href="https://github.com/lllyasviel/Fooocus/discussions/390" target="_blank">\U0001F4D4 Documentation</a>')
with gr.TabItem(label='Image Prompt') as ip_tab: with gr.Tab(label='Image Prompt', id='ip_tab') as ip_tab:
with gr.Row(): with gr.Row():
ip_images = [] ip_images = []
ip_types = [] ip_types = []
@@ -198,30 +220,29 @@ with shared.gradio_root:
ip_weights = [] ip_weights = []
ip_ctrls = [] ip_ctrls = []
ip_ad_cols = [] ip_ad_cols = []
for _ in range(flags.controlnet_image_count): for image_count in range(modules.config.default_controlnet_image_count):
image_count += 1
with gr.Column(): with gr.Column():
ip_image = grh.Image(label='Image', source='upload', type='numpy', show_label=False, height=300) ip_image = grh.Image(label='Image', source='upload', type='numpy', show_label=False, height=300, value=modules.config.default_ip_images[image_count])
ip_images.append(ip_image) ip_images.append(ip_image)
ip_ctrls.append(ip_image) ip_ctrls.append(ip_image)
with gr.Column(visible=False) as ad_col: with gr.Column(visible=modules.config.default_image_prompt_advanced_checkbox) as ad_col:
with gr.Row(): with gr.Row():
default_end, default_weight = flags.default_parameters[flags.default_ip] ip_stop = gr.Slider(label='Stop At', minimum=0.0, maximum=1.0, step=0.001, value=modules.config.default_ip_stop_ats[image_count])
ip_stop = gr.Slider(label='Stop At', minimum=0.0, maximum=1.0, step=0.001, value=default_end)
ip_stops.append(ip_stop) ip_stops.append(ip_stop)
ip_ctrls.append(ip_stop) ip_ctrls.append(ip_stop)
ip_weight = gr.Slider(label='Weight', minimum=0.0, maximum=2.0, step=0.001, value=default_weight) ip_weight = gr.Slider(label='Weight', minimum=0.0, maximum=2.0, step=0.001, value=modules.config.default_ip_weights[image_count])
ip_weights.append(ip_weight) ip_weights.append(ip_weight)
ip_ctrls.append(ip_weight) ip_ctrls.append(ip_weight)
ip_type = gr.Radio(label='Type', choices=flags.ip_list, value=flags.default_ip, container=False) ip_type = gr.Radio(label='Type', choices=flags.ip_list, value=modules.config.default_ip_types[image_count], container=False)
ip_types.append(ip_type) ip_types.append(ip_type)
ip_ctrls.append(ip_type) ip_ctrls.append(ip_type)
ip_type.change(lambda x: flags.default_parameters[x], inputs=[ip_type], outputs=[ip_stop, ip_weight], queue=False, show_progress=False) ip_type.change(lambda x: flags.default_parameters[x], inputs=[ip_type], outputs=[ip_stop, ip_weight], queue=False, show_progress=False)
ip_ad_cols.append(ad_col) ip_ad_cols.append(ad_col)
ip_advanced = gr.Checkbox(label='Advanced', value=False, container=False) ip_advanced = gr.Checkbox(label='Advanced', value=modules.config.default_image_prompt_advanced_checkbox, container=False)
gr.HTML('* \"Image Prompt\" is powered by Fooocus Image Mixture Engine (v1.0.1). <a href="https://github.com/lllyasviel/Fooocus/discussions/557" target="_blank">\U0001F4D4 Documentation</a>') gr.HTML('* \"Image Prompt\" is powered by Fooocus Image Mixture Engine (v1.0.1). <a href="https://github.com/lllyasviel/Fooocus/discussions/557" target="_blank">\U0001F4D4 Documentation</a>')
def ip_advance_checked(x): def ip_advance_checked(x):
@@ -234,11 +255,11 @@ with shared.gradio_root:
outputs=ip_ad_cols + ip_types + ip_stops + ip_weights, outputs=ip_ad_cols + ip_types + ip_stops + ip_weights,
queue=False, show_progress=False) queue=False, show_progress=False)
with gr.TabItem(label='Inpaint or Outpaint') as inpaint_tab: with gr.Tab(label='Inpaint or Outpaint', id='inpaint_tab') as inpaint_tab:
with gr.Row(): with gr.Row():
with gr.Column(): with gr.Column():
inpaint_input_image = grh.Image(label='Image', source='upload', type='numpy', tool='sketch', height=500, brush_color="#FFFFFF", elem_id='inpaint_canvas', show_label=False) inpaint_input_image = grh.Image(label='Image', source='upload', type='numpy', tool='sketch', height=500, brush_color="#FFFFFF", elem_id='inpaint_canvas', show_label=False)
inpaint_advanced_masking_checkbox = gr.Checkbox(label='Enable Advanced Masking Features', value=False) inpaint_advanced_masking_checkbox = gr.Checkbox(label='Enable Advanced Masking Features', value=modules.config.default_inpaint_advanced_masking_checkbox)
inpaint_mode = gr.Dropdown(choices=modules.flags.inpaint_options, value=modules.config.default_inpaint_method, label='Method') inpaint_mode = gr.Dropdown(choices=modules.flags.inpaint_options, value=modules.config.default_inpaint_method, label='Method')
inpaint_additional_prompt = gr.Textbox(placeholder="Describe what you want to inpaint.", elem_id='inpaint_additional_prompt', label='Inpaint Additional Prompt', visible=False) inpaint_additional_prompt = gr.Textbox(placeholder="Describe what you want to inpaint.", elem_id='inpaint_additional_prompt', label='Inpaint Additional Prompt', visible=False)
outpaint_selections = gr.CheckboxGroup(choices=['Left', 'Right', 'Top', 'Bottom'], value=[], label='Outpaint Direction') outpaint_selections = gr.CheckboxGroup(choices=['Left', 'Right', 'Top', 'Bottom'], value=[], label='Outpaint Direction')
@@ -249,9 +270,9 @@ with shared.gradio_root:
gr.HTML('* Powered by Fooocus Inpaint Engine <a href="https://github.com/lllyasviel/Fooocus/discussions/414" target="_blank">\U0001F4D4 Documentation</a>') gr.HTML('* Powered by Fooocus Inpaint Engine <a href="https://github.com/lllyasviel/Fooocus/discussions/414" target="_blank">\U0001F4D4 Documentation</a>')
example_inpaint_prompts.click(lambda x: x[0], inputs=example_inpaint_prompts, outputs=inpaint_additional_prompt, show_progress=False, queue=False) example_inpaint_prompts.click(lambda x: x[0], inputs=example_inpaint_prompts, outputs=inpaint_additional_prompt, show_progress=False, queue=False)
with gr.Column(visible=False) as inpaint_mask_generation_col: with gr.Column(visible=modules.config.default_inpaint_advanced_masking_checkbox) as inpaint_mask_generation_col:
inpaint_mask_image = grh.Image(label='Mask Upload', source='upload', type='numpy', tool='sketch', height=500, brush_color="#FFFFFF", mask_opacity=1, elem_id='inpaint_mask_canvas') inpaint_mask_image = grh.Image(label='Mask Upload', source='upload', type='numpy', tool='sketch', height=500, brush_color="#FFFFFF", mask_opacity=1, elem_id='inpaint_mask_canvas')
invert_mask_checkbox = gr.Checkbox(label='Invert Mask When Generating', value=False) invert_mask_checkbox = gr.Checkbox(label='Invert Mask When Generating', value=modules.config.default_invert_mask_checkbox)
inpaint_mask_model = gr.Dropdown(label='Mask generation model', inpaint_mask_model = gr.Dropdown(label='Mask generation model',
choices=flags.inpaint_mask_models, choices=flags.inpaint_mask_models,
value=modules.config.default_inpaint_mask_model) value=modules.config.default_inpaint_mask_model)
@@ -311,40 +332,41 @@ with shared.gradio_root:
example_inpaint_mask_dino_prompt_text], example_inpaint_mask_dino_prompt_text],
queue=False, show_progress=False) queue=False, show_progress=False)
with gr.TabItem(label='Describe') as desc_tab: with gr.Tab(label='Describe', id='describe_tab') as describe_tab:
with gr.Row(): with gr.Row():
with gr.Column(): with gr.Column():
desc_input_image = grh.Image(label='Image', source='upload', type='numpy', show_label=False) describe_input_image = grh.Image(label='Image', source='upload', type='numpy', show_label=False)
with gr.Column(): with gr.Column():
desc_method = gr.Radio( describe_methods = gr.CheckboxGroup(
label='Content Type', label='Content Type',
choices=[flags.desc_type_photo, flags.desc_type_anime], choices=flags.describe_types,
value=flags.desc_type_photo) value=modules.config.default_describe_content_type)
desc_btn = gr.Button(value='Describe this Image into Prompt') describe_apply_styles = gr.Checkbox(label='Apply Styles', value=modules.config.default_describe_apply_prompts_checkbox)
desc_image_size = gr.Textbox(label='Image Size and Recommended Size', elem_id='desc_image_size', visible=False) describe_btn = gr.Button(value='Describe this Image into Prompt')
describe_image_size = gr.Textbox(label='Image Size and Recommended Size', elem_id='describe_image_size', visible=False)
gr.HTML('<a href="https://github.com/lllyasviel/Fooocus/discussions/1363" target="_blank">\U0001F4D4 Documentation</a>') gr.HTML('<a href="https://github.com/lllyasviel/Fooocus/discussions/1363" target="_blank">\U0001F4D4 Documentation</a>')
def trigger_show_image_properties(image): def trigger_show_image_properties(image):
value = modules.util.get_image_size_info(image, modules.flags.sdxl_aspect_ratios) value = modules.util.get_image_size_info(image, modules.flags.sdxl_aspect_ratios)
return gr.update(value=value, visible=True) return gr.update(value=value, visible=True)
desc_input_image.upload(trigger_show_image_properties, inputs=desc_input_image, describe_input_image.upload(trigger_show_image_properties, inputs=describe_input_image,
outputs=desc_image_size, show_progress=False, queue=False) outputs=describe_image_size, show_progress=False, queue=False)
with gr.TabItem(label='Enhance') as enhance_tab: with gr.Tab(label='Enhance', id='enhance_tab') as enhance_tab:
with gr.Row(): with gr.Row():
with gr.Column(): with gr.Column():
enhance_input_image = grh.Image(label='Use with Enhance, skips image generation', source='upload', type='numpy') enhance_input_image = grh.Image(label='Use with Enhance, skips image generation', source='upload', type='numpy')
gr.HTML('<a href="https://github.com/lllyasviel/Fooocus/discussions/3281" target="_blank">\U0001F4D4 Documentation</a>') gr.HTML('<a href="https://github.com/lllyasviel/Fooocus/discussions/3281" target="_blank">\U0001F4D4 Documentation</a>')
with gr.TabItem(label='Metadata') as metadata_tab: with gr.Tab(label='Metadata', id='metadata_tab') as metadata_tab:
with gr.Column(): with gr.Column():
metadata_input_image = grh.Image(label='For images created by Fooocus', source='upload', type='filepath') metadata_input_image = grh.Image(label='For images created by Fooocus', source='upload', type='pil')
metadata_json = gr.JSON(label='Metadata') metadata_json = gr.JSON(label='Metadata')
metadata_import_button = gr.Button(value='Apply Metadata') metadata_import_button = gr.Button(value='Apply Metadata')
def trigger_metadata_preview(filepath): def trigger_metadata_preview(file):
parameters, metadata_scheme = modules.meta_parser.read_info_from_image(filepath) parameters, metadata_scheme = modules.meta_parser.read_info_from_image(file)
results = {} results = {}
if parameters is not None: if parameters is not None:
@@ -360,7 +382,7 @@ with shared.gradio_root:
with gr.Row(visible=modules.config.default_enhance_checkbox) as enhance_input_panel: with gr.Row(visible=modules.config.default_enhance_checkbox) as enhance_input_panel:
with gr.Tabs(): with gr.Tabs():
with gr.TabItem(label='Upscale or Variation'): with gr.Tab(label='Upscale or Variation'):
with gr.Row(): with gr.Row():
with gr.Column(): with gr.Column():
enhance_uov_method = gr.Radio(label='Upscale or Variation:', choices=flags.uov_list, enhance_uov_method = gr.Radio(label='Upscale or Variation:', choices=flags.uov_list,
@@ -385,7 +407,7 @@ with shared.gradio_root:
enhance_inpaint_engine_ctrls = [] enhance_inpaint_engine_ctrls = []
enhance_inpaint_update_ctrls = [] enhance_inpaint_update_ctrls = []
for index in range(modules.config.default_enhance_tabs): for index in range(modules.config.default_enhance_tabs):
with gr.TabItem(label=f'#{index + 1}') as enhance_tab_item: with gr.Tab(label=f'#{index + 1}') as enhance_tab_item:
enhance_enabled = gr.Checkbox(label='Enable', value=False, elem_classes='min_check', enhance_enabled = gr.Checkbox(label='Enable', value=False, elem_classes='min_check',
container=False) container=False)
@@ -527,7 +549,7 @@ with shared.gradio_root:
uov_tab.select(lambda: 'uov', outputs=current_tab, queue=False, _js=down_js, show_progress=False) uov_tab.select(lambda: 'uov', outputs=current_tab, queue=False, _js=down_js, show_progress=False)
inpaint_tab.select(lambda: 'inpaint', outputs=current_tab, queue=False, _js=down_js, show_progress=False) inpaint_tab.select(lambda: 'inpaint', outputs=current_tab, queue=False, _js=down_js, show_progress=False)
ip_tab.select(lambda: 'ip', outputs=current_tab, queue=False, _js=down_js, show_progress=False) ip_tab.select(lambda: 'ip', outputs=current_tab, queue=False, _js=down_js, show_progress=False)
desc_tab.select(lambda: 'desc', outputs=current_tab, queue=False, _js=down_js, show_progress=False) describe_tab.select(lambda: 'desc', outputs=current_tab, queue=False, _js=down_js, show_progress=False)
enhance_tab.select(lambda: 'enhance', outputs=current_tab, queue=False, _js=down_js, show_progress=False) enhance_tab.select(lambda: 'enhance', outputs=current_tab, queue=False, _js=down_js, show_progress=False)
metadata_tab.select(lambda: 'metadata', outputs=current_tab, queue=False, _js=down_js, show_progress=False) metadata_tab.select(lambda: 'metadata', outputs=current_tab, queue=False, _js=down_js, show_progress=False)
enhance_checkbox.change(lambda x: gr.update(visible=x), inputs=enhance_checkbox, enhance_checkbox.change(lambda x: gr.update(visible=x), inputs=enhance_checkbox,
@@ -671,9 +693,9 @@ with shared.gradio_root:
value=modules.config.default_sample_sharpness, value=modules.config.default_sample_sharpness,
info='Higher value means image and texture are sharper.') info='Higher value means image and texture are sharper.')
gr.HTML('<a href="https://github.com/lllyasviel/Fooocus/discussions/117" target="_blank">\U0001F4D4 Documentation</a>') gr.HTML('<a href="https://github.com/lllyasviel/Fooocus/discussions/117" target="_blank">\U0001F4D4 Documentation</a>')
dev_mode = gr.Checkbox(label='Developer Debug Mode', value=False, container=False) dev_mode = gr.Checkbox(label='Developer Debug Mode', value=modules.config.default_developer_debug_mode_checkbox, container=False)
with gr.Column(visible=False) as dev_tools: with gr.Column(visible=modules.config.default_developer_debug_mode_checkbox) as dev_tools:
with gr.Tab(label='Debug Tools'): with gr.Tab(label='Debug Tools'):
adm_scaler_positive = gr.Slider(label='Positive ADM Guidance Scaler', minimum=0.1, maximum=3.0, adm_scaler_positive = gr.Slider(label='Positive ADM Guidance Scaler', minimum=0.1, maximum=3.0,
step=0.001, value=1.5, info='The scaler multiplied to positive ADM (use 1.0 to disable). ') step=0.001, value=1.5, info='The scaler multiplied to positive ADM (use 1.0 to disable). ')
@@ -748,6 +770,10 @@ with shared.gradio_root:
inputs=black_out_nsfw, outputs=disable_preview, queue=False, inputs=black_out_nsfw, outputs=disable_preview, queue=False,
show_progress=False) show_progress=False)
if not args_manager.args.disable_image_log:
save_final_enhanced_image_only = gr.Checkbox(label='Save only final enhanced image',
value=modules.config.default_save_only_final_enhanced_image)
if not args_manager.args.disable_metadata: if not args_manager.args.disable_metadata:
save_metadata_to_images = gr.Checkbox(label='Save Metadata to Images', value=modules.config.default_save_metadata_to_images, save_metadata_to_images = gr.Checkbox(label='Save Metadata to Images', value=modules.config.default_save_metadata_to_images,
info='Adds parameters to generated images allowing manual regeneration.') info='Adds parameters to generated images allowing manual regeneration.')
@@ -969,6 +995,9 @@ with shared.gradio_root:
ctrls += freeu_ctrls ctrls += freeu_ctrls
ctrls += inpaint_ctrls ctrls += inpaint_ctrls
if not args_manager.args.disable_image_log:
ctrls += [save_final_enhanced_image_only]
if not args_manager.args.disable_metadata: if not args_manager.args.disable_metadata:
ctrls += [save_metadata_to_images, metadata_scheme] ctrls += [save_metadata_to_images, metadata_scheme]
@@ -995,8 +1024,8 @@ with shared.gradio_root:
load_parameter_button.click(modules.meta_parser.load_parameter_button_click, inputs=[prompt, state_is_generating, inpaint_mode], outputs=load_data_outputs, queue=False, show_progress=False) load_parameter_button.click(modules.meta_parser.load_parameter_button_click, inputs=[prompt, state_is_generating, inpaint_mode], outputs=load_data_outputs, queue=False, show_progress=False)
def trigger_metadata_import(filepath, state_is_generating): def trigger_metadata_import(file, state_is_generating):
parameters, metadata_scheme = modules.meta_parser.read_info_from_image(filepath) parameters, metadata_scheme = modules.meta_parser.read_info_from_image(file)
if parameters is None: if parameters is None:
print('Could not find metadata in the image!') print('Could not find metadata in the image!')
parsed_parameters = {} parsed_parameters = {}
@@ -1032,30 +1061,54 @@ with shared.gradio_root:
gr.Audio(interactive=False, value=notification_file, elem_id='audio_notification', visible=False) gr.Audio(interactive=False, value=notification_file, elem_id='audio_notification', visible=False)
break break
def trigger_describe(mode, img): def trigger_describe(modes, img, apply_styles):
if mode == flags.desc_type_photo: describe_prompts = []
from extras.interrogate import default_interrogator as default_interrogator_photo styles = set()
return default_interrogator_photo(img), ["Fooocus V2", "Fooocus Enhance", "Fooocus Sharp"]
if mode == flags.desc_type_anime:
from extras.wd14tagger import default_interrogator as default_interrogator_anime
return default_interrogator_anime(img), ["Fooocus V2", "Fooocus Masterpiece"]
return mode, ["Fooocus V2"]
desc_btn.click(trigger_describe, inputs=[desc_method, desc_input_image], if flags.describe_type_photo in modes:
outputs=[prompt, style_selections], show_progress=True, queue=True) from extras.interrogate import default_interrogator as default_interrogator_photo
describe_prompts.append(default_interrogator_photo(img))
styles.update(["Fooocus V2", "Fooocus Enhance", "Fooocus Sharp"])
if flags.describe_type_anime in modes:
from extras.wd14tagger import default_interrogator as default_interrogator_anime
describe_prompts.append(default_interrogator_anime(img))
styles.update(["Fooocus V2", "Fooocus Masterpiece"])
if len(styles) == 0 or not apply_styles:
styles = gr.update()
else:
styles = list(styles)
if len(describe_prompts) == 0:
describe_prompt = gr.update()
else:
describe_prompt = ', '.join(describe_prompts)
return describe_prompt, styles
describe_btn.click(trigger_describe, inputs=[describe_methods, describe_input_image, describe_apply_styles],
outputs=[prompt, style_selections], show_progress=True, queue=True) \
.then(fn=style_sorter.sort_styles, inputs=style_selections, outputs=style_selections, queue=False, show_progress=False) \
.then(lambda: None, _js='()=>{refresh_style_localization();}')
if args_manager.args.enable_auto_describe_image: if args_manager.args.enable_auto_describe_image:
def trigger_auto_describe(mode, img, prompt): def trigger_auto_describe(mode, img, prompt, apply_styles):
# keep prompt if not empty # keep prompt if not empty
if prompt == '': if prompt == '':
return trigger_describe(mode, img) return trigger_describe(mode, img, apply_styles)
return gr.update(), gr.update() return gr.update(), gr.update()
uov_input_image.upload(trigger_auto_describe, inputs=[desc_method, uov_input_image, prompt], uov_input_image.upload(trigger_auto_describe, inputs=[describe_methods, uov_input_image, prompt, describe_apply_styles],
outputs=[prompt, style_selections], show_progress=True, queue=True) outputs=[prompt, style_selections], show_progress=True, queue=True) \
.then(fn=style_sorter.sort_styles, inputs=style_selections, outputs=style_selections, queue=False, show_progress=False) \
.then(lambda: None, _js='()=>{refresh_style_localization();}')
enhance_input_image.upload(lambda: gr.update(value=True), outputs=enhance_checkbox, queue=False, show_progress=False) \ enhance_input_image.upload(lambda: gr.update(value=True), outputs=enhance_checkbox, queue=False, show_progress=False) \
.then(trigger_auto_describe, inputs=[desc_method, enhance_input_image, prompt], outputs=[prompt, style_selections], show_progress=True, queue=True) .then(trigger_auto_describe, inputs=[describe_methods, enhance_input_image, prompt, describe_apply_styles],
outputs=[prompt, style_selections], show_progress=True, queue=True) \
.then(fn=style_sorter.sort_styles, inputs=style_selections, outputs=style_selections, queue=False, show_progress=False) \
.then(lambda: None, _js='()=>{refresh_style_localization();}')
def dump_default_english_config(): def dump_default_english_config():
from modules.localization import dump_english_config from modules.localization import dump_english_config