UI persistence (#7050)

This commit is contained in:
oobabooga 2025-06-07 22:46:52 -03:00 committed by GitHub
parent db847eed4c
commit 35ed55d18f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 112 additions and 16 deletions

View file

@ -35,6 +35,8 @@ settings = {
'mode': 'instruct',
'chat_style': 'cai-chat',
'chat-instruct_command': 'Continue the chat dialogue below. Write a single reply for the character "<|character|>".\n\n<|prompt|>',
'enable_web_search': False,
'web_search_pages': 3,
'prompt-default': 'QA',
'prompt-notebook': 'QA',
'character': 'Assistant',

View file

@ -1,4 +1,5 @@
import copy
import threading
from pathlib import Path
import gradio as gr
@ -7,6 +8,16 @@ import yaml
import extensions
from modules import shared
from modules.chat import load_history
from modules.utils import gradio
# Global state for auto-saving UI settings with debouncing
_auto_save_timer = None
_auto_save_lock = threading.Lock()
_last_interface_state = None
_last_preset = None
_last_extensions = None
_last_show_controls = None
_last_theme_state = None
with open(Path(__file__).resolve().parent / '../css/NotoSans/stylesheet.css', 'r') as f:
css = f.read()
@ -334,6 +345,101 @@ def save_settings(state, preset, extensions_list, show_controls, theme_state):
return yaml.dump(output, sort_keys=False, width=float("inf"), allow_unicode=True)
def store_current_state_and_debounce(interface_state, preset, extensions, show_controls, theme_state):
"""Store current state and trigger debounced save"""
global _auto_save_timer, _last_interface_state, _last_preset, _last_extensions, _last_show_controls, _last_theme_state
if shared.args.multi_user:
return
# Store the current state in global variables
_last_interface_state = interface_state
_last_preset = preset
_last_extensions = extensions
_last_show_controls = show_controls
_last_theme_state = theme_state
# Reset the debounce timer
with _auto_save_lock:
if _auto_save_timer is not None:
_auto_save_timer.cancel()
_auto_save_timer = threading.Timer(2.0, _perform_debounced_save)
_auto_save_timer.start()
def _perform_debounced_save():
"""Actually perform the save using the stored state"""
global _auto_save_timer
try:
if _last_interface_state is not None:
contents = save_settings(_last_interface_state, _last_preset, _last_extensions, _last_show_controls, _last_theme_state)
settings_path = Path('user_data') / 'settings.yaml'
settings_path.parent.mkdir(exist_ok=True)
with open(settings_path, 'w', encoding='utf-8') as f:
f.write(contents)
except Exception as e:
print(f"Auto-save failed: {e}")
finally:
with _auto_save_lock:
_auto_save_timer = None
def setup_auto_save():
"""Attach auto-save to key UI elements"""
if shared.args.multi_user:
return
change_elements = [
# Chat tab (ui_chat.py)
'start_with',
'enable_web_search',
'web_search_pages',
'mode',
'chat_style',
'chat-instruct_command',
'character_menu',
'name1',
'user_bio',
'custom_system_message',
'chat_template_str',
# Parameters tab (ui_parameters.py)
'preset_menu',
'max_new_tokens',
'prompt_lookup_num_tokens',
'max_tokens_second',
'auto_max_new_tokens',
'ban_eos_token',
'add_bos_token',
'enable_thinking',
'skip_special_tokens',
'stream',
'static_cache',
'seed',
'custom_stopping_strings',
'custom_token_bans',
'negative_prompt',
# Default tab (ui_default.py)
'prompt_menu-default',
# Notebook tab (ui_notebook.py)
'prompt_menu-notebook',
# Session tab (ui_session.py)
'show_controls',
'theme_state',
]
for element_name in change_elements:
if element_name in shared.gradio:
shared.gradio[element_name].change(
gather_interface_values, gradio(shared.input_elements), gradio('interface_state')).then(
store_current_state_and_debounce, gradio('interface_state', 'preset_menu', 'extensions_menu', 'show_controls', 'theme_state'), None, show_progress=False)
def create_refresh_button(refresh_component, refresh_method, refreshed_args, elem_class, interactive=True):
"""
Copied from https://github.com/AUTOMATIC1111/stable-diffusion-webui

View file

@ -10,11 +10,10 @@ def create_ui():
with gr.Tab("Session", elem_id="session-tab"):
with gr.Row():
with gr.Column():
shared.gradio['reset_interface'] = gr.Button("Apply flags/extensions and restart", interactive=not mu)
with gr.Row():
shared.gradio['toggle_dark_mode'] = gr.Button('Toggle 💡')
shared.gradio['save_settings'] = gr.Button('Save UI defaults to user_data/settings.yaml', interactive=not mu)
shared.gradio['reset_interface'] = gr.Button("Apply flags/extensions and restart", interactive=not mu)
with gr.Row():
with gr.Column():
shared.gradio['extensions_menu'] = gr.CheckboxGroup(choices=utils.get_available_extensions(), value=shared.args.extensions, label="Available extensions", info='Note that some of these extensions may require manually installing Python requirements through the command: pip install -r extensions/extension_name/requirements.txt', elem_classes='checkboxgroup-table')
@ -42,20 +41,6 @@ def create_ui():
lambda x: 'dark' if x == 'light' else 'light', gradio('theme_state'), gradio('theme_state')).then(
None, None, None, js=f'() => {{{ui.dark_theme_js}; toggleDarkMode()}}')
shared.gradio['save_settings'].click(
ui.gather_interface_values, gradio(shared.input_elements), gradio('interface_state')).then(
handle_save_settings, gradio('interface_state', 'preset_menu', 'extensions_menu', 'show_controls', 'theme_state'), gradio('save_contents', 'save_filename', 'save_root', 'file_saver'), show_progress=False)
def handle_save_settings(state, preset, extensions, show_controls, theme):
contents = ui.save_settings(state, preset, extensions, show_controls, theme)
return [
contents,
"settings.yaml",
"user_data/",
gr.update(visible=True)
]
def set_interface_arguments(extensions, bool_active):
shared.args.extensions = extensions

View file

@ -150,6 +150,9 @@ def create_interface():
ui_parameters.create_event_handlers()
ui_model_menu.create_event_handlers()
# UI persistence events
ui.setup_auto_save()
# Interface launch events
shared.gradio['interface'].load(
None,