diff --git a/CHANGELOG.md b/CHANGELOG.md index 342d2e6d2..9fff0bb00 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,9 +18,10 @@ - **sampler**: add laplace beta schedule results in better prompt adherence and smoother infills - **prompt enhance**: improve handling and refresh ui, thanks @CalamitousFelicitousness - new models such moondream-3 and xiaomo-mimo + new models such moondream-3 and xiaomo-mimo add support for *thinking* mode where model can reason about the prompt add support for *vision* processing where prompt enhance can also optionally analyze input image + add support for *pre-fill* mode where prompt enhance can continue from existing caption - **UI** - kanvas add send-to functionality - kanvas improve support for standardui diff --git a/javascript/progressBar.js b/javascript/progressBar.js index 5062517e0..c12d71346 100644 --- a/javascript/progressBar.js +++ b/javascript/progressBar.js @@ -7,7 +7,7 @@ function setRefreshInterval() { document.addEventListener('visibilitychange', () => { if (document.hidden) refreshInterval = Math.max(2500, opts.live_preview_refresh_period || 1000); else refreshInterval = opts.live_preview_refresh_period || 1000; - log('refreshInterval', document.visibilityState, refreshInterval); + // log('refreshInterval', document.visibilityState, refreshInterval); }); } diff --git a/modules/call_queue.py b/modules/call_queue.py index 38b372ca2..7ed03e5b9 100644 --- a/modules/call_queue.py +++ b/modules/call_queue.py @@ -1,15 +1,26 @@ +import os +import sys import html import threading import time import cProfile from modules import shared, progress, errors, timer + queue_lock = threading.Lock() +debug = os.environ.get('SD_QUEUE_DEBUG', None) is not None + + +def get_lock(): + if debug: + fn = f'{sys._getframe(3).f_code.co_name}:{sys._getframe(2).f_code.co_name}:{sys._getframe(1).f_code.co_name}' # pylint: disable=protected-access + errors.log.debug(f'Queue: fn={fn} lock={queue_lock.locked()}') + return queue_lock def wrap_queued_call(func): def f(*args, **kwargs): - with queue_lock: + with get_lock(): res = func(*args, **kwargs) return res return f @@ -24,7 +35,7 @@ def wrap_gradio_gpu_call(func, extra_outputs=None, name=None): progress.add_task_to_queue(id_task) else: id_task = None - with queue_lock: + with get_lock(): progress.start_task(id_task) res = [None, '', '', ''] try: diff --git a/modules/framepack/framepack_wrappers.py b/modules/framepack/framepack_wrappers.py index ad4745846..2e98944c6 100644 --- a/modules/framepack/framepack_wrappers.py +++ b/modules/framepack/framepack_wrappers.py @@ -6,7 +6,7 @@ import numpy as np import torch import gradio as gr from PIL import Image -from modules import shared, processing, timer, paths, extra_networks, progress, ui_video_vlm +from modules import shared, processing, timer, paths, extra_networks, progress, ui_video_vlm, call_queue from modules.video_models.video_utils import check_av from modules.framepack import framepack_install # pylint: disable=wrong-import-order from modules.framepack import framepack_load # pylint: disable=wrong-import-order @@ -18,7 +18,6 @@ tmp_dir = os.path.join(paths.data_path, 'tmp', 'framepack') git_dir = os.path.join(os.path.dirname(__file__), 'framepack') git_repo = 'https://github.com/lllyasviel/framepack' git_commit = 'c5d375661a2557383f0b8da9d11d14c23b0c4eaf' -queue_lock = threading.Lock() loaded_variant = None @@ -131,7 +130,7 @@ def run_framepack(task_id, _ui_state, init_image, end_image, start_weight, end_w return progress.add_task_to_queue(task_id) - with queue_lock: + with call_queue.get_lock(): progress.start_task(task_id) yield from load_model(variant, attention) diff --git a/modules/ltx/ltx_process.py b/modules/ltx/ltx_process.py index 257c7c67b..582cef6b4 100644 --- a/modules/ltx/ltx_process.py +++ b/modules/ltx/ltx_process.py @@ -4,7 +4,7 @@ import threading import torch from PIL import Image -from modules import shared, errors, timer, memstats, progress, processing, sd_models, sd_samplers, extra_networks +from modules import shared, errors, timer, memstats, progress, processing, sd_models, sd_samplers, extra_networks, call_queue from modules.video_models.video_save import save_video from modules.video_models.video_utils import check_av from modules.processing_callbacks import diffusers_callback @@ -15,7 +15,6 @@ debug = shared.log.trace if os.environ.get('SD_VIDEO_DEBUG', None) is not None e # engine, model = 'LTX Video', 'LTXVideo 0.9.7 13B' upsample_repo_id = "a-r-r-o-w/LTX-Video-0.9.7-Latent-Spatial-Upsampler-diffusers" upsample_pipe = None -queue_lock = threading.Lock() def run_ltx(task_id, @@ -72,7 +71,7 @@ def run_ltx(task_id, # from diffusers import LTXConditionPipeline # pylint: disable=unused-import check_av() progress.add_task_to_queue(task_id) - with queue_lock: + with call_queue.get_lock(): progress.start_task(task_id) memstats.reset_stats() timer.process.reset() @@ -241,7 +240,7 @@ def run_ltx(task_id, frames = vae_decode(latents, decode_timestep, seed) else: frames = latents - except TypeError as e: + except TypeError: frames = latents # likely because the latents are already decoded except AssertionError as e: yield from abort(e, ok=True, p=p) diff --git a/modules/ui_control.py b/modules/ui_control.py index 27483525f..7ae41e35d 100644 --- a/modules/ui_control.py +++ b/modules/ui_control.py @@ -89,11 +89,12 @@ def get_units(*values): def generate_click(job_id: str, state: str, active_tab: str, *args): while helpers.busy: - time.sleep(0.01) + debug(f'Control: tab="{active_tab}" job={job_id} busy') + time.sleep(0.1) from modules.control.run import control_run debug(f'Control: tab="{active_tab}" job={job_id} args={args}') progress.add_task_to_queue(job_id) - with call_queue.queue_lock: + with call_queue.get_lock(): yield [None, None, None, None, 'Control: starting', ''] shared.mem_mon.reset() jobid = shared.state.begin('Control') @@ -251,8 +252,18 @@ def create_ui(_blocks: gr.Blocks=None): show_input.change(fn=lambda x: gr.update(visible=x), inputs=[show_input], outputs=[column_input]) show_preview.change(fn=lambda x: gr.update(visible=x), inputs=[show_preview], outputs=[column_preview]) input_type.change(fn=lambda x: gr.update(visible=x == 2), inputs=[input_type], outputs=[column_init]) - btn_prompt_counter.click(fn=call_queue.wrap_queued_call(ui_common.update_token_counter), inputs=[prompt], outputs=[prompt_counter], show_progress = 'hidden') - btn_negative_counter.click(fn=call_queue.wrap_queued_call(ui_common.update_token_counter), inputs=[negative], outputs=[negative_counter], show_progress = 'hidden') + btn_prompt_counter.click( + fn=call_queue.wrap_queued_call(ui_common.update_token_counter), + inputs=[prompt], + outputs=[prompt_counter], + show_progress = 'hidden', + ) + btn_negative_counter.click( + fn=call_queue.wrap_queued_call(ui_common.update_token_counter), + inputs=[negative], + outputs=[negative_counter], + show_progress = 'hidden', + ) select_dict = dict( fn=helpers.select_input, @@ -303,12 +314,14 @@ def create_ui(_blocks: gr.Blocks=None): result_txt, output_html_log, ] + global control_dict # pylint: disable=global-statement control_dict = dict( fn=generate_click, _js="submit_control", inputs=[tabs_state, state, tabs_state] + input_fields + input_script_args, outputs=output_fields, - show_progress='full', + show_progress='hidden', + # queue=not shared.cmd_opts.listen, ) prompt.submit(**control_dict) negative.submit(**control_dict) diff --git a/modules/ui_control_helpers.py b/modules/ui_control_helpers.py index 6940411ef..f1545dd07 100644 --- a/modules/ui_control_helpers.py +++ b/modules/ui_control_helpers.py @@ -131,7 +131,7 @@ def process_kanvas(x): # only used when kanvas overrides gr.Image object def select_input(input_mode, input_image, init_image, init_type, input_video, input_batch, input_folder): global busy, input_source, input_init, input_mask # pylint: disable=global-statement t0 = time.time() - busy = True + busy = False selected_input = input_image # default: Image or Kanvas if input_mode == 'Video': selected_input = input_video @@ -142,8 +142,9 @@ def select_input(input_mode, input_image, init_image, init_type, input_video, in size = [gr.update(), gr.update()] if selected_input is None: input_source = None - busy = False return [gr.Tabs.update(), None, ''] + size + + busy = True input_type = type(selected_input) input_mask = None status = 'Control input | Unknown'