Source code for endoreg_db.models.metadata.model_meta
# filepath: /home/admin/dev/endo-ai/endoreg-db/endoreg_db/models/metadata/model_meta.py
"""
Defines the ModelMeta model and its manager for storing metadata related to AI models,
including versioning, configuration, and associated weights files.
Logic is primarily handled in model_meta_logic.py.
"""
from pathlib import Path
from typing import Optional, TYPE_CHECKING, List, Tuple, Dict, Any, Type
# Removed shutil import, now in logic
from django.db import models
from django.core.validators import FileExtensionValidator
from django.conf import settings
# Removed torch import, now in logic
# from torch import nn
from ..utils import WEIGHTS_DIR, STORAGE_DIR
# Import logic functions
from . import model_meta_logic as logic
if TYPE_CHECKING:
from endoreg_db.models import LabelSet, AiModel # pylint: disable=import-outside-toplevel
from torch.nn import Module as TorchModule
class ModelMetaManager(models.Manager):
"""
Custom manager for the ModelMeta model.
Provides methods for retrieving ModelMeta instances using natural keys.
"""
# ... existing code ...
[docs]
class ModelMeta(models.Model):
"""
Represents the metadata for a specific version of an AI model.
Logic for creation, querying, and configuration is in model_meta_logic.py.
"""
# ... (fields remain the same: name, version, model, labelset, activation, weights, mean, std, etc.) ...
# --- Model Identification ---
name = models.CharField(
max_length=255,
help_text="User-defined name for this specific model metadata set (e.g., 'segmentation_base').",
)
version = models.CharField(
max_length=255,
help_text="Version identifier for this metadata set (e.g., '1', '2a').",
)
model = models.ForeignKey(
"AiModel",
on_delete=models.CASCADE,
related_name="metadata_versions",
help_text="The base AI model architecture this metadata belongs to.",
)
# --- Model Configuration ---
labelset = models.ForeignKey(
"LabelSet",
on_delete=models.CASCADE,
related_name="model_metadata",
help_text="The set of labels this model version predicts.",
)
activation = models.CharField(
max_length=50, default="sigmoid", help_text="Output activation function (e.g., 'sigmoid', 'softmax', 'none')."
)
# weights = models.FileField(
from django.core.files.storage import FileSystemStorage
# from ..utils import WEIGHTS_DIR, STORAGE_DIR # Already imported
weights = models.FileField(
upload_to=WEIGHTS_DIR.relative_to(STORAGE_DIR).as_posix(), # Ensure posix path for consistency
validators=[FileExtensionValidator(allowed_extensions=["safetensors", "pth", "pt"])],
storage=FileSystemStorage(location=STORAGE_DIR),
null=True,
blank=True,
help_text="Path to the model weights file (.safetensors), relative to MEDIA_ROOT.",
)
# --- Normalization and Input Shape ---
mean = models.CharField(
max_length=255,
default="0.45211223,0.27139644,0.19264949",
help_text="Comma-separated mean values for input normalization.",
)
std = models.CharField(
max_length=255,
default="0.31418097,0.21088019,0.16059452",
help_text="Comma-separated standard deviation values for input normalization.",
)
size_x = models.IntegerField(default=716, help_text="Expected input image width.")
size_y = models.IntegerField(default=716, help_text="Expected input image height.")
axes = models.CharField(
max_length=10, default="2,0,1", help_text="Comma-separated target axis order (e.g., '2,0,1' for CHW)."
)
# --- Inference Parameters ---
batchsize = models.IntegerField(default=16, help_text="Default batch size for inference.")
num_workers = models.IntegerField(default=0, help_text="Default number of workers for data loading.")
# --- Metadata ---
description = models.TextField(blank=True, null=True, help_text="Optional description.")
date_created = models.DateTimeField(auto_now_add=True)
objects = ModelMetaManager()
# --- Type Hinting for Related Fields ---
if TYPE_CHECKING:
labelset: "LabelSet"
model: "AiModel" # Corrected from ai_model to match field name
class Meta:
"""Metadata options for the ModelMeta model."""
# ... existing code ...
[docs]
@classmethod
def create_from_file(
cls: Type["ModelMeta"],
meta_name: str,
model_name: str,
labelset_name: str,
weights_file: str,
requested_version: Optional[str] = None,
bump_if_exists: bool = False,
**kwargs: Any,
) -> "ModelMeta":
"""
Creates or updates a ModelMeta instance using external logic.
"""
# Delegate to logic function, passing the class (cls)
return logic.create_model_meta_from_file(
cls, meta_name, model_name, labelset_name, weights_file,
requested_version, bump_if_exists, **kwargs
)
[docs]
@classmethod
def get_latest_version_number(cls: Type["ModelMeta"], meta_name: str, model_name: str) -> int:
"""
Gets the latest version *number* using external logic.
"""
# Delegate to logic function
return logic.get_latest_version_number_logic(cls, meta_name, model_name)
[docs]
@staticmethod
def get_activation_function(activation_name: str) -> "TorchModule":
"""
Retrieves a PyTorch activation function using external logic.
"""
# Delegate to logic function
return logic.get_activation_function_logic(activation_name)
[docs]
def get_inference_dataset_config(self) -> Dict[str, Any]:
"""
Generates an inference dataset configuration using external logic.
"""
# Delegate to logic function
return logic.get_inference_dataset_config_logic(self)
# ... existing code ...
def __str__(self) -> str:
"""String representation of the ModelMeta instance."""
# ... existing code ...
[docs]
def get_config_dict(self) -> Dict[str, Any]:
"""
Returns the model's configuration parameters using external logic.
"""
# Delegate to logic function
return logic.get_config_dict_logic(self)
[docs]
@classmethod
def get_by_name_version(
cls: Type["ModelMeta"],
meta_name: str,
model_name: str,
version: Optional[str] = None,
) -> "ModelMeta":
"""
Retrieves a ModelMeta instance by name, model name, and optionally version using external logic.
"""
# Delegate to logic function
return logic.get_model_meta_by_name_version_logic(cls, meta_name, model_name, version)
[docs]
@classmethod
def get_latest(cls: Type["ModelMeta"], meta_name: str, model_name: str) -> "ModelMeta":
"""Alias for get_by_name_version(meta_name, model_name, version=None) using external logic."""
# Delegate directly to the specific logic function
return logic.get_model_meta_by_name_version_logic(cls, meta_name, model_name, version=None)