feat(lora): support relative paths in <lora:folder/name:strength> syntax (#917)

Autocomplete, copy/send-to-workflow, and recipe syntax now emit
<lora:folder/name:strength> instead of <lora:name:strength>, using
relative paths to disambiguate identically-named loras in different
subfolders without requiring file renames.

Backend: 3-tier hybrid resolution (path → bare → basename fallback)
across get_lora_info, get_lora_info_absolute, get_model_preview_url,
get_model_civitai_url, get_model_info_by_name, get_lora_metadata_by_filename,
and get_hash_by_filename. Also fix get_random_loras and get_cycler_list
to return path-prefixed names for randomizer/cycler consistency.

Frontend: autocomplete, copyLoraSyntax, handleSendToWorkflow emit
folder-prefixed syntax. extract_lora_name preserves relative paths.

Saved image metadata (<lora:...> in EXIF) intentionally keeps basename-only
for compatibility with A1111/Forge ecosystem.
This commit is contained in:
Will Miao
2026-05-20 19:39:12 +08:00
parent 33e5f3d85d
commit 9ce56dd40c
13 changed files with 404 additions and 48 deletions

View File

@@ -2517,6 +2517,7 @@ class RecipeScanner:
continue
file_name = None
folder = ""
hash_value = (lora.get("hash") or "").lower()
if (
hash_value
@@ -2526,6 +2527,11 @@ class RecipeScanner:
file_path = self._lora_scanner._hash_index.get_path(hash_value)
if file_path:
file_name = os.path.splitext(os.path.basename(file_path))[0]
if lora_cache is not None:
for cached_lora in getattr(lora_cache, "raw_data", []):
if cached_lora.get("file_path") == file_path:
folder = cached_lora.get("folder", "")
break
if not file_name and lora.get("modelVersionId") and lora_cache is not None:
for cached_lora in getattr(lora_cache, "raw_data", []):
@@ -2540,13 +2546,16 @@ class RecipeScanner:
file_name = os.path.splitext(os.path.basename(cached_path))[
0
]
folder = cached_lora.get("folder", "")
break
if not file_name:
file_name = lora.get("file_name", "unknown-lora")
folder = lora.get("folder", "")
lora_name = f"{folder}/{file_name}" if folder else file_name
strength = lora.get("strength", 1.0)
syntax_parts.append(f"<lora:{file_name}:{strength}>")
syntax_parts.append(f"<lora:{lora_name}:{strength}>")
return syntax_parts