mirror of https://github.com/vladmandic/automatic
parent
d588ced2ef
commit
4e1c1a6844
|
|
@ -1 +1 @@
|
|||
Subproject commit bdc35c4731ee37e2191d52d3cf3ba6ccd37eecf8
|
||||
Subproject commit f287be148c8345913cba177982c4fb6e18ad70dc
|
||||
|
|
@ -1619,6 +1619,15 @@ def read_options():
|
|||
opts = json.loads(opts)
|
||||
except Exception as e:
|
||||
log.error(f'Error reading options file: {file} {e}')
|
||||
if os.path.isfile(args.secrets):
|
||||
with open(args.secrets, encoding="utf8") as file:
|
||||
try:
|
||||
secrets = json.load(file)
|
||||
if type(secrets) is str:
|
||||
secrets = json.loads(secrets)
|
||||
opts = opts | secrets
|
||||
except Exception as e:
|
||||
log.error(f"Error reading secrets file: {file} {e}")
|
||||
ts('options', t_start)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -272,7 +272,7 @@ def post_settings(request: dict):
|
|||
shared.opts.data['civitai_save_subfolder'] = save_subfolder
|
||||
if discard_hash_mismatch is not None:
|
||||
shared.opts.data['civitai_discard_hash_mismatch'] = discard_hash_mismatch
|
||||
shared.opts.save(shared.config_filename)
|
||||
shared.opts.save()
|
||||
return get_settings()
|
||||
|
||||
|
||||
|
|
@ -606,5 +606,3 @@ def register_api():
|
|||
# Legacy endpoints (backward compatibility)
|
||||
api.add_api_route("/sdapi/v1/civitai", legacy_get_civitai, methods=["GET"], response_model=list, tags=["Models"])
|
||||
api.add_api_route("/sdapi/v1/civitai", legacy_post_civitai, methods=["POST"], response_model=list, tags=["Models"])
|
||||
|
||||
log.debug('CivitAI API: registered endpoints')
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ def add_core_args(p):
|
|||
|
||||
def add_config_arg(p, data_dir):
|
||||
p.add_argument("--config", type=str, default=os.environ.get("SD_CONFIG", os.path.join(data_dir, 'config.json')), help="Use specific server configuration file, default: %(default)s")
|
||||
p.add_argument("--secrets", type=str, default=os.environ.get("SD_SECRETS", os.path.join(data_dir, 'secrets.json')), help="Use specific server secrets file, default: %(default)s")
|
||||
|
||||
|
||||
def add_compute_args(p):
|
||||
|
|
@ -42,9 +43,11 @@ def add_compute_args(p):
|
|||
p.add_argument("--no-half", default=env_flag("SD_NOHALF", False), action='store_true', help="Do not switch the model to 16-bit float, default: %(default)s")
|
||||
p.add_argument("--no-half-vae", default=env_flag("SD_NOHALFVAE", False), action='store_true', help="Do not switch VAE model to 16-bit float, default: %(default)s")
|
||||
|
||||
|
||||
def add_ui_args(p):
|
||||
p.add_argument('--theme', type=str, default=os.environ.get("SD_THEME", None), help='Override UI theme')
|
||||
p.add_argument('--locale', type=str, default=os.environ.get("SD_LOCALE", None), help='Override UI locale')
|
||||
p.add_argument("--enso", default=env_flag("SD_ENSO", False), action="store_true", help="Enable Enso frontend, default: %(default)s")
|
||||
|
||||
|
||||
def add_http_args(p):
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
from __future__ import annotations
|
||||
import os
|
||||
import sys
|
||||
import json
|
||||
import threading
|
||||
from typing import TYPE_CHECKING
|
||||
|
|
@ -16,55 +17,79 @@ if TYPE_CHECKING:
|
|||
|
||||
cmd_opts = cmd_args.parse_args()
|
||||
compatibility_opts = ['clip_skip', 'uni_pc_lower_order_final', 'uni_pc_order']
|
||||
secrets_pattern = ['_version', '_token', '_key', '_secret', '_password']
|
||||
|
||||
|
||||
class Options:
|
||||
data_labels: dict[str, OptionInfo | LegacyOption]
|
||||
data: dict[str, Any]
|
||||
secrets: dict[str, Any]
|
||||
typemap = {int: float}
|
||||
debug = os.environ.get('SD_CONFIG_DEBUG', None) is not None
|
||||
secrets_debug = os.environ.get("SD_SECRETS_DEBUG", None) is not None
|
||||
|
||||
def __init__(self, options_templates: dict[str, OptionInfo | LegacyOption] = None, restricted_opts: set[str] | None = None, *, filename = ''):
|
||||
def __init__(self, options_templates: dict[str, OptionInfo | LegacyOption] = None, restricted: set[str] | None = None, *, filename = '', secrets = ''):
|
||||
if options_templates is None:
|
||||
options_templates = {}
|
||||
if restricted_opts is None:
|
||||
restricted_opts = set()
|
||||
if restricted is None:
|
||||
restricted = set()
|
||||
super().__setattr__('data_labels', options_templates)
|
||||
super().__setattr__('data', {k: v.default for k, v in options_templates.items()})
|
||||
super().__setattr__('secrets', {})
|
||||
self.filename: str = filename or cmd_opts.config
|
||||
self.restricted_opts = restricted_opts
|
||||
self.secretsfn: str = secrets or cmd_opts.secrets
|
||||
self.restricted: set[str] = restricted
|
||||
self.legacy = [k for k, v in options_templates.items() if isinstance(v, LegacyOption)]
|
||||
self.load()
|
||||
|
||||
def __setattr__(self, key, value): # pylint: disable=inconsistent-return-statements
|
||||
if key in self.data or key in self.data_labels:
|
||||
if cmd_opts.freeze:
|
||||
log.warning(f'Settings are frozen: {key}')
|
||||
return
|
||||
if cmd_opts.hide_ui_dir_config and key in self.restricted_opts:
|
||||
log.warning(f'Settings key is restricted: {key}')
|
||||
return
|
||||
if self.debug:
|
||||
log.trace(f'Settings set: {key}={value}')
|
||||
if key in self.legacy:
|
||||
log.warning(f'Settings set: {key}={value} legacy')
|
||||
self.data[key] = value
|
||||
return
|
||||
return super().__setattr__(key, value) # pylint: disable=super-with-arguments
|
||||
def __getattr__(self, item):
|
||||
if item == 'secrets':
|
||||
return super().__getattribute__('secrets')
|
||||
if item == 'data':
|
||||
return super().__getattribute__('data')
|
||||
if item in self.secrets:
|
||||
if self.secrets_debug:
|
||||
fn = f"{sys._getframe(2).f_code.co_name}:{sys._getframe(1).f_code.co_name}" # pylint: disable=protected-access
|
||||
log.trace(f"Secret: get={item} fn={fn}")
|
||||
return self.secrets[item]
|
||||
if item in self.data:
|
||||
return self.data[item]
|
||||
if item in self.data_labels:
|
||||
return self.data_labels[item].default
|
||||
return super().__getattribute__(item) # pylint: disable=super-with-arguments
|
||||
|
||||
def get(self, item):
|
||||
if item in self.secrets:
|
||||
if self.secrets_debug:
|
||||
fn = f'{sys._getframe(2).f_code.co_name}:{sys._getframe(1).f_code.co_name}' # pylint: disable=protected-access
|
||||
log.trace(f"Secret: get={item} fn={fn}")
|
||||
return self.secrets[item]
|
||||
if item in self.data:
|
||||
return self.data[item]
|
||||
if item in self.data_labels:
|
||||
return self.data_labels[item].default
|
||||
return super().__getattribute__(item) # pylint: disable=super-with-arguments
|
||||
return super().__getattribute__(item) # pylint: disable=super-with-arguments
|
||||
|
||||
def __getattr__(self, item):
|
||||
if item in self.data:
|
||||
return self.data[item]
|
||||
if item in self.data_labels:
|
||||
return self.data_labels[item].default
|
||||
return super().__getattribute__(item) # pylint: disable=super-with-arguments
|
||||
def __setattr__(self, key, value): # pylint: disable=inconsistent-return-statements
|
||||
if (key in self.data_labels) or (key in self.data) or (key in self.secrets):
|
||||
if cmd_opts.freeze:
|
||||
log.warning(f"Settings are frozen: {key}")
|
||||
return
|
||||
if cmd_opts.hide_ui_dir_config and key in self.restricted:
|
||||
log.warning(f"Settings key is restricted: {key}")
|
||||
return
|
||||
if self.debug:
|
||||
log.trace(f"Settings set: {key}={value}")
|
||||
if key in self.legacy:
|
||||
log.warning(f"Settings set: {key}={value} legacy")
|
||||
if any(key.endswith(pattern) for pattern in secrets_pattern):
|
||||
if self.secrets_debug:
|
||||
log.trace(f"Secret: set={key}")
|
||||
self.secrets[key] = value
|
||||
else:
|
||||
self.data[key] = value
|
||||
return
|
||||
return super().__setattr__(key, value) # pylint: disable=super-with-arguments
|
||||
|
||||
def set(self, key, value):
|
||||
"""sets an option and calls its onchange callback, returning True if the option changed and False otherwise"""
|
||||
|
|
@ -102,28 +127,22 @@ class Options:
|
|||
components = [k for k, v in self.data_labels.items() if v.visible]
|
||||
return components
|
||||
|
||||
def save_atomic(self, filename=None, silent=False):
|
||||
def save_atomic(self, silent=False):
|
||||
if self.debug:
|
||||
log.debug(f'Settings: save settings="{self.filename}" override="{filename}" cmd="{cmd_opts.config}" cwd="{os.getcwd()}"')
|
||||
if filename is None:
|
||||
filename = self.filename
|
||||
filename = os.path.abspath(filename)
|
||||
log.debug(f'Settings: save settings="{self.filename}" secrets="{self.secretsfn}" cmd="{cmd_opts.config}" cwd="{os.getcwd()}"')
|
||||
filename = os.path.abspath(self.filename)
|
||||
secretsfn = os.path.abspath(self.secretsfn)
|
||||
if cmd_opts.freeze:
|
||||
log.warning(f'Setting: fn="{filename}" save disabled')
|
||||
return
|
||||
try:
|
||||
diff = {}
|
||||
unused_settings = []
|
||||
|
||||
# if self.debug:
|
||||
# log.debug('Settings: user')
|
||||
# for k, v in self.data.items():
|
||||
# log.trace(f' Config: item={k} value={v} default={self.data_labels[k].default if k in self.data_labels else None}')
|
||||
|
||||
if self.debug:
|
||||
log.debug(f'Settings: total={len(self.data.keys())} known={len(self.data_labels.keys())}')
|
||||
log.debug(f'Settings: total={len(self.data.keys())} secrets={len(self.secrets.keys())} known={len(self.data_labels.keys())}')
|
||||
|
||||
for k, v in self.data.items():
|
||||
all_options = self.data | self.secrets
|
||||
diff = {}
|
||||
for k, v in all_options.items():
|
||||
if k in self.data_labels:
|
||||
default = self.data_labels[k].default
|
||||
if isinstance(v, list):
|
||||
|
|
@ -142,16 +161,24 @@ class Options:
|
|||
unused_settings.append(k)
|
||||
if self.debug:
|
||||
log.trace(f'Settings unknown: {k}={v}')
|
||||
writefile(diff, filename, silent=silent)
|
||||
options = {}
|
||||
secrets = {}
|
||||
for k, v in diff.items():
|
||||
if any(k.endswith(pattern) for pattern in secrets_pattern):
|
||||
secrets[k] = v
|
||||
else:
|
||||
options[k] = v
|
||||
writefile(options, filename, silent=silent)
|
||||
writefile(secrets, secretsfn, silent=silent)
|
||||
if self.debug:
|
||||
log.trace(f'Settings save: count={len(diff.keys())} {diff}')
|
||||
if len(unused_settings) > 0:
|
||||
log.debug(f"Settings: unused={unused_settings}")
|
||||
except Exception as err:
|
||||
log.error(f'Settings: fn="{filename}" {err}')
|
||||
log.error(f'Settings: config="{filename}" secrets="{secretsfn}" {err}')
|
||||
|
||||
def save(self, filename=None, silent=False):
|
||||
threading.Thread(target=self.save_atomic, args=(filename, silent)).start()
|
||||
def save(self, silent=False):
|
||||
threading.Thread(target=self.save_atomic, args=(silent,)).start()
|
||||
|
||||
def same_type(self, x, y):
|
||||
if x is None or y is None:
|
||||
|
|
@ -160,15 +187,15 @@ class Options:
|
|||
type_y = self.typemap.get(type(y), type(y))
|
||||
return type_x == type_y
|
||||
|
||||
def load(self, filename=None):
|
||||
if filename is None:
|
||||
filename = self.filename
|
||||
filename = os.path.abspath(filename)
|
||||
def load(self):
|
||||
filename = os.path.abspath(self.filename)
|
||||
secretsfn = os.path.abspath(self.secretsfn)
|
||||
if not os.path.isfile(filename):
|
||||
log.debug(f'Settings: fn="{filename}" created')
|
||||
self.save(filename)
|
||||
log.debug(f'Settings: config="{filename}" secrets="{secretsfn}" created')
|
||||
self.save()
|
||||
return
|
||||
self.data = readfile(filename, lock=True, as_type="dict")
|
||||
self.secrets = readfile(secretsfn, lock=True, as_type="dict")
|
||||
if self.data.get('quicksettings') is not None and self.data.get('quicksettings_list') is None:
|
||||
self.data['quicksettings_list'] = [i.strip() for i in self.data.get('quicksettings', '').split(',')]
|
||||
unknown_settings = []
|
||||
|
|
|
|||
|
|
@ -162,7 +162,8 @@ from modules.shared_legacy import get_legacy_options
|
|||
options_templates.update(get_legacy_options())
|
||||
from modules.options_handler import Options
|
||||
config_filename = cmd_opts.config
|
||||
opts = Options(options_templates, restricted_opts, filename=config_filename)
|
||||
secrets_filename = cmd_opts.secrets
|
||||
opts = Options(options_templates, restricted=restricted_opts, filename=config_filename, secrets=secrets_filename)
|
||||
cmd_opts = cmd_args.settings_args(opts, cmd_opts)
|
||||
cmd_opts = cmd_args.override_args(opts, cmd_opts)
|
||||
if cmd_opts.locale is not None:
|
||||
|
|
|
|||
Loading…
Reference in New Issue