Skip to content

legacy_models

Pydantic models encapsulating the legacy-to-new reference normalization rules.

_ALLOWED_CONFIG_FILENAMES module-attribute

_ALLOWED_CONFIG_FILENAMES = {
    "v2-inference-v.yaml",
    "v1-inference.yaml",
}

_BASELINE_NORMALIZATION_MAP module-attribute

_BASELINE_NORMALIZATION_MAP = {
    "stable diffusion 1": "stable_diffusion_1",
    "stable diffusion 2": "stable_diffusion_2_768",
    "stable diffusion 2 512": "stable_diffusion_2_512",
    "stable_diffusion_xl": "stable_diffusion_xl",
    "stable_cascade": "stable_cascade",
}

LegacyRecordUnion module-attribute

LegacyRecordUnion = (
    LegacyStableDiffusionRecord
    | LegacyTextGenerationRecord
    | LegacyBlipRecord
    | LegacyClipRecord
    | LegacyCodeformerRecord
    | LegacyControlnetRecord
    | LegacyEsrganRecord
    | LegacyGfpganRecord
    | LegacyGenericRecord
    | LegacySafetyCheckerRecord
    | LegacyMiscellaneousRecord
)

LegacyConfigFile

Bases: BaseModel

A single legacy config file entry.

Source code in src/horde_model_reference/legacy/classes/legacy_models.py
class LegacyConfigFile(BaseModel):
    """A single legacy config file entry."""

    model_config = ConfigDict(extra="allow")

    path: str
    md5sum: str | None = None
    sha256sum: str | None = None
    file_type: str | None = None
    content_hash: str | None = None
    """The normalized tensor-region content hash of this component file (distinct from the whole-file
    ``sha256sum``): the cross-platform-stable identity used for cross-process sharing. ``None`` when unknown
    or unhashable."""

    @model_validator(mode="after")
    def _ensure_sha256sum_for_model_files(self, info: ValidationInfo) -> LegacyConfigFile:
        if not self.path:
            _record_issue(info, "has a config file with no path.")
            return self
        if ".yaml" in self.path or ".json" in self.path:
            return self
        if ".ckpt" not in self.path:
            _record_issue(info, "has a config file with an invalid path.")
        if self.sha256sum is None:
            _record_issue(info, "has a config file with no sha256sum.")
        return self

    @model_serializer(mode="wrap", when_used="always")
    def _serialize_without_none(self, handler: SerializerFunctionWrapHandler) -> dict[str, Any]:
        return _drop_none_keys(handler, self)

model_config class-attribute instance-attribute

model_config = ConfigDict(extra='allow')

path instance-attribute

path: str

md5sum class-attribute instance-attribute

md5sum: str | None = None

sha256sum class-attribute instance-attribute

sha256sum: str | None = None

file_type class-attribute instance-attribute

file_type: str | None = None

content_hash class-attribute instance-attribute

content_hash: str | None = None

The normalized tensor-region content hash of this component file (distinct from the whole-file sha256sum): the cross-platform-stable identity used for cross-process sharing. None when unknown or unhashable.

_ensure_sha256sum_for_model_files

_ensure_sha256sum_for_model_files(
    info: ValidationInfo,
) -> LegacyConfigFile
Source code in src/horde_model_reference/legacy/classes/legacy_models.py
@model_validator(mode="after")
def _ensure_sha256sum_for_model_files(self, info: ValidationInfo) -> LegacyConfigFile:
    if not self.path:
        _record_issue(info, "has a config file with no path.")
        return self
    if ".yaml" in self.path or ".json" in self.path:
        return self
    if ".ckpt" not in self.path:
        _record_issue(info, "has a config file with an invalid path.")
    if self.sha256sum is None:
        _record_issue(info, "has a config file with no sha256sum.")
    return self

_serialize_without_none

_serialize_without_none(
    handler: SerializerFunctionWrapHandler,
) -> dict[str, Any]
Source code in src/horde_model_reference/legacy/classes/legacy_models.py
@model_serializer(mode="wrap", when_used="always")
def _serialize_without_none(self, handler: SerializerFunctionWrapHandler) -> dict[str, Any]:
    return _drop_none_keys(handler, self)

LegacyConfigDownload

Bases: BaseModel

A single legacy config download entry.

Source code in src/horde_model_reference/legacy/classes/legacy_models.py
class LegacyConfigDownload(BaseModel):
    """A single legacy config download entry."""

    model_config = ConfigDict(extra="allow")

    file_name: str | None = None
    file_path: str | None = ""
    file_url: str | None = None

    @model_validator(mode="after")
    def _validate_download_fields(self, info: ValidationInfo) -> LegacyConfigDownload:
        if not self.file_name:
            _record_issue(info, "has a download with no file_name.")
        if not self.file_url:
            category = None
            if info.context is not None:
                category = info.context.get("category")
            if category != MODEL_REFERENCE_CATEGORY.clip:
                _record_issue(info, "has a download with no file_url.")
        return self

    @model_serializer(mode="wrap", when_used="always")
    def _serialize_without_none(self, handler: SerializerFunctionWrapHandler) -> dict[str, Any]:
        return _drop_none_keys(handler, self)

model_config class-attribute instance-attribute

model_config = ConfigDict(extra='allow')

file_name class-attribute instance-attribute

file_name: str | None = None

file_path class-attribute instance-attribute

file_path: str | None = ''

file_url class-attribute instance-attribute

file_url: str | None = None

_validate_download_fields

_validate_download_fields(
    info: ValidationInfo,
) -> LegacyConfigDownload
Source code in src/horde_model_reference/legacy/classes/legacy_models.py
@model_validator(mode="after")
def _validate_download_fields(self, info: ValidationInfo) -> LegacyConfigDownload:
    if not self.file_name:
        _record_issue(info, "has a download with no file_name.")
    if not self.file_url:
        category = None
        if info.context is not None:
            category = info.context.get("category")
        if category != MODEL_REFERENCE_CATEGORY.clip:
            _record_issue(info, "has a download with no file_url.")
    return self

_serialize_without_none

_serialize_without_none(
    handler: SerializerFunctionWrapHandler,
) -> dict[str, Any]
Source code in src/horde_model_reference/legacy/classes/legacy_models.py
@model_serializer(mode="wrap", when_used="always")
def _serialize_without_none(self, handler: SerializerFunctionWrapHandler) -> dict[str, Any]:
    return _drop_none_keys(handler, self)

LegacyConfig

Bases: BaseModel

Typed representation of the legacy config payload.

Source code in src/horde_model_reference/legacy/classes/legacy_models.py
class LegacyConfig(BaseModel):
    """Typed representation of the legacy `config` payload."""

    model_config = ConfigDict(extra="ignore")

    files: list[LegacyConfigFile] = Field(default_factory=list)
    download: list[LegacyConfigDownload] = Field(default_factory=list)
    embedded_component_hashes: dict[str, str] | None = None
    """Maps a component kind (``vae``, ``text_encoders``) to the tensor-region content hash of that component
    embedded in the primary checkpoint: the cross-platform-stable identity for cross-process sharing. ``None``
    when the model embeds no shareable component or is unhashable."""

    @classmethod
    def _coerce_config_dict(cls, value: object, info: ValidationInfo) -> dict[str, Any]:
        if value is None:
            return {}
        if not isinstance(value, dict):
            raise TypeError("config entries must be provided as a mapping")
        raw_dict: dict[str, object] = {str(k): v for k, v in value.items()}
        # The embedded-hash maps are legitimate extra config entries, not part of the legacy files/download
        # pair the ">2 entries" heuristic guards against.
        embedded_keys = ("embedded_component_hashes",)
        countable = {key: value for key, value in raw_dict.items() if key not in embedded_keys}
        if len(countable) > 2:
            _record_issue(info, "has more than 2 config entries.")
        coerced: dict[str, Any] = {}
        for key in ("files", "download"):
            entries = raw_dict.get(key) or []
            if not isinstance(entries, Iterable):
                raise TypeError(f"config[{key!s}] must be iterable")
            coerced[key] = list(entries)
        for key in embedded_keys:
            if raw_dict.get(key) is not None:
                coerced[key] = raw_dict[key]
        return coerced

    _coerce_config_dict = model_validator(mode="before")(_coerce_config_dict)  # type: ignore[assignment]  # Pydantic wraps the classmethod in a descriptor proxy

    @model_validator(mode="after")
    def _normalize_entries(self, info: ValidationInfo) -> LegacyConfig:
        sha_lookup: dict[str, str] = {}

        for file_entry in self.files:
            if not file_entry.path:
                _record_issue(info, "has a config file with no path.")
                continue
            path_obj = Path(file_entry.path)
            if path_obj.suffix == ".yaml":
                if path_obj.name not in _ALLOWED_CONFIG_FILENAMES:
                    _record_issue(info, "has a non-standard config file.")
                continue
            if ".ckpt" not in file_entry.path:
                _record_issue(info, "has a config file with an invalid path.")
            if not file_entry.sha256sum:
                _record_issue(info, "has a config file with no sha256sum.")
            else:
                if len(file_entry.sha256sum) != 64:
                    _record_issue(info, "has a config file with an invalid sha256sum.")
                sha_lookup[file_entry.path] = file_entry.sha256sum

        for download_entry in self.download:
            if download_entry.file_path is None:
                _record_issue(info, "has a download with a file_path.")
                download_entry.file_path = ""
            elif download_entry.file_path != "":
                _record_issue(info, "has a download with a file_path.")
            if not download_entry.file_url:
                continue
            try:
                parsed_url = urllib.parse.urlparse(download_entry.file_url)
            except Exception:
                _record_issue(info, "has a download with an invalid file_url.")
                raise ValueError("invalid download url") from None
            _increment_host_counter(info, parsed_url.netloc)

        return self

    def is_empty(self) -> bool:
        """Return True when no download entries survive normalization.

        Note: files are always cleared during normalization (new format doesn't use them).
        """
        return len(self.download) == 0

    @model_serializer(mode="wrap", when_used="always")
    def _serialize_without_none(self, handler: SerializerFunctionWrapHandler) -> dict[str, Any]:
        """Drop ``None`` keys so an absent ``embedded_component_hashes`` is omitted, not emitted as null."""
        return _drop_none_keys(handler, self)

model_config class-attribute instance-attribute

model_config = ConfigDict(extra='ignore')

files class-attribute instance-attribute

files: list[LegacyConfigFile] = Field(default_factory=list)

download class-attribute instance-attribute

download: list[LegacyConfigDownload] = Field(
    default_factory=list
)

embedded_component_hashes class-attribute instance-attribute

embedded_component_hashes: dict[str, str] | None = None

Maps a component kind (vae, text_encoders) to the tensor-region content hash of that component embedded in the primary checkpoint: the cross-platform-stable identity for cross-process sharing. None when the model embeds no shareable component or is unhashable.

_coerce_config_dict class-attribute classmethod instance-attribute

_coerce_config_dict: dict[str, Any] = model_validator(
    mode="before"
)(_coerce_config_dict)

_normalize_entries

_normalize_entries(info: ValidationInfo) -> LegacyConfig
Source code in src/horde_model_reference/legacy/classes/legacy_models.py
@model_validator(mode="after")
def _normalize_entries(self, info: ValidationInfo) -> LegacyConfig:
    sha_lookup: dict[str, str] = {}

    for file_entry in self.files:
        if not file_entry.path:
            _record_issue(info, "has a config file with no path.")
            continue
        path_obj = Path(file_entry.path)
        if path_obj.suffix == ".yaml":
            if path_obj.name not in _ALLOWED_CONFIG_FILENAMES:
                _record_issue(info, "has a non-standard config file.")
            continue
        if ".ckpt" not in file_entry.path:
            _record_issue(info, "has a config file with an invalid path.")
        if not file_entry.sha256sum:
            _record_issue(info, "has a config file with no sha256sum.")
        else:
            if len(file_entry.sha256sum) != 64:
                _record_issue(info, "has a config file with an invalid sha256sum.")
            sha_lookup[file_entry.path] = file_entry.sha256sum

    for download_entry in self.download:
        if download_entry.file_path is None:
            _record_issue(info, "has a download with a file_path.")
            download_entry.file_path = ""
        elif download_entry.file_path != "":
            _record_issue(info, "has a download with a file_path.")
        if not download_entry.file_url:
            continue
        try:
            parsed_url = urllib.parse.urlparse(download_entry.file_url)
        except Exception:
            _record_issue(info, "has a download with an invalid file_url.")
            raise ValueError("invalid download url") from None
        _increment_host_counter(info, parsed_url.netloc)

    return self

is_empty

is_empty() -> bool

Return True when no download entries survive normalization.

Note: files are always cleared during normalization (new format doesn't use them).

Source code in src/horde_model_reference/legacy/classes/legacy_models.py
def is_empty(self) -> bool:
    """Return True when no download entries survive normalization.

    Note: files are always cleared during normalization (new format doesn't use them).
    """
    return len(self.download) == 0

_serialize_without_none

_serialize_without_none(
    handler: SerializerFunctionWrapHandler,
) -> dict[str, Any]

Drop None keys so an absent embedded_component_hashes is omitted, not emitted as null.

Source code in src/horde_model_reference/legacy/classes/legacy_models.py
@model_serializer(mode="wrap", when_used="always")
def _serialize_without_none(self, handler: SerializerFunctionWrapHandler) -> dict[str, Any]:
    """Drop ``None`` keys so an absent ``embedded_component_hashes`` is omitted, not emitted as null."""
    return _drop_none_keys(handler, self)

LegacyGenericRecord

Bases: BaseModel

Base legacy record representation with shared validation rules.

Source code in src/horde_model_reference/legacy/classes/legacy_models.py
class LegacyGenericRecord(BaseModel):
    """Base legacy record representation with shared validation rules."""

    model_config = ConfigDict(extra="allow", frozen=True)

    name: str
    type: str | None = None
    description: str | None = None
    version: str | None = None
    style: str | None = None
    nsfw: bool | None = None
    download_all: bool | None = None
    config: LegacyConfig = Field(default_factory=LegacyConfig)
    available: bool | None = None
    features_not_supported: list[str] | None = None

    @model_validator(mode="after")
    def _validate_common_rules(self, info: ValidationInfo) -> LegacyGenericRecord:
        model_key = None
        debug_mode = False
        if info.context is not None:
            model_key = info.context.get("model_key")
            debug_mode = bool(info.context.get("debug_mode"))
        if model_key and self.name != model_key:
            _record_issue(info, "name mismatch.")
        if self.available:
            _record_issue(info, "is flagged 'available'.")
        if self.download_all and debug_mode:
            _record_issue(info, "has download_all set.")
        if self.config.is_empty():
            _record_issue(info, "has no config.")
        if self.description is None:
            _record_issue(info, "has no description.")
        if self.style == "":
            _record_issue(info, "has no style.")
        return self

model_config class-attribute instance-attribute

model_config = ConfigDict(extra='allow', frozen=True)

name instance-attribute

name: str

type class-attribute instance-attribute

type: str | None = None

description class-attribute instance-attribute

description: str | None = None

version class-attribute instance-attribute

version: str | None = None

style class-attribute instance-attribute

style: str | None = None

nsfw class-attribute instance-attribute

nsfw: bool | None = None

download_all class-attribute instance-attribute

download_all: bool | None = None

config class-attribute instance-attribute

config: LegacyConfig = Field(default_factory=LegacyConfig)

available class-attribute instance-attribute

available: bool | None = None

features_not_supported class-attribute instance-attribute

features_not_supported: list[str] | None = None

_validate_common_rules

_validate_common_rules(
    info: ValidationInfo,
) -> LegacyGenericRecord
Source code in src/horde_model_reference/legacy/classes/legacy_models.py
@model_validator(mode="after")
def _validate_common_rules(self, info: ValidationInfo) -> LegacyGenericRecord:
    model_key = None
    debug_mode = False
    if info.context is not None:
        model_key = info.context.get("model_key")
        debug_mode = bool(info.context.get("debug_mode"))
    if model_key and self.name != model_key:
        _record_issue(info, "name mismatch.")
    if self.available:
        _record_issue(info, "is flagged 'available'.")
    if self.download_all and debug_mode:
        _record_issue(info, "has download_all set.")
    if self.config.is_empty():
        _record_issue(info, "has no config.")
    if self.description is None:
        _record_issue(info, "has no description.")
    if self.style == "":
        _record_issue(info, "has no style.")
    return self

LegacyStableDiffusionRecord

Bases: LegacyGenericRecord

Stable Diffusion legacy record with category-specific validation.

Source code in src/horde_model_reference/legacy/classes/legacy_models.py
class LegacyStableDiffusionRecord(LegacyGenericRecord):
    """Stable Diffusion legacy record with category-specific validation."""

    type: Literal["ckpt"] = "ckpt"
    inpainting: bool = False
    baseline: str
    tags: list[str] | None = None
    showcases: list[str] | None = None
    min_bridge_version: int | None = None
    trigger: list[str] | None = None
    homepage: str | None = None
    size_on_disk_bytes: int | None = None
    optimization: str | None = None
    requirements: dict[str, int | float | str | list[int] | list[float] | list[str] | bool] | None = None

    @field_validator("baseline", mode="before")
    def _normalize_baseline(cls, value: str) -> str:
        if value in _BASELINE_NORMALIZATION_MAP:
            return _BASELINE_NORMALIZATION_MAP[value]
        return value

    @field_validator("showcases", mode="before")
    def _validate_showcases(cls, value: list[str] | None) -> list[str] | None:
        if value is None:
            return value
        for showcase in value:
            if "huggingface" in showcase:
                raise ValueError("huggingface showcases are not allowed")
        return value

    # Non-mutating "after" validator to enforce Stable Diffusion specific rules and record issues without raising
    # and respecting the "frozen" model config (legacy models are immutable after validation)
    @model_validator(mode="after")
    def _validate_stable_diffusion_rules(self, info: ValidationInfo) -> LegacyStableDiffusionRecord:
        if self.baseline not in _BASELINE_NORMALIZATION_MAP.values():
            _record_issue(info, "has an unrecognized baseline.")
        if self.showcases is None or len(self.showcases) == 0:
            _record_issue(info, "has no showcases defined.")
        if self.showcases is not None and any("huggingface" in showcase for showcase in self.showcases):
            _record_issue(info, "has a huggingface showcase.")

        on_disk_showcases: list[str] | None = None
        if info.context is not None:
            existing_showcases: dict[str, list[str]] = info.context.get("existing_showcase_files", {})
            model_key = info.context.get("model_key", self.name)
            expected_showcase_foldername = model_name_to_showcase_folder_name(model_key)
            on_disk_showcases = existing_showcases.get(expected_showcase_foldername)

        if (
            self.showcases is not None
            and on_disk_showcases is not None
            and len(self.showcases) != len(on_disk_showcases)
        ):
            _record_issue(
                info,
                "has a mismatch between defined showcases and the files present on disk.",
            )

        return self

    @model_serializer(when_used="always")
    def sort_model_fields(self) -> dict[str, Any]:
        """Sort fields for consistent JSON output."""
        field_order = [
            "name",
            "baseline",
            "optimization",
            "type",
            "inpainting",
            "description",
            "tags",
            "showcases",
            "version",
            "style",
            "trigger",
            "homepage",
            "nsfw",
            "download_all",
            "requirements",
            "config",
            "available",
            "features_not_supported",
            "size_on_disk_bytes",
        ]

        return_dict = {
            field: getattr(self, field)
            for field in field_order
            if hasattr(self, field) and getattr(self, field) is not None
        }

        # translate _BASELINE_NORMALIZATION_MAP keys back to their original values for output
        if "baseline" in return_dict:
            for original, normalized in _BASELINE_NORMALIZATION_MAP.items():
                if return_dict["baseline"] == normalized:
                    return_dict["baseline"] = original
                    break

        return return_dict

type class-attribute instance-attribute

type: Literal['ckpt'] = 'ckpt'

inpainting class-attribute instance-attribute

inpainting: bool = False

baseline instance-attribute

baseline: str

tags class-attribute instance-attribute

tags: list[str] | None = None

showcases class-attribute instance-attribute

showcases: list[str] | None = None

min_bridge_version class-attribute instance-attribute

min_bridge_version: int | None = None

trigger class-attribute instance-attribute

trigger: list[str] | None = None

homepage class-attribute instance-attribute

homepage: str | None = None

size_on_disk_bytes class-attribute instance-attribute

size_on_disk_bytes: int | None = None

optimization class-attribute instance-attribute

optimization: str | None = None

requirements class-attribute instance-attribute

requirements: (
    dict[
        str,
        int
        | float
        | str
        | list[int]
        | list[float]
        | list[str]
        | bool,
    ]
    | None
) = None

model_config class-attribute instance-attribute

model_config = ConfigDict(extra='allow', frozen=True)

name instance-attribute

name: str

description class-attribute instance-attribute

description: str | None = None

version class-attribute instance-attribute

version: str | None = None

style class-attribute instance-attribute

style: str | None = None

nsfw class-attribute instance-attribute

nsfw: bool | None = None

download_all class-attribute instance-attribute

download_all: bool | None = None

config class-attribute instance-attribute

config: LegacyConfig = Field(default_factory=LegacyConfig)

available class-attribute instance-attribute

available: bool | None = None

features_not_supported class-attribute instance-attribute

features_not_supported: list[str] | None = None

_normalize_baseline

_normalize_baseline(value: str) -> str
Source code in src/horde_model_reference/legacy/classes/legacy_models.py
@field_validator("baseline", mode="before")
def _normalize_baseline(cls, value: str) -> str:
    if value in _BASELINE_NORMALIZATION_MAP:
        return _BASELINE_NORMALIZATION_MAP[value]
    return value

_validate_showcases

_validate_showcases(
    value: list[str] | None,
) -> list[str] | None
Source code in src/horde_model_reference/legacy/classes/legacy_models.py
@field_validator("showcases", mode="before")
def _validate_showcases(cls, value: list[str] | None) -> list[str] | None:
    if value is None:
        return value
    for showcase in value:
        if "huggingface" in showcase:
            raise ValueError("huggingface showcases are not allowed")
    return value

_validate_stable_diffusion_rules

_validate_stable_diffusion_rules(
    info: ValidationInfo,
) -> LegacyStableDiffusionRecord
Source code in src/horde_model_reference/legacy/classes/legacy_models.py
@model_validator(mode="after")
def _validate_stable_diffusion_rules(self, info: ValidationInfo) -> LegacyStableDiffusionRecord:
    if self.baseline not in _BASELINE_NORMALIZATION_MAP.values():
        _record_issue(info, "has an unrecognized baseline.")
    if self.showcases is None or len(self.showcases) == 0:
        _record_issue(info, "has no showcases defined.")
    if self.showcases is not None and any("huggingface" in showcase for showcase in self.showcases):
        _record_issue(info, "has a huggingface showcase.")

    on_disk_showcases: list[str] | None = None
    if info.context is not None:
        existing_showcases: dict[str, list[str]] = info.context.get("existing_showcase_files", {})
        model_key = info.context.get("model_key", self.name)
        expected_showcase_foldername = model_name_to_showcase_folder_name(model_key)
        on_disk_showcases = existing_showcases.get(expected_showcase_foldername)

    if (
        self.showcases is not None
        and on_disk_showcases is not None
        and len(self.showcases) != len(on_disk_showcases)
    ):
        _record_issue(
            info,
            "has a mismatch between defined showcases and the files present on disk.",
        )

    return self

sort_model_fields

sort_model_fields() -> dict[str, Any]

Sort fields for consistent JSON output.

Source code in src/horde_model_reference/legacy/classes/legacy_models.py
@model_serializer(when_used="always")
def sort_model_fields(self) -> dict[str, Any]:
    """Sort fields for consistent JSON output."""
    field_order = [
        "name",
        "baseline",
        "optimization",
        "type",
        "inpainting",
        "description",
        "tags",
        "showcases",
        "version",
        "style",
        "trigger",
        "homepage",
        "nsfw",
        "download_all",
        "requirements",
        "config",
        "available",
        "features_not_supported",
        "size_on_disk_bytes",
    ]

    return_dict = {
        field: getattr(self, field)
        for field in field_order
        if hasattr(self, field) and getattr(self, field) is not None
    }

    # translate _BASELINE_NORMALIZATION_MAP keys back to their original values for output
    if "baseline" in return_dict:
        for original, normalized in _BASELINE_NORMALIZATION_MAP.items():
            if return_dict["baseline"] == normalized:
                return_dict["baseline"] = original
                break

    return return_dict

_validate_common_rules

_validate_common_rules(
    info: ValidationInfo,
) -> LegacyGenericRecord
Source code in src/horde_model_reference/legacy/classes/legacy_models.py
@model_validator(mode="after")
def _validate_common_rules(self, info: ValidationInfo) -> LegacyGenericRecord:
    model_key = None
    debug_mode = False
    if info.context is not None:
        model_key = info.context.get("model_key")
        debug_mode = bool(info.context.get("debug_mode"))
    if model_key and self.name != model_key:
        _record_issue(info, "name mismatch.")
    if self.available:
        _record_issue(info, "is flagged 'available'.")
    if self.download_all and debug_mode:
        _record_issue(info, "has download_all set.")
    if self.config.is_empty():
        _record_issue(info, "has no config.")
    if self.description is None:
        _record_issue(info, "has no description.")
    if self.style == "":
        _record_issue(info, "has no style.")
    return self

LegacyTextGenerationRecord

Bases: LegacyGenericRecord

Text generation legacy record with category-specific validation.

Source code in src/horde_model_reference/legacy/classes/legacy_models.py
class LegacyTextGenerationRecord(LegacyGenericRecord):
    """Text generation legacy record with category-specific validation."""

    model_name: str | None = None
    baseline: str | None = None
    parameters: int | None = None
    display_name: str | None = None
    url: str | None = None
    tags: list[str] | None = None
    instruct_format: str | None = None
    settings: dict[str, int | float | str | list[int] | list[float] | list[str] | bool] | None = None

    @model_validator(mode="after")
    def _validate_text_generation_rules(self, info: ValidationInfo) -> LegacyTextGenerationRecord:
        """Validate text generation specific rules."""
        if self.parameters is None:
            _record_issue(info, "has no parameters count.")
        return self

model_name class-attribute instance-attribute

model_name: str | None = None

baseline class-attribute instance-attribute

baseline: str | None = None

parameters class-attribute instance-attribute

parameters: int | None = None

display_name class-attribute instance-attribute

display_name: str | None = None

url class-attribute instance-attribute

url: str | None = None

tags class-attribute instance-attribute

tags: list[str] | None = None

instruct_format class-attribute instance-attribute

instruct_format: str | None = None

settings class-attribute instance-attribute

settings: (
    dict[
        str,
        int
        | float
        | str
        | list[int]
        | list[float]
        | list[str]
        | bool,
    ]
    | None
) = None

model_config class-attribute instance-attribute

model_config = ConfigDict(extra='allow', frozen=True)

name instance-attribute

name: str

type class-attribute instance-attribute

type: str | None = None

description class-attribute instance-attribute

description: str | None = None

version class-attribute instance-attribute

version: str | None = None

style class-attribute instance-attribute

style: str | None = None

nsfw class-attribute instance-attribute

nsfw: bool | None = None

download_all class-attribute instance-attribute

download_all: bool | None = None

config class-attribute instance-attribute

config: LegacyConfig = Field(default_factory=LegacyConfig)

available class-attribute instance-attribute

available: bool | None = None

features_not_supported class-attribute instance-attribute

features_not_supported: list[str] | None = None

_validate_text_generation_rules

_validate_text_generation_rules(
    info: ValidationInfo,
) -> LegacyTextGenerationRecord

Validate text generation specific rules.

Source code in src/horde_model_reference/legacy/classes/legacy_models.py
@model_validator(mode="after")
def _validate_text_generation_rules(self, info: ValidationInfo) -> LegacyTextGenerationRecord:
    """Validate text generation specific rules."""
    if self.parameters is None:
        _record_issue(info, "has no parameters count.")
    return self

_validate_common_rules

_validate_common_rules(
    info: ValidationInfo,
) -> LegacyGenericRecord
Source code in src/horde_model_reference/legacy/classes/legacy_models.py
@model_validator(mode="after")
def _validate_common_rules(self, info: ValidationInfo) -> LegacyGenericRecord:
    model_key = None
    debug_mode = False
    if info.context is not None:
        model_key = info.context.get("model_key")
        debug_mode = bool(info.context.get("debug_mode"))
    if model_key and self.name != model_key:
        _record_issue(info, "name mismatch.")
    if self.available:
        _record_issue(info, "is flagged 'available'.")
    if self.download_all and debug_mode:
        _record_issue(info, "has download_all set.")
    if self.config.is_empty():
        _record_issue(info, "has no config.")
    if self.description is None:
        _record_issue(info, "has no description.")
    if self.style == "":
        _record_issue(info, "has no style.")
    return self

LegacyBlipRecord

Bases: LegacyGenericRecord

BLIP legacy record with category-specific normalization.

Source code in src/horde_model_reference/legacy/classes/legacy_models.py
class LegacyBlipRecord(LegacyGenericRecord):
    """BLIP legacy record with category-specific normalization."""

    type: Literal["blip"] = "blip"

type class-attribute instance-attribute

type: Literal['blip'] = 'blip'

model_config class-attribute instance-attribute

model_config = ConfigDict(extra='allow', frozen=True)

name instance-attribute

name: str

description class-attribute instance-attribute

description: str | None = None

version class-attribute instance-attribute

version: str | None = None

style class-attribute instance-attribute

style: str | None = None

nsfw class-attribute instance-attribute

nsfw: bool | None = None

download_all class-attribute instance-attribute

download_all: bool | None = None

config class-attribute instance-attribute

config: LegacyConfig = Field(default_factory=LegacyConfig)

available class-attribute instance-attribute

available: bool | None = None

features_not_supported class-attribute instance-attribute

features_not_supported: list[str] | None = None

_validate_common_rules

_validate_common_rules(
    info: ValidationInfo,
) -> LegacyGenericRecord
Source code in src/horde_model_reference/legacy/classes/legacy_models.py
@model_validator(mode="after")
def _validate_common_rules(self, info: ValidationInfo) -> LegacyGenericRecord:
    model_key = None
    debug_mode = False
    if info.context is not None:
        model_key = info.context.get("model_key")
        debug_mode = bool(info.context.get("debug_mode"))
    if model_key and self.name != model_key:
        _record_issue(info, "name mismatch.")
    if self.available:
        _record_issue(info, "is flagged 'available'.")
    if self.download_all and debug_mode:
        _record_issue(info, "has download_all set.")
    if self.config.is_empty():
        _record_issue(info, "has no config.")
    if self.description is None:
        _record_issue(info, "has no description.")
    if self.style == "":
        _record_issue(info, "has no style.")
    return self

LegacyClipRecord

Bases: LegacyGenericRecord

CLIP legacy record with category-specific normalization.

Source code in src/horde_model_reference/legacy/classes/legacy_models.py
class LegacyClipRecord(LegacyGenericRecord):
    """CLIP legacy record with category-specific normalization."""

    type: Literal["clip", "coca"] = "clip"
    pretrained_name: str | None = None

type class-attribute instance-attribute

type: Literal['clip', 'coca'] = 'clip'

pretrained_name class-attribute instance-attribute

pretrained_name: str | None = None

model_config class-attribute instance-attribute

model_config = ConfigDict(extra='allow', frozen=True)

name instance-attribute

name: str

description class-attribute instance-attribute

description: str | None = None

version class-attribute instance-attribute

version: str | None = None

style class-attribute instance-attribute

style: str | None = None

nsfw class-attribute instance-attribute

nsfw: bool | None = None

download_all class-attribute instance-attribute

download_all: bool | None = None

config class-attribute instance-attribute

config: LegacyConfig = Field(default_factory=LegacyConfig)

available class-attribute instance-attribute

available: bool | None = None

features_not_supported class-attribute instance-attribute

features_not_supported: list[str] | None = None

_validate_common_rules

_validate_common_rules(
    info: ValidationInfo,
) -> LegacyGenericRecord
Source code in src/horde_model_reference/legacy/classes/legacy_models.py
@model_validator(mode="after")
def _validate_common_rules(self, info: ValidationInfo) -> LegacyGenericRecord:
    model_key = None
    debug_mode = False
    if info.context is not None:
        model_key = info.context.get("model_key")
        debug_mode = bool(info.context.get("debug_mode"))
    if model_key and self.name != model_key:
        _record_issue(info, "name mismatch.")
    if self.available:
        _record_issue(info, "is flagged 'available'.")
    if self.download_all and debug_mode:
        _record_issue(info, "has download_all set.")
    if self.config.is_empty():
        _record_issue(info, "has no config.")
    if self.description is None:
        _record_issue(info, "has no description.")
    if self.style == "":
        _record_issue(info, "has no style.")
    return self

LegacyCodeformerRecord

Bases: LegacyGenericRecord

Codeformers legacy record with category-specific normalization.

Source code in src/horde_model_reference/legacy/classes/legacy_models.py
class LegacyCodeformerRecord(LegacyGenericRecord):
    """Codeformers legacy record with category-specific normalization."""

    type: Literal["CodeFormers"] = "CodeFormers"

type class-attribute instance-attribute

type: Literal['CodeFormers'] = 'CodeFormers'

model_config class-attribute instance-attribute

model_config = ConfigDict(extra='allow', frozen=True)

name instance-attribute

name: str

description class-attribute instance-attribute

description: str | None = None

version class-attribute instance-attribute

version: str | None = None

style class-attribute instance-attribute

style: str | None = None

nsfw class-attribute instance-attribute

nsfw: bool | None = None

download_all class-attribute instance-attribute

download_all: bool | None = None

config class-attribute instance-attribute

config: LegacyConfig = Field(default_factory=LegacyConfig)

available class-attribute instance-attribute

available: bool | None = None

features_not_supported class-attribute instance-attribute

features_not_supported: list[str] | None = None

_validate_common_rules

_validate_common_rules(
    info: ValidationInfo,
) -> LegacyGenericRecord
Source code in src/horde_model_reference/legacy/classes/legacy_models.py
@model_validator(mode="after")
def _validate_common_rules(self, info: ValidationInfo) -> LegacyGenericRecord:
    model_key = None
    debug_mode = False
    if info.context is not None:
        model_key = info.context.get("model_key")
        debug_mode = bool(info.context.get("debug_mode"))
    if model_key and self.name != model_key:
        _record_issue(info, "name mismatch.")
    if self.available:
        _record_issue(info, "is flagged 'available'.")
    if self.download_all and debug_mode:
        _record_issue(info, "has download_all set.")
    if self.config.is_empty():
        _record_issue(info, "has no config.")
    if self.description is None:
        _record_issue(info, "has no description.")
    if self.style == "":
        _record_issue(info, "has no style.")
    return self

LegacyEsrganRecord

Bases: LegacyGenericRecord

ESRGAN legacy record with category-specific normalization.

Source code in src/horde_model_reference/legacy/classes/legacy_models.py
class LegacyEsrganRecord(LegacyGenericRecord):
    """ESRGAN legacy record with category-specific normalization."""

    type: Literal["realesrgan"] = "realesrgan"

type class-attribute instance-attribute

type: Literal['realesrgan'] = 'realesrgan'

model_config class-attribute instance-attribute

model_config = ConfigDict(extra='allow', frozen=True)

name instance-attribute

name: str

description class-attribute instance-attribute

description: str | None = None

version class-attribute instance-attribute

version: str | None = None

style class-attribute instance-attribute

style: str | None = None

nsfw class-attribute instance-attribute

nsfw: bool | None = None

download_all class-attribute instance-attribute

download_all: bool | None = None

config class-attribute instance-attribute

config: LegacyConfig = Field(default_factory=LegacyConfig)

available class-attribute instance-attribute

available: bool | None = None

features_not_supported class-attribute instance-attribute

features_not_supported: list[str] | None = None

_validate_common_rules

_validate_common_rules(
    info: ValidationInfo,
) -> LegacyGenericRecord
Source code in src/horde_model_reference/legacy/classes/legacy_models.py
@model_validator(mode="after")
def _validate_common_rules(self, info: ValidationInfo) -> LegacyGenericRecord:
    model_key = None
    debug_mode = False
    if info.context is not None:
        model_key = info.context.get("model_key")
        debug_mode = bool(info.context.get("debug_mode"))
    if model_key and self.name != model_key:
        _record_issue(info, "name mismatch.")
    if self.available:
        _record_issue(info, "is flagged 'available'.")
    if self.download_all and debug_mode:
        _record_issue(info, "has download_all set.")
    if self.config.is_empty():
        _record_issue(info, "has no config.")
    if self.description is None:
        _record_issue(info, "has no description.")
    if self.style == "":
        _record_issue(info, "has no style.")
    return self

LegacyGfpganRecord

Bases: LegacyGenericRecord

GFPGAN legacy record with category-specific normalization.

Source code in src/horde_model_reference/legacy/classes/legacy_models.py
class LegacyGfpganRecord(LegacyGenericRecord):
    """GFPGAN legacy record with category-specific normalization."""

    type: Literal["gfpgan"] = "gfpgan"

type class-attribute instance-attribute

type: Literal['gfpgan'] = 'gfpgan'

model_config class-attribute instance-attribute

model_config = ConfigDict(extra='allow', frozen=True)

name instance-attribute

name: str

description class-attribute instance-attribute

description: str | None = None

version class-attribute instance-attribute

version: str | None = None

style class-attribute instance-attribute

style: str | None = None

nsfw class-attribute instance-attribute

nsfw: bool | None = None

download_all class-attribute instance-attribute

download_all: bool | None = None

config class-attribute instance-attribute

config: LegacyConfig = Field(default_factory=LegacyConfig)

available class-attribute instance-attribute

available: bool | None = None

features_not_supported class-attribute instance-attribute

features_not_supported: list[str] | None = None

_validate_common_rules

_validate_common_rules(
    info: ValidationInfo,
) -> LegacyGenericRecord
Source code in src/horde_model_reference/legacy/classes/legacy_models.py
@model_validator(mode="after")
def _validate_common_rules(self, info: ValidationInfo) -> LegacyGenericRecord:
    model_key = None
    debug_mode = False
    if info.context is not None:
        model_key = info.context.get("model_key")
        debug_mode = bool(info.context.get("debug_mode"))
    if model_key and self.name != model_key:
        _record_issue(info, "name mismatch.")
    if self.available:
        _record_issue(info, "is flagged 'available'.")
    if self.download_all and debug_mode:
        _record_issue(info, "has download_all set.")
    if self.config.is_empty():
        _record_issue(info, "has no config.")
    if self.description is None:
        _record_issue(info, "has no description.")
    if self.style == "":
        _record_issue(info, "has no style.")
    return self

LegacySafetyCheckerRecord

Bases: LegacyGenericRecord

Safety Checker legacy record with category-specific normalization.

Source code in src/horde_model_reference/legacy/classes/legacy_models.py
class LegacySafetyCheckerRecord(LegacyGenericRecord):
    """Safety Checker legacy record with category-specific normalization."""

    type: Literal["safety_checker"] = "safety_checker"

type class-attribute instance-attribute

type: Literal['safety_checker'] = 'safety_checker'

model_config class-attribute instance-attribute

model_config = ConfigDict(extra='allow', frozen=True)

name instance-attribute

name: str

description class-attribute instance-attribute

description: str | None = None

version class-attribute instance-attribute

version: str | None = None

style class-attribute instance-attribute

style: str | None = None

nsfw class-attribute instance-attribute

nsfw: bool | None = None

download_all class-attribute instance-attribute

download_all: bool | None = None

config class-attribute instance-attribute

config: LegacyConfig = Field(default_factory=LegacyConfig)

available class-attribute instance-attribute

available: bool | None = None

features_not_supported class-attribute instance-attribute

features_not_supported: list[str] | None = None

_validate_common_rules

_validate_common_rules(
    info: ValidationInfo,
) -> LegacyGenericRecord
Source code in src/horde_model_reference/legacy/classes/legacy_models.py
@model_validator(mode="after")
def _validate_common_rules(self, info: ValidationInfo) -> LegacyGenericRecord:
    model_key = None
    debug_mode = False
    if info.context is not None:
        model_key = info.context.get("model_key")
        debug_mode = bool(info.context.get("debug_mode"))
    if model_key and self.name != model_key:
        _record_issue(info, "name mismatch.")
    if self.available:
        _record_issue(info, "is flagged 'available'.")
    if self.download_all and debug_mode:
        _record_issue(info, "has download_all set.")
    if self.config.is_empty():
        _record_issue(info, "has no config.")
    if self.description is None:
        _record_issue(info, "has no description.")
    if self.style == "":
        _record_issue(info, "has no style.")
    return self

LegacyMiscellaneousRecord

Bases: LegacyGenericRecord

Miscellaneous legacy record with category-specific normalization.

Source code in src/horde_model_reference/legacy/classes/legacy_models.py
class LegacyMiscellaneousRecord(LegacyGenericRecord):
    """Miscellaneous legacy record with category-specific normalization."""

    type: Literal["layer_diffuse"] = "layer_diffuse"

type class-attribute instance-attribute

type: Literal['layer_diffuse'] = 'layer_diffuse'

model_config class-attribute instance-attribute

model_config = ConfigDict(extra='allow', frozen=True)

name instance-attribute

name: str

description class-attribute instance-attribute

description: str | None = None

version class-attribute instance-attribute

version: str | None = None

style class-attribute instance-attribute

style: str | None = None

nsfw class-attribute instance-attribute

nsfw: bool | None = None

download_all class-attribute instance-attribute

download_all: bool | None = None

config class-attribute instance-attribute

config: LegacyConfig = Field(default_factory=LegacyConfig)

available class-attribute instance-attribute

available: bool | None = None

features_not_supported class-attribute instance-attribute

features_not_supported: list[str] | None = None

_validate_common_rules

_validate_common_rules(
    info: ValidationInfo,
) -> LegacyGenericRecord
Source code in src/horde_model_reference/legacy/classes/legacy_models.py
@model_validator(mode="after")
def _validate_common_rules(self, info: ValidationInfo) -> LegacyGenericRecord:
    model_key = None
    debug_mode = False
    if info.context is not None:
        model_key = info.context.get("model_key")
        debug_mode = bool(info.context.get("debug_mode"))
    if model_key and self.name != model_key:
        _record_issue(info, "name mismatch.")
    if self.available:
        _record_issue(info, "is flagged 'available'.")
    if self.download_all and debug_mode:
        _record_issue(info, "has download_all set.")
    if self.config.is_empty():
        _record_issue(info, "has no config.")
    if self.description is None:
        _record_issue(info, "has no description.")
    if self.style == "":
        _record_issue(info, "has no style.")
    return self

LegacyControlnetRecord

Bases: LegacyGenericRecord

ControlNet legacy record with category-specific normalization.

Source code in src/horde_model_reference/legacy/classes/legacy_models.py
class LegacyControlnetRecord(LegacyGenericRecord):
    """ControlNet legacy record with category-specific normalization."""

    type: Literal[
        "control_canny",
        "control_depth",
        "control_hed",
        "control_mlsd",
        "control_normal",
        "control_openpose",
        "control_fakescribbles",
        "control_scribble",
        "control_seg",
        "control_qr",
        "control_qr_xl",
        "control_lineart",
        "control_lineart_anime",
        "control_normal_bae",
        "control_recolor",
        "control_tile",
    ]

type instance-attribute

type: Literal[
    "control_canny",
    "control_depth",
    "control_hed",
    "control_mlsd",
    "control_normal",
    "control_openpose",
    "control_fakescribbles",
    "control_scribble",
    "control_seg",
    "control_qr",
    "control_qr_xl",
    "control_lineart",
    "control_lineart_anime",
    "control_normal_bae",
    "control_recolor",
    "control_tile",
]

model_config class-attribute instance-attribute

model_config = ConfigDict(extra='allow', frozen=True)

name instance-attribute

name: str

description class-attribute instance-attribute

description: str | None = None

version class-attribute instance-attribute

version: str | None = None

style class-attribute instance-attribute

style: str | None = None

nsfw class-attribute instance-attribute

nsfw: bool | None = None

download_all class-attribute instance-attribute

download_all: bool | None = None

config class-attribute instance-attribute

config: LegacyConfig = Field(default_factory=LegacyConfig)

available class-attribute instance-attribute

available: bool | None = None

features_not_supported class-attribute instance-attribute

features_not_supported: list[str] | None = None

_validate_common_rules

_validate_common_rules(
    info: ValidationInfo,
) -> LegacyGenericRecord
Source code in src/horde_model_reference/legacy/classes/legacy_models.py
@model_validator(mode="after")
def _validate_common_rules(self, info: ValidationInfo) -> LegacyGenericRecord:
    model_key = None
    debug_mode = False
    if info.context is not None:
        model_key = info.context.get("model_key")
        debug_mode = bool(info.context.get("debug_mode"))
    if model_key and self.name != model_key:
        _record_issue(info, "name mismatch.")
    if self.available:
        _record_issue(info, "is flagged 'available'.")
    if self.download_all and debug_mode:
        _record_issue(info, "has download_all set.")
    if self.config.is_empty():
        _record_issue(info, "has no config.")
    if self.description is None:
        _record_issue(info, "has no description.")
    if self.style == "":
        _record_issue(info, "has no style.")
    return self

_drop_none_keys

_drop_none_keys(
    handler: SerializerFunctionWrapHandler,
    instance: BaseModel,
) -> dict[str, Any]

Serialize instance and drop keys whose value is None.

The legacy GitHub JSON omits absent optional fields entirely (e.g. a config file entry with only path + sha256sum never carries md5sum/file_type). Pydantic's default serialization emits those as null, which would pollute the diff produced by the GitHub sync for newly added/modified models. Dropping None keys keeps API-written records byte-compatible with the hand-authored legacy format while preserving field order and any extra keys.

Source code in src/horde_model_reference/legacy/classes/legacy_models.py
def _drop_none_keys(handler: SerializerFunctionWrapHandler, instance: BaseModel) -> dict[str, Any]:
    """Serialize ``instance`` and drop keys whose value is ``None``.

    The legacy GitHub JSON omits absent optional fields entirely (e.g. a config file
    entry with only ``path`` + ``sha256sum`` never carries ``md5sum``/``file_type``).
    Pydantic's default serialization emits those as ``null``, which would pollute the
    diff produced by the GitHub sync for newly added/modified models. Dropping ``None``
    keys keeps API-written records byte-compatible with the hand-authored legacy format
    while preserving field order and any ``extra`` keys.
    """
    serialized = handler(instance)
    if not isinstance(serialized, dict):
        return serialized
    return {key: value for key, value in serialized.items() if value is not None}

_record_issue

_record_issue(info: ValidationInfo, message: str) -> None

Append a validation issue message to the shared conversion context.

Source code in src/horde_model_reference/legacy/classes/legacy_models.py
def _record_issue(info: ValidationInfo, message: str) -> None:
    """Append a validation issue message to the shared conversion context."""
    issues: list[str] | None = None
    if info.context is not None:
        issues = info.context.get("issues")
    if issues is None:
        return
    model_key = None
    if info.context is not None:
        model_key = info.context.get("model_key")
    if model_key:
        issues.append(f"{model_key} {message}")
    else:
        issues.append(message)

_increment_host_counter

_increment_host_counter(
    info: ValidationInfo, host: str
) -> None
Source code in src/horde_model_reference/legacy/classes/legacy_models.py
def _increment_host_counter(info: ValidationInfo, host: str) -> None:
    if info.context is None:
        return
    host_counter = info.context.get("host_counter")
    if isinstance(host_counter, dict):
        host_counter[host] = host_counter.get(host, 0) + 1

get_legacy_model_type

get_legacy_model_type(
    category: MODEL_REFERENCE_CATEGORY,
) -> type[LegacyRecordUnion]

Get the appropriate Pydantic model class for a given category.

Source code in src/horde_model_reference/legacy/classes/legacy_models.py
def get_legacy_model_type(category: MODEL_REFERENCE_CATEGORY) -> type[LegacyRecordUnion]:
    """Get the appropriate Pydantic model class for a given category."""
    category_model_map: dict[MODEL_REFERENCE_CATEGORY, type[LegacyRecordUnion]] = {
        MODEL_REFERENCE_CATEGORY.image_generation: LegacyStableDiffusionRecord,
        MODEL_REFERENCE_CATEGORY.text_generation: LegacyTextGenerationRecord,
        MODEL_REFERENCE_CATEGORY.blip: LegacyBlipRecord,
        MODEL_REFERENCE_CATEGORY.clip: LegacyClipRecord,
        MODEL_REFERENCE_CATEGORY.codeformer: LegacyCodeformerRecord,
        MODEL_REFERENCE_CATEGORY.controlnet: LegacyControlnetRecord,
        MODEL_REFERENCE_CATEGORY.esrgan: LegacyEsrganRecord,
        MODEL_REFERENCE_CATEGORY.gfpgan: LegacyGfpganRecord,
        MODEL_REFERENCE_CATEGORY.safety_checker: LegacySafetyCheckerRecord,
        MODEL_REFERENCE_CATEGORY.miscellaneous: LegacyMiscellaneousRecord,
    }
    return category_model_map.get(category, LegacyGenericRecord)