diff --git a/enhanced/topbar.py b/enhanced/topbar.py index 2dc77278..34c82a55 100644 --- a/enhanced/topbar.py +++ b/enhanced/topbar.py @@ -1664,6 +1664,11 @@ def wait_for_vlm_completion(check_interval=0.5): logger.error(f"VLM Error: {str(e)}") return None def avoid_empty_prompt_for_scene(prompt, state, canvas_image, input_image1, scene_theme, additional_prompt, additional_prompt_2): + if canvas_image is None and isinstance(state, dict): + _cache_key = state.get('user_did', '') or 'default' + _cached = util.get_scene_canvas_cache(_cache_key) + if _cached is not None: + canvas_image = _cached describe_prompt = None if not prompt and 'scene_frontend' in state: visible = _scene_disvisible_with_optional_inputs(state["scene_frontend"]) @@ -1879,6 +1884,11 @@ def _scene_director_audio_status_for_generation(scene_director_enabled=False, sc def process_before_generation(state_params, seed_random, image_seed, backend_params, scene_theme, scene_canvas_image, scene_input_image1, scene_input_image2, scene_input_image3, scene_input_image4, scene_additional_prompt, scene_additional_prompt_2, scene_var_number, scene_var_number2, scene_var_number3, scene_var_number4, scene_var_number5, scene_var_number6, scene_var_number7, scene_var_number8, scene_var_number9, scene_var_number10, scene_steps, scene_switch_option1, scene_switch_option2, scene_switch_option3, scene_switch_option4, scene_aspect_ratio, scene_image_number, scene_video, scene_audio, scene_original_video_path, active_video_source, sam3_input_video, sam3_original_video_path, sam3_mask_video, overwrite_width=None, overwrite_height=None, resolution_multiplier=1.0, resolution_quantize_step=None, resolution_edit_mode=None, resolution_original_input=False, sam3_trim_payload=None, overwrite_step=None, scene_director_enabled=False, scene_director_state=None, scene_video_duration=None, scene_reference_video=None, scene_reference_video_original_path=None): + if scene_canvas_image is None and isinstance(state_params, dict): + _cache_key = state_params.get('user_did', '') or 'default' + _cached = util.get_scene_canvas_cache(_cache_key) + if _cached is not None: + scene_canvas_image = _cached regen_scene_additional_prompt = scene_additional_prompt regen_scene_additional_prompt_2 = scene_additional_prompt_2 user_did = _state_user_did(state_params) diff --git a/modules/util.py b/modules/util.py index 96bf999d..237166b8 100644 --- a/modules/util.py +++ b/modules/util.py @@ -13,6 +13,8 @@ import json import hashlib +import threading +import time as _time_module from PIL import Image @@ -48,6 +50,36 @@ def log_ui_trace(target_logger, *args, **kwargs): pass +_scene_canvas_cache: dict = {} +_scene_canvas_cache_lock = threading.Lock() +_SCENE_CANVAS_CACHE_TTL = 300 + + +def store_scene_canvas_cache(key, value): + with _scene_canvas_cache_lock: + now = _time_module.monotonic() + for k in list(_scene_canvas_cache.keys()): + if now - _scene_canvas_cache[k][1] > _SCENE_CANVAS_CACHE_TTL: + del _scene_canvas_cache[k] + _scene_canvas_cache[key] = (value, now) + + +def get_scene_canvas_cache(key): + with _scene_canvas_cache_lock: + entry = _scene_canvas_cache.get(key) + if entry and _time_module.monotonic() - entry[1] <= _SCENE_CANVAS_CACHE_TTL: + return entry[0] + return None + + +def clear_scene_canvas_cache(key=None): + with _scene_canvas_cache_lock: + if key is not None: + _scene_canvas_cache.pop(key, None) + else: + _scene_canvas_cache.clear() + + def erode_or_dilate(x, k): k = int(k) if k > 0: diff --git a/webui.py b/webui.py index c2a284c4..b1e8b524 100644 --- a/webui.py +++ b/webui.py @@ -2625,6 +2625,7 @@ def _launch_root_app_with_frontend_port_retry(**kwargs): scene_original_video_path = gr.State(None) scene_original_video_backup = gr.State(None) scene_reference_video_original_path = gr.State(None) + _scene_canvas_pass = gr.State(None) active_video_source = gr.State(None) resolution_source_meta = gr.Textbox(value="{}", visible="hidden", elem_id="resolution_source_meta", elem_classes=["resolution-hidden-control"]) resolution_quantize_step = gr.Number(value=flags.default_resolution_quantize_step, visible="hidden", elem_id="resolution_quantize_step", elem_classes=["resolution-hidden-control"]) @@ -8559,6 +8560,8 @@ def cache_input_image_func(state_params, enhance_enabled, tab, uov, inpaint, enh enhance_enabled_bool = bool(enhance_enabled) if is_scene: + _cache_key = state_params.get('user_did', '') or 'default' + util.store_scene_canvas_cache(_cache_key, scene_canvas) processed, label, scene_hidden, scene_candidates = resolve_scene_comparison_input(state_params, scene1, scene_canvas) if processed is not None: util.log_ui_trace( @@ -8999,7 +9002,7 @@ def bind_generation_failure_cleanup(event): topbar.process_before_generation, inputs=[ state_topbar, seed_random, image_seed, params_backend, scene_theme, - scene_canvas_image, scene_input_image1, scene_input_image2, scene_input_image3, scene_input_image4, + _scene_canvas_pass, scene_input_image1, scene_input_image2, scene_input_image3, scene_input_image4, scene_additional_prompt, scene_additional_prompt_2, scene_var_number, scene_var_number2, scene_var_number3, scene_var_number4, scene_var_number5, scene_var_number6, scene_var_number7, scene_var_number8, @@ -9017,7 +9020,7 @@ def bind_generation_failure_cleanup(event): )) generate_event = bind_generation_failure_cleanup(generate_event.success(_sync_model_params_state_from_ui, inputs=model_state_ui_inputs, outputs=model_params_state, show_progress=False, queue=False)) generate_event = bind_generation_failure_cleanup(generate_event.success(topbar.wait_for_vlm_completion, outputs=[], show_progress=False, queue=False)) - generate_event = bind_generation_failure_cleanup(generate_event.success(topbar.avoid_empty_prompt_for_scene, inputs=[prompt, state_topbar, scene_canvas_image, scene_input_image1, scene_theme, scene_additional_prompt, scene_additional_prompt_2], outputs=prompt, show_progress=False, queue=False)) + generate_event = bind_generation_failure_cleanup(generate_event.success(topbar.avoid_empty_prompt_for_scene, inputs=[prompt, state_topbar, _scene_canvas_pass, scene_input_image1, scene_theme, scene_additional_prompt, scene_additional_prompt_2], outputs=prompt, show_progress=False, queue=False)) generate_event = bind_generation_failure_cleanup(generate_event.success(apply_scene_director_prompt_for_generation, inputs=[prompt, params_backend, scene_director_enabled, scene_director_state, state_topbar, scene_theme], outputs=[prompt, params_backend], show_progress=False, queue=False)) generate_event = bind_generation_failure_cleanup(generate_event.success(select_random_aspect_ratio, inputs=[random_aspect_ratio_checkbox, random_aspect_ratio_state, aspect_ratios_selection], outputs=[overwrite_width, overwrite_height, aspect_ratios_selection, random_aspect_ratio_state], show_progress=False, queue=False)) generate_event = bind_generation_failure_cleanup(generate_event.success(sync_quick_enhance_for_generation, inputs=[quick_enhance, quick_enhance_uov_strength, enhance_checkbox, enhance_uov_method, enhance_uov_strength], outputs=[enhance_checkbox, enhance_uov_method, enhance_uov_strength], show_progress=False, queue=False, js=sync_enhance_submit_state_js))