fix(utils): sanitize path template folder names

This commit is contained in:
pixelpaws
2025-10-18 16:20:47 +08:00
parent 15edd7a42c
commit f7a856349a
4 changed files with 87 additions and 4 deletions

View File

@@ -9,6 +9,7 @@ from urllib.parse import urlparse
from ..utils.models import LoraMetadata, CheckpointMetadata, EmbeddingMetadata
from ..utils.constants import CARD_PREVIEW_WIDTH, VALID_LORA_TYPES
from ..utils.civitai_utils import rewrite_preview_url
from ..utils.utils import sanitize_folder_name
from ..utils.exif_utils import ExifUtils
from ..utils.metadata_manager import MetadataManager
from .service_registry import ServiceRegistry
@@ -427,8 +428,8 @@ class DownloadManager:
formatted_path = formatted_path.replace('{base_model}', mapped_base_model)
formatted_path = formatted_path.replace('{first_tag}', first_tag)
formatted_path = formatted_path.replace('{author}', author)
formatted_path = formatted_path.replace('{model_name}', model_info.get('name', ''))
formatted_path = formatted_path.replace('{version_name}', version_info.get('name', ''))
formatted_path = formatted_path.replace('{model_name}', sanitize_folder_name(model_info.get('name', '')))
formatted_path = formatted_path.replace('{version_name}', sanitize_folder_name(version_info.get('name', '')))
if model_type == 'embedding':
formatted_path = formatted_path.replace(' ', '_')

View File

@@ -1,5 +1,6 @@
from difflib import SequenceMatcher
import os
import re
from typing import Dict
from ..services.service_registry import ServiceRegistry
from ..config import config
@@ -85,6 +86,41 @@ def fuzzy_match(text: str, pattern: str, threshold: float = 0.85) -> bool:
# All words found either as substrings or fuzzy matches
return True
def sanitize_folder_name(name: str, replacement: str = "_") -> str:
"""Sanitize a folder name by removing or replacing invalid characters.
Args:
name: The original folder name.
replacement: The character to use when replacing invalid characters.
Returns:
A sanitized folder name safe to use across common filesystems.
"""
if not name:
return ""
# Replace invalid characters commonly restricted on Windows and POSIX
invalid_chars_pattern = r'[<>:"/\\|?*\x00-\x1f]'
sanitized = re.sub(invalid_chars_pattern, replacement, name)
# Trim whitespace introduced during sanitization
sanitized = sanitized.strip()
# Collapse repeated replacement characters to a single instance
if replacement:
sanitized = re.sub(f"{re.escape(replacement)}+", replacement, sanitized)
sanitized = sanitized.strip(replacement)
# Remove trailing spaces or periods which are invalid on Windows
sanitized = sanitized.rstrip(" .")
if not sanitized:
return "unnamed"
return sanitized
def calculate_recipe_fingerprint(loras):
"""
Calculate a unique fingerprint for a recipe based on its LoRAs.
@@ -175,11 +211,11 @@ def calculate_relative_path_for_model(model_data: Dict, model_type: str = 'lora'
first_tag = 'no tags' # Default if no tags available
# Format the template with available data
model_name = model_data.get('model_name', '')
model_name = sanitize_folder_name(model_data.get('model_name', ''))
version_name = ''
if isinstance(civitai_data, dict):
version_name = civitai_data.get('name') or ''
version_name = sanitize_folder_name(civitai_data.get('name') or '')
formatted_path = path_template
formatted_path = formatted_path.replace('{base_model}', mapped_base_model)