From 74507cef05443855c9996c401bafe0be9e56d828 Mon Sep 17 00:00:00 2001 From: Will Miao <13051207myq@gmail.com> Date: Sat, 6 Sep 2025 17:39:51 +0800 Subject: [PATCH] feat(settings): add validation for settings.json to ensure required configuration is present fix(usage_stats): handle initialization errors for usage statistics when no valid paths are configured, fixes #375 --- py/routes/stats_routes.py | 8 +++++- py/utils/usage_stats.py | 5 ++-- standalone.py | 54 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 64 insertions(+), 3 deletions(-) diff --git a/py/routes/stats_routes.py b/py/routes/stats_routes.py index 3fa1a519..b61762d1 100644 --- a/py/routes/stats_routes.py +++ b/py/routes/stats_routes.py @@ -33,7 +33,13 @@ class StatsRoutes: self.lora_scanner = await ServiceRegistry.get_lora_scanner() self.checkpoint_scanner = await ServiceRegistry.get_checkpoint_scanner() self.embedding_scanner = await ServiceRegistry.get_embedding_scanner() - self.usage_stats = UsageStats() + + # Only initialize usage stats if we have valid paths configured + try: + self.usage_stats = UsageStats() + except RuntimeError as e: + logger.warning(f"Could not initialize usage statistics: {e}") + self.usage_stats = None async def handle_stats_page(self, request: web.Request) -> web.Response: """Handle GET /statistics request""" diff --git a/py/utils/usage_stats.py b/py/utils/usage_stats.py index 84488890..08021964 100644 --- a/py/utils/usage_stats.py +++ b/py/utils/usage_stats.py @@ -67,8 +67,9 @@ class UsageStats: def _get_stats_file_path(self) -> str: """Get the path to the stats JSON file""" if not config.loras_roots or len(config.loras_roots) == 0: - # Fallback to temporary directory if no lora roots - return os.path.join(config.temp_directory, self.STATS_FILENAME) + # If no lora roots are available, we can't save stats + # This will be handled by the caller + raise RuntimeError("No LoRA root directories configured. Cannot initialize usage statistics.") # Use the first lora root return os.path.join(config.loras_roots[0], self.STATS_FILENAME) diff --git a/standalone.py b/standalone.py index 83c2d236..b8532abf 100644 --- a/standalone.py +++ b/standalone.py @@ -213,6 +213,54 @@ class StandaloneServer: # After all mocks are in place, import LoraManager from py.lora_manager import LoraManager +def validate_settings(): + """Validate that settings.json exists and has required configuration""" + settings_path = os.path.join(os.path.dirname(__file__), 'settings.json') + if not os.path.exists(settings_path): + logger.error("=" * 80) + logger.error("CONFIGURATION ERROR: settings.json file not found!") + logger.error("") + logger.error("To run in standalone mode, you need to create a settings.json file.") + logger.error("Please follow these steps:") + logger.error("") + logger.error("1. Copy the provided settings.json.example file to create a new file") + logger.error(" named settings.json in the comfyui-lora-manager folder") + logger.error("") + logger.error("2. Edit settings.json to include your correct model folder paths") + logger.error(" and CivitAI API key") + logger.error("=" * 80) + return False + + # Check if settings.json has valid folder paths + try: + with open(settings_path, 'r', encoding='utf-8') as f: + settings = json.load(f) + + folder_paths = settings.get('folder_paths', {}) + has_valid_paths = False + + for path_type in ['loras', 'checkpoints', 'embeddings']: + paths = folder_paths.get(path_type, []) + if paths and any(os.path.exists(p) for p in paths): + has_valid_paths = True + break + + if not has_valid_paths: + logger.warning("=" * 80) + logger.warning("CONFIGURATION WARNING: No valid model folder paths found!") + logger.warning("") + logger.warning("Your settings.json exists but doesn't contain valid folder paths.") + logger.warning("Please check and update the folder_paths section in settings.json") + logger.warning("to include existing directories for your models.") + logger.warning("=" * 80) + return False + + except Exception as e: + logger.error(f"Error reading settings.json: {e}") + return False + + return True + class StandaloneLoraManager(LoraManager): """Extended LoraManager for standalone mode""" @@ -405,6 +453,12 @@ async def main(): # Set log level logging.getLogger().setLevel(getattr(logging, args.log_level)) + # Validate settings before proceeding + if not validate_settings(): + logger.error("Cannot start server due to configuration issues.") + logger.error("Please fix the settings.json file and try again.") + return + # Create the server instance server = StandaloneServer()