Skip to content

Feature: Smart Name Matching & Search Improvements #16

Description

@slahiri

Feature Request: Smart Name Matching & Search Improvements

Source

Inspired by mcrataobrabo/comfyui-smart-lora-downloader

Overview

Enhance model search and matching capabilities with intelligent name normalization, multi-strategy search, and similarity scoring to improve the accuracy of finding models on HuggingFace and CivitAI.


1. Smart Name Matching (Levenshtein + Word Overlap)

Description

Implement sophisticated similarity scoring using multiple algorithms to find the best match from search results.

Implementation

def calculate_name_similarity(name1: str, name2: str) -> float:
    """Calculate similarity using Levenshtein distance + word overlap"""
    
    # Normalize both names
    norm1 = normalize_name(name1).lower()
    norm2 = normalize_name(name2).lower()
    
    # Exact match
    if norm1 == norm2:
        return 1.0
    
    # Containment check
    if norm1 in norm2 or norm2 in norm1:
        return 0.8
    
    # Levenshtein distance similarity
    max_len = max(len(norm1), len(norm2))
    distance = levenshtein_distance(norm1, norm2)
    lev_similarity = 1.0 - (distance / max_len)
    
    # Word overlap (Jaccard similarity)
    words1 = set(norm1.split())
    words2 = set(norm2.split())
    intersection = len(words1 & words2)
    union = len(words1 | words2)
    word_similarity = intersection / union if union > 0 else 0.0
    
    # Combined score (weighted)
    return (lev_similarity * 0.4) + (word_similarity * 0.6)

Benefits

  • Better match accuracy when filenames differ slightly
  • Handles abbreviations and variations
  • Reduces false positives from simple substring matching

2. Multi-Strategy Search

Description

Try multiple search queries to maximize chances of finding the correct model.

Strategies

  1. Original - Use the exact filename from workflow
  2. Normalized - Clean up the name (remove extensions, versions)
  3. Keywords - Extract top 3 meaningful keywords
  4. First Keyword - Use just the primary keyword if long enough

Implementation

def search_with_multiple_strategies(model_name: str) -> list:
    strategies = [
        ("original", model_name),
        ("normalized", normalize_name(model_name)),
        ("keywords", " ".join(extract_keywords(model_name)[:3])),
        ("first_keyword", extract_keywords(model_name)[0] if len(extract_keywords(model_name)[0]) >= 5 else None)
    ]
    
    all_results = []
    for strategy_name, query in strategies:
        if query:
            results = search_api(query)
            all_results.extend(results)
    
    # Deduplicate and find best match using similarity scoring
    return find_best_match(model_name, all_results)

Benefits

  • Higher success rate finding models
  • Handles various naming conventions
  • Falls back gracefully when exact match fails

3. Name Normalization

Description

Clean up model names for better search matching by removing noise.

Normalization Rules

def normalize_name(name: str) -> str:
    # Remove file extensions
    name = re.sub(r'\.(safetensors|ckpt|pt|bin)$', '', name, flags=re.IGNORECASE)
    
    # Convert camelCase to spaces
    name = re.sub(r'([a-z])([A-Z])', r'\1 \2', name)
    
    # Split on numbers
    name = re.sub(r'([a-z])(\d)', r'\1 \2', name)
    name = re.sub(r'(\d)([a-z])', r'\1 \2', name)
    
    # Convert separators to spaces
    name = re.sub(r'[_-]+', ' ', name)
    
    # Remove version patterns (v1, v1.5, SD1.5, XL)
    name = re.sub(r'\bv\d+(\.\d+)?\b', '', name, flags=re.IGNORECASE)
    name = re.sub(r'\b(sd|xl)\d*(\.\d+)?\b', '', name, flags=re.IGNORECASE)
    
    # Remove common terms
    name = re.sub(r'\b(lora|model|checkpoint|vae|unet)s?\b', '', name, flags=re.IGNORECASE)
    
    # Clean up whitespace
    return re.sub(r'\s+', ' ', name).strip()

Examples

Original Normalized
flux1-dev-fp8.safetensors flux dev fp8
SDXL_Lightning_v2.0.ckpt Lightning
dreamshaperXL_v21.safetensors dreamshaper

4. Duplicate Detection

Description

Detect and warn about duplicate models (same name, different extensions or versions).

Implementation

def find_duplicates(models_dir: str) -> dict:
    """Find potential duplicate model files"""
    files = os.listdir(models_dir)
    base_names = {}
    
    for file in files:
        if file.endswith(('.safetensors', '.ckpt', '.pt', '.bin')):
            base_name = normalize_name(file)
            if base_name not in base_names:
                base_names[base_name] = []
            base_names[base_name].append(file)
    
    # Return only groups with more than one file
    return {k: v for k, v in base_names.items() if len(v) > 1}

UI Integration

  • Show warning icon next to duplicate models
  • Add "Duplicates" section in settings/tools
  • Option to auto-cleanup (keep .safetensors, remove .ckpt)

5. Disk Space Check

Description

Verify sufficient disk space before starting downloads.

Implementation

import shutil

def check_disk_space(download_path: str, required_bytes: int) -> tuple[bool, str]:
    """Check if enough disk space is available"""
    try:
        total, used, free = shutil.disk_usage(download_path)
        
        # Require 10% buffer beyond file size
        required_with_buffer = required_bytes * 1.1
        
        if free < required_with_buffer:
            return False, f"Insufficient space: {free/(1024**3):.1f}GB free, need {required_with_buffer/(1024**3):.1f}GB"
        
        return True, f"OK: {free/(1024**3):.1f}GB available"
    except Exception as e:
        return True, f"Could not check: {e}"  # Proceed anyway

UI Integration

  • Show disk space in download panel
  • Block download with warning if insufficient space
  • Show estimated space needed for pending downloads

Priority

Medium-High - Significantly improves model discovery and download reliability

Implementation Order

  1. Name Normalization (foundation for others)
  2. Smart Name Matching (improves accuracy)
  3. Multi-Strategy Search (uses both above)
  4. Disk Space Check (quick win)
  5. Duplicate Detection (nice to have)

🤖 Generated with Claude Code

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions