W8)@-7PYg(dMkKxVgi3T$c{dxj~
zNKH3uJ}ax{{xqwN{z$q2nu;RUOe%0wDt5cq0E_)g4l@nMQBY8ZKtbk5*Y5SsV
zAP|4evu(qdtr^?1ny5WiK_Vw9j|dfi8L(pppGnFOftY3jQ(PzL1yfV*E@M6p;nqYt`foPr6q0)GG9PW^R
zB$6Zx8{gpr5$H;CuC|tZS1e%^Fwft_o7=O3Q89Xz_Vz8Y*!re$Uk^$U5x-|D6>ZZ<
z@p!esZUm}Y4!V@Y4rj-m(5x*iD3MD6pY(({?2(ZL9-Wqy;w0_cGK{JM>0DvQE(1Q6
zffuu+adP0eNMwU5{blfSv;^
z=$>t&b4A+Mz6ElMJffn7_FJpOU;q8siSm+vWKcHYY^gJct2{B|3i9P8_lSS%{&tET
zgY7>Vl~sGVFmeE`Jk_+qwIek5KO7bPa<#C&t_k~_d&t=B6ool#yO`&o`F1!$66`u`
ziI{Qzspaa&+vT;Sl9T#=ry(O|qiE|iSib08*;Ux_$ESSm#djZb+kZ*gDoqJp|
zYN_uVjm6~qbHhhJpeBJVU8QQj^i|O6RO_rd3{BxvWJR>x
zxzZ!^vOU`9!~Rk3_pAs7qV#i}c3Ws5L%P7{{CA(slRUP_Ur{fEx4nwe4^%)ado3#p
zaN$Qs?)(t!XFy!9a+rjdhPK49oxp&@XZmb{-m|58fG>Mo1<<8zpH5naTkclTrlZO>Me+PFTDD(-)EI>df
zSxFkdBRkqClx6E?=)@3H@JD*x^3;SJF_-yZOw^(CM7bfTcntG1Wn&6dy`F}n=}8~o
zR1}EZ7Z-4{9D!HGjLIc4u(Bqb3WdBX&?GvjnCaoBggRH~@+ZOOhaI_|xEjXOvh-c#
zV*`Oxe{TRC-0*U{mD4zx(5Q3FLPc7!Mt*s7m9^E`Pn3BY$3O!@efH#pm(RBYHeP_A
zyLALkH44aF$2AL%!N-egsxfS_o{!diJ&jA6GxGH>luAyh|LLWXMtn?>CF@C96L-vM
zTXjnEiYjAQ*$a{Pn%+{YUp0_Jxp{sYeNT$@=lHa<31{r+>lXNhaSg>l9$5044PFG1?FF?)YE7n|
zmVa%E4bCXP-3M8q(5B=*Hlm?$M|LhWkO9n+56lsUw&9NGPl79#Q?dCY~9wlgjK8&%bJ6)o6mxEY@7Uw4sKxf`O6r&KG>w-8X={zNN(?
zA@{b~sIc+QQ!<~K&ea`QN6vWp{I=_X-*-Uis_>k4nlIc`$^qV`cq3hRBb^I1SJz?H
z{d$Fdrz&%GVEr|yiHi?=l2+;ra!h(UP|0V$
zNEXLvw_(nzN2GrUHI%6#+d*tsje1qd`=L3P^m{GIYzei!hZ`lAuW+qj$MS0rL=qZo
zIs5)G<*>`-qB$t1QbN~7@sEF9*c|J_4B7X2m3j9c!;qd_w_Bvx$^q4!SifGF*!6o6
z^E=JHF3ykvKzcrQ@SD4qEbnYg8K|yZ*3(jsYx{m$!X7HtxD1TN1KEPpW{auHjr9Ylj|=?AoU=
z+dA|$-AZ9*)l)Kv}y}g%lEhb
z${YlA{qIAYdu7f%FBDx=X?9yhkn@*MXYyNq>kH;htj8i{ze?MeX%|E-mxLqCHUKe>
zC&DXy*~~bm_pLnE)UM&_({d3kd4$XS%sde*-)WbUVh;3NgHpaVBt6a*Gj^q!0E$Aw
z0NY$@xgi=>Ry$qkGvlE
zNTu{EjwT|66%uv0%gm;laB%s1X$!$hTODQ`7Q^kOF*(DD9>uF)0{#?!ucNb&a&LHF
zm%)n8OjYQ$+2H!#&jA;bA2j+?q@MMn@`$VWLfa*XEA>uydQ8Y0jAcCV%?G|--5Y=e
z*I!;3r_g%tg&suM99yuwobu87wUB2H*}Nyp&8wcLo8h
z-=Yp?6#dF$8!@CRWIS>Dx(%d-Qqoq8yVx|}=G9mjB*MgG=U
z^}(vIhladC`l0uwTIyO&W+lCjZe82YZ7(#iC_KLP1~7ERS2O~4Gi!W@$U0t1;f1$314%6+i0ay
zwXBRos);3gdld6e9K=?1ajX(Woa3}#ueq~&mo=1)4O&A$Pn+v5Wb0ODFDs-)+^aVh
z5QOL)@N}hkD-%>^W^TB8EH~ked)0GOZy$nD4m+9I#RZ7NWm_H6qyCWa>B%VxU1R|3
z+3#84N7aGKoHYANcr(_cQ+Q5L#J5~~!(;#GlS5y8tHdf=MJXsuF-DbUE44P&yF;vG
z!a}|Nb;@Q1iG(`2a-3>3$H_45+B&@K1^`p*e^=)&J?P8*m$^NJrY>F&Ym@B#WKZq@+UEy;*uPf*
zrm-Sk(5F`F*5%TEbEvwaie+9A?`nC0Zf?SkWVrgaJvOC9$hL6{_LFA%iWJFjlW0cv
zUh`rdyFQ1Ep*a1=5rPj$l%_Mg>VF~T?cH`hAhckq*Sw(}PnESoo&MlmkSa8~4hi?0
z(^aLm-^%}`D-fqnR=l(77oPgZFb3bu*?EZ&7eQ&3OuadFy1+5F1^p8VsA<6h9m!
zG=1Q3cZ2>^*8NUYcF=N|lzazF?qeqi&W+Jbk;{JEoY56T%$js1#R>D00B}9wN$OBY
zs<=EHZ{c3I#%MTU)YsR^1)hx
pZ)TVPh{BgFji^?BgQA#X432I+X`(dr3u>}lG124nSoP-b{{X_R7Q6re
literal 0
HcmV?d00001
diff --git a/sdxl_styles/sdxl_styles_fooocus.json b/sdxl_styles/sdxl_styles_fooocus.json
index 81d6442e..cf64eab4 100644
--- a/sdxl_styles/sdxl_styles_fooocus.json
+++ b/sdxl_styles/sdxl_styles_fooocus.json
@@ -3,6 +3,10 @@
"name": "Fooocus Enhance",
"negative_prompt": "(worst quality, low quality, normal quality, lowres, low details, oversaturated, undersaturated, overexposed, underexposed, grayscale, bw, bad photo, bad photography, bad art:1.4), (watermark, signature, text font, username, error, logo, words, letters, digits, autograph, trademark, name:1.2), (blur, blurry, grainy), morbid, ugly, asymmetrical, mutated malformed, mutilated, poorly lit, bad shadow, draft, cropped, out of frame, cut off, censored, jpeg artifacts, out of focus, glitch, duplicate, (airbrushed, cartoon, anime, semi-realistic, cgi, render, blender, digital art, manga, amateur:1.3), (3D ,3D Game, 3D Game Scene, 3D Character:1.1), (bad hands, bad anatomy, bad body, bad face, bad teeth, bad arms, bad legs, deformities:1.3)"
},
+ {
+ "name": "Fooocus Semi Realistic",
+ "negative_prompt": "(worst quality, low quality, normal quality, lowres, low details, oversaturated, undersaturated, overexposed, underexposed, bad photo, bad photography, bad art:1.4), (watermark, signature, text font, username, error, logo, words, letters, digits, autograph, trademark, name:1.2), (blur, blurry, grainy), morbid, ugly, asymmetrical, mutated malformed, mutilated, poorly lit, bad shadow, draft, cropped, out of frame, cut off, censored, jpeg artifacts, out of focus, glitch, duplicate, (bad hands, bad anatomy, bad body, bad face, bad teeth, bad arms, bad legs, deformities:1.3)"
+ },
{
"name": "Fooocus Sharp",
"prompt": "cinematic still {prompt} . emotional, harmonious, vignette, 4k epic detailed, shot on kodak, 35mm photo, sharp focus, high budget, cinemascope, moody, epic, gorgeous, film grain, grainy",
From 86cba3f223720245269b96d86560d8ef16806c2a Mon Sep 17 00:00:00 2001
From: Manuel Schmid
Date: Fri, 15 Mar 2024 23:11:26 +0100
Subject: [PATCH 088/103] feat: add translation for unsupported image error
(#2537)
---
language/en.json | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/language/en.json b/language/en.json
index 0f97e6e9..fefc79c4 100644
--- a/language/en.json
+++ b/language/en.json
@@ -384,5 +384,6 @@
"Metadata Scheme": "Metadata Scheme",
"Image Prompt parameters are not included. Use png and a1111 for compatibility with Civitai.": "Image Prompt parameters are not included. Use png and a1111 for compatibility with Civitai.",
"fooocus (json)": "fooocus (json)",
- "a1111 (plain text)": "a1111 (plain text)"
+ "a1111 (plain text)": "a1111 (plain text)",
+ "Unsupported image type in input": "Unsupported image type in input"
}
\ No newline at end of file
From d057f2fae9c8222cb30a1eb20c549a7cf2c96bda Mon Sep 17 00:00:00 2001
From: Manuel Schmid <9307310+mashb1t@users.noreply.github.com>
Date: Sun, 17 Mar 2024 14:01:10 +0100
Subject: [PATCH 089/103] fix: correctly handle empty lora array in a1111
metadata log scheme (#2551)
---
modules/meta_parser.py | 19 +++++++++----------
1 file changed, 9 insertions(+), 10 deletions(-)
diff --git a/modules/meta_parser.py b/modules/meta_parser.py
index 546c093f..e518a9cf 100644
--- a/modules/meta_parser.py
+++ b/modules/meta_parser.py
@@ -377,7 +377,7 @@ class A1111MetadataParser(MetadataParser):
data[key] = filename
break
- if 'lora_hashes' in data:
+ if 'lora_hashes' in data and data['lora_hashes'] != '':
lora_filenames = modules.config.lora_filenames.copy()
if modules.config.sdxl_lcm_lora in lora_filenames:
lora_filenames.remove(modules.config.sdxl_lcm_lora)
@@ -431,16 +431,15 @@ class A1111MetadataParser(MetadataParser):
if key in data:
generation_params[self.fooocus_to_a1111[key]] = data[key]
- lora_hashes = []
- for index, (lora_name, lora_weight, lora_hash) in enumerate(self.loras):
- # workaround for Fooocus not knowing LoRA name in LoRA metadata
- lora_hashes.append(f'{lora_name}: {lora_hash}: {lora_weight}')
- lora_hashes_string = ', '.join(lora_hashes)
+ if len(self.loras) > 0:
+ lora_hashes = []
+ for index, (lora_name, lora_weight, lora_hash) in enumerate(self.loras):
+ # workaround for Fooocus not knowing LoRA name in LoRA metadata
+ lora_hashes.append(f'{lora_name}: {lora_hash}: {lora_weight}')
+ lora_hashes_string = ', '.join(lora_hashes)
+ generation_params[self.fooocus_to_a1111['lora_hashes']] = lora_hashes_string
- generation_params |= {
- self.fooocus_to_a1111['lora_hashes']: lora_hashes_string,
- self.fooocus_to_a1111['version']: data['version']
- }
+ generation_params[self.fooocus_to_a1111['version']] = data['version']
if modules.config.metadata_created_by != '':
generation_params[self.fooocus_to_a1111['created_by']] = modules.config.metadata_created_by
From 6b44c101dbfe742fd912456c200ad1bfa4a88473 Mon Sep 17 00:00:00 2001
From: Manuel Schmid
Date: Mon, 18 Mar 2024 12:30:39 +0100
Subject: [PATCH 090/103] feat: update changelog and readme
---
readme.md | 10 +++++++---
update_log.md | 11 +++++++++++
2 files changed, 18 insertions(+), 3 deletions(-)
diff --git a/readme.md b/readme.md
index 4e47ac08..6ec24eed 100644
--- a/readme.md
+++ b/readme.md
@@ -84,6 +84,10 @@ The first time you launch the software, it will automatically download models:
After Fooocus 2.1.60, you will also have `run_anime.bat` and `run_realistic.bat`. They are different model presets (and require different models, but they will be automatically downloaded). [Check here for more details](https://github.com/lllyasviel/Fooocus/discussions/679).
+After Fooocus 2.3.0 you can also switch presets directly in the browser. Keep in mind to add these arguments if you want to change the default behavior:
+* Use `--disable-preset-selection` to disable preset selection in the browser.
+* Use `--always-download-new-model` to download missing models on preset switch. Default is fallback to `previous_default_models` defined in the corresponding preset, also see terminal output.
+

If you already have these files, you can copy them to the above locations to speed up installation.
@@ -115,7 +119,7 @@ See also the common problems and troubleshoots [here](troubleshoot.md).
### Colab
-(Last tested - 2024 Mar 11)
+(Last tested - 2024 Mar 18 - @mashb1t)
| Colab | Info
| --- | --- |
@@ -125,9 +129,9 @@ In Colab, you can modify the last line to `!python entry_with_update.py --share
Note that this Colab will disable refiner by default because Colab free's resources are relatively limited (and some "big" features like image prompt may cause free-tier Colab to disconnect). We make sure that basic text-to-image is always working on free-tier Colab.
-Using `--always-high-vram` shifts resource allocation from RAM to VRAM and achieves the overall best balance between performance, flexibility and stability on the default T4 instance.
+Using `--always-high-vram` shifts resource allocation from RAM to VRAM and achieves the overall best balance between performance, flexibility and stability on the default T4 instance. Please find more information [here](https://github.com/lllyasviel/Fooocus/pull/1710#issuecomment-1989185346).
-Thanks to [camenduru](https://github.com/camenduru)!
+Thanks to [camenduru](https://github.com/camenduru) for the template!
### Linux (Using Anaconda)
diff --git a/update_log.md b/update_log.md
index 322c19c1..4e22db0a 100644
--- a/update_log.md
+++ b/update_log.md
@@ -1,3 +1,14 @@
+# [2.3.0](https://github.com/lllyasviel/Fooocus/releases/tag/2.3.0)
+
+* Add performance "lightning" (based on [SDXL-Lightning 4 step LoRA](https://huggingface.co/ByteDance/SDXL-Lightning/blob/main/sdxl_lightning_4step_lora.safetensors))
+* Add preset selection to UI, disable with argument `--disable-preset-selection`. Use `--always-download-new-model` to download missing models on preset switch.
+* Improve face swap consistency by switching later in the process to (synthetic) refiner
+* Add temp path cleanup on startup
+* Add support for wildcard subdirectories
+* Add scrollable 2 column layout for styles for better structure
+* Improve Colab resource needs for T4 instances (default), positively tested with all image prompt features
+* Improve anime preset, now uses style `Fooocus Semi Realistic` instead of `Fooocus Negative` (less wet look images)
+
# [2.2.1](https://github.com/lllyasviel/Fooocus/releases/tag/2.2.1)
* Fix some small bugs (e.g. image grid, upscale fast 2x, LoRA weight width in Firefox)
From c08518abae926d596ac5095ba8af7c3c3d88cc4d Mon Sep 17 00:00:00 2001
From: Manuel Schmid
Date: Mon, 18 Mar 2024 17:40:37 +0100
Subject: [PATCH 091/103] feat: add backwards compatibility for presets without
disable/enable LoRA boolean
https://github.com/lllyasviel/Fooocus/pull/2507
---
modules/config.py | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/modules/config.py b/modules/config.py
index c82f61c2..f3bf7f1f 100644
--- a/modules/config.py
+++ b/modules/config.py
@@ -323,8 +323,12 @@ default_loras = get_config_item_or_set_default(
1.0
]
],
- validator=lambda x: isinstance(x, list) and all(len(y) == 3 and isinstance(y[0], bool) and isinstance(y[1], str) and isinstance(y[2], numbers.Number) for y in x)
+ validator=lambda x: isinstance(x, list) and all(
+ len(y) == 3 and isinstance(y[0], bool) and isinstance(y[1], str) and isinstance(y[2], numbers.Number)
+ or len(y) == 2 and isinstance(y[0], str) and isinstance(y[1], numbers.Number)
+ for y in x)
)
+default_loras = [(y[0], y[1], y[2]) if len(y) == 3 else (True, y[0], y[1]) for y in default_loras]
default_max_lora_number = get_config_item_or_set_default(
key='default_max_lora_number',
default_value=len(default_loras) if isinstance(default_loras, list) and len(default_loras) > 0 else 5,
From ee361715afb7dab10ff266fcf8d8c6abcebfd81a Mon Sep 17 00:00:00 2001
From: Manuel Schmid
Date: Mon, 18 Mar 2024 18:04:15 +0100
Subject: [PATCH 092/103] docs: bump version number to 2.3.0
---
fooocus_version.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/fooocus_version.py b/fooocus_version.py
index 6c3c2c90..a4b8895b 100644
--- a/fooocus_version.py
+++ b/fooocus_version.py
@@ -1 +1 @@
-version = '2.2.1'
+version = '2.3.0'
From 3efce581cac1df4441980710f55c28fbde3ac3d7 Mon Sep 17 00:00:00 2001
From: Manuel Schmid
Date: Mon, 18 Mar 2024 18:13:15 +0100
Subject: [PATCH 093/103] docs: add hint for colab preset timeout to readme
---
readme.md | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/readme.md b/readme.md
index 6ec24eed..5f66e02a 100644
--- a/readme.md
+++ b/readme.md
@@ -119,7 +119,7 @@ See also the common problems and troubleshoots [here](troubleshoot.md).
### Colab
-(Last tested - 2024 Mar 18 - @mashb1t)
+(Last tested - 2024 Mar 18 by [mashb1t](https://github.com/mashb1t))
| Colab | Info
| --- | --- |
@@ -127,6 +127,8 @@ See also the common problems and troubleshoots [here](troubleshoot.md).
In Colab, you can modify the last line to `!python entry_with_update.py --share --always-high-vram` or `!python entry_with_update.py --share --always-high-vram --preset anime` or `!python entry_with_update.py --share --always-high-vram --preset realistic` for Fooocus Default/Anime/Realistic Edition.
+You can also change the preset in the UI. Please be aware that this may lead to timeouts after 60 seconds. If this is the case, please wait until the download has finished, change the preset to initial and back to the one you've selected or reload the page.
+
Note that this Colab will disable refiner by default because Colab free's resources are relatively limited (and some "big" features like image prompt may cause free-tier Colab to disconnect). We make sure that basic text-to-image is always working on free-tier Colab.
Using `--always-high-vram` shifts resource allocation from RAM to VRAM and achieves the overall best balance between performance, flexibility and stability on the default T4 instance. Please find more information [here](https://github.com/lllyasviel/Fooocus/pull/1710#issuecomment-1989185346).
From 532a6e2e67634a8b33fb218a44da498c4f689db5 Mon Sep 17 00:00:00 2001
From: Manuel Schmid
Date: Tue, 19 Mar 2024 19:10:14 +0100
Subject: [PATCH 094/103] fix: remove positive prompt from anime prefix
prevents the prompt from getting overridden when switching presets in browser
---
presets/anime.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/presets/anime.json b/presets/anime.json
index 6fe6e4ba..2610677c 100644
--- a/presets/anime.json
+++ b/presets/anime.json
@@ -34,7 +34,7 @@
"default_sampler": "dpmpp_2m_sde_gpu",
"default_scheduler": "karras",
"default_performance": "Speed",
- "default_prompt": "1girl, ",
+ "default_prompt": "",
"default_prompt_negative": "",
"default_styles": [
"Fooocus V2",
From 856eb750ab515a3b5b28b7d35360fca1411dd933 Mon Sep 17 00:00:00 2001
From: Manuel Schmid
Date: Tue, 19 Mar 2024 23:08:38 +0100
Subject: [PATCH 095/103] fix: add enabled value to LoRA when setting
default_max_lora_number
---
modules/config.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/modules/config.py b/modules/config.py
index f3bf7f1f..ba2a76fb 100644
--- a/modules/config.py
+++ b/modules/config.py
@@ -476,7 +476,7 @@ metadata_created_by = get_config_item_or_set_default(
example_inpaint_prompts = [[x] for x in example_inpaint_prompts]
-config_dict["default_loras"] = default_loras = default_loras[:default_max_lora_number] + [['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
possible_preset_keys = {
From 978267f461e204c6c4359a79ed818ee2e3e1af39 Mon Sep 17 00:00:00 2001
From: Manuel Schmid
Date: Wed, 20 Mar 2024 21:12:21 +0100
Subject: [PATCH 096/103] fix: correctly set preset config and loras in meta
parser
---
modules/config.py | 8 --------
modules/meta_parser.py | 19 ++++++++++++++-----
2 files changed, 14 insertions(+), 13 deletions(-)
diff --git a/modules/config.py b/modules/config.py
index ba2a76fb..76ffd348 100644
--- a/modules/config.py
+++ b/modules/config.py
@@ -124,14 +124,6 @@ def try_get_preset_content(preset):
print(e)
return {}
-
-try:
- with open(os.path.abspath(f'./presets/default.json'), "r", encoding="utf-8") as json_file:
- config_dict.update(json.load(json_file))
-except Exception as e:
- print(f'Load default preset failed.')
- print(e)
-
available_presets = get_presets()
preset = args_manager.args.preset
config_dict.update(try_get_preset_content(preset))
diff --git a/modules/meta_parser.py b/modules/meta_parser.py
index 15f0ad7b..10bc6896 100644
--- a/modules/meta_parser.py
+++ b/modules/meta_parser.py
@@ -169,11 +169,20 @@ def get_freeu(key: str, fallback: str | None, source_dict: dict, results: list,
def get_lora(key: str, fallback: str | None, source_dict: dict, results: list):
try:
- n, w = source_dict.get(key, source_dict.get(fallback)).split(' : ')
- w = float(w)
- results.append(True)
- results.append(n)
- results.append(w)
+ split_data = source_dict.get(key, source_dict.get(fallback)).split(' : ')
+ enabled = True
+ name = split_data[0]
+ weight = split_data[1]
+
+ if len(split_data) == 3:
+ enabled = split_data[0] == 'True'
+ name = split_data[1]
+ weight = split_data[2]
+
+ weight = float(weight)
+ results.append(enabled)
+ results.append(name)
+ results.append(weight)
except:
results.append(True)
results.append('None')
From 7564dd5131ebef2b62b34ea88215f05d29bcdd60 Mon Sep 17 00:00:00 2001
From: Manuel Schmid <9307310+mashb1t@users.noreply.github.com>
Date: Sat, 23 Mar 2024 12:49:20 +0100
Subject: [PATCH 097/103] fix: load image number from preset (#2611)
* fix: add default_image_number to preset handling
* fix: use minimum image number of preset and config to prevent UI overflow
---
modules/config.py | 1 +
modules/meta_parser.py | 14 +++++++++++++-
2 files changed, 14 insertions(+), 1 deletion(-)
diff --git a/modules/config.py b/modules/config.py
index 76ffd348..6c02ca13 100644
--- a/modules/config.py
+++ b/modules/config.py
@@ -485,6 +485,7 @@ possible_preset_keys = {
"default_scheduler": "scheduler",
"default_overwrite_step": "steps",
"default_performance": "performance",
+ "default_image_number": "image_number",
"default_prompt": "prompt",
"default_prompt_negative": "negative_prompt",
"default_styles": "styles",
diff --git a/modules/meta_parser.py b/modules/meta_parser.py
index 10bc6896..8cd21cbc 100644
--- a/modules/meta_parser.py
+++ b/modules/meta_parser.py
@@ -27,8 +27,9 @@ def load_parameter_button_click(raw_metadata: dict | str, is_generating: bool):
loaded_parameter_dict = json.loads(raw_metadata)
assert isinstance(loaded_parameter_dict, dict)
- results = [len(loaded_parameter_dict) > 0, 1]
+ results = [len(loaded_parameter_dict) > 0]
+ get_image_number('image_number', 'Image Number', loaded_parameter_dict, results)
get_str('prompt', 'Prompt', loaded_parameter_dict, results)
get_str('negative_prompt', 'Negative Prompt', loaded_parameter_dict, results)
get_list('styles', 'Styles', loaded_parameter_dict, results)
@@ -92,6 +93,17 @@ def get_float(key: str, fallback: str | None, source_dict: dict, results: list,
results.append(gr.update())
+def get_image_number(key: str, fallback: str | None, source_dict: dict, results: list, default=None):
+ try:
+ h = source_dict.get(key, source_dict.get(fallback, default))
+ assert h is not None
+ h = int(h)
+ h = min(h, modules.config.default_max_image_number)
+ results.append(h)
+ except:
+ results.append(1)
+
+
def get_steps(key: str, fallback: str | None, source_dict: dict, results: list, default=None):
try:
h = source_dict.get(key, source_dict.get(fallback, default))
From 9aaa40055334978742295b6187c90bac72a81f84 Mon Sep 17 00:00:00 2001
From: Manuel Schmid <9307310+mashb1t@users.noreply.github.com>
Date: Sat, 23 Mar 2024 13:10:21 +0100
Subject: [PATCH 098/103] fix: use correct base dimensions for outpaint mask
padding (#2612)
---
modules/async_worker.py | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/modules/async_worker.py b/modules/async_worker.py
index fa959361..d8a1e072 100644
--- a/modules/async_worker.py
+++ b/modules/async_worker.py
@@ -614,12 +614,12 @@ def worker():
H, W, C = inpaint_image.shape
if 'left' in outpaint_selections:
- inpaint_image = np.pad(inpaint_image, [[0, 0], [int(H * 0.3), 0], [0, 0]], mode='edge')
- inpaint_mask = np.pad(inpaint_mask, [[0, 0], [int(H * 0.3), 0]], mode='constant',
+ inpaint_image = np.pad(inpaint_image, [[0, 0], [int(W * 0.3), 0], [0, 0]], mode='edge')
+ inpaint_mask = np.pad(inpaint_mask, [[0, 0], [int(W * 0.3), 0]], mode='constant',
constant_values=255)
if 'right' in outpaint_selections:
- inpaint_image = np.pad(inpaint_image, [[0, 0], [0, int(H * 0.3)], [0, 0]], mode='edge')
- inpaint_mask = np.pad(inpaint_mask, [[0, 0], [0, int(H * 0.3)]], mode='constant',
+ inpaint_image = np.pad(inpaint_image, [[0, 0], [0, int(W * 0.3)], [0, 0]], mode='edge')
+ inpaint_mask = np.pad(inpaint_mask, [[0, 0], [0, int(W * 0.3)]], mode='constant',
constant_values=255)
inpaint_image = np.ascontiguousarray(inpaint_image.copy())
From 523ef5c70e527c817a08dfd4ee975e00ddfca0f2 Mon Sep 17 00:00:00 2001
From: Manuel Schmid <9307310+mashb1t@users.noreply.github.com>
Date: Sat, 23 Mar 2024 16:37:18 +0100
Subject: [PATCH 099/103] fix: add Civitai compatibility for LoRAs in a1111
metadata scheme by switching schema (#2615)
* feat: update sha256 generation functions
https://github.com/lllyasviel/stable-diffusion-webui-forge/blob/29be1da7cf2b5dccfc70fbdd33eb35c56a31ffb7/modules/hashes.py
* feat: add compatibility for LoRAs in a1111 metadata scheme
* feat: add backwards compatibility
* refactor: extract remove_special_loras
* fix: correctly apply LoRA weight for legacy schema
---
modules/config.py | 1 +
modules/meta_parser.py | 47 ++++++++++++++++++++++++++++--------------
modules/util.py | 38 +++++++++++++++++++++++++++++-----
3 files changed, 66 insertions(+), 20 deletions(-)
diff --git a/modules/config.py b/modules/config.py
index 6c02ca13..b81e218a 100644
--- a/modules/config.py
+++ b/modules/config.py
@@ -539,6 +539,7 @@ wildcard_filenames = []
sdxl_lcm_lora = 'sdxl_lcm_lora.safetensors'
sdxl_lightning_lora = 'sdxl_lightning_4step_lora.safetensors'
+loras_metadata_remove = [sdxl_lcm_lora, sdxl_lightning_lora]
def get_model_filenames(folder_paths, extensions=None, name_filter=None):
diff --git a/modules/meta_parser.py b/modules/meta_parser.py
index 8cd21cbc..70ab8860 100644
--- a/modules/meta_parser.py
+++ b/modules/meta_parser.py
@@ -1,5 +1,4 @@
import json
-import os
import re
from abc import ABC, abstractmethod
from pathlib import Path
@@ -12,7 +11,7 @@ import modules.config
import modules.sdxl_styles
from modules.flags import MetadataScheme, Performance, Steps
from modules.flags import SAMPLERS, CIVITAI_NO_KARRAS
-from modules.util import quote, unquote, extract_styles_from_prompt, is_json, get_file_from_folder_list, calculate_sha256
+from modules.util import quote, unquote, extract_styles_from_prompt, is_json, get_file_from_folder_list, sha256
re_param_code = r'\s*(\w[\w \-/]+):\s*("(?:\\.|[^\\"])+"|[^,]*)(?:,|$)'
re_param = re.compile(re_param_code)
@@ -110,7 +109,8 @@ def get_steps(key: str, fallback: str | None, source_dict: dict, results: list,
assert h is not None
h = int(h)
# if not in steps or in steps and performance is not the same
- if h not in iter(Steps) or Steps(h).name.casefold() != source_dict.get('performance', '').replace(' ', '_').casefold():
+ if h not in iter(Steps) or Steps(h).name.casefold() != source_dict.get('performance', '').replace(' ',
+ '_').casefold():
results.append(h)
return
results.append(-1)
@@ -204,7 +204,8 @@ def get_lora(key: str, fallback: str | None, source_dict: dict, results: list):
def get_sha256(filepath):
global hash_cache
if filepath not in hash_cache:
- hash_cache[filepath] = calculate_sha256(filepath)
+ # is_safetensors = os.path.splitext(filepath)[1].lower() == '.safetensors'
+ hash_cache[filepath] = sha256(filepath)
return hash_cache[filepath]
@@ -231,8 +232,9 @@ def parse_meta_from_preset(preset_content):
height = height[:height.index(" ")]
preset_prepared[meta_key] = (width, height)
else:
- preset_prepared[meta_key] = items[settings_key] if settings_key in items and items[settings_key] is not None else getattr(modules.config, settings_key)
-
+ preset_prepared[meta_key] = items[settings_key] if settings_key in items and items[
+ settings_key] is not None else getattr(modules.config, settings_key)
+
if settings_key == "default_styles" or settings_key == "default_aspect_ratio":
preset_prepared[meta_key] = str(preset_prepared[meta_key])
@@ -288,6 +290,12 @@ class MetadataParser(ABC):
lora_hash = get_sha256(lora_path)
self.loras.append((Path(lora_name).stem, lora_weight, lora_hash))
+ @staticmethod
+ def remove_special_loras(lora_filenames):
+ for lora_to_remove in modules.config.loras_metadata_remove:
+ if lora_to_remove in lora_filenames:
+ lora_filenames.remove(lora_to_remove)
+
class A1111MetadataParser(MetadataParser):
def get_scheme(self) -> MetadataScheme:
@@ -397,12 +405,19 @@ class A1111MetadataParser(MetadataParser):
data[key] = filename
break
- if 'lora_hashes' in data and data['lora_hashes'] != '':
+ lora_data = ''
+ if 'lora_weights' in data and data['lora_weights'] != '':
+ lora_data = data['lora_weights']
+ elif 'lora_hashes' in data and data['lora_hashes'] != '' and data['lora_hashes'].split(', ')[0].count(':') == 2:
+ lora_data = data['lora_hashes']
+
+ if lora_data != '':
lora_filenames = modules.config.lora_filenames.copy()
- if modules.config.sdxl_lcm_lora in lora_filenames:
- lora_filenames.remove(modules.config.sdxl_lcm_lora)
- for li, lora in enumerate(data['lora_hashes'].split(', ')):
- lora_name, lora_hash, lora_weight = lora.split(': ')
+ self.remove_special_loras(lora_filenames)
+ for li, lora in enumerate(lora_data.split(', ')):
+ lora_split = lora.split(': ')
+ lora_name = lora_split[0]
+ lora_weight = lora_split[2] if len(lora_split) == 3 else lora_split[1]
for filename in lora_filenames:
path = Path(filename)
if lora_name == path.stem:
@@ -453,11 +468,15 @@ class A1111MetadataParser(MetadataParser):
if len(self.loras) > 0:
lora_hashes = []
+ lora_weights = []
for index, (lora_name, lora_weight, lora_hash) in enumerate(self.loras):
# workaround for Fooocus not knowing LoRA name in LoRA metadata
- lora_hashes.append(f'{lora_name}: {lora_hash}: {lora_weight}')
+ lora_hashes.append(f'{lora_name}: {lora_hash}')
+ lora_weights.append(f'{lora_name}: {lora_weight}')
lora_hashes_string = ', '.join(lora_hashes)
+ lora_weights_string = ', '.join(lora_weights)
generation_params[self.fooocus_to_a1111['lora_hashes']] = lora_hashes_string
+ generation_params[self.fooocus_to_a1111['lora_weights']] = lora_weights_string
generation_params[self.fooocus_to_a1111['version']] = data['version']
@@ -480,9 +499,7 @@ class FooocusMetadataParser(MetadataParser):
def parse_json(self, metadata: dict) -> dict:
model_filenames = modules.config.model_filenames.copy()
lora_filenames = modules.config.lora_filenames.copy()
- if modules.config.sdxl_lcm_lora in lora_filenames:
- lora_filenames.remove(modules.config.sdxl_lcm_lora)
-
+ self.remove_special_loras(lora_filenames)
for key, value in metadata.items():
if value in ['', 'None']:
continue
diff --git a/modules/util.py b/modules/util.py
index 7c46d946..9e0fb294 100644
--- a/modules/util.py
+++ b/modules/util.py
@@ -7,9 +7,9 @@ import math
import os
import cv2
import json
+import hashlib
from PIL import Image
-from hashlib import sha256
import modules.sdxl_styles
@@ -182,16 +182,44 @@ def get_files_from_folder(folder_path, extensions=None, name_filter=None):
return filenames
-def calculate_sha256(filename, length=HASH_SHA256_LENGTH) -> str:
- hash_sha256 = sha256()
+def sha256(filename, use_addnet_hash=False, length=HASH_SHA256_LENGTH):
+ print(f"Calculating sha256 for {filename}: ", end='')
+ if use_addnet_hash:
+ with open(filename, "rb") as file:
+ sha256_value = addnet_hash_safetensors(file)
+ else:
+ sha256_value = calculate_sha256(filename)
+ print(f"{sha256_value}")
+
+ return sha256_value[:length] if length is not None else sha256_value
+
+
+def addnet_hash_safetensors(b):
+ """kohya-ss hash for safetensors from https://github.com/kohya-ss/sd-scripts/blob/main/library/train_util.py"""
+ hash_sha256 = hashlib.sha256()
+ blksize = 1024 * 1024
+
+ b.seek(0)
+ header = b.read(8)
+ n = int.from_bytes(header, "little")
+
+ offset = n + 8
+ b.seek(offset)
+ for chunk in iter(lambda: b.read(blksize), b""):
+ hash_sha256.update(chunk)
+
+ return hash_sha256.hexdigest()
+
+
+def calculate_sha256(filename) -> str:
+ hash_sha256 = hashlib.sha256()
blksize = 1024 * 1024
with open(filename, "rb") as f:
for chunk in iter(lambda: f.read(blksize), b""):
hash_sha256.update(chunk)
- res = hash_sha256.hexdigest()
- return res[:length] if length else res
+ return hash_sha256.hexdigest()
def quote(text):
From e2f9bcb11d06216d6800676c48d8d74d6fd77a4b Mon Sep 17 00:00:00 2001
From: Manuel Schmid <9307310+mashb1t@users.noreply.github.com>
Date: Sat, 23 Mar 2024 16:57:11 +0100
Subject: [PATCH 100/103] docs: bump version number to 2.3.1, add changelog
(#2616)
---
fooocus_version.py | 2 +-
update_log.md | 7 +++++++
2 files changed, 8 insertions(+), 1 deletion(-)
diff --git a/fooocus_version.py b/fooocus_version.py
index a4b8895b..b2050196 100644
--- a/fooocus_version.py
+++ b/fooocus_version.py
@@ -1 +1 @@
-version = '2.3.0'
+version = '2.3.1'
diff --git a/update_log.md b/update_log.md
index 4e22db0a..62c4882b 100644
--- a/update_log.md
+++ b/update_log.md
@@ -1,3 +1,10 @@
+# [2.3.1](https://github.com/lllyasviel/Fooocus/releases/tag/2.3.1)
+
+* Remove positive prompt from anime prefix to not reset prompt after switching presets
+* Fix image number being reset to 1 when switching preset, now doesn't reset anymore
+* Fix outpainting dimension calculation when extending left/right
+* Fix LoRA compatibility for LoRAs in a1111 metadata scheme
+
# [2.3.0](https://github.com/lllyasviel/Fooocus/releases/tag/2.3.0)
* Add performance "lightning" (based on [SDXL-Lightning 4 step LoRA](https://huggingface.co/ByteDance/SDXL-Lightning/blob/main/sdxl_lightning_4step_lora.safetensors))
From d16a54edd69f82158ae7ffe5669618db33a01ac7 Mon Sep 17 00:00:00 2001
From: Manuel Schmid <9307310+mashb1t@users.noreply.github.com>
Date: Wed, 1 May 2024 14:11:38 +0200
Subject: [PATCH 101/103] fix: use LF as line breaks for Docker entrypoint.sh
(#2843)
adjusted for Linux again, see https://github.com/lllyasviel/Fooocus/discussions/2836
---
entrypoint.sh | 34 +---------------------------------
1 file changed, 1 insertion(+), 33 deletions(-)
diff --git a/entrypoint.sh b/entrypoint.sh
index d0dba09c..57b06c6b 100755
--- a/entrypoint.sh
+++ b/entrypoint.sh
@@ -1,33 +1 @@
-#!/bin/bash
-
-ORIGINALDIR=/content/app
-# Use predefined DATADIR if it is defined
-[[ x"${DATADIR}" == "x" ]] && DATADIR=/content/data
-
-# Make persistent dir from original dir
-function mklink () {
- mkdir -p $DATADIR/$1
- ln -s $DATADIR/$1 $ORIGINALDIR
-}
-
-# Copy old files from import dir
-function import () {
- (test -d /import/$1 && cd /import/$1 && cp -Rpn . $DATADIR/$1/)
-}
-
-cd $ORIGINALDIR
-
-# models
-mklink models
-# Copy original files
-(cd $ORIGINALDIR/models.org && cp -Rpn . $ORIGINALDIR/models/)
-# Import old files
-import models
-
-# outputs
-mklink outputs
-# Import old files
-import outputs
-
-# Start application
-python launch.py $*
+#!/bin/bash
ORIGINALDIR=/content/app
# Use predefined DATADIR if it is defined
[[ x"${DATADIR}" == "x" ]] && DATADIR=/content/data
# Make persistent dir from original dir
function mklink () {
mkdir -p $DATADIR/$1
ln -s $DATADIR/$1 $ORIGINALDIR
}
# Copy old files from import dir
function import () {
(test -d /import/$1 && cd /import/$1 && cp -Rpn . $DATADIR/$1/)
}
cd $ORIGINALDIR
# models
mklink models
# Copy original files
(cd $ORIGINALDIR/models.org && cp -Rpn . $ORIGINALDIR/models/)
# Import old files
import models
# outputs
mklink outputs
# Import old files
import outputs
# Start application
python launch.py $*
\ No newline at end of file
From c36e951781b17b36657369854a10664b5c09b118 Mon Sep 17 00:00:00 2001
From: Manuel Schmid <9307310+mashb1t@users.noreply.github.com>
Date: Sat, 4 May 2024 14:37:40 +0200
Subject: [PATCH 102/103] Revert "fix: use LF as line breaks for Docker
entrypoint.sh (#2843)" (#2865)
False alarm, worked as intended before. Sorry for the fuzz.
This reverts commit d16a54edd69f82158ae7ffe5669618db33a01ac7.
---
entrypoint.sh | 34 +++++++++++++++++++++++++++++++++-
1 file changed, 33 insertions(+), 1 deletion(-)
diff --git a/entrypoint.sh b/entrypoint.sh
index 57b06c6b..d0dba09c 100755
--- a/entrypoint.sh
+++ b/entrypoint.sh
@@ -1 +1,33 @@
-#!/bin/bash
ORIGINALDIR=/content/app
# Use predefined DATADIR if it is defined
[[ x"${DATADIR}" == "x" ]] && DATADIR=/content/data
# Make persistent dir from original dir
function mklink () {
mkdir -p $DATADIR/$1
ln -s $DATADIR/$1 $ORIGINALDIR
}
# Copy old files from import dir
function import () {
(test -d /import/$1 && cd /import/$1 && cp -Rpn . $DATADIR/$1/)
}
cd $ORIGINALDIR
# models
mklink models
# Copy original files
(cd $ORIGINALDIR/models.org && cp -Rpn . $ORIGINALDIR/models/)
# Import old files
import models
# outputs
mklink outputs
# Import old files
import outputs
# Start application
python launch.py $*
\ No newline at end of file
+#!/bin/bash
+
+ORIGINALDIR=/content/app
+# Use predefined DATADIR if it is defined
+[[ x"${DATADIR}" == "x" ]] && DATADIR=/content/data
+
+# Make persistent dir from original dir
+function mklink () {
+ mkdir -p $DATADIR/$1
+ ln -s $DATADIR/$1 $ORIGINALDIR
+}
+
+# Copy old files from import dir
+function import () {
+ (test -d /import/$1 && cd /import/$1 && cp -Rpn . $DATADIR/$1/)
+}
+
+cd $ORIGINALDIR
+
+# models
+mklink models
+# Copy original files
+(cd $ORIGINALDIR/models.org && cp -Rpn . $ORIGINALDIR/models/)
+# Import old files
+import models
+
+# outputs
+mklink outputs
+# Import old files
+import outputs
+
+# Start application
+python launch.py $*
From 6308fb8b54f62e61711aa57b086b30466ebbb857 Mon Sep 17 00:00:00 2001
From: Manuel Schmid <9307310+mashb1t@users.noreply.github.com>
Date: Thu, 9 May 2024 19:03:30 +0200
Subject: [PATCH 103/103] feat: update anime from animaPencilXL_v100 to
animaPencilXL_v310 (#2454)
* feat: update anime from animaPencilXL_v100 to animaPencilXL_v200
* feat: update animaPencilXL from 2.0.0 to 2.6.0
* feat: update animaPencilXL from 2.6.0 to 3.1.0
* feat: reduce cfg as suggested by vendor from 3.0.0
https://civitai.com/models/261336?modelVersionId=435001
"recommend to decrease CFG scale." + all examples are in CFG 6
---
presets/anime.json | 14 ++++++++++----
1 file changed, 10 insertions(+), 4 deletions(-)
diff --git a/presets/anime.json b/presets/anime.json
index 2610677c..78607edb 100644
--- a/presets/anime.json
+++ b/presets/anime.json
@@ -1,5 +1,5 @@
{
- "default_model": "animaPencilXL_v100.safetensors",
+ "default_model": "animaPencilXL_v310.safetensors",
"default_refiner": "None",
"default_refiner_switch": 0.5,
"default_loras": [
@@ -29,7 +29,7 @@
1.0
]
],
- "default_cfg_scale": 7.0,
+ "default_cfg_scale": 6.0,
"default_sample_sharpness": 2.0,
"default_sampler": "dpmpp_2m_sde_gpu",
"default_scheduler": "karras",
@@ -43,9 +43,15 @@
],
"default_aspect_ratio": "896*1152",
"checkpoint_downloads": {
- "animaPencilXL_v100.safetensors": "https://huggingface.co/lllyasviel/fav_models/resolve/main/fav/animaPencilXL_v100.safetensors"
+ "animaPencilXL_v310.safetensors": "https://huggingface.co/mashb1t/fav_models/resolve/main/fav/animaPencilXL_v310.safetensors"
},
"embeddings_downloads": {},
"lora_downloads": {},
- "previous_default_models": []
+ "previous_default_models": [
+ "animaPencilXL_v300.safetensors",
+ "animaPencilXL_v260.safetensors",
+ "animaPencilXL_v210.safetensors",
+ "animaPencilXL_v200.safetensors",
+ "animaPencilXL_v100.safetensors"
+ ]
}
\ No newline at end of file