diff --git a/py/workflow_params/node_processors/flux_guidance_processor.py b/py/workflow_params/node_processors/flux_guidance_processor.py new file mode 100644 index 00000000..14e450b2 --- /dev/null +++ b/py/workflow_params/node_processors/flux_guidance_processor.py @@ -0,0 +1,22 @@ +from typing import Dict, Any +from .base_processor import NodeProcessor, register_processor + +@register_processor +class FluxGuidanceProcessor(NodeProcessor): + """Processor for Flux Guidance nodes""" + + NODE_CLASS_TYPE = "FluxGuidance" + REQUIRED_FIELDS = {"guidance"} + + def process(self, workflow_parser) -> Dict[str, Any]: + """Process a FluxGuidance node to extract guidance value""" + result = {} + + positive_text = self.resolve_input("conditioning", workflow_parser) + if positive_text: + result["positive"] = positive_text + + if "guidance" in self.inputs: + result["guidance"] = str(self.inputs["guidance"]) + return result + diff --git a/static/js/components/ContextMenu.js b/static/js/components/ContextMenu.js index b02f2828..77380b1d 100644 --- a/static/js/components/ContextMenu.js +++ b/static/js/components/ContextMenu.js @@ -1,6 +1,7 @@ import { refreshSingleLoraMetadata } from '../api/loraApi.js'; import { showToast, getNSFWLevelName } from '../utils/uiHelpers.js'; import { NSFW_LEVELS } from '../utils/constants.js'; +import { getStorageItem } from '../utils/storageHelpers.js'; export class LoraContextMenu { constructor() { @@ -149,7 +150,7 @@ export class LoraContextMenu { updateCardBlurEffect(card, level) { // Get user settings for blur threshold - const blurThreshold = parseInt(localStorage.getItem('nsfwBlurLevel') || '4'); + const blurThreshold = parseInt(getStorageItem('nsfwBlurLevel') || '4'); // Get card preview container const previewContainer = card.querySelector('.card-preview'); diff --git a/static/js/core.js b/static/js/core.js index 3485e01e..a38fda70 100644 --- a/static/js/core.js +++ b/static/js/core.js @@ -7,6 +7,7 @@ import { HeaderManager } from './components/Header.js'; import { SettingsManager } from './managers/SettingsManager.js'; import { showToast, initTheme, initBackToTop, lazyLoadImages } from './utils/uiHelpers.js'; import { initializeInfiniteScroll } from './utils/infiniteScroll.js'; +import { migrateStorageItems } from './utils/storageHelpers.js'; // Core application class export class AppCore { @@ -17,6 +18,8 @@ export class AppCore { // Initialize core functionality async initialize() { if (this.initialized) return; + + console.log('AppCore: Initializing...'); // Initialize managers state.loadingManager = new LoadingManager(); @@ -64,6 +67,11 @@ export class AppCore { } } +document.addEventListener('DOMContentLoaded', () => { + // Migrate localStorage items to use the namespace prefix + migrateStorageItems(); +}); + // Create and export a singleton instance export const appCore = new AppCore(); diff --git a/static/js/loras.js b/static/js/loras.js index b4c0bc74..fbfc314d 100644 --- a/static/js/loras.js +++ b/static/js/loras.js @@ -1,5 +1,5 @@ import { appCore } from './core.js'; -import { state, initPageState } from './state/index.js'; +import { state } from './state/index.js'; import { showLoraModal, toggleShowcase, scrollToTop } from './components/LoraModal.js'; import { loadMoreLoras, fetchCivitai, deleteModel, replacePreview, resetAndReload, refreshLoras } from './api/loraApi.js'; import { @@ -97,9 +97,6 @@ function initializeEventListeners() { // Initialize everything when DOM is ready document.addEventListener('DOMContentLoaded', async () => { - // Initialize page state - initPageState('loras'); - // Initialize core application await appCore.initialize(); diff --git a/static/js/managers/FilterManager.js b/static/js/managers/FilterManager.js index 6f2c8d2e..96d31388 100644 --- a/static/js/managers/FilterManager.js +++ b/static/js/managers/FilterManager.js @@ -2,6 +2,7 @@ import { BASE_MODELS, BASE_MODEL_CLASSES } from '../utils/constants.js'; import { state, getCurrentPageState } from '../state/index.js'; import { showToast, updatePanelPositions } from '../utils/uiHelpers.js'; import { loadMoreLoras } from '../api/loraApi.js'; +import { removeStorageItem, setStorageItem, getStorageItem } from '../utils/storageHelpers.js'; export class FilterManager { constructor(options = {}) { @@ -267,7 +268,7 @@ export class FilterManager { const storageKey = `${this.currentPage}_filters`; // Save filters to localStorage - localStorage.setItem(storageKey, JSON.stringify(this.filters)); + setStorageItem(storageKey, this.filters); // Update state with current filters pageState.filters = { ...this.filters }; @@ -323,9 +324,9 @@ export class FilterManager { this.updateTagSelections(); this.updateActiveFiltersCount(); - // Remove from localStorage + // Remove from local Storage const storageKey = `${this.currentPage}_filters`; - localStorage.removeItem(storageKey); + removeStorageItem(storageKey); // Update UI this.filterButton.classList.remove('active'); @@ -344,16 +345,14 @@ export class FilterManager { loadFiltersFromStorage() { const storageKey = `${this.currentPage}_filters`; - const savedFilters = localStorage.getItem(storageKey); + const savedFilters = getStorageItem(storageKey); if (savedFilters) { try { - const parsedFilters = JSON.parse(savedFilters); - // Ensure backward compatibility with older filter format this.filters = { - baseModel: parsedFilters.baseModel || [], - tags: parsedFilters.tags || [] + baseModel: savedFilters.baseModel || [], + tags: savedFilters.tags || [] }; // Update state with loaded filters diff --git a/static/js/managers/SearchManager.js b/static/js/managers/SearchManager.js index f0fc49af..4d909b36 100644 --- a/static/js/managers/SearchManager.js +++ b/static/js/managers/SearchManager.js @@ -1,5 +1,6 @@ import { updatePanelPositions } from "../utils/uiHelpers.js"; import { getCurrentPageState } from "../state/index.js"; +import { setStorageItem, getStorageItem } from "../utils/storageHelpers.js"; /** * SearchManager - Handles search functionality across different pages * Each page can extend or customize this base functionality @@ -183,7 +184,7 @@ export class SearchManager { loadSearchPreferences() { try { - const preferences = JSON.parse(localStorage.getItem(`${this.currentPage}_search_prefs`)) || {}; + const preferences = getStorageItem(`${this.currentPage}_search_prefs`) || {}; // Apply search options if (preferences.options) { @@ -254,7 +255,7 @@ export class SearchManager { preferences.recursive = this.recursiveSearchToggle.checked; } - localStorage.setItem(`${this.currentPage}_search_prefs`, JSON.stringify(preferences)); + setStorageItem(`${this.currentPage}_search_prefs`, preferences); } catch (error) { console.error('Error saving search preferences:', error); } diff --git a/static/js/managers/SettingsManager.js b/static/js/managers/SettingsManager.js index da485760..ad716b40 100644 --- a/static/js/managers/SettingsManager.js +++ b/static/js/managers/SettingsManager.js @@ -2,6 +2,7 @@ import { modalManager } from './ModalManager.js'; import { showToast } from '../utils/uiHelpers.js'; import { state } from '../state/index.js'; import { resetAndReload } from '../api/loraApi.js'; +import { setStorageItem } from '../utils/storageHelpers.js'; export class SettingsManager { constructor() { @@ -75,7 +76,7 @@ export class SettingsManager { state.global.settings.show_only_sfw = showOnlySFW; // Save settings to localStorage - localStorage.setItem('settings', JSON.stringify(state.global.settings)); + setStorageItem('settings', state.global.settings); try { // Save backend settings via API diff --git a/static/js/managers/UpdateService.js b/static/js/managers/UpdateService.js index 3f83584f..0f2b2e8d 100644 --- a/static/js/managers/UpdateService.js +++ b/static/js/managers/UpdateService.js @@ -1,4 +1,5 @@ import { modalManager } from './ModalManager.js'; +import { getStorageItem, setStorageItem } from '../utils/storageHelpers.js'; export class UpdateService { constructor() { @@ -7,13 +8,13 @@ export class UpdateService { this.latestVersion = "v0.0.0"; // Initialize with default values this.updateInfo = null; this.updateAvailable = false; - this.updateNotificationsEnabled = localStorage.getItem('show_update_notifications') !== 'false'; - this.lastCheckTime = parseInt(localStorage.getItem('last_update_check') || '0'); + this.updateNotificationsEnabled = getStorageItem('show_update_notifications') !== 'false'; + this.lastCheckTime = parseInt(getStorageItem('last_update_check') || '0'); } initialize() { // Initialize update preferences from localStorage - const showUpdates = localStorage.getItem('show_update_notifications'); + const showUpdates = getStorageItem('show_update_notifications'); this.updateNotificationsEnabled = showUpdates === null || showUpdates === 'true'; // Register event listener for update notification toggle @@ -22,7 +23,7 @@ export class UpdateService { updateCheckbox.checked = this.updateNotificationsEnabled; updateCheckbox.addEventListener('change', (e) => { this.updateNotificationsEnabled = e.target.checked; - localStorage.setItem('show_update_notifications', e.target.checked); + setStorageItem('show_update_notifications', e.target.checked); this.updateBadgeVisibility(); }); } @@ -71,7 +72,7 @@ export class UpdateService { // Update last check time this.lastCheckTime = now; - localStorage.setItem('last_update_check', now.toString()); + setStorageItem('last_update_check', now.toString()); // Update UI this.updateBadgeVisibility(); diff --git a/static/js/utils/storageHelpers.js b/static/js/utils/storageHelpers.js new file mode 100644 index 00000000..c7654515 --- /dev/null +++ b/static/js/utils/storageHelpers.js @@ -0,0 +1,110 @@ +/** + * Utility functions for localStorage with namespacing to avoid conflicts + * with other ComfyUI extensions or the main application + */ + +// Namespace prefix for all localStorage keys +const STORAGE_PREFIX = 'lora_manager_'; + +/** + * Get an item from localStorage with namespace support and fallback to legacy keys + * @param {string} key - The key without prefix + * @param {any} defaultValue - Default value if key doesn't exist + * @returns {any} The stored value or defaultValue + */ +export function getStorageItem(key, defaultValue = null) { + // Try with prefix first + const prefixedValue = localStorage.getItem(STORAGE_PREFIX + key); + + if (prefixedValue !== null) { + // If it's a JSON string, parse it + try { + return JSON.parse(prefixedValue); + } catch (e) { + return prefixedValue; + } + } + + // Fallback to legacy key (without prefix) + const legacyValue = localStorage.getItem(key); + + if (legacyValue !== null) { + // If found in legacy storage, migrate it to prefixed storage + try { + const parsedValue = JSON.parse(legacyValue); + setStorageItem(key, parsedValue); + return parsedValue; + } catch (e) { + setStorageItem(key, legacyValue); + return legacyValue; + } + } + + // Return default value if neither prefixed nor legacy key exists + return defaultValue; +} + +/** + * Set an item in localStorage with namespace prefix + * @param {string} key - The key without prefix + * @param {any} value - The value to store + */ +export function setStorageItem(key, value) { + const prefixedKey = STORAGE_PREFIX + key; + + // Convert objects and arrays to JSON strings + if (typeof value === 'object' && value !== null) { + localStorage.setItem(prefixedKey, JSON.stringify(value)); + } else { + localStorage.setItem(prefixedKey, value); + } +} + +/** + * Remove an item from localStorage (both prefixed and legacy) + * @param {string} key - The key without prefix + */ +export function removeStorageItem(key) { + localStorage.removeItem(STORAGE_PREFIX + key); + localStorage.removeItem(key); // Also remove legacy key +} + +/** + * Migrate all existing localStorage items to use the prefix + * This should be called once during application initialization + */ +export function migrateStorageItems() { + // List of known keys used in the application + const knownKeys = [ + 'nsfwBlurLevel', + 'theme', + 'activeFolder', + 'folderTagsCollapsed', + 'settings', + 'loras_filters', + 'recipes_filters', + 'checkpoints_filters', + 'loras_search_prefs', + 'recipes_search_prefs', + 'checkpoints_search_prefs', + 'show_update_notifications', + 'last_update_check' + ]; + + // Migrate each known key + knownKeys.forEach(key => { + const value = localStorage.getItem(key); + if (value !== null) { + try { + // Try to parse as JSON first + const parsedValue = JSON.parse(value); + setStorageItem(key, parsedValue); + } catch (e) { + // If not JSON, store as is + setStorageItem(key, value); + } + } + }); + + console.log('Lora Manager: Storage migration completed'); +} \ No newline at end of file diff --git a/static/js/utils/uiHelpers.js b/static/js/utils/uiHelpers.js index 84600910..e038b2e8 100644 --- a/static/js/utils/uiHelpers.js +++ b/static/js/utils/uiHelpers.js @@ -1,5 +1,6 @@ import { state } from '../state/index.js'; import { resetAndReload } from '../api/loraApi.js'; +import { getStorageItem, setStorageItem } from './storageHelpers.js'; export function showToast(message, type = 'info') { const toast = document.createElement('div'); @@ -27,7 +28,7 @@ export function lazyLoadImages() { } export function restoreFolderFilter() { - const activeFolder = localStorage.getItem('activeFolder'); + const activeFolder = getStorageItem('activeFolder'); const folderTag = activeFolder && document.querySelector(`.tag[data-folder="${activeFolder}"]`); if (folderTag) { folderTag.classList.add('active'); @@ -36,13 +37,13 @@ export function restoreFolderFilter() { } export function initTheme() { - document.body.dataset.theme = localStorage.getItem('theme') || 'dark'; + document.body.dataset.theme = getStorageItem('theme') || 'dark'; } export function toggleTheme() { const theme = document.body.dataset.theme === 'light' ? 'dark' : 'light'; document.body.dataset.theme = theme; - localStorage.setItem('theme', theme); + setStorageItem('theme', theme); } export function toggleFolder(tag) { @@ -158,12 +159,12 @@ export function toggleFolderTags() { // Change icon to indicate folders are hidden toggleBtn.className = 'fas fa-folder-plus'; toggleBtn.parentElement.title = 'Show folder tags'; - localStorage.setItem('folderTagsCollapsed', 'true'); + setStorageItem('folderTagsCollapsed', 'true'); } else { // Change icon to indicate folders are visible toggleBtn.className = 'fas fa-folder-minus'; toggleBtn.parentElement.title = 'Hide folder tags'; - localStorage.setItem('folderTagsCollapsed', 'false'); + setStorageItem('folderTagsCollapsed', 'false'); } // Update panel positions after toggling @@ -176,7 +177,7 @@ export function toggleFolderTags() { // Add this to your existing initialization code export function initFolderTagsVisibility() { - const isCollapsed = localStorage.getItem('folderTagsCollapsed') === 'true'; + const isCollapsed = getStorageItem('folderTagsCollapsed') === 'true'; if (isCollapsed) { const folderTags = document.querySelector('.folder-tags'); const toggleBtn = document.querySelector('.toggle-folders-btn i'); diff --git a/web/comfyui/loras_widget.js b/web/comfyui/loras_widget.js index ebe162c9..2540826f 100644 --- a/web/comfyui/loras_widget.js +++ b/web/comfyui/loras_widget.js @@ -771,6 +771,7 @@ async function saveRecipeDirectly(widget) { try { // Get the workflow data from the ComfyUI app const prompt = await app.graphToPrompt(); + console.log('Prompt:', prompt.output); // Show loading toast if (app && app.extensionManager && app.extensionManager.toast) {