mirror of
https://github.com/willmiao/ComfyUI-Lora-Manager.git
synced 2026-03-25 07:05:43 -03:00
Merge pull request #467 from willmiao/codex/migrate-frontend-settings-to-backend
feat(settings): centralize settings loading and snake_case keys
This commit is contained in:
@@ -179,7 +179,7 @@ class MiscRoutes:
|
|||||||
# Define keys that should be synced from backend to frontend
|
# Define keys that should be synced from backend to frontend
|
||||||
sync_keys = [
|
sync_keys = [
|
||||||
'civitai_api_key',
|
'civitai_api_key',
|
||||||
'default_lora_root',
|
'default_lora_root',
|
||||||
'default_checkpoint_root',
|
'default_checkpoint_root',
|
||||||
'default_embedding_root',
|
'default_embedding_root',
|
||||||
'base_model_path_mappings',
|
'base_model_path_mappings',
|
||||||
@@ -193,8 +193,15 @@ class MiscRoutes:
|
|||||||
'proxy_username',
|
'proxy_username',
|
||||||
'proxy_password',
|
'proxy_password',
|
||||||
'example_images_path',
|
'example_images_path',
|
||||||
'optimizeExampleImages',
|
'optimize_example_images',
|
||||||
'autoDownloadExampleImages'
|
'auto_download_example_images',
|
||||||
|
'blur_mature_content',
|
||||||
|
'autoplay_on_hover',
|
||||||
|
'display_density',
|
||||||
|
'card_info_display',
|
||||||
|
'include_trigger_words',
|
||||||
|
'show_only_sfw',
|
||||||
|
'compact_mode'
|
||||||
]
|
]
|
||||||
|
|
||||||
# Build response with only the keys that should be synced
|
# Build response with only the keys that should be synced
|
||||||
|
|||||||
@@ -5,10 +5,41 @@ from typing import Any, Dict
|
|||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
DEFAULT_SETTINGS: Dict[str, Any] = {
|
||||||
|
"civitai_api_key": "",
|
||||||
|
"language": "en",
|
||||||
|
"show_only_sfw": False,
|
||||||
|
"enable_metadata_archive_db": False,
|
||||||
|
"proxy_enabled": False,
|
||||||
|
"proxy_host": "",
|
||||||
|
"proxy_port": "",
|
||||||
|
"proxy_username": "",
|
||||||
|
"proxy_password": "",
|
||||||
|
"proxy_type": "http",
|
||||||
|
"default_lora_root": "",
|
||||||
|
"default_checkpoint_root": "",
|
||||||
|
"default_embedding_root": "",
|
||||||
|
"base_model_path_mappings": {},
|
||||||
|
"download_path_templates": {},
|
||||||
|
"example_images_path": "",
|
||||||
|
"optimize_example_images": True,
|
||||||
|
"auto_download_example_images": False,
|
||||||
|
"blur_mature_content": True,
|
||||||
|
"autoplay_on_hover": False,
|
||||||
|
"display_density": "default",
|
||||||
|
"card_info_display": "always",
|
||||||
|
"include_trigger_words": False,
|
||||||
|
"compact_mode": False,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class SettingsManager:
|
class SettingsManager:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.settings_file = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))), 'settings.json')
|
self.settings_file = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))), 'settings.json')
|
||||||
self.settings = self._load_settings()
|
self.settings = self._load_settings()
|
||||||
|
self._migrate_setting_keys()
|
||||||
|
self._ensure_default_settings()
|
||||||
self._migrate_download_path_template()
|
self._migrate_download_path_template()
|
||||||
self._auto_set_default_roots()
|
self._auto_set_default_roots()
|
||||||
self._check_environment_variables()
|
self._check_environment_variables()
|
||||||
@@ -23,11 +54,49 @@ class SettingsManager:
|
|||||||
logger.error(f"Error loading settings: {e}")
|
logger.error(f"Error loading settings: {e}")
|
||||||
return self._get_default_settings()
|
return self._get_default_settings()
|
||||||
|
|
||||||
|
def _ensure_default_settings(self) -> None:
|
||||||
|
"""Ensure all default settings keys exist"""
|
||||||
|
updated = False
|
||||||
|
for key, value in self._get_default_settings().items():
|
||||||
|
if key not in self.settings:
|
||||||
|
if isinstance(value, dict):
|
||||||
|
self.settings[key] = value.copy()
|
||||||
|
else:
|
||||||
|
self.settings[key] = value
|
||||||
|
updated = True
|
||||||
|
if updated:
|
||||||
|
self._save_settings()
|
||||||
|
|
||||||
|
def _migrate_setting_keys(self) -> None:
|
||||||
|
"""Migrate legacy camelCase setting keys to snake_case"""
|
||||||
|
key_migrations = {
|
||||||
|
'optimizeExampleImages': 'optimize_example_images',
|
||||||
|
'autoDownloadExampleImages': 'auto_download_example_images',
|
||||||
|
'blurMatureContent': 'blur_mature_content',
|
||||||
|
'autoplayOnHover': 'autoplay_on_hover',
|
||||||
|
'displayDensity': 'display_density',
|
||||||
|
'cardInfoDisplay': 'card_info_display',
|
||||||
|
'includeTriggerWords': 'include_trigger_words',
|
||||||
|
'compactMode': 'compact_mode',
|
||||||
|
}
|
||||||
|
|
||||||
|
updated = False
|
||||||
|
for old_key, new_key in key_migrations.items():
|
||||||
|
if old_key in self.settings:
|
||||||
|
if new_key not in self.settings:
|
||||||
|
self.settings[new_key] = self.settings[old_key]
|
||||||
|
del self.settings[old_key]
|
||||||
|
updated = True
|
||||||
|
|
||||||
|
if updated:
|
||||||
|
logger.info("Migrated legacy setting keys to snake_case")
|
||||||
|
self._save_settings()
|
||||||
|
|
||||||
def _migrate_download_path_template(self):
|
def _migrate_download_path_template(self):
|
||||||
"""Migrate old download_path_template to new download_path_templates"""
|
"""Migrate old download_path_template to new download_path_templates"""
|
||||||
old_template = self.settings.get('download_path_template')
|
old_template = self.settings.get('download_path_template')
|
||||||
templates = self.settings.get('download_path_templates')
|
templates = self.settings.get('download_path_templates')
|
||||||
|
|
||||||
# If old template exists and new templates don't exist, migrate
|
# If old template exists and new templates don't exist, migrate
|
||||||
if old_template is not None and not templates:
|
if old_template is not None and not templates:
|
||||||
logger.info("Migrating download_path_template to download_path_templates")
|
logger.info("Migrating download_path_template to download_path_templates")
|
||||||
@@ -78,18 +147,11 @@ class SettingsManager:
|
|||||||
|
|
||||||
def _get_default_settings(self) -> Dict[str, Any]:
|
def _get_default_settings(self) -> Dict[str, Any]:
|
||||||
"""Return default settings"""
|
"""Return default settings"""
|
||||||
return {
|
defaults = DEFAULT_SETTINGS.copy()
|
||||||
"civitai_api_key": "",
|
# Ensure nested dicts are independent copies
|
||||||
"language": "en",
|
defaults['base_model_path_mappings'] = {}
|
||||||
"show_only_sfw": False, # Show only SFW content
|
defaults['download_path_templates'] = {}
|
||||||
"enable_metadata_archive_db": False, # Enable metadata archive database
|
return defaults
|
||||||
"proxy_enabled": False, # Enable app-level proxy
|
|
||||||
"proxy_host": "", # Proxy host
|
|
||||||
"proxy_port": "", # Proxy port
|
|
||||||
"proxy_username": "", # Proxy username (optional)
|
|
||||||
"proxy_password": "", # Proxy password (optional)
|
|
||||||
"proxy_type": "http" # Proxy type: http, https, socks4, socks5
|
|
||||||
}
|
|
||||||
|
|
||||||
def get(self, key: str, default: Any = None) -> Any:
|
def get(self, key: str, default: Any = None) -> Any:
|
||||||
"""Get setting value"""
|
"""Get setting value"""
|
||||||
|
|||||||
@@ -945,7 +945,7 @@ export class BaseModelApiClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Determine optimize setting
|
// Determine optimize setting
|
||||||
const optimize = state.global?.settings?.optimizeExampleImages ?? true;
|
const optimize = state.global?.settings?.optimize_example_images ?? true;
|
||||||
|
|
||||||
// Make the API request to start the download process
|
// Make the API request to start the download process
|
||||||
const response = await fetch(DOWNLOAD_ENDPOINTS.exampleImages, {
|
const response = await fetch(DOWNLOAD_ENDPOINTS.exampleImages, {
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ class RecipeCard {
|
|||||||
|
|
||||||
// NSFW blur logic - similar to LoraCard
|
// NSFW blur logic - similar to LoraCard
|
||||||
const nsfwLevel = this.recipe.preview_nsfw_level !== undefined ? this.recipe.preview_nsfw_level : 0;
|
const nsfwLevel = this.recipe.preview_nsfw_level !== undefined ? this.recipe.preview_nsfw_level : 0;
|
||||||
const shouldBlur = state.settings.blurMatureContent && nsfwLevel > NSFW_LEVELS.PG13;
|
const shouldBlur = state.settings.blur_mature_content && nsfwLevel > NSFW_LEVELS.PG13;
|
||||||
|
|
||||||
if (shouldBlur) {
|
if (shouldBlur) {
|
||||||
card.classList.add('nsfw-content');
|
card.classList.add('nsfw-content');
|
||||||
|
|||||||
@@ -405,7 +405,7 @@ export function createModelCard(model, modelType) {
|
|||||||
card.dataset.nsfwLevel = nsfwLevel;
|
card.dataset.nsfwLevel = nsfwLevel;
|
||||||
|
|
||||||
// Determine if the preview should be blurred based on NSFW level and user settings
|
// Determine if the preview should be blurred based on NSFW level and user settings
|
||||||
const shouldBlur = state.settings.blurMatureContent && nsfwLevel > NSFW_LEVELS.PG13;
|
const shouldBlur = state.settings.blur_mature_content && nsfwLevel > NSFW_LEVELS.PG13;
|
||||||
if (shouldBlur) {
|
if (shouldBlur) {
|
||||||
card.classList.add('nsfw-content');
|
card.classList.add('nsfw-content');
|
||||||
}
|
}
|
||||||
@@ -433,7 +433,7 @@ export function createModelCard(model, modelType) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check if autoplayOnHover is enabled for video previews
|
// Check if autoplayOnHover is enabled for video previews
|
||||||
const autoplayOnHover = state.global?.settings?.autoplayOnHover || false;
|
const autoplayOnHover = state.global?.settings?.autoplay_on_hover || false;
|
||||||
const isVideo = previewUrl.endsWith('.mp4');
|
const isVideo = previewUrl.endsWith('.mp4');
|
||||||
const videoAttrs = autoplayOnHover ? 'controls muted loop' : 'controls autoplay muted loop';
|
const videoAttrs = autoplayOnHover ? 'controls muted loop' : 'controls autoplay muted loop';
|
||||||
|
|
||||||
|
|||||||
@@ -155,7 +155,7 @@ function renderMediaItem(img, index, exampleFiles) {
|
|||||||
|
|
||||||
// Check if media should be blurred
|
// Check if media should be blurred
|
||||||
const nsfwLevel = img.nsfwLevel !== undefined ? img.nsfwLevel : 0;
|
const nsfwLevel = img.nsfwLevel !== undefined ? img.nsfwLevel : 0;
|
||||||
const shouldBlur = state.settings.blurMatureContent && nsfwLevel > NSFW_LEVELS.PG13;
|
const shouldBlur = state.settings.blur_mature_content && nsfwLevel > NSFW_LEVELS.PG13;
|
||||||
|
|
||||||
// Determine NSFW warning text based on level
|
// Determine NSFW warning text based on level
|
||||||
let nsfwText = "Mature Content";
|
let nsfwText = "Mature Content";
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ export class AppCore {
|
|||||||
// Initialize the help manager
|
// Initialize the help manager
|
||||||
helpManager.initialize();
|
helpManager.initialize();
|
||||||
|
|
||||||
const cardInfoDisplay = state.global.settings.cardInfoDisplay || 'always';
|
const cardInfoDisplay = state.global.settings.card_info_display || 'always';
|
||||||
document.body.classList.toggle('hover-reveal', cardInfoDisplay === 'hover');
|
document.body.classList.toggle('hover-reveal', cardInfoDisplay === 'hover');
|
||||||
|
|
||||||
initializeEventManagement();
|
initializeEventManagement();
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { state } from '../state/index.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internationalization (i18n) system for LoRA Manager
|
* Internationalization (i18n) system for LoRA Manager
|
||||||
* Uses user-selected language from settings with fallback to English
|
* Uses user-selected language from settings with fallback to English
|
||||||
@@ -123,26 +125,12 @@ class I18nManager {
|
|||||||
* @returns {string} Language code
|
* @returns {string} Language code
|
||||||
*/
|
*/
|
||||||
getLanguageFromSettings() {
|
getLanguageFromSettings() {
|
||||||
// Check localStorage for user-selected language
|
const language = state?.global?.settings?.language;
|
||||||
const STORAGE_PREFIX = 'lora_manager_';
|
|
||||||
let userLanguage = null;
|
if (language && this.availableLocales[language]) {
|
||||||
|
return language;
|
||||||
try {
|
|
||||||
const settings = localStorage.getItem(STORAGE_PREFIX + 'settings');
|
|
||||||
if (settings) {
|
|
||||||
const parsedSettings = JSON.parse(settings);
|
|
||||||
userLanguage = parsedSettings.language;
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
console.warn('Failed to parse settings from localStorage:', e);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If user has selected a language, use it
|
|
||||||
if (userLanguage && this.availableLocales[userLanguage]) {
|
|
||||||
return userLanguage;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fallback to English
|
|
||||||
return 'en';
|
return 'en';
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -165,18 +153,10 @@ class I18nManager {
|
|||||||
this.readyPromise = this.initializeWithLocale(languageCode);
|
this.readyPromise = this.initializeWithLocale(languageCode);
|
||||||
await this.readyPromise;
|
await this.readyPromise;
|
||||||
|
|
||||||
// Save to localStorage
|
if (state?.global?.settings) {
|
||||||
const STORAGE_PREFIX = 'lora_manager_';
|
state.global.settings.language = languageCode;
|
||||||
const currentSettings = localStorage.getItem(STORAGE_PREFIX + 'settings');
|
|
||||||
let settings = {};
|
|
||||||
|
|
||||||
if (currentSettings) {
|
|
||||||
settings = JSON.parse(currentSettings);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
settings.language = languageCode;
|
|
||||||
localStorage.setItem(STORAGE_PREFIX + 'settings', JSON.stringify(settings));
|
|
||||||
|
|
||||||
console.log(`Language changed to: ${languageCode}`);
|
console.log(`Language changed to: ${languageCode}`);
|
||||||
|
|
||||||
// Dispatch event to notify components of language change
|
// Dispatch event to notify components of language change
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ export class ExampleImagesManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Setup auto download if enabled
|
// Setup auto download if enabled
|
||||||
if (state.global.settings.autoDownloadExampleImages) {
|
if (state.global.settings.auto_download_example_images) {
|
||||||
this.setupAutoDownload();
|
this.setupAutoDownload();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,7 +106,7 @@ export class ExampleImagesManager {
|
|||||||
showToast('toast.exampleImages.pathUpdateFailed', { message: error.message }, 'error');
|
showToast('toast.exampleImages.pathUpdateFailed', { message: error.message }, 'error');
|
||||||
}
|
}
|
||||||
// Setup or clear auto download based on path availability
|
// Setup or clear auto download based on path availability
|
||||||
if (state.global.settings.autoDownloadExampleImages) {
|
if (state.global.settings.auto_download_example_images) {
|
||||||
if (hasPath) {
|
if (hasPath) {
|
||||||
this.setupAutoDownload();
|
this.setupAutoDownload();
|
||||||
} else {
|
} else {
|
||||||
@@ -225,7 +225,7 @@ export class ExampleImagesManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const optimize = state.global.settings.optimizeExampleImages;
|
const optimize = state.global.settings.optimize_example_images;
|
||||||
|
|
||||||
const response = await fetch('/api/lm/download-example-images', {
|
const response = await fetch('/api/lm/download-example-images', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
@@ -677,7 +677,7 @@ export class ExampleImagesManager {
|
|||||||
|
|
||||||
canAutoDownload() {
|
canAutoDownload() {
|
||||||
// Check if auto download is enabled
|
// Check if auto download is enabled
|
||||||
if (!state.global.settings.autoDownloadExampleImages) {
|
if (!state.global.settings.auto_download_example_images) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -713,7 +713,7 @@ export class ExampleImagesManager {
|
|||||||
try {
|
try {
|
||||||
console.log('Performing auto download check...');
|
console.log('Performing auto download check...');
|
||||||
|
|
||||||
const optimize = state.global.settings.optimizeExampleImages;
|
const optimize = state.global.settings.optimize_example_images;
|
||||||
|
|
||||||
const response = await fetch('/api/lm/download-example-images', {
|
const response = await fetch('/api/lm/download-example-images', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
|
|||||||
@@ -182,9 +182,6 @@ export class OnboardingManager {
|
|||||||
// Update state
|
// Update state
|
||||||
state.global.settings.language = languageCode;
|
state.global.settings.language = languageCode;
|
||||||
|
|
||||||
// Save to localStorage
|
|
||||||
setStorageItem('settings', state.global.settings);
|
|
||||||
|
|
||||||
// Save to backend
|
// Save to backend
|
||||||
const response = await fetch('/api/lm/settings', {
|
const response = await fetch('/api/lm/settings', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import { modalManager } from './ModalManager.js';
|
import { modalManager } from './ModalManager.js';
|
||||||
import { showToast } from '../utils/uiHelpers.js';
|
import { showToast } from '../utils/uiHelpers.js';
|
||||||
import { state } from '../state/index.js';
|
import { state, createDefaultSettings } from '../state/index.js';
|
||||||
import { resetAndReload } from '../api/modelApiFactory.js';
|
import { resetAndReload } from '../api/modelApiFactory.js';
|
||||||
import { setStorageItem, getStorageItem } from '../utils/storageHelpers.js';
|
|
||||||
import { DOWNLOAD_PATH_TEMPLATES, MAPPABLE_BASE_MODELS, PATH_TEMPLATE_PLACEHOLDERS, DEFAULT_PATH_TEMPLATES } from '../utils/constants.js';
|
import { DOWNLOAD_PATH_TEMPLATES, MAPPABLE_BASE_MODELS, PATH_TEMPLATE_PLACEHOLDERS, DEFAULT_PATH_TEMPLATES } from '../utils/constants.js';
|
||||||
import { translate } from '../utils/i18nHelpers.js';
|
import { translate } from '../utils/i18nHelpers.js';
|
||||||
|
import { i18n } from '../i18n/index.js';
|
||||||
|
|
||||||
export class SettingsManager {
|
export class SettingsManager {
|
||||||
constructor() {
|
constructor() {
|
||||||
@@ -14,7 +14,9 @@ export class SettingsManager {
|
|||||||
|
|
||||||
// Add initialization to sync with modal state
|
// Add initialization to sync with modal state
|
||||||
this.currentPage = document.body.dataset.page || 'loras';
|
this.currentPage = document.body.dataset.page || 'loras';
|
||||||
|
|
||||||
|
this.backendSettingKeys = new Set(Object.keys(createDefaultSettings()));
|
||||||
|
|
||||||
// Start initialization but don't await here to avoid blocking constructor
|
// Start initialization but don't await here to avoid blocking constructor
|
||||||
this.initializationPromise = this.initializeSettings();
|
this.initializationPromise = this.initializeSettings();
|
||||||
|
|
||||||
@@ -29,177 +31,91 @@ export class SettingsManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async initializeSettings() {
|
async initializeSettings() {
|
||||||
// Load frontend-only settings from localStorage
|
// Reset to defaults before syncing
|
||||||
this.loadFrontendSettingsFromStorage();
|
state.global.settings = createDefaultSettings();
|
||||||
|
|
||||||
// Sync settings from backend to frontend
|
// Sync settings from backend to frontend
|
||||||
await this.syncSettingsFromBackend();
|
await this.syncSettingsFromBackend();
|
||||||
}
|
}
|
||||||
|
|
||||||
loadFrontendSettingsFromStorage() {
|
|
||||||
// Get saved settings from localStorage
|
|
||||||
const savedSettings = getStorageItem('settings');
|
|
||||||
|
|
||||||
// Frontend-only settings that should be stored in localStorage
|
|
||||||
const frontendOnlyKeys = [
|
|
||||||
'blurMatureContent',
|
|
||||||
'autoplayOnHover',
|
|
||||||
'displayDensity',
|
|
||||||
'cardInfoDisplay',
|
|
||||||
'includeTriggerWords'
|
|
||||||
];
|
|
||||||
|
|
||||||
// Apply saved frontend settings to state if available
|
|
||||||
if (savedSettings) {
|
|
||||||
const frontendSettings = {};
|
|
||||||
frontendOnlyKeys.forEach(key => {
|
|
||||||
if (savedSettings[key] !== undefined) {
|
|
||||||
frontendSettings[key] = savedSettings[key];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
state.global.settings = { ...state.global.settings, ...frontendSettings };
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize default values for frontend settings if they don't exist
|
|
||||||
if (state.global.settings.blurMatureContent === undefined) {
|
|
||||||
state.global.settings.blurMatureContent = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (state.global.settings.show_only_sfw === undefined) {
|
|
||||||
state.global.settings.show_only_sfw = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (state.global.settings.autoplayOnHover === undefined) {
|
|
||||||
state.global.settings.autoplayOnHover = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (state.global.settings.cardInfoDisplay === undefined) {
|
|
||||||
state.global.settings.cardInfoDisplay = 'always';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (state.global.settings.displayDensity === undefined) {
|
|
||||||
// Migrate legacy compactMode if it exists
|
|
||||||
if (state.global.settings.compactMode === true) {
|
|
||||||
state.global.settings.displayDensity = 'compact';
|
|
||||||
} else {
|
|
||||||
state.global.settings.displayDensity = 'default';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (state.global.settings.includeTriggerWords === undefined) {
|
|
||||||
state.global.settings.includeTriggerWords = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save updated frontend settings to localStorage
|
|
||||||
this.saveFrontendSettingsToStorage();
|
|
||||||
}
|
|
||||||
|
|
||||||
async syncSettingsFromBackend() {
|
async syncSettingsFromBackend() {
|
||||||
try {
|
try {
|
||||||
const response = await fetch('/api/lm/settings');
|
const response = await fetch('/api/lm/settings');
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
throw new Error(`HTTP error! status: ${response.status}`);
|
throw new Error(`HTTP error! status: ${response.status}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
if (data.success && data.settings) {
|
if (data.success && data.settings) {
|
||||||
// Merge backend settings with current state
|
state.global.settings = this.mergeSettingsWithDefaults(data.settings);
|
||||||
state.global.settings = { ...state.global.settings, ...data.settings };
|
|
||||||
|
|
||||||
// Set defaults for backend settings if they're null/undefined
|
|
||||||
this.setBackendSettingDefaults();
|
|
||||||
|
|
||||||
console.log('Settings synced from backend');
|
console.log('Settings synced from backend');
|
||||||
} else {
|
} else {
|
||||||
console.error('Failed to sync settings from backend:', data.error);
|
console.error('Failed to sync settings from backend:', data.error);
|
||||||
|
state.global.settings = this.mergeSettingsWithDefaults();
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to sync settings from backend:', error);
|
console.error('Failed to sync settings from backend:', error);
|
||||||
// Set defaults if backend sync fails
|
state.global.settings = this.mergeSettingsWithDefaults();
|
||||||
this.setBackendSettingDefaults();
|
}
|
||||||
|
|
||||||
|
await this.applyLanguageSetting();
|
||||||
|
this.applyFrontendSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
async applyLanguageSetting() {
|
||||||
|
const desiredLanguage = state?.global?.settings?.language;
|
||||||
|
|
||||||
|
if (!desiredLanguage) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (i18n.getCurrentLocale() !== desiredLanguage) {
|
||||||
|
await i18n.setLanguage(desiredLanguage);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.warn('Failed to apply language from settings:', error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setBackendSettingDefaults() {
|
mergeSettingsWithDefaults(backendSettings = {}) {
|
||||||
// Set defaults for backend settings
|
const defaults = createDefaultSettings();
|
||||||
const backendDefaults = {
|
const merged = { ...defaults, ...backendSettings };
|
||||||
civitai_api_key: '',
|
|
||||||
default_lora_root: '',
|
|
||||||
default_checkpoint_root: '',
|
|
||||||
default_embedding_root: '',
|
|
||||||
base_model_path_mappings: {},
|
|
||||||
download_path_templates: { ...DEFAULT_PATH_TEMPLATES },
|
|
||||||
enable_metadata_archive_db: false,
|
|
||||||
language: 'en',
|
|
||||||
show_only_sfw: false,
|
|
||||||
proxy_enabled: false,
|
|
||||||
proxy_type: 'http',
|
|
||||||
proxy_host: '',
|
|
||||||
proxy_port: '',
|
|
||||||
proxy_username: '',
|
|
||||||
proxy_password: '',
|
|
||||||
example_images_path: '',
|
|
||||||
optimizeExampleImages: true,
|
|
||||||
autoDownloadExampleImages: false
|
|
||||||
};
|
|
||||||
|
|
||||||
Object.keys(backendDefaults).forEach(key => {
|
const baseMappings = backendSettings?.base_model_path_mappings;
|
||||||
if (state.global.settings[key] === undefined || state.global.settings[key] === null) {
|
if (baseMappings && typeof baseMappings === 'object' && !Array.isArray(baseMappings)) {
|
||||||
state.global.settings[key] = backendDefaults[key];
|
merged.base_model_path_mappings = baseMappings;
|
||||||
|
} else {
|
||||||
|
merged.base_model_path_mappings = defaults.base_model_path_mappings;
|
||||||
|
}
|
||||||
|
|
||||||
|
let templates = backendSettings?.download_path_templates;
|
||||||
|
if (typeof templates === 'string') {
|
||||||
|
try {
|
||||||
|
const parsed = JSON.parse(templates);
|
||||||
|
if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
|
||||||
|
templates = parsed;
|
||||||
|
}
|
||||||
|
} catch (parseError) {
|
||||||
|
console.warn('Failed to parse download_path_templates string from backend, using defaults');
|
||||||
|
templates = null;
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
// Ensure all model types have templates
|
if (!templates || typeof templates !== 'object' || Array.isArray(templates)) {
|
||||||
Object.keys(DEFAULT_PATH_TEMPLATES).forEach(modelType => {
|
templates = {};
|
||||||
if (!state.global.settings.download_path_templates[modelType]) {
|
}
|
||||||
state.global.settings.download_path_templates[modelType] = DEFAULT_PATH_TEMPLATES[modelType];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
saveFrontendSettingsToStorage() {
|
merged.download_path_templates = { ...DEFAULT_PATH_TEMPLATES, ...templates };
|
||||||
// Save only frontend-specific settings to localStorage
|
|
||||||
const frontendOnlyKeys = [
|
|
||||||
'blurMatureContent',
|
|
||||||
'autoplayOnHover',
|
|
||||||
'displayDensity',
|
|
||||||
'cardInfoDisplay',
|
|
||||||
'includeTriggerWords'
|
|
||||||
];
|
|
||||||
|
|
||||||
const frontendSettings = {};
|
Object.keys(merged).forEach(key => this.backendSettingKeys.add(key));
|
||||||
frontendOnlyKeys.forEach(key => {
|
|
||||||
if (state.global.settings[key] !== undefined) {
|
|
||||||
frontendSettings[key] = state.global.settings[key];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
setStorageItem('settings', frontendSettings);
|
return merged;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper method to determine if a setting should be saved to backend
|
// Helper method to determine if a setting should be saved to backend
|
||||||
isBackendSetting(settingKey) {
|
isBackendSetting(settingKey) {
|
||||||
const backendKeys = [
|
return this.backendSettingKeys.has(settingKey);
|
||||||
'civitai_api_key',
|
|
||||||
'default_lora_root',
|
|
||||||
'default_checkpoint_root',
|
|
||||||
'default_embedding_root',
|
|
||||||
'base_model_path_mappings',
|
|
||||||
'download_path_templates',
|
|
||||||
'enable_metadata_archive_db',
|
|
||||||
'language',
|
|
||||||
'show_only_sfw',
|
|
||||||
'proxy_enabled',
|
|
||||||
'proxy_type',
|
|
||||||
'proxy_host',
|
|
||||||
'proxy_port',
|
|
||||||
'proxy_username',
|
|
||||||
'proxy_password',
|
|
||||||
'example_images_path',
|
|
||||||
'optimizeExampleImages',
|
|
||||||
'autoDownloadExampleImages'
|
|
||||||
];
|
|
||||||
return backendKeys.includes(settingKey);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper method to save setting based on whether it's frontend or backend
|
// Helper method to save setting based on whether it's frontend or backend
|
||||||
@@ -207,36 +123,35 @@ export class SettingsManager {
|
|||||||
// Update state
|
// Update state
|
||||||
state.global.settings[settingKey] = value;
|
state.global.settings[settingKey] = value;
|
||||||
|
|
||||||
if (this.isBackendSetting(settingKey)) {
|
if (!this.isBackendSetting(settingKey)) {
|
||||||
// Save to backend
|
return;
|
||||||
try {
|
}
|
||||||
const payload = {};
|
|
||||||
payload[settingKey] = value;
|
|
||||||
|
|
||||||
const response = await fetch('/api/lm/settings', {
|
// Save to backend
|
||||||
method: 'POST',
|
try {
|
||||||
headers: {
|
const payload = {};
|
||||||
'Content-Type': 'application/json',
|
payload[settingKey] = value;
|
||||||
},
|
|
||||||
body: JSON.stringify(payload)
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!response.ok) {
|
const response = await fetch('/api/lm/settings', {
|
||||||
throw new Error('Failed to save setting to backend');
|
method: 'POST',
|
||||||
}
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify(payload)
|
||||||
|
});
|
||||||
|
|
||||||
// Parse response and check for success
|
if (!response.ok) {
|
||||||
const data = await response.json();
|
throw new Error('Failed to save setting to backend');
|
||||||
if (data.success === false) {
|
|
||||||
throw new Error(data.error || 'Failed to save setting to backend');
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error(`Failed to save backend setting ${settingKey}:`, error);
|
|
||||||
throw error;
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// Save frontend settings to localStorage
|
// Parse response and check for success
|
||||||
this.saveFrontendSettingsToStorage();
|
const data = await response.json();
|
||||||
|
if (data.success === false) {
|
||||||
|
throw new Error(data.error || 'Failed to save setting to backend');
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Failed to save backend setting ${settingKey}:`, error);
|
||||||
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -298,43 +213,42 @@ export class SettingsManager {
|
|||||||
// Set frontend settings from state
|
// Set frontend settings from state
|
||||||
const blurMatureContentCheckbox = document.getElementById('blurMatureContent');
|
const blurMatureContentCheckbox = document.getElementById('blurMatureContent');
|
||||||
if (blurMatureContentCheckbox) {
|
if (blurMatureContentCheckbox) {
|
||||||
blurMatureContentCheckbox.checked = state.global.settings.blurMatureContent;
|
blurMatureContentCheckbox.checked = state.global.settings.blur_mature_content ?? true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const showOnlySFWCheckbox = document.getElementById('showOnlySFW');
|
const showOnlySFWCheckbox = document.getElementById('showOnlySFW');
|
||||||
if (showOnlySFWCheckbox) {
|
if (showOnlySFWCheckbox) {
|
||||||
// Sync with state (backend will set this via template)
|
showOnlySFWCheckbox.checked = state.global.settings.show_only_sfw ?? false;
|
||||||
state.global.settings.show_only_sfw = showOnlySFWCheckbox.checked;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set video autoplay on hover setting
|
// Set video autoplay on hover setting
|
||||||
const autoplayOnHoverCheckbox = document.getElementById('autoplayOnHover');
|
const autoplayOnHoverCheckbox = document.getElementById('autoplayOnHover');
|
||||||
if (autoplayOnHoverCheckbox) {
|
if (autoplayOnHoverCheckbox) {
|
||||||
autoplayOnHoverCheckbox.checked = state.global.settings.autoplayOnHover || false;
|
autoplayOnHoverCheckbox.checked = state.global.settings.autoplay_on_hover || false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set display density setting
|
// Set display density setting
|
||||||
const displayDensitySelect = document.getElementById('displayDensity');
|
const displayDensitySelect = document.getElementById('displayDensity');
|
||||||
if (displayDensitySelect) {
|
if (displayDensitySelect) {
|
||||||
displayDensitySelect.value = state.global.settings.displayDensity || 'default';
|
displayDensitySelect.value = state.global.settings.display_density || 'default';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set card info display setting
|
// Set card info display setting
|
||||||
const cardInfoDisplaySelect = document.getElementById('cardInfoDisplay');
|
const cardInfoDisplaySelect = document.getElementById('cardInfoDisplay');
|
||||||
if (cardInfoDisplaySelect) {
|
if (cardInfoDisplaySelect) {
|
||||||
cardInfoDisplaySelect.value = state.global.settings.cardInfoDisplay || 'always';
|
cardInfoDisplaySelect.value = state.global.settings.card_info_display || 'always';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set optimize example images setting
|
// Set optimize example images setting
|
||||||
const optimizeExampleImagesCheckbox = document.getElementById('optimizeExampleImages');
|
const optimizeExampleImagesCheckbox = document.getElementById('optimizeExampleImages');
|
||||||
if (optimizeExampleImagesCheckbox) {
|
if (optimizeExampleImagesCheckbox) {
|
||||||
optimizeExampleImagesCheckbox.checked = state.global.settings.optimizeExampleImages || false;
|
optimizeExampleImagesCheckbox.checked = state.global.settings.optimize_example_images ?? true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set auto download example images setting
|
// Set auto download example images setting
|
||||||
const autoDownloadExampleImagesCheckbox = document.getElementById('autoDownloadExampleImages');
|
const autoDownloadExampleImagesCheckbox = document.getElementById('autoDownloadExampleImages');
|
||||||
if (autoDownloadExampleImagesCheckbox) {
|
if (autoDownloadExampleImagesCheckbox) {
|
||||||
autoDownloadExampleImagesCheckbox.checked = state.global.settings.autoDownloadExampleImages || false;
|
autoDownloadExampleImagesCheckbox.checked = state.global.settings.auto_download_example_images || false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load download path templates
|
// Load download path templates
|
||||||
@@ -343,7 +257,7 @@ export class SettingsManager {
|
|||||||
// Set include trigger words setting
|
// Set include trigger words setting
|
||||||
const includeTriggerWordsCheckbox = document.getElementById('includeTriggerWords');
|
const includeTriggerWordsCheckbox = document.getElementById('includeTriggerWords');
|
||||||
if (includeTriggerWordsCheckbox) {
|
if (includeTriggerWordsCheckbox) {
|
||||||
includeTriggerWordsCheckbox.checked = state.global.settings.includeTriggerWords || false;
|
includeTriggerWordsCheckbox.checked = state.global.settings.include_trigger_words || false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load metadata archive settings
|
// Load metadata archive settings
|
||||||
@@ -883,38 +797,17 @@ export class SettingsManager {
|
|||||||
if (!element) return;
|
if (!element) return;
|
||||||
|
|
||||||
const value = element.checked;
|
const value = element.checked;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Update frontend state with mapped keys
|
await this.saveSetting(settingKey, value);
|
||||||
if (settingKey === 'blur_mature_content') {
|
|
||||||
await this.saveSetting('blurMatureContent', value);
|
if (settingKey === 'proxy_enabled') {
|
||||||
} else if (settingKey === 'show_only_sfw') {
|
|
||||||
await this.saveSetting('show_only_sfw', value);
|
|
||||||
} else if (settingKey === 'autoplay_on_hover') {
|
|
||||||
await this.saveSetting('autoplayOnHover', value);
|
|
||||||
} else if (settingKey === 'optimize_example_images') {
|
|
||||||
await this.saveSetting('optimizeExampleImages', value);
|
|
||||||
} else if (settingKey === 'auto_download_example_images') {
|
|
||||||
await this.saveSetting('autoDownloadExampleImages', value);
|
|
||||||
} else if (settingKey === 'compact_mode') {
|
|
||||||
await this.saveSetting('compactMode', value);
|
|
||||||
} else if (settingKey === 'include_trigger_words') {
|
|
||||||
await this.saveSetting('includeTriggerWords', value);
|
|
||||||
} else if (settingKey === 'enable_metadata_archive_db') {
|
|
||||||
await this.saveSetting('enable_metadata_archive_db', value);
|
|
||||||
} else if (settingKey === 'proxy_enabled') {
|
|
||||||
await this.saveSetting('proxy_enabled', value);
|
|
||||||
|
|
||||||
// Toggle visibility of proxy settings group
|
|
||||||
const proxySettingsGroup = document.getElementById('proxySettingsGroup');
|
const proxySettingsGroup = document.getElementById('proxySettingsGroup');
|
||||||
if (proxySettingsGroup) {
|
if (proxySettingsGroup) {
|
||||||
proxySettingsGroup.style.display = value ? 'block' : 'none';
|
proxySettingsGroup.style.display = value ? 'block' : 'none';
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// For any other settings that might be added in the future
|
|
||||||
await this.saveSetting(settingKey, value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Refresh metadata archive status when enable setting changes
|
// Refresh metadata archive status when enable setting changes
|
||||||
if (settingKey === 'enable_metadata_archive_db') {
|
if (settingKey === 'enable_metadata_archive_db') {
|
||||||
await this.updateMetadataArchiveStatus();
|
await this.updateMetadataArchiveStatus();
|
||||||
@@ -941,16 +834,11 @@ export class SettingsManager {
|
|||||||
// Recalculate layout when compact mode changes
|
// Recalculate layout when compact mode changes
|
||||||
if (settingKey === 'compact_mode' && state.virtualScroller) {
|
if (settingKey === 'compact_mode' && state.virtualScroller) {
|
||||||
state.virtualScroller.calculateLayout();
|
state.virtualScroller.calculateLayout();
|
||||||
showToast('toast.settings.compactModeToggled', {
|
showToast('toast.settings.compactModeToggled', {
|
||||||
state: value ? 'toast.settings.compactModeEnabled' : 'toast.settings.compactModeDisabled'
|
state: value ? 'toast.settings.compactModeEnabled' : 'toast.settings.compactModeDisabled'
|
||||||
}, 'success');
|
}, 'success');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Special handling for metadata archive settings
|
|
||||||
if (settingKey === 'enable_metadata_archive_db') {
|
|
||||||
await this.updateMetadataArchiveStatus();
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
showToast('toast.settings.settingSaveFailed', { message: error.message }, 'error');
|
showToast('toast.settings.settingSaveFailed', { message: error.message }, 'error');
|
||||||
}
|
}
|
||||||
@@ -964,23 +852,8 @@ export class SettingsManager {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
// Update frontend state with mapped keys
|
// Update frontend state with mapped keys
|
||||||
if (settingKey === 'default_lora_root') {
|
await this.saveSetting(settingKey, value);
|
||||||
await this.saveSetting('default_lora_root', value);
|
|
||||||
} else if (settingKey === 'default_checkpoint_root') {
|
|
||||||
await this.saveSetting('default_checkpoint_root', value);
|
|
||||||
} else if (settingKey === 'default_embedding_root') {
|
|
||||||
await this.saveSetting('default_embedding_root', value);
|
|
||||||
} else if (settingKey === 'display_density') {
|
|
||||||
await this.saveSetting('displayDensity', value);
|
|
||||||
} else if (settingKey === 'card_info_display') {
|
|
||||||
await this.saveSetting('cardInfoDisplay', value);
|
|
||||||
} else if (settingKey === 'proxy_type') {
|
|
||||||
await this.saveSetting('proxy_type', value);
|
|
||||||
} else {
|
|
||||||
// For any other settings that might be added in the future
|
|
||||||
await this.saveSetting(settingKey, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Apply frontend settings immediately
|
// Apply frontend settings immediately
|
||||||
this.applyFrontendSettings();
|
this.applyFrontendSettings();
|
||||||
|
|
||||||
@@ -1296,13 +1169,13 @@ export class SettingsManager {
|
|||||||
async saveLanguageSetting() {
|
async saveLanguageSetting() {
|
||||||
const element = document.getElementById('languageSelect');
|
const element = document.getElementById('languageSelect');
|
||||||
if (!element) return;
|
if (!element) return;
|
||||||
|
|
||||||
const selectedLanguage = element.value;
|
const selectedLanguage = element.value;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Use the universal save method for language (frontend-only setting)
|
// Use the universal save method for language (frontend-only setting)
|
||||||
await this.saveSetting('language', selectedLanguage);
|
await this.saveSetting('language', selectedLanguage);
|
||||||
|
|
||||||
// Reload the page to apply the new language
|
// Reload the page to apply the new language
|
||||||
window.location.reload();
|
window.location.reload();
|
||||||
|
|
||||||
@@ -1347,7 +1220,7 @@ export class SettingsManager {
|
|||||||
|
|
||||||
applyFrontendSettings() {
|
applyFrontendSettings() {
|
||||||
// Apply autoplay setting to existing videos in card previews
|
// Apply autoplay setting to existing videos in card previews
|
||||||
const autoplayOnHover = state.global.settings.autoplayOnHover;
|
const autoplayOnHover = state.global.settings.autoplay_on_hover;
|
||||||
document.querySelectorAll('.card-preview video').forEach(video => {
|
document.querySelectorAll('.card-preview video').forEach(video => {
|
||||||
// Remove previous event listeners by cloning and replacing the element
|
// Remove previous event listeners by cloning and replacing the element
|
||||||
const videoParent = video.parentElement;
|
const videoParent = video.parentElement;
|
||||||
@@ -1377,17 +1250,17 @@ export class SettingsManager {
|
|||||||
// Apply display density class to grid
|
// Apply display density class to grid
|
||||||
const grid = document.querySelector('.card-grid');
|
const grid = document.querySelector('.card-grid');
|
||||||
if (grid) {
|
if (grid) {
|
||||||
const density = state.global.settings.displayDensity || 'default';
|
const density = state.global.settings.display_density || 'default';
|
||||||
|
|
||||||
// Remove all density classes first
|
// Remove all density classes first
|
||||||
grid.classList.remove('default-density', 'medium-density', 'compact-density');
|
grid.classList.remove('default-density', 'medium-density', 'compact-density');
|
||||||
|
|
||||||
// Add the appropriate density class
|
// Add the appropriate density class
|
||||||
grid.classList.add(`${density}-density`);
|
grid.classList.add(`${density}-density`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply card info display setting
|
// Apply card info display setting
|
||||||
const cardInfoDisplay = state.global.settings.cardInfoDisplay || 'always';
|
const cardInfoDisplay = state.global.settings.card_info_display || 'always';
|
||||||
document.body.classList.toggle('hover-reveal', cardInfoDisplay === 'hover');
|
document.body.classList.toggle('hover-reveal', cardInfoDisplay === 'hover');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,20 +1,43 @@
|
|||||||
// Create the new hierarchical state structure
|
// Create the new hierarchical state structure
|
||||||
import { getStorageItem, getMapFromStorage } from '../utils/storageHelpers.js';
|
import { getStorageItem, getMapFromStorage } from '../utils/storageHelpers.js';
|
||||||
import { MODEL_TYPES } from '../api/apiConfig.js';
|
import { MODEL_TYPES } from '../api/apiConfig.js';
|
||||||
|
import { DEFAULT_PATH_TEMPLATES } from '../utils/constants.js';
|
||||||
|
|
||||||
// Load only frontend settings from localStorage with defaults
|
const DEFAULT_SETTINGS_BASE = Object.freeze({
|
||||||
// Backend settings will be loaded by SettingsManager from the backend
|
civitai_api_key: '',
|
||||||
const savedSettings = getStorageItem('settings', {
|
language: 'en',
|
||||||
blurMatureContent: true,
|
|
||||||
show_only_sfw: false,
|
show_only_sfw: false,
|
||||||
cardInfoDisplay: 'always',
|
enable_metadata_archive_db: false,
|
||||||
autoplayOnHover: false,
|
proxy_enabled: false,
|
||||||
displayDensity: 'default',
|
proxy_type: 'http',
|
||||||
optimizeExampleImages: true,
|
proxy_host: '',
|
||||||
autoDownloadExampleImages: true,
|
proxy_port: '',
|
||||||
includeTriggerWords: false
|
proxy_username: '',
|
||||||
|
proxy_password: '',
|
||||||
|
default_lora_root: '',
|
||||||
|
default_checkpoint_root: '',
|
||||||
|
default_embedding_root: '',
|
||||||
|
base_model_path_mappings: {},
|
||||||
|
download_path_templates: {},
|
||||||
|
example_images_path: '',
|
||||||
|
optimize_example_images: true,
|
||||||
|
auto_download_example_images: false,
|
||||||
|
blur_mature_content: true,
|
||||||
|
autoplay_on_hover: false,
|
||||||
|
display_density: 'default',
|
||||||
|
card_info_display: 'always',
|
||||||
|
include_trigger_words: false,
|
||||||
|
compact_mode: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export function createDefaultSettings() {
|
||||||
|
return {
|
||||||
|
...DEFAULT_SETTINGS_BASE,
|
||||||
|
base_model_path_mappings: {},
|
||||||
|
download_path_templates: { ...DEFAULT_PATH_TEMPLATES },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// Load preview versions from localStorage for each model type
|
// Load preview versions from localStorage for each model type
|
||||||
const loraPreviewVersions = getMapFromStorage('loras_preview_versions');
|
const loraPreviewVersions = getMapFromStorage('loras_preview_versions');
|
||||||
const checkpointPreviewVersions = getMapFromStorage('checkpoints_preview_versions');
|
const checkpointPreviewVersions = getMapFromStorage('checkpoints_preview_versions');
|
||||||
@@ -23,7 +46,7 @@ const embeddingPreviewVersions = getMapFromStorage('embeddings_preview_versions'
|
|||||||
export const state = {
|
export const state = {
|
||||||
// Global state
|
// Global state
|
||||||
global: {
|
global: {
|
||||||
settings: savedSettings,
|
settings: createDefaultSettings(),
|
||||||
loadingManager: null,
|
loadingManager: null,
|
||||||
observer: null,
|
observer: null,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ export class VirtualScroller {
|
|||||||
const availableContentWidth = containerWidth - paddingLeft - paddingRight;
|
const availableContentWidth = containerWidth - paddingLeft - paddingRight;
|
||||||
|
|
||||||
// Get display density setting
|
// Get display density setting
|
||||||
const displayDensity = state.global.settings?.displayDensity || 'default';
|
const displayDensity = state.global.settings?.display_density || 'default';
|
||||||
|
|
||||||
// Set exact column counts and grid widths to match CSS container widths
|
// Set exact column counts and grid widths to match CSS container widths
|
||||||
let maxColumns, maxGridWidth;
|
let maxColumns, maxGridWidth;
|
||||||
|
|||||||
@@ -339,7 +339,7 @@ export function copyLoraSyntax(card) {
|
|||||||
const baseSyntax = buildLoraSyntax(card.dataset.file_name, usageTips);
|
const baseSyntax = buildLoraSyntax(card.dataset.file_name, usageTips);
|
||||||
|
|
||||||
// Check if trigger words should be included
|
// Check if trigger words should be included
|
||||||
const includeTriggerWords = state.global.settings.includeTriggerWords;
|
const includeTriggerWords = state.global.settings.include_trigger_words;
|
||||||
|
|
||||||
if (!includeTriggerWords) {
|
if (!includeTriggerWords) {
|
||||||
const message = translate('uiHelpers.lora.syntaxCopied', {}, 'LoRA syntax copied to clipboard');
|
const message = translate('uiHelpers.lora.syntaxCopied', {}, 'LoRA syntax copied to clipboard');
|
||||||
|
|||||||
Reference in New Issue
Block a user