Compare commits

...
Author SHA1 Message Date
dependabot[bot] e6236ce525 chore(deps): bump actions/checkout from 5 to 6
Bumps [actions/checkout](https://github.com/actions/checkout) from 5 to 6.
- [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/v5...v6)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-12-01 19:17:07 +00:00
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
Manuel Schmid f97adafc09 Merge pull request #3292 from lllyasviel/develop
Release v2.5.0
2024-07-17 12:18:08 +02:00
Manuel Schmid 97a8475a62 feat: revert disabling persistent style sorting, code cleanup 2024-07-17 12:04:34 +02:00
Manuel Schmid 033cb90e6e feat: revert adding issue templates 2024-07-17 11:52:20 +02:00
Manuel Schmid aed3240ccd feat: revert adding audio tab 2024-07-17 11:45:27 +02:00
Manuel Schmid 4f12bbb02b docs: add instructions how to manually update packages, update download URL in readme 2024-07-17 11:37:21 +02:00
Manuel Schmid 9f93cf6110 fix: resolve circular dependency for sha256, update files and init cache after initial model download
fixes https://github.com/lllyasviel/Fooocus/issues/2372

(cherry picked from commit 5c43a4bece)
2024-07-17 10:51:50 +02:00
Manuel Schmid 1f429ffeda release: bump version to 2.5.0, update changelog 2024-07-17 10:30:58 +02:00
Manuel Schmid 8d67166dd1 chore: use opencv-contrib-python-headless
https://github.com/lllyasviel/Fooocus/pull/1964
(cherry picked from commit 1f32f9f4ab)
2024-07-16 19:56:39 +02:00
Manuel Schmid 3a86fa2f0d chore: update packages #2 2024-07-16 16:31:15 +02:00
Manuel Schmid ef8dd27f91 chore: update packages
see https://github.com/lllyasviel/Fooocus/pull/2927
2024-07-16 16:30:47 +02:00
Manuel Schmid d46e47ab3d feat: revert adding translate feature #2 2024-07-16 14:48:54 +02:00
Manuel Schmid 069bea534b feat: change example audio file
(cherry picked from commit 02b06ccb33)
2024-07-16 13:59:51 +02:00
39 changed files with 488 additions and 362 deletions
+1 -1
View File
@@ -1 +1 @@
* @mashb1t
* @lllyasviel
-77
View File
@@ -1,77 +0,0 @@
name: Bug Report
description: Describe a problem
title: "[Bug]: "
labels: ["bug", "triage"]
body:
- type: markdown
attributes:
value: |
Thank you for taking the time to fill out this bug report form!
- type: checkboxes
id: prerequisites
attributes:
label: Prerequisites
description: Please make sure to troubleshoot yourself before continuing.
options:
- label: I have read the [Troubleshooting Guide](https://github.com/lllyasviel/Fooocus/blob/main/troubleshoot.md)
required: true
- label: I have checked that this is not a duplicate of an already existing [issue](https://github.com/lllyasviel/Fooocus/issues)
required: true
- type: textarea
id: description
attributes:
label: Describe the problem
description: Also tell us, what did you expect to happen?
placeholder: "A clear and concise description of what the bug is."
validations:
required: true
- type: textarea
id: logs
attributes:
label: Full console log output
description: Please copy and paste the **full** console log here. You will make our job easier if you give a **full** log. This will be automatically formatted into code, so no need for backticks.
render: shell
validations:
required: true
- type: textarea
id: version
attributes:
label: Version
description: What version of Fooocus are you using? (see browser tab title or console log)
placeholder: "Example: Fooocus 2.1.855"
validations:
required: true
- type: dropdown
id: hosting
attributes:
label: Where are you running Fooocus?
multiple: false
options:
- Locally
- Locally with virtualisation (e.g. Docker)
- Cloud (Gradio)
- Cloud (other)
validations:
required: true
- type: input
id: operating-system
attributes:
label: Operating System
description: What operating system are you using?
placeholder: "Example: Windows 10"
- type: dropdown
id: browsers
attributes:
label: What browsers are you seeing the problem on?
multiple: true
options:
- Chrome
- Firefox
- Microsoft Edge
- Safari
- other
validations:
required: true
- type: markdown
attributes:
value: "Thank you for completing our form!"
+3 -3
View File
@@ -16,9 +16,9 @@ body:
description: |
Please perform basic debugging to see if your configuration is the cause of the issue.
Basic debug procedure
 2. 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
 5. Try a fresh installation of Fooocus in a different directory - see if a clean installation solves the issue
 1. Update Fooocus - sometimes things just need to be updated
 2. Backup and remove your config.txt - check if the issue is caused by bad configuration
 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.
options:
- label: The issue has not been resolved by following the [troubleshooting guide](https://github.com/lllyasviel/Fooocus/blob/main/troubleshoot.md)
@@ -1,34 +0,0 @@
name: Feature request
description: Suggest an idea for this project
title: "[Feature]: "
labels: ["enhancement"]
body:
- type: markdown
attributes:
value: |
Thank you for taking the time to fill out this feature request form!
- type: checkboxes
id: prerequisites
attributes:
label: Prerequisites
options:
- label: I have checked that this is not a duplicate of an already existing [feature request](https://github.com/lllyasviel/Fooocus/issues)
required: true
- type: textarea
id: relation-to-problem
attributes:
label: Is your feature request related to a problem? Please describe.
placeholder: "A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
."
validations:
required: true
- type: textarea
id: description
attributes:
label: Describe the idea you'd like
placeholder: "A clear and concise description of what you want to happen."
validations:
required: true
- type: markdown
attributes:
value: "Thank you for completing our form!"
+1 -1
View File
@@ -17,7 +17,7 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v6
- name: Log in to the Container registry
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("--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',
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',
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',
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):
if is_url(url_or_filename):
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):
checkpoint = torch.load(url_or_filename, map_location='cpu')
checkpoint = torch.load(url_or_filename, map_location='cpu', weights_only=True)
else:
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):
if is_url(url_or_filename):
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):
checkpoint = torch.load(url_or_filename, map_location='cpu')
checkpoint = torch.load(url_or_filename, map_location='cpu', weights_only=True)
else:
raise RuntimeError('checkpoint url or path is invalid')
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)
# 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.'
for k, v in deepcopy(load_net).items():
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(
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.eval()
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')
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"]
cross_attention_dim = ip_state_dict["ip_adapter"]["1.to_k_ip.weight"].shape[1]
sdxl = cross_attention_dim == 2048
+1 -1
View File
@@ -8,7 +8,7 @@
},
"outputs": [],
"source": [
"!pip install pygit2==1.12.2\n",
"!pip install pygit2==1.15.1\n",
"%cd /content\n",
"!git clone https://github.com/lllyasviel/Fooocus.git\n",
"%cd /content/Fooocus\n",
+1 -1
View File
@@ -1 +1 @@
version = '2.5.0-rc1'
version = '2.5.5'
+4
View File
@@ -17,6 +17,7 @@
"Content Type": "Content Type",
"Photograph": "Photograph",
"Art/Anime": "Art/Anime",
"Apply Styles": "Apply Styles",
"Describe this Image into Prompt": "Describe this Image into Prompt",
"Image Size and Recommended Size": "Image Size and Recommended Size",
"Upscale or Variation:": "Upscale or Variation:",
@@ -68,6 +69,9 @@
"Read wildcards in order": "Read wildcards in order",
"Black Out NSFW": "Black Out NSFW",
"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",
"Image Style": "Image Style",
"Fooocus V2": "Fooocus V2",
+14 -6
View File
@@ -21,7 +21,6 @@ import fooocus_version
from build_launcher import build_launcher
from modules.launch_util import is_installed, run, python, run_pip, requirements_met, delete_folder_content
from modules.model_loader import load_file_from_url
from modules import config
REINSTALL_ALL = False
TRY_INSTALL_XFORMERS = False
@@ -81,11 +80,13 @@ if args.gpu_device_id is not None:
os.environ['CUDA_VISIBLE_DEVICES'] = str(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)
print("Set hf_mirror to:", args.hf_mirror)
from modules import config
from modules.hash_cache import init_cache
os.environ["U2NET_HOME"] = config.path_inpaint
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):
from modules.util import get_file_from_folder_list
for file_name, url in vae_approx_filenames:
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
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:
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'Fooocus will use [{alternative_model_name}] to avoid downloading new 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
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():
load_file_from_url(url=url, model_dir=config.path_embeddings, file_name=file_name)
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():
load_file_from_url(url=url, model_dir=config.path_vae, file_name=file_name)
@@ -141,4 +146,7 @@ config.default_base_model_name, config.checkpoint_downloads = download_models(
config.default_base_model_name, config.previous_default_models, config.checkpoint_downloads,
config.embeddings_downloads, config.lora_downloads, config.vae_downloads)
config.update_files()
init_cache(config.model_filenames, config.paths_checkpoints, config.lora_filenames, config.paths_loras)
from webui import *
@@ -8,7 +8,7 @@ class CLIPEmbeddingNoiseAugmentation(ImageConcatWithNoiseAugmentation):
if clip_stats_path is None:
clip_mean, clip_std = torch.zeros(timestep_dim), torch.ones(timestep_dim)
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_std", clip_std[None, :], persistent=False)
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:
embed_out = safe_load_embed_zip(embed_path)
else:
embed = torch.load(embed_path, map_location="cpu")
embed = torch.load(embed_path, map_location="cpu", weights_only=True)
except Exception as e:
print(traceback.format_exc())
print()
@@ -377,15 +377,15 @@ class VQAutoEncoder(nn.Module):
)
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:
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]")
elif "params" in chkpt:
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]")
else:
@@ -273,8 +273,8 @@ class GFPGANBilinear(nn.Module):
if decoder_load_path:
self.stylegan_decoder.load_state_dict(
torch.load(
decoder_load_path, map_location=lambda storage, loc: storage
)["params_ema"]
decoder_load_path, map_location=lambda storage, loc: storage,
weights_only=True)["params_ema"]
)
# fix decoder without updating params
if fix_decoder:
@@ -373,8 +373,8 @@ class GFPGANv1(nn.Module):
if decoder_load_path:
self.stylegan_decoder.load_state_dict(
torch.load(
decoder_load_path, map_location=lambda storage, loc: storage
)["params_ema"]
decoder_load_path, map_location=lambda storage, loc: storage,
weights_only=True)["params_ema"]
)
# fix decoder without updating params
if fix_decoder:
@@ -284,8 +284,8 @@ class GFPGANv1Clean(nn.Module):
if decoder_load_path:
self.stylegan_decoder.load_state_dict(
torch.load(
decoder_load_path, map_location=lambda storage, loc: storage
)["params_ema"]
decoder_load_path, map_location=lambda storage, loc: storage,
weights_only=True)["params_ema"]
)
# fix decoder without updating params
if fix_decoder:
+59 -29
View File
@@ -9,7 +9,7 @@ patch_all()
class AsyncTask:
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.config import default_max_lora_number
import args_manager
@@ -95,12 +95,13 @@ class AsyncTask:
self.inpaint_advanced_masking_checkbox = args.pop()
self.invert_mask_checkbox = 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.metadata_scheme = MetadataScheme(
args.pop()) if not args_manager.args.disable_metadata else MetadataScheme.FOOOCUS
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_stop = args.pop()
cn_weight = args.pop()
@@ -153,12 +154,14 @@ class AsyncTask:
enhance_inpaint_erode_or_dilate,
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 = []
class EarlyReturnException:
class EarlyReturnException(BaseException):
pass
@@ -197,7 +200,6 @@ def worker():
from modules.upscaler import perform_upscale
from modules.flags import Performance
from modules.meta_parser import get_metadata_parser
from modules.translator import translate2en
pid = os.getpid()
print(f'Started worker with PID {pid}')
@@ -278,7 +280,7 @@ def worker():
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,
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:
ldm_patched.modules.model_management.interrupt_current_processing()
if 'cn' in goals:
@@ -315,9 +317,8 @@ def worker():
if modules.config.default_black_out_nsfw or async_task.black_out_nsfw:
progressbar(async_task, current_progress, 'Checking for NSFW content ...')
imgs = default_censor(imgs)
progressbar(async_task, current_progress,
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)
progressbar(async_task, current_progress, 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)
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)
@@ -333,7 +334,7 @@ def worker():
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 = []
for x in imgs:
d = [('Prompt', 'prompt', task['log_positive_prompt']),
@@ -388,7 +389,7 @@ def worker():
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))
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
@@ -688,13 +689,20 @@ def worker():
task_styles = async_task.style_selections.copy()
if use_style:
placeholder_replaced = False
for j, s in enumerate(task_styles):
if s == random_style_name:
s = get_random_style(task_rng)
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
negative_basic_workloads = negative_basic_workloads + n
if not placeholder_replaced:
positive_basic_workloads = [task_prompt] + positive_basic_workloads
else:
positive_basic_workloads.append(task_prompt)
@@ -959,7 +967,7 @@ def worker():
inpaint_engine, inpaint_respective_field, inpaint_strength,
prompt, negative_prompt, final_scheduler_name, goals, height, img, mask,
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 = []
inpaint_head_model_path = None
inpaint_parameterized = inpaint_engine != 'None' # inpaint_engine = None, improve detail
@@ -980,7 +988,7 @@ def worker():
progressbar(async_task, current_progress, 'Checking for NSFW content ...')
img = default_censor(img)
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,
do_not_show_finished_images=not show_intermediate_results or async_task.disable_intermediate_results)
return current_progress, img, prompt, negative_prompt
@@ -1014,7 +1022,8 @@ def worker():
final_scheduler_name, goals, initial_latent, steps, switch,
task_enhance['c'], task_enhance['uc'], task_enhance, loras,
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
return current_progress, imgs[0], prompt, negative_prompt
@@ -1022,7 +1031,7 @@ def worker():
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,
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
inpaint_worker.current_task = None
@@ -1040,7 +1049,7 @@ def worker():
controlnet_cpds_path, current_progress, current_task_id, denoising_strength, False,
'None', 0.0, 0.0, prompt, negative_prompt, final_scheduler_name,
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:
if async_task.last_stop == 'skip':
@@ -1157,6 +1166,8 @@ def worker():
current_progress += 1
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:
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,
@@ -1212,6 +1223,8 @@ def worker():
height, width, _ = async_task.enhance_input_image.shape
# input image already provided, processing is skipped
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
@@ -1262,8 +1275,8 @@ def worker():
int(current_progress + async_task.callback_steps),
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 should_enhance
show_intermediate_results = len(tasks) > 1 or async_task.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):
progressbar(async_task, current_progress, f'Preparing task {current_task_id + 1}/{async_task.image_number} ...')
@@ -1276,7 +1289,8 @@ def worker():
initial_latent, async_task.steps, switch, task['c'],
task['uc'], task, loras, tiled, use_expansion, width,
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))
images_to_enhance += imgs
@@ -1294,7 +1308,7 @@ def worker():
execution_time = time.perf_counter() - execution_start_time
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')
stop_processing(async_task, processing_start_time)
return
@@ -1303,9 +1317,14 @@ def worker():
active_enhance_tabs = len(async_task.enhance_ctrls)
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:
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
async_task.images_to_enhance_count = len(images_to_enhance)
base_progress = current_progress
current_task_id = -1
@@ -1313,19 +1332,23 @@ def worker():
done_steps_inpainting = 0
enhance_steps, _, _, _ = apply_overrides(async_task, async_task.original_steps, height, width)
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()
last_enhance_prompt = async_task.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
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(
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,
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':
continue
elif exception_result == 'break':
@@ -1337,6 +1360,8 @@ def worker():
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} ...')
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 = {}
if enhance_mask_model == 'sam':
@@ -1367,13 +1392,13 @@ def worker():
async_task.yields.append(['preview', (current_progress, 'Loading ...', mask)])
yield_result(async_task, mask, current_progress, async_task.black_out_nsfw, False,
async_task.disable_intermediate_results)
async_task.enhance_stats[index] += 1
print(f'[Enhance] {dino_detection_count} boxes detected')
print(f'[Enhance] {sam_detection_count} segments detected in boxes')
print(f'[Enhance] {sam_detection_on_mask_count} segments applied to mask')
if enhance_mask_model == 'sam' and (
dino_detection_count == 0 or not async_task.debugging_dino and sam_detection_on_mask_count == 0):
if enhance_mask_model == 'sam' and (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')
continue
@@ -1386,7 +1411,8 @@ def worker():
enhance_inpaint_engine, enhance_inpaint_respective_field, enhance_inpaint_strength,
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,
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
and async_task.enhance_uov_prompt_type == flags.enhancement_uov_prompt_type_last_filled):
@@ -1413,14 +1439,18 @@ def worker():
if exception_result == '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
# last step in enhance, always save
persist_image = True
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,
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,
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':
continue
elif exception_result == 'break':
+114 -12
View File
@@ -7,7 +7,6 @@ import args_manager
import tempfile
import modules.flags
import modules.sdxl_styles
from modules.hash_cache import init_cache
from modules.model_loader import load_file_from_url
from modules.extra_utils import makedirs_with_log, get_files_from_folder, try_eval_env_var
@@ -404,12 +403,36 @@ default_performance = get_config_item_or_set_default(
validator=lambda x: x in Performance.values(),
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(
key='default_advanced_checkbox',
default_value=False,
validator=lambda x: isinstance(x, 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(
key='default_max_image_number',
default_value=32,
@@ -470,6 +493,69 @@ default_inpaint_engine_version = get_config_item_or_set_default(
validator=lambda x: x in modules.flags.inpaint_engine_versions,
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(
key='default_inpaint_method',
default_value=modules.flags.inpaint_option_default,
@@ -527,12 +613,6 @@ default_enhance_tabs = get_config_item_or_set_default(
validator=lambda x: isinstance(x, int) and 1 <= x <= 5,
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(
key='default_enhance_uov_method',
default_value=modules.flags.disabled,
@@ -563,6 +643,12 @@ default_black_out_nsfw = get_config_item_or_set_default(
validator=lambda x: isinstance(x, 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(
key='default_save_metadata_to_images',
default_value=False,
@@ -585,6 +671,13 @@ metadata_created_by = get_config_item_or_set_default(
example_inpaint_prompts = [[x] for x in example_inpaint_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(
key='default_inpaint_mask_model',
default_value='isnet-general-use',
@@ -609,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(
key='default_inpaint_mask_sam_model',
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
)
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))]
# mapping config to meta parameter
@@ -889,7 +995,3 @@ def downloading_sam_vit_h():
file_name='sam_vit_h_4b8939.pth'
)
return os.path.join(path_sam, 'sam_vit_h_4b8939.pth')
update_files()
init_cache(model_filenames, paths_checkpoints, lora_filenames, paths_loras)
+1 -1
View File
@@ -231,7 +231,7 @@ def get_previewer(model):
if vae_approx_filename in VAE_approx_models:
VAE_approx_model = VAE_approx_models[vae_approx_filename]
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.load_state_dict(sd)
del sd
+6 -4
View File
@@ -67,6 +67,9 @@ default_vae = 'Default (model)'
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_face = "FaceSwap"
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_options = [inpaint_option_default, inpaint_option_detail, inpaint_option_modify]
desc_type_photo = 'Photograph'
desc_type_anime = 'Art/Anime'
describe_type_photo = 'Photograph'
describe_type_anime = 'Art/Anime'
describe_types = [describe_type_photo, describe_type_anime]
sdxl_aspect_ratios = [
'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),
]
controlnet_image_count = 4
class OutputFormat(Enum):
PNG = 'png'
+1 -2
View File
@@ -4,8 +4,7 @@ from concurrent.futures import ThreadPoolExecutor
from multiprocessing import cpu_count
import args_manager
from modules.util import get_file_from_folder_list
from modules.util import sha256, HASH_SHA256_LENGTH
from modules.util import sha256, HASH_SHA256_LENGTH, get_file_from_folder_list
hash_cache_filename = 'hash_cache.txt'
hash_cache = {}
+1 -1
View File
@@ -196,7 +196,7 @@ class InpaintWorker:
if inpaint_head_model is None:
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)
feed = torch.cat([
+3 -5
View File
@@ -9,7 +9,6 @@ from PIL import Image
import fooocus_version
import modules.config
import modules.sdxl_styles
from modules import hash_cache
from modules.flags import MetadataScheme, Performance, Steps
from modules.flags import SAMPLERS, CIVITAI_NO_KARRAS
from modules.hash_cache import sha256_from_cache
@@ -605,9 +604,8 @@ def get_metadata_parser(metadata_scheme: MetadataScheme) -> MetadataParser:
raise NotImplementedError
def read_info_from_image(filepath) -> tuple[str | None, MetadataScheme | None]:
with Image.open(filepath) as image:
items = (image.info or {}).copy()
def read_info_from_image(file) -> tuple[str | None, MetadataScheme | None]:
items = (file.info or {}).copy()
parameters = items.pop('parameters', None)
metadata_scheme = items.pop('fooocus_scheme', None)
@@ -616,7 +614,7 @@ def read_info_from_image(filepath) -> tuple[str | None, MetadataScheme | None]:
if parameters is not None and is_json(parameters):
parameters = json.loads(parameters)
elif exif is not None:
exif = image.getexif()
exif = file.getexif()
# 0x9286 = UserComment
parameters = exif.get(0x9286, None)
# 0x927C = MakerNote
+2 -2
View File
@@ -21,8 +21,8 @@ def get_current_html_path(output_format=None):
return html_name
def log(img, metadata, metadata_parser: MetadataParser | None = None, output_format=None, task=None) -> str:
path_outputs = modules.config.temp_path if args_manager.args.disable_image_log else modules.config.path_outputs
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 or not persist_image else modules.config.path_outputs
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)
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):
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):
-2
View File
@@ -37,7 +37,6 @@ def sort_styles(selected):
global all_styles
unselected = [y for y in all_styles if y not in selected]
sorted_styles = selected + unselected
"""
try:
with open('sorted_styles.json', 'wt', encoding='utf-8') as fp:
json.dump(sorted_styles, fp, indent=4)
@@ -45,7 +44,6 @@ def sort_styles(selected):
print('Write style sorting failed.')
print(e)
all_styles = sorted_styles
"""
return gr.CheckboxGroup.update(choices=sorted_styles)
-15
View File
@@ -1,15 +0,0 @@
import translators
from functools import lru_cache
@lru_cache(maxsize=32, typed=False)
def translate2en(text, element):
if not text:
return text
try:
result = translators.translate_text(text,to_language='en')
print(f'[Parameters] Translated {element}: {result}')
return result
except Exception as e:
print(f'[Parameters] Error during translation of {element}: {e}')
return text
+1 -1
View File
@@ -17,7 +17,7 @@ def perform_upscale(img):
if model is None:
model_filename = downloading_upscale_model()
sd = torch.load(model_filename)
sd = torch.load(model_filename, weights_only=True)
sdo = OrderedDict()
for k, v in sd.items():
sdo[k.replace('residual_block_', 'RDB')] = v
Binary file not shown.
Binary file not shown.
+79 -51
View File
@@ -1,40 +1,30 @@
<div align=center>
<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>
# 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.
* 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.
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).
**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 |
| - | - |
@@ -55,7 +45,7 @@ Using Fooocus is as easy as (probably easier than) Midjourney but this does
| InsightFace | Input Image -> Image Prompt -> Advanced -> FaceSwap |
| 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 |
| - | - |
@@ -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 |
| 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
@@ -71,7 +61,7 @@ Fooocus also developed many "fooocus-only" features for advanced users to get pe
You can directly download Fooocus with:
**[>>> Click here to download <<<](https://github.com/lllyasviel/Fooocus/releases/download/release/Fooocus_win64_2-1-831.7z)**
**[>>> Click here to download <<<](https://github.com/lllyasviel/Fooocus/releases/download/v2.5.0/Fooocus_win64_2-5-0.7z)**
After you download the file, please uncompress it and then run the "run.bat".
@@ -119,7 +109,7 @@ See also the common problems and troubleshoots [here](troubleshoot.md).
### 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
| --- | --- |
@@ -225,7 +215,7 @@ Then run the `run.bat`.
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
@@ -303,7 +293,8 @@ In both ways the access is unauthenticated by default. You can add basic authent
## List of "Hidden" Tricks
<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).
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.
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.
</details>
## Customization
@@ -371,15 +363,14 @@ entry_with_update.py [-h] [--listen [IP]] [--port PORT]
[--hf-mirror HF_MIRROR]
[--external-working-path PATH [PATH ...]]
[--output-path OUTPUT_PATH]
[--temp-path TEMP_PATH]
[--cache-path CACHE_PATH] [--in-browser]
[--disable-in-browser]
[--temp-path TEMP_PATH] [--cache-path CACHE_PATH]
[--in-browser] [--disable-in-browser]
[--gpu-device-id DEVICE_ID]
[--async-cuda-allocation | --disable-async-cuda-allocation]
[--disable-attention-upcast]
[--all-in-fp32 | --all-in-fp16]
[--unet-in-bf16 | --unet-in-fp16 | --unet-in-fp8-e4m3fn | --unet-in-fp8-e5m2]
[--vae-in-fp16 | --vae-in-fp32 | --vae-in-bf16]
[--vae-in-fp16 | --vae-in-fp32 | --vae-in-bf16]
[--vae-in-cpu]
[--clip-in-fp8-e4m3fn | --clip-in-fp8-e5m2 | --clip-in-fp16 | --clip-in-fp32]
[--directml [DIRECTML_DEVICE]]
@@ -387,36 +378,75 @@ entry_with_update.py [-h] [--listen [IP]] [--port PORT]
[--preview-option [none,auto,fast,taesd]]
[--attention-split | --attention-quad | --attention-pytorch]
[--disable-xformers]
[--always-gpu | --always-high-vram | --always-normal-vram |
--always-low-vram | --always-no-vram | --always-cpu [CPU_NUM_THREADS]]
[--always-gpu | --always-high-vram | --always-normal-vram | --always-low-vram | --always-no-vram | --always-cpu [CPU_NUM_THREADS]]
[--always-offload-from-vram]
[--pytorch-deterministic] [--disable-server-log]
[--debug-mode] [--is-windows-embedded-python]
[--disable-server-info] [--multi-user] [--share]
[--preset PRESET] [--disable-preset-selection]
[--pytorch-deterministic] [--disable-server-log]
[--debug-mode] [--is-windows-embedded-python]
[--disable-server-info] [--multi-user] [--share]
[--preset PRESET] [--disable-preset-selection]
[--language LANGUAGE]
[--disable-offload-from-vram] [--theme THEME]
[--disable-image-log] [--disable-analytics]
[--disable-metadata] [--disable-preset-download]
[--enable-describe-uov-image]
[--disable-offload-from-vram] [--theme THEME]
[--disable-image-log] [--disable-analytics]
[--disable-metadata] [--disable-preset-download]
[--disable-enhance-output-sorting]
[--enable-auto-describe-image]
[--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
[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 |
| - |
| [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 ... |
See also [About Forking and Promotion of Forks](https://github.com/lllyasviel/Fooocus/discussions/699).
| [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 ... |
## 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
@@ -424,8 +454,6 @@ The log is [here](update_log.md).
## 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.
For example, below is the content of `Fooocus/language/example.json`:
+20 -18
View File
@@ -1,22 +1,24 @@
torchsde==0.2.5
einops==0.4.1
transformers==4.30.2
safetensors==0.3.1
accelerate==0.21.0
pyyaml==6.0
Pillow==9.2.0
scipy==1.9.3
tqdm==4.65.0
psutil==5.9.5
pytorch_lightning==1.9.4
omegaconf==2.2.3
torchsde==0.2.6
einops==0.8.0
transformers==4.42.4
safetensors==0.4.3
accelerate==0.32.1
pyyaml==6.0.1
pillow==10.4.0
scipy==1.14.0
tqdm==4.66.4
psutil==6.0.0
pytorch_lightning==2.3.3
omegaconf==2.3.0
gradio==3.41.2
pygit2==1.12.2
opencv-contrib-python==4.8.0.74
httpx==0.24.1
onnxruntime==1.16.3
timm==0.9.2
translators==5.9.2
pygit2==1.15.1
opencv-contrib-python-headless==4.10.0.84
httpx==0.27.0
onnxruntime==1.18.1
timm==1.0.7
numpy==1.26.4
tokenizers==0.19.1
packaging==24.1
rembg==2.0.57
groundingdino-py==0.4.0
segment_anything==1.0
+40 -2
View File
@@ -1,10 +1,48 @@
# [2.5.0-rc1](https://github.com/lllyasviel/Fooocus/releases/tag/v2.5.0-rc1)
# [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)
This version includes various package updates. If the auto-update doesn't work you can do one of the following:
1. Open a terminal in the Fooocus folder (location of config.txt) and run `git pull`
2. Update packages
- Windows (installation through zip file): open a terminal in the Fooocus folder (location of config.txt) `..\python_embeded\python.exe -m pip install -r .\requirements_versions.txt` (Windows using embedded python, installation method zip file) or download Fooocus again (zip file attached to this release)
- other: manually update the packages using `python.exe -m pip install -r requirements_versions.txt` or use the docker image
---
* Update python dependencies, add segment_anything
* Add enhance feature, which offers easy image refinement steps (similar to adetailer, but based on dynamic image detection instead of specific mask detection models). See [documentation](https://github.com/lllyasviel/Fooocus/discussions/3281).
* Rewrite async worker code, make code much more reusable to allow iterations and improve reusability
* Improve GroundingDINO and SAM image masking
* Fix inference tensor version counter tracking issue for GroundingDINO after using Enhance (see [discussion](https://github.com/lllyasviel/Fooocus/discussions/3213))
* Update python dependencies, add segment_anything
* Move checkboxes Enable Mask Upload and Invert Mask When Generating from Developer Debug Mode to Inpaint Or Outpaint
* Add persistent model cache for metadata. Use `--rebuild-hash-cache X` (X = int, number of CPU cores, default all) to manually rebuild the cache for all non-cached hashes
* Rename `--enable-describe-uov-image` to `--enable-auto-describe-image`, now also works for enhance image upload
+113 -73
View File
@@ -73,6 +73,9 @@ def generate_clicked(task: worker.AsyncTask):
gr.update(visible=True, value=product), \
gr.update(visible=False)
if flag == 'finish':
if not args_manager.args.disable_enhance_output_sorting:
product = sort_enhance_images(product, task)
yield gr.update(visible=False), \
gr.update(visible=False), \
gr.update(visible=False), \
@@ -90,6 +93,25 @@ def generate_clicked(task: worker.AsyncTask):
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):
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')
skip_button.click(skip_clicked, inputs=currentTask, outputs=currentTask, queue=False, show_progress=False)
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')
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.Tabs():
with gr.TabItem(label='Upscale or Variation') as uov_tab:
with gr.Row(visible=modules.config.default_image_prompt_checkbox) as image_input_panel:
with gr.Tabs(selected=modules.config.default_selected_image_input_tab_id):
with gr.Tab(label='Upscale or Variation', id='uov_tab') as uov_tab:
with gr.Row():
with gr.Column():
uov_input_image = grh.Image(label='Image', source='upload', type='numpy', show_label=False)
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>')
with gr.TabItem(label='Image Prompt') as ip_tab:
with gr.Tab(label='Image Prompt', id='ip_tab') as ip_tab:
with gr.Row():
ip_images = []
ip_types = []
@@ -198,30 +220,29 @@ with shared.gradio_root:
ip_weights = []
ip_ctrls = []
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():
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_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():
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=default_end)
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_stops.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_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_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_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>')
def ip_advance_checked(x):
@@ -234,11 +255,11 @@ with shared.gradio_root:
outputs=ip_ad_cols + ip_types + ip_stops + ip_weights,
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.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_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_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')
@@ -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>')
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')
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',
choices=flags.inpaint_mask_models,
value=modules.config.default_inpaint_mask_model)
@@ -311,40 +332,41 @@ with shared.gradio_root:
example_inpaint_mask_dino_prompt_text],
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.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():
desc_method = gr.Radio(
describe_methods = gr.CheckboxGroup(
label='Content Type',
choices=[flags.desc_type_photo, flags.desc_type_anime],
value=flags.desc_type_photo)
desc_btn = gr.Button(value='Describe this Image into Prompt')
desc_image_size = gr.Textbox(label='Image Size and Recommended Size', elem_id='desc_image_size', visible=False)
choices=flags.describe_types,
value=modules.config.default_describe_content_type)
describe_apply_styles = gr.Checkbox(label='Apply Styles', value=modules.config.default_describe_apply_prompts_checkbox)
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>')
def trigger_show_image_properties(image):
value = modules.util.get_image_size_info(image, modules.flags.sdxl_aspect_ratios)
return gr.update(value=value, visible=True)
desc_input_image.upload(trigger_show_image_properties, inputs=desc_input_image,
outputs=desc_image_size, show_progress=False, queue=False)
describe_input_image.upload(trigger_show_image_properties, inputs=describe_input_image,
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.Column():
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>')
with gr.TabItem(label='Metadata') as metadata_tab:
with gr.Tab(label='Metadata', id='metadata_tab') as metadata_tab:
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_import_button = gr.Button(value='Apply Metadata')
def trigger_metadata_preview(filepath):
parameters, metadata_scheme = modules.meta_parser.read_info_from_image(filepath)
def trigger_metadata_preview(file):
parameters, metadata_scheme = modules.meta_parser.read_info_from_image(file)
results = {}
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.Tabs():
with gr.TabItem(label='Upscale or Variation'):
with gr.Tab(label='Upscale or Variation'):
with gr.Row():
with gr.Column():
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_update_ctrls = []
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',
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)
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)
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)
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,
@@ -671,9 +693,9 @@ with shared.gradio_root:
value=modules.config.default_sample_sharpness,
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>')
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'):
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). ')
@@ -748,6 +770,10 @@ with shared.gradio_root:
inputs=black_out_nsfw, outputs=disable_preview, queue=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:
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.')
@@ -860,24 +886,6 @@ with shared.gradio_root:
refresh_files.click(refresh_files_clicked, [], refresh_files_output + lora_ctrls,
queue=False, show_progress=False)
with gr.Tab(label='Audio'):
play_notification = gr.Checkbox(label='Play notification after rendering', value=False)
notification_file = 'notification.mp3'
if os.path.exists(notification_file):
notification = gr.State(value=notification_file)
notification_input = gr.Audio(label='Notification', interactive=True, elem_id='audio_notification', visible=False, show_edit_button=False)
def play_notification_checked(r, notification):
return gr.update(visible=r, value=notification if r else None)
def notification_input_changed(notification_input, notification):
if notification_input:
notification = notification_input
return notification
play_notification.change(fn=play_notification_checked, inputs=[play_notification, notification], outputs=[notification_input], queue=False)
notification_input.change(fn=notification_input_changed, inputs=[notification_input, notification], outputs=[notification], queue=False)
state_is_generating = gr.State(False)
load_data_outputs = [advanced_checkbox, image_number, prompt, negative_prompt, style_selections,
@@ -987,6 +995,9 @@ with shared.gradio_root:
ctrls += freeu_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:
ctrls += [save_metadata_to_images, metadata_scheme]
@@ -1013,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)
def trigger_metadata_import(filepath, state_is_generating):
parameters, metadata_scheme = modules.meta_parser.read_info_from_image(filepath)
def trigger_metadata_import(file, state_is_generating):
parameters, metadata_scheme = modules.meta_parser.read_info_from_image(file)
if parameters is None:
print('Could not find metadata in the image!')
parsed_parameters = {}
@@ -1045,30 +1056,59 @@ with shared.gradio_root:
progress_html, progress_window, progress_gallery, gallery],
queue=False)
def trigger_describe(mode, img):
if mode == flags.desc_type_photo:
from extras.interrogate import default_interrogator as default_interrogator_photo
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"]
for notification_file in ['notification.ogg', 'notification.mp3']:
if os.path.exists(notification_file):
gr.Audio(interactive=False, value=notification_file, elem_id='audio_notification', visible=False)
break
desc_btn.click(trigger_describe, inputs=[desc_method, desc_input_image],
outputs=[prompt, style_selections], show_progress=True, queue=True)
def trigger_describe(modes, img, apply_styles):
describe_prompts = []
styles = set()
if flags.describe_type_photo in modes:
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:
def trigger_auto_describe(mode, img, prompt):
def trigger_auto_describe(mode, img, prompt, apply_styles):
# keep prompt if not empty
if prompt == '':
return trigger_describe(mode, img)
return trigger_describe(mode, img, apply_styles)
return gr.update(), gr.update()
uov_input_image.upload(trigger_auto_describe, inputs=[desc_method, uov_input_image, prompt],
outputs=[prompt, style_selections], show_progress=True, queue=True)
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) \
.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) \
.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():
from modules.localization import dump_english_config