feat(example_images): add dedicated folder check and update settings handling for example images path, see #431

This commit is contained in:
Will Miao
2025-09-18 19:22:29 +08:00
parent 46e430ebbb
commit d30fbeb286
4 changed files with 88 additions and 32 deletions

View File

@@ -4,6 +4,7 @@ import sys
import threading
import asyncio
import subprocess
import re
from server import PromptServer # type: ignore
from aiohttp import web
from ..services.settings_manager import settings
@@ -85,6 +86,54 @@ node_registry = NodeRegistry()
class MiscRoutes:
"""Miscellaneous routes for various utility functions"""
@staticmethod
def is_dedicated_example_images_folder(folder_path):
"""
Check if a folder is a dedicated example images folder.
A dedicated folder should either be:
1. Empty
2. Only contain .download_progress.json file and/or folders with valid SHA256 hash names (64 hex characters)
Args:
folder_path (str): Path to the folder to check
Returns:
bool: True if the folder is dedicated, False otherwise
"""
try:
if not os.path.exists(folder_path) or not os.path.isdir(folder_path):
return False
items = os.listdir(folder_path)
# Empty folder is considered dedicated
if not items:
return True
# Check each item in the folder
for item in items:
item_path = os.path.join(folder_path, item)
# Allow .download_progress.json file
if item == '.download_progress.json' and os.path.isfile(item_path):
continue
# Allow folders with valid SHA256 hash names (64 hex characters)
if os.path.isdir(item_path):
# Check if the folder name is a valid SHA256 hash
if re.match(r'^[a-fA-F0-9]{64}$', item):
continue
# If we encounter anything else, it's not a dedicated folder
return False
return True
except Exception as e:
logger.error(f"Error checking if folder is dedicated: {e}")
return False
@staticmethod
def setup_routes(app):
"""Register miscellaneous routes"""
@@ -180,7 +229,7 @@ class MiscRoutes:
if value == settings.get(key):
# No change, skip
continue
# Special handling for example_images_path - verify path exists
# Special handling for example_images_path - verify path exists and is dedicated
if key == 'example_images_path' and value:
if not os.path.exists(value):
return web.json_response({
@@ -188,6 +237,13 @@ class MiscRoutes:
'error': f"Path does not exist: {value}"
})
# Check if folder is dedicated for example images
if not MiscRoutes.is_dedicated_example_images_folder(value):
return web.json_response({
'success': False,
'error': "Please set a dedicated folder for example images."
})
# Path changed - server restart required for new path to take effect
old_path = settings.get('example_images_path')
if old_path != value:

View File

@@ -40,10 +40,10 @@ class DownloadManager:
Expects a JSON body with:
{
"output_dir": "path/to/output", # Base directory to save example images
"optimize": true, # Whether to optimize images (default: true)
"model_types": ["lora", "checkpoint"], # Model types to process (default: both)
"delay": 1.0 # Delay between downloads to avoid rate limiting (default: 1.0)
"delay": 1.0, # Delay between downloads to avoid rate limiting (default: 1.0)
"auto_mode": false # Flag to indicate automatic download (default: false)
}
"""
global download_task, is_downloading, download_progress
@@ -64,16 +64,30 @@ class DownloadManager:
try:
# Parse the request body
data = await request.json()
output_dir = data.get('output_dir')
auto_mode = data.get('auto_mode', False)
optimize = data.get('optimize', True)
model_types = data.get('model_types', ['lora', 'checkpoint'])
delay = float(data.get('delay', 0.2)) # Default to 0.2 seconds
# Get output directory from settings
from ..services.service_registry import ServiceRegistry
settings_manager = await ServiceRegistry.get_settings_manager()
output_dir = settings_manager.get('example_images_path')
if not output_dir:
return web.json_response({
'success': False,
'error': 'Missing output_dir parameter'
}, status=400)
error_msg = 'Example images path not configured in settings'
if auto_mode:
# For auto mode, just log and return success to avoid showing error toasts
logger.debug(error_msg)
return web.json_response({
'success': True,
'message': 'Example images path not configured, skipping auto download'
})
else:
return web.json_response({
'success': False,
'error': error_msg
}, status=400)
# Create the output directory
os.makedirs(output_dir, exist_ok=True)
@@ -426,7 +440,6 @@ class DownloadManager:
Expects a JSON body with:
{
"model_hashes": ["hash1", "hash2", ...], # List of model hashes to download
"output_dir": "path/to/output", # Base directory to save example images
"optimize": true, # Whether to optimize images (default: true)
"model_types": ["lora", "checkpoint"], # Model types to process (default: both)
"delay": 1.0 # Delay between downloads (default: 1.0)
@@ -444,7 +457,6 @@ class DownloadManager:
# Parse the request body
data = await request.json()
model_hashes = data.get('model_hashes', [])
output_dir = data.get('output_dir')
optimize = data.get('optimize', True)
model_types = data.get('model_types', ['lora', 'checkpoint'])
delay = float(data.get('delay', 0.2)) # Default to 0.2 seconds
@@ -454,11 +466,16 @@ class DownloadManager:
'success': False,
'error': 'Missing model_hashes parameter'
}, status=400)
# Get output directory from settings
from ..services.service_registry import ServiceRegistry
settings_manager = await ServiceRegistry.get_settings_manager()
output_dir = settings_manager.get('example_images_path')
if not output_dir:
return web.json_response({
'success': False,
'error': 'Missing output_dir parameter'
'error': 'Example images path not configured in settings'
}, status=400)
# Create the output directory

View File

@@ -100,9 +100,7 @@ export class ExampleImagesManager {
this.updateDownloadButtonState(hasPath);
try {
await settingsManager.saveSetting('example_images_path', pathInput.value);
if (hasPath) {
showToast('toast.exampleImages.pathUpdated', {}, 'success');
}
} catch (error) {
console.error('Failed to update example images path:', error);
showToast('toast.exampleImages.pathUpdateFailed', { message: error.message }, 'error');
@@ -227,13 +225,6 @@ export class ExampleImagesManager {
}
try {
const outputDir = document.getElementById('exampleImagesPath').value || '';
if (!outputDir) {
showToast('toast.exampleImages.enterLocationFirst', {}, 'warning');
return;
}
const optimize = state.global.settings.optimizeExampleImages;
const response = await fetch('/api/lm/download-example-images', {
@@ -242,7 +233,6 @@ export class ExampleImagesManager {
'Content-Type': 'application/json'
},
body: JSON.stringify({
output_dir: outputDir,
optimize: optimize,
model_types: ['lora', 'checkpoint', 'embedding'] // Example types, adjust as needed
})
@@ -691,9 +681,8 @@ export class ExampleImagesManager {
return false;
}
// Check if download path is set
const pathInput = document.getElementById('exampleImagesPath');
if (!pathInput || !pathInput.value.trim()) {
// Check if download path is set in settings
if (!state.global.settings.example_images_path) {
return false;
}
@@ -724,7 +713,6 @@ export class ExampleImagesManager {
try {
console.log('Performing auto download check...');
const outputDir = document.getElementById('exampleImagesPath').value;
const optimize = state.global.settings.optimizeExampleImages;
const response = await fetch('/api/lm/download-example-images', {
@@ -733,7 +721,6 @@ export class ExampleImagesManager {
'Content-Type': 'application/json'
},
body: JSON.stringify({
output_dir: outputDir,
optimize: optimize,
model_types: ['lora', 'checkpoint', 'embedding'],
auto_mode: true // Flag to indicate this is an automatic download

View File

@@ -140,7 +140,7 @@ export class SettingsManager {
proxy_password: '',
example_images_path: '',
optimizeExampleImages: true,
autoDownloadExampleImages: true
autoDownloadExampleImages: false
};
Object.keys(backendDefaults).forEach(key => {
@@ -972,10 +972,6 @@ export class SettingsManager {
await this.saveSetting('default_embedding_root', value);
} else if (settingKey === 'display_density') {
await this.saveSetting('displayDensity', value);
// Also update compactMode for backwards compatibility
state.global.settings.compactMode = (value !== 'default');
this.saveFrontendSettingsToStorage();
} else if (settingKey === 'card_info_display') {
await this.saveSetting('cardInfoDisplay', value);
} else if (settingKey === 'proxy_type') {