Files
ComfyUI-Lora-Manager/py/utils/base_model.py
T
Will Miao 838a374a56 feat(recipes): reconnect suggestions, undo, and base-model family tolerance
Enhance the deleted-LoRA reconnect flow in the recipe modal:

- Suggest local reconnect candidates when the panel opens, ranked by
  identity (same hash / same CivitAI version) then filename/name
  similarity, with a hard filter on confident base-model mismatches;
  the input gets a Combobox backed by the same endpoint as you type.
- Snapshot the pre-reconnect entry and offer a permanent restore:
  reconnected entries show an undo icon at the right end of the info
  row, with the original filename in the tooltip.
- Relax the manual reconnect base-model guard to a three-tier check:
  exact/unknown labels pass silently, same-architecture families
  (e.g. Pony <-> Illustrious) pass with a warning toast, and only
  cross-architecture mismatches stay hard-rejected.
2026-08-30 08:17:35 +08:00

80 lines
3.1 KiB
Python

"""Base-model architecture families and compatibility relations.
CivitAI base-model labels describe fine-tune lineages, not architectures.
A LoRA physically loads on any checkpoint sharing its tensor architecture,
so e.g. Pony / Illustrious / NoobAI / SDXL 1.0 LoRAs are interchangeable
(quality varies, but nothing breaks). Different architectures (SD 1.5 vs
SDXL vs Flux) are guaranteed failures and must stay hard-rejected.
Only families with high-confidence architecture equivalence are listed.
Anything not in the table is treated as its own family, i.e. only an exact
label match is accepted — unknown new labels never get wrongly waved through.
"""
from __future__ import annotations
from typing import Optional
# Normalized (casefolded, stripped) base-model label -> architecture family.
_BASE_MODEL_FAMILIES = {
# SD 1.x — all share the original 512px latent UNet.
"sd 1.4": "sd1",
"sd 1.5": "sd1",
"sd 1.5 lcm": "sd1",
"sd 1.5 hyper": "sd1",
# SDXL lineage — Pony / Illustrious / NoobAI are SDXL fine-tunes.
# Note: Pony V7 is AuraFlow-based, NOT SDXL, so it is deliberately absent.
"sdxl 1.0": "sdxl",
"sdxl lightning": "sdxl",
"sdxl hyper": "sdxl",
"pony": "sdxl",
"pony diffusion": "sdxl",
"pony diffusion v6 xl": "sdxl",
"illustrious": "sdxl",
"illustrious 0.1": "sdxl",
"illustrious 1.0": "sdxl",
"illustrious 1.1": "sdxl",
"noobai": "sdxl",
# Flux.1 — dev/schnell/Krea share the 12B rectified-flow transformer.
"flux.1 d": "flux1",
"flux.1 s": "flux1",
"flux.1 krea": "flux1",
# SD 3.5 Large and its Turbo distill share the 8B MMDiT. SD 3 (2B) and
# SD 3.5 Medium (2.5B) have different shapes and stay unlisted.
"sd 3.5 large": "sd35-large",
"sd 3.5 large turbo": "sd35-large",
}
_UNKNOWN_TOKENS = {"", "unknown", "other", "none", "null"}
# Relation constants returned by base_model_relation().
RELATION_UNKNOWN = "unknown" # at least one side has no usable label
RELATION_SAME = "same" # identical labels
RELATION_COMPATIBLE = "compatible" # different labels, same architecture family
RELATION_INCOMPATIBLE = "incompatible" # different labels, different/unknown family
def _normalize(label: Optional[str]) -> str:
return (label or "").strip().casefold()
def base_model_relation(a: Optional[str], b: Optional[str]) -> str:
"""Classify how two base-model labels relate for reconnect purposes.
``RELATION_UNKNOWN`` when either side has no usable label (callers treat
it as lenient-allow), ``RELATION_SAME`` for identical labels,
``RELATION_COMPATIBLE`` when both labels map to the same architecture
family, and ``RELATION_INCOMPATIBLE`` otherwise — including when a label
is missing from the family table (conservative fallback).
"""
na, nb = _normalize(a), _normalize(b)
if na in _UNKNOWN_TOKENS or nb in _UNKNOWN_TOKENS:
return RELATION_UNKNOWN
if na == nb:
return RELATION_SAME
fa = _BASE_MODEL_FAMILIES.get(na)
fb = _BASE_MODEL_FAMILIES.get(nb)
if fa is not None and fa == fb:
return RELATION_COMPATIBLE
return RELATION_INCOMPATIBLE