diff --git a/fooocus_api_version.py b/fooocus_api_version.py index 9adc13c..576e0fc 100644 --- a/fooocus_api_version.py +++ b/fooocus_api_version.py @@ -1 +1 @@ -version = '0.4.1.0' +version = '0.4.1.1' diff --git a/fooocusapi/worker.py b/fooocusapi/worker.py index ed2a481..4bab45c 100644 --- a/fooocusapi/worker.py +++ b/fooocusapi/worker.py @@ -103,7 +103,8 @@ def process_generate(async_task: QueueTask): remove_empty_str, HWC3, resize_image, get_image_shape_ceil, set_image_shape_ceil, get_shape_ceil, resample_image, erode_or_dilate, - get_enabled_loras, parse_lora_references_from_prompt, apply_wildcards + get_enabled_loras, parse_lora_references_from_prompt, apply_wildcards, + remove_performance_lora ) from modules.upscaler import perform_upscale @@ -540,8 +541,10 @@ def yield_result(_, images, tasks, extension='png', extra_negative_prompts = negative_prompts[1:] if len(negative_prompts) > 1 else [] progressbar(async_task, 3, 'Loading models ...') - loras, prompt = parse_lora_references_from_prompt(prompt, loras, config.default_max_lora_number) + lora_filenames = remove_performance_lora(config.lora_filenames, performance_selection) + loras, prompt = parse_lora_references_from_prompt(prompt, loras, config.default_max_lora_number, lora_filenames=lora_filenames) loras += performance_loras + pipeline.refresh_everything( refiner_model_name=refiner_model_name, base_model_name=base_model_name, @@ -926,16 +929,33 @@ def yield_result(_, images, tasks, extension='png', if scheduler_name in ['lcm', 'tcd']: final_scheduler_name = 'sgm_uniform' - if pipeline.final_unet is not None: - pipeline.final_unet = core.opModelSamplingDiscrete.patch( + + def patch_discrete(unet): + return core.opModelSamplingDiscrete.patch( pipeline.final_unet, sampling=scheduler_name, zsnr=False)[0] + + if pipeline.final_unet is not None: + pipeline.final_unet = patch_discrete(pipeline.final_unet) if pipeline.final_refiner_unet is not None: - pipeline.final_refiner_unet = core.opModelSamplingDiscrete.patch( - pipeline.final_refiner_unet, + pipeline.final_refiner_unet = patch_discrete(pipeline.final_refiner_unet) + logger.std_info(f'[Fooocus] Using {scheduler_name} scheduler.') + elif scheduler_name == 'edm_playground_v2.5': + final_scheduler_name = 'karras' + + def patch_edm(unet): + return core.opModelSamplingContinuousEDM.patch( + unet, sampling=scheduler_name, - zsnr=False)[0] + sigma_max=120.0, + sigma_min=0.002)[0] + + if pipeline.final_unet is not None: + pipeline.final_unet = patch_edm(pipeline.final_unet) + if pipeline.final_refiner_unet is not None: + pipeline.final_refiner_unet = patch_edm(pipeline.final_refiner_unet) + logger.std_info(f'[Fooocus] Using {scheduler_name} scheduler.') outputs.append(['preview', (13, 'Moving model to GPU ...', None)]) diff --git a/repositories/Fooocus/args_manager.py b/repositories/Fooocus/args_manager.py index e023da2..5a2b37c 100644 --- a/repositories/Fooocus/args_manager.py +++ b/repositories/Fooocus/args_manager.py @@ -1,7 +1,4 @@ import ldm_patched.modules.args_parser as args_parser -import os - -from tempfile import gettempdir args_parser.parser.add_argument("--share", action='store_true', help="Set whether to share on Gradio.") diff --git a/repositories/Fooocus/fooocus_version.py b/repositories/Fooocus/fooocus_version.py index 7501145..84d1586 100644 --- a/repositories/Fooocus/fooocus_version.py +++ b/repositories/Fooocus/fooocus_version.py @@ -1 +1 @@ -version = '2.4.1' +version = '2.4.3' diff --git a/repositories/Fooocus/ldm_patched/contrib/external_custom_sampler.py b/repositories/Fooocus/ldm_patched/contrib/external_custom_sampler.py index 985b03a..60d5e3b 100644 --- a/repositories/Fooocus/ldm_patched/contrib/external_custom_sampler.py +++ b/repositories/Fooocus/ldm_patched/contrib/external_custom_sampler.py @@ -107,8 +107,7 @@ def INPUT_TYPES(s): def get_sigmas(self, model, steps, denoise): start_step = 10 - int(10 * denoise) timesteps = torch.flip(torch.arange(1, 11) * 100 - 1, (0,))[start_step:start_step + steps] - ldm_patched.modules.model_management.load_models_gpu([model]) - sigmas = model.model.model_sampling.sigma(timesteps) + sigmas = model.model_sampling.sigma(timesteps) sigmas = torch.cat([sigmas, sigmas.new_zeros([1])]) return (sigmas, ) diff --git a/repositories/Fooocus/ldm_patched/contrib/external_model_advanced.py b/repositories/Fooocus/ldm_patched/contrib/external_model_advanced.py index 9b52c36..b9f0ebd 100644 --- a/repositories/Fooocus/ldm_patched/contrib/external_model_advanced.py +++ b/repositories/Fooocus/ldm_patched/contrib/external_model_advanced.py @@ -108,7 +108,7 @@ class ModelSamplingContinuousEDM: @classmethod def INPUT_TYPES(s): return {"required": { "model": ("MODEL",), - "sampling": (["v_prediction", "eps"],), + "sampling": (["v_prediction", "edm_playground_v2.5", "eps"],), "sigma_max": ("FLOAT", {"default": 120.0, "min": 0.0, "max": 1000.0, "step":0.001, "round": False}), "sigma_min": ("FLOAT", {"default": 0.002, "min": 0.0, "max": 1000.0, "step":0.001, "round": False}), }} @@ -121,17 +121,25 @@ def INPUT_TYPES(s): def patch(self, model, sampling, sigma_max, sigma_min): m = model.clone() + latent_format = None + sigma_data = 1.0 if sampling == "eps": sampling_type = ldm_patched.modules.model_sampling.EPS elif sampling == "v_prediction": sampling_type = ldm_patched.modules.model_sampling.V_PREDICTION + elif sampling == "edm_playground_v2.5": + sampling_type = ldm_patched.modules.model_sampling.EDM + sigma_data = 0.5 + latent_format = ldm_patched.modules.latent_formats.SDXL_Playground_2_5() class ModelSamplingAdvanced(ldm_patched.modules.model_sampling.ModelSamplingContinuousEDM, sampling_type): pass model_sampling = ModelSamplingAdvanced(model.model.model_config) - model_sampling.set_sigma_range(sigma_min, sigma_max) + model_sampling.set_parameters(sigma_min, sigma_max, sigma_data) m.add_object_patch("model_sampling", model_sampling) + if latent_format is not None: + m.add_object_patch("latent_format", latent_format) return (m, ) class RescaleCFG: diff --git a/repositories/Fooocus/ldm_patched/k_diffusion/sampling.py b/repositories/Fooocus/ldm_patched/k_diffusion/sampling.py index d1bc1e4..ea5540a 100644 --- a/repositories/Fooocus/ldm_patched/k_diffusion/sampling.py +++ b/repositories/Fooocus/ldm_patched/k_diffusion/sampling.py @@ -832,5 +832,7 @@ def sample_tcd(model, x, sigmas, extra_args=None, callback=None, disable=None, n if eta > 0 and sigmas[i + 1] > 0: noise = noise_sampler(sigmas[i], sigmas[i + 1]) x = x / alpha_prod_s[i+1].sqrt() + noise * (sigmas[i+1]**2 + 1 - 1/alpha_prod_s[i+1]).sqrt() + else: + x *= torch.sqrt(1.0 + sigmas[i + 1] ** 2) return x \ No newline at end of file diff --git a/repositories/Fooocus/ldm_patched/modules/latent_formats.py b/repositories/Fooocus/ldm_patched/modules/latent_formats.py index 2252a07..1606793 100644 --- a/repositories/Fooocus/ldm_patched/modules/latent_formats.py +++ b/repositories/Fooocus/ldm_patched/modules/latent_formats.py @@ -1,3 +1,4 @@ +import torch class LatentFormat: scale_factor = 1.0 @@ -34,6 +35,70 @@ def __init__(self): ] self.taesd_decoder_name = "taesdxl_decoder" +class SDXL_Playground_2_5(LatentFormat): + def __init__(self): + self.scale_factor = 0.5 + self.latents_mean = torch.tensor([-1.6574, 1.886, -1.383, 2.5155]).view(1, 4, 1, 1) + self.latents_std = torch.tensor([8.4927, 5.9022, 6.5498, 5.2299]).view(1, 4, 1, 1) + + self.latent_rgb_factors = [ + # R G B + [ 0.3920, 0.4054, 0.4549], + [-0.2634, -0.0196, 0.0653], + [ 0.0568, 0.1687, -0.0755], + [-0.3112, -0.2359, -0.2076] + ] + self.taesd_decoder_name = "taesdxl_decoder" + + def process_in(self, latent): + latents_mean = self.latents_mean.to(latent.device, latent.dtype) + latents_std = self.latents_std.to(latent.device, latent.dtype) + return (latent - latents_mean) * self.scale_factor / latents_std + + def process_out(self, latent): + latents_mean = self.latents_mean.to(latent.device, latent.dtype) + latents_std = self.latents_std.to(latent.device, latent.dtype) + return latent * latents_std / self.scale_factor + latents_mean + + class SD_X4(LatentFormat): def __init__(self): self.scale_factor = 0.08333 + self.latent_rgb_factors = [ + [-0.2340, -0.3863, -0.3257], + [ 0.0994, 0.0885, -0.0908], + [-0.2833, -0.2349, -0.3741], + [ 0.2523, -0.0055, -0.1651] + ] + +class SC_Prior(LatentFormat): + def __init__(self): + self.scale_factor = 1.0 + self.latent_rgb_factors = [ + [-0.0326, -0.0204, -0.0127], + [-0.1592, -0.0427, 0.0216], + [ 0.0873, 0.0638, -0.0020], + [-0.0602, 0.0442, 0.1304], + [ 0.0800, -0.0313, -0.1796], + [-0.0810, -0.0638, -0.1581], + [ 0.1791, 0.1180, 0.0967], + [ 0.0740, 0.1416, 0.0432], + [-0.1745, -0.1888, -0.1373], + [ 0.2412, 0.1577, 0.0928], + [ 0.1908, 0.0998, 0.0682], + [ 0.0209, 0.0365, -0.0092], + [ 0.0448, -0.0650, -0.1728], + [-0.1658, -0.1045, -0.1308], + [ 0.0542, 0.1545, 0.1325], + [-0.0352, -0.1672, -0.2541] + ] + +class SC_B(LatentFormat): + def __init__(self): + self.scale_factor = 1.0 / 0.43 + self.latent_rgb_factors = [ + [ 0.1121, 0.2006, 0.1023], + [-0.2093, -0.0222, -0.0195], + [-0.3087, -0.1535, 0.0366], + [ 0.0290, -0.1574, -0.4078] + ] \ No newline at end of file diff --git a/repositories/Fooocus/ldm_patched/modules/model_sampling.py b/repositories/Fooocus/ldm_patched/modules/model_sampling.py index 57f51a0..8971b4e 100644 --- a/repositories/Fooocus/ldm_patched/modules/model_sampling.py +++ b/repositories/Fooocus/ldm_patched/modules/model_sampling.py @@ -1,7 +1,7 @@ import torch -import numpy as np from ldm_patched.ldm.modules.diffusionmodules.util import make_beta_schedule import math +import numpy as np class EPS: def calculate_input(self, sigma, noise): @@ -12,12 +12,28 @@ def calculate_denoised(self, sigma, model_output, model_input): sigma = sigma.view(sigma.shape[:1] + (1,) * (model_output.ndim - 1)) return model_input - model_output * sigma + def noise_scaling(self, sigma, noise, latent_image, max_denoise=False): + if max_denoise: + noise = noise * torch.sqrt(1.0 + sigma ** 2.0) + else: + noise = noise * sigma + + noise += latent_image + return noise + + def inverse_noise_scaling(self, sigma, latent): + return latent class V_PREDICTION(EPS): def calculate_denoised(self, sigma, model_output, model_input): sigma = sigma.view(sigma.shape[:1] + (1,) * (model_output.ndim - 1)) return model_input * self.sigma_data ** 2 / (sigma ** 2 + self.sigma_data ** 2) - model_output * sigma * self.sigma_data / (sigma ** 2 + self.sigma_data ** 2) ** 0.5 +class EDM(V_PREDICTION): + def calculate_denoised(self, sigma, model_output, model_input): + sigma = sigma.view(sigma.shape[:1] + (1,) * (model_output.ndim - 1)) + return model_input * self.sigma_data ** 2 / (sigma ** 2 + self.sigma_data ** 2) + model_output * sigma * self.sigma_data / (sigma ** 2 + self.sigma_data ** 2) ** 0.5 + class ModelSamplingDiscrete(torch.nn.Module): def __init__(self, model_config=None): @@ -42,21 +58,25 @@ def _register_schedule(self, given_betas=None, beta_schedule="linear", timesteps else: betas = make_beta_schedule(beta_schedule, timesteps, linear_start=linear_start, linear_end=linear_end, cosine_s=cosine_s) alphas = 1. - betas - alphas_cumprod = torch.tensor(np.cumprod(alphas, axis=0), dtype=torch.float32) - # alphas_cumprod_prev = np.append(1., alphas_cumprod[:-1]) + alphas_cumprod = torch.cumprod(alphas, dim=0) timesteps, = betas.shape self.num_timesteps = int(timesteps) self.linear_start = linear_start self.linear_end = linear_end + # self.register_buffer('betas', torch.tensor(betas, dtype=torch.float32)) + # self.register_buffer('alphas_cumprod', torch.tensor(alphas_cumprod, dtype=torch.float32)) + # self.register_buffer('alphas_cumprod_prev', torch.tensor(alphas_cumprod_prev, dtype=torch.float32)) + sigmas = ((1 - alphas_cumprod) / alphas_cumprod) ** 0.5 + alphas_cumprod = torch.tensor(np.cumprod(alphas, axis=0), dtype=torch.float32) self.set_sigmas(sigmas) self.set_alphas_cumprod(alphas_cumprod.float()) def set_sigmas(self, sigmas): - self.register_buffer('sigmas', sigmas) - self.register_buffer('log_sigmas', sigmas.log()) + self.register_buffer('sigmas', sigmas.float()) + self.register_buffer('log_sigmas', sigmas.log().float()) def set_alphas_cumprod(self, alphas_cumprod): self.register_buffer("alphas_cumprod", alphas_cumprod.float()) @@ -94,8 +114,6 @@ def percent_to_sigma(self, percent): class ModelSamplingContinuousEDM(torch.nn.Module): def __init__(self, model_config=None): super().__init__() - self.sigma_data = 1.0 - if model_config is not None: sampling_settings = model_config.sampling_settings else: @@ -103,9 +121,11 @@ def __init__(self, model_config=None): sigma_min = sampling_settings.get("sigma_min", 0.002) sigma_max = sampling_settings.get("sigma_max", 120.0) - self.set_sigma_range(sigma_min, sigma_max) + sigma_data = sampling_settings.get("sigma_data", 1.0) + self.set_parameters(sigma_min, sigma_max, sigma_data) - def set_sigma_range(self, sigma_min, sigma_max): + def set_parameters(self, sigma_min, sigma_max, sigma_data): + self.sigma_data = sigma_data sigmas = torch.linspace(math.log(sigma_min), math.log(sigma_max), 1000).exp() self.register_buffer('sigmas', sigmas) #for compatibility with some schedulers @@ -134,3 +154,56 @@ def percent_to_sigma(self, percent): log_sigma_min = math.log(self.sigma_min) return math.exp((math.log(self.sigma_max) - log_sigma_min) * percent + log_sigma_min) + +class StableCascadeSampling(ModelSamplingDiscrete): + def __init__(self, model_config=None): + super().__init__() + + if model_config is not None: + sampling_settings = model_config.sampling_settings + else: + sampling_settings = {} + + self.set_parameters(sampling_settings.get("shift", 1.0)) + + def set_parameters(self, shift=1.0, cosine_s=8e-3): + self.shift = shift + self.cosine_s = torch.tensor(cosine_s) + self._init_alpha_cumprod = torch.cos(self.cosine_s / (1 + self.cosine_s) * torch.pi * 0.5) ** 2 + + #This part is just for compatibility with some schedulers in the codebase + self.num_timesteps = 10000 + sigmas = torch.empty((self.num_timesteps), dtype=torch.float32) + for x in range(self.num_timesteps): + t = (x + 1) / self.num_timesteps + sigmas[x] = self.sigma(t) + + self.set_sigmas(sigmas) + + def sigma(self, timestep): + alpha_cumprod = (torch.cos((timestep + self.cosine_s) / (1 + self.cosine_s) * torch.pi * 0.5) ** 2 / self._init_alpha_cumprod) + + if self.shift != 1.0: + var = alpha_cumprod + logSNR = (var/(1-var)).log() + logSNR += 2 * torch.log(1.0 / torch.tensor(self.shift)) + alpha_cumprod = logSNR.sigmoid() + + alpha_cumprod = alpha_cumprod.clamp(0.0001, 0.9999) + return ((1 - alpha_cumprod) / alpha_cumprod) ** 0.5 + + def timestep(self, sigma): + var = 1 / ((sigma * sigma) + 1) + var = var.clamp(0, 1.0) + s, min_var = self.cosine_s.to(var.device), self._init_alpha_cumprod.to(var.device) + t = (((var * min_var) ** 0.5).acos() / (torch.pi * 0.5)) * (1 + s) - s + return t + + def percent_to_sigma(self, percent): + if percent <= 0.0: + return 999999999.9 + if percent >= 1.0: + return 0.0 + + percent = 1.0 - percent + return self.sigma(torch.tensor(percent)) \ No newline at end of file diff --git a/repositories/Fooocus/ldm_patched/modules/samplers.py b/repositories/Fooocus/ldm_patched/modules/samplers.py index 35cb3d7..9ed1fcd 100644 --- a/repositories/Fooocus/ldm_patched/modules/samplers.py +++ b/repositories/Fooocus/ldm_patched/modules/samplers.py @@ -523,7 +523,7 @@ def sample(self, model_wrap, sigmas, extra_args, callback, noise, latent_image=N KSAMPLER_NAMES = ["euler", "euler_ancestral", "heun", "heunpp2","dpm_2", "dpm_2_ancestral", "lms", "dpm_fast", "dpm_adaptive", "dpmpp_2s_ancestral", "dpmpp_sde", "dpmpp_sde_gpu", - "dpmpp_2m", "dpmpp_2m_sde", "dpmpp_2m_sde_gpu", "dpmpp_3m_sde", "dpmpp_3m_sde_gpu", "ddpm", "lcm", "tcd"] + "dpmpp_2m", "dpmpp_2m_sde", "dpmpp_2m_sde_gpu", "dpmpp_3m_sde", "dpmpp_3m_sde_gpu", "ddpm", "lcm", "tcd", "edm_playground_v2.5"] class KSAMPLER(Sampler): def __init__(self, sampler_function, extra_options={}, inpaint_options={}): diff --git a/repositories/Fooocus/modules/async_worker.py b/repositories/Fooocus/modules/async_worker.py index d7d9b9f..76e10f9 100644 --- a/repositories/Fooocus/modules/async_worker.py +++ b/repositories/Fooocus/modules/async_worker.py @@ -462,8 +462,10 @@ def handler(async_task): progressbar(async_task, 2, 'Loading models ...') - loras, prompt = parse_lora_references_from_prompt(prompt, loras, modules.config.default_max_lora_number) + lora_filenames = modules.util.remove_performance_lora(modules.config.lora_filenames, performance_selection) + loras, prompt = parse_lora_references_from_prompt(prompt, loras, modules.config.default_max_lora_number, lora_filenames=lora_filenames) loras += performance_loras + pipeline.refresh_everything(refiner_model_name=refiner_model_name, base_model_name=base_model_name, loras=loras, base_model_additional_loras=base_model_additional_loras, use_synthetic_refiner=use_synthetic_refiner, vae_name=vae_name) @@ -826,16 +828,33 @@ def handler(async_task): if scheduler_name in ['lcm', 'tcd']: final_scheduler_name = 'sgm_uniform' - if pipeline.final_unet is not None: - pipeline.final_unet = core.opModelSamplingDiscrete.patch( + + def patch_discrete(unet): + return core.opModelSamplingDiscrete.patch( pipeline.final_unet, sampling=scheduler_name, zsnr=False)[0] + + if pipeline.final_unet is not None: + pipeline.final_unet = patch_discrete(pipeline.final_unet) if pipeline.final_refiner_unet is not None: - pipeline.final_refiner_unet = core.opModelSamplingDiscrete.patch( - pipeline.final_refiner_unet, + pipeline.final_refiner_unet = patch_discrete(pipeline.final_refiner_unet) + print(f'Using {scheduler_name} scheduler.') + elif scheduler_name == 'edm_playground_v2.5': + final_scheduler_name = 'karras' + + def patch_edm(unet): + return core.opModelSamplingContinuousEDM.patch( + unet, sampling=scheduler_name, - zsnr=False)[0] + sigma_max=120.0, + sigma_min=0.002)[0] + + if pipeline.final_unet is not None: + pipeline.final_unet = patch_edm(pipeline.final_unet) + if pipeline.final_refiner_unet is not None: + pipeline.final_refiner_unet = patch_edm(pipeline.final_refiner_unet) + print(f'Using {scheduler_name} scheduler.') async_task.yields.append(['preview', (flags.preparation_step_count, 'Moving model to GPU ...', None)]) diff --git a/repositories/Fooocus/modules/config.py b/repositories/Fooocus/modules/config.py index cb651c5..e3c427d 100644 --- a/repositories/Fooocus/modules/config.py +++ b/repositories/Fooocus/modules/config.py @@ -2,13 +2,14 @@ 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 +from modules.extra_utils import makedirs_with_log, get_files_from_folder, try_eval_env_var from modules.flags import OutputFormat, Performance, MetadataScheme @@ -200,7 +201,7 @@ def get_dir_or_set_default(key, default_value, as_array=False, make_directory=Fa path_outputs = get_path_output() -def get_config_item_or_set_default(key, default_value, validator, disable_empty_as_none=False): +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: @@ -208,6 +209,7 @@ def get_config_item_or_set_default(key, default_value, validator, disable_empty_ 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 @@ -252,41 +254,49 @@ def init_temp_path(path: str | None, default_path: str) -> str: 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) + 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) + 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) + 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) + 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 + 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 + 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 + 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', @@ -320,38 +330,45 @@ def init_temp_path(path: str | None, default_path: str) -> str: 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) + 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 + 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) + 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) + 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 + 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 + 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) + validator=lambda x: isinstance(x, str), + expected_type=str ) default_styles = get_config_item_or_set_default( key='default_styles', @@ -360,121 +377,144 @@ def init_temp_path(path: str | None, default_path: str) -> str: "Fooocus Enhance", "Fooocus Sharp" ], - validator=lambda x: isinstance(x, list) and all(y in modules.sdxl_styles.legal_style_names for y in x) + 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 + 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 + 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.list() + validator=lambda x: x in Performance.list(), + expected_type=str ) default_advanced_checkbox = get_config_item_or_set_default( key='default_advanced_checkbox', default_value=False, - validator=lambda x: isinstance(x, bool) + 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 + 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() + 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 + 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()) + 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()) + 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()) + 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 + 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 + 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 + validator=lambda x: x in modules.flags.inpaint_engine_versions, + 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) + 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 + 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) + 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) + validator=lambda x: isinstance(x, int), + expected_type=int ) 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) + validator=lambda x: isinstance(x, list) and all(isinstance(v, str) for v in x), + expected_type=list ) default_black_out_nsfw = get_config_item_or_set_default( key='default_black_out_nsfw', default_value=False, - validator=lambda x: isinstance(x, bool) + 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) + 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] + 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) + validator=lambda x: isinstance(x, str), + expected_type=str ) example_inpaint_prompts = [[x] for x in example_inpaint_prompts] @@ -548,25 +588,9 @@ def add_ratio(x): model_filenames = [] lora_filenames = [] -lora_filenames_no_special = [] vae_filenames = [] wildcard_filenames = [] -sdxl_lcm_lora = 'sdxl_lcm_lora.safetensors' -sdxl_lightning_lora = 'sdxl_lightning_4step_lora.safetensors' -sdxl_hyper_sd_lora = 'sdxl_hyper_sd_4step_lora.safetensors' -loras_metadata_remove = [sdxl_lcm_lora, sdxl_lightning_lora, sdxl_hyper_sd_lora] - - -def remove_special_loras(lora_filenames): - global loras_metadata_remove - - loras_no_special = lora_filenames.copy() - for lora_to_remove in loras_metadata_remove: - if lora_to_remove in loras_no_special: - loras_no_special.remove(lora_to_remove) - return loras_no_special - def get_model_filenames(folder_paths, extensions=None, name_filter=None): if extensions is None: @@ -582,10 +606,9 @@ def get_model_filenames(folder_paths, extensions=None, name_filter=None): def update_files(): - global model_filenames, lora_filenames, lora_filenames_no_special, vae_filenames, wildcard_filenames, available_presets + 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) - lora_filenames_no_special = remove_special_loras(lora_filenames) vae_filenames = get_model_filenames(path_vae) wildcard_filenames = get_files_from_folder(path_wildcards, ['.txt']) available_presets = get_presets() @@ -634,26 +657,27 @@ 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=sdxl_lcm_lora + file_name=modules.flags.PerformanceLoRA.EXTREME_SPEED.value ) - return sdxl_lcm_lora + 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=sdxl_lightning_lora + file_name=modules.flags.PerformanceLoRA.LIGHTNING.value ) - return sdxl_lightning_lora + 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=sdxl_hyper_sd_lora + file_name=modules.flags.PerformanceLoRA.HYPER_SD.value ) - return sdxl_hyper_sd_lora + return modules.flags.PerformanceLoRA.HYPER_SD.value def downloading_controlnet_canny(): diff --git a/repositories/Fooocus/modules/core.py b/repositories/Fooocus/modules/core.py index 3ca4cc5..78c8975 100644 --- a/repositories/Fooocus/modules/core.py +++ b/repositories/Fooocus/modules/core.py @@ -21,8 +21,7 @@ from modules.util import get_file_from_folder_list from ldm_patched.modules.lora import model_lora_keys_unet, model_lora_keys_clip from modules.config import path_embeddings -from ldm_patched.contrib.external_model_advanced import ModelSamplingDiscrete - +from ldm_patched.contrib.external_model_advanced import ModelSamplingDiscrete, ModelSamplingContinuousEDM opEmptyLatentImage = EmptyLatentImage() opVAEDecode = VAEDecode() @@ -32,6 +31,7 @@ opControlNetApplyAdvanced = ControlNetApplyAdvanced() opFreeU = FreeU_V2() opModelSamplingDiscrete = ModelSamplingDiscrete() +opModelSamplingContinuousEDM = ModelSamplingContinuousEDM() class StableDiffusionModel: diff --git a/repositories/Fooocus/modules/extra_utils.py b/repositories/Fooocus/modules/extra_utils.py index 9906c82..c2dfa81 100644 --- a/repositories/Fooocus/modules/extra_utils.py +++ b/repositories/Fooocus/modules/extra_utils.py @@ -1,4 +1,6 @@ import os +from ast import literal_eval + def makedirs_with_log(path): try: @@ -24,3 +26,16 @@ def get_files_from_folder(folder_path, extensions=None, name_filter=None): filenames.append(path) return filenames + + +def try_eval_env_var(value: str, expected_type=None): + try: + value_eval = value + if expected_type is bool: + value_eval = value.title() + value_eval = literal_eval(value_eval) + if expected_type is not None and not isinstance(value_eval, expected_type): + return value + return value_eval + except: + return value diff --git a/repositories/Fooocus/modules/flags.py b/repositories/Fooocus/modules/flags.py index e48052e..29ac461 100644 --- a/repositories/Fooocus/modules/flags.py +++ b/repositories/Fooocus/modules/flags.py @@ -48,7 +48,7 @@ KSAMPLER_NAMES = list(KSAMPLER.keys()) -SCHEDULER_NAMES = ["normal", "karras", "exponential", "sgm_uniform", "simple", "ddim_uniform", "lcm", "turbo", "align_your_steps", "tcd"] +SCHEDULER_NAMES = ["normal", "karras", "exponential", "sgm_uniform", "simple", "ddim_uniform", "lcm", "turbo", "align_your_steps", "tcd", "edm_playground_v2.5"] SAMPLER_NAMES = KSAMPLER_NAMES + list(SAMPLER_EXTRA.keys()) sampler_list = SAMPLER_NAMES @@ -91,6 +91,7 @@ '1664*576', '1728*576' ] + class MetadataScheme(Enum): FOOOCUS = 'fooocus' A1111 = 'a1111' @@ -115,6 +116,14 @@ def list(cls) -> list: return list(map(lambda c: c.value, cls)) +class PerformanceLoRA(Enum): + QUALITY = None + SPEED = None + EXTREME_SPEED = 'sdxl_lcm_lora.safetensors' + LIGHTNING = 'sdxl_lightning_4step_lora.safetensors' + HYPER_SD = 'sdxl_hyper_sd_4step_lora.safetensors' + + class Steps(IntEnum): QUALITY = 60 SPEED = 30 @@ -122,6 +131,10 @@ class Steps(IntEnum): LIGHTNING = 4 HYPER_SD = 4 + @classmethod + def keys(cls) -> list: + return list(map(lambda c: c, Steps.__members__)) + class StepsUOV(IntEnum): QUALITY = 36 @@ -142,6 +155,14 @@ class Performance(Enum): def list(cls) -> list: return list(map(lambda c: c.value, cls)) + @classmethod + def values(cls) -> list: + return list(map(lambda c: c.value, cls)) + + @classmethod + def by_steps(cls, steps: int | str): + return cls[Steps(int(steps)).name] + @classmethod def has_restricted_features(cls, x) -> bool: if isinstance(x, Performance): @@ -149,7 +170,10 @@ def has_restricted_features(cls, x) -> bool: return x in [cls.EXTREME_SPEED.value, cls.LIGHTNING.value, cls.HYPER_SD.value] def steps(self) -> int | None: - return Steps[self.name].value if Steps[self.name] else None + return Steps[self.name].value if self.name in Steps.__members__ else None def steps_uov(self) -> int | None: - return StepsUOV[self.name].value if Steps[self.name] else None + return StepsUOV[self.name].value if self.name in StepsUOV.__members__ else None + + def lora_filename(self) -> str | None: + return PerformanceLoRA[self.name].value if self.name in PerformanceLoRA.__members__ else None diff --git a/repositories/Fooocus/modules/meta_parser.py b/repositories/Fooocus/modules/meta_parser.py index 586e62d..ff930cc 100644 --- a/repositories/Fooocus/modules/meta_parser.py +++ b/repositories/Fooocus/modules/meta_parser.py @@ -32,7 +32,7 @@ def load_parameter_button_click(raw_metadata: dict | str, is_generating: bool): 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) - get_str('performance', 'Performance', loaded_parameter_dict, results) + performance = get_str('performance', 'Performance', loaded_parameter_dict, results) get_steps('steps', 'Steps', loaded_parameter_dict, results) get_number('overwrite_switch', 'Overwrite Switch', loaded_parameter_dict, results) get_resolution('resolution', 'Resolution', loaded_parameter_dict, results) @@ -59,19 +59,27 @@ def load_parameter_button_click(raw_metadata: dict | str, is_generating: bool): get_freeu('freeu', 'FreeU', loaded_parameter_dict, results) + # prevent performance LoRAs to be added twice, by performance and by lora + performance_filename = None + if performance is not None and performance in Performance.values(): + performance = Performance(performance) + performance_filename = performance.lora_filename() + for i in range(modules.config.default_max_lora_number): - get_lora(f'lora_combined_{i + 1}', f'LoRA {i + 1}', loaded_parameter_dict, results) + get_lora(f'lora_combined_{i + 1}', f'LoRA {i + 1}', loaded_parameter_dict, results, performance_filename) return results -def get_str(key: str, fallback: str | None, source_dict: dict, results: list, default=None): +def get_str(key: str, fallback: str | None, source_dict: dict, results: list, default=None) -> str | None: try: h = source_dict.get(key, source_dict.get(fallback, default)) assert isinstance(h, str) results.append(h) + return h except: results.append(gr.update()) + return None def get_list(key: str, fallback: str | None, source_dict: dict, results: list, default=None): @@ -111,8 +119,9 @@ 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(): + performance_name = source_dict.get('performance', '').replace(' ', '_').replace('-', '_').casefold() + performance_candidates = [key for key in Steps.keys() if key.casefold() == performance_name and Steps[key] == h] + if len(performance_candidates) == 0: results.append(h) return results.append(-1) @@ -181,7 +190,7 @@ def get_freeu(key: str, fallback: str | None, source_dict: dict, results: list, results.append(gr.update()) -def get_lora(key: str, fallback: str | None, source_dict: dict, results: list): +def get_lora(key: str, fallback: str | None, source_dict: dict, results: list, performance_filename: str | None): try: split_data = source_dict.get(key, source_dict.get(fallback)).split(' : ') enabled = True @@ -193,6 +202,9 @@ def get_lora(key: str, fallback: str | None, source_dict: dict, results: list): name = split_data[1] weight = split_data[2] + if name == performance_filename: + raise Exception + weight = float(weight) results.append(enabled) results.append(name) @@ -221,7 +233,7 @@ def parse_meta_from_preset(preset_content): loras = getattr(modules.config, settings_key) if settings_key in items: loras = items[settings_key] - for index, lora in enumerate(loras[:5]): + for index, lora in enumerate(loras[:modules.config.default_max_lora_number]): preset_prepared[f'lora_combined_{index + 1}'] = ' : '.join(map(str, lora)) elif settings_key == "default_aspect_ratio": if settings_key in items and items[settings_key] is not None: @@ -248,7 +260,7 @@ def __init__(self): self.full_prompt: str = '' self.raw_negative_prompt: str = '' self.full_negative_prompt: str = '' - self.steps: int = 30 + self.steps: int = Steps.SPEED.value self.base_model_name: str = '' self.base_model_hash: str = '' self.refiner_model_name: str = '' @@ -261,11 +273,11 @@ def get_scheme(self) -> MetadataScheme: raise NotImplementedError @abstractmethod - def parse_json(self, metadata: dict | str) -> dict: + def to_json(self, metadata: dict | str) -> dict: raise NotImplementedError @abstractmethod - def parse_string(self, metadata: dict) -> str: + def to_string(self, metadata: dict) -> str: raise NotImplementedError def set_data(self, raw_prompt, full_prompt, raw_negative_prompt, full_negative_prompt, steps, base_model_name, @@ -328,7 +340,7 @@ def get_scheme(self) -> MetadataScheme: 'version': 'Version' } - def parse_json(self, metadata: str) -> dict: + def to_json(self, metadata: str) -> dict: metadata_prompt = '' metadata_negative_prompt = '' @@ -382,9 +394,9 @@ def parse_json(self, metadata: str) -> dict: data['styles'] = str(found_styles) # try to load performance based on steps, fallback for direct A1111 imports - if 'steps' in data and 'performance' not in data: + if 'steps' in data and 'performance' in data is None: try: - data['performance'] = Performance[Steps(int(data['steps'])).name].value + data['performance'] = Performance.by_steps(data['steps']).value except ValueError | KeyError: pass @@ -414,7 +426,7 @@ def parse_json(self, metadata: str) -> dict: 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 modules.config.lora_filenames_no_special: + for filename in modules.config.lora_filenames: path = Path(filename) if lora_name == path.stem: data[f'lora_combined_{li + 1}'] = f'{filename} : {lora_weight}' @@ -422,7 +434,7 @@ def parse_json(self, metadata: str) -> dict: return data - def parse_string(self, metadata: dict) -> str: + def to_string(self, metadata: dict) -> str: data = {k: v for _, k, v in metadata} width, height = eval(data['resolution']) @@ -502,14 +514,14 @@ class FooocusMetadataParser(MetadataParser): def get_scheme(self) -> MetadataScheme: return MetadataScheme.FOOOCUS - def parse_json(self, metadata: dict) -> dict: + def to_json(self, metadata: dict) -> dict: for key, value in metadata.items(): if value in ['', 'None']: continue if key in ['base_model', 'refiner_model']: metadata[key] = self.replace_value_with_filename(key, value, modules.config.model_filenames) elif key.startswith('lora_combined_'): - metadata[key] = self.replace_value_with_filename(key, value, modules.config.lora_filenames_no_special) + metadata[key] = self.replace_value_with_filename(key, value, modules.config.lora_filenames) elif key == 'vae': metadata[key] = self.replace_value_with_filename(key, value, modules.config.vae_filenames) else: @@ -517,7 +529,7 @@ def parse_json(self, metadata: dict) -> dict: return metadata - def parse_string(self, metadata: list) -> str: + def to_string(self, metadata: list) -> str: for li, (label, key, value) in enumerate(metadata): # remove model folder paths from metadata if key.startswith('lora_combined_'): @@ -557,6 +569,8 @@ def replace_value_with_filename(key, value, filenames): elif value == path.stem: return filename + return None + def get_metadata_parser(metadata_scheme: MetadataScheme) -> MetadataParser: match metadata_scheme: diff --git a/repositories/Fooocus/modules/private_logger.py b/repositories/Fooocus/modules/private_logger.py index eb8f0cc..6fdb680 100644 --- a/repositories/Fooocus/modules/private_logger.py +++ b/repositories/Fooocus/modules/private_logger.py @@ -27,7 +27,7 @@ def log(img, metadata, metadata_parser: MetadataParser | None = None, output_for 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) - parsed_parameters = metadata_parser.parse_string(metadata.copy()) if metadata_parser is not None else '' + parsed_parameters = metadata_parser.to_string(metadata.copy()) if metadata_parser is not None else '' image = Image.fromarray(img) if output_format == OutputFormat.PNG.value: diff --git a/repositories/Fooocus/modules/sample_hijack.py b/repositories/Fooocus/modules/sample_hijack.py index 4ab3cbb..84752ed 100644 --- a/repositories/Fooocus/modules/sample_hijack.py +++ b/repositories/Fooocus/modules/sample_hijack.py @@ -175,7 +175,7 @@ def calculate_sigmas_scheduler_hacked(model, scheduler_name, steps): elif scheduler_name == "sgm_uniform": sigmas = normal_scheduler(model, steps, sgm=True) elif scheduler_name == "turbo": - sigmas = SDTurboScheduler().get_sigmas(namedtuple('Patcher', ['model'])(model=model), steps=steps, denoise=1.0)[0] + sigmas = SDTurboScheduler().get_sigmas(model=model, steps=steps, denoise=1.0)[0] elif scheduler_name == "align_your_steps": model_type = 'SDXL' if isinstance(model.latent_format, ldm_patched.modules.latent_formats.SDXL) else 'SD1' sigmas = AlignYourStepsScheduler().get_sigmas(model_type=model_type, steps=steps, denoise=1.0)[0] diff --git a/repositories/Fooocus/modules/util.py b/repositories/Fooocus/modules/util.py index 8317dd5..5003f79 100644 --- a/repositories/Fooocus/modules/util.py +++ b/repositories/Fooocus/modules/util.py @@ -16,6 +16,7 @@ import modules.config import modules.sdxl_styles +from modules.flags import Performance LANCZOS = (Image.Resampling.LANCZOS if hasattr(Image, 'Resampling') else Image.LANCZOS) @@ -381,9 +382,6 @@ def get_file_from_folder_list(name, folders): return os.path.abspath(os.path.realpath(os.path.join(folders[0], name))) -def ordinal_suffix(number: int) -> str: - return 'th' if 10 <= number % 100 <= 20 else {1: 'st', 2: 'nd', 3: 'rd'}.get(number % 10, 'th') - def makedirs_with_log(path): try: @@ -397,10 +395,15 @@ def get_enabled_loras(loras: list, remove_none=True) -> list: def parse_lora_references_from_prompt(prompt: str, loras: List[Tuple[AnyStr, float]], loras_limit: int = 5, - skip_file_check=False, prompt_cleanup=True, deduplicate_loras=True) -> tuple[List[Tuple[AnyStr, float]], str]: + skip_file_check=False, prompt_cleanup=True, deduplicate_loras=True, + lora_filenames=None) -> tuple[List[Tuple[AnyStr, float]], str]: + if lora_filenames is None: + lora_filenames = [] + found_loras = [] prompt_without_loras = '' cleaned_prompt = '' + for token in prompt.split(','): matches = LORAS_PROMPT_PATTERN.findall(token) @@ -410,7 +413,7 @@ def parse_lora_references_from_prompt(prompt: str, loras: List[Tuple[AnyStr, flo for match in matches: lora_name = match[1] + '.safetensors' if not skip_file_check: - lora_name = get_filname_by_stem(match[1], modules.config.lora_filenames_no_special) + lora_name = get_filname_by_stem(match[1], lora_filenames) if lora_name is not None: found_loras.append((lora_name, float(match[2]))) token = token.replace(match[0], '') @@ -440,6 +443,22 @@ def parse_lora_references_from_prompt(prompt: str, loras: List[Tuple[AnyStr, flo return updated_loras[:loras_limit], cleaned_prompt +def remove_performance_lora(filenames: list, performance: Performance | None): + loras_without_performance = filenames.copy() + + if performance is None: + return loras_without_performance + + performance_lora = performance.lora_filename() + + for filename in filenames: + path = Path(filename) + if performance_lora == path.name: + loras_without_performance.remove(filename) + + return loras_without_performance + + def cleanup_prompt(prompt): prompt = re.sub(' +', ' ', prompt) prompt = re.sub(',+', ',', prompt) diff --git a/repositories/Fooocus/presets/.gitignore b/repositories/Fooocus/presets/.gitignore index 481930c..27e7413 100644 --- a/repositories/Fooocus/presets/.gitignore +++ b/repositories/Fooocus/presets/.gitignore @@ -2,5 +2,6 @@ !anime.json !default.json !lcm.json +!playground_v2.5.json !realistic.json !sai.json \ No newline at end of file diff --git a/repositories/Fooocus/presets/playground_v2.5.json b/repositories/Fooocus/presets/playground_v2.5.json new file mode 100644 index 0000000..5bc6059 --- /dev/null +++ b/repositories/Fooocus/presets/playground_v2.5.json @@ -0,0 +1,49 @@ +{ + "default_model": "playground-v2.5-1024px-aesthetic.fp16.safetensors", + "default_refiner": "None", + "default_refiner_switch": 0.5, + "default_loras": [ + [ + true, + "None", + 1.0 + ], + [ + true, + "None", + 1.0 + ], + [ + true, + "None", + 1.0 + ], + [ + true, + "None", + 1.0 + ], + [ + true, + "None", + 1.0 + ] + ], + "default_cfg_scale": 2.0, + "default_sample_sharpness": 2.0, + "default_sampler": "dpmpp_2m", + "default_scheduler": "edm_playground_v2.5", + "default_performance": "Speed", + "default_prompt": "", + "default_prompt_negative": "", + "default_styles": [ + "Fooocus V2" + ], + "default_aspect_ratio": "1024*1024", + "checkpoint_downloads": { + "playground-v2.5-1024px-aesthetic.fp16.safetensors": "https://huggingface.co/mashb1t/fav_models/resolve/main/fav/playground-v2.5-1024px-aesthetic.fp16.safetensors" + }, + "embeddings_downloads": {}, + "lora_downloads": {}, + "previous_default_models": [] +} \ No newline at end of file