1079 lines
39 KiB
Python
1079 lines
39 KiB
Python
import os
|
||
import json
|
||
import math
|
||
import numbers
|
||
|
||
import args_manager
|
||
import tempfile
|
||
import modules.flags
|
||
import modules.sdxl_styles
|
||
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
|
||
from modules.flags import OutputFormat, Performance, MetadataScheme
|
||
|
||
|
||
def get_config_path(key, default_value):
|
||
env = os.getenv(key)
|
||
if env is not None and isinstance(env, str):
|
||
print(f"Environment: {key} = {env}")
|
||
return env
|
||
else:
|
||
return os.path.abspath(default_value)
|
||
|
||
|
||
wildcards_max_bfs_depth = 64
|
||
config_path = get_config_path('config_path', "./config.txt")
|
||
config_example_path = get_config_path(
|
||
'config_example_path', "config_modification_tutorial.txt")
|
||
config_dict = {}
|
||
always_save_keys = []
|
||
visited_keys = []
|
||
|
||
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)
|
||
|
||
try:
|
||
if os.path.exists(config_path):
|
||
with open(config_path, "r", encoding="utf-8") as json_file:
|
||
config_dict.update(json.load(json_file))
|
||
always_save_keys = list(config_dict.keys())
|
||
except Exception as e:
|
||
print(
|
||
f'Failed to load config file "{config_path}" . The reason is: {str(e)}')
|
||
print('Please make sure that:')
|
||
print(
|
||
f'1. The file "{config_path}" is a valid text file, and you have access to read it.')
|
||
print('2. Use "\\\\" instead of "\\" when describing paths.')
|
||
print('3. There is no "," before the last "}".')
|
||
print('4. All key/value formats are correct.')
|
||
|
||
|
||
def try_load_deprecated_user_path_config():
|
||
global config_dict
|
||
|
||
if not os.path.exists('user_path_config.txt'):
|
||
return
|
||
|
||
try:
|
||
deprecated_config_dict = json.load(
|
||
open('user_path_config.txt', "r", encoding="utf-8"))
|
||
|
||
def replace_config(old_key, new_key):
|
||
if old_key in deprecated_config_dict:
|
||
config_dict[new_key] = deprecated_config_dict[old_key]
|
||
del deprecated_config_dict[old_key]
|
||
|
||
replace_config('modelfile_path', 'path_checkpoints')
|
||
replace_config('lorafile_path', 'path_loras')
|
||
replace_config('embeddings_path', 'path_embeddings')
|
||
replace_config('vae_approx_path', 'path_vae_approx')
|
||
replace_config('upscale_models_path', 'path_upscale_models')
|
||
replace_config('inpaint_models_path', 'path_inpaint')
|
||
replace_config('controlnet_models_path', 'path_controlnet')
|
||
replace_config('clip_vision_models_path', 'path_clip_vision')
|
||
replace_config('fooocus_expansion_path', 'path_fooocus_expansion')
|
||
replace_config('temp_outputs_path', 'path_outputs')
|
||
|
||
if deprecated_config_dict.get("default_model", None) == 'juggernautXL_version6Rundiffusion.safetensors':
|
||
os.replace('user_path_config.txt',
|
||
'user_path_config-deprecated.txt')
|
||
print('Config updated successfully in silence. '
|
||
'A backup of previous config is written to "user_path_config-deprecated.txt".')
|
||
return
|
||
|
||
if input("Newer models and configs are available. "
|
||
"Download and update files? [Y/n]:") in ['n', 'N', 'No', 'no', 'NO']:
|
||
config_dict.update(deprecated_config_dict)
|
||
print('Loading using deprecated old models and deprecated old configs.')
|
||
return
|
||
else:
|
||
os.replace('user_path_config.txt',
|
||
'user_path_config-deprecated.txt')
|
||
print('Config updated successfully by user. '
|
||
'A backup of previous config is written to "user_path_config-deprecated.txt".')
|
||
return
|
||
except Exception as e:
|
||
print('Processing deprecated config failed')
|
||
print(e)
|
||
return
|
||
|
||
|
||
try_load_deprecated_user_path_config()
|
||
|
||
|
||
def get_presets():
|
||
preset_folder = 'presets'
|
||
presets = ['initial']
|
||
if not os.path.exists(preset_folder):
|
||
print('No presets found.')
|
||
return presets
|
||
|
||
return presets + [f[:f.index(".json")] for f in os.listdir(preset_folder) if f.endswith('.json')]
|
||
|
||
|
||
def update_presets():
|
||
global available_presets
|
||
available_presets = get_presets()
|
||
|
||
|
||
def try_get_preset_content(preset):
|
||
if isinstance(preset, str):
|
||
preset_path = os.path.abspath(f'./presets/{preset}.json')
|
||
try:
|
||
if os.path.exists(preset_path):
|
||
with open(preset_path, "r", encoding="utf-8") as json_file:
|
||
json_content = json.load(json_file)
|
||
print(f'Loaded preset: {preset_path}')
|
||
return json_content
|
||
else:
|
||
raise FileNotFoundError
|
||
except Exception as e:
|
||
print(f'Load preset [{preset_path}] failed')
|
||
print(e)
|
||
return {}
|
||
|
||
|
||
available_presets = get_presets()
|
||
preset = args_manager.args.preset
|
||
config_dict.update(try_get_preset_content(preset))
|
||
|
||
|
||
def get_path_output() -> str:
|
||
"""
|
||
Checking output path argument and overriding default path.
|
||
"""
|
||
global config_dict
|
||
path_output = get_dir_or_set_default(
|
||
'path_outputs', '../outputs/', make_directory=True)
|
||
if args_manager.args.output_path:
|
||
print(
|
||
f'Overriding config value path_outputs with {args_manager.args.output_path}')
|
||
config_dict['path_outputs'] = path_output = args_manager.args.output_path
|
||
return path_output
|
||
|
||
|
||
def get_dir_or_set_default(key, default_value, as_array=False, make_directory=False):
|
||
global config_dict, visited_keys, always_save_keys
|
||
|
||
if key not in visited_keys:
|
||
visited_keys.append(key)
|
||
|
||
if key not in always_save_keys:
|
||
always_save_keys.append(key)
|
||
|
||
v = os.getenv(key)
|
||
if v is not None:
|
||
print(f"Environment: {key} = {v}")
|
||
config_dict[key] = v
|
||
else:
|
||
v = config_dict.get(key, None)
|
||
|
||
if isinstance(v, str):
|
||
if make_directory:
|
||
makedirs_with_log(v)
|
||
if os.path.exists(v) and os.path.isdir(v):
|
||
return v if not as_array else [v]
|
||
elif isinstance(v, list):
|
||
if make_directory:
|
||
for d in v:
|
||
makedirs_with_log(d)
|
||
if all([os.path.exists(d) and os.path.isdir(d) for d in v]):
|
||
return v
|
||
|
||
if v is not None:
|
||
print(
|
||
f'Failed to load config key: {json.dumps({key:v})} is invalid or does not exist; will use {json.dumps({key:default_value})} instead.')
|
||
if isinstance(default_value, list):
|
||
dp = []
|
||
for path in default_value:
|
||
abs_path = os.path.abspath(
|
||
os.path.join(os.path.dirname(__file__), path))
|
||
dp.append(abs_path)
|
||
os.makedirs(abs_path, exist_ok=True)
|
||
else:
|
||
dp = os.path.abspath(os.path.join(
|
||
os.path.dirname(__file__), default_value))
|
||
os.makedirs(dp, exist_ok=True)
|
||
if as_array:
|
||
dp = [dp]
|
||
config_dict[key] = dp
|
||
return dp
|
||
|
||
|
||
paths_checkpoints = get_dir_or_set_default(
|
||
'path_checkpoints', ['../models/checkpoints/'], True)
|
||
paths_loras = get_dir_or_set_default('path_loras', ['../models/loras/'], True)
|
||
path_embeddings = get_dir_or_set_default(
|
||
'path_embeddings', '../models/embeddings/')
|
||
path_vae_approx = get_dir_or_set_default(
|
||
'path_vae_approx', '../models/vae_approx/')
|
||
path_vae = get_dir_or_set_default('path_vae', '../models/vae/')
|
||
path_upscale_models = get_dir_or_set_default(
|
||
'path_upscale_models', '../models/upscale_models/')
|
||
path_inpaint = get_dir_or_set_default('path_inpaint', '../models/inpaint/')
|
||
path_controlnet = get_dir_or_set_default(
|
||
'path_controlnet', '../models/controlnet/')
|
||
path_clip_vision = get_dir_or_set_default(
|
||
'path_clip_vision', '../models/clip_vision/')
|
||
path_fooocus_expansion = get_dir_or_set_default(
|
||
'path_fooocus_expansion', '../models/prompt_expansion/fooocus_expansion')
|
||
path_wildcards = get_dir_or_set_default('path_wildcards', '../wildcards/')
|
||
path_safety_checker = get_dir_or_set_default(
|
||
'path_safety_checker', '../models/safety_checker/')
|
||
path_sam = get_dir_or_set_default('path_sam', '../models/sam/')
|
||
path_outputs = get_path_output()
|
||
|
||
|
||
def get_config_item_or_set_default(key, default_value, validator, disable_empty_as_none=False, expected_type=None):
|
||
global config_dict, visited_keys
|
||
|
||
if key not in visited_keys:
|
||
visited_keys.append(key)
|
||
|
||
v = os.getenv(key)
|
||
if v is not None:
|
||
v = try_eval_env_var(v, expected_type)
|
||
print(f"Environment: {key} = {v}")
|
||
config_dict[key] = v
|
||
|
||
if key not in config_dict:
|
||
config_dict[key] = default_value
|
||
return default_value
|
||
|
||
v = config_dict.get(key, None)
|
||
if not disable_empty_as_none:
|
||
if v is None or v == '':
|
||
v = 'None'
|
||
if validator(v):
|
||
return v
|
||
else:
|
||
if v is not None:
|
||
print(
|
||
f'Failed to load config key: {json.dumps({key:v})} is invalid; will use {json.dumps({key:default_value})} instead.')
|
||
config_dict[key] = default_value
|
||
return default_value
|
||
|
||
|
||
def init_temp_path(path: str | None, default_path: str) -> str:
|
||
if args_manager.args.temp_path:
|
||
path = args_manager.args.temp_path
|
||
|
||
if path != '' and path != default_path:
|
||
try:
|
||
if not os.path.isabs(path):
|
||
path = os.path.abspath(path)
|
||
os.makedirs(path, exist_ok=True)
|
||
print(f'Using temp path {path}')
|
||
return path
|
||
except Exception as e:
|
||
print(f'Could not create temp path {path}. Reason: {e}')
|
||
print(f'Using default temp path {default_path} instead.')
|
||
|
||
os.makedirs(default_path, exist_ok=True)
|
||
return default_path
|
||
|
||
|
||
default_temp_path = os.path.join(tempfile.gettempdir(), 'fooocus')
|
||
temp_path = init_temp_path(get_config_item_or_set_default(
|
||
key='temp_path',
|
||
default_value=default_temp_path,
|
||
validator=lambda x: isinstance(x, str),
|
||
expected_type=str
|
||
), default_temp_path)
|
||
temp_path_cleanup_on_launch = get_config_item_or_set_default(
|
||
key='temp_path_cleanup_on_launch',
|
||
default_value=True,
|
||
validator=lambda x: isinstance(x, bool),
|
||
expected_type=bool
|
||
)
|
||
default_base_model_name = default_model = get_config_item_or_set_default(
|
||
key='default_model',
|
||
default_value='model.safetensors',
|
||
validator=lambda x: isinstance(x, str),
|
||
expected_type=str
|
||
)
|
||
previous_default_models = get_config_item_or_set_default(
|
||
key='previous_default_models',
|
||
default_value=[],
|
||
validator=lambda x: isinstance(x, list) and all(
|
||
isinstance(k, str) for k in x),
|
||
expected_type=list
|
||
)
|
||
default_refiner_model_name = default_refiner = get_config_item_or_set_default(
|
||
key='default_refiner',
|
||
default_value='None',
|
||
validator=lambda x: isinstance(x, str),
|
||
expected_type=str
|
||
)
|
||
default_refiner_switch = get_config_item_or_set_default(
|
||
key='default_refiner_switch',
|
||
default_value=0.8,
|
||
validator=lambda x: isinstance(x, numbers.Number) and 0 <= x <= 1,
|
||
expected_type=numbers.Number
|
||
)
|
||
default_loras_min_weight = get_config_item_or_set_default(
|
||
key='default_loras_min_weight',
|
||
default_value=-2,
|
||
validator=lambda x: isinstance(x, numbers.Number) and -10 <= x <= 10,
|
||
expected_type=numbers.Number
|
||
)
|
||
default_loras_max_weight = get_config_item_or_set_default(
|
||
key='default_loras_max_weight',
|
||
default_value=2,
|
||
validator=lambda x: isinstance(x, numbers.Number) and -10 <= x <= 10,
|
||
expected_type=numbers.Number
|
||
)
|
||
default_loras = get_config_item_or_set_default(
|
||
key='default_loras',
|
||
default_value=[
|
||
[
|
||
True,
|
||
"None",
|
||
1.0
|
||
],
|
||
[
|
||
True,
|
||
"None",
|
||
1.0
|
||
],
|
||
[
|
||
True,
|
||
"None",
|
||
1.0
|
||
],
|
||
[
|
||
True,
|
||
"None",
|
||
1.0
|
||
],
|
||
[
|
||
True,
|
||
"None",
|
||
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)
|
||
or len(y) == 2 and isinstance(y[0], str) and isinstance(y[1], numbers.Number)
|
||
for y in x),
|
||
expected_type=list
|
||
)
|
||
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,
|
||
validator=lambda x: isinstance(x, int) and x >= 1,
|
||
expected_type=int
|
||
)
|
||
default_cfg_scale = get_config_item_or_set_default(
|
||
key='default_cfg_scale',
|
||
default_value=7.0,
|
||
validator=lambda x: isinstance(x, numbers.Number),
|
||
expected_type=numbers.Number
|
||
)
|
||
default_sample_sharpness = get_config_item_or_set_default(
|
||
key='default_sample_sharpness',
|
||
default_value=2.0,
|
||
validator=lambda x: isinstance(x, numbers.Number),
|
||
expected_type=numbers.Number
|
||
)
|
||
default_sampler = get_config_item_or_set_default(
|
||
key='default_sampler',
|
||
default_value='dpmpp_2m_sde_gpu',
|
||
validator=lambda x: x in modules.flags.sampler_list,
|
||
expected_type=str
|
||
)
|
||
default_scheduler = get_config_item_or_set_default(
|
||
key='default_scheduler',
|
||
default_value='karras',
|
||
validator=lambda x: x in modules.flags.scheduler_list,
|
||
expected_type=str
|
||
)
|
||
default_vae = get_config_item_or_set_default(
|
||
key='default_vae',
|
||
default_value=modules.flags.default_vae,
|
||
validator=lambda x: isinstance(x, str),
|
||
expected_type=str
|
||
)
|
||
default_styles = get_config_item_or_set_default(
|
||
key='default_styles',
|
||
default_value=[
|
||
"Fooocus V2",
|
||
"Fooocus Enhance",
|
||
"Fooocus Sharp"
|
||
],
|
||
validator=lambda x: isinstance(x, list) and all(
|
||
y in modules.sdxl_styles.legal_style_names for y in x),
|
||
expected_type=list
|
||
)
|
||
default_prompt_negative = get_config_item_or_set_default(
|
||
key='default_prompt_negative',
|
||
default_value='',
|
||
validator=lambda x: isinstance(x, str),
|
||
disable_empty_as_none=True,
|
||
expected_type=str
|
||
)
|
||
default_prompt = get_config_item_or_set_default(
|
||
key='default_prompt',
|
||
default_value='',
|
||
validator=lambda x: isinstance(x, str),
|
||
disable_empty_as_none=True,
|
||
expected_type=str
|
||
)
|
||
default_performance = get_config_item_or_set_default(
|
||
key='default_performance',
|
||
default_value=Performance.SPEED.value,
|
||
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,
|
||
validator=lambda x: isinstance(x, int) and x >= 1,
|
||
expected_type=int
|
||
)
|
||
default_output_format = get_config_item_or_set_default(
|
||
key='default_output_format',
|
||
default_value='png',
|
||
validator=lambda x: x in OutputFormat.list(),
|
||
expected_type=str
|
||
)
|
||
default_image_number = get_config_item_or_set_default(
|
||
key='default_image_number',
|
||
default_value=2,
|
||
validator=lambda x: isinstance(
|
||
x, int) and 1 <= x <= default_max_image_number,
|
||
expected_type=int
|
||
)
|
||
checkpoint_downloads = get_config_item_or_set_default(
|
||
key='checkpoint_downloads',
|
||
default_value={},
|
||
validator=lambda x: isinstance(x, dict) and all(
|
||
isinstance(k, str) and isinstance(v, str) for k, v in x.items()),
|
||
expected_type=dict
|
||
)
|
||
lora_downloads = get_config_item_or_set_default(
|
||
key='lora_downloads',
|
||
default_value={},
|
||
validator=lambda x: isinstance(x, dict) and all(
|
||
isinstance(k, str) and isinstance(v, str) for k, v in x.items()),
|
||
expected_type=dict
|
||
)
|
||
embeddings_downloads = get_config_item_or_set_default(
|
||
key='embeddings_downloads',
|
||
default_value={},
|
||
validator=lambda x: isinstance(x, dict) and all(
|
||
isinstance(k, str) and isinstance(v, str) for k, v in x.items()),
|
||
expected_type=dict
|
||
)
|
||
vae_downloads = get_config_item_or_set_default(
|
||
key='vae_downloads',
|
||
default_value={},
|
||
validator=lambda x: isinstance(x, dict) and all(
|
||
isinstance(k, str) and isinstance(v, str) for k, v in x.items()),
|
||
expected_type=dict
|
||
)
|
||
available_aspect_ratios = get_config_item_or_set_default(
|
||
key='available_aspect_ratios',
|
||
default_value=modules.flags.sdxl_aspect_ratios,
|
||
validator=lambda x: isinstance(x, list) and all(
|
||
'*' in v for v in x) and len(x) > 1,
|
||
expected_type=list
|
||
)
|
||
default_aspect_ratio = get_config_item_or_set_default(
|
||
key='default_aspect_ratio',
|
||
default_value='1152*896' if '1152*896' in available_aspect_ratios else available_aspect_ratios[0],
|
||
validator=lambda x: x in available_aspect_ratios,
|
||
expected_type=str
|
||
)
|
||
default_inpaint_engine_version = get_config_item_or_set_default(
|
||
key='default_inpaint_engine_version',
|
||
default_value='v2.6',
|
||
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,
|
||
validator=lambda x: x in modules.flags.inpaint_options,
|
||
expected_type=str
|
||
)
|
||
default_cfg_tsnr = get_config_item_or_set_default(
|
||
key='default_cfg_tsnr',
|
||
default_value=7.0,
|
||
validator=lambda x: isinstance(x, numbers.Number),
|
||
expected_type=numbers.Number
|
||
)
|
||
default_clip_skip = get_config_item_or_set_default(
|
||
key='default_clip_skip',
|
||
default_value=2,
|
||
validator=lambda x: isinstance(
|
||
x, int) and 1 <= x <= modules.flags.clip_skip_max,
|
||
expected_type=int
|
||
)
|
||
default_overwrite_step = get_config_item_or_set_default(
|
||
key='default_overwrite_step',
|
||
default_value=-1,
|
||
validator=lambda x: isinstance(x, int),
|
||
expected_type=int
|
||
)
|
||
default_overwrite_switch = get_config_item_or_set_default(
|
||
key='default_overwrite_switch',
|
||
default_value=-1,
|
||
validator=lambda x: isinstance(x, int),
|
||
expected_type=int
|
||
)
|
||
default_overwrite_upscale = get_config_item_or_set_default(
|
||
key='default_overwrite_upscale',
|
||
default_value=-1,
|
||
validator=lambda x: isinstance(x, numbers.Number)
|
||
)
|
||
example_inpaint_prompts = get_config_item_or_set_default(
|
||
key='example_inpaint_prompts',
|
||
default_value=[
|
||
'highly detailed face', 'detailed girl face', 'detailed man face', 'detailed hand', 'beautiful eyes'
|
||
],
|
||
validator=lambda x: isinstance(x, list) and all(
|
||
isinstance(v, str) for v in x),
|
||
expected_type=list
|
||
)
|
||
example_enhance_detection_prompts = get_config_item_or_set_default(
|
||
key='example_enhance_detection_prompts',
|
||
default_value=[
|
||
'face', 'eye', 'mouth', 'hair', 'hand', 'body'
|
||
],
|
||
validator=lambda x: isinstance(x, list) and all(
|
||
isinstance(v, str) for v in x),
|
||
expected_type=list
|
||
)
|
||
|
||
default_enhance_prompts = {
|
||
'face': {
|
||
'positive': "Enhance the face to ensure clear and detailed features. The face should have a well-defined structure with smooth skin, natural contours, and a balanced complexion. Make sure the expression is natural and engaging.",
|
||
'negative': "Avoid any blurriness or distortions in the face. Do not include uneven skin tones, unnatural facial expressions, or any missing facial features. Ensure there are no artifacts or unnatural smoothing that might distort the face's natural appearance."
|
||
},
|
||
'eye': {
|
||
'positive': "Enhance the eyes to be clear, sharp, and vividly detailed. The eyes should have natural reflections and a realistic appearance. Ensure the irises and pupils are distinct, and there are no shadows or blurs affecting the eyes.",
|
||
'negative': "Exclude any blurring, distortions, or unnatural reflections in the eyes. Avoid asymmetrical or misaligned eyes, and ensure there are no unnatural colors or artifacts that could detract from a realistic appearance."
|
||
},
|
||
'mouth': {
|
||
'positive': "Enhance the mouth to appear natural and symmetrical. The lips should be smooth and well-defined, with no abnormalities. Ensure the mouth reflects a realistic expression and that teeth are visible only if naturally exposed.",
|
||
'negative': "Avoid any distortions, asymmetry, or unnatural shapes in the mouth. Do not include missing or extra teeth, and ensure there are no anomalies or artifacts affecting the mouth's appearance."
|
||
},
|
||
'hair': {
|
||
'positive': "Enhance the hair to look full, natural, and well-styled. The texture should be realistic, with clear individual strands or locks and natural shine. Ensure the color and style match the intended look without any unnatural effects.",
|
||
'negative': "Exclude any unnatural textures, blurs, or artifacts in the hair. Avoid colors that look artificial or inconsistent, and ensure there are no missing or irregular sections of hair that could disrupt the natural appearance."
|
||
},
|
||
'hand': {
|
||
'positive': "Enhance the hands to ensure all fingers are clearly visible and well-defined. The hands should have realistic textures and proportions, with no missing or distorted fingers. The overall appearance should be natural and proportional.",
|
||
'negative': "Avoid any distortions or missing fingers in the hands. Do not include unnatural shapes or proportions, and ensure there are no anomalies or artifacts that affect the realistic appearance of the hands."
|
||
},
|
||
'body': {
|
||
'positive': "Enhance the body to ensure a complete and natural appearance with all limbs properly defined. The body should reflect realistic proportions and posture, with no missing or distorted body parts. Ensure the overall shape and anatomy are natural and well-balanced.",
|
||
'negative': "Exclude any missing limbs, distortions, or unrealistic body shapes. Avoid anomalies in body posture or proportions, and ensure there are no artifacts or inconsistencies that could affect the natural appearance of the body."
|
||
}
|
||
}
|
||
|
||
default_enhance_tabs = get_config_item_or_set_default(
|
||
key='default_enhance_tabs',
|
||
default_value=3,
|
||
validator=lambda x: isinstance(x, int) and 1 <= x <= 5,
|
||
expected_type=int
|
||
)
|
||
default_enhance_uov_method = get_config_item_or_set_default(
|
||
key='default_enhance_uov_method',
|
||
default_value=modules.flags.disabled,
|
||
validator=lambda x: x in modules.flags.uov_list,
|
||
expected_type=int
|
||
)
|
||
default_enhance_uov_processing_order = get_config_item_or_set_default(
|
||
key='default_enhance_uov_processing_order',
|
||
default_value=modules.flags.enhancement_uov_before,
|
||
validator=lambda x: x in modules.flags.enhancement_uov_processing_order,
|
||
expected_type=int
|
||
)
|
||
default_enhance_uov_prompt_type = get_config_item_or_set_default(
|
||
key='default_enhance_uov_prompt_type',
|
||
default_value=modules.flags.enhancement_uov_prompt_type_original,
|
||
validator=lambda x: x in modules.flags.enhancement_uov_prompt_types,
|
||
expected_type=int
|
||
)
|
||
default_sam_max_detections = get_config_item_or_set_default(
|
||
key='default_sam_max_detections',
|
||
default_value=0,
|
||
validator=lambda x: isinstance(x, int) and 0 <= x <= 10,
|
||
expected_type=int
|
||
)
|
||
default_black_out_nsfw = get_config_item_or_set_default(
|
||
key='default_black_out_nsfw',
|
||
default_value=False,
|
||
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,
|
||
validator=lambda x: isinstance(x, bool),
|
||
expected_type=bool
|
||
)
|
||
default_metadata_scheme = get_config_item_or_set_default(
|
||
key='default_metadata_scheme',
|
||
default_value=MetadataScheme.FOOOCUS.value,
|
||
validator=lambda x: x in [y[1]
|
||
for y in modules.flags.metadata_scheme if y[1] == x],
|
||
expected_type=str
|
||
)
|
||
metadata_created_by = get_config_item_or_set_default(
|
||
key='metadata_created_by',
|
||
default_value='',
|
||
validator=lambda x: isinstance(x, str),
|
||
expected_type=str
|
||
)
|
||
|
||
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',
|
||
validator=lambda x: x in modules.flags.inpaint_mask_models,
|
||
expected_type=str
|
||
)
|
||
|
||
default_enhance_inpaint_mask_model = get_config_item_or_set_default(
|
||
key='default_enhance_inpaint_mask_model',
|
||
default_value='sam',
|
||
validator=lambda x: x in modules.flags.inpaint_mask_models,
|
||
expected_type=str
|
||
)
|
||
|
||
default_inpaint_mask_cloth_category = get_config_item_or_set_default(
|
||
key='default_inpaint_mask_cloth_category',
|
||
default_value='full',
|
||
validator=lambda x: x in modules.flags.inpaint_mask_cloth_category,
|
||
expected_type=str
|
||
)
|
||
|
||
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 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
|
||
possible_preset_keys = {
|
||
"default_model": "base_model",
|
||
"default_refiner": "refiner_model",
|
||
"default_refiner_switch": "refiner_switch",
|
||
"previous_default_models": "previous_default_models",
|
||
"default_loras_min_weight": "default_loras_min_weight",
|
||
"default_loras_max_weight": "default_loras_max_weight",
|
||
"default_loras": "<processed>",
|
||
"default_cfg_scale": "guidance_scale",
|
||
"default_sample_sharpness": "sharpness",
|
||
"default_cfg_tsnr": "adaptive_cfg",
|
||
"default_clip_skip": "clip_skip",
|
||
"default_sampler": "sampler",
|
||
"default_scheduler": "scheduler",
|
||
"default_overwrite_step": "steps",
|
||
"default_overwrite_switch": "overwrite_switch",
|
||
"default_performance": "performance",
|
||
"default_image_number": "image_number",
|
||
"default_prompt": "prompt",
|
||
"default_prompt_negative": "negative_prompt",
|
||
"default_styles": "styles",
|
||
"default_aspect_ratio": "resolution",
|
||
"default_save_metadata_to_images": "default_save_metadata_to_images",
|
||
"checkpoint_downloads": "checkpoint_downloads",
|
||
"embeddings_downloads": "embeddings_downloads",
|
||
"lora_downloads": "lora_downloads",
|
||
"vae_downloads": "vae_downloads",
|
||
"default_vae": "vae",
|
||
# "default_inpaint_method": "inpaint_method", # disabled so inpaint mode doesn't refresh after every preset change
|
||
"default_inpaint_engine_version": "inpaint_engine_version",
|
||
}
|
||
|
||
REWRITE_PRESET = False
|
||
|
||
if REWRITE_PRESET and isinstance(args_manager.args.preset, str):
|
||
save_path = 'presets/' + args_manager.args.preset + '.json'
|
||
with open(save_path, "w", encoding="utf-8") as json_file:
|
||
json.dump({k: config_dict[k]
|
||
for k in possible_preset_keys}, json_file, indent=4)
|
||
print(f'Preset saved to {save_path}. Exiting ...')
|
||
exit(0)
|
||
|
||
|
||
def add_ratio(x):
|
||
a, b = x.replace('*', ' ').split(' ')[:2]
|
||
a, b = int(a), int(b)
|
||
g = math.gcd(a, b)
|
||
return f'{a}×{b} <span style="color: grey;"> \U00002223 {a // g}:{b // g}</span>'
|
||
|
||
|
||
default_aspect_ratio = add_ratio(default_aspect_ratio)
|
||
available_aspect_ratios_labels = [
|
||
add_ratio(x) for x in available_aspect_ratios]
|
||
|
||
|
||
# Only write config in the first launch.
|
||
if not os.path.exists(config_path):
|
||
with open(config_path, "w", encoding="utf-8") as json_file:
|
||
json.dump({k: config_dict[k]
|
||
for k in always_save_keys}, json_file, indent=4)
|
||
|
||
|
||
# Always write tutorials.
|
||
with open(config_example_path, "w", encoding="utf-8") as json_file:
|
||
cpa = config_path.replace("\\", "\\\\")
|
||
json_file.write(f'You can modify your "{cpa}" using the below keys, formats, and examples.\n'
|
||
f'Do not modify this file. Modifications in this file will not take effect.\n'
|
||
f'This file is a tutorial and example. Please edit "{cpa}" to really change any settings.\n'
|
||
+ 'Remember to split the paths with "\\\\" rather than "\\", '
|
||
'and there is no "," before the last "}". \n\n\n')
|
||
json.dump({k: config_dict[k] for k in visited_keys}, json_file, indent=4)
|
||
|
||
model_filenames = []
|
||
lora_filenames = []
|
||
vae_filenames = []
|
||
wildcard_filenames = []
|
||
|
||
|
||
def get_model_filenames(folder_paths, extensions=None, name_filter=None):
|
||
if extensions is None:
|
||
extensions = ['.pth', '.ckpt', '.bin',
|
||
'.safetensors', '.fooocus.patch']
|
||
files = []
|
||
|
||
if not isinstance(folder_paths, list):
|
||
folder_paths = [folder_paths]
|
||
for folder in folder_paths:
|
||
files += get_files_from_folder(folder, extensions, name_filter)
|
||
|
||
return files
|
||
|
||
|
||
def update_files():
|
||
global model_filenames, lora_filenames, vae_filenames, wildcard_filenames, available_presets
|
||
model_filenames = get_model_filenames(paths_checkpoints)
|
||
lora_filenames = get_model_filenames(paths_loras)
|
||
vae_filenames = get_model_filenames(path_vae)
|
||
wildcard_filenames = get_files_from_folder(path_wildcards, ['.txt'])
|
||
available_presets = get_presets()
|
||
return
|
||
|
||
|
||
def downloading_inpaint_models(v):
|
||
assert v in modules.flags.inpaint_engine_versions
|
||
|
||
load_file_from_url(
|
||
url='https://huggingface.co/lllyasviel/fooocus_inpaint/resolve/main/fooocus_inpaint_head.pth',
|
||
model_dir=path_inpaint,
|
||
file_name='fooocus_inpaint_head.pth'
|
||
)
|
||
head_file = os.path.join(path_inpaint, 'fooocus_inpaint_head.pth')
|
||
patch_file = None
|
||
|
||
if v == 'v1':
|
||
load_file_from_url(
|
||
url='https://huggingface.co/lllyasviel/fooocus_inpaint/resolve/main/inpaint.fooocus.patch',
|
||
model_dir=path_inpaint,
|
||
file_name='inpaint.fooocus.patch'
|
||
)
|
||
patch_file = os.path.join(path_inpaint, 'inpaint.fooocus.patch')
|
||
|
||
if v == 'v2.5':
|
||
load_file_from_url(
|
||
url='https://huggingface.co/lllyasviel/fooocus_inpaint/resolve/main/inpaint_v25.fooocus.patch',
|
||
model_dir=path_inpaint,
|
||
file_name='inpaint_v25.fooocus.patch'
|
||
)
|
||
patch_file = os.path.join(path_inpaint, 'inpaint_v25.fooocus.patch')
|
||
|
||
if v == 'v2.6':
|
||
load_file_from_url(
|
||
url='https://huggingface.co/lllyasviel/fooocus_inpaint/resolve/main/inpaint_v26.fooocus.patch',
|
||
model_dir=path_inpaint,
|
||
file_name='inpaint_v26.fooocus.patch'
|
||
)
|
||
patch_file = os.path.join(path_inpaint, 'inpaint_v26.fooocus.patch')
|
||
|
||
return head_file, patch_file
|
||
|
||
|
||
def downloading_sdxl_lcm_lora():
|
||
load_file_from_url(
|
||
url='https://huggingface.co/lllyasviel/misc/resolve/main/sdxl_lcm_lora.safetensors',
|
||
model_dir=paths_loras[0],
|
||
file_name=modules.flags.PerformanceLoRA.EXTREME_SPEED.value
|
||
)
|
||
return modules.flags.PerformanceLoRA.EXTREME_SPEED.value
|
||
|
||
|
||
def downloading_sdxl_lightning_lora():
|
||
load_file_from_url(
|
||
url='https://huggingface.co/mashb1t/misc/resolve/main/sdxl_lightning_4step_lora.safetensors',
|
||
model_dir=paths_loras[0],
|
||
file_name=modules.flags.PerformanceLoRA.LIGHTNING.value
|
||
)
|
||
return modules.flags.PerformanceLoRA.LIGHTNING.value
|
||
|
||
|
||
def downloading_sdxl_hyper_sd_lora():
|
||
load_file_from_url(
|
||
url='https://huggingface.co/mashb1t/misc/resolve/main/sdxl_hyper_sd_4step_lora.safetensors',
|
||
model_dir=paths_loras[0],
|
||
file_name=modules.flags.PerformanceLoRA.HYPER_SD.value
|
||
)
|
||
return modules.flags.PerformanceLoRA.HYPER_SD.value
|
||
|
||
|
||
def downloading_controlnet_canny():
|
||
load_file_from_url(
|
||
url='https://huggingface.co/lllyasviel/misc/resolve/main/control-lora-canny-rank128.safetensors',
|
||
model_dir=path_controlnet,
|
||
file_name='control-lora-canny-rank128.safetensors'
|
||
)
|
||
return os.path.join(path_controlnet, 'control-lora-canny-rank128.safetensors')
|
||
|
||
|
||
def downloading_controlnet_cpds():
|
||
load_file_from_url(
|
||
url='https://huggingface.co/lllyasviel/misc/resolve/main/fooocus_xl_cpds_128.safetensors',
|
||
model_dir=path_controlnet,
|
||
file_name='fooocus_xl_cpds_128.safetensors'
|
||
)
|
||
return os.path.join(path_controlnet, 'fooocus_xl_cpds_128.safetensors')
|
||
|
||
|
||
def downloading_ip_adapters(v):
|
||
assert v in ['ip', 'face']
|
||
|
||
results = []
|
||
|
||
load_file_from_url(
|
||
url='https://huggingface.co/lllyasviel/misc/resolve/main/clip_vision_vit_h.safetensors',
|
||
model_dir=path_clip_vision,
|
||
file_name='clip_vision_vit_h.safetensors'
|
||
)
|
||
results += [os.path.join(path_clip_vision,
|
||
'clip_vision_vit_h.safetensors')]
|
||
|
||
load_file_from_url(
|
||
url='https://huggingface.co/lllyasviel/misc/resolve/main/fooocus_ip_negative.safetensors',
|
||
model_dir=path_controlnet,
|
||
file_name='fooocus_ip_negative.safetensors'
|
||
)
|
||
results += [os.path.join(path_controlnet,
|
||
'fooocus_ip_negative.safetensors')]
|
||
|
||
if v == 'ip':
|
||
load_file_from_url(
|
||
url='https://huggingface.co/lllyasviel/misc/resolve/main/ip-adapter-plus_sdxl_vit-h.bin',
|
||
model_dir=path_controlnet,
|
||
file_name='ip-adapter-plus_sdxl_vit-h.bin'
|
||
)
|
||
results += [os.path.join(path_controlnet,
|
||
'ip-adapter-plus_sdxl_vit-h.bin')]
|
||
|
||
if v == 'face':
|
||
load_file_from_url(
|
||
url='https://huggingface.co/lllyasviel/misc/resolve/main/ip-adapter-plus-face_sdxl_vit-h.bin',
|
||
model_dir=path_controlnet,
|
||
file_name='ip-adapter-plus-face_sdxl_vit-h.bin'
|
||
)
|
||
results += [os.path.join(path_controlnet,
|
||
'ip-adapter-plus-face_sdxl_vit-h.bin')]
|
||
|
||
return results
|
||
|
||
|
||
def downloading_upscale_model():
|
||
load_file_from_url(
|
||
url='https://huggingface.co/lllyasviel/misc/resolve/main/fooocus_upscaler_s409985e5.bin',
|
||
model_dir=path_upscale_models,
|
||
file_name='fooocus_upscaler_s409985e5.bin'
|
||
)
|
||
return os.path.join(path_upscale_models, 'fooocus_upscaler_s409985e5.bin')
|
||
|
||
|
||
def downloading_safety_checker_model():
|
||
load_file_from_url(
|
||
url='https://huggingface.co/mashb1t/misc/resolve/main/stable-diffusion-safety-checker.bin',
|
||
model_dir=path_safety_checker,
|
||
file_name='stable-diffusion-safety-checker.bin'
|
||
)
|
||
return os.path.join(path_safety_checker, 'stable-diffusion-safety-checker.bin')
|
||
|
||
|
||
def download_sam_model(sam_model: str) -> str:
|
||
match sam_model:
|
||
case 'vit_b':
|
||
return downloading_sam_vit_b()
|
||
case 'vit_l':
|
||
return downloading_sam_vit_l()
|
||
case 'vit_h':
|
||
return downloading_sam_vit_h()
|
||
case _:
|
||
raise ValueError(f"sam model {sam_model} does not exist.")
|
||
|
||
|
||
def downloading_sam_vit_b():
|
||
load_file_from_url(
|
||
url='https://huggingface.co/mashb1t/misc/resolve/main/sam_vit_b_01ec64.pth',
|
||
model_dir=path_sam,
|
||
file_name='sam_vit_b_01ec64.pth'
|
||
)
|
||
return os.path.join(path_sam, 'sam_vit_b_01ec64.pth')
|
||
|
||
|
||
def downloading_sam_vit_l():
|
||
load_file_from_url(
|
||
url='https://huggingface.co/mashb1t/misc/resolve/main/sam_vit_l_0b3195.pth',
|
||
model_dir=path_sam,
|
||
file_name='sam_vit_l_0b3195.pth'
|
||
)
|
||
return os.path.join(path_sam, 'sam_vit_l_0b3195.pth')
|
||
|
||
|
||
def downloading_sam_vit_h():
|
||
load_file_from_url(
|
||
url='https://huggingface.co/mashb1t/misc/resolve/main/sam_vit_h_4b8939.pth',
|
||
model_dir=path_sam,
|
||
file_name='sam_vit_h_4b8939.pth'
|
||
)
|
||
return os.path.join(path_sam, 'sam_vit_h_4b8939.pth')
|