diff --git a/launch.py b/launch.py index 6afbd7458..ab1530fac 100644 --- a/launch.py +++ b/launch.py @@ -150,12 +150,12 @@ def start_server(immediate=True, server=None): server.wants_restart = False else: if args.api_only: - server = server.api_only() + uvicorn = server.api_only() else: - server = server.webui(restart=not immediate) + uvicorn = server.webui(restart=not immediate) if args.profile: installer.print_profile(pr, 'WebUI') - return server + return uvicorn, server if __name__ == "__main__": @@ -207,20 +207,21 @@ if __name__ == "__main__": # installer.log.debug(f"Args: {vars(args)}") logging.disable(logging.NOTSET if args.debug else logging.DEBUG) - instance = start_server(immediate=True, server=None) + uv, instance = start_server(immediate=True, server=None) while True: try: - alive = instance.thread.is_alive() - requests = instance.server_state.total_requests if hasattr(instance, 'server_state') else 0 + alive = uv.thread.is_alive() + requests = uv.server_state.total_requests if hasattr(uv, 'server_state') else 0 except Exception: alive = False requests = 0 if round(time.time()) % 120 == 0: - installer.log.debug(f'Server alive={alive} requests={requests} memory {get_memory_stats()} ') + state = f'job="{instance.state.job}" {instance.state.job_no}/{instance.state.job_count}' + installer.log.debug(f'Server alive={alive} requests={requests} memory {get_memory_stats()} {state}') if not alive: if instance.wants_restart: installer.log.info('Server restarting...') - instance = start_server(immediate=False, server=instance) + uv, instance = start_server(immediate=False, server=instance) else: installer.log.info('Exiting...') break diff --git a/modules/api/api.py b/modules/api/api.py index ce5bda675..39436d14a 100644 --- a/modules/api/api.py +++ b/modules/api/api.py @@ -263,7 +263,7 @@ class Api: p.scripts = script_runner p.outpath_grids = shared.opts.outdir_grids or shared.opts.outdir_txt2img_grids p.outpath_samples = shared.opts.outdir_samples or shared.opts.outdir_txt2img_samples - shared.state.begin() + shared.state.begin('api-txt2img') script_args = self.init_script_args(p, txt2imgreq, self.default_script_arg_txt2img, selectable_scripts, selectable_script_idx, script_runner) if selectable_scripts is not None: processed = scripts.scripts_txt2img.run(p, *script_args) # Need to pass args as list here @@ -311,7 +311,7 @@ class Api: p.scripts = script_runner p.outpath_grids = shared.opts.outdir_img2img_grids p.outpath_samples = shared.opts.outdir_img2img_samples - shared.state.begin() + shared.state.begin('api-img2img') script_args = self.init_script_args(p, img2imgreq, self.default_script_arg_img2img, selectable_scripts, selectable_script_idx, script_runner) if selectable_scripts is not None: processed = scripts.scripts_img2img.run(p, *script_args) # Need to pass args as list here @@ -513,7 +513,7 @@ class Api: def create_embedding(self, args: dict): try: - shared.state.begin() + shared.state.begin('api-create-embedding') filename = create_embedding(**args) # create empty embedding sd_hijack.model_hijack.embedding_db.load_textual_inversion_embeddings() # reload embeddings so new one can be immediately used shared.state.end() @@ -524,7 +524,7 @@ class Api: def create_hypernetwork(self, args: dict): try: - shared.state.begin() + shared.state.begin('api-create-hypernetwork') filename = create_hypernetwork(**args) # create empty embedding # pylint: disable=E1111 shared.state.end() return models.CreateResponse(info = f"create hypernetwork filename: {filename}") @@ -534,7 +534,7 @@ class Api: def preprocess(self, args: dict): try: - shared.state.begin() + shared.state.begin('api-preprocess') preprocess(**args) # quick operation unless blip/booru interrogation is enabled shared.state.end() return models.PreprocessResponse(info = 'preprocess complete') @@ -550,7 +550,7 @@ class Api: def train_embedding(self, args: dict): try: - shared.state.begin() + shared.state.begin('api-train-embedding') apply_optimizations = False error = None filename = '' @@ -571,7 +571,7 @@ class Api: def train_hypernetwork(self, args: dict): try: - shared.state.begin() + shared.state.begin('api-train-hypernetwork') shared.loaded_hypernetworks = [] apply_optimizations = False error = None diff --git a/modules/call_queue.py b/modules/call_queue.py index 568d79344..d75ae55cd 100644 --- a/modules/call_queue.py +++ b/modules/call_queue.py @@ -19,6 +19,7 @@ def wrap_queued_call(func): def wrap_gradio_gpu_call(func, extra_outputs=None): + name = func.__name__ def f(*args, **kwargs): # if the first argument is a string that says "task(...)", it is treated as a job id if len(args) > 0 and type(args[0]) == str and args[0][0:5] == "task(" and args[0][-1] == ")": @@ -27,7 +28,6 @@ def wrap_gradio_gpu_call(func, extra_outputs=None): else: id_task = None with queue_lock: - shared.state.begin() progress.start_task(id_task) res = [None, '', '', ''] try: @@ -42,13 +42,15 @@ def wrap_gradio_gpu_call(func, extra_outputs=None): progress.finish_task(id_task) shared.state.end() return res - return wrap_gradio_call(f, extra_outputs=extra_outputs, add_stats=True) + return wrap_gradio_call(f, extra_outputs=extra_outputs, add_stats=True, name=name) -def wrap_gradio_call(func, extra_outputs=None, add_stats=False): +def wrap_gradio_call(func, extra_outputs=None, add_stats=False, name=None): + job_name = name if name is not None else func.__name__ def f(*args, extra_outputs_array=extra_outputs, **kwargs): t = time.perf_counter() shared.mem_mon.reset() + shared.state.begin(job_name) try: if shared.cmd_opts.profile: pr = cProfile.Profile() @@ -67,15 +69,10 @@ def wrap_gradio_call(func, extra_outputs=None, add_stats=False): print('Profile Exec:', s.getvalue()) except Exception as e: errors.display(e, 'gradio call') - shared.state.job = "" - shared.state.job_count = 0 if extra_outputs_array is None: extra_outputs_array = [None, ''] res = extra_outputs_array + [f"
{html.escape(type(e).__name__+': '+str(e))}
"] - shared.state.skipped = False - shared.state.interrupted = False - shared.state.paused = False - shared.state.job_count = 0 + shared.state.end() if not add_stats: return tuple(res) elapsed = time.perf_counter() - t diff --git a/modules/extras.py b/modules/extras.py index f13b61306..6e61b8426 100644 --- a/modules/extras.py +++ b/modules/extras.py @@ -54,9 +54,7 @@ def to_half(tensor, enable): def run_modelmerger(id_task, primary_model_name, secondary_model_name, tertiary_model_name, interp_method, multiplier, save_as_half, custom_name, checkpoint_format, config_source, bake_in_vae, discard_weights, save_metadata): # pylint: disable=unused-argument - shared.state.begin() - shared.state.job = 'model-merge' - + shared.state.begin('model-merge') save_as_half = save_as_half == 0 def fail(message): @@ -321,9 +319,7 @@ def run_modelconvert(model, checkpoint_formats, precision, conv_type, custom_nam "vae": vae_conv, "other": others_conv } - shared.state.begin() - shared.state.job = 'model-convert' - + shared.state.begin('model-convert') model_info = sd_models.checkpoints_list[model] shared.state.textinfo = f"Loading {model_info.filename}..." shared.log.info(f"Model convert loading: {model_info.filename}") diff --git a/modules/interrogate.py b/modules/interrogate.py index be465d9b2..61bb14cc9 100644 --- a/modules/interrogate.py +++ b/modules/interrogate.py @@ -181,8 +181,7 @@ class InterrogateModels: def interrogate(self, pil_image): res = "" - shared.state.begin() - shared.state.job = 'interrogate' + shared.state.begin('interrogate') try: if shared.cmd_opts.lowvram or shared.cmd_opts.medvram: lowvram.send_everything_to_cpu() diff --git a/modules/modelloader.py b/modules/modelloader.py index bb0639389..38b9c8377 100644 --- a/modules/modelloader.py +++ b/modules/modelloader.py @@ -65,8 +65,7 @@ def download_civit_preview(model_path: str, preview_url: str): total_size = int(req.headers.get('content-length', 0)) block_size = 16384 # 16KB blocks written = 0 - shared.state.begin() - shared.state.job = 'download preview' + shared.state.begin('civitai-download-preview') try: with open(preview_file, 'wb') as f: with p.Progress(p.TextColumn('[cyan]{task.description}'), p.DownloadColumn(), p.BarColumn(), p.TaskProgressColumn(), p.TimeRemainingColumn(), p.TimeElapsedColumn(), p.TransferSpeedColumn()) as progress: @@ -105,8 +104,7 @@ def download_civit_model(model_url: str, model_name: str, model_path: str, model total_size = int(req.headers.get('content-length', 0)) block_size = 16384 # 16KB blocks written = 0 - shared.state.begin() - shared.state.job = 'download model' + shared.state.begin('civitai-download-model') try: with open(model_file, 'wb') as f: with p.Progress(p.TextColumn('[cyan]{task.description}'), p.DownloadColumn(), p.BarColumn(), p.TaskProgressColumn(), p.TimeRemainingColumn(), p.TimeElapsedColumn(), p.TransferSpeedColumn()) as progress: @@ -136,8 +134,7 @@ def download_civit_model(model_url: str, model_name: str, model_path: str, model def download_diffusers_model(hub_id: str, cache_dir: str = None, download_config: Dict[str, str] = None, token = None, variant = None, revision = None, mirror = None): from diffusers import DiffusionPipeline import huggingface_hub as hf - shared.state.begin() - shared.state.job = 'download model' + shared.state.begin('huggingface-download-model') if download_config is None: download_config = { "force_download": False, diff --git a/modules/postprocessing.py b/modules/postprocessing.py index 4ff648461..c82aac540 100644 --- a/modules/postprocessing.py +++ b/modules/postprocessing.py @@ -10,8 +10,7 @@ from modules.shared import opts def run_postprocessing(extras_mode, image, image_folder: List[tempfile.NamedTemporaryFile], input_dir, output_dir, show_extras_results, *args, save_output: bool = True): devices.torch_gc() - shared.state.begin() - shared.state.job = 'extras' + shared.state.begin('extras') image_data = [] image_names = [] image_ext = [] diff --git a/modules/sd_vae.py b/modules/sd_vae.py index d632618a1..0360d83b3 100644 --- a/modules/sd_vae.py +++ b/modules/sd_vae.py @@ -232,6 +232,8 @@ def reload_vae_weights(sd_model=None, vae_file=unspecified): from modules import lowvram, sd_hijack if not sd_model: sd_model = shared.sd_model + if sd_model is None: + return global checkpoint_info # pylint: disable=global-statement checkpoint_info = sd_model.sd_checkpoint_info checkpoint_file = checkpoint_info.filename diff --git a/modules/shared.py b/modules/shared.py index ebc142a63..fe2ec4e4d 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -137,19 +137,20 @@ class State: } return obj - def begin(self): - self.sampling_step = 0 - self.job_count = -1 - self.processing_has_refined_job_count = False - self.job_no = 0 - self.job_timestamp = datetime.datetime.now().strftime("%Y%m%d%H%M%S") - self.current_latent = None + def begin(self, title=""): self.current_image = None self.current_image_sampling_step = 0 + self.current_latent = None self.id_live_preview = 0 - self.skipped = False self.interrupted = False + self.job = title + self.job_count = -1 + self.job_no = 0 + self.job_timestamp = datetime.datetime.now().strftime("%Y%m%d%H%M%S") self.paused = False + self.processing_has_refined_job_count = False + self.sampling_step = 0 + self.skipped = False self.textinfo = None self.time_start = time.time() devices.torch_gc() @@ -157,7 +158,10 @@ class State: def end(self): self.job = "" self.job_count = 0 + self.job_no = 0 self.paused = False + self.interrupted = False + self.skipped = False devices.torch_gc() def set_current_image(self): @@ -278,8 +282,9 @@ def temp_disable_extensions(): for ext in ['sd-webui-controlnet', 'multidiffusion-upscaler-for-automatic1111', 'a1111-sd-webui-lycoris']: if ext not in opts.disabled_extensions: disabled.append(ext) - log.warning(f'Diffusers disabling uncompatible extensions: {disabled}') + log.info(f'Diffusers disabling uncompatible extensions: {disabled}') if opts.lyco_patch_lora and backend != Backend.DIFFUSERS: + cmd_opts.lyco_dir = opts.lora_dir if 'Lora' not in opts.disabled_extensions: disabled.append('Lora') return disabled @@ -428,7 +433,7 @@ options_templates.update(options_section(('system-paths', "System Paths"), { "ckpt_dir": OptionInfo(os.path.join(paths.models_path, 'Stable-diffusion'), "Path to directory with stable diffusion checkpoints"), "diffusers_dir": OptionInfo(os.path.join(paths.models_path, 'Diffusers'), "Path to directory with stable diffusion diffusers"), "vae_dir": OptionInfo(os.path.join(paths.models_path, 'VAE'), "Path to directory with VAE files"), - "sd_lora": OptionInfo("", "Add LoRA to prompt", gr.CheckboxGroup, {"choices": [], "visible": False}), + "sd_lora": OptionInfo("", "Add LoRA to prompt", gr.Textbox, {"choices": [], "visible": False}), "lora_dir": OptionInfo(os.path.join(paths.models_path, 'Lora'), "Path to directory with LoRA network(s)"), "lyco_dir": OptionInfo(os.path.join(paths.models_path, 'LyCORIS'), "Path to directory with LyCORIS network(s)"), "styles_dir": OptionInfo(os.path.join(paths.data_path, 'styles.csv'), "Path to user-defined styles file"), diff --git a/modules/ui_extra_networks.py b/modules/ui_extra_networks.py index 17cf429b9..1f5274e1f 100644 --- a/modules/ui_extra_networks.py +++ b/modules/ui_extra_networks.py @@ -219,7 +219,7 @@ class ExtraNetworksPage: else: return '' t1 = time.time() - shared.log.debug(f'Extra networks: {self.name} items={len(self.items)} subdirs={len(subdirs)} tab={tabname} time={round(t1-t0, 2)}') + shared.log.debug(f'Extra networks: page={self.name} items={len(self.items)} subdirs={len(subdirs)} tab={tabname} dirs={self.allowed_directories_for_previews()} time={round(t1-t0, 2)}') threading.Thread(target=self.create_thumb).start() def list_items(self): diff --git a/webui.py b/webui.py index 6624934cd..fb32f809f 100644 --- a/webui.py +++ b/webui.py @@ -39,6 +39,7 @@ from modules.shared import cmd_opts, opts import modules.hypernetworks.hypernetwork from modules.middleware import setup_middleware +state = shared.state if not modules.loader.initialized: timer.startup.record("libraries") log.info('Loaded librareis') @@ -152,8 +153,7 @@ def initialize(): def load_model(): if opts.sd_checkpoint_autoload: - shared.state.begin() - shared.state.job = 'load model' + shared.state.begin('load model') thread_model = Thread(target=lambda: shared.sd_model) thread_model.start() thread_refiner = Thread(target=lambda: shared.sd_refiner)