2023-08-14 11:46:07 -03:00
|
|
|
import copy
|
2025-06-07 22:46:52 -03:00
|
|
|
import threading
|
2023-03-15 12:33:26 -03:00
|
|
|
from pathlib import Path
|
|
|
|
|
|
2023-01-22 00:02:46 -03:00
|
|
|
import gradio as gr
|
2023-08-14 11:46:07 -03:00
|
|
|
import yaml
|
2023-01-22 00:02:46 -03:00
|
|
|
|
2024-01-04 20:33:32 -08:00
|
|
|
import extensions
|
2025-06-15 15:53:16 -07:00
|
|
|
import modules.extensions as extensions_module
|
2023-04-12 10:27:06 -03:00
|
|
|
from modules import shared
|
2025-06-02 09:50:17 -03:00
|
|
|
from modules.chat import load_history
|
2025-06-07 22:46:52 -03:00
|
|
|
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
|
2023-04-12 10:27:06 -03:00
|
|
|
|
2025-06-11 03:16:50 +02:00
|
|
|
with open(Path(__file__).resolve().parent / '../css/NotoSans/stylesheet.css', 'r', encoding='utf-8') as f:
|
2023-03-15 12:33:26 -03:00
|
|
|
css = f.read()
|
2025-06-11 03:16:50 +02:00
|
|
|
with open(Path(__file__).resolve().parent / '../css/main.css', 'r', encoding='utf-8') as f:
|
2023-09-13 13:29:00 -07:00
|
|
|
css += f.read()
|
2025-06-11 03:16:50 +02:00
|
|
|
with open(Path(__file__).resolve().parent / '../css/katex/katex.min.css', 'r', encoding='utf-8') as f:
|
2024-04-26 10:13:11 -03:00
|
|
|
css += f.read()
|
2025-06-11 03:16:50 +02:00
|
|
|
with open(Path(__file__).resolve().parent / '../css/highlightjs/highlightjs-copy.min.css', 'r', encoding='utf-8') as f:
|
2024-04-26 10:13:11 -03:00
|
|
|
css += f.read()
|
2025-06-11 03:16:50 +02:00
|
|
|
with open(Path(__file__).resolve().parent / '../js/main.js', 'r', encoding='utf-8') as f:
|
2023-08-13 01:12:15 -03:00
|
|
|
js = f.read()
|
2025-06-11 03:16:50 +02:00
|
|
|
with open(Path(__file__).resolve().parent / '../js/global_scope_js.js', 'r', encoding='utf-8') as f:
|
2025-01-11 16:59:21 -03:00
|
|
|
global_scope_js = f.read()
|
2025-06-11 03:16:50 +02:00
|
|
|
with open(Path(__file__).resolve().parent / '../js/save_files.js', 'r', encoding='utf-8') as f:
|
2023-08-02 18:50:13 -07:00
|
|
|
save_files_js = f.read()
|
2025-06-11 03:16:50 +02:00
|
|
|
with open(Path(__file__).resolve().parent / '../js/switch_tabs.js', 'r', encoding='utf-8') as f:
|
2023-08-13 18:14:09 -07:00
|
|
|
switch_tabs_js = f.read()
|
2025-06-11 03:16:50 +02:00
|
|
|
with open(Path(__file__).resolve().parent / '../js/show_controls.js', 'r', encoding='utf-8') as f:
|
2023-08-16 02:39:58 -03:00
|
|
|
show_controls_js = f.read()
|
2025-06-11 03:16:50 +02:00
|
|
|
with open(Path(__file__).resolve().parent / '../js/update_big_picture.js', 'r', encoding='utf-8') as f:
|
2023-11-19 02:05:17 -03:00
|
|
|
update_big_picture_js = f.read()
|
2025-06-11 03:16:50 +02:00
|
|
|
with open(Path(__file__).resolve().parent / '../js/dark_theme.js', 'r', encoding='utf-8') as f:
|
2024-07-20 20:32:57 -07:00
|
|
|
dark_theme_js = f.read()
|
2023-03-15 12:01:32 -03:00
|
|
|
|
2023-07-04 00:03:30 -03:00
|
|
|
refresh_symbol = '🔄'
|
2023-05-20 17:48:45 -07:00
|
|
|
delete_symbol = '🗑️'
|
|
|
|
|
save_symbol = '💾'
|
|
|
|
|
|
2023-04-18 23:36:23 -03:00
|
|
|
theme = gr.themes.Default(
|
2023-09-13 13:29:00 -07:00
|
|
|
font=['Noto Sans', 'Helvetica', 'ui-sans-serif', 'system-ui', 'sans-serif'],
|
2023-04-18 23:36:23 -03:00
|
|
|
font_mono=['IBM Plex Mono', 'ui-monospace', 'Consolas', 'monospace'],
|
|
|
|
|
).set(
|
|
|
|
|
border_color_primary='#c5c5d2',
|
2023-04-21 00:20:33 -03:00
|
|
|
button_large_padding='6px 12px',
|
2023-04-21 02:47:18 -03:00
|
|
|
body_text_color_subdued='#484848',
|
2024-03-13 08:18:49 -07:00
|
|
|
background_fill_secondary='#eaeaea',
|
2024-04-26 10:13:11 -03:00
|
|
|
background_fill_primary='var(--neutral-50)',
|
2024-06-27 20:47:42 -07:00
|
|
|
body_background_fill="white",
|
|
|
|
|
block_background_fill="#f4f4f4",
|
|
|
|
|
body_text_color="#333",
|
|
|
|
|
button_secondary_background_fill="#f4f4f4",
|
|
|
|
|
button_secondary_border_color="var(--border-color-primary)"
|
2023-04-18 23:36:23 -03:00
|
|
|
)
|
2023-04-07 00:15:45 -03:00
|
|
|
|
2024-12-17 00:47:41 -03:00
|
|
|
if not shared.args.old_colors:
|
|
|
|
|
theme = theme.set(
|
|
|
|
|
# General Colors
|
|
|
|
|
border_color_primary='#c5c5d2',
|
|
|
|
|
body_text_color_subdued='#484848',
|
|
|
|
|
background_fill_secondary='#eaeaea',
|
2025-06-19 11:28:12 -07:00
|
|
|
background_fill_secondary_dark='var(--selected-item-color-dark, #282930)',
|
2024-12-17 00:47:41 -03:00
|
|
|
background_fill_primary='var(--neutral-50)',
|
2025-06-19 11:28:12 -07:00
|
|
|
background_fill_primary_dark='var(--darker-gray, #1C1C1D)',
|
2024-12-17 00:47:41 -03:00
|
|
|
body_background_fill="white",
|
|
|
|
|
block_background_fill="transparent",
|
2025-05-05 06:16:11 -07:00
|
|
|
body_text_color='rgb(64, 64, 64)',
|
2025-06-08 15:19:25 -07:00
|
|
|
button_secondary_background_fill="white",
|
2024-12-17 00:47:41 -03:00
|
|
|
button_secondary_border_color="var(--border-color-primary)",
|
2025-06-08 15:19:25 -07:00
|
|
|
input_shadow="none",
|
|
|
|
|
button_shadow_hover="none",
|
2024-12-17 00:47:41 -03:00
|
|
|
|
|
|
|
|
# Dark Mode Colors
|
2025-06-19 11:28:12 -07:00
|
|
|
input_background_fill_dark='var(--darker-gray, #1C1C1D)',
|
|
|
|
|
checkbox_background_color_dark='var(--darker-gray, #1C1C1D)',
|
2024-12-17 00:47:41 -03:00
|
|
|
block_background_fill_dark='transparent',
|
|
|
|
|
block_border_color_dark='transparent',
|
2025-06-19 11:28:12 -07:00
|
|
|
input_border_color_dark='var(--border-color-dark, #525252)',
|
|
|
|
|
input_border_color_focus_dark='var(--border-color-dark, #525252)',
|
|
|
|
|
checkbox_border_color_dark='var(--border-color-dark, #525252)',
|
|
|
|
|
border_color_primary_dark='var(--border-color-dark, #525252)',
|
|
|
|
|
button_secondary_border_color_dark='var(--border-color-dark, #525252)',
|
|
|
|
|
body_background_fill_dark='var(--dark-gray, #212125)',
|
2024-12-17 00:47:41 -03:00
|
|
|
button_primary_background_fill_dark='transparent',
|
|
|
|
|
button_secondary_background_fill_dark='transparent',
|
|
|
|
|
checkbox_label_background_fill_dark='transparent',
|
|
|
|
|
button_cancel_background_fill_dark='transparent',
|
2025-06-19 11:28:12 -07:00
|
|
|
button_secondary_background_fill_hover_dark='var(--selected-item-color-dark, #282930)',
|
|
|
|
|
checkbox_label_background_fill_hover_dark='var(--selected-item-color-dark, #282930)',
|
|
|
|
|
table_even_background_fill_dark='var(--darker-gray, #1C1C1D)',
|
|
|
|
|
table_odd_background_fill_dark='var(--selected-item-color-dark, #282930)',
|
|
|
|
|
code_background_fill_dark='var(--darker-gray, #1C1C1D)',
|
2024-12-17 00:47:41 -03:00
|
|
|
|
|
|
|
|
# Shadows and Radius
|
|
|
|
|
checkbox_label_shadow='none',
|
|
|
|
|
block_shadow='none',
|
|
|
|
|
block_shadow_dark='none',
|
2025-05-30 11:32:24 -07:00
|
|
|
input_shadow_focus='none',
|
|
|
|
|
input_shadow_focus_dark='none',
|
2024-12-17 00:47:41 -03:00
|
|
|
button_large_radius='0.375rem',
|
|
|
|
|
button_large_padding='6px 12px',
|
|
|
|
|
input_radius='0.375rem',
|
2025-06-08 18:11:27 -07:00
|
|
|
block_radius='0',
|
2024-12-17 00:47:41 -03:00
|
|
|
)
|
|
|
|
|
|
2025-04-26 08:56:54 -03:00
|
|
|
if Path("user_data/notification.mp3").exists():
|
2023-08-06 21:49:27 -03:00
|
|
|
audio_notification_js = "document.querySelector('#audio_notification audio')?.play();"
|
|
|
|
|
else:
|
|
|
|
|
audio_notification_js = ""
|
|
|
|
|
|
2023-05-03 21:43:17 -03:00
|
|
|
|
2023-04-14 11:07:28 -03:00
|
|
|
def list_model_elements():
|
2023-07-04 00:03:30 -03:00
|
|
|
elements = [
|
2023-09-25 10:28:35 -07:00
|
|
|
'filter_by_loader',
|
2025-01-10 18:04:32 -03:00
|
|
|
'loader',
|
2023-07-04 00:03:30 -03:00
|
|
|
'cpu_memory',
|
2025-05-13 12:07:59 -07:00
|
|
|
'gpu_layers',
|
2023-07-04 00:03:30 -03:00
|
|
|
'threads',
|
2023-10-01 21:27:04 -07:00
|
|
|
'threads_batch',
|
2025-04-18 09:59:37 -03:00
|
|
|
'batch_size',
|
2025-04-25 16:59:03 -07:00
|
|
|
'ctx_size',
|
2025-01-10 18:04:32 -03:00
|
|
|
'cache_type',
|
|
|
|
|
'tensor_split',
|
2025-04-25 07:32:51 -07:00
|
|
|
'extra_flags',
|
2025-04-29 05:28:46 -07:00
|
|
|
'streaming_llm',
|
2025-01-10 18:04:32 -03:00
|
|
|
'gpu_split',
|
2023-08-25 06:53:37 -07:00
|
|
|
'alpha_value',
|
2023-09-27 03:05:00 +02:00
|
|
|
'rope_freq_base',
|
2025-01-10 18:04:32 -03:00
|
|
|
'compress_pos_emb',
|
|
|
|
|
'compute_dtype',
|
|
|
|
|
'quant_type',
|
|
|
|
|
'num_experts_per_token',
|
|
|
|
|
'load_in_8bit',
|
|
|
|
|
'load_in_4bit',
|
2024-06-13 03:34:54 +00:00
|
|
|
'flash_attn',
|
2025-07-09 18:38:45 -07:00
|
|
|
'attn_implementation',
|
2025-01-10 18:04:32 -03:00
|
|
|
'cpu',
|
|
|
|
|
'disk',
|
|
|
|
|
'row_split',
|
2025-04-18 09:59:37 -03:00
|
|
|
'no_kv_offload',
|
2025-01-10 18:04:32 -03:00
|
|
|
'no_mmap',
|
|
|
|
|
'mlock',
|
|
|
|
|
'numa',
|
|
|
|
|
'use_double_quant',
|
|
|
|
|
'bf16',
|
|
|
|
|
'autosplit',
|
|
|
|
|
'enable_tp',
|
2025-08-17 13:19:11 -07:00
|
|
|
'tp_backend',
|
2025-01-10 18:04:32 -03:00
|
|
|
'no_flash_attn',
|
|
|
|
|
'no_xformers',
|
|
|
|
|
'no_sdpa',
|
|
|
|
|
'cfg_cache',
|
2024-06-24 02:30:03 -03:00
|
|
|
'cpp_runner',
|
2025-01-10 18:04:32 -03:00
|
|
|
'trust_remote_code',
|
|
|
|
|
'no_use_fast',
|
2025-04-23 20:10:16 -03:00
|
|
|
'model_draft',
|
|
|
|
|
'draft_max',
|
|
|
|
|
'gpu_layers_draft',
|
|
|
|
|
'device_draft',
|
|
|
|
|
'ctx_size_draft',
|
2025-08-10 01:27:25 -03:00
|
|
|
'mmproj',
|
2023-07-04 00:03:30 -03:00
|
|
|
]
|
2024-07-21 22:06:49 -07:00
|
|
|
|
2023-04-14 11:07:28 -03:00
|
|
|
return elements
|
|
|
|
|
|
|
|
|
|
|
2023-07-04 00:03:30 -03:00
|
|
|
def list_interface_input_elements():
|
|
|
|
|
elements = [
|
|
|
|
|
'temperature',
|
2024-01-08 23:28:35 -03:00
|
|
|
'dynatemp_low',
|
|
|
|
|
'dynatemp_high',
|
|
|
|
|
'dynatemp_exponent',
|
2024-02-03 21:20:02 -06:00
|
|
|
'smoothing_factor',
|
2024-03-03 10:22:21 -06:00
|
|
|
'smoothing_curve',
|
2023-11-02 14:32:51 -05:00
|
|
|
'min_p',
|
2025-01-10 18:04:32 -03:00
|
|
|
'top_p',
|
2023-07-04 00:03:30 -03:00
|
|
|
'top_k',
|
|
|
|
|
'typical_p',
|
2025-01-10 18:04:32 -03:00
|
|
|
'xtc_threshold',
|
|
|
|
|
'xtc_probability',
|
2023-07-04 00:03:30 -03:00
|
|
|
'epsilon_cutoff',
|
|
|
|
|
'eta_cutoff',
|
2025-01-10 18:04:32 -03:00
|
|
|
'tfs',
|
|
|
|
|
'top_a',
|
2025-03-14 16:45:11 -03:00
|
|
|
'top_n_sigma',
|
2025-01-10 18:04:32 -03:00
|
|
|
'dry_multiplier',
|
|
|
|
|
'dry_allowed_length',
|
|
|
|
|
'dry_base',
|
2023-07-04 00:03:30 -03:00
|
|
|
'repetition_penalty',
|
2023-10-25 10:10:28 -05:00
|
|
|
'frequency_penalty',
|
2025-01-10 18:04:32 -03:00
|
|
|
'presence_penalty',
|
2023-07-04 00:03:30 -03:00
|
|
|
'encoder_repetition_penalty',
|
|
|
|
|
'no_repeat_ngram_size',
|
2025-01-10 18:04:32 -03:00
|
|
|
'repetition_penalty_range',
|
2023-07-04 00:03:30 -03:00
|
|
|
'penalty_alpha',
|
2025-01-10 18:04:32 -03:00
|
|
|
'guidance_scale',
|
2023-07-04 00:03:30 -03:00
|
|
|
'mirostat_mode',
|
|
|
|
|
'mirostat_tau',
|
|
|
|
|
'mirostat_eta',
|
2025-01-10 18:04:32 -03:00
|
|
|
'max_new_tokens',
|
|
|
|
|
'prompt_lookup_num_tokens',
|
|
|
|
|
'max_tokens_second',
|
|
|
|
|
'do_sample',
|
|
|
|
|
'dynamic_temperature',
|
|
|
|
|
'temperature_last',
|
|
|
|
|
'auto_max_new_tokens',
|
2023-07-04 00:03:30 -03:00
|
|
|
'ban_eos_token',
|
2025-01-10 18:04:32 -03:00
|
|
|
'add_bos_token',
|
2025-04-28 22:37:01 -07:00
|
|
|
'enable_thinking',
|
2025-08-05 15:19:11 -07:00
|
|
|
'reasoning_effort',
|
2023-07-04 00:03:30 -03:00
|
|
|
'skip_special_tokens',
|
|
|
|
|
'stream',
|
2025-01-04 17:52:57 -08:00
|
|
|
'static_cache',
|
2025-01-10 18:04:32 -03:00
|
|
|
'truncation_length',
|
|
|
|
|
'seed',
|
|
|
|
|
'sampler_priority',
|
|
|
|
|
'custom_stopping_strings',
|
|
|
|
|
'custom_token_bans',
|
|
|
|
|
'negative_prompt',
|
|
|
|
|
'dry_sequence_breakers',
|
|
|
|
|
'grammar_string',
|
2025-05-27 23:55:27 -04:00
|
|
|
'navigate_message_index',
|
|
|
|
|
'navigate_direction',
|
2025-05-28 17:09:05 -07:00
|
|
|
'navigate_message_role',
|
2025-05-27 23:55:27 -04:00
|
|
|
'edit_message_index',
|
|
|
|
|
'edit_message_text',
|
|
|
|
|
'edit_message_role',
|
|
|
|
|
'branch_index',
|
2025-05-28 04:27:28 -03:00
|
|
|
'enable_web_search',
|
|
|
|
|
'web_search_pages',
|
2023-07-04 00:03:30 -03:00
|
|
|
]
|
|
|
|
|
|
2023-08-13 01:12:15 -03:00
|
|
|
# Chat elements
|
|
|
|
|
elements += [
|
|
|
|
|
'history',
|
2025-01-02 18:46:40 -08:00
|
|
|
'search_chat',
|
2024-07-21 00:01:42 -03:00
|
|
|
'unique_id',
|
2025-01-10 18:04:32 -03:00
|
|
|
'textbox',
|
|
|
|
|
'start_with',
|
|
|
|
|
'mode',
|
|
|
|
|
'chat_style',
|
|
|
|
|
'chat-instruct_command',
|
|
|
|
|
'character_menu',
|
2023-08-13 01:12:15 -03:00
|
|
|
'name2',
|
|
|
|
|
'context',
|
2025-01-10 18:04:32 -03:00
|
|
|
'greeting',
|
|
|
|
|
'name1',
|
|
|
|
|
'user_bio',
|
2023-11-07 20:02:58 -03:00
|
|
|
'custom_system_message',
|
2023-12-12 17:23:14 -03:00
|
|
|
'instruction_template_str',
|
|
|
|
|
'chat_template_str',
|
2023-08-13 01:12:15 -03:00
|
|
|
]
|
2023-04-24 03:05:47 -03:00
|
|
|
|
2023-08-13 01:12:15 -03:00
|
|
|
# Notebook/default elements
|
|
|
|
|
elements += [
|
|
|
|
|
'textbox-default',
|
2025-01-10 18:04:32 -03:00
|
|
|
'textbox-notebook',
|
2023-08-14 11:46:07 -03:00
|
|
|
'prompt_menu-default',
|
|
|
|
|
'prompt_menu-notebook',
|
2025-01-10 18:04:32 -03:00
|
|
|
'output_textbox',
|
2023-08-13 01:12:15 -03:00
|
|
|
]
|
|
|
|
|
|
|
|
|
|
# Model elements
|
2023-04-14 11:07:28 -03:00
|
|
|
elements += list_model_elements()
|
2023-08-13 01:12:15 -03:00
|
|
|
|
2025-06-08 09:31:38 -07:00
|
|
|
# Other elements
|
|
|
|
|
elements += [
|
2025-06-16 13:19:29 -03:00
|
|
|
'show_two_notebook_columns',
|
2025-06-12 16:54:43 -07:00
|
|
|
'paste_to_attachment',
|
|
|
|
|
'include_past_attachments',
|
2025-06-08 09:31:38 -07:00
|
|
|
]
|
|
|
|
|
|
2023-04-12 10:27:06 -03:00
|
|
|
return elements
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def gather_interface_values(*args):
|
2024-07-21 22:06:49 -07:00
|
|
|
interface_elements = list_interface_input_elements()
|
|
|
|
|
|
2023-04-12 10:27:06 -03:00
|
|
|
output = {}
|
2024-07-21 22:06:49 -07:00
|
|
|
for element, value in zip(interface_elements, args):
|
|
|
|
|
output[element] = value
|
2023-04-24 03:05:47 -03:00
|
|
|
|
2023-07-04 00:03:30 -03:00
|
|
|
if not shared.args.multi_user:
|
|
|
|
|
shared.persistent_interface_state = output
|
|
|
|
|
|
2025-06-06 22:38:20 -07:00
|
|
|
# Remove the chat input, as it gets cleared after this function call
|
|
|
|
|
shared.persistent_interface_state.pop('textbox')
|
|
|
|
|
|
2025-06-02 09:50:17 -03:00
|
|
|
# Prevent history loss if backend is restarted but UI is not refreshed
|
2025-07-04 06:04:04 -07:00
|
|
|
if (output['history'] is None or (len(output['history'].get('visible', [])) == 0 and len(output['history'].get('internal', [])) == 0)) and output['unique_id'] is not None:
|
2025-06-02 09:50:17 -03:00
|
|
|
output['history'] = load_history(output['unique_id'], output['character_menu'], output['mode'])
|
|
|
|
|
|
2023-04-12 10:27:06 -03:00
|
|
|
return output
|
|
|
|
|
|
|
|
|
|
|
2023-04-24 03:05:47 -03:00
|
|
|
def apply_interface_values(state, use_persistent=False):
|
|
|
|
|
if use_persistent:
|
|
|
|
|
state = shared.persistent_interface_state
|
2024-12-17 00:47:41 -03:00
|
|
|
if 'textbox-default' in state and 'prompt_menu-default' in state:
|
2024-07-22 11:05:40 -07:00
|
|
|
state.pop('prompt_menu-default')
|
|
|
|
|
|
2025-04-26 18:25:06 -07:00
|
|
|
if 'textbox-notebook' in state and 'prompt_menu-notebook' in state:
|
2024-07-22 11:05:40 -07:00
|
|
|
state.pop('prompt_menu-notebook')
|
2023-04-24 03:05:47 -03:00
|
|
|
|
2023-07-04 00:03:30 -03:00
|
|
|
elements = list_interface_input_elements()
|
2024-07-22 11:05:40 -07:00
|
|
|
|
2023-04-24 03:05:47 -03:00
|
|
|
if len(state) == 0:
|
|
|
|
|
return [gr.update() for k in elements] # Dummy, do nothing
|
|
|
|
|
else:
|
2023-07-07 09:09:14 -07:00
|
|
|
return [state[k] if k in state else gr.update() for k in elements]
|
2023-04-14 11:07:28 -03:00
|
|
|
|
|
|
|
|
|
2025-06-11 07:39:49 -07:00
|
|
|
def save_settings(state, preset, extensions_list, show_controls, theme_state, manual_save=False):
|
2023-08-14 11:46:07 -03:00
|
|
|
output = copy.deepcopy(shared.settings)
|
2025-06-08 01:58:02 -03:00
|
|
|
exclude = []
|
2023-08-14 11:46:07 -03:00
|
|
|
for k in state:
|
|
|
|
|
if k in shared.settings and k not in exclude:
|
|
|
|
|
output[k] = state[k]
|
|
|
|
|
|
|
|
|
|
output['preset'] = preset
|
2025-06-16 13:19:29 -03:00
|
|
|
output['prompt-notebook'] = state['prompt_menu-default'] if state['show_two_notebook_columns'] else state['prompt_menu-notebook']
|
2023-08-14 11:46:07 -03:00
|
|
|
output['character'] = state['character_menu']
|
|
|
|
|
output['seed'] = int(output['seed'])
|
2023-08-16 07:03:53 -07:00
|
|
|
output['show_controls'] = show_controls
|
2024-01-09 04:20:10 -08:00
|
|
|
output['dark_theme'] = True if theme_state == 'dark' else False
|
2025-06-08 01:58:02 -03:00
|
|
|
output.pop('instruction_template_str')
|
2025-06-08 22:14:56 -07:00
|
|
|
output.pop('truncation_length')
|
2023-08-14 11:46:07 -03:00
|
|
|
|
2025-06-15 15:53:16 -07:00
|
|
|
# Handle extensions and extension parameters
|
2025-06-11 07:39:49 -07:00
|
|
|
if manual_save:
|
2025-06-15 15:53:16 -07:00
|
|
|
# Save current extensions and their parameter values
|
2025-06-11 07:39:49 -07:00
|
|
|
output['default_extensions'] = extensions_list
|
2025-06-15 15:53:16 -07:00
|
|
|
|
|
|
|
|
for extension_name in extensions_list:
|
|
|
|
|
extension = getattr(extensions, extension_name, None)
|
|
|
|
|
if extension:
|
|
|
|
|
extension = extension.script
|
|
|
|
|
if hasattr(extension, 'params'):
|
|
|
|
|
params = getattr(extension, 'params')
|
|
|
|
|
for param in params:
|
|
|
|
|
_id = f"{extension_name}-{param}"
|
|
|
|
|
# Only save if different from default value
|
|
|
|
|
if param not in shared.default_settings or params[param] != shared.default_settings[param]:
|
|
|
|
|
output[_id] = params[param]
|
2025-06-11 07:39:49 -07:00
|
|
|
else:
|
2025-06-15 15:53:16 -07:00
|
|
|
# Preserve existing extensions and extension parameters during autosave
|
2025-06-11 07:39:49 -07:00
|
|
|
settings_path = Path('user_data') / 'settings.yaml'
|
|
|
|
|
if settings_path.exists():
|
|
|
|
|
try:
|
|
|
|
|
with open(settings_path, 'r', encoding='utf-8') as f:
|
|
|
|
|
existing_settings = yaml.safe_load(f.read()) or {}
|
2025-06-11 07:47:25 -07:00
|
|
|
|
2025-06-15 15:53:16 -07:00
|
|
|
# Preserve default_extensions
|
2025-06-11 07:39:49 -07:00
|
|
|
if 'default_extensions' in existing_settings:
|
|
|
|
|
output['default_extensions'] = existing_settings['default_extensions']
|
2025-06-15 15:53:16 -07:00
|
|
|
|
|
|
|
|
# Preserve extension parameter values
|
|
|
|
|
for key, value in existing_settings.items():
|
|
|
|
|
if any(key.startswith(f"{ext_name}-") for ext_name in extensions_module.available_extensions):
|
|
|
|
|
output[key] = value
|
2025-06-11 07:39:49 -07:00
|
|
|
except Exception:
|
|
|
|
|
pass # If we can't read the file, just don't modify extensions
|
|
|
|
|
|
2024-01-09 18:59:04 -08:00
|
|
|
# Do not save unchanged settings
|
|
|
|
|
for key in list(output.keys()):
|
|
|
|
|
if key in shared.default_settings and output[key] == shared.default_settings[key]:
|
|
|
|
|
output.pop(key)
|
|
|
|
|
|
2024-07-21 10:45:01 -07:00
|
|
|
return yaml.dump(output, sort_keys=False, width=float("inf"), allow_unicode=True)
|
2023-08-14 11:46:07 -03:00
|
|
|
|
|
|
|
|
|
2025-06-07 22:46:52 -03:00
|
|
|
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()
|
|
|
|
|
|
2025-06-08 01:58:02 -03:00
|
|
|
_auto_save_timer = threading.Timer(1.0, _perform_debounced_save)
|
2025-06-07 22:46:52 -03:00
|
|
|
_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:
|
2025-06-11 07:39:49 -07:00
|
|
|
contents = save_settings(_last_interface_state, _last_preset, _last_extensions, _last_show_controls, _last_theme_state, manual_save=False)
|
2025-06-07 22:46:52 -03:00
|
|
|
settings_path = Path('user_data') / 'settings.yaml'
|
2025-06-17 07:11:59 -07:00
|
|
|
settings_path.parent.mkdir(exist_ok=True)
|
2025-06-07 22:46:52 -03:00
|
|
|
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',
|
2025-06-08 01:58:02 -03:00
|
|
|
'name2',
|
|
|
|
|
'context',
|
|
|
|
|
'greeting',
|
2025-06-07 22:46:52 -03:00
|
|
|
'user_bio',
|
|
|
|
|
'custom_system_message',
|
|
|
|
|
'chat_template_str',
|
|
|
|
|
|
2025-06-08 01:58:02 -03:00
|
|
|
# Parameters tab (ui_parameters.py) - Generation parameters
|
2025-06-07 22:46:52 -03:00
|
|
|
'preset_menu',
|
2025-06-08 01:58:02 -03:00
|
|
|
'temperature',
|
|
|
|
|
'dynatemp_low',
|
|
|
|
|
'dynatemp_high',
|
|
|
|
|
'dynatemp_exponent',
|
|
|
|
|
'smoothing_factor',
|
|
|
|
|
'smoothing_curve',
|
|
|
|
|
'min_p',
|
|
|
|
|
'top_p',
|
|
|
|
|
'top_k',
|
|
|
|
|
'typical_p',
|
|
|
|
|
'xtc_threshold',
|
|
|
|
|
'xtc_probability',
|
|
|
|
|
'epsilon_cutoff',
|
|
|
|
|
'eta_cutoff',
|
|
|
|
|
'tfs',
|
|
|
|
|
'top_a',
|
|
|
|
|
'top_n_sigma',
|
|
|
|
|
'dry_multiplier',
|
|
|
|
|
'dry_allowed_length',
|
|
|
|
|
'dry_base',
|
|
|
|
|
'repetition_penalty',
|
|
|
|
|
'frequency_penalty',
|
|
|
|
|
'presence_penalty',
|
|
|
|
|
'encoder_repetition_penalty',
|
|
|
|
|
'no_repeat_ngram_size',
|
|
|
|
|
'repetition_penalty_range',
|
|
|
|
|
'penalty_alpha',
|
|
|
|
|
'guidance_scale',
|
|
|
|
|
'mirostat_mode',
|
|
|
|
|
'mirostat_tau',
|
|
|
|
|
'mirostat_eta',
|
2025-06-07 22:46:52 -03:00
|
|
|
'max_new_tokens',
|
|
|
|
|
'prompt_lookup_num_tokens',
|
|
|
|
|
'max_tokens_second',
|
2025-06-08 01:58:02 -03:00
|
|
|
'do_sample',
|
|
|
|
|
'dynamic_temperature',
|
|
|
|
|
'temperature_last',
|
2025-06-07 22:46:52 -03:00
|
|
|
'auto_max_new_tokens',
|
|
|
|
|
'ban_eos_token',
|
|
|
|
|
'add_bos_token',
|
|
|
|
|
'enable_thinking',
|
2025-08-05 15:19:11 -07:00
|
|
|
'reasoning_effort',
|
2025-06-07 22:46:52 -03:00
|
|
|
'skip_special_tokens',
|
|
|
|
|
'stream',
|
|
|
|
|
'static_cache',
|
2025-06-08 01:58:02 -03:00
|
|
|
'truncation_length',
|
2025-06-07 22:46:52 -03:00
|
|
|
'seed',
|
2025-06-08 01:58:02 -03:00
|
|
|
'sampler_priority',
|
2025-06-07 22:46:52 -03:00
|
|
|
'custom_stopping_strings',
|
|
|
|
|
'custom_token_bans',
|
|
|
|
|
'negative_prompt',
|
2025-06-08 01:58:02 -03:00
|
|
|
'dry_sequence_breakers',
|
|
|
|
|
'grammar_string',
|
2025-06-07 22:46:52 -03:00
|
|
|
|
|
|
|
|
# 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',
|
2025-06-16 13:19:29 -03:00
|
|
|
'show_two_notebook_columns',
|
2025-06-12 16:54:43 -07:00
|
|
|
'paste_to_attachment',
|
|
|
|
|
'include_past_attachments'
|
2025-06-07 22:46:52 -03:00
|
|
|
]
|
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
|
|
|
|
|
|
2023-09-26 05:44:04 -07:00
|
|
|
def create_refresh_button(refresh_component, refresh_method, refreshed_args, elem_class, interactive=True):
|
2023-07-25 15:49:04 -07:00
|
|
|
"""
|
|
|
|
|
Copied from https://github.com/AUTOMATIC1111/stable-diffusion-webui
|
|
|
|
|
"""
|
2023-01-22 00:02:46 -03:00
|
|
|
def refresh():
|
|
|
|
|
refresh_method()
|
|
|
|
|
args = refreshed_args() if callable(refreshed_args) else refreshed_args
|
|
|
|
|
|
|
|
|
|
return gr.update(**(args or {}))
|
|
|
|
|
|
2023-10-10 22:20:49 -03:00
|
|
|
refresh_button = gr.Button(refresh_symbol, elem_classes=elem_class, interactive=interactive)
|
2023-01-22 00:02:46 -03:00
|
|
|
refresh_button.click(
|
2024-01-08 17:49:54 -08:00
|
|
|
fn=lambda: {k: tuple(v) if type(k) is list else v for k, v in refresh().items()},
|
2023-01-22 00:02:46 -03:00
|
|
|
inputs=[],
|
|
|
|
|
outputs=[refresh_component]
|
|
|
|
|
)
|
2023-07-04 00:03:30 -03:00
|
|
|
|
2023-01-22 00:02:46 -03:00
|
|
|
return refresh_button
|